*,*::before,*::after{box-sizing:border-box}
:root{
  /* Sombre par défaut : une photographie se regarde mieux sur du noir, et
     c'est le parti pris du site. Le mode clair est un choix du visiteur. */
  --bg:#000; --surface:#121212; --surface2:#1b1b1b;
  --ink:#f2f2f2; --ink2:#8c8c8c; --ink3:#d8d8d8; --line:#262626;
  /* Jetons inversés : boutons, bandeau, pastille. Ils doivent trancher sur le
     fond, donc ils suivent le thème en sens contraire. */
  --inv-bg:#fff; --inv-ink:#000; --inv-ink2:#555; --inv-line:#e4e4e4; --inv-survol:#f2f2f2;
  --voile:rgba(0,0,0,.92);
  --alerte:#b98b3c;
  --rail:300px; --barre-haute:56px;
  /* La poignée des barres de défilement. Elle avait la couleur des filets,
     qui sont faits pour se faire oublier : sur le noir, on ne voyait pas
     qu'une colonne pouvait défiler. */
  --poignee:#4f4f4f;
  --sans:"Archivo",system-ui,sans-serif;
  --serif:"Newsreader",Georgia,serif;
}

/* Clair : un crème de papier, chaud, pour l'univers du mariage. Les gris
   tirent vers le brun plutôt que vers le bleu, sinon l'ensemble vire au
   froid et perd ce qu'on est venu chercher. */
:root[data-theme="clair"]{
  --bg:#f7f2ea; --surface:#ece4d8; --surface2:#e2d8c9;
  --ink:#231e19; --ink2:#6b6157; --ink3:#3c352e; --line:#ded3c4;
  --inv-bg:#231e19; --inv-ink:#f7f2ea; --inv-ink2:#a39889; --inv-line:#3a332c; --inv-survol:#3a332c;
  --voile:rgba(247,242,234,.92);
  --alerte:#8a5d12;
  --poignee:#ab9c85;
}
html{background:var(--bg)}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--sans);font-size:15px;line-height:1.5;
  -webkit-font-smoothing:antialiased;overflow-x:hidden}
img{display:block;max-width:100%}
/* Sans !important, un display posé par une classe l'emporte sur l'attribut :
   un .btn caché restait visible. */
[hidden]{display:none!important}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}
:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.skip{position:fixed;left:-999px;top:0;z-index:99;background:var(--inv-bg);color:var(--inv-ink);padding:.6rem 1rem}
.skip:focus{left:0}

/* ---------- bascule clair / sombre ---------- */
/* Fixe en haut à droite, au même endroit sur mobile et sur ordinateur : c'est
   là qu'on cherche ce réglage, et le rail de gauche est déjà occupé. */
.theme{position:fixed;top:calc((var(--barre-haute) - 40px) / 2);right:.6rem;z-index:46;
  width:40px;height:40px;display:grid;place-items:center;color:var(--ink2);border-radius:50%}
.theme:hover{color:var(--ink);background:var(--surface)}
.theme svg{width:19px;height:19px}

/* ---------- barre haute (mobile) ---------- */
.topbar{position:sticky;top:0;z-index:35;height:var(--barre-haute);
  display:flex;align-items:center;justify-content:space-between;
  gap:1rem;padding:0 3.2rem 0 1rem;background:var(--voile);backdrop-filter:blur(12px);
  border-bottom:1px solid var(--line)}
.topbar a.qui{font-size:.82rem;color:var(--ink2);white-space:nowrap;
  display:flex;align-items:center;min-height:44px;margin:-11px 0}  /* cible tactile */


/* ---------- rail (desktop) ---------- */
.rail{display:none}
.rail-bouton{display:none}
/* Le logo est la seule couleur de la page. Tout le reste reste achromatique. */
.wordmark{display:block;line-height:0}
.wordmark img{width:215px;height:auto}
.topbar .wordmark img{width:140px}
.rail-line{font-family:var(--serif);font-weight:300;font-size:1.05rem;line-height:1.45;color:var(--ink);margin:1.6rem 0 0}
.nav{margin-top:auto;display:grid;gap:.35rem;font-size:.95rem}
.nav a{color:var(--ink2);width:max-content;padding:.1rem 0;border-bottom:1px solid transparent}
.nav a:hover{color:var(--ink)}
.nav a.on{color:var(--ink);border-bottom-color:var(--ink)}
.nav-sep{height:1px;background:var(--line);width:2rem;margin:.6rem 0}
.rail-foot{color:var(--ink2);font-size:.8rem;margin:1.6rem 0 0;line-height:1.7}
.rail-foot a{border-bottom:1px solid var(--line)}
.rail-foot a:hover{color:var(--ink)}
.todo{color:var(--alerte)!important}

/* ---------- feed ---------- */
main{padding-bottom:6.5rem}
.hero{padding:1.25rem 1rem .25rem}
.hero h1{font-family:var(--serif);font-weight:300;font-size:clamp(1.55rem,5.2vw,1.95rem);line-height:1.2;margin:0;max-width:20ch;letter-spacing:-.005em;text-wrap:balance}
.hero .lede{font-family:var(--serif);font-weight:300;font-size:1.05rem;color:var(--ink);margin:.6rem 0 0;max-width:42ch;text-wrap:pretty}
.hero p{color:var(--ink2);margin:.7rem 0 0;max-width:46ch;text-wrap:pretty}

