/* ============================================================
   Back-office — charte v1.0.

   NOTE. Les regles de structure sont confinees sous `.app`, racine de la
   console. Cette feuille et club.css sont chargees ensemble, et plusieurs
   classes y portent des sens differents : `.nav` designe ici un bouton, la
   un conteneur ; `.side` a une largeur fixe ici, pas la-bas. Sans ce
   confinement, la console imposait sa mise en page a l'espace club.
   Repris du prototype contractuel specs/admin_phase1.html.

   Les jetons sont ceux de tokens.css, communs à l'espace membre et au
   back-office : cette feuille n'en redéfinit aucun. Elle ajoute les
   alias locaux du prototype, puis les composants propres à l'écran
   d'administration.
   ============================================================ */

/* Alias de compatibilité locale du back-office (bloc `:root` du prototype). */
:root{
  --ink-2:var(--muted);
  --accent-soft-2:rgba(226,0,26,.14);
  --sh-1:var(--shadow-1); --sh-2:var(--shadow-2); --sh-pop:var(--shadow-2);
  --sidebar:264px; --header:64px;
  --f:var(--font);
}
@supports (color: color-mix(in srgb, red 50%, white)) {
  :root{ --accent-soft-2:color-mix(in srgb, var(--accent) 14%, transparent); }
}

/* ============================================================
   SHELL
   ============================================================ */
/* `min-height:100vh` et non `100%` : le socle pose `html,body{height:100%}`,
   qui borne la hauteur du conteneur au lieu de la laisser croître. L'en-tête
   collant s'y trouvait rogné. */
.app{min-height:100vh;display:flex;flex-direction:column}

.header{
  position:sticky;top:0;z-index:60;height:var(--header);flex:none;
  display:flex;align-items:center;gap:16px;
  padding:0 20px;background:rgba(250,250,248,.86);
  -webkit-backdrop-filter:saturate(1.4) blur(12px);backdrop-filter:saturate(1.4) blur(12px);
  border-bottom:1px solid var(--line);
}
.header .spacer{flex:1}

/* `flex-direction:row` explicite : auth.css porte un `.brand` en colonne —
   la marque verticale des écrans de connexion, logo au-dessus du nom. Les
   deux prototypes emploient la même classe pour deux dispositions opposées,
   et sans cette déclaration la colonne d'auth.css l'emporterait ici. */
.header .brand{
  display:flex;flex-direction:row;align-items:center;gap:12px;min-width:0;
  margin:0;text-decoration:none;cursor:pointer;
  /* Le lien enveloppe deux lignes de texte et une pastille : sans rayon,
     l'anneau de focus du socle dessine un rectangle à angles vifs autour de
     tout le bloc, très visible au chargement de la page. */
  border-radius:var(--r-ctl);padding:4px;
}
.header .brand .logo{
  width:32px;height:32px;border-radius:var(--r-ctl);flex:none;
  background:var(--accent);color:var(--on-accent);display:grid;place-items:center;
  font-weight:600;font-size:12px;letter-spacing:.02em;box-shadow:var(--shadow-1);
}
.header .brand .names{display:flex;flex-direction:column;line-height:1.15;min-width:0}
.header .brand .club{font-weight:600;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.header .brand .kind{font-size:12px;color:var(--ink-2)}

.me{
  display:flex;align-items:center;gap:12px;padding:4px 8px 4px 4px;border-radius:var(--r-pill);
  transition:background var(--dur);cursor:pointer;list-style:none;
}
.me::-webkit-details-marker{display:none}
.me:hover{background:var(--n1)}
.me .who{line-height:1.15;text-align:right}
.me .who b{font-weight:600;font-size:14px;display:block}
.me .who span{font-size:12px;color:var(--ink-2)}

/* Avatars. La couleur de fond est tirée du nom côté client : sans elle, la
   pastille reste sur un neutre lisible plutôt que sur du transparent. */
.av{
  border-radius:var(--r-pill);display:grid;place-items:center;font-weight:600;flex:none;
  overflow:hidden;line-height:1;background:var(--n2);color:var(--muted-strong);
}
.av.s{width:32px;height:32px;font-size:12px}
.av.m{width:40px;height:40px;font-size:14px}
.av.l{width:56px;height:56px;font-size:18px}

/* Pas de `min-height:0` ici : la page défile normalement, et l'en-tête reste
   collant par `position:sticky`. Borner cette zone ferait défiler le contenu
   à l'intérieur d'elle, ce qui décrocherait la barre latérale collante. */
.body{flex:1;display:flex}

/* ============================================================
   BARRE LATERALE
   ============================================================ */
.app .side{
  width:var(--sidebar);flex:none;padding:16px 16px 24px;
  border-right:1px solid var(--line);
  position:sticky;top:var(--header);height:calc(100vh - var(--header));overflow-y:auto;
}
.navgroup{margin-bottom:var(--space-8)}
.navgroup>.gl{
  font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);padding:16px 12px 8px;
}
.app .nav{
  display:flex;align-items:center;gap:12px;width:100%;
  padding:12px;border-radius:var(--r-ctl);
  font-size:14px;font-weight:500;color:var(--ink-2);text-align:left;
  transition:background .18s var(--ease-out),color .18s;position:relative;
  border:none;background:none;cursor:pointer;font-family:inherit;text-decoration:none;
}
.app .nav svg{width:20px;height:20px;flex:none}
.app .nav:hover{background:var(--n1);color:var(--ink)}
.app .nav.on{background:var(--accent-soft);color:var(--accent-ink)}
.app .nav.on svg{color:var(--accent)}
/* Retour au clic : l'entrée prend l'accent dès l'appui, puis `.on` prend le
   relais quand la nouvelle page arrive.

   Volontairement `:active` et `:focus-visible`, et non `:focus`. La barre est
   rendue hors de la frame Turbo, donc jamais re-rendue : un `:focus` posé par
   la souris resterait accroché à l'entrée quittée, et deux entrées
   paraîtraient actives en même temps. Le contrôleur `admin-nav` retire donc
   aussi le focus clavier une fois la visite terminée. */
