@import "pico-theme-14_NLw3.css";

/* ------------------------------------------------------------------
   Jetons de mise en page.

   Les espacements et les tailles de titre passaient par des valeurs écrites au
   cas par cas : deux cartes voisines ne respiraient pas pareil et les titres se
   lisaient tous au même niveau. Ces jetons donnent un rythme unique, réglable
   d'un seul endroit.
   ------------------------------------------------------------------ */
:root {
  --app-space-xs: 0.25rem;
  --app-space-sm: 0.5rem;
  --app-space-md: 1rem;
  --app-space-lg: 1.5rem;
  --app-space-xl: 2.5rem;

  /* Hauteur d'un champ de formulaire, reprise de la formule des inputs Pico. Pico ne
     l'applique pas aux selects ni à Tom Select : ils s'en servent pour s'aligner. */
  --app-field-height: calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);

  /* Échelle typographique : chaque cran vaut environ 1,25 fois le précédent,
     assez pour hiérarchiser sans écraser le contenu. */
  --app-font-xs: 0.78rem;
  --app-font-sm: 0.875rem;
  --app-font-md: 1rem;
  --app-font-lg: 1.25rem;
  --app-font-xl: 1.6rem;

  /* Couleur de texte figée à la racine.
     Pico redéfinit --pico-color à l'intérieur d'un <a> — c'est ainsi qu'il colore
     les liens — donc `color: var(--pico-color)` sur une carte cliquable rend du
     bleu, pas du texte. Ce jeton, lui, garde la valeur du corps de page. */
  --app-text: var(--pico-color);
}

/* Hiérarchie des titres : le h1 domine la page, le h2 découpe, le h3 annote.
   Pico les rend presque identiques, d'où l'aplatissement constaté. */
main h1 {
  font-size: var(--app-font-xl);
  line-height: 1.2;
  margin-bottom: var(--app-space-xs);
}

main h2 {
  font-size: var(--app-font-lg);
  line-height: 1.3;
}

main h3 {
  font-size: var(--app-font-md);
  font-weight: 600;
  color: var(--pico-muted-color);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Sous-titre de page : la ligne qui suit le h1 dans un hgroup. */
main hgroup > p {
  color: var(--pico-muted-color);
  font-size: var(--app-font-sm);
}

/* Aide d'un champ : pastille « i » après le libellé, texte en info-bulle (Pico). */
.form-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  margin-left: 0.35rem;
  border: 1px solid currentColor;
  border-radius: 50%;
  color: var(--pico-muted-color);
  font-size: 0.65rem;
  font-weight: 700;
  font-style: normal;
  line-height: 1;
  vertical-align: 0.1em;
  cursor: default;
  /* Pico souligne en pointillé tout élément à info-bulle */
  border-bottom: 1px solid currentColor;
}

.form-info:hover,
.form-info:focus-visible {
  color: var(--pico-primary);
}

/* L'infobulle Pico ne passe pas à la ligne : une aide de deux phrases sortait de
   l'écran. Son z-index (99) la laissait aussi sous la barre latérale (100). */
.form-info[data-tooltip]::before,
.form-info[data-tooltip]::after {
  z-index: 150;
}

.form-info[data-tooltip]::before {
  width: max-content;
  max-width: min(18rem, 60vw);
  white-space: normal;
  text-align: left;
  font-weight: 400;
  line-height: 1.4;
}

/* App shell : sidebar + contenu principal */
.app-shell {
  display: grid;
  grid-template-columns: 240px 1fr;
  min-height: 100vh;
}

.app-shell--no-sidebar {
  grid-template-columns: 1fr;
}

.app-content {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.app-content > main.container {
  flex: 1;
  padding: 1.5rem 2rem 2rem;
  max-width: none;
  width: 100%;
}

@media (max-width: 768px) {
  .app-content > main.container {
    padding: 1rem 1rem 1.5rem;
  }
}

.app-footer {
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--pico-muted-border-color);
  text-align: center;
  color: var(--pico-muted-color);
}

/* Sidebar */
.sidebar {
  background: var(--pico-card-background-color);
  border-right: 1px solid var(--pico-muted-border-color);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  z-index: 100;
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.1rem 1rem;
  border-bottom: 1px solid var(--pico-muted-border-color);
}

.sidebar-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 700;
  color: inherit;
  text-decoration: none;
  font-size: 1.05rem;
}

.sidebar-brand-icon {
  font-size: 1.4rem;
}

/* Logo déposé par le club : cadré sur la hauteur de la ligne de marque, quelle
   que soit la taille du fichier fourni. */
.brand-logo {
  height: 1.6em;
  width: auto;
  vertical-align: middle;
}

.sidebar-close {
  display: none;
  background: transparent;
  border: 0;
  color: var(--pico-muted-color);
  font-size: 1.25rem;
  cursor: pointer;
  padding: 0.25rem 0.5rem;
  width: auto;
}

.sidebar-nav {
  flex: 1;
  padding: 0.75rem 0;
}

.sidebar-nav ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

/* Pico tire la première liste d'un <nav> vers la gauche — marge négative prévue
   pour une barre horizontale. Dans une barre verticale, le premier groupe se
   retrouvait 7 px en avant du groupe Administration. Le sélecteur reprend celui
   de Pico, à égalité de spécificité : app.css est chargé après, il l'emporte. */
.sidebar-nav ul:first-of-type {
  margin-left: 0;
}

.sidebar-nav li {
  margin: 0;
}

.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 1rem;
  /* Texte courant, pas bleu de lien : dans un menu tout est cliquable, donc
     colorer chaque entrée en accent efface la seule qui compte, l'entrée active.
     (--pico-color vaut le bleu de lien à l'intérieur d'un <a>.) */
  color: var(--app-text);
  text-decoration: none;
  border-left: 3px solid transparent;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.sidebar-nav a:hover,
.sidebar-nav a:focus-visible {
  background: var(--app-surface-muted);
  color: var(--app-text);
}

.sidebar-nav a.active {
  background: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  border-left-color: var(--pico-primary);
  font-weight: 600;
}

.sidebar-icon {
  display: inline-flex;
  width: 1.5rem;
  justify-content: center;
  align-items: center;
  color: var(--pico-muted-color);
}

.sidebar-icon .icon {
  width: 1.15rem;
  height: 1.15rem;
}

/* L'entrée active teinte aussi son icône : sans cela l'icône reste grise sur
   fond marqué et l'ensemble paraît éteint. */
.sidebar-nav a.active .sidebar-icon,
.sidebar-footer-link.active .sidebar-icon {
  color: inherit;
}

.sidebar-section-title {
  padding: 1rem 1rem 0.4rem;
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--pico-muted-color);
  font-weight: 600;
}

.sidebar-badge {
  margin-left: auto;
  background: var(--pico-del-color, #c0392b);
  color: #fff;
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1.2;
}

.sidebar-footer {
  border-top: 1px solid var(--pico-muted-border-color);
  padding: 0.5rem 0;
  display: flex;
  flex-direction: column;
}

.sidebar-user-info {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 1rem;
  color: var(--pico-muted-color);
  font-size: 0.85rem;
}

.sidebar-user-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar-footer-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 1rem;
  color: var(--app-text);
  text-decoration: none;
  font-size: 0.9rem;
  border-left: 3px solid transparent;
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* Le bouton de thème porte la même classe qu'un lien de pied de menu, mais Pico
   habille tout <button> en action primaire : il s'affichait en barre bleue pleine
   largeur, comme s'il était l'action principale de la page. C'est un réglage. */
button.sidebar-footer-link {
  /* Pico impose aux boutons sa couleur de texte inverse : blanc. Sur la barre
     latérale, blanche en thème clair, le libellé « Thème » devenait invisible —
     les liens voisins y échappaient seulement parce que Pico les repeint en bleu.
     Le jeton de texte de la racine règle les deux cas. */
  --pico-color: var(--app-text);
  --pico-background-color: transparent;

  width: 100%;
  background: transparent;
  color: var(--app-text);
  border: 0;
  border-left: 3px solid transparent;
  border-radius: 0;
  margin: 0;
  font-weight: inherit;
  text-align: left;
  cursor: pointer;
}

.sidebar-footer-link:hover,
.sidebar-footer-link:focus-visible {
  background: var(--app-surface-muted);
  color: var(--app-text);
}

.sidebar-footer-link.active {
  background: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  border-left-color: var(--pico-primary);
  font-weight: 600;
}

.sidebar-footer-link--danger {
  color: var(--pico-del-color, #c0392b);
}

.sidebar-footer-link--danger:hover {
  color: #fff;
  background: var(--pico-del-color, #c0392b);
}

/* Topbar : mobile only quand logged, sinon public. Fond de carte comme la
   sidebar — elle flotte au-dessus du contenu, elle n'est pas dedans. */
.topbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.6rem 1rem;
  background: var(--pico-card-background-color);
  border-bottom: 1px solid var(--pico-muted-border-color);
  position: sticky;
  top: 0;
  z-index: 50;
}

.topbar--mobile {
  display: none;
  justify-content: space-between;
}

.topbar--public {
  justify-content: space-between;
  padding: 0.75rem 1.5rem;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.topbar-brand {
  font-size: 1.1rem;
}

.topbar-spacer {
  width: 2rem;
}

.topbar-theme {
  padding: 0.4rem 0.7rem;
  width: auto;
  margin: 0;
}

/* Sélecteur de saison dans la sidebar */
.sidebar-season {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--pico-muted-border-color);
}

/* Saison consultée : simple rappel cliquable, la bascule est dans Mon profil */
.sidebar-season-current {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  color: inherit;
  text-decoration: none;
}

.sidebar-season-label {
  margin: 0;
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--pico-muted-color);
  font-weight: 600;
}

.sidebar-season-badge {
  margin: 0;
  align-self: flex-start;
  background: var(--pico-mark-background-color);
  color: var(--pico-mark-color);
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
}

.topbar-season {
  font-size: 0.8rem;
  color: var(--pico-muted-color);
}

/* Bandeau rappelant qu'on consulte une autre saison que celle du club */
.season-notice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 1rem;
  padding: 0.5rem 1rem;
  background: var(--pico-mark-background-color);
  color: var(--pico-mark-color);
  font-size: 0.9rem;
}

.season-notice form {
  margin: 0;
}

.season-notice button {
  margin: 0;
  padding: 0.2rem 0.6rem;
  width: auto;
  font-size: 0.8rem;
}

