:root { --density: 0.9; }
html { font-size: calc(14px * var(--density)); }

/* ════════════════════════════════════════════════════════════════════════
   Thème Keycloak « GED » — feuille de style login.
   Portée VERBATIM depuis app/globals.css (bloc .login-wrap, lignes ~560-836)
   pour garantir un rendu 1:1 avec l'écran de connexion React de l'app.
   L'écran de login est TOUJOURS clair (color-scheme: light).
   Police : Plus Jakarta Sans (sans) + JetBrains Mono (--font-mono).
   ════════════════════════════════════════════════════════════════════════ */
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;700&display=swap");

/* ── Reset / base (aucune CSS Keycloak parente : template.ftl est autonome) ── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }
body {
  font-family: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  color: var(--ink); background: var(--paper);
}
:root { --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
button { font-family: inherit; }
a { color: inherit; }
.icon { display: inline-block; vertical-align: middle; }

/* ════════════════════════════════════════════════════════════════════════
   Tokens partagés (.login-wrap) — échelle verte + sémantique claire du portail.
   ════════════════════════════════════════════════════════════════════════ */
.login-wrap, .lp-scope {
  color-scheme: light;
  /* ── LA TEINTE ET LA SATURATION DE LA MARQUE ──────────────────────────
   *  Ce thème est servi PAR KEYCLOAK : il ne lit ni `app_config` ni le pont.
   *  La GED pousse les deux nombres en attributs du realm PORTAIL, et
   *  `template.ftl` les écrit — la couleur suit sans redéployer le thème.
   *
   *  Défauts : 155 et 1, les coordonnées de `--green-600` (= `--primary` du
   *  portail). Un VERT, comme le reste du portail — et non le violet de la
   *  GED. Miroir exact de `ged-portal/app/globals.css`.
   *
   *  Les couleurs de SENS — statuts, alertes — ne suivent pas. */
  --teinte-marque: 155;
  --facteur-chroma: 1;

  --green-950: oklch(0.20 calc(0.035 * var(--facteur-chroma)) calc(var(--teinte-marque) + 3));
  --green-900: oklch(0.26 calc(0.045 * var(--facteur-chroma)) calc(var(--teinte-marque) + 3));
  --green-800: oklch(0.33 calc(0.065 * var(--facteur-chroma)) calc(var(--teinte-marque) + 2));
  --green-700: oklch(0.44 calc(0.095 * var(--facteur-chroma)) calc(var(--teinte-marque) + 1));
  --green-600: oklch(0.53 calc(0.115 * var(--facteur-chroma)) var(--teinte-marque));
  --green-500: oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2));
  --green-300: oklch(0.80 calc(0.10 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5));
  --green-100: oklch(0.93 calc(0.035 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5));
  --green-50:  oklch(0.97 calc(0.018 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5));
  --paper:  oklch(0.985 calc(0.004 * var(--facteur-chroma)) calc(var(--teinte-marque) - 15));
  --ink:    oklch(0.255 calc(0.012 * var(--facteur-chroma)) var(--teinte-marque));
  --slate:  oklch(0.50 calc(0.014 * var(--facteur-chroma)) var(--teinte-marque));
  --faint:  oklch(0.62 calc(0.012 * var(--facteur-chroma)) var(--teinte-marque));
  --line:   oklch(0.915 calc(0.006 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5));
  --lp-card: #ffffff;
  --r-sm: 8px; --r-md: 12px; --r-lg: 18px;
  --shadow-sm: 0 1px 2px oklch(0.3 calc(0.02 * var(--facteur-chroma)) var(--teinte-marque) / 0.06), 0 1px 3px oklch(0.3 calc(0.02 * var(--facteur-chroma)) var(--teinte-marque) / 0.05);
  --shadow-md: 0 4px 12px oklch(0.3 calc(0.02 * var(--facteur-chroma)) var(--teinte-marque) / 0.07), 0 2px 4px oklch(0.3 calc(0.02 * var(--facteur-chroma)) var(--teinte-marque) / 0.05);
  --lp-ring: oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.30);
}
.login-wrap {
  display: grid; grid-template-columns: 1.05fr 1fr;
  grid-template-rows: 100vh; grid-template-rows: 100dvh; overflow: hidden;
}

/* ── Panneau marque (toujours sombre) ── */
/* ══════════════════════════════════════════════════════════════════════
   MOTIF DE FOND — jumeau du thème Keycloak de la GED et de `app/globals.css`.
   ══════════════════════════════════════════════════════════════════════

   Le fichier sert de POCHOIR : c'est son canal alpha qui découpe la couche, la
   couleur venant d'ici — donc du thème. Deux modes de fusion, parce qu'une
   texture ne se pose pas de la même façon sur un panneau sombre et sur une
   page claire : `screen` n'ÉCLAIRCIT que — et le texte blanc ne peut pas
   l'être davantage ; `multiply` n'ASSOMBRIT que — et le texte noir non plus.
   Aucun contraste n'est donc perdu.

   `z-index: -1` glisse la couche entre le fond de son conteneur et son
   contenu ; les conteneurs portent `isolation: isolate`, sans quoi elle
   descendrait derrière eux et deviendrait invisible. */