.app .nav:active{background:var(--accent-soft);color:var(--accent-ink)}
.app .nav:active svg{color:var(--accent)}
.app .nav:focus{outline:none}
.app .nav:focus-visible{
  background:var(--accent-soft);color:var(--accent-ink);
  outline:2px solid var(--accent);outline-offset:2px;
}
.app .nav:focus-visible svg{color:var(--accent)}
/* Une section inerte ne donne aucun retour : rien ne s'y ouvre. */
.app .nav.locked:active, .app .nav:disabled:active, 
.app .nav.locked:focus-visible, .app .nav:disabled:focus-visible{background:none;color:var(--ink-2)}
.app .nav.locked:active svg, .app .nav:disabled:active svg, 
.app .nav.locked:focus-visible svg, .app .nav:disabled:focus-visible svg{color:inherit}
.app .nav .count{
  margin-left:auto;font-size:12px;font-weight:600;color:var(--ink-2);
  background:var(--n2);border-radius:var(--r-pill);padding:1px 8px;
}
.app .nav.on .count{background:var(--accent-soft-2);color:var(--accent-ink)}
/* Sections à construire : visibles mais inertes, le prototype faisant foi
   sur la présence du menu complet. */
.app .nav.locked, .app .nav:disabled{opacity:.6;cursor:not-allowed}
.app .nav.locked:hover, .app .nav:disabled:hover{background:none;color:var(--ink-2)}

/* ============================================================
   ZONE PRINCIPALE
   ============================================================ */
.app .main{flex:1;min-width:0;display:flex;flex-direction:column}
.content{max-width:1200px;width:100%;margin:0 auto;padding:24px 32px 96px}

/* Une turbo-frame est en ligne par défaut : sans cette règle, la zone de
   contenu ne remplirait pas la largeur disponible. */
turbo-frame{display:block;flex:1}

.content.enter-view{animation:viewIn var(--dur-in) var(--ease-out)}
@keyframes viewIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ============================================================
   ATTENTE — squelettes, traces du prototype contractuel
   specs/admin_phase1.html (`skeletonFor`, `.sk`, `.skrow`).
   ============================================================ */

/* Le squelette double le contenu : il occupe la place pendant que la reponse
   arrive, puis s'efface. Les deux se superposent dans la meme boite, faute de
   quoi la page sauterait de l'un a l'autre. */
.viewstate{position:relative}
/* Fond opaque : le contenu ne s'efface plus pendant l'attente, et sans lui le
   squelette se lirait par transparence par-dessus le texte qu'il recouvre. */
.viewstate>.skeleton{position:absolute;inset:0;pointer-events:none;background:var(--bg)}

