/* =================================================================
   Youen Frémont — En-tête, hero, corps et panneau blanc
   Feuille 2 sur 8. La feuille unique a été découpée le 2026-09-19 aux
   frontières de ses sections, sans qu'une règle ne change de place : les huit
   fichiers se chargent dans l'ordre de base.njk, et cet ordre EST la cascade.
   Les tokens et les surfaces vivent dans style.css, chargée en premier.
   ================================================================= */

/* -----------------------------------------------------------------
   5. En-tête — fixe sur toutes les pages, elle survole le contenu.
   Transparente en haut de page, voilée et floutée dès que ça défile.
   ----------------------------------------------------------------- */
.entete {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 10;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--pas-4);
  min-height: var(--hauteur-entete);
  padding: var(--decalage-entete) var(--marge-page) var(--pas-4);
  /* L'en-tête ne décide pas de sa couleur : elle emprunte celle de la surface
     qui passe sous elle. En haut de page c'est le hero, donc la couleur. */
  color: var(--encre);
}

/* Le voile et le flou vivent dans un calque à part, masqué en dégradé : le flou
   s'éteint progressivement vers le bas au lieu de couper net. Le voile est le
   fond de la surface empruntée, à peine transparent : au-dessus du panneau il
   est blanc, au-dessus d'une planche de projet il est de la couleur de la page.
   Sans JavaScript, pas de détection de défilement : le voile reste posé. */
.entete::before {
  position: absolute;
  inset: 0 0 calc(var(--hauteur-entete) * -0.6);
  z-index: -1;
  opacity: 0;
  background-image: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--fond) 85%, transparent),
    transparent
  );
  /* Le #000 d'un masque n'est pas une couleur : seul son canal alpha compte. */
  mask-image: linear-gradient(to bottom, #000 45%, transparent);
  content: "";
}

/* Le voile ne se pose que là où quelque chose passe vraiment sous l'en-tête : le
   panneau blanc, ou les images bord à bord d'une page projet. Sur le hero, un
   aplat uni, il n'a rien à séparer ni à flouter.
   Le flou est déclaré ici et pas plus haut, pour la même raison : un
   backdrop-filter monte une couche de composition dès qu'il est déclaré, et sur
   un aplat uni elle ne rend qu'une bande à peine plus terne que le fond —
   c'était la bande visible en haut de page. */
.entete[data-papier]::before,
.entete--planches[data-defile]::before {
  opacity: 1;
  backdrop-filter: blur(var(--flou-voile));
}

html:not(.js) .entete::before {
  opacity: 1;
}

/* Les actions de droite se tiennent ensemble : sans ce groupe, l'espacement
   automatique de l'en-tête les écarterait l'une de l'autre. */
.entete__actions {
  display: flex;
  align-items: flex-start;
  gap: var(--pas-3);
}

/* Quand le panneau blanc arrive sous l'en-tête — et pas avant : le hero fait
   une hauteur d'écran et reste collé dessous tout ce temps —, elle bascule sur
   la surface papier : texte noir, voile blanc, remplissage en aplat. Tant que
   c'est le hero qui passe, elle garde la couleur, et son voile, de la couleur de
   la page, ne se voit pas. C'est ce qui évite le voile blanc étalé sur l'aplat.
   Les pages projet en sont exclues : sous elles il n'y a jamais de panneau, mais
   la couleur ou une photo. data-papier est posé par main.js.
   La bascule elle-même est déclarée avec la surface papier, section 2. */

/* Sans JavaScript, rien ne dit ce qui passe sous l'en-tête : elle reste sur le
   hero à l'arrivée, puis sur le panneau au défilement, et aucune encre ne tient
   sur les deux. Son voile devient donc opaque et lui donne son propre fond, la
   couleur de la page — ce qui garantit son texte, jamais sous 5,47:1, là où
   choisir le blanc le faisait tomber à 1,3:1 sur le lime et choisir le noir à
   1,8:1 sur le vert. */
html:not(.js) .entete::before {
  inset: 0;
  background-image: none;
  background-color: var(--fond);
  /* Un fond opaque n'a rien à laisser voir : le flou ne coûterait qu'une couche. */
  backdrop-filter: none;
  mask-image: none;
}


