/* =============================================================================================
   Vision UI — FEUILLE DE TOKENS · périmètre ADMINISTRATION SaaS (base maître)
   Jumeau #203 de app-locataire.css : feuilles DISTINCTES et DUPLIQUÉES (aucun CSS partagé entre
   les deux mondes). Seuls les BINAIRES de police (/fonts, assets inertes) sont mutualisés.

   Les tokens sont posés sur la RACINE <html> quand le monde SaaS est actif (classe .ideale-monde-saas,
   posée par idealeTheme.applyMonde) → ils cascadent PARTOUT, y compris les portails MudDialog/MudPopover
   rendus sous <body>. Les deux feuilles peuvent donc coexister sans collision (chacune scopée à sa classe
   de monde).

   IMPORTANT — NOMMAGE PRÉFIXÉ « --ds-* » : tous les tokens du design system sont préfixés pour ne JAMAIS
   entrer en collision avec les variables globales d'app.css (ex. --s-2, --r-sm, --r-lg y sont des valeurs
   DIFFÉRENTES), qui servent encore les layouts hérités.

   CES TOKENS SONT INCONDITIONNELS : ils ne dépendent PAS du thème d'interface. Ce fichier a longtemps affirmé
   l'inverse (« le thème Classique n'utilise PAS ces tokens → zéro régression ») — vrai au Lot 1, FAUX depuis
   le re-style 5A, où les écrans se sont mis à consommer le kit. Classique rendait donc un hybride (MudBlazor
   bleu + kit sarcelle) que ce commentaire a masqué. Le thème « Classique » est retiré (PAL1, #300) : il n'y a
   plus qu'un thème, et ces tokens SONT sa palette.

   PARITÉ OBLIGATOIRE : les valeurs de couleur ci-dessous sont dupliquées côté C# (IdealeThemesSaaS) — MudBlazor
   fige ses variables dérivées à l'émission, un pont CSS est donc impossible. Toute modification ici doit être
   répercutée là-bas ; le test ParitePaletteTokensTests le verrouille.
   ============================================================================================= */

/* ---- Polices self-hostées (AUCUN fetch Google au runtime ; binaires sous /fonts) ---------------- */
@font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/hanken-grotesk-400.woff2') format('woff2'); }
@font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/hanken-grotesk-500.woff2') format('woff2'); }
@font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 600; font-display: swap; src: url('../fonts/hanken-grotesk-600.woff2') format('woff2'); }
@font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 700; font-display: swap; src: url('../fonts/hanken-grotesk-700.woff2') format('woff2'); }
@font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 800; font-display: swap; src: url('../fonts/hanken-grotesk-800.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/jetbrains-mono-400.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/jetbrains-mono-500.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 600; font-display: swap; src: url('../fonts/jetbrains-mono-600.woff2') format('woff2'); }
/* Police d'icônes du design system (variable) — servie localement, chargée en font-display:block. */
@font-face { font-family: 'Material Symbols Rounded'; font-style: normal; font-weight: 100 700; font-display: block; src: url('../fonts/material-symbols-rounded.woff2') format('woff2'); }

/* ---- Tokens du design system (CLAIR) — actifs quand le monde SaaS est en mode clair ------------- */
html.ideale-monde-saas {
    /* Typographies */
    --ds-font-ui: 'Hanken Grotesk', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --ds-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    /* Rayons & espacements (échelle du design system) */
    --ds-r-xs: 6px; --ds-r-sm: 8px; --ds-r-md: 10px; --ds-r-lg: 14px; --ds-r-xl: 20px; --ds-r-2xl: 28px; --ds-r-pill: 999px;
    /* Rayon des avatars & pastilles d'identité (DOCTRINE du rond, cf. bloc « le rond n'appartient qu'à IDeal »
       plus bas). Exprimé en POURCENTAGE, jamais en px : invariant d'échelle → ~7 px sur une boîte de 30
       (7/30 ≈ 0,23) et la MÊME proportion sur un avatar de 24, 40 ou 64. */
    --ds-rayon-avatar: 23%;
    /* Fond NEUTRE de l'avatar d'initiales sans photo (valeurs arrêtées sur la maquette de connexion : carré 30 /
       rayon 7 / fond #2B303C). Défini pour être CONSOMMÉ par ③ (la page de connexion) ; AUCUN avatar n'est
       recoloré dans ce lot, dont la doctrine est la FORME. Fond neutre constant clair/sombre. */
    --ds-avatar-fond: #2B303C;
    --ds-s-1: 4px; --ds-s-2: 8px; --ds-s-3: 12px; --ds-s-4: 16px; --ds-s-5: 20px; --ds-s-6: 24px; --ds-s-8: 32px; --ds-s-10: 40px; --ds-s-12: 48px; --ds-s-16: 64px;
    /* Surfaces & fonds */
    --ds-bg-body: #FFFFFF; --ds-bg-canvas: #F5F7F8; --ds-bg-surface: #FFFFFF; --ds-bg-surface-2: #F7F9FA; --ds-bg-surface-3: #EFF3F3; --ds-bg-inset: #E8EDED;
    --ds-bg-hover: #F0F3F3; --ds-bg-active: #E4EFEF; --ds-bg-sidebar: #FFFFFF;
    /* Bordures */
    --ds-border: #E0E6E7; --ds-border-strong: #79898C; --ds-border-subtle: #EBEFEF;
    /* Texte */
    --ds-text-strong: #0E1517; --ds-text: #2C3739; --ds-text-muted: #5B686C; --ds-text-subtle: #8A979B; --ds-text-on-brand: #FFFFFF;
    /* Accent de marque (défaut sarcelle — surchargeable par [data-accent]) */
    --ds-brand: #15565F; --ds-brand-hover: #114851; --ds-brand-active: #0E3A42; --ds-brand-subtle: #E4EFEF; --ds-brand-subtle-2: #CFE4E4; --ds-brand-border: #B4D2D3; --ds-brand-text: #124E57;
    /* Sémantiques */
    --ds-success: #1B8A5A; --ds-success-subtle: #E4F4EC; --ds-success-text: #0E6B43; --ds-success-border: #B6E0CA;
    --ds-warning: #B06A00; --ds-warning-subtle: #FAEFD8; --ds-warning-text: #875200; --ds-warning-border: #EACF9A;
    --ds-danger: #C93A2E; --ds-danger-subtle: #FBE7E4; --ds-danger-text: #A62A20; --ds-danger-border: #F1C1BA;
    --ds-info: #2563C9; --ds-info-subtle: #E6EDFB; --ds-info-text: #1E52A8; --ds-info-border: #BFD1F1;
    /* Séries de graphes — DISTINCTES des sémantiques : une série de données ne « veut rien dire ». Détourner
       --ds-success pour colorer une série (= « série 2 ») est une erreur de catégorie : le vert devrait dire
       « succès », pas « résolus ». Ces tokens donnent aux graphes leur propre vocabulaire.
       NB : ils fixent une PALETTE, ils ne choisissent aucune bibliothèque de graphes (décision DS9 ouverte). */
    --ds-chart-1: #15565F; --ds-chart-2: #3E888F; --ds-chart-3: #7CB8BD; --ds-chart-4: #2563C9; --ds-chart-5: #B06A00;
    --ds-chart-grid: #E5EAEA; --ds-chart-track: #EDF1F1;
    /* Focus & ombres & voile */
    --ds-focus-ring: 0 0 0 3px rgba(21, 86, 95, .26);
    --ds-shadow-xs: 0 1px 2px rgba(14, 30, 34, .06);
    --ds-shadow-sm: 0 1px 3px rgba(14, 30, 34, .09), 0 1px 2px rgba(14, 30, 34, .05);
    --ds-shadow-md: 0 6px 18px -4px rgba(14, 30, 34, .12), 0 2px 6px -2px rgba(14, 30, 34, .07);
    --ds-shadow-lg: 0 18px 40px -8px rgba(14, 30, 34, .20), 0 6px 14px -6px rgba(14, 30, 34, .10);
    --ds-overlay: rgba(12, 22, 24, .42);
}

/* ---- Tokens du design system (SOMBRE) ---------------------------------------------------------- */
html.ideale-monde-saas[data-theme="dark"] {
    --ds-bg-body: #080B0C; --ds-bg-canvas: #0B0F10; --ds-bg-surface: #13181A; --ds-bg-surface-2: #1A2124; --ds-bg-surface-3: #232B2E; --ds-bg-inset: #0E1314;
    --ds-bg-hover: rgba(255, 255, 255, .055); --ds-bg-active: #0F3138; --ds-bg-sidebar: #0E1314;
    --ds-border: #252D30; --ds-border-strong: #5F7175; --ds-border-subtle: #1B2225;
    /* --ds-text-on-brand : le texte posé SUR la marque. Assombri #052422 -> #010D0C (WCAG AA, PAL1) : sur le
       sarcelle sombre #2E8C95, l'ancienne paire tombait à 4,14:1, sous le seuil AA de 4,5 exigé pour un
       libellé de bouton (14 px/600 = texte normal). On corrige par le levier FONCTIONNEL (le texte) et non
       par la marque, qui est IDENTITAIRE : 4,98:1, marque intacte, reflet sarcelle du texte conservé. */
    --ds-text-strong: #F2F6F6; --ds-text: #CFD7D9; --ds-text-muted: #93A0A3; --ds-text-subtle: #697579; --ds-text-on-brand: #010D0C;
    --ds-brand: #2E8C95; --ds-brand-hover: #379AA3; --ds-brand-active: #45AAB2; --ds-brand-subtle: #0F3138; --ds-brand-subtle-2: #123C43; --ds-brand-border: #1C4C53; --ds-brand-text: #67BEC6;
    --ds-success: #33B37B; --ds-success-subtle: #0F2C21; --ds-success-text: #57C892; --ds-success-border: #1E4B39;
    --ds-warning: #DFA23C; --ds-warning-subtle: #2C2410; --ds-warning-text: #E8B65E; --ds-warning-border: #4A3C1A;
    --ds-danger: #E56A5D; --ds-danger-subtle: #2E1512; --ds-danger-text: #F08579; --ds-danger-border: #552420;
    --ds-info: #5B9BF0; --ds-info-subtle: #122139; --ds-info-text: #82B2F3; --ds-info-border: #26375A;
    --ds-chart-1: #3FA3AC; --ds-chart-2: #6FC0C8; --ds-chart-3: #2E8C95; --ds-chart-4: #5B9BF0; --ds-chart-5: #E0A23C;
    --ds-chart-grid: #1F2729; --ds-chart-track: #1A2124;
    --ds-focus-ring: 0 0 0 3px rgba(103, 190, 198, .32);
    --ds-shadow-xs: 0 1px 2px rgba(0, 0, 0, .4);
    --ds-shadow-sm: 0 1px 3px rgba(0, 0, 0, .5), 0 1px 2px rgba(0, 0, 0, .4);
    --ds-shadow-md: 0 8px 22px -6px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);
    --ds-shadow-lg: 0 22px 48px -10px rgba(0, 0, 0, .7), 0 8px 16px -8px rgba(0, 0, 0, .55);
    --ds-overlay: rgba(0, 0, 0, .62);
}