/* Rien ne s'affiche avant le seuil. Un squelette montre pendant 80 ms est
   un clignotement, plus genant que l'absence d'animation : on ne signale
   l'attente que lorsqu'il y a vraiment attente.

   Le retard est porte par l'animation et non par une transition : une
   transition repartirait de son etat courant a chaque bascule, quand
   l'animation, elle, se rejoue depuis le debut a chaque chargement. */
.skeleton{opacity:0}
turbo-frame[aria-busy="true"] .skeleton{animation:skeletonIn 0s var(--skeleton-delay,300ms) forwards}
@keyframes skeletonIn{to{opacity:1}}

/* Le contenu reste visible pendant l'attente.

   Il s'effacait auparavant des le depart de la requete, quand le squelette
   cense le remplacer n'apparaissait qu'apres 300 ms : l'ecran se vidait entre
   les deux. Aligner les deux seuils supprimait le vide mais laissait
   l'enregistrement d'un formulaire faire clignoter la saisie, ce que rien ne
   justifie — l'ecran ne change pas de contenu, il attend une confirmation.

   Le squelette garde son role, mais pour ce qu'il sait faire : occuper la
   place d'un contenu pas encore arrive. Il se superpose alors au contenu
   sortant, qui n'a plus a s'effacer pour lui laisser la place. */

.sk{
  background:linear-gradient(100deg,var(--n2) 30%,var(--n1) 50%,var(--n2) 70%);
  background-size:220% 100%;animation:sh 1.3s linear infinite;border-radius:var(--r-pill);
}
@keyframes sh{from{background-position:220% 0}to{background-position:-20% 0}}
.skrow{
  display:grid;grid-template-columns:var(--cols);gap:16px;align-items:center;
  padding:16px 24px;border-bottom:1px solid var(--line);
}
.skrow:last-child{border-bottom:none}
.skcirc{width:40px;height:40px;border-radius:50%;flex:none}
.skid{display:flex;align-items:center;gap:12px}
/* Colonne des actions : la largeur de deux boutons d'icone et de leur ecart,
   pour qu'une colonne en `auto` garde sa mesure pendant l'attente. */
.skact{width:88px;height:40px;border-radius:var(--r-ctl);margin-left:auto}

/* Un ecran qui n'attend pas ne s'anime pas : la reserve vaut pour le
   balayage comme pour l'entree de vue. */
@media (prefers-reduced-motion:reduce){
  .sk{animation:none}
  turbo-frame[aria-busy="true"] .skeleton{animation-duration:.001ms}
}

.phead{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:24px;flex-wrap:wrap}
.phead h1{font-size:32px;font-weight:600;letter-spacing:-.01em;margin:0}
.phead p{color:var(--ink-2);font-size:14px;margin:4px 0 0}
.phead .actions{display:flex;gap:12px;flex-wrap:wrap}

.prod-foot{margin:0 auto;max-width:1200px;width:100%;padding:0 32px 24px;text-align:center;font-size:12px;color:var(--ink-2)}

/* ============================================================
   TUILES DE CHIFFRES
   ============================================================ */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px}
.stat{
  background:var(--surface);border-radius:var(--r-card);box-shadow:var(--sh-1);padding:24px;
  display:block;text-decoration:none;color:inherit;
}
.stat .k{font-size:14px;color:var(--ink-2);font-weight:500;display:flex;align-items:center;gap:8px}
.stat .k svg{width:16px;height:16px;flex:none}
.stat .v{font-size:32px;font-weight:600;letter-spacing:-.02em;margin-top:8px;display:block}
.stat .d{font-size:12px;color:var(--ink-2);margin-top:4px;display:block}
.stat--link{cursor:pointer;transition:box-shadow var(--dur) var(--ease-out)}
.stat--link:hover{box-shadow:var(--shadow-2)}

/* ============================================================
   BOUTONS
   Le back-office porte ses propres modificateurs (.p, .s, .sm), distincts
   des .btn--primary du socle : le prototype les nomme ainsi.
   ============================================================ */
.btn.p{background:var(--accent);color:var(--on-accent);border-color:transparent}
.btn.p:hover{background:var(--accent-hover)}
.btn.s{background:var(--n2);color:var(--ink);border-color:var(--line)}
.btn.s:hover{background:var(--n3)}
.btn.sm{height:40px;padding:0 16px;font-size:14px}
/* Bouton reduit a son icone, pour les actions de ligne : un libelle y prend
   la place du nom qu'il accompagne, et l'effacait sur mobile ou la ligne
   devient une carte de deux colonnes. Carre, pour que l'icone soit centree
   et la cible tactile assez large. Le sens passe par `title` et
   `aria-label`, poses sur chaque bouton. */
