/* La page CV : le contenu posé sur le champ de points du site.

   Le fond n'est plus découpé en couches. La descente du haut, la grille du
   milieu et la remontée du bas sont un seul halftone, dessiné d'un coup par
   scripts/points-champ.js — un seul objet pour tout le fond, aux mêmes
   réglages. Il n'y a donc plus ni masque ni raccord entre deux trames.

   Ce fichier place ce champ, puis tout le contenu par-dessus. */

/* La seconde main de la page : celle qui annote. Elle ne sert qu'aux notes
   manuscrites, jamais au contenu — d'où le chargement ici et non dans
   shared.css, et le font-display: swap, qui laisse la page s'afficher sans
   l'attendre. Cedarville Cursive, sous licence SIL Open Font : les lettres y
   sont attachées, ce qu'aucune script détachée ne sait imiter. */
@font-face {
    font-family: 'Cedarville Cursive';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/cedarville-cursive-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

.fond-page .site-content {
    /* Le grain cream-paper laisse la place aux points. */
    background-image: none;
    /* Trois écrans : dégradé du haut, semis, dégradé du bas. */
    min-height: 300vh;
    padding: 0;
}

/* === HERO =================================================================
   Un écran, pas plus : le portrait et la phrase en haut, les quatre chiffres
   collés au bas du viewport. La phrase est grise, et seuls les mots qui
   portent l'information reviennent au noir — c'est le contraste qui fait la
   hiérarchie, pas la taille.

   La photo de montagne prévue au brief n'est pas encore là. */
.fond-hero {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 100vh;
    /* Le bas est plus généreux qu'il n'y paraît : les outils fixes du coin
       inférieur gauche passent sous les chiffres, ils ont besoin de la
       place. */
    /* Le bas reprend exactement l axe des outils du coin gauche : leur boite
       s arrete a 1,25rem du bord et l icone est centree dans ses 44 px, soit
       12,5 px de rembourrage. */
    padding: clamp(5rem, 12vh, 9rem) var(--fond-marge) calc(1.25rem + 12.5px);
    display: grid;
    grid-template-rows: 1fr auto;
    gap: 2rem;
}

/* Portrait puis phrase, l'un sous l'autre et tous deux centrés dans la
   colonne. Le bloc est centré dans la hauteur qui lui reste, entre le haut
   de l'écran et les chiffres. */
.fond-hero-haut {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: clamp(0.75rem, 2vh, 1.5rem);
    text-align: center;
}

.fond-hero-photo {
    width: clamp(8rem, 13vw, 12rem);
    height: auto;
    aspect-ratio: 4 / 5;
    object-fit: cover;
    border-radius: 1.25rem;
    /* Le bas de l'image se dissout dans le papier, comme les dégradés de
       points : le portrait est posé sur la page, il n'y est pas collé. Le
       fondu part sous le menton — le visage reste intact. */
    -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
}

.fond-hero-phrase {
    /* Centrée, une ligne trop longue se lit mal : la mesure reste plus
       courte que la colonne. */
    width: 100%;
    max-width: 56ch;
    /* Sans équilibrage, la dernière ligne se réduisait à « Luxembourg). ». */
    text-wrap: balance;
    margin: 0;
    font-size: clamp(1.15rem, 1.9vw, 1.8rem);
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: -0.015em;
    /* Le gris n'est pas décoratif : c'est lui qui laisse ressortir le noir. */
    color: rgba(var(--text-rgb), 0.42);
}

.fond-hero-phrase strong {
    color: var(--text);
    font-weight: 700;
}

/* Les chiffres, alignés sur le bas de l'écran.

   Les colonnes se dimensionnent sur leur contenu, et non en quatre parts
   égales : à parts égales, « Réservations attribuées à Google Ads » passait à
   la ligne et son chiffre remontait, seul, au-dessus des trois autres. */
.fond-hero-chiffres {
    display: grid;
    grid-template-columns: repeat(4, auto);
    justify-content: space-between;
    gap: clamp(1rem, 3vw, 2.5rem);
    align-items: end;
}

.fond-kpi b {
    display: block;
    font-size: clamp(1.4rem, 2.4vw, 2.1rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* La borne basse d'une fourchette est une donnée, pas un ornement : elle
   recule sans devenir illisible. */
.fond-kpi b span { opacity: 0.45; font-weight: 700; }

.fond-kpi > span {
    display: block;
    font-size: 0.9rem;
    font-weight: 600;
    line-height: 1.35;
    /* Filet de sécurité pour les largeurs où un libellé passe sur deux
       lignes : ils la réservent tous, et les quatre chiffres restent
       alignés. Sur desktop, la grille ci-dessous fait mieux et le retire. */
    min-height: 2.7em;
}

/* Sur desktop, les trois lignes d'un chiffre entrent dans une grille commune
   aux quatre : chaque étage y forme une rangée, et l'alignement ne dépend
   plus d'une hauteur réservée d'avance. C'est ce qui supprime le vide entre
   le libellé et sa précision quand aucun des quatre ne passe à la ligne — le
   cas courant. */
@media (min-width: 901px) {
    .fond-hero-chiffres {
        grid-auto-flow: column;
        grid-template-rows: auto auto auto;
        row-gap: 0;
    }

    /* La boîte du chiffre s'efface : ce sont ses trois lignes qui entrent
       dans la grille, une par rangée. */
    .fond-kpi { display: contents; }

    .fond-kpi b { align-self: end; }

    .fond-kpi > span {
        min-height: 0;
        align-self: start;
    }

    .fond-kpi small {
        margin-top: 0.15rem;
        align-self: start;
    }
}

.fond-kpi small {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: rgba(var(--text-rgb), 0.5);
}

/* Sous 900 px, la phrase reprend toute la largeur : la mesure de 56ch la
   laisserait plus étroite que la colonne. */
@media (max-width: 900px) {
    .fond-hero { height: auto; min-height: 100vh; }

    .fond-hero-photo { width: min(45%, 10rem); }

    .fond-hero-phrase { max-width: none; }

    .fond-hero-chiffres { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem; }
}

/* === RAIL DE NAVIGATION ===================================================
   Fixe, centré verticalement à gauche. Des mots sur desktop, des points sur
   mobile — mais le libellé reste toujours dans le DOM : sur mobile il est
   masqué visuellement, jamais retiré, sinon le point serait un lien sans
   nom. L'état actif se lit aussi par aria-current, pas seulement à la
   couleur. */
/* Rail et outils sont calés sur le bord gauche du viewport, pas sur la
   colonne de contenu : --fond-bord est cette gouttière, et chacun corrige
   son propre rembourrage interne pour que le mot, le point et l'icône
   commencent tous exactement dessus. */
.fond-page { --fond-bord: 1.5rem; }

.fond-rail {
    position: fixed;
    left: var(--fond-bord);
    top: 50%;
    transform: translateY(-50%);
    z-index: 20;
    display: grid;
    gap: 0.55rem;
}

.fond-rail a {
    display: flex;
    align-items: center;
    color: var(--text);
    text-decoration: none;
    font-size: 0.82rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    /* L'entrée s'efface à mesure qu'elle s'éloigne de la section courante.
       --eloignement est posé par fond-rail.js ; le plancher évite qu'une
       entrée lointaine disparaisse tout à fait. */
    opacity: max(0.07, calc(0.34 - (var(--eloignement, 1) - 1) * 0.07));
    transition: opacity 0.25s ease;
}

.fond-rail a:hover { opacity: 0.65; }

/* La page est en noir et blanc, et la couleur d'accent n'y sert qu'à une
   chose : dire ce qui est actif ou ce qu'on est en train de toucher. C'est sa
   seule règle sur cette page — d'où sa rareté.
   --accent-ink et non --accent : sur du texte de cette taille, le violet clair
   ne passe pas le rapport de 4,5:1. */
.fond-rail a[aria-current="true"] { opacity: 1; color: var(--accent-ink); }

/* Mobile : plus que les points. Le mot reste lisible par les lecteurs
   d'écran, la zone tactile déborde largement du point. */
@media (max-width: 760px) {
    /* Le point est décalé de son rembourrage : on ramène le rail d'autant
       pour qu'il retombe sur --fond-bord. */
    /* 50svh et non 50% : sur mobile, la hauteur du viewport change quand la
       barre d'adresse se replie, et un élément centré dessus se déplaçait à
       chaque fois. La « small viewport height » est celle du navigateur
       barres déployées — une constante, donc un rail immobile. */
    .fond-rail { gap: 0; left: calc(var(--fond-bord) - 14px); top: 50svh; }

    .fond-rail a {
        padding: 9px 14px;
        /* Plancher haut, volontairement : sur un point de 7 px, un voisin a
           0,06 est invisible. Seul le point actif se voyait, et il semblait
           donc se teleporter d un cran a chaque changement de section au lieu
           de se deplacer dans une colonne visible. */
        opacity: max(0.22, calc(0.42 - (var(--eloignement, 1) - 1) * 0.05));
    }

    .fond-rail a::before {
        content: '';
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: currentColor;
    }

    .fond-rail a[aria-current="true"] { opacity: 1; }

    .fond-rail a span {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
        border: 0;
    }
}

/* === OUTILS (bas de page, à gauche) =======================================
   Thème, langue, contact. Pas de bouton dessiné : rien que l'icône posée sur
   le papier, sur l'axe vertical du rail. Fixes, comme lui.

   L'opacité de repos est à 0,50 et non plus bas : sous cette valeur, l'icône
   passe sous le rapport de 3:1 exigé pour un élément d'interface, et ces
   trois-là sont cliquables, pas décoratifs. */
.fond-outils {
    position: fixed;
    /* L'icône est centrée dans une cible de 44 px : on retire la moitié de la
       marge intérieure pour que son trait démarre sur --fond-bord, comme les
       mots du rail. */
    left: calc(var(--fond-bord) - 12.5px);
    bottom: 1.25rem;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.fond-outil {
    display: flex;
    align-items: center;
    justify-content: center;
    /* La cible tactile déborde largement de l'icône, qui reste petite. */
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text);
    text-decoration: none;
    cursor: pointer;
    /* Le cercle du survol, repris du site : il apparaît derrière l'icône. */
    border-radius: 50%;
    opacity: 0.5;
    transition: opacity 0.25s ease, background 0.2s ease;
}

.fond-outil:hover,
.fond-outil:focus-visible { opacity: 1; background: rgba(26, 26, 26, 0.06); }

:root[data-theme="dark"] .fond-outil:hover,
:root[data-theme="dark"] .fond-outil:focus-visible { background: rgba(255, 255, 255, 0.08); }

.fond-outil svg { width: 19px; height: 19px; }

/* Le bouton de langue emprunte tout son mécanisme à shared.css ; il ne reste
   qu'à lui rendre la taille de cible des deux autres. */
.fond-outil.lang-btn {
    width: 44px;
    height: 44px;
    font-size: 0.82rem;
    font-weight: 800;
    letter-spacing: 0.04em;
}

/* Le voile : sur mobile, les trois icônes n'ont plus la marge de gauche pour
   elles seules, elles passent au milieu et le contenu défile juste dessous.
   Cette bande floute ce qui passe derrière elles, et s'éteint vers le haut
   pour qu'aucune ligne franche ne traverse la page. Elle n'existe pas sur
   desktop, où les icônes sont dans la marge. */
.fond-voile { display: none; }

@media (max-width: 760px) {
    .fond-voile {
        display: block;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        height: 6rem;
        z-index: 19;
        pointer-events: none;
        -webkit-backdrop-filter: blur(7px);
        backdrop-filter: blur(7px);
        /* Le fondu se fait par le masque, pas par une couleur : la teinte du
           papier reste celle du thème en cours, sans être répétée ici. */
        -webkit-mask-image: linear-gradient(to top, #000 40%, transparent 100%);
        mask-image: linear-gradient(to top, #000 40%, transparent 100%);
    }

    /* Les trois icônes reviennent au centre ; la signature les suit, plus
       bas dans ce fichier — après les règles qu elle doit contredire. */
    .fond-outils {
        left: 0;
        right: 0;
        bottom: 0.75rem;
        justify-content: center;
    }

    /* En haut, le hero se contente de la moitié de son air : sinon la photo,
       la phrase et les quatre chiffres dépassent l'écran, et les chiffres
       arrivent sous le voile. En bas, il rend la hauteur d'une cible (44 px)
       plus l'épaisseur du voile, sans quoi le flou les mangerait. */
    .fond-hero {
        padding-top: clamp(1.5rem, 4vh, 2.5rem);
        padding-bottom: calc(6rem + 0.5rem);
    }
}

/* Les titres sont la cible des ancres : on leur laisse de l'air en haut
   plutôt que de les coller au bord de la fenêtre. */
.fond-page .fond-titre { scroll-margin-top: 35vh; }

html { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
}

/* === TITRE POSÉ SUR LA TRAME ==============================================
   Le titre s'écrit sur une rangée de points, et cette rangée est plus
   foncée que les autres. Les positions viennent de fond-titre.js. */
/* Le rail occupe la marge gauche : les titres commencent après lui, sinon
   le texte passe à travers les points sur mobile. */
.fond-page { --fond-marge: max(11rem, calc(50vw - 34rem)); }

@media (max-width: 760px) {
    /* Le rail se réduit à des points : la colonne peut se resserrer nettement.
       --fond-bord suit, sinon le point mordrait sur le texte. */
    .fond-page { --fond-marge: 2.25rem; --fond-bord: 0.75rem; }
}

.fond-page .fond-titre {
    position: absolute;
    left: var(--fond-marge);
    margin: 0;
    font-size: clamp(2.2rem, 5vw, 3.4rem);
    font-weight: 700;
    letter-spacing: -0.025em;
    /* Interligne à 1 : la ligne de base est alors prévisible, et c'est elle
       qu'on aligne sur la rangée de points. */
    line-height: 1;
}

/* La rangée assombrie : une seule ligne de points.

   La boîte doit être assez haute pour contenir ses points. Le masque qui
   perce la rangée sous le titre a un mask-clip à border-box par défaut :
   sur une boîte d'1 px, il rognait chaque point à une lamelle d'1 px et le
   reste disparaissait. D'où une hauteur de 16 px, avec le tracé recentré
   dedans (fond-titre.js pose le haut de la boîte à 8 px au-dessus de la
   rangée visée). */
.fond-page .fond-ligne {
    position: absolute;
    left: 0;
    right: 0;
    height: 16px;
    z-index: -1;
    color: var(--text);
    pointer-events: none;
}

/* display: block est indispensable, pas cosmétique. Un <svg> est inline :
   il se pose sur une ligne de texte, et le strut du line-height le décalait
   d'environ 18 px vers le bas — la rangée assombrie tombait alors sous la
   grille au lieu de coïncider avec elle. */
.fond-page .fond-ligne svg { display: block; }

/* === SECTIONS =============================================================
   Le contenu d'un titre. Posé en absolu comme lui, sur la même colonne ;
   fond-titre.js lui donne son top et repousse d'autant le titre suivant. */
.fond-page .fond-section {
    position: absolute;
    left: var(--fond-marge);
    right: var(--fond-marge);
}

/* === PROJETS ==============================================================
   Une ligne par projet : nom à gauche, phrase au milieu, flèche à droite.
   Les filets sont la seule règle tracée de la page — ailleurs, ce sont les
   points qui font les lignes. */
.fond-projet { border-bottom: 1px solid rgba(var(--text-rgb), 0.14); }
.fond-projet:first-child { border-top: 1px solid rgba(var(--text-rgb), 0.14); }

.fond-projet-tete {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) auto;
    align-items: center;
    gap: 1.5rem;
    width: 100%;
    padding: 1.6rem 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.fond-projet-nom {
    transition: color 0.25s ease;
    font-size: clamp(1.3rem, 2.1vw, 1.85rem);
    font-weight: 800;
    letter-spacing: -0.025em;
    line-height: 1.1;
}

.fond-projet-resume {
    transition: color 0.25s ease;
    font-size: 0.98rem;
    font-weight: 500;
    line-height: 1.4;
    color: rgba(var(--text-rgb), 0.5);
}

/* Un plus qui devient un moins : la barre verticale pivote d'un quart de tour
   et vient se confondre avec l'horizontale. Le signe change, le trait reste
   le même — c'est plus lisible qu'un symbole qui se substitue à un autre. */
.fond-plus-barre {
    transform-box: view-box;
    transform-origin: 12px 12px;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.fond-projet[data-ouvert] .fond-plus-barre { transform: rotate(90deg); }

.fond-projet-icone {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    opacity: 0.45;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
}

.fond-projet-icone svg { width: 20px; height: 20px; }

/* Au survol, la ligne visée avance d'un demi-pas vers la droite et les deux
   autres reculent. Rien n'apparaît, rien ne se brouille : c'est la liste
   entière qui désigne celle qu'on regarde.

   Le :has() est ici indispensable — il faut agir sur les lignes voisines de
   celle qu'on survole, ce qu'aucun sélecteur ne savait faire avant lui. Là où
   il manque, il ne se passe simplement rien.

   Rien de tout ceci au doigt : (hover: hover) écarte les écrans tactiles, où
   le survol est un état collé qui ne se retire jamais. */
.fond-projet-nom,
.fond-projet-resume,
.fond-projet-icone {
    transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease, color 0.25s ease;
}

@media (hover: hover) and (min-width: 761px) {
    .fond-projets:has(.fond-projet-tete:hover) .fond-projet:not(:has(.fond-projet-tete:hover)) .fond-projet-nom,
    .fond-projets:has(.fond-projet-tete:hover) .fond-projet:not(:has(.fond-projet-tete:hover)) .fond-projet-resume,
    .fond-projets:has(.fond-projet-tete:hover) .fond-projet:not(:has(.fond-projet-tete:hover)) .fond-projet-icone {
        opacity: 0.38;
    }

    .fond-projet-tete:hover .fond-projet-nom { transform: translateX(0.55rem); }
}

.fond-projet-tete:focus-visible .fond-projet-nom { color: var(--accent-ink); }

.fond-projet-tete:hover .fond-projet-icone,
.fond-projet-tete:focus-visible .fond-projet-icone { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    .fond-projet-nom,
    .fond-projet-resume,
    .fond-projet-icone { transition: none; }

    .fond-projet-tete:hover .fond-projet-nom { transform: none; }
}
.fond-projet[data-ouvert] .fond-projet-icone { opacity: 1; color: var(--accent); }

/* Ouvrir vers une hauteur inconnue : la seule façon de l'animer est de faire
   passer une piste de grille de 0fr à 1fr. L'enfant doit donc porter le
   overflow, sinon il déborde pendant tout le trajet. */
.fond-projet-corps {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}

.fond-projet[data-ouvert] .fond-projet-corps { grid-template-rows: 1fr; }

.fond-projet-interieur {
    overflow: hidden;
    display: grid;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1fr);
    gap: clamp(1.5rem, 4vw, 3.5rem);
    /* Replié, le contenu ne doit rien laisser dépasser — ni pixel, ni focus. */
    visibility: hidden;
    transition: visibility 0s linear 0.45s;
}

.fond-projet[data-ouvert] .fond-projet-interieur {
    visibility: visible;
    transition-delay: 0s;
}

.fond-projet-interieur > * { padding-bottom: 2.5rem; }
.fond-projet-interieur--sans-media { grid-template-columns: minmax(0, 1fr); }
.fond-projet-interieur--sans-media .fond-projet-texte { max-width: 46rem; }

.fond-projet-medias { display: grid; gap: 0.5rem; }
.fond-projet-medias--mosaique {
    position: relative;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* De quoi écrire « C'est moi ! » et sa flèche sous la dernière rangée. La
   réserve suit la taille de la note, qui suit la largeur de la fenêtre.
   Le sélecteur est plus lourd qu'il n'en a l'air parce qu'il doit passer
   devant celui qui rogne le premier enfant sous 900 px. */
.fond-projet-interieur > .fond-projet-medias--mosaique:first-child {
    padding-bottom: clamp(3.25rem, 6vw, 4.75rem);
}

/* La note vise la cinquième vignette — deuxième rangée, colonne du milieu.
   Elle s'écrit sous la mosaïque, sur le papier, et c'est sa flèche qui
   remonte vers la photo : posée dessus, elle se lisait mal, quel que soit le
   halo qu'on lui donnait. La bande qui l'accueille est le rembourrage bas de
   la mosaïque, élargi pour elle. */
.fond-note--moi {
    bottom: 0.15rem;
    left: 30%;
    color: var(--text);
    opacity: 0.85;
}

.fond-note--moi .fond-note-trait {
    width: 2.52em;
    height: 1.93em;
    margin: 0 0 0.07em 0.67em;
}

.fond-projet-medias img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 0.5rem;
}

.fond-projet-medias:not(.fond-projet-medias--mosaique) img { aspect-ratio: 16 / 9; }

.fond-projet-label {
    display: block;
    margin-bottom: 0.75rem;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: rgba(var(--text-rgb), 0.5);
}

.fond-projet-texte p {
    margin: 0 0 0.9rem;
    font-size: 0.98rem;
    line-height: 1.6;
    color: rgba(var(--text-rgb), 0.78);
}

.fond-preuves {
    margin: 1.1rem 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 0.4rem;
    font-size: 0.92rem;
    font-weight: 600;
}

.fond-preuves li { padding-left: 1rem; position: relative; }

.fond-preuves li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.62em;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.35;
}

@media (max-width: 900px) {
    .fond-projet-tete {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 0.4rem 1rem;
    }

    .fond-projet-nom { grid-column: 1; }
    .fond-projet-resume { grid-column: 1; }
    .fond-projet-icone { grid-column: 2; grid-row: 1 / 3; }

    .fond-projet-interieur { grid-template-columns: minmax(0, 1fr); }
    .fond-projet-interieur > *:first-child { padding-bottom: 1.25rem; }
}

/* === PARCOURS =============================================================
   Trois groupes, une ligne par entrée. La date tient une colonne fixe : les
   deux colonnes s'alignent d'un groupe à l'autre, ce qui rend le tout
   parcourable d'un coup d'œil. */
.fond-parcours { display: grid; gap: clamp(1.75rem, 3vw, 2.5rem); }

.fond-parcours-groupe h3 {
    margin: 0 0 0.75rem;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: rgba(var(--text-rgb), 0.45);
}

.fond-parcours-ligne {
    display: grid;
    grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
    gap: 0.5rem 1.5rem;
    padding: 0.6rem 0;
    border-top: 1px solid rgba(var(--text-rgb), 0.1);
    font-size: 0.95rem;
    line-height: 1.45;
}

.fond-dates {
    font-size: 0.85rem;
    font-weight: 600;
    color: rgba(var(--text-rgb), 0.5);
    font-variant-numeric: tabular-nums;
}

/* === COMPÉTENCES ==========================================================
   Quatre champs, puis la boîte à outils. */
.fond-competences { display: grid; gap: clamp(1.5rem, 3vw, 2.25rem); }

.fond-competences-intro,
.fond-boite-intro {
    max-width: 60ch;
    margin: 0;
    font-size: 1rem;
    line-height: 1.55;
    color: rgba(var(--text-rgb), 0.55);
}

.fond-boite-intro { margin-top: clamp(0.75rem, 2vw, 1.5rem); }

.fond-champs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(1.25rem, 3vw, 2.25rem);
}

.fond-champ h3 {
    margin: 0 0 0.4rem;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.fond-champ p {
    margin: 0;
    font-size: 0.94rem;
    line-height: 1.55;
    color: rgba(var(--text-rgb), 0.7);
}

.fond-boite { display: grid; gap: 1.1rem; }

.fond-boite-rang {
    display: grid;
    grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
    gap: 0.5rem 1.5rem;
    align-items: start;
}

.fond-boite-cat {
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    padding-top: 0.4rem;
    color: rgba(var(--text-rgb), 0.45);
}

.fond-boite-liste { display: flex; flex-wrap: wrap; gap: 0.4rem; }

.fond-boite-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.7rem;
    border: 1px solid rgba(var(--text-rgb), 0.12);
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 600;
}

/* Les marques sont monochromes : elles suivent l'encre de la page plutôt que
   d'y planter vingt-six couleurs. */
.fond-boite-item svg {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    fill: currentColor;
    opacity: 0.65;
}

.fond-boite-item svg.glyph { fill: none; stroke: currentColor; stroke-width: 1.7; }

@media (max-width: 760px) {
    .fond-champs { grid-template-columns: minmax(0, 1fr); }
    .fond-parcours-ligne,
    .fond-boite-rang { grid-template-columns: minmax(0, 1fr); }
    .fond-boite-cat { padding-top: 0; }
}

/* === PASSIONS =============================================================
   Deux cartes, l'une sous l'autre. Dans chacune : la photo à gauche, collée
   aux trois bords qu'elle touche, et le texte à droite. */
.fond-passions {
    display: grid;
    gap: 1.25rem;
}

.fond-passion {
    --rayon: 1.25rem;
    position: relative;
    display: grid;
    /* La photo mène la hauteur de la carte : plus elle est large, plus la
       carte est haute, puisque son rapport ne bouge pas. On lui donne donc
       une largeur bornée plutôt qu'une part du cadre — sans quoi la carte
       s'allongeait avec la fenêtre. */
    grid-template-columns: minmax(0, clamp(13rem, 30%, 20rem)) minmax(0, 1fr);
    align-items: stretch;
    margin: 0;
    border: 1px solid rgba(var(--text-rgb), 0.14);
    border-radius: var(--rayon);
    background-color: var(--bg);
    background-image: linear-gradient(rgba(var(--text-rgb), 0.035), rgba(var(--text-rgb), 0.035));
}

/* Le même semis que les blocs de contrat et de contact : dense sur deux
   coins opposés. Celui du haut à gauche passe sous la photo, qui est
   opaque ; il ne reste que celui du bas à droite, dans la colonne de texte.

   Un élément positionné passe devant ceux qui ne le sont pas, quel que soit
   l'ordre : sans z-index sur la photo et le texte, le semis leur passerait
   dessus. */
.fond-passion .fond-bloc-semis {
    border-radius: inherit;
    overflow: hidden;
}

.fond-passion img,
.fond-passion-texte { position: relative; z-index: 1; }

/* Rien entre la photo et le cadre : elle touche le bord et en reprend
   l'arrondi, sur ses quatre coins. Un pixel de moins que le cadre — le rayon
   intérieur d'une bordure d'un pixel — pour que les deux courbes restent
   concentriques.

   Le rapport donne à la photo sa hauteur, et c'est elle qui donne à la carte
   la sienne : le texte, plus court, se centre dans ce qui reste. La hauteur à
   100 % ne sert qu'ensuite, si l'autre carte de la paire est plus haute. */
.fond-passion img {
    display: block;
    width: 100%;
    height: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: calc(var(--rayon) - 1px);
}

.fond-passion-texte {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: clamp(1.25rem, 3vw, 2rem);
}

.fond-passion-texte h3 {
    margin: 0 0 0.4rem;
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.fond-passion-texte p {
    margin: 0;
    max-width: 46ch;
    font-size: 0.94rem;
    line-height: 1.55;
    color: rgba(var(--text-rgb), 0.7);
}

/* Trop étroit pour deux colonnes : la photo passe au-dessus du texte, dans
   l'ordre où ils sont écrits.

   Le seuil est haut — 1100 px — parce que ce n'est pas la place qui manque,
   c'est l'équilibre : sous cette largeur, le texte devient plus haut que la
   photo, la rangée s'étire à sa mesure et la photo, qui doit remplir la
   carte, se fait rogner d'autant. Empilées, les deux gardent leur taille. */
@media (max-width: 1100px) {
    .fond-passions { gap: 1rem; }

    .fond-passion { grid-template-columns: minmax(0, 1fr); }

    .fond-passion img { height: auto; }

    .fond-passion-texte { padding: 1.1rem; }
}

/* === AVIS =================================================================
   Un carrousel : une carte par avis, deux flèches en haut à droite. La carte
   suivante dépasse volontairement du cadre — c'est le seul indice qu'il y en
   a d'autres, et il vaut mieux qu'une pastille. */
.fond-avis { display: grid; gap: 1.25rem; }

.fond-avis-fleches {
    justify-self: end;
    display: flex;
    gap: 0.5rem;
    /* Le cadre du carrousel remonte sous elles pour laisser passer les
       notes : sans ce plan, il recouvrirait le bas de leur cible. */
    position: relative;
    z-index: 1;
}

.fond-avis-fleche {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 1px solid rgba(var(--text-rgb), 0.16);
    border-radius: 50%;
    background: none;
    color: var(--text);
    cursor: pointer;
    opacity: 0.55;
    transition: opacity 0.2s ease, background 0.2s ease;
}

.fond-avis-fleche:hover,
.fond-avis-fleche:focus-visible {
    opacity: 1;
    color: var(--accent-ink);
    border-color: rgba(var(--text-rgb), 0.28);
    background: rgba(var(--text-rgb), 0.05);
}
.fond-avis-fleche svg { width: 18px; height: 18px; }

/* La carte qui dépasse est tranchée net par le bord du cadre. On la laisse
   plutôt se dissoudre dans la page : le fondu dit « ça continue » là où la
   coupe disait « c'est cassé ». */
.fond-avis-cadre {
    overflow: hidden;
    /* Le rembourrage agrandit la zone visible sans rien déplacer — la marge
       négative le reprend. C'est ce qui laisse les notes manuscrites
       dépasser en haut et en bas des cartes au lieu d'être tranchées.

       Plus haut que large : une note écrite au-dessus du bord monte de
       0,85 em, et l'encre monte encore au-delà de sa boîte, parce que
       line-height: 1 arrête la boîte à la hauteur de l'em tandis que les
       hampes de la Cedarville la dépassent. Sous les 20 px d'avant, le L de
       « Lindt » était tranché net. */
    padding: 2.25rem 0 1.25rem;
    margin: -2.25rem 0 -1.25rem;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 5.5rem), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 5.5rem), transparent 100%);
}

.fond-avis-piste {
    display: flex;
    align-items: stretch;
    gap: 1.25rem;
    transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
    will-change: transform;
}

.fond-avis-piste.sans-animation { transition: none; }

.fond-avis-carte {
    position: relative;
    flex: 0 0 auto;
    /* Assez large pour se lire, assez étroite pour que la suivante dépasse. */
    width: min(62%, 34rem);
    margin: 0;
    padding: clamp(1.25rem, 2.5vw, 1.75rem);
    border: 1px solid rgba(var(--text-rgb), 0.14);
    border-radius: 1rem;
    /* Opaque, et pas juste teintee : les points du semis traversaient la
       carte et se melaient au texte. */
    background-color: var(--bg);
    background-image: linear-gradient(rgba(var(--text-rgb), 0.022), rgba(var(--text-rgb), 0.022));
}

.fond-avis-tete {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin-bottom: 1rem;
}

.fond-avis-tete img {
    width: 46px;
    height: 46px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

.fond-avis-role {
    display: block;
    font-size: 0.76rem;
    font-weight: 600;
    line-height: 1.3;
    color: rgba(var(--text-rgb), 0.5);
}

.fond-avis-tete a {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin: 0.1rem 0;
    color: var(--text);
    text-decoration: none;
    font-size: 1rem;
    font-weight: 700;
}

/* Le glyphe LinkedIn dit que le nom mène quelque part. */
.fond-avis-li {
    width: 14px;
    height: 14px;
    fill: currentColor;
    opacity: 0.45;
    transition: opacity 0.2s ease;
}

.fond-avis-tete a:hover .fond-avis-li,
.fond-avis-tete a:focus-visible .fond-avis-li { opacity: 1; }

.fond-avis-tete a:hover,
.fond-avis-tete a:focus-visible { text-decoration: underline; text-underline-offset: 0.2em; }

.fond-avis-carte blockquote {
    margin: 0;
    font-size: 0.94rem;
    line-height: 1.6;
    color: rgba(var(--text-rgb), 0.78);
}

.fond-avis-carte blockquote p { margin: 0 0 0.8rem; }
.fond-avis-carte blockquote p:last-child { margin-bottom: 0; }

/* Les avis n'ont pas la même longueur, et les cartes ont toutes la hauteur de
   la plus haute : le plus court est composé un cran plus grand, ce qui
   rattrape une partie du vide sans toucher au texte. */
.fond-avis-carte--court blockquote { font-size: 1.08rem; line-height: 1.65; }

/* === NOTES MANUSCRITES ====================================================
   Une deuxième couche, posée sur la page comme on annote une feuille déjà
   imprimée : toujours en absolu, jamais dans le flux, jamais dans l'arbre
   d'accessibilité. Rien de ce qui suit ne tient la mise en page — retirez le
   bloc entier et la section reste exactement la même.

   Quatre traitements différents, un par recommandation : une flèche, un
   cercle, une note en marge, un astérisque. C'est un essai : ils sont là pour
   être comparés, pas pour cohabiter éternellement. */
.fond-note {
    position: absolute;
    z-index: 2;
    /* Une note ne se clique pas et n'intercepte rien : le lien LinkedIn
       qu'elle recouvre reste cliquable. */
    pointer-events: none;
    font-family: 'Cedarville Cursive', 'Segoe Script', cursive;
    /* Une note tient sur une ligne et ne se coupe jamais. Sa taille suit
       donc la largeur de la fenêtre : écrite trop grand sur un écran
       étroit, elle sortait de sa carte par la gauche et le cadre du
       carrousel lui tranchait sa première lettre.

       Tout ce qui la compose est exprimé en em : le trait, la flèche,
       l'écart au bord. Une note est un seul objet, écrit d'une seule main —
       elle grandit et rapetisse d'un bloc. */
    font-size: clamp(0.9rem, 1.5vw + 0.2rem, 1.35rem);
    line-height: 1;
    white-space: nowrap;
    /* La même encre que la page, juste plus légère : une note écrite à la
       main n'a pas de raison d'avoir sa couleur à elle. */
    color: rgba(var(--text-rgb), 0.62);
}

.fond-note-texte { display: inline-block; }

.fond-note-trait {
    display: block;
    /* Le trait est tracé à la même encre que le mot, et de la même épaisseur
       apparente que la plume. */
    color: inherit;
    overflow: visible;
}

/* 1 — La flèche. La note s'écrit au-dessus du bord haut et son trait
   redescend vers le nom. */
.fond-note--fleche {
    top: -0.85em;
    right: 0.74em;
    text-align: right;
    transform: rotate(-2deg);
}

.fond-note--fleche .fond-note-trait {
    width: 6.3em;
    /* Assez court pour que la pointe s arrete dans le blanc au-dessus de la
       citation : posee un cran plus bas, elle barrait la premiere ligne. */
    height: 2.96em;
    margin: 0.11em 0.55em 0 auto;
}

/* 2 — Le mot entouré. Le cercle est tracé par-dessus la note elle-même : il
   la déborde de tous les côtés, comme un trait fait après coup. */
.fond-note--cercle {
    top: 0.52em;
    right: 1.19em;
    transform: rotate(-2deg);
}

.fond-note--cercle .fond-note-trait {
    position: absolute;
    top: -0.37em;
    right: -1em;
    bottom: -0.33em;
    left: -0.78em;
    width: auto;
    height: auto;
}

/* 3 — La note en marge, tournée, qui déborde au-dessus du bord haut gauche. */
.fond-note--marge {
    top: -0.78em;
    left: 1.04em;
    transform: rotate(-4deg);
}

.fond-note--marge .fond-note-trait {
    width: 11.1em;
    height: 0.48em;
    margin-top: 0.04em;
}

/* 4 — L'astérisque et son mot, sur la ligne du nom. */
.fond-note--etoile {
    top: 0.37em;
    right: 1em;
    display: flex;
    align-items: center;
    gap: 0.26em;
    transform: rotate(2.5deg);
}

.fond-note--etoile .fond-note-trait {
    width: 0.85em;
    height: 0.85em;
    flex-shrink: 0;
}

/* Sur mobile, le carrousel sort de la colonne et va d'un bord à l'autre de
   l'écran : la carte suivante déborde à droite, et celle qu'on quitte s'en va
   par la gauche. C'est le rembourrage de la piste, et non la marge de la
   section, qui aligne la carte active sur le reste de la page — sinon la
   translation calculée en JS décalerait tout d'autant. */
@media (max-width: 760px) {
    .fond-page .fond-avis { left: 0; right: 0; }

    .fond-avis-fleches { padding-right: var(--fond-marge); }

    .fond-avis-piste { padding-left: var(--fond-marge); }

    .fond-avis-carte { width: 82%; }

    /* Le fondu se resserre : à 88 px il aurait avalé tout le débord. */
    .fond-avis-cadre {
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent 100%);
        mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent 100%);
    }
}

