/* =============================================================
   Galerie client — surface sombre, même grammaire que le portfolio
   ============================================================= */

/* --bg et non --ink-0 : sur une galerie en thème clair, la surface change
   mais la classe posée par le serveur, elle, reste la même. */
body.surface-dark, body.surface-paper { background: var(--bg); color: var(--fg); }
body.is-cover-page { overflow: hidden; }

/* =============================================================
   Page d'accès (code client)
   ============================================================= */
.access { min-height: 100svh; display: grid; place-items: center; padding: 24px; }
.access-inner {
  width: 100%; max-width: 420px;
  animation: panelIn 620ms var(--ease-out) both;
}
.access-inner .display { margin: 18px 0 26px; }
.access-text { color: var(--fg-2); font-size: var(--text-sm); line-height: 1.75; margin-bottom: 34px; }
.access-code { font-family: var(--font-mono); font-size: 15px; letter-spacing: .04em; }
.access-back { margin-top: 40px; }

/* =============================================================
   Couverture de galerie
   ============================================================= */
.cover { position: relative; min-height: 100svh; display: flex; flex-direction: column; overflow: hidden; }
.cover-bg {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  transform: scale(1.06);
  animation: coverZoom 14s var(--ease-out) both;
}
@keyframes coverZoom { from { transform: scale(1.14); opacity: 0; } to { transform: scale(1.06); opacity: 1; } }
.cover-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to bottom, rgba(8,11,12,.62) 0%, rgba(8,11,12,.28) 34%, rgba(8,11,12,.86) 100%),
    rgba(8,11,12,.18);
}

.cover-top, .cover-inner, .cover-foot {
  position: relative; z-index: 2;
  /* Sans width:100%, les marges automatiques de .wrap annulent l'étirement flex. */
  width: 100%;
}
.cover-top {
  display: flex; align-items: center; justify-content: space-between;
  padding-top: max(clamp(18px, 2.4vw, 30px), var(--sat));
  padding-bottom: clamp(18px, 2.4vw, 30px);
  animation: fadeIn 700ms 120ms var(--ease-out) both;
}
.cover-brand {
  font-family: var(--font-display); font-weight: 600; font-size: var(--text-md);
  letter-spacing: -.01em; color: #fff;
}
.cover-site {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255,255,255,.55); text-decoration: none;
}
.cover-site:hover { color: #fff; }
.cover-top-right { display: flex; align-items: center; gap: clamp(16px, 2.5vw, 32px); }

/* ---- Bascule FR / EN, reprise du portfolio ---- */
.lang-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em;
}
.lang-btn {
  color: inherit; text-decoration: none;
  padding: 4px 6px; min-height: 32px;
  display: inline-flex; align-items: center;
  opacity: .35;
  transition: opacity 200ms var(--ease-out);
}
.lang-btn.active { opacity: 1; }
@media (hover: hover) { .lang-btn:not(.active):hover { opacity: .7; } }
.lang-sep { opacity: .2; }

.cover-inner {
  flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
  padding-bottom: clamp(40px, 8vh, 90px);
}
.cover-kicker, .cover-title, .cover-welcome { max-width: 15ch; }
.cover-title { max-width: 14ch; }
.cover-welcome { max-width: 46ch; }
.cover-kicker { color: rgba(255,255,255,.62); max-width: none; animation: panelIn 620ms 160ms var(--ease-out) both; }
.cover-title {
  color: #fff; margin: clamp(18px, 3vh, 30px) 0;
  animation: panelIn 700ms 260ms var(--ease-out) both;
}
.cover-welcome {
  color: rgba(255,255,255,.72); font-size: clamp(15px, 1.4vw, 18px);
  line-height: 1.75; max-width: 52ch; margin-bottom: clamp(28px, 5vh, 44px);
  animation: panelIn 700ms 340ms var(--ease-out) both;
}
.cover-form { width: min(100%, 320px); animation: panelIn 700ms 420ms var(--ease-out) both; }
.cover-enter { animation: panelIn 700ms 420ms var(--ease-out) both; }
.cover-form .field-input { color: #fff; border-bottom-color: rgba(255,255,255,.28); }
.cover-form .btn-solid { width: 100%; }
.cover-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  flex-wrap: wrap;
  padding-bottom: max(clamp(18px, 3vh, 30px), var(--sab));
  color: rgba(255,255,255,.4);
  animation: fadeIn 800ms 600ms var(--ease-out) both;
}