.btn.sm.btn--icon{width:40px;padding:0}
.btn svg{width:20px;height:20px;flex:none}
.btn.sm svg{width:16px;height:16px}

/* ============================================================
   CARTES ET FORMULAIRES
   ============================================================ */
.card{background:var(--surface);border-radius:var(--r-card);box-shadow:var(--sh-1)}
/* Deux blocs qui se suivent respirent : sans cette regle ils se touchent, et
   l'ombre portee ne suffit pas a les separer — le formulaire « Designer un
   administrateur » semblait coller a la liste qui le precede.
   `.listcard` figure des deux cotes du selecteur : une liste precede souvent
   un formulaire, et ne pas la nommer laissait justement ce cas sans marge.
   La marge n'est posee qu'entre voisins, jamais sur le premier, qui suit deja
   l'en-tete de page. */
.card + .card,
.listcard + .card,
.card + .listcard,
.listcard + .listcard{margin-top:24px}
.pad{padding:24px}
.form-card{max-width:640px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}

/* Le socle stylise `.control input` ; les champs produits par le composant
   Form vivent dans la même enveloppe et héritent donc du même rendu. Restent
   à couvrir les types qu'il n'atteint pas. */
.control select,.control textarea{
  width:100%;height:48px;padding:0 16px;border-radius:var(--r-ctl);
  border:1px solid var(--line);background:#fff;color:var(--ink);font-size:16px;
  font-family:inherit;transition:border-color var(--dur),box-shadow var(--dur);
}
.control textarea{height:auto;min-height:112px;padding:12px 16px;resize:vertical;line-height:1.5}
.control select:focus,.control textarea:focus{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent);
}

/* ============================================================
   BARRE DE FILTRES
   ============================================================ */
/* Filtres d'une liste : un formulaire GET, l'etat de la recherche vivant dans
   l'URL. Les champs reprennent le rendu des `.control` du socle plutot que de
   le redefinir — un filtre est un champ comme un autre, en plus compact. */
.filters{margin-bottom:16px}
.filters-row{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.filters-search{flex:1 1 240px;min-width:0}
.filters input[type=search],.filters select{
  height:44px;padding:0 14px;border-radius:var(--r-ctl);
  border:1px solid var(--line);background:var(--surface);color:var(--ink);
  font-size:14px;font-family:inherit;
  transition:border-color var(--dur),box-shadow var(--dur);
}
.filters input[type=search]{width:100%}
.filters input[type=search]:focus,.filters select:focus{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent);
}
/* Sur mobile, les filtres s'empilent : cote a cote ils deviennent illisibles
   bien avant de manquer de place. */
@media (max-width:640px){
  .filters-row{flex-direction:column;align-items:stretch}
  .filters select,.filters .btn{width:100%}
}

.field .hint{font-size:12px;color:var(--ink-2);margin-top:8px}
.field .preview b{color:var(--ink);font-weight:600}

/* Astérisque des champs obligatoires. `abbr` porte un `title` que les
   navigateurs soulignent en pointillé : à retirer, le sens étant déjà donné
   au lecteur d'écran par le libellé masqué qui suit. */
.field label .required{
  color:var(--accent);margin-left:2px;
  text-decoration:none;border:none;cursor:default;
}

/* Texte réservé aux lecteurs d'écran. `display:none` ne conviendrait pas —
   il retire l'élément de l'arbre d'accessibilité, et rien ne serait lu. Le
   texte est donc rendu, mais réduit à un point hors du flux visible. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* Champ suivi d'un suffixe fixe (le domaine racine d'un sous-domaine) : les
   deux partagent un même cadre, l'anneau de focus entourant l'ensemble. */
.control--suffixed{
  display:flex;align-items:stretch;
  border:1px solid var(--line);border-radius:var(--r-ctl);background:#fff;
  transition:border-color var(--dur),box-shadow var(--dur);overflow:hidden;
}
.control--suffixed:focus-within{
  border-color:var(--accent);
  box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent);
}
.control--suffixed input{
  flex:1;min-width:0;border:none;border-radius:0;background:none;
  box-shadow:none;text-align:right;
}
.control--suffixed input:focus{outline:none;border:none;box-shadow:none}
.control--suffixed .suffix{
  display:flex;align-items:center;padding:0 16px 0 0;
  color:var(--ink-2);font-size:16px;white-space:nowrap;user-select:none;
}
/* L'anneau du cadre remplace celui du champ : le doubler cernerait deux
   rectangles imbriqués. */
