/* =============================================================================
   mobile.css — Refonte mobile STANDALONE du portail E-TRAK.
   Chargé APRÈS app.css + layout-fit.css. Entièrement scopé en @media : aucun
   impact sur le bureau. Supprimable d'un bloc (retirer le <link>) sans rien casser.
   Principe : sur petit écran, on abandonne le « plein écran sans scroll » (qui n'a
   pas de sens sur un téléphone) → tout défile naturellement, une colonne, cibles
   tactiles confortables, tableaux qui défilent horizontalement.
   ============================================================================= */

@media (max-width: 820px) {

  /* ---- 1. On neutralise le châssis « fit / fullscreen » : scroll naturel partout ---- */
  html:has(body.lyt-fit), body.lyt-fit,
  html:has(body.adash-fullscreen), body.adash-fullscreen { height: auto !important; overflow: visible !important; }
  body.lyt-fit .shell, body.lyt-fit .main,
  body.adash-fullscreen .shell, body.adash-fullscreen .main { height: auto !important; overflow: visible !important; }
  body.lyt-fit .content, body.adash-fullscreen .content { overflow: visible !important; min-height: 0; }

  /* ---- 2. Conteneur & cartes ---- */
  .content { padding: 14px 12px !important; max-width: none !important; }
  .card { padding: 14px; }
  .page-title { font-size: 19px; }

  /* ---- 3. Grilles : une seule colonne (KPIs = 2, puis 1 sur très petit) ---- */
  .grid.cols-2, .grid.cols-3, .dashf-cols,
  .adash-low, .adash-charts, .adash-side,
  .param-grid, .fact-grid, .calib-grid, .prn-grid, .set-grid,
  .adash-sys-grid {
    display: grid !important; grid-template-columns: 1fr !important; grid-template-rows: auto !important;
  }
  .param-grid .pg-wide, .set-grid .card.wide, .set-grid .card.half { grid-column: auto !important; }
  .grid.kpis, .admin-kpis, .adash-kpis { grid-template-columns: repeat(2, 1fr) !important; }
  /* Items de grille : min-width:0 OBLIGATOIRE. Par défaut un item grille/flex a min-width:auto
     = min-content ; si l'item contient une table à `th nowrap` (min-content large), la piste 1fr
     ne peut PAS rétrécir sous cette largeur → l'item déborde le conteneur et pousse la PAGE
     (ex. /systeme/journal : 2 cartes en .grid.cols-2, table audit → page à 412px). min-width:0
     laisse l'item rétrécir à la colonne ; la table reprend alors son scroll-x interne (ou tient). */
  .grid.cols-2 > *, .grid.cols-3 > *,
  .dashf-cols > *, .adash-low > *, .param-grid > *, .fact-grid > *,
  .calib-grid > *, .prn-grid > *, .set-grid > *, .adash-sys-grid > * { min-width: 0 !important; }

  /* ---- 4. Barre de période + filtres : empilés, pleine largeur ---- */
  /* Période (conteneur « Intervalle ») : libellé « Période » seul sur sa ligne en HAUT, puis les
     DEUX champs de date (début → fin) CÔTE À CÔTE sur une même ligne, de MÊME largeur, la flèche
     entre eux (lecture naturelle d'une plage, plus compact qu'empilé). Cible TOUS les inputs
     (type=date ET type=text/flatpickr du rapport). Raccourcis en grille 4 col pleine largeur dessous. */
  .dashf-period {
    width: 100% !important; display: flex !important; flex-wrap: wrap !important;
    align-items: center !important; gap: 8px !important;
  }
  .dashf-period .dashf-period-lbl { flex: 1 1 100% !important; margin-bottom: 2px !important; }  /* libellé seul, en haut */
  .dashf-period .dashf-sep { flex: 0 0 auto !important; margin: 0 !important; }                   /* flèche entre les 2 champs */
  .dashf-period input {
    flex: 1 1 0 !important; width: auto !important; max-width: none !important; min-width: 0 !important;
    margin-left: 0 !important;                                                                    /* 2 champs égaux, côte à côte */
  }
  .dashf-period .period-presets { flex: 1 1 100% !important; }                                    /* raccourcis pleine largeur, dessous */
  .flt-rest { flex-direction: column !important; align-items: stretch !important; }
  .flt-rest > .fsec + .fsec { padding-left: 0 !important; }
  .flt-rest > .fsec + .fsec::before { display: none !important; }
  .flt-rest .fsec-actions { margin-left: 0 !important; }
  .filterbox, .filterbox.flt-2 { width: 100%; }

  /* Présélections de période (Aujourd'hui … Tout) : 7 puces. La grille 4 col laissait un TROU
     à droite de la 2e rangée (4+3 → 1 cellule vide). On passe en FLEX-WRAP avec flex-grow : chaque
     rangée se remplit ENTIÈREMENT (4 puces rangée 1, 3 puces élargies rangée 2), zéro trou, bords
     alignés des deux côtés. !important : layout-fit.css impose display:flex/gap avec forte spécificité
     (body.lyt-fit .filterbox .dashf-period .period-presets …). */
  .period-presets {
    display: flex !important; flex-wrap: wrap !important;
    gap: 6px !important; width: 100% !important; margin-left: 0 !important;
  }
  .period-presets .lbl { display: none !important; }   /* l'étiquette ne prend pas de place */
  .period-presets .preset {
    flex: 1 1 22% !important;                          /* ~4 par rangée puis grow → rangées pleines */
    width: auto !important; min-width: 0 !important; margin: 0 !important;
    padding: 0 6px !important; font-size: 11.5px !important;
    /* display:flex + centrage 2 axes : .btn est inline-block → avec min-height:40px (§8)
       et padding vertical 0, le texte se collait EN HAUT (ex. « Cette semaine »). En flex,
       align-items+justify-content centrent vraiment le libellé dans la puce. */
    display: flex !important; align-items: center; justify-content: center;
    text-align: center; white-space: nowrap; line-height: 1.1;
  }

  /* ---- 5. Barres d'actions / exports : on garde CSV/PDF CÔTE À CÔTE ----
     §13 les empilait pleine largeur → deux énormes pavés dominant le haut de page.
     Ici : parts égales sur une seule rangée. Le style « teinté » (fond translucide
     + bordure + texte colorés) est désormais le style de base dans app.css
     (.rep-exp-btn.csv/.pdf), partagé desktop + mobile → rien à dupliquer ici. */
  .exp-bar { flex-wrap: wrap; gap: 8px; }
  .exp-bar .rep-exp-btn { flex: 1 1 0; text-align: center; justify-content: center; }
  .exp-bar .btn, .exp-bar .mac-back { flex: 1 1 auto; text-align: center; justify-content: center; }

  /* Rapport — rangée du haut (onglets de vue + exports CSV/PDF). Sur bureau : 3 onglets
     à gauche, exports poussés à droite par margin-left:auto. Sur mobile ce push laisse
     les exports rognés/serrés à droite sur une 2e ligne. On range en 2 rangées nettes :
     rangée 1 = onglets en parts égales ; rangée 2 = exports pleine largeur en parts
     égales. On annule le margin-left:auto (sinon les boutons restent collés à droite). */
  .viewtabs { flex-wrap: wrap; gap: 8px; }
  .viewtabs > a { flex: 1 1 0; text-align: center; padding: 10px 12px; }
  .viewtabs .rep-export { margin-left: 0 !important; flex: 1 1 100%; }
  .viewtabs .rep-export .rep-exp-btn { flex: 1 1 0; justify-content: center; text-align: center; }

  /* ---- 6. Tableaux : COMPACTION pour réduire le scroll horizontal ----
     Préf. UX (mémoire) : « vue d'ensemble > empilage ; ne rien retirer ». On ne
     empile donc PAS en cartes et on ne masque AUCUNE colonne. Le seul levier est
     de réduire ce que chaque colonne occupe : police 13→11.5px, padding resserré,
     et la colonne « Part » (barre de proportion, min-width:140px inline) ramenée à
     ~52px. Gain RÉEL ~15-20 % de largeur (ex. machines 847→720px). Honnêtement, ça
     n'élimine PAS le scroll pour 8-14 colonnes à 390px — physiquement impossible sans
     empiler/retirer (exclus par la préf. UX). Le scroll-x reste donc comme filet. */
  .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-height: none !important; }
  table.data { font-size: 11.5px; }
  /* white-space:nowrap : chaque colonne prend sa largeur naturelle → la table défile
     horizontalement (filet de sécurité) plutôt que de comprimer des colonnes en lignes
     énormes. NB : table-layout:fixed (pour tout faire tenir) a été testé et REJETÉ : il
     casse le rendu de certaines pages (noms de clients chevauchant la colonne tonnage)
     et agit de façon imprévisible d'une page à l'autre. Levier retenu = COMPACTION pure. */
  table.data th { padding: 6px 7px; white-space: nowrap; font-size: 10px; }
  table.data td { padding: 5px 7px; white-space: nowrap; }
  /* Colonne « Part » : barre de proportion forcée à min-width:140px en inline
     (machines/opérateurs/clients/utilisation) → ~90px gaspillés. Resserrée à 52px
     (la barre reste lisible en proportion). Gain de largeur fiable sur ces tables. */
  table.data td:has(> .bar-track) { min-width: 52px !important; }
  table.data .bar-track { min-width: 0 !important; }
  /* Cellules d'ACTIONS : les petits boutons groupés (.btn-act) s'empilaient verticalement quand la
     colonne est étroite (min-height:40px §8 × 4 boutons) → rangées énormes (rapports-auto : 195px !).
     On garde le groupe sur UNE ligne (la table défile déjà horizontalement pour les atteindre) et on
     compacte les boutons (actions secondaires, 34px suffit). :has(.btn-act) ne vise que ces cellules. */
  table.data td > div:has(.btn-act) { flex-wrap: nowrap !important; }
  table.data .btn-act { min-height: 34px !important; padding: 4px 9px !important; white-space: nowrap; }

  /* ---- 7. Cartes Leaflet : hauteur lisible ---- */
  #map, #mto-map, #rp-map, #minimap, .wx-map { height: 60vh !important; min-height: 300px; }
  .leaflet-container { min-height: 300px; }

  /* ---- 8. Cibles tactiles ≥ 40px ---- */
  input, select, textarea, .btn, .btn-mini, .preset, .rep-exp-btn { min-height: 40px; }
  .etk-mapbtn { width: 40px; height: 40px; }

  /* ---- 9. Modale : quasi plein écran ---- */
  .etk-modal { padding: 4vh 10px; align-items: center; }
  .etk-modal-dialog { width: 100%; max-height: 92vh; }

  /* ---- 10. Topbar compacte ---- */
  .topbar { padding: 0 12px; gap: 10px; }
  .topbar .page-lbl, .topbar .brand-name { display: none; }
  .topbar .user-role { display: none; }
  /* En mode « fit », layout-fit.css masque le h1.page-title (identité reportée dans la
     topbar via .page-lbl) ; mais ici .page-lbl est aussi masquée → plus AUCUN titre sur
     mobile. Comme les pages fit défilent déjà sur mobile, on réaffiche le titre en contenu. */
  body.lyt-fit .content .page-title { display: block !important; }

  /* ---- 11. Détail machine / opérateur : la carte « chargements » défile avec la page ---- */
  body.lyt-fit.page-machine #loads-card, body.lyt-fit.page-operateur #loads-card {
    min-height: 0 !important; max-height: none !important; display: block !important; }
  /* On retire le PLAFOND vertical (la carte grandit avec la page) MAIS on garde le
     défilement horizontal : sinon la table large pousse toute la page (overflow-x). */
  body.lyt-fit.page-machine .mac-loads-scroll, body.lyt-fit.page-operateur .mac-loads-scroll {
    overflow-x: auto !important; overflow-y: visible !important; max-height: none !important; }

  /* ---- 12. Dashboard admin : redevient une page qui défile ---- */
  body.adash-fullscreen .adash { height: auto !important; display: block; }
  body.adash-fullscreen .adash > * { margin-bottom: 14px; }
  body.adash-fullscreen .adash-chart { height: 240px !important; flex: none !important; }
  body.adash-fullscreen .adash-kpis .kpi { padding: 10px 12px; }

  /* ---- 13. Dashboard client (mode fit) : panneaux empilés, hauteurs auto ---- */
  body.lyt-fit .dashf-cols, body.lyt-fit .dashf { display: block !important; }
  body.lyt-fit .chart, body.lyt-fit .dashf-map { height: 300px !important; }
  /* Barre du haut : période puis pastille d'alerte EMPILÉES. La pastille « ⚠ N Voir les alertes »
     était poussée à droite (margin-left:auto) → orpheline avec un vide à gauche sur mobile. On la
     passe pleine largeur, centrée (meilleur équilibre + cible tactile). */
  .dashf-bar { flex-direction: column !important; align-items: stretch !important; gap: 10px !important; }
  .dashf-bar .dashf-alert {
    margin-left: 0 !important; width: 100% !important;
    justify-content: center !important; box-sizing: border-box !important;
  }

  /* ---- 14. Zones : la grille carte+liste reste en 2 col en mode fit (règle interne plus
     spécifique que son @media) → on force 1 col, sinon débordement horizontal de la page. ---- */
  body.page-zones #z-grid { grid-template-columns: 1fr !important; }
  body.page-zones #z-grid > .card { overflow: hidden !important; }

  /* ---- 15. Onglets (gestion, admin) : barre d'onglets qui s'enroule au lieu de déborder. ---- */
  .admin-tabs { flex-wrap: wrap; }

  /* ---- 15b. Entretien : les tables larges (échéances, journal) sont dans un .fsec d'une
     .card.filterbox, qui est un flex (layout-fit §.card.filterbox : display:flex row-wrap ;
     .fsec lui-même flex). Le min-width:auto d'un item flex = min-content de la table
     (gonflé par `th nowrap` global, app.css:514) → le .fsec ne rétrécit pas, la table
     dépasse l'écran, son scroll-x propre (table.data{display:block;overflow-x:auto},
     app.css:513) NE s'active pas, et .filterbox{overflow:hidden} (app.css:285) la rogne →
     colonnes inaccessibles. Fix mobile : le .fsec contenant une table repasse en block +
     min-width:0 → il rétrécit à la largeur de la carte, la table redevient un bloc normal
     (width:100%) et reprend son défilement horizontal interne. Ciblé :has(> table.data)
     pour ne PAS toucher les .fsec de filtres. (Tables hors flex, ex. gestion : défilent
     déjà, non concernées.) */
  .filterbox .fsec:has(> table.data) { display: block; min-width: 0; }

  /* ---- 16. Filtres : pour chaque ligne contenant UN DROPDOWN → LIBELLÉ à gauche,
     DROPDOWN collé à droite (au lieu du libellé empilé au-dessus). Ciblé via :has(> select)
     pour ne PAS toucher les champs texte ; navigateurs sans :has → repli empilé (inoffensif).
     !important nécessaire : layout-fit.css impose row/width:auto/height:26px avec une
     spécificité supérieure (body.lyt-fit .flt-rest .flt-filters …). */
  .filter-grid { grid-template-columns: 1fr !important; gap: 10px !important; }
  .filter-grid > div:has(> select),
  .flt-rest > .fsec:has(> select) {
    display: flex !important; flex-direction: row !important; align-items: center !important;
    justify-content: space-between !important; gap: 12px !important; flex: 1 1 auto !important;
  }
  .filter-grid > div:has(> select) > label,
  .flt-rest > .fsec:has(> select) > .fsec-title {
    margin: 0 !important; flex: 0 0 auto !important; white-space: nowrap;
  }
  .filter-grid > div:has(> select) > select,
  .flt-rest > .fsec:has(> select) > select {
    flex: 0 0 auto !important; width: 58% !important; max-width: 58% !important; min-width: 0 !important;
    height: auto !important; font-size: 14px !important; padding: 8px 28px 8px 10px !important;
  }

  /* ---- 16b. Paramètres : EXCEPTION à la règle #16. Les libellés y sont longs
     (« Unité de mesure », « Fond de carte »…) ; en disposition libellé-gauche/select-droite,
     un libellé nowrap + le select à 58% débordent la rangée de 340px et poussaient la PAGE à
     ~501px (débordement horizontal). On restaure le design natif de la page (.params) :
     libellé AU-DESSUS, contrôle PLEINE LARGEUR. Plus spécifique que #16 (.params en tête) → gagne. */
  .params .filter-grid > div:has(> select) {
    flex-direction: column !important; align-items: stretch !important; justify-content: flex-start !important;
  }
  .params .filter-grid > div:has(> select) > label {
    white-space: normal !important; flex: 0 0 auto !important;
  }
  .params .filter-grid > div:has(> select) > select {
    width: 100% !important; max-width: 100% !important;
  }

  /* ---- 17. Filtres d'analyse (rapport, utilisation…) : rythme vertical resserré ----
     Le conteneur .flt-rest empile en colonne « Ventiler par » + 7 sélecteurs de
     dimension, chacun à 40px (cible tactile §8) + 10px d'écart → ~450px avant le
     tableau. On compacte : écart de rangée 10→6px et sélecteurs 40→36px (reste
     confortable au doigt, picker natif). Hauteur globale ~−25 %, sans toucher la
     lisibilité ni le pattern libellé-gauche/champ-droite. Scopé .flt-rest (pages
     d'analyse) → n'affecte ni les filtres .filterbox simples ni les .params. */
  .flt-rest { gap: 6px 14px !important; }
  .flt-rest .filter-grid { gap: 6px !important; }
  .flt-rest select {
    min-height: 36px !important; height: 36px !important; font-size: 13px !important;
    padding-top: 6px !important; padding-bottom: 6px !important;
  }

  /* ---- 18. « À comparer » (.flt-pick) : sélecteur de comparaison (clients/matériaux/
     opérateurs…). Sur bureau c'est une grappe de cases en flex-wrap dans une boîte de
     66px qui scrolle — illisible sur mobile (jusqu'à 100+ entités tassées). On en fait
     une LISTE à colonne unique : en-tête propre (titre + Tout/Aucun compacts), puis cases
     pleine largeur, cibles tactiles, dans un cadre scrollable plus haut. ---- */
  .flt-rest .flt-pick { width: 100% !important; flex: 1 1 100% !important; }
  .flt-rest .flt-pick .flt-pick-head {
    display: flex !important; align-items: center; justify-content: space-between;
    gap: 8px; margin-bottom: 8px;
  }
  .flt-rest .flt-pick .chk-toggle { display: flex; gap: 8px; flex: 0 0 auto; }
  .flt-rest .flt-pick .chk-toggle .btn-mini {
    min-height: 32px; padding: 0 14px; border-radius: 8px; font-size: 12px;
  }
  .flt-rest .flt-pick .chk-group {
    display: flex !important; flex-direction: column !important; flex-wrap: nowrap !important;
    gap: 0 !important; max-height: 240px !important; overflow: auto !important;
    border: 1px solid var(--border); border-radius: 8px; background: var(--input, var(--card-2));
    -webkit-overflow-scrolling: touch;
  }
  .flt-rest .flt-pick .chk-group label {
    display: flex !important; align-items: center; gap: 10px;
    padding: 10px 12px !important; min-height: 42px; margin: 0 !important;
    border-bottom: 1px solid var(--border); cursor: pointer; font-size: 13px;
  }
  .flt-rest .flt-pick .chk-group label:last-child { border-bottom: 0; }
  .flt-rest .flt-pick .chk-group input[type=checkbox] { width: 18px; height: 18px; flex: 0 0 auto; accent-color: var(--accent-2); }
}

