/* ═══════════════════════════════════════════════════════════════════════════
   SOCLE RESPONSIVE — la base commune de toute l'application.

   Avant, chaque page avait ses propres largeurs de bascule (22 valeurs
   différentes !) et ses propres tailles figées. Résultat : sur téléphone,
   des textes trop petits, des boutons impossibles à viser, des bouts de
   contenu coupés. Ce fichier pose une règle unique pour tout le monde.

   LES QUATRE TAILLES D'ÉCRAN, ET RIEN D'AUTRE :
     ≤ 420 px   petit téléphone            (--ecran: xs)
     ≤ 640 px   téléphone                  (--ecran: sm)
     ≤ 900 px   grand téléphone, tablette portrait   ← « mobile »
     ≤ 1200 px  tablette paysage, petit portable
     > 1200 px  ordinateur

   Il est chargé EN DERNIER : il peut donc corriger ce que les autres
   feuilles posent, sans qu'on ait à les réécrire une par une.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  /* Marge sur les côtés de la page : elle grandit avec l'écran, sans jamais
     coller au bord sur un petit téléphone ni s'étaler sur un grand écran. */
  /* theme.css définit déjà --page-x : on s'aligne dessus plutôt que
     d'inventer une deuxième valeur qui finirait par diverger. */
  --gouttiere:var(--page-x, clamp(14px,3vw,26px));
  --ecart:clamp(10px, 2.4vw, 16px);
  --ecart-grand:clamp(14px, 3.2vw, 24px);

  /* Hauteur réellement occupée par la barre du bas (encoche comprise). */
  --barre-bas:0px;
  --haut-sur:env(safe-area-inset-top, 0px);
  --bas-sur:env(safe-area-inset-bottom, 0px);

  /* Cibles tactiles : la taille minimale d'un bouton que l'on vise au doigt. */
  --touche:44px;
  --touche-mini:40px;
}

/* ── garde-fous universels ────────────────────────────────────────────────── */
img,video,canvas,svg,iframe{max-width:100%}
img,video{height:auto}
/* un mot à rallonge (adresse, jeton, nom de fichier) ne pousse plus la page */
p,li,td,th,dd,dt,label,figcaption,
.small,.faint,.muted,b,em,i,span:not(.ic),h1,h2,h3,h4{overflow-wrap:anywhere}
/* dans une rangée souple, un enfant peut toujours rétrécir */
.row>*,.ligne>*,.linkrow>*,.es-actions>*,.entete-section>*{min-width:0}

/* ═══════════════════════════════════════════════════════════════════════════
   OUTILS RÉUTILISABLES — à poser sur n'importe quel bloc, partout.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Dans une liste verticale qui défile, chaque ligne garde sa hauteur
   naturelle. Sans cela le navigateur les comprime pour tenir dans la boîte,
   et leur contenu déborde par le bas — c'est la cause la plus courante de
   « texte qui sort de sa carte » sur un téléphone. */
.liste-lignes>*,.liste-choix>*,.fil>*,.evlist>*,.feuille-liste>*,
.cms-liste>*,.liste-doc>*,.cands>*{flex:0 0 auto}

/* Une rangée qui défile du doigt au lieu de déborder. */
.rangee-defilante{display:flex;gap:var(--ecart);overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
  scroll-snap-type:x proximity;overscroll-behavior-x:contain}
.rangee-defilante::-webkit-scrollbar{display:none}
.rangee-defilante>*{flex:0 0 auto;scroll-snap-align:start}

/* Une grille qui choisit toute seule son nombre de colonnes. */
.grille-auto{display:grid;gap:var(--ecart);
  grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--min-carte,260px)),1fr))}

/* Empile verticalement dès qu'on passe sur téléphone. */
@media (max-width:640px){
  .pile-tel{display:flex;flex-direction:column;align-items:stretch}
  .pile-tel>*{width:100%}
}

