/* ============================================================
   Portfolio — Matheline Chevalier
   Papier blanc cassé, typographie serif/script, accents vert sauge
   ============================================================ */

/* ------------------------------------------------------------
   THÈME CLAIR — palette de référence.

   Les jetons décrivent un RÔLE, pas une teinte : `--sage-900` est
   « la couleur du texte d'accent », claire sur fond sombre et foncée sur
   fond clair. C'est ce qui permet au thème sombre plus bas de ne
   redéfinir que ces quelques lignes, sans toucher au reste du fichier.

   Le thème sombre est posé par theme.js, qui écrit `data-theme` sur
   <html> avant le premier rendu — y compris quand le choix vient du
   système. D'où un seul bloc `[data-theme="dark"]` ici, et pas de
   `@media (prefers-color-scheme)` qui le dupliquerait. Conséquence
   assumée : sans JavaScript, le site reste en thème clair — comme il
   reste sans projets ni parcours, qui sont eux aussi injectés.
   ------------------------------------------------------------ */
:root {
  color-scheme: light;

  --paper:      #ffffff;
  --paper-warm: #fafafa;   /* fond du bandeau haut */
  --ink:        #0a0a0a;
  --ink-soft:   #4a4a4a;

  --sage-100:   #e7efea;
  --sage-200:   #cfded6;   /* fond des cartes projet */
  --sage-400:   #a7c4b0;
  --sage-500:   #6e9f86;   /* pétales décoratifs */
  --sage-700:   #5f967a;   /* ombre pleine des cartes */
  --sage-900:   #3f5a49;   /* texte d'accent (yeux, libellés, liens) */

  --line:       #e5e5e5;

  /* Nuances qui n'existent qu'à un endroit, mais qui doivent basculer */
  --card-hover:   #d8e6df;                   /* carte projet au survol */
  --card-shadow:  rgba(10, 10, 10, 0.45);    /* ombre portée au survol */
  --pill-on-card: rgba(255, 255, 255, 0.55); /* pastilles sur fond sauge */
  --pill-on-card-border: rgba(95, 150, 122, 0.35);
  --petal:         #6e9f86;                  /* corolles du décor */
  --petal-opacity: 0.83;
  /* Le lettrage et le monogramme sont des SVG noirs servis en <img> : le CSS
     ne peut pas atteindre leurs tracés. En thème sombre ils sont inversés,
     ce qui suffit puisqu'ils sont monochromes. */
  --lettering-filter: none;

  /* Typographie */
  /* Polices de la maquette Canva.
     Anaktoria (titres, nav) est servie en local : elle n'est pas sur Google Fonts.
     Le prénom est en Amsterdam Three — police sous licence Canva, non diffusable
     sur le web : le lettrage du hero est donc un SVG tracé depuis la maquette.

     Le texte courant était en IM Fell English, une romaine du XVIIe siècle
     redessinée à l'identique, jambages compris. Très juste avec le reste, mais
     illisible sur la longueur en thème sombre : ses traits fins tombent sous le
     pixel et se dissolvent dans le fond, et comme elle n'existe qu'en romain, le
     navigateur simulait gras et italique. Lora garde l'esprit sérif du site avec
     des pleins qui tiennent sur fond sombre, et apporte ses vraies graisses. */
  --font-display: "Anaktoria", Georgia, "Times New Roman", serif;
  --font-body:    "Lora", Georgia, "Times New Roman", serif;

  /* Divers */
  --radius:     26px;
  --radius-sm:  14px;
  --container:  1180px;
  --header-h:   76px;
  --transition: 0.25s ease;
  /* Bascule clair / sombre : un peu plus lente que les survols, pour qu'on
     lise le fondu. Alignée sur TRANSITION_MS dans theme.js. */
  --theme-transition: 0.35s ease;
}

/* ------------------------------------------------------------
   THÈME SOMBRE

   Les rôles s'inversent : les sauges très clairs (100, 200), qui servent
   de fonds, deviennent des sauges très sombres, tandis que `--sage-900`,
   qui sert de texte d'accent, devient clair. Les valeurs sont légèrement
   vertes plutôt que grises, pour garder le parti pris du site.
   ------------------------------------------------------------ */
[data-theme="dark"] {
  color-scheme: dark;

  --paper:      #17211c;   /* surfaces posées : cartes, encarts */
  --paper-warm: #101614;   /* fond de page et bandeau */
  --ink:        #ecefea;
  --ink-soft:   #a7b1a9;

  --sage-100:   #1c2823;   /* fonds teintés discrets */
  --sage-200:   #24352c;   /* fond des cartes projet */
  --sage-400:   #3d5748;   /* filets et bordures */
  --sage-500:   #6e9f86;
  --sage-700:   #55806a;
  --sage-900:   #9dc3ad;   /* texte d'accent : clair, ici */

  --line:       #27322c;

  --card-hover:   #2c4034;
  --card-shadow:  rgba(0, 0, 0, 0.65);
  --pill-on-card: rgba(255, 255, 255, 0.07);
  --pill-on-card-border: rgba(157, 195, 173, 0.28);
  --petal:         #6e9f86;
  /* Le même vert sur fond sombre ressort beaucoup plus : le décor
     redeviendrait le premier élément lu de la page. */
  --petal-opacity: 0.30;
  --lettering-filter: invert(1);
}

