/* ============================================================
   DCP — Schemas animes : sans / avec le DCP

   Le SVG est construit par schema-anime.js ; cette feuille ne connait
   que ses classes. Les deux tons reprennent la regle du site posee dans
   tokens.css : sans le protocole, rouge leger ; avec lui, vert.
   ============================================================ */

.schemas-grille {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  margin-top: 1.25rem;
}

/* --- Deux affichages ----------------------------------------------------- */

/* La barre de bascule : « cote a cote » compare, la legende cede la place
   a des infobulles et le survol fige les deux scenes ; « l'une apres
   l'autre » joue une seule scene a la fois, sans puis avec, pour chaque
   vendeur, la legende en bas. Le choix du visiteur est retenu. */
.schemas-barre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  margin-top: 1.25rem;
}

.schemas-modes {
  display: inline-flex;
  padding: 2px;
  border: 1.5px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
}

.schemas-mode {
  border: 0;
  padding: 0.35rem 0.9rem;
  border-radius: 999px;
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 200ms ease, color 200ms ease;
}

.schemas-mode[aria-pressed="true"] {
  background: var(--text-primary);
  color: var(--sur-inverse);
}

.schemas-mode:focus-visible {
  outline: 2px solid var(--accent-gold);
  outline-offset: 2px;
}

.schemas-aide {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

/* En sequence : une colonne, et la scene qui attend son tour disparait.
   La colonne est bornee par la hauteur de la fenetre : la scene doit tenir
   a l'ecran, titre, legende et commandes compris (22rem de budget), et le
   dessin fait 800 sur 590, d'ou le facteur 1,356. Plafond 760px, la
   largeur des pages de texte du site ; plancher 360px. Dans une iframe,
   100vh serait la hauteur de l'iframe elle-meme, qui depend du contenu :
   la page parente transmet la sienne dans --hauteur-fenetre. La barre de
   bascule suit la meme largeur. */
.schemas--sequence .schemas-barre,
.schemas--sequence .schemas-signature,
.schemas--sequence .schemas-grille {
  grid-template-columns: 1fr;
  max-width: clamp(360px, calc((var(--hauteur-fenetre, 100vh) - 22rem) * 1.356), 760px);
  margin-inline: auto;
}
/* Les deux scenes occupent la meme case et se fondent l'une dans l'autre
   (700 ms) plutot que de se remplacer d'un coup : comme elles partagent le
   plan, la zone du vendeur, sa boutique et le telephone restent a la meme
   place pendant le fondu, et seul ce qui change semble se redessiner. La
   scene qui attend reste dans la grille (la case garde la hauteur de la
   plus haute), invisible et sans prise au pointeur. */
.schemas--sequence .schema {
  grid-area: 1 / 1;
  transition: opacity 700ms ease, visibility 0s linear 0s;
}
.schemas--sequence .schema--attente {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 700ms ease, visibility 0s linear 700ms;
}

/* Au reveil d'une scene, ses noeuds se recachent d'un coup, sans leur
   fondu de 420 ms : sinon l'etat final du tour precedent transparaitrait
   pendant que la figure elle-meme apparait. */
.schema--instantane .schema-noeud,
.schema--instantane .schema-zone,
.schema--instantane .schema-zone-libelle { transition: none; }

/* En comparaison, la legende ne sert plus quand on peut survoler : le
   visiteur ne lirait pas deux textes a la fois, l'infobulle de la zone
   survolee la remplace. Sans survol possible (tactile), elle reste. */
@media (hover: hover) {
  .schemas--comparaison .schema-legende { display: none; }
}

.schema { position: relative; }

.schema-infobulle {
  position: absolute;
  z-index: 2;
  max-width: 280px;
  padding: 0.6rem 0.8rem;
  border-radius: 8px;
  background: var(--text-primary);
  color: var(--sur-inverse);
  font-size: 0.8125rem;
  line-height: 1.5;
  box-shadow: var(--shadow);
  pointer-events: none;
}

.schema-infobulle-titre {
  margin: 0 0 0.25rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sur-inverse-doux);
}

.schema-infobulle-texte { margin: 0; white-space: pre-line; }

/* --- La signature ------------------------------------------------------- */

/* Discrete : petit texte secondaire, a droite sous le bloc, et le noeud a
   22px de haut. C'est elle qui ramene chez nous quand le bloc est repris
   en iframe ailleurs. Le logo vient de --logo-src, donc du theme : le
   fond de la page nue est le notre, le noeud lui correspond toujours. */
.schemas-signature {
  display: flex;
  justify-content: flex-end;
  margin: 0.75rem 0 0;
}

.schemas-signature-lien {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.75rem;
  color: var(--text-secondary);
  text-decoration: none;
  opacity: 0.8;
  transition: opacity 200ms ease, color 200ms ease;
}

