/* ==========================================================================
   Commita — feuille de style partagee de la plateforme.
   Meme direction artistique que le site public (commita.net) :
   fond night-indigo, terracotta / or / teal, grain de film, zellige en
   filigrane, typographie editoriale a graisse contrastee.

   REGLE DE MAINTENANCE : aucune classe n'est renommee ni supprimee ici.
   Huit pages en dependent (.appbar .brand .appnav .card .grid .g2 .g3 .btn
   .btn-primary .btn-ghost .pill .msg .empty .field .wrap ...). On enrichit,
   on n'ampute pas. Les <style> locaux des pages sont charges APRES ce
   fichier : a specificite egale, la page garde le dernier mot.
   ========================================================================== */

/* --------------------------------------------------------------- TOKENS */
:root{
  --bg:#07090F;--bg-2:#0D1119;--bg-3:#141A26;
  --ink:#F6F4EF;--ink-2:#B3AFA4;
  /* --ink-3 remonte de #6F6C66 a #8B8880 : le gris precedent tombait a 3.7:1
     sur le fond, sous le seuil AA de 4.5:1 pour du texte de 14-15px.
     Il tient maintenant 5.4:1 sur --bg et 4.9:1 sur --bg-3. */
  --ink-3:#8B8880;
  /* BRAND ACCENTS on the dark app ground. Brightened from the logo values so
     they hold contrast on #07090F: blue #2E90F0, lime #C9D94A, teal #3FBFB0.
     Old token names kept as aliases so every rule keeps working. */
  --sky:#2E90F0;--brand-blue:#2E90F0;--brand-green:#7BC142;
  --terra:#2E90F0;--gold:#C9D94A;--teal:#3FBFB0;--indigo:#12233F;
  --terra-btn:#2E90F0;--terra-btn-2:#1E74D6;
  --terra-soft:#7FB6F2;--teal-soft:#8FD9D0;
  --line:rgba(46,144,240,.18);--line-2:rgba(246,244,239,.07);
  --line-3:rgba(246,244,239,.13);
  --r:14px;--r-lg:20px;
  --sans:ui-sans-serif,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;
  --ar:"SF Arabic","Geeza Pro","Noto Naskh Arabic",Tahoma,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  --ease:cubic-bezier(.22,.61,.36,1);
  --shadow:0 1px 0 rgba(246,244,239,.03) inset,0 22px 45px -34px rgba(0,0,0,.95);
  --shadow-hi:0 1px 0 rgba(246,244,239,.05) inset,0 26px 55px -30px rgba(0,0,0,1);

  /* Grain de film — exactement le meme data-URI que le site public. */
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");

  /* Zellige : etoile a huit branches (deux carres tournes de 45 deg),
     motif raccorde aux quatre coins pour se repeter sans couture. */
  --zellige:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cg fill='none' stroke='%232E90F0' stroke-width='1.1' stroke-linejoin='round'%3E%3Cg transform='translate(64 64)'%3E%3Crect x='-23' y='-23' width='46' height='46'/%3E%3Crect x='-23' y='-23' width='46' height='46' transform='rotate(45)'/%3E%3Ccircle r='10'/%3E%3C/g%3E%3Cg transform='translate(0 0)'%3E%3Crect x='-23' y='-23' width='46' height='46'/%3E%3Crect x='-23' y='-23' width='46' height='46' transform='rotate(45)'/%3E%3C/g%3E%3Cg transform='translate(128 0)'%3E%3Crect x='-23' y='-23' width='46' height='46'/%3E%3Crect x='-23' y='-23' width='46' height='46' transform='rotate(45)'/%3E%3C/g%3E%3Cg transform='translate(0 128)'%3E%3Crect x='-23' y='-23' width='46' height='46'/%3E%3Crect x='-23' y='-23' width='46' height='46' transform='rotate(45)'/%3E%3C/g%3E%3Cg transform='translate(128 128)'%3E%3Crect x='-23' y='-23' width='46' height='46'/%3E%3Crect x='-23' y='-23' width='46' height='46' transform='rotate(45)'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");

  /* Chevron des <select> (l'apparence native est neutralisee plus bas). */
  --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9'%3E%3Cpath d='M1 1l6 6 6-6' fill='none' stroke='%23B3AFA4' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
html[lang="ar"]{--sans:var(--ar)}

*{box-sizing:border-box;margin:0;padding:0}

/* L'attribut `hidden` doit gagner, toujours.
   La feuille de l'agent utilisateur ne pose que `[hidden]{display:none}` :
   la moindre regle d'auteur portant un `display` (ici `.appnav a{display:
   inline-flex}`, mais aussi `.grid{display:grid}` sur les sections de
   project.html) l'ecrase et laisse apparaitre un element que le JS croit
   masque. C'est ainsi que le lien « Administration » restait visible pour
   les membres non-admins sur directory/activity/academy : le gating JS etait
   correct, c'est le CSS qui le contredisait. Le controle d'acces reel est
   cote serveur (403), mais on ne montre pas une porte fermee.
   Regle globale et !important : `hidden` est une intention, pas un style. */
[hidden]{display:none!important}

html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scrollbar-color:var(--line-3) transparent}
body{background:var(--bg);color:var(--ink);font-family:var(--sans);line-height:1.6;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;min-height:100vh}

/* Grain de film : une couche fixe, non cliquable, qui casse l'effet
   « gabarit administratif » sans couter la moindre requete reseau. */
body::after{
  content:"";position:fixed;inset:0;z-index:200;pointer-events:none;opacity:.05;
  background-image:var(--grain);mix-blend-mode:overlay}