/* Bandeau des saisons archivées */
.archived-notice {
  margin-bottom: 1rem;
  padding: 0.6rem 0.9rem;
  border-left: 4px solid var(--pico-mark-background-color);
  background: var(--pico-card-sectioning-background-color);
  color: var(--pico-muted-color);
  font-size: 0.9rem;
}

/* Bouton Ajouter dans la sidebar */
.sidebar-actions {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--pico-muted-border-color);
}

.sidebar-add {
  margin: 0;
}

.sidebar-add > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.5rem 0.75rem;
  background: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  border: 0;
  border-radius: var(--pico-border-radius);
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}

.sidebar-add > summary::-webkit-details-marker {
  display: none;
}

.sidebar-add > summary::after {
  display: none;
}

.sidebar-add > summary:hover {
  background: var(--pico-primary-hover-background);
}

.sidebar-add ul {
  margin: 0.25rem 0 0;
}

/* --app-text et non --pico-color : Pico redéfinit ce dernier à l'intérieur d'un
   <button>, où il vaut --pico-primary-inverse — la couleur du texte posé SUR le
   bleu de marque, donc du blanc. Sur la topbar, qui est blanche en thème clair,
   le ☰ disparaissait ; en thème sombre la topbar est foncée, le défaut ne se
   voyait pas. Même piège que sur les liens, déjà noté à la définition du jeton. */
.sidebar-toggle {
  display: none;
  background: transparent;
  border: 0;
  color: var(--app-text);
  font-size: 1.4rem;
  cursor: pointer;
  padding: 0.3rem 0.6rem;
  width: auto;
  margin: 0;
}

.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 90;
}

.sidebar-backdrop.open {
  display: block;
}

.impersonation-banner {
  background: #f59e0b;
  color: #000;
  padding: 0.5rem 1rem;
  text-align: center;
}

/* Mobile : sidebar en drawer + topbar visible.

   Le drawer reprend la barre latérale du bureau, dessinée pour une souris :
   lignes de 0,6 rem de haut et icônes de 1,15 rem, soit des cibles de ~36 px là
   où le doigt en demande 44. Sous ce point de rupture, les lignes respirent et
   les libellés reviennent à la taille du texte courant. */
@media (max-width: 1024px) {
  .app-shell {
    grid-template-columns: 1fr;
  }

  .sidebar {
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: min(340px, 88vw);
    transform: translateX(-100%);
    transition: transform 0.2s ease;
  }

  .sidebar.open {
    transform: translateX(0);
    box-shadow: 4px 0 16px rgba(0, 0, 0, 0.3);
  }

  .sidebar-header {
    padding: var(--app-space-md) var(--app-space-lg);
  }

  .sidebar-brand {
    font-size: var(--app-font-lg);
  }

  .sidebar-close {
    display: inline-flex;
    font-size: 1.5rem;
    padding: var(--app-space-sm) var(--app-space-md);
  }

  .sidebar-nav {
    padding: var(--app-space-sm) 0;
  }

  /* La racine du thème est à 14 px, choix de densité fait pour le bureau. Au
     doigt, une ligne de menu à cette taille descend sous les 44 px de cible
     recommandés : le cran typographique supérieur les rétablit sans toucher au
     reste de la page. */
  .sidebar-nav a,
  .sidebar-footer-link {
    gap: var(--app-space-md);
    padding: 0.85rem var(--app-space-lg);
    font-size: var(--app-font-lg);
  }

  .sidebar-icon {
    width: 1.9rem;
  }

  .sidebar-icon .icon {
    width: 1.5rem;
    height: 1.5rem;
  }

  .sidebar-section-title {
    padding: var(--app-space-md) var(--app-space-lg) var(--app-space-xs);
    font-size: var(--app-font-xs);
  }

  .sidebar-user-info {
    padding: 0.85rem var(--app-space-lg);
    gap: var(--app-space-md);
    font-size: var(--app-font-md);
  }

  .sidebar-actions,
  .sidebar-season {
    padding-left: var(--app-space-lg);
    padding-right: var(--app-space-lg);
  }

  .sidebar-add > summary {
    padding: 0.75rem var(--app-space-md);
    font-size: var(--app-font-lg);
  }

  .sidebar-add ul li a {
    padding: 0.7rem var(--app-space-md);
    font-size: var(--app-font-md);
  }

  .sidebar-toggle {
    display: inline-flex;
  }

  .topbar--mobile {
    display: flex;
  }

  body.sidebar-locked {
    overflow: hidden;
  }
}

/* Sur téléphone, le drawer prend tout l'écran : la bande de fond restante ne
   servait qu'à fermer le menu, ce que la croix et le geste de retour font déjà,
   et elle rognait la largeur utile des libellés. */
@media (max-width: 640px) {
  .sidebar {
    width: 100%;
  }

  .sidebar.open {
    box-shadow: none;
  }
}

/* Calendrier */
.calendar-page {
  max-width: 1400px;
  margin: 0 auto;
}

.calendar-header {
  text-align: center;
  margin-bottom: 1.5rem;
}

.calendar-header h1 {
  margin-bottom: 1rem;
}

.calendar-nav {
  display: flex;
  justify-content: center;
  align-items: stretch;
  gap: 0.5rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

.calendar-nav-btn,
.calendar-nav-today {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 1rem;
  border-radius: var(--pico-border-radius);
  text-decoration: none;
  font-size: 0.95rem;
  background: var(--app-surface-muted);
  color: var(--pico-color);
  border: 1px solid var(--pico-muted-border-color);
}

.calendar-nav-today {
  background: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  border-color: var(--pico-primary-border);
  font-weight: 600;
}

.calendar-nav-btn:hover,
.calendar-nav-today:hover {
  filter: brightness(1.05);
}

.calendar-actions {
  margin: 0;
}

/* Grille mensuelle */
.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--pico-muted-border-color);
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  overflow: hidden;
}

.weekday-header {
  background: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  padding: 0.6rem 0.5rem;
  text-align: center;
  font-weight: 600;
  font-size: 0.85rem;
}

.calendar-day {
  background: var(--pico-card-background-color);
  min-height: 110px;
  padding: 0.4rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.calendar-day.empty {
  background: var(--pico-background-color);
}

.calendar-day.today {
  outline: 2px solid var(--pico-primary);
  outline-offset: -2px;
}

.day-number {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--pico-color);
}

.calendar-day.today .day-number {
  color: var(--pico-primary);
}

.day-events {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  overflow: hidden;
}

/* Items événement (utilisés grille + agenda) */
.event-item {
  display: block;
  padding: 0.25rem 0.4rem;
  border-radius: 4px;
  font-size: 0.75rem;
  text-decoration: none;
  color: var(--pico-color);
  background: var(--app-surface-muted);
  border-left: 3px solid var(--pico-muted-color);
  line-height: 1.3;
  transition: filter 0.15s ease;
}

.event-item:hover {
  filter: brightness(1.1);
}

.event-time {
  font-weight: 700;
  margin-right: 0.3rem;
}

.event-title {
  display: inline;
}