.field.has-error .control--suffixed{
  border-color:var(--err);
  box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--err);
}
.field.has-error .control--suffixed input{box-shadow:none}

/* ------------------------------------------------------------
   Couleur — habillage de Coloris aux jetons de la charte.

   La bibliothèque construit elle-même sa pastille et son panneau ; ces
   règles ne font que les aligner sur le reste des formulaires. Les
   sélecteurs `.clr-*` sont ceux de Coloris.
   ------------------------------------------------------------ */
.control--color{position:relative}
/* Coloris enveloppe le champ : l'enveloppe doit occuper toute la largeur,
   sans quoi le champ se rétracte. */
.control--color .clr-field{display:block;width:100%}
.control--color .clr-field input{width:100%;padding-right:56px}

/* Pastille de couleur, à droite du champ. */
.control--color .clr-field button{
  width:32px;height:32px;right:8px;left:auto;top:50%;transform:translateY(-50%);
  border-radius:8px;border:1px solid var(--line);
}
/* Le damier de transparence signale « aucune couleur » plutôt qu'un noir
   trompeur. */
.control--color .clr-field button::after{border-radius:7px}

.clr-picker{
  border-radius:var(--r-card);box-shadow:var(--shadow-2);
  border:1px solid var(--line);background:var(--surface);
  font-family:var(--font);
}
.clr-picker input[type="text"]{
  font-family:var(--font);font-size:14px;color:var(--ink);
  border-radius:8px;border:1px solid var(--line);
}
.clr-picker input[type="text"]:focus{
  outline:none;border-color:var(--accent);
  box-shadow:0 0 0 2px var(--surface), 0 0 0 3px var(--accent);
}
.clr-swatches button{border-radius:6px}
.clr-clear,.clr-preview{border-radius:8px}
.clr-clear{
  font-family:var(--font);font-size:13px;font-weight:500;
  color:var(--ink-2);
}
.clr-clear:hover{color:var(--ink)}

/* Case à cocher : la case et son libellé sur une même ligne, la `.control`
   n'ayant pas de sens ici. */
.field .check{display:flex;align-items:center;gap:12px;cursor:pointer;font-size:14px;font-weight:500;margin:0}
.field .check input{width:20px;height:20px;flex:none;accent-color:var(--accent);cursor:pointer}

.form-actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:24px}

/* Bandeau d'erreur de niveau formulaire, repris de l'état d'erreur des
   écrans de connexion. */
.auth-error{
  display:flex;align-items:flex-start;gap:12px;
  background:var(--err-soft);color:var(--err);
  border-radius:var(--r-ctl);padding:12px 16px;margin-bottom:16px;font-size:14px;
}
.auth-error svg{width:16px;height:16px;flex:none;margin-top:2px}

/* ============================================================
   LISTES
   ============================================================ */
