/* ============================================================================
   bynoah × joinly : la feuille de styles de la page portfolio

   Les jetons viennent du thème « rythme » de joinly
   (`src/lib/alternance/types.ts`, THEMES_PORTFOLIO.rythme) et de ses jetons
   globaux (`src/app/globals.css`). Ils sont recopiés ici tels quels : c'est
   une page partenaire, pas une variation.
   ============================================================================ */

:root{
  --accent:#4f46e5;
  --violet:#8b5cf6;
  --ink:#16161d;
  --doux:#6a6a78;
  --fond:#F8F8FD;
  --carte:#ffffff;
  --trait:#eaeaf4;
  --banniere:linear-gradient(145deg,#E9E9FE 0%,#EFEAFE 55%,#F5F1FF 100%);
  --gradient:linear-gradient(110deg, var(--accent), var(--violet));
  --accent-tint:color-mix(in srgb, var(--accent) 12%, transparent);
  --accent-glow:color-mix(in srgb, var(--accent) 19%, transparent);
  --violet-glow:color-mix(in srgb, var(--violet) 19%, transparent);

  --ease:cubic-bezier(.22,1,.36,1);
  --lim:1080px;
}

*{ box-sizing:border-box; margin:0; padding:0; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
body{
  background:var(--fond); color:var(--ink);
  font:400 16px/1.68 Manrope, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{ font-family:Sora, Manrope, sans-serif; letter-spacing:-.032em; line-height:1.15; text-wrap:balance; }
a{ color:inherit; text-decoration:none; }
img,svg{ display:block; max-width:100%; }
button{ font-family:inherit; }
:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:8px; }

/* ============================================================================
   LA ZONE SÛRE DE L'IPHONE

   Les deux pages déclarent `viewport-fit=cover` : elles se dessinent SOUS la
   Dynamic Island et sous la barre de gestes, jusqu'aux bords physiques de
   l'écran. C'est ce qui donne un bandeau en pleine largeur, mais il faut
   alors écarter le contenu soi-même, sinon la pilule noire mange le haut de
   la page. C'est ce que fait joinly, avec un `env(safe-area-inset-top)` sur
   son conteneur ; il manquait ici.

   `env()` vaut zéro partout ailleurs : ces règles ne changent rien sur un
   ordinateur ni sur un téléphone sans encoche.
   ============================================================================ */
.lim{
  max-width:var(--lim); margin:0 auto;
  /* En paysage, l'encoche passe sur le côté : la marge s'élargit d'autant. */
  padding-left:max(clamp(20px,4.5vw,34px), env(safe-area-inset-left, 0px));
  padding-right:max(clamp(20px,4.5vw,34px), env(safe-area-inset-right, 0px));
}

.saut{
  position:absolute; left:-9999px; top:10px; z-index:100;
  background:var(--ink); color:#fff; padding:10px 16px; border-radius:10px;
  font-weight:700; font-size:14px;
}
.saut:focus{ left:14px; }

/* --------------------------------------------------------- les mouvements */
@keyframes monte{ from{ opacity:0; transform:translateY(16px); } to{ opacity:1; transform:none; } }
@keyframes derive{
  0%,100%{ transform:translate(0,0) scale(1); }
  33%{ transform:translate(30px,-24px) scale(1.07); }
  66%{ transform:translate(-24px,18px) scale(.95); }
}
/* L'arrivée d'une rubrique quand on change d'onglet. Sans elle, la
   substitution est sèche : on ne sait pas si la page a changé ou clignoté. */
@keyframes entree{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }
.rubrique[data-entre], .fiche-projet[data-entre], #frise-vue[data-entre]{ animation:entree .34s var(--ease) both; }

@media (prefers-reduced-motion: reduce){
  *{ animation:none !important; transition:none !important; }
  html{ scroll-behavior:auto; }
  /* Le voile d'ouverture disparaît au lieu de se figer : sans animation, il
     resterait devant la page pour toujours. */
  .lancement{ display:none !important; }
  .apparait.en-attente{ opacity:1 !important; transform:none !important; }
}

/* ============================================================================
   L'OUVERTURE : bynoah × joinly

   Les deux marques arrivent chacune de son côté, la croix les rejoint, puis
   le voile se lève. Tout est en CSS, sans une ligne de JavaScript : un voile
   qui dépend d'un script peut rester coincé devant la page si le script
   échoue, et c'est le pire défaut qu'une page d'accueil puisse avoir.
   ============================================================================ */
@keyframes voile-part{
  0%, 62%   { opacity:1; visibility:visible; }
  92%, 100% { opacity:0; visibility:hidden; }
}
@keyframes venu-gauche{ from{ opacity:0; transform:translateX(-26px); } to{ opacity:1; transform:none; } }
@keyframes venu-droite{ from{ opacity:0; transform:translateX(26px); } to{ opacity:1; transform:none; } }
@keyframes croix-nait{
  0%  { opacity:0; transform:scale(.3) rotate(-90deg); }
  70% { opacity:1; transform:scale(1.25) rotate(0deg); }
  100%{ opacity:1; transform:scale(1) rotate(0deg); }
}
/* Le rapprochement : une fois les deux mots posés, l'ensemble se resserre
   d'un cheveu. C'est ce petit geste qui fait « collaboration » plutôt que
   « deux logos alignés ». */
@keyframes resserre{ from{ letter-spacing:.06em; } to{ letter-spacing:-.04em; } }

.lancement{
  position:fixed; inset:0; z-index:200;
  /* `max-width` en plus de `inset` : si un autre bloc rend la page plus large
     que la fenêtre, un élément fixe peut hériter de cette largeur-là. */
  max-width:100%; overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  background:var(--banniere);
  animation:voile-part 2.15s var(--ease) forwards;
}
.lancement-in{ display:flex; align-items:center; gap:clamp(10px,2vw,16px); }
.l-mot{ font-size:clamp(26px,6vw,46px); line-height:1; letter-spacing:-.04em; color:var(--ink); }
.l-noah{ font-family:Sora, sans-serif; font-weight:800; animation:venu-gauche .58s var(--ease) both, resserre .6s var(--ease) .7s both; }
.l-noah i{ font-style:normal; color:var(--accent); font-family:ui-monospace,Menlo,monospace; margin-right:3px; }
.l-joinly{ font-family:Poppins, Sora, sans-serif; font-weight:800; animation:venu-droite .58s var(--ease) .18s both, resserre .6s var(--ease) .7s both; }
.l-croix{
  font-size:clamp(15px,2.4vw,22px); font-weight:600; color:var(--doux);
  animation:croix-nait .5s var(--ease) .34s both;
}

/* ============================================================================
   LE BANDEAU
   ============================================================================ */
.bandeau{ position:relative; overflow:hidden; background:var(--banniere); }
.lueur{
  position:absolute; z-index:0; pointer-events:none; border-radius:50%;
  animation:derive 15s ease-in-out infinite;
}
.lueur-a{
  left:4%; top:-220px; width:min(600px,95vw); height:min(600px,95vw);
  background:radial-gradient(circle, var(--accent-glow) 0%, transparent 70%);
}
.lueur-b{
  right:-160px; top:60px; width:min(540px,90vw); height:min(540px,90vw);
  background:radial-gradient(circle, var(--violet-glow) 0%, transparent 70%);
  animation-direction:reverse;
}
/* La tache lumineuse de joinly : de la profondeur, sans un mot de plus. */
.halo{
  position:absolute; z-index:0; pointer-events:none; border-radius:50%;
  right:-140px; top:-180px; width:440px; height:440px;
  background:radial-gradient(circle, rgba(255,255,255,.92), transparent 70%);
}
/* LE BANDEAU EST CENTRÉ, comme une page de profil joinly. Aligné à gauche,
   les logos de gauche n'avaient nulle part où aller : ils tombaient sous le
   bord de la page et `overflow:hidden` les coupait. Centrer donne la même
   place des deux côtés, et c'est aussi la composition du modèle. */
.bandeau-in{
  position:relative; z-index:2; text-align:center;
  /* Le dégradé, lui, continue jusqu'en haut de l'écran : c'est le contenu
     qu'on descend, pas le fond. */
  padding-top:calc(clamp(24px,3.6vw,36px) + env(safe-area-inset-top, 0px));
  /* LE MENU FAIT LA CÉSURE. Noah, le 4 septembre 2026 : « en dessous ma
     photo de profil c'est une couleur un peu plus foncée, en dessous mes
     projets c'est clair : j'aimerais que le menu fasse vraiment la coupure
     entre les deux ».

     Il restait quarante-six pixels de bandeau sous les langues : la teinte
     foncée s'arrêtait donc bien avant lui, et il flottait sur le clair au lieu
     de marquer le passage. Le bandeau se termine maintenant juste au-dessus,
     et c'est le menu lui-même qui ouvre la zone claire. L'écart qui reste est
     dans le menu, pas dans le bandeau : « sans que ça fasse trop collé non
     plus ». */
  /* ⚠️ LE MINIMUM EST POUR LE TÉLÉPHONE, et c'est là qu'il faut le plus
     d'air, pas le moins. Un `clamp` sert sa borne basse sur écran étroit :
     les langues n'avaient plus que quatorze pixels avant le changement de
     teinte, et la dernière pastille venait toucher la césure. Sur téléphone
     elles se rangent en outre sur deux lignes, donc la dernière tombe seule et
     se voit d'autant plus près du bord. */
  padding-bottom:clamp(26px,3.4vw,32px);
}
.bandeau-in .lockup{ justify-content:center; }
.bandeau-in .langues{ justify-content:center; }

/* --- le co-branding --- */
.lockup{ display:flex; align-items:center; gap:11px; margin-bottom:clamp(28px,4.5vw,46px); }
.mot{ font-size:20px; letter-spacing:-.04em; line-height:1; }
/* bynoah garde son chevron et sa graisse ; joinly garde Poppins 800, la
   police de son mot-symbole. Deux marques ne se composent pas pareil. */
.mot-noah{ font-family:Sora, sans-serif; font-weight:800; color:var(--ink); }
.mot-noah i{ font-style:normal; color:var(--accent); font-family:ui-monospace,Menlo,monospace; margin-right:2px; }
.mot-joinly{ font-family:Poppins, Sora, sans-serif; font-weight:800; color:var(--ink); }
.croix{ font-size:15px; font-weight:500; color:var(--doux); opacity:.65; }

/* LE MOT-SYMBOLE DE CLIENTBASE. Les trois marques de cette page se composent
   chacune à sa façon : bynoah a son chevron, joinly a son Poppins, ClientBase
   a son point violet. Sans ça, son nom se lisait comme les huit autres titres
   de projet, alors que c'est une marque. */
.mot-cb{ font-family:Sora, sans-serif; font-weight:800; letter-spacing:-.035em; color:#000; }
.mot-cb i{ font-style:normal; color:var(--accent); }

/* Les mots-symboles sont des boutons : ils ouvrent leur fiche de marque. Ils
   n'en prennent pas l'allure pour autant, c'est un mot, pas un bouton. */
button.mot, button.mot-cb{
  appearance:none; background:none; border:0; padding:0; cursor:pointer;
  font-family:inherit; text-align:left;
}
button.mot-cb{ font-family:Sora, sans-serif; font-size:17px; }
button.mot:hover, button.mot-cb:hover{ opacity:.72; }
button.mot:active, button.mot-cb:active{ opacity:.55; }

/* Le « Lire le détail » de la carte ClientBase est un vrai bouton : sa carte
   n'en est plus un, puisque le mot-symbole en occupe déjà le titre. */
.ouvrir-bouton{ appearance:none; background:none; border:0; padding:0; cursor:pointer; font-family:inherit; }
.jalon .corps.corps-marque{ cursor:default; }
.jalon .corps.corps-marque:hover{ transform:none; }
.jalon .corps.corps-marque:hover .ouvrir i{ transform:translateX(3px); }

/* ============================================================================
   LES PAGES DE MARQUE

   Ce ne sont plus des fenêtres posées sur le site : ce sont des pages, au même
   titre que les quatre rubriques. Noah : « je veux vraiment une page dédiée,
   pas juste une pop-up, et surtout avec des animations d'entrée et de sortie ».

   Le bandeau reste, le menu reste, seul le contenu se remplace. La page entre
   par le haut et sort par le bas, et son motif se joue à chaque entrée.

   Chacune a son motif, tiré de ce que la marque EST :
     bynoah      une invite de commande, curseur qui clignote
     joinly      une page de profil, dont les lettres se rejoignent
     ClientBase  une semaine d'agenda, et le point du `.fr` qui se pose
   ============================================================================ */
/* Elle finit comme une rubrique finit : avec de l'air avant le pied de page.
   Sans cette marge, le dernier bouton touchait le pied, et la page semblait
   coupee net. */
.page-marque{ position:relative; margin-bottom:clamp(44px,6vw,72px); }
.page-marque[hidden]{ display:none; }
/* Elle recoit le clavier a l ouverture, pour qu Echap et la tabulation partent
   d ici. Elle ne doit pas pour autant s entourer d un cerne : on ne l a pas
   atteinte au clavier, on a clique sur un mot-symbole. Le cerne reste pour qui
   navigue vraiment au clavier, via :focus-visible. */
.page-marque:focus{ outline:none; }

/* ─── le bandeau de titre ─────────────────────────────────────────────── */
/* LE BANDEAU DE TITRE porte deux choses : un OBJET qui montre ce que la
   marque fabrique, et le mot-symbole. Cote a cote sur grand ecran, l'un sous
   l'autre sur telephone. Noah, le 2 septembre 2026 : « fais des pages
   beaucoup plus visuelles ». Une phrase decrit ; un objet montre. */
.pm-hero{
  position:relative; overflow:hidden;
  border-radius:24px; padding:clamp(28px,4.4vw,46px) clamp(20px,4vw,36px);
  margin-bottom:clamp(22px,3.4vw,32px);
  display:grid; gap:clamp(24px,3.4vw,40px); align-items:center;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
}
.pm-titre{ position:relative; text-align:left; }
.pm-visuel{ position:relative; justify-self:center; width:100%; max-width:320px; }
@media (max-width:760px){
  .pm-hero{ grid-template-columns:1fr; text-align:center; }
  .pm-titre{ text-align:center; }
  .pm-visuel{ order:-1; max-width:270px; }
}
.pm-mot{ position:relative; font-size:clamp(32px,6vw,52px); line-height:1; }
.pm-mot > span{ display:inline-block; }
.pm-dit{
  position:relative; margin-top:18px;
  font-family:Sora,sans-serif; font-weight:700;
  font-size:clamp(17px,2.8vw,22px); letter-spacing:-.02em; color:var(--ink);
}
.pm-corps{ max-width:66ch; margin-inline:auto; text-align:center; }
.pm-tx{ font-size:clamp(15px,1.8vw,17px); line-height:1.7; color:var(--doux); }
.pm-actions{ margin-top:26px; display:flex; flex-wrap:wrap; gap:10px; justify-content:center; }
.pm-ok{
  appearance:none; border:0; cursor:pointer; font-family:inherit;
  background:var(--gradient); color:#fff; border-radius:999px;
  padding:13px 26px; font-weight:800; font-size:14.5px;
  box-shadow:0 14px 30px -16px color-mix(in srgb, var(--accent) 80%, transparent);
}
.pm-lien{
  border-radius:999px; padding:13px 24px; font-weight:800; font-size:14.5px;
  color:var(--accent); background:var(--accent-tint);
}
.pm-ok:hover, .pm-lien:hover{ filter:brightness(1.04); }

/* ════ LES TROIS OBJETS ════════════════════════════════════════════════
   Chacun est dessine en CSS, sans une seule image : ils pesent zero octet,
   ils sont nets a toutes les definitions, et ils suivent la palette du site
   si elle change. */

/* bynoah : une fenetre de navigateur, qui montre ce site */
.pm-fenetre{
  border-radius:14px; overflow:hidden; background:var(--carte);
  box-shadow:0 0 0 1px var(--trait), 0 30px 60px -34px rgba(20,20,60,.5);
}
.pmf-barre{
  display:flex; align-items:center; gap:5px; padding:9px 12px;
  background:#F1F1F8; box-shadow:inset 0 -1px 0 var(--trait);
}
.pmf-barre i{ width:7px; height:7px; border-radius:50%; background:#D6D6E4; }
.pmf-barre b{
  margin-left:8px; font:700 9.5px/1 ui-monospace, Menlo, monospace;
  color:var(--doux); letter-spacing:.02em;
}
.pmf-ecran{ padding-bottom:14px; }
.pmf-bandeau{
  background:var(--banniere); padding:18px 14px 16px; text-align:center;
}
.pmf-rond{
  display:block; width:34px; height:34px; margin:0 auto 9px; border-radius:50%;
  background:var(--gradient); box-shadow:0 0 0 3px rgba(255,255,255,.9);
}
.pmf-nom{ display:block; width:74px; height:9px; margin:0 auto 6px; border-radius:5px; background:var(--ink); opacity:.82; }
.pmf-sous{ display:block; width:52px; height:5px; margin:0 auto; border-radius:5px; background:var(--accent); opacity:.5; }
.pmf-onglets{ display:flex; gap:4px; padding:10px 14px; }
.pmf-onglets i{ flex:1; height:13px; border-radius:999px; background:#ECECF7; }
.pmf-onglets i.actif{ background:var(--gradient); }
.pmf-lignes{ display:grid; gap:6px; padding:2px 14px 0; }
.pmf-lignes i{ height:6px; border-radius:4px; background:#E9E9F2; }
.pmf-lignes i:nth-child(2){ width:82%; }
.pmf-lignes i:nth-child(3){ width:56%; }

/* joinly : un telephone, avec la page qu'il fabrique */
.pm-tel{
  max-width:196px; border-radius:26px; padding:7px; background:linear-gradient(160deg,#3a3c47,#1a1b22 45%,#2f313b);
  box-shadow:0 0 0 1px rgba(20,20,40,.12), 0 34px 66px -32px rgba(20,20,60,.6);
}
.pmt-ecran{
  position:relative; border-radius:20px; overflow:hidden; background:var(--carte);
  padding-bottom:14px;
}
.pmt-encoche{
  position:absolute; left:50%; top:6px; translate:-50% 0; z-index:2;
  width:40px; height:9px; border-radius:999px; background:#15161c;
}
.pmt-banniere{ display:block; height:66px; background:var(--banniere); }
.pmt-photo{
  display:block; width:44px; height:44px; margin:-24px auto 9px; border-radius:50%;
  background:var(--gradient); box-shadow:0 0 0 4px var(--carte);
  position:relative; z-index:1;
}
.pmt-nom{ display:block; width:78px; height:9px; margin:0 auto 6px; border-radius:5px; background:var(--ink); opacity:.82; }
.pmt-sous{ display:block; width:54px; height:5px; margin:0 auto 12px; border-radius:5px; background:var(--accent); opacity:.5; }
.pmt-liens{ display:grid; gap:6px; padding:0 12px; }
.pmt-liens i{ height:20px; border-radius:8px; background:var(--fond); box-shadow:inset 0 0 0 1px var(--trait); }

/* ClientBase : une journee d'agenda */
.pm-agenda{
  border-radius:16px; padding:16px 14px; background:var(--carte);
  box-shadow:0 0 0 1px var(--trait), 0 26px 54px -32px rgba(20,20,60,.45);
}
.pma-jour{ margin-top:14px; display:grid; gap:7px; }
.pma-rdv{
  display:flex; align-items:center; gap:10px;
  background:var(--fond); border-radius:11px; padding:10px 12px;
  box-shadow:inset 0 0 0 1px var(--trait);
}
.pma-rdv b{ font:800 11px/1 Sora, sans-serif; color:var(--doux); font-variant-numeric:tabular-nums; }
.pma-rdv span{ flex:1; height:6px; border-radius:4px; background:#E4E4EF; }
.pma-rdv.pris{ background:var(--accent-tint); box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--accent) 28%, transparent); }
.pma-rdv.pris b{ color:var(--accent); }
.pma-rdv.pris span{ background:color-mix(in srgb, var(--accent) 40%, transparent); }

/* bynoah : le terminal, sous le mot */
.pm-bynoah .pm-hero{ background:linear-gradient(168deg, #F4F4FE 0%, #FBFBFF 70%); box-shadow:0 0 0 1px var(--trait); }
.pm-invite{
  font-family:ui-monospace, Menlo, monospace; font-size:12.5px; letter-spacing:.02em;
  color:var(--doux); opacity:.75; margin-bottom:18px;
  white-space:nowrap; overflow:hidden; display:inline-block;
}
.pm-curseur{
  display:inline-block; width:.46ch; height:.86em; margin-left:.18em;
  background:var(--accent); vertical-align:-.04em;
}
.pm-lignes{ list-style:none; margin-top:26px; display:grid; gap:11px; text-align:left; }
.pm-lignes li{
  font-size:14.5px; line-height:1.55; color:var(--doux);
  padding-left:15px; box-shadow:inset 2px 0 0 color-mix(in srgb, var(--accent) 40%, transparent);
}
.pm-lignes b{ font-family:Sora,sans-serif; font-weight:800; color:var(--accent); margin-right:7px; }

/* ─── joinly : la page de profil ──────────────────────────────────────── */
.pm-joinly .pm-hero{ background:var(--banniere); }
.pm-halo{
  position:absolute; left:66%; top:-180px; width:460px; height:460px;
  translate:-50% 0; border-radius:50%; pointer-events:none;
  background:radial-gradient(circle, color-mix(in srgb, var(--violet) 24%, transparent) 0%, transparent 68%);
}
/* Le mot-symbole de joinly est une typographie, rien d'autre : le rond qui
   l'accompagnait ajoutait un signe que la marque n'a pas. Noah : « le logo de
   joinly, c'est vraiment juste la typo, il n'y a pas besoin de plus. » */
.pm-pastilles{ list-style:none; margin-top:24px; display:flex; flex-wrap:wrap; gap:8px; justify-content:center; }
.pm-pastilles li{
  background:var(--carte); border-radius:999px; padding:10px 16px;
  font-size:13.5px; font-weight:700; color:var(--ink); box-shadow:0 0 0 1px var(--trait);
}

/* ─── ClientBase : l'agenda ───────────────────────────────────────────── */
.pm-cb .pm-hero{ background:linear-gradient(150deg, #F1F0FE 0%, #FAF9FF 72%); box-shadow:0 0 0 1px var(--trait); }
.pm-semaine{ position:relative; list-style:none; display:flex; gap:5px; justify-content:space-between; }
.pm-semaine li{
  flex:1; height:28px; border-radius:9px;
  display:flex; align-items:center; justify-content:center;
  font-size:12px; font-weight:800; color:var(--doux);
  background:var(--carte); box-shadow:0 0 0 1px var(--trait);
}
.pm-semaine li.pris{
  color:#fff; background:var(--gradient);
  box-shadow:0 10px 20px -9px color-mix(in srgb, var(--accent) 80%, transparent);
}
.pm-faits{ list-style:none; margin-top:24px; display:grid; grid-template-columns:repeat(3,1fr); gap:10px; }
.pm-faits li{ background:var(--carte); border-radius:15px; padding:16px 10px; box-shadow:0 0 0 1px var(--trait); }
.pm-faits b{ display:block; font-family:Sora,sans-serif; font-weight:800; font-size:19px; color:var(--accent); }
.pm-faits span{ display:block; margin-top:4px; font-size:12px; line-height:1.35; color:var(--doux); }
@media (max-width:460px){ .pm-faits{ grid-template-columns:1fr; } }

/* ─── l'entrée : la page monte, son motif se joue ─────────────────────── */
.page-marque[data-entre] .pm-hero{ animation:pm-monte .5s var(--ease) both; }
.page-marque[data-entre] .pm-corps{ animation:pm-monte .5s var(--ease) .1s both; }
.page-marque[data-entre] .retour{ animation:pm-monte .4s var(--ease) both; }

.pm-bynoah[data-entre] .pm-visuel{ animation:pm-pose .56s var(--ease) .1s both; }
.pm-bynoah[data-entre] .pm-invite{ animation:pm-tape .44s steps(11) .16s both; }
.pm-bynoah[data-entre] .pm-curseur{ animation:pm-cligne 1.05s steps(1) .8s infinite; }
.pm-bynoah[data-entre] .pm-mot > span{ animation:pm-glisse .52s var(--ease) .2s both; }

.pm-joinly[data-entre] .pm-visuel{ animation:pm-pose .56s var(--ease) .1s both; }
.pm-joinly[data-entre] .pm-mot > span{ animation:pm-resserre .6s var(--ease) .26s both; }
.pm-joinly[data-entre] .pm-pastilles li{ animation:pm-pose .42s var(--ease) both; }
.pm-joinly[data-entre] .pm-pastilles li:nth-child(1){ animation-delay:.42s; }
.pm-joinly[data-entre] .pm-pastilles li:nth-child(2){ animation-delay:.5s; }
.pm-joinly[data-entre] .pm-pastilles li:nth-child(3){ animation-delay:.58s; }

.pm-cb[data-entre] .pm-visuel{ animation:pm-pose .56s var(--ease) .1s both; }
.pm-cb[data-entre] .pm-semaine li{ animation:pm-pose .34s var(--ease) both; }
.pm-cb[data-entre] .pma-rdv{ animation:pm-pose .38s var(--ease) both; }
.pm-cb[data-entre] .pma-rdv:nth-child(1){ animation-delay:.44s; }
.pm-cb[data-entre] .pma-rdv:nth-child(2){ animation-delay:.52s; }
.pm-cb[data-entre] .pma-rdv:nth-child(3){ animation-delay:.6s; }
.pm-cb[data-entre] .pm-semaine li:nth-child(1){ animation-delay:.14s; }
.pm-cb[data-entre] .pm-semaine li:nth-child(2){ animation-delay:.18s; }
.pm-cb[data-entre] .pm-semaine li:nth-child(3){ animation-delay:.22s; }
.pm-cb[data-entre] .pm-semaine li:nth-child(4){ animation-delay:.26s; }
.pm-cb[data-entre] .pm-semaine li:nth-child(5){ animation-delay:.3s; }
.pm-cb[data-entre] .pm-semaine li:nth-child(6){ animation-delay:.34s; }
.pm-cb[data-entre] .pm-semaine li:nth-child(7){ animation-delay:.38s; }
.pm-cb[data-entre] .pm-mot > span{ animation:pm-monte-mot .5s var(--ease) .34s both; }
.pm-cb[data-entre] .mot-cb i{ display:inline-block; animation:pm-tombe .42s cubic-bezier(.3,1.5,.5,1) .8s both; }

/* ─── la sortie : la page redescend et s'efface ───────────────────────── */
.page-marque.part{ animation:pm-part .3s var(--ease) both; pointer-events:none; }

@keyframes pm-monte{ from{ opacity:0; translate:0 18px; } to{ opacity:1; translate:0 0; } }
@keyframes pm-part{ from{ opacity:1; translate:0 0; } to{ opacity:0; translate:0 14px; } }
@keyframes pm-tape{ from{ width:0; } to{ width:8.6em; } }
@keyframes pm-cligne{ 0%,49%{ opacity:1; } 50%,100%{ opacity:0; } }
@keyframes pm-glisse{ from{ opacity:0; translate:-20px 0; } to{ opacity:1; translate:0 0; } }
@keyframes pm-pose{ from{ opacity:0; translate:0 10px; scale:.9; } to{ opacity:1; translate:0 0; scale:1; } }
@keyframes pm-monte-mot{ from{ opacity:0; translate:0 14px; } to{ opacity:1; translate:0 0; } }
@keyframes pm-tombe{ from{ opacity:0; translate:0 -16px; } to{ opacity:1; translate:0 0; } }
@keyframes pm-resserre{
  from{ opacity:0; letter-spacing:.3em; filter:blur(7px); }
  to  { opacity:1; letter-spacing:-.04em; filter:blur(0); }
}

/* Sans mouvement, chaque page se pose sans se jouer. */
@media (prefers-reduced-motion: reduce){
  .page-marque *, .page-marque{ animation:none !important; }
  .pm-invite{ width:auto; }
}

.lockup.petit .mot{ font-size:17px; }

/* ============================================================================
   L'IDENTITÉ : LA PHOTO, ET LES LOGOS QUI VOLENT AUTOUR

   Tout vient de la page de profil de joinly (`PageJoinly.tsx`), reprise à
   l'identique : les places de `COINS`, la taille de la photo, celle des
   logos :

       photo    108 px de côté        (`const cote = serre ? 78 : 108`)
       logos     38 px de côté        (`taille={serre ? 26 : 38}`)
       places   { -138, 18 } { 140, 34 } { -116, 96 } { 122, 104 }

   ⚠️ LES PLACES SONT EN PIXELS DEPUIS LE CENTRE, PAS EN POURCENTAGES. Le
   commentaire d'origine dit pourquoi : « un pourcentage dépend de la largeur
   du conteneur : les logos se rapprocheraient de la photo sur un téléphone
   étroit et lui rentreraient dedans. En pixels, l'écart reste le même
   partout. »

   ⚠️ ET LA PHOTO DOIT RESTER PETITE. C'était mon erreur : une photo de 144 px
   avec les écarts d'une photo de 108 ne laisse plus que quatre pixels entre
   le cercle et les logos. Ces trois nombres vont ensemble ; en changer un
   seul referme le semis. Tel quel, il reste 58 à 87 pixels de vide autour du
   cercle, exactement comme sur le modèle.

   ⚠️ TROIS TRANSFORMATIONS, TROIS PROPRIÉTÉS SÉPARÉES. `transform` place et
   incline, et ne bouge jamais ; `translate` porte le vol ; `scale` porte le
   survol. Tout réunir dans `transform` ferait que la dernière écrase les
   autres.
   ============================================================================ */
.champ{
  position:relative; display:flex; justify-content:center;
  margin-top:clamp(4px,2vw,10px);
  /* UN SEUL FACTEUR POUR TOUTE LA FIGURE. La photo, la taille des logos et
     leurs places sont les trois nombres du modèle ; ils ne valent que les uns
     par rapport aux autres. Les faire varier séparément : une photo plus
     grande, des places inchangées : referme le semis sur le visage. Ici, un
     seul `--k` les emporte tous, et les proportions de joinly tiennent de
     l'iPhone SE à l'écran de bureau. */
  --k:1;
}
.portrait{
  display:block; border-radius:50%; object-fit:cover;
  width:calc(108px * var(--k)); height:calc(108px * var(--k));
  box-shadow:0 0 0 5px rgba(255,255,255,.92), 0 22px 44px -22px rgba(20,20,60,.4);
  animation:monte .6s ease backwards;
}
/* Sur grand écran, toute la figure grandit d'un sixième : photo, logos et
   écarts ensemble. Sous 360 px, elle rétrécit d'un huitième pour ne pas
   toucher le bord. Dans les deux cas c'est le même dessin, à une autre
   échelle. */
@media (min-width:900px){ .champ{ --k:1.16; } }
@media (max-width:359px){ .champ{ --k:.88; } }

.pastille{
  position:absolute;
  left:calc(50% + var(--x)); top:var(--y);
  width:calc(38px * var(--k)); height:calc(38px * var(--k));
  border-radius:24%;                 /* le squircle de joinly : 0,24 du côté */
  background:var(--fond);
  display:flex; align-items:center; justify-content:center;
  transform:translate(-50%,-50%) rotate(var(--r));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.38),
    inset 0 0 0 1px rgba(10,10,30,.06),
    0 14px 26px -12px rgba(20,20,60,.55);
  animation:
    pose .7s cubic-bezier(.22,1,.36,1) calc(.3s + var(--n) * .1s) backwards,
    vole var(--d) ease-in-out calc(1.1s + var(--n) * .35s) infinite;
  transition:scale .18s var(--ease), box-shadow .18s var(--ease);
}
.pastille svg{ width:52%; height:52%; }
/* Deux d'entre eux sont des clins d'oeil sans adresse : ils ne doivent pas se
   comporter comme un lien. */
a.pastille:hover{
  scale:1.1;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.38),
    inset 0 0 0 1px rgba(10,10,30,.06),
    0 22px 36px -14px rgba(20,20,60,.6);
}
a.pastille:active{ scale:.94; }

/* LES DEUX DU BAS SONT REMONTES par rapport au modele de joinly (96 et 104).
   La-bas, sous la photo, il n'y a qu'un nom court ; ici « Noah Pascual » est
   compose en tres grand, et son bloc remonte plus haut. Resultat : deux logos
   s'arretaient a six pixels des lettres, et le quatrieme les chevauchait de
   six. Noah, le 2 septembre 2026 : « des fois ils s'approchent un peu trop de
   Noah Pascual ».

   Ils gardent leur ecartement horizontal, donc le semis garde sa forme ; c'est
   seulement leur descente qui est ecourtee. Le vol, lui, ne les rapproche
   jamais du nom : il ne va que vers le haut. */
.p1{ --x:calc(-138px * var(--k)); --y:calc(16px * var(--k)); --r:-12deg; --d:6.4s; --n:0; }
.p2{ --x:calc(-118px * var(--k)); --y:calc(74px * var(--k)); --r:8deg;   --d:7.2s; --n:1; }
.p3{ --x:calc(140px * var(--k));  --y:calc(30px * var(--k)); --r:10deg;  --d:8.0s; --n:2; }
.p4{ --x:calc(124px * var(--k));  --y:calc(80px * var(--k)); --r:-9deg;  --d:6.8s; --n:3; }

@keyframes pose{
  from{ opacity:0; filter:blur(10px); translate:0 10px; }
  to  { opacity:1; filter:blur(0);    translate:0 0; }
}
/* Le vol passe par `translate`, jamais par `transform` : celui-ci porte le
   centrage et l'inclinaison, et les deux doivent coexister. */
@keyframes vole{
  0%,100%{ translate:0 0; }
  50%    { translate:0 -8px; }
}

/* ============================================================================
   LE NOM, LA SITUATION, LES LANGUES
   ============================================================================ */
.metier{
  display:inline-flex; align-items:center; gap:8px; margin-top:clamp(16px,2.4vw,22px);
  background:rgba(255,255,255,.75); border-radius:999px; padding:7px 13px;
  font-size:10.5px; font-weight:800; letter-spacing:.08em; text-transform:uppercase; color:var(--accent);
}
.metier i{ width:6px; height:6px; border-radius:50%; background:var(--accent); flex:none; }

.nom{
  margin-top:12px; font-weight:800;
  font-size:clamp(38px,6.4vw,58px); letter-spacing:-.045em; line-height:1;
  animation:monte .6s ease backwards;
}
/* La ligne de situation, en indigo : c'est elle qui dit en trois mots à qui
   on a affaire, et c'est la seule ligne colorée du bandeau. */
.situation{
  margin-top:10px; font-size:clamp(15px,1.7vw,17.5px); font-weight:700; color:var(--accent);
  animation:monte .6s ease .08s backwards;
}

.langues{
  list-style:none; margin-top:clamp(18px,2.6vw,24px);
  display:flex; flex-wrap:wrap; gap:8px;
  animation:monte .6s ease .16s backwards;
}
.langues li{
  display:inline-flex; align-items:center; gap:8px;
  border-radius:999px; padding:8px 15px 8px 9px;
  background:rgba(255,255,255,.85); color:var(--ink);
  font-size:13.5px; font-weight:600;
  box-shadow:inset 0 0 0 1px rgba(20,20,60,.05);
}
/* Le niveau, en pastille dans la pastille : c'est ce qu'on cherche quand on
   lit une ligne de langue, alors il se détache. */
.langues b{
  font-size:11.5px; font-weight:800; letter-spacing:.02em;
  color:var(--accent); background:var(--accent-tint);
  border-radius:999px; padding:3px 8px;
}
.drapeau{ width:20px; height:20px; flex:none; border-radius:50%; overflow:hidden; }
.drapeau svg{ width:100%; height:100%; }
.drapeau.permis{
  border-radius:50%; background:var(--accent-tint); color:var(--accent);
  display:flex; align-items:center; justify-content:center;
}
.drapeau.permis svg{ width:64%; height:64%; }

/* ============================================================================
   LE MENU : un contrôle segmenté

   Quatre parts égales dans un même étui, et la part ouverte prend le dégradé.
   Les pastilles séparées de la version précédente laissaient croire à des
   filtres qu'on pouvait cumuler ; un étui unique dit qu'on choisit UNE
   rubrique. Et rien ne défile : les quatre se voient d'un coup, sur téléphone
   comme sur ordinateur.
   ============================================================================ */
.menu{
  /* ⚠️ L'ÉCART D'ENCOCHE EST DANS `top`, PAS DANS LE REMBOURRAGE.

     Il était en rembourrage, donc permanent : au repos, sur un téléphone à
     encoche, il ouvrait soixante-treize pixels de vide entre la césure et la
     pilule au lieu de quatorze. Or cette marge ne sert QUE lorsque le menu est
     collé sous la Dynamic Island, au repos, c'est le bandeau qui est là-haut,
     et il s'en occupe déjà.

     Dans `top`, elle ne coûte rien tant que le menu suit la page, et elle le
     pose sous la pilule noire dès qu'il se colle. Et comme `top` n'entre pas
     dans le calcul de la mise en page, rien ne saute au moment où il s'arrête. */
  position:sticky; top:env(safe-area-inset-top, 0px); z-index:20;
  background:color-mix(in srgb, var(--fond) 90%, transparent);
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
}
/* La bande qui coiffe l'encoche, quand le menu est collé. Le menu s'arrête
   sous la pilule noire : sans elle, la page défilerait à découvert dans les
   soixante pixels laissés au-dessus de lui. Elle ne se montre qu'à ce
   moment-là, posée en permanence, elle recouvrirait le bas du bandeau.

   ELLE EST OPAQUE, ET ELLE N'APPARAIT QU'UNE FOIS LE BANDEAU PASSE. Deux
   corrections successives, et il fallait les deux.

   D'abord elle a porte le fond clair du menu en permanence : a l'instant ou
   celui-ci se colle, la bande contient encore le bas du BANDEAU, et elle
   passait le lavande au neutre. Une barre claire apparaissait sur le bandeau.

   Puis elle n'a plus eu de couleur du tout, seulement un flou : le texte de la
   page continuait alors de defiler au-dessus du menu, bien visible. Noah, le
   2 septembre 2026 : « la page apparait encore au-dessus du menu, ca fait
   bizarre, mets juste un espace ou on ne voit pas ».

   La bonne reponse est dans le MOMENT, pas dans la matiere : `joinly.js` ne
   pose la classe qu'une fois le bandeau entierement defile. Passe ce point, ce
   qu'il y a derriere la bande est toujours le fond de page : l'opaque est
   juste, et plus rien ne traverse. */
.menu::before{
  content:""; position:absolute; left:0; right:0; bottom:100%;
  height:env(safe-area-inset-top, 0px);
  background:var(--fond);
  opacity:0; transition:opacity .14s linear; pointer-events:none;
}
.menu.colle::before{ opacity:1; }

/* Le rembourrage est ICI, dans la zone claire, et pas en bas du bandeau :
   c'est ce qui met de l'air autour du menu sans repousser la césure. */
/* Le menu se permet des marges plus serrees que le reste de la page : c'est
   ce qui rend au dernier mot la place qui lui manquait. */
.menu .lim{
  padding-block:clamp(14px,2.4vw,18px);
  padding-inline:clamp(12px,3vw,34px);
}
.segments{
  display:grid; grid-template-columns:repeat(4,1fr); gap:4px;
  background:#ECECF7; border-radius:999px; padding:5px;
  /* « Ressources » est le mot le plus long et il occupe la derniere colonne :
     il finissait a quatre pixels du bord de la pilule. */
  max-width:620px; margin:0 auto;
}
.segment{
  appearance:none; border:0; cursor:pointer;
  /* `1fr` ne descend pas tout seul sous la largeur de son mot le plus long :
     à 320 px, « Alternance » élargissait sa colonne, l'étui débordait, et
     toute la page se mettait à défiler de travers. */
  min-width:0;
  padding:11px 6px; border-radius:999px;
  font:700 13.5px/1 Manrope, sans-serif; color:var(--doux); background:transparent;
  transition:color .18s linear, background-color .18s linear, box-shadow .18s var(--ease);
}
.segment:hover{ color:var(--ink); }
.segment[aria-selected="true"]{
  color:#fff; background:var(--gradient);
  box-shadow:0 8px 18px -10px color-mix(in srgb, var(--accent) 80%, transparent);
}
/* Les tout petits écrans : le texte se resserre plutôt que de déborder. */
@media (max-width:440px){
  .segment{ font-size:12px; padding-inline:4px; letter-spacing:-.012em; }
}
@media (max-width:360px){
  .segment{ font-size:11.5px; padding-inline:2px; }
}

/* ============================================================================
   LES RUBRIQUES
   ============================================================================ */
/* L'air du haut est fait pour une rubrique qui COMMENCE : un titre, une
   phrase d'introduction. Une fiche projet ou une page de marque, elles,
   s'ouvrent sur leur bouton de sortie, qui doit rester sous le menu. */
.page{ padding-block:clamp(30px,4.5vw,50px) 0; }
.page.serre{ padding-top:10px; }
.rubrique{ margin-bottom:clamp(44px,6vw,72px); }
.rubrique[hidden]{ display:none; }

/* la barre de 16 px, puis le titre en petites capitales : la signature
   d'une rubrique joinly */
/* UN TIRET DE CHAQUE CÔTÉ. Il n'y en avait qu'un devant : le titre partait
   d'un trait et s'arrêtait dans le vide. Encadré, il se tient. */
.titre-rub{ display:flex; align-items:center; gap:10px; margin-bottom:18px; }
.titre-rub i{ width:16px; height:3px; border-radius:999px; background:var(--gradient); flex:none; }
.titre-rub span{ font-size:10.5px; font-weight:800; letter-spacing:.09em; text-transform:uppercase; color:var(--accent); }
.titre-rub.second{ margin-top:clamp(30px,4vw,44px); }
.intro-rub{ margin:-6px 0 22px; max-width:62ch; color:var(--doux); font-size:16.5px; }

.texte{ color:var(--doux); max-width:62ch; }
.texte.petit{ font-size:14.5px; margin-top:14px; }

/* --- profil : une seule phrase, puis des images et des chiffres --- */
.phrase{
  font-size:clamp(19px,2.2vw,23px); line-height:1.45; font-weight:600;
  max-width:34ch; margin-bottom:clamp(22px,3vw,30px);
}

.chiffres{ display:grid; grid-template-columns:repeat(4,1fr); gap:12px; }
.chiffre{ background:var(--carte); border-radius:16px; padding:20px; box-shadow:0 0 0 1px var(--trait); }
.chiffre b{
  display:block; font-family:Sora,sans-serif; font-weight:800;
  font-size:clamp(28px,3.4vw,38px); letter-spacing:-.04em; line-height:1;
  font-variant-numeric:tabular-nums;
  background:var(--gradient); -webkit-background-clip:text; background-clip:text; color:transparent;
}
.chiffre span{ display:block; margin-top:9px; font-size:13px; line-height:1.4; color:var(--doux); }
@media (max-width:820px){ .chiffres{ grid-template-columns:1fr 1fr; } }

/* la photo de l'atelier, en pleine largeur, avec sa légende posée dessus */
.vitrine{ position:relative; margin-top:12px; border-radius:20px; overflow:hidden; box-shadow:0 0 0 1px var(--trait); }
/* ⚠️ ELLE N'EST PAS ROGNÉE SUR LES CÔTÉS. La photo du bureau est en portrait
   depuis le 4 septembre 2026 ; l'ancienne hauteur fixe la réduisait à une
   bande. Noah : « mets la photo telle qu'elle est, ne la rogne pas trop sur
   les côtés pour qu'on la voie vraiment bien ».

   `height:auto` la laisse à ses proportions, donc pleine largeur ET pleine
   hauteur sur téléphone. Le plafond n'entre en jeu que sur grand écran, où la
   photo aurait sinon un mètre de haut : elle y devient un large panorama, et
   c'est encore toute sa largeur qu'on voit, c'est la hauteur qui se resserre,
   jamais les côtés. */
.vitrine img{
  display:block; width:100%; height:auto;
  max-height:min(680px, 128vw);
  object-fit:cover; object-position:center 46%;
}
.vitrine figcaption{
  position:absolute; left:0; right:0; bottom:0; padding:20px;
  background:linear-gradient(0deg, rgba(12,12,26,.72), rgba(12,12,26,0));
  color:#fff;
}
.vitrine figcaption b{ display:block; font-family:Sora,sans-serif; font-weight:700; font-size:17px; }
.vitrine figcaption span{ display:block; margin-top:2px; font-size:13.5px; color:rgba(255,255,255,.8); }

/* --- ce que je sais faire --- */
.savoirs{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.savoir{
  background:var(--carte); border-radius:18px; padding:22px;
  box-shadow:0 0 0 1px var(--trait);
  transition:transform .18s var(--ease), box-shadow .18s var(--ease);
}
.savoir:hover{ transform:translateY(-3px); box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent), 0 18px 40px -24px rgba(22,22,29,.3); }
.savoir .ic{ width:42px; height:42px; border-radius:13px; display:flex; align-items:center; justify-content:center; background:var(--accent-tint); color:var(--accent); }
.savoir .ic svg{ width:21px; height:21px; }
.savoir h3{ margin-top:14px; font-weight:700; font-size:18px; }
.savoir p{ margin-top:8px; font-size:15px; color:var(--doux); }
@media (max-width:820px){ .savoirs{ grid-template-columns:1fr; } }

.outils{ margin-top:12px; background:var(--carte); border-radius:18px; padding:20px; box-shadow:0 0 0 1px var(--trait); }
.jetons{ margin-top:12px; display:flex; flex-wrap:wrap; gap:8px; }
.jetons span{
  border-radius:999px; padding:7px 14px; font-size:13.5px; font-weight:600;
  background:var(--fond); color:#44444f; box-shadow:0 0 0 1px var(--trait);
}

/* --- les faits de l'alternance --- */
/* AUTANT DE COLONNES QU'IL Y A DE CARTES. C'était `repeat(4,1fr)` pour les
   quatre d'alors ; en retirer une laissait une colonne vide au bout de la
   ligne. `auto-fit` s'accorde au nombre réel, aujourd'hui comme demain. */
.faits{ display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px; }
.faits.deux{ grid-template-columns:1fr 1fr; margin-top:12px; }
.fait{
  background:var(--carte); border-radius:14px; padding:16px 18px;
  box-shadow:0 0 0 1px var(--trait); transition:transform .18s var(--ease);
}
.fait:hover{ transform:translateY(-2px); }
.fait-lab{ font-size:10px; font-weight:800; letter-spacing:.07em; text-transform:uppercase; color:var(--doux); }
.fait-val{ margin-top:7px; font-family:Sora,sans-serif; font-weight:800; font-size:17px; letter-spacing:-.03em; line-height:1.3; }
.fait-det{ margin-top:6px; font-size:13.5px; line-height:1.5; color:var(--doux); }
@media (max-width:900px){ .faits{ grid-template-columns:1fr 1fr; } }
@media (max-width:520px){ .faits, .faits.deux{ grid-template-columns:1fr; } }

.carte-large{ margin-top:12px; background:var(--carte); border-radius:18px; padding:20px; box-shadow:0 0 0 1px var(--trait); }
.semaine{ margin-top:14px; display:grid; grid-template-columns:repeat(5,1fr); gap:8px; }
.jour{ border-radius:12px; padding:14px 8px; text-align:center; background:var(--fond); box-shadow:0 0 0 1px var(--trait); }
.jour b{ display:block; font-size:13px; font-weight:800; }
.jour span{ display:block; margin-top:4px; font-size:11.5px; color:var(--doux); }
.jour.chez-vous{ background:var(--accent-tint); box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 26%, transparent); }
.jour.chez-vous b{ color:var(--accent); }
.jour.chez-vous span{ color:color-mix(in srgb, var(--accent) 72%, var(--ink)); }
@media (max-width:520px){ .semaine{ grid-template-columns:repeat(3,1fr); } .jour{ padding:11px 6px; } }

/* ============================================================================
   L'ALTERNANCE

   La rubrique était juste et plate : six cartes blanches alignées, toutes de
   la même voix. Elle s'ouvre maintenant sur un panneau au dégradé qui porte
   l'essentiel, et le reste vient en dessous, plus calme.
   ============================================================================ */
.alt-tete{
  background:var(--gradient); color:#fff; border-radius:22px;
  padding:clamp(24px,3.4vw,34px);
  display:grid; gap:24px; align-items:center;
  box-shadow:0 24px 56px -34px color-mix(in srgb, var(--accent) 85%, transparent);
}
@media (min-width:860px){ .alt-tete{ grid-template-columns:1.5fr auto; gap:34px; } }
.alt-eyebrow{ font-size:10.5px; font-weight:800; letter-spacing:.09em; text-transform:uppercase; color:rgba(255,255,255,.75); }
.alt-tete h2{ margin-top:11px; font-weight:800; font-size:clamp(26px,3.4vw,36px); color:#fff; }
.alt-tete p{ margin-top:12px; color:rgba(255,255,255,.85); max-width:46ch; font-size:16px; }
.alt-tete-cle{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.alt-tete-cle > div{
  background:rgba(255,255,255,.14); border-radius:16px; padding:16px 18px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.22);
}
.alt-tete-cle b{ display:block; font-family:Sora,sans-serif; font-weight:800; font-size:24px; letter-spacing:-.03em; }
.alt-tete-cle span{ display:block; margin-top:5px; font-size:12.5px; color:rgba(255,255,255,.8); line-height:1.35; }

.alt-semaine{ margin-top:12px; background:var(--carte); border-radius:18px; padding:20px; box-shadow:0 0 0 1px var(--trait); }

/* Le picto d'un fait : la même pastille teintée que partout ailleurs. */
.fait-ic{
  display:flex; align-items:center; justify-content:center;
  width:34px; height:34px; border-radius:11px; margin-bottom:12px;
  background:var(--accent-tint); color:var(--accent);
}
.fait-ic svg{ width:17px; height:17px; }

/* LA SCOLARITÉ, EN RUBANS. Trois jalons posés sur une ligne disent la
   progression mieux qu'une liste : on voit le chemin, pas trois faits. */
.alt-scolarite{ margin-top:12px; background:var(--carte); border-radius:18px; padding:20px; box-shadow:0 0 0 1px var(--trait); }
.rubans{ list-style:none; margin-top:14px; display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
.rubans li{
  position:relative; background:var(--fond); border-radius:14px; padding:16px;
  box-shadow:0 0 0 1px var(--trait);
}
/* La flèche entre deux rubans : le chemin se lit sans le dire. */
.rubans li + li::before{
  content:"›"; position:absolute; left:-11px; top:50%; transform:translateY(-50%);
  font-size:19px; font-weight:700; color:color-mix(in srgb, var(--accent) 55%, transparent);
}
.ruban-an{ display:block; font-size:11px; font-weight:800; letter-spacing:.07em; color:var(--doux); font-variant-numeric:tabular-nums; }
.rubans b{ display:block; margin-top:7px; font-family:Sora,sans-serif; font-weight:700; font-size:16px; letter-spacing:-.03em; }
.ruban-ou{ display:block; margin-top:5px; font-size:13px; color:var(--doux); line-height:1.4; }
.rubans .en-cours{
  background:var(--accent-tint);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
}
.rubans .en-cours b{ color:var(--accent); }
@media (max-width:760px){
  .rubans{ grid-template-columns:1fr; }
  .rubans li + li::before{ content:"⌄"; left:50%; top:-13px; transform:translateX(-50%); }
}

/* ============================================================================
   LA FRISE
   Un rail vertical, une pastille par jalon, la carte à droite. Les projets
   encore vivants ont une pastille pleine et un halo ; les autres une pastille
   creuse. L'état se lit avant l'étiquette.
   ============================================================================ */
/* LA FRISE MORD SUR LA MARGE DE GAUCHE. Noah, le 2 septembre 2026 : « décale-la
   un peu plus à gauche pour libérer de la place pour le reste, sans la coller
   au bord de l'écran ». Deux gestes : la gouttière des années se resserre, et
   la liste entière se décale hors du limiteur. Les cartes gagnent la somme des
   deux, et la marge restante suffit à ce que rien ne touche le bord. */
.frise{
  list-style:none; position:relative; margin-top:4px; --rail:66px;
  margin-left:calc(-1 * clamp(0px, 3.2vw, 48px));
}
/* Faible en haut, plein en bas : la frise va du premier essai à aujourd'hui,
   et c'est aujourd'hui qui compte. */
.frise::before{
  content:""; position:absolute; left:calc(var(--rail) - 1px); top:14px; bottom:26px;
  width:2px; border-radius:2px;
  background:linear-gradient(180deg, color-mix(in srgb, var(--accent) 18%, transparent) 0%, var(--accent) 92%);
}

/* La troisième colonne a une largeur FIXE, et non `auto` : sinon la largeur de
   l'étiquette d'état décide de celle de la carte, et les neuf cartes finissent
   avec neuf bords droits différents. */
.jalon{
  position:relative; display:grid;
  /* DEUX COLONNES, PLUS TROIS. L'état vivait dans une troisième colonne, à
     droite de la carte : « Au ralenti », « À plein temps » y tenaient sur deux
     lignes serrées, et la lecture sautait de la carte au bord de l'écran.
     Noah, le 4 septembre 2026 : « sur desktop, que ça fasse retour à la ligne,
     un peu comme sur mobile ». Il se pose donc sous la carte, partout. */
  grid-template-columns:var(--rail) 1fr; gap:0 18px; align-items:start;
  padding:0 0 26px;
}
.jalon:last-child{ padding-bottom:0; }
.jalon .an{
  grid-column:1; padding-top:3px; text-align:right; padding-right:16px;
  font-size:13px; font-weight:800; color:var(--doux); font-variant-numeric:tabular-nums;
}
/* La pastille est posée SUR le rail : sa position vient du même `--rail` que
   le trait, donc les deux ne peuvent pas se désaligner. */
.jalon .point{
  position:absolute; left:calc(var(--rail) - 7px); top:6px;
  width:14px; height:14px; border-radius:50%;
  background:var(--carte); box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent);
}
.jalon.vif .point{
  background:var(--accent);
  box-shadow:0 0 0 2px var(--accent), 0 0 0 6px color-mix(in srgb, var(--accent) 16%, transparent);
}

/* La carte est un BOUTON : le jalon s'ouvre sur sa fiche détaillée. */
.jalon .corps{
  grid-column:2; width:100%; text-align:left; cursor:pointer; border:0;
  background:var(--carte); border-radius:16px; padding:16px 18px;
  box-shadow:0 0 0 1px var(--trait);
  transition:transform .18s var(--ease), box-shadow .18s var(--ease);
}
.jalon .corps:hover{ transform:translateX(2px); box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent), 0 14px 32px -22px rgba(22,22,29,.4); }
.jalon h3{ font-weight:700; font-size:17px; }
.jalon .corps p{ margin-top:6px; font-size:14.5px; color:var(--doux); max-width:62ch; }
.ouvrir{
  display:inline-flex; align-items:center; gap:6px; margin-top:11px;
  font-size:13px; font-weight:800; color:var(--accent);
}
.ouvrir i{ font-style:normal; transition:transform .16s var(--ease); }
.jalon .corps:hover .ouvrir i{ transform:translateX(3px); }
/* ============================================================================
   L'ÉTAT D'UN PROJET, ET CE QU'IL VEUT DIRE

   « Arrêté » ne dit pas pourquoi, « Au ralenti » ne dit pas à quel point. La
   pastille est donc un bouton : elle ouvre une phrase sous elle. Noah : « une
   petite précision qui s'ouvre, mais surtout pas une pop-up ». Rien ne se pose
   par-dessus la page : le texte pousse simplement le reste vers le bas.

   L'ouverture passe par `grid-template-rows: 0fr → 1fr`, la seule façon
   d'animer une hauteur qu'on ne connaît pas d'avance. L'enfant porte
   `overflow:hidden`, sans quoi le texte dépasserait pendant le trajet.
   ============================================================================ */
.etat-zone{ grid-column:2; margin-top:10px; }
button.etat{
  appearance:none; border:0; cursor:pointer; font-family:inherit;
  display:inline-flex; align-items:center; gap:7px;
  transition:box-shadow .18s var(--ease), background-color .18s linear;
}
button.etat svg{ width:11px; height:11px; opacity:.75; transition:transform .24s var(--ease); }
button.etat:hover{ box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent); }
.etat-zone.ouvert button.etat svg{ transform:rotate(180deg); }

.etat-dit{
  display:grid; grid-template-rows:0fr; opacity:0; margin-top:0;
  font-size:13.5px; line-height:1.6; color:var(--doux); max-width:58ch;
  transition:grid-template-rows .3s var(--ease), opacity .22s linear, margin-top .3s var(--ease);
}
.etat-dit > span{ display:block; overflow:hidden; }
.etat-zone.ouvert .etat-dit{ grid-template-rows:1fr; opacity:1; margin-top:10px; }
/* Le filet d'accent relie la phrase à la pastille qui l'a ouverte. */
.etat-dit > span{ padding-left:12px; box-shadow:inset 2px 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }

/* ============================================================================
   LES DEUX CARTES QUI NE SONT PAS DES PROJETS

   La frise porte neuf projets, et deux choses qui n'en sont pas : ce qui vient
   après ClientBase, et l'emploi d'été qui l'a financé. Elles ne sont pas des
   boutons, il n'y a pas de fiche derrière, et elles ne se ressemblent pas
   entre elles : l'une est teintée d'accent parce qu'elle regarde devant,
   l'autre est neutre et porte son étiquette en toutes lettres. Noah : « qu'on
   sache que je ne le compte pas comme un projet ».
   ============================================================================ */
.jalon .corps.hors{
  cursor:default; background:var(--carte);
  box-shadow:0 0 0 1px var(--trait);
}
.jalon .corps.hors:hover{ transform:none; }
.hors-lab{
  font-size:10.5px; font-weight:800; letter-spacing:.08em; text-transform:uppercase;
  color:var(--doux); margin-bottom:8px;
}
.jalon.hors .point{ background:var(--carte); box-shadow:0 0 0 2px var(--trait); }
.hors-photo{
  margin-top:14px; border-radius:12px; overflow:hidden;
  background:var(--fond); box-shadow:0 0 0 1px var(--trait);
}
.hors-photo img{ display:block; margin-inline:auto; width:auto; height:auto; max-width:100%; max-height:min(420px,60vh); }
.hors-photo figcaption{ padding:10px 13px; font-size:12.5px; line-height:1.45; color:var(--doux); }

/* LA CARTE QUI ANNONCE LA SUITE. Elle regarde devant : elle prend l'accent. */
.jalon .corps.suite{
  cursor:default;
  background:linear-gradient(140deg, color-mix(in srgb, var(--accent) 8%, var(--carte)), var(--carte));
  box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent);
}
.jalon .corps.suite:hover{ transform:none; }

/* LE JALON D'OÙ L'ON VIENT. Revenir au parcours après avoir lu un projet
   ramenait tout en haut de la frise : on cherchait où l'on en était. Le jalon
   est maintenant recentré et s'allume une seconde. */
@keyframes rappel{
  0%   { box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent), 0 0 0 8px color-mix(in srgb, var(--accent) 18%, transparent); }
  100% { box-shadow:0 0 0 1px var(--trait), 0 0 0 8px transparent; }
}
.jalon.revenu .corps{ animation:rappel 1.6s var(--ease) both; }

.etat{
  font-size:11px; font-weight:800; letter-spacing:.05em; text-transform:uppercase;
  color:var(--doux); background:var(--carte); box-shadow:0 0 0 1px var(--trait);
  border-radius:999px; padding:6px 11px; white-space:nowrap;
}
.etat.vif{ color:var(--accent); background:var(--accent-tint); box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 26%, transparent); }

@media (max-width:700px){
  .frise{ --rail:26px; }
  .jalon{ grid-template-columns:var(--rail) 1fr; gap:0 14px; padding-bottom:20px; }
  .jalon .an{ grid-column:2; grid-row:1; text-align:left; padding:0 0 6px; color:var(--accent); }
  .jalon .corps{ grid-column:2; grid-row:2; }
  .etat-zone{ grid-column:2; grid-row:3; margin-top:8px; }
  .jalon .point{ top:2px; }
}

/* ============================================================================
   LA FICHE D'UN PROJET
   Tout ce que portait l'ancien site : le récit, les photos, les légendes.
   ============================================================================ */
.fiche-projet[hidden]{ display:none; }
/* ============================================================================
   LE BOUTON DE RETOUR

   Petit, simple, et il porte son libellé : une flèche seule ne dit pas où
   elle ramène, il faut l'avoir vue arriver pour le deviner. Le chevron ne
   fait qu'accompagner le mot.
   ============================================================================ */
.retour{
  display:inline-flex; align-items:center; gap:7px;
  cursor:pointer; border:0;
  background:var(--carte); color:var(--ink); box-shadow:0 0 0 1px var(--trait);
  border-radius:999px; padding:9px 16px 9px 12px; font:800 13px/1 Manrope,sans-serif;
  transition:box-shadow .18s var(--ease), transform .18s var(--ease), background-color .18s linear, color .18s linear;
}
.retour svg{ width:15px; height:15px; color:var(--accent); transition:transform .18s var(--ease); }
.retour:hover{
  background:var(--accent-tint); color:var(--accent);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 32%, transparent);
}
.retour:hover svg{ transform:translateX(-2px); }
/* IL SE COLLE AU MENU. C'est une sortie, pas un titre : il n'a aucune raison
   de flotter au milieu. Noah, le 2 septembre 2026 : « tu peux vraiment plus
   les coller au menu en haut ».

   ⚠️ L'ECART NE SE CORRIGE PAS ICI, et c'etait ma premiere erreur. Une marge
   negative sur ce bouton FUSIONNE avec celles de ses parents : elle remonte
   toute la section au lieu de rapprocher le bouton, et l'ecart mesure ne
   bouge pas d'un pixel. C'est le rembourrage de `main` qui se resserre, par
   la classe `serre` que pose `joinly.js`. */
.retour.haut{ margin-bottom:18px; }
/* En bas de page, le même bouton en plus grand : on y cherche une sortie
   après avoir lu, pas un repère de navigation. */
.retour.bas{ margin-top:clamp(22px,3vw,32px); padding:14px 24px; font-size:14px; }

.fp-an{ margin-top:0; font-size:11px; font-weight:800; letter-spacing:.08em; text-transform:uppercase; color:var(--accent); }
/* LES NOMS DE PROJETS SONT EN NOIR FRANC, aux trois endroits où ils
   apparaissent : le titre de la fiche, la carte de la frise, et les deux
   boutons qui mènent au projet voisin. Noah, le 4 septembre 2026 : « j'aimerais
   que mes titres de projets soient en noir ».

   Le titre de fiche héritait de `--ink`, #16161d : un noir tiré vers le bleu,
   qui va bien à du texte courant mais qui, sur quarante pixels de haut, se
   voyait plus doux que les mêmes noms ailleurs. Les trois valent maintenant la
   même chose, et c'est écrit plutôt qu'hérité. */
.fp-titre,
.jalon h3,
.sp-nom{ color:#000; }

.fp-titre{ margin-top:10px; font-weight:800; font-size:clamp(28px,4.2vw,42px); letter-spacing:-.04em; }
.fp-intro{ margin-top:14px; max-width:62ch; font-size:17px; color:var(--doux); }
.fp-jetons{ margin-top:18px; }

/* LE FIL CONDUCTEUR. Noah : « essaye de faire un petit fil conducteur
   derrière les histoires, histoire que ça fasse pas une trop longue page ».
   Un rail vertical relie les blocs, avec une pastille par étape du récit : on
   voit d'un coup d'oeil combien il en reste, et la page cesse d'être une pile
   de cartes sans fin. */
.recit{
  position:relative; margin-top:clamp(26px,4vw,40px);
  display:grid; gap:clamp(18px,2.6vw,26px);
  padding-left:38px;
}
.recit::before{
  content:""; position:absolute; left:11px; top:12px; bottom:12px; width:2px;
  border-radius:2px;
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 55%, transparent) 0%,
    color-mix(in srgb, var(--accent) 18%, transparent) 88%,
    transparent 100%);
}
.recit > .bl{ position:relative; }
.recit > .bl::before{
  content:""; position:absolute; left:-33px; top:26px;
  width:12px; height:12px; border-radius:50%;
  background:var(--carte); box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent);
}
/* Le dernier point est plein : le récit s'arrête là, et ça se voit. */
.recit > .bl:last-child::before{
  background:var(--accent);
  box-shadow:0 0 0 2px var(--accent), 0 0 0 6px color-mix(in srgb, var(--accent) 15%, transparent);
}
@media (max-width:640px){
  .recit{ padding-left:26px; }
  .recit::before{ left:5px; }
  .recit > .bl::before{ left:-27px; top:20px; width:10px; height:10px; }
}