.schemas-signature-lien:hover,
.schemas-signature-lien:focus-visible {
  opacity: 1;
  color: var(--text-primary);
  text-decoration: underline;
}

.schemas-signature-lien:focus-visible {
  outline: 2px solid var(--accent-gold);
  outline-offset: 2px;
}

.schemas-signature-logo {
  width: 14px;
  height: 22px;
  background: var(--logo-src) center / contain no-repeat;
}

/* --- La page nue (iframe) et l'outil ------------------------------------- */

body.nu { background: var(--bg); padding: 0.5rem; }
body.nu .schemas-barre { margin-top: 0; }

.resume-embarquer {
  margin-top: 2rem;
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  max-width: var(--laisse-texte);
}

.resume-embarquer-titre {
  font-size: 1.125rem;
  margin: 0 0 0.5rem;
}

.resume-embarquer pre {
  overflow-x: auto;
  padding: 0.75rem 1rem;
  border-radius: 6px;
  background: var(--bg);
  font-size: 0.8125rem;
  line-height: 1.5;
}

.schema {
  margin: 0;
  padding: 1.25rem 1.25rem 1rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background-color: var(--bg);
}

/* Le ton pilote l'accent de tout le schema par une seule variable locale,
   que chaque regle ci-dessous consomme. */
.schema--sans { --schema-accent: var(--sans-dcp-accent); --schema-fond: var(--sans-dcp-fond); }
.schema--avec { --schema-accent: var(--avec-dcp-accent); --schema-fond: var(--avec-dcp-fond); }

.schema-titre {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--schema-accent);
  margin: 0 0 0.75rem;
}

.schema-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* --- Zones : l'espace de chacun ------------------------------------------ */


/* Teinte neutre a dessein : la zone dit a qui appartient l'espace, pas
   si le protocole est la. Le rouge et le vert restent aux flux. */
.schema-zone {
  fill: var(--surface-alt);
  stroke: var(--border);
  stroke-width: 1;
  stroke-dasharray: 4 4;
  opacity: 0.85;
}

.schema-zone-libelle {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  fill: var(--text-secondary);
}

/* Les blocs apparaissent quand ils servent : un noeud reste invisible tant
   qu'aucun flux n'en est parti ni n'y est arrive, une zone se montre avec
   son premier noeud. Le telephone, lui, est la des le depart. Ces regles
   viennent apres .schema-zone, dont l'opacite de 0.85 l'emporterait sinon
   a specificite egale. */
.schema-zone, .schema-zone-libelle { transition: opacity 420ms ease; }
.schema-noeud--cache, .schema-zone--cache { opacity: 0; }

/* --- Flux -------------------------------------------------------------- */

.schema-flux {
  fill: none;
  stroke: var(--schema-accent);
  stroke-width: 2.5;
  stroke-linecap: round;
  opacity: 0.9;
  transition: opacity 300ms ease;
}

/* Un flux bloque reste visible jusqu'a son arret, mais s'estompe : il a
   essaye, il n'est pas passe. Le tirete du trace anime est deja pris par
   le dessin progressif, d'ou l'opacite plutot qu'un pointille. */
.schema-flux--bloque { opacity: 0.45; }

/* Un flux en pointille est conditionnel : il n'a lieu que si l'acheteur
   l'autorise. Le tirete lui-meme est pose en ligne par le moteur, qui en
   fait un motif aussi long que le trace ; ici seulement un trait plus
   leger, pour qu'il se lise comme une possibilite, pas comme un fait. */
.schema-flux--pointille { opacity: 0.7; }

.schema-fleche { fill: var(--schema-accent); }

/* La croix a l'endroit ou le paquet s'est arrete : toujours rouge, c'est
   la couleur du « sans », quel que soit le ton du schema. */
.schema-blocage {
  stroke: var(--sans-dcp-accent);
  stroke-width: 4;
  stroke-linecap: round;
  opacity: 0;
  transition: opacity 250ms ease;
}

.schema-blocage--visible { opacity: 1; }

/* --- Noeuds ------------------------------------------------------------ */

.schema-noeud-fond {
  fill: var(--surface);
  stroke: var(--border);
  stroke-width: 1.5;
  transition: stroke 250ms ease, fill 250ms ease;
}

.schema-noeud { color: var(--text-secondary); transition: color 250ms ease, opacity 420ms ease; }

.schema-noeud--atteint { color: var(--text-primary); }
.schema-noeud--atteint .schema-noeud-fond { stroke: var(--schema-accent); stroke-width: 2; }

.schema-noeud-libelle {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 13px;
  font-weight: 600;
  fill: var(--text-secondary);
}

.schema-noeud--atteint .schema-noeud-libelle { fill: var(--text-primary); }

/* La note sous le libelle : ce que la scene dit du noeud, dans le ton du
   schema. C'est elle qui porte la difference entre les deux dessins. */
.schema-noeud-note {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 11px;
  font-style: italic;
  fill: var(--schema-accent);
}