.event-event { border-left-color: #2196f3; }
.event-team_match { border-left-color: #4caf50; }
.event-tournament { border-left-color: #ff9800; }
.event-tournament_match { border-left-color: #9c27b0; }

[data-theme="light"] .event-event { background: #e3f2fd; }
[data-theme="light"] .event-team_match { background: #e8f5e9; }
[data-theme="light"] .event-tournament { background: #fff3e0; }
[data-theme="light"] .event-tournament_match { background: #f3e5f5; }

/* Vue agenda (mobile) */
.calendar-agenda {
  display: none;
  flex-direction: column;
  gap: 0.75rem;
}

.agenda-day {
  margin: 0;
  padding: 0.75rem 1rem;
  background: var(--pico-card-background-color);
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
}

.agenda-day.today {
  border-left: 4px solid var(--pico-primary);
}

.agenda-day-header {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  padding: 0;
  background: transparent;
  border: 0;
}

.agenda-day-number {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--pico-primary);
  line-height: 1;
}

.agenda-day-name {
  color: var(--pico-muted-color);
  font-size: 0.95rem;
}

.agenda-day-badge {
  margin-left: auto;
  background: var(--pico-primary);
  color: var(--pico-primary-inverse);
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
}

.agenda-events {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.agenda-events .event-item {
  font-size: 0.85rem;
  padding: 0.5rem 0.75rem;
}

.agenda-events .event-title {
  display: block;
  font-weight: 600;
  margin-top: 0.1rem;
}

.event-details {
  display: block;
  font-size: 0.75rem;
  color: var(--pico-muted-color);
  margin-top: 0.15rem;
}

.agenda-empty {
  text-align: center;
  color: var(--pico-muted-color);
  padding: 2rem 1rem;
  background: var(--pico-card-background-color);
  border-radius: var(--pico-border-radius);
}

/* Légende */
.calendar-legend {
  margin-top: 2rem;
  padding: 1rem;
  background: var(--pico-card-background-color);
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
}

.calendar-legend strong {
  display: block;
  margin-bottom: 0.6rem;
}

.legend-items {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
}

.legend-color {
  display: inline-block;
  width: 16px;
  height: 16px;
  border-radius: 3px;
  background: var(--app-surface-muted);
  border-left: 3px solid var(--pico-muted-color);
}

/* Mobile : agenda visible, grille cachée */
@media (max-width: 768px) {
  .calendar-grid {
    display: none;
  }

  .calendar-agenda {
    display: flex;
  }

  .calendar-nav-label {
    display: none;
  }

  .calendar-nav-btn {
    padding: 0.5rem 0.8rem;
  }
}

/* Page "événements à venir" - timeline */
.upcoming-page {
  max-width: 900px;
  margin: 0 auto;
}

.upcoming-page h1 {
  margin-bottom: 1.5rem;
}

.no-events {
  text-align: center;
  padding: 2rem;
  background: var(--pico-card-background-color);
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  color: var(--pico-muted-color);
}

.timeline {
  position: relative;
  padding-left: 1.5rem;
}

.timeline::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--pico-muted-border-color);
}

.timeline-date {
  margin: 1.5rem 0 0.75rem;
}

.timeline-date h3 {
  color: var(--pico-primary);
  font-size: 1.05rem;
  margin: 0;
}

.timeline-item {
  position: relative;
  margin-bottom: 1rem;
  padding-left: 1.25rem;
}

.timeline-marker {
  position: absolute;
  left: -1.65rem;
  top: 0.5rem;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--pico-muted-color);
  border: 2px solid var(--pico-background-color);
}

.timeline-event .timeline-marker { background: #2196f3; }
.timeline-team_match .timeline-marker { background: #4caf50; }
.timeline-tournament .timeline-marker { background: #ff9800; }
.timeline-tournament_match .timeline-marker { background: #9c27b0; }

.timeline-content {
  background: var(--pico-card-background-color);
  border: 1px solid var(--pico-muted-border-color);
  padding: 0.75rem 1rem;
  border-radius: var(--pico-border-radius);
}

.timeline-time {
  font-size: 0.85rem;
  color: var(--pico-muted-color);
  font-weight: 700;
  margin-bottom: 0.3rem;
}

.timeline-title {
  font-size: 1rem;
  margin-bottom: 0.4rem;
}

.timeline-title a {
  color: var(--pico-color);
  text-decoration: none;
  font-weight: 600;
}

.timeline-title a:hover {
  color: var(--pico-primary);
}

.timeline-details {
  font-size: 0.85rem;
  color: var(--pico-muted-color);
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
}

.badge,
.status-badge {
  display: inline-block;
  padding: 0.2rem 0.6rem;
  /* Pastille : le rayon suit la hauteur, quel que soit le libellé */
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
  background: var(--app-surface-muted);
  color: var(--pico-color);
}

.badge {
  text-transform: uppercase;
}

.badge-event,
.status-scheduled { background: rgba(33, 150, 243, 0.18); color: #2196f3; }
.badge-team_match { background: rgba(76, 175, 80, 0.18); color: #4caf50; }
.badge-tournament,
.status-in_progress,
.status-pending,
.status-partial,
.status-draw { background: rgba(255, 152, 0, 0.18); color: #ff9800; }
.badge-tournament_match { background: rgba(156, 39, 176, 0.18); color: #9c27b0; }
.status-completed,
.status-registration_open,
.status-done,
.status-paid,
.status-win { background: rgba(76, 175, 80, 0.18); color: #4caf50; }
/* Une saison sans tarif n'a pas de pastille dédiée : le gris neutre est le rendu voulu */
.status-not_done,
.status-unpaid,
.status-loss { background: rgba(244, 67, 54, 0.18); color: #f44336; }

@media (max-width: 768px) {
  .timeline {
    padding-left: 1.25rem;
  }

  .timeline-item {
    padding-left: 0.75rem;
  }

  .timeline-marker {
    left: -1.4rem;
  }
}

/* Tablette : grille compacte */
@media (min-width: 769px) and (max-width: 1024px) {
  .calendar-day {
    min-height: 90px;
    padding: 0.3rem;
  }

  .event-item {
    font-size: 0.7rem;
    padding: 0.15rem 0.3rem;
  }

  .event-title {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* Utilities */
.text-center { text-align: center; }
.text-muted { color: var(--pico-muted-color); }

/* Danger button */
.btn-danger {
  background-color: #c0392b !important;
  border-color: #c0392b !important;
  color: #fff !important;
}
.btn-danger:hover,
.btn-danger:focus {
  background-color: #a93226 !important;
  border-color: #a93226 !important;
}

/* Tableau de suivi des adhésions */
.amount-cell {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}

.amount-cell input {
  margin: 0;
  width: 6rem;
  padding: 0.35rem 0.5rem;
  text-align: right;
}

.amount-cell span {
  font-size: 0.85rem;
  color: var(--pico-muted-color);
}

.row-error {
  color: var(--pico-del-color, #c0392b);
}

.membership-summary {
  margin: 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--pico-muted-border-color);
  font-weight: 600;
}

/* Formulaires longs : regroupement en sections */
.form-section {
  margin-bottom: 1.5rem;
  padding: 1rem 1.25rem 0.25rem;
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  background: var(--pico-card-background-color);
}

.form-section > legend {
  padding: 0 0.5rem;
  font-weight: 600;
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--pico-muted-color);
}

/* Les cases à cocher ne s'alignent pas sur une grille de champs texte */
.form-section .grid > label:has(input[type="checkbox"]) {
  align-self: end;
}

.form-required {
  margin-left: 0.2rem;
  color: var(--pico-del-color, #c0392b);
  text-decoration: none;
  border: 0;
  cursor: help;
}

.form-hint {
  margin: 0 0 1rem;
  font-size: 0.85rem;
  color: var(--pico-muted-color);
}

/* Form actions bar */
.form-actions {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  margin-top: 1rem;
}

/* Barres d'actions : Pico étire le bouton de soumission sur toute la largeur, lui
   donne une marge basse et le gabarit d'un champ (38px), quand un lien-bouton voisin
   garde le gabarit compact du thème (33px). Tous prennent ici la hauteur d'un champ. */
.form-actions button,
.form-actions [role="button"],
.page-actions button,
.page-actions [role="button"] {
  display: inline-flex;
  align-items: center;
  width: auto;
  gap: 0.4rem;
  height: var(--app-field-height);
  margin: 0;
  padding: 0 1rem;
  font-size: var(--app-font-sm);
}

/* Barre d'actions en pied de page de détail : une seule ligne, la navigation à
   gauche, les actions poussées à droite par l'espaceur. Elle passe à la ligne sur
   petit écran plutôt que de déborder. */
.page-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--app-space-sm);
  margin-top: var(--app-space-lg);
}

.page-actions__spacer {
  flex: 1;
}

/* Pico donne une marge basse aux boutons et formulaires : elle décalerait le
   bouton de suppression, emballé dans son formulaire, par rapport aux liens. */
.page-actions > *,
.page-actions form button {
  margin: 0;
}

/* Filters bar */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-end;
  padding: 1rem;
  margin-bottom: 1.5rem;
  background: var(--pico-card-background-color);
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
}

.filters label {
  margin-bottom: 0;
  flex: 1;
  min-width: 150px;
}

/* Sans hauteur explicite, un select garde sa hauteur native, plus basse que celle
   d'un input : les deux juraient côte à côte dans les filtres et les formulaires. */
select:not([multiple], [size]) {
  height: var(--app-field-height);
}

/* Pico donne une marge basse aux champs : alignés par le bas, les champs texte et
   les selects remontaient d'autant au-dessus des cases à cocher et des boutons. */
.filters input:not([type="checkbox"]),
.filters select {
  margin-bottom: 0;
}

/* Case à cocher : libellé à la hauteur d'un champ, la case centrée dedans, pour
   s'aligner sur la ligne des selects. */
.filters label:has(input[type="checkbox"]) {
  /* Ni étirée ni comprimée : avec flex: 0, la case s'écrasait à zéro de large et
     le libellé passait sous le bouton voisin. Trop longue, la ligne passe à la ligne. */
  flex: 0 0 auto;
  min-width: 0;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  height: var(--app-field-height);
}

.filters input[type="checkbox"] {
  flex-shrink: 0;
  margin: 0;
}

.filters button,
.filters a[role="button"] {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* Danger zone (delete area) */
.danger-zone {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--pico-muted-border-color);
  display: flex;
  justify-content: flex-end;
}

/* Ligne du club dans un classement de poule : repérable sans lecture. */
.standing--club > td {
  background: var(--pico-primary-focus);
}

/* Page d'erreur 404 / 403 : bloc centré, respiration verticale. */
.error-page {
  max-width: 32rem;
  margin: 3rem auto;
  text-align: center;
}

/* Texte réservé aux lecteurs d'écran : retiré du flux visuel sans être retiré de
   l'arbre d'accessibilité, contrairement à display:none ou visibility:hidden. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Numéro de téléphone cliquable : lisible sans souligner toute la ligne, et jamais
   coupé en deux par un retour à la ligne. */
.phone-link {
  white-space: nowrap;
  text-decoration: none;
}

.phone-link:hover {
  text-decoration: underline;
}

/* Actions d'une ligne de liste : réduites à leur icône, libellé porté par
   aria-label/title. Le conteneur gère l'espacement, pas les marges des enfants. */
.table-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
}

/* Champ de filtre au-dessus d'un tableau. Pico étire les champs sur toute la
   largeur : on le borne, une recherche de nom n'a pas besoin de plus. */
.table-filter {
  max-width: 22rem;
}

/* Le mode empilé passe les lignes en display:block, ce qui l'emporterait sur
   l'attribut hidden posé par le filtre. */
tr[hidden] {
  display: none !important;
}

/* Boîte de dialogue des échéances.
   Pico stylise déjà dialog ; on ne règle ici que la largeur et l'en-tête. */
.modal::backdrop {
  background: rgba(0, 0, 0, 0.55);
}

.modal > article {
  width: min(46rem, 92vw);
  max-height: 85vh;
  overflow-y: auto;
  margin: 0;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0;
}

.modal-header h2 {
  margin: 0;
  font-size: 1.15rem;
}

/* Le retour vers la liste n'a pas de sens dans la popup */
.modal turbo-frame > a[href*="/admin/membership"] {
  display: none;
}

/* Rappel du membre et du tarif, au-dessus de la saisie */
.payments-context {
  margin: 0 0 1rem;
  color: var(--pico-muted-color);
  font-size: 0.9rem;
}

/* La saisie précède l'historique : c'est l'action attendue à l'ouverture */
.payments-form {
  margin-bottom: 1rem;
}

.modal .payments-form {
  padding: 1rem;
}

/* Sprite d'icônes : présent dans le DOM pour les <use>, jamais rendu lui-même */
.icon-sprite {
  display: none;
}

/* Icône en trait, alignée sur la couleur et la taille du texte environnant */
.icon {
  width: 1.15em;
  height: 1.15em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -0.2em;
}

/* Bouton d'action d'une ligne de tableau.
   2.25rem au repos, 2.75rem au doigt : en dessous de 44px la cible tactile est
   trop petite pour être visée de façon fiable. */
.icon-action {
  /* Pico redéfinit ces variables sur les boutons — sans ce recalage, un <button>
     hérite de la couleur inverse et d'une ombre que le <a> voisin n'a pas. */
  --pico-color: inherit;
  --pico-background-color: transparent;
  --pico-box-shadow: none;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  /* Taille figée : sans flex none, un lien placé directement dans la barre en flex
     se comprime alors que le bouton, protégé par son formulaire, garde sa taille. */
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  margin: 0;
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  background: var(--pico-card-background-color);
  box-shadow: none;
  color: inherit;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 400;
  line-height: 1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  appearance: none;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}

.icon-action:hover {
  background: var(--app-surface-muted);
  border-color: var(--pico-secondary);
}

.icon-action:active {
  transform: translateY(1px);
}

.icon-action:focus-visible {
  outline: 2px solid var(--pico-primary);
  outline-offset: 2px;
}

.icon-action--danger:hover {
  background: rgba(244, 67, 54, 0.14);
  border-color: rgba(244, 67, 54, 0.55);
}

.icon-action--success:hover {
  background: rgba(76, 175, 80, 0.14);
  border-color: rgba(76, 175, 80, 0.55);
}

@media (max-width: 1024px) {
  .icon-action {
    width: 2.75rem;
    height: 2.75rem;
    font-size: 1.1rem;
  }
}

/* Tableau qui se replie en cartes sur petit écran.
   Chaque cellule porte un data-label, repris en intitulé une fois l'en-tête masqué :
   un tableau de saisie à cinq colonnes est illisible sur un téléphone. */
@media (max-width: 768px) {
  .table--stacked thead {
    /* Masqué à l'œil, conservé pour les lecteurs d'écran */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  .table--stacked,
  .table--stacked tbody,
  .table--stacked tr,
  .table--stacked td {
    display: block;
    width: 100%;
  }

  .table--stacked tr {
    margin-bottom: 0.75rem;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--pico-muted-border-color);
    border-radius: var(--pico-border-radius);
    background: var(--pico-card-background-color);
  }

  .table--stacked td {
    display: grid;
    grid-template-columns: minmax(6rem, 35%) 1fr;
    align-items: center;
    gap: 0.75rem;
    padding: 0.3rem 0;
    border: 0;
  }

  .table--stacked td::before {
    content: attr(data-label);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--pico-muted-color);
  }

  /* Cellules sans intitulé utile : le contenu prend toute la largeur */
  .table--stacked td[data-label=""]::before {
    content: none;
  }

  .table--stacked td[data-label=""] {
    grid-template-columns: 1fr;
  }

  .table--stacked td select,
  .table--stacked td input:not([type="checkbox"]) {
    width: 100%;
    margin: 0;
  }

  .table--stacked .table-actions {
    justify-content: flex-end;
  }

  /* La cellule cotisation garde son montant et sa pastille sur une seule ligne
     en tableau ; en carte elle doit pouvoir passer à la ligne. */
  .table--stacked .amount-cell {
    flex-wrap: wrap;
    white-space: normal;
  }
}

/* Pagination */
.pagination {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin: 1.5rem 0 0;
}

.pagination ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.3rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pagination li {
  margin: 0;
}

.pagination a,
.pagination .is-disabled {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  height: 2.5rem;
  padding: 0 0.6rem;
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  background: var(--pico-card-background-color);
  color: var(--pico-color);
  text-decoration: none;
  font-size: 0.9rem;
  line-height: 1;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.pagination a:hover {
  background: var(--app-surface-muted);
  border-color: var(--pico-secondary);
}

.pagination a:focus-visible {
  outline: 2px solid var(--pico-primary);
  outline-offset: 2px;
}

.pagination a.is-current {
  background: var(--pico-primary-background);
  border-color: var(--pico-primary);
  color: var(--pico-primary-inverse);
  font-weight: 600;
}

.pagination .is-disabled {
  opacity: 0.4;
  cursor: default;
}

.pagination-total {
  margin: 0;
  font-size: 0.8rem;
  color: var(--pico-muted-color);
}

/* Compteur affiché à la place des numéros quand la largeur manque */
.pagination-counter {
  display: none;
  padding: 0 0.5rem;
  font-size: 0.85rem;
  color: var(--pico-muted-color);
}

@media (max-width: 640px) {
  .pagination-page {
    display: none;
  }

  .pagination-counter {
    display: inline-flex;
    align-items: center;
  }

  .pagination a,
  .pagination .is-disabled {
    min-width: 2.75rem;
    height: 2.75rem;
  }
}

/* Formulaire réduit à un bouton, aligné dans une barre d'actions.
   inline-flex et non inline : dans une barre en flex, un formulaire inline crée une
   ligne de texte qui décale son bouton par rapport aux liens voisins. */
.inline-form {
  display: inline-flex;
  flex: none;
  margin: 0;
}

/* Messages flash : la couleur porte le niveau, une erreur ne doit pas se lire
   comme un succès. Bordure latérale plutôt qu'un fond plein, plus sobre. */
.flash {
  border-left: 4px solid var(--pico-muted-border-color);
}

.flash--success { border-left-color: #4caf50; }
.flash--warning { border-left-color: var(--app-warning); }
.flash--error,
.flash--verify_email_error { border-left-color: #f44336; }

/* Confrontation : les deux participants et le séparateur, centrés */
.versus {
  text-align: center;
}

.versus-separator {
  color: var(--pico-muted-color);
}

/* Barre d'actions d'un formulaire qui en précède une autre */
.form-actions--spaced {
  margin-bottom: 1rem;
}

/* Champ conditionné par une case à cocher : grisé tant qu'elle est décochée */
.dependent-field.is-disabled {
  opacity: 0.5;
}

.form-actions--top {
  margin-top: 1rem;
}

/* Panneau étroit centré : connexion, mot de passe oublié, inscription */
.narrow-panel {
  max-width: 500px;
  margin: 2rem auto;
}


/* Grille de cartes auto-ajustée : effectif d'équipe, listes de profils */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.25rem;
  margin-top: 1.25rem;
}

.roster-card h3 {
  margin-bottom: 0.75rem;
}

/* Classement : mise en avant du leader et couleur des colonnes de résultat */
.is-leader {
  font-weight: 600;
}

.score-win {
  color: var(--app-success);
  font-weight: 700;
}

.score-loss {
  color: #f44336;
}

/* Tableau de tournoi */
.bracket-vs {
  text-align: center;
  color: var(--pico-muted-color);
  font-size: 0.85rem;
}

.bracket-record {
  margin-top: 0.5rem;
}

/* Tuiles de chiffres clés */
.stat-tile {
  text-align: center;
}

.stat-value {
  font-size: 2.5rem;
}

.stat-value--sm {
  font-size: 2rem;
}

.text-muted-sm {
  font-size: 0.75rem;
  color: var(--pico-muted-color);
}

/* Série de résultats récents */
.form-streak {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.streak-win,
.streak-loss {
  padding: 0.4rem 0.9rem;
  font-weight: 700;
  text-decoration: none;
}

.plain {
  text-decoration: none;
}

/* Avatar en initiales */
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  /* Neutre plutôt que couleur de marque : une liste de trente membres affichait
     trente pastilles bleues, qui tiraient l'œil avant les noms. La couleur reste
     réservée aux actions et à l'état actif. */
  background: var(--pico-card-sectioning-background-color);
  border: 1px solid var(--pico-muted-border-color);
  color: var(--pico-muted-color);
  font-weight: 600;
  margin: 0 auto;
}

.avatar--lg {
  width: 150px;
  height: 150px;
  font-size: 3rem;
}

/* Initiales dans une ligne de tableau */
.avatar--sm {
  width: 40px;
  height: 40px;
  font-size: 0.9rem;
}

/* Pastille de résultat dans une série */
.streak-dot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #fff;
  font-weight: 700;
}

.streak-dot--win { background: var(--app-success); }
.streak-dot--loss { background: #f44336; }

.form-streak--centered {
  justify-content: center;
}

.stat-grid--spaced {
  margin-top: 2rem;
}

.is-champion {
  background: var(--pico-primary-focus);
}

.champion-flag {
  color: var(--pico-secondary);
}

/* ------------------------------------------------------------------
   Disponibilités : une ligne par rencontre, la réponse toujours à
   portée de pouce. La contrainte est la densité — un joueur répond sur
   une dizaine de rencontres d'affilée, souvent depuis un téléphone.
------------------------------------------------------------------ */

.availability-day {
  padding: 0;
  overflow: hidden;
}

.availability-day__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  margin: 0;
  background: var(--pico-card-sectioning-background-color);
}

.availability-day__count {
  display: block;
  opacity: 0.7;
}

.availability-day__bulk {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}

.availability-day__bulk-label {
  font-size: 0.75rem;
  opacity: 0.7;
}

.availability-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.availability-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding: 0.6rem 1rem;
  border-top: 1px solid var(--pico-muted-border-color);
  /* Liseré de statut : la couleur seule ne suffirait pas, le bouton actif la double */
  border-left: 3px solid transparent;
}

.availability-item--available { border-left-color: #4caf50; }
.availability-item--maybe { border-left-color: #ff9800; }
.availability-item--unavailable { border-left-color: #f44336; }

.availability-item__match {
  min-width: 12rem;
  flex: 1 1 16rem;
}

.availability-item__teams em {
  opacity: 0.6;
  font-style: normal;
}

.availability-item__meta {
  display: block;
  opacity: 0.7;
}

.availability-item__form {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}

.availability-note {
  margin: 0;
}

.availability-note > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.35rem 0.55rem;
  border-radius: var(--pico-border-radius);
  font-size: 0.85rem;
  opacity: 0.5;
}

.availability-note > summary {
  display: block;
}

/* Pico ajoute son propre chevron en ::after, en plus du marqueur natif. */
.availability-note > summary::-webkit-details-marker,
.availability-note > summary::marker,
.availability-note > summary::after { display: none; content: ''; }

.availability-note > summary:hover,
.availability-note[open] > summary { opacity: 1; }

.availability-note__input {
  width: 12rem;
  margin: 0.35rem 0 0;
  padding: 0.3rem 0.5rem;
  font-size: 0.8rem;
  height: auto;
}

.availability-choice {
  margin: 0;
  width: auto;
}

/* Non sélectionné : surface neutre, jamais la couleur secondaire de marque. Ces
   trois boutons ne disent rien tant qu'on n'a pas répondu — les teinter aux couleurs
   du club leur donnait un poids qu'ils n'ont pas, et la lisibilité du texte dépendait
   alors de la couleur choisie par l'instance. Seul l'état choisi porte une couleur,
   et elle y porte un sens. */
.availability-choice__btn {
  margin: 0;
  padding: 0.35rem 0.7rem;
  font-size: 0.8rem;
  line-height: 1.2;
  white-space: nowrap;
  background: var(--app-surface-muted);
  border-color: var(--pico-muted-border-color);
  /* --app-text : dans un <button>, --pico-color vaut --pico-primary-inverse. */
  color: var(--app-text);
}

.availability-choice__btn:hover {
  border-color: var(--pico-muted-color);
}

.availability-choice__btn.is-selected {
  font-weight: 700;
}

.availability-choice__btn--available.is-selected {
  background: #4caf50;
  border-color: #4caf50;
  color: #fff;
}

.availability-choice__btn--maybe.is-selected {
  background: #ff9800;
  border-color: #ff9800;
  color: #1a1a1a;
}

.availability-choice__btn--unavailable.is-selected {
  background: #f44336;
  border-color: #f44336;
  color: #fff;
}

.availability-choice--sm .availability-choice__btn {
  padding: 0.25rem 0.5rem;
  font-size: 0.72rem;
}

/* Sur mobile, le libellé cède la place au pictogramme : trois boutons texte
   ne tiennent pas sur la largeur d'un téléphone sans passer à la ligne. */
@media (max-width: 640px) {
  .availability-choice__label {
    display: none;
  }

  .availability-item__form {
    width: 100%;
    flex-wrap: wrap;
    align-items: flex-start;
  }

  /* Cibles tactiles : les trois choix se partagent la largeur disponible. */
  .availability-item__form .availability-choice {
    flex: 1 1 auto;
    display: flex;
  }

  .availability-item__form .availability-choice__btn {
    flex: 1;
    min-height: 2.4rem;
  }

  .availability-note__input {
    width: 100%;
  }
}

/* ------------------------------------------------------------------
   Page rencontre : le travail du capitaine en trois temps. Chaque étape
   est repliable, l'en-tête résume l'état pour décider sans déplier.
------------------------------------------------------------------ */

.match-step {
  margin: 0 0 0.75rem;
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  overflow: hidden;
}

.match-step__summary {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 0.7rem 1rem;
  margin: 0;
  cursor: pointer;
  background: var(--pico-card-sectioning-background-color);
}

.match-step__summary::after {
  margin-left: auto;
}

.match-step__index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  flex: 0 0 auto;
  border-radius: 999px;
  background: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  font-size: 0.8rem;
  font-weight: 700;
}

.match-step__title {
  font-weight: 700;
}

.match-step__state {
  font-size: 0.78rem;
  opacity: 0.7;
}

.match-step__body {
  padding: 1rem;
}

.match-step__body > section:first-child > h2:first-child {
  margin-top: 0;
}

.match-step__answers {
  margin: 0;
  padding-left: 1.1rem;
  font-size: 0.9rem;
}

.match-step__record {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--pico-muted-border-color);
}

/* Pico étire tout champ à 100 % : sans largeur explicite, le select et la note
   passaient chacun sur leur propre ligne et le formulaire s'étalait sur trois rangs. */
.match-step__record select,
.match-step__record .ts-wrapper,
.match-step__record input[type="text"] {
  width: auto;
  flex: 0 1 14rem;
  min-width: 9rem;
  margin: 0;
  padding: 0.35rem 0.5rem;
  font-size: 0.85rem;
  height: auto;
}

/* Tom Select recopie les classes du select sur son conteneur : le padding est
   porté par son champ interne, pas par le conteneur. */
.match-step__record .ts-wrapper {
  padding: 0;
}

@media (max-width: 640px) {
  .match-step__record select,
  .match-step__record .ts-wrapper,
  .match-step__record input[type="text"] {
    flex: 1 1 100%;
  }

  .match-step__record .availability-choice {
    flex: 1 1 100%;
    display: flex;
  }

  .match-step__record .availability-choice__btn {
    flex: 1;
    min-height: 2.4rem;
  }
}

.planning-availability {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 0.5rem;
  font-size: 0.85rem;
}

/* Les trois statuts de disponibilité reprennent le code couleur des boutons. */
.status-available { background: rgba(76, 175, 80, 0.18); color: #4caf50; }
.status-maybe { background: rgba(255, 152, 0, 0.18); color: #ff9800; }
.status-unavailable { background: rgba(244, 67, 54, 0.18); color: #f44336; }

/* ------------------------------------------------------------------
   Listes de rencontres du tableau de bord.
   Ces règles vivaient dans un <style> au milieu de dashboard/index.html.twig :
   invisibles à la relecture, rechargées à chaque rendu, hors de portée du reste
   de la feuille.
   ------------------------------------------------------------------ */

    .match-list, .match-list li { list-style: none; }
    .match-list { padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.5rem; }
    .match-list li::marker, .match-list li::before { content: none; display: none; }
    .match-row {
        display: flex; align-items: center; gap: 1rem;
        padding: 0.75rem 1rem;
        background: transparent;
        border: 1px solid var(--pico-muted-border-color);
        border-radius: var(--pico-border-radius);
        text-decoration: none; color: var(--pico-color);
        transition: border-color 0.15s ease, background 0.15s ease;
    }
    .match-row:hover { border-color: var(--pico-primary); background: var(--pico-card-sectioning-background-color); }
    .match-date {
        display: flex; flex-direction: column; align-items: center; justify-content: center;
        min-width: 3.5rem; padding: 0.4rem 0.6rem;
        background: var(--pico-primary); color: var(--pico-primary-inverse);
        border-radius: var(--pico-border-radius);
        line-height: 1;
    }
    .match-date-day { font-size: 1.4rem; font-weight: 700; }
    .match-date-month { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; margin-top: 0.15rem; }
    .match-teams { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem; flex: 1; }
    .match-vs { color: var(--pico-muted-color); font-size: 0.85rem; }
    .match-location { color: var(--pico-muted-color); font-size: 0.8rem; flex-basis: 100%; }
    /* Score du direct en attente de la feuille FFTT */
    .match-provisional { color: var(--pico-muted-color); font-size: 0.8rem; font-style: italic; flex-basis: 100%; }
    .match-score { display: flex; align-items: baseline; gap: 0.4rem; font-size: 1.2rem; font-variant-numeric: tabular-nums; }
    .match-score-sep { color: var(--pico-muted-color); }
    .match-winner { color: var(--app-text); font-weight: 700; }
    .match-loser { color: var(--pico-muted-color); font-weight: 400; }


/* La pastille de date ne porte plus l'aplat de marque : le bleu est réservé aux
   actions et à l'état actif, sinon trois bleus se superposent sur une même carte. */
.match-date {
  background: var(--pico-card-sectioning-background-color);
  color: var(--app-text);
  border: 1px solid var(--pico-muted-border-color);
}

.match-date-month {
  color: var(--pico-muted-color);
}

/* État vide : sobre, centré, l'icône reste discrète. */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--app-space-sm);
  padding: var(--app-space-xl) var(--app-space-md);
  color: var(--pico-muted-color);
  text-align: center;
}

.empty-state .icon {
  width: 2rem;
  height: 2rem;
  opacity: 0.5;
}

.empty-state p {
  margin: 0;
}

/* ------------------------------------------------------------------
   Tableaux : lisibilité d'une longue liste.
   L'œil perd sa ligne au bout de vingt entrées sans repère au survol, et les
   en-têtes se confondaient avec les données.
   ------------------------------------------------------------------ */
table thead th {
  color: var(--pico-muted-color);
  font-size: var(--app-font-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

table tbody tr {
  transition: background-color 0.12s ease;
}

table tbody tr:hover {
  background: var(--pico-card-sectioning-background-color);
}

/* Chiffres alignés sur la même largeur : une colonne de classements se compare
   d'un coup d'œil, ce que des chiffres proportionnels empêchent. */
table td:has(+ td),
.tabular-nums {
  font-variant-numeric: tabular-nums;
}

/* Filtres au-dessus d'une liste : un bloc, pas une ligne de champs disparates. */
.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--app-space-md);
}

/* Espacement des blocs de page : le rythme vient du conteneur, pas des marges
   ajoutées au cas par cas sur chaque élément. */
main > hgroup {
  margin-bottom: var(--app-space-lg);
}

main > article + article,
main > .grid + article,
main > article + .grid {
  margin-top: var(--app-space-lg);
}

/* Dans une carte de rencontre, la ligne entière est cliquable : les noms d'équipe
   n'ont pas à porter la couleur de lien en plus, sinon la carte compte trois bleus
   et plus aucun ne signale quoi que ce soit. */
.match-row strong {
  color: var(--app-text);
}

.match-row:hover strong {
  color: var(--pico-primary);
}

/* Deux cartes côte à côte : chacune s'arrête à son contenu. Étirées à la même
   hauteur, une carte vide creusait un trou de plusieurs centaines de pixels. */
main > .grid {
  align-items: start;
}

/* ------------------------------------------------------------------
   Pastilles d'état.
   Les <mark> de Pico rendaient tout dans la même teinte : « Approuvé »,
   « Archivée » et « ADMIN » se ressemblaient. La couleur porte désormais un
   sens, et rien d'autre : neutre par défaut, teintée quand l'état le mérite.
   ------------------------------------------------------------------ */
.badge {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: var(--app-font-xs);
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  text-transform: none;
}

.badge--neutral {
  background: var(--pico-card-sectioning-background-color);
  border-color: var(--pico-muted-border-color);
  color: var(--pico-muted-color);
}

.badge--success {
  background: rgba(76, 175, 80, 0.15);
  border-color: rgba(76, 175, 80, 0.35);
  color: #6cc070;
}

.badge--warning {
  background: rgba(255, 152, 0, 0.15);
  border-color: rgba(255, 152, 0, 0.35);
  color: #ffab2e;
}

.badge--danger {
  background: rgba(244, 67, 54, 0.15);
  border-color: rgba(244, 67, 54, 0.35);
  color: #f4665c;
}

/* ------------------------------------------------------------------
   Colonne d'actions d'une liste.
   Trois à cinq boutons de 2,25 rem au trait presque invisible : l'œil ne les
   distinguait pas du fond et la cible était courte pour le pouce.
   ------------------------------------------------------------------ */
td:has(> .table-actions) {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}

td:has(> .table-actions) .table-actions {
  /* La cellule est réduite à son contenu : sans cela les boutons se répartissent
     sur deux lignes dès qu'il y en a trois, ce que nowrap ne corrige pas sur un
     conteneur flex. */
  flex-wrap: nowrap;
  justify-content: flex-end;
  gap: 0.35rem;
}

.icon-action {
  width: 2.375rem;
  height: 2.375rem;
  border-color: var(--pico-muted-border-color);
  background: var(--pico-card-sectioning-background-color);
  color: var(--pico-muted-color);
}

/* Pico étire button[type="submit"] sur toute la largeur, avec un sélecteur plus
   spécifique que .icon-action : dans un formulaire réduit à son contenu, le bouton
   s'écrasait sur son icône, plus étroit que le lien voisin. */
button.icon-action {
  width: 2.375rem;
}

.icon-action .icon {
  width: 1.05rem;
  height: 1.05rem;
}

/* Au survol l'action se révèle : contour marqué, icône en pleine couleur. Rien
   ne bouge de place, seul le contraste change. */
.icon-action:hover {
  background: var(--pico-card-background-color);
  border-color: var(--pico-primary);
  color: var(--pico-primary);
}

.icon-action--danger:hover {
  border-color: rgba(244, 67, 54, 0.55);
  color: #f4665c;
}

/* Formulaire de filtres : le bouton d'envoi prenait toute la largeur d'une
   colonne de grille, ce qui en faisait l'élément le plus voyant de la page. */
.filters button[type="submit"],
article > form .grid > button[type="submit"] {
  width: auto;
  justify-self: start;
  margin: 0;
}

/* Coffre partagé : la valeur masquée et son décompte tiennent sur une ligne, sans
   que le tableau ne bouge quand le clair remplace les points — d'où la largeur
   minimale, faute de quoi chaque révélation redistribuerait les colonnes. */
.secret-value {
  display: inline-block;
  min-width: 8ch;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
}

.secret-countdown {
  margin-left: var(--pico-spacing);
  font-size: 0.75em;
  color: var(--pico-muted-color);
  font-variant-numeric: tabular-nums;
}

/* Mot d'ouverture de saison, au-dessus des alertes : ton festif, pas d'action. */
.dashboard-message {
  border-left: 3px solid var(--pico-primary);
  display: flex;
  flex-direction: column;
  gap: var(--app-space-xs);
}

.dashboard-message p {
  margin: 0;
}

/* Préférences de notification du profil : la case occupe sa propre colonne,
   libellé et aide s'alignent à sa droite au lieu de repasser sous elle. */
.notification-preferences {
  display: flex;
  flex-direction: column;
  gap: var(--app-space-sm);
}

.notification-preferences label {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--app-space-sm);
  align-items: start;
}

.notification-preferences input[type="checkbox"] {
  grid-row: span 2;
  margin: 0.2em 0 0;
}

/* Pico traite tout « input + small » comme une aide de champ et lui donne une
   marge haute négative : elle remontait l'aide sur le libellé. */
.notification-preferences small {
  grid-column: 2;
  margin: 0;
}

/* Alertes du tableau de bord : un bandeau fin de pastilles cliquables. La carte à
   en-tête qui les portait occupait le haut de l'écran pour une ou deux lignes. */
.alert-strip {
  display: flex;
  align-items: center;
  /* Pico écarte les enfants d'un <nav> aux deux bords. */
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: var(--app-space-xs) var(--app-space-sm);
  margin-bottom: var(--app-space-md);
}

.alert-strip__icon {
  display: inline-flex;
  color: var(--pico-del-color, #d93526);
}

.alert-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--app-space-xs);
  padding: 0.2rem 0.65rem;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 0.85rem;
  line-height: 1.4;
  text-decoration: none;
}

.alert-chip span {
  /* --app-text : dans un <a>, --pico-color vaut le bleu de lien. */
  color: var(--app-text);
}

.alert-chip--warning { color: #ff9800; background: rgba(255, 152, 0, 0.08); }
.alert-chip--danger { color: #f44336; background: rgba(244, 67, 54, 0.08); }

.alert-chip:hover,
.alert-chip:focus-visible {
  filter: brightness(0.95);
  text-decoration: none;
}

/* Fiche d'une rencontre.

   L'en-tête tenait dans une carte pleine largeur pour un badge et un nom de salle.
   Ces informations descendent sur la ligne de sous-titre : même contenu, sans le
   bloc vide qui occupait le haut de l'écran. */
.match-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--app-space-sm) var(--app-space-md);
  margin: 0;
}

.match-meta .icon {
  vertical-align: -0.15em;
}

/* Le score garde un bloc à lui : c'est ce qu'on vient chercher une fois la rencontre
   jouée. Une ligne plutôt qu'une carte centrée haute. */
.match-score {
  display: flex;
  align-items: baseline;
  gap: var(--app-space-md);
  flex-wrap: wrap;
  padding: var(--app-space-sm) var(--app-space-md);
  margin-bottom: var(--app-space-md);
  border-left: 3px solid var(--pico-primary);
  background: var(--app-surface-muted);
  border-radius: var(--pico-border-radius);
}

.match-score__value {
  font-size: 1.75rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.match-score__outcome {
  color: var(--pico-muted-color);
}

/* Tableau de score de la feuille de match : noms de part et d'autre, score centré.
   Les deux colonnes de nom ont la même largeur pour que le tiret tombe au milieu. */
.sheet-score {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--app-space-md);
  padding: var(--app-space-md);
  margin-bottom: var(--app-space-lg);
  background: var(--app-surface-muted);
  border-radius: var(--pico-border-radius);
}

.sheet-score__team {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.sheet-score__team--home {
  text-align: right;
}

.sheet-score__value {
  display: flex;
  align-items: center;
  gap: var(--app-space-sm);
  font-size: 3rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.sheet-score__separator,
.sheet-score__loser {
  color: var(--pico-muted-color);
}

/* Sur mobile, les noms longs écrasaient le score : il passe au-dessus, seul. */
@media (max-width: 576px) {
  .sheet-score {
    grid-template-columns: 1fr 1fr;
  }

  .sheet-score__value {
    grid-column: 1 / -1;
    grid-row: 1;
    justify-content: center;
    font-size: 2.5rem;
  }
}

/* L'étape de composition est celle qu'on ouvre : son filet la distingue des deux
   autres, repliées. La couleur ne porte pas l'information seule — c'est l'ouverture
   par défaut qui la porte. */
.match-step--primary {
  border-color: var(--pico-primary);
}

/* Titulaires : le nom domine, le reste est en appui. Sans cette hiérarchie, le
   numéro de licence et les points se lisaient au même poids que le joueur. */
.lineup-starters {
  margin: 0;
  padding-left: 1.5rem;
}

.lineup-starters li {
  margin-bottom: var(--app-space-xs);
}

.lineup-starters__name {
  font-weight: 600;
  text-decoration: none;
}

.lineup-starters__points,
.lineup-starters__override {
  color: var(--pico-muted-color);
  font-size: 0.85em;
}

.lineup-starters__override {
  display: block;
}

/* Le numéro de licence se recopie sur la feuille de match : il doit ressortir
   plus que les points, en gras et en chasse fixe pour éviter les erreurs de lecture. */
.lineup-starters__license {
  padding: 0 var(--app-space-xs);
  border-radius: var(--pico-border-radius);
  background: var(--pico-code-background-color);
  font-family: var(--pico-font-family-monospace);
  font-size: 0.9em;
  font-weight: 700;
}

/* La coche dit « confirmé sur la feuille FFTT » : elle doit se voir sans souligner. */
.lineup-starters__confirmed {
  text-decoration: none;
  color: #4caf50;
}

/* Proposition affichée à défaut de composition enregistrée. Plus discrète que des
   titulaires validés : ce n'est pas une décision, c'est ce que le moteur alignerait. */
.lineup-starters--suggested .lineup-starters__name {
  font-weight: 500;
}

.lineup-roster__notice {
  margin-bottom: var(--app-space-sm);
}


/* La proposition sur l'écran de composition : une carte à part, avant les colonnes
   de sélection. Elle précède le travail, elle n'en fait pas partie. */
.lineup-suggestion {
  margin-bottom: var(--app-space-md);
  border-left: 3px solid var(--pico-primary);
}

/* ------------------------------------------------------------------
   Commandes de maintenance : une ligne par commande, son libellé à
   gauche, son lancement à droite.
   ------------------------------------------------------------------ */
.command-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--app-space-md);
}

.command-item {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--app-space-md);
  padding-bottom: var(--app-space-md);
  border-bottom: 1px solid var(--pico-muted-border-color);
}

.command-item:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.command-item__text {
  flex: 1;
  min-width: 16rem;
}

.command-item__text p {
  margin: var(--app-space-xs) 0 0;
  font-size: var(--app-font-sm);
}

.command-item__meta {
  color: var(--pico-muted-color);
  font-size: var(--app-font-xs);
}

/* Le formulaire de lancement reste sur une ligne : case à cocher puis bouton. */
.command-item__form {
  display: flex;
  align-items: center;
  gap: var(--app-space-sm);
  margin: 0;
}

.command-item__dry-run {
  display: flex;
  align-items: center;
  gap: var(--app-space-xs);
  margin: 0;
  white-space: nowrap;
  font-size: var(--app-font-sm);
}

.command-item__form button {
  margin: 0;
  white-space: nowrap;
}

/* Sortie de commande : largeur libre, on fait défiler le bloc et non la page. */
.command-output {
  max-height: 30rem;
  overflow: auto;
  font-size: var(--app-font-xs);
  line-height: 1.5;
}

.command-warning {
  border-left: 4px solid var(--pico-del-color, #c0392b);
}

/* Lignes de l'écran de composition.

   `.is-blocked` existait dans le gabarit sans qu'aucune règle ne la peigne : un joueur
   indisponible ou déjà engagé se lisait exactement comme un joueur disponible. Le filet
   de gauche porte l'état, en doublure des badges — jamais à leur place, la couleur ne
   doit pas être le seul signal. */
.lineup-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--app-space-md);
  flex-wrap: wrap;
  padding: var(--app-space-sm);
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--pico-muted-border-color);
}

.lineup-row:last-child {
  border-bottom: 0;
}

.lineup-row form {
  margin: 0;
}

.lineup-row button,
.lineup-row input[type="text"] {
  margin: 0;
  width: auto;
}

/* Effectif déclaré de l'équipe, sans réserve : ce qu'on aligne en premier. */
.lineup-row.is-squad {
  border-left-color: #4caf50;
}

/* Avertissement : jouable, mais quelque chose mérite un regard — hors effectif
   déclaré, licence incomplète. */
.lineup-row.is-warning {
  border-left-color: #ff9800;
}

/* Bloqué : indisponible, brûlé, déjà engagé ce tour, quota de mutés. Le fond très
   légèrement teinté évite de ne compter que sur le filet. */
.lineup-row.is-blocked {
  border-left-color: #f44336;
  background: rgba(244, 67, 54, 0.06);
}

/* Liste de joueurs dans une carte : composition du planning, feuille FFTT. Ce sont
   des noms, pas une énumération — les puces par défaut posaient une colonne de points
   au milieu d'une carte déjà dense et décalaient le texte sans rien apporter. */
/* Épingle de la salle adverse. Pas de soulignement : c'est une icône, pas un mot
   dans une phrase. L'adresse voyage dans l'infobulle Pico (`data-tooltip`), le clic
   ouvre la carte — la carte de planning n'a pas la place d'une adresse complète. */
.venue-pin {
  display: inline-flex;
  align-items: center;
  margin-left: 0.15rem;
  text-decoration: none;
  border-bottom: 0;
}

/* L'infobulle par défaut ne passe pas à la ligne : une adresse de salle y tiendrait
   sur une seule ligne large de tout l'écran. */
.venue-pin[data-tooltip]::before {
  width: max-content;
  max-width: 16rem;
  white-space: normal;
  text-align: center;
}

/* Composition : un joueur par ligne, son classement en bout de ligne. Les points
   alignés à droite sur un filet fin — sans cet alignement les nombres flottaient
   au milieu du texte et la liste se lisait comme une phrase, pas comme une compo. */
.player-list {
  list-style: none;
  margin: 0 0 var(--app-space-sm);
  padding-left: 0;
}

.player-list li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--app-space-sm);
  margin: 0;
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--pico-muted-border-color);
}

/* Le dernier filet doublerait la bordure de la carte qui porte la liste. */
.player-list li:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

/* Joueur du club sur une feuille de match : pastille aux couleurs du club plutôt
   qu'un soulignement. La graisse reste héritée pour que le vainqueur d'une partie
   ressorte toujours en gras. */
.club-player,
.pill-link {
  display: inline-block;
  padding: 0.05em 0.55em;
  border-radius: 999px;
  background: color-mix(in srgb, var(--pico-primary) 12%, transparent);
  color: var(--pico-primary);
  font-weight: inherit;
  text-decoration: none;
}

.club-player:hover,
.club-player:focus-visible,
.pill-link:hover,
.pill-link:focus-visible {
  background: color-mix(in srgb, var(--pico-primary) 22%, transparent);
  text-decoration: none;
}

/* Les points : au bout de la ligne, en retrait, chiffres de largeur fixe pour que
   les nombres s'alignent d'une ligne à l'autre. */
.player-list li > small {
  flex: 0 0 auto;
  color: var(--pico-muted-color);
  font-variant-numeric: tabular-nums;
}

/* Variante des cartes du planning, où la liste n'est qu'un rappel : même structure,
   corps réduit et filets plus discrets. */
.player-list--compact {
  font-size: 0.875em;
}

.player-list--compact li {
  padding: 0.2rem 0;
}

/* ------------------------------------------------------------------
   Score en direct.
   Deux écrans le portent : la carte « en ce moment » du tableau de bord et
   l'étape de la fiche rencontre. Le score ne se rafraîchit pas tout seul, la
   mise en forme ne doit donc rien promettre de plus qu'une page rechargée.
   ------------------------------------------------------------------ */

.live-panel {
  border-left: 3px solid var(--pico-primary);
}

.live-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--app-space-md);
  flex-wrap: wrap;
}

.live-panel__header h2 {
  margin: 0;
}

/* Le libellé, pas la seule couleur, dit que la rencontre est en cours. */
.live-panel__badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  margin-right: var(--app-space-xs);
  border-radius: var(--pico-border-radius);
  background: var(--pico-primary);
  color: var(--pico-primary-inverse);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* Tableau du score : les deux côtés et le séparateur sur une ligne, qui passe en
   colonne dès que la largeur manque — c'est un écran de téléphone, en salle. */
.live-board {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--app-space-md);
}

.live-board__side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--app-space-xs);
  flex: 1 1 8rem;
}

