/* ============================================================================
   Manon Vanbastelaer — CV, version onepage
   ----------------------------------------------------------------------------
   Même grammaire typographique et chromatique que cv.magalicontrino.com :
   papier gris clair, capitales très espacées, photos qui se dévoilent par le
   bas, une seule courbe d'assouplissement pour tout le site. Strictement
   monochrome : noir, blanc et deux gris, aucune couleur d'accent.

   Sommaire
     1.  Jetons et polices
     2.  Base
     3.  Rideau d'entrée
     4.  Jauge de défilement
     5.  Navigation par points
     6.  Grammaire d'apparition (reveal / unmask / split)
     7.  Accueil
     8.  Bande de repères
     9.  Chapitres
     10. Lignes — formation et expérience
     12. Filtres et grille — techniques
     13. Menu — plats signature
     14. Compétences et disponibilités
     15. Contact
     16. Visionneuse
     17. Mouvement réduit
     18. Impression
   ============================================================================ */

/* ------------------------------------------------------ 1. Jetons, polices - */

@font-face { font-family: 'Bai Jamjuree'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('assets/fonts/bai-jamjuree-700-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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Bai Jamjuree'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('assets/fonts/bai-jamjuree-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

@font-face { font-family: 'Raleway'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('assets/fonts/raleway-variable-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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Raleway'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('assets/fonts/raleway-variable-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

@font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 200; font-display: swap;
  src: url('assets/fonts/source-sans-pro-200-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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 300; font-display: swap;
  src: url('assets/fonts/source-sans-pro-300-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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 300; font-display: swap;
  src: url('assets/fonts/source-sans-pro-300-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('assets/fonts/source-sans-pro-600-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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('assets/fonts/source-sans-pro-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 900; font-display: swap;
  src: url('assets/fonts/source-sans-pro-900-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+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 900; font-display: swap;
  src: url('assets/fonts/source-sans-pro-900-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

:root {
  --paper:      #fafaf9;
  --white:      #ffffff;
  --black:      #000000;
  --ink:        #474747;
  --ink-strong: #1c1a1a;
  --muted:      #919191;
  --rule:       rgba(28, 26, 26, .11);

  /* Noir et blanc pour le texte. La couleur est réservée aux carrés des pictos,
     une teinte par chapitre : elle sert de repère, pas de décor. Toutes sont
     assez sombres pour porter un picto blanc. */
  --mark:      #1c1a1a;

  --c-formation:  #e0356f;
  --c-experience: #5b4bdb;
  --c-techniques: #0f8f8f;

  /* Formes : cartes très arrondies, boutons en gélule. C'est ce qui adoucit
     l'ensemble plus sûrement que la couleur. */
  --radius:    22px;
  --radius-sm: 14px;
  --pill:      999px;

  --display: 'Bai Jamjuree', sans-serif;
  --label:   'Raleway', sans-serif;
  --body:    'Source Sans Pro', sans-serif;

  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-soft: cubic-bezier(.4, 0, .2, 1);

  --gut: clamp(1.25rem, 5vw, 6rem);
  --max: 78rem;

  /* Incrément d'échelonnement, relu par data-delay. */
  --step: 90ms;
}

/* --------------------------------------------------------------- 2. Base - */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: auto; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-weight: 300;
  font-size: clamp(1rem, .95rem + .25vw, 1.125rem);
  line-height: 1.75;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

body.is-locked { overflow: hidden; }

h1, h2, h3, h4, p, ul, ol, dl, dd, figure, blockquote { margin: 0; padding: 0; }
ul, ol { list-style: none; }
img { display: block; max-width: 100%; }
button { font: inherit; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
  border-radius: 2px;
}

/* Étiquette en capitales très espacées — l'accent typographique du site. */
.eyebrow, .tag, .sub, .chapter__num, .avail__title {
  font-family: var(--label);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .36em;
}

/* Lien : le trait se déroule depuis la gauche au survol. */
.link {
  display: inline-block;
  margin-top: 1.1rem;
  font-size: .92em;
  text-decoration: none;
  position: relative;
  padding-bottom: 2px;
}
.link::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .5s var(--ease);
}
.link:hover::after, .link:focus-visible::after { transform: scaleX(1); transform-origin: left; }

/* ---------------------------------------------------- 3. Rideau d'entrée - */

.curtain {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--white);
  transition: transform 1s var(--ease), visibility 0s linear 1s;
  /* Filet : le rideau se lève tout seul au bout de 5 s même si le script n'a
     jamais posé `is-open`. Rien ne doit pouvoir laisser le CV sous un aplat
     noir. */
  animation: curtain-failsafe 0s linear 5s forwards;
}
@keyframes curtain-failsafe { to { transform: translateY(-101%); visibility: hidden; } }
body.is-open .curtain { transform: translateY(-101%); visibility: hidden; }

/* ------------------------------------------------- 4. Jauge de défilement - */

.progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 60;
  pointer-events: none;
}
.progress__bar {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--mark);
  transform: scaleX(0);
  transform-origin: left;
  will-change: transform;
}

/* ------------------------------------------------ 5. Navigation par points - */

.dots {
  position: fixed;
  right: clamp(.75rem, 2vw, 1.75rem);
  top: 50%;
  transform: translateY(-50%);
  z-index: 60;
  opacity: 0;
  transition: opacity .6s var(--ease);
}
body.is-open .dots { opacity: 1; }

.dots ul { display: flex; flex-direction: column; gap: .9rem; align-items: flex-end; }

.dots a {
  display: flex;
  align-items: center;
  gap: .6rem;
  text-decoration: none;
  font-family: var(--label);
  font-weight: 700;
  font-size: .58rem;
  text-transform: uppercase;
  letter-spacing: .22em;
  color: var(--ink);
}
/* L'intitulé n'apparaît qu'au survol ; le point, lui, est toujours là. */
.dots a span {
  opacity: 0;
  transform: translateX(.5rem);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.dots a:hover span, .dots a:focus-visible span { opacity: 1; transform: none; }

.dots a::after {
  content: '';
  width: 7px; height: 7px;
  border-radius: 50%;
  border: 1px solid var(--ink);
  background: transparent;
  transition: background .4s var(--ease), transform .4s var(--ease), border-color .4s var(--ease);
}
.dots a.is-active::after { background: var(--ink); transform: scale(1.45); }

@media (max-width: 700px) { .dots { display: none; } }

/* ------------------------------------------------ 5 bis. Retour en haut - */

.totop {
  position: fixed;
  right: clamp(.75rem, 2vw, 1.75rem);
  bottom: clamp(1rem, 3vh, 2.25rem);
  z-index: 60;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid rgba(71, 71, 71, .22);
  border-radius: 50%;
  background: var(--white);
  color: var(--ink-strong);
  box-shadow: 0 2px 14px rgba(28, 26, 26, .09);

  opacity: 0;
  visibility: hidden;
  transform: translateY(.75rem);
  transition:
    opacity .5s var(--ease), transform .5s var(--ease),
    visibility 0s linear .5s,
    background .4s var(--ease), color .4s var(--ease), border-color .4s var(--ease);
}
.totop.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity .5s var(--ease), transform .5s var(--ease),
    visibility 0s linear 0s,
    background .4s var(--ease), color .4s var(--ease), border-color .4s var(--ease);
}

.totop svg {
  width: 1.05rem;
  height: 1.05rem;
  fill: currentColor;
  transform: rotate(90deg);
  transition: transform .45s var(--ease);
}
.totop:hover, .totop:focus-visible { background: var(--ink-strong); color: var(--paper); border-color: var(--ink-strong); }
.totop:hover svg, .totop:focus-visible svg { transform: rotate(90deg) translateX(.18rem); }

/* ------------------------------------- 6. Grammaire d'apparition (reveal) - */

/* IMPORTANT — tous les états de départ sont sous `html.anim`, classe posée par
   app.js. Sans script, ou si le script casse avant cette ligne, rien n'est
   masqué et le CV se lit intégralement. Un CV ne doit jamais dépendre d'une
   animation pour être visible. */

.anim [data-reveal] {
  opacity: 0;
  transform: translateY(2.2rem);
  transition:
    opacity 1s var(--ease) var(--d, 0ms),
    transform 1s var(--ease) var(--d, 0ms);
}
.anim [data-reveal].is-in { opacity: 1; transform: none; }

/* Image : la photo se dévoile par le bas dans son cadre. Le masque porte sur
   l'IMAGE, jamais sur le cadre observé — un élément `clip-path: inset(0 0 100%)`
   a une surface rendue nulle et ne serait jamais détecté comme visible. */
.anim [data-unmask] img {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.4s var(--ease);
}
.anim [data-unmask].is-in img { clip-path: inset(0 0 0 0); }

/* Titre découpé en mots puis en lettres par app.js. Le mot reste insécable, la
   ligne ne peut donc rompre qu'entre deux mots. */
.split-word { display: inline-block; white-space: nowrap; }
.split-char { display: inline-block; }
.anim .split-char {
  opacity: 0;
  transform: translateY(.9em) rotate(3deg);
  transition:
    opacity .9s var(--ease) calc(var(--i) * 28ms),
    transform .9s var(--ease) calc(var(--i) * 28ms);
}
.anim .is-in .split-char { opacity: 1; transform: none; }

/* Aplat que l'on aperçoit sous la photo pendant qu'elle se dévoile, et qui
   tient sa place avant qu'elle n'arrive. */
/* Une encre très diluée plutôt qu'un gris fixe : le cadre s'assombrit
   légèrement quelle que soit la couleur de la section qui le porte. */
figure.media { overflow: hidden; background: rgba(28, 26, 26, .035); position: relative; }

/* Les cadres autonomes s'arrondissent comme les cartes. Ceux qui sont DANS une
   carte n'y touchent pas : la carte les découpe déjà, et arrondir les quatre
   coins d'une image collée en haut d'un bloc lui décollerait le bas. */
.media--tall { border-radius: var(--radius); }
figure.media img { width: 100%; height: 100%; object-fit: cover; will-change: transform; }

/* Photo cliquable : le curseur et une légère montée l'annoncent. */
figure.media img[data-zoom] { cursor: zoom-in; }

/* ------------------------------------------------------------ 7. Accueil - */

.intro {
  min-height: 100svh;
  display: grid;
  grid-template-columns: 1fr minmax(0, 42%);
  align-items: center;
  /* `align-content` centre la rangée dans la hauteur restante ; sans lui, la
     grille cale son contenu en haut et le blanc s'accumule sous les boutons. */
  align-content: center;
  gap: clamp(1.5rem, 5vw, 5rem);
  /* Marges haute et basse identiques : un centrage optique se fait avec des
     valeurs symétriques, pas avec un haut deux fois plus grand que le bas. */
  padding: clamp(2.5rem, 7vh, 6rem) var(--gut);
  position: relative;
}

/* `min-width: 0` : sans lui, un élément de grille refuse de descendre sous la
   largeur de son contenu. Un mot long comme « VANBASTELAER » élargissait alors
   la colonne au-delà de la page, qui se mettait à déborder latéralement. */
.intro__text { max-width: 34rem; min-width: 0; margin-left: auto; margin-right: clamp(0rem, 2vw, 3rem); }

.mark {
  display: inline-block;
  width: clamp(1.6rem, 4vh, 2.1rem);
  margin-bottom: clamp(.6rem, 1.8vh, 1.5rem);
  color: var(--mark);
}
.mark svg { width: 100%; height: auto; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; display: block; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.eyebrow { font-size: .68rem; color: var(--ink); margin-bottom: clamp(.7rem, 2.1vh, 1.6rem); }

.intro__name {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.6rem, 7.4vw, 6rem);
  line-height: .95;
  letter-spacing: -.02em;
  color: var(--ink-strong);
  text-transform: uppercase;
  margin-bottom: clamp(.8rem, 2.5vh, 2.4rem);
}

.intro__roles {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.4rem, 3vw, 2.2rem);
  line-height: 1.15;
  color: var(--ink);
  margin-bottom: clamp(.7rem, 2.1vh, 2rem);
}

.intro__pitch {
  max-width: 30rem;
  font-size: clamp(.92rem, .88rem + .2vh, .98rem);
  line-height: 1.65;
  margin-bottom: clamp(.9rem, 2.6vh, 2.5rem);
}
.intro__pitch strong { font-weight: 600; color: var(--ink-strong); }

.intro__nav { display: flex; flex-wrap: wrap; gap: .55rem; }
.intro__nav a {
  display: block;
  font-family: var(--label);
  font-weight: 700;
  font-size: .62rem;
  text-transform: uppercase;
  letter-spacing: .26em;
  text-decoration: none;
  padding: .85rem 1.5rem;
  border: 1px solid var(--rule);
  border-radius: var(--pill);
  background: transparent;
  color: var(--ink);
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
/* Le fond monte depuis le bas et le texte s'inverse. */
.intro__nav a::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink-strong);
  transform: translateY(101%);
  transition: transform .55s var(--ease);
}
.intro__nav a:hover, .intro__nav a:focus-visible { color: var(--white); border-color: var(--ink-strong); }
.intro__nav a:hover::before, .intro__nav a:focus-visible::before { transform: none; }

.intro__portrait { height: min(70svh, 42rem); }
.media--tall { height: 100%; }
/* Le cadre du portrait est nettement plus haut que large : un recadrage centré
   couperait le visage au niveau du front. On remonte le point d'ancrage. */
.media--tall img { object-position: center 28%; }

.scroll-cue {
  position: absolute;
  left: var(--gut);
  bottom: clamp(1.5rem, 5vh, 3rem);
  width: 1px;
  height: clamp(3rem, 8vh, 5rem);
  background: var(--rule);
  overflow: hidden;
}
.scroll-cue__line {
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: translateY(-100%);
  animation: cue 2.4s var(--ease-soft) infinite;
}
@keyframes cue {
  0%   { transform: translateY(-100%); }
  55%  { transform: translateY(0); }
  100% { transform: translateY(100%); }
}

@media (max-width: 900px) {
  /* Sur téléphone, tout est calculé pour que les six boutons de navigation
     restent au-dessus de la ligne de flottaison : c'est par eux qu'on entre
     dans le CV, les laisser sous le pli revient à les cacher. La photo cède
     donc de la hauteur, et les marges se resserrent. */
  .intro {
    grid-template-columns: 1fr;
    gap: clamp(.75rem, 1.8vh, 1.5rem);
    padding-block: clamp(1rem, 3vh, 3rem);
    /* Volontairement un peu moins que l'écran : la bande teintée du chapitre
       suivant dépasse alors de quelques dizaines de pixels en bas. C'est le
       signal le plus honnête qu'il y a une suite — plus qu'une flèche, qu'on
       peut prendre pour une décoration. */
    min-height: 90svh;
  }
  .intro__text { margin: 0; max-width: none; order: 2; }
  /* Le portrait ne prend PAS toute la largeur. Un cadre pleine largeur et court
     donne un rapport de 3 pour 1 : le recadrage n'en garde qu'une tranche, et
     le visage se retrouve coupé au front et au menton. On fixe donc le rapport
     de forme et on limite la largeur — la hauteur en découle. */
  .intro__portrait {
    order: 1;
    width: min(44vw, 11.5rem);
    height: auto;
    aspect-ratio: 4 / 5;
  }
  /* L'interlettrage large fait passer la ligne de lieu sur deux lignes pour
     une poignée de pixels de texte. On le resserre plutôt que de la couper. */
  .eyebrow { letter-spacing: .2em; }
  .intro__roles { font-size: clamp(1.25rem, 5vw, 1.6rem); }
  /* Boutons plus compacts : ils tiennent alors sur deux rangs au lieu de trois,
     ce qui vaut une quarantaine de pixels. */
  .intro__nav { gap: .4rem; }
  .intro__nav a { padding: .72rem 1.1rem; font-size: .58rem; letter-spacing: .2em; }
  .scroll-cue { display: none; }
}

/* Écran court — un petit téléphone, ou un grand en paysage. Là, même resserré,
   l'accueil ne tient plus : la toque et une part de la photo cèdent la place.
   La toque est décorative et reste visible dans l'onglet ; les boutons, eux,
   sont la seule porte d'entrée du CV. */
@media (max-width: 900px) and (max-height: 780px) {
  .mark { display: none; }
  /* Encore plus court : le carré est le recadrage le moins destructeur pour une
     photo presque carrée. */
  .intro__portrait { width: min(32vw, 8.5rem); aspect-ratio: 1 / 1; }
  .intro__pitch { font-size: .88rem; line-height: 1.55; }
  .intro__roles { font-size: 1.15rem; }
}

/* -------------------------------------------------- 8. Bande de repères - */

.strip {
  padding: clamp(1rem, 2.5vh, 1.75rem) var(--gut);
}
.strip__list {
  max-width: var(--max);
  margin: 0 auto;
  background: var(--ink-strong);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 3vh, 2rem) clamp(1.25rem, 3vw, 2.5rem);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
}
.strip__list li { display: grid; gap: .15rem; }
.strip__k {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.15rem, 2.4vw, 1.6rem);
  line-height: 1.15;
  color: var(--white);
}
.strip__k sup { font-size: .55em; }
.strip__v {
  font-family: var(--label);
  font-weight: 700;
  font-size: .58rem;
  text-transform: uppercase;
  letter-spacing: .26em;
  color: rgba(255, 255, 255, .55);
}

/* --------------------------------------------------------- 9. Chapitres - */

.chapter {
  /* Resserré : à 14vh de haut ET de bas, cinq chapitres coûtaient à eux seuls
     plus d'un écran de vide. */
  padding: clamp(2.5rem, 7vh, 5rem) var(--gut);
  position: relative;
}
/* L'alternance se joue entre le papier légèrement chaud et le blanc franc. */
.chapter--soft { background: var(--white); }

.chapter__head {
  max-width: var(--max);
  margin: 0 auto clamp(1.25rem, 3.5vh, 2.5rem);
  display: flex;
  align-items: baseline;
  gap: clamp(1rem, 3vw, 2.5rem);
}
.chapter__num { font-size: .68rem; color: var(--muted); }
.chapter__title {
  font-family: var(--label);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .18em;
  /* Plancher abaissé pour « TECHNIQUES APPRISES » : à 1.8rem et .18em
     d'interlettrage, le seul mot « TECHNIQUES » dépassait la largeur d'un
     écran de 320 px, et un mot ne se coupe pas. */
  font-size: clamp(1.35rem, 4vw, 2.6rem);
  line-height: 1.1;
  color: var(--ink-strong);
  /* Élément de flex : sans min-width, il refuse de descendre sous la largeur de
     son contenu et pousse la page à déborder. Le retour à la ligne forcé est le
     dernier filet, si un titre plus long est ajouté un jour. */
  min-width: 0;
  overflow-wrap: break-word;
}

/* Chapeau posé sous le titre : il remonte dans la marge laissée par la tête de
   chapitre, il ne doit donc pas hériter de sa marge basse complète. */
.chapter__lead {
  max-width: var(--max);
  margin: 0 auto clamp(1.25rem, 3vh, 2rem);
  font-size: 1rem;
}

.sub {
  max-width: var(--max);
  margin: clamp(1.75rem, 4vh, 2.75rem) auto clamp(.75rem, 1.8vh, 1.25rem);
  font-size: .72rem;
  color: var(--ink-strong);
}
.sub:first-of-type { margin-top: 0; }

.prose { max-width: 46rem; }
.chapter > .prose { margin-inline: auto; max-width: var(--max); }

/* ------------------------------ 10. Lignes — formation et expérience - */

/* Une seule grammaire pour les deux chapitres : picto ou date, intitulé,
   description. Trois colonnes qui se replient l'une sous l'autre en petit
   écran. Les grandes cartes et la piste à photos collantes ont disparu — elles
   demandaient de faire défiler trois écrans pour lire ce qui tient ici d'un
   regard. */

.rows { max-width: var(--max); margin: 0 auto; }

.rows li {
  display: grid;
  grid-template-columns: 2.9rem minmax(0, 17rem) minmax(0, 1.6fr);
  gap: clamp(.9rem, 2.5vw, 2rem);
  align-items: baseline;
  padding: clamp(.7rem, 1.6vh, 1.05rem) 0;
  border-bottom: 1px solid var(--rule);
}
.rows li:first-child { border-top: 1px solid var(--rule); }

/* Variante datée : la date remplace le picto en première colonne. Elle est à
   gauche pour qu'on suive la chronologie sans la chercher dans le texte. */
.rows--dated li { grid-template-columns: minmax(0, 8rem) minmax(0, 17rem) minmax(0, 1.6fr); }

/* Tous les pictos du site sont posés dans un carré d'encre à coins arrondis.
   Le fond est porté par l'enveloppe et non par l'image : `invert` s'applique à
   tout l'élément, il retournerait aussi le noir du carré.

   Trois tailles, une seule mécanique — formation, familles d'expérience,
   fiches techniques. */
.badge {
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--ink-strong);
  flex: none;
  transition: transform .4s var(--ease);
}

/* Une teinte par chapitre. On voit à quelle partie du CV on appartient sans
   remonter au titre. */
#formation  .badge { background: var(--c-formation); }
#experience .badge { background: var(--c-experience); }
#techniques .badge { background: var(--c-techniques); }
/* Les pictos sont des aplats noirs sur fond transparent : l'inversion les passe
   en blanc sans toucher à la transparence, donc sans second jeu de fichiers. */
.badge__img { filter: invert(1); display: block; }

.badge--lg { width: 2.9rem; height: 2.9rem; align-self: start; transform: translateY(.1em); }
.badge--lg .badge__img { width: 1.85rem; height: 1.85rem; }
.rows li:hover .badge--lg { transform: translateY(.1em) scale(1.06); }

.badge--md { width: 2.6rem; height: 2.6rem; border-radius: 11px; }
.badge--md .badge__img { width: 1.65rem; height: 1.65rem; }

.badge--sm { width: 2.3rem; height: 2.3rem; border-radius: 9px; grid-row: span 2; align-self: start; transform: translateY(.15rem); }
.badge--sm .badge__img { width: 1.45rem; height: 1.45rem; }
.tile:hover .badge--sm { transform: translateY(.15rem) scale(1.06); }

.rows__date {
  font-weight: 600;
  font-size: .8rem;
  letter-spacing: .08em;
  color: var(--muted);
}

/* Poste en cours : la pastille qui bat, reprise de l'ancienne piste. */
.rows li.is-now .rows__date {
  color: var(--ink-strong);
  display: flex;
  align-items: baseline;
  gap: .5rem;
}
.rows li.is-now .rows__date::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--ink-strong);
  animation: pulse 2.6s var(--ease-soft) infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.8); } }

