/* ============================================================
   PaysagePro — 20-layout.css
   Coque applicative : grille, sidebar, topbar, contenu, pied de page.

   Source de verite UNIQUE. Avant ce fichier, .app-main etait declaree
   9 fois dans 4 feuilles (app.css, zip14, zip15, zip-j-layout-hotfix),
   .app 5 fois et .app-sidebar 4 fois, avec des !important contradictoires.

   Toutes les regles de coque sont prefixees body.pp-app : la feuille est
   chargee aussi par le shell 'auth' (login, 404, 403, reset) pour les
   utilitaires communs, ou elle reste inerte.

   Aucun !important dans ce fichier.
   ============================================================ */

/* ------------------------------------------------------------
   1. Structure generale

   L'ancien montage empilait html,body{height:100%;overflow:hidden}
   + .app{height:100vh}, avec la barre de recherche (~50px) placee
   AVANT .app. Total 100vh + 50px dans un conteneur en overflow:hidden :
   les 50 derniers pixels de chaque page etaient inatteignables et le
   pied de page n'etait jamais visible. Le padding-bottom:80px du
   hotfix zip-j etait un pansement sur ce symptome.

   Ici : une colonne flex, plus aucune hauteur fixe, et le defilement
   confine a .app-main.
   ------------------------------------------------------------ */
body.pp-app {
  /* Hauteur BORNEE au viewport, et non un simple plancher : « min-block-size »
     seul laissait la grille grandir avec son contenu. La sidebar couvrant les
     trois lignes grandissait alors elle aussi, sa navigation en « flex: 1 1 auto »
     recevait toute la place et n'avait plus rien a faire defiler, et le surplus
     finissait coupe par l'overflow:hidden ci-dessous — donc inatteignable.
     Avec une hauteur definie, le minmax(0, 1fr) de .app se resout a l'espace
     reellement disponible et le menu defile a l'interieur de l'ecran.
     Un frere en flux place avant .app (bandeau de previsualisation de role)
     reste pris en compte : .app n'a pas de hauteur propre, il se retrecit
     d'autant. C'est ce qui distingue ce montage de l'ancien decrit plus haut,
     ou .app portait lui-meme un 100vh en plus d'un frere de 50 px. */
  block-size: 100vh;        /* repli : sans dvh, la ligne suivante est ignoree */
  block-size: 100dvh;       /* dvh : suit la barre d'URL mobile, ce que 100vh ne fait pas */
  display: flex;
  flex-direction: column;
  overflow: hidden;         /* le defilement vit dans .app-main */
}

body.pp-app > .app {
  flex: 1 1 auto;
  min-block-size: 0;        /* la ligne qui debloque tout : sans elle, un enfant flex
                               refuse de retrecir sous la hauteur de son contenu */
  display: grid;
  grid-template-columns: var(--pp-sidebar-w) 1fr;
  /* minmax(0, 1fr) et non 1fr : « 1fr » vaut minmax(auto, 1fr), et ce minimum
     automatique interdit a la ligne de descendre sous la hauteur de son contenu.
     Un menu plus long que l'ecran faisait donc grandir toute la grille au lieu
     de declencher son propre defilement — bas du menu hors du viewport, coupe
     par l'overflow:hidden du body, et flyout repousse contre le bandeau. */
  grid-template-rows: var(--pp-header-h) minmax(0, 1fr) auto;
  grid-template-areas:
    "sidebar header"
    "sidebar main"
    "sidebar footer";
  background: var(--pp-bg);
}

body.pp-app.sidebar-hidden > .app {
  grid-template-columns: 0 1fr;
}
body.pp-app.sidebar-hidden .app-sidebar {
  display: none;
}

/* ------------------------------------------------------------
   2. Contenu principal
   ------------------------------------------------------------ */
.app-main {
  grid-area: main;
  min-inline-size: 0;       /* un enfant de grille a min-width:auto et refuse de
                               retrecir : c'est ce qui poussait toute la page,
                               en-tete compris, a deborder sur mobile */
  min-block-size: 0;
  overflow-y: auto;
  overflow-x: hidden;       /* le defilement horizontal appartient aux tableaux,
                               pas a la page (voir .pp-table-wrap) */
  background: var(--pp-bg);
  color: var(--pp-text);
  padding: var(--pp-space-6) var(--pp-space-8) var(--pp-space-10);
  scroll-padding-block-end: var(--pp-space-10);
}

