/*
 * A+ Connect — les écrans.
 *
 * Sobre et lisible : ce sont des écrans d'authentification, pas une vitrine. Ils
 * s'ouvrent souvent sur un téléphone, parfois sur un réseau lent, et toujours au
 * milieu d'autre chose que la personne essayait de faire.
 *
 * Aucune police distante, aucun script : ces pages doivent s'afficher en entier
 * même quand rien d'autre ne charge.
 *
 * La palette vient du thème Keycloak de l'ancienne version — l'orange A+ et les
 * gris qui l'accompagnent. Ce qui n'en vient pas, c'est la mise en page : on
 * garde la structure de ces écrans-ci et on y met la marque, plutôt que de
 * refaire le gabarit Keycloak dont on s'est débarrassé.
 */

:root {
	color-scheme: light dark;

	/*
	 * LE BOUTON PORTE L'ORANGE DU LOGO — arbitrage de Lionel, 2026-10-02.
	 *
	 * #ff5a00, le même des deux côtés du thème, et le même que la marque. Ce qui
	 * change pour le permettre, c'est l'ENCRE : le texte du bouton est sombre.
	 *
	 * C'était l'empêchement depuis le début. Du blanc sur #ff5a00 donne 3,1:1,
	 * très en dessous des 4,5:1 exigés — d'où les deux détours précédents, un
	 * orange assombri puis un orange rompu, qui tous deux s'éloignaient du logo
	 * pour sauver le texte blanc. Du texte sombre sur le MÊME orange donne 5,8:1.
	 * Il n'y avait pas à choisir entre la marque et la lisibilité : il y avait à
	 * changer la couleur du texte.
	 *
	 * `--lien` est l'autre orange, celui qui s'écrit EN TEXTE sur la carte — les
	 * liens, et les boutons à filet. Là, pas de fond coloré pour le porter : sur
	 * blanc, #ff5a00 retombe à 3,1:1. Il lui faut donc une version par thème, et
	 * c'est la seule raison pour laquelle deux orangés subsistent.
	 */
	--marque: #ff5a00;
	--accent: #ff5a00;
	--accent-survol: #ff7324;
	--accent-texte: #151515;
	--lien: #c74600;

	--fond: #f8f9fa;
	--carte: #ffffff;
	--texte: #212529;
	--texte-doux: #6c757d;
	--bord: #dee2e6;
	--alerte: #8c2f22;
	--alerte-fond: #fdf1ef;
	--attente-fond: #fff4ec;
	--attente-bord: #ffcaa6;
	--tuile: #ffffff;
}

@media (prefers-color-scheme: dark) {
	:root {
		/*
		 * Le bouton ne change pas de thème : même orange, même encre sombre, 5,8:1
		 * ici aussi. Seul `--lien` bouge, parce que #ff5a00 écrit sur la carte
		 * sombre donne 5,5:1 — ça passe, mais #ff7a33 en donne 6,6 et se lit mieux
		 * en petit.
		 */
		--marque: #ff5a00;
		--accent: #ff5a00;
		--accent-survol: #ff7324;
		--accent-texte: #151515;
		--lien: #ff7a33;

		--fond: #121212;
		--carte: #1c1c1c;
		--texte: #ececea;
		--texte-doux: #a0a0a0;
		--bord: #333333;
		--alerte: #f0998c;
		--alerte-fond: #2e1d1a;
		--attente-fond: #2a1d12;
		--attente-bord: #5a3a1c;
		/* Le logo porte son propre fond blanc : la tuile le prolonge, elle ne le
		   recouvre pas. */
		--tuile: #ffffff;
	}
}

* {
	box-sizing: border-box;
}