/* ------------------------------------------------------------
   BASCULE D'UN THÈME À L'AUTRE

   Le basculement ne doit pas être brutal. Plutôt que de lister les
   quelques éléments à adoucir — la liste était toujours incomplète, et
   filets, pastilles, icônes et cartes sautaient d'un coup pendant que le
   fond, lui, fondait —, la transition est posée sur toute la page, mais
   seulement pendant la bascule : theme.js écrit `data-theme-switching`
   sur <html> puis le retire au bout de --theme-transition.

   C'est ce qui la rend sans effet le reste du temps : au premier rendu
   (rien ne doit fondre depuis le thème clair) comme au survol, où chaque
   élément garde sa propre transition. Seules les propriétés qui changent
   avec le thème sont animées ; ni `transform` ni `opacity`, pour ne pas
   marcher sur les apparitions au défilement ni sur le carrousel.
   ------------------------------------------------------------ */
[data-theme-switching] *,
[data-theme-switching] *::before,
[data-theme-switching] *::after {
  transition: background-color var(--theme-transition),
    border-color var(--theme-transition),
    color var(--theme-transition),
    fill var(--theme-transition),
    fill-opacity var(--theme-transition),
    stroke var(--theme-transition),
    box-shadow var(--theme-transition),
    outline-color var(--theme-transition),
    text-decoration-color var(--theme-transition),
    filter var(--theme-transition);
}

@media (prefers-reduced-motion: reduce) {
  [data-theme-switching] *,
  [data-theme-switching] *::before,
  [data-theme-switching] *::after { transition: none; }
}

/* Anaktoria — George Douros, Unicode Fonts for Ancient Scripts.
   « Fonts in this site are free for any use » (v6.31). */
@font-face {
  font-family: "Anaktoria";
  src: url("fonts/Anaktoria.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- Reset léger ---------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* L'en-tête est collant : les ancres s'arrêtent au-dessus de la cible pour
   qu'elle ne passe pas dessous. */
:target, [id] { scroll-margin-top: calc(var(--header-h) + 40px); }
body {
  margin: 0;
  position: relative;
  overflow-x: clip;
  font-family: var(--font-body);
  font-size: 1.05rem;
  color: var(--ink);
  background: var(--paper-warm);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
ul, ol { list-style: none; margin: 0; padding: 0; }
h1, h2, h3 { font-family: var(--font-display); line-height: 1.1; margin: 0; font-weight: 400; }

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 32px;
}

/* ============================================================
   DÉCOR — pétales verts (injectés par app.js)
   ============================================================ */
.deco-layer {
  position: absolute;
  inset: 0;
  overflow: clip;
  pointer-events: none;
  /* Tout en fond : aucune section n'a de fond opaque (c'est le body qui porte
     la couleur), les pétales restent donc visibles partout tout en passant
     derrière le texte, les cartes et l'en-tête. En haut de page l'en-tête est
     transparent : ils débordent dessus comme sur la maquette. */
  z-index: 0;
}
.deco { position: absolute; pointer-events: none; will-change: rotate; }
/* app.js écrit `fill` et `fill-opacity` comme attributs sur le <g> : ce sont
   des attributs de présentation, de priorité inférieure à n'importe quelle
   règle CSS. Ces deux lignes les emportent donc, et le décor suit le thème
   sans que le JavaScript ait à connaître la palette. */
.deco g {
  fill: var(--petal);
  fill-opacity: var(--petal-opacity);
}
/* Le pivot est le cœur de la corolle (et non le centre du SVG), pour que la
   rotation au défilement ressemble à une fleur qui tourne sur sa tige. */
.deco-tr { transform-origin: 87.5% 50%; }
.deco-l  { transform-origin: 22.5% 50%; }
/* Les grappes sont dimensionnées en vw : la page reste une mise à l'échelle
   fidèle de la maquette (dessinée pour 1366 px) quelle que soit la fenêtre. */
/* Grappe haut-droite : déborde sur l'en-tête, comme sur la maquette */
.deco-tr { top: -22.7vw; right: -8vw; width: 44vw; }
/* Grappe gauche : centrée sur le bas du premier écran, comme la maquette */
.deco-l  { top: calc(100vh - 24.75vw); left: -9.8vw; width: 44vw; }
@supports (height: 100svh) { .deco-l { top: calc(100svh - 24.75vw); } }

/* Les grappes sont décalées vers l'extérieur quand la page se resserre,
   pour ne jamais passer sous le texte. */
@media (max-width: 1280px) { .deco-l { left: -260px; } }
@media (max-width: 1150px) { .deco-l { left: -320px; } }
@media (max-width: 900px) {
  .deco-tr { width: 380px; top: -200px; right: -70px; }
  .deco-l  { display: none; }
}

/* ============================================================
   BOUTONS / LIENS
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 30px;
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  border: 1px solid transparent;
  transition: transform var(--transition), background var(--transition),
    color var(--transition), border-color var(--transition);
}
.btn-primary {
  background: var(--sage-200);
  color: var(--ink);
}
/* sans ombre, c'est le fond qui se fonce pour marquer le survol */
.btn-primary:hover { transform: translate(-2px, -2px); background: var(--sage-400); }
.btn-ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--sage-400);
}
.btn-ghost:hover { background: var(--sage-100); }

