{"id":118327,"date":"2026-10-09T15:52:50","date_gmt":"2026-10-09T15:52:50","guid":{"rendered":"https:\/\/ohmycad.com\/simulateur-de-prix-outscale\/"},"modified":"2026-10-09T15:52:50","modified_gmt":"2026-10-09T15:52:50","slug":"simulateur-de-prix-outscale","status":"publish","type":"page","link":"https:\/\/ohmycad.com\/fr-ca\/simulateur-de-prix-outscale\/","title":{"rendered":"Simulateur de prix Outscale"},"content":{"rendered":"<main id='bde-main'><section class=\"bde-section-118327-700 bde-section omc-contact-sec\">\n  \n  \n\t\n\n\n\n<div class=\"section-container\"><div class=\"bde-code-block-118327-701 bde-code-block\">\n\n  <!-- OHMYCAD \/simulateur-de-prix-outscale\/ : simulateur de prix Outscale (hero + 4 offres, onglets Profil \/ Situation \/ Besoins \/ Offre). Rebuilt in plain HTML\/CSS\/JS from the Claude Design export refs\/Simulateur\/simulateur-de-prix-outscale.html, page structure of \/simulateur-de-prix\/ (117306). Prices and formulas from the lab brief. Scope .ocs-sim. FRONT-END ONLY: no network call, nothing stored. -->\n<style>\n  .bde-section-118327-700>.section-container{max-width:none!important;padding:0!important}\n  .bde-code-block-118327-701{width:100%!important;max-width:none!important;align-self:stretch!important;padding:0!important;margin:0!important}\n  .ocs-sim{--omc-blue:#008CDF;--omc-blue-hover:#0070C0;--omc-ink:#06283D;--omc-white:#FFFFFF;--omc-gray:#5C5C5C;--omc-text-3:#8A8F98;--omc-font:Inter,'Segoe UI',Arial,sans-serif;--omc-font-label:'Archivo','Segoe UI',Arial,sans-serif;--v:#7C3AED;\n    position:relative;width:100%;align-self:stretch;min-height:100vh;overflow:hidden;background:var(--omc-ink);color:#fff;font-family:var(--omc-font);-webkit-font-smoothing:antialiased}\n  .ocs-sim *,.ocs-sim *::before,.ocs-sim *::after{box-sizing:border-box}\n  .ocs-sim h1,.ocs-sim h2,.ocs-sim h3,.ocs-sim p{margin:0;font-family:inherit;color:inherit}\n  .ocs-sim button,.ocs-sim input,.ocs-sim select{font-family:inherit}\n  .ocs-sim a{color:var(--omc-blue)}\n  .ocs-sim a:hover{color:var(--omc-blue-hover)}\n  .ocs-sim :focus-visible{outline:2px solid #A78BFA;outline-offset:2px}\n  .ocs-sim .sv{display:block;flex:none}\n  .ocs-sim .s-grid{position:absolute;inset:0;pointer-events:none;background-image:linear-gradient(to right,rgba(255,255,255,.05) 1px,transparent 1px),linear-gradient(to bottom,rgba(255,255,255,.05) 1px,transparent 1px);background-size:56px 56px}\n  .ocs-sim .s-in{position:relative;max-width:960px;margin:0 auto;padding:0 20px}\n  \/* Hero: the section is pulled 5% up under the header, as on \/simulateur-de-prix\/, so the top padding adds it back *\/\n  .ocs-sim .s-hero{text-align:center;padding:calc(80px + 5vw) 0 0}\n  .ocs-sim .s-hero h1{margin:0 auto;max-width:760px;font-size:clamp(30px,5vw,50px);line-height:1.08;font-weight:800;letter-spacing:-.005em;text-wrap:balance}\n  .ocs-sim .s-hero p{margin:18px 0 0;font-size:19px;line-height:1.5;color:rgba(255,255,255,.82)}\n  .ocs-sim .s-body{padding:48px 0 72px}\n  .ocs-sim .s-uw{all:unset;box-sizing:border-box;cursor:pointer}\n\n  \/* Start *\/\n  .ocs-sim .s-start{max-width:800px;margin:0 auto}\n  .ocs-sim .s-start h2{margin:0 0 24px;text-align:center;font-size:clamp(24px,3vw,30px);line-height:1.25;font-weight:700}\n  .ocs-sim .s-offers{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr));gap:16px}\n  .ocs-sim .s-offer{display:flex;align-items:center;gap:18px;padding:24px;background:#fff;color:var(--omc-ink);border:1px solid #E3E6EB;border-radius:10px;transition:box-shadow .18s ease,border-color .18s ease}\n  .ocs-sim .s-offer:hover{box-shadow:0 8px 24px rgba(6,40,61,.18);border-color:var(--v)}\n  .ocs-sim .s-offer-ic{width:48px;height:48px;border-radius:9px;background:rgba(124,58,237,.10);display:flex;align-items:center;justify-content:center;color:var(--v);flex:none}\n  .ocs-sim .s-offer-tx{display:flex;flex-direction:column;gap:4px;min-width:0}\n  .ocs-sim .s-offer-tx b{font-size:19px;font-weight:700;line-height:1.3}\n  .ocs-sim .s-offer-tx span{font-size:15px;line-height:1.45;color:var(--omc-gray)}\n  .ocs-sim .s-trust{display:flex;flex-wrap:wrap;justify-content:center;gap:12px 32px;margin-top:36px;font-size:16px;color:rgba(255,255,255,.88);list-style:none;padding:0}\n  .ocs-sim .s-trust li{display:flex;align-items:center;gap:10px}\n  .ocs-sim .s-trust li::before{content:\"\";width:7px;height:7px;border-radius:50%;background:var(--v)}\n\n  \/* Tabs + nav *\/\n  .ocs-sim .s-tabs-w{display:flex;justify-content:center}\n  .ocs-sim .s-tabs-in{display:inline-flex;flex-direction:column;gap:10px;max-width:100%}\n  .ocs-sim .s-tabs{display:flex;flex-wrap:wrap;justify-content:center;gap:6px;list-style:none;padding:0;margin:0}\n  .ocs-sim .s-tab{font-family:var(--omc-font-label),Archivo,sans-serif;font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;padding:9px 14px;color:rgba(255,255,255,.55);display:inline-block}\n  .ocs-sim .s-tab.is-on{background:#fff;color:var(--omc-ink);border-radius:4px}\n  .ocs-sim .s-tab.is-done{color:#C4B5FD}\n  .ocs-sim .s-prog{height:3px;background:rgba(255,255,255,.18);border-radius:2px;overflow:hidden}\n  .ocs-sim .s-prog i{display:block;height:100%;background:var(--v);transition:width .18s ease}\n  .ocs-sim .s-nav{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-top:28px}\n  .ocs-sim .s-back{display:flex;align-items:center;gap:10px;font-size:16px;font-weight:600;color:#fff;min-height:44px}\n  .ocs-sim .s-restart{display:flex;align-items:center;gap:8px;font-size:15px;font-weight:600;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:9px;padding:0 16px;min-height:42px}\n  .ocs-sim .s-restart:hover{background:rgba(255,255,255,.12)}\n\n  \/* Questions *\/\n  .ocs-sim .s-q{margin:24px 0 0;font-size:clamp(26px,3.4vw,34px);line-height:1.2;font-weight:800;letter-spacing:-.005em;text-wrap:pretty}\n  .ocs-sim .s-q:focus{outline:none}\n  .ocs-sim .s-help{margin:8px 0 0;font-size:17px;line-height:1.5;color:rgba(255,255,255,.8)}\n  .ocs-sim .s-list{display:flex;flex-direction:column;gap:12px;margin-top:24px}\n  .ocs-sim .s-card{display:flex;flex-wrap:wrap;align-items:center;gap:14px 18px;padding:16px 20px;min-height:76px;border-radius:10px;border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.03);transition:border-color .18s ease,background .18s ease}\n  .ocs-sim .is-sel{border-color:var(--v)!important;background:rgba(124,58,237,.18)!important}\n  .ocs-sim .s-card-ic{width:44px;height:44px;border-radius:9px;background:rgba(124,58,237,.24);display:flex;align-items:center;justify-content:center;color:#C4B5FD;flex:none}\n  .ocs-sim .s-card-tx{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:3px}\n  .ocs-sim .s-card-tx b{font-size:18px;font-weight:700;line-height:1.3}\n  .ocs-sim .s-card-tx span{font-size:15px;line-height:1.45;color:rgba(255,255,255,.72)}\n  .ocs-sim .s-card-pr{flex:0 1 auto;display:flex;flex-direction:column;align-items:flex-end;gap:2px;text-align:right;max-width:280px}\n  .ocs-sim .s-card-pr span:first-child{display:flex;align-items:baseline;gap:10px}\n  .ocs-sim .s-card-pr s{font-size:15px;color:rgba(255,255,255,.55)}\n  .ocs-sim .s-card-pr b{font-size:18px;font-weight:800}\n  .ocs-sim .s-card-pr small{font-size:13px;line-height:1.4;color:rgba(255,255,255,.7)}\n  .ocs-sim .s-box{width:22px;height:22px;border-radius:4px;border:2px solid rgba(255,255,255,.45);display:flex;align-items:center;justify-content:center;flex:none}\n  .ocs-sim .is-sel .s-box{border-color:#A78BFA;background:var(--v)}\n  .ocs-sim .s-arrow{color:#C4B5FD;font-size:18px;flex:none}\n  .ocs-sim .s-advise{margin-top:12px;width:100%;display:flex;align-items:center;justify-content:center;gap:12px;min-height:64px;padding:14px 20px;border-radius:10px;border:1.5px dashed rgba(255,255,255,.4);background:transparent;font-size:17px;font-weight:700;color:#fff}\n  .ocs-sim .s-advise.is-on{border-color:#A78BFA;background:rgba(124,58,237,.18)}\n  .ocs-sim .s-other{width:100%;max-width:420px;height:46px;padding:0 14px;border:1px solid rgba(255,255,255,.3);border-radius:9px;background:rgba(255,255,255,.06);color:#fff;font-size:16px;outline:none;margin-top:14px}\n  .ocs-sim .s-other:focus{border-color:#A78BFA}\n  .ocs-sim .s-other::placeholder{color:rgba(255,255,255,.55)}\n  .ocs-sim .s-sizes{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-top:24px}\n  .ocs-sim .s-size{display:flex;flex-direction:column;gap:6px;padding:18px 20px;border-radius:10px;border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.03);transition:border-color .18s ease,background .18s ease}\n  .ocs-sim .s-size b{font-size:26px;font-weight:800;line-height:1.1}\n  .ocs-sim .s-size span{font-size:15px;line-height:1.4;color:rgba(255,255,255,.75)}\n  .ocs-sim .s-sl{margin-top:28px}\n  .ocs-sim .s-sl-h{display:flex;justify-content:space-between;align-items:baseline;gap:16px;margin-bottom:12px}\n  .ocs-sim .s-lab{font-family:var(--omc-font-label),Archivo,sans-serif;font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.75)}\n  .ocs-sim .s-sl-v{display:flex;align-items:baseline;gap:6px}\n  .ocs-sim .s-sl-v b{font-size:34px;font-weight:800;line-height:1}\n  .ocs-sim .s-sl-v span{font-size:16px;color:rgba(255,255,255,.8)}\n  .ocs-sim .s-sl input[type=range]{width:100%;margin:0;accent-color:var(--v);cursor:pointer;height:22px}\n  .ocs-sim .s-ticks{display:flex;justify-content:space-between;margin-top:6px;font-size:13px;color:rgba(255,255,255,.65)}\n  .ocs-sim .s-big{display:flex;flex-wrap:wrap;align-items:center;gap:20px 40px}\n  .ocs-sim .s-big-v{display:flex;align-items:baseline;gap:8px;min-width:150px}\n  .ocs-sim .s-big-v b{font-size:60px;font-weight:800;line-height:1}\n  .ocs-sim .s-big-v span{font-size:17px;color:rgba(255,255,255,.8)}\n  .ocs-sim .s-big-r{flex:1 1 320px;min-width:0}\n  .ocs-sim .s-live{margin-top:24px;padding:18px 24px;border-radius:10px;border:1px solid rgba(124,58,237,.6);background:rgba(124,58,237,.14);display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:8px 24px}\n  .ocs-sim .s-live .s-lab{color:#C4B5FD}\n  .ocs-sim .s-live-v{display:flex;flex-direction:column;align-items:flex-end;gap:4px;text-align:right}\n  .ocs-sim .s-live-v b{font-size:26px;font-weight:800;line-height:1.2}\n  .ocs-sim .s-live-v span{font-size:14px;color:rgba(255,255,255,.75)}\n  .ocs-sim .s-grp{margin-top:28px}\n  .ocs-sim .s-grp-h{margin-bottom:12px;display:flex;flex-wrap:wrap;align-items:center;gap:10px}\n  .ocs-sim .s-opt-tag{font-family:var(--omc-font-label),Archivo,sans-serif;font-weight:700;text-transform:uppercase;letter-spacing:.08em;font-size:10.5px;color:#C4B5FD;border:1px solid rgba(196,181,253,.5);border-radius:4px;padding:3px 7px}\n  .ocs-sim .s-expert{margin-left:auto;font-family:var(--omc-font);text-transform:none;letter-spacing:0;font-size:13px;font-weight:600;color:rgba(255,255,255,.7);border:1px solid rgba(255,255,255,.28);background:transparent;border-radius:4px;padding:6px 10px;display:flex;align-items:center;gap:6px;min-height:32px}\n  .ocs-sim .s-expert.is-on{color:#fff;border-color:var(--v);background:rgba(124,58,237,.35)}\n  .ocs-sim .s-cards2{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}\n  .ocs-sim .s-rc{display:flex;align-items:flex-start;gap:14px;padding:16px 18px;border-radius:10px;border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.03);transition:border-color .18s ease,background .18s ease}\n  .ocs-sim .s-ring{width:18px;height:18px;margin-top:2px;border-radius:50%;border:2px solid rgba(255,255,255,.45);display:flex;align-items:center;justify-content:center;flex:none}\n  .ocs-sim .s-ring i{width:8px;height:8px;border-radius:50%;background:transparent}\n  .ocs-sim .is-sel .s-ring{border-color:#A78BFA}\n  .ocs-sim .is-sel .s-ring i{background:#A78BFA}\n  .ocs-sim .s-rc-tx{display:flex;flex-direction:column;gap:3px;min-width:0}\n  .ocs-sim .s-rc-tx b{font-size:17px;font-weight:700;line-height:1.3}\n  .ocs-sim .s-rc-tx span{font-size:14px;line-height:1.45;color:rgba(255,255,255,.72)}\n  .ocs-sim .s-chips{display:flex;flex-wrap:wrap;gap:10px}\n  .ocs-sim .s-chip{display:flex;align-items:center;gap:8px;min-height:44px;padding:0 16px;border-radius:9px;font-size:15px;font-weight:600;border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.03);color:#fff}\n  .ocs-sim .s-fixed{display:flex;align-items:center;gap:10px;margin-top:22px;font-size:16px;color:rgba(255,255,255,.88)}\n  .ocs-sim .s-acts{display:flex;flex-wrap:wrap;gap:12px;margin-top:32px}\n  .ocs-sim .s-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:var(--omc-font);font-weight:600;line-height:1;text-decoration:none;border-radius:9px;cursor:pointer;transition:background .18s ease,border-color .18s ease,color .18s ease;height:48px;padding:0 26px;font-size:15px;background:var(--omc-blue);color:#fff;border:1px solid transparent}\n  .ocs-sim .s-btn:hover{background:var(--omc-blue-hover)}\n  .ocs-sim .s-btn:disabled{cursor:not-allowed;opacity:.5;background:var(--omc-blue)}\n  .ocs-sim .s-btn-ghost{background:transparent;color:#fff;border:1px solid rgba(255,255,255,.45)}\n  .ocs-sim .s-btn-ghost:hover{background:transparent;border-color:#fff}\n  .ocs-sim .s-btn-full{display:flex;width:100%}\n\n  \/* White cards: estimate, forms, IA *\/\n  .ocs-sim .s-white{margin-top:24px;background:#fff;color:var(--omc-ink);border-radius:10px;padding:clamp(22px,4vw,36px)}\n  .ocs-sim .s-ey{font-family:var(--omc-font-label),Archivo,sans-serif;font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:#6D28D9}\n  .ocs-sim .s-h2w{margin:8px 0 0;font-size:clamp(24px,3vw,30px);line-height:1.2;font-weight:800;letter-spacing:-.005em}\n  .ocs-sim .s-h2w:focus{outline:none}\n  .ocs-sim .s-tiles{margin-top:24px;display:flex;flex-wrap:wrap;gap:16px}\n  .ocs-sim .s-tiles.is-locked{filter:blur(10px);user-select:none;pointer-events:none}\n  .ocs-sim .s-t1{flex:2 1 300px;min-width:0;border:1px solid rgba(124,58,237,.35);border-radius:10px;padding:24px 28px;background:#FAF8FF}\n  .ocs-sim .s-t2{flex:1 1 200px;min-width:0;border:1px solid #E3E6EB;border-radius:10px;padding:24px;background:#fff;display:flex;flex-direction:column;justify-content:flex-end}\n  .ocs-sim .s-tl{font-family:var(--omc-font-label),Archivo,sans-serif;font-weight:700;letter-spacing:.12em;text-transform:uppercase;font-size:11px;color:#6D28D9}\n  .ocs-sim .s-t2 .s-tl{color:var(--omc-gray)}\n  .ocs-sim .s-month{margin-top:12px;font-size:clamp(44px,7vw,64px);font-weight:800;line-height:1;letter-spacing:-.015em}\n  .ocs-sim .s-t1{container-type:inline-size}\n  \/* Monthly price and \"\/ mois\" on one line: the size follows the tile width, the amount itself never breaks *\/\n  .ocs-sim .s-t1 .s-month{font-size:clamp(30px,5vw,64px);font-size:clamp(26px,11cqi,64px)}\n  .ocs-sim .s-month>span{white-space:nowrap}\n  .ocs-sim .s-month .s-per{font-size:.55em;letter-spacing:0}\n  .ocs-sim .s-t1 .s-month.is-long{font-size:clamp(24px,4vw,56px);font-size:clamp(22px,8.6cqi,56px)}\n  .ocs-sim .s-old{margin-top:12px;font-size:15px;color:var(--omc-text-3);text-decoration:line-through}\n  .ocs-sim .s-pre{margin-top:12px;font-size:14px;color:var(--omc-gray)}\n  .ocs-sim .s-setup{margin-top:4px;font-size:28px;font-weight:800;line-height:1.1}\n  .ocs-sim .s-setup-l{margin-top:8px;font-size:14px;color:var(--omc-gray)}\n  .ocs-sim .s-sub{margin-top:10px;font-size:16px;color:var(--omc-gray)}\n  .ocs-sim .s-note{margin:14px 0 0;font-size:13px;line-height:1.5;color:var(--omc-text-3);max-width:640px}\n  .ocs-sim .s-rows{margin-top:24px;padding:0;list-style:none}\n  .ocs-sim .s-rows li{display:flex;justify-content:space-between;gap:24px;padding:8px 0;font-size:16px}\n  .ocs-sim .s-rows li span{color:var(--omc-gray);flex:none}\n  .ocs-sim .s-rows li b{font-weight:600;text-align:right}\n  .ocs-sim .s-inc{margin-top:24px;background:#F3F4F6;border-radius:10px;padding:20px 24px}\n  .ocs-sim .s-inc .s-tl{margin-bottom:12px}\n  .ocs-sim .s-inc ul{display:flex;flex-direction:column;gap:8px;list-style:none;margin:0;padding:0}\n  .ocs-sim .s-inc li{display:flex;gap:10px;align-items:flex-start;font-size:16px;line-height:1.45}\n  .ocs-sim .s-inc li .sv{margin-top:2px}\n  .ocs-sim .s-lock{margin-top:24px;border:1px solid #E3E6EB;background:#FAF8FF;border-radius:10px;padding:18px 20px;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:16px}\n  .ocs-sim .s-lock-tx{display:flex;gap:12px;align-items:flex-start;flex:1 1 320px;min-width:0;color:var(--v)}\n  .ocs-sim .s-lock-tx p{font-size:15px;line-height:1.5;color:var(--omc-gray)}\n  .ocs-sim .s-lock-tx strong{color:var(--omc-ink)}\n  .ocs-sim .s-form{margin-top:36px;max-width:640px}\n  .ocs-sim .s-form h3{margin:0 0 20px;font-size:22px;font-weight:700}\n  .ocs-sim .s-fields{display:flex;flex-direction:column;gap:16px}\n  .ocs-sim .s-row{display:grid;gap:16px}\n  .ocs-sim .s-row-2{grid-template-columns:repeat(auto-fit,minmax(min(100%,180px),1fr))}\n  .ocs-sim .s-row-1{grid-template-columns:minmax(0,1fr)}\n  .ocs-sim .s-row-t{grid-template-columns:120px minmax(0,1fr)}\n  .ocs-sim .s-fld{display:flex;flex-direction:column;gap:7px;min-width:0}\n  .ocs-sim .s-fld label{font-family:var(--omc-font-label),Archivo,sans-serif;font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--omc-ink)}\n  .ocs-sim .s-in-f{width:100%;height:46px;padding:0 14px;border:1px solid #E3E6EB;border-radius:9px;font-size:16px;color:var(--omc-ink);background:#fff;outline:none}\n  .ocs-sim select.s-in-f{padding:0 10px}\n  .ocs-sim .s-in-f:focus{border-color:#008CDF;box-shadow:0 0 0 3px rgba(0,140,223,.15)}\n  .ocs-sim .s-in-f[aria-invalid=\"true\"]{border-color:#D92D20}\n  .ocs-sim .s-in-f::placeholder{color:#8A8F98}\n  .ocs-sim .s-err{margin:14px 0 0;font-size:15px;color:#D92D20}\n  .ocs-sim .s-legal{margin:16px 0 0;font-size:14px;line-height:1.5;color:var(--omc-gray)}\n  .ocs-sim .s-sent{margin-top:28px;padding:24px;border:1px solid rgba(124,58,237,.4);background:#FAF8FF;border-radius:10px;display:flex;gap:16px;align-items:flex-start}\n  .ocs-sim .s-sent-ic{width:44px;height:44px;border-radius:9px;background:rgba(124,58,237,.12);display:flex;align-items:center;justify-content:center;color:var(--v);flex:none}\n  .ocs-sim .s-sent h3{font-size:24px;font-weight:800}\n  .ocs-sim .s-sent p{margin:6px 0 0;font-size:17px;line-height:1.5}\n  .ocs-sim .s-link{margin-top:14px;font-size:16px;font-weight:600;color:var(--omc-blue);min-height:32px;display:inline-flex;align-items:center}\n  .ocs-sim .s-link:hover{text-decoration:underline}\n  .ocs-sim .s-ia{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr));gap:20px;margin-top:28px;align-items:start}\n  .ocs-sim .s-ia-card{background:var(--omc-ink);border:1px solid var(--v);border-radius:10px;padding:clamp(22px,3vw,32px);display:flex;flex-direction:column;align-items:flex-start}\n  .ocs-sim .s-ia-tag{font-family:var(--omc-font-label),Archivo,sans-serif;font-weight:700;letter-spacing:.12em;text-transform:uppercase;font-size:11px;color:#DDD6FE;background:rgba(124,58,237,.28);border-radius:4px;padding:6px 9px}\n  .ocs-sim .s-ia-t{margin-top:18px;font-size:clamp(34px,4.5vw,44px);font-weight:800;line-height:1.05;letter-spacing:-.01em}\n  .ocs-sim .s-ia-d{margin-top:10px;font-size:17px;line-height:1.5;color:rgba(255,255,255,.82)}\n  .ocs-sim .s-ia-ck{display:flex;flex-direction:column;gap:10px;margin-top:26px;padding:0;align-self:stretch;list-style:none}\n  .ocs-sim .s-ia-ck li{display:flex;gap:10px;align-items:flex-start;font-size:16px;line-height:1.45}\n  .ocs-sim .s-ia-ck li .sv{margin-top:2px}\n  .ocs-sim .s-ia-pr{margin-top:22px;font-size:13px;font-weight:600;color:rgba(255,255,255,.85);border:1px solid rgba(255,255,255,.3);border-radius:4px;padding:6px 10px}\n  .ocs-sim .s-ia .s-white{margin-top:0}\n  .ocs-sim .s-ia .s-white h3{margin:0 0 20px;font-size:22px;font-weight:700}\n  .ocs-sim .s-ia .s-sent{margin-top:0}\n  .ocs-sim .s-direct{max-width:640px;margin:0 auto}\n  .ocs-sim .s-direct .s-white{margin-top:12px}\n  .ocs-sim .s-consent{display:flex;gap:12px;align-items:flex-start;margin-top:18px;cursor:pointer;font-size:15px;line-height:1.5}\n  .ocs-sim .s-consent input{width:20px;height:20px;margin:1px 0 0;accent-color:#008CDF;flex:none;cursor:pointer}\n  .ocs-sim .s-reass{display:flex;flex-wrap:wrap;justify-content:center;gap:10px 28px;margin-top:18px;font-size:14px;color:var(--omc-gray)}\n  .ocs-sim .s-reass span{display:flex;align-items:center;gap:8px;color:var(--omc-gray)}\n  .ocs-sim .s-reass .sv{color:var(--v)}\n  .ocs-sim .s-foot{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px 24px;margin-top:40px}\n  .ocs-sim .s-foot>span{font-size:14px;color:rgba(255,255,255,.75)}\n  .ocs-sim .s-chat{display:flex;align-items:center;gap:10px;min-height:44px;font-size:15px;font-weight:700;color:#fff}\n  .ocs-sim .s-chat:hover,.ocs-sim .s-back-d:hover{text-decoration:underline}\n  .ocs-sim .s-back-d{display:flex;align-items:center;gap:8px;min-height:44px;font-size:16px;font-weight:600;color:#fff}\n  .ocs-sim .s-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n  \/* Touch: 44 px hit areas on small screens, same look *\/\n  @media (max-width:767px){\n    .ocs-sim .s-tab.is-done,.ocs-sim .s-expert,.ocs-sim .s-link{min-height:44px;display:inline-flex;align-items:center}\n    .ocs-sim .s-sl input[type=range]{height:44px}\n  }\n  \/* Lot 04: Stockage setup block, shown after the form *\/\n  .ocs-sim .s-sbox{margin-top:24px;position:relative;overflow:hidden;background:var(--omc-ink);color:#fff;border-radius:10px;padding:28px;display:flex;flex-wrap:wrap;align-items:center;gap:24px 40px}\n  .ocs-sim .s-sbox-l{flex:1 1 340px;min-width:0}\n  .ocs-sim .s-sbox-t{font-size:22px;font-weight:800;line-height:1.2}\n  .ocs-sim .s-sbox-l p{margin-top:8px;font-size:16px;line-height:1.5;color:rgba(255,255,255,.82)}\n  .ocs-sim .s-sbox ul{list-style:none;padding:0;margin:18px 0 0;display:grid;grid-template-columns:1fr 1fr;gap:10px 24px}\n  .ocs-sim .s-sbox li{display:flex;gap:10px;align-items:flex-start;font-size:15px;font-weight:600;line-height:1.45}\n  .ocs-sim .s-sbox li .sv{flex:none;margin-top:2px}\n  .ocs-sim .s-sbox-r{flex:0 0 auto;display:flex;flex-direction:column;gap:4px}\n  .ocs-sim .s-sbox-old{font-size:18px;font-weight:600;color:rgba(255,255,255,.62);text-decoration:line-through;text-decoration-thickness:1px}\n  .ocs-sim .s-sbox-p{font-size:34px;font-weight:800;line-height:1.05}\n  .ocs-sim .s-sbox-n{margin-top:6px;font-size:13px;line-height:1.45;color:rgba(255,255,255,.82);max-width:240px}\n  @media (max-width:480px){.ocs-sim .s-sbox{padding:24px 20px}.ocs-sim .s-sbox ul{grid-template-columns:1fr}}\n  @media (prefers-reduced-motion:reduce){.ocs-sim *{transition:none!important}}\n  \/* Mode une page (Victor 09\/10) : dans le parcours, chaque etape tient dans l'ecran sur desktop *\/\n  @media (min-width:768px){\n    .ocs-sim.is-flow .s-hero{padding:120px 0 0}\n    .ocs-sim.is-flow .s-hero h1{max-width:none;font-size:clamp(24px,2.6vw,32px)}\n    .ocs-sim.is-flow .s-body{padding:20px 0 48px}\n    .ocs-sim.is-flow .s-nav{margin-top:12px}\n    .ocs-sim.is-flow .s-back,.ocs-sim.is-flow .s-restart{min-height:38px}\n    .ocs-sim.is-flow .s-q{margin-top:8px;font-size:clamp(22px,2.4vw,28px)}\n    .ocs-sim.is-flow .s-help{margin-top:4px;font-size:16px}\n    .ocs-sim.is-flow .s-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:16px}\n    .ocs-sim.is-flow .s-list>:not(.s-card){grid-column:1\/-1}\n    .ocs-sim.is-flow .s-card{min-height:60px;padding:10px 16px;gap:10px 14px}\n    .ocs-sim.is-flow .s-card-ic{width:36px;height:36px}\n    .ocs-sim.is-flow .s-card-tx b{font-size:17px}\n    .ocs-sim.is-flow .s-card-tx span{font-size:14px}\n    .ocs-sim.is-flow .s-advise{min-height:52px;margin-top:10px}\n  }\n<\/style>\n<div class=\"ocs ocs-sim\" id=\"ocs-sim\">\n  <div class=\"s-grid\" aria-hidden=\"true\"><\/div>\n  <div class=\"s-in\">\n    <header class=\"s-hero\">\n      <h1>Combien co\u00fbte votre cloud souverain ?<\/h1>\n    <\/header>\n    <div class=\"s-body\">\n      <div id=\"sim-app\"><\/div>\n      <p class=\"s-sr\" id=\"sim-live\" aria-live=\"polite\"><\/p>\n    <\/div>\n  <\/div>\n<\/div>\n<script>\n(function () {\n  \/* Outscale price simulator. Leads are sent to HubSpot by send() (console only on the lab). *\/\n  var app = document.getElementById('sim-app'), live = document.getElementById('sim-live');\n  if (!app) return;\n\n  \/* ---------- Config: every price of the page, EUR HT. Open points stay here as one-line changes. ---------- *\/\n  var CONFIG = {\n    storage: {\n      \/* Monthly price per hosting: cs = Cloud souverain, snc = SecNumCloud (Victor 09\/10). *\/\n      packs: [{ max: 1, name: 'Starter', cs: 50, snc: 60 }, { max: 3, name: 'Pro', cs: 120, snc: 145 }, { max: 10, name: 'Scale', cs: 330, snc: 400 }],\n      setup: { annual: 195, annualStruck: 390, flex: 390 }\n    },\n    suite: {\n      included: 5, minUsers: 5, maxUsers: 50,\n      plans: {\n        drive: { cs: 290, snc: 350, setup: 490, perUser: true },\n        full: { cs: 390, snc: 470, setup: 990, perUser: true }\n      },\n      extraUser: { cs: 15, snc: 18 }\n    },\n    vps: {\n      \/* Monthly unit prices in 1\/10000 EUR (integers only). *\/\n      unit: {\n        std: { vcpu: 332880, ramGo: 43800, diskGo: 1320, backupGo: 660, vpn: 262800 },\n        snc: { vcpu: 402960, ramGo: 52560, diskGo: 1584, backupGo: 792, vpn: 315360 }\n      },\n      roundTo: 100000, \/* 10 EUR, rounded up *\/\n      maxServers: 10,\n      backupVolumeIsDisk: true,\n      setup: { single: 600, network: 2400, severalFrom: 600 }\n    }\n  };\n  var TBD = '\u00c0 pr\u00e9ciser au cadrage';\n  var DEBUG_PAYLOAD = location.hostname === 'lab.ohmycad.com' || location.protocol === 'data:'; \/* lab and local preview only *\/\n\n  var IC = {\n    database: '<ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\"\/><path d=\"M3 5v14a9 3 0 0 0 18 0V5\"\/><path d=\"M3 12a9 3 0 0 0 18 0\"\/>',\n    server: '<rect x=\"2\" y=\"2\" width=\"20\" height=\"8\" rx=\"2\"\/><rect x=\"2\" y=\"14\" width=\"20\" height=\"8\" rx=\"2\"\/><path d=\"M6 6h.01M6 18h.01\"\/>',\n    file: '<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><path d=\"M14 2v6h6M8 13h8M8 17h5\"\/>',\n    cpu: '<rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\"\/><rect x=\"9\" y=\"9\" width=\"6\" height=\"6\"\/><path d=\"M9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3\"\/>',\n    heart: '<path d=\"M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z\"\/>',\n    history: '<path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"\/><path d=\"M3 3v5h5M12 7v5l4 2\"\/>',\n    box: '<path d=\"M21 8 12 3 3 8v8l9 5 9-5z\"\/><path d=\"M3 8l9 5 9-5M12 13v8\"\/>',\n    archive: '<rect x=\"2\" y=\"3\" width=\"20\" height=\"5\" rx=\"1\"\/><path d=\"M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8M10 12h4\"\/>',\n    help: '<circle cx=\"12\" cy=\"12\" r=\"10\"\/><path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3M12 17h.01\"\/>',\n    globe: '<circle cx=\"12\" cy=\"12\" r=\"10\"\/><path d=\"M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\"\/>',\n    wrench: '<path d=\"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94z\"\/>',\n    chart: '<path d=\"M3 3v18h18\"\/><path d=\"m7 15 4-4 4 4 6-6\"\/>',\n    userCheck: '<circle cx=\"9\" cy=\"7\" r=\"4\"\/><path d=\"M2 21v-2a4 4 0 0 1 4-4h6a4 4 0 0 1 4 4v2M16 11l2 2 4-4\"\/>',\n    refresh: '<path d=\"M21 12a9 9 0 1 1-3-6.7L21 8\"\/><path d=\"M21 3v5h-5\"\/>',\n    key: '<circle cx=\"7.5\" cy=\"15.5\" r=\"5.5\"\/><path d=\"m21 2-9.6 9.6M15.5 7.5l3 3L22 7l-3-3\"\/>',\n    layers: '<path d=\"M12 2 2 7l10 5 10-5z\"\/><path d=\"m2 17 10 5 10-5M2 12l10 5 10-5\"\/>',\n    mail: '<rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"\/><path d=\"m22 7-10 6L2 7\"\/>',\n    book: '<path d=\"M4 19.5A2.5 2.5 0 0 1 6.5 17H20V2H6.5A2.5 2.5 0 0 0 4 4.5z\"\/><path d=\"M4 19.5A2.5 2.5 0 0 0 6.5 22H20v-5\"\/>',\n    pen: '<path d=\"M12 20h9\"\/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4z\"\/>',\n    search: '<circle cx=\"11\" cy=\"11\" r=\"8\"\/><path d=\"m21 21-4.35-4.35\"\/>',\n    message: '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"\/>',\n    shield: '<path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\"\/>',\n    zap: '<path d=\"M13 2 3 14h9l-1 8 10-12h-9z\"\/>',\n    flag: '<path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\"\/><path d=\"M4 22v-7\"\/>',\n    activity: '<path d=\"M22 12h-4l-3 9L9 3l-3 9H2\"\/>',\n    gauge: '<path d=\"m12 14 4-4\"\/><path d=\"M3.34 19a10 10 0 1 1 17.32 0\"\/>',\n    fileCheck: '<path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><path d=\"M14 2v6h6M9 15l2 2 4-4\"\/>',\n    back: '<path d=\"M19 12H5M12 19l-7-7 7-7\"\/>',\n    restart: '<path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"\/><path d=\"M3 3v5h5\"\/>',\n    chat: '<path d=\"M7.9 20A9 9 0 1 0 4 16.1L2 22z\"\/><path d=\"M8 12h.01M12 12h.01M16 12h.01\"\/>',\n    send: '<path d=\"M22 2 11 13\"\/><path d=\"M22 2 15 22l-4-9-9-4z\"\/>',\n    check: '<path d=\"M20 6 9 17l-5-5\"\/>',\n    lock: '<rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\"\/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"\/>',\n    briefcase: '<rect x=\"2\" y=\"7\" width=\"20\" height=\"14\" rx=\"2\"\/><path d=\"M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2M2 13h20\"\/>',\n    code: '<path d=\"m16 18 6-6-6-6M8 6l-6 6 6 6\"\/>',\n    cart: '<circle cx=\"9\" cy=\"21\" r=\"1\"\/><circle cx=\"20\" cy=\"21\" r=\"1\"\/><path d=\"M1 1h4l2.7 13.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6\"\/>',\n    userX: '<circle cx=\"9\" cy=\"7\" r=\"4\"\/><path d=\"M2 21v-2a4 4 0 0 1 4-4h6a4 4 0 0 1 4 4v2M17 8l5 5M22 8l-5 5\"\/>',\n    folder: '<path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\"\/>',\n    plus: '<circle cx=\"12\" cy=\"12\" r=\"10\"\/><path d=\"M12 8v8M8 12h8\"\/>',\n    grid: '<rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"\/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"\/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"\/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"\/>',\n    dots: '<circle cx=\"12\" cy=\"12\" r=\"1\"\/><circle cx=\"19\" cy=\"12\" r=\"1\"\/><circle cx=\"5\" cy=\"12\" r=\"1\"\/>',\n    compass: '<circle cx=\"12\" cy=\"12\" r=\"10\"\/><path d=\"m16.24 7.76-2.12 6.36-6.36 2.12 2.12-6.36z\"\/>',\n    clock: '<circle cx=\"12\" cy=\"12\" r=\"10\"\/><path d=\"M12 6v6l4 2\"\/>'\n  };\n  function ic(n, size, color) {\n    return '<svg class=\"sv\" width=\"' + (size || 22) + '\" height=\"' + (size || 22) + '\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"' + (color || 'currentColor') +\n      '\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">' + (IC[n] || '') + '<\/svg>';\n  }\n\n  \/* ---------- Content (copy from the export) ---------- *\/\n  var SCREENS = {\n    storage: [['profile', 0], ['situation', 1], ['need', 2], ['vol', 2], ['final', 3]],\n    vps: [['profile', 0], ['situation', 1], ['use', 2], ['size', 2], ['options', 2], ['final', 3]],\n    suite: [['profile', 0], ['situationSuite', 1], ['plan', 2], ['users', 2], ['reqs', 2], ['final', 3]],\n    ia: [['profile', 0], ['situation', 1], ['use', 2], ['stage', 2], ['reqs', 2], ['final', 3]]\n  };\n  var TAB_LABELS = ['Profil', 'Situation', 'Besoins', 'Offre'];\n  var START = [\n    ['storage', 'database', 'Stockage objet', 'Compatible S3, donn\u00e9es de sant\u00e9 incluses'],\n    ['vps', 'server', 'Serveurs et VPS', 'Vos applications et bases de donn\u00e9es'],\n    ['suite', 'file', 'Suite bureautique souveraine', 'Documents, mail et partage pour votre \u00e9quipe'],\n    ['ia', 'cpu', 'IA souveraine', 'Mod\u00e8les h\u00e9berg\u00e9s en France, sur vos donn\u00e9es']\n  ];\n  var OFFER_NAMES = { storage: 'Stockage objet', vps: 'Serveurs et VPS', suite: 'Suite bureautique souveraine', ia: 'IA souveraine' };\n  var PROFILES = [['direction', 'Direction g\u00e9n\u00e9rale', 'briefcase'], ['dsi', 'DSI \/ CTO', 'server'], ['rssi', 'RSSI', 'shield'], ['dev', 'D\u00e9veloppeur \/ DevOps', 'code'], ['achats', 'Achats', 'cart'], ['none', 'Je ne veux pas pr\u00e9ciser', 'userX']];\n  var SITS = [['prod', 'Une application en production', '', 'activity'], ['building', 'Une application en construction', '', 'wrench'], ['files', 'Des fichiers et documents partag\u00e9s', '', 'folder'], ['servers', 'Des serveurs ou machines virtuelles', '', 'server'], ['nothing', 'Rien encore', 'On part de z\u00e9ro', 'plus'], ['unknown', 'Je ne veux pas pr\u00e9ciser', '', 'help']];\n  var SIT_UNKNOWN = { storage: 'Je ne veux pas pr\u00e9ciser', vps: 'Je ne veux pas pr\u00e9ciser', ia: 'Je ne saurais pas pr\u00e9ciser' };\n  var SUITE_SITS = [['m365', 'Microsoft 365', '', 'grid'], ['gws', 'Google Workspace', '', 'globe'], ['internal', 'Un serveur interne', '', 'server'], ['separate', 'Des outils s\u00e9par\u00e9s', 'Dropbox, WeTransfer\u2026', 'box'], ['nothing', 'Rien encore', '', 'plus'], ['other', 'Autre', '', 'dots']];\n  var STORAGE_NEEDS = [['sante', 'Donn\u00e9es de sant\u00e9', 'heart'], ['backup', 'Sauvegardes', 'history'], ['app', \"Fichiers d'une application\", 'box'], ['archive', 'Archives et documents', 'archive'], ['other', 'Autre', 'help']];\n  var VOLS = [1, 2, 3, 5, 10, 11];\n  var SETUP_CHECKS = ['Cr\u00e9ation du compte', 'Acc\u00e8s', 'Bucket', 'Versioning', 'Sauvegardes', 'Mise en relation HDS avec Outscale'];\n  var VPS_USES = [['web', 'Application web', 'globe'], ['db', 'Base de donn\u00e9es', 'database'], ['internal', 'Outils internes', 'wrench'], ['compute', 'Calcul ou traitement de donn\u00e9es', 'chart'], ['unknown', 'Je ne sais pas encore', 'help']];\n  var SIZES = { S: [2, 4, 50], M: [4, 16, 100], L: [8, 32, 200], XL: [16, 64, 500] };\n  var PLANS = {\n    drive: { title: 'Drive & Bureautique', desc: 'Drive partag\u00e9, documents, tableurs et pr\u00e9sentations en ligne', icon: 'layers' },\n    full: { title: 'Suite compl\u00e8te', desc: 'Tout Drive & Bureautique, plus le mail sur votre domaine', icon: 'mail' }\n  };\n  var SUITE_OPTS = ['Visio', \"Chat d'entreprise\", 'Assistant IA', 'VPN'];\n  var IA_USES = [['doc', 'Assistant documentaire', 'Interroger normes, proc\u00e9dures et documentation en langage naturel', 'book'], ['be', \"Copilote bureau d'\u00e9tudes\", 'Assister la conception \u00e0 partir de vos donn\u00e9es CAO\/PDM', 'pen'], ['analyse', 'Analyse de documents', 'Extraire, r\u00e9sumer, comparer contrats et rapports', 'search'], ['support', 'Support technique augment\u00e9', 'R\u00e9pondre plus vite \u00e0 partir de votre base de connaissances', 'message'], ['secure', 'Assistant interne s\u00e9curis\u00e9', 'Sur donn\u00e9es sensibles : d\u00e9fense, sant\u00e9, secteur public', 'shield'], ['auto', 'Automatisation m\u00e9tier', 'Des agents outill\u00e9s sur vos syst\u00e8mes internes', 'zap']];\n  var IA_STAGES = [['pilot', \"Valider un premier cas d'usage\", 'flag'], ['prod', 'Un assistant m\u00e9tier en production', 'activity'], ['intense', 'Un usage intensif et sensible', 'gauge'], ['reg', 'Un besoin r\u00e9glement\u00e9 ou sp\u00e9cifique', 'fileCheck'], ['unknown', 'Je ne sais pas encore', 'help']];\n  var IA_REGIONS = [['std', 'Standard', 'Donn\u00e9es en France'], ['snc', 'SecNumCloud', 'Qualification ANSSI']];\n  var IA_USERS = ['Quelques-uns', '10 \u00e0 50', '50 \u00e0 200', 'Plus de 200', 'Je ne sais pas encore'];\n  var ENTRY = {\n    pilot: { title: 'D\u00e9couverte', desc: \"Pour valider un premier cas d'usage.\", checks: [\"Mod\u00e8le l\u00e9ger, servi en API souveraine ou sur une VM GPU \u00e0 l'heure\", 'RAG sur une source de donn\u00e9es', 'Quelques utilisateurs', 'Mise en route accompagn\u00e9e'] },\n    prod: { title: '\u00c9quipe', desc: 'Pour un assistant m\u00e9tier en production.', checks: ['Mod\u00e8le \u00e9quilibr\u00e9, GPU d\u00e9di\u00e9', 'RAG multi-sources', 'Infog\u00e9rance et suivi des co\u00fbts', 'R\u00e9gion standard ou SecNumCloud'] },\n    intense: { title: 'Avanc\u00e9', desc: 'Pour un usage intensif et sensible.', checks: ['Mod\u00e8le de t\u00eate auto-h\u00e9berg\u00e9', 'Cluster GPU, haute disponibilit\u00e9', 'Isolation renforc\u00e9e', 'R\u00e9gion SecNumCloud en option'] },\n    reg: { title: 'Sur mesure', desc: 'Pour un besoin r\u00e9glement\u00e9 ou sp\u00e9cifique.', checks: ['Sp\u00e9cialisation et agents', 'Int\u00e9gration \u00e0 votre SI', 'SecNumCloud', 'Cadrage d\u00e9di\u00e9'] }\n  };\n\n  \/* ---------- State ---------- *\/\n  function base() {\n    return {\n      offer: null, step: 0, direct: false, directSent: false, consent: false,\n      c: { profile: null, sit: null, sitOther: '' },\n      s: { need: [], vol: 2, host: 'cs' },\n      v: { use: [], size: null, cpu: 4, ram: 16, count: 1, disk: 100, region: 'std', backup: 'yes', vpn: 'no', managed: 'team' },\n      u: { plan: null, users: 5, usersUnknown: false, host: 'cs', opts: [] },\n      i: { use: [], stage: null, region: null, users: null },\n      defaults: {}, formOpen: false, submitted: false, err: null, errFields: {},\n      f: { prenom: '', nom: '', societe: '', email: '', ind: '+33', tel: '' }\n    };\n  }\n  var st = base();\n  var utm = (function () {\n    var q = new URLSearchParams(location.search), o = {};\n    ['utm_source', 'utm_medium', 'utm_campaign'].forEach(function (k) { o[k] = q.get(k) || ''; });\n    return o;\n  })();\n\n  \/* Deep links: ?offre=stockage|vps|suite|ia opens that offer at PROFIL; &pack=starter|pro|scale (Stockage) presets the volume,\n     &hebergement=secnumcloud (Stockage) presets SecNumCloud. &formule=drive|full (Suite) presets the plan. &formule=secure (old Suite card) opens Stockage with Starter preselected.\n     Unknown or missing value = normal start. *\/\n  var entry = '';\n  (function () {\n    var q = new URLSearchParams(location.search), has = function (o, k) { return Object.prototype.hasOwnProperty.call(o, k); };\n    var OFFRE = { stockage: 'storage', vps: 'vps', suite: 'suite', ia: 'ia' }, PACK = { starter: 0, pro: 2, scale: 4 };\n    var o = (q.get('offre') || '').toLowerCase(), pk = (q.get('pack') || '').toLowerCase(), fo = (q.get('formule') || '').toLowerCase();\n    if (!has(OFFRE, o)) return;\n    st.offer = OFFRE[o]; entry = 'offre-' + o;\n    if (o === 'stockage' && has(PACK, pk)) { st.s.vol = PACK[pk]; entry = 'stockage-souverain-' + pk; }\n    if (o === 'stockage' && (q.get('hebergement') || '').toLowerCase() === 'secnumcloud') st.s.host = 'snc';\n    if (o === 'suite' && fo === 'secure') { st.offer = 'storage'; st.s.vol = PACK.starter; entry = 'suite-souveraine-secure'; }\n    else if (o === 'suite' && has(PLANS, fo)) { st.u.plan = fo; entry = 'suite-souveraine-' + fo; }\n  })();\n\n  \/* ---------- Helpers ---------- *\/\n  function esc(s) { return String(s == null ? '' : s).replace(\/[&<>\"']\/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c]; }); }\n  function fmt(n) { return Math.round(n).toLocaleString('fr-FR').replace(\/[\u202f\u00a0\\s]\/g, '\u00a0'); }\n  function eur(n) { return fmt(n) + '\u00a0\u20ac HT'; }\n  function screens() { return SCREENS[st.offer]; }\n  function sid() { return st.offer ? screens()[st.step][0] : null; }\n  function toggle(arr, id) {\n    var ex = ['unknown', 'advise'];\n    if (ex.indexOf(id) > -1) return arr.indexOf(id) > -1 ? [] : [id];\n    var a = arr.filter(function (x) { return ex.indexOf(x) < 0; });\n    return a.indexOf(id) > -1 ? a.filter(function (x) { return x !== id; }) : a.concat([id]);\n  }\n  function setDefault(key, on) { if (on) st.defaults[key] = true; else delete st.defaults[key]; }\n  function track(event, data) {\n    if (Array.isArray(window.dataLayer)) { var o = { event: event }; for (var k in data) o[k] = data[k]; window.dataLayer.push(o); }\n  }\n\n  \/* ---------- Prices ---------- *\/\n  function pack(vol) { var p = CONFIG.storage.packs; for (var k = 0; k < p.length; k++) if (vol <= p[k].max) return p[k]; return null; }\n  function volLabel(i) { var v = VOLS[i]; return v > 10 ? 'Plus de 10 To' : v + ' To'; }\n  function planKey() { return PLANS[st.u.plan] ? st.u.plan : 'drive'; }\n  function suiteTotal() {\n    var k = planKey(), p = CONFIG.suite.plans[k], h = st.u.host === 'snc' ? 'snc' : 'cs';\n    return p[h] + (p.perUser ? (st.u.users - CONFIG.suite.included) * CONFIG.suite.extraUser[h] : 0);\n  }\n  \/* VPS estimate: integer arithmetic in 1\/10000 EUR, rounded up to the next 10 EUR. Called only once the unlock form is valid. *\/\n  function vpsEstimate() {\n    var v = st.v, r = v.size === 'custom' ? [v.cpu, v.ram] : SIZES[SIZES[v.size] ? v.size : 'M'];\n    var u = CONFIG.vps.unit[v.region === 'snc' ? 'snc' : 'std'];\n    var per = r[0] * u.vcpu + r[1] * u.ramGo + v.disk * u.diskGo + (v.backup === 'yes' ? v.disk * u.backupGo : 0);\n    var total = v.count * per + (v.vpn === 'yes' ? u.vpn : 0);\n    var monthly = Math.floor((total + CONFIG.vps.roundTo - 1) \/ CONFIG.vps.roundTo) * (CONFIG.vps.roundTo \/ 10000);\n    return { monthly: monthly, setup: vpsSetup() };\n  }\n  function vpsSetup() {\n    var s = CONFIG.vps.setup;\n    return st.v.vpn === 'yes' ? { pre: '', amount: s.network } : st.v.count === 1 ? { pre: '', amount: s.single } : { pre: '\u00c0 partir de', amount: s.severalFrom };\n  }\n  function vpsRes() { var v = st.v; return v.size === 'custom' ? [v.cpu, v.ram] : SIZES[SIZES[v.size] ? v.size : 'M']; }\n\n  \/* ---------- Render: question screens ---------- *\/\n  var H = [];\n  function on(fn) { H.push(fn); return H.length - 1; }\n  function listCard(title, desc, icon, sel, fn, extra, multi) {\n    var e = extra || {}, h = '<button type=\"button\" class=\"s-uw s-card' + (sel ? ' is-sel' : '') + '\" data-h=\"' + on(fn) + '\" aria-pressed=\"' + !!sel + '\" data-fid=\"' + esc(title) + '\">' +\n      '<span class=\"s-card-ic\">' + ic(icon, 22) + '<\/span><span class=\"s-card-tx\"><b>' + esc(title) + '<\/b>' + (desc ? '<span>' + esc(desc) + '<\/span>' : '') + '<\/span>';\n    if (e.price != null && st.submitted) h += '<span class=\"s-card-pr\"><span>' + (e.old ? '<s>' + eur(e.old) + '<\/s>' : '') + '<b>' + eur(e.price) + '<\/b><\/span>' + (e.note ? '<small>' + esc(e.note) + '<\/small>' : '') + '<\/span>';\n    h += multi ? '<span class=\"s-box\" aria-hidden=\"true\">' + (sel ? ic('check', 14, '#fff') : '') + '<\/span>' : '<span class=\"s-arrow\" aria-hidden=\"true\">\u2192<\/span>';\n    return h + '<\/button>';\n  }\n  function optCard(title, desc, sel, fn) {\n    return '<button type=\"button\" class=\"s-uw s-rc' + (sel ? ' is-sel' : '') + '\" data-h=\"' + on(fn) + '\" aria-pressed=\"' + !!sel + '\" data-fid=\"' + esc(title) + '\"><span class=\"s-ring\" aria-hidden=\"true\"><i><\/i><\/span>' +\n      '<span class=\"s-rc-tx\"><b>' + esc(title) + '<\/b>' + (desc ? '<span>' + esc(desc) + '<\/span>' : '') + '<\/span><\/button>';\n  }\n  function chip(label, sel, fn) {\n    return '<button type=\"button\" class=\"s-uw s-chip' + (sel ? ' is-sel' : '') + '\" data-h=\"' + on(fn) + '\" aria-pressed=\"' + !!sel + '\" data-fid=\"' + esc(label) + '\">' + (sel ? ic('check', 16, '#C4B5FD') : '') + esc(label) + '<\/button>';\n  }\n  function slider(o) {\n    var input = '<input type=\"range\" id=\"sl-' + o.key + '\" data-sl=\"' + o.key + '\" min=\"' + o.min + '\" max=\"' + o.max + '\" step=\"' + o.step + '\" value=\"' + o.value + '\" aria-label=\"' + esc(o.aria) + '\" aria-valuetext=\"' + esc(o.big + ' ' + o.unit) + '\">' +\n      '<div class=\"s-ticks\" aria-hidden=\"true\">' + o.ticks.map(function (t) { return '<span>' + t + '<\/span>'; }).join('') + '<\/div>';\n    if (o.bigLeft) return '<div class=\"s-sl\"><div class=\"s-big\"><div class=\"s-big-v\"><b data-bind=\"' + o.key + '-big\">' + esc(o.big) + '<\/b><span data-bind=\"' + o.key + '-unit\">' + esc(o.unit) + '<\/span><\/div><div class=\"s-big-r\">' + input + '<\/div><\/div><\/div>';\n    return '<div class=\"s-sl\"><div class=\"s-sl-h\"><label class=\"s-lab\" for=\"sl-' + o.key + '\">' + esc(o.label) + '<\/label><span class=\"s-sl-v\"><b data-bind=\"' + o.key + '-big\">' + esc(o.big) + '<\/b><span data-bind=\"' + o.key + '-unit\">' + esc(o.unit) + '<\/span><\/span><\/div>' + input + '<\/div>';\n  }\n  function next() { var l = screens().length; st.step = Math.min(l - 1, st.step + 1); st.err = null; st.errFields = {}; render(true); }\n  var tAuto;\n  function auto(fn) { fn(); render(false); clearTimeout(tAuto); tAuto = setTimeout(next, 150); }\n  function answer(id, value) { track('sim_answer', { screen_id: id, value: value }); }\n\n  function sliderDefs(id) {\n    var s = st.s, v = st.v, u = st.u;\n    if (id === 'vol') return [{ key: 'vol', bigLeft: true, big: VOLS[s.vol] > 10 ? '+10' : String(VOLS[s.vol]), unit: 'To', aria: 'Volume', min: 0, max: 5, step: 1, value: s.vol, ticks: ['1 To', '2 To', '3 To', '5 To', '10 To', '+10 To'],\n      set: function (x) { s.vol = x; setDefault('storage_volume', false); } }];\n    if (id === 'users') return [{ key: 'users', bigLeft: true, big: String(u.users), unit: 'utilisateurs', aria: \"Nombre d'utilisateurs\", min: 5, max: 50, step: 1, value: u.users, ticks: ['5', '25', '50'],\n      set: function (x) { u.users = x; u.usersUnknown = false; setDefault('suite_users', false); } }];\n    if (id === 'size') {\n      var out = [];\n      if (v.size === 'custom') out.push(\n        { key: 'cpu', label: 'vCPU', aria: 'vCPU', big: String(v.cpu), unit: 'vCPU', min: 1, max: 32, step: 1, value: v.cpu, ticks: ['1', '16', '32'], set: function (x) { v.cpu = x; } },\n        { key: 'ram', label: 'RAM', aria: 'RAM', big: String(v.ram), unit: 'Go', min: 2, max: 128, step: 2, value: v.ram, ticks: ['2 Go', '64 Go', '128 Go'], set: function (x) { v.ram = x; } });\n      out.push(\n        { key: 'count', label: 'Nombre de serveurs', aria: 'Nombre de serveurs', big: v.count > 10 ? '10 et +' : String(v.count), unit: v.count > 10 ? '' : (v.count > 1 ? 'serveurs' : 'serveur'), min: 1, max: 11, step: 1, value: v.count, ticks: ['1', '5', '10 et +'], set: function (x) { v.count = x; } },\n        { key: 'disk', label: 'Stockage disque', aria: 'Stockage disque', big: fmt(v.disk), unit: 'Go', min: 20, max: 2000, step: 10, value: v.disk, ticks: ['20 Go', '1 000 Go', '2 000 Go'], set: function (x) { v.disk = x; } });\n      return out;\n    }\n    return [];\n  }\n  function liveDef() {\n    if (sid() !== 'users') return null;\n    var t = suiteTotal();\n    return { big: eur(t) + ' \/ mois', small: 'soit ' + (t \/ st.u.users).toLocaleString('fr-FR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).replace(\/[\u202f\u00a0\\s]\/g, '\u00a0') + '\u00a0\u20ac HT par utilisateur' };\n  }\n\n  function questionHtml() {\n    var id = sid(), c = st.c, s = st.s, v = st.v, u = st.u, i = st.i, offer = st.offer;\n    var title = '', help = '', list = '', grid = '', groups = '', advise = '', other = '', fixed = '', liveBox = '';\n    var acts = false, unsure = true, unsureLabel = 'Je ne sais pas encore', contLabel = 'Continuer', disabled = false, onCont = next, onUnsure = next;\n    if (id === 'profile') {\n      title = 'Quel est votre profil ?';\n      list = PROFILES.map(function (n) { return listCard(n[1], '', n[2], c.profile === n[0], function () { auto(function () { c.profile = n[0]; answer(id, n[0]); }); }); }).join('');\n    }\n    if (id === 'situation') {\n      title = \"Qu'avez-vous d\u00e9j\u00e0 en place ?\";\n      list = SITS.map(function (n) { return listCard(n[0] === 'unknown' ? SIT_UNKNOWN[offer] : n[1], n[2], n[3], c.sit === n[0], function () { auto(function () { c.sit = n[0]; answer(id, n[0]); }); }); }).join('');\n    }\n    if (id === 'situationSuite') {\n      title = \"Qu'utilisez-vous aujourd'hui ?\";\n      list = SUITE_SITS.map(function (n) { return listCard(n[1], n[2], n[3], c.sit === n[0], function () {\n        if (n[0] === 'other') { clearTimeout(tAuto); c.sit = 'other'; answer(id, 'other'); render(false); var o = app.querySelector('[data-text=\"sitOther\"]'); if (o) o.focus(); }\n        else auto(function () { c.sit = n[0]; answer(id, n[0]); });\n      }); }).join('');\n      if (c.sit === 'other') { other = '<input class=\"s-other\" data-text=\"sitOther\" value=\"' + esc(c.sitOther) + '\" placeholder=\"Pr\u00e9cisez\" aria-label=\"Pr\u00e9cisez\" data-fid=\"sitOther\">'; acts = true; unsure = false; }\n    }\n    if (offer === 'storage') {\n      if (id === 'need') {\n        title = 'Que voulez-vous stocker ?';\n        list = STORAGE_NEEDS.map(function (n) { return listCard(n[1], '', n[2], s.need.indexOf(n[0]) > -1, function () { s.need = toggle(s.need, n[0]); answer(id, s.need.slice()); render(false); }, null, true); }).join('');\n        acts = true; disabled = !s.need.filter(function (x) { return x !== 'unknown'; }).length;\n        onUnsure = function () { s.need = ['unknown']; setDefault('storage_need', true); answer(id, 'unknown'); next(); };\n      }\n      if (id === 'vol') {\n        title = 'Quel volume ?';\n        \/* Same 2 cards as the \"Hebergement\" block of the other offers, Cloud souverain preselected. *\/\n        groups = group('H\u00e9bergement', false, '<div class=\"s-cards2\">' +\n          optCard('Cloud souverain', 'H\u00e9bergement en France chez Outscale', s.host !== 'snc', function () { s.host = 'cs'; answer('storage_hosting', 'cs'); render(false); }) +\n          optCard('SecNumCloud', 'Qualification ANSSI', s.host === 'snc', function () { s.host = 'snc'; answer('storage_hosting', 'snc'); render(false); }) + '<\/div>');\n        acts = true; onCont = function () { answer(id, VOLS[s.vol]); next(); };\n        onUnsure = function () { s.vol = 2; setDefault('storage_volume', true); answer(id, 'unknown'); next(); };\n      }\n    }\n    if (offer === 'vps') {\n      if (id === 'use') {\n        title = '\u00c0 quoi servira votre serveur ?';\n        list = VPS_USES.map(function (n) { return listCard(n[1], '', n[2], v.use.indexOf(n[0]) > -1, function () { v.use = toggle(v.use, n[0]); answer(id, v.use.slice()); render(false); }, null, true); }).join('');\n        acts = true; disabled = !v.use.length;\n        onUnsure = function () { v.use = ['unknown']; setDefault('vps_use', true); answer(id, 'unknown'); next(); };\n      }\n      if (id === 'size') {\n        title = 'Quelle taille de serveur ?';\n        grid = '<div class=\"s-sizes\">' + Object.keys(SIZES).map(function (k) { var z = SIZES[k];\n          return sizeCard(k, z[0] + ' vCPU \u00b7 ' + z[1] + ' Go de RAM', v.size === k, function () { v.size = k; v.cpu = z[0]; v.ram = z[1]; v.disk = z[2]; setDefault('vps_size', false); answer(id, k); render(false); }); }).join('') +\n          sizeCard('Sur mesure', 'Je choisis mes ressources', v.size === 'custom', function () { v.size = 'custom'; setDefault('vps_size', false); answer(id, 'custom'); render(false); }) + '<\/div>';\n        acts = true; disabled = !v.size || v.size === 'unknown';\n        onCont = function () { answer('vps_config', { size: v.size, cpu: vpsRes()[0], ram: vpsRes()[1], count: v.count, disk: v.disk }); next(); };\n        onUnsure = function () { v.size = 'unknown'; v.cpu = 4; v.ram = 16; v.disk = 100; setDefault('vps_size', true); answer(id, 'unknown'); next(); };\n      }\n      if (id === 'options') {\n        title = 'Vos options';\n        groups = expert('R\u00e9gion', 'region', [['std', 'Standard', 'Donn\u00e9es en France'], ['snc', 'SecNumCloud', 'Qualification ANSSI, environ +20 %']]) +\n          expert('Sauvegardes quotidiennes', 'backup', [['yes', 'Oui'], ['no', 'Non']]) +\n          expert('Connexion VPN vers vos sites', 'vpn', [['yes', 'Oui'], ['no', 'Non']]) +\n          expert('Qui g\u00e8re le syst\u00e8me ?', 'managed', [['team', 'Votre \u00e9quipe'], ['omc', 'Ohmycad', 'Infog\u00e9rance, chiffr\u00e9e sur devis']]);\n        fixed = '<div class=\"s-fixed\">' + ic('check', 18, '#A78BFA') + 'Adresse IP publique incluse<\/div>';\n        acts = true; unsure = false; contLabel = 'Voir mon estimation';\n      }\n    }\n    if (offer === 'suite') {\n      if (id === 'plan') {\n        title = \"De quoi votre \u00e9quipe a-t-elle besoin ?\";\n        list = Object.keys(PLANS).map(function (k) { var p = PLANS[k]; return listCard(p.title, p.desc, p.icon, u.plan === k, function () { auto(function () { u.plan = k; answer(id, k); }); }); }).join('');\n      }\n      if (id === 'users') {\n        title = \"Combien d'utilisateurs ?\";\n        var lv = st.submitted && liveDef(); \/* aucun prix avant le formulaire (Victor 09\/10) *\/\n        if (lv) liveBox = '<div class=\"s-live\"><span class=\"s-lab\">Votre abonnement<\/span><span class=\"s-live-v\"><b data-bind=\"live-big\">' + esc(lv.big) + '<\/b><span data-bind=\"live-small\">' + esc(lv.small) + '<\/span><\/span><\/div>';\n        acts = true; unsureLabel = 'Aucune id\u00e9e, conseillez-moi';\n        onCont = function () { answer(id, u.users); next(); };\n        onUnsure = function () { u.users = 5; u.usersUnknown = true; setDefault('suite_users', true); answer(id, 'unknown'); next(); };\n      }\n      if (id === 'reqs') {\n        title = 'Vos exigences';\n        groups = group('H\u00e9bergement', false, '<div class=\"s-cards2\">' +\n            optCard('Cloud souverain', 'H\u00e9bergement en France chez Outscale', u.host === 'cs', function () { u.host = 'cs'; setDefault('suite_hosting', false); answer('suite_hosting', 'cs'); render(false); }) +\n            optCard('SecNumCloud', 'Qualification ANSSI', u.host === 'snc', function () { u.host = 'snc'; setDefault('suite_hosting', false); answer('suite_hosting', 'snc'); render(false); }) + '<\/div>') +\n          group('Options sur devis (facultatif)', false, '<div class=\"s-chips\">' + SUITE_OPTS.map(function (o) { var sel = u.opts.indexOf(o) > -1;\n            return chip(o, sel, function () { u.opts = sel ? u.opts.filter(function (x) { return x !== o; }) : u.opts.concat([o]); answer('suite_options', u.opts.slice()); render(false); }); }).join('') + '<\/div>');\n        acts = true; contLabel = 'Voir mon estimation';\n        onUnsure = function () { u.host = 'cs'; setDefault('suite_hosting', true); answer('suite_hosting', 'unknown'); next(); };\n      }\n    }\n    if (offer === 'ia') {\n      if (id === 'use') {\n        title = \"Quel est votre cas d'usage ?\";\n        list = IA_USES.map(function (n) { return listCard(n[1], n[2], n[3], i.use.indexOf(n[0]) > -1, function () { i.use = toggle(i.use, n[0]); answer(id, i.use.slice()); render(false); }, null, true); }).join('');\n        var adOn = i.use.indexOf('advise') > -1;\n        advise = '<button type=\"button\" class=\"s-uw s-advise' + (adOn ? ' is-on' : '') + '\" aria-pressed=\"' + adOn + '\" data-fid=\"advise\" data-h=\"' + on(function () { i.use = toggle(i.use, 'advise'); answer(id, i.use.slice()); render(false); }) + '\">' + ic('compass', 22, '#C4B5FD') + 'Aucune id\u00e9e, conseillez-moi<\/button>';\n        acts = true; unsure = false; disabled = !i.use.length;\n      }\n      if (id === 'stage') {\n        title = 'O\u00f9 en \u00eates-vous ?';\n        list = IA_STAGES.map(function (n) { return listCard(n[1], '', n[2], i.stage === n[0], function () { auto(function () { i.stage = n[0]; setDefault('ia_stage', n[0] === 'unknown'); answer(id, n[0]); }); }); }).join('');\n      }\n      if (id === 'reqs') {\n        title = 'Vos exigences';\n        groups = group('R\u00e9gion', false, '<div class=\"s-cards2\">' + IA_REGIONS.map(function (r) { return optCard(r[1], r[2], i.region === r[0], function () { i.region = r[0]; answer('ia_region', r[0]); render(false); }); }).join('') + '<\/div>') +\n          group(\"Combien d'utilisateurs ?\", false, '<div class=\"s-chips\">' + IA_USERS.map(function (o) { return chip(o, i.users === o, function () { i.users = o; answer('ia_users', o); render(false); }); }).join('') + '<\/div>');\n        acts = true; unsure = false;\n      }\n    }\n    var h = '<h2 class=\"s-q\" tabindex=\"-1\" id=\"sim-q\">' + esc(title) + '<\/h2>' + (help ? '<p class=\"s-help\">' + esc(help) + '<\/p>' : '');\n    if (list) h += '<div class=\"s-list\">' + list + '<\/div>' + advise + other;\n    h += grid + sliderDefs(id).map(slider).join('') + liveBox + groups + fixed;\n    if (acts) h += '<div class=\"s-acts\"><button type=\"button\" class=\"s-btn\" data-fid=\"cont\" data-h=\"' + on(onCont) + '\"' + (disabled ? ' disabled' : '') + '>' + esc(contLabel) + ' <span aria-hidden=\"true\">\u2192<\/span><\/button>' +\n      (unsure ? '<button type=\"button\" class=\"s-btn s-btn-ghost\" data-fid=\"unsure\" data-h=\"' + on(onUnsure) + '\">' + esc(unsureLabel) + '<\/button>' : '') + '<\/div>';\n    return h;\n  }\n  function sizeCard(title, desc, sel, fn) {\n    return '<button type=\"button\" class=\"s-uw s-size' + (sel ? ' is-sel' : '') + '\" data-h=\"' + on(fn) + '\" aria-pressed=\"' + !!sel + '\" data-fid=\"size-' + esc(title) + '\"><b>' + esc(title) + '<\/b><span>' + esc(desc) + '<\/span><\/button>';\n  }\n  function group(label, optional, inner, expertHtml) {\n    return '<div class=\"s-grp\" role=\"group\" aria-label=\"' + esc(label) + '\"><div class=\"s-grp-h s-lab\"><span>' + esc(label) + '<\/span>' + (optional ? '<span class=\"s-opt-tag\">Facultatif<\/span>' : '') + (expertHtml || '') + '<\/div>' + inner + '<\/div>';\n  }\n  function expert(label, key, opts) {\n    var v = st.v, exOn = v[key] === 'unknown';\n    var ex = '<button type=\"button\" class=\"s-uw s-expert' + (exOn ? ' is-on' : '') + '\" aria-pressed=\"' + exOn + '\" data-fid=\"ex-' + key + '\" data-h=\"' + on(function () { v[key] = 'unknown'; setDefault('vps_' + key, true); answer('vps_' + key, 'unknown'); render(false); }) + '\">' + (exOn ? ic('check', 14, '#fff') : '') + '\u00c0 d\u00e9finir avec un expert<\/button>';\n    var cards = '<div class=\"s-cards2\">' + opts.map(function (o) { return optCard(o[1], o[2] || '', v[key] === o[0], function () { v[key] = o[0]; setDefault('vps_' + key, false); answer('vps_' + key, o[0]); render(false); }); }).join('') + '<\/div>';\n    return group(label, false, cards, ex);\n  }\n\n  \/* ---------- Render: final screens ---------- *\/\n  function finalData() {\n    var offer = st.offer, s = st.s, v = st.v, u = st.u, d = st.defaults;\n    var F = { title: '', rows: [], month: '', perMonth: true, setup: null, setupOld: null, setupPre: '', subs: [], note: '', inc: null, incTitle: '', locked: false, quote: false, formTitle: 'Recevoir mon devis', formBtn: 'Recevoir mon devis', price: null };\n    var yn = function (x) { return x === 'yes' ? 'Oui' : x === 'no' ? 'Non' : TBD; };\n    if (offer === 'storage') {\n      var pk = pack(VOLS[s.vol]);\n      F.title = pk ? 'Stockage souverain, pack ' + pk.name : 'Stockage souverain, sur mesure';\n      var shost = s.host === 'snc' ? 'snc' : 'cs';\n      \/* Hosting travels like the Suite one: a recap row, so a \"- Hebergement : ...\" line in message. *\/\n      F.rows = [{ k: 'Volume', v: d.storage_volume ? TBD : volLabel(s.vol) }, { k: 'H\u00e9bergement', v: shost === 'snc' ? 'SecNumCloud' : 'Cloud souverain' }];\n      if (pk) {\n        \/* Setup no longer chosen in the flow: monthly tile only, setup block shown after the form (no setup fee sent). *\/\n        F.price = { monthly: pk[shost], pack: pk.name };\n        if (st.submitted) { F.month = eur(pk[shost]); F.setupBox = true; }\n        else { \/* Locked like VPS: fixed placeholder digits. *\/ F.locked = true; F.month = '8 888 \u20ac HT'; }\n      }\n      else { F.month = 'Sur devis'; F.perMonth = false; F.quote = true; F.formTitle = '\u00catre rappel\u00e9 par un sp\u00e9cialiste'; F.price = 'Sur devis'; }\n      F.incTitle = 'Inclus dans chaque pack'; F.inc = [\"H\u00e9berg\u00e9 sur l'infrastructure certifi\u00e9e HDS d'Outscale\", 'Sauvegardes versionn\u00e9es', 'Trafic sortant inclus', 'Volume modulable'];\n    }\n    if (offer === 'vps') {\n      var devis = v.count > CONFIG.vps.maxServers, r = vpsRes();\n      var sizeName = v.size === 'custom' ? 'sur mesure' : (SIZES[v.size] ? v.size : 'M');\n      var reg = v.region === 'snc' ? 'SecNumCloud' : 'standard';\n      F.title = devis ? 'Plus de 10 serveurs, r\u00e9gion ' + reg : v.count + ' serveur' + (v.count > 1 ? 's' : '') + ' ' + sizeName + ', r\u00e9gion ' + reg;\n      var srv = (devis ? '10 et +' : v.count) + ' \u00d7 ' + (v.size === 'custom' ? 'Sur mesure' : sizeName) + ' \u00b7 ' + r[0] + ' vCPU \u00b7 ' + r[1] + ' Go de RAM';\n      F.rows = [\n        { k: 'Serveurs', v: v.size === 'unknown' ? srv + ', taille \u00e0 pr\u00e9ciser au cadrage' : srv },\n        { k: 'Stockage', v: fmt(v.disk) + ' Go par serveur' },\n        { k: 'R\u00e9gion', v: v.region === 'snc' ? 'SecNumCloud' : v.region === 'std' ? 'Standard, donn\u00e9es en France' : TBD },\n        { k: 'Sauvegardes', v: v.backup === 'yes' ? 'Quotidiennes' : yn(v.backup) },\n        { k: 'VPN', v: yn(v.vpn) },\n        { k: 'Exploitation', v: v.managed === 'omc' ? 'Ohmycad, infog\u00e9rance' : v.managed === 'team' ? 'Votre \u00e9quipe' : TBD }\n      ];\n      if (devis) { F.month = 'Sur devis'; F.perMonth = false; F.quote = true; F.formTitle = '\u00catre rappel\u00e9 par un sp\u00e9cialiste'; F.formBtn = '\u00catre rappel\u00e9'; F.price = 'Sur devis'; }\n      else {\n        F.subs = v.managed === 'omc' ? ['Infog\u00e9rance : sur devis'] : [];\n        if (st.submitted) {\n          var e = vpsEstimate();\n          F.month = '\u2248 ' + eur(e.monthly); F.setup = eur(e.setup.amount); F.setupPre = e.setup.pre;\n          F.note = 'Estimation indicative. Le devis final est \u00e9tabli apr\u00e8s un cadrage avec un ing\u00e9nieur Ohmycad.';\n          F.price = { monthly: e.monthly, setup: e.setup.amount, setupFrom: !!e.setup.pre };\n        } else {\n          \/* Locked: fixed placeholder digits, independent of the configuration. *\/\n          F.locked = true; F.month = '\u2248 8\u00a0888\u00a0\u20ac HT'; F.setup = '8\u00a0888\u00a0\u20ac HT';\n        }\n      }\n    }\n    if (offer === 'suite') {\n      var k = planKey(), p = PLANS[k], cfg = CONFIG.suite.plans[k], t = suiteTotal();\n      var host = { k: 'H\u00e9bergement', v: d.suite_hosting ? TBD : (u.host === 'snc' ? 'SecNumCloud' : 'Cloud souverain') };\n      var opts = { k: 'Options', v: u.opts.length ? u.opts.join(', ') : 'Aucune' };\n      F.title = p.title + ', ' + (u.usersUnknown ? '5' : u.users) + ' utilisateurs';\n      F.rows = [{ k: 'Offre', v: p.title }, { k: 'Utilisateurs', v: u.usersUnknown ? TBD : String(u.users) }, host, opts];\n      if (st.submitted) { if (cfg.setup != null) F.setup = eur(cfg.setup); F.month = eur(t); }\n      else { \/* Locked like VPS: fixed placeholder digits, independent of the configuration. *\/ F.locked = true; F.month = '8 888 \u20ac HT'; if (cfg.setup != null) F.setup = '8 888 \u20ac HT'; }\n      F.subs = u.opts.length ? ['Options : chiffr\u00e9es sur devis'] : [];\n      F.incTitle = 'Inclus partout'; F.inc = ['Instance d\u00e9di\u00e9e en France chez Outscale', 'Double authentification, sauvegardes, mises \u00e0 jour', 'Support Ohmycad'];\n      F.price = { monthly: t, setup: cfg.setup };\n    }\n    if (offer === 'ia') {\n      F.entry = ENTRY[ENTRY[st.i.stage] ? st.i.stage : 'pilot'];\n      F.price = 'Sur devis';\n    }\n    return F;\n  }\n\n  function fieldsHtml(prefix) {\n    var e = st.errFields || {};\n    function fld(k, label, ph, type, ac) {\n      var id = prefix + '-' + k;\n      return '<div class=\"s-fld\"><label for=\"' + id + '\">' + label + '<\/label><input class=\"s-in-f\" id=\"' + id + '\" data-f=\"' + k + '\" data-fid=\"' + id + '\" type=\"' + type + '\" value=\"' + esc(st.f[k]) +\n        '\" placeholder=\"' + ph + '\" autocomplete=\"' + ac + '\" required' + (e[k] ? ' aria-invalid=\"true\" aria-describedby=\"' + prefix + '-err\"' : '') + '><\/div>';\n    }\n    var ind = ['+33|FR +33', '+32|BE +32', '+41|CH +41', '+352|LU +352'];\n    return '<div class=\"s-fields\">' +\n      '<div class=\"s-row s-row-2\">' + fld('prenom', 'Pr\u00e9nom', 'Ada', 'text', 'given-name') + fld('nom', 'Nom', 'Lovelace', 'text', 'family-name') + '<\/div>' +\n      '<div class=\"s-row s-row-1\">' + fld('societe', 'Soci\u00e9t\u00e9', 'Votre soci\u00e9t\u00e9', 'text', 'organization') + '<\/div>' +\n      '<div class=\"s-row s-row-1\">' + fld('email', 'Email professionnel', 'ada@lovelace.com', 'email', 'email') + '<\/div>' +\n      '<div class=\"s-row s-row-t\"><div class=\"s-fld\"><label for=\"' + prefix + '-ind\">Indicatif<\/label><select class=\"s-in-f\" id=\"' + prefix + '-ind\" data-f=\"ind\" data-fid=\"' + prefix + '-ind\" autocomplete=\"tel-country-code\">' +\n      ind.map(function (o) { var p = o.split('|'); return '<option value=\"' + p[0] + '\"' + (st.f.ind === p[0] ? ' selected' : '') + '>' + p[1] + '<\/option>'; }).join('') + '<\/select><\/div>' +\n      fld('tel', 'T\u00e9l\u00e9phone', '6 12 34 56 78', 'tel', 'tel-national') + '<\/div><\/div>' +\n      (st.err ? '<p class=\"s-err\" id=\"' + prefix + '-err\" role=\"alert\">' + esc(st.err) + '<\/p>' : '');\n  }\n  var LEGAL = '<p class=\"s-legal\">En envoyant, vous acceptez d\\'\u00eatre recontact\u00e9 par Ohmycad. Aucune revente de vos donn\u00e9es. <a href=\"\/politique-de-confidentialite\/\">Politique de confidentialit\u00e9<\/a><\/p>';\n  function sentHtml(backAct, backLabel) {\n    return '<div class=\"s-sent\" id=\"sim-sent\" tabindex=\"-1\"><span class=\"s-sent-ic\">' + ic('check', 22, '#7C3AED') + '<\/span><div style=\"min-width:0\"><h3>Demande envoy\u00e9e.<\/h3><p>Un sp\u00e9cialiste Ohmycad vous rappelle sous 1 jour ouvr\u00e9.<\/p>' +\n      '<button type=\"button\" class=\"s-uw s-link\" data-h=\"' + on(backAct) + '\">' + backLabel + '<\/button><\/div><\/div>';\n  }\n\n  function finalHtml() {\n    var F = finalData(), h = '';\n    if (st.offer === 'ia') {\n      var en = F.entry;\n      h += '<h2 class=\"s-q\" tabindex=\"-1\" id=\"sim-q\">Voici par o\u00f9 commencer.<\/h2><p class=\"s-help\">Un sp\u00e9cialiste IA vous rappelle pour cadrer ce point d\\'entr\u00e9e avec vous.<\/p>';\n      h += '<div class=\"s-ia\"><div class=\"s-ia-card\"><span class=\"s-ia-tag\">Point d\\'entr\u00e9e recommand\u00e9<\/span><div class=\"s-ia-t\">' + esc(en.title) + '<\/div><div class=\"s-ia-d\">' + esc(en.desc) + '<\/div>' +\n        '<ul class=\"s-ia-ck\">' + en.checks.map(function (k) { return '<li>' + ic('check', 18, '#A78BFA') + '<span>' + esc(k) + '<\/span><\/li>'; }).join('') + '<\/ul><span class=\"s-ia-pr\">Tarif \u00e9tabli au cadrage<\/span><\/div>';\n      h += st.submitted ? sentHtml(restart, 'Faire une autre simulation \u2192') :\n        '<div class=\"s-white\"><form data-form=\"end\" novalidate><h3>Recevoir mon devis<\/h3>' + fieldsHtml('fe') + '<div style=\"margin-top:22px\"><button type=\"submit\" class=\"s-btn\" data-fid=\"send\">Recevoir mon devis ' + ic('send', 18) + '<\/button><\/div>' + LEGAL + '<\/form><\/div>';\n      return h + '<\/div>';\n    }\n    if (st.offer === 'vps' && st.formOpen && !st.submitted) {\n      return '<div class=\"s-white\"><div style=\"max-width:640px\"><div class=\"s-ey\">Serveurs et VPS \u00b7 Estimation<\/div><h2 class=\"s-h2w\" tabindex=\"-1\" id=\"sim-q\">Afficher mon estimation<\/h2>' +\n        '<p class=\"s-help\" style=\"color:var(--omc-gray);margin:8px 0 24px\">Vos coordonn\u00e9es pour d\u00e9bloquer l\\'estimation mensuelle de votre configuration.<\/p>' +\n        '<form data-form=\"vps_unlock\" novalidate>' + fieldsHtml('fu') + '<div style=\"margin-top:22px\"><button type=\"submit\" class=\"s-btn\" data-fid=\"send\">Afficher mon estimation <span aria-hidden=\"true\">\u2192<\/span><\/button><\/div>' + LEGAL + '<\/form><\/div><\/div>';\n    }\n    if ((st.offer === 'storage' || st.offer === 'suite') && st.formOpen && !st.submitted) {\n      return '<div class=\"s-white\"><div style=\"max-width:640px\"><div class=\"s-ey\">' + OFFER_NAMES[st.offer] + ' \u00b7 Prix<\/div><h2 class=\"s-h2w\" tabindex=\"-1\" id=\"sim-q\">Afficher mon prix<\/h2>' +\n        '<p class=\"s-help\" style=\"color:var(--omc-gray);margin:8px 0 24px\">Vos coordonn\u00e9es pour afficher le prix de votre configuration.<\/p>' +\n        '<form data-form=\"price_unlock\" novalidate>' + fieldsHtml('fu') + '<div style=\"margin-top:22px\"><button type=\"submit\" class=\"s-btn\" data-fid=\"send\">Afficher mon prix <span aria-hidden=\"true\">\u2192<\/span><\/button><\/div>' + LEGAL + '<\/form><\/div><\/div>';\n    }\n    h += '<div class=\"s-white\"><div class=\"s-ey\">Votre configuration<\/div><h2 class=\"s-h2w\" tabindex=\"-1\" id=\"sim-q\">' + esc(F.title) + '<\/h2>';\n    h += '<div class=\"s-tiles' + (F.locked ? ' is-locked' : '') + '\"' + (F.locked ? ' aria-hidden=\"true\"' : '') + '><div class=\"s-t1\"><div class=\"s-tl\">Chaque mois<\/div><div class=\"s-month' + (F.month.length > 12 ? ' is-long' : '') + '\"><span id=\"sim-month\">' + F.month + '<\/span>' + (F.perMonth ? '<span class=\"s-per\"> \/ mois<\/span>' : '') + '<\/div><\/div>';\n    if (F.setup) h += '<div class=\"s-t2\"><div class=\"s-tl\">Une seule fois<\/div>' + (F.setupOld ? '<div class=\"s-old\">' + F.setupOld + '<\/div>' : '') + (F.setupPre ? '<div class=\"s-pre\">' + F.setupPre + '<\/div>' : '') +\n      '<div class=\"s-setup\" id=\"sim-setup\">' + F.setup + '<\/div><div class=\"s-setup-l\">Mise en service<\/div><\/div>';\n    h += '<\/div>' + F.subs.map(function (x) { return '<div class=\"s-sub\">' + esc(x) + '<\/div>'; }).join('') + (F.note ? '<p class=\"s-note\">' + esc(F.note) + '<\/p>' : '');\n    if (F.setupBox) { var su = CONFIG.storage.setup;\n      h += '<div class=\"s-sbox\"><div class=\"s-sbox-l\"><div class=\"s-sbox-t\">La mise en service, on s\\'en occupe.<\/div><p>Un ing\u00e9nieur Ohmycad configure tout avec vous, vous n\\'avez rien \u00e0 installer.<\/p><ul>' +\n        SETUP_CHECKS.map(function (x) { return '<li>' + ic('check', 18, '#A78BFA') + '<span>' + esc(x) + '<\/span><\/li>'; }).join('') + '<\/ul><\/div>' +\n        '<div class=\"s-sbox-r\"><div class=\"s-sbox-old\">' + eur(su.annualStruck) + '<\/div><div class=\"s-sbox-p\">' + eur(su.annual) + '<\/div><div class=\"s-sbox-n\">Paiement unique, avec engagement annuel sur le pack.<\/div><\/div><\/div>'; }\n    h += '<ul class=\"s-rows\">' + F.rows.map(function (r) { return '<li><span>' + esc(r.k) + '<\/span><b>' + esc(r.v) + '<\/b><\/li>'; }).join('') + '<\/ul>';\n    if (F.inc) h += '<div class=\"s-inc\"><div class=\"s-tl\">' + esc(F.incTitle) + '<\/div><ul>' + F.inc.map(function (x) { return '<li>' + ic('check', 16, '#7C3AED') + '<span>' + esc(x) + '<\/span><\/li>'; }).join('') + '<\/ul><\/div>';\n    var isVps = st.offer === 'vps';\n    if (F.locked) h += '<div class=\"s-lock\"><div class=\"s-lock-tx\">' + ic('lock', 20, '#7C3AED') + (isVps\n        ? '<p><strong>Estimation verrouill\u00e9e.<\/strong> Renseignez vos coordonn\u00e9es pour afficher votre estimation mensuelle.<\/p><\/div>'\n        : '<p><strong>Prix verrouill\u00e9.<\/strong> Renseignez vos coordonn\u00e9es pour afficher votre prix.<\/p><\/div>') +\n      '<button type=\"button\" class=\"s-btn\" data-fid=\"unlock\" data-h=\"' + on(function () { st.formOpen = true; st.err = null; st.errFields = {}; render(true); }) + '\">' + (isVps ? 'D\u00e9bloquer l\\'estimation' : 'Afficher mon prix') + '<\/button><\/div>';\n    else if (st.submitted) h += sentHtml(restart, 'Faire une autre simulation \u2192');\n    else if (F.quote) h += '<div class=\"s-form\"><form data-form=\"end\" novalidate><h3>' + esc(F.formTitle) + '<\/h3>' + fieldsHtml('fe') +\n      '<div style=\"margin-top:22px\"><button type=\"submit\" class=\"s-btn\" data-fid=\"send\">' + esc(F.formBtn) + ' ' + ic('send', 18) + '<\/button><\/div>' + LEGAL + '<\/form><\/div>';\n    return h + '<\/div>';\n  }\n\n  function directHtml() {\n    var h = '<div class=\"s-direct\"><button type=\"button\" class=\"s-uw s-back-d\" data-fid=\"close-direct\" data-h=\"' + on(closeDirect) + '\">\u2190 Revenir au simulateur<\/button><div class=\"s-white\">';\n    if (st.directSent) {\n      h += '<div style=\"display:flex;gap:16px;align-items:flex-start\" id=\"sim-sent\" tabindex=\"-1\"><span class=\"s-sent-ic\">' + ic('check', 22, '#7C3AED') + '<\/span><div style=\"min-width:0\"><h3 style=\"font-size:24px;font-weight:800\">Demande envoy\u00e9e.<\/h3>' +\n        '<p style=\"margin:6px 0 0;font-size:17px;line-height:1.5\">Un sp\u00e9cialiste Ohmycad vous rappelle sous 1 jour ouvr\u00e9.<\/p><button type=\"button\" class=\"s-uw s-link\" data-h=\"' + on(closeDirect) + '\">\u2190 Revenir au simulateur<\/button><\/div><\/div>';\n    } else {\n      h += '<form data-form=\"quick\" novalidate><div class=\"s-ey\">\u00c9change direct<\/div><h2 class=\"s-h2w\" tabindex=\"-1\" id=\"sim-q\">Demande de contact<\/h2>' +\n        '<p style=\"margin:8px 0 24px;font-size:17px;line-height:1.5;color:var(--omc-gray)\">Un sp\u00e9cialiste vous rappelle pour comprendre votre besoin, sans engagement.<\/p>' + fieldsHtml('fq') +\n        '<label class=\"s-consent\"><input type=\"checkbox\" data-consent=\"1\" data-fid=\"consent\"' + (st.consent ? ' checked' : '') + ' required><span>J\\'autorise Ohmycad \u00e0 me recontacter concernant cette demande.<\/span><\/label>' +\n        '<div style=\"margin-top:22px\"><button type=\"submit\" class=\"s-btn s-btn-full\" data-fid=\"send\">Envoyer ma demande<\/button><\/div>' +\n        '<div class=\"s-reass\"><span>' + ic('shield', 16) + 'Donn\u00e9es confidentielles<\/span><span>' + ic('clock', 16) + 'Rappel sous 1 jour ouvr\u00e9<\/span><\/div><\/form>';\n    }\n    return h + '<\/div><\/div>';\n  }\n\n  function startHtml() {\n    return '<div class=\"s-start\"><h2 tabindex=\"-1\" id=\"sim-q\">Que souhaitez-vous chiffrer ?<\/h2><div class=\"s-offers\">' +\n      START.map(function (d) { return '<button type=\"button\" class=\"s-uw s-offer\" data-fid=\"offer-' + d[0] + '\" data-h=\"' + on(function () { st = base(); st.offer = d[0]; answer('offer', d[0]); render(true); }) + '\">' +\n        '<span class=\"s-offer-ic\">' + ic(d[1], 22) + '<\/span><span class=\"s-offer-tx\"><b>' + esc(d[2]) + '<\/b><span>' + esc(d[3]) + '<\/span><\/span><\/button>'; }).join('') +\n      '<\/div><\/div><ul class=\"s-trust\"><li>H\u00e9bergement en France chez Outscale<\/li><li>Rappel sous 1 jour ouvr\u00e9<\/li><li>Un interlocuteur unique<\/li><\/ul>';\n  }\n\n  function flowHtml() {\n    var sc = screens(), curTab = sc[st.step][1], id = sid();\n    var tabs = TAB_LABELS.map(function (l, n) {\n      if (n === curTab) return '<li><span class=\"s-tab is-on\" aria-current=\"step\">' + l + '<\/span><\/li>';\n      if (n < curTab) return '<li><button type=\"button\" class=\"s-uw s-tab is-done\" data-fid=\"tab-' + n + '\" data-h=\"' + on(function () { for (var k = 0; k < sc.length; k++) if (sc[k][1] === n) { st.step = k; break; } st.err = null; st.errFields = {}; render(true); }) + '\">\u00b7 ' + l + '<\/button><\/li>';\n      return '<li><span class=\"s-tab\">' + l + '<\/span><\/li>';\n    }).join('');\n    var h = '<nav class=\"s-tabs-w\" aria-label=\"\u00c9tapes\"><div class=\"s-tabs-in\"><ol class=\"s-tabs\">' + tabs + '<\/ol><div class=\"s-prog\" aria-hidden=\"true\"><i style=\"width:' + ((st.step + 1) \/ sc.length * 100) + '%\"><\/i><\/div><\/div><\/nav>';\n    h += '<div class=\"s-nav\"><button type=\"button\" class=\"s-uw s-back\" data-fid=\"back\" data-h=\"' + on(back) + '\">' + ic('back', 18) + 'Retour<\/button>' +\n      '<button type=\"button\" class=\"s-uw s-restart\" data-fid=\"restart\" data-h=\"' + on(restart) + '\">' + ic('restart', 16) + 'Red\u00e9marrer<\/button><\/div>';\n    return h + (id === 'final' ? finalHtml() : questionHtml());\n  }\n\n  function footHtml() {\n    return '<div class=\"s-foot\"><span>Prix HT. Vos donn\u00e9es restent confidentielles (RGPD).<\/span>' +\n      (st.direct ? '' : '<button type=\"button\" class=\"s-uw s-chat\" data-fid=\"open-direct\" data-h=\"' + on(openDirect) + '\">' + ic('chat', 20) + 'Vous pr\u00e9f\u00e9rez \u00e9changer directement avec nous ?<\/button>') + '<\/div>';\n  }\n\n  var lastView = '';\n  function render(focusTitle) {\n    var act = document.activeElement, fid = act && app.contains(act) ? act.getAttribute('data-fid') : null;\n    H = [];\n    app.innerHTML = (st.direct ? directHtml() : st.offer ? flowHtml() : startHtml()) + footHtml();\n    document.getElementById('ocs-sim').classList.toggle('is-flow', !!(st.offer || st.direct));\n    var view = st.direct ? 'direct' : st.offer ? st.offer + ':' + sid() + (st.formOpen ? ':form' : '') : 'start';\n    if (view !== lastView) {\n      lastView = view;\n      track('sim_screen_view', { offer: st.offer || '', tab: st.offer && !st.direct ? TAB_LABELS[screens()[st.step][1]] : '', screen_id: st.direct ? 'quick_form' : (sid() || 'start'), step_number: st.offer ? st.step + 1 : 0 });\n    }\n    if (focusTitle) {\n      var t = document.getElementById('sim-q') || document.getElementById('sim-sent');\n      if (t) { t.focus({ preventScroll: true });\n        var h1 = document.querySelector('#ocs-sim .s-hero h1'), hd = document.getElementById('omh');\n        if (window.innerWidth >= 768 && h1) { \/* mode une page : recalage instantane, seulement si le titre est cache sous le header (pas d'animation : le header change de hauteur au defilement) *\/\n          var hb = hd ? Math.max(0, hd.getBoundingClientRect().bottom) : 72, ht = h1.getBoundingClientRect().top;\n          var ty = Math.max(0, ht + window.scrollY - hb - 40); if (Math.abs(ty - window.scrollY) > 4) window.scrollTo({ top: ty, behavior: 'instant' }); }\n        else { var top = t.getBoundingClientRect().top; if (top < 80 || top > window.innerHeight * 0.7) window.scrollBy({ top: top - 120, behavior: 'smooth' }); } }\n    } else if (fid) {\n      var el = app.querySelector('[data-fid=\"' + fid.replace(\/\"\/g, '\\\\\"') + '\"]'); if (el && !el.disabled) el.focus({ preventScroll: true });\n    }\n  }\n\n  \/* ---------- Navigation ---------- *\/\n  var saved = null;\n  function back() {\n    clearTimeout(tAuto);\n    if (st.step === 0) st.offer = null;\n    else if (st.formOpen && !st.submitted && sid() === 'final') st.formOpen = false;\n    else st.step -= 1;\n    st.err = null; st.errFields = {}; render(true);\n  }\n  function restart() { clearTimeout(tAuto); st = base(); render(true); }\n  function openDirect() {\n    clearTimeout(tAuto);\n    saved = { err: st.err, errFields: st.errFields };\n    st.direct = true; st.directSent = false; st.err = null; st.errFields = {};\n    track('sim_quick_form_open', { offer: st.offer || '', screen_id: sid() || 'start' });\n    render(true);\n  }\n  function closeDirect() {\n    st.direct = false; st.directSent = false; st.err = saved ? saved.err : null; st.errFields = saved ? saved.errFields : {};\n    track('sim_quick_form_back', { offer: st.offer || '', screen_id: sid() || 'start' });\n    render(true);\n  }\n\n  \/* ---------- Forms ---------- *\/\n  function validate(needConsent) {\n    var f = st.f, bad = {};\n    ['prenom', 'nom', 'societe', 'email', 'tel'].forEach(function (k) { if (!f[k].trim()) bad[k] = 1; });\n    var msg = Object.keys(bad).length ? 'Merci de compl\u00e9ter tous les champs.' : null;\n    if (!msg && !\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$\/.test(f.email.trim())) { bad.email = 1; msg = 'Adresse email mal form\u00e9e.'; }\n    if (!msg && !\/^\\+?\\d{6,15}$\/.test(f.tel.replace(\/[\\s.()-]\/g, ''))) { bad.tel = 1; msg = 'Num\u00e9ro de t\u00e9l\u00e9phone mal form\u00e9.'; }\n    if (!msg && needConsent && !st.consent) msg = \"Merci de cocher la case d'autorisation.\";\n    return { msg: msg, bad: bad };\n  }\n  function configRows() { if (!st.offer) return []; var F = finalData(); return st.offer === 'ia' ? [] : F.rows; }\n  function besoins() {\n    var o = st.offer;\n    if (o === 'storage') return { need: st.s.need.slice(), volume: st.defaults.storage_volume ? 'unknown' : volLabel(st.s.vol), hosting: st.s.host };\n    if (o === 'vps') { var r = vpsRes(); return { use: st.v.use.slice(), size: st.v.size, vcpu: r[0], ramGo: r[1], servers: st.v.count > 10 ? '10+' : st.v.count, diskGo: st.v.disk, region: st.v.region, backups: st.v.backup, vpn: st.v.vpn, managed: st.v.managed }; }\n    if (o === 'suite') return { plan: st.u.plan, users: st.u.usersUnknown ? 'unknown' : st.u.users, hosting: st.defaults.suite_hosting ? 'unknown' : st.u.host, options: st.u.opts.slice() };\n    if (o === 'ia') return { useCases: st.i.use.slice(), stage: st.i.stage, region: st.i.region, users: st.i.users };\n    return {};\n  }\n  function defaultsUsed() {\n    var d = Object.keys(st.defaults);\n    return d;\n  }\n  function payload(formType) {\n    var F = st.offer ? finalData() : null, price = null;\n    if (F) {\n      if (st.offer === 'vps' && !F.quote) { var e = vpsEstimate(); price = { monthly: e.monthly, setup: e.setup.amount, setupFrom: !!e.setup.pre }; }\n      else price = F.price;\n    }\n    return {\n      contact: { prenom: st.f.prenom.trim(), nom: st.f.nom.trim(), societe: st.f.societe.trim(), email: st.f.email.trim(), indicatif: st.f.ind, telephone: st.f.tel.trim(), consent: formType === 'quick' ? !!st.consent : undefined },\n      simulator: {\n        offer: st.offer, profil: st.c.profile, situation: st.c.sit, situationAutre: st.c.sitOther.trim(),\n        besoins: besoins(), configuration: configRows(), defaultsUsed: defaultsUsed(), price: price, lastScreen: sid() || 'start'\n      },\n      hidden: { business_unit: 'Outscale', source_page: location.pathname, offer: st.offer || '', utm_source: utm.utm_source, utm_medium: utm.utm_medium, utm_campaign: utm.utm_campaign, form_type: formType, form_version: 'simulateur-v1', entry: entry }\n    };\n  }\n  \/* HubSpot form \"Simulateur cloud souverain\" (Victor 07\/10): real properties instead of one message field.\n     topic_requested = sovereign_cloud is always sent here (routing). No token: the Forms endpoint does not need one.\n     On the lab (DEBUG_PAYLOAD) nothing is sent: the HubSpot body is logged to the console. *\/\n  var HS_URL = 'https:\/\/api.hsforms.com\/submissions\/v3\/integration\/submit\/8764694\/ae15a692-f37a-41ff-ac65-863a0cfa6640';\n  var IND_CC = { '+33': 'FR', '+32': 'BE', '+41': 'CH', '+352': 'LU' };\n  var HS_OFFER = { storage: 'stockage', suite: 'suite', vps: 'vps' }; \/* IA: no value given for cloud_offer, offer kept in the message *\/\n  function send(data) {\n    var c = data.contact, s = data.simulator, h = data.hidden, tel = c.indicatif + ' ' + c.telephone;\n    \/* Quick form opened before the configuration screens: send no pack, price or configuration (they would be defaults). *\/\n    var idx = function (id) { var l = screens(); for (var i = 0; i < l.length; i++) if (l[i][0] === id) return i; return 99; };\n    var configured = !st.offer ? false : h.form_type !== 'quick' ? true\n      : st.offer === 'storage' ? st.step > idx('vol') : st.offer === 'vps' ? !!st.v.size : st.offer === 'suite' ? !!st.u.plan : false;\n    var F = st.offer && configured ? finalData() : null, p = configured && s.price && typeof s.price === 'object' ? s.price : null;\n    var pack = '';\n    if (st.offer === 'storage' && p && p.pack) pack = p.pack;\n    else if (st.offer === 'suite') pack = PLANS[planKey()].title;\n    else if (st.offer === 'vps' && F) pack = F.title;\n    var lines = ['Simulateur cloud souverain, formulaire ' + h.form_type];\n    if (st.offer && !HS_OFFER[st.offer]) lines.push('Offre : ' + OFFER_NAMES[st.offer]);\n    if (F && F.title) lines.push('Configuration : ' + F.title);\n    if (configured) (s.configuration || []).forEach(function (r) { lines.push('- ' + r.k + ' : ' + r.v); });\n    if (configured && typeof s.price === 'string') lines.push('Prix : ' + s.price);\n    else if (p && p.setupFrom) lines.push('Mise en service : \u00e0 partir de ' + p.setup + ' \u20ac HT');\n    if (st.offer === 'storage') lines.push('Mise en service : \u00e0 pr\u00e9ciser lors de l\\'appel');\n    if (s.situation) lines.push('Situation : ' + s.situation + (s.situationAutre ? ' (' + s.situationAutre + ')' : ''));\n    if (s.defaultsUsed && s.defaultsUsed.length) lines.push('Valeurs par d\u00e9faut : ' + s.defaultsUsed.join(', '));\n    if (h.entry) lines.push('Entr\u00e9e : ' + h.entry);\n    if (h.utm_source || h.utm_medium || h.utm_campaign) lines.push('UTM : ' + [h.utm_source, h.utm_medium, h.utm_campaign].filter(Boolean).join(' \/ '));\n    function num(v) { return v == null || v === '' || isNaN(v) ? '' : String(Math.round(+v)); }\n    var fields = [\n      { objectTypeId: '0-1', name: 'firstname', value: c.prenom },\n      { objectTypeId: '0-1', name: 'lastname', value: c.nom },\n      { objectTypeId: '0-1', name: 'email', value: c.email },\n      { objectTypeId: '0-1', name: 'company', value: c.societe },\n      { objectTypeId: '0-1', name: 'mobilephone', value: tel }, { objectTypeId: '0-1', name: 'phone', value: tel },\n      { objectTypeId: '0-1', name: 'cb_billingcountry', value: IND_CC[c.indicatif] || '' },\n      { objectTypeId: '0-1', name: 'cloud_offer', value: HS_OFFER[st.offer] || '' },\n      { objectTypeId: '0-1', name: 'cloud_profile', value: st.c.profile || '' },\n      { objectTypeId: '0-1', name: 'cloud_pack', value: pack },\n      { objectTypeId: '0-1', name: 'cloud_monthly_price', value: p ? num(p.monthly) : '' },\n      { objectTypeId: '0-1', name: 'cloud_setup_fee', value: p ? num(p.setup) : '' },\n      { objectTypeId: '0-1', name: 'simulation_form_type', value: (h.form_type === 'quick' || (st.offer !== 'ia' && s.price === 'Sur devis')) ? 'Callback' : 'See the price' },\n      { objectTypeId: '0-1', name: 'message', value: lines.join('\\n') },\n      { objectTypeId: '0-1', name: 'topic_requested', value: 'sovereign_cloud' }\n    ].filter(function (x) { return x.value !== ''; });\n    var m = document.cookie.match(\/(?:^|; )hubspotutk=([^;]*)\/), ctx = { pageUri: location.href, pageName: document.title };\n    if (m) ctx.hutk = decodeURIComponent(m[1]);\n    var body = { fields: fields, context: ctx };\n    if (DEBUG_PAYLOAD) { console.log('[lab] HubSpot (non envoy\u00e9)', body); return Promise.resolve(); }\n    return fetch(HS_URL, { method: 'POST', headers: { 'Content-Type': 'application\/json' }, body: JSON.stringify(body) })\n      .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); });\n  }\n  var logged = {}, sending = false;\n  function submit(formType) {\n    var r = validate(formType === 'quick');\n    if (r.msg) {\n      st.err = r.msg; st.errFields = r.bad; render(false);\n      var first = Object.keys(r.bad)[0], pre = formType === 'quick' ? 'fq' : (formType === 'vps_unlock' || formType === 'price_unlock') ? 'fu' : 'fe';\n      var el = document.getElementById(pre + '-' + (first || 'prenom')); if (el && first) el.focus(); else if (!first) { var cb = app.querySelector('[data-consent]'); if (cb) cb.focus(); }\n      return;\n    }\n    var data = payload(formType);\n    if (DEBUG_PAYLOAD && !logged[formType]) { logged[formType] = true; console.log('[lab] simulator payload (' + formType + ')', JSON.parse(JSON.stringify(data))); }\n    if (sending) return;\n    sending = true;\n    send(data).then(function () {\n      sending = false;\n      track('sim_form_submit', { form_type: formType, offer: st.offer || '' });\n      st.err = null; st.errFields = {};\n      if (formType === 'quick') st.directSent = true; else st.submitted = true;\n      if (formType === 'vps_unlock' || formType === 'price_unlock') st.formOpen = false;\n      render(true);\n      live.textContent = 'Demande envoy\u00e9e. Un sp\u00e9cialiste Ohmycad vous rappelle sous 1 jour ouvr\u00e9.';\n    }).catch(function (e) {\n      sending = false;\n      track('sim_form_error', { form_type: formType, offer: st.offer || '', error: (e && e.message) || 'network' });\n      st.err = \"L'envoi a \u00e9chou\u00e9. R\u00e9essayez dans quelques instants.\"; st.errFields = {}; render(false);\n      live.textContent = st.err;\n    });\n  }\n\n  \/* ---------- Events ---------- *\/\n  app.addEventListener('click', function (e) {\n    var b = e.target.closest('[data-h]'); if (!b || !app.contains(b) || b.disabled) return;\n    var fn = H[+b.getAttribute('data-h')]; if (fn) fn();\n  });\n  app.addEventListener('submit', function (e) { e.preventDefault(); var t = e.target.getAttribute('data-form'); if (t) submit(t); });\n  app.addEventListener('input', function (e) {\n    var t = e.target;\n    if (t.hasAttribute('data-sl')) {\n      var key = t.getAttribute('data-sl'), def = sliderDefs(sid()).filter(function (d) { return d.key === key; })[0];\n      if (!def) return; def.set(+t.value);\n      var now = sliderDefs(sid()).filter(function (d) { return d.key === key; })[0];\n      var bb = app.querySelector('[data-bind=\"' + key + '-big\"]'), bu = app.querySelector('[data-bind=\"' + key + '-unit\"]');\n      if (bb) bb.textContent = now.big; if (bu) bu.textContent = now.unit;\n      t.setAttribute('aria-valuetext', now.big + ' ' + now.unit);\n      var lv = st.submitted && liveDef(); if (lv) { app.querySelector('[data-bind=\"live-big\"]').textContent = lv.big; app.querySelector('[data-bind=\"live-small\"]').textContent = lv.small; }\n      return;\n    }\n    if (t.hasAttribute('data-text')) { st.c[t.getAttribute('data-text')] = t.value; return; }\n    var k = t.getAttribute('data-f');\n    if (k) { st.f[k] = t.value; if (st.errFields[k]) { delete st.errFields[k]; t.removeAttribute('aria-invalid'); } }\n  });\n  app.addEventListener('change', function (e) {\n    var t = e.target;\n    if (t.hasAttribute('data-sl')) { answer(sid() + '_' + t.getAttribute('data-sl'), +t.value); return; }\n    if (t.hasAttribute('data-consent')) { st.consent = t.checked; return; }\n    var k = t.getAttribute('data-f'); if (k) st.f[k] = t.value;\n  });\n\n  if (entry) answer('entry', entry);\n  render(false);\n})();\n<\/script>\n<!-- omc-rappel:start -->\n<script>\n(function () {\n  function fix(links) {\n    Array.prototype.forEach.call(links, function (a) {\n      \n      var h = a.getAttribute('href') || '';\n      if (h && h.indexOf('sujet=') < 0) a.setAttribute('href', h.split('#')[0].split('?')[0] + '?sujet=sovereign_cloud');\n    });\n  }\n  \/* Outscale pages only: header callback link -> \/contactez-nous\/?sujet=sovereign_cloud *\/\n  fix(document.querySelectorAll('header a.omh-cta, header a.omh-mphone'));\n})();\n<\/script>\n<!-- omc-rappel:end -->\n\n\n<\/div><\/div>\n<\/section><\/main>","protected":false},"excerpt":{"rendered":"<p>Combien co\u00fbte votre cloud souverain ?<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"_breakdance_hide_in_design_set":false,"_breakdance_tags":"","footnotes":""},"class_list":["post-118327","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/ohmycad.com\/fr-ca\/wp-json\/wp\/v2\/pages\/118327","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ohmycad.com\/fr-ca\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ohmycad.com\/fr-ca\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ohmycad.com\/fr-ca\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ohmycad.com\/fr-ca\/wp-json\/wp\/v2\/comments?post=118327"}],"version-history":[{"count":0,"href":"https:\/\/ohmycad.com\/fr-ca\/wp-json\/wp\/v2\/pages\/118327\/revisions"}],"wp:attachment":[{"href":"https:\/\/ohmycad.com\/fr-ca\/wp-json\/wp\/v2\/media?parent=118327"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}