/* =====================================================================
   melvinplassiard.fr – feuille de style unique
   Direction : fond noir profond, accent orangé #fc7f1e (90 % du chemin vers l'orange Prodepix), deux blobs dorés en fond.
   Aucune ressource externe (polices système), compatible CSP stricte.
   ===================================================================== */

/* Coolvetica Regular, seule police web du site, reprise telle quelle de
   prodepix.fr (fichier identique, non modifie). Reserve de licence a lever :
   fsType = 4, voir assets/fonts/LICENCE-coolvetica.txt. `swap` : le titre
   s'affiche tout de suite dans la police de secours puis bascule, plutot que de
   rester invisible pendant le telechargement. */
@font-face {
  font-family: "Coolvetica";
  src: url("../assets/fonts/coolvetica-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #0b0b0d;
  --bg-2: #111114;
  --bg-3: #17171b;
  --line: rgba(255, 255, 255, 0.08);
  --line-strong: rgba(255, 255, 255, 0.16);
  --text: #f2f0ec;
  --muted: #a7a49e;
  --accent: #fc7f1e;
  --accent-2: #fdac6d;
  --radius: 2.75px;
  --max: 1120px;
  --font-body: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Segoe UI Variable Display", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; scroll-padding-top: 84px; }

body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  position: relative;
}

img { max-width: 100%; display: block; }
a { color: var(--accent-2); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
ul, ol { list-style: none; }

.skip-link {
  position: absolute; left: -999px; top: 8px;
  background: var(--accent); color: #000; padding: .5rem .9rem; border-radius: 2.75px; z-index: 100;
}
.skip-link:focus { left: 8px; }

/* ---------------- Header / nav ---------------- */
.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  background: rgba(11, 11, 13, 0.82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.nav {
  max-width: var(--max); margin: 0 auto; padding: .7rem 1.25rem;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  position: relative;
}
/* Logo et adresse de l'agence, un seul lien sans cadre. Un filet vertical le
   separe du nom. Au survol, le texte passe a l'orange. Le cadre a ete retire a
   la demande de Ren, le logo reste tel quel, sans disque blanc derriere. */
.brand-prodepix {
  display: flex; align-items: center; gap: .5rem; flex: 0 0 auto;
  padding: 0 .95rem 0 0; border-right: 1px solid var(--line-strong);
  color: var(--text); font-size: .88rem; letter-spacing: .02em; white-space: nowrap;
  transition: color .2s ease;
}
.brand-prodepix:hover { color: var(--accent-2); text-decoration: none; }
.brand-prodepix img { width: 26px; height: 26px; display: block; }
.brand { display: flex; align-items: center; gap: .65rem; color: var(--text); }
.brand:hover { text-decoration: none; }
.brand-name { font-family: var(--font-display); letter-spacing: .02em; font-size: 1.02rem; white-space: nowrap; }
.brand-name strong { color: var(--accent-2); font-weight: 700; }

.nav-links { display: flex; align-items: center; gap: 1.05rem; }

/* Logos des reseaux, sur le modele du site de Louison : gris au repos, couleur
   de marque au survol. Les SVG sont ecrits dans la page, aucune requete externe
   -- la CSP du site interdit les images distantes. */
.nav-socials { display: flex; align-items: center; gap: .45rem; margin-left: 1rem; }
.nav-links { margin-left: auto; }
.nav-socials a {
  width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;
  border-radius: 2.75px; color: inherit; transition: transform .2s ease;
}
.nav-socials svg { width: 19px; height: 19px; fill: var(--muted); display: block; transition: fill .2s ease; }
.nav-socials a:hover { transform: scale(1.12); }
.nav-socials a:active { transform: scale(.94); transition: transform .08s ease; }
.nav-socials a:hover svg { fill: var(--social); }
.social-malt { --social: #ff5c57; }
.marque-malt {
  width: 19px; height: 19px; display: block; background: var(--muted);
  -webkit-mask: url("../assets/malt-mark.png") center / contain no-repeat;
  mask: url("../assets/malt-mark.png") center / contain no-repeat;
  transition: background .2s ease;
}
.social-malt:hover .marque-malt { background: var(--social); }
.nav-links a {
  color: var(--muted); font-size: .84rem; letter-spacing: .1em; text-transform: uppercase;
  white-space: nowrap;
  padding: .3rem 0; border-bottom: 1px solid transparent; transition: color .2s, border-color .2s;
}
.nav-links a:hover, .nav-links a.is-active { color: var(--text); border-color: var(--accent); text-decoration: none; }

.burger {
  display: none; width: 40px; height: 40px; background: transparent; border: 1px solid var(--line-strong);
  border-radius: 2.75px; cursor: pointer; flex-direction: column; justify-content: center; align-items: center; gap: 5px;
}
.burger span { width: 18px; height: 2px; background: var(--text); border-radius: 2.75px; transition: transform .25s, opacity .25s; }
.nav-open .burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-open .burger span:nth-child(2) { opacity: 0; }
.nav-open .burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ---------------- Boutons ---------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .8rem 1.35rem; border-radius: 2.75px; font-weight: 600; font-size: .95rem;
  border: 1px solid transparent; cursor: pointer; font-family: inherit; line-height: 1.2;
  transition: transform .15s ease, background .2s, border-color .2s, box-shadow .2s;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-primary { background: var(--accent); color: #0b0b0d; box-shadow: 0 8px 30px rgba(252, 127, 30, .25); }
.btn-primary:hover { background: var(--accent-2); }
.btn-ghost { background: transparent; color: var(--text); border-color: var(--line-strong); }
.btn-ghost:hover { border-color: var(--accent); }
.btn-small { padding: .45rem .9rem; font-size: .8rem; letter-spacing: .08em; text-transform: uppercase; }

/* ---------------- Hero video ----------------
   Bande plein cadre en haut de page, sur le modele de prodepix.fr.
   La hauteur est figee en JS via --hero-video-height, pas en dvh : la video est
   en `cover` et contrainte par la hauteur, donc si la boite grandit quand la
   barre d'adresse du telephone se retracte, le cover zoome mecaniquement et la
   video "grossit" en plein defilement. Le 100svh n'est qu'un repli avant que le
   script, charge en defer, ne s'execute. */
.hero {
  /* Le hero ne peint plus rien : la video et son voile sont fixes, lui ne fait
     que reserver la hauteur d'un ecran avant le contenu. `pointer-events: none`
     parce qu'il n'y a rien a y cliquer et que le contenu passe par-dessus. */
  position: relative;
  height: 100svh;
  height: var(--hero-video-height, 100svh);
  min-height: 420px;
  display: grid;
  place-items: center;
  overflow: visible;
  background: transparent;
  pointer-events: none;
  z-index: 0;
  margin: 0;
  max-width: none;
  padding: 0;
}
.hero-showreel {
  /* Fixe, pas absolue : le montage reste derriere toute la page pendant que le
     contenu defile par-dessus. C'est le mecanisme de prodepix.fr. Il n'y a donc
     aucune jonction a adoucir -- la video ne s'arrete nulle part, elle est
     recouverte par le fond de .apres-hero. Masquer ou flouter son bord etait
     une fausse piste : le bord n'a pas a exister. */
  position: fixed; inset: 0; z-index: 0;
  width: 100vw; height: var(--hero-video-height, 100svh);
  /* voir le bloc (hover: hover) plus bas : sur ordinateur cette hauteur figee
     est remplacee par 100vh, elle ne sert qu'au telephone */
  object-fit: cover; object-position: center center;
  /* L'affiche est posee en fond plutot que par l'attribut poster : celui-ci ne
     prend qu'une seule URL, alors que les montages horizontal et vertical
     n'auront pas du tout le meme cadrage. Un fond CSS se choisit par media
     query. cover + center reproduisent le object-fit de la video : les deux se
     superposent au pixel pres, le passage image vers video ne saute pas. */
  background-color: #000;
  background-image: url("../assets/hero-poster.webp?v=2026091813");
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
}
/* Sur telephone, l'affiche est tiree du montage vertical : meme plan, meme
   cadrage que la video qui prend le relais, pour que le passage ne saute pas.
   Meme seuil que le script qui choisit le fichier (max-width: 768px). */
@media (max-width: 768px) {
  .hero-showreel { background-image: url("../assets/hero-poster-mobile.webp?v=2026091813"); }
}

/* Sur ordinateur la hauteur figee ne sert a rien et fait des degats : aucune
   barre d'adresse ne bouge, et des que --hero-video-height se retrouve plus
   petit que la fenetre -- fenetre redimensionnee, zoom, valeur mesuree avant
   stabilisation -- le bas de la video fixe devient une ligne horizontale nette,
   avec le fond de page a nu en dessous. 100vh supprime le cas. La hauteur figee
   reste sur telephone, ou elle empeche la video de zoomer toute seule quand la
   barre d'adresse se retracte. */
@media (hover: hover) and (pointer: fine) {
  .hero { height: 100vh; }
  .hero-showreel { height: 100vh; }
}

/* Voile : sans lui le titre devient illisible des qu'un plan clair passe
   dessous. Fixe comme la video, sinon il defilerait sans elle. Il n'a plus a
   assombrir le bas du hero -- c'est le fond de .apres-hero qui recouvre. */
.hero::after {
  content: ""; position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(ellipse 68% 58% at 50% 50%, rgba(0, 0, 0, .66), rgba(0, 0, 0, .30) 62%, rgba(0, 0, 0, .12) 100%),
    linear-gradient(180deg, rgba(0, 0, 0, .42), rgba(0, 0, 0, 0) 28%, rgba(0, 0, 0, 0) 58%, rgba(11, 11, 13, .55) 84%, rgba(11, 11, 13, .88) 100%);
}
.hero-inner {
  position: relative; z-index: 2; text-align: center; padding: 0 1.25rem;
  max-width: 1000px;
}
h1 {
  font-family: "Coolvetica", var(--font-display);
  font-weight: 400; line-height: .98; letter-spacing: -.01em;
}
.hero-line { display: block; }
.hero-line:first-child {
  font-size: clamp(2.4rem, 8vw, 6.5rem);
  text-transform: uppercase;
  letter-spacing: .01em;
  text-shadow: 0 4px 40px rgba(0, 0, 0, .55);
}
.hero-accent {
  font-family: var(--font-body);
  font-size: clamp(1rem, 2.2vw, 1.6rem); font-weight: 400;
  letter-spacing: .28em; text-transform: uppercase;
  margin-top: 1.1rem; color: #e8e5e0;
  text-shadow: 0 2px 20px rgba(0, 0, 0, .6);
}

/* ---------------- Bande d'introduction ----------------
   Ce qui occupait le hero avant la video : accroche, paragraphe et boutons.
   Superposes au montage, ils l'auraient encombre. */
.intro {
  max-width: 760px; margin: 0 auto; padding: 3.4rem 1.25rem 1rem; text-align: center;
  position: relative; z-index: 1;
}
.eyebrow {
  color: var(--accent-2); font-size: .82rem; letter-spacing: .22em; text-transform: uppercase; margin-bottom: 1.2rem;
}
.hero-lead { margin: 0 auto; max-width: 60ch; font-size: 1.08rem; color: #d6d3cd; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.5rem; justify-content: center; }
.contact-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.5rem; }

/* ---------------- Portrait, descendu dans "A propos" ---------------- */
/* Photo seule, avec un filet neutre d'un pixel. Il y avait trois habillages,
   retires a la demande de Ren : un anneau de 10 px teinte d'orange a 5 %, qui
   sur fond noir donnait un cercle brunatre ; une ombre portee de 60 px, le
   degrade noir autour ; et un arc orange en conic-gradient sur le bord. Le filet
   reste parce que le fond de la photo est sombre lui aussi : sans lui, le bord
   du cercle se perdrait dans le fond de page. */
.portrait {
  position: relative; width: min(260px, 62vw); aspect-ratio: 1;
  border-radius: 50%; overflow: hidden;
  border: 1px solid var(--line-strong);
}
.portrait-photo {
  width: 100%; height: 100%; border-radius: 50%; object-fit: cover; object-position: center 20%;
  filter: saturate(.92) contrast(1.04);
}

/* ---------------- Blobs dorés ----------------
   Deux halos qui dérivent en fond, l'un en haut, l'autre en bas.
   Aucun script : la piste extérieure anime l'axe X, le blob intérieur l'axe Y
   avec une durée différente. Deux périodes non multiples l'une de l'autre
   donnent une trajectoire qui ne se répète pas à l'œil, sans aléatoire réel.
   Seul `transform` est animé, donc le rendu reste composité par le GPU :
   animer le flou ou border-radius obligerait à re-calculer le flou à chaque
   image, ce qui ramerait sur téléphone. */
/* Les deux blobs sont ancres au DOCUMENT, pas a la fenetre : celui du haut se
   trouve en haut de page, celui du bas au pied, et tous deux defilent avec le
   contenu. Il leur faut donc un conteneur absolu couvrant toute la hauteur du
   document, d'ou `position: relative` sur body -- sans ancetre positionne, un
   `bottom: 0` viserait le bas de la fenetre, pas celui de la page.
   `overflow: hidden` empeche leur debordement de rallonger la page. */
.blobs-page {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  /* `overflow: hidden` tranchait net le blob du haut, dont le `top` est negatif
     depuis que ce conteneur est descendu dans .apres-hero -- c'est le bord droit
     visible en bas du montage. `clip` sur le seul axe horizontal empeche
     toujours les blobs d'elargir la page, sans rien couper verticalement.
     Contrairement a `hidden`, `clip` autorise `visible` sur l'autre axe. */
  /* Rogne sur les deux axes. En laissant deborder verticalement, le blob du bas
     -- que son animation descend de 17vh -- rallongeait le document sous le
     pied de page, et cette bande laissait voir la video fixe a nu. `clip`
     plutot que `hidden` : meme rognage, mais sans creer de conteneur de
     defilement. Les deux blobs sont assez rentres pour que leur animation ne
     touche jamais le bord : le degre visible d'un blob s'arrete a 78 % de son
     rayon, le reste est deja transparent. */
  overflow: clip;
}
.blob-piste { position: absolute; will-change: transform; }
.blob {
  display: block; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(252, 127, 30, .34), rgba(252, 127, 30, .13) 55%, transparent 78%);
  filter: blur(36px);
  will-change: transform;
}
.blob-haut { top: 16vh; left: 6vw; animation: blob-x 11.5s ease-in-out infinite alternate; }
.blob-haut .blob { width: 42vmax; animation: blob-y 15.5s ease-in-out infinite alternate; }
.blob-bas { bottom: 16vh; left: 50%; margin-left: -24vmax; animation: blob-x 14.5s ease-in-out infinite alternate -3.5s; }
.blob-bas .blob { width: 48vmax; animation: blob-y 18.5s ease-in-out infinite alternate -5.5s; }

@keyframes blob-x {
  from { transform: translateX(-16vw); }
  to   { transform: translateX(19vw); }
}
@keyframes blob-y {
  from { transform: translateY(-13vh) scale(.84) rotate(-16deg); }
  to   { transform: translateY(17vh) scale(1.16) rotate(17deg); }
}

/* Le contenu passe devant les blobs. */
main, .site-footer { position: relative; z-index: 1; }

/* Le recouvrement de la video fixe. Transparent en haut sur une centaine de
   pixels : le montage reste visible derriere le debut du texte, exactement
   comme sur prodepix.fr, puis le fond devient opaque et la video disparait
   pour le reste de la page. Valeurs reprises de .home-page .craft. */
.apres-hero {
  position: relative; z-index: 2;
  /* Les blobs de Projets et Parcours debordent volontairement sur les cotes.
     `overflow-x: hidden` sur body suffit sur ordinateur, pas sur telephone : le
     navigateur mobile elargit sa zone d'affichage a tout ce qui depasse, et la
     page passait a 438 px sur un ecran de 375, texte coupe a droite. `clip` ne
     rogne que l'horizontale -- le raccord flou, qui remonte dans le hero, n'est
     pas touche. */
  overflow-x: clip;
  background: linear-gradient(180deg,
    rgba(11, 11, 13, 0) 0,
    rgba(11, 11, 13, .74) clamp(58px, 6vw, 100px),
    var(--bg) clamp(140px, 15vw, 230px));
}
.apres-hero > section { position: relative; z-index: 1; }

/* Le raccord flou. Il demarre 26vh au-dessus du conteneur, donc dans le hero :
   le flou doit monter en puissance pendant que le montage est encore
   entierement visible, et atteindre son maximum juste au moment ou le fond du
   conteneur devient opaque. Place uniquement dans la bande de recouvrement, il
   flouterait sous un fond deja plein et ne se verrait pas.

   Trois calques et non un : masquer un `backdrop-filter` unique en degrade fait
   varier son opacite, donc la part de flou melangee a l'image nette, et la
   transition se lit comme une ligne. Trois intensites revelees a des hauteurs
   differentes font varier le rayon. Chacun floute la sortie du precedent, les
   rayons se cumulent. */
.raccord-flou {
  --montee: 26vh;
  position: absolute; left: 0; right: 0;
  top: calc(var(--montee) * -1);
  /* La bande descend bien au-dela du point ou le fond devient opaque. Calee
     pile dessus, son bord bas restait lisible : a cet endroit le fond n'est
     opaque qu'a la toute derniere etape du degrade, et la frontiere du
     `backdrop-filter` -- floute au-dessus, net en dessous -- se voyait comme un
     trait en travers des boutons. Plus bas, il n'y a plus rien derriere a
     flouter, donc plus rien a voir. */
  height: calc(var(--montee) + clamp(140px, 15vw, 230px) + 22vh);
  z-index: 0; pointer-events: none;
}
.raccord-flou span {
  position: absolute; inset: 0;
  -webkit-backdrop-filter: blur(var(--f));
  backdrop-filter: blur(var(--f));
}
.raccord-flou span:nth-child(1) {
  --f: 3px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 30%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 30%);
}
.raccord-flou span:nth-child(2) {
  --f: 9px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 22%, #000 48%);
  mask-image: linear-gradient(to bottom, transparent 22%, #000 48%);
}
.raccord-flou span:nth-child(3) {
  --f: 20px;
  /* Le dernier palier redescend a transparent avant le bord : meme sans rien de
     visible derriere, une coupure franche du flou peut laisser une couture. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 42%, #000 64%, #000 88%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 42%, #000 64%, #000 88%, transparent 100%);
}
/* Un `backdrop-filter` par-dessus une video en lecture se recalcule a chaque
   image : trois calques empiles coutent trois flous par image. Sur telephone on
   n'en garde qu'un. */
@media (max-width: 768px) {
  .raccord-flou { --montee: 14vh; }
  .raccord-flou span:nth-child(1), .raccord-flou span:nth-child(2) { display: none; }
  .raccord-flou span:nth-child(3) {
    --f: 12px;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 72%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 72%);
  }
}
/* Le pied de page doit etre opaque lui aussi, sinon la video fixe reapparait
   sous lui. */
.site-footer { z-index: 2; background: var(--bg); }

/* Troisieme blob, celui-ci porte par la section Projets elle-meme plutot que
   par le conteneur de page : il reste ainsi cale sur la section meme si le
   contenu au-dessus s'allonge. Il n'est pas rogne, son debordement vertical
   sur les sections voisines fait justement la transition. Les enfants de la
   section passent en z-index 1, sans quoi un element positionne comme celui-ci
   se peindrait par-dessus du contenu non positionne. */
#projets, #parcours { position: relative; }
#projets > .section-head, #projets > .projects,
#parcours > .section-head, #parcours > .two-col { position: relative; z-index: 1; }
.blob-milieu { top: 4vmax; right: -12vmax; z-index: 0; animation: blob-x 17.5s ease-in-out infinite alternate -5s; }
.blob-milieu .blob { width: 44vmax; animation: blob-y 21.5s ease-in-out infinite alternate -9s; }
/* Celui du parcours part de la gauche, pour alterner avec le precedent. */
.blob-parcours { top: 8vmax; left: -14vmax; z-index: 0; animation: blob-x 13.5s ease-in-out infinite alternate -2s; }
.blob-parcours .blob { width: 40vmax; animation: blob-y 19.5s ease-in-out infinite alternate -6s; }

/* ---------------- Sections ---------------- */
.section { max-width: var(--max); margin: 0 auto; padding: 3.4rem 1.25rem; }
.section + .section { border-top: 1px solid var(--line); }
.section-head { display: flex; align-items: baseline; gap: 1rem; margin-bottom: 1.6rem; }
.section-num { font-family: var(--font-display); color: var(--accent); font-size: .95rem; letter-spacing: .2em; }
/* Numeros de section generes par un compteur CSS plutot qu'ecrits en dur. Un
   compteur ignore les elements masques : a l'ecran, sans le parcours, les
   sections vont de 01 a 04 ; sur papier, parcours compris, de 01 a 05. */
.apres-hero { counter-reset: section; }
.section-head { counter-increment: section; }
.section-num::before { content: counter(section, decimal-leading-zero); }

/* Contenu reserve a la version imprimee (le parcours). */
.impression-seule { display: none; }
/* CV papier, assemble par scripts/cv-papier.js : jamais affiche a l'ecran. */
.cv-papier { display: none; }
h2 { font-family: var(--font-display); font-size: clamp(1.8rem, 3.6vw, 2.6rem); font-weight: 800; letter-spacing: -.01em; }
h3 { font-family: var(--font-display); font-size: 1.2rem; font-weight: 700; }
.sub-title { color: var(--accent-2); text-transform: uppercase; letter-spacing: .16em; font-size: .85rem; margin-bottom: 1rem; }

.reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s ease; }
.reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .blob-piste, .blob { animation: none; }
  html { scroll-behavior: auto; }
}

.two-col { display: grid; grid-template-columns: 1.5fr 1fr; gap: 2rem; align-items: start; }
.two-col-wide { grid-template-columns: 1.2fr 1fr; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.4rem; }

.prose p + p { margin-top: 1rem; }
.prose { font-size: 1.04rem; color: #d6d3cd; max-width: 62ch; }
.prose h3 { margin: 1.8rem 0 .6rem; color: var(--text); }
.prose h3:first-child { margin-top: 0; }

.card {
  background: linear-gradient(180deg, var(--bg-2), var(--bg-3));
  border: 1px solid var(--line); border-radius: var(--radius); padding: 1.6rem;
  transition: border-color .2s, transform .2s;
}
.card:hover { border-color: rgba(252, 127, 30, .45); }
.card h3 { display: flex; align-items: center; gap: .6rem; }
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 12px var(--accent); }
.card-sub { color: var(--muted); font-size: .9rem; margin: .35rem 0 1.1rem; }


/* A propos : texte et photo cote a cote, centres l'un sur l'autre. */
.apropos-haut { align-items: center; }
.apropos-haut .portrait { justify-self: center; }

/* Les reperes sous le texte, qui remplacent la carte "En bref". Meme langage
   visuel que les .tags des competences, un cran plus grands. */
.reperes { list-style: none; display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1.8rem; padding: 0; }
.reperes li {
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: .5rem .95rem; font-size: .92rem; color: var(--text);
  background: rgba(255, 255, 255, .02);
  transition: border-color .2s ease;
}
/* Survol : la bordure seule passe a l'orange de l'accent. Seulement sur un pointeur
   qui survole vraiment : sur ecran tactile, :hover reste colle apres un tap. */
@media (hover: hover) {
  .reperes li:hover { border-color: rgba(252, 127, 30, .6); }
}

.tags { display: flex; flex-wrap: wrap; gap: .45rem; }
.tags li {
  font-size: .82rem; padding: .32rem .7rem; border-radius: 2.75px; border: 1px solid var(--line-strong);
  color: #e6e3dd; background: rgba(255, 255, 255, .02);
}
.tags-small li { font-size: .76rem; padding: .25rem .6rem; }

/* ---------------- Projets ---------------- */
.projects { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.4rem; }
.project {
  position: relative; padding: 1.7rem; border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--bg-2); overflow: hidden; transition: border-color .2s, transform .2s;
}
.project::after {
  content: ""; position: absolute; inset: auto -40% -60% auto; width: 60%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, rgba(252, 127, 30, .16), transparent 65%); pointer-events: none;
  opacity: 0; transition: opacity .3s;
}
.project:hover { border-color: rgba(252, 127, 30, .5); transform: translateY(-2px); }
.project:hover::after { opacity: 1; }
.project-meta { display: flex; justify-content: space-between; gap: 1rem; font-size: .8rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-bottom: .8rem; }
.project-year { color: var(--accent-2); }
.project h3 { font-size: 1.35rem; margin-bottom: .6rem; }
.project h3 a { color: var(--text); }
.project h3 a::after { content: " ↗"; color: var(--accent); font-size: .9em; }
.project p { color: #d6d3cd; margin-bottom: 1rem; }

/* Cartes vidéo : la vignette YouTube est servie en local, la CSP du site
   interdisant les images externes (img-src 'self' data:). */
.sub-title-spaced { margin-top: 3rem; }
.project-film { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.project-film > :not(.film-media) { padding-inline: 1.4rem; }
.project-film > :last-child { padding-bottom: 1.4rem; }
.film-media {
  display: block; position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  background: var(--bg-3); border-bottom: 1px solid var(--line);
}
.film-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .4s ease, filter .3s ease; filter: saturate(.85) brightness(.85); }
.project-film:hover .film-media img { transform: scale(1.04); filter: none; }
.film-play {
  position: absolute; inset: 50% auto auto 50%; transform: translate(-50%, -50%);
  width: 54px; height: 54px; border-radius: 50%;
  background: rgba(11, 11, 13, .68); border: 1px solid var(--accent);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  transition: background .25s ease, transform .25s ease;
}
.film-play::before {
  content: ""; position: absolute; inset: 50% auto auto 54%; transform: translate(-50%, -50%);
  border-style: solid; border-width: 9px 0 9px 15px;
  border-color: transparent transparent transparent var(--accent);
}
.project-film:hover .film-play { background: var(--accent); transform: translate(-50%, -50%) scale(1.06); }
.project-film:hover .film-play::before { border-left-color: #0b0b0d; }
.project-film .project-meta { margin-top: 1.1rem; }
.project-film h3 { font-size: 1.2rem; }
.film-links { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .9rem; }
.film-links a {
  display: inline-block; font-size: .78rem; padding: .28rem .65rem; border-radius: 2.75px;
  border: 1px solid var(--line-strong); color: #e6e3dd;
}
.film-links a:hover { border-color: var(--accent); color: var(--accent-2); text-decoration: none; }

/* ---------------- Timeline ---------------- */
.timeline { position: relative; padding-left: 1.6rem; }
.timeline li:not(:last-child)::after {
  content: ""; position: absolute; left: calc(-1.6rem + 5px);
  top: calc(.45rem + 14px); bottom: -.45rem; width: 1px;
  background: var(--line-strong);
}
.timeline li { position: relative; padding-bottom: 1.25rem; }
.timeline li:last-child { padding-bottom: 0; }
.timeline li::before {
  content: ""; position: absolute; left: -1.6rem; top: .45rem; width: 11px; height: 11px; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--accent); box-shadow: 0 0 10px rgba(252, 127, 30, .5);
}
.tl-date { display: block; color: var(--accent-2); font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; margin-bottom: .3rem; }
.tl-body h4 { font-family: var(--font-display); font-size: 1.08rem; font-weight: 700; }
.tl-org { color: var(--muted); font-size: .9rem; margin: .15rem 0 .5rem; }
.tl-body p:last-child { color: #d6d3cd; font-size: .95rem; }

/* ---------------- Contact ---------------- */
.contact-card { text-align: center; padding: 2rem 1.6rem; }
.contact-lead { font-size: 1.25rem; max-width: 40ch; margin: 0 auto; }
.contact-card .contact-actions { justify-content: center; }
.contact-note { color: var(--muted); font-size: .9rem; margin-top: 1.2rem; }

/* ---------------- Footer ---------------- */
.site-footer {
  border-top: 1px solid var(--line); padding: 1.4rem 1.25rem 1.8rem; text-align: center; color: var(--muted); font-size: .85rem;
}
.site-footer p + p { margin-top: .4rem; }

.legal { padding-top: 4rem; }

/* ---------------- Responsive ---------------- */
@media (max-width: 900px) {
  .two-col, .two-col-wide, .grid-3, .projects { grid-template-columns: 1fr; }
  .hero-line:first-child { letter-spacing: 0; }
  .hero-accent { letter-spacing: .2em; }
  .intro { padding-top: 2.6rem; }
}
@media (max-width: 1060px) {
  .burger { display: flex; }
  .nav-socials { order: 2; margin-left: auto; margin-right: .1rem; gap: .3rem; }
  .burger { order: 3; }
  .nav-socials a { width: 26px; height: 26px; }
  .nav-socials svg, .marque-malt { width: 17px; height: 17px; }
  .brand-prodepix img { width: 22px; height: 22px; }
  .brand-prodepix { padding: 0 .7rem 0 0; gap: .4rem; font-size: .82rem; }
  .nav { gap: .45rem; }
  .nav-links {
    position: absolute; top: calc(100% + .5rem); right: 1.25rem; left: 1.25rem;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--bg-2); border: 1px solid var(--line-strong); border-radius: var(--radius);
    padding: .5rem; opacity: 0; pointer-events: none; transform: translateY(-6px); transition: .2s;
  }
  .nav-links a, .nav-links .btn { display: block; padding: .8rem 1rem; text-align: center; }
  .nav-links .btn { margin: .4rem; }
  .nav-open .nav-links { opacity: 1; pointer-events: auto; transform: none; }
  .nav-links-static { position: static; opacity: 1; pointer-events: auto; transform: none; flex-direction: row; border: 0; background: none; padding: 0; }
}

@media (max-width: 760px) {
  .section { padding: 2.4rem 1.25rem; }
}

/* =====================================================================
   Impression : la page devient un CV A4, fond blanc, sans navigation.
   ===================================================================== */
/* Sur les plus petits ecrans, le bloc ne garde que le logo : avec le nom, les
   deux icones et le burger, le texte ferait deborder la barre. */
@media (max-width: 420px) {
  .brand-prodepix-texte { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .brand-prodepix { padding: 0 .6rem 0 0; }
}

@media print {
  @page { size: A4; margin: 12mm 15mm; }
  :root { --text: #111; --muted: #555; --line: #ddd; --line-strong: #bbb; --bg: #fff; --bg-2: #fff; --bg-3: #fff; }
  html { scroll-behavior: auto; }
  body { background: #fff; color: #111; font-size: 10.5pt; line-height: 1.4; }
  .site-header, .nav-socials, .burger, .blobs-page, .hero-actions, .hero-showreel, .raccord-flou, .brand-prodepix, .contact-actions, .site-footer, .skip-link, .btn { display: none !important; }
  /* Sur papier le hero redevient un simple titre : ni video, ni hauteur
     d'ecran, ni voile sombre. */
  .hero { height: auto; min-height: 0; display: block; padding: 0; overflow: visible; }
  .hero::after { display: none; }
  .hero-inner { text-align: left; padding: 0; max-width: none; }
  .intro { max-width: none; padding: 0 0 6mm; text-align: left; border-bottom: 1px solid #bbb; }
  .hero-lead { margin-left: 0; }
  .hero-actions { justify-content: flex-start; }
  .portrait { display: none; }
  .hero-line:first-child { font-size: 22pt; text-shadow: none; }
  .hero-accent { font-size: 12pt; color: #444; margin-top: 2pt; letter-spacing: .12em; text-shadow: none; }
  .hero-lead { font-size: 10.5pt; color: #222; margin-top: 4mm; max-width: none; }
  .eyebrow { color: #a65414; margin-bottom: 2mm; }
  .section { padding: 5mm 0 0; }
  .card, .project, .timeline li, .section-head { break-inside: avoid; }
  .section + .section { border-top: 0; }
  .section-head { margin-bottom: 2.5mm; }
  .section-num { color: #a65414; }
  h2 { font-size: 13pt; }
  h3 { font-size: 11pt; }
  .reveal { opacity: 1 !important; transform: none !important; }
  .two-col, .two-col-wide { grid-template-columns: 1.4fr 1fr; gap: 8mm; }
  .grid-3 { grid-template-columns: repeat(3, 1fr); gap: 4mm; }
  .projects { grid-template-columns: repeat(2, 1fr); gap: 4mm; }
  .card, .project { border: 1px solid #ccc; background: #fff; padding: 3.5mm; border-radius: 2.75px; box-shadow: none; }
  .project::after, .dot, .film-media { display: none; }
  .project-film > :not(.film-media) { padding-inline: 0; }
  .film-links a { border-color: #bbb; color: #222; font-size: 8pt; }
  .sub-title-spaced { margin-top: 4mm; }
  .project h3 { font-size: 11pt; }
  .project h3 a { color: #111; }
  .project h3 a::after { content: ""; }
  .project p, .prose, .tl-body p:last-child { color: #222; font-size: 9.5pt; }
  .tags li { border-color: #bbb; color: #222; font-size: 8pt; padding: .5mm 2mm; background: #fff; }
  .timeline li:not(:last-child)::after { background: #bbb; }
  .timeline li::before { box-shadow: none; border-color: #a65414; background: #fff; }
  .timeline li { padding-bottom: 3mm; }
  .tl-date, .project-year, .sub-title { color: #a65414; }
  .card-sub, .tl-org, .project-meta { color: #555; }
  .reperes { gap: 2mm; margin-top: 3mm; }
  .reperes li { border-color: #bbb; background: none; color: #222; padding: 1mm 2.5mm; font-size: 9pt; }
  .contact-card { text-align: left; padding: 3mm; }
  .contact-lead { font-size: 10.5pt; margin: 0; max-width: none; }
  .contact-note { margin-top: 1mm; color: #333; }
  .contact-note::before { content: "Contact : prodepix.fr/contact · "; }
  a { color: #111; }

  /* Compaction du CV papier, qui faisait 4 pages dont deux a moitie vides. */
  /* Le degrade de raccord avec la video part du noir : sur papier, ou le fond
     de page est blanc, il imprimait une bande gris fonce derriere l'intro. */
  .apres-hero { background: none; overflow: visible; }
  /* .blobs-page etait deja masque, pas les blobs portes par les sections. */
  .blob-piste { display: none !important; }
  .hero, .hero-inner, .hero h1 { text-align: left; }
  /* La photo est masquee a l'impression mais sa colonne restait reservee :
     le texte d'A propos s'imprimait sur la moitie de la largeur. */
  .apropos-haut { display: block; }
  /* Parcours en une seule colonne, formation sous l'experience. En deux
     colonnes, la formation s'arretait en page 2 et les onze experiences
     continuaient seules sur deux pages, la moitie droite blanche. */
  #parcours .two-col { display: block; }
  #parcours .two-col > div + div { margin-top: 4mm; }
  .timeline li { padding-bottom: 2mm; }
  .tl-body p:last-child { font-size: 8.8pt; }
  /* Projets : trois colonnes de cartes resserrees au lieu de deux colonnes de
     grandes boites creuses. */
  .projects { grid-template-columns: repeat(3, 1fr); gap: 3mm; }
  .project { padding: 2.5mm 3mm; }
  .project-film > :last-child { padding-bottom: 0; }
  .project-meta { margin-bottom: 1mm; font-size: 7pt; }
  .project h3 { font-size: 10pt; margin-bottom: 1.5mm; }
  .grid-3 .card { padding: 2.5mm 3mm; }
  .card-sub { margin: .5mm 0 2mm; font-size: 8.5pt; }
  /* Le titre restait centre et reduit a sa largeur. Le hero d'ecran porte
     `place-items: center` ; les Chromium recents appliquent justify-items aux
     blocs ordinaires, plus seulement aux grilles, donc meme passe en `block`
     il centrait encore son contenu. Constate en lisant les styles calcules en
     mode impression : .hero-inner faisait 234 px de large sur 634. */
  .hero { display: block; place-items: normal; }
  /* Sauts de page : le parcours ouvre la page 2 au lieu de laisser son titre
     seul en bas de la page 1, et aucun intitule ne se separe de son contenu. */
  .impression-seule { display: block; }
  #parcours { break-before: page; }
  .section-head, .sub-title { break-after: avoid; }
  #contact { break-inside: avoid; padding-top: 3mm; }
  /* Sur papier le cadre n'apporte rien : sans lui le contact tient en bas de
     la page 2 au lieu d'ouvrir une page 3 pour deux lignes. */
  .contact-card { padding: 0; border: 0; }
  /* 62 caracteres de large, pense pour l'ecran : sur A4 le texte d'A propos
     n'occupait que la moitie de la page. */
  .prose { max-width: none; }
  /* Experiences et formation en deux colonnes. La frise -- ligne verticale et
     pastilles -- n'a pas de sens coupee en colonnes : sur papier, date en
     couleur puis intitule, comme un CV classique. */
  .timeline { padding-left: 0; columns: 2; column-gap: 8mm; }
  .timeline li::before, .timeline li:not(:last-child)::after { display: none; }
  .timeline li { break-inside: avoid; padding-bottom: 2mm; }
  .tl-date { margin-bottom: .3mm; font-size: 7.5pt; }
  .tl-body h4 { font-size: 10pt; }
  .tl-org { margin: 0 0 .8mm; font-size: 8.5pt; }

  /* ================= CV PAPIER =================
     Quand scripts/cv-papier.js a assemble le CV, lui seul s'imprime : tout le
     reste de la page est masque. Sans le script, les regles ci-dessus
     impriment encore le site, comme avant. */
  body.cv-pret > *:not(.cv-papier) { display: none !important; }
  body.cv-pret { font-size: 9.3pt; line-height: 1.38; color: #1a1a1a; }
  .cv-papier { display: block; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .cv-papier a { color: inherit; text-decoration: none; }

  .cv-tete {
    display: flex; justify-content: space-between; align-items: flex-end; gap: 8mm;
    padding-bottom: 4mm; margin-bottom: 5mm; border-bottom: 1.5pt solid #a65414;
  }
  .cv-nom { font-family: "Coolvetica", var(--font-display); font-size: 26pt; line-height: 1; letter-spacing: .01em; text-transform: uppercase; color: #111; }
  .cv-metier { font-size: 12pt; color: #a65414; letter-spacing: .14em; text-transform: uppercase; margin-top: 2mm; }
  .cv-accroche { font-size: 8.5pt; color: #666; letter-spacing: .08em; text-transform: uppercase; margin-top: 1mm; }
  .cv-coordonnees { display: flex; flex-direction: column; align-items: flex-end; gap: .8mm; font-style: normal; font-size: 8.8pt; color: #333; }

  .cv-corps { display: grid; grid-template-columns: 54mm 1fr; column-gap: 7mm; align-items: start; }
  .cv-cote { background: #f4f1ec; padding: 4mm 4mm 2mm; }
  .cv-bloc { margin-bottom: 5mm; }
  .cv-titre {
    font-family: var(--font-body); font-size: 8.3pt; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
    color: #a65414; padding-bottom: 1.2mm; margin-bottom: 2.5mm; border-bottom: .6pt solid #d9d2c7;
  }
  .cv-cote h3 { font-family: var(--font-body); font-size: 9pt; font-weight: 700; color: #111; }
  .cv-groupe { margin-bottom: 3mm; }
  .cv-groupe p { font-size: 8.4pt; color: #333; margin-top: .6mm; }
  .cv-liste { list-style: none; padding: 0; }
  .cv-liste li { font-size: 8.6pt; padding: .7mm 0 .7mm 3mm; position: relative; }
  .cv-liste li::before { content: ""; position: absolute; left: 0; top: 2.35mm; width: 1.3mm; height: 1.3mm; border-radius: 50%; background: #a65414; }
  .cv-formation { margin-bottom: 3mm; break-inside: avoid; }
  .cv-date { font-size: 7.8pt; letter-spacing: .1em; text-transform: uppercase; color: #a65414; white-space: nowrap; }
  .cv-org { font-size: 8.4pt; color: #666; }

  .cv-texte { font-size: 9pt; color: #222; }
  .cv-texte + .cv-texte { margin-top: 1.8mm; }
  .cv-poste { margin-bottom: 3.6mm; break-inside: avoid; }
  .cv-poste-tete { display: flex; justify-content: space-between; align-items: baseline; gap: 4mm; }
  .cv-principal h3 { font-family: var(--font-body); font-size: 10pt; font-weight: 700; color: #111; }
  .cv-poste .cv-org { margin: .3mm 0 1mm; }
  .cv-projets { list-style: none; padding: 0; }
  .cv-projets li { font-size: 9pt; padding: .8mm 0; border-bottom: .4pt solid #eee; }
  .cv-projets li:last-child { border-bottom: 0; }
  .cv-projets a { font-weight: 700; color: #111; }
  .cv-titre { break-after: avoid; }

}