/* === PIED DE PAGE =========================================================
   « Ce que je recherche » et « Parlons-en » réunis en un seul bloc, posé en
   fin de colonne. fond-titre.js lui donne son top et cale la hauteur de la
   page dessus.

   Il suit la colonne de contenu à gauche plutôt que le bord du viewport :
   sinon le rail, qui reste fixe et centré, passerait par-dessus. */
.fond-contact { display: grid; gap: clamp(1.25rem, 2.5vw, 1.75rem); }

.fond-contact-intro {
    max-width: 42ch;
    margin: 0;
    font-size: 1rem;
    line-height: 1.55;
    color: rgba(var(--text-rgb), 0.55);
}

/* Deux blocs distincts, l'un sur l'autre : ce qu'il cherche, puis comment
   l'atteindre. Leur fond est opaque, et pas seulement teinté : c'est ce qui
   arrête le semis de la page, dont les points traversaient le bloc. */
.fond-bloc {
    position: relative;
    padding: clamp(1.75rem, 3.5vw, 2.5rem);
    border: 1px solid rgba(var(--text-rgb), 0.14);
    border-radius: 1.25rem;
    background-color: var(--bg);
    background-image: linear-gradient(rgba(var(--text-rgb), 0.035), rgba(var(--text-rgb), 0.035));
    /* Le semis du bloc est rogné par les angles arrondis. */
    overflow: hidden;
}

