Files
Site_web/exercices/TP_Nuisibles.html
gauthier.chombart 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

1628 lines
63 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TP Nuisibles final — Étude de cas</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">
<link rel="stylesheet" href="../header-style.css"/>
<style>
/* SLIDES */
.slide {
position: absolute;
inset: 0;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
padding-top: calc(70px + 2rem);
padding-bottom: calc(52px + 2rem);
opacity: 0;
transition: opacity 0.4s ease;
overflow-y: auto;
min-height: calc(100vh - 70px);
}
.slide.active {
display: flex;
opacity: 1;
}
.slide.fade-in { animation: fadeIn 0.5s ease forwards; }
@keyframes fadeIn {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
.progress-fill {
background: var(--coral-mid);
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;
background: rgba(250, 238, 218, 0.98);
border-top: 2px solid var(--amber);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
z-index: 100;
backdrop-filter: blur(10px);
}
/* SLIDE NAV */
.slide-counter {
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;
}
.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;
}
.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; }
/* CARDS & BUTTONS */
.btn {
font-family: 'Syne', sans-serif;
font-size: 14px;
font-weight: 600;
padding: 12px 28px;
border-radius: 40px;
border: none;
cursor: pointer;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: scale(0.98); }
.btn-teal { background: var(--amber); color: white; }
.btn-amber { background: var(--amber); color: white; }
.btn-coral { background: var(--coral-mid); color: white; }
.btn-purple { background: var(--amber); color: white; }
.btn-blue { background: var(--amber); color: white; }
.btn-outline {
background: transparent;
border: 1.5px solid currentColor;
}
/* HINT BUTTON */
.hint-btn {
font-family: 'DM Sans', sans-serif;
font-size: 13px;
background: var(--amber-light);
color: var(--amber-dark);
border: 1px solid rgba(186,117,23,0.2);
border-radius: 20px;
padding: 6px 16px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.2s;
}
.hint-btn:hover { background: #F5DFB8; }
/* CASE CARDS */
.case-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12px;
width: 100%;
max-width: 860px;
}
.case-card {
background: white;
border: 1.5px solid var(--border);
border-radius: 16px;
padding: 1.25rem 0.75rem;
text-align: center;
cursor: pointer;
transition: all 0.25s;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.case-card:hover {
border-color: var(--amber);
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(29,158,117,0.15);
}
.case-card.selected {
border-color: var(--amber);
background: var(--amber-light);
}
.case-icon { font-size: 32px; }
.case-title {
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
color: var(--text);
line-height: 1.3;
}
.case-sub { font-size: 11px; color: var(--text-muted); }
/* QUESTIONS */
.questions-list {
list-style: none;
width: 100%;
max-width: 680px;
display: flex;
flex-direction: column;
gap: 10px;
}
.q-item {
background: white;
border: 0.5px solid var(--border);
border-radius: 12px;
padding: 14px 18px;
font-size: 14px;
line-height: 1.5;
display: flex;
align-items: flex-start;
gap: 12px;
}
.q-num {
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 800;
min-width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 1px;
}
/* ANSWER FIELDS */
.answer-field {
width: 100%;
margin-top: 8px;
font-family: 'DM Sans', sans-serif;
font-size: 13.5px;
color: var(--text);
background: var(--bg);
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px 14px;
resize: vertical;
min-height: 64px;
line-height: 1.5;
transition: border-color 0.2s, background 0.2s;
}
.answer-field:focus {
outline: none;
border-color: var(--amber);
background: white;
}
.q-item { flex-direction: column; align-items: stretch; }
.q-item .q-head { display: flex; align-items: flex-start; gap: 12px; }
/* IDENTIFICATION SCREEN */
.id-form {
width: 100%;
max-width: 420px;
display: flex;
flex-direction: column;
gap: 14px;
margin: 1.25rem 0;
}
.id-field label {
display: block;
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 6px;
text-align: left;
}
.id-field input {
width: 100%;
font-family: 'DM Sans', sans-serif;
font-size: 15px;
padding: 12px 16px;
border: 1.5px solid var(--border);
border-radius: 10px;
background: white;
color: var(--text);
}
.id-field input:focus {
outline: none;
border-color: var(--amber);
}
/* Carte d'identité encadrée (modèle BioCID) */
.id-card {
background: white;
border: 0.5px solid var(--border);
border-radius: 16px;
padding: 20px 22px;
max-width: 460px;
width: 100%;
margin: 1.25rem auto;
box-shadow: 0 8px 30px rgba(0,0,0,0.04);
}
.id-card .id-form { margin: 0; max-width: none; }
/* TABLE FORM CONTROLS */
.risk-table input, .risk-table textarea {
width: 100%;
font-family: 'DM Sans', sans-serif;
font-size: 13px;
color: var(--text);
background: transparent;
border: none;
border-bottom: 1px dashed var(--border);
padding: 4px 2px;
font-style: normal;
}
.risk-table input:focus, .risk-table textarea:focus {
outline: none;
border-bottom-color: var(--amber);
background: var(--amber-light);
}
.risk-table textarea { resize: vertical; min-height: 40px; }
.risk-cell {
border: none !important;
background: transparent;
width: 100%;
font-family: 'DM Sans', sans-serif;
font-size: 13px;
color: var(--text);
resize: vertical;
min-height: 36px;
padding: 4px 2px;
}
.risk-cell:focus { outline: none; background: var(--amber-light); }
.risk-cell::placeholder { color: var(--text-muted); font-style: italic; }
.add-row-btn {
font-family: 'Syne', sans-serif;
font-size: 12px;
font-weight: 700;
color: var(--amber-dark);
background: var(--amber-light);
border: 1px dashed var(--amber);
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
margin-top: 10px;
}
.add-row-btn:hover { background: #F5DFB8; }
/* SUBMIT / STATUS */
.submit-zone {
width: 100%;
max-width: 680px;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
margin-top: 1.5rem;
}
.submit-status {
font-family: 'DM Sans', sans-serif;
font-size: 13px;
padding: 10px 18px;
border-radius: 10px;
display: none;
}
.submit-status.show { display: block; }
.submit-status.loading { background: var(--blue-light); color: var(--blue); }
.submit-status.success { background: var(--teal-light); color: var(--teal-dark); }
.submit-status.error { background: var(--coral-light); color: var(--coral); }
.btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }
.btn-outline.btn-teal { color: var(--amber-dark); border-color: var(--amber); }
/* TABLE */
.risk-table {
width: 100%;
max-width: 800px;
border-collapse: collapse;
background: white;
border-radius: 12px;
overflow: hidden;
border: 0.5px solid var(--border);
font-size: 13px;
}
.risk-table th {
background: var(--amber-light);
color: var(--amber);
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
padding: 12px 16px;
text-align: left;
border-bottom: 2px solid var(--amber);
}
.risk-table td {
padding: 10px 16px;
border-bottom: 0.5px solid var(--border);
color: var(--text-muted);
font-style: italic;
}
.risk-table tr:last-child td { border-bottom: none; }
.risk-table .meta-row td {
background: #FAFAFA;
font-style: normal;
font-size: 12px;
}
.risk-table .meta-label {
font-family: 'Syne', sans-serif;
font-weight: 700;
font-size: 11px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.04em;
}
/* MODAL OVERLAY */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.45);
display: none;
align-items: center;
justify-content: center;
z-index: 200;
padding: 2rem;
}
.modal-overlay.open { display: flex; }
.modal {
background: white;
border-radius: 20px;
padding: 2rem;
max-width: 480px;
width: 100%;
position: relative;
animation: modalIn 0.3s ease;
}
@keyframes modalIn {
from { opacity: 0; transform: scale(0.92) translateY(12px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
.modal-close {
position: absolute;
top: 16px; right: 16px;
background: var(--bg);
border: none;
width: 28px; height: 28px;
border-radius: 50%;
cursor: pointer;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-muted);
}
.modal-icon { font-size: 28px; margin-bottom: 12px; }
.modal-title {
font-family: 'Syne', sans-serif;
font-size: 16px;
font-weight: 700;
margin-bottom: 10px;
}
.modal-body { font-size: 14px; line-height: 1.7; color: var(--text-muted); }
.modal-body strong { color: var(--text); }
/* SLIDE SPECIFIC */
.hero-label {
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--amber);
margin-bottom: 8px;
}
.hero-title {
font-family: 'Syne', sans-serif;
font-size: clamp(36px, 6vw, 68px);
font-weight: 800;
line-height: 1.0;
color: var(--text);
margin-bottom: 12px;
}
.hero-sub {
font-size: 16px;
color: var(--text-muted);
max-width: 440px;
text-align: center;
line-height: 1.6;
margin-bottom: 2rem;
}
.section-tag {
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 4px 12px;
border-radius: 20px;
margin-bottom: 10px;
display: inline-block;
}
.slide-title {
font-family: 'Syne', sans-serif;
font-size: clamp(22px, 3.5vw, 34px);
font-weight: 800;
line-height: 1.15;
margin-bottom: 0.5rem;
text-align: center;
}
.slide-intro {
font-size: 14px;
color: var(--text-muted);
text-align: center;
max-width: 560px;
line-height: 1.6;
margin-bottom: 1.5rem;
}
.steps-row {
display: flex;
gap: 8px;
margin-bottom: 1.5rem;
flex-wrap: wrap;
justify-content: center;
}
.step-pill {
font-size: 12px;
padding: 4px 14px;
border-radius: 20px;
border: 1px solid var(--border);
color: var(--text-muted);
background: white;
}
.step-pill.active-pill {
border-color: currentColor;
font-weight: 500;
}
.actions-row {
display: flex;
gap: 12px;
align-items: center;
margin-top: 1.5rem;
flex-wrap: wrap;
justify-content: center;
}
/* CASE SELECTED BANNER */
.case-banner {
display: none;
background: var(--amber-light);
border: 1px solid rgba(29,158,117,0.25);
border-radius: 12px;
padding: 10px 18px;
font-size: 13px;
color: var(--amber-dark);
margin-bottom: 1rem;
align-items: center;
gap: 8px;
max-width: 680px;
width: 100%;
}
.case-banner.visible { display: flex; }
.case-banner strong { font-family: 'Syne', sans-serif; font-weight: 700; }
/* RESOURCE CARD */
.resource-card {
background: white;
border: 0.5px solid var(--border);
border-radius: 12px;
padding: 14px 18px;
max-width: 680px;
width: 100%;
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 1rem;
}
.resource-icon { font-size: 24px; }
.resource-body { flex: 1; }
.resource-title { font-size: 13px; font-weight: 500; }
.resource-sub { font-size: 12px; color: var(--text-muted); }
.resource-link {
font-size: 12px;
color: var(--amber);
text-decoration: none;
font-weight: 500;
}
.resource-link:hover { text-decoration: underline; }
/* FINAL */
.final-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
max-width: 640px;
width: 100%;
margin: 1.5rem 0;
}
.final-card {
background: white;
border: 0.5px solid var(--border);
border-radius: 14px;
padding: 1.25rem;
text-align: center;
}
.final-card-icon { font-size: 28px; margin-bottom: 8px; }
.final-card-title { font-family: 'Syne', sans-serif; font-size: 12px; font-weight: 700; }
.final-card-sub { font-size: 11px; color: var(--text-muted); margin-top: 4px; }
/* PYRAMID */
.pyramid { display: flex; flex-direction: column; align-items: center; gap: 3px; margin: 1rem 0; }
.pyr-level {
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
font-family: 'Syne', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: white;
height: 28px;
}
/* SCROLLABLE AREA */
.scroll-area {
overflow-y: auto;
max-height: calc(100vh - 232px);
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding: 0.5rem 0 4rem;
}
.scroll-area::-webkit-scrollbar { width: 4px; }
.scroll-area::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
/* DECORATIVE BG */
.deco-circle {
position: fixed;
border-radius: 50%;
pointer-events: none;
z-index: 0;
}
.slide > * { position: relative; z-index: 1; }
</style>
</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">Gauthier Chombart & Nathan Chauwin</div>
<nav>
<a href="../index.html">Accueil</a>
<a href="../index.html#formations">Exercices</a>
<a href="../index.html#documentation">Documentation</a>
<a href="../index.html#rapports">Rapports</a>
<a href="../index.html#about">À propos</a>
<a href="../index.html#contact">Contact</a>
</nav>
</header>
<!-- 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>
<!-- Modal overlay -->
<div class="modal-overlay" id="modalOverlay" onclick="closeModal(event)">
<div class="modal" id="modal">
<button class="modal-close" onclick="closeModal()"></button>
<div class="modal-icon" id="modalIcon"></div>
<div class="modal-title" id="modalTitle"></div>
<div class="modal-body" id="modalBody"></div>
</div>
</div>
<!-- ======================== SLIDE 0 — IDENTIFICATION ======================== -->
<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-card">
<div class="id-form">
<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>
<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>
<div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap;">
<button class="btn btn-teal" onclick="confirmIdentite()">Continuer →</button>
<a href="corriger-exercice.html?exo=tp" class="btn btn-outline btn-teal">Corriger</a>
</div>
</div>
</div>
<!-- ======================== SLIDE 1 — ACCUEIL ======================== -->
<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</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>
</div>
<!-- ======================== SLIDE 2 — CHOIX DU CAS ======================== -->
<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>
<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="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>
<div class="case-title">Punaises de lit</div>
<div class="case-sub">Hôtel</div>
</div>
<div class="case-card" onclick="selectCase('frelons','🐝','Apiculture — Frelons','Nid de frelons à 15m de hauteur')">
<div class="case-icon">🐝</div>
<div class="case-title">Frelons</div>
<div class="case-sub">Apiculteur</div>
</div>
<div class="case-card" onclick="selectCase('mites','🌾','Boulangerie — Mites alimentaires','Infestation dans l\'atelier de production')">
<div class="case-icon">🌾</div>
<div class="case-title">Mites alimentaires</div>
<div class="case-sub">Boulangerie</div>
</div>
<div class="case-card" onclick="selectCase('rongeurs','🐀','Agroalimentaire — Rongeurs','Plan anti-nuisibles complet')">
<div class="case-icon">🐀</div>
<div class="case-title">Rongeurs</div>
<div class="case-sub">Société agro</div>
</div>
<div class="case-card" onclick="selectCase('moustiques','🦟','Camping — Moustiques','Restaurant près de la piscine')">
<div class="case-icon">🦟</div>
<div class="case-title">Moustiques</div>
<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 ======================== -->
<div class="slide" id="slide-3">
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">Consignes</div>
<div class="slide-title">Déroulé des travaux pratiques</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:14px;max-width:660px;width:100%;margin:1.5rem 0;">
<div style="background:white;border:0.5px solid var(--border);border-radius:14px;padding:1.25rem;text-align:center;">
<div style="font-size:28px;margin-bottom:8px;">🗂️</div>
<div style="font-family:'Syne',sans-serif;font-size:13px;font-weight:700;margin-bottom:4px;">TP 1</div>
<div style="font-size:12px;color:var(--text-muted);">Définir un protocole d'intervention</div>
</div>
<div style="background:white;border:0.5px solid var(--border);border-radius:14px;padding:1.25rem;text-align:center;">
<div style="font-size:28px;margin-bottom:8px;">🔍</div>
<div style="font-family:'Syne',sans-serif;font-size:13px;font-weight:700;margin-bottom:4px;">TP 2</div>
<div style="font-size:12px;color:var(--text-muted);">Trouver votre produit sur biocid-anses.fr</div>
</div>
<div style="background:white;border:0.5px solid var(--border);border-radius:14px;padding:1.25rem;text-align:center;">
<div style="font-size:28px;margin-bottom:8px;">⚠️</div>
<div style="font-family:'Syne',sans-serif;font-size:13px;font-weight:700;margin-bottom:4px;">TP 3</div>
<div style="font-size:12px;color:var(--text-muted);">Réaliser l'analyse de risques complète</div>
</div>
</div>
<div style="background:var(--amber-light);border-radius:12px;padding:12px 18px;max-width:560px;width:100%;font-size:13px;color:var(--amber-dark);display:flex;gap:10px;align-items:flex-start;margin-bottom:1.5rem;">
<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 ======================== -->
<div class="slide" id="slide-4">
<div class="deco-circle" style="width:280px;height:280px;background:var(--amber-light);top:-40px;right:-40px;opacity:0.5;"></div>
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">TP 1 — Définir un protocole</div>
<div class="slide-title">Votre cas pratique</div>
<div class="case-banner visible" id="caseBanner4" style="margin-top:0.75rem;">
<span id="caseIcon4">🛏️</span>
<div><strong id="caseTitle4">Cas sélectionné</strong><span id="caseDesc4">Description</span></div>
</div>
<p class="slide-intro" style="margin-top:0.5rem;">Vous recevez un appel de votre client. Il vous décrit la situation et attend votre expertise. Organisez votre réponse en 3 étapes : prévention, intervention, évaluation.</p>
<div class="steps-row">
<div class="step-pill" style="color:var(--amber);border-color:var(--amber);">1. Prévention & conseil</div>
<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 ======================== -->
<div class="slide" id="slide-5">
<div class="scroll-area">
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">TP 1 — Étape 1 / 3</div>
<div class="slide-title">Prévention & conseil</div>
<div class="case-banner" id="caseBanner5">
<span id="caseIcon5">🛏️</span><strong id="caseTitle5">Cas</strong>
</div>
<ul class="questions-list">
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">1</span>
<span>Quelles questions posez-vous au client lors du premier contact ?</span>
</div>
<textarea class="answer-field" id="ans_prevention_1" placeholder="Votre réponse…" data-question="Questions posées au client lors du premier contact"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">2</span>
<span>Quels conseils lui donnez-vous en premier lieu ?</span>
</div>
<textarea class="answer-field" id="ans_prevention_2" placeholder="Votre réponse…" data-question="Conseils donnés en premier lieu"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">3</span>
<span>Quelles actions de prévention allez-vous mener sur le site ?</span>
</div>
<textarea class="answer-field" id="ans_prevention_3" placeholder="Votre réponse…" data-question="Actions de prévention menées sur le site"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">4</span>
<span>Quels éléments allez-vous observer ? Comment prouver la présence du nuisible ?</span>
</div>
<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>
<!-- ======================== SLIDE 6 — TP1 INTERVENTION ======================== -->
<div class="slide" id="slide-6">
<div class="scroll-area">
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">TP 1 — Étape 2 / 3</div>
<div class="slide-title">Intervention</div>
<div class="case-banner" id="caseBanner6">
<span id="caseIcon6">🛏️</span><strong id="caseTitle6">Cas</strong>
</div>
<ul class="questions-list">
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">1</span>
<span>Quelles solutions alternatives (non-biocides) pouvez-vous mettre en place ?</span>
</div>
<textarea class="answer-field" id="ans_intervention_1" placeholder="Votre réponse…" data-question="Solutions alternatives non-biocides"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">2</span>
<span>Quelles solutions biocides allez-vous mettre en place ?</span>
</div>
<textarea class="answer-field" id="ans_intervention_2" placeholder="Votre réponse…" data-question="Solutions biocides mises en place"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">3</span>
<span>Quel est le type de produit (TP) adapté ? Avec quel mode de traitement ?</span>
</div>
<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>
<!-- ======================== SLIDE 7 — TP1 EVALUATION ======================== -->
<div class="slide" id="slide-7">
<div class="scroll-area">
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">TP 1 — Étape 3 / 3</div>
<div class="slide-title">Évaluation & suivi</div>
<div class="case-banner" id="caseBanner7">
<span id="caseIcon7">🛏️</span><strong id="caseTitle7">Cas</strong>
</div>
<ul class="questions-list">
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">1</span>
<span>Quel suivi allez-vous mettre en place ? Pendant combien de temps ?</span>
</div>
<textarea class="answer-field" id="ans_evaluation_1" placeholder="Votre réponse…" data-question="Suivi mis en place et durée"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--amber-light);color:var(--amber-dark);">2</span>
<span>Comment allez-vous gérer les déchets issus de votre intervention ?</span>
</div>
<textarea class="answer-field" id="ans_evaluation_2" placeholder="Votre réponse…" data-question="Gestion des déchets"></textarea>
</li>
</ul>
<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>
<!-- ======================== SLIDE 8 — TP2 INTRO ======================== -->
<div class="slide" id="slide-8">
<div class="deco-circle" style="width:280px;height:280px;background:var(--coral-light);top:-40px;left:-40px;opacity:0.5;"></div>
<div class="section-tag" style="background:var(--coral-light);color:var(--coral);">TP 2 — Trouver le produit</div>
<div class="slide-title">Enquête produit</div>
<div class="case-banner visible" id="caseBanner8">
<span id="caseIcon8">🛏️</span>
<div><strong id="caseTitle8">Cas sélectionné</strong></div>
</div>
<p class="slide-intro">Rendez-vous sur le registre officiel des biocides. Utilisez la <strong>recherche avancée</strong> en filtrant par substance active et nuisible dans l'usage.</p>
<div class="resource-card">
<div class="resource-icon">🌐</div>
<div class="resource-body">
<div class="resource-title">Registre officiel des biocides</div>
<div class="resource-sub">Recherche avancée → Substance / Nuisible dans Usage</div>
</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 ======================== -->
<div class="slide" id="slide-9">
<div class="scroll-area">
<div class="section-tag" style="background:var(--coral-light);color:var(--coral);">TP 2 — Partie 1 / 2</div>
<div class="slide-title">Fiche de données de sécurité</div>
<div class="case-banner" id="caseBanner9">
<span id="caseIcon9">🛏️</span><strong id="caseTitle9">Cas</strong>
</div>
<ul class="questions-list">
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">1</span>
<span>Trouvez et téléchargez la <strong>Fiche de Données de Sécurité (FDS)</strong> de votre produit.</span>
</div>
<textarea class="answer-field" id="ans_fds_1" placeholder="Notez ici les éléments principaux de la FDS…" data-question="FDS trouvée (éléments principaux)"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">2</span>
<span>Quel est le <strong>nom du produit</strong> et de son fabricant / fournisseur ?</span>
</div>
<textarea class="answer-field" id="ans_fds_2" placeholder="Votre réponse…" data-question="Nom du produit et fabricant/fournisseur"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">3</span>
<span>Quel est son <strong>numéro d'Autorisation de Mise sur le Marché (AMM)</strong> ?</span>
</div>
<textarea class="answer-field" id="ans_fds_3" placeholder="Votre réponse…" data-question="Numéro AMM"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">4</span>
<span>Quels sont les <strong>risques pour la santé</strong> liés à ce produit ?</span>
</div>
<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>
<!-- ======================== SLIDE 10 — TP2 EPI & SECOURS ======================== -->
<div class="slide" id="slide-10">
<div class="scroll-area">
<div class="section-tag" style="background:var(--coral-light);color:var(--coral);">TP 2 — Partie 2 / 2</div>
<div class="slide-title">EPI, environnement & premiers secours</div>
<div class="case-banner" id="caseBanner10">
<span id="caseIcon10">🛏️</span><strong id="caseTitle10">Cas</strong>
</div>
<ul class="questions-list">
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">5</span>
<span>Quels <strong>équipements de protection individuelle (EPI)</strong> dois-je porter lors de la manipulation ?</span>
</div>
<textarea class="answer-field" id="ans_epi_1" placeholder="Votre réponse…" data-question="EPI à porter"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">6</span>
<span>Quels sont les <strong>risques pour l'environnement</strong> ? Que faire en cas de dispersion accidentelle ?</span>
</div>
<textarea class="answer-field" id="ans_epi_2" placeholder="Votre réponse…" data-question="Risques environnement / dispersion accidentelle"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">7</span>
<span>Quelle est la <strong>DL50</strong> de la (ou des) substance(s) active(s) ?</span>
</div>
<textarea class="answer-field" id="ans_epi_3" placeholder="Votre réponse…" data-question="DL50 substance(s) active(s)"></textarea>
</li>
<li class="q-item">
<div class="q-head">
<span class="q-num" style="background:var(--coral-light);color:var(--coral);">8</span>
<span>Quels <strong>gestes de premiers secours</strong> adopter en cas d'exposition ?</span>
</div>
<textarea class="answer-field" id="ans_epi_4" placeholder="Votre réponse…" data-question="Gestes de premiers secours"></textarea>
</li>
</ul>
<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>
<!-- ======================== SLIDE 11 — TP3 INTRO ======================== -->
<div class="slide" id="slide-11">
<div class="deco-circle" style="width:260px;height:260px;background:var(--amber-light);bottom:-40px;right:-40px;opacity:0.5;"></div>
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">TP 3 — Analyse de risques</div>
<div class="slide-title">Protégez votre équipe</div>
<p class="slide-intro">Avant toute intervention, vous devez rédiger l'analyse de risques. Rappel de la hiérarchie de prévention :</p>
<div class="pyramid">
<div class="pyr-level" style="width:200px;background:#633806;">Élimination</div>
<div class="pyr-level" style="width:240px;background:#BA7517;">Réduction</div>
<div class="pyr-level" style="width:280px;background:#BA7517;">Protection collective</div>
<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 ======================== -->
<div class="slide" id="slide-12">
<div class="scroll-area">
<div class="section-tag" style="background:var(--amber-light);color:var(--amber-dark);">TP 3 — Tableau d'analyse</div>
<div class="slide-title">Analyse de risques complète</div>
<div class="case-banner" id="caseBanner12">
<span id="caseIcon12">🛏️</span><strong id="caseTitle12">Cas</strong>
</div>
<table class="risk-table" style="max-width:780px;width:100%;" id="riskTable">
<tr class="meta-row">
<td style="width:200px;" class="meta-label">Intitulé du projet</td>
<td colspan="2"><input type="text" id="meta_intitule" placeholder="À compléter par votre groupe"></td>
</tr>
<tr class="meta-row">
<td class="meta-label">Description de l'activité</td>
<td colspan="2"><input type="text" id="meta_description" placeholder="À compléter"></td>
</tr>
<tr class="meta-row">
<td class="meta-label">Lieu de l'activité</td>
<td colspan="2"><input type="text" id="meta_lieu" placeholder="À compléter"></td>
</tr>
<tr class="meta-row">
<td class="meta-label">Début de l'activité prévu le</td>
<td colspan="2"><input type="date" id="meta_debut"></td>
</tr>
<tr class="meta-row">
<td class="meta-label">Numéro(s) d'urgence</td>
<td colspan="2" style="color:var(--text-muted);font-style:italic;">15 · 17 · 18 · 112</td>
</tr>
<tr>
<th>Étapes de l'activité</th>
<th>Risques</th>
<th>Mesures de prévention</th>
</tr>
<tbody id="riskTableBody">
<tr class="risk-row">
<td onclick="showHint('etape1')" style="cursor:pointer;"><textarea class="risk-cell" placeholder="Ex : Préparation du produit 💡"></textarea></td>
<td onclick="showHint('risque1')" style="cursor:pointer;"><textarea class="risk-cell" placeholder="Ex : Contact cutané 💡"></textarea></td>
<td onclick="showHint('mesure1')" style="cursor:pointer;"><textarea class="risk-cell" placeholder="Ex : Port de gants nitrile 💡"></textarea></td>
</tr>
<tr class="risk-row">
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
</tr>
<tr class="risk-row">
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
</tr>
</tbody>
<tr class="meta-row">
<td class="meta-label"><input type="text" id="meta_realisee_par" placeholder="Analyse réalisée par"></td>
<td class="meta-label"><input type="text" id="meta_verifiee_par" placeholder="Vérifiée par"></td>
<td class="meta-label"><input type="text" id="meta_maj_par" placeholder="Mise à jour par"></td>
</tr>
</table>
<div class="actions-row" style="margin-top:-6px;">
<button class="add-row-btn" onclick="addRiskRow()">+ Ajouter une ligne</button>
</div>
<div style="background:var(--amber-light);border-radius:10px;padding:10px 16px;max-width:780px;width:100%;font-size:12px;color:var(--amber-dark);margin:0.75rem 0;">
💡 Cliquez sur les cellules de la première ligne pour obtenir des indices. Reproduisez ce tableau sur papier pour votre groupe.
</div>
<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>
<!-- ======================== SLIDE 13 — FIN ======================== -->
<div class="slide" id="slide-13">
<div class="deco-circle" style="width:350px;height:350px;background:var(--amber-light);bottom:-80px;right:-80px;opacity:0.5;"></div>
<div class="deco-circle" style="width:180px;height:180px;background:var(--amber-light);top:20px;left:-40px;opacity:0.5;"></div>
<div style="text-align:center;">
<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. Le formateur va maintenant corriger à l'oral.</p>
<div class="final-grid">
<div class="final-card">
<div class="final-card-icon">🗂️</div>
<div class="final-card-title">TP 1</div>
<div class="final-card-sub">Protocole d'intervention</div>
</div>
<div class="final-card">
<div class="final-card-icon">🔍</div>
<div class="final-card-title">TP 2</div>
<div class="final-card-sub">Produit biocide</div>
</div>
<div class="final-card">
<div class="final-card-icon">⚠️</div>
<div class="final-card-title">TP 3</div>
<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>
<a href="corriger-exercice.html?exo=tp" class="btn btn-outline btn-teal">Corriger</a>
</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>
</div>
</div>
<script>
let currentSlide = 0;
let history = [];
const totalSlides = 13;
const selectedCase = { key: '', icon: '', title: '', desc: '' };
const stagiaire = { nom: '', date: '', formateur: '' };
const hints = {
prevention: {
icon: '💡',
title: 'Indice — Prévention & conseil',
body: `<strong>Questions à poser au client :</strong> ancienneté de l'infestation, surface concernée, présence de personnes vulnérables, traitements déjà réalisés.<br><br>
<strong>Prouver la présence :</strong> pièges collants, inspection visuelle, excréments, mues, morsures, témoignages.<br><br>
<strong>Prévention :</strong> information du client, mesures d'hygiène, inspection régulière.`
},
intervention: {
icon: '🛡️',
title: 'Indice — Types de produits (TP)',
body: `<strong>Principaux types biocides :</strong><br>
• <strong>TP 14</strong> — Rodenticides (rongeurs)<br>
• <strong>TP 18</strong> — Insecticides (insectes rampants, volants)<br>
• <strong>TP 19</strong> — Répulsifs & attractifs<br><br>
<strong>Solutions alternatives :</strong> pièges mécaniques, barrières physiques, thermique (vapeur, chaleur), modification de l'environnement.`
},
evaluation: {
icon: '📋',
title: 'Indice — Évaluation & déchets',
body: `<strong>Suivi :</strong> visites de contrôle à J+15, J+30 et J+60 minimum. Rapport de traitement obligatoire.<br><br>
<strong>Gestion des déchets :</strong> tri selon la réglementation DASRI si contact avec organismes vivants. Emballages vides → filière agréée. Ne jamais jeter dans les ordures ménagères.`
},
fds: {
icon: '🔍',
title: 'Indice — Trouver la FDS',
body: `Sur <strong>biocid-anses.fr</strong> :<br>
1. Cliquez sur <em>"Recherche avancée"</em><br>
2. Filtrez par <em>"Substance active"</em> et <em>"Nuisible dans usage"</em><br>
3. Sélectionnez votre produit → onglet <em>"Documents"</em><br><br>
La FDS est un document de 16 sections standardisées (règlement REACH).`
},
epi: {
icon: '🦺',
title: 'Indice — DL50 et EPI',
body: `<strong>DL50</strong> (Dose Létale 50%) : trouvée à la <strong>section 11</strong> de la FDS (informations toxicologiques). S'exprime en mg/kg de poids corporel — plus elle est basse, plus la substance est toxique.<br><br>
<strong>EPI courants :</strong> gants nitrile, lunettes, masque FFP2 ou à cartouche, combinaison, bottes. Vérifier la FDS section 8.`
},
etape1: {
icon: '🗂️',
title: 'Indice — Étapes de l\'activité',
body: `Listez les étapes chronologiques de votre intervention :<br><br>
• Transport des produits<br>
• Préparation et dilution du produit<br>
• Application / traitement<br>
• Aération des locaux<br>
• Rangement et décontamination du matériel<br>
• Gestion des déchets`
},
risque1: {
icon: '⚠️',
title: 'Indice — Types de risques',
body: `Pour chaque étape, identifiez les risques :<br><br>
• <strong>Chimiques :</strong> inhalation, contact cutané, ingestion accidentelle<br>
• <strong>Biologiques :</strong> contact avec animaux nuisibles, excréments<br>
• <strong>Physiques :</strong> chute de hauteur, TMS, bruit<br>
• <strong>Pour les tiers :</strong> contamination des aliments, clients présents`
},
mesure1: {
icon: '🛡️',
title: 'Indice — Mesures de prévention',
body: `Appliquez la pyramide de prévention :<br><br>
<strong>1. Élimination</strong> : supprimer le risque à la source<br>
<strong>2. Réduction</strong> : dose minimale efficace<br>
<strong>3. Protection collective</strong> : signalisation, ventilation, balisage<br>
<strong>4. Communication</strong> : formation, étiquetage, consignes<br>
<strong>5. EPI</strong> : en dernier recours seulement`
},
analyse: {
icon: '📊',
title: 'Aide — Analyse de risques',
body: `L'analyse de risques doit couvrir <strong>toutes les phases</strong> de l'intervention, pas seulement le traitement lui-même.<br><br>
Pensez à inclure : préparation, transport, manipulation des produits, application, nettoyage, gestion des déchets, et les risques pour les tiers présents sur le site.`
}
};
function goTo(n) {
const cur = document.getElementById('slide-' + currentSlide);
const next = document.getElementById('slide-' + n);
if (!next) return;
history.push(currentSlide);
cur.classList.remove('active', 'fade-in');
cur.style.display = 'none';
currentSlide = n;
next.style.display = 'flex';
setTimeout(() => { next.classList.add('active', 'fade-in'); }, 10);
if (n === 13) setTimeout(launchConfetti, 200);
updateUI();
updateCaseBanners();
}
function goBack() {
if (history.length === 0) return;
const prev = history.pop();
const cur = document.getElementById('slide-' + currentSlide);
const target = document.getElementById('slide-' + prev);
cur.classList.remove('active', 'fade-in');
cur.style.display = 'none';
currentSlide = prev;
target.style.display = 'flex';
setTimeout(() => { target.classList.add('active', 'fade-in'); }, 10);
updateUI();
}
function updateUI() {
const fill = document.getElementById('progressFill');
fill.style.width = currentSlide === 0 ? '0%' : ((currentSlide / totalSlides) * 100) + '%';
const counter = document.getElementById('slideCounter');
counter.textContent = currentSlide === 0 ? '' : currentSlide + ' / ' + totalSlides;
const bottomBar = document.getElementById('bottomBar');
if (bottomBar) bottomBar.style.display = currentSlide === 0 ? 'none' : 'flex';
const backBtn = document.getElementById('backBtn');
backBtn.style.display = history.length > 0 ? 'block' : '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';
}
}
function selectCase(key, icon, title, desc) {
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';
}
function updateCaseBanners() {
if (!selectedCase.key) return;
const banners = [4, 5, 6, 7, 8, 9, 10, 12];
banners.forEach(n => {
const b = document.getElementById('caseBanner' + n);
if (b) {
b.classList.add('visible');
const iconEl = document.getElementById('caseIcon' + n);
const titleEl = document.getElementById('caseTitle' + n);
const descEl = document.getElementById('caseDesc' + n);
if (iconEl) iconEl.textContent = selectedCase.icon;
if (titleEl) titleEl.textContent = selectedCase.title;
if (descEl) descEl.textContent = selectedCase.desc;
}
});
}
function showHint(key) {
const h = hints[key];
if (!h) return;
document.getElementById('modalIcon').textContent = h.icon;
document.getElementById('modalTitle').textContent = h.title;
document.getElementById('modalBody').innerHTML = h.body;
document.getElementById('modalOverlay').classList.add('open');
}
function closeModal(e) {
if (!e || e.target === document.getElementById('modalOverlay') || e.target.classList.contains('modal-close')) {
document.getElementById('modalOverlay').classList.remove('open');
}
}
function restartAll() {
history = [];
document.querySelectorAll('.slide').forEach(s => {
s.classList.remove('active', 'fade-in');
s.style.display = 'none';
});
currentSlide = 0;
const first = document.getElementById('slide-0');
first.style.display = 'flex';
setTimeout(() => first.classList.add('active', 'fade-in'), 10);
updateUI();
}
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeModal();
});
/* ======================== FORMATEUR ======================== */
function selectFormateur(nom) {
stagiaire.formateur = nom;
document.querySelectorAll('.formateur-btn').forEach(b => b.classList.remove('selected'));
document.getElementById('btn' + nom).classList.add('selected');
}
/* ======================== IDENTIFICATION ======================== */
function confirmIdentite() {
const nom = document.getElementById('inputNom').value.trim();
const date = document.getElementById('inputDate').value;
if (!nom) {
document.getElementById('idError').style.display = 'block';
return;
}
document.getElementById('idError').style.display = 'none';
stagiaire.nom = nom;
stagiaire.date = date || new Date().toISOString().slice(0, 10);
goTo(1);
}
/* ======================== TABLEAU TP3 — LIGNES DYNAMIQUES ======================== */
function addRiskRow() {
const tbody = document.getElementById('riskTableBody');
const tr = document.createElement('tr');
tr.className = 'risk-row';
tr.innerHTML = `
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
<td><textarea class="risk-cell" placeholder="…"></textarea></td>
<td><textarea class="risk-cell" placeholder="…"></textarea></td>`;
tbody.appendChild(tr);
}
/* ======================== COLLECTE DES RÉPONSES ======================== */
function collecterReponses() {
const reponses = [];
document.querySelectorAll('.answer-field').forEach(el => {
reponses.push({
id: el.id,
question: el.dataset.question || '',
reponse: el.value.trim()
});
});
const tableauRisques = [];
document.querySelectorAll('#riskTableBody .risk-row').forEach(row => {
const cells = row.querySelectorAll('.risk-cell');
tableauRisques.push({
etape: cells[0] ? cells[0].value.trim() : '',
risque: cells[1] ? cells[1].value.trim() : '',
mesure: cells[2] ? cells[2].value.trim() : ''
});
});
return {
nom: stagiaire.nom,
date_session: stagiaire.date,
formateur: stagiaire.formateur || '',
cas_choisi: selectedCase.title || '',
cas_cle: selectedCase.key || '',
reponses: reponses,
tp3_meta: {
intitule: val('meta_intitule'),
description: val('meta_description'),
lieu: val('meta_lieu'),
debut: val('meta_debut'),
realise_par: val('meta_realisee_par'),
verifie_par: val('meta_verifiee_par'),
maj_par: val('meta_maj_par')
},
tp3_tableau: tableauRisques,
date_envoi: new Date().toISOString()
};
}
function val(id) {
const el = document.getElementById(id);
return el ? el.value.trim() : '';
}
/* ======================== ENVOI VERS LE SERVEUR ======================== */
function envoyerReponses() {
const data = collecterReponses();
const statusEl = document.getElementById('submitStatus');
const btn = document.getElementById('btnEnvoyer');
if (!data.nom) {
statusEl.className = 'submit-status show error';
statusEl.textContent = '⚠️ Nom du groupe manquant. Veuillez recommencer depuis le début.';
return;
}
statusEl.className = 'submit-status show loading';
statusEl.textContent = '⏳ Envoi en cours…';
btn.disabled = true;
fetch('save_results.asp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(res => {
if (!res.ok) throw new Error('Erreur serveur (' + res.status + ')');
return res.json();
})
.then(json => {
if (json && json.success) {
statusEl.className = 'submit-status show success';
statusEl.textContent = '✅ Réponses envoyées avec succès au formateur !';
btn.textContent = '✅ Envoyé';
} else {
throw new Error((json && json.error) || 'Réponse invalide du serveur');
}
})
.catch(err => {
statusEl.className = 'submit-status show error';
statusEl.textContent = '❌ Échec de l\'envoi (' + err.message + '). Téléchargez le PDF et transmettez-le manuellement.';
btn.disabled = false;
});
}
/* ======================== EXPORT PDF (impression navigateur) ======================== */
function exporterPDF() {
const data = collecterReponses();
const w = window.open('', '_blank');
const lignes = data.reponses.map(r =>
`<div style="margin-bottom:14px;"><strong>${escapeHtml(r.question)}</strong><p style="margin:4px 0 0;white-space:pre-wrap;">${escapeHtml(r.reponse) || '<em>(sans réponse)</em>'}</p></div>`
).join('');
const tableauRows = data.tp3_tableau.map(r =>
`<tr><td>${escapeHtml(r.etape)}</td><td>${escapeHtml(r.risque)}</td><td>${escapeHtml(r.mesure)}</td></tr>`
).join('');
w.document.write(`
<html><head><meta charset="utf-8"><title>Résultats TP — ${escapeHtml(data.nom)}</title>
<style>
body { font-family: Arial, sans-serif; padding: 30px; color: #1a1a18; }
h1 { font-size: 20px; border-bottom: 2px solid #BA7517; padding-bottom: 8px; }
h2 { font-size: 15px; margin-top: 28px; color: #633806; }
table { width: 100%; border-collapse: collapse; margin-top: 8px; }
td, th { border: 1px solid #ccc; padding: 6px 8px; font-size: 12px; text-align: left; vertical-align: top; }
.meta { font-size: 13px; color: #555; margin-bottom: 4px; }
</style></head>
<body>
<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>
<p class="meta"><strong>Cas pratique :</strong> ${escapeHtml(data.cas_choisi)}</p>
<h2>Réponses TP1 &amp; TP2</h2>
${lignes}
<h2>TP3 — Analyse de risques</h2>
<p class="meta"><strong>Intitulé :</strong> ${escapeHtml(data.tp3_meta.intitule)}</p>
<p class="meta"><strong>Description :</strong> ${escapeHtml(data.tp3_meta.description)}</p>
<p class="meta"><strong>Lieu :</strong> ${escapeHtml(data.tp3_meta.lieu)}</p>
<p class="meta"><strong>Début prévu le :</strong> ${escapeHtml(data.tp3_meta.debut)}</p>
<table>
<tr><th>Étapes</th><th>Risques</th><th>Mesures de prévention</th></tr>
${tableauRows}
</table>
<p class="meta" style="margin-top:16px;">Réalisée par : ${escapeHtml(data.tp3_meta.realise_par)} — Vérifiée par : ${escapeHtml(data.tp3_meta.verifie_par)} — Mise à jour par : ${escapeHtml(data.tp3_meta.maj_par)}</p>
</body></html>
`);
w.document.close();
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;');
}
updateUI();
</script>
</body>
</html>