.app-main > :last-child {
  margin-block-end: var(--pp-space-6);
}

/* ------------------------------------------------------------
   3. Sidebar
   ------------------------------------------------------------ */
.app-sidebar {
  grid-area: sidebar;
  min-inline-size: 0;
  min-block-size: 0;        /* meme raison que min-inline-size : un enfant de grille a
                               min-height:auto et impose sa hauteur de contenu aux
                               lignes qu'il traverse. Sans cette ligne, l'overflow-y
                               ci-dessous ne s'arme jamais — la sidebar pousse la
                               grille au lieu de defiler. */
  background: var(--pp-sidebar-bg);
  color: var(--pp-sidebar-text);
  padding: var(--pp-space-5) 0;
  /* Le menu tient dans la hauteur de l'ecran : bandeau de marque en haut et
     pied de version en bas restent en place, seule la navigation defile.
     Auparavant c'etait tout le bloc qui defilait — le pied disparaissait et,
     en mode rail (sidebar en position absolue, /css/pp-sidebar-rail.css),
     rien ne bornait la hauteur : le bas du menu passait sous le viewport. */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.app-sidebar > .sidebar-brand { flex: 0 0 auto; }
.app-sidebar > .sidebar-nav {
  flex: 1 1 auto;
  min-block-size: 0;        /* sans cela, overflow-y ne s'arme pas dans un flex */
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
}
.app-sidebar > .sidebar-nav::-webkit-scrollbar { width: 6px; }
.app-sidebar > .sidebar-nav::-webkit-scrollbar-track { background: transparent; }
.app-sidebar > .sidebar-nav::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.25);
  border-radius: 3px;
}
.app-sidebar > .sidebar-nav::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.4); }

.app-sidebar .sidebar-brand {
  padding: 0 var(--pp-space-5) var(--pp-space-5);
  font-size: 1.25rem;
  font-weight: 700;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  align-items: center;
  gap: var(--pp-space-2);
}
.app-sidebar .sidebar-brand .leaf { font-size: 1.5rem; }

/* v1.60.4 : le bandeau de marque est cliquable — logo et nom ramenent a
   l'accueil. Le lien reprend la mise en ligne du bandeau (le nom garde son
   flex: 1 defini dans pp-sidebar-rail.css) et occupe la place laissee libre
   par le bouton de repli. */
.app-sidebar .sidebar-brand .sidebar-brand-home {
  flex: 1 1 auto;
  min-inline-size: 0;
  display: flex;
  align-items: center;
  gap: var(--pp-space-2);
  color: inherit;
  text-decoration: none;
  border-radius: var(--pp-radius-sm, 6px);
  transition: opacity var(--pp-dur-fast) var(--pp-ease-standard);
}
.app-sidebar .sidebar-brand .sidebar-brand-home:hover,
.app-sidebar .sidebar-brand .sidebar-brand-home:focus-visible {
  color: inherit;
  text-decoration: none;
  opacity: 0.85;
}

.app-sidebar nav { margin-top: var(--pp-space-5); }
.app-sidebar nav a {
  display: flex;
  align-items: center;
  gap: var(--pp-space-2);
  padding: var(--pp-space-2) var(--pp-space-5);
  color: rgba(255, 255, 255, 0.85);
  border-left: 3px solid transparent;
  transition: background-color var(--pp-dur-fast) var(--pp-ease-standard),
              color var(--pp-dur-fast) var(--pp-ease-standard);
}
.app-sidebar nav a:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  text-decoration: none;
}
.app-sidebar nav a.active {
  background: rgba(255, 255, 255, 0.1);
  border-left-color: var(--pp-green-300);
  color: #fff;
}
.app-sidebar nav .nav-section {
  padding: var(--pp-space-3) var(--pp-space-5) var(--pp-space-1);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.4);
  font-weight: 600;
}

/* ------------------------------------------------------------
   4. Topbar

   La barre de recherche globale vivait dans .topbar-search-row, un
   bloc pleine largeur pose AVANT .app (cause racine du clipping).
   Elle est maintenant un enfant de l'en-tete. Les identifiants
   #topbar-search-input / #topbar-search-results / #topbar-search-wrap
   sont conserves : topbar-search.js fonctionne sans modification.
   ------------------------------------------------------------ */
