/* WebBot Optima — widget de chat. Autonome, ne dépend pas du thème.
 * Palette calée sur la charte publique Optima (accent #2c5ca7, light-only). */

#webbot-optima-root {
	--wb-accent: #2c5ca7;
	--wb-accent-dark: #234a86;
	--wb-accent-grad: linear-gradient(135deg, #2c5ca7, #3a7dd2);
	--wb-bg: #ffffff;
	--wb-soft: #f6f7f9;
	--wb-text: #1e293b;
	--wb-muted: #64748b;
	--wb-border: #e4e7ec;
	--wb-border-strong: #cdd3dc;
	--wb-radius: 14px;
	position: fixed;
	right: 20px;
	/* 88px : laisse la place aux widgets bas-droite fréquents (accessibilité, cookies). */
	bottom: 88px;
	z-index: 99990;
	font-family: InterVariable, Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
	font-feature-settings: "cv11", "ss01", "ss03";
	font-size: 15px;
	line-height: 1.45;
	color: var(--wb-text);
}

/* ------------------------------------------------- Blindage thème -------
   Le widget s'installe chez l'habitant : le thème du site stylise ses
   <button> (Hello/Elementor pose une bordure et un fond de marque au survol
   ET au focus). On repart donc d'un bouton nu dans nos deux racines, sur
   TOUS les états — sans quoi un bouton neutre au repos vire aux couleurs du
   thème dès qu'on le survole. Nos propres règles, plus spécifiques,
   reprennent la main juste après. */
#webbot-optima-root button,
#webbot-optima-root button:hover,
#webbot-optima-root button:focus,
#webbot-optima-root button:active,
.wb-hero button,
.wb-hero button:hover,
.wb-hero button:focus,
.wb-hero button:active {
	background-color: transparent;
	background-image: none;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	text-decoration: none;
	text-transform: none;
	letter-spacing: normal;
	font-weight: inherit;
}

/* Notre feuille est chargée AVANT celle du thème : à spécificité égale, c'est
   le thème qui gagnerait. Le blindage doit donc le dépasser strictement — et
   se retrouve, mécaniquement, au-dessus de la définition de repos de nos
   propres boutons. Tout ce qui fait leur FORME est donc réaffirmé ici, état
   par état, à une spécificité supérieure au blindage.
   Règle à retenir en ajoutant un bouton décoré : le déclarer dans ce bloc. */
#webbot-optima-root .wb-bubble,
#webbot-optima-root .wb-bubble:hover,
#webbot-optima-root .wb-bubble:focus,
#webbot-optima-root .wb-bubble:active {
	border-radius: 50%;
	background-image: var(--wb-accent-grad);
	box-shadow: 0 6px 20px rgba(15, 23, 42, 0.22);
}

.wb-hero .wb-hero-send,
.wb-hero .wb-hero-send:hover,
.wb-hero .wb-hero-send:focus,
.wb-hero .wb-hero-send:active {
	border-radius: 50%;
	background-image: var(--wb-accent-grad);
}

#webbot-optima-root .wb-send,
#webbot-optima-root .wb-send:focus,
#webbot-optima-root .wb-send:active {
	border-radius: 50%;
	background-color: var(--wb-accent);
}

#webbot-optima-root .wb-send:hover:not(:disabled) {
	border-radius: 50%;
	background-color: var(--wb-accent-dark);
}

/* Même problème pour les LIENS : un thème qui repeint les boutons repeint
   presque toujours `a:hover`. Nos cartes ne fixaient leur couleur qu'au repos —
   d'où des titres aux couleurs du thème, soulignés, au survol. Le
   text-decoration d'un <a> se propageant à ses descendants, il est
   impossible de le rattraper depuis l'enfant : on le neutralise ici. */
#webbot-optima-root .wb-card,
#webbot-optima-root .wb-card:hover,
#webbot-optima-root .wb-card:focus,
#webbot-optima-root .wb-card:active,
#webbot-optima-root .wb-card:visited,
.wb-hero .wb-card,
.wb-hero .wb-card:hover,
.wb-hero .wb-card:focus,
.wb-hero .wb-card:active,
.wb-hero .wb-card:visited {
	text-decoration: none;
	color: var(--wb-text);
	background-color: #fff;
	background-image: none;
}

/* Les champs aussi : un `input:focus { box-shadow }` de thème poserait un halo
   de marque À L'INTÉRIEUR de la pilule blanche du héro. */
#webbot-optima-root input,
#webbot-optima-root input:hover,
#webbot-optima-root input:focus,
.wb-hero input,
.wb-hero input:hover,
.wb-hero input:focus {
	box-shadow: none;
	text-transform: none;
	letter-spacing: normal;
	min-height: 0;
}

/* Boutons discrets : pas de fond au repos, une pastille arrondie au survol. */
#webbot-optima-root .wb-close,
#webbot-optima-root .wb-close:hover,
#webbot-optima-root .wb-close:focus,
#webbot-optima-root .wb-reset,
#webbot-optima-root .wb-reset:hover,
#webbot-optima-root .wb-reset:focus {
	border-radius: 8px;
}

/* Bouton d'effacement du héro : rond, sans libellé, calé sur la même emprise
   de 32 px que la pastille de reprise. */
.wb-hero .wb-hero-reset,
.wb-hero .wb-hero-reset:hover,
.wb-hero .wb-hero-reset:focus,
.wb-hero .wb-hero-reset:active {
	border-radius: 999px;
	padding: 0;
	min-width: 32px;
	min-height: 32px;
}