.rows__title {
  font-family: var(--body);
  font-weight: 900;
  font-size: clamp(.98rem, 1.8vw, 1.1rem);
  line-height: 1.35;
  color: var(--ink-strong);
}
/* L'employeur ou le lieu, sous l'intitulé : même bloc, autre rang. */
.rows__sub {
  display: block;
  font-family: var(--label);
  font-weight: 700;
  font-style: normal;
  font-size: .58rem;
  text-transform: uppercase;
  letter-spacing: .2em;
  color: var(--muted);
  margin-top: .35rem;
}
.rows__body { font-size: .9rem; line-height: 1.55; }
.rows__body b { font-weight: 600; color: var(--ink-strong); }
.rows__body sup { font-size: .7em; }
.rows__body .link { margin-top: .5rem; display: block; }

/* Intitulé de famille, aligné sur la colonne des dates. */
.rows__group {
  max-width: var(--max);
  margin: clamp(1.5rem, 3.5vh, 2.25rem) auto clamp(.5rem, 1.2vh, .8rem);
  display: flex;
  align-items: center;
  gap: .7rem;
  font-family: var(--label);
  font-weight: 700;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .3em;
  color: var(--ink-strong);
}

.rows__group:first-of-type { margin-top: 0; }

@media (max-width: 820px) {
  .rows li, .rows--dated li {
    grid-template-columns: 2.9rem minmax(0, 1fr);
    gap: .45rem .9rem;
  }
  .rows--dated li { grid-template-columns: 1fr; }
  .rows__body { grid-column: 2; }
  .rows--dated .rows__body { grid-column: 1; }
  .rows__date { margin-bottom: .1rem; }
}

