/* ============================================================================
   VENTILO.IO - COUCHE 4/4 : PAGES
   ----------------------------------------------------------------------------
   Compositions qui n'existent que sur une page. Rien ici n'est un composant du
   design system : si un bloc de ce fichier finit par servir sur une deuxième
   page, il remonte dans components.css et perd son préfixe de page.

   Ordre : /etudiant/ - /decouvrir/ - /configuration/ - /tarifs/
   ========================================================================== */


/* ══════════════════════════════════════════════════════════════════════════
   /etudiant/ - CHRONOLOGIE
   ══════════════════════════════════════════════════════════════════════════ */
.vs-timeline { max-width: 52rem; margin-inline: auto; }
.vs-timeline__step { position: relative; }

/* Le filet vertical relie une étape à la suivante. La dernière ne le porte
   pas, sinon le trait dépasse dans le vide. */
.vs-timeline__step--linked::before {
  content: '';
  position: absolute;
  left: 41px;
  top: 40px;
  bottom: 4px;
  width: 2px;
  background: var(--v-border);
}
.vs-timeline__when {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 84px;
  height: 34px;
  border-radius: var(--v-radius-pill);
  background: var(--v-secondary);
  color: var(--v-on-dark);
  font-size: 0.78rem;
  font-weight: var(--v-weight-bold);
}
@media (max-width: 575.98px) {
  .vs-timeline__step { flex-direction: column; gap: var(--v-space-2) !important; }
  .vs-timeline__step--linked::before { display: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   /decouvrir/ - SIMULATEUR DE CAS
   ══════════════════════════════════════════════════════════════════════════
   Panneau de choix à gauche, résultat à droite. Le panneau reste collé au
   défilement sur grand écran ; sous 900 px tout repasse en colonne. */
.vs-sim {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: 1.75rem;
  align-items: start;
}
@media (max-width: 900px) { .vs-sim { grid-template-columns: 1fr; } }

.vs-sim__panel {
  position: sticky;
  top: 90px;
  padding: 1.75rem;
  border: 0;
  border-radius: var(--v-radius-lg);
  background: var(--v-surface);
  box-shadow: none;
}
@media (max-width: 900px) { .vs-sim__panel { position: static; } }

.vs-sim__field { margin-bottom: 1.4rem; }
.vs-sim__field:last-child { margin-bottom: 0; }

.vs-sim__label {
  display: block;
  margin-bottom: 0.7rem;
  font-size: var(--v-text-label);
  font-weight: var(--v-weight-bold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--v-secondary);
}

.vs-sim__options { display: flex; flex-wrap: wrap; gap: var(--v-space-2); }

/* Choix. Sélectionné, il est plein : l'état ne repose pas sur la seule teinte,
   le contraste fond/texte s'inverse franchement. */
.vs-sim__pill {
  padding: var(--v-space-2) var(--v-space-4);
  border: 1px solid var(--v-border);
  border-radius: var(--v-radius-pill);
  background: var(--v-surface);
  color: var(--v-text);
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: var(--v-weight-semibold);
  line-height: 1.2;
  cursor: pointer;
  transition: background-color var(--v-duration-1) var(--v-ease),
              border-color var(--v-duration-1) var(--v-ease),
              color var(--v-duration-1) var(--v-ease);
}
.vs-sim__pill:hover { border-color: var(--v-primary); color: var(--v-primary); }
.vs-sim__pill.is-active {
  background: var(--v-primary);
  border-color: var(--v-primary);
  color: var(--v-on-dark);
}
/* En choix multiple l'état actif est plus doux : plusieurs pleins côte à côte
   deviennent illisibles. */
.vs-sim__options--multi .vs-sim__pill.is-active {
  background: var(--v-primary-bg);
  border-color: var(--v-primary);
  color: var(--v-primary);
}

.vs-sim__result { min-width: 0; }
.vs-sim__summary {
  display: flex;
  align-items: center;
  gap: var(--v-space-2);
  margin-bottom: 1.4rem;
  color: var(--v-primary);
  font-weight: var(--v-weight-bold);
}
.vs-sim__phase {
  position: relative;
  margin-bottom: 1.6rem;
  padding-left: var(--v-space-6);
  border-left: 2px solid var(--v-border);
}
.vs-sim__phase:last-child { margin-bottom: 0; }
.vs-sim__phase-label {
  display: inline-block;
  margin-bottom: 0.7rem;
  font-size: 0.7rem;
  font-weight: var(--v-weight-black);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--v-muted);
}
.vs-sim__step { margin-bottom: 1.15rem; }
.vs-sim__step:last-child { margin-bottom: 0; }
.vs-sim__step-title { margin: 0 0 var(--v-space-1); font-size: var(--v-text-body); font-weight: var(--v-weight-bold); color: var(--v-secondary); }
.vs-sim__step-desc  { margin: 0 0 0.55rem; color: var(--v-muted); font-size: 0.9rem; line-height: 1.5; }
.vs-sim__chips { display: flex; flex-wrap: wrap; gap: 0.35rem; }


/* ══════════════════════════════════════════════════════════════════════════
   /configuration/ - QUESTIONNAIRE
   ══════════════════════════════════════════════════════════════════════════ */
.vs-cfg__progress {
  height: 6px;
  border-radius: var(--v-radius-pill);
  background: var(--v-border);
  overflow: hidden;
}
.vs-cfg__progress span {
  display: block;
  height: 100%;
  background: var(--v-primary);
  transition: width var(--v-duration-3) var(--v-ease);
}

/* Réponse. Bordure conservée : c'est un contrôle cliquable, pas une carte de
   contenu, et son bord dit où finit la zone de clic. */
.vs-cfg__option {
  padding: 0.85rem var(--v-space-4);
  border: 1px solid var(--v-border);
  /* Rayon d'une commande et non celui d'un bloc : c'est un controle cliquable
     (user, 04/09/2026). Taille normale : sa hauteur vient de son texte, pas
     d'un gabarit de bouton. */
  border-radius: var(--v-radius-btn);
  background: var(--v-surface);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--v-duration-1) var(--v-ease),
              background-color var(--v-duration-1) var(--v-ease);
}
.vs-cfg__option:hover { border-color: var(--v-primary); background: var(--v-bg); }