.link-arrow {
  letter-spacing: 0.06em;
  color: var(--sage-900);
  transition: color var(--transition);
}
.link-arrow:hover { color: var(--ink); }

/* Flèches décoratives (— ►) */
.arrow {
  position: relative;
  display: inline-block;
  width: clamp(32px, 4vw, 82px);
  height: 1px;
  background: var(--ink);
  flex-shrink: 0;
}
.arrow::after {
  content: "";
  position: absolute;
  right: -1px;
  top: -3.5px;
  border-left: 8px solid var(--ink);
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
}
.arrow-flip { transform: scaleX(-1); }

/* ============================================================
   HEADER / NAV
   ============================================================ */
/* Transparent en haut de page (les pétales débordent dessus, comme la maquette),
   opaque dès qu'on défile pour rester lisible. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
  transition: background var(--transition), box-shadow var(--transition);
}
.site-header.is-scrolled {
  background: var(--paper-warm);
  box-shadow: 0 1px 0 var(--line);
}
.nav {
  position: relative;
  display: flex;
  align-items: center;
  max-width: none;          /* bandeau pleine largeur, comme la maquette */
  padding-inline: 36px;
  height: var(--header-h);
}
.brand {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  line-height: 0;
}
.brand img { width: 68px; height: auto; filter: var(--lettering-filter); }
.nav-links {
  position: absolute;
  inset-inline: 8%;
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  font-family: var(--font-display);   /* nav en Anaktoria, comme la maquette */
  font-size: 1.15rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.nav-links a {
  position: relative;
  padding-bottom: 3px;
  color: var(--ink);
  transition: color var(--transition);
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--sage-700);
  transform: scaleX(0);
  transition: transform var(--transition);
}
.nav-links a:hover::after,
.nav-links a.is-active::after { transform: scaleX(1); }
.nav-links a.is-active { color: var(--sage-900); }

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  margin-left: auto;
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px;
}
.nav-toggle span {
  width: 24px;
  height: 1.5px;
  background: var(--ink);
  transition: transform var(--transition), opacity var(--transition);
}

/* ---------- Sélecteur de langue ----------
   Deux boutons plutôt qu'un menu déroulant : avec seulement deux langues, le
   choix disponible se lit d'un coup d'œil et se prend en un clic. Ils reprennent
   le soulignement des liens de nav pour ne pas introduire une seconde grammaire
   visuelle dans le bandeau. */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.lang-btn {
  position: relative;
  padding: 0 0 3px;
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  letter-spacing: inherit;
  color: var(--ink-soft);
  transition: color var(--transition);
}
.lang-btn::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--sage-700);
  transform: scaleX(0);
  transition: transform var(--transition);
}
.lang-btn:hover { color: var(--ink); }
.lang-btn:hover::after,
.lang-btn.is-active::after { transform: scaleX(1); }
.lang-btn.is-active { color: var(--sage-900); }
.lang-sep { color: var(--line); }

/* ---------- Bouton de thème ----------
   Voisin du sélecteur de langue : ce sont les deux mêmes gestes, choisir
   comment le site s'affiche plutôt qu'où l'on va. L'icône montre le thème
   vers lequel on bascule, pas celui qui est actif — c'est ce que le clic
   promet. L'état, lui, est porté par `aria-pressed`. */
.theme-btn {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  margin-left: 14px;
  padding: 0;
  background: none;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  color: var(--ink-soft);
  transition: color var(--transition), background var(--transition);
}
.theme-btn:hover { color: var(--ink); background: var(--sage-100); }
.theme-btn:focus-visible { outline: 2px solid var(--sage-700); outline-offset: 2px; }
.theme-icon { width: 19px; height: 19px; display: block; }
/* Thème clair : on propose la lune. Thème sombre : on propose le soleil. */
.theme-icon-sun { display: none; }
[data-theme="dark"] .theme-icon-sun { display: block; }
[data-theme="dark"] .theme-icon-moon { display: none; }