/* =============================================================================
   Contrôles de carte vs tiroir off-canvas — calé sur le breakpoint du tiroir
   (app.css : ≤860px → .sidebar devient un tiroir z-index 1000, backdrop 900).
   Les contrôles Leaflet (.leaflet-top/.leaflet-bottom = z-index 1000) et nos
   boutons custom (.etk-mapctl = z-index 1200) sont ≥ la sidebar et arrivent
   APRÈS elle dans le DOM → ils peignaient PAR-DESSUS le menu ouvert (+/− sur
   « Clients/Projets », boutons accueil/localiser/plein écran sur le voile).
   Fix scopé à l'état ouvert (body.nav-open) UNIQUEMENT : on fait passer tous
   les contrôles de carte SOUS le backdrop (z-index 400 = niveau des panes).
   La carte tiroir fermé n'est pas touchée (UX de zoom intacte). */
@media (max-width: 860px) {
  body.nav-open .leaflet-top,
  body.nav-open .leaflet-bottom,
  body.nav-open .etk-mapctl { z-index: 400 !important; }
}

/* Très petits écrans : KPIs gardés en 2 colonnes (compacts) plutôt qu'empilés en
   une seule colonne très haute — moins de scroll avant le contenu utile (graphes). */
@media (max-width: 460px) {
  .grid.kpis, .admin-kpis, .adash-kpis { grid-template-columns: repeat(2, 1fr) !important; gap: 8px !important; }
  .kpi .value, body.lyt-fit .kpi .value { font-size: 19px !important; line-height: 1.1; }
  .kpi .unit { font-size: 12px; }
  /* Tuiles plus denses : padding resserré + rythme interne compact → plus
     d'indicateurs visibles d'un coup (valeurs toujours bien lisibles). */
  .kpi { padding: 10px 11px !important; }
  .kpi .label { margin-top: 1px; line-height: 1.25; }
  .kpi .delta, .kpi .kpi-delta { font-size: 11px; }
  /* CSV/PDF restent côte à côte (2 boutons tiennent à 360px) ; les autres .btn s'empilent. */
  .exp-bar .btn { flex-basis: 100%; }
}

