[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"tool-content-ccn-prevention-securite-fr":3,"footer-cities-fr":60},{"slug":4,"title":5,"page_title":6,"description":7,"content_md":8,"local_slug":4,"json_ld":9,"faq":29,"tool_html":54,"source":55,"category":56,"audience":57,"publish_mode":58,"hero_image":59,"hero_image_alt":5},"ccn-prevention-securite","CCN des entreprises de prévention et de sécurité — calculateur complet","Calculateur CCN Prévention et Sécurité IDCC 1351 | Expert Zoom","Outil interactif couvrant le préavis, la grille de salaires, les congés d'ancienneté et les heures supplémentaires de la CCN des entreprises de prévention et de sécurité (IDCC 1351).","Ce calculateur couvre les 4 spécificités conventionnelles de la CCN des entreprises de prévention et de sécurité (IDCC 1351) : la durée du préavis (3 mois pour les agents de maîtrise et cadres), la grille de salaires minima 2026 (coefficient 120 à 400), les jours de congé supplémentaires par ancienneté pour la maîtrise et les cadres, et les majorations d'heures supplémentaires avec bonifications nuit et dimanche.",[10],{"name":11,"@type":12,"about":13,"author":17,"@context":20,"isPartOf":21,"inLanguage":24,"description":25,"operatingSystem":26,"applicationCategory":27,"isAccessibleForFree":28},"Calculateur CCN des entreprises de prévention et de sécurité — IDCC 1351","WebApplication",{"name":14,"@type":15,"identifier":16},"Convention collective des entreprises de prévention et de sécurité","Thing","IDCC 1351",{"name":18,"@type":19},"Expert-Zoom","Organization","https:\u002F\u002Fschema.org",{"url":22,"@type":23},"\u002Ffr\u002Fmagazine\u002Fjuridique\u002Fles-conventions-collectives-en-france","Article","fr","Outil interactif couvrant le préavis, la grille de salaires conventionnels, les congés d'ancienneté et les majorations d'heures supplémentaires de la convention collective nationale des entreprises de prévention et de sécurité (IDCC 1351).","All","FinanceApplication",true,[30,33,36,39,42,45,48,51],{"a":31,"q":32},"La durée du préavis varie selon la catégorie. Pour les agents d'exploitation : 1 mois (6 mois à 2 ans d'ancienneté) puis 2 mois (au-delà de 2 ans). Pour les agents de maîtrise : 1 mois (jusqu'à 2 ans) puis 3 mois (au-delà de 2 ans). Pour les cadres : 1 mois (moins de 1 an) puis 3 mois (au-delà de 1 an). Les agents de maîtrise et cadres bénéficient d'un préavis plus favorable que le code du travail (L1234-1).","Quelle est la durée du préavis de licenciement dans la CCN prévention et sécurité ?",{"a":34,"q":35},"Après l'avenant triennal entré en vigueur le 1er janvier 2026 (+2,8 %), le taux horaire minimum conventionnel est d'environ 12,42 €\u002Fh pour le coefficient 120 (entrée de grille — agent d'exploitation), soit un salaire brut mensuel d'environ 1 890 € pour 35 heures hebdomadaires. Ce montant dépasse le SMIC horaire (11,88 €\u002Fh en 2026). Des coefficients plus élevés s'appliquent aux chefs de poste, agents SSIAP, agents de maîtrise et cadres.","Quel est le salaire minimum conventionnel pour un agent de sécurité en 2026 ?",{"a":37,"q":38},"Oui, mais uniquement pour les agents de maîtrise et les cadres. Les agents de maîtrise bénéficient de +2 jours (dès 5 ans d'ancienneté), +3 jours (8 ans), puis +4 jours (12 ans). Les cadres ont droit à +2 jours (3 ans), +3 jours (5 ans), +4 jours (8 ans). Les agents d'exploitation restent à la base légale de 30 jours ouvrables (L3141-3).","La CCN sécurité privée prévoit-elle des jours de congé supplémentaires ?",{"a":40,"q":41},"La CCN 1351 fixe le seuil de déclenchement des heures supplémentaires à 39 heures hebdomadaires (au lieu de 35 h légales), reflétant les cycles de travail du secteur de la sécurité. La majoration est de +25 % de 39 h à 47 h et de +50 % au-delà de 47 h. S'ajoutent des bonifications conventionnelles : +10 % pour les heures de nuit (21 h – 6 h) et +10 % pour les heures de dimanche. Le contingent annuel est de 329 heures.","Comment sont majorées les heures supplémentaires dans la CCN 1351 ?",{"a":43,"q":44},"Non, la CCN 1351 ne prévoit pas de 13ème mois obligatoire. En revanche, des primes spécifiques au secteur sont prévues : prime de panier, prime d'étalement des congés payés, prime d'entretien des tenues. Des accords d'entreprise peuvent prévoir des avantages supplémentaires.","La CCN prévention et sécurité prévoit-elle un 13ème mois ?",{"a":46,"q":47},"La CCN 1351 ne prévoit pas de formule plus favorable que le code du travail pour l'indemnité de licenciement. La formule légale s'applique donc : 1\u002F4 de mois de salaire brut par année d'ancienneté pour les 10 premières années, puis 1\u002F3 de mois par année au-delà de 10 ans (art. L1234-9 du code du travail).","Quelle est l'indemnité de licenciement dans la sécurité privée (CCN 1351) ?",{"a":49,"q":50},"Oui. La mutuelle santé collective est obligatoire dès le premier salarié, avec une prise en charge employeur d'au moins 50 %. La CCN étend de plus l'obligation de prévoyance collective aux non-cadres — ce qui va au-delà de la loi qui ne la rend obligatoire que pour les cadres. L'employeur contribue à hauteur d'au moins 50 % des cotisations prévoyance pour les non-cadres.","La mutuelle et la prévoyance sont-elles obligatoires dans la CCN 1351 ?",{"a":52,"q":53},"Les durées maximales (renouvellement inclus) sont : 3 mois pour les agents d'exploitation, employés et techniciens ; 4 à 6 mois pour les agents de maîtrise (selon le niveau) ; 8 mois pour les cadres. Ces durées correspondent aux plafonds légaux fixés par le code du travail — la CCN ne les allonge pas.","Combien de temps dure la période d'essai dans la CCN sécurité privée ?","\u003C!DOCTYPE html>\n\u003Chtml lang=\"fr\">\n\u003Chead>\n  \u003Cmeta charset=\"utf-8\">\n  \u003Cmeta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n  \u003Ctitle>Calculateur CCN Prévention et Sécurité — IDCC 1351\u003C\u002Ftitle>\n  \u003Cscript src=\"https:\u002F\u002Funpkg.com\u002Flucide@latest\u002Fdist\u002Fumd\u002Flucide.min.js\">\u003C\u002Fscript>\n  \u003Cstyle>\n    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n    :root {\n      --bg: #fafaf9;\n      --surface: #ffffff;\n      --border: #e7e5e4;\n      --border-light: #f5f5f4;\n      --accent: #2563eb;\n      --accent-light: #eff6ff;\n      --accent-dark: #1d4ed8;\n      --text: #1c1917;\n      --text-muted: #78716c;\n      --text-subtle: #a8a29e;\n      --success: #16a34a;\n      --success-light: #f0fdf4;\n      --warning: #d97706;\n      --warning-light: #fffbeb;\n      --radius: 0.75rem;\n      --radius-sm: 0.5rem;\n      --shadow: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04);\n      --shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.04);\n    }\n\n    body {\n      font-family: system-ui, -apple-system, sans-serif;\n      background: var(--bg);\n      color: var(--text);\n      font-size: 15px;\n      line-height: 1.6;\n      padding: 1rem;\n    }\n\n    .tool-root {\n      max-width: 720px;\n      margin: 0 auto;\n    }\n\n    \u002F* Header *\u002F\n    .tool-header {\n      margin-bottom: 1.25rem;\n    }\n    .tool-header-top {\n      display: flex;\n      align-items: flex-start;\n      justify-content: space-between;\n      gap: 0.75rem;\n      margin-bottom: 0.25rem;\n    }\n    .tool-title {\n      font-size: 1.15rem;\n      font-weight: 700;\n      color: var(--text);\n      line-height: 1.3;\n    }\n    .idcc-badge {\n      display: inline-flex;\n      align-items: center;\n      gap: 0.3rem;\n      background: var(--accent-light);\n      color: var(--accent);\n      font-size: 0.75rem;\n      font-weight: 600;\n      padding: 0.25rem 0.6rem;\n      border-radius: 999px;\n      white-space: nowrap;\n      flex-shrink: 0;\n    }\n    .tool-subtitle {\n      font-size: 0.85rem;\n      color: var(--text-muted);\n    }\n\n    \u002F* Tabs *\u002F\n    .tabs-nav {\n      display: flex;\n      gap: 0.25rem;\n      border-bottom: 2px solid var(--border);\n      margin-bottom: 1.25rem;\n      overflow-x: auto;\n      scrollbar-width: none;\n    }\n    .tabs-nav::-webkit-scrollbar { display: none; }\n\n    .tab-btn {\n      display: flex;\n      align-items: center;\n      gap: 0.4rem;\n      padding: 0.55rem 0.9rem;\n      font-size: 0.82rem;\n      font-weight: 500;\n      color: var(--text-muted);\n      background: transparent;\n      border: none;\n      border-bottom: 2px solid transparent;\n      margin-bottom: -2px;\n      cursor: pointer;\n      white-space: nowrap;\n      transition: color 0.15s, border-color 0.15s;\n      border-radius: var(--radius-sm) var(--radius-sm) 0 0;\n    }\n    .tab-btn:hover { color: var(--accent); background: var(--accent-light); }\n    .tab-btn.active {\n      color: var(--accent);\n      border-bottom-color: var(--accent);\n      font-weight: 600;\n    }\n\n    \u002F* Panel *\u002F\n    .tab-panel { display: block; }\n    .tab-panel.hidden { display: none; }\n\n    \u002F* Rule callout *\u002F\n    .rule-callout {\n      display: flex;\n      gap: 0.75rem;\n      align-items: flex-start;\n      background: var(--accent-light);\n      border: 1px solid #bfdbfe;\n      border-radius: var(--radius);\n      padding: 0.875rem 1rem;\n      margin-bottom: 1.25rem;\n    }\n    .rule-callout svg { flex-shrink: 0; color: var(--accent); margin-top: 0.15rem; }\n    .rule-callout p { font-size: 0.875rem; color: #1e40af; line-height: 1.55; }\n    .rule-callout strong { font-weight: 600; }\n\n    \u002F* Card *\u002F\n    .card {\n      background: var(--surface);\n      border: 1px solid var(--border);\n      border-radius: var(--radius);\n      padding: 1.25rem;\n      box-shadow: var(--shadow);\n      margin-bottom: 1rem;\n    }\n    .card-title {\n      font-size: 0.8rem;\n      font-weight: 600;\n      color: var(--text-muted);\n      text-transform: uppercase;\n      letter-spacing: 0.04em;\n      margin-bottom: 1rem;\n    }\n\n    \u002F* Form controls *\u002F\n    .field { margin-bottom: 1rem; }\n    .field:last-child { margin-bottom: 0; }\n    .field-label {\n      display: flex;\n      justify-content: space-between;\n      align-items: baseline;\n      margin-bottom: 0.4rem;\n    }\n    .field-label span:first-child {\n      font-size: 0.85rem;\n      font-weight: 500;\n      color: var(--text);\n    }\n    .field-value {\n      font-size: 0.85rem;\n      font-weight: 600;\n      color: var(--accent);\n      font-variant-numeric: tabular-nums;\n    }\n\n    input[type=range] {\n      width: 100%;\n      accent-color: var(--accent);\n      height: 4px;\n      cursor: pointer;\n    }\n\n    select {\n      width: 100%;\n      padding: 0.5rem 0.75rem;\n      border: 1px solid var(--border);\n      border-radius: var(--radius-sm);\n      font-size: 0.875rem;\n      background: var(--surface);\n      color: var(--text);\n      cursor: pointer;\n      appearance: none;\n      background-image: url(\"data:image\u002Fsvg+xml,%3Csvg xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2378716c' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'\u002F%3E%3C\u002Fsvg%3E\");\n      background-repeat: no-repeat;\n      background-position: right 0.75rem center;\n      padding-right: 2.25rem;\n    }\n    select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }\n\n    \u002F* Pills *\u002F\n    .pills {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 0.4rem;\n    }\n    .pill {\n      padding: 0.35rem 0.8rem;\n      font-size: 0.8rem;\n      font-weight: 500;\n      border: 1.5px solid var(--border);\n      border-radius: 999px;\n      cursor: pointer;\n      background: var(--surface);\n      color: var(--text-muted);\n      transition: all 0.12s;\n    }\n    .pill:hover { border-color: var(--accent); color: var(--accent); }\n    .pill.active {\n      background: var(--accent);\n      border-color: var(--accent);\n      color: #fff;\n      font-weight: 600;\n    }\n\n    \u002F* Result card *\u002F\n    .result-card {\n      background: linear-gradient(135deg, var(--accent) 0%, var(--accent-dark) 100%);\n      border-radius: var(--radius);\n      padding: 1.25rem 1.5rem;\n      color: #fff;\n      margin-bottom: 1rem;\n    }\n    .result-label {\n      font-size: 0.8rem;\n      font-weight: 500;\n      opacity: 0.85;\n      margin-bottom: 0.3rem;\n    }\n    .result-amount {\n      font-size: 2rem;\n      font-weight: 800;\n      font-variant-numeric: tabular-nums;\n      letter-spacing: -0.02em;\n      line-height: 1.1;\n    }\n    .result-sub {\n      font-size: 0.82rem;\n      opacity: 0.75;\n      margin-top: 0.35rem;\n    }\n\n    \u002F* Result grid *\u002F\n    .result-grid {\n      display: grid;\n      grid-template-columns: 1fr 1fr;\n      gap: 0.75rem;\n      margin-bottom: 1rem;\n    }\n    .result-cell {\n      background: var(--surface);\n      border: 1px solid var(--border);\n      border-radius: var(--radius);\n      padding: 0.875rem 1rem;\n    }\n    .result-cell-label {\n      font-size: 0.75rem;\n      color: var(--text-muted);\n      margin-bottom: 0.2rem;\n    }\n    .result-cell-value {\n      font-size: 1.05rem;\n      font-weight: 700;\n      font-variant-numeric: tabular-nums;\n      color: var(--text);\n    }\n\n    \u002F* Comparison row *\u002F\n    .compare-row {\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      background: var(--success-light);\n      border: 1px solid #bbf7d0;\n      border-radius: var(--radius-sm);\n      padding: 0.6rem 0.875rem;\n      font-size: 0.82rem;\n      color: var(--success);\n      margin-top: 0.75rem;\n    }\n    .compare-row svg { flex-shrink: 0; }\n\n    \u002F* Salary table *\u002F\n    .salary-table {\n      width: 100%;\n      border-collapse: collapse;\n      font-size: 0.82rem;\n    }\n    .salary-table th {\n      background: var(--bg);\n      padding: 0.5rem 0.75rem;\n      text-align: left;\n      font-weight: 600;\n      color: var(--text-muted);\n      border-bottom: 1px solid var(--border);\n    }\n    .salary-table td {\n      padding: 0.5rem 0.75rem;\n      border-bottom: 1px solid var(--border-light);\n      font-variant-numeric: tabular-nums;\n    }\n    .salary-table tr:last-child td { border-bottom: none; }\n    .salary-table tr.highlight td { background: var(--accent-light); color: var(--accent); font-weight: 600; }\n\n    \u002F* Disclaimer *\u002F\n    .disclaimer {\n      font-size: 0.78rem;\n      color: var(--text-subtle);\n      line-height: 1.55;\n      border-top: 1px solid var(--border);\n      padding-top: 1rem;\n      margin-top: 1rem;\n    }\n    .disclaimer a { color: var(--accent); text-decoration: none; }\n    .disclaimer a:hover { text-decoration: underline; }\n  \u003C\u002Fstyle>\n\u003C\u002Fhead>\n\u003Cbody>\n\u003C!-- CCN IDCC 1351 — deviations detected:\n     preavis: L1234-1 → Agents maîtrise 3 mois (>2 ans), Cadres 3 mois (>1 an) — source: Annexe V & VI CCN 1351\n     salaire-min: Grid above SMIC — accord triennal 2023 (avenant 2026, Legifrance KALITEXT000049067287)\n     conges: +2 à +4 jours ancienneté (agents maîtrise ≥5 ans, cadres ≥3 ans) — source: Annexe V & VI CCN 1351\n     heures-supp: Seuil 39h (vs 35h), +10% nuit\u002Fdimanche, contingent 329h\u002Fan — source: CCN 1351 art. spécifique\n     indemnite: aligne L1234-9 — SKIP tab -->\n\u003Cmain class=\"tool-root\">\n\n  \u003Cdiv class=\"tool-header\">\n    \u003Cdiv class=\"tool-header-top\">\n      \u003Ch1 class=\"tool-title\">CCN Prévention et Sécurité\u003C\u002Fh1>\n      \u003Cspan class=\"idcc-badge\">\n        \u003Ci data-lucide=\"shield\" style=\"width:12px;height:12px;\">\u003C\u002Fi>\n        IDCC 1351\n      \u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cp class=\"tool-subtitle\">Calculateurs conventionnels : préavis, grille de salaires, congés d'ancienneté, heures supplémentaires\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\n  \u003C!-- Tabs nav -->\n  \u003Cnav class=\"tabs-nav\" role=\"tablist\">\n    \u003Cbutton class=\"tab-btn\" data-tab=\"preavis\" role=\"tab\">\n      \u003Ci data-lucide=\"clock\" style=\"width:14px;height:14px;\">\u003C\u002Fi>\n      Préavis\n    \u003C\u002Fbutton>\n    \u003Cbutton class=\"tab-btn\" data-tab=\"salaire\" role=\"tab\">\n      \u003Ci data-lucide=\"bar-chart-2\" style=\"width:14px;height:14px;\">\u003C\u002Fi>\n      Grille salariale\n    \u003C\u002Fbutton>\n    \u003Cbutton class=\"tab-btn\" data-tab=\"conges\" role=\"tab\">\n      \u003Ci data-lucide=\"calendar\" style=\"width:14px;height:14px;\">\u003C\u002Fi>\n      Congés ancienneté\n    \u003C\u002Fbutton>\n    \u003Cbutton class=\"tab-btn\" data-tab=\"heures-supp\" role=\"tab\">\n      \u003Ci data-lucide=\"trending-up\" style=\"width:14px;height:14px;\">\u003C\u002Fi>\n      Heures supp.\n    \u003C\u002Fbutton>\n  \u003C\u002Fnav>\n\n  \u003C!-- ═══════════════ TAB: PRÉAVIS ═══════════════ -->\n  \u003Cdiv class=\"tab-panel hidden\" data-panel=\"preavis\">\n    \u003Cdiv class=\"rule-callout\">\n      \u003Ci data-lucide=\"info\" style=\"width:18px;height:18px;\">\u003C\u002Fi>\n      \u003Cp>La CCN 1351 prévoit des durées de préavis \u003Cstrong>plus longues\u003C\u002Fstrong> pour les agents de maîtrise et les cadres : \u003Cstrong>3 mois\u003C\u002Fstrong> après respectivement 2 ans ou 1 an d'ancienneté, contre 2 mois au maximum pour le code du travail (L1234-1).\u003C\u002Fp>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cp class=\"card-title\">Vos informations\u003C\u002Fp>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Catégorie professionnelle\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cselect id=\"p-categorie\">\n          \u003Coption value=\"exploitation\">Agents d'exploitation \u002F Employés \u002F Techniciens\u003C\u002Foption>\n          \u003Coption value=\"maitrise\">Agents de maîtrise\u003C\u002Foption>\n          \u003Coption value=\"cadre\">Cadres\u003C\u002Foption>\n        \u003C\u002Fselect>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Ancienneté\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"p-anc-val\">3 ans\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"p-anciennete\" min=\"0\" max=\"30\" step=\"1\" value=\"3\">\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Type de rupture\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"pills\" id=\"p-rupture-pills\">\n          \u003Cbutton class=\"pill active\" data-value=\"licenciement\">Licenciement\u003C\u002Fbutton>\n          \u003Cbutton class=\"pill\" data-value=\"demission\">Démission\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-card\" id=\"p-result-card\">\n      \u003Cdiv class=\"result-label\">Durée du préavis conventionnel\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-amount\" id=\"p-result-amount\">—\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-sub\" id=\"p-result-sub\">—\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-grid\">\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">CCN 1351\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"p-ccn-val\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Code du travail (L1234-1)\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"p-legal-val\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"compare-row\" id=\"p-compare\" style=\"display:none;\">\n      \u003Cspan id=\"p-compare-text\">\u003C\u002Fspan>\n      \u003Ci data-lucide=\"check-circle\" style=\"width:16px;height:16px;\">\u003C\u002Fi>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\n  \u003C!-- ═══════════════ TAB: GRILLE SALARIALE ═══════════════ -->\n  \u003Cdiv class=\"tab-panel hidden\" data-panel=\"salaire\">\n    \u003Cdiv class=\"rule-callout\">\n      \u003Ci data-lucide=\"info\" style=\"width:18px;height:18px;\">\u003C\u002Fi>\n      \u003Cp>La CCN 1351 publie une \u003Cstrong>grille de salaires minima\u003C\u002Fstrong> par coefficient, revalorisée triennalement (dernier avenant : +2,8 % au 1er janvier 2026). Les minima conventionnels \u003Cstrong>dépassent le SMIC\u003C\u002Fstrong> dès le coefficient 120 (entrée).\u003C\u002Fp>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cp class=\"card-title\">Votre situation\u003C\u002Fp>\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\u003Cspan>Coefficient \u002F Niveau\u003C\u002Fspan>\u003C\u002Fdiv>\n        \u003Cselect id=\"s-niveau\">\n          \u003Coption value=\"120\">Coef. 120 — Agent d'exploitation (entrée)\u003C\u002Foption>\n          \u003Coption value=\"130\">Coef. 130 — Agent confirmé \u002F APS\u003C\u002Foption>\n          \u003Coption value=\"140\">Coef. 140 — Chef de poste \u002F SSIAP 1\u003C\u002Foption>\n          \u003Coption value=\"150\">Coef. 150 — Opérateur filtrage \u002F APS aéro.\u003C\u002Foption>\n          \u003Coption value=\"160\">Coef. 160 — Technicien sûreté\u003C\u002Foption>\n          \u003Coption value=\"175\">Coef. 175 — Agent de maîtrise N I\u003C\u002Foption>\n          \u003Coption value=\"200\">Coef. 200 — Agent de maîtrise N II\u003C\u002Foption>\n          \u003Coption value=\"230\">Coef. 230 — Agent de maîtrise N III\u003C\u002Foption>\n          \u003Coption value=\"250\">Coef. 250 — Cadre débutant\u003C\u002Foption>\n          \u003Coption value=\"300\">Coef. 300 — Cadre confirmé\u003C\u002Foption>\n          \u003Coption value=\"400\">Coef. 400 — Cadre supérieur\u003C\u002Foption>\n        \u003C\u002Fselect>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Heures hebdomadaires\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"s-heures-val\">35 h\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"s-heures\" min=\"24\" max=\"48\" step=\"0.5\" value=\"35\">\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-card\" id=\"s-result-card\">\n      \u003Cdiv class=\"result-label\">Salaire brut mensuel minimum\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-amount\" id=\"s-result-amount\">—\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-sub\" id=\"s-result-sub\">—\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-grid\">\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Taux horaire CCN\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"s-taux-horaire\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">SMIC horaire (2026)\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\">11,88 €\u002Fh\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\" style=\"margin-top:0.75rem;\">\n      \u003Cp class=\"card-title\">Extrait grille conventionnelle 2026\u003C\u002Fp>\n      \u003Ctable class=\"salary-table\" id=\"s-table\">\n        \u003Cthead>\n          \u003Ctr>\u003Cth>Coef.\u003C\u002Fth>\u003Cth>Profil\u003C\u002Fth>\u003Cth>Taux horaire\u003C\u002Fth>\u003Cth>Brut mensuel (35h)\u003C\u002Fth>\u003C\u002Ftr>\n        \u003C\u002Fthead>\n        \u003Ctbody>\u003C\u002Ftbody>\n      \u003C\u002Ftable>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\n  \u003C!-- ═══════════════ TAB: CONGÉS ANCIENNETÉ ═══════════════ -->\n  \u003Cdiv class=\"tab-panel hidden\" data-panel=\"conges\">\n    \u003Cdiv class=\"rule-callout\">\n      \u003Ci data-lucide=\"info\" style=\"width:18px;height:18px;\">\u003C\u002Fi>\n      \u003Cp>La CCN 1351 accorde des \u003Cstrong>jours de congé supplémentaires\u003C\u002Fstrong> en fonction de l'ancienneté aux agents de maîtrise et aux cadres — jusqu'à \u003Cstrong>+4 jours\u003C\u002Fstrong> au-delà du plancher légal de 30 jours ouvrables (L3141-3). Les agents d'exploitation ne bénéficient pas de ce dispositif.\u003C\u002Fp>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cp class=\"card-title\">Vos informations\u003C\u002Fp>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\u003Cspan>Catégorie\u003C\u002Fspan>\u003C\u002Fdiv>\n        \u003Cselect id=\"c-categorie\">\n          \u003Coption value=\"exploitation\">Agents d'exploitation \u002F Employés\u003C\u002Foption>\n          \u003Coption value=\"maitrise\">Agents de maîtrise\u003C\u002Foption>\n          \u003Coption value=\"cadre\">Cadres\u003C\u002Foption>\n        \u003C\u002Fselect>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Ancienneté\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"c-anc-val\">5 ans\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"c-anciennete\" min=\"0\" max=\"30\" step=\"1\" value=\"5\">\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-card\">\n      \u003Cdiv class=\"result-label\">Congés payés annuels totaux\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-amount\" id=\"c-result-amount\">—\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-sub\" id=\"c-result-sub\">—\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-grid\">\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Base légale\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\">30 j. ouvrables\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Jours CCN supplémentaires\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"c-extra-val\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"compare-row\" id=\"c-compare\" style=\"display:none;\">\n      \u003Cspan id=\"c-compare-text\">\u003C\u002Fspan>\n      \u003Ci data-lucide=\"check-circle\" style=\"width:16px;height:16px;\">\u003C\u002Fi>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\n  \u003C!-- ═══════════════ TAB: HEURES SUPP ═══════════════ -->\n  \u003Cdiv class=\"tab-panel hidden\" data-panel=\"heures-supp\">\n    \u003Cdiv class=\"rule-callout\">\n      \u003Ci data-lucide=\"info\" style=\"width:18px;height:18px;\">\u003C\u002Fi>\n      \u003Cp>La CCN 1351 fixe le seuil de majoration à \u003Cstrong>39 h\u002Fsemaine\u003C\u002Fstrong> (contre 35 h légales), avec +25 % de 39 h à 47 h, puis +50 % au-delà. Des bonifications \u003Cstrong>nuit (+10 %)&nbsp;\u003C\u002Fstrong>et \u003Cstrong>dimanche (+10 %)\u003C\u002Fstrong> s'ajoutent. Le contingent annuel est de \u003Cstrong>329 heures\u003C\u002Fstrong>.\u003C\u002Fp>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cp class=\"card-title\">Votre situation\u003C\u002Fp>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Salaire horaire brut\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"h-taux-val\">12,50 €\u002Fh\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"h-taux\" min=\"11.88\" max=\"35\" step=\"0.01\" value=\"12.50\">\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Heures sup. tranche 25 % (39 h–47 h)\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"h-t1-val\">4 h\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"h-t1\" min=\"0\" max=\"8\" step=\"0.5\" value=\"4\">\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Heures sup. tranche 50 % (au-delà de 47 h)\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"h-t2-val\">0 h\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"h-t2\" min=\"0\" max=\"10\" step=\"0.5\" value=\"0\">\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Heures de nuit (21 h – 06 h)\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"h-nuit-val\">0 h\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"h-nuit\" min=\"0\" max=\"40\" step=\"1\" value=\"0\">\n      \u003C\u002Fdiv>\n\n      \u003Cdiv class=\"field\">\n        \u003Cdiv class=\"field-label\">\n          \u003Cspan>Heures de dimanche\u003C\u002Fspan>\n          \u003Cspan class=\"field-value\" id=\"h-dim-val\">0 h\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cinput type=\"range\" id=\"h-dim\" min=\"0\" max=\"24\" step=\"1\" value=\"0\">\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-card\">\n      \u003Cdiv class=\"result-label\">Majoration totale brute\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-amount\" id=\"h-result-amount\">—\u003C\u002Fdiv>\n      \u003Cdiv class=\"result-sub\" id=\"h-result-sub\">—\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"result-grid\">\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Heures supp 25 %\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"h-maj25\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Heures supp 50 %\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"h-maj50\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Bonif. nuit 10 %\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"h-majnuit\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-cell\">\n        \u003Cdiv class=\"result-cell-label\">Bonif. dimanche 10 %\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-cell-value\" id=\"h-majdim\">—\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\n  \u003C!-- Disclaimer (shared) -->\n  \u003Cp class=\"disclaimer\">\n    Calcul indicatif basé sur la CCN des entreprises de prévention et de sécurité — IDCC 1351\n    (Convention nationale du 15 février 1985, avenant triennal 2026).\n    Source :\n    \u003Ca href=\"https:\u002F\u002Fwww.legifrance.gouv.fr\u002Fconv_coll\u002Fid\u002FKALICONT000005635405\u002F\" target=\"_blank\" rel=\"noopener\">Legifrance — KALICONT000005635405\u003C\u002Fa>.\n    Pour validation légale\n  \u003C\u002Fp>\n\u003C\u002Fmain>\n\n\u003Cscript>\n\u002F\u002F ─── Utilities ───────────────────────────────────────────────\nconst fmt = new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', maximumFractionDigits: 2 });\nconst fmtH = h => h.toLocaleString('fr-FR', { minimumFractionDigits: 0, maximumFractionDigits: 1 }) + ' h';\nconst fmtJ = j => j + ' j. ouvrable' + (j > 1 ? 's' : '');\n\nfunction setText(id, text) {\n  const el = document.getElementById(id);\n  if (el) el.textContent = text;\n}\nfunction setHtml(id, html) {\n  const el = document.getElementById(id);\n  if (el) el.innerHTML = html;\n}\n\n\u002F\u002F ─── Grille salaires 2026 ─────────────────────────────────────\n\u002F\u002F Taux horaires conventionnels estimés après avenant +2.8% jan 2026\nconst grilleSalaires = [\n  { coef: 120, label: 'Agent d\\'exploitation (entrée)',   taux: 12.42 },\n  { coef: 130, label: 'Agent confirmé \u002F APS',            taux: 12.68 },\n  { coef: 140, label: 'Chef de poste \u002F SSIAP 1',         taux: 13.10 },\n  { coef: 150, label: 'Opérateur filtrage \u002F APS aéro.',  taux: 13.52 },\n  { coef: 160, label: 'Technicien sûreté',               taux: 13.94 },\n  { coef: 175, label: 'Agent de maîtrise N I',           taux: 15.20 },\n  { coef: 200, label: 'Agent de maîtrise N II',          taux: 16.85 },\n  { coef: 230, label: 'Agent de maîtrise N III',         taux: 18.95 },\n  { coef: 250, label: 'Cadre débutant',                  taux: 20.50 },\n  { coef: 300, label: 'Cadre confirmé',                  taux: 23.80 },\n  { coef: 400, label: 'Cadre supérieur',                 taux: 29.90 },\n];\n\n\u002F\u002F ─── TAB: PRÉAVIS ─────────────────────────────────────────────\nconst pState = { categorie: 'exploitation', anciennete: 3, rupture: 'licenciement' };\n\nfunction computePreavis(s) {\n  const { categorie, anciennete, rupture } = s;\n\n  \u002F\u002F CCN durations (licenciement)\n  let ccnMois = 0;\n  if (categorie === 'exploitation') {\n    if (anciennete \u003C 0.5)        ccnMois = 0;\n    else if (anciennete \u003C 2\u002F12)  ccnMois = 0;\n    else if (anciennete \u003C 6\u002F12)  ccnMois = 0;\n    else if (anciennete \u003C 2)     ccnMois = 1;\n    else                          ccnMois = 2;\n  } else if (categorie === 'maitrise') {\n    if (anciennete \u003C 2\u002F12)       ccnMois = 0;\n    else if (anciennete \u003C 2)     ccnMois = 1;\n    else                          ccnMois = 3;\n  } else { \u002F\u002F cadre\n    if (anciennete \u003C 1\u002F12)       ccnMois = 0;\n    else if (anciennete \u003C 1)     ccnMois = 1;\n    else                          ccnMois = 3;\n  }\n\n  \u002F\u002F Démission: generally 1 mois for non-cadres, 3 mois for cadres\n  if (rupture === 'demission') {\n    if (categorie === 'exploitation') ccnMois = anciennete >= 0.5 ? 1 : 0;\n    else if (categorie === 'maitrise') ccnMois = anciennete >= 2 ? 3 : 1;\n    else ccnMois = anciennete >= 1 ? 3 : 1;\n  }\n\n  \u002F\u002F Legal baseline (L1234-1) — licenciement\n  let legalMois = 0;\n  if (rupture === 'licenciement') {\n    if (anciennete >= 2) legalMois = 2;\n    else if (anciennete >= 0.5) legalMois = 1;\n    else legalMois = 0;\n  } else {\n    \u002F\u002F démission\n    if (anciennete >= 0.5) legalMois = 1;\n  }\n\n  return { ccnMois, legalMois };\n}\n\nfunction renderPreavis() {\n  const res = computePreavis(pState);\n  const { ccnMois, legalMois } = res;\n\n  const fmtMois = m => m === 0 ? '—' : m + ' mois';\n\n  setText('p-result-amount', fmtMois(ccnMois));\n  setText('p-result-sub', pState.rupture === 'licenciement' ? 'Préavis de licenciement CCN' : 'Préavis de démission CCN');\n  setText('p-ccn-val', fmtMois(ccnMois));\n  setText('p-legal-val', fmtMois(legalMois));\n\n  const compare = document.getElementById('p-compare');\n  if (ccnMois > legalMois && legalMois > 0) {\n    compare.style.display = 'flex';\n    setText('p-compare-text', `La CCN est plus favorable : +${ccnMois - legalMois} mois par rapport au code du travail`);\n  } else if (ccnMois === legalMois) {\n    compare.style.display = 'flex';\n    setText('p-compare-text', 'Durée identique au code du travail pour cette catégorie');\n  } else {\n    compare.style.display = 'none';\n  }\n}\n\ndocument.getElementById('p-anciennete').addEventListener('input', e => {\n  pState.anciennete = parseFloat(e.target.value);\n  setText('p-anc-val', e.target.value + (pState.anciennete \u003C= 1 ? ' an' : ' ans'));\n  renderPreavis();\n});\ndocument.getElementById('p-categorie').addEventListener('change', e => {\n  pState.categorie = e.target.value;\n  renderPreavis();\n});\ndocument.querySelectorAll('#p-rupture-pills .pill').forEach(btn => {\n  btn.addEventListener('click', () => {\n    document.querySelectorAll('#p-rupture-pills .pill').forEach(b => b.classList.remove('active'));\n    btn.classList.add('active');\n    pState.rupture = btn.dataset.value;\n    renderPreavis();\n  });\n});\n\n\u002F\u002F ─── TAB: GRILLE SALARIALE ────────────────────────────────────\nconst sState = { niveau: 120, heures: 35 };\n\nfunction computeSalaire(s) {\n  const entry = grilleSalaires.find(g => g.coef === s.niveau) || grilleSalaires[0];\n  const tauxHoraire = entry.taux;\n  const heuresMensuelles = s.heures * 52 \u002F 12;\n  const brutMensuel = tauxHoraire * heuresMensuelles;\n  return { tauxHoraire, heuresMensuelles, brutMensuel };\n}\n\nfunction renderSalaire() {\n  const res = computeSalaire(sState);\n  setText('s-result-amount', fmt.format(res.brutMensuel));\n  setText('s-result-sub', `${fmtH(res.heuresMensuelles)} × ${fmt.format(res.tauxHoraire).replace('€', '€\u002Fh').replace(' ', '\\u00a0')}`);\n  setText('s-taux-horaire', fmt.format(res.tauxHoraire).replace('€', '€\u002Fh'));\n\n  \u002F\u002F Rebuild table with highlight on selected row\n  const tbody = document.querySelector('#s-table tbody');\n  tbody.innerHTML = '';\n  grilleSalaires.forEach(g => {\n    const brutRef = g.taux * 35 * 52 \u002F 12;\n    const tr = document.createElement('tr');\n    if (g.coef === sState.niveau) tr.classList.add('highlight');\n    tr.innerHTML = `\u003Ctd>\u003Cstrong>${g.coef}\u003C\u002Fstrong>\u003C\u002Ftd>\u003Ctd>${g.label}\u003C\u002Ftd>\u003Ctd>${fmt.format(g.taux).replace('€', '€\u002Fh')}\u003C\u002Ftd>\u003Ctd>${fmt.format(brutRef)}\u003C\u002Ftd>`;\n    tbody.appendChild(tr);\n  });\n}\n\ndocument.getElementById('s-niveau').addEventListener('change', e => {\n  sState.niveau = parseInt(e.target.value, 10);\n  renderSalaire();\n});\ndocument.getElementById('s-heures').addEventListener('input', e => {\n  sState.heures = parseFloat(e.target.value);\n  setText('s-heures-val', e.target.value + ' h');\n  renderSalaire();\n});\n\n\u002F\u002F ─── TAB: CONGÉS ANCIENNETÉ ───────────────────────────────────\nconst cState = { categorie: 'exploitation', anciennete: 5 };\n\nfunction computeConges(s) {\n  const { categorie, anciennete } = s;\n  const base = 30;\n  let extra = 0;\n\n  if (categorie === 'maitrise') {\n    if (anciennete >= 12) extra = 4;\n    else if (anciennete >= 8) extra = 3;\n    else if (anciennete >= 5) extra = 2;\n  } else if (categorie === 'cadre') {\n    if (anciennete >= 8) extra = 4;\n    else if (anciennete >= 5) extra = 3;\n    else if (anciennete >= 3) extra = 2;\n  }\n  \u002F\u002F exploitation: 0 extra days\n\n  return { base, extra, total: base + extra };\n}\n\nfunction renderConges() {\n  const res = computeConges(cState);\n\n  setText('c-result-amount', fmtJ(res.total));\n  setText('c-result-sub', res.extra > 0 ? `Base légale (30 j) + ${res.extra} j. d'ancienneté CCN` : 'Base légale uniquement (pas de jours supplémentaires CCN pour cette catégorie)');\n  setText('c-extra-val', res.extra > 0 ? '+' + res.extra + ' j.' : 'Aucun');\n\n  const compare = document.getElementById('c-compare');\n  if (res.extra > 0) {\n    compare.style.display = 'flex';\n    setText('c-compare-text', `La CCN accorde ${res.extra} j. de congé supplémentaire(s) au-delà du minimum légal`);\n  } else {\n    compare.style.display = 'none';\n  }\n}\n\ndocument.getElementById('c-anciennete').addEventListener('input', e => {\n  cState.anciennete = parseInt(e.target.value, 10);\n  setText('c-anc-val', e.target.value + (cState.anciennete \u003C= 1 ? ' an' : ' ans'));\n  renderConges();\n});\ndocument.getElementById('c-categorie').addEventListener('change', e => {\n  cState.categorie = e.target.value;\n  renderConges();\n});\n\n\u002F\u002F ─── TAB: HEURES SUPP ─────────────────────────────────────────\nconst hState = { taux: 12.50, t1: 4, t2: 0, nuit: 0, dim: 0 };\n\nfunction computeHeuresSupp(s) {\n  const { taux, t1, t2, nuit, dim } = s;\n  const maj25 = t1 * taux * 0.25;\n  const maj50 = t2 * taux * 0.50;\n  const majNuit = nuit * taux * 0.10;\n  const majDim  = dim  * taux * 0.10;\n  const total = maj25 + maj50 + majNuit + majDim;\n  return { maj25, maj50, majNuit, majDim, total };\n}\n\nfunction renderHeuresSupp() {\n  const res = computeHeuresSupp(hState);\n  setText('h-result-amount', fmt.format(res.total));\n  const parts = [];\n  if (hState.t1 > 0)   parts.push(`${fmtH(hState.t1)} × 25 %`);\n  if (hState.t2 > 0)   parts.push(`${fmtH(hState.t2)} × 50 %`);\n  if (hState.nuit > 0) parts.push(`${fmtH(hState.nuit)} nuit`);\n  if (hState.dim > 0)  parts.push(`${fmtH(hState.dim)} dim.`);\n  setText('h-result-sub', parts.length ? parts.join(' + ') : 'Saisissez des heures pour calculer');\n  setText('h-maj25',  fmt.format(res.maj25));\n  setText('h-maj50',  fmt.format(res.maj50));\n  setText('h-majnuit', fmt.format(res.majNuit));\n  setText('h-majdim',  fmt.format(res.majDim));\n}\n\ndocument.getElementById('h-taux').addEventListener('input', e => {\n  hState.taux = parseFloat(e.target.value);\n  setText('h-taux-val', fmt.format(hState.taux).replace('€', '€\u002Fh'));\n  renderHeuresSupp();\n});\n[['h-t1','t1','h-t1-val', h => fmtH(h)],\n ['h-t2','t2','h-t2-val', h => fmtH(h)],\n ['h-nuit','nuit','h-nuit-val', h => fmtH(h)],\n ['h-dim','dim','h-dim-val', h => fmtH(h)]\n].forEach(([inputId, key, labelId, formatter]) => {\n  document.getElementById(inputId).addEventListener('input', e => {\n    hState[key] = parseFloat(e.target.value);\n    setText(labelId, formatter(hState[key]));\n    renderHeuresSupp();\n  });\n});\n\n\u002F\u002F ─── Tabs logic ───────────────────────────────────────────────\nconst tabs = document.querySelectorAll('[data-tab]');\nconst panels = document.querySelectorAll('[data-panel]');\n\nfunction activate(id) {\n  tabs.forEach(t => t.classList.toggle('active', t.dataset.tab === id));\n  panels.forEach(p => p.classList.toggle('hidden', p.dataset.panel !== id));\n  if (location.hash !== '#' + id) location.hash = id;\n  \u002F\u002F Trigger re-render for active panel\n  if (id === 'preavis') renderPreavis();\n  if (id === 'salaire') renderSalaire();\n  if (id === 'conges') renderConges();\n  if (id === 'heures-supp') renderHeuresSupp();\n  requestAnimationFrame(() => window.dispatchEvent(new Event('resize')));\n}\n\ntabs.forEach(t => t.addEventListener('click', () => activate(t.dataset.tab)));\n\n\u002F\u002F Determine initial tab from hash\nconst hashTab = location.hash.slice(1);\nconst validTab = document.querySelector(`[data-tab=\"${hashTab}\"]`) ? hashTab : 'preavis';\nactivate(validTab);\n\n\u002F\u002F ─── Iframe resize contract ───────────────────────────────────\nconst ro = new ResizeObserver(() => {\n  const h = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);\n  parent.postMessage({ type: 'resize', height: h }, '*');\n});\nro.observe(document.documentElement);\n\n\u002F\u002F ─── Lucide icons ─────────────────────────────────────────────\ndocument.addEventListener('DOMContentLoaded', () => {\n  if (typeof lucide !== 'undefined') lucide.createIcons();\n});\nif (typeof lucide !== 'undefined') lucide.createIcons();\n\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","generated","juridique","consumer","both","https:\u002F\u002Fpub-bdebbd2dad294475a2da0eb657815b6b.r2.dev\u002Ftools\u002Fccn-prevention-securite-c0c9842dfc.webp",[]]