/* ============================================================
   HERO (accueil)
   ============================================================ */
/* Pas de séparation visible entre le hero et la suite : même fond, pas de trait.
   Le hero occupe exactement le premier écran pour que la flèche de défilement
   reste toujours visible sans scroller. */
.hero {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: calc(100vh - var(--header-h));
  min-height: calc(100svh - var(--header-h));
  padding: 30px 0 clamp(80px, 9vw, 150px);
  text-align: center;
}
.hero > .container,
.page-head > .container { position: relative; z-index: 1; }
.hero-name { margin: 0; }
/* Lettrage vectorisé depuis la maquette : proportions et calage identiques,
   net à n'importe quelle taille d'écran. */
.hero-wordmark {
  display: block;
  width: 44vw;
  max-width: 940px;
  height: auto;
  margin-inline: auto;
  filter: var(--lettering-filter);
}
.hero-tagline {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(14px, 1.9vw, 40px);
  margin: clamp(40px, 7.1vw, 150px) 0 0;
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 1.2vw, 1.55rem);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin-top: 48px;
}

/* ---------- Invitation à faire défiler ---------- */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: clamp(18px, 2.2vw, 40px);
  translate: -50% 0;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  opacity: 0.45;
  transition: opacity var(--transition), translate var(--transition);
}
.scroll-cue:hover { opacity: 0.9; }
.scroll-cue-arrow {
  width: 15px;
  height: 15px;
  border-right: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  rotate: 45deg;
  margin-top: -6px;
  animation: scroll-cue 2.6s ease-in-out infinite;
}
@keyframes scroll-cue {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50%      { transform: translateY(6px); opacity: 1; }
}

/* ---------- Intro ---------- */
.intro {
  position: relative;
  z-index: 1;
  padding: 120px 0 10px;
  /* La marge d'ancrage générale (en-tête + 40px) s'ajouterait aux 120px de
     respiration de la section : la flèche du hero s'arrêterait trop haut, en
     laissant le bas du hero visible. Ici le padding suffit à dégager le texte
     de l'en-tête collant. */
  scroll-margin-top: 0;
}
.intro-text {
  max-width: 940px;
  margin: 0 0 0 auto;   /* bloc calé à droite, comme la maquette */
  text-align: justify;
  font-size: 1.12rem;
}

/* ============================================================
   SECTIONS
   ============================================================ */
.section {
  position: relative;
  z-index: 1;
  padding: 70px 0;
}
.section-title {
  font-size: clamp(1.6rem, 2.9vw, 2.2rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin-bottom: 44px;
}
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 44px;
}
.section-head .section-title { margin-bottom: 0; }

/* ---------- En-tête de page (projects.html / project.html) ---------- */
.page-head {
  position: relative;
  z-index: 1;
  padding: 90px 0 60px;
  text-align: center;
}
.page-title {
  font-size: clamp(2.2rem, 6vw, 3.6rem);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 10px 0 18px;
}
.page-lead {
  max-width: 620px;
  margin: 0 auto;
  color: var(--ink-soft);
  font-size: 1.1rem;
}
.section-eyebrow {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.9rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--sage-900);
}
.back-link {
  display: inline-block;
  margin-bottom: 22px;
  letter-spacing: 0.08em;
  color: var(--sage-900);
}
.back-link:hover { color: var(--ink); }
/* Les deux règles doublent la classe (`.section.section-top-0`) pour passer
   devant le `.section { padding: 54px 0 }` du repli mobile, plus bas dans le
   fichier : à spécificité égale, c'est lui qui gagnait, et le retrait choisi
   ici sautait sous 760 px. */
.section.section-top-0 { padding-top: 56px; }
/* Page contact : la carte est le seul contenu de la page, et l'accroche
   juste au-dessus s'adresse directement à elle. Les 56 px du retrait commun
   les séparaient comme deux sections indépendantes ; ici on les rapproche
   pour qu'elles se lisent d'un bloc. */
.section.section-contact { padding-top: 12px; }

/* ============================================================
   CARTES PROJET
   ============================================================ */
.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 46px 42px;
}
.project-card {
  display: flex;
  flex-direction: column;
  min-height: 300px;
  padding: 26px 32px 22px;
  background: var(--sage-200);
  border-radius: var(--radius);
  transition: transform var(--transition), box-shadow var(--transition),
    background var(--transition);
}
/* Pas d'ombre au repos : au survol, une ombre douce et neutre suffit à faire
   décoller la carte (accueil comme page « Mes projets »). */