.app-header {
  grid-area: header;
  min-inline-size: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--pp-space-3);
  flex-wrap: nowrap;
  padding: 0 var(--pp-space-6);
  background: var(--pp-header-bg);
  color: var(--pp-text);
  border-bottom: 1px solid var(--pp-border);
  box-shadow: var(--pp-shadow);
  z-index: var(--pp-z-header);
}

.topbar-left {
  display: flex;
  align-items: center;
  gap: var(--pp-space-2);
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
}
.topbar-left .header-title,
.topbar-left .page-title {
  font-weight: 600;
  color: var(--pp-green-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.topbar-context {
  display: inline-block;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-left: var(--pp-space-2);
  flex-shrink: 0;
}

.topbar-right,
.header-user.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--pp-space-2);
  flex-shrink: 0;
  color: var(--pp-muted);
}
.topbar-user-info { display: flex; flex-direction: column; min-width: 0; }

.app-header .user-avatar {
  width: 36px; height: 36px;
  border-radius: var(--pp-radius-full);
  background: var(--pp-green-500);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600;
  flex-shrink: 0;
}

/* --- Recherche globale, desormais dans l'en-tete --- */
.topbar-search {
  position: relative;
  flex: 0 1 clamp(200px, 30vw, 520px);
  min-width: 0;
}
.topbar-search-input {
  width: 100%;
  padding: var(--pp-space-2) var(--pp-space-3);
  border-radius: var(--pp-radius-sm);
  border: 1px solid var(--pp-border);
  background: var(--pp-input-bg);
  color: var(--pp-text);
  font-size: 0.9rem;
  transition: border-color var(--pp-dur-fast), background-color var(--pp-dur-fast),
              box-shadow var(--pp-dur-fast);
}
.topbar-search-input::placeholder { color: var(--pp-muted); opacity: 0.85; }
.topbar-search-input:focus {
  outline: none;
  border-color: var(--pp-primary);
  background: var(--pp-input-bg-hover);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pp-primary) 22%, transparent);
}

.topbar-search-results {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--pp-card-bg);
  border: 1px solid var(--pp-border);
  border-radius: var(--pp-radius-sm);
  box-shadow: var(--pp-shadow-lg);
  max-height: 70vh;
  overflow-y: auto;
  z-index: var(--pp-z-dropdown);
}
.topbar-search-cat { padding: var(--pp-space-1) 0; border-bottom: 1px solid var(--pp-border); }
.topbar-search-cat:last-child { border-bottom: 0; }
.topbar-search-cat-title {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--pp-primary);
  padding: var(--pp-space-1) var(--pp-space-3) var(--pp-space-1);
  font-weight: 600;
}
.topbar-search-item {
  display: block;
  padding: var(--pp-space-2) var(--pp-space-3);
  text-decoration: none;
  color: var(--pp-text);
  border-left: 3px solid transparent;
  transition: background-color var(--pp-dur-instant), border-color var(--pp-dur-instant);
}
.topbar-search-item:hover {
  background: var(--pp-input-bg-hover);
  border-left-color: var(--pp-primary);
  text-decoration: none;
}
.topbar-search-item-label { font-weight: 500; font-size: 0.92rem; }
.topbar-search-item-sub { font-size: 0.78rem; color: var(--pp-muted); margin-top: 2px; }
.topbar-search-empty {
  padding: var(--pp-space-4);
  text-align: center;
  color: var(--pp-muted);
  font-size: 0.9rem;
}
.topbar-search-footer {
  padding: var(--pp-space-2) var(--pp-space-3);
  text-align: center;
  border-top: 1px solid var(--pp-border);
}
.topbar-search-footer a { font-size: 0.85rem; font-weight: 500; }

/* ------------------------------------------------------------
   5. Pied de page

   Il etait rendu APRES </div class="app">, donc hors de la grille et
   hors du viewport : jamais visible en desktop. Il occupe desormais
   sa propre ligne de grille.
   ------------------------------------------------------------ */
.app-footer {
  grid-area: footer;
  min-inline-size: 0;
  text-align: center;
  padding: var(--pp-space-3) var(--pp-space-4);
  font-size: 0.85rem;
  color: var(--pp-muted);
  background: var(--pp-card-bg);
  border-top: 1px solid var(--pp-border);
}

