/* ============================================================
   Félix Perrier - portfolio
   Direction : dossier technique / atelier. Porcelaine bleutée,
   bleu poudré (portrait), encre bleu-gris, accent laiton.
   ============================================================ */

:root {
  --paper: #f4f7f9;
  --paper-2: #eaf0f4;
  --card: #fdfefe;
  --ink: #1f2e38;
  --ink-soft: #546875;
  --blue: #a9c6d9;
  --blue-tint: #dce8f0;
  --blue-deep: #38607c;
  --brass: #8a683a;
  --line: #c9d6de;
  --ok: #3f6650;

  --font-display: "Bricolage Grotesque", "Instrument Sans", system-ui, sans-serif;
  --font-body: "Instrument Sans", system-ui, -apple-system, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "Courier New", monospace;

  --maxw: 1140px;
  --radius: 14px;
  --shadow: 0 1px 2px rgba(31, 46, 56, 0.05), 0 12px 32px -16px rgba(31, 46, 56, 0.18);
  --shadow-lift: 0 2px 4px rgba(31, 46, 56, 0.06), 0 24px 48px -20px rgba(31, 46, 56, 0.28);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 88px;
}

body {
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

a { color: var(--blue-deep); }

::selection { background: var(--blue); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--blue-deep);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Topbar ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 2rem;
  padding: 0.85rem clamp(1.25rem, 4vw, 3rem);
  background: color-mix(in srgb, var(--paper) 96%, transparent);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  text-decoration: none;
  color: var(--ink);
}

.brand-mark {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  color: var(--paper);
  background: var(--blue-deep);
  padding: 0.3rem 0.5rem;
  border-radius: 8px;
}

.brand-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}

.nav {
  display: flex;
  gap: 0.25rem;
  margin-left: auto;
}

.nav-link {
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 0.45rem 0.85rem;
  border-radius: 999px;
  transition: color 0.2s, background-color 0.2s;
}

.nav-link:hover { color: var(--ink); background: var(--blue-tint); }

.nav-link.is-active { color: var(--ink); background: var(--blue-tint); }

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ok);
  text-decoration: none;
  border: 1px solid color-mix(in srgb, var(--ok) 40%, transparent);
  background: color-mix(in srgb, var(--ok) 8%, transparent);
  padding: 0.42rem 0.9rem;
  border-radius: 999px;
  white-space: nowrap;
  transition: background-color 0.2s;
}

.status-pill:hover { background: color-mix(in srgb, var(--ok) 16%, transparent); }

.status-pill .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ok);
  animation: pulse 2.4s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 45%, transparent); }
  50% { box-shadow: 0 0 0 5px transparent; }
}

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 42px;
  height: 42px;
  padding: 0 10px;
  background: none;
  border: 1px solid var(--line);
  border-radius: 10px;
  cursor: pointer;
}

.nav-toggle span {
  display: block;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform 0.25s, opacity 0.25s;
}

.nav-toggle[aria-expanded="true"] span:first-child { transform: translateY(3.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:last-child { transform: translateY(-3.5px) rotate(-45deg); }

/* ---------- Hero ---------- */

.hero {
  position: relative;
  background:
    linear-gradient(to bottom, transparent, var(--paper) 92%),
    repeating-linear-gradient(0deg, color-mix(in srgb, var(--blue-deep) 7%, transparent) 0 1px, transparent 1px 56px),
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--blue-deep) 7%, transparent) 0 1px, transparent 1px 56px),
    var(--paper);
}

.hero-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(3.5rem, 8vh, 6.5rem) clamp(1.25rem, 4vw, 3rem) 3rem;
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(300px, 0.75fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}

.hero-copy, .hero-portrait { min-width: 0; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.4rem;
}

.eyebrow-num {
  color: var(--brass);
  font-weight: 500;
  white-space: nowrap;
}

.eyebrow-label {
  flex: 1;
  min-width: 0;
}

.eyebrow-num::after {
  content: "";
  display: inline-block;
  width: 2.2rem;
  height: 1px;
  background: var(--brass);
  vertical-align: middle;
  margin-left: 0.75rem;
}

.hero h1 {
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 6vw, 4.4rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.03em;
  margin-bottom: 1.5rem;
}

.hero h1 em {
  font-style: normal;
  color: var(--blue-deep);
}

.lede {
  font-size: clamp(1.05rem, 1.4vw, 1.2rem);
  color: var(--ink-soft);
  max-width: 34em;
  margin-bottom: 2.2rem;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin-bottom: 3rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.97rem;
  text-decoration: none;
  padding: 0.8rem 1.5rem;
  border-radius: 999px;
  border: 1px solid transparent;
  transition: transform 0.18s, box-shadow 0.18s, background-color 0.18s, border-color 0.18s;
}

.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn-primary {
  background: var(--blue-deep);
  color: #fff;
  box-shadow: var(--shadow);
}

.btn-primary:hover {
  background: color-mix(in srgb, var(--blue-deep) 88%, black);
  box-shadow: var(--shadow-lift);
}

.btn-ghost {
  color: var(--ink);
  border-color: var(--line);
  background: color-mix(in srgb, var(--card) 65%, transparent);
}

.btn-ghost:hover { border-color: var(--blue-deep); }

.btn-lg { padding: 1rem 2rem; font-size: 1.05rem; }

.hero-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1.5rem;
  border-top: 1px solid var(--line);
  padding-top: 1.6rem;
}

.hero-stats dt {
  font-family: var(--font-display);
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--blue-deep);
  font-variant-numeric: tabular-nums;
}

.hero-stats dd {
  font-size: 0.85rem;
  color: var(--ink-soft);
  max-width: 13em;
}

/* Portrait annoté façon plan coté */

.hero-portrait { position: relative; }

.portrait-frame {
  position: relative;
  border-radius: var(--radius);
  box-shadow: var(--shadow-lift);
}

.portrait-frame img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  border: 1px solid var(--line);
}

.measure {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--brass);
}

.measure i {
  flex: 1;
  height: 1px;
  background: var(--brass);
  position: relative;
}

.measure i::before,
.measure i::after {
  content: "";
  position: absolute;
  top: -3.5px;
  width: 1px;
  height: 8px;
  background: var(--brass);
}

.measure i::before { left: 0; }
.measure i::after { right: 0; display: none; }

.measure-top {
  top: -1.6rem;
  left: 0;
  right: 0;
}

.measure-top i:first-of-type::after { display: none; }
.measure-top i:last-of-type::after { display: block; }

.measure-right {
  top: 0;
  bottom: 0;
  right: -1.7rem;
  flex-direction: column;
}

.measure-right b { writing-mode: vertical-rl; }

.measure-right i {
  width: 1px;
  height: auto;
  align-self: center;
}

.measure-right i::before,
.measure-right i::after {
  top: auto;
  left: -3.5px;
  width: 8px;
  height: 1px;
}

.measure-right i:first-of-type::before { top: 0; }
.measure-right i:last-of-type::after { bottom: 0; display: block; }

.measure b { font-weight: 500; }

.cartouche {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin-top: 1.1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
  overflow: hidden;
}

.cartouche span {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.55rem 0.8rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--ink);
}

.cartouche span + span { border-left: 1px solid var(--line); }

.cartouche b {
  font-weight: 400;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
}

.scroll-hint {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 4vw, 3rem) 2.5rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ---------- Sections ---------- */

.section {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(4rem, 9vh, 6.5rem) clamp(1.25rem, 4vw, 3rem);
}

.section-panel {
  max-width: none;
  background: var(--paper-2);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.section-panel > * {
  max-width: var(--maxw);
  margin-left: auto;
  margin-right: auto;
}

.section-head { margin-bottom: clamp(2.5rem, 5vh, 3.75rem); }

.section-head h2 {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 3.6vw, 2.8rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.1;
  margin-bottom: 1rem;
  max-width: 18em;
}

.section-lede {
  color: var(--ink-soft);
  max-width: 38em;
  font-size: 1.05rem;
}

/* ---------- Timeline ---------- */

.timeline {
  position: relative;
  list-style: none;
  margin-left: 0.5rem;
  display: grid;
  gap: 2.4rem;
}

/* Rail vertical + barre de progression qui se trace au scroll (scaleY via GSAP). */
.timeline-track {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
}

.timeline-bar {
  display: block;
  position: absolute;
  inset: 0;
  width: 1px;
  background: var(--brass);
  transform-origin: top center;
}

/* Fallback (GSAP absent ou reduced-motion) : barre pleine. */
html:not(.gsap) .timeline-bar { transform: none; }

.timeline-item {
  position: relative;
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 1.5rem;
  padding-left: 2rem;
}

.timeline-item::before {
  content: "";
  position: absolute;
  left: -4.5px;
  top: 0.55rem;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--brass);
  transition: background-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
}

/* Point allumé quand le fil l'atteint (classe .lit posée par GSAP). */
.timeline-item.lit::before {
  background: var(--brass);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--brass) 18%, transparent);
}

/* Fallback : tous les points allumés. */
html:not(.gsap) .timeline-item::before { background: var(--brass); }

.timeline-year {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--brass);
  padding-top: 0.3rem;
}

.timeline-item h3 {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: 0.35rem;
}

.timeline-item p {
  color: var(--ink-soft);
  max-width: 44em;
}

/* ---------- Photographie personnelle (fin de Parcours) ---------- */

.perso-photo {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px dashed var(--line);
  /* Section basse, souvent hors-écran au chargement : différée. */
  content-visibility: auto;
  contain-intrinsic-size: auto 560px;
}

.perso-photo-shots {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.perso-photo-shots .shot {
  aspect-ratio: 3 / 4;
}

.perso-photo-shots .shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.perso-photo-cap {
  margin-top: 0.85rem;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  flex-wrap: wrap;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.perso-photo-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brass);
}

@media (max-width: 640px) {
  .perso-photo-shots { grid-template-columns: 1fr 1fr; }
  .perso-photo-shots .shot:last-child { display: none; }
}

/* ---------- Atelier ---------- */

.bench-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
  /* Bloc hors-écran au chargement : layout/paint différés (perf #3). */
  content-visibility: auto;
  contain-intrinsic-size: auto 420px;
}

.bench {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem 1.5rem;
  box-shadow: var(--shadow);
}

.bench h3 {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 1.1rem;
}

.bench-ref {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--blue-deep);
  background: var(--blue-tint);
  border: 1px solid color-mix(in srgb, var(--blue-deep) 25%, transparent);
  border-radius: 7px;
  padding: 0.15rem 0.5rem;
}

.bench ul { list-style: none; display: grid; gap: 0.45rem; }

.bench li {
  font-size: 0.95rem;
  color: var(--ink-soft);
  padding-left: 1.1rem;
  position: relative;
}

.bench li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 1px;
  background: var(--blue);
  transform: rotate(45deg);
}

.ai-note {
  margin-top: 1.25rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--brass);
  border-radius: var(--radius);
  padding: 1.4rem 1.6rem;
  box-shadow: var(--shadow);
}

.ai-note-label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 0.4rem;
}

.ai-note p:last-child { color: var(--ink-soft); max-width: 60em; }

.ai-note strong { color: var(--ink); }

.certs {
  margin-top: 2.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.certs span {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  border: 1px dashed var(--line);
  border-radius: 999px;
  padding: 0.4rem 0.95rem;
  background: color-mix(in srgb, var(--card) 55%, transparent);
}

/* ---------- Minia vidéo PORTRAIT - reel entièrement lisible ---------- */
/* Cadre au ratio réel du reel (9:16) - réutilisé par la planche contact vidéo
   (préfixe .contact-vframe-portrait). Le premier plan reste en `contain` :
   rien n'est rogné, le texte incrusté du reel est lisible. */
.video-thumb-portrait {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* Fond : l'image en cover + flou → comble les côtés sans bande morte. */
.video-thumb-portrait .video-thumb-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(18px) saturate(1.1) brightness(0.72);
  transform: scale(1.15);         /* mange les bords flous */
  transition: none;
}

/* Premier plan : l'image ENTIÈRE, non rognée (texte du reel lisible). */
.video-thumb-portrait .video-thumb-fg {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: contain;            /* rien n'est coupé */
  transition: transform 0.4s;
}

/* Timecode mono en bas - cohérent avec les minias paysage + ADN technique. */
.video-thumb-tc {
  position: absolute;
  left: 0.6rem;
  bottom: 0.6rem;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  color: #fff;
  background: color-mix(in srgb, var(--ink) 62%, transparent);
  padding: 0.18rem 0.5rem;
  border-radius: 6px;
}

.shot {
  position: relative;
  overflow: hidden;
  background: var(--blue-tint);
  /* Empêche l'auto-min-size de la grille/flex de s'étendre à la taille
     intrinsèque de l'image quand elle arrive (lazy) → zéro reflow / CLS. */
  min-width: 0;
  min-height: 0;
}

.shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s;
}