.project-card:is(:hover, :focus-visible) {
  transform: translateY(-3px);
  background: var(--card-hover);
  box-shadow: 0 10px 22px -16px var(--card-shadow);
}
.project-card:focus-visible {
  outline: 2px solid var(--sage-900);
  outline-offset: 5px;
}
.project-card-title {
  font-size: 1.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  text-align: center;
  margin-bottom: 18px;
}
.project-card-desc {
  margin: 0;
  text-align: justify;
  hyphens: auto;
  font-size: 1rem;
}
.project-card-media {
  display: grid;
  place-items: center;
  flex: 1;
  min-height: 90px;
  margin-top: 18px;
}
.project-card-media img { max-height: 96px; width: auto; object-fit: contain; }
.project-card-more {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(95, 150, 122, 0.3);
  font-size: 0.95rem;
  letter-spacing: 0.08em;
  color: var(--sage-900);
  transition: color var(--transition);
}
/* La flèche est posée en CSS pour pouvoir glisser toute seule. */
.project-card-more::after {
  content: "→";
  display: inline-block;
  margin-left: 8px;
  transition: transform var(--transition);
}
.project-card:is(:hover, :focus-visible) .project-card-more { color: var(--ink); }
.project-card:is(:hover, :focus-visible) .project-card-more::after {
  transform: translateX(4px);
}
.project-monogram {
  font-family: var(--font-display);
  font-size: 3.6rem;
  line-height: 1;
  color: var(--sage-900);
  opacity: 0.75;
  transition: opacity var(--transition);
}
.project-card:is(:hover, :focus-visible) .project-monogram { opacity: 1; }

/* Mouvement réduit : on garde les changements de couleur, qui suffisent à
   signaler que la carte est cliquable, et on retire les déplacements. */
@media (prefers-reduced-motion: reduce) {
  .project-card,
  .project-card-more::after { transition: none; }
  .project-card:is(:hover, :focus-visible),
  .project-card:is(:hover, :focus-visible) .project-card-more::after { transform: none; }
}

/* ============================================================
   CARROUSEL PROJETS (accueil)
   ============================================================ */
/* Défilement natif avec accroche : molette, trackpad et glissé tactile
   fonctionnent tels quels ; les flèches ne font que piloter le scroll. */
.carousel-viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Les cartes démarrent près du bord gauche (comme la maquette) plutôt que sur
     la colonne de texte. scroll-padding doit reprendre la même valeur, sinon
     l'accroche du premier élément fait disparaître la marge de gauche. */
  padding-inline: clamp(22px, 3.5vw, 64px);
  scroll-padding-inline: clamp(22px, 3.5vw, 64px);
}
.carousel-viewport::-webkit-scrollbar { display: none; }
.carousel-viewport:focus-visible { outline: 2px solid var(--sage-700); outline-offset: 4px; }

.carousel-track { display: flex; }
.carousel-slide {
  flex: 0 0 min(460px, 84vw);
  display: flex;
  scroll-snap-align: start;
  /* marge pour laisser respirer l'ombre pleine des cartes */
  padding: 6px 24px 26px 0;
  transition: opacity 0.4s ease;
}
.carousel-slide .project-card { flex: 1; }
/* les cartes hors cadre s'estompent : on sent qu'il y a une suite */
.carousel-slide.is-outside { opacity: 0.45; }

.carousel-nav { display: flex; gap: 10px; }
.carousel-btn {
  width: 42px;
  height: 42px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--sage-400);
  background: transparent;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background var(--transition), opacity var(--transition),
    border-color var(--transition);
}
.carousel-btn span {
  width: 9px;
  height: 9px;
  border-top: 1px solid var(--ink);
  border-right: 1px solid var(--ink);
}
.carousel-prev span { rotate: -135deg; margin-left: 3px; }
.carousel-next span { rotate: 45deg; margin-right: 3px; }
.carousel-btn:hover:not(:disabled) { background: var(--sage-100); border-color: var(--sage-700); }
.carousel-btn:disabled { opacity: 0.25; cursor: default; }

/* ---------- Flèches posées sur les bords ----------
   Un simple chevron, sans cercle ni fond : il se pose sur les cartes et
   n'apparaît qu'au survol du carrousel. Le défilement marche déjà sans lui
   (molette, trackpad, glissé, flèches du titre de section), il ne fait que
   le rendre évident à la souris.

   Le bouton garde 46 px de zone cliquable alors que le chevron n'en fait
   que 18 : la cible reste confortable à la souris comme au clavier.

   Les sélecteurs doublent la classe (`.carousel-btn.carousel-edge`) pour
   passer devant `.carousel-btn:disabled`, qui laisserait sinon une flèche
   fantôme à 25 % d'opacité alors que rien n'est survolé. */
.carousel { position: relative; }

.carousel-btn.carousel-edge {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  z-index: 2;
  width: 46px;
  height: 46px;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  color: var(--ink);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition), color var(--transition);
}
.carousel-edge-prev { left: clamp(2px, 0.8vw, 14px); }
.carousel-edge-next { right: clamp(2px, 0.8vw, 14px); }

