:root {
    --vaa-blue-900: #0b2545;
    --vaa-blue-700: #13355e;
    --vaa-blue-500: #1d4e89;
    --vaa-red-500: #c8102e;
    --vaa-grey-100: #f5f7fa;
    --vaa-grey-200: #e6e9ee;
    --vaa-grey-500: #6b7280;
    --vaa-grey-800: #1f2933;
    --vaa-white: #ffffff;
    --vaa-radius: 8px;
    --vaa-shadow: 0 1px 3px rgba(11, 37, 69, 0.12), 0 1px 2px rgba(11, 37, 69, 0.08);
}

* { box-sizing: border-box; }

/* Réserve la place de la barre de défilement verticale dès le premier rendu (09/09/2026, demande
   explicite de l'utilisateur : "sur la page quand on rafraichi on a un bandeau blanc a droite des
   chiffres" — bandeau constaté sur la bannière d'accueil, capture d'écran fournie). Cause probable :
   sans cette règle, une page qui charge plus de contenu qu'elle n'en affiche au premier rendu (avant
   que l'image de la bannière et les polices soient chargées, la hauteur de page peut encore être
   inférieure à celle de l'écran) s'affiche d'abord SANS barre de défilement, sur toute la largeur —
   puis, dès que la hauteur dépasse celle de l'écran, le navigateur fait apparaître la barre et
   décale tout le contenu de sa largeur (~15-20px) vers la gauche d'un coup, ce qui laisse
   brièvement voir le fond de la page (blanc) à l'ancien bord droit, sous forme de "bandeau blanc" —
   exactement ce qui a été signalé, à l'extrémité droite de la bannière (là où se trouve le cadre
   "Pilotes inscrits"/etc.) ainsi que dans les sections suivantes. `scrollbar-gutter: stable` réserve
   cette largeur DÈS le tout premier rendu, que la barre soit affichée ou non : plus aucun décalage
   ne se produit après coup. Propriété récente (support Safari depuis 2024) : ignorée sans erreur ni
   effet indésirable par un navigateur plus ancien, qui retombe simplement sur l'ancien comportement
   (dégradation silencieuse, comme les autres améliorations progressives de ce fichier). */
html {
    scrollbar-gutter: stable;
}

/* Image de fond du site entier (28/08/2026, demande explicite de l'utilisateur : "rajouter l'image
   en fond de site"), avec le nouvel avion "Air Alsace" fourni. Superposition dégradé blanc quasi-
   opaque (0.90) PAR-DESSUS l'image (et non l'inverse) pour "l'éclaircir" comme demandé : la couleur
   de fond d'origine (--vaa-grey-100) reste visible en dominante, l'avion n'apparaît qu'en filigrane
   très clair — les cartes du site restent blanches et bien lisibles par-dessus. background-size:
   cover + background-position: center pour que l'image (772×403px, relativement petite) remplisse
   l'écran sans se répéter, quitte à perdre un peu de netteté sur de très grands écrans plutôt que
   d'apparaître pixelisée en la répétant. background-attachment: fixed pour qu'elle ne défile pas
   avec le contenu (effet "papier peint" plutôt qu'une image qui accompagne le scroll) ; se dégrade
   simplement en scroll normal sur les navigateurs qui ne supportent pas "fixed" (iOS Safari
   notamment), sans rien casser.
   Différent du filigrane posé uniquement derrière le bandeau "Bienvenue" de l'accueil (voir .hero
   plus bas, hero-banner.jpg) : celui-ci couvre tout le site, sur toutes les pages. */
body {
    margin: 0;
    font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    color: var(--vaa-grey-800);
    background:
        linear-gradient(rgba(245, 247, 250, 0.90), rgba(245, 247, 250, 0.90)),
        url("../img/site-background.jpg");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-attachment: fixed;
    line-height: 1.5;
}

/* Largeur de .container — historique de cette règle, pour qui retrouverait les anciennes valeurs dans
   un vieux commit/zip livré : 960px à l'origine : élargi à 1200px pour l'accueil/statistiques
   seulement le 28/08/2026 (`.page-home`, via `$bodyClass`) ; bandeau de liens du header fixé
   indépendamment à 1200px le 29/08/2026 pour ne plus jamais varier d'une page à l'autre (sinon les
   liens passaient sur 2 lignes en dehors de l'accueil/statistiques, "tout bouge" au chargement) ;
   élargi encore, à 96vw mais seulement sur `admin/index.php`, le 03/09/2026 pour laisser respirer le
   tableau des membres (colonne VID). **Généralisé à tout le site le 03/09/2026** (suite immédiate,
   demande explicite : "on peut le faire sur tout le site ?") : au lieu de multiplier les exceptions
   par page (`.page-home`, `.page-admin-wide`, ...), `.container` s'élargit désormais en `vw` — donc
   "en fonction de la taille de l'écran" comme demandé au tour précédent — PARTOUT sur le site,
   `.page-home`/`.page-admin-wide` retirées (devenues inutiles, toutes les pages ont maintenant la
   même largeur). `$bodyClass = 'page-home'` reste posé sans effet sur `index.php`/`statistiques.php`
   (vestige harmless, gardé au cas où une mise en page spécifique à ces pages soit réintroduite plus
   tard) ; l'équivalent ajouté le même jour sur `admin/index.php` a été retiré, n'ayant plus lieu
   d'être. `.site-header .container` (bandeau de liens) reçoit la MÊME valeur `96vw` que le contenu de
   page ci-dessous, pour qu'ils restent alignés visuellement sur un grand écran — plutôt que de
   revenir à une valeur fixe qui aurait recréé l'écart entre header et contenu que la règle du
   29/08/2026 corrigeait justement. La règle dédiée au header reste néanmoins présente (au lieu d'un
   simple retrait) : elle garantit que le bandeau de liens ne dépendra plus JAMAIS d'un `$bodyClass`
   propre à une page, quelle que soit une éventuelle exception réintroduite plus tard sur
   `.container` — c'est précisément ce filet de sécurité qui manquait avant le 29/08/2026. */
.container {
    max-width: 96vw;
    margin: 0 auto;
    padding: 0 20px;
}

.site-header .container {
    max-width: 96vw;
}

a { color: var(--vaa-blue-500); text-decoration: none; transition: color .12s ease; }
a:hover { text-decoration: underline; }

/* --- Header --- */
/* Bandeau de liens fixé en haut au défilement (09/09/2026, demande explicite de l'utilisateur :
   "esqu'il serait possible de bloque le menu des lein en haut et que seul le reste de la page
   scroll ?") — `position: sticky` plutôt que `fixed` : reste dans le flux normal du document (pas
   besoin d'un `padding-top` compensatoire ailleurs comme l'exigerait `fixed`), simplement "collé" en
   haut du viewport dès que la page défile assez pour l'atteindre. `z-index: 100` : au-dessus du
   contenu de page (le plus haut z-index utilisé ailleurs sur une page, hors #toast-container à 1000,
   est le panneau des menus déroulants du bandeau lui-même, `.main-nav__dropdown-panel` à 40) — le
   bandeau doit rester au-dessus de tout le contenu qui défile sous lui. `box-shadow` ajoutée
   uniquement pour détacher visuellement le bandeau du contenu une fois qu'il n'est plus collé au
   tout début de page (sinon la limite entre les deux devient peu visible sur un fond de page déjà
   sombre en haut de .hero) — posée en permanence plutôt que conditionnée au scroll (éviter du JS
   uniquement pour ce détail visuel mineur), sans effet perceptible quand le bandeau est déjà tout en
   haut de page (rien en dessous à distinguer). */
.site-header {
    background: var(--vaa-blue-900);
    color: var(--vaa-white);
    position: sticky;
    top: 0;
    z-index: 100;
    box-shadow: 0 2px 10px rgba(11, 37, 69, 0.35);
}

/* Compense le bandeau `.site-header` (position: sticky, ci-dessus) pour toute cible d'ancre "#..."
   sur laquelle le navigateur peut être amené à sauter directement au chargement (09/09/2026, demande
   explicite de l'utilisateur : "quand on clic sur carte des aeroport visite [...] il faudrais que
   l'on arrive sur le tablea vol compagnie et vol libre" — voir public/pilote.php, id="pilot-flights"
   posé sur la carte "Vols compagnie" et l'ancre "#pilot-flights" ajoutée à l'URL générée par un clic
   sur la carte des aéroports visités). Sans cette règle, le navigateur aligne le HAUT de la cible
   avec le HAUT du viewport — qui se trouve alors caché sous le bandeau collant, laissant le titre
   "Vols compagnie" invisible juste après le saut. `scroll-margin-top` ajoute cette même marge à
   TOUTE navigation vers cette cible (clic direct sur une ancre "#pilot-flights" comprise, pas
   seulement l'arrivée déclenchée par JavaScript), de façon cohérente avec la hauteur du bandeau
   (~14px de padding haut/bas + son contenu) plus une petite marge de confort. */
#pilot-flights {
    scroll-margin-top: 84px;
}

.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    padding: 14px 20px;
    gap: 12px;
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--vaa-white);
}
.brand:hover { text-decoration: none; }

.brand__mark {
    background: var(--vaa-red-500);
    color: var(--vaa-white);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.5px;
    padding: 4px 8px;
    border-radius: 4px;
}

.brand__name { font-weight: 600; font-size: 18px; }

.main-nav {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}

.main-nav a { color: var(--vaa-grey-100); }
.main-nav__hello { color: var(--vaa-grey-200); font-size: 14px; }

/* --- Menu déroulant "AlsaéroVol" (29/08/2026, demande explicite de l'utilisateur : renommer "Vols"
   en "AlsaéroVol" et faire apparaître au survol des sous-liens vers Rapport de vol / Nos lignes /
   Mes réservations, "avec un effet 3d ou moderne"). CSS pur (comme le reste du site, aucun JS de
   menu ailleurs) : le panneau se déploie au survol (`:hover`) ou au focus clavier (`:focus-within`,
   pour rester utilisable au clavier — le déclencheur est le premier élément focusable du conteneur,
   donc le panneau s'ouvre dès qu'on le tabule, avant même de tabuler vers ses propres liens).
   `visibility` volontairement absente de la transition (seuls `opacity`/`transform`/`pointer-events`
   changent) pour que les sous-liens restent atteignables au clavier même quand le panneau est
   visuellement masqué. Effet "3D" : `perspective` sur le conteneur + `rotateX` sur le panneau, qui
   bascule d'une légère inclinaison vers l'arrière (`rotateX(-12deg)`, comme un pan qui se rabat) à
   plat au survol, combiné à un léger `translateY` et un fondu — plus une ombre portée marquée pour
   détacher le panneau du fond bleu du bandeau.
   Ajustement (29/08/2026, suite immédiate, demande explicite de l'utilisateur : "verrouiller" le
   libellé pour qu'il ne navigue plus lui-même) : le déclencheur n'est plus un `<a href="vols.php">`
   mais un `<button type="button" class="main-nav__dropdown-trigger">` sans action propre (voir
   header.php) — `.main-nav__dropdown-trigger` réinitialise l'apparence par défaut d'un `<button>`
   (fond, bordure, curseur, police) pour qu'il reste visuellement identique aux autres liens du
   bandeau. Sur mobile (pas de survol tactile), un tap sur ce bouton le fait passer au premier plan
   du focus, ce qui déclenche `:focus-within` et affiche le sous-menu — comportement standard de la
   plupart des navigateurs mobiles pour un élément focusable ; un second tap sur un sous-lien navigue
   ensuite normalement.
   Renommé "AlsaeroLoc" (29/08/2026, suite immédiate, demande explicite de l'utilisateur —
   "AlsaeroVol je vais le garder pour le tracker") : l'utilisateur réserve "AlsaéroVol" à un autre
   usage, donc ce libellé de menu change de nom pour éviter toute confusion ; aucun impact sur ce
   fichier (le texte du bouton vit dans header.php), juste une note pour retrouver ce changement. */