.live-board__team {
  text-align: center;
  font-weight: 600;
}

.live-board__score {
  font-size: 3rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.live-board__separator {
  font-size: 2rem;
  color: var(--pico-muted-color);
}

.live-board__controls {
  display: flex;
  gap: var(--app-space-xs);
}

.live-board__controls form {
  margin: 0;
}

/* Cible tactile large : le score se saisit au bord de la table, debout. */
.live-board__step {
  min-width: 3rem;
  padding: 0.5rem 0.75rem;
  margin: 0;
  font-variant-numeric: tabular-nums;
}

/* Filet du score au tableau de bord, sur les rencontres en cours comme sur les
   rencontres jouées : vert quand le club mène ou l'emporte, orange quand il est
   mené ou tombe, neutre sur un derby ou une égalité — voir MatchExtension. */
.match-score--ahead {
  border-left-color: var(--app-success);
}

.match-score--behind {
  border-left-color: var(--app-warning);
}

/* Saisie directe : le rattrapage quand personne n'a tenu le compteur. En retrait
   des gros boutons, c'est le geste occasionnel, pas celui du suivi. */
.live-entry {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--app-space-sm);
  margin-top: var(--app-space-md);
}

.live-entry__label {
  color: var(--pico-muted-color);
  font-size: 0.85rem;
}

