/* Portrait vivant : quatre planches tramées de cases 240 × 300.
 * --e est l'échelle d'affichage. Une trame ne supporte qu'un agrandissement entier
 * en pixels d'écran, sinon elle produit du moiré : ×2 et ×1 partout, ×1,5 seulement
 * sur les écrans d'ordinateur trop bas, où la densité double le rend entier.
 * L'état est porté par des attributs, jamais par un attribut style.
 */
.portrait {
  --e: 2; --c: 1; --l: 1;
  position: absolute; left: 1%; bottom: 0;
  width: calc(240px * var(--e)); height: calc(300px * var(--e));
  image-rendering: pixelated;
  background: url('/images/portrait/bonus.png') no-repeat 0 0 / calc(1200px * var(--e)) calc(300px * var(--e));
}

/* Repos, et état sans script : pose neutre, clignement toutes les quatre secondes. */
.portrait[data-etat="repos"] { animation: portrait-cligne 4s steps(1) infinite; }
@keyframes portrait-cligne {
  0%, 88% { background-position: 0 0; }
  90%, 96% { background-position: calc(-240px * var(--e)) 0; }
  92%, 94% { background-position: calc(-480px * var(--e)) 0; }
  98%, 100% { background-position: 0 0; }
}

/* Chuchotement de la bulle : neutre et bouche entrouverte en alternance. */
.portrait[data-etat="chuchote"] { animation: portrait-chuchote .6s steps(1) 3; }
@keyframes portrait-chuchote {
  0%, 50% { background-position: 0 0; }
  25%, 75% { background-position: calc(-720px * var(--e)) 0; }
}

/* Regard : grille 3 × 3. Colonne 0 = tête tournée vers la droite de l'écran. */
.portrait[data-etat="regard"], .portrait[data-etat="grimace"] {
  background-size: calc(720px * var(--e)) calc(900px * var(--e));
  background-position: calc(-240px * var(--e) * var(--c)) calc(-300px * var(--e) * var(--l));
}
.portrait[data-etat="regard"] { background-image: url('/images/portrait/regards.png'); }
.portrait[data-etat="grimace"] { background-image: url('/images/portrait/grimaces.png'); }
.portrait[data-case="0"] { --c: 0; --l: 0; } .portrait[data-case="1"] { --c: 1; --l: 0; } .portrait[data-case="2"] { --c: 2; --l: 0; }
.portrait[data-case="3"] { --c: 0; --l: 1; } .portrait[data-case="4"] { --c: 1; --l: 1; } .portrait[data-case="5"] { --c: 2; --l: 1; }
.portrait[data-case="6"] { --c: 0; --l: 2; } .portrait[data-case="7"] { --c: 1; --l: 2; } .portrait[data-case="8"] { --c: 2; --l: 2; }

/* Bâillement : seize images, une fois. */
.portrait[data-etat="baille"] {
  background-image: url('/images/portrait/baille.png');
  background-size: calc(3840px * var(--e)) calc(300px * var(--e));
  animation: portrait-baille 3.2s steps(16, jump-none) 1 both;
}
@keyframes portrait-baille { from { background-position: 0 0; } to { background-position: calc(-3600px * var(--e)) 0; } }

[data-portrait-mount][data-deverrouille] .portrait { cursor: pointer; }