/* Rembobinage. La GÉOMÉTRIE est réaffirmée ici, pas seulement la peinture :
   `min-height` l'emporte sur `height` quelle que soit la spécificité, donc un
   thème posant `button { min-height: 44px }` étirerait la pastille hors de sa
   gouttière — et sur mobile, un fil en `overflow-y: auto` (donc `overflow-x`
   calculé à `auto`) gagnerait un ascenseur horizontal. */
#webbot-optima-root .wb-rewind,
#webbot-optima-root .wb-rewind:hover,
#webbot-optima-root .wb-rewind:focus,
#webbot-optima-root .wb-rewind:active,
.wb-hero .wb-rewind,
.wb-hero .wb-rewind:hover,
.wb-hero .wb-rewind:focus,
.wb-hero .wb-rewind:active {
	border-radius: 999px;
	min-width: 0;
	min-height: 0;
	/* Le retrait droit soude la cible à la bulle : sans lui, le couloir de
	   6 px entre les deux n'appartient à personne et la pastille clignote
	   quand on le traverse. */
	padding: 0 6px 0 0;
}

/* « Annuler la reprise ». Il lui faut un contour : sur le gris du panneau
   flottant, un fond `--wb-soft` est exactement celui du fil — le bouton
   disparaîtrait purement et simplement. */
#webbot-optima-root .wb-undo-go,
#webbot-optima-root .wb-undo-go:hover,
#webbot-optima-root .wb-undo-go:focus,
#webbot-optima-root .wb-undo-go:active,
.wb-hero .wb-undo-go,
.wb-hero .wb-undo-go:hover,
.wb-hero .wb-undo-go:focus,
.wb-hero .wb-undo-go:active {
	border-radius: 999px;
	min-height: 0;
	padding: 5px 12px;
	font-weight: 500;
	background-color: var(--wb-soft);
	border: 1px solid var(--wb-border-strong);
}

#webbot-optima-root *,
#webbot-optima-root *::before,
#webbot-optima-root *::after {
	box-sizing: border-box;
}

#webbot-optima-root .wb-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;
}

/* Focus visible — outline accent, variante blanche sur aplats bleus */
#webbot-optima-root :focus-visible {
	outline: 2px solid var(--wb-accent);
	outline-offset: 2px;
}

#webbot-optima-root .wb-bubble:focus-visible,
#webbot-optima-root .wb-close:focus-visible {
	outline-color: #ffffff;
}

/* Bulle */
#webbot-optima-root .wb-bubble {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	border: 0;
	border-radius: 50%;
	background: var(--wb-accent-grad);
	color: #fff;
	cursor: pointer;
	box-shadow: 0 6px 20px rgba(15, 23, 42, 0.22);
	transition: transform 0.15s ease, filter 0.15s ease;
}

#webbot-optima-root .wb-bubble:hover {
	filter: brightness(0.94);
	transform: scale(1.06);
}

/* Panneau */
#webbot-optima-root .wb-panel {
	position: absolute;
	right: 0;
	bottom: 70px;
	display: flex;
	flex-direction: column;
	width: 370px;
	max-width: calc(100vw - 32px);
	height: 520px;
	max-height: calc(100vh - 120px);
	background: var(--wb-bg);
	border-radius: var(--wb-radius);
	box-shadow: 0 12px 40px rgba(15, 23, 42, 0.18);
	overflow: hidden;
}

#webbot-optima-root .wb-panel[hidden] {
	display: none;
}

#webbot-optima-root .wb-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 10px 8px 10px 16px;
	background: var(--wb-accent-grad);
	color: #fff;
}

#webbot-optima-root .wb-title {
	font-weight: 600;
}

/* ---------------------------------------------- Suggestion cliquable ----
   Le texte gris du champ n'est pas un placeholder mais un vrai bouton posé
   par-dessus : on peut cliquer DESSUS pour l'accepter, tandis qu'un clic
   ailleurs dans la barre place simplement le curseur, comme d'habitude. */

#webbot-optima-root .wb-field,
.wb-hero .wb-field {
	position: relative;
	display: flex;
	flex: 1;
	min-width: 0;
}

#webbot-optima-root .wb-ghost,
.wb-hero .wb-ghost {
	position: absolute;
	top: 0;
	bottom: 0;
	/* Aligné sur le texte saisi : retrait du champ (15px) + sa bordure (1px).
	   Pas de `right` : la zone cliquable s'arrête au texte, tout le reste de
	   la barre continue de servir à poser le curseur. */
	left: 16px;
	display: flex;
	align-items: center;
	max-width: calc(100% - 32px);
	border: 0;
	padding: 0;
	background: none;
	font: inherit;
	text-align: left;
	color: var(--wb-muted);
	cursor: pointer;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	transition: color 0.15s ease;
}

#webbot-optima-root .wb-ghost[hidden],
.wb-hero .wb-ghost[hidden] {
	display: none;
}

/* Le héro a un champ sans retrait propre : le fantôme se cale sur son bord. */
.wb-hero .wb-ghost {
	left: 0;
	max-width: 100%;
}

/* Au repos, la suggestion se lit comme un VRAI placeholder : le gris de
   l'invite du champ, aucune décoration — rien ne doit trahir qu'elle est autre
   chose qu'un texte d'attente. Elle ne se signale comme cliquable qu'au survol
   ou au focus clavier : accent + gras.
   Décision PO du 2026-07-31, qui arbitre contre l'affordance permanente en
   pointillé. Reste ouvert : le tactile, où le survol n'existe pas — la
   suggestion y est aujourd'hui sans signal de cliquabilité. */