.motif-fond {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  -webkit-mask-image: url("../img/motif.webp");
  mask-image: url("../img/motif.webp");
  -webkit-mask-size: 460px; mask-size: 460px;
  -webkit-mask-repeat: repeat; mask-repeat: repeat;
}
.motif-fond--sombre {
  background-color: var(--green-500); mix-blend-mode: screen; opacity: 0.09;
}
.motif-fond--page {
  background-color: var(--green-800); mix-blend-mode: multiply; opacity: 0.05;
}

/* Le bouton vert plein — `mask-attachment: fixed` cale la tuile sur la
   FENÊTRE et non sur le bouton : sans cela, un bouton n'afficherait qu'un
   fragment arbitraire de la tuile de 460 px. Calé sur la fenêtre, le dessin le
   traverse en prolongement du fond, comme s'il y était découpé. */
.lp-btn { position: relative; isolation: isolate; overflow: hidden; }
.lp-btn::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  border-radius: inherit;
  background-color: #ffffff; mix-blend-mode: screen; opacity: 0.08;
  -webkit-mask-image: url("../img/motif.webp");
  mask-image: url("../img/motif.webp");
  -webkit-mask-size: 460px; mask-size: 460px;
  -webkit-mask-repeat: repeat; mask-repeat: repeat;
  -webkit-mask-attachment: fixed; mask-attachment: fixed;
}
@media print { .motif-fond, .lp-btn::after { display: none; } }

.brand-panel {
  /* `isolation` : support de la couche de motif (cf. ci-dessus). */
  position: relative; isolation: isolate; overflow: hidden; color: #fff;
  background: radial-gradient(120% 80% at 15% 0%, var(--green-800) 0%, var(--green-950) 55%, oklch(0.16 calc(0.03 * var(--facteur-chroma)) calc(var(--teinte-marque) + 3)) 100%);
  padding: 3.4286rem 4.0rem 2.8571rem; display: grid; grid-template-rows: 1fr auto;
}
/* Contenu du panneau marque : centré verticalement (parité PortalShell). */
.bp-main { grid-row: 1; align-self: center; }
.bp-main, .bp-foot { position: relative; z-index: 1; }
.bp-glow {
  position: absolute; width: 37.1429rem; height: 37.1429rem; right: -11.4286rem; top: 8%;
  background: radial-gradient(circle, var(--green-500) 0%, transparent 68%);
  opacity: 0.28; filter: blur(8px); pointer-events: none;
}
.bp-logo { display: flex; align-items: center; gap: 0.9286rem; margin-bottom: 2.5714rem; }
.bp-logo-mark { width: 2.8571rem; height: 2.8571rem; border-radius: 0.7857rem; flex: none; overflow: hidden; display: grid; place-items: center;
  background: linear-gradient(145deg, var(--green-500), var(--green-700)); box-shadow: 0 4px 12px oklch(0.2 calc(0.05 * var(--facteur-chroma)) var(--teinte-marque) / 0.4); }
.bp-logo-mark img { width: 100%; height: 100%; object-fit: contain; padding: 0.4286rem; }
.bp-name { font-weight: 700; font-size: 1.1429rem; letter-spacing: -0.01em; line-height: 1.1; }
.bp-org { font-size: 0.8929rem; color: var(--green-300); margin-top: 0.0714rem; }
.bp-hero { max-width: 38.5714rem; animation: fadeUp .6s ease; }
.bp-eyebrow {
  display: inline-flex; align-items: center; align-self: flex-start;
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.7857rem; letter-spacing: 0.2em; font-weight: 500;
  color: var(--green-300); margin-bottom: 1.5714rem; padding: 0.4286rem 1.0rem; border-radius: 71.3571rem;
  background: oklch(0.7 calc(0.1 * var(--facteur-chroma)) calc(var(--teinte-marque) - 3) / 0.10); border: 1px solid oklch(0.7 calc(0.12 * var(--facteur-chroma)) calc(var(--teinte-marque) - 3) / 0.22);
}
.bp-h1 { font-size: clamp(2.4286rem, 3.6vw, 3.7143rem); line-height: 1.04; font-weight: 700; letter-spacing: -0.025em; margin: 0; }
.bp-h1 .accent, .bp-h1 span { color: var(--green-300); }
.bp-sub { margin-top: 1.4286rem; font-size: 1.1071rem; line-height: 1.6; color: oklch(0.86 calc(0.02 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5) / 0.8); max-width: 31.4286rem; }