/* Aplat portant du texte blanc : --terra-btn (4.68:1) et non --terra (4.0:1). */
::selection{background:var(--terra-btn);color:#fff}
a{color:inherit;text-decoration:none}
:target{scroll-margin-block-start:6rem}
.wrap{width:min(1100px,92vw);margin-inline:auto}

/* Anneau de focus unique pour tout ce qui se parcourt au clavier.
   :where() garde une specificite nulle : n'importe quelle page peut le
   remplacer sans avoir a surencherir. */
:where(a,button,summary,[tabindex],[role="button"]):focus-visible{
  outline:2px solid var(--gold);outline-offset:3px}

/* --------------------------------------------------------------- APPBAR */
.appbar{position:sticky;top:0;z-index:50;
  background:linear-gradient(180deg,rgba(7,9,15,.94),rgba(7,9,15,.86));
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line-2)}
/* Lisere or : un filet degrade, presque subliminal, qui pose la marque. */
.appbar::after{content:"";position:absolute;inset-block-end:-1px;inset-inline:0;block-size:1px;
  background:linear-gradient(90deg,transparent,rgba(46,144,240,.55) 22%,rgba(123,193,66,.5) 50%,rgba(46,144,240,.55) 78%,transparent);
  opacity:.7;pointer-events:none}
.appbar .wrap{display:flex;align-items:center;gap:1.2rem;min-height:64px;padding-block:.3rem}
.brand{display:flex;align-items:center;gap:.55rem;font-weight:700;letter-spacing:-.02em;
  flex:none;min-height:44px}
.brand svg{width:26px;height:26px;flex:none}
.brand span{font-size:1.02rem}
.appnav{display:flex;align-items:center;gap:1.1rem;margin-inline-start:auto;
  font-size:.9rem;color:var(--ink-2);flex-wrap:wrap}
/* Cible tactile >= 44px : la barre reste dense a l'oeil, pas au doigt. */
.appnav a{display:inline-flex;align-items:center;min-height:44px;padding-block:.35rem;
  border-bottom:2px solid transparent;transition:color .2s var(--ease),border-color .2s var(--ease)}
.appnav a:hover{color:var(--ink);border-bottom-color:var(--line-3)}
.appnav a[aria-current="page"]{color:var(--gold);border-bottom-color:var(--gold)}

/* ------------------------------------------------------------ TYPOGRAPHIE */
main{padding-block:2.5rem 4rem;position:relative;isolation:isolate}
/* Zellige en filigrane derriere l'en-tete de page : un lavis tres faible,
   fondu vers le bas, jamais un fond decoratif franc. */
main{position:relative}
main::before{
  content:"";position:absolute;inset-block-start:0;inset-inline:0;block-size:min(460px,58vh);
  z-index:-1;pointer-events:none;opacity:.09;
  background-image:var(--zellige);background-size:132px 132px;background-position:center -18px;
  -webkit-mask-image:linear-gradient(180deg,rgba(0,0,0,1),transparent 85%);
  mask-image:linear-gradient(180deg,rgba(0,0,0,1),transparent 85%)}
/* Warm top glow echoing the marketing-site hero, so platform pages have depth
   instead of reading as flat black admin panels. Sits behind the zellige. */
main::after{
  content:"";position:absolute;inset-block-start:0;inset-inline:0;block-size:min(520px,60vh);
  z-index:-2;pointer-events:none;
  background:radial-gradient(120% 90% at 30% -10%, color-mix(in srgb,var(--terra) 14%, transparent), transparent 60%),
             radial-gradient(120% 90% at 85% -20%, color-mix(in srgb,var(--gold) 10%, transparent), transparent 55%)}
/* Meme filigrane, mais pose explicitement par une page qui le souhaite. */
.pagehead{position:relative;isolation:isolate;padding-block-end:.4rem}
.pagehead::before{content:"";position:absolute;inset:-1.4rem -1rem;z-index:-1;pointer-events:none;
  opacity:.055;background-image:var(--zellige);background-size:118px 118px;
  -webkit-mask-image:radial-gradient(120% 100% at 20% 0,rgba(0,0,0,.95),transparent 72%);
  mask-image:radial-gradient(120% 100% at 20% 0,rgba(0,0,0,.95),transparent 72%)}

/* Graisse 300 sur les grands titres + interlettrage negatif : c'est ce
   contraste de graisse qui fait la difference entre un outil interne et
   une page tenue editorialement. */
h1{font-size:clamp(1.75rem,3.6vw,2.55rem);line-height:1.08;letter-spacing:-.04em;
  font-weight:300;margin-block-end:.45rem;font-feature-settings:"liga" 1}
h1 b,h1 strong,h1 .grad{font-weight:700;letter-spacing:-.045em}
h1 .grad{background:linear-gradient(100deg,var(--gold),var(--terra) 60%,var(--gold));
  -webkit-background-clip:text;background-clip:text;color:transparent}
h2{font-size:1.2rem;font-weight:700;letter-spacing:-.02em;margin-block-end:.9rem}
h3{letter-spacing:-.01em}
.muted{color:var(--ink-3);font-size:.9rem}
.eyebrow{display:inline-flex;align-items:center;gap:.5rem;font-size:.72rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--gold);
  border:1px solid rgba(201,217,74,.28);background:rgba(201,217,74,.07);
  padding:.34rem .8rem;border-radius:999px}
/* L'arabe est une ecriture liee : tout interlettrage negatif la casse. */
html[lang="ar"] :is(h1,h2,h3,.brand,.eyebrow,.pill,th){letter-spacing:0}
html[lang="ar"] h1{font-weight:600;line-height:1.32}

/* ---------------------------------------------------------------- CARTES */
.card{position:relative;
  background:linear-gradient(180deg,var(--bg-2),var(--bg-2) 58%,rgba(21,28,44,.55));
  border:1px solid var(--line-2);border-radius:var(--r-lg);padding:1.5rem;
  box-shadow:var(--shadow);
  transition:border-color .35s var(--ease),box-shadow .35s var(--ease),transform .35s var(--ease);
  animation:rise .5s var(--ease) backwards}
/* Filet superieur degrade, revele au survol — repris de .card du site. */
.card::before{content:"";position:absolute;inset-block-start:0;inset-inline:0;block-size:1px;
  border-radius:var(--r-lg) var(--r-lg) 0 0;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--terra),transparent);
  opacity:0;transition:opacity .35s var(--ease)}