/* Le noeud barre : le contrat qui reste hors de portee, sans le DCP. */
.schema-barre {
  stroke: var(--sans-dcp-accent);
  stroke-width: 4;
  stroke-linecap: round;
  opacity: 0;
  transform: scale(0.6);
  transform-origin: 0 0;
  transition: opacity 300ms ease, transform 300ms ease;
}

.schema-noeud--barre .schema-barre { opacity: 1; transform: scale(1); }
.schema-noeud--barre { color: var(--text-secondary); }
.schema-noeud--barre .schema-noeud-fond { stroke: var(--sans-dcp-accent); }

/* --- Telephone --------------------------------------------------------- */

.schema-tel-corps {
  fill: var(--text-primary);
  stroke: var(--border);
  stroke-width: 1.5;
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.22));
}

.schema-tel-ecran { fill: var(--bg); }

.schema-tel-encoche { fill: var(--sur-inverse-doux); }

.schema-telephone.schema-noeud--atteint .schema-tel-ecran { fill: var(--schema-fond); }

/* --- Ecran : les vues, une visible a la fois ---------------------------- */

.schema-vue {
  opacity: 0;
  transition: opacity 320ms ease;
  pointer-events: none;
}

.schema-vue--active { opacity: 1; }

.schema-vue-statut { fill: var(--border); }

.schema-vue-icone { color: var(--schema-accent); }

/* Une vue au ton « alerte » (le refus) porte l'icone et le titre en rouge,
   quel que soit le ton du schema : on refuse, ce n'est pas un succes. */
.schema-vue--alerte .schema-vue-icone { color: var(--sans-dcp-accent); }
.schema-vue--alerte .schema-vue-titre { fill: var(--sans-dcp-accent); }

.schema-vue-texte {
  font-family: 'Source Serif Pro', Georgia, serif;
  font-size: 30px;
  font-weight: 700;
  fill: var(--text-primary);
  letter-spacing: 0.04em;
}

.schema-vue-titre {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 600;
  fill: var(--text-primary);
}

/* Une ligne de texte dans l'ecran : le nom d'un service choisi, par
   exemple. Meme rythme que les barres, 22px. */
.schema-vue-ligne-texte {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 500;
  fill: var(--text-primary);
}
.schema-vue-ligne-texte--ok     { fill: var(--avec-dcp-accent); }
.schema-vue-ligne-texte--alerte { fill: var(--sans-dcp-accent); }

.schema-vue-ligne--neutre { fill: var(--border); }
.schema-vue-ligne--alerte { fill: var(--sans-dcp-accent); }
.schema-vue-ligne--ok     { fill: var(--avec-dcp-accent); }

/* --- Paquets voyageurs ------------------------------------------------- */

.schema-paquet {
  opacity: 0;
  color: var(--sur-inverse);
  transition: opacity 200ms ease;
}

.schema-paquet--visible { opacity: 1; }

.schema-paquet-fond {
  fill: var(--schema-accent);
  stroke: var(--bg);
  stroke-width: 2;
}

/* --- Legende et commandes --------------------------------------------- */

.schema-legende {
  min-height: 3.2em;
  margin: 0.75rem 0 0.5rem;
  font-size: 0.9375rem;
  color: var(--text-secondary);
  line-height: 1.6;
}