.shot.is-empty img { display: none; }

.shot.is-empty::after {
  content: "à venir : " attr(data-file);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--blue-deep);
  background:
    repeating-linear-gradient(-45deg, transparent 0 10px, color-mix(in srgb, var(--blue-deep) 5%, transparent) 10px 20px),
    var(--blue-tint);
  border: 1px dashed color-mix(in srgb, var(--blue-deep) 35%, transparent);
  margin: 6px;
  border-radius: 8px;
}

.video-slot {
  position: relative;
  background: var(--blue-tint);
}

.video-slot video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-slot.is-empty video { display: none; }

.video-slot.is-empty::after {
  content: "vidéo à venir : " attr(data-file);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--blue-deep);
  background:
    repeating-linear-gradient(-45deg, transparent 0 10px, color-mix(in srgb, var(--blue-deep) 5%, transparent) 10px 20px),
    var(--blue-tint);
  border: 1px dashed color-mix(in srgb, var(--blue-deep) 35%, transparent);
  margin: 6px;
  border-radius: 8px;
}

.badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.18rem 0.6rem;
  border-radius: 999px;
}

.badge-prod { color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }
.badge-cours { color: var(--blue-deep); background: var(--blue-tint); }
/* Ton laiton foncé réservé au badge pour atteindre le contraste AA (4.5:1).
   #7a5a30 sur le fond composité (~rgb(229,229,225)) = 4.99:1, contre 4.03:1
   avec --brass (#8a683a). Le --brass décoratif reste inchangé ailleurs. */
.badge-livre { color: #7a5a30; background: color-mix(in srgb, var(--brass) 14%, transparent); }

/* ---------- Contact ---------- */

.section-contact {
  text-align: left;
  /* Dernière section, toujours hors-écran au chargement (perf #3). */
  content-visibility: auto;
  contain-intrinsic-size: auto 480px;
  /* Section finale courte : sans hauteur mini, la page se termine avant que
     l'ancre #contact puisse remonter sous la topbar (le fond de page est
     atteint alors que l'eyebrow est encore ~250 px trop bas). On garantit
     l'espace de scroll pour un atterrissage propre à 88 px. Le padding de
     .section garde le contenu aligné en haut ; l'espace ajouté est en bas. */
  min-height: calc(100svh - 88px);
}

.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-bottom: 1.5rem;
}

.contact-meta {
  font-size: 0.92rem;
  color: var(--ink-soft);
}

/* ---------- Footer ---------- */

.footer {
  border-top: 1px solid var(--line);
  padding: 2rem clamp(1.25rem, 4vw, 3rem);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
  text-align: center;
}

.footer a { color: var(--blue-deep); }

/* ---------- Marquee outils (entre Atelier et Missions) ---------- */

.marquee {
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--paper-2);
  padding: 0.7rem 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee 42s linear infinite;
}

.marquee { position: relative; }

/* Pause au survol souris ET au focus clavier (belt-and-suspenders WCAG 2.2.2). */
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track { animation-play-state: paused; }

/* Pause explicite pilotée par le bouton (état persistant, opérable clavier). */
.marquee.is-paused .marquee-track { animation-play-state: paused !important; }

.marquee-toggle {
  position: absolute;
  top: 50%;
  right: 0.6rem;
  transform: translateY(-50%);
  z-index: 2;
  width: 1.9rem;
  height: 1.9rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--ink-soft);
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}

/* Zone tactile étendue à 44px min (WCAG 2.5.5) sans grossir le disque visible. */
.marquee-toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

.marquee-toggle:hover { color: var(--ink); border-color: var(--brass); }
.marquee-toggle:focus-visible { outline: 2px solid var(--blue-deep); outline-offset: 2px; }

/* Icône pause (deux barres) par défaut ; bascule en triangle "lecture" quand pausé. */
.marquee-toggle-icon {
  display: block;
  width: 0.5rem;
  height: 0.6rem;
  border-left: 2px solid currentColor;
  border-right: 2px solid currentColor;
}

.marquee.is-paused .marquee-toggle-icon {
  width: 0;
  height: 0;
  border-left: 0.55rem solid currentColor;
  border-right: 0;
  border-top: 0.35rem solid transparent;
  border-bottom: 0.35rem solid transparent;
}

.marquee-list {
  display: flex;
  align-items: center;
  list-style: none;
  flex-shrink: 0;
}

.marquee-list li {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  white-space: nowrap;
  padding: 0 1.6rem;
  position: relative;
}

.marquee-list li::after {
  content: "◆";
  position: absolute;
  right: -0.35rem;
  color: var(--brass);
  font-size: 0.55rem;
  top: 50%;
  transform: translateY(-50%);
}

@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ---------- Miniature vidéo cliquable (feed → modale) ---------- */

.video-thumb {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--blue-tint);
  cursor: pointer;
  overflow: hidden;
}

.video-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s;
}

.video-thumb-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 66px;
  height: 66px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--ink) 52%, transparent);
  border: 2px solid rgba(255, 255, 255, 0.9);
  box-shadow: 0 6px 20px -6px rgba(31, 46, 56, 0.6);
  transition: background-color 0.2s, transform 0.2s;
}

.video-thumb-play::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 54%;
  transform: translate(-50%, -50%);
  border-style: solid;
  border-width: 9px 0 9px 15px;
  border-color: transparent transparent transparent #fff;
}

.video-thumb:hover .video-thumb-play {
  background: var(--blue-deep);
  transform: translate(-50%, -50%) scale(1.07);
}

.video-thumb:focus-visible {
  outline: 2px solid var(--blue-deep);
  outline-offset: -3px;
}

@media (prefers-reduced-motion: reduce) {
  .video-thumb img, .video-thumb-play { transition: none; }
}

/* ---------- Modale détail ---------- */

.pm[hidden] { display: none; }

.pm {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.75rem, 3vw, 2rem);
  opacity: 0;
  transition: opacity 0.22s ease;
}

.pm.is-open { opacity: 1; }

.pm-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ink) 58%, transparent);
}

.pm-dialog {
  position: relative;
  width: 100%;
  max-width: 940px;
  max-height: 90vh;
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--shadow-lift);
  transform: translateY(12px) scale(0.99);
  transition: transform 0.22s ease;
}

.pm.is-open .pm-dialog { transform: none; }

.pm-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /* padding-right réserve la place du bouton fermer flottant (.pm-close-wrap,
     sorti du flux) : sans ça le titre passe sous le bouton en mobile. */
  padding: 1.1rem clamp(3.25rem, 8vw, 3.75rem) 1.1rem clamp(1.1rem, 3vw, 1.75rem);
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
}

.pm-title {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
}

.pm-close {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--ink);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 50%;
  cursor: pointer;
  transition: background-color 0.2s;
}

.pm-close:hover { background: var(--blue-tint); }

.pm-body { padding: clamp(1.1rem, 3vw, 1.75rem); }

.pm-intro {
  color: var(--ink-soft);
  max-width: 60ch;
  margin-bottom: 1.75rem;
}

/* Cartouche « dossier technique » dans la modale (dt/dd, langage cotes/REF). */
.pm-cartouche {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.4rem 1.5rem;
  margin: 0 0 1.75rem;
  padding: 1rem 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.pm-cartouche > div {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  min-width: 0;
}

.pm-cartouche dt {
  flex: 0 0 auto;
  min-width: 5.5rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.pm-cartouche dd {
  min-width: 0;
  font-size: 0.9rem;
  color: var(--ink);
}

/* Placeholder honnête (vidéo non livrée, ex. REF 008 pub MMAD). */
.pm-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  min-height: 220px;
  padding: 2rem;
  text-align: center;
  color: var(--ink-soft);
  background:
    repeating-linear-gradient(45deg, color-mix(in srgb, var(--line) 40%, transparent) 0 1px, transparent 1px 12px),
    var(--blue-tint);
  border: 1px dashed color-mix(in srgb, var(--blue-deep) 30%, var(--line));
  border-radius: 12px;
}

.pm-placeholder-badge {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--blue-deep);
  padding: 0.25rem 0.7rem;
  border: 1px solid color-mix(in srgb, var(--blue-deep) 35%, var(--line));
  border-radius: 999px;
}

.pm-section + .pm-section {
  margin-top: 2rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}

.pm-section-title {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 1rem;
}

.pm-video {
  display: flex;
  justify-content: center;
  background: var(--blue-tint);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 1.15rem;
}

.pm-video video {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 68vh;
}

.pm-gallery {
  display: flex;
  gap: 0.85rem;
  overflow-x: auto;
  padding-bottom: 0.5rem;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}

.pm-shot {
  flex: 0 0 auto;
  width: clamp(150px, 40vw, 210px);
  scroll-snap-align: start;
}

.pm-shot img {
  width: 100%;
  height: auto;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--blue-tint);
}

.pm-shot figcaption {
  margin-top: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-soft);
  text-align: center;
}

body.pm-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .pm, .pm-dialog { transition: none; }
  .pm-dialog { transform: none; }
}

/* ============================================================
   FICHES v2, direction B « éditorial magazine ».
   La modale garde son shell (.pm / .pm-dialog) ; quand la fiche
   est migrée (d.ref présent), le dialog porte .pm-v2 : héros
   plein cadre, métadonnées en ligne, mosaïque, cadre film.
   Les fiches non migrées (poste Établi) gardent le rendu legacy.
   ============================================================ */

/* Bouton fermer flottant, visible en permanence au scroll */
.pm-close-wrap {
  position: sticky;
  top: 0;
  z-index: 6;
  height: 0;
  display: flex;
  justify-content: flex-end;
  padding: 1rem 1.1rem 0 0;
}
.pm-close-wrap .pm-close {
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* En v2, la barre de titre legacy disparaît (le titre vit dans le héros) */
.pm-v2 .pm-head { display: none; }
.pm-v2 .pm-body { padding: 0; }

/* Folio REF en coin du héros */
.pm-folio {
  position: absolute;
  top: 1.15rem;
  left: 1.4rem;
  z-index: 3;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--paper);
  text-shadow: 0 1px 6px rgba(31, 46, 56, 0.55);
}
.pm-folio .num { color: var(--brass); }

/* ---------- Héros plein cadre ---------- */
.pm-hero { position: relative; width: 100%; }

.pm-hero-media {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 2;
  max-height: 52vh;
  overflow: hidden;
  background: var(--blue-tint);
}
.pm-hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.pm-hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(31, 46, 56, 0.78) 0%, rgba(31, 46, 56, 0.22) 42%, transparent 68%);
  pointer-events: none;
}

.pm-hero-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: clamp(1.5rem, 4vw, 2.75rem) clamp(1.5rem, 5vw, 3.25rem);
}

.pm-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--paper) 88%, transparent);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.pm-eyebrow .num { color: var(--brass); font-weight: 500; white-space: nowrap; }
.pm-eyebrow .num::after {
  content: "";
  display: inline-block;
  width: 2.2rem;
  height: 1px;
  background: var(--brass);
  vertical-align: middle;
  margin-left: 0.75rem;
}

.pm-hero-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.1rem, 5.2vw, 3.4rem);
  line-height: 0.98;
  letter-spacing: -0.03em;
  color: var(--paper);
  max-width: 18ch;
}
.pm-hero-title .sub {
  display: block;
  font-family: var(--font-body);
  font-size: clamp(0.95rem, 1.8vw, 1.2rem);
  font-weight: 500;
  letter-spacing: -0.005em;
  color: color-mix(in srgb, var(--paper) 82%, transparent);
  margin-top: 0.6rem;
  line-height: 1.25;
}

