:root {
  --ink: #17231f;
  --muted: #66736e;
  --line: #dce4df;
  --panel: #ffffff;
  --canvas: #f3f6f4;
  --green: #145c45;
  --green-2: #1d7a5d;
  --mint: #dcefe7;
  --amber: #e6a23c;
  --amber-soft: #fff2d8;
  --red: #b74343;
  --red-soft: #fbe3e3;
  --blue-soft: #e4edf9;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--ink);
  background: var(--canvas);
}

* { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; background: var(--canvas); }
button, input, select { font: inherit; }
button { cursor: pointer; }

.app-shell { min-height: 100vh; display: grid; grid-template-columns: 248px minmax(0, 1fr); }
/* La barre est collée en haut et haute d'un écran : sans défilement propre, tout ce qui
   dépasse est **définitivement** hors d'atteinte, puisque faire défiler la page ne la
   déplace pas. Sur une fenêtre de moins de 1 100 px, « Page de fin » et « Administration »
   devenaient inaccessibles — un menu qu'on ne peut pas atteindre n'existe pas. */
.sidebar {
  position: sticky; top: 0; height: 100vh; padding: 14px; overflow-y: auto;
  background: #102d24; color: white; display: flex; flex-direction: column; gap: 12px;
}
.brand { display: flex; align-items: center; gap: 12px; }
.brand-mark {
  width: 34px; height: 34px; border-radius: 8px; display: grid; place-items: center;
  color: #102d24; background: #bce0d0; font-weight: 800; font-size: 19px;
}
.brand strong { display: block; font-size: 19px; }
.brand small { display: block; color: #adc5bb; margin-top: 2px; }
.site-public-link {
  width: fit-content; margin-top: 0; color: #c9d9d2; font-size: 13px; font-weight: 600;
  text-decoration: none;
}
.site-public-link:hover, .site-public-link:focus { color: white; text-decoration: underline; }
.eyebrow { display: block; color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: .11em; text-transform: uppercase; }
.sidebar .eyebrow { color: #9eb9ae; }
.mode-card { border: 1px solid #315346; border-radius: 8px; padding: 16px; background: #183b30; }
.mode-card strong { display: block; margin-top: 5px; font-size: 18px; }
.mode-card p { margin: 8px 0 0; color: #bcd0c7; font-size: 13px; line-height: 1.45; }
.navigation { display: grid; gap: 2px; }
/* Ce qui ne relève d'aucun module descend en bas de la colonne, séparé du fil
   de travail par un trait. `margin-top: auto` le pousse vers le bas quelle que
   soit la longueur de la navigation du module affiché. */
.navigation-globale {
  margin-top: auto; padding-top: 8px; border-top: 1px solid #2a4c40;
}
/* Un compte client ne voit pas l'administration : le bloc se retire alors entièrement.
   Sans cette règle, il ne resterait qu'un trait de séparation suspendu au bas de la
   colonne, sous lequel il n'y a rien. */
.navigation-globale:not(:has(.nav-button:not(.hidden))) { display: none; }
.nav-button {
  padding: 5px 10px; line-height: 1.3; border: 0; border-left: 3px solid transparent; border-radius: 6px;
  color: #c9d9d2; background: transparent; text-align: left; font-weight: 600; font-size: 13px;
}
.nav-button:hover { color: white; background: #245443; }
.nav-button.active { color: white; background: #245443; border-left-color: #bce0d0; }
/* Même habillage qu'un bouton de navigation, mais c'est un lien : il quitte l'application
   pour les pages d'outils internes, il ne change pas de vue. */
.nav-lien {
  display: block; padding: 5px 10px; line-height: 1.3; border-left: 3px solid transparent; border-radius: 6px;
  color: #c9d9d2; text-decoration: none; font-weight: 600; font-size: 13px;
}
.nav-lien:hover { color: white; background: #245443; }
.nav-lien::after { content: " ↗"; opacity: .6; }
.prototype-warning { margin-top: auto; padding: 14px; border-radius: 8px; background: #0b211a; font-size: 12px; }
.prototype-warning strong, .prototype-warning span { display: block; }
.prototype-warning span { margin-top: 5px; color: #a9beb5; line-height: 1.4; }

.sidebar-study-context { min-width:0; padding:10px; border:1px solid #315346; border-radius:8px; background:#183b30; }
.sidebar-study-context .eyebrow { margin-bottom:4px; }
.sidebar-study-context #active-study-name { display:block; font-size:14px; line-height:1.3; overflow-wrap:anywhere; }
.sidebar-study-context select { width:100%; min-width:0; max-width:100%; margin:0; padding:7px 5px; border:1px solid #527568; border-radius:5px; color:white; background:#183b30; font-weight:650; font-size:13px; text-overflow:ellipsis; }
.sidebar-study-context [data-mobilites-context] strong { font-size:13px; }
.sidebar-study-actions { display:grid; margin-top:-4px; }
.sidebar-study-actions .save-state { justify-self:start; max-width:100%; font-size:11px; padding:5px 9px; }
.sidebar-footer { margin-top:auto; display:grid; gap:10px; }
.sidebar-footer .session-account button { width:100%; }
.main-content { min-width: 0; }
.topbar {
  height: 60px; padding: 0 28px; display: flex; align-items: center; justify-content: space-between;
  background: rgba(255,255,255,.94); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 20;
  backdrop-filter: blur(10px);
}
.topbar > div, .topbar [data-od-study-context] { display: flex; align-items: center; gap: 10px; }
.topbar select {
  width: auto; min-width: 0; max-width: 520px; min-height: 36px; margin-top: 0; padding: 7px 12px;
  border: 1px solid #cbd7d1; border-radius: 6px; font-weight: 600; color: var(--ink); background: white;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.save-state { padding: 8px 12px; border-radius: 99px; font-size: 12px; font-weight: 600; background: #edf1ef; color: var(--muted); }
.save-state.saving { background: var(--amber-soft); color: #86580e; }
.save-state.saved { background: var(--mint); color: var(--green); }
.save-state.error { background: var(--red-soft); color: var(--red); }
.audit-warning {
  margin: 12px 14px 0; padding: 14px 18px; border: 1px solid #d58a8a; border-radius: 8px;
  background: var(--red-soft); color: #7d2626;
}
.audit-warning strong, .audit-warning span { display: block; }
.audit-warning span { margin-top: 4px; line-height: 1.4; }
/* Les vues occupent toute la largeur disponible. Un rapport de stationnement aligne des
   tableaux de quinze colonnes et des graphiques côte à côte : chaque pixel rendu aux
   marges est un pixel de moins pour les données, et sur un écran large la gouttière
   centrée d'un site vitrine ne fait que rétrécir le travail. */
.view { display: none; padding: 20px 14px 28px; max-width: none; margin: 0; }
.view.active { display: block; }
#view-entry { width: 100%; max-width: none; margin: 0; padding: 9px 7px 5px; }
#view-entry .page-heading { align-items: center; margin-bottom: 7px; }
#view-entry .page-heading h1 { margin-top: 2px; font-size: clamp(24px, 2.4vw, 32px); }
#view-entry .page-heading p { margin-top: 3px; max-width: none; line-height: 1.3; font-size: 12px; }
#view-entry .page-heading .eyebrow { font-size: 9px; }
#view-entry .pass-count-badge { padding: 8px 10px; }
#view-entry .pass-controls button { padding: 8px 12px; }
#view-entry .legend { margin-bottom: 6px; gap: 12px; font-size: 11px; }
#view-inventory { width: 100%; max-width: none; margin: 0; padding: 18px 12px 96px; }
#view-inventory .page-heading { margin-bottom: 12px; }
#view-inventory .page-heading h1 { font-size: clamp(27px, 2.7vw, 36px); }
/* L'ancien bandeau dégradé de la vue d'ensemble est un panneau comme les autres :
   l'information reste, l'estrade disparaît. */
.hero {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line); border-radius: 8px;
  padding: 22px 24px; display: flex; justify-content: space-between; align-items: center; gap: 30px;
}
.hero .eyebrow { color: var(--muted); }
h1 { margin: 7px 0 8px; font-size: 26px; letter-spacing: -.02em; }
.hero p { max-width: 740px; margin: 0; color: var(--muted); line-height: 1.6; }
.hero-stat { min-width: 155px; padding: 14px 18px; border: 1px solid var(--line); border-radius: 8px; background: #f4f7f5; }
.hero-stat strong { display: block; font-size: 28px; }
.hero-stat span { color: var(--muted); font-size: 13px; }
.two-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; margin-top: 22px; }
.dashboard-study-columns { grid-template-columns: minmax(0, 1.7fr) minmax(340px, .8fr); align-items: start; }
.dashboard-study-columns.editing { grid-template-columns: minmax(0, 1fr); }
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 24px; }
.panel-heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
.panel h2, .page-heading h1 { margin: 5px 0 0; }
.study-creation-panel .panel-heading { align-items: flex-start; }
.study-creation-panel .panel-heading p { max-width: 760px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.study-creation-form { display: grid; gap: 16px; }
.study-creation-groups { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.creation-settings-group { min-width: 0; margin: 0; padding: 15px; border: 1px solid var(--line); border-radius: 8px; background: #fbfdfc; }
.creation-settings-group legend { padding: 0 7px; color: var(--green); font-size: 14px; font-weight: 800; }
.creation-settings-group > p { min-height: 39px; margin: 0 0 12px; color: var(--muted); font-size: 12px; line-height: 1.45; }
.creation-settings-group .form-grid { gap: 12px; }
.study-creation-form > .primary { width: 100%; }
.study-protocol-editor { display: grid; gap: 14px; margin-top: 18px; }
.study-protocol-editor.hidden { display: none; }
.study-protocol-editor > .study-protocol-section {
  margin: 0; padding: 16px; border: 1px solid var(--line); border-radius: 8px;
  background: #fbfdfc;
}
.study-protocol-section .panel-heading { margin-bottom: 14px; }
.study-protocol-section h3 { margin: 0; font-size: 17px; }
.study-protocol-section p { margin: 5px 0 0; color: var(--muted); line-height: 1.45; }
.existing-import-panel { margin-top: 22px; }
.existing-import-panel .panel-heading { margin-bottom: 0; gap: 24px; }
.existing-import-panel p { max-width: 820px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.study-manager-panel { margin-top: 22px; }
.study-manager-panel .panel-heading { margin-bottom: 12px; }
.study-manager-list { max-height: 290px; overflow-y: auto; border: 1px solid var(--line); border-radius: 8px; background: #f7faf8; }
.study-manager-row { display: grid; grid-template-columns: minmax(220px, 1fr) minmax(190px, auto) auto auto; gap: 12px; align-items: center; padding: 10px 12px; border-bottom: 1px solid var(--line); }
.study-manager-row:last-child { border-bottom: 0; }
.study-manager-row.active { background: var(--mint); }
.study-manager-name strong, .study-manager-name small { display: block; }
.study-manager-name small, .study-manager-stats { margin-top: 3px; color: var(--muted); font-size: 12px; }
.study-manager-row button { min-height: 34px; padding: 6px 10px; }
.study-manager-empty { padding: 25px; text-align: center; color: var(--muted); }
.backup-panel { margin-top: 22px; border-color: #b9d5c9; background: #f8fcfa; }
.backup-panel .panel-heading { margin-bottom: 0; gap: 24px; }
.backup-panel p { max-width: 920px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.backup-panel code { color: var(--green); font-weight: 600; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; }
.form-span { grid-column: 1 / -1; }
.schedule-fields { display: grid; grid-template-columns: repeat(2, minmax(180px, 1fr)); gap: 12px; }
.custom-times { display: grid; grid-template-columns: repeat(auto-fit, minmax(125px, 1fr)); gap: 10px; }
.custom-times label { padding: 8px; border-radius: 6px; background: #f4f7f5; }
.day-panel { margin-top: 22px; }
.day-panel .panel-heading { gap: 24px; align-items: flex-start; }
.day-panel p { max-width: 860px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.day-editor { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.day-bound { display: flex; align-items: center; gap: 9px; padding: 11px 13px; border-radius: 6px; background: #f4f7f5; }
.day-bound input[type="checkbox"] { width: 18px; min-width: 18px; height: 18px; min-height: 18px; margin: 0; accent-color: var(--green); }
.day-bound span { line-height: 1.35; }
.schedule-panel { margin-top: 22px; }
.schedule-editor { display: grid; grid-template-columns: minmax(190px, .45fr) 1fr; gap: 16px; align-items: end; }
.schedule-editor .custom-times { grid-column: 1 / -1; }
label { color: #485650; font-size: 13px; font-weight: 600; }
input, select {
  width: 100%; min-height: 42px; margin-top: 6px; padding: 9px 11px; border: 1px solid #cbd7d1;
  border-radius: 6px; color: var(--ink); background: white; outline: none;
}
input:focus, select:focus { border-color: var(--green-2); box-shadow: 0 0 0 3px rgba(29,122,93,.12); }
/* Une case à cocher n'est pas un champ de saisie : la règle générique ci-dessus l'étirait
   sur toute la largeur du bloc — d'où des coches géantes sur « Journées retenues ». */
input[type="checkbox"], input[type="radio"] {
  width: 16px; min-width: 16px; height: 16px; min-height: 16px;
  margin: 0; padding: 0; accent-color: var(--green);
}
.form-grid button { align-self: end; }
button.primary, button.secondary {
  min-height: 36px; padding: 8px 14px; border-radius: 6px; font-weight: 600; font-size: 13.5px;
}
button.primary { color: white; border: 1px solid var(--green); background: var(--green); }
button.primary:hover { background: #0e4c38; }
button.secondary { color: var(--green); border: 1px solid #a9c8bb; background: white; }
button.secondary:hover { background: #edf7f2; }
.danger-button { min-height: 38px; padding: 8px 12px; border: 1px solid #d9abab; border-radius: 6px; color: #9e3434; background: white; font-weight: 600; }
.danger-button:hover { color: white; background: var(--red); }
.danger-button:disabled { opacity: .45; cursor: not-allowed; }
.study-meta { display: block; margin-top: 5px; color: var(--muted); }
.summary-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 0; }
.summary-grid div { padding: 13px; border-radius: 8px; background: #f4f7f5; }
.summary-grid dt { color: var(--muted); font-size: 11px; font-weight: 700; text-transform: uppercase; }
.summary-grid dd { margin: 5px 0 0; font-size: 19px; font-weight: 700; }

.page-heading { display: flex; justify-content: space-between; gap: 25px; align-items: flex-end; margin-bottom: 24px; }
.page-heading p { max-width: 800px; margin: 8px 0 0; color: var(--muted); line-height: 1.55; font-size: 14px; }
.inventory-toolbar { display: flex; flex-wrap: wrap; gap: 10px; }
.source-banner {
  margin-bottom: 12px; padding: 12px 15px; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  border: 1px solid #b9d5c9; border-radius: 8px; background: #edf7f2;
}
.source-banner strong, .source-banner span { display: block; }
.source-banner div > span { margin-top: 3px; color: var(--muted); font-size: 12px; }
.source-banner-actions { display: flex; align-items: center; gap: 8px; align-self: flex-start; }
.dismiss-sig-warnings {
  width: 29px; height: 29px; padding: 0; display: inline-flex; align-items: center;
  justify-content: center; border: 1px solid #c9d8d1; border-radius: 50%; color: #53645d;
  background: #fff; font: 22px/1 Arial, sans-serif; cursor: pointer;
}
.dismiss-sig-warnings:hover { color: #7b250f; border-color: #d79b8a; background: #fff5f1; }
.dismiss-sig-warnings:focus-visible { outline: 3px solid rgba(26, 105, 78, .25); outline-offset: 2px; }
.matrix-generation-status {
  margin: -8px 0 16px; padding: 13px 16px; display: flex; align-items: center; gap: 13px;
  border: 1px solid #9fcbb8; border-radius: 8px; color: var(--green); background: #edf7f2;
}
.matrix-generation-status strong, .matrix-generation-status span { display: block; }
.matrix-generation-status div > span { margin-top: 3px; color: var(--muted); font-size: 12px; }
.matrix-inventory-note {
  margin: -8px 0 12px; padding: 9px 12px; border: 1px solid #b9d5c8;
  border-radius: 7px; color: #315a49; background: #f1f8f5; font-size: 12px;
}
.matrix-inventory-note strong { margin-right: 5px; }
.loading-spinner {
  flex: 0 0 22px; width: 22px; height: 22px; border: 3px solid #bddbce;
  border-top-color: var(--green); border-radius: 50%; animation: statio-spin .8s linear infinite;
}
@keyframes statio-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .loading-spinner { animation-duration: 1.8s; } }
.sig-warning-list { margin: 9px 0 0; padding-left: 18px; color: #79520f; font-size: 12px; line-height: 1.45; }
.source-status { padding: 6px 9px; border-radius: 99px; font-size: 11px; font-weight: 700; }
.source-status.ok { color: var(--green); background: #d9eee5; }
.source-status.warning { color: #875a10; background: var(--amber-soft); }
.sections-editor { display: block; padding-bottom: 95px; }
/* Le cadre suit le tableau au lieu de l'étirer : sans cela, le surplus de largeur des
   grands écrans partait dans les colonnes non bornées — Section, Total légal et la
   colonne des × devenaient des prairies (constat d'Eddy du 23/08). */
/* Plus de hauteur plafonnée : le tableau se déroule en entier et c'est la page qui
   défile. Une barre de défilement interne obligeait à faire défiler dans le défilement,
   et cachait le bas de l'inventaire derrière un pied de page qui n'existe plus. Le
   défilement horizontal, lui, reste : vingt typologies ne tiennent pas en largeur. */
/* Le cadre défile dans les deux sens et **borne sa hauteur** : sans cela, la page seule
   défile, l'en-tête colle au haut d'un cadre qui s'en va avec elle, et les colonnes se
   lisent sans titre passé la trentième ligne. Une étude en compte plusieurs centaines. */
/* L'écran de l'inventaire tient dans la fenêtre : le titre et ses boutons ne bougent pas,
   tout le reste défile dans `.inventory-scroll`. C'est ce **seul** ascenseur qui rend
   l'en-tête du tableau collant — tant que le cadre du tableau défilait de son côté,
   l'en-tête se figeait au sommet d'un cadre qui s'en allait avec la page. */
#view-inventory.active {
  display: flex; flex-direction: column; height: calc(100vh - 60px); overflow: hidden;
  /* Ni marge basse ni marge haute : le contenu ne se termine pas sur la page mais sur le
     bord d'un cadre qui défile, et tout ce qui était pris au-dessus l'était sur la carte. */
  padding: 0 14px;
}
/* Le titre tient sur une ligne, boutons compris : le sous-titre explique un écran qu'on
   ouvre des dizaines de fois par étude, et il coûtait deux lignes de hauteur à chaque fois.
   Il reste dans l'infobulle du titre, pour la première ouverture. */
#view-inventory > .page-heading {
  align-items: center; gap: 16px; margin: 0; padding: 8px 0;
}
#view-inventory > .page-heading > div:first-child {
  display: flex; align-items: baseline; gap: 10px;
}
#view-inventory > .page-heading h1 { margin: 0; font-size: 20px; }
#view-inventory > .page-heading .eyebrow { margin: 0; }
#view-inventory > .page-heading p { display: none; }
#view-inventory > .page-heading { flex: none; }
.inventory-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding-right: 2px; }
.inventory-table-wrap {
  width: max-content; max-width: none; margin: 0 auto;
  border: 1px solid var(--line); border-radius: 8px; background: white;
}
.inventory-table { width: max-content; }
/* Colonnes resserrées : une étude porte une vingtaine de typologies, et à 86 px de
   large le tableau débordait de l'écran avant même la moitié. Le corps est réduit
   plutôt que le contenu tronqué. */
.inventory-table th { position: sticky; top: 0; z-index: 8; min-width: 58px; max-width: 82px; padding: 6px 4px; font-size: 10px; white-space: normal; line-height: 1.1; text-align: center; }
.inventory-table td { padding: 4px; font-size: 12px; }
.inventory-table td input { font-size: 12px; padding: 4px 6px; }
.inventory-table td { padding: 2px 4px; text-align: center; background: white; }
/* Deux colonnes collées à gauche : la case à cocher, puis le nom de section. La case ne
   porte qu'un carré de 16 px — elle prend la largeur d'un carré, pas celle d'un intitulé
   (la règle des 132 px visait la colonne du nom, qui n'était plus la première). */
.inventory-table th.colonne-coche, .inventory-table td.colonne-coche {
  position: sticky; left: 0; z-index: 3; width: 36px; min-width: 36px; max-width: 36px;
  padding: 2px; background: #f1f6f3;
}
.inventory-table th.colonne-coche { z-index: 6; background: #e7f0eb; }
.inventory-table .colonne-coche input { width: 16px; min-width: 0; height: 16px;
  min-height: 0; margin: 0 auto; accent-color: var(--green-2); }
.inventory-table th.colonne-coche + th, .inventory-table td.colonne-coche + td {
  position: sticky; left: 36px; z-index: 3; min-width: 132px; background: #f1f6f3;
  box-shadow: 2px 0 0 #cdd9d3;
}
.inventory-table th.colonne-coche + th { z-index: 6; background: #e7f0eb; }
.inventory-table input { min-height: 25px; height: 25px; margin: 0; padding: 2px 5px; border-radius: 5px; text-align: center; }
.inventory-table .section-name-input { min-width: 0; font-weight: 700; }
.inventory-table .quantity-input { width: 64px; }
/* La largeur calculée compte des caractères ; bordures et marges internes du champ
   s'ajoutent ici — sans quoi « Faubourg » perdait sa dernière lettre. */
.inventory-table .content-column {
  width: calc(var(--inventory-column-width) + 24px);
  min-width: calc(var(--inventory-column-width) + 24px);
  max-width: calc(var(--inventory-column-width) + 24px);
}
/* Les largeurs calculées des intitulés restent bornées : « NON MATÉRIALISÉE » revient à
   la ligne plutôt que d'élargir sa colonne, et toutes les colonnes de comptage se
   ressemblent. */
.inventory-table th.content-column { max-width: 110px; }
/* Les colonnes de comptage sont uniformes ; les colonnes de texte (zone, identifiant…)
   gardent la largeur calculée sur leur contenu le plus long. */
.inventory-table td.content-column:has(.quantity-input) { width: 64px; min-width: 64px; max-width: 72px; }
.inventory-table .quantity-input { text-align: center; }
.inventory-table td.content-column input { width: 100%; min-width: 0; }
.inventory-table td.content-column .quantity-input { width: 100%; }
.inventory-table th.colonne-coche + th, .inventory-table td.colonne-coche + td {
  width: calc(var(--inventory-column-width, 128px) + 24px);
  min-width: 132px;
  max-width: 280px;
}
.inventory-table tr.section-choisie td { background: var(--mint); }
.inventory-table tr.section-choisie td.colonne-coche { background: #cde7da; }
.inventory-table .section-name-input { width: 100%; }
/* Les nombres se saisissent au clavier : les flèches décentraient la valeur pour un
   service qu'on ne leur demandait pas. Cliquer sélectionne, taper remplace. */
.inventory-table input[type="number"] { appearance: textfield; }
.inventory-table input[type="number"]::-webkit-inner-spin-button,
.inventory-table input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.inventory-table th:last-child, .inventory-table td:last-child { width: 44px; min-width: 44px; max-width: 44px; }
.inventory-table .illegal-column { background: #fff0f0; }
.inventory-table .configurable-heading { position: sticky; }
.configurable-heading span { display: block; padding-right: 15px; }
.remove-definition {
  position: absolute; top: 3px; right: 3px; width: 18px; height: 18px; padding: 0;
  border: 0; border-radius: 50%; color: #8c4a4a; background: rgba(255,255,255,.72);
  font-size: 13px; line-height: 18px;
}
.remove-definition:hover { color: white; background: var(--red); }
.inventory-table tr.offer-mismatch td { border-top: 2px solid var(--amber); border-bottom: 2px solid var(--amber); }
.inventory-offer-mismatch-note {
  display: flex; align-items: center; gap: 8px; width: max-content; max-width: 100%;
  margin: 0 auto 7px; padding: 6px 10px; border: 1px solid #edc270;
  border-radius: 6px; color: #80560b; background: #fff8e9; font-size: 12px;
}
.inventory-offer-mismatch-note > span:first-child {
  width: 24px; height: 0; flex: none; border-top: 2px solid var(--amber);
}
.inventory-offer-mismatch-text { flex: 1 1 auto; }
.dismiss-offer-mismatches {
  width: 22px; height: 22px; flex: none; padding: 0; border: 1px solid #d9a94c;
  border-radius: 50%; color: #80560b; background: white; font: 18px/18px Arial, sans-serif;
}
.dismiss-offer-mismatches:hover { color: white; background: #a66c08; }
.inventory-locked-note {
  width: max-content; max-width: 100%; margin: 0 auto 7px; padding: 7px 10px;
  border: 1px solid #b9d5c8; border-radius: 6px; color: #315a49;
  background: #f1f8f5; font-size: 12px;
}
.inventory-table .quantity-input[readonly] {
  color: #53645d; background: #eef3f0; cursor: not-allowed;
}
.section-card { background: white; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.section-card-header { padding: 15px 18px; display: grid; grid-template-columns: 1fr 1fr 1fr 1.3fr auto; gap: 12px; align-items: end; border-bottom: 1px solid var(--line); background: #f8faf9; }
.section-card-header input { margin-top: 4px; }
.remove-section { width: 38px; height: 38px; border: 1px solid #e6c4c4; border-radius: 6px; background: white; color: var(--red); }
.type-grid { padding: 16px 18px 20px; display: grid; grid-template-columns: repeat(8, minmax(100px, 1fr)); gap: 10px; }
.type-field { padding: 9px; border-radius: 6px; background: #f5f8f6; }
.type-field.illegal { background: var(--red-soft); }
.type-field span { display: block; min-height: 27px; color: var(--muted); font-size: 10px; font-weight: 700; text-transform: uppercase; }
.type-field input { min-height: 36px; margin: 3px 0 0; }
.sticky-actions {
  position: fixed; left: 260px; right: 12px; bottom: 12px; z-index: 15; padding: 14px 18px;
  display: flex; justify-content: space-between; align-items: center; gap: 20px;
  border: 1px solid #bfd2c9; border-radius: 8px; background: rgba(255,255,255,.96); box-shadow: 0 12px 45px rgba(24,51,41,.16);
}
.sticky-actions span { display: block; color: var(--muted); font-size: 12px; margin-top: 3px; }
.hidden { display: none !important; }
.empty-state { padding: 50px 20px; border: 1px dashed #b9c8c1; border-radius: 8px; text-align: center; color: var(--muted); background: rgba(255,255,255,.55); }

.progress-panel { margin-top: 18px; }
.progress-steps { display: grid; grid-template-columns: repeat(7, minmax(90px, 1fr)); gap: 8px; padding: 0; margin: 0 0 14px; list-style: none; }
.progress-steps li { display: flex; align-items: center; gap: 7px; min-width: 0; padding: 9px; border: 1px solid var(--line); border-radius: 6px; color: var(--muted); background: #f7faf8; font-size: 11px; }
.progress-steps li span { display: grid; flex: 0 0 23px; height: 23px; place-items: center; border-radius: 50%; background: #e3ebe7; font-weight: 700; }
.progress-steps li strong { overflow: hidden; text-overflow: ellipsis; }
.progress-steps li.done { color: var(--green); background: #edf7f2; border-color: #bedbce; }
.progress-steps li.done span { color: white; background: var(--green); }
.progress-steps li.current { color: #76500d; background: var(--amber-soft); border-color: #e2c481; }
.progress-steps li.current span { color: white; background: #b9790c; }
.progress-next { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 14px 16px; border-radius: 8px; }
.progress-next.warning { background: var(--amber-soft); }
.progress-next.ready { background: #e7f5ee; }
.progress-next div { display: grid; gap: 3px; }
.progress-next span, .progress-next small { color: var(--muted); }
.progress-error { display: grid; gap: 4px; padding: 14px 16px; border-radius: 8px; color: #7c2727; background: #f8e5e5; }
@media (max-width: 1100px) { .progress-steps { grid-template-columns: repeat(4, minmax(110px, 1fr)); } }
@media (max-width: 720px) {
  .progress-steps { grid-template-columns: repeat(2, minmax(110px, 1fr)); }
  .progress-next { align-items: stretch; flex-direction: column; }
}
.pass-controls { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; align-items: center; }
.pass-controls select { min-width: 180px; margin: 0; }
.pass-count-badge { padding: 10px 13px; border: 1px solid #c7d7d0; border-radius: 6px; color: var(--green); background: white; font-size: 13px; font-weight: 700; }
.legend { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 15px; color: var(--muted); font-size: 12px; }
.legend span { display: flex; align-items: center; gap: 6px; }
/* Ce que dit le nombre entre parenthèses des étiquettes : une mention, pas une classe de
   couleur. Elle n'a donc pas de pastille et se tient un peu en retrait. */
.legend span.legend-note { font-style: italic; opacity: 0.85; }
.dot { width: 10px; height: 10px; border-radius: 50%; background: #ddd; }
.dot.same, .dot.repeated-a { background: #83DDB0; }.dot.repeated-b { background: #FFB067; }.dot.repeated-illicit { background: #A7B2AE; }.dot.duplicate { background: #F3A6C4; }.dot.illegal { background: #db7777; }.dot.hors-zone { background: #7A1330; }.dot.empty { background: #c9d0cd; }
kbd { padding: 2px 6px; border: 1px solid #cad4cf; border-radius: 4px; background: white; box-shadow: 0 1px 0 #cad4cf; }
.matrix-wrap, .table-scroll { overflow: auto; border: 1px solid var(--line); border-radius: 8px; background: white; }
.matrix-wrap {
  position: relative;
  height: calc(100vh - 232px);
  min-height: 300px;
  max-height: none;
  scrollbar-gutter: stable both-edges;
  overscroll-behavior: contain;
}
table { width: 100%; border-collapse: separate; border-spacing: 0; }
th { position: sticky; top: 0; z-index: 2; padding: 11px 10px; color: #4c5a54; background: #eef3f0; border-bottom: 1px solid #cfdad5; text-align: left; font-size: 11px; text-transform: uppercase; white-space: nowrap; }
td { padding: 7px 10px; border-bottom: 1px solid #edf1ef; font-size: 13px; }
.matrix-table tr.section-start td { border-top: 5px solid #a6baaf; }
.matrix-table tr.hors-offre { background: #fff8f8; }
.matrix-table { width: max-content; min-width: 100%; }
.matrix-table th { text-align: center; }
.matrix-table th,
.matrix-table td {
  border-right: 1px solid rgba(95, 126, 112, .28);
  border-bottom: 1px solid rgba(95, 126, 112, .28);
  text-align: center;
  vertical-align: middle;
}
.matrix-table tr > :first-child { border-left: 1px solid rgba(95, 126, 112, .28); }
.matrix-table thead tr:first-child th { border-top: 1px solid rgba(95, 126, 112, .28); }
.matrix-table tbody tr > td { background: var(--type-color, white); color: var(--type-text, var(--ink)); }
.matrix-table tbody tr > td input,
.matrix-table tbody tr > td select {
  color: var(--ink);
  background: rgba(255, 255, 255, .72);
  text-align: center;
  text-align-last: center;
}
/* La grille s'adapte à son contenu — cinq caractères, pas une immatriculation entière —
   et `--grid-zoom` (boutons A− / A+) la resserre encore quand tous les passages doivent
   tenir à l'écran. */
.matrix-table th, .matrix-table td { font-size: calc(13px * var(--grid-zoom, 1)); }
.matrix-table .passage-heading { min-width: calc(150px * var(--grid-zoom, 1)); text-align: center; }
.rotation-grid .matrix-table .passage-heading { width: auto; min-width: calc(58px * var(--grid-zoom, 1)); }
.matrix-table .passage-heading strong, .matrix-table .passage-heading small { display: block; }
.matrix-table .passage-heading small { margin-top: 3px; color: var(--ink); font-size: calc(14px * var(--grid-zoom, 1)); font-weight: 700; text-transform: none; }
.matrix-table .observation-cell { min-width: calc(150px * var(--grid-zoom, 1)); padding: 5px; transition: background .15s ease; }
.rotation-grid .matrix-table .observation-cell {
  width: auto;
  min-width: calc(58px * var(--grid-zoom, 1));
  padding: 3px 4px;
  text-align: center;
  vertical-align: middle;
}
/* Les actions de ligne restent discrètes et n'apparaissent qu'au survol, pour ne pas
   encombrer une grille déjà dense ni risquer un clic malheureux pendant la saisie. */
.matrix-table .type-cell { white-space: nowrap; }
.row-actions { display: inline-flex; gap: 3px; margin-left: 6px; opacity: 1; transition: opacity .12s; }
.matrix-table tbody tr:hover .row-actions, .row-actions:focus-within { opacity: 1; }
.row-actions button {
  width: 17px; height: 17px; padding: 0; vertical-align: middle;
  border: 1px solid rgba(95, 126, 112, .45); border-radius: 4px;
  background: rgba(255, 255, 255, .85); font-size: 12px; font-weight: 700; line-height: 15px;
}
.row-actions .add-like-row { color: var(--green); }
.row-actions .add-like-row:hover { color: white; border-color: var(--green); background: var(--green); }
.row-actions .remove-row { color: #9e3434; }
.row-actions .remove-row:hover { color: white; border-color: var(--red); background: var(--red); }
.add-place-button {
  width: 17px; height: 17px; margin-left: 5px; padding: 0; vertical-align: middle;
  border: 1px solid rgba(95, 126, 112, .45); border-radius: 4px;
  color: var(--green); background: rgba(255, 255, 255, .8);
  font-size: 12px; font-weight: 700; line-height: 15px;
}
.add-place-button:hover { color: white; border-color: var(--green); background: var(--green); }
.matrix-zone-cell { white-space: nowrap; }
.edit-section-zone {
  width: 20px; height: 20px; margin-left: 5px; padding: 0; vertical-align: middle;
  border: 1px solid rgba(95, 126, 112, .45); border-radius: 4px;
  color: var(--green); background: white; font-size: 12px; line-height: 18px;
}
.edit-section-zone:hover { color: white; border-color: var(--green); background: var(--green); }
.type-menu {
  position: absolute; z-index: 40; min-width: 210px; max-height: 60vh; overflow-y: auto;
  padding: 6px; border: 1px solid #bfd2c9; border-radius: 6px; background: white;
  box-shadow: 0 14px 40px rgba(24, 51, 41, .2);
}
.type-menu-group {
  padding: 7px 9px 3px; color: var(--muted);
  font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
}
.type-menu button {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 9px;
  border: 0; border-radius: 8px; background: transparent; color: var(--ink);
  font-size: 13px; font-weight: 600; text-align: left;
}
.type-menu button:hover, .type-menu button:focus { background: var(--mint); outline: none; }
.type-menu button i {
  width: 13px; height: 13px; border: 1px solid rgba(95, 126, 112, .45); border-radius: 3px;
}
.matrix-table .unavailable-cell {
  color: #9aa8a2; background: repeating-linear-gradient(
    135deg, #eef1ef, #eef1ef 4px, #e3e8e5 4px, #e3e8e5 8px);
}
.matrix-table .remark-heading,
.matrix-table .remark-cell { width: 220px; min-width: 220px; max-width: 220px; }
.matrix-table .remark-input { width: 100%; min-width: 0; }
.matrix-table .occupation-cell { min-width: 190px; }
/* Séjour licite qui dure : vert, puis orange pour le bloc suivant. L'alternance évite que
   deux séjours successifs de plaques différentes ne se lisent comme un seul. */
.matrix-table .observation-cell.same-plate.same-series-a { background: #83DDB0 !important; box-shadow: inset 0 0 0 3px #147A52 !important; }
.matrix-table .observation-cell.same-plate.same-series-b { background: #FFB067 !important; box-shadow: inset 0 0 0 3px #B25E12 !important; }
/* Séjour illicite qui dure : gris, pour ne jamais le confondre avec un séjour régulier. */
.matrix-table .observation-cell.same-plate.illicit-series-a { background: #C9D0CD !important; box-shadow: inset 0 0 0 3px #5F7E70 !important; }
.matrix-table .observation-cell.same-plate.illicit-series-b { background: #A7B2AE !important; box-shadow: inset 0 0 0 3px #3D5249 !important; }
/* Rose : la même plaque réapparaît ailleurs dans la matrice, sans continuité. Ce marquage
   prime sur la couleur du séjour, car c'est un fait à vérifier avant toute analyse — d'où
   les sélecteurs combinés, sans lesquels la règle du séjour l'emporterait par spécificité. */
.matrix-table .observation-cell.duplicate-plate,
.matrix-table .observation-cell.same-plate.same-series-a.duplicate-plate,
.matrix-table .observation-cell.same-plate.same-series-b.duplicate-plate,
.matrix-table .observation-cell.same-plate.illicit-series-a.duplicate-plate,
.matrix-table .observation-cell.same-plate.illicit-series-b.duplicate-plate {
  background: #F3A6C4 !important; box-shadow: inset 0 0 0 3px #A52A62 !important;
}
.matrix-table .observation-cell.occupied-observation { background: #e5f5ed; }
.matrix-table .observation-cell.illegal-observation { background: #fde6e6; }
.matrix-table .observation-cell.empty-observation { background: #f0f2f1; }
.matrix-table input, .matrix-table select { min-height: 34px; margin: 0; padding: 5px 10px; }
/* Cellules en texte simple : la valeur est affichée, jamais éditée sur place. */
.matrix-table .observation-cell {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-weight: 700; letter-spacing: .04em; white-space: nowrap;
}
.matrix-table .observation-cell.active-cell { box-shadow: inset 0 0 0 2px var(--green) !important; }
/* Le passage actif est signalé sur son seul en-tête. Colorer toute la colonne donnait
   l'impression d'avoir sélectionné le passage entier au moindre clic dans une cellule. */
.matrix-table th.active-pass { color: var(--green); background: var(--mint); }

/* Champ de saisie unique, positionné sur la cellule active. */
.cell-editor {
  position: absolute; z-index: 6; width: auto; min-height: 0; margin: 0; padding: 0 4px;
  border: 2px solid var(--green); border-radius: 3px; background: white; color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-weight: 700; font-size: 13px; letter-spacing: .04em; text-align: center;
  caret-color: transparent;                       /* mode navigation : pas de curseur */
}
.cell-editor.editing { caret-color: var(--green); background: #fffdf5; }
.cell-editor:focus { box-shadow: 0 0 0 3px rgba(29, 122, 93, .18); }

/* Colonnes descriptives figées à gauche, comme le volet figé de l'export Excel. */
.matrix-table .frozen-column { position: sticky; z-index: 3; }
.matrix-table thead .frozen-column { z-index: 5; }
.matrix-table tbody tr > td.frozen-column { background: var(--type-color, white); }
.matrix-table tbody tr > td.frozen-column:last-of-type { box-shadow: 2px 0 0 rgba(95, 126, 112, .45); }

/* Barre de position : quand on tape en écoutant, c'est ce qui empêche de dériver. */
.entry-position {
  position: sticky; top: 0; z-index: 12; display: flex; flex-wrap: wrap; gap: 18px;
  align-items: center; margin-bottom: 6px; padding: 8px 13px;
  border: 1px solid #bfd2c9; border-radius: 6px; background: rgba(255, 255, 255, .97);
  box-shadow: 0 4px 18px rgba(24, 51, 41, .08);
}
.position-main { display: flex; align-items: baseline; gap: 9px; }
.position-main strong { font-size: 17px; }
.position-main span { color: var(--muted); font-size: 13px; font-weight: 600; }
.position-detail { display: flex; flex-direction: column; line-height: 1.25; }
.position-label { color: var(--muted); font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.position-detail strong { font-size: 14px; }
.position-mode { padding: 5px 11px; border-radius: 99px; background: #edf1ef; color: var(--muted); font-size: 11px; font-weight: 700; }
.position-mode.editing { background: var(--amber-soft); color: #86580e; }
.position-actions { display: flex; gap: 7px; margin-left: auto; }
.position-actions button { min-height: 32px; padding: 5px 11px; font-size: 12px; }

#view-entry .matrix-table td { height: 29px; padding: 1px 5px; }
#view-entry .matrix-table .observation-cell { padding: 1px 3px; }
#view-entry .matrix-table input { min-height: 25px; height: 25px; padding: 2px 8px; border-radius: 6px; }
#view-entry .cell-editor { height: 29px; }
.cell-controls { display: grid; grid-template-columns: minmax(110px, 1fr) 31px 31px; gap: 4px; margin-top: 4px; }
.cell-controls .compact-status { min-width: 0; font-size: 11px; }
.occupation-cell .compact-status { min-width: 175px; }
.cell-controls button { width: 31px; height: 31px; padding: 0; border: 1px solid #cad6d0; border-radius: 6px; background: white; color: var(--green); }
.cell-controls button:disabled { opacity: .35; cursor: not-allowed; }
.previous-plate { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; color: var(--muted); font-weight: 600; }
.quick-actions { display: flex; gap: 4px; }
.quick-actions button { width: 31px; height: 31px; padding: 0; border: 1px solid #cad6d0; border-radius: 6px; background: white; color: var(--green); }
.metric-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 15px; margin-bottom: 18px; }
/* La carte est une colonne et sa valeur est poussee en bas. Un titre sur deux lignes
   remontait sinon son chiffre par rapport a ses voisins, et une ligne de cadres se lisait
   en escalier. Demande d'Eddy le 09/09/2026 : tout descend au niveau du plus bas. */
.metric-card { display: flex; flex-direction: column; padding: 20px; border-radius: 8px; background: white; border: 1px solid var(--line); }
.metric-card span { color: var(--muted); font-size: 12px; font-weight: 600; }
.metric-card strong { display: block; margin-top: auto; padding-top: 7px; font-size: 28px; letter-spacing: -.01em; }
td, .indicator-table td, .summary-grid dd, .metric-card strong, .hero-stat strong { font-variant-numeric: tabular-nums; }

/* --- Saisie : colonne de l'heure du disque, sur les seules lignes bleues --- */
.disc-cell {
  width: calc(46px * var(--grid-zoom, 1)); min-width: calc(46px * var(--grid-zoom, 1));
  padding: 1px 3px; text-align: center;
  cursor: text; font-family: Consolas, ui-monospace, monospace;
  font-size: calc(12px * var(--grid-zoom, 1));
  color: #17457a; background: #eef4fb; border-left: 1px dashed #c3d4e8;
  font-variant-numeric: tabular-nums;
}
.disc-editor {
  width: 100%; min-width: 0; box-sizing: border-box; min-height: 0; height: 20px;
  margin: 0; padding: 0 2px; border: 1px solid var(--green-2); border-radius: 3px;
  text-align: center; font: inherit; font-size: 12px;
}
/* Le cadre du séjour enveloppe la paire plaque + disque : le côté mitoyen s'efface,
   l'heure vit dans le bloc coloré du véhicule. */
.matrix-table .observation-cell.avec-disque.same-plate.same-series-a { box-shadow: inset 3px 0 0 #147A52, inset 0 3px 0 #147A52, inset 0 -3px 0 #147A52 !important; }
.matrix-table .disc-cell.same-plate.same-series-a { background: #83DDB0 !important; box-shadow: inset -3px 0 0 #147A52, inset 0 3px 0 #147A52, inset 0 -3px 0 #147A52 !important; border-left-color: transparent; color: inherit; }
.matrix-table .observation-cell.avec-disque.same-plate.same-series-b { box-shadow: inset 3px 0 0 #B25E12, inset 0 3px 0 #B25E12, inset 0 -3px 0 #B25E12 !important; }
.matrix-table .disc-cell.same-plate.same-series-b { background: #FFB067 !important; box-shadow: inset -3px 0 0 #B25E12, inset 0 3px 0 #B25E12, inset 0 -3px 0 #B25E12 !important; border-left-color: transparent; color: inherit; }
.matrix-table .observation-cell.avec-disque.same-plate.illicit-series-a { box-shadow: inset 3px 0 0 #5F7E70, inset 0 3px 0 #5F7E70, inset 0 -3px 0 #5F7E70 !important; }
.matrix-table .disc-cell.same-plate.illicit-series-a { background: #C9D0CD !important; box-shadow: inset -3px 0 0 #5F7E70, inset 0 3px 0 #5F7E70, inset 0 -3px 0 #5F7E70 !important; border-left-color: transparent; color: inherit; }
.matrix-table .observation-cell.avec-disque.same-plate.illicit-series-b { box-shadow: inset 3px 0 0 #3D5249, inset 0 3px 0 #3D5249, inset 0 -3px 0 #3D5249 !important; }
.matrix-table .disc-cell.same-plate.illicit-series-b { background: #A7B2AE !important; box-shadow: inset -3px 0 0 #3D5249, inset 0 3px 0 #3D5249, inset 0 -3px 0 #3D5249 !important; border-left-color: transparent; color: inherit; }
.matrix-table .disc-cell.duplicate-plate { background: #F3A6C4 !important; box-shadow: inset -3px 0 0 #A52A62, inset 0 3px 0 #A52A62, inset 0 -3px 0 #A52A62 !important; border-left-color: transparent; }
.matrix-table .observation-cell.avec-disque.duplicate-plate { box-shadow: inset 3px 0 0 #A52A62, inset 0 3px 0 #A52A62, inset 0 -3px 0 #A52A62 !important; }
.matrix-table .disc-cell.illegal-observation { background: #fde6e6; }

/* --- Zone bleue : les couleurs sont celles du processus de référence --- */
.zb-parametres { max-width: 860px; margin: 0 0 16px; color: var(--muted); line-height: 1.5; }
.zb-alerte { margin-bottom: 14px; }
.zb-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(480px, 1fr)); gap: 14px; margin-top: 14px; }
/* Un créneau de dix relevés déborde d'une carte : le tableau défile dans son panneau au
   lieu d'être rogné. */
.zb-defilement { overflow-x: auto; }
.zb-severite-legende { margin: 6px 0 0; color: var(--muted); font-size: 12.5px; max-width: 720px; }
.zb-selection { margin-top: 14px; }
.zb-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.zb-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px;
  border: 1px solid var(--line); border-radius: 99px; background: #f7faf8;
  font-size: 12.5px; font-weight: 600; cursor: pointer; user-select: none;
}
.zb-chip:has(input:checked) { background: var(--mint); border-color: #a9c8bb; }
.zb-chip input { width: 14px; min-width: 14px; height: 14px; min-height: 14px; margin: 0; accent-color: var(--green); }
.zb-chip small { color: var(--muted); font-weight: 600; }

/* --- Payant : géographie, comparaison, grille recolorée --- */
.payant-geo-grille { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin: 10px 0; }
.payant-geo-grille textarea {
  width: 100%; margin-top: 6px; padding: 8px 10px; border: 1px solid #cbd7d1;
  border-radius: 6px; font: 12.5px Consolas, ui-monospace, monospace; resize: vertical;
}
.payant-comparaison { margin-top: 14px; }
.payant-legende { margin: 8px 0 0; display: flex; flex-wrap: wrap; gap: 6px; }
.payant-legende-item { padding: 2px 8px; border-radius: 3px; font-size: 11.5px; font-weight: 600; }
.payant-grille { margin-top: 22px; }
.payant-table td { font-family: Consolas, ui-monospace, monospace; font-size: 12px; }
.payant-table td:nth-child(-n+3) { font-family: inherit; }
.payant-table td small { display: block; font-size: 9px; line-height: 1.15; opacity: .85; }
.payant-hors-plage { color: var(--muted); background: #f4f6f5; }
@media (max-width: 900px) { .payant-geo-grille { grid-template-columns: 1fr; } }
.zb-tourneurs { margin-top: 14px; }
.zone-bleue-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.zone-bleue-table th, .zone-bleue-table td { padding: 6px 9px; border-bottom: 1px solid var(--line); text-align: center; }
.zone-bleue-table thead th { color: var(--muted); font-size: 11px; font-weight: 700; text-transform: uppercase; }
.zone-bleue-table .zb-libelle { display: flex; align-items: center; gap: 7px; text-align: left; font-weight: 600; }
.zone-bleue-table .zb-total th, .zone-bleue-table .zb-total td { font-weight: 700; color: #0070c0; }
.zb-pastille { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.zb-pastille.zb-ok { background: #92d050; }
.zb-pastille.zb-depasse { background: #ffc000; }
.zb-pastille.zb-anticipe { background: #7030a0; }
.zb-pastille.zb-absent { background: #ff0000; }
.zb-pastille.zb-heure_fausse { background: #808080; }
.zb-histogramme { margin: 0 0 12px; overflow-x: auto; }
.zb-histogramme svg { display: block; width: 100%; height: auto; }
.zb-histo-heure { font-size: 10px; fill: var(--muted); }
.zb-histo-total { font-size: 10px; font-weight: 700; fill: var(--ink); }
.zb-explication { margin: 0 0 14px; max-width: 900px; }
.zb-explication summary { cursor: pointer; font-weight: 700; color: var(--green); }
.zb-explication ul { margin: 10px 0 0; padding-left: 20px; }
.zb-explication li { margin-bottom: 7px; line-height: 1.5; font-size: 13.5px; }
.zb-explication p { margin: 10px 0 0; font-size: 13.5px; color: var(--muted); }
.zb-fenetre { margin-top: 22px; }
.zb-fenetre-tete { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin: 0 0 10px; }
.zb-fenetre-tete h2 { margin: 0; }
.zb-fenetre-tete span { color: var(--muted); font-size: 13px; }
.analysis-table td { white-space: nowrap; }
.analysis-detail-panel { margin-top: 18px; }
/* Protocole de stationnement : les horaires se comparent par zone avant de lire le
   glossaire. Les textes restent courts, mais doivent revenir à la ligne sur un portable. */
#study-protocol > * + * { margin-top: 18px; }
#study-protocol + .panel { margin-top: 18px; }
.protocol-summary-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.protocol-summary-grid .panel p, .protocol-schedule-panel .panel-heading p,
.protocol-complements p { margin: 8px 0 0; color: var(--muted); line-height: 1.55; }
.protocol-schedule-panel .panel-heading { align-items: flex-start; }
.protocol-table { width: 100%; }
.protocol-table th { text-align: left; }
.protocol-table td { white-space: normal; vertical-align: top; line-height: 1.45; }
.protocol-table td:first-child { min-width: 190px; }
.protocol-table td:nth-child(2) { min-width: 260px; }
.protocol-times { display: block; margin-top: 4px; color: var(--muted); font-weight: 600; }
.protocol-feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }
.protocol-feature-grid section { padding: 16px; border: 1px solid var(--line); border-radius: 8px; background: #f4f7f5; }
.protocol-feature-grid h3 { margin: 0; font-size: 15px; }
@media (max-width: 850px) {
  .protocol-summary-grid { grid-template-columns: 1fr; }
}
/* Une note qui désamorce une lecture fausse vaut mieux qu'un chiffre qu'on croit erroné :
   elle se pose sous le titre, en retrait, sans concurrencer le tableau. */
.tableau-note { margin: -12px 0 14px; font-size: 12px; line-height: 1.5; color: var(--muted); }
.toast { position: fixed; right: 24px; bottom: 24px; z-index: 50; max-width: 420px; padding: 13px 17px; border-radius: 6px; background: #17231f; color: white; opacity: 0; transform: translateY(12px); pointer-events: none; transition: .2s ease; }
.toast.show { opacity: 1; transform: translateY(0); }
.toast.error { background: var(--red); }
/* Une erreur attend d'être lue : elle reste, on la ferme. D'où la croix, et le clic qui
   doit l'atteindre — le bandeau laisse passer la souris tant qu'il n'est pas montré. */
.toast.show { pointer-events: auto; }
.toast { display: flex; align-items: flex-start; gap: 10px; }
.toast-texte { white-space: pre-line; flex: 1; }
.toast-fermer { flex: none; background: none; border: 0; color: inherit; font-size: 20px; line-height: 1; padding: 0 2px; cursor: pointer; opacity: .8; }
.toast-fermer:hover { opacity: 1; }

/* Le panneau des manques. Contrairement au bandeau, il attend : `pointer-events` par défaut
   pour qu'on puisse le fermer et cliquer son bouton, une hauteur bornée pour que quarante
   manques défilent au lieu de sortir de l'écran. */
.blocage { position: fixed; right: 24px; bottom: 24px; z-index: 60; width: min(520px, calc(100vw - 48px));
  max-height: min(70vh, 640px); overflow-y: auto; padding: 16px 18px; border-radius: 8px;
  background: var(--red); color: white; box-shadow: 0 18px 50px rgba(0,0,0,.28); }
.blocage[hidden] { display: none; }
.blocage-tete { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.blocage-tete h2 { font-size: 16px; margin: 0; }
.blocage-fermer { min-height: 26px; padding: 0 9px; border: 0; border-radius: 6px; font-size: 17px;
  line-height: 1; background: rgba(255,255,255,.18); color: white; cursor: pointer; }
.blocage-fermer:hover { background: rgba(255,255,255,.3); }
.blocage p { margin: 8px 0 0; font-size: 13px; }
.blocage ul { margin: 10px 0 0; padding-left: 20px; font-size: 12.5px; }
.blocage li { margin-bottom: 4px; }
.blocage .aide { color: rgba(255,255,255,.82); font-size: 11.5px; }
.blocage-actions { margin-top: 12px; }
.blocage-actions .secondary { background: white; color: var(--red); border-color: white; }


@media (max-width: 1100px) {
  .app-shell { grid-template-columns: 210px minmax(0, 1fr); }
  .type-grid { grid-template-columns: repeat(4, 1fr); }
  .section-card-header { grid-template-columns: 1fr 1fr; }
  .lieux-columns, .lieux-form { grid-template-columns: 1fr; }
  .sticky-actions { left: 236px; }
}

/* ---------------------------------------------------------------- Enquêtes OD */

.od-stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; min-width: 0; }
.od-stack > *, .od-chart-grid, .od-chart { min-width: 0; }
.od-study-list { display: grid; gap: .65rem; }
.od-study-card {
  width: 100%; text-align: left; display: grid; gap: .18rem; padding: .9rem 1rem;
  border: 1px solid var(--line); border-radius: 8px; background: var(--panel);
  color: var(--ink); cursor: pointer;
}
.od-study-card:hover, .od-study-card.active { border-color: var(--green); background: #f1faf6; }
.od-study-card span, .od-study-card small { color: var(--muted); }
.od-question-list { display: grid; gap: .85rem; }
.od-question-card { border: 1px solid var(--line); border-radius: 8px; padding: 1rem; background: #fbfcfb; }
.od-question-head { display: grid; grid-template-columns: auto minmax(16rem, 1fr) auto; gap: .75rem; align-items: end; }
.od-order { display: flex; gap: .25rem; padding-bottom: .25rem; }
.od-order button { min-width: 2rem; padding: .35rem; border: 1px solid var(--line); background: white; color: var(--green); }
.button-row { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: .65rem; }
.od-question-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .75rem; margin-top: .8rem; }
.od-question-grid textarea { resize: vertical; min-height: 4rem; }
.od-options-field, .od-coding-field { grid-column: span 2; }
.od-stations-table input { min-width: 7rem; width: 100%; }
.od-stations-table td:nth-child(2) input { min-width: 13rem; }
.panel-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: .65rem; margin-top: 1rem; }
.od-entry-columns { align-items: start; }
.od-entry-card { position: sticky; top: 1rem; }
.od-interview-form { display: grid; gap: 1rem; }
.od-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9rem; }
.od-field { min-width: 0; }
.od-field label { height: 100%; }
.od-field input, .od-field select, .od-field textarea { width: 100%; }
.od-field:has(textarea), .od-field:has(.od-multiple) { grid-column: 1 / -1; }
.od-multiple { display: flex; flex-wrap: wrap; gap: .55rem; padding: .65rem; border: 1px solid var(--line); border-radius: 8px; }
.od-multiple label { display: inline-flex; flex-direction: row; align-items: center; gap: .35rem; margin: 0; }
.od-multiple input { width: auto; }
.od-save-interview { min-height: 3.25rem; font-size: 1rem; }
.od-interview-list { display: grid; gap: .55rem; max-height: 65vh; overflow: auto; }
.od-interview-row { display: flex; justify-content: space-between; gap: 1rem; align-items: center; border-bottom: 1px solid var(--line); padding: .65rem 0; }
.od-interview-row div { min-width: 0; display: grid; gap: .15rem; }
.od-interview-row strong { overflow-wrap: anywhere; }
.od-interview-row small { color: var(--muted); }
.od-chart-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
.od-chart { display: grid; grid-template-columns: 9rem 1fr; grid-template-rows: auto 1fr; align-items: center; gap: .8rem 1.2rem; }
.od-chart h3 { grid-column: 1 / -1; margin: 0; }
.od-pie { width: 9rem; aspect-ratio: 1; border-radius: 50%; position: relative; }
.od-pie::after { content: ""; position: absolute; inset: 31%; border-radius: 50%; background: var(--panel); }
.od-chart ul { list-style: none; padding: 0; margin: 0; display: grid; gap: .38rem; }
.od-chart li { display: grid; grid-template-columns: .75rem 1fr auto; gap: .45rem; align-items: center; font-size: .86rem; }
.od-chart li i { width: .7rem; height: .7rem; border-radius: 3px; }
.od-chart li span { overflow-wrap: anywhere; }

@media (max-width: 900px) {
  .od-question-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .od-chart-grid { grid-template-columns: 1fr; }
  .od-entry-card { position: static; }
}

@media (max-width: 620px) {
  .od-question-head { grid-template-columns: 1fr auto; }
  .od-question-head .od-order { grid-column: 1 / -1; padding: 0; }
  .od-question-grid, .od-fields { grid-template-columns: 1fr; }
  .od-options-field, .od-coding-field, .od-field:has(textarea), .od-field:has(.od-multiple) { grid-column: auto; }
  .od-chart { grid-template-columns: 6.5rem 1fr; }
  .od-pie { width: 6.5rem; }
  .od-interview-row { align-items: flex-start; }
}

@media (max-width: 1300px) {
  .study-creation-groups { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .app-shell { display: block; }
  .sidebar { position: static; width: 100%; height: auto; }
  .navigation { grid-template-columns: 1fr 1fr; }
  .prototype-warning { display: none; }
  .topbar { padding: 12px 18px; }
  .topbar select { min-width: 180px; }
  .view { padding: 22px 16px; }
  #view-entry { padding: 7px 5px 3px; }
  .hero, .page-heading { align-items: flex-start; flex-direction: column; }
  .two-columns, .form-grid, .metric-cards, .schedule-editor, .schedule-fields,
  .study-creation-groups { grid-template-columns: 1fr; }
  .lieux-form { grid-template-columns: 1fr; }
  .study-manager-row { grid-template-columns: 1fr auto; }
  .study-manager-stats { grid-column: 1 / -1; grid-row: 2; }
  .type-grid { grid-template-columns: repeat(2, 1fr); }
  .sticky-actions { left: 15px; right: 15px; bottom: 12px; }
  .matrix-wrap { height: calc(100vh - 165px); min-height: 300px; }
}

/* Analyse : disposition des feuilles de résultats — une ligne par indicateur, une colonne
   par passage — avec l'échelle colorée de la macro. */
.indicator-table { width: max-content; min-width: 100%; }
.indicator-table th, .indicator-table td { text-align: center; white-space: nowrap; }
/* Colonnes d'heures resserrées : elles ne portent que deux ou trois caractères et leur
   largeur d'origine était payée par la carte, à droite. L'en-tête passe à la verticale
   pour tenir dans la même colonne que ses valeurs. */
.side-map-layout .indicator-table th, .side-map-layout .indicator-table td { padding: 3px 4px; font-size: 12px; }
.side-map-layout .indicator-table thead th:not(.indicator-label) { padding: 5px 3px; font-size: 11px; }
.side-map-layout .indicator-table .indicator-label { min-width: 130px; padding: 3px 8px; }
.indicator-table .indicator-label { text-align: left; font-weight: 700; background: #f4f7f5; position: sticky; left: 0; z-index: 2; }
.indicator-table td { border: 1px solid #d8e0dc; font-variant-numeric: tabular-nums; }
.indicator-table .average-cell { font-weight: 700; background: #eef3f0; }
.indicator-table tr.section-start td { border-top: 3px solid #a6baaf; }
.synthesis-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); gap: 18px; margin-top: 18px; }
.synthesis-grid .analysis-table th, .synthesis-grid .analysis-table td { text-align: center; }
.synthesis-grid .analysis-table th:first-child, .synthesis-grid .analysis-table td:first-child { text-align: left; }
.chart { overflow-x: auto; }
.chart svg { display: block; width: 100%; min-width: 560px; height: auto; }
.chart-grid { stroke: #e2e9e5; stroke-width: 1; }
.chart-axis { fill: var(--muted); font-size: 10px; font-weight: 600; }
.chart-total { fill: var(--ink); font-size: 10px; font-weight: 700; }
.chart-line { fill: none; stroke: #2F5597; stroke-width: 2; }
.chart-legend { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 4px; color: var(--muted); font-size: 12px; font-weight: 600; }
.chart-legend span { display: flex; align-items: center; gap: 6px; }
.chart-legend i { width: 12px; height: 12px; border-radius: 3px; }
/* La pastille hachuree de la legende : meme lecture que les barres, hors emplacement.
   Neutre en couleur, c'est le motif qui porte l'information. */
.chart-legend .chart-legend-motif { background: repeating-linear-gradient(45deg,#c9d2cd 0 2px,#17231f 2px 4px); }
.chart-legend .chart-legend-line { height: 3px; border-radius: 0; background: #2F5597; }

.settings-panel { margin-top: 22px; }
.settings-panel p { max-width: 860px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.threshold-preview { display: flex; align-items: center; padding: 11px 13px; border-radius: 6px; background: #f4f7f5; color: var(--muted); font-size: 13px; font-weight: 600; }
.window-panel { margin-bottom: 18px; }
.window-panel p { max-width: 900px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.window-list { display: flex; flex-wrap: wrap; gap: 9px; }
.window-chip { display: flex; align-items: center; gap: 8px; padding: 7px 12px; border: 1px solid #bfd2c9; border-radius: 99px; background: white; font-size: 13px; font-weight: 600; }
.window-chip small { color: var(--muted); font-weight: 600; }
.window-chip button { width: 18px; height: 18px; padding: 0; border: 0; border-radius: 50%; color: #9e3434; background: #f6e6e6; font-weight: 700; line-height: 16px; }
.inventory-buttons { display: flex; gap: 10px; flex-wrap: wrap; }
.window-actions { display: flex; align-items: end; gap: 12px; flex-wrap: wrap; }
/* La barre du périmètre : le créneau et la zone que suit l'écran. Elle se pose au-dessus
   du contenu qu'elle commande, jamais ailleurs — on doit voir sous quelle hypothèse on lit. */
.perimetre-barre { display: flex; align-items: end; gap: 14px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 10px 14px; border: 1px solid var(--line);
  border-radius: 8px; background: #f7faf8; }
.perimetre-barre small { color: var(--muted); font-weight: 600; }
.inline-field { display: grid; gap: 3px; font-size: 12px; font-weight: 600; color: var(--muted); }
.inline-field select { min-height: 36px; }
/* Un bloc complet par créneau, côte à côte : chiffres, tableaux, graphiques et typologies
   se comparent d'une période à l'autre — pas seulement le tableau des indicateurs. */
.window-block { min-width: 0; }
.window-block-title { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; }
.window-block-title h2 { font-size: 19px; }
.window-block-title small { color: var(--muted); font-weight: 600; }
/* Chaque colonne choisit son créneau et sa zone : les réglages se posent dans la colonne
   qu'ils commandent, pas dans une barre commune qui ne pourrait en régler qu'une. */
.window-block-choix { display: flex; align-items: end; gap: 12px; flex-wrap: wrap;
  margin-bottom: 12px; padding: 9px 12px; border: 1px solid var(--line);
  border-radius: 6px; background: #f7faf8; }
.lien-discret { border: 0; background: none; padding: 4px 2px; color: #9e3434;
  font-size: 12px; font-weight: 700; cursor: pointer; text-decoration: underline; }
.window-block-compare .metric-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.window-block-compare .synthesis-grid { grid-template-columns: 1fr; }
/* Les seize passages tiennent dans la colonne sans défilement : deux tableaux voisins
   doivent s'aligner ligne à ligne, sinon la comparaison se fait de mémoire. La largeur
   se prend sur les cellules — resserrées — et jamais sur la hauteur des lignes, qui doit
   rester identique d'une colonne à l'autre. */
.indicator-table-compacte { table-layout: fixed; width: 100%; }
.indicator-table-compacte th, .indicator-table-compacte td {
  padding: 4px 2px; font-size: 11px; text-align: center; overflow: hidden;
  text-overflow: ellipsis; }
/* Le libellé revient à la ligne plutôt que d'être coupé : « NON MATERIALISEE » doit se
   lire en entier. Les deux colonnes portent les mêmes libellés, donc la hauteur de ligne
   reste la même de l'une à l'autre — l'alignement tient. */
.indicator-table-compacte .indicator-label {
  width: 116px; padding: 4px 7px; font-size: 10.5px; text-align: left;
  white-space: normal; line-height: 1.2; overflow: visible; }
.indicator-table-compacte thead th { padding: 6px 2px; font-size: 10px; }
/* `table-layout: fixed` ne lit les largeurs que sur la première rangée : c'est l'en-tête
   qui fixe la colonne des libellés, pas les cellules du corps. Sans cette règle, la
   colonne tombait à vingt-deux pixels utiles et tous les libellés étaient coupés. */
.indicator-table-compacte thead th:first-child { width: 126px; }
/* Les autres tableaux d'un bloc tiennent aussi sans défilement : les intitulés reviennent
   à la ligne, les chiffres se resserrent, et la première colonne garde de quoi nommer sa
   ligne. Faire défiler un tableau, c'est perdre l'alignement avec la colonne d'à côté. */
.tableau-compact { width: 100%; table-layout: fixed; }
.tableau-compact th, .tableau-compact td {
  padding: 5px 3px; font-size: 11px; text-align: center;
  white-space: normal; overflow-wrap: anywhere; }
.tableau-compact thead th { font-size: 10px; letter-spacing: 0; }
.tableau-compact .colonne-libelle { width: 84px; text-align: left; padding-left: 8px; }
.tableau-compact tbody .colonne-libelle { font-size: 11px; }
/* Le tableau section par section porte deux colonnes de tête — la zone et la section —
   avant la catégorie : c'est à elles trois de tenir dans la largeur laissée par la carte. */
.table-sections thead th:nth-child(1) { width: 62px; }
.table-sections thead th:nth-child(2) { width: 54px; }
.table-sections thead th:nth-child(3) { width: 104px; }
.table-sections td:nth-child(1), .table-sections td:nth-child(2) {
  font-size: 10px; text-align: left; white-space: normal; line-height: 1.15; }
/* Données détaillées : aucune ligne ne se dédouble (demande d'Eddy du 23/08) — zone,
   section et catégorie restent sur une seule ligne, en plus petit, et les colonnes de
   passage récupèrent la largeur. */
.table-sections th, .table-sections td { padding: 3px 2px; font-size: 10.5px; }
.table-sections .indicator-label {
  white-space: nowrap; overflow: visible; font-size: 10px; line-height: 1.2;
}
.table-sections thead th:nth-child(3) { width: 118px; }
.table-sections td:nth-child(1), .table-sections td:nth-child(2) {
  white-space: nowrap; font-size: 9.5px;
}
/* Un graphique par ligne, sur toute la largeur du bloc : deux par ligne, chacun devait
   défiler horizontalement pour montrer ses seize passages. Le dessin s'étire désormais à
   la largeur disponible et sa hauteur suit ses proportions — proportions rendues
   identiques pour les six graphiques d'une pile, sans quoi celui des trois classes de
   durée était près de deux fois plus haut que ses voisins. */
/* Un graphique par ligne : le tracé à gauche, la lecture qu'on en fait à droite. */
.window-block .charts-pair { grid-template-columns: 1fr; }
/* Deux colonnes qui se remplissent : le tracé occupe toute la sienne, l'encadré la
   sienne sur toute la hauteur du tracé. Un graphique posé au milieu du vide avec une
   petite boîte de texte en coin, c'était l'inverse de ce que ces deux colonnes doivent
   montrer — le dessin et sa lecture, à parts comparables. */
.graphique-et-lecture { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px; align-items: stretch; }
.lecture-graphique { display: flex; flex-direction: column; gap: 5px; font-size: 12px;
  font-weight: 600; color: var(--muted); }
/* Le texte se lit à côté d'un graphique, pas dans un formulaire : plus gros, centré, et
   aéré. Il reste modifiable — c'est une zone de saisie — mais il doit d'abord se lire. */
.lecture-graphique textarea { width: 100%; flex: 1; min-height: 150px; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 6px; background: #fbfdfc;
  font: inherit; font-size: 15px; font-weight: 400; color: var(--ink); line-height: 1.7;
  text-align: center; resize: vertical; }
.lecture-graphique textarea:focus { outline: 2px solid var(--green-2); outline-offset: 1px; }
.lecture-graphique small { min-height: 14px; font-size: 11px; font-weight: 600;
  color: var(--green-2); }
/* En comparaison, la colonne est déjà étroite : la lecture passe sous son graphique
   plutôt que de lui prendre la moitié de la largeur. */
.window-block-compare .graphique-et-lecture { grid-template-columns: 1fr; }
.window-block-compare .lecture-graphique textarea { min-height: 90px; }
@media (max-width: 1180px) { .graphique-et-lecture { grid-template-columns: 1fr; } }
/* En colonne, et non en ligne : le conteneur porte le tracé **puis** sa légende. Mis en
   ligne, la légende devenait une seconde colonne haute de 420 px à côté du graphique. */
.window-block .charts-pair .chart {
  overflow-x: visible; display: flex; flex-direction: column; align-items: stretch; }
/* Le plafond de hauteur : sans lui, un bloc seul occupe toute la largeur de l'écran et
   le dessin, qui garde ses proportions, montait à sept cent cinquante pixels — il fallait
   faire défiler la page pour voir un seul graphique. Passé le plafond, c'est la largeur
   qui se réduit, et le tracé se centre. */
/* Le tracé prend toute la largeur de sa colonne ; sa hauteur suit ses proportions, qui
   sont les mêmes pour les six graphiques — ils gardent donc la même hauteur. */
.window-block .charts-pair .chart svg {
  width: 100%; height: auto; min-width: 0; max-width: 100%; }
.window-block .charts-single { grid-template-columns: 1fr; }
.window-tables { display: grid; grid-template-columns: repeat(auto-fit, minmax(520px, 1fr)); gap: 18px; }
/* Les panneaux et les éléments de chaque graphique partagent les rangées de la
   grille parente. alignerComparaisons les associe par leur identité et calcule le
   nombre de rangées, y compris lorsqu'une colonne ne possède pas tous les graphiques.
   Sans subgrid, l'empilement ordinaire reste disponible. */
@supports (grid-template-rows: subgrid) {
  .aligned-comparison > :is(.window-block, .typology-column) {
    display: grid; grid-template-rows: subgrid;
    grid-row: span var(--comparison-rows); align-content: start;
  }
  .aligned-comparison > .window-block > .charts-pair,
  .aligned-comparison > .window-block > .charts-pair > article,
  .aligned-comparison > .typology-column > .typology-chart {
    display: grid; grid-template-rows: subgrid; grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
  }
  .aligned-comparison > .window-block > .charts-pair > article > .graphique-et-lecture,
  .aligned-comparison > .window-block > .charts-pair .chart,
  .aligned-comparison > .typology-column > .typology-chart > .chart { display: contents; }
  .aligned-comparison .report-chart-choice { grid-row: 1; }
  .aligned-comparison > .window-block > .charts-pair .panel-heading,
  .aligned-comparison > .typology-column > .typology-chart > h3 { grid-row: 2; }
  .aligned-comparison > .window-block > .charts-pair svg,
  .aligned-comparison > .typology-column > .typology-chart svg { grid-row: 3; align-self: start; }
  .aligned-comparison > .window-block > .charts-pair .chart-legend,
  .aligned-comparison > .typology-column > .typology-chart .chart-legend { grid-row: 4; }
  .aligned-comparison > .window-block > .charts-pair .lecture-graphique { grid-row: 5; }
}

/* Le parent borne le bandeau : arrivé à la rangée suivante, il cède sa place.
   Ne pas créer de conteneur de défilement sur ces parents (overflow: hidden/auto). */
.analysis-sticky-heading,
.typology-columns > .typology-column > .typology-title {
  position: sticky; top: var(--analysis-sticky-top, 60px); z-index: 10; align-self: start;
}
.analysis-sticky-heading { background: var(--paper, #f3f6f4); padding: 8px 0;
  border-bottom: 1px solid var(--line); }
.analysis-sticky-heading .window-block-choix { margin-bottom: 0; }
.typology-columns > .typology-column { overflow: clip; }
@media print {
  .analysis-sticky-heading, .typology-columns > .typology-column > .typology-title {
    position: static;
  }
}
.window-tables .panel { min-width: 0; }
.window-tables .panel-heading small { display: block; margin-top: 4px; color: var(--muted); font-weight: 600; }
.aggregate-row td { background: #eef3f0; }
.total-row td { border-top: 2px solid #a6baaf; font-weight: 700; }

.typology-view-actions { display: flex; align-items: end; gap: 10px; }
.column-count-control { display: grid; gap: 4px; color: var(--muted); font-size: 11px; font-weight: 700; }
.column-count-control select { min-width: 74px; padding: 7px 26px 7px 9px; }
.typology-group { margin-bottom: 18px; }
/* Le nombre est choisi séparément dans chaque onglet et conservé sur le poste. Toutes
   les colonnes d'un rang gardent la même largeur ; le dernier rang ne s'étale jamais. */
.typology-columns { display: grid; grid-template-columns: repeat(var(--typology-column-count, 3), minmax(0, 1fr)); gap: 16px; }
.typology-column { min-width: 0; border: 1px solid var(--line); border-radius: 8px;
  overflow: hidden; background: white; }
/* Toutes les colonnes réservent la place du sous-titre de la colonne Illicite. Son
   intitulé sur deux lignes ne décale ainsi plus tous les graphiques qui le suivent. */
.typology-title { display: flex; align-items: center; justify-content: space-between; gap: 6px;
  min-height: 50px; padding: 7px 10px; box-sizing: border-box;
  font-size: 15px; font-weight: 700; text-align: center; }
.typology-title > span { flex: 1; min-width: 0; }
.typology-title small { display: block; margin-top: 1px; font-size: 10px; font-weight: 600; opacity: .78; text-transform: uppercase; letter-spacing: .04em; }
.typology-move { border: 0; background: rgb(255 255 255 / 22%); color: inherit; border-radius: 6px; min-height: 24px; padding: 2px 7px; font-size: 11px; font-weight: 700; cursor: pointer; }
.typology-move:hover:not(:disabled) { background: rgb(255 255 255 / 40%); }
.typology-move:disabled { opacity: .35; cursor: default; }
.typology-figures { display: flex; justify-content: space-around; gap: 10px; padding: 9px 8px; background: #f7faf8; color: var(--muted); font-size: 11px; font-weight: 600; text-align: center; }
.typology-figures strong { display: block; margin-top: 2px; color: var(--ink); font-size: 15px; }
.typology-chart { margin: 8px; padding: 10px 8px; border: 1px solid var(--line);
  border-radius: 6px; background: white; }
.typology-chart h3 { margin: 0 0 6px; font-size: 12px; text-align: center; }
.typology-chart .chart svg { min-width: 0; }
/* Le choix reste exact quelle que soit la taille de la fenêtre. Les cartes peuvent devenir
   étroites si six colonnes sont demandées, mais l'interface ne remplace jamais le réglage
   explicite de l'utilisateur par une valeur responsive cachée. */

/* --- Cartes ------------------------------------------------------------- */
.map-panel { margin-bottom: 18px; }
.map-panel p { max-width: 900px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.map-toolbar { display: flex; flex-wrap: wrap; gap: 12px; align-items: end; }
.map-toolbar .map-controls { display: flex; flex-wrap: wrap; gap: 12px; align-items: end; }
.map-toolbar label { display: flex; flex-direction: column; font-size: 12px; }
.map-toolbar select { min-width: 170px; }
.map-frame { overflow: hidden; border: 1px solid var(--line); border-radius: 8px; }
.map-canvas { height: 460px; background: #eef2f0; }
/* L'offre de l'étude, au-dessus de sa carte. */
.inventory-offer {
  /* Encadré centré sous le titre, en pleine lecture : le total sur sa ligne, le détail
     en dessous et en retrait, pour qu'on lise « tant de places, dont ceci, dont cela »
     sans avoir à démêler une enfilade de nombres. */
  max-width: 620px; margin: 0 auto 14px; padding: 14px 22px;
  border: 1px solid var(--line); border-radius: 10px; background: white;
  font-size: 15px; line-height: 1.7; color: var(--muted);
}
.inventory-offer strong { display: block; font-size: 17px; color: var(--ink); }
/* Un poste par ligne, précédé d'un tiret, et son détail sous un « dont : ». Une
   énumération séparée par des points médians se lit comme une phrase, alors qu'on vient
   y compter des postes un par un. */
.inventory-offer .offre-poste { display: block; padding-left: 1.2em; }
.inventory-offer .offre-dont { display: flex; gap: .5em; padding-left: 2.6em; }
.inventory-offer .offre-dont-mot { flex: none; }
/* Le « + » en grand : les places spécifiques ne s'additionnent pas aux ordinaires, et
   rien ne doit laisser croire le contraire. */
.inventory-offer .offre-plus { padding-left: .4em; }
.inventory-offer .signe-plus { font-size: 26px; line-height: 1; vertical-align: -3px; margin-right: .15em; }
.inventory-offer b { color: var(--ink); }

/* Inventaire et Cartographie montrent la même feuille A4 paysage. La feuille garde
   toujours la hauteur du viewport moins la barre supérieure et les commandes (60 + 34 px).
   Sa position dans la page ne change donc jamais sa taille. */
#inventory-map-frame {
  width: min(100%, calc((100vh - 94px) * 297 / 210)); max-height: none;
  height: calc(100vh - 94px); margin: 0 auto;
  aspect-ratio: 297 / 210; background: #eef2f0;
}
#inventory-map-frame .carto-iframe { width: 100%; height: 100%; border: 0; display: block; }
#inventory-map-frame .empty-state { display: grid; place-items: center; height: 100%; }

/* Leaflet empile ses calques à partir de z-index 400. Sans contexte d'empilement
   propre, ils s'échappaient au-dessus de la barre d'étude, qui n'est qu'à 20 : la
   carte passait par-dessus la bannière au défilement. `isolation` les enferme. */
.leaflet-container { isolation: isolate; }

.map-legend { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 12px; color: var(--muted); font-size: 12px; font-weight: 600; }
.side-map .map-legend { gap: 5px 9px; margin-top: 6px; font-size: 10px; }
.map-legend span { display: flex; align-items: center; gap: 6px; }
.map-legend i { width: 16px; height: 5px; border-radius: 3px; }
/* « Sans stationnement » se dessine en tireté sur la carte : la pastille le montre tireté,
   sinon la légende annonce une couleur pleine qu'aucune section ne porte. */
.map-legend i.legend-dashed {
  background: repeating-linear-gradient(90deg, #222 0 4px, transparent 4px 7px) !important;
  border-radius: 0;
}
.map-note { color: var(--muted); font-size: 12px; font-weight: 600; }
/* Réglage de la taille des étiquettes, sur le modèle du « Rendu » de la carte assemblée. */
.etiquette-echelle { display: flex; align-items: center; gap: 6px; height: 38px; align-self: flex-end; }
.etiquette-echelle label { font-size: 12px; color: var(--muted); font-weight: 600; }
.etiquette-echelle button {
  width: 26px; min-height: 26px; padding: 0; border: 1px solid #cbd7d1; border-radius: 6px;
  background: white; font-weight: 700; line-height: 1; cursor: pointer;
}
.etiquette-echelle button:hover { border-color: var(--accent); }
.etiquette-echelle output { min-width: 42px; font-size: 12px; font-weight: 600; text-align: center; }
.map-note-warning { color: #86580e; }
.leaflet-container { font: inherit; }
/* La carte de Données détaillées reprend la fiche complète de la cartographie : les
   libellés restent alignés pendant que le curseur suit une section étroite. */
.leaflet-tooltip.statio-tooltip-fiche {
  padding: 0; overflow: hidden; border: 1px solid #cad5d0; border-radius: 8px;
  background: #fff; color: var(--ink); box-shadow: 0 4px 14px rgba(18, 45, 36, .18);
}
.statio-tooltip-complet { min-width: 220px; font-size: 12px; line-height: 1.25; }
.statio-tooltip-entete {
  padding: 8px 10px; background: #edf4f0; color: var(--ink); font-size: 13px;
}
.statio-tooltip-entete small {
  display: block; margin-top: 2px; color: var(--muted); font-size: 10px;
  text-transform: uppercase; letter-spacing: .04em;
}
.statio-tooltip-complet table { width: 100%; border-collapse: collapse; }
.statio-tooltip-complet th, .statio-tooltip-complet td {
  padding: 2px 9px; border: 0; background: #fff; font-size: 11px;
}
.statio-tooltip-complet th { color: #43544d; font-weight: 500; text-align: left; }
.statio-tooltip-complet td { font-weight: 700; text-align: right; white-space: nowrap; }
.photo-pin {
  display: grid; place-items: center; border: 2px solid white; border-radius: 50%;
  background: var(--green); color: white; font-size: 10px; font-weight: 700;
  box-shadow: 0 2px 6px rgba(0,0,0,.35);
}
#details-body tr.section-highlight td { box-shadow: inset 0 0 0 2px var(--green); }
#details-body tr[data-section-name] { cursor: pointer; }
/* La case du nom est le bouton d'ouverture de la section : elle se voit comme telle —
   couleur de marque, relief, et le mot « Zoomer » dessous. Un curseur en main ne se
   remarque qu'une fois la souris dessus, donc trop tard pour qui cherche quoi cliquer. */
#details-body td.section-open {
  background: linear-gradient(180deg, #ffffff, #e8f3ed);
  border-left: 3px solid var(--green);
  box-shadow: 0 1px 0 #b9d2c5 inset, 0 2px 4px rgb(27 52 43 / 12%);
  border-radius: 4px;
  vertical-align: middle;
}
#details-body td.section-open strong { color: var(--green-2); white-space: nowrap; }
/* Le chevron reste collé au numéro : la colonne des sections est étroite, et posé après
   le mot « Zoomer » il ajoutait une troisième ligne à la case. */
#details-body td.section-open strong::after {
  content: " ⤢"; color: var(--green); font-weight: 700;
}
#details-body tr[data-section-name]:hover td.section-open {
  background: linear-gradient(180deg, #f2fbf6, #d6ebe0);
}
#details-body tr.section-highlight td.section-open {
  background: linear-gradient(180deg, #e2f4ea, #c9e6d8);
}

/* Étiquette portée par une section : son numéro et son offre, écrits sur le tracé.
   Le fond translucide et le liseré blanc la gardent lisible aussi bien sur un plan clair
   que sur une vue aérienne. `pointer-events` la rend transparente au clic, sinon elle
   masquerait la section qu'elle désigne. */
/* L'ancre ne fait que porter la position ; l'étiquette elle-même est centrée dessus et
   pivotée pour suivre le trait de sa section. */
.section-label-anchor { width: 0 !important; height: 0 !important; pointer-events: none; overflow: visible; }
/* Étiquette nue à halo blanc, comme celles du visualiseur cartographique — c'est la
   différence qu'Eddy voyait en premier entre les deux cartes, le 13/08. Elle était posée
   ici dans une pastille blanche bordée et ombrée : sur un plan dense, cent pastilles
   masquent le fond de plan qu'elles sont censées annoter, et deux cartes du même relevé
   qui n'écrivent pas pareil se lisent comme deux relevés.

   Le gabarit trace le halo en SVG (`label-halo`, `paint-order: stroke`). En HTML la même
   lecture s'obtient par une ombre portée blanche répétée autour du glyphe : huit directions
   sans flou dessinent un contour net plutôt qu'un nuage. `--halo` et le corps sont posés
   en ligne par `carte.js`, qui les calcule sur le zoom. */
.section-label {
  position: absolute; display: inline-block;
  width: auto !important; height: auto !important;
  pointer-events: none; white-space: nowrap;
  font-family: "MS Shell Dlg 2", Arial, sans-serif;
  color: #111; font-weight: 700; line-height: 1.25; text-align: center;
  --halo: 2.6px;
  text-shadow:
    var(--halo) 0 0 #fff, calc(var(--halo) * -1) 0 0 #fff,
    0 var(--halo) 0 #fff, 0 calc(var(--halo) * -1) 0 #fff,
    calc(var(--halo) * .7) calc(var(--halo) * .7) 0 #fff,
    calc(var(--halo) * -.7) calc(var(--halo) * .7) 0 #fff,
    calc(var(--halo) * .7) calc(var(--halo) * -.7) 0 #fff,
    calc(var(--halo) * -.7) calc(var(--halo) * -.7) 0 #fff;
}
.section-label b { font-weight: 700; }
/* Valeur en bleu, entre parenthèses, à côté du numéro : c'est la lecture retenue par les
   consignes cartographiques, et elle distingue d'un coup d'œil l'identité de la mesure.
   Teinte relevée dans `LABEL_PLACE_COLOR` du gabarit. */
.section-label i { color: #138fd0; font-style: normal; font-weight: 700; }

/* Disposition « tableau à gauche, carte à droite ». La carte est collée en haut de la
   fenêtre : on descend dans les résultats sans jamais la perdre de vue. */
/* Le tableau s'étire pour remplir la largeur qu'on lui donne : ses colonnes d'heures ne
   se resserrent donc pas en jouant sur leur contenu, mais en rendant de la place à la
   carte. Les deux se partagent l'écran à parts presque égales. */
.side-map-layout { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(380px, .95fr); gap: 16px; align-items: start; }
/* Sans fichier SIG, la carte se masque — et sa colonne restait réservée : le tableau
   gardait 548 px sur un écran de 1366, l'autre moitié vide, alors qu'il a seize passages à
   montrer. Mesuré au navigateur le 13/08 sur une étude sans cartographie, un cas normal
   puisque toutes n'en ont pas. La colonne libérée revient au tableau. */
.side-map-layout:has(> .side-map.hidden) { grid-template-columns: minmax(0, 1fr); }
.side-map { position: sticky; top: 88px; margin-bottom: 0; padding: 12px; }
.side-map .panel-heading { display: block; }
.side-map .panel-heading p { max-width: none; margin-top: 4px; font-size: 12px; line-height: 1.4; }
.side-map .map-toolbar { margin: 0 0 7px; gap: 5px 8px; }
.side-map .map-toolbar select { min-width: 0; width: 100%; }
.side-map .map-toolbar label { flex: 1 1 105px; font-size: 10px; line-height: 1.15; }
.side-map .map-toolbar select { min-height: 31px; margin-top: 3px; padding: 5px 24px 5px 7px;
  font-size: 11px; }
.side-map .map-toolbar .checkbox-label { flex: 0 0 auto; height: 27px; gap: 4px;
  margin-right: 7px; font-size: 10px; }
.side-map .map-toolbar .checkbox-label input { width: 13px; min-width: 13px; height: 13px; }
.side-map .map-toolbar .etiquette-echelle { height: 31px; gap: 3px; }
.side-map .map-toolbar .etiquette-echelle label,
.side-map .map-toolbar .etiquette-echelle output { font-size: 10px; }
.side-map .map-toolbar .etiquette-echelle output { min-width: 34px; }
.side-map .map-toolbar .etiquette-echelle button { width: 23px; min-height: 23px; font-size: 11px; }
@media (max-width: 1250px) { .side-map-layout { grid-template-columns: 1fr; } .side-map { position: static; } }

/* Cadres au format d'une feuille A4, dans le sens du périmètre cartographié : la carte est
   vue à l'écran telle qu'elle sortira de l'imprimante.

   Le cadre doit tenir tout entier dans la fenêtre. Une planche qu'il faut faire défiler
   pour voir en entier ne se juge pas : on ne sait plus si le périmètre entre dans la page.
   La hauteur est donc plafonnée à ce que la fenêtre laisse au panneau, et c'est la largeur
   qui cède — le rapport A4 est tenu par `aspect-ratio` dans les deux sens. */
.frame-a4-landscape, .frame-a4-portrait { margin: 0 auto; }
/* Le rapport A4 est tenu par `aspect-ratio` : la hauteur se déduit de la largeur. Sur un
   panneau large, une planche PORTRAIT devient une fois et demie plus haute que large et
   sort de l'écran — c'est ce qu'on voyait sur l'inventaire de TM04, dont l'emprise est
   plus haute que large. On plafonne donc la largeur pour que la hauteur tienne dans la
   fenêtre : le format reste juste, et `margin: 0 auto` garde la planche centrée.
   Plafonner la hauteur ne conviendrait pas — la largeur ne suivrait pas et le cadre
   cesserait d'être au format A4.

   Un plancher, en revanche, est nécessaire. Sans lui, une fenêtre un peu basse — ou une
   barre d'outils qui s'allonge d'un réglage — rétrécissait la planche jusqu'à la rendre
   inutilisable. Sous ce plancher, c'est la page qui défile, ce qui est le moindre mal :
   une carte trop petite ne se lit pas du tout, une carte à faire défiler se lit encore. */
.frame-a4-landscape {
  aspect-ratio: 297 / 210;
  width: min(100%, max(620px, (100vh - 210px) * 297 / 210));
}
.frame-a4-portrait {
  aspect-ratio: 210 / 297;
  width: min(100%, max(460px, (100vh - 210px) * 210 / 297));
}
.side-map .frame-a4-portrait {
  width: min(100%, max(460px, (100vh - 150px) * 210 / 297));
}
/* Déclarée après la règle générale pour l'emporter sur elle : l'écran des mobilités porte
   une rangée de boutons de plus, il lui faut un peu plus de marge. */
.mobilites-carte-a4 { width: min(100%, calc((100vh - 280px) * 297 / 210)); }
.frame-a4-landscape .map-canvas, .frame-a4-portrait .map-canvas { height: 100%; }
#details-map, #observations-map { height: 520px; }
.frame-a4-landscape #details-map, .frame-a4-portrait #details-map,
.frame-a4-landscape #observations-map, .frame-a4-portrait #observations-map { height: 100%; }
/* La case à cocher n'a pas de libellé au-dessus, contrairement aux listes voisines : sans
   ce calage, elle flotte plus haut qu'elles et la rangée paraît de travers. */
.checkbox-label { display: flex; flex-direction: row !important; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; }
.map-toolbar .checkbox-label { height: 38px; align-self: flex-end; }
.checkbox-label input { width: 15px; height: 15px; min-height: 0; margin: 0; }

/* --- Observations -------------------------------------------------------- */
#view-observations { padding-top: 6px; padding-bottom: 8px; }
#view-observations .page-heading { align-items: center; gap: 12px; margin-bottom: 6px; }
#view-observations .page-heading h1 { margin: 0; font-size: 22px; }
#view-observations .pass-count-badge,
#view-observations .pass-controls button { padding: 6px 10px; }
#observations-map-panel { top: 68px; padding: 8px; }
#observations-map-frame { width: 100%; margin: 0 auto; }
/* Même partage que « Données détaillées » : la carte dispose de presque la moitié de
   l'écran, donc ses quatre listes et ses boutons ne sont plus comprimés sur trois lignes.
   La galerie conserve deux photos par rangée dans la moitié restante. */
.observations-layout {
  grid-template-columns: minmax(0, 1.05fr) minmax(380px, .95fr);
}
.observations-layout .photo-gallery { grid-column: auto; }
.photo-gallery { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; align-content: start; }
@media (max-width: 1250px) {
  .observations-layout { grid-template-columns: 1fr; }
  .observations-layout .photo-gallery { grid-column: auto; }
}
@media (max-width: 820px) { .photo-gallery { grid-template-columns: 1fr; } }

/* --- Cartographie --------------------------------------------------------- */
/* La carte web est une application à part entière : elle occupe tout l'espace restant,
   dans un cadre isolé pour que ses styles et les nôtres ne se contrarient pas. */
/* La carte prime sur le bandeau de démonstration : en défilant, elle passe par-dessus
   (même niveau que le bandeau, mais plus tard dans la page — elle gagne). L'avertissement
   reste affiché partout ailleurs, et la carte porte de toute façon sa propre marque. */
#carto-frame, .carto-frame { position: relative; z-index: 19; }
#carto-frame { width:100%; height:calc(100dvh - 64px); min-height:240px;
  margin:0; border:1px solid var(--line); border-radius:8px;
  overflow:hidden; background:white; }
.carto-iframe { width: 100%; height: 100%; border: 0; display: block; }
#carto-frame .empty-state { display: grid; place-items: center; height: 100%; }
.photo-card { position: relative; margin: 0; border: 1px solid var(--line); border-radius: 8px; background: white; overflow: hidden; box-shadow: 0 8px 30px rgba(27,52,43,.05); }
.photo-card img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: #eef2f0; cursor: zoom-in; }
.photo-selected { outline: 3px solid var(--green); outline-offset: 2px; }
.photo-pin-active { background: #17231f !important; transform: scale(1.35); z-index: 900 !important; }
.photo-index { position: absolute; top: 10px; left: 10px; z-index: 2; display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--green); color: white; font-size: 12px; font-weight: 700; }
.photo-card figcaption { display: grid; gap: 8px; padding: 12px 14px 14px; }
.photo-section { font-size: 15px; }
.photo-card label { font-size: 11px; }
.photo-card input, .photo-card select { min-height: 34px; margin-top: 3px; padding: 6px 9px; font-size: 13px; }
/* `wrap` depuis le geste de revue : la ligne portait trois éléments, elle en porte quatre,
   et sans repli le nom du fichier écrasait les boutons sur une carte étroite. */
.photo-meta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; color: var(--muted); font-size: 11px; }
.photo-meta button { min-height: 28px; padding: 4px 9px; font-size: 11px; }
.photo-highlight { outline: 3px solid var(--green); outline-offset: 2px; }

/* --- Synthèse ------------------------------------------------------------ */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 16px; margin-bottom: 18px; }
.kpi { padding: 20px; border-radius: 8px; border: 1px solid var(--line); background: white; }
.kpi strong { display: block; font-size: 38px; line-height: 1.05; letter-spacing: -.03em; }
.kpi span { display: block; margin-top: 6px; font-size: 13px; font-weight: 600; line-height: 1.35; }
.kpi em { display: block; margin-top: 4px; color: var(--muted); font-size: 11px; }
.kpi-alert { border-color: #e9b4b4; background: #fdf3f3; } .kpi-alert strong { color: #a53131; }
.kpi-warn { border-color: #e6cf9c; background: #fffaf0; } .kpi-warn strong { color: #8a5f10; }
.kpi-calm { border-color: #b9d5c9; background: #f6fbf8; } .kpi-calm strong { color: var(--green); }
.synthesis-columns { display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: 18px; }
.synthesis-list { margin: 0; padding-left: 20px; display: grid; gap: 12px; line-height: 1.6; }
.synthesis-leads li { color: #3d4c46; }
.synthesis-editor { width: 100%; min-height: 96px; box-sizing: border-box; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 7px; background: #fbfcfb; color: var(--ink);
  overflow: hidden; font: inherit; line-height: 1.6; resize: none; }
.synthesis-editor:focus { outline: 2px solid var(--green-2); outline-offset: 1px; background: white; }
.synthesis-save-state { display: block; min-height: 16px; margin-top: 6px; color: var(--green);
  font-size: 11px; font-weight: 600; }
.synthesis-copy { white-space: pre-wrap; line-height: 1.6; }

/* La synthèse tient dans la fenêtre. Chaque cadre conserve la hauteur de son texte ; le
   script resserre les deux textes seulement si le plus long atteindrait le bas de l'écran. */
.app-shell:not(.client-app-shell) #view-synthesis.active {
  display: flex; flex-direction: column; box-sizing: border-box;
  height: var(--synthesis-height, calc(100vh - 60px)); overflow: hidden;
  padding: 7px 14px 9px;
}
.app-shell:not(.client-app-shell) #view-synthesis > .page-heading {
  flex: none; align-items: center; margin: 0 0 6px;
}
.app-shell:not(.client-app-shell) #view-synthesis > .page-heading h1 {
  margin: 0; font-size: 21px;
}
.app-shell:not(.client-app-shell) #synthesis-content {
  display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0;
}
.app-shell:not(.client-app-shell) #synthesis-content > .perimetre-barre {
  flex: none; gap: 8px; margin-bottom: 7px; padding: 5px 9px;
}
.app-shell:not(.client-app-shell) #synthesis-content > .perimetre-barre .inline-field {
  gap: 2px; font-size: 10px;
}
.app-shell:not(.client-app-shell) #synthesis-content > .perimetre-barre select {
  min-height: 29px; margin-top: 2px; padding: 4px 26px 4px 8px; font-size: 11px;
}
.app-shell:not(.client-app-shell) #synthesis-content > .perimetre-barre small {
  font-size: 10px;
}
.app-shell:not(.client-app-shell) #synthesis-content > .kpi-row {
  flex: none; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 7px;
  margin-bottom: 7px;
}
.app-shell:not(.client-app-shell) #view-synthesis .kpi { padding: 9px 11px; }
.app-shell:not(.client-app-shell) #view-synthesis .kpi strong { font-size: 28px; }
.app-shell:not(.client-app-shell) #view-synthesis .kpi span {
  margin-top: 3px; font-size: 11px; line-height: 1.2;
}
.app-shell:not(.client-app-shell) #view-synthesis .kpi em {
  margin-top: 2px; font-size: 9px;
}
.app-shell:not(.client-app-shell) #synthesis-content > .synthesis-columns {
  display: grid; flex: 0 0 auto; grid-template-columns: 1fr 1fr; min-height: 0;
  align-items: start; gap: 8px;
}
.app-shell:not(.client-app-shell) #synthesis-content > .synthesis-columns > .panel {
  display: flex; flex-direction: column; width: 100%; min-height: 0; padding: 11px;
}
.app-shell:not(.client-app-shell) #synthesis-content .synthesis-columns .panel-heading {
  flex: none; margin-bottom: 6px;
}
.app-shell:not(.client-app-shell) #synthesis-content .synthesis-columns h2 {
  margin: 0; font-size: 19px;
}
.app-shell:not(.client-app-shell) #synthesis-content .synthesis-columns .panel-heading small {
  font-size: 9px;
}
.app-shell:not(.client-app-shell) #synthesis-content .synthesis-editor {
  flex: none; height: auto; min-height: 0; padding: 9px 11px; overflow: hidden; resize: none;
  font-size: 13px; line-height: 1.4;
}
.app-shell:not(.client-app-shell) #synthesis-content .synthesis-save-state {
  flex: none; min-height: 11px; margin-top: 2px; font-size: 9px; line-height: 1.1;
}
@media (max-width: 1000px) { .synthesis-columns { grid-template-columns: 1fr; } }

/* --- Rapport : page de garde et page de fin ------------------------------ */
.report-page { position: relative; display: flex; flex-direction: column; margin-bottom: 26px; padding: 46px; min-height: 640px; border: 1px solid var(--line); border-radius: 8px; background: white; box-shadow: 0 12px 40px rgba(27,52,43,.07); }
.analysis-validation-actions { display: flex; align-items: center; justify-content: flex-end; gap: 9px; flex-wrap: wrap; }
.validation-status {
  padding: 8px 11px; border: 1px solid #a9d2bf; border-radius: 99px;
  background: var(--mint); color: var(--green); font-size: 12px; font-weight: 700;
}
.validation-locked-note { border-color: #9fc9b6; background: #eaf6f0; }
.study-readonly .observation-cell { pointer-events: none; }
.study-readonly input:disabled, .inventory-table input:disabled {
  opacity: 1; color: var(--ink); background: #f4f7f5; cursor: default;
}
.cover-logo-manager {
  display: grid; grid-template-columns: minmax(220px, 1fr) auto auto; gap: 12px 18px;
  align-items: center; margin-bottom: 16px; padding: 14px 16px;
}
.cover-logo-manager > div:first-child span { display: block; margin-top: 3px; color: var(--muted); font-size: 12px; }
.cover-date-editor label { display: grid; gap: 3px; color: var(--muted); font-size: 12px; }
.cover-date-editor input { min-height: 36px; }
.cover-logo-actions { display: flex; gap: 8px; }
.cover-logo-list { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 8px; }
.cover-logo-item {
  display: grid; grid-template-columns: 72px minmax(100px, 1fr) auto auto; gap: 9px;
  align-items: center; min-width: 370px; padding: 7px; border: 1px solid var(--line);
  border-radius: 7px; background: #f8fbf9;
}
.cover-logo-item img { width: 72px; height: 44px; padding: 3px; object-fit: contain; background: white; }
.cover-logo-item small { display: block; max-width: 180px; overflow: hidden; color: var(--muted); text-overflow: ellipsis; white-space: nowrap; }
.cover-logo-item button { min-width: 30px; min-height: 30px; padding: 3px; }
.cover-logo-size { display: flex; align-items: center; gap: 5px; }
.cover-logo-size output { min-width: 45px; color: var(--muted); font-size: 12px; text-align: center; }
.cover-logo-empty { color: var(--muted); font-size: 12px; }
.report-brand { display: flex; align-items: center; gap: 12px; }
.report-brand strong { display: block; font-size: 19px; }
.report-brand small { display: block; color: var(--muted); }
/* Page de garde : une feuille A4 paysage dont l'image occupe toute la surface.

   L'illustration tenait dans une colonne de gauche, donc dans un format debout : elle ne
   montrait qu'une bande du secteur. Elle couvre désormais la feuille entière, au format
   dans lequel la page sera imprimée. Un périmètre en longueur — TM04 fait 260 m sur 539 —
   ne remplit un paysage qu'en découvrant du terrain alentour : c'est voulu, une couverture
   situe le secteur dans sa ville plutôt que de le cadrer au plus juste.

   Le bloc de titre est posé par-dessus, sur un voile sombre : le texte reste lisible sans
   que l'image soit tronquée. */
.page-a4-landscape { aspect-ratio: 297 / 210; min-height: 0; margin: 0 auto 26px; padding: 0; overflow: hidden; }
.report-cover { position: relative; display: block; }
.cover-logos {
  position: absolute; z-index: 3; left: 3.5%; display: flex; align-items: center;
  flex-wrap: wrap; gap: 9px; max-width: 57%;
}
.cover-client-logos { top: 3.5%; }
.cover-producer-logos { bottom: 3.5%; }
.cover-logos img {
  width: auto;
  height: calc(56px * var(--cover-logo-scale, 1));
  max-width: calc(145px * var(--cover-logo-scale, 1));
  padding: 6px 8px;
  border-radius: 6px; object-fit: contain; background: rgba(255,255,255,.94);
  box-shadow: 0 3px 12px rgba(0,0,0,.16);
}
/* `z-index: 0` n'est pas décoratif : il **enferme** la carte dans son propre contexte
   d'empilement. Sans lui, un conteneur Leaflet en `position: relative; z-index: auto` n'en
   crée aucun, et ses calques internes — numérotés de 200 à 800 par la bibliothèque —
   remontent au niveau du bloc de titre, qui n'est qu'à 2. Le titre s'affichait donc
   correctement, puis disparaissait sous les tuiles dès qu'elles arrivaient. */
.cover-visual { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: #0d1a15; }
/* Un cartouche en haut à droite plutôt qu'un bandeau sur toute la hauteur : la vue
   aérienne est l'illustration de la page, et le flou lui mangeait 38 % de la largeur sur
   toute sa hauteur. Le texte y tient largement — titre, commune, date — et la photographie
   se voit enfin. Le dégradé descend sous le cartouche pour que le pied de page reste
   lisible sur une ortho claire. */
.cover-text {
  position: absolute; z-index: 2; inset: 0 0 auto auto; width: 30%;
  display: flex; flex-direction: column; gap: 4px; padding: 3.5% 3.5% 4%;
  color: white; backdrop-filter: blur(7px);
  border-bottom-left-radius: 14px;
  background: linear-gradient(160deg, rgba(10,22,18,.88) 0%, rgba(10,22,18,.80) 60%, rgba(10,22,18,0) 100%);
}
.cover-text .eyebrow { color: #b9d9cc; }
.cover-date { margin: 6px 0 0; font-size: 13px; color: #cfe2da; }
.report-cover .report-footer { position: absolute; right: 3.5%; bottom: 3%; z-index: 2; }
.report-cover .report-brand strong { color: white; }
.report-cover .report-brand small, .report-cover .report-subtitle,
.report-cover .report-footer { color: white; background: rgba(15,39,31,.88); padding: 7px 10px; border-radius: 4px; }
.report-cover .report-facts div { background: rgba(255,255,255,.12); }
.report-cover .report-facts dt { color: #b9d9cc; }
.report-cover .report-facts dd { color: white; }
.cover-photo { width: 100%; height: 100%; object-fit: cover; }
.cover-empty { display: grid; place-items: center; align-content: center; gap: 10px; padding: 30px; text-align: center; color: #b9d9cc; }
.cover-missing strong { font-size: 16px; color: white; }
.cover-missing p { margin: 0; max-width: 380px; line-height: 1.5; font-size: 13px; }
.cover-missing code { padding: 7px 10px; border-radius: 8px; background: rgba(255,255,255,.1); color: #d8ece3; font-size: 11px; word-break: break-all; }
.report-cover h1 { margin: 8px 0 6px; font-size: clamp(22px, 2.3vw, 38px); line-height: 1.1; }

/* L'illustration est une vue aérienne à plat, qui remplit la feuille. Une bascule en
   perspective avait été essayée : elle obligeait à agrandir la carte pour couvrir les
   coins, donc à reculer pour compenser, et le rendu se discutait à chaque réglage pour un
   gain d'illustration nul. Une image nette du secteur dit la même chose sans détour. */
.cover-map { width: 100%; height: 100%; }
.cover-visual .leaflet-control-container { display: none; }
.report-subtitle { margin: 0; color: var(--muted); font-size: 17px; font-weight: 600; }
/* Deux colonnes fixes : les quatre chiffres forment un carré, là où un ajustement
   automatique les cassait en trois plus un. */
.report-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 22px 0 0; }
.report-facts div { padding: 14px; border-radius: 8px; background: #f4f7f5; }
.report-facts dt { color: var(--muted); font-size: 11px; font-weight: 700; text-transform: uppercase; }
.report-facts dd { margin: 5px 0 0; font-size: 20px; font-weight: 700; }
.report-footer { margin-top: auto; padding-top: 24px; color: var(--muted); font-size: 13px; }
.report-closing { justify-content: center; align-items: center; text-align: center; background: linear-gradient(135deg, #145c45, #0d3d2e); color: white; }
.report-closing .eyebrow { color: #b9d9cc; }
.report-closing h2 { margin: 10px 0 18px; font-size: 32px; }
.report-closing p { max-width: 620px; margin: 0 auto 12px; line-height: 1.6; color: #dcece5; }
.report-note { font-size: 13px; color: #b9d9cc !important; }
.report-brand-end { justify-content: center; margin-top: 30px; }
.report-brand-end small { color: #b9d9cc; }
@media print {
  .sidebar, .topbar, .page-heading button, .nav-button, .nav-lien { display: none !important; }
  .cover-logo-manager { display: none !important; }
  .view { padding: 0; }
  .report-page { page-break-after: always; box-shadow: none; border: 0; min-height: 96vh; }
}

/* --- Administration ------------------------------------------------------- */
.admin-panel { margin-top: 22px; }
.admin-panel .panel-heading p { max-width: 900px; margin-top: 6px; color: var(--muted); line-height: 1.5; }
.organisation-card { padding: 16px; margin-bottom: 12px; border: 1px solid var(--line); border-radius: 8px; background: #f8fbf9; }
.organisation-card.interne { border-color: #b9d5c9; background: #f2f9f5; }
.organisation-card.demo { border-color: #d49a37; background: #fff9e8; }
.demo-tag {
  display: inline-block; margin-left: 7px; padding: 3px 7px; border-radius: 99px;
  background: #ffd45c; color: #5c3900; font-size: 10px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}

/* La carte de démonstration ne porte plus de bandeau par-dessus : il cachait la carte,
   et le fictif est déjà dit par le nom du dossier et l'attribution en coin de carte.
   La classe reste posée — c'est le marqueur structurel qui coupe les tuiles réelles. */
.organisation-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.organisation-head strong { font-size: 16px; }
.organisation-head small { color: var(--muted); }
.access-list { display: grid; gap: 7px; margin: 12px 0; }
.access-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 12px; align-items: center; padding: 8px 11px; border-radius: 6px; background: white; border: 1px solid var(--line); }
.access-row small { display: block; margin-top: 2px; color: var(--muted); font-size: 12px; }
.access-row button { min-height: 30px; padding: 4px 9px; font-size: 12px; }
.access-done { color: var(--green); }
.access-pending { color: #86580e; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.access-form { display: flex; flex-wrap: wrap; gap: 9px; align-items: end; }
.access-form label { flex: 1 1 190px; font-size: 12px; }
.access-form input { min-height: 36px; }
.archived-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 14px; align-items: center; padding: 10px 12px; border-bottom: 1px solid var(--line); }
.archived-row:last-child { border-bottom: 0; }
.archived-row small { color: var(--muted); font-size: 12px; }
.admin-empty { padding: 18px; color: var(--muted); text-align: center; }

/* --- Connexion ------------------------------------------------------------ */
.session-gate { position: fixed; inset: 0; z-index: 1600; display: grid; place-items: center; padding: 24px; background: linear-gradient(135deg, #145c45, #0d3d2e); }
.session-card { width: 100%; max-width: 420px; padding: 32px; border-radius: 8px; background: white; box-shadow: 0 24px 70px rgba(0,0,0,.3); }
.session-card .brand { margin-bottom: 22px; }
.session-card .brand strong { color: var(--ink); }
.session-card h1 { margin: 0 0 6px; font-size: 26px; }
.session-card p { margin: 0 0 20px; color: var(--muted); line-height: 1.5; }
.session-card form { display: grid; gap: 14px; }
.session-card label { display: grid; gap: 5px; font-size: 13px; font-weight: 600; }
.session-card input { min-height: 42px; padding: 9px 12px; }
.session-error { padding: 11px 13px; border-radius: 6px; background: var(--red-soft); color: var(--red); font-size: 13px; line-height: 1.45; }
.session-ok { background: var(--mint); color: var(--green); }
.link-button { margin-top: 14px; padding: 0; border: 0; background: none; color: var(--green); font-size: 13px; font-weight: 600; text-decoration: underline; }
.session-account { display: flex; align-items: center; gap: 12px; }
.session-account small { display: block; color: var(--muted); font-size: 11px; }
.session-account button { min-height: 30px; padding: 4px 10px; font-size: 12px; }

/* ============================ Comptage routier ============================ */

/* Journées retenues : une ligne de cases par date, cochables d'un geste. */
.jours { display: flex; flex-wrap: wrap; gap: 10px 22px; margin: 10px 0 4px; }
.jours .jour { display: inline-flex; align-items: center; gap: 8px;
  font-weight: 600; color: var(--ink); }

/* Le sélecteur de modules. Il est au-dessus de la navigation parce qu'il la commande :
   changer de métier change tous les onglets en dessous. */
/* Les métiers ne tiennent pas côte à côte : au-delà de deux, les libellés débordaient du
   cadre. Une colonne les rend tous lisibles, y compris les futurs OD et RPM, et le module
   actif se voit d'un coup d'œil. */
.modules { display: grid; gap: 2px; margin-bottom: 0; padding: 4px; border-radius: 8px; background: #0b211a; }
.module-button {
  padding: 6px 12px; line-height: 1.3; border: 0; border-radius: 6px; background: transparent;
  color: #9ab3a8; font-weight: 600; font-size: 13px; text-align: left; white-space: nowrap;
}
.module-button:hover { color: #dcebe4; }
.module-button.active { color: #102d24; background: #bce0d0; }

/* Listes de lieux : le tracé prépare une donnée de terrain, il reste visible au-dessus des
   catalogues enregistrés au lieu d'être enfermé dans une boîte de dialogue. */
.lieux-zone-panel { margin-bottom: 22px; }
.lieux-zone-panel .panel-heading p { max-width: 900px; margin: 7px 0 0; color: var(--muted); line-height: 1.5; }
.lieux-toolbar { margin-bottom: 13px; }
.lieux-toolbar .map-note { flex: 1 1 270px; align-self: center; }
.lieux-form { margin-top: 16px; grid-template-columns: minmax(280px, 1fr) auto; }
.lieux-form .source-banner { margin: 0; align-self: end; }
.lieux-columns { align-items: start; }
.lieux-columns > .panel { min-width: 0; }
.lieux-catalogues { display: grid; gap: 9px; max-height: 610px; overflow-y: auto; }
.lieux-catalogue {
  width: 100%; padding: 13px 14px; border: 1px solid var(--line); border-radius: 6px;
  color: var(--ink); background: #f8faf9; text-align: left;
}

/* --------------------------------------------------------------- Module RPM */
.rpm-study-list { display: grid; gap: .7rem; }
.rpm-entry-form { margin-top: 1rem; border-top: 1px solid var(--line); padding-top: 1rem; }
#rpm-postes input:not([type="checkbox"]), #rpm-relations input, #rpm-relations select { min-width: 7rem; }
#rpm-relations [data-rpm-relation="name"] { min-width: 13rem; }
/* Le plan de réglage du carrefour RPM : même hauteur que celui du directionnel, et les
   pointes de flèche reprennent la pointe des remontées de file, colorées par sens. */
/* Un bloc au format A4 paysage, à la mesure de l'écran : aussi haut que la fenêtre le
   permet une fois les réglages et le tableau comptés, jamais plus large que le panneau,
   centré. Ce qu'on y cadre est ce qui sortira sur une planche. Demande d'Eddy du 15/09. */
.rpm-plan {
  /* Cadre A4 paysage calé sur la HAUTEUR de l'écran : sa hauteur remplit la place laissée
     par la barre du haut, le titre et le formulaire (~230 px), et sa largeur en découle par
     le ratio 297/210 — jamais plus large que le panneau. Ainsi le cadre tient toujours dans
     l'écran sans le faire défiler. Le contenu (décor de démo portrait, ou postes d'une
     étude) garde son format à l'intérieur, centré. Réglé avec Eddy les 15-16/09/2026. */
  aspect-ratio: 297 / 210; width: min(100%, calc(82vh * 1.4143)); height: auto;
  margin: .9rem auto; border-radius: 8px; overflow: hidden; border: 1px solid var(--line);
  background: #eef1ef;
}
.rpm-carrefour-form { margin-bottom: .4rem; }
.rpm-carrefour-form .field-label { display: block; font-weight: 600; margin-bottom: .3rem; }
.rpm-creneaux-table { margin: 0 0 .4rem; }
.rpm-creneaux-table input { width: 100%; box-sizing: border-box; }
.rpm-creneaux-table th:last-child, .rpm-creneaux-table td:last-child { width: 5rem; text-align: right; }
.rpm-nouveau-poste { justify-content: flex-start; align-items: center; gap: .6rem; margin-bottom: .6rem; }
/* Le même bloc, une fois posé en contrôle sur la carte : une carte blanche compacte en haut
   à droite, le sélecteur au-dessus du bouton. */
.rpm-nouveau-poste.rpm-plan-control {
  flex-direction: column; align-items: stretch; gap: 6px; margin: 0;
  background: #fff; padding: 8px 10px; border-radius: 8px; box-shadow: 0 1px 6px rgba(16,45,36,.35);
}
.rpm-nouveau-poste.rpm-plan-control .field-inline { flex-direction: column; align-items: stretch; gap: 3px; white-space: nowrap; }
.rpm-nouveau-poste.rpm-plan-control select, .rpm-nouveau-poste.rpm-plan-control button { width: 100%; }
.rpm-nouveau-poste .field-inline { white-space: nowrap; }
.rpm-arrow-head { background: none; border: 0; }
.rpm-arrow-head span {
  display: block; width: 0; height: 0;
  border-left: 8px solid transparent; border-right: 8px solid transparent;
  border-bottom: 16px solid #444;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .45));
}
.rpm-trajet-form { justify-content: flex-start; align-items: end; margin-bottom: .6rem; }
/* Le schéma des flux : un cadre A4 paysage lui aussi, le SVG s'y étale. */
.rpm-schema { aspect-ratio: 297 / 210; width: min(100%, calc(82vh * 1.4143)); margin: .8rem auto 0; }
.rpm-schema svg { width: 100%; height: 100%; }
.rpm-schema-poste { fill: white; font-size: 15px; font-weight: 700; }
.rpm-schema-nom { font-size: 12px; font-weight: 600; paint-order: stroke; stroke: white; stroke-width: 3px; }
.rpm-schema-valeur { font-size: 15px; font-weight: 700; paint-order: stroke; stroke: white; stroke-width: 4px; }
/* Le chiffre d'un flux posé sur le fond de carte : un petit nombre cerné de blanc, centré
   sur le milieu de la flèche (icône Leaflet de taille nulle, le span se recentre lui-même). */
.rpm-carte-valeur { background: none; border: 0; }
.rpm-carte-valeur span {
  display: inline-block; transform: translate(-50%, -50%); white-space: nowrap;
  font-size: 13px; font-weight: 800;
  text-shadow: 0 0 3px #fff, 0 0 3px #fff, 1px 1px 2px #fff, -1px -1px 2px #fff;
}
/* La pastille de couleur d'un mouvement, en tête de sa ligne : même teinte que sa flèche. */
.rpm-mvt-puce {
  display: inline-block; width: .8rem; height: .8rem; border-radius: 3px;
  margin-right: .5rem; vertical-align: -1px;
}
.rpm-trajet-chemin { font-variant-numeric: tabular-nums; }
/* Le tableau des postes : colonnes serrées pour laisser la place aux liaisons. */
.rpm-postes-table td:nth-child(2) input { min-width: 8rem; }
.rpm-postes-table th:nth-child(3), .rpm-postes-table th:nth-child(4),
.rpm-postes-table td:nth-child(3), .rpm-postes-table td:nth-child(4) { text-align: center; white-space: nowrap; }
/* Chaque poste nettement séparé du suivant : bordure épaisse pleine largeur (portée par les
   cellules, donc visible quel que soit le mode de bordure) — utile quand les cases
   « Points accessibles » s'enroulent sur deux lignes. */
.rpm-postes-table tbody td { border-bottom: 3px solid #9aa4b2; padding-top: .55rem; padding-bottom: .55rem; vertical-align: middle; }
/* La colonne « Points accessibles » : une case cochable par autre poste. Le flex est sur le
   div intérieur, pas sur le <td> (sans quoi la cellule sort du tableau et sa bordure se
   désaligne des autres colonnes). Les cases s'enroulent si la largeur manque. */
.rpm-acces-cases { display: flex; flex-wrap: wrap; gap: .2rem .55rem; align-items: center; }
.rpm-acces-case {
  display: inline-flex; align-items: center; gap: .15rem; white-space: nowrap;
  font-variant-numeric: tabular-nums; font-size: .82rem; color: var(--muted, #555);
}
.rpm-acces-case input { margin: 0; }
.rpm-acces-case.rpm-demitour { font-weight: 700; color: var(--accent, #146c43); }
.rpm-od-matrix th { text-align: center; }
.rpm-od-matrix th:first-child { text-align: left; width: 1%; white-space: nowrap; }
.rpm-od-matrix td { text-align: center; font-variant-numeric: tabular-nums; }
.rpm-suggestion-list { margin-top: 1rem; border-top: 1px solid var(--line); padding-top: 1rem; }
.rpm-suggestion-list h3 { margin: 0 0 .75rem; }
.rpm-suggestion { display: grid; grid-template-columns: minmax(12rem, 1fr) auto auto auto;
  gap: .6rem; align-items: center; padding: .65rem 0; border-bottom: 1px solid var(--line); }
.rpm-suggestion strong { color: #9f1239; letter-spacing: .04em; }
@media (max-width: 900px) {
  .rpm-suggestion { grid-template-columns: 1fr; }
}
.lieux-catalogue:hover, .lieux-catalogue.active { border-color: #77b49c; background: var(--mint); }
.lieux-catalogue strong, .lieux-catalogue span, .lieux-catalogue small { display: block; }
.lieux-catalogue span { margin-top: 5px; color: var(--green); font-size: 13px; font-weight: 600; }
.lieux-catalogue small { margin-top: 3px; color: var(--muted); }
.lieux-actions { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 12px; }
.lieux-source { margin: 0 0 14px; }
.lieux-table-wrap { max-height: 430px; margin-top: 8px; overflow: auto; border: 1px solid var(--line); border-radius: 6px; }
.lieux-table-wrap table { width: 100%; min-width: 670px; border-collapse: collapse; }
.lieux-table-wrap th { position: sticky; top: 0; z-index: 1; background: #edf4f0; }
.lieux-table-wrap th, .lieux-table-wrap td { padding: 8px 10px; border-bottom: 1px solid var(--line); text-align: left; font-size: 12px; }
.lieux-table-wrap tr:last-child td { border-bottom: 0; }

.dropzone {
  padding: 26px; border: 2px dashed var(--line); border-radius: 8px; text-align: center;
  background: #fafcfb; transition: border-color .15s, background .15s;
}
.dropzone.hover { border-color: #3b82f6; background: #eff6ff; }
.dropzone p { margin: 10px 0 0; color: var(--muted); font-size: 13px; }

.import-state { margin-top: 12px; font-size: 13px; white-space: pre-line; color: var(--muted); }
.import-state.warning { color: #92400e; }
.import-state .inline-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; white-space: normal; }

.indicator-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 16px 0; }
.indicator { padding: 14px; border: 1px solid var(--line); border-radius: 8px; background: #fafcfb; }
.indicator strong { display: block; margin: 4px 0 2px; font-size: 26px; line-height: 1.1; }
.indicator small { color: var(--muted); font-size: 12px; }

/* Profil horaire. Deux barres par heure — ouvrés et week-end — parce qu'une moyenne
   unique efface la pointe du matin, qui est ce qu'on cherche à voir. */
.hourly-profile { margin-top: 22px; }
.hourly-profile h3 { margin: 0 0 6px; font-size: 15px; }
.hourly-profile .legend { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; font-size: 12px; color: var(--muted); }
.hourly-profile .swatch { width: 11px; height: 11px; border-radius: 3px; }
.hourly-profile .swatch + .swatch { margin-left: 12px; }
.swatch.weekday, .bar.weekday { background: #2563eb; }
.swatch.weekend, .bar.weekend { background: #f59e0b; }
.hourly-profile .hours { display: grid; grid-template-columns: repeat(24, 1fr); gap: 3px; align-items: end; }
.hourly-profile .hour { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.hourly-profile .bars { display: flex; align-items: flex-end; gap: 2px; height: 110px; width: 100%; justify-content: center; }
.hourly-profile .bar { width: 45%; min-height: 1px; border-radius: 2px 2px 0 0; }
.hourly-profile small { font-size: 10px; color: var(--muted); }

#comptage-points input { width: 100%; padding: 6px 8px; border: 1px solid var(--line); border-radius: 6px; font: inherit; }
#comptage-points td a.secondary { display: inline-block; margin-left: 6px; text-decoration: none; }
#comptage-carte { height: 68vh; border-radius: 8px; overflow: hidden; }
/* La hauteur des cartes est portée par l'identifiant : la classe `carto-frame` seule ne
   mesure rien, et une carte Leaflet dans un cadre de zéro pixel est invisible. */
#trafic-national-carte { height: 62vh; min-height: 420px; border-radius: 8px; overflow: hidden; }

/* Photographies de pose. Deux par ligne en 4/3, comme les observations du stationnement. */
.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; margin-top: 16px; }
/* Ces règles sont cantonnées à `.photo-grid` : sans cette portée, elles écrasaient la
   galerie des observations du stationnement, qui utilise la même classe `.photo-card` et
   se retrouvait sans ses photographies. Deux modules, une même classe : la dernière
   déclaration gagnait, en silence. */
.photo-grid .photo-card { margin: 0; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; background: #fff; }
.photo-grid .photo-card.orpheline { border-color: #f59e0b; }
.photo-grid .photo-card img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: #eef2f0; }
.photo-grid .photo-card figcaption { padding: 9px 11px 4px; display: grid; gap: 2px; }
.photo-grid .photo-card figcaption span { font-size: 12px; color: var(--muted); }
.photo-grid .photo-card figcaption small { font-size: 11px; color: #9aa5a1; overflow-wrap: anywhere; }
.photo-grid .photo-card select { width: calc(100% - 22px); margin: 6px 11px 11px; padding: 5px 7px; border: 1px solid var(--line); border-radius: 6px; font: inherit; font-size: 12px; }

.tag { display: inline-block; padding: 1px 7px; border-radius: 99px; background: #eef2f0; color: var(--muted); font-size: 11px; font-weight: 600; }
.tag.warn { background: #fef3c7; color: #92400e; }
/* Une réserve tient parfois en plusieurs lignes — « données insuffisantes » s'explique.
   La pastille doit alors se comporter en paragraphe, sans cesser de se voir. */
p.tag.warn { display: block; max-width: 620px; margin: 8px 0 0; padding: 8px 12px; border-radius: 6px; font-size: 12px; line-height: 1.45; }
/* Note sous un tableau : elle porte une convention de lecture, pas un commentaire. */
.table-note { margin: 8px 0 0; max-width: 760px; color: var(--muted); font-size: 12px; line-height: 1.5; }
/* Avis posé sur une carte dont le fond n'a pas pu être chargé. Au-dessus des calques
   Leaflet — numérotés jusqu'à 800 — sinon il passerait dessous et personne ne le verrait. */
.fond-absent {
  /* En bas, et non au centre : l'avis dit que les tracés au-dessus sont justes, il aurait
     mauvaise grâce à les recouvrir. */
  position: absolute; z-index: 900; left: 50%; bottom: 14px; transform: translateX(-50%);
  display: grid; gap: 6px; max-width: 460px; padding: 12px 16px; border-radius: 8px;
  border: 1px solid var(--line); background: rgba(255,255,255,.96);
  box-shadow: 0 10px 30px rgba(27,52,43,.14); text-align: center;
}
.fond-absent strong { font-size: 14px; }
.fond-absent span { color: var(--muted); font-size: 12px; line-height: 1.5; }
.fond-absent code { padding: 6px 9px; border-radius: 8px; background: #eef2f0; font-size: 11px; word-break: break-all; }
/* Les planches d'un carrefour : une par période de pointe, côte à côte quand la place le
   permet, l'une sous l'autre sinon. Elles se comparent d'un regard — mêmes branches, mêmes
   couleurs, deux moments — ce qui est tout l'intérêt de les poser ensemble. */
/* Étiquette et champ sur une ligne, dans une barre d'actions. */
.field-inline { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; color: var(--muted); }
/* Sans largeur minimale, le sélecteur se laissait comprimer par la barre d'actions jusqu'à
   couper son propre libellé — « Tableaux » s'affichait « Tableau… ». */
.field-inline select { min-width: 132px; }
.junction-boards { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 18px; }
.junction-board { margin: 0; }
.junction-board .table-scroll { margin-top: 10px; }
/* La carte d'une planche : les entrants et sortants posés en vraies coordonnées, à la même
   place que sur la carte de réglage, et les panneaux de branches tout autour. La hauteur
   suit la fenêtre : les panneaux prennent la place qu'ils prennent, et une carte de 340 px
   ne laissait plus qu'un timbre-poste au carrefour. */
.board-plan { height: min(56vh, 620px); min-height: 420px; margin-top: 10px; border-radius: 8px; overflow: hidden; border: 1px solid var(--line); }
/* Dimensions d'impression, posées **avant** l'appel à l'imprimante et non par une règle
   `@media print`. Une carte Leaflet place ses tuiles en pixels absolus : la redimensionner au
   moment du rendu d'impression décale le fond des flèches sans que rien ne le recale. En la
   redimensionnant d'abord, on peut lui dire de se recalculer, puis imprimer.
   1 000 × 640 pixels tiennent dans une A4 paysage à marges de 12 mm. */
body.impression .board-plan { width: 1000px; height: 640px; min-height: 0; }

/* Le dossier commun est le point de départ du client. Sa liste et ses six lignes d'outils
   doivent rester lisibles comme un parcours, pas comme des fragments de formulaire collés. */
#dossiers-liste { display: grid; gap: 8px; }
#dossiers-liste .list-row {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: 6px;
  background: #fff; color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
#dossiers-liste .list-row:hover { border-color: var(--green); background: #f5fbf8; }
#dossiers-liste .list-row span { color: var(--muted); font-size: 12px; white-space: nowrap; }
.dossier-outil-row {
  display: grid; grid-template-columns: minmax(170px, 230px) minmax(0, 1fr); gap: 16px;
  align-items: center; padding: 14px 0; border-bottom: 1px solid var(--line);
}
.dossier-outil-row:last-child { border-bottom: 0; }
.dossier-outil-row > div:first-child { display: grid; gap: 3px; }
.dossier-outil-row > div:first-child small { color: var(--muted); }
.dossier-outil-row .inline-actions { display: flex; flex-wrap: wrap; align-items: end; gap: 8px; }
.dossier-outil-row .inline-actions > select { flex: 1 1 260px; }
.dossier-outil-row .inline-actions label { min-width: 140px; margin: 0; }
@media (max-width: 860px) {
  .dossier-outil-row { grid-template-columns: 1fr; }
}
/* La planche était bien à 1 000 px, mais **son cadre ne l'était pas** : mesuré le 14/08 en
   média « impression », `.junction-boards` et chaque `.junction-board` faisaient 1 363 px et
   la matrice origine-destination 1 361, contre 1 000 utiles sur une A4 paysage. La carte
   tenait donc dans la page pendant que le tableau qui l'accompagne en sortait, et personne
   ne le voyait à l'écran. La largeur est imposée à tout le bloc, pas seulement à la carte. */
body.impression .junction-boards { grid-template-columns: 1fr; width: 1000px; }
body.impression .junction-board,
body.impression .junction-board .matrix-table { max-width: 1000px; }
body.impression .junction-board .table-scroll { overflow: visible; }
/* Les deux réglages de la planche — ce qu'affichent les schémas, la forme des panneaux —
   restaient visibles à l'impression : ce sont des commandes d'écran, elles n'ont rien à
   faire sur une planche remise à un client. Le `.page-heading` porte le titre, qu'on garde. */
body.impression #view-dir-carto .actions,
body.impression #view-dir-global .actions { display: none !important; }
/* La carte d'ensemble occupe la page entière, dans le format choisi. Marges de 12 mm :
   1 000 × 707 pixels en paysage, 707 × 1 000 en portrait, à 96 points par pouce. */
body.impression #dir-global-carte { width: 1000px; height: 707px; }
body.impression #dir-global-carte.portrait { width: 707px; height: 1000px; }
/* Panneau posé sur la carte, à côté de sa pastille. Le marqueur lui-même est un point sans
   dimension : c'est la classe de côté qui décale le contenu vers l'extérieur, en pixels,
   pour que l'écart à la pastille ne change pas avec le zoom. */
/* Le panneau se saisit à la souris pour le poser ailleurs — il masque parfois la rue qu'on
   voulait montrer. Il capte donc le pointeur, ce qui l'empêche de servir de prise pour faire
   glisser la carte : c'est le prix du réglage, et la carte reste saisissable partout
   ailleurs. */
.branch-overlay { background: none; border: 0; cursor: grab; }
.branch-overlay:active { cursor: grabbing; }
.branch-overlay > div { position: absolute; }
.branch-overlay > div.haut { transform: translate(-50%, calc(-100% - 16px)); }
.branch-overlay > div.bas { transform: translate(-50%, 16px); }
.branch-overlay > div.gauche { transform: translate(calc(-100% - 16px), -50%); }
.branch-overlay > div.droite { transform: translate(16px, -50%); }
.branch-overlay .branch-panel { box-shadow: 0 2px 10px rgba(16, 45, 36, .22); }
.board-plan.sans-fond { background: #eef2f0; }
.junction-board h3 { margin: 0 0 6px; font-size: 13px; }
/* Matrice origine-destination : les chiffres se comparent colonne par colonne, ils sont
   donc centrés sous leur en-tête. Seule la première colonne reste à gauche — c'est un
   libellé de branche, pas une valeur. */
.matrix-table th, .matrix-table td { text-align: center; }
.matrix-table tbody th:first-child, .matrix-table thead th:first-child { text-align: left; }

.directionnel-details .panel-heading { align-items: flex-start; gap: 24px; }
.directionnel-details .panel-heading p { max-width: 820px; }
.detail-groupe { margin-top: 14px; border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.detail-groupe > summary { cursor: pointer; padding: 14px 16px; font-weight: 700; color: var(--green); }
.detail-groupe > summary .tag { float: right; }
.detail-matrices { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 430px), 1fr)); gap: 14px; padding: 0 14px 14px; }
.detail-matrice { min-width: 0; padding: 12px; border-radius: 8px; background: var(--paper); }
.detail-matrice h3 { margin: 0 0 8px; font-size: 15px; }
.blocage-details { padding: 16px; border: 1px solid #d29b31; border-radius: 8px; background: #fff7e5; }
.blocage-details ul { max-height: 320px; overflow: auto; }
.branch-editor { border: 1px solid var(--line); border-radius: 8px; padding: 12px; }
.branch-editor legend { padding: 0 6px; font-weight: 700; color: var(--green); }
.branch-form-row { display: grid; grid-template-columns: 90px minmax(220px, 1fr); gap: 10px; margin-bottom: 10px; }
.branch-form-row label { margin: 0; }
@media (max-width: 620px) { .branch-form-row { grid-template-columns: 1fr; } }
/* Déclaration des mouvements existants. Repliée par défaut : on vient sur cet écran pour
   saisir, pas pour décrire une voirie — mais il faut pouvoir la décrire une fois. */
.movement-setup { margin: 0 0 12px; padding: 10px 14px; border: 1px solid var(--line); border-radius: 8px; background: #f7faf8; }
.movement-setup summary { cursor: pointer; font-weight: 600; font-size: 13px; }
.movement-setup > p { margin: 8px 0 10px; max-width: 720px; color: var(--muted); font-size: 12px; line-height: 1.5; }
.movement-setup .table-scroll { max-width: 560px; }
.movement-setup label { display: grid; place-items: center; gap: 2px; cursor: pointer; }
.movement-setup label span { font-size: 10px; color: var(--muted); font-weight: 600; }
.movement-setup td.demi-tour { background: #eef2f0; }
.movement-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.movement-etat:empty { display: none; }
.movement-etat { margin: 10px 0 0; padding: 8px 12px; border-radius: 6px; font-size: 12px; line-height: 1.5; background: #eef2f0; color: var(--muted); }
.movement-etat.warning { background: #fef3c7; color: #92400e; }
/* Rappel des branches au-dessus d'une grille de mouvements : « A » ne se retient pas. */
.branch-key { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 0 0 10px; font-size: 12px; color: var(--muted); }
.branch-key span { display: inline-flex; align-items: baseline; gap: 6px; }
.branch-key b { display: inline-grid; place-items: center; min-width: 20px; height: 20px; border-radius: 6px; background: #1f5f4b; color: white; font-size: 11px; }
/* Marqueur de branche sur le plan : la même lettre que le schéma et que les colonnes de
   saisie, pour qu'on passe de l'un à l'autre sans traduction. */
/* Légende des sens, dans le chapeau de la carte : la couleur y est dite une fois, et les
   flèches n'ont plus besoin d'être expliquées. */
.legend-sens { display: block; margin-top: 6px; }
.legend-sens i {
  display: inline-block; width: 16px; height: 4px; border-radius: 2px;
  margin: 0 5px 0 12px; vertical-align: middle;
}
.legend-sens i:first-child { margin-left: 0; }
.legend-sens i.sens1 { background: #c0392b; }
.legend-sens i.sens2 { background: #1d4ed8; }
.legend-sens i.trafic-concede { background: #d98014; }
.legend-sens i.trafic-non-concede { background: #1d7a5d; }
/* Chiffre posé au bout d'une flèche de sens : cerné de blanc pour rester lisible sur
   n'importe quel fond de carte. */
.flow-label { background: none; border: 0; cursor: grab; }
.flow-label:active { cursor: grabbing; }
.flow-label span {
  display: block; text-align: center; font-size: 12px; font-weight: 700; color: #12324a;
  text-shadow: 0 0 3px white, 0 0 3px white, 0 0 3px white, 0 0 3px white;
  transform-origin: center center;
}
/* Point de mesure : une pastille, avec sa référence au survol. Déplaçable, parce que le GPS
   d'un compteur est celui de l'appareil et que deux appareils voisins se recouvrent. */
.point-pin { background: none; border: 0; cursor: grab; }
.point-pin:active { cursor: grabbing; }
.point-pin span {
  display: block; width: 16px; height: 16px; border-radius: 50%;
  background: #12324a; border: 3px solid white; box-shadow: 0 1px 4px rgba(16,45,36,.5);
  overflow: hidden; text-indent: -999px;
}
/* Poignée d'orientation : un anneau creux, pour ne pas la confondre avec la pastille pleine
   de la branche — l'une règle la position, l'autre la direction. */
.bearing-handle { background: none; border: 0; cursor: grab; }
.bearing-handle:active { cursor: grabbing; }
.bearing-handle span {
  display: block; width: 18px; height: 18px; border-radius: 50%;
  border: 4px solid currentColor; background: white; box-shadow: 0 1px 4px rgba(16,45,36,.4);
}
/* Le centre du carrefour : une mire, pas une pastille. Il ne désigne pas un relevé mais un
   repère, et se distingue donc des points de branche par la forme autant que par la couleur. */
.junction-center { background: none; border: 0; cursor: grab; }
.junction-center:active { cursor: grabbing; }
.junction-center span {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  border: 2px dashed #5a6b64; background: rgba(255, 255, 255, .45);
}
.junction-center i { width: 6px; height: 6px; border-radius: 50%; background: #5a6b64; }
/* Bouton qui se lit comme un lien : il est au milieu d'une phrase, et un bouton plein y
   ferait un pavé au beau milieu du texte. */
button.lien {
  padding: 0; border: 0; background: none; font: inherit; color: inherit;
  text-decoration: underline; cursor: pointer;
}
.branch-pin { background: none; border: 0; }
.branch-pin span {
  display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%;
  background: #1f5f4b; color: white; font-size: 12px; font-weight: 700;
  border: 2px solid white; box-shadow: 0 2px 6px rgba(16,45,36,.45);
}

/* Rapport de comptage : mise en pages pour l'impression, d'où sort le PDF. */
.print-page { margin-bottom: 26px; }
.print-page.cover h1 { margin: 0 0 4px; font-size: 30px; }
.cover-sub { margin: 0 0 2px; font-size: 17px; color: var(--muted); }
.cover-meta { margin: 0 0 18px; font-size: 13px; color: var(--muted); }
.cover-note { margin-top: 14px; font-size: 12px; color: var(--muted); font-style: italic; }
.photo-grid.report { grid-template-columns: repeat(2, 1fr); }
.photo-grid.report .photo-card select { display: none; }
.actions { display: flex; gap: 8px; }

@media print {
  /* Ne s'imprime que le rapport : la navigation, les formulaires et les boutons n'ont rien
     à faire dans un document remis à un client. */
  .sidebar, .topbar, .no-print, .session-gate, .prototype-warning, .audit-warning { display: none !important; }
  .app-shell, .main-content { display: block; margin: 0; padding: 0; }
  .view { display: none !important; }
  /* La vue affichée s'imprime, quelle qu'elle soit. Seul le rapport de comptage était
     autorisé : les boutons « Imprimer / PDF » des directionnels sortaient une page blanche,
     ce qui ne se distingue pas d'une panne d'imprimante. */
  .view.active, .view#view-comptage-rapport { display: block !important; }
  /* Les planches s'impriment l'une sous l'autre, une par page : côte à côte, chacune ferait
     la moitié d'une largeur d'A4 et les panneaux posés autour du carrefour deviendraient
     illisibles. */
  .junction-boards { grid-template-columns: 1fr; }
  .junction-board { break-inside: avoid; break-after: page; }
  .junction-board:last-child { break-after: auto; }
  /* Le plan de paramétrage ne s'imprime pas : c'est l'outil de réglage — pastilles
     déplaçables, poignées d'orientation, boutons de zoom —, pas un livrable. Il sortait en
     pleine page, sans flux ni chiffres, avant les planches qui, elles, disent quelque chose.
     Le même fond de carte est sous chaque planche, au cadrage qu'on lui a donné ici. */
  #view-dir-carto > .panel:first-of-type { display: none !important; }
  .panel { border: 0; box-shadow: none; padding: 0; }
  /* Une page par sens de circulation, et un tableau qui ne se coupe pas au milieu d'une
     ligne — une journée à cheval sur deux pages se relit deux fois. */
  .print-page { break-after: page; margin: 0 0 12mm; }
  .print-page:last-child { break-after: auto; }
  table, .indicator-grid, .hourly-profile, .photo-card { break-inside: avoid; }
  tr { break-inside: avoid; }
  .table-scroll { overflow: visible !important; }
  body { background: #fff; font-size: 11px; }
  /* Aucune orientation imposée. Un `size: A4 portrait` en CSS **désactive** le choix
     portrait/paysage dans la boîte d'impression du navigateur : l'utilisateur cochait
     « paysage » et sortait du portrait sans comprendre pourquoi. Les marges, elles, restent
     fixées — elles ne se règlent pas depuis la boîte. */
  @page { margin: 12mm; }
}

/* Répartition des longueurs. Elle est là pour qu'un seuil se place en voyant la donnée,
   et non en reprenant un chiffre par habitude. */
.length-chart { margin: 4px 0 18px; }
.length-chart .bars { display: flex; align-items: flex-end; gap: 1px; height: 120px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.length-chart .bars span { flex: 1; min-height: 1px; background: #2563eb; border-radius: 1px 1px 0 0; }
.length-chart .bars span:hover { background: #1d4ed8; }
.length-chart .scale { display: flex; justify-content: space-between; margin-top: 4px; font-size: 11px; color: var(--muted); }
.length-chart .hint { margin: 6px 0 0; font-size: 12px; color: var(--muted); }
.checkbox { display: flex; align-items: flex-start; gap: 8px; font-weight: 500; }
.checkbox input { width: auto; margin-top: 3px; }
.checkbox small { display: block; color: var(--muted); font-size: 11px; }

/* Grille horaire éditable. Les couleurs reprennent la convention du tableur : jaune pour
   ce qui a été complété par moyenne, bleu pour ce que l'opérateur a rectifié. */
.grid-controls { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; margin-bottom: 12px; }
.grid-controls label { display: grid; gap: 3px; font-size: 12px; font-weight: 600; color: var(--muted); }
.grid-controls .grow { flex: 1; min-width: 240px; }
.grid-controls select, .grid-controls input { padding: 6px 8px; border: 1px solid var(--line); border-radius: 6px; font: inherit; }
.legend-grid { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 4px 0 2px; font-size: 12px; color: var(--muted); }
.legend-grid .swatch-cell + span, .legend-grid span + .swatch-cell { margin-left: 10px; }
.swatch-cell { display: inline-block; width: 13px; height: 13px; border: 1px solid var(--line); border-radius: 3px; }
.swatch-cell.mesuree { background: #fff; }
.swatch-cell.estimee { background: #FFF3C4; }
.swatch-cell.corrigee { background: #DBEAFE; }
.grid-day { margin-bottom: 22px; }
.grid-day h3 { margin: 0 0 6px; font-size: 14px; }
.grid-table { font-size: 12px; }
.grid-table th { position: sticky; top: 0; background: #f4f7f6; white-space: nowrap; }
.grid-table td { text-align: center; min-width: 44px; }
.grid-table td[contenteditable]:focus { outline: 2px solid #2563eb; background: #fff; }
.grid-table td.estimee { background: #FFF3C4; }
.grid-table td.corrigee { background: #DBEAFE; font-weight: 600; }
.grid-table td.invalide { background: #FEE2E2; outline: 2px solid #dc2626; }
.grid-table td.total { font-weight: 600; background: #f4f7f6; }
kbd { padding: 1px 5px; border: 1px solid var(--line); border-radius: 4px; background: #f4f7f6; font-size: 11px; }

/* Carrefours. Deux représentations côte à côte : le schéma se lit, le plan situe. */
.branch-panel {
  width: 186px; padding: 7px 9px 8px; border: 1px solid var(--line);
  border-top: 3px solid var(--teinte); border-radius: 8px; background: white;
}
.branch-panel header { display: flex; align-items: center; gap: 8px; }
/* Enfant **direct** de l'en-tête : la pastille seule. Sans le `>`, la règle attrapait aussi
   les nombres en gras du bloc de flux, qui s'affichaient en pastilles de couleur empilées. */
.branch-panel header > b {
  display: inline-grid; place-items: center; flex: 0 0 auto; width: 22px; height: 22px;
  border-radius: 50%; background: var(--teinte); color: white; font-size: 12px;
}
/* Les deux totaux de la branche, en grille : le libellé à gauche, le chiffre aligné à
   droite. Sur une seule ligne courante, « vers le carrefour 393 · en retour 604 » passait à
   la ligne au milieu d'un nombre. */
.branch-panel-flux {
  display: grid; grid-template-columns: 1fr auto; gap: 0 8px; margin: 0;
  font-size: 10px; line-height: 1.4; color: var(--muted);
}
.branch-panel-flux i { font-style: normal; }
.branch-panel-flux b { color: var(--ink); font-size: 11px; }
.branch-panel-note { margin: 3px 0 0; font-size: 10px; color: var(--muted); text-align: center; }
.branch-panel-vide { margin: 4px 0 0; font-size: 11px; color: var(--muted); }
.branch-table { width: 100%; font-size: 12px; }
.branch-table th, .branch-table td { padding: 2px 4px; text-align: center; }
/* La destination se dit par sa lettre et sa couleur, comme sur le plan. Le nom de la rue est
   au survol, et écrit en clair sur le plan à côté de sa pastille. */
.branch-table td.dest { width: 26px; font-size: 12px; }
/* Le nom de la voie dans la colonne « De / Vers » : en second rang derrière la lettre, qui
   reste la clé de lecture de toute la page. */
.matrix-table th.voie-de { white-space: nowrap; }
.matrix-table th.voie-de .voie { margin-left: 6px; font-weight: 600; color: var(--muted); font-size: 11px; }
.branch-table td.picto { width: 22px; }
.branch-table td.part { color: var(--muted); white-space: nowrap; }
.branch-table tfoot th, .branch-table tfoot td { border-top: 1px solid var(--line); font-weight: 700; }
.picto-tour { display: block; width: 18px; height: 18px; }
/* Ni largeur ni hauteur imposées : la figure porte les siennes, en pixels, égales à son
   cadre. C'est ce qui garde l'échelle des épaisseurs commune à tous les panneaux — étirée à
   la largeur du panneau, chaque figure retrouverait son propre agrandissement. */
.branch-fan svg { display: block; margin: 0 auto; }
/* Le panneau se serre alors sur sa figure au lieu d'imposer sa largeur : une branche à un
   seul mouvement occupe une petite boîte, et rend le reste au plan. */
.branch-panel-figure { width: max-content; padding: 6px; }
/* En plein écran, la vue est seule à l'écran : elle reprend le fond de l'application, que le
   navigateur remplace sinon par du noir. */
#view-dir-carto:fullscreen { background: var(--bg); padding: 12px 18px; overflow: auto; }
/* Mode présentation : tout ce qui n'est pas la planche se replie. Le titre et le texte
   d'explication disparaissent, la barre d'actions reste — on présente une planche pour en
   commenter plusieurs, et il faut pouvoir changer de période sans tout rouvrir. */
body.presentation .sidebar,
body.presentation .topbar,
body.presentation #view-dir-carto .page-heading > div:first-child,
body.presentation #view-dir-global .page-heading > div:first-child { display: none; }
/* La carte d'ensemble prend toute la hauteur restante : c'est une vue de secteur, elle n'a
   d'intérêt qu'assez grande pour qu'on voie plusieurs carrefours à la fois. */
/* La carte d'ensemble a **le format de la page** sur laquelle elle sortira, et tient dans
   l'écran sans le faire défiler : ce qu'on cadre est ce qui s'imprimera, aux bords près.
   La largeur se déduit de la hauteur disponible, et se rabat sur la largeur du bloc quand
   l'écran est plus haut que large — la hauteur suit alors le rapport, jamais l'inverse, sans
   quoi la boîte déborderait par le bas et ramènerait le défilement qu'on veut éviter. */
#dir-global-carte {
  /* Valeur de repli avant la mesure : la vraie hauteur est posée par le script. */
  --hauteur: calc(100vh - 240px);
  width: min(100%, calc(var(--hauteur) * 297 / 210));
  aspect-ratio: 297 / 210;
  height: auto; min-height: 0; margin-inline: auto;
}
#dir-global-carte.portrait {
  width: min(100%, calc(var(--hauteur) * 210 / 297));
  aspect-ratio: 210 / 297;
}

/* Référence du carrefour sur la carte d'ensemble. À cette échelle, les lettres A, B, C de
   cinq carrefours se ressemblent toutes : c'est le code qui situe. */
.junction-tag { background: none; border: 0; }
.junction-tag span {
  display: grid; place-items: center; height: 20px; padding: 0 8px; border-radius: 6px;
  background: #12324a; color: white; font-size: 11px; font-weight: 700;
  border: 2px solid white; box-shadow: 0 2px 6px rgba(16, 45, 36, .45);
}
/* La coquille est une grille « 248 px + le reste ». Masquer la barre latérale la retire du
   flux : le contenu principal devenait alors le premier élément et se logeait dans la colonne
   de 248 px, planche comprise. La grille repasse donc à une seule colonne. */
body.presentation .app-shell { grid-template-columns: minmax(0, 1fr); }
body.presentation .main-content { margin: 0; padding: 8px 14px; }
body.presentation #view-dir-carto .page-heading { justify-content: flex-end; margin-bottom: 6px; }

.junction-schema svg { width: 100%; height: auto; max-height: 62vh; }
/* Hauteur de repli seulement : le plan de réglage prend en réalité les dimensions mesurées
   d'une planche, pour que ce qu'on cadre soit ce qui sortira. */
.junction-plan { height: min(56vh, 620px); margin-inline: auto; border-radius: 8px; overflow: hidden; background: #eef2f0; }
.junction-plan p { padding: 18px; color: var(--muted); font-size: 13px; }


/* Deux graphiques par ligne, et rien d'autre : ce conteneur n'entoure que les graphiques,
   donc la mise en page du reste de la page reste celle d'avant. */
.charts-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px;
  align-items: start; }
.charts-pair .analysis-detail-panel { margin-top: 18px; min-width: 0; }
/* Hauteur fixe, largeur naturelle. Un SVG en `width:100%; height:auto` prend la hauteur que
   lui dicte le rapport de son viewBox : seize libellés horaires donnent un dessin large et
   bas, trois libellés de durée un dessin étroit et haut. C'est la largeur qu'on laisse
   varier — quitte à faire défiler horizontalement — et la hauteur qu'on fige. */
.charts-pair .chart { overflow-x: auto; }
.charts-pair .chart svg { height: 340px; width: auto; max-width: none; min-width: 0; }
@media (max-width: 1180px) { .charts-pair { grid-template-columns: 1fr; } }


/* Cartographie sans titre. Les boutons sont **hors de la carte**, sur leur propre rangée.

   Ils ont d'abord été posés par-dessus le bandeau sombre, pour ne rien coûter en hauteur :
   d'abord au centre de la première rangée — donc sur « Zones » et « Sections », si bien que
   cliquer « Zones » actualisait la carte — puis sur la seconde, à droite, là où la barre ne
   portait rien. Ce placement tenait à ce que la barre laisse une place libre, ce qui dépend
   de la largeur de la fenêtre et de ce que le groupe contient : lui ajouter le menu de
   secteur et le bouton de cadrage l'a élargi jusqu'à déborder sur la carte.

   Se poser sur quelque chose qu'on ne contrôle pas ne se répare pas, ça se recommence. Les
   34 px que la rangée réclame étaient déjà retirés de la hauteur du cadre ci-dessous. */
.carto-actions { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
.carto-actions .secondary { padding:7px 12px; font-size:13px; }
#view-carto { padding:8px 10px; }
.cartography-heading { flex-direction:row; align-items:center; flex-wrap:wrap; gap:6px 12px; margin-bottom:8px; }
.cartography-heading h1 { margin:0; }
.cartography-heading .inline-field { display:flex; flex-direction:row; align-items:center; flex-wrap:wrap; margin:0; min-width:0; gap:6px; }
.cartography-heading select { width:clamp(180px, 30vw, 580px); max-width:100%; padding:6px 8px; font-size:13px; }
body.statio-map-expanded { overflow:hidden; }
.statio-map-expanded #view-carto.active { position:fixed; inset:0; z-index:1200; overflow:auto; background:var(--canvas); }
#carto-frame iframe { width:100%; height:100%; border:0; display:block; }

/* Le détail d'un sens de comptage : replié par défaut, parce qu'il porte vingt-quatre
   heures fois douze classes fois quatre catégories et que la plupart des consultations
   s'arrêtent aux cinq indicateurs du haut. */
.detail-comptage { margin-top: 18px; border-top: 1px solid var(--line); padding-top: 12px; }
.detail-comptage > summary {
  cursor: pointer; font-weight: 700; color: var(--muted);
  padding: 6px 0; list-style-position: inside;
}
.detail-comptage > summary:hover { color: inherit; }
.detail-comptage .detail-corps > * + * { margin-top: 20px; }
.detail-comptage h3 { font-size: 14px; margin-bottom: 8px; }
/* Le pourcentage sous l'effectif : c'est lui qui se lit dans un rapport, et le recalculer
   de tête sur douze classes est précisément ce qu'on ne fait pas. */
.detail-comptage td small.part { display: block; color: var(--muted); font-weight: 600; }
/* Les deux journées moyennes ferment le tableau de flux : elles se distinguent des sept
   journées mesurées au-dessus, sans quoi on les lit comme un huitième et un neuvième jour. */
.detail-comptage tr.ligne-moyenne { background: var(--surface-2, rgba(0,0,0,.04)); }
.detail-comptage tr.ligne-moyenne th { font-weight: 700; }
.detail-comptage h4 { font-size: 13px; margin: 14px 0 6px; color: var(--muted); }
.detail-comptage th .tag { margin-left: 6px; font-weight: 600; }

/* Les deux graphiques de flux du modèle. Dessinés en SVG et en barres CSS : deux figures
   ne valent pas une bibliothèque de plus à tenir à jour, et l'outil doit rester utilisable
   hors ligne. */
.graphiques-flux { margin-top: 20px; }
.graphe { margin: 0 0 22px; }
.graphe figcaption { font-size: 13px; font-weight: 700; color: var(--muted); margin-bottom: 6px; }
.graphe svg { width: 100%; height: auto; display: block; }
.graphe .grille { stroke: var(--line); stroke-width: 1; }
.graphe .graduation { font-size: 11px; fill: var(--muted); font-weight: 600; }
.graphe .courbe { fill: none; stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.legende-graphe { display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
  margin-top: 6px; font-size: 12px; font-weight: 600; color: var(--muted); }
.legende-graphe span { display: flex; align-items: center; gap: 6px; }
.legende-graphe i { width: 16px; height: 4px; border-radius: 2px; }
/* Sept journées se comparent, elles ne se suivent pas : des barres, jamais une courbe. */
.barres-jours { display: flex; align-items: flex-end; gap: 10px; height: 160px;
  padding-bottom: 4px; border-bottom: 1px solid var(--line); }
.jour-colonne { flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: flex-end; height: 100%; }
.jour-colonne .paire { display: flex; align-items: flex-end; gap: 3px; height: 100%; width: 100%;
  justify-content: center; }
.jour-colonne .barre { width: 42%; border-radius: 2px 2px 0 0; min-height: 1px; }
/* Une journée non mesurée n'a pas un trafic nul : rien n'est dessiné plutôt qu'un zéro. */
.jour-colonne .barre.absente { background: repeating-linear-gradient(45deg,
  var(--line) 0 3px, transparent 3px 6px); height: 100%; opacity: .5; }
.jour-colonne small { font-size: 11px; color: var(--muted); font-weight: 600; margin-top: 4px; }

/* ---------------------------------------------------- Masquage des photographies */
/* L'originale reste visible dans Statio ; les rectangles ci-dessous préparent uniquement
   les copies d'export. L'écran doit rendre les propositions automatiques faciles à corriger. */

.floutage-overlay {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2vh 2vw;
  background: rgba(15, 18, 22, 0.82);
}

.floutage-boite {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  max-width: min(1100px, 96vw);
  max-height: 96vh;
  overflow-y: auto;
  padding: 1rem 1.25rem 1.25rem;
  background: var(--surface, #fff);
  border-radius: 6px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.4);
}

.floutage-entete h2 { margin: 0 0 0.25rem; }
.floutage-entete .hint { margin: 0; }

.floutage-detection {
  min-height: 2.5rem;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: #f4f8f6;
  color: var(--muted);
  line-height: 1.35;
}
.floutage-detection.erreur { border-color: #d97706; background: #fff7ed; color: #7c2d12; }

/* Le cadre s'ajuste à l'image : les zones étant placées en pourcentage, tout décalage
   entre le cadre et l'image masquerait à côté de la plaque. */
.floutage-cadre {
  position: relative;
  display: inline-block;
  flex: 0 0 auto;
  align-self: center;
  max-width: 100%;
  min-height: 0;
  overflow: hidden;
  cursor: crosshair;
  touch-action: none;
  line-height: 0;
}

.floutage-cadre img {
  display: block;
  max-width: 100%;
  /* Le cadre et l'image doivent rétrécir ensemble. Sans cette réserve pour l'en-tête,
     l'état et les actions, Flexbox comprimait seulement le cadre sur une fenêtre basse :
     les zones en pourcentage remontaient alors au-dessus des plaques. */
  max-height: clamp(180px, calc(96vh - 280px), 70vh);
  user-select: none;
  -webkit-user-drag: none;
}

.floutage-zones {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.floutage-zone {
  position: absolute;
  background: rgba(20, 22, 26, 0.72);
  border: 2px solid #f3a6c4;
  pointer-events: auto;
}

.floutage-en-cours {
  background: rgba(20, 22, 26, 0.35);
  border-style: dashed;
  pointer-events: none;
}

.floutage-retirer {
  position: absolute;
  top: -12px;
  right: -12px;
  width: 24px;
  height: 24px;
  padding: 0;
  font-size: 1rem;
  line-height: 22px;
  color: #fff;
  cursor: pointer;
  background: #b3123c;
  border: 2px solid #fff;
  border-radius: 50%;
}

.floutage-pied {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  justify-content: space-between;
}

.floutage-actions { display: flex; gap: 0.5rem; }

/* La pastille dit d'un coup d'œil ce qui a été regardé. Sans elle, on ne peut rien
   affirmer sur un lot de photographies.

   Le vert appartient à la **revue déclarée**, jamais au masquage : une photographie où l'on a
   masqué une plaque sur trois est en attente, pas en règle. C'est la distinction relevée en
   revue le 17/08/2026 — la pastille verte se posait au premier rectangle. */
.photo-marque {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  z-index: 2;
  padding: 0.1rem 0.45rem;
  font-size: 0.72rem;
  font-weight: 600;
  color: #fff;
  background: #2f7d4f;
  border-radius: 999px;
}

.photo-marque.attente { color: #7c2d12; background: #f59e0b; }

.photo-card.photo-revue { box-shadow: inset 0 0 0 2px #2f7d4f; }

/* L'aperçu est une lecture des pixels exportés, jamais un second éditeur. Il occupe la
   fenêtre sans recadrer l'image afin que les petites plaques restent contrôlables. */
.photo-apercu-overlay {
  position: fixed; inset: 0; z-index: 1250; display: flex; align-items: center;
  justify-content: center; padding: 2vh 2vw; background: rgba(15, 18, 22, 0.88);
}
.photo-apercu-boite {
  display: flex; flex-direction: column; gap: 0.75rem; width: min(1500px, 96vw);
  max-height: 96vh; padding: 1rem 1.25rem 1.25rem; background: var(--surface, #fff);
  border-radius: 7px; box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
}
.photo-apercu-entete, .photo-apercu-pied {
  display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center;
  justify-content: space-between;
}
.photo-apercu-entete h2 { margin: 0 0 0.2rem; }
.photo-apercu-entete p { margin: 0; color: var(--muted); }
#photo-apercu-fermer-haut {
  align-self: flex-start; min-width: 38px; min-height: 38px; padding: 0;
  font-size: 1.5rem; line-height: 1;
}
.photo-apercu-cadre {
  display: flex; width: 100%; min-width: 0; min-height: 0; flex: 1 1 auto;
  align-items: center; justify-content: center; overflow: auto; background: #111714;
}
.photo-apercu-cadre img {
  display: block; width: auto; height: auto; max-width: 100%;
  max-height: calc(96vh - 180px); object-fit: contain;
}
.photo-apercu-pied { color: var(--muted); font-size: 0.9rem; }
.photo-apercu-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }

@media (max-width: 700px) {
  .photo-apercu-overlay { padding: 0; }
  .photo-apercu-boite { width: 100vw; max-height: 100vh; border-radius: 0; }
  .photo-apercu-cadre img { max-height: calc(100vh - 230px); }
}

/* ----------------------------------------------------------- Remontées de file */
.dir-file-settings { align-items: stretch; }

.queue-length-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(72px, 1fr));
  gap: 0.75rem;
  align-items: end;
}

.queue-length-grid button { grid-column: 1 / -1; justify-self: start; }
.queue-map { min-height: 520px; cursor: crosshair; }

.queue-trace-list { display: grid; gap: 0.75rem; }
.queue-trace-row {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) auto auto;
  gap: 1rem;
  align-items: center;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--line);
}
.queue-trace-row:last-child { border-bottom: 0; }
.queue-trace-row .actions { justify-content: flex-end; }
.queue-sense { font-weight: 600; }
.queue-sense.conforme { color: #2f7d4f; }
.queue-sense.ambigu,
.queue-sense.non_evalue { color: #b45309; }
.queue-marker-icon {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  color: #fff;
  font-weight: 700;
  background: #9f1239;
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

.queue-entry-scroll { overflow-x: auto; }
.queue-entry-grid {
  width: max-content;
  min-width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}
.queue-entry-grid th,
.queue-entry-grid td {
  min-width: 190px;
  padding: 0.65rem;
  text-align: left;
  vertical-align: top;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.queue-entry-grid thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--panel);
}
.queue-entry-grid tr > :first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  min-width: 180px;
  background: var(--panel);
}
.queue-entry-grid thead tr > :first-child { z-index: 3; }
.queue-entry-grid th span { display: block; margin-top: 0.25rem; font-weight: 400; }
.queue-entry-grid td select { display: block; width: 100%; }
.queue-entry-grid td select + select { margin-top: 0.4rem; }
.queue-source {
  display: inline-block;
  margin-top: 0.4rem;
  padding: 0.15rem 0.4rem;
  color: #7c2d12;
  font-size: 0.75rem;
  font-weight: 600;
  background: #ffedd5;
  border-radius: 999px;
}

.queue-critical-controls {
  align-items: end;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: .65rem;
  grid-column: 1 / -1;
  padding-top: .75rem;
}

.queue-critical-controls label { min-width: 12rem; }

.queue-critical-results {
  border-top: 1px solid var(--line);
  margin-top: 1rem;
  padding-top: .75rem;
}

.queue-critical-results h3 { margin: 0 0 .45rem; }

.queue-critical-marker span {
  background: #f59e0b;
  border: 2px solid #78350f;
  border-radius: 50%;
  display: block;
  height: 14px;
  width: 14px;
}

.queue-critical-marker { background: none; border: 0; }
.queue-source[hidden] { display: none; }
.warning-text { color: #b45309; }

.queue-report-cover {
  min-height: 520px;
  padding: 42px;
  color: #fff;
  background: linear-gradient(135deg, #143f33, #1f6b52);
  border-radius: 8px;
}
.queue-report-cover .eyebrow,
.queue-report-cover .report-footer { color: #cde8dc; }
.queue-report-cover h1 { margin: 12px 0 4px; font-size: 38px; }
.queue-report-cover > p { font-size: 18px; }
.queue-report-cover .report-facts div { background: rgba(255, 255, 255, 0.12); }
.queue-report-cover .report-facts dt { color: #cde8dc; }
.queue-report-cover .report-facts dd { color: #fff; }
.queue-summaries { display: grid; gap: 18px; margin: 22px 0; }
.queue-summary-card .indicator strong { font-size: 18px; }
.queue-summary-card .indicator span { color: var(--muted); font-size: 12px; }
.queue-peaks { margin: 8px 0 0; padding-left: 20px; color: var(--muted); }
.queue-report-maps { display: grid; grid-template-columns: repeat(auto-fit, minmax(460px, 1fr)); gap: 18px; }
.queue-report-intro,
.queue-report-board { padding: 20px; border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.queue-report-map { height: 430px; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.queue-report-legend { display: grid; gap: 4px; margin-top: 10px; font-size: 12px; }
.queue-map-source { color: var(--muted); font-size: 11px; margin-top: 4px; }
.queue-critical-label {
  color: #78350f;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}
.view[aria-busy="true"] { opacity: .65; }
.queue-result-marker { background: none; border: 0; }
.queue-result-marker span {
  display: block; width: 16px; height: 16px; background: #c81e4d;
  border: 3px solid #fff; border-radius: 50%; box-shadow: 0 1px 5px rgba(0, 0, 0, .4);
}
/* La planche remise au client : une carte par carrefour, jamais côte à côte avec une autre. */
.queue-synthese-maps { display: grid; gap: 18px; margin: 22px 0; }
.queue-synthese-board .panel-heading p { color: var(--muted); font-size: 12px; margin: 4px 0 0; }
.queue-arrow-head { background: none; border: 0; }
.queue-arrow-head span {
  display: block;
  width: 0;
  height: 0;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
  border-bottom: 18px solid #c81e4d;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .45));
}
.queue-arrow-label {
  color: #7f1130;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}
body.impression-files .queue-report-maps { display: none !important; }
body.impression-files .queue-synthese-maps { display: block; width: 1000px; }
body.impression-files-interne .queue-report-cover,
body.impression-files-interne .queue-summaries,
body.impression-files-interne .queue-synthese-maps { display: none !important; }
body.impression-files-interne .queue-report-maps { display: block; width: 1000px; }
body.impression-files .queue-report-map,
body.impression-files-interne .queue-report-map { width: 1000px; height: 590px; }
body.impression-files .queue-report-board,
body.impression-files .queue-report-intro,
body.impression-files-interne .queue-report-board,
body.impression-files-interne .queue-report-intro { width: 1000px; border: 0; }

@media (max-width: 900px) {
  .queue-length-grid { grid-template-columns: repeat(2, minmax(90px, 1fr)); }
  .queue-trace-row { grid-template-columns: 1fr; }
  .queue-trace-row .actions { justify-content: flex-start; }
  .queue-report-maps { grid-template-columns: 1fr; }
}

@media print {
  .queue-report-cover { border-radius: 0; }
  .queue-summaries { display: block; }
  .queue-summary-card { break-inside: avoid; margin-bottom: 10mm; }
  .queue-report-board { break-after: page; }
  .queue-report-board:last-child { break-after: auto; }
  .queue-report-map .leaflet-control-attribution { display: none; }
}

/* Données publiques INSEE : les limites restent dans le même bloc visuel que la donnée. */
.mobilites-search { align-items: end; display: grid; gap: 12px; grid-template-columns: minmax(240px, 1fr) auto; }
.mobilites-search-results { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.mobilites-commune-choice { text-align: left; }
.mobilites-columns { align-items: start; }
.mobilites-flow-table td:first-child small { color: var(--muted); display: block; font-size: 11px; }
.mobilites-flow-table h3, .mobilites-profils h3 { margin-top: 18px; }
.mobilites-profile { border-top: 1px solid var(--line); margin-top: 18px; padding-top: 14px; }
.mobilites-profile-row {
  display: grid; gap: 4px 10px; grid-template-columns: minmax(160px, 1fr) auto;
  margin: 8px 0;
}
.mobilites-profile-row i {
  background: linear-gradient(90deg, #176448 var(--part), #e6eee9 var(--part));
  border-radius: 999px; grid-column: 1 / -1; height: 8px;
}

/* ------------------------------------------------ Graphiques partagés (camemberts, barres)
   Une seule écriture pour tous les écrans de répartition — INSEE aujourd'hui, OD demain. */
.graphique { margin: 0; }
.graphique-camembert { display: flex; align-items: center; justify-content: center;
  gap: 16px; flex-wrap: wrap; }
.graphique-legende { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px;
  font-size: 12.5px; min-width: 190px; }
.graphique-legende li { display: grid; grid-template-columns: 14px 1fr auto;
  align-items: center; gap: 8px; }
.graphique-legende i { width: 14px; height: 14px; border-radius: 4px; display: block; }
.graphique-legende b { font-variant-numeric: tabular-nums; }
.graphique-histogramme { display: grid; gap: 7px; }
.graphique-barre-ligne { display: grid; grid-template-columns: minmax(120px, 170px) 1fr 56px;
  align-items: center; gap: 10px; font-size: 12.5px; }
.graphique-barre-piste { background: #e6eee9; border-radius: 999px; height: 12px;
  overflow: hidden; }
.graphique-barre-piste i { display: block; height: 100%; border-radius: 999px; }
.graphique-barre-ligne b { font-variant-numeric: tabular-nums; text-align: right; }
/* Le tableau à gauche garde les effectifs, le graphique à droite porte les parts —
   camembert et légende centrés dans leur moitié, à hauteur du tableau. */
.profil-duo { display: grid; grid-template-columns: minmax(230px, 1fr) minmax(250px, 1.1fr);
  gap: 8px 22px; align-items: center; }
@media (max-width: 900px) { .profil-duo { grid-template-columns: 1fr; } }

/* Boutons segmentés : un choix exclusif, l'état actif porté par la couleur de marque. */
.choix-segmente { display: inline-flex; border: 1px solid #cbd7d1; border-radius: 6px;
  overflow: hidden; }
.choix-segmente button { border: 0; background: white; padding: 7px 14px; font-weight: 600;
  font-size: 12.5px; color: var(--muted); }
.choix-segmente button + button { border-left: 1px solid #cbd7d1; }
.choix-segmente button.active { background: var(--green-2); color: white; }
.mobilites-carte-choix { flex-wrap: wrap; }
/* Bascules indépendantes : chacune allume ou éteint une couche d'habillage. */
.choix-bascules { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.choix-bascules button { border: 1px solid #cbd7d1; border-radius: 999px; background: white;
  padding: 6px 12px; font-weight: 600; font-size: 12px; color: var(--muted); }
.choix-bascules button.active { background: #e3f2ea; border-color: var(--green-2);
  color: var(--green); }

/* Légende posée sur la carte des flux : les classes de la carte, pas une décoration. */
.legende-flux { background: rgba(255, 255, 255, .94); border: 1px solid var(--line);
  border-radius: 6px; padding: 9px 12px; font-size: 12px; line-height: 1.5;
  box-shadow: 0 4px 14px rgba(27, 52, 43, .12); }
.legende-flux strong { display: block; margin-bottom: 4px; }
.legende-flux .ligne { display: flex; align-items: center; gap: 8px; }
.legende-flux .ligne i { width: 26px; border-radius: 3px; display: inline-block;
  flex-shrink: 0; }
/* Les liaisons sans géométrie — « travaillant à l'étranger (sans précision de
   commune) » — se lisent au bas de la légende, séparées d'un liseré. */
.legende-horscarte { margin-top: 7px; padding-top: 6px; border-top: 1px solid #d8e2dc;
  max-width: 250px; }
.legende-horscarte .ligne { align-items: flex-start; }
.legende-horscarte .ligne i { margin-top: 3px; }

/* Étiquette posée sur la commune, comme sur les planches QGIS : du texte en prise directe
   sur la carte, lisible par un halo clair — pas une bulle. */
/* Fond clair de la carte mobilités : aucune tuile, un aplat très pâle. Leaflet
   peint sinon un gris soutenu, sur lequel les limites communales se perdent
   autant que sur un plan chargé. */
.leaflet-container.fond-clair { background: #f6f7f9; }

.etiquette-commune {
  background: transparent; border: 0; box-shadow: none; font-size: 12px; font-weight: 600;
  color: #1c2a24;
  text-shadow: 0 0 3px white, 0 0 3px white, 0 0 3px white, 0 0 3px white;
}
.etiquette-commune::before { display: none; }
.etiquette-region {
  background: transparent; border: 0; box-shadow: none; font-size: 13px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: #40474a;
  text-shadow: 0 0 3px white, 0 0 3px white, 0 0 3px white;
}
.etiquette-region::before { display: none; }
/* Les noms de toutes les communes du secteur : une écriture discrète, jamais en
   concurrence avec les étiquettes des communes coloriées. */
.etiquette-commune-discrete {
  background: transparent; border: 0; box-shadow: none; font-size: 10px; font-weight: 500;
  color: #6a736e; text-shadow: 0 0 2px white, 0 0 2px white;
}
.etiquette-commune-discrete::before { display: none; }
.mobilites-source {
  background: #eef7f2; border: 1px solid #bdd8ca; border-left: 5px solid #176448;
  border-radius: 6px; margin-top: 16px; padding: 12px 14px;
}
.mobilites-source p { margin: 0 0 8px; }
.mobilites-source ul { margin: 0; padding-left: 20px; }
.mobilites-source li { margin: 4px 0; }
.mobilites-comparaison .source-banner.warning { background: #fff7e6; border-color: #e7bb62; color: #6f4908; }
.mobilites-side-by-side { display: grid; gap: 14px; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 18px 0; }
.mobilites-side-by-side article { background: #f5f7f6; border: 1px solid var(--line); border-radius: 8px; padding: 16px; }
.mobilites-side-by-side span, .mobilites-side-by-side small { color: var(--muted); display: block; }
.mobilites-side-by-side strong { display: block; font-size: 30px; margin: 8px 0 2px; }
.mobilites-side-by-side ul { padding-left: 20px; }

@media (max-width: 900px) {
  .mobilites-search, .mobilites-side-by-side { grid-template-columns: 1fr; }
}

/* --- Simulation d'aménagement ---------------------------------------------- */
.simulation-scenario {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin: 16px 0;
  align-items: start;
}
@media (max-width: 980px) { .simulation-scenario { grid-template-columns: 1fr; } }
.sim-apercu {
  display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center;
  padding: 10px 14px; margin-top: 10px;
  background: var(--mint, #e7f3ec); border: 1px solid #bcd9c8; border-radius: 10px;
}
.sim-apercu label { display: inline-flex; gap: 6px; align-items: center; font-weight: 600; }
.sim-apercu input { width: 190px; }
.sim-apercu select { min-width: 140px; }
.sim-aide { flex-basis: 100%; color: var(--muted); font-size: 0.85rem; }
.sim-poignee, .sim-acces { background: none; border: 0; cursor: grab; }
.sim-direction { background: none; border: 0; pointer-events: none; }
.sim-direction span {
  display: grid; place-items: center; width: 24px; height: 24px;
  color: #263238; font-size: 21px; font-weight: 900;
  text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;
}
.sim-avertissement {
  flex-basis: 100%; padding: 8px 10px; border-left: 4px solid #e28b16;
  background: #fff7e8; color: #6f4708; border-radius: 4px;
}
/* Deux états lisibles au premier regard : l'esquisse dont l'implantation PMR n'est
   qu'indicative, et le scénario dont le cheminement accessible est vérifié. */
.sim-indicatif {
  flex-basis: 100%; padding: 8px 10px; border-left: 4px solid #7e57c2;
  background: #f3effa; color: #4527a0; border-radius: 4px;
}
.sim-verifie {
  flex-basis: 100%; padding: 8px 10px; border-left: 4px solid #2e7d32;
  background: #edf6ee; color: #1b5e20; border-radius: 4px;
}
.sim-emprises-table .sim-indicatif {
  display: inline; padding: 0; border: 0; background: none; color: #4527a0;
}
.sim-variantes {
  flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 7px;
  padding-top: 4px;
}
.sim-variantes > span { color: var(--muted); font-size: 0.8rem; font-weight: 700; }
.sim-variantes small {
  padding: 4px 8px; border: 1px solid var(--line); border-radius: 999px; background: #fff;
}
.sim-variantes small.active { border-color: #1565c0; color: #0d47a1; background: #e8f2ff; }
.sim-apercu button:disabled { cursor: not-allowed; opacity: 0.55; }
.sim-vide { color: var(--muted); font-style: italic; }
.sim-version { display: block; color: var(--muted); font-size: 0.72rem; }
.simulation-en-dessin, .simulation-en-dessin * { cursor: crosshair !important; }
.sim-pointe { margin: 6px 2px 12px; }
.sim-sections-defilement { max-height: 340px; overflow: auto; }
.sim-retiree th, .sim-retiree td { background: #fdeaea; }
.sim-badge {
  display: inline-block; min-width: 62px; text-align: center; padding: 2px 8px;
  border-radius: 999px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.sim-detendu { background: #e3f2e8; color: #1b5e20; }
.sim-equilibre { background: #d9ecc8; color: #33691e; }
.sim-tendu { background: #ffe4c4; color: #a04d00; }
.sim-sature { background: #ffd4d4; color: #b71c1c; }
.sim-congestion-table td, .sim-congestion-table th { white-space: nowrap; }

.sim-emprises-table td, .sim-emprises-table th { white-space: nowrap; vertical-align: middle; }
/* Les intitulés des choix doivent tenir en entier : « Automatique » tronqué en « Autc »
   ne dit plus rien de ce que fait l'outil. */
.sim-emprises-table select { width: auto; min-width: 148px; max-width: 200px; }
.sim-emprises-table small { display: block; color: var(--muted); font-size: 0.78rem; }

/* --- Manque à gagner du payant --------------------------------------------- */
.payant-mag-table td, .payant-mag-table th { white-space: nowrap; }
.payant-jours { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; margin: 12px 0; }
.payant-jours span { display: inline-flex; gap: 7px; align-items: center; font-weight: 400; }
.payant-jours input { width: 92px; }
/* Les créneaux à gauche, les durées non payées à droite : deux lectures du même jour
   d'enquête, côte à côte plutôt qu'à deux hauteurs de défilement (demande d'Eddy). */
.payant-colonnes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  align-items: start;
  margin-top: 18px;
}
@media (max-width: 1180px) { .payant-colonnes { grid-template-columns: 1fr; } }
.payant-colonne { min-width: 0; }
.payant-colonne .zb-fenetre { margin-top: 0; }
.payant-colonne .zb-fenetre + .zb-fenetre { margin-top: 18px; }
.payant-durees-note { color: var(--muted); font-size: 0.86rem; margin: 10px 0 8px; }
/* Aucun décalage supérieur : le maximum et la ligne zéro coïncident avec le graphique
   des créneaux dans la colonne voisine. */
.payant-durees-graphique { margin: 0 0 16px; }
.payant-tarif-cellule { font-size: 0.82rem; color: var(--muted); }
.payant-tarifs textarea { width: 100%; box-sizing: border-box; font-family: inherit; }

.zone-protocols-panel {
  margin: 0 0 1rem;
  padding: .8rem 1rem;
  border: 1px solid var(--border, #d7ddd9);
  border-radius: .7rem;
  background: #fff;
}
.zone-protocols-panel summary { cursor: pointer; font-weight: 700; }
.zone-protocols-grid { display: grid; gap: .55rem; margin: .8rem 0; }
.zone-protocol-row {
  display: grid;
  grid-template-columns: minmax(8rem, 1fr) minmax(11rem, auto) 3fr;
  gap: .75rem;
  align-items: center;
  padding: .55rem .7rem;
  border-radius: .45rem;
  background: #f5f7f6;
}
.zone-pass-list { display: flex; flex-wrap: wrap; gap: .35rem .75rem; }
.zone-pass-list label { display: inline-flex; gap: .25rem; align-items: center; }
/* Bordeaux, et non plus orange : l'orange est déjà la seconde série d'un même véhicule
   sur plusieurs passages, et deux sens pour une couleur dans la même grille se lisent
   l'un pour l'autre. */
.protocol-unavailable-cell { background: #7A1330 !important; color: #fff; }
@media (max-width: 850px) {
  .zone-protocol-row { grid-template-columns: 1fr; }
}

/* Le compositeur de créneau : une ligne de cases à cocher, un nom, deux boutons. Il ne
   s'ouvre que sur demande et se referme dès qu'on a créé le créneau. */
.window-form { margin-top: 12px; padding: 14px 16px; border: 1px solid var(--line);
  border-radius: 8px; background: #fbfdfc; display: flex; flex-direction: column; gap: 10px; }
.window-form p { margin: 0; color: var(--muted); font-size: 12.5px; line-height: 1.5; }
.window-form-passes { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.window-form-passes label { display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; }
.window-form-actions { display: flex; gap: 10px; }

/* Le rapport client est composé dans une coquille qui sert le même moteur que le ZIP. */
.report-composer { margin-top: 16px; }
.report-composer-frame {
  width: 100%; min-height: 78vh; border: 1px solid var(--line);
  border-radius: 10px; background: #f7f9f8;
}

/* Le composeur conserve son iframe et son panier lors du changement d'onglet. */
#view-livrables.active { display:flex; flex-direction:column; gap:8px; height:calc(100dvh - 60px); padding:8px 14px; overflow:auto; }
#view-livrables > .page-heading { margin:0; align-items:center; flex-shrink:0; }
#view-livrables > .page-heading h1 { margin:0; font-size:22px; }
.livrables-tabs { display:flex; gap:6px; flex-shrink:0; }
.livrables-tabs [aria-selected="true"] { background:var(--green); color:white; }
#livrables-controle { flex-shrink:0; }
#livrables-controle .carte { padding:6px 10px; margin:0; }
#livrables-controle h3 { margin:0; font-size:13px; }
#livrables-composer { flex:1; min-height:240px; }
#livrables-composer .report-composer { height:100%; margin:0; padding:0; }
#livrables-composer .report-composer-frame { display:block; height:100%; min-height:0; }
#livrables-composer.report-composer-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 1400;
  width: 100vw;
  height: 100dvh;
  min-height: 0;
  background: #fff;
}
#livrables-composer.report-composer-fullscreen .report-composer {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
}
#livrables-composer.report-composer-fullscreen .report-composer-frame {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
}
body.report-composer-fullscreen { overflow: hidden; }
#livrables-fichiers { overflow:auto; min-height:0; }
#view-livrables [role="tabpanel"][hidden] { display:none; }

/* Le cadrage des photos se règle dans Observations, puis est repris par les livrables. */
#view-observations .observation-photo-frame {position:relative;aspect-ratio:4/3;overflow:hidden;background:#fff;flex:none;width:100%;}
#view-observations .observation-photo-frame img {position:absolute;display:block;max-width:none;max-height:none;aspect-ratio:auto;object-fit:fill;user-select:none;}
#view-observations .photo-frame-controls {padding:10px 12px;border-top:1px solid #d5e4de;cursor:default;}
#view-observations #photo-gallery {align-items:start;}
#view-observations #photo-gallery > .photo-card:has(.photo-frame-editing) {grid-column:1/-1;}
#view-observations .photo-frame-editor[hidden],#view-observations .photo-frame-controls button[hidden] {display:none;}
#view-observations .photo-frame-editor p {font-size:14px;line-height:1.4;margin:0 0 10px;}
#view-observations .photo-frame-zoom {display:flex;align-items:center;gap:8px;margin-bottom:10px;}
#view-observations .photo-frame-zoom label {display:flex;align-items:center;gap:8px;flex:1;min-width:0;}
#view-observations .photo-frame-zoom input {min-width:0;width:100%;accent-color:#155f4b;}
#view-observations .photo-frame-zoom output {min-width:48px;text-align:right;}
#view-observations .photo-frame-actions {display:flex;flex-wrap:wrap;gap:8px;}
#view-observations .photo-frame-editing {cursor:grab;touch-action:none;outline:3px solid #9bd9c4;outline-offset:-3px;}
#view-observations .photo-frame-editing:active {cursor:grabbing;}
#view-observations .photo-frame-editing img {pointer-events:none;}

/* Les definitions longues portent leurs propres retours a la ligne : le taux
   d'illicite s'enonce en une phrase puis quatre tirets, et le HTML ecrase un
   saut de ligne en espace tant qu'on ne le lui interdit pas. Sans cette regle,
   les tirets se suivraient sur une seule ligne et l'aeration voulue n'existerait
   que dans la chaine Python. */
#definitions-table td:last-child { white-space: pre-line; }

/* L'unite d'une tuile tient sur une ligne secondaire. Dans la composition du rapport,
   le cadre mesure 132 px : « 2,89 stationnements/place » rendu d'un bloc en 28 px
   debordait et l'unite etait coupee. Releve par Codex le 09/09/2026 en ouvrant la
   diapositive 10 du rapport compose, invisible a l'ecran Analyse ou le cadre fait
   555 px. */
.metric-card small { display: block; margin-top: 1px; font-size: 11px; line-height: 1.2; color: var(--muted); font-weight: 600; }
