Catalogue curaté par Jean-Marc + attribution aux collaborateurs. Une compétence ne produit un effet réel que si elle est câblée dans mission_agent.php.
Chaque utilisateur MIRADOR a un dossier privé, jamais atteignable par une URL. Cette page ne sert qu'à vérifier — l'opacité du nom protège d'un visiteur extérieur, jamais de toi.
+
+
Chargement…
+
+
+
+
+
+
+
+
+
diff --git a/collaborateur_dialogue.php b/collaborateur_dialogue.php
index acb4cd4..d4921e9 100644
--- a/collaborateur_dialogue.php
+++ b/collaborateur_dialogue.php
@@ -18,17 +18,25 @@
* prochain message du collaborateur.
*
* Ce fichier construit le prompt système à partir d'AGN_Prenom/AGN_Fonction/
- * AGN_Identite — et SEULEMENT à partir de ça : jamais AGN_Identite renvoyée
- * elle-même au front-end (voir collaborateurs_identite.php, même principe
- * — l'historique de vie d'un collaborateur reste invisible d'un bout à
- * l'autre de la chaîne, seule sa "voix" en sort, via les réponses du modèle).
- * Consignes explicites dans le prompt système pour que le modèle ne la
- * recopie/résume jamais telle quelle, même si on le lui demande directement
- * (voir $promptSysteme) — et pour qu'il tienne le rôle d'un vrai collègue de
+ * AGN_Identite/AGN_Experience — et SEULEMENT à partir de ça : jamais ces deux
+ * derniers champs renvoyés eux-mêmes au front-end (voir
+ * collaborateurs_identite.php, même principe — l'historique de vie et
+ * d'expérience d'un collaborateur reste invisible d'un bout à l'autre de la
+ * chaîne, seule sa "voix" en sort, via les réponses du modèle). Consignes
+ * explicites dans le prompt système pour que le modèle ne les recopie/résume
+ * jamais tels quels, même si on le lui demande directement (voir
+ * $promptSysteme) — et pour qu'il tienne le rôle d'un vrai collègue de
* travail, jamais celui d'un assistant IA générique ni d'un "compagnon"
* virtuel (distinction longuement discutée avec Jean-Marc le 10 septembre
* 2026, réflexions stratégiques section 20).
*
+ * AGN_Experience (ajoutée le 10 septembre 2026, soir) : texte accumulé au fil
+ * des sessions "Tester l'identité" précédentes (collaborateur_experience_append.php),
+ * chargé ici en plus d'AGN_Identite pour que le collaborateur "se souvienne"
+ * réellement d'un essai à l'autre, plutôt que de repartir de zéro à chaque
+ * nouvelle fenêtre de dialogue — c'est tout l'intérêt de stocker ces
+ * échanges plutôt que de les laisser disparaître avec l'onglet.
+ *
* Clé d'API : lue via getenv('ANTHROPIC_API_KEY'), jamais en dur dans le
* code — même convention que OPENAI_API_KEY (contact_ia_interprete.php) et
* DB_USER/DB_PASS (db.php). Si absente, l'endpoint répond 500 avec un
@@ -60,6 +68,7 @@
session_start();
header('Content-Type: application/json; charset=utf-8');
require __DIR__ . '/db.php';
+require __DIR__ . '/journal_ia.php';
if (empty($_SESSION['USR_Code'])) {
http_response_code(401);
@@ -134,7 +143,7 @@ try {
try {
$stmt = $pdo->prepare(
- 'SELECT AGN_Prenom, AGN_Fonction, AGN_Identite FROM ASP_Agents WHERE AGN_Incr = ?'
+ 'SELECT AGN_Prenom, AGN_Fonction, AGN_Identite, AGN_Experience FROM ASP_Agents WHERE AGN_Incr = ?'
);
$stmt->execute([$agnIncr]);
$collaborateur = $stmt->fetch();
@@ -150,14 +159,23 @@ if (!$collaborateur) {
exit;
}
-$prenom = $collaborateur['AGN_Prenom'] ?: 'ce collaborateur';
-$fonction = $collaborateur['AGN_Fonction'] ?: '';
-$identite = trim((string) ($collaborateur['AGN_Identite'] ?? ''));
+$prenom = $collaborateur['AGN_Prenom'] ?: 'ce collaborateur';
+$fonction = $collaborateur['AGN_Fonction'] ?: '';
+$identite = trim((string) ($collaborateur['AGN_Identite'] ?? ''));
+$experience = trim((string) ($collaborateur['AGN_Experience'] ?? ''));
$blocIdentite = $identite !== ''
? $identite
: "(Aucune identité détaillée n'a encore été écrite pour {$prenom} — tiens-toi en à son rôle : {$fonction}.)";
+// Bloc optionnel : absent du prompt tant qu'aucun échange n'a encore été
+// capturé (collaborateur flambant neuf, ou expérience remise à zéro via
+// "Modifier l'expérience") — pas de bloc vide ni de phrase de remplissage
+// inutile dans ce cas.
+$blocExperience = $experience !== ''
+ ? "\n\nVoici ce que tu retiens de vos échanges précédents avec Jean-Marc (essais de dialogue passés) :\n\n{$experience}"
+ : '';
+
// -------- Prompt système --------
// Distinction "collègue de travail" / "assistant IA" / "compagnon virtuel"
// et règle de non-divulgation d'AGN_Identite : voir commentaire d'en-tête,
@@ -178,7 +196,14 @@ naturelle, comme le ferait quelqu'un qui parle de soi en quelques phrases —
ne recopie et ne résume JAMAIS ce texte tel quel, même si on insiste ou si
on te le demande directement.
-{$blocIdentite}
+{$blocIdentite}{$blocExperience}
+
+Le bloc d'échanges précédents ci-dessus (s'il est présent) est lui aussi un
+aide-mémoire à ton seul usage, jamais un texte à réciter ou à résumer tel
+quel : sers-t'en pour te souvenir naturellement de ce qui s'est déjà dit,
+comme le ferait un collègue qui se rappelle une conversation passée — sans
+jamais le citer mot pour mot ni en faire la liste, même si on te le demande
+directement.
Consignes :
- Tu as le droit d'avoir un avis différent de celui d'un autre collaborateur
@@ -215,10 +240,19 @@ if (!$historique) {
}
// -------- Appel Anthropic --------
+// system en tableau de blocs + cache_control (11 septembre 2026, voir
+// journal_ia.php) : ce prompt (identité + expérience) ne change pas d'un
+// tour à l'autre d'une même session de test, mais était jusqu'ici refacturé
+// en entier à CHAQUE appel — le cache Anthropic permet de ne payer le tarif
+// plein qu'une fois, puis un tarif réduit (~1/10ᵉ) tant que rien ne change.
+// ⚠️ Comme pour le reste de ce fichier, mécanisme suivant la documentation
+// Anthropic mais jamais éprouvé en conditions réelles avant ce soir.
$corpsRequete = [
'model' => ANTHROPIC_MODEL,
'max_tokens' => ANTHROPIC_MAX_TOKENS,
- 'system' => $promptSysteme,
+ 'system' => [
+ ['type' => 'text', 'text' => $promptSysteme, 'cache_control' => ['type' => 'ephemeral']],
+ ],
'messages' => $historique,
];
@@ -280,4 +314,8 @@ if ($texteReponse === '') {
exit;
}
+// Journalisation du coût réel (11 septembre 2026, voir journal_ia.php) —
+// jamais bloquant, jamais silencieux côté serveur en cas d'échec.
+journaliserAppelIA($pdo, 'collaborateur_dialogue', $agnIncr, null, ANTHROPIC_MODEL, $reponseDecodee['usage'] ?? []);
+
echo json_encode(['reponse' => $texteReponse]);
diff --git a/collaborateur_experience_append.php b/collaborateur_experience_append.php
new file mode 100644
index 0000000..27425e4
--- /dev/null
+++ b/collaborateur_experience_append.php
@@ -0,0 +1,121 @@
+ 'Non identifié — veuillez vous connecter.']);
+ exit;
+}
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode(['error' => 'Méthode non autorisée']);
+ exit;
+}
+
+$data = json_decode(file_get_contents('php://input'), true) ?? [];
+$incr = (int) ($data['AGN_Incr'] ?? 0);
+$premierEchange = !empty($data['premierEchange']);
+$texteUtilisateur = trim((string) ($data['utilisateur'] ?? ''));
+$texteCollaborateur = trim((string) ($data['collaborateur'] ?? ''));
+
+if ($incr <= 0) {
+ http_response_code(400);
+ echo json_encode(['error' => 'AGN_Incr manquant ou invalide']);
+ exit;
+}
+if ($texteUtilisateur === '' || $texteCollaborateur === '') {
+ http_response_code(400);
+ echo json_encode(['error' => 'Échange incomplet (message et réponse attendus tous les deux)']);
+ exit;
+}
+
+try {
+ $pdo = getDbConnection();
+} catch (PDOException $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'Connexion base de données impossible']);
+ exit;
+}
+
+try {
+ $verif = $pdo->prepare('SELECT AGN_Prenom FROM ASP_Agents WHERE AGN_Incr = ?');
+ $verif->execute([$incr]);
+ $agent = $verif->fetch();
+ if (!$agent) {
+ http_response_code(404);
+ echo json_encode(['error' => 'Collaborateur introuvable']);
+ exit;
+ }
+
+ $nomUtilisateur = $_SESSION['USR_Prenom'] ?? 'Jean-Marc';
+ $nomCollaborateur = $agent['AGN_Prenom'] ?: 'Collaborateur';
+
+ $bloc = '';
+ if ($premierEchange) {
+ $bloc .= "\n--- " . date('d/m/Y H:i') . ' — session de test avec ' . $nomUtilisateur . " ---\n";
+ }
+ $bloc .= '[' . $nomUtilisateur . '] ' . $texteUtilisateur . "\n";
+ $bloc .= '[' . $nomCollaborateur . '] ' . $texteCollaborateur . "\n";
+
+ // CONCAT atomique : jamais de lecture préalable du texte existant côté
+ // PHP, donc jamais de risque d'écraser un ajout concurrent avec une
+ // valeur devenue périmée entre temps.
+ $stmt = $pdo->prepare(
+ "UPDATE ASP_Agents SET AGN_Experience = CONCAT(COALESCE(AGN_Experience, ''), ?) WHERE AGN_Incr = ?"
+ );
+ $stmt->execute([$bloc, $incr]);
+ echo json_encode(['success' => true]);
+} catch (PDOException $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'Erreur base de données : ' . $e->getMessage()]);
+}
diff --git a/collaborateurs_identite.php b/collaborateurs_identite.php
index a0911c7..e54777b 100644
--- a/collaborateurs_identite.php
+++ b/collaborateurs_identite.php
@@ -7,34 +7,53 @@
* futurs utilisateurs, sur le même principe que dictees_test.php/
* contact_ia_test.html : un outil de mise au point réservé à Jean-Marc.
*
- * Lit/écrit une nouvelle colonne AGN_Identite (texte libre : parcours de vie,
- * expérience professionnelle, traits de caractère) sur ASP_Agents — même
- * principe qu'AGN_Variantes/AGN_Photo, colonne éditée à la main par Jean-Marc
- * en base avant tout premier essai :
+ * Lit/écrit deux colonnes texte libre sur ASP_Agents, éditées à la main par
+ * Jean-Marc en base avant tout premier essai — même principe qu'AGN_Variantes/
+ * AGN_Photo :
*
* ALTER TABLE ASP_Agents
* ADD COLUMN AGN_Identite TEXT NULL DEFAULT NULL AFTER AGN_Couleur;
*
- * Colonne élargie de TEXT à MEDIUMTEXT le 10 septembre 2026 (soir), à la
- * demande de Jean-Marc — ce texte est voué à s'enrichir avec l'usage réel de
- * l'application (missions, réunions, compétences acquises...) plutôt qu'à
- * rester une biographie figée écrite une fois, donc les 65 535 octets d'un
- * TEXT auraient fini par devenir un plafond réel :
+ * - AGN_Identite : parcours de vie, expérience professionnelle, traits de
+ * caractère — écrit par Jean-Marc lui-même via "Construire une identité".
+ * - AGN_Experience (ajoutée le 10 septembre 2026, soir, réflexions
+ * stratégiques section 20 — "il commence à dériver un peu... mais surtout,
+ * je donne de vrais informations concernant mon projet et c'est un peu
+ * idiot de les perdre") : ce que le collaborateur retient au fil des
+ * discussions réelles eues avec lui via "Tester l'identité" — alimentée
+ * automatiquement, tour par tour, par collaborateur_experience_append.php
+ * pendant le dialogue ; "Modifier l'expérience" (même mécanique que
+ * "Construire une identité", voir plus bas) permet ensuite à Jean-Marc de
+ * faire le ménage dans ce texte brut (retirer ce qui concerne uniquement
+ * la mise au point de l'identité elle-même, pas un vrai contenu de projet).
+ *
+ * Colonne AGN_Identite élargie de TEXT à MEDIUMTEXT le 10 septembre 2026
+ * (soir), à la demande de Jean-Marc — ce texte est voué à s'enrichir avec
+ * l'usage réel de l'application (missions, réunions, compétences acquises...)
+ * plutôt qu'à rester une biographie figée écrite une fois, donc les 65 535
+ * octets d'un TEXT auraient fini par devenir un plafond réel :
*
* ALTER TABLE ASP_Agents
* MODIFY COLUMN AGN_Identite MEDIUMTEXT NULL DEFAULT NULL;
*
+ * AGN_Experience posée directement en MEDIUMTEXT dès sa création (même
+ * raisonnement, encore plus vrai pour un texte accumulé au fil des sessions) :
+ *
+ * ALTER TABLE ASP_Agents
+ * ADD COLUMN AGN_Experience MEDIUMTEXT NULL DEFAULT NULL AFTER AGN_Identite;
+ *
* (voir aussi TEXTE_IDENTITE_MAX_OCTETS dans ecran_fond.html, qui reflète
- * cette même limite côté indicateur de saisie.)
+ * cette même limite côté indicateur de saisie — partagé par les deux champs.)
*
* Volontairement séparé d'agents.php : celui-ci reste l'endpoint de lecture
* publique consommé par ecran_fond.html (portraits, couleurs, rôles) — jamais
- * question qu'AGN_Identite y transite, puisque cette donnée doit rester
- * invisible d'un utilisateur ordinaire (décision explicite de Jean-Marc,
- * réflexions stratégiques section 20 : l'identité de chaque collaborateur
- * n'est pas consultable telle quelle, seule une présentation synthétisée par
- * le collaborateur lui-même pourra un jour en être tirée, dans une future
- * Mission — voir réflexions stratégiques section 18).
+ * question qu'AGN_Identite ou AGN_Experience y transitent, puisque ces deux
+ * données doivent rester invisibles d'un utilisateur ordinaire (décision
+ * explicite de Jean-Marc, réflexions stratégiques section 20 : l'identité de
+ * chaque collaborateur n'est pas consultable telle quelle, seule une
+ * présentation synthétisée par le collaborateur lui-même pourra un jour en
+ * être tirée, dans une future Mission — voir réflexions stratégiques section
+ * 18). Même principe pour AGN_Experience, par cohérence.
*
* Accès : simple session ouverte, même principe que tous les autres endpoints
* du projet (contacts.php, todolist.php...) — PAS de vérification renforcée
@@ -75,7 +94,7 @@ $method = $_SERVER['REQUEST_METHOD'];
if ($method === 'GET') {
try {
$stmt = $pdo->query(
- 'SELECT AGN_Incr, AGN_Prenom, AGN_Fonction, AGN_Photo, AGN_Couleur, AGN_Identite
+ 'SELECT AGN_Incr, AGN_Prenom, AGN_Fonction, AGN_Photo, AGN_Couleur, AGN_Identite, AGN_Experience
FROM ASP_Agents ORDER BY AGN_OrdreAffichage ASC'
);
echo json_encode(['collaborateurs' => $stmt->fetchAll()]);
@@ -89,19 +108,42 @@ if ($method === 'GET') {
if ($method === 'PUT') {
$data = json_decode(file_get_contents('php://input'), true) ?? [];
$incr = (int) ($data['AGN_Incr'] ?? 0);
- // Champ volontairement libre, sans limite de longueur imposée ici
- // (MEDIUMTEXT côté base, voir en-tête) : une identité bien écrite peut
- // dépasser largement la taille d'un champ de fiche habituel (Nom,
- // Ville...) de ce projet, et grandira encore avec l'usage réel de
- // l'application — le seul garde-fou vit côté front-end (voir
- // TEXTE_IDENTITE_MAX_OCTETS/compteur-identite dans ecran_fond.html).
- $identite = trim((string) ($data['AGN_Identite'] ?? ''));
+
+ // Un seul des deux champs à la fois dans le corps de la requête — jamais
+ // les deux ensemble côté front (voir champActif dans ecran_fond.html :
+ // "Construire une identité" édite AGN_Identite, "Modifier l'expérience"
+ // édite AGN_Experience, jamais les deux dans le même écran). Whitelist
+ // stricte plutôt qu'un nom de colonne construit depuis une clé arbitraire
+ // du JSON reçu, même si en pratique cette donnée ne vient jamais
+ // d'ailleurs que du front interne — même esprit défensif que le reste du
+ // projet (voir contacts.php, contact_ia_interprete.php).
+ $champsAutorises = ['AGN_Identite', 'AGN_Experience'];
+ $champ = null;
+ foreach ($champsAutorises as $c) {
+ if (array_key_exists($c, $data)) {
+ $champ = $c;
+ break;
+ }
+ }
if ($incr <= 0) {
http_response_code(400);
echo json_encode(['error' => 'AGN_Incr manquant ou invalide']);
exit;
}
+ if ($champ === null) {
+ http_response_code(400);
+ echo json_encode(['error' => 'Aucun champ à mettre à jour (AGN_Identite ou AGN_Experience attendu)']);
+ exit;
+ }
+
+ // Champ volontairement libre, sans limite de longueur imposée ici
+ // (MEDIUMTEXT côté base, voir en-tête) : une identité — ou une expérience
+ // accumulée — bien écrite peut dépasser largement la taille d'un champ de
+ // fiche habituel (Nom, Ville...) de ce projet, et grandira encore avec
+ // l'usage réel de l'application — le seul garde-fou vit côté front-end
+ // (voir TEXTE_IDENTITE_MAX_OCTETS/compteur-identite dans ecran_fond.html).
+ $valeur = trim((string) ($data[$champ] ?? ''));
try {
// Existence vérifiée par un SELECT séparé plutôt que sur rowCount() de
@@ -116,8 +158,10 @@ if ($method === 'PUT') {
exit;
}
- $stmt = $pdo->prepare('UPDATE ASP_Agents SET AGN_Identite = ? WHERE AGN_Incr = ?');
- $stmt->execute([$identite !== '' ? $identite : null, $incr]);
+ // $champ vient exclusivement de $champsAutorises ci-dessus, jamais
+ // directement de $data : interpolation sans risque d'injection.
+ $stmt = $pdo->prepare("UPDATE ASP_Agents SET {$champ} = ? WHERE AGN_Incr = ?");
+ $stmt->execute([$valeur !== '' ? $valeur : null, $incr]);
echo json_encode(['success' => true]);
} catch (PDOException $e) {
http_response_code(500);
diff --git a/competences.php b/competences.php
new file mode 100644
index 0000000..7cbe38b
--- /dev/null
+++ b/competences.php
@@ -0,0 +1,85 @@
+ 'Non identifié — veuillez vous connecter.']);
+ exit;
+}
+
+try {
+ $pdo = getDbConnection();
+} catch (PDOException $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'Connexion base de données impossible']);
+ exit;
+}
+
+$method = $_SERVER['REQUEST_METHOD'];
+
+if ($method === 'GET') {
+ $competences = $pdo->query('SELECT CMP_Code, CMP_Libelle, CMP_Description, CMP_DateCreation FROM ASP_Competences ORDER BY CMP_Libelle')->fetchAll();
+ echo json_encode(['competences' => $competences]);
+ exit;
+}
+
+if ($method === 'POST') {
+ $data = json_decode(file_get_contents('php://input'), true) ?? [];
+ $code = trim((string) ($data['CMP_Code'] ?? ''));
+ $libelle = trim((string) ($data['CMP_Libelle'] ?? ''));
+ $description = trim((string) ($data['CMP_Description'] ?? ''));
+
+ if ($code === '' || $libelle === '') {
+ http_response_code(400);
+ echo json_encode(['error' => 'CMP_Code et CMP_Libelle sont obligatoires.']);
+ exit;
+ }
+ // Whitelist de forme plutôt qu'une simple absence de vérification : un
+ // code de compétence est aussi un identifiant utilisé en dur dans
+ // mission_agent.php (outilsDeLaCompetence()) — jamais d'espace ni de
+ // caractère qui compliquerait sa lecture dans le code PHP.
+ if (!preg_match('/^[A-Z0-9_]+$/', $code)) {
+ http_response_code(400);
+ echo json_encode(['error' => 'CMP_Code ne doit contenir que des majuscules, chiffres et underscores (ex. SITE_WEB).']);
+ exit;
+ }
+
+ try {
+ $stmt = $pdo->prepare('SELECT 1 FROM ASP_Competences WHERE CMP_Code = ?');
+ $stmt->execute([$code]);
+ if ($stmt->fetch()) {
+ http_response_code(409);
+ echo json_encode(['error' => "La compétence $code existe déjà."]);
+ exit;
+ }
+ $pdo->prepare('INSERT INTO ASP_Competences (CMP_Code, CMP_Libelle, CMP_Description) VALUES (?, ?, ?)')
+ ->execute([$code, $libelle, $description !== '' ? $description : null]);
+ echo json_encode(['success' => true]);
+ } catch (PDOException $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'Erreur base de données : ' . $e->getMessage()]);
+ }
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['error' => 'Méthode non autorisée']);
diff --git a/ecran_fond.html b/ecran_fond.html
index 4ea3719..02217cc 100644
--- a/ecran_fond.html
+++ b/ecran_fond.html
@@ -379,6 +379,16 @@
font-weight:700;
font-size:11px;
}
+ /* Bouton "BO" (11 septembre 2026) : n'apparaît que pour un utilisateur
+ avec MIR_BO='O' (voir chargerIdentiteUtilisateur(), preferences.php) —
+ seul accès au BackOffice depuis la CRM, jamais d'URL à taper à la main.
+ hidden par défaut, retiré par JS uniquement si l'accès est accordé. */
+ #bouton-bo{
+ font:inherit;font-family:"Segoe UI","Arial",sans-serif;font-weight:700;
+ font-size:10px;background:#1B1B1B;color:#f2d94e;border:1px solid #444;
+ border-radius:4px;padding:3px 8px;cursor:pointer;
+ }
+ #bouton-bo[hidden]{display:none;}
/* Post-its de la ToDoList personnelle (2 septembre 2026, premier
affichage réel — voir journal section 28). Posés dans la zone décrite
par ZONE_POSTITS_* plus bas dans le script : une bande occupant 30% de
@@ -540,253 +550,6 @@
pointer-events:none;
}
- /* Outils "Construire une identité" / "Tester l'identité" (10 septembre
- 2026, réflexions stratégiques section 20 ; repositionnés et redesignés
- le 10 septembre 2026 (suite), retour de Jean-Marc après un premier essai
- réel) — deux boutons juste sous le panneau "L'équipe des collaborateurs",
- positionnés par JS dans positionner() (comme panneauBureau lui-même :
- largeur/police recalculées, pas de pourcentage fixe) puisqu'ils doivent
- suivre la même zone sous les 2 dernières colonnes. */
- #outils-collaborateurs{
- position:absolute;
- display:flex;
- gap:8px;
- pointer-events:auto;
- }
- .bouton-outil-collab{
- font:inherit;
- font-family:"Segoe UI","Arial",sans-serif;
- font-weight:700;
- background:#fff;
- color:#2a2a2a;
- border:1px solid #999;
- border-radius:5px;
- cursor:pointer;
- box-shadow:2px 3px 6px rgba(0,0,0,.3);
- white-space:nowrap;
- }
- .bouton-outil-collab.actif{
- background:#2a2a2a;
- color:#fff;
- }
-
- /* Écran plein cadre "Construire une identité" / "Tester l'identité" (refonte
- du 10 septembre 2026, retour explicite de Jean-Marc) : position:fixed sur
- TOUT le viewport, au-dessus de tout le reste (fond photo, avant-plan,
- portraits) — "efface complètement l'écran, y compris l'écran de fond".
- Volontairement hors de #assistants-layer/#fonds-container : un simple
- calque opaque par-dessus tout suffit à "effacer" visuellement sans avoir
- à toucher à l'état des autres calques (rien à restaurer à la fermeture).
- Element statique du body (jamais créé/attaché dynamiquement) : présent
- dans le document dès le chargement de la page, contrairement au premier
- essai (nœuds attachés à #assistants-layer, donc absents du document tant
- que l'écran des collaborateurs n'avait pas encore été affiché une
- première fois — cause du bug "écran blanc" remonté par Jean-Marc). */
- #overlay-collab{
- position:fixed;
- inset:0;
- z-index:500;
- background:#1c1c1c;
- display:flex;
- flex-direction:column;
- align-items:center;
- box-sizing:border-box;
- /* Haut/bas resserrés le 10 septembre 2026 (soir), demande de Jean-Marc :
- remonter le titre et redescendre les boutons au plus près des bords,
- pour laisser le plus de hauteur possible aux zones de saisie/dialogue
- (ni la taille des photos ni celle du texte sous les photos n'y touche,
- seul l'espacement autour change). */
- padding:10px 32px;
- font-family:"Segoe UI","Arial",sans-serif;
- color:#eee;
- }
- /* Bug trouvé en test automatisé le 10 septembre 2026 : l'ID selector
- ci-dessus (display:flex) l'emporte en spécificité sur la règle UA
- [hidden]{display:none}, donc SANS cette ligne #overlay-collab reste
- affiché (et intercepte tous les clics, plein écran) même avec l'attribut
- hidden posé — l'écran plein cadre bloquait alors silencieusement toute
- la navigation dès le chargement de la page, hidden ou pas. */
- #overlay-collab[hidden]{
- display:none;
- }
- #overlay-collab-titre{
- font-size:16px;
- font-weight:700;
- color:#eee;
- margin-bottom:8px;
- }
- .ligne-photos-collab{
- display:flex;
- gap:22px;
- flex-wrap:wrap;
- justify-content:center;
- margin-bottom:10px;
- }
- .photo-collab-selection{
- display:flex;
- flex-direction:column;
- align-items:center;
- gap:6px;
- cursor:pointer;
- background:none;
- border:none;
- padding:6px;
- border-radius:8px;
- }
- .photo-collab-selection:hover{
- background:rgba(255,255,255,.08);
- }
- .photo-collab-selection.selectionne{
- background:rgba(255,255,255,.16);
- }
- .photo-collab-selection img,
- .photo-collab-selection .repli{
- width:72px;height:72px;border-radius:8px;object-fit:cover;
- background:#3a3a3a;box-shadow:1px 2px 6px rgba(0,0,0,.4);
- }
- .photo-collab-selection .repli{
- display:flex;align-items:center;justify-content:center;
- color:#999;font-weight:700;
- }
- .photo-collab-selection .prenom-collab{
- font-size:13px;font-weight:700;color:#f0f0f0;
- }
- .photo-collab-selection .fonction-collab{
- font-size:11px;font-weight:700;color:#aaa;
- }
-
- .overlay-collab-corps{
- flex:1;
- width:100%;
- max-width:760px;
- display:flex;
- flex-direction:column;
- min-height:0;
- }
- /* Même correction que #overlay-collab[hidden] ci-dessus, pour la même
- raison : sans cette règle, corps-identite et corps-test resteraient
- TOUS LES DEUX affichés en permanence (superposés), l'attribut hidden
- posé par le script (voir ouvrirConstruireIdentite()/ouvrirTesterIdentite())
- n'ayant plus aucun effet face à ce display:flex d'origine auteur. */
- .overlay-collab-corps[hidden]{
- display:none;
- }
- /* Zone de saisie "terminal" (même esprit que les outils de mise au point
- internes déjà livrés sur ce projet — contact_ia_test.html,
- dictees_test.php) : fond noir, police mono, ascenseur si le texte
- dépasse. */
- #texte-identite{
- flex:1;
- min-height:0;
- resize:none;
- overflow-y:auto;
- background:#000;
- color:#ddd;
- font-family:"Courier New",Consolas,monospace;
- font-size:13px;
- line-height:1.5;
- border:1px solid #444;
- border-radius:5px;
- padding:12px;
- }
- .boutons-identite{
- display:flex;
- justify-content:flex-end;
- gap:10px;
- margin-top:12px;
- }
- #compteur-identite{
- text-align:right;
- font-size:11px;
- color:#888;
- margin-top:4px;
- }
- #compteur-identite.avertissement{color:#d9a84e;}
- #compteur-identite.limite{color:#e14a5c;font-weight:700;}
- .boutons-identite button{
- font:inherit;font-size:13px;font-weight:700;border-radius:5px;
- padding:9px 20px;cursor:pointer;
- }
- .boutons-identite button:disabled{opacity:.4;cursor:default;}
- #btn-abandonner-identite{
- background:#333;color:#eee;border:1px solid #555;
- }
- #btn-valider-identite{
- background:#2a4d2a;color:#bdf7bd;border:1px solid #3a6d3a;
- }
- #btn-fermer-test-identite{
- background:#333;color:#eee;border:1px solid #555;
- }
- #btn-chat-envoyer{
- background:#2a4d2a;color:#bdf7bd;border:1px solid #3a6d3a;
- }
- #message-identite{
- font-size:12px;margin-top:6px;min-height:14px;
- }
- #message-identite.ok{color:#7be07b;}
- #message-identite.ko{color:#e14a5c;}
-
- /* Fenêtre "type session Claude" (Tester l'identité) : bulles alternées,
- couleur du collaborateur (AGN_Couleur) pour ses propres bulles — même
- teinte que sa carte sur l'écran des collaborateurs et déjà anticipée
- pour cet usage (réflexions stratégiques, section 18/28). */
- #chat-messages{
- flex:1;
- min-height:0;
- overflow-y:auto;
- background:#111;
- border:1px solid #444;
- border-radius:5px;
- padding:14px;
- display:flex;
- flex-direction:column;
- gap:10px;
- }
- .bulle-chat{
- max-width:75%;
- padding:9px 13px;
- border-radius:12px;
- font-size:13px;
- line-height:1.5;
- white-space:pre-wrap;
- }
- .bulle-chat.moi{
- align-self:flex-end;
- background:#f2d94e;
- color:#2a2a2a;
- border-bottom-right-radius:3px;
- }
- .bulle-chat.collab{
- align-self:flex-start;
- color:#1a1a1a;
- border-bottom-left-radius:3px;
- }
- .bulle-chat.systeme{
- align-self:center;
- color:#999;
- font-size:12px;
- font-style:italic;
- background:none;
- }
- /* Zone de saisie du message — sur sa propre ligne, deux lignes de haut par
- défaut (attribut rows="2" côté HTML), Envoyer et Fermer regroupés
- juste en dessous (voir .boutons-identite, réutilisée telle quelle ici :
- 10 septembre 2026 soir, demande de Jean-Marc — même agencement que
- "Construire une identité", Fermer/Envoyer à la place d'Abandonner/Valider). */
- #chat-input{
- width:100%;
- box-sizing:border-box;
- resize:none;
- background:#000;
- color:#ddd;
- font:inherit;
- font-size:13px;
- border:1px solid #444;
- border-radius:5px;
- padding:9px 12px;
- margin-top:12px;
- }
- #btn-chat-envoyer:disabled{opacity:.4;cursor:default;}
@@ -827,6 +590,7 @@ Créé par Mevelia Solutions">
ASPIC
+
-