/* Héros typographique (fiche sans visuel, ex. Colibrimo) : papier + grille */
.pm-hero.is-typo .pm-hero-media {
  aspect-ratio: auto;
  min-height: 220px;
  background:
    repeating-linear-gradient(0deg, color-mix(in srgb, var(--blue-deep) 7%, transparent) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--blue-deep) 7%, transparent) 0 1px, transparent 1px 26px),
    var(--paper-2);
}
.pm-hero.is-typo .pm-hero-media::after { background: none; }
.pm-hero.is-typo .pm-hero-caption { position: static; padding-top: clamp(3.25rem, 7vw, 4.5rem); }
.pm-hero.is-typo .pm-eyebrow { color: var(--ink-soft); }
.pm-hero.is-typo .pm-hero-title { color: var(--ink); }
.pm-hero.is-typo .pm-hero-title .sub { color: var(--ink-soft); }
.pm-hero.is-typo ~ * .pm-folio { color: var(--ink-soft); text-shadow: none; }
.pm-v2 .pm-hero.is-typo .pm-folio { color: var(--ink-soft); text-shadow: none; }

/* ---------- Corps éditorial ---------- */
.pm-body-inner {
  padding: clamp(2rem, 5vw, 3.25rem) clamp(1.5rem, 5vw, 3.25rem) clamp(2.25rem, 5vw, 3.5rem);
}

/* Métadonnées en ligne : mono, points médians laiton */
.pm-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem 0.85rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-bottom: 1.6rem;
  margin-bottom: 2.25rem;
  border-bottom: 1px solid var(--line);
}
.pm-meta .item { display: inline-flex; align-items: baseline; gap: 0.4rem; }
.pm-meta .item + .item::before {
  content: "·";
  color: var(--brass);
  font-size: 0.85em;
}
.pm-meta .k { color: color-mix(in srgb, var(--ink-soft) 78%, var(--line)); }
.pm-meta .v { color: var(--ink); }

/* Intro magazine : gros corps display, colonne étroite centrée */
.pm-lede {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.15rem, 1.9vw, 1.38rem);
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--ink);
  max-width: 36ch;
  margin: 0 auto 1.5rem;
}
.pm-lede::first-letter { color: var(--blue-deep); }
.pm-more {
  max-width: 52ch;
  margin: 0 auto 2.75rem;
  color: var(--ink-soft);
}
.pm-lede:last-child, .pm-lede + .pm-block-head { margin-top: 2.75rem; }

/* En-tête de bloc */
.pm-block-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin: 2.5rem 0 1.4rem;
}
.pm-block-head:first-child { margin-top: 0; }
.pm-block-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}
.pm-block-num {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.pm-block-num .num { color: var(--brass); }

/* ---------- Mosaïque asymétrique ---------- */
.pm-mosaic {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-flow: dense;
  gap: 0.9rem;
}
.pm-mosaic .shot { margin: 0; overflow: hidden; display: flex; flex-direction: column; }
.pm-mosaic .shot .frame {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--blue-tint);
}
.pm-mosaic .shot .frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s ease, filter 0.3s ease;
  filter: saturate(0.96);
}
.pm-mosaic .shot:hover .frame img { transform: scale(1.03); filter: saturate(1.04); }
.pm-mosaic .shot figcaption {
  margin-top: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-style: italic;
  line-height: 1.35;
  color: var(--ink-soft);
}
/* Variante écrans téléphone : vignettes uniformes 9:16, 3 par rangée */
.pm-mosaic.is-portrait .shot .frame { aspect-ratio: 9 / 16; }
.pm-mosaic.is-portrait .shot .frame img { object-position: top; }

.shot-hero { grid-column: span 4; grid-row: span 2; }
.shot-hero .frame { aspect-ratio: auto; flex: 1; min-height: 0; }
.shot-s2 { grid-column: span 2; }
.shot-s2 .frame { aspect-ratio: 4 / 3; }
.shot-s3 { grid-column: span 3; }
.shot-s3 .frame { aspect-ratio: 3 / 2; }
.shot-s6 { grid-column: span 6; }
.shot-s6 .frame { aspect-ratio: 21 / 9; }

/* ---------- Cadre film ---------- */
.pm-film { display: flex; justify-content: center; padding: 0.25rem 0; }
.film-frame {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  background: var(--ink);
  box-shadow: var(--shadow-lift);
}
.film-frame.is-916 { width: clamp(240px, 34vw, 330px); aspect-ratio: 9 / 16; }
.film-frame.is-169 { width: 100%; max-width: 720px; aspect-ratio: 16 / 9; }
.film-frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.pm-film-caption {
  margin: 1.1rem 0 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-style: italic;
  color: var(--ink-soft);
}
.pm-film-caption .brass { color: var(--brass); font-style: normal; }

/* ---------- Bloc chiffres (fiches data sans visuel) ---------- */
.pm-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1.25rem;
  margin: 0.5rem 0 0.75rem;
}
.pm-stats .stat {
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
}
.pm-stats .stat .n {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  letter-spacing: -0.02em;
  color: var(--blue-deep);
  line-height: 1.05;
}
.pm-stats .stat .l {
  margin-top: 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Filet laiton de clôture */
.pm-rule {
  margin-top: 2.75rem;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.pm-rule::before { content: ""; width: 2.4rem; height: 1px; background: var(--brass); }
.pm-rule::after { content: ""; flex: 1; height: 1px; background: var(--line); }

@media (max-width: 720px) {
  .pm-mosaic { grid-template-columns: repeat(2, 1fr); }
  .shot-hero { grid-column: span 2; grid-row: auto; }
  .shot-hero .frame { aspect-ratio: 16 / 10; flex: none; }
  .shot-s2, .shot-s3 { grid-column: span 1; }
  .shot-s6 { grid-column: span 2; }
  .pm-lede, .pm-more { max-width: none; }
  .film-frame.is-916 { width: min(72vw, 300px); }
}

/* ---------- Reveal ---------- */

/* Fallback IntersectionObserver (GSAP absent) : masqué uniquement si le JS tourne
   (html.js posé par le script inline du head), et PAS si GSAP prend la main (html.gsap).
   Sans JS, tout le contenu reste visible. */
html.js:not(.gsap) .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1), transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

html.js:not(.gsap) .reveal.in {
  opacity: 1;
  transform: none;
}

/* Quand GSAP est actif, l'état caché des reveals est posé par CSS (et non plus
   par un gsap.set() sur les 17 éléments au chargement, qui forçait le layout des
   éléments hors-écran et pénalisait le TBT). L'IntersectionObserver anime ensuite
   chaque élément avec gsap.fromTo() à son entrée. On ne masque QUE hors
   reduced-motion, et le hero se dé-masque tout seul (sa timeline retire .reveal).
   Filet de sécurité : si l'observer ne tire jamais, le contenu reste accessible
   (voir .reveal.is-shown ci-dessous, posé dès qu'un élément est révélé). */
@media (prefers-reduced-motion: no-preference) {
  html.gsap .reveal { opacity: 0; }
  html.gsap .reveal.is-shown { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js:not(.gsap) .reveal { opacity: 1; transform: none; transition: none; }
  .status-pill .dot { animation: none; }
  .btn, .shot img { transition: none; }
  .marquee-track { animation: none !important; }
  /* Animation figée : le bouton pause/lecture n'a plus d'objet. */
  .marquee-toggle { display: none; }
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
  .hero-inner {
    grid-template-columns: 1fr;
    padding-top: 3rem;
  }

  .hero-portrait {
    order: -1;
    max-width: 340px;
    padding-right: 1.9rem;
  }

  .bench-grid { grid-template-columns: 1fr; }

  .status-pill { display: none; }

  .nav-toggle { display: flex; margin-left: auto; }

  .nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    padding: 0.75rem clamp(1.25rem, 4vw, 3rem) 1.25rem;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    margin-left: 0;
  }

  .nav.is-open { display: flex; }

  .nav-link { padding: 0.7rem 0.85rem; font-size: 1rem; }
}

@media (max-width: 640px) {
  .hero h1 br { display: none; }

  .hero h1 { font-size: clamp(1.9rem, 9vw, 2.5rem); }

  .timeline-item {
    grid-template-columns: 1fr;
    gap: 0.3rem;
    padding-left: 1.5rem;
  }

  .hero-stats { gap: 1.25rem 2rem; }
}

/* ============================================================
   POSTES v3 - sommaire, bandeaux d'univers, SVG line-art cotés.
   Ambiance par poste via --poste-accent (posée en inline sur
   .poste-card et .poste). Teintes prises dans la palette existante.
   ============================================================ */

:root {
  /* Vert-atelier pour le poste Établi : dérivé de --ok, reste dans la famille. */
  --atelier: #34564a;
  /* Accent d'ambiance piloté par JS ; valeur de repli = bleu-deep. */
  --poste-accent: #38607c;
}

/* Accent statique par poste (fallback + reduced-motion) ; le JS interpole
   entre ces mêmes valeurs au scroll (spec-animations §4). */
#poste-ordinateur { --poste-accent: var(--blue-deep); }
#poste-camera { --poste-accent: var(--brass); }
#poste-etabli { --poste-accent: var(--atelier); }

/* ---------- SOMMAIRE « les postes » ---------- */

.postes-index .section-head { margin-bottom: clamp(2rem, 4vh, 3rem); }

.poste-cards {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}

.poste-card { min-width: 0; }

.poste-link {
  --edge: color-mix(in srgb, var(--poste-accent) 30%, var(--line));
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 1.5rem 1.5rem 1.35rem;
  text-decoration: none;
  color: var(--ink);
  background:
    linear-gradient(color-mix(in srgb, var(--poste-accent) 4%, var(--card)), var(--card)),
    var(--card);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  cursor: pointer;
  transition: transform 0.28s cubic-bezier(0.22,1,0.36,1), box-shadow 0.28s, border-color 0.28s;
}

/* grille de fond « plan » ténue, teintée par le poste */
.poste-link::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(0deg, color-mix(in srgb, var(--poste-accent) 6%, transparent) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--poste-accent) 6%, transparent) 0 1px, transparent 1px 26px);
  opacity: 0.5;
  pointer-events: none;
  transition: opacity 0.28s;
}

.poste-link:hover,
.poste-link:focus-visible {
  transform: translateY(-5px);
  box-shadow: var(--shadow-lift);
  border-color: var(--poste-accent);
  outline: none;
}

.poste-link:hover::before { opacity: 0.9; }

.poste-link:focus-visible {
  box-shadow: var(--shadow-lift), 0 0 0 3px color-mix(in srgb, var(--poste-accent) 35%, transparent);
}

.poste-card-num {
  position: relative;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  letter-spacing: 0.14em;
  color: var(--poste-accent);
}

.poste-card-num::after {
  content: "";
  display: inline-block;
  width: 1.8rem; height: 1px;
  margin-left: 0.7rem;
  vertical-align: middle;
  background: var(--poste-accent);
}