/* ═══════════════════════════════════════════════════════════════════════════
   DOIGT PLUTÔT QUE SOURIS — tout ce qui se touche devient visable.
   Ne s'applique qu'aux écrans tactiles : la version bureau ne bouge pas.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (pointer:coarse){
  .btn{min-height:var(--touche);padding-block:10px}
  .btn.sm{min-height:var(--touche-mini);padding:9px 14px;font-size:.86rem}
  .btn.icone,.btn.icone.sm{min-width:var(--touche);min-height:var(--touche);padding:10px}
  .btn.icone.sm{min-width:var(--touche-mini);min-height:var(--touche-mini)}
  .btn.gros{min-height:52px}

  .tab,.sous-onglet{min-height:46px;padding-inline:14px}
  .chip,.puce,.filtres-puces button,.seg button,.segments button{min-height:var(--touche-mini);
    padding-block:9px;display:inline-flex;align-items:center}

  /* icônes seules posées dans une carte ou une liste */
  .heart,.ligne-out button,.cms-item-out button,.cms-vign-out button,.cms-tailles button,
  .pf-carte-out button,.doc-out button,.rdv-out button,.tuile-out button,.mini-out button,
  button.icone,a.icone{min-width:var(--touche);min-height:var(--touche)}
  .cms-haut,.cms-bas{min-width:var(--touche-mini);min-height:var(--touche-mini)}

  /* interrupteurs : on agrandit la zone, pas le dessin */
  label.interrupteur{min-height:var(--touche);padding-block:2px}
  label.interrupteur.mini,label.interrupteur.petit{min-height:var(--touche-mini)}

  /* cases à cocher et boutons radio */
  input[type=checkbox],input[type=radio]{width:22px;height:22px;flex:none}
  .check,.coche{min-height:var(--touche);align-items:center}

  /* liens seuls dans un paragraphe : on ne les grossit pas, on les espace */
  .feuille-liste button{min-height:52px}

  /* Boutons qui ressemblent à du texte (« Tout publier », « Fusionner… ») :
     on leur donne une vraie zone de frappe sans changer leur allure. */
  .lien-texte,.liens-bas .lien-texte,a.or,a.small.or,.oeil,
  .es-actions a:not(.btn),.entete-section a:not(.btn){
    min-height:var(--touche-mini);display:inline-flex;align-items:center}
  .lien-texte{padding-block:9px}
  .oeil{width:var(--touche);height:var(--touche)}
  /* une ligne entière cliquable (document, rendez-vous, client) */
  a.ligne,button.ligne,.carte-evt,.doc-ligne,.liste-doc a{min-height:var(--touche)}

  /* listes de liens sans classe : liens entre documents, titres de projets,
     puces de variables d'une campagne, réseaux du pied de page du site. */
  .liens-doc a,.pf-corps a,.cp-variables button,
  .pp-pied-liens a,.pp-reseaux a,.pp-pied a,.pp-marque{
    min-height:var(--touche-mini);display:inline-flex;align-items:center}
  .liens-doc a{min-height:var(--touche)}
  .cp-variables button{padding-block:9px}
  .pp-marque{min-height:var(--touche)}
}