/* Bulle et statut : il parle. Vides, ils n'existent pas à l'écran. */
.bulle, .portrait-statut {
  position: absolute; z-index: 2;
  left: calc(1% + 240px * var(--e-bulle, 2) * .82);
  bottom: calc(300px * var(--e-bulle, 2) * .74);
  max-width: 26ch; margin: 0; padding: 10px 14px;
  background: var(--neutral-white); color: var(--brand-blue);
  font-family: var(--font-body); font-size: 15px; line-height: 1.4;
}
.bulle::before, .portrait-statut::before {
  content: ''; position: absolute; left: -9px; bottom: 14px; width: 10px; height: 10px;
  background: var(--neutral-white); clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
.bulle:empty, .portrait-statut:empty { display: none; }

/* Écrans d'ordinateur bas ou étroits : à ×2, le portrait touche le titre sous 900 px de large. */
@media (min-width: 861px) and (max-height: 820px), (min-width: 861px) and (max-width: 999px) {
  .portrait { --e: 1.5; }
  .bulle, .portrait-statut { --e-bulle: 1.5; }
}
/* Grands écrans, 1440p et au-delà : ×3 reste entier, la trame reste nette. */
@media (min-width: 1800px) and (min-height: 1100px) {
  .portrait { --e: 3; }
  .bulle, .portrait-statut { --e-bulle: 3; }
}
/* Écrans 4K sans mise à l'échelle : ×4, toujours entier. */
@media (min-width: 2800px) and (min-height: 1500px) {
  .portrait { --e: 4; }
  .bulle, .portrait-statut { --e-bulle: 4; }
}
@media (max-width: 860px) {
  .portrait { --e: 1; position: relative; left: auto; bottom: auto; }
  /* Au téléphone, la bulle flotte sur le buste : elle ne décale jamais le titre. */
  .bulle, .portrait-statut { left: 50%; bottom: auto; top: calc(16px + 212px); transform: translateX(-50%); width: max-content; max-width: min(26ch, calc(100% - 40px)); }
  .bulle::before, .portrait-statut::before { left: calc(50% - 5px); top: -9px; bottom: auto; clip-path: polygon(0 100%, 50% 0, 100% 100%); }
}
@media (prefers-reduced-motion: reduce) {
  .portrait[data-etat] { animation: none; }
}
/* Sans les deux capacités, details conserve intégralement son rendu natif. */
@supports selector(details::details-content) and (interpolate-size: allow-keywords) {
  @media (prefers-reduced-motion: no-preference) {
    .liste details { interpolate-size:allow-keywords; }
    .liste details::details-content {
      block-size:0;
      overflow:clip;
    }
    /* La recherche et les fragments révèlent le contenu immédiatement.
       Seule l’ouverture depuis le summary prend le temps de se déplier. */
    .liste details:focus-within::details-content {
      transition:block-size .22s ease-out, content-visibility .22s allow-discrete;
    }
    .liste details:has(:target)::details-content { transition:none; }
    .liste details[open]::details-content { block-size:auto; }
  }
}

/* Navigation entre documents de même origine, sans intercepter les liens. */
@view-transition { navigation:auto; }
.site-head { view-transition-name:site-header; }
::view-transition-group(*) { animation-duration:.25s; animation-timing-function:ease-out; }
::view-transition-old(*), ::view-transition-new(*) { animation-duration:.25s; }
/* L’en-tête d’arrivée reste net, sans fondu ni interpolation de sa géométrie. */
::view-transition-group(site-header),
::view-transition-new(site-header) { animation:none; }
::view-transition-old(site-header) { display:none; }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation:none; }
}
.comparison-graph .wrap { position:relative; }
.comparison-graph .titre { max-width:20ch; margin:auto; }
.graph-columns { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:48px; margin-top:42px; }
.graph-run { min-width:0; }
.graph-run h3 { font-family:var(--font-body); font-stretch:75%; font-size:22px; font-weight:500; text-align:center; margin:0 0 18px; }
.graph-run svg { display:block; width:100%; max-width:500px; height:auto; margin:auto; overflow:visible; }
.graph-run text { fill:var(--color-text); font-family:var(--font-body); font-stretch:75%; font-size:14px; }
.graph-run .graph-result { font-size:16px; font-weight:600; }
.graph-node { fill:var(--color-background); stroke:var(--graph-wire); stroke-width:1; }
.graph-base { fill:none; stroke:var(--graph-wire); stroke-width:1; }
.graph-active,.graph-success,.graph-stop { fill:none; stroke:var(--graph-signal); stroke-width:1.5; }
.graph-stop { stroke-width:3; }
.graph-boundary { fill:none; stroke:var(--graph-wire); stroke-width:1; stroke-dasharray:3 5; animation:graph-boundary 10s linear infinite; }
.graph-draw,.graph-active { stroke-dasharray:1; stroke-dashoffset:0; }
.graph-draw { animation:graph-draw 10s linear infinite; }
.graph-active,.graph-pulse,.graph-arrival { animation-duration:10s; animation-timing-function:linear; animation-iteration-count:infinite; }
.graph-pulse { fill:var(--graph-signal); opacity:0; offset-rotate:0deg; offset-anchor:0px 0px; }
.graph-caption { margin:24px auto 0; text-align:center; }
.graph-repository { margin:16px auto 0; text-align:center; font-size:14px; }
.graph-static { width:16px; height:16px; margin:26px 8px 0 0; accent-color:var(--graph-signal); vertical-align:middle; }
.graph-switch { display:inline-block; margin-top:26px; vertical-align:middle; font-family:var(--font-body); font-size:13px; color:var(--color-muted); cursor:pointer; }
.graph-static:focus-visible { outline:2px solid var(--color-focus); outline-offset:4px; }
.comparison-graph .graph-static:checked~.graph-columns * { animation:none !important; }
@keyframes graph-draw {
  0% {stroke-dashoffset:1}
  18%,94% {stroke-dashoffset:0}
  100% {stroke-dashoffset:1}
}
@media(max-width:859px) {
  .graph-columns { grid-template-columns:minmax(0,1fr); gap:44px; }
  .graph-run+.graph-run { border-top:1px solid var(--color-decoration); padding-top:32px; }
}
@media(prefers-reduced-motion:reduce) {
  .comparison-graph .graph-columns * { animation:none !important; }
  .graph-static,.graph-switch { display:none; }
}