/* Les deux champs, le tiret et le bouton forment un bloc insécable : sur un écran
   étroit, c'est le libellé qui passe au-dessus, pas un champ qui part seul à la ligne. */
.live-entry__fields {
  display: flex;
  align-items: center;
  gap: var(--app-space-xs);
}

.live-entry__fields input {
  width: 4rem;
  margin: 0;
  padding-inline: var(--app-space-xs);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.live-entry__fields .live-board__separator {
  font-size: 1.25rem;
}

.live-entry button {
  margin: 0;
}

.live-board__footnote {
  margin: var(--app-space-sm) 0 0;
  text-align: center;
}

/* L'étape du direct est celle qu'on garde ouverte pendant la rencontre. */
.match-step--live {
  border-color: var(--pico-primary);
}

/* Bascule « compo validée » : le bouton et son explication, pas côte à côte —
   l'explication se lit sous le bouton, pas au bout de la ligne. */
.match-step__validate {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--app-space-xs);
  margin-top: var(--app-space-md);
}

.match-step__validate button {
  margin: 0;
}

/* Paramètres du club : calendrier d'un rappel de composition */
.reminder-schedule__days {
  max-width: 8rem;
}

/* Jours d'envoi : une ligne de cases plutôt qu'une colonne de sept */
.weekday-choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--app-space-sm) var(--app-space-md);
}