.schema-commandes {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.schema-lecture {
  width: 32px;
  height: 32px;
  border: 1.5px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-primary);
  font-size: 0.75rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.schema-lecture:hover { border-color: var(--schema-accent); color: var(--schema-accent); }

.schema-etapes {
  list-style: none;
  display: flex;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
}

.schema-etape {
  width: 12px;
  height: 12px;
  padding: 0;
  border: 1.5px solid var(--schema-accent);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  transition: background-color 200ms ease;
}

.schema-etape[aria-current="true"] { background-color: var(--schema-accent); }

/* --- Tours : un vendeur apres l'autre ------------------------------------ */

/* A chaque tour, la zone et la boutique prennent la teinte du vendeur
   (jetons --vendeur-N-* de tokens.css, cinq vendeurs). Sans le DCP, toutes
   les vues de l'ecran la prennent aussi et gagnent un bandeau : c'est le
   site de ce vendeur, different a chaque fois. Avec le DCP, seule la vue
   de la boutique la porte : le reste est votre application. */
/* La zone d'un vendeur prend son accent a 35 %, pas son fond pale : le
   fond etait a 19 unites RGB du gris neutre en clair et 12 en sombre,
   invisible. Bord plein, et le libelle passe en texte principal pour
   garder son contraste sur la teinte. */
[class*="schema-zone--t"] {
  fill-opacity: 0.35;
  stroke-dasharray: none;
  stroke-width: 1.5;
}

.schema-zone--t1 { fill: var(--vendeur-1-accent); stroke: var(--vendeur-1-accent); }
.schema-zone--t2 { fill: var(--vendeur-2-accent); stroke: var(--vendeur-2-accent); }
.schema-zone--t3 { fill: var(--vendeur-3-accent); stroke: var(--vendeur-3-accent); }
.schema-zone--t4 { fill: var(--vendeur-4-accent); stroke: var(--vendeur-4-accent); }
.schema-zone--t5 { fill: var(--vendeur-5-accent); stroke: var(--vendeur-5-accent); }

[class*="schema-zone--t"] + .schema-zone-libelle { fill: var(--text-primary); }

.schema-noeud--t1 { color: var(--vendeur-1-accent); }
.schema-noeud--t2 { color: var(--vendeur-2-accent); }
.schema-noeud--t3 { color: var(--vendeur-3-accent); }
.schema-noeud--t4 { color: var(--vendeur-4-accent); }
.schema-noeud--t5 { color: var(--vendeur-5-accent); }
.schema-noeud--t1 .schema-noeud-fond { fill: var(--vendeur-1-fond); stroke: var(--vendeur-1-accent); }
.schema-noeud--t2 .schema-noeud-fond { fill: var(--vendeur-2-fond); stroke: var(--vendeur-2-accent); }
.schema-noeud--t3 .schema-noeud-fond { fill: var(--vendeur-3-fond); stroke: var(--vendeur-3-accent); }
.schema-noeud--t4 .schema-noeud-fond { fill: var(--vendeur-4-fond); stroke: var(--vendeur-4-accent); }
.schema-noeud--t5 .schema-noeud-fond { fill: var(--vendeur-5-fond); stroke: var(--vendeur-5-accent); }

/* Une vue chez le vendeur se reconnait a son fond teinte, son bandeau et
   son icone a sa couleur, ses lignes carrees. La teinte se pose vue par
   vue (schema-vue--tN), pas sur le telephone : sans le DCP toutes les vues
   sont chez le vendeur ; avec, seule la boutique. Le fond de vue est
   transparent partout ailleurs et laisse voir l'ecran. */
.schema-vue-fond { fill: transparent; }
.schema-vue-entete { opacity: 0; }

.schema-vue--t1 .schema-vue-fond { fill: var(--vendeur-1-fond); }
.schema-vue--t2 .schema-vue-fond { fill: var(--vendeur-2-fond); }
.schema-vue--t3 .schema-vue-fond { fill: var(--vendeur-3-fond); }
.schema-vue--t4 .schema-vue-fond { fill: var(--vendeur-4-fond); }
.schema-vue--t5 .schema-vue-fond { fill: var(--vendeur-5-fond); }

.schema-vue--t1 .schema-vue-entete { fill: var(--vendeur-1-accent); opacity: 1; }
.schema-vue--t2 .schema-vue-entete { fill: var(--vendeur-2-accent); opacity: 1; }
.schema-vue--t3 .schema-vue-entete { fill: var(--vendeur-3-accent); opacity: 1; }
.schema-vue--t4 .schema-vue-entete { fill: var(--vendeur-4-accent); opacity: 1; }
.schema-vue--t5 .schema-vue-entete { fill: var(--vendeur-5-accent); opacity: 1; }

.schema-vue--t1 .schema-vue-icone, .schema-vue--t1 .schema-vue-statut { color: var(--vendeur-1-accent); fill: var(--vendeur-1-fond); }
.schema-vue--t2 .schema-vue-icone, .schema-vue--t2 .schema-vue-statut { color: var(--vendeur-2-accent); fill: var(--vendeur-2-fond); }
.schema-vue--t3 .schema-vue-icone, .schema-vue--t3 .schema-vue-statut { color: var(--vendeur-3-accent); fill: var(--vendeur-3-fond); }
.schema-vue--t4 .schema-vue-icone, .schema-vue--t4 .schema-vue-statut { color: var(--vendeur-4-accent); fill: var(--vendeur-4-fond); }
.schema-vue--t5 .schema-vue-icone, .schema-vue--t5 .schema-vue-statut { color: var(--vendeur-5-accent); fill: var(--vendeur-5-fond); }

[class*="schema-vue--t"] .schema-vue-ligne { rx: 0; }

.schema-lecture:focus-visible,
.schema-etape:focus-visible {
  outline: 2px solid var(--accent-gold);
  outline-offset: 2px;
}

/* --- Mouvement reduit ------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .schema-noeud, .schema-noeud-fond, .schema-barre, .schema-vue,
  .schema-zone, .schema-zone-libelle,
  .schema-paquet, .schema-etape, .schemas-mode, .schemas-signature-lien { transition: none; }
  .schemas--sequence .schema,
  .schemas--sequence .schema--attente { transition: none; }
}

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

@media (max-width: 899px) {
  .schemas-grille { grid-template-columns: 1fr; }
}

/* Sous 600px le SVG tient sur moins de 300px : ses libelles de 13px
   tombent vers 4,6px a l'ecran, illisibles. La legende narree sous le
   schema et les icones portent le sens, on les tait plutot que de les
   laisser bruire. */
@media (max-width: 599px) {
  .schema-noeud-libelle,
  .schema-noeud-note,
  .schema-vue-ligne-texte { display: none; }
}

/* --- Une scene seule : « Mon application et mes services » --------------- */

/* Le bloc de /services/ n'a qu'une scene et rien a comparer : pas de
   bascule, une seule colonne, bornee comme la sequence du resume pour
   tenir a l'ecran, et la legende toujours visible (en comparaison le
   resume la tait au profit des infobulles ; ici il n'y a pas de seconde
   scene a lire en meme temps). */
.schemas--seul .schemas-grille,
.schemas--seul .schemas-signature {
  grid-template-columns: 1fr;
  max-width: clamp(360px, calc((var(--hauteur-fenetre, 100vh) - 18rem) * 1.356), 800px);
  margin-inline: auto;
}

@media (hover: hover) {
  .schemas--seul.schemas--comparaison .schema-legende { display: block; }
}

/* --- Le noeud-photo : une vignette realiste dans la scene stylisee ------- */

/* Le cadre prend la teinte du tour comme un disque de noeud (teinter),
   l'image se pose dessus, recadree au centre. Le repli stylise (l'icone
   du cas) ne se voit que tant que l'image manque ou n'a pas charge. */
.schema-vignette-fond { transition: fill 250ms ease, stroke 250ms ease; }

.schema-vignette-image { opacity: 1; transition: opacity 300ms ease; }
.schema-vignette--sans-image .schema-vignette-image { opacity: 0; }

.schema-vignette-repli { opacity: 0; transition: opacity 300ms ease; }
.schema-vignette--sans-image .schema-vignette-repli { opacity: 1; }

.schema-vignette-bord {
  fill: none;
  stroke: var(--border);
  stroke-width: 1.5;
}

.schema-vignette.schema-noeud--atteint .schema-vignette-bord {
  stroke: var(--schema-accent);
  stroke-width: 2;
}

/* --- Le telephone teinte : l'application d'un tiers ----------------------- */

/* Quand l'application est celle d'une banque ou d'un assureur (appliTeinte),
   le telephone prend un lisere a sa couleur ; ses vues, elles, sont
   teintees comme celles d'un vendeur (schema-vue--tN). */
.schema-telephone.schema-noeud--t1 .schema-tel-corps { stroke: var(--vendeur-1-accent); stroke-width: 3; }
.schema-telephone.schema-noeud--t2 .schema-tel-corps { stroke: var(--vendeur-2-accent); stroke-width: 3; }
.schema-telephone.schema-noeud--t3 .schema-tel-corps { stroke: var(--vendeur-3-accent); stroke-width: 3; }
.schema-telephone.schema-noeud--t4 .schema-tel-corps { stroke: var(--vendeur-4-accent); stroke-width: 3; }
.schema-telephone.schema-noeud--t5 .schema-tel-corps { stroke: var(--vendeur-5-accent); stroke-width: 3; }

/* --- Les formes de terminal ---------------------------------------------- */

/* Un terminal dessine un chassis par forme qu'il prend au fil des tours
   (telephone, PC, portable) ; le groupe porte la forme courante en classe
   et seul ce chassis se voit. */
.schema-terminal-forme { display: none; }
.schema-terminal--telephone > [data-forme="telephone"],
.schema-terminal--pc > [data-forme="pc"],
.schema-terminal--portable > [data-forme="portable"] { display: inline; }

/* Un ecran en paysage (PC, portable) est bas : l'icone a gauche, le titre
   et les lignes a droite, en plus petit, sinon deux lignes suffisent a
   sortir de l'ecran. */
.schema-vue--paysage .schema-vue-titre { font-size: 11px; }
.schema-vue--paysage .schema-vue-ligne-texte { font-size: 8.5px; }
.schema-vue--paysage .schema-vue-texte { font-size: 22px; }

/* --- L'annonce d'un cas --------------------------------------------------- */

/* La carte qui ouvre un tour (annonce d'une etape) : au centre, au-dessus
   de tout, le temps de l'etape, puis elle s'efface. Surtitre a l'accent du
   schema, titre en serif, une ligne de contexte. */
.schema-annonce {
  opacity: 0;
  transition: opacity 400ms ease;
  pointer-events: none;
}
.schema-annonce--visible { opacity: 1; }

.schema-annonce-fond {
  fill: var(--bg);
  stroke: var(--schema-accent);
  stroke-width: 1.5;
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.18));
}