/* =============================================================================
   Sélecteur d'UNITÉ dans la topbar — clarté sur petit écran.
   Sous 480px, app.css masque l'étiquette .ts-cap → le sélecteur n'affiche plus
   qu'un « t » nu (ambigu : tonne ? texte ?), alors que « FR » (langue) se lit seul.
   On préfixe le sélecteur d'unité d'une petite icône balance monochrome (même gris
   %238a93a3 que la flèche des selects) → « ⚖ t ▾ » sans réafficher le mot.
   :has cible uniquement ce sélecteur (langue intacte). iOS 17 supporte :has. */
@media (max-width: 480px) {
  .topbar-select:has(#unit-select)::before {
    content: ""; flex: 0 0 auto; width: 14px; height: 14px; opacity: .8;
    background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a93a3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 3v18M6 7h12M9 7l-3 6a3 3 0 006 0L9 7zm9 0l-3 6a3 3 0 006 0l-3-6M8 21h8'/></svg>") no-repeat center / 14px;
  }
}

/* =============================================================================
   TABLEAUX → CARTES EMPILÉES sur TÉLÉPHONE (≤ 600px). Zéro scroll horizontal :
   chaque rangée devient une carte « libellé : valeur », toutes les colonnes visibles
   (rien retiré). Au-dessus de 600px (tablette/bureau) le tableau classique est conservé
   (+ compaction §6). Le libellé de chaque cellule vient de data-label, posé en JS
   (base.twig) depuis l'en-tête de colonne. Suppression d'un bloc = retirer ce @media
   + le petit script data-label dans base.twig.
   Pourquoi 600 et pas 820 : à 8 colonnes un tableau (~720px) tient déjà sans scroll
   dès ~720-800px de large (tablette / paysage), où la « vue d'ensemble » tabulaire
   reste préférable ; les cartes ne servent que là où l'écran ne peut PAS l'afficher. */