.poste-card-svg {
  position: relative;
  color: var(--poste-accent);       /* currentColor du SVG */
  margin: 0.9rem 0 1.1rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.poste-card-svg svg {
  width: 100%;
  height: auto;
  max-height: 190px;
}

.poste-card-foot { position: relative; margin-top: auto; }

.poste-card-name {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
}

.poste-card-tag {
  margin-top: 0.35rem;
  font-size: 0.92rem;
  color: var(--ink-soft);
}

.poste-card-count {
  margin-top: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.poste-card-count span {
  color: var(--poste-accent);
  font-weight: 500;
}

.poste-card-go {
  position: relative;
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.05em;
  color: var(--poste-accent);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 0.25s, transform 0.25s;
}

.poste-link:hover .poste-card-go,
.poste-link:focus-visible .poste-card-go {
  opacity: 1;
  transform: none;
}

/* ---------- BANDEAU DE POSTE (header d'univers) ---------- */

.poste {
  position: relative;
  max-width: none;
  padding: clamp(3.5rem, 8vh, 6rem) 0 clamp(4rem, 9vh, 6.5rem);
  border-top: 1px solid var(--line);
  scroll-margin-top: 88px;
}

/* Le corps du poste (terminal / nomenclature) reste différé ; le bandeau NON
   (piège content-visibility × getTotalLength, spec-animations §0.1/§1.4). Les SVG
   mesurés (nomen-leaders) tracent en mode "enter" : leur getTotalLength() est calculé
   paresseusement à l'entrée du trigger, donc APRÈS rendu réel → mesure correcte.
   ⚠️ v8 : content-visibility:auto impose une CONTAINMENT PAINT qui clippe les enfants
   à la boîte de l'élément. Les .subposte contiennent des éléments FULL-BLEED (pellicule
   02·B, tableau 02·C) qui débordent en 100vw : sous la containment ils étaient rognés à
   la largeur du subposte (~1140px) et ne touchaient donc PAS les bords de l'écran.
   → on retire content-visibility des .subposte (coût perf négligeable : images lazy). */
.poste .term,
.poste .nomen {
  content-visibility: auto;
  contain-intrinsic-size: auto 1200px;
}

.poste > * {
  max-width: var(--maxw);
  margin-left: auto;
  margin-right: auto;
  padding-left: clamp(1.25rem, 4vw, 3rem);
  padding-right: clamp(1.25rem, 4vw, 3rem);
}

/* Fond « wash » léger qui suit l'accent (couleur seulement → aucun layout). */
.poste::before {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(120% 60% at 50% 0%,
    color-mix(in srgb, var(--poste-accent) 5%, transparent), transparent 70%);
  pointer-events: none;
  z-index: -1;
}

.poste-head {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  margin-bottom: clamp(2.5rem, 5vh, 3.75rem);
}

/* Numéro de poste géant, en filigrane derrière le SVG */
.poste-mark {
  position: absolute;
  top: 50%;
  right: clamp(1.25rem, 4vw, 3rem);
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: clamp(9rem, 22vw, 17rem);
  font-weight: 400;
  line-height: 0.8;
  color: color-mix(in srgb, var(--poste-accent) 9%, transparent);
  pointer-events: none;
  user-select: none;
  z-index: 0;
}
/* Masqué au repos seulement si le JS tourne (le module reveal l'anime). */
html.js .poste-header:not(.is-shown) .poste-mark { opacity: 0; }

.poste-figure {
  position: relative;
  z-index: 1;
  color: var(--poste-accent);       /* currentColor du SVG */
  order: 2;
}

.poste-figure svg {
  width: 100%;
  height: auto;
  max-height: 300px;
}

.poste-intro { position: relative; z-index: 1; order: 1; min-width: 0; }

.poste-intro h2 {
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 4.5vw, 3.2rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.02;
  margin: 0.2rem 0 0.9rem;
}

.poste-intro .eyebrow { margin-bottom: 0.9rem; }
.poste-intro .eyebrow-num { color: var(--poste-accent); }
.poste-intro .eyebrow-num::after { background: var(--poste-accent); }
.poste-eyebrow { color: var(--poste-accent); }

.poste-lede {
  font-size: clamp(1.02rem, 1.4vw, 1.15rem);
  color: var(--ink-soft);
  max-width: 34em;
  margin-bottom: 1.6rem;
}

.poste-tooling {
  border-top: 1px solid var(--line);
  padding-top: 1.1rem;
}

.poste-tooling-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--poste-accent);
  margin-bottom: 0.7rem;
}

.poste-tooling ul {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 0.55rem;
}

.poste-tooling li {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  border: 1px solid color-mix(in srgb, var(--poste-accent) 22%, var(--line));
  border-radius: 999px;
  padding: 0.32rem 0.8rem;
  background: color-mix(in srgb, var(--poste-accent) 4%, var(--card));
}

.poste .term,
.poste .nomen { margin-top: 0; }

/* ---------- SOUS-POSTES (Photo / Vidéo dans la Caméra) ---------- */

.subposte + .subposte { margin-top: clamp(4.5rem, 10vh, 6.5rem); }

.subposte-head {
  position: relative;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.85rem 1.25rem;
  margin-bottom: 2rem;
  padding-top: 1.15rem;
  padding-bottom: 1rem;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

/* Repère de planche : segment accent épais qui ouvre chaque sous-partie */
.subposte-head::before {
  content: "";
  position: absolute;
  top: -2px;
  left: 0;
  width: 4.5rem;
  height: 3px;
  background: var(--poste-accent);
}

.subposte-num {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  color: var(--poste-accent);
  border: 1px solid color-mix(in srgb, var(--poste-accent) 45%, transparent);
  border-radius: 4px;
  padding: 0.22rem 0.5rem;
  flex-shrink: 0;
}

.subposte-title {
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.8vw, 2.7rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
}

.subposte-head > div { flex: 1 1 20rem; min-width: 0; }

.subposte-lede {
  font-size: 0.95rem;
  color: var(--ink-soft);
  max-width: 44em;
  margin-top: 0.4rem;
}

.subposte-count {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-soft);
  flex-shrink: 0;
  margin-left: auto;
}

/* ---------- SVG postes : traits fins, tracé animable ---------- */

.poste-svg { display: block; }
.poste-svg-dims { opacity: 0.7; }

/* Épaisseur de trait stable si le SVG est mis à l'échelle. */
[data-draw] .draw { vector-effect: non-scaling-stroke; }

/* Hook tracé au scroll (le spec animations pilote --l via getTotalLength).
   Fallback : sans JS/GSAP, tout est visible (aucun dashoffset appliqué ici). */
html.gsap .poste-svg .draw {
  stroke-dasharray: var(--l, none);
  stroke-dashoffset: var(--l, 0);
}

/* ---------- Micro-anims hover des objets (desktop, pointer:fine) ---------- */

@media (hover: hover) and (pointer: fine) {
  /* Caméra (rig) : les volets de la matte box s'inclinent, le point REC clignote */
  .obj-matte-top, .obj-matte-top-b { transform-origin: 242px 100px; transition: transform 0.45s cubic-bezier(0.22,1,0.36,1); }
  .obj-matte-bot, .obj-matte-bot-b { transform-origin: 242px 156px; transition: transform 0.45s cubic-bezier(0.22,1,0.36,1); }
  .poste-link:hover .obj-matte-top,
  .poste-figure:hover .obj-matte-top-b { transform: rotate(-12deg); }
  .poste-link:hover .obj-matte-bot,
  .poste-figure:hover .obj-matte-bot-b { transform: rotate(12deg); }
  .obj-rec, .obj-rec-b { transition: opacity 0.2s; }
  .poste-link:hover .obj-rec,
  .poste-figure:hover .obj-rec-b { animation: rec-blink 0.9s steps(1) infinite; }

  /* Imprimante 3D - poste Établi : tête qui coulisse + bobine qui tourne */
  #printer-head, #printer-head-b {
    transform-origin: center;
    transition: transform 0.55s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .poste-link:hover #printer-head,
  .poste-figure:hover #printer-head-b { transform: translateX(-64px); }
  #printer-spool, #printer-spool-b {
    transform-origin: 54px 46px;   /* axe de la bobine dans le viewBox 320x240 */
    transition: transform 0.9s cubic-bezier(0.33, 0, 0.2, 1);
  }
  .poste-link:hover #printer-spool,
  .poste-figure:hover #printer-spool-b { transform: rotate(150deg); }

  /* Ordinateur : le caret clignote */
  #pc-caret, #pc-caret-b { transition: opacity 0.2s; }
  .poste-link:hover #pc-caret,
  .poste-figure:hover #pc-caret-b { animation: pc-blink 0.9s steps(1) infinite; }
}

@keyframes pc-blink { 0%,50% { opacity: 1; } 50.01%,100% { opacity: 0; } }
@keyframes rec-blink { 0%,50% { opacity: 1; } 50.01%,100% { opacity: 0.12; } }

/* ---------- Responsive postes ---------- */

@media (max-width: 900px) {
  .poste-cards { grid-template-columns: 1fr; }
  .poste-card-svg svg { max-height: 210px; }

  .poste-head { grid-template-columns: 1fr; gap: 1.5rem; }
  .poste-figure { order: 1; max-width: 420px; }
  .poste-intro { order: 2; }
  .poste-mark {
    top: clamp(1rem, 4vw, 2rem);
    right: clamp(1rem, 5vw, 2rem);
    transform: none;
    font-size: clamp(6rem, 24vw, 10rem);
  }
}

@media (max-width: 640px) {
  .poste-card-svg svg { max-height: 170px; }
  .poste-figure svg { max-height: 230px; }
  .subposte-head { gap: 0.4rem 1rem; }
  .subposte-count { flex-basis: 100%; margin-left: 0; }
  .poste-tooling li { font-size: 0.72rem; padding: 0.28rem 0.7rem; }
}

/* ============================================================
   ANIMATIONS v3 - hooks CSS (le JS est posé par l'agent app.js).
   ============================================================ */

/* ---------- Bandeau : machine à écrire mono (spec-animations §2) ---------- */

.poste-typed {
  position: relative;
  display: inline-block;
  white-space: pre;
}
/* Ghost/live du typewriter - partagé par .poste-typed ET .term-type (terminal).
   Sans ces règles sur .term-type, le ghost (place réservée) resterait VISIBLE et
   le live coulerait à sa suite → ligne de commande dédoublée. */
.poste-typed .tw-ghost,
.term-type .tw-ghost { visibility: hidden; }
/* Le live se superpose EXACTEMENT au ghost : il remplit la border-box du parent
   et hérite de son padding (box-sizing: border-box) → le texte animé démarre au
   même x que le texte final, padding horizontal préservé pendant toute l'anim.
   Ancien bug : left:0 calait le live sur le padding-edge, ignorant le padding-left
   (0.8rem) → le texte chevauchait la bordure gauche des pastilles pendant le typewriter.
   .term-type n'a pas de padding → padding:inherit = 0, aucun effet de bord. */
.poste-typed .tw-live,
.term-type .tw-live {
  position: absolute;
  inset: 0;
  padding: inherit;
  box-sizing: border-box;
}
.poste-typed.is-typing .tw-live::after {
  content: "▌";
  color: var(--poste-accent, var(--brass));
  animation: tw-caret 0.9s steps(1) infinite;
}
@keyframes tw-caret { 50% { opacity: 0; } }
/* Sans JS, le texte statique reste visible tel quel. */
html:not(.js) .poste-typed .tw-ghost,
html:not(.js) .term-type .tw-ghost { visibility: visible; }

/* ---------- Stagger des fiches (spec-animations §3) ---------- */

/* ---------- Réticule « instrument » (spec-animations §5) ---------- */

.reticle {
  position: fixed;
  top: 0; left: 0;
  width: 0; height: 0;
  z-index: 300;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
  will-change: transform;
}
.reticle.is-visible { opacity: 1; }

.reticle-h, .reticle-v {
  position: absolute;
  background: color-mix(in srgb, var(--poste-accent, var(--blue-deep)) 55%, transparent);
}
.reticle-h { left: -14px; top: 0; width: 28px; height: 1px; }
.reticle-v { top: -14px; left: 0; width: 1px; height: 28px; }
.reticle-dot {
  position: absolute; top: -2px; left: -2px;
  width: 4px; height: 4px; border-radius: 50%;
  border: 1px solid var(--poste-accent, var(--blue-deep));
  transition: transform 0.18s ease;
}
.reticle-coord {
  position: absolute;
  top: 10px; left: 12px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.05em;
  color: color-mix(in srgb, var(--poste-accent, var(--blue-deep)) 75%, transparent);
  white-space: nowrap;
}
.reticle.is-big .reticle-h { left: -20px; width: 40px; }
.reticle.is-big .reticle-v { top: -20px; height: 40px; }
.reticle.is-big .reticle-dot { transform: scale(2.4); }

@media (pointer: coarse), (prefers-reduced-motion: reduce) {
  .reticle { display: none !important; }
}

/* ---------- Hover objets sommaire + CTA + timecode (spec-animations §6) ---------- */

.obj svg { transition: transform 0.35s cubic-bezier(0.22,1,0.36,1); transform-origin: center; }
.obj.is-hover svg { transform: translateY(-4px) scale(1.02); }

/* Timecode « REC » au hover des minias paysage (celles sans .video-thumb-tc statique). */
.video-thumb:not(.video-thumb-portrait)::before {
  content: "REC ● 00:00";
  position: absolute;
  top: 0.55rem; left: 0.6rem;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,0.5);
  opacity: 0;
  transition: opacity 0.25s ease;
}
.video-thumb:not(.video-thumb-portrait):hover::before,
.video-thumb:not(.video-thumb-portrait):focus-visible::before { opacity: 0.9; }