/* Trust items (3 lignes icône + titre + description) — parité PortalShell */
.bp-list { margin-top: 2.8571rem; display: flex; flex-direction: column; gap: 1.5714rem; }
.bp-item { display: flex; gap: 1.0714rem; max-width: 32.8571rem; }
.bp-ico {
  flex: none; width: 2.8571rem; height: 2.8571rem; border-radius: 0.7857rem; display: grid; place-items: center;
  background: oklch(0.7 calc(0.1 * var(--facteur-chroma)) calc(var(--teinte-marque) - 3) / 0.12); border: 1px solid oklch(0.7 calc(0.12 * var(--facteur-chroma)) calc(var(--teinte-marque) - 3) / 0.2); color: var(--green-300);
}
.bp-it-title { font-weight: 600; font-size: 1.0714rem; }
.bp-it-text { font-size: 0.9643rem; line-height: 1.5; color: oklch(0.82 calc(0.015 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5) / 0.66); margin-top: 0.2143rem; }

.bp-foot { grid-row: 2; align-self: end; }
.bp-badge { display: inline-flex; align-items: center; gap: 0.5714rem; font-size: 0.8929rem; color: oklch(0.85 calc(0.02 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5) / 0.7); font-family: var(--font-mono, ui-monospace, monospace); letter-spacing: -0.01em; }
.bp-badge-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--green-500); box-shadow: 0 0 0 4px oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.18); }
@keyframes fadeUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .bp-hero { animation: none !important; }
}

/* ── Panneau formulaire (clair) ── */
.form-side {
  /* `isolation` : même raison que `.brand-panel`. */
  background: var(--paper); position: relative; isolation: isolate; padding: 2.8571rem;
  display: grid; grid-template-rows: 1fr auto; justify-items: center; overflow-y: auto;
}
.form-card { grid-row: 1; align-self: center; width: 100%; max-width: 28.0rem; }
.fc-head { text-align: center; margin-bottom: 2.0rem; }
.fc-head h2 { font-size: 1.8571rem; font-weight: 700; letter-spacing: -0.02em; color: var(--ink); margin: 0; }
.fc-head p { color: var(--slate); font-size: 1.0rem; margin-top: 0.4286rem; margin-bottom: 0; }

/* Badge 2FA (étape OTP) — parité PortalShell/page.tsx .otp-badge */
.otp-badge {
  display: inline-flex; align-items: center; gap: 0.4286rem;
  font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  padding: 0.2857rem 0.7143rem; border-radius: 71.3571rem;
  background: oklch(0.96 0.045 80); color: oklch(0.62 0.13 75);
  border: 1px solid oklch(0.62 0.13 75 / 0.3);
}