@media (max-width: 600px) {
  /* Le conteneur ne défile plus : les cartes s'empilent dans le flux normal. */
  .table-scroll { overflow-x: visible !important; }

  /* IMPORTANT — on ne carde QUE les vraies tables de données (avec <thead>).
     Les listes simples SANS en-tête (ex. Top clients/matériaux/transporteurs du
     dashboard : <tr><td>nom</td><td>valeur</td></tr>) sont traitées plus bas en
     « une ligne par entrée », surtout PAS en cartes (qui les couperaient en 2 lignes). */

  /* !important + max-width + overflow:visible : neutralise app.css:539
     (table.data{display:block;width:100%;overflow-x:auto}) qui laissait la table
     garder sa largeur max-content (~720px) et déborder hors écran (valeurs invisibles
     à droite). On force la table à la largeur de l'écran ; les cellules s'empilent. */
  table.data:has(thead) {
    display: block !important; width: 100% !important; max-width: 100% !important;
    min-width: 0 !important;            /* annule le min-content (~720px) résolu via auto */
    overflow: visible !important; font-size: 13px;
  }
  table.data:has(thead) thead { display: none !important; }        /* en-têtes repris cellule par cellule */
  table.data:has(thead) tbody { display: block !important; width: 100% !important; }
  /* :not(#zones-table) — cette table est un arbre repliable dont les lignes enfants
     sont masquées via inline display:none + toggle JS ; un display:block!important
     casserait le repli. Elle est restaurée en tableau classique plus bas. */
  table.data:has(thead):not(#zones-table) tr {
    display: block !important; width: auto !important; max-width: 100% !important;
    margin-bottom: 10px; padding: 4px 12px;
    border: 1px solid var(--border); border-radius: 10px; background: var(--card-2);
  }
  /* Lignes-hôtes de modale (/vehicules : <tr.veh-edit-host> ne contient qu'une popup position:fixed cachée) :
     ne PAS les rendre comme des cartes vides — neutralisées (0 hauteur), la modale s'affiche par-dessus à l'ouverture. */
  table.data:has(thead) tr.veh-edit-host,
  table.data:has(thead) tr.veh-edit-host td {
    display: block !important; margin: 0 !important; padding: 0 !important;
    border: 0 !important; background: none !important; border-radius: 0 !important;
  }
  table.data:has(thead) tbody tr:hover { background: var(--card-2); }   /* pas de surbrillance en mode carte */
  /* CORRECTIF GLOBAL : en mode cartes le `tr{display:block!important}` écrasait le masquage des filtres JS
     (style.display='none' inline). On rétablit la priorité du masquage inline pour TOUTES les tables filtrées. */
  table.data:has(thead):not(#zones-table) tr[style*="display:none"],
  table.data:has(thead):not(#zones-table) tr[style*="display: none"] { display: none !important; }

  /* Chaque cellule = une ligne « LIBELLÉ ………… valeur ». */
  table.data:has(thead) td {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 7px 0 !important; border: 0 !important; min-width: 0 !important;
    white-space: normal !important; text-align: right; overflow-wrap: anywhere;
  }
  table.data:has(thead) td + td { border-top: 1px solid var(--border) !important; }
  table.data:has(thead) td::before {
    content: attr(data-label); flex: 0 0 auto; margin-right: auto; text-align: left;
    color: var(--text-dim); font-size: 11px; font-weight: 600; text-transform: uppercase;
    letter-spacing: .4px; white-space: nowrap;
  }
  /* Cellule sans data-label (ex. ligne « aucune donnée » en colspan) : pas de préfixe. */
  table.data:has(thead) td:not([data-label])::before { content: ""; margin: 0; }
  table.data:has(thead) td[colspan] { justify-content: center; text-align: center; }

  /* 1re colonne « # » (rang) : en bandeau-titre de la carte, sans préfixe « # ». */
  table.data:has(thead) td[data-label="#"] { justify-content: flex-start; font-weight: 700; font-size: 14px; padding-top: 4px !important; }
  table.data:has(thead) td[data-label="#"]::before { content: "N° "; color: var(--text-dim); font-size: 11px; }

  /* Barre de proportion (« Part », « Taux d'utilisation »…) : RÉTRACTABLE (flex 0 1)
     pour laisser de la place à une valeur éventuelle à sa droite (ex. « 19,2 % »).
     Quand la cellule ne contient QUE la barre (Part), elle s'étire jusqu'à 130px. */
  table.data:has(thead) td .bar-track, table.data:has(thead) td .share { flex: 0 1 130px !important; width: 130px; max-width: 50%; min-width: 48px; }
  /* Valeur qui suit la barre (span.muted) : insécable → « 19,2 % » reste sur une ligne
     (la barre rétrécit à la place au lieu de faire passer le « % » à la ligne suivante). */
  table.data:has(thead) td .bar-track + span, table.data:has(thead) td .share + span { flex: 0 0 auto; white-space: nowrap; }

  /* Cellule d'actions (boutons) : alignée à droite, sur une ligne. */
  table.data:has(thead) td:has(.btn-act) { flex-wrap: wrap; justify-content: flex-end; }

  /* Cellule ÉDITABLE (contient un <input>, ex. matrice de tarifs matériaux×carrières) :
     libellé AU-DESSUS + champ PLEINE LARGEUR. Sinon un libellé long (« CARRIÈRE & SABLIÈRE
     BOISVERT (LA GABELLE) », nowrap) + un input à largeur fixe (80-90px) poussaient le champ
     HORS écran (débordement). Empilé, le libellé peut s'enrouler et le champ est confortable
     à éditer au doigt. */
  table.data:has(thead) td:has(input:not([type=checkbox]):not([type=hidden])) {
    flex-direction: column; align-items: stretch; gap: 4px; text-align: left;
  }
  table.data:has(thead) td:has(input:not([type=checkbox]):not([type=hidden]))::before {
    margin: 0; white-space: normal;
  }
  table.data:has(thead) td input:not([type=checkbox]):not([type=hidden]) {
    width: 100% !important; max-width: 100% !important; min-width: 0 !important; box-sizing: border-box;
  }

  /* ---- Listes SANS en-tête (Top clients/matériaux/transporteurs…) : UNE LIGNE par
     entrée. nom (tronqué …) à gauche, valeur à droite. Pas de carte, pas de scroll. ---- */
  table.data:not(:has(thead)) {
    display: block !important; width: 100% !important; min-width: 0 !important; overflow: visible !important;
  }
  table.data:not(:has(thead)) tbody { display: block !important; }
  table.data:not(:has(thead)) tr {
    display: flex !important; align-items: baseline; justify-content: space-between; gap: 12px;
    padding: 7px 0; border: 0; border-bottom: 1px solid var(--border);
  }
  table.data:not(:has(thead)) tr:last-child { border-bottom: 0; }
  table.data:not(:has(thead)) td { display: block; padding: 0 !important; border: 0 !important; white-space: nowrap; }
  table.data:not(:has(thead)) td:first-child { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  table.data:not(:has(thead)) td:last-child { flex: 0 0 auto; text-align: right; font-weight: 600; }

  /* Panneaux « top » du dashboard : plus de scroll interne (220px) — on laisse défiler
     la page. La liste s'affiche en entier, une ligne par entrée. */
  .dashf-scroll { max-height: none !important; overflow: visible !important; }

  /* ---- EXCLUSION du cardage : #zones-table (page Zones, « Zones définies ») ----
     C'est un ARBRE repliable : lignes carrière (.zone-parent) + tas enfants
     (.zone-child, display:none par défaut, dépliés au clic via JS). Le cardage
     forçait tr{display:block} → écrasait le display:none des enfants (toggle/
     sous-dossier cassés) et ::before injectait les libellés dans les cellules.
     On restaure un TABLEAU classique scrollable : le repli/dépli JS refonctionne. */
  .table-scroll:has(> #zones-table) { overflow-x: auto !important; }
  table#zones-table { display: table !important; width: auto !important; min-width: 0 !important; max-width: none !important; font-size: 11.5px; }
  table#zones-table thead { display: table-header-group !important; }
  table#zones-table tbody { display: table-row-group !important; }
  /* PAS de display forcé sur tr ici : les lignes enfants (.zone-child) doivent garder
     leur display:none inline (repli) ; le toggle JS les bascule. La règle de cardage tr
     exclut déjà #zones-table (:not), donc tr = table-row par défaut, inline respecté. */
  table#zones-table th, table#zones-table td {
    display: table-cell !important; padding: 6px 8px !important;
    border: 0 !important; border-bottom: 1px solid var(--border) !important;
    white-space: nowrap !important; text-align: left;   /* !important : bat le white-space:normal du cardage → la table scrolle au lieu d'enrouler les noms */
  }
  table#zones-table th::before, table#zones-table td::before { content: none !important; }
}

/* ===========================================================================
   TOPBAR — recherche « N° ticket » déplacée dans le tiroir latéral (≤ 860px).
   Sur petit écran la topbar débordait (search + langue + unité + compte ne
   tiennent pas) → on masque la recherche de la topbar et on révèle sa copie
   placée en haut du tiroir (.sidebar-ticket, cf. base.twig). Aligné sur le
   breakpoint du tiroir off-canvas (≤860px, app.css).
   =========================================================================== */
@media (max-width: 860px) {
  .topbar-ticket { display: none !important; }
  .sidebar-ticket { display: flex !important; align-items: center; }
}

/* ===========================================================================
   PONT-BASCULE — modales (popups) & afficheurs sur petit écran (≤ 600px).
   Le pont-bascule (templates/pont_bascule.twig) définit ses styles .wb-* en
   INLINE, sans variante mobile : les popups gardent donc leur marge desktop,
   leurs champs en 2 colonnes et un gros chiffre de balance qui débordent sur
   téléphone. Ici on les rend « pro » sur mobile — sans toucher au desktop.
   =========================================================================== */
@media (max-width: 600px) {
  /* Overlay : coller aux bords (récupère la largeur), ancrer en haut + zone sûre iOS,
     défilement vertical fluide. */
  .wb-modal { padding: 8px 6px !important; align-items: flex-start !important;
              padding-top: max(8px, env(safe-area-inset-top)) !important;
              -webkit-overflow-scrolling: touch; }
  .wb-modal > div { max-width: none !important; width: 100% !important; max-height: 95vh !important;
                    border-radius: 12px !important; }
  .wb-modal-head { padding: 12px 14px !important; font-size: 15px !important; }
  .wb-modal-body { padding: 13px 14px 18px !important; }
  .wb-modal-x { font-size: 30px !important; padding: 0 4px !important; }   /* cible tactile plus grande */

  /* Grilles de champs en 2 colonnes (inline grid-template-columns) → 1 colonne :
     les <select>/<input> prennent toute la largeur, plus faciles à toucher. */
  .wb-modal-body [style*="grid-template-columns"] { grid-template-columns: 1fr !important; }
  #ex-veh-pick > div { grid-template-columns: 1fr !important; }

  /* Bandeau « poids balance » en tête de modale : autoriser le retour à la ligne,
     réduire le gros chiffre pour qu'il ne pousse pas le bouton « figer » hors cadre. */
  .wb-mw-bar { flex-wrap: wrap !important; }
  .wb-mw { font-size: 27px !important; }
  .wb-mw-top { flex-wrap: wrap !important; }
  .wb-freeze { flex: 1 1 100% !important; justify-content: center !important; }  /* figer = pleine largeur, sous le poids */
  .wb-mw-breakdown { gap: 6px 14px !important; }

  /* Détail cour (clic sur une barre) : étiquettes au-dessus des valeurs plutôt qu'en 2 colonnes serrées. */
  .wb-yd-grid { grid-template-columns: 1fr !important; gap: 2px 0 !important; }
  .wb-yd-grid dt { margin-top: 6px; }

  /* Afficheur temps réel (pont sélectionné) : chiffre compact, le bouton « tare officielle »
     repasse à gauche au lieu d'être collé à droite. */
  .wb-display-val .wb-weight { font-size: 32px !important; }
  .wb-tare-top { margin-left: 0 !important; }
}

/* ============================================================================
   TABLEAUX .ui_table → CARTES sur téléphone (≤ 600px) — même rendu que table.data.
   Beaucoup de tableaux de données (RTK, capteurs, etc.) utilisent .ui_table ; on leur
   applique le mode carte « libellé : valeur » (data-label posé par le JS de base.twig,
   sélecteur étendu à .ui_table). Seules les tables AVEC <thead> sont cardées : les
   tables clé/valeur sans en-tête (ex. « Branchement ») gardent leur rendu normal.
   ============================================================================ */
@media (max-width: 600px) {
  table.ui_table:has(thead) {
    display: block; width: 100% !important; max-width: 100% !important; min-width: 0 !important;
    overflow: visible; font-size: 13px;
  }
  table.ui_table:has(thead) thead { display: none; }
  table.ui_table:has(thead) tbody { display: block; width: 100%; }
  table.ui_table:has(thead) tr {
    display: block; width: auto; max-width: 100%; margin-bottom: 10px; padding: 4px 12px;
    border: 1px solid var(--border); border-radius: 10px; background: var(--card-2);
  }
  table.ui_table:has(thead) td {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 7px 0 !important; border: 0 !important; min-width: 0 !important;
    white-space: normal !important; text-align: right; overflow-wrap: anywhere;
  }
  table.ui_table:has(thead) td + td { border-top: 1px solid var(--border) !important; }
  table.ui_table:has(thead) td::before {
    content: attr(data-label); flex: 0 0 auto; margin-right: auto; text-align: left;
    color: var(--text-dim); font-size: 11px; font-weight: 600; text-transform: uppercase;
    letter-spacing: .4px; white-space: nowrap;
  }
  table.ui_table:has(thead) td:not([data-label])::before { content: ""; margin: 0; }
  table.ui_table:has(thead) td[colspan] { justify-content: center; text-align: center; }

  /* 1re cellule = bandeau-titre de la carte (nom de la ligne), sans libellé. */
  table.ui_table:has(thead) td:first-child {
    justify-content: flex-start; text-align: left; font-size: 14px; font-weight: 700; color: var(--text);
    padding: 4px 0 8px !important; margin-bottom: 4px; border-bottom: 1px solid var(--border) !important;
  }
  table.ui_table:has(thead) td:first-child::before { content: ""; margin: 0; }

  /* Cellules d'ACTIONS / formulaires : libellé sur sa ligne puis contrôles pleine largeur (pas serrés). */
  table.ui_table:has(thead) td:is(:has(form), :has(.btn), :has(button), :has(select), :has(input)) {
    display: block; text-align: left;
  }
  table.ui_table:has(thead) td:is(:has(form), :has(.btn), :has(button), :has(select), :has(input))::before {
    display: block; margin: 0 0 5px;
  }
  table.ui_table:has(thead) td form { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 2px 4px 2px 0; }
  table.ui_table:has(thead) td .btn { margin: 2px 0; }
  table.ui_table:has(thead) td select, table.ui_table:has(thead) td input { max-width: 100%; }

  /* Cellule vide (ex. colonne d'actions vide pour un non-admin) : masquée. */
  table.ui_table:has(thead) td:empty { display: none; }
}