/* Raccourcis du licencié au tableau de bord : tuiles cliquables, quatre de front sur
   grand écran, deux sur téléphone. */
.player-shortcuts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: var(--app-space-sm);
  margin-bottom: var(--app-space-md);
}

@media (max-width: 640px) {
  .player-shortcuts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.player-shortcut {
  display: flex;
  flex-direction: column;
  gap: var(--app-space-xs);
  padding: var(--app-space-sm) var(--app-space-md);
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  background: var(--pico-card-background-color);
  color: inherit;
  text-decoration: none;
  transition: border-color 0.15s ease;
}

.player-shortcut:hover {
  border-color: var(--pico-primary);
  color: inherit;
}

.player-shortcut__label {
  display: flex;
  align-items: center;
  gap: var(--app-space-xs);
  font-size: 0.85rem;
  color: var(--pico-muted-color);
}

.player-shortcut__value {
  font-size: 1.75rem;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.player-shortcut__value--text {
  font-size: 1rem;
}

.player-shortcut__hint {
  color: var(--pico-muted-color);
  overflow-wrap: anywhere;
}

/* Bloc rechargé seul par Turbo après un clic (journée des disponibilités,
   composition). Pendant l'envoi, il s'estompe : on voit que la demande part. */
.turbo-block {
  display: block;
  transition: opacity 0.15s ease;
}

.turbo-block[aria-busy="true"] {
  opacity: 0.6;
  pointer-events: none;
}

/* ================================================================
   Fiche membre
   ================================================================ */
.member-sheet {
  display: flex;
  flex-direction: column;
  gap: var(--app-space-md);
}

.member-sheet article {
  margin: 0;
}

.member-hero {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--app-space-md);
}

.member-hero__avatar {
  width: 72px;
  height: 72px;
  font-size: 1.6rem;
  margin: 0;
  flex-shrink: 0;
}

.member-hero__identity {
  flex: 1;
  min-width: 12rem;
}

.member-hero__identity h1 {
  margin-bottom: var(--app-space-xs);
}

.member-hero__badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--app-space-xs);
  margin: 0;
}