.vs-cfg__step { position: relative; }
.vs-cfg__when {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 76px;
  height: 30px;
  padding-inline: var(--v-space-2);
  border-radius: var(--v-radius-pill);
  background: var(--v-secondary);
  color: var(--v-on-dark);
  font-size: 0.72rem;
  font-weight: var(--v-weight-bold);
  white-space: nowrap;
}
.vs-cfg__when--plain {
  min-width: 30px;
  background: var(--v-primary-bg);
  color: var(--v-primary);
}
.vs-cfg__tool {
  display: inline-block;
  padding: var(--v-space-1) 0.65rem;
  border-radius: var(--v-radius-pill);
  background: var(--v-primary-bg);
  color: var(--v-primary);
  font-size: 0.72rem;
  font-weight: var(--v-weight-semibold);
  text-decoration: none;
}
.vs-cfg__tool:hover { color: var(--v-primary-hover); }

.vs-cfg__notes { padding: 0.9rem var(--v-space-4); border-radius: var(--v-radius-sm); background: var(--v-bg); }
.vs-cfg__plan  { padding: 0.9rem var(--v-space-4); border-radius: var(--v-radius-sm); background: var(--v-success-bg); }


/* ══════════════════════════════════════════════════════════════════════════
   /tarifs/ - GRILLE DES PLANS
   ══════════════════════════════════════════════════════════════════════════ */
/* PLAN MIS EN AVANT. Ni ombre ni bordure - le site n'en a pas : c'est un
   LISERE interieur qui detoure la carte sans ajouter de relief. En OR, comme
   l'etiquette qu'il encadre (user, 04/09/2026) : le liseré et l'etiquette
   disent la meme chose, ils n'ont pas a le dire dans deux couleurs.

   L'or VIF et non l'or sombre : un trait n'a pas a etre lisible comme du
   texte, il a a se voir. */
.vs-plan--phare {
  box-shadow: inset 0 0 0 2px var(--v-gold);
}

/* Les deux autres plans s'arretent sur LEUR contenu. .vs-card porte un
   height:100% qui alignait les trois cartes sur la plus haute : elles gagnaient
   donc, en vide, la hauteur de l'etiquette doree. Sans lui, elles s'arretent
   exactement 37 px plus haut - l'etiquette et sa marge - et la carte du milieu
   depasse, ce qui la designe une deuxieme fois sans rien ajouter. */
[data-plan-card]:not(.vs-plan--phare) { height: auto; }

/* MENTION ETUDIANTE, en etiquette en haut de carte. Aplat dore et texte en or
   sombre - le meme couple aplat / encre que les etats du site, ici applique a
   l'or. Pas de degrade decoupe dans le texte comme dans l'en-tete : sur un
   aplat, un texte plein se lit mieux qu'un texte a couleur variable. */
.vs-plan__etudiant {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 var(--v-space-3);
  padding: 0.25rem var(--v-space-3);
  border-radius: var(--v-radius-pill);
  background: var(--v-gold-bg);
  color: var(--v-gold-ink);
  font-size: var(--v-text-sm);
  font-weight: var(--v-weight-bold);
  line-height: var(--v-lh-snug);
  text-decoration: none;
}
.vs-plan__etudiant .vs-ico { color: var(--v-gold); font-size: 1.05em; }
.vs-plan__etudiant:hover { color: var(--v-gold-ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.2em; }

.vs-plan__amount {
  font-size: var(--v-space-10);
  font-weight: var(--v-weight-black);
  letter-spacing: var(--v-tracking-h2);
  color: var(--v-secondary);
}
.vs-plan__rows li {
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  padding-block: 0.3rem;
  font-size: 0.9rem;
  color: var(--v-text);
}
.vs-plan__rows li .vs-ico { flex-shrink: 0; color: var(--v-success-ink); }

/* Rubrique absente du plan. Elle reste lisible : une ligne grisée au point
   d'être illisible ne renseigne plus sur ce qu'on n'a pas. */
.vs-plan__row--off { color: var(--v-muted); }
.vs-plan__row--off .vs-ico { color: var(--v-border); }

.vs-plan__note { margin-top: 0.6rem; color: var(--v-pink-ink); font-size: 0.72rem; }


/* ══════════════════════════════════════════════════════════════════════════
   /design-system/ - STYLEGUIDE
   ══════════════════════════════════════════════════════════════════════════
   Documentation vivante : elle utilise le CSS du site, donc elle ne peut pas
   se désynchroniser de lui. Page noindex, absente du sitemap.
   Ces classes ne servent QUE sur cette page. */
.vs-ds__toc {
  display: flex;
  flex-wrap: wrap;
  gap: var(--v-space-2);
  padding: 0;
  margin: 0;
  list-style: none;
}
.vs-ds__toc a {
  display: inline-block;
  padding: var(--v-space-2) var(--v-space-4);
  border-radius: var(--v-radius-pill);
  background: var(--v-bg);
  color: var(--v-secondary);
  font-size: 0.85rem;
  font-weight: var(--v-weight-semibold);
  text-decoration: none;
}
.vs-ds__toc a:hover { background: var(--v-primary-bg); color: var(--v-primary); }

/* Un bloc de doc = le rendu réel, puis le balisage à recopier. */
.vs-ds__block { margin-bottom: var(--v-space-16); }
.vs-ds__block > h3 { margin-bottom: var(--v-space-2); }
.vs-ds__note { max-width: var(--v-measure); color: var(--v-muted); margin-bottom: var(--v-space-5); }

.vs-ds__demo {
  padding: var(--v-space-8);
  border-radius: var(--v-radius-lg) var(--v-radius-lg) 0 0;
  background: var(--v-bg);
}
/* Certains composants ne se lisent que sur blanc : la variante inverse le fond
   du bac de démonstration. */
.vs-ds__demo--white { background: var(--v-surface); box-shadow: inset 0 0 0 1px var(--v-border); }
.vs-ds__demo--dark  { background: var(--v-secondary); }

.vs-ds__code {
  margin: 0 0 var(--v-space-6);
  padding: var(--v-space-5) var(--v-space-6);
  border-radius: 0 0 var(--v-radius-lg) var(--v-radius-lg);
  background: var(--v-secondary);
  color: #cdd3de;
  font-size: 0.8rem;
  line-height: 1.7;
  overflow-x: auto;
  tab-size: 2;
}
.vs-ds__code code { color: inherit; white-space: pre; }

/* Nuancier. */
.vs-ds__swatches {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--v-space-4);
}
.vs-ds__swatch { border-radius: var(--v-radius-md); overflow: hidden; background: var(--v-surface); }
.vs-ds__swatch-chip { height: 76px; }
.vs-ds__swatch-meta { padding: var(--v-space-3) var(--v-space-4); }
.vs-ds__swatch-meta code { display: block; color: var(--v-secondary); font-size: 0.78rem; font-weight: var(--v-weight-bold); }
.vs-ds__swatch-meta small { color: var(--v-muted); font-size: 0.72rem; }