/* ------------------------------------------------------------
   6. Voile de la sidebar mobile

   Remplace body.sidebar-open::after de zip09 : un element reel est
   cliquable proprement et permet de gerer l'inertie du contenu.
   ------------------------------------------------------------ */
.app-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--pp-z-scrim);
  background: rgba(9, 17, 13, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--pp-dur-base) var(--pp-ease-standard);
}

/* ------------------------------------------------------------
   7. Lien d'evitement

   Absent jusqu'ici : un utilisateur au clavier devait traverser les
   63 entrees de la navigation avant d'atteindre le contenu.
   ------------------------------------------------------------ */
.pp-skip-link {
  position: absolute;
  inset-inline-start: var(--pp-space-2);
  inset-block-start: -100%;
  z-index: var(--pp-z-tooltip);
  padding: var(--pp-space-2) var(--pp-space-4);
  background: var(--pp-primary);
  color: var(--pp-primary-on);
  border-radius: var(--pp-radius-sm);
  box-shadow: var(--pp-shadow-lg);
  text-decoration: none;
  font-weight: 600;
  transition: inset-block-start var(--pp-dur-fast) var(--pp-ease-out);
}
.pp-skip-link:focus {
  inset-block-start: var(--pp-space-2);
  color: var(--pp-primary-on);
  text-decoration: none;
}

/* ------------------------------------------------------------
   8. Responsive — un seul jeu de seuils

   L'ancien socle en comptait six (600, 720, 768, 900, 980) repartis
   sur treize feuilles, avec trois comportements mobiles concurrents
   de la sidebar et une zone morte 901-980px ou le CSS etait en mode
   mobile pendant que pp-ui.js se croyait en desktop.

   Seuils retenus : sm 640 / md 768 / lg 1024 / xl 1280.
   Le seuil structurel est 1024px et lui seul : il doit rester
   identique dans pp-ui.js (constante MOBILE_QUERY).
   ------------------------------------------------------------ */

/* --- lg : sous 1024px, la sidebar devient un tiroir --- */
@media (max-width: 1023.98px) {
  body.pp-app > .app {
    grid-template-columns: 1fr;
    grid-template-areas: "header" "main" "footer";
  }
  body.pp-app.sidebar-hidden > .app { grid-template-columns: 1fr; }

  .app-sidebar,
  body.pp-app.sidebar-hidden .app-sidebar {
    display: flex;          /* le tiroir garde la colonne flex : nav defilant,
                               pied de version cale en bas */
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: var(--pp-sidebar-w-mobile);
    max-inline-size: 85vw;
    z-index: var(--pp-z-sidebar);
    transform: translateX(-100%);
    transition: transform var(--pp-dur-base) var(--pp-ease-standard);
    box-shadow: var(--pp-shadow-lg);
  }
  body.pp-app.sidebar-open .app-sidebar { transform: none; }
  body.pp-app.sidebar-open .app-scrim { opacity: 1; pointer-events: auto; }

  .app-main { padding: var(--pp-space-4) var(--pp-space-4) var(--pp-space-10); }
}

/* --- md : la recherche se replie, la topbar se resserre --- */
@media (max-width: 767.98px) {
  .app-header { padding: 0 var(--pp-space-3); gap: var(--pp-space-2); }
  .topbar-search { flex-basis: 100%; }
  .topbar-user-info { display: none; }
}

/* --- sm : telephone --- */
@media (max-width: 639.98px) {
  .topbar-context { display: none; }
  .app-header .user-avatar { display: none; }
  .topbar-icon { width: 32px; height: 32px; font-size: 1rem; }
  .app-main { padding: var(--pp-space-3) var(--pp-space-3) var(--pp-space-10); }
}

/* --- xl : plus de plafond de largeur --- */
/* Cette zone portait un « .app-main > * { max-inline-size: 1440px } » au-dela
   de 1600px, cense donner une largeur de lecture confortable. Il produisait
   l'effet inverse : chaque enfant direct du contenu etait rabote a 1440px et
   colle a gauche, tandis que les tableaux denses — dont la largeur min-content
   depasse le plafond — le traversaient et allaient jusqu'au bord. Sur /ao la
   bande de KPI s'arretait donc bien avant le tableau situe juste dessous.
   Les pages du projet sont des ecrans de travail (tableaux, grilles de KPI,
   filtres), pas des colonnes de texte : elles occupent toute la largeur. */