/* Ouverture et fermeture : le même bouton rond, à la même place. Le menu déplié
   se superpose à l'en-tête sans que rien ne bouge. */
.bouton-rond {
  display: grid;
  place-items: center;
  width: var(--taille-bouton);
  height: var(--taille-bouton);
  padding: 0;
  border: 0;
  border-radius: var(--rayon-pilule);
}

/* Dans l'en-tête, posés à nu sur la page, les fonds n'apportent rien : on ne
   garde que le signe et le libellé, dans l'encre de la surface qui passe
   dessous. Le remplissage revient au survol, comme repère. */
.entete .bouton-rond,
.entete .bouton-pilule {
  background-color: transparent;
  color: inherit;
}

.entete .bouton-rond:hover,
.entete .bouton-rond:focus-visible,
.entete .bouton-pilule:hover,
.entete .bouton-pilule:focus-visible {
  background-color: var(--remplissage);
  color: var(--remplissage-texte);
}

/* Une croix est un plus tourné à 45° : un seul dessin pour les deux états. */
.icone-plus,
.icone-plus::before {
  display: block;
  width: 1rem;
  height: 2px;
  border-radius: var(--rayon-trait);
  background-color: currentColor;
}

.icone-plus {
  position: relative;
}

.icone-plus::before {
  position: absolute;
  left: 0;
  transform: rotate(90deg);
  content: "";
}

.bouton-fermer .icone-plus {
  transform: rotate(45deg);
}