/* Échelles (rayons, espacements). */
.vs-ds__scale { display: flex; flex-wrap: wrap; gap: var(--v-space-6); align-items: flex-end; }
.vs-ds__scale-item { text-align: center; }
.vs-ds__scale-box { background: var(--v-primary-bg); border: 2px solid var(--v-primary); }
.vs-ds__scale-item code { display: block; margin-top: var(--v-space-2); font-size: 0.72rem; color: var(--v-muted); }

/* Tableau des règles. */
.vs-ds__rules { width: 100%; border-collapse: collapse; }
.vs-ds__rules th,
.vs-ds__rules td { padding: var(--v-space-3) var(--v-space-4); text-align: left; vertical-align: top; border-bottom: 1px solid var(--v-border); }
.vs-ds__rules th { font-size: var(--v-text-label); text-transform: uppercase; letter-spacing: var(--v-tracking-label); color: var(--v-muted); }
.vs-ds__rules td:first-child { width: 42%; font-weight: var(--v-weight-semibold); color: var(--v-secondary); }
.vs-ds__yes { color: var(--v-success-ink); font-weight: var(--v-weight-bold); }
.vs-ds__no  { color: var(--v-error-ink);   font-weight: var(--v-weight-bold); }



/* ══════════════════════════════════════════════════════════════════════════
   ACCUEIL - SECTION « UN ÉCOSYSTÈME, UN COMPTE »
   ══════════════════════════════════════════════════════════════════════════
   Sur bureau : le visuel occupe la colonne de droite, les deux cartes sont
   empilées dans celle de gauche et calées EN BAS de la rangée. align-items:end
   suffit : la hauteur de la rangée est donnée par le visuel, les cartes s'y
   accrochent par le bas au lieu de partir du haut.

   Le visuel est écrit en PREMIER dans le HTML : c'est l'ordre de lecture voulu
   sur mobile, où tout s'empile. Sur bureau, grid-column le renvoie à droite
   sans toucher au balisage. */
.vs-eco {
  display: grid;
  gap: var(--v-space-6);
}
.vs-eco__cards {
  display: flex;
  flex-direction: column;
  gap: var(--v-space-4);
}

@media (min-width: 992px) {
  /* Le visuel occupe la colonne de GAUCHE, plus large, et deborde par la
     droite : il passe donc SUR les cartes. Il est au premier plan, sinon elles
     le rogneraient. Le fichier porte 18,8 % de vide transparent a droite,
     c'est ce qui absorbe le recouvrement sans que le portable ne touche le
     texte des cartes. */
  .vs-eco {
    grid-template-columns: 6fr 6fr;
    gap: var(--v-space-8);
    align-items: end;
    /* Le bloc sort du conteneur par la GAUCHE et va au bord de l'ecran.
       50% = la moitie du conteneur, 50vw = la moitie de l'ecran : la
       difference vaut exactement la marge de page, quelle que soit sa
       largeur. Le bord droit, lui, ne bouge pas. */
    margin-left: calc(50% - 50vw);
  }
  .vs-eco__media {
    grid-column: 1;
    grid-row: 1;
    position: relative;
    z-index: var(--v-z-raised);
    /* Le visuel est CENTRE verticalement sur la hauteur de la rangee (donc par
       rapport a la colonne des deux cartes), au lieu d'etre cale en bas comme
       le veut align-items:end sur .vs-eco. */
    align-self: center;
    margin-right: calc(-1 * var(--v-space-24));
    /* COMPENSATION DU VIDE TRANSPARENT (horizontal). Le fichier n'est pas
       detoure au ras : il porte 4,4 % de vide a gauche. Sans correction le
       portable flotte a 37 px du bord. Cette marge negative ramene son bord
       VISIBLE sur celui du conteneur ; le pourcentage se resout sur la largeur,
       il suit donc la taille du bloc. (La compensation basse -5.7 % n'a plus
       lieu d'etre : elle servait au calage en bas.) */
    margin-left: -5%;
  }
  .vs-eco__cards {
    grid-column: 2;
    grid-row: 1;
    /* Les cartes sont calees en bas de la rangee par align-items:end ; une
       marge basse POSITIVE les fait donc remonter. Leur bas n'est plus aligne
       sur celui du portable, c'est voulu. */
    margin-bottom: var(--v-space-8);
  }
}