#webbot-optima-root .wb-ghost,
.wb-hero .wb-ghost {
	text-decoration: none;
}

/* Bouton décoré au survol → déclaré à une spécificité qui passe au-dessus du
   blindage (voir le bloc « Blindage thème »), sans quoi son `font-weight:
   inherit` reprendrait la main sur le gras à l'instant du survol. */
#webbot-optima-root .wb-ghost:hover:not(:disabled),
.wb-hero .wb-ghost:hover:not(:disabled),
#webbot-optima-root .wb-ghost:focus-visible,
.wb-hero .wb-ghost:focus-visible {
	color: var(--wb-accent);
	font-weight: 700;
	text-decoration: none;
}

#webbot-optima-root .wb-ghost:focus-visible,
.wb-hero .wb-ghost:focus-visible {
	outline-offset: -2px;
	border-radius: 8px;
}

#webbot-optima-root .wb-ghost:disabled,
.wb-hero .wb-ghost:disabled {
	opacity: 0.45;
	cursor: default;
}

#webbot-optima-root .wb-header-actions {
	display: flex;
	align-items: center;
}

#webbot-optima-root .wb-close,
#webbot-optima-root .wb-reset {
	display: flex;
	align-items: center;
	justify-content: center;
	min-width: 40px;
	min-height: 40px;
	border: 0;
	background: none;
	color: #fff;
	font-size: 22px;
	line-height: 1;
	cursor: pointer;
	border-radius: 8px;
}

#webbot-optima-root .wb-close:hover:not(:disabled),
#webbot-optima-root .wb-reset:hover:not(:disabled) {
	background: rgba(255, 255, 255, 0.16);
}

/* Fil de messages */
#webbot-optima-root .wb-messages {
	flex: 1;
	overflow-y: auto;
	/* Un peu plus d'air sur les côtés que sur le haut/bas. */
	padding: 14px 16px;
	display: flex;
	flex-direction: column;
	gap: 10px;
	background: var(--wb-soft);
}