/* ------------------------------------------- 11 bis. Lieux et plans - */

.places {
  max-width: var(--max);
  margin: clamp(1.75rem, 4vh, 3rem) auto 0;
  padding-top: clamp(1.5rem, 3.5vh, 2.5rem);
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(1.75rem, 4vw, 3rem);
}

.place__name {
  font-family: var(--body);
  font-weight: 900;
  font-size: clamp(1.05rem, 2vw, 1.3rem);
  line-height: 1.3;
  color: var(--ink-strong);
  margin-bottom: .35rem;
}
.place__addr { font-size: .95rem; color: var(--muted); margin-bottom: 1.25rem; }

/* Avant le clic, le cadre montre un plan schématique dessiné en CSS : un
   quadrillage de rues et une épingle. Il tient exactement la place que prendra
   la carte, donc rien ne saute au chargement. */
.place__frame {
  position: relative;
  height: clamp(7rem, 14vh, 9.5rem);
  overflow: hidden;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  display: grid;
  place-items: center;
}

.place__grid {
  position: absolute;
  inset: -20%;
  background-image:
    linear-gradient(var(--rule) 1px, transparent 1px),
    linear-gradient(90deg, var(--rule) 1px, transparent 1px),
    linear-gradient(rgba(28, 26, 26, .14) 2px, transparent 2px);
  background-size: 34px 34px, 34px 34px, 100% 118px;
  transform: rotate(-11deg);
  transition: transform 1.2s var(--ease);
}
.place:hover .place__grid { transform: rotate(-11deg) scale(1.06); }