/* Pas de z-index négatif ici : il ferait passer le semis sous le fond du bloc,
   où il disparaîtrait. Il reste au-dessus, et c'est le contenu qui monte. */
.fond-bloc-semis {
    position: absolute;
    inset: 0;
    color: var(--text);
    pointer-events: none;
}

.fond-bloc-semis svg { display: block; }

/* Le même semis sur les cartes de recommandation. Il ne peut pas être rogné
   par la carte — overflow: hidden y couperait les notes manuscrites, qui
   débordent volontairement — donc c'est le semis lui-même qui reprend les
   angles de la carte et se rogne tout seul. */
.fond-avis-carte .fond-bloc-semis {
    border-radius: inherit;
    overflow: hidden;
}

.fond-avis-tete,
.fond-avis-carte blockquote { position: relative; z-index: 1; }

/* Chaque champ d'expertise a son propre contenant — quatre blocs, pas un
   seul qui les rassemble. Sans semis : le motif diagonal appartient au bloc
   de contact. */
.fond-champ { padding: clamp(1.1rem, 2.5vw, 1.6rem); }

.fond-pied-specs,
.fond-pied-liens { position: relative; z-index: 1; }

.fond-pied-specs,
.fond-pied-liens {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1.5rem clamp(1rem, 3vw, 2.5rem);
    margin: 0;
}