#webbot-optima-root .wb-msg,
.wb-hero .wb-msg {
	max-width: 85%;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

#webbot-optima-root .wb-msg--assistant,
.wb-hero .wb-msg--assistant {
	align-self: flex-start;
}

#webbot-optima-root .wb-msg--user,
.wb-hero .wb-msg--user {
	align-self: flex-end;
}

#webbot-optima-root .wb-msg-text,
.wb-hero .wb-msg-text {
	padding: 9px 13px;
	border-radius: 12px;
	white-space: pre-wrap;
	word-wrap: break-word;
}

#webbot-optima-root .wb-msg--assistant .wb-msg-text,
.wb-hero .wb-msg--assistant .wb-msg-text {
	background: #fff;
	border: 1px solid var(--wb-border);
	border-bottom-left-radius: 4px;
}

#webbot-optima-root .wb-msg--user .wb-msg-text,
.wb-hero .wb-msg--user .wb-msg-text {
	background: var(--wb-accent);
	color: #fff;
	border-bottom-right-radius: 4px;
}

/* ------------------------------------------------- Rembobinage du fil ---
   Chaque question posée peut redevenir le point de départ. Le bouton se pose
   DANS la gouttière à gauche de la bulle (elle fait au minimum 12 % de la
   largeur du fil, la pastille tient dedans sans jamais déborder). */

#webbot-optima-root .wb-msg--user,
.wb-hero .wb-msg--user {
	position: relative;
}

#webbot-optima-root .wb-rewind,
.wb-hero .wb-rewind {
	position: absolute;
	top: 50%;
	right: 100%;
	transform: translateY(-50%);
	margin-right: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	/* 32 px de cible (SC 2.5.8), glyphe à 15 px : l'emprise grandit, pas le
	   dessin. La gouttière la plus étroite (héro à 320 px) laisse ~35 px. */
	width: 32px;
	height: 32px;
	border: 0;
	background: none;
	color: var(--wb-muted);
	cursor: pointer;
	/* Discret au repos : le fil doit rester une conversation, pas une barre
	   d'outils. Il se révèle au survol du message ou au passage clavier —
	   et `pointer-events: none` évite qu'un contrôle INVISIBLE ouvre un flux
	   destructif sur les appareils qui se déclarent à tort « hover: hover »
	   (tablettes Windows, iPad avec pointeur). Le focus clavier, lui, n'est
	   pas concerné par pointer-events. */
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}

#webbot-optima-root .wb-msg--user:hover .wb-rewind:not(:disabled),
.wb-hero .wb-msg--user:hover .wb-rewind:not(:disabled),
#webbot-optima-root .wb-rewind:focus-visible,
.wb-hero .wb-rewind:focus-visible {
	opacity: 1;
	pointer-events: auto;
}

/* Teinte d'accent plutôt que `--wb-soft` : dans le widget flottant, le fil EST
   déjà `--wb-soft`, la pastille n'aurait aucune surface au survol. */
#webbot-optima-root .wb-rewind:hover:not(:disabled),
.wb-hero .wb-rewind:hover:not(:disabled),
#webbot-optima-root .wb-rewind:active:not(:disabled),
.wb-hero .wb-rewind:active:not(:disabled) {
	color: var(--wb-accent);
	background-color: rgba(44, 92, 167, 0.1);
}

/* Une réponse est en route : rembobiner la ferait atterrir dans un fil qui
   n'est plus le sien. */
#webbot-optima-root .wb-rewind:disabled,
.wb-hero .wb-rewind:disabled {
	opacity: 0;
	pointer-events: none;
}

/* Sans survol, le bouton ne se montrerait jamais : en tactile il reste visible
   en permanence. À pleine opacité — c'est le SEUL signal de la fonction sur
   mobile, et `--wb-muted` à 0.5 tombait à 1,9:1, sous le plancher de 3:1 des
   éléments non textuels. La discrétion vient de la taille et de la position,
   pas de l'alpha. */
@media (hover: none) {
	#webbot-optima-root .wb-rewind:not(:disabled),
	.wb-hero .wb-rewind:not(:disabled) {
		opacity: 1;
		pointer-events: auto;
	}
}

/* Le filet de rattrapage, posé APRÈS coup : la reprise est immédiate, mais
   tant que cette bande est là, elle est réversible. */
#webbot-optima-root .wb-undo,
.wb-hero .wb-undo {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
	padding: 9px 12px;
	/* Trait plein et légère teinte : en pointillé gris la bande passait
	   visuellement DERRIÈRE les bulles, alors qu'elle est la seule chose qui
	   sépare le visiteur d'une perte définitive. Le pointillé dit d'ailleurs
	   « emplacement vide » dans la plupart des langages visuels — l'inverse
	   d'un événement qui vient de se produire. */
	border: 1px solid rgba(44, 92, 167, 0.35);
	border-radius: 10px;
	font-size: 13px;
	line-height: 1.35;
	/* Teinte OPAQUE, pas une transparence : le fil du héro n'a pas de fond, la
	   bande hériterait donc de celui de la page — un héro posé dans une section
	   colorée faisait tomber le texte sous 4,5:1. C'est un encart, il porte son
	   propre fond (l'accent à 5 % sur blanc). */
	background: #f5f8fd;
	color: var(--wb-text);
}

#webbot-optima-root .wb-undo-label,
.wb-hero .wb-undo-label {
	flex: 1;
	min-width: 140px;
}

/* Ni `border` ni raccourci `font` ici : à spécificité égale, ils annuleraient
   le contour et la graisse posés dans le bloc de blindage plus haut. */
#webbot-optima-root .wb-undo-go,
.wb-hero .wb-undo-go {
	padding: 5px 12px;
	font-family: inherit;
	font-size: 13px;
	line-height: 1.35;
	cursor: pointer;
	flex-shrink: 0;
	background: var(--wb-soft);
	color: var(--wb-text);
}

#webbot-optima-root .wb-undo-go:hover,
.wb-hero .wb-undo-go:hover {
	background: #eceef1;
}

/* Cartes de contenu */
#webbot-optima-root .wb-cards,
.wb-hero .wb-cards {
	display: flex;
	flex-direction: column;
	gap: 8px;
	width: 100%;
}

#webbot-optima-root .wb-card,
.wb-hero .wb-card {
	display: flex;
	gap: 10px;
	background: #fff;
	border: 1px solid var(--wb-border);
	border-radius: 10px;
	/* 12 px, pas 8 : le texte d'une carte tombe alors sur celui des bulles
	   (1 px de bord + 12 ≈ 1 + 13), un écart de 5 px se voyait depuis que la
	   barre et le fil sont calés. */
	padding: 8px 12px;
	text-decoration: none;
	color: var(--wb-text);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

#webbot-optima-root .wb-card:hover,
.wb-hero .wb-card:hover {
	border-color: var(--wb-accent);
	box-shadow: 0 3px 12px rgba(15, 23, 42, 0.12);
}

#webbot-optima-root .wb-card-thumb,
.wb-hero .wb-card-thumb {
	width: 58px;
	height: 58px;
	object-fit: cover;
	border-radius: 7px;
	flex-shrink: 0;
}

#webbot-optima-root .wb-card-body,
.wb-hero .wb-card-body {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

#webbot-optima-root .wb-card-title,
.wb-hero .wb-card-title {
	font-weight: 600;
	font-size: 14px;
	color: var(--wb-accent);
}

#webbot-optima-root .wb-card-excerpt,
.wb-hero .wb-card-excerpt {
	font-size: 12.5px;
	color: var(--wb-muted);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* Indicateur de frappe */
#webbot-optima-root .wb-typing,
.wb-hero .wb-typing {
	flex-direction: row;
	gap: 4px;
	padding: 12px 14px;
	background: #fff;
	border: 1px solid var(--wb-border);
	border-radius: 12px;
	border-bottom-left-radius: 4px;
	width: max-content;
}

#webbot-optima-root .wb-typing i,
.wb-hero .wb-typing i {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--wb-muted);
	animation: wb-blink 1.2s infinite ease-in-out;
}

#webbot-optima-root .wb-typing i:nth-child(2),
.wb-hero .wb-typing i:nth-child(2) { animation-delay: 0.15s; }
#webbot-optima-root .wb-typing i:nth-child(3),
.wb-hero .wb-typing i:nth-child(3) { animation-delay: 0.3s; }

@keyframes wb-blink {
	0%, 60%, 100% { opacity: 0.25; }
	30% { opacity: 1; }
}

/* Saisie */
#webbot-optima-root .wb-form {
	display: flex;
	gap: 8px;
	/* NB : ne pas toucher au retrait interne de .wb-input — l'aplomb de la
	   suggestion (.wb-ghost { left: 16px }) est calé dessus au pixel près. */
	padding: 10px 14px;
	border-top: 1px solid var(--wb-border);
	background: #fff;
}

#webbot-optima-root .wb-input {
	flex: 1;
	border: 1px solid var(--wb-border-strong);
	border-radius: 999px;
	padding: 9px 15px;
	font: inherit;
	color: inherit;
	outline: none;
}

#webbot-optima-root .wb-input:focus {
	border-color: var(--wb-accent);
	box-shadow: 0 0 0 3px rgba(44, 92, 167, 0.15);
}