@keyframes graph-boundary { 0%,18% {visibility:hidden} 22%,94% {visibility:visible} 100% {visibility:hidden} }
.pipeline-graph .titre { max-width:20ch; margin:auto; }
.pipeline-graph .sous { max-width:46ch; }
.pipeline-figure { margin:44px auto 0; max-width:1200px; }
.pipeline-scene { display:block; width:100%; height:auto; overflow:visible; }
.pipeline-v { max-width:340px; margin:auto; }
.pipeline-h { display:none; }
@media(min-width:1180px) { .pipeline-h { display:block; } .pipeline-v { display:none; } }

/* Textes du schéma */
.pipeline-scene text { fill:var(--color-text); font-family:var(--font-body); font-stretch:75%; font-size:14px; }
.pipeline-scene .pipeline-label { font-size:17px; font-weight:600; }
.pipeline-scene .pipeline-value { fill:var(--graph-signal); font-size:22px; font-weight:600; }
.pipeline-scene .pipeline-note { fill:var(--color-muted); font-size:14px; font-stretch:75%; letter-spacing:.06em; text-transform:uppercase; }
.pipeline-station[data-state="planned"] .pipeline-label { fill:var(--color-muted); }

/* Pictogrammes */
.picto-line,.picto-rule,.picto-mesh { fill:none; stroke:var(--color-text); stroke-width:1.6; stroke-linejoin:round; stroke-linecap:round; }
.picto-rule { stroke:var(--graph-signal); }
.picto-mesh { stroke:var(--graph-wire); stroke-width:1; }
.picto-fill { fill:var(--graph-signal); opacity:.18; }
.picto-led { fill:var(--graph-signal); }
.picto-planned { stroke:var(--graph-wire); stroke-dasharray:4 4; }
.pipeline-scene .picto-chip { fill:var(--graph-wire); font-size:15px; font-weight:600; letter-spacing:.08em; }

/* Rails, limite et paquets */
.pipeline-rail { fill:none; stroke:var(--graph-signal); stroke-width:1; opacity:.35; }
.pipeline-cross .pipeline-rail,.pipeline-end .pipeline-rail { stroke:var(--graph-wire); opacity:1; stroke-dasharray:3 5; }
.pipeline-boundary { fill:none; stroke:var(--graph-wire); stroke-width:1; stroke-dasharray:3 5; }
.pkt { fill:var(--graph-signal); opacity:0; }
.pkt-ghost { fill:var(--color-background); stroke:var(--graph-signal); stroke-width:1.5; }
.drop { fill:var(--graph-signal); opacity:0; }
.pipeline-h .pipeline-done { --d:114px; }
.pipeline-h .pipeline-cross { --d:164px; }
.pipeline-h .pipeline-end { --d:64px; }
.pipeline-v .pipeline-done { --d:58px; }
.pipeline-v .pipeline-cross { --d:108px; }
.pipeline-v .pipeline-end { --d:58px; }