/* Entre 992 et 1200 px le conteneur se resserre : a debordement constant, le
   portable finirait par mordre sur le texte des cartes. On reduit d'autant. */
@media (min-width: 992px) and (max-width: 1399.98px) {
  .vs-eco__media { margin-right: calc(-1 * var(--v-space-10)); }
}


/* ══════════════════════════════════════════════════════════════════════════
   /nouveautes/ - JOURNAL DES LANCEMENTS
   ══════════════════════════════════════════════════════════════════════════
   Une liste ordonnee, la plus recente en haut. La date est SORTIE de la carte
   et posee au-dessus : on parcourt la colonne des dates du regard, sans avoir
   a entrer dans chaque bloc. */
.vs-news { padding: 0; margin: 0; list-style: none; }
.vs-news__item + .vs-news__item { margin-top: var(--v-space-8); }
.vs-news__date {
  display: block;
  margin-bottom: var(--v-space-2);
  color: var(--v-muted);
  font-size: var(--v-text-sm);
  font-weight: var(--v-weight-semibold);
  letter-spacing: var(--v-tracking-label);
  text-transform: uppercase;
}


/* ══════════════════════════════════════════════════════════════════════════
   AUTOCOLLANT (accroche de /etudiant/)
   ══════════════════════════════════════════════════════════════════════════
   Un mot du titre pose de travers, comme une etiquette collee a la main. Aplat
   blanc sur la photo sombre du hero : l'etiquette est le seul bloc clair du
   titre, c'est elle qui arrete l'oeil.

   Trois precautions :
   - inline-block, sinon la rotation ne s'applique pas a un element en ligne ;
   - un padding en em et non en px, pour que l'etiquette suive la taille du
     titre, qui est fluide (clamp) ;
   - la rotation se fait autour du BAS GAUCHE : autour du centre, le mot
     remonterait a droite et casserait la ligne de base du titre. */
.vs-sticker {
  display: inline-block;
  padding: 0.06em 0.34em 0.1em;
  border-radius: var(--v-radius-md);
  /* Fond BLANC ici, degrade d'or sur le MOT, porte par un .vs-or a l'interieur.
     Les deux ne peuvent pas vivre sur le meme element : background-clip:text
     decoupe TOUS les fonds de la boite, donc l'aplat blanc disparaitrait avec.
     D'ou l'etiquette qui porte la plaque, et le span qui porte l'encre. */
  background: var(--v-surface);
  transform: rotate(-2deg) translateY(0.12em);
  transform-origin: 0 100%;
}
/* Ecart avant la plaque, sur grand ecran seulement (user, 04/09/2026) :
   l'etiquette y suit le mot precedent sur la meme ligne, et son retrait interne
   blanc collait au dernier caractere. En em, donc proportionnel au corps du
   titre.
   Sous 768px le mot est seul sur sa ligne : il n'y a rien a ecarter, et une
   marge gauche l'y decalerait hors de son centrage. */
@media (min-width: 768px) {
  .vs-sticker { margin-left: 0.2em; }
}


/* ══════════════════════════════════════════════════════════════════════════
   /fonctionnalites/ - VISUEL DE FICHE
   ══════════════════════════════════════════════════════════════════════════
   Le visuel ferme la page et TOUCHE le bandeau d'appel a l'action : aucune
   marge basse, les deux blocs se lisent comme un seul pied de page. Les coins
   bas restent arrondis, c'est ce qui evite l'impression d'une image coupee.

   Le format portrait est BORNE et centre : etale sur les 1296 px du conteneur,
   une maquette de telephone ferait plus de deux ecrans de haut. */
.vs-feature-visuel { margin-bottom: 0; }
.vs-feature-visuel--portrait { max-width: 24rem; margin-inline: auto; }

/* ══════════════════════════════════════════════════════════════════════════
   /fonctionnalites/ - ILLUSTRATION DU TITRE
   ══════════════════════════════════════════════════════════════════════════
   L'illustration suit la taille du titre qu'elle accompagne : celui d'une fiche
   fait 38 px, contre 20 px pour le titre d'une carte de /decouvrir/. Une meme
   valeur pour les deux laisserait l'icone perdue a cote du grand titre.
   Selecteur sur h1 : seul le titre de page est concerne, les cartes gardent
   leur icone de 2,75rem. */
h1.vs-card__head .vs-card__icon {
  width: 4.5rem;
  height: 4.5rem;
}


/* ══════════════════════════════════════════════════════════════════════════
   /etudiant/app/ - HERO : CONTENU DE /etudiant/ CENTRE, TELEPHONE DESSOUS
   ══════════════════════════════════════════════════════════════════════════
   Page reprise de zero (user, 13/09/2026). Sur un fond de CIEL CLAIR, une
   seule colonne a toutes les largeurs : le contenu du hero de /etudiant/ a
   l'identique (titre a autocollant, chapeau, deux actions), centre, puis le
   telephone tenu en main, centre dessous et qui touche le bas du hero. La
   version en deux colonnes a ete essayee puis abandonnee (user, 13/09/2026). Les composants (.vs-hero__content, __lead, __cta, .vs-sticker,
   .vs-btn-partner) sont ceux de /etudiant/ ; ce bloc ne regle que ce qui
   change sur fond clair et la mise en colonnes. */