/* =============================================================
   Barre flottante de l'album
   ============================================================= */
.gal-top {
  position: sticky; top: 0; z-index: 70;
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  backdrop-filter: saturate(180%) blur(16px);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--hairline);
}
.gal-top-inner {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding-top: max(14px, var(--sat)); padding-bottom: 14px;
  min-height: 60px;
}
/* Un titre qui ne génère aucune boîte : présent pour les lecteurs d'écran,
   invisible pour la mise en page, qui continue de traiter .gal-brand. */
.gal-heading { display: contents; font: inherit; margin: 0; }

.gal-brand {
  display: flex; align-items: baseline; gap: 12px; min-width: 0;
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(15px, 1.6vw, 19px); letter-spacing: -.015em;
  color: var(--fg); text-decoration: none;
}
/* Le nom du client se lit, il ne se devine pas : --fg-3 tombait à 2,49 de
   contraste sur la surface claire, sous le minimum lisible. */
.gal-brand .role {
  font-family: var(--font-mono); font-size: 11px; font-weight: 400;
  letter-spacing: .08em; color: var(--fg-2); white-space: nowrap;
}
.gal-actions { display: flex; align-items: center; gap: clamp(12px, 2vw, 26px); flex: none; }
.gal-action {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--fg-2); text-decoration: none;
  background: none; border: none; cursor: pointer;
  padding: 8px 0; display: inline-flex; align-items: center; gap: 7px;
  border-bottom: 1px solid transparent;
  transition: color var(--dur-micro) var(--ease-out), border-color var(--dur-micro) var(--ease-out);
  white-space: nowrap;
}
.gal-action:hover, .gal-action.is-active { color: var(--fg); border-bottom-color: var(--fg-3); }
.gal-badge {
  font-size: 10px; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: var(--radius-pill); background: var(--fg-4); color: var(--fg);
  display: inline-flex; align-items: center; justify-content: center;
}

.gal-folders {
  display: flex; gap: 8px; overflow-x: auto; padding-bottom: 12px;
  scrollbar-width: none;
}
.gal-folders::-webkit-scrollbar { display: none; }
/* Même remarque que pour .cta : les pastilles sont des <button>, il faut
   leur retirer la boîte grise du navigateur avant de poser la nôtre. */
.gal-folder {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-2); text-decoration: none; white-space: nowrap;
  appearance: none; -webkit-appearance: none;
  background: none;
  cursor: pointer;
  padding: 8px 14px; border: 1px solid var(--hairline); border-radius: var(--radius-pill);
  transition: all var(--dur-micro) var(--ease-out);
}
.gal-folder span { opacity: .45; margin-left: 5px; }
.gal-folder:hover { color: var(--fg); border-color: var(--fg-3); }
.gal-folder.is-active { background: var(--btn-bg); color: var(--btn-fg); border-color: transparent; }
.gal-folder.is-active span { opacity: .55; }



/* =============================================================
   Contenu
   ============================================================= */
.gal-main { padding-bottom: clamp(60px, 10vh, 120px); }
/* padding-block, jamais le raccourci « padding » : il écraserait les marges
   latérales de .wrap et le contenu viendrait coller au bord de l'écran. */
.gal-intro { padding-block: clamp(34px, 6vh, 64px) clamp(18px, 3vh, 30px); }
.gal-intro .display-sm { margin: 14px 0 0; }
.gal-intro-actions { display: flex; gap: 24px; flex-wrap: wrap; margin-top: 26px; }
.gal-empty { padding-block: clamp(60px, 16vh, 160px); text-align: center; }
.gal-empty .lead { margin: 18px auto 28px; max-width: 44ch; color: var(--fg-2); }
.gal-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  flex-wrap: wrap; margin-top: clamp(48px, 8vh, 90px);
  padding-top: 24px; border-top: 1px solid var(--hairline);
  color: var(--fg-3);
}
/* Un lien de pied de page reste un lien qu'on touche : sans hauteur propre,
   il ne faisait que la hauteur de sa ligne, 16 px, impossible à viser au doigt. */
.gal-foot a {
  color: inherit;
  display: inline-flex; align-items: center;
  min-height: 24px;
}

/* =============================================================
   Grille justifiée
   ============================================================= */