.member-hero__stats {
  margin: 0;
}

/* Chiffres clés : tuiles compactes, plus sobres que les stat-card du tableau de bord */
.member-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--app-space-sm);
}

.member-figure {
  display: flex;
  flex-direction: column;
  gap: var(--app-space-xs);
  padding: var(--app-space-sm) var(--app-space-md);
  background: var(--app-surface-muted);
  border-radius: var(--pico-border-radius);
}

.member-figure__value {
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.member-figure__label {
  font-size: 0.8rem;
  color: var(--pico-muted-color);
}

.member-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--app-space-md);
}

.member-card--alert {
  border-left: 3px solid var(--pico-del-color);
}

/* Libellé à gauche, valeur à droite : se lit comme une fiche, sans grille de tableau */
.member-details {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--app-space-sm) var(--app-space-md);
  margin: 0;
}

.member-details dt {
  color: var(--pico-muted-color);
  font-weight: 400;
}

.member-details dd {
  margin: 0;
  text-align: right;
}

.member-teams {
  display: flex;
  flex-wrap: wrap;
  gap: var(--app-space-sm);
  margin: 0;
}

.member-season summary {
  font-weight: 600;
}

.member-matches {
  margin: 0;
}

.member-matches td {
  padding: var(--app-space-xs) var(--app-space-sm);
}

.member-matches__date {
  white-space: nowrap;
  color: var(--pico-muted-color);
  font-variant-numeric: tabular-nums;
}

.member-matches__record {
  white-space: nowrap;
  text-align: right;
}

/* ================================================================
   Tom Select aux couleurs de Pico
   Son thème par défaut (bordure grise, rayon de 3px, fond blanc) jurait avec les
   champs voisins et restait clair en thème sombre : on le rebranche sur les
   jetons de formulaire Pico.
   ================================================================ */
.ts-wrapper {
  /* Tom Select impose 36px minimum, au-dessus des champs Pico compacts */
  min-height: 0;
  margin-bottom: var(--pico-spacing);
}