/* Un bloc de récit : le texte à gauche, l'image à droite. Un bloc sur deux
   s'inverse, pour que la page ne devienne pas une colonne de légendes. */
.bl{
  display:grid; grid-template-columns:1fr 1.15fr; gap:clamp(18px,2.6vw,28px);
  align-items:center;
  background:var(--carte); border-radius:20px; padding:clamp(18px,2.4vw,26px);
  box-shadow:0 0 0 1px var(--trait);
}
.bl:nth-child(even) .bl-tx{ order:2; }
.bl:nth-child(even) .bl-md{ order:1; }
.bl-seul, .bl-large{ grid-template-columns:1fr; }
.bl-kicker{ font-size:10.5px; font-weight:800; letter-spacing:.08em; text-transform:uppercase; color:var(--accent); }
.bl h4{ margin-top:9px; font-weight:700; font-size:clamp(19px,2.2vw,23px); }
.bl p{ margin-top:10px; font-size:15.5px; color:var(--doux); max-width:60ch; }
.bl-note{ margin-top:12px; font-size:13px; font-style:italic; color:#8a8a96; }
.bl-compte{ margin-top:16px; }
.bl-compte b{
  display:block; font-family:Sora,sans-serif; font-weight:800; font-size:clamp(30px,4vw,40px);
  letter-spacing:-.04em; line-height:1;
  background:var(--gradient); -webkit-background-clip:text; background-clip:text; color:transparent;
}
.bl-compte span{ display:block; margin-top:6px; font-size:13.5px; color:var(--doux); }

.cliche{ border-radius:14px; overflow:hidden; background:var(--fond); box-shadow:0 0 0 1px var(--trait); }
/* Les photos de l'ancien site sont de tous les formats : des captures très
   larges et des photos de téléphone très hautes. Sans plafond, une seule
   photo verticale fait un bloc de deux écrans. On la recadre au centre. */
/* ============================================================================
   ON RÉDUIT LA PHOTO, ON NE LA COUPE PAS

   Vingt-deux des trente-trois photos de ce site sont VERTICALES : des captures
   de téléphone, des clichés pris au portable. Avec une hauteur plafonnée et
   `object-fit:cover`, il n'en restait qu'une tranche du milieu, un quart de
   l'image pour une capture Vinted. Noah, le 2 septembre 2026 : « globalement
   tu les as rognées et du coup elles perdent complètement de leur intérêt ».

   La contrainte porte maintenant sur les DEUX dimensions à la fois, sans
   `object-fit` : le navigateur réduit la photo jusqu'à ce qu'elle tienne, en
   gardant ses proportions. Une capture verticale se pose donc au centre de sa
   carte, entière, avec du fond de chaque côté, exactement comme on regarde
   l'écran d'un téléphone. Rien n'est perdu.
   ============================================================================ */
.cliche img{
  display:block; margin-inline:auto;
  width:auto; height:auto;
  max-width:100%; max-height:min(620px, 76vh);
}
/* La même photo dans le récit : plus haute, parce qu'elle est en portrait et
   qu'à 420 pixels il n'en resterait qu'une tranche. */
.cliche img[src$="ia-setup.jpg"]{ max-height:min(680px, 132vw); }
/* En bande, plusieurs photos partagent la ligne : le plafond descend, mais le
   principe ne change pas, elles rétrécissent, elles ne se coupent pas. */
.bl-bande .cliche img, .bl-duo .cliche img{ max-height:min(400px, 46vh); }
/* LA VIDÉO EST VERTICALE, comme la publicité l'était. On ne la rogne pas :
   on lui donne sa hauteur, plafonnée pour qu'elle ne mange pas l'écran. */
.cliche.film video{
  display:block; width:100%; height:auto;
  max-height:min(72vh, 560px); background:#0c0c1a;
}
.cliche figcaption{ padding:11px 14px; font-size:12.5px; line-height:1.45; color:var(--doux); }

.bl-bande{ margin-top:18px; display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
.bl-duo{ margin-top:18px; display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.duo-lab{
  margin-bottom:8px; font-size:11px; font-weight:800; letter-spacing:.06em;
  text-transform:uppercase; color:var(--doux);
}
@media (max-width:820px){
  .bl{ grid-template-columns:1fr; }
  .bl:nth-child(even) .bl-tx{ order:0; }
  .bl:nth-child(even) .bl-md{ order:0; }
  .bl-bande{ grid-template-columns:1fr 1fr; }
}
@media (max-width:520px){ .bl-bande, .bl-duo{ grid-template-columns:1fr; } }

/* ============================================================================
   L'AVANT / APRÈS

   Deux images au même endroit, et deux onglets pour passer de l'une à
   l'autre. C'est le bloc de l'ancien site, remis dans la DA de joinly : les
   poser côte à côte revenait à demander au lecteur de faire la comparaison
   lui-même, alors que c'est le travail du bloc.
   ============================================================================ */
.compare{ margin-top:18px; }
.cmp-scene{
  position:relative; border-radius:14px; overflow:hidden;
  background:var(--fond); box-shadow:0 0 0 1px var(--trait);
  aspect-ratio:4 / 3;
}
.cmp-img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:contain; background:var(--fond);
  transition:opacity .42s var(--ease);
}
.cmp-img.sorti{ opacity:0; }
.cmp-onglets{
  margin-top:12px; display:inline-grid; grid-auto-flow:column; gap:4px;
  background:#ECECF7; border-radius:999px; padding:4px;
}
.cmp-onglet{
  appearance:none; border:0; cursor:pointer; border-radius:999px;
  padding:9px 16px; font:700 13px/1 Manrope,sans-serif;
  color:var(--doux); background:transparent;
  transition:color .18s linear, background-color .18s linear;
}
.cmp-onglet:hover{ color:var(--ink); }
.cmp-onglet.actif{ color:#fff; background:var(--gradient); }
.cmp-legende{ margin-top:12px; font-size:13px; line-height:1.5; color:var(--doux); }

/* ============================================================================
   PASSER D'UN PROJET À L'AUTRE
   ============================================================================ */
.entre-projets{
  margin-top:clamp(26px,4vw,40px); display:grid; grid-template-columns:1fr 1fr; gap:12px;
}
.saut-projet{
  appearance:none; border:0; cursor:pointer; text-align:left;
  background:var(--carte); border-radius:16px; padding:16px 18px;
  box-shadow:0 0 0 1px var(--trait);
  transition:transform .18s var(--ease), box-shadow .18s var(--ease);
  /* La flèche d'un côté, le texte de l'autre. Elle est collée au bord dont
     elle parle, donc le sens se lit avant le libellé. */
  display:flex; align-items:center; gap:12px;
}
.sp-txt{ min-width:0; }
.sp-fleche{
  flex:none; width:20px; height:20px; color:var(--accent);
  transition:transform .18s var(--ease);
}
.saut-projet.suiv{ text-align:right; justify-content:space-between; }
.saut-projet.prec:hover .sp-fleche{ transform:translateX(-3px); }
.saut-projet.suiv:hover .sp-fleche{ transform:translateX(3px); }
.saut-projet:hover{ transform:translateY(-2px); box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent), 0 14px 32px -22px rgba(22,22,29,.4); }
.sp-lab{ display:block; font-size:10.5px; font-weight:800; letter-spacing:.08em; text-transform:uppercase; color:var(--accent); }
.sp-nom{ display:block; margin-top:6px; font-family:Sora,sans-serif; font-weight:700; font-size:16px; letter-spacing:-.03em; }
/* Empilés, les deux boutons perdent leur gauche et leur droite : la flèche
   reste le seul repère, et elle garde son bord. */
@media (max-width:560px){
  .entre-projets{ grid-template-columns:1fr; }
  .saut-projet.suiv{ text-align:left; }
  .saut-projet.suiv .sp-txt{ margin-right:auto; }
}

/* ============================================================================
   LES BLOCS QUI APPARAISSENT

   Chaque bloc de récit monte de quelques pixels en entrant dans l'écran. Ils
   sont posés visibles par défaut : si le script ne tourne pas, on lit la page
   normalement au lieu de tomber sur du blanc.
   ============================================================================ */
.apparait.en-attente{ opacity:0; transform:translateY(22px); }
.apparait.venu{ opacity:1; transform:none; transition:opacity .6s var(--ease), transform .6s var(--ease); }

/* ============================================================================
   LES RESSOURCES
   ============================================================================ */
.ressources{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.ressource{
  position:relative; display:flex; align-items:center; gap:16px;
  background:var(--carte); border-radius:18px; padding:20px;
  box-shadow:0 0 0 1px var(--trait); overflow:hidden;
  transition:transform .18s var(--ease), box-shadow .18s var(--ease);
}
/* Une lueur qui monte du coin au survol : la carte répond au doigt sans
   bouger de place, ce qui est le geste juste pour un lien de téléchargement. */
.ressource::after{
  content:""; position:absolute; right:-40px; bottom:-40px;
  width:130px; height:130px; border-radius:50%;
  background:radial-gradient(circle, var(--accent-glow), transparent 70%);
  opacity:0; transition:opacity .28s linear;
}
.ressource:hover{ transform:translateY(-3px); box-shadow:0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent), 0 18px 40px -24px rgba(22,22,29,.35); }
.ressource:hover::after{ opacity:1; }
.ressource > *{ position:relative; }
/* La flèche qui dit « ça s'ouvre ». Elle avance de trois pixels au survol. */
.ressource .fleche{
  margin-left:auto; color:var(--accent); flex:none;
  transition:transform .18s var(--ease);
}
.ressource:hover .fleche{ transform:translateX(4px); }
.res-ic{
  width:46px; height:46px; flex:none; border-radius:14px;
  display:flex; align-items:center; justify-content:center;
  background:var(--gradient); color:#fff;
  box-shadow:0 8px 18px -10px color-mix(in srgb, var(--accent) 75%, transparent);
}
.res-ic svg{ width:21px; height:21px; }
.res-tx b{ display:block; font-weight:700; font-size:15.5px; }
.res-tx span{ display:block; margin-top:3px; font-size:13.5px; color:var(--doux); }
@media (max-width:700px){ .ressources{ grid-template-columns:1fr; } }

/* ============================================================================
   LE PIED
   ============================================================================ */
.pied{ border-top:1px solid var(--trait); background:var(--carte); }
/* En bas, la barre de gestes : le dernier texte ne doit pas passer dessous. */
.pied-in{ padding-block:32px calc(46px + env(safe-area-inset-bottom, 0px)); }
.pied-dit{ margin-top:14px; font-size:14.5px; color:var(--doux); max-width:52ch; }
.pied-dit b{ font-family:Poppins, Sora, sans-serif; color:var(--ink); font-weight:800; }
.pied-legal{ margin-top:16px; font-size:13px; color:var(--doux); }

/* ════════════════════════════════════════════════════════════════════
   LE TÉLÉPHONE

   Chez joinly, la version téléphone n'est pas la version d'ordinateur en
   plus étroit : c'est une page à part (`AccueilTelephone.tsx`), et elle
   suit deux règles.

   1. TOUT EST CENTRÉ. « Sur un écran de 390 pixels, un titre aligné à
      gauche sur trois lignes laisse un bord droit en dents de scie ;
      centré, il fait un bloc. »
   2. LES GRILLES DE CARTES DEVIENNENT DES LISTES, picto à gauche, comme
      les réglages d'un téléphone.

   C'est aussi le public le plus important : un lien envoyé à un recruteur
   s'ouvre presque toujours sur un téléphone.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width:640px){

  /* --- le bandeau, centré --- */
  .bandeau-in{ text-align:center; }
  .lockup{ justify-content:center; margin-bottom:22px; }
  .champ{ margin-inline:auto; }
  .langues{ justify-content:center; }
  .langues li{ font-size:13px; }

  /* --- les têtes de rubrique, centrées elles aussi --- */
  .titre-rub{ justify-content:center; }
  .intro-rub, .phrase{ text-align:center; margin-inline:auto; max-width:none; }
  .retour.haut{ margin-inline:auto; }
  .fp-an, .fp-titre, .fp-intro{ text-align:center; margin-inline:auto; }
  .fp-jetons{ justify-content:center; }

  /* --- les compétences deviennent une liste à picto ---
     La carte reste, mais son picto passe à gauche du titre au lieu d'être
     posé au-dessus : sur une colonne, quatre pictos empilés font quatre
     pauses avant d'arriver au texte. */
  .savoir{ display:grid; grid-template-columns:auto 1fr; gap:0 14px; align-items:center; padding:18px; }
  .savoir .ic{ width:38px; height:38px; border-radius:11px; grid-row:1; }
  .savoir .ic svg{ width:19px; height:19px; }
  .savoir h3{ grid-column:2; grid-row:1; margin-top:0; font-size:16.5px; }
  .savoir p{ grid-column:1 / -1; margin-top:12px; }

  /* --- l'alternance --- */
  .alt-tete{ text-align:center; }
  .alt-tete p{ margin-inline:auto; }
  .alt-tete-cle{ grid-template-columns:1fr 1fr; }

  /* --- les fiches projet --- */
  .bl-kicker, .bl h4, .bl p{ text-align:center; }
  .bl p{ margin-inline:auto; }
  .retour{ width:100%; justify-content:center; }

  /* --- le pied --- */
  .pied-in{ text-align:center; }
  .lockup.petit{ justify-content:center; }
  .pied-dit{ margin-inline:auto; }
}