.schema-annonce-surtitre {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  fill: var(--schema-accent);
}

.schema-annonce-titre {
  font-family: 'Source Serif Pro', Georgia, serif;
  font-size: 16px;
  font-weight: 700;
  fill: var(--text-primary);
}

.schema-annonce-texte {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 10.5px;
  fill: var(--text-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .schema-annonce { transition: none; }
}

/* Le libelle d'une zone de vendeur prend l'accent de la teinte du tour :
   la zone elle-meme est cet accent a 35 %, le libelle est donc « la meme
   teinte, un peu plus foncee ». Deux classes, pas une : la regle du resume
   « [class*=schema-zone--t] + .schema-zone-libelle » (texte primaire) pese
   deux classes elle aussi, et gagnait sur une seule. */
.schema-zone-libelle.schema-zone-libelle--t1 { fill: var(--vendeur-1-accent); }
.schema-zone-libelle.schema-zone-libelle--t2 { fill: var(--vendeur-2-accent); }
.schema-zone-libelle.schema-zone-libelle--t3 { fill: var(--vendeur-3-accent); }
.schema-zone-libelle.schema-zone-libelle--t4 { fill: var(--vendeur-4-accent); }
.schema-zone-libelle.schema-zone-libelle--t5 { fill: var(--vendeur-5-accent); }

/* --- La carte d'annonce plein cadre, avec la photo du cas ---------------- */

/* Une photographie n'a pas de theme : le voile qui monte du bas est un
   bleu nuit fixe (le navy du site) et le texte qui se pose dessus est
   clair, en clair comme en sombre. C'est la seule couleur codee en dur de
   la feuille, et c'est pour cela. Le fondu est plus long que celui de la
   petite carte : c'est une transition, pas une etiquette. */
.schema-annonce--pleine { transition: opacity 900ms ease; }

.schema-annonce--pleine .schema-annonce-fond {
  fill: #0B1B33;
  stroke: none;
  filter: none;
}

.schema-annonce--pleine .schema-annonce-surtitre {
  font-size: 13px;
  fill: rgba(255, 255, 255, 0.78);
}

.schema-annonce--pleine .schema-annonce-titre {
  font-size: 30px;
  fill: #FFFFFF;
}

.schema-annonce--pleine .schema-annonce-texte {
  font-size: 14px;
  fill: rgba(255, 255, 255, 0.85);
}

/* Le sablier suit la meme regle que le reste de la carte : il se pose sur
   une photographie, donc il est blanc en dur, pas en jeton de theme. Pas de
   transition sur la jauge : elle est repoussee a chaque image, une
   transition la ferait trainer derriere l'horloge.

   Il est frere de la carte et non son enfant (c'est un controle, la carte
   est decorative) : il porte donc son propre fondu. visibility le sort de
   l'ordre de tabulation entre deux cas, et son retard de 900 ms la laisse
   se faire. */
.schema-annonce-sablier {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  cursor: pointer;
  transition: opacity 900ms ease, visibility 0s linear 900ms;
}

.schema-annonce-sablier--visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 900ms ease, visibility 0s;
}