.ts-wrapper .ts-control,
.ts-wrapper.single.input-active .ts-control,
.ts-wrapper.single .ts-control {
  min-height: 0;
  padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);
  border: var(--pico-border-width) solid var(--pico-form-element-border-color);
  border-radius: var(--pico-border-radius);
  background: var(--pico-form-element-background-color);
  box-shadow: none;
  color: var(--pico-color);
  /* Même corps que les champs du thème (pico-theme.css) */
  font-size: 0.875rem;
  line-height: var(--pico-line-height);
}

/* Hauteur calculée comme celle des inputs Pico. Sans elle, l'élément choisi et le
   champ de recherche interne (7rem minimum) passaient à la ligne dans un select
   étroit, et le champ dépassait ses voisins. */
.ts-wrapper.single .ts-control {
  height: var(--app-field-height);
  flex-wrap: nowrap;
  align-items: center;
}

.ts-wrapper.multi .ts-control {
  min-height: var(--app-field-height);
  align-items: center;
}

.ts-wrapper.single .ts-control > input {
  min-width: 0;
}

/* Bouton d'effacement : une croix nue, grise, collée au chevron. Pastille ronde
   discrète à la place, à gauche du chevron. */
.ts-wrapper.plugin-clear_button {
  --ts-pr-clear-button: 1.75rem;
}

.ts-wrapper.plugin-clear_button .clear-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  padding: 0;
  border-radius: 50%;
  color: var(--pico-muted-color);
  font-size: 1rem;
  line-height: 1;
  transition: opacity var(--pico-transition), background-color var(--pico-transition);
}

.ts-wrapper.plugin-clear_button.single .clear-button {
  right: 2rem;
}

.ts-wrapper.plugin-clear_button .clear-button:hover {
  background: var(--app-surface-muted) !important;
  color: var(--pico-color);
}

.ts-wrapper.single .ts-control::after {
  border-top-color: var(--pico-muted-color);
}

.ts-wrapper.single.dropdown-active .ts-control::after {
  border-bottom-color: var(--pico-muted-color);
}

.ts-wrapper.focus .ts-control {
  border-color: var(--pico-form-element-focus-color);
  box-shadow: 0 0 0 var(--pico-outline-width) var(--pico-form-element-focus-color);
}

/* Le champ de saisie interne hérite des styles d'input de Pico (bordure, hauteur,
   marge) : il doit rester invisible dans son conteneur. */
.ts-wrapper .ts-control > input {
  height: auto;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
  color: inherit;
  font-size: inherit;
  line-height: inherit;
}

.ts-dropdown {
  margin-top: var(--app-space-xs);
  border: var(--pico-border-width) solid var(--pico-form-element-border-color);
  border-radius: var(--pico-border-radius);
  background: var(--pico-dropdown-background-color, var(--pico-background-color));
  box-shadow: var(--pico-dropdown-box-shadow, var(--pico-card-box-shadow));
  color: var(--pico-color);
  overflow: hidden;
  /* Rattachée au body, la liste doit passer au-dessus des cartes et de la barre latérale */
  z-index: 1000;
}

.ts-dropdown .option,
.ts-dropdown .no-results {
  padding: var(--app-space-sm) var(--pico-form-element-spacing-horizontal);
}

.ts-dropdown .active {
  background: var(--app-surface-muted);
  color: var(--pico-color);
}

.ts-dropdown .selected {
  color: var(--pico-primary);
  font-weight: 600;
}

/* Formulaire de disponibilité de la fiche match : même gabarit compact que la note
   voisine. Placé après le thème, et aussi spécifique que ses états, pour l'emporter. */
.match-step__record .ts-wrapper.single .ts-control,
.match-step__record .ts-wrapper.single.input-active .ts-control {
  height: calc(0.85rem * var(--pico-line-height) + 0.35rem * 2 + var(--pico-border-width) * 2);
  padding: 0.35rem 2rem 0.35rem 0.5rem;
  font-size: 0.85rem;
}

/* ================================================================
   Planning : étape de chaque rencontre lisible d'un coup d'œil
   Le liseré gauche et le badge portent la même couleur ; le badge porte aussi le
   mot, la couleur ne transmet pas l'information seule.
   ================================================================ */
.planning-card {
  border-left: 4px solid var(--planning-stage-color, var(--pico-muted-border-color));
}

.planning-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--app-space-sm);
}

.planning-card--lineup_to_fill,
.planning-stage--lineup_to_fill { --planning-stage-color: #f44336; }
.planning-card--lineup_in_progress,
.planning-stage--lineup_in_progress { --planning-stage-color: #ff9800; }
.planning-card--lineup_ready,
.planning-stage--lineup_ready { --planning-stage-color: var(--app-success); }
.planning-card--live,
.planning-stage--live { --planning-stage-color: var(--pico-primary); }
.planning-card--completed,
.planning-stage--completed { --planning-stage-color: var(--pico-muted-color); }

.planning-stage {
  display: inline-flex;
  align-items: center;
  gap: var(--app-space-xs);
  flex-shrink: 0;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--planning-stage-color) 16%, transparent);
  color: var(--planning-stage-color);
  font-size: 0.75rem;
  font-weight: 700;
  white-space: nowrap;
}

/* Point pulsé : le direct est le seul état qui bouge */
.planning-stage--live::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: currentColor;
  animation: planning-live-pulse 1.5s ease-in-out infinite;
}

@keyframes planning-live-pulse {
  50% { opacity: 0.3; }
}

@media (prefers-reduced-motion: reduce) {
  .planning-stage--live::before {
    animation: none;
  }
}

/* Une rencontre terminée n'appelle plus d'action : la carte s'efface un peu */
.planning-card--completed {
  opacity: 0.8;
}

.planning-score strong {
  font-size: 1.5rem;
  font-variant-numeric: tabular-nums;
}

.venue-link {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  white-space: nowrap;
}

.venue-link[data-tooltip]::before {
  width: max-content;
  max-width: 16rem;
  white-space: normal;
  text-align: center;
}

/* État oui/non dans une colonne de tableau : coche verte ou croix atténuée */
.state-mark {
  display: inline-flex;
  align-items: center;
  font-size: 1.15rem;
}

.state-mark--on {
  color: var(--app-success);
}

.state-mark--off {
  color: var(--pico-muted-color);
}

/* Coins arrondis des tableaux. Le figure qui les enveloppe défile déjà (overflow-x
   de Pico) : l'arrondir suffit à rogner l'en-tête et la dernière ligne, sans passer
   les tableaux en border-collapse: separate. */
figure:has(> table) {
  border-radius: var(--pico-border-radius);
}

figure > table {
  margin-bottom: 0;
}

/* Formulaire relancé à la volée : bouton « Filtrer » inutile. Masqué en CSS dès le
   premier rendu — le masquer en JavaScript le faisait clignoter. base.html.twig le
   réaffiche dans un <noscript>. */
[data-auto-submit-target="submit"] {
  display: none;
}

/* En-tête de colonne triable : garde l'apparence d'un intitulé, la flèche signale
   qu'on peut cliquer. */
.sort-link,
.sort-button {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
}

.sort-link:hover,
.sort-button:hover {
  color: var(--pico-primary);
}

.sort-indicator {
  color: var(--pico-muted-color);
  opacity: 0.6;
  font-size: 0.9em;
}

.sort-indicator--active {
  color: var(--pico-primary);
  opacity: 1;
}

/* Le bouton d'en-tête triable ne doit garder aucun habillage de bouton Pico */
.sort-button {
  width: auto;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}

.sort-button:focus-visible {
  outline: var(--pico-outline-width) solid var(--pico-primary-focus);
  outline-offset: 2px;
}

/* Select multiple (joueurs d'une équipe…) : les éléments choisis deviennent des
   pastilles aux couleurs du club, comme les joueurs d'une feuille de match, au lieu
   des étiquettes grises carrées de Tom Select séparées par un filet. */
.ts-wrapper.multi .ts-control {
  gap: 0.35rem;
  padding-top: calc(var(--pico-form-element-spacing-vertical) * 0.6);
  padding-bottom: calc(var(--pico-form-element-spacing-vertical) * 0.6);
}

.ts-wrapper.multi .ts-control > .item {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  margin: 0;
  padding: 0.15rem 0.25rem 0.15rem 0.65rem;
  border: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--pico-primary) 14%, transparent);
  color: var(--pico-primary);
  font-size: 0.85em;
  font-weight: 500;
  line-height: 1.4;
  /* Ombre portée du thème Tom Select : sur une pastille, elle dédoublait les lettres */
  text-shadow: none;
}

.ts-wrapper.multi .ts-control > .item.active {
  background: color-mix(in srgb, var(--pico-primary) 28%, transparent);
  color: var(--pico-primary);
}

/* :not(.rtl) : la règle de Tom Select qui pose le filet gauche est aussi spécifique */
.ts-wrapper.plugin-remove_button:not(.rtl) .item .remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  color: inherit;
  font-size: 0.95rem;
  line-height: 1;
  text-decoration: none;
  opacity: 0.6;
  transition: opacity var(--pico-transition), background-color var(--pico-transition);
}

.ts-wrapper.plugin-remove_button:not(.rtl) .item .remove:hover {
  background: color-mix(in srgb, var(--pico-primary) 25%, transparent);
  opacity: 1;
}

.ts-wrapper.multi .ts-control > input {
  flex: 1 1 4rem;
  min-width: 4rem !important;
}

/* Onglets de rubrique (Championnat : à venir / résultats). Soulignement de l'onglet
   courant plutôt que des boutons : ce sont deux vues d'une même rubrique. */
.page-tabs {
  display: flex;
  /* Pico étale les enfants d'un <nav> aux deux bords */
  justify-content: flex-start;
  gap: var(--app-space-lg);
  margin-bottom: var(--app-space-lg);
  border-bottom: 1px solid var(--pico-muted-border-color);
}

.page-tabs a {
  margin: 0 0 -1px;
  padding: var(--app-space-sm) 0;
  border-bottom: 2px solid transparent;
  color: var(--pico-muted-color);
  font-weight: 600;
  text-decoration: none;
}

.page-tabs a:hover {
  color: var(--app-text);
}

.page-tabs a[aria-current="page"] {
  border-bottom-color: var(--pico-primary);
  color: var(--app-text);
}

/* Résultats groupés par journée : une carte par journée */
.results-day {
  margin-bottom: var(--app-space-lg);
}

.results-day__title {
  margin: 0;
  font-size: var(--app-font-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--pico-muted-color);
}