.grid {
  display: flex; flex-wrap: wrap;
  gap: var(--grid-gap, 8px);
  padding: clamp(16px, 2.4vw, 30px) clamp(10px, 1.6vw, 22px) 0;
  align-content: flex-start;
}
/* Repli avant l'entrée en scène du JavaScript */
.grid:not(.is-justified) .cell {
  flex: 1 1 clamp(160px, 22vw, 320px);
  aspect-ratio: var(--ar, 1.5);
}

.cell {
  position: relative; margin: 0; overflow: hidden;
  background: var(--bg-2); border-radius: 2px;
  opacity: 0; animation: fadeIn 520ms var(--ease-out) forwards;
}
.grid.is-justified .cell { flex: 0 0 auto; }
.cell-open {
  display: block; width: 100%; height: 100%;
  padding: 0; border: none; background: none; cursor: zoom-in;
}
.cell-img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 620ms var(--ease-out), opacity 400ms var(--ease-out);
  -webkit-user-drag: none; user-select: none;
}
@media (hover: hover) {
  .cell:hover .cell-img { transform: scale(1.035); }
}

.cell-play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center; pointer-events: none;
  background: rgba(10,13,14,.42); color: #fff;
  border: 1px solid rgba(255,255,255,.5);
  backdrop-filter: blur(3px);
}