.vs-hero--light {
  color: var(--v-text);
  background-color: var(--v-surface);
  text-align: center;
  /* Pas de marge basse : le telephone est la derniere chose du hero, la main
     est coupee net par la section qui suit. */
  padding-bottom: 0;
}
.vs-hero--light h1 { color: var(--v-secondary); }
/* MARGE SOUS L'EN-TETE SUR MOBILE (user, 13/09/2026). .vs-hero--full reserve la
   hauteur de l'en-tete en haut du hero, mais sous 992 px une regle de
   components.css (« .vs-hero { padding-top: --v-space-14 } », placee apres et
   de meme specificite) l'ecrase : le titre remontait sous l'en-tete
   transparent. Sur /etudiant/ cela ne se voit pas, le contenu y est centre
   sur la hauteur de l'ecran ; ici il est plus haut que l'ecran et part du
   haut. On remet la meme reserve qu'au-dessus de 992 px : l'ecart de section
   plus la hauteur reelle de l'en-tete (ecrite par le script du pied de page). */
@media (max-width: 991.98px) {
  .vs-hero--full.vs-hero--light {
    padding-top: calc(var(--v-section-y) + var(--v-header-h));
  }
}
/* Le ciel de fond est une .vs-hero__media (absolue, plan de base) : le contenu
   passe au-dessus. Le fond blanc de la section reste en repli tant que l'image
   n'est pas arrivee. */
.vs-hero--light > .container {
  position: relative;
  z-index: var(--v-z-content);
}
/* L'anneau blanc du hero sombre (base.css) disparaitrait sur le ciel clair : on
   revient a l'anneau violet de tout le site. */
.vs-hero--light :focus-visible { outline-color: rgba(var(--bs-primary-rgb), .35); }

/* Le bloc de texte se centre (le .vs-hero__content porte une largeur max, il
   faut donc aussi centrer la boite). Le chapeau garde le gris lisible sur fond clair (le blanc casse du
   hero sombre y disparaitrait). */
.vs-hero--light .vs-hero__content { margin-inline: auto; }
.vs-hero--light .vs-hero__lead {
  color: var(--v-muted);
  margin-inline: auto;
}

/* CHAMP + BOUTON (user, 13/09/2026) : une seule barre blanche posee sur le ciel,
   le champ « Nom de mon app » a gauche, « Commencer » aligne a droite dans la
   meme barre. Barre sans bordure ni ombre (DA du site) : c'est son aplat blanc
   qui la detache du ciel.
   Rayon CONCENTRIQUE : celui du bouton plus l'ecart qui l'entoure, pour que les
   deux arrondis restent paralleles. 34rem de large au plus, pleine largeur sur
   telephone ; le bouton ne se comprime jamais, c'est le champ qui cede. */
.vs-app-hero__form {
  display: flex;
  align-items: center;
  gap: var(--v-space-2);
  width: 100%;
  max-width: 34rem;
  margin-inline: auto;
  padding: var(--v-space-2);
  border-radius: calc(var(--v-radius-btn-lg) + var(--v-space-2));
  background-color: var(--v-surface);
  transition: background-color var(--v-duration-2) var(--v-ease);
}
/* VERRE DEPOLI AU REPOS (user, 13/09/2026) : tant que le champ n'a pas le
   focus, la barre est un blanc a 55 % sur un flou du ciel, qui la fond tres
   subtilement dans le fond. Au clic (focus dans le formulaire, champ OU
   bouton), elle redevient blanc plein : c'est le moment ou il faut lire ce
   qu'on tape.
   Blanc plein ecrit juste au-dessus en repli : un navigateur sans color-mix()
   garde la barre opaque. Sans flou non plus (backdrop-filter absent), le blanc
   a 55 % reste lisible sur ce ciel clair. Qui demande moins de transparence
   au systeme retrouve le blanc plein. */