#webbot-optima-root .wb-input:disabled,
#webbot-optima-root .wb-send:disabled {
	opacity: 0.45;
	cursor: default;
}

#webbot-optima-root .wb-send {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 0;
	border-radius: 50%;
	background: var(--wb-accent);
	color: #fff;
	cursor: pointer;
	flex-shrink: 0;
}

#webbot-optima-root .wb-send:hover:not(:disabled) {
	background: var(--wb-accent-dark);
}

/* La région live sort de la clandestinité quand un voyant doit la lire aussi
   (une section de la page vient d'être personnalisée).
   Le sélecteur DOUBLE la classe `.wb-sr-only` au lieu de compter sur l'ordre :
   celle du héro est déclarée plus bas dans le fichier, à spécificité égale,
   et reprenait donc la main — le message était invisible sur le héro, c'est-à-
   dire sur l'intégration principale du site. */
#webbot-optima-root .wb-sr-only.wb-status-visible,
.wb-hero .wb-sr-only.wb-status-visible {
	position: static;
	width: auto;
	height: auto;
	margin: 0;
	padding: 8px 4px 0;
	clip: auto;
	overflow: visible;
	white-space: normal;
	font-size: 12.5px;
	line-height: 1.35;
	/* Pas `--wb-muted` : une annonce qui doit être VUE ne peut pas se donner
	   la couleur d'une mention secondaire. */
	color: var(--wb-text);
	text-align: left;
}

/* ================================================================== HÉRO
 * [webbot_optima] — la barre d'entrée principale, dans la page.
 * La conversation se déroule dessous, dans le flux. */

.wb-hero {
	--wb-hero-size: 17px;
	/* Gouttière horizontale du fil. Calée pour que le texte des bulles
	   (+13 px de retrait propre) tombe sur celui de la barre de saisie, dont
	   le retrait est de 28 px. Changer l'un = changer l'autre. */
	--wb-hero-gutter: 14px;
	--wb-accent: #2c5ca7;
	--wb-accent-dark: #234a86;
	--wb-accent-grad: linear-gradient(135deg, #2c5ca7, #3a7dd2);
	--wb-soft: #f6f7f9;
	--wb-text: #1e293b;
	--wb-muted: #64748b;
	--wb-border: #e4e7ec;
	--wb-border-strong: #cdd3dc;
	width: 100%;
	max-width: 760px;
	margin: 0 auto;
	font-family: InterVariable, Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
	font-feature-settings: "cv11", "ss01", "ss03";
	font-size: 16px;
	line-height: 1.5;
	color: var(--wb-text);
}

.wb-hero *,
.wb-hero *::before,
.wb-hero *::after {
	box-sizing: border-box;
}

.wb-hero .wb-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;
}

.wb-hero :focus-visible {
	outline: 2px solid var(--wb-accent);
	outline-offset: 2px;
}

/* Bloc conversation : la barre d'outils vit HORS du fil, sinon le dégradé
   d'effacement du haut la mangerait aussi. */
.wb-hero .wb-hero-convo {
	margin: 0 0 18px;
}

.wb-hero .wb-hero-convo[hidden] {
	display: none;
}

.wb-hero .wb-hero-tools {
	display: flex;
	justify-content: flex-end;
	margin-bottom: 6px;
}

.wb-hero .wb-hero-reset {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	border: 0;
	border-radius: 999px;
	background: none;
	color: var(--wb-muted);
	cursor: pointer;
	transition: color 0.15s ease, background-color 0.15s ease;
}

/* Teinte d'accent plutôt que --wb-soft : dans le widget flottant, --wb-soft est
   déjà le fond du fil (voir la pastille de reprise, même raison). */
.wb-hero .wb-hero-reset:hover:not(:disabled),
.wb-hero .wb-hero-reset:active:not(:disabled) {
	color: var(--wb-accent);
	background: rgba(44, 92, 167, 0.1);
}

/* Rien à effacer, ou réponse en cours : le bouton se retire poliment plutôt
   que de rester cliquable pour ne rien faire. */
.wb-hero .wb-hero-reset:disabled,
#webbot-optima-root .wb-reset:disabled,
#webbot-optima-root .wb-close:disabled {
	opacity: 0.4;
	cursor: default;
}

/* Après un effacement, le fil ne porte plus que le « Annuler » : un bouton
   d'effacement grisé au-dessus serait une tache sans fonction. On le retire
   de la vue en gardant sa place, pour que la bande ne saute pas. */
.wb-hero .wb-hero-reset:disabled {
	visibility: hidden;
}

/* Fil de conversation : au-dessus de la barre, dans la page.
   Le bloc épouse la hauteur des messages et ne se met à défiler qu'une fois la
   limite atteinte — pas de saut d'un fil vide à un cadre pleine hauteur. */