/* Le libellé recule, la valeur porte. Même traitement dans les deux rangées
   pour qu'elles se lisent comme un seul tableau. */
.fond-pied-specs dt,
.fond-lien-label {
    display: block;
    margin-bottom: 0.4rem;
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: rgba(var(--text-rgb), 0.45);
}

.fond-pied-specs dd {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.4;
}

.fond-pied-liens a {
    display: block;
    color: var(--text);
    text-decoration: none;
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.4;
}

/* Au survol, l'icône se déplie à gauche et pousse la valeur. Elle est repliée
   par une largeur nulle plutôt que masquée : c'est ce qui rend le décalage
   du texte continu au lieu de brutal. */
.fond-lien-valeur {
    display: inline-flex;
    align-items: center;
}

/* Sans min-width, un enfant de flex ne descend pas sous sa largeur
   min-content : l'adresse mail débordait de sa colonne au lieu de se couper.

   Elle se coupe maintenant au seul endroit qui se lit — devant l'arobase, où
   le HTML pose un <wbr>. « anywhere » l'aurait coupée avant, au dernier
   caractère qui tenait dans la colonne ; « break-word » ne sert que de
   dernier recours, si même « pierregumilar » ne tenait pas. */
.fond-pied-liens b {
    min-width: 0;
    overflow-wrap: break-word;
}