/* L'épingle : un disque plein surmontant son halo, qui bat comme le poste en
   cours. */
.place__pin {
  position: absolute;
  top: 42%; left: 50%;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  background: var(--ink-strong);
}
.place__pin::after {
  content: '';
  position: absolute;
  inset: -13px;
  border-radius: 50%;
  border: 1px solid var(--ink-strong);
  opacity: .5;
  animation: ping 3s var(--ease-soft) infinite;
}
@keyframes ping {
  0%   { transform: scale(.6); opacity: .7; }
  70%  { transform: scale(1.5); opacity: 0; }
  100% { transform: scale(1.5); opacity: 0; }
}

.place__load {
  position: relative;
  z-index: 1;
  font-family: var(--label);
  font-weight: 700;
  font-size: .6rem;
  text-transform: uppercase;
  letter-spacing: .24em;
  color: var(--ink-strong);
  background: rgba(255, 255, 255, .92);
  border: 1px solid var(--rule);
  border-radius: var(--pill);
  padding: .9rem 1.7rem;
  cursor: pointer;
  backdrop-filter: blur(2px);
  transition: background .45s var(--ease), color .45s var(--ease), border-color .45s var(--ease);
}
.place__load:hover, .place__load:focus-visible {
  background: var(--ink-strong);
  color: var(--white);
  border-color: var(--ink-strong);
}