.vs-app-hero__form:not(:focus-within) {
  background-color: color-mix(in srgb, var(--v-surface) 55%, transparent);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  backdrop-filter: blur(12px) saturate(140%);
}
@media (prefers-reduced-transparency: reduce) {
  .vs-app-hero__form:not(:focus-within) {
    background-color: var(--v-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
.vs-app-hero__form .btn { flex-shrink: 0; }
/* Tuile « icone de l'app », avant le champ : un carre de la hauteur du bouton,
   rayon du bouton, aplat et pictogramme de la pastille violette du site
   (.vs-icon). Elle ne se comprime jamais, c'est le champ qui cede. */
.vs-app-hero__icone {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--v-btn-h-lg);
  height: var(--v-btn-h-lg);
  border-radius: var(--v-radius-btn-lg);
  background: var(--v-primary-bg);
  color: var(--v-primary);
  font-size: 1.5rem;
}
/* Le champ se fond dans la barre : pas de fond ni de bordure propres. Corps de
   16 px au moins, sinon Safari iOS zoome sur la page a la saisie. L'anneau de
   focus du site (base.css) reste celui du champ, on ne le neutralise pas. */
.vs-app-hero__champ {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--v-btn-h-lg);
  padding-inline: var(--v-space-4);
  border: 0;
  border-radius: var(--v-radius-btn-lg);
  background: transparent;
  color: var(--v-text);
  font-size: var(--v-text-body);
  font-weight: var(--v-weight-medium);
}
.vs-app-hero__champ::placeholder { color: var(--v-muted); opacity: 1; }
/* Petit telephone : tuile + champ + bouton se partagent ~336 px. Le champ perd
   son retrait interieur pour que « Nom de mon app » reste lisible en entier. */
@media (max-width: 399.98px) {
  .vs-app-hero__champ { padding-inline: var(--v-space-2); }
}

/* TITRE SUR DEUX LIGNES A TOUTES LES LARGEURS (user, 13/09/2026). La coupure
   est un <br> ; le titre est insecable par ailleurs, il faut donc que la plus
   longue ligne tienne toujours, sinon elle deborderait.
   Mesure en Manrope 800 (13/09/2026) : « Lancez l'app de ton » 8,86 em,
   « BDE en [5 minutes] » 8,65 em plaque comprise - « Lance » est plus court
   encore. Diviseur arrondi a 9,5 pour le crenage.
   TITRE AGRANDI (user, 13/09/2026) : 1,3 fois le corps du H1, soit 75 px au
   plus contre 57,6. 1,6 (92 px) a ete essaye et juge trop gros. Derive du token
   et non ecrit en dur, pour ne pas ouvrir un huitieme cran de typo. Le titre
   prend le plus petit de deux corps :
   - 1,3 fois le corps normal du H1 (token) ;
   - la largeur utile de l'ecran (moins les deux gouttieres du conteneur,
     1,5rem) divisee par 9,5 : c'est lui qui gouverne sur telephone.
   Verifie : la ligne longue fait 664 px au plus, sous la borne de 46rem
   (736 px) du bloc de texte ; 571 px a 992, 424 px a 576, 341 px pour 366 a
   390 px d'ecran.
   A refaire si le texte du titre change : la ligne la plus longue fixe le
   diviseur. */
.vs-app-hero__titre {
  font-size: min(calc(var(--v-text-h1) * 1.3), calc((100vw - 1.5rem) / 9.5));
  white-space: nowrap;
}
/* TITRE EN BLANC sur le ciel (user, 13/09/2026). Specificite superieure a
   « .vs-hero--light h1 », qui le passe a l'encre. L'autocollant n'est pas
   concerne : son mot est peint par degrade (.vs-or, couleur transparente) sur
   sa plaque blanche.
   ATTENTION CONTRASTE : le ciel mesure 1,9:1 (bleu, #63c7fe) a 1,3:1 (nuages,
   #c9e7f8) face au blanc, sous le seuil de 3:1 des grands titres.
   D'ou une OMBRE TRES LEGERE (user, 13/09/2026), seule ombre de texte du site :
   un halo diffus bleu nuit qui detache les lettres des nuages, et un trait
   serre qui tient leurs bords. Couleur tiree du token nuit (--bs-secondary-rgb),
   aucune valeur en dur. */
.vs-hero--light .vs-app-hero__titre {
  color: var(--v-on-dark);
  text-shadow:
    0 1px 2px rgba(var(--bs-secondary-rgb), .18),
    0 2px 16px rgba(var(--bs-secondary-rgb), .22);
}
/* Pas d'ombre sous l'autocollant : son mot est un degrade decoupe dans un texte
   TRANSPARENT (.vs-or), l'ombre heritee se verrait a travers les lettres et
   salirait le bleu. La plaque blanche le detache deja du ciel. */
.vs-app-hero__tag { text-shadow: none; }

/* L'autocollant « 5 minutes » tient en DEUX mots : insecable, sinon la plaque
   pourrait se couper entre le chiffre et l'unite et ne se lirait plus comme
   une etiquette. Les coupures du titre sont posees par des <br>, pas par le
   retour automatique (voir le HTML).
   COLLE AU MOT « en » (user, 13/09/2026) : aucun ecart en plus de l'espace
   du texte, a toutes les largeurs. La regle vaut aussi contre la marge de 0,2em
   que .vs-sticker pose a partir de 768 px (bloc AUTOCOLLANT, plus haut dans
   cette feuille : a specificite egale, la regle la plus basse l'emporte). */
.vs-app-hero__tag {
  white-space: nowrap;
  margin-left: 0;
}
/* MOT EN BLEU CIEL, plus en or (user, 13/09/2026) : une nuance du ciel de
   fond. Meme geste que .vs-or (degrade decoupe dans le texte), du bleu sombre
   au bleu vif ; seul le degrade change, la decoupe reste celle de .vs-or. Les
   deux bouts passent le seuil de contraste des grands titres sur la plaque
   blanche (voir --v-sky / --v-sky-ink dans tokens.css). */
.vs-app-hero__tag .vs-or {
  background-image: linear-gradient(135deg, var(--v-sky-ink) 0%, var(--v-sky) 100%);
}

/* Le telephone en main : 40rem au plus (36rem juge un peu petit, user
   13/09/2026 ; le fichier fait 1320 px de large, il reste net au double de
   640 px). Sa hauteur suit son format,
   width/height dans le HTML reservent la place avant le chargement. */
.vs-app-hero__media {
  display: block;
  width: 100%;
  max-width: 40rem;
  height: auto;
  margin: var(--v-space-12) auto 0;
}

/* ── ETIQUETTE PARTENAIRE HELLOASSO (user, 13/09/2026) ──────────────────────
   Etiquette blanche FIXEE en bas a gauche de l'ecran : « Partenaire » + logo.
   Elle ne bouge pas au defilement (retour au fixe voulu par le user, apres
   deux essais « attachee a la page »).
   COLLEE AU BORD GAUCHE : elle sort du bord comme un onglet, d'ou les arrondis
   a DROITE seulement (haut et bas).
   REPLI SYNCHRONISE AVEC LA BARRE FLOTTANTE : quand la barre « Nom de mon app »
   remonte en bas de l'ecran, le mot « Partenaire » se replie et il ne reste que
   le logo HelloAsso ; quand elle redescend (retour au hero), il se redeplie.
   Aucun JavaScript de plus : l'etiquette suit la barre dans le HTML, le
   selecteur de soeur suivante lit sa classe .is-visible.
   Sans ombre (DA du site) : son aplat blanc la detache du ciel et du contenu.
   Plan --v-z-float. Bas et gauche tiennent compte de la barre d'accueil et de
   l'encoche des iPhone. */
.vs-app-partenaire {
  position: fixed;
  left: 0;
  bottom: calc(var(--v-space-4) + env(safe-area-inset-bottom, 0px));
  z-index: var(--v-z-float);
  display: inline-flex;
  align-items: center;
  padding-block: var(--v-space-2);
  padding-right: var(--v-space-4);
  padding-left: calc(var(--v-space-4) + env(safe-area-inset-left, 0px));
  border-radius: 0 var(--v-radius-pill) var(--v-radius-pill) 0;
  background-color: var(--v-surface);
}
/* Le mot se replie en LARGEUR (max-width) et en fondu ; son ecart avec le logo
   est porte par sa propre marge, pour se replier avec lui. 8rem couvre
   « PARTENAIRE » en petites capitales. */
.vs-app-partenaire__texte {
  display: inline-block;
  max-width: 8rem;
  margin-right: var(--v-space-2);
  overflow: hidden;
  white-space: nowrap;
  color: var(--v-muted);
  font-size: var(--v-text-label);
  font-weight: var(--v-weight-bold);
  letter-spacing: var(--v-tracking-label);
  text-transform: uppercase;
  transition:
    max-width var(--v-duration-3) var(--v-ease),
    margin-right var(--v-duration-3) var(--v-ease),
    opacity var(--v-duration-3) var(--v-ease);
}
.vs-app-barre.is-visible ~ .vs-app-partenaire .vs-app-partenaire__texte {
  max-width: 0;
  margin-right: 0;
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .vs-app-partenaire__texte { transition: none; }
}
/* Le logo est un LIEN vers helloasso.com (user, 13/09/2026). Le lien epouse
   exactement le logo (bloc, sans hauteur de ligne en plus) : la zone cliquable
   est l'image, rien d'autre. Pas d'effet de survol (DA du site : un logo de
   marque ne se recolore pas) ; l'anneau de focus du site reste visible au
   clavier. */
.vs-app-partenaire__lien {
  display: block;
  line-height: 0;
  border-radius: var(--v-radius-xs);
}
/* Le logo est dimensionne par sa hauteur seule : sa largeur reste celle du
   fichier, un fichier de marque ne se deforme pas. */
.vs-app-partenaire__logo {
  display: block;
  width: auto;
  height: 1.1rem;
}
/* Sous 992 px la barre flottante prend presque toute la largeur : l'etiquette
   est posee UNE FOIS POUR TOUTES au-dessus de son emplacement (bas + marge +
   hauteur de la barre, bouton de 48 px et 2 x 8 px de retrait, + un ecart).
   Elle ne bouge jamais, que la barre soit visible ou non. */
@media (max-width: 991.98px) {
  .vs-app-partenaire {
    bottom: calc(var(--v-space-4) + var(--v-btn-h-lg) + 2 * var(--v-space-2) + var(--v-space-3) + env(safe-area-inset-bottom, 0px));
  }
}


/* ══════════════════════════════════════════════════════════════════════════
   /etudiant/app/ - SECTION 1 : TROIS CARTES
   ══════════════════════════════════════════════════════════════════════════
   Section basique (user, 13/09/2026) : tout vient du design system
   (.vs-section, .vs-section__head, .vs-lead, .vs-card--tinted, .vs-media).
   Ne sont regles ici que le titre sur deux lignes et l'interieur de la carte. */

/* Titre de section sur DEUX LIGNES exactement : chaque ligne est un bloc
   insecable. Lignes volontairement courtes (19 signes au plus, ~9 em en
   Manrope) : elles tiennent au corps minimal du h2 (1,8rem) des 360 px. */
.vs-app-ligne {
  display: block;
  white-space: nowrap;
}

/* L'image est posee en haut de la carte, dans son retrait. Rayon d'un bloc
   INTERIEUR a une carte (--v-radius-md), plus petit que celui de la carte :
   le rayon decroit avec l'imbrication.
   Format VERTICAL 2:3 (user, 13/09/2026), fichier attendu 800 x 1200 : ecrit
   avec les dimensions du fichier, on lit d'un coup d'oeil la taille a fournir. */
.vs-app-carte .vs-media {
  aspect-ratio: 800 / 1200;
  border-radius: var(--v-radius-md);
}
.vs-app-carte__titre { margin: var(--v-space-5) 0 var(--v-space-2); }
/* Icones 3D des titres (user, 13/09/2026) : PLUS GROSSES que celles du
   composant (.vs-card__icon, 2,75rem) et PLUS COLLEES au titre (ecart de
   --v-space-1 au lieu de --v-space-3). Les fichiers ont leur propre marge
   transparente autour du dessin : un ecart CSS plus large les decollait trop
   du texte. 3,5rem reste net avec des fichiers de 256 et 512 px. */
.vs-app-carte .vs-card__head { gap: var(--v-space-1); }
.vs-app-carte .vs-card__icon {
  width: 3.5rem;
  height: 3.5rem;
}


/* ══════════════════════════════════════════════════════════════════════════
   /etudiant/app/ - SECTION 2 : LES ETAPES
   ══════════════════════════════════════════════════════════════════════════
   Quatre cartes en damier (user, 13/09/2026). Section teintee, cartes
   blanches (.vs-card). Difference voulue avec la section 1 : colonnes
   inegales (7/5 puis 5/7, dans le HTML) et images HORIZONTALES. Le titre de
   section sur deux lignes reprend .vs-app-ligne.
   CARTES AFFINEES (user, 13/09/2026 : la section prenait trop de place) :
   retrait interieur ramene a 24 px et image moins haute. */
.vs-app-etape { padding: var(--v-space-6); }

/* EN-TETE DE CARTE SUR UNE LIGNE (user, 13/09/2026) : pastille « Etape n » et
   titre, alignes sur leur milieu.
   Passage a la ligne si la carte est trop etroite (telephone, colonne de 5). */
.vs-app-etape__entete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--v-space-2) var(--v-space-3);
  margin-bottom: var(--v-space-2);
}
.vs-app-etape__num {
  padding: var(--v-space-1) var(--v-space-3);
  border-radius: var(--v-radius-pill);
  font-size: var(--v-text-sm);
  font-weight: var(--v-weight-semibold);
}