.cell-fav {
  position: absolute; right: 8px; bottom: 8px;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: rgba(10,13,14,.35); border: none;
  color: rgba(255,255,255,.85);
  opacity: 0; transform: translateY(4px);
  transition: opacity var(--dur-micro) var(--ease-out),
              transform var(--dur-micro) var(--ease-out),
              color var(--dur-micro) var(--ease-out);
  backdrop-filter: blur(6px);
}
.cell-fav svg { fill: none; stroke: currentColor; stroke-width: 1.6; }
.cell-fav.is-on { opacity: 1; transform: none; color: #fff; }
.cell-fav.is-on svg { fill: #fff; stroke: #fff; }
.cell:hover .cell-fav, .cell-fav:focus-visible { opacity: 1; transform: none; }
@media (hover: none) { .cell-fav { opacity: .9; transform: none; } }

/* =============================================================
   Visionneuse
   ============================================================= */
/* La visionneuse reste sombre même sur une galerie en thème clair : une
   photographie se regarde sur du noir, pas sur du papier. C'est délibéré, et
   tokens.css lui donne le jeu de jetons sombre en propre (voir .surface-dark). */
.lb {
  position: fixed; inset: 0; z-index: 120;
  background: var(--bg);
  display: flex; flex-direction: column;
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-ui) var(--ease-out);
}
.lb.is-open { opacity: 1; pointer-events: auto; }

.lb-top {
  position: relative; z-index: 3;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: max(14px, var(--sat)) clamp(14px, 2.5vw, 28px) 14px;
}
.lb-meta {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .12em; color: rgba(255,255,255,.5);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-tools { display: flex; align-items: center; gap: 4px; flex: none; }
.lb-btn {
  width: 44px; height: 44px; display: grid; place-items: center;
  background: none; border: none; cursor: pointer;
  color: rgba(255,255,255,.62); border-radius: 50%;
  transition: color var(--dur-micro) var(--ease-out), background var(--dur-micro) var(--ease-out);
}
.lb-btn:hover { color: #fff; background: rgba(255,255,255,.08); }
.lb-btn svg { fill: none; stroke: currentColor; stroke-width: 1.6; }
.lb-btn.is-on { color: #fff; }
.lb-btn.is-on svg { fill: #fff; }

.lb-stage { flex: 1; position: relative; min-height: 0; }
/* Le porte-image est en position absolue : ainsi l’image ne peut jamais
   pousser la hauteur de la scène, quelle que soit sa définition. */
.lb-holder {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 0 clamp(10px, 5vw, 70px);
}
.lb-img {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
  opacity: 0; transition: opacity 300ms var(--ease-out);
  -webkit-user-drag: none; user-select: none;
}
.lb-img.is-loaded { opacity: 1; }
.lb-video { max-width: 100%; max-height: 100%; background: #000; }
.lb-holder .vp { width: 100%; height: 100%; }

.lb-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: none; border: none; cursor: pointer;
  color: rgba(255,255,255,.45); padding: 20px 14px;
  transition: color var(--dur-micro) var(--ease-out);
}
.lb-nav:hover { color: #fff; }
.lb-nav svg { fill: none; stroke: currentColor; stroke-width: 1.4; }
.lb-prev { left: clamp(2px, 1.2vw, 18px); }
.lb-next { right: clamp(2px, 1.2vw, 18px); }
.lb-nav[hidden] { display: none; }

.lb-foot {
  padding: 14px clamp(14px, 2.5vw, 28px) max(16px, var(--sab));
  display: flex; align-items: center; justify-content: center; gap: 18px;
}
.lb-counter {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em;
  color: rgba(255,255,255,.42);
}

/* Panneau de commentaires */
.lb-comments {
  position: absolute; right: 0; top: 0; bottom: 0; z-index: 4;
  width: min(92vw, 380px);
  background: var(--ink-1); border-left: 1px solid var(--hairline);
  transform: translateX(100%); transition: transform var(--dur-ui) var(--ease-in-out);
  display: flex; flex-direction: column;
  padding: max(20px, var(--sat)) 22px max(20px, var(--sab));
}
.lb.comments-open .lb-comments { transform: none; }
.lb-comments h3 {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--fg-3);
  margin-bottom: 18px;
}
.lb-comment-list { flex: 1; overflow-y: auto; margin: 0 0 18px; padding: 0; list-style: none; }
.lb-comment { padding: 12px 0; border-bottom: 1px solid var(--hairline); }
.lb-comment b { display: block; font-weight: 500; font-size: 13px; margin-bottom: 5px; }
.lb-comment time { font-family: var(--font-mono); font-size: 10px; color: var(--fg-3); }
.lb-comment p { font-size: 14px; line-height: 1.65; color: var(--fg-2); margin-top: 6px; }
.lb-comment-empty { color: var(--fg-3); font-size: 13px; line-height: 1.7; }
.lb-comment-form .field-input, .lb-comment-form .field-textarea { font-size: 14px; }

/* =============================================================
   Lecteur vidéo (reprise du player du portfolio)
   ============================================================= */
.vp { position: relative; width: 100%; height: 100%; display: grid; place-items: center; }
.vp-video { width: 100%; height: 100%; object-fit: contain; background: #000; }
.vp-play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 76px; height: 76px; border-radius: 50%;
  background: rgba(10,13,14,.4); border: 1px solid rgba(255,255,255,.55);
  color: #fff; cursor: pointer; display: grid; place-items: center;
  backdrop-filter: blur(4px);
  transition: opacity var(--dur-ui) var(--ease-out), transform var(--dur-ui) var(--ease-out);
}
.vp.is-playing .vp-play { opacity: 0; transform: translate(-50%, -50%) scale(.85); pointer-events: none; }

/* =============================================================
   Sélection : quota, listes, notes, validation
   ============================================================= */
.gal-badge.is-full { background: var(--btn-bg); color: var(--btn-fg); }

.sel-lists { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }

.sel-locked {
  margin-top: 24px; padding: 16px 20px;
  border: 1px solid var(--hairline); border-radius: var(--radius-md);
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--fg);
  max-width: 60ch;
}
.sel-locked-note {
  display: block; margin-top: 8px;
  font-family: var(--font-body); font-size: 13px;
  letter-spacing: normal; text-transform: none; line-height: 1.6; color: var(--fg-2);
}

/* Pastille discrète sur les photos annotées */
.cell.has-note::after {
  content: ''; position: absolute; left: 8px; bottom: 8px;
  width: 7px; height: 7px; border-radius: 50%;
  background: #fff; opacity: .85;
  box-shadow: 0 0 0 3px rgba(10,13,14,.35);
}

/* Bloc « note pour le photographe » dans le panneau latéral */
.lb-note { padding-bottom: 20px; margin-bottom: 4px; border-bottom: 1px solid var(--hairline); }
.lb-note .field-textarea { min-height: 88px; font-size: 14px; }
.lb-note-save { width: 100%; }

/* Aperçu flouté : le fond de la cellule pendant que la vignette arrive */
.cell { background-size: cover; background-position: center; }
.cell-img { opacity: 0; transition: opacity 420ms var(--ease-out), transform 620ms var(--ease-out); }
.cell-img.is-shown, .cell-img[data-loaded] { opacity: 1; }

/* Sentinelle de chargement en bas de grille */
.grid-sentinel {
  display: flex; align-items: center; justify-content: center;
  padding: clamp(30px, 6vh, 60px) 0;
}

/* =============================================================
   Téléchargement en volumes
   ============================================================= */
.vol-page { padding-top: clamp(60px, 14vh, 130px); padding-bottom: clamp(60px, 12vh, 120px); max-width: 720px; }
.vol-page .display-sm { margin: 16px 0 18px; }
.vol-intro { color: var(--fg-2); font-size: var(--text-sm); line-height: 1.75; margin-bottom: clamp(30px, 5vh, 48px); }
.vol-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hairline); }
.vol-item { border-bottom: 1px solid var(--hairline); }
.vol-link {
  display: grid; grid-template-columns: 1fr auto 28px;
  gap: 18px; align-items: baseline;
  padding: 20px 0; text-decoration: none;
  transition: opacity var(--dur-micro) var(--ease-out);
}
.vol-link:hover { opacity: .6; }
.vol-name { font-family: var(--font-display); font-size: 19px; font-weight: 400; letter-spacing: -.015em; }
.vol-meta { font-family: var(--font-mono); font-size: 11px; letter-spacing: .08em; color: var(--fg-3); }
.vol-arrow { text-align: right; color: var(--fg-3); }
.vol-back { margin-top: clamp(32px, 6vh, 56px); }

/* =============================================================
   Zoom, diaporama, nouveautés, aide clavier
   ============================================================= */
.lb-img { transform-origin: center; will-change: transform; }
.lb.is-zoomed .lb-holder { cursor: grab; }
.lb.is-zoomed .lb-holder:active { cursor: grabbing; }
.lb.is-zoomed .lb-nav { opacity: 0; pointer-events: none; }

/* Pendant le diaporama, l'interface s'efface pour laisser la place aux images */
.lb.is-playing .lb-top,
.lb.is-playing .lb-nav,
.lb.is-playing .lb-foot { opacity: .12; transition: opacity 600ms var(--ease-out); }
.lb.is-playing:hover .lb-top,
.lb.is-playing:hover .lb-nav,
.lb.is-playing:hover .lb-foot { opacity: 1; }
.lb.is-playing [data-act="slideshow"] { color: #fff; }

/* Repère discret sur les médias jamais ouverts */
.cell.is-new::before {
  content: ''; position: absolute; top: 8px; left: 8px; z-index: 2;
  width: 7px; height: 7px; border-radius: 50%;
  background: #fff; box-shadow: 0 0 0 3px rgba(10,13,14,.35);
}

/* Aide clavier */
.help-panel {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(8,11,12,.86);
  display: grid; place-items: center; padding: 24px;
  animation: fadeIn 240ms var(--ease-out) both;
  backdrop-filter: blur(6px);
}
.help-inner {
  width: min(100%, 440px);
  background: var(--ink-1); border: 1px solid var(--hairline);
  border-radius: var(--radius-md); padding: clamp(24px, 4vw, 36px);
}
.help-inner h2 {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--fg-3);
  margin-bottom: 22px;
}
.help-inner dl {
  display: grid; grid-template-columns: 88px 1fr; gap: 12px 18px;
  margin: 0 0 26px; align-items: baseline;
}
.help-inner dt {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .08em;
  color: var(--fg); padding: 5px 9px; border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); text-align: center;
}
.help-inner dd { margin: 0; font-size: 14px; line-height: 1.5; color: var(--fg-2); }
.help-inner .btn { width: 100%; }

/* Filtre « nouvelles » : on masque ce qui a déjà été ouvert */
.grid.only-new .cell:not(.is-new) { display: none; }
.gal-action.is-active { color: var(--fg); border-bottom-color: var(--fg); }

/* Choix de la taille au téléchargement */
.lb-tools { position: relative; }
.lb-dl-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 5;
  background: var(--ink-1); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); overflow: hidden; min-width: 220px;
  animation: fadeIn 160ms var(--ease-out) both;
}
.lb-dl-menu a {
  display: block; padding: 12px 16px; text-decoration: none;
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-2);
  transition: background var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.lb-dl-menu a + a { border-top: 1px solid var(--hairline); }