.wb-hero .wb-hero-thread {
	display: flex;
	flex-direction: column;
	gap: 12px;
	/* Le fil respire sur les deux bords, comme la barre de saisie. */
	padding: 2px var(--wb-hero-gutter);
	/* Gouttière d'ascenseur réservée en permanence : sans ça, un ascenseur
	   classique (Firefox/Windows, par opposition aux ascenseurs en
	   surimpression de macOS) rogne la boîte dès que le fil défile et casse la
	   symétrie gauche/droite. */
	scrollbar-gutter: stable;
	max-height: min(440px, 62vh);
	max-height: min(440px, 62dvh);
	overflow-y: auto;
	overscroll-behavior: contain;
	/* Un élément ramené en haut du fil par Tab se retrouverait sous le fondu,
	   contour de focus compris. */
	scroll-padding-top: 76px;
	/* Pas de fond ni de cadre : la conversation se pose directement dans la
	   page, seules les bulles de messages portent une surface. */
	background: none;
	border: 0;
}

/* Le fondu du haut n'apparaît qu'une fois le fil réellement défilé — sinon il
   mangerait le premier message d'une conversation qui tient dans le cadre.
   La classe est posée par le JS au défilement. */
.wb-hero .wb-hero-thread.wb-faded {
	-webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 72px);
	mask-image: linear-gradient(to bottom, transparent 0, #000 72px);
}

/* Ascenseur dessiné : fin, arrondi, sans piste, et discret tant qu'on ne
   survole pas le fil. */
.wb-hero .wb-hero-thread,
#webbot-optima-root .wb-messages {
	scrollbar-width: thin;
	scrollbar-color: rgba(100, 116, 139, 0.25) transparent;
}

.wb-hero .wb-hero-thread::-webkit-scrollbar,
#webbot-optima-root .wb-messages::-webkit-scrollbar {
	width: 6px;
}

.wb-hero .wb-hero-thread::-webkit-scrollbar-track,
#webbot-optima-root .wb-messages::-webkit-scrollbar-track {
	background: transparent;
}

.wb-hero .wb-hero-thread::-webkit-scrollbar-thumb,
#webbot-optima-root .wb-messages::-webkit-scrollbar-thumb {
	background-color: rgba(100, 116, 139, 0.25);
	border-radius: 999px;
}

.wb-hero .wb-hero-thread:hover,
#webbot-optima-root .wb-messages:hover {
	scrollbar-color: rgba(100, 116, 139, 0.45) transparent;
}

.wb-hero .wb-hero-thread:hover::-webkit-scrollbar-thumb,
#webbot-optima-root .wb-messages:hover::-webkit-scrollbar-thumb {
	background-color: rgba(100, 116, 139, 0.45);
}

.wb-hero .wb-msg {
	max-width: 88%;
}

/* Le fil n'a plus de fond : c'est la bulle qui porte la surface, sinon la
   réponse de l'assistant serait blanche sur blanc. */
.wb-hero .wb-msg--assistant .wb-msg-text {
	background: var(--wb-soft);
	border-color: transparent;
}

/* Cartes en grille sur la largeur du héro */
.wb-hero .wb-cards {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	gap: 10px;
}

/* La barre principale */
.wb-hero .wb-hero-form {
	display: flex;
	align-items: center;
	gap: 10px;
	/* Retrait gauche = point d'alignement du texte saisi (voir --wb-hero-gutter). */
	padding: 8px 12px 8px 28px;
	background: #fff;
	border: 1px solid var(--wb-border-strong);
	border-radius: 999px;
	box-shadow: 0 10px 34px rgba(15, 23, 42, 0.12);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.wb-hero .wb-hero-form:focus-within {
	border-color: var(--wb-accent);
	box-shadow: 0 10px 34px rgba(44, 92, 167, 0.22);
}

.wb-hero .wb-hero-input {
	flex: 1;
	min-width: 0;
	border: 0;
	background: none;
	padding: 14px 0;
	font: inherit;
	/* Taille partagée avec la suggestion : elle doit se lire comme un texte
	   déjà dans le champ, sans saut de corps au moment où on l'accepte. */
	font-size: var(--wb-hero-size);
	color: inherit;
	outline: none;
}

.wb-hero .wb-ghost {
	font-size: var(--wb-hero-size);
}

.wb-hero .wb-hero-input::placeholder {
	color: var(--wb-muted);
}

.wb-hero .wb-hero-input:disabled {
	opacity: 0.45;
}

.wb-hero .wb-hero-send {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	border: 0;
	border-radius: 50%;
	background: var(--wb-accent-grad);
	color: #fff;
	cursor: pointer;
	flex-shrink: 0;
	transition: filter 0.15s ease;
}

.wb-hero .wb-hero-send:hover:not(:disabled) {
	filter: brightness(0.94);
}

.wb-hero .wb-hero-send:disabled {
	opacity: 0.45;
	cursor: default;
}

/* Le fil grandit AU-DESSUS de la barre : plus il est haut, plus la barre
   descend. Sur un écran court clavier ouvert, elle sortait du champ visible —
   d'où une hauteur réduite en petit écran, et `dvh` qui, lui, tient compte du
   clavier là où `vh` ne bouge pas. */
@media (max-width: 640px) {
	.wb-hero .wb-hero-thread {
		max-height: min(300px, 44vh);
		max-height: min(300px, 44dvh);
	}
}

@media (max-width: 480px) {
	.wb-hero {
		--wb-hero-size: 16px; /* évite le zoom auto iOS */
		/* La barre porte champ + envoi : à 320 px il ne restait que ~150 px de
		   texte utile quand elle portait aussi le micro (retiré en v0.28.0).
		   On récupère de la place sur les retraits. La gouttière du fil suit le
		   retrait de la barre — les deux se changent ensemble, voir
		   --wb-hero-gutter. */
		--wb-hero-gutter: 10px;
	}

	.wb-hero .wb-hero-form {
		padding-left: 18px;
		gap: 6px;
	}

	.wb-hero .wb-cards {
		grid-template-columns: 1fr;
	}

	/* Même raison côté widget : Safari iOS zoome tout champ sous 16px. */
	#webbot-optima-root .wb-input,
	#webbot-optima-root .wb-ghost {
		font-size: 16px;
	}
}