/* Une fois la carte chargée, elle remplace le contenu du cadre. */
.place__frame iframe { width: 100%; height: 100%; border: 0; display: block; }
.place__frame.is-loaded { display: block; }


/* --------------------------------------- 12. Filtres et grille — techniques - */

.filters {
  max-width: var(--max);
  margin: 0 auto clamp(2rem, 5vh, 3rem);
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.chip {
  font-family: var(--label);
  font-weight: 700;
  font-size: .6rem;
  text-transform: uppercase;
  letter-spacing: .24em;
  padding: .8rem 1.5rem;
  border: 1px solid var(--rule);
  border-radius: var(--pill);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: color .45s var(--ease), border-color .45s var(--ease);
}
.chip::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink-strong);
  transform: translateY(101%);
  transition: transform .55s var(--ease);
}
.chip:hover, .chip:focus-visible { color: var(--white); border-color: var(--ink-strong); }
.chip:hover::before, .chip:focus-visible::before { transform: none; }

.chip.is-on { color: var(--white); border-color: var(--mark); }
.chip.is-on::before { background: var(--mark); transform: none; }

.grid {
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 12.5rem), 1fr));
  gap: clamp(.55rem, 1vw, .8rem);
}

.tile {
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  /* Une ligne à picto plutôt qu'une vignette à photo : quatorze fiches en
     images occupaient trois écrans à elles seules. */
  display: grid;
  grid-template-columns: 2.3rem minmax(0, 1fr);
  align-items: start;
  gap: .2rem .75rem;
  padding: clamp(.8rem, 1.6vw, 1rem);
  transition: transform .55s var(--ease), box-shadow .55s var(--ease);
}
.tile:hover { transform: translateY(-3px); box-shadow: 0 12px 26px rgba(28, 26, 26, .07); }