body {
	margin: 0;
	padding: 2rem 1rem 4rem;
	/*
	 * La lueur orange en haut à gauche vient du thème de l'ancienne version. Elle
	 * est presque invisible et c'est voulu : elle donne une couleur à la page sans
	 * gêner la lecture d'un formulaire.
	 *
	 * `background-color` est déclaré séparément et EN DERNIER recours : la couche
	 * du dessous doit rester opaque, faute de quoi la page emprunte le fond de son
	 * hôte là où le dégradé est transparent.
	 */
	background-color: var(--fond);
	background-image: radial-gradient(circle at top left,
			color-mix(in srgb, var(--marque) 12%, transparent), transparent 32%);
	background-repeat: no-repeat;
	background-attachment: fixed;
	color: var(--texte);
	font: 16px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	display: flex;
	flex-direction: column;
	align-items: center;
}

/*
 * 40rem et non 34 (arbitrage de Lionel, 2026-10-02) : l'ecran du profil demande
 * une quinzaine de champs, dont trois rangees de deux ou trois. A 34rem, « Ville
 * / Region / Code postal » se repliait en colonne des le poste de travail.
 *
 * Toujours un `max-width` et jamais une largeur : sur telephone c'est la largeur
 * de l'ecran qui commande, et le `padding` du body qui donne la marge.
 */
main {
	width: 100%;
	max-width: 40rem;
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: 10px;
	padding: 2rem;
}

/* Meme largeur que la carte, sinon le logo ne s'aligne plus sur son bord. */
.marque {
	width: 100%;
	max-width: 40rem;
	margin-bottom: 1.25rem;
	display: flex;
	align-items: center;
	gap: 0.65rem;
}

/*
 * Le logo porte son propre fond blanc. La tuile le prolonge — même blanc, coins
 * arrondis, fine bordure — au lieu d'essayer de le détourer : sur fond sombre,
 * un logo noir et orange sans son fond blanc deviendrait illisible.
 */
.marque img {
	width: 2.1rem;
	height: 2.1rem;
	border-radius: 6px;
	background: var(--tuile);
	border: 1px solid var(--bord);
	/* Le SVG est carré-ish (440×400) : `contain` évite de l'étirer. */
	object-fit: contain;
	flex: none;
}

/* Pousse la provenance et le sélecteur de langue à droite du logo. */
.marque .provenance {
	margin-left: auto;
}

.marque strong {
	font-size: 1.05rem;
	letter-spacing: 0.01em;
}

.provenance {
	color: var(--texte-doux);
	font-size: 0.875rem;
}

h1 {
	margin: 0 0 0.35rem;
	font-size: 1.4rem;
	line-height: 1.25;
	text-wrap: balance;
}

.sous-titre {
	margin: 0 0 1.5rem;
	color: var(--texte-doux);
	font-size: 0.95rem;
}

form {
	display: flex;
	flex-direction: column;
	gap: 1.1rem;
}

label {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	font-size: 0.9rem;
	font-weight: 600;
}

/* Hors d'un `label` aussi : le volet du telephone porte son aide devant le
   couple pays + numero, qui n'est pas un champ unique a etiqueter. */
.aide {
	margin: 0;
	font-weight: 400;
	color: var(--texte-doux);
	font-size: 0.85rem;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="tel"],
select {
	width: 100%;
	padding: 0.65rem 0.7rem;
	font: inherit;
	color: var(--texte);
	background: var(--fond);
	border: 1px solid var(--bord);
	border-radius: 6px;
}

input:focus-visible,
select:focus-visible,
button:focus-visible,
a:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

/* Le code se lit chiffre par chiffre : chasse fixe, et de l'air entre eux. */
input[name="code"] {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 1.45rem;
	letter-spacing: 0.35em;
	text-align: center;
}

button {
	padding: 0.7rem 1rem;
	font: inherit;
	font-weight: 600;
	color: var(--accent-texte);
	background: var(--accent);
	border: 1px solid transparent;
	border-radius: 6px;
	cursor: pointer;
}

button:hover {
	background: var(--accent-survol);
}

/* Un bouton desactive pendant la recherche de position ne doit pas se donner
   l'air cliquable. */