/* Le chevron lui-même. `.carousel-btn span` le dessine en 9 px et 1 px de
   trait, calibré pour les petits boutons ronds du titre de section ; sans
   fond pour le porter, il lui faut ici plus de corps. L'ombre portée le
   détache du texte de la carte qu'il recouvre. */
.carousel-btn.carousel-edge span {
  width: 18px;
  height: 18px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  filter: drop-shadow(0 1px 3px var(--card-shadow));
}
/* La rotation vit sur `.carousel-prev` / `.carousel-next`, que ces
   boutons-ci n'ont pas : sans ces deux lignes le chevron resterait dans son
   orientation brute, un angle pointant en haut à droite. */
.carousel-edge-prev span { rotate: -135deg; margin-left: 5px; }
.carousel-edge-next span { rotate: 45deg; margin-right: 5px; }

.carousel:hover .carousel-btn.carousel-edge {
  opacity: 1;
  pointer-events: auto;
}
/* Au clavier seulement. `:focus-within` restait vrai après un clic souris —
   sur une flèche, une pastille, une carte, ou le viewport lui-même qui est
   focusable —, et les flèches restaient alors affichées souris partie, tant
   qu'on n'avait pas cliqué ailleurs. `:has(:focus-visible)` ne réagit qu'au
   focus que le navigateur juge digne d'être montré, donc pas au clic.

   Règle séparée du survol au-dessus, et non ajoutée à sa liste : un
   navigateur sans `:has()` invaliderait toute la liste, et les flèches ne
   sortiraient plus du tout. */
.carousel:has(:focus-visible) .carousel-btn.carousel-edge {
  opacity: 1;
  pointer-events: auto;
}
/* En bout de course, la flèche n'a plus rien à faire : on l'efface plutôt
   que de la laisser grisée sur la carte qu'elle recouvre. */
.carousel:hover .carousel-btn.carousel-edge:disabled {
  opacity: 0;
  pointer-events: none;
}
.carousel:has(:focus-visible) .carousel-btn.carousel-edge:disabled {
  opacity: 0;
  pointer-events: none;
}
/* `background: none` est indispensable ici : la règle générique
   `.carousel-btn:hover:not(:disabled)` repose un fond sauge, prévu pour les
   boutons ronds du titre de section. Sans coin arrondi pour l'accueillir, il
   apparaissait en rectangle vert derrière le chevron. */
.carousel-btn.carousel-edge:hover:not(:disabled) {
  background: none;
  color: var(--sage-900);
}

/* Sans survol (tactile), ces flèches seraient inatteignables : on les
   retire, et ce sont celles du titre de section qui servent. */
@media (hover: none) {
  .carousel-btn.carousel-edge { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .carousel-btn.carousel-edge { transition: none; }
}

.carousel-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-top: 10px;
}
.carousel-dots { display: flex; gap: 8px; }
.carousel-dot {
  width: 26px;
  height: 3px;
  padding: 0;
  border: none;
  border-radius: 2px;
  background: var(--sage-200);
  cursor: pointer;
  transition: background var(--transition), width var(--transition);
}
.carousel-dot:hover { background: var(--sage-400); }
.carousel-dot.is-active { background: var(--sage-700); width: 44px; }

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

/* ============================================================
   ÉTUDES
   ============================================================ */
.timeline {
  display: grid;
  gap: 34px;
  max-width: 880px;
  margin-inline: auto;
  counter-reset: none;
}
.timeline-item {
  position: relative;
  padding: 28px 30px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 3px solid var(--sage-400);
  border-radius: var(--radius-sm);
}
.timeline-year {
  display: block;
  font-size: 0.9rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--sage-900);
}
.timeline-title { font-size: 1.4rem; margin: 6px 0 2px; font-family: var(--font-body);}
.timeline-place { margin: 0; color: var(--ink-soft); }
.timeline-desc { margin: 16px 0 0; }
.timeline-details {
  display: grid;
  gap: 8px;
  margin-top: 16px;
}
.timeline-details li {
  position: relative;
  padding-left: 20px;
}
.timeline-details li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.7em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--sage-400);
}
.timeline-skills { margin-top: 20px; }

/* ---------- Pastilles de compétences ---------- */
.skill-label {
  font-family: var(--font-display);
  font-size: 0.82rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sage-900);
  margin: 0 0 10px;
}
.skill-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.skill-list li {
  padding: 4px 13px;
  border: 1px solid var(--sage-400);
  border-radius: 999px;
  background: var(--sage-100);
  font-size: 0.9rem;
  line-height: 1.5;
}
/* sur les cartes projet, plus discrètes et sur le fond sauge */
.skill-list-card {
  margin-top: 18px;
  gap: 6px;
}
.skill-list-card li {
  background: var(--pill-on-card);
  border-color: var(--pill-on-card-border);
  font-size: 0.82rem;
  padding: 2px 11px;
}