/* Mode barre : champ de saisie visible en permanence, conversation déployée au focus */
#webbot-optima-root.wb-mode-bar .wb-bubble {
	display: none;
}

#webbot-optima-root.wb-mode-bar .wb-panel {
	position: static;
	width: 340px;
	height: auto;
	max-height: none;
}

#webbot-optima-root.wb-mode-bar:not(.wb-open) .wb-panel {
	border-radius: 999px;
	box-shadow: 0 8px 28px rgba(15, 23, 42, 0.16);
}

#webbot-optima-root.wb-mode-bar:not(.wb-open) .wb-header,
#webbot-optima-root.wb-mode-bar:not(.wb-open) .wb-messages {
	display: none;
}

#webbot-optima-root.wb-mode-bar:not(.wb-open) .wb-form {
	border-top: 0;
	border-radius: 999px;
}

#webbot-optima-root.wb-mode-bar.wb-open .wb-panel {
	width: 370px;
	height: 520px;
	max-height: calc(100vh - 120px);
}

/* Mobile : panneau plein écran en bas (état déployé uniquement) */
@media (max-width: 480px) {
	#webbot-optima-root.wb-mode-bar:not(.wb-open) .wb-panel {
		width: calc(100vw - 40px);
	}

	#webbot-optima-root:not(.wb-mode-bar) .wb-panel,
	#webbot-optima-root.wb-mode-bar.wb-open .wb-panel {
		position: fixed;
		inset: auto 0 0 0;
		width: 100%;
		max-width: 100%;
		height: 78vh;
		height: 78dvh;
		max-height: none;
		border-radius: var(--wb-radius) var(--wb-radius) 0 0;
	}
}

/* Accessibilité : réduire les animations si demandé */
@media (prefers-reduced-motion: reduce) {
	#webbot-optima-root .wb-bubble,
	#webbot-optima-root .wb-bubble:hover {
		transition: none;
		transform: none;
	}

	#webbot-optima-root .wb-typing i,
	.wb-hero .wb-typing i {
		animation: none;
		opacity: 0.6;
	}
}

/* ============================================================ Personnage

   La mascotte Optima, posée à gauche de la barre du héro. Elle porte deux
   signaux que l'interface n'avait pas : la réflexion pendant la latence, et
   le pointage quand une section de la page vient de changer.

   FEUILLE DÉTOURÉE, à canal alpha (0.30.1). Elle était auparavant à fond
   blanc opaque, affichée en `mix-blend-mode: multiply` — une astuce qui
   effaçait le blanc sans payer le canal. Elle exigeait en retour un fond
   clair : vrai dans le flux d'une page blanche, faux dès que le personnage
   déborde au-dessus d'un contenu quelconque, ce que le dock fait par
   construction. Sur les chantiers v2 cela donnait un rectangle blanc opaque
   posé sur la photo du héro.
   Le détourage se fait par RÉGION CONNEXE, et il a fallu deux essais ratés
   pour y arriver — les deux sont instructifs :
   1. alpha proportionnelle à la noirceur du pixel → le corps devient
      translucide, puisqu'il va du gris 33 au gris 165. On voyait la page à
      travers le robot.
   2. alpha par seuil de clarté → l'ŒIL du robot, point lumineux quasi blanc,
      passe pour du fond. On lui perce un trou.
   3. le correctif du 2 écrit à son tour, dans le masque, le clair enfermé et le
      fond dans LA MÊME couleur avant de les distinguer. Les deux redevenaient
      du fond : l'œil restait troué, et la mesure disait le contraire parce
      qu'elle sondait un rectangle qui contenait aussi du fond.
   La règle juste : le fond n'est pas « ce qui est clair », c'est « ce qui est
   clair ET connexe au bord de l'image ». Le clair ENFERMÉ dans la silhouette
   — l'œil — reste opaque. Recette reproductible dans `assets/perso/detourage.sh`.
   La couleur est dépremultipliée : pas de frange blanche sur les bords.
   Recomposée sur blanc, la feuille détourée redonne l'originale au pixel près.
   Prix : 486 Ko → 1,15 Mo, au premier survol seulement.

   Le personnage déborde volontairement à gauche du héro. Sous 1025 px il est
   MASQUÉ : il n'y a pas la place, et la page d'accueil déborde déjà
   horizontalement sur mobile (`min-width: 600px` sur la rangée du héro, sans
   reprise responsive). Tant que ce défaut n'est pas réglé, le personnage ne
   doit pas l'aggraver. */

.wb-hero {
	position: relative;
}