.lb-dl-menu a:hover { background: var(--hover); color: var(--fg); }

/* =============================================================
   Filtres du client
   ============================================================= */
.gal-filters {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
  padding-bottom: 14px;
}
.gal-filters-label {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--fg-3); margin-right: 4px;
}
.gal-filters .gal-folder { cursor: pointer; }
.gal-filters .gal-folder.is-active { background: var(--btn-bg); color: var(--btn-fg); border-color: transparent; }
.gal-filters .gal-folder.is-active span { opacity: .55; }
.gal-filters-clear {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase;
  background: none; border: none; cursor: pointer;
  color: var(--fg-3); padding: 8px 4px;
  border-bottom: 1px solid transparent;
  transition: color var(--dur-micro) var(--ease-out), border-color var(--dur-micro) var(--ease-out);
}
.gal-filters-clear:hover { color: var(--fg); border-bottom-color: var(--fg-3); }

.gal-filter-empty {
  padding: clamp(50px, 12vh, 110px) clamp(20px, 3.4vw, 48px);
  text-align: center; color: var(--fg-2);
  font-size: clamp(15px, 1.4vw, 18px);
}



/* Séparateur entre dossiers et étiquettes dans la barre de filtres */
.gal-filters-sep {
  width: 1px; height: 20px; background: var(--hairline);
  margin: 0 6px; flex: none;
}
.gal-folder.is-tag { border-style: dashed; }
.gal-folder.is-tag.is-active { border-style: solid; }