/* ============================================================
   CONTACT
   ============================================================ */
.contact-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* La zone de statut de la copie réserve sa hauteur en permanence, sous les
     boutons : additionnée à cet écart, elle creusait un trou entre les
     boutons et les informations, deux fois plus grand qu'entre les autres
     blocs de la carte. */
  gap: 22px;
  max-width: 620px;
  margin-inline: auto;
  padding: 46px 40px;
  background: var(--paper);
  border-radius: var(--radius);
  box-shadow: 12px 14px 0 var(--sage-700);
  border: 1px solid var(--sage-200);
  text-align: center;
}
.contact-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.contact-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 16px;
}
.contact-mail { font-size: 1.05rem; letter-spacing: 0.04em; text-transform: none; }
/* Le bouton confirme la copie sans bouger d'un pixel : bordure teintée
   seulement, pour ne pas décaler ce qui suit. */
.contact-mail.is-copied { border-color: var(--sage-700); }
/* Hauteur réservée en permanence : le message apparaît et disparaît sans
   faire sauter la carte. */
.copy-status {
  margin: 0;
  /* Interligne resserré et aligné sur la hauteur réservée : avec l'interligne
     de 1,7 du corps de texte, la ligne du message était plus haute que la
     réservation, et la carte sautait quand même de quelques pixels. */
  min-height: 1.4em;
  line-height: 1.4;
  font-size: 0.9rem;
  color: var(--sage-900);
}
.contact-facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px 48px;
  margin: 0;
}
.contact-facts dt {
  font-family: var(--font-display);
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sage-900);
}
.contact-facts dd { margin: 2px 0 0; }
.contact-socials {
  display: flex;
  gap: 30px;
  font-family: var(--font-display);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 0.95rem;
}
.contact-socials a { border-bottom: 1px solid transparent; transition: border-color var(--transition); }
.contact-socials a:hover { border-color: var(--sage-700); }

/* ============================================================
   FOOTER
   ============================================================ */
.site-footer {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--line);
  background: var(--paper-warm);
  padding: 26px 0;
}
.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

/* ============================================================
   PAGE PROJET (détail)
   ============================================================ */
.project-hero-media {
  display: grid;
  place-items: center;
  min-height: 240px;
  margin-bottom: 48px;
  padding: 40px;
  background: var(--sage-200);
  border-radius: var(--radius);
  box-shadow: 12px 14px 0 var(--sage-700);
}
.project-hero-media img { max-height: 200px; width: auto; }
.project-hero-media .project-monogram { font-size: 5rem; }

/* Rôle, année et compétences ouvrent la page en bandeau. En colonne latérale,
   ils rognaient toute la hauteur du texte pour trois lignes d'information. */
.project-meta {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 18px 52px;
  align-items: start;
  margin: 6px 0 42px;
  padding: 22px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.meta-label {
  display: block;
  font-family: var(--font-display);
  font-size: 0.82rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sage-900);
  margin-bottom: 8px;
}
.project-meta-item { min-width: 0; }
.project-meta-item .skill-list { margin: 0; }
.project-detail-main h2 {
  font-size: 1.5rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0 0 16px;
}
.project-detail-main h2:not(:first-child) { margin-top: 40px; }
.project-detail-main p { margin: 0 0 16px; font-size: 1.08rem; }
.feature-list { display: grid; gap: 12px; }
.feature-list li { display: flex; align-items: center; gap: 14px; }
.hl-icon {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--sage-200);
  color: var(--sage-900);
  font-size: 0.8rem;
}
/* Récit long : sous-titres discrets, pour que le texte reste lisible sur la
   longueur sans concurrencer les h2 de la page.
   Police du texte courant et non celle des titres : ces libellés viennent des
   données d'un projet, ils se lisent comme des phrases, et l'Anaktoria des
   titres les rendait décoratifs au point de gêner la lecture au kilomètre. */
.story-title {
  font-family: var(--font-body);
  font-size: 1.2rem;
  line-height: 1.3;
  color: var(--sage-900);
  margin: 36px 0 12px;
}
.project-story > .story-title:first-child { margin-top: 0; }
/* Sous-partie d'une section : un cran sous `.story-title`, assez marqué pour
   servir de repère dans un long récit sans se faire passer pour une section.
   Deux réglages font la hiérarchie, la taille seule ne suffisant pas :
   la graisse 400 comme les h1/h2/h3 (un h4 est gras par défaut dans le
   navigateur, ce qui le rendait plus lourd que le titre qu'il complète), et
   le gris doux au lieu du vert d'accent, réservé aux titres de section.
   L'alinéa achève de les rattacher à leur section : décalés, ils se lisent
   comme un cran de plus dans le plan, et le bord gauche du texte courant
   reste le seul repère de lecture. */