/* La prise : invisible, mais elle porte le clic et l'appui. */
.schema-annonce-sablier-prise { fill: transparent; }

.schema-annonce-sablier:hover .schema-annonce-sablier-piste,
.schema-annonce-sablier:focus-visible .schema-annonce-sablier-piste {
  stroke: rgba(255, 255, 255, 0.85);
}

.schema-annonce-sablier:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 3px;
  border-radius: 50%;
}

.schema-annonce-sablier-piste {
  fill: rgba(11, 27, 51, 0.45);
  stroke: rgba(255, 255, 255, 0.3);
  stroke-width: 2;
}

.schema-annonce-sablier-jauge {
  fill: none;
  stroke: #FFFFFF;
  stroke-width: 2.5;
  stroke-linecap: round;
}

.schema-annonce-sablier-lecture { fill: rgba(255, 255, 255, 0.9); }

/* Le dessin se reduit avec la fenetre : a 375 px l'anneau tombait a 11 px,
   trop discret pour l'indication qu'il porte. Il grossit donc en dessous de
   la laisse, sur le groupe interieur : une transform posee sur le groupe
   exterieur ecraserait son translate. */
@media (max-width: 599px) {
  .schema-annonce-sablier-corps { transform: scale(1.5); }
}

@media (prefers-reduced-motion: reduce) {
  .schema-annonce--pleine { transition: none; }
  .schema-annonce-sablier { transition: none; }
  .schema-annonce-sablier--visible { transition: none; }
}

/* --- « Cet exemple nécessiterait… » : la liste des besoins ---------------- */

/* Sous la légende, les commandes à gauche et la liste à droite. Elle se
   remplit au fil du tour (un élément par noeud touché) : des icônes
   seules, en pastilles comme le bouton de lecture ; le nom, la note et la
   description sont dans l'infobulle, la même que celle des noeuds du
   dessin (demande de l'auteur). Sous 600 px le module ne s'affiche pas :
   trop petit pour des infobulles, et l'écran est au dessin. */
.schema-pied {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
}