/* =============================================================
   Performance : ce qui est hors écran ne coûte rien
   ============================================================= */

/* Le navigateur saute la mise en page et le dessin des cellules hors écran.
   Sur 800 photos, c'est le réglage qui compte le plus sur un téléphone.
   La taille annoncée évite que la barre de défilement saute. */
.grid .cell {
  content-visibility: auto;
  contain-intrinsic-size: auto 280px;
}

/* La visionneuse est le dernier enfant de <body> : on ne peut pas masquer
   la grille par un sélecteur de voisinage, et lui poser content-visibility
   casserait la transition de vue à l'ouverture. On s'en tient aux cellules. */

/* Bascule clair / sombre — même poids visuel que la bascule de langue. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  color: var(--fg-2); text-decoration: none;
  border-radius: var(--radius-pill);
  transition: color var(--dur-micro) var(--ease-out), background var(--dur-micro) var(--ease-out);
}
@media (hover: hover) { .theme-toggle:hover { color: var(--fg); background: var(--hover); } }

/* Durée d'une vidéo, lisible avant de cliquer : on sait si c'est un plan de
   quinze secondes ou le film complet. Même grammaire que les pastilles. */
.cell-duration {
  position: absolute; right: 8px; bottom: 8px;
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .06em; font-variant-numeric: tabular-nums;
  color: #fff; background: rgba(10,13,14,.62);
  padding: 3px 7px; border-radius: var(--radius-pill);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  pointer-events: none;
}

/* Croix de fermeture du panneau de commentaires. Le panneau glisse par-dessus
   le bouton de la barre : sans elle, on ne pouvait plus le refermer. */
.lb-comments-close {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  appearance: none; -webkit-appearance: none;
  background: none; border: 0; border-radius: var(--radius-pill);
  color: var(--fg-2); cursor: pointer;
  transition: color var(--dur-micro) var(--ease-out), background var(--dur-micro) var(--ease-out);
}
@media (hover: hover) {
  .lb-comments-close:hover { color: var(--fg); background: var(--hover); }
}

/* Bandeau d'aperçu administrateur — jamais vu par un client. Il doit trancher
   avec la galerie pour qu'on ne le confonde pas avec son contenu. */