/* ---- Axe d'accent (thème « Nouveau ») — surcharge des tokens --ds-brand* ------------------------ */
/* Sarcelle = défaut (déjà posé ci-dessus) ; déclaration explicite pour la lisibilité de l'axe. */
html.ideale-monde-saas[data-accent="sarcelle"] {
    --ds-brand: #15565F; --ds-brand-hover: #114851; --ds-brand-active: #0E3A42; --ds-brand-subtle: #E4EFEF; --ds-brand-subtle-2: #CFE4E4; --ds-brand-border: #B4D2D3; --ds-brand-text: #124E57;
}
html.ideale-monde-saas[data-accent="sarcelle"][data-theme="dark"] {
    --ds-brand: #2E8C95; --ds-brand-hover: #379AA3; --ds-brand-active: #45AAB2; --ds-brand-subtle: #0F3138; --ds-brand-subtle-2: #123C43; --ds-brand-border: #1C4C53; --ds-brand-text: #67BEC6;
}
/* Crème — CÂBLÉ mais NON EXPOSÉ dans l'UI (prêt à activer, cf. handoff). */
html.ideale-monde-saas[data-accent="creme"] {
    --ds-brand: #1E6B62; --ds-brand-hover: #185A52; --ds-brand-active: #124942; --ds-brand-subtle: #E3F0EE; --ds-brand-subtle-2: #C9E3DE; --ds-brand-border: #B4D8D2; --ds-brand-text: #1A5F57;
}
html.ideale-monde-saas[data-accent="creme"][data-theme="dark"] {
    --ds-brand: #3E9A8E; --ds-brand-hover: #49A99C; --ds-brand-active: #55B7A9; --ds-brand-subtle: #0E302C; --ds-brand-subtle-2: #123B36; --ds-brand-border: #1C4C46; --ds-brand-text: #6FC3B8;
}
/* Azur — CÂBLÉ mais NON EXPOSÉ dans l'UI (prêt à activer, cf. handoff). */
html.ideale-monde-saas[data-accent="azur"] {
    --ds-brand: #1863C7; --ds-brand-hover: #1556AE; --ds-brand-active: #124995; --ds-brand-subtle: #E6EEFB; --ds-brand-subtle-2: #CFDEF6; --ds-brand-border: #BBD0F0; --ds-brand-text: #1A5AB4;
}
html.ideale-monde-saas[data-accent="azur"][data-theme="dark"] {
    --ds-brand: #4C93F0; --ds-brand-hover: #5E9FF2; --ds-brand-active: #72ADF4; --ds-brand-subtle: #10233E; --ds-brand-subtle-2: #163050; --ds-brand-border: #244069; --ds-brand-text: #86B6F5;
}

/* ---- Réglages PROPRES au thème « Nouveau » (jamais appliqués au thème « Classique ») ------------ */
/* Boutons en pilule (design system) — uniquement quand le thème « Nouveau » est actif. */
html.ideale-monde-saas[data-theme-ui="nouveau"] .mud-button-root { border-radius: var(--ds-r-pill); }

/* Classe utilitaire d'icône du design system (Material Symbols) — disponible pour les écrans témoins et
   les lots ultérieurs ; le shell garde ses icônes MudBlazor (SVG) inchangées pour ce lot. */
html.ideale-monde-saas .ms {
    font-family: 'Material Symbols Rounded';
    font-weight: normal; font-style: normal; line-height: 1; letter-spacing: normal; text-transform: none;
    display: inline-block; white-space: nowrap; direction: ltr;
    font-variation-settings: 'opsz' 24, 'wght' 400, 'FILL' 0, 'GRAD' 0;
    -webkit-font-smoothing: antialiased; vertical-align: middle; user-select: none;
}

/* ---- Pastille d'accent de marque (indicateur des préférences ; 100 % tokens, zéro hex en dur) ------ */
/* Les autres utilitaires .ideale-ds-* (surfaces, swatchs, mono, bouton témoin) ont été RETIRÉS avec la
   surface de préversion qu'ils habillaient (PAL1, #300) : plus aucun consommateur. */
html.ideale-monde-saas .ideale-ds-chip-brand { display: inline-flex; align-items: center; gap: 6px; padding: 4px 11px; border-radius: var(--ds-r-pill); font-size: 12px; font-weight: 600; color: var(--ds-brand-text); background: var(--ds-brand-subtle); border: 1px solid var(--ds-brand-border); }

/* =============================================================================================
   DOCTRINE « le rond n'appartient qu'à IDeal » (Interface ①) · périmètre SaaS
   Jumeau #203 : règle DUPLIQUÉE à l'identique dans app-locataire.css (scopée à l'autre monde).
   Dans un écran fait de carrés arrondis, le SEUL rond est la présence d'IDeal (définie juste en dessous) :
   l'œil l'apprend en trois secondes et ne s'y trompe plus. Tout MudAvatar — avatar utilisateur, initiales
   locataire, logo d'entité (Organisation/Solution/Projet/société), emblème de statut — devient donc carré
   arrondi. Restent ronds, par EXCEPTION (traités ailleurs) : la géométrie (spinners, jauges, graphes), les
   pilules, et les points < ~12 px. Aucun rayon en dur : tout dérive de --ds-rayon-avatar (cf. tokens).
   IDeal est INTOUCHABLE par CONSTRUCTION : son avatar est un <div class="ideale-ideal-av"> (un blob CSS qui
   respire), JAMAIS un MudAvatar — cette règle ne peut donc pas l'atteindre. */
html.ideale-monde-saas .mud-avatar { border-radius: var(--ds-rayon-avatar); }

/* =============================================================================================
   Vision UI Lot 2 + Interface ② — Présence de l'IA « IDeal » + écran de connexion split · périmètre SaaS
   Jumeau #203 de app-locataire.css (styles DUPLIQUÉS ; classes .ideale-ideal-* propres à ce périmètre).
   Depuis ② l'avatar EST le logo animé : monochrome, colorway --ds-marque-*
   (bascule clair/sombre, jamais l'accent d'UI). Nom « IDeal » affiché en ITALIQUE.
   ============================================================================================= */

/* ---- Tokens FIXES de l'IA « IDeal » (ne se recolorent JAMAIS avec l'accent ni le mode) ----------
   Depuis ② l'avatar (mono) tire ses couleurs de --ds-marque-* (plus bas) ; ne restent ici que le CYAN du
   caret de la phrase du login et le PICOT rouge (source unique, chaînée par la marque --ds-marque-picot).
   (L'ambiance « nuit indigo » du panneau a disparu au ③ : le panneau visage PERMUTE désormais avec le thème
   — cf. --ds-login-visage-fond — au lieu d'un fond fixe.) */
html.ideale-monde-saas {
    --ideal-cyan: #5FE0EF; --ideal-picot: #C6402F;
}

/* ---- Tokens de la MARQUE (le logo) — périmètre SaaS, jumeau #203 de app-locataire.css -----------
   FIXES comme ceux de l'avatar : la marque bascule clair/sombre et ne suit JAMAIS l'accent d'UI. DEUX
   colorways, pas plus. Le PICOT chaîne sur celui de l'avatar (--ideal-picot) : la marque et l'avatar sont le
   même personnage — une seule source de vérité pour le rouge, jamais deux valeurs à resynchroniser.
   Exposés en --ds-* parce que la feuille du kit ne référence QUE des tokens --ds-* (contrainte ferme #286).
   ATTENTION : le DISQUE porte aussi le LOGOTYPE (le mot-symbole est posé sur la page, pas dans le disque) ;
   l'ENCRE est le visage, à l'intérieur du disque. Les confondre rend le nom invisible sur son propre fond. */
html.ideale-monde-saas {
    --ds-marque-disque: #1B1C1E;   /* colorway « posé sur fond clair » */
    --ds-marque-encre: #FFFFFF;
    --ds-marque-picot: var(--ideal-picot);
}
html.ideale-monde-saas[data-theme="dark"] {
    --ds-marque-disque: #FFFFFF;   /* colorway « posé sur fond sombre » */
    --ds-marque-encre: #1B1C1E;
}

/* ---- Tokens de l'ÉCRAN DE CONNEXION ③ (Interface ③) — deux colorways clair/sombre --------------
   Valeurs arrêtées sur la maquette (Stéphane). La maquette EST le rendu SOMBRE (forme sombre, visage clair) ;
   le rendu CLAIR n'en est PAS le négatif paresseux — il a son propre équilibre. Doctrine : la colonne FORME
   suit le thème (--ds-login-forme-fond) ; le panneau VISAGE en est l'INVERSE (--ds-login-visage-fond) ; les
   champs, le bouton et le colorway de l'avatar CONTRASTENT toujours leur panneau. AUCUN fallback (un fallback
   masquerait un bug au lieu de le révéler). Jumeau #203 dans app-locataire.css. */
html.ideale-monde-saas {
    /* Colorway CLAIR (base) : forme claire, visage sombre. */
    --ds-login-forme-fond: #F0F0F1;
    --ds-login-visage-fond: #0E0F12;
    --ds-login-visage-texte: #EAECFF;
    --ds-visage-marque-disque: #FFFFFF;   /* visage SOMBRE → disque BLANC (contraste son panneau) */
    --ds-visage-marque-encre: #1B1C1E;
    --ds-champ-fond: #FFFFFF;
    --ds-champ-bord: #D7D9E0;             /* filet visible sur un panneau clair (le sombre n'en a pas) */
    --ds-champ-texte: #1B1C1E;
    --ds-champ-libelle: #5A5D66;
    --ds-bouton-fond: #14161C;            /* bouton foncé sur panneau clair — contraste le panneau */
    --ds-bouton-texte: #FFFFFF;
    /* Encre & taille de la TUILE NEUTRE d'IDeal (le carré arrondi du descripteur sur --ds-avatar-fond, fixe). */
    --ds-avatar-encre: #FFFFFF;
    --ds-avatar-tuile: 30px;
    /* Invariants (identiques dans les deux colorways) — valeurs arrêtées sur la maquette. */
    --ds-champ-rayon: 7px;
    --ds-champ-hauteur: 38px;
    --ds-champ-texte-taille: 12.5px;
    --ds-champ-libelle-taille: 11.5px;
    --ds-bouton-hauteur: 36px;
    --ds-bienvenue-taille: 25px;
    --ds-bienvenue-graisse: 500;
    --ds-pied-taille: 10.5px;
}
html.ideale-monde-saas[data-theme="dark"] {
    /* Colorway SOMBRE (= la maquette) : forme sombre, visage clair. */
    --ds-login-forme-fond: #0E0F12;
    --ds-login-visage-fond: #F0F0F1;
    --ds-login-visage-texte: #23252C;
    --ds-visage-marque-disque: #1B1C1E;   /* visage CLAIR → disque SOMBRE */
    --ds-visage-marque-encre: #FFFFFF;
    --ds-champ-fond: #2B303C;
    --ds-champ-bord: transparent;         /* pas de filet en sombre (maquette) */
    --ds-champ-texte: #EDEEF2;
    --ds-champ-libelle: #C9CBD2;
    --ds-bouton-fond: #FFFFFF;
    --ds-bouton-texte: #0E0F12;
}