/* ═══════════════════════════════════════════════════════════════════════════
   TÉLÉPHONE ET TABLETTE (≤ 900 px)
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width:900px){
  :root{--barre-bas:calc(62px + var(--bas-sur))}

  /* Une rangée qui se fait couper net au bord de l'écran a l'air cassée.
     On la fait s'effacer en douceur sur les 20 derniers pixels : ça se lit
     tout de suite comme « il y en a d'autres, faites glisser ».
     (Quand on est arrivé au bout, le dégradé disparaît.)                    */
  .filtres-puces,.sous-onglets,.pl-resume,.filters{
    --fondu:linear-gradient(90deg,#000 calc(100% - 20px),transparent);
    -webkit-mask-image:var(--fondu);mask-image:var(--fondu)}
  .filtres-puces:not(.defile),.sous-onglets:not(.defile),
  .pl-resume:not(.defile),.filters:not(.defile){-webkit-mask-image:none;mask-image:none}

  /* Plus rien de trop petit pour être lu au soleil de Bamako :
     11 px est le plancher, même pour les étiquettes et les pastilles. */
  .small,small{font-size:.84rem}
  .stat span,.chiffre span,.tag,.badge,.meta,.version,.side-file,
  .tf-badge,.ed-etiq,.doc-meta,.rdv-meta{font-size:.72rem}
  .mini-avatar,.pastille-nb,.nav-bas em,.nav-bas .pastille-nb,
  .pl-col-tete.jour span,.pl-bande button span,.pl-mois-j,.cp-heure,
  .small-brand,.pl-bloc-bas em,.pl-carte-bas em,.nav-bas a,.nav-bas button,
  #stats .stat span,.stats .stat span,.mois-col span,.gcount .small,
  .pp-marque small,.gcount-n span,.bar-legende span,
  .nav-bas a span,.nav-bas button span{
    font-size:.7rem!important;letter-spacing:.06em}
  .side-top .small-brand,.gtitle .small-brand,
  body.pf-galerie .gtitle .small-brand{letter-spacing:.2em}
  /* une pastille de compteur reste ronde même avec une police plus grande */
  .pastille-nb{min-width:22px;height:22px;border-radius:11px}
  .nav-bas .pastille-nb,.nav-bas em{min-width:18px;height:18px;border-radius:9px}

  /* Les champs : 16 px minimum, sinon l'iPhone zoome tout seul à la saisie. */
  input,select,textarea{font-size:16px}
  input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),
  select,textarea{min-height:var(--touche)}

  /* On laisse toujours la place de faire remonter le bas de page
     au-dessus de la barre d'onglets. */
  .main,.gpage,.vpage{padding-bottom:calc(var(--barre-bas) + 28px)}

  /* Un tableau ne tient jamais sur un téléphone : il défile. */
  .table-enveloppe,.tableau-defilant{overflow-x:auto;-webkit-overflow-scrolling:touch;
    scrollbar-width:none;margin-inline:calc(-1 * var(--gouttiere));
    padding-inline:var(--gouttiere)}
  .table-enveloppe::-webkit-scrollbar,.tableau-defilant::-webkit-scrollbar{display:none}
  table{width:100%}

  /* UNE seule marge latérale pour toute la page. Avant, la page avait 14 px
     et les rangées de puces se décalaient de 22 px pour aller « bord à
     bord » : elles dépassaient donc de l'écran. Les deux lisent désormais
     la même valeur, et le débordement ne peut plus arriver. */
  .main{padding-inline:var(--gouttiere)}

  /* Les barres d'onglets et de filtres défilent au lieu de se tasser. */
  .tabs,.sous-onglets,.filtres-puces,.segments,.cms-onglets,.tf-cats,
  .pt-filtres,.rp-statuts,.pl-onglets-mobile{
    overflow-x:auto;overflow-y:hidden;scrollbar-width:none;flex-wrap:nowrap;
    overscroll-behavior-x:contain}
  .tabs::-webkit-scrollbar,.sous-onglets::-webkit-scrollbar,
  .filtres-puces::-webkit-scrollbar,.cms-onglets::-webkit-scrollbar,
  .tf-cats::-webkit-scrollbar,.pt-filtres::-webkit-scrollbar{display:none}
  /* elles vont bord à bord, en reprenant exactement la marge de la page */
  .filtres-puces,.tf-cats,.pt-filtres,.rp-statuts{
    margin-inline:calc(-1 * var(--gouttiere));
    padding-inline:var(--gouttiere)}

  /* Un champ + un bouton côte à côte passent l'un sous l'autre. */
  .linkrow{flex-wrap:wrap}
  .linkrow>input{flex:1 1 100%}

  /* Sur un grand écran, la ligne de détail d'une opération tient en une
     ligne avec « … ». Sur un téléphone, mieux vaut deux lignes lisibles
     que la moitié de la phrase. */
  .ligne-corps .small,.doc-ligne .small,.ce-meta,.pp-cat-tete p{
    white-space:normal;display:-webkit-box;-webkit-box-orient:vertical;
    -webkit-line-clamp:2;line-clamp:2;overflow:hidden}
  .ligne{align-items:flex-start;gap:8px 12px}
  /* quand le montant passe à la ligne, il reste aligné à droite comme
     dans une colonne de comptes */
  .ligne-chiffres{align-self:center;margin-left:auto;text-align:right}
  .ligne-chiffres:only-child{margin-left:0}
}

/* ── petit téléphone (≤ 420 px) ───────────────────────────────────────────── */
@media (max-width:420px){
  .es-actions{width:100%}
  .es-actions>.btn:not(.icone){flex:1 1 auto}
  .grille-auto{--min-carte:100%}
}