/* PASTILLES « ETAPE N » EN DEGRADE FLOU (user, 13/09/2026) : la direction
   artistique de la page, reprise des fonds colores des captures de l'app.
   Une ambiance par etape (tokens --v-blur-* dans tokens.css), en teintes
   VITAMINEES (saturees et lumineuses, reglage du user), texte nuit lisible.
   Degrade en CSS pur, sans image : l'essai avec les images de reference a ete
   ecarte par le user, qui a garde cette version.
   - GRAIN : un bruit SVG leger pose PAR-DESSUS le degrade (premiere couche de
     fond), comme le grain des images de reference.
   - RELIEF : EXCEPTION DOCUMENTEE a la regle « ni bordure ni ombre » du site,
     voulue par le user pour donner du volume a la pastille - un filet blanc
     translucide, un reflet clair en haut et un liseré sombre tres fin en bas,
     tous a l'interieur (inset) : la pastille ne projette aucune ombre autour
     d'elle. Pastille un peu plus epaisse que les autres pour laisser voir le
     degrade. */
.vs-app-etape__num {
  --vs-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .5 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)' opacity='.3'/%3E%3C/svg%3E");
  padding: var(--v-space-2) var(--v-space-4);
  border: 1px solid rgba(255, 255, 255, .7);
  color: var(--v-secondary);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .75),
    inset 0 -1px 0 rgba(var(--bs-secondary-rgb), .1);
}
.vs-app-etape__num--1 { background: var(--vs-grain), var(--v-blur-bleu-rose); }
.vs-app-etape__num--2 { background: var(--vs-grain), var(--v-blur-orange); }
.vs-app-etape__num--3 { background: var(--vs-grain), var(--v-blur-vert); }
.vs-app-etape__num--4 { background: var(--vs-grain), var(--v-blur-rose-corail); }
.vs-app-etape__titre { margin: 0; }