.fond-lien-icone {
    width: 0;
    height: 16px;
    flex-shrink: 0;
    opacity: 0;
    transform: translateX(-4px);
    transition: width 0.45s cubic-bezier(0.16, 1, 0.3, 1),
                margin-right 0.45s cubic-bezier(0.16, 1, 0.3, 1),
                opacity 0.35s ease, transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}

.fond-lien-icone--plein { fill: currentColor; }

.fond-pied-liens a:hover .fond-lien-icone,
.fond-pied-liens a:focus-visible .fond-lien-icone {
    color: var(--accent-ink);
    width: 16px;
    margin-right: 0.4rem;
    opacity: 1;
    transform: translateX(0);
}

/* Souligné en permanence : rien d'autre, dans le bloc, ne dit que ces quatre
   lignes sont cliquables. Le trait reste plus clair que le texte pour ne pas
   alourdir, et se colore au survol. Seule la valeur le porte — le libellé de
   la colonne n'est pas le lien. */
.fond-pied-liens b {
    font-weight: 600;
    text-decoration: underline;
    text-decoration-color: rgba(var(--text-rgb), 0.32);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.25em;
    transition: text-decoration-color 0.25s ease;
}

.fond-pied-liens a:hover b,
.fond-pied-liens a:focus-visible b { text-decoration-color: var(--accent-ink); }