.main-nav__dropdown {
    position: relative;
}
.main-nav__dropdown-trigger {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: var(--vaa-grey-100);
    cursor: pointer;
}
.main-nav__dropdown-trigger::after {
    content: " ▾";
    display: inline-block;
    font-size: 10px;
    opacity: .8;
    transition: transform .18s ease;
}
.main-nav__dropdown:hover .main-nav__dropdown-trigger::after,
.main-nav__dropdown:focus-within .main-nav__dropdown-trigger::after {
    transform: rotate(180deg);
}
.main-nav__dropdown-panel {
    position: absolute;
    top: 100%;
    left: 50%;
    min-width: 220px;
    padding: 8px;
    margin: 0;
    background: var(--vaa-white);
    border-radius: var(--vaa-radius);
    box-shadow: 0 24px 48px rgba(11, 37, 69, 0.35), 0 4px 14px rgba(11, 37, 69, 0.18);
    opacity: 0;
    pointer-events: none;
    transform: translateX(-50%) translateY(-4px) perspective(600px) rotateX(-12deg);
    transform-origin: top center;
    transition: opacity .18s ease, transform .18s ease;
    z-index: 40;
}
.main-nav__dropdown:hover .main-nav__dropdown-panel,
.main-nav__dropdown:focus-within .main-nav__dropdown-panel {
    opacity: 1;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0) perspective(600px) rotateX(0deg);
}
.main-nav__dropdown-panel a {
    display: block;
    color: var(--vaa-grey-800) !important;
    padding: 10px 14px;
    border-radius: 6px;
    font-size: 14px;
    white-space: nowrap;
    transition: background .12s ease, transform .12s ease;
}
.main-nav__dropdown-panel a:hover,
.main-nav__dropdown-panel a:focus {
    background: var(--vaa-grey-100);
    text-decoration: none;
    transform: translateX(3px);
}