@media(prefers-reduced-motion:no-preference) {
  .pipeline-h .pkt { animation:pipeline-h 2.4s linear infinite; }
  .pipeline-v .pkt { animation:pipeline-v 2.4s linear infinite; }
  .pipeline-h .pkt-ghost { animation-name:pipeline-h-ghost; animation-duration:4.8s; }
  .pipeline-v .pkt-ghost { animation-name:pipeline-v-ghost; animation-duration:4.8s; }
  .pkt:nth-child(2) { animation-delay:-.3s; } .pkt:nth-child(3) { animation-delay:-.6s; } .pkt:nth-child(4) { animation-delay:-.9s; }
  .pkt:nth-child(5) { animation-delay:-1.2s; } .pkt:nth-child(6) { animation-delay:-1.5s; } .pkt:nth-child(7) { animation-delay:-1.8s; } .pkt:nth-child(8) { animation-delay:-2.1s; }
  .pipeline-end .pkt-ghost { animation-delay:-2.4s; }
  .drop { animation:pipeline-drop 2.4s ease-in infinite; }
  .drop:nth-child(2) { animation-delay:-.8s; } .drop:nth-child(3) { animation-delay:-1.6s; }
  .picto-led { animation:pipeline-led 1.6s steps(1,end) infinite; }
  .picto g:nth-child(2) .picto-led { animation-delay:-.9s; } .picto g:nth-child(3) .picto-led { animation-delay:-.3s; }
  .picto-planned { animation:pipeline-march 6s linear infinite; }
  .pipeline-graph .graph-static:checked~.pipeline-figure * { animation:none; }
}
.drop:nth-child(1) { --dx:-14px; } .drop:nth-child(2) { --dx:4px; } .drop:nth-child(3) { --dx:16px; }
/* Sans animation, le schéma reste complet : paquets masqués, voyants allumés, flux lisibles par leurs chiffres. */
@keyframes pipeline-h { 0% {transform:translateX(0);opacity:0} 10%,88% {opacity:1} 100% {transform:translateX(var(--d));opacity:0} }
@keyframes pipeline-v { 0% {transform:translateY(0);opacity:0} 10%,88% {opacity:1} 100% {transform:translateY(var(--d));opacity:0} }
@keyframes pipeline-h-ghost { 0% {transform:translateX(0);opacity:0} 12%,85% {opacity:.9} 100% {transform:translateX(var(--d));opacity:0} }
@keyframes pipeline-v-ghost { 0% {transform:translateY(0);opacity:0} 12%,85% {opacity:.9} 100% {transform:translateY(var(--d));opacity:0} }
@keyframes pipeline-drop { 0% {transform:translate(0,0);opacity:0} 15% {opacity:.9} 100% {transform:translate(var(--dx),48px);opacity:0} }
@keyframes pipeline-led { 0% {opacity:1} 50% {opacity:.25} }
@keyframes pipeline-march { to { stroke-dashoffset:-48; } }

.pipeline-columns { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:48px; max-width:1200px; margin:48px auto 0; padding-top:36px; border-top:1px solid var(--color-decoration); }
.pipeline-columns p { margin:0 0 14px; }
.pipeline-columns .kicker { margin-bottom:14px; }
.pipeline-remaining { font:400 64px/1 var(--font-display); color:var(--graph-signal); font-size:round(nearest, 64px, var(--pixel-step)); }
.pipeline-scope { font-size:14px; color:var(--color-muted); }
@media(max-width:1179px) { .pipeline-columns { grid-template-columns:minmax(0,1fr); max-width:60ch; gap:28px; } }
@media(prefers-reduced-motion:reduce) { .pipeline-graph .graph-static,.pipeline-graph .graph-switch { display:none; } }