/* ---- Avatar IDeal (Interface ② : LE LOGO qui s'anime) — face de la marque (MarqueIDeal, viewBox 200×200,
   SOURCE DE VÉRITÉ de la géométrie), rendue VIVANTE. Rond PARFAIT, MONOCHROME, plat : plus de dégradé, halo,
   ombre, anneau ni morph. Colorway = --ds-marque-* (l'avatar EST le logo : le disque contraste la page ; les
   couleurs vivent sur les éléments SVG). L'ANIMATION est l'organe vital : respire, cligne, suit le regard,
   sourit au survol. La MARQUE, elle, reste immobile. */
html.ideale-monde-saas .ideale-ideal-av {
    width: 66px; height: 66px; flex: 0 0 auto; cursor: pointer;
    overflow: visible; transition: transform .22s ease;
}
html.ideale-monde-saas .ideale-ideal-av:hover { transform: scale(1.12); }
/* ⚠️ TAILLE PAR SCALE — un `transform` ne RÉSERVE pas sa place : l'avatar PEINT 1,85 × sa boîte mais n'en réserve
   que la taille nominale. Son seul usage (panneau de connexion) COMPENSE ce débordement par une marge qui DÉRIVE
   de --ideal-av-scale (voir plus bas). Le flat n'a plus ni halo ni ombre : le scale ne fait que grossir le disque. */
html.ideale-monde-saas .ideale-ideal-av--grand { --ideal-av-scale: 1.85; transform: scale(var(--ideal-av-scale)); }
html.ideale-monde-saas .ideale-ideal-av--grand:hover { transform: scale(2.02); }
html.ideale-monde-saas .ideale-ideal-av--mini { width: 44px; height: 44px; }
/* Respiration : léger battement d'échelle du visage (~1,5 %). Le disque reste un CERCLE PARFAIT — un scale ne le
   déforme jamais. C'est tout l'intérêt du mono : la vie vient du MOUVEMENT, pas d'un contour qui morphe. */
html.ideale-monde-saas .ideale-ideal-souffle {
    transform-box: fill-box; transform-origin: center;
    animation: ideale-ideal-souffle 5s ease-in-out infinite;
}
/* Yeux : ce groupe reçoit le SUIVI DU REGARD (translate posé par ideal-presence.js, en unités du viewBox). */
html.ideale-monde-saas .ideale-ideal-yeux { transition: transform .12s ease-out; }
/* Chaque œil CLIGNE (fermeture verticale), origine au centre de l'œil (transform-box:fill-box). */
html.ideale-monde-saas .ideale-ideal-oeil {
    transform-box: fill-box; transform-origin: center;
    animation: ideale-ideal-blink 5.4s infinite;
}
/* Sourire : s'accentue au survol (scaleY), origine au sommet du trait. */
html.ideale-monde-saas .ideale-ideal-sourire {
    transform-box: fill-box; transform-origin: center top; transition: transform .22s ease;
}
html.ideale-monde-saas .ideale-ideal-av:hover .ideale-ideal-sourire { transform: scaleY(1.35); }
@keyframes ideale-ideal-souffle {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.025); }
}
@keyframes ideale-ideal-blink {
    0%, 92%, 100% { transform: scaleY(1); }
    96% { transform: scaleY(.08); }
}

/* ---- Bulle flottante (bas-droite) : lanceur ---------------------------------------------------- */
/* Hauteur du pied de page fixe (③bis, défaut 5). La bulle IDeal reste TOUJOURS visible : elle se pose
   AU-DESSUS du pied (le pied ne gagne jamais). Le pied (.mud-main-content padding-bottom, app.css) ET le
   décalage bas de la bulle DÉRIVENT de ce seul token → si le pied change de hauteur, la bulle suit toute
   seule (un token, jamais un chiffre en dur). */
html.ideale-monde-saas { --ds-pied-hauteur: 44px; }
html.ideale-monde-saas .ideale-ideal-bulle {
    position: fixed; right: 22px; bottom: calc(var(--ds-pied-hauteur) + 16px); z-index: 1300;
    border: 0; background: transparent; padding: 0; cursor: pointer; line-height: 0;
}
html.ideale-monde-saas .ideale-ideal-bulle .ideale-ideal-av--mini { transform: scale(.9); transition: transform .22s ease; }
html.ideale-monde-saas .ideale-ideal-bulle:hover .ideale-ideal-av--mini { transform: scale(1.06); }
html.ideale-monde-saas .ideale-ideal-bulle:focus-visible { outline: none; }
html.ideale-monde-saas .ideale-ideal-bulle:focus-visible .ideale-ideal-av--mini { box-shadow: var(--ds-focus-ring); border-radius: 50%; }
@keyframes ideale-ideal-rebond {
    0% { transform: scale(.9); } 40% { transform: scale(1.14); } 70% { transform: scale(.98); } 100% { transform: scale(1); }
}
html.ideale-monde-saas .ideale-ideal-bulle--rebond .ideale-ideal-av--mini { animation: ideale-ideal-rebond .4s ease; }

/* ---- Volet latéral droit redimensionnable ------------------------------------------------------ */
html.ideale-monde-saas .ideale-ideal-volet {
    position: fixed; right: 0; z-index: 1301; display: flex; flex-direction: column;
    background: var(--ds-bg-surface); color: var(--ds-text);
    border-left: 1px solid var(--ds-border); box-shadow: var(--ds-shadow-lg);
    animation: ideale-ideal-volet-apparait .22s ease;
}
/* #321 F1 — largeur redimensionnable : la variable --volet-largeur (posée sur la RACINE par le module JS, donc
   partagée avec le décalage de l'écran-tâche ci-dessous) l'emporte ; à défaut, la largeur par défaut du mode. */
html.ideale-monde-saas .ideale-ideal-volet--compact {
    right: 22px; bottom: 22px; width: var(--volet-largeur, min(384px, 94vw)); height: min(560px, 74vh);
    border: 1px solid var(--ds-border); border-radius: var(--ds-r-lg);
}
html.ideale-monde-saas .ideale-ideal-volet--plein {
    top: 0; bottom: 0; height: 100vh; width: var(--volet-largeur, min(440px, 96vw)); border-radius: 0;
}
/* #321 F1 — poignée de redimensionnement : bord GAUCHE du volet (ancré à droite), fine, curseur col-resize,
   focusable (anneau AA). Ne rogne pas le contenu (superposée). Masquée sur petit écran (voir media query). */
html.ideale-monde-saas .ideale-ideal-poignee {
    position: absolute; left: 0; top: 0; bottom: 0; width: 8px; z-index: 2;
    cursor: col-resize; touch-action: none; background: transparent;
}
html.ideale-monde-saas .ideale-ideal-poignee:hover { background: var(--ds-border-subtle); }
html.ideale-monde-saas .ideale-ideal-poignee:focus-visible {
    outline: 2px solid var(--ds-focus, var(--ds-brand)); outline-offset: -2px;
}

/* #310-C (revue UX) — volet PLEIN par-dessus un ÉCRAN-TÂCHE : jamais d'action recouverte. En pleine hauteur,
   le volet (fixed, z 1301) recouvrait la croix de sortie ET le volet d'action droit (bouton « Enregistrer »)
   de l'écran-tâche — violation des invariants §1/§2 pendant l'usage même que la doctrine encourage (« IDeal,
   seule surface flottante admise par-dessus une saisie »). Deux parades, par largeur (jumeau #203 strict) :
   · ≥ 1280 px : CÔTE-À-CÔTE — l'écran-tâche se décale de la largeur du volet (transition 225 ms, cohérente
     avec le shell) et TOUT reste visible : la conversation accompagne la saisie au lieu de la recouvrir ;
   · < 1280 px : le plein retombe au GABARIT COMPACT le temps de l'écran-tâche (l'état Plein du circuit est
     conservé — il se ré-exprime dès que la place existe ou de retour dans le shell standard). */
@media (min-width: 1280px) {
    html.ideale-monde-saas .kit-ecran-tache {
        transition: margin-right 225ms cubic-bezier(0, 0, 0.2, 1);
    }

    html.ideale-monde-saas:has(.ideale-ideal-volet--plein) .kit-ecran-tache {
        /* #321 F1 — le décalage suit la largeur choisie (même variable de racine que le volet) : jamais de
           contenu recouvert ni d'espace mort, quelle que soit la largeur redimensionnée. */
        margin-right: var(--volet-largeur, min(440px, 96vw));
    }
}