.card:hover{border-color:var(--line);box-shadow:var(--shadow-hi)}
.card:hover::before,.card:focus-within::before{opacity:1}
/* Le soulevement est reserve aux cartes cliquables : une carte qui porte un
   formulaire ne doit pas bouger sous le curseur pendant la saisie. */
a.card:hover,.card.is-link:hover{transform:translateY(-3px)}
.card > :last-child{margin-block-end:0}

.grid{display:grid;gap:1rem}
.g2{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}

/* ------------------------------------------------------------ FORMULAIRES */
label{display:block;font-size:.82rem;color:var(--ink-2);margin-block-end:.35rem;
  letter-spacing:.01em}
/* font-size : 16px pile, jamais moins.
   En dessous de 16px, Safari iOS zoome le viewport a la prise de focus et ne
   dezoome PAS au blur : le membre reste coince dans une page agrandie qu'il
   doit pincer pour reduire. Le .95rem precedent valait 15.2px et declenchait
   ce zoom sur toute la chaine d'authentification, le profil et les filtres du
   registre. On corrige par le corps de texte, jamais par
   `maximum-scale=1` / `user-scalable=no` : supprimer le pincement serait une
   regression d'accessibilite bien pire que le zoom automatique. */
input,select,textarea{width:100%;background:var(--bg-3);border:1px solid var(--line-2);color:var(--ink);
  border-radius:var(--r);padding:.7rem .85rem;font:inherit;font-size:1rem;
  transition:border-color .2s var(--ease),box-shadow .2s var(--ease),background .2s var(--ease)}
/* Cibles tactiles : 44px mini, sauf cases et boutons radio qui gardent leur
   dimension native (auth.html les masque volontairement en 1px). */
input:not([type="checkbox"]):not([type="radio"]),select{min-height:44px}
textarea{min-height:112px;resize:vertical;line-height:1.55}
input::placeholder,textarea::placeholder{color:var(--ink-3);opacity:1}
input:hover:not(:disabled),select:hover:not(:disabled),textarea:hover:not(:disabled){border-color:var(--line-3)}
input:focus,select:focus,textarea:focus{outline:2px solid var(--gold);outline-offset:1px;
  border-color:rgba(201,217,74,.45);background:var(--bg-2);
  box-shadow:0 0 0 4px rgba(201,217,74,.10)}
input:disabled,select:disabled,textarea:disabled,
input[readonly],textarea[readonly]{opacity:.55;cursor:not-allowed;
  background:rgba(20,26,38,.55);color:var(--ink-2);box-shadow:none}
input[type="checkbox"],input[type="radio"]{width:auto;min-height:0;accent-color:var(--terra)}
input[type="search"]{-webkit-appearance:none;appearance:none}
/* <select> : apparence native neutralisee pour un chevron coherent en
   sombre, avec la position miroir en RTL. */
select{-webkit-appearance:none;appearance:none;padding-inline-end:2.5rem;cursor:pointer;
  background-image:var(--chev);background-repeat:no-repeat;
  background-position:right .95rem center;background-size:13px 8px}
html[dir="rtl"] select{background-position:left .95rem center}
option,optgroup{background:var(--bg-3);color:var(--ink)}

.field{margin-block-end:1rem}
.field > .hint,.field-hint{display:block;font-size:.78rem;color:var(--ink-3);margin-block-start:.35rem}
/* Erreur : jamais annoncee par la seule couleur — bordure, halo et texte. */
[aria-invalid="true"],.field.is-invalid input,.field.is-invalid select,.field.is-invalid textarea{
  border-color:rgba(46,144,240,.6);box-shadow:0 0 0 3px rgba(46,144,240,.12)}
[aria-invalid="true"]:focus,.field.is-invalid :is(input,select,textarea):focus{
  outline-color:#F26D6D;box-shadow:0 0 0 4px rgba(230,74,74,.20)}
.field-err{display:flex;align-items:flex-start;gap:.4rem;font-size:.8rem;color:var(--terra-soft);
  margin-block-start:.35rem}
.field-err::before{content:"!";flex:none;inline-size:1.05em;block-size:1.05em;border-radius:50%;
  border:1px solid currentColor;font-size:.72rem;font-weight:700;line-height:1;
  display:grid;place-items:center;margin-block-start:.18em}
/* :user-invalid n'est pas partout : rule isolee pour ne pas invalider le reste. */
input:user-invalid,select:user-invalid,textarea:user-invalid{
  border-color:rgba(46,144,240,.6);box-shadow:0 0 0 3px rgba(46,144,240,.12)}
fieldset{border:0}
legend{font-size:.82rem;color:var(--ink-2);margin-block-end:.4rem}

/* ---------------------------------------------------------------- BOUTONS */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;font:inherit;
  font-weight:600;font-size:.93rem;min-height:44px;padding:.72rem 1.25rem;border-radius:999px;
  border:1px solid transparent;cursor:pointer;text-align:center;
  transition:transform .2s var(--ease),box-shadow .2s var(--ease),background .2s var(--ease),
             border-color .2s var(--ease),color .2s var(--ease)}