/* Note bas de login (« Accès délivré par l'administration… ») — parité .fc-note */
.fc-note { margin-top: 1.8571rem; padding-top: 1.5714rem; border-top: 0.0714rem solid var(--line); font-size: 0.8929rem; line-height: 1.6; color: var(--faint); text-align: center; display: flex; flex-direction: column; align-items: center; gap: 0.5714rem; }
.fc-note .fc-note-ico { color: var(--green-600); display: inline-flex; }
.fc-note a, .fc-note button { color: var(--green-700); font-weight: 600; text-decoration: none; background: none; border: none; cursor: pointer; padding: 0; font: inherit; }
.fc-note a:hover, .fc-note button:hover { text-decoration: underline; }
.lp-field-label { display: block; font-size: 0.9286rem; font-weight: 600; color: var(--ink); margin-bottom: 0.5rem; }
.lp-field-row { display: flex; align-items: baseline; justify-content: space-between; gap: 0.8571rem; }
.lp-link-sm { font-size: 0.8929rem; color: var(--green-700); font-weight: 600; text-decoration: none; cursor: pointer; background: none; border: none; padding: 0; }
.lp-link-sm:hover { text-decoration: underline; }
.lp-field {
  display: flex; align-items: center; gap: 0.7143rem; height: 3.4286rem; padding: 0 1.0rem;
  background: var(--lp-card); border: 1px solid var(--line); border-radius: var(--r-md);
  transition: all .15s ease; box-shadow: var(--shadow-sm);
}
.lp-field:focus-within { border-color: var(--green-500); box-shadow: var(--shadow-sm), 0 0 0 2px oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.08); }
.lp-field-ico { color: var(--faint); display: grid; place-items: center; flex: none; }
.lp-field:focus-within .lp-field-ico { color: var(--green-600); }
.lp-field input { flex: 1; border: none; outline: none !important; box-shadow: none !important; font-size: 1.0357rem; color: var(--ink); background: none; width: 100%; color-scheme: light; }
.lp-field input:focus, .lp-field input:focus-visible { outline: none !important; box-shadow: none !important; }
.lp-field input::placeholder { color: var(--faint); }
.lp-field input:-webkit-autofill,
.lp-field input:-webkit-autofill:hover,
.lp-field input:-webkit-autofill:focus,
.lp-field input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--ink) !important;
  -webkit-box-shadow: 0 0 0 1000px var(--lp-card) inset !important;
  box-shadow: 0 0 0 1000px var(--lp-card) inset !important;
  caret-color: var(--ink);
  transition: background-color 100000s ease-in-out 0s;
}
.lp-field-eye { color: var(--faint); display: grid; place-items: center; background: none; border: none; cursor: pointer; flex: none; }
.lp-field-eye:hover { color: var(--green-600); }
.lp-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5714rem;
  font-weight: 600; font-size: 1.0714rem; border-radius: var(--r-md); width: 100%; height: 3.5714rem;
  transition: all .16s ease; border: none; cursor: pointer;
  background: var(--green-600); color: #fff;
  box-shadow: 0 1px 2px oklch(0.3 calc(0.05 * var(--facteur-chroma)) var(--teinte-marque) / .3), inset 0 1px 0 oklch(0.75 calc(0.12 * var(--facteur-chroma)) calc(var(--teinte-marque) - 3) / .35);
}
.lp-btn:hover:not(:disabled) { background: var(--green-700); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.lp-btn:active:not(:disabled) { transform: translateY(0); }
.lp-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.lp-spin { width: 1.2857rem; height: 1.2857rem; border: 2.2px solid oklch(1 0 0 / 0.4); border-top-color: #fff; border-radius: 50%; animation: spin 0.7s linear infinite; }
.lp-bio-sep { display: flex; align-items: center; gap: 0.8571rem; margin: 1.2857rem 0 1.0rem; color: var(--faint); font-size: 0.8571rem; font-weight: 600; }
.lp-bio-sep::before, .lp-bio-sep::after { content: ""; flex: 1; height: 0.0714rem; background: var(--line); }
.lp-btn-bio {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6429rem;
  width: 100%; height: 3.4286rem; border-radius: var(--r-md); cursor: pointer;
  font-weight: 600; font-size: 1.0357rem; transition: all .16s ease;
  background: var(--lp-card); color: var(--green-700);
  border: 1.5px solid var(--green-600);
}
.lp-btn-bio:hover:not(:disabled) { background: oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.10); color: var(--green-700); transform: translateY(-1px); box-shadow: 0 4px 14px -4px oklch(0.53 calc(0.115 * var(--facteur-chroma)) var(--teinte-marque) / 0.45); }
.lp-btn-bio:active:not(:disabled) { transform: translateY(0); }
.lp-btn-bio:disabled { opacity: 0.55; cursor: not-allowed; }
.lp-err { color: #d4183d; font-size: 0.8571rem; margin-top: 0.4286rem; }
.form-foot { grid-row: 2; align-self: end; display: flex; gap: 0.7143rem; align-items: center; font-size: 0.8929rem; color: var(--faint); flex-wrap: wrap; justify-content: center; padding-top: 1.4286rem; }
.dotsep { opacity: 0.5; }
.foot-secure { display: inline-flex; align-items: center; gap: 0.5rem; }
.foot-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2)); box-shadow: 0 0 0 3px oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.18); }
.lp-vendor {
  position: absolute; right: 1.8571rem; bottom: 1.2857rem; z-index: 2;
  display: inline-flex; align-items: center; gap: 0.6429rem; transition: transform .28s ease; user-select: none;
}
.lp-vendor:hover { transform: translateY(-1px); }
.lp-vendor-label { font-size: 0.7143rem; line-height: 1; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600; color: var(--slate); white-space: nowrap; }
.lp-vendor-logo { height: 2.1429rem; width: auto; display: block; }

/* Logo compact mobile (panneau marque masqué < 940px). */
.mobile-logo { display: none; align-items: center; justify-content: center; gap: 0.7143rem; position: absolute; top: 2.0rem; left: 0; right: 0; }
.mobile-logo .bp-logo-mark { width: 2.5714rem; height: 2.5714rem; }
.mobile-logo .ml-name { font-size: 1.0714rem; font-weight: 700; letter-spacing: -0.01em; color: var(--ink); line-height: 1.1; }
.mobile-logo .ml-org { font-size: 0.8571rem; color: var(--slate); }