.serie{margin-top:2.25rem}
.serie-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;padding:0 1rem .6rem}
/* Le titre d'une série dans la voix du photographe ; le lieu, à côté, reste
   en Archivo gris : l'écart de police fait la hiérarchie, sans gras. */
.serie-head h2{font-family:var(--serif);font-weight:300;font-size:1.3rem;line-height:1.2;margin:0;letter-spacing:-.005em}
.serie-head span{color:var(--ink2);font-size:.8rem;white-space:nowrap}
/* Le lien vers la galerie de livraison est le seul de la page à sortir du
   site : il doit se voir, sans pour autant rivaliser avec les photos. */
.gal{display:inline-flex;align-items:center;gap:.4rem;margin-top:.2rem;padding:.55rem .9rem;
  border:1px solid var(--line);color:var(--ink3);font-family:var(--sans);font-size:.85rem;
  white-space:nowrap;text-decoration:none;transition:border-color .2s ease,color .2s ease}
.gal:hover,.gal:focus-visible{border-color:var(--ink3);color:var(--ink)}
.gal svg{width:15px;height:15px;flex:none}

.track{position:relative}
.strip{display:flex;gap:2px;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;cursor:grab;
  -webkit-overflow-scrolling:touch}
.strip::-webkit-scrollbar{display:none}
/* margin:0 est indispensable : un <figure> porte une marge de 1em 40px du
   navigateur lui-même. Elle ouvrait un vide de 40 px avant la première image
   et après la dernière, où l'on pouvait glisser sans que rien ne suive. */
.frame{position:relative;flex:0 0 100%;margin:0;scroll-snap-align:center;background:var(--surface);
  /* 4/5, le format portrait le plus haut d'Instagram. Le 2/3 d'origine
     occupait presque tout l'écran d'un téléphone : on ne devinait pas qu'il y
     avait quelque chose en dessous, et rien n'invitait à faire défiler. */
  aspect-ratio:4/5;overflow:hidden;-webkit-user-select:none;user-select:none}
/* contain, et non cover : la photo s'inscrit entière dans le cadre au lieu
   d'en remplir la surface. Une image n'est jamais rognée, c'est le cadrage du
   photographe qui décide, pas celui du site. Le fond fait letterbox. */
.frame img{width:100%;height:100%;object-fit:contain;opacity:0;transition:opacity .6s ease}
.frame img.in{opacity:1}
.arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;width:44px;height:44px;
  display:none;place-items:center;background:rgba(0,0,0,.45);color:#fff;backdrop-filter:blur(6px);
  opacity:.65;transition:opacity .2s}
.arrow svg{width:24px;height:24px}
.arrow.prev{left:0}.arrow.next{right:0}
.arrow[disabled]{opacity:0!important;pointer-events:none}
.track:hover .arrow,.arrow:focus-visible{opacity:1}
.track:hover .arrow{background:rgba(0,0,0,.6)}
/* Le cadre du favori dit la même chose que le cœur de la barre : il porte
   donc la même encre, et suit le thème. En blanc fixe, il disparaissait sur
   le crème du mode clair. */
.frame.liked::after{content:"";position:absolute;inset:0;box-shadow:inset 0 0 0 2px var(--ink);pointer-events:none}

.burst{position:absolute;inset:0;display:grid;pointer-events:none}
/* Même encre que le cœur de la barre et que le cadre du favori : les trois
   disent la même chose. Le halo, lui, prend la couleur du fond, donc il
   s'inverse avec le thème et le cœur reste lisible par-dessus une photo
   claire comme par-dessus une sombre. */
.burst svg{grid-area:1/1;place-self:center;width:88px;height:88px;fill:var(--ink);opacity:0;transform:scale(.4);
  filter:drop-shadow(0 2px 14px var(--voile))}
.burst svg.heart{fill:none;stroke:var(--ink);stroke-width:1.4}
.burst svg:last-child{display:none}            /* like : cœur plein */
.burst.off svg:first-child{display:none}       /* unlike : cœur creux */
.burst.off svg:last-child{display:block}
.burst.go svg{animation:pop .75s cubic-bezier(.2,.9,.3,1) forwards}
@keyframes pop{15%{opacity:.95;transform:scale(1.08)}40%{transform:scale(.96)}100%{opacity:0;transform:scale(1.15)}}

.bar{display:flex;align-items:center;gap:1.1rem;padding:.25rem 1rem 0}
.bar button{display:inline-flex;align-items:center;min-height:44px}  /* cible tactile */
.bar .heart{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.6}
.bar button[aria-pressed="true"] .heart{fill:currentColor}
.bar .txt{font-size:.85rem;color:var(--ink2)}
.bar .txt:hover{color:var(--ink)}
.bar .dots{margin-left:auto;display:flex;gap:5px}
.bar .dots i{width:5px;height:5px;border-radius:50%;background:var(--line)}
.bar .dots i.on{background:var(--ink2)}
.cap{font-family:var(--serif);font-weight:300;font-size:1rem;line-height:1.45;color:var(--ink);padding:.5rem 1rem 0;margin:0;max-width:60ch;text-wrap:pretty}
.cap em{display:block;font-style:normal;color:var(--ink2)}

/* ---------- univers (accueil) ---------- */
.univers{display:grid;gap:2px;margin-top:1.75rem}
.u{position:relative;display:block;aspect-ratio:16/10;overflow:hidden;background:var(--surface)}
.u img{width:100%;height:100%;object-fit:cover;opacity:.75;transition:opacity .5s ease,transform 4s ease}
.u:hover img,.u:focus-visible img{opacity:.8;transform:scale(1.03)}
.u::after{content:"";position:absolute;inset:40% 0 0;pointer-events:none;
  background:linear-gradient(to bottom,transparent,rgba(0,0,0,.75))}