.apercu-admin {
  position: relative; z-index: 200;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 10px clamp(14px, 3vw, 28px);
  background: #b4442f; color: #fff;
  font-size: 13px; line-height: 1.5;
}
.apercu-admin-etiquette {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 3px 9px; border-radius: var(--radius-pill);
  background: rgba(255,255,255,.18); white-space: nowrap;
}
.apercu-admin a { color: #fff; text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }

/* =============================================================
   ADAPTATIONS
   Toutes les surcharges de taille d'écran vivent ici, en fin de feuille :
   à spécificité égale c'est la dernière règle qui gagne, donc les placer
   après les styles de base est la seule façon fiable de les voir s'appliquer.
   ============================================================= */

/* En dessous de 700 px, le titre et les actions ne tiennent plus côte à côte :
   le titre garde sa ligne, les actions passent dessous et défilent
   horizontalement plutôt que de déborder ou de s'empiler sur trois rangs. */
@media (max-width: 700px) {
  .gal-top-inner { flex-wrap: wrap; gap: 6px 16px; padding-bottom: 6px; }
  .gal-brand .role { display: none; }

  /* Sept commandes et un nom de fichier ne tiennent pas sur un téléphone : le
     nom se réduisait à « IM… », ce qui n'apprend rien. Mieux vaut le taire,
     le compteur du bas situe déjà la photo. */
  .lb-meta { display: none; }
  .gal-brand {
    display: block; max-width: 100%;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .gal-actions {
    width: 100%;
    gap: 20px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 6px;
  }
  .gal-actions::-webkit-scrollbar { display: none; }
  .gal-action { font-size: 10px; letter-spacing: .1em; flex: none; }

  /* Les filtres défilent aussi : une ligne, pas trois. */
  .gal-filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 12px;
  }
  .gal-filters::-webkit-scrollbar { display: none; }
  .gal-filters > * { flex: none; }
  .gal-filters-label { width: auto; margin-bottom: 0; }

  /* Visionneuse : l'image occupe toute la largeur, les flèches se resserrent. */
  .lb-stage { padding: 0; }
  .lb-holder { padding: 0 8px; }
  .lb-nav { padding: 30px 6px; }
  .lb-comments { width: 100%; }
}

/* =============================================================
   Écrans tactiles — placé en fin de feuille pour surcharger les
   tailles définies plus haut, à spécificité égale.
   ============================================================= */
@media (pointer: coarse) {
  .gal-action,
  .gal-folder,
  .lang-btn,
  .gal-filters-clear { min-height: 44px; }

  .gal-brand { padding: 6px 0; }
  .gal-foot a { min-height: 44px; }
  .cell-fav { width: 42px; height: 42px; }
  .cell-play { width: 54px; height: 54px; }
  .lb-btn { width: 48px; height: 48px; }
  .lb-nav { padding: 34px 18px; }
  .cta { padding-top: 10px; padding-bottom: 8px; }

  /* Le survol n'existe pas au doigt : les commandes restent visibles. */
  .cell-fav { opacity: .92; transform: none; }
}

/* Téléphone en paysage : la hauteur est la ressource rare. On rend tout ce qui
   n'est pas l'image aussi mince que possible, sans rien retirer. */
@media (max-height: 520px) and (orientation: landscape) {
  .gal-top-inner { min-height: 0; padding-top: max(8px, var(--sat)); padding-bottom: 6px; }
  .gal-actions { padding-bottom: 2px; }
  .gal-filters { padding-bottom: 8px; }
  .gal-folder { padding-top: 6px; padding-bottom: 6px; }

  .lb-top { padding-top: max(6px, var(--sat)); padding-bottom: 6px; }
  .lb-foot { padding-top: 6px; padding-bottom: max(8px, var(--sab)); }
  .lb-btn { width: 40px; height: 40px; }
  .lb-nav { padding: 16px 10px; }

  .cover-inner { padding-bottom: 20px; }
  .cover-title { font-size: clamp(28px, 6vw, 44px); }
  .cover-welcome { display: none; }

  .gal-intro { padding-block: 20px 12px; }
}

/* =============================================================
   Robustesse visible : image en échec, bandeau hors ligne, éclat
   ============================================================= */

/* Une vignette qui n'a pas pu charger le dit, plutôt que de rester floue */
.cell.is-broken .cell-img { opacity: 0; }
.cell.is-broken::after {
  content: attr(data-broken);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 9px;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--fg-3);
  background: var(--bg-2);
}

/* Bandeau hors ligne : présent, discret, jamais bloquant */
.offline-banner {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(20px + var(--sab)); z-index: 210;
  max-width: min(92vw, 460px);
  padding: 12px 20px; border-radius: var(--radius-pill);
  background: var(--ink-1); color: var(--fg);
  border: 1px solid var(--hairline);
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .06em; text-align: center;
  animation: panelIn 320ms var(--ease-out) both;
}
.offline-banner.is-back { border-color: color-mix(in srgb, var(--success) 45%, transparent); }