.wb-perso {
	/* Taille d'AFFICHAGE, indépendante des 128x225 auxquels la feuille est
	   dessinée : la découpe se fait en pourcentages (voir `poser()` dans
	   perso.js), le personnage suit donc sa boîte. */
	--wb-perso-w: 88px;
	--wb-perso-h: 148px;
	--wb-perso-gap: 16px;
	/* Variabilisé pour qu'un intégrateur ajuste le dégagement sans toucher au
	   CSS du plugin. Le personnage monte ~150 px au-dessus de la barre, dans
	   la gouttière gauche : prévoir ce dégagement au-dessus. ⚠️ Depuis le
	   détourage (0.30.1) une collision MASQUE : le personnage est opaque et
	   recouvre ce qui passe dessous. Avec `multiply` le texte le traversait. */
	--wb-perso-bottom: -12px;
	position: absolute;
	left: calc(-1 * (var(--wb-perso-w) + var(--wb-perso-gap)));
	bottom: var(--wb-perso-bottom);
	width: var(--wb-perso-w);
	height: var(--wb-perso-h);
	background-repeat: no-repeat;
	background-position: 0 0;
	/* Pose fixe tant que la feuille n'est pas chargée. Le JS remplace cette
	   image et pose `background-size` une fois la feuille décodée. */
	background-size: 100% 100%;
	/* Le personnage FAIT PARTIE de la zone de survol.
	   En `pointer-events: none`, le pointeur ne pouvait jamais l'atteindre :
	   aller le regarder revenait donc à QUITTER le héro, et l'animation
	   s'arrêtait au moment précis où on la regardait. Comme il est un
	   descendant de `.wb-hero`, le rendre survolable suffit — `mouseleave` ne
	   se déclenche pas quand on passe sur un descendant, même situé hors de
	   la boîte du parent.
	   Il reste décoratif : `aria-hidden` côté balisage, aucun curseur de
	   clic, et rien d'interactif derrière lui (il vit dans la gouttière). */
	cursor: default;
	user-select: none;
}

/* 1100 px et pas 1025 : le héro fait 760 px centrés et le personnage réclame
   144 px à sa gauche, soit 1048 px de conteneur — et un débordement à gauche
   en LTR ne crée pas d'ascenseur, il COUPE : on afficherait un demi-robot. Le
   reste absorbe les marges intérieures du conteneur qui l'accueille.
   MIROIR de la constante `SEUIL` de `perso.js`, qui empêche le téléchargement
   de la feuille en dessous. Changer l'un = changer l'autre. */
@media (max-width: 1099px) {
	.wb-perso {
		display: none;
	}
}

/* En contraste forcé, le navigateur ne peut pas corriger une image : le
   personnage resterait tel quel dans une palette qu'il ignore. Autant le
   retirer franchement que laisser une tache — le signal textuel, lui, reste. */
@media (forced-colors: active) {
	.wb-perso {
		display: none;
	}
}

/* ------------------------------------------------ Fondu de la section désignée

   Le bloc s'efface puis revient, et il atteint 100 % PILE au moment où le
   doigt du personnage arrive en bas. C'est ce qui relie le geste à sa cible :
   sans lui, le personnage désignerait une section présente à l'écran depuis
   deux secondes — donc ne désignerait rien.

   La durée est posée par `blocks.js` d'après le tempo réel du geste, que seul
   le personnage connaît. La classe est retirée à la fin de l'animation, sinon
   deux désignations rapprochées ne rejoueraient pas (`animation-name` ne
   changerait jamais) — le piège mesuré au banc le 2026-08-01. */

.wb-block-flash {
	animation: wb-block-flash var(--wb-flash-duree, 900ms) ease-in-out both;
}

@keyframes wb-block-flash {
	0%   { opacity: 1; }
	28%  { opacity: 0.08; }
	100% { opacity: 1; }
}

/* Le fondu est un confort de mise en scène, jamais un porteur d'information :
   qui demande moins d'animations garde la section, simplement affichée. */
@media (prefers-reduced-motion: reduce) {
	.wb-block-flash {
		animation: none;
	}
}

/* ================================================================== DOCK
 * Le héro, ancré en bas de l'écran. Aucun style de composant ici : tout vient
 * du bloc HÉRO ci-dessus, qui tourne sur le pilote depuis le premier jour.
 * Ce bloc ne fait que POSER le composant — et lui donner la surface blanche
 * qu'il avait dans la page. */

.wb-dock {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	/* Sous les modales d'un thème, au-dessus du contenu ordinaire. */
	z-index: 999990;
	/* La surface du composant, reprise du héro tel qu'il vit dans la page. */
	background: var(--wb-bg);
	border-top: 1px solid var(--wb-border);
	box-shadow: 0 -6px 24px rgba(15, 23, 42, 0.06);
	padding: 12px 24px 14px;
}

/* Le fil grandit vers le HAUT, plafonné : ancré, il ne peut plus pousser la
   page devant lui. Plus court que dans le flux (440 px / 62 dvh) — un dispositif
   permanent qui mange les deux tiers de l'écran cesse d'être une barre. */
.wb-dock .wb-hero-thread {
	max-height: min(300px, 40vh);
	max-height: min(300px, 40dvh);
}

/* Le personnage déborde vers le haut, hors de la barre : il doit rester
   visible au-dessus d'elle, pas être rogné par son cadre. */
.wb-dock {
	overflow: visible;
}

@media (max-width: 640px) {
	.wb-dock {
		padding: 10px 14px 12px;
	}

	.wb-dock .wb-hero-thread {
		max-height: min(240px, 38dvh);
	}
}