/* Ce texte est posé sur une photo, sous un voile sombre : il reste clair dans
   les deux thèmes. Le faire suivre le thème le rendait invisible en mode
   crème, gris foncé sur image sombre. */
/* Le nom de l'univers dans la voix du photographe, la même que ses titres :
   plus grand et plus léger que l'Archivo en gras d'avant, qui tenait de
   l'interface. Le décompte reste en Archivo, c'est une information. */
.u span{position:absolute;z-index:1;left:1rem;bottom:1rem;font-family:var(--serif);font-weight:300;
  font-size:1.7rem;line-height:1.1;letter-spacing:-.01em;
  color:#fff;text-shadow:0 1px 20px rgba(0,0,0,.8)}
.u b{display:block;margin-top:.3rem;font-family:var(--sans);font-weight:400;font-size:.78rem;letter-spacing:0;color:#c9c9c9}

.perdu{display:flex;flex-wrap:wrap;gap:.6rem 1.25rem;margin:1.5rem 0 0}
.perdu a{border-bottom:1px solid var(--line);padding:.35rem 0}
.perdu a:hover{color:var(--ink);border-bottom-color:var(--ink)}

/* ---------- portrait ---------- */
/* height:auto sinon l'attribut height du <img> fige la hauteur et annule aspect-ratio */
.portrait{width:120px;height:auto;aspect-ratio:2/3;object-fit:cover;flex:0 0 auto}
.portrait.large{width:min(200px,45%);height:auto;float:right;margin:.2rem 0 1rem 1.25rem}
.bio-court{display:flex;gap:1.25rem;align-items:flex-start;margin-top:2.5rem;
  padding-top:2rem;border-top:1px solid var(--line)}
.bio-court h2{margin-top:0}
.bio-court p{font-size:1rem;margin:.3rem 0 0}
.bio-court .btn{width:max-content;padding:.6rem 1.1rem;margin-top:1rem}

/* ---------- projets flashs ---------- */
.flashs{display:grid;gap:2px;margin-top:1.75rem}
.flash{position:relative;background:var(--surface)}
.flash img{width:100%;height:auto;display:block}
.flash-txt{padding:1rem 1rem 1.6rem}
.flash-txt h2{margin:0;font-size:1.05rem;font-weight:500;letter-spacing:-.01em}
.flash-txt p{margin:.25rem 0 0;font-size:.85rem;color:var(--ink2);text-wrap:pretty}
.flash-txt .btn{width:max-content;padding:.6rem 1.1rem;margin-top:.9rem}

/* ---------- pages ---------- */
.page{padding:1.5rem 1rem 0;max-width:62ch}
.page h1{font-family:var(--serif);font-weight:300;font-size:clamp(1.5rem,5vw,1.9rem);margin:0 0 1rem;line-height:1.2;max-width:20ch;text-wrap:balance}
.page h2{font-family:var(--serif);font-weight:300;font-size:1.35rem;line-height:1.25;margin:2.2rem 0 .5rem;
  letter-spacing:-.005em;text-wrap:balance}
.page p{font-family:var(--serif);font-weight:300;font-size:1.05rem;line-height:1.6;color:var(--ink3);text-wrap:pretty}
.offers{margin:1.25rem 0 0;display:grid;gap:1px;background:var(--line);border-block:1px solid var(--line)}
.offer{background:var(--bg);padding:1rem 0;display:grid;grid-template-columns:1fr auto;gap:.2rem 1rem;align-items:baseline}
.offer h2{margin:0;font-family:var(--serif);font-weight:300;font-size:1.3rem;line-height:1.2;letter-spacing:-.005em;text-wrap:balance}
.offer b{font-weight:500;font-variant-numeric:tabular-nums}
.offer p{grid-column:1/-1;text-wrap:pretty;margin:.3rem 0 0;font-family:var(--sans);font-size:.88rem;line-height:1.45;color:var(--ink2)}
.note a{border-bottom:1px solid var(--line);display:inline-block;padding:.25rem 0}
.note a:hover{color:var(--ink)}
.note{font-size:.9rem!important;color:var(--ink2);font-family:var(--sans)!important}

/* ---------- forms ---------- */
label{display:block;font-size:.8rem;color:var(--ink2);margin:1rem 0 .3rem}
input,select,textarea{width:100%;background:var(--surface);border:1px solid var(--line);color:var(--ink);
  border-radius:0;padding:.7rem .75rem;font:inherit}
textarea{min-height:6.5rem;resize:vertical}
.btn{display:block;width:100%;background:var(--inv-bg);color:var(--inv-ink);text-align:center;padding:.85rem;font-weight:500;margin-top:1.4rem}
.btn:hover{background:var(--inv-survol)}
.btn-ghost{background:none;color:var(--ink);border:1px solid var(--line)}
.btn-ghost:hover{background:var(--surface)}

/* ---------- selection ---------- */
/* 110 px et non 88 : c'est une page où l'on revoit ses images, pas une
   planche-contact, et la croix a besoin de place pour ne pas manger la
   vignette. */
.picked{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:2px;margin:1rem 0 0}
.tile{position:relative;margin:0;min-width:0}
.picked img{width:100%;height:auto;aspect-ratio:2/3;object-fit:cover}

/* La croix : 44 px de zone touchée, un disque de 30 px à l'œil. Sans cet
   écart, la cible tactile couvrait le quart de la vignette. */
.rm{position:absolute;top:0;right:0;z-index:1;width:44px;height:44px;
  display:grid;place-items:center;color:#fff}
.rm svg{width:30px;height:30px;padding:6px;border-radius:50%;
  background:rgba(0,0,0,.55);backdrop-filter:blur(6px);transition:background .2s ease}
.rm:hover svg,.rm:focus-visible svg{background:rgba(0,0,0,.85)}

/* Armé : la question couvre la vignette entière, pas la seule croix, et
   reste affichée jusqu'à confirmation ou expiration. */
.tile:has(.rm.ask)::after{content:"Retirer ?\A Toucher pour confirmer";white-space:pre-line;
  position:absolute;inset:0;display:grid;place-items:center;pointer-events:none;
  background:rgba(0,0,0,.82);color:#fff;font-size:.75rem;line-height:1.3;padding:.4rem;
  text-align:center;text-wrap:balance;box-shadow:inset 0 0 0 2px #fff}
.tile:has(.rm.ask) img{filter:grayscale(1)}
.empty{color:var(--ink2);font-family:var(--serif);font-weight:300;font-size:1.05rem}

/* ---------- message éphémère ---------- */
.toast{position:fixed;left:50%;bottom:calc(6.5rem + env(safe-area-inset-bottom));z-index:50;
  transform:translate(-50%,8px);background:var(--inv-bg);color:var(--inv-ink);
  padding:.55rem 1rem;font-size:.82rem;white-space:nowrap;backdrop-filter:blur(10px);
  opacity:0;pointer-events:none;transition:opacity .2s ease,transform .2s ease}
.toast.on{opacity:1;transform:translate(-50%,0)}

/* ---------- recap bar ---------- */
.recap{position:fixed;left:0;right:0;bottom:calc(52px + env(safe-area-inset-bottom));z-index:30;
  background:var(--inv-bg);color:var(--inv-ink);display:flex;align-items:stretch;
  transform:translateY(130%);transition:transform .45s cubic-bezier(.2,.8,.2,1)}
.recap.up{transform:none}
.recap-go{flex:1;min-width:0;display:flex;justify-content:space-between;gap:.9rem;align-items:center;
  padding:.85rem 1rem;text-align:left;font-weight:500;color:var(--inv-ink);min-height:44px}
.recap-go > span:first-child{min-width:0}
.recap-go > span:last-child{white-space:nowrap;font-size:.9rem}
.recap-go:hover{background:var(--inv-survol)}
.recap small{font-weight:400;color:var(--inv-ink2);display:block;font-size:.78rem;text-wrap:pretty}
.recap-x{width:48px;display:grid;place-items:center;color:var(--inv-ink2);border-left:1px solid var(--inv-line)}
.recap-x svg{width:18px;height:18px}
.recap-x:hover{color:var(--inv-ink);background:var(--inv-survol)}
/* une fois écarté, le bandeau ne propose plus rien : il rassure, puis s'efface */
.recap.done .recap-x{display:none}
.recap.done .recap-go{pointer-events:none}

/* on désigne l'endroit où la sélection reste disponible */
.ping{position:relative}
.ping::before{content:"";position:absolute;inset:-6px -10px;border:1px solid var(--ink);
  animation:ping 1.1s ease-out 2}
.tabbar .ping::before{inset:2px 6px}
@keyframes ping{from{opacity:.9;transform:scale(.96)}to{opacity:0;transform:scale(1.06)}}

.foot{padding:2.5rem 1rem calc(5rem + env(safe-area-inset-bottom));color:var(--ink2);font-size:.8rem;line-height:1.6;
  border-top:1px solid var(--line);margin:3rem 1rem 0}
.foot p{margin:0 0 .4rem;max-width:44ch;text-wrap:pretty}
.foot a{border-bottom:1px solid var(--line);display:inline-block;padding-block:.25rem}
.foot a:hover{color:var(--ink)}

/* ---------- tabbar ---------- */
.tabbar{position:fixed;left:0;right:0;bottom:0;z-index:40;display:grid;grid-template-columns:repeat(4,1fr);
  background:var(--voile);backdrop-filter:blur(12px);border-top:1px solid var(--line);
  padding-bottom:env(safe-area-inset-bottom);font-size:.72rem}
/* Le libellé et son compte tiennent sur une ligne : à 320 px, « Sélection 3 »
   se coupait en deux et décalait toute la barre. Il y a la place, à condition
   de ne pas laisser le compte être rejeté. */
.tabbar a{padding:1rem .3rem;text-align:center;color:var(--ink2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tabbar a.on{color:var(--ink)}
.count{display:inline-grid;place-items:center;min-width:16px;height:16px;padding:0 4px;
  background:var(--inv-bg);color:var(--inv-ink);border-radius:8px;font-size:.65rem;margin-left:.2rem;
  vertical-align:1px;flex:none}
/* En dessous de 360 px, le mot se réduit plutôt que de pousser le compte à la
   ligne : mieux vaut un libellé un peu serré qu'une barre qui saute. */
@media (max-width:360px){
  .tabbar{font-size:.68rem}
  .tabbar a{padding-inline:.15rem}
}

/* ---------- sheet ---------- */
.sheet{position:fixed;inset:0;z-index:60}
.sheet-bg{position:absolute;inset:0;background:rgba(0,0,0,.72)}
.sheet-panel{position:absolute;left:0;right:0;bottom:0;max-height:88vh;overflow:auto;
  background:var(--bg);border-top:1px solid var(--line);padding:1.25rem 1rem calc(2rem + env(safe-area-inset-bottom));
  animation:rise .35s cubic-bezier(.2,.8,.2,1)}
@keyframes rise{from{transform:translateY(100%)}}
.sheet-x{position:sticky;top:0;float:right;font-size:.8rem;color:var(--ink2)}
.sheet h2{margin:0 0 .25rem;font-family:var(--serif);font-weight:300;font-size:1.5rem}
.sheet .sub{color:var(--ink2);margin:0;font-size:.9rem;text-wrap:pretty}

@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important}}

/* ---------- desktop ---------- */
@media (min-width:900px){
  body{font-size:16px}
  .tabbar,.topbar,.foot{display:none}
  .theme{top:.9rem;right:1rem}
  .arrow{display:grid}
  /* Même raison que l'ambiance : 100lvh plutôt que bottom:0, sinon le bas
     du rail se coupait pendant que la barre d'adresse se repliait. La marge
     basse en reprend l'écart, pour que son pied ne finisse pas sous la barre
     quand elle est affichée. */
  .rail{display:block;position:fixed;left:0;top:0;height:100vh;height:100lvh;width:var(--rail);
    padding:2.5rem 2rem;padding:2.5rem 2rem calc(2.5rem + 100lvh - 100svh);
    border-right:1px solid var(--line)}
  .rail-in{display:flex;flex-direction:column;height:100%}
  main{margin-left:var(--rail);padding:3rem 2.5rem 6rem;max-width:calc(var(--rail) + 560px)}
  .hero,.serie-head,.bar,.cap,.page{padding-left:0;padding-right:0}
  /* La colonne de texte est plus large sur grand écran : les bornes serrées
     du mobile y coupaient les accroches trop tôt. */
  .hero h1{max-width:36ch}
  .hero .lede{max-width:52ch}
  .hero p{max-width:56ch}
  .page .btn{width:max-content;padding:.85rem 1.7rem}
  .univers{grid-template-columns:1fr 1fr}
  .flashs{grid-template-columns:1fr 1fr}
  .u{aspect-ratio:4/3}
  .hero{padding-top:0}
  .page{padding-top:0}
  /* La photo prend une part de la hauteur visible, sans dépasser ce qui reste
     sous le titre de la série et au-dessus de sa barre : sur un écran peu
     haut, 74 % de la fenêtre plus ces deux lignes passaient sous le bord, et
     la photo se lisait coupée. svh suit la barre d'adresse d'une tablette. */
  .frame{aspect-ratio:auto;height:min(74vh,820px);height:max(10rem,min(74svh,100svh - 8rem,820px))}
  .strip{gap:0}
  .recap{left:var(--rail);bottom:0;padding:1rem 2.5rem}
  .toast{left:calc(var(--rail) + (100vw - var(--rail)) / 2);bottom:5.5rem}
  .sheet-panel{left:auto;right:0;top:0;bottom:0;width:min(460px,100%);max-height:none;
    border-left:1px solid var(--line);border-top:0;animation:slide .35s cubic-bezier(.2,.8,.2,1)}
  @keyframes slide{from{transform:translateX(100%)}}
}

/* Le champ piège du formulaire : invisible à l'écran, mais bien présent pour
   un robot qui remplit tout ce qu'il trouve. On le sort de l'écran plutôt que
   de l'effacer : un display:none est détecté, et une personne au lecteur
   d'écran ne doit pas l'entendre non plus, d'où l'aria-hidden côté HTML. */
.trap{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ---------- tutoriel de première visite ---------- */
/* Il se pose sur le premier carrousel, pas au milieu de l'écran : les flèches
   doivent désigner la piste et le cœur, sinon elles n'expliquent rien. */
.serie{position:relative}
.tuto{position:absolute;inset:0;z-index:5;display:grid;place-items:center;
  color:#fff;text-align:center;animation:tuto-entre .4s ease both}
.tuto-voile{position:absolute;inset:0;background:rgba(0,0,0,.66)}
.tuto p{position:relative;margin:0;font-family:var(--sans);font-size:.95rem;line-height:1.45}
.tuto svg{position:relative;display:block;margin:0 auto;color:#fff}

.tuto-glisse{position:relative;display:grid;gap:.6rem;justify-items:center}
.tuto-glisse svg{width:72px;height:28px;animation:tuto-glisse 1.8s ease-in-out infinite}

/* Le cœur vit dans la barre sous l'image. La flèche le désigne sans sortir
   du cadre : dehors, elle est blanche sur fond clair, donc invisible. Elle
   s'arrête au bord et pointe vers le bas, ce qui suffit à le montrer. */
.tuto .tuto-coeur{position:absolute;left:1.25rem;bottom:7.5rem;margin:0;text-align:left}
.tuto .tuto-fleche{position:absolute;left:1rem;bottom:.5rem;margin:0;
  width:120px;height:96px;color:#fff;pointer-events:none}

.tuto-ok{position:absolute;top:.75rem;right:.75rem;z-index:1;width:auto;margin:0;
  padding:.45rem .9rem;font-size:.8rem;background:rgba(0,0,0,.55);color:#fff;border-color:rgba(255,255,255,.5)}
.tuto-ok:hover{background:rgba(0,0,0,.8)}

@keyframes tuto-glisse{
  0%,100%{transform:translateX(-10px)}
  50%{transform:translateX(10px)}
}
@keyframes tuto-entre{from{opacity:0}to{opacity:1}}

@media (prefers-reduced-motion:reduce){
  .tuto,.tuto-glisse svg{animation:none}
}

/* Sur un écran étroit, le cadre est moins haut : le repère se resserre pour
   ne pas chevaucher le texte du geste de glissement, au centre. */
@media (max-width:480px){
  .tuto .tuto-coeur{left:1rem;bottom:6.5rem;font-size:.88rem}
  /* La pointe doit tomber sur le cœur, à 27 px du bord : 1 rem de décalage
     plus la pointe du dessin, qui n'est pas au bord de sa boîte. */
  .tuto .tuto-fleche{left:1.15rem;bottom:.25rem;width:96px;height:76px}
}

@media (min-width:900px){
  .tuto p{font-size:1.05rem}
  .tuto-glisse svg{width:96px}
}

/* ---------- les trois façons de me joindre ---------- */
.contacts{display:flex;flex-wrap:wrap;gap:.5rem;margin:1.6rem 0 0;padding:0;list-style:none}
.contacts a{display:inline-flex;align-items:center;gap:.5rem;padding:.6rem .95rem;
  border:1px solid var(--line);color:var(--ink3);font-family:var(--sans);font-size:.9rem;
  text-decoration:none;transition:border-color .2s ease,color .2s ease}
.contacts a:hover,.contacts a:focus-visible{border-color:var(--ink3);color:var(--ink)}
.contacts svg{width:19px;height:19px;flex:none}

/* ---------- avis clients ---------- */
.avis{margin-top:2.5rem;padding-top:2rem;border-top:1px solid var(--line)}
/* Pas d'accrochage ici : il lutterait contre le défilement continu et
   ramènerait la bande sur une carte à chaque image. */
/* La bande d'avis ne défile pas : elle se déplace. Le défilement natif
   arrondit sa position au pixel entier, et à trente pixels par seconde cela
   donne un pas toutes les deux images au lieu d'un mouvement. Une
   transformation accepte le sous-pixel et se joue hors du fil principal. */
.avis .strip{display:block;overflow:hidden;scroll-snap-type:none;cursor:grab;touch-action:pan-y}
.avis .strip.tenue{cursor:grabbing}
.avis .piste{display:flex;gap:2px;will-change:transform}
/* margin:0 : un <figure> porte une marge de 1em 40px du navigateur. */
.avis figure{flex:0 0 min(86%,22rem);margin:0;padding:1.25rem 1rem;background:var(--surface)}
.avis .etoiles{margin:0;font-family:var(--sans);font-size:.85rem;letter-spacing:.08em;color:var(--ink2)}
.avis blockquote{margin:.75rem 0 0;font-family:var(--serif);font-weight:300;font-size:1.05rem;
  line-height:1.5;color:var(--ink);text-wrap:pretty}
.avis figcaption{margin-top:.9rem;font-size:.8rem;color:var(--ink2)}
.avis-liens{display:flex;flex-wrap:wrap;gap:.5rem 1.5rem;margin:1rem 0 0;padding:0 1rem;font-size:.85rem}
.avis-liens a{color:var(--ink2)}

/* Lu par les lecteurs d'écran, invisible à l'œil. */
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* Le message d'erreur du formulaire : lisible sans être criard, et sans
   couleur d'accent, qui n'existe pas dans ce site. */
.note.erreur{margin-top:.9rem;padding:.7rem .9rem;border-left:2px solid var(--alerte);color:var(--ink)}

/* ---------- ambiance : la photo regardée éclaire la pièce ---------- */
/* Le site est achromatique, sa seule couleur vient des images. Autant la
   laisser déborder du cadre : la photo au centre du regard est reprise en
   très grand, très floue, derrière la page et derrière le rail. Le masque
   garde le centre calme, là où se lisent les textes : la lumière vient des
   bords, elle n'entre jamais dans une ligne de texte. */
/* Sur un téléphone la photo occupe toute la largeur : il ne reste que le haut
   et le bas pour recevoir la lueur. Le masque les éclaire et laisse la bande
   centrale, celle qu'on lit, tranquille. */
/* 100lvh, la plus grande hauteur que l'écran puisse prendre, et non le bas
   de la fenêtre : sur téléphone, quand la barre d'adresse se replie sous le
   doigt, la fenêtre grandit mais un calque fixe n'est redimensionné qu'au
   lâcher. Son bas découvrait alors une bande du fond de page. */
.ambiance{position:fixed;top:0;left:0;right:0;height:100vh;height:100lvh;z-index:-1;pointer-events:none;overflow:hidden;contain:strict;
  opacity:.55;
  -webkit-mask-image:linear-gradient(to bottom,#000,transparent 34%,transparent 66%,#000);
  mask-image:linear-gradient(to bottom,#000,transparent 34%,transparent 66%,#000)}
:root[data-theme="clair"] .ambiance{opacity:.34}
/* max-width:none : la règle globale img{max-width:100%} ramènerait le calque
   dans le cadre et laisserait les bords de l'écran nus. */
/* Flouter un calque plein écran coûte cher à chaque image rendue. On floute
   donc une vignette : le calque ne fait que 8 % de l'écran, son flou de 6 px
   y équivaut à 90 px, et c'est l'agrandissement au facteur 15 qui le porte à
   l'écran. 8 % × 15 = 120 % de la fenêtre, décalés de -10 % pour que les
   bords ne se voient jamais. Identique à l'œil, deux cents fois moins de
   surface à flouter. */
.ambiance img{position:absolute;top:0;left:0;width:8%;height:8%;max-width:none;object-fit:cover;
  transform-origin:0 0;transform:scale(15) translate(-8.33%,-8.33%);
  filter:blur(6px) saturate(190%);
  opacity:0;transition:opacity 1.1s ease}

@media (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:view()){
    /* Chaque bloc se pose en arrivant par le bas. Rien de tout cela ne dépend
       de JavaScript : le navigateur lie l'animation au défilement lui-même,
       donc elle suit le doigt au lieu de se jouer en différé. */
    .serie,.u,.flash,.bio-court,.avis,.offer,.contacts{
      animation:arrive linear both;animation-duration:auto;
      animation-timeline:view();animation-range:entry 0% entry 45%}
    /* Le voile ne descend jamais jusqu'à zéro : un bloc entièrement
       transparent est un bloc absent, pour un lecteur d'écran comme pour un
       navigateur qui n'aurait pas encore joué l'animation. Le mouvement
       suffit à faire l'entrée. */
    @keyframes arrive{from{opacity:.25;transform:translateY(30px)}}
    /* Le titre et la légende traversent le cadre un peu plus lentement que
       lui : la photo tient en place, le texte glisse autour. Onze pixels,
       pas davantage : au-delà, le décalage se remarque plus que la photo. */
    .serie-head,.cap{
      animation:glisse linear both;animation-duration:auto;
      animation-timeline:view();animation-range:cover}
    @keyframes glisse{from{transform:translateY(11px)}to{transform:translateY(-11px)}}
  }
}

@media (min-width:900px){
  /* Sur grand écran la colonne d'images est étroite : la lueur peut venir de
     tout le pourtour, rail compris, et contourner la colonne de texte. */
  .ambiance{-webkit-mask-image:radial-gradient(120% 78% at 50% 44%,transparent 26%,#000 100%);
    mask-image:radial-gradient(120% 78% at 50% 44%,transparent 26%,#000 100%)}
}

/* Le fond de page revient à <html> : celui de <body> est peint après les
   calques d'arrière-plan et masquerait la lueur entièrement. */
body{background:none}

/* ---------- barre de défilement ---------- */
/* Elle suit le thème toute seule : ses couleurs sont les jetons du site, qui
   changent avec lui. Pas d'angle arrondi, rien n'en a ailleurs.

   Les pistes des carrousels gardent la leur masquée : leur règle est plus
   spécifique et l'emporte sur celles-ci. */
html{scrollbar-width:thin;scrollbar-color:var(--poignee) var(--bg)}

::-webkit-scrollbar{width:11px;height:11px}
::-webkit-scrollbar-track{background:var(--bg)}
::-webkit-scrollbar-thumb{background:var(--poignee);border:3px solid var(--bg)}
::-webkit-scrollbar-thumb:hover{background:var(--ink3)}
::-webkit-scrollbar-corner{background:var(--bg)}

/* Fil d'Ariane des sous-sections. Discret : il sert à remonter, pas à être lu. */
.fil{display:flex;gap:.5rem;align-items:baseline;padding:1rem 1rem 0;
  font-family:var(--sans);font-size:.82rem;color:var(--ink2)}
.fil a{color:var(--ink2);text-decoration:none;border-bottom:1px solid var(--line)}
.fil a:hover{color:var(--ink)}
.fil span[aria-current]{color:var(--ink)}
@media (min-width:900px){.fil{padding-left:0}}

/* ---------- entre le téléphone et le bureau ---------- */
/* De 600 à 899 px, une tablette tenue droite ou une fenêtre étroite : trop
   large pour les règles du téléphone appliquées telles quelles, trop étroit
   pour le rail. La colonne restait collée à gauche, la barre du bas écartait
   ses quatre entrées sur toute la largeur, et une photo en 4/5 faisait 800 px
   de haut. C'est la disposition du téléphone à qui l'on donne de la place :
   une seule colonne, centrée, et les barres qui s'alignent dessus. */
@media (min-width:600px) and (max-width:899px){
  :root{--colonne:640px}
  main{max-width:var(--colonne);margin-inline:auto}
  /* Les barres gardent leur fond pleine largeur, leur contenu suit la colonne. */
  .topbar,.tabbar,.recap{padding-inline:max(1rem,calc((100% - var(--colonne)) / 2 + 1rem))}
  .tabbar{grid-template-columns:repeat(4,1fr)}
  .toast{bottom:calc(6.5rem + env(safe-area-inset-bottom))}
  /* La photo prend une hauteur d'écran, pas une largeur de colonne. */
  .frame{aspect-ratio:auto;height:min(72vh,800px);height:max(10rem,min(72svh,100svh - 12rem,800px))}
  .univers,.flashs{grid-template-columns:1fr 1fr}
  .u{aspect-ratio:4/3}
  .foot{margin-inline:1rem}
}

/* ---------- téléphone à l'horizontale ---------- */
/* Assez large pour la disposition de bureau, deux fois trop court pour elle :
   sur 412 px de haut, le rail en faisait 655, et tout son bas, le menu et la
   sélection compris, était hors d'atteinte. Rien n'indiquait qu'il manquait
   quelque chose, et rien ne permettait d'y accéder.

   On garde le rail, qui tient l'identité, mais allégé : la bio se lit sur
   « Qui suis-je », et ce qui reste doit tenir. Il défile s'il le faut. */
@media (min-width:900px) and (max-height:600px){
  /* Le rail fait la plus grande hauteur d'écran : quand la barre d'adresse
     est affichée, son bas passe dessous. Le surplus en marge basse garde la
     fin du menu atteignable. */
  .rail{padding:1.1rem 1.5rem;padding:1.1rem 1.5rem calc(1.1rem + 100lvh - 100svh);overflow-y:auto;overscroll-behavior:contain}
  .rail .wordmark img{width:150px}
  .rail-line{display:none}
  .nav{margin-top:1.1rem;gap:.1rem;font-size:.9rem}
  .nav-sep{margin:.4rem 0}
  .rail-foot{margin-top:.9rem;line-height:1.5}
  main{padding:1.2rem 2rem 3rem}
  .hero{padding-bottom:.5rem}

  /* La photo prend la hauteur qui reste, sans quoi il faut faire défiler
     pour voir une seule image. */
  .frame{height:min(78vh,820px);height:max(10rem,min(100svh - 6.5rem,820px))}

  /* Les bulles du tutoriel étaient posées pour un écran haut : elles se
     chevauchaient ici, et la phrase du bas passait sous celle du milieu. */
  .tuto .tuto-coeur{top:.75rem;bottom:auto;left:1rem;max-width:14rem}
  .tuto .tuto-fleche{display:none}
  .toast{bottom:3.5rem}
}

/* Sans logo, le nom tient la place. Même famille que la voix du photographe,
   pour que la marque reste une signature et non une étiquette d'interface. */
.wordmark-nom{display:block;font-family:var(--serif);font-weight:300;
  font-size:1.5rem;line-height:1.15;letter-spacing:.01em;color:var(--ink)}
.topbar .wordmark-nom{font-size:1.15rem}

/* Sur une page de texte légal, un sous-titre doit se lire comme subordonné :
   sans règle, il héritait du navigateur et passait au-dessus de son titre. */
.page h3{font-family:var(--sans);font-size:.85rem;font-weight:500;
  color:var(--ink2);margin:1.2rem 0 .3rem}

/* Bandeau de prévisualisation. Visible seulement pour qui est connecté au
   back office : il dit que la page n'est pas en ligne, pour qu'on ne la
   partage pas en croyant le contraire. */
.apercu{position:sticky;top:0;z-index:60;margin:0;padding:.55rem 1rem;
  font-family:var(--sans);font-size:.8rem;text-align:center;
  background:#facc15;color:#000}

/* Le bouton de thème porte trois icônes, une par état : le rond partagé pour
   « celui de la page », le soleil pour le clair, la lune pour le sombre. Une
   seule est montrée à la fois, celle de l'état courant. */
.theme svg{display:none}
.theme[data-mode="auto"] .theme-auto,
.theme[data-mode="clair"] .theme-clair,
.theme[data-mode="sombre"] .theme-sombre{display:block}

/* ---------- rail replié, écrans moyens ---------- */
/* Entre 900 et 1279 px, le rail gardait 300 px et laissait aux photos une
   colonne étroite, collée à gauche. Il se replie en un bandeau fin ; son
   bouton le déplie, et il reprend alors sa place en poussant la page, comme
   sur grand écran. Le choix se garde d'une page à l'autre (data-rail sur
   <html>, posé avant l'affichage). Au-delà, la place suffit aux deux. */
@media (min-width:900px) and (max-width:1279px){
  :root{--rail-mini:64px}
  .rail{width:var(--rail-mini);padding:0;overflow:visible;z-index:45;background:var(--bg);transition:width .25s ease}
  /* Le bouton glisse avec le rail, à la même vitesse : il sautait d'un coin
     à l'autre pendant que le rail s'ouvrait. */
  .rail-bouton{display:grid;place-items:center;position:absolute;top:.9rem;left:10px;z-index:1;
    width:44px;height:44px;color:var(--ink2);transition:transform .25s ease}
  .rail-bouton:hover{color:var(--ink)}
  .rail-bouton svg{width:24px;height:24px}
  .rail-bouton .icone-plein{opacity:0;transition:opacity .25s}
  .rail-in{position:absolute;top:0;left:0;width:var(--rail);height:100%;
    padding:2.5rem 2rem;padding:2.5rem 2rem calc(2.5rem + 100lvh - 100svh);overflow-y:auto;
    visibility:hidden;transform:translateX(-100%);transition:transform .25s ease,visibility .25s}
  /* Quand la hauteur manque, margin-top:auto tombe à zéro et le menu collait
     à la présentation. */
  .rail-in .nav{padding-top:1.4rem}
  main{margin-left:var(--rail-mini);max-width:none;
    padding-inline:max(2.5rem,calc((100vw - var(--rail-mini) - 780px) / 2));
    transition:margin-left .25s ease,padding .25s ease}

  :root[data-rail="ouvert"] .rail{width:var(--rail)}
  :root[data-rail="ouvert"] .rail-in{visibility:visible;transform:none}
  :root[data-rail="ouvert"] .rail-bouton{transform:translateX(calc(var(--rail) - 62px))}
  :root[data-rail="ouvert"] .rail-bouton .icone-plein{opacity:.35}
  :root[data-rail="ouvert"] main{margin-left:var(--rail);
    padding-inline:max(2.5rem,calc((100vw - var(--rail) - 780px) / 2))}
}