/* Éclat au moment où une photo rejoint les favoris */
@keyframes coeurEclat {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.32); }
  60%  { transform: scale(.94); }
  100% { transform: scale(1); }
}
.cell-fav.is-burst svg,
.lb-btn.is-burst svg { animation: coeurEclat 520ms var(--ease-out); }
.cell-fav.is-burst::after {
  content: ''; position: absolute; inset: -6px;
  border-radius: 50%; border: 1.5px solid rgba(255,255,255,.55);
  animation: ringPulse 560ms var(--ease-out) forwards;
}
@keyframes ringPulse {
  from { transform: scale(.7); opacity: .8; }
  to   { transform: scale(1.5); opacity: 0; }
}

/* =============================================================
   Agréments : transition d'ouverture, fil, curseur
   ============================================================= */

/* L'image cliquée grandit jusqu'à sa place plein écran. */
::view-transition-old(photo-active),
::view-transition-new(photo-active) {
  animation-duration: 340ms;
  animation-timing-function: var(--ease-out);
  mix-blend-mode: normal;
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 220ms;
  animation-timing-function: var(--ease-out);
}

/* Fil de progression : un pixel qui dit où l'on en est dans l'album */
.gal-progress {
  position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; background: var(--fg);
  transform: scaleX(0); transform-origin: left;
  transition: transform 120ms linear;
  opacity: .55;
}

/* Curseur éditorial, sur pointeur fin uniquement */
.gal-cursor {
  position: fixed; top: 0; left: 0; z-index: 90;
  width: 62px; height: 62px; border-radius: 50%;
  display: grid; place-items: center;
  pointer-events: none;
  background: var(--btn-bg); color: var(--btn-fg);
  font-family: var(--font-mono); font-size: 9px;
  letter-spacing: .16em; text-transform: uppercase;
  opacity: 0; transform: translate(-50%, -50%) scale(.7);
  transition: opacity 180ms var(--ease-out), scale 220ms var(--ease-out);
}
.gal-cursor.is-on { opacity: 1; }
@media (pointer: fine) {
  .grid .cell-open { cursor: none; }
}

/* Sur pointeur fin, la vignette respire légèrement au survol */
@media (hover: hover) and (pointer: fine) {
  .cell { transition: filter 320ms var(--ease-out); }
  .grid:hover .cell:not(:hover) { filter: brightness(.82); }
}

/* =============================================================
   Lecteur vidéo — même grammaire que le reste
   ============================================================= */
.vp-controls {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; gap: 12px;
  padding: 14px clamp(12px, 2vw, 20px) max(14px, var(--sab));
  background: linear-gradient(to top, rgba(8,11,12,.82), transparent);
  opacity: 0; transform: translateY(6px);
  transition: opacity var(--dur-ui) var(--ease-out), transform var(--dur-ui) var(--ease-out);
}
.vp:not(.is-playing) .vp-controls,
.vp:hover .vp-controls,
.vp:focus-within .vp-controls { opacity: 1; transform: none; }

.vp-btn {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  background: none; border: none; cursor: pointer;
  color: rgba(255,255,255,.85); border-radius: 50%;
  transition: color var(--dur-micro) var(--ease-out), background var(--dur-micro) var(--ease-out);
}
.vp-btn:hover { color: #fff; background: rgba(255,255,255,.1); }
.vp-btn svg { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }

.vp-time {
  font-family: var(--font-mono); font-size: 11px;
  color: rgba(255,255,255,.8); flex: none; min-width: 38px;
}
.vp-total { text-align: right; }

.vp-bar {
  position: relative; flex: 1; height: 22px; cursor: pointer;
  display: flex; align-items: center;
}
.vp-bar::before {
  content: ''; position: absolute; left: 0; right: 0; height: 2px;
  background: rgba(255,255,255,.22); border-radius: 2px;
}
.vp-buffered, .vp-played {
  position: absolute; left: 0; height: 2px; border-radius: 2px; width: 0;
}
.vp-buffered { background: rgba(255,255,255,.38); }
.vp-played   { background: #fff; }
.vp-knob {
  position: absolute; top: 50%; left: 0;
  width: 10px; height: 10px; border-radius: 50%; background: #fff;
  transform: translate(-50%, -50%) scale(0);
  transition: transform var(--dur-micro) var(--ease-out);
}
.vp-bar:hover .vp-knob,
.vp-bar:focus-visible .vp-knob { transform: translate(-50%, -50%) scale(1); }
.vp-played + .vp-knob { left: var(--pos, 0); }

@media (pointer: coarse) {
  .vp-btn { width: 42px; height: 42px; }
  .vp-bar { height: 34px; }
}