.listcard{background:var(--surface);border-radius:var(--r-card);box-shadow:var(--sh-1);overflow:hidden}
.listhead{
  display:grid;grid-template-columns:var(--cols);align-items:center;gap:16px;
  padding:16px 24px;border-bottom:1px solid var(--line);
  font-size:12px;font-weight:600;color:var(--ink-2);letter-spacing:.02em;text-transform:uppercase;
}
.row{
  display:grid;grid-template-columns:var(--cols);align-items:center;gap:16px;
  padding:12px 24px;border-bottom:1px solid var(--line);
  transition:background .16s var(--ease-out);position:relative;
}
.row:last-child{border-bottom:none}
.row:hover{background:var(--n1)}
.row .idc{display:flex;align-items:center;gap:12px;min-width:0}
.row .idc .nm{min-width:0}
.row .idc .nm b{font-weight:600;font-size:14px;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.row .idc .nm span{font-size:12px;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.row .cell{font-size:14px;color:var(--ink-soft)}

/* Adresse d'un club, sous son nom : elle double la colonne du meme nom, qui
   disparait en format carte. Masquee sur grand ecran, ou la colonne suffit —
   l'afficher aux deux endroits ferait doublon. */
.row .idc .nm .sub-domain{display:none;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}

/* Lien vers l'adresse du club. Discret par defaut : c'est une donnee de la
   ligne autant qu'un lien, et une couleur d'accent en ferait l'element le
   plus voyant de la liste. */
.domainlink{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;
  color:var(--ink-2);text-decoration:none;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;
}
.domainlink:hover{color:var(--accent);text-decoration:underline}

/* Actions de ligne : révélées au survol sur écran fin de pointage, toujours
   visibles au toucher, où le survol n'existe pas. */
.row .rowact{display:flex;gap:8px;justify-content:flex-end;opacity:0;transition:opacity .16s}
.row:hover .rowact,.row:focus-within .rowact{opacity:1}
@media (hover:none){.row .rowact{opacity:1}}
.mutedrow{opacity:.55}
.muted{color:var(--ink-2)}
.row code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;color:var(--ink-2)}

/* ============================================================
   PAGINATION
   ============================================================ */
.pager{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 24px;color:var(--ink-2);font-size:14px;
}
.pager .pg{display:flex;gap:8px;align-items:center}
.pgbtn{
  width:40px;height:40px;border-radius:var(--r-ctl);
  display:grid;place-items:center;
  border:1px solid var(--line);background:var(--surface);color:var(--ink-2);
  font-weight:500;font-size:14px;text-decoration:none;
  transition:background .15s,border-color .15s,color .15s;
}
a.pgbtn:hover{border-color:var(--n4);color:var(--ink)}
.pgbtn.on{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.pgbtn.is-disabled{opacity:.4;pointer-events:none}
.pgbtn svg{width:16px;height:16px}
/* Le chevron du jeu d'icônes pointe vers le bas : on le tourne d'un quart
   pour les deux bornes, plutôt que d'ajouter deux tracés de plus. */
.pgbtn[rel="prev"] svg,.pg > .pgbtn:first-child svg{transform:rotate(90deg)}
.pgbtn[rel="next"] svg,.pg > .pgbtn:last-child svg{transform:rotate(-90deg)}
.pgellipsis{color:var(--ink-2);padding:0 4px;user-select:none}

@media (max-width:560px){
  .pager{flex-direction:column;align-items:stretch;gap:16px;text-align:center}
  .pager .pg{justify-content:center;flex-wrap:wrap}
}

/* ============================================================
   ETIQUETTES
   ============================================================ */
.tag{
  display:inline-flex;align-items:center;gap:4px;height:24px;padding:0 12px;border-radius:var(--r-pill);
  font-size:12px;font-weight:500;background:var(--n2);color:var(--muted-strong);white-space:nowrap;
}
.tag.ok{background:var(--ok-soft);color:var(--ok)}
.tag.warn{background:var(--warn-soft);color:var(--warn)}
.tag.err{background:var(--err-soft);color:var(--err)}
.tag.acc{background:var(--accent-soft);color:var(--accent-ink)}
.tag.tiny{height:20px;font-size:12px;padding:0 8px}

/* Grappe d'etiquettes : les permissions d'un role tiennent rarement sur une
   ligne, et une liste qui deborde de sa cellule casse la grille. */
.taglist{display:flex;flex-wrap:wrap;gap:6px;min-width:0}

/* Bloc de champs distinct dans un meme formulaire : le trait separe ce qui
   releve d'un autre objet (l'administrateur, et non le club). */
.formsection{margin-top:24px;padding-top:24px;border-top:1px solid var(--line)}
.formsection h3{font-size:16px;font-weight:600;margin:0 0 4px}
.formsection p{font-size:14px;margin:0 0 16px}

/* ============================================================
   COMPOSITION DES ROLES
   ============================================================ */
.baseline-card{margin-bottom:24px}
.baseline-card h3{font-size:16px;font-weight:600;margin:0 0 4px}
.baseline-card p{font-size:14px;margin:0 0 12px}

/* Un groupe de permissions. `fieldset` sans bordure : la semantique compte
   pour les lecteurs d'ecran, le trait ne rimerait a rien ici. */
.permgroup{border:0;padding:0;margin:16px 0 0}
.permgroup legend{
  padding:0;font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--ink-2);margin-bottom:8px;
}

/* Une permission : la case, puis son libelle et ce qu'elle autorise. Cocher
   sans lire mene a trop accorder, d'ou la description sous chaque libelle. */
.permline{
  display:flex;align-items:flex-start;gap:12px;padding:10px 12px;border-radius:var(--r-ctl);
  cursor:pointer;
}
.permline:hover{background:var(--n2)}
.permline input{margin-top:2px;flex:none;width:16px;height:16px;accent-color:var(--accent)}
.permtext{display:flex;flex-direction:column;gap:2px;min-width:0}
.permtext b{font-size:14px;font-weight:500}
.permtext span{font-size:13px;color:var(--ink-2)}

/* ============================================================
   ETAT VIDE
   ============================================================ */
.empty{padding:64px 24px;text-align:center;color:var(--ink-2)}
.empty .ill{
  width:64px;height:64px;border-radius:var(--r-card);background:var(--accent-soft);
  display:grid;place-items:center;margin:0 auto 16px;color:var(--accent-ink);
}
.empty .ill svg{width:var(--icon-lg);height:var(--icon-lg)}
.empty h3{color:var(--ink);font-size:18px;font-weight:600;margin:0 0 8px}
.empty p{max-width:340px;margin:0 auto 16px;font-size:14px}

/* ============================================================
   MENU DEPLIANT (compte)
   ============================================================ */
.filterwrap{position:relative}
.pop{
  position:absolute;top:calc(100% + 8px);left:0;z-index:40;min-width:200px;
  background:var(--surface);border-radius:var(--r-card);box-shadow:var(--sh-2);padding:8px;
  border:1px solid var(--line);transform-origin:top left;animation:pop .18s var(--ease-out);
}
.pop.right{left:auto;right:0;transform-origin:top right}
@keyframes pop{from{opacity:0;transform:scale(.97) translateY(-4px)}to{opacity:1;transform:none}}
.pop .opt{
  display:flex;align-items:center;gap:12px;padding:8px 12px;border-radius:var(--r-ctl);
  font-size:14px;width:100%;text-align:left;transition:background .15s;
  border:none;background:none;cursor:pointer;font-family:inherit;color:inherit;text-decoration:none;
}
.pop .opt:hover{background:var(--n1)}

/* Selecteur de club — transposition de `.club-switch` du prototype
   contractuel specs/membre_phase1.html, en tete de barre laterale : il tient
   lieu de bloc de marque plutot que de s'ajouter a cote d'un bloc qui dirait
   la meme chose.

   Porte par un `details` natif comme les autres menus du back-office : il
   s'ouvre, se ferme au clic exterieur et a l'echappement sans code, et reste
   utilisable au clavier. */
.app .club-switch{position:relative;margin-bottom:var(--space-8)}
.club-switch>summary{list-style:none;cursor:pointer}
.club-switch>summary::-webkit-details-marker{display:none}
.app .club-btn{
  display:flex;align-items:center;gap:12px;width:100%;padding:12px;
  border-radius:var(--r-ctl);transition:background .18s var(--ease-out);
}
.club-switch>summary:hover .club-btn,.club-switch>summary.club-btn:hover{background:var(--n1)}
/* Un seul club : la marque reste, le menu disparait. */
.club-btn--static{cursor:default}
.club-meta{display:flex;flex-direction:column;line-height:1.25;min-width:0;text-align:left}
.club-meta .cn{font-weight:600;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.club-meta .ct{font-size:12px;color:var(--ink-2)}
.club-btn .chev{display:flex;width:16px;height:16px;margin-left:auto;color:var(--ink-2);flex:none;transition:transform .18s var(--ease-out)}
.club-switch[open] .chev{transform:rotate(180deg)}

/* Le menu s'ouvre sous la marque, sur toute la largeur de la barre. */
.club-menu{
  position:absolute;top:calc(100% + 8px);left:0;right:0;z-index:40;
  background:var(--surface);border-radius:var(--r-card);box-shadow:var(--sh-2);padding:8px;
  border:1px solid var(--line);transform-origin:top left;animation:pop .18s var(--ease-out);
}
.club-menu form{margin:0}
.club-item{
  display:flex;align-items:center;gap:12px;padding:8px 12px;border-radius:var(--r-ctl);
  font-size:14px;width:100%;text-align:left;transition:background .15s;
  border:none;background:none;cursor:pointer;font-family:inherit;color:inherit;
}
.club-item:hover{background:var(--n1)}
.club-item .club-name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Le club courant n'est pas un bouton : on y est deja. */
.club-item.active{cursor:default}
.club-item.active:hover{background:none}
.app .club-mono{
  display:grid;place-items:center;width:40px;height:40px;border-radius:var(--r-ctl);flex:none;
  background:var(--accent);color:var(--on-accent);font-size:12px;font-weight:600;
  box-shadow:var(--shadow-1);
}
.club-menu .club-mono{width:28px;height:28px;border-radius:10px;font-size:11px;box-shadow:none}
.club-item .dot{
  width:8px;height:8px;border-radius:50%;margin-left:auto;background:var(--ok);
  opacity:0;flex:none;
}
.club-item.active .dot{opacity:1}

/* ============================================================
   NOTIFICATIONS
   ============================================================ */
.toasts{
  position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:200;
  display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none;
}
.toasts .toast{
  display:flex;align-items:center;gap:12px;background:var(--ink);color:#fff;
  padding:12px 16px;border-radius:var(--r-ctl);box-shadow:var(--sh-2);
  font-size:14px;font-weight:500;pointer-events:auto;max-width:90vw;
  opacity:0;transform:translateY(12px);
  transition:opacity var(--dur) var(--ease-out),transform var(--dur) var(--ease-out);
}
.toasts .toast.show{opacity:1;transform:none}
.toasts .toast svg{width:16px;height:16px;flex:none}
/* Les variantes viennent de base.css, mais `.toasts .toast` ci-dessus est
   plus specifique et redefinit `background` : elles doivent donc etre reprises
   ici a specificite egale, sans quoi le fond neutre l'emporterait. */
.toasts .toast.ok{background:var(--ok);color:#fff}
.toasts .toast.err{background:var(--err);color:#fff}
.toasts .toast.warn{background:var(--warn);color:#fff}

/* ============================================================
   BARRE MOBILE
   ============================================================ */
.mnav{display:none}

@media (max-width:1080px){
  .stats{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:900px){
  :root{--header:56px}
  .side{display:none}
  .content{padding:16px 16px 112px}
  .prod-foot{padding:0 16px 96px}
  .header{padding:0 16px;gap:12px}
  .me .who{display:none}
  .phead h1{font-size:24px}

  /* Les lignes deviennent des cartes empilées. */
  .listhead{display:none}
  .row{grid-template-columns:1fr auto;gap:12px;padding:16px;align-items:flex-start}
  .row>.cell{display:none}
  .row>.cell.mkeep{display:flex}
  .row .idc{grid-column:1}
  /* La colonne « Adresse » est tombee avec les autres : l'adresse reparait
     sous le nom du club, ou elle reste lisible sans elargir la carte. Elle
     prend la place de la date de creation plutot que de s'y ajouter — trois
     lignes sous la pastille rendraient la carte confuse, et c'est l'adresse
     qui sert, la date se retrouvant sur grand ecran. */
  .row .idc .nm .sub-domain{display:block}
  .row .idc .nm .sub-date{display:none}
  /* Les actions reviennent à droite de l'identité, et toujours visibles : le
     survol n'existe pas au toucher. Le sélecteur doit porter `.cell`, sans quoi
     le `display:none` ci-dessus l'emporte — le prototype n'a pas ce besoin, son
     `.rowact` n'étant pas une cellule. */
  .row>.cell.rowact{display:flex;opacity:1;grid-column:2;grid-row:1}

  /* Deux champs côte à côte ne tiennent plus : le prototype les empile ici,
     et non à 560px. */
  .grid2{grid-template-columns:1fr}

  .mnav{
    display:flex;position:fixed;bottom:0;left:0;right:0;z-index:70;
    background:rgba(250,250,248,.94);
    -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
    border-top:1px solid var(--line);
    padding:8px 8px calc(8px + env(safe-area-inset-bottom));
    justify-content:space-around;
  }
  .mnav>a{
    display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px 12px;
    border-radius:12px;color:var(--ink-2);font-size:12px;font-weight:500;
    transition:color .18s;flex:1;position:relative;text-decoration:none;
    cursor:pointer;list-style:none;
  }
  .mnav>button{
    display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px 12px;
    border-radius:12px;color:var(--ink-2);font-size:12px;font-weight:500;
    flex:1;border:none;background:none;font-family:inherit;opacity:.5;cursor:not-allowed;
  }
  .mnav svg{width:24px;height:24px}
  .mnav>a.on{color:var(--accent)}
  /* Même retour au clic que dans la barre latérale, et même raison de s'en
     tenir à `:active` / `:focus-visible`. */
  .mnav>a:active{color:var(--accent)}
  .mnav>a:focus{outline:none}
  .mnav>a:focus-visible{color:var(--accent);outline:2px solid var(--accent);outline-offset:2px}

}
@media (max-width:560px){
  .stats{grid-template-columns:1fr 1fr;gap:12px}
  .stat{padding:16px}
  .stat .v{font-size:24px}
  /* Les actions de tête passent pleine largeur et se partagent la ligne. */
  .phead .actions{width:100%}
  .phead .actions .btn{flex:1}
}

@media (prefers-reduced-motion:reduce){
  .content.enter-view{animation:none}
}
