[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"footer-root-categories-fr-FR":3,"tool-content-ccn-ouvriers-des-travaux-publics-fr":83,"footer-cities-fr":146},[4,14,22,30,38,45,53,60,67,75],{"seo_content":5,"id":8,"name":9,"slug":10,"parentId":7,"lang":11,"_count":12},[6],{"page_slug":7},null,"cmkzhl7xm00dbulbc93h4qog5","Juridique","avocats","fr-FR",{"experts":13},8,{"seo_content":15,"id":17,"name":18,"slug":19,"parentId":7,"lang":11,"_count":20},[16],{"page_slug":7},"cmkzhl84700djulbcbv6pzu9e","Informatique","informaticiens",{"experts":21},3,{"seo_content":23,"id":25,"name":26,"slug":27,"parentId":7,"lang":11,"_count":28},[24],{"page_slug":7},"cmkzhlaos00gnulbc07i9jrco","Amélioration de la Maison","artisans",{"experts":29},4,{"seo_content":31,"id":33,"name":34,"slug":35,"parentId":7,"lang":11,"_count":36},[32],{"page_slug":7},"cmkzhlaqg00gpulbcx38bwoc2","Général","divers-generalistes",{"experts":37},0,{"seo_content":39,"id":41,"name":42,"slug":43,"parentId":7,"lang":11,"_count":44},[40],{"page_slug":7},"cmkzhlbvq00i3ulbcutdbcz50","Électronique Grand Public","techniciens-electronique",{"experts":21},{"seo_content":46,"id":48,"name":49,"slug":50,"parentId":7,"lang":11,"_count":51},[47],{"page_slug":7},"cmkzhlcaw00ilulbc38pxoogr","Santé","medecins",{"experts":52},5,{"seo_content":54,"id":56,"name":57,"slug":58,"parentId":7,"lang":11,"_count":59},[55],{"page_slug":7},"cmkzhlcmi00izulbcxva1m47f","Gestion de Patrimoine","conseillers-patrimoniaux",{"experts":21},{"seo_content":61,"id":63,"name":64,"slug":65,"parentId":7,"lang":11,"_count":66},[62],{"page_slug":7},"cmkzhldcv00jvulbcmcd5a7mk","Animaux et Vétérinaires","veterinaires",{"experts":21},{"seo_content":68,"id":70,"name":71,"slug":72,"parentId":7,"lang":11,"_count":73},[69],{"page_slug":7},"cmkzhldrr00kdulbchxfo67eg","Mécanique et Réparation","mecaniciens",{"experts":74},1,{"seo_content":76,"id":78,"name":79,"slug":80,"parentId":7,"lang":11,"_count":81},[77],{"page_slug":7},"cmkzhl9l300fbulbcv3i8q8p3","Aide aux Devoirs","professeurs-particuliers",{"experts":82},6,{"slug":84,"title":85,"page_title":86,"description":87,"content_md":88,"local_slug":84,"json_ld":89,"faq":109,"tool_html":140,"source":141,"category":142,"audience":143,"publish_mode":144,"hero_image":145,"hero_image_alt":85},"ccn-ouvriers-des-travaux-publics","CCN des ouvriers des travaux publics — calculateur complet","Calculateur CCN Ouvriers des Travaux Publics IDCC 1702 | Expert Zoom","Outil interactif couvrant l'indemnité de licenciement, le préavis, la grille salariale régionale, les congés d'ancienneté et la période d'essai de la CCN des ouvriers des travaux publics (IDCC 1702).","Ce calculateur couvre les 5 principales dérogations de la convention collective des ouvriers des travaux publics (IDCC 1702) : la formule d'indemnité de licenciement (1\u002F10 puis 3\u002F20 par année), la durée de préavis graduée par ancienneté, la grille salariale régionale avec coefficients 100 à 180, les jours de congés supplémentaires selon l'ancienneté avec prime de vacances à 30 %, et la période d'essai de 2 mois renouvelable.",[90],{"name":91,"@type":92,"about":93,"author":97,"@context":100,"isPartOf":101,"inLanguage":104,"description":105,"operatingSystem":106,"applicationCategory":107,"isAccessibleForFree":108},"Calculateur CCN des ouvriers des travaux publics — IDCC 1702","WebApplication",{"name":94,"@type":95,"identifier":96},"Convention collective des ouvriers des travaux publics","Thing","IDCC 1702",{"name":98,"@type":99},"Expert-Zoom","Organization","https:\u002F\u002Fschema.org",{"url":102,"@type":103},"\u002Ffr\u002Fmagazine\u002Fjuridique\u002Fles-conventions-collectives-en-france","Article","fr","Outil interactif couvrant l'indemnité de licenciement, le préavis, la grille salariale régionale, les congés d'ancienneté et la période d'essai de la convention collective des ouvriers des travaux publics (IDCC 1702).","All","FinanceApplication",true,[110,113,116,119,122,125,128,131,134,137],{"a":111,"q":112},"La CCN IDCC 1702 prévoit une formule spécifique : 1\u002F10 de mois de salaire par année d'ancienneté jusqu'à 5 ans, puis 3\u002F20 de mois par année à partir de 5 ans (appliqué à toute la carrière). Un bonus de 10 % s'ajoute pour les salariés âgés de 55 ans ou plus. En cas de licenciement économique avec au moins 5 ans d'ancienneté, un complément forfaitaire de 35\u002F100 de mois est versé. L'indemnité conventionnelle ne peut jamais être inférieure à l'indemnité légale (art. L1234-9 du Code du travail).","Comment est calculée l'indemnité de licenciement dans la convention collective des ouvriers des travaux publics (IDCC 1702) ?",{"a":114,"q":115},"La durée du préavis est graduée selon l'ancienneté : 2 jours si l'ancienneté est inférieure à 3 mois, 2 semaines entre 3 et 6 mois, 1 mois entre 6 mois et 2 ans, et 2 mois au-delà de 2 ans. Les travailleurs handicapés bénéficient d'un préavis doublé, plafonné à 3 mois. En cas de démission, le préavis est de 2 jours (moins de 3 mois d'ancienneté) ou 2 semaines (au-delà).","Quelle est la durée du préavis en cas de licenciement dans la CCN des ouvriers des travaux publics ?",{"a":117,"q":118},"La CCN IDCC 1702 publie des grilles de salaires minima régionales, organisées en 4 niveaux (I à IV) et 2 positions, avec des coefficients allant de 100 (Niveau I-1) à 180 (Niveau IV-1). À titre d'exemple pour la Bretagne en 2026, le minimum annuel varie de 23 863 € (coeff. 100) à 34 529 € (coeff. 180) pour un temps plein de 35 heures. Ces grilles sont révisées par des avenants régionaux négociés chaque année.","Quelle est la grille des salaires minima des ouvriers des travaux publics en 2026 ?",{"a":120,"q":121},"Oui. En plus des 30 jours ouvrables de congés légaux, la CCN IDCC 1702 accorde des jours de congés d'ancienneté : 2 jours supplémentaires à partir de 20 ans d'ancienneté, 4 jours à partir de 25 ans et 6 jours à partir de 30 ans. Ces jours doivent être pris dans l'année, de préférence pendant les périodes de faible activité, et ne peuvent pas être accolés au congé principal.","Les ouvriers des travaux publics ont-ils droit à des congés supplémentaires au titre de l'ancienneté ?",{"a":123,"q":124},"La prime de vacances est une obligation conventionnelle spécifique aux travaux publics : elle est égale à 30 % de l'indemnité principale de congé (calculée sur 24 jours ouvrables). Elle est due à tout salarié justifiant d'au moins 1 200 heures travaillées durant la période de référence (du 1er mai au 30 avril). Elle est versée en même temps que la paie de vacances, distinctement du salaire.","Qu'est-ce que la prime de vacances prévue par la CCN IDCC 1702 ?",{"a":126,"q":127},"La convention collective fixe la période d'essai à 2 mois pour les ouvriers. Elle peut être renouvelée une seule fois avec l'accord des deux parties, portant la durée maximale à 4 mois. Des délais de prévenance stricts s'appliquent : en cas de rupture par l'employeur, le préavis est de 24 h (moins de 8 jours de présence), 48 h (8 jours à 1 mois), 2 semaines (1 à 3 mois) ou 1 mois (après 3 mois).","Quelle est la durée de la période d'essai pour un ouvrier des travaux publics ?",{"a":129,"q":130},"Non. La CCN des ouvriers des travaux publics n'a pas instauré de dérogation sur les taux de majoration. Les heures supplémentaires sont majorées selon le barème légal : +25 % pour les 8 premières heures supplémentaires (heures 36 à 43), et +50 % pour toute heure au-delà. Le contingent annuel est de 220 heures.","Les taux de majoration des heures supplémentaires sont-ils différents dans la CCN IDCC 1702 ?",{"a":132,"q":133},"La CCN IDCC 1702 ne prévoit pas de 13e mois ou de prime annuelle obligatoire pour les ouvriers. En revanche, la prime de vacances (30 % de l'indemnité de congé) est obligatoire. Un 13e mois peut être accordé par accord d'entreprise ou par usage, mais il ne résulte pas d'une obligation conventionnelle nationale.","Existe-t-il un 13e mois ou une prime annuelle dans la convention collective des ouvriers des travaux publics ?",{"a":135,"q":136},"Oui, la convention collective nationale des ouvriers des travaux publics (brochure JO 3005, tome 2) s'applique à l'ensemble des ouvriers des entreprises relevant du secteur des travaux publics sur tout le territoire français. Les grilles de salaires minima sont toutefois négociées au niveau régional, ce qui introduit des variations de montants selon la région.","La CCN IDCC 1702 s'applique-t-elle à tous les ouvriers des travaux publics en France ?",{"a":138,"q":139},"La base de calcul retient le montant le plus favorable entre : (1) le douzième de la rémunération brute totale des 12 derniers mois précédant le licenciement, et (2) le tiers de la rémunération brute des 3 derniers mois. En cas de temps partiel, l'indemnité est calculée proportionnellement au temps effectivement travaillé par rapport à un temps plein.","Comment est calculée la base salariale pour l'indemnité de licenciement dans la CCN travaux publics ?","\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 Ouvriers des Travaux Publics IDCC 1702\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    :root {\n      --bg: #fafaf9;\n      --surface: #ffffff;\n      --border: #e7e5e4;\n      --accent: #2563eb;\n      --accent-light: #eff6ff;\n      --accent-dark: #1d4ed8;\n      --text: #1c1917;\n      --text-muted: #78716c;\n      --warning-bg: #fffbeb;\n      --warning-border: #fcd34d;\n      --warning-text: #92400e;\n      --success-bg: #f0fdf4;\n      --success-border: #86efac;\n      --success-text: #166534;\n      --info-bg: #eff6ff;\n      --info-border: #93c5fd;\n      --info-text: #1e40af;\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.06);\n    }\n    body {\n      font-family: system-ui, -apple-system, sans-serif;\n      background: var(--bg);\n      color: var(--text);\n      line-height: 1.5;\n      padding: 1rem;\n    }\n    .tool-root { max-width: 720px; margin: 0 auto; }\n\n    \u002F* Header *\u002F\n    .tool-header {\n      background: var(--surface);\n      border: 1px solid var(--border);\n      border-radius: var(--radius);\n      padding: 1.25rem 1.5rem;\n      margin-bottom: 1rem;\n      display: flex;\n      align-items: flex-start;\n      justify-content: space-between;\n      gap: 1rem;\n      box-shadow: var(--shadow);\n    }\n    .tool-header h1 {\n      font-size: 1.125rem;\n      font-weight: 700;\n      color: var(--text);\n      line-height: 1.3;\n    }\n    .tool-header p {\n      font-size: 0.8125rem;\n      color: var(--text-muted);\n      margin-top: 0.25rem;\n    }\n    .idcc-badge {\n      background: var(--accent-light);\n      color: var(--accent);\n      font-size: 0.75rem;\n      font-weight: 700;\n      padding: 0.25rem 0.625rem;\n      border-radius: 999px;\n      white-space: nowrap;\n      border: 1px solid var(--info-border);\n    }\n\n    \u002F* Tabs *\u002F\n    .tabs-nav {\n      display: flex;\n      gap: 0.25rem;\n      background: var(--surface);\n      border: 1px solid var(--border);\n      border-radius: var(--radius) var(--radius) 0 0;\n      padding: 0.5rem 0.5rem 0;\n      overflow-x: auto;\n      scrollbar-width: none;\n    }\n    .tabs-nav::-webkit-scrollbar { display: none; }\n    .tab-btn {\n      display: flex;\n      align-items: center;\n      gap: 0.375rem;\n      padding: 0.5rem 0.875rem;\n      font-size: 0.8125rem;\n      font-weight: 500;\n      color: var(--text-muted);\n      background: transparent;\n      border: none;\n      border-radius: var(--radius-sm) var(--radius-sm) 0 0;\n      cursor: pointer;\n      white-space: nowrap;\n      transition: all 0.15s;\n      position: relative;\n      bottom: -1px;\n    }\n    .tab-btn:hover { color: var(--accent); background: var(--accent-light); }\n    .tab-btn.active {\n      color: var(--accent);\n      background: var(--bg);\n      border: 1px solid var(--border);\n      border-bottom-color: var(--bg);\n      font-weight: 600;\n    }\n    .tab-btn svg { width: 14px; height: 14px; }\n\n    \u002F* Panels *\u002F\n    .tab-panels {\n      background: var(--bg);\n      border: 1px solid var(--border);\n      border-top: none;\n      border-radius: 0 0 var(--radius) var(--radius);\n      padding: 1.25rem;\n    }\n    .tab-panel { display: none; }\n    .tab-panel.active { display: block; }\n\n    \u002F* Rule callout *\u002F\n    .rule-callout {\n      display: flex;\n      gap: 0.75rem;\n      align-items: flex-start;\n      background: var(--info-bg);\n      border: 1px solid var(--info-border);\n      border-radius: var(--radius-sm);\n      padding: 0.875rem 1rem;\n      margin-bottom: 1.25rem;\n    }\n    .rule-callout svg { color: var(--accent); flex-shrink: 0; margin-top: 0.125rem; width: 16px; height: 16px; }\n    .rule-callout p { font-size: 0.875rem; color: var(--info-text); line-height: 1.55; }\n    .rule-callout strong { font-weight: 700; }\n\n    \u002F* Form *\u002F\n    .form-grid {\n      display: grid;\n      grid-template-columns: 1fr 1fr;\n      gap: 1rem;\n      margin-bottom: 1.25rem;\n    }\n    @media (max-width: 520px) { .form-grid { grid-template-columns: 1fr; } }\n    .form-group { display: flex; flex-direction: column; gap: 0.375rem; }\n    .form-group.full { grid-column: 1 \u002F -1; }\n    label {\n      font-size: 0.8125rem;\n      font-weight: 600;\n      color: var(--text);\n    }\n    .label-hint { font-weight: 400; color: var(--text-muted); font-size: 0.75rem; margin-left: 0.25rem; }\n    input[type=\"range\"] {\n      width: 100%;\n      accent-color: var(--accent);\n      cursor: pointer;\n      height: 4px;\n    }\n    .range-val {\n      font-size: 0.8125rem;\n      font-weight: 600;\n      color: var(--accent);\n      font-variant-numeric: tabular-nums;\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      background: var(--surface);\n      font-size: 0.875rem;\n      color: var(--text);\n      cursor: pointer;\n    }\n    select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }\n\n    \u002F* Pills *\u002F\n    .pills { display: flex; flex-wrap: wrap; gap: 0.375rem; }\n    .pill {\n      padding: 0.375rem 0.75rem;\n      border: 1.5px solid var(--border);\n      border-radius: 999px;\n      font-size: 0.8125rem;\n      cursor: pointer;\n      transition: all 0.12s;\n      background: var(--surface);\n      color: var(--text-muted);\n      font-weight: 500;\n    }\n    .pill.selected {\n      background: var(--accent);\n      border-color: var(--accent);\n      color: #fff;\n    }\n    .pill:hover:not(.selected) { border-color: var(--accent); color: var(--accent); }\n\n    \u002F* Toggle *\u002F\n    .toggle-wrap { display: flex; align-items: center; gap: 0.625rem; }\n    .toggle {\n      position: relative; width: 38px; height: 22px; cursor: pointer;\n      display: inline-block;\n    }\n    .toggle input { opacity: 0; width: 0; height: 0; }\n    .toggle-track {\n      position: absolute; inset: 0; background: var(--border);\n      border-radius: 999px; transition: background 0.2s;\n    }\n    .toggle input:checked + .toggle-track { background: var(--accent); }\n    .toggle-thumb {\n      position: absolute; top: 3px; left: 3px;\n      width: 16px; height: 16px; background: #fff;\n      border-radius: 50%; transition: left 0.2s;\n    }\n    .toggle input:checked ~ .toggle-thumb { left: 19px; }\n    .toggle-label { font-size: 0.875rem; color: var(--text); }\n\n    \u002F* Result *\u002F\n    .result-card {\n      background: var(--surface);\n      border: 2px solid var(--accent);\n      border-radius: var(--radius);\n      padding: 1.25rem 1.5rem;\n      margin-top: 0.5rem;\n    }\n    .result-label { font-size: 0.8125rem; color: var(--text-muted); font-weight: 500; }\n    .result-value {\n      font-size: 1.875rem;\n      font-weight: 800;\n      color: var(--accent);\n      font-variant-numeric: tabular-nums;\n      line-height: 1.2;\n      margin: 0.25rem 0;\n    }\n    .result-detail { font-size: 0.8125rem; color: var(--text-muted); line-height: 1.6; }\n    .result-detail strong { color: var(--text); font-weight: 600; }\n    .result-compare {\n      display: flex;\n      gap: 0.5rem;\n      align-items: flex-start;\n      margin-top: 0.75rem;\n      padding-top: 0.75rem;\n      border-top: 1px solid var(--border);\n    }\n    .result-compare svg { color: var(--success-text); flex-shrink: 0; margin-top: 2px; width: 14px; height: 14px; }\n    .result-compare p { font-size: 0.8125rem; color: var(--success-text); }\n\n    \u002F* Salary table *\u002F\n    .salary-table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; margin-top: 0.75rem; }\n    .salary-table th {\n      background: var(--accent-light);\n      color: var(--accent-dark);\n      font-weight: 600;\n      padding: 0.5rem 0.75rem;\n      text-align: left;\n      border-bottom: 2px solid var(--info-border);\n    }\n    .salary-table td {\n      padding: 0.5rem 0.75rem;\n      border-bottom: 1px solid var(--border);\n      font-variant-numeric: tabular-nums;\n    }\n    .salary-table tr:last-child td { border-bottom: none; }\n    .salary-table tr.highlighted td { background: var(--accent-light); font-weight: 700; color: var(--accent-dark); }\n\n    \u002F* Conges specific *\u002F\n    .conges-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; margin-top: 0.75rem; }\n    @media (max-width: 520px) { .conges-grid { grid-template-columns: 1fr; } }\n    .conges-card {\n      background: var(--surface);\n      border: 1px solid var(--border);\n      border-radius: var(--radius-sm);\n      padding: 0.75rem;\n      text-align: center;\n    }\n    .conges-card .val { font-size: 1.5rem; font-weight: 800; color: var(--accent); font-variant-numeric: tabular-nums; }\n    .conges-card .lbl { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.125rem; }\n\n    \u002F* Disclaimer *\u002F\n    .disclaimer {\n      margin-top: 1.5rem;\n      padding: 0.875rem 1rem;\n      background: var(--warning-bg);\n      border: 1px solid var(--warning-border);\n      border-radius: var(--radius-sm);\n      font-size: 0.8rem;\n      color: var(--warning-text);\n      line-height: 1.55;\n    }\n    .disclaimer a { color: var(--warning-text); font-weight: 600; }\n  \u003C\u002Fstyle>\n\u003C\u002Fhead>\n\u003Cbody>\n\u003C!-- CCN IDCC 1702 — Ouvriers des travaux publics — deviations detected\n     indemnite: L1234-9 → formule 1\u002F10+3\u002F20 avec bonus âge 55+ et licenciement économique (art. 30 CCN)\n     preavis: L1234-1 → durées graduées par ancienneté : 2j \u002F 2sem \u002F 1mois \u002F 2mois (art. 10.1 CCN)\n     salaire-min: Grille régionale 7 niveaux coeff. 100-180 (avenants régionaux 2026)\n     conges: L3141-3 → jours d'ancienneté +2\u002F+4\u002F+6 j à 20\u002F25\u002F30 ans + prime de vacances 30% (art. 5.7 CCN)\n     periode-essai: Initialement 2 mois renouvelables 1 fois (max 4 mois) vs. durée légale non précisée pour ouvriers\n     heures-supp: aligné L3121-36 (25%\u002F50%) — SKIP\n     13e-mois: non prévu par la CCN — SKIP\n-->\n\u003Cdiv class=\"tool-root\">\n  \u003Cdiv class=\"tool-header\">\n    \u003Cdiv>\n      \u003Ch1>Convention collective des ouvriers des travaux publics\u003C\u002Fh1>\n      \u003Cp>Calculateur interactif — indemnité, préavis, grille salariale, congés, période d'essai\u003C\u002Fp>\n    \u003C\u002Fdiv>\n    \u003Cspan class=\"idcc-badge\">IDCC 1702\u003C\u002Fspan>\n  \u003C\u002Fdiv>\n\n  \u003Cdiv class=\"tabs-nav\">\n    \u003Cbutton class=\"tab-btn\" data-tab=\"indemnite\">\n      \u003Ci data-lucide=\"coins\">\u003C\u002Fi> Indemnité\n    \u003C\u002Fbutton>\n    \u003Cbutton class=\"tab-btn\" data-tab=\"preavis\">\n      \u003Ci data-lucide=\"clock\">\u003C\u002Fi> Préavis\n    \u003C\u002Fbutton>\n    \u003Cbutton class=\"tab-btn\" data-tab=\"salaire-min\">\n      \u003Ci data-lucide=\"bar-chart-2\">\u003C\u002Fi> Grille salariale\n    \u003C\u002Fbutton>\n    \u003Cbutton class=\"tab-btn\" data-tab=\"conges\">\n      \u003Ci data-lucide=\"calendar\">\u003C\u002Fi> Congés\n    \u003C\u002Fbutton>\n    \u003Cbutton class=\"tab-btn\" data-tab=\"periode-essai\">\n      \u003Ci data-lucide=\"user-check\">\u003C\u002Fi> Essai\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\n  \u003Cdiv class=\"tab-panels\">\n\n    \u003C!-- TAB: INDEMNITÉ DE LICENCIEMENT -->\n    \u003Cdiv class=\"tab-panel\" data-panel=\"indemnite\">\n      \u003Cdiv class=\"rule-callout\">\n        \u003Ci data-lucide=\"info\">\u003C\u002Fi>\n        \u003Cp>La CCN IDCC 1702 prévoit une formule spécifique : \u003Cstrong>1\u002F10 de mois par année jusqu'à 5 ans\u003C\u002Fstrong>, puis \u003Cstrong>3\u002F20 de mois par année\u003C\u002Fstrong> à partir de 5 ans. Un bonus de \u003Cstrong>+10 %\u003C\u002Fstrong> s'applique dès 55 ans. En cas de licenciement économique avec 5+ ans d'ancienneté, un complément forfaitaire de 35\u002F100 de mois est ajouté.\u003C\u002Fp>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form-grid\">\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Salaire brut mensuel \u003Cspan class=\"label-hint\">(dernier mois ou moy. 12 mois)\u003C\u002Fspan>\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"ind-salaire\" min=\"1600\" max=\"8000\" step=\"50\" value=\"2800\">\n          \u003Cspan class=\"range-val\" id=\"ind-salaire-val\">2 800 €\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Ancienneté\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"ind-anciennete\" min=\"0\" max=\"40\" step=\"1\" value=\"8\">\n          \u003Cspan class=\"range-val\" id=\"ind-anciennete-val\">8 ans\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Motif du licenciement\u003C\u002Flabel>\n          \u003Cdiv class=\"pills\" id=\"ind-motif\">\n            \u003Cdiv class=\"pill selected\" data-val=\"perso\">Personnel\u003C\u002Fdiv>\n            \u003Cdiv class=\"pill\" data-val=\"eco\">Économique\u003C\u002Fdiv>\n            \u003Cdiv class=\"pill\" data-val=\"inaptitude\">Inaptitude\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Âge du salarié\u003C\u002Flabel>\n          \u003Cdiv class=\"pills\" id=\"ind-age\">\n            \u003Cdiv class=\"pill selected\" data-val=\"lt55\">Moins de 55 ans\u003C\u002Fdiv>\n            \u003Cdiv class=\"pill\" data-val=\"gte55\">55 ans ou plus\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-card\" id=\"ind-result\">\n        \u003Cdiv class=\"result-label\">Indemnité conventionnelle estimée\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-value\" id=\"ind-montant\">–\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-detail\" id=\"ind-detail\">\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-compare\">\n          \u003Ci data-lucide=\"trending-up\">\u003C\u002Fi>\n          \u003Cp id=\"ind-compare\">\u003C\u002Fp>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003C!-- TAB: PRÉAVIS -->\n    \u003Cdiv class=\"tab-panel\" data-panel=\"preavis\">\n      \u003Cdiv class=\"rule-callout\">\n        \u003Ci data-lucide=\"info\">\u003C\u002Fi>\n        \u003Cp>La CCN fixe des durées de préavis \u003Cstrong>graduées par ancienneté\u003C\u002Fstrong> en cas de licenciement : de 2 jours (ancienneté \u003C 3 mois) jusqu'à \u003Cstrong>2 mois\u003C\u002Fstrong> (+ de 2 ans). Les salariés reconnus travailleurs handicapés bénéficient d'un préavis doublé, plafonné à 3 mois.\u003C\u002Fp>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form-grid\">\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Type de rupture\u003C\u002Flabel>\n          \u003Cdiv class=\"pills\" id=\"pre-type\">\n            \u003Cdiv class=\"pill selected\" data-val=\"licenciement\">Licenciement\u003C\u002Fdiv>\n            \u003Cdiv class=\"pill\" data-val=\"demission\">Démission\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Statut\u003C\u002Flabel>\n          \u003Cdiv class=\"pills\" id=\"pre-statut\">\n            \u003Cdiv class=\"pill selected\" data-val=\"normal\">Standard\u003C\u002Fdiv>\n            \u003Cdiv class=\"pill\" data-val=\"th\">Trav. handicapé\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Ancienneté\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"pre-anciennete\" min=\"0\" max=\"240\" step=\"1\" value=\"24\">\n          \u003Cspan class=\"range-val\" id=\"pre-anciennete-val\">24 mois\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-card\" id=\"pre-result\">\n        \u003Cdiv class=\"result-label\">Durée du préavis\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-value\" id=\"pre-duree\">–\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-detail\" id=\"pre-detail\">\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-compare\">\n          \u003Ci data-lucide=\"info\">\u003C\u002Fi>\n          \u003Cp id=\"pre-heures\">\u003C\u002Fp>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003C!-- TAB: GRILLE SALARIALE -->\n    \u003Cdiv class=\"tab-panel\" data-panel=\"salaire-min\">\n      \u003Cdiv class=\"rule-callout\">\n        \u003Ci data-lucide=\"info\">\u003C\u002Fi>\n        \u003Cp>La CCN publie des \u003Cstrong>grilles régionales\u003C\u002Fstrong> de salaires minima par niveau (I à IV) et position (1 ou 2), avec des coefficients allant de 100 à 180. Ces minima conventionnels sont \u003Cstrong>supérieurs au SMIC\u003C\u002Fstrong> pour les niveaux supérieurs.\u003C\u002Fp>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form-grid\">\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Niveau et position\u003C\u002Flabel>\n          \u003Cselect id=\"sal-niveau\">\n            \u003Coption value=\"I-1\">Niveau I – Position 1 (coeff. 100)\u003C\u002Foption>\n            \u003Coption value=\"I-2\">Niveau I – Position 2 (coeff. 110)\u003C\u002Foption>\n            \u003Coption value=\"II-1\">Niveau II – Position 1 (coeff. 125)\u003C\u002Foption>\n            \u003Coption value=\"II-2\">Niveau II – Position 2 (coeff. 140)\u003C\u002Foption>\n            \u003Coption value=\"III-1\">Niveau III – Position 1 (coeff. 150)\u003C\u002Foption>\n            \u003Coption value=\"III-2\">Niveau III – Position 2 (coeff. 165)\u003C\u002Foption>\n            \u003Coption value=\"IV-1\">Niveau IV – Position 1 (coeff. 180)\u003C\u002Foption>\n          \u003C\u002Fselect>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Heures hebdomadaires\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"sal-heures\" min=\"24\" max=\"44\" step=\"1\" value=\"35\">\n          \u003Cspan class=\"range-val\" id=\"sal-heures-val\">35 h\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Région (référence)\u003C\u002Flabel>\n          \u003Cselect id=\"sal-region\">\n            \u003Coption value=\"bretagne\">Bretagne\u003C\u002Foption>\n            \u003Coption value=\"idf\">Île-de-France\u003C\u002Foption>\n            \u003Coption value=\"normandie\">Normandie\u003C\u002Foption>\n            \u003Coption value=\"grand-est\">Grand Est\u003C\u002Foption>\n            \u003Coption value=\"occitanie\">Occitanie\u003C\u002Foption>\n          \u003C\u002Fselect>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-card\" id=\"sal-result\">\n        \u003Cdiv class=\"result-label\">Salaire minimum conventionnel brut (2026)\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-value\" id=\"sal-montant\">–\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-detail\" id=\"sal-detail\">\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003C!-- TAB: CONGÉS -->\n    \u003Cdiv class=\"tab-panel\" data-panel=\"conges\">\n      \u003Cdiv class=\"rule-callout\">\n        \u003Ci data-lucide=\"info\">\u003C\u002Fi>\n        \u003Cp>En plus des 30 jours ouvrables légaux, la CCN accorde des \u003Cstrong>jours d'ancienneté\u003C\u002Fstrong> (+2 j à 20 ans, +4 j à 25 ans, +6 j à 30 ans). Une \u003Cstrong>prime de vacances\u003C\u002Fstrong> égale à 30 % de l'indemnité principale de congé est versée à tout salarié justifiant d'au moins 1 200 heures travaillées sur l'année de référence.\u003C\u002Fp>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form-grid\">\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Ancienneté\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"con-anciennete\" min=\"0\" max=\"35\" step=\"1\" value=\"10\">\n          \u003Cspan class=\"range-val\" id=\"con-anciennete-val\">10 ans\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group\">\n          \u003Clabel>Salaire brut mensuel\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"con-salaire\" min=\"1600\" max=\"6000\" step=\"50\" value=\"2500\">\n          \u003Cspan class=\"range-val\" id=\"con-salaire-val\">2 500 €\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Heures travaillées sur l'année de référence\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"con-heures\" min=\"0\" max=\"2080\" step=\"10\" value=\"1400\">\n          \u003Cspan class=\"range-val\" id=\"con-heures-val\">1 400 h\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"conges-grid\" id=\"con-grid\">\n        \u003Cdiv class=\"conges-card\">\n          \u003Cdiv class=\"val\" id=\"con-jours-legaux\">30\u003C\u002Fdiv>\n          \u003Cdiv class=\"lbl\">Jours légaux\u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"conges-card\">\n          \u003Cdiv class=\"val\" id=\"con-jours-anciennete\">0\u003C\u002Fdiv>\n          \u003Cdiv class=\"lbl\">Jours ancienneté\u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"conges-card\">\n          \u003Cdiv class=\"val\" id=\"con-jours-total\">30\u003C\u002Fdiv>\n          \u003Cdiv class=\"lbl\">Total jours\u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-card\" id=\"con-result\" style=\"margin-top:1rem\">\n        \u003Cdiv class=\"result-label\">Prime de vacances conventionnelle\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-value\" id=\"con-prime\">–\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-detail\" id=\"con-detail\">\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003C!-- TAB: PÉRIODE D'ESSAI -->\n    \u003Cdiv class=\"tab-panel\" data-panel=\"periode-essai\">\n      \u003Cdiv class=\"rule-callout\">\n        \u003Ci data-lucide=\"info\">\u003C\u002Fi>\n        \u003Cp>La CCN fixe la période d'essai des ouvriers à \u003Cstrong>2 mois\u003C\u002Fstrong>, renouvelable une fois avec accord des deux parties, pour un maximum de \u003Cstrong>4 mois\u003C\u002Fstrong>. Des délais de prévenance stricts s'appliquent en cas de rupture pendant l'essai.\u003C\u002Fp>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form-grid\">\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Renouvellement de la période d'essai\u003C\u002Flabel>\n          \u003Cdiv class=\"pills\" id=\"ess-renouvellement\">\n            \u003Cdiv class=\"pill selected\" data-val=\"non\">Non renouvelée\u003C\u002Fdiv>\n            \u003Cdiv class=\"pill\" data-val=\"oui\">Renouvelée (1 fois)\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Temps écoulé depuis le début de l'essai\u003C\u002Flabel>\n          \u003Cinput type=\"range\" id=\"ess-jours\" min=\"0\" max=\"120\" step=\"1\" value=\"30\">\n          \u003Cspan class=\"range-val\" id=\"ess-jours-val\">30 jours\u003C\u002Fspan>\n        \u003C\u002Fdiv>\n        \u003Cdiv class=\"form-group full\">\n          \u003Clabel>Auteur de la rupture\u003C\u002Flabel>\n          \u003Cdiv class=\"pills\" id=\"ess-auteur\">\n            \u003Cdiv class=\"pill selected\" data-val=\"employeur\">Employeur\u003C\u002Fdiv>\n            \u003Cdiv class=\"pill\" data-val=\"salarie\">Salarié\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"result-card\" id=\"ess-result\">\n        \u003Cdiv class=\"result-label\">Durée maximale de la période d'essai\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-value\" id=\"ess-duree\">–\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-detail\" id=\"ess-detail\">\u003C\u002Fdiv>\n        \u003Cdiv class=\"result-compare\">\n          \u003Ci data-lucide=\"bell\">\u003C\u002Fi>\n          \u003Cp id=\"ess-prevenance\">\u003C\u002Fp>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n  \u003C\u002Fdiv>\u003C!-- \u002Ftab-panels -->\n\n  \u003Cp class=\"disclaimer\">\n    \u003Ci data-lucide=\"triangle-alert\" style=\"display:inline;vertical-align:-3px;width:14px;height:14px;margin-right:4px;\">\u003C\u002Fi>\n    Calcul indicatif basé sur la CCN IDCC 1702 (ouvriers des travaux publics) et les avenants en vigueur en 2026.\n    Source : \u003Ca href=\"https:\u002F\u002Fwww.legifrance.gouv.fr\u002Fconv_coll\u002Fid\u002FKALISCTA000005704263\u002F\" target=\"_blank\" rel=\"noopener\">Legifrance\u003C\u002Fa>.\n    Les grilles salariales varient par région. Pour validation légale\n  \u003C\u002Fp>\n\u003C\u002Fdiv>\n\n\u003Cscript>\n(function () {\n  'use strict';\n\n  \u002F\u002F ── Formatters ──────────────────────────────────────────────────────────────\n  const fmtEur = v => new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(v);\n  const fmtNum = v => new Intl.NumberFormat('fr-FR').format(v);\n\n  \u002F\u002F ── State ────────────────────────────────────────────────────────────────────\n  const state = {\n    ind: { salaire: 2800, anciennete: 8, motif: 'perso', age: 'lt55' },\n    pre: { type: 'licenciement', statut: 'normal', anciennete: 24 },\n    sal: { niveau: 'I-1', heures: 35, region: 'bretagne' },\n    con: { anciennete: 10, salaire: 2500, heures: 1400 },\n    ess: { renouvellement: 'non', jours: 30, auteur: 'employeur' },\n  };\n\n  \u002F\u002F ── Salary grid data (annual 35h reference, 2026) ───────────────────────────\n  \u002F\u002F Values per region (annual gross minimum)\n  const SALAIRES = {\n    bretagne: { 'I-1': 23863, 'I-2': 24133, 'II-1': 24621, 'II-2': 27126, 'III-1': 29020, 'III-2': 31711, 'IV-1': 34529 },\n    idf:      { 'I-1': 23709, 'I-2': 24021, 'II-1': 24560, 'II-2': 27200, 'III-1': 29180, 'III-2': 31900, 'IV-1': 34569 },\n    normandie:{ 'I-1': 23462, 'I-2': 23771, 'II-1': 24250, 'II-2': 26800, 'III-1': 28700, 'III-2': 31350, 'IV-1': 34634 },\n    'grand-est':{ 'I-1': 23294, 'I-2': 23580, 'II-1': 24050, 'II-2': 26450, 'III-1': 28350, 'III-2': 30950, 'IV-1': 33525 },\n    occitanie:{ 'I-1': 23160, 'I-2': 23450, 'II-1': 23950, 'II-2': 26400, 'III-1': 28250, 'III-2': 30820, 'IV-1': 33928 },\n  };\n  const COEFF_LABELS = { 'I-1': 100, 'I-2': 110, 'II-1': 125, 'II-2': 140, 'III-1': 150, 'III-2': 165, 'IV-1': 180 };\n  const SMIC_ANNUAL_35H = 21203; \u002F\u002F SMIC 2026 approximation (11.88 × 35 × 52)\n\n  \u002F\u002F ── Compute indemnité ────────────────────────────────────────────────────────\n  function computeIndemnite(s) {\n    if (s.anciennete \u003C 1) return null;\n    \u002F\u002F CCN formula: 1\u002F10 per year for first 5 years, then 3\u002F20 per year from year 1\n    let base = 0;\n    if (s.anciennete \u003C= 5) {\n      base = s.salaire * (1 \u002F 10) * s.anciennete;\n    } else {\n      \u002F\u002F 3\u002F20 applied to all years once threshold passed\n      base = s.salaire * (3 \u002F 20) * s.anciennete;\n    }\n    \u002F\u002F Age bonus: +10% if ≥55\n    let ageBonus = s.age === 'gte55' ? base * 0.10 : 0;\n    \u002F\u002F Economic dismissal supplement for 5+ years\n    let ecoSupplement = 0;\n    if (s.motif === 'eco' && s.anciennete >= 5) {\n      ecoSupplement = s.salaire * (35 \u002F 100);\n    } else if (s.motif === 'eco' && s.anciennete >= 2) {\n      ecoSupplement = base * 0.70; \u002F\u002F 70% of base\n    }\n    const total = base + ageBonus + ecoSupplement;\n\n    \u002F\u002F Baseline comparison (L1234-9)\n    let baseline = 0;\n    if (s.anciennete \u003C= 10) {\n      baseline = s.salaire * (1 \u002F 4) * s.anciennete;\n    } else {\n      baseline = s.salaire * (1 \u002F 4) * 10 + s.salaire * (1 \u002F 3) * (s.anciennete - 10);\n    }\n\n    return { base, ageBonus, ecoSupplement, total, baseline };\n  }\n\n  function renderIndemnite() {\n    const s = state.ind;\n    const r = computeIndemnite(s);\n    if (!r) {\n      document.getElementById('ind-montant').textContent = 'Ancienneté insuffisante (\u003C 1 an)';\n      document.getElementById('ind-detail').textContent = '';\n      document.getElementById('ind-compare').textContent = '';\n      return;\n    }\n    document.getElementById('ind-montant').textContent = fmtEur(r.total);\n    let detail = `Base CCN : ${fmtEur(r.base)}`;\n    if (r.ageBonus > 0) detail += ` · Bonus 55+ : +${fmtEur(r.ageBonus)}`;\n    if (r.ecoSupplement > 0) detail += ` · Complément éco : +${fmtEur(r.ecoSupplement)}`;\n    document.getElementById('ind-detail').innerHTML = `\u003Cstrong>${detail}\u003C\u002Fstrong>`;\n    const diff = r.total - r.baseline;\n    const sign = diff >= 0 ? '+' : '';\n    document.getElementById('ind-compare').textContent =\n      `Indemnité légale (L1234-9) : ${fmtEur(r.baseline)} — Écart CCN : ${sign}${fmtEur(diff)}`;\n  }\n\n  \u002F\u002F ── Compute préavis ──────────────────────────────────────────────────────────\n  function computePreavis(s) {\n    let duree, unite, heures = '';\n    if (s.type === 'licenciement') {\n      if (s.anciennete \u003C 3) { duree = 2; unite = 'jours'; heures = ''; }\n      else if (s.anciennete \u003C 6) { duree = 2; unite = 'semaines'; heures = '12 h pour recherche d\\'emploi'; }\n      else if (s.anciennete \u003C 24) { duree = 1; unite = 'mois'; heures = '25 h pour recherche d\\'emploi'; }\n      else { duree = 2; unite = 'mois'; heures = '25 h pour recherche d\\'emploi'; }\n      if (s.statut === 'th') {\n        \u002F\u002F Double, max 3 months\n        if (unite === 'jours') { duree = 4; }\n        else if (unite === 'semaines') { duree = 4; }\n        else { duree = Math.min(duree * 2, 3); }\n      }\n    } else {\n      \u002F\u002F démission\n      if (s.anciennete \u003C 3) { duree = 2; unite = 'jours'; }\n      else { duree = 2; unite = 'semaines'; }\n      heures = 'Pas d\\'heures de recherche d\\'emploi lors d\\'une démission';\n    }\n    return { duree, unite, heures };\n  }\n\n  function renderPreavis() {\n    const s = state.pre;\n    const r = computePreavis(s);\n    document.getElementById('pre-duree').textContent = `${fmtNum(r.duree)} ${r.unite}`;\n    const ancMois = s.anciennete;\n    let tranche = ancMois \u003C 3 ? '0-3 mois' : ancMois \u003C 6 ? '3-6 mois' : ancMois \u003C 24 ? '6 mois-2 ans' : '+ 2 ans';\n    document.getElementById('pre-detail').innerHTML =\n      `\u003Cstrong>Tranche d'ancienneté :\u003C\u002Fstrong> ${tranche}${s.statut === 'th' ? ' · Doublement TH appliqué (max 3 mois)' : ''}`;\n    document.getElementById('pre-heures').textContent = r.heures || 'Aucune heure de recherche d\\'emploi sur cette tranche';\n  }\n\n  \u002F\u002F ── Compute grille salariale ─────────────────────────────────────────────────\n  function computeSalaire(s) {\n    const annuel = SALAIRES[s.region]?.[s.niveau] ?? 23863;\n    const mensuel = annuel \u002F 12;\n    \u002F\u002F Adjust for hours (linear prorata)\n    const mensuelAdj = mensuel * (s.heures \u002F 35);\n    const horaire = mensuelAdj \u002F (s.heures * 52 \u002F 12);\n    const coeff = COEFF_LABELS[s.niveau];\n    return { annuel, mensuel: mensuelAdj, horaire, coeff };\n  }\n\n  function renderSalaire() {\n    const s = state.sal;\n    const r = computeSalaire(s);\n    document.getElementById('sal-montant').textContent = fmtEur(r.mensuel) + '\u002Fmois';\n    const aboveSmic = r.annuel > SMIC_ANNUAL_35H\n      ? `+${fmtEur(r.annuel - SMIC_ANNUAL_35H)} au-dessus du SMIC annuel`\n      : 'Proche du SMIC — vérifier le minimum légal';\n    document.getElementById('sal-detail').innerHTML =\n      `\u003Cstrong>Annuel brut :\u003C\u002Fstrong> ${fmtEur(r.annuel)} · \u003Cstrong>Horaire :\u003C\u002Fstrong> ${r.horaire.toFixed(2)} €\u002Fh · Coefficient ${r.coeff}\u003Cbr>${aboveSmic}`;\n  }\n\n  \u002F\u002F ── Compute congés ───────────────────────────────────────────────────────────\n  function computeConges(s) {\n    const joursLegaux = 30;\n    let joursAnc = 0;\n    if (s.anciennete >= 30) joursAnc = 6;\n    else if (s.anciennete >= 25) joursAnc = 4;\n    else if (s.anciennete >= 20) joursAnc = 2;\n    const total = joursLegaux + joursAnc;\n    \u002F\u002F Prime de vacances: 30% of 24j vacation pay, only if ≥1200h\n    const eligible = s.heures >= 1200;\n    \u002F\u002F Vacation pay basis: 10% of annual salary prorated to 24\u002Ftotal days\n    const indemniteBase = (s.salaire * 12) * 0.10 * (24 \u002F total);\n    const prime = eligible ? indemniteBase * 0.30 : 0;\n    return { joursLegaux, joursAnc, total, prime, eligible };\n  }\n\n  function renderConges() {\n    const s = state.con;\n    const r = computeConges(s);\n    document.getElementById('con-jours-legaux').textContent = r.joursLegaux;\n    document.getElementById('con-jours-anciennete').textContent = r.joursAnc;\n    document.getElementById('con-jours-total').textContent = r.total;\n    document.getElementById('con-prime').textContent = r.eligible ? fmtEur(r.prime) : 'Non éligible';\n    const msg = r.eligible\n      ? `30 % de l'indemnité principale de congé (24 j de base). Salaire annuel de référence : ${fmtEur(s.salaire * 12)}.`\n      : `Seuil de 1 200 heures non atteint (${fmtNum(s.heures)} h). La prime de vacances n'est pas due.`;\n    document.getElementById('con-detail').textContent = msg;\n  }\n\n  \u002F\u002F ── Compute période d'essai ──────────────────────────────────────────────────\n  function computeEssai(s) {\n    const dureeMax = s.renouvellement === 'oui' ? 4 : 2; \u002F\u002F mois\n    const dureeMaxJ = dureeMax * 30;\n\n    \u002F\u002F Délai de prévenance\n    let prevenance = '';\n    const j = s.jours;\n    if (s.auteur === 'employeur') {\n      if (j \u003C= 7) prevenance = '24 heures';\n      else if (j \u003C= 30) prevenance = '48 heures';\n      else if (j \u003C= 90) prevenance = '2 semaines';\n      else prevenance = '1 mois';\n    } else {\n      if (j \u003C= 7) prevenance = '24 heures';\n      else prevenance = '48 heures';\n    }\n    const enCours = j \u003C= dureeMaxJ;\n    return { dureeMax, dureeMaxJ, prevenance, enCours };\n  }\n\n  function renderEssai() {\n    const s = state.ess;\n    const r = computeEssai(s);\n    document.getElementById('ess-duree').textContent = `${r.dureeMax} mois maximum`;\n    const statut = r.enCours\n      ? `Période en cours — ${r.dureeMaxJ - s.jours} jour(s) restant(s) sur ${r.dureeMaxJ} jours.`\n      : `Période d'essai dépassée (${s.jours} j > ${r.dureeMaxJ} j max). Le salarié est considéré confirmé.`;\n    document.getElementById('ess-detail').innerHTML = `\u003Cstrong>${statut}\u003C\u002Fstrong>`;\n    document.getElementById('ess-prevenance').textContent =\n      `Délai de prévenance avant rupture par ${s.auteur === 'employeur' ? \"l'employeur\" : 'le salarié'} : ${r.prevenance}`;\n  }\n\n  \u002F\u002F ── Renderers map ────────────────────────────────────────────────────────────\n  const renderers = { indemnite: renderIndemnite, preavis: renderPreavis, 'salaire-min': renderSalaire, conges: renderConges, 'periode-essai': renderEssai };\n\n  \u002F\u002F ── Generic helpers ──────────────────────────────────────────────────────────\n  function bindRange(id, stateKey, subKey, valId, fmt, render) {\n    const el = document.getElementById(id);\n    el.addEventListener('input', () => {\n      state[stateKey][subKey] = +el.value;\n      document.getElementById(valId).textContent = fmt(+el.value);\n      render();\n    });\n    document.getElementById(valId).textContent = fmt(+el.value);\n  }\n\n  function bindPills(containerId, stateKey, subKey, render) {\n    const container = document.getElementById(containerId);\n    if (!container) return;\n    container.querySelectorAll('.pill').forEach(p => {\n      p.addEventListener('click', () => {\n        container.querySelectorAll('.pill').forEach(x => x.classList.remove('selected'));\n        p.classList.add('selected');\n        state[stateKey][subKey] = p.dataset.val;\n        render();\n      });\n    });\n  }\n\n  function bindSelect(id, stateKey, subKey, render) {\n    const el = document.getElementById(id);\n    el.addEventListener('change', () => {\n      state[stateKey][subKey] = el.value;\n      render();\n    });\n  }\n\n  \u002F\u002F ── Bind indemnité inputs ────────────────────────────────────────────────────\n  bindRange('ind-salaire', 'ind', 'salaire', 'ind-salaire-val', v => fmtEur(v), renderIndemnite);\n  bindRange('ind-anciennete', 'ind', 'anciennete', 'ind-anciennete-val', v => `${v} an${v > 1 ? 's' : ''}`, renderIndemnite);\n  bindPills('ind-motif', 'ind', 'motif', renderIndemnite);\n  bindPills('ind-age', 'ind', 'age', renderIndemnite);\n\n  \u002F\u002F ── Bind préavis inputs ──────────────────────────────────────────────────────\n  bindPills('pre-type', 'pre', 'type', renderPreavis);\n  bindPills('pre-statut', 'pre', 'statut', renderPreavis);\n  bindRange('pre-anciennete', 'pre', 'anciennete', 'pre-anciennete-val', v => `${v} mois`, renderPreavis);\n\n  \u002F\u002F ── Bind grille salariale inputs ─────────────────────────────────────────────\n  bindSelect('sal-niveau', 'sal', 'niveau', renderSalaire);\n  bindRange('sal-heures', 'sal', 'heures', 'sal-heures-val', v => `${v} h`, renderSalaire);\n  bindSelect('sal-region', 'sal', 'region', renderSalaire);\n\n  \u002F\u002F ── Bind congés inputs ───────────────────────────────────────────────────────\n  bindRange('con-anciennete', 'con', 'anciennete', 'con-anciennete-val', v => `${v} ans`, renderConges);\n  bindRange('con-salaire', 'con', 'salaire', 'con-salaire-val', v => fmtEur(v), renderConges);\n  bindRange('con-heures', 'con', 'heures', 'con-heures-val', v => `${fmtNum(v)} h`, renderConges);\n\n  \u002F\u002F ── Bind période d'essai inputs ──────────────────────────────────────────────\n  bindPills('ess-renouvellement', 'ess', 'renouvellement', renderEssai);\n  bindRange('ess-jours', 'ess', 'jours', 'ess-jours-val', v => `${v} jours`, renderEssai);\n  bindPills('ess-auteur', 'ess', 'auteur', renderEssai);\n\n  \u002F\u002F ── Tabs ─────────────────────────────────────────────────────────────────────\n  const tabBtns = document.querySelectorAll('[data-tab]');\n  const tabPanels = document.querySelectorAll('[data-panel]');\n\n  function activate(id) {\n    tabBtns.forEach(t => t.classList.toggle('active', t.dataset.tab === id));\n    tabPanels.forEach(p => p.classList.toggle('active', p.dataset.panel === id));\n    if (location.hash !== '#' + id) location.hash = id;\n    if (renderers[id]) renderers[id]();\n    requestAnimationFrame(() => window.dispatchEvent(new Event('resize')));\n  }\n\n  tabBtns.forEach(t => t.addEventListener('click', () => activate(t.dataset.tab)));\n\n  \u002F\u002F Activate on load (hash or first tab)\n  const hashTab = location.hash.slice(1);\n  const firstTab = tabBtns[0]?.dataset.tab ?? 'indemnite';\n  const startTab = hashTab && document.querySelector(`[data-tab=\"${hashTab}\"]`) ? hashTab : firstTab;\n  activate(startTab);\n\n  \u002F\u002F ── Initial render all ────────────────────────────────────────────────────────\n  Object.values(renderers).forEach(fn => fn());\n\n  \u002F\u002F ── Lucide icons ─────────────────────────────────────────────────────────────\n  if (window.lucide) lucide.createIcons();\n\n  \u002F\u002F ── ResizeObserver ────────────────────────────────────────────────────────────\n  const ro = new ResizeObserver(() => {\n    const h = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);\n    parent.postMessage({ type: 'resize', height: h }, '*');\n  });\n  ro.observe(document.documentElement);\n})();\n\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","generated","juridique","consumer","both","https:\u002F\u002Fpub-bdebbd2dad294475a2da0eb657815b6b.r2.dev\u002Ftools\u002Fccn-ouvriers-des-travaux-publics-9c7e319995.webp",[]]