/* ── LA SÉPARATION EN VAGUE ────────────────────────────────────────────────
 *
 *  Jumeau de la section homonyme de la GED : les deux écrans de connexion
 *  doivent porter le MÊME arc. Un portail qui s'ouvre sur une autre courbe se
 *  lit comme un autre produit.
 *
 *  Le panneau sombre est ÉLARGI de `--vague-amp`, puis découpé par le
 *  `clipPath` `#vague-login` — un tracé en unités `objectBoundingBox` (0 → 1),
 *  qui s'étire donc à toute taille d'écran sans le moindre recalcul.
 *
 *  L'élargissement est rendu à l'identique en `padding-right` : le contenu du
 *  panneau ne bouge pas d'un pixel, et l'axe neutre de l'arc retombe
 *  exactement sur l'ancienne frontière.
 *
 *  Le panneau formulaire devient TRANSPARENT : il vient après dans le DOM et,
 *  opaque, il recouvrirait le renflement du panneau sombre qui déborde sous
 *  lui. Le fond clair et son motif remontent donc sur `.login-wrap`.
 *
 *  Le placement des trois calques est EXPLICITE : sans cela le liseré
 *  prendrait la première cellule et décalerait les deux panneaux d'un cran.
 */
.login-wrap {
  --vague-amp: 6.5%;
  position: relative; isolation: isolate; background: var(--paper);
}
.login-wrap > .brand-panel  { grid-area: 1 / 1; justify-self: start; }
.login-wrap > .form-side    { grid-area: 1 / 2; }
.login-wrap > .vague-lisere { grid-area: 1 / 1; justify-self: start; }