.libelle-invisible {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* -----------------------------------------------------------------
   6. Hero — reste collé en haut, le panneau blanc lui passe dessus.
   ----------------------------------------------------------------- */
/* Le bloc pastille + titre est centré sur la hauteur de l'écran. La ligne du bas
   est sortie du flux pour ne pas décaler ce centrage, et les marges hautes et
   basses se répondent pour que l'en-tête fixe ne fausse pas l'équilibre. */
.hero {
  position: sticky;
  top: 0;
  z-index: 0;
  display: grid;
  /* stretch et non center : c'est le bloc de contenu qui prend toute la hauteur
     utile, et c'est lui qui centre le titre — voir .hero__contenu. */
  place-items: stretch;
  min-height: 100svh;
  padding: var(--hauteur-entete) var(--marge-page);
  overflow: hidden;
}

.hero__image {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.hero__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__image::after {
  position: absolute;
  inset: 0;
  background-color: color-mix(in srgb, var(--noir) 35%, transparent);
  content: "";
}

/* Carrousel vidéo en fond du hero de l'accueil (hero-carrousel.njk), validé
   le 2026-09-24. Derrière le contenu, comme .hero__image : même empilement,
   même voile. Tous les plans dans la même case de grille, un seul visible. */
.hero__carrousel {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Le fondu du carrousel « Travaillons ensemble » (contact-pied.css) :
   `visibility` retardée à la disparition seulement, pour que deux plans se
   croisent, et pour que le lien d'un plan éteint sorte de la tabulation. */
.hero__plan {
  grid-area: 1 / 1;
  min-height: 0;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--duree-carrousel-fondu) ease,
    visibility 0s linear var(--duree-carrousel-fondu);
}

.hero__plan[data-actif] {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

.hero__plan-media {
  position: absolute;
  inset: 0;
}

.hero__plan-media video,
.hero__plan-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* L'image animée qui remplace la vidéo quand Safari en refuse la lecture
   (mode économie d'énergie, voir hero-carrousel.js) : exactement par-dessus. */
.hero__plan-anime {
  position: absolute;
  inset: 0;
}

/* Le même voile que sous une photo de hero : c'est lui qui garde le nom et la
   pastille lisibles sur n'importe quel plan. */
.hero__plan-media::after {
  position: absolute;
  inset: 0;
  background-color: color-mix(in srgb, var(--noir) 35%, transparent);
  content: "";
}

/* Rôle, titre et année sur une seule ligne, au corps de la ligne du bas du
   hero. L'accueil n'a plus de flèche depuis le 2026-09-24 : l'info prend sa
   place, juste au-dessus de la ligne « ville / rôles » — empilée sur deux
   lignes sous 34 em (ecrans.css), d'où la hauteur plus grande en mobile. */
.hero__projet {
  position: absolute;
  right: var(--marge-page);
  bottom: calc(var(--pas-5) + var(--pas-8));
  left: var(--marge-page);
  display: flex;
  justify-content: center;
  gap: var(--pas-2);
  margin: 0;
  overflow: hidden;
  color: var(--encre);
  /* En italique et un cran plus petit, demandé le 2026-09-24 : la ligne se lit
     comme une légende, pas comme un libellé. L'italique est le vrai, servi par
     le kit Adobe avec le romain. */
  font-size: var(--texte-xxs);
  font-style: italic;
  letter-spacing: var(--approche-libelle);
  text-transform: uppercase;
  white-space: nowrap;
}

@media (min-width: 34em) {
  .hero__projet {
    bottom: calc(var(--pas-5) + var(--pas-6));
  }
}

/* Sur grand écran, il y a la place entre « France » et les rôles : l'info
   descend dans la ligne du bas, au centre. */
@media (min-width: 64em) {
  .hero__projet {
    bottom: var(--pas-5);
  }
}

.hero__projet-lien {
  color: inherit;
  font-weight: var(--graisse-forte);
}

/* Le carrousel est sous le contenu du hero : sans ceci, la ligne du bas et
   le bloc du titre recouvrent le lien et le rendent inatteignable à la
   souris. Le titre garde le pointeur, pour son effet de points. */
.hero:has(.hero__carrousel) :is(.hero__contenu, .hero__pied, .hero__invite) {
  pointer-events: none;
}

.hero:has(.hero__carrousel) .hero__titre {
  pointer-events: auto;
}

/* C'est le TITRE qui doit tomber au centre de l'écran, pas la boîte qui le
   contient. Centrée en bloc, la boîte poussait le nom vers le bas de toute la
   hauteur de la pastille et de son écart — 32 px mesurés le 2026-08-26 sur
   l'accueil, et l'œil le voyait avant la règle.
   Trois rangées, dont deux égales : la pastille occupe la première, le titre la
   deuxième, les filtres la troisième. Les deux rangées extrêmes valant 1fr
   chacune, le titre tombe au centre exact quoi qu'elles contiennent — une
   pastille seule, des filtres seuls, les deux ou aucun des deux. C'est la même
   raison qui avait sorti la ligne du bas du flux, mais traitée pour de bon. */
.hero__contenu {
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  align-items: center;
  justify-items: center;
  text-align: center;
}

.hero__contenu > .pastille-dispo {
  grid-row: 1;
  align-self: end;
  margin-bottom: var(--pas-4);
}

.hero__titre {
  grid-row: 2;
}

.hero__contenu > .filtres {
  grid-row: 3;
  align-self: start;
}

.pastille-dispo {
  display: flex;
  align-items: center;
  gap: var(--pas-2);
}

/* Le point prend le remplissage de la surface, pas un vert : la charte n'en a
   pas, et le sien se confondait avec l'aplat lime. Il est décoratif, donc hors
   du minimum AA — mais il ne peut pas être une septième couleur. */
/* Le rond plein a laissé la place à la petite marque, le 2026-09-02. Elle prend
   le remplissage de la surface, comme le rond avant elle — l'aplat sur le
   papier, l'encre du couple sur l'aplat. Un peu plus haute que large, d'où la
   largeur calée sur la hauteur et non l'inverse. */
.pastille-dispo__point {
  display: block;
  height: 0.85em;
  color: var(--remplissage);
}

.pastille-dispo__point .marque {
  display: block;
  width: auto;
  height: 100%;
}

/* Le nom sur l'aplat est un titre : il prend la couleur de sa surface, soit ici
   la seconde couleur du couple, celle que la charte donne au logo. */
.hero__titre {
  position: relative;
  display: grid;
  color: var(--titre);
  font-size: var(--texte-xl);
  font-family: var(--police-titre);
  font-weight: var(--graisse-forte);
  /* Plus aéré que les autres titres : l'accent du É de FRÉMONT monte au-dessus
     de la hauteur de capitale et viendrait toucher la ligne du dessus. */
  line-height: 1.1;
  letter-spacing: var(--approche-titre);
  text-transform: uppercase;
  text-wrap: balance;
}

/* Nuage de points posé par hero-points.js : hors écran tant que la souris ne
   survole pas le titre, jamais interactif lui-même — c'est le titre, dessous,
   qui reçoit le pointeur, pour que le nuage ne se dérobe pas sous lui-même. */
/* Il déborde du titre de tous côtés : c'est l'espace d'où les points arrivent
   et où ils s'envolent (2026-09-24). Le script lit ce débord pour s'y caler. */
.hero__points {
  position: absolute;
  inset: calc(var(--pas-9) * -1);
  width: calc(100% + var(--pas-9) * 2);
  height: calc(100% + var(--pas-9) * 2);
  pointer-events: none;
  opacity: 0;
}

/* Le canevas s'affiche d'un coup : ce sont ses points qui naissent et
   s'éteignent en onde, dessinés par le script, et le canevas n'est retiré
   qu'une fois le dernier éteint. Les lettres, elles, fondent pendant que
   l'onde passe, dans un sens puis dans l'autre (2026-09-24). */
@media (prefers-reduced-motion: no-preference) {
  .hero__titre[data-points-visibles] .hero__points {
    opacity: 1;
  }

  .hero__titre[data-points-visibles] > span {
    transition: opacity 0.35s ease;
  }

  /* Le texte reste dans le flux, rien ne change de taille en dessous. */
  .hero__titre[data-points-actifs] > span {
    opacity: 0;
  }
}

/* Une lettre du nom, quand main.js l'a découpé. Le bloc en ligne est ce qui la
   rend déplaçable ; il est posé ici et non sous la règle de mouvement, pour que
   la mise en page soit exactement la même que l'animation joue ou non. */
.hero__lettre {
  display: inline-block;
}

/* Tri par métier, sous le titre du hero et sous la liste. Rien autour des
   libellés : ni fond, ni filet de séparation — celui-ci se lisait comme un
   contour de bouton à peine visible. C'est l'écart et la couleur du texte qui
   séparent et qui disent l'état. */
.filtres {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 var(--pas-2);
  margin-top: var(--pas-2);
}

.filtres button {
  padding: var(--pas-2) var(--pas-4);
  border: 0;
  background: none;
  color: var(--encre-attenuee);
  font-size: var(--texte-s);
  font-weight: var(--graisse-forte);
  letter-spacing: var(--approche-libelle);
  text-transform: uppercase;
}

/* C'est le libellé qui porte la couleur : en permanence sur le filtre en cours,
   au survol et au focus clavier sur les autres. Rien n'est cerné ni rempli.
   L'opacité qui distinguait les deux états ne portait aucune couleur, et le
   libellé éteint passait sous AA sur les aplats les plus serrés.
   La page Work est fixée sur le violet depuis le 2026-09-08 : le libellé en
   couleur y tient à 7,75:1, sur le panneau comme sur le hero (mesuré le
   2026-09-19). À revérifier si elle change d'aplat — sur le rouge, le lime ou
   le magenta, le hero tomberait à 2,5:1. */
.filtres button[aria-pressed="true"],
.filtres button:not([aria-pressed="true"]):hover,
.filtres button:not([aria-pressed="true"]):focus-visible {
  color: var(--remplissage);
}

/* Sous 30 em les trois libellés ne tiennent plus sur une ligne : ils s'empilent. */
@media (max-width: 29.999em) {
  .filtres {
    flex-direction: column;
    align-items: center;
  }
}

html:not(.js) .filtres {
  display: none;
}

.section-projets .filtres {
  margin-top: var(--pas-7);
}

/* La liste ne doit pas se caler sous l'en-tête fixe quand un filtre l'y ramène. */
.grille-projets {
  scroll-margin-top: calc(var(--hauteur-entete) + var(--pas-4));
}

.resultat-filtre {
  margin-bottom: var(--pas-4);
  font-size: var(--texte-xs);
  letter-spacing: var(--approche-libelle);
  text-transform: uppercase;
  color: var(--encre-attenuee);
}

/* La flèche d'invitation au défilement, demandée le 2026-08-21. Elle est posée
   au-dessus du pied du hero, centrée, et dessinée à même le CSS : deux bords
   d'un carré tourné d'un quart de tour. Pas de fichier, pas de fonte d'icônes.
   Elle prend l'encre de la surface, donc le noir ou le blanc selon l'aplat —
   jamais sous 5,35:1 sur les six déclinaisons. */
.hero__invite {
  position: absolute;
  right: 0;
  bottom: calc(var(--pas-5) + var(--pas-6));
  left: 0;
  display: grid;
  justify-items: center;
  margin: 0;
  line-height: 0;
  /* Le centrage ne passe surtout pas par `translate` : le sautillement s'en sert
     et l'écraserait, ce qui décalait la flèche de 5 px vers la droite. */
}

.hero__fleche {
  display: block;
  width: 0.6rem;
  height: 0.6rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  rotate: 45deg;
}

/* La pilule « Scroll down » de curseur-defiler.js, d'après la capture du
   2026-09-24 : elle remplace le curseur sur le hero de Work et le suit. Elle
   prend le remplissage de la page, comme un bouton plein, et ne reçoit jamais
   le pointeur. Sur les filtres, le vrai curseur revient. */
.hero[data-defiler-actif] {
  cursor: none;

  & :is(a, button, input, label) {
    cursor: pointer;
  }
}

/* Petite, et dans les codes des libellés du site : même corps, même approche
   et même capitale que la pastille « Disponible », la graisse et la forme des
   boutons pilules. Le corps passe du plus petit cran au suivant sur un grand
   écran, et le reste, en em, suit. Aucune taille nouvelle (2026-09-24). */
.curseur-defiler {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 40;
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.6em 1.1em;
  border-radius: var(--rayon-pilule);
  background: var(--remplissage);
  color: var(--remplissage-texte);
  font-size: var(--texte-xs);
  font-weight: var(--graisse-forte);
  letter-spacing: var(--approche-libelle);
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
  translate: calc(var(--curseur-x, 0px) - 50%) calc(var(--curseur-y, 0px) - 50%);
  opacity: 0;
  scale: 0.6;
}

@media (min-width: 80em) {
  .curseur-defiler {
    font-size: var(--texte-s);
  }
}

.curseur-defiler[data-visible] {
  opacity: 1;
  scale: 1;
}

.curseur-defiler__fleche {
  width: 1.1em;
  height: 1.1em;
}

/* Le fondu ne vaut qu'à l'apparition : en sortant du hero, le curseur doit
   redevenir normal tout de suite, sans pilule qui s'attarde (2026-09-24). */
@media (prefers-reduced-motion: no-preference) {
  .curseur-defiler[data-visible] {
    transition: opacity 0.2s ease, scale 0.2s ease;
  }
}

.hero__pied {
  position: absolute;
  right: var(--marge-page);
  bottom: var(--pas-5);
  left: var(--marge-page);
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: var(--pas-4);
}

/* -----------------------------------------------------------------
   7. Corps et panneau blanc
   ----------------------------------------------------------------- */
/* Tout ce qui n'est pas le pied. Deux rôles, aucun décoratif : il passe devant
   le pied resté collé au bas de la fenêtre, et il borne le collage du hero —
   sinon le hero tiendrait la fenêtre jusqu'au dernier pixel de la page et le
   pied ne se découvrirait jamais. */
.corps {
  position: relative;
  z-index: 1;
}

/* Le panneau est la surface papier du site : il porte sa classe dans base.njk,
   et c'est elle qui pose son fond et son encre. */
.panneau {
  position: relative;
  z-index: 1;
}

/* Les coins arrondis n'ont de sens que là où le panneau recouvre le hero.
   Le rognage évite qu'une image bord à bord ne dépasse des arrondis.
   « clip » et non « hidden » : hidden fait du panneau une zone de défilement,
   et une colonne collante à l'intérieur s'y collerait au panneau au lieu de
   l'écran — l'intitulé de la vitrine ne suivrait plus. */
/* Arrondi des quatre côtés depuis le 2026-08-20 : le bas du panneau se lève
   sur le pied en fin de course, et un angle droit s'y lisait comme une coupure.
   Arrondi, il se lit comme une feuille posée sur la couleur. */
.hero + .panneau {
  overflow: clip;
  border-radius: var(--rayon-l);
}