.schema-besoins {
  flex: 0 1 320px;
  min-width: 0;
  margin-left: auto;
  text-align: right;
  transition: opacity 300ms ease, visibility 300ms;
}

/* Pendant la carte d'annonce d'un cas, le module se tait (visibility, pas
   display : le titre garde sa place, rien ne saute quand il revient). */
.schema-besoins--attente { opacity: 0; visibility: hidden; }

.schema-besoins-titre {
  margin: 0 0 0.4rem;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.schema-besoins-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.35rem;
}

.schema-besoin { animation: schema-besoin-entree 420ms ease both; }

@keyframes schema-besoin-entree {
  from { opacity: 0; transform: scale(0.6); }
  to   { opacity: 1; transform: none; }
}

.schema-besoin-bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin: 0;
  padding: 0;
  border: 1.5px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-primary);
  cursor: help;
}

.schema-besoin-bouton:hover,
.schema-besoin-bouton:focus-visible {
  border-color: var(--schema-accent);
  color: var(--schema-accent);
}

.schema-besoin-bouton:focus-visible {
  outline: 2px solid var(--schema-accent);
  outline-offset: 2px;
}

.schema-besoin-icone {
  width: 17px;
  height: 17px;
  display: block;
}

@media (prefers-reduced-motion: reduce) {
  .schema-besoin { animation: none; }
  .schema-besoins { transition: none; }
}

@media (max-width: 599px) {
  .schema-besoins { display: none; }
}

/* --- La carte des contributions (schema.carte) ------------------------------ */

/* Une scene immobile ; la legende du bas devient un encadre qui montre la
   fiche de la place survolee. Toutes les fiches sont dans la meme case de
   grille et une seule est visible : l'encadre a toujours la hauteur de la
   plus longue, a toutes les largeurs, et rien ne saute d'une place a
   l'autre. Pas de hauteur minimale a regler : elle se deduit du texte.
   L'or porte la place choisie, comme ailleurs sur le site il porte ce
   qui attire l'oeil. */
.schema-encadre {
  display: grid;
  margin: 1rem 0 0;
  padding: 1rem 1.25rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-gold);
  border-radius: 8px;
  background-color: var(--surface);
  color: var(--text-secondary);
}

.schema-encadre-famille {
  margin: 0;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-gold-text);
}

.schema-encadre-titre {
  margin: 0.25rem 0 0.375rem;
  font-family: 'Source Serif Pro', Georgia, serif;
  font-size: 1.1875rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text-primary);
}

.schema-encadre-texte {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--text-primary);
}

.schema-encadre-lieu {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  font-style: italic;
  color: var(--text-secondary);
}

/* Les liens d'une fiche : le cas de l'animation, les publics, les
   ressources. Cinq au plus, en ligne, sur le motif de .maniere-liens.
   Ils ne sont cliquables que sur la fiche visible : les autres sont en
   visibility: hidden, donc hors de l'ordre de tabulation. C'est ce qui
   donne son emploi au figeage : sans lui, le pointeur ne pourrait pas
   descendre jusqu'a eux sans changer de fiche en chemin. */
.schema-encadre-liens {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.125rem;
  margin: 0.75rem 0 0;
}

.schema-encadre-liens a {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--accent-gold-text);
  text-decoration: none;
}

.schema-encadre-liens a:hover { text-decoration: underline; }

.schema-encadre-liens a:focus-visible {
  outline: 2px solid var(--accent-gold);
  outline-offset: 2px;
  border-radius: 3px;
}

/* La cle de famille, posee une fois par suite : elle dit ce que les liens
   qui suivent ont en commun, sans une ligne de plus. */
.schema-encadre-liens-cle {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  align-self: center;
}

/* Au doigt, un lien de fiche est une cible comme une autre. Le retrait
   reste mesure : a 375 px chaque lien prend sa ligne, et l'encadre ne doit
   pas ecraser le dessin, deja reduit a la largeur du telephone. */
@media (max-width: 767px) {
  .schema-encadre-liens { gap: 0 0.875rem; }
  .schema-encadre-liens a { padding-block: 0.3125rem; }
}

/* Les fiches, superposees ; seule l'active se voit, et rejoue un fondu
   court en apparaissant. visibility et non display : les fiches cachees
   gardent leur place dans le calcul de hauteur. */
.schema-encadre-fiche { grid-area: 1 / 1; visibility: hidden; }
.schema-encadre-fiche--active { visibility: visible; }
.schema-encadre-fiche--active > * { animation: schema-encadre-entree 240ms ease both; }

@keyframes schema-encadre-entree {
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: none; }
}

/* Les fleches se tracent par transition CSS, pas par la boucle d'animation :
   le mode carte n'a ni horloge ni requestAnimationFrame. Le script pose la
   duree en ligne, pour qu'un seul chiffre serve des deux cotes, et coupe la
   transition le temps de remettre une fleche a zero. */