/* ═══════════════════════════════════════════════════════════════════════════
   LE MENU LATÉRAL RÉTRACTABLE

   Sur téléphone, le panneau de gauche n'est plus supprimé : il glisse
   par-dessus la page quand on touche le hamburger. Le contenu ne bouge
   jamais d'un pixel — c'est ce qui fait la différence entre un menu qui
   « pousse » la page (et casse la mise en page) et un menu qui se pose
   dessus, comme dans WhatsApp.
   ═══════════════════════════════════════════════════════════════════════════ */
.hamburger{display:flex;flex-direction:column;justify-content:center;gap:4px;width:20px;height:16px}
.hamburger i{display:block;height:2px;border-radius:2px;background:currentColor;
  transition:transform .28s cubic-bezier(.2,.8,.2,1),opacity .18s}
.hamburger i:nth-child(1){width:20px}
.hamburger i:nth-child(2){width:14px}
.hamburger i:nth-child(3){width:17px}
body.menu-ouvert .hamburger i:nth-child(1){transform:translateY(6px) rotate(45deg);width:20px}
body.menu-ouvert .hamburger i:nth-child(2){opacity:0;transform:translateX(-8px)}
body.menu-ouvert .hamburger i:nth-child(3){transform:translateY(-6px) rotate(-45deg);width:20px}

#btnMenu{display:none}

@media (max-width:900px){
  #btnMenu{display:inline-flex;flex:none}
  /* on ne montre le retour que s'il sert : les deux ne se bousculent pas */
  .barre-mobile.avec-retour #btnMenu{display:none}

  /* le panneau : au-dessus de tout, jamais dans le flux */
  .side{display:flex!important;position:fixed;inset:0 auto 0 0;z-index:9200;
    width:min(86vw,330px);height:100vh;height:100dvh;overflow-y:auto;overscroll-behavior:contain;
    -webkit-overflow-scrolling:touch;flex-direction:column;
    padding:calc(18px + var(--haut-sur)) 16px calc(18px + var(--bas-sur));
    background:var(--bg2);border-right:1px solid var(--line);
    transform:translateX(-102%);visibility:hidden;
    transition:transform .34s cubic-bezier(.22,.8,.2,1),visibility 0s linear .34s;
    box-shadow:24px 0 60px rgba(0,0,0,.5)}
  body.menu-ouvert .side{transform:none;visibility:visible;transition-delay:0s}

  .voile-menu{display:block!important;position:fixed;inset:0;z-index:9100;
    background:rgba(0,0,0,.55);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);
    opacity:0;pointer-events:none;transition:opacity .3s}
  body.menu-ouvert .voile-menu{opacity:1;pointer-events:auto}
  /* la page ne défile plus derrière le menu ouvert */
  body.menu-ouvert{overflow:hidden}

  /* dans le panneau, tout se touche confortablement */
  .side .side-nav a,.side .side-lien{min-height:var(--touche);padding:12px 14px;border-radius:12px}
  .side .side-nav a[hidden]{display:none}
  .side .evlist{flex-direction:column;overflow:visible;gap:8px}
  .side .evitem{min-width:0;width:100%}
  .side-bot{margin-top:auto;padding-top:14px}
}

/* ═══════════════════════════════════════════════════════════════════════════
   LE CLAVIER NE DOIT JAMAIS CACHER LE CHAMP EN COURS
   ═══════════════════════════════════════════════════════════════════════════ */
input,select,textarea,.field,[contenteditable]{scroll-margin-block:96px 140px}

