Compare commits

...

42 Commits

Author SHA1 Message Date
0b818414ed Restaure index.html supprime par erreur, avec les masquages
Le commit precedent avait supprime index.html au lieu de le modifier.
Ce commit le retablit dans son integralite (429 lignes) avec le
display:none sur la documentation et les rapports de veille.
2026-07-21 08:31:08 +02:00
f027dfcf4c Masque provisoirement la documentation et les rapports de veille
Ajoute display:none aux liens de navigation, aux boutons du hero et aux
deux sections #documentation et #rapports. Le contenu reste dans le code
pour un reaffichage ulterieur.
2026-07-21 08:29:55 +02:00
34216a52f9 Fusion de exos-rework dans main
Retravaille le TP Nuisibles : inversion accueil/identification, style
BioCID, navigation regroupee dans la bottom bar, boutons d'action
simplifies et encadres finaux recentres.

# Conflicts:
#	.gitignore
2026-07-21 08:24:27 +02:00
f611bdcd7e Recentre les encadres TP1/TP2/TP3 de la slide finale
Passe la marge de .final-grid de 1.5rem 0 a 1.5rem auto pour centrer la
grille des trois travaux pratiques.
2026-07-21 08:22:29 +02:00
f7c846c85c Simplifie les boutons d'action du TP Nuisibles
Slide 1 : retire le bouton "Corriger un rendu", l'ecran de contexte ne
garde que l'identification. Slide 13 : ne conserve que Telecharger le PDF,
Corriger un rendu et Recommencer, aligne sur le style BioCID (PDF plein
ambre, deux boutons contour) et retire le lien biocid-anses.fr.
2026-07-21 08:20:13 +02:00
a74df51201 Migre la navigation du TP Nuisibles dans la bottom bar
Reprend le modele de footer d'Exo_BioCID : tous les boutons d'avancement
et d'aide passent dans la barre du bas, pilotes par un slideConfig
(bouton suivant, libelle, indice par slide). Supprime les boutons
in-slide correspondants, gere la validation du nom de groupe et le
deverrouillage du bouton apres choix du cas, et applique le style
footer-btn (compteur a gauche, actions centrees).
2026-07-21 08:16:05 +02:00
42650ca351 Aligne le TP Nuisibles sur le style des autres exercices
Inverse l'accueil et l'identification (héro en slide 0, contexte et
identification du groupe en slide 1), applique le style BioCID aux deux
premieres slides et supprime le badge d'avancement en haut a droite,
redondant avec la barre de progression.
2026-07-21 08:10:09 +02:00
21a7359057 Retravaille l'exercice FDS : étiquette libre et corrigé déplacé
- Slide 5 (FT) : reformule la question sur le type de produit en « Où se
  trouve la liste des TP (type de produit) ? »
- Slide 7 : l'utilisateur peut désormais cliquer n'importe quelle zone,
  même incorrecte ; le clic est enregistré et l'exercice avance.
- Slide 7 : « Terminer l'exercice » mène directement à la synthèse ; le
  récapitulatif « l'étiquette annotée » quitte le déroulé des slides.
- Déplace ce récapitulatif (étiquette annotée + check-list réglementaire)
  vers corriger-exercice.html, en corrigé de référence du rendu FDS.
2026-07-21 08:01:12 +02:00
6bb7985512 Uniformise l'identification du groupe sur BioCID et TP Nuisibles
Applique le style de carte de référence (Exo_FDS) à ExoBIOCID et au TP
Nuisibles : titre dans la carte, champs nom/date, et sélecteur de
formateur Nathan/Gauthier en boutons remplis à l'état actif, à la place
du champ texte libre (BioCID) et des boutons pilule (TP).
2026-07-21 07:46:15 +02:00
090cbc19a2 Aligne les deux premières slides du TP Nuisibles sur BioCID
Les slides 1 et 2 reprennent la présentation des slides BioCID :
étiquette de section, titre, introduction et encadré d'information.
La slide 1 abandonne le bloc héro au profit de ce gabarit, la slide 2
gagne un encadré rappelant que le cas choisi vaut pour tout le TP.

La règle .info-card, absente de ce fichier, est reprise de BioCID.
Aucun champ ni contenu déplacé, numérotation des slides inchangée.
2026-07-20 21:12:56 +02:00
794ae69fa0 Ajoute une slide d'introduction à l'exercice 1 de BioCID
L'exercice 1 s'ouvre désormais sur une slide de présentation calquée
sur celles de l'exercice FDS : cercle décoratif, étiquette de section,
titre avec emoji, texte d'introduction et encadré d'information.

Les slides suivantes sont décalées d'un rang (2 à 6 deviennent 3 à 7),
le compteur passe à 7 étapes et les confettis se déclenchent sur la
nouvelle slide finale. Les questions et leurs champs sont inchangés.
2026-07-20 21:12:56 +02:00
88b075fb88 Bloque les fichiers ne correspondant pas à l'exercice choisi
Chaque exercice dispose désormais d'une signature propre, basée sur
l'en-tête du PDF qu'il exporte. La fonction detectExercise identifie
l'exercice réellement contenu dans le fichier déposé (signature d'abord,
sentinelle en secours).

Si le PDF correspond à un autre exercice que celui sélectionné, un
message d'incompatibilité nommant les deux exercices s'affiche et la
correction n'est pas générée.
2026-07-20 20:51:23 +02:00
b5f2eac842 Sauvegarde les réponses de BioCID et du TP Nuisibles
Les réponses saisies sont désormais enregistrées dans le navigateur au fil
de la frappe, sous une clé propre à chaque exercice. Un rechargement ne les
perd plus.

Au chargement, rien n'est restauré d'office : un bandeau signale les
réponses retrouvées avec leur date et propose « Restaurer » ou « Repartir
de zéro ». Sur un poste de formation partagé, un nouveau groupe ne démarre
donc jamais sur le travail du précédent.

Sont restaurés les champs d'identification, les réponses, la position dans
le diaporama et, pour le TP, le tableau de risques (lignes ajoutées
recréées avant remplissage), le cas pratique choisi et le formateur.

L'avertissement avant rechargement est conservé comme second filet. Les
accès à localStorage sont protégés : en navigation privée ou en file://
sous Safari, la page fonctionne normalement, sans sauvegarde.

FDS reste à traiter : ses réponses ne vivent pas dans des champs de
formulaire mais dans l'état des zones de dépôt, des liaisons et de
l'étiquette, ce qui demande une logique de réaffichage dédiée.
2026-07-20 20:44:47 +02:00
a42957ad41 Avertit avant la perte des réponses sur les trois TD
Les réponses saisies dans les exercices ne sont pas enregistrées : un
rechargement ou une navigation les efface sans prévenir.

Ajoute sur BioCID, FDS et TP Nuisibles un indicateur de saisie et un
gestionnaire beforeunload : dès qu'une réponse a été renseignée, le
navigateur demande confirmation avant de recharger ou de quitter la page.
Aucune alerte tant que rien n'a été saisi.

Sur FDS, les parties glisser-déposer, liaisons FT et zones cliquables de
l'étiquette ne produisent pas d'événement input : elles signalent la
saisie explicitement. Même chose pour le choix du cas pratique du TP.

Note : le texte affiché dans la boîte de dialogue est imposé par le
navigateur et n'est pas personnalisable.
2026-07-20 20:36:19 +02:00
421ae4c2bf Unifie la correction des exercices en une page unique
La page de correction ne réagissait pas au dépôt d'un PDF : elle encodait
le fichier en base64 dans localStorage puis redirigeait vers une page
dédiée censée le relire. Ce relais échoue en file://, qui est le mode
d'ouverture habituel des pages.

corriger-exercice.html devient autonome : sélection de l'exercice, dépôt
du PDF et affichage des réponses se font sur place, sans localStorage ni
redirection. Les trois parseurs (BioCID, FDS, TP Nuisibles) sont regroupés
derrière un format commun avec carrousel exercice par exercice, bandeau
participants, correction chiffrée pour la partie FDS et annexe TP3.

Ajoute un garde-fou signalant un PDF ne correspondant pas à l'exercice
sélectionné, repointe les boutons « Corriger » de Exo_FDS et TP_Nuisibles
vers la page unifiée, et supprime les trois pages de correction dédiées
devenues sans référence.
2026-07-20 20:30:16 +02:00
affa042c05 Aligne les slides d'intro et la bottom bar sur le modèle BioCID
- FDS : bottom bar refaite façon BioCID (84 px, compteur à gauche, boutons pilule centrés en style footer-btn, bouton retour intégré, masquée sur l'accueil)
- FDS : bouton "Démarrer le TD" remis dans la slide d'accueil et 2e cercle déco passé en ambre
- TP_Nuisibles : formulaire d'identification encadré dans une carte blanche comme la carte identité BioCID
2026-07-19 18:17:56 +02:00
30817c829b Retravaille l'exercice FDS : boutons, étiquette et récapitulatif
- index : emoji de la carte "Corriger un exercice" ✔️
- Boutons de toutes les slides centralisés et uniformisés dans la bottom bar
- Slide 1 : encadré "Durée 30 min" remonté au-dessus des trois parties
- Slides 3 et 5 : suppression du bouton "Vérifier mes réponses" et blocage du passage à la partie suivante tant que tout n'est pas rempli/relié
- Slide 7 : bouton "Terminer l'exercice" (ex "Voir le récapitulatif") réparé, faux pictogrammes remplacés par les vraies images SGH, volet de correction de droite et encadré de résultats supprimés
- Slide 8 : encadrés 💡 retirés, boutons déplacés sous le tableau comparatif, bouton "Retour aux exercices" supprimé
- Confettis déplacés de la slide 6 vers la slide 8
2026-07-19 17:59:02 +02:00
41d8b98f96 Ajuste les slides 1 et 5 de l'exercice BioCID
- Slide 1 : encadrés '4 exercices' et 'Plateforme BioCID' inversés et mis à la même largeur
- Slide 1 : passage à l'exercice 1 bloqué tant que le nom du groupe n'est pas renseigné (message d'alerte)
- Slide 5 : titre 'Mise en situation réelle' -> 'Mise en situation'
- Slide 5 : reformulation de la mise en situation (restaurant / choix entre plusieurs références)
- Slide 5 : bouton 'Voir les bonnes pratiques' -> 'Terminer l'exercice'
2026-07-19 17:15:34 +02:00
d251782842 Ajoute une page unique de correction des exercices
- Nouvelle page corriger-exercice.html : sélection de l'exercice (BioCID, FDS, TP Nuisibles) + zone de dépôt PDF
- Le PDF déposé est transmis à la page de correction dédiée qui se charge automatiquement (?auto=1)
- Carte 'Corriger un exercice' ajoutée à la section Exercices de l'index
- Slide 6 BioCID : suppression du bouton biocid-anses.fr, alignement des boutons Télécharger / Corriger / Recommencer
- Le bouton 'Corriger un rendu' redirige vers la nouvelle page
2026-07-19 17:08:59 +02:00
66ed3c505f Uniformise les boutons du footer BioCID et ajoute des confettis
- Bouton 'Commencer l'exercice 1' déplacé de la slide 1 vers la bottom bar
- Nouveau style .footer-btn uniforme pour les trois boutons (is-primary / is-secondary)
- Effet de confettis au canvas déclenché à l'arrivée sur la slide 6 (comme le TP Nuisibles)
2026-07-19 16:53:32 +02:00
543bb6cd52 Retravaille le footer de l'exercice BioCID
- Footer agrandi (84px) avec les trois boutons Retour, Voir les indications et Exercice suivant centrés
- Boutons d'indications et de navigation déplacés du corps des slides vers le footer
- Suppression du badge 'Exercice .../4' en haut à droite (doublon)
- Slide 3 : simplification du texte des filtres (par TP)
2026-07-19 16:48:40 +02:00
a2a4fea004 Retravaille les exercices FDS/FT/Étiquettes (slides 1, 3, 5, 7)
Slide 1 : blocage de la navigation tant que le nom du stagiaire/groupe n'est pas renseigné, et choix du formateur via boutons Nathan/Gauthier.
Slide 3 : étiquettes renommées « Rubrique 1…16 » (au lieu de « R… ») et élargies.
Slide 5 : suppression du tag « Partie 2/3 — FT ».
Slide 7 : suppression du tag « Partie 3/3 — Étiquette » ; l'encadré de réponse s'affiche à côté de l'étiquette (plus en superposition) ; le récapitulatif fait glisser l'étiquette à gauche et affiche le tableau de réponses à sa droite.
2026-07-17 17:50:22 +02:00
8164b03cc4 Refonte du rapport de veille Certibiocide semaine 28
Enrichit et restructure le rapport HTML de la semaine 28 (06-12 juillet 2026).
2026-07-17 17:03:57 +02:00
d351ee6efb Refonte de la slide 7 FDS en étiquette cliquable (hotspots)
Remplace les menus déroulants de la partie Étiquette par une étiquette
DÉS'INFECT reconstituée (Annexe I du guide FHER) avec 9 zones cliquables :
info-bulle de justification réglementaire au clic, états visuels
correct/incorrect, mise en situation professionnelle en introduction,
et écran de synthèse sur le modèle de la check-list FHER p.15
(étiquette annotée + tableau). Export PDF recâblé sur les nouvelles zones.
2026-07-16 14:36:09 +02:00
0b4c2244fe Ajoute l'option Absent à la slide 5 (FT)
La question sur la compatibilité des matières se relie désormais à Absent, ajouté comme cinquième section (correspondance 1-à-1).
2026-07-16 09:19:31 +02:00
f720beaf3c Refonte de la slide 5 FT en exercice à relier + boutons Recommencer
La slide 5 (Fiche Technique) devient un exercice de mise en relation : questions à gauche, sections mélangées à droite, reliées au glisser (pointer events + tracé SVG). La vérification colore les liaisons (vert/rouge) et n'est active qu'une fois les 5 questions reliées. L'export PDF lit désormais les liaisons.

Ajout d'un bouton Recommencer sur les slides 3 (FDS glisser-déposer) et 5 (FT), qui réinitialise l'exercice concerné (réponses effacées, message et vérification remis à zéro, éléments re-mélangés).
2026-07-16 09:15:07 +02:00
2a2ed26563 Ignore le web.config de l'API Memory (contient le mot de passe SQL) 2026-07-16 09:00:16 +02:00
fb5c7e9720 Refonte de la slide 3 FDS en glisser-déposer
- Renomme la carte formation en 'FDS, FT & Étiquettes'
- Slide 3 : deux colonnes de huit questions, banques d'étiquettes (rubriques 1 à 16 + Absent) de part et d'autre à glisser-déposer dans chaque case (repli au clic pour le tactile)
- Bloque la vérification tant que les seize cases ne sont pas remplies
- Retire l'étiquette 'Partie 1/3' et remonte le titre pour éviter le défilement
- Ordre d'affichage après correction : réponse, emoji, case
2026-07-16 08:58:34 +02:00
a418558393 Ajoute la correction sur fichier aux exercices BioCID et FDS
Reprend le fonctionnement du TP Nuisibles (« Corriger » à partir du PDF
généré avec les réponses du groupe) pour les deux exercices.

- BioCID et FDS : carte « Identification du groupe » (groupe, date,
  formateur) sur l'écran d'intro, reprise dans l'en-tête du PDF exporté.
- FDS : ajout d'un export PDF (inexistant) récapitulant réponse du groupe
  et réponse attendue, partie par partie, avec le score global.
- Bouton « Corriger un rendu » sur l'écran final des deux exercices.
- Nouvelle page correction-biocid.html : lecture du PDF, réponses
  regroupées par exercice avec badge renseigné / sans réponse.
- Nouvelle page correction-fds.html : notation automatique du QCM
  (anneau de réussite, score par partie, ✓/✗/? par question).
2026-07-15 23:07:45 +02:00
c1bd61c10c Refonte des exercices BioCID et FDS en canvas slide par slide
Reprend le fonctionnement du TP Nuisibles : navigation page par page,
barre de progression, barre basse avec retour et compteur, badge de phase
et modales d'aide. BioCID passe en 7 slides avec champs de notes et export
PDF ; FDS passe en 9 slides (code couleur amber/coral/teal) en conservant
la logique de quiz et de score. Style harmonisé avec le reste du site.
2026-07-15 22:46:04 +02:00
317f98b711 Merge branch 'memory-results' : classement Memory en ligne 2026-07-15 22:35:33 +02:00
2a85ced1e6 Passe le classement Memory en ligne (ASP.NET + SQL Server)
Le classement du jeu Memory était stocké en localStorage (visible d'un seul
joueur, sur un seul poste). Il est désormais partagé en ligne via une API
ASP.NET/SQL Server adaptée à l'hébergement bsite.net.

- API scores.ashx (C#, compilée au vol par IIS) : lecture GET et
  enregistrement POST, création automatique de la table, ne conserve que le
  top 10 de chaque mode (facile / normal / difficile).
- leaderboard.js : le classement passe par fetch vers l'API (états
  chargement/erreur/vide, surbrillance de la ligne du joueur). Les
  statistiques personnelles restent stockées localement.
- memory-game.js : rafraîchit le classement après l'enregistrement (async).
- Style .is-me pour la ligne du joueur courant.
- web.config.example fourni ; le web.config réel (mot de passe) est ignoré.
2026-07-15 22:35:24 +02:00
44be41b2b2 Renomme la marque en Gauthier Chombart & Nathan Chauwin et finalise le jeu Memory
Header, footer, titres et balises meta de toutes les pages actives : remplace NextGN Formation par Gauthier Chombart & Nathan Chauwin. Nouveau pied de page uniforme mentionnant les droits reserves et le statut de formateurs independants (dossier archives/ laisse inchange).

Integre aussi la refonte du jeu Memory (CSS/JS/HUD/leaderboard) et ajoute le rapport de veille Certibiocide semaine 28.
2026-07-14 23:02:09 +02:00
9140d2f468 Harmonise le jeu Memory avec le style ambre du site et corrige le titre
Le jeu utilisait le teal comme couleur dominante (titres, bordures,
boutons, cartes) alors que le reste du site n'emploie le teal que
ponctuellement (état de succès) et repose sur l'ambre comme couleur
principale. Remplace toutes les références teal par l'ambre déjà
défini dans header-style.css, et réaffecte le teal à son rôle habituel
de couleur de succès (paire trouvée), à la place du vert générique
utilisé jusqu'ici.

Renomme aussi le titre en "Memory pictogrammes", augmente la marge
sous le header pour éviter tout chevauchement, et ajoute un paramètre
de version aux feuilles de style du jeu pour éviter les soucis de
cache navigateur lors des prochaines mises à jour.
2026-07-07 17:23:57 +02:00
75c5a1ac84 Retire le pictogramme manette de l'en-tête du jeu 2026-07-07 17:14:22 +02:00
1e757ccda8 Corrige le panneau "Vos statistiques" et compacte son affichage
Deux règles CSS différentes partageaient le nom .player-stats (la
ligne de détails sous chaque joueur du classement, et tout le panneau
"Vos statistiques"). Le panneau héritait donc du display:flex prévu
pour la ligne de détails, ce qui empêchait la grille de stats de
prendre toute la largeur et l'affichait en une colonne étroite.

Renomme la ligne de détails en .rank-meta et aligne les 4 encadrés de
stats sur une seule rangée compacte sous le titre.
2026-07-07 17:12:29 +02:00
f7f73591c1 Ajoute la config du serveur de preview local
Permet de lancer le site en local (python3 -m http.server) via l'outil
de preview.
2026-07-07 17:08:08 +02:00
cf69373417 Corrige la superposition header/contenu et harmonise le style du jeu Memory
L'animation d'entrée (translation + rebond infini du badge) pouvait
faire chevaucher le header. Remplacée par une simple apparition sans
déplacement vertical, avec plus de marge sous le header.

Aligne aussi les rayons d'angle, les ombres et les boutons du jeu sur
le langage visuel déjà utilisé ailleurs sur le site (cartes à 12px de
rayon, ombres neutres, titre de section souligné, style de bouton
partagé depuis header-style.css).
2026-07-07 17:06:09 +02:00
2227aa89d5 Refonte visuelle du jeu Memory Pictogrammes GHS
Corrige les pictogrammes cassés (mauvais noms de fichiers dans
utils.js) et le conflit de classe CSS .progress-bar avec le header
qui cassait la barre de progression du jeu. Réorganise l'interface
dans un panneau de jeu unifié, ajoute des icônes aux statistiques
et au sélecteur de difficulté, et rend le dos des cartes plus ludique.
2026-07-07 16:58:40 +02:00
954c7d2b1a Corrige le domaine canonique et les liens de rapports cassés
Remplace le domaine placeholder par le vrai domaine (canonical + og:url)
et corrige les liens vers les rapports de veille semaine 20 et 21 qui
pointaient vers un chemin inexistant. Ajoute aussi le rapport de la
semaine 26 non encore suivi.
2026-07-07 16:41:13 +02:00
0d4bc8121d Rangement du dossier veille 2026-06-17 18:47:58 +02:00
742d86dfaa Ajout d'une possibilité de correction pour le TP Nuisibles 2026-06-17 18:38:56 +02:00
39 changed files with 7040 additions and 6285 deletions

11
.claude/launch.json Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "static-site",
"runtimeExecutable": "python3",
"runtimeArgs": ["-m", "http.server", "8123"],
"port": 8123
}
]
}

4
.gitignore vendored
View File

@@ -1,2 +1,6 @@
.DS_Store
# Contient le mot de passe de la base SQL Server — à créer/éditer uniquement sur
# le serveur bsite.net à partir de web.config.example (ne jamais versionner)
exercices/memory-pictogrammes/api/web.config

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Index Documentation Technique & Biologie | NextGN Formation</title>
<title>Index Documentation Technique & Biologie | Gauthier Chombart & Nathan Chauwin</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
@@ -506,7 +506,7 @@
<nav class="nav-header">
<a href="index.html" class="header-logo">
<span>NextGN</span> Formation
Gauthier Chombart & Nathan Chauwin
</a>
<div class="header-nav">
<a href="index.html#formations">Exercices interactifs</a>
@@ -548,7 +548,7 @@
</main>
<footer>
<p>&copy; 2026 NextGN Formation - Index Documentation Technique & Biologie</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p>Tous droits réservés — Gauthier Chombart & Nathan Chauwin — Formateurs indépendants</p>
</footer>

BIN
data/ghs05-corrosif.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
data/ghs07-nocif.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@
justify-content: center;
padding: 2rem;
padding-top: calc(70px + 2rem);
padding-bottom: calc(52px + 2rem);
padding-bottom: calc(84px + 2rem);
opacity: 0;
transition: opacity 0.4s ease;
overflow-y: auto;
@@ -38,73 +38,67 @@
transition: width 0.4s ease;
}
/* PHASE INDICATOR */
.phase-badge {
position: fixed;
top: 80px; right: 16px;
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 4px 12px;
border-radius: 20px;
z-index: 100;
}
/* BOTTOM BAR */
.bottom-bar {
position: fixed;
bottom: 0; left: 0; right: 0;
height: 52px;
height: 84px;
background: rgba(250, 238, 218, 0.98);
border-top: 2px solid var(--amber);
display: flex;
align-items: center;
justify-content: space-between;
justify-content: center;
padding: 0 20px;
z-index: 100;
backdrop-filter: blur(10px);
}
/* SLIDE NAV */
.bottom-actions {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
justify-content: center;
}
.footer-btn {
font-family: 'Syne', sans-serif;
font-size: 13px;
font-weight: 600;
padding: 11px 24px;
border-radius: 40px;
border: 1.5px solid var(--amber);
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
line-height: 1;
transition: all 0.2s;
}
.footer-btn:hover { transform: translateY(-1px); }
.footer-btn:active { transform: scale(0.98); }
.footer-btn.is-primary { background: var(--amber); color: #fff; }
.footer-btn.is-primary:hover { background: var(--amber-dark); }
.footer-btn.is-secondary { background: transparent; color: var(--amber-dark); }
.footer-btn.is-secondary:hover { background: rgba(186,117,23,0.08); }
.slide-counter {
position: absolute;
left: 20px;
font-size: 12px;
font-family: 'Syne', sans-serif;
font-weight: 600;
color: var(--amber-dark);
}
/* BACK BUTTON */
.back-btn {
background: none;
border: 0.5px solid var(--amber);
border-radius: 20px;
padding: 6px 16px;
font-size: 12px;
color: var(--amber-dark);
cursor: pointer;
transition: all 0.2s;
font-family: 'DM Sans', sans-serif;
@media (max-width: 560px) {
.slide-counter { display: none; }
}
.back-btn:hover { background: rgba(186,117,23,0.08); }
/* FORMATEUR SELECTOR */
.formateur-btn {
font-family: 'Syne', sans-serif;
font-size: 14px;
font-weight: 600;
padding: 10px 24px;
border-radius: 30px;
border: 1.5px solid var(--border);
background: white;
color: var(--text-muted);
cursor: pointer;
transition: all 0.2s;
flex: 1;
flex: 1; font-family: 'DM Sans', sans-serif; font-size: 13.5px;
padding: 9px 13px; border: 1px solid var(--border); border-radius: 10px;
background: var(--bg); color: var(--text); cursor: pointer; transition: all 0.2s ease;
}
.formateur-btn:hover { border-color: var(--amber); color: var(--amber); }
.formateur-btn.selected { background: var(--amber-light); border-color: var(--amber); color: var(--amber-dark); font-weight: 700; }
.formateur-btn:hover { border-color: var(--amber); }
.formateur-btn.selected { background: var(--amber); border-color: var(--amber); color: #fff; }
/* CARDS & BUTTONS */
.btn {
@@ -246,40 +240,42 @@
.q-item { flex-direction: column; align-items: stretch; }
.q-item .q-head { display: flex; align-items: flex-start; gap: 12px; }
/* IDENTIFICATION SCREEN */
.id-form {
/* IDENTIFICATION SCREEN — carte modèle BioCID / FDS */
.identity-card {
background: white;
border: 0.5px solid var(--border);
border-radius: 14px;
padding: 16px 18px;
max-width: 460px;
width: 100%;
max-width: 420px;
display: flex;
flex-direction: column;
gap: 14px;
margin: 1.25rem 0;
margin: 1.25rem auto;
text-align: left;
}
.id-field label {
display: block;
.identity-card .identity-title {
font-family: 'Syne', sans-serif;
font-size: 11px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 6px;
text-align: left;
color: var(--amber-dark);
margin-bottom: 10px;
display: flex; align-items: center; gap: 6px;
}
.id-field input {
width: 100%;
.identity-fields { display: flex; flex-direction: column; gap: 8px; }
.identity-fields input {
font-family: 'DM Sans', sans-serif;
font-size: 15px;
padding: 12px 16px;
border: 1.5px solid var(--border);
border-radius: 10px;
background: white;
font-size: 13.5px;
color: var(--text);
background: var(--bg);
border: 1px solid var(--border);
border-radius: 10px;
padding: 9px 13px;
width: 100%;
box-sizing: border-box;
}
.id-field input:focus {
outline: none;
border-color: var(--amber);
}
.identity-fields input:focus { outline: none; border-color: var(--amber); background: white; }
.formateur-label { font-size: 11px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-muted); margin: 4px 0 2px; }
.formateur-row { display: flex; gap: 8px; }
/* TABLE FORM CONTROLS */
.risk-table input, .risk-table textarea {
@@ -496,6 +492,19 @@
line-height: 1.6;
margin-bottom: 1.5rem;
}
.info-card {
background: var(--amber-light);
border-radius: 12px;
padding: 16px 20px;
max-width: 620px;
width: 100%;
font-size: 14px;
color: var(--amber-dark);
line-height: 1.6;
display: flex;
gap: 10px;
align-items: flex-start;
}
.steps-row {
display: flex;
gap: 8px;
@@ -574,7 +583,7 @@
gap: 12px;
max-width: 640px;
width: 100%;
margin: 1.5rem 0;
margin: 1.5rem auto;
}
.final-card {
background: white;
@@ -606,7 +615,7 @@
/* SCROLLABLE AREA */
.scroll-area {
overflow-y: auto;
max-height: calc(100vh - 232px);
max-height: calc(100vh - 200px);
width: 100%;
display: flex;
flex-direction: column;
@@ -628,9 +637,12 @@
</head>
<body>
<!-- CONFETTI CANVAS -->
<canvas id="confettiCanvas" style="position:fixed;inset:0;pointer-events:none;z-index:150;display:none;"></canvas>
<!-- HEADER WITH NAVIGATION -->
<header>
<div class="logo">NextGN Formation</div>
<div class="logo">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="../index.html">Accueil</a>
<a href="../index.html#formations">Exercices</a>
@@ -644,13 +656,14 @@
<!-- Progress bar -->
<div class="progress-bar"><div class="progress-fill" id="progressFill"></div></div>
<!-- Phase badge -->
<div class="phase-badge" id="phaseBadge" style="display:none"></div>
<!-- Bottom bar -->
<div class="bottom-bar" id="bottomBar" style="display:none;">
<button class="back-btn" id="backBtn" onclick="goBack()" style="display:none;">← Retour</button>
<div class="slide-counter" id="slideCounter"></div>
<div class="bottom-actions">
<button class="footer-btn is-secondary" id="backBtn" onclick="goBack()" style="display:none;">← Retour</button>
<button class="footer-btn is-secondary" id="footerHintBtn" onclick="showHintCurrent()" style="display:none;">💡 Besoin d'aide ?</button>
<button class="footer-btn is-primary" id="footerNextBtn" onclick="goNext()" style="display:none;">Étape suivante →</button>
</div>
</div>
<!-- Modal overlay -->
@@ -663,45 +676,40 @@
</div>
</div>
<!-- ======================== SLIDE 0 — IDENTIFICATION ======================== -->
<!-- ======================== SLIDE 0 — ACCUEIL ======================== -->
<div class="slide active fade-in" id="slide-0">
<div class="deco-circle" style="width:320px;height:320px;background:var(--amber-light);top:-80px;left:-80px;opacity:0.5;"></div>
<div style="text-align:center; z-index:1; width:100%;">
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">Avant de commencer</div>
<div class="slide-title">Identification du groupe</div>
<p class="slide-intro" style="margin:0.5rem auto 0;max-width:420px;">Ces informations permettront au formateur de retrouver vos réponses.</p>
<div class="id-form" style="margin-left:auto;margin-right:auto;">
<div class="id-field">
<label for="inputNom">Nom du stagiaire ou du groupe</label>
<input type="text" id="inputNom" placeholder="Ex : Groupe 3 - Dupont / Martin" autocomplete="off">
</div>
<div class="id-field">
<label for="inputDate">Date de la session</label>
<input type="date" id="inputDate">
</div>
<div class="id-field">
<label>Formateur de la session</label>
<div style="display:flex;gap:10px;margin-top:2px;">
<button type="button" class="formateur-btn" id="btnNathan" onclick="selectFormateur('Nathan')">Nathan</button>
<button type="button" class="formateur-btn" id="btnGauthier" onclick="selectFormateur('Gauthier')">Gauthier</button>
</div>
</div>
</div>
<div id="idError" style="color:var(--coral);font-size:13px;margin-bottom:0.5rem;display:none;">Merci de renseigner au moins le nom du groupe.</div>
<button class="btn btn-teal" onclick="confirmIdentite()">Continuer →</button>
<div class="deco-circle" style="width:400px;height:400px;background:var(--amber-light);top:-100px;right:-80px;opacity:0.6;"></div>
<div class="deco-circle" style="width:200px;height:200px;background:var(--amber-light);bottom:60px;left:-60px;opacity:0.5;"></div>
<div style="text-align:center;">
<div class="hero-label">Certibiocide — Travaux pratiques</div>
<div class="hero-title">Étude de cas<br>Nuisibles</div>
<p class="hero-sub">Votre mission, si vous l'acceptez : maîtriser l'identification, le traitement et la sécurité face aux nuisibles.</p>
<button class="btn btn-amber" onclick="goTo(1)">Démarrer la mission →</button>
</div>
</div>
<!-- ======================== SLIDE 1 — ACCUEIL ======================== -->
<!-- ======================== SLIDE 1 — CONTEXTE & IDENTIFICATION ======================== -->
<div class="slide" id="slide-1">
<div class="deco-circle" style="width:400px;height:400px;background:var(--amber-light);top:-100px;right:-80px;opacity:0.6;"></div>
<div class="deco-circle" style="width:200px;height:200px;background:var(--amber-light);bottom:60px;left:-60px;opacity:0.5;"></div>
<div style="text-align:center; z-index:1;">
<div class="hero-label">Formation 2025</div>
<div class="hero-title">CERTIBIOCIDE</div>
<div style="font-family:'Syne',sans-serif;font-size:clamp(14px,2.5vw,22px);font-weight:600;color:var(--amber-mid);letter-spacing:0.04em;margin-bottom:1.5rem;">TRAVAUX PRATIQUES</div>
<p class="hero-sub">Votre mission, si vous l'acceptez : maîtriser l'identification, le traitement et la sécurité face aux nuisibles.</p>
<button class="btn btn-teal" onclick="goTo(2)">Démarrer la mission →</button>
<div class="deco-circle" style="width:300px;height:300px;background:var(--amber-light);top:-60px;left:-60px;opacity:0.4;"></div>
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">Avant de commencer</div>
<div class="slide-title">Contexte & accès</div>
<p class="slide-intro">3 travaux pratiques vous attendent : protocole d'intervention, recherche produit sur BioCID, puis analyse de risques. Ces informations permettront au formateur de retrouver vos réponses.</p>
<div class="info-card" style="max-width:620px;">
<span>🎯</span>
<div>Vous allez définir un <strong>protocole d'intervention</strong>, trouver votre <strong>produit sur BioCID</strong>, puis réaliser l'<strong>analyse de risques</strong>.</div>
</div>
<div class="identity-card" style="max-width:620px;margin-top:0.5rem;">
<div class="identity-title">👥 Identification du groupe</div>
<div class="identity-fields">
<input type="text" id="inputNom" placeholder="Nom du groupe / stagiaires (ex : Groupe 3 — Dupont / Martin)" autocomplete="off">
<input type="date" id="inputDate">
<div class="formateur-label">Formateur de la session</div>
<div class="formateur-row">
<button type="button" class="formateur-btn" id="btnNathan" onclick="selectFormateur('Nathan')">Nathan</button>
<button type="button" class="formateur-btn" id="btnGauthier" onclick="selectFormateur('Gauthier')">Gauthier</button>
</div>
</div>
<div id="idError" style="color:var(--coral);font-size:13px;margin-top:8px;display:none;">Merci de renseigner au moins le nom du groupe.</div>
</div>
</div>
@@ -709,8 +717,12 @@
<div class="slide" id="slide-2">
<div class="deco-circle" style="width:300px;height:300px;background:var(--amber-light);top:-60px;left:-60px;opacity:0.4;"></div>
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">Étape 1 / 3</div>
<div class="slide-title">Choisissez votre mission</div>
<div class="slide-title">🎯 Choisissez votre mission</div>
<p class="slide-intro">Chaque groupe choisit un cas pratique. Vous travaillerez avec ce scénario tout au long des 3 exercices.</p>
<div class="info-card" style="margin-bottom:1.25rem;">
<span>💡</span>
<div>Le cas retenu conditionne <strong>tous les exercices suivants</strong> et apparaît dans le PDF final. Choisissez celui qui se rapproche le plus de votre pratique.</div>
</div>
<div class="case-grid">
<div class="case-card" onclick="selectCase('punaises','🛏️','Hôtel — Punaises de lit','Infestation importante dans un hôtel')">
<div class="case-icon">🛏️</div>
@@ -738,9 +750,6 @@
<div class="case-sub">Camping</div>
</div>
</div>
<div class="actions-row">
<button class="btn btn-teal" id="btnConfirmCase" onclick="goTo(3)" style="display:none">Confirmer le choix →</button>
</div>
</div>
<!-- ======================== SLIDE 3 — CONSIGNES ======================== -->
@@ -768,7 +777,6 @@
<span>💡</span>
<div>À tout moment, cliquez sur <strong>« Besoin d'aide ? »</strong> pour accéder à un indice. Le formateur corrigera à l'oral en fin de séance.</div>
</div>
<button class="btn btn-teal" onclick="goTo(4)">Commencer le TP 1 →</button>
</div>
<!-- ======================== SLIDE 4 — TP1 INTRO ======================== -->
@@ -786,7 +794,6 @@
<div class="step-pill">2. Intervention</div>
<div class="step-pill">3. Évaluation</div>
</div>
<button class="btn btn-amber" onclick="goTo(5)">Commencer →</button>
</div>
<!-- ======================== SLIDE 5 — TP1 PREVENTION ======================== -->
@@ -827,10 +834,6 @@
<textarea class="answer-field" id="ans_prevention_4" placeholder="Votre réponse…" data-question="Éléments observés / preuve de présence du nuisible"></textarea>
</li>
</ul>
<div class="actions-row">
<button class="hint-btn" onclick="showHint('prevention')">💡 Besoin d'aide ?</button>
<button class="btn btn-amber" onclick="goTo(6)">Étape suivante →</button>
</div>
</div>
</div>
@@ -865,10 +868,6 @@
<textarea class="answer-field" id="ans_intervention_3" placeholder="Votre réponse…" data-question="Type de produit (TP) et mode de traitement"></textarea>
</li>
</ul>
<div class="actions-row">
<button class="hint-btn" onclick="showHint('intervention')">💡 Besoin d'aide ?</button>
<button class="btn btn-amber" onclick="goTo(7)">Étape suivante →</button>
</div>
</div>
</div>
@@ -899,10 +898,6 @@
<div style="background:var(--amber-light);border-radius:12px;padding:14px 18px;max-width:680px;width:100%;font-size:13px;color:var(--amber-dark);margin:0.75rem 0;">
<strong>TP 1 terminé !</strong> Préparez-vous à identifier le produit adapté à votre cas sur biocid-anses.fr.
</div>
<div class="actions-row">
<button class="hint-btn" onclick="showHint('evaluation')">💡 Besoin d'aide ?</button>
<button class="btn btn-coral" onclick="goTo(8)">Passer au TP 2 →</button>
</div>
</div>
</div>
@@ -924,7 +919,6 @@
</div>
<a href="https://biocid-anses.fr" target="_blank" class="resource-link">Ouvrir le site ↗</a>
</div>
<button class="btn btn-coral" onclick="goTo(9)">Commencer →</button>
</div>
<!-- ======================== SLIDE 9 — TP2 FDS & AMM ======================== -->
@@ -965,10 +959,6 @@
<textarea class="answer-field" id="ans_fds_4" placeholder="Votre réponse…" data-question="Risques pour la santé"></textarea>
</li>
</ul>
<div class="actions-row">
<button class="hint-btn" onclick="showHint('fds')">💡 Besoin d'aide ?</button>
<button class="btn btn-coral" onclick="goTo(10)">Partie suivante →</button>
</div>
</div>
</div>
@@ -1013,10 +1003,6 @@
<div style="background:var(--amber-light);border-radius:12px;padding:14px 18px;max-width:680px;width:100%;font-size:13px;color:var(--amber-dark);margin:0.75rem 0;">
<strong>TP 2 terminé !</strong> Passez maintenant à l'analyse de risques complète.
</div>
<div class="actions-row">
<button class="hint-btn" onclick="showHint('epi')">💡 Besoin d'aide ?</button>
<button class="btn btn-purple" onclick="goTo(11)">Passer au TP 3 →</button>
</div>
</div>
</div>
@@ -1033,9 +1019,6 @@
<div class="pyr-level" style="width:320px;background:#D85A30;">Communication</div>
<div class="pyr-level" style="width:360px;background:#BA7517;">EPI (dernier recours)</div>
</div>
<div class="actions-row" style="margin-top:1rem;">
<button class="btn btn-purple" onclick="goTo(12)">Remplir le tableau →</button>
</div>
</div>
<!-- ======================== SLIDE 12 — TP3 TABLEAU ======================== -->
@@ -1104,10 +1087,6 @@
<div style="background:var(--amber-light);border-radius:12px;padding:14px 18px;max-width:780px;width:100%;font-size:13px;color:var(--amber-dark);margin:0.25rem 0;">
<strong>TP 3 terminé !</strong> Présentez vos réponses au formateur pour la correction.
</div>
<div class="actions-row">
<button class="hint-btn" onclick="showHint('analyse')">💡 Aide générale</button>
<button class="btn btn-blue" onclick="goTo(13)">Terminer la mission →</button>
</div>
</div>
</div>
@@ -1119,7 +1098,7 @@
<div style="font-size:48px;margin-bottom:1rem;">🎉</div>
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">Mission accomplie</div>
<div class="slide-title" style="margin-top:0.5rem;">Félicitations !</div>
<p style="font-size:14px;color:var(--text-muted);max-width:480px;text-align:center;line-height:1.7;margin:1rem auto;">Vous avez complété les 3 travaux pratiques de la formation Certibiocide 2025. Le formateur va maintenant corriger à l'oral.</p>
<p style="font-size:14px;color:var(--text-muted);max-width:480px;text-align:center;line-height:1.7;margin:1rem auto;">Vous avez complété les 3 travaux pratiques de la formation Certibiocide. Le formateur va maintenant corriger à l'oral.</p>
<div class="final-grid">
<div class="final-card">
<div class="final-card-icon">🗂️</div>
@@ -1137,14 +1116,10 @@
<div class="final-card-sub">Analyse de risques</div>
</div>
</div>
<div class="submit-zone">
<div style="display:flex;gap:10px;justify-content:center;flex-wrap:wrap;">
<button class="btn btn-teal" onclick="exporterPDF()">⬇ Télécharger en PDF</button>
</div>
</div>
<div style="display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:0.75rem;">
<a href="https://biocid-anses.fr" target="_blank" class="btn btn-outline btn-teal" style="font-size:13px;padding:10px 20px;">biocid-anses.fr ↗</a>
<button class="btn btn-teal" onclick="restartAll()">↺ Recommencer depuis le début</button>
<div class="actions-row">
<button class="btn btn-amber" onclick="exporterPDF()">⬇ Télécharger mes réponses (PDF)</button>
<a href="corriger-exercice.html?exo=tp" class="btn btn-outline btn-teal">✔ Corriger un rendu</a>
<button class="btn btn-outline btn-teal" onclick="restartAll()">↺ Recommencer</button>
</div>
</div>
</div>
@@ -1157,6 +1132,22 @@ const totalSlides = 13;
const selectedCase = { key: '', icon: '', title: '', desc: '' };
const stagiaire = { nom: '', date: '', formateur: '' };
// Configuration des boutons du footer par slide (modèle BioCID)
const slideConfig = {
1: { next: 2, nextLabel: 'Continuer →' },
2: { next: 3, nextLabel: 'Confirmer le choix →' },
3: { next: 4, nextLabel: 'Commencer le TP 1 →' },
4: { next: 5, nextLabel: 'Commencer →' },
5: { next: 6, nextLabel: 'Étape suivante →', hint: 'prevention' },
6: { next: 7, nextLabel: 'Étape suivante →', hint: 'intervention' },
7: { next: 8, nextLabel: 'Passer au TP 2 →', hint: 'evaluation' },
8: { next: 9, nextLabel: 'Commencer →' },
9: { next: 10, nextLabel: 'Partie suivante →', hint: 'fds' },
10: { next: 11, nextLabel: 'Passer au TP 3 →', hint: 'epi' },
11: { next: 12, nextLabel: 'Remplir le tableau →' },
12: { next: 13, nextLabel: 'Terminer la mission →', hint: 'analyse' }
};
const hints = {
prevention: {
icon: '💡',
@@ -1243,10 +1234,28 @@ function goTo(n) {
currentSlide = n;
next.style.display = 'flex';
setTimeout(() => { next.classList.add('active', 'fade-in'); }, 10);
const sa = next.querySelector('.scroll-area');
if (sa) sa.scrollTop = 0;
if (n === 13) setTimeout(launchConfetti, 200);
updateUI();
updateCaseBanners();
}
function goNext() {
const cfg = slideConfig[currentSlide];
if (!cfg || cfg.next == null) return;
// Slide 1 : validation du nom du groupe avant de continuer
if (currentSlide === 1) { confirmIdentite(); return; }
// Slide 2 : un cas doit être sélectionné
if (currentSlide === 2 && !selectedCase.key) return;
goTo(cfg.next);
}
function showHintCurrent() {
const cfg = slideConfig[currentSlide];
if (cfg && cfg.hint) showHint(cfg.hint);
}
function goBack() {
if (history.length === 0) return;
const prev = history.pop();
@@ -1271,37 +1280,31 @@ function updateUI() {
if (bottomBar) bottomBar.style.display = currentSlide === 0 ? 'none' : 'flex';
const backBtn = document.getElementById('backBtn');
backBtn.style.display = history.length > 0 ? 'block' : 'none';
backBtn.style.display = history.length > 0 ? 'inline-flex' : 'none';
const badge = document.getElementById('phaseBadge');
if (currentSlide === 0 || currentSlide === 1 || currentSlide === 2 || currentSlide === 3 || currentSlide === 13) {
badge.style.display = 'none';
} else if (currentSlide >= 4 && currentSlide <= 7) {
badge.style.display = 'block';
badge.style.background = 'var(--amber-light)';
badge.style.color = 'var(--amber-dark)';
badge.textContent = 'TP 1 — Protocole';
} else if (currentSlide >= 8 && currentSlide <= 10) {
badge.style.display = 'block';
badge.style.background = 'var(--coral-light)';
badge.style.color = 'var(--coral)';
badge.textContent = 'TP 2 — Produit';
} else if (currentSlide >= 11 && currentSlide <= 12) {
badge.style.display = 'block';
badge.style.background = 'var(--amber-light)';
badge.style.color = 'var(--amber-dark)';
badge.textContent = 'TP 3 — Risques';
const cfg = slideConfig[currentSlide] || {};
const hintBtn = document.getElementById('footerHintBtn');
const nextBtn = document.getElementById('footerNextBtn');
hintBtn.style.display = cfg.hint ? 'inline-flex' : 'none';
if (cfg.next != null) {
// Slide 2 : le bouton n'apparaît qu'une fois le cas choisi
const gated = currentSlide === 2 && !selectedCase.key;
nextBtn.style.display = gated ? 'none' : 'inline-flex';
nextBtn.textContent = cfg.nextLabel;
} else {
nextBtn.style.display = 'none';
}
}
function selectCase(key, icon, title, desc) {
marquerModifie();
selectedCase.key = key;
selectedCase.icon = icon;
selectedCase.title = title;
selectedCase.desc = desc;
document.querySelectorAll('.case-card').forEach(c => c.classList.remove('selected'));
event.currentTarget.classList.add('selected');
document.getElementById('btnConfirmCase').style.display = 'inline-flex';
updateUI();
}
function updateCaseBanners() {
@@ -1371,7 +1374,7 @@ function confirmIdentite() {
document.getElementById('idError').style.display = 'none';
stagiaire.nom = nom;
stagiaire.date = date || new Date().toISOString().slice(0, 10);
goTo(1);
goTo(2);
}
/* ======================== TABLEAU TP3 — LIGNES DYNAMIQUES ======================== */
@@ -1497,7 +1500,7 @@ function exporterPDF() {
.meta { font-size: 13px; color: #555; margin-bottom: 4px; }
</style></head>
<body>
<h1>TP Nuisibles — Certibiocide 2025</h1>
<h1>TP Nuisibles — Certibiocide</h1>
<p class="meta"><strong>Groupe / Stagiaire :</strong> ${escapeHtml(data.nom)}</p>
<p class="meta"><strong>Date de session :</strong> ${escapeHtml(data.date_session)}</p>
<p class="meta"><strong>Formateur :</strong> ${escapeHtml(data.formateur)}</p>
@@ -1520,11 +1523,234 @@ function exporterPDF() {
setTimeout(() => w.print(), 300);
}
/* ======================== CONFETTI ======================== */
function launchConfetti() {
const canvas = document.getElementById('confettiCanvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.display = 'block';
const colors = ['#BA7517', '#D85A30', '#F5DFB8', '#633806', '#F0A855', '#E8C068', '#FF8C5A'];
const particles = Array.from({ length: 180 }, () => ({
x: Math.random() * canvas.width,
y: -(Math.random() * canvas.height * 0.5),
w: Math.random() * 10 + 5,
h: Math.random() * 5 + 3,
color: colors[Math.floor(Math.random() * colors.length)],
rotation: Math.random() * Math.PI * 2,
rotSpeed: (Math.random() - 0.5) * 0.18,
vx: (Math.random() - 0.5) * 2.5,
vy: Math.random() * 3 + 2,
opacity: 1,
shape: Math.random() < 0.4 ? 'circle' : 'rect'
}));
let rafId;
let start = null;
const totalDuration = 3800;
function draw(ts) {
if (!start) start = ts;
const elapsed = ts - start;
ctx.clearRect(0, 0, canvas.width, canvas.height);
let active = false;
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
p.vy += 0.04;
p.rotation += p.rotSpeed;
p.opacity = elapsed < totalDuration * 0.55
? 1
: Math.max(0, 1 - (elapsed - totalDuration * 0.55) / (totalDuration * 0.45));
if (p.y < canvas.height + 20) active = true;
ctx.save();
ctx.translate(p.x, p.y);
ctx.rotate(p.rotation);
ctx.globalAlpha = p.opacity;
ctx.fillStyle = p.color;
if (p.shape === 'circle') {
ctx.beginPath();
ctx.arc(0, 0, p.w / 2, 0, Math.PI * 2);
ctx.fill();
} else {
ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
}
ctx.restore();
});
if (active && elapsed < totalDuration * 1.3) {
rafId = requestAnimationFrame(draw);
} else {
canvas.style.display = 'none';
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
if (rafId) cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(draw);
}
function escapeHtml(str) {
if (!str) return '';
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
/* ======================== SAUVEGARDE AUTOMATIQUE ======================== */
/* Les réponses sont enregistrées dans le navigateur au fil de la saisie, puis
proposées à la restauration au rechargement. En file://, localStorage peut être
indisponible (Safari) : dans ce cas la page fonctionne normalement, sans filet. */
const CLE_SAUVEGARDE = 'certibiocide:tp-nuisibles:v1';
let reponsesModifiees = false;
function marquerModifie() { reponsesModifiees = true; sauvegarder(); }
document.addEventListener('input', marquerModifie, true);
document.addEventListener('change', marquerModifie, true);
// Avertit avant tout rechargement ou départ. Le texte de la boîte est imposé
// par le navigateur, il n'est pas personnalisable.
window.addEventListener('beforeunload', e => {
if (!reponsesModifiees) return;
e.preventDefault();
e.returnValue = '';
});
function etatCourant() {
const champs = {};
document.querySelectorAll('input[id], textarea[id]').forEach(el => {
if (el.value) champs[el.id] = el.value;
});
// Les cellules du tableau TP3 n'ont pas d'id : on les repère par leur position.
const risques = Array.from(document.querySelectorAll('#riskTableBody .risk-row'))
.map(row => Array.from(row.querySelectorAll('.risk-cell')).map(c => c.value));
return {
savedAt: new Date().toISOString(),
slide: currentSlide,
champs,
risques,
cas: selectedCase.key || '',
formateur: stagiaire.formateur || '',
nom: stagiaire.nom || '',
date: stagiaire.date || '',
};
}
let minuteurSauvegarde = null;
function sauvegarder() {
clearTimeout(minuteurSauvegarde);
minuteurSauvegarde = setTimeout(() => {
try {
localStorage.setItem(CLE_SAUVEGARDE, JSON.stringify(etatCourant()));
} catch (e) { /* navigation privée ou quota : on continue sans sauvegarde */ }
}, 400);
}
function lireSauvegarde() {
try { return JSON.parse(localStorage.getItem(CLE_SAUVEGARDE)); }
catch (e) { return null; }
}
function effacerSauvegarde() {
try { localStorage.removeItem(CLE_SAUVEGARDE); } catch (e) {}
}
function appliquerSauvegarde(data) {
Object.entries(data.champs || {}).forEach(([id, v]) => {
const el = document.getElementById(id);
if (el) el.value = v;
});
// Recrée autant de lignes de risques que nécessaire avant de les remplir
const risques = data.risques || [];
const tbody = document.getElementById('riskTableBody');
while (tbody.querySelectorAll('.risk-row').length < risques.length) addRiskRow();
tbody.querySelectorAll('.risk-row').forEach((row, i) => {
const valeurs = risques[i] || [];
row.querySelectorAll('.risk-cell').forEach((cell, j) => { cell.value = valeurs[j] || ''; });
});
// Le cas pratique et le formateur passent par leurs boutons, qui remettent
// aussi l'interface (carte sélectionnée, bouton de confirmation) dans le bon état.
if (data.cas) {
const carte = Array.from(document.querySelectorAll('.case-card'))
.find(c => (c.getAttribute('onclick') || '').includes("'" + data.cas + "'"));
if (carte) carte.click();
}
if (data.formateur) {
const btn = document.getElementById('btn' + data.formateur);
if (btn) btn.click();
}
stagiaire.nom = data.nom || stagiaire.nom;
stagiaire.date = data.date || stagiaire.date;
reponsesModifiees = true;
if (typeof data.slide === 'number' && data.slide > 0) goTo(data.slide);
updateUI();
}
/* Bandeau de restauration : on ne restaure jamais sans demander, pour qu'un
nouveau groupe n'hérite pas des réponses du précédent sur un poste partagé. */
function injecterStylesBandeau() {
const style = document.createElement('style');
style.textContent = `
.restore-bar {
position: fixed; top: 84px; left: 50%; transform: translateX(-50%);
z-index: 900; max-width: min(680px, calc(100vw - 32px));
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
background: var(--white); border: 1.5px solid var(--amber);
border-radius: 14px; padding: 14px 18px;
box-shadow: 0 8px 28px rgba(0,0,0,0.12); font-size: 13.5px;
}
.restore-bar .restore-text { flex: 1; min-width: 220px; line-height: 1.5; }
.restore-bar .restore-actions { display: flex; gap: 8px; flex-shrink: 0; }
.restore-bar button {
font-family: 'Syne', sans-serif; font-weight: 700; font-size: 12.5px;
padding: 8px 16px; border-radius: 20px; cursor: pointer;
border: 1px solid var(--border); background: transparent; color: var(--text-muted);
}
.restore-bar button:hover { border-color: var(--amber); color: var(--amber); }
.restore-bar button.primary {
background: var(--amber); border-color: var(--amber); color: #fff;
}
.restore-bar button.primary:hover { background: var(--amber-dark); border-color: var(--amber-dark); color: #fff; }
`;
document.head.appendChild(style);
}
function proposerRestauration() {
const data = lireSauvegarde();
if (!data) return;
const aDesReponses = (data.champs && Object.keys(data.champs).length > 0)
|| (data.risques || []).some(r => r.some(v => v));
if (!aDesReponses) return;
const quand = new Date(data.savedAt);
const libelle = isNaN(quand.getTime()) ? '' :
` du ${quand.toLocaleDateString('fr-FR')} à ${quand.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })}`;
injecterStylesBandeau();
const bar = document.createElement('div');
bar.className = 'restore-bar';
bar.innerHTML = `
<span class="restore-text">💾 Des réponses enregistrées${libelle} ont été retrouvées sur ce poste.</span>
<span class="restore-actions">
<button type="button" class="primary" id="btnRestaurer">Restaurer</button>
<button type="button" id="btnRepartir">Repartir de zéro</button>
</span>`;
document.body.appendChild(bar);
document.getElementById('btnRestaurer').onclick = () => { appliquerSauvegarde(data); bar.remove(); };
document.getElementById('btnRepartir').onclick = () => { effacerSauvegarde(); bar.remove(); };
}
proposerRestauration();
updateUI();
</script>
</body>

View File

@@ -1,299 +0,0 @@
<%@ Language="VBScript" %>
<%
Response.Buffer = True
Response.CharSet = "UTF-8"
' ------- À ADAPTER : même chaîne de connexion que save_results.asp -------
Dim connString
connString = "Provider=SQLOLEDB;Data Source=sql.bsite.net\MSSQL2016;" & _
"Initial Catalog=nextgnformation_reponses_exercices;" & _
"User ID=nextgnformation_reponses_exercices;" & _
"Password=S5$NyFXzEjJCg6jD;"
' ------- À ADAPTER : mot de passe d'accès à cette page -------
Dim ADMIN_PASSWORD
ADMIN_PASSWORD = "Sm#gnttCaYE5f3ED"
' -----------------------------------------------------------------------
Dim authenticated
authenticated = False
If Request.Cookies("tp_admin_auth") = "ok" Then
authenticated = True
End If
If Request.Form("password") <> "" Then
If Request.Form("password") = ADMIN_PASSWORD Then
authenticated = True
Response.Cookies("tp_admin_auth") = "ok"
Response.Cookies("tp_admin_auth").Expires = DateAdd("h", 8, Now)
Else
authenticated = False
End If
End If
Function HtmlEscape(s)
If IsNull(s) Then
HtmlEscape = ""
Exit Function
End If
s = CStr(s)
s = Replace(s, "&", "&amp;")
s = Replace(s, "<", "&lt;")
s = Replace(s, ">", "&gt;")
HtmlEscape = s
End Function
%>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Résultats des TP — NextGN Formation</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
--amber: #BA7517; --amber-light: #FAEEDA; --amber-dark: #633806;
--coral: #993C1D; --coral-mid: #D85A30; --coral-light: #FAECE7;
--bg: #F7F6F2; --white: #FFFFFF; --text: #1a1a18; --text-muted: #6b6a65;
--border: rgba(0,0,0,0.1);
}
* { box-sizing: border-box; }
body {
margin: 0; font-family: 'DM Sans', sans-serif; background: var(--bg); color: var(--text);
padding-top: 70px;
}
.nav-header {
position: fixed; top: 0; left: 0; right: 0; height: 70px;
background: rgba(250,238,218,0.98); border-bottom: 2px solid var(--amber);
display: flex; align-items: center; justify-content: space-between; padding: 0 40px; z-index: 1000;
}
.header-logo {
font-family: 'Syne', sans-serif; font-size: 16px; font-weight: 700;
background: linear-gradient(135deg, var(--amber), var(--coral-mid));
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.wrap { max-width: 1200px; margin: 0 auto; padding: 2rem; }
h1 { font-family: 'Syne', sans-serif; font-size: 24px; font-weight: 800; }
.login-box {
max-width: 360px; margin: 80px auto; background: white; border: 1px solid var(--border);
border-radius: 16px; padding: 2rem; text-align: center;
}
.login-box input[type="password"] {
width: 100%; padding: 12px 16px; border: 1.5px solid var(--border); border-radius: 10px;
font-size: 15px; margin: 1rem 0;
}
.login-box button, .btn {
font-family: 'Syne', sans-serif; font-size: 13px; font-weight: 700; letter-spacing: 0.05em;
text-transform: uppercase; background: var(--amber); color: white; border: none;
border-radius: 30px; padding: 10px 24px; cursor: pointer;
}
.error-msg { color: var(--coral); font-size: 13px; margin-bottom: 0.5rem; }
table.results { width: 100%; border-collapse: collapse; background: white; border-radius: 12px; overflow: hidden; border: 1px solid var(--border); font-size: 13px; }
table.results th {
background: var(--amber-light); color: var(--amber-dark); font-family: 'Syne', sans-serif;
font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
padding: 10px 14px; text-align: left; border-bottom: 2px solid var(--amber);
}
table.results td { padding: 10px 14px; border-bottom: 1px solid var(--border); vertical-align: top; }
table.results tr:hover { background: #FAFAFA; }
.detail-toggle { cursor: pointer; color: var(--amber-dark); font-weight: 700; text-decoration: underline; background: none; border: none; font-family: 'DM Sans', sans-serif; font-size: 13px; }
.detail-row { display: none; }
.detail-row.open { display: table-row; }
.detail-content { background: #FAFAFA; padding: 16px 24px; }
.detail-content h3 { font-family: 'Syne', sans-serif; font-size: 13px; margin: 14px 0 6px; color: var(--amber-dark); }
.detail-content p { margin: 4px 0; font-size: 13px; line-height: 1.5; }
.topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
.count-badge { background: var(--amber-light); color: var(--amber-dark); padding: 6px 14px; border-radius: 20px; font-size: 12px; font-weight: 700; font-family: 'Syne', sans-serif; }
.risk-mini { width: 100%; border-collapse: collapse; margin-top: 4px; }
.risk-mini td { border: 1px solid var(--border); padding: 4px 8px; font-size: 12px; }
</style>
</head>
<body>
<nav class="nav-header">
<span class="header-logo">NextGN Formation — Admin</span>
</nav>
<div class="wrap">
<%
If Not authenticated Then
%>
<div class="login-box">
<h1 style="font-size:18px;">Accès résultats TP</h1>
<% If Request.Form("password") <> "" Then %>
<div class="error-msg">Mot de passe incorrect.</div>
<% End If %>
<form method="POST">
<input type="password" name="password" placeholder="Mot de passe" autofocus>
<br>
<button type="submit">Se connecter</button>
</form>
</div>
<%
Else
Dim conn, rs
Set conn = Server.CreateObject("ADODB.Connection")
On Error Resume Next
conn.Open connString
If Err.Number <> 0 Then
%>
<p style="color:var(--coral);">Erreur de connexion à la base : <%= HtmlEscape(Err.Description) %></p>
<%
Else
Err.Clear
Set rs = conn.Execute("SELECT * FROM tp_resultats ORDER BY date_enregistrement DESC")
If Err.Number <> 0 Then
%>
<p style="color:var(--coral);">La table tp_resultats n'existe pas encore — aucun envoi reçu pour le moment.</p>
<%
Else
%>
<div class="topbar">
<h1>Résultats des stagiaires</h1>
<span class="count-badge"><%= IIf_Count(rs) %></span>
</div>
<table class="results">
<tr>
<th>Groupe / Stagiaire</th>
<th>Date session</th>
<th>Cas pratique</th>
<th>Reçu le</th>
<th>Détail</th>
</tr>
<%
Dim rowIndex
rowIndex = 0
Do While Not rs.EOF
rowIndex = rowIndex + 1
%>
<tr>
<td><%= HtmlEscape(rs("nom")) %></td>
<td><%= HtmlEscape(rs("date_session")) %></td>
<td><%= HtmlEscape(rs("cas_choisi")) %></td>
<td><%= HtmlEscape(rs("date_enregistrement")) %></td>
<td><button class="detail-toggle" onclick="toggleDetail(<%= rowIndex %>)">Voir le détail</button></td>
</tr>
<tr class="detail-row" id="detail-<%= rowIndex %>">
<td colspan="5">
<div class="detail-content">
<h3>Réponses TP1 &amp; TP2</h3>
<%= RenderReponses(rs("reponses_json")) %>
<h3>TP3 — Analyse de risques</h3>
<p><strong>Intitulé :</strong> <%= HtmlEscape(rs("tp3_intitule")) %></p>
<p><strong>Description :</strong> <%= HtmlEscape(rs("tp3_description")) %></p>
<p><strong>Lieu :</strong> <%= HtmlEscape(rs("tp3_lieu")) %></p>
<p><strong>Début prévu :</strong> <%= HtmlEscape(rs("tp3_debut")) %></p>
<%= RenderTableau(rs("tp3_tableau_json")) %>
<p><strong>Réalisée par :</strong> <%= HtmlEscape(rs("tp3_realise_par")) %> —
<strong>Vérifiée par :</strong> <%= HtmlEscape(rs("tp3_verifie_par")) %> —
<strong>MAJ par :</strong> <%= HtmlEscape(rs("tp3_maj_par")) %></p>
</div>
</td>
</tr>
<%
rs.MoveNext
Loop
%>
</table>
<%
End If
conn.Close
End If
End If
%>
</div>
<script>
function toggleDetail(i) {
var row = document.getElementById('detail-' + i);
row.classList.toggle('open');
}
</script>
</body>
</html>
<%
Function IIf_Count(rs)
Dim n
n = 0
Do While Not rs.EOF
n = n + 1
rs.MoveNext
Loop
rs.MoveFirst
IIf_Count = n & " envoi(s)"
End Function
' --- Parsing JSON minimal via ScriptControl pour l'affichage admin ---
Function RenderReponses(jsonStr)
Dim out
out = ""
If Trim(jsonStr) = "" Then
RenderReponses = "<p><em>Aucune réponse.</em></p>"
Exit Function
End If
Dim sc
Set sc = Server.CreateObject("MSScriptControl.ScriptControl")
sc.Language = "JScript"
sc.AddCode "function parseArr(s){ return eval('(' + s + ')'); }"
On Error Resume Next
Dim arr
Set arr = sc.Run("parseArr", jsonStr)
If Err.Number <> 0 Then
RenderReponses = "<p><em>Erreur de lecture des réponses.</em></p>"
Exit Function
End If
On Error Goto 0
Dim i
For i = 0 To arr.length - 1
Dim q, r
q = arr.Item(i).question
r = arr.Item(i).reponse
If Trim(r) = "" Then r = "(sans réponse)"
out = out & "<p><strong>" & ServerHtmlEscape(q) & " :</strong> " & ServerHtmlEscape(r) & "</p>"
Next
RenderReponses = out
End Function
Function RenderTableau(jsonStr)
Dim out
out = ""
If Trim(jsonStr) = "" Then
RenderTableau = ""
Exit Function
End If
Dim sc
Set sc = Server.CreateObject("MSScriptControl.ScriptControl")
sc.Language = "JScript"
sc.AddCode "function parseArr(s){ return eval('(' + s + ')'); }"
On Error Resume Next
Dim arr
Set arr = sc.Run("parseArr", jsonStr)
If Err.Number <> 0 Then
RenderTableau = "<p><em>Erreur de lecture du tableau.</em></p>"
Exit Function
End If
On Error Goto 0
out = "<table class='risk-mini'><tr><th>Étape</th><th>Risque</th><th>Mesure</th></tr>"
Dim i
For i = 0 To arr.length - 1
out = out & "<tr><td>" & ServerHtmlEscape(arr.Item(i).etape) & "</td><td>" & _
ServerHtmlEscape(arr.Item(i).risque) & "</td><td>" & _
ServerHtmlEscape(arr.Item(i).mesure) & "</td></tr>"
Next
out = out & "</table>"
RenderTableau = out
End Function
Function ServerHtmlEscape(s)
If IsNull(s) Then
ServerHtmlEscape = ""
Exit Function
End If
s = CStr(s)
s = Replace(s, "&", "&amp;")
s = Replace(s, "<", "&lt;")
s = Replace(s, ">", "&gt;")
ServerHtmlEscape = s
End Function
%>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
# API du classement Memory (ASP.NET + SQL Server)
Petit service **ASP.NET (C#) + SQL Server** qui héberge en ligne le
**classement partagé** du jeu Memory. Tous les joueurs enregistrent leurs
scores au même endroit et voient le même top 10 par mode (facile / normal /
difficile).
> Adapté à l'hébergement **FreeASPHosting.net / bsite.net** (Windows, IIS,
> base MSSQL 2016). Le fichier `scores.ashx` est compilé au vol par IIS :
> **aucune étape de build**, il suffit de le déposer.
## Contenu
| Fichier | Rôle |
|---|---|
| `scores.ashx` | Point d'entrée de l'API (GET pour lire, POST pour enregistrer). Crée la table automatiquement au premier appel. |
| `web.config.example` | Modèle de configuration à copier en `web.config`. |
| `web.config` | **À créer sur le serveur** avec le mot de passe SQL Server (clé `MemoryDb`). Non versionné. |
| `README.md` | Ce fichier. |
## Installation sur bsite.net
1. **Récupérer le mot de passe** de la base dans le panneau
*Manage Databases*. La base existe déjà :
- Serveur : `sql.bsite.net\MSSQL2016`
- Base / utilisateur : `nextgnformation_reponses_exercices`
2. **Créer `web.config`** à partir du modèle (`cp web.config.example web.config`),
puis remplacer `VOTRE_MOT_DE_PASSE` par le mot de passe réel dans la clé
`MemoryDb`.
3. **Déposer le dossier `api/`** via *My Files*, au même endroit que
`memory.html` (chemin attendu par le jeu :
`exercices/memory-pictogrammes/api/scores.ashx`).
4. C'est prêt : au premier score enregistré (ou premier appel GET), la table
`memory_scores` est créée automatiquement.
## Vérification rapide
- Lecture du classement :
`GET https://nextgnformation.bsite.net/exercices/memory-pictogrammes/api/scores.ashx?difficulty=all`
doit renvoyer `{"ok":true,"scores":[...]}`.
- Seuls les 10 meilleurs de chaque mode sont conservés : après chaque
enregistrement, les scores hors top 10 du mode concerné sont supprimés.
## Points d'attention
- **Ne poussez jamais `web.config` avec le vrai mot de passe dans un dépôt
public.** Éditez-le directement sur le serveur via *My Files*.
- Les statistiques personnelles (« Vos statistiques ») restent stockées
localement dans le navigateur de chaque joueur ; seul le classement est en ligne.
- Le score étant calculé côté navigateur, l'API valide les types et les bornes
mais ne garantit pas l'absence de triche (recalcul serveur possible plus tard).

View File

@@ -0,0 +1,329 @@
<%@ WebHandler Language="C#" Class="ScoresHandler" %>
/*
* API du classement Memory (pictogrammes de sécurité) — ASP.NET + SQL Server.
*
* GET scores.ashx?difficulty=easy|normal|hard|all[&limit=10]
* -> renvoie le classement (top N) trié par score décroissant.
*
* POST scores.ashx (corps JSON)
* { playerName, userId, score, moves, timeSeconds, difficulty, isPerfect }
* -> enregistre le score, ne conserve que le top N par difficulté,
* renvoie { ok, saved, rank, isTop }.
*
* Seul le top N (défaut 10) de chaque mode est conservé : les scores plus
* faibles sont supprimés après chaque insertion.
*
* Fichier compilé au vol par IIS : il suffit de le déposer, aucune build.
* La chaîne de connexion est lue dans web.config (clé "MemoryDb").
*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Configuration;
using System.Web.Script.Serialization;
public class ScoresHandler : IHttpHandler
{
static readonly string[] Difficulties = { "easy", "normal", "hard" };
const int TopN = 10;
public bool IsReusable { get { return false; } }
public void ProcessRequest(HttpContext ctx)
{
ctx.Response.ContentType = "application/json; charset=utf-8";
ctx.Response.AddHeader("X-Content-Type-Options", "nosniff");
var connString = WebConfigurationManager.ConnectionStrings["MemoryDb"] != null
? WebConfigurationManager.ConnectionStrings["MemoryDb"].ConnectionString
: null;
if (string.IsNullOrEmpty(connString))
{
Fail(ctx, 500, "Configuration manquante (connectionString 'MemoryDb' dans web.config).");
return;
}
try
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
EnsureTable(conn);
if (ctx.Request.HttpMethod == "GET")
{
HandleGet(ctx, conn);
}
else if (ctx.Request.HttpMethod == "POST")
{
HandlePost(ctx, conn);
}
else
{
ctx.Response.StatusCode = 405;
ctx.Response.AddHeader("Allow", "GET, POST");
Write(ctx, new Dictionary<string, object> {
{ "ok", false }, { "error", "Méthode non autorisée." }
});
}
}
}
catch (Exception)
{
Fail(ctx, 500, "Erreur serveur.");
}
}
// --- Création de la table si besoin -------------------------------------
void EnsureTable(SqlConnection conn)
{
const string sql =
"IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'memory_scores') " +
"CREATE TABLE memory_scores (" +
" id INT IDENTITY(1,1) PRIMARY KEY," +
" player_name NVARCHAR(40) NOT NULL," +
" user_id NVARCHAR(64) NOT NULL," +
" score INT NOT NULL," +
" moves INT NOT NULL," +
" time_seconds INT NOT NULL," +
" difficulty NVARCHAR(16) NOT NULL," +
" is_perfect BIT NOT NULL DEFAULT 0," +
" created_at DATETIME NOT NULL" +
");";
using (var cmd = new SqlCommand(sql, conn)) { cmd.ExecuteNonQuery(); }
}
// --- GET : renvoie le classement ----------------------------------------
void HandleGet(HttpContext ctx, SqlConnection conn)
{
var difficulty = (ctx.Request.QueryString["difficulty"] ?? "all").Trim();
int limit;
if (!int.TryParse(ctx.Request.QueryString["limit"], out limit)) limit = TopN;
if (limit < 1) limit = 1;
if (limit > TopN) limit = TopN;
var rows = new List<Dictionary<string, object>>();
if (difficulty == "all")
{
foreach (var diff in Difficulties)
rows.AddRange(FetchTop(conn, diff, TopN));
rows.Sort(CompareRows);
if (rows.Count > limit) rows = rows.GetRange(0, limit);
}
else
{
if (Array.IndexOf(Difficulties, difficulty) < 0)
{
Fail(ctx, 400, "Difficulté inconnue.");
return;
}
rows = FetchTop(conn, difficulty, limit);
}
Write(ctx, new Dictionary<string, object> { { "ok", true }, { "scores", rows } });
}
// --- POST : enregistre un score puis élague au top N --------------------
void HandlePost(HttpContext ctx, SqlConnection conn)
{
string body;
using (var reader = new StreamReader(ctx.Request.InputStream, Encoding.UTF8))
body = reader.ReadToEnd();
Dictionary<string, object> data = null;
try { data = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(body); }
catch { data = null; }
if (data == null)
{
Fail(ctx, 400, "Corps JSON invalide.");
return;
}
var difficulty = Str(data, "difficulty");
if (Array.IndexOf(Difficulties, difficulty) < 0)
{
Fail(ctx, 400, "Difficulté inconnue.");
return;
}
// Nettoyage / bornage des entrées
var playerName = Str(data, "playerName").Trim();
playerName = StripControlChars(playerName);
if (playerName.Length == 0) playerName = "Anonyme";
if (playerName.Length > 40) playerName = playerName.Substring(0, 40);
var userId = OnlyIdChars(Str(data, "userId"));
if (userId.Length > 64) userId = userId.Substring(0, 64);
if (userId.Length == 0) userId = "anon";
int score = Clamp(Int(data, "score"), 0, 100000000);
int moves = Clamp(Int(data, "moves"), 0, 100000);
int time = Clamp(Int(data, "timeSeconds"), 0, 1000000);
int isPerfect = Bool(data, "isPerfect") ? 1 : 0;
int insertedId;
using (var cmd = new SqlCommand(
"INSERT INTO memory_scores " +
"(player_name, user_id, score, moves, time_seconds, difficulty, is_perfect, created_at) " +
"OUTPUT INSERTED.id " +
"VALUES (@name, @uid, @score, @moves, @time, @diff, @perfect, GETUTCDATE())", conn))
{
cmd.Parameters.Add("@name", SqlDbType.NVarChar, 40).Value = playerName;
cmd.Parameters.Add("@uid", SqlDbType.NVarChar, 64).Value = userId;
cmd.Parameters.Add("@score", SqlDbType.Int).Value = score;
cmd.Parameters.Add("@moves", SqlDbType.Int).Value = moves;
cmd.Parameters.Add("@time", SqlDbType.Int).Value = time;
cmd.Parameters.Add("@diff", SqlDbType.NVarChar, 16).Value = difficulty;
cmd.Parameters.Add("@perfect", SqlDbType.Bit).Value = isPerfect;
insertedId = (int)cmd.ExecuteScalar();
}
// Ne conserver que le top N pour ce mode
using (var cmd = new SqlCommand(
"WITH ranked AS (" +
" SELECT id, ROW_NUMBER() OVER (" +
" PARTITION BY difficulty ORDER BY score DESC, time_seconds ASC, id ASC) AS rn" +
" FROM memory_scores WHERE difficulty = @diff" +
") DELETE FROM memory_scores WHERE id IN (SELECT id FROM ranked WHERE rn > @topN)", conn))
{
cmd.Parameters.Add("@diff", SqlDbType.NVarChar, 16).Value = difficulty;
cmd.Parameters.Add("@topN", SqlDbType.Int).Value = TopN;
cmd.ExecuteNonQuery();
}
// Le score inséré a-t-il survécu à l'élagage ? Quel rang ?
var top = FetchTop(conn, difficulty, TopN);
int? rank = null;
for (int i = 0; i < top.Count; i++)
{
if ((int)top[i]["id"] == insertedId) { rank = i + 1; break; }
}
Write(ctx, new Dictionary<string, object> {
{ "ok", true },
{ "saved", true },
{ "isTop", rank.HasValue },
{ "rank", rank.HasValue ? (object)rank.Value : null }
});
}
// --- Accès données -------------------------------------------------------
List<Dictionary<string, object>> FetchTop(SqlConnection conn, string difficulty, int limit)
{
var result = new List<Dictionary<string, object>>();
using (var cmd = new SqlCommand(
"SELECT TOP (@limit) id, player_name, user_id, score, moves, time_seconds, " +
"difficulty, is_perfect, created_at " +
"FROM memory_scores WHERE difficulty = @diff " +
"ORDER BY score DESC, time_seconds ASC, id ASC", conn))
{
cmd.Parameters.Add("@limit", SqlDbType.Int).Value = limit;
cmd.Parameters.Add("@diff", SqlDbType.NVarChar, 16).Value = difficulty;
using (var r = cmd.ExecuteReader())
{
while (r.Read())
{
result.Add(new Dictionary<string, object> {
{ "id", (int)r["id"] },
{ "playerName", r["player_name"].ToString() },
{ "userId", r["user_id"].ToString() },
{ "score", (int)r["score"] },
{ "moves", (int)r["moves"] },
{ "timeSeconds", (int)r["time_seconds"] },
{ "difficulty", r["difficulty"].ToString() },
{ "isPerfect", Convert.ToBoolean(r["is_perfect"]) },
{ "date", ((DateTime)r["created_at"]).ToString("yyyy-MM-ddTHH:mm:ss") + "Z" }
});
}
}
}
return result;
}
int CompareRows(Dictionary<string, object> a, Dictionary<string, object> b)
{
int sa = (int)a["score"], sb = (int)b["score"];
if (sa != sb) return sb - sa;
return (int)a["timeSeconds"] - (int)b["timeSeconds"];
}
// --- Sérialisation / helpers --------------------------------------------
void Write(HttpContext ctx, object payload)
{
// On retire la clé "id" (interne) des lignes avant l'envoi.
var scrubbed = Scrub(payload);
ctx.Response.Write(new JavaScriptSerializer().Serialize(scrubbed));
}
object Scrub(object payload)
{
var dict = payload as Dictionary<string, object>;
if (dict != null && dict.ContainsKey("scores"))
{
var list = dict["scores"] as List<Dictionary<string, object>>;
if (list != null)
foreach (var row in list) row.Remove("id");
}
return payload;
}
void Fail(HttpContext ctx, int status, string message)
{
ctx.Response.StatusCode = status;
ctx.Response.Write(new JavaScriptSerializer().Serialize(
new Dictionary<string, object> { { "ok", false }, { "error", message } }));
}
static string Str(Dictionary<string, object> d, string key)
{
object v; return (d.TryGetValue(key, out v) && v != null) ? v.ToString() : "";
}
static int Int(Dictionary<string, object> d, string key)
{
object v; int n;
if (d.TryGetValue(key, out v) && v != null && int.TryParse(v.ToString(), out n)) return n;
return 0;
}
static bool Bool(Dictionary<string, object> d, string key)
{
object v;
if (!d.TryGetValue(key, out v) || v == null) return false;
if (v is bool) return (bool)v;
var s = v.ToString().ToLowerInvariant();
return s == "true" || s == "1";
}
static int Clamp(int value, int min, int max)
{
if (value < min) return min;
if (value > max) return max;
return value;
}
static string StripControlChars(string s)
{
var sb = new StringBuilder(s.Length);
foreach (var c in s) if (!char.IsControl(c)) sb.Append(c);
return sb.ToString();
}
static string OnlyIdChars(string s)
{
var sb = new StringBuilder(s.Length);
foreach (var c in s)
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-')
sb.Append(c);
return sb.ToString();
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
MODÈLE de configuration. Sur le serveur bsite.net :
1. Copiez ce fichier en « web.config ».
2. Renseignez le mot de passe fourni par le panneau « Manage Databases ».
Le vrai « web.config » n'est PAS versionné (voir .gitignore) afin de ne
jamais exposer le mot de passe dans l'historique Git.
-->
<connectionStrings>
<add name="MemoryDb"
connectionString="Server=sql.bsite.net\MSSQL2016;Database=nextgnformation_reponses_exercices;User Id=nextgnformation_reponses_exercices;Password=VOTRE_MOT_DE_PASSE;"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>

View File

@@ -44,15 +44,15 @@
@keyframes matchSuccess {
0% {
transform: scale(1);
filter: drop-shadow(0 0 0px rgba(76, 175, 80, 0.6));
filter: drop-shadow(0 0 0px rgba(29, 158, 117, 0.6));
}
50% {
transform: scale(1.15) rotate(5deg);
filter: drop-shadow(0 0 12px rgba(76, 175, 80, 0.8));
filter: drop-shadow(0 0 12px rgba(29, 158, 117, 0.8));
}
100% {
transform: scale(1);
filter: drop-shadow(0 0 0px rgba(76, 175, 80, 0));
filter: drop-shadow(0 0 0px rgba(29, 158, 117, 0));
}
}
@@ -101,14 +101,14 @@
/* Pulse Progress Bar */
@keyframes progressPulse {
0%, 100% {
box-shadow: 0 0 8px rgba(29, 158, 117, 0.4);
box-shadow: 0 0 8px rgba(186, 117, 23, 0.4);
}
50% {
box-shadow: 0 0 24px rgba(29, 158, 117, 0.8);
box-shadow: 0 0 24px rgba(186, 117, 23, 0.8);
}
}
.progress-bar.pulse {
.game-progress-fill.pulse {
animation: progressPulse 0.6s ease-out;
}
@@ -189,7 +189,7 @@
@keyframes statUpdate {
0% {
transform: scale(0.8);
background: rgba(29, 158, 117, 0.2);
background: rgba(186, 117, 23, 0.2);
}
100% {
transform: scale(1);
@@ -255,10 +255,10 @@
/* Card glow hover */
@keyframes glowCard {
0% {
box-shadow: 0 0 0px rgba(29, 158, 117, 0);
box-shadow: 0 0 0px rgba(186, 117, 23, 0);
}
100% {
box-shadow: 0 0 16px rgba(29, 158, 117, 0.3);
box-shadow: 0 0 16px rgba(186, 117, 23, 0.3);
}
}
@@ -281,10 +281,10 @@
/* Pulse button */
@keyframes buttonPulse {
0%, 100% {
box-shadow: 0 0 0px rgba(29, 158, 117, 0.7);
box-shadow: 0 0 0px rgba(186, 117, 23, 0.7);
}
50% {
box-shadow: 0 0 16px rgba(29, 158, 117, 0.4);
box-shadow: 0 0 16px rgba(186, 117, 23, 0.4);
}
}

View File

@@ -7,15 +7,14 @@
============================================ */
.game-hud {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
grid-template-columns: repeat(4, minmax(120px, 1fr));
gap: 16px;
margin-bottom: 32px;
animation: fadeInUp 0.6s ease-out 0.4s both;
flex: 1;
}
.stat-box {
background: linear-gradient(135deg, var(--teal-light), var(--white));
border: 2px solid var(--teal-mid);
background: linear-gradient(135deg, var(--amber-light), var(--white));
border: 2px solid var(--amber-mid);
border-radius: 12px;
padding: 20px;
text-align: center;
@@ -38,7 +37,7 @@
.stat-box:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
border-color: var(--teal-dark);
border-color: var(--amber-dark);
}
.stat-box:hover::before {
@@ -57,7 +56,7 @@
.stat-box .value {
font-size: 32px;
font-weight: 800;
background: linear-gradient(135deg, var(--teal-mid), var(--teal-dark));
background: linear-gradient(135deg, var(--amber-mid), var(--amber-dark));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
@@ -73,7 +72,7 @@
PROGRESS BAR (Paires trouvées)
============================================ */
.progress-container {
background: var(--teal-light);
background: var(--amber-light);
border-radius: 12px;
overflow: hidden;
height: 12px;
@@ -82,14 +81,14 @@
box-shadow: var(--shadow-sm);
}
.progress-bar {
.game-progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--teal-mid), var(--teal-dark));
background: linear-gradient(90deg, var(--amber-mid), var(--amber-dark));
width: 0%;
transition: width 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.progress-container.pulse .progress-bar {
.progress-container.pulse .game-progress-fill {
animation: progressPulse 0.6s ease-out;
}
@@ -148,15 +147,15 @@
}
.modal-content {
background: linear-gradient(135deg, var(--white), var(--teal-light));
border-radius: 24px;
background: linear-gradient(135deg, var(--white), var(--amber-light));
border-radius: 12px;
padding: 48px;
max-width: 500px;
width: 100%;
text-align: center;
animation: slideUp 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
border: 2px solid var(--teal-mid);
box-shadow: 0 32px 64px rgba(15, 110, 86, 0.3);
border: 2px solid var(--amber-mid);
box-shadow: 0 32px 64px rgba(186, 117, 23, 0.3);
position: relative;
overflow: hidden;
}
@@ -177,7 +176,7 @@
font-family: 'Syne', sans-serif;
font-size: 42px;
font-weight: 800;
color: var(--teal);
color: var(--amber);
margin: 32px 0 12px;
position: relative;
z-index: 1;
@@ -186,7 +185,7 @@
.modal-content .score-display {
font-size: 64px;
font-weight: 800;
background: linear-gradient(135deg, var(--teal-mid), var(--teal-dark));
background: linear-gradient(135deg, var(--amber-mid), var(--amber-dark));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
@@ -203,10 +202,10 @@
}
.stats-summary .stat {
background: var(--teal-light);
background: var(--amber-light);
padding: 12px;
border-radius: 8px;
border: 1px solid var(--teal-mid);
border: 1px solid var(--amber-mid);
animation: popIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@@ -217,7 +216,7 @@
.stats-summary .stat-value {
font-weight: 700;
color: var(--teal-dark);
color: var(--amber-dark);
font-size: 16px;
font-family: 'Syne', sans-serif;
}
@@ -230,6 +229,41 @@
margin-top: 4px;
}
/* ============================================
PLAYER NAME MODAL
============================================ */
.name-modal-content h2 {
margin-top: 32px;
}
.name-modal-text {
color: var(--text-muted);
font-size: 14px;
line-height: 1.5;
margin-bottom: 24px;
position: relative;
z-index: 1;
}
.name-input {
width: 100%;
padding: 14px 16px;
font-size: 16px;
font-family: 'DM Sans', sans-serif;
border: 2px solid var(--amber-mid);
border-radius: 8px;
background: var(--white);
color: var(--text);
text-align: center;
box-sizing: border-box;
}
.name-input:focus {
outline: none;
border-color: var(--amber-dark);
box-shadow: 0 0 0 3px rgba(186, 117, 23, 0.15);
}
/* ============================================
ACHIEVEMENTS
============================================ */
@@ -289,52 +323,6 @@
min-width: 140px;
}
/* ============================================
PAUSE MODAL
============================================ */
.pause-modal {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
z-index: 1999;
backdrop-filter: blur(5px);
}
.pause-content {
background: var(--white);
border-radius: 16px;
padding: 40px;
text-align: center;
border: 2px solid var(--teal-mid);
animation: slideUp 0.4s ease-out;
}
.pause-content h2 {
font-family: 'Syne', sans-serif;
font-size: 32px;
color: var(--teal);
margin-bottom: 24px;
}
.pause-content .pause-timer {
font-size: 48px;
font-family: 'Syne', sans-serif;
font-weight: 800;
color: var(--teal-dark);
margin-bottom: 24px;
animation: timerTick 0.5s ease-out;
}
.pause-actions {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
}
/* ============================================
RESPONSIVE DESIGN
============================================ */

View File

@@ -2,18 +2,25 @@
LEADERBOARD & PLAYER STATS
============================================ */
.leaderboard-section {
margin-top: 80px;
.leaderboard-panel {
animation: fadeInUp 0.6s ease-out 0.6s both;
text-align: center;
}
.stats-panel {
animation: fadeInUp 0.6s ease-out 0.6s both;
}
.leaderboard-section h2 {
.leaderboard-panel h2 {
font-family: 'Syne', sans-serif;
font-size: clamp(24px, 5vw, 32px);
font-size: clamp(20px, 4vw, 26px);
font-weight: 800;
color: var(--teal);
margin-bottom: 24px;
text-align: center;
letter-spacing: -0.5px;
color: var(--text);
margin: 0 auto 24px;
padding-bottom: 12px;
border-bottom: 3px solid var(--amber-mid);
display: inline-block;
}
/* ============================================
@@ -30,7 +37,7 @@
.tab-btn {
padding: 10px 20px;
background: var(--white);
border: 2px solid var(--teal-light);
border: 2px solid var(--amber-light);
border-radius: 8px;
font-family: 'Syne', sans-serif;
font-size: 12px;
@@ -43,13 +50,13 @@
}
.tab-btn:hover {
border-color: var(--teal-mid);
color: var(--teal-mid);
border-color: var(--amber-mid);
color: var(--amber-mid);
}
.tab-btn.active {
background: linear-gradient(135deg, var(--teal-mid), var(--teal-dark));
border-color: var(--teal-dark);
background: linear-gradient(135deg, var(--amber-mid), var(--amber-dark));
border-color: var(--amber-dark);
color: var(--white);
box-shadow: var(--shadow-md);
}
@@ -58,12 +65,13 @@
LEADERBOARD LIST
============================================ */
.leaderboard {
background: linear-gradient(135deg, var(--teal-light), var(--white));
border-radius: 16px;
background: linear-gradient(135deg, var(--amber-light), var(--white));
border-radius: 12px;
padding: 24px;
border: 2px solid var(--teal-mid);
border: 2px solid var(--amber-mid);
margin-bottom: 48px;
box-shadow: var(--shadow-sm);
text-align: left;
}
.leaderboard-list {
@@ -73,19 +81,32 @@
}
.rank-item {
display: grid;
grid-template-columns: 50px 1fr auto auto;
align-items: center;
gap: 16px;
display: flex;
flex-direction: column;
gap: 8px;
background: var(--white);
padding: 16px;
padding: 14px;
border-radius: 8px;
transition: all 0.3s ease;
border-left: 4px solid var(--teal-light);
border-left: 4px solid var(--amber-light);
position: relative;
overflow: hidden;
}
/* Ligne du joueur courant dans le classement */
.rank-item.is-me {
border-left-color: var(--amber-dark);
background: linear-gradient(135deg, var(--amber-light), var(--white));
box-shadow: 0 2px 8px rgba(186, 117, 23, 0.15);
}
.rank-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.rank-item::before {
content: '';
position: absolute;
@@ -93,14 +114,14 @@
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(29, 158, 117, 0.1), transparent);
background: linear-gradient(90deg, transparent, rgba(186, 117, 23, 0.1), transparent);
transition: left 0.5s ease;
}
.rank-item:hover {
transform: translateX(8px);
box-shadow: 0 4px 12px rgba(15, 110, 86, 0.15);
border-left-color: var(--teal-mid);
box-shadow: 0 4px 12px rgba(186, 117, 23, 0.15);
border-left-color: var(--amber-mid);
}
.rank-item:hover::before {
@@ -111,35 +132,21 @@
.rank-number {
font-weight: 800;
font-size: 18px;
color: var(--teal-mid);
color: var(--amber-mid);
text-align: center;
font-family: 'Syne', sans-serif;
}
.rank-number.medal-1 {
font-size: 24px;
}
.rank-number.medal-1::before {
content: '🥇';
display: block;
}
.rank-number.medal-2::before {
content: '🥈';
display: block;
font-size: 20px;
}
.rank-number.medal-3::before {
content: '🥉';
display: block;
font-size: 20px;
.rank-number.medal-1,
.rank-number.medal-2,
.rank-number.medal-3 {
font-size: 22px;
}
/* Infos joueur */
.rank-info {
flex: 1;
min-width: 0;
}
.player-name {
@@ -147,17 +154,20 @@
color: var(--text);
margin-bottom: 4px;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.player-stats {
font-size: 12px;
.rank-meta {
font-size: 11px;
color: var(--text-muted);
display: flex;
gap: 12px;
gap: 10px;
flex-wrap: wrap;
}
.player-stats span {
.rank-meta span {
display: inline-flex;
align-items: center;
gap: 4px;
@@ -166,39 +176,11 @@
/* Score et difficulté */
.rank-score {
font-weight: 700;
color: var(--teal-dark);
font-size: 18px;
color: var(--amber-dark);
font-size: 16px;
font-family: 'Syne', sans-serif;
min-width: 60px;
text-align: right;
}
.rank-difficulty {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 4px 8px;
border-radius: 4px;
background: var(--teal-light);
color: var(--teal-dark);
min-width: 60px;
text-align: center;
}
.rank-difficulty.easy {
background: #C8E6C9;
color: #2E7D32;
}
.rank-difficulty.normal {
background: var(--teal-light);
color: var(--teal-dark);
}
.rank-difficulty.hard {
background: #FFCCBC;
color: #D84315;
flex-shrink: 0;
}
/* Message si pas de scores */
@@ -227,32 +209,32 @@
PLAYER STATS SECTION
============================================ */
.player-stats {
background: linear-gradient(135deg, rgba(15, 110, 86, 0.05), transparent);
border-radius: 16px;
padding: 32px;
border: 2px solid var(--teal-light);
background: linear-gradient(135deg, rgba(186, 117, 23, 0.05), transparent);
border-radius: 12px;
padding: 24px;
border: 2px solid var(--amber-light);
}
.player-stats h3 {
font-family: 'Syne', sans-serif;
font-size: 24px;
font-size: 18px;
font-weight: 700;
color: var(--teal);
margin-bottom: 24px;
color: var(--amber);
margin-bottom: 16px;
text-align: center;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.stat-card {
background: var(--white);
border: 2px solid var(--teal-light);
border-radius: 12px;
padding: 20px;
border: 2px solid var(--amber-light);
border-radius: 10px;
padding: 14px 8px;
text-align: center;
transition: all 0.3s ease;
display: flex;
@@ -263,27 +245,27 @@
.stat-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-md);
border-color: var(--teal-mid);
border-color: var(--amber-mid);
}
.stat-icon {
font-size: 32px;
margin-bottom: 12px;
font-size: 22px;
margin-bottom: 6px;
}
.stat-label {
font-size: 11px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
margin-bottom: 8px;
margin-bottom: 4px;
}
.stat-value {
font-size: 28px;
font-size: 20px;
font-weight: 800;
background: linear-gradient(135deg, var(--teal-mid), var(--teal-dark));
background: linear-gradient(135deg, var(--amber-mid), var(--amber-dark));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
@@ -291,7 +273,7 @@
}
.stat-card.high-value .stat-value {
font-size: 32px;
font-size: 22px;
animation: popIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@@ -324,7 +306,7 @@
RESPONSIVE DESIGN
============================================ */
@media (max-width: 768px) {
.leaderboard-section h2 {
.leaderboard-panel h2 {
font-size: 24px;
}
@@ -337,15 +319,6 @@
font-size: 11px;
}
.rank-item {
grid-template-columns: 40px 1fr auto;
gap: 12px;
}
.rank-difficulty {
display: none;
}
.rank-number {
font-size: 16px;
}
@@ -355,29 +328,29 @@
}
.player-stats {
padding: 24px;
padding: 20px;
}
.player-stats h3 {
font-size: 20px;
font-size: 18px;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
gap: 10px;
}
.stat-card {
padding: 16px;
padding: 14px 10px;
}
.stat-icon {
font-size: 28px;
margin-bottom: 8px;
font-size: 24px;
margin-bottom: 6px;
}
.stat-value {
font-size: 24px;
font-size: 22px;
}
}
@@ -397,17 +370,10 @@
}
.rank-item {
grid-template-columns: 40px 1fr;
gap: 10px;
gap: 8px;
padding: 12px;
}
.rank-score {
grid-column: 1 / -1;
text-align: left;
margin-top: 8px;
}
.rank-number {
font-size: 14px;
}
@@ -421,22 +387,23 @@
}
.player-stats h3 {
font-size: 18px;
font-size: 16px;
}
.stats-grid {
grid-template-columns: 1fr;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
.stat-card {
padding: 12px;
padding: 12px 8px;
}
.stat-icon {
font-size: 24px;
font-size: 22px;
}
.stat-value {
font-size: 20px;
font-size: 18px;
}
}

View File

@@ -5,15 +5,15 @@
:root {
/* Gamification Colors */
--success: #4CAF50;
--success: var(--teal-mid);
--warning: #FF9800;
--info: #2196F3;
--accent: #FFD700;
/* Shadows */
--shadow-sm: 0 4px 8px rgba(15, 110, 86, 0.1);
--shadow-md: 0 8px 16px rgba(15, 110, 86, 0.15);
--shadow-lg: 0 16px 32px rgba(15, 110, 86, 0.25);
/* Shadows (alignées sur le langage visuel du site) */
--shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.05);
--shadow-md: 0 12px 32px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 20px 50px rgba(0, 0, 0, 0.15);
}
/* ============================================
@@ -21,12 +21,12 @@
============================================ */
main {
margin-top: 70px;
padding: 40px;
padding: 96px 40px 40px;
min-height: calc(100vh - 70px);
}
.game-container {
max-width: 1200px;
max-width: 1440px;
margin: 0 auto;
}
@@ -34,15 +34,16 @@ main {
INTRO SECTION
============================================ */
.intro-section {
margin-bottom: 60px;
animation: fadeInDown 0.6s ease-out;
margin-bottom: 48px;
animation: fadeIn 0.6s ease-out;
text-align: center;
}
.intro-section h1 {
font-family: 'Syne', sans-serif;
font-size: clamp(28px, 5vw, 48px);
font-size: clamp(28px, 5vw, 44px);
font-weight: 800;
color: var(--teal);
color: var(--amber);
margin-bottom: 8px;
text-align: center;
}
@@ -56,11 +57,10 @@ main {
}
.intro-box {
background: linear-gradient(135deg, var(--teal-light), var(--white));
border-left: 4px solid var(--teal-mid);
background: linear-gradient(135deg, var(--amber-light), var(--white));
border-left: 4px solid var(--amber-mid);
border-radius: 8px;
padding: 20px;
margin-bottom: 32px;
font-size: 0.95em;
color: var(--text-muted);
line-height: 1.6;
@@ -70,93 +70,148 @@ main {
text-align: center;
}
/* ============================================
TOP BAR (niveau + stats en temps réel)
============================================ */
.game-top-bar {
max-width: 1440px;
margin: 0 auto 32px;
background: var(--white);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px clamp(20px, 3vw, 36px);
box-shadow: var(--shadow-sm);
display: flex;
align-items: center;
justify-content: space-between;
gap: clamp(20px, 3vw, 40px);
animation: fadeInUp 0.6s ease-out 0.2s both;
}
/* ============================================
GAME LAYOUT (classement / jeu / stats)
============================================ */
.game-layout {
display: grid;
grid-template-columns: minmax(0, 320px) minmax(0, 760px) minmax(0, 320px);
grid-template-areas: "leaderboard game stats";
justify-content: center;
align-items: start;
gap: 32px;
margin-bottom: 80px;
}
.leaderboard-panel {
grid-area: leaderboard;
}
.stats-panel {
grid-area: stats;
}
/* ============================================
GAME SECTION / PANEL
============================================ */
.game-section {
grid-area: game;
animation: fadeInUp 0.6s ease-out 0.3s both;
}
.game-panel {
background: var(--white);
border: 1px solid var(--border);
border-radius: 12px;
padding: clamp(20px, 4vw, 32px);
box-shadow: var(--shadow-sm);
}
/* ============================================
DIFFICULTY SELECTOR
============================================ */
.difficulty-selector {
margin-bottom: 48px;
text-align: center;
animation: fadeInUp 0.6s ease-out 0.2s both;
text-align: left;
flex-shrink: 0;
}
.difficulty-selector label {
display: block;
font-size: 14px;
font-weight: 600;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
letter-spacing: 0.1em;
color: var(--text-muted);
margin-bottom: 16px;
margin-bottom: 14px;
}
.btn-group {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
grid-template-columns: repeat(3, minmax(100px, 1fr));
gap: 12px;
max-width: 500px;
margin: 0 auto;
}
.btn-difficulty {
background: var(--white);
border: 2px solid var(--teal-light);
border-radius: 8px;
padding: 16px 12px;
background: var(--amber-light);
background: linear-gradient(135deg, rgba(250, 238, 218, 0.5), transparent);
border: 2px solid transparent;
border-radius: 12px;
padding: 14px 12px;
font-family: 'Syne', sans-serif;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
gap: 2px;
}
.btn-difficulty:hover {
border-color: var(--teal-mid);
transform: translateY(-4px);
border-color: var(--amber-mid);
transform: translateY(-3px);
box-shadow: var(--shadow-md);
}
.btn-difficulty.active {
background: linear-gradient(135deg, var(--teal-light), var(--white));
border-color: var(--teal-mid);
color: var(--teal);
background: linear-gradient(135deg, var(--amber-mid), var(--amber-dark));
border-color: var(--amber-dark);
box-shadow: var(--shadow-md);
}
.btn-difficulty.active .btn-label,
.btn-difficulty.active .btn-desc {
color: var(--white);
}
.btn-icon {
font-size: 20px;
line-height: 1;
margin-bottom: 2px;
}
.btn-label {
font-size: 14px;
font-weight: 700;
color: var(--teal);
color: var(--amber);
}
.btn-desc {
font-size: 12px;
font-size: 11px;
font-family: 'DM Sans', sans-serif;
color: var(--text-muted);
font-weight: 400;
}
/* ============================================
GAME SECTION
============================================ */
.game-section {
margin-bottom: 80px;
animation: fadeInUp 0.6s ease-out 0.3s both;
}
/* ============================================
GAME GRID & CARDS
============================================ */
.game-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(clamp(70px, 15vw, 140px), 1fr));
gap: clamp(12px, 2vw, 20px);
max-width: 900px;
margin: 0 auto 40px;
grid-template-columns: repeat(auto-fit, minmax(clamp(70px, 15vw, 110px), 1fr));
gap: clamp(10px, 2vw, 16px);
margin: 0 auto 32px;
padding: 20px;
background: linear-gradient(135deg, rgba(225, 245, 238, 0.4), transparent);
border-radius: 16px;
border: 1px solid var(--teal-light);
background: linear-gradient(135deg, rgba(250, 238, 218, 0.4), transparent);
border-radius: 12px;
border: 1px solid var(--amber-light);
}
/* MEMORY CARD STYLES */
@@ -188,16 +243,19 @@ main {
}
.card-face.front {
background: linear-gradient(135deg, var(--teal-light), var(--teal-light));
border: 2px solid var(--teal-mid);
color: var(--teal-dark);
background:
radial-gradient(circle at 30% 25%, rgba(255, 255, 255, 0.6), transparent 60%),
linear-gradient(135deg, var(--amber-mid), var(--amber-dark));
border: 2px solid var(--amber-dark);
color: var(--white);
box-shadow: var(--shadow-sm);
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
.card-face.back {
transform: rotateY(180deg);
background: linear-gradient(135deg, var(--white), var(--teal-light));
border: 2px solid var(--teal-mid);
background: linear-gradient(135deg, var(--white), var(--amber-light));
border: 2px solid var(--amber-mid);
flex-direction: column;
gap: 8px;
padding: 8px;
@@ -246,7 +304,7 @@ main {
}
.memory-card.matched .card-face.back {
background: linear-gradient(135deg, var(--white), rgba(76, 175, 80, 0.2));
background: linear-gradient(135deg, var(--white), rgba(29, 158, 117, 0.2));
border-color: var(--success);
}
@@ -271,26 +329,16 @@ footer {
}
/* ============================================
BUTTONS
BUTTONS (métriques héritées du style général du site)
============================================ */
.btn {
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: linear-gradient(135deg, var(--teal-mid), var(--teal-dark));
background: linear-gradient(135deg, var(--amber-mid), var(--amber-dark));
color: var(--white);
}
@@ -301,21 +349,49 @@ footer {
.btn-secondary {
background: var(--white);
border: 2px solid var(--teal-mid);
color: var(--teal-mid);
border: 2px solid var(--amber-mid);
color: var(--amber-mid);
}
.btn-secondary:hover {
background: var(--teal-light);
border-color: var(--teal-dark);
background: var(--amber-light);
border-color: var(--amber-dark);
}
/* ============================================
RESPONSIVE DESIGN
============================================ */
@media (max-width: 1100px) {
.game-layout {
grid-template-columns: 1fr;
grid-template-areas:
"game"
"leaderboard"
"stats";
gap: 40px;
}
}
@media (max-width: 900px) {
.game-top-bar {
flex-direction: column;
align-items: stretch;
gap: 24px;
}
.difficulty-selector {
text-align: center;
}
.btn-group {
max-width: 520px;
margin: 0 auto;
}
}
@media (max-width: 768px) {
main {
padding: 20px;
padding: 56px 20px 20px;
}
.intro-section h1 {
@@ -345,7 +421,7 @@ footer {
@media (max-width: 480px) {
main {
padding: 16px;
padding: 40px 16px 16px;
}
.intro-section h1 {

View File

@@ -175,7 +175,6 @@ class GameSessionState {
this.moves = 0;
this.score = 0;
this.matched = 0;
this.isPaused = false;
this.gameActive = false;
}
@@ -190,7 +189,6 @@ class GameSessionState {
this.score = 0;
this.matched = 0;
this.gameActive = true;
this.isPaused = false;
}
/**

View File

@@ -1,89 +1,113 @@
/* ============================================
LEADERBOARD & PLAYER STATISTICS
============================================
Le CLASSEMENT est désormais partagé EN LIGNE : tous les joueurs
enregistrent leurs scores via l'API PHP (api/scores.php) et voient le
même top 10 par mode de jeu.
Les STATISTIQUES PERSONNELLES (« Vos statistiques ») restent stockées
localement dans le navigateur du joueur, car le serveur ne conserve que
le top 10 de chaque mode (et non l'historique complet de chacun).
============================================ */
/**
* Manager du classement
*/
class LeaderboardManager {
static KEY_LEADERBOARD = 'nextgn_leaderboard';
static MAX_SCORES = 100;
// Point d'entrée de l'API (relatif à memory.html) — ASP.NET + SQL Server
static API_URL = 'api/scores.ashx';
// Historique local des parties du joueur (pour ses stats perso)
static KEY_HISTORY = 'nextgn_player_history';
static MAX_HISTORY = 500;
// Cache mémoire du dernier classement récupéré (par difficulté)
static _cache = {};
/**
* Ajouter un score au classement
* Enregistrer une partie :
* - envoie le score au classement en ligne
* - conserve la partie dans l'historique local (stats perso)
* @returns {Promise<Object>} résultat de l'API ({ ok, isTop, rank } ou { ok:false })
*/
static addScore(gameData) {
const scores = this.getAllScores();
const newScore = {
sessionId: generateUUID(),
static async addScore(gameData) {
const record = {
playerName: getPlayerName(),
userId: getUserId(),
score: gameData.score,
moves: gameData.moves,
timeSeconds: gameData.duration,
difficulty: gameData.difficulty,
date: new Date().toISOString(),
isPerfect: gameData.moves === DIFFICULTY_MODES[gameData.difficulty].paires,
won: gameData.won !== false
won: gameData.won !== false,
date: new Date().toISOString()
};
scores.push(newScore);
// 1) Historique local (statistiques personnelles)
this._recordLocalHistory(record);
// Limiter à MAX_SCORES (garder les plus récents)
if (scores.length > this.MAX_SCORES) {
scores.sort((a, b) => new Date(b.date) - new Date(a.date));
scores.splice(this.MAX_SCORES);
// 2) Classement en ligne
try {
const res = await fetch(this.API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(record)
});
const data = await res.json();
DEBUG.log('Score submitted:', data);
return data;
} catch (e) {
console.error('Leaderboard submit error:', e);
return { ok: false, error: 'network' };
}
localStorage.setItem(this.KEY_LEADERBOARD, JSON.stringify(scores));
DEBUG.log('Score added:', newScore);
return newScore;
}
/**
* Obtenir tous les scores
* Ajouter la partie à l'historique local du joueur
*/
static getAllScores() {
static _recordLocalHistory(record) {
const history = this._getLocalHistory();
history.push(record);
if (history.length > this.MAX_HISTORY) {
history.splice(0, history.length - this.MAX_HISTORY);
}
try {
const scores = JSON.parse(localStorage.getItem(this.KEY_LEADERBOARD)) || [];
return scores;
localStorage.setItem(this.KEY_HISTORY, JSON.stringify(history));
} catch (e) {
console.error('History save error:', e);
}
}
/**
* Historique local des parties du joueur
*/
static _getLocalHistory() {
try {
return JSON.parse(localStorage.getItem(this.KEY_HISTORY)) || [];
} catch (e) {
console.error('Leaderboard error:', e);
return [];
}
}
/**
* Obtenir le classement (top X)
* Récupérer le classement en ligne (top X) pour un mode donné.
* @returns {Promise<Array>}
*/
static getLeaderboard(difficulty = 'all', limit = 10) {
let scores = this.getAllScores();
// Filtrer par difficulté
if (difficulty !== 'all') {
scores = scores.filter(s => s.difficulty === difficulty);
static async getLeaderboard(difficulty = 'all', limit = 10) {
const url = `${this.API_URL}?difficulty=${encodeURIComponent(difficulty)}&limit=${limit}`;
const res = await fetch(url, { headers: { 'Accept': 'application/json' } });
const data = await res.json();
if (!data || data.ok !== true || !Array.isArray(data.scores)) {
throw new Error('Réponse invalide du serveur');
}
// Trier par score (décroissant)
scores.sort((a, b) => {
if (b.score !== a.score) {
return b.score - a.score;
}
// En cas d'égalité, par temps
return a.timeSeconds - b.timeSeconds;
});
return scores.slice(0, limit);
this._cache[difficulty] = data.scores;
return data.scores;
}
/**
* Obtenir les stats d'un joueur
* Statistiques du joueur, calculées à partir de son historique LOCAL.
*/
static getPlayerStats(userId) {
const scores = this.getAllScores().filter(s => s.userId === userId);
static getPlayerStats() {
const scores = this._getLocalHistory();
if (scores.length === 0) {
return {
@@ -116,61 +140,35 @@ class LeaderboardManager {
}
/**
* Obtenir le rang d'un score
* Mettre à jour l'affichage du classement (asynchrone).
*/
static getPlayerRank(userId, difficulty = 'all') {
const leaderboard = this.getLeaderboard(difficulty, Infinity);
const rank = leaderboard.findIndex(s => s.userId === userId) + 1;
return rank > 0 ? rank : null;
}
/**
* Vérifier si c'est un nouveau record personnel
*/
static isPersonalRecord(userId, newScore) {
const stats = this.getPlayerStats(userId);
return newScore > stats.bestScore;
}
/**
* Obtenir les statistiques globales
*/
static getGlobalStats() {
const scores = this.getAllScores();
if (scores.length === 0) {
return {
totalGames: 0,
totalPlayers: 0,
averageScore: 0,
highestScore: 0,
fastestCompletion: Infinity
};
}
const uniquePlayers = new Set(scores.map(s => s.userId));
const totalScore = scores.reduce((a, b) => a + b.score, 0);
const highestScore = Math.max(...scores.map(s => s.score), 0);
const fastestCompletion = Math.min(...scores.map(s => s.timeSeconds), Infinity);
return {
totalGames: scores.length,
totalPlayers: uniquePlayers.size,
averageScore: Math.round(totalScore / scores.length),
highestScore: highestScore,
fastestCompletion: fastestCompletion === Infinity ? 0 : fastestCompletion
};
}
/**
* Mettre à jour l'affichage du classement
*/
static updateDisplay(difficulty = 'all') {
const leaderboard = this.getLeaderboard(difficulty, 10);
static async updateDisplay(difficulty = 'all') {
const leaderboardList = document.getElementById('leaderboard-list');
if (!leaderboardList) return;
// État de chargement
leaderboardList.innerHTML = `
<div class="empty-state">
<div class="empty-state-icon">⏳</div>
<div class="empty-state-text">Chargement du classement…</div>
</div>
`;
let leaderboard;
try {
leaderboard = await this.getLeaderboard(difficulty, 10);
} catch (e) {
console.error('Leaderboard load error:', e);
leaderboardList.innerHTML = `
<div class="empty-state">
<div class="empty-state-icon">⚠️</div>
<div class="empty-state-text">Classement indisponible</div>
<div class="empty-state-hint">Vérifiez votre connexion et réessayez.</div>
</div>
`;
return;
}
if (leaderboard.length === 0) {
leaderboardList.innerHTML = `
<div class="empty-state">
@@ -182,118 +180,80 @@ class LeaderboardManager {
return;
}
const myUserId = getUserId();
leaderboardList.innerHTML = '';
leaderboard.forEach((score, index) => {
const rankItem = document.createElement('div');
rankItem.className = 'rank-item';
if (score.userId === myUserId) {
rankItem.classList.add('is-me');
}
const rankNumber = this.getRankDisplay(index);
const medal = index < 3 ? `class="rank-number medal-${index + 1}"` : 'class="rank-number"';
rankItem.innerHTML = `
<div ${medal}>${rankNumber}</div>
<div class="rank-top">
<div ${medal}>${rankNumber}</div>
<div class="rank-score">${formatNumber(score.score)}</div>
</div>
<div class="rank-info">
<div class="player-name">${this.escapeHTML(score.playerName)}</div>
<div class="player-stats">
<div class="rank-meta">
<span>⏱ ${formatTime(score.timeSeconds)}</span>
<span>🎯 ${score.moves} mouvements</span>
${score.isPerfect ? '<span>✨ Parfait</span>' : ''}
<span>🎯 ${score.moves}</span>
${score.isPerfect ? '<span>✨</span>' : ''}
</div>
</div>
<div class="rank-score">${formatNumber(score.score)}</div>
<div class="rank-difficulty ${score.difficulty}">${DIFFICULTY_MODES[score.difficulty].name}</div>
`;
leaderboardList.appendChild(rankItem);
});
analyticsManager.track('leaderboard_viewed', { filter: difficulty });
if (typeof analyticsManager !== 'undefined') {
analyticsManager.track('leaderboard_viewed', { filter: difficulty });
}
}
/**
* Mettre à jour les statistiques du joueur
* Mettre à jour les statistiques du joueur (locales).
*/
static updatePlayerStats() {
const userId = getUserId();
const stats = this.getPlayerStats(userId);
const stats = this.getPlayerStats();
// Remplir les éléments HTML
document.getElementById('total-games').textContent = stats.totalGames;
document.getElementById('best-score').textContent = formatNumber(stats.bestScore);
document.getElementById('best-time').textContent = stats.bestTime === Infinity ? '--' : formatTime(stats.bestTime);
document.getElementById('win-rate').textContent = `${stats.winRate}%`;
const totalGamesEl = document.getElementById('total-games');
const bestScoreEl = document.getElementById('best-score');
const bestTimeEl = document.getElementById('best-time');
const winRateEl = document.getElementById('win-rate');
// Ajouter des classes pour animation si valeurs élevées
if (stats.bestScore > 5000) {
document.getElementById('best-score').parentElement.classList.add('high-value');
if (totalGamesEl) totalGamesEl.textContent = stats.totalGames;
if (bestScoreEl) bestScoreEl.textContent = formatNumber(stats.bestScore);
if (bestTimeEl) bestTimeEl.textContent = stats.bestTime === Infinity || stats.bestTime === 0 ? '--' : formatTime(stats.bestTime);
if (winRateEl) winRateEl.textContent = `${stats.winRate}%`;
if (bestScoreEl && stats.bestScore > 5000) {
bestScoreEl.parentElement.classList.add('high-value');
}
if (stats.winRate >= 50) {
document.getElementById('win-rate').parentElement.classList.add('high-value');
if (winRateEl && stats.winRate >= 50) {
winRateEl.parentElement.classList.add('high-value');
}
}
/**
* Afficher le rang du joueur
* Effacer l'historique local du joueur (DEBUG).
* N'affecte PAS le classement en ligne partagé.
*/
static updatePlayerRank(difficulty = 'all') {
const userId = getUserId();
const rank = this.getPlayerRank(userId, difficulty);
if (rank) {
const rankDisplay = document.getElementById('player-rank');
if (rankDisplay) {
rankDisplay.textContent = `Vous êtes #{rank}`;
}
}
}
/**
* Afficher les statistiques globales
*/
static displayGlobalStats() {
const globalStats = this.getGlobalStats();
DEBUG.log('Global Statistics:', globalStats);
return globalStats;
}
/**
* Nettoyer les scores (DEBUG)
*/
static clearAll() {
if (confirm('Êtes-vous ABSOLUMENT certain de vouloir supprimer TOUS les scores?')) {
localStorage.removeItem(this.KEY_LEADERBOARD);
this.updateDisplay();
static clearLocalHistory() {
if (confirm('Effacer VOS statistiques locales ? (le classement en ligne n\'est pas touché)')) {
localStorage.removeItem(this.KEY_HISTORY);
this.updatePlayerStats();
DEBUG.log('✓ Tous les scores ont été supprimés');
DEBUG.log('✓ Historique local effacé');
return true;
}
return false;
}
/**
* Exporter les scores en CSV
*/
static exportCSV() {
const scores = this.getAllScores();
let csv = 'Rang,Joueur,Score,Difficulté,Temps (s),Mouvements,Parfait,Date\n';
scores.forEach((score, index) => {
csv += `${index + 1},"${score.playerName}",${score.score},"${score.difficulty}",${score.timeSeconds},${score.moves},${score.isPerfect ? 'Oui' : 'Non'},"${score.date}"\n`;
});
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `leaderboard-${new Date().toISOString().slice(0, 10)}.csv`;
link.click();
URL.revokeObjectURL(url);
}
/**
* Obtenir l'affichage du rang (numéro ou médaille)
*/
@@ -312,78 +272,11 @@ class LeaderboardManager {
}
}
/**
* Statistiques avancées
*/
class AdvancedStats {
/**
* Obtenir la distribution des scores par difficulté
*/
static getDistributionByDifficulty() {
const scores = LeaderboardManager.getAllScores();
const distribution = {};
Object.keys(DIFFICULTY_MODES).forEach(difficulty => {
distribution[difficulty] = scores.filter(s => s.difficulty === difficulty).length;
});
return distribution;
}
/**
* Obtenir la tendance temporelle
*/
static getTimelineTrend(days = 7) {
const scores = LeaderboardManager.getAllScores();
const now = new Date();
const timeline = {};
for (let i = 0; i < days; i++) {
const date = new Date(now);
date.setDate(date.getDate() - i);
const dateStr = date.toISOString().slice(0, 10);
timeline[dateStr] = scores.filter(s => s.date.slice(0, 10) === dateStr).length;
}
return timeline;
}
/**
* Obtenir la moyenne de temps par difficulté
*/
static getAverageTimeByDifficulty() {
const scores = LeaderboardManager.getAllScores();
const averages = {};
Object.keys(DIFFICULTY_MODES).forEach(difficulty => {
const diffScores = scores.filter(s => s.difficulty === difficulty);
if (diffScores.length > 0) {
const totalTime = diffScores.reduce((a, b) => a + b.timeSeconds, 0);
averages[difficulty] = Math.round(totalTime / diffScores.length);
}
});
return averages;
}
/**
* Taux de réussite global
*/
static getGlobalSuccessRate() {
const scores = LeaderboardManager.getAllScores();
if (scores.length === 0) return 0;
const perfectGames = scores.filter(s => s.isPerfect).length;
return Math.round((perfectGames / scores.length) * 100);
}
}
// ============================================
// INITIALISATION
// ============================================
// Exporter pour utilisation globale
window.LeaderboardManager = LeaderboardManager;
window.AdvancedStats = AdvancedStats;
DEBUG.log('Leaderboard Manager initialized');
DEBUG.log('Leaderboard Manager initialized (online mode)');

View File

@@ -14,7 +14,6 @@ class MemoryGameEngine {
moves: 0,
score: 0,
isProcessing: false,
isPaused: false,
gameStarted: false
};
this.startTime = null;
@@ -128,7 +127,6 @@ class MemoryGameEngine {
if (this.gameState.flipped.length === 2) return;
if (this.cards[cardIndex].isMatched) return;
if (this.gameState.flipped.includes(cardIndex)) return;
if (this.gameState.isPaused) return;
// Retourner la carte
this.flipCard(cardIndex);
@@ -260,9 +258,7 @@ class MemoryGameEngine {
this.startTime = Date.now();
this.timerInterval = setInterval(() => {
if (!this.gameState.isPaused) {
this.updateTimer();
}
this.updateTimer();
}, 100);
this.analytics.trackGameStart(this.difficulty);
@@ -351,10 +347,14 @@ class MemoryGameEngine {
achievements: achievements.map(a => a.id)
});
// Sauvegarder score
// Sauvegarder le score (classement en ligne) puis rafraîchir l'affichage
LeaderboardManager.addScore({
...gameData,
score: finalScore.totalScore
}).then(() => {
const activeFilter = document.querySelector('.tab-btn.active')?.getAttribute('data-filter') || 'all';
LeaderboardManager.updateDisplay(activeFilter);
LeaderboardManager.updatePlayerStats();
});
// Afficher modal victoire
@@ -429,7 +429,6 @@ class MemoryGameEngine {
moves: 0,
score: 0,
isProcessing: false,
isPaused: false,
gameStarted: false
};
@@ -444,24 +443,6 @@ class MemoryGameEngine {
document.getElementById('timer-display').style.animation = '';
}
/**
* Pause/Reprise
*/
togglePause() {
if (!this.gameState.gameStarted) return;
this.gameState.isPaused = !this.gameState.isPaused;
const pauseBtn = document.getElementById('pause-btn');
if (this.gameState.isPaused) {
pauseBtn.textContent = '▶ Reprendre';
pauseBtn.classList.add('paused');
} else {
pauseBtn.textContent = '⏸ Pause';
pauseBtn.classList.remove('paused');
}
}
/**
* Setup event listeners
*/
@@ -469,9 +450,6 @@ class MemoryGameEngine {
// Bouton restart
document.getElementById('restart-btn').addEventListener('click', () => this.restart());
// Bouton pause
document.getElementById('pause-btn').addEventListener('click', () => this.togglePause());
// Sélecteur de difficulté
document.querySelectorAll('.btn-difficulty').forEach(btn => {
btn.addEventListener('click', () => {
@@ -512,14 +490,51 @@ class MemoryGameEngine {
// ============================================
let game;
document.addEventListener('DOMContentLoaded', () => {
// Initialiser le jeu
game = new MemoryGameEngine('normal');
/**
* Demander le nom du joueur à la première partie
*/
function setupPlayerNameModal(onReady) {
const nameConfirmed = localStorage.getItem('nextgn_name_confirmed') === 'true';
if (nameConfirmed) {
onReady();
return;
}
const modal = document.getElementById('player-name-modal');
const input = document.getElementById('player-name-input');
const confirmBtn = document.getElementById('player-name-confirm');
modal.classList.remove('hidden');
input.focus();
const confirmName = () => {
const name = input.value.trim();
localStorage.setItem('nextgn_playerName', name || getPlayerName());
localStorage.setItem('nextgn_name_confirmed', 'true');
modal.classList.add('hidden');
onReady();
};
confirmBtn.addEventListener('click', confirmName, { once: true });
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') confirmName();
}, { once: true });
}
document.addEventListener('DOMContentLoaded', () => {
// Afficher le leaderboard initial
LeaderboardManager.updateDisplay('all');
LeaderboardManager.updatePlayerStats();
setupPlayerNameModal(() => {
LeaderboardManager.updateDisplay('all');
LeaderboardManager.updatePlayerStats();
});
// Initialiser le jeu
game = new MemoryGameEngine('normal');
// Scroll progress
window.addEventListener('scroll', () => {
game.updateHUD();

View File

@@ -9,7 +9,7 @@ const PICTOGRAMMES = [
{
id: 1,
nom: "Gaz comprimé",
filename: "1-gaz-comprime.png",
filename: "sous_pression.jpg",
texte: "Je suis sous pression",
danger: "Danger physique",
couleur: "teal"
@@ -17,15 +17,15 @@ const PICTOGRAMMES = [
{
id: 2,
nom: "Exclamation",
filename: "2-exclamation.png",
texte: "Je nuis gravement à la santé",
danger: "Danger pour la santé",
filename: "nocif_irritant_ozone.jpg",
texte: "J'altère la santé ou la couche d'ozone",
danger: "Danger pour la santé/Environnement",
couleur: "teal"
},
{
id: 3,
nom: "Explosion",
filename: "3-explosion.png",
filename: "explosif.jpg",
texte: "J'explose",
danger: "Danger physique",
couleur: "teal"
@@ -33,7 +33,7 @@ const PICTOGRAMMES = [
{
id: 4,
nom: "Crâne",
filename: "4-crane.png",
filename: "toxicite_aigue.jpg",
texte: "Je tue",
danger: "Danger physique",
couleur: "teal"
@@ -41,7 +41,7 @@ const PICTOGRAMMES = [
{
id: 5,
nom: "Flamme",
filename: "5-flamme.png",
filename: "inflammable.jpg",
texte: "Je flambe",
danger: "Danger physique",
couleur: "teal"
@@ -49,7 +49,7 @@ const PICTOGRAMMES = [
{
id: 6,
nom: "Comburant",
filename: "6-comburant.png",
filename: "comburant.jpg",
texte: "Je fais flamber",
danger: "Danger physique",
couleur: "teal"
@@ -57,7 +57,7 @@ const PICTOGRAMMES = [
{
id: 7,
nom: "Environnement",
filename: "7-environnement.png",
filename: "pollution.jpg",
texte: "Je pollue",
danger: "Danger pour l'environnement",
couleur: "teal"
@@ -65,17 +65,17 @@ const PICTOGRAMMES = [
{
id: 8,
nom: "Corrosion",
filename: "8-corrosion.png",
filename: "corrosif.jpg",
texte: "Je ronge",
danger: "Danger physique",
couleur: "teal"
},
{
id: 9,
nom: "Santé/Environnement",
filename: "9-sante-environnement.png",
texte: "J'altère la santé ou la couche d'ozone",
danger: "Danger pour la santé/Environnement",
nom: "Santé (CMR)",
filename: "cmr.jpg",
texte: "Je nuis gravement à la santé",
danger: "Danger pour la santé",
couleur: "teal"
}
];
@@ -292,10 +292,10 @@ function getRank(index) {
}
/**
* Vérifier si le score est dans le top 10
* Vérifier si le score est dans le top 10 (classement en ligne, asynchrone)
*/
function isTopScore(score, difficulty = 'all') {
const scores = LeaderboardManager.getLeaderboard(difficulty, 10);
async function isTopScore(score, difficulty = 'all') {
const scores = await LeaderboardManager.getLeaderboard(difficulty, 10);
return scores.some(s => s.score === score.score && s.userId === score.userId);
}
@@ -318,57 +318,25 @@ function formatDate(isoDate) {
}
/**
* Obtenir les statistiques d'un joueur
* Obtenir les statistiques locales du joueur
*/
function getPlayerStatistics(userId) {
const scores = LeaderboardManager.getAllScores().filter(s => s.userId === userId);
if (scores.length === 0) {
return {
totalGames: 0,
bestScore: 0,
averageScore: 0,
averageTime: 0,
bestTime: Infinity,
winRate: 0,
perfectGames: 0
};
}
const bestScore = Math.max(...scores.map(s => s.score), 0);
const totalScore = scores.reduce((a, b) => a + b.score, 0);
const totalTime = scores.reduce((a, b) => a + b.timeSeconds, 0);
const bestTime = Math.min(...scores.map(s => s.timeSeconds), Infinity);
const perfectGames = scores.filter(s => s.isPerfect).length;
const winRate = (perfectGames / scores.length) * 100;
return {
totalGames: scores.length,
bestScore: bestScore,
averageScore: Math.round(totalScore / scores.length),
averageTime: Math.round(totalTime / scores.length),
bestTime: bestTime === Infinity ? 0 : bestTime,
winRate: Math.round(winRate),
perfectGames: perfectGames
};
function getPlayerStatistics() {
return LeaderboardManager.getPlayerStats();
}
/**
* Déboguer : afficher tous les scores en console
* Déboguer : afficher l'historique local du joueur en console
*/
function debugScores() {
console.table(LeaderboardManager.getAllScores());
console.table(LeaderboardManager._getLocalHistory());
}
/**
* Déboguer : nettoyer tous les scores
* Déboguer : effacer les statistiques locales du joueur
* (le classement en ligne partagé n'est pas affecté)
*/
function clearAllScores() {
if (confirm('Êtes-vous sûr de vouloir supprimer tous les scores?')) {
localStorage.removeItem('nextgn_leaderboard');
console.log('✓ Tous les scores ont été supprimés');
location.reload();
}
LeaderboardManager.clearLocalHistory();
}
/**

View File

@@ -3,20 +3,20 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memory Pictogrammes GHS - NextGN Formation</title>
<title>Memory Pictogrammes GHS - Gauthier Chombart & Nathan Chauwin</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<!-- Styles -->
<link rel="stylesheet" href="../../header-style.css"/>
<link rel="stylesheet" href="assets/css/memory-game.css">
<link rel="stylesheet" href="assets/css/hud.css">
<link rel="stylesheet" href="assets/css/animations.css">
<link rel="stylesheet" href="assets/css/leaderboard.css">
<link rel="stylesheet" href="assets/css/memory-game.css?v=3">
<link rel="stylesheet" href="assets/css/hud.css?v=3">
<link rel="stylesheet" href="assets/css/animations.css?v=3">
<link rel="stylesheet" href="assets/css/leaderboard.css?v=3">
</head>
<body>
<!-- HEADER NextGN Formation -->
<!-- HEADER Gauthier Chombart & Nathan Chauwin -->
<header>
<div class="logo">NextGN Formation</div>
<div class="logo">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="../../index.html">Accueil</a>
<a href="../../index.html#formations">Exercices</a>
@@ -36,7 +36,7 @@
<main class="game-container">
<!-- INTRO SECTION -->
<section class="intro-section">
<h1>🎮 Memory Pictogrammes GHS</h1>
<h1>Memory pictogrammes</h1>
<p class="subtitle">Maîtrisez les 9 symboles de danger</p>
<div class="intro-box">
@@ -45,116 +45,149 @@
Plus rapide vous êtes, plus de points vous gagnez! 🏆
</p>
</div>
</section>
<!-- TOP BAR (niveau + stats en temps réel) -->
<div class="game-top-bar">
<!-- DIFFICULTY SELECTOR -->
<div class="difficulty-selector">
<label>Choisir le niveau :</label>
<label>Choisir le niveau</label>
<div class="btn-group">
<button class="btn btn-difficulty" data-difficulty="easy">
<span class="btn-icon">🌱</span>
<span class="btn-label">Facile</span>
<span class="btn-desc">4 paires</span>
</button>
<button class="btn btn-difficulty active" data-difficulty="normal">
<span class="btn-icon">🎯</span>
<span class="btn-label">Normal</span>
<span class="btn-desc">9 paires</span>
</button>
<button class="btn btn-difficulty" data-difficulty="hard">
<span class="btn-icon">🔥</span>
<span class="btn-label">Difficile</span>
<span class="btn-desc">2 min chrono</span>
</button>
</div>
</div>
</section>
<!-- GAME SECTION -->
<section class="game-section">
<!-- HUD (Stats en temps réel) -->
<div class="game-hud">
<div class="stat-box">
<div class="label">Score</div>
<div class="label">🏆 Score</div>
<div class="value" id="score-display">0</div>
</div>
<div class="stat-box">
<div class="label">Mouvements</div>
<div class="label">👆 Mouvements</div>
<div class="value" id="moves-display">0</div>
</div>
<div class="stat-box">
<div class="label">Temps</div>
<div class="label">Temps</div>
<div class="value" id="timer-display">00:00</div>
</div>
<div class="stat-box">
<div class="label">Paires</div>
<div class="label">🧩 Paires</div>
<div class="value" id="pairs-display">0/9</div>
</div>
</div>
</div>
<!-- PROGRESS BAR -->
<div class="progress-container">
<div class="progress-bar" id="progress-bar"></div>
</div>
<!-- GAME LAYOUT (classement / jeu / statistiques) -->
<div class="game-layout">
<!-- LEADERBOARD PANEL (gauche) -->
<aside class="leaderboard-panel">
<h2>🏆 Classement</h2>
<!-- GAME GRID -->
<div class="game-grid" id="game-grid">
<!-- Cartes générées par JS -->
</div>
<!-- CONTROLS -->
<div class="game-controls">
<button class="btn btn-primary" id="restart-btn">
🔄 Recommencer
</button>
<button class="btn btn-secondary" id="pause-btn">
⏸ Pause
</button>
</div>
</section>
<!-- LEADERBOARD SECTION -->
<section class="leaderboard-section">
<h2>🏆 Classement</h2>
<div class="tabs">
<button class="tab-btn active" data-filter="all">Tous</button>
<button class="tab-btn" data-filter="easy">Facile</button>
<button class="tab-btn" data-filter="normal">Normal</button>
<button class="tab-btn" data-filter="hard">Difficile</button>
</div>
<div class="leaderboard">
<div class="leaderboard-list" id="leaderboard-list">
<!-- Rempli par JS -->
<div class="tabs">
<button class="tab-btn active" data-filter="all">Tous</button>
<button class="tab-btn" data-filter="easy">Facile</button>
<button class="tab-btn" data-filter="normal">Normal</button>
<button class="tab-btn" data-filter="hard">Difficile</button>
</div>
</div>
<!-- PLAYER STATS -->
<div class="player-stats">
<h3>Vos statistiques</h3>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon">🎮</div>
<div class="stat-label">Jeux joués</div>
<div class="stat-value" id="total-games">0</div>
</div>
<div class="stat-card">
<div class="stat-icon"></div>
<div class="stat-label">Meilleur score</div>
<div class="stat-value" id="best-score">0</div>
</div>
<div class="stat-card">
<div class="stat-icon"></div>
<div class="stat-label">Temps record</div>
<div class="stat-value" id="best-time">--</div>
</div>
<div class="stat-card">
<div class="stat-icon">🏅</div>
<div class="stat-label">Taux de réussite</div>
<div class="stat-value" id="win-rate">0%</div>
<div class="leaderboard">
<div class="leaderboard-list" id="leaderboard-list">
<!-- Rempli par JS -->
</div>
</div>
</div>
</section>
</aside>
<!-- GAME SECTION (centre) -->
<section class="game-section">
<div class="game-panel">
<!-- PROGRESS BAR -->
<div class="progress-container">
<div class="game-progress-fill" id="progress-bar"></div>
</div>
<!-- GAME GRID -->
<div class="game-grid" id="game-grid">
<!-- Cartes générées par JS -->
</div>
<!-- CONTROLS -->
<div class="game-controls">
<button class="btn btn-primary" id="restart-btn">
🔄 Recommencer
</button>
</div>
</div>
</section>
<!-- PLAYER STATS PANEL (droite) -->
<aside class="stats-panel">
<div class="player-stats">
<h3>Vos statistiques</h3>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon">🎮</div>
<div class="stat-label">Jeux joués</div>
<div class="stat-value" id="total-games">0</div>
</div>
<div class="stat-card">
<div class="stat-icon"></div>
<div class="stat-label">Meilleur score</div>
<div class="stat-value" id="best-score">0</div>
</div>
<div class="stat-card">
<div class="stat-icon"></div>
<div class="stat-label">Temps record</div>
<div class="stat-value" id="best-time">--</div>
</div>
<div class="stat-card">
<div class="stat-icon">🏅</div>
<div class="stat-label">Taux de réussite</div>
<div class="stat-value" id="win-rate">0%</div>
</div>
</div>
</div>
</aside>
</div>
</main>
<!-- PLAYER NAME MODAL (1ère partie) -->
<div class="victory-modal hidden" id="player-name-modal">
<div class="modal-content name-modal-content">
<h2>Bienvenue ! 👋</h2>
<p class="name-modal-text">
Entrez votre nom ou un pseudo pour apparaître dans le classement général.
</p>
<input
type="text"
id="player-name-input"
class="name-input"
maxlength="20"
placeholder="Votre nom ou pseudo"
autocomplete="off"
>
<div class="modal-actions">
<button class="btn btn-primary" id="player-name-confirm">
🎮 Commencer à jouer
</button>
</div>
</div>
</div>
<!-- VICTORY MODAL -->
<div class="victory-modal hidden" id="victory-modal">
<div class="modal-content">
@@ -196,7 +229,7 @@
<!-- FOOTER -->
<footer>
<p>&copy; 2024 NextGN Formation - Memory Pictogrammes GHS</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p style="margin-top: 10px; opacity: 0.6;">Tous droits réservés - Formateurs indépendants</p>
</footer>

View File

@@ -1,213 +0,0 @@
<%@ Language="VBScript" %>
<%
' ============================================================
' save_results.asp
' Reçoit les réponses de l'exercice TP Nuisibles (JSON en POST)
' et les enregistre dans la base SQL Server.
' ============================================================
Response.Buffer = True
Response.ContentType = "application/json"
Response.CharSet = "UTF-8"
' ------- À ADAPTER : chaîne de connexion vers votre base -------
' Récupérée depuis le panneau "Manage Databases" de FreeASPHosting :
' Server Name : sql.bsite.net\MSSQL2016
' SQL Username : nextgnformation_reponses_exercices
' Database name : (généralement identique au username, à vérifier dans le panneau)
Dim connString
connString = "Provider=SQLOLEDB;Data Source=sql.bsite.net\MSSQL2016;" & _
"Initial Catalog=nextgnformation_reponses_exercices;" & _
"User ID=nextgnformation_reponses_exercices;" & _
"Password=S5$NyFXzEjJCg6jD;"
' -----------------------------------------------------------------
Function JSONEscape(s)
s = Replace(s, "\", "\\")
s = Replace(s, Chr(34), "\""")
s = Replace(s, vbCrLf, "\n")
s = Replace(s, vbLf, "\n")
s = Replace(s, vbCr, "\n")
s = Replace(s, vbTab, "\t")
JSONEscape = s
End Function
Sub SendJSON(success, message)
Dim out
out = "{""success"":" & LCase(CStr(success)) & ",""error"":""" & JSONEscape(message) & """}"
Response.Write out
Response.End
End Sub
' --- Lecture du corps de la requête (JSON brut envoyé en POST) ---
Dim rawJSON
Dim totalBytes
totalBytes = Request.TotalBytes
If totalBytes = 0 Then
SendJSON False, "Aucune donnée reçue."
End If
Dim binData
binData = Request.BinaryRead(totalBytes)
' Conversion des octets UTF-8 en chaîne VBScript
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 ' adTypeBinary
objStream.Open
objStream.Write binData
objStream.Position = 0
objStream.Type = 2 ' adTypeText
objStream.CharSet = "utf-8"
rawJSON = objStream.ReadText
objStream.Close
Set objStream = Nothing
If Trim(rawJSON) = "" Then
SendJSON False, "Corps de requête vide."
End If
' --- Parsing JSON minimal sans librairie externe ---
' On utilise le moteur JScript via ScriptControl pour parser le JSON de façon fiable.
Dim sc
Set sc = Server.CreateObject("MSScriptControl.ScriptControl")
sc.Language = "JScript"
sc.AddCode "function parseIt(s){ return eval('(' + s + ')'); } " & _
"function getStr(o,k){ return (o && o[k] != null) ? String(o[k]) : ''; } " & _
"function getReponsesJSON(o){ var arr = o.reponses || []; var out = []; " & _
"for (var i=0;i<arr.length;i++){ out.push({id:String(arr[i].id||''), question:String(arr[i].question||''), reponse:String(arr[i].reponse||'')}); } return out; } " & _
"function getTableauJSON(o){ var arr = o.tp3_tableau || []; var out = []; " & _
"for (var i=0;i<arr.length;i++){ out.push({etape:String(arr[i].etape||''), risque:String(arr[i].risque||''), mesure:String(arr[i].mesure||'')}); } return out; }"
Dim dataObj
On Error Resume Next
Set dataObj = sc.Run("parseIt", rawJSON)
If Err.Number <> 0 Then
SendJSON False, "JSON invalide : " & Err.Description
End If
On Error Goto 0
Dim nom, dateSession, casChoisi, casCle, dateEnvoi
Dim metaIntitule, metaDescription, metaLieu, metaDebut, metaRealise, metaVerifie, metaMaj
nom = sc.Run("getStr", dataObj, "nom")
dateSession = sc.Run("getStr", dataObj, "date_session")
casChoisi = sc.Run("getStr", dataObj, "cas_choisi")
casCle = sc.Run("getStr", dataObj, "cas_cle")
dateEnvoi = sc.Run("getStr", dataObj, "date_envoi")
Dim tp3Obj
tp3Obj = dataObj.tp3_meta
metaIntitule = sc.Run("getStr", tp3Obj, "intitule")
metaDescription = sc.Run("getStr", tp3Obj, "description")
metaLieu = sc.Run("getStr", tp3Obj, "lieu")
metaDebut = sc.Run("getStr", tp3Obj, "debut")
metaRealise = sc.Run("getStr", tp3Obj, "realise_par")
metaVerifie = sc.Run("getStr", tp3Obj, "verifie_par")
metaMaj = sc.Run("getStr", tp3Obj, "maj_par")
If Trim(nom) = "" Then
SendJSON False, "Le nom du groupe est obligatoire."
End If
' --- Sérialisation des réponses et du tableau en JSON texte (stockés en colonnes NVARCHAR(MAX)) ---
Dim reponsesArr, tableauArr
Set reponsesArr = sc.Run("getReponsesJSON", dataObj)
Set tableauArr = sc.Run("getTableauJSON", dataObj)
Dim reponsesJSONStr, tableauJSONStr
reponsesJSONStr = "["
Dim i
For i = 0 To reponsesArr.length - 1
If i > 0 Then reponsesJSONStr = reponsesJSONStr & ","
reponsesJSONStr = reponsesJSONStr & "{""id"":""" & JSONEscape(reponsesArr.Item(i).id) & _
""",""question"":""" & JSONEscape(reponsesArr.Item(i).question) & _
""",""reponse"":""" & JSONEscape(reponsesArr.Item(i).reponse) & """}"
Next
reponsesJSONStr = reponsesJSONStr & "]"
tableauJSONStr = "["
For i = 0 To tableauArr.length - 1
If i > 0 Then tableauJSONStr = tableauJSONStr & ","
tableauJSONStr = tableauJSONStr & "{""etape"":""" & JSONEscape(tableauArr.Item(i).etape) & _
""",""risque"":""" & JSONEscape(tableauArr.Item(i).risque) & _
""",""mesure"":""" & JSONEscape(tableauArr.Item(i).mesure) & """}"
Next
tableauJSONStr = tableauJSONStr & "]"
' --- Connexion et insertion en base ---
Dim conn
Set conn = Server.CreateObject("ADODB.Connection")
On Error Resume Next
conn.Open connString
If Err.Number <> 0 Then
SendJSON False, "Connexion BDD impossible : " & Err.Description
End If
On Error Goto 0
' Création de la table si elle n'existe pas encore
Dim createTableSQL
createTableSQL = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='tp_resultats' AND xtype='U') " & _
"CREATE TABLE tp_resultats (" & _
"id INT IDENTITY(1,1) PRIMARY KEY, " & _
"nom NVARCHAR(255), " & _
"date_session NVARCHAR(50), " & _
"cas_choisi NVARCHAR(255), " & _
"cas_cle NVARCHAR(100), " & _
"reponses_json NVARCHAR(MAX), " & _
"tp3_intitule NVARCHAR(500), " & _
"tp3_description NVARCHAR(1000), " & _
"tp3_lieu NVARCHAR(500), " & _
"tp3_debut NVARCHAR(50), " & _
"tp3_realise_par NVARCHAR(255), " & _
"tp3_verifie_par NVARCHAR(255), " & _
"tp3_maj_par NVARCHAR(255), " & _
"tp3_tableau_json NVARCHAR(MAX), " & _
"date_envoi NVARCHAR(50), " & _
"date_enregistrement DATETIME DEFAULT GETDATE())"
On Error Resume Next
conn.Execute createTableSQL
If Err.Number <> 0 Then
SendJSON False, "Création de table impossible : " & Err.Description
End If
On Error Goto 0
' Insertion via requête paramétrée (Command) pour éviter les injections SQL
Dim cmd
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = "INSERT INTO tp_resultats " & _
"(nom, date_session, cas_choisi, cas_cle, reponses_json, tp3_intitule, tp3_description, tp3_lieu, tp3_debut, tp3_realise_par, tp3_verifie_par, tp3_maj_par, tp3_tableau_json, date_envoi) " & _
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
cmd.CommandType = 1 ' adCmdText
Dim p
Set p = cmd.CreateParameter("nom", 202, 1, 255, nom) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("date_session", 202, 1, 50, dateSession) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("cas_choisi", 202, 1, 255, casChoisi) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("cas_cle", 202, 1, 100, casCle) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("reponses_json", 203, 1, Len(reponsesJSONStr), reponsesJSONStr) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_intitule", 202, 1, 500, metaIntitule) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_description", 202, 1, 1000, metaDescription) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_lieu", 202, 1, 500, metaLieu) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_debut", 202, 1, 50, metaDebut) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_realise_par", 202, 1, 255, metaRealise) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_verifie_par", 202, 1, 255, metaVerifie) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_maj_par", 202, 1, 255, metaMaj) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("tp3_tableau_json", 203, 1, Len(tableauJSONStr), tableauJSONStr) : cmd.Parameters.Append p
Set p = cmd.CreateParameter("date_envoi", 202, 1, 50, dateEnvoi) : cmd.Parameters.Append p
On Error Resume Next
cmd.Execute
If Err.Number <> 0 Then
conn.Close
SendJSON False, "Erreur lors de l'insertion : " & Err.Description
End If
On Error Goto 0
conn.Close
Set conn = Nothing
SendJSON True, ""
%>

View File

@@ -3,25 +3,25 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NextGN Formation - Formations Certibiocide & Techniques</title>
<title>Gauthier Chombart & Nathan Chauwin - Formations Certibiocide & Techniques</title>
<!-- SEO de base -->
<meta name="description" content="Formations Certibiocide pratiques et interactives par des formateurs indépendants experts. Exercices, documentation technique sur les nuisibles et rapports de veille réglementaire.">
<meta name="keywords" content="Certibiocide, formation biocides, hygiène professionnelle, nuisibles, désinfection, 3D, ESOD, formateurs indépendants">
<meta name="author" content="Gauthier Chombart, Nathan Chauwin">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://VOTRE-DOMAINE.fr/">
<link rel="canonical" href="https://nextgnformation.bsite.net/">
<!-- Open Graph (partage sur les réseaux sociaux et LinkedIn) -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://VOTRE-DOMAINE.fr/">
<meta property="og:title" content="NextGN Formation - Formations Certibiocide & Techniques">
<meta property="og:url" content="https://nextgnformation.bsite.net/">
<meta property="og:title" content="Gauthier Chombart & Nathan Chauwin - Formations Certibiocide & Techniques">
<meta property="og:description" content="Formations Certibiocide pratiques et interactives par des formateurs indépendants experts. Exercices, documentation technique sur les nuisibles et rapports de veille réglementaire.">
<meta property="og:locale" content="fr_FR">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="NextGN Formation - Formations Certibiocide & Techniques">
<meta name="twitter:title" content="Gauthier Chombart & Nathan Chauwin - Formations Certibiocide & Techniques">
<meta name="twitter:description" content="Formations Certibiocide pratiques et interactives par des formateurs indépendants experts.">
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
@@ -29,11 +29,11 @@
</head>
<body>
<header>
<div class="logo">NextGN Formation</div>
<div class="logo">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="#formations">Exercices interactifs</a>
<a href="#documentation">Documentation</a>
<a href="#rapports">Rapports de veille</a>
<a href="#documentation" style="display:none;">Documentation</a>
<a href="#rapports" style="display:none;">Rapports de veille</a>
<a href="#about">À propos</a>
<a href="#contact">Contact</a>
</nav>
@@ -53,8 +53,8 @@
<div class="cta-group">
<a href="#formations" class="btn btn-primary">Suivre les exercices interactifs</a>
<a href="#documentation" class="btn btn-secondary">Documentation</a>
<a href="#rapports" class="btn btn-secondary">Rapports de veille</a>
<a href="#documentation" class="btn btn-secondary" style="display:none;">Documentation</a>
<a href="#rapports" class="btn btn-secondary" style="display:none;">Rapports de veille</a>
</div>
<div class="stats">
@@ -103,7 +103,7 @@
<div class="formation-card">
<div class="formation-header">
<div class="formation-icon">📋</div>
<h3 class="formation-title">FDS & Étiquettes</h3>
<h3 class="formation-title">FDS, FT & Étiquettes</h3>
<p class="formation-subtitle">Aller plus loin</p>
</div>
<div class="formation-body">
@@ -137,11 +137,24 @@
<a href="exercices/memory-pictogrammes/memory.html" class="formation-link">Jouer</a>
</div>
</div>
<!-- Correction : page unique pour tous les exercices -->
<div class="formation-card">
<div class="formation-header">
<div class="formation-icon"></div>
<h3 class="formation-title">Corriger un exercice</h3>
<p class="formation-subtitle">Correction des rendus</p>
</div>
<div class="formation-body">
<p class="formation-description">Déposez le PDF exporté par un groupe et obtenez la lecture de son rendu. Page unique de correction pour l'ensemble des exercices.</p>
<a href="exercices/corriger-exercice.html" class="formation-link">Corriger</a>
</div>
</div>
</div>
</section>
<!-- DOCUMENTATION TECHNIQUE SECTION -->
<section id="documentation" class="documentation-section">
<section id="documentation" class="documentation-section" style="display:none;">
<div class="section-header">
<h2>Documentation technique et biologie des espèces</h2>
<p>Accédez à notre base de connaissances : études détaillées, analyses scientifiques et rapports techniques sur les nuisibles, les biocides et les enjeux réglementaires.</p>
@@ -178,7 +191,7 @@
</section>
<!-- RAPPORTS DE VEILLE HEBDOMADAIRES -->
<section id="rapports" class="rapports-section">
<section id="rapports" class="rapports-section" style="display:none;">
<div class="section-header">
<h2>Rapports de veille hebdomadaires</h2>
<p>Suivez chaque semaine l'actualité réglementaire, les opportunités de marché et les tendances du secteur Certibiocide en France et en Europe.</p>
@@ -208,7 +221,7 @@
<li>125+ offres d'emploi techniciens 3D</li>
</ul>
</div>
<a href="veille/rapport-semaine-21.html" class="rapport-link">Consulter le rapport complet →</a>
<a href="veille/rapports/veille-certibiocide-semaine-21.html" class="rapport-link">Consulter le rapport complet →</a>
</div>
<!-- Semaine 20 -->
@@ -226,7 +239,7 @@
<li>Opportunités secteur 3D</li>
</ul>
</div>
<a href="veille/rapport-semaine-20.html" class="rapport-link">Consulter le rapport complet →</a>
<a href="veille/rapports/veille-certibiocide-semaine-20.html" class="rapport-link">Consulter le rapport complet →</a>
</div>
<!-- Archive -->
@@ -314,7 +327,7 @@
</main>
<footer>
<p>&copy; 2026 NextGN Formation - Formations Certibiocide & Techniques</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p style="margin-top: 10px; opacity: 0.6;">Tous droits réservés — Gauthier Chombart & Nathan Chauwin — Formateurs indépendants</p>
</footer>

View File

@@ -1,420 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Veille Certibiocide</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:opsz,wght@9..40,300;9..40,400;9..40,500&display=swap" rel="stylesheet">
<style>
:root {
--bg: #F5F4F0; --white: #FFFFFF; --text: #1C1C1A; --muted: #7A7974; --border: rgba(0,0,0,0.08);
--teal: #0F6E56; --teal-light: #E2F4EE;
--amber: #A86412; --amber-light: #FAF0E0;
--coral: #B53520; --coral-light: #FAEBE7;
--blue: #1A5FA8; --blue-light: #E6F0FB;
--purple: #5040A8; --purple-light: #EDEAFA;
--slate: #3A4A5C; --slate-light: #EDF1F5;
--green2: #2E7D32; --green2-light: #E8F5E9;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'DM Sans', sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; padding-bottom: 4rem; }
.header {
background: var(--white); border-bottom: 0.5px solid var(--border);
padding: 1.25rem 2rem; position: sticky; top: 0; z-index: 50;
display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.header-title { font-family: 'Syne', sans-serif; font-size: 16px; font-weight: 800; }
.header-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.header-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.week-badge { font-size: 12px; background: var(--teal-light); color: var(--teal); padding: 4px 12px; border-radius: 20px; font-weight: 500; }
.refresh-btn {
font-family: 'Syne', sans-serif; font-size: 12px; font-weight: 600;
background: var(--text); color: white; border: none; border-radius: 20px;
padding: 6px 16px; cursor: pointer; display: flex; align-items: center; gap: 6px; transition: opacity 0.2s;
}
.refresh-btn:hover { opacity: 0.8; }
.refresh-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.spin { animation: spin 1s linear infinite; display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }
.main { padding: 1.5rem 2rem; max-width: 1200px; margin: 0 auto; }
.status-banner {
border-radius: 10px; padding: 10px 16px; font-size: 12px;
margin-bottom: 1.25rem; display: flex; align-items: flex-start; gap: 8px; line-height: 1.6;
border: 0.5px solid transparent;
}
.banner-info { background: var(--blue-light); color: var(--blue); border-color: rgba(26,95,168,0.2); }
.banner-ok { background: var(--teal-light); color: var(--teal); border-color: rgba(15,110,86,0.2); }
.banner-warn { background: #FFF8E1; color: #7A5400; border-color: rgba(186,117,23,0.25); }
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.grid-full { grid-column: 1 / -1; }
.card { background: var(--white); border: 0.5px solid var(--border); border-radius: 14px; overflow: hidden; }
.card-header {
padding: 0.9rem 1.2rem 0.75rem; border-bottom: 0.5px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
}
.card-label { display: flex; align-items: center; gap: 8px; }
.card-icon { font-size: 15px; }
.card-title { font-family: 'Syne', sans-serif; font-size: 13px; font-weight: 700; }
.card-tag { font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 10px; font-family: 'Syne', sans-serif; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; }
.card-body { padding: 0.9rem 1.2rem; }
.item { padding: 0.7rem 0; border-bottom: 0.5px solid var(--border); animation: fadeUp 0.35s ease both; }
.item:first-child { padding-top: 0; }
.item:last-child { border-bottom: none; padding-bottom: 0; }
@keyframes fadeUp { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:translateY(0); } }
.item-source {
font-size: 10px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
font-family: 'Syne', sans-serif; display: inline-block;
padding: 1px 8px; border-radius: 8px; margin-bottom: 4px;
}
.item-text { font-size: 13px; line-height: 1.6; }
.item-meta { display: flex; align-items: center; gap: 8px; margin-top: 3px; }
.item-date { font-size: 11px; color: var(--muted); }
.item-link { font-size: 11px; color: var(--blue); text-decoration: none; font-weight: 500; }
.item-link:hover { text-decoration: underline; }
.sources-bar { margin-top: 10px; padding-top: 8px; border-top: 0.5px solid var(--border); display: flex; flex-wrap: wrap; gap: 4px; }
.source-chip { font-size: 10px; background: var(--bg); border: 0.5px solid var(--border); border-radius: 10px; padding: 2px 8px; color: var(--muted); }
.agenda-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; }
.agenda-item { padding: 0.7rem 1rem 0.7rem 0; border-bottom: 0.5px solid var(--border); }
.agenda-item:nth-child(n+4) { border-bottom: none; }
.agenda-item:not(:nth-child(3n)) { border-right: 0.5px solid var(--border); margin-right: 1rem; }
.last-update { text-align: center; font-size: 11px; color: var(--muted); margin-top: 1.5rem; }
/* Skeleton */
.sk { background: linear-gradient(90deg,#EEEDE9 25%,#E5E4E0 50%,#EEEDE9 75%); background-size:200% 100%; animation:shimmer 1.3s infinite; border-radius:5px; height:12px; margin-bottom:5px; }
.sk.s{width:55%;} .sk.m{width:80%;} .sk.f{width:100%;}
@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
.sk-block { padding:0.7rem 0; border-bottom:0.5px solid var(--border); }
.sk-block:last-child { border-bottom:none; }
/* Loading overlay */
.loading-overlay { display:none; position:fixed; inset:0; background:rgba(245,244,240,0.88); z-index:200; align-items:center; justify-content:center; flex-direction:column; gap:12px; }
.loading-overlay.active { display:flex; }
.loader { width:34px; height:34px; border:3px solid var(--border); border-top-color:var(--teal); border-radius:50%; animation:spin 0.8s linear infinite; }
.loading-label { font-family:'Syne',sans-serif; font-size:14px; font-weight:600; }
.loading-sub { font-size:12px; color:var(--muted); }
.loading-progress { display:flex; gap:4px; margin-top:4px; }
.lp-dot { width:6px; height:6px; border-radius:50%; background:var(--border); transition:background 0.3s; }
.lp-dot.done { background:var(--teal); }
.lp-dot.active { background:var(--amber); animation:pulse 0.8s infinite; }
@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.4}}
</style>
</head>
<body>
<div class="loading-overlay" id="loadingOverlay">
<div class="loader"></div>
<div class="loading-label">Actualisation en cours…</div>
<div class="loading-sub" id="loadingStatus">Initialisation</div>
<div class="loading-progress" id="loadingProgress"></div>
</div>
<div class="header">
<div>
<div class="header-title">Veille Certibiocide</div>
<div class="header-sub">Formation Biocides — Actualisation hebdomadaire</div>
</div>
<div class="header-right">
<div class="week-badge" id="weekBadge"></div>
<button class="refresh-btn" id="refreshBtn" onclick="refreshAll()">
<span id="refreshIcon"></span> Actualiser
</button>
</div>
</div>
<div class="main">
<div class="status-banner banner-info" id="statusBanner">
<span id="statusText">Données pré-chargées (mai 2025). Cliquez sur <strong>Actualiser</strong> pour récupérer les dernières actualités via l'API.</span>
</div>
<div class="grid">
<!-- RÉGLEMENTAIRE -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">⚖️</span><span class="card-title">Actualité réglementaire</span></div>
<span class="card-tag" style="background:var(--teal-light);color:var(--teal);">ECHA · ANSES · MTE</span>
</div>
<div class="card-body">
<div id="content-reglementaire">
<div class="item"><span class="item-source" style="background:var(--teal-light);color:var(--teal);">ECHA</span><div class="item-text">L'ECHA a publié en avril 2025 la mise à jour des substances actives approuvées pour les TP 14 et TP 18, avec de nouvelles restrictions sur le bromadiolone et la difethialone en usage extérieur.</div><div class="item-meta"><span class="item-date">Avril 2025</span><a href="https://echa.europa.eu/fr/regulations/biocidal-products-regulation" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--teal-light);color:var(--teal);">ANSES</span><div class="item-text">L'ANSES a mis à jour biocid-anses.fr avec 12 nouvelles AMM délivrées au T1 2025, principalement pour des insecticides à base de deltaméthrine et des rodenticides de 2e génération.</div><div class="item-meta"><span class="item-date">Mars 2025</span><a href="https://www.anses.fr/fr/content/biocides" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--teal-light);color:var(--teal);">Ministère Transition Écologique</span><div class="item-text">Le décret du 15 mars 2025 renforce les obligations de formation des applicateurs de biocides en milieu agroalimentaire, avec une mise à jour des référentiels Certibiocide prévue pour septembre 2025.</div><div class="item-meta"><span class="item-date">Mars 2025</span><a href="https://www.ecologie.gouv.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--teal-light);color:var(--teal);">Légifrance</span><div class="item-text">L'arrêté du 7 février 2025 modifie les conditions de mise sur le marché des rodenticides anticoagulants de 2e génération, renforçant l'obligation de confinement des appâts.</div><div class="item-meta"><span class="item-date">Février 2025</span><a href="https://www.legifrance.gouv.fr" target="_blank" class="item-link">↗ Source</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">echa.europa.eu</span><span class="source-chip">anses.fr</span><span class="source-chip">ecologie.gouv.fr</span><span class="source-chip">legifrance.fr</span></div>
</div>
</div>
<!-- MARCHÉ FORMATION -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">🎓</span><span class="card-title">Marché formation Certibiocide</span></div>
<span class="card-tag" style="background:var(--amber-light);color:var(--amber);">Organismes · CA · Sessions</span>
</div>
<div class="card-body">
<div id="content-marche">
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">France Compétences</span><div class="item-text">Le Certibiocide enregistre une hausse de 18 % des candidatures CPF en 2024, avec plus de 4 200 dossiers validés. Le financement moyen s'établit à 980 € par stagiaire via Mon Compte Formation.</div><div class="item-meta"><span class="item-date">Janvier 2025</span><a href="https://www.francecompetences.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">Qualiopi</span><div class="item-text">Plus de 320 organismes de formation sont référencés Qualiopi pour le Certibiocide, soit +22 % sur 12 mois. L'Île-de-France concentre 28 % de l'offre nationale.</div><div class="item-meta"><span class="item-date">Février 2025</span><a href="https://www.qualiopi.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">LinkedIn</span><div class="item-text">Les formations Certibiocide en format hybride (e-learning + présentiel) progressent fortement. Plusieurs organismes proposent des sessions weekend pour les salariés en activité dans le secteur 3D.</div><div class="item-meta"><span class="item-date">Avril 2025</span><a href="https://www.linkedin.com" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">OPCO EP</span><div class="item-text">L'OPCO EP maintient la prise en charge à 100 % pour les entreprises de moins de 50 salariés, avec un plafond horaire revalorisé à 14,50 €/h en 2025.</div><div class="item-meta"><span class="item-date">Janvier 2025</span><a href="https://www.opcoep.fr" target="_blank" class="item-link">↗ Source</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">francecompetences.fr</span><span class="source-chip">qualiopi.fr</span><span class="source-chip">LinkedIn</span><span class="source-chip">opcoep.fr</span></div>
</div>
</div>
<!-- NUISIBLES -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">🐀</span><span class="card-title">Espèces nuisibles & ESOD</span></div>
<span class="card-tag" style="background:var(--coral-light);color:var(--coral);">Entomologie · Épidémio</span>
</div>
<div class="card-body">
<div id="content-nuisibles">
<div class="item"><span class="item-source" style="background:var(--coral-light);color:var(--coral);">Santé Publique France</span><div class="item-text">Le moustique tigre est présent dans 78 départements en 2025, avec une progression vers le nord. La saison active démarre plus tôt en raison des températures printanières élevées.</div><div class="item-meta"><span class="item-date">Avril 2025</span><a href="https://www.anses.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--coral-light);color:var(--coral);">OFB</span><div class="item-text">Le frelon asiatique est classé ESOD dans 96 départements. Les arrêtés préfectoraux 2025 renforcent les obligations de signalement et de destruction des nids avec de nouvelles aides communales.</div><div class="item-meta"><span class="item-date">Mars 2025</span><a href="https://www.ofb.gouv.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--coral-light);color:var(--coral);">INRAE</span><div class="item-text">Une publication INRAE documente l'émergence de résistances aux anticoagulants chez les populations de rats dans 6 grandes agglomérations françaises, nécessitant une rotation des molécules actives.</div><div class="item-meta"><span class="item-date">Mars 2025</span><a href="https://www.inrae.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--coral-light);color:var(--coral);">Signalement Punaises</span><div class="item-text">Les signalements de punaises de lit progressent de 31 % en 2024, concentrés dans l'hôtellerie et les transports. Le plan national 2024-2027 prévoit des actions de sensibilisation renforcées.</div><div class="item-meta"><span class="item-date">Février 2025</span><a href="https://www.signalement-punaises.fr" target="_blank" class="item-link">↗ Source</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">anses.fr</span><span class="source-chip">ofb.gouv.fr</span><span class="source-chip">inrae.fr</span><span class="source-chip">sante.fr</span></div>
</div>
</div>
<!-- DÉSINFECTION -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">🧴</span><span class="card-title">Désinfection & nettoyage</span></div>
<span class="card-tag" style="background:var(--blue-light);color:var(--blue);">Biocides · Normes · Éco</span>
</div>
<div class="card-body">
<div id="content-desinfection">
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">ECHA / BPR</span><div class="item-text">La Commission européenne a approuvé en mars 2025 l'élargissement des usages du dioxyde de chlore (ClO₂) en TP 2, avec de nouvelles concentrations maximales autorisées pour les environnements alimentaires.</div><div class="item-meta"><span class="item-date">Mars 2025</span><a href="https://echa.europa.eu" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">AFNOR</span><div class="item-text">La norme NF EN 16615 sur l'évaluation bactéricide sur surfaces a été révisée en janvier 2025, avec des protocoles renforcés pour les surfaces poreuses en milieu agroalimentaire.</div><div class="item-meta"><span class="item-date">Janvier 2025</span><a href="https://www.afnor.org" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">Europropre</span><div class="item-text">Les alternatives aux biocides chimiques (vapeur sèche, UV-C, ozone) représentent 14 % du marché de la désinfection professionnelle en France, en hausse de 4 points sur un an.</div><div class="item-meta"><span class="item-date">Avril 2025</span><a href="https://www.europropre.com" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">CNIDEP</span><div class="item-text">Le CNIDEP publie un guide de bonnes pratiques pour la désinfection en présence de personnes vulnérables (EHPAD, crèches), avec des recommandations sur les temps d'attente post-application.</div><div class="item-meta"><span class="item-date">Février 2025</span><a href="https://www.cnidep.com" target="_blank" class="item-link">↗ Source</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">echa.europa.eu</span><span class="source-chip">afnor.org</span><span class="source-chip">cnidep.com</span><span class="source-chip">europropre.com</span></div>
</div>
</div>
<!-- OPPORTUNITÉS -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">🚀</span><span class="card-title">Opportunités</span></div>
<span class="card-tag" style="background:var(--green2-light);color:var(--green2);">Marché · Appels d'offres</span>
</div>
<div class="card-body">
<div id="content-opportunites">
<div class="item"><span class="item-source" style="background:var(--green2-light);color:var(--green2);">BOAMP</span><div class="item-text">Plusieurs marchés publics de formation Certibiocide sont ouverts en mai 2025 pour des collectivités d'Île-de-France et d'Occitanie. Budget estimé : 80 000150 000 € par lot. Délai : fin juin 2025.</div><div class="item-meta"><span class="item-date">Mai 2025</span><a href="https://www.boamp.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--green2-light);color:var(--green2);">Mon Compte Formation</span><div class="item-text">Le CPF finance le Certibiocide à hauteur de 980 €/stagiaire en moyenne. Les organismes référencés sur moncompteformation.gouv.fr avant la rentrée 2025 capteront ce flux en forte croissance.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://www.moncompteformation.gouv.fr" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--green2-light);color:var(--green2);">Hôtellerie</span><div class="item-text">La médiatisation des punaises de lit crée une forte demande de formation dans l'hôtellerie. Les groupes Accor, B&B et Best Western cherchent des prestataires 3D formés pour des contrats-cadres nationaux.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://www.linkedin.com" target="_blank" class="item-link">↗ LinkedIn</a></div></div>
<div class="item"><span class="item-source" style="background:var(--green2-light);color:var(--green2);">Agroalimentaire</span><div class="item-text">Les certifications IFS/BRC exigent désormais un personnel formé Certibiocide sur site dans les établissements agroalimentaires. Ce nouveau prérequis génère des besoins massifs en formation intra-entreprise.</div><div class="item-meta"><span class="item-date">2025</span></div></div>
</div>
<div class="sources-bar"><span class="source-chip">boamp.fr</span><span class="source-chip">moncompteformation.gouv.fr</span><span class="source-chip">LinkedIn</span><span class="source-chip">opcoep.fr</span></div>
</div>
</div>
<!-- INNOVATION -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">💡</span><span class="card-title">Innovation</span></div>
<span class="card-tag" style="background:var(--purple-light);color:var(--purple);">R&D · Technologies · Brevets</span>
</div>
<div class="card-body">
<div id="content-innovation">
<div class="item"><span class="item-source" style="background:var(--purple-light);color:var(--purple);">PubMed / INRAE</span><div class="item-text">Une étude publiée en février 2025 démontre l'efficacité des nématodes entomopathogènes (Steinernema feltiae) contre les larves de mouches en élevage, comme alternative aux insecticides chimiques conventionnels.</div><div class="item-meta"><span class="item-date">Février 2025</span><a href="https://pubmed.ncbi.nlm.nih.gov" target="_blank" class="item-link">↗ PubMed</a></div></div>
<div class="item"><span class="item-source" style="background:var(--purple-light);color:var(--purple);">IoT / Start-up</span><div class="item-text">Anticimex Smart déploie ses pièges connectés à IA en France pour la détection en temps réel des rongeurs, avec une interface de reporting utilisable directement par les techniciens Certibiocide.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://www.anticimex.com" target="_blank" class="item-link">↗ Source</a></div></div>
<div class="item"><span class="item-source" style="background:var(--purple-light);color:var(--purple);">CORDIS</span><div class="item-text">Le projet européen LIFE BioPest (2024-2027) finance le développement de bioinsecticides à base de champignons entomopathogènes pour remplacer les pyréthrinoïdes en milieu urbain. Budget : 3,2 M€.</div><div class="item-meta"><span class="item-date">20242027</span><a href="https://cordis.europa.eu" target="_blank" class="item-link">↗ CORDIS</a></div></div>
<div class="item"><span class="item-source" style="background:var(--purple-light);color:var(--purple);">BPIFrance</span><div class="item-text">BPIFrance ouvre un appel à projets "Green Tech 2025" incluant la lutte biologique contre les nuisibles urbains. Les PME du secteur 3D peuvent soumettre jusqu'au 30 juin 2025 pour un financement jusqu'à 200 000 €.</div><div class="item-meta"><span class="item-date">Juin 2025</span><a href="https://www.bpifrance.fr" target="_blank" class="item-link">↗ Source</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">pubmed.ncbi.nlm.nih.gov</span><span class="source-chip">cordis.europa.eu</span><span class="source-chip">bpifrance.fr</span><span class="source-chip">inrae.fr</span></div>
</div>
</div>
<!-- AGENDA -->
<div class="card grid-full">
<div class="card-header">
<div class="card-label"><span class="card-icon">📅</span><span class="card-title">Agenda — Formations & événements à venir</span></div>
<span class="card-tag" style="background:var(--slate-light);color:var(--slate);">Salons · Webinaires · Sessions</span>
</div>
<div class="card-body">
<div class="agenda-grid" id="content-agenda">
<div class="agenda-item"><span class="item-source" style="background:var(--slate-light);color:var(--slate);">Europropre</span><div class="item-text" style="font-size:13px;line-height:1.5;">Salon Europropre — Paris Expo Porte de Versailles. Nettoyage, hygiène et services professionnels.</div><div class="item-meta" style="margin-top:4px;"><span class="item-date">35 juin 2025, Paris</span><a href="https://www.europropre.com" target="_blank" class="item-link" style="margin-left:8px;">↗ Site</a></div></div>
<div class="agenda-item"><span class="item-source" style="background:var(--slate-light);color:var(--slate);">ANSES</span><div class="item-text" style="font-size:13px;line-height:1.5;">Webinaire ANSES "Résistances aux anticoagulants rodenticides : état des lieux". Inscription gratuite.</div><div class="item-meta" style="margin-top:4px;"><span class="item-date">15 mai 2025, en ligne</span><a href="https://www.anses.fr/fr/agenda" target="_blank" class="item-link" style="margin-left:8px;">↗ Inscription</a></div></div>
<div class="agenda-item"><span class="item-source" style="background:var(--slate-light);color:var(--slate);">PestWorld Europe</span><div class="item-text" style="font-size:13px;line-height:1.5;">Congrès européen de la lutte antiparasitaire. Conférences techniques et exposition commerciale.</div><div class="item-meta" style="margin-top:4px;"><span class="item-date">Septembre 2025, Berlin</span><a href="https://www.pestworld-europe.com" target="_blank" class="item-link" style="margin-left:8px;">↗ Site</a></div></div>
<div class="agenda-item"><span class="item-source" style="background:var(--slate-light);color:var(--slate);">INRAE</span><div class="item-text" style="font-size:13px;line-height:1.5;">Journée technique "Nuisibles urbains : nouvelles espèces invasives et lutte intégrée". Ouvert aux professionnels 3D.</div><div class="item-meta" style="margin-top:4px;"><span class="item-date">22 mai 2025, Lyon</span><a href="https://www.inrae.fr" target="_blank" class="item-link" style="margin-left:8px;">↗ Programme</a></div></div>
<div class="agenda-item"><span class="item-source" style="background:var(--slate-light);color:var(--slate);">Certibiocide CPF</span><div class="item-text" style="font-size:13px;line-height:1.5;">Sessions Certibiocide disponibles en juin-juillet 2025 en format hybride et présentiel dans toutes les régions.</div><div class="item-meta" style="margin-top:4px;"><span class="item-date">JuinJuillet 2025</span><a href="https://www.moncompteformation.gouv.fr" target="_blank" class="item-link" style="margin-left:8px;">↗ CPF</a></div></div>
<div class="agenda-item"><span class="item-source" style="background:var(--slate-light);color:var(--slate);">Expoprotection</span><div class="item-text" style="font-size:13px;line-height:1.5;">Salon international sécurité, sûreté et gestion des risques. Présence d'acteurs biocides et 3D.</div><div class="item-meta" style="margin-top:4px;"><span class="item-date">Novembre 2025, Paris</span><a href="https://www.expoprotection.com" target="_blank" class="item-link" style="margin-left:8px;">↗ Site</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">expoprotection.com</span><span class="source-chip">anses.fr</span><span class="source-chip">inrae.fr</span><span class="source-chip">pestworld-europe.com</span><span class="source-chip">europropre.com</span></div>
</div>
</div>
<!-- EUROPE -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">🇪🇺</span><span class="card-title">Veille européenne & internationale</span></div>
<span class="card-tag" style="background:var(--blue-light);color:var(--blue);">BPR · ECHA · OMS</span>
</div>
<div class="card-body">
<div id="content-europe">
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">ECHA / BPR</span><div class="item-text">La révision du règlement BPR 528/2012 avance avec une proposition pour accélérer l'évaluation des substances à faible risque et simplifier les procédures d'autorisation Union en 2025.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://echa.europa.eu/fr/regulations/biocidal-products-regulation/understanding-bpr" target="_blank" class="item-link">↗ ECHA</a></div></div>
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">EFSA</span><div class="item-text">L'EFSA publie en avril 2025 son rapport sur les résidus de biocides dans les aliments, soulignant la nécessité de renforcer les contrôles sur les produits TP 4 et TP 14.</div><div class="item-meta"><span class="item-date">Avril 2025</span><a href="https://www.efsa.europa.eu" target="_blank" class="item-link">↗ EFSA</a></div></div>
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">OMS</span><div class="item-text">L'OMS alerte sur la résistance mondiale aux insecticides chez les moustiques Aedes et Anopheles, recommandant des stratégies de rotation et de lutte intégrée pour préserver l'efficacité des traitements.</div><div class="item-meta"><span class="item-date">Mars 2025</span><a href="https://www.who.int" target="_blank" class="item-link">↗ OMS</a></div></div>
<div class="item"><span class="item-source" style="background:var(--blue-light);color:var(--blue);">Commission Européenne</span><div class="item-text">La directive SUR (utilisation durable des pesticides) impacte le secteur biocides, plusieurs États membres alignant leurs réglementations sur les principes de réduction des risques chimiques.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://ec.europa.eu" target="_blank" class="item-link">↗ Source</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">echa.europa.eu</span><span class="source-chip">efsa.europa.eu</span><span class="source-chip">who.int</span><span class="source-chip">ec.europa.eu</span></div>
</div>
</div>
<!-- RH -->
<div class="card">
<div class="card-header">
<div class="card-label"><span class="card-icon">👥</span><span class="card-title">Veille RH & concurrentielle</span></div>
<span class="card-tag" style="background:var(--amber-light);color:var(--amber);">Emploi · Acteurs · Certif</span>
</div>
<div class="card-body">
<div id="content-rh">
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">LinkedIn / France Travail</span><div class="item-text">Plus de 280 offres d'emploi de techniciens 3D en France en mai 2025, dont 45 mentionnent le Certibiocide comme prérequis. Les salaires progressent de 8 % par rapport à 2024.</div><div class="item-meta"><span class="item-date">Mai 2025</span><a href="https://www.linkedin.com/jobs" target="_blank" class="item-link">↗ LinkedIn</a></div></div>
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">France Compétences</span><div class="item-text">Deux nouvelles certifications RNCP liées aux biocides enregistrées en 2025 : "Responsable Hygiène Environnementale" (niveau 5) et "Gestionnaire de plan de maîtrise sanitaire" avec module biocides.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://www.francecompetences.fr" target="_blank" class="item-link">↗ RNCP</a></div></div>
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">Presse Pro</span><div class="item-text">Rentokil Initial renforce sa présence en France avec l'acquisition de 3 PME régionales du secteur 3D en 2025, intensifiant la concurrence sur les contrats-cadres nationaux et les formations internes.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://www.linkedin.com" target="_blank" class="item-link">↗ LinkedIn</a></div></div>
<div class="item"><span class="item-source" style="background:var(--amber-light);color:var(--amber);">FFDH</span><div class="item-text">La FFDH lance une campagne nationale de valorisation des métiers 3D en 2025, avec des partenariats avec des lycées professionnels pour développer des formations initiales au secteur.</div><div class="item-meta"><span class="item-date">2025</span><a href="https://www.ffdh.fr" target="_blank" class="item-link">↗ FFDH</a></div></div>
</div>
<div class="sources-bar"><span class="source-chip">linkedin.com</span><span class="source-chip">francetravail.fr</span><span class="source-chip">francecompetences.fr</span><span class="source-chip">ffdh.fr</span></div>
</div>
</div>
</div>
<div class="last-update" id="lastUpdate">Données pré-chargées — Mai 2025</div>
</div>
<script>
// ── Utils ──────────────────────────────────────────────────────────────────
function getWeekLabel() {
const now = new Date();
const mon = new Date(now); mon.setDate(now.getDate() - ((now.getDay()+6)%7));
const sun = new Date(mon); sun.setDate(mon.getDate()+6);
const f = d => d.toLocaleDateString('fr-FR',{day:'numeric',month:'short'});
return `Sem. ${f(mon)} ${f(sun)}`;
}
function esc(s){ return s ? String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;') : ''; }
function setSkeleton(id){
const el = document.getElementById('content-'+id); if(!el) return;
el.innerHTML = [1,2,3].map(()=>`<div class="sk-block"><div class="sk s"></div><div class="sk f"></div><div class="sk m"></div></div>`).join('');
}
function setBanner(type, html){
const b = document.getElementById('statusBanner');
b.className = 'status-banner banner-'+type;
document.getElementById('statusText').innerHTML = html;
}
// ── Sections config ────────────────────────────────────────────────────────
const SECTIONS = [
{ id:'reglementaire', label:'Réglementaire', c:'--teal', bg:'--teal-light',
prompt:`Recherche web : 4 actualités réglementaires récentes sur les biocides en France/Europe (ECHA, ANSES, MTE, Légifrance). Nouvelles AMM, retraits, BPR, obligations Certibiocide. JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases factuelles","date":"date","url":"url ou null"}]}` },
{ id:'marche', label:'Marché formation', c:'--amber', bg:'--amber-light',
prompt:`Recherche web : 4 infos récentes sur le marché formation Certibiocide France (Qualiopi, CPF, OPCO, sessions, chiffres). JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases","date":"date","url":"url ou null"}]}` },
{ id:'nuisibles', label:'Nuisibles & ESOD', c:'--coral', bg:'--coral-light',
prompt:`Recherche web : 4 actualités récentes sur nuisibles/ESOD en France (moustique tigre, frelon asiatique, rongeurs résistants, punaises de lit). Sources ANSES, INRAE, OFB. JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases","date":"date","url":"url ou null"}]}` },
{ id:'desinfection', label:'Désinfection', c:'--blue', bg:'--blue-light',
prompt:`Recherche web : 4 actualités récentes sur désinfection/biocides (normes AFNOR, produits homologués, alternatives). JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases","date":"date","url":"url ou null"}]}` },
{ id:'opportunites', label:'Opportunités', c:'--green2', bg:'--green2-light',
prompt:`Recherche web : 4 opportunités concrètes pour organisme formation Certibiocide (BOAMP appels d'offres, CPF, secteurs demandeurs). JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases","date":"date","url":"url ou null"}]}` },
{ id:'innovation', label:'Innovation', c:'--purple', bg:'--purple-light',
prompt:`Recherche web : 4 innovations récentes biocides/lutte antiparasitaire (bioinsecticides, IoT, IA, brevets, CORDIS, PubMed). JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases","date":"date","url":"url ou null"}]}` },
{ id:'europe', label:'Veille européenne', c:'--blue', bg:'--blue-light',
prompt:`Recherche web : 4 actualités européennes/internationales récentes sur biocides (révision BPR, EFSA, OMS résistances insecticides). JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases","date":"date","url":"url ou null"}]}` },
{ id:'rh', label:'RH & Concurrence', c:'--amber', bg:'--amber-light',
prompt:`Recherche web : 4 infos RH/concurrentielles secteur 3D et Certibiocide (offres emploi LinkedIn, mouvements acteurs, certifications RNCP). JSON uniquement sans markdown : {"items":[{"source":"SOURCE","text":"2 phrases","date":"date","url":"url ou null"}]}` },
];
// ── Fetch one section via Netlify function ─────────────────────────────────
async function fetchSection(s, dotIndex) {
setSkeleton(s.id);
updateDot(dotIndex, 'active');
document.getElementById('loadingStatus').textContent = `Recherche : ${s.label}`;
try {
const res = await fetch('/.netlify/functions/veille', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: s.prompt })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Erreur serveur');
if (data.error) throw new Error(data.error);
if (data.items?.length) {
renderItems(s.id, data.items, s.c, s.bg);
updateDot(dotIndex, 'done');
} else throw new Error('Réponse vide');
} catch(e) {
console.error(s.id, e);
const el = document.getElementById('content-'+s.id);
if(el) el.innerHTML = `<div style="text-align:center;padding:1rem;color:var(--muted);font-size:13px;">⚠️ ${esc(e.message)}</div>`;
updateDot(dotIndex, 'done');
}
}
function renderItems(id, items, cVar, bgVar) {
const el = document.getElementById('content-'+id); if(!el) return;
el.innerHTML = items.map((item,i) => `
<div class="item" style="animation-delay:${i*0.07}s">
<span class="item-source" style="background:var(${bgVar});color:var(${cVar});">${esc(item.source)}</span>
<div class="item-text">${esc(item.text)}</div>
<div class="item-meta">
<span class="item-date">${esc(item.date||'')}</span>
${item.url?`<a href="${esc(item.url)}" target="_blank" class="item-link">↗ Source</a>`:''}
</div>
</div>`).join('');
}
// ── Progress dots ──────────────────────────────────────────────────────────
function initDots(n) {
document.getElementById('loadingProgress').innerHTML =
Array(n).fill('').map((_,i)=>`<div class="lp-dot" id="dot-${i}"></div>`).join('');
}
function updateDot(i, state) {
const d = document.getElementById('dot-'+i); if(d){ d.className='lp-dot '+state; }
}
// ── Main refresh ───────────────────────────────────────────────────────────
async function refreshAll() {
const btn = document.getElementById('refreshBtn');
const icon = document.getElementById('refreshIcon');
btn.disabled = true; icon.classList.add('spin');
document.getElementById('loadingOverlay').classList.add('active');
setBanner('info','Actualisation en cours…');
initDots(SECTIONS.length);
// Run in parallel by pairs to avoid rate limits
for(let i=0; i<SECTIONS.length; i+=2){
await Promise.all([
fetchSection(SECTIONS[i], i),
SECTIONS[i+1] ? fetchSection(SECTIONS[i+1], i+1) : Promise.resolve()
]);
}
const now = new Date();
const label = now.toLocaleDateString('fr-FR',{weekday:'long',day:'numeric',month:'long'}) +
' à ' + now.toLocaleTimeString('fr-FR',{hour:'2-digit',minute:'2-digit'});
document.getElementById('lastUpdate').textContent = `Dernière actualisation : ${label}`;
document.getElementById('weekBadge').textContent = getWeekLabel();
setBanner('ok', `✅ Actualisation terminée — ${label}`);
btn.disabled = false; icon.classList.remove('spin');
document.getElementById('loadingOverlay').classList.remove('active');
}
// ── Init ───────────────────────────────────────────────────────────────────
document.getElementById('weekBadge').textContent = getWeekLabel();
</script>
</body>
</html>

View File

@@ -1,817 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rapport Veille Semaine 20 - Certibiocide</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
--teal: #0F6E56;
--teal-mid: #1D9E75;
--teal-light: #E1F5EE;
--amber: #BA7517;
--amber-mid: #D4921A;
--amber-light: #FAEEDA;
--amber-dark: #633806;
--coral: #993C1D;
--coral-mid: #D85A30;
--coral-light: #FAECE7;
--purple: #BA7517;
--purple-light: #FAEEDA;
--blue: #185FA5;
--blue-light: #E6F1FB;
--green: #2E7D32;
--green-light: #E8F5E9;
--bg: #F7F6F2;
--white: #FFFFFF;
--text: #1a1a18;
--text-muted: #6b6a65;
--border: rgba(0,0,0,0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
body {
font-family: 'DM Sans', sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
padding-top: 70px;
}
/* ===== HEADER FIXE ===== */
header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 70px;
background: rgba(250, 238, 218, 0.98);
backdrop-filter: blur(10px);
border-bottom: 2px solid var(--amber);
z-index: 1000;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
}
.logo {
font-family: 'Syne', sans-serif;
font-size: 16px;
font-weight: 700;
letter-spacing: -0.5px;
background: linear-gradient(135deg, var(--teal-mid), var(--coral-mid));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-decoration: none;
}
nav {
display: flex;
gap: 2rem;
}
nav a {
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
text-decoration: none;
color: var(--text-muted);
transition: color 0.3s ease;
}
nav a:hover {
color: var(--amber);
}
/* ===== PROGRESS BAR ===== */
.progress {
position: fixed;
top: 70px;
left: 0;
right: 0;
height: 3px;
background: var(--border);
z-index: 999;
}
.progress-bar {
height: 100%;
background: var(--amber);
width: 0%;
transition: width 0.3s ease;
}
/* ===== MAIN CONTENT ===== */
main {
max-width: 1000px;
margin: 0 auto;
padding: 3rem 2rem;
}
.section {
margin-bottom: 3rem;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ===== BREADCRUMB ===== */
.breadcrumb {
display: flex;
gap: 0.5rem;
align-items: center;
font-size: 12px;
color: var(--text-muted);
margin-bottom: 1.5rem;
font-family: 'Syne', sans-serif;
}
.breadcrumb a {
color: var(--amber);
text-decoration: none;
font-weight: 600;
transition: color 0.3s ease;
}
.breadcrumb a:hover {
color: var(--amber-dark);
}
/* ===== PAGE HEADER ===== */
.page-header {
background: var(--amber-light);
border-left: 4px solid var(--amber);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.page-header h1 {
font-family: 'Syne', sans-serif;
font-size: 2.2rem;
font-weight: 800;
color: var(--text);
margin-bottom: 0.5rem;
}
.page-meta {
display: flex;
flex-wrap: wrap;
gap: 2rem;
font-size: 0.95rem;
color: var(--text-muted);
margin-top: 1rem;
}
.meta-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.meta-item strong {
color: var(--amber);
}
/* ===== CONTENT SECTIONS ===== */
h2 {
font-family: 'Syne', sans-serif;
font-size: 1.6rem;
font-weight: 700;
color: var(--text);
margin-bottom: 1rem;
margin-top: 2.5rem;
padding-bottom: 0.75rem;
border-bottom: 3px solid var(--amber);
display: flex;
align-items: center;
gap: 0.75rem;
}
h3 {
font-family: 'Syne', sans-serif;
font-size: 1.05rem;
font-weight: 700;
color: var(--text);
margin-top: 1.5rem;
margin-bottom: 0.75rem;
}
/* ===== CONTENT ITEMS ===== */
.content-item {
background: var(--white);
border-left: 4px solid var(--amber-light);
border-radius: 6px;
padding: 1.5rem;
margin-bottom: 1.5rem;
transition: all 0.3s ease;
}
.content-item:hover {
border-left-color: var(--amber);
box-shadow: 0 4px 12px rgba(186, 117, 23, 0.1);
}
.content-item strong {
color: var(--amber-dark);
display: block;
margin-bottom: 0.5rem;
font-size: 1rem;
}
.content-item p {
font-size: 0.95rem;
line-height: 1.7;
margin-bottom: 0.75rem;
color: var(--text);
}
.content-item p:last-child {
margin-bottom: 0;
}
.item-meta {
display: flex;
gap: 1rem;
flex-wrap: wrap;
font-size: 0.85rem;
color: var(--text-muted);
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid rgba(186, 117, 23, 0.1);
}
.item-date {
display: flex;
align-items: center;
gap: 0.4rem;
}
.item-link {
color: var(--amber);
text-decoration: none;
font-weight: 600;
transition: color 0.3s ease;
}
.item-link:hover {
color: var(--amber-dark);
}
/* ===== ATTENTION SECTION ===== */
.attention-section {
background: linear-gradient(135deg, var(--amber-light), rgba(250, 236, 218, 0.7));
border: 2px solid var(--amber);
border-radius: 8px;
padding: 2rem;
margin: 2rem 0;
}
.attention-section h2 {
border-bottom-color: var(--amber-dark);
margin-top: 0;
}
.attention-item {
background: var(--white);
border-left: 4px solid var(--amber-dark);
border-radius: 6px;
padding: 1.25rem;
margin-bottom: 1rem;
}
.attention-item:last-child {
margin-bottom: 0;
}
.attention-item strong {
color: var(--amber-dark);
display: block;
margin-bottom: 0.5rem;
}
/* ===== TABLE OF CONTENTS ===== */
.toc {
background: var(--blue-light);
border-left: 4px solid var(--blue);
border-radius: 8px;
padding: 1.5rem;
margin: 2rem 0;
}
.toc h3 {
margin-top: 0;
color: var(--blue);
}
.toc-list {
list-style: none;
padding: 0;
margin: 0;
}
.toc-list li {
margin-bottom: 0.5rem;
}
.toc-list a {
color: var(--blue);
text-decoration: none;
font-weight: 500;
font-size: 0.95rem;
transition: color 0.3s ease;
}
.toc-list a:hover {
color: var(--teal-mid);
}
/* ===== FOOTER ===== */
footer {
background: var(--text);
color: var(--white);
padding: 2.5rem;
text-align: center;
font-size: 13px;
margin-top: 4rem;
border-top: 1px solid var(--border);
}
footer p {
margin-bottom: 0.5rem;
}
footer p:last-child {
opacity: 0.6;
font-size: 12px;
margin-top: 0.5rem;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 768px) {
header {
padding: 0 1rem;
}
.logo {
font-size: 14px;
}
nav {
gap: 1rem;
}
nav a {
font-size: 9px;
}
main {
padding: 2rem 1rem;
}
h1 {
font-size: 1.8rem;
}
h2 {
font-size: 1.3rem;
}
.page-meta {
gap: 1rem;
flex-direction: column;
}
.attention-section {
padding: 1.5rem;
}
}
</style>
</head>
<body>
<!-- PROGRESS BAR -->
<div class="progress">
<div class="progress-bar" id="progressBar"></div>
</div>
<!-- HEADER -->
<header>
<div class="logo">NextGN Formation</div>
<nav>
<a href="../../../index.html">Exercices interactifs</a>
<a href="../../../index.html#documentation">Documentation</a>
<a href="../../../index.html#rapports">Rapports de veille</a>
<a href="../../../index.html#about">À propos</a>
<a href="../../../index.html#contact">Contact</a>
</nav>
</header>
<!-- MAIN CONTENT -->
<main>
<!-- BREADCRUMB -->
<div class="breadcrumb">
<a href="index.html">Accueil</a>
<span></span>
<a href="veille-index.html">Rapports de veille</a>
<span></span>
<span>Semaine 20</span>
</div>
<!-- PAGE HEADER -->
<section class="page-header">
<h1>📊 Rapport Veille Semaine 20</h1>
<div class="page-meta">
<div class="meta-item">
<strong>Période :</strong> 11-17 mai 2026
</div>
<div class="meta-item">
<strong>8 rubriques</strong> analysées
</div>
<div class="meta-item">
<strong>25+</strong> sources officielles
</div>
</div>
</section>
<!-- TABLE OF CONTENTS -->
<div class="toc">
<h3>📑 Sommaire</h3>
<ul class="toc-list">
<li><a href="#reglementaire">⚖️ Réglementaire</a></li>
<li><a href="#marche">🎓 Marché formation</a></li>
<li><a href="#nuisibles">🐀 Nuisibles & ESOD</a></li>
<li><a href="#desinfection">🧴 Désinfection</a></li>
<li><a href="#opportunites">💡 Opportunités</a></li>
<li><a href="#innovation">🔬 Innovation</a></li>
<li><a href="#europe">🇪🇺 Veille européenne</a></li>
<li><a href="#rh">👥 RH & Concurrence</a></li>
<li><a href="#attention">⚠️ Points d'attention</a></li>
</ul>
</div>
<!-- ===== RÉGLEMENTAIRE ===== -->
<section class="section" id="reglementaire">
<h2>⚖️ Réglementaire — AMM, retraits, BPR, obligations Certibiocide</h2>
<div class="content-item">
<strong>ANSES / Certibiocide — Obligation étendue aux établissements de santé</strong>
<p>Depuis le 1er janvier 2026, le programme de formation Certibiocide (7 heures, renouvelable tous les 5 ans) est obligatoire pour tous les professionnels utilisant, achetant ou distribuant des produits biocides à usage professionnel. Cette obligation s'étend désormais aux centres de santé et établissements médico-sociaux.</p>
<div class="item-meta">
<div class="item-date">📅 Janvier 2026</div>
<a href="#" class="item-link">Source ANSES →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Non-renouvellement cyperméthrine (TP18)</strong>
<p>La cyperméthrine (insecticide pyréthrinoïde, TP18) ne remplit plus les conditions d'approbation européenne suite au retrait volontaire de la demande de renouvellement par le demandeur en mai 2025. Ce retrait a des conséquences directes sur les produits rodenticides et insecticides contenant cette substance active.</p>
<div class="item-meta">
<div class="item-date">📅 Conséquences effectives 2026</div>
<a href="#" class="item-link">ECHA guidance →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Avis positif éthanol (désinfection)</strong>
<p>Le Comité des produits biocides de l'ECHA a publié un avis d'examen positif soutenant l'éthanol comme substance active biocide pour la désinfection (TP1, TP2). Ce jalon ouvre la voie à l'approbation formelle au niveau européen.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">ECHA guidance →</a>
</div>
</div>
<div class="content-item">
<strong>Knoell — Newsletter mondiale biocides</strong>
<p>La newsletter mensuelle mondiale de Knoell (février 2026) recense les dernières approbations et rejets de substances actives biocides au niveau international, utile pour anticiper les évolutions du portefeuille produits disponibles en France.</p>
<div class="item-meta">
<div class="item-date">📅 Février 2026</div>
<a href="#" class="item-link">Knoell news →</a>
</div>
</div>
</section>
<!-- ===== MARCHÉ FORMATION ===== -->
<section class="section" id="marche">
<h2>🎓 Marché formation — Qualiopi, CPF, OPCO</h2>
<div class="content-item">
<strong>Parlement français — Loi anti-fraude formation ADOPTÉE</strong>
<p>Le projet de loi de lutte contre les fraudes à la formation professionnelle a été définitivement adopté le 13 mai 2026. Il instaure des sanctions renforcées pour les fraudes au CPF, de nouvelles obligations de contrôle pour les OPCO et les CFA, et impose la vérification d'identité du stagiaire dès l'inscription et au premier jour de formation.</p>
<div class="item-meta">
<div class="item-date">📅 13 mai 2026</div>
<a href="#" class="item-link">Service-public.fr →</a>
</div>
</div>
<div class="content-item">
<strong>Service-public.fr — Évolutions CPF 2026</strong>
<p>Les nouvelles règles d'utilisation du CPF pour 2026 sont officiellement publiées : justificatifs renforcés selon le montant de la formation, délai de rétractation porté à 30 jours, et procédures de contrôle systématiques côté OPCO avant toute validation de dossier.</p>
<div class="item-meta">
<div class="item-date">📅 Mai 2026</div>
<a href="#" class="item-link">Lire →</a>
</div>
</div>
<div class="content-item">
<strong>Centre Inffo — Bilan formation 2026 : contexte dégradé</strong>
<p>Centre Inffo qualifie 2026 d'"annus horribilis" pour la formation professionnelle en raison de la multiplication des contrôles, du durcissement réglementaire et des tensions budgétaires touchant les financeurs. Un contexte à surveiller pour les organismes indépendants.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">Centre Inffo →</a>
</div>
</div>
<div class="content-item">
<strong>FAFCEA — Qualiopi obligatoire pour artisans</strong>
<p>Qualiopi est désormais obligatoire pour accéder aux financements FAFCEA (artisans), en plus des OPCO. Rappel : Qualiopi ne suffit pas seul pour l'éligibilité CPF ; des critères complémentaires s'appliquent via Mon Compte Formation.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FAFCEA info →</a>
</div>
</div>
</section>
<!-- ===== NUISIBLES & ESOD ===== -->
<section class="section" id="nuisibles">
<h2>🐀 Nuisibles & ESOD — Espèces nuisibles et invasives</h2>
<div class="content-item">
<strong>Santé Publique France — Moustique tigre, couverture 90 départements</strong>
<p>Le dispositif national de surveillance et de contrôle des maladies transmises par le moustique tigre est renforcé pour 2026. Le moustique tigre couvre désormais environ 90 départements métropolitains (contre 81 début 2025), progression directement liée aux hivers de plus en plus doux.</p>
<div class="item-meta">
<div class="item-date">📅 Printemps 2026</div>
<a href="#" class="item-link">SPF →</a>
</div>
</div>
<div class="content-item">
<strong>Professionnels 3D — Pression moustique tigre en hausse</strong>
<p>Les professionnels de la lutte antiparasitaire alertent sur la pression croissante liée au moustique tigre : 20 000 interventions en 2024, demande en forte hausse pour le printemps-été 2026. Les plateformes de signalement ANSES restent les outils de référence.</p>
<div class="item-meta">
<div class="item-date">📅 Avril-mai 2026</div>
<a href="#" class="item-link">ANSES signalement →</a>
</div>
</div>
<div class="content-item">
<strong>ARS Île-de-France — Guide espèces à enjeux sanitaires</strong>
<p>La région Île-de-France publie un guide à destination des collectivités sur la lutte contre les espèces à enjeux sanitaires : moustique tigre, tiques, punaises de lit, rongeurs, chenilles urticantes. Document de référence utile pour les modules de formation.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">ARS IDF →</a>
</div>
</div>
<div class="content-item">
<strong>Lyon Capitale — Espèces invasives et débat de lutte</strong>
<p>Lyon et sa métropole font face à une recrudescence des espèces invasives (frelon asiatique, moustique tigre, chenilles processionnaires). Le débat sur les moyens de lutte, entre approche chimique et solutions alternatives, est relancé dans les collectivités.</p>
<div class="item-meta">
<div class="item-date">📅 Printemps 2026</div>
<a href="#" class="item-link">Lire →</a>
</div>
</div>
</section>
<!-- ===== DÉSINFECTION ===== -->
<section class="section" id="desinfection">
<h2>🧴 Désinfection — Normes, produits homologués, alternatives</h2>
<div class="content-item">
<strong>AFNOR / NF EN 14885 — Norme désinfectants</strong>
<p>Norme de référence pour les biocides désinfectants (hôpitaux, industrie alimentaire, environnement). Complétée par NF EN 1276 (bactéricides) et NF EN 1650 (fongicides) pour la validation de l'efficacité des produits.</p>
<div class="item-meta">
<div class="item-date">📅 En vigueur</div>
<a href="#" class="item-link">AFNOR →</a>
</div>
</div>
<div class="content-item">
<strong>AFNOR — Révision NF U43-500 en cours</strong>
<p>La norme NF U43-500 sur les bonnes pratiques d'application des produits phytosanitaires et biocides est en cours de consultation. Elle concerne directement les applicateurs professionnels et pourrait impacter le contenu des formations Certibiocide.</p>
<div class="item-meta">
<div class="item-date">📅 En cours de révision</div>
<a href="#" class="item-link">AFNOR norminfo →</a>
</div>
</div>
<div class="content-item">
<strong>Climalife — Certibiocide Désinfectants obligatoire santé</strong>
<p>La certification Certibiocide Désinfectants (7h, 5 ans) est désormais requise dans les établissements de santé pour toute personne supervisant l'achat ou l'utilisation de désinfectants professionnels. Opportunité pour les organismes de formation spécialisés.</p>
<div class="item-meta">
<div class="item-date">📅 Janvier 2026</div>
<a href="#" class="item-link">Climalife →</a>
</div>
</div>
</section>
<!-- ===== OPPORTUNITÉS ===== -->
<section class="section" id="opportunites">
<h2>💡 Opportunités — BOAMP, CPF, secteurs demandeurs</h2>
<div class="content-item">
<strong>BOAMP 3/BOAMP/266207 — Marché EPMO-VGE, Paris 7e</strong>
<p>Marché de dératisation, désinsectisation et désinfection pour le Musée d'Orsay, le Musée de l'Orangerie et les installations administratives associées. Marché public actif en 2026.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
<div class="content-item">
<strong>BOAMP 3/BOAMP/264816 — Accord-cadre prévention nuisibles</strong>
<p>Accord-cadre à bon de commande pour prestations de prévention et lutte contre les nuisibles, montant maximum 50 000 € HT/an. Marché accessible aux structures de taille intermédiaire.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
<div class="content-item">
<strong>BOAMP 3/BOAMP/2616972 — Département de l'Oise</strong>
<p>Missions 3D (dératisation, désinsectisation, désinfection + traitements spécifiques) sur les sites départementaux et le réseau routier de l'Oise, en 2 lots. Notification prévue juillet 2026.</p>
<div class="item-meta">
<div class="item-date">📅 Mars-juillet 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
<div class="content-item">
<strong>BOAMP 3/BOAMP/2632494 — Carrières-sous-Poissy (78)</strong>
<p>Marché anti-nuisibles 4D pour Carrières-sous-Poissy. Au total, 81+ appels d'offres dératisation/désinsectisation répertoriés en cours. Opportunité commerciale majeure pour formateurs spécialisés.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
</section>
<!-- ===== INNOVATION ===== -->
<section class="section" id="innovation">
<h2>🔬 Innovation — Bioinsecticides, IoT, IA, brevets</h2>
<div class="content-item">
<strong>Groupe Berkem — NOVATERM® avec IA</strong>
<p>Piège anti-termites intégrant un suivi par intelligence artificielle pour la détection précoce de l'activité des insectes. Présenté à Parasitec 2025, ce type de solution connectée illustre la convergence IA/piégeage physique dans le secteur 3D.</p>
<div class="item-meta">
<div class="item-date">📅 Parasitec 2025</div>
<a href="#" class="item-link">Berkem →</a>
</div>
</div>
<div class="content-item">
<strong>NPiMagazine — Capteurs IoT & analyse data</strong>
<p>Le trio capteurs/traitement de données IoT/analyse est identifié comme le modèle gagnant de la lutte antiparasitaire connectée : détection en temps réel, alertes automatisées, réduction des interventions non justifiées et optimisation des tournées.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">NPI Magazine →</a>
</div>
</div>
<div class="content-item">
<strong>CORDIS / LOCDIS Project — Lutte biologique européenne</strong>
<p>Le projet européen LOCDIS (financé par l'UE via CORDIS) explore la lutte antiparasitaire biologique comme alternative aux biocides chimiques. Les résultats s'orientent vers des solutions combinant agents biologiques et dispositifs connectés.</p>
<div class="item-meta">
<div class="item-date">📅 En cours</div>
<a href="#" class="item-link">CORDIS →</a>
</div>
</div>
<div class="content-item">
<strong>Nuisible Control — Tendances 2026 dératisation éthique</strong>
<p>Le secteur 3D évolue vers une dératisation plus éthique : remplacement progressif des poses systématiques de raticides par des pièges connectés, IA prédictive et cartographie des risques. Tendance de fond à intégrer dans les supports de formation.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">Nuisible Control →</a>
</div>
</div>
</section>
<!-- ===== VEILLE EUROPÉENNE ===== -->
<section class="section" id="europe">
<h2>🇪🇺 Veille européenne — BPR, EFSA, résistances</h2>
<div class="content-item">
<strong>Commission européenne — Évaluation BPR en cours</strong>
<p>L'évaluation formelle du Règlement sur les Produits Biocides (BPR n°528/2012) se poursuit depuis le Q4 2025. Elle porte sur l'efficacité du cadre réglementaire et pourrait déboucher sur une révision législative majeure impactant tous les types de produits biocides.</p>
<div class="item-meta">
<div class="item-date">📅 Q4 2025 en cours</div>
<a href="#" class="item-link">EC health →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Cyperméthrine non-renouvelée</strong>
<p>La cyperméthrine ne sera pas renouvelée en Europe. Ce retrait impacte directement les produits insecticides de type 18 (lutte contre les insectes nuisibles) et 14 (rodenticides associés). Les formulateurs doivent anticiper des reformulations.</p>
<div class="item-meta">
<div class="item-date">📅 Effectif 2026</div>
<a href="#" class="item-link">ECHA →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Guidance résistances intégrée</strong>
<p>La "Resistance Guidance" (guidance sur les résistances aux biocides) est désormais intégrée dans l'évaluation des nouvelles soumissions BPR. Les questions de résistances aux insecticides font officiellement partie du cadre d'évaluation européen.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">ECHA →</a>
</div>
</div>
</section>
<!-- ===== RH & CONCURRENCE ===== -->
<section class="section" id="rh">
<h2>👥 RH & Concurrence — Emploi 3D, certifications RNCP</h2>
<div class="content-item">
<strong>Indeed (8 mai 2026) — 125+ offres techniciens 3D</strong>
<p>Plus de 100 offres d'emploi de technicien nuisibles et 25+ postes de technicien dératisation/désinsectisation répertoriés en France. Le marché de l'emploi 3D reste très dynamique avec une demande saisonnière renforcée pour printemps-été 2026.</p>
<div class="item-meta">
<div class="item-date">📅 8 mai 2026</div>
<a href="#" class="item-link">Indeed →</a>
</div>
</div>
<div class="content-item">
<strong>France Compétences — RNCP41350 nouveau CQP</strong>
<p>Une nouvelle certification CQP "Technicien en maîtrise du risque nuisible" (RNCP41350) est référencée sur MesCertifs, en complément du CQP historique RNCP36313. Le Certibiocide (RS6442) reste requis dans toutes les fiches de poste du secteur.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">MesCertifs →</a>
</div>
</div>
<div class="content-item">
<strong>Ensystex Solution Pro — CQP métier d'avenir</strong>
<p>Article mettant en avant le CQP technicien applicateur comme "métier d'avenir" face aux exigences réglementaires croissantes (Certibiocide, connaissance des résistances, outils connectés). Argument commercial à fort potentiel pour le recrutement en formation continue.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">Ensystex →</a>
</div>
</div>
</section>
<!-- ===== POINTS D'ATTENTION ===== -->
<section class="attention-section" id="attention">
<h2>⚠️ Points d'attention — Semaine 20</h2>
<div class="attention-item">
<strong>1. Loi anti-fraude formation définitivement adoptée (13 mai 2026)</strong>
<p>Entrée en vigueur progressive dès le 1er juillet 2026 : vérification d'identité obligatoire au 1er jour de formation CPF, contrôles OPCO renforcés.</p>
<p style="margin-top: 0.75rem;"><strong>➜ Action :</strong> En tant que formateur indépendant Certibiocide, anticiper dès maintenant : émargements numériques, procédure d'identification stagiaires, et vérification de la cohérence CPF/projet professionnel lors des inscriptions.</p>
</div>
<div class="attention-item">
<strong>2. Non-renouvellement de la cyperméthrine en Europe</strong>
<p>Ce retrait impacte des produits TP14 et TP18 encore largement utilisés.</p>
<p style="margin-top: 0.75rem;"><strong>➜ Action :</strong> Les supports de formation Certibiocide Nuisibles doivent être mis à jour pour alerter les stagiaires sur ce changement de portefeuille produit et les orienter vers des substances actives alternatives homologuées.</p>
</div>
<div class="attention-item">
<strong>3. Quatre appels d'offres BOAMP 3D actifs en 2026</strong>
<p>Opportunité concrète pour générer de nouveaux clients 3D et augmenter la demande de formations.</p>
<p style="margin-top: 0.75rem;"><strong>➜ Action :</strong> Les marchés publics 3D génèrent des besoins en recrutement de techniciens certifiés, donc en formation Certibiocide. Démarcher les entreprises attributaires de ces marchés peut être une stratégie de développement commercial directe.</p>
</div>
</section>
</main>
<!-- FOOTER -->
<footer>
<p>&copy; 2026 NextGN Formation - Formations Certibiocide & Techniques</p>
<p style="margin-top: 10px; opacity: 0.6;">Tous droits réservés — Gauthier Chombart & Nathan Chauwin — Formateurs indépendants</p>
</footer>
<!-- PROGRESS BAR SCRIPT -->
<script>
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
const scrollPercent = (scrollTop / docHeight) * 100;
document.getElementById('progressBar').style.width = scrollPercent + '%';
});
</script>
</body>
</html>

View File

@@ -1,817 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rapport Veille Semaine 21 - Certibiocide</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
--teal: #0F6E56;
--teal-mid: #1D9E75;
--teal-light: #E1F5EE;
--amber: #BA7517;
--amber-mid: #D4921A;
--amber-light: #FAEEDA;
--amber-dark: #633806;
--coral: #993C1D;
--coral-mid: #D85A30;
--coral-light: #FAECE7;
--purple: #BA7517;
--purple-light: #FAEEDA;
--blue: #185FA5;
--blue-light: #E6F1FB;
--green: #2E7D32;
--green-light: #E8F5E9;
--bg: #F7F6F2;
--white: #FFFFFF;
--text: #1a1a18;
--text-muted: #6b6a65;
--border: rgba(0,0,0,0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
body {
font-family: 'DM Sans', sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
padding-top: 70px;
}
/* ===== HEADER FIXE ===== */
header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 70px;
background: rgba(250, 238, 218, 0.98);
backdrop-filter: blur(10px);
border-bottom: 2px solid var(--amber);
z-index: 1000;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
}
.logo {
font-family: 'Syne', sans-serif;
font-size: 16px;
font-weight: 700;
letter-spacing: -0.5px;
background: linear-gradient(135deg, var(--teal-mid), var(--coral-mid));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-decoration: none;
}
nav {
display: flex;
gap: 2rem;
}
nav a {
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
text-decoration: none;
color: var(--text-muted);
transition: color 0.3s ease;
}
nav a:hover {
color: var(--amber);
}
/* ===== PROGRESS BAR ===== */
.progress {
position: fixed;
top: 70px;
left: 0;
right: 0;
height: 3px;
background: var(--border);
z-index: 999;
}
.progress-bar {
height: 100%;
background: var(--amber);
width: 0%;
transition: width 0.3s ease;
}
/* ===== MAIN CONTENT ===== */
main {
max-width: 1000px;
margin: 0 auto;
padding: 3rem 2rem;
}
.section {
margin-bottom: 3rem;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ===== BREADCRUMB ===== */
.breadcrumb {
display: flex;
gap: 0.5rem;
align-items: center;
font-size: 12px;
color: var(--text-muted);
margin-bottom: 1.5rem;
font-family: 'Syne', sans-serif;
}
.breadcrumb a {
color: var(--amber);
text-decoration: none;
font-weight: 600;
transition: color 0.3s ease;
}
.breadcrumb a:hover {
color: var(--amber-dark);
}
/* ===== PAGE HEADER ===== */
.page-header {
background: var(--amber-light);
border-left: 4px solid var(--amber);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.page-header h1 {
font-family: 'Syne', sans-serif;
font-size: 2.2rem;
font-weight: 800;
color: var(--text);
margin-bottom: 0.5rem;
}
.page-meta {
display: flex;
flex-wrap: wrap;
gap: 2rem;
font-size: 0.95rem;
color: var(--text-muted);
margin-top: 1rem;
}
.meta-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.meta-item strong {
color: var(--amber);
}
/* ===== CONTENT SECTIONS ===== */
h2 {
font-family: 'Syne', sans-serif;
font-size: 1.6rem;
font-weight: 700;
color: var(--text);
margin-bottom: 1rem;
margin-top: 2.5rem;
padding-bottom: 0.75rem;
border-bottom: 3px solid var(--amber);
display: flex;
align-items: center;
gap: 0.75rem;
}
h3 {
font-family: 'Syne', sans-serif;
font-size: 1.05rem;
font-weight: 700;
color: var(--text);
margin-top: 1.5rem;
margin-bottom: 0.75rem;
}
/* ===== CONTENT ITEMS ===== */
.content-item {
background: var(--white);
border-left: 4px solid var(--amber-light);
border-radius: 6px;
padding: 1.5rem;
margin-bottom: 1.5rem;
transition: all 0.3s ease;
}
.content-item:hover {
border-left-color: var(--amber);
box-shadow: 0 4px 12px rgba(186, 117, 23, 0.1);
}
.content-item strong {
color: var(--amber-dark);
display: block;
margin-bottom: 0.5rem;
font-size: 1rem;
}
.content-item p {
font-size: 0.95rem;
line-height: 1.7;
margin-bottom: 0.75rem;
color: var(--text);
}
.content-item p:last-child {
margin-bottom: 0;
}
.item-meta {
display: flex;
gap: 1rem;
flex-wrap: wrap;
font-size: 0.85rem;
color: var(--text-muted);
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid rgba(186, 117, 23, 0.1);
}
.item-date {
display: flex;
align-items: center;
gap: 0.4rem;
}
.item-link {
color: var(--amber);
text-decoration: none;
font-weight: 600;
transition: color 0.3s ease;
}
.item-link:hover {
color: var(--amber-dark);
}
/* ===== ATTENTION SECTION ===== */
.attention-section {
background: linear-gradient(135deg, var(--amber-light), rgba(250, 236, 218, 0.7));
border: 2px solid var(--amber);
border-radius: 8px;
padding: 2rem;
margin: 2rem 0;
}
.attention-section h2 {
border-bottom-color: var(--amber-dark);
margin-top: 0;
}
.attention-item {
background: var(--white);
border-left: 4px solid var(--amber-dark);
border-radius: 6px;
padding: 1.25rem;
margin-bottom: 1rem;
}
.attention-item:last-child {
margin-bottom: 0;
}
.attention-item strong {
color: var(--amber-dark);
display: block;
margin-bottom: 0.5rem;
}
/* ===== TABLE OF CONTENTS ===== */
.toc {
background: var(--blue-light);
border-left: 4px solid var(--blue);
border-radius: 8px;
padding: 1.5rem;
margin: 2rem 0;
}
.toc h3 {
margin-top: 0;
color: var(--blue);
}
.toc-list {
list-style: none;
padding: 0;
margin: 0;
}
.toc-list li {
margin-bottom: 0.5rem;
}
.toc-list a {
color: var(--blue);
text-decoration: none;
font-weight: 500;
font-size: 0.95rem;
transition: color 0.3s ease;
}
.toc-list a:hover {
color: var(--teal-mid);
}
/* ===== FOOTER ===== */
footer {
background: var(--text);
color: var(--white);
padding: 2.5rem;
text-align: center;
font-size: 13px;
margin-top: 4rem;
border-top: 1px solid var(--border);
}
footer p {
margin-bottom: 0.5rem;
}
footer p:last-child {
opacity: 0.6;
font-size: 12px;
margin-top: 0.5rem;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 768px) {
header {
padding: 0 1rem;
}
.logo {
font-size: 14px;
}
nav {
gap: 1rem;
}
nav a {
font-size: 9px;
}
main {
padding: 2rem 1rem;
}
h1 {
font-size: 1.8rem;
}
h2 {
font-size: 1.3rem;
}
.page-meta {
gap: 1rem;
flex-direction: column;
}
.attention-section {
padding: 1.5rem;
}
}
</style>
</head>
<body>
<!-- PROGRESS BAR -->
<div class="progress">
<div class="progress-bar" id="progressBar"></div>
</div>
<!-- HEADER -->
<header>
<div class="logo">NextGN Formation</div>
<nav>
<a href="../../../index.html">Exercices interactifs</a>
<a href="../../../index.html#documentation">Documentation</a>
<a href="../../../index.html#rapports">Rapports de veille</a>
<a href="../../../index.html#about">À propos</a>
<a href="../../../index.html#contact">Contact</a>
</nav>
</header>
<!-- MAIN CONTENT -->
<main>
<!-- BREADCRUMB -->
<div class="breadcrumb">
<a href="index.html">Accueil</a>
<span></span>
<a href="veille-index.html">Rapports de veille</a>
<span></span>
<span>Semaine 21</span>
</div>
<!-- PAGE HEADER -->
<section class="page-header">
<h1>📊 Rapport Veille Semaine 21</h1>
<div class="page-meta">
<div class="meta-item">
<strong>Période :</strong> 18-24 mai 2026
</div>
<div class="meta-item">
<strong>8 rubriques</strong> analysées
</div>
<div class="meta-item">
<strong>25+</strong> sources officielles
</div>
</div>
</section>
<!-- TABLE OF CONTENTS -->
<div class="toc">
<h3>📑 Sommaire</h3>
<ul class="toc-list">
<li><a href="#reglementaire">⚖️ Réglementaire</a></li>
<li><a href="#marche">🎓 Marché formation</a></li>
<li><a href="#nuisibles">🐀 Nuisibles & ESOD</a></li>
<li><a href="#desinfection">🧴 Désinfection</a></li>
<li><a href="#opportunites">💡 Opportunités</a></li>
<li><a href="#innovation">🔬 Innovation</a></li>
<li><a href="#europe">🇪🇺 Veille européenne</a></li>
<li><a href="#rh">👥 RH & Concurrence</a></li>
<li><a href="#attention">⚠️ Points d'attention</a></li>
</ul>
</div>
<!-- ===== RÉGLEMENTAIRE ===== -->
<section class="section" id="reglementaire">
<h2>⚖️ Réglementaire — AMM, retraits, BPR, obligations Certibiocide</h2>
<div class="content-item">
<strong>ANSES / Certibiocide — Obligation étendue aux établissements de santé</strong>
<p>Depuis le 1er janvier 2026, le programme de formation Certibiocide (7 heures, renouvelable tous les 5 ans) est obligatoire pour tous les professionnels utilisant, achetant ou distribuant des produits biocides à usage professionnel. Cette obligation s'étend désormais aux centres de santé et établissements médico-sociaux.</p>
<div class="item-meta">
<div class="item-date">📅 Janvier 2026</div>
<a href="#" class="item-link">Source ANSES →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Non-renouvellement cyperméthrine (TP18)</strong>
<p>La cyperméthrine (insecticide pyréthrinoïde, TP18) ne remplit plus les conditions d'approbation européenne suite au retrait volontaire de la demande de renouvellement par le demandeur en mai 2025. Ce retrait a des conséquences directes sur les produits rodenticides et insecticides contenant cette substance active.</p>
<div class="item-meta">
<div class="item-date">📅 Conséquences effectives 2026</div>
<a href="#" class="item-link">ECHA guidance →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Avis positif éthanol (désinfection)</strong>
<p>Le Comité des produits biocides de l'ECHA a publié un avis d'examen positif soutenant l'éthanol comme substance active biocide pour la désinfection (TP1, TP2). Ce jalon ouvre la voie à l'approbation formelle au niveau européen.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">ECHA guidance →</a>
</div>
</div>
<div class="content-item">
<strong>Knoell — Newsletter mondiale biocides</strong>
<p>La newsletter mensuelle mondiale de Knoell (février 2026) recense les dernières approbations et rejets de substances actives biocides au niveau international, utile pour anticiper les évolutions du portefeuille produits disponibles en France.</p>
<div class="item-meta">
<div class="item-date">📅 Février 2026</div>
<a href="#" class="item-link">Knoell news →</a>
</div>
</div>
</section>
<!-- ===== MARCHÉ FORMATION ===== -->
<section class="section" id="marche">
<h2>🎓 Marché formation — Qualiopi, CPF, OPCO</h2>
<div class="content-item">
<strong>Parlement français — Loi anti-fraude formation ADOPTÉE</strong>
<p>Le projet de loi de lutte contre les fraudes à la formation professionnelle a été définitivement adopté le 13 mai 2026. Il instaure des sanctions renforcées pour les fraudes au CPF, de nouvelles obligations de contrôle pour les OPCO et les CFA, et impose la vérification d'identité du stagiaire dès l'inscription et au premier jour de formation.</p>
<div class="item-meta">
<div class="item-date">📅 13 mai 2026</div>
<a href="#" class="item-link">Service-public.fr →</a>
</div>
</div>
<div class="content-item">
<strong>Service-public.fr — Évolutions CPF 2026</strong>
<p>Les nouvelles règles d'utilisation du CPF pour 2026 sont officiellement publiées : justificatifs renforcés selon le montant de la formation, délai de rétractation porté à 30 jours, et procédures de contrôle systématiques côté OPCO avant toute validation de dossier.</p>
<div class="item-meta">
<div class="item-date">📅 Mai 2026</div>
<a href="#" class="item-link">Lire →</a>
</div>
</div>
<div class="content-item">
<strong>Centre Inffo — Bilan formation 2026 : contexte dégradé</strong>
<p>Centre Inffo qualifie 2026 d'"annus horribilis" pour la formation professionnelle en raison de la multiplication des contrôles, du durcissement réglementaire et des tensions budgétaires touchant les financeurs. Un contexte à surveiller pour les organismes indépendants.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">Centre Inffo →</a>
</div>
</div>
<div class="content-item">
<strong>FAFCEA — Qualiopi obligatoire pour artisans</strong>
<p>Qualiopi est désormais obligatoire pour accéder aux financements FAFCEA (artisans), en plus des OPCO. Rappel : Qualiopi ne suffit pas seul pour l'éligibilité CPF ; des critères complémentaires s'appliquent via Mon Compte Formation.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FAFCEA info →</a>
</div>
</div>
</section>
<!-- ===== NUISIBLES & ESOD ===== -->
<section class="section" id="nuisibles">
<h2>🐀 Nuisibles & ESOD — Espèces nuisibles et invasives</h2>
<div class="content-item">
<strong>Santé Publique France — Moustique tigre, couverture 90 départements</strong>
<p>Le dispositif national de surveillance et de contrôle des maladies transmises par le moustique tigre est renforcé pour 2026. Le moustique tigre couvre désormais environ 90 départements métropolitains (contre 81 début 2025), progression directement liée aux hivers de plus en plus doux.</p>
<div class="item-meta">
<div class="item-date">📅 Printemps 2026</div>
<a href="#" class="item-link">SPF →</a>
</div>
</div>
<div class="content-item">
<strong>Professionnels 3D — Pression moustique tigre en hausse</strong>
<p>Les professionnels de la lutte antiparasitaire alertent sur la pression croissante liée au moustique tigre : 20 000 interventions en 2024, demande en forte hausse pour le printemps-été 2026. Les plateformes de signalement ANSES restent les outils de référence.</p>
<div class="item-meta">
<div class="item-date">📅 Avril-mai 2026</div>
<a href="#" class="item-link">ANSES signalement →</a>
</div>
</div>
<div class="content-item">
<strong>ARS Île-de-France — Guide espèces à enjeux sanitaires</strong>
<p>La région Île-de-France publie un guide à destination des collectivités sur la lutte contre les espèces à enjeux sanitaires : moustique tigre, tiques, punaises de lit, rongeurs, chenilles urticantes. Document de référence utile pour les modules de formation.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">ARS IDF →</a>
</div>
</div>
<div class="content-item">
<strong>Lyon Capitale — Espèces invasives et débat de lutte</strong>
<p>Lyon et sa métropole font face à une recrudescence des espèces invasives (frelon asiatique, moustique tigre, chenilles processionnaires). Le débat sur les moyens de lutte, entre approche chimique et solutions alternatives, est relancé dans les collectivités.</p>
<div class="item-meta">
<div class="item-date">📅 Printemps 2026</div>
<a href="#" class="item-link">Lire →</a>
</div>
</div>
</section>
<!-- ===== DÉSINFECTION ===== -->
<section class="section" id="desinfection">
<h2>🧴 Désinfection — Normes, produits homologués, alternatives</h2>
<div class="content-item">
<strong>AFNOR / NF EN 14885 — Norme désinfectants</strong>
<p>Norme de référence pour les biocides désinfectants (hôpitaux, industrie alimentaire, environnement). Complétée par NF EN 1276 (bactéricides) et NF EN 1650 (fongicides) pour la validation de l'efficacité des produits.</p>
<div class="item-meta">
<div class="item-date">📅 En vigueur</div>
<a href="#" class="item-link">AFNOR →</a>
</div>
</div>
<div class="content-item">
<strong>AFNOR — Révision NF U43-500 en cours</strong>
<p>La norme NF U43-500 sur les bonnes pratiques d'application des produits phytosanitaires et biocides est en cours de consultation. Elle concerne directement les applicateurs professionnels et pourrait impacter le contenu des formations Certibiocide.</p>
<div class="item-meta">
<div class="item-date">📅 En cours de révision</div>
<a href="#" class="item-link">AFNOR norminfo →</a>
</div>
</div>
<div class="content-item">
<strong>Climalife — Certibiocide Désinfectants obligatoire santé</strong>
<p>La certification Certibiocide Désinfectants (7h, 5 ans) est désormais requise dans les établissements de santé pour toute personne supervisant l'achat ou l'utilisation de désinfectants professionnels. Opportunité pour les organismes de formation spécialisés.</p>
<div class="item-meta">
<div class="item-date">📅 Janvier 2026</div>
<a href="#" class="item-link">Climalife →</a>
</div>
</div>
</section>
<!-- ===== OPPORTUNITÉS ===== -->
<section class="section" id="opportunites">
<h2>💡 Opportunités — BOAMP, CPF, secteurs demandeurs</h2>
<div class="content-item">
<strong>BOAMP 3/BOAMP/266207 — Marché EPMO-VGE, Paris 7e</strong>
<p>Marché de dératisation, désinsectisation et désinfection pour le Musée d'Orsay, le Musée de l'Orangerie et les installations administratives associées. Marché public actif en 2026.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
<div class="content-item">
<strong>BOAMP 3/BOAMP/264816 — Accord-cadre prévention nuisibles</strong>
<p>Accord-cadre à bon de commande pour prestations de prévention et lutte contre les nuisibles, montant maximum 50 000 € HT/an. Marché accessible aux structures de taille intermédiaire.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
<div class="content-item">
<strong>BOAMP 3/BOAMP/2616972 — Département de l'Oise</strong>
<p>Missions 3D (dératisation, désinsectisation, désinfection + traitements spécifiques) sur les sites départementaux et le réseau routier de l'Oise, en 2 lots. Notification prévue juillet 2026.</p>
<div class="item-meta">
<div class="item-date">📅 Mars-juillet 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
<div class="content-item">
<strong>BOAMP 3/BOAMP/2632494 — Carrières-sous-Poissy (78)</strong>
<p>Marché anti-nuisibles 4D pour Carrières-sous-Poissy. Au total, 81+ appels d'offres dératisation/désinsectisation répertoriés en cours. Opportunité commerciale majeure pour formateurs spécialisés.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">FranceMarchés →</a>
</div>
</div>
</section>
<!-- ===== INNOVATION ===== -->
<section class="section" id="innovation">
<h2>🔬 Innovation — Bioinsecticides, IoT, IA, brevets</h2>
<div class="content-item">
<strong>Groupe Berkem — NOVATERM® avec IA</strong>
<p>Piège anti-termites intégrant un suivi par intelligence artificielle pour la détection précoce de l'activité des insectes. Présenté à Parasitec 2025, ce type de solution connectée illustre la convergence IA/piégeage physique dans le secteur 3D.</p>
<div class="item-meta">
<div class="item-date">📅 Parasitec 2025</div>
<a href="#" class="item-link">Berkem →</a>
</div>
</div>
<div class="content-item">
<strong>NPiMagazine — Capteurs IoT & analyse data</strong>
<p>Le trio capteurs/traitement de données IoT/analyse est identifié comme le modèle gagnant de la lutte antiparasitaire connectée : détection en temps réel, alertes automatisées, réduction des interventions non justifiées et optimisation des tournées.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">NPI Magazine →</a>
</div>
</div>
<div class="content-item">
<strong>CORDIS / LOCDIS Project — Lutte biologique européenne</strong>
<p>Le projet européen LOCDIS (financé par l'UE via CORDIS) explore la lutte antiparasitaire biologique comme alternative aux biocides chimiques. Les résultats s'orientent vers des solutions combinant agents biologiques et dispositifs connectés.</p>
<div class="item-meta">
<div class="item-date">📅 En cours</div>
<a href="#" class="item-link">CORDIS →</a>
</div>
</div>
<div class="content-item">
<strong>Nuisible Control — Tendances 2026 dératisation éthique</strong>
<p>Le secteur 3D évolue vers une dératisation plus éthique : remplacement progressif des poses systématiques de raticides par des pièges connectés, IA prédictive et cartographie des risques. Tendance de fond à intégrer dans les supports de formation.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">Nuisible Control →</a>
</div>
</div>
</section>
<!-- ===== VEILLE EUROPÉENNE ===== -->
<section class="section" id="europe">
<h2>🇪🇺 Veille européenne — BPR, EFSA, résistances</h2>
<div class="content-item">
<strong>Commission européenne — Évaluation BPR en cours</strong>
<p>L'évaluation formelle du Règlement sur les Produits Biocides (BPR n°528/2012) se poursuit depuis le Q4 2025. Elle porte sur l'efficacité du cadre réglementaire et pourrait déboucher sur une révision législative majeure impactant tous les types de produits biocides.</p>
<div class="item-meta">
<div class="item-date">📅 Q4 2025 en cours</div>
<a href="#" class="item-link">EC health →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Cyperméthrine non-renouvelée</strong>
<p>La cyperméthrine ne sera pas renouvelée en Europe. Ce retrait impacte directement les produits insecticides de type 18 (lutte contre les insectes nuisibles) et 14 (rodenticides associés). Les formulateurs doivent anticiper des reformulations.</p>
<div class="item-meta">
<div class="item-date">📅 Effectif 2026</div>
<a href="#" class="item-link">ECHA →</a>
</div>
</div>
<div class="content-item">
<strong>ECHA — Guidance résistances intégrée</strong>
<p>La "Resistance Guidance" (guidance sur les résistances aux biocides) est désormais intégrée dans l'évaluation des nouvelles soumissions BPR. Les questions de résistances aux insecticides font officiellement partie du cadre d'évaluation européen.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">ECHA →</a>
</div>
</div>
</section>
<!-- ===== RH & CONCURRENCE ===== -->
<section class="section" id="rh">
<h2>👥 RH & Concurrence — Emploi 3D, certifications RNCP</h2>
<div class="content-item">
<strong>Indeed (8 mai 2026) — 125+ offres techniciens 3D</strong>
<p>Plus de 100 offres d'emploi de technicien nuisibles et 25+ postes de technicien dératisation/désinsectisation répertoriés en France. Le marché de l'emploi 3D reste très dynamique avec une demande saisonnière renforcée pour printemps-été 2026.</p>
<div class="item-meta">
<div class="item-date">📅 8 mai 2026</div>
<a href="#" class="item-link">Indeed →</a>
</div>
</div>
<div class="content-item">
<strong>France Compétences — RNCP41350 nouveau CQP</strong>
<p>Une nouvelle certification CQP "Technicien en maîtrise du risque nuisible" (RNCP41350) est référencée sur MesCertifs, en complément du CQP historique RNCP36313. Le Certibiocide (RS6442) reste requis dans toutes les fiches de poste du secteur.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">MesCertifs →</a>
</div>
</div>
<div class="content-item">
<strong>Ensystex Solution Pro — CQP métier d'avenir</strong>
<p>Article mettant en avant le CQP technicien applicateur comme "métier d'avenir" face aux exigences réglementaires croissantes (Certibiocide, connaissance des résistances, outils connectés). Argument commercial à fort potentiel pour le recrutement en formation continue.</p>
<div class="item-meta">
<div class="item-date">📅 2026</div>
<a href="#" class="item-link">Ensystex →</a>
</div>
</div>
</section>
<!-- ===== POINTS D'ATTENTION ===== -->
<section class="attention-section" id="attention">
<h2>⚠️ Points d'attention — Semaine 21</h2>
<div class="attention-item">
<strong>1. Loi anti-fraude formation définitivement adoptée (13 mai 2026)</strong>
<p>Entrée en vigueur progressive dès le 1er juillet 2026 : vérification d'identité obligatoire au 1er jour de formation CPF, contrôles OPCO renforcés.</p>
<p style="margin-top: 0.75rem;"><strong>➜ Action :</strong> En tant que formateur indépendant Certibiocide, anticiper dès maintenant : émargements numériques, procédure d'identification stagiaires, et vérification de la cohérence CPF/projet professionnel lors des inscriptions.</p>
</div>
<div class="attention-item">
<strong>2. Non-renouvellement de la cyperméthrine en Europe</strong>
<p>Ce retrait impacte des produits TP14 et TP18 encore largement utilisés.</p>
<p style="margin-top: 0.75rem;"><strong>➜ Action :</strong> Les supports de formation Certibiocide Nuisibles doivent être mis à jour pour alerter les stagiaires sur ce changement de portefeuille produit et les orienter vers des substances actives alternatives homologuées.</p>
</div>
<div class="attention-item">
<strong>3. Quatre appels d'offres BOAMP 3D actifs en 2026</strong>
<p>Opportunité concrète pour générer de nouveaux clients 3D et augmenter la demande de formations.</p>
<p style="margin-top: 0.75rem;"><strong>➜ Action :</strong> Les marchés publics 3D génèrent des besoins en recrutement de techniciens certifiés, donc en formation Certibiocide. Démarcher les entreprises attributaires de ces marchés peut être une stratégie de développement commercial directe.</p>
</div>
</section>
</main>
<!-- FOOTER -->
<footer>
<p>&copy; 2026 NextGN Formation - Formations Certibiocide & Techniques</p>
<p style="margin-top: 10px; opacity: 0.6;">Tous droits réservés — Gauthier Chombart & Nathan Chauwin — Formateurs indépendants</p>
</footer>
<!-- PROGRESS BAR SCRIPT -->
<script>
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
const scrollPercent = (scrollTop / docHeight) * 100;
document.getElementById('progressBar').style.width = scrollPercent + '%';
});
</script>
</body>
</html>

View File

@@ -1,663 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Veille Certibiocide — Semaine 22 | 25 au 31 mai 2026</title>
<meta name="description" content="Rapport de veille réglementaire et technique Certibiocide — Semaine 22, du 25 au 31 mai 2026. Réglementation biocides, marché formation, nuisibles, désinfection, BOAMP, innovation, Europe, RH." />
<style>
/* ── Reset & base ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
font-size: 16px;
line-height: 1.7;
color: #1a1a2e;
background: #f7f8fc;
}
a { color: #2563eb; text-decoration: none; }
a:hover { text-decoration: underline; }
/* ── Header ── */
header {
background: linear-gradient(135deg, #1e3a5f 0%, #2563eb 100%);
color: #fff;
padding: 3rem 2rem 2.5rem;
text-align: center;
}
header .badge {
display: inline-block;
background: rgba(255,255,255,0.2);
border: 1px solid rgba(255,255,255,0.35);
border-radius: 999px;
padding: 0.25rem 1rem;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
margin-bottom: 1rem;
}
header h1 { font-size: clamp(1.6rem, 4vw, 2.4rem); font-weight: 800; margin-bottom: 0.5rem; }
header p { font-size: 1rem; opacity: 0.85; }
/* ── Nav sommaire ── */
nav {
background: #fff;
border-bottom: 1px solid #e2e8f0;
padding: 0.75rem 2rem;
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.25rem;
justify-content: center;
position: sticky;
top: 0;
z-index: 100;
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
nav a {
font-size: 0.82rem;
font-weight: 600;
color: #475569;
white-space: nowrap;
}
nav a:hover { color: #2563eb; text-decoration: none; }
/* ── Layout ── */
main {
max-width: 900px;
margin: 2rem auto;
padding: 0 1.25rem;
display: flex;
flex-direction: column;
gap: 1.75rem;
}
/* ── Attention box ── */
.attention-box {
background: #fff7ed;
border: 1px solid #fdba74;
border-left: 4px solid #f97316;
border-radius: 10px;
padding: 1.5rem 1.75rem;
}
.attention-box h2 {
font-size: 1rem;
font-weight: 800;
color: #9a3412;
margin-bottom: 1rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.attention-items { display: flex; flex-direction: column; gap: 0.85rem; }
.attention-item {
display: flex;
gap: 0.75rem;
align-items: flex-start;
}
.attention-num {
flex-shrink: 0;
width: 1.6rem;
height: 1.6rem;
background: #f97316;
color: #fff;
border-radius: 50%;
font-size: 0.78rem;
font-weight: 800;
display: flex;
align-items: center;
justify-content: center;
margin-top: 0.15rem;
}
.attention-item p { font-size: 0.92rem; color: #7c2d12; }
.attention-item strong { color: #9a3412; }
/* ── Section cards ── */
section {
background: #fff;
border: 1px solid #e2e8f0;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.section-header {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1.1rem 1.5rem;
border-bottom: 1px solid #e2e8f0;
}
.section-emoji { font-size: 1.4rem; }
.section-header h2 {
font-size: 0.95rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.06em;
color: #1e3a5f;
}
.section-header .section-sub {
font-size: 0.8rem;
font-weight: 500;
color: #94a3b8;
margin-left: auto;
}
/* ── News items ── */
.news-list { list-style: none; }
.news-item {
padding: 1.1rem 1.5rem;
border-bottom: 1px solid #f1f5f9;
display: grid;
grid-template-columns: auto 1fr;
gap: 0 1rem;
}
.news-item:last-child { border-bottom: none; }
.news-dot {
width: 8px;
height: 8px;
background: #2563eb;
border-radius: 50%;
margin-top: 0.6rem;
flex-shrink: 0;
}
.news-content {}
.news-source {
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #2563eb;
margin-bottom: 0.2rem;
}
.news-text { font-size: 0.92rem; color: #334155; margin-bottom: 0.3rem; }
.news-meta {
display: flex;
align-items: center;
gap: 0.75rem;
flex-wrap: wrap;
}
.news-date {
font-size: 0.75rem;
color: #94a3b8;
font-style: italic;
}
.news-link {
font-size: 0.75rem;
font-weight: 600;
color: #64748b;
border: 1px solid #e2e8f0;
border-radius: 4px;
padding: 0.1rem 0.5rem;
}
.news-link:hover { background: #f1f5f9; text-decoration: none; }
/* ── Warning note ── */
.note-warning {
margin: 0 1.5rem 1rem;
padding: 0.6rem 0.9rem;
background: #fefce8;
border: 1px solid #fde68a;
border-radius: 6px;
font-size: 0.8rem;
color: #92400e;
}
/* ── Footer ── */
footer {
text-align: center;
padding: 2.5rem 1rem;
color: #94a3b8;
font-size: 0.8rem;
border-top: 1px solid #e2e8f0;
margin-top: 1rem;
}
footer strong { color: #475569; }
/* ── Responsive ── */
@media (max-width: 600px) {
header { padding: 2rem 1rem 1.75rem; }
nav { padding: 0.6rem 1rem; gap: 0.4rem 0.9rem; }
.section-header, .news-item { padding-left: 1rem; padding-right: 1rem; }
}
</style>
</head>
<body>
<!-- ═══ HEADER ═══ -->
<header>
<div class="badge">Rapport de veille</div>
<h1>Veille Certibiocide — Semaine 22</h1>
<p>Semaine du 25 au 31 mai 2026 &nbsp;·&nbsp; 8 rubriques &nbsp;·&nbsp; Sources officielles prioritaires</p>
</header>
<!-- ═══ NAVIGATION ═══ -->
<nav aria-label="Sommaire">
<a href="#reglementaire">⚖️ Réglementaire</a>
<a href="#formation">🎓 Formation</a>
<a href="#nuisibles">🐀 Nuisibles</a>
<a href="#desinfection">🧴 Désinfection</a>
<a href="#opportunites">💡 Opportunités</a>
<a href="#innovation">🔬 Innovation</a>
<a href="#europe">🇪🇺 Europe</a>
<a href="#rh">👥 RH</a>
</nav>
<main>
<!-- ═══ POINTS D'ATTENTION ═══ -->
<div class="attention-box" id="attention">
<h2>📌 Points d'attention — Semaine 22</h2>
<div class="attention-items">
<div class="attention-item">
<div class="attention-num">1</div>
<p><strong>Deadline FAFCEA Qualiopi : 30 juin 2026.</strong> Dans 5 semaines, la période de souplesse prend fin. Tout organisme de formation non encore certifié Qualiopi perd l'accès aux financements FAFCEA au 1er juillet. Si la démarche est en cours, c'est le moment de finaliser.</p>
</div>
<div class="attention-item">
<div class="attention-num">2</div>
<p><strong>Échéance perturbateurs endocriniens au 31 décembre 2026.</strong> Des retraits de substances actives supplémentaires sont probables début 2027, dans la lignée du non-renouvellement de la cyperméthrine. À anticiper dans la mise à jour des supports de formation Certibiocide Nuisibles.</p>
</div>
<div class="attention-item">
<div class="attention-num">3</div>
<p><strong>94 appels d'offres BOAMP dératisation actifs.</strong> Le marché public 3D est très dynamique ce printemps. Les entreprises attributaires ont besoin de techniciens certifiés : opportunité de prospection directe auprès des entreprises 3D répondant à ces AO.</p>
</div>
</div>
</div>
<!-- ═══ 1. RÉGLEMENTAIRE ═══ -->
<section id="reglementaire">
<div class="section-header">
<span class="section-emoji">⚖️</span>
<h2>Réglementaire</h2>
<span class="section-sub">AMM · BPR · Certibiocide</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">ANSES / BioCID</div>
<p class="news-text">Le registre des AMM biocides recense 3 223 produits biocides autorisés en France (données sept. 2024, dernière actualisation publique disponible). Toute décision récente de mai 2026 est à consulter directement sur biocid-anses.fr — aucune nouvelle AMM ou retrait majeur n'a été identifié via sources ouvertes cette semaine.</p>
<div class="news-meta">
<span class="news-date">Permanent</span>
<a class="news-link" href="https://www.anses.fr/fr/decisions_biocide" target="_blank" rel="noopener">→ anses.fr</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Services-Propreté</div>
<p class="news-text">Point de situation sur l'état de la réglementation biocides en France : rappel des obligations Certibiocide en vigueur depuis janvier 2026 et des procédures de vérification des habilitations pour les acheteurs professionnels.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://services-proprete.fr/technique-1/27682/ou-en-est-la-reglementation-biocides" target="_blank" rel="noopener">→ services-proprete.fr</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">ECHA — Perturbateurs endocriniens</div>
<p class="news-text">Pour un certain nombre de substances actives biocides, les données manquantes relatives aux propriétés de perturbation endocrinienne doivent être soumises aux autorités compétentes avant le <strong>31 décembre 2026</strong>. Échéance critique pour les formulateurs et acteurs de la chaîne biocides.</p>
<div class="news-meta">
<span class="news-date">Avant le 31 déc. 2026</span>
<a class="news-link" href="https://echa.europa.eu/fr/biocides" target="_blank" rel="noopener">→ echa.europa.eu</a>
</div>
</div>
</li>
</ul>
<p class="note-warning">⚠️ Aucune nouvelle AMM biocide spécifique à mai 2026 n'a pu être vérifiée via sources ouvertes cette semaine. Consulter directement <a href="https://biocid-anses.fr" target="_blank">BioCID</a> pour les décisions récentes.</p>
</section>
<!-- ═══ 2. FORMATION ═══ -->
<section id="formation">
<div class="section-header">
<span class="section-emoji">🎓</span>
<h2>Marché formation</h2>
<span class="section-sub">Qualiopi · CPF · OPCO</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">FAFCEA / Qualiopi — Fin de la période de souplesse</div>
<p class="news-text">La période de souplesse pour accéder aux financements FAFCEA sans Qualiopi se termine le <strong>30 juin 2026</strong>. À partir du 1er juillet 2026, aucun financement FAFCEA ne sera accordé sans certification Qualiopi valide. Point d'attention immédiat pour les formateurs indépendants.</p>
<div class="news-meta">
<span class="news-date">Deadline : 30 juin 2026</span>
<a class="news-link" href="https://csfc-federation.org/blog/qualiopi-devient-obligatoire-pour-les-financements-fafcea-des-2026/" target="_blank" rel="noopener">→ csfc-federation.org</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">France Compétences — Renouvellement instances Qualiopi</div>
<p class="news-text">Les 8 instances de labellisation habilitées à délivrer la certification Qualiopi ont été renouvelées pour 3 ans à compter du 1er janvier 2026 (validité jusqu'en 2028). Stabilité du dispositif de certification garantie pour les organismes en cours d'audit.</p>
<div class="news-meta">
<span class="news-date">Janvier 2026</span>
<a class="news-link" href="https://www.digi-certif.com/debut-2026-quelles-actualites-pour-la-formation-pro-et-qualiopi/" target="_blank" rel="noopener">→ digi-certif.com</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">OPCO / Urssaf — Nouvelle option de collecte</div>
<p class="news-text">Depuis janvier 2026, les branches professionnelles peuvent choisir de confier la collecte de leurs contributions conventionnelles de formation aux Urssaf plutôt qu'à leur OPCO. Ce changement peut modifier les circuits de financement des formations sectorielles, dont le Certibiocide.</p>
<div class="news-meta">
<span class="news-date">Janvier 2026</span>
<a class="news-link" href="https://www.starthack.fr/financement-de-la-formation-professionnelle-en-2026-opco-budgets-et-obligations-des-centres-de-formation/" target="_blank" rel="noopener">→ starthack.fr</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Centre Inffo</div>
<p class="news-text">Centre Inffo qualifie 2026 d'« annus horribilis » pour la formation professionnelle : multiplication des contrôles post-loi anti-fraude, tensions budgétaires chez les financeurs, durcissement réglementaire. Un contexte qui pèse sur les petits organismes mais valorise ceux bien structurés.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.centre-inffo.fr/site-centre-inffo/actualites-centre-inffo/le-quotidien-de-la-formation-actualite-formation-professionnelle-apprentissage/actualites-2026/2026-annus-horribilis-pour-la-formation-professionnelle" target="_blank" rel="noopener">→ centre-inffo.fr</a>
</div>
</div>
</li>
</ul>
</section>
<!-- ═══ 3. NUISIBLES ═══ -->
<section id="nuisibles">
<div class="section-header">
<span class="section-emoji">🐀</span>
<h2>Nuisibles &amp; ESOD</h2>
<span class="section-sub">Moustique tigre · Frelon · Rongeurs · Punaises</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Santé Publique France / ANSES</div>
<p class="news-text">Le moustique tigre colonise désormais environ <strong>90 départements</strong> métropolitains. Le plan national de lutte lancé en mars 2026 mobilise les plateformes de signalement officielles (<a href="https://signalement-moustique.anses.fr" target="_blank">signalement-moustique.anses.fr</a>, <a href="https://frelonasiatique.mnhn.fr" target="_blank">frelonasiatique.mnhn.fr</a>). La saison de surveillance est officiellement activée pour l'été 2026.</p>
<div class="news-meta">
<span class="news-date">Printemps-été 2026</span>
<a class="news-link" href="https://www.santepubliquefrance.fr/en/press/2026-stepped-efforts-combat-tiger-mosquito-activation-surveillance-and-control-system" target="_blank" rel="noopener">→ santepubliquefrance.fr</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Vespikill — Prototypes 2026 frelon asiatique</div>
<p class="news-text">Vespikill, spécialiste du piégeage du frelon asiatique, annonce la présentation exclusive de prototypes de pièges 2026. Le frelon asiatique est présent dans plus de 70 départements français, avec des enjeux apicoles et de sécurité publique croissants.</p>
<div class="news-meta">
<span class="news-date">Printemps 2026</span>
<a class="news-link" href="https://www.application-iot.fr/industrie-4-0/les-pieges-connectes-revolutionnent-la-gestion-des-nuisibles-dans-lindustrie-alimentaire/" target="_blank" rel="noopener">→ application-iot.fr</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Lyon Capitale — Espèces invasives</div>
<p class="news-text">Le débat sur les moyens de lutte contre les espèces invasives est relancé dans les collectivités. La tension entre approches chimiques et alternatives biologiques/mécaniques alimente les discussions sur l'évolution des pratiques 3D.</p>
<div class="news-meta">
<span class="news-date">Printemps 2026</span>
<a class="news-link" href="https://www.lyoncapitale.fr/actualite/lyon-la-guerre-contre-les-especes-invasives-aura-t-elle-lieu" target="_blank" rel="noopener">→ lyoncapitale.fr</a>
</div>
</div>
</li>
</ul>
<p class="note-warning">⚠️ Aucune donnée spécifique et vérifiée sur les rongeurs résistants ou les punaises de lit n'a été identifiée cette semaine via sources officielles.</p>
</section>
<!-- ═══ 4. DÉSINFECTION ═══ -->
<section id="desinfection">
<div class="section-header">
<span class="section-emoji">🧴</span>
<h2>Désinfection</h2>
<span class="section-sub">Normes AFNOR · Produits homologués · Alternatives</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">AFNOR — NF EN 14476 (virucide)</div>
<p class="news-text">La norme NF EN 14476 évalue l'efficacité virucide des désinfectants chimiques et antiseptiques. Norme incontournable pour les produits de type TP2 et TP1 utilisés en milieux sensibles (santé, agroalimentaire). Complète la famille NF EN 1276 (bactéricides) et NF EN 1650 (fongicides).</p>
<div class="news-meta">
<span class="news-date">En vigueur</span>
<a class="news-link" href="https://www.boutique.afnor.org/en-gb/standard/nf-en-14476/chemical-disinfectants-and-antiseptics-quantitative-suspension-test-for-the/fa166895/1398" target="_blank" rel="noopener">→ boutique.afnor.org</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">AFNOR — Consultation NF U43-500</div>
<p class="news-text">La révision de la norme NF U43-500 sur les bonnes pratiques d'application des produits phytosanitaires et biocides est toujours en phase de consultation. Son adoption pourrait modifier les exigences de formation pour les applicateurs professionnels.</p>
<div class="news-meta">
<span class="news-date">En cours de révision</span>
<a class="news-link" href="https://norminfo.afnor.org/consultation/nf-u43-500/bonnes-pratiques-dapplication-des-produits-phytosanitaires-et-biocides-maitrise-des-applications-de-produits-phytosanitaires/108423" target="_blank" rel="noopener">→ norminfo.afnor.org</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">ProdHYBase</div>
<p class="news-text">ProdHYBase reste la base de données de référence pour consulter les normes applicables aux désinfectants en France (bactéricides, fongicides, virucides, sporicides). Outil à recommander systématiquement aux stagiaires Certibiocide Désinfectants.</p>
<div class="news-meta">
<span class="news-date">Référence permanente</span>
<a class="news-link" href="https://www.prodhybase.fr/norme_generalite.html" target="_blank" rel="noopener">→ prodhybase.fr</a>
</div>
</div>
</li>
</ul>
</section>
<!-- ═══ 5. OPPORTUNITÉS ═══ -->
<section id="opportunites">
<div class="section-header">
<span class="section-emoji">💡</span>
<h2>Opportunités</h2>
<span class="section-sub">BOAMP · CPF · Secteurs demandeurs</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">BOAMP — Le Cannet (06) · réf. 3/BOAMP/2612774</div>
<p class="news-text">Marché de dératisation, désinsectisation, démoustication et désinfection du domaine public et privé de la ville du Cannet, en 2 lots. Nouvelle consultation 2026 non identifiée les semaines précédentes.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.francemarches.com/appel-offre/3boamp2612774-2026-2025-deratisation-desinsectisation" target="_blank" rel="noopener">→ francemarches.com</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">BOAMP — Prestations 3D · réf. 3/BOAMP/2623657</div>
<p class="news-text">Nouveau marché de prestations de dératisation et désinsectisation référencé sur francemarches.com. S'ajoute aux marchés déjà identifiés les semaines précédentes (Oise, Carrières-sous-Poissy, EPMO-VGE).</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.francemarches.com/appel-offre/3boamp2623657-2026-prestations-deratisation-desinsectisation" target="_blank" rel="noopener">→ francemarches.com</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Francemarches.com — Baromètre marchés publics 3D</div>
<p class="news-text"><strong>94 appels d'offres</strong> publics en cours sur le mot-clé « dératisation » (81 pour « dératisation-désinsectisation »). Signal fort d'un marché public 3D très actif au printemps 2026.</p>
<div class="news-meta">
<span class="news-date">Mai 2026</span>
<a class="news-link" href="https://www.francemarches.com/appels-offre/deratisation" target="_blank" rel="noopener">→ francemarches.com</a>
</div>
</div>
</li>
</ul>
<p class="note-warning">⚠️ Aucun appel d'offres spécifique à la formation Certibiocide ou 3D n'a été identifié cette semaine sur BOAMP.</p>
</section>
<!-- ═══ 6. INNOVATION ═══ -->
<section id="innovation">
<div class="section-header">
<span class="section-emoji">🔬</span>
<h2>Innovation</h2>
<span class="section-sub">Bioinsecticides · IoT · IA · Brevets</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Biocinov / Hamelin — Piège connecté rongeur</div>
<p class="news-text">Le piège connecté rongeur de Biocinov est présenté comme un outil de référence pour la lutte contre les rongeurs en milieu industriel et agroalimentaire : détection en temps réel, alertes automatisées, réduction des visites de contrôle inutiles et diminution de l'usage de rodenticides.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.hamelin.info/actus/partenaire/piege-connecte-rongeur-biocinov/" target="_blank" rel="noopener">→ hamelin.info</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">APA — Innovations en désinsectisation</div>
<p class="news-text">Passage en revue des innovations technologiques récentes en désinsectisation : pièges UV connectés, systèmes de détection thermique, diffuseurs automatiques et traitements ciblés par IA. Tendance de fond vers la réduction des biocides chimiques.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.a-p-a.fr/les-innovations-technologiques-en-desinsectisation/" target="_blank" rel="noopener">→ a-p-a.fr</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">PubMed / NCBI — Pièges non-insecticides</div>
<p class="news-text">Une étude publiée en 2026 démontre que les pièges non-insecticides en intérieur peuvent compléter efficacement les moustiquaires imprégnées pour cibler les vecteurs de maladies résistants aux insecticides. Résultat transposable à la lutte contre les moustiques tigres résistants.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC12063245/" target="_blank" rel="noopener">→ ncbi.nlm.nih.gov</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Anticimex — Centre d'innovation mondial</div>
<p class="news-text">Plus de 120 brevets déposés dans le monde par Anticimex, avec un centre d'innovation dédié aux solutions connectées et autonomes. Référence sectorielle à intégrer dans les formations pour illustrer l'évolution des pratiques métier 3D.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.anticimex.ch/fr/sur-anticimex/centre-innovation-anticimex/" target="_blank" rel="noopener">→ anticimex.ch</a>
</div>
</div>
</li>
</ul>
</section>
<!-- ═══ 7. EUROPE ═══ -->
<section id="europe">
<div class="section-header">
<span class="section-emoji">🇪🇺</span>
<h2>Veille européenne</h2>
<span class="section-sub">BPR · EFSA · Résistances</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">Commission européenne — Évaluation BPR en cours</div>
<p class="news-text">L'évaluation formelle du BPR (n°528/2012), lancée au Q4 2025, se poursuit. Elle porte sur la performance globale du règlement et pourrait déboucher sur une révision législative majeure impactant l'ensemble des types de produits biocides. Résultats attendus courant 2026-2027.</p>
<div class="news-meta">
<span class="news-date">Q4 2025 en cours</span>
<a class="news-link" href="https://health.ec.europa.eu/biocides/regulation/evaluation-biocidal-products-regulation_en" target="_blank" rel="noopener">→ health.ec.europa.eu</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">ECHA / EFSA — Guidance eau potable, obligatoire depuis avril 2026</div>
<p class="news-text">Depuis le 1er avril 2026, la guidance conjointe ECHA/EFSA sur les résidus de substances actives dans l'eau potable est obligatoire pour toutes les nouvelles soumissions BPR. Impact direct sur les types TP11 et TP12 (systèmes de refroidissement, fluides de traitement).</p>
<div class="news-meta">
<span class="news-date">Depuis avril 2026</span>
<a class="news-link" href="https://www.cehtra.com/fr/post/interaction-entre-la-directive-eau-potable-ue-2020-2184-et-le-r%C3%A8glement-biocides-bpr" target="_blank" rel="noopener">→ cehtra.com</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">EUON / ECHA — BPR et nanomatériaux</div>
<p class="news-text">L'Observatoire européen des nanomatériaux publie des analyses sur l'encadrement des nanomatériaux dans le cadre du BPR. Sujet émergent à surveiller pour les biocides de nouvelle génération susceptibles de contenir des nano-agents actifs.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://euon.echa.europa.eu/fr/the-biocidal-products-regulation-bpr-and-nanomaterials" target="_blank" rel="noopener">→ euon.echa.europa.eu</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">ECHA — Échéance perturbateurs endocriniens</div>
<p class="news-text">Rappel de l'échéance du <strong>31 décembre 2026</strong> pour la soumission des données sur les propriétés de perturbation endocrinienne de certaines substances actives biocides. Les dossiers incomplets risquent le non-renouvellement d'approbation avec effet sur les produits formulés.</p>
<div class="news-meta">
<span class="news-date">Avant le 31 déc. 2026</span>
<a class="news-link" href="https://echa.europa.eu/fr/biocides" target="_blank" rel="noopener">→ echa.europa.eu</a>
</div>
</div>
</li>
</ul>
</section>
<!-- ═══ 8. RH ═══ -->
<section id="rh">
<div class="section-header">
<span class="section-emoji">👥</span>
<h2>RH &amp; Concurrence</h2>
<span class="section-sub">Emploi 3D · Certifications RNCP</span>
</div>
<ul class="news-list">
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">SAD'S INTERIM — CDI Technicien 3D</div>
<p class="news-text">Offre de CDI pour un technicien dératisation-désinsectisation-désinfection, avec Certibiocide requis. Confirmation que le Certibiocide est désormais un prérequis systématique dans les fiches de poste du secteur 3D, y compris en intérim.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.sads-interim.eu/emploi/cdi-technicien-deratisa-azwwd2kpnr/" target="_blank" rel="noopener">→ sads-interim.eu</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">ISTAV — Journées techniques 3D</div>
<p class="news-text">ISTAV propose des journées techniques spécialisées 3D tout au long de 2026, destinées aux professionnels souhaitant se mettre à jour sur les techniques et réglementations. Format complémentaire aux formations Certibiocide initiales.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://istav.fr/journees-techniques-3d/" target="_blank" rel="noopener">→ istav.fr</a>
</div>
</div>
</li>
<li class="news-item">
<div class="news-dot"></div>
<div class="news-content">
<div class="news-source">CertifAgri — Formation technicien 3D</div>
<p class="news-text">CertifAgri propose une formation de technicien en désinfection, désinsectisation et dératisation articulée autour des exigences RNCP et du Certibiocide. Concurrent direct à surveiller pour le positionnement pédagogique sur ce segment.</p>
<div class="news-meta">
<span class="news-date">2026</span>
<a class="news-link" href="https://www.certif-agri.com/formations/metiers/technicien-en-desinfection-desinsectisation-et-deratisation-3d/" target="_blank" rel="noopener">→ certif-agri.com</a>
</div>
</div>
</li>
</ul>
</section>
</main>
<!-- ═══ FOOTER ═══ -->
<footer>
<p>Rapport généré le <strong>25 mai 2026</strong> — Sources : ANSES, ECHA, Légifrance, France Compétences, Santé Publique France, AFNOR, BOAMP</p>
<p style="margin-top:0.4rem;">Ce rapport est à usage informatif. Vérifier les informations auprès des sources officielles avant toute décision.</p>
</footer>
</body>
</html>

View File

@@ -419,7 +419,7 @@
<!-- HEADER -->
<header>
<div class="logo">NextGN Formation</div>
<div class="logo">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="#formations">Exercices interactifs</a>
<a href="#documentation">Documentation</a>
@@ -799,7 +799,7 @@
<!-- FOOTER -->
<footer>
<p>&copy; 2024 NextGN Formation - Rapport Veille Semaine 20</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p>Tous droits réservés - Formateur indépendant spécialisé en Certibiocide</p>
</footer>

View File

@@ -419,7 +419,7 @@
<!-- HEADER -->
<header>
<div class="logo">NextGN Formation</div>
<div class="logo">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="#formations">Exercices interactifs</a>
<a href="#documentation">Documentation</a>
@@ -799,7 +799,7 @@
<!-- FOOTER -->
<footer>
<p>&copy; 2024 NextGN Formation - Rapport Veille Semaine 21</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p>Tous droits réservés - Formateur indépendant spécialisé en Certibiocide</p>
</footer>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Veille Certibiocide — Semaine 23 | NextGN Formation</title>
<title>Veille Certibiocide — Semaine 23 | Gauthier Chombart & Nathan Chauwin</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
@@ -355,7 +355,7 @@
<!-- NAV -->
<nav class="nav-header">
<a href="index.html" class="header-logo"><span>NextGN</span> Formation</a>
<a href="index.html" class="header-logo">Gauthier Chombart & Nathan Chauwin</a>
<nav class="header-nav">
<a href="index.html#formations">Exercices interactifs</a>
<a href="index.html#about">À propos</a>
@@ -800,7 +800,7 @@
</main>
<footer>
<p>&copy; 2026 NextGN Formation — Veille Certibiocide Semaine 23</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p style="margin-top:10px; opacity:0.6;">Tous droits réservés — Formateurs indépendants</p>
</footer>

View File

@@ -356,7 +356,7 @@
<!-- Navigation -->
<nav class="nav-header">
<a href="index.html" class="header-logo"><span>NextGN</span> Formation</a>
<a href="index.html" class="header-logo">Gauthier Chombart & Nathan Chauwin</a>
<nav class="header-nav" id="mainNav">
<a href="index.html#formations">Exercices interactifs</a>
<a href="index.html#about">À propos</a>
@@ -790,7 +790,7 @@
</div><!-- /container -->
<footer>
<p>&copy; 2026 NextGN Formation — Veille Certibiocide Semaine 24</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p style="margin-top:10px; opacity:0.6;">Tous droits réservés — Formateurs indépendants</p>
</footer>

View File

@@ -375,7 +375,7 @@
<!-- NAV HEADER -->
<nav class="nav-header">
<a href="index.html" class="header-logo"><span>NextGN</span> Formation</a>
<a href="index.html" class="header-logo">Gauthier Chombart & Nathan Chauwin</a>
<button class="hamburger" id="hamburger" aria-label="Menu">
<span></span><span></span><span></span>
</button>
@@ -704,7 +704,7 @@
<!-- FOOTER -->
<footer>
<p>&copy; 2026 NextGN Formation - Veille Certibiocide Semaine 25</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p>Tous droits réservés - Formateurs indépendants</p>
</footer>

View File

@@ -0,0 +1,825 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Veille Certibiocide — Semaine 26 | Gauthier Chombart & Nathan Chauwin</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
--teal: #0F6E56;
--teal-mid: #1D9E75;
--teal-light: #E1F5EE;
--teal-dark: #085041;
--amber: #BA7517;
--amber-light: #FAEEDA;
--amber-dark: #633806;
--coral: #993C1D;
--coral-mid: #D85A30;
--coral-light: #FAECE7;
--purple: #534AB7;
--purple-light: #EEEDFE;
--purple-dark: #3C3489;
--blue: #185FA5;
--blue-light: #E6F1FB;
--bg: #F7F6F2;
--white: #FFFFFF;
--text: #1a1a18;
--text-muted: #6b6a65;
--border: rgba(0,0,0,0.1);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
padding-top: 73px;
background: var(--bg);
font-family: 'DM Sans', sans-serif;
color: var(--text);
line-height: 1.6;
}
.nav-header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 70px;
background: rgba(255,255,255,0.95);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border);
z-index: 1000;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 40px;
}
.header-logo {
font-family: 'Syne', sans-serif;
font-weight: 800;
font-size: 20px;
text-decoration: none;
background: linear-gradient(135deg, var(--teal), var(--coral-mid));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header-nav {
display: flex;
gap: 32px;
}
.header-nav a {
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
text-decoration: none;
position: relative;
padding-bottom: 2px;
transition: color 0.2s;
}
.header-nav a::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: var(--teal-mid);
transition: width 0.25s ease;
}
.header-nav a:hover { color: var(--teal); }
.header-nav a:hover::after { width: 100%; }
.progress {
height: 3px;
background: var(--border);
position: fixed;
top: 70px;
left: 0;
right: 0;
z-index: 999;
}
.progress-bar {
height: 100%;
background: var(--teal-mid);
width: 0%;
transition: width 0.1s ease;
}
.hero {
background: var(--teal-light);
border-bottom: 2px solid var(--teal-mid);
padding: 60px 40px 50px;
text-align: center;
}
.hero-badge {
display: inline-block;
background: var(--teal-mid);
color: var(--white);
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
padding: 6px 16px;
border-radius: 20px;
margin-bottom: 20px;
}
.hero h1 {
font-family: 'Syne', sans-serif;
font-weight: 800;
font-size: 2.6rem;
color: var(--teal-dark);
margin-bottom: 12px;
line-height: 1.15;
}
.hero-meta {
font-size: 15px;
color: var(--text-muted);
font-weight: 400;
}
.hero-meta strong {
color: var(--teal);
font-weight: 500;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 0 24px 60px;
}
.sommaire {
background: var(--white);
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.07);
padding: 24px 28px;
margin: 32px 0;
position: sticky;
top: 80px;
z-index: 100;
}
.sommaire h3 {
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--text-muted);
margin-bottom: 14px;
}
.sommaire-links {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.sommaire-links a {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12px;
font-weight: 500;
color: var(--teal);
text-decoration: none;
background: var(--teal-light);
padding: 5px 12px;
border-radius: 20px;
transition: background 0.2s, color 0.2s, transform 0.2s;
}
.sommaire-links a:hover {
background: var(--teal-mid);
color: var(--white);
transform: translateY(-1px);
}
.attention-box {
background: var(--amber-light);
border-left: 4px solid var(--amber);
border-radius: 10px;
padding: 24px 28px;
margin-bottom: 36px;
}
.attention-box h2 {
font-family: 'Syne', sans-serif;
font-weight: 700;
font-size: 1.1rem;
color: var(--amber-dark);
margin-bottom: 16px;
}
.attention-item {
display: flex;
gap: 12px;
margin-bottom: 12px;
align-items: flex-start;
}
.attention-num {
flex-shrink: 0;
width: 26px;
height: 26px;
background: var(--amber);
color: var(--white);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
margin-top: 1px;
}
.attention-item p {
font-size: 14px;
color: var(--amber-dark);
line-height: 1.55;
}
.section {
background: var(--white);
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.06);
margin-bottom: 28px;
overflow: hidden;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.section-header {
background: var(--teal-light);
padding: 18px 24px;
display: flex;
align-items: center;
gap: 12px;
border-bottom: 1px solid rgba(29,158,117,0.15);
}
.section-header h2 {
font-family: 'Syne', sans-serif;
font-weight: 700;
font-size: 1.05rem;
color: var(--teal-dark);
}
.section-header .emoji { font-size: 1.3rem; }
.section-body { padding: 20px 24px; }
.actu {
border-bottom: 1px solid var(--border);
padding: 16px 0;
}
.actu:last-child { border-bottom: none; padding-bottom: 0; }
.actu:first-child { padding-top: 0; }
.actu-source {
display: inline-block;
background: var(--teal-mid);
color: var(--white);
font-size: 10px;
font-weight: 700;
font-family: 'Syne', sans-serif;
text-transform: uppercase;
letter-spacing: 0.08em;
padding: 3px 10px;
border-radius: 4px;
margin-bottom: 6px;
}
.actu p {
font-size: 14px;
line-height: 1.55;
color: var(--text);
margin-bottom: 6px;
}
.actu-meta {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.actu-date {
font-size: 12px;
color: var(--text-muted);
font-style: italic;
}
.actu-link {
font-size: 12px;
color: var(--teal-mid);
text-decoration: none;
font-weight: 500;
transition: transform 0.2s, color 0.2s;
display: inline-block;
}
.actu-link:hover {
color: var(--teal-dark);
transform: translateY(-1px);
}
footer {
background: var(--text);
color: var(--white);
padding: 40px;
font-size: 13px;
text-align: center;
}
footer p:last-child {
margin-top: 10px;
opacity: 0.6;
}
@media (max-width: 768px) {
.nav-header {
padding: 12px 20px;
flex-wrap: wrap;
height: auto;
gap: 10px;
}
.header-nav { gap: 16px; flex-wrap: wrap; }
body { padding-top: 100px; }
.progress { top: 100px; }
.hero { padding: 40px 20px 36px; }
.hero h1 { font-size: 1.8rem; }
.container { padding: 0 16px 40px; }
.sommaire { position: static; }
.section-header h2 { font-size: 0.95rem; }
}
</style>
</head>
<body>
<nav class="nav-header">
<a href="index.html" class="header-logo">Gauthier Chombart & Nathan Chauwin</a>
<nav class="header-nav">
<a href="index.html#formations">Exercices interactifs</a>
<a href="index.html#about">À propos</a>
<a href="index.html#contact">Contact</a>
</nav>
</nav>
<div class="progress"><div class="progress-bar" id="progressBar"></div></div>
<div class="hero">
<div class="hero-badge">📋 Rapport de veille hebdomadaire</div>
<h1>Veille Certibiocide<br>Semaine 26 — 2026</h1>
<p class="hero-meta">
<strong>Semaine du 23 au 29 juin 2026</strong> &nbsp;·&nbsp;
Généré le 29 juin 2026 &nbsp;·&nbsp; Gauthier Chombart & Nathan Chauwin
</p>
</div>
<div class="container">
<nav class="sommaire">
<h3>📑 Sommaire</h3>
<div class="sommaire-links">
<a href="#reglementaire">⚖️ Réglementaire</a>
<a href="#marche-formation">🎓 Marché formation</a>
<a href="#nuisibles">🐀 Nuisibles &amp; ESOD</a>
<a href="#desinfection">🧴 Désinfection</a>
<a href="#opportunites">💡 Opportunités</a>
<a href="#innovation">🔬 Innovation</a>
<a href="#europe">🇪🇺 Veille européenne</a>
<a href="#rh">👥 RH &amp; Concurrence</a>
<a href="#attention">📌 Points d'attention</a>
</div>
</nav>
<!-- POINTS D'ATTENTION -->
<div class="attention-box" id="attention">
<h2>📌 Points d'attention — Semaine 26</h2>
<div class="attention-item">
<div class="attention-num">1</div>
<p><strong>Certibiocide Désinfectants pleinement en vigueur depuis janvier 2026 :</strong> les décideurs, acheteurs et distributeurs de biocides désinfectants professionnels doivent être certifiés. Vérifiez que vos stagiaires maîtrisent les 3 catégories (Désinfectants TP2/3/4, Nuisibles TP14/18/20, Autres produits TP8/15/21) et l'obligation de déclaration annuelle avant le 31 mars. Qualiopi obligatoire pour le FAFCEA depuis le 1er juillet 2026.</p>
</div>
<div class="attention-item">
<div class="attention-num">2</div>
<p><strong>CPF : reste à charge à 150 € depuis le 2 avril 2026.</strong> Ce changement peut freiner les inscriptions CPF. Les demandeurs d'emploi restent exonérés. Anticipez cet argument dans vos entretiens de vente et orientez les salariés vers un financement OPCO (prise en charge jusqu'à 100 % pour les TPE/PME &lt; 50 salariés).</p>
</div>
<div class="attention-item">
<div class="attention-num">3</div>
<p><strong>Appel d'offres BOAMP Fos-sur-Mer — clôture le 2 juillet 2026 :</strong> à transmettre à vos partenaires prestataires. Le secteur 3D affiche une demande structurelle en recrutement (>25 offres actives sur Indeed au 11 juin), ce qui renforce l'argumentaire de vos formations Certibiocide Nuisibles.</p>
</div>
</div>
<!-- 1. RÉGLEMENTAIRE -->
<section class="section" id="reglementaire">
<div class="section-header">
<span class="emoji">⚖️</span>
<h2>Réglementaire — AMM, BPR, obligations Certibiocide</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">ANSES</span>
<p>Plusieurs <strong>décisions de modifications administratives d'AMM biocides</strong> publiées le 17 juin 2026 : <em>ANTI-MITES ALIMENTAIRES-GEA</em> (signé 08/06), <em>SANYTOL LACTIC SA-APP</em> (signé 04/06), <em>BELOX</em> (signé 05/06). Ces décisions portent sur des ajustements de compositions ou d'usages autorisés, sans retrait de marché.</p>
<div class="actu-meta">
<span class="actu-date">17 juin 2026</span>
<a href="https://www.anses.fr/fr/decisions_biocide" class="actu-link" target="_blank" rel="noopener">→ Registre AMM biocides ANSES</a>
</div>
</div>
<div class="actu">
<span class="actu-source">ANSES</span>
<p>Modifications administratives publiées les 10 et 17 juin pour <strong>TWIST-TIE MD2 INPEST, PHEROMONE DROP FOR CLOTHES MOTHS, AUTAN KIDS SPRAY</strong> et <strong>BRODITEC P-29F</strong>. Principalement des ajustements des conditions d'emploi et des mises en garde. Aucun retrait complet d'AMM identifié cette semaine.</p>
<div class="actu-meta">
<span class="actu-date">Juin 2026</span>
<a href="https://www.anses.fr/fr/decisions_biocide" class="actu-link" target="_blank" rel="noopener">→ Registre AMM biocides ANSES</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Réglementation FR</span>
<p>La <strong>triple catégorisation du Certibiocide</strong> est opérationnelle depuis le 1er janvier 2026. Les distributeurs ont l'obligation d'enregistrer le numéro de certificat de leurs acheteurs professionnels. La <strong>déclaration annuelle</strong> à l'application gouvernementale est à effectuer avant le 31 mars de chaque année.</p>
<div class="actu-meta">
<span class="actu-date">En vigueur depuis le 01/01/2026</span>
<a href="https://climalife.com/fr/certibiocide-reglementation-2026/" class="actu-link" target="_blank" rel="noopener">→ Climalife synthèse réglementaire</a>
</div>
</div>
<div class="actu">
<span class="actu-source">ECHA / Commission UE</span>
<p>L'<strong>évaluation complète du BPR</strong> (UE) n° 528/2012 se poursuit après la consultation publique du 11 décembre 2025 au 5 mars 2026. Les conclusions alimenteront la révision du règlement, ciblant les retards d'approbation des substances actives et les inefficacités du marché sur 12 ans de mise en œuvre.</p>
<div class="actu-meta">
<span class="actu-date">Suivi 2026</span>
<a href="https://en.reach24h.com/news/industry-news/disinfectant-biocide/eu-bpr-evaluation-public-consultation" class="actu-link" target="_blank" rel="noopener">→ REACH24H évaluation BPR</a>
</div>
</div>
</div>
</section>
<!-- 2. MARCHÉ FORMATION -->
<section class="section" id="marche-formation">
<div class="section-header">
<span class="emoji">🎓</span>
<h2>Marché formation — Qualiopi, CPF, OPCO</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">Service-Public.fr</span>
<p>Depuis le <strong>2 avril 2026</strong>, le reste à charge CPF est fixé à <strong>150 € par dossier de formation</strong>, quel que soit le montant. Les demandeurs d'emploi inscrits à France Travail restent exonérés. Ce changement impacte directement les inscriptions CPF aux formations Certibiocide pour les salariés.</p>
<div class="actu-meta">
<span class="actu-date">Depuis le 2 avril 2026</span>
<a href="https://www.service-public.gouv.fr/particuliers/actualites/A18831" class="actu-link" target="_blank" rel="noopener">→ Service-public.fr CPF 2026</a>
</div>
</div>
<div class="actu">
<span class="actu-source">OPCO / PDC</span>
<p>Le budget national du <strong>PDC 2026 recule à 521 M€</strong> (vs 550 M€ en 2025). Les TPE/PME &lt; 50 salariés restent prioritaires avec une prise en charge jusqu'à <strong>100 % des coûts pédagogiques</strong> via OPCO. Les formations Certibiocide pour les petites structures 3D restent donc finançables à taux plein.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://formaltic.fr/financement-opco-formations-2026/" class="actu-link" target="_blank" rel="noopener">→ Formaltic financement OPCO 2026</a>
</div>
</div>
<div class="actu">
<span class="actu-source">FAFCEA / Qualiopi</span>
<p>Depuis le <strong>1er juillet 2026</strong>, Qualiopi est strictement obligatoire pour les financements FAFCEA (artisans). Cette date butoir est atteinte : les organismes de formation Certibiocide non certifiés Qualiopi sont désormais exclus des financements FAFCEA. À vérifier impérativement si vous intervenez auprès d'artisans.</p>
<div class="actu-meta">
<span class="actu-date">En vigueur au 01/07/2026</span>
<a href="https://csfc-federation.org/blog/qualiopi-devient-obligatoire-pour-les-financements-fafcea-des-2026/" class="actu-link" target="_blank" rel="noopener">→ CSFC Fédération</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Branches pro / Urssaf</span>
<p>Depuis <strong>janvier 2026</strong>, les branches professionnelles peuvent confier la collecte de leurs contributions conventionnelles aux Urssaf. Les formations en <strong>période de reconversion</strong> sont désormais cofinançables via OPCO ou CPF, ouvrant de nouvelles opportunités pour les reconversions vers les métiers 3D/biocides.</p>
<div class="actu-meta">
<span class="actu-date">Depuis janvier 2026</span>
<a href="https://up-academie.com/cpf-et-dispositifs-de-financement/" class="actu-link" target="_blank" rel="noopener">→ UP Académie dispositifs 2026</a>
</div>
</div>
</div>
</section>
<!-- 3. NUISIBLES & ESOD -->
<section class="section" id="nuisibles">
<div class="section-header">
<span class="emoji">🐀</span>
<h2>Nuisibles &amp; ESOD — Moustique tigre, frelon, rongeurs, punaises</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">Santé publique — Castres</span>
<p>Nuit du <strong>10 au 11 juin 2026</strong> : opération sanitaire d'urgence à <strong>Castres (Tarn)</strong> suite à un cas importé de <strong>chikungunya</strong>. Le moustique tigre (<em>Aedes albopictus</em>), présent localement, peut transmettre le virus à partir d'un patient virémique, justifiant une démoustication nocturne en centre-ville.</p>
<div class="actu-meta">
<span class="actu-date">11 juin 2026</span>
<a href="https://solution-nuisible.fr/actualites/chikungunya-a-castres-pourquoi-le-moustique-tigre-a-declenche-une-intervention-nocturne/" class="actu-link" target="_blank" rel="noopener">→ Solution-nuisible.fr</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Municipalité Royan</span>
<p>Royan ouvre un dispositif d'<strong>aide de 50 € par nid de frelon asiatique</strong> détruit (1er juin 30 novembre 2026), dans le cadre du plan national de lutte lancé en mars 2026. Ce modèle de subvention communale est à surveiller : d'autres collectivités pourraient l'adopter, générant une demande accrue pour les prestataires agréés.</p>
<div class="actu-meta">
<span class="actu-date">Juin 2026</span>
<a href="https://solution-nuisible.fr/actualites/a-royan-une-aide-de-50-euros-face-a-la-recrudescence-du-frelon-asiatique/" class="actu-link" target="_blank" rel="noopener">→ Solution-nuisible.fr</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Étude 2026</span>
<p><strong>62 % des Français</strong> déclarent avoir été touchés par des nuisibles à domicile. Entre 2021 et 2025 : guêpes/frelons ×2,8 — rongeurs ×2,5 — punaises de lit ×2,1. Ces données confirment la tension structurelle du marché 3D et la légitimité des formations Certibiocide face à une demande en forte hausse.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://monimmeuble.com/actualite/nuisibles-a-domicile-62-des-francais-touches-un-fleau-qui-explose" class="actu-link" target="_blank" rel="noopener">→ Monimmeuble.com</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Lyon Capitale</span>
<p>La métropole lyonnaise interroge sa capacité à coordonner une réponse cohérente face à la prolifération printanière 2026 des espèces invasives (frelon asiatique, moustique tigre, processionnaire). La demande en prestataires agréés et techniciens formés Certibiocide s'intensifie dans les grandes métropoles.</p>
<div class="actu-meta">
<span class="actu-date">Printemps 2026</span>
<a href="https://www.lyoncapitale.fr/actualite/lyon-la-guerre-contre-les-especes-invasives-aura-t-elle-lieu" class="actu-link" target="_blank" rel="noopener">→ Lyon Capitale</a>
</div>
</div>
</div>
</section>
<!-- 4. DÉSINFECTION -->
<section class="section" id="desinfection">
<div class="section-header">
<span class="emoji">🧴</span>
<h2>Désinfection — Normes AFNOR, produits homologués, alternatives</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">Réglementation 2026</span>
<p>Depuis le <strong>1er janvier 2026</strong>, le <strong>Certibiocide Désinfectants</strong> (TP2/3/4) est obligatoire pour les décideurs, acheteurs et distributeurs de désinfectants professionnels. Formation de 7h, QCM de 30 questions (seuil : 20/30), certificat nominatif valable 5 ans. L'obligation concerne aussi les entreprises de propreté utilisant des désinfectants biocides.</p>
<div class="actu-meta">
<span class="actu-date">En vigueur depuis le 01/01/2026</span>
<a href="https://www.monde-proprete.com/certibiocide-desinfectant-obligation" class="actu-link" target="_blank" rel="noopener">→ Le Monde de la Propreté</a>
</div>
</div>
<div class="actu">
<span class="actu-source">AFNOR</span>
<p>La norme <strong>NF U43-500</strong> (bonnes pratiques d'application des produits biocides) est en cours de révision 2026. L'AFNOR confirme le maintien des normes de référence en désinfection : <strong>EN 14476</strong> (virucide) et <strong>EN 14885</strong> (référentiel européen désinfectants). Ces normes structurent les contenus des formations Certibiocide Désinfectants.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://norminfo.afnor.org/consultation/nf-u43-500/bonnes-pratiques-dapplication-des-produits-phytosanitaires-et-biocides-maitrise-des-applications-de-produits-phytosanitaires/108423" class="actu-link" target="_blank" rel="noopener">→ AFNOR consultation NF U43-500</a>
</div>
</div>
<div class="actu">
<span class="actu-source">BPR / ECHA</span>
<p>Nouvelles décisions BPR d'<strong>avril 2026</strong> sur des substances actives désinfectantes clés : <strong>cyperméthrine, DBNPA, libérateurs de formaldéhyde et éthanol</strong>. Ces mises à jour de conformité affectent les produits biocides TP2/3/4 disponibles sur le marché UE. Les supports de formation Certibiocide Désinfectants doivent être actualisés.</p>
<div class="actu-meta">
<span class="actu-date">Avril 2026</span>
<a href="https://en.reach24h.com/news/industry-news/disinfectant-biocide/eu-brp-key-biocidal-active-substances-update" class="actu-link" target="_blank" rel="noopener">→ REACH24H substances actives</a>
</div>
</div>
<div class="actu">
<span class="actu-source">ProdHyBase</span>
<p><strong>ProdHyBase</strong> reste la référence française pour identifier les normes AFNOR validées par chaque désinfectant (dossiers fournis par les distributeurs). Outil pédagogique central pour les formations Certibiocide Désinfectants : permet aux stagiaires de vérifier l'homologation d'un produit TP2/3/4 et ses normes de validation.</p>
<div class="actu-meta">
<span class="actu-date">Permanent</span>
<a href="https://www.prodhybase.fr/norme_generalite.html" class="actu-link" target="_blank" rel="noopener">→ ProdHyBase</a>
</div>
</div>
</div>
</section>
<!-- 5. OPPORTUNITÉS -->
<section class="section" id="opportunites">
<div class="section-header">
<span class="emoji">💡</span>
<h2>Opportunités — Appels d'offres BOAMP, CPF, secteurs demandeurs</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">BOAMP</span>
<p><strong>⚡ Urgent — Clôture le 02/07/2026 :</strong> Appel d'offres de la ville de <strong>Fos-sur-Mer</strong> pour des prestations de lutte contre les nuisibles en 2 lots (Lot 1 : 3D — dératisation, désinsectisation, désinfection ; Lot 2 : dératisation par prédation). À transmettre immédiatement à vos partenaires prestataires.</p>
<div class="actu-meta">
<span class="actu-date">Clôture 02/07/2026</span>
<a href="https://www.francemarches.com/appel-offre/3boamp2651311-2026-prestations-lutte-contre" class="actu-link" target="_blank" rel="noopener">→ FranceMarches Fos-sur-Mer</a>
</div>
</div>
<div class="actu">
<span class="actu-source">BOAMP</span>
<p>Accord-cadre mono-attributaire pour des <strong>prestations de prévention et lutte contre les nuisibles et l'insalubrité</strong> (réf. 3/boamp/264816-2026) — montant maximum annuel : <strong>50 000 € HT</strong>. Ce type de marché à bons de commande est particulièrement accessible pour les petites structures indépendantes du secteur 3D.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.francemarches.com/appel-offre/3boamp264816-2026-prestations-prevention-lutte" class="actu-link" target="_blank" rel="noopener">→ FranceMarches accord-cadre nuisibles</a>
</div>
</div>
<div class="actu">
<span class="actu-source">BOAMP — Oise</span>
<p>Le <strong>Département de l'Oise</strong> a lancé un marché multi-sites pour des missions 3D sur ses bâtiments départementaux, collèges publics et réseau routier (réf. 3/boamp/2616972). Volume significatif pour les prestataires régionaux — nécessite des opérateurs certifiés Certibiocide Nuisibles.</p>
<div class="actu-meta">
<span class="actu-date">Envoi : 13/02/2026</span>
<a href="https://www.francemarches.com/appel-offre/3boamp2616972-2026-missions-deratisation-desinsectisation" class="actu-link" target="_blank" rel="noopener">→ FranceMarches Département Oise</a>
</div>
</div>
<div class="actu">
<span class="actu-source">BOAMP — Musées Paris</span>
<p>Les <strong>Musées d'Orsay et de l'Orangerie (Paris 7e)</strong> ont lancé un marché de traitement 3D pour leurs locaux (réf. 3/boamp/266207). La multiplication des marchés institutionnels (patrimoine, collectivités, établissements publics) souligne la demande en professionnels certifiés capables d'intervenir dans des environnements sensibles.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.francemarches.com/appel-offre/3boamp266207-2026-marche-traitement-deratisation" class="actu-link" target="_blank" rel="noopener">→ FranceMarches Musées d'Orsay</a>
</div>
</div>
</div>
</section>
<!-- 6. INNOVATION -->
<section class="section" id="innovation">
<div class="section-header">
<span class="emoji">🔬</span>
<h2>Innovation — Bioinsecticides, IoT, IA</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">UE — LIFE BioPest</span>
<p>Le projet européen <strong>LIFE BioPest (2024-2027)</strong> finance le développement de <strong>bioinsecticides à base de champignons entomopathogènes</strong> pour remplacer les pyréthrinoïdes en milieu urbain. Ces substances biologiques pourraient à terme faire l'objet d'AMM biocides et modifier les pratiques enseignées en formation Certibiocide Nuisibles.</p>
<div class="actu-meta">
<span class="actu-date">2024-2027 (en cours)</span>
<a href="https://www.hamelin.info/actus/desinsectisation/lutte-antiparasitaire-innovation-tradition/" class="actu-link" target="_blank" rel="noopener">→ Hamelin innovation antiparasitaire</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Anticimex France</span>
<p>Les <strong>pièges connectés IoT couplés à l'IA</strong> se déploient massivement dans l'industrie agroalimentaire et la restauration en 2026. Alertes en temps réel, anticipation des schémas saisonniers, tableaux de bord de données. Anticimex France détaille cette intégration IA + IoT + data pour une lutte préventive optimisée.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.anticimex.fr/blog/lutte-nuisibles-connectee-ia-iot-data/" class="actu-link" target="_blank" rel="noopener">→ Anticimex France IoT &amp; IA</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Nuisible Control</span>
<p>Les tendances 2026 orientent le marché vers une <strong>dératisation éthique</strong> : méthodes biologiques (prédation, champignons), réduction des rodenticides de 2e génération, montée des alternatives aux biocides chimiques. Les formateurs Certibiocide doivent intégrer ces évolutions dans leurs supports pédagogiques pour rester pertinents.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://nuisible-control.fr/actualites/tendance-deratisation-ethique-et-efficace" class="actu-link" target="_blank" rel="noopener">→ Nuisible Control tendances 2026</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Application-IoT.fr</span>
<p>Les <strong>pièges connectés IoT révolutionnent la gestion des nuisibles dans l'industrie alimentaire</strong> : capteurs intégrés, transmission de données en temps réel, réduction des passages physiques de contrôle. Cette technologie constitue un argument de vente fort pour les prestataires 3D formés et à jour sur les outils connectés.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.application-iot.fr/industrie-4-0/les-pieges-connectes-revolutionnent-la-gestion-des-nuisibles-dans-lindustrie-alimentaire/" class="actu-link" target="_blank" rel="noopener">→ Application-IoT.fr</a>
</div>
</div>
</div>
</section>
<!-- 7. VEILLE EUROPÉENNE -->
<section class="section" id="europe">
<div class="section-header">
<span class="emoji">🇪🇺</span>
<h2>Veille européenne — BPR, EFSA, résistances insecticides</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">Commission européenne</span>
<p>L'<strong>évaluation complète du BPR</strong> après 12 ans de mise en œuvre se poursuit. La consultation publique (11 décembre 2025 5 mars 2026) a recueilli les contributions des parties prenantes. Les conclusions orienteront une révision ciblant les retards d'approbation des substances actives et la simplification administrative du régime biocides.</p>
<div class="actu-meta">
<span class="actu-date">En cours — 2026</span>
<a href="https://en.reach24h.com/news/industry-news/disinfectant-biocide/eu-bpr-evaluation-public-consultation" class="actu-link" target="_blank" rel="noopener">→ REACH24H évaluation BPR</a>
</div>
</div>
<div class="actu">
<span class="actu-source">ECHA — Substances actives</span>
<p>Décisions d'<strong>avril 2026</strong> sur les substances actives clés : <strong>cyperméthrine</strong> (TP14, TP18), <strong>DBNPA, libérateurs de formaldéhyde, éthanol</strong>. Ces mises à jour de conformité impactent directement le statut des produits biocides sur le marché UE. Points à intégrer dans les contenus de formation Certibiocide.</p>
<div class="actu-meta">
<span class="actu-date">Avril 2026</span>
<a href="https://en.reach24h.com/news/industry-news/disinfectant-biocide/eu-brp-key-biocidal-active-substances-update" class="actu-link" target="_blank" rel="noopener">→ REACH24H BPR substances actives</a>
</div>
</div>
<div class="actu">
<span class="actu-source">ECHA — Programme d'examen</span>
<p>Le programme d'examen des <strong>substances actives biocides existantes</strong> continue en 2026 avec la publication d'un nouveau règlement délégué de mise à jour. Le suivi de l'avancement est crucial : certaines substances utilisées en formation (TP14/18/20) pourraient être restreintes ou retirées à l'issue des évaluations.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.atoutchimie.eu/avancement-du-programme-dexamen-europeen-des-substances-actives-existantes" class="actu-link" target="_blank" rel="noopener">→ Atout Chimie programme d'examen</a>
</div>
</div>
<div class="actu">
<span class="actu-source">GB BPR (post-Brexit)</span>
<p>Les renouvellements de <strong>substances actives sous le GB BPR sont attendus en 2026</strong>. Pertinent pour les entreprises françaises exportant vers le Royaume-Uni ou travaillant avec des fournisseurs britanniques de produits biocides. À surveiller pour anticiper d'éventuelles divergences réglementaires UE/UK.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://ecomundo.eu/en" class="actu-link" target="_blank" rel="noopener">→ Ecomundo GB BPR 2026</a>
</div>
</div>
</div>
</section>
<!-- 8. RH & CONCURRENCE -->
<section class="section" id="rh">
<div class="section-header">
<span class="emoji">👥</span>
<h2>RH &amp; Concurrence — Emploi 3D, RNCP, mouvements du secteur</h2>
</div>
<div class="section-body">
<div class="actu">
<span class="actu-source">Indeed — 11 juin 2026</span>
<p>Au <strong>11 juin 2026</strong>, Indeed recense <strong>&gt; 25 offres actives pour des techniciens dératisation 3D</strong> et &gt; 75 offres en CDI pour techniciens dératisation/désinsectisation. Le secteur recrute structurellement avec des embauches directes à l'issue du stage — argument fort pour les formations Certibiocide orientées insertion.</p>
<div class="actu-meta">
<span class="actu-date">11 juin 2026</span>
<a href="https://fr.indeed.com/q-deratisation-3d-emplois.html" class="actu-link" target="_blank" rel="noopener">→ Indeed offres 3D</a>
</div>
</div>
<div class="actu">
<span class="actu-source">France Compétences</span>
<p>Le <strong>CQP Technicien applicateur — RNCP 36313 (niveau 3, équivalent CAP)</strong> reste la certification de référence. Il intègre le Certibiocide Nuisibles dans son programme (3 mois dont 3 semaines de stage). Accessible demandeurs d'emploi et reconversions. Vérifiez la date de renouvellement RNCP pour anticiper toute échéance.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.francecompetences.fr/recherche/rncp/36313/" class="actu-link" target="_blank" rel="noopener">→ France Compétences RNCP 36313</a>
</div>
</div>
<div class="actu">
<span class="actu-source">Secteur 3D</span>
<p>Le secteur 3D compte <strong>&gt; 1 200 entreprises actives</strong> en France pour un CA supérieur à <strong>500 millions d'euros</strong>. La pénurie de techniciens qualifiés est structurelle. Les formateurs Certibiocide indépendants bénéficient d'un contexte porteur : forte demande en formation initiale et continue, amplifiée par les obligations réglementaires 2026.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.je-change-de-metier.com/fiche-metier-deratiseur" class="actu-link" target="_blank" rel="noopener">→ Je-change-de-métier.com</a>
</div>
</div>
<div class="actu">
<span class="actu-source">CS3D / ProSane</span>
<p>L'association <strong>CS3D / ProSane</strong> continue de structurer la profession : référencement des techniciens, annuaire professionnel, formations éligibles au CQP. Partenaire potentiel pour les formateurs Certibiocide indépendants cherchant à développer leur réseau et leur visibilité auprès des entreprises 3D recruteuses.</p>
<div class="actu-meta">
<span class="actu-date">2026</span>
<a href="https://www.association-prosane.fr/technicien-specalise-maitrise-nuisibles" class="actu-link" target="_blank" rel="noopener">→ CS3D ProSane</a>
</div>
</div>
</div>
</section>
</div>
<footer>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p>Tous droits réservés — Formateurs indépendants</p>
</footer>
<script>
window.addEventListener('scroll', () => {
const scrolled = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
document.getElementById('progressBar').style.width = Math.min(scrolled, 100) + '%';
});
</script>
</body>
</html>

View File

@@ -0,0 +1,835 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Veille Certibiocide — Semaine 28 | NextGN Formation</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
--teal: #0F6E56;
--teal-mid: #1D9E75;
--teal-light: #E1F5EE;
--teal-dark: #085041;
--amber: #BA7517;
--amber-light: #FAEEDA;
--amber-dark: #633806;
--coral: #993C1D;
--coral-mid: #D85A30;
--coral-light: #FAECE7;
--purple: #534AB7;
--purple-light: #EEEDFE;
--purple-dark: #3C3489;
--blue: #185FA5;
--blue-light: #E6F1FB;
--bg: #F7F6F2;
--white: #FFFFFF;
--text: #1a1a18;
--text-muted: #6b6a65;
--border: rgba(0,0,0,0.1);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
padding-top: 70px;
background: var(--bg);
font-family: 'DM Sans', sans-serif;
color: var(--text);
line-height: 1.6;
}
/* ── PROGRESS BAR ── */
.progress {
height: 3px;
background: var(--border);
position: fixed;
top: 70px;
left: 0;
right: 0;
z-index: 999;
}
.progress-bar {
height: 100%;
background: var(--teal-mid);
width: 0%;
transition: width 0.3s ease;
}
/* ── NAV HEADER ── */
.nav-header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 70px;
background: rgba(255,255,255,0.95);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border);
z-index: 1000;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 40px;
}
.header-logo {
font-family: 'Syne', sans-serif;
font-weight: 800;
font-size: 18px;
text-decoration: none;
background: linear-gradient(135deg, var(--teal), var(--coral-mid));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header-nav {
display: flex;
gap: 28px;
}
.header-nav a {
font-family: 'Syne', sans-serif;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text);
text-decoration: none;
position: relative;
padding-bottom: 2px;
}
.header-nav a::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 1px;
background: var(--teal-mid);
transition: width 0.2s ease;
}
.header-nav a:hover::after { width: 100%; }
.header-nav a:hover { color: var(--teal-mid); }
/* ── HERO ── */
.hero {
background: var(--teal-light);
border-bottom: 2px solid var(--teal-mid);
padding: 60px 40px 50px;
text-align: center;
}
.hero-badge {
display: inline-block;
background: var(--teal-mid);
color: var(--white);
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
padding: 6px 16px;
border-radius: 20px;
margin-bottom: 20px;
}
.hero h1 {
font-family: 'Syne', sans-serif;
font-weight: 800;
font-size: clamp(28px, 4vw, 46px);
color: var(--teal-dark);
margin-bottom: 12px;
line-height: 1.15;
}
.hero-meta {
font-size: 14px;
color: var(--text-muted);
font-weight: 300;
}
.hero-meta strong { color: var(--teal); font-weight: 500; }
/* ── CONTAINER ── */
.container {
max-width: 960px;
margin: 0 auto;
padding: 40px 24px;
}
/* ── SOMMAIRE ── */
.sommaire {
background: var(--white);
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
padding: 28px 32px;
margin-bottom: 32px;
}
.sommaire h2 {
font-family: 'Syne', sans-serif;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
margin-bottom: 16px;
}
.sommaire-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 8px;
}
.sommaire-grid a {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--teal-dark);
text-decoration: none;
padding: 6px 10px;
border-radius: 6px;
transition: background 0.2s;
}
.sommaire-grid a:hover {
background: var(--teal-light);
color: var(--teal);
}
/* ── POINTS D'ATTENTION ── */
.attention-box {
background: var(--amber-light);
border-left: 4px solid var(--amber);
border-radius: 0 10px 10px 0;
padding: 28px 32px;
margin-bottom: 36px;
}
.attention-box h2 {
font-family: 'Syne', sans-serif;
font-weight: 700;
font-size: 16px;
color: var(--amber-dark);
margin-bottom: 16px;
}
.attention-item {
display: flex;
gap: 14px;
margin-bottom: 14px;
align-items: flex-start;
}
.attention-item:last-child { margin-bottom: 0; }
.attention-num {
background: var(--amber);
color: var(--white);
font-family: 'Syne', sans-serif;
font-weight: 700;
font-size: 12px;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 2px;
}
.attention-text {
font-size: 14px;
color: var(--amber-dark);
line-height: 1.55;
}
.attention-text strong { font-weight: 500; }
/* ── SECTIONS RUBRIQUES ── */
.section {
background: var(--white);
border-radius: 10px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
margin-bottom: 28px;
overflow: hidden;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.section-header {
background: var(--teal-light);
border-bottom: 1px solid rgba(29,158,117,0.2);
padding: 20px 28px;
display: flex;
align-items: center;
gap: 12px;
}
.section-emoji { font-size: 22px; }
.section-header h2 {
font-family: 'Syne', sans-serif;
font-weight: 700;
font-size: 17px;
color: var(--teal-dark);
}
.section-subtitle {
font-size: 11px;
color: var(--text-muted);
font-weight: 300;
margin-top: 2px;
}
.section-body { padding: 24px 28px; }
/* ── ACTUALITÉ CARD ── */
.actu {
border-bottom: 1px solid var(--border);
padding-bottom: 20px;
margin-bottom: 20px;
transition: transform 0.2s;
}
.actu:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.actu-header { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.source-badge {
display: inline-block;
background: var(--teal-mid);
color: var(--white);
font-size: 10px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 3px 10px;
border-radius: 12px;
}
.actu-date {
font-size: 12px;
color: var(--text-muted);
font-style: italic;
}
.actu p {
font-size: 14px;
color: var(--text);
line-height: 1.6;
margin-bottom: 6px;
}
.actu a {
font-size: 12px;
color: var(--teal-mid);
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 4px;
transition: transform 0.2s;
}
.actu a:hover { transform: translateY(-1px); color: var(--teal-dark); }
.actu a::before { content: '→ '; }
/* ── NOTE AVERTISSEMENT ── */
.warning-note {
background: var(--amber-light);
border: 1px solid var(--amber);
border-radius: 6px;
padding: 12px 16px;
font-size: 13px;
color: var(--amber-dark);
margin-top: 8px;
}
/* ── FOOTER ── */
footer {
background: var(--text);
color: var(--white);
padding: 40px;
font-size: 13px;
text-align: center;
}
footer p { margin-bottom: 4px; }
/* ── RESPONSIVE ── */
@media (max-width: 768px) {
.nav-header { padding: 0 20px; }
.header-nav { gap: 14px; }
.header-nav a { font-size: 10px; }
.hero { padding: 40px 20px 36px; }
.container { padding: 24px 16px; }
.section-header { padding: 16px 20px; }
.section-body { padding: 18px 20px; }
.sommaire { padding: 20px; }
.attention-box { padding: 20px; }
.sommaire-grid { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
.header-nav { display: none; }
}
</style>
</head>
<body>
<!-- Barre de progression -->
<div class="progress"><div class="progress-bar" id="progressBar"></div></div>
<!-- Navigation -->
<nav class="nav-header">
<a href="index.html" class="header-logo"><span>NextGN</span> Formation</a>
<nav class="header-nav">
<a href="index.html#formations">Exercices interactifs</a>
<a href="index.html#about">À propos</a>
<a href="index.html#contact">Contact</a>
</nav>
</nav>
<!-- Hero -->
<header class="hero">
<div class="hero-badge">Rapport de veille · Semaine 28</div>
<h1>Veille Certibiocide</h1>
<p class="hero-meta">
<strong>Semaine du 7 au 13 juillet 2026</strong> &nbsp;·&nbsp;
8 rubriques · Sources officielles prioritaires
</p>
</header>
<div class="container">
<!-- Sommaire -->
<nav class="sommaire" aria-label="Sommaire">
<h2>Sommaire</h2>
<div class="sommaire-grid">
<a href="#reglementaire">⚖️ Réglementaire</a>
<a href="#formation">🎓 Marché formation</a>
<a href="#nuisibles">🐀 Nuisibles &amp; ESOD</a>
<a href="#desinfection">🧴 Désinfection</a>
<a href="#opportunites">💡 Opportunités</a>
<a href="#innovation">🔬 Innovation</a>
<a href="#europe">🇪🇺 Veille européenne</a>
<a href="#rh">👥 RH &amp; Concurrence</a>
</div>
</nav>
<!-- Points d'attention -->
<div class="attention-box">
<h2>📌 Points d'attention — Semaine 28</h2>
<div class="attention-item">
<div class="attention-num">1</div>
<div class="attention-text">
<strong>Qualiopi FAFCEA obligatoire depuis le 1er juillet 2026.</strong>
Les organismes non certifiés Qualiopi ne peuvent plus accéder aux financements FAFCEA (chefs d'entreprise artisanale). Point critique à vérifier si Certibiocide est dispensée à des artisans.
</div>
</div>
<div class="attention-item">
<div class="attention-num">2</div>
<div class="attention-text">
<strong>Réforme Omnibus BPR : vers une approbation indéfinie des substances actives.</strong>
La Commission européenne propose de supprimer le renouvellement obligatoire tous les 10 ans pour les substances ne relevant pas des critères d'exclusion. Changement structurel majeur à intégrer dans les contenus de formation réglementaire.
</div>
</div>
<div class="attention-item">
<div class="attention-num">3</div>
<div class="attention-text">
<strong>Moustique tigre dans 83 départements (86 % du territoire).</strong>
La progression continue crée une forte demande de formation désinsectisation/démoustication. Opportunité de développement de modules spécifiques pour les professionnels 3D.
</div>
</div>
</div>
<!-- ─── 1. RÉGLEMENTAIRE ─── -->
<section class="section" id="reglementaire">
<div class="section-header">
<span class="section-emoji">⚖️</span>
<div>
<h2>Réglementaire</h2>
<div class="section-subtitle">ANSES · ECHA · MTE · Légifrance</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">ANSES</span>
<span class="actu-date">Publié le 01/07/2026</span>
</div>
<p><strong>Nouvelle AMM — ZANZA SPRAY autorisé.</strong> L'ANSES a signé le 18 juin 2026 la décision d'autorisation de mise à disposition sur le marché du produit biocide ZANZA SPRAY, publiée au registre le 1er juillet 2026. Ce produit rejoint la liste des répulsifs ou insecticides biocides homologués en France.</p>
<a href="https://www.anses.fr/fr/decisions_biocide" target="_blank" rel="noopener">Registre AMM biocides ANSES</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">ANSES</span>
<span class="actu-date">Publiés le 24/06/2026</span>
</div>
<p><strong>Retraits d'AMM — 5 produits de traitement du bois.</strong> Cinq produits biocides ont fait l'objet d'une décision de retrait d'autorisation signée le 15/06/2026 et publiée le 24/06/2026 : TRAITEMENT DU BOIS MULTI USAGES, WINKO TRAITEMENT BOIS UNIVERSEL, XILIX 7000, XYL SORX 2000 et EKOLIS TRAITEMENT BOIS MULTI USAGES. Les professionnels concernés doivent procéder à la liquidation de leurs stocks dans les délais impartis.</p>
<a href="https://www.anses.fr/fr/decisions_biocide" target="_blank" rel="noopener">Registre AMM biocides ANSES</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">ANSES</span>
<span class="actu-date">2026 (en cours)</span>
</div>
<p><strong>Consultation publique — lignes directrices AMM biocides.</strong> L'ANSES a mis en consultation publique sa proposition de lignes directrices pour la délivrance des AMM biocides en France. Ce document vise à clarifier et standardiser le processus d'instruction des dossiers d'autorisation pour les fabricants et importateurs.</p>
<a href="https://www.anses.fr/fr/content/lanses-met-en-consultation-publique-sa-proposition-de-lignes-directrices-pour-la-delivrance" target="_blank" rel="noopener">Consultation ANSES</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">Ecologie.gouv.fr</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Rappel réglementaire — Certification obligatoire 2026 renforcée.</strong> L'année 2026 marque un renforcement de la réglementation biocide en France : la certification Certibiocide reste obligatoire pour tout professionnel utilisant des produits biocides à usage professionnel. Les OF délivrant la formation doivent eux-mêmes être certifiés Qualiopi pour accéder aux fonds publics.</p>
<a href="https://www.ecologie.gouv.fr/politiques-publiques/produits-biocides" target="_blank" rel="noopener">MTE — Produits biocides</a>
</div>
</div>
</section>
<!-- ─── 2. MARCHÉ FORMATION ─── -->
<section class="section" id="formation">
<div class="section-header">
<span class="section-emoji">🎓</span>
<div>
<h2>Marché formation</h2>
<div class="section-subtitle">France Compétences · Mon Compte Formation · OPCO EP</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">France Compétences</span>
<span class="actu-date">1er juillet 2026</span>
</div>
<p><strong>Qualiopi obligatoire pour FAFCEA dès le 1er juillet 2026.</strong> Depuis le 1er juillet 2026, seuls les organismes de formation certifiés Qualiopi sont éligibles aux financements FAFCEA (Fonds d'Assurance Formation des Chefs d'Entreprise Artisanale). Point critique pour les formateurs Certibiocide intervenant auprès d'artisans plombiers, carreleurs ou autres professions exposées.</p>
<a href="https://csfc-federation.org/blog/qualiopi-devient-obligatoire-pour-les-financements-fafcea-des-2026/" target="_blank" rel="noopener">CSFC-Fédération</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">IGAS / OPCO</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Budget OPCO 2026 — 11,8 Mds€ gérés, 521M€ pour les TPE/PME.</strong> Selon les données IGAS publiées en novembre 2025, les 11 OPCO gèrent 11,8 milliards d'euros de ressources en 2026. L'enveloppe dédiée au plan de développement des compétences des entreprises de moins de 50 salariés atteint 521 millions d'euros — un levier important pour les formations Certibiocide en entreprise.</p>
<a href="https://www.starthack.fr/financement-de-la-formation-professionnelle-en-2026-opco-budgets-et-obligations-des-centres-de-formation/" target="_blank" rel="noopener">Analyse financement 2026</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">France Compétences</span>
<span class="actu-date">Janvier 2026</span>
</div>
<p><strong>Renouvellement des 8 instances de labellisation Qualiopi jusqu'en 2028.</strong> France Compétences a renouvelé pour trois ans (à compter du 1er janvier 2026) les huit certificateurs habilités à délivrer la certification Qualiopi. Les OF certifiés n'ont pas à rechanger d'organisme certificateur avant 2028.</p>
<a href="https://www.digi-certif.com/debut-2026-quelles-actualites-pour-la-formation-pro-et-qualiopi/" target="_blank" rel="noopener">Actualités Qualiopi 2026</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">OPCO</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Délais d'instruction OPCO : 15 à 30 jours.</strong> En 2026, le délai moyen entre le dépôt d'un dossier de financement et la notification se situe entre 15 et 30 jours selon les OPCO. Un délai à anticiper dans la planification des sessions de formation Certibiocide pour les clients entreprises.</p>
<a href="https://formaltic.fr/financement-opco-formations-2026/" target="_blank" rel="noopener">Financement OPCO 2026</a>
</div>
</div>
</section>
<!-- ─── 3. NUISIBLES & ESOD ─── -->
<section class="section" id="nuisibles">
<div class="section-header">
<span class="section-emoji">🐀</span>
<div>
<h2>Nuisibles &amp; ESOD</h2>
<div class="section-subtitle">ANSES · INRAE · OFB · Santé Publique France</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">Santé Publique France</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Moustique tigre — 83 départements colonisés (86 % du territoire).</strong> Début 2026, <em>Aedes albopictus</em> est implanté de façon permanente dans 83 des 96 départements de métropole. L'espèce représente un risque sanitaire croissant avec des transmissions locales de dengue et de chikungunya, amplifiées par le réchauffement climatique. Juillet et août sont les mois de pic d'activité.</p>
<a href="https://www.service-public.gouv.fr/particuliers/actualites/A14140" target="_blank" rel="noopener">Service-public.fr — Moustique tigre</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">IZIPest / OFB</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Frelon asiatique — 70 départements touchés, 20 % de la mortalité apicole.</strong> En 2026, le frelon asiatique (<em>Vespa velutina</em>) est présent dans plus de 70 départements français. Il contribue à environ 20 % de la mortalité des colonies d'abeilles domestiques. Le frelon asiatique reste classé ESOD (Espèce Susceptible d'Occasionner des Dégâts) dans toutes les régions concernées.</p>
<a href="https://izipest.com/blog/top-3-especes-envahissantes-france-2026/" target="_blank" rel="noopener">IZIPest — Espèces invasives 2026</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">ANSES / INRAE</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Punaises de lit — enjeu socio-économique majeur persistant.</strong> Les punaises de lit (<em>Cimex lectularius</em>) ne transmettent pas de maladie mais génèrent un impact psychologique, social et économique important. Leur élimination reste coûteuse et techniquement exigeante, nécessitant une intervention certifiée. Le niveau de demande d'intervention professionnelle reste élevé en 2026.</p>
<a href="https://www.larochedeglun.fr/Lutte-contre-le-frelon-asiatique-moustique-tigre-Punaises" target="_blank" rel="noopener">Info espèces nuisibles</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">IZIPest</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Fourmi d'Argentine — 3e espèce invasive préoccupante en 2026.</strong> Aux côtés du moustique tigre et du frelon asiatique, la fourmi d'Argentine (<em>Linepithema humile</em>) est identifiée parmi les espèces invasives les plus préoccupantes pour les professionnels de la lutte antiparasitaire. Sa présence dans les zones urbaines et péri-urbaines du Sud de la France est en progression.</p>
<a href="https://izipest.com/blog/top-3-especes-envahissantes-france-2026/" target="_blank" rel="noopener">IZIPest — Top 3 espèces 2026</a>
</div>
<div class="warning-note">
⚠️ <em>Aucune publication officielle vérifiée cette semaine sur les rongeurs résistants aux rodenticides (ANSES, INRAE) pour la période juillet 2026. Données issues des sources les plus récentes disponibles.</em>
</div>
</div>
</section>
<!-- ─── 4. DÉSINFECTION ─── -->
<section class="section" id="desinfection">
<div class="section-header">
<span class="section-emoji">🧴</span>
<div>
<h2>Désinfection</h2>
<div class="section-subtitle">ANSES · AFNOR</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">AFNOR / ANSES</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Renforcement de la certification obligatoire pour les professionnels de la désinfection.</strong> En 2026, la réglementation biocide française renforce l'obligation pour tout professionnel manipulant des désinfectants biocides d'être titulaire du Certibiocide. Ce renforcement est documenté sur plusieurs sites de formation spécialisés (TBCF, Delcourt) à la suite de nouvelles exigences réglementaires entrées en vigueur début 2026.</p>
<a href="https://tbcformation.com/certibiocide-2026-nouveautes-reglementation-desinfection/" target="_blank" rel="noopener">TBCF — Certibiocide 2026</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">AFNOR</span>
<span class="actu-date">En vigueur</span>
</div>
<p><strong>Norme NF T 72-281 — Désinfection des surfaces par voie aérienne.</strong> La norme NF T 72-281 (AFNOR) encadre les dispositifs de désinfection par fumigation et nébulisation. Elle reste la référence technique pour les professionnels 3D intervenant sur des surfaces étendues. Les produits biocides utilisés dans ce cadre doivent impérativement disposer d'une AMM valide.</p>
<a href="https://normalisation.afnor.org/actualites/antiseptiques-et-desinfectants-chimiques-afnor-vous-eclaire-sur-lapport-des-normes-volontaires/" target="_blank" rel="noopener">AFNOR — Normes désinfectants</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">AFNOR</span>
<span class="actu-date">En vigueur</span>
</div>
<p><strong>NF EN 14885 — Norme cadre des produits biocides en désinfection.</strong> La NF EN 14885 est la norme européenne régissant les produits biocides pour la désinfection en milieux hospitalier, industriel, agroalimentaire et communautaire. Elle définit les conditions d'évaluation de l'efficacité anti-microbienne (bactéricide, fongicide, virucide, sporicide). Point de référence incontournable en formation Certibiocide TP 19.</p>
<a href="https://www.boutique.afnor.org/en-gb/standard/nf-en-14476/chemical-disinfectants-and-antiseptics-quantitative-suspension-test-for-the/fa166895/1398" target="_blank" rel="noopener">AFNOR — NF EN 14476</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">ANSES / UE</span>
<span class="actu-date">En vigueur</span>
</div>
<p><strong>Rappel — Règlement UE 528/2012 : enregistrement obligatoire de tous les désinfectants biocides.</strong> Tout désinfectant commercialisé doit être enregistré conformément au règlement BPR (UE) 528/2012. L'autorisation est délivrée par l'autorité nationale compétente (ANSES en France), garantissant sécurité et efficacité pour l'usage revendiqué. Ce cadre doit être rappelé systématiquement en formation.</p>
<a href="https://www.prodhybase.fr/norme_generalite.html" target="_blank" rel="noopener">ProdHYBase — Normes</a>
</div>
</div>
</section>
<!-- ─── 5. OPPORTUNITÉS ─── -->
<section class="section" id="opportunites">
<div class="section-header">
<span class="section-emoji">💡</span>
<div>
<h2>Opportunités</h2>
<div class="section-subtitle">BOAMP · CPF · Secteurs demandeurs</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">BOAMP</span>
<span class="actu-date">Juillet 2026</span>
</div>
<p><strong>AO Département de l'Oise — Missions 3D sur sites et réseau routier.</strong> Un marché public significatif pour des missions de dératisation, désinsectisation, désinfection et traitements spécifiques sur les sites et le réseau routier du département de l'Oise (réf. 3/boamp/2616972). La date prévisionnelle de notification du marché-cadre est fixée à juillet 2026. Ce type de marché nécessite des intervenants titulaires du Certibiocide.</p>
<a href="https://www.francemarches.com/appel-offre/3boamp2616972-2026-missions-deratisation-desinsectisation" target="_blank" rel="noopener">AO Oise — FranceMarchés</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">BOAMP</span>
<span class="actu-date">2026 (en cours)</span>
</div>
<p><strong>AO Prestations anti-nuisibles 4D — Marché pluriannuel.</strong> Plusieurs marchés 4D (dératisation, désinsectisation, désinfection, dépigeonnisation) sont actuellement ouverts sur BOAMP (réf. 3/boamp/2627622 et 3/boamp/264816). Ces marchés publiés incluent des prestations de prévention et de lutte contre les nuisibles et l'insalubrité, ciblant les collectivités et établissements publics.</p>
<a href="https://www.francemarches.com/appels-offre/deratisation-desinsectisation" target="_blank" rel="noopener">81 AO dératisation-désinsectisation en cours</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">BOAMP</span>
<span class="actu-date">2026</span>
</div>
<p><strong>AO Ville de Fos-sur-Mer — Lutte contre les nuisibles en 2 lots.</strong> La ville de Fos-sur-Mer a publié un appel d'offres en 2026 pour des prestations de lutte antiparasitaire en deux lots : (1) dératisation/désinsectisation/désinfection classique et (2) campagne de lutte contre les rats par prédation. Ce second lot illustre l'intérêt croissant pour les méthodes alternatives aux rodenticides chimiques.</p>
<a href="https://www.francemarches.com/appel-offre/3boamp2651311-2026-prestations-lutte-contre" target="_blank" rel="noopener">AO Fos-sur-Mer</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">FranceMarchés</span>
<span class="actu-date">Juillet 2026</span>
</div>
<p><strong>94 AO dératisation et 81 AO désinsectisation-désinfection actifs en France.</strong> Au moment de la veille (semaine 28), FranceMarchés recense 94 appels d'offres actifs pour la dératisation seule et 81 pour la dématisation-désinsectisation. Ce volume confirme un marché dynamique et une demande soutenue en professionnels certifiés Certibiocide.</p>
<a href="https://www.francemarches.com/appels-offre/deratisation" target="_blank" rel="noopener">FranceMarchés — 94 AO dératisation</a>
</div>
</div>
</section>
<!-- ─── 6. INNOVATION ─── -->
<section class="section" id="innovation">
<div class="section-header">
<span class="section-emoji">🔬</span>
<div>
<h2>Innovation</h2>
<div class="section-subtitle">CORDIS · PubMed · BPI France</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">CORDIS / UE</span>
<span class="actu-date">20242027</span>
</div>
<p><strong>Projet LIFE BioPest — Bioinsecticides fongiques pour remplacer les pyréthroïdes urbains.</strong> Le projet européen LIFE BioPest (2024-2027) finance le développement de bioinsecticides à base de champignons entomopathogènes destinés à remplacer les pyréthroïdes en milieu urbain. Ce projet vise directement les pratiques des techniciens 3D et pourrait modifier les produits disponibles en TP 18 (désinsectisation).</p>
<a href="https://www.mdpi.com/2077-0472/16/5/597" target="_blank" rel="noopener">MDPI — Contrôle biologique des insectes 2026</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">Haaretz / R&amp;D</span>
<span class="actu-date">Mai 2026</span>
</div>
<p><strong>IA pour la conception de bioinsecticides protéiques — 1er proof-of-concept mondial.</strong> Une entreprise a annoncé en mai 2026 avoir atteint un jalon critique : la mise au point du premier proof-of-concept mondial d'une plateforme de conception de bioinsecticides protéiques pilotée par IA. Cette approche de novo permet de cibler des espèces nuisibles spécifiques avec une haute sélectivité et sans résistance croisée.</p>
<a href="https://www.haaretz.com/haaretz-labels/cutting-edge/2026-05-25/ty-article-labels/.premium/pioneering-next-generation-crop-protection/0000019e-5e92-d6cc-a79e-dfbe61750000" target="_blank" rel="noopener">Haaretz — Next-Gen Crop Protection</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">Anticimex / IoT</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Pièges connectés et surveillance IoT temps réel — la lutte antiparasitaire 2.0.</strong> Les solutions de lutte antiparasitaire connectées (pièges intelligents, détecteurs automatiques, tableaux de bord IoT) se déploient en industrie agroalimentaire et grande distribution. Ces dispositifs permettent une prévention proactive plutôt qu'une intervention curative. Le formateur Certibiocide doit intégrer ces outils dans les modules sur les méthodes alternatives.</p>
<a href="https://www.anticimex.fr/blog/lutte-nuisibles-connectee-ia-iot-data/" target="_blank" rel="noopener">Anticimex — IA, IoT &amp; Data</a>
</div>
</div>
</section>
<!-- ─── 7. VEILLE EUROPÉENNE ─── -->
<section class="section" id="europe">
<div class="section-header">
<span class="section-emoji">🇪🇺</span>
<div>
<h2>Veille européenne</h2>
<div class="section-subtitle">ECHA · EFSA · Commission européenne</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">Commission européenne</span>
<span class="actu-date">En cours — 2025/2026</span>
</div>
<p><strong>Évaluation du règlement BPR en cours depuis Q4 2025.</strong> La Commission européenne a lancé fin 2025 une évaluation complète du règlement BPR (UE 528/2012) par rapport à ses objectifs initiaux et aux besoins émergents (durabilité, simplification, résistances). Les résultats orienteront une révision potentielle du texte à moyen terme, avec des implications directes sur le Certibiocide.</p>
<a href="https://health.ec.europa.eu/biocides/regulation_en" target="_blank" rel="noopener">Commission européenne — BPR</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">ECHA</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Programme de révision des substances actives — 42 % achevé.</strong> L'ECHA indique que 42 % du programme d'examen des substances actives biocides existantes est désormais terminé. Ce programme est essentiel car il conditionne les approbations européennes, et donc les AMM nationales. Les substances non encore évaluées restent sous statut transitoire.</p>
<a href="https://echa.europa.eu/fr/regulations/biocidal-products-regulation/upcoming-deadlines" target="_blank" rel="noopener">ECHA — Prochaines échéances</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">ECHA</span>
<span class="actu-date">Échéance : 31/12/2026</span>
</div>
<p><strong>Deadline perturbateurs endocriniens — données à soumettre avant fin 2026.</strong> Le 31 décembre 2026 est la date limite à laquelle les données manquantes sur les perturbateurs endocriniens (PE) doivent être soumises pour plusieurs substances actives biocides. Les fabricants et importateurs concernés sont en cours de constitution des dossiers. Impact potentiel sur la disponibilité de certains produits utilisés en TP 18 et 19.</p>
<a href="https://echa.europa.eu/fr/regulations/biocidal-products-regulation/upcoming-deadlines" target="_blank" rel="noopener">ECHA — Upcoming deadlines</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">Commission européenne</span>
<span class="actu-date">2026 (proposition)</span>
</div>
<p><strong>Réforme Omnibus — approbation indéfinie des substances actives biocides.</strong> La Commission européenne propose de supprimer le renouvellement obligatoire tous les 10 ans des substances actives biocides approuvées sous le BPR, dès lors qu'elles ne relèvent pas des critères d'exclusion ou de substitution. Les substances éligibles passeraient automatiquement en approbation indéfinie — simplification majeure pour les industriels.</p>
<a href="https://www.knoell.com/en/news/monthly-global-biocides-regulatory-newsletter-february-2026" target="_blank" rel="noopener">Knoell — Newsletter biocides</a>
</div>
</div>
</section>
<!-- ─── 8. RH & CONCURRENCE ─── -->
<section class="section" id="rh">
<div class="section-header">
<span class="section-emoji">👥</span>
<div>
<h2>RH &amp; Concurrence</h2>
<div class="section-subtitle">Indeed · Glassdoor · France Travail · CS3D</div>
</div>
</div>
<div class="section-body">
<div class="actu">
<div class="actu-header">
<span class="source-badge">Indeed</span>
<span class="actu-date">23/06/2026</span>
</div>
<p><strong>50+ offres "Technicien Certibiocide" sur Indeed en juin 2026.</strong> Au 23 juin 2026, Indeed recense plus de 50 offres d'emploi ciblant spécifiquement les techniciens titulaires du Certibiocide. Ce volume confirme que la certification est devenue un prérequis de recrutement dans le secteur 3D — un argument pédagogique fort à valoriser en formation.</p>
<a href="https://fr.indeed.com/q-technicien-certibiocide-emplois.html" target="_blank" rel="noopener">Indeed — Offres Certibiocide</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">Indeed / Glassdoor</span>
<span class="actu-date">JuinJuillet 2026</span>
</div>
<p><strong>94 offres 3D actives sur Glassdoor France, 25+ sur Indeed.</strong> Le marché de l'emploi 3D reste en tension : Glassdoor dénombre 84 offres "dératisation désinsectisation" en France, et Indeed plus de 25 offres spécifiques "dératisation 3D" (au 11/06/2026). Les postes proposent en moyenne 1 752 €/mois brut avec véhicule utilitaire fourni.</p>
<a href="https://www.glassdoor.fr/Emploi/deratisation-desinsectisation-et-emplois-SRCH_KO0,32.htm" target="_blank" rel="noopener">Glassdoor — Offres 3D</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">CS3D / France Compétences</span>
<span class="actu-date">2026</span>
</div>
<p><strong>CQP Maîtrise des nuisibles (RNCP niveau 3) — intègre le Certibiocide.</strong> Le CQP Technicien applicateur en maîtrise des nuisibles, développé par la CS3D et inscrit au RNCP niveau 3 (équivalent CAP), inclut le passage du Certibiocide dans un programme de 3 mois. Avec 1 200+ entreprises actives et 500 M€ de CA sectoriel, les débouchés restent nombreux pour les diplômés.</p>
<a href="https://www.francecompetences.fr/recherche/rncp/36313/" target="_blank" rel="noopener">France Compétences — RNCP 36313</a>
</div>
<div class="actu">
<div class="actu-header">
<span class="source-badge">France Travail</span>
<span class="actu-date">2026</span>
</div>
<p><strong>Offres en régions — exemple : Technicien 3D à Perpignan (CDI, réf. 196LSNT).</strong> France Travail recense des offres de techniciens dératisation/désinsectisation/désinfection dans toutes les régions. L'offre en Occitanie illustre la diffusion nationale des recrutements 3D. La maîtrise du Certibiocide y est systématiquement mentionnée comme un "atout fortement apprécié" ou une exigence.</p>
<a href="https://candidat.francetravail.fr/offres/recherche/detail/196LSNT" target="_blank" rel="noopener">France Travail — Offre Perpignan</a>
</div>
</div>
</section>
</div>
<!-- Footer -->
<footer>
<p>&copy; 2026 NextGN Formation - Veille Certibiocide Semaine 28</p>
<p style="margin-top:10px; opacity:0.6;">Tous droits réservés - Formateurs indépendants</p>
</footer>
<script>
window.addEventListener('scroll', () => {
const scrolled = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
document.getElementById('progressBar').style.width = scrolled + '%';
});
</script>
</body>
</html>

View File

@@ -1,521 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Index Veille Certibiocide - Archives & Rapports</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap" rel="stylesheet">
<style>
:root {
--teal: #0F6E56;
--teal-mid: #1D9E75;
--teal-light: #E1F5EE;
--amber: #BA7517;
--amber-light: #FAEEDA;
--amber-dark: #633806;
--coral: #993C1D;
--coral-mid: #D85A30;
--coral-light: #FAECE7;
--purple: #534AB7;
--purple-light: #EEEDFE;
--blue: #185FA5;
--blue-light: #E6F1FB;
--bg: #F7F6F2;
--white: #FFFFFF;
--text: #1a1a18;
--text-muted: #6b6a65;
--border: rgba(0,0,0,0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
body {
font-family: 'DM Sans', sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
padding-top: 70px;
}
/* ===== HEADER FIXE ===== */
header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 70px;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-bottom: 2px solid var(--purple);
z-index: 1000;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
}
.logo {
font-family: 'Syne', sans-serif;
font-size: 16px;
font-weight: 700;
letter-spacing: -0.5px;
background: linear-gradient(135deg, var(--teal-mid), var(--coral-mid));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-decoration: none;
}
nav {
display: flex;
gap: 2rem;
}
nav a {
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
text-decoration: none;
color: var(--text-muted);
transition: color 0.3s ease;
}
nav a:hover {
color: var(--purple);
}
/* ===== PROGRESS BAR ===== */
.progress {
position: fixed;
top: 70px;
left: 0;
right: 0;
height: 3px;
background: var(--border);
z-index: 999;
}
.progress-bar {
height: 100%;
background: var(--purple);
width: 0%;
transition: width 0.3s ease;
}
/* ===== MAIN CONTENT ===== */
main {
max-width: 1100px;
margin: 0 auto;
padding: 3rem 2rem;
}
.section {
margin-bottom: 3rem;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ===== PAGE HEADER ===== */
.page-header {
background: var(--amber-light);
border-left: 4px solid var(--purple);
border-radius: 8px;
padding: 2rem;
margin-bottom: 2rem;
}
.page-header h1 {
font-family: 'Syne', sans-serif;
font-size: 2.2rem;
font-weight: 800;
color: var(--text);
margin-bottom: 0.5rem;
}
.page-header p {
font-size: 0.95rem;
color: var(--text-muted);
line-height: 1.7;
}
/* ===== CONTENT SECTIONS ===== */
h2 {
font-family: 'Syne', sans-serif;
font-size: 1.6rem;
font-weight: 700;
color: var(--text);
margin-bottom: 1.5rem;
margin-top: 2.5rem;
padding-bottom: 0.75rem;
border-bottom: 3px solid var(--purple);
}
h3 {
font-family: 'Syne', sans-serif;
font-size: 1.1rem;
font-weight: 700;
color: var(--text);
margin-top: 1.5rem;
margin-bottom: 1rem;
}
/* ===== RAPPORTS GRID ===== */
.rapports-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
margin-bottom: 2rem;
}
.rapport-card {
background: var(--white);
border: 2px solid var(--amber-light);
border-radius: 8px;
padding: 1.5rem;
transition: all 0.3s ease;
cursor: pointer;
text-decoration: none;
display: flex;
flex-direction: column;
height: 100%;
}
.rapport-card:hover {
border-color: var(--purple);
box-shadow: 0 12px 32px rgba(186, 117, 23, 0.15);
transform: translateY(-4px);
}
.rapport-semaine {
font-family: 'Syne', sans-serif;
font-size: 1.3rem;
font-weight: 700;
color: var(--purple);
margin-bottom: 0.5rem;
}
.rapport-date {
font-size: 0.85rem;
color: var(--text-muted);
font-weight: 500;
margin-bottom: 1rem;
}
.rapport-desc {
font-size: 0.9rem;
color: var(--text);
line-height: 1.6;
flex-grow: 1;
margin-bottom: 1rem;
}
.rapport-btn {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.05em;
color: var(--purple);
text-decoration: none;
transition: gap 0.3s ease;
margin-top: auto;
width: fit-content;
}
.rapport-btn:hover {
gap: 12px;
}
/* ===== RUBRIQUES EXPLICATIVES ===== */
.rubriques-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
margin: 2rem 0;
}
.rubrique-card {
background: var(--white);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.5rem;
transition: all 0.3s ease;
}
.rubrique-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.rubrique-icon {
font-size: 1.8rem;
margin-bottom: 0.75rem;
}
.rubrique-title {
font-family: 'Syne', sans-serif;
font-size: 1rem;
font-weight: 700;
color: var(--text);
margin-bottom: 0.5rem;
}
.rubrique-desc {
font-size: 0.85rem;
color: var(--text-muted);
line-height: 1.6;
}
/* ===== FOOTER ===== */
footer {
background: var(--text);
color: var(--white);
padding: 2.5rem;
text-align: center;
font-size: 13px;
margin-top: 4rem;
border-top: 1px solid var(--border);
}
footer p {
margin-bottom: 0.5rem;
}
footer p:last-child {
opacity: 0.6;
font-size: 12px;
margin-top: 0.5rem;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 768px) {
header {
padding: 0 1rem;
}
nav {
gap: 1rem;
}
nav a {
font-size: 9px;
}
main {
padding: 2rem 1rem;
}
.page-header h1 {
font-size: 1.8rem;
}
h2 {
font-size: 1.3rem;
}
.rapports-grid {
grid-template-columns: 1fr;
}
.rubriques-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<!-- PROGRESS BAR -->
<div class="progress">
<div class="progress-bar" id="progressBar"></div>
</div>
<!-- HEADER -->
<header>
<div class="logo">NextGN Formation</div>
<nav>
<a href="#formations">Exercices interactifs</a>
<a href="#documentation">Documentation</a>
<a href="#rapports">Rapports de veille</a>
<a href="#about">À propos</a>
<a href="#contact">Contact</a>
</nav>
</header>
<!-- MAIN CONTENT -->
<main>
<!-- PAGE HEADER -->
<section class="page-header">
<h1>📚 Index Veille Certibiocide</h1>
<p>Accédez à l'ensemble des rapports de veille hebdomadaires, analysant l'actualité réglementaire, les opportunités de marché et les tendances du secteur Certibiocide. Chaque rapport synthétise 8 rubriques thématiques.</p>
</section>
<!-- RAPPORTS RÉCENTS -->
<section class="section">
<h2>📊 Rapports Récents</h2>
<p style="color: var(--text-muted); margin-bottom: 1.5rem;">Consultez les derniers rapports de veille, mis à jour chaque semaine.</p>
<div class="rapports-grid">
<!-- Semaine 21 -->
<a href="rapport-semaine-21.html" class="rapport-card">
<div class="rapport-semaine">Semaine 21</div>
<div class="rapport-date">18-24 mai 2026</div>
<div class="rapport-desc">
Loi anti-fraude formation adoptée, non-renouvellement cyperméthrine, appels d'offres BOAMP, marché emploi dynamique (125+ postes).
</div>
<span class="rapport-btn">Consulter →</span>
</a>
<!-- Semaine 20 -->
<a href="rapport-semaine-20.html" class="rapport-card">
<div class="rapport-semaine">Semaine 20</div>
<div class="rapport-date">11-17 mai 2026</div>
<div class="rapport-desc">
Actualisation réglementaire, marché formation, surveillance nuisibles invasifs, opportunités secteur 3D, et tendances innovation.
</div>
<span class="rapport-btn">Consulter →</span>
</a>
</div>
</section>
<!-- EXPLICATION RUBRIQUES -->
<section class="section">
<h2>🎯 8 Rubriques Thématiques Couvertes</h2>
<p style="color: var(--text-muted); margin-bottom: 1.5rem;">Chaque rapport synthétise l'actualité sur ces 8 axes clés du secteur Certibiocide.</p>
<div class="rubriques-grid">
<!-- Réglementaire -->
<div class="rubrique-card">
<div class="rubrique-icon">⚖️</div>
<div class="rubrique-title">Réglementaire</div>
<div class="rubrique-desc">AMM, retraits, BPR, obligations Certibiocide, directives ECHA, évolutions légales France et Europe.</div>
</div>
<!-- Marché Formation -->
<div class="rubrique-card">
<div class="rubrique-icon">🎓</div>
<div class="rubrique-title">Marché Formation</div>
<div class="rubrique-desc">Qualiopi, CPF, OPCO, chiffres clés du marché formation, financements, réglementations des organismes.</div>
</div>
<!-- Nuisibles & ESOD -->
<div class="rubrique-card">
<div class="rubrique-icon">🐀</div>
<div class="rubrique-title">Nuisibles & ESOD</div>
<div class="rubrique-desc">Moustique tigre, frelon asiatique, rongeurs résistants, punaises de lit, espèces invasives, surveillance.</div>
</div>
<!-- Désinfection -->
<div class="rubrique-card">
<div class="rubrique-icon">🧴</div>
<div class="rubrique-title">Désinfection</div>
<div class="rubrique-desc">Normes AFNOR, produits homologués, protocoles de désinfection, alternatives aux biocides chimiques.</div>
</div>
<!-- Opportunités -->
<div class="rubrique-card">
<div class="rubrique-icon">💡</div>
<div class="rubrique-title">Opportunités</div>
<div class="rubrique-desc">Appels d'offres BOAMP, marchés publics 3D, CPF, secteurs demandeurs, niches commerciales.</div>
</div>
<!-- Innovation -->
<div class="rubrique-card">
<div class="rubrique-icon">🔬</div>
<div class="rubrique-title">Innovation</div>
<div class="rubrique-desc">Bioinsecticides, IoT, IA, brevets, lutte biologique, solutions connectées, tendances technologiques.</div>
</div>
<!-- Veille Européenne -->
<div class="rubrique-card">
<div class="rubrique-icon">🇪🇺</div>
<div class="rubrique-title">Veille Européenne</div>
<div class="rubrique-desc">Révision BPR, EFSA, OMS, résistances insecticides, harmonisation EU, benchmarking international.</div>
</div>
<!-- RH & Concurrence -->
<div class="rubrique-card">
<div class="rubrique-icon">👥</div>
<div class="rubrique-title">RH & Concurrence</div>
<div class="rubrique-desc">Offres d'emploi 3D, mouvements du secteur, certifications RNCP, tendances RH, analyses concurrentielles.</div>
</div>
</div>
</section>
<!-- COMMENT UTILISER -->
<section class="section">
<h2>📖 Comment Utiliser Cette Veille</h2>
<div style="background: var(--blue-light); border-left: 4px solid var(--blue); border-radius: 8px; padding: 1.5rem; margin: 1.5rem 0;">
<h3 style="margin-top: 0; color: var(--blue);">Pour Formateurs Indépendants</h3>
<p style="margin-bottom: 0.75rem;"><strong>Mettre à jour vos supports :</strong> Les rapports signalent les changements réglementaires (ex: non-renouvellement cyperméthrine) qui doivent être intégrés dans vos formations Certibiocide.</p>
<p style="margin-bottom: 0.75rem;"><strong>Identifier les opportunités commerciales :</strong> Les appels d'offres BOAMP et marchés publics 3D génèrent des besoins en formation.</p>
<p style="margin-bottom: 0.75rem;"><strong>Anticiper les tendances marché :</strong> Comprenez les évolutions de l'emploi 3D, les niches en croissance (innovation, bioinsecticides) et adaptez vos offres.</p>
<p style="margin-bottom: 0;"><strong>Enrichir vos cas d'étude :</strong> Les actualités réglementaires et sectorielles fournissent des matériaux pédagogiques pertinents et actualisés.</p>
</div>
<div style="background: var(--green-light); border-left: 4px solid var(--green); border-radius: 8px; padding: 1.5rem; margin: 1.5rem 0;">
<h3 style="margin-top: 0; color: var(--green);">Pour Professionnels 3D</h3>
<p style="margin-bottom: 0.75rem;"><strong>Rester à jour réglementairement :</strong> Connaissance des changements d'AMM, substances actives interdites, nouvelles obligations de formation.</p>
<p style="margin-bottom: 0.75rem;"><strong>Adapter votre stratégie commerciale :</strong> Identifier les appels d'offres, les nouveaux secteurs demandeurs, les marchés publics.</p>
<p style="margin-bottom: 0.75rem;"><strong>Suivre l'innovation :</strong> Découvrir les nouvelles solutions (IoT, IA, lutte biologique) pour différencier votre offre.</p>
<p style="margin-bottom: 0;"><strong>Planifier vos recrutements :</strong> Anticiper les besoins en certifications, formations, et compétences spécialisées.</p>
</div>
</section>
<!-- FRÉQUENCE & SOURCES -->
<section class="section">
<h2>📅 Fréquence & Sources</h2>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem;">
<div style="background: var(--white); border: 1px solid var(--border); border-radius: 8px; padding: 1.5rem;">
<h3 style="margin-top: 0;">Mise à Jour Hebdomadaire</h3>
<p style="margin: 0; color: var(--text-muted); font-size: 0.9rem;">Chaque semaine, une nouvelle synthèse de 8 rubriques est générée, couvrant les 7 jours précédents. Les archives complètes restent accessibles pour historique et recherche.</p>
</div>
<div style="background: var(--white); border: 1px solid var(--border); border-radius: 8px; padding: 1.5rem;">
<h3 style="margin-top: 0;">Sources Officielles</h3>
<p style="margin: 0; color: var(--text-muted); font-size: 0.9rem;">ANSES, ECHA, Légifrance, France Compétences, INRAE, Santé Publique France, Commission Européenne, presse professionnelle certifiée.</p>
</div>
</div>
</section>
</main>
<!-- FOOTER -->
<footer>
<p>&copy; 2024 NextGN Formation - Index Veille Certibiocide</p>
<p>Tous droits réservés - Formateur indépendant spécialisé en Certibiocide et formations techniques</p>
</footer>
<!-- PROGRESS BAR SCRIPT -->
<script>
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
const scrollPercent = (scrollTop / docHeight) * 100;
document.getElementById('progressBar').style.width = scrollPercent + '%';
});
</script>
</body>
</html>

View File

@@ -353,7 +353,7 @@
<!-- HEADER -->
<header>
<div class="logo">NextGN Formation</div>
<div class="logo">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="../../index.html">Exercices interactifs</a>
<a href="../../index.html#documentation">Documentation</a>
@@ -503,7 +503,7 @@
<!-- FOOTER -->
<footer>
<p>&copy; 2026 NextGN Formation - Formations Certibiocide & Techniques</p>
<p>&copy; 2026 Gauthier Chombart & Nathan Chauwin<br>Tous droits réservés — Formations Certibiocide & Techniques — Formateurs indépendants</p>
<p style="margin-top: 10px; opacity: 0.6;">Tous droits réservés — Gauthier Chombart & Nathan Chauwin — Formateurs indépendants</p>
</footer>

View File

@@ -1,256 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Veille Hygiène & Pest Control</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
padding: 40px;
}
.header {
margin-bottom: 40px;
border-bottom: 3px solid #2c3e50;
padding-bottom: 20px;
}
.header h1 {
font-size: 32px;
color: #2c3e50;
margin-bottom: 8px;
}
.header p {
color: #7f8c8d;
font-size: 14px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
margin-bottom: 30px;
}
.card {
background: #f8f9fa;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 24px;
transition: all 0.3s ease;
}
.card:hover {
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
transform: translateY(-2px);
border-color: #3498db;
}
.card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.card-icon {
font-size: 28px;
}
.card h3 {
font-size: 16px;
color: #2c3e50;
font-weight: 600;
}
.card ul {
list-style: none;
padding: 0;
}
.card li {
margin-bottom: 12px;
font-size: 13px;
color: #555;
line-height: 1.6;
padding-left: 0;
}
.card strong {
color: #2c3e50;
display: block;
margin-bottom: 2px;
}
.footer {
background: #ecf0f1;
border-radius: 8px;
padding: 16px;
margin-bottom: 24px;
}
.footer p {
font-size: 12px;
color: #7f8c8d;
margin: 0;
}
.footer strong {
color: #2c3e50;
}
.buttons {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
button {
padding: 10px 16px;
border: 1px solid #bdc3c7;
background: white;
border-radius: 6px;
font-size: 13px;
color: #2c3e50;
cursor: pointer;
transition: all 0.2s ease;
}
button:hover {
border-color: #3498db;
background: #ecf4f9;
color: #2980b9;
}
.date {
font-size: 12px;
color: #95a5a6;
margin-top: 20px;
text-align: center;
padding-top: 20px;
border-top: 1px solid #ecf0f1;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>📊 Veille Hygiène & Pest Control</h1>
<p>Semaine du 14-20 avril 2026</p>
</div>
<div class="grid">
<!-- REGLEMENTATION -->
<div class="card">
<div class="card-header">
<span class="card-icon">⚖️</span>
<h3>Réglementation</h3>
</div>
<ul>
<li><strong>ANSES :</strong> Mise à jour des listes de substances autorisées Certibiocide</li>
<li><strong>JO :</strong> Nouvelles exigences d'étiquetage pour les biocides (avril 2026)</li>
<li><strong>UE :</strong> Révision des critères d'évaluation toxicologique</li>
</ul>
</div>
<!-- INNOVATIONS -->
<div class="card">
<div class="card-header">
<span class="card-icon">💡</span>
<h3>Innovations</h3>
</div>
<ul>
<li><strong>Biotech :</strong> Nouvelles enzymes pour désinsectisation éco-responsable</li>
<li><strong>IoT :</strong> Monitoring en temps réel des nuisibles (startup française)</li>
<li><strong>Chimie verte :</strong> Fongicides à base d'huiles essentielles certifiés</li>
</ul>
</div>
<!-- MARCHE -->
<div class="card">
<div class="card-header">
<span class="card-icon">📈</span>
<h3>Marché</h3>
</div>
<ul>
<li><strong>Trends :</strong> +15% demande biocides dans secteur agroalimentaire</li>
<li><strong>Concurrence :</strong> Rachat de 2 PME par groupe allemand</li>
<li><strong>Recrutement :</strong> Formation Certibiocide en hausse (+35%)</li>
</ul>
</div>
<!-- RECHERCHE -->
<div class="card">
<div class="card-header">
<span class="card-icon">🔬</span>
<h3>Recherche scientifique</h3>
</div>
<ul>
<li><strong>Résistance :</strong> Étude INRAE sur résistance aux pyréthrines</li>
<li><strong>Santé :</strong> Nouvel article PubMed sur impact santé-environnement</li>
<li><strong>Méthodes :</strong> Protocoles d'évaluation de l'efficacité (ECHA)</li>
</ul>
</div>
<!-- FORMATION -->
<div class="card">
<div class="card-header">
<span class="card-icon">🎓</span>
<h3>Formations & Agréments</h3>
</div>
<ul>
<li><strong>Nouveaux agréés :</strong> 8 organismes cette semaine</li>
<li><strong>Tendance pédago :</strong> Hybrid e-learning davantage demandé</li>
<li><strong>Métier :</strong> Fiche de poste "Technicien Certibiocide" (2026)</li>
</ul>
</div>
<!-- ALERTE -->
<div class="card">
<div class="card-header">
<span class="card-icon">⚠️</span>
<h3>Alertes & Incidents</h3>
</div>
<ul>
<li><strong>Rappel :</strong> Substance X interdite dans l'UE (en vigueur mai)</li>
<li><strong>Incident :</strong> Contamination dans le secteur laitier (source maîtrisée)</li>
<li><strong>Certificat :</strong> Perte d'agrément d'1 organisme (non-conformité)</li>
</ul>
</div>
</div>
<div class="footer">
<p><strong>Sources :</strong> ANSES, JO (JORF), publications PubMed, LinkedIn professionnel, communiqués organismes, études INRAE, ECHA, Ministère Écologie</p>
</div>
<div class="buttons">
<button onclick="alert('Fonctionnalité : Détails réglementation ANSES')">📄 En savoir plus</button>
<button onclick="alert('Fonctionnalité : Détails des nouveaux agréments')">🔍 Agréments détail</button>
<button onclick="alert('Fonctionnalité : Innovations intéressantes')">💡 Innovations</button>
</div>
<div class="date">
Veille mise à jour le 14 avril 2026
</div>
</div>
</body>
</html>