.schema--carte .schema-flux {
  transition: stroke-dashoffset 520ms ease, opacity 400ms ease,
              stroke 250ms ease, stroke-width 250ms ease;
}

.schema--carte .schema-flux--fige { transition: none; }

/* La veille, posee apres l'introduction : tout passe en pastel et les
   fleches a peine visibles, pour que la place choisie ressorte seule. */
.schema-carte--veille .schema-noeud,
.schema-carte--veille .schema-zone,
.schema-carte--veille .schema-zone-libelle { opacity: 0.4; }

.schema-carte--veille .schema-flux { opacity: 0.1; }

.schema-carte--veille .schema-noeud.schema-cible--active,
.schema-carte--veille .schema-zone.schema-cible--active,
.schema-carte--veille .schema-zone-libelle.schema-cible--active,
.schema-carte--veille .schema-flux.schema-flux--active { opacity: 1; }

/* Les etiquettes : une pastille posee sur le dessin, qui nomme et rend
   survolable une place sans icone a elle (une zone, les fleches du
   contrat). Elles restent lisibles en veille : ce sont elles qui disent ou
   sont ces places, c'etait tout le probleme. */
.schema-etiquette { transition: opacity 420ms ease; }

.schema-etiquette-fond {
  fill: var(--surface);
  stroke: var(--border);
  stroke-width: 1.5;
  transition: stroke 250ms ease, stroke-width 250ms ease;
}

.schema-etiquette-texte {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 600;
  fill: var(--text-secondary);
  transition: fill 250ms ease;
}

.schema-carte--veille .schema-etiquette { opacity: 0.85; }
.schema-carte--veille .schema-etiquette.schema-cible--active { opacity: 1; }

.schema-etiquette.schema-cible--active .schema-etiquette-fond {
  stroke: var(--accent-gold);
  stroke-width: 2.5;
}

.schema-etiquette.schema-cible--active .schema-etiquette-texte { fill: var(--text-primary); }

/* Les places cliquables se signalent avant tout survol : le curseur au
   survol, et en veille un appel lent, decale de l'une a l'autre par le
   script (animation-delay), qui dit que le dessin repond. */
.schema--carte .schema-cible-possible { cursor: pointer; }

/* « both » est indispensable : le script decale chaque icone
   (animation-delay), et sans remplissage l'icone resterait a sa valeur de
   cascade pendant son delai, donc pleinement visible avant de s'eteindre. */
.schema-carte--veille .schema-noeud.schema-cible-possible:not(.schema-cible--active) {
  animation: schema-carte-appel 3.2s ease-in-out infinite both;
}

@keyframes schema-carte-appel {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 0.66; }
}

/* La place choisie : le disque et son libelle, le chassis d'un terminal,
   la fleche ou le cadre d'une zone passent a l'or. */
.schema-noeud.schema-cible--active { color: var(--accent-gold-text); }
.schema-noeud.schema-cible--active .schema-noeud-fond { stroke: var(--accent-gold); stroke-width: 3; }
.schema-noeud.schema-cible--active .schema-noeud-libelle { fill: var(--text-primary); }
.schema-telephone.schema-cible--active .schema-tel-corps { stroke: var(--accent-gold); stroke-width: 3; }
.schema-flux.schema-cible--active { stroke: var(--accent-gold); stroke-width: 4; opacity: 1; }
.schema-zone.schema-cible--active { stroke: var(--accent-gold); stroke-width: 2; stroke-dasharray: none; }

.schema--carte .schema-svg--survol { cursor: pointer; }

/* Piege de specificite, mesure : au-dessus de 900 px le bloc passe en mode
   comparaison, ou la regle du resume .schemas--seul.schemas--comparaison
   .schema-legende (trois classes, sous hover) remet toute legende en
   display: block. L'encadre perdait sa grille, les douze fiches
   s'empilaient et il mesurait 1 530 px. Trois classes ici aussi, et apres. */
.schema--carte .schema-legende.schema-encadre { display: grid; }

/* Sous 600 px les libelles de noeud sont tus (regle commune) : l'encadre
   reste, c'est lui qui porte le sens, et un appui choisit la place. */
@media (max-width: 599px) {
  .schema-encadre { padding: 0.875rem 1rem; }
  .schema-encadre-titre { font-size: 1.0625rem; }
}

/* Figee, la carte ne suit plus le pointeur : les autres places cessent
   d'appeler, elles ne repondraient pas au survol. Le curseur reste en
   pointeur, car un clic, lui, change bien de place. */
.schema-carte--figee .schema-noeud.schema-cible-possible,
.schema-carte--figee .schema-etiquette { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .schema-encadre-fiche--active > * { animation: none; }
  .schema--carte .schema-flux { transition: none; }
  .schema-carte--veille .schema-noeud.schema-cible-possible:not(.schema-cible--active) {
    animation: none;
  }
}