.brand-panel {
  width: calc(100% + var(--vague-amp));
  padding-right: calc(4.0rem + var(--vague-amp));
  clip-path: url(#vague-login);
}
.form-side {
  background: transparent;
  padding-left: calc(2.8571rem + var(--vague-amp));
  z-index: 1;
}

/* Le liseré souligne l'arête. Il double le panneau à l'identique — même
   cellule, même largeur — mais SANS découpe : le halo peut donc déborder sur
   le panneau clair, ce qui donne la profondeur. */
.vague-lisere { width: calc(100% + var(--vague-amp)); height: 100%; z-index: 2; pointer-events: none; }
.vague-lisere svg { width: 100%; height: 100%; display: block; overflow: visible; }
/* `non-scaling-stroke` : le viewBox 0 → 1 est étiré sans conserver le rapport,
   une épaisseur exprimée en unités de tracé deviendrait donc illisible. */
.vague-lisere .vl-trait { fill: none; stroke: oklch(0.9 calc(0.11 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5) / 0.8); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.vague-lisere .vl-halo  { fill: none; stroke: oklch(0.68 calc(0.14 * var(--facteur-chroma)) calc(var(--teinte-marque) - 3) / 0.55); stroke-width: 16; vector-effect: non-scaling-stroke; filter: blur(11px); }

@media (max-width: 940px) {
  .login-wrap { grid-template-columns: 1fr; }
  .brand-panel { display: none; }
  /* Le panneau de marque disparu, la vague n'a plus d'objet : le formulaire
     reprend la colonne unique, sa marge d'origine, et le liseré s'efface. */
  .login-wrap > .form-side { grid-area: auto; padding-left: 2.8571rem; }
  .vague-lisere { display: none; }
  .mobile-logo { display: flex; }
  .lp-vendor { position: static; margin: 1.0rem auto 0; justify-content: center; }
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Toast vanilla (l'écran KC n'est pas React) — réplique le toast de l'app ── */
/* Toasts « galet » bottom-right — parité components/ToasterProvider.tsx
   (fixed bottom-4 right-4, items-end, gap-2.5, rounded-[18px], py-2 pl-3 pr-2,
   ombre 0 14px 34px -14px, entrée pillIn translateY↑ / sortie pillOut). */
.toasts { position: fixed; bottom: 1.1429rem; right: 1.1429rem; z-index: 9999; display: flex; flex-direction: column; align-items: flex-end; gap: 0.7143rem; }
.toast {
  display: flex; align-items: center; gap: 0.7143rem; max-width: min(31.4286rem, calc(100vw - 2.2857rem));
  padding: 0.5714rem 0.5714rem 0.5714rem 0.8571rem; border-radius: 1.2857rem; background: #fff; color: var(--ink);
  box-shadow: 0 14px 34px -14px rgba(0,0,0,.55);
  border: 1px solid var(--line); opacity: 0; transform: translateY(10px) scale(0.96); transition: opacity .3s ease, transform .3s ease;
}
.toast.in { opacity: 1; transform: none; }
.toast.out { opacity: 0; transform: translateY(6px) scale(0.97); }
.toast .tile { width: 2.4286rem; height: 2.4286rem; border-radius: 0.7143rem; display: grid; place-items: center; flex: none; }
/* Couleurs LITTÉRALES (pas de var) : le conteneur .toasts est rendu hors du
   scope où --green-* sont définis → var() y serait invalide (fond transparent,
   icône invisible). */
.toast.error .tile { background: linear-gradient(135deg, #ef4444, #b91c1c); }
.toast.success .tile { background: linear-gradient(135deg, oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2)), oklch(0.44 calc(0.095 * var(--facteur-chroma)) calc(var(--teinte-marque) + 1))); }
.toast.info .tile { background: linear-gradient(135deg, oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2)), oklch(0.44 calc(0.095 * var(--facteur-chroma)) calc(var(--teinte-marque) + 1))); }
.toast.warning .tile { background: linear-gradient(135deg, oklch(0.75 0.15 70), oklch(0.62 0.15 55)); }
.toast .body { flex: 1; min-width: 0; }
.toast .ttl { font-size: 0.9643rem; font-weight: 700; }
.toast .dsc { font-size: 0.8929rem; color: var(--slate); margin-top: 0.1429rem; line-height: 1.4; }
.toast .toast-x { background: none; border: none; color: var(--faint); cursor: pointer; padding: 0.1429rem; flex: none; }
.toast .toast-x:hover { color: var(--ink); }

/* Alerte inline (pages stock KC via registrationLayout). */
.alert { display: flex; align-items: center; gap: 0.6429rem; padding: 0.8571rem 1.0rem; border-radius: var(--r-md); background: oklch(0.97 0.02 25); border: 1px solid oklch(0.85 0.09 25); color: #b91c1c; font-size: 0.9286rem; line-height: 1.45; }
.alert .icon { flex: none; }
.alert.alert-success { background: var(--green-50); border-color: oklch(0.80 calc(0.10 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5)); color: var(--green-700); }

/* FlipWords (accent animé du titre) — remplace le composant React. */
.flip-words { display: inline-block; position: relative; }
.flip-words .fw { display: inline-block; opacity: 0; transform: translateY(10px); transition: opacity .4s ease, transform .4s ease; position: absolute; left: 0; white-space: nowrap; }
.flip-words .fw.on { opacity: 1; transform: translateY(0); position: relative; }

/* ── Écrans auth additionnels (reset, OTP/2FA, TOTP-QR, update-password) ── */
/* Onglets Email / Pseudonyme (reset) */
.lp-tabs { display: flex; gap: 0.2857rem; padding: 0.2857rem; border-radius: 0.8571rem; margin-bottom: 1.1429rem; background: var(--green-50); border: 1px solid var(--line); }
.lp-tab { flex: 1; padding: 0.5714rem; font-size: 0.8571rem; font-weight: 600; border-radius: 0.5714rem; border: none; background: none; color: var(--slate); cursor: pointer; transition: all .15s ease; }
.lp-tab.active { background: var(--lp-card); color: var(--green-700); box-shadow: var(--shadow-sm); }
/* Champ OTP à 6 cases (réplique shadcn InputOTP) */
.lp-otp { display: flex; gap: 0.5714rem; justify-content: center; margin: 1.4286rem 0; }
.lp-otp input {
  width: 3.2857rem; height: 3.8571rem; text-align: center; font-size: 1.4286rem; font-weight: 600; color: var(--ink);
  background: var(--lp-card); border: 1px solid var(--line); border-radius: var(--r-md); outline: none;
  box-shadow: var(--shadow-sm); transition: all .15s ease; font-family: inherit; color-scheme: light;
}
.lp-otp input:focus { border-color: var(--green-500); box-shadow: var(--shadow-sm), 0 0 0 2px oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.08); }
/* Pas-à-pas (étapes) */
.lp-steps { display: flex; align-items: center; justify-content: center; gap: 0.5714rem; margin: 0.2857rem 0 0.5714rem; }
.lp-step-dot { width: 1.8571rem; height: 1.8571rem; border-radius: 50%; display: grid; place-items: center; font-size: 0.8571rem; font-weight: 700; background: var(--green-50); color: var(--slate); border: 1px solid var(--line); }
.lp-step-dot.active { background: var(--green-600); color: #fff; border-color: transparent; }
.lp-step-dot.done { background: var(--green-100); color: var(--green-700); border-color: transparent; }
.lp-step-bar { width: 2.4286rem; height: 0.1429rem; border-radius: 0.1429rem; background: var(--line); }
/* TOTP : QR + clé secrète */
.lp-qr { display: flex; justify-content: center; }
.lp-qr-box { border-radius: var(--r-md); background: #fff; padding: 0.8571rem; box-shadow: var(--shadow-md); }
.lp-qr-box img { width: 12.0rem; height: 12.0rem; display: block; image-rendering: pixelated; }
.lp-secret { border-radius: var(--r-md); background: oklch(0 0 0 / 0.03); border: 1px solid var(--line); padding: 0.7143rem 0.8571rem; margin-top: 0.8571rem; }
.lp-secret-lbl { font-size: 0.7143rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--slate); margin-bottom: 0.1429rem; }
.lp-secret-code { font-family: var(--font-mono, monospace); font-size: 0.8571rem; color: var(--ink); word-break: break-all; }
/* Logo lockup carré (écrans 2FA/reset app) */
.lp-lockup { display: flex; justify-content: center; margin-bottom: 1.0rem; }
.lp-lockup-mark { width: 3.7143rem; height: 3.7143rem; border-radius: 1.0714rem; display: grid; place-items: center; color: #fff; background: linear-gradient(145deg, var(--green-500), var(--green-700)); box-shadow: 0 8px 20px -6px oklch(0.53 calc(0.115 * var(--facteur-chroma)) var(--teinte-marque) / 0.45); }
.lp-lockup-mark.err { background: linear-gradient(145deg, oklch(0.62 0.20 25), oklch(0.50 0.19 25)); box-shadow: 0 8px 20px -6px oklch(0.55 0.20 25 / 0.45); }
.lp-lockup-mark.warn { background: linear-gradient(145deg, oklch(0.75 0.15 70), oklch(0.62 0.15 55)); box-shadow: 0 8px 20px -6px oklch(0.65 0.15 60 / 0.45); }
/* Lien retour bas de formulaire */
.lp-back { width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 0.4286rem; padding: 0.5714rem; margin-top: 0.7143rem; font-size: 1.0rem; color: var(--slate); background: none; border: none; cursor: pointer; text-decoration: none; }
.lp-back:hover { color: var(--ink); }
/* Hint / encart d'information */
.lp-hint { border-radius: var(--r-md); background: var(--green-50); border: 1px solid oklch(0.80 calc(0.10 * var(--facteur-chroma)) calc(var(--teinte-marque) - 5) / 0.5); padding: 0.7143rem 0.8571rem; margin-top: 0.8571rem; font-size: 0.7857rem; line-height: 1.5; color: var(--green-700); }

/* ── Codes de récupération (backup 2FA) ── */
.lp-codes-box { border-radius: var(--r-md); border: 2px dashed oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.5); background: oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.10); padding: 1.0rem; }
.lp-codes-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4286rem 1.0rem; font-family: var(--font-mono, monospace); font-size: 1.0rem; color: var(--ink); }
.lp-code { display: flex; align-items: center; gap: 0.5714rem; }
.lp-code .n { font-size: 0.7143rem; color: var(--slate); width: 1.1429rem; text-align: right; }
.lp-code .v { font-weight: 700; letter-spacing: 0.06em; }
.lp-warn { border-radius: var(--r-sm); border: 1px solid oklch(0.85 0.09 70); background: oklch(0.97 0.03 80); padding: 0.7143rem 0.8571rem; margin-top: 0.8571rem; font-size: 0.7857rem; line-height: 1.5; color: oklch(0.45 0.10 60); }
/* Avis de verrouillage (login.ftl) — ambre sémantique de .lp-warn : un
   avertissement, pas la marque ; il ne suit donc pas --teinte-marque. */