/* IMAGE EN TETE DE CARTE, HAUTEUR FIXE COMMUNE (user, 13/09/2026). Deux
   ratios differents (16:9 et 4:3) dans des cartes de largeurs differentes ne
   donnaient que des hauteurs VOISINES : les images d'une rangee ne
   s'alignaient pas au pixel. Les quatre images ont donc la MEME hauteur, a
   toutes les largeurs ; seule leur largeur suit la carte, et le visuel remplit
   le cadre (object-fit: cover de .vs-media), recadre au besoin - garder le
   sujet au centre du fichier.
   Hauteur : 10rem sur telephone, qui grandit avec l'ecran jusqu'a 13rem.
   Rayon d'un bloc interieur a une carte (--v-radius-md). */
.vs-app-etape__media {
  height: clamp(10rem, 16vw, 13rem);
  aspect-ratio: auto;
  margin-bottom: var(--v-space-5);
  border-radius: var(--v-radius-md);
}

/* CARTE D'OFFRE : la surprise de la section (kit de communication offert au
   lancement). MEME FOND BLANC que les autres cartes (user, 13/09/2026 : la
   version fond nuit a ete retiree) ; elle se signale par l'icone cadeau 3D
   posee devant sa phrase. */

/* Icone cadeau devant la phrase : alignee sur le milieu du texte, jamais
   comprimee, un ecart court comme les icones de titres de la section 1. */
.vs-app-etape__texte--offre {
  display: flex;
  align-items: center;
  gap: var(--v-space-2);
}
.vs-app-etape__cadeau {
  flex: 0 0 auto;
  width: 2.75rem;
  height: 2.75rem;
}


/* ══════════════════════════════════════════════════════════════════════════
   /etudiant/app/ - BARRE FLOTTANTE « NOM DE MON APP »
   ══════════════════════════════════════════════════════════════════════════
   (user, 13/09/2026) Copie du formulaire du hero, fixee en bas de l'ecran des
   que le formulaire du hero sort par le haut (script de la page, classe
   .is-visible). Elle reprend .vs-app-hero__form : meme barre, meme verre
   depoli au repos, blanc plein au focus.
   ANIMATION : cachee, elle attend sous le bord de l'ecran (translation de sa
   hauteur + un cran) et transparente ; visible, elle remonte a sa place. Seuls
   transform et opacity s'animent, sur la duree et la courbe du site. Qui
   demande moins d'animations la voit seulement apparaitre en fondu.
   OMBRE : la barre flotte reellement au-dessus du contenu, c'est l'emploi
   prevu de --v-overlay-shadow (tokens.css), comme le mega-menu. */
.vs-app-barre {
  position: fixed;
  left: 50%;
  bottom: calc(var(--v-space-4) + env(safe-area-inset-bottom, 0px));
  z-index: var(--v-z-float);
  width: calc(100% - 2 * var(--v-space-4));
  max-width: 34rem;
  opacity: 0;
  transform: translate(-50%, calc(100% + var(--v-space-8)));
  transition:
    transform var(--v-duration-3) var(--v-ease),
    opacity var(--v-duration-3) var(--v-ease);
  pointer-events: none;
}
.vs-app-barre.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}
.vs-app-barre__form {
  margin: 0;
  max-width: none;
  box-shadow: var(--v-overlay-shadow);
}
@media (prefers-reduced-motion: reduce) {
  .vs-app-barre,
  .vs-app-barre.is-visible { transform: translate(-50%, 0); }
  .vs-app-barre { transition: opacity var(--v-duration-3) var(--v-ease); }
}

/* PIED DE PAGE : la barre flottante couvrirait sa derniere ligne. On lui
   ajoute en bas la place de la barre (64 px) et de sa marge, sur cette page
   seulement (:has, la regle ne vaut que si la barre existe). */
body:has(.vs-app-barre) .vs-footer {
  padding-bottom: calc(var(--v-space-8) + var(--v-btn-h-lg) + 2 * var(--v-space-2) + var(--v-space-4));
}