.btn-primary{background:linear-gradient(165deg,var(--terra-btn),var(--terra-btn-2));color:#fff;
  box-shadow:0 10px 30px -14px rgba(46,144,240,.85)}
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 16px 38px -14px rgba(46,144,240,.95)}
.btn-ghost{border-color:var(--line);background:rgba(246,244,239,.03);color:var(--ink)}
.btn-ghost:hover{border-color:var(--line-3);background:rgba(246,244,239,.07);transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
.btn:disabled,.btn[aria-disabled="true"]{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none;
  filter:saturate(.6)}
.btn-sm{min-height:36px;padding:.42rem .85rem;font-size:.85rem}
html[dir="rtl"] .btn svg{transform:scaleX(-1)}

/* ------------------------------------------------------------------ PILLS */
.pill{display:inline-flex;align-items:center;gap:.35rem;font-size:.72rem;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;line-height:1.5;
  padding:.25rem .62rem;border-radius:999px;border:1px solid var(--line);
  background:rgba(201,217,74,.07);color:var(--gold);white-space:nowrap}
.pill[data-s="validated"]{color:var(--teal);border-color:rgba(46,158,146,.4);background:rgba(46,158,146,.09)}
.pill[data-s="pending"]{color:var(--gold)}
.pill[data-s="rejected"]{color:#F28B8B;border-color:rgba(230,74,74,.42);background:rgba(230,74,74,.12)}

/* --------------------------------------------------------------- TABLEAUX */
table{width:100%;border-collapse:collapse;font-size:.9rem;font-variant-numeric:tabular-nums}
th,td{text-align:start;padding:.72rem .6rem;border-bottom:1px solid var(--line-2);vertical-align:top}
th{color:var(--ink-3);font-weight:600;font-size:.78rem;letter-spacing:.05em;text-transform:uppercase;
  white-space:nowrap;border-bottom-color:var(--line)}
tbody tr{transition:background .2s var(--ease)}
tbody tr:hover{background:rgba(246,244,239,.025)}
tbody tr:last-child :is(td,th){border-bottom:0}
caption{caption-side:bottom;text-align:start;color:var(--ink-3);font-size:.8rem;padding-block-start:.6rem}
code{font-family:var(--mono);font-size:.82rem;color:var(--ink-2);direction:ltr;display:inline-block}

/* ------------------------------------------------------- MESSAGES / VIDES */
.msg{position:relative;padding:.8rem 1rem;border-radius:var(--r);font-size:.9rem;
  margin-block-end:1rem;border:1px solid var(--line-2);
  animation:rise .35s var(--ease) backwards}
.msg.err{background:rgba(230,74,74,.12);border-color:rgba(230,74,74,.38);color:#F3A9A9}
.msg.ok{background:rgba(46,158,146,.12);border-color:rgba(46,158,146,.35);color:var(--teal-soft)}
.msg.info{background:rgba(201,217,74,.09);border-color:var(--line);color:var(--ink-2)}

.empty{text-align:center;color:var(--ink-3);padding:2.6rem 1rem;font-size:.92rem;
  border:1px dashed var(--line-2);border-radius:var(--r-lg);
  background:radial-gradient(120% 140% at 50% 0,rgba(201,217,74,.045),transparent 62%);
  animation:rise .45s var(--ease) backwards}
/* Losange zellige minuscule : un vide qui reste dessine, pas un trou. */
.empty::before{content:"";display:block;inline-size:20px;block-size:20px;margin:0 auto .75rem;
  border:1px solid var(--line);transform:rotate(45deg);opacity:.8}

/* ------------------------------------------------------------- ANIMATIONS */
/* fill-mode « backwards » et non « both » : une animation en « both » garde
   la main sur transform apres coup et neutraliserait les :hover. */
@keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes fade{from{opacity:0}to{opacity:1}}

/* ------------------------------------------------------------ RESPONSIVE */

/* En dessous de ~700px, la barre de navigation cessait d'etre une barre :
   les sept liens + les trois boutons de langue se repliaient sur quatre
   rangees, soit 209px de haut en francais — un quart d'un ecran de 844px —
   et, comme l'en-tete est `sticky`, ce quart etait confisque en permanence
   sur les cinq pages.
   Sans toucher au HTML (aucun bouton hamburger n'existe dans le balisage),
   deux mesures suffisent et se cumulent :
   1. l'en-tete repasse dans le flux : il defile avec la page et rend la
      totalite de la fenetre au contenu des qu'on descend ;
   2. les liens tiennent sur UNE seule ligne, faisable au doigt par un
      defilement horizontal, au lieu de s'empiler.
   Hauteur ramenee de 209px colles a ~100px qui s'en vont au defilement.
   La specificite `.appbar .appnav` (0,2,0) est volontaire : les <style> des
   pages sont charges apres ce fichier et definissent `.langbar` (0,1,0). */
@media(max-width:700px){
  .appbar{position:static}
  .appbar .wrap{flex-wrap:wrap;gap:.35rem .8rem;min-height:0;padding-block:.35rem .1rem}
  .brand{min-height:40px}
  .appbar .appnav{
    /* order:9 — la barre passe DERRIERE le selecteur de langue dans l'ordre
       visuel, donc rangee 1 = logo + langues, rangee 2 = navigation pleine
       largeur. Sans cela le selecteur de langue tombait sur une 3e rangee. */
    order:9;
    inline-size:100%;margin-inline-start:0;flex-wrap:nowrap;gap:.85rem;
    overflow-x:auto;overflow-y:hidden;overscroll-behavior-inline:contain;
    -webkit-overflow-scrolling:touch;scrollbar-width:thin;
    /* Marge interne : l'anneau de focus (outline-offset:3px) ne doit pas
       etre rogne par le conteneur de defilement. */
    padding-block:.2rem;padding-inline-end:.15rem}
  /* Rien ne se retrecit ni ne se coupe : on defile. */
  .appbar .appnav > *{flex:none}
  /* 44px et non 40 : c'est le minimum tactile, et la barre est justement
     l'endroit ou l'on vise au pouce, en marchant. */
  .appnav a{min-height:44px;white-space:nowrap}
  .appbar .langbar{margin-inline-start:auto}

  /* ---- cibles tactiles de la chrome permanente ----
     Mesures relevees au doigt sur 390x844 : FR 38x28, EN 38x28, ع 29x28.
     Le bouton arabe etait le plus petit controle de la plateforme, et c'est
     precisement celui dont un lecteur arabophone a besoin en premier.
     `.appbar .langbar button` (0,2,1) passe devant le `.langbar button`
     (0,1,1) des <style> locaux, charges apres cette feuille. */
  .appbar .langbar button{
    display:inline-flex;align-items:center;justify-content:center;
    min-block-size:44px;min-inline-size:44px;padding:.2rem .55rem}
  .appbar .langbar{gap:.3rem}
  /* Boutons compacts (fermeture de session : 155x37) : 44px au doigt. */
  .btn-sm{min-height:44px;padding-block:.5rem}
  /* Liens inline en fin de section (46x22, 77x22) : on rembourre en bloc.
     Sur un element inline le padding vertical n'ecarte pas les lignes, il
     n'agrandit QUE la zone cliquable — le rythme typographique ne bouge pas. */
  .link{padding-block:.7rem}
}

@media(max-width:640px){
  /* Le `gap` est desormais pose par le palier 700px ci-dessus (specificite
     0,2,0) ; ici on ne garde que la reduction de corps. */
  .appnav{font-size:.82rem}
  main{padding-block:1.8rem 3rem}
  .card{padding:1.2rem}
  h1{font-size:clamp(1.6rem,7vw,2rem)}
}

/* Mouvement reduit : on coupe, on ne raccourcit pas. */
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition-duration:.01ms!important}
  .card:hover,a.card:hover,.card.is-link:hover,.btn:hover{transform:none}
}
@media(prefers-contrast:more){
  :root{--ink-3:#A6A29A;--line-2:rgba(246,244,239,.16);--line:rgba(201,217,74,.4)}
  .card{border-color:var(--line-3)}
}
@media print{
  body::after,main::before,.appbar{display:none}
  body{background:#fff;color:#111}
  .card{border-color:#ccc;background:none;box-shadow:none}
}

/* ---- accessibility primitives ----
   These were duplicated in the local <style> of all 16 pages by the a11y repair
   pass. They belong here, once, next to the focus rules. */
.skip{position:absolute;inset-inline-start:-9999px;inset-block-start:0;z-index:999;
  background:var(--terra);color:#fff;padding:.75rem 1.1rem;border-radius:0 0 10px 0;
  font-weight:600;text-decoration:none}
.skip:focus{inset-inline-start:0}
.visually-hidden{position:absolute!important;inline-size:1px;block-size:1px;
  padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* ---- nav overflow ----
   The shared nav grew to 10 entries and wrapped around the logo. Keep it on a
   single line and let it scroll horizontally instead.

   CORRECTIF DE CASCADE — ce bloc etait pose a nu, en fin de fichier, donc APRES
   le palier `@media(max-width:700px)` ci-dessus. `.appbar .wrap{flex-wrap:nowrap}`
   et `.appbar .wrap{flex-wrap:wrap}` ont la meme specificite (0,2,0) : le
   dernier gagnait et annulait la mise en page mobile. Consequence mesuree sur
   390x844 : `inline-size:100%` n'avait plus de rangee ou s'appliquer, la barre
   se reduisait au reliquat entre le logo et les langues — clientWidth 111px
   pour scrollWidth 806px, soit 86% de la navigation hors ecran, 1 lien visible
   sur 11, et le lien de la page courante lui-meme hors champ.
   Tout le bloc est desormais borne a `min-width:701px` : il ne peut plus
   atteindre le mobile. */
@media(min-width:701px){
  .appbar .wrap{flex-wrap:nowrap}
  .appnav{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
    -ms-overflow-style:none;gap:.95rem;white-space:nowrap;min-inline-size:0}
  .appnav::-webkit-scrollbar{display:none}
  .appnav a{flex:none}
}
@media(min-width:1100px){.appnav{gap:1.15rem}}
@media(min-width:701px) and (max-width:900px){.appnav{font-size:.84rem;gap:.8rem}}

/* ============================================================ REPLI DE LA NAV
   Un defilement horizontal sans barre visible n'est pas une affordance : rien
   n'indique qu'il reste dix destinations a droite. Trois etats de repli, poses
   par app.js (`syncNavMode`) qui MESURE le debordement au lieu de le deviner a
   partir d'une largeur de fenetre — le contenu de la barre change avec la
   langue (l'arabe et l'anglais ne mesurent pas comme le francais) et avec le
   role (deux entrees de plus pour un admin).

   data-navmode="tight": il manque peu -> on resserre le pas et le corps, la
                         barre reste sur une seule rangee, tous les libelles
                         lisibles. C'est le cas du bureau a 1456px (900px de
                         liens pour 833px disponibles : « Deconnexion » etait
                         coupe a « De ») ; on retombe a ~775px.
   data-navmode="row"  : meme resserree la barre ne tient pas a cote du logo,
                         mais tiendrait sur une rangee entiere -> on lui donne
                         sa propre rangee. Aucun bouton, rien a apprendre.
   data-navmode="menu" : meme une rangee entiere ne suffit pas (telephone) ->
                         bouton de divulgation + panneau empile.

   Sans JavaScript, aucun attribut n'est pose : le palier 700px ci-dessus reste
   le repli, la barre garde sa rangee pleine largeur et son defilement. */
.navtoggle{display:none}

/* --- une rangee, resserree --- */
/* (0,3,0) : passe devant les paliers `.appnav` (0,1,0) poses plus haut. */
.appbar[data-navmode="tight"] .appnav{gap:.6rem;font-size:.82rem}

/* --- etats communs : la barre prend sa propre rangee --- */
.appbar[data-navmode="row"] .wrap,
.appbar[data-navmode="menu"] .wrap{flex-wrap:wrap;row-gap:0}
.appbar[data-navmode="row"] .appnav,
.appbar[data-navmode="menu"] .appnav{
  order:9;inline-size:100%;min-inline-size:0;margin-inline-start:0;flex:none}
.appbar[data-navmode="row"] .langbar{margin-inline-start:auto}

/* --- rangee dediee --- */
.appbar[data-navmode="row"] .appnav{
  flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:thin;
  border-block-start:1px solid var(--line-2);
  margin-block-start:.15rem;padding-block:.15rem}

/* --- panneau de divulgation --- */
.appbar[data-navmode="menu"] .navtoggle{
  display:inline-flex;align-items:center;justify-content:center;gap:.45rem;
  order:1;margin-inline-start:auto;flex:none;
  min-block-size:44px;min-inline-size:44px;padding:.35rem .8rem;
  font:inherit;font-size:.85rem;font-weight:600;line-height:1;color:var(--ink-2);
  background:rgba(246,244,239,.03);border:1px solid var(--line-2);border-radius:999px;
  cursor:pointer;
  transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease)}
.appbar[data-navmode="menu"] .langbar{order:2}
/* Sous ~430px le libelle « Menu » ne passe plus : logo + bouton + trois
   pastilles de langue de 44px font 363px pour 359px utiles, et le selecteur
   de langue tombait sur une deuxieme rangee — en arabe seulement, ce qui
   donnait un en-tete de 96px en AR contre 52px en FR. On garde l'icone
   seule ; le nom du controle reste porte par aria-label. */
@media(max-width:430px){
  .appbar[data-navmode="menu"] .navtoggle{padding-inline:.5rem}
  .appbar[data-navmode="menu"] .navtoggle span{display:none}
}
.navtoggle:hover{color:var(--ink);border-color:var(--line-3)}
.navtoggle[aria-expanded="true"]{color:var(--gold);border-color:var(--line);
  background:rgba(201,217,74,.08)}
.navtoggle svg{inline-size:17px;block-size:17px;flex:none}
.appbar[data-navmode="menu"] .appnav{
  flex-direction:column;align-items:stretch;flex-wrap:nowrap;gap:0;
  overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;
  /* 560px = les 11 entrees d'un membre (48px chacune) tiennent d'un coup sur
     un ecran de 844px, sans defilement interne ; au-dela (13 entrees pour un
     admin, ou un ecran court) le panneau defile plutot que de deborder. */
  max-block-size:min(72vh,560px);white-space:normal;
  border-block-start:1px solid var(--line-2);
  margin-block-start:.3rem;padding-block:.15rem .35rem;
  animation:fade .18s var(--ease)}
.appbar[data-navmode="menu"] .appnav a{
  min-block-size:48px;inline-size:100%;padding-inline:.2rem;
  border-block-end:1px solid var(--line-2)}
.appbar[data-navmode="menu"] .appnav a:last-child{border-block-end-color:transparent}
.appbar[data-navmode="menu"] .appnav a[aria-current="page"]{
  border-block-end-color:var(--gold);background:rgba(201,217,74,.06)}

/* ---- iOS zoom guard ----
   Safari on iOS zooms the whole page when a focused field is under 16px. A QA
   pass measured 15.2px on profile.html: page-level <style> blocks load after
   this file, so a bare `input{font-size:1rem}` here loses to them. The extra
   `body` raises specificity to (0,1,1) so the guard actually applies, and it is
   scoped to touch widths so desktop density is untouched. */
@media(max-width:700px){
  body input:not([type="checkbox"]):not([type="radio"]),
  body select,
  body textarea{font-size:16px}
}

/* Real brand mark in the appbar. The bright blue/green/yellow butterfly reads
   perfectly on the dark app ground. */
.brand .markimg{block-size:26px;inline-size:auto;flex:none;display:block}
.brand span{background:linear-gradient(90deg,var(--sky,#2E90F0),#7BC142);-webkit-background-clip:text;background-clip:text;color:transparent;font-weight:800}

/* ==================================================================== 2026 UI KIT
   Elevated shared primitives: motion, skeletons, toasts, data-viz marks, and a
   command palette. Page scripts consume these via window.Commita.* helpers. */
:root{
  --spring:cubic-bezier(.34,1.56,.64,1);
  --smooth:cubic-bezier(.4,0,.2,1);
  --c-cat-1:var(--sky,#2E90F0); --c-cat-2:var(--teal,#3FBFB0); --c-cat-3:var(--gold,#C9D94A);
  --c-good:#3FBFB0; --c-warn:#E0B341; --c-crit:#E5484D;
  --glass:linear-gradient(180deg,rgba(255,255,255,.03),rgba(255,255,255,0));
}
@media(prefers-reduced-motion:no-preference){
  .reveal{opacity:0;transform:translateY(12px);animation:rvup .55s var(--smooth) forwards}
  .reveal.d1{animation-delay:.06s}.reveal.d2{animation-delay:.12s}.reveal.d3{animation-delay:.18s}.reveal.d4{animation-delay:.24s}
  @keyframes rvup{to{opacity:1;transform:none}}
}
/* card lift + top sheen, applied opt-in via .card2 (never renames .card) */
.card2{position:relative;background:linear-gradient(180deg,var(--bg-2),var(--bg-2));border:1px solid var(--line-2);
  border-radius:var(--r-lg);transition:transform .3s var(--smooth),border-color .3s,box-shadow .3s;overflow:hidden}
.card2::before{content:"";position:absolute;inset-block-start:0;inset-inline:0;block-size:1px;
  background:linear-gradient(90deg,transparent,var(--sky,#2E90F0),transparent);opacity:0;transition:opacity .3s}
.card2:hover{transform:translateY(-3px);border-color:var(--line);box-shadow:0 18px 40px -24px rgba(0,0,0,.9)}
.card2:hover::before{opacity:.7}

/* skeleton shimmer */
.sk{position:relative;overflow:hidden;background:var(--bg-3);border-radius:8px;min-block-size:1em}
.sk::after{content:"";position:absolute;inset:0;transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.06),transparent);animation:shimmer 1.3s infinite}
@keyframes shimmer{100%{transform:translateX(100%)}}

/* toasts */
.toasts{position:fixed;inset-block-end:20px;inset-inline-start:50%;transform:translateX(-50%);z-index:500;
  display:flex;flex-direction:column;gap:.5rem;align-items:center;pointer-events:none}
html[dir=rtl] .toasts{inset-inline-start:auto;inset-inline-end:50%;transform:translateX(50%)}
.toast{pointer-events:auto;display:flex;align-items:center;gap:.6rem;background:var(--bg-2);
  border:1px solid var(--line);border-radius:12px;padding:.7rem 1rem;font-size:.9rem;color:var(--ink);
  box-shadow:0 16px 40px -18px rgba(0,0,0,.85);animation:tin .35s var(--spring)}
.toast.out{animation:tout .3s var(--smooth) forwards}
.toast .ic{inline-size:18px;block-size:18px;flex:none}
.toast.ok .ic{color:var(--c-good)}.toast.err .ic{color:var(--c-crit)}.toast.info .ic{color:var(--sky,#2E90F0)}
@keyframes tin{from{opacity:0;transform:translateY(12px) scale(.96)}}
@keyframes tout{to{opacity:0;transform:translateY(8px)}}

/* data-viz marks (thin marks, 4px rounded ends, recessive) */
.spark{display:block;inline-size:100%;block-size:40px;overflow:visible}
.spark .ln{fill:none;stroke:var(--sky,#2E90F0);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.spark .ar{fill:url(#sparkfill);opacity:.5}
.spark .dot{fill:var(--sky,#2E90F0)}
.ring{--v:0;--sz:64px;inline-size:var(--sz);block-size:var(--sz);border-radius:50%;display:grid;place-items:center;
  background:conic-gradient(var(--sky,#2E90F0) calc(var(--v)*1%),var(--bg-3) 0)}
.ring::before{content:"";position:absolute;inline-size:calc(var(--sz) - 12px);block-size:calc(var(--sz) - 12px);
  border-radius:50%;background:var(--bg-2)}
.ring b{position:relative;font-size:.9rem;font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums}
.bars{display:flex;align-items:flex-end;gap:3px;block-size:48px}
.bars i{flex:1;min-inline-size:4px;border-radius:4px 4px 2px 2px;background:var(--c-cat-1);opacity:.85;transition:block-size .5s var(--smooth)}

/* command palette */
.cmdk{position:fixed;inset:0;z-index:600;display:none;align-items:flex-start;justify-content:center;
  padding-block-start:12vh;background:rgba(3,6,12,.6);backdrop-filter:blur(4px)}
.cmdk.on{display:flex;animation:tin .2s ease}
.cmdk-box{inline-size:min(560px,92vw);background:var(--bg-2);border:1px solid var(--line);border-radius:16px;
  overflow:hidden;box-shadow:0 30px 80px -20px rgba(0,0,0,.9)}
.cmdk-box input{width:100%;background:transparent;border:0;border-block-end:1px solid var(--line-2);
  color:var(--ink);font:inherit;font-size:1.05rem;padding:1rem 1.2rem;outline:none}
.cmdk-list{max-block-size:52vh;overflow-y:auto;padding:.4rem}
.cmdk-item{display:flex;align-items:center;gap:.7rem;padding:.7rem .8rem;border-radius:10px;cursor:pointer;font-size:.93rem;color:var(--ink-2)}
.cmdk-item.sel,.cmdk-item:hover{background:var(--bg-3);color:var(--ink)}
.cmdk-item .k{margin-inline-start:auto;font-size:.72rem;color:var(--ink-3);border:1px solid var(--line-2);border-radius:5px;padding:.1rem .4rem}
.cmdk-empty{padding:1.2rem;color:var(--ink-3);text-align:center;font-size:.9rem}

/* ==================================================================== NAV 2026
   Replaces the old horizontal text-link bar with: a slim top bar (logo + tool
   cluster), a collapsible left ICON RAIL, and a mobile BOTTOM TAB BAR. These
   rules come last, so they override the legacy .appbar/.appnav styling above. */

/* --- slim top bar --- */
.appbar .wrap{gap:.8rem;min-height:56px}
.brand span{background:linear-gradient(90deg,var(--sky),#7BC142);-webkit-background-clip:text;background-clip:text;color:transparent;font-weight:800}
.appnav.apptools{display:flex;align-items:center;gap:.5rem;margin-inline-start:auto;flex-wrap:nowrap;border:0}
.apptools .tool{display:inline-flex;align-items:center;gap:.5rem;font:inherit;font-size:.85rem;font-weight:600;
  color:var(--ink-2);background:transparent;border:1px solid transparent;border-radius:999px;cursor:pointer;
  padding:.45rem .7rem;min-height:40px;transition:.18s var(--smooth)}
.apptools .tool svg{inline-size:19px;block-size:19px;flex:none}
.apptools .tool:hover{color:var(--ink);background:var(--bg-3)}
.apptools .tool.jump{border-color:var(--line-2);color:var(--ink-3);padding-inline-end:.55rem}
.apptools .tool.jump:hover{border-color:var(--line);color:var(--ink)}
.apptools .tool.jump kbd{font:inherit;font-size:.7rem;color:var(--ink-3);background:var(--bg-3);border:1px solid var(--line-2);border-radius:6px;padding:.05rem .35rem}
.apptools .tool.ico{padding:.45rem;position:relative}
.apptools .badge{position:absolute;inset-block-start:2px;inset-inline-end:2px;min-inline-size:16px;block-size:16px;
  border-radius:999px;background:var(--c-crit);color:#fff;font-size:.66rem;font-weight:800;display:grid;place-items:center;padding:0 3px}
.apptools .avatar-wrap{position:relative}
.apptools .avatar{background:var(--bg-3);border-radius:50%}
.avatar-menu{position:absolute;inset-block-start:calc(100% + .5rem);inset-inline-end:0;z-index:60;min-inline-size:200px;
  background:var(--bg-2);border:1px solid var(--line);border-radius:14px;padding:.4rem;box-shadow:0 20px 50px -18px rgba(0,0,0,.85);animation:tin .18s ease}
.avatar-menu .am-head{font-size:.8rem;color:var(--ink-3);padding:.5rem .7rem .3rem}
.avatar-menu a{display:flex;align-items:center;gap:.6rem;padding:.6rem .7rem;border-radius:10px;font-size:.9rem;color:var(--ink-2)}
.avatar-menu a svg{inline-size:17px;block-size:17px}
.avatar-menu a:hover{background:var(--bg-3);color:var(--ink)}
.avatar-menu .am-out{color:var(--terra-soft)}
@media(max-width:560px){.apptools .tool.jump .jt,.apptools .tool.jump kbd{display:none}.apptools .tool.jump{padding:.45rem}}

/* --- left icon rail (desktop) --- */
#nav-rail{position:fixed;inset-block:0;inset-inline-start:0;z-index:70;inline-size:64px;
  background:linear-gradient(180deg,rgba(13,17,25,.98),rgba(7,9,15,.98));border-inline-end:1px solid var(--line-2);
  display:flex;flex-direction:column;padding:.6rem .5rem;gap:.15rem;overflow:hidden;
  transition:inline-size .26s var(--smooth),box-shadow .26s;backdrop-filter:blur(10px)}
#nav-rail:hover,body.rail-open #nav-rail{inline-size:232px;box-shadow:24px 0 60px -30px rgba(0,0,0,.9)}
.rail-toggle{flex:none;inline-size:44px;block-size:44px;display:grid;place-items:center;background:transparent;
  border:0;border-radius:12px;color:var(--ink-3);cursor:pointer;margin-block-end:.4rem}
.rail-toggle svg{inline-size:20px;block-size:20px}
.rail-toggle:hover{color:var(--ink);background:var(--bg-3)}
.rail-nav{display:flex;flex-direction:column;gap:.12rem;overflow-y:auto;overflow-x:hidden;scrollbar-width:none}
.rail-nav::-webkit-scrollbar{display:none}
.rail-grp{font-size:.66rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);
  padding:.9rem .8rem .35rem;white-space:nowrap;opacity:0;transition:opacity .2s}
#nav-rail:hover .rail-grp,body.rail-open .rail-grp{opacity:1}
.rail-item{display:flex;align-items:center;gap:.85rem;padding:.6rem;border-radius:12px;color:var(--ink-2);
  position:relative;white-space:nowrap;min-block-size:44px;transition:background .18s,color .18s}
.rail-item .ri-ic{flex:none;inline-size:32px;block-size:24px;display:grid;place-items:center}
.rail-item .ri-ic svg{inline-size:21px;block-size:21px}
.rail-item .ri-lb{opacity:0;transition:opacity .2s;font-size:.9rem;font-weight:600}
#nav-rail:hover .ri-lb,body.rail-open .ri-lb{opacity:1}
.rail-item:hover{background:var(--bg-3);color:var(--ink)}
.rail-item.on{color:var(--sky)}
.rail-item.on::before{content:"";position:absolute;inset-inline-start:-.5rem;inset-block:.35rem;inline-size:3px;
  border-radius:999px;background:linear-gradient(180deg,var(--sky),var(--teal))}
.rail-item.on .ri-ic{color:var(--sky)}
@media(min-width:900px){
  body{padding-inline-start:64px}
  #nav-bottom{display:none}
}
@media(max-width:899px){
  #nav-rail{display:none}
}

/* --- mobile bottom tab bar --- */
#nav-bottom{position:fixed;inset-block-end:0;inset-inline:0;z-index:70;display:flex;
  background:rgba(7,9,15,.94);backdrop-filter:blur(14px);border-block-start:1px solid var(--line-2);
  padding-block-end:env(safe-area-inset-bottom,0)}
#nav-bottom .bb-item{flex:1;display:flex;flex-direction:column;align-items:center;gap:.15rem;padding:.5rem .2rem;
  background:transparent;border:0;color:var(--ink-3);font:inherit;font-size:.66rem;font-weight:600;cursor:pointer;min-block-size:52px}
#nav-bottom .bb-item svg{inline-size:22px;block-size:22px}
#nav-bottom .bb-item.on{color:var(--sky)}
#nav-bottom .bb-item:active{transform:scale(.94)}
@media(min-width:900px){main{padding-block-end:4rem}}
@media(max-width:899px){main{padding-block-end:5rem}}

/* --- mobile "more" sheet --- */
#nav-sheet{position:fixed;inset:0;z-index:80;display:flex;align-items:flex-end;background:rgba(3,6,12,.6);
  opacity:0;pointer-events:none;transition:opacity .25s}
#nav-sheet.on{opacity:1;pointer-events:auto}
.sheet-card{inline-size:100%;background:var(--bg-2);border-start-start-radius:20px;border-start-end-radius:20px;
  border-block-start:1px solid var(--line);padding:1rem 1.1rem calc(1.4rem + env(safe-area-inset-bottom,0));
  max-block-size:82vh;overflow-y:auto;transform:translateY(100%);transition:transform .3s var(--spring)}
#nav-sheet.on .sheet-card{transform:none}
.sheet-grab{inline-size:38px;block-size:4px;border-radius:999px;background:var(--line-3);margin:0 auto 1rem}
.sheet-grp{font-size:.68rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);margin:1rem 0 .5rem}
.sheet-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}
.sheet-item{display:flex;flex-direction:column;align-items:center;gap:.4rem;padding:.9rem .5rem;border-radius:14px;
  background:var(--bg-3);color:var(--ink-2);font-size:.76rem;font-weight:600;text-align:center;border:1px solid var(--line-2)}
.sheet-item svg{inline-size:22px;block-size:22px}
.sheet-item.on{color:var(--sky);border-color:color-mix(in srgb,var(--sky) 40%,transparent)}
.sheet-out{display:flex;align-items:center;justify-content:center;gap:.5rem;margin-block-start:1.2rem;padding:.8rem;
  border-radius:12px;background:var(--bg-3);color:var(--terra-soft);font-weight:600}

/* corrective (source order): the base #nav-bottom{display:flex} above re-enabled
   it on desktop; this final rule keeps it mobile-only. */
@media(min-width:900px){ #nav-bottom{display:none} }
@media(max-width:899px){ #nav-bottom{display:flex} .appbar .apptools .jump .jt{display:none} }
