{"id":56762,"date":"2026-10-10T19:28:52","date_gmt":"2026-10-10T19:28:52","guid":{"rendered":"https:\/\/carmelcosmeticslabs.com\/?page_id=56762"},"modified":"2026-11-08T15:23:30","modified_gmt":"2026-11-08T15:23:30","slug":"cosmetic-price-calculator","status":"publish","type":"page","link":"https:\/\/carmelcosmeticslabs.com\/en\/cosmetic-price-calculator\/","title":{"rendered":"Cosmetic price calculator"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"56762\" class=\"elementor elementor-56762 elementor-52935\" data-elementor-post-type=\"page\">\n\t\t\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-b437d6a0 e-flex e-con-full cm-calculator-page e-con e-parent\" data-id=\"b437d6a0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0ee4c642 elementor-widget elementor-widget-html\" data-id=\"0ee4c642\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style>\n\/* Layout: guided flow (one question per step) on the left, live answer card on the right; full analysis below. Carmel teal on mint. *\/\n.cm-px,.px-dock{\n  --bg:#f4f8f6; --paper:#ffffff; --mint:#e9f3ef; --mint-2:#d7e8e1;\n  --ink:#10292a; --muted:#566d6c; --line:#dbe7e3;\n  --teal:#2f7266; --teal-ink:#ffffff; --deep:#0f3a35; --deep-ink:#eaf5f2; --deep-muted:#a9c9c2; --deep-line:#25544d;\n  --c-fab:#00826b; --c-mkt:#8048c4; --c-marge:#d6941a; --c-canal:#3f6fd1; --c-tva:#c4502f;\n  --k-fab:#27a582; --k-mkt:#9a7fe0; --k-marge:#bd841a; --k-canal:#5d8ae3; --k-tva:#dd6c50;\n  --good:#1d7a46; --warn:#8a5d00; --bad:#b3261e;\n  --z-low:#c4502f; --z-ok:#2a9d6e; --z-high:#d6941a;\n  --shade:16 58 53;\n  --f-display:\"Proxima Nova\",\"Bricolage Grotesque\",system-ui,sans-serif;\n  --f-body:\"Lato\",\"Instrument Sans\",system-ui,sans-serif;\n  --r-panel:20px; --r-card:16px; --r-field:12px;\n  --ease-out:cubic-bezier(.23,1,.32,1);\n}\n.cm-px{font:400 16px\/1.55 var(--f-body);color:var(--ink);background:var(--bg);-webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums;padding-block:clamp(32px,6vw,72px) 112px}\n.cm-px *{box-sizing:border-box}\n.cm-px [hidden]{display:none!important}\n.cm-px ::selection{background:var(--teal);color:var(--teal-ink)}\n.cm-px .wrap{max-width:1160px;margin-inline:auto;padding-inline:clamp(16px,4vw,40px)}\n.cm-px h1,.cm-px h2,.cm-px h3{font-family:var(--f-display);margin:0;text-wrap:balance;letter-spacing:-.015em;font-weight:700}\n.cm-px p{margin:0}\n.cm-px :focus-visible{outline:2px solid var(--teal);outline-offset:2px;border-radius:8px}\n.cm-px .ico{width:18px;height:18px;flex:none;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}\n\n.px-head{display:grid;gap:10px;max-width:720px;margin-bottom:clamp(24px,4vw,40px)}\n.px-head .px-h1{font-size:clamp(30px,4.4vw,48px);line-height:1.06}\n.px-lead{font-size:clamp(16px,1.6vw,18px);color:var(--muted);max-width:60ch}\n.px-eyebrow{font:600 13px\/1.2 var(--f-body);letter-spacing:.06em;text-transform:uppercase;color:var(--teal)}\n.px-proof{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px 22px;font-size:14px;color:var(--ink)}\n.px-proof li{display:flex;align-items:center;gap:8px}\n.px-proof .ico{width:16px;height:16px;color:var(--teal);stroke-width:2.4}\n.px-kick{font-size:16px;color:var(--ink)!important;font-weight:500}\n.px-faq{margin-top:clamp(48px,7vw,80px);display:grid;gap:14px}\n.px-faq h2{font-size:clamp(24px,3vw,32px)}\n.px-faq .px-method{margin-top:0;border-bottom:0}\n.px-faq .px-method:last-child{border-bottom:1px solid var(--line)}\n.px-faq-a{font-size:15px!important;line-height:1.6;color:var(--muted)}\n.px-note{margin:clamp(40px,6vw,64px) 0 0;max-width:720px;display:grid;gap:18px;padding-left:clamp(16px,2.4vw,26px);border-left:3px solid var(--teal)}\n.px-note blockquote{margin:0;display:grid;gap:12px;font-size:clamp(16px,1.6vw,18px);line-height:1.6;color:var(--ink)}\n.px-note figcaption{display:flex;align-items:center;gap:12px;font-size:14px;color:var(--muted)}\n.px-note figcaption b{display:block;color:var(--ink);font-weight:600}\n.px-note-av{width:40px;height:40px;border-radius:50%;background:var(--deep);color:var(--deep-ink);display:grid;place-items:center;font:700 14px\/1 var(--f-display)}\n\n.px-grid{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,1fr);gap:clamp(20px,3vw,32px);align-items:start}\n.px-panel{background:var(--paper);border:1px solid var(--line);border-radius:var(--r-panel);padding:clamp(20px,2.6vw,30px);min-width:0}\n\n\/* flow *\/\n.px-flow{display:grid;gap:24px}\n.px-prog{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:6px}\n.px-prog button{appearance:none;border:0;background:none;padding:0;display:grid;gap:8px;text-align:left;font:500 12.5px\/1.2 var(--f-body);color:var(--muted);cursor:pointer;min-height:28px}\n.px-prog button::before{content:\"\";height:4px;border-radius:2px;background:var(--mint-2);transition:background-color .3s ease}\n.px-prog button.done::before,.px-prog button.cur::before{background:var(--teal)}\n.px-prog button.cur{color:var(--ink);font-weight:600}\n.px-prog button:disabled{cursor:default;opacity:.7}\n.px-steps{min-height:290px;display:grid;align-content:start}\n.px-step{display:grid;gap:20px;align-content:start}\n.px-step.in-r{animation:px-in-r .26s var(--ease-out)}\n.px-step.in-l{animation:px-in-l .26s var(--ease-out)}\n@keyframes px-in-r{from{opacity:0;transform:translateX(16px)}to{opacity:1;transform:none}}\n@keyframes px-in-l{from{opacity:0;transform:translateX(-16px)}to{opacity:1;transform:none}}\n.px-q{display:grid;gap:6px}\n.px-q h2{font-size:clamp(22px,2.6vw,28px);line-height:1.15;outline:none}\n.px-q p{color:var(--muted);font-size:15px;max-width:52ch}\n\n.px-cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}\n.px-cards.tight{gap:8px}\n.px-co{position:relative;display:grid;gap:4px;align-content:start;padding:16px 44px 16px 16px;border:1px solid var(--line);border-radius:var(--r-card);background:var(--bg);cursor:pointer;transition:border-color .15s ease,background-color .15s ease,transform .16s var(--ease-out)}\n.px-co input{position:absolute;opacity:0;pointer-events:none}\n.px-co b{font:600 16px\/1.25 var(--f-body)}\n.px-co small{font-size:13.5px;line-height:1.4;color:var(--muted)}\n.px-co .meta{font-size:13px;font-weight:600;color:var(--teal);margin-top:4px}\n.px-co .tick{position:absolute;top:14px;right:14px;width:22px;height:22px;border-radius:50%;border:1.5px solid var(--line);display:grid;place-items:center;transition:background-color .15s ease,border-color .15s ease}\n.px-co .tick svg{width:13px;height:13px;stroke:var(--teal-ink);stroke-width:2.6;fill:none;opacity:0;transform:scale(.8);transition:opacity .15s ease,transform .2s var(--ease-out)}\n.px-co:active{transform:scale(.98)}\n.px-co:has(input:checked){border-color:var(--teal);background:var(--mint);box-shadow:inset 0 0 0 1px var(--teal)}\n.px-co:has(input:checked) .tick{background:var(--teal);border-color:var(--teal)}\n.px-co:has(input:checked) .tick svg{opacity:1;transform:none}\n.px-co:has(input:focus-visible){outline:2px solid var(--teal);outline-offset:2px}\n.px-co.small{padding:13px 40px 13px 14px}\n.px-co.small b{font-size:15px}\n.px-co.small .tick{top:12px;right:12px}\n.px-stair{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;align-items:stretch}\n.px-tier{position:relative;display:flex;flex-direction:column;justify-content:flex-start;gap:6px;padding:16px 12px 14px;border:1px solid var(--line);border-radius:var(--r-card);background:color-mix(in srgb,var(--teal) var(--tint),var(--paper));color:var(--ink);cursor:pointer;transition:background-color .22s ease,border-color .22s ease,color .22s ease,transform .18s var(--ease-out),box-shadow .22s ease}\n.px-tier input{position:absolute;opacity:0;pointer-events:none}\n.px-tier b{font:700 15px\/1.15 var(--f-display);letter-spacing:-.015em}\n.px-tier small{font-size:12.5px;line-height:1.4;color:var(--muted);transition:color .22s ease}\n.px-tier .px-lvl{margin-bottom:10px}\n.px-tier:has(input:checked) .px-lvl i{background:var(--deep-line)}\n.px-tier:has(input:checked) .px-lvl i.on{background:var(--deep-ink)}\n.px-tier .where{font-size:12px;line-height:1.35;color:var(--muted);margin-top:auto;padding-top:9px;border-top:1px solid color-mix(in srgb,var(--ink) 10%,transparent);transition:color .22s ease,border-color .22s ease}\n.px-tier .tick{position:absolute;top:12px;right:12px;width:22px;height:22px;border-radius:50%;border:1.5px solid color-mix(in srgb,var(--ink) 18%,transparent);display:grid;place-items:center;transition:background-color .2s ease,border-color .2s ease}\n.px-tier .tick svg{width:13px;height:13px;stroke:var(--deep);stroke-width:2.6;fill:none;opacity:0;transform:scale(.8);transition:opacity .15s ease,transform .2s var(--ease-out)}\n.px-tier:active{transform:scale(.98)}\n.px-tier:has(input:checked){background:var(--deep);border-color:var(--deep);color:var(--deep-ink);box-shadow:0 14px 30px -18px rgb(var(--shade)\/.7)}\n.px-tier:has(input:checked) small,.px-tier:has(input:checked) .where{color:var(--deep-muted)}\n.px-tier:has(input:checked) .where{border-color:var(--deep-line)}\n.px-tier:has(input:checked) .tick{background:var(--deep-ink);border-color:var(--deep-ink)}\n.px-tier:has(input:checked) .tick svg{opacity:1;transform:none}\n.px-tier:has(input:focus-visible){outline:2px solid var(--teal);outline-offset:2px}\n.px-lvl{display:inline-flex;align-items:flex-end;gap:2px;height:12px;margin-bottom:6px}\n.px-lvl i{width:4px;border-radius:1px;background:var(--mint-2)}\n.px-lvl i:nth-child(1){height:4px}.px-lvl i:nth-child(2){height:6.5px}.px-lvl i:nth-child(3){height:9px}.px-lvl i:nth-child(4){height:12px}\n.px-lvl i.on{background:var(--teal)}\n\n.px-fields{display:grid;gap:18px}\n.px-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:end}\n.px-row.three{grid-template-columns:repeat(3,minmax(0,1fr))}\n.px-field{display:grid;gap:7px;min-width:0;align-content:start}\n.px-field > label,.px-lab{font:500 14px\/1.3 var(--f-body);color:var(--ink)}\n.px-in{position:relative;display:flex;align-items:center}\n.px-in input,.px-in select{width:100%;height:48px;border:1px solid var(--line);border-radius:var(--r-field);background:var(--bg);color:var(--ink);font:500 16px\/1 var(--f-body);font-variant-numeric:tabular-nums;padding:0 64px 0 14px;transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease}\n.px-in select{padding-right:40px;appearance:none;cursor:pointer;background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%);background-position:calc(100% - 20px) 50%,calc(100% - 15px) 50%;background-size:5px 5px;background-repeat:no-repeat}\n.px-in input:focus,.px-in select:focus{outline:none;border-color:var(--teal);background:var(--paper);box-shadow:0 0 0 3px color-mix(in srgb,var(--teal) 20%,transparent)}\n.px-in .unit{position:absolute;right:14px;font-size:13.5px;color:var(--muted);pointer-events:none}\n.px-in.big input{height:64px;font:600 28px\/1 var(--f-display);letter-spacing:-.01em;padding-right:72px}\n.px-in.bad input{border-color:var(--bad);box-shadow:0 0 0 3px color-mix(in srgb,var(--bad) 15%,transparent)}\n.px-hint{font-size:13.5px;line-height:1.45;color:var(--muted)}\n.px-msg{font-size:13.5px;color:var(--bad)}\n.px-pills{display:flex;flex-wrap:wrap;gap:6px}\n.px-pill{appearance:none;border:1px solid var(--line);background:var(--bg);color:var(--ink);border-radius:999px;min-height:36px;padding:0 13px;font:500 13.5px\/1 var(--f-body);cursor:pointer;transition:border-color .15s ease,background-color .15s ease,transform .16s var(--ease-out)}\n.px-pill:active{transform:scale(.96)}\n.px-pill[aria-pressed=\"true\"]{background:var(--teal);border-color:var(--teal);color:var(--teal-ink)}\n\n.px-range{display:grid;grid-template-columns:1fr auto;gap:18px;align-items:center}\n.px-range input[type=range]{width:100%;accent-color:var(--teal);height:32px;cursor:pointer}\n.px-gfield{gap:10px}\n#px-g-range{-webkit-appearance:none;appearance:none;height:12px;border-radius:999px;background:var(--track,var(--mint-2));cursor:pointer;margin:12px 0}\n#px-g-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:28px;height:28px;border-radius:50%;background:var(--paper);border:3px solid var(--ink);box-shadow:0 2px 8px rgb(var(--shade)\/.3);transition:transform .15s var(--ease-out)}\n#px-g-range:active::-webkit-slider-thumb{transform:scale(1.12)}\n#px-g-range::-moz-range-thumb{width:22px;height:22px;border-radius:50%;background:var(--paper);border:3px solid var(--ink);box-shadow:0 2px 8px rgb(var(--shade)\/.3)}\n#px-g-range::-moz-range-track{height:12px;border-radius:999px;background:var(--track,var(--mint-2))}\n#px-g-range:focus-visible{outline:2px solid var(--teal);outline-offset:6px}\n.px-zone{display:flex;flex-wrap:wrap;gap:6px 18px;font-size:12.5px;color:var(--muted)}\n.px-zone span{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}\n.px-zone span::before{content:\"\";width:10px;height:10px;border-radius:3px;background:var(--c)}\n.px-zone .lo{--c:var(--z-low)}.px-zone .mid{--c:var(--z-ok);font-weight:600;color:var(--ink)}.px-zone .hi{--c:var(--z-high)}\n.px-zone-msg{display:flex;gap:8px;align-items:flex-start;font-size:13.5px;line-height:1.5;color:var(--muted)}\n.px-zone-msg .ico{margin-top:2px}\n.px-zone-msg[data-z=\"ok\"] .ico{color:var(--good)}\n.px-zone-msg[data-z=\"low\"] .ico{color:var(--bad)}\n.px-zone-msg[data-z=\"high\"] .ico{color:var(--warn)}\n#px-g-out[data-z=\"ok\"]{color:var(--good)}\n#px-g-out[data-z=\"low\"]{color:var(--bad)}\n#px-g-out[data-z=\"high\"]{color:var(--warn)}\n.px-range output{font:700 34px\/1 var(--f-display);min-width:3em;text-align:right;letter-spacing:-.02em}\n\n.px-adv{border:1px solid var(--line);border-radius:var(--r-card);background:var(--bg)}\n.px-adv > summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:60px;padding:12px 16px;font:600 15px\/1.3 var(--f-body)}\n.px-adv-h{display:grid;gap:3px;min-width:0}\n.px-adv-h small{font:400 13px\/1.4 var(--f-body);color:var(--muted)}\n.px-tabs{display:flex;gap:4px;padding:4px;background:var(--mint);border-radius:12px;overflow-x:auto}\n.px-tabs button{appearance:none;border:0;background:none;border-radius:9px;min-height:38px;padding:0 14px;font:600 13.5px\/1 var(--f-body);color:var(--muted);cursor:pointer;white-space:nowrap;transition:background-color .15s ease,color .15s ease}\n.px-tabs button[aria-selected=\"true\"]{background:var(--paper);color:var(--ink);box-shadow:0 1px 2px rgb(var(--shade)\/.12),0 2px 8px rgb(var(--shade)\/.06)}\n.px-chnote{font-size:13px;line-height:1.5;color:var(--muted)}\n.px-hyp{display:grid;gap:20px}\n.px-hg{display:grid}\n.px-hg header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding-bottom:8px;border-bottom:1px solid var(--line)}\n.px-hg h4{margin:0;display:flex;align-items:center;gap:8px;font:600 14.5px\/1.2 var(--f-body)}\n.px-hg h4::before{content:\"\";width:10px;height:10px;border-radius:3px;background:var(--sw)}\n.px-hg-t{font-size:13px;color:var(--muted)}\n.px-hg-t b{color:var(--ink);font-weight:600}\n.px-h{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.4fr) minmax(76px,auto);gap:6px 16px;align-items:center;padding:14px 0;border-bottom:1px dashed var(--line)}\n.px-h:last-child{border-bottom:0;padding-bottom:4px}\n.px-h-l label{font:600 14px\/1.3 var(--f-body);color:var(--ink)}\n.px-h-l p{font-size:12.5px;line-height:1.4;color:var(--muted);margin-top:3px}\n.px-h-c{display:flex;align-items:center;gap:10px;min-width:0}\n.px-h-c input[type=range]{flex:1;min-width:0;height:28px;accent-color:var(--sw);cursor:pointer}\n.px-h-v{flex:none;width:92px;justify-content:flex-end;display:inline-flex;align-items:center;gap:3px;height:36px;padding:0 9px;border:1px solid var(--line);border-radius:9px;background:var(--paper);transition:border-color .15s ease,box-shadow .15s ease}\n.px-h-v:focus-within{border-color:var(--teal);box-shadow:0 0 0 3px color-mix(in srgb,var(--teal) 20%,transparent)}\n.px-h-v input{width:100%;min-width:0;border:0;background:none;padding:0;font:600 14.5px\/1 var(--f-body);font-variant-numeric:tabular-nums;color:var(--ink);text-align:right}\n.px-h-v input:focus{outline:none}\n.px-h-v i{font-style:normal;font-size:12.5px;color:var(--muted)}\n.px-h-a{text-align:right;font-size:12.5px;line-height:1.3;color:var(--muted);white-space:nowrap}\n.px-h-a b{display:block;font-size:14.5px;font-weight:600;color:var(--ink)}\n.px-link{appearance:none;border:0;background:none;padding:6px 0;min-height:36px;font:600 13.5px\/1.3 var(--f-body);color:var(--teal);cursor:pointer;text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px}\n.px-link:hover{color:var(--ink)}\n.px-bm-for{font:600 13.5px\/1.3 var(--f-body);color:var(--good)}\n.px-h-b{grid-column:1 \/ -1;display:flex;gap:7px;align-items:flex-start;margin:2px 0 0;padding:9px 11px;border-radius:10px;background:var(--paper);font-size:12.5px;line-height:1.4;color:var(--muted)}\n.px-h-b .ico{width:15px;height:15px;margin-top:1px;flex:none}\n.px-h-b[data-in=\"1\"] .ico{color:var(--good)}\n.px-h-b[data-in=\"0\"] .ico{color:var(--warn)}\n.px-h-b b{font-weight:600;color:var(--ink)}\n.px-h-b[data-in=\"0\"] b{color:var(--warn)}\n.px-h-b small{display:block;font-size:12px;color:var(--muted);margin-top:2px}\n.px-b-none{font-style:normal;color:var(--muted)}\n.px-h-c input.px-hr{-webkit-appearance:none;appearance:none;height:8px;border-radius:999px;background:var(--track,var(--mint-2));margin:10px 0}\n.px-hr::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:22px;height:22px;border-radius:50%;background:var(--paper);border:3px solid var(--sw);box-shadow:0 1px 5px rgb(var(--shade)\/.25)}\n.px-hr::-moz-range-thumb{width:16px;height:16px;border-radius:50%;background:var(--paper);border:3px solid var(--sw)}\n.px-hr::-moz-range-track{height:8px;border-radius:999px;background:var(--track,var(--mint-2))}\n.px-hg header{padding-bottom:6px}\n.px-r{border-bottom:1px solid var(--line)}\n.px-r:last-child{border-bottom:0}\n.px-r-head{appearance:none;border:0;background:none;width:100%;display:grid;grid-template-columns:minmax(0,1fr) auto auto minmax(80px,auto) 16px;grid-template-areas:\"name val pill amt chev\";align-items:center;gap:12px;min-height:52px;padding:10px 4px;margin:0;text-align:left;font:inherit;color:var(--ink);cursor:pointer;border-radius:10px;transition:background-color .15s ease}\n.px-r-name{grid-area:name;font:500 14.5px\/1.3 var(--f-body)}\n.px-r-val{grid-area:val;font:600 15px\/1 var(--f-body);font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap}\n.px-r-pill{grid-area:pill;justify-self:start;display:inline-flex;align-items:center;gap:5px;height:26px;padding:0 10px;border-radius:999px;font:500 12px\/1 var(--f-body);white-space:nowrap;border:1px solid var(--line);background:var(--paper);color:var(--muted)}\n.px-r-pill .ico{width:13px;height:13px}\n.px-r-pill[data-s=\"in\"]{color:var(--good);border-color:color-mix(in srgb,var(--good) 30%,transparent);background:color-mix(in srgb,var(--good) 8%,var(--paper))}\n.px-r-pill[data-s=\"out\"]{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent);background:color-mix(in srgb,var(--warn) 12%,var(--paper))}\n.px-r-amt{grid-area:amt;font-size:13.5px;color:var(--muted);text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}\n.px-r-chev{grid-area:chev;width:16px;height:16px;color:var(--muted);transition:transform .22s var(--ease-out)}\n.px-r.is-open .px-r-chev{transform:rotate(180deg)}\n.px-r.is-open .px-r-head{background:var(--paper)}\n.px-r-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .24s var(--ease-out)}\n.px-r.is-open .px-r-body{grid-template-rows:1fr}\n.px-r-inner{min-height:0;overflow:hidden}\n.px-r-pad{display:grid;gap:10px;padding:8px 4px 16px}\n.px-r-help{font-size:13px;line-height:1.45;color:var(--muted)}\n.px-r-src{font-size:12.5px;line-height:1.5;color:var(--muted)}\n.px-r-src b{font-weight:600;color:var(--ink)}\n@media (hover:hover) and (pointer:fine){ .px-r-head:hover{background:var(--paper)} }\n.px-hyp{gap:12px}\n.px-hg{background:var(--paper);border:1px solid var(--line);border-radius:14px;overflow:hidden;box-shadow:0 1px 2px rgb(var(--shade)\/.05),0 4px 14px -8px rgb(var(--shade)\/.12)}\n.px-hg header{padding:11px 14px;border-bottom:1px solid var(--line);background:color-mix(in srgb,var(--sw) 8%,var(--paper))}\n.px-hg h4{font-size:14px}\n.px-hg .px-r-head{padding:10px 14px;border-radius:0}\n.px-hg .px-r.is-open .px-r-head{background:color-mix(in srgb,var(--sw) 5%,var(--paper))}\n.px-hg .px-r.is-open .px-r-body{background:color-mix(in srgb,var(--sw) 5%,var(--paper))}\n.px-hg .px-r-pad{padding:2px 14px 16px}\n.px-hg .px-r-pill[data-s=\"na\"]{background:var(--bg)}\n.px-hg .px-h-v{background:var(--bg)}\n.px-bm-for{padding-top:2px}\n.px-hg-t{white-space:nowrap}\n.px-hg header{flex-wrap:wrap;row-gap:2px}\n.px-adv{border:0;background:none;border-radius:0}\n.px-adv > summary{border:1px solid var(--line);border-radius:14px;background:var(--bg)}\n.px-adv[open] > summary{margin-bottom:14px}\n.px-adv .px-adv-body{padding:0}\n@media (hover:hover) and (pointer:fine){ .px-hg .px-r-head:hover{background:color-mix(in srgb,var(--sw) 5%,var(--paper))} }\n.px-adv-foot{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 16px;padding-top:4px}\n.px-adv > summary::-webkit-details-marker{display:none}\n.px-adv > summary .ico{transition:transform .2s var(--ease-out);color:var(--muted)}\n.px-adv[open] > summary .ico{transform:rotate(180deg)}\n.px-adv-body{display:grid;gap:22px;padding:6px 16px 18px}\n.px-sub{display:grid;gap:12px}\n.px-sub h3{font:600 13.5px\/1.3 var(--f-body);color:var(--muted)}\n.px-co.multi .tick{border-radius:7px}\n.px-strat{display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:4px;border-radius:14px;background:color-mix(in srgb,var(--deep-ink) 8%,transparent)}\n.px-strat button{appearance:none;border:0;border-radius:10px;min-height:46px;padding:6px 10px;background:transparent;color:var(--deep-muted);font:600 14px\/1.2 var(--f-body);cursor:pointer;transition:background-color .2s ease,color .2s ease,transform .16s var(--ease-out)}\n.px-strat button small{display:block;font-weight:400;font-size:12px;margin-top:2px;opacity:.85}\n.px-strat button:active{transform:scale(.97)}\n.px-strat button[aria-pressed=\"true\"]{background:var(--deep-ink);color:var(--deep)}\n.px-chlist{list-style:none;margin:4px 0 0;padding:0;display:grid}\n.px-chlist li{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:12px 0;border-top:1px solid var(--deep-line)}\n.px-chlist li:first-child{border-top:0;padding-top:4px}\n.px-chlist li > span:first-child{font-size:15px}\n.px-chlist li > span:last-child{text-align:right}\n.px-chlist b{display:block;font:700 28px\/1 var(--f-display);letter-spacing:-.015em}\n.px-chlist small{display:block;font-size:12.5px;color:var(--deep-muted);margin-top:4px}\n.px-ctable{width:100%;min-width:560px;border-collapse:collapse;font-size:14.5px}\n.px-ctable th{font:500 12.5px\/1.3 var(--f-body);color:var(--muted);text-align:right;padding:0 10px 10px;border-bottom:1px solid var(--line);vertical-align:bottom}\n.px-ctable th:first-child,.px-ctable td:first-child{text-align:left;padding-left:12px}\n.px-ctable td{padding:12px 10px;text-align:right;border-bottom:1px solid var(--line);white-space:nowrap;font-weight:500}\n.px-ctable td small{display:block;font-weight:400;font-size:12.5px;color:var(--muted);margin-top:2px}\n.px-ctable tr.cur td{background:var(--mint)}\n.px-ctable tr.cur td:first-child{border-radius:10px 0 0 10px}\n.px-ctable tr.cur td:last-child{border-radius:0 10px 10px 0}\n.px-ctable td.gain{color:var(--good);font-weight:600}\n.px-adv .px-in input,.px-adv .px-in select{background:var(--paper)}\n\n.px-nav{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-top:18px;border-top:1px solid var(--line)}\n.px-nav .count{font-size:13.5px;color:var(--muted)}\n.px-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:48px;padding:0 22px;border-radius:999px;font:600 15px\/1 var(--f-body);text-decoration:none;cursor:pointer;border:0;background:var(--teal);color:var(--teal-ink);transition:transform .16s var(--ease-out),background-color .2s ease,opacity .2s ease;white-space:nowrap}\n.px-btn:active{transform:scale(.97)}\n.px-btn .ico{width:16px;height:16px;transition:transform .2s var(--ease-out)}\n.px-back{appearance:none;border:0;background:none;display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 4px;font:600 14.5px\/1 var(--f-body);color:var(--muted);cursor:pointer}\n.px-back .ico{width:16px;height:16px;transform:rotate(180deg)}\n.px-back[disabled]{visibility:hidden}\n\n\/* answer card *\/\n.px-aside{position:static;display:grid;gap:14px;min-width:0}\n.px-answer{background:var(--deep);color:var(--deep-ink);border-radius:var(--r-panel);padding:clamp(22px,2.8vw,30px);display:grid;gap:20px;box-shadow:0 18px 40px -24px rgb(var(--shade)\/.55)}\n.px-recap{display:flex;flex-wrap:wrap;gap:6px}\n.px-tok{appearance:none;border:1px solid var(--deep-line);background:transparent;color:var(--deep-ink);border-radius:999px;min-height:30px;padding:0 11px;font:500 12.5px\/1 var(--f-body);cursor:pointer;transition:background-color .15s ease,border-color .15s ease}\n.px-ans-top{display:grid;gap:6px}\n.px-ans-label{display:flex;justify-content:space-between;align-items:center;gap:12px;font:500 14.5px\/1.3 var(--f-body);color:var(--deep-muted)}\n.px-big{font:700 clamp(46px,6.4vw,64px)\/1 var(--f-display);letter-spacing:-.025em;font-variant-numeric:tabular-nums}\n.px-ans-note{font-size:14px;color:var(--deep-muted)}\n.px-switch{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-size:13px;color:var(--deep-muted);white-space:nowrap}\n.px-switch input{appearance:none;width:30px;height:18px;border-radius:999px;background:var(--deep-line);position:relative;cursor:pointer;margin:0;transition:background-color .2s ease}\n.px-switch input::after{content:\"\";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:var(--deep-ink);transition:transform .2s var(--ease-out)}\n.px-switch input:checked{background:#5aa898}\n.px-switch input:checked::after{transform:translateX(12px)}\n.px-figs{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:0;padding-top:18px;border-top:1px solid var(--deep-line)}\n.px-figs div{display:grid;gap:3px;min-width:0}\n.px-figs dt{font-size:13px;color:var(--deep-muted);line-height:1.3}\n.px-figs dd{margin:0;font:600 18px\/1.2 var(--f-body);overflow-wrap:anywhere}\n.px-figs dd small{display:block;font:400 12.5px\/1.3 var(--f-body);color:var(--deep-muted);margin-top:2px}\n.px-figs.one{grid-template-columns:1fr}\n.px-figs.one div{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.px-figs.one dt{font-size:14.5px}\n.px-figs.one dd{font:700 26px\/1.1 var(--f-display);letter-spacing:-.01em;text-align:right}\n.px-figs.one dd small{display:inline;font:500 15px\/1 var(--f-body);color:var(--deep-muted);margin:0 0 0 8px;letter-spacing:0}\n.px-quote{display:grid;gap:8px;padding-top:18px;border-top:1px solid var(--deep-line)}\n.px-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n.px-answer{position:relative;overflow:hidden}\n.px-answer.is-locked > :not(.px-wait):not(.px-sr){display:none!important}\n.px-answer:not(.is-locked) .px-wait{display:none}\n.px-wait{display:grid;gap:22px}\n.px-wait-h{display:grid;gap:8px}\n.px-wait-h h3{font:700 24px\/1.15 var(--f-display);color:var(--deep-ink);letter-spacing:-.01em}\n.px-wait-h p{font-size:14.5px;line-height:1.5;color:var(--deep-muted);max-width:42ch}\n.px-wait-list{list-style:none;margin:0;padding:0;display:grid;gap:2px}\n.px-wait-list li{display:grid;grid-template-columns:26px minmax(0,1fr) auto;align-items:center;gap:12px;padding:10px 0;border-top:1px solid var(--deep-line);font-size:14px;color:var(--deep-muted);transition:color .3s ease}\n.px-wait-list li:first-child{border-top:0}\n.px-wait-list .dot{width:22px;height:22px;border-radius:50%;border:1.5px solid var(--deep-line);display:grid;place-items:center;transition:background-color .3s ease,border-color .3s ease}\n.px-wait-list .dot svg{width:12px;height:12px;stroke:var(--deep);stroke-width:2.8;fill:none;opacity:0;transform:scale(.6);transition:opacity .25s ease,transform .3s var(--ease-out)}\n.px-wait-list li.done{color:var(--deep-ink)}\n.px-wait-list li.done .dot{background:#7fdcaa;border-color:#7fdcaa}\n.px-wait-list li.done .dot svg{opacity:1;transform:none}\n.px-wait-list li.cur .dot{border-color:var(--deep-ink);box-shadow:0 0 0 4px color-mix(in srgb,var(--deep-ink) 12%,transparent)}\n.px-wait-list li.cur{color:var(--deep-ink);font-weight:600}\n.px-wait-list li em{font-style:normal;font-size:13px;color:var(--deep-muted);text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:170px}\n.px-ghost-rib{display:flex;gap:3px;height:26px;opacity:.5}\n.px-ghost-rib span{border-radius:6px;background:linear-gradient(90deg,color-mix(in srgb,var(--deep-ink) 8%,transparent),color-mix(in srgb,var(--deep-ink) 16%,transparent),color-mix(in srgb,var(--deep-ink) 8%,transparent));background-size:200% 100%;animation:px-shim 2.4s ease-in-out infinite}\n.px-ghost-rib span:nth-child(1){flex:16}.px-ghost-rib span:nth-child(2){flex:13}.px-ghost-rib span:nth-child(3){flex:24}.px-ghost-rib span:nth-child(4){flex:29}.px-ghost-rib span:nth-child(5){flex:16}\n@keyframes px-shim{0%{background-position:100% 0}100%{background-position:-100% 0}}\n\/* r\u00e9v\u00e9lation : balayage lumineux, contenus en cascade, ruban qui se d\u00e9ploie, rep\u00e8re qui se pose *\/\n.px-answer.px-reveal::after{content:\"\";position:absolute;inset:0;pointer-events:none;background:linear-gradient(105deg,transparent 35%,rgb(255 255 255\/.10) 50%,transparent 65%);transform:translateX(-110%);animation:px-sweep 1.1s .1s var(--ease-out) forwards}\n@keyframes px-sweep{to{transform:translateX(110%)}}\n.px-answer.px-reveal #px-recap,.px-answer.px-reveal #px-ans > *{animation:px-rise .6s var(--ease-out) both}\n.px-answer.px-reveal #px-ans > :nth-child(1){animation-delay:.05s}\n.px-answer.px-reveal #px-ans > :nth-child(2){animation-delay:.15s}\n.px-answer.px-reveal #px-ans > :nth-child(3){animation-delay:.25s}\n.px-answer.px-reveal #px-ans > :nth-child(4){animation-delay:.35s}\n.px-answer.px-reveal #px-ans > :nth-child(5){animation-delay:.45s}\n@keyframes px-rise{from{opacity:0;transform:translateY(12px);filter:blur(4px)}to{opacity:1;transform:none;filter:none}}\n.px-answer.px-reveal .px-rseg{transform-origin:left center;animation:px-grow .7s var(--ease-out) both;animation-delay:calc(.35s + var(--d,0) * 70ms)}\n@keyframes px-grow{from{transform:scaleX(0);opacity:0}to{transform:none;opacity:1}}\n.px-answer.px-reveal .px-lad-pin{animation:px-drop .6s .7s var(--ease-out) both}\n@keyframes px-drop{from{opacity:0;translate:0 -10px}to{opacity:1;translate:0 0}}\n@media (prefers-reduced-motion:reduce){.px-answer.px-reveal *,.px-answer.px-reveal::after,.px-ghost-rib span{animation:none!important}}\n.px-a-sec{display:grid;gap:14px;padding-top:20px;border-top:1px solid var(--deep-line)}\n.px-a-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.px-a-h h3{font:600 15px\/1.3 var(--f-body);color:var(--deep-ink);letter-spacing:0}\n.px-a-total{font-size:12.5px;color:var(--deep-muted);white-space:nowrap}\n.px-a-ch{display:flex;flex-wrap:wrap;gap:6px}\n.px-a-ch .px-pill{background:transparent;border-color:var(--deep-line);color:var(--deep-muted);min-height:30px;font-size:12.5px}\n.px-a-ch .px-pill[aria-pressed=\"true\"]{background:var(--deep-ink);border-color:var(--deep-ink);color:var(--deep)}\n.px-ribbon{position:relative;display:flex;gap:3px;height:34px}\n.px-rseg{position:relative;display:flex;align-items:center;justify-content:center;min-width:4px;height:100%;padding:0;border:0;border-radius:6px;background:var(--c);color:#0b1f1c;font:700 11.5px\/1 var(--f-body);font-variant-numeric:tabular-nums;cursor:default;overflow:hidden;white-space:nowrap;transition:flex-grow .5s var(--ease-out),opacity .15s ease,transform .2s var(--ease-out)}\n.px-rseg:first-child{border-radius:10px 6px 6px 10px}\n.px-rseg:last-of-type{border-radius:6px 10px 10px 6px}\n.px-rseg.is-you{box-shadow:inset 0 0 0 2px #fff6dc;z-index:1}\n.px-ribbon:hover .px-rseg{opacity:.55}\n.px-ribbon .px-rseg:hover,.px-ribbon .px-rseg:focus-visible{opacity:1;transform:translateY(-2px)}\n.px-ribbon .px-tip{background:var(--deep-ink);color:var(--deep)}\n.px-rleg{list-style:none;margin:0;padding:0;display:grid;gap:7px}\n.px-rleg li{display:grid;grid-template-columns:9px minmax(0,1fr) auto 52px;align-items:center;gap:10px;font-size:13.5px;color:var(--deep-muted)}\n.px-rleg li::before{content:\"\";width:9px;height:9px;border-radius:3px;background:var(--c)}\n.px-rleg li span{min-width:0}\n.px-rleg li b{font-weight:600;color:var(--deep-ink);font-variant-numeric:tabular-nums;white-space:nowrap}\n.px-rleg li small{font-size:12px;color:var(--deep-muted);text-align:right;font-variant-numeric:tabular-nums}\n.px-rleg li.is-you span,.px-rleg li.is-you b{color:#f6d58a}\n.px-rleg li.neg b{color:#f59a90}\n.px-a-more summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;min-height:32px;font:600 13px\/1.3 var(--f-body);color:var(--deep-muted)}\n.px-a-more summary::-webkit-details-marker{display:none}\n.px-a-more summary .ico{width:14px;height:14px;transition:transform .2s var(--ease-out)}\n.px-a-more[open] summary .ico{transform:rotate(180deg)}\n.px-a-more summary:hover{color:var(--deep-ink)}\n.px-a-table{width:100%;border-collapse:collapse;font-size:13px;margin-top:6px;color:var(--deep-ink)}\n.px-a-table td{padding:7px 0;border-top:1px solid var(--deep-line)}\n.px-a-table td:nth-child(2),.px-a-table td:nth-child(3){text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}\n.px-a-table td:nth-child(3){color:var(--deep-muted);width:56px}\n.px-a-table td:first-child{display:flex;align-items:center;gap:8px}\n.px-a-table td:first-child::before{content:\"\";width:7px;height:7px;border-radius:2px;background:var(--c);flex:none}\n.px-a-table tr.total td{font-weight:600;border-top:1px solid var(--deep-muted)}\n.px-a-table tr.total td:first-child::before{background:transparent}\n.px-a-table tr.neg td:nth-child(2){color:#f59a90}\n.px-ladder{position:relative;padding-top:34px}\n.px-lad-track{display:flex;gap:3px;height:10px}\n.px-lad-track span{flex:1;border-radius:4px;background:color-mix(in srgb,var(--deep-ink) 12%,transparent);transition:background-color .3s ease}\n.px-lad-track span:first-child{flex:.6;background:color-mix(in srgb,var(--deep-ink) 6%,transparent)}\n.px-lad-track span.sel{background:color-mix(in srgb,var(--deep-ink) 38%,transparent)}\n.px-lad-labels{display:flex;gap:3px;margin-top:8px;font-size:11.5px;color:var(--deep-muted)}\n.px-lad-labels span{flex:1;text-align:center;line-height:1.25}\n.px-lad-labels span:first-child{flex:.6}\n.px-lad-labels span.sel{color:var(--deep-ink);font-weight:600}\n.px-lad-pin{position:absolute;top:0;transform:translateX(-50%);display:grid;justify-items:center;transition:left .55s var(--ease-out)}\n.px-lad-pin b{display:block;padding:4px 9px;border-radius:999px;background:var(--deep-ink);color:var(--deep);font:700 11.5px\/1.2 var(--f-body);white-space:nowrap}\n.px-lad-pin i{display:block;width:2px;height:10px;background:var(--deep-ink)}\n.px-lad-pin::after{content:\"\";width:12px;height:12px;border-radius:50%;background:var(--deep-ink);box-shadow:0 0 0 3px var(--deep);margin-top:-1px}\n.px-lad-pin[data-tone=\"warn\"] b,.px-lad-pin[data-tone=\"warn\"] i,.px-lad-pin[data-tone=\"warn\"]::after{background:#f3c867}\n.px-lad-pin[data-tone=\"warn\"] b{color:#3a2a00}\n.px-a-verdict{display:grid;gap:4px;font-size:13.5px;line-height:1.5;color:var(--deep-muted)}\n.px-a-verdict b{color:var(--deep-ink);font-weight:600}\n.px-a-verdict .tag{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:600;color:var(--deep-ink)}\n.px-a-verdict .tag[data-tone=\"good\"] .ico{color:#7fdcaa}\n.px-a-verdict .tag[data-tone=\"warn\"] .ico{color:#f3c867}\n@media (prefers-reduced-motion:reduce){.px-lad-pin,.px-rseg{transition:none}}\n.px-nego{display:flex;flex-wrap:wrap;gap:6px 20px;font-size:13.5px;line-height:1.5;color:var(--deep-muted)}\n.px-nego b{color:var(--deep-ink);font-weight:600}\n.px-quote label{font:500 14px\/1.3 var(--f-body);color:var(--deep-ink)}\n.px-quote .px-in input{background:color-mix(in srgb,var(--deep-ink) 8%,transparent);border-color:var(--deep-line);color:var(--deep-ink)}\n.px-quote .px-in input::placeholder{color:var(--deep-muted)}\n.px-quote .px-in .unit{color:var(--deep-muted)}\n.px-status{display:flex;gap:8px;align-items:flex-start;font-size:14px;line-height:1.45;color:var(--deep-ink)}\n.px-status .ico{margin-top:1px}\n.px-status[data-tone=\"good\"] .ico{color:#7fdcaa}\n.px-status[data-tone=\"warn\"] .ico{color:#f3c867}\n.px-status[data-tone=\"bad\"] .ico{color:#f59a90}\n.px-err{display:flex;gap:10px;font-size:15px;line-height:1.5;color:var(--deep-ink)}\n.px-err .ico{color:#f3c867;margin-top:2px}\n.px-act{display:grid;gap:12px;padding-top:20px;border-top:1px solid rgb(255 255 255\/.08)}\n.px-act p{font-size:14px;color:var(--deep-muted)}\n.px-act-row{display:flex;gap:10px}\n.px-act-btn{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:10px;height:50px;border-radius:999px;background:var(--deep-ink);color:var(--deep);font:700 15px\/1 var(--f-body);text-decoration:none;transition:transform .16s var(--ease-out),background-color .15s ease}\n.px-act-btn .ico{width:17px;height:17px;transition:transform .2s var(--ease-out)}\n.px-act-copy{appearance:none;display:inline-flex;align-items:center;gap:8px;height:50px;padding:0 18px;border-radius:999px;border:1px solid rgb(255 255 255\/.16);background:transparent;color:var(--deep-ink);font:600 14px\/1 var(--f-body);cursor:pointer;transition:transform .16s var(--ease-out),background-color .15s ease}\n.px-act-copy .ico{width:16px;height:16px}\n.px-act-btn:active,.px-act-copy:active{transform:scale(.97)}\n@media (hover:hover) and (pointer:fine){ .px-act-btn:hover{background:#fff} .px-act-btn:hover .ico{transform:translateX(3px)} .px-act-copy:hover{background:rgb(255 255 255\/.06)} }\n.px-disc{display:flex;gap:8px;align-items:flex-start;margin-top:14px;font-size:12.5px;line-height:1.5;color:var(--muted)}\n.px-disc .ico{width:15px;height:15px;margin-top:2px;flex:none}\n.px-answer.is-locked ~ .px-disc{display:none}\n.px-legal{margin-top:clamp(28px,4vw,40px)!important;font-size:12.5px;line-height:1.6;color:var(--muted);max-width:90ch}\n.px-legal b{color:var(--ink);font-weight:600}\n.px-ghost{appearance:none;border:0;background:none;display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0;font:600 14.5px\/1 var(--f-body);color:var(--teal);cursor:pointer}\n.px-ghost .ico{width:16px;height:16px}\n@media (hover:hover) and (pointer:fine){\n  .px-co:hover,.px-pill:hover{border-color:var(--teal)}\n  .px-tier:hover{transform:translateY(-3px);box-shadow:0 12px 26px -16px rgb(var(--shade)\/.5);border-color:var(--teal)}\n  .px-tier:has(input:checked):hover{border-color:var(--deep)}\n  .px-btn:hover{background:color-mix(in srgb,var(--teal) 86%,var(--ink))}\n  .px-btn:hover .ico{transform:translateX(3px)}\n  .px-back:hover{color:var(--ink)}\n  .px-ghost:hover{text-decoration:underline;text-underline-offset:3px}\n  .px-tok:hover{background:color-mix(in srgb,var(--deep-ink) 10%,transparent);border-color:var(--deep-muted)}\n  .px-prog button:not(:disabled):hover{color:var(--ink)}\n}\n\n\/* analysis *\/\n.px-detail{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(16px,2.4vw,24px);margin-top:clamp(28px,4vw,44px)}\n.px-detail .px-panel{display:grid;gap:18px;align-content:start}\n.px-detail h2{font-size:20px}\n.px-wide{grid-column:1 \/ -1}\n.px-bar{display:flex;gap:2px;height:40px;position:relative}\n.px-seg-b{height:100%;min-width:3px;cursor:pointer;border:none;padding:0;transition:flex-grow .45s var(--ease-out),opacity .15s ease}\n.px-seg-b:first-child{border-radius:10px 0 0 10px}\n.px-seg-b:last-of-type{border-radius:0 10px 10px 0}\n.px-bar:hover .px-seg-b{opacity:.5}\n.px-bar .px-seg-b:hover,.px-bar .px-seg-b:focus-visible{opacity:1}\n.px-tip{position:absolute;bottom:calc(100% + 8px);transform:translateX(-50%);background:var(--ink);color:var(--paper);padding:7px 10px;border-radius:8px;font-size:13px;line-height:1.35;white-space:nowrap;pointer-events:none;z-index:2}\n.px-legend{display:grid;grid-template-columns:repeat(auto-fill,minmax(118px,1fr));gap:14px 12px;margin:0}\n.px-legend div{display:grid;gap:2px;min-width:0}\n.px-legend dt{display:flex;align-items:center;gap:7px;font-size:13px;color:var(--muted);line-height:1.25}\n.px-legend dt::before{content:\"\";width:9px;height:9px;border-radius:3px;background:var(--sw);flex:none}\n.px-legend dd{margin:0;font:600 15.5px\/1.25 var(--f-body)}\n.px-legend dd small{font-weight:400;font-size:12.5px;color:var(--muted);margin-left:4px}\n.px-more summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:6px;min-height:36px;font:600 14px\/1.3 var(--f-body);color:var(--teal)}\n.px-more summary::-webkit-details-marker{display:none}\n.px-more summary .ico{width:16px;height:16px;transition:transform .2s var(--ease-out)}\n.px-more[open] summary .ico{transform:rotate(90deg)}\n.px-table{width:100%;border-collapse:collapse;font-size:14px;margin-top:6px}\n.px-table td{padding:9px 0;border-top:1px solid var(--line)}\n.px-table td:nth-child(2),.px-table td:nth-child(3){text-align:right;white-space:nowrap}\n.px-table td:nth-child(3){color:var(--muted);width:64px;font-size:13px}\n.px-table td:first-child{display:flex;align-items:center;gap:8px}\n.px-table td:first-child::before{content:\"\";width:8px;height:8px;border-radius:2px;background:var(--sw);flex:none}\n.px-table tr.total td{font-weight:600;border-top:1.5px solid var(--ink)}\n.px-table tr.total td:first-child::before{background:transparent}\n.px-table tr.neg td:nth-child(2){color:var(--bad)}\n.px-scale{display:grid;gap:8px}\n.px-track{position:relative;height:28px}\n.px-zones{position:absolute;inset:9px 0;display:flex;gap:2px;border-radius:6px;overflow:hidden}\n.px-zones div{flex:1}\n.px-mark{position:absolute;top:0;width:4px;height:28px;margin-left:-2px;border-radius:3px;background:var(--ink);box-shadow:0 0 0 2px var(--paper);transition:left .45s var(--ease-out)}\n.px-zlabels{display:grid;grid-template-columns:repeat(5,1fr);font-size:12px;color:var(--muted);text-align:center}\n.px-zlabels .sel{color:var(--teal);font-weight:600}\n.px-verdict{font-size:14.5px;line-height:1.55;display:grid;gap:4px}\n.px-verdict b{font-weight:600}\n.px-verdict .tag{display:flex;align-items:center;gap:8px;font-weight:600}\n.px-verdict .tag[data-tone=\"good\"] .ico{color:var(--good)}\n.px-verdict .tag[data-tone=\"warn\"] .ico{color:var(--warn)}\n.px-tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}\n\n\/* benchmarks *\/\n.px-bench{margin-top:clamp(48px,7vw,80px);display:grid;gap:18px}\n.px-bench h2,.px-levers-sec h2{font-size:clamp(24px,3vw,32px)}\n.px-bnotes{display:grid;gap:8px;font-size:14px;line-height:1.55;max-width:80ch}\n\n.px-levers-sec{margin-top:clamp(48px,7vw,80px);display:grid;gap:22px}\n.px-levers{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:26px 32px}\n.px-levers li{display:grid;gap:6px;align-content:start;padding-top:16px;border-top:2px solid var(--mint-2)}\n.px-levers b{font:600 16px\/1.3 var(--f-body)}\n.px-levers p{font-size:14.5px;color:var(--muted);line-height:1.55}\n.px-method{margin-top:8px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}\n.px-method summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;min-height:60px;font:600 16px\/1.3 var(--f-body)}\n.px-method summary::-webkit-details-marker{display:none}\n.px-method summary .ico{color:var(--muted);transition:transform .2s var(--ease-out)}\n.px-method[open] summary .ico{transform:rotate(180deg)}\n.px-method ol{margin:0 0 20px;padding-left:20px;display:grid;gap:8px;font-size:14.5px;line-height:1.55;max-width:72ch}\n.px-method p{font-size:13.5px;color:var(--muted);margin-bottom:22px;max-width:72ch}\n.px-cta{margin-top:clamp(36px,5vw,56px);background:var(--deep);color:var(--deep-ink);border-radius:var(--r-panel);padding:clamp(24px,3.4vw,40px);display:grid;grid-template-columns:minmax(0,1fr) auto;gap:20px 32px;align-items:center}\n.px-cta h2{font-size:clamp(22px,2.6vw,28px)}\n.px-cta p{color:var(--deep-muted);margin-top:8px;max-width:56ch}\n.px-cta .px-btn{background:var(--deep-ink);color:var(--deep)}\n\n.px-dock{position:fixed;left:0;right:0;bottom:0;z-index:20;display:none;font-family:var(--f-body);font-variant-numeric:tabular-nums;padding:10px 16px calc(10px + env(safe-area-inset-bottom,0px));background:var(--deep);color:var(--deep-ink);box-shadow:0 -8px 24px rgb(0 0 0\/.18);align-items:center;justify-content:space-between;gap:12px;transition:transform .3s var(--ease-out)}\n.px-dock.hide{transform:translateY(110%)}\n.px-dock span{display:block;font-size:12.5px;color:var(--deep-muted)}\n.px-dock b{font:700 22px\/1.15 var(--f-display)}\n.px-dock a{color:var(--deep-ink);font:600 14px\/1 var(--f-body);text-decoration:none;display:inline-flex;align-items:center;min-height:44px;padding:0 16px;border-radius:999px;border:1px solid var(--deep-line)}\n\n@media (max-width:960px){\n  .px-grid,.px-detail{grid-template-columns:1fr}\n  .px-aside{position:static}\n  .px-levers{grid-template-columns:1fr 1fr}\n  .px-dock{display:flex}\n  .px-steps{min-height:0}\n}\n@media (max-width:620px){\n  .px-r-head{grid-template-columns:minmax(0,1fr) auto 16px;grid-template-areas:\"name val chev\" \"pill amt chev\";row-gap:6px}\n  .px-r-amt{text-align:right}\n  .px-h{grid-template-columns:minmax(0,1fr) auto;gap:8px 12px}\n  .px-h-l{grid-column:1 \/ -1}\n  .px-stair{grid-template-columns:1fr;align-items:stretch;gap:8px}\n  .px-tier{padding:14px 44px 14px 16px}\n  .px-tier b{font-size:17px}\n  .px-tier .where{margin-top:2px;padding-top:7px}\n  .px-prog button{font-size:0;gap:0}\n  .px-row.three{grid-template-columns:1fr 1fr}\n  .px-levers{grid-template-columns:1fr}\n  .px-cta{grid-template-columns:1fr}\n  .px-cta .px-btn{width:100%}\n  .px-figs{grid-template-columns:1fr 1fr}\n  .px-figs .is-key{grid-column:1 \/ -1;order:-1}\n}\n@media (max-width:440px){\n  .px-zone{font-size:11.5px}\n  .px-cards{grid-template-columns:1fr}\n  .px-cards.tight{grid-template-columns:1fr 1fr}\n  .px-row,.px-row.three{grid-template-columns:1fr}\n  .px-range output{font-size:28px}\n}\n@media (prefers-reduced-motion:reduce){.cm-px *,.cm-px *::before,.cm-px *::after,.px-dock{transition:none!important;animation:none!important}}\n\n\/* ===== Carte r\u00e9sultat : \u00e9tiquette de prix premium ===== *\/\n.px-answer{--pad:clamp(22px,2.8vw,32px);padding:var(--pad);border-radius:26px;border:1px solid rgb(255 255 255\/.07);\n  background:radial-gradient(120% 60% at 100% 0%,rgb(108 191 174\/.22),transparent 62%),radial-gradient(90% 50% at 0% 100%,rgb(189 132 26\/.10),transparent 60%),linear-gradient(180deg,#13463f 0%,#0c302b 100%);\n  box-shadow:0 40px 70px -38px rgb(16 58 53\/.65),0 2px 6px rgb(16 58 53\/.14),inset 0 1px 0 rgb(255 255 255\/.07)}\n.px-ans-top{position:relative;gap:10px}\n.px-ans-top::before{content:\"\";position:absolute;left:-8%;top:18%;width:70%;height:95%;background:radial-gradient(closest-side,rgb(127 220 170\/.16),transparent);pointer-events:none}\n.px-ans-top > *{position:relative}\n.px-ans-label{font-size:14px;color:var(--deep-muted)}\n.px-big{display:flex;align-items:baseline;font:700 clamp(58px,7.4vw,84px)\/.92 var(--f-display);letter-spacing:-.04em;color:#f3fbf8;font-variant-numeric:tabular-nums;margin-top:4px}\n.px-big .dec{font-size:.46em;letter-spacing:-.02em;color:#d7ece6}\n.px-big .cur{font:600 .24em\/1 var(--f-body);letter-spacing:.04em;color:var(--deep-muted);margin-left:.45em;align-self:flex-start;margin-top:.55em}\n.px-figs.one{border-top:0;padding-top:0}\n.px-figs.one div{display:inline-flex;align-items:center;gap:14px;width:fit-content;max-width:100%;padding:10px 16px 10px 14px;border-radius:999px;background:linear-gradient(90deg,rgb(240 189 79\/.16),rgb(240 189 79\/.06));border:1px solid rgb(240 189 79\/.32)}\n.px-figs.one dt{display:flex;align-items:center;gap:8px;font-size:13.5px;color:#f6d58a}\n.px-figs.one dt::before{content:\"\";width:8px;height:8px;border-radius:50%;background:#f0bd4f;box-shadow:0 0 0 3px rgb(240 189 79\/.18)}\n.px-figs.one dd{font:700 20px\/1 var(--f-display);color:#fff4d6;text-align:left;letter-spacing:-.01em;white-space:nowrap}\n.px-figs.one dd small{display:inline;font:500 13px\/1 var(--f-body);color:#e9cf8d;margin-left:6px}\n.px-perf{position:relative;height:30px;margin:2px calc(var(--pad) * -1) -6px;\n  background:radial-gradient(circle at 0 50%,var(--bg) 13px,transparent 13.5px),radial-gradient(circle at 100% 50%,var(--bg) 13px,transparent 13.5px)}\n.px-perf::before{content:\"\";position:absolute;left:calc(var(--pad) - 4px);right:calc(var(--pad) - 4px);top:50%;border-top:2px dashed rgb(255 255 255\/.13)}\n.px-a-sec.px-a-first{border-top:0;padding-top:0}\n.px-a-sec + .px-a-sec{border-top:1px solid rgb(255 255 255\/.07)}\n.px-a-h h3{font:600 15.5px\/1.3 var(--f-display);letter-spacing:-.005em}\n.px-ribbon{height:46px;gap:3px;padding:4px;border-radius:14px;background:rgb(0 0 0\/.18);box-shadow:inset 0 1px 2px rgb(0 0 0\/.25)}\n.px-rseg{border-radius:9px;font-size:12px;box-shadow:inset 0 1px 0 rgb(255 255 255\/.28),inset 0 -1px 0 rgb(0 0 0\/.12)}\n.px-rseg:first-child{border-radius:10px 6px 6px 10px}\n.px-rseg:last-of-type{border-radius:6px 10px 10px 6px}\n.px-rseg.is-you{box-shadow:inset 0 0 0 2px #fff1c7,0 0 18px rgb(240 189 79\/.35)}\n.px-raxis{display:flex;justify-content:space-between;margin-top:-6px;font-size:11.5px;color:var(--deep-muted);font-variant-numeric:tabular-nums}\n.px-rleg{gap:4px}\n.px-rleg li{padding:6px 10px;border-radius:10px;margin-inline:-10px}\n.px-rleg li.is-you{background:rgb(240 189 79\/.10)}\n.px-lad-track{height:12px;gap:4px}\n.px-lad-track span{border-radius:6px}\n.px-lad-track span.sel{background:linear-gradient(90deg,rgb(127 220 170\/.55),rgb(127 220 170\/.85));box-shadow:0 0 16px rgb(127 220 170\/.30)}\n.px-lad-labels span.sel{color:#bff0d6}\n.px-lad-pin b{padding:5px 11px;box-shadow:0 6px 16px -6px rgb(0 0 0\/.45)}\n.px-lad-pin::after{width:14px;height:14px;box-shadow:0 0 0 3px #0f3a35,0 0 14px rgb(234 245 242\/.45)}\n.px-a-verdict{padding:14px 16px;border-radius:14px;background:rgb(255 255 255\/.04);border:1px solid rgb(255 255 255\/.06)}\n.px-answers{display:grid;gap:10px;padding-top:18px;border-top:1px solid rgb(255 255 255\/.07)}\n.px-answers > p{font-size:12.5px;color:var(--deep-muted)}\n.px-tok{background:rgb(255 255 255\/.04)}\n.px-strat{margin-bottom:6px}\n\n\/* ===== Carte r\u00e9sultat : version minimaliste ===== *\/\n#px-ans{gap:18px!important}\n.px-perf{height:22px;margin:0 calc(var(--pad) * -1)}\n.px-a-sec{gap:12px}\n.px-a-sec + .px-a-sec{border-top:0;padding-top:4px}\n.px-a-h h3{font:600 14px\/1.3 var(--f-body);color:var(--deep-muted);letter-spacing:0}\n.px-ribbon{height:40px}\n.px-rleg{grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 18px}\n.px-rleg li{grid-template-columns:8px minmax(0,1fr) auto;gap:8px;padding:0;margin:0;font-size:13px;background:none!important}\n.px-rleg li::before{width:8px;height:8px}\n.px-rleg li b{font-weight:600}\n.px-ladder{padding-top:30px}\n.px-a-verdict{padding:0;background:none;border:0;gap:2px}\n.px-a-verdict .tag{font-size:14.5px}\n.px-a-verdict p:last-child{padding-left:26px;font-size:13px}\n.px-quote{gap:10px}\n.px-quote label{font-size:13.5px;color:var(--deep-muted)}\n\n\/* ===== \u00c9tapes de saisie : finitions ===== *\/\n.px-flowline{display:flex;flex-wrap:wrap;row-gap:6px;align-items:center;gap:6px;margin-top:12px;font-size:12px;color:var(--muted)}\n.px-flowline i{font-style:normal;white-space:nowrap;padding:3px 8px;border-radius:999px;background:var(--paper);border:1px solid var(--line)}\n.px-flowline i.on{color:var(--teal);border-color:color-mix(in srgb,var(--teal) 40%,transparent);font-weight:600}\n.px-flowline .ico{width:14px;height:14px;color:var(--muted)}\n.px-co:has(input:checked) .px-flowline i{background:var(--paper)}\n.px-cards{align-items:stretch}\n.px-sel{position:relative}\n.px-sel select{background-image:none!important;height:52px;padding-right:44px;font-weight:500}\n.px-sel .ico{position:absolute;right:16px;width:16px;height:16px;color:var(--muted);pointer-events:none}\n.px-tier{gap:4px}\n.px-tier b{margin-bottom:auto}\n.px-tier .where{margin-top:14px}\n.px-chgroups{display:grid;gap:16px}\n.px-chgroup{display:grid;gap:8px}\n.px-chgroup-t{font:600 12.5px\/1.3 var(--f-body);color:var(--muted)}\n.px-chcount{font-size:13px;color:var(--teal);font-weight:600}\n.px-nav{justify-content:space-between}\n\n.px-co.small small{white-space:nowrap}\n@media (max-width:620px){ .px-chgroup .px-cards.tight{grid-template-columns:1fr} .px-co.small{padding:12px 44px 12px 14px} .px-co.small b{font-size:14.5px} }\n\n.px-figs.px-chm{display:grid;grid-template-columns:1fr;gap:8px;border-top:0;padding-top:0;margin:0}\n.px-figs.px-chm dt{font-size:13px;color:#f6d58a}\n.px-figs.px-chm dd{margin:0;display:flex;flex-wrap:wrap;gap:6px}\n.px-chm-i{appearance:none;white-space:nowrap;display:inline-flex;align-items:baseline;gap:8px;padding:8px 12px;border-radius:999px;border:1px solid rgb(240 189 79\/.28);background:rgb(240 189 79\/.08);color:var(--deep-ink);font:500 13px\/1 var(--f-body);cursor:pointer;transition:background-color .15s ease,border-color .15s ease,transform .16s var(--ease-out)}\n.px-chm-i span{color:var(--deep-muted)}\n.px-chm-i b{font:700 15px\/1 var(--f-display);color:#fff4d6}\n.px-chm-i:active{transform:scale(.97)}\n.px-chm-i.on{background:rgb(240 189 79\/.18);border-color:#f0bd4f}\n.px-chm-i.low b{color:#f3c867}\n.px-chm-i.low::before{content:\"\";width:6px;height:6px;border-radius:50%;background:#f3c867;align-self:center}\n@media (hover:hover) and (pointer:fine){ .px-chm-i:hover{border-color:#f0bd4f} }\n@media (max-width:440px){ .px-rleg{grid-template-columns:1fr} }\n\n.px-hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}\n\n\/* rep\u00e8res v32 *\/\n.px-bench{gap:clamp(28px,4vw,44px)!important}\n.px-bench-head{display:grid;grid-template-columns:minmax(0,1fr) 240px;gap:24px 48px;align-items:end}\n.px-bench-hl{display:grid;gap:10px}\n.px-bench-hl .px-kick{color:var(--muted)!important;font-weight:400;max-width:58ch}\n.px-stat{display:grid;gap:2px;padding:20px 22px;border-radius:var(--r-card);background:var(--deep);color:var(--deep-ink);text-decoration:none;transition:transform .16s var(--ease-out)}\n.px-stat:active{transform:scale(.98)}\n.px-stat b{font:700 44px\/1 var(--f-display);letter-spacing:-.02em}\n.px-stat > span{font-size:14px;color:var(--deep-muted)}\n.px-stat em{display:inline-flex;align-items:center;gap:6px;margin-top:14px;padding-top:12px;border-top:1px solid var(--deep-line);font:600 13.5px\/1 var(--f-body);font-style:normal}\n.px-stat em .ico{width:15px;height:15px;transform:rotate(90deg);transition:transform .2s var(--ease-out)}\n.px-stat:hover em .ico{transform:rotate(90deg) translateX(2px)}\n.px-coef{background:var(--paper);border:1px solid var(--line);border-radius:var(--r-panel);padding:clamp(20px,3vw,32px);display:grid;gap:18px}\n.px-coef-h{display:grid;gap:6px}\n.px-coef-h h3{font-size:18px}\n.px-coef-h p{font-size:13.5px;line-height:1.55;color:var(--muted);max-width:80ch}\n.px-coef-axis,.px-coef-row{display:grid;grid-template-columns:140px minmax(0,1fr) 104px;column-gap:20px;align-items:center}\n.px-axis{position:relative;height:16px;font:500 11.5px\/1 var(--f-body);color:var(--muted);font-variant-numeric:tabular-nums}\n.px-axis i{position:absolute;top:0;font-style:normal;transform:translateX(-50%)}\n.px-axis i:first-child{transform:none}.px-axis i:last-child{transform:translateX(-100%)}\n.px-coef-rows{list-style:none;margin:0;padding:0;display:grid}\n.px-coef-row{row-gap:8px;padding:16px 0;border-top:1px solid var(--line)}\n.px-coef-n{font-weight:600;font-size:15px}\n.px-track{position:relative;height:10px;border-radius:5px;background:var(--mint)}\n.px-track span{position:absolute;top:0;bottom:0;border-radius:5px;background:var(--lc)}\n.px-coef-row:nth-child(1){--lc:#8fc3b6}.px-coef-row:nth-child(2){--lc:#4f9a89}.px-coef-row:nth-child(3){--lc:#2f7266}.px-coef-row:nth-child(4){--lc:#0f3a35}\n.px-coef-k{font:700 17px\/1.2 var(--f-display);text-align:right;white-space:nowrap}\n.px-coef-why{grid-column:2 \/ 4;font-size:13.5px;line-height:1.55;color:var(--muted)}\n.px-cites{display:inline-flex;flex-wrap:wrap;gap:4px;vertical-align:1px;margin-left:2px}\n.px-cite{display:inline-grid;place-items:center;min-width:22px;height:18px;padding:0 5px;border-radius:9px;background:var(--mint);color:var(--teal);font:600 10.5px\/1 var(--f-body);text-decoration:none;font-variant-numeric:tabular-nums;transition:background-color .15s ease,color .15s ease}\n.px-cite:hover{background:var(--teal);color:var(--teal-ink)}\n.px-bnotes{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px!important;max-width:none!important}\n.px-bnote{display:grid;gap:8px;align-content:start;padding:18px 20px;border-radius:var(--r-card);background:var(--paper);border:1px solid var(--line)}\n.px-bnote h3{font:600 14.5px\/1.3 var(--f-body);letter-spacing:0}\n.px-bnote p{font-size:13.5px;line-height:1.55;color:var(--muted)}\n.px-bnote.is-limit{background:transparent;border-style:dashed}\n.px-bnote:nth-child(1),.px-bnote:nth-child(4),.px-bnote:nth-child(6){grid-column:span 2}\n.px-bench-foot{display:grid}\n.px-bench-foot .px-method + .px-method{margin-top:0;border-top:0}\n.px-srcs summary > span{display:inline}\n.px-src-cols{columns:2 340px;column-gap:40px;padding-bottom:24px}\n.px-src-g{break-inside:avoid;margin-bottom:22px}\n.px-src-g h4{margin:0 0 8px;font:600 11.5px\/1.3 var(--f-body);letter-spacing:.06em;text-transform:uppercase;color:var(--teal)}\n.px-src-g ul{list-style:none;margin:0;padding:0;display:grid}\n.px-src-g li{display:grid;grid-template-columns:26px minmax(0,1fr);gap:8px;padding:7px 8px 7px 0;border-top:1px solid var(--line);font-size:13px;line-height:1.45;color:var(--ink);border-radius:6px;scroll-margin:120px}\n.px-src-g li:first-child{border-top:0}\n.px-src-i{font:600 11.5px\/1.6 var(--f-body);color:var(--muted);font-variant-numeric:tabular-nums}\n.px-src-t a{display:inline-flex;align-items:center;gap:3px;margin-left:8px;color:var(--teal);font-size:12px;text-decoration:none;white-space:nowrap}\n.px-src-t a:hover{text-decoration:underline}\n.px-src-t a .ico{width:11px;height:11px;transform:rotate(-45deg)}\n.px-src-g li.is-hit{animation:px-hit 1.6s ease-out}\n@keyframes px-hit{0%,30%{background:var(--mint-2)}100%{background:transparent}}\n.px-lev-n{font:600 12px\/1 var(--f-body);color:var(--teal);font-variant-numeric:tabular-nums;letter-spacing:.04em}\n.px-faq{grid-template-columns:minmax(0,1fr) minmax(0,2fr);gap:20px 48px!important;align-items:start}\n.px-faq-h{display:grid;gap:10px;position:sticky;top:96px}\n.px-faq-list{display:grid}\n.px-faq script{display:none}\n@media (max-width:860px){\n  .px-bench-head{grid-template-columns:1fr}\n  .px-bnotes{grid-template-columns:1fr}\n  .px-bnote:nth-child(1),.px-bnote:nth-child(4),.px-bnote:nth-child(6){grid-column:auto}\n  .px-faq{grid-template-columns:1fr}\n  .px-faq-h{position:static}\n}\n@media (max-width:620px){\n  .px-coef-axis{display:none}\n  .px-coef-row{grid-template-columns:minmax(0,1fr) auto;row-gap:10px}\n  .px-coef-n{grid-column:1}.px-coef-k{grid-column:2}\n  .px-track{grid-column:1 \/ 3;grid-row:2}\n  .px-coef-why{grid-column:1 \/ 3}\n}\n@media (prefers-reduced-motion:reduce){.px-src-g li.is-hit{animation:none;background:var(--mint-2)}}\n\/* Consultation native : une seule section, jamais de formulaire imbriqu\u00e9. *\/\n.cm-calculator-form-source{display:none!important;padding:0!important;margin:0!important}\n.cm-px .px-consultation{width:100%;max-width:720px;margin:clamp(28px,4vw,44px) auto 0;padding:clamp(22px,3vw,34px);border:1px solid var(--line);border-radius:var(--r-panel);background:var(--paper);display:grid;gap:22px;scroll-margin-top:110px;min-width:0}\n.cm-px .px-consult-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}\n.cm-px .px-consult-head > div{display:grid;gap:8px;min-width:0}\n.cm-px .px-consult-head h2{font-size:clamp(24px,3vw,30px);line-height:1.2}\n.cm-px .px-consult-head p{font-size:15px;line-height:1.5;color:var(--muted);max-width:52ch}\n.cm-px .px-consult-head .px-link{flex:none}\n.cm-px .px-consult-details{border-top:1px solid var(--line);min-width:0}\n.cm-px .px-consult-details summary{display:flex;align-items:center;justify-content:space-between;gap:12px;list-style:none;font:600 14px\/1.4 var(--f-body);color:var(--teal);cursor:pointer;min-height:44px}\n.cm-px .px-consult-details summary::-webkit-details-marker{display:none}\n.cm-px .px-consult-details pre{margin:0;padding:8px 0 16px;white-space:pre-wrap;overflow-wrap:anywhere;font:400 13.5px\/1.65 var(--f-body);color:var(--muted)}\n.cm-px .px-consult-privacy{font-size:12.5px;line-height:1.5;color:var(--muted)}\n.cm-px .px-consult-privacy a{color:var(--teal);text-underline-offset:3px}\n#px-dock[hidden]{display:none!important}\n.cm-px .px-act-btn{border:0;cursor:pointer}\n#px-consult-form-host,#px-consult-form-host .elementor-widget-container,#px-consult-form-host .eael-contact-form,#px-consult-form-host .eael-wpforms,#px-consult-form-host .wpforms-container{width:100%!important;max-width:100%!important;margin:0!important;padding:0!important;background:transparent!important;border:0!important;box-shadow:none!important}\n#px-consult-form-host form{margin:0!important}\n#px-consult-form-host .wpforms-head-container{display:none!important}\n#px-consult-form-host .wpforms-field-container{display:grid;grid-template-columns:1fr 1fr;gap:18px}\n#px-consult-form-host .wpforms-field{min-width:0;max-width:100%!important;width:100%!important;padding:0!important;margin:0!important;float:none!important}\n#px-consult-form-host #wpforms-56741-field_1-container,#px-consult-form-host #wpforms-56741-field_4-container,#px-consult-form-host #wpforms-56741-field_5-container{grid-column:1\/-1}\n\/* Optional snapshot must be submitted natively, never disabled\/required. *\/\n#wpforms-56741-field_6-container{display:none!important}\n#px-consult-form-host .wpforms-field-label{font:600 14px\/1.3 var(--f-body)!important;color:var(--ink)!important;margin:0 0 8px!important}\n#px-consult-form-host input[type=text],#px-consult-form-host input[type=email],#px-consult-form-host input[type=tel]{width:100%!important;max-width:100%!important;min-height:48px;border:1px solid var(--line)!important;border-radius:var(--r-field)!important;background:var(--paper)!important;color:var(--ink)!important;font:400 16px\/1.4 var(--f-body)!important;padding:12px 14px!important;box-shadow:none!important}\n#px-consult-form-host input:focus-visible,#px-consult-form-host button:focus-visible{outline:2px solid var(--teal)!important;outline-offset:3px!important}\n#px-consult-form-host input[type=checkbox]{accent-color:var(--teal);width:18px;height:18px}\n#px-consult-form-host .wpforms-field-checkbox ul{margin:0!important;padding:0!important}\n#px-consult-form-host .wpforms-field-checkbox li{display:flex;gap:10px;align-items:flex-start;list-style:none!important}\n#px-consult-form-host .wpforms-field-label-inline{font:400 14px\/1.5 var(--f-body)!important;color:var(--ink)!important}\n#px-consult-form-host .wpforms-submit-container{padding:0!important;margin-top:22px!important}\n#px-consult-form-host button.wpforms-submit{min-height:48px!important;border:0!important;border-radius:999px!important;padding:14px 22px!important;background:var(--teal)!important;color:var(--teal-ink)!important;font:600 14px\/1.3 var(--f-body)!important;white-space:normal!important;max-width:100%}\n#px-consult-form-host button.wpforms-submit:disabled{opacity:.6;cursor:not-allowed}\n#px-consult-form-host .wpforms-error{color:var(--bad)!important;font-size:13px!important}\n#px-consult-form-host .wpforms-confirmation-container-full{background:var(--mint)!important;color:var(--ink)!important;border:0!important;border-radius:var(--r-card);padding:20px!important}\n@media(max-width:520px){#px-consult-form-host .wpforms-field-container{grid-template-columns:1fr}}\n<\/style>\n\n<div lang=\"en\"><svg width=\"0\" height=\"0\" style=\"position:absolute\" aria-hidden=\"true\">\n  <symbol id=\"i-check\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"9\"\/><path d=\"M8 12.5l2.8 2.8L16 10\"\/><\/symbol>\n  <symbol id=\"i-tick\" viewBox=\"0 0 24 24\"><path d=\"M5 12.5l4.5 4.5L19 7.5\"\/><\/symbol>\n  <symbol id=\"i-alert\" viewBox=\"0 0 24 24\"><path d=\"M12 4l9 16H3z\"\/><path d=\"M12 10v4M12 17h.01\"\/><\/symbol>\n  <symbol id=\"i-x\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"9\"\/><path d=\"M9 9l6 6M15 9l-6 6\"\/><\/symbol>\n  <symbol id=\"i-chev\" viewBox=\"0 0 24 24\"><path d=\"M9 6l6 6-6 6\"\/><\/symbol>\n  <symbol id=\"i-down\" viewBox=\"0 0 24 24\"><path d=\"M6 9l6 6 6-6\"\/><\/symbol>\n  <symbol id=\"i-copy\" viewBox=\"0 0 24 24\"><rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\"\/><path d=\"M5 15V5a1 1 0 0 1 1-1h10\"\/><\/symbol>\n  <symbol id=\"i-arrow\" viewBox=\"0 0 24 24\"><path d=\"M5 12h14M13 6l6 6-6 6\"\/><\/symbol>\n<\/svg>\n\n<div class=\"cm-px\" id=\"px-root\">\n <div class=\"wrap\">\n\n  <header class=\"px-head\">\n    <p class=\"px-eyebrow\">Free calculator, no sign-up<\/p>\n    <h1 class=\"px-h1\">What price to sell your cosmetic product at, and how much to pay your manufacturer<\/h1>\n    <p class=\"px-lead\">This cosmetic pricing calculator takes five questions and margin assumptions by channel, and gives you your retail price, your margin and the purchase price not to exceed.<\/p>\n    <ul class=\"px-proof\">\n      <li><svg class=\"ico\"><use href=\"#i-check\"\/><\/svg>47 public sources cited<\/li>\n      <li><svg class=\"ico\"><use href=\"#i-check\"\/><\/svg>8 sales channels<\/li>\n      <li><svg class=\"ico\"><use href=\"#i-check\"\/><\/svg>Built by the manufacturer of 500+ brands<\/li>\n    <\/ul>\n  <\/header>\n\n  <div class=\"px-grid\">\n   <section class=\"px-panel px-flow\" aria-label=\"Calculator\">\n    <nav class=\"px-prog\" id=\"px-prog\" aria-label=\"Steps\"><\/nav>\n\n    <form class=\"px-steps\" id=\"px-form\" autocomplete=\"off\" onsubmit=\"return false\">\n\n     <div class=\"px-step\" data-step=\"1\">\n      <div class=\"px-q\"><h2 tabindex=\"-1\">What do you want to calculate?<\/h2><\/div>\n      <div class=\"px-cards\" role=\"radiogroup\" aria-label=\"Goal\">\n        <label class=\"px-co\"><input type=\"radio\" name=\"px-mode\" value=\"sell\" checked><span class=\"tick\"><svg><use href=\"#i-tick\"\/><\/svg><\/span><b>My selling price<\/b><small>I have a quote and I am looking for the right retail price.<\/small><span class=\"px-flowline\"><i>Quote<\/i><svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg><i class=\"on\">Retail price<\/i><\/span><\/label>\n        <label class=\"px-co\"><input type=\"radio\" name=\"px-mode\" value=\"buy\"><span class=\"tick\"><svg><use href=\"#i-tick\"\/><\/svg><\/span><b>My maximum purchase price<\/b><small>I have a target retail price and want to know how much to negotiate.<\/small><span class=\"px-flowline\"><i>Retail price<\/i><svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg><i class=\"on\">Maximum quote<\/i><\/span><\/label>\n      <\/div>\n     <\/div>\n\n     <div class=\"px-step\" data-step=\"2\" hidden>\n      <div class=\"px-q\">\n        <h2 tabindex=\"-1\" data-show=\"sell\">How much does one unit cost you?<\/h2>\n        <h2 tabindex=\"-1\" data-show=\"buy\" hidden>What price do you want to sell it at?<\/h2>\n        <p data-show=\"sell\">The unit price on your quote, packaging and filling included.<\/p>\n        <p data-show=\"buy\" hidden>The price shown on the shelf or on your website, taxes included.<\/p>\n      <\/div>\n      <div class=\"px-fields\">\n        <div class=\"px-field\">\n          <label for=\"px-market\">Country of sale<\/label>\n          <div class=\"px-in px-sel\"><select id=\"px-market\">\n            <option value=\"ma\">Morocco (MAD)<\/option>\n            <option value=\"fr\">France (EUR)<\/option>\n            <option value=\"be\">Belgium (EUR)<\/option>\n            <option value=\"es\">Spain (EUR)<\/option>\n            <option value=\"de\">Germany (EUR)<\/option>\n            <option value=\"uk\">United Kingdom (GBP)<\/option>\n            <option value=\"ae\">United Arab Emirates (AED)<\/option>\n            <option value=\"sa\">Saudi Arabia (SAR)<\/option>\n            <option value=\"us\">United States (USD)<\/option>\n          <\/select><svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/div>\n        <\/div>\n        <div class=\"px-field\" data-show=\"sell\">\n          <label for=\"px-A\">Unit purchase price (excl. VAT)<\/label>\n          <div class=\"px-in big\" id=\"px-A-box\"><input id=\"px-A\" inputmode=\"decimal\" value=\"32\"><span class=\"unit\" data-cur>MAD<\/span><\/div>\n        <\/div>\n        <div class=\"px-field\" data-show=\"buy\" hidden>\n          <label for=\"px-P\" id=\"px-P-lab\">Target retail price (incl. VAT)<\/label>\n          <div class=\"px-in big\" id=\"px-P-box\"><input id=\"px-P\" inputmode=\"decimal\" value=\"199\"><span class=\"unit\" data-cur>MAD<\/span><\/div>\n        <\/div>\n        <p class=\"px-msg\" id=\"px-step2-msg\" hidden><\/p>\n      <\/div>\n     <\/div>\n\n     <div class=\"px-step\" data-step=\"3\" hidden>\n      <div class=\"px-q\"><h2 tabindex=\"-1\">What is your positioning?<\/h2><p>It guides your marketing budget, your margin and how the price is rounded.<\/p><\/div>\n      <div class=\"px-stair\" id=\"px-pos\" role=\"radiogroup\" aria-label=\"Positioning\"><\/div>\n     <\/div>\n\n     <div class=\"px-step\" data-step=\"4\" hidden>\n      <div class=\"px-q\"><h2 tabindex=\"-1\">Where will you sell it?<\/h2><p>One or several: you will get a single price or a price per channel.<\/p><\/div>\n      <div class=\"px-chgroups\" id=\"px-channels\" role=\"group\" aria-label=\"Sales channels\"><\/div>\n      <p class=\"px-chcount\" id=\"px-chcount\" aria-live=\"polite\"><\/p>\n      <p class=\"px-msg\" id=\"px-step4-msg\" hidden>Keep at least one channel.<\/p>\n     <\/div>\n\n     <div class=\"px-step\" data-step=\"5\" hidden>\n      <div class=\"px-q\"><h2 tabindex=\"-1\">What margin do you want to keep?<\/h2><p>What you have left once everything is paid. Aim for the green zone.<\/p><\/div>\n      <div class=\"px-field px-gfield\">\n        <div class=\"px-range\">\n          <input type=\"range\" id=\"px-g-range\" min=\"0\" max=\"70\" step=\"1\" value=\"45\" aria-label=\"Target margin\" aria-describedby=\"px-zone-msg\">\n          <output id=\"px-g-out\" for=\"px-g-range\">45%<\/output>\n        <\/div>\n        <div class=\"px-zone\" aria-hidden=\"true\"><span class=\"lo\">Fragile margin<\/span><span class=\"mid\" id=\"px-zone-mid\">Typical range<\/span><span class=\"hi\">Outside benchmarks<\/span><\/div>\n        <p class=\"px-zone-msg\" id=\"px-zone-msg\"><\/p>\n      <\/div>\n      <details class=\"px-adv\" id=\"px-adv\">\n        <summary><span class=\"px-adv-h\"><b>Check our assumptions<\/b><small id=\"px-adv-sum\"><\/small><\/span><svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary>\n        <div class=\"px-adv-body\">\n          <p class=\"px-hint\">Each value is set to the benchmark for your positioning and channel. Tap a line to change it: the result updates instantly. Amounts are per unit.<\/p>\n          <div class=\"px-tabs\" id=\"px-edit\" role=\"tablist\" aria-label=\"Channel to adjust\" hidden><\/div>\n          <p class=\"px-bm-for\" id=\"px-bm-for\"><\/p>\n          <p class=\"px-chnote\" id=\"px-ch-note\"><\/p>\n          <div class=\"px-hyp\" id=\"px-hyp\"><\/div>\n          <div class=\"px-adv-foot\">\n            <button type=\"button\" class=\"px-link\" id=\"px-reset\">Apply the benchmarks<\/button>\n            <button type=\"button\" class=\"px-link\" id=\"px-showall\"><\/button>\n          <\/div>\n        <\/div>\n      <\/details>\n     <\/div>\n    <\/form>\n\n    <div class=\"px-nav\">\n      <button type=\"button\" class=\"px-back\" id=\"px-back\" disabled><svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg>Back<\/button>\n      <span class=\"count px-sr\" id=\"px-count\" aria-live=\"polite\">Step 1 of 5<\/span>\n      <button type=\"button\" class=\"px-btn\" id=\"px-next\">Continue<svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg><\/button>\n    <\/div>\n   <\/section>\n\n   <aside class=\"px-aside\">\n    <section class=\"px-answer is-locked\" id=\"px-answer\">\n      <div class=\"px-wait\" id=\"px-wait\">\n        <div class=\"px-wait-h\"><h3>Your price sheet will appear here<\/h3><p>Recommended retail price, margin, price breakdown and market positioning, from your 5<sup>th<\/sup> answer.<\/p><\/div>\n        <ol class=\"px-wait-list\" id=\"px-wait-list\"><\/ol>\n        <div class=\"px-ghost-rib\" aria-hidden=\"true\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/div>\n      <\/div>\n      <p class=\"px-sr\" id=\"px-reveal-live\" aria-live=\"polite\"><\/p>\n      <div class=\"px-strat\" id=\"px-strat\" role=\"group\" aria-label=\"Pricing strategy\" hidden>\n        <button type=\"button\" data-s=\"unique\" aria-pressed=\"true\">Single price<small>recommended<\/small><\/button>\n        <button type=\"button\" data-s=\"per\" aria-pressed=\"false\">Price by channel<small>one price for each<\/small><\/button>\n      <\/div>\n      <div class=\"px-err\" id=\"px-err\" hidden><svg class=\"ico\"><use href=\"#i-alert\"\/><\/svg><span id=\"px-err-t\"><\/span><\/div>\n      <div id=\"px-ans\" style=\"display:grid;gap:22px\">\n        <div class=\"px-ans-top\">\n          <div class=\"px-ans-label\"><span id=\"px-ans-label\">Recommended retail price (incl. VAT)<\/span>\n            <label class=\"px-switch\" data-show=\"sell\"><input type=\"checkbox\" id=\"px-round\" checked>Rounding<\/label><\/div>\n          <div class=\"px-big\" id=\"px-big\">\u2026<\/div>\n          <p class=\"px-sr\" id=\"px-live\" aria-live=\"polite\"><\/p>\n          <ul class=\"px-chlist\" id=\"px-chlist\" hidden><\/ul>\n          <p class=\"px-ans-note\" id=\"px-ans-note\"><\/p>\n        <\/div>\n        <dl class=\"px-figs\" id=\"px-figs\"><\/dl>\n        <div class=\"px-quote\" data-show=\"buy\" hidden>\n          <p class=\"px-nego\" id=\"px-nego\"><\/p>\n          <label for=\"px-quote\">Already have a quote?<\/label>\n          <div class=\"px-in\"><input id=\"px-quote\" inputmode=\"decimal\" placeholder=\"Proposed unit price\"><span class=\"unit\" data-cur>MAD<\/span><\/div>\n          <p class=\"px-status\" id=\"px-quote-v\" hidden><\/p>\n        <\/div>\n        <div class=\"px-perf\" aria-hidden=\"true\"><\/div>\n        <section class=\"px-a-sec px-a-first\" aria-labelledby=\"px-bd-t\">\n          <div class=\"px-a-h\"><h3 id=\"px-bd-t\">Where the price goes<\/h3><span class=\"px-a-total\" id=\"px-a-total\"><\/span><\/div>\n          <div class=\"px-a-ch\" id=\"px-bd-ch\" role=\"group\" hidden><\/div>\n          <div class=\"px-ribbon\" id=\"px-bar\" role=\"img\"><\/div>\n          <ul class=\"px-rleg\" id=\"px-legend\"><\/ul>\n        <\/section>\n        <section class=\"px-a-sec\" aria-labelledby=\"px-pos-t\">\n          <div class=\"px-a-h\"><h3 id=\"px-pos-t\">Positioning<\/h3><\/div>\n          <div class=\"px-ladder\" id=\"px-scale\"><\/div>\n          <div class=\"px-a-verdict\" id=\"px-verdict\"><\/div>\n        <\/section>\n        <p class=\"px-status\" id=\"px-pos-line\" hidden><\/p>\n        <div class=\"px-recap\" id=\"px-recap\" hidden><\/div>\n        <div class=\"px-act\" id=\"px-actions\">\n          <p>Let\u2019s review the feasibility of your product.<\/p>\n          <div class=\"px-act-row\">\n            <button type=\"button\" class=\"px-act-btn\" data-consult-placement=\"resultat\" aria-controls=\"px-consultation\" aria-expanded=\"false\">Free consultation<svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg><\/button>\n            <button type=\"button\" class=\"px-act-copy\" id=\"px-copy\"><svg class=\"ico\"><use href=\"#i-copy\"\/><\/svg><span>Copy<\/span><\/button>\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/section>\n    <p class=\"px-disc\" id=\"px-disc\"><svg class=\"ico\"><use href=\"#i-alert\"\/><\/svg><span>Indicative price, calculated from your answers and public averages. It replaces neither a study of your market nor a quote: compare your competitors\u2019 prices, your retailers\u2019 terms and your actual costs before setting your own.<\/span><\/p>\n   <\/aside>\n  <\/div>\n\n  <section class=\"px-consultation\" id=\"px-consultation\" hidden aria-labelledby=\"px-consult-title\">\n    <div class=\"px-consult-head\">\n      <div><h2 id=\"px-consult-title\" tabindex=\"-1\">Let\u2019s talk about your product<\/h2><p>A project manager reviews your request. You can attach your simulation to explain your price target.<\/p><\/div>\n      <button type=\"button\" class=\"px-link\" id=\"px-consult-close\">Close<\/button>\n    <\/div>\n    <div id=\"px-consult-form-host\"><\/div>\n    <p id=\"px-consult-fallback\" class=\"px-consult-privacy\" role=\"status\">If the form does not appear, <a href=\"\/demande-de-devis\/\">request your consultation on our contact page<\/a>.<\/p>\n    <details id=\"px-consult-simulation\" class=\"px-consult-details\" hidden>\n      <summary>View the attached simulation<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary>\n      <pre id=\"px-consult-summary\"><\/pre>\n    <\/details>\n    <p class=\"px-consult-privacy\">No commitment. This simulation is not a quote. Your contact details are used to process your request. <a href=\"\/politique-de-confidentialite\/\">Privacy policy<\/a>.<\/p>\n  <\/section>\n\n  <div class=\"px-detail\" id=\"px-detail\">\n    <section class=\"px-panel px-wide\" id=\"px-multi\" aria-labelledby=\"px-multi-t\" hidden>\n      <h2 id=\"px-multi-t\">Channel by channel<\/h2>\n      <div class=\"px-tablewrap\"><table class=\"px-ctable\"><thead id=\"px-ct-head\"><\/thead><tbody id=\"px-ct-body\"><\/tbody><\/table><\/div>\n      <p class=\"px-hint\" id=\"px-ct-foot\"><\/p>\n    <\/section>\n  <\/div>\n\n  <section class=\"px-bench\" id=\"px-bench\" aria-labelledby=\"px-bench-t\">\n    <div class=\"px-bench-head\">\n      <div class=\"px-bench-hl\">\n        <p class=\"px-eyebrow\">Our benchmarks<\/p>\n        <h2 id=\"px-bench-t\">Real margins, not guesses<\/h2>\n        <p class=\"px-kick\">Each rate comes from an annual report, a competition authority opinion, a fee schedule or a price survey. Everything is sourced and verifiable.<\/p>\n      <\/div>\n      <a class=\"px-stat\" href=\"#px-srcs\" id=\"px-stat\"><b id=\"px-stat-n\">47<\/b><span>public sources cited<\/span><em>See the list<svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg><\/em><\/a>\n    <\/div>\n\n    <div class=\"px-coef\">\n      <div class=\"px-coef-h\"><h3>Coefficient by positioning<\/h3><p id=\"px-bench-intro\"><\/p><\/div>\n      <div class=\"px-coef-axis\" aria-hidden=\"true\"><span><\/span><div class=\"px-axis\"><i style=\"left:0\">\u00d71<\/i><i style=\"left:22.22%\">\u00d73<\/i><i style=\"left:44.44%\">\u00d75<\/i><i style=\"left:66.67%\">\u00d77<\/i><i style=\"left:100%\">\u00d710<\/i><\/div><\/div>\n      <ol class=\"px-coef-rows\" id=\"px-bench-rows\"><\/ol>\n    <\/div>\n\n    <div class=\"px-bnotes\" id=\"px-bench-notes\"><\/div>\n\n    <div class=\"px-bench-foot\">\n    <details class=\"px-method\">\n      <summary>How the calculation works<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary>\n      <ol>\n        <li>Retail price excl. VAT = price incl. VAT \u00f7 (1 + VAT).<\/li>\n        <li>The retailer buys at the price excl. VAT \u00d7 (1 \u2212 its margin). The distributor, if there is one, takes its margin on that price.<\/li>\n        <li>What remains is your selling price excl. VAT. We subtract commissions, marketing, promotion, the purchase price and logistics: what is left is your margin.<\/li>\n        <li>Maximum purchase price = selling price excl. VAT \u00d7 (1 \u2212 commissions \u2212 marketing \u2212 promotion \u2212 target margin) \u2212 logistics.<\/li>\n        <li>Coefficient = retail price excluding taxes \u00f7 purchase price. It does not depend on the VAT rate, so countries can be compared.<\/li>\n        <li>Typical margin range: the margin you get when your retail price stays within the coefficient range for your positioning (see our benchmarks), with your channel\u2019s margins and costs.<\/li>\n      <\/ol>\n      <p>Indicative results. Middleman margins vary by retailer, country and your agreements.<\/p>\n    <\/details>\n      <details class=\"px-method px-srcs\" id=\"px-srcs\">\n        <summary><span>The <span id=\"px-srcs-n\">47<\/span> sources, with their links<\/span><svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary>\n        <div class=\"px-src-cols\" id=\"px-sources\"><\/div>\n      <\/details>\n    <\/div>\n  <\/section>\n\n  <section class=\"px-levers-sec\" aria-labelledby=\"px-lev-t\">\n    <h2 id=\"px-lev-t\">Quote above your maximum purchase price? Six ways to bring it down<\/h2>\n    <ul class=\"px-levers\">\n      <li><span class=\"px-lev-n\">01<\/span><b>A stock bottle<\/b><p>A bottle the manufacturer already lists avoids tooling costs and costs less than a custom model.<\/p><\/li>\n      <li><span class=\"px-lev-n\">02<\/span><b>An adapted existing formula<\/b><p>Starting from an already validated formula reduces development and the number of stability tests you pay for.<\/p><\/li>\n      <li><span class=\"px-lev-n\">03<\/span><b>Simpler decoration<\/b><p>A well-designed label costs less than multi-color screen printing or hot stamping.<\/p><\/li>\n      <li><span class=\"px-lev-n\">04<\/span><b>The carton, only if it earns its place<\/b><p>Pharmacies and perfumeries often expect one. When selling online, many brands go without.<\/p><\/li>\n      <li><span class=\"px-lev-n\">05<\/span><b>Shared components<\/b><p>The same bottle and the same pump across several products: you buy more of each component, so it costs less.<\/p><\/li>\n      <li><span class=\"px-lev-n\">06<\/span><b>Comparable quotes<\/b><p>Check what each quote includes: filling, quality control, Product Information File (PIF), safety assessment.<\/p><\/li>\n    <\/ul>\n  <\/section>\n\n  <section class=\"px-faq\" aria-labelledby=\"px-faq-t\">\n    <div class=\"px-faq-h\"><p class=\"px-eyebrow\">FAQ<\/p><h2 id=\"px-faq-t\">Cosmetic pricing calculator: frequently asked questions<\/h2><\/div>\n    <div class=\"px-faq-list\">\n      <details class=\"px-method\"><summary>Is the calculator really free?<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary><p class=\"px-faq-a\">Yes. You answer the five questions and the result appears right away, with no sign-up and no email. No payment, no commitment.<\/p><\/details>\n      <details class=\"px-method\"><summary>Do I need to manufacture with Carmel to use it?<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary><p class=\"px-faq-a\">No. The calculation applies to any manufacturer. Use your maximum purchase price to compare and negotiate all your quotes.<\/p><\/details>\n      <details class=\"px-method\"><summary>Where do the retailer margins come from?<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary><p class=\"px-faq-a\">From annual reports of cosmetics groups and retailers, competition authority opinions and public commission schedules. The 47 sources are listed above, with their links.<\/p><\/details>\n      <details class=\"px-method\"><summary>I sell through several channels: which price should I show?<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary><p class=\"px-faq-a\">Select all your channels. The calculator suggests a single retail price, set by the most demanding channel, so your product costs the same everywhere. You can also show a price per channel.<\/p><\/details>\n      <details class=\"px-method\"><summary>Can I rely on the results to negotiate?<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary><p class=\"px-faq-a\">They are solid orders of magnitude, not a quote. Margins vary by retailer, country and your agreements. If you know yours, correct them in \u201cCheck our assumptions\u201d.<\/p><\/details>\n      <details class=\"px-method\"><summary>My maximum purchase price is too low: what can I do?<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary><p class=\"px-faq-a\">Change channel or positioning, apply the six levers above, or request a free consultation. A project manager reviews with you the feasibility of the product, the formulation and packaging options and your price target. The simulation is not a quote and does not guarantee a manufacturing price.<\/p><\/details>\n      <details class=\"px-method\"><summary>What happens if I request a consultation?<svg class=\"ico\"><use href=\"#i-down\"\/><\/svg><\/summary><p class=\"px-faq-a\">You enter your product and your contact details in the form. The \u201cAttach my simulation\u201d box is optional: unchecked, no simulation is attached. A project manager reviews your request, with no commitment. The manufacturing price will be set in the quote.<\/p><\/details>\n    <\/div>\n    <script type=\"application\/ld+json\">{\"@context\": \"https:\/\/schema.org\", \"@type\": \"FAQPage\", \"mainEntity\": [{\"@type\": \"Question\", \"name\": \"What happens if I request a consultation?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"You enter your product and your contact details in the form. The \u201cAttach my simulation\u201d box is optional: unchecked, no simulation is attached. A project manager reviews your request, with no commitment. The manufacturing price will be set in the quote.\"}}, {\"@type\": \"Question\", \"name\": \"Is the calculator really free?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Yes. You answer the five questions and the result appears right away, with no sign-up and no email. No payment, no commitment.\"}}, {\"@type\": \"Question\", \"name\": \"Do I need to manufacture with Carmel to use it?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. The calculation applies to any manufacturer. Use your maximum purchase price to compare and negotiate all your quotes.\"}}, {\"@type\": \"Question\", \"name\": \"Where do the retailer margins come from?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"From annual reports of cosmetics groups and retailers, competition authority opinions and public commission schedules. The 47 sources are listed above, with their links.\"}}, {\"@type\": \"Question\", \"name\": \"I sell through several channels: which price should I show?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Select all your channels. The calculator suggests a single retail price, set by the most demanding channel, so your product costs the same everywhere. You can also show a price per channel.\"}}, {\"@type\": \"Question\", \"name\": \"Can I rely on the results to negotiate?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"They are solid orders of magnitude, not a quote. Margins vary by retailer, country and your agreements. If you know yours, correct them in \u201cCheck our assumptions\u201d.\"}}, {\"@type\": \"Question\", \"name\": \"My maximum purchase price is too low: what can I do?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Change channel or positioning, apply the six levers above, or request a free consultation. A project manager reviews with you the feasibility of the product, the formulation and packaging options and your price target. The simulation is not a quote and does not guarantee a manufacturing price.\"}}]}<\/script>\n  <\/section>\n\n  <figure class=\"px-note\">\n    <blockquote>\n      <p>The first question we get is almost always: how much does a bottle cost? It comes too early. First you need to know what your customer will pay, what the pharmacy, the distributor or the marketplace will keep, and what will be left for you.<\/p>\n      <p>Without that number, you negotiate blind and find out too late that a product leaves no margin. We built this calculator so you arrive at your first manufacturer meeting with your maximum purchase price in hand, with us or elsewhere.<\/p>\n    <\/blockquote>\n    <figcaption><span class=\"px-note-av\" aria-hidden=\"true\">MH<\/span><span><b>Mohamed El Hjouji<\/b>Founder, Carmel Cosmetics Labs<\/span><\/figcaption>\n  <\/figure>\n\n  <section class=\"px-cta\">\n    <div>\n      <h2>You have your maximum purchase price: let\u2019s review your project<\/h2>\n      <p>Talk about your product with a Carmel project manager. They review its feasibility, your price target and the formulation and packaging options. The manufacturing price will be set in the quote, with no guarantee that it matches the simulation. More than 500 brands, in more than 35 countries, have already trusted us with their manufacturing.<\/p>\n    <\/div>\n    <button type=\"button\" class=\"px-btn\" data-consult-placement=\"bas-page\" aria-controls=\"px-consultation\" aria-expanded=\"false\">Free consultation<svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg><\/button>\n  <\/section>\n\n  <p class=\"px-legal\"><b>Disclaimer.<\/b> This calculator gives orders of magnitude, for information only. Results depend on the assumptions entered and on averages from public sources; they are neither financial, legal or tax advice, nor a price offer from Carmel Cosmetics Labs. Retailer margins, commissions, taxes and logistics costs vary by country, retailer and your agreements. Before setting your price, do your own research: competitor prices on the shelf and online, the actual terms of your distributors, quotes from your suppliers and, if needed, the advice of an accountant. The selling price remains your decision.<\/p>\n <\/div>\n<\/div>\n\n<div class=\"px-dock\" id=\"px-dock\" aria-hidden=\"true\">\n  <div><span id=\"px-dock-k\">Recommended retail price<\/span><b id=\"px-dock-v\">\u2026<\/b><\/div>\n  <a href=\"#px-answer\">See the result<\/a>\n<\/div>\n\n<script>\n(function(){\n  const $ = id => document.getElementById(id);\n\n  const MARKETS = {\n    ma:{name:'Morocco',cur:'MAD',vat:20,rate:10.8,help:'VAT: standard rate in Morocco.'},\n    fr:{name:'France',cur:'EUR',vat:20,rate:1,help:'VAT: standard rate in France.'},\n    be:{name:'Belgium',cur:'EUR',vat:21,rate:1,help:'VAT: standard rate in Belgium.'},\n    es:{name:'Spain',cur:'EUR',vat:21,rate:1,help:'IVA (VAT): standard rate in Spain.'},\n    de:{name:'Germany',cur:'EUR',vat:19,rate:1,help:'MwSt (VAT): standard rate in Germany.'},\n    uk:{name:'United Kingdom',cur:'GBP',vat:20,rate:0.86,help:'VAT: standard rate in the United Kingdom.'},\n    ae:{name:'UAE',cur:'AED',vat:5,rate:4.0,help:'VAT in the United Arab Emirates.'},\n    sa:{name:'Saudi Arabia',cur:'SAR',vat:15,rate:4.1,help:'VAT in Saudi Arabia.'},\n    us:{name:'United States',cur:'USD',vat:0,rate:1.1,help:'In the United States, retail prices are shown excluding sales tax.'}\n  };\n  \/\/ r = marge revendeur, d = distributeur, f = commissions\/remises (% du prix HT de la marque),\n  \/\/ am\/ap = ajustement publicit\u00e9\/promotion par rapport au positionnement, L2 = livraison par unit\u00e9 en EUR\n  const CHANNELS = [\n    {k:'dtc',name:'Your online store',short:'Online store',r:0,d:0,f:3,am:8,ap:-4,L2:2.5,note:'When selling direct, you pay the payment fees and the shipping of every order.'},\n    {k:'mkp',name:'Marketplace',short:'Marketplace',r:0,d:0,f:15,am:3,ap:-4,L2:3,note:'Amazon takes 8% on beauty products up to \u20ac10 and 15% above, excluding shipping fees (Amazon seller fee schedule).'},\n    {k:'pha',name:'Pharmacy',short:'Pharmacy',r:35,d:0,f:0,am:0,ap:1,L2:0.3,note:'Parapharmacy prices are free. The average commercial margin of French pharmacies was 27.6% in 2022, all products combined (Insee). No public figure exists for Morocco.'},\n    {k:'sel',name:'Perfumery',short:'Perfumery',r:40,d:0,f:0,am:0,ap:4,L2:0.3,note:'In France, the competition authority found a recommended price of about 1.97 times the wholesale price excl. VAT, or nearly 40% of the price excl. VAT for the perfumer. In the United States, chains take 50 to 60%.'},\n    {k:'gms',name:'Mass retail',short:'Mass retail',r:30,d:0,f:8,am:0,ap:3,L2:0.3,note:'Walmart gross margin: 24%, all categories. Retailers often add year-end discounts and trade cooperation fees.'},\n    {k:'disc',name:'Discount chains',short:'Discount',r:22,d:0,f:2,am:0,ap:2,L2:0.3,note:'2025 gross margin: 19% at BIM, 41% at Action. Discount chains demand the lowest prices on the market.'},\n    {k:'spa',name:'Salons and spas',short:'Salons',r:50,d:0,f:0,am:-5,ap:0,L2:0.3,note:'Salons and spas generally resell at double their purchase price (the \u201ckeystone\u201d rule).'},\n    {k:'exp',name:'Export',short:'Export',r:40,d:25,f:0,am:-5,ap:-1,L2:0.2,note:'The distributor takes its margin, then the local retailer takes its own.'}\n  ];\n  const CH = Object.fromEntries(CHANNELS.map(c=>[c.k,c]));\n  \/\/ lo\/hi = coefficient prix public HT \u00f7 prix d'achat (voir BENCH, sources publi\u00e9es) ; m\/p\/g = publicit\u00e9, promotion, marge vis\u00e9e par d\u00e9faut\n  const POS = [\n    {k:'hd',name:'Hard discount',of:'entry price',who:'discount brands',lvl:1,lo:1.5,hi:3,m:2,p:5,g:25,round:'low',desc:'The lowest price on the shelf, simple packaging.',where:'Discount chains, entry-price ranges'},\n    {k:'mass',name:'Mass market',of:'mass market',who:'mass market brands',lvl:2,lo:3,hi:5,m:9,p:7,g:35,round:'low',desc:'Accessible and available everywhere.',where:'Supermarkets, e-commerce'},\n    {k:'hdg',name:'Premium',of:'premium',who:'premium brands',lvl:3,lo:5,hi:7,m:16,p:8,g:45,round:'mid',desc:'Carefully chosen actives, a polished brand.',where:'Pharmacy, salons, digital brands'},\n    {k:'lux',name:'Luxury',of:'luxury',who:'luxury brands',lvl:4,lo:7,hi:10,m:22,p:6,g:55,round:'lux',desc:'An object and a brand experience.',where:'Selective perfumery, department stores'}\n  ];\n  const BENCH = {\"intro\": \"The coefficient compares the retail price excluding tax with the purchase price of one unit. We rebuilt it from the gross margins published by cosmetics groups and from retailer margins, then cross-checked it with industry experts. These benchmarks apply to established brands: a young brand usually pays more and should aim for the top of the range.\", \"rows\": [{\"pos\": \"Hard discount\", \"k\": \"\u00d71.5 to \u00d73\", \"why\": \"Often the retailer is the brand: with a 19% gross margin at BIM and 41% at Action, the selling price is 1.2 to 1.7 times the cost. A brand selling to a discounter adds its own margin.\", \"src\": [1, 2]}, {\"pos\": \"Mass market\", \"k\": \"\u00d73 to \u00d75\", \"why\": \"Gross margin of mass market groups: 47% at Unilever, 51% at P&G, 58% at Beiersdorf, 71% at e.l.f. Retailer margin: 24% at Walmart, 39% at Ulta Beauty.\", \"src\": [3, 4, 5, 6, 7, 8]}, {\"pos\": \"Premium\", \"k\": \"\u00d75 to \u00d77\", \"why\": \"Gross margin of 71 to 74% (e.l.f., L'Or\u00e9al group), or 3.4 to 3.9 times the cost, then the margin of the pharmacy or beauty chain.\", \"src\": [6, 9, 10, 8]}, {\"pos\": \"Luxury\", \"k\": \"\u00d77 to \u00d710\", \"why\": \"Gross margin of 74 to 77% (Est\u00e9e Lauder, Puig, Shiseido), or 3.9 to 4.3 times the cost, then selective distribution. Experts interviewed by Beauty Independent cite 8 to 10 times the cost.\", \"src\": [11, 12, 13, 14, 15]}], \"notes\": [{\"t\": \"Shelf prices for a 50 ml face care product (survey of October 9, 2026) : in Morocco, MAD 30 to 90 for hard discount, MAD 65 to 180 for mass market, MAD 190 to 370 for pharmacy and premium, MAD 1,100 to 1,700 for luxury (Lanc\u00f4me, Clarins, Est\u00e9e Lauder at Marionnaud). In France: \u20ac2 to \u20ac6, \u20ac4 to \u20ac15, \u20ac16 to \u20ac40 and \u20ac85 to \u20ac140. The calculator compares your price with these ranges.\", \"src\": [42, 43, 44, 45, 46, 47]}, {\"t\": \"Marketing : advertising and promotion account for 12% (P&G) to 24% (e.l.f. Beauty) of revenue for mass market brands, 22% (Beiersdorf) to 32% (L'Or\u00e9al) for premium groups, and 25% to 30% (Est\u00e9e Lauder 25%, Coty Prestige 28%, Shiseido 29%) in luxury. The calculator's benchmarks are derived from these figures.\", \"src\": [18, 19, 20, 21, 22, 3, 23, 13]}, {\"t\": \"Online payments : Stripe charges 1.5% + \u20ac0.25 per standard European card. No reliable public benchmark exists for export distributor margins or for mass retail discounts: the calculator says so.\", \"src\": [24]}, {\"t\": \"Delivery : for your online store, the cost per order (picking, packing and delivery) comes from studies published in 2025 and 2026 by European and US logistics providers, converted to a per-unit figure at 1.3 products per order. No recent independent study publishes this cost. FEVAD puts the average basket in France at around \u20ac60. For the marketplace, we use Amazon's shipping fees. In Morocco, we use the cost observed by Carmel: MAD 40 per shipment. In the UAE and Saudi Arabia, no verified study exists: we use the postal rate, flagged as such.\", \"src\": [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41]}, {\"t\": \"Channels : Amazon takes 8% then 15% on beauty; salons and spas resell at double their purchase price.\", \"src\": [16, 17]}, {\"t\": \"Limits : the margins of large groups include their own stores and very large-scale purchasing. No public data exists on retail margins in Morocco.\", \"src\": []}], \"sources\": [{\"t\": \"BIM, Q4 2025 results, p. 15\", \"u\": \"https:\/\/english.bim.com.tr\/investorPresentations\/2025\/BIM%204Q25%20Results%20Presentation.pdf\"}, {\"t\": \"3i Group, Action 2026 presentation, p. 47\", \"u\": \"https:\/\/www.3i.com\/media\/0hkffvm0\/2026-action-cms-presentation_vfinal.pdf\"}, {\"t\": \"Unilever, 2025 annual results\", \"u\": \"https:\/\/data.fca.org.uk\/artefacts\/NSM\/RNS\/b82e96e8-7680-4ddf-8c41-f0bb2a051dd5.html\"}, {\"t\": \"Procter & Gamble, 10-K annual report, fiscal 2025\", \"u\": \"https:\/\/www.sec.gov\/Archives\/edgar\/data\/80424\/000008042425000076\/pg-20250630.htm\"}, {\"t\": \"Beiersdorf, 2025 annual report, income statement\", \"u\": \"https:\/\/reports.beiersdorf.com\/annual-report\/2025\/consolidated-financial-statements\/consolidated-financial-statements\/income-statement.html\"}, {\"t\": \"e.l.f. Beauty, fiscal 2026 results\", \"u\": \"https:\/\/investor.elfbeauty.com\/stock-and-financial\/press-releases\/landing-news\/2026\/05-20-2026-210538723\"}, {\"t\": \"Walmart, 10-K annual report, fiscal 2026\", \"u\": \"https:\/\/www.sec.gov\/Archives\/edgar\/data\/104169\/000010416926000055\/wmt-20260131.htm\"}, {\"t\": \"Ulta Beauty, fiscal 2025 results\", \"u\": \"https:\/\/www.ulta.com\/investor\/news-events\/press-releases\/detail\/224\/ulta-beauty-announces-fourth-quarter-and-fiscal-2025\"}, {\"t\": \"L'Or\u00e9al, 2025 annual results\", \"u\": \"https:\/\/www.loreal-finance.com\/eng\/press-release\/2025-annual-results\"}, {\"t\": \"Insee Premi\u00e8re no. 2036, pharmacies, January 2025\", \"u\": \"https:\/\/www.insee.fr\/fr\/statistiques\/fichier\/8341260\/ip2036.pdf\"}, {\"t\": \"Est\u00e9e Lauder Companies, fiscal 2025 results\", \"u\": \"https:\/\/www.elcompanies.com\/en\/news-and-media\/newsroom\/press-releases\/2025\/08-20-2025-110025649\"}, {\"t\": \"Moodie Davitt Report, Puig 2025 results, February 2026\", \"u\": \"https:\/\/moodiedavittreport.com\/puig-records-7-8-revenue-growth-in-fy2025-outperforming-premium-beauty-market\/\"}, {\"t\": \"Shiseido, 2025 results, p. 10\", \"u\": \"https:\/\/corp.shiseido.com\/en\/ir\/pdf\/ir20260210_244.pdf\"}, {\"t\": \"French Competition Authority, decision 06-D-04 on luxury perfumery, 2006\", \"u\": \"https:\/\/autoritedelaconcurrence.fr\/sites\/default\/files\/commitments\/06d04.pdf\"}, {\"t\": \"Beauty Independent, \u201cIs A 700% Retail Markup Too Much For A Beauty Product?\u201d, Rachel Brown, March 2020\", \"u\": \"https:\/\/www.beautyindependent.com\/retail-markup-beauty-product-fur-oil-shark-tank\/\"}, {\"t\": \"Amazon, seller fees (beauty category)\", \"u\": \"https:\/\/sell.amazon.fr\/tarifs\"}, {\"t\": \"American Spa, \u201cLaunching your line\u201d, July 2009\", \"u\": \"https:\/\/www.americanspa.com\/business\/launching-your-line\"}, {\"t\": \"L'Or\u00e9al, 2025 universal registration document, advertising and promotion expenses\", \"u\": \"https:\/\/www.loreal-finance.com\/eng\/2025-universal-registration-document\/en\/article\/43\/\"}, {\"t\": \"Est\u00e9e Lauder Companies, 10-K annual report, fiscal 2026\", \"u\": \"https:\/\/www.sec.gov\/Archives\/edgar\/data\/0001001250\/000100125026000041\/el-20260630.htm\"}, {\"t\": \"Coty, 10-K annual report, fiscal 2025\", \"u\": \"https:\/\/www.sec.gov\/Archives\/edgar\/data\/1024305\/000102430525000030\/coty-20250630.htm\"}, {\"t\": \"e.l.f. Beauty, 10-K annual report, fiscal 2026\", \"u\": \"https:\/\/www.sec.gov\/Archives\/edgar\/data\/0001600033\/000160003326000020\/elf-20260331.htm\"}, {\"t\": \"Beiersdorf, 2025 management report, group results\", \"u\": \"https:\/\/reports.beiersdorf.com\/annual-report\/2025\/combined-management-report\/economic-report\/results-of-operations\/results-of-operations-group.html\"}, {\"t\": \"Procter & Gamble, 10-K annual report, fiscal 2026\", \"u\": \"https:\/\/www.sec.gov\/Archives\/edgar\/data\/0000080424\/000008042426000103\/pg-20260630.htm\"}, {\"t\": \"Stripe, France pricing\", \"u\": \"https:\/\/stripe.com\/fr\/pricing\"}, {\"t\": \"La Poste, 2026 Colissimo rates\", \"u\": \"https:\/\/www.laposte.fr\/tarif-colissimo\"}, {\"t\": \"bpost, 2026 practical guide to parcels\", \"u\": \"https:\/\/www.bpost.be\/sites\/default\/files\/pricing\/2026\/Praktische_gids_voor_particuliere_zendingen_2026_FR.pdf\"}, {\"t\": \"Correos, 2026 rates, Peninsula and Balearic Islands\", \"u\": \"https:\/\/www.correos.es\/\"}, {\"t\": \"DHL, 2026 domestic rates\", \"u\": \"https:\/\/www.dhl.de\/en\/privatkunden\/pakete-versenden\/deutschlandweit-versenden\/preise-national.html\"}, {\"t\": \"Royal Mail, 2026 online parcel rates\", \"u\": \"https:\/\/www.royalmail.com\/current-postage-prices\/online-parcel-price-reduction\"}, {\"t\": \"Emirates Post, 2026 domestic rates\", \"u\": \"https:\/\/www.emiratespost.ae\/all-services\/domestic-rates\"}, {\"t\": \"SPL, economy parcel\", \"u\": \"https:\/\/splonline.com.sa\/en\/economy\/\"}, {\"t\": \"USPS, Notice 123, rates as of October 4, 2026\", \"u\": \"https:\/\/pe.usps.com\/text\/dmm300\/Notice123.htm\"}, {\"t\": \"Amazon, FBA rate card Europe and UK, July 2026\", \"u\": \"https:\/\/m.media-amazon.com\/images\/G\/02\/sell\/images\/260630-FBA-Rate-Card-EN1.pdf\"}, {\"t\": \"Amazon.com, FBA shipping fees\", \"u\": \"https:\/\/sellercentral.amazon.com\/help\/hub\/reference\/external\/GABBX6GZPA8MSZGW\"}, {\"t\": \"Amazon.ae, seller fees\", \"u\": \"https:\/\/sell.amazon.ae\/pricing\"}, {\"t\": \"Amazon.sa, seller fees\", \"u\": \"https:\/\/sell.amazon.sa\/pricing\"}, {\"t\": \"Masson International, 3PL logistics costs in Europe, June 2025\", \"u\": \"https:\/\/www.massoninternational.com\/blog\/third-party-logistics-costs-europe\"}, {\"t\": \"Euroship Fulfillment, fulfillment cost in Europe, September 2026\", \"u\": \"https:\/\/euroshipfulfillment.com\/blog\/fulfillment-cost-europe-breakdown\"}, {\"t\": \"UK Pre Fulfilment, 2025 pick and pack rates\", \"u\": \"https:\/\/ukprefulfillment.com\/pick-pack-pricing-uk-2025-cost-breakdown\/\"}, {\"t\": \"Red Stag Fulfillment, 3PL pricing explained, August 2026\", \"u\": \"https:\/\/redstagfulfillment.com\/3pl-pricing-explained\/\"}, {\"t\": \"FEVAD, 2026 e-commerce key figures\", \"u\": \"https:\/\/www.fevad.com\/ledition-2026-des-chiffres-cles-du-e-commerce\/\"}, {\"t\": \"Marjane Mall, Nivea 50 ml cream and entry-level care, October 2026 survey\", \"u\": \"https:\/\/www.marjanemall.ma\/p\/NIV4005900573209\"}, {\"t\": \"Parachezvous.ma, La Roche-Posay, Av\u00e8ne, Bioderma, Vichy, October 2026 survey\", \"u\": \"https:\/\/parachezvous.ma\/\"}, {\"t\": \"Marionnaud Morocco, Lanc\u00f4me R\u00e9nergie, Clarins, Est\u00e9e Lauder, October 2026 survey\", \"u\": \"https:\/\/marionnaud.ma\/products\/lancome-renergie-hpn-300-peptide\"}, {\"t\": \"Carrefour.fr, private label face creams, Nivea, Garnier, L'Or\u00e9al, October 2026 survey\", \"u\": \"https:\/\/www.carrefour.fr\/\"}, {\"t\": \"Redcare Pharmacie, La Roche-Posay, Av\u00e8ne, Vichy, October 2026 survey\", \"u\": \"https:\/\/www.redcare-pharmacie.fr\/\"}, {\"t\": \"Sephora.fr, Lanc\u00f4me R\u00e9nergie, Clarins, Est\u00e9e Lauder, list prices, October 2026 survey\", \"u\": \"https:\/\/www.sephora.fr\/p\/renergie---creme-jour-2158.html\"}]};\n\n  \/\/ Prix en rayon d'un soin visage de 50 ml, TTC, relev\u00e9s le 9 octobre 2026 (voir nos rep\u00e8res)\n  const SHELF = {ma:{where:'in Morocco',hd:[30,90],mass:[65,180],hdg:[190,370],lux:[1100,1700]},\n                 eur:{where:'in France',hd:[2,6],mass:[4,15],hdg:[16,40],lux:[85,140]}};\n  function shelfBand(k){ const m=state.market, B = m==='ma' ? SHELF.ma : ['fr','be','es','de'].includes(m) ? SHELF.eur : null; return B&&B[k] ? {lo:B[k][0],hi:B[k][1],where:B.where} : null; }\n  const STEPS = ['Goal','Product','Positioning','Channels','Margin'];\n  const state = {mode:'sell', market:'ma', channels:['pha'], edit:'pha', strategy:'unique', pos:'hdg', step:1, reached:1, g:.45, vat:20, L1:3, L1e:0.28, showAll:false, open:null, gTouched:false, base:{A:32\/10.8,P:199\/10.8,quote:null}, revealed:false};\n  const cv = {};   \/\/ hypoth\u00e8ses par canal : r, d, f, m, p (%) et L2 (montant par unit\u00e9)\n  const posOf = () => POS.find(x=>x.k===state.pos);\n  const sel = () => CHANNELS.filter(c=>state.channels.includes(c.k));\n  const tickSvg = '<span class=\"tick\"><svg><use href=\"#i-tick\"\/><\/svg><\/span>';\n\n  POS.forEach(x=>{\n    const l=document.createElement('label'); l.className='px-tier';\n    l.style.cssText=`--lvl:${x.lvl};--tint:${2+x.lvl*3}%`;\n    l.innerHTML=`<input type=\"radio\" name=\"px-pos\" value=\"${x.k}\"${x.k===state.pos?' checked':''}>${tickSvg}<span class=\"px-lvl\" aria-hidden=\"true\">${[1,2,3,4].map(n=>`<i class=\"${n<=x.lvl?'on':''}\"><\/i>`).join('')}<\/span><b>${x.name}<\/b><span class=\"where\">${x.where}<\/span>`;\n    $('px-pos').appendChild(l);\n  });\n  \/\/ canaux regroup\u00e9s : vente directe, puis via des revendeurs\n  [['Direct sales',['dtc','mkp']],['Through resellers',['pha','sel','gms','disc','spa','exp']]].forEach(([title,keys])=>{\n    const g=document.createElement('div'); g.className='px-chgroup';\n    g.innerHTML=`<p class=\"px-chgroup-t\">${title}<\/p><div class=\"px-cards tight\"><\/div>`;\n    keys.forEach(k=>{ const c=CH[k];\n      const sub = c.d>0 ? `${c.d}% + ${c.r}%` : c.r>0 ? `${c.r}% to the retailer` : `Commission ${c.f}%`;\n      const l=document.createElement('label'); l.className='px-co small multi';\n      l.innerHTML=`<input type=\"checkbox\" name=\"px-ch\" value=\"${c.k}\"${state.channels.includes(c.k)?' checked':''}>${tickSvg}<b>${c.name}<\/b><small>${sub}<\/small>`;\n      g.lastChild.appendChild(l); });\n    $('px-channels').appendChild(g);\n  });\n  STEPS.forEach((s,i)=>{ const b=document.createElement('button'); b.type='button'; b.dataset.step=i+1; b.textContent=s; $('px-prog').appendChild(b); });\n\n  const num = id => { const v=parseFloat(String($(id).value).replace(\/\\s\/g,'').replace(',','.')); return isFinite(v)?v:NaN; };\n  const fmt = (v,dec=2) => (Math.round(v*10**dec)\/10**dec).toString();\n  const setNum = (id,v,dec=2) => { $(id).value=fmt(v,dec); };\n  const cur = () => MARKETS[state.market].cur;\n  const nf = {};\n  function money(v, forceDec){\n    const c=cur(), dec = forceDec!=null ? forceDec : (Math.abs(v)>=1000 ? 0 : (Math.abs(v-Math.round(v))<0.005 ? 0 : 2));\n    const key=c+dec;\n    nf[key]=nf[key]||new Intl.NumberFormat('en-US',{style:'currency',currency:c,currencyDisplay:'narrowSymbol',minimumFractionDigits:dec,maximumFractionDigits:dec});\n    return nf[key].format(v);\n  }\n  const pct = v => (Math.round(v*1000)\/10).toString()+'%';\n  const coef = v => '\u00d7'+(Math.round(v*10)\/10).toString();\n  const plain = s => s.replace('\u2011','-');\n\n  \/\/ arrondi au palier psychologique le plus proche (au-dessus ou en dessous), \u00e9cart plafonn\u00e9 \u00e0 5 %\n  function psych(x){\n    const c=cur(), eur=(c==='EUR'||c==='GBP'||c==='USD'), r=posOf().round;\n    let cand;\n    if (r==='lux'){ const step = eur ? (x<100?5:10) : (x<500?10:50); cand=[Math.floor(x\/step)*step, Math.ceil(x\/step)*step]; }\n    else if (eur && x<100){ const e = r==='low'?0.99:0.9, up=Math.ceil(x-e)+e; cand=[up-1, up]; }\n    else { const up=Math.ceil((x+1)\/10)*10-1; cand=[up-10, up]; }\n    cand=cand.filter(v=>v>0);\n    let best=cand.reduce((a,b)=>Math.abs(b-x)<Math.abs(a-x)?b:a, cand[cand.length-1]);\n    if (!cand.length || Math.abs(best-x)\/x>0.05) best = x<20 ? Math.round(x*10)\/10 : Math.round(x);\n    return best;\n  }\n\n  \/* ---------- hypoth\u00e8ses par canal ---------- *\/\n  \/\/ Livraison par d\u00e9faut : tarif public du pays (colis \u00e0 domicile pour le site en ligne, Amazon pour la marketplace)\n  const SHIP = {\"fr\": {\"p\": [4.85, 7.85, 4.85, \"Cost per order in France: picking and packing \u20ac1.80 and delivery \u20ac4.50 (Masson International, 2025), up to \u20ac10.20 from a warehouse in the Netherlands (Euroship, 2026). Converted to a per-unit figure at 1.3 products per order (Euroship). Logistics provider studies: indicative figures.\"], \"f\": [3.33, 5.07, 5.07, \"Amazon.fr, FBA shipping fees July 2026: \u20ac3.33 (envelope) to \u20ac5.07 (small parcel up to 400 g).\"]}, \"be\": {\"p\": [4.77, 5.92, 5.12, \"Cost per order in Belgium: picking and packing \u20ac1.95 and delivery \u20ac4.70 (Masson International, 2025), \u20ac6.20 to \u20ac7.70 from the Netherlands (Euroship, 2026). Converted to a per-unit figure at 1.3 products per order (Euroship). Logistics provider studies: indicative figures.\"], \"f\": [2.47, 3.67, 3.67, \"Amazon.com.be, FBA shipping fees July 2026: \u20ac2.47 (envelope) to \u20ac3.67 (small parcel).\"]}, \"es\": {\"p\": [6.5, 9.38, 6.5, \"Cost per order in Spain: picking and packing \u20ac2.20 (Euroship, 2026) and Correos delivery \u20ac6.25 excl. VAT, up to \u20ac12.20 from the Netherlands. Converted to a per-unit figure at 1.3 products per order (Euroship). Logistics provider studies: indicative figures.\"], \"f\": [3.26, 3.74, 3.74, \"Amazon.es, FBA shipping fees July 2026: \u20ac3.26 (envelope) to \u20ac3.74 (small parcel).\"]}, \"de\": {\"p\": [5.15, 7.08, 6.12, \"Cost per order in Germany: picking and packing \u20ac2.20 and delivery \u20ac4.50 to \u20ac7.00 (Euroship, 2026). Converted to a per-unit figure at 1.3 products per order (Euroship). Logistics provider studies: indicative figures.\"], \"f\": [2.57, 3.39, 3.39, \"Amazon.de, FBA shipping fees July 2026: \u20ac2.57 (envelope) to \u20ac3.39 (small parcel).\"]}, \"uk\": {\"p\": [3.96, 4.5, 4.23, \"Cost per order in the United Kingdom: picking and packing \u00a31.50 to \u00a32.20 (UK Pre Fulfilment, 2025) and Royal Mail tracked parcel \u00a33.65. Converted to a per-unit figure at 1.3 products per order (Euroship). Logistics provider studies: indicative figures.\"], \"f\": [2.1, 3.0, 3.0, \"Amazon.co.uk, FBA shipping fees July 2026: \u00a32.10 (envelope) to \u00a33.00 (small parcel).\"]}, \"ae\": {\"p\": [9.2, 9.5, 9.2, \"Estimate: no public study in the UAE. We use Amazon.ae shipping fees (picking, packing and delivery included), AED 9.2 to 9.5 excl. VAT per product (August 2025).\"], \"f\": [9.2, 9.5, 9.2, \"Amazon.ae, FBA shipping fees August 2025: AED 9.2 to 9.5 excl. VAT.\"]}, \"sa\": {\"p\": [9.2, 9.5, 9.2, \"Estimate: no public study in Saudi Arabia. We use Amazon.sa shipping fees (picking, packing and delivery included), SAR 9.2 to 9.5 excl. VAT per product (August 2025).\"], \"f\": [9.2, 9.5, 9.2, \"Amazon.sa, FBA shipping fees August 2025: SAR 9.2 to 9.5 excl. VAT.\"]}, \"us\": {\"p\": [8.15, 9.42, 8.15, \"Cost per order in the United States: picking and packing $3.25 (Red Stag Fulfillment, 2026) and USPS delivery $7.34, up to $12.25 with a ground carrier ($8 to $9). Converted to a per-unit figure at 1.3 products per order (Euroship). Logistics provider studies: indicative figures.\"], \"f\": [3.54, 4.2, 3.95, \"Amazon.com, FBA shipping fees 2026: $3.54 to $4.20 depending on weight (outside the holiday season).\"]}, \"ma\": {\"p\": [30.77, 30.77, 30.77, \"Cost observed by Carmel Cosmetics Labs in Morocco: MAD 40 per shipment, picking, packing and delivery included, or MAD 30.77 per product at 1.3 products per order.\"]}};\n  function shipRef(k){ const s=SHIP[state.market]; if(!s) return null; return k==='dtc'?s.p : k==='mkp'?s.f : null; }\n  function defaultL2(k){ const ref=shipRef(k), rate=MARKETS[state.market].rate, dec=rate>3?1:2; return ref ? ref[2] : Math.round(CH[k].L2*rate*10**dec)\/10**dec; }\n  function initChannel(k){\n    const c=CH[k], x=posOf(), rate=MARKETS[state.market].rate;\n    cv[k]=fitMkt({r:c.r,d:c.d,f:c.f,m:Math.max(0,x.m+c.am),p:Math.max(0,x.p+c.ap),L2:defaultL2(k)});\n  }\n  function applyMix(){ const x=posOf(); Object.keys(cv).forEach(k=>{ if(cv[k].mTouched) return; const c=CH[k]; cv[k].m=Math.max(0,x.m+c.am); cv[k].p=Math.max(0,x.p+c.ap); fitMkt(cv[k]); }); }\n  \/\/ Hypoth\u00e8ses lisibles : group\u00e9es par destinataire de l'argent, m\u00eames couleurs que le graphique\n  const getV=(k,id)=> id==='L1'?state.L1 : id==='vat'?state.vat : cv[k][id];\n  const setV=(k,id,v)=>{ if(isFinite(v)&&v<0) v=0; if(id==='L1'){ state.L1=v; state.L1e=v\/MARKETS[state.market].rate; } else if(id==='vat') state.vat=v; else { cv[k][id]=v; if(id==='m'||id==='p') cv[k].mTouched=true; } };\n  \/* Rep\u00e8res par combinaison positionnement x canal. [min, max, source]. Rempli \u00e0 partir de la recherche documentaire. *\/\n  const BMK = {\"r\": {\"pha\": [25, 35, \"Average commercial margin of French pharmacies: 27.6% in 2022, all products, medicines included (Insee). Parapharmacy, at free prices, is generally above.\"], \"sel\": [39, 60, \"France: about 39% (French Competition Authority, 1999 to 2005 data). United States: 50 to 60% (Beauty Independent, 2020).\"], \"gms\": [24, 39, \"No public figure specific to beauty in mass retail. Benchmarks: Walmart gross margin, all categories, 24%; Ulta Beauty, a specialty chain, 39%.\"], \"disc\": [19, 41, \"2025 gross margin of BIM: 19%; of Action: 41%.\"], \"spa\": [45, 50, \"Keystone rule: resale at double the purchase price (American Spa).\"]}, \"f\": {\"mkp\": [8, 15, \"Amazon seller fee schedule, beauty category: 8% up to \u20ac10, 15% above, calculated on the price paid by the buyer (VAT included).\"], \"dtc\": [1.5, 3.2, \"Stripe: 1.5% per standard European card, up to 3.15% for an international card. The fixed \u20ac0.25 per order is added to logistics.\"]}, \"m\": {\"pos\": {\"mass\": [12, 24], \"hdg\": [22, 32], \"lux\": [25, 30]}, \"src\": {\"mass\": \"Advertising and promotion spend as a share of revenue: P&G 12%, Unilever 16%, e.l.f. Beauty 24%.\", \"hdg\": \"Advertising and promotion spend as a share of revenue: Beiersdorf 22%, Est\u00e9e Lauder 25% (with product development), Coty 27%, L\u2019Or\u00e9al 32%.\", \"lux\": \"Advertising and promotion spend as a share of revenue: Est\u00e9e Lauder 25% (with product development), Coty Prestige 28%, Shiseido 29%.\"}}};\n  function noneText(k,id){\n    if (id==='L2'){\n      if (k==='dtc'&&state.market==='ma') return 'Estimate: no verified public study or rate in Morocco (Amana does not publish its e-commerce rates). Replace it with your carrier\u2019s quote.';\n      if (k==='mkp') return 'Estimate: no public fee schedule from the platform for this country. Replace it with its quote.';\n      return 'Estimate: no public rate exists for delivery to stores. Replace it with your carrier\u2019s quote.';\n    }\n    return NONE[id]||'No public benchmark.';\n  }\n  const NONE = {r:'No reliable public benchmark for this channel.',d:'No reliable public benchmark for cosmetics distributors.',f:'No verified public benchmark for this channel.',m:'No public benchmark: entry-price brands invest little in advertising.',L1:'No benchmark: depends on your carrier and country of origin.',L2:'No benchmark: depends on your logistics setup.'};\n  function bench(k,id){\n    const x=posOf();\n    if (id==='L2'){ const ref=shipRef(k); return ref ? {lo:ref[0],hi:ref[1],src:ref[3],money:true} : null; }\n    if (id==='vat') return {lo:MARKETS[state.market].vat,hi:MARKETS[state.market].vat,src:'Legal rate in the country of sale.'};\n    if (id==='p') return BMK.m.pos[x.k] ? {ref:true} : null;\n    if (id==='m'){ const r=BMK.m.pos[x.k]; return r ? {lo:r[0],hi:r[1],src:BMK.m.src[x.k],total:true} : null; }\n    const v=BMK[id]&&BMK[id][k]; return v ? {lo:v[0],hi:v[1],src:v[2]} : null;\n  }\n  \/\/ garde le budget marketing par d\u00e9faut (publicit\u00e9 + promotion) dans le rep\u00e8re du positionnement\n  function fitMkt(o){ const r=BMK.m.pos[posOf().k]; if(!r) return o; const t=o.m+o.p; if(t<r[0]) o.m+=r[0]-t; if(t>r[1]) o.m=Math.max(0,o.m-(t-r[1])); return o; }\n  const benchLabel = k => `${plain(posOf().name).toLowerCase()}, ${CH[k].short.toLowerCase()}`;\n  function hypDefs(k){\n    const c=CH[k], cu=MARKETS[state.market].cur, rate=MARKETS[state.market].rate;\n    const fHelp={dtc:'Online payment and subscription fees for your store.',mkp:'Commission taken by the platform on each sale.',gms:'Year-end discounts and trade cooperation fees required by the retailer.',disc:'Discounts required by the retailer.'}[k]||'Discounts or commissions required by the channel.';\n    const mMax=Math.max(Math.ceil(20*rate), Math.ceil((state.L1||0)*2), Math.ceil((cv[k].L2||0)*2));\n    return [\n      {g:'Distribution',sw:'var(--c-canal)',rows:[\n        {id:'r',lab:'Store margin',help:'What the retailer keeps on its selling price excl. VAT.',unit:'%',max:70,show:c.r>0},\n        {id:'d',lab:'Distributor margin',help:'What the importer or wholesaler takes, before the store.',unit:'%',max:50,show:c.d>0},\n        {id:'f',lab:'Commissions and discounts',help:fHelp,unit:'%',max:30,show:c.f>0}]},\n      {g:'Marketing',sw:'var(--c-mkt)',rows:[\n        {id:'m',lab:'Advertising and influencers',help:'Online ads, influencers and content, as a share of what you invoice.',unit:'%',max:40,show:true},\n        {id:'p',lab:'Promotion',help:'Offers, testers, samples, point-of-sale displays.',unit:'%',max:30,show:true}]},\n      {g:'Logistics',sw:'var(--c-fab)',rows:[\n        {id:'L1',lab:'Transport and customs',help:'From the factory to your stock. Same amount for all your channels.',unit:cu,max:mMax,show:true},\n        {id:'L2',lab:'Delivery',help:k==='dtc'?'Order picking and delivery to the customer, converted to one product.':k==='mkp'?'Platform shipping fees, per product.':'Delivery of your cartons to the store, converted to a per-unit figure.',unit:cu,max:mMax,show:true}]},\n      {g:'Taxes',sw:'var(--c-tva)',rows:[\n        {id:'vat',lab:'VAT',help:MARKETS[state.market].help+' Same rate for all your channels.',unit:'%',max:25,show:true}]}\n    ];\n  }\n  \/\/ Une ligne compacte par poste (nom, valeur, rep\u00e8re, montant) ; un clic ouvre le r\u00e9glage\n  function buildHyp(){\n    const k=state.edit, multi=state.channels.length>1, rate=MARKETS[state.market].rate;\n    $('px-edit').hidden=!multi;\n    $('px-edit').innerHTML=sel().map(c=>`<button type=\"button\" role=\"tab\" aria-selected=\"${c.k===k}\" data-k=\"${c.k}\">${c.short}<\/button>`).join('');\n    $('px-ch-note').hidden=true;\n    $('px-bm-for').textContent=`Benchmarks for: ${plain(posOf().name)}, ${CH[k].name}`;\n    let hiddenN=0;\n    $('px-hyp').innerHTML=hypDefs(k).map(G=>{\n      const rows=G.rows.filter(r=>{ const on=r.show||state.showAll||getV(k,r.id)>0; if(!on) hiddenN++; return on; });\n      if (!rows.length) return '';\n      return `<section class=\"px-hg\" style=\"--sw:${G.sw}\"><header><h4>${G.g}<\/h4><span class=\"px-hg-t\" data-gt=\"${G.g}\"><\/span><\/header>${rows.map(r=>{\n        const v=getV(k,r.id), isM=r.unit!=='%', step=isM?(rate>3?0.5:0.05):0.5, dec=isM?(rate>3?1:2):1;\n        const bm0=bench(k,r.id), bm=bm0&&!bm0.total&&!bm0.ref?bm0:null, P=x=>Math.min(100,Math.max(0,x\/r.max*100));\n        const track = bm ? `--track:linear-gradient(90deg,var(--mint-2) 0%,var(--mint-2) ${P(bm.lo)}%,var(--z-ok) ${P(bm.lo)}%,var(--z-ok) ${Math.max(P(bm.hi),P(bm.lo)+1.5)}%,var(--mint-2) ${Math.max(P(bm.hi),P(bm.lo)+1.5)}%,var(--mint-2) 100%)` : '';\n        const open = state.open===r.id;\n        return `<div class=\"px-r${open?' is-open':''}\" data-row=\"${r.id}\">\n          <button type=\"button\" class=\"px-r-head\" aria-expanded=\"${open}\" aria-controls=\"hb-${r.id}\">\n            <span class=\"px-r-name\">${r.lab}<\/span>\n            <span class=\"px-r-val\" data-v=\"${r.id}\" data-unit=\"${isM?'m':'%'}\" data-dec=\"${dec}\"><\/span>\n            <span class=\"px-r-pill\" data-pill=\"${r.id}\"><\/span>\n            <span class=\"px-r-amt\" data-a=\"${r.id}\"><\/span>\n            <svg class=\"ico px-r-chev\"><use href=\"#i-down\"\/><\/svg>\n          <\/button>\n          <div class=\"px-r-body\" id=\"hb-${r.id}\"${open?'':' inert'}><div class=\"px-r-inner\"><div class=\"px-r-pad\">\n            <p class=\"px-r-help\">${r.help}<\/p>\n            <div class=\"px-h-c\"><input type=\"range\" class=\"px-hr\" id=\"h-${r.id}\" data-id=\"${r.id}\" min=\"0\" max=\"${r.max}\" step=\"${step}\" value=\"${v}\" style=\"${track}\" aria-label=\"${r.lab}\">\n            <span class=\"px-h-v\"><input type=\"text\" inputmode=\"decimal\" data-id=\"${r.id}\" data-dec=\"${dec}\" aria-label=\"${r.lab}, value\" value=\"${fmt(v,dec)}\"><i>${isM?r.unit:'%'}<\/i><\/span><\/div>\n            <p class=\"px-r-src\" data-src=\"${r.id}\"><\/p>\n          <\/div><\/div><\/div>\n        <\/div>`; }).join('')}<\/section>`;\n    }).join('');\n    const sa=$('px-showall'); sa.hidden = hiddenN===0 && !state.showAll;\n    sa.textContent = state.showAll ? 'Hide items that do not apply' : `Show other items (${hiddenN})`;\n  }\n  function toggleRow(id){\n    state.open = state.open===id ? null : id;\n    document.querySelectorAll('#px-hyp .px-r').forEach(r=>{\n      const on=r.dataset.row===state.open; r.classList.toggle('is-open',on);\n      r.querySelector('.px-r-head').setAttribute('aria-expanded',String(on));\n      const body=r.querySelector('.px-r-body'); if(on) body.removeAttribute('inert'); else body.setAttribute('inert','');\n    });\n  }\n  function updateHyp(o){\n    const k=state.edit, c=CH[k], v=cv[k];\n    const parts=[];\n    if (c.r>0||v.r>0) parts.push(`store ${fmt(v.r,1)}%`);\n    if (c.d>0||v.d>0) parts.push(`distributor ${fmt(v.d,1)}%`);\n    if (c.f>0||v.f>0) parts.push(`commissions ${fmt(v.f,1)}%`);\n    parts.push(`marketing ${fmt(v.m+v.p,1)}%`, isFinite(state.vat)?`VAT ${fmt(state.vat,1)}%`:'VAT to be entered');\n    $('px-adv-sum').textContent = state.channels.length>1 ? `${state.channels.length} channels, adjustable one by one. ${c.short}: ${parts.join(', ')}.` : `${c.name}: ${parts.join(', ')}.`;\n    const row = o && !o.err ? o.rows.find(r=>r.k===k) : null;\n    const amt = row ? {r:row.HT-row.W, d:row.W-row.R, f:row.f*row.R, m:row.m*row.R, p:row.pr*row.R, L1:state.L1, L2:row.L-state.L1, vat:row.P-row.HT} : {};\n    document.querySelectorAll('#px-hyp [data-a]').forEach(el=>{ const id=el.dataset.a, a=amt[id]; el.textContent = (id==='L1'||id==='L2') ? '' : a!=null&&isFinite(a) ? money(a,2) : ''; });\n    document.querySelectorAll('#px-hyp [data-v]').forEach(el=>{ const val=getV(k,el.dataset.v); el.textContent = !isFinite(val) ? '?' : el.dataset.unit==='m' ? money(val,Number(el.dataset.dec)) : `${fmt(val,1)}%`; });\n    let off=0;\n    document.querySelectorAll('#px-hyp [data-pill]').forEach(el=>{\n      const id=el.dataset.pill, bm=bench(k,id), src=document.querySelector(`#px-hyp [data-src=\"${id}\"]`);\n      if (bm && bm.ref){ el.dataset.s='na'; el.textContent='With advertising'; src.innerHTML='Counted with advertising in the marketing benchmark.'; return; }\n      if (!bm){ el.dataset.s='na'; el.textContent='No benchmark'; src.innerHTML=noneText(k,id); return; }\n      const val = bm.total ? getV(k,'m')+getV(k,'p') : getV(k,id);\n      const range = bm.money ? (bm.lo===bm.hi ? money(bm.lo,2) : `${money(bm.lo,2)} to ${money(bm.hi,2)}`) : bm.lo===bm.hi ? `${fmt(bm.lo,1)}%` : `${fmt(bm.lo,1)}-${fmt(bm.hi,1)}%`;\n      const inside = val>=bm.lo-1e-6 && val<=bm.hi+1e-6; if(!inside) off++;\n      el.dataset.s = inside ? 'in' : 'out';\n      el.innerHTML = `${icon(inside?'check':'alert')}${id==='vat'?'Legal rate':bm.total?`Marketing ${range}`:bm.money?'Benchmark':`Benchmark ${range}`}`;\n      const lbl = bm.total ? `Total marketing benchmark (advertising + promotion), ${plain(posOf().name).toLowerCase()}: ${range}` : id==='vat' ? `Legal rate: ${range}` : bm.money ? `Benchmark ${MARKETS[state.market].name}, ${CH[k].short.toLowerCase()}: ${range} per product` : `Benchmark ${benchLabel(k)}: ${range}`;\n      src.innerHTML = `<b>${lbl}<\/b>${inside?'':` \u00b7 you are at ${bm.money?money(val,2):fmt(val,1)+'%'}`}<br>${bm.src}`;\n    });\n    $('px-adv-sum').textContent += off ? ` ${off} value${off>1?'s':''} outside the benchmark.` : ' All benchmarked values are within the benchmarks.';\n    const tot={Distribution:['r','d','f'],Marketing:['m','p'],Logistics:['L1','L2'],Taxes:['vat']};\n    document.querySelectorAll('#px-hyp [data-gt]').forEach(el=>{ const s=tot[el.dataset.gt].reduce((x,id)=>x+(amt[id]||0),0); el.innerHTML = row ? `<b>${money(s,2)}<\/b> of ${money(row.P)}` : ''; });\n  }\n  \/\/ Zone d'usage de la marge : la marge obtenue quand le prix public reste dans la fourchette\n  \/\/ de coefficients du positionnement (rep\u00e8res sourc\u00e9s), avec les marges du canal le plus exigeant\n  function marginZone(o){\n    const b=o.rows[o.bind], x=posOf();\n    const gAt = K => { const A = o.mode==='sell' ? o.A : o.HT\/K, HT = o.mode==='sell' ? K*A : o.HT, R=HT*(1-b.r)*(1-b.d); return 1-b.f-b.mp-(A+b.L)\/R; };\n    return [gAt(x.lo)*100, gAt(x.hi)*100];\n  }\n  function snapMargin(){\n    if (state.gTouched) return;   \/\/ la marge choisie par l'utilisateur n'est jamais \u00e9cras\u00e9e\n    const o=compute(); let v=posOf().g;\n    if (!o.err){ const [lo,hi]=marginZone(o); if (hi>lo && hi>0){ if (v<lo) v=Math.ceil(lo); if (v>hi) v=Math.floor(hi); } }\n    setMargin(Math.min(70,Math.max(0,v)));\n  }\n  function renderZone(o){\n    const el=$('px-g-range'), out=$('px-g-out'), msg=$('px-zone-msg'), MIN=0, MAX=70;\n    const P = v => Math.min(100,Math.max(0,(v-MIN)\/(MAX-MIN)*100));\n    if (!o || o.err){ el.style.removeProperty('--track'); msg.hidden=true; $('px-zone-mid').textContent='Typical range'; out.removeAttribute('data-z'); return; }\n    const [lo,hi]=marginZone(o), x=posOf(), nm=plain(x.name).toLowerCase(), real=o.rows[o.bind].gReal*100, g=real;\n    const gap = Math.abs(real-state.g*100)>0.5 ? ` With ${o.mode==='sell'?'the rounded price':'this quote'}, your actual margin is ${fmt(real,1)}%.` : '';\n    const where = o.multi ? `, in the most demanding channel (${o.rows[o.bind].name})` : ` (${o.rows[0].name})`;\n    msg.hidden=false;\n    if (!(hi>MIN && hi>lo)){\n      el.style.setProperty('--track','linear-gradient(90deg,var(--z-low),var(--z-high))');\n      $('px-zone-mid').textContent='Typical range';\n      out.dataset.z='low'; msg.dataset.z='low';\n      msg.innerHTML=`${icon('alert')}<span>With these costs, no margin can reach the usual ${nm} prices. Review the purchase price, the channel or the positioning.<\/span>`;\n      return;\n    }\n    const zl=P(lo), zh=P(hi);\n    el.style.setProperty('--track',`linear-gradient(90deg,var(--z-low) 0%,var(--z-low) ${Math.max(0,zl-10)}%,var(--z-ok) ${zl}%,var(--z-ok) ${zh}%,var(--z-high) ${Math.min(100,zh+10)}%,var(--z-high) 100%)`);\n    const mid=$('px-zone-mid');\n    mid.textContent = lo<MIN ? `Typical range: up to ${Math.min(MAX,Math.round(hi))}%` : `Typical range: ${Math.round(lo)} to ${Math.min(MAX,Math.round(hi))}%`;\n    const z = g<lo-0.5 ? 'low' : g>hi+0.5 ? 'high' : 'ok';\n    out.dataset.z=z; msg.dataset.z=z;\n    const sellM = o.mode==='sell';\n    msg.innerHTML = z==='ok'\n      ? `${icon('check')}<span>Within the typical range for ${nm} products${where}.${gap}<\/span>`\n      : z==='low'\n      ? `${icon('alert')}<span>Fragile margin: it may not cover your fixed costs.${gap}<\/span>`\n      : `${icon('alert')}<span>Outside the benchmarks: ${sellM?'price above comparable brands, to be justified by your brand.':'product much cheaper than comparable brands: check the quality.'}${gap}<\/span>`;\n  }\n  function setMargin(v){ $('px-g-range').value=v; $('px-g-out').textContent=v+'%'; }\n  function applyMarket(k){\n    const nu=MARKETS[k], dec=nu.rate>3?1:2;\n    state.market=k;\n    \/\/ on repart toujours des valeurs saisies (stock\u00e9es en euros) : pas de d\u00e9rive apr\u00e8s plusieurs changements de pays\n    [['px-A','A',dec],['px-P','P',nu.rate>3?0:2],['px-quote','quote',dec]].forEach(([id,key,dd])=>{ const b=state.base[key]; if(b!=null&&isFinite(b)) setNum(id,b*nu.rate,dd); });\n    state.L1=Math.round(state.L1e*nu.rate*10**dec)\/10**dec;\n    state.vat=nu.vat;\n    Object.keys(cv).forEach(ck=>{ cv[ck].L2=defaultL2(ck); });\n    document.querySelectorAll('[data-cur]').forEach(e=>e.textContent=nu.cur);\n    $('px-P-lab').textContent = nu.vat>0 ? 'Target retail price (incl. VAT)' : 'Target retail price (excl. sales tax)';\n  }\n\n  \/* ---------- calcul ---------- *\/\n  function chParams(k,L1,t,P){\n    const v=cv[k], r=v.r\/100, d=v.d\/100, cu=cur();\n    let fr=v.f\/100;\n    if (k==='mkp' && P!=null && (cu==='EUR'||cu==='GBP'||cu==='USD') && P<=10) fr=Math.min(fr,0.08);   \/\/ Amazon beaut\u00e9 : 8 % jusqu'\u00e0 10\n    \/\/ la commission Amazon porte sur le prix pay\u00e9 par l'acheteur (TTC) : on la ram\u00e8ne au prix HT de la marque\n    const f = k==='mkp' ? fr*(1+(t||0))\/((1-r)*(1-d)) : fr;\n    \/\/ frais fixe de paiement en ligne (Stripe : 0,25 \u20ac par commande, 1,3 produit par commande)\n    const fix = (k==='dtc' && state.market!=='ma') ? 0.25*MARKETS[state.market].rate\/1.3 : 0;\n    return {k,name:CH[k].name,short:CH[k].short,r,d,f,m:v.m\/100,pr:v.p\/100,mp:(v.m+v.p)\/100,L:L1+(v.L2||0)+fix,online:k==='dtc'||k==='mkp'};\n  }\n  function at(c,P,A,t){ const HT=P\/(1+t), W=HT*(1-c.r), R=W*(1-c.d), gross=R*(1-c.f)-A-c.L, mktU=c.mp*R, net=gross-mktU; return Object.assign({},c,{P,HT,W,R,A,gross,mktU,net,gReal:net\/R}); }\n\n  function compute(){\n    const t=state.vat\/100, L1=state.L1||0, g=Number($('px-g-range').value)\/100;\n    if (!isFinite(t)) return {err:'Enter the VAT rate.'};\n    const check = cs => { for (const c of cs){\n      if ([c.r,c.d,c.f,c.m,c.pr,c.L].some(v=>!isFinite(v))) return `Complete the assumptions for the ${c.name} channel.`;\n      if (c.r>=1||c.d>=1) return `${c.name}: a middleman margin must stay below 100%.`;\n      if (c.f+c.mp+g>=1) return `${c.name}: commissions, marketing, promotion and target margin exceed 100% of the selling price. Lower one of these percentages.`;\n    } return null; };\n    const keys=sel().map(c=>c.k), multi=keys.length>1, round=$('px-round').checked;\n    \/\/ le prix unique et le prix d'achat maximum se calent sur les canaux de revente quand il y en a\n    const poolOf = (cs,ok) => { const idx=cs.map((c,i)=>i).filter(ok); const retail=idx.filter(i=>!cs[i].online); return retail.length?retail:idx; };\n    if (state.mode==='sell'){\n      const A=num('px-A');\n      if (!(A>0)) return {err:'Enter the purchase price from your quote.'};\n      const solve = c => (A+c.L)\/((1-c.f-c.mp-g)*(1-c.d)*(1-c.r))*(1+t);\n      const cs=keys.map(k=>{ let c=chParams(k,L1,t); const e=check([c]); if(e) return {err:e}; c.Praw=solve(c); if(k==='mkp'){ const c2=chParams(k,L1,t,c.Praw); if(c2.f!==c.f){ c2.Praw=solve(c2); c=c2; } } c.Pr=round?psych(c.Praw):c.Praw; return c; });\n      const bad=cs.find(c=>c.err); if (bad) return {err:bad.err};\n      const pool=poolOf(cs,()=>true); let bind=pool[0]; pool.forEach(i=>{ if(cs[i].Praw>cs[bind].Praw) bind=i; });\n      const Praw=cs[bind].Praw, Puni=round?psych(Praw):Praw, per=multi && state.strategy==='per';\n      const rows=cs.map(c=>{ const Pu = per||!multi ? c.Pr : Puni; const cc = c.k==='mkp' ? chParams(c.k,L1,t,Pu) : c; return Object.assign(at(cc,Pu,A,t),{Praw:c.Praw,Pr:c.Pr}); });\n      const Pm=per?rows[bind].P:Puni;\n      return {mode:'sell',t,g,A,multi,per,rows,bind,P:Pm,Praw,HT:Pm\/(1+t)};\n    }\n    const P=num('px-P');\n    if (!(P>0)) return {err:'Enter the retail price you are targeting.'};\n    const cs=keys.map(k=>chParams(k,L1,t,P)); const e=check(cs); if (e) return {err:e};\n    const lims=cs.map(c=>{ const R=P\/(1+t)*(1-c.r)*(1-c.d); return {Amax:R*(1-c.f-c.mp-g)-c.L, Aceil:R*(1-c.f-c.mp-Math.max(g-0.1,0))-c.L}; });\n    const pool=poolOf(cs,i=>lims[i].Amax>0);\n    if (!pool.length) return {err:`At this price, distribution and your costs absorb everything${multi?' in all your channels':''}. Raise the target price or lower the target margin.`};\n    let bind=pool[0]; pool.forEach(i=>{ if(lims[i].Amax<lims[bind].Amax) bind=i; });\n    const quote=num('px-quote'), A = quote>0 ? quote : lims[bind].Amax;\n    const rows=cs.map((c,i)=>Object.assign(at(c,P,A,t),lims[i],{Aopen:lims[i].Amax*0.85,impossible:lims[i].Amax<=0}));\n    const b=rows[bind];\n    return {mode:'buy',t,g,A,multi,rows,bind,P,HT:P\/(1+t),quote,Amax:b.Amax,Aceil:b.Aceil,Aopen:b.Amax*0.85,gFloor:Math.max(g-0.1,0),impossible:rows.filter(r=>r.impossible).map(r=>r.name)};\n  }\n\n  const icon = n => `<svg class=\"ico\"><use href=\"#i-${n}\"\/><\/svg>`;\n  function setStatus(el,tone,html){ el.dataset.tone=tone; el.innerHTML=icon(tone==='good'?'check':tone==='bad'?'x':'alert')+`<span>${html}<\/span>`; el.hidden=false; }\n\n  \/* ---------- parcours ---------- *\/\n  const reduced = () => matchMedia('(prefers-reduced-motion: reduce)').matches;\n  function stepValid(n){\n    if (n===4){ const ok=state.channels.length>0; $('px-step4-msg').hidden=ok; return ok; }\n    if (n!==2) return true;\n    const okP = state.mode==='sell' ? num('px-A')>0 : num('px-P')>0;\n    $(state.mode==='sell'?'px-A-box':'px-P-box').classList.toggle('bad',!okP);\n    const msg=$('px-step2-msg');\n    msg.hidden = okP;\n    msg.textContent = state.mode==='sell'?'Enter the unit price from your quote.':'Enter the retail price you are targeting.';\n    return okP;\n  }\n  function go(n){\n    if (n===state.step) return;\n    if (n>state.step) for (let i=state.step;i<n;i++) if(!stepValid(i)) { n=i; break; }\n    if (n===state.step) return;\n    const dir = n>state.step ? 'in-r' : 'in-l';\n    state.step=n; state.reached=Math.max(state.reached,n);\n    document.querySelectorAll('.px-step').forEach(s=>{\n      const on = Number(s.dataset.step)===n; s.hidden=!on; s.classList.remove('in-r','in-l');\n      if (on){ void s.offsetWidth; s.classList.add(dir); }\n    });\n    renderNav();\n    if (!state.revealed){ if (n===5) reveal(); else renderWait(); }\n    const h=document.querySelector(`.px-step[data-step=\"${n}\"] h2:not([hidden])`);\n    if (h) h.focus({preventScroll:true});\n    const flow=document.querySelector('.px-flow');\n    if (flow.getBoundingClientRect().top<0) flow.scrollIntoView({behavior:reduced()?'auto':'smooth',block:'start'});\n  }\n  function renderCount(){ const n=state.channels.length; $('px-chcount').textContent = `${n} channel${n>1?'s':''} selected`; }\n  function renderNav(){\n    [...$('px-prog').children].forEach(b=>{ const i=Number(b.dataset.step);\n      b.classList.toggle('cur',i===state.step); b.classList.toggle('done',i<state.step);\n      b.disabled = i>state.reached; if(i===state.step) b.setAttribute('aria-current','step'); else b.removeAttribute('aria-current'); });\n    $('px-back').disabled = state.step===1;\n    $('px-count').textContent=`Step ${state.step} of 5`;\n    $('px-next').firstChild.textContent = state.step===5 ? (state.revealed?'See the analysis':'See my result') : 'Continue';\n  }\n\n  \/* ---------- affichage ---------- *\/\n  function chipsFor(el,label){\n    const cs=sel();\n    el.hidden = cs.length<2;\n    el.innerHTML = cs.map(c=>`<button type=\"button\" class=\"px-pill\" data-k=\"${c.k}\" aria-pressed=\"${c.k===state.edit}\">${c.short}<\/button>`).join('');\n    el.setAttribute('aria-label',label);\n  }\n  function recap(){\n    if ($('px-recap').hidden) return;\n    const x=posOf(), cs=sel();\n    const chs = cs.length<=2 ? cs.map(c=>c.short).join(' + ') : `${cs[0].short} + ${cs.length-1} channels`;\n    const items=[\n      [state.mode==='sell'?`Quote ${isFinite(num('px-A'))?money(num('px-A'),2):'?'}`:`Target price ${isFinite(num('px-P'))?money(num('px-P')):'?'}`,2],\n      [plain(x.name),3],[chs,4],[MARKETS[state.market].name,2],[`Margin ${Math.round(state.g*100)}%`,5]];\n    $('px-recap').innerHTML=items.map(([l,s])=>`<button type=\"button\" class=\"px-tok\" data-step=\"${s}\" aria-label=\"Edit: ${l}\">${l}<\/button>`).join('');\n  }\n\n  let last=null;\n  \/\/ carte en attente tant que les cinq \u00e9tapes ne sont pas parcourues\n  function renderWait(){\n    const x=posOf(), A=num('px-A'), P=num('px-P');\n    const vals=[\n      state.mode==='sell'?'My selling price':'My maximum purchase price',\n      `${state.mode==='sell'?(A>0?'Quote '+money(A,2):''):(P>0?'Target price '+money(P):'')} \u00b7 ${MARKETS[state.market].name}`,\n      plain(x.name),\n      sel().map(c=>c.short).join(' + '),\n      `${Math.round(state.g*100)}%`];\n    $('px-wait-list').innerHTML=STEPS.map((l,i)=>{ const n=i+1, done=n<state.step, cur=n===state.step;\n      return `<li class=\"${done?'done':''}${cur?' cur':''}\"><span class=\"dot\"><svg viewBox=\"0 0 24 24\"><path d=\"M5 12.5l4.5 4.5L19 7.5\"\/><\/svg><\/span><span>${l}<\/span><em>${done?vals[i]:cur?'in progress':''}<\/em><\/li>`; }).join('');\n  }\n  const decOf = v => Math.abs(v)>=1000 ? 0 : (Math.abs(v-Math.round(v))<0.005 ? 0 : 2);\n  function bigHTML(v,dec){\n    const parts=new Intl.NumberFormat('en-US',{style:'currency',currency:cur(),currencyDisplay:'narrowSymbol',minimumFractionDigits:dec,maximumFractionDigits:dec}).formatToParts(v);\n    let int='',frac='',cu='';\n    parts.forEach(p=>{ if(p.type==='currency') cu=p.value; else if(p.type==='decimal'||p.type==='fraction') frac+=p.value; else if(p.type==='integer'||p.type==='group'||p.type==='minusSign') int+=p.value; });\n    return `<span class=\"cur\" style=\"margin:.55em .3em 0 0\">${cu}<\/span><span class=\"int\">${int}<\/span>${frac?`<span class=\"dec\">${frac}<\/span>`:''}`;\n  }\n  function countUp(el, target, dec){\n    if (reduced() || !isFinite(target)) { el.innerHTML=bigHTML(target,dec); return; }\n    const t0=performance.now(), D=900;\n    const tick=t=>{ const k=Math.min(1,(t-t0)\/D), e=1-Math.pow(1-k,3); el.innerHTML=bigHTML(k<1?target*e:target,dec); if(k<1) requestAnimationFrame(tick); };\n    requestAnimationFrame(tick);\n  }\n  function countUpOld(el, target, txt){\n    if (reduced() || !isFinite(target)) { el.textContent=txt; return; }\n    const dec = \/\\.\\d\/.test(txt) ? 2 : 0, t0=performance.now(), D=900;\n    const tick=t=>{ const k=Math.min(1,(t-t0)\/D), e=1-Math.pow(1-k,3); el.textContent = k<1 ? money(target*e,dec) : txt; if(k<1) requestAnimationFrame(tick); };\n    requestAnimationFrame(tick);\n  }\n  function reveal(){\n    state.revealed=true;\n    const card=$('px-answer'); card.classList.remove('is-locked'); renderNav(); $('px-actions').classList.remove('is-locked');\n    render();\n    card.classList.remove('px-reveal'); void card.offsetWidth; card.classList.add('px-reveal');\n    [...document.querySelectorAll('#px-bar .px-rseg')].forEach((s,i)=>s.style.setProperty('--d',i));\n    const big=$('px-big'); if (!big.hidden && last && !last.err) countUp(big, last.mode==='sell'?last.P:last.Amax, last.mode==='sell'?decOf(last.P):2);\n    $('px-reveal-live').textContent='Your result is ready.';\n    try{ (window.dataLayer=window.dataLayer||[]).push({event:'calculateur_resultat', calculateur_mode:state.mode, calculateur_canaux:state.channels.length}); }catch(e){}\n    setTimeout(()=>card.classList.remove('px-reveal'),1800);\n  }\n  function render(){\n    document.querySelectorAll('[data-show]').forEach(e=>e.hidden=e.dataset.show!==state.mode);\n    state.g=Number($('px-g-range').value)\/100;\n    if (!state.channels.includes(state.edit)) state.edit=state.channels[0];\n    chipsFor($('px-bd-ch'),'Channel shown'); if (state.mode==='sell') $('px-bd-ch').hidden=true;\n    recap();\n    const o=compute(); last=o;\n    refreshConsultation();\n    if (!state.revealed){ renderWait(); $('px-detail').hidden=true; $('px-dock').classList.add('hide'); }\n    updateHyp(o);\n    renderZone(o);\n    if (o.err){\n      $('px-err').hidden=false; $('px-err-t').textContent=o.err; $('px-ans').hidden=true; $('px-strat').hidden=true;\n      $('px-detail').hidden=true; $('px-dock-v').textContent='\u2026';\n      return;\n    }\n    $('px-err').hidden=true; $('px-ans').hidden=false; $('px-detail').hidden=!o.multi||!state.revealed;\n    const x=posOf(), sell=o.mode==='sell', b=o.rows[o.bind];\n    $('px-strat').hidden = true;   \/\/ un seul prix public, align\u00e9 sur tous les canaux\n    [...$('px-strat').children].forEach(btn=>btn.setAttribute('aria-pressed',String(btn.dataset.s===state.strategy)));\n    \/\/ carte r\u00e9sultat : uniquement le prix et la marge\n    const list=$('px-chlist'); list.hidden=true; $('px-big').hidden=false; $('px-figs').hidden=false;\n    $('px-ans-note').hidden=true; $('px-pos-line').hidden=true; $('px-figs').className='px-figs one';\n    const marginFig = (val, sub) => `<div><dt>Margin<\/dt><dd>${val}${sub?`<small>${sub}<\/small>`:''}<\/dd><\/div>`;\n    if (sell){\n      if (o.per){\n        $('px-ans-label').textContent='Recommended retail price by channel';\n        $('px-big').hidden=true; $('px-figs').hidden=true; list.hidden=false;\n        list.innerHTML=o.rows.map(r=>`<li><span>${r.name}<\/span><span><b>${money(r.P)}<\/b><small>margin ${pct(r.gReal)}<\/small><\/span><\/li>`).join('');\n        const ps=o.rows.map(r=>r.P);\n        $('px-dock-k').textContent='Recommended prices'; $('px-dock-v').textContent=`${money(Math.min(...ps))} to ${money(Math.max(...ps))}`;\n      } else {\n        $('px-ans-label').textContent= o.multi ? `Recommended retail price, aligned across your ${o.rows.length} channels` : 'Recommended retail price';\n        $('px-big').innerHTML=bigHTML(o.P,decOf(o.P));\n        if (o.multi){\n          \/\/ marge par canal au prix align\u00e9 ; chaque pastille choisit aussi le canal d\u00e9taill\u00e9 plus bas\n          $('px-figs').className='px-figs px-chm';\n          $('px-figs').innerHTML=`<dt>Margin by channel<\/dt><dd>${o.rows.map(r=>`<button type=\"button\" class=\"px-chm-i${r.k===state.edit?' on':''}${r.gReal<o.g-0.005?' low':''}\" data-k=\"${r.k}\" aria-pressed=\"${r.k===state.edit}\" title=\"${r.gReal<o.g-0.005?'Below your target margin at this price':'Target margin reached'}\"><span>${r.short}<\/span><b>${pct(r.gReal)}<\/b><\/button>`).join('')}<\/dd>`;\n        } else {\n          $('px-figs').innerHTML=marginFig(money(b.net,2),pct(b.gReal));\n        }\n        $('px-dock-k').textContent='Recommended retail price'; $('px-dock-v').textContent=money(o.P);\n      }\n    } else {\n      $('px-ans-label').textContent='Maximum purchase price';\n      $('px-big').innerHTML=bigHTML(o.Amax,2);\n      const imp = o.impossible.length ? ` \u00b7 ${o.impossible.join(', ')}: not possible at this price` : '';\n      $('px-figs').innerHTML = o.quote>0 ? marginFig(pct(b.gReal), 'with this quote'+imp) : marginFig(pct(o.g), (o.multi?'at minimum, across your channels':'')+imp);\n      $('px-nego').innerHTML=`<span>Open at <b>${money(o.Aopen,2)}<\/b><\/span><span>Ceiling <b>${money(o.Aceil,2)}<\/b><\/span>`;\n      $('px-nego').title=`Opening offer: 15% below the target price. Ceiling: your margin falls to ${pct(o.gFloor)}.`;\n      const qv=$('px-quote-v');\n      if (o.quote>0){\n        const where = o.multi ? ` in ${b.name}` : '';\n        if (o.quote<=o.Amax) setStatus(qv,'good',o.multi?'Within your target, in all your channels.':'Within your target.');\n        else if (o.quote<=o.Aceil) setStatus(qv,'warn',`Workable: renegotiate${where}.`);\n        else setStatus(qv,'bad',`Over budget${where}.`);\n      } else qv.hidden=true;\n      $('px-dock-k').textContent='Maximum purchase price'; $('px-dock-v').textContent=money(o.Amax,2);\n    }\n\n    \/\/ positionnement : une ligne d'\u00e9tat et une ligne de contexte (prix en rayon, sinon marge habituelle)\n    const Aref = sell ? o.A : (o.quote>0?o.quote:o.Amax), K=o.HT\/Aref, nm=plain(x.name).toLowerCase();\n    const nf0=new Intl.NumberFormat('en-US',{maximumFractionDigits:0}), nf2=new Intl.NumberFormat('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});\n    const rng=(a,z,d2)=> `${money(a,d2?2:0)} to ${money(z,d2?2:0)}`;\n    const mb=shelfBand(x.k), shelf = mb ? `Shelf prices ${mb.where}: ${rng(mb.lo,mb.hi)}` : '';\n    const aLo = mb ? mb.lo\/(x.hi*(1+o.t)) : 0, aHi = mb ? mb.hi\/(x.lo*(1+o.t)) : 0;\n    let tone, short, long;\n    if (sell){\n      const coef = `Usual range for this segment: ${rng(o.A*x.lo*(1+o.t),o.A*x.hi*(1+o.t))}`;\n      if (mb && o.P<mb.lo*0.9){ tone='warn'; short=`Low price for a ${nm} product`; long=`${shelf}. These brands buy their product at ${rng(aLo,aHi)} excl. VAT.`; }\n      else if (mb && o.P>mb.hi*1.1){ tone='warn'; short=`Above the market`; long=`${shelf}.`; }\n      else if (K<x.lo){ tone='warn'; short=`Tight margin for a ${nm} product`; long=`${coef}.`; }\n      else if (K>x.hi){ tone='warn'; short=`High price for a ${nm} product`; long=`${coef}.`; }\n      else { tone='good'; short=`In line with ${nm} pricing`; long= mb ? `${shelf}.` : `${coef}.`; }\n    } else {\n      const lo=o.HT\/x.hi, hi=o.HT\/x.lo, buyTxt=`Usual purchase price at this retail price: ${rng(lo,hi,1)} excl. VAT`;\n      if (mb && (o.P<mb.lo*0.9 || o.P>mb.hi*1.1)){ tone='warn'; short = o.P<mb.lo*0.9 ? `Low target price for a ${nm} product` : `Target price above the market`; long=`${shelf}.`; }\n      else if (o.quote>0){\n        if (Aref>hi){ tone='warn'; short=`High quote for a ${nm} product`; long=`${buyTxt}.`; }\n        else if (Aref<lo){ tone='good'; short=`Low quote for a ${nm} product`; long=`${buyTxt}. Check the quality.`; }\n        else { tone='good'; short=`Quote in line with ${nm} pricing`; long=`${buyTxt}.`; }\n      }\n      else if (Aref<lo){ tone='warn'; short=`Tight purchase budget`; long=`${buyTxt}.`; }\n      else if (Aref>hi){ tone='good'; short=`Comfortable purchase budget`; long=`${buyTxt}.`; }\n      else { tone='good'; short=`In line with ${nm} pricing`; long=`${buyTxt}.`; }\n    }\n    $('px-verdict').innerHTML=`<p class=\"tag\" data-tone=\"${tone}\">${icon(tone==='good'?'check':'alert')}${short}<\/p><p>${long}<\/p>`;\n    renderScale(K,tone);\n    renderBreakdown(o.rows.find(r=>r.k===state.edit)||b, o.multi);\n    renderMulti(o);\n    clearTimeout(render.t); render.t=setTimeout(()=>{ $('px-live').textContent=`${$('px-ans-label').textContent} : ${$('px-dock-v').textContent}`; },700);\n  }\n\n  const ZONES=[{a:0,b:1.5,l:'Too tight'},{a:1.5,b:3,l:'Discount',k:'hd'},{a:3,b:5,l:'Mass',k:'mass'},{a:5,b:7,l:'Premium',k:'hdg'},{a:7,b:10,l:'Luxury',k:'lux'}];\n  function renderScale(k,tone){\n    \/\/ \u00e9chelle de positionnement : paliers de m\u00eame largeur (le premier plus \u00e9troit), rep\u00e8re \u00ab Votre prix \u00bb interpol\u00e9 dans son palier\n    const W=ZONES.map((z,i)=>i===0?0.6:1), tot=W.reduce((a,b)=>a+b,0);\n    let i=ZONES.findIndex(z=>k<z.b), pos;\n    if (i<0) pos=100; else { const before=W.slice(0,i).reduce((a,b)=>a+b,0), frac=(Math.max(k,0)-ZONES[i].a)\/(ZONES[i].b-ZONES[i].a); pos=(before+frac*W[i])\/tot*100; }\n    pos=Math.min(97,Math.max(3,pos));\n    const el=$('px-scale');\n    if (!el.firstChild){ el.innerHTML=`<div class=\"px-lad-pin\" aria-hidden=\"true\"><b>Your price<\/b><i><\/i><\/div><div class=\"px-lad-track\" aria-hidden=\"true\">${ZONES.map(()=>'<span><\/span>').join('')}<\/div><div class=\"px-lad-labels\" aria-hidden=\"true\">${ZONES.map(z=>`<span>${z.l}<\/span>`).join('')}<\/div>`; }\n    const pin=el.querySelector('.px-lad-pin'); pin.style.left=pos+'%'; pin.dataset.tone=tone;\n    pin.querySelector('b').textContent = state.mode==='sell' ? 'Your price' : (num('px-quote')>0 ? 'Your quote' : 'Your purchase price');\n    [...el.querySelectorAll('.px-lad-track span')].forEach((sp,j)=>sp.classList.toggle('sel',ZONES[j].k===state.pos));\n    [...el.querySelectorAll('.px-lad-labels span')].forEach((sp,j)=>sp.classList.toggle('sel',ZONES[j].k===state.pos));\n  }\n\n  function renderBreakdown(o, multi){\n    $('px-a-total').textContent = multi ? o.name : '';\n    const rows=[\n      {g:0,l:'Manufacturer purchase price',v:o.A},{g:0,l:'Logistics',v:o.L},\n      {g:1,l:'Advertising and influencers',v:o.m*o.R},{g:1,l:'Promotion',v:o.pr*o.R},\n      {g:2,l:'Brand margin',v:o.net},\n      {g:3,l:'Commissions and discounts',v:o.f*o.R},{g:3,l:'Distributor margin',v:o.W-o.R},{g:3,l:'Retailer margin',v:o.HT-o.W},\n      {g:4,l:'VAT',v:o.P-o.HT}\n    ];\n    const G=[{l:'Manufacturing',c:'var(--k-fab)'},{l:'Marketing',c:'var(--k-mkt)'},{l:'Your margin',c:'var(--k-marge)',you:1},{l:'Distribution',c:'var(--k-canal)'},{l:'Taxes',c:'var(--k-tva)'}];\n    const gv=[0,0,0,0,0]; rows.forEach(r=>gv[r.g]+=r.v);\n    const bar=$('px-bar'); bar.innerHTML='';\n    const tip=document.createElement('div'); tip.className='px-tip'; tip.hidden=true;\n    gv.forEach((v,i)=>{\n      if (v<=0.0001) return;\n      const share=v\/o.P, s=document.createElement('div'); s.className='px-rseg'+(G[i].you?' is-you':''); s.tabIndex=0;\n      s.style.cssText=`flex:${v} 1 0;--c:${G[i].c}`;\n      s.textContent = share>=0.1 ? pct(share).replace(\/\\.\\d\/,'') : '';   \/\/ \u00e9tiquette directe sur les segments assez larges\n      s.setAttribute('aria-label',`${G[i].l}: ${money(v,2)}, ${pct(share)}`);\n      const show=()=>{ tip.innerHTML=`${G[i].l} \u00b7 ${money(v,2)} \u00b7 ${pct(share)}`; tip.hidden=false; const bb=bar.getBoundingClientRect(), sb=s.getBoundingClientRect(); tip.style.left=Math.max(80,Math.min(bb.width-80,sb.left+sb.width\/2-bb.left))+'px'; };\n      s.addEventListener('mouseenter',show); s.addEventListener('focus',show);\n      s.addEventListener('mouseleave',()=>tip.hidden=true); s.addEventListener('blur',()=>tip.hidden=true);\n      bar.appendChild(s);\n    });\n    bar.appendChild(tip);\n    bar.setAttribute('aria-label','Retail price breakdown: '+G.map((g,i)=>`${g.l} ${pct(gv[i]\/o.P)}`).join(', '));\n    $('px-legend').innerHTML=G.map((g,i)=>g.you?'':`<li class=\"${g.you?'is-you':''}${gv[i]<0?' neg':''}\" style=\"--c:${g.c}\"><span>${g.l}<\/span><b>${money(gv[i],decOf(gv[i])||2)}<\/b><\/li>`).join('');\n    \/\/ (le d\u00e9tail ligne par ligne vit dans \u00ab V\u00e9rifier nos hypoth\u00e8ses \u00bb)\n  }\n\n  function renderMulti(o){\n    const box=$('px-multi'); box.hidden=!o.multi;\n    if (!o.multi) return;\n    const tag = i => i===o.bind ? '<small>most demanding<\/small>' : '';\n    if (o.mode==='sell'){\n      $('px-ct-head').innerHTML=`<tr><th>Channel<\/th><th>Recommended price for this channel alone<\/th><th>Aligned price<\/th><th>You invoice (excl. VAT)<\/th><th>Your margin<\/th><\/tr>`;\n      $('px-ct-body').innerHTML=o.rows.map((r,i)=>`<tr class=\"${i===o.bind?'cur':''}\"><td>${r.name}${tag(i)}<\/td><td>${money(r.Pr)}<\/td><td>${money(r.P)}<\/td><td>${money(r.R,2)}<\/td><td class=\"${r.gReal>=o.g-1e-6?'gain':''}\">${pct(r.gReal)}<\/td><\/tr>`).join('');\n      $('px-ct-foot').textContent = o.per\n        ? 'A price per channel keeps the same margin everywhere, but your retailers will see the gaps. Keep gaps small between channels visible to the same customer.'\n        : `A single price protects your retailers and your image. It is set by the most demanding resale channel.${o.rows.some(r=>r.online&&r.gReal<o.g-0.005)?' Online, the margin is lower at this price because of delivery: have customers pay part of the shipping or accept this margin.':''}`;\n    } else {\n      $('px-ct-head').innerHTML=`<tr><th>Channel<\/th><th>Maximum purchase price<\/th><th>You invoice (excl. VAT)<\/th><th>${o.quote>0?'Margin with this quote':'Margin at target price'}<\/th><\/tr>`;\n      $('px-ct-body').innerHTML=o.rows.map((r,i)=>`<tr class=\"${i===o.bind?'cur':''}\"><td>${r.name}${tag(i)}<\/td><td>${r.impossible?'Not possible at this price':money(r.Amax,2)}<\/td><td>${money(r.R,2)}<\/td><td class=\"${r.gReal>=o.g-1e-6?'gain':''}\">${pct(r.gReal)}<\/td><\/tr>`).join('');\n      $('px-ct-foot').textContent='Your purchase price must fit the most demanding channel. If a channel costs too much, you can sell higher there or drop it.';\n    }\n  }\n\n  const SRC_GROUPS=[\n    {t:'Brand and retailer margins',ids:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]},\n    {t:'Marketing and promotion',ids:[18,19,20,21,22,23]},\n    {t:'Commissions and payments',ids:[16,17,24]},\n    {t:'Delivery and logistics',ids:[25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41]},\n    {t:'Shelf prices, October 2026 survey',ids:[42,43,44,45,46,47]}];\n  const cite = ids => `<span class=\"px-cites\">${ids.map(n=>`<a class=\"px-cite\" href=\"#px-src-${n}\" title=\"${(BENCH.sources[n-1]||{}).t||''}\">${n}<\/a>`).join('')}<\/span>`;\n  function renderBench(){\n    if (!BENCH.rows.length){ $('px-bench').hidden=true; return; }\n    const S=BENCH.sources, x=v=>Math.max(0,Math.min(100,(v-1)\/9*100));\n    $('px-stat-n').textContent=S.length; $('px-srcs-n').textContent=S.length;\n    $('px-bench-intro').textContent=BENCH.intro;\n    $('px-bench-rows').innerHTML=BENCH.rows.map((r,i)=>{ const p=POS[i]||{lo:1,hi:2};\n      return `<li class=\"px-coef-row\" style=\"--lv:${i}\"><b class=\"px-coef-n\">${r.pos}<\/b><div class=\"px-track\" role=\"img\" aria-label=\"${r.pos}: coefficient ${r.k}\"><span style=\"left:${x(p.lo)}%;width:${x(p.hi)-x(p.lo)}%\"><\/span><\/div><span class=\"px-coef-k\">${r.k}<\/span><p class=\"px-coef-why\">${r.why} ${cite(r.src)}<\/p><\/li>`; }).join('');\n    $('px-bench-notes').innerHTML=BENCH.notes.map(n=>{\n      let k=n.t.indexOf(' : '), title=n.t.slice(0,k), body=n.t.slice(k+3), m=title.match(\/^(.*?)\\s*\\((.*)\\)$\/);\n      if (m){ title=m[1]; body=m[2].charAt(0).toUpperCase()+m[2].slice(1)+'. '+body.charAt(0).toUpperCase()+body.slice(1); }\n      else body=body.charAt(0).toUpperCase()+body.slice(1);\n      return `<article class=\"px-bnote${\/^Limits\/.test(title)?' is-limit':''}\"><h3>${title}<\/h3><p>${body}<\/p>${n.src.length?cite(n.src):''}<\/article>`; }).join('');\n    $('px-sources').innerHTML=SRC_GROUPS.map(g=>`<section class=\"px-src-g\"><h4>${g.t}<\/h4><ul>${g.ids.map(n=>{ const s=S[n-1]; if(!s) return '';\n      return `<li id=\"px-src-${n}\"><span class=\"px-src-i\">${n}<\/span><span class=\"px-src-t\">${s.t}<a href=\"${s.u}\" target=\"_blank\" rel=\"noopener nofollow\">${s.u.replace(\/^https?:\\\/\\\/\/,'').replace(\/\\\/.*$\/,'').replace(\/^www\\.\/,'')}<svg class=\"ico\"><use href=\"#i-arrow\"\/><\/svg><\/a><\/span><\/li>`; }).join('')}<\/ul><\/section>`).join('');\n  }\n  \/\/ une citation ouvre la liste des sources et met la ligne en \u00e9vidence\n  document.addEventListener('click',e=>{\n    const a=e.target.closest('a[href^=\"#px-src\"]'); if(!a) return;\n    const det=$('px-srcs'); if(!det) return; e.preventDefault(); det.open=true;\n    const id=a.getAttribute('href').slice(1), el=$(id==='px-srcs'?'px-srcs':id); if(!el) return;\n    el.scrollIntoView({behavior:reduced()?'auto':'smooth',block:id==='px-srcs'?'start':'center'});\n    if(id!=='px-srcs'){ el.classList.remove('is-hit'); void el.offsetWidth; el.classList.add('is-hit'); }\n  });\n\n\n  function summary(){\n    const o=last; if(!o||o.err) return '';\n    const x=posOf();\n    const lines=['Cosmetic price calculator (Carmel Cosmetics Labs)',\n      `${plain(x.name)} \u00b7 ${MARKETS[state.market].name} \u00b7 target margin ${pct(o.g)}`];\n    if (o.mode==='sell'){\n      lines.push(`Purchase price: ${money(o.A,2)} excl. VAT`);\n      if (o.multi && !o.per) lines.push(`Recommended single retail price: ${money(o.P,2)} incl. VAT`);\n      o.rows.forEach(r=>lines.push(`${r.name}: ${money(r.P,2)} incl. VAT, you invoice ${money(r.R,2)} excl. VAT, margin ${pct(r.gReal)}`));\n    } else {\n      lines.push(`Target retail price: ${money(o.P,2)} incl. VAT`,`Target purchase price: ${money(o.Amax,2)} excl. VAT (opening ${money(o.Aopen,2)}, ceiling ${money(o.Aceil,2)})`);\n      if (o.multi) o.rows.forEach(r=>lines.push(`${r.name}: maximum purchase price ${money(r.Amax,2)} excl. VAT`));\n      if (o.quote>0) lines.push(`Quote tested: ${money(o.quote,2)}`);\n    }\n    lines.push('Indicative price, to be checked with your own research (competition, retailer terms, quotes).','https:\/\/carmelcosmeticslabs.com\/en\/');\n    return lines.join('\\n');\n  }\n\n  \/* ---------- consultation WPForms native 56741 ---------- *\/\n  \/\/ No PII is read by this integration or sent to analytics\/storage\/URLs.\n  const consultation = {form:null,attach:null,snapshot:null,trigger:null,observer:null,timer:null};\n  function consultationSnapshot(){\n    const result=summary();\n    if(!state.revealed || !result) return '';\n    const lines=[result,'','Current assumptions (indicative)',\n      `Currency: ${cur()} \u00b7 VAT: ${fmt(state.vat,1)}% \u00b7 target margin: ${pct(state.g)}`,\n      `Transport and customs per product: ${money(state.L1,2)} excl. VAT \u00b7 psychological rounding: ${$('px-round').checked?'yes':'no'}`,\n      `Strategy: ${state.strategy==='per'?'price by channel':'single retail price'}`];\n    if(state.market==='us') lines.push('United States: retail price excluding sales tax (VAT in the calculation: 0%).');\n    state.channels.forEach(k=>{\n      const v=cv[k],r=last.rows.find(row=>row.k===k);\n      lines.push(`${CH[k].short}: retailer ${fmt(v.r,1)}%, distributor ${fmt(v.d,1)}%, commissions\/discounts entered ${fmt(v.f,1)}%${r?', effective '+pct(r.f)+' of the brand\u2019s revenue excl. VAT':''}, advertising ${fmt(v.m,1)}%, promotion ${fmt(v.p,1)}%, delivery ${money(v.L2,2)} excl. VAT\/product.`);\n    });\n    return lines.join('\\n');\n  }\n  function refreshConsultation(){\n    if(!consultation.attach || !consultation.snapshot || successCounted) return;\n    const attached=consultation.attach.checked, text=attached?consultationSnapshot():'';\n    consultation.snapshot.value=text;\n    $('px-consult-simulation').hidden=!attached;\n    $('px-consult-summary').textContent=attached?(text||'Complete the five steps with valid values to attach your simulation.'):'';\n    if(!attached) $('px-consult-simulation').open=false;\n  }\n  function consultationEvent(event, extra){\n    try{(window.dataLayer=window.dataLayer||[]).push(Object.assign({event},extra||{}));}catch(_){}\n  }\n  function openConsultation(trigger){\n    consultation.trigger=trigger;\n    $('px-consultation').hidden=false;\n    $('px-dock').hidden=true;\n    document.querySelectorAll('[data-consult-placement]').forEach(b=>b.setAttribute('aria-expanded','true'));\n    refreshConsultation();\n    consultationEvent('calculateur_consultation_clic',{placement:trigger.dataset.consultPlacement});\n    $('px-consult-title').focus({preventScroll:true});\n    $('px-consultation').scrollIntoView({behavior:reduced()?'auto':'smooth',block:'start'});\n  }\n  function closeConsultation(){\n    $('px-consultation').hidden=true;\n    $('px-dock').hidden=false;\n    document.querySelectorAll('[data-consult-placement]').forEach(b=>b.setAttribute('aria-expanded','false'));\n    if(consultation.trigger) consultation.trigger.focus({preventScroll:true});\n  }\n  document.querySelectorAll('[data-consult-placement]').forEach(b=>b.addEventListener('click',()=>openConsultation(b)));\n  $('px-consult-close').addEventListener('click',closeConsultation);\n  $('px-consultation').addEventListener('keydown',e=>{if(e.key==='Escape'){e.preventDefault();closeConsultation();}});\n  \/\/ Capture phase runs before WPForms' own validation\/AJAX serialization.\n  document.addEventListener('submit',e=>{if(e.target===consultation.form) refreshConsultation();},true);\n  let successBound=false,successCounted=false;\n  function bindConsultationSuccess(){\n    if(successBound || !window.jQuery) return;\n    successBound=true;\n    window.jQuery(document).on('wpformsAjaxSubmitSuccess.cmPx56741',(event,response)=>{\n      \/\/ Verified WPForms contract: triggered on the form, response is the sole extra argument.\n      const nativeForm=event.target && event.target.closest && event.target.closest('form');\n      if(nativeForm!==consultation.form || !nativeForm || nativeForm.id!=='wpforms-form-56741') return;\n      if(!response || response.success!==true) return;\n      if(successCounted) return;\n      successCounted=true;\n      $('px-consult-simulation').hidden=true;\n      $('px-consult-summary').textContent='';\n      \/\/ Native confirmation is left intact: acceptance is not proof of email\/CRM delivery.\n      consultationEvent('calculateur_demande_envoyee');\n    });\n  }\n  function mountConsultationForm(){\n    bindConsultationSuccess();\n    if(consultation.form) return true;\n    const source=document.querySelector('.cm-calculator-form-source');\n    const form=source && source.querySelector('#wpforms-form-56741');\n    if(!form) return false;\n    const attach=form.querySelector('#wpforms-56741-field_5_1');\n    const snapshot=form.querySelector('#wpforms-56741-field_6');\n    const wrapper=form.closest('.wpforms-container');\n    if(!attach || !snapshot || !wrapper || !source.contains(wrapper)) return false;\n    \/\/ Move only the native wrapper once; the hidden Elementor source stays in place.\n    \/\/ Retain listeners, security fields and nonce. No clone, innerHTML or new form.\n    consultation.form=form;consultation.attach=attach;consultation.snapshot=snapshot;\n    snapshot.required=false;\n    const field=snapshot.closest('.wpforms-field');if(field) field.hidden=true;\n    $('px-consult-form-host').appendChild(wrapper);\n    $('px-consult-fallback').hidden=true;\n    attach.addEventListener('change',refreshConsultation);\n    [['1','off'],['2','name'],['3','email'],['4','tel']].forEach(([id,autocomplete])=>{\n      const input=form.querySelector('#wpforms-56741-field_'+id);if(input) input.setAttribute('autocomplete',autocomplete);\n    });\n    refreshConsultation();\n    if(consultation.observer) consultation.observer.disconnect();\n    clearTimeout(consultation.timer);\n    return true;\n  }\n  function initConsultationForm(){\n    if(mountConsultationForm()) return;\n    \/\/ Wait for Elementor's deferred widget, but never watch the page forever.\n    consultation.observer=new MutationObserver(()=>mountConsultationForm());\n    consultation.observer.observe($('px-root').closest('.elementor')||document.body,{childList:true,subtree:true});\n    consultation.timer=setTimeout(()=>{\n      consultation.observer.disconnect();\n      mountConsultationForm();\n      \/\/ Missing\/invalid native markup leaves the honest contact-link fallback visible.\n    },20000);\n  }\n\n  \/* ---------- \u00e9v\u00e9nements ---------- *\/\n  document.querySelectorAll('input[name=\"px-mode\"]').forEach(i=>i.addEventListener('change',e=>{state.mode=e.target.value;snapMargin();render();}));\n  $('px-pos').addEventListener('change',e=>{state.pos=e.target.value;applyMix();buildHyp();snapMargin();render();});\n  $('px-channels').addEventListener('change',e=>{\n    const k=e.target.value;\n    if (e.target.checked){ if(!cv[k]) initChannel(k); state.channels.push(k); state.edit=k; }\n    else if (state.channels.length===1){ e.target.checked=true; $('px-step4-msg').hidden=false; return; }\n    else { state.channels=state.channels.filter(x=>x!==k); }\n    $('px-step4-msg').hidden=true;\n    renderCount(); buildHyp(); snapMargin(); render();\n  });\n  \/\/ aucune \u00e9tape n'avance seule : l'utilisateur choisit, puis clique sur Continuer\n  $('px-market').addEventListener('change',e=>{applyMarket(e.target.value);buildHyp();render();});\n  [['px-A','A'],['px-P','P'],['px-quote','quote']].forEach(([id,key])=>$(id).addEventListener('input',()=>{ const v=num(id); state.base[key]= v>0 ? v\/MARKETS[state.market].rate : null; if(!$('px-step2-msg').hidden) stepValid(2); render(); }));\n  $('px-hyp').addEventListener('input',e=>{\n    const el=e.target, id=el.dataset.id; if(!id) return;\n    if (el.type==='range'){ const v=Number(el.value); setV(state.edit,id,v); const t=el.parentNode.querySelector('input[type=text]'); t.value=fmt(v,Number(t.dataset.dec)); }\n    else { const v=parseFloat(el.value.replace(\/\\s\/g,'').replace(',','.')); setV(state.edit,id,isFinite(v)?v:NaN); if(isFinite(v)){ const r=el.closest('.px-h-c').querySelector('input[type=range]'); if(v>Number(r.max)) r.max=Math.ceil(v); r.value=v; } }\n    render();\n  });\n  $('px-hyp').addEventListener('click',e=>{ const h=e.target.closest('.px-r-head'); if(h) toggleRow(h.parentNode.dataset.row); });\n  $('px-reset').addEventListener('click',()=>{ initChannel(state.edit); state.vat=MARKETS[state.market].vat; buildHyp(); render(); });\n  $('px-showall').addEventListener('click',()=>{ state.showAll=!state.showAll; buildHyp(); render(); });\n  const pickEdit = e => { const b=e.target.closest('[data-k]'); if(!b) return; state.edit=b.dataset.k; buildHyp(); render(); };\n  $('px-edit').addEventListener('click',pickEdit);\n  $('px-bd-ch').addEventListener('click',pickEdit);\n  $('px-figs').addEventListener('click',pickEdit);\n  $('px-strat').addEventListener('click',e=>{ const b=e.target.closest('[data-s]'); if(!b) return; state.strategy=b.dataset.s; render(); });\n  $('px-g-range').addEventListener('input',e=>{state.gTouched=true;setMargin(e.target.value);render();});\n  $('px-round').addEventListener('change',render);\n  $('px-next').addEventListener('click',()=>{ if(state.step<5) go(state.step+1); else { $('px-answer').scrollIntoView({behavior:reduced()?'auto':'smooth',block:'start'}); } });\n  $('px-back').addEventListener('click',()=>go(state.step-1));\n  $('px-prog').addEventListener('click',e=>{ const b=e.target.closest('[data-step]'); if(b&&!b.disabled) go(Number(b.dataset.step)); });\n  $('px-recap').addEventListener('click',e=>{ const b=e.target.closest('[data-step]'); if(!b) return; state.reached=5; go(Number(b.dataset.step)); if(innerWidth<=960) document.querySelector('.px-flow').scrollIntoView({behavior:reduced()?'auto':'smooth',block:'start'}); });\n  $('px-form').addEventListener('keydown',e=>{ if(e.key==='Enter' && e.target.tagName==='INPUT' && e.target.type!=='radio' && e.target.type!=='checkbox'){ e.preventDefault(); $('px-next').click(); } });\n  $('px-copy').addEventListener('click',async()=>{\n    const txt=summary(), lab=$('px-copy').querySelector('span');\n    try{ await navigator.clipboard.writeText(txt); lab.textContent='Copied'; }\n    catch(e){ const ta=document.createElement('textarea'); ta.value=txt; ta.style.cssText='position:fixed;opacity:0'; document.body.appendChild(ta); ta.select(); try{document.execCommand('copy'); lab.textContent='Copied';}catch(_){lab.textContent='Copy failed';} ta.remove(); }\n    setTimeout(()=>lab.textContent='Copy',2200);\n  });\n\n  const dock=$('px-dock');\n  if ('IntersectionObserver' in window) new IntersectionObserver(es=>es.forEach(en=>dock.classList.toggle('hide',en.isIntersecting||!state.revealed)),{threshold:0.2}).observe($('px-answer'));\n\n  state.L1=Math.round(state.L1e*MARKETS[state.market].rate*10)\/10;\n  initChannel('pha');\n  setMargin(posOf().g);\n  buildHyp();\n  snapMargin();\n  renderNav();\n  renderCount();\n  renderBench();\n  render();\n  if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',initConsultationForm,{once:true});\n  else initConsultationForm();\n})();\n<\/script>\n<\/div><script>document.querySelectorAll('[data-s]').forEach(function(e){e.setAttribute('data-s',(e.getAttribute('data-s')+' '+e.textContent).toLowerCase())});<\/script>\t\t\t\t<\/div>\n\t\t<div data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-element elementor-element-eeb85036 e-flex e-con-full cm-calculator-form-source e-con e-child\" data-id=\"eeb85036\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a38db15 cm-calculator-wpform eael-wpforms-labels-yes eael-wpforms-form-button-custom elementor-widget elementor-widget-eael-wpforms\" data-id=\"7a38db15\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"eael-wpforms.default\">\n\t\t\t\t\t            <div class=\"eael-contact-form eael-wpforms eael-wpforms-align-default\">\n                                <div class=\"wpforms-container wpforms-container-full cm-calculator-wpform wpforms-render-modern\" id=\"wpforms-56741\"><form id=\"wpforms-form-56741\" class=\"wpforms-validate wpforms-form wpforms-ajax-form\" data-formid=\"56741\" method=\"post\" enctype=\"multipart\/form-data\" action=\"\/en\/wp-json\/wp\/v2\/pages\/56762\" data-token=\"c249fa53b4ae321399f6cf17415786d1\" data-token-time=\"1794193640\"><div class=\"wpforms-head-container\"><div class=\"wpforms-title\">Price calculator \u2013 EN<\/div><div class=\"wpforms-description\">Your simulation will help us understand your price target.<\/div><\/div><noscript class=\"wpforms-error-noscript\">Please enable JavaScript in your browser to complete this form.<\/noscript><div id=\"wpforms-error-noscript\" style=\"display: none;\">Please enable JavaScript in your browser to complete this form.<\/div><div class=\"wpforms-field-container\"><div id=\"wpforms-56741-field_1-container\" class=\"wpforms-field wpforms-field-text\" data-field-type=\"text\" data-field-id=\"1\"><label class=\"wpforms-field-label\" for=\"wpforms-56741-field_1\">Intended product <span class=\"wpforms-required-label\" aria-hidden=\"true\">*<\/span><\/label><input type=\"text\" id=\"wpforms-56741-field_1\" class=\"wpforms-field-large wpforms-field-required\" name=\"wpforms[fields][1]\" placeholder=\"Ex. : s\u00e9rum visage\" aria-errormessage=\"wpforms-56741-field_1-error\" required><\/div><div id=\"wpforms-56741-field_2-container\" class=\"wpforms-field wpforms-field-text\" data-field-type=\"text\" data-field-id=\"2\"><label class=\"wpforms-field-label\" for=\"wpforms-56741-field_2\">Name <span class=\"wpforms-required-label\" aria-hidden=\"true\">*<\/span><\/label><input type=\"text\" id=\"wpforms-56741-field_2\" class=\"wpforms-field-large wpforms-field-required\" name=\"wpforms[fields][2]\" aria-errormessage=\"wpforms-56741-field_2-error\" required><\/div><div id=\"wpforms-56741-field_3-container\" class=\"wpforms-field wpforms-field-email\" data-field-type=\"email\" data-field-id=\"3\"><label class=\"wpforms-field-label\" for=\"wpforms-56741-field_3\">Email <span class=\"wpforms-required-label\" aria-hidden=\"true\">*<\/span><\/label><input type=\"email\" id=\"wpforms-56741-field_3\" class=\"wpforms-field-large wpforms-field-required\" name=\"wpforms[fields][3]\" spellcheck=\"false\" aria-errormessage=\"wpforms-56741-field_3-error\" required><\/div><div id=\"wpforms-56741-field_4-container\" class=\"wpforms-field wpforms-field-text\" data-field-type=\"text\" data-field-id=\"4\"><label class=\"wpforms-field-label\" for=\"wpforms-56741-field_4\">Phone<\/label><input type=\"text\" id=\"wpforms-56741-field_4\" class=\"wpforms-field-large\" name=\"wpforms[fields][4]\" aria-errormessage=\"wpforms-56741-field_4-error\" aria-describedby=\"wpforms-56741-field_4-description\" ><div id=\"wpforms-56741-field_4-description\" class=\"wpforms-field-description\">Optional<\/div><\/div><div id=\"wpforms-56741-field_5-container\" class=\"wpforms-field wpforms-field-checkbox\" data-field-type=\"checkbox\" data-field-id=\"5\"><fieldset><legend class=\"wpforms-field-label wpforms-label-hide\" aria-hidden=\"false\">Simulation<\/legend><ul id=\"wpforms-56741-field_5\"><li class=\"choice-1 depth-1\"><input type=\"checkbox\" id=\"wpforms-56741-field_5_1\" name=\"wpforms[fields][5][]\" value=\"Attach my simulation\" aria-errormessage=\"wpforms-56741-field_5_1-error\"  ><label class=\"wpforms-field-label-inline\" for=\"wpforms-56741-field_5_1\">Attach my simulation<\/label><\/li><\/ul><\/fieldset><\/div><div id=\"wpforms-56741-field_6-container\" class=\"wpforms-field wpforms-field-textarea cm-calculator-simulation-field\" data-field-type=\"textarea\" data-field-id=\"6\"><label class=\"wpforms-field-label wpforms-label-hide\" for=\"wpforms-56741-field_6\" aria-hidden=\"false\">Cosmetic price simulation<\/label><textarea id=\"wpforms-56741-field_6\" class=\"wpforms-field-large\" name=\"wpforms[fields][6]\" aria-errormessage=\"wpforms-56741-field_6-error\" ><\/textarea><\/div><div id=\"wpforms-56741-field_7-container\" class=\"wpforms-field wpforms-field-hidden ccl-utm_source\" data-field-type=\"hidden\" data-field-id=\"7\"><input type=\"hidden\" id=\"wpforms-56741-field_7\" name=\"wpforms[fields][7]\"><\/div><div id=\"wpforms-56741-field_8-container\" class=\"wpforms-field wpforms-field-hidden ccl-utm_medium\" data-field-type=\"hidden\" data-field-id=\"8\"><input type=\"hidden\" id=\"wpforms-56741-field_8\" name=\"wpforms[fields][8]\"><\/div><div id=\"wpforms-56741-field_9-container\" class=\"wpforms-field wpforms-field-hidden ccl-utm_campaign\" data-field-type=\"hidden\" data-field-id=\"9\"><input type=\"hidden\" id=\"wpforms-56741-field_9\" name=\"wpforms[fields][9]\"><\/div><div id=\"wpforms-56741-field_10-container\" class=\"wpforms-field wpforms-field-hidden ccl-utm_term\" data-field-type=\"hidden\" data-field-id=\"10\"><input type=\"hidden\" id=\"wpforms-56741-field_10\" name=\"wpforms[fields][10]\"><\/div><div id=\"wpforms-56741-field_11-container\" class=\"wpforms-field wpforms-field-hidden ccl-utm_content\" data-field-type=\"hidden\" data-field-id=\"11\"><input type=\"hidden\" id=\"wpforms-56741-field_11\" name=\"wpforms[fields][11]\"><\/div><div id=\"wpforms-56741-field_12-container\" class=\"wpforms-field wpforms-field-hidden ccl-gclid\" data-field-type=\"hidden\" data-field-id=\"12\"><input type=\"hidden\" id=\"wpforms-56741-field_12\" name=\"wpforms[fields][12]\"><\/div><div id=\"wpforms-56741-field_13-container\" class=\"wpforms-field wpforms-field-hidden ccl-gbraid\" data-field-type=\"hidden\" data-field-id=\"13\"><input type=\"hidden\" id=\"wpforms-56741-field_13\" name=\"wpforms[fields][13]\"><\/div><div id=\"wpforms-56741-field_14-container\" class=\"wpforms-field wpforms-field-hidden ccl-wbraid\" data-field-type=\"hidden\" data-field-id=\"14\"><input type=\"hidden\" id=\"wpforms-56741-field_14\" name=\"wpforms[fields][14]\"><\/div><div id=\"wpforms-56741-field_15-container\" class=\"wpforms-field wpforms-field-hidden ccl-fbclid\" data-field-type=\"hidden\" data-field-id=\"15\"><input type=\"hidden\" id=\"wpforms-56741-field_15\" name=\"wpforms[fields][15]\"><\/div><div id=\"wpforms-56741-field_16-container\" class=\"wpforms-field wpforms-field-hidden ccl-landing\" data-field-type=\"hidden\" data-field-id=\"16\"><input type=\"hidden\" id=\"wpforms-56741-field_16\" name=\"wpforms[fields][16]\"><\/div><div id=\"wpforms-56741-field_17-container\" class=\"wpforms-field wpforms-field-hidden ccl-referrer\" data-field-type=\"hidden\" data-field-id=\"17\"><input type=\"hidden\" id=\"wpforms-56741-field_17\" name=\"wpforms[fields][17]\"><\/div><div id=\"wpforms-56741-field_18-container\" class=\"wpforms-field wpforms-field-hidden ccl-first_touch\" data-field-type=\"hidden\" data-field-id=\"18\"><input type=\"hidden\" id=\"wpforms-56741-field_18\" name=\"wpforms[fields][18]\"><\/div><div id=\"wpforms-56741-field_19-container\" class=\"wpforms-field wpforms-field-hidden ccl-canal\" data-field-type=\"hidden\" data-field-id=\"19\"><input type=\"hidden\" id=\"wpforms-56741-field_19\" name=\"wpforms[fields][19]\"><\/div><div id=\"wpforms-56741-field_20-container\" class=\"wpforms-field wpforms-field-hidden ccl-campagne\" data-field-type=\"hidden\" data-field-id=\"20\"><input type=\"hidden\" id=\"wpforms-56741-field_20\" name=\"wpforms[fields][20]\"><\/div><\/div><!-- .wpforms-field-container --><div class=\"wpforms-field wpforms-field-hp\"><label for=\"wpforms-56741-field-hp\" class=\"wpforms-field-label\">Phone<\/label><input type=\"text\" name=\"wpforms[hp]\" id=\"wpforms-56741-field-hp\" class=\"wpforms-field-medium\"><\/div><div class=\"wpforms-submit-container\" ><input type=\"hidden\" name=\"wpforms[id]\" value=\"56741\"><input type=\"hidden\" name=\"wpforms[time_token]\" value=\"1794193640.11fff70e7de8099ade3c040d21f39c759a6f34310a3bd15069cbd4011215ac3a\"><input type=\"hidden\" name=\"page_title\" value=\"\"><input type=\"hidden\" name=\"page_url\" value=\"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/pages\/56762\"><input type=\"hidden\" name=\"url_referer\" value=\"\"><button type=\"submit\" name=\"wpforms[submit]\" id=\"wpforms-submit-56741\" class=\"wpforms-submit px-btn\" data-alt-text=\"Envoi en cours...\" data-submit-text=\"Request my free consultation\" aria-live=\"assertive\" value=\"wpforms-submit\">Request my free consultation<\/button><img decoding=\"async\" src=\"https:\/\/carmelcosmeticslabs.com\/wp-content\/plugins\/wpforms\/assets\/images\/submit-spin.svg\" class=\"wpforms-submit-spinner\" style=\"display: none;\" width=\"26\" height=\"26\" alt=\"Loading\" title=\"| Carmel Cosmetics Labs\"><\/div><\/form><\/div>  <!-- .wpforms-container -->            <\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-56762","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/pages\/56762","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/comments?post=56762"}],"version-history":[{"count":2,"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/pages\/56762\/revisions"}],"predecessor-version":[{"id":56764,"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/pages\/56762\/revisions\/56764"}],"wp:attachment":[{"href":"https:\/\/carmelcosmeticslabs.com\/en\/wp-json\/wp\/v2\/media?parent=56762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}