@media (max-width: 1279.98px) {
    html.ideale-monde-saas:has(.kit-ecran-tache) .ideale-ideal-volet--plein {
        top: auto; right: 22px; bottom: 22px;
        width: min(384px, 94vw); height: min(560px, 74vh);
        border: 1px solid var(--ds-border); border-radius: var(--ds-r-lg);
    }
}
@keyframes ideale-ideal-volet-apparait { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
html.ideale-monde-saas .ideale-ideal-volet-entete {
    display: flex; align-items: center; gap: 12px; padding: 12px 14px;
    border-bottom: 1px solid var(--ds-border-subtle);
}
html.ideale-monde-saas .ideale-ideal-volet-entete .ideale-ideal-av { width: 40px; height: 40px; cursor: default; }
html.ideale-monde-saas .ideale-ideal-nom { font-style: italic; font-weight: 600; }
html.ideale-monde-saas .ideale-ideal-volet-fil {
    flex: 1 1 auto; overflow-y: auto; overflow-x: hidden; padding: 14px; display: flex; flex-direction: column; gap: 10px;
}
/* #322 (G1/G2/G3) — chaque « tour » groupe un message et sa rangée d'actions/horodatage. La question reste à
   droite (bulle) ; la réponse coule « dans le blanc » à gauche, pleine largeur utile. */
html.ideale-monde-saas .ideale-ideal-tour { display: flex; flex-direction: column; gap: 3px; }
html.ideale-monde-saas .ideale-ideal-tour--moi { align-self: flex-end; align-items: flex-end; max-width: 92%; }
html.ideale-monde-saas .ideale-ideal-tour--ia { align-self: stretch; }
html.ideale-monde-saas .ideale-ideal-msg { border-radius: var(--ds-r-md); padding: 8px 11px; }
html.ideale-monde-saas .ideale-ideal-msg--moi { background: var(--ds-brand-subtle); color: var(--ds-brand-text); }
/* #322 (G1) — la RÉPONSE « dans le blanc » : ni carte, ni bordure, ni fond ; le texte coule sur le fond du volet. */
html.ideale-monde-saas .ideale-ideal-msg--ia { padding: 2px 0; background: transparent; border: none; }
/* L'attente « réfléchit » (avatar) reste un message IA (enfant direct du fil) : elle coule aussi dans le blanc,
   alignée à gauche. */
html.ideale-monde-saas .ideale-ideal-attente { align-self: flex-start; max-width: 92%; display: flex; align-items: center; gap: 8px; }
/* #324 V5 — écran d'accueil (fil vide) : le titre REMONTE — on réduit l'espace mort sous l'en-tête pour un
   rythme naturel (en-tête → titre → sous-titre → suggestions → saisie). */
html.ideale-monde-saas .ideale-ideal-vide { text-align: center; padding: 6px 8px 14px; }
html.ideale-monde-saas .ideale-ideal-proposition { margin: 4px 14px; padding: 10px 12px; border: 1px solid var(--ds-brand-border); background: var(--ds-brand-subtle); border-radius: var(--ds-r-md); }
html.ideale-monde-saas .ideale-ideal-actions { padding: 6px 14px 0; }
/* ---- Suggestions contextuelles (#311) : la bande qui fait qu'IDeal SUIT l'administrateur ----------------
   Jumeau #203 de la règle d'app-locataire.css (feuilles scopées par monde, jamais de règle partagée).
   Les pastilles se renouvellent à chaque changement d'écran pendant que la conversation, elle, ne bouge pas.
   `flex: 0 0 auto` sur la ZONE est ESSENTIEL : le fil (flex: 1 1 auto) garde toute sa place et son propre
   défilement — la bande s'intercale au-dessus de la saisie sans jamais rogner la conversation. */
html.ideale-monde-saas .ideale-ideal-suggestions-zone { flex: 0 0 auto; padding: 6px 14px 0; }
/* #321 F2 — RETOUR À LA LIGNE (flex-wrap) : plus AUCUN ascenseur horizontal, quelle que soit la largeur (F1) ou
   la longueur des libellés. Hauteur bornée (≈ 3 lignes) avec défilement VERTICAL discret si les suggestions sont
   nombreuses — jamais horizontal. */
html.ideale-monde-saas .ideale-ideal-suggestions {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    margin-top: 2px;
    max-height: 6.5rem; overflow-y: auto; overflow-x: hidden;
    scrollbar-width: thin;
}
/* Chaque pastille garde son libellé sur une ligne (jamais coupé au milieu d'un mot) : c'est la BANDE qui passe à
   la ligne, plus le contenu qui défile latéralement. */
html.ideale-monde-saas .ideale-ideal-suggestions .ideale-ideal-sugg { white-space: nowrap; }
/* La pastille est un BOUTON réel (focus clavier, activation Entrée/Espace, anneau de focus AA — jamais un div
   cliquable) simplement habillé en pastille. `nowrap` garantit un libellé lisible d'un bloc : c'est la bande
   qui défile, jamais le mot qui se coupe. */
/* #324 V3 — puces de suggestions COMPACTES et redessinées. Direction retenue (voir CR) : « fond très léger,
   sans bordure au repos, léger relief au survol » — substance et identité de marque sans la lourdeur de l'ancien
   contour plein toujours teinté. Le TEXTE ne change pas de taille (consigne) ; c'est la pilule qui se resserre
   (padding réduit) et se redessine. Cible tactile ~32px conservée (min-height 30 + padding). Tokens only,
   contraste AA (brand-text sur brand-subtle). */
html.ideale-monde-saas .ideale-ideal-sugg {
    border-radius: var(--ds-r-pill);
    text-transform: none;
    min-width: 0; min-height: 30px;
    padding: 3px 12px;
    background: var(--ds-brand-subtle); color: var(--ds-brand-text);
    border: 1px solid transparent; font-weight: 600; line-height: 1.3;
    box-shadow: none;
    transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
html.ideale-monde-saas .ideale-ideal-sugg:hover {
    background: var(--ds-brand-subtle-2); border-color: var(--ds-brand-border); box-shadow: var(--ds-shadow-xs);
}
/* Focus clavier : anneau GLOBAL du projet (outline accent, app.css) conservé — pas d'outline:none ici. */
@media (prefers-reduced-motion: reduce) { html.ideale-monde-saas .ideale-ideal-sugg { transition: none; } }
/* #323 P3-a — bandeau de prudence TOUT EN BAS, sous la saisie : micro-typo centrée, discrète, contraste AA
   préservé (token --ds-text-muted). Permanent : il porte la transparence IA depuis le retrait du badge (#322). */
html.ideale-monde-saas .ideale-ideal-avertissement { padding: 6px 12px 8px; text-align: center; }
html.ideale-monde-saas .ideale-ideal-avertissement .mud-typography { font-size: .68rem; }
/* #323 P3 — zone de saisie : les commandes s'alignent en BAS pour que le champ auto-extensible pousse vers le
   HAUT (le duo droit reste au ras de la dernière ligne, comme les assistants de référence). */
/* #324 V5 — rangée de saisie : on resserre le bas pour RAPPROCHER le bandeau de prudence du champ (le bandeau
   garde sa règle inchangée : padding 6px 12px 8px — verrou de test #323). */
html.ideale-monde-saas .ideale-ideal-saisie { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px 4px; border-top: 1px solid var(--ds-border-subtle); }
html.ideale-monde-saas .ideale-ideal-champ { flex: 1 1 auto; }
html.ideale-monde-saas .ideale-ideal-mic { flex: 0 0 auto; }
/* #323 P3-b — bouton multirôle envoi / stop / coche (droite). */
html.ideale-monde-saas .ideale-ideal-envoi { flex: 0 0 auto; }
/* #323 P3-d — visualiseur d'onde de dictée (remplace le champ pendant l'enregistrement) : occupe la place du
   champ, teinté « enregistrement » (rouge de danger), hauteur d'une ligne. Le dessin (barres réagissant au niveau
   réel, ou pulsation d'opacité sous mouvement réduit) est piloté côté JS via ce color (currentColor du canvas). */
html.ideale-monde-saas .ideale-ideal-onde-zone { flex: 1 1 auto; display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 0 4px; }
html.ideale-monde-saas .ideale-ideal-onde { flex: 1 1 auto; height: 28px; width: 100%; color: var(--ds-danger); }
html.ideale-monde-saas .ideale-ideal-onde-libelle { color: var(--ds-danger); font-weight: 600; white-space: nowrap; }

/* ============================ #324 — finition visuelle de la zone de saisie (jumeau #203) =====================
   Polissage PUR (aucune logique, aucun markup, aucune resx) : gabarit de boutons unifié carré-arrondi (V1),
   alignement au cordeau de la rangée (V2), puces compactes redessinées (V3), rythme vertical resserré (V5).
   Tokens uniquement, contraste AA, mouvement réduit respecté. Jumeau strict d'app-locataire.css. */

/* V2 — le champ auto-extensible pousse vers le HAUT (align-items:flex-end) ; on COLLE le bas VISIBLE du champ au
   bas des boutons en retirant la marge d'aide réservée (MudTextField dense réserve ~4px sous le champ, même sans
   texte d'aide) — sinon le duo droit flottait 4px sous l'axe du champ. Le display:none garde l'alignement si un
   texte d'aide venait à s'afficher. */
html.ideale-monde-saas .ideale-ideal-champ { margin-bottom: 0; }
html.ideale-monde-saas .ideale-ideal-champ .mud-input-helper-text { display: none; }

/* V1 — GABARIT UNIQUE des icônes-boutons de la rangée (💡, micro, croix, envoi, stop, coche) : carré à coins
   arrondis (token modéré ~8px, jamais un cercle), ~38px de côté, icône centrée optiquement. Bat le rayon pill du
   thème « nouveau » (spécificité + ordre source). Le clic fiable (#323 P3-f) reste garanti (glyphe transparent). */
html.ideale-monde-saas .ideale-ideal-saisie .mud-icon-button {
    width: 38px; height: 38px; min-width: 38px; flex: 0 0 auto; padding: 0;
    border-radius: var(--ds-r-sm);
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: none;
    transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
html.ideale-monde-saas .ideale-ideal-saisie .mud-icon-button .mud-icon-root { font-size: 20px; color: inherit; }
/* Anneau de focus : on s'appuie sur l'anneau GLOBAL du projet (outline accent, app.css) — jamais d'outline:none
   ici, qui retirerait l'indicateur de focus clavier (WCAG 2.4.7). box-shadow:none ne touche que l'élévation. */
@media (prefers-reduced-motion: reduce) {
    html.ideale-monde-saas .ideale-ideal-saisie .mud-icon-button { transition: none; }
}

/* V1 — ACCENT PLEIN : envoi + coche (le bouton PRINCIPAL « aller / valider »). Accent de la charte (--ds-brand),
   glyphe sur fond (--ds-text-on-brand). :not(.ideale-ideal-stop) exclut le stop, qui partage .ideale-ideal-envoi. */
html.ideale-monde-saas .ideale-ideal-envoi:not(.ideale-ideal-stop) {
    background: var(--ds-brand); color: var(--ds-text-on-brand);
}
html.ideale-monde-saas .ideale-ideal-envoi:not(.ideale-ideal-stop):hover { background: var(--ds-brand-hover); }
html.ideale-monde-saas .ideale-ideal-envoi:not(.ideale-ideal-stop):active { background: var(--ds-brand-active); }
/* Envoi DÉSACTIVÉ (champ vide) : gabarit conservé, gris de token propre (bat le disabled !important de MudBlazor,
   plus net que son voile noir translucide). « Envoi grisé champ vide » (V1). */
html.ideale-monde-saas .ideale-ideal-envoi:not(.ideale-ideal-stop):disabled,
html.ideale-monde-saas .ideale-ideal-envoi:not(.ideale-ideal-stop).mud-disabled {
    background: var(--ds-bg-inset) !important; color: var(--ds-text-subtle) !important;
}

/* V1 — FANTÔME (ghost) du MÊME gabarit : micro, croix (annuler la dictée), stop (arrêter la génération) et la
   bascule 💡 — l'envoi est plein, le reste discret. « stop et croix » = déclinaison token cohérente (teinte adaptée). */
html.ideale-monde-saas .ideale-ideal-mic,
html.ideale-monde-saas .ideale-ideal-stop,
html.ideale-monde-saas .ideale-ideal-sugg-bascule {
    background: transparent; color: var(--ds-text-muted);
}
html.ideale-monde-saas .ideale-ideal-mic:hover,
html.ideale-monde-saas .ideale-ideal-stop:hover,
html.ideale-monde-saas .ideale-ideal-sugg-bascule:hover {
    background: var(--ds-bg-hover); color: var(--ds-text);
}
/* La bascule 💡 REPLIÉE s'aligne sur le ghost du micro (muted, même tonalité) ; DÉPLIÉE, MudBlazor la teinte
   accent (.mud-primary-text = --ds-brand, état actif) — on ne « muted » donc que l'état replié. Spécificité
   renforcée car MudBlazor colore le bouton enveloppé dans le MudBadge en --ds-text. */
html.ideale-monde-saas .ideale-ideal-saisie .ideale-ideal-sugg-bascule:not(.mud-primary-text) { color: var(--ds-text-muted); }
/* #324 (revue adversariale) — le Stop est rendu Variant.Filled Color.Primary : MudBlazor le REMPLIT de marque
   à :focus-visible ET :active (.mud-button-filled-primary:focus-visible/:active et .mud-icon-button:active
   .mud-button-filled-primary, spécificité 0,3,0 — au-dessus du ghost de base 0,2,1). Sans garde, un utilisateur
   CLAVIER (focus) ou à l'activation verrait le Stop reprendre le fond de marque, le glyphe muted tombant alors
   sous 3:1. On maintient le ghost transparent sur ces deux états, spécificité renforcée (0,4,1 > 0,3,0). L'anneau
   de focus (box-shadow du gabarit) reste visible. Micro/croix/💡 ne sont pas « filled » → non concernés. */
html.ideale-monde-saas .ideale-ideal-saisie .ideale-ideal-stop:focus-visible,
html.ideale-monde-saas .ideale-ideal-saisie .ideale-ideal-stop:active { background: transparent; }

/* ============================ #335 — bouton flottant « Revenir en bas » du fil (jumeau #203) ==================
   Quand le fil est défilé vers le haut (seuil ~200 px, arbitré côté JS), un bouton apparaît en fondu, CENTRÉ
   au-dessus de la zone de saisie ; un clic ramène en bas (défilement doux). Apparition/disparition ET clic sont
   100 % client (écouteur scroll du module — zéro aller-retour .NET, doctrine #308). L'hôte est positionné dans la
   rangée de saisie (position:relative), en dehors du flux flex (aucun impact sur la rangée). Carré-arrondi,
   gabarit #324 — JAMAIS rond (le cercle est réservé à l'avatar d'IDeal). Tokens uniquement, contraste AA,
   mouvement réduit respecté. Jumeau strict d'app-locataire.css. */
html.ideale-monde-saas .ideale-ideal-saisie { position: relative; }
html.ideale-monde-saas .ideale-ideal-vers-bas-hote {
    position: absolute; left: 50%; bottom: calc(100% + 8px); z-index: 3;
    transform: translateX(-50%) translateY(6px);
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity .18s ease, transform .18s ease;
}
html.ideale-monde-saas .ideale-ideal-vers-bas-hote--visible {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: translateX(-50%) translateY(0);
}
@media (prefers-reduced-motion: reduce) {
    html.ideale-monde-saas .ideale-ideal-vers-bas-hote { transition: none; }
}
html.ideale-monde-saas .ideale-ideal-vers-bas {
    width: 38px; height: 38px; padding: 0; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--ds-border); border-radius: var(--ds-r-sm);
    background: var(--ds-bg-surface); color: var(--ds-text-muted); box-shadow: var(--ds-shadow-md);
    transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
html.ideale-monde-saas .ideale-ideal-vers-bas:hover {
    background: var(--ds-bg-hover); color: var(--ds-text); box-shadow: var(--ds-shadow-lg);
}
html.ideale-monde-saas .ideale-ideal-vers-bas:focus-visible {
    outline: 2px solid var(--mud-palette-primary); outline-offset: 2px;
}
html.ideale-monde-saas .ideale-ideal-vers-bas .mud-icon-root { font-size: 20px; }
@media (prefers-reduced-motion: reduce) {
    html.ideale-monde-saas .ideale-ideal-vers-bas { transition: none; }
}

/* ---- Voix (#306) : note d'erreur vocale présentable (les états « J'écoute… » / « Transcription… » sont désormais
   rendus DANS la zone de saisie — visualiseur d'onde #323 P3-d). ------------------------------------------------ */
html.ideale-monde-saas .ideale-ideal-note { margin: 0 14px 4px; }
@media (prefers-reduced-motion: reduce) {
    /* #321 (revue) : l'apparition du volet (translation + opacité) suit la discipline maison — figée en
       mouvement réduit (comme le rebond de la bulle et les animations de la présence). */
    html.ideale-monde-saas .ideale-ideal-volet { animation: none; }
}

/* ---- #321 F1 — petit écran : volet pleine largeur, poignée masquée --------------------------------------
   La préférence de largeur est ignorée (width:auto + left/right:0 l'emportent sur --volet-largeur). Choisi à
   768 px (téléphone + tablette portrait) : au-delà, le panneau latéral reprend tout son sens et redevient ajustable. */
@media (max-width: 767.98px) {
    html.ideale-monde-saas .ideale-ideal-volet--compact,
    html.ideale-monde-saas .ideale-ideal-volet--plein { left: 0; right: 0; width: auto; }
    html.ideale-monde-saas .ideale-ideal-poignee { display: none; }
}

/* ---- #321 F3 / #322 G2-G3 — barres d'actions sous chaque message : discrètes, tokens, jamais de débordement ---
   Base commune (réponse ET question) ; la réponse reste alignée à gauche (comportement #321 inchangé), la question
   s'aligne à droite et s'atténue au repos (pleine au survol/focus ; toujours visible au toucher). */
html.ideale-monde-saas .ideale-ideal-barre {
    display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-top: 4px;
}
html.ideale-monde-saas .ideale-ideal-barre-question { justify-content: flex-end; }
/* #322 (revue AA) — l'atténuation au repos ne porte QUE sur les BOUTONS d'action (révélés au survol/focus).
   L'horodatage est de l'INFORMATION persistante, pas une action : il reste à pleine opacité (--ds-text-muted tient
   l'AA ; l'atténuer via l'opacité du parent le ferait chuter sous 4,5:1, ce que l'opacité d'un ancêtre rend
   inévitable pour tout le sous-arbre — d'où l'atténuation ciblée sur les seules actions). */
html.ideale-monde-saas .ideale-ideal-barre-question .ideale-ideal-action {
    opacity: .62; transition: opacity .15s ease;
}
html.ideale-monde-saas .ideale-ideal-tour--moi:hover .ideale-ideal-barre-question .ideale-ideal-action,
html.ideale-monde-saas .ideale-ideal-barre-question:focus-within .ideale-ideal-action { opacity: 1; }
/* Tactile (pas de survol) : actions toujours pleinement visibles — jamais une action « cachée » derrière un hover absent. */
@media (hover: none) { html.ideale-monde-saas .ideale-ideal-barre-question .ideale-ideal-action { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { html.ideale-monde-saas .ideale-ideal-barre-question .ideale-ideal-action { transition: none; } }
/* #322 (G2) — horodatage : micro-typo DISCRÈTE mais contraste AA (token --ds-text-muted, jamais --ds-text-subtle). */
html.ideale-monde-saas .ideale-ideal-horodatage { font-size: .68rem; color: var(--ds-text-muted); white-space: nowrap; }
html.ideale-monde-saas .ideale-ideal-horodatage--fin { margin-left: 4px; }

/* ============================ #323 — affinages des barres, clic fiable, marqueur d'arrêt ======================== */
/* P3-e — icônes des barres d'actions plus FINES (glyphe ~16px) ; la cible tactile reste généreuse (bouton ≥ ~32px).
   On réduit le DESSIN, jamais l'accessibilité. L'horodatage NE change PAS (taille validée par le pilotage). */
html.ideale-monde-saas .ideale-ideal-barre .ideale-ideal-action { min-width: 30px; }
html.ideale-monde-saas .ideale-ideal-barre .ideale-ideal-action .mud-icon-root { font-size: 1rem; }
/* P3-e — la barre RÉPONSE s'atténue aussi au repos (montée au survol/focus), comme la barre question. L'atténuation
   porte UNIQUEMENT sur les ACTIONS (jamais l'horodatage, qui est de l'information — verrou AA #322 conservé). */
html.ideale-monde-saas .ideale-ideal-barre-reponse .ideale-ideal-action { opacity: .62; transition: opacity .15s ease; }
html.ideale-monde-saas .ideale-ideal-tour--ia:hover .ideale-ideal-barre-reponse .ideale-ideal-action,
html.ideale-monde-saas .ideale-ideal-barre-reponse:focus-within .ideale-ideal-action { opacity: 1; }
@media (hover: none) { html.ideale-monde-saas .ideale-ideal-barre-reponse .ideale-ideal-action { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { html.ideale-monde-saas .ideale-ideal-barre-reponse .ideale-ideal-action { transition: none; } }
/* P3-f — CLIC FIABLE : le glyphe / le badge ne captent JAMAIS l'événement (ils faisaient rater le clic au centre de
   l'ampoule) → toute la surface du bouton répond, jusqu'au bord. Corrigé à la RACINE (pointer-events du glyphe),
   pas par un agrandissement cosmétique. Couvre TOUTES les icônes-boutons du volet (bascule, micro, envoi/stop/coche,
   barres d'actions, en-tête). */
html.ideale-monde-saas .ideale-ideal-volet .mud-icon-button .mud-icon-root,
html.ideale-monde-saas .ideale-ideal-volet .mud-badge__badge { pointer-events: none; }
/* #323 P1 — marqueur DISCRET « Génération arrêtée » (ni réponse, ni action, ni vote). */
html.ideale-monde-saas .ideale-ideal-arret { display: flex; align-items: center; gap: 6px; padding: 2px 0; }
html.ideale-monde-saas .ideale-ideal-arret .mud-icon-root { font-size: 1rem; }

/* #322 (G1) — sources DISCRÈTES en pied de réponse : reliées par un filet fin, jamais enfermées dans une carte.
   (Côté SaaS, l'assistant n'ancre pas sur un graphe : cette zone reste inutilisée par ReponseIDealSaaS ; la règle
   est conservée par PARITÉ visuelle avec le locataire.) */
html.ideale-monde-saas .ideale-ideal-sources {
    display: flex; flex-direction: column; gap: 2px;
    margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--ds-border-subtle);
}

/* #322 (G4) — zone de suggestions REPLIABLE : animation de hauteur par grille (0fr↔1fr), débranchée sous
   prefers-reduced-motion. Repliée, l'intérieur est visibility:hidden → retiré du parcours clavier et de l'arbre
   d'accessibilité (jamais un bouton focalisable invisible) ; la visibilité reste le temps de la fermeture puis se
   coupe. `flex: 0 0 auto` : la zone ne rogne jamais le fil (flex: 1 1 auto). */
html.ideale-monde-saas .ideale-ideal-suggestions-repli {
    flex: 0 0 auto; display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s ease;
}
html.ideale-monde-saas .ideale-ideal-suggestions-repli--ouvert { grid-template-rows: 1fr; }
html.ideale-monde-saas .ideale-ideal-suggestions-repli-inner {
    overflow: hidden; min-height: 0; visibility: hidden; transition: visibility .22s;
}
html.ideale-monde-saas .ideale-ideal-suggestions-repli--ouvert .ideale-ideal-suggestions-repli-inner { visibility: visible; }
@media (prefers-reduced-motion: reduce) {
    html.ideale-monde-saas .ideale-ideal-suggestions-repli,
    html.ideale-monde-saas .ideale-ideal-suggestions-repli-inner { transition: none; }
}
html.ideale-monde-saas .ideale-ideal-sugg-bascule { flex: 0 0 auto; }

/* #322 (G3) — mini-confirm inline « remplacer le brouillon ? » : discret, au-dessus de la saisie, jamais un modal
   par-dessus le volet flottant. Ne rogne pas le fil (flex: 0 0 auto). */
html.ideale-monde-saas .ideale-ideal-confirm {
    flex: 0 0 auto; margin: 0 14px 4px; padding: 8px 10px;
    border: 1px solid var(--ds-brand-border); background: var(--ds-brand-subtle); border-radius: var(--ds-r-md);
    display: flex; flex-direction: column; gap: 4px;
}
html.ideale-monde-saas .ideale-ideal-confirm-actions { display: flex; justify-content: flex-end; gap: 6px; }

/* ---- #321 F4 — présence « réfléchit » : on RÉUTILISE les keyframes existants (souffle/clignement) en
   n'accélérant que la DURÉE — géométrie et couleurs gravées intactes, aucun morph, aucun nouveau glyphe. ----- */
html.ideale-monde-saas .ideale-ideal-av--reflechit .ideale-ideal-souffle { animation-duration: 1.3s; }
html.ideale-monde-saas .ideale-ideal-av--reflechit .ideale-ideal-oeil { animation-duration: 2.2s; }
/* Sous prefers-reduced-motion, le figeage général coupe tout mouvement ; « réfléchit » signale l'activité par une
   pulsation d'OPACITÉ douce (jamais de translation ni de scale). Le !important + la spécificité battent le figeage.
   Keyframe au NOM GLOBAL PARTAGÉ avec le locataire (comme souffle/blink/volet-apparait) : définitions identiques
   dans les deux feuilles, aucune collision (chacune scopée à son monde). */
@keyframes ideale-ideal-reflechit-opacite { 0%, 100% { opacity: 1; } 50% { opacity: .6; } }
@media (prefers-reduced-motion: reduce) {
    html.ideale-monde-saas .ideale-ideal-av--reflechit .ideale-ideal-souffle {
        animation: ideale-ideal-reflechit-opacite 1.8s ease-in-out infinite !important;
    }
}

/* =============================================================================================
   Écran de connexion ③ (Interface ③) — PAGE PLEINE, split forme|visage + pied PLEINE LARGEUR.
   Plus de « box » : le formulaire EST la moitié gauche. La colonne FORME suit le thème
   (--ds-login-forme-fond) ; le panneau VISAGE en est l'INVERSE (--ds-login-visage-fond) → deux tons quel que
   soit le thème, qui PERMUTENT à la bascule clair/sombre. Champs, bouton, descripteur et colorway de l'avatar
   dérivent des tokens (aucune valeur en dur ici). Jumeau #203 dans app-locataire.css. =========== */
html.ideale-monde-saas .ideale-ideal-login {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 1fr auto;
    grid-template-areas: "forme visage" "pied pied";
    min-height: 100vh;
}
/* Sous 900 px : une seule colonne (le panneau visage disparaît) + rangée du pied. */
@media (max-width: 900px) {
    html.ideale-monde-saas .ideale-ideal-login {
        grid-template-columns: 1fr;
        grid-template-areas: "forme" "pied";
    }
}

/* ---- Colonne FORME (gauche) : tête ancrée (nom + langue), formulaire centré ---- */
html.ideale-monde-saas .ideale-ideal-login-forme {
    grid-area: forme; position: relative;
    display: flex; align-items: center; justify-content: center;
    padding: 24px 28px; background: var(--ds-login-forme-fond);
}
/* Tête ANCRÉE en absolu (nom à gauche, langue à droite) → le corps se centre sur TOUTE la hauteur de la colonne,
   au même niveau optique que le visage d'en face (et non décalé sous une bande d'en-tête). */
html.ideale-monde-saas .ideale-ideal-login-tete {
    position: absolute; top: 22px; left: 28px; right: 28px;
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
html.ideale-monde-saas .ideale-ideal-login-corps { width: 100%; max-width: 300px; }

/* ---- Panneau VISAGE (droite) : la présence + la phrase tournante. Fond INVERSE du thème. ---- */
html.ideale-monde-saas .ideale-ideal-login-visage {
    grid-area: visage; position: relative; overflow: hidden;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 22px;
    padding: 48px 40px;
    background: var(--ds-login-visage-fond); color: var(--ds-login-visage-texte);
}
@media (max-width: 900px) { html.ideale-monde-saas .ideale-ideal-login-visage { display: none; } }
/* L'avatar du panneau suit le colorway du PANNEAU (inverse du thème), porté par --ds-visage-marque-* — ce qui
   REMPLACE le forçage ② « disque toujours blanc » : le panneau n'est plus fixe, il permute. Aucun hex ici. */
html.ideale-monde-saas .ideale-ideal-login-visage .ideale-ideal-av {
    --ideal-av-taille: 80px;
    width: var(--ideal-av-taille); height: var(--ideal-av-taille);
    --ds-marque-disque: var(--ds-visage-marque-disque);
    --ds-marque-encre: var(--ds-visage-marque-encre);
}
/* On réserve la place réellement PEINTE par le scale de --grand (l'avatar peint taille×scale mais n'en réserve
   que la nominale). Marge DÉRIVÉE, jamais divergente du scale. L'avatar ② n'est pas touché : c'est la mise en
   page qui disait faux sur la place qu'il occupe. */
html.ideale-monde-saas .ideale-ideal-login-visage .ideale-ideal-av--grand {
    margin-block: calc(var(--ideal-av-taille) * (var(--ideal-av-scale) - 1) / 2);
}
html.ideale-monde-saas .ideale-ideal-login-message {
    max-width: 320px; text-align: center; font-size: 17px; line-height: 1.5; font-weight: 500;
    color: var(--ds-login-visage-texte); min-height: 3.2em;
}
html.ideale-monde-saas .ideale-ideal-caret {
    display: inline-block; width: 2px; height: 1.1em; margin-left: 2px; vertical-align: text-bottom;
    background: var(--ideal-cyan); animation: ideale-ideal-caret 1s step-end infinite;
}
@keyframes ideale-ideal-caret { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }

/* ---- Visage « remonté » sous 900 px : le panneau étant masqué, la présence apparaît en petit au-dessus du
   titre, dans la colonne formulaire (le seul rond de l'écran reste UNIQUE — l'un OU l'autre selon la largeur). */
html.ideale-monde-saas .ideale-ideal-login-visage-mobile { display: none; }
@media (max-width: 900px) {
    html.ideale-monde-saas .ideale-ideal-login-visage-mobile {
        display: block; width: 56px; height: 56px; margin: 0 0 18px;
    }
}

/* ---- Pied de page — court sur TOUTE la largeur (sous les deux panneaux), fond de la colonne formulaire. ---- */
html.ideale-monde-saas .ideale-ideal-login-pied {
    grid-area: pied; display: flex; align-items: center; justify-content: center;
    padding: 8px 16px; background: var(--ds-login-forme-fond);
    font-size: var(--ds-pied-taille);
    /* Pas de border-top ici : le FILET est porté par le composant .ideale-pied-copyright (③bis, défaut 2 —
       sinon deux traits se superposaient au-dessus du pied). */
}

/* ---- « Bienvenue » + descripteur (tuile neutre --ds-avatar-fond OU identité du client) ---- */
html.ideale-monde-saas .ideale-login-bienvenue {
    margin: 0 0 6px; line-height: 1.2;
    font-size: var(--ds-bienvenue-taille); font-weight: var(--ds-bienvenue-graisse); color: var(--ds-champ-texte);
}
html.ideale-monde-saas .ideale-login-descripteur {
    display: flex; align-items: center; gap: 9px; margin-bottom: 22px; min-width: 0; color: var(--ds-champ-libelle);
}
html.ideale-monde-saas .ideale-login-descripteur-texte { font-size: 13px; min-width: 0; }
/* Tuile NEUTRE d'IDeal : carré ARRONDI (doctrine ① : --ds-rayon-avatar, jamais un rond) sur le fond neutre
   --ds-avatar-fond — le token créé au ①, ENFIN consommé — encre claire fixe --ds-avatar-encre. */
html.ideale-monde-saas .ideale-login-descripteur-tuile {
    width: var(--ds-avatar-tuile); height: var(--ds-avatar-tuile); flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--ds-rayon-avatar); background: var(--ds-avatar-fond); color: var(--ds-avatar-encre);
}
/* Logo d'entreprise du client (prompt 231) : carré arrondi, jamais rogné. */
html.ideale-monde-saas .ideale-login-descripteur-logo {
    width: auto; height: var(--ds-avatar-tuile); max-width: 132px; flex: 0 0 auto;
    object-fit: contain; border-radius: var(--ds-rayon-avatar);
}
/* AvatarHabille (identité du client) dans le descripteur : dimensionné à la tuile ; sa FORME (carré arrondi ①)
   et son dégradé d'habillage — le fond du client — restent INCHANGÉS (on ne fait que le dimensionner). */
html.ideale-monde-saas .ideale-login-descripteur .mud-avatar {
    width: var(--ds-avatar-tuile); height: var(--ds-avatar-tuile); font-size: 13px;
}

/* ---- Champs & bouton du formulaire ③ — surcharge TOKENISÉE, SCOPÉE au login (n'affecte ni Login.razor ni les
   autres POST natifs, qui gardent la base .ideale-form-field d'app.css). ---- */
html.ideale-monde-saas .ideale-ideal-login .ideale-form-label {
    margin: 14px 0 5px; font-weight: 600;
    font-size: var(--ds-champ-libelle-taille); color: var(--ds-champ-libelle);
}
html.ideale-monde-saas .ideale-ideal-login .ideale-form-field {
    height: var(--ds-champ-hauteur); padding: 8px 12px;
    border: 1px solid var(--ds-champ-bord); border-radius: var(--ds-champ-rayon);
    background: var(--ds-champ-fond); color: var(--ds-champ-texte); font-size: var(--ds-champ-texte-taille);
}
html.ideale-monde-saas .ideale-ideal-login .ideale-form-field:hover { border-color: var(--ds-border-strong); }
html.ideale-monde-saas .ideale-ideal-login .ideale-form-field:focus {
    outline: none; border-color: var(--ds-brand); box-shadow: var(--ds-focus-ring);
}
/* Champ mot de passe + bouton « œil » (afficher/masquer), ancré à droite dans le champ. */
html.ideale-monde-saas .ideale-ideal-login .ideale-login-champ-mdp { position: relative; }
html.ideale-monde-saas .ideale-ideal-login .ideale-login-champ-mdp .ideale-form-field { padding-right: 42px; }
html.ideale-monde-saas .ideale-ideal-login .ideale-login-oeil {
    position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: 0; cursor: pointer; color: var(--ds-champ-libelle);
}
html.ideale-monde-saas .ideale-ideal-login .ideale-login-oeil:focus-visible {
    outline: none; box-shadow: var(--ds-focus-ring); border-radius: var(--ds-r-sm);
}
/* Bouton « Se connecter » : PILULE, contraste le panneau formulaire (blanc sur sombre / foncé sur clair). */
html.ideale-monde-saas .ideale-ideal-login .ideale-login-bouton {
    display: inline-flex; align-items: center; justify-content: center;
    width: 100%; height: var(--ds-bouton-hauteur); margin-top: 20px;
    border: 0; border-radius: var(--ds-r-pill);
    background: var(--ds-bouton-fond); color: var(--ds-bouton-texte);
    font-family: var(--ds-font-ui); font-size: 13px; font-weight: 600; cursor: pointer;
    transition: filter .15s ease, transform .05s ease;
}
html.ideale-monde-saas .ideale-ideal-login .ideale-login-bouton:hover { filter: brightness(0.93); }
html.ideale-monde-saas .ideale-ideal-login .ideale-login-bouton:active { transform: translateY(1px); }
html.ideale-monde-saas .ideale-ideal-login .ideale-login-bouton:focus-visible { outline: none; box-shadow: var(--ds-focus-ring); }

/* ---- prefers-reduced-motion : avatar figé, message fixe, aucun mouvement ------------------------ */
@media (prefers-reduced-motion: reduce) {
    html.ideale-monde-saas .ideale-ideal-souffle,
    html.ideale-monde-saas .ideale-ideal-oeil,
    html.ideale-monde-saas .ideale-ideal-sourire,
    html.ideale-monde-saas .ideale-ideal-bulle--rebond .ideale-ideal-av--mini,
    html.ideale-monde-saas .ideale-ideal-caret { animation: none !important; }
    html.ideale-monde-saas .ideale-ideal-yeux { transition: none !important; }
}

/* =============================================================================================
   Vision UI Lot 3 (#285) — SHELL LATÉRAL « Pro · 2026 » (menu 1F). Scopé au MONDE SaaS (#203 :
   règles DUPLIQUÉES, jamais partagées ; jumeau dans app-locataire.css). Tokens du design system (--ds-*).
   ============================================================================================= */

/* ---- Conteneur du tiroir : plein hauteur, flyout autorisé à déborder du rail ---- */
html.ideale-monde-saas .ideal-drawer-shell .mud-drawer-content { height: 100%; padding: 0; overflow: visible; }
html.ideale-monde-saas .mud-drawer.ideal-drawer-shell { overflow: visible; }

/* ---- Aside : colonne pleine hauteur ---- */
html.ideale-monde-saas .ideal-shell {
    position: relative; display: flex; flex-direction: column; height: 100%;
    background: var(--ds-bg-surface); color: var(--ds-text);
    font-family: var(--ds-font-ui); letter-spacing: -0.006em;
}

/* ---- 1) En-tête : sélecteur d'espace + burger ---- */
html.ideale-monde-saas .ideal-shell-entete { flex: none; display: flex; align-items: center; gap: 6px; padding: 10px 10px 8px; }
html.ideale-monde-saas .ideal-shell--replie .ideal-shell-entete { justify-content: center; padding: 10px 6px 8px; }
html.ideale-monde-saas .ideal-espace {
    flex: 1; min-width: 0; display: flex; align-items: center; gap: 9px; padding: 8px 10px;
    background: var(--ds-bg-surface-2); border: 1px solid var(--ds-border); border-radius: var(--ds-r-md);
    cursor: pointer; text-align: left; color: inherit; transition: border-color .15s;
}
html.ideale-monde-saas .ideal-espace:hover { border-color: var(--ds-border-strong); }
html.ideale-monde-saas .ideal-espace-pastille {
    width: 26px; height: 26px; flex: none; border-radius: 7px; background: var(--ds-brand);
    color: var(--ds-text-on-brand); display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 800;
}
html.ideale-monde-saas .ideal-espace-texte { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; }
html.ideale-monde-saas .ideal-espace-nom { display: block; font-size: 12.5px; font-weight: 700; color: var(--ds-text-strong); text-overflow: ellipsis; overflow: hidden; }
html.ideale-monde-saas .ideal-espace-plan { display: block; font-size: 10.5px; color: var(--ds-text-muted); text-overflow: ellipsis; overflow: hidden; }
html.ideale-monde-saas .ideal-burger {
    width: 38px; height: 44px; flex: none; display: inline-flex; align-items: center; justify-content: center;
    background: var(--ds-bg-surface-2); border: 1px solid var(--ds-border); border-radius: var(--ds-r-md);
    color: var(--ds-text-muted); cursor: pointer; transition: border-color .15s, color .15s;
}
html.ideale-monde-saas .ideal-burger:hover { border-color: var(--ds-border-strong); color: var(--ds-text-strong); }
html.ideale-monde-saas .ideal-burger--rail { width: 44px; height: 38px; }

/* ---- Expansion au survol/focus (#305) : le menu complet en SURIMPRESSION au-dessus du contenu, PENDANT que
   le MudDrawer reste réduit (74 px) — le contenu de page ne bouge pas (aucun saut de layout). L'overlay
   s'appuie sur la chaîne overflow:visible du tiroir (ci-dessus) et les tokens du monde. Transition douce
   (opacité + léger glissement), coupée si l'utilisateur préfère réduire les animations. */
html.ideale-monde-saas .ideal-shell--etendu {
    position: absolute; top: 0; left: 0; height: 100%; width: 280px; z-index: 30;
    border-right: 1px solid var(--ds-border); box-shadow: var(--ds-shadow-lg);
    animation: ideal-shell-etendu-saas .16s ease;
}
@keyframes ideal-shell-etendu-saas { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
    html.ideale-monde-saas .ideal-shell--etendu { animation: none; }
}
/* #308 (recette) — pendant l'expansion en surimpression, le TIROIR passe AU-DESSUS de la bande basse fixe
   (.ideale-bas-fixe, z 1300). Pourquoi : MudBlazor décale cette bande de la largeur du TIROIR (74 px en rail,
   règle « .mud-drawer--closed ~ div ») et non de celle de l'overlay (280 px) ; la tranche x∈[74;280] du pied
   (« Aide ») passait donc SOUS la bande — rognée ET non cliquable (mesuré : elementFromPoint au centre du
   bouton renvoyait le copyright). Cran 1310 : au-dessus de la bande (1300), toujours SOUS les dialogues,
   popovers et snackbars MudBlazor (1400+). Rail et épinglé sont sains par construction (la bande démarre au
   bord du tiroir) : le cran ne s'applique QUE pendant l'overlay — aucune autre superposition modifiée. */
html.ideale-monde-saas .mud-drawer.ideal-drawer-shell:has(.ideal-shell--etendu) { z-index: 1310; }

/* ---- Séparateurs ---- */
html.ideale-monde-saas .ideal-shell-sep { flex: none; height: 1px; background: var(--ds-border-subtle); margin: 4px 12px; }

/* ---- 2) Navigation (déployée) ---- */
html.ideale-monde-saas .ideal-shell-nav { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 6px 10px 10px; }
html.ideale-monde-saas .ideal-shell--replie .ideal-shell-nav { padding: 6px 6px 10px; }
/* Libellé de section du menu : --ds-text-muted et NON --ds-text-subtle (PAL1). Ces libellés portent la
   STRUCTURE de navigation (« PLATEFORME », « ADMINISTRATION »…) = information → WCAG AA, que subtle échoue
   (3,01:1 en clair / 3,77:1 en sombre) — d'autant plus critique à 9,5 px. muted = 5,77:1 / 6,65:1. */
html.ideale-monde-saas .ideal-nav-section {
    font-family: var(--ds-font-mono); font-size: 9.5px; font-weight: 700; letter-spacing: .12em;
    color: var(--ds-text-muted); padding: 10px 8px 4px; text-transform: uppercase;
}
html.ideale-monde-saas .ideal-nav-item-hote { position: relative; }
html.ideale-monde-saas .ideal-nav-item {
    position: relative; display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 7px 9px; margin-bottom: 1px; border: 0; border-radius: var(--ds-r-sm); cursor: pointer;
    text-align: left; font-size: 13px; background: transparent; color: var(--ds-text);
    font-weight: 600; transition: background .12s, color .12s;
}
html.ideale-monde-saas .ideal-nav-item:hover { background: var(--ds-bg-hover); }
html.ideale-monde-saas .ideal-nav-item--n2, html.ideale-monde-saas .ideal-nav-item--n3 { font-size: 12.5px; font-weight: 500; color: var(--ds-text-muted); padding: 6px 9px; }
html.ideale-monde-saas .ideal-nav-item.actif { background: var(--ds-brand-subtle); color: var(--ds-brand-text); font-weight: 700; }
html.ideale-monde-saas .ideal-nav-item.actif::before {
    content: ""; position: absolute; left: -10px; top: 50%; transform: translateY(-50%);
    width: 3px; height: 17px; background: var(--ds-brand); border-radius: 0 3px 3px 0;
}
html.ideale-monde-saas .ideal-nav-item-icone { flex: none; }
html.ideale-monde-saas .ideal-nav-item-libelle { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.ideale-monde-saas .ideal-nav-item-badge {
    flex: none; background: var(--ds-bg-surface-3); color: var(--ds-text-muted); border-radius: var(--ds-r-xs);
    font-size: 10px; font-weight: 700; padding: 1px 6px; font-family: var(--ds-font-mono);
}
/* Raccourci clavier (Alt+1..5) : --ds-text-muted et NON --ds-text-subtle (PAL1) — un raccourci découvrable
   est une information, pas une décoration ; à 9,5 px, subtle (3,01:1) le rendait quasi illisible. */
html.ideale-monde-saas .ideal-nav-item-kbd {
    flex: none; font-family: var(--ds-font-mono); font-size: 9.5px; font-weight: 600; color: var(--ds-text-muted);
    border: 1px solid var(--ds-border); border-radius: 5px; padding: 1px 5px; background: var(--ds-bg-surface-2);
}
html.ideale-monde-saas .ideal-nav-item-chevron { flex: none; color: var(--ds-text-subtle); }
html.ideale-monde-saas .ideal-nav-item--verrou { color: var(--ds-text-subtle); cursor: not-allowed; opacity: .7; }
html.ideale-monde-saas .ideal-nav-enfants { margin: 1px 0 3px 19px; padding-left: 10px; border-left: 1px solid var(--ds-border); }

/* ---- 2 bis) Rail d'icônes (mode réduit) ---- */
html.ideale-monde-saas .ideal-rail { display: flex; flex-direction: column; align-items: center; gap: 4px; }
html.ideale-monde-saas .ideal-rail-item {
    position: relative; width: 46px; height: 44px; flex: none; display: flex; align-items: center;
    justify-content: center; border: 0; border-radius: 11px; cursor: pointer;
    background: transparent; color: var(--ds-text-muted); transition: background .12s, color .12s;
}
html.ideale-monde-saas .ideal-rail-item:hover { background: var(--ds-bg-hover); color: var(--ds-text-strong); }
html.ideale-monde-saas .ideal-rail-item.actif { background: var(--ds-brand-subtle); color: var(--ds-brand-text); }
html.ideale-monde-saas .ideal-rail-item.actif::before {
    content: ""; position: absolute; left: -11px; top: 50%; transform: translateY(-50%);
    width: 3px; height: 20px; background: var(--ds-brand); border-radius: 0 3px 3px 0;
}
html.ideale-monde-saas .ideal-rail-pastille {
    position: absolute; top: 6px; right: 8px; width: 7px; height: 7px; border-radius: var(--ds-r-pill);
    background: var(--ds-danger); border: 1.5px solid var(--ds-bg-surface);
}

/* (#305 : le flyout par groupe du mode réduit est REMPLACÉ par l'expansion en surimpression ci-dessus ; la
   carte « Conso IA » du pied a quitté le shell — côté SaaS l'information vit sur /plateforme/ia.) */

/* ---- 3) Pied : aide seule (#307 — carte profil remontée en barre du haut, indicateur de santé supprimé ;
        le pied ne porte plus que des liens de navigation, aucun bloc sans forme « rail » propre) ---- */
html.ideale-monde-saas .ideal-shell-pied { flex: none; padding: 6px 10px 10px; }
html.ideale-monde-saas .ideal-shell--replie .ideal-shell-pied { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 6px 6px 10px; }
/* (.ideal-pied-cloche / .ideal-pied-theme / --rail retirées au ③bis ; .ideal-pied-statut / .ideal-pied-profil*
   retirées au #307 : tout le contenu non-navigation du pied vit désormais dans la barre du haut.) */

/* Pilotage support (Vision UI 5F-2) — carte VEDETTE du taux résolu par l'IA : filet d'accent de marque qui la
   distingue des tuiles KPI voisines (§E2, hiérarchie). Remplace un « border-left: 4px solid var(--mud-palette-
   primary) » posé en Style inline : la couleur vient désormais du token de monde, clair ET sombre. Style de
   PAGE (.ideale-*) → feuille du monde SaaS scopée, jamais kit-ui.css qui est commun aux deux mondes. */
html.ideale-monde-saas .ideale-support-vedette { border-left: 4px solid var(--ds-brand); }

/* ======================================================================================================
   EXP-9d (B) — CHASSE AU GRIS · jumelles écrites SÉPARÉMENT (#203 : on duplique, on ne factorise pas).
   Ces règles descendent de la feuille COMMUNE app.css, où elles portaient une dette : le gris legacy
   --s-2 (#EBEEF4) était la seule teinte BLEUE du shell, hors famille sarcelle. Réparer dans la commune
   aurait masqué la dette #203 au lieu de la solder. Aucune valeur nouvelle : jetons existants.
   ====================================================================================================== */

/* Le champ de recherche de la barre : gris de la FAMILLE (--ds-bg-inset, 180°) au lieu du bleu legacy.
   Spécificité (0,4,1) > (0,3,0) d'app.css, et cette feuille est chargée APRÈS : la jumelle gagne. */
html.ideale-monde-saas .ideale-recherche-globale .mud-input.mud-input-outlined {
    background-color: var(--ds-bg-inset) !important;
}
/* En SOMBRE, --ds-bg-inset est très proche de la barre : sans filet, le champ n'aurait plus de contour du
   tout. On le lui rend au repos — le seul endroit du chantier où blanchir RETIRAIT de la lisibilité. */
html.ideale-monde-saas[data-theme="dark"] .ideale-recherche-globale .mud-input.mud-input-outlined {
    box-shadow: inset 0 0 0 1px var(--ds-border);
}

/* Décision ③ (9a) enfin appliquée au JUMEAU : le menu latéral en gris très doux, pour que le canevas blanc
   respire. Le locataire l'a depuis 9a (app-locataire.css) ; le scope y avait été volontairement restreint.
   ⚠️ Cette règle ÉCRASE par la CASCADE le `background` de la règle de base plus haut (même spécificité,
   déclarée après) : NE PAS « nettoyer » cette dernière en croyant supprimer un doublon — elle porte
   position/display/height/color/font, que cette surcharge ne redéclare pas. */
html.ideale-monde-saas .ideal-shell { background: var(--ds-bg-canvas); }
html.ideale-monde-saas[data-theme="dark"] .ideal-shell { background: var(--ds-bg-surface-2); }

/* ==========================================================================================================
   LANGAGE D'INTERACTION (#354, SL2) — LE CHÂSSIS S'EFFACE PENDANT QU'UNE BOÎTE EST OUVERTE.
   JUMEAU de app-locataire.css : même règle, deux feuilles, jamais partagée (#203).

   POURQUOI. Les tokens d'empilement du langage sont CONTRACTUELS et ne bougent pas : modale 1000,
   alerte 1100, toast 1200. Or le châssis de ce monde vit AU-DESSUS — mesuré au navigateur, sur le shell
   réel, au lot #354 : barre 1300, pied fixe 1300, bulle IDeal 1300, volet IDeal 1301, tiroir 1100 (1310
   déployé). Une boîte s'ouvrirait donc DERRIÈRE la barre et le menu. C'est le shell qui passe dessous, le
   temps de la boîte — jamais le langage qui monte.

   LA CLASSE EST POSÉE ET RETIRÉE PAR LE CYCLE DE VIE DE LA BOÎTE (BoiteModaleBase : ouverture, fermeture,
   ET DisposeAsync pour les chemins d'erreur), sur un ENSEMBLE de clés — une alerte posée sur un dialogue
   ne rend donc pas le shell en se fermant.

   ⚠️ CE QU'ON N'ABAISSE PAS, DÉLIBÉRÉMENT :
     · #components-reconnect-modal (9999, Blazor) — si le circuit tombe, il faut le dire PAR-DESSUS
       n'importe quelle boîte ; l'abaisser cacherait la seule information qui compte encore ;
     · .mud-popover (1201/1302) et .ideale-aide-bulle (1400) — ce sont les listes déroulantes, menus et
       bulles d'aide des champs QUI VIVENT DANS la boîte : ils doivent s'ouvrir au-dessus d'elle. Les champs
       restent MudBlazor jusqu'au SL3, donc ce comportement est celui qu'on veut (consigné au lot) ;
     · .mud-snackbar (1500) — un message système n'a pas à être masqué par une boîte.
   ========================================================================================================== */
html.ideale-monde-saas.li-boite-ouverte .mud-appbar,
html.ideale-monde-saas.li-boite-ouverte .mud-drawer,
html.ideale-monde-saas.li-boite-ouverte .mud-drawer.ideal-drawer-shell:has(.ideal-shell--etendu),
html.ideale-monde-saas.li-boite-ouverte .ideale-bas-fixe,
html.ideale-monde-saas.li-boite-ouverte .ideale-ideal-bulle,
html.ideale-monde-saas.li-boite-ouverte .ideale-ideal-volet {
    z-index: 900;
}

/* ----------------------------------------------------------------------------------------------------------
   … ET LA PILE DE TOASTS, ELLE, MONTE — PARCE QU'ELLE SURVIT À LA BOÎTE (STOP écran du pilote, 08/08/2026).
   JUMEAU de app-locataire.css : même règle, deux feuilles, jamais partagée (#203).

   LE DÉFAUT QUE CETTE RÈGLE RÉPARE, mesuré au navigateur sur les DEUX shells réels. L'abaissement ci-dessus
   est lié au cycle de vie de la BOÎTE. Le toast, lui, vit ≈ 6 s APRÈS elle. Il était donc parfaitement visible
   TANT QUE la boîte était ouverte, et repassait DERRIÈRE la barre à l'instant précis où elle se fermait —
   c'est-à-dire pendant TOUTE sa durée de vie utile. Mesure : pile à 1200, barre à 1300, 36 px du toast masqués
   sur 41 ; et « Annuler » n'était pas seulement illisible, il n'était pas ATTEIGNABLE (elementFromPoint rendait
   la barre : le clic partait dans le châssis).

   POURQUOI CE N'EST PAS COSMÉTIQUE. La révision de #244 a retiré la confirmation de mise à la corbeille EN
   ÉCHANGE d'un toast qui nomme le lieu de retour (§7 et §7 bis des standards UX). Un toast masqué, c'est une
   confirmation retirée SANS CONTREPARTIE.

   ÉCART D'IMPLÉMENTATION ASSUMÉ, ET CONSIGNÉ. Le token « --z-toast: 1200 » reste INCHANGÉ : il est contractuel
   DANS l'échelle du langage (menu 600 < contextuel 900 < modale 1000 < alerte 1100 < aperçu 1150 < toast 1200),
   et cet ordre RELATIF est intégralement préservé. Ce qui est ajouté ici est sa TRANSLATION dans l'échelle du
   PRODUIT — même nature d'écart que le scoping [data-li], et consigné au même titre.

   POURQUOI 1550 ET PAS UN AUTRE NOMBRE — les deux bornes sont MESURÉES, pas supposées :
     · PLANCHER — le châssis culmine à 1310 (tiroir déployé) ; barre, pied fixe et bulle IDeal 1300, volet 1301.
       S'y ajoutent, côté MudBlazor : dialogue 1400 et surtout SNACKBAR 1500. C'est l'incohérence relevée par le
       pilote — un message système MudBlazor était visible, le nôtre non. Le toast du langage passe donc AUSSI
       au-dessus du snackbar, qu'il a vocation à remplacer.
     · PLAFOND — infobulle MudBlazor 1600 (un survol volontaire doit rester lisible), puis, tout en haut,
       #components-reconnect-modal à 9999 : si le circuit tombe, il faut le dire PAR-DESSUS n'importe quel
       message. Le toast ne s'en approche jamais.

   ⛔ NE JAMAIS ajouter « .li-toasts » à la règle d'abaissement ci-dessus : ce serait exactement le défaut qu'on
   répare ici, réintroduit en croyant harmoniser. Tenu par T42 d'EmpilementLangage354Tests ; la visibilité
   elle-même est tenue par T41, qui mesure le rectangle du toast contre celui de la barre, dans les deux mondes,
   boîte ouverte PUIS boîte fermée.
   ---------------------------------------------------------------------------------------------------------- */
html.ideale-monde-saas .li-toasts {
    z-index: 1550;
}