/* L'étoile marque les gestes tenus en autonomie. Elle est en haut à droite,
   hors du flux : elle ne doit pas décaler le titre d'une fiche à l'autre. */
.tile { position: relative; }
.tile__star {
  position: absolute;
  top: .7rem;
  right: .8rem;
  font-size: .82rem;
  line-height: 1;
  color: var(--ink-strong);
}
/* Une fiche étoilée s'affirme un peu plus que les autres. */
.tile.is-known { border-color: rgba(28, 26, 26, .28); }

/* La légende, entre le filtre et la grille. */
.grid__legend {
  max-width: var(--max);
  margin: 0 auto clamp(.9rem, 2vh, 1.4rem);
  font-size: .88rem;
  line-height: 1.6;
  color: var(--ink);
}
.grid__legend .tile__star { position: static; font-size: .95rem; }

/* Le savoir-être : un texte, pas une liste. Il ferme le chapitre, décalé par un
   filet à gauche pour qu'on voie tout de suite que ce n'est plus une fiche. */
.note {
  max-width: 52rem;
  margin: clamp(1.75rem, 4vh, 2.75rem) auto 0;
  padding-left: clamp(1rem, 2.5vw, 1.75rem);
  border-left: 2px solid var(--ink-strong);
  font-size: 1rem;
  line-height: 1.7;
}

/* Langues et disponibilités, en pied de contact : deux colonnes d'appoint. */
.aside {
  max-width: var(--max);
  margin: clamp(2rem, 5vh, 3.5rem) auto 0;
  padding-top: clamp(1.5rem, 3.5vh, 2.5rem);
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(1.5rem, 4vw, 3.5rem);
}
.aside .avail__title { margin-bottom: .9rem; }
.aside .skills { display: block; }
/* Dans une colonne étroite, l'alignement à droite des intitulés — hérité de la
   liste pleine largeur — donnait un bord gauche en dents de scie. */
.aside .skills li { grid-template-columns: minmax(0, 8rem) minmax(0, 1fr); }
.aside .skills__name { text-align: left; }
.aside .avail__list { grid-template-columns: 1fr; }

/* Fiche écartée par le filtre : on la sort du flux une fois le fondu terminé,
   sinon la grille garderait des trous. `hidden` est posé par app.js. */
.tile.is-out { opacity: 0; transform: scale(.96); transition: opacity .35s var(--ease), transform .35s var(--ease); }
.tile[hidden] { display: none; }

.tile__body .tag { margin-bottom: .4rem; font-size: .56rem; }

.tile__name {
  font-family: var(--body);
  font-weight: 900;
  font-size: 1rem;
  line-height: 1.3;
  color: var(--ink-strong);
  margin-bottom: .3rem;
}
.tile__desc { font-size: .84rem; line-height: 1.5; }

.grid__empty {
  max-width: var(--max);
  margin: 2rem auto 0;
  color: var(--muted);
  font-size: .95rem;
}

/* --------------------------------------------- 13. Liste — plats signature - */

/* Une liste, pas une grille de vignettes : chaque plat tient sur une ligne, le
   picto ne fait que le signaler. Trois colonnes — picto, nom, note — qui se
   replient l'une sous l'autre en petit écran. */
.dishes { max-width: var(--max); margin: 0 auto; }

.dishes li {
  display: grid;
  grid-template-columns: 3.4rem minmax(0, 17.5rem) minmax(0, 1.5fr);
  gap: clamp(.9rem, 2.5vw, 2rem);
  align-items: baseline;
  padding: clamp(1rem, 2.2vh, 1.5rem) 0;
  border-bottom: 1px solid var(--rule);
}
.dishes li:first-child { border-top: 1px solid var(--rule); }

/* Le picto est décoratif : il double le nom, il ne le remplace pas. Aligné sur
   la première ligne de texte, pas sur la ligne de base du bloc. */
.dishes__icon {
  width: 2.6rem;
  height: 2.6rem;
  align-self: start;
  transform: translateY(.1em);
  opacity: .85;
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.dishes li:hover .dishes__icon { opacity: 1; transform: translateY(.1em) scale(1.08); }

.dishes__name {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1rem, 1.9vw, 1.2rem);
  line-height: 1.3;
  color: var(--ink-strong);
}
.dishes__note { font-size: .95rem; line-height: 1.65; }

@media (max-width: 760px) {
  .dishes li {
    grid-template-columns: 3rem minmax(0, 1fr);
    gap: .5rem .9rem;
  }
  /* La note passe sous le nom, alignée avec lui et non avec le picto. */
  .dishes__note { grid-column: 2; }
}

/* --------------------------------- 14. Compétences et disponibilités - */

.skills {
  max-width: var(--max);
  margin: 0 auto;
  /* Deux colonnes : seize lignes empilées sur toute la largeur faisaient
     défiler pour rien, alors que chacune tient en une demi-ligne. */
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  column-gap: clamp(1.25rem, 3vw, 2.5rem);
}

.skills li {
  display: grid;
  grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr);
  gap: clamp(.6rem, 1.5vw, 1rem);
  align-items: baseline;
  padding: clamp(.35rem, .9vh, .55rem) 0;
  border-bottom: 1px solid var(--rule);
  position: relative;
}
/* Le trait du bas se dessine de gauche à droite quand la ligne arrive. */
.anim .skills li::after {
  content: '';
  position: absolute;
  left: 0; bottom: -1px;
  height: 1px; width: 100%;
  background: var(--ink-strong);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 1.1s var(--ease) var(--d, 0ms);
}
.anim .skills li.is-in::after { transform: scaleX(1); }