/* ── validation : on voit tout de suite ce qui ne va pas ──────────────────── */
.champ-erreur,input.champ-erreur,textarea.champ-erreur,select.champ-erreur{
  border-color:var(--red,#e06a60)!important;
  box-shadow:0 0 0 3px rgba(224,106,96,.18)!important;
  animation:tg-secoue .38s}
@keyframes tg-secoue{0%,100%{transform:none}20%{transform:translateX(-5px)}
  40%{transform:translateX(5px)}60%{transform:translateX(-3px)}80%{transform:translateX(3px)}}
.message-erreur{display:flex;align-items:flex-start;gap:7px;margin-top:6px;
  font-size:.82rem;color:var(--red,#e06a60);line-height:1.4}
.message-erreur svg.ic{width:15px;height:15px;flex:none;margin-top:1px}
/* un champ obligatoire encore vide ne crie pas avant qu'on ait essayé */
form.a-valider :invalid:not(:placeholder-shown){border-color:var(--red,#e06a60)}
/* quand mobile.js détecte le clavier, il pose --clavier : on réserve la place */
body.clavier-ouvert{--barre-bas:0px}
body.clavier-ouvert .nav-bas{transform:translateY(120%);pointer-events:none}
body.clavier-ouvert .barre-enregistrer.flottante,
body.clavier-ouvert .barre-action-tel{bottom:calc(var(--clavier, 0px) + 12px)}

/* ═══════════════════════════════════════════════════════════════════════════
   HAUTEURS D'ÉCRAN — 100vh ment sur téléphone (barre d'adresse). On prend
   la hauteur réellement visible.
   ═══════════════════════════════════════════════════════════════════════════ */
@supports (height:100dvh){
  .shell{min-height:100dvh}
  .side{height:100dvh}
}

/* ═══════════════════════════════════════════════════════════════════════════
   ANIMATIONS — vives mais légères, et coupées si l'appareil le demande.
   ═══════════════════════════════════════════════════════════════════════════ */
@keyframes tg-monte{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@keyframes tg-entre{from{opacity:0}to{opacity:1}}
@keyframes tg-pousse{from{transform:scale(.94)}to{transform:none}}

/* Changement de page : le contenu arrive au lieu d'apparaître d'un coup.
   Attention : l'application se rafraîchit toute seule en arrière-plan. On
   n'anime donc QUE sur une vraie navigation (mobile.js pose « nav-change »
   le temps de l'animation), sinon l'écran clignoterait sans arrêt. */
@media (max-width:900px){
  body.nav-change .section:not([hidden])>*{animation:tg-monte .32s cubic-bezier(.2,.8,.2,1) both}
  body.nav-change .section:not([hidden])>*:nth-child(2){animation-delay:.03s}
  body.nav-change .section:not([hidden])>*:nth-child(3){animation-delay:.06s}
  body.nav-change .section:not([hidden])>*:nth-child(n+4){animation-delay:.08s}
}

/* ═══════════════════════════════════════════════════════════════════════════
   MICRO-INTERACTIONS — de quoi sentir que l'on a bien appuyé.
   Uniquement des transformations et de l'opacité : rien qui fasse ramer.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (pointer:coarse){
  .btn,.chip,.tab,.carte-evt,.ligne,.pf-carte,.carte-reglage,.cms-modele,
  .cms-style,.cms-tuile,.pl-carte,.tache-carte,.evitem,.feuille-liste button,
  .pp-bouton,.pp-projet,.pp-univ,.pp-pack{transition:transform .16s cubic-bezier(.2,.8,.2,1),
    opacity .16s,background-color .16s,border-color .16s}
  .btn:active,.chip:active,.feuille-liste button:active,.pp-bouton:active{transform:scale(.96)}
  .carte-evt:active,.ligne:active,.pf-carte:active,.carte-reglage:active,
  .cms-modele:active,.cms-style:active,.pl-carte:active,.tache-carte:active,
  .evitem:active,.pp-projet:active,.pp-univ:active{transform:scale(.985)}
  /* on ne colore plus au survol (il n'y en a pas au doigt) : on éclaire à l'appui */
  .ligne:active,.evitem:active{background:rgba(var(--accent-rgb),.07)}
}
/* l'onglet du bas fait un petit ressort quand on le choisit */
.nav-bas a.on svg.ic,.nav-bas button.on svg.ic{animation:tg-ressort .34s cubic-bezier(.2,1.6,.4,1)}
@keyframes tg-ressort{0%{transform:translateY(-1px) scale(.85)}60%{transform:translateY(-1px) scale(1.12)}
  100%{transform:translateY(-1px) scale(1)}}

/* le hamburger et le voile respirent ensemble */
.voile-menu{will-change:opacity}
.side{will-change:transform}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
}
html[data-anim="reduites"] .section:not([hidden])>*,
html[data-anim="aucune"] .section:not([hidden])>*{animation:none}

/* Même règle dans l'application studio : un message ne masque jamais
   le bas d'une feuille ni la barre d'onglets. */
body.feuille-ouverte #toasts{top:calc(14px + env(safe-area-inset-top));bottom:auto}