button:disabled {
	opacity: 0.6;
	cursor: default;
}

/* Pas de fond coloré pour porter le texte : c'est `--lien` qui s'applique, le
   seul des deux orangés qui se lise sur la carte. */
button.discret {
	color: var(--lien);
	background: transparent;
	border-color: var(--bord);
	font-weight: 500;
}

a {
	color: var(--lien);
}

.champs {
	display: grid;
	gap: 1.1rem;
	grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

fieldset {
	margin: 0;
	padding: 0.9rem 1rem 1rem;
	border: 1px solid var(--bord);
	border-radius: 8px;
	display: grid;
	gap: 0.9rem;
}

legend {
	padding: 0 0.35rem;
	font-size: 0.85rem;
	font-weight: 600;
	color: var(--texte-doux);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

.choix {
	display: flex;
	flex-wrap: wrap;
	gap: 0.9rem;
}

.choix label {
	flex-direction: row;
	align-items: center;
	gap: 0.4rem;
	font-weight: 400;
}

/*
 * Les bascules particulier/entreprise et postal/GPS, sans une ligne de
 * JavaScript : `:has()` regarde si la case cochée est dans le groupe qui
 * précède. Tant que rien n'est coché, les deux volets restent fermés — ce qui
 * dit exactement ce que le domaine dit : tant que la nature est inconnue, elle
 * est le seul manque qu'on puisse nommer.
 */
.bascule {
	display: grid;
	gap: 1.1rem;
}

.si-pp,
.si-pm,
.si-postal,
.si-gps,
.si-email,
.si-phone {
	display: none;
}

/*
 * L'ECART APPARTIENT AU VOLET, L'OUVERTURE A LA REGLE `:has()`.
 *
 * Les deux etaient melanges, et le `gap: 0.35rem` ajoute pour l'inscription —
 * un champ et son aide — s'etait applique aux volets du PROFIL, qui sont des
 * listes de six champs. Personne ne l'avait demande, et rien ne le disait.
 *
 * Separes, les deux reglages ne peuvent plus se marcher dessus : celui du
 * dessous ne decide que de ce qui s'affiche.
 */
.si-pp,
.si-pm,
.si-postal,
.si-gps {
	gap: 0.9rem;
}

.si-email,
.si-phone {
	gap: 0.35rem;
}

.bascule > .choix:has(input[value="PP"]:checked) ~ .si-pp,
.bascule > .choix:has(input[value="PM"]:checked) ~ .si-pm,
.bascule > .choix:has(input[value="POSTAL"]:checked) ~ .si-postal,
.bascule > .choix:has(input[value="GPS"]:checked) ~ .si-gps,
.bascule > .choix:has(input[value="EMAIL"]:checked) ~ .si-email,
.bascule > .choix:has(input[value="PHONE"]:checked) ~ .si-phone {
	display: grid;
}

/*
 * Indicatif et numéro sur UNE ligne.
 *
 * `min-width: 0` sur le champ : sans lui, la largeur intrinsèque d'un input
 * l'empêche de se réduire et le couple déborde du cadre sur un téléphone. C'est
 * le défaut le plus courant d'une rangée flex, et il ne se voit qu'en étroit.
 */
.telephone {
	display: flex;
	gap: 0.5rem;
	align-items: stretch;
}

/*
 * Moitie-moitie, et pas une largeur fixe pour l'indicatif : « Cameroon (+237) »
 * tenait dans 11rem, « United Arab Emirates (+971) » non, et le nom du pays
 * etait coupe au milieu. `flex-basis: 0` avec le meme `grow` partage l'espace
 * disponible en deux parts egales quel que soit le contenu — donc quelle que
 * soit la langue affichee, ce qu'une largeur en rem ne peut pas promettre.
 */
.telephone .indicatif,
.telephone .numero {
	flex: 1 1 0;
	min-width: 0;
}

.erreur,
.manques,
.avis {
	border-radius: 8px;
	padding: 0.8rem 0.9rem;
	font-size: 0.92rem;
	margin: 0 0 1.25rem;
}

.erreur {
	background: var(--alerte-fond);
	border: 1px solid var(--alerte);
	color: var(--alerte);
}

/*
	Plusieurs manquements d'un coup, quand un mot de passe enfreint plus d'une
	règle. La puce reste À L'INTÉRIEUR du cadre : en `outside`, elle sort du fond
	rouge et flotte dans la page, ce qui défait le bloc au lieu de l'organiser.
*/
.erreur-liste {
	list-style-position: inside;
}

.erreur-liste li + li {
	margin-top: 0.45rem;
}

.manques,
.avis {
	background: var(--attente-fond);
	border: 1px solid var(--attente-bord);
}

.manques ul {
	margin: 0.45rem 0 0;
	padding-left: 1.2rem;
}

.pied {
	margin-top: 1.5rem;
	padding-top: 1.1rem;
	border-top: 1px solid var(--bord);
	font-size: 0.9rem;
	color: var(--texte-doux);
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

/*
 * Le sélecteur de langue. Chaque langue est écrite DANS SA LANGUE : quand on ne
 * comprend pas la page où l'on est tombé, « Anglais » n'aide pas — il faut
 * pouvoir chercher le mot qu'on reconnaît.
 */
.langues {
	margin-left: auto;
	display: flex;
	gap: 0.65rem;
}

.langues a.courante {
	color: var(--texte-doux);
	text-decoration: none;
	font-weight: 600;
	cursor: default;
}

.secondaire {
	display: flex;
	gap: 0.75rem;
	align-items: center;
	flex-wrap: wrap;
}

/*
 * Les renvois de code : UNE ligne, et de l'air avant.
 *
 * Ils s'empilaient en colonne, chacun à sa largeur, et c'était un accident de
 * cascade : ce bloc est un `form`, et `form` pose `flex-direction: column`. La
 * classe redéclarait `display: flex` — déjà vrai — mais pas la DIRECTION, donc
 * la colonne restait, et `align-items: center` les centrait les uns sous les
 * autres. Trois boutons de trois largeurs, sous un bouton pleine largeur.
 *
 * `flex: 1 1 9rem` leur donne la même part : alignés sur « Valider » au-dessus
 * quand la place suffit, et repliés proprement quand elle manque — plutôt que
 * d'écraser « Envoyer sur WhatsApp » sur un téléphone étroit.
 *
 * Seulement sur `form.secondaire` : la même classe habille aussi le bouton
 * « Utiliser ma position », seul dans son `div`, qui n'a aucune raison de
 * s'étaler sur toute la largeur.
 */
form.secondaire {
	flex-direction: row;
	margin-top: 1.5rem;
}

form.secondaire button {
	flex: 1 1 9rem;
}

code {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.9em;
}

/* ---------------------------------------------------------------------------
   La capture des pieces d'identite
   --------------------------------------------------------------------------- */

/* POUR QUEL COMPTE la verification est en cours. Discret mais lisible : la
   personne doit pouvoir le verifier d'un coup d'oeil avant de photographier sa
   piece d'identite, surtout sur un poste partage. */
.titulaire {
	margin: 0 0 1rem;
	font-size: 0.9rem;
	color: var(--texte-doux);
}

.titulaire strong {
	color: var(--texte);
}

/* Le contact entre parentheses : il desambigue deux homonymes sans voler la
   vedette au nom. */
.titulaire .contact::before { content: " ("; }
.titulaire .contact::after { content: ")"; }


/* L'ECRAN DE DEMARRAGE : choix du mode, et QR code vers le telephone. */

/* Les trois modes, en tuiles cliquables. Un `radio` cache et son `label` : la
   selection reste au clavier et au lecteur d'ecran, sans une ligne de script. */
.modes {
	display: grid;
	gap: 0.6rem;
	margin: 1rem 0;
}

@media (min-width: 40rem) {
	.modes { grid-template-columns: repeat(3, 1fr); }
}

.mode input {
	position: absolute;
	opacity: 0;
	pointer-events: none;
}

.mode label {
	display: block;
	height: 100%;
	padding: 0.9rem;
	background: var(--carte);
	border: 2px solid var(--bord);
	border-radius: 8px;
	cursor: pointer;
}

.mode input:checked + label {
	border-color: var(--accent);
}

/* Le focus doit rester visible sur la tuile, puisque la case est invisible. */
.mode input:focus-visible + label {
	outline: 2px solid var(--lien);
	outline-offset: 2px;
}

.mode strong { display: block; }

.mode span {
	display: block;
	margin-top: 0.2rem;
	font-size: 0.85rem;
	color: var(--texte-doux);
}

/* Le QR code. `max-width` en rem et non en pixels : il doit rester scannable
   quand la personne a grossi les caracteres du systeme. */
.qr {
	display: block;
	width: 100%;
	max-width: 13rem;
	height: auto;
	margin: 0.8rem 0;
	background: #ffffff;
	border: 1px solid var(--bord);
	border-radius: 6px;
}

/* L'adresse en clair, sous le QR : un ordinateur sans camera doit pouvoir
   l'envoyer autrement. Elle porte un billet, donc elle se coupe sans deborder
   mais ne se tronque pas — tronquee, elle serait inutilisable. */
.adresse-capture {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 0.78rem;
	word-break: break-all;
	color: var(--texte-doux);
}


/* ---------------------------------------------------------------------------
   La page de capture guidee
   --------------------------------------------------------------------------- */

/* Un titre de section, entre le h1 de la page et les legendes de fieldset. */
main h2 {
	margin: 1.8rem 0 0.2rem;
	font-size: 1.05rem;
}

/* La barre d'etapes. Cliquable : la personne qui a rate son verso doit pouvoir
   y revenir sans refaire le reste. */
.etapes {
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	gap: 0.3rem;
	margin: 1rem 0 0.5rem;
}

.etapes button {
	min-height: 2.3rem;
	padding: 0 0.4rem;
	font-size: 0.75rem;
	font-weight: 600;
	color: var(--texte-doux);
	background: var(--fond);
	border: 1px solid var(--bord);
	border-radius: 6px;
	cursor: pointer;
}

.etapes button.active {
	color: var(--accent-texte);
	background: var(--accent);
	border-color: var(--accent);
}

.etape[hidden] { display: none !important; }

.actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 0.8rem;
}

.navigation { justify-content: space-between; }

/* Un `input file` deguise en bouton : le champ brut n'est pas stylable, et son
   libelle natif n'est pas traduisible. */
.fichier input[type=file] { display: none; }

.fichier {
	display: inline-flex;
	align-items: center;
	min-height: 2.6rem;
	padding: 0 0.9rem;
	border-radius: 6px;
	cursor: pointer;
}

/* L'apercu camera. `object-fit: cover` remplit le cadre — et c'est pour cela
   que le recadrage en JavaScript defait cette transformation avant de dessiner :
   recadrer sur les coordonnees de l'ecran rognerait la piece. */
.apercu {
	position: relative;
	overflow: hidden;
	border-radius: 8px;
	background: #101513;
}

.apercu video {
	display: block;
	width: 100%;
	max-height: 23rem;
	object-fit: cover;
}

/*
 * L'APERCU DU VISAGE EST MIROITE, LA PHOTO NE L'EST PAS.
 *
 * Sans miroir, « tournez la tete vers la gauche » fait partir le visage vers la
 * DROITE de l'ecran : la consigne et ce qu'on voit se contredisent, et l'arc qui
 * s'allume acheve de perdre la personne. Tout selfie se montre en miroir pour
 * cette raison.
 *
 * La photo, elle, reste telle que la camera l'a vue : `drawImage` lit les images
 * du flux et ignore les transformations CSS. C'est ce qu'il faut, puisque cette
 * image part en comparaison faciale.
 *
 * A savoir si l'ovale cesse un jour d'etre centre : `zoneSource` calcule le
 * recadrage en coordonnees d'ecran, qui sont miroitees par rapport au flux. Tant
 * que la zone est symetrique autour de l'axe vertical, les deux coincident.
 */
#videoVisage { transform: scaleX(-1); }

/* Le cadre de visee. Son rapport vient du type de piece, pose en variable par
   le script : un passeport n'a pas le format d'une carte bancaire. */
.cadre-document {
	position: absolute;
	left: 50%;
	top: 50%;
	width: 82%;
	max-height: 70%;
	aspect-ratio: var(--rapport, 1.586);
	transform: translate(-50%, -50%);
	border: 3px solid #f1c94b;
	border-radius: 10px;
	/* L'ombre immense assombrit TOUT sauf le cadre : la personne voit ou placer
	   sa piece sans qu'on ait a le lui ecrire. */
	box-shadow: 0 0 0 99rem rgba(5, 9, 8, 0.42);
	pointer-events: none;
}

/*
 * LA GEOMETRIE DE L'OVALE, ET RIEN QUE LA GEOMETRIE.
 *
 * Invisible : plus de bordure ni d'ombre. Sa boite reste la source de verite
 * pour deux consommateurs — `zoneSource`, qui recadre la photo dessus, et
 * `dessinerOvale`, qui en deduit l'ellipse du SVG. Un seul endroit ou changer
 * les dimensions, donc aucun risque de voir le trait et le recadrage diverger.
 */
.ovale-zone {
	position: absolute;
	left: 50%;
	top: 50%;
	width: min(50vw, 16rem);
	height: min(68vw, 22rem);
	max-height: 80%;
	transform: translate(-50%, -50%);
	pointer-events: none;
}

/*
 * UN OVALE DE VISAGE EST PLUS HAUT QUE LARGE.
 *
 * La regle ci-dessus ne le garantissait pas : `max-height: 80%` ecrasait la
 * hauteur contre un apercu en 4:3, et l'ellipse devenait COUCHEE — 195 x 175 px
 * sur un telephone, mesure au rendu. Une tete n'entre pas dedans, et on se
 * demande ce qu'on doit cadrer.
 *
 * Le rapport est donc impose, et c'est la hauteur qui mene. `@supports` parce
 * qu'un navigateur sans `aspect-ratio` lirait `width: auto` sur un element
 * absolu et reduirait l'ovale a rien — il garde alors la regle du dessus, qui
 * est imparfaite mais visible.
 */
@supports (aspect-ratio: 1 / 1) {
	.ovale-zone {
		/* 66 % et non 78 : au-dela, le bas de l'ovale passe SOUS le bandeau de
		   consigne, et on ne voit plus ou s'arrete le cadre. Remonte de quatre
		   points pour la meme raison. */
		height: min(66%, 22rem);
		max-height: none;
		aspect-ratio: 72 / 100;
		width: auto;
		top: 46%;
	}
}

/*
 * L'APERCU DU VISAGE EST EN PORTRAIT.
 *
 * Il heritait du 4:3 de la camera, donc d'un cadre large ou un ovale vertical ne
 * tient pas. On lui donne la forme de ce qu'on y cherche : un visage.
 */
#cameraVisage .apercu { aspect-ratio: 3 / 4; max-height: 70vh; }
#cameraVisage .apercu video { height: 100%; max-height: none; }

/* Le SVG couvre tout l'apercu : le voile doit assombrir au-dela de l'ellipse. */
.masque-visage {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
}

.masque-visage .voile { fill: rgba(5, 9, 8, 0.42); }

.masque-visage .contour {
	fill: none;
	stroke: #f1c94b;
	stroke-width: 3;
	/* Le trait suit exactement l'ellipse decoupee : c'est le meme calcul qui pose
	   les deux, donc ils ne peuvent plus se decaler. */
	vector-effect: non-scaling-stroke;
}

/*
 * LES DEUX ARCS LATERAUX.
 *
 * Eteints par defaut. Allumes, ils disent OU REGARDER — la consigne ecrite, mais
 * a l'endroit ou l'oeil est deja pose. Ils ne disent pas « c'est bon » : rien
 * n'est mesure pendant cette etape, et une couleur qui affirmerait un constat
 * qui n'existe pas serait pire que pas de couleur.
 */
.masque-visage .arc {
	fill: none;
	stroke: transparent;
	stroke-width: 7;
	stroke-linecap: round;
	vector-effect: non-scaling-stroke;
	transition: stroke 0.25s ease;
}

.masque-visage .arc.demande {
	stroke: #f1c94b;
	animation: arc-respire 1.6s ease-in-out infinite;
}

/*
 * LE VERT DIT « CONSTATE », ET RIEN D'AUTRE.
 *
 * Il n'apparait que quand la detection a vu le visage a la bonne taille, au bon
 * endroit, tourne du bon cote — et qu'elle l'a vu dix fois de suite. C'est le
 * meme sens que sur le cadre du document : « ne bougez plus, ca part ».
 *
 * L'animation s'arrete en meme temps : un trait qui clignote encore laisse
 * croire qu'on attend toujours quelque chose.
 */
.masque-visage .arc.constate,
.masque-visage .contour.constate {
	stroke: #37c487;
	stroke-width: 7;
	animation: none;
	opacity: 1;
}

@keyframes arc-respire {
	0%, 100% { opacity: 0.45; }
	50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
	.masque-visage .arc.demande { animation: none; opacity: 1; }
}

/* Vert des que la mesure passe le seuil : c'est le seul retour qui dise « ne
   bougez plus », et il arrive avant le declenchement.
   Le cadre du document l'a, parce qu'il MESURE (nettete + luminosite). L'ovale
   ne l'a plus : il passait au vert au dernier clic, donc il annoncait un constat
   que personne n'avait fait. */
.cadre-document.pret { border-color: #37c487; }

.indice {
	position: absolute;
	left: 0.7rem;
	right: 0.7rem;
	bottom: 0.7rem;
	margin: 0;
	padding: 0.6rem 0.7rem;
	border-radius: 6px;
	background: rgba(12, 20, 17, 0.74);
	color: #ffffff;
	font-weight: 600;
	text-align: center;
}

/* La jauge de qualite. Elle existe pour que l'attente soit lisible : sans elle,
   la capture automatique ressemble a une page qui ne fait rien. */
.jauge {
	height: 0.5rem;
	margin-top: 0.6rem;
	overflow: hidden;
	background: var(--bord);
	border-radius: 999px;
}

.jauge span {
	display: block;
	height: 100%;
	width: 0;
	background: var(--accent);
	transition: width 0.18s ease;
}

/* La planche a signer. Le cadre en pointilles dit « ecrivez ici » sans texte. */
.cadre-signature {
	position: relative;
	margin-top: 0.5rem;
	background: #ffffff;
	border: 3px dashed #f1c94b;
	border-radius: 10px;
}

.cadre-signature.signee {
	border-style: solid;
	border-color: #37c487;
}

.cadre-signature canvas {
	display: block;
	width: 100%;
	height: 12rem;
	border-radius: 8px;
	/* Sans cela, le doigt fait defiler la page au lieu de tracer. */
	touch-action: none;
}

.ligne-signature {
	position: absolute;
	left: 8%;
	right: 8%;
	bottom: 2.1rem;
	border-bottom: 1px solid var(--bord);
	pointer-events: none;
}

.indice-signature {
	position: absolute;
	left: 0;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	text-align: center;
	color: #9aa8a2;
	font-weight: 600;
	pointer-events: none;
}

.cadre-signature.signee .indice-signature { display: none; }

/* Les trois etats d'une ligne de statut. « recu » est volontairement sobre et
   SURTOUT pas vert vif : une piece recue n'est ni verifiee ni acceptee. */
.etat {
	min-height: 1.3rem;
	margin: 0.5rem 0 0;
	font-size: 0.88rem;
}

.etat.recu { color: var(--texte); font-weight: 600; }
.etat.attente { color: var(--texte-doux); }
.etat.alerte { color: var(--alerte); }

.aide {
	margin: 0.2rem 0 0;
	font-size: 0.85rem;
	color: var(--texte-doux);
}


/* ---------------------------------------------------------------------------
   L'ecran du moderateur
   --------------------------------------------------------------------------- */

/* Le bandeau : titre a gauche, sortie a droite. */
.bandeau-revue {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	align-items: flex-start;
	justify-content: space-between;
}

.bandeau-revue h1 { margin-bottom: 0.2rem; }

/* La file. `overflow-x` sur un conteneur et non sur la page : une table large
   ne doit pas faire defiler tout l'ecran lateralement. */
.file {
	display: block;
	width: 100%;
	overflow-x: auto;
	border-collapse: collapse;
	margin: 1rem 0;
}

.file caption {
	text-align: left;
	padding-bottom: 0.5rem;
	font-size: 0.85rem;
	color: var(--texte-doux);
}

.file th,
.file td {
	padding: 0.6rem 0.7rem;
	text-align: left;
	border-bottom: 1px solid var(--bord);
	vertical-align: top;
}

.file th {
	font-size: 0.78rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--texte-doux);
}

.file .contact {
	display: block;
	font-size: 0.8rem;
	color: var(--texte-doux);
}

/* La recommandation. Les trois niveaux se distinguent par la COULEUR ET par le
   texte : une pastille qui ne dirait son niveau que par sa teinte serait
   illisible pour qui ne distingue pas le rouge du vert. */
.recommandation {
	display: inline-block;
	margin-left: 0.4rem;
	padding: 0.1rem 0.5rem;
	font-size: 0.75rem;
	font-weight: 600;
	border: 1px solid var(--bord);
	border-radius: 999px;
	white-space: nowrap;
}

.recommandation.LOW_RISK_APPROVE_CANDIDATE { border-color: #37c487; }
.recommandation.MEDIUM_RISK_REVIEW { border-color: var(--attente-bord); }
.recommandation.HIGH_RISK_REVIEW,
.recommandation.HIGH_RISK_REJECT_CANDIDATE {
	border-color: var(--alerte);
	color: var(--alerte);
}

/* La fiche : libelle a gauche, valeur a droite, sur deux colonnes. */
.fiche {
	display: grid;
	grid-template-columns: minmax(8rem, auto) 1fr;
	gap: 0.35rem 1rem;
	margin: 0.6rem 0 1rem;
}

.fiche dt {
	font-size: 0.85rem;
	color: var(--texte-doux);
}

.fiche dd {
	margin: 0;
	overflow-wrap: anywhere;
}

/* Les pieces, cote a cote. C'est tout l'interet de l'ecran : confronter le
   visage de la piece a celui de la capture sans changer de page. */
.pieces {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
	gap: 1rem;
	margin: 0.8rem 0 1.5rem;
}

.pieces figure {
	margin: 0;
	padding: 0.7rem;
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: 8px;
}

/* `contain` et JAMAIS `cover` : on recadre une photo decorative, pas une piece
   d'identite. Un coin coupe est exactement ce qu'un relecteur doit voir. */
.piece {
	display: block;
	width: 100%;
	height: 11rem;
	object-fit: contain;
	background: var(--fond);
	border-radius: 6px;
}

.pieces figcaption {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.4rem;
	margin-top: 0.5rem;
	font-size: 0.85rem;
}

/* Reserve aux lecteurs d'ecran : un en-tete de colonne qui n'a pas de texte
   visible doit quand meme en avoir un. */
.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}