@media (prefers-reduced-motion: reduce) {
    .fond-lien-icone { transition: none; }
}

/* Les drapeaux tiennent la place des noms de pays. */
.fond-drapeaux { display: inline-flex; gap: 0.35rem; vertical-align: -0.15em; }

.fond-drapeau {
    width: 21px;
    height: 14px;
    border-radius: 2px;
    display: block;
    box-shadow: 0 0 0 1px rgba(var(--text-rgb), 0.12) inset;
}

.fond-mobilite-note {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: rgba(var(--text-rgb), 0.6);
}

/* La signature vit dans le coin de la fenêtre, pas dans le bloc, et ne se
   montre qu'une fois le bas de la page atteint — fond-rail.js pose la classe.
   Elle reste discrète : c'est un crédit, pas une information. */
/* Meme hauteur de boite et meme bas que les outils du coin oppose : c est
   ce qui met les deux sur le meme axe. */
.fond-signature {
    position: fixed;
    right: var(--fond-bord);
    bottom: 1.25rem;
    min-height: 44px;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin: 0;
    font-size: 0.72rem;
    font-weight: 600;
    color: rgba(var(--text-rgb), 0.4);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease;
}

/* Tant qu'elle est invisible, elle ne doit rien intercepter — d'où le
   pointer-events: none de la règle de base, qu'on lui rend une fois
   apparue, puisqu'elle mène maintenant quelque part. */