.skills__name {
  font-weight: 900;
  font-size: .82rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-strong);
  text-align: right;
  font-size: clamp(.9rem, 1.6vw, 1.05rem);
}
.skills__use { font-weight: 200; font-size: .88rem; line-height: 1.45; color: var(--black); }

@media (max-width: 620px) {
  .skills li { grid-template-columns: 1fr; gap: .1rem; text-align: center; padding: .85rem 0; }
  .skills__name { text-align: center; }
}

.avail__title { font-size: .72rem; color: var(--ink-strong); margin-bottom: .9rem; }
.avail__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: .6rem clamp(1.5rem, 4vw, 3rem);
}
.avail__list li {
  display: grid;
  grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: clamp(.75rem, 2vw, 2rem);
  align-items: baseline;
}
.avail__k {
  font-family: var(--label);
  font-weight: 700;
  font-size: .6rem;
  text-transform: uppercase;
  letter-spacing: .22em;
  color: var(--ink-strong);
}
.avail__v { font-size: .98rem; line-height: 1.6; }

@media (max-width: 620px) {
  .avail__list li { grid-template-columns: 1fr; gap: .1rem; }
}

/* ------------------------------------------------------------ 15. Contact - */

.chapter--contact { padding-bottom: clamp(2rem, 5vh, 3rem); }

.contact {
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 7vw, 6rem);
  align-items: start;
}

.contact__direct { display: grid; gap: .6rem; justify-items: start; }
.contact__big {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.25rem, 3.2vw, 2.1rem);
  line-height: 1.2;
  color: var(--ink-strong);
  text-decoration: none;
  word-break: break-word;
  position: relative;
  width: max-content;
  max-width: 100%;
}
.contact__big::after {
  content: '';
  position: absolute;
  left: 0; bottom: -.1em;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .6s var(--ease);
}
.contact__big:hover::after, .contact__big:focus-visible::after { transform: scaleX(1); transform-origin: left; }

.contact__where {
  font-family: var(--label);
  font-weight: 700;
  font-size: .62rem;
  text-transform: uppercase;
  letter-spacing: .26em;
  color: var(--muted);
  margin-top: .5rem;
}

.form { display: grid; gap: 1.1rem; }

/* Étiquette flottante : elle remonte dès que le champ est rempli ou visé. */
.field { position: relative; }
.field input, .field textarea {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-strong);
  font-family: var(--body);
  font-weight: 300;
  font-size: 1rem;
  padding: 1.2rem 0 .5rem;
  border-radius: 0;
  transition: border-color .4s var(--ease);
  resize: vertical;
}
.field label {
  position: absolute;
  left: 0; top: 1.4rem;
  font-family: var(--label);
  font-weight: 700;
  font-size: .62rem;
  text-transform: uppercase;
  letter-spacing: .26em;
  color: var(--muted);
  pointer-events: none;
  transform-origin: left top;
  transition: transform .45s var(--ease), color .45s var(--ease);
}
.field input:focus, .field textarea:focus { outline: none; border-bottom-color: var(--ink-strong); }
.field input:focus + label,
.field textarea:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:not(:placeholder-shown) + label {
  transform: translateY(-1.35rem) scale(.92);
  color: var(--ink-strong);
}

.btn {
  justify-self: start;
  font-family: var(--label);
  font-weight: 700;
  font-size: .62rem;
  text-transform: uppercase;
  letter-spacing: .26em;
  color: var(--ink-strong);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--pill);
  padding: 1.05rem 2.6rem;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: color .45s var(--ease), border-color .45s var(--ease);
}
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink-strong);
  transform: translateY(101%);
  transition: transform .55s var(--ease);
}
.btn:hover, .btn:focus-visible { color: var(--white); border-color: var(--ink-strong); }
.btn:hover::before, .btn:focus-visible::before { transform: none; }

.btn--ghost { margin-top: .75rem; }

.form__note { font-size: .82rem; color: var(--muted); line-height: 1.5; }

.foot {
  max-width: var(--max);
  margin: clamp(2rem, 5vh, 3.5rem) auto 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem 2rem;
  flex-wrap: wrap;
  font-size: .82rem;
  color: var(--muted);
}
/* Le crédit des pictogrammes : obligatoire, donc lisible, mais il n'a pas à
   tenir le même rang que le nom. */
.foot__credit { flex: 1 1 22rem; font-size: .72rem; line-height: 1.5; }
.foot__credit a { text-decoration: underline; text-underline-offset: 3px; }
.foot__credit a:hover { color: var(--ink-strong); }

@media (max-width: 820px) { .contact { grid-template-columns: 1fr; } }

/* -------------------------------------------------------- 16. Visionneuse - */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(250, 250, 249, .97);
  display: grid;
  place-items: center;
  padding: clamp(1rem, 5vw, 4rem);
  opacity: 0;
  transition: opacity .4s var(--ease);
}
.lightbox.is-open { opacity: 1; }
.lightbox[hidden] { display: none; }

.lightbox__figure {
  max-width: min(78rem, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  transform: scale(.97);
  transition: transform .5s var(--ease);
}
.lightbox.is-open .lightbox__figure { transform: none; }

.lightbox__img {
  max-width: 100%;
  max-height: 78vh;
  width: auto;
  margin: 0 auto;
  object-fit: contain;
  border-radius: var(--radius-sm);
}

.lightbox__caption {
  font-family: var(--label);
  font-weight: 700;
  font-size: .62rem;
  text-transform: uppercase;
  letter-spacing: .26em;
  color: var(--muted);
  text-align: center;
}

.lightbox__close {
  position: absolute;
  top: clamp(.75rem, 3vw, 2rem);
  right: clamp(.75rem, 3vw, 2rem);
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--white);
  color: var(--ink-strong);
  cursor: pointer;
  transition: background .4s var(--ease), color .4s var(--ease);
}
.lightbox__close svg { width: 1rem; height: 1rem; fill: currentColor; }
.lightbox__close:hover { background: var(--ink-strong); color: var(--white); }