/* ---------- Déclencheur photo : flash de cadre (spec-animations §7) ---------- */

[data-shutter] { position: relative; }

.shutter-flash {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: var(--paper);
  opacity: 0;
}
.shutter-flash.is-firing { animation: shutter-fire 0.12s ease-out 1; }
@keyframes shutter-fire {
  0%   { opacity: 0; }
  35%  { opacity: 0.8; }
  100% { opacity: 0; }
}

/* ---------- Reduced-motion : tout figé, objets/cotes visibles ---------- */

@media (prefers-reduced-motion: reduce) {
  html.gsap .poste-header .poste-mark { opacity: 1 !important; }
  html.gsap .poste-svg .draw { stroke-dasharray: none; stroke-dashoffset: 0; }
  .poste-link, .poste-card-go { transition: none; }
  .obj-matte-top, .obj-matte-top-b, .obj-matte-bot, .obj-matte-bot-b,
  .obj-rec, .obj-rec-b, #printer-head, #printer-head-b,
  #printer-spool, #printer-spool-b, #pc-caret, #pc-caret-b {
    transition: none; animation: none; transform: none;
  }
  .obj svg { transition: none; }
  .poste-typed.is-typing .tw-live::after { display: none; }
  .video-thumb::before { transition: none; }
  .shutter-flash { display: none !important; }
  .video-thumb-portrait .video-thumb-fg { transition: none; }
}

/* ============================================================
   POSTE 01 - LE TERMINAL (v4). SEUL bloc sombre du site.
   Fond encre #1f2e38 sur le CORPS uniquement. Texte porcelaine /
   bleu poudré, accents laiton. transform/opacity only.
   ============================================================ */
.term { margin-top: clamp(1.5rem, 4vw, 2.75rem); }

.term-window {
  max-width: 860px;
  margin: 0 auto;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--ink) 24%, transparent);
  box-shadow: 0 22px 48px -28px rgba(31, 46, 56, 0.55);
  background: var(--ink);
}