.lp-verrou { display: flex; align-items: flex-start; gap: 0.6429rem; margin: -0.8571rem 0 1.1429rem; padding: 0.7857rem 0.9286rem; border-radius: var(--r-md); border: 1px solid oklch(0.85 0.09 70); background: oklch(0.97 0.03 80); color: oklch(0.45 0.10 60); line-height: 1.45; }
.lp-verrou-ico { flex: none; display: inline-flex; margin-top: 0.0714rem; color: oklch(0.62 0.15 55); }
.lp-verrou-titre { font-size: 0.9286rem; font-weight: 600; color: oklch(0.40 0.10 55); }
.lp-verrou-texte { font-size: 0.8214rem; margin-top: 0.2143rem; }
.lp-btn-row { display: flex; gap: 0.5714rem; margin-top: 0.8571rem; }
.lp-btn-2 { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 0.4286rem; padding: 0.6429rem; border-radius: var(--r-md); font-size: 0.8929rem; font-weight: 600; color: var(--ink); background: var(--lp-card); border: 1px solid var(--line); cursor: pointer; transition: background .15s ease; }
.lp-btn-2:hover { background: oklch(0 0 0 / 0.04); }
.lp-check { display: flex; align-items: center; gap: 0.6429rem; margin-top: 1.0rem; font-size: 0.8929rem; color: var(--slate); cursor: pointer; user-select: none; }
.lp-check input { width: 1.1429rem; height: 1.1429rem; accent-color: var(--green-700); flex: none; }