/* --- Buttons --- */
.button {
    display: inline-block;
    background: var(--vaa-red-500);
    color: var(--vaa-white) !important;
    padding: 10px 18px;
    border-radius: var(--vaa-radius);
    border: none;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none !important;
    transition: background-color .15s ease, transform .1s ease, box-shadow .15s ease;
}
.button:hover { background: #a90c25; transform: translateY(-1px); box-shadow: 0 3px 8px rgba(11, 37, 69, 0.18); }
.button:active { transform: translateY(0); box-shadow: none; }
.button:disabled { opacity: .6; cursor: default; transform: none; box-shadow: none; }
.button--small { padding: 6px 12px; font-size: 13px; }
.button--secondary { background: var(--vaa-grey-500); }
.button--secondary:hover { background: #565e69; }
.button--danger { background: #8a1220; }

/* --- Cards / forms --- */
.card {
    background: var(--vaa-white);
    border-radius: var(--vaa-radius);
    box-shadow: var(--vaa-shadow);
    padding: 28px;
    margin: 28px 0;
    animation: vaaFadeInUp .35s ease both;
}

.card h1, .card h2 { margin-top: 0; color: var(--vaa-blue-900); }

form .field { margin-bottom: 16px; }

form label {
    display: block;
    font-weight: 600;
    margin-bottom: 6px;
    font-size: 14px;
}

.hint {
    display: block;
    font-weight: 400;
    color: var(--vaa-grey-500);
    font-size: 13px;
    margin-top: 4px;
}

/* Drapeau pays affiché juste avant un code OACI, partout où un aéroport est affiché (09/09/2026,
   demande explicite de l'utilisateur : "afficher le drapeau du pays a côté de l'aéroport [...]
   partout ou il y a des aeroport inscrit") — voir airport_flag()/country_flag_img() dans
   config/bootstrap.php. */
.airport-flag {
    display: inline-block;
}
/* Image SVG (flagcdn.com, voir country_flag_img()) remplaçant l'émoji d'origine (09/09/2026, suite
   immédiate, demande explicite de l'utilisateur : "j'ai des membres qui me dissent que les drapeau
   ne s'affiche il a uniquement FR ou US qui s'affiche il utilise chrome" — la police d'émoji de
   Windows ne dessine un vrai drapeau que pour une poignée de pays, tous les autres retombent sur les
   deux lettres du code ; une image, elle, s'affiche IDENTIQUEMENT partout). Hauteur calée sur le
   texte environnant (`1em`, comme l'ancien émoji), largeur `auto` pour ne JAMAIS déformer un drapeau
   qui n'a pas le ratio 4:3 le plus courant (le Népal, notamment, est un cas extrême). Léger
   ajustement vertical (`vertical-align`) + fine bordure/ombre très discrète (la plupart des drapeaux
   ont un bord blanc/clair, invisible sans un contour léger sur le fond blanc des tableaux du site) —
   `border-radius` minime, cohérent avec `--vaa-radius` utilisé partout ailleurs sur le site mais
   réduit ici vu la petite taille. */
.flag-icon {
    display: inline-block;
    height: 1em;
    width: auto;
    vertical-align: -0.15em;
    border-radius: 2px;
    box-shadow: 0 0 0 1px rgba(11, 37, 69, .15);
}

form input[type="text"],
form input[type="email"],
form input[type="password"],
form select {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    font-size: 15px;
    background: var(--vaa-white);
}

/* Pas de règle dédiée aux <textarea> avant le 28/08/2026 : ils gardaient donc la taille par défaut
   du navigateur (~20 colonnes), bien plus étroite que les autres champs du formulaire — remarqué
   par l'utilisateur sur le champ "Remarques" des rapports de vol (compagnie et libre, un seul et
   même champ partagé, voir vols.php). Alignée sur les autres champs (largeur 100%, mêmes bordure/
   police), avec un `resize: vertical` pour laisser le pilote agrandir en hauteur si besoin. */
form textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    font-size: 15px;
    font-family: inherit;
    background: var(--vaa-white);
    resize: vertical;
    box-sizing: border-box;
}

form input:focus, form select:focus, form textarea:focus {
    outline: 2px solid var(--vaa-blue-500);
    outline-offset: 1px;
}

.callsign-field {
    display: flex;
    align-items: center;
    gap: 8px;
}
.callsign-field__prefix {
    background: var(--vaa-grey-200);
    padding: 10px 12px;
    border-radius: var(--vaa-radius);
    font-weight: 700;
    letter-spacing: 1px;
}
.callsign-field input {
    width: 100px;
    letter-spacing: 2px;
    font-weight: 600;
}

.field-error {
    color: var(--vaa-red-500);
    font-size: 13px;
    margin-top: 4px;
    display: block;
}

.required::after {
    content: " *";
    color: var(--vaa-red-500);
}

/* --- Alerts --- */
.alert {
    padding: 14px 16px;
    border-radius: var(--vaa-radius);
    margin: 20px 0;
    font-size: 14px;
}
.alert--success { background: #e3f6e8; color: #1e6b3a; border: 1px solid #bfe8cb; }
.alert--error { background: #fdecec; color: #8a1220; border: 1px solid #f7c6c6; }
.alert--info { background: #e8f0fb; color: #13355e; border: 1px solid #c7d9f2; }

/* --- Tables (admin) --- */
table.data-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--vaa-white);
    box-shadow: var(--vaa-shadow);
    border-radius: var(--vaa-radius);
    overflow: hidden;
}
table.data-table th, table.data-table td {
    padding: 10px 12px;
    text-align: left;
    border-bottom: 1px solid var(--vaa-grey-200);
    font-size: 14px;
}
table.data-table th {
    background: var(--vaa-blue-900);
    color: var(--vaa-white);
    font-weight: 600;
}
table.data-table tr:last-child td { border-bottom: none; }
table.data-table tbody tr { transition: background-color .12s ease; }
table.data-table tbody tr:hover { background: var(--vaa-grey-100); }

/* Ligne ATIS mise en évidence dans le tableau "Fréquences radio" de hub.php (29/08/2026) : pas de
   texte ATIS en direct disponible gratuitement (aucune API équivalente à METAR/TAF ne couvrant les
   aéroports européens, voir App\AviationWeather) — décision confirmée par l'utilisateur, on se
   contente de faire ressortir la fréquence à l'écoute plutôt que de la noyer dans le reste du
   tableau. Le gras d'origine a été retiré le même jour (suite immédiate, demande explicite de
   l'utilisateur) : seul le fond coloré marque désormais la ligne. */
table.data-table tbody tr.freq-row--atis {
    background: #eaf2fb;
}
table.data-table tbody tr.freq-row--atis:hover { background: #dbe9f8; }

/* En-têtes de colonnes triables (ex : fiche pilote) : garder le blanc du
   thème sur fond bleu foncé plutôt que le bleu clair des liens standards. */
table.data-table th a {
    color: inherit;
}
table.data-table th a:hover {
    text-decoration: underline;
}

/* En-têtes de colonnes triables côté client (tableaux "Lignes compagnie" de
   hub.php et de l'onglet "Lignes" de vols.php, 29/08/2026, voir
   assets/js/sortable-table.js) : même apparence que les liens de tri
   serveur ci-dessus (fiche pilote), mais un <button> puisqu'il n'y a pas de
   rechargement de page ici. */
table.data-table th button.sort-button {
    background: none;
    border: 0;
    margin: 0;
    padding: 0;
    color: inherit;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
}
table.data-table th button.sort-button:hover {
    text-decoration: underline;
}

/* Tableau "Nos pilotes" (public/pilotes.php, 05/09/2026, demande explicite : "centrer tous les
   titre" plutôt que l'alignement à gauche par défaut de .data-table ci-dessus) — scopé à CE
   tableau via .pilots-table plutôt que de changer la règle générale table.data-table th (qui
   habille aussi les tableaux admin, vols, flotte... non concernés par cette demande). Les deux
   sous-en-têtes "ID"/"Token" de la colonne "VID FSHub" avaient d'abord dérogé à ce centrage
   ("a gauche pour fshub ID et a droite Token", puis étendu aux valeurs elles-mêmes), avant que
   l'utilisateur ne revienne dessus le jour même ("le oui n'est pas centrer" -> "les deux : centrer
   ID et Token") : ID et Token sont donc CENTRÉS eux aussi désormais, comme tout le reste de ce
   tableau — voir plus bas, la règle dédiée a remplacé l'alignement gauche/droite. */
.pilots-table thead th {
    text-align: center;
}
/* Séparateurs verticaux entre colonnes (05/09/2026, suite immédiate, demande explicite : "je vois
   que les VID ivao et vatsim soit centre et qu'il y est une petite separation verticale entre
   chaque ID mais pas entre chaque titre") — .data-table ne définit par défaut que des bordures
   HORIZONTALES (border-bottom, séparant les lignes) : la légère séparation déjà visible entre
   cellules de données venait simplement de l'espacement naturel entre elles, pas d'une bordure
   réelle, d'où son absence, plus perceptible, sur la ligne d'en-tête à deux niveaux (rowspan/
   colspan) qui casse ce rythme régulier. Bordure verticale explicite ajoutée sur TOUTES les
   cellules (`<th>` ET `<td>`, y compris la dernière colonne — la légère ligne le long du bord droit
   du tableau est volontaire, cohérente avec une grille complète plutôt qu'une grille interrompue au
   dernier pilier) pour que l'en-tête et le corps du tableau affichent la même séparation entre
   chaque colonne. */
.pilots-table th,
.pilots-table td {
    border-right: 1px solid var(--vaa-grey-200);
}
/* "ID"/"Token" forcées à la même largeur (05/09/2026, suite immédiate : "le titre VID FSHub est pas
   centrer [...] cela fait que l'on a l'impression que ID et Tokken ne sont pas a gauche et droite")
   — le titre "VID FSHub" était BIEN centré au sens CSS (text-align: center sur la cellule
   colspan="2"), mais son centre visuel ne tombait pas à la frontière entre les colonnes ID/Token
   tant que ces deux colonnes n'avaient pas la même largeur (Token naturellement plus large que ID,
   son libellé étant plus long) : le titre semblait donc décalé vers la droite. Largeur égale
   imposée aux deux `<th>` pour que le milieu du groupe coïncide avec la frontière entre les deux
   colonnes.
*/
.pilots-table th.col-fshub-id,
.pilots-table th.col-fshub-token {
    width: 4.5em;
}
/* ID/Token recentrés (05/09/2026, suite immédiate, demande explicite : "le oui n'est pas centrer"
   -> "les deux : centrer ID et Token") — remplace l'alignement gauche/droite mis en place plus tôt
   dans la même journée : les titres étaient déjà centrés par .pilots-table thead th, seules les
   valeurs ("Oui"/"Non"/l'identifiant réel) avaient besoin de cette règle explicite, .data-table td
   étant alignée à gauche par défaut. */
.pilots-table td.col-fshub-id,
.pilots-table td.col-fshub-token {
    text-align: center;
}
/* VID IVAO/VATSIM : titres déjà centrés par .pilots-table thead th ci-dessus, valeurs centrées elles
   aussi (05/09/2026, suite immédiate, demande explicite : "peut tu centrer les vid egalement") —
   scopé aux seules colonnes VID IVAO/VATSIM via .col-vid, pas à toutes les colonnes de
   pilotes.php (nom du pilote, HUB, heures... restent alignées à gauche, plus lisibles ainsi pour
   du texte). */
.pilots-table td.col-vid {
    text-align: center;
}
table.data-table th .sort-arrow {
    display: inline-block;
    min-width: 1em;
}

/* Filtre par heure de départ au-dessus des tableaux "Lignes compagnie"
   (hub.php + onglet "Lignes" de vols.php, 02/09/2026, voir
   assets/js/route-hour-filter.js) : hors d'un <form> (ce n'est pas une
   soumission), donc règles dédiées plutôt que réutiliser les styles
   `form label`/`form select` qui ne s'appliqueraient pas ici. */
[data-hour-filter-field] {
    margin-bottom: 16px;
}
[data-hour-filter-field] label {
    display: block;
    font-weight: 600;
    margin-bottom: 6px;
    font-size: 14px;
}
[data-hour-filter-field] select.hour-filter {
    padding: 10px 12px;
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    font-size: 15px;
    background: var(--vaa-white);
    max-width: 260px;
}
[data-hour-filter-field] select.hour-filter:focus {
    outline: 2px solid var(--vaa-blue-500);
    outline-offset: 1px;
}

.badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
}
.badge--active { background: #e3f6e8; color: #1e6b3a; }
.badge--pending { background: #fff4de; color: #925c00; }
.badge--awaiting_validation { background: #efe6fb; color: #5b3aa6; }
.badge--suspended { background: #fdecec; color: #8a1220; }
.badge--admin { background: #e8f0fb; color: #13355e; }
/* 09/09/2026, nouveau rôle "staff" (voir migration_046_visibility_groups.sql) — teinte distincte
   (sarcelle) de .badge--admin ci-dessus pour ne jamais confondre les deux au premier coup d'œil
   dans la liste des membres (public/admin/index.php). */
.badge--staff { background: #e0f5f3; color: #0f6b61; }
.badge--approved { background: #e3f6e8; color: #1e6b3a; }
.badge--rejected { background: #fdecec; color: #8a1220; }
.badge--grade { background: #fdf0d5; color: #8a5a00; vertical-align: middle; }
.badge--muted { background: #eef0f3; color: #55606b; }
/* AOG (Aircraft On Ground — voir migration_044, 07/09/2026) : même famille de rouge que
   .badge--suspended (maintenance planifiée) mais INVERSÉE (fond plein plutôt que pastel), pour se
   distinguer visuellement comme plus urgente sans introduire une nouvelle couleur dans la palette. */
.badge--aog { background: #8a1220; color: #ffffff; }

/* Colonne "VID" du tableau des membres (admin/index.php, 03/09/2026, suite immédiate) : les trois
   identifiants réseau (IVAO, VATSIM, FSHUB) affichés sur trois lignes empilées dans une seule
   cellule/colonne, plutôt que trois colonnes séparées — demande explicite de l'utilisateur après
   que les trois colonnes distinctes ont trop élargi le tableau ("on voit plus le reste du
   tableau"). Petite taille pour rester compact sur trois lignes sans agrandir la hauteur de ligne
   du tableau au-delà du nécessaire. */
.vid-stack {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 12px;
    white-space: nowrap;
}

/* Colonne "Type de vol" du tableau de la flotte (admin/aircraft.php, 04/09/2026) : même
   principe d'empilement compact que .vid-stack ci-dessus (plusieurs badges dans une seule
   cellule/colonne plutôt que colonnes séparées), mais nom générique car réutilisable pour
   n'importe quelle liste de badges empilés, pas seulement des identifiants VID. */
.badge-stack {
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: flex-start;
}
/* Colonne "Briefing" du tableau "Mes réservations en cours" (public/partials/
   reservation-panel.php, 04/09/2026) : icône SimBrief à l'intérieur du bouton
   ".button--small", dimensionnée en `em` pour rester proportionnelle au texte du bouton qui la
   porte, un peu plus grande que le repère "compte FSHUB lié" qui existait jusqu'ici sur la fiche
   pilote (retiré le 05/09/2026, remplacé par la colonne "VID FSHub" de pilotes.php) car seule dans
   le bouton, pas accolée à un nom. */
.briefing-icon {
    display: inline-flex;
    vertical-align: -3px;
    width: 1em;
    height: 1em;
    margin-right: 4px;
}
.briefing-icon svg { width: 100%; height: 100%; display: block; }

/* Bouton "voir le rapport détaillé" (œil, icône 'eye') posé dans sa propre colonne "Détail" (1ʳᵉ
   colonne) des tableaux "Vols compagnie"/"Vols libres" (fiche pilote) et "Rapport de vol" (mes
   vols) pour les vols trackés FSHUB (12/09/2026, demande explicite de l'utilisateur : "pour voir
   les rapports pilote on peut rajouter un oeil a gauche dans la premiere colonne pour afficher le
   detail du rapport"). Agrandie et déplacée dans une colonne dédiée (au lieu d'accoler l'icône au
   texte d'une colonne existante) — demande explicite immédiate : "enlever le lien sur la date et
   rajouter un titre de la colonne Détail et agrandir l'icone" — taille fixe plutôt qu'en `em`
   (n'a plus besoin de suivre la taille du texte voisin, elle est seule dans sa colonne). */
.report-view-icon {
    display: inline-flex;
    width: 22px;
    height: 22px;
    color: var(--vaa-blue-500);
}
.report-view-icon svg { width: 100%; height: 100%; display: block; }

.actions-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0; }
.table-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.table-actions form { display: inline-flex; gap: 4px; align-items: center; }
.table-actions__input {
    padding: 4px 8px;
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    font-size: 13px;
    width: 140px;
}

.per-page-form {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 4px 0 16px;
    font-size: 14px;
    color: var(--vaa-grey-500);
}
.per-page-form select {
    width: auto;
    padding: 6px 10px;
}

/* Graphique "Nombre de vols par période" (28/08/2026, demande explicite de l'utilisateur, voir
   render_flights_chart() dans bootstrap.php) : SVG généré côté serveur, une seule teinte (bleu de
   marque, cohérent avec le reste du site — une seule série, pas de légende nécessaire). */
.flights-chart__svg {
    display: block;
}
.flights-chart__gridline {
    stroke: var(--vaa-grey-200);
    stroke-width: 1;
    shape-rendering: crispEdges;
}
.flights-chart__axis-label {
    fill: var(--vaa-grey-500);
    font-size: 11px;
    font-family: inherit;
}
/* Chiffre au-dessus de chaque barre masqué par défaut, affiché seulement au survol/focus de la
   barre (09/09/2026, demande explicite de l'utilisateur : "esque l'on peux afficher le chiffre des
   statistique que lorsque quand la souris va sur le trait des stat") — avant cette demande, ce
   chiffre était affiché en permanence au-dessus de chaque barre. `pointer-events: none` pour que le
   texte (qui déborde légèrement au-dessus de la barre) ne vole pas le survol à la barre elle-même
   ou à sa voisine. S'applique aux quatre graphiques (vols, heures, NM, carburant), tous générés par
   render_stats_bar_chart() et partageant ces mêmes classes CSS. */
.flights-chart__value-label {
    fill: var(--vaa-blue-900);
    font-size: 13px;
    font-weight: 700;
    font-family: inherit;
    opacity: 0;
    pointer-events: none;
    transition: opacity .15s ease;
}
.flights-chart__bar-group:hover .flights-chart__value-label,
.flights-chart__bar-group:focus .flights-chart__value-label {
    opacity: 1;
}
.flights-chart__bar {
    fill: var(--vaa-blue-500);
    transition: fill .15s ease;
}
/* La barre "réagit" au survol/focus (soulignement visuel demandé par le guide de dataviz interne :
   "the hovered mark lifts") — le groupe entier est focusable au clavier (tabindex="0" posé côté
   PHP), l'infobulle native <title> et le contour de focus suivent la même cible. */
.flights-chart__bar-group:hover .flights-chart__bar,
.flights-chart__bar-group:focus .flights-chart__bar {
    fill: var(--vaa-blue-700);
}
.flights-chart__bar-group:focus {
    outline: 2px solid var(--vaa-blue-500);
    outline-offset: 2px;
}
.flights-chart__table-toggle {
    margin-top: 22px;
}
.flights-chart__table-toggle summary {
    cursor: pointer;
    color: var(--vaa-blue-500);
    font-weight: 500;
    font-size: 13px;
}
.flights-chart__table-toggle table {
    margin-top: 10px;
}

.checkbox-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    margin-top: 4px;
}
.checkbox-list__item {
    font-weight: normal;
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Ordre d'affichage des sections de hub.php (admin/settings.php, 05/09/2026, suite immédiate des
   cases à cocher show/hide ci-dessus : "possibilite de rajouter [...] un ordre d'affichage
   egalement") — chaque bouton ▲/▼ est son propre petit <form>, d'où le padding/gap réduits sur
   .reorder-list__form pour qu'ils restent visuellement une simple paire de boutons côte à côte. */
.reorder-list {
    list-style: none;
    margin: 4px 0 0;
    padding: 0;
    max-width: 420px;
}
.reorder-list__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--vaa-grey-200);
}
.reorder-list__item:last-child {
    border-bottom: none;
}
.reorder-list__actions {
    display: flex;
    gap: 6px;
}
.reorder-list__form {
    margin: 0;
    display: inline;
}

/* Médiathèque (14/09/2026, voir migration_059/(223)) — public/admin/media.php, en mode normal ET en
   mode sélecteur (`?picker=1`, ouverte en popup, voir assets/js/media-picker.js). Grille responsive
   simple (`auto-fill`/`minmax`, pas de point de rupture dédié à maintenir) : autant de colonnes que
   la largeur de la popup ou de l'écran le permet, jamais moins d'une carte de 140px de large. */
.media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 14px;
    margin-top: 16px;
}
.media-grid__item {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.media-grid__thumb {
    display: block;
    aspect-ratio: 4 / 3;
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    overflow: hidden;
    background: var(--vaa-grey-100);
    padding: 0;
    cursor: default;
}
/* Uniquement en mode sélecteur (.media-picker-select, voir media.php) : la vignette devient un vrai
   bouton cliquable — curseur main + léger zoom au survol pour signaler qu'elle est sélectionnable,
   contrairement au mode normal ci-dessus où elle n'est qu'un aperçu. */
button.media-grid__thumb.media-picker-select {
    cursor: pointer;
    transition: transform .15s ease, border-color .15s ease;
}
button.media-grid__thumb.media-picker-select:hover {
    transform: scale(1.03);
    border-color: var(--vaa-blue-500);
}
.media-grid__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.media-grid__caption {
    font-size: .85rem;
    font-weight: 600;
    margin: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.media-grid__meta {
    font-size: .78rem;
    color: var(--vaa-grey-500);
    margin: 0;
}
.media-grid__link {
    font-size: .75rem;
    width: 100%;
}

/* Pagination des tableaux "Lignes compagnie" de la page Hub (assets/js/table-pagination.js,
   05/09/2026, demande explicite : "affichage par 20 vol par default et un numero de page"). */
.table-pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
}
.table-pagination__page.is-active {
    background: var(--vaa-blue-500);
    color: var(--vaa-white);
    border-color: var(--vaa-blue-500);
}

/* Grille "Fréquences radio / Pistes / Aides à la navigation" de la page Hub (public/hub.php,
   05/09/2026, demande explicite : "un tableau avec 4 colonne. 2 Colone de gauche Fréquences radio
   et les 2 de droite Pistes et en dessous de piste mettre aides navigation") : deux colonnes de
   largeur égale (donc "4 colonnes" au sens de deux moitiés de page) — la colonne de gauche contient
   la carte Fréquences, la colonne de droite empile Pistes puis Aides à la navigation. Repasse en
   une seule colonne sur petit écran, même seuil que .fshub-airports (autre grille à deux colonnes
   du site) pour rester cohérent. */
.hub-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    align-items: start;
}
.hub-grid__col .card:first-child {
    margin-top: 0;
}
@media (max-width: 700px) {
    .hub-grid { grid-template-columns: 1fr; }
}

/* Carte d'identité du hub (nom/OACI/aéroport) + météo (METAR) + prévisions (TAF) sur 3 colonnes
   (public/hub.php, 05/09/2026, demande explicite : "on peut faire trois colonne sur le premier
   tableau a gauche Aeroport au milieu le Metart et a droite le TAF") — nombre de colonnes calculé
   côté PHP (`$hubIdentityColumns`) selon que METAR et/ou TAF sont affichés, d'où les trois variantes
   ci-dessous plutôt qu'un nombre de colonnes fixe. Seuil de repli mobile plus large (900px) que
   .hub-grid (700px) : trois colonnes ont besoin de plus de place que deux avant de devenir trop
   étroites. */
.hub-identity-grid {
    display: grid;
    gap: 24px;
    align-items: start;
}
.hub-identity-grid--cols-1 { grid-template-columns: 1fr; }
.hub-identity-grid--cols-2 { grid-template-columns: 1fr 1fr; }
.hub-identity-grid--cols-3 { grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 900px) {
    .hub-identity-grid--cols-2,
    .hub-identity-grid--cols-3 {
        grid-template-columns: 1fr;
    }
}

/* --- Onglets (ex : type de vol sur mes-vols.php) --- */
.tabs {
    display: inline-flex;
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    overflow: hidden;
    margin-top: 4px;
}
.tabs__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 9px 18px;
    font-weight: 600;
    font-size: 14px;
    cursor: pointer;
    background: var(--vaa-white);
    color: var(--vaa-grey-800);
    user-select: none;
    transition: background-color .15s ease, color .15s ease;
}
.tabs__item:hover:not(.is-active) { background: var(--vaa-grey-100); }
.tabs__item + .tabs__item {
    border-left: 1px solid var(--vaa-grey-200);
}
.tabs__item.is-active {
    background: var(--vaa-blue-500);
    color: var(--vaa-white);
}
.tabs__radio {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}
.is-hidden {
    display: none;
}

/* --- Autocomplete aéroport (assets/js/airport-search.js) --- */
.airport-search {
    position: relative;
}
.airport-search__results {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    background: #fff;
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    max-height: 240px;
    overflow-y: auto;
    margin-top: 4px;
}
.airport-search__item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 10px;
    border: none;
    background: none;
    font-size: 14px;
    cursor: pointer;
}
.airport-search__item:hover,
.airport-search__item:focus {
    background: var(--vaa-grey-100);
}

/* --- Stat tiles (fiche pilote) --- */
.stats-row {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    margin: 20px 0;
}
.stat-tile {
    flex: 1 1 160px;
    background: var(--vaa-grey-100);
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    padding: 16px;
    text-align: center;
    transition: transform .15s ease, box-shadow .15s ease;
}
.stat-tile:hover { transform: translateY(-2px); box-shadow: var(--vaa-shadow); }
.stat-tile__value {
    font-size: 28px;
    font-weight: 700;
    color: var(--vaa-blue-900);
}
.stat-tile__label {
    font-size: 13px;
    color: var(--vaa-grey-500);
    margin-top: 4px;
}

/* Tableau de bord "Notre compagnie en quelques chiffres" — page d'accueil uniquement (28/08/2026,
   demande explicite d'un affichage "moderne et dynamique" : tuiles + icônes + chiffres qui
   s'animent au défilement, voir assets/js/stat-counter.js pour l'animation). Classes posées EN
   PLUS de .stat-tile/.stats-row (jamais une modification de ces dernières, réutilisées telles
   quelles par pilote.php) — .stats-dashboard/.stat-tile--rounded/.stat-icon ne s'appliquent qu'à
   cette section d'index.php. Les six tuiles sont volontairement identiques au repos (taille,
   couleur) — une variante "phare" plus grande avait été testée puis retirée à la demande de
   l'utilisateur, qui a préféré six tuiles uniformes. Forme rectangulaire à angles arrondis (suite
   immédiate, remplace la forme ronde initiale).

   Disposition en flexbox plutôt qu'en CSS grid (grid utilisé dans une itération précédente) —
   changement nécessaire pour permettre l'effet "accordéon" au survol ci-dessous : flex-grow est
   animable et redistribue l'espace disponible entre tuiles, ce que grid-template-columns ne
   permet pas de faire dynamiquement par tuile individuelle sans JavaScript. flex: 1 1 0 (base à
   zéro, pas une largeur fixe) pose le même point de départ à chacune ET fait en sorte que TOUTE
   la largeur disponible — pas seulement le surplus au-delà d'une base fixe — soit répartie selon
   le ratio de grow, condition nécessaire pour que l'effet de zoom au survol soit réellement
   marqué plutôt qu'à peine perceptible. L'alignement se fait naturellement sur une seule ligne de
   6 dès que la largeur le permet, et repasse sur moins de tuiles par ligne (flex-wrap) aux
   largeurs réduites SANS media query dédiée — le point de bascule suit directement min-width. */
.stats-dashboard {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin: 20px 0;
    /* Nécessaire pour que translateZ (effet 3D au survol ci-dessous) ait un vrai effet de
       profondeur sur les tuiles enfants, plutôt qu'un simple agrandissement à plat. */
    perspective: 1200px;
}
.stat-tile--rounded {
    flex: 1 1 0;
    min-width: 100px;
    border-radius: 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-height: 140px;
    background: linear-gradient(135deg, var(--vaa-blue-500), var(--vaa-blue-900));
    border: none;
    box-shadow: var(--vaa-shadow);
    padding: 16px 10px;
    text-align: center;
    transform: perspective(1200px) scale(1) translateZ(0) rotateX(0deg);
    transition: box-shadow .35s ease, transform .35s ease;
}
.stat-tile--rounded .stat-tile__value { color: var(--vaa-white); font-size: 1.25rem; margin: 0; }
.stat-tile--rounded .stat-tile__label { color: rgba(255, 255, 255, 0.85); font-size: .75rem; line-height: 1.25; margin-top: 0; }
/* Report d'heures admin affiché "dont Xh de report" sous la tuile "Heures totales" (14/09/2026, voir
   migration_060/(224/225)) — .hint (gris moyen) serait illisible sur le fond bleu dégradé de
   .stat-tile--rounded ci-dessus, d'où ce style dédié plutôt qu'une réutilisation de .hint ici. */
.stat-tile__hint { display: block; color: rgba(255, 255, 255, 0.65); font-size: .68rem; margin-top: -2px; }
.stat-tile__hint a { color: rgba(255, 255, 255, 0.9); text-decoration: underline; }
.stat-icon {
    width: 26px;
    height: 26px;
    color: rgba(255, 255, 255, 0.9);
}
.stat-icon svg { width: 100%; height: 100%; display: block; }

/* Effet "zoom 3D prononcé" au survol, demande explicite de l'utilisateur à l'origine (le premier
   ajout — agrandissement/rapetissement par flex-grow seul — a été jugé pas assez marqué, d'où
   l'ajout d'une vraie composante 3D par-dessus).
   - "Accordéon" (flex-grow animé 1 → 3 sur la tuile ciblée, les autres se rapetissant pour
     compenser) RETIRÉ le 28/08/2026 (demande explicite de l'utilisateur : l'écran "tremblait" au
     survol) — flex-grow modifie la mise en page (flexbox redistribue vraiment l'espace), donc
     chaque entrée/sortie de :hover déplaçait les tuiles voisines ET le bord de la tuile survolée
     elle-même ; dès que ce mouvement faisait sortir le curseur de la tuile (souvent), :hover se
     désactivait, la tuile revenait à sa taille d'origine, le curseur se retrouvait de nouveau
     dedans, :hover se redéclenchait... — oscillation rapide perçue comme un tremblement. `padding`
     au survol (16px→20px) causait exactly le même problème (modifie aussi la boîte, donc la mise
     en page) et est retiré avec.
   - Le zoom 3D (scale/translateZ/rotateX) est conservé : `transform` ne modifie JAMAIS la mise en
     page (propriété gérée par le compositeur graphique, pas par le moteur de layout) — la tuile
     survolée grossit et se soulève visuellement SANS déplacer ses voisines ni bouger sous le
     curseur, ce qui élimine le tremblement tout en gardant un effet de survol marqué. scale(1.18)
     (zoom visuel), translateZ(50px) (rapproche la tuile du "point de vue", nécessite `perspective`
     posé sur .stats-dashboard plus haut pour un vrai effet de profondeur) et rotateX(-6deg) (légère
     bascule vers l'avant). `z-index` posé pendant le survol pour que la tuile agrandie passe
     visuellement AU-DESSUS de ses voisines (sans quoi, une transform ne changeant pas l'ordre
     d'empilement, elle resterait dessous). Ombre nettement plus prononcée et plus sombre pour
     vendre la sensation de profondeur.
   - Gardé uniquement pour les appareils avec un vrai pointeur/survol (souris) via
     @media (hover: hover) and (pointer: fine) : sur tactile, :hover peut rester "collé" après un
     tap (notamment iOS Safari), ce qui bloquerait une tuile agrandie/inclinée tant que
     l'utilisateur ne touche pas ailleurs sur l'écran — expérience à éviter, d'où ce repli qui
     laisse les tuiles tactiles à leur taille et position fixes habituelles. */
@media (hover: hover) and (pointer: fine) {
    .stat-tile--rounded:hover {
        position: relative;
        z-index: 2;
        transform: perspective(1200px) scale(1.18) translateZ(50px) rotateX(-6deg);
        box-shadow: 0 24px 48px rgba(11, 37, 69, 0.5);
    }
}

/* --- Footer --- */
.site-footer {
    color: var(--vaa-grey-500);
    font-size: 13px;
    text-align: center;
    padding: 30px 0;
}

/* --- Hero (accueil) --- */
/* Historique du 28-29/08/2026 : image ajoutée en filigrane le 28/08/2026 (cover, texte par-dessus —
   version jugée "très bien intégrée" par l'utilisateur). Le 29/08/2026, plusieurs allers-retours ont
   suivi : déplacement dans un bandeau .site-banner séparé, puis retour dans .hero avec
   `aspect-ratio` (bloc trop agrandi selon l'utilisateur), puis `background-size: contain` (image
   jugée trop réduite par l'utilisateur : "elle est reduite j'ai l'impression"). Retour explicite de
   l'utilisateur au final : "hier elle etait tres bien integrer dans le menu au moment ou tu la
   integrer pour la premiere fois" — on revient donc exactement à cette toute première version :
   `background-size: cover`, sans `aspect-ratio`, bloc dimensionné par son padding et son contenu
   comme n'importe quel autre bloc du site.
   Image de fond retirée le 06/09/2026 (demande explicite de l'utilisateur : "on peut enlever
   l'image de fond du menu bienvenue"), devenue redondante depuis l'ajout de la bannière `.welcome-
   banner` juste au-dessus (05/09/2026, voir plus bas). `hero-banner.jpg` reste présente sur le
   disque au cas où — simplement plus référencée ici. Dégradé passé en couleurs pleines (alpha
   retiré) plutôt que laissé semi-transparent : ces valeurs `rgba` n'avaient de sens que superposées
   à l'image, un dégradé semi-transparent sans rien en dessous aurait laissé transparaître l'image de
   fond globale du site (`body`, voir plus bas .site-background), un rendu non voulu ici. */
.hero {
    background: linear-gradient(135deg, rgb(11, 37, 69), rgb(29, 78, 137));
    color: var(--vaa-white);
    border-radius: var(--vaa-radius);
    padding: 48px 32px;
    margin: 28px 0;
}
.hero h1 { margin-top: 0; font-size: 32px; }
.hero p { font-size: 16px; max-width: 600px; }

/* Texte de présentation de la compagnie (06/09/2026, demande explicite de l'utilisateur : "esque tu
   peux également rajouter dans le menu bienvenue ce texte entre le message bienvenue .... et
   Rejoingnez ..."), placé entre le <h1> "Bienvenue chez..." et le <p> "Rejoignez notre compagnie..."
   déjà existant — voir public/index.php.
   Passé de 760px à 100% (06/09/2026, suite immédiate, demande explicite : "esqu'il est possible de
   mettre le texte sur toute la largeur du menu bienvenues") : `.hero__intro` lui-même n'était déjà
   plus limité qu'à 760px, mais chaque <p> à l'intérieur héritait EN PLUS de `max-width: 600px` depuis
   la règle générale `.hero p` (même spécificité CSS, propriété jamais réécrite ici jusqu'à présent) —
   c'est cette limite oubliée, pas les 760px du conteneur, qui empêchait réellement le texte de
   s'élargir. `.hero__intro p` fixe maintenant explicitement `max-width: none` pour lever cette
   limite héritée. */
.hero__intro { max-width: 100%; }
.hero__intro p { max-width: none; font-size: 15px; line-height: 1.6; margin: 0 0 14px; }
.hero__intro p:last-child { margin-bottom: 0; }

/* Signature en bas à droite du texte de présentation (06/09/2026, demande explicite de
   l'utilisateur : "et le message de bienvenue rajouter en bas à droite Le responsable de la V.A.A /
   Eric / VAA068"). */
.hero__signature { text-align: right; font-style: italic; opacity: 0.9; }

/* Logos partenaires IVAO (06/09/2026, demande explicite de l'utilisateur : "le logo ivao france a
   droite et l'autre a gauche et qu'il soit cliquable vers le lien de leurs site") — IVAO Partner VA à
   gauche, IVAO France à droite (voir index.php pour les liens). Encart blanc arrondi derrière chaque
   logo : les deux logos fournis sont en bleu marine sur fond transparent, invisibles à même le
   dégradé navy de .hero sans ce fond clair derrière eux.
   Recentré (06/09/2026, suite immédiate, demande explicite : "centrer la ligne inscition avec le
   logo") : `justify-content` passe de `space-between` (logos collés aux deux bords) à `center` — les
   deux logos se retrouvent groupés au centre, avec un espace entre eux, alignés avec la ligne
   d'inscription centrée juste en dessous (voir `.hero__cta`) plutôt que plaqués aux extrémités d'un
   bloc désormais pleine largeur. */
.hero__partners {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    gap: 24px;
    margin: 4px 0 14px;
}
.hero__partner-logo {
    display: inline-flex;
    align-items: center;
    background: var(--vaa-white);
    border-radius: 8px;
    padding: 8px 16px;
}
.hero__partner-logo img { display: block; height: 36px; width: auto; }

/* Ligne d'inscription ("Rejoignez notre compagnie..." + bouton "Devenir pilote"/"Accéder à mon
   compte") centrée (06/09/2026, demande explicite de l'utilisateur : "centrer la ligne inscition avec
   le logo") — alignée avec `.hero__partners` juste au-dessus, elle aussi centrée. `margin: 0 auto`
   sur le <p> : `text-align: center` seul ne centre que le TEXTE à l'intérieur du bloc, pas le bloc
   lui-même dans .hero (qui reste pleine largeur) — nécessaire ici pour que le <p>, contraint par
   `.hero p { max-width: 600px }`, soit lui-même centré plutôt que collé à gauche. */
.hero__cta { text-align: center; }
.hero__cta p { margin-left: auto; margin-right: auto; }

/* Bannière d'accueil (image), entre le menu et le reste du contenu (05/09/2026, demande explicite
   de l'utilisateur : "mettre cette image en banniere du site entre les menus et le tableau
   bienvenue essayer de la centrer et que cela face plus baniere donc plus large que haute mais
   sans trop deformer ou etirer"). Historique de largeur (avant le 07/09/2026, voir ci-dessous) :
   `height: auto` conservait strictement le ratio d'origine de l'image via une largeur plafonnée
   (`max-width`) et un centrage horizontal (`margin: 0 auto`) — 1100px → 720px le 06/09/2026
   (demande explicite : "retrecir la banniere en hauteur"). Image source retravaillée le 06/09/2026
   (demande explicite : "retravailler l'image pour qu'elle fasse la meme hauteur voir 750 de haut et
   1600 de large") : essai initial à 1600×750 avec bandes bleu marine haut/bas, puis (suite
   immédiate, même jour : "juste plus large pour la hauteur on est bon") bandes retirées, image
   mise à l'échelle uniforme sur sa hauteur (1875×750, ratio ~2,50:1).
   Élargie sur toute la largeur de page le 07/09/2026 (demande explicite de l'utilisateur : "tu peu
   l'elargir sur la largeur de page en gardant la hauteur comme ça ou a peine plus haut", juste après
   le remplacement de l'image du 07/09/2026 par un visuel plus large — ratio ~3:1) : `max-width`
   retiré (largeur pleine du `.container`, 96vw), essai initial avec `height: 260px` fixe +
   `object-fit: cover` pour éviter que la hauteur ne suive le ratio ~3:1 sur toute la largeur de
   l'écran. Retour immédiat de l'utilisateur, même jour : "pour la hauteur laisse libre car l'image
   est trop couper" — la demande initiale de garder une hauteur quasi identique passait donc APRÈS la
   priorité de ne pas recadrer l'image, contrairement à la lecture faite au premier essai. Revenu à
   `height: auto` (comme avant le 07/09/2026, plus de recadrage ni de hauteur fixe, retiré aussi côté
   mobile) : la bannière garde son ratio réel sur toute la largeur de page, donc mécaniquement plus
   haute qu'avant (l'image entière reste visible, y compris le petit avion à hélice perdu par le
   recadrage de l'essai précédent) — hauteur laissée entièrement libre comme demandé, aucun plafond. */
.welcome-banner {
    display: block;
    width: 100%;
    height: auto;
    margin: 0;
    border-radius: var(--vaa-radius);
}

/* Conteneur `position: relative` autour de l'image (08/09/2026, ajout des chiffres clés en
   incrustation, voir index.php pour le contexte complet) — porte la marge verticale de 24px
   auparavant sur `.welcome-banner` elle-même, et sert de repère de positionnement à
   `.welcome-banner__stats` (`position: absolute`, bas-droite).
   `container-type: inline-size` (08/09/2026, suite immédiate, demande explicite de l'utilisateur :
   "verouiller la taille des encadre par rapport au % de l'image [...] de façon à ce que sur PC et
   telephone nous avons le meme affichage") : fait de ce wrapper un "container query container" —
   sa largeur, qui vaut TOUJOURS exactement la largeur affichée de `.welcome-banner` (l'image est en
   `width: 100%` de ce wrapper, voir plus haut), devient l'unité de référence `cqw` utilisée
   ci-dessous par `.welcome-banner__stats`/`.welcome-banner__stat` — au lieu du `vw` (relatif à
   l'écran ENTIER, pas à l'image) ou de pixels fixes (identiques quelle que soit la taille de
   l'image). Résultat : les cadres sont mécaniquement toujours à la même taille PROPORTIONNELLE à la
   bannière, sur n'importe quel écran, sans distinction PC/tablette/téléphone ni point de rupture à
   maintenir. */
.welcome-banner-wrap {
    position: relative;
    margin: 24px auto;
    container-type: inline-size;
}

.welcome-banner__stats {
    position: absolute;
    right: clamp(6px, 1.6cqw, 16px);
    bottom: clamp(6px, 1.6cqw, 16px);
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: clamp(4px, 1cqw, 10px);
    color: var(--vaa-white);
    /* Nécessaire pour que translateZ (effet 3D au survol des cadres ci-dessous) ait un vrai effet
       de profondeur — même technique que .stats-dashboard (tableau de bord "chiffres" plus bas sur
       cette page), voir son commentaire pour le détail complet du raisonnement. */
    perspective: 1200px;
}

/* Chaque chiffre dans son propre cadre (08/09/2026, demande explicite de l'utilisateur : "garder le
   meme principe que le menu des chiffres [...] esque chaque chiffre soit dans un cadres et si
   possible le cadres vraiment transparant") — remplace l'unique bloc partagé du premier essai
   (fond unique à 55% d'opacité autour des 5 chiffres) par des cadres individuels, chacun BEAUCOUP
   plus transparent (fond à 18% d'opacité, plus une fine bordure claire à 30% pour que le cadre
   reste visible même là où l'image est déjà très claire) — `text-shadow` sur la valeur/le libellé
   (ci-dessous) compense la lisibilité perdue par cette transparence accrue, plutôt que de remonter
   l'opacité du fond. `transform` au repos posée explicitement (état de départ du survol ci-dessous,
   même mécanique que .stat-tile--rounded) : une `transform` ne modifie jamais la mise en page,
   contrairement à une évolution de padding/taille, donc le zoom au survol ne fait ni bouger les
   cadres voisins ni "fuir" sous le curseur.
   Padding en `clamp(…, …cqw, …)` (08/09/2026, même demande que ci-dessus sur le wrapper) : plancher
   en pixels fixes pour rester lisible même sur un très petit écran (l'unité `cqw` seule finirait par
   produire du texte illisible en dessous d'une certaine largeur d'image), plafond en pixels fixes
   pour ne pas non plus grossir sans limite sur un très grand écran, et suit fidèlement le
   pourcentage de la largeur de l'image entre les deux — exactement le comportement demandé. Un
   navigateur trop ancien pour comprendre `cqw` ignore simplement ces déclarations (dégradation
   silencieuse, pas de mise en page cassée) et retombe sur la taille de police héritée. */
/* Correctif du 14/09/2026 (rapport utilisateur : "un trait blanc verticale qui apparait entre la
   tuile distance et nombres de passager", au chargement/F5) : chaque cadre est un calque GPU
   indépendant (`transform` posée au repos, voir plus bas) ET porte son propre `backdrop-filter` —
   combinaison connue pour produire, sur Chrome/Chromium, une fine ligne de "couture" au moment du
   premier rendu entre deux calques composités adjacents (surtout sur une image de fond très
   contrastée comme ici), qui disparaît ensuite au premier repaint (survol, redimensionnement...) —
   d'où le symptôme précisément "au chargement/F5" rapporté. Deux changements pour l'éliminer :
   (1) `backdrop-filter: blur(1px)` retiré — un flou de seulement 1px était de toute façon à peine
   perceptible visuellement, mais c'est justement ce filtre par calque qui déclenche la couture ;
   (2) le `perspective(1200px)` du `transform` au repos est retiré, car redondant avec la
   `perspective: 1200px` déjà posée sur le parent `.welcome-banner__stats` — cette double
   déclaration (calque propre ET perspective propre à chaque cadre) est ce qui promeut chaque cadre
   en calque composité distinct en premier lieu. `translateZ(0)` reste seul au repos : c'est lui qui
   évite que les cadres voisins ne "sautent" au survol de l'un d'eux (voir commentaire plus haut) —
   comportement inchangé, juste sans la promotion de calque superflue qui causait la couture. Le
   `perspective(1200px)` reste posé dans la règle `:hover` plus bas, seul endroit où l'effet de
   profondeur 3D est réellement utilisé. */
.welcome-banner__stat {
    text-align: center;
    padding: clamp(5px, 1cqw, 8px) clamp(8px, 1.8cqw, 14px);
    background: rgba(11, 37, 69, .18);
    border: 1px solid rgba(255, 255, 255, .3);
    border-radius: var(--vaa-radius);
    transform: scale(1) translateZ(0) rotateX(0deg);
    transition: transform .35s ease, box-shadow .35s ease, background .35s ease;
}
/* Icône au-dessus de chaque chiffre (08/09/2026, demande explicite de l'utilisateur — "peut tu
   mettre les logo sur les encadre des heures vols etc [...] car cela faisait jolie" : même
   `stat_icon()`/`.stat-icon` que le tableau de bord "chiffres" retiré la veille, mais réduite
   et centrée par `margin: 0 auto` — `.welcome-banner__stat` n'est pas un conteneur flex comme
   `.stat-tile--rounded`, donc pas de `align-items: center` disponible ici pour centrer
   automatiquement le bloc icône. Taille en `clamp(…cqw…)`, même raisonnement que le padding
   ci-dessus. */
.welcome-banner__stat .stat-icon {
    width: clamp(13px, 2.2cqw, 20px);
    height: clamp(13px, 2.2cqw, 20px);
    margin: 0 auto 4px;
}
.welcome-banner__stat-value {
    font-size: clamp(11px, 2.1cqw, 18px);
    font-weight: 700;
    line-height: 1.15;
    white-space: nowrap;
    text-shadow: 0 1px 4px rgba(0, 0, 0, .65);
}
.welcome-banner__stat-label {
    font-size: clamp(7px, 1.05cqw, 10px);
    text-transform: uppercase;
    letter-spacing: .03em;
    opacity: .9;
    white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .65);
}

/* Repli compact sous une certaine largeur d'IMAGE (08/09/2026, suite immédiate — voir le
   raisonnement complet sur `.welcome-banner-wrap` plus haut) : 6 cadres "icône + valeur + libellé"
   empilés sur 3 lignes ne tiennent plus, même à leur taille plancher, sans passer sur 2 rangées —
   et 2 rangées de cadres pleine hauteur deviennent alors plus hautes que la moitié basse "libre"
   (sans logo) d'une bannière proportionnellement très basse sur un téléphone étroit, recouvrant le
   titre "Virtuel Air Alsace" en haut de l'image. Piloté par une "container query" sur la largeur
   RÉELLE de l'image (`@container`, et non `@media` sur la largeur de l'écran) : un même seuil
   relatif s'applique qu'il s'agisse d'un petit téléphone, d'une fenêtre de bureau volontairement
   réduite ou d'une tablette en portrait — pas de distinction figée "PC" vs "téléphone". Les cadres
   restent EXACTEMENT les mêmes (même transparence, même bordure, même position bas-droite) : seul
   leur CONTENU passe d'un empilement vertical (icône / valeur / libellé, 3 lignes) à une ligne
   compacte "icône + valeur" — le libellé disparaît, l'icône suffisant à distinguer chaque chiffre à
   cette taille. Deux rangées de cadres ainsi condensées tiennent alors dans la moitié basse de
   l'image sans toucher au titre. */
@container (max-width: 480px) {
    .welcome-banner__stat {
        display: flex;
        align-items: center;
        gap: 5px;
    }
    .welcome-banner__stat .stat-icon {
        margin: 0;
        flex: none;
    }
    .welcome-banner__stat-label {
        display: none;
    }
}

/* Effet "zoom 3D" au survol d'un cadre — IDENTIQUE à .stat-tile--rounded:hover du tableau de bord
   plus bas (voir son commentaire pour l'historique complet : accordéon par flex-grow essayé puis
   retiré à cause d'un tremblement, remplacé par un zoom scale/translateZ/rotateX pur qui ne
   modifie jamais la mise en page). Fond légèrement moins transparent pendant le survol (`.32` au
   lieu de `.18` au repos) : le cadre agrandi couvre alors une zone plus grande de l'image, un peu
   plus d'opacité évite qu'il ne devienne difficile à repérer visuellement une fois zoomé. Gardé
   uniquement pour les appareils avec un vrai pointeur/survol (`@media (hover: hover) and
   (pointer: fine)`), même garde-fou tactile que le tableau de bord. */
@media (hover: hover) and (pointer: fine) {
    .welcome-banner__stat:hover {
        position: relative;
        z-index: 2;
        background: rgba(11, 37, 69, .32);
        transform: perspective(1200px) scale(1.18) translateZ(50px) rotateX(-6deg);
        box-shadow: 0 24px 48px rgba(11, 37, 69, .5);
    }
}

/* --- Badges "Discord"/"AlsaéroVol" de la bannière d'accueil (10/09/2026) --- */
/* Coins haut-gauche/haut-droit de `.welcome-banner-wrap` (voir index.php pour le détail complet de
   la demande) — même logique de positionnement en incrustation, mêmes unités `cqw` que
   `.welcome-banner__stats` ci-dessus (coin bas-droit), pour un dimensionnement cohérent PC/téléphone
   sans point de rupture dédié. `z-index` posé ici (pas seulement sur le panneau) pour que le badge
   agrandi au survol (voir plus bas) passe bien AU-DESSUS des chiffres bas-droite s'ils se
   chevauchent sur une bannière très basse. */
.welcome-banner__corner {
    position: absolute;
    top: clamp(6px, 1.6cqw, 16px);
    z-index: 3;
}
.welcome-banner__corner--left { left: clamp(6px, 1.6cqw, 16px); }
.welcome-banner__corner--right { right: clamp(6px, 1.6cqw, 16px); }

/* Cadre du badge lui-même — même transparence/bordure/flou que `.welcome-banner__stat`, mais en
   ligne (icône + libellé côte à côte, plus compact que la pile icône/valeur/libellé des chiffres) et
   posé aussi bien sur un `<button>` (Discord) que sur un `<a>` (AlsaéroVol) : `font`/`cursor`/
   `text-decoration` neutralisent les styles par défaut du navigateur pour que les deux aient
   exactement le même rendu. */
.welcome-banner__badge {
    display: flex;
    align-items: center;
    gap: clamp(4px, 1cqw, 8px);
    padding: clamp(5px, 1cqw, 8px) clamp(8px, 1.8cqw, 14px);
    background: rgba(11, 37, 69, .18);
    border: 1px solid rgba(255, 255, 255, .3);
    border-radius: var(--vaa-radius);
    -webkit-backdrop-filter: blur(1px);
    backdrop-filter: blur(1px);
    color: var(--vaa-white);
    text-decoration: none;
    cursor: pointer;
    font: inherit;
    /* Annule le rendu natif du navigateur sur le <button> Discord (le <a> AlsaéroVol n'en a pas
       besoin, mais la règle reste sans effet sur lui) — sans ceci, certains navigateurs affichent un
       léger relief natif sous le fond/la bordure personnalisés ci-dessus. */
    appearance: none;
    -webkit-appearance: none;
    transform: perspective(1200px) scale(1) translateZ(0) rotateX(0deg);
    transition: transform .35s ease, box-shadow .35s ease, background .35s ease;
}
.welcome-banner__badge-icon {
    width: clamp(13px, 2.2cqw, 20px);
    height: clamp(13px, 2.2cqw, 20px);
    flex-shrink: 0;
    display: block;
}
.welcome-banner__badge-icon svg { width: 100%; height: 100%; display: block; }
.welcome-banner__badge-label {
    font-size: clamp(9px, 1.6cqw, 13px);
    font-weight: 700;
    white-space: nowrap;
    text-shadow: 0 1px 4px rgba(0, 0, 0, .65);
}

/* Effet "zoom 3D" au survol — MÊME technique que `.welcome-banner__stat:hover` ci-dessus (valeurs
   très légèrement réduites : ces badges sont plus petits, un `scale(1.18)`/`translateZ(50px)`
   identique les ferait empiéter davantage sur le titre de la bannière juste en dessous). S'applique
   aux DEUX badges (Discord et AlsaéroVol), révélé par la MÊME règle sur le conteneur PARENT
   (`.welcome-banner__corner:hover`) plutôt que sur le badge seul : survoler le panneau une fois
   ouvert ne doit pas le refermer. `:focus-within` en plus de `:hover` : un badge atteint au clavier
   (Tab) révèle aussi son panneau, pas seulement à la souris.

   Historique du panneau Discord (11/09/2026, même journée, trois versions successives) : d'abord un
   panneau (widget compact intégré à la bannière), puis retiré le même jour (demande explicite :
   "on peux enlever le discord sur la page d'acceuil [...] créer une page [...] quand on clic [...]
   on arrive sur la page discord qui nous affiche le serveur complet" — badge devenu simple lien SANS
   panneau, livraison (184)), puis réintroduit aussitôt après (demande explicite, reformulant
   l'intention d'origine : "lorsque l'on passe la souris dessus en effet 3D on ouvre le menu discord
   pour afficher qui est connecter sur discord") — cette fois structuré à l'identique du panneau
   AlsaéroVol (aperçu au survol + lien vers la page complète), voir plus bas. L'ancienne bascule
   tactile JS du panneau (`.is-open`, `initDiscordToggle()`) reste retirée : contrairement à la
   version du 183, ce panneau-ci n'a jamais eu besoin de JS, la révélation restant purement CSS comme
   pour AlsaéroVol — aucune régression tactile à gérer, un tap sur le badge navigue simplement vers
   discord.php sans jamais afficher le panneau (`@media (hover: hover) and (pointer: fine)`
   ci-dessous). */
@media (hover: hover) and (pointer: fine) {
    .welcome-banner__corner:hover .welcome-banner__badge,
    .welcome-banner__corner:focus-within .welcome-banner__badge {
        position: relative;
        z-index: 2;
        background: rgba(11, 37, 69, .32);
        transform: perspective(1200px) scale(1.1) translateZ(30px) rotateX(-6deg);
        box-shadow: 0 18px 36px rgba(11, 37, 69, .5);
    }
    .welcome-banner__corner:hover .welcome-banner__panel,
    .welcome-banner__corner:focus-within .welcome-banner__panel {
        display: block;
    }
}

/* Panneau (aperçu Discord ou mini carte AlsaéroVol au survol, voir ci-dessus) — masqué par défaut
   (`display: none`, révélé ci-dessus), fond opaque `--vaa-blue-900` (contrairement aux cadres très
   transparents du reste de la bannière) : celui-ci porte du contenu à lire (widget/légende), pas
   seulement un chiffre décoratif, il a besoin d'un contraste fiable quel que soit ce qu'il y a
   derrière sur la photo. */
.welcome-banner__panel {
    display: none;
    position: absolute;
    /* `top: 100%` SANS marge (10/09/2026) — un intervalle entre le badge et le panneau laisserait un
       point mort où le pointeur quitte `.welcome-banner__corner` en descendant de l'un vers l'autre
       (le panneau, `display: none` tant qu'il n'est pas survolé, ne peut pas combler ce vide via un
       pseudo-élément) : le panneau se refermerait aussitôt qu'ouvert, avant même d'avoir pu l'atteindre
       à la souris. Les deux se touchent directement plutôt que de tenter de "ponter" l'écart. */
    top: 100%;
    width: 260px;
    max-width: calc(100vw - 32px);
    background: var(--vaa-blue-900);
    color: var(--vaa-white);
    border-radius: var(--vaa-radius);
    box-shadow: var(--vaa-shadow);
    padding: 12px;
    box-sizing: border-box;
    z-index: 4;
}
.welcome-banner__corner--left .welcome-banner__panel { left: 0; }
.welcome-banner__corner--right .welcome-banner__panel { right: 0; }
.welcome-banner__panel-title { margin: 0 0 8px; font-size: 13px; font-weight: 700; }
.welcome-banner__panel iframe { display: block; border-radius: 6px; }
.welcome-banner__panel-cta { display: block; margin-top: 8px; text-align: center; }
.welcome-banner__panel-cta--text {
    font-size: 12px;
    color: rgba(255, 255, 255, .85);
    text-decoration: underline;
}
/* Message de repli du panneau Discord quand aucun widget n'est configuré (11/09/2026) — même
   situation que le message "non configuré" de public/discord.php, en plus compact pour ce panneau. */
.welcome-banner__panel-text {
    margin: 0 0 8px;
    font-size: 12px;
    line-height: 1.5;
    color: rgba(255, 255, 255, .75);
}
/* Iframe du widget Discord dans son panneau compact (11/09/2026) — hauteur fixe modeste (à la
   différence du widget en pleine taille de public/discord.php, `.discord-widget`, ceci n'est qu'un
   APERÇU au survol) : suffisante pour voir quelques membres connectés sans que le panneau ne devienne
   disproportionné à côté du badge qui le déclenche. */
.welcome-banner__panel--discord iframe {
    width: 100%;
    height: 260px;
    border: none;
}
/* Panneau AlsaéroVol nettement agrandi (11/09/2026, retour utilisateur après un premier test réel :
   "la minimap [...] est trop petite [...] genre prend l'ecran") — le panneau générique ci-dessus
   (260px, pensé pour un simple texte/iframe compact) reste la largeur par défaut pour un éventuel
   futur panneau plus modeste ; seul celui d'AlsaéroVol (`.welcome-banner__panel--map`, voir le
   `id="welcome-alsaerovol-panel"` dans index.php) prend ces dimensions bien plus généreuses. Toujours
   plafonné en `vw`/`vh` plutôt qu'en valeur fixe pour ne jamais déborder l'écran sur une fenêtre
   étroite, et toujours ANCRÉ au badge (`top: 100%`, sans marge, voir plus haut) : l'agrandir ne
   réintroduit pas le point mort du survol déjà corrigé, contrairement à un panneau qui aurait été
   recentré au milieu de l'écran (ce qui aurait, lui, cassé la continuité `:hover` badge → panneau).
   Repris automatiquement à 260px sous 480px de largeur de bannière par le `@container` plus bas (même
   règle `.welcome-banner__panel`, la spécificité identique + l'ordre du fichier la fait gagner) :
   cette taille XL ne concerne que les fenêtres suffisamment larges pour l'accueillir. */
.welcome-banner__panel--map {
    width: min(640px, 92vw);
}
/* Enveloppe de la mini carte (11/09/2026, nouvelle) — `position: relative` uniquement pour servir de
   repère au bouton "Agrandir" posé en incrustation dessus (`position: absolute`, voir plus bas) ;
   n'existait pas quand la carte était un simple aperçu sans rien au-dessus d'elle. */
.welcome-banner__mini-map-wrap {
    position: relative;
}
/* Conteneur de la mini carte Leaflet (AlsaéroVol) — hauteur fixe (Leaflet a besoin d'une taille
   réelle pour s'initialiser, voir assets/js/welcome-banner-badges.js), fond de repli identique à
   `.network-map`/`.fshub-map` (voir plus haut) le temps que les tuiles OpenStreetMap chargent.
   Agrandie le 11/09/2026 (voir le commentaire de `.welcome-banner__panel--map` ci-dessus) de 150px à
   une hauteur proportionnelle à l'écran. Le `cursor: pointer` posé brièvement le même jour (pour
   signaler que toute la carte naviguait vers reseau.php au clic) a été retiré aussitôt après, la
   carte étant devenue une VRAIE carte interactive (voir plus bas) : Leaflet applique déjà son propre
   curseur "main" (`.leaflet-grab`) quand le glisser est activé, `cursor: pointer` ici l'aurait
   contredit. */
.welcome-banner__mini-map {
    width: 100%;
    height: 150px;
    border-radius: 6px;
    background: #e9edf2;
}
.welcome-banner__panel--map .welcome-banner__mini-map {
    height: min(60vh, 520px);
}
/* Bouton "Agrandir" en incrustation sur la carte (11/09/2026, demande explicite : "il faudrais
   mettre sur cette carte un logo pour cliquez dessus pour l'ouvrir en grand") — coin haut-droit,
   opposé au bouton de zoom Leaflet (haut-gauche par défaut) et à l'attribution (bas-droite par
   défaut) pour ne chevaucher aucun des deux. `z-index` au-dessus des panes Leaflet (dont les
   contrôles plafonnent à 1000) pour rester cliquable en toute circonstance. */
.welcome-banner__mini-map-expand {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 1001;
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(11, 37, 69, .75);
    color: var(--vaa-white);
    border-radius: 6px;
    text-decoration: none;
    transition: background .2s ease, transform .2s ease;
}
.welcome-banner__mini-map-expand:hover {
    background: rgba(11, 37, 69, .95);
    transform: scale(1.08);
}
.welcome-banner__mini-map-expand svg { width: 16px; height: 16px; display: block; }

/* Sous une certaine largeur d'image (même seuil/mécanisme que `.welcome-banner__stat` plus haut,
   voir le `@container (max-width: 480px)` déjà existant) : le libellé texte du badge disparaît,
   l'icône seule suffit à un pouce sur un petit téléphone, et le panneau perd sa largeur fixe pour ne
   jamais dépasser la largeur de l'image elle-même. */
@container (max-width: 480px) {
    .welcome-banner__badge-label { display: none; }
    .welcome-banner__panel { width: min(260px, 100%); }
}

/* Ancien point de rupture mobile RETIRÉ le 08/09/2026 (demande explicite de l'utilisateur :
   "verouiller la taille des encadre par rapport au % de l'image [...] de façon à ce que sur PC et
   telephone nous avons le meme affichage") : l'incrustation basculait sous l'image en dessous de
   700px, avec un fond opaque distinct — exactement le genre d'affichage "différent selon l'appareil"
   que l'utilisateur demande maintenant d'éliminer. Les cadres restent DÉSORMAIS en incrustation à
   toute taille d'écran, dimensionnés en continu via `cqw` (voir `.welcome-banner-wrap` plus haut) —
   `flex-wrap: wrap` sur `.welcome-banner__stats` (ci-dessus) prend le relais si la largeur devient
   trop juste pour tenir sur une seule ligne (6 chiffres sur un très petit écran, par exemple) : les
   cadres passent alors naturellement sur 2 lignes, ancrées au même coin bas-droite, sans qu'aucune
   règle spécifique à une largeur d'écran ne soit nécessaire. */

/* Mise en page de l'accueil (historique : 28-29/08/2026, mise en page à 2 colonnes .home-layout/
   .home-main/.home-sidebar--right pour "Comment ça marche ?" + Discord — voir l'historique complet
   dans une révision antérieure de ce fichier si besoin). Retirée le 08/09/2026 : "Comment ça marche
   ?" a déménagé dans `.hero__cta` (voir index.php) et Discord — seul contenu restant sous le bandeau
   "Bienvenue" — n'a donc plus besoin d'une grille à 2 colonnes, une simple `.card` pleine largeur
   suffit désormais (comme les autres sections de la page) ; `.home-layout`/`.home-main`/
   `.home-sidebar`/`.home-sidebar--right` sont retirées ici, plus utilisées nulle part sur le site. */

/* Tableaux de statistiques de la page Statistiques (28/08/2026) : une carte par ligne, sur toute la
   largeur (28/08/2026, suite immédiate, demande explicite de l'utilisateur — "chaque statistique sur
   une ligne, un menu par ligne" — remplace une grille responsive à plusieurs colonnes par ligne
   utilisée pour cette même page jusqu'ici). Simple conteneur de flux : chaque `.card` garde son
   `margin` par défaut pour l'espacement vertical entre les cartes, `:first-child` remis à zéro pour
   ne pas ajouter d'espace superflu juste sous "Notre compagnie en quelques chiffres" au-dessus. */
.home-stats-grid .card:first-child {
    margin-top: 0;
}

@media (max-width: 600px) {
    .site-header__inner { flex-direction: column; align-items: flex-start; }
}

/* --- Mouvement & retour visuel (28/08/2026, "rendre le site plus dynamique") --- */
@keyframes vaaFadeInUp {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Rejoue à chaque fois qu'un bloc passe de display:none à visible (ex : bascule
   Ligne compagnie / Vol libre sur vols.php) — un changement de `display` relance
   toujours une animation CSS, aucun JS supplémentaire nécessaire. */
.fade-in-block {
    animation: vaaFadeInUp .25s ease both;
}

/* Toasts (voir assets/js/toast.js) : notifications posées après une action
   traitée en AJAX (ex : réserver/libérer un avion sur vols.php), en
   remplacement du bandeau .alert habituel qui suppose un rechargement de page. */
#toast-container {
    position: fixed;
    top: 16px;
    right: 16px;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 320px;
}
.toast {
    padding: 12px 16px;
    border-radius: var(--vaa-radius);
    box-shadow: var(--vaa-shadow);
    font-size: 14px;
    opacity: 0;
    transform: translateX(16px);
    transition: opacity .2s ease, transform .2s ease;
}
.toast.is-visible {
    opacity: 1;
    transform: translateX(0);
}
.toast--success { background: #e3f6e8; color: #1e6b3a; border: 1px solid #bfe8cb; }
.toast--error { background: #fdecec; color: #8a1220; border: 1px solid #f7c6c6; }
.toast--info { background: #e8f0fb; color: #13355e; border: 1px solid #c7d9f2; }

/* Effet 3D au défilement — page d'accueil uniquement (assets/js/scroll-reveal.js,
   28/08/2026, demande explicite de l'utilisateur). Posé par le script sur les
   sections sous la ligne de flottaison (pas sur .hero, déjà visible au
   chargement) : légère bascule en perspective + fondu, résolue dès que la
   section entre dans la zone visible au défilement. */
.scroll-reveal {
    opacity: 0;
    transform: perspective(1000px) rotateX(14deg) translateY(24px);
    transform-origin: center bottom;
    transition: opacity .6s ease, transform .6s cubic-bezier(0.22, 0.85, 0.32, 1.1);
    will-change: transform, opacity;
}
.scroll-reveal.is-revealed {
    opacity: 1;
    transform: perspective(1000px) rotateX(0deg) translateY(0);
}

/* Respecte la préférence système "mouvement réduit" : toutes les animations/
   transitions ajoutées ci-dessus (et les transitions hover plus haut dans ce
   fichier) sont neutralisées d'un coup plutôt que reprises une par une. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

/* --- Détail d'un vol FSHUB (public/vol-fshub.php, 03/09/2026) --- */

.checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 400;
    margin-top: 8px;
}
.checkbox-label input[type="checkbox"] { width: auto; }

.fshub-map {
    width: 100%;
    height: 360px;
    border-radius: var(--vaa-radius);
    /* Couleur de repli tant que les tuiles OpenStreetMap chargent (ou si le
       chargement échoue) : évite un rectangle blanc brut. */
    background: #e9edf2;
}

/* --- Carte du réseau (06/09/2026, remaniée le 10/09/2026 — livraison (182)) --- */
/* Même mécanique Leaflet que .fshub-map ci-dessus, mais plus haute : ici la
   carte EST le contenu principal de la page (public/reseau.php), pas une
   illustration secondaire au milieu d'un détail de vol. */
/* Disposition carte + panneau de détail (10/09/2026, demande explicite de l'utilisateur : "afficher
   sur la gauche type webeyes") — panneau AVANT la carte dans le DOM (voir reseau.php) pour qu'il
   apparaisse naturellement à gauche en `row`, sans dépendre d'un `order` CSS. Caché par défaut
   (attribut HTML `hidden`, aucune règle CSS dédiée nécessaire) : la carte occupe alors toute la
   largeur, le panneau ne prenant sa place qu'au clic sur un avion. */
.network-map-layout {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    flex-wrap: wrap;
}
.network-map {
    flex: 1 1 420px;
    min-width: 0;
    width: 100%;
    height: 520px;
    border-radius: var(--vaa-radius);
    background: #e9edf2;
}
/* Panneau de détail d'un vol sélectionné (10/09/2026, "type webeyes") — fond sombre volontairement
   distinct du reste du site (cartes blanches partout ailleurs) pour se démarquer comme un panneau
   d'instruments plutôt qu'une carte de contenu classique, à l'image de la référence fournie par
   l'utilisateur. */
.network-map__panel {
    flex: 0 0 300px;
    width: 300px;
    max-width: 100%;
    max-height: 520px;
    overflow-y: auto;
    background: var(--vaa-blue-900);
    color: var(--vaa-white);
    border-radius: var(--vaa-radius);
    box-shadow: var(--vaa-shadow);
    padding: 16px;
    box-sizing: border-box;
}
.network-map__panel-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
}
.network-map__panel-callsign { font-size: 20px; font-weight: 700; }
.network-map__panel-sub { font-size: 13px; color: rgba(255, 255, 255, .7); margin-top: 2px; }
.network-map__panel-close {
    background: transparent;
    border: none;
    color: var(--vaa-white);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 4px;
    flex-shrink: 0;
}
.network-map__panel-close:hover { background: rgba(255, 255, 255, .12); }
.network-map__panel-route {
    font-size: 15px;
    margin: 12px 0;
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.network-map__panel-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    margin: 12px 0;
}
.network-map__panel-tile {
    background: rgba(255, 255, 255, .08);
    border-radius: 6px;
    padding: 8px;
    text-align: center;
}
.network-map__panel-tile-value { font-size: 15px; font-weight: 700; }
.network-map__panel-tile-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: rgba(255, 255, 255, .65);
    margin-top: 2px;
}
.network-map__panel-section-title {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: rgba(255, 255, 255, .6);
    margin: 14px 0 4px;
}
.network-map__panel-text {
    font-size: 12px;
    line-height: 1.5;
    word-break: break-word;
    color: rgba(255, 255, 255, .85);
    margin: 0;
}
.network-map__panel-remarks {
    font-family: 'Courier New', monospace;
    font-size: 11px;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
    background: rgba(0, 0, 0, .2);
    border-radius: 6px;
    padding: 8px;
    max-height: 120px;
    overflow-y: auto;
    color: rgba(255, 255, 255, .85);
    margin: 0;
}
.network-map__legend {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    margin-top: 12px;
    font-size: 13px;
    color: var(--vaa-grey-500);
}
.network-map__legend-item { display: flex; align-items: center; gap: 6px; }
.network-map__dot {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    flex-shrink: 0;
}
.network-map__dot--hub { background: #0b2545; border: 2px solid #ffffff; box-shadow: 0 0 0 1px #0b2545; }
.network-map__dot--destination { background: #7ea6d1; border: 1px solid #1d4e89; }
/* Couleurs par état IVAO (`lastTrack.state`, 10/09/2026, demande explicite de l'utilisateur : "on
   affiche l'avion de differente couleurs selon [l'état]") — remplace l'unique point terracotta
   "pilote en vol" d'origine (06/09/2026), la carte affichant désormais tout pilote VAA connecté quel
   que soit son état. Ordre catégoriel fixe, jamais recalculé dynamiquement : chaque état garde
   toujours la même couleur, sur la carte comme dans la légende. `--state-departing` réutilise la
   teinte terracotta d'origine ("sur le point de partir"), `--state-climbing` le vert déjà utilisé
   pour la flotte "à son hub" (progression positive), `--state-enroute` le bleu de marque du site. */
.network-map__dot--state-ground { background: #6b7280; border: 1px solid #ffffff; box-shadow: 0 0 0 1px #6b7280; }
.network-map__dot--state-departing { background: #e2622b; border: 1px solid #ffffff; box-shadow: 0 0 0 1px #e2622b; }
.network-map__dot--state-climbing { background: #2f9e52; border: 1px solid #ffffff; box-shadow: 0 0 0 1px #2f9e52; }
.network-map__dot--state-enroute { background: #1d4e89; border: 1px solid #ffffff; box-shadow: 0 0 0 1px #1d4e89; }
.network-map__dot--state-approach { background: #7c5cbf; border: 1px solid #ffffff; box-shadow: 0 0 0 1px #7c5cbf; }
.network-map__dot--state-landed { background: #334155; border: 1px solid #ffffff; box-shadow: 0 0 0 1px #334155; }
.network-map__dot--state-unknown { background: #9aa5b1; border: 1px dashed #ffffff; }
/* Carte de la flotte sur public/flotte.php (07/09/2026, demande explicite de l'utilisateur : "un
   point vert" pour un avion sur son hub, "point bleu" hors de son hub, précisé ensuite "maintenance
   = rouge") — mêmes teintes que les badges de statut déjà utilisés ailleurs sur le site
   (.badge--active/.badge--approved pour le vert, .badge--suspended/.badge--rejected pour le rouge)
   plutôt que de nouvelles couleurs inédites. Le bleu "hors de son hub" réutilise directement
   .network-map__dot--destination ci-dessus, déjà exactement cette teinte. */
.network-map__dot--fleet-home { background: #2f9e52; border: 1px solid #1e6b3a; }
.network-map__dot--fleet-maintenance { background: #d64550; border: 1px solid #8a1220; }
/* Icône avion sur la carte du réseau (06/09/2026, demande explicite de l'utilisateur : "et mettre
   une icone d'avion plutot qu'un point") — annule le fond/bordure blancs par défaut de Leaflet sur
   un divIcon (.leaflet-div-icon), sans quoi l'avion apparaîtrait dans un carré blanc disgracieux. */
.network-map__plane-icon { background: transparent; border: none; }
/* Icône de position actuelle sur la carte des aéroports visités d'une fiche pilote (11-12/09/2026,
   demandes explicites successives de l'utilisateur — "tête de pilote", puis casquette, puis
   silhouette de personne : "du coup logo d'une personne en ombre" — voir pilotIcon() en JS,
   public/pilote.php, pour le détail du SVG final du marqueur) — même correctif que
   .network-map__plane-icon ci-dessus (annule le fond/bordure blancs par défaut de Leaflet sur un
   divIcon). Swatch de légende dessiné en pur CSS (disque + silhouette tête/buste), pour ne pas
   dupliquer le SVG inline du marqueur juste pour la légende. */
.network-map__pilot-icon { background: transparent; border: none; }
.network-map__pilot-icon-swatch {
    display: inline-block;
    position: relative;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #1d4e89;
    border: 1px solid #ffffff;
    box-shadow: 0 0 0 1px #1d4e89;
    flex-shrink: 0;
    overflow: hidden;
}
.network-map__pilot-icon-swatch::before {
    /* Tête */
    content: '';
    position: absolute;
    top: 2px;
    left: 5px;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: #0b2545;
}
.network-map__pilot-icon-swatch::after {
    /* Épaules/buste — grand cercle tronqué par `overflow: hidden` du swatch ci-dessus, même
       principe que le `clip-path` du SVG du marqueur. */
    content: '';
    position: absolute;
    bottom: -6px;
    left: -2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #0b2545;
}
.network-map__line-swatch {
    display: inline-block;
    width: 18px;
    height: 0;
    border-top: 2px solid #1d4e89;
    opacity: 0.55;
    flex-shrink: 0;
}
/* Trajectoire colorée par tendance d'altitude (10/09/2026, demande explicite de l'utilisateur :
   "au fur et a mesure que lavion prend ou perd de l'altitude ... changement de couleur du trait de
   suivi") — un segment par paire de points consécutifs (voir reseau.php), coloré selon que l'avion
   montait, descendait, ou restait globalement stable entre les deux. Réutilise volontairement les
   mêmes teintes que les états ci-dessus (vert = montée/Climbing, bleu = croisière/En Route) plutôt
   que d'inventer une troisième palette. */
.network-map__legend-item .network-map__line-swatch--climb { border-top-color: #2f9e52; opacity: 1; }
.network-map__legend-item .network-map__line-swatch--descend { border-top-color: #d9822b; opacity: 1; }
.network-map__legend-item .network-map__line-swatch--level { border-top-color: #1d4e89; opacity: 1; }
@media (max-width: 700px) {
    .network-map-layout { flex-direction: column; }
    .network-map__panel { width: 100%; flex-basis: auto; max-height: 280px; }
}
/* Widget Discord sur sa propre page (public/discord.php, 10/09/2026) — auparavant contraint par la
   mise en page à 2 colonnes de l'accueil (max 350px de large, 700px de haut), désormais plus grand
   maintenant que la page lui est entièrement dédiée. Largeur plafonnée volontairement (contrairement
   à `.network-map` qui occupe tout l'espace disponible) : le widget officiel Discord est une liste
   verticale de membres, l'étirer sur toute la largeur d'une carte laisserait un vide disgracieux de
   part et d'autre plutôt que d'apporter du contenu utile. */
.discord-widget {
    width: 100%;
    max-width: 480px;
    margin: 0 auto;
}
.discord-widget iframe {
    display: block;
    width: 100%;
    height: 600px;
    border: none;
    border-radius: var(--vaa-radius);
}
/* Rendu du contenu d'une page du mini-CMS (07/09/2026, voir public/page.php/App\MarkdownLite) —
   simple espacement typographique, aucune règle générique h2/h3/p/ul/ol n'existant ailleurs dans ce
   fichier (chaque page du site structure plutôt son contenu en tableaux/tuiles) : sans ces règles,
   le contenu d'une page (règlement, mentions légales...) serait affiché sans aucun espacement entre
   paragraphes/titres/listes, illisible pour un texte long. Volontairement scopé à `.page-content`
   plutôt que posé sur les éléments globalement, pour ne rien changer ailleurs sur le site. */
.page-content > *:first-child { margin-top: 0; }
.page-content > *:last-child { margin-bottom: 0; }
.page-content h2, .page-content h3, .page-content h4 { color: var(--vaa-blue-900); margin: 1.5em 0 0.5em; }
.page-content p { margin: 0 0 1em; line-height: 1.6; }
.page-content ul, .page-content ol { margin: 0 0 1em; padding-left: 1.5em; line-height: 1.6; }
.page-content li { margin-bottom: 0.35em; }
.page-content a { color: var(--vaa-blue-900); }
/* Balises supplémentaires possibles depuis le passage à l'éditeur WYSIWYG (TinyMCE, 07/09/2026,
   voir App\HtmlSanitizer) : images, tableaux, citations — absentes de la syntaxe Markdown-lite
   d'origine, jamais stylées ici jusqu'à présent. */
.page-content img { max-width: 100%; height: auto; border-radius: var(--vaa-radius); margin: 0 0 1em; }
.page-content blockquote {
    margin: 0 0 1em;
    padding: 4px 16px;
    border-left: 3px solid var(--vaa-grey-200);
    color: var(--vaa-grey-500);
}
.page-content hr { border: none; border-top: 1px solid var(--vaa-grey-200); margin: 1.5em 0; }
.page-content table { width: 100%; border-collapse: collapse; margin: 0 0 1em; }
.page-content th, .page-content td { border: 1px solid var(--vaa-grey-200); padding: 8px 10px; text-align: left; }
.page-content th { background: var(--vaa-grey-100); }

/* Grille de vignettes pour le système de téléchargements (public/telechargements.php, voir
   migration_042) — 07/09/2026, demande explicite de l'utilisateur : "systeme de telechargement
   [...] avec possibilité de mettre des illustration en image [...] type cms egalement e107 par
   exemple". Nouveau pattern de grille avec vignette d'illustration, aucun équivalent existant sur
   le site (les autres listes publiques du site — hubs, pilotes... — sont des tableaux) : une
   illustration a besoin de place pour être lisible, un tableau ne convenait pas. `.download-card`
   réutilise `.card`'s ombre/rayon implicitement via `--vaa-shadow`/`--vaa-radius` pour rester
   cohérent visuellement sans dupliquer `.card` elle-même (pas de padding identique : le visuel
   "vignette pleine largeur en haut, texte en dessous" diffère d'une carte classique). */
.downloads-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 20px;
    margin-top: 16px;
}
.download-card {
    display: flex;
    flex-direction: column;
    background: var(--vaa-grey-100);
    border: 1px solid var(--vaa-grey-200);
    border-radius: var(--vaa-radius);
    overflow: hidden;
}
.download-card__thumb {
    aspect-ratio: 16 / 9;
    background: var(--vaa-white);
    display: flex;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid var(--vaa-grey-200);
}
.download-card__thumb img { width: 100%; height: 100%; object-fit: cover; }
.download-card__thumb-icon { width: 42px; height: 42px; color: var(--vaa-grey-500); }
.download-card__thumb-icon svg { width: 100%; height: 100%; display: block; }
.download-card__body { padding: 16px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.download-card__body h3 { margin: 0; color: var(--vaa-blue-900); font-size: 1rem; }
.download-card__description { margin: 0; font-size: 13px; color: var(--vaa-grey-800); line-height: 1.5; }
.download-card__meta { margin: 0; font-size: 12px; color: var(--vaa-grey-500); }
.download-card__body .button { margin-top: auto; align-self: flex-start; }

/* Liste d'articles d'une catégorie AlsaéroWiki (public/wiki.php, voir migration_053, 12/09/2026) —
   simple liste de liens par catégorie, plus légère qu'une grille de vignettes (.downloads-grid
   ci-dessus) : un article n'a pas d'illustration, juste un titre. */
.wiki-article-list { list-style: none; margin: 16px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.wiki-article-list li { border-bottom: 1px solid var(--vaa-grey-200); padding-bottom: 8px; }
.wiki-article-list li:last-child { border-bottom: none; padding-bottom: 0; }
.wiki-article-list a { font-weight: 600; }

.fshub-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 16px;
}
.fshub-stat {
    min-width: 120px;
    padding: 12px 16px;
    background: #f4f7fb;
    border-radius: var(--vaa-radius);
}
.fshub-stat__value {
    font-size: 22px;
    font-weight: 700;
    color: var(--vaa-blue-900);
}
.fshub-stat__label {
    font-size: 13px;
    color: var(--vaa-grey-500);
}

.fshub-airports {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
}
@media (max-width: 700px) {
    .fshub-airports { grid-template-columns: 1fr; }
}

.fshub-detail-list {
    margin: 8px 0 0;
    padding-left: 18px;
    font-size: 14px;
    color: var(--vaa-grey-500);
}

/* Commentaires OurAirports sur hub.php (05/09/2026, demande explicite : "afficher le maximum
   d'information sur les hubs") — liste simple plutôt qu'un tableau, le corps d'un commentaire
   pouvant faire plusieurs paragraphes. */
.airport-comments {
    list-style: none;
    margin: 0;
    padding: 0;
}
.airport-comments__item {
    padding: 12px 0;
    border-bottom: 1px solid var(--vaa-grey-200);
}
.airport-comments__item:last-child {
    border-bottom: none;
}
.airport-comments__meta {
    margin: 0 0 4px;
}
.airport-comments__subject {
    margin: 0 0 4px;
}
.airport-comments__body {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.fshub-detail-list li { margin-bottom: 4px; }