/* Barre de titre - claire, contraste avec le corps encre */
.term-bar {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.55rem 0.9rem;
  background: color-mix(in srgb, var(--ink) 88%, #000 12%);
  border-bottom: 1px solid color-mix(in srgb, #000 30%, transparent);
}
.term-dots { display: inline-flex; gap: 0.4rem; }
.term-dots i {
  width: 11px; height: 11px; border-radius: 50%;
  background: #4a5a64;
}
.term-dots i:nth-child(1) { background: #b85c4e; }
.term-dots i:nth-child(2) { background: #c39a4e; }
.term-dots i:nth-child(3) { background: #5c8a5f; }
.term-titlebar {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  color: #a9c6d9; /* bleu poudré */
  opacity: 0.9;
}

/* Corps encre - SEUL bloc sombre du site */
.term-body {
  background: #1f2e38;
  color: #f4f7f9; /* porcelaine */
  padding: clamp(1rem, 3vw, 1.6rem) clamp(1rem, 3.2vw, 1.9rem) clamp(1.1rem, 3vw, 1.5rem);
  font-family: var(--font-mono);
  font-size: clamp(0.82rem, 0.72rem + 0.4vw, 0.95rem);
  line-height: 1.7;
}

/* Ligne de commande */
.term-cmd { display: flex; align-items: baseline; gap: 0.55rem; margin: 0 0 0.75rem; }
.term-prompt { color: #8a683a; font-weight: 600; } /* laiton */
.term-type { color: #f4f7f9; white-space: pre; position: relative; display: inline-block; }
.term-cmd-end { margin: 0.65rem 0 0; }

/* Curseur bloc clignotant (CSS pur) - ligne finale */
.term-caret {
  display: inline-block;
  width: 0.6em; height: 1.05em;
  margin-left: 0.15rem;
  background: #a9c6d9;
  transform: translateY(0.16em);
  animation: term-blink 1.05s steps(1, end) infinite;
}
@keyframes term-blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

/* Caret machine à écrire (rejoué à la fin du typewriter, cf. JS is-typing) */
.term-type.is-typing::after {
  content: "";
  display: inline-block;
  width: 0.55em; height: 1.05em;
  margin-left: 0.1rem;
  background: #a9c6d9;
  transform: translateY(0.16em);
  animation: term-blink 1.05s steps(1, end) infinite;
}

/* Liste des 3 entrées */
.term-list { list-style: none; margin: 0; padding: 0; }
.term-row { margin: 0; }

/* Une entrée = un bouton pleine largeur, colonnes mono alignées */
.term-entry {
  display: grid;
  grid-template-columns: 4.8em 1fr auto auto;
  align-items: baseline;
  column-gap: 1.1rem;
  width: 100%;
  padding: 0.34rem 0.55rem;
  margin: 0.05rem 0;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color 0.16s ease, color 0.16s ease;
}
.term-ref    { color: #8a683a; letter-spacing: 0.02em; }         /* laiton */
.term-desc   { color: #f4f7f9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.term-stack  { color: #a9c6d9; white-space: nowrap; }            /* bleu poudré */
.term-status { white-space: nowrap; font-weight: 600; letter-spacing: 0.02em; }
.term-status.is-cours { color: #c39a4e; }   /* ambre - En cours */
.term-status.is-livre { color: #7fb083; }   /* vert - Livré */

/* Hover / focus : la ligne s'éclaircit */
@media (hover: hover) and (pointer: fine) {
  .term-entry:hover { background: color-mix(in srgb, #a9c6d9 14%, transparent); }
  .term-entry:hover .term-desc { color: #ffffff; }
}
.term-entry:focus-visible {
  outline: 2px solid #a9c6d9;
  outline-offset: 2px;
  background: color-mix(in srgb, #a9c6d9 14%, transparent);
}

/* Aperçu flottant au hover (un seul élément réutilisé, injecté en JS) */
.term-preview {
  position: fixed;
  top: 0; left: 0;
  width: 260px;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  box-shadow: 0 16px 34px -18px rgba(31, 46, 56, 0.6);
  background: var(--ink);
  pointer-events: none;
  opacity: 0;
  z-index: 60;
  will-change: transform, opacity;
  transition: opacity 0.16s ease;
}
.term-preview.is-visible { opacity: 1; }
.term-preview img { display: block; width: 100%; height: auto; }

/* Responsive <=640 : stack/statut sous la désignation (2 lignes/entrée) */
@media (max-width: 640px) {
  .term-body { line-height: 1.65; }
  .term-entry {
    grid-template-columns: 4.8em 1fr;
    row-gap: 0.15rem;
    column-gap: 0.8rem;
  }
  .term-desc { white-space: normal; }
  .term-stack  { grid-column: 2; color: #a9c6d9; }
  .term-status { grid-column: 2; justify-self: start; }
}

/* reduced-motion : pas de clignotement, pas d'aperçu (géré aussi en JS) */
@media (prefers-reduced-motion: reduce) {
  .term-caret,
  .term-type.is-typing::after { animation: none; opacity: 1; }
}

/* ============================================================
   POSTE 02 - PLANCHE CONTACT (préfixe .contact-)
   Dense bord à bord ; hover cadre + marquage crayon laiton discret.
   ============================================================ */

/* ---- PHOTO : planche contact ---- */
.contact-sheet {
  display: flex;
  flex-direction: column;
  gap: 22px;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 16px 20px;
  box-shadow: var(--shadow);
}

.contact-group { display: flex; flex-direction: column; }

.contact-group-label {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 4px 2px 8px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 8px;
}
.contact-group-label .contact-ref  { color: var(--brass); font-weight: 600; }
.contact-group-label .contact-name { color: var(--ink); font-weight: 600; letter-spacing: 0.06em; }
.contact-group-label .contact-vol  { color: var(--blue-deep); margin-left: auto; }

/* Grille dense de frames : colonnes fluides, gap fin façon planche */
.contact-frames {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 6px;
}

.contact-frame {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--ink);
  cursor: pointer;
  overflow: hidden;
  aspect-ratio: 3 / 2;               /* garantit une hauteur -> lazy charge */
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.contact-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 3 / 2;
  transition: transform 0.3s ease, filter 0.25s ease;
  filter: saturate(0.94);
}

/* Numéro de vue mono, coin bas-gauche */
.contact-vue {
  position: absolute;
  left: 4px;
  bottom: 4px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  color: var(--paper);
  background: rgba(31, 46, 56, 0.62);
  padding: 1px 5px;
  border-radius: 2px;
  pointer-events: none;
}

/* Marquage crayon laiton discret (cercle dessiné), opacity only */
.contact-frame::after {
  content: "";
  position: absolute;
  inset: 8px;
  border: 1.5px solid var(--brass);
  border-radius: 50%;
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}

/* Hover desktop uniquement */
@media (hover: hover) and (pointer: fine) {
  .contact-frame:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lift);
    border-color: var(--brass);
    z-index: 2;
  }
  .contact-frame:hover .contact-img { transform: scale(1.04); filter: saturate(1.05); }
  .contact-frame:hover::after { opacity: 0.5; }
}

.contact-frame:focus-visible {
  outline: 2px solid var(--blue-deep);
  outline-offset: 2px;
  z-index: 3;
}

/* Stagger « tirage » : état caché posé quand GSAP prend la main (html.gsap) */
html.gsap .contact-frame { opacity: 0; }
html.gsap .contact-frame.is-pulled { opacity: 1; }  /* filet si tween échoue */

/* ====================================================================
   BANDEAU PHOTO DÉFILANT (v10) - chaque groupe montre TOUT le volume shooté.
   JS (initContactMarquee) remplace les vignettes statiques par .contact-marquee
   > .contact-track (2 passes) qui défile en boucle. Hauteur fixe, largeur des
   vignettes = ratio naturel (portrait étroit / paysage large) => variété visible.
   ==================================================================== */
.contact-frames.is-marquee { display: block; }        /* plus une grille : une bande pleine largeur */

.contact-marquee {
  position: relative;
  overflow: hidden;
  /* fondus latéraux : la bande « entre » et « sort » proprement */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent);
}

.contact-track {
  display: flex;
  width: max-content;
  animation: contactScroll var(--gal-dur, 48s) linear infinite;
  will-change: transform;
}
@keyframes contactScroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }   /* piste = 2 passes -> boucle sans couture */
}
/* pause au survol / focus clavier (desktop) */
@media (hover: hover) and (pointer: fine) {
  .contact-marquee:hover .contact-track,
  .contact-marquee:focus-within .contact-track { animation-play-state: paused; }
}

/* vignette dans la bande : hauteur fixe, largeur naturelle (override de la grille) */
.contact-track .contact-frame {
  flex: 0 0 auto;
  width: auto;
  height: 148px;
  aspect-ratio: auto;
  margin-right: 6px;                        /* marge portée par l'item -> duplication exacte -> -50% pile */
  border-radius: 3px;
}
.contact-track .contact-img {
  width: auto;
  height: 100%;
  aspect-ratio: auto;
}
html.gsap .contact-track .contact-frame { opacity: 1; }   /* jamais masquées par le reveal « tirage » */

/* Tactile (pas de hover) OU reduced-motion : rail à défilement MANUEL, pas d'auto */
@media (hover: none), (prefers-reduced-motion: reduce) {
  .contact-marquee {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    -webkit-mask-image: none;
            mask-image: none;
  }
  .contact-track { animation: none; }
  .contact-track .contact-frame--dup { display: none; }   /* pas de doublon en scroll manuel */
}

/* ---- VIDÉO : bande pellicule full-bleed (spec v5-pellicule) ---- */

/* Breakout : la bande touche les deux bords. Aucun width:100vw (créerait une
   scrollbar) ; body{overflow-x:clip} écrête le débord du 50vw, scrollbar
   Windows comprise. */
.contact-reel {
  position: relative;
  margin-top: 24px;
  margin-inline: calc(50% - 50vw);   /* full-bleed sans overflow horizontal */
  width: auto;
  padding: 30px 0;                   /* place pour les perforations haut/bas */
  background: #14202880;             /* voile encre léger, cohérent site clair */
  isolation: isolate;                /* les fondus de bords passent au-dessus proprement */
}

/* Perforations dessinées, en haut ET en bas, CSS pur (conservées, repositionnées) */
.contact-reel::before,
.contact-reel::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 16px;
  background-image: repeating-linear-gradient(
    to right,
    transparent 0 10px,
    var(--paper) 10px 22px,
    transparent 22px 32px
  );
  background-size: 32px 10px;
  background-position: center;
  background-repeat: repeat-x;
  opacity: 0.85;
  pointer-events: none;
  z-index: 2;
}
.contact-reel::before { top: 8px; }
.contact-reel::after  { bottom: 8px; }

/* Fondus de bords : dégradés G/D qui suggèrent la continuité. */
.contact-reel .reel-fade {
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(40px, 7vw, 120px);
  z-index: 3;
  pointer-events: none;
  transition: opacity 0.25s ease;
}
.contact-reel .reel-fade-left {
  left: 0;
  background: linear-gradient(to right, var(--paper) 12%, transparent);
}
.contact-reel .reel-fade-right {
  right: 0;
  background: linear-gradient(to left, var(--paper) 12%, transparent);
}
/* Au bord, le fondu correspondant s'efface (plus rien à annoncer de ce côté). */
.contact-reel.is-at-start .reel-fade-left { opacity: 0; }
.contact-reel.is-at-end   .reel-fade-right { opacity: 0; }

/* Viewport scrollable : c'est lui qu'on pilote en scrollLeft. */
.contact-reel-strip {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  padding: 4px max(clamp(1.25rem, 4vw, 3rem), calc(50vw - var(--maxw) / 2 + clamp(1.25rem, 4vw, 3rem)));
  scroll-behavior: auto;             /* le JS gère le smooth des flèches lui-même */
  -webkit-overflow-scrolling: touch;
}

/* Cellule = cadre image (haut) + légende (bas) */
.reel-cell {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Frame pellicule AGRANDIE (v5 : hauteur 360) */
.contact-vframe {
  position: relative;
  flex: 0 0 auto;
  height: 360px;
  border: 2px solid #0d161c;
  border-radius: 2px;
  background: #0d161c;
  overflow: hidden;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.contact-vframe .video-thumb { height: 100%; width: 100%; }

/* 16:9 -> 360*16/9 = 640 ; portrait -> 360*9/16 = 202 (entier, non rogné) */
.contact-vframe:not(.contact-vframe-portrait):not(.contact-vframe-soon) { width: 640px; }
.contact-vframe-portrait { width: 202px; }
.contact-vframe-soon     { width: 260px; display: block; padding: 0; cursor: pointer; }
.reel-cell-portrait, .reel-cell-soon { }  /* largeur portée par la .contact-vframe interne */

/* Les portraits restent ENTIERS et lisibles : contain, pas cover */
.contact-vframe-portrait .video-thumb-fg { object-fit: contain; }

.contact-vlabel {
  position: absolute;
  left: 6px;
  bottom: 6px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.04em;
  color: var(--paper);
  background: rgba(13, 22, 28, 0.7);
  padding: 1px 5px;
  border-radius: 2px;
  pointer-events: none;
  z-index: 4;
}
/* Portrait : .video-thumb-tc (durée) occupe DÉJÀ le bas-gauche en permanence
   -> l'étiquette REF passe en haut pour ne pas se superposer (chevauchement
   pré-existant, d'autant plus visible que le nom du projet est long). */
.contact-vframe-portrait .contact-vlabel { top: 6px; bottom: auto; }

/* Frame « bientôt » hachurée (conservée) */
.contact-vframe-soon {
  border-style: dashed;
  border-color: var(--brass);
  background:
    repeating-linear-gradient(45deg,
      rgba(138, 104, 58, 0.14) 0 8px,
      transparent 8px 16px),
    #101b22;
}
.contact-soon {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
}
.contact-soon-badge {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brass);
  border: 1px solid var(--brass);
  border-radius: 999px;
  padding: 2px 10px;
}
.contact-soon-text {
  font-family: var(--font-display);
  font-size: 0.95rem;
  line-height: 1.25;
  color: var(--paper);
}

/* LÉGENDE sous chaque frame */
.reel-cap {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 0 2px;
  max-width: 100%;
}
.reel-cap-title {
  font-family: var(--font-display);
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.reel-cap-meta {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.reel-cap-dur {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  color: var(--brass);
}

/* Hover frame (desktop) : élévation légère */
@media (hover: hover) and (pointer: fine) {
  .contact-vframe:hover,
  .contact-vframe-soon:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-lift);
    border-color: var(--brass);
    z-index: 5;
  }
}
.contact-vframe .video-thumb:focus-visible,
.contact-vframe-soon:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  z-index: 6;
}

/* Flèches ‹ › : desktop only (masquées par défaut, affichées en hover+fine) */
.reel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  display: none;                     /* caché par défaut → mobile/tactile */
  width: 42px;
  height: 42px;
  border-radius: 999px;
  border: 1px solid var(--brass);
  background: rgba(20, 32, 40, 0.82);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  transition: background 0.18s ease, transform 0.12s ease, opacity 0.2s ease;
}
.reel-arrow-prev { left: clamp(8px, 2vw, 24px); }
.reel-arrow-next { right: clamp(8px, 2vw, 24px); }
.reel-arrow:hover { background: var(--brass); }
.reel-arrow:active { transform: translateY(-50%) scale(0.94); }
.reel-arrow:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
/* Flèche masquée/désactivée quand on est déjà au bout correspondant */
.contact-reel.is-at-start .reel-arrow-prev,
.contact-reel.is-at-end   .reel-arrow-next { opacity: 0.35; pointer-events: none; }

@media (hover: hover) and (pointer: fine) {
  .reel-arrow { display: flex; }
}

/* Stagger « tirage » vidéo (conservé, cible inchangée : .contact-vframe) */
html.gsap .contact-vframe { opacity: 0; }
html.gsap .contact-vframe.is-pulled { opacity: 1; }

/* ---- MOBILE : full-bleed aussi, swipe naturel, flèches masquées ---- */
@media (max-width: 640px) {
  /* Photo : 3 colonnes strictes (inchangé) */
  .contact-frames { grid-template-columns: repeat(3, 1fr); gap: 4px; }
  .contact-sheet { padding: 12px 10px 14px; gap: 16px; }
  .contact-group-label { font-size: 0.66rem; gap: 8px; }

  /* Vidéo : PAS de scroll-snap ici - `x proximity` rabat chaque incrément de la
     dérive auto (rAF scrollLeft) vers le point d'ancrage : pellicule figée à 0.
     Le swipe manuel reste fluide sans snap (esprit pellicule qui glisse). */
  .contact-reel { margin-top: 16px; padding: 22px 0; }
  .contact-reel-strip {
    padding: 4px 12px;
    gap: 10px;
  }
  .contact-vframe { height: 260px; }
  .contact-vframe:not(.contact-vframe-portrait):not(.contact-vframe-soon) { width: 82vw; max-width: 420px; }
  .contact-vframe-portrait { width: 146px; }
  .contact-vframe-soon { width: 60vw; max-width: 240px; }
  .reel-arrow { display: none !important; }   /* flèches masquées en mobile */
  .reel-fade { width: 32px; }
  .reel-cap-title { font-size: 0.82rem; }
}

/* ---- REDUCED MOTION : tout visible, aucun stagger ---- */
@media (prefers-reduced-motion: reduce) {
  html.gsap .contact-frame,
  html.gsap .contact-vframe { opacity: 1 !important; transform: none !important; }
}

/* ================= POSTE 03 - NOMENCLATURE ================= */
.nomen {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 clamp(1rem, 4vw, 2rem);
}

/* ---- Feuille de plan normée (remplace l'ancienne bande de vignettes) ---- */
.nomen-sheet{
  position: relative;
  border: 1px solid var(--line);
  border-radius: 4px;
  /* Fond millimétré léger : mailles fines (8px) + traits forts tous les 40px */
  background:
    repeating-linear-gradient(0deg,
      color-mix(in srgb, var(--blue-deep) 4%, transparent) 0 1px, transparent 1px 8px),
    repeating-linear-gradient(90deg,
      color-mix(in srgb, var(--blue-deep) 4%, transparent) 0 1px, transparent 1px 8px),
    repeating-linear-gradient(0deg,
      color-mix(in srgb, var(--blue-deep) 7%, transparent) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(90deg,
      color-mix(in srgb, var(--blue-deep) 7%, transparent) 0 1px, transparent 1px 40px),
    var(--card);
  box-shadow: var(--shadow);
  padding: 2.4rem;
  overflow: hidden;                 /* le fond millimétré ne bave pas hors du cadre arrondi */
}

/* Cadre à marges (double filet) */
.nomen-sheet::before{
  content: ""; position: absolute; inset: 0.9rem;
  border: 1px solid color-mix(in srgb, var(--ink) 55%, transparent);
  pointer-events: none;
}
.nomen-sheet::after{
  content: ""; position: absolute; inset: 1.5rem;
  border: 1px solid var(--line);
  pointer-events: none;
}

/* Repères alphanumériques sur les bords (entre les deux filets) */
.nomen-marks{
  position: absolute; inset: 0.9rem; pointer-events: none;
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.05em;
  color: var(--ink-soft);
}
.nomen-marks span{ position: absolute; transform: translate(-50%,-50%); line-height: 1; }
.nomen-marks .nm-top{ top: 0.3rem; }
.nomen-marks .nm-bot{ top: auto; bottom: -0.3rem; transform: translate(-50%,50%); }
.nomen-marks .nm-lft{ left: 0.3rem; }
.nomen-marks .nm-rgt{ left: auto; right: -0.3rem; transform: translate(50%,-50%); }

/* Cartouche de coin (bas-droite) */
.nomen-cartouche{
  position: absolute; right: 1.5rem; bottom: 1.5rem; z-index: 4;
  display: flex; flex-direction: column;
  font-family: var(--font-mono); font-size: 0.56rem; line-height: 1.3;
  color: var(--ink);
  background: var(--card);
  border: 1px solid color-mix(in srgb, var(--ink) 55%, transparent);
}
.nomen-cartouche b{
  padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--line);
  letter-spacing: 0.08em; font-weight: 600; color: var(--ink);
  background: color-mix(in srgb, var(--blue-deep) 4%, var(--card));
}
.nomen-cartouche .cart-grid{ display: grid; grid-template-columns: repeat(3, auto); }
.nomen-cartouche .cart-grid span{
  padding: 0.3rem 0.55rem; border-right: 1px solid var(--line);
  color: var(--ink-soft); white-space: nowrap; letter-spacing: 0.03em;
}
.nomen-cartouche .cart-grid span:last-child{ border-right: 0; }

/* Aire de dessin des figures + lignes de rappel.
   margin-bottom réserve la bande des dots ①..④ SOUS les figures. */
.nomen-plate{ position: relative; z-index: 2; margin: 0.8rem 0 2.6rem; }

.nomen-figs{
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(0.75rem, 2.4vw, 1.4rem);
}
.nomen-fig{ position: relative; }

/* La vignette EST le bouton (button.fiche-open - slugs conservés) */
.nomen-fig .fiche-open{
  appearance: none; display: block; width: 100%; padding: 0; margin: 0;
  border: 0; background: transparent; cursor: pointer; text-align: left;
  color: inherit; font: inherit;
}
.nomen-shot{
  position: relative; aspect-ratio: 4 / 3;   /* hauteur définie -> lazy-img se charge (piège v3) */
  overflow: hidden;
  border: 1px solid var(--ink);
  background: var(--blue-tint);
  box-shadow: 0 0 0 3px var(--card), var(--shadow);   /* liseré blanc = tirage posé sur la feuille */
  transition: box-shadow 0.25s, border-color 0.25s;
}
.nomen-shot img{
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 0.4s;
}

/* Placeholder honnête (atelier-01 absent) - repris de v3/v4 */
.nomen-shot.is-empty img{ display: none; }
.nomen-shot.is-empty::after{
  content: "à venir : " attr(data-file);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 0.5rem; text-align: center;
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.04em;
  color: var(--ink-soft);
  background: repeating-linear-gradient(45deg,
    var(--blue-tint) 0 8px, var(--paper-2) 8px 16px);
}

/* Légende mono sous chaque figure */
.nomen-cap{
  display: flex; justify-content: space-between; gap: 0.4rem;
  margin-top: 0.45rem;
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.03em;
  color: var(--ink-soft);
}
.nomen-cap b{ color: var(--ink); font-weight: 600; letter-spacing: 0.06em; }

/* Repère cerclé posé sur la figure (coin haut-gauche) */
.nomen-rep{
  position: absolute; top: -0.55rem; left: -0.55rem; z-index: 3;
  width: 1.55rem; height: 1.55rem;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 0.85rem; line-height: 1;
  color: var(--ink); background: var(--card);
  border: 1px solid var(--ink); border-radius: 50%;
  box-shadow: var(--shadow);
  transition: color 0.2s, background 0.2s, border-color 0.2s, transform 0.2s;
}

/* Lignes de rappel SVG (traits fins vers repères cerclés sous les figures) */
.nomen-leaders{
  position: absolute; left: 0; bottom: -2.1rem;
  width: 100%; height: 2.1rem; overflow: visible; pointer-events: none;
}
.nomen-leader{ stroke: var(--line); stroke-width: 1; fill: none; }
.nomen-dot{
  stroke: var(--line); stroke-width: 1; fill: var(--card);
  transition: stroke 0.2s, fill 0.2s;
}
/* Chiffre HTML centré sur chaque dot (dot cy=86/120 dans une bande de 2.1rem) */
.nomen-dot-num{
  position: absolute; bottom: -1.6rem; transform: translate(-50%, 50%);
  font-family: var(--font-mono); font-size: 0.7rem; line-height: 1;
  color: var(--ink-soft); pointer-events: none; transition: color 0.2s;
}

/* ---- État allumé (couplage figure ↔ repère, posé par runNomenclature) ---- */
.nomen-fig.is-lit .nomen-rep{
  color: var(--card); background: var(--brass); border-color: var(--brass);
  transform: scale(1.08);
}
.nomen-fig.is-lit .nomen-shot{
  border-color: var(--brass);
  box-shadow: 0 0 0 3px var(--card),
              0 0 0 6px color-mix(in srgb, var(--brass) 30%, transparent);
}
.nomen-fig.is-lit .nomen-shot img{ transform: scale(1.04); }
.nomen-fig.is-lit .nomen-cap b{ color: var(--brass); }
.nomen-leader.is-lit, .nomen-dot.is-lit{ stroke: var(--brass); }
.nomen-dot.is-lit{ fill: color-mix(in srgb, var(--brass) 18%, transparent); }
.nomen-dot-num.is-lit{ color: var(--brass); font-weight: 600; }

/* Focus clavier visible sur le trigger (la vignette entière) */
.nomen-fig .fiche-open:focus-visible{ outline: none; }
.nomen-fig .fiche-open:focus-visible .nomen-shot{
  outline: 2px solid var(--brass); outline-offset: 3px;
}

/* ---- Table de nomenclature ---- */
.nomen-table {
  width: 100%;
  margin-top: 2.4rem;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 0.82rem;
}
.nomen-table thead th {
  text-align: left;
  padding: 0.6rem 0.9rem;
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  border-bottom: 1.5px solid var(--ink);
  white-space: nowrap;
}
.nomen-col-rep { width: 3.5rem; }
.nomen-col-sta { width: 6.5rem; }

.nomen-row {
  border-bottom: 1px solid var(--line);
  transition: background 0.18s;
}
.nomen-row td {
  padding: 0.7rem 0.9rem;
  vertical-align: middle;
  color: var(--ink);
}
.nomen-row:hover,
.nomen-row:focus-within {
  background: var(--blue-tint);
}

/* Row porteuse (position: relative) -> le pseudo-élément du bouton couvre TOUTE la row,
   sans débordement horizontal. Le <tr> reste un ancrage valide pour position:absolute. */
.nomen-row { position: relative; }
.nomen-cell-rep .fiche-open {
  appearance: none;
  border: 0; background: transparent; cursor: pointer;
  padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.9rem;
  color: var(--ink);
}
.nomen-rep-mark {
  font-family: var(--font-mono);
  font-size: 1.05rem; line-height: 1;
}
/* Pseudo-élément qui étend la zone cliquable à toute la <tr> (ancré sur .nomen-row) */
.nomen-cell-rep .fiche-open::after {
  content: "";
  position: absolute;
  inset: 0;              /* couvre la row entière, aucun débord */
}

.nomen-cell-des { color: var(--ink); white-space: normal; }
.nomen-ref {
  display: inline-block;
  margin-right: 0.6rem;
  color: var(--brass);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
}
.nomen-cell-out, .nomen-cell-liv { color: var(--ink-soft); }

.nomen-status {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.nomen-status.is-livre { color: #7a5a30; background: color-mix(in srgb, var(--brass) 14%, transparent); }
.nomen-status.is-cours { color: var(--blue-deep); background: var(--blue-tint); }
.nomen-status.is-actif { color: var(--ok);        background: color-mix(in srgb, var(--ok) 12%, transparent); }

/* Focus clavier visible sur le trigger */
.nomen-cell-rep .fiche-open:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 3px;
  border-radius: 4px;
}
/* Recopie de l'état allumé quand la row a le focus clavier (pas seulement hover) */
.nomen-row:focus-within .nomen-rep-mark { color: var(--brass); }

/* Utilitaire lecteur d'écran (si absent de styles.css) */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- Mobile : feuille en 2×2 + table en liste compacte ---- */
@media (max-width: 640px) {
  /* --- Feuille en 2×2, rappels masqués proprement --- */
  .nomen-sheet{ padding: 1.5rem 1.1rem; }
  .nomen-sheet::before{ inset: 0.55rem; }
  .nomen-sheet::after{ inset: 1rem; }
  .nomen-marks{ display: none; }                 /* repères de bord masqués (place réduite) */
  .nomen-figs{ grid-template-columns: repeat(2, 1fr); gap: 1.4rem 1rem; }
  .nomen-plate{ margin: 0.6rem 0 3.4rem; }        /* bande basse réservée au cartouche */
  .nomen-leaders, .nomen-dot-num{ display: none; } /* lignes de rappel masquées en 2×2 */
  .nomen-cap{ font-size: 0.56rem; }
  .nomen-cartouche{ right: 1rem; bottom: 1rem; font-size: 0.52rem; }
  .nomen-cartouche b{ padding: 0.28rem 0.5rem; }
  .nomen-cartouche .cart-grid span{ padding: 0.24rem 0.45rem; }

  /* --- Table : liste compacte (INCHANGÉ vs v4) --- */
  .nomen-table thead { display: none; }
  .nomen-table, .nomen-table tbody, .nomen-row, .nomen-row td { display: block; width: 100%; }
  .nomen-row {
    /* position: relative déjà posé plus haut (bouton étendu) */
    display: grid;
    grid-template-columns: 2rem 1fr;
    grid-template-areas:
      "rep des"
      "rep sta";
    gap: 0.15rem 0.6rem;
    align-items: center;
    padding: 0.7rem 0.5rem;
  }
  .nomen-row td { padding: 0; }
  .nomen-cell-rep { grid-area: rep; }
  .nomen-cell-des { grid-area: des; font-size: 0.8rem; }
  .nomen-cell-sta { grid-area: sta; }
  .nomen-cell-out, .nomen-cell-liv { display: none; }   /* dans la modale */
}

/* ---- reduced-motion : tout tracé, aucun mouvement ---- */
@media (prefers-reduced-motion: reduce) {
  .nomen-leader, .nomen-dot { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .nomen-shot img, .nomen-rep { transition: none; }
}

/* =====================================================================
   02.C - TABLEAU EN LIEGE (v8 : full-bleed VRAI + deco + etagere + cascade)
   Full-bleed : meme breakout que la pellicule (.contact-reel). body{overflow-x:clip}
   ecrete deja le debord du 50vw. v8 : la surface fait 100% de large (plus de
   cap 1180px) -> elle touche les 2 bords. Hauteur plafonnee, objets recomposes
   sur toute la largeur, coords en % (validees dans specs/preview/tableau-v8.html).
   ===================================================================== */

.tableau-liege {
  --wild-red: #b3241f;
  --poste-accent: var(--brass);              /* defaut = laiton Camera (avant apparition) */
  position: relative;
  margin-top: 28px;
  margin-inline: calc(50% - 50vw);           /* full-bleed sans scrollbar */
  width: 100vw;
  padding: 10px 0;                            /* le cadre bois affleure ce liseré haut/bas */
  isolation: isolate;
  transition: color 0.5s ease;
}
.tableau-liege.is-inview { --poste-accent: var(--wild-red); }
html:not(.gsap) .tableau-liege { --poste-accent: var(--wild-red); }

/* ---- Cadre bois (liseré haut/bas ; plus de cap, va bord a bord) ---- */
.liege-frame {
  position: absolute; inset: 0;
  background: linear-gradient(135deg, #7a5a30, #a37c44 30%, #6f4f28 70%, #8a683a);
  box-shadow: inset 0 0 0 2px rgba(0,0,0,0.12), 0 10px 30px -14px rgba(0,0,0,0.5);
  z-index: 0; pointer-events: none;
}
/* ---- Surface liege PLEINE LARGEUR, hauteur plafonnee ---- */
.liege-surface {
  position: relative;
  container-type: inline-size;               /* punaises/scotch/polaroid en cqw */
  width: 100%;
  height: clamp(320px, 38vw, 660px);         /* min 320 : sur mobile/tablette la planche est plus panoramique -> moins de liege vide en bas (compo pensee large) */
  background-color: #c9a36b;
  background-image:
    radial-gradient(circle at 18% 12%, rgba(255,255,255,0.10), transparent 45%),
    radial-gradient(circle at 88% 92%, rgba(60,40,15,0.14), transparent 50%),
    var(--liege-tex);
  background-size: auto, auto, 1120px;         /* texture liege repetee (pas etiree sur 100vw) */
  background-repeat: no-repeat, no-repeat, repeat;
  box-shadow: inset 0 0 80px rgba(90,60,20,0.30);
  overflow: hidden;
  z-index: 1;
}

/* ---- Objet epingle (generique) ---- */
.pin-obj {
  position: absolute;
  margin: 0;
  transform: rotate(var(--rot, 0deg));
  transform-origin: 50% 8%;                   /* pivote depuis le point de fixation en haut */
  transition: transform 0.28s cubic-bezier(.2,.7,.3,1), filter 0.28s ease;
  filter: drop-shadow(0 7px 11px rgba(40,25,10,0.38));
  cursor: pointer;                            /* delegation : tout objet ouvre la fiche */
  will-change: transform;
}
.pin-obj .obj-media,
.pin-obj .obj-img,
.pin-obj .polaroid { display: block; width: 100%; height: auto; }
.obj-media { background-repeat: no-repeat; background-position: center bottom; background-size: contain; }

/* ---- PUNAISE 3D (SVG externe, pointe de l'aiguille au bas-centre du viewBox) ---- */
.pin {
  --pin-w: clamp(16px, 1.9cqw, 30px);
  position: absolute;
  width: var(--pin-w);
  aspect-ratio: 64 / 80;
  background: url('assets/img/wild/punaise-red.svg') no-repeat center / contain;
  z-index: 7; pointer-events: none;
  filter: drop-shadow(2px 4px 3px rgba(0,0,0,0.4));
}
.pin-white { background-image: url('assets/img/wild/punaise-white.svg'); }
.pin-blue  { background-image: url('assets/img/wild/punaise-blue.svg'); }
/* ancrage : la pointe de l'aiguille (bas-centre du SVG) doit tomber sur l'objet,
   ~10px sous le bord haut -> on remonte l'element de sa propre hauteur (w*80/64) - 10px */
.pin-top { top: calc(-1 * var(--pin-w) * 80 / 64 + 10px); left: 50%; transform: translateX(-50%); }
.pin-loose { z-index: 4; }                    /* punaise seule plantee dans le liege (deco) */

/* ---- SCOTCH ---- */
.tape {
  position: absolute; width: 5cqw; max-width: 62px; height: 1.7cqw; max-height: 22px;
  background: linear-gradient(rgba(232,228,205,0.6), rgba(210,205,180,0.52));
  border-left: 1px dashed rgba(255,255,255,0.4); border-right: 1px dashed rgba(255,255,255,0.4);
  box-shadow: 0 1px 2px rgba(0,0,0,0.14); z-index: 7; pointer-events: none;
}
.tape-tl { top: -10px; left: 6%;  transform: rotate(-22deg); }
.tape-tr { top: -10px; right: 6%; transform: rotate(20deg); }
.tape-solo {                                  /* bout de scotch seul (deco) */
  position: absolute; width: 3.2cqw; height: 1.5cqw; z-index: 5;
  background: linear-gradient(rgba(232,228,205,0.5), rgba(210,205,180,0.42));
  border-left: 1px dashed rgba(255,255,255,0.35); border-right: 1px dashed rgba(255,255,255,0.35);
  box-shadow: 0 1px 2px rgba(0,0,0,0.1); pointer-events: none;
}

/* Ombre de contact des stickers */
.sticker-shadow {
  position: absolute; inset: 8% 8% -2% 8%; border-radius: 50%;
  background: rgba(30,20,10,0.26); filter: blur(6px); z-index: -1; pointer-events: none;
}
.obj-sticker { filter: drop-shadow(0 3px 5px rgba(40,25,10,0.3)); }

/* ---- POLAROID (cadre + legende en cqw) ---- */
.polaroid { display: block; background: #fdfdfb; padding: 0.7cqw 0.7cqw 2.4cqw; box-shadow: 0 10px 18px rgba(0,0,0,0.32); }
.polaroid .obj-img { width: 100%; height: auto; }
.polaroid-cap {
  display: block; margin-top: 0.5cqw; text-align: center;
  font-family: "Bricolage Grotesque", var(--font-display);
  font-size: 1.15cqw; color: #2a3138; transform: rotate(-1.5deg); white-space: nowrap;
}
.dogear {                                     /* coin corne (deco) */
  position: absolute; right: -1px; bottom: -1px; width: 2cqw; height: 2cqw; z-index: 3;
  background: linear-gradient(135deg, transparent 48%, #ded9c8 50%, #b8b09a 100%);
  box-shadow: -1px -1px 2px rgba(0,0,0,0.12);
}

/* ---- ETAGERE BOIS vissee (porte ecocups + briquet) ---- */
.liege-shelf { position: absolute; z-index: 4; }
.shelf-plank {
  position: absolute; left: 0; right: 0; bottom: 0; height: 11%;
  background: linear-gradient(180deg, #a9793d 0%, #855a28 42%, #63421b 100%);
  border-radius: 3px 3px 2px 2px;
  box-shadow: 0 10px 16px -5px rgba(0,0,0,0.5), inset 0 2px 0 rgba(255,255,255,0.2), inset 0 -3px 6px rgba(0,0,0,0.38);
  z-index: 5;
}
.shelf-plank::before {                        /* chant sombre (tranche) */
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 6px;
  background: linear-gradient(180deg, #4d3115, #372209); border-radius: 0 0 3px 3px;
}
.shelf-screw {                                /* vis dans le liege */
  position: absolute; width: 9px; height: 9px; border-radius: 50%; z-index: 6;
  background: radial-gradient(circle at 35% 30%, #f0f0f0, #8f8f8f 60%, #4a4a4a);
  box-shadow: 0 1px 1px rgba(0,0,0,0.5);
}
.shelf-screw::after { content: ""; position: absolute; left: 15%; right: 15%; top: 44%; height: 12%; background: rgba(30,30,30,0.7); border-radius: 1px; }
.shelf-screw.s-l { left: 14%; bottom: 9%; }
.shelf-screw.s-r { right: 14%; bottom: 9%; }

/* ---- INSCRIPTIONS feutre deco (cork vide) ---- */
.liege-deco { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.ins {
  position: absolute; font-family: "Bricolage Grotesque", var(--font-display); font-weight: 800;
  color: rgba(60,38,20,0.42); text-transform: uppercase; letter-spacing: 0.05em;
  white-space: nowrap; mix-blend-mode: multiply;
}
.ins-red { color: rgba(150,30,25,0.5); }
.ins-underline { border-bottom: 2px solid currentColor; padding-bottom: 2px; }
.ins-star { font-size: 1.4cqw; }

/* ---- FILS d'enquete (stroke non-scaling pour rester fin sous preserveAspectRatio none) ---- */
.liege-threads { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 3; pointer-events: none; overflow: visible; }
.liege-threads path {
  fill: none; stroke: #a11f1a; stroke-width: 1.4; vector-effect: non-scaling-stroke;
  opacity: 0.66; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.3)); stroke-linecap: round;
}

/* ---- ETIQUETTE nom (cartouche mono, cachee au repos, revele au hover) ---- */
.obj-tag {
  position: absolute; left: 50%; bottom: -10px; transform: translate(-50%, 6px);
  padding: 3px 8px; font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.04em;
  white-space: nowrap; color: #f4f7f9; background: rgba(31,46,56,0.92); border-radius: 3px;
  box-shadow: 0 4px 10px rgba(0,0,0,0.3); opacity: 0; pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease; z-index: 9;
}

/* ---- ECOCUP slot (le canvas anime se branche dedans) ---- */
.ecocup-slot { position: relative; width: 100%; }
.ecocup-slot canvas, .ecocup-slot .ecocup-fallback { display: block; width: 100%; height: auto; }
.ecocup-slot.has-canvas .ecocup-fallback { display: none; }

/* ---- HOVER : l'objet se redresse + se souleve + etiquette ---- */
@media (hover: hover) and (pointer: fine) {
  .pin-obj:hover {
    transform: rotate(calc(var(--rot) * 0.15)) translateY(-6px);
    filter: drop-shadow(0 14px 20px rgba(40,25,10,0.45));
    z-index: 20;
  }
  .pin-obj:hover .obj-tag { opacity: 1; transform: translate(-50%, 0); }
}
.tableau-cta:focus-visible { outline: 2px solid var(--wild-red); outline-offset: 3px; }

/* ---- CTA + intro ---- */
.tableau-intro { max-width: var(--maxw); margin: 0 auto 4px; font-size: 0.98rem; color: var(--ink-soft); }
.tableau-cta {
  display: inline-flex; align-items: center; gap: 0.4em; margin-left: 0.3em;
  padding: 0.3em 0.7em; min-height: 40px; font-family: var(--font-mono);
  font-size: 0.8rem; font-weight: 600; color: #fff; background: var(--wild-red, #b3241f);
  border: none; border-radius: 6px; cursor: pointer; text-decoration: none;
  transition: background 0.2s ease, transform 0.15s ease;
}
.tableau-cta:hover { background: #8f1c18; transform: translateY(-1px); }
.tableau-cta-foot { position: relative; z-index: 2; text-align: center; margin-top: 20px; }

/* ===================================================================
   Positionnement (v8 large ~2.4:1) - coords % de .liege-surface.
   Validees dans specs/preview/tableau-v8.html (captures specs/verify/v8-preview-*).
   =================================================================== */
.obj-drapeau  { left: 0.5%;  top: 7%;   width: 14.5%; aspect-ratio: 550 / 674; }
.obj-table    { left: 16%;   top: 4%;   width: 15%;   aspect-ratio: 800 / 754; }
.obj-tablecol { left: 31%;   top: 6%;   width: 15%;   aspect-ratio: 800 / 754; }
.obj-logo     { left: 57%;   top: 4%;   width: 11%;   aspect-ratio: 1 / 1;     }
.obj-logo2    { left: 69.5%; top: 6%;   width: 11%;   aspect-ratio: 1 / 1;     }
.obj-logo3    { left: 82%;   top: 10%;  width: 10.5%; aspect-ratio: 1 / 1;     }
.obj-polaroid { left: 36%;   top: 33%;  width: 20%;                            }
.obj-capote   { left: 64%;   top: 48%;  width: 9.5%;  aspect-ratio: 800 / 789; }
.obj-sweat    { left: 2%;    top: 43%;  width: 15%;   aspect-ratio: 352 / 460; }
.obj-tote     { left: 18.5%; top: 51%;  width: 9%;    aspect-ratio: 450 / 836; }
.liege-shelf  { left: 73.5%; top: 45%;  width: 26%;   height: 46%; }
/* objets poses sur l'etagere (bottom = sommet du plateau a 11%) */
.obj-ecocup   { left: 4%;   bottom: 11%; width: 36%; aspect-ratio: 520 / 820; }
.obj-ecocup2  { left: 44%;  bottom: 11%; width: 36%; aspect-ratio: 520 / 820; }
.obj-briquet  { left: 84%;  bottom: 11%; width: 13%; aspect-ratio: 260 / 800; }
.pin-obj .obj-media { height: 100%; }
/* logo3 au ras du bord droit : etiquette alignee a droite (sinon coupee par overflow:hidden) */
.obj-logo3 .obj-tag { left: auto; right: 0; transform: translate(0, 6px); }
.pin-obj.obj-logo3:hover .obj-tag { transform: translate(0, 0); }

/* =====================================================================
   CASCADE D'EPINGLAGE (v8) - JS pose .is-cascade (cache) puis .is-armed (joue).
   Sans JS / reduced-motion : rien n'est cache (progressive enhancement).
   Anim en fill "backwards" seulement -> apres la chute, l'objet reprend son
   etat CSS de base (transform:rotate(--rot)) et le :hover refonctionne.
   ===================================================================== */
.tableau-liege.is-cascade .pin-obj,
.tableau-liege.is-cascade .pin,
.tableau-liege.is-cascade .tape,
.tableau-liege.is-cascade .tape-solo,
.tableau-liege.is-cascade .liege-threads,
.tableau-liege.is-cascade .liege-deco { opacity: 0; }

.tableau-liege.is-armed .pin-obj {
  animation: pinDrop 0.55s var(--delay, 0s) cubic-bezier(.18,1.04,.35,1) backwards;
}
@keyframes pinDrop {
  0%   { opacity: 0; transform: translateY(-34px) rotate(calc(var(--rot, 0deg) - 5deg)); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: translateY(0) rotate(var(--rot, 0deg)); }
}
/* la punaise s'enfonce juste apres le design (offset court = design puis punaise, groupes ;
   la vague G->D vient du --delay pose par JS selon la position horizontale de l'objet.
   scale = propriete separee du transform de positionnement pin-top, donc pas de conflit) */
.tableau-liege.is-armed .pin,
.tableau-liege.is-armed .tape,
.tableau-liege.is-armed .tape-solo {
  animation: pinStab 0.26s calc(var(--delay, 0.3s) + 0.22s) backwards;
}
@keyframes pinStab {
  0%   { opacity: 0; scale: 0.2; }
  70%  { opacity: 1; scale: 1.18; }
  100% { opacity: 1; scale: 1; }
}
/* les fils sont traces (draw-on) par JS, punaise apres punaise, apres leur epinglage.
   .liege-threads reste cache par .is-cascade { opacity:0 } tant que non arme. */
.tableau-liege.is-armed .liege-deco    { animation: tabFade 0.8s 0.5s backwards; }
@keyframes tabFade { from { opacity: 0; } to { opacity: 1; } }

/* =====================================================================
   FALLBACKS
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  .pin-obj { transition: none; transform: rotate(var(--rot)); }
  .pin-obj:hover { transform: rotate(var(--rot)); filter: none; }
  /* securite : si .is-cascade/.is-armed etaient poses, ne rien cacher/animer */
  .tableau-liege.is-cascade .pin-obj, .tableau-liege.is-cascade .pin,
  .tableau-liege.is-cascade .tape, .tableau-liege.is-cascade .tape-solo,
  .tableau-liege.is-cascade .liege-threads, .tableau-liege.is-cascade .liege-deco { opacity: 1; }
  .tableau-liege .pin-obj, .tableau-liege .pin, .tableau-liege .tape,
  .tableau-liege .tape-solo, .tableau-liege .liege-threads, .tableau-liege .liege-deco { animation: none; }
  .tableau-liege { transition: none; }
}

/* Responsive <= 640 px : MEME scene reduite (choix Felix). Positions en %, accastillage
   en cqw -> tout scale seul ; la hauteur clamp(min 360) garde une planche ~carree, pas
   un ruban ecrase. On masque juste les etiquettes (illisibles a cette echelle). */
@media (max-width: 640px) {
  .obj-tag { display: none; }
  .tableau-cta { min-height: 44px; padding: 0.5em 1em; }
  .tableau-cta-foot { margin-top: 18px; }
}