/* ── Sélection de méthode 2FA (select-authenticator) ── */
.lp-authn-list { display: flex; flex-direction: column; gap: 0.7143rem; }
.lp-authn-opt { display: flex; align-items: center; gap: 0.8571rem; width: 100%; text-align: left; padding: 1.0rem 1.1429rem; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--lp-card); color: var(--ink); cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease, background .15s ease; }
.lp-authn-opt:hover { border-color: var(--green-500); box-shadow: 0 0 14px -4px oklch(0.63 calc(0.135 * var(--facteur-chroma)) calc(var(--teinte-marque) - 2) / 0.38); }
.lp-authn-ic { display: grid; place-items: center; width: 2.7143rem; height: 2.7143rem; flex: none; border-radius: 0.7857rem; color: var(--green-600); background: var(--green-50); }
.lp-authn-txt { display: flex; flex-direction: column; gap: 0.1429rem; flex: 1; min-width: 0; }
.lp-authn-name { font-size: 1.0rem; font-weight: 600; color: var(--ink); }
.lp-authn-help { font-size: 0.8571rem; color: var(--slate); }
.lp-authn-arr { color: var(--faint); flex: none; }
.lp-authn-opt:hover .lp-authn-arr { color: var(--green-600); }

/* ── Lien « essayer une autre méthode » (fallback 2FA) ── */
.lp-try-another { margin-top: 1.0rem; text-align: center; }
.lp-try-another button { background: none; border: none; padding: 0.2857rem; font-size: 0.9286rem; font-weight: 600; color: var(--green-600); cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.lp-try-another button:hover { color: var(--green-700); }

/* ══════════════════════════════════════════════════════════════════════
   BASCULE DE LANGUE — jumelle de celle du thème GED
   ══════════════════════════════════════════════════════════════════════ */
.ged-lang {
  position: absolute; top: 1.25rem; right: 1.25rem; z-index: 30;
  box-sizing: border-box;
  display: inline-flex; align-items: center;
  width: 5rem; height: 2.25rem; padding: 0 0.25rem;
  border-radius: 71.3571rem;
  border: 1px solid var(--line, #e5e7eb); background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(6px);
  text-decoration: none;
  transition: background-color .25s ease;
}
.ged-lang:hover { background: #fff; }
.ged-lang:focus-visible { outline: 2px solid var(--green-700, oklch(0.441 calc(0.063 * var(--facteur-chroma)) calc(var(--teinte-marque) + 14))); outline-offset: 2px; }
/* Piste gravée : les DEUX codes restent écrits. Sans cela l'interrupteur se
   lirait comme un réglage éteint, or aucune des deux langues n'est un défaut
   désactivé. Celui que le curseur recouvre s'efface. */
.ged-lang-track {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 0.6875rem;
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.01em;
  color: var(--slate, #6b7280);
  pointer-events: none;
}
.ged-lang-code { transition: opacity .3s ease; }
.ged-lang-code--fr { opacity: 0; }
.ged-lang-code--en { opacity: 1; }
.ged-lang.is-en .ged-lang-code--fr { opacity: 1; }
.ged-lang.is-en .ged-lang-code--en { opacity: 0; }
/* Le curseur porte le drapeau, donc il porte l'information. La course vaut la
   largeur intérieure moins le curseur ; les deux filets d'un pixel ne portent
   pas de dimension et n'ont donc pas à s'échelonner, d'où le `calc`. */
.ged-lang-knob {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem;
  border-radius: 71.3571rem;
  background: #fff;
  /* L'anneau est VERT : le curseur ne se contente pas d'occuper une position,
     il dit « c'est votre langue ». Un anneau gris se lisait comme un simple
     relief. Le halo qui l'accompagne doit se SENTIR, pas se voir — d'où des
     opacités basses. La teinte vient du jeton, jamais d'une valeur écrite
     ici : `color-mix` garde une source unique quand la charte change. */
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.08),
    0 0 0 1px color-mix(in oklch, var(--green-600) 48%, transparent),
    0 0 0.75rem color-mix(in oklch, var(--green-600) 20%, transparent);
  transform: translateX(0);
  /* Dépassement léger à l'arrivée : la sensation d'un objet lancé, pas d'une
     image remplacée. */
  transition: transform .42s cubic-bezier(.34, 1.42, .64, 1);
}
.ged-lang.is-en .ged-lang-knob { transform: translateX(calc(2.75rem - 2px)); }
@media (prefers-reduced-motion: reduce) {
  .ged-lang-knob, .ged-lang-code, .ged-lang { transition: none; }
}
.ged-flag {
  width: 1rem; height: 0.6875rem; flex: none; border-radius: 0.125rem;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
}