.fond-signature.visible { opacity: 1; pointer-events: auto; }

.fond-signature a {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    color: inherit;
    text-decoration: none;
    transition: color 0.25s ease;
}

.fond-signature a:hover { color: rgba(var(--text-rgb), 0.75); }
.fond-signature a:hover img { opacity: 0.9; }

/* Le logotype complet, pas la seule initiale. */
.fond-signature img {
    height: 15px;
    width: auto;
    display: block;
    opacity: 0.65;
    transition: opacity 0.25s ease;
}

@media (prefers-reduced-motion: reduce) {
    .fond-signature { transition: none; }
}

/* Sur mobile, la signature quitte le coin droit : elle se pose au centre,
   juste au-dessus des trois icônes. */
@media (max-width: 760px) {
    .fond-signature {
        left: 0;
        right: 0;
        bottom: calc(0.75rem + 44px + 0.25rem);
        min-height: 0;
        justify-content: center;
    }
}

@media (max-width: 900px) {
    .fond-pied-specs,
    .fond-pied-liens { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Le champ de points : un seul dessin pour toute la page, sans masque —
   c'est le tracé lui-même qui sait où il est dense et où il est clair. */
.fond-page .points-champ {
    position: absolute;
    inset: 0;
    z-index: -1;
    color: var(--text);
    pointer-events: none;
}

.fond-page .points-champ svg { display: block; overflow: visible; }

/* ============================================================
   Les apparitions
   ============================================================

   Deux règles, et une seule idée : ce qui n'a pas encore été atteint est
   transparent et posé un cheveu plus bas ; le script lui retire ce retard
   quand son tour vient, en décalant les voisins d'un souffle.

   Tout dépend de .fond-anime, posée sur <html> par le script en tête de
   document — donc avant le premier rendu, sinon la page apparaîtrait avant de
   se cacher pour entrer. Sans JavaScript, ou si l'on demande moins de
   mouvement, la classe n'est jamais posée et rien de ce qui suit ne
   s'applique : la page s'affiche entière, comme avant.

   La liste est enfermée dans :where() pour n'avoir aucun poids : quel que
   soit le sélecteur qu'on y ajoute — même un enfant direct, qui en pèserait
   trois — l'état révélé le bat toujours. Sans cela, .fond-contact > .fond-bloc
   restait invisible pour l'éternité. */
.fond-anime :where(
    .fond-hero-photo,
    .fond-hero-phrase,
    .fond-kpi > *,
    .fond-titre,
    .fond-ligne,
    .fond-projet,
    .fond-parcours-groupe,
    .fond-competences-intro,
    .fond-champ,
    .fond-boite-intro,
    .fond-boite-rang,
    .fond-avis-fleches,
    .fond-avis-cadre,
    .fond-passion,
    .fond-contact-intro,
    .fond-contact > .fond-bloc,
    .fond-outils,
    .fond-voile
) {
    opacity: 0;
    transform: translateY(var(--anim-monte, 0.85rem));
    transition: opacity 0.6s ease var(--anim-retard, 0s),
                transform 0.6s cubic-bezier(0.16, 1, 0.3, 1) var(--anim-retard, 0s);
}

/* Un titre et sa rangée assombrie sont posés au pixel près l'un sur l'autre,
   sur une rangée du champ ; le voile est collé au bas de l'écran. Ceux-là ne
   peuvent que se révéler sur place — les faire glisser, c'est refaire
   exactement ce saut de ligne qu'on cherchait à supprimer. */
.fond-anime :where(.fond-titre, .fond-ligne, .fond-voile) { --anim-monte: 0px; }

.fond-anime [data-anim="vu"] { opacity: 1; --anim-monte: 0px; }

/* Un KPI est en display: contents sur desktop — il n'a pas de boîte à animer.
   Ce sont ses trois lignes qui entrent, sur le retard qu'il leur transmet. */
.fond-anime .fond-kpi[data-anim="vu"] > * { opacity: 1; }

/* Le papier arrive le premier, et vite : un seul fondu sur tout le champ,
   plutôt que sur ses milliers de points. C'est une seule couche à composer,
   le navigateur ne repeint rien. */
.fond-anime .points-champ {
    opacity: 0;
    transition: opacity 0.35s ease var(--anim-retard, 0s);
}

.fond-anime .points-champ[data-anim="vu"] { opacity: 1; }

/* Le rail est centré par un transform à lui : lui en poser un autre le
   décentrerait. Il se contente donc d'apparaître. */
.fond-anime .fond-rail {
    opacity: 0;
    transition: opacity 0.6s ease var(--anim-retard, 0s);
}

.fond-anime .fond-rail[data-anim="vu"] { opacity: 1; }

/* La phrase du hero s'écrit lettre à lettre. Chacune reste en display: inline
   — un inline ne se laisse pas déplacer par transform, mais il se laisse
   effacer par opacity, et c'est tout ce qu'on lui demande. C'est aussi ce qui
   fait qu'un lecteur d'écran continue de lire la phrase d'un trait.

   Le fondu de chaque lettre est court devant le temps que met la vague à
   traverser la phrase : c'est ce rapport-là qui rend le passage lisible.
   Allongé, on ne voit plus qu'un bloc qui s'éclaircit d'un coup. */
.fond-anime .fond-lettre {
    opacity: 0;
    transition: opacity 0.18s ease var(--anim-retard, 0s);
}

.fond-anime .fond-lettre[data-anim="vu"] { opacity: 1; }


/* === AU-DELA DE 1600 ======================================================
   Jusqu'ici, la page cessait de reagir bien avant les grands ecrans : les
   vingt et un clamp de ce fichier atteignent tous leur plafond entre 1000 et
   1516 px, et le media query le plus large valait 1100. Sur un 2560, la
   colonne occupait donc 43 % de la largeur, figee, au milieu de deux bandes
   vides de 736 px.

   Le raccord est exact, et ce n'est pas un hasard : a 1600 px, 1rem et 1vw
   valent tous deux 16 px. Chaque valeur reprend donc en vw le coefficient
   qu'elle avait en rem, et repart de son ancien plafond sans le moindre saut.
   La colonne suit la meme regle, en clamp plutot qu'en marge, pour rejoindre
   68rem pile a 1600.

   Le corps de texte n'est pas invite : il reste a sa taille. Un 4K a 150 %
   rend deja un 16 px a sa taille apparente normale, et tous les blocs de
   texte sont bornes en ch, donc la ligne la plus longue de la page ne bouge
   pas d'un signe. C'est la mise en page qui respire, pas la lecture. */
@media (min-width: 1600px) {
    .fond-page {
        --fond-colonne: clamp(68rem, calc(68rem + (100vw - 1600px) * 0.25), 82rem);
        --fond-marge: max(11rem, calc((100vw - var(--fond-colonne)) / 2));
    }

    .fond-hero-photo  { width: clamp(12rem, 12vw, 18rem); }
    .fond-hero-phrase { font-size: clamp(1.8rem, 1.8vw, 2.45rem); }
    .fond-kpi b       { font-size: clamp(2.1rem, 2.1vw, 2.9rem); }

    .fond-page .fond-titre { font-size: clamp(3.4rem, 3.4vw, 4.6rem); }

    /* Le rail est fixe au bord : si tout grandit et pas lui, il se detache de
       la page au lieu de l'accompagner. */
    .fond-rail a { font-size: clamp(0.82rem, 0.82vw, 0.98rem); }
}