/* ---------------------------------------------------- 17. Mouvement réduit - */

/* Rien ne bouge, tout reste lisible. Les états de départ des animations sont
   neutralisés, sinon la page resterait vide. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  [data-unmask] img { clip-path: none; transform: none; }
  .split-char { opacity: 1; transform: none; }
  .skills li::after { transform: scaleX(1); }
  .curtain { display: none; }
  .scroll-cue { display: none; }
  .tile:hover { transform: none; }
}

/* ---------------------------------------------------------- 18. Impression - */

/* Un CV doit pouvoir sortir sur papier. On retire tout le décor d'écran, on
   remet le texte en noir sur blanc, on resserre la mise en page et on empêche
   les blocs de se couper en deux au changement de page.

   Les photos des grilles disparaissent à l'impression : à l'écran elles sont le
   sujet, sur papier elles coûteraient six pages pour un CV que personne ne lira
   au-delà de la deuxième. Seul le portrait reste. */
@media print {
  @page { margin: 1.4cm 1.2cm; }

  .curtain, .progress, .dots, .totop, .scroll-cue, .lightbox,
  .filters, .form, .btn, .mark, .chapter__lead, .place__frame,
  .media--tile { display: none !important; }

  html, body { background: #fff !important; color: #000 !important; font-size: 10pt !important; line-height: 1.45 !important; }

  /* Toutes les apparitions sont forcées à l'état final : sans ça, ce qui n'a
     pas encore été révélé à l'écran sortirait blanc sur la feuille. */
  [data-reveal], [data-unmask] img, .split-char { opacity: 1 !important; transform: none !important; clip-path: none !important; }

  .chapter, .intro, .strip { padding: .5cm 0 !important; min-height: 0 !important; page-break-inside: auto; }
  .chapter--soft, .strip, .strip__list, .tile, .avail { background: #fff !important; color: #000 !important; border-color: #ccc !important; padding-inline: 0 !important; }
  .tag, .chapter__num, .avail__k, .strip__v { color: #555 !important; }
  .strip__k { color: #000 !important; }
  .chapter--soft .chapter__title, .chapter--soft .rows__title,
  .strip__k, .contact__big { color: #000 !important; }
  .tag, .chapter__num, .rows__sub, .strip__v, .avail__k, .rows__date { color: #555 !important; }
  /* Le poste en cours s'écrit en blanc sur le fond sombre de l'écran : sur
     papier il disparaîtrait, il ne resterait que sa pastille. */
  .rows li.is-now .rows__date { color: #000 !important; }
  .rows li.is-now .rows__date::before { background: #000 !important; animation: none !important; }
  .job, .skills li { border-color: #ccc !important; }
  .avail { border-left: 2pt solid #000 !important; padding: .4cm 0 .4cm .5cm !important; }

  /* Le portrait reste à droite du bloc d'identité. Un float aurait démarré
     après le texte — donc trop bas — puisqu'il le suit dans le document. */
  /* Une page A4 fait environ 794 px CSS : la règle mobile (max-width: 900px)
     s'applique donc à l'impression et inverse l'ordre des deux colonnes. On la
     défait explicitement, sinon le portrait passe devant le nom. */
  .intro { grid-template-columns: 1fr 4.5cm !important; align-items: start !important; gap: .8cm !important; }
  .intro__text { order: 0 !important; max-width: none !important; margin: 0 !important; }
  .intro__portrait { order: 0 !important; height: 5.5cm !important; }
  .intro__name { font-size: 30pt !important; margin-bottom: .3cm !important; }
  .intro__roles { font-size: 12pt !important; margin-bottom: .3cm !important; }
  .intro__nav { display: none; }

  .chapter__title { font-size: 15pt !important; }
  .chapter__head { margin-bottom: .45cm !important; }
  .sub { margin: .5cm 0 .25cm !important; }

  /* Trois colonnes serrées : sans les photos, les fiches ne sont plus que du
     texte court et tiennent largement. */
  .grid { grid-template-columns: repeat(3, 1fr) !important; gap: .45cm !important; }
  .rows li, .rows--dated li { grid-template-columns: minmax(0, 3.5cm) minmax(0, 5cm) minmax(0, 1fr) !important; gap: .3cm !important; padding: .12cm 0 !important; }
  .badge { display: none !important; }
  .rows li:not(.rows--dated li) { grid-template-columns: minmax(0, 5cm) minmax(0, 1fr) !important; }
  .rows__group { margin: .35cm 0 .15cm !important; }
  .rows__group img { display: none !important; }
  .dishes li { grid-template-columns: minmax(0, 6cm) minmax(0, 1fr) !important; gap: .3cm !important; padding: .12cm 0 !important; }
  .dishes__icon { display: none !important; }
  .dishes__name { color: #000 !important; }
  .places { grid-template-columns: repeat(2, 1fr) !important; gap: .45cm !important; margin-top: .5cm !important; padding-top: .4cm !important; border-top-color: #ccc !important; }
  .place__name { color: #000 !important; }
  .tile__body { padding: 0 !important; }
  .skills li { padding: .12cm 0 !important; }
  .avail__list { gap: .2cm !important; }

  .tile, .rows li, .avail, .strip__list li, .chapter__head { page-break-inside: avoid; }
  .chapter { page-break-before: auto; }

  a { text-decoration: none; }
}