.story-subtitle {
  font-family: var(--font-body);
  font-size: 1.12rem;
  line-height: 1.35;
  font-weight: 400;
  color: var(--ink-soft);
  margin: 28px 0 8px 30px;
}
.story-title + .story-subtitle { margin-top: 16px; }
.project-story p { margin: 0 0 14px; }

/* Posés sous la première capture, donc au milieu du texte : centrés, ils se
   lisent comme une invitation à aller voir plutôt que comme un pied de page. */
.project-detail-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin: 28px 0 40px;
}


/* ============================================================
   LANGUES (page « Mes études »)
   ============================================================ */
.language-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 18px;
}
.language-list li {
  padding: 22px 26px;
  background: var(--sage-100);
  border-radius: var(--radius-sm);
}
.language-name {
  display: block;
  /* Police du texte courant, comme les titres du parcours juste au-dessus :
     Anaktoria reste aux titres de section et aux libellés, pas au contenu. */
  font-family: var(--font-body);
  font-size: 1.26rem;
  line-height: 1.2;
}
.language-level {
  display: block;
  margin-top: 6px;
  color: var(--ink-soft);
  font-size: 0.95rem;
}

/* ============================================================
   CAPTURES D'UN PROJET (page projet)
   ============================================================ */
/* Les captures vivent dans le fil du texte, à l'endroit qu'elles illustrent.
   L'espace au-dessus est plus grand qu'en dessous : la figure appartient
   visuellement au paragraphe qui la précède, pas à celui qui la suit. */
.shot {
  margin: 34px 0 30px;
  display: flex;
  flex-direction: column;
  /* Légende collée à l'image : elle doit se lire comme sa suite immédiate,
     pas comme un paragraphe séparé. */
  align-items: center;
  gap: 6px;
}
.shot img {
  display: block;
  /* Pas de hauteur imposée : captures d'écran et schémas vont du 3:1 au 6:5.
     Une boîte au format fixe les faisait flotter dans du vide, et la légende
     se retrouvait loin de l'image. Chacune prend donc sa hauteur naturelle.
     `max-width` plutôt que `width` : une image plus étroite que la colonne
     reste à sa taille d'origine au lieu d'être agrandie et floue. */
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

/* La légende se lit sous l'image, en permanence : rien à survoler, et les
   lecteurs d'écran la rencontrent dans l'ordre naturel du document. */
.shot-caption {
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.96rem;
  line-height: 1.45;
  text-align: center;
  /* Sur une légende longue, une ligne pleine largeur se détacherait de
     l'image ; on la resserre et on la recentre sous elle. */
  max-width: 46em;
  margin-inline: auto;
}

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

/* ============================================================
   ANIMATIONS
   ============================================================ */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 900px) {
  /* Le bandeau d'en-tête s'empile : les pastilles de compétences ont besoin
     de toute la largeur dès que la ligne devient étroite. */
  .project-meta { grid-template-columns: 1fr; gap: 22px; }
}

@media (max-width: 760px) {
  .nav-toggle { display: flex; }
  .nav-links {
    position: absolute;
    top: var(--header-h);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 14px 32px 24px;
    background: var(--paper-warm);
    border-bottom: 1px solid var(--line);
    transform: translateY(-10px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition), transform var(--transition);
  }
  .nav-links.open { opacity: 1; transform: none; pointer-events: auto; }
  .nav-links li { padding: 8px 0; }
  /* Le choix de langue n'est pas une destination : un filet le sépare des
     liens de navigation dans le menu déroulé. */
  .nav-lang {
    margin-top: 4px;
    padding-top: 14px !important;
    border-top: 1px solid var(--line);
  }

  .hero { padding: 70px 0 84px; }
  .container { padding-inline: 22px; }
  .hero-wordmark { width: 88%; }
  .hero-tagline { gap: 14px; letter-spacing: 0.1em; }
  .arrow { width: 32px; }
  .section { padding: 54px 0; }
  .intro-text { text-align: left; }
  .footer-inner { flex-direction: column; text-align: center; }
}

/* ============================================================
   Repli sans JavaScript

   Les projets, le parcours et les coordonnées sont injectés par app.js :
   sans JavaScript, ces pages seraient vides. Ce bloc n'apparaît que dans
   ce cas — il ne coûte rien aux autres visiteurs.
   ============================================================ */
.noscript-note {
  max-width: 620px;
  margin: 0 auto;
  padding: 22px 26px;
  border: 1px solid var(--sage-400);
  border-radius: var(--radius-sm);
  background: var(--sage-100);
  color: var(--ink);
  text-align: center;
}

.noscript-note a { color: inherit; }

.noscript-note [lang="en"] {
  display: block;
  margin-top: 10px;
  color: var(--ink-soft);
  font-size: 0.94em;
}
