:root {
  --fond: #10131a;
  --surface: #171b24;
  --creux: #0b0e13;
  --texte: #d7dce5;
  --attenue: #79839a;
  --trait: #262c38;
  --info: #6ea8fe;
  --ok: #5ec27a;
  --warn: #e6b450;
  --erreur: #ff6b6b;

  --code: Hack, "DejaVu Sans Mono", ui-monospace, monospace;
  --prose: "Ubuntu Sans", Ubuntu, "Noto Sans", sans-serif;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--fond);
  color: var(--texte);
  font: 13px/1.65 var(--code);
  font-variant-numeric: tabular-nums;
}
.page { max-width: 1000px; margin: 0 auto; padding: 1.5rem 1.5rem 5rem; }

/* ---------- Bandeau, repris de la page d'état du proxy ---------- */
.bandeau {
  display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; align-items: baseline;
  padding: 0.55rem 0.8rem;
  background: var(--creux); border-left: 3px solid var(--info);
}
.bandeau .titre { color: var(--info); font-weight: 700; letter-spacing: 0.05em; }
.bandeau .meta { color: var(--attenue); font-size: 0.88em; }
.pouls { margin-left: auto; color: var(--ok); font-size: 0.88em; }

/* ---------- La thèse, en clair ---------- */
.these {
  padding: 5rem 0 4rem;
  font-family: var(--prose);
  font-size: clamp(1.6rem, 4vw, 2.6rem);
  font-weight: 300; line-height: 1.25; letter-spacing: -0.015em;
  max-width: 20ch;
}
.these b { font-weight: 600; color: var(--info); }
.chapeau {
  font-family: var(--prose); font-size: 1rem; line-height: 1.7;
  color: var(--attenue); max-width: 56ch; margin: -2.5rem 0 3.5rem;
}

/* ---------- Signature : le traceur ---------- */
/* Une seule requête descend la page. Chaque section est une étape de son
   trajet, et porte la ligne de journal que le proxy écrirait vraiment. */
.trace { position: relative; padding-left: 2.2rem; }
.trace::before {
  content: ""; position: absolute; left: 0.42rem; top: 0.6rem; bottom: 5rem;
  width: 1px; background: var(--trait);
}
.etape { position: relative; padding: 0 0 3.2rem; }
.etape::before {
  content: ""; position: absolute; left: -1.9rem; top: 0.5rem;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--fond); border: 1px solid var(--attenue);
}
.etape.info::before { border-color: var(--info); background: var(--info); }
.etape.warn::before { border-color: var(--warn); background: var(--warn); }
.etape.ok::before   { border-color: var(--ok);   background: var(--ok); }

.ligne { display: flex; gap: 0.75rem; align-items: baseline; white-space: nowrap; overflow-x: auto; }
.niv { flex: none; width: 3.4em; font-size: 0.82em; letter-spacing: 0.04em; }
.niv.i { color: var(--info); }
.niv.w { color: var(--warn); }
.niv.o { color: var(--ok); }
.prefixe { flex: none; color: var(--attenue); }
.prefixe b { color: var(--texte); font-weight: 700; }
.horo { margin-left: auto; color: var(--attenue); font-size: 0.85em; padding-left: 1.5rem; }

.etape h2 {
  font-family: var(--prose); font-weight: 500; font-size: 1.22rem;
  margin: 1.1rem 0 0.5rem; letter-spacing: -0.01em;
}
.etape p {
  font-family: var(--prose); font-size: 0.95rem; line-height: 1.7;
  color: var(--attenue); max-width: 62ch; margin: 0 0 0.8rem;
}
.etape p b { color: var(--texte); font-weight: 500; }

pre {
  margin: 0.9rem 0 0; padding: 0.75rem 0.9rem;
  background: var(--surface); border: 1px solid var(--trait); border-radius: 3px;
  font: 12px/1.6 var(--code); overflow-x: auto; white-space: pre;
}
code { font-family: var(--code); color: var(--texte); }
.mauvais { color: var(--erreur); }
.bon { color: var(--ok); }
.gris { color: var(--attenue); }

/* ---------- Les routes, en lignes de journal ---------- */
.routes { border: 1px solid var(--trait); border-radius: 3px; background: var(--surface); overflow: hidden; }
.routes header {
  padding: 0.45rem 0.8rem; background: var(--creux);
  border-bottom: 1px solid var(--trait); font-size: 0.88em; color: var(--attenue);
}
.routes header b { color: var(--texte); }
.routes .r { display: flex; gap: 0.9rem; align-items: baseline; padding: 0.3rem 0.8rem; white-space: nowrap; }
.routes .r span:first-child { flex: none; width: 15em; color: var(--info); }
.routes .r span:last-child { color: var(--attenue); }
.routes .r.opt span:first-child { color: var(--warn); }

/* ---------- Fin ---------- */
.fin { padding: 3.5rem 0 0; }
.fin h2 { font-family: var(--prose); font-weight: 500; font-size: 1.4rem; margin: 0 0 0.6rem; }
.boutons { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 1.4rem; }
.bouton {
  font: 12px/1 var(--code); letter-spacing: 0.03em;
  padding: 0.8rem 1.1rem; border: 1px solid var(--trait); border-radius: 3px;
  color: var(--texte); text-decoration: none; background: var(--surface);
}
.bouton:hover { border-color: var(--info); color: var(--info); }
.bouton.plein { background: var(--info); border-color: var(--info); color: var(--creux); font-weight: 700; }
.bouton.plein:hover { background: var(--texte); border-color: var(--texte); color: var(--creux); }
.pied { margin-top: 3rem; padding-top: 1.2rem; border-top: 1px solid var(--trait); color: var(--attenue); font-size: 0.88em; }
.pied a { color: var(--info); }

@media (max-width: 620px) {
  .page { padding: 1rem 1rem 3rem; }
  .horo { display: none; }
  .trace { padding-left: 1.5rem; }
  .etape::before { left: -1.35rem; }
  .trace::before { left: 0.2rem; }

  /* Sur un écran étroit, la ligne de journal revient à la ligne plutôt que de
     défiler : coupée en plein mot sans indice de défilement, elle se lisait
     comme un contenu tronqué. Les blocs de code, eux, continuent de défiler,
     leur alignement en colonnes porte du sens et ne survivrait pas au repli. */
  .ligne { flex-wrap: wrap; white-space: normal; overflow-x: visible; }
  .ligne .prefixe { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; }

  /* Le tableau des routes passe en deux lignes par route, le libellé sous le
     chemin, plutôt qu'en deux colonnes dont la seconde sortait de l'écran. */
  .routes .r { flex-wrap: wrap; gap: 0 0.9rem; white-space: normal; }
  .routes .r span:first-child { width: auto; flex: 1 1 100%; }
  .routes .r span:last-child { flex: 1 1 100%; }
}
/* Le traceur : l'étape s'inscrit en entrant à l'écran, c'est index.js qui pose
   la classe. Le masquage n'existe que si le script peut tourner, sinon la page
   reste lisible telle quelle. */
@media (scripting: enabled) {
  .etape { transition: opacity 0.45s ease, transform 0.45s ease; }
  .etape:not(.vue) { opacity: 0; transform: translateY(8px); }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }
/* À l'impression, aucune étape n'entre jamais dans l'écran : tout doit être là. */
@media print { .etape { opacity: 1 !important; transform: none !important; } }
a:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
