{"id":15663,"date":"2026-10-16T19:08:46","date_gmt":"2026-10-16T17:08:46","guid":{"rendered":"https:\/\/www.ok3d.fr\/?page_id=15663"},"modified":"2026-10-16T19:52:07","modified_gmt":"2026-10-16T17:52:07","slug":"configurateur-projet","status":"publish","type":"page","link":"https:\/\/www.ok3d.fr\/en\/configurateur-projet\/","title":{"rendered":"Project configurator"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"15663\" class=\"elementor elementor-15663\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bbe5d3c e-con e-atomic-element e-flexbox-base e-ba436fd \" data-id=\"bbe5d3c\" data-element_type=\"e-flexbox\" data-e-type=\"e-flexbox\" data-interaction-id=\"bbe5d3c\" data-e-type=\"e-flexbox\" data-id=\"bbe5d3c\">\n    \t\t<div class=\"elementor-element elementor-element-c1d60fd elementor-widget elementor-widget-html\" data-id=\"c1d60fd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!-- Configurateur OK3D v2.1 \u2014 int\u00e9gration native Elementor, liaison Keystroke. Une instance par page. -->\r\n<style>\r\n\/* OK3D \/ Configurateur v2 \u2014 styles limit\u00e9s au module. *\/\r\n#ok3d-project {\r\n  --okp-bg: #080a10;\r\n  --okp-surface: #0e111a;\r\n  --okp-text: #f1f3fa;\r\n  --okp-muted: #a1a8ba;\r\n  --okp-blue: #648cff;\r\n  --okp-line: rgba(255,255,255,.12);\r\n  --okp-font: 'Manrope', Arial, sans-serif;\r\n  --okp-display: 'Space Grotesk', Arial, sans-serif;\r\n  --okp-gutter: clamp(22px,5vw,88px);\r\n  --okp-header-offset: 94px;\r\n  position: relative;\r\n  isolation: isolate;\r\n  width: 100%;\r\n  max-width: none;\r\n  margin: 0;\r\n  background: var(--okp-bg);\r\n  color: var(--okp-text);\r\n  font: 400 15px\/1.65 var(--okp-font);\r\n  -webkit-font-smoothing: antialiased;\r\n  color-scheme: dark;\r\n  overflow: clip;\r\n}\r\n#ok3d-project *, #ok3d-project *::before, #ok3d-project *::after { box-sizing: border-box; }\r\n#ok3d-project :is(h1,h2,h3,p,dl,dd,fieldset) { margin: 0; }\r\n#ok3d-project :is(h1,h2,h3) { color: var(--okp-text); font-family: var(--okp-display); font-style: normal; text-transform: none; }\r\n#ok3d-project :is(a,button,input,textarea,summary) { -webkit-tap-highlight-color: transparent; }\r\n#ok3d-project a { color: inherit; text-decoration: none; }\r\n#ok3d-project button { font: inherit; text-transform: none; letter-spacing: normal; box-shadow: none; cursor: pointer; margin: 0; }\r\n#ok3d-project :is(input,textarea) { font: inherit; letter-spacing: normal; color: var(--okp-text); box-shadow: none; }\r\n#ok3d-project :focus-visible { outline: 2px solid #9bb7ff; outline-offset: 5px; }\r\n#ok3d-project h2[tabindex='-1']:focus { outline: none; }\r\n#ok3d-project [hidden] { display: none !important; }\r\n#ok3d-project svg { display: block; }\r\n#ok3d-project .okp-wrap { width: min(100%,1600px); margin-inline: auto; padding-inline: var(--okp-gutter); }\r\n.elementor-widget-html:has(#ok3d-project), .elementor-widget-html:has(#ok3d-project) > .elementor-widget-container { width: 100%; max-width: none !important; margin: 0; padding: 0; }\r\n\r\n\/* Ouverture sombre pour le header transparent global d\u2019OK3D. *\/\r\n#ok3d-project .okp-hero { position: relative; padding-top: calc(var(--okp-header-offset) + 54px); background: radial-gradient(ellipse at 85% 40%,rgba(57,86,165,.13),transparent 54%),#080a10; }\r\n#ok3d-project .okp-hero::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: linear-gradient(90deg,transparent,#859fe040,transparent); }\r\n#ok3d-project .okp-hero-grid { display: grid; grid-template-columns: minmax(0,1.6fr) minmax(220px,.8fr); gap: 40px; align-items: center; padding-bottom: 46px; }\r\n#ok3d-project .okp-kicker { display: inline-flex; align-items: center; gap: 10px; font: 500 10px\/1.5 var(--okp-font); letter-spacing: .15em; color: #a6b5d1; }\r\n#ok3d-project .okp-dot { height: 5px; width: 5px; border-radius: 50%; background: #9bb7ff; box-shadow: 0 0 12px #648cff70; }\r\n#ok3d-project h1 { font-size: clamp(46px,5.2vw,82px); font-weight: 400; letter-spacing: -.065em; line-height: 1.08; margin-top: 24px; }\r\n#ok3d-project h1 span { color: #a6beff; }\r\n#ok3d-project .okp-lead { color: #abb3c7; font-size: 15px; line-height: 1.85; margin-top: 24px; max-width: 620px; }\r\n#ok3d-project .okp-hero-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 27px; color: #8f9ab1; font-size: 10px; }\r\n#ok3d-project .okp-hero-meta i { width: 3px; height: 3px; border-radius: 50%; background: #64738f; }\r\n#ok3d-project .okp-art { position: relative; max-width: 380px; width: 100%; justify-self: end; }\r\n#ok3d-project .okp-art-halo { position: absolute; inset: 5%; border-radius: 50%; background: radial-gradient(ellipse,#648cff22,transparent 65%); filter: blur(20px); }\r\n#ok3d-project .okp-art-svg { position: relative; width: 100%; height: auto; filter: drop-shadow(0 0 14px #648cff20); }\r\n#ok3d-project .okp-art-caption { display: block; text-align: center; color: #7e8fae; font-size: 8px; letter-spacing: .2em; margin-top: 8px; }\r\n#ok3d-project .okp-hero-bottom { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 20px 0; border-top: 1px solid var(--okp-line); color: #8c98af; font-size: 9px; letter-spacing: .1em; }\r\n#ok3d-project .okp-hero-bottom a { font-size: 11px; letter-spacing: 0; color: #d0d8ed; }\r\n#ok3d-project .okp-hero-bottom a span { display: inline-block; margin-left: 20px; color: #9db7ff; transition: transform .2s; }\r\n#ok3d-project .okp-hero-bottom a:hover span { transform: translateY(3px); }\r\n#ok3d-project .okp-body { padding: 48px 0 0; background: radial-gradient(ellipse at 0 38%,#2134580b,transparent 55%),var(--okp-bg); }\r\n#ok3d-project .okp-section-label { display: flex; justify-content: space-between; gap: 20px; font-size: 9px; letter-spacing: .13em; color: #8e9ebd; margin-bottom: 20px; }\r\n#ok3d-project .okp-section-label > span + span { letter-spacing: 0; font-size: 11px; color: #919bb0; }\r\n#ok3d-project .okp-workspace { display: grid; grid-template-columns: minmax(0,1fr) 310px; gap: 28px; align-items: start; scroll-margin-top: 116px; }\r\n#ok3d-project .okp-editor { min-width: 0; border: 1px solid #a0b9ed24; border-radius: 12px; background: linear-gradient(145deg,#101521,#0c1019 70%); box-shadow: 0 15px 65px #00000018; overflow: hidden; }\r\n#ok3d-project .okp-step-nav { display: grid; grid-template-columns: repeat(6,minmax(0,1fr)); border-bottom: 1px solid var(--okp-line); padding: 0 16px; }\r\n#ok3d-project .okp-step { position: relative; display: flex; align-items: center; justify-content: center; gap: 7px; min-height: 64px; background: transparent; border: 0; border-radius: 0; padding: 12px 5px; color: #8290a9; font-size: 10px; transition: color .2s; }\r\n#ok3d-project .okp-step::after { content: ''; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 2px; background: var(--okp-blue); transform: scaleX(0); transition: transform .25s; }\r\n#ok3d-project .okp-step-num { font-family: var(--okp-display); font-size: 10px; color: #8798b8; }\r\n#ok3d-project .okp-step[aria-current='step'] { color: #e7ecfa; }\r\n#ok3d-project .okp-step[aria-current='step']::after { transform: scaleX(1); }\r\n#ok3d-project .okp-step[aria-current='step'] .okp-step-num, #ok3d-project .okp-step.is-done .okp-step-num { color: #a6beff; }\r\n#ok3d-project .okp-step:disabled { cursor: default; color: #66748e; }\r\n#ok3d-project .okp-step:not(:disabled):hover { color: #fff; }\r\n#ok3d-project .okp-panel { padding: clamp(25px,3vw,44px); min-height: 550px; }\r\n#ok3d-project .okp-panel-top { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 13px; }\r\n#ok3d-project .okp-panel-top .okp-kicker { font-size: 9px; }\r\n#ok3d-project .okp-step-counter { color: #a6beff; font: 400 12px var(--okp-display); }\r\n#ok3d-project .okp-progress { height: 2px; background: #ffffff0c; border-radius: 2px; overflow: hidden; margin-bottom: 28px; }\r\n#ok3d-project .okp-progress-fill { height: 100%; width: 0; background: linear-gradient(90deg,#426ee7,#a8c0ff); transition: width .35s; }\r\n#ok3d-project .okp-panel h2 { font-size: clamp(27px,2.6vw,37px); font-weight: 400; line-height: 1.2; letter-spacing: -.045em; }\r\n#ok3d-project .okp-question-note { color: #a1abc0; font-size: 12px; line-height: 1.85; margin-top: 11px; margin-bottom: 26px; }\r\n#ok3d-project .okp-options { border: 0; padding: 0; display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 12px; min-width: 0; }\r\n#ok3d-project .okp-option { position: relative; display: flex; flex-direction: column; align-items: flex-start; min-width: 0; padding: 19px 21px 20px; min-height: 145px; background: #ffffff02; border: 1px solid #a0b9ed26; border-radius: 7px; cursor: pointer; transition: background .22s,border-color .22s,box-shadow .22s; }\r\n#ok3d-project .okp-option::before { content: ''; position: absolute; top: -1px; left: 20%; right: 20%; height: 1px; background: linear-gradient(90deg,transparent,#a6beff80,transparent); opacity: 0; transition: opacity .25s; }\r\n#ok3d-project .okp-option:hover { border-color: #93b0ff75; background: #648cff09; }\r\n#ok3d-project .okp-option.is-selected { background: linear-gradient(135deg,#648cff18,#648cff05); border-color: #8aabffb8; box-shadow: inset 0 0 0 1px #648cff10; }\r\n#ok3d-project .okp-option.is-selected::before { opacity: 1; }\r\n#ok3d-project .okp-option:has(input:focus-visible) { outline: 2px solid #a3bdff; outline-offset: 4px; }\r\n#ok3d-project .okp-option input { position: absolute; width: 1px; height: 1px; opacity: 0; }\r\n#ok3d-project .okp-option-icon { width: 23px; height: 23px; color: #a3bbf4; margin-bottom: 15px; }\r\n#ok3d-project .okp-option-icon svg { width: 100%; height: 100%; }\r\n#ok3d-project .okp-option-title { font-size: 13px; font-weight: 500; line-height: 1.5; color: #e4eaf9; padding-right: 8px; }\r\n#ok3d-project .okp-option-description { font-size: 11px; font-weight: 400; line-height: 1.7; color: #a0abc0; margin-top: 5px; }\r\n#ok3d-project .okp-check { display: grid; place-items: center; position: absolute; right: 13px; top: 15px; width: 15px; height: 15px; border-radius: 50%; border: 1px solid #b1c3ed55; color: transparent; font: 600 9px\/1 var(--okp-font); }\r\n#ok3d-project .okp-options.is-multiple .okp-check { border-radius: 3px; }\r\n#ok3d-project .is-selected .okp-check { color: #0d162c; border-color: #a6beff; background: #a6beff; }\r\n#ok3d-project .okp-tip { display: flex; gap: 10px; margin-top: 22px; color: #a0acc4; font-size: 11px; line-height: 1.8; }\r\n#ok3d-project .okp-tip > span { color: #a6beff; }\r\n#ok3d-project .okp-navigation { display: flex; justify-content: space-between; align-items: center; gap: 18px; border-top: 1px solid var(--okp-line); padding-top: 24px; margin-top: 27px; }\r\n#ok3d-project .okp-btn { position: relative; display: inline-flex; justify-content: space-between; align-items: center; gap: 32px; min-height: 48px; padding: 13px 19px; border: 1px solid #8eacff80; border-radius: 3px; background: linear-gradient(135deg,#648cff25,#648cff0c); color: #edf2ff; font-size: 12px; font-weight: 500; line-height: 1.5; text-align: left; transition: border-color .2s,background .2s,box-shadow .2s; }\r\n#ok3d-project .okp-btn svg { width: 15px; height: 15px; flex: 0 0 15px; color: #a6beff; transition: transform .2s; }\r\n#ok3d-project .okp-btn:hover { border-color: #a3bdff; background: linear-gradient(135deg,#648cff38,#648cff15); box-shadow: 0 5px 25px #20418d20; }\r\n#ok3d-project .okp-btn:hover svg { transform: translate(2px,-2px); }\r\n#ok3d-project .okp-btn:disabled { color: #7c89a3; background: #ffffff03; border-color: #ffffff12; cursor: default; box-shadow: none; }\r\n#ok3d-project .okp-btn:disabled svg { opacity: .35; transform: none; }\r\n#ok3d-project .okp-btn.is-full { display: flex; width: 100%; }\r\n#ok3d-project .okp-text-btn { padding: 6px 0; border: 0; background: transparent; color: #a7b3ca; font-size: 11px; line-height: 1.6; border-radius: 0; }\r\n#ok3d-project .okp-text-btn:hover { color: #e0e9ff; background: transparent; }\r\n#ok3d-project .okp-text-btn:disabled { cursor: default; opacity: .5; }\r\n#ok3d-project .okp-back { min-height: 44px; }\r\n#ok3d-project .okp-sidebar { position: sticky; top: 116px; min-width: 0; padding: 27px 26px 20px; border: 1px solid #a0b9ed24; border-radius: 10px; background: linear-gradient(160deg,#151c2c80,#0d111a); }\r\n#ok3d-project .okp-summary-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 22px; }\r\n#ok3d-project .okp-summary-head .okp-kicker { font-size: 9px; }\r\n#ok3d-project .okp-summary-count { font: 400 11px var(--okp-display); color: #9db6f5; }\r\n#ok3d-project .okp-sidebar h2 { font-size: 28px; font-weight: 400; letter-spacing: -.045em; line-height: 1.2; }\r\n#ok3d-project .okp-summary-intro { margin-top: 13px; color: #a0abc2; font-size: 11px; line-height: 1.8; }\r\n#ok3d-project .okp-summary { margin-top: 24px; }\r\n#ok3d-project .okp-summary-row { display: grid; grid-template-columns: 75px minmax(0,1fr); gap: 12px; border-top: 1px solid var(--okp-line); padding: 12px 0; font-size: 10px; line-height: 1.7; }\r\n#ok3d-project .okp-summary-row dt { color: #8c9ab5; }\r\n#ok3d-project .okp-summary-row dd { text-align: right; color: #d8e2f9; overflow-wrap: anywhere; }\r\n#ok3d-project .okp-summary-row dd.is-empty { color: #7d8ba6; }\r\n#ok3d-project .okp-sidebar-note { display: flex; gap: 9px; border-top: 1px solid var(--okp-line); padding-top: 17px; margin-top: 4px; color: #9daccb; font-size: 10px; line-height: 1.85; }\r\n#ok3d-project .okp-sidebar-note > span { color: #a6beff; }\r\n#ok3d-project .okp-reset { background: transparent; border: 0; padding: 6px 0; margin-top: 15px; color: #a4b2cf; font-size: 10px; text-decoration: underline; text-underline-offset: 4px; }\r\n#ok3d-project .okp-direct { display: flex; align-items: center; justify-content: space-between; gap: 30px; border-top: 1px solid var(--okp-line); padding: 35px 0; margin-top: 44px; }\r\n#ok3d-project .okp-direct .okp-kicker { font-size: 9px; }\r\n#ok3d-project .okp-direct p { margin-top: 7px; font-size: 12px; color: #a5b0c8; }\r\n#ok3d-project .okp-direct > a { font: 400 clamp(20px,2.2vw,30px)\/1.3 var(--okp-display); letter-spacing: -.04em; white-space: nowrap; }\r\n#ok3d-project .okp-direct > a span { display: inline-block; margin-left: 15px; color: #9cb7ff; transition: transform .2s; }\r\n#ok3d-project .okp-direct > a:hover span { transform: translate(3px,-3px); }\r\n#ok3d-project .okp-bottom-note { display: flex; justify-content: space-between; gap: 20px; border-top: 1px solid var(--okp-line); padding: 19px 0 27px; color: #8c9bb8; font-size: 10px; line-height: 1.8; }\r\n#ok3d-project .okp-bottom-note a { white-space: nowrap; }\r\n\r\n\/* Recommandation, brief, contact. *\/\r\n#ok3d-project .okp-result-label { display: inline-flex; gap: 8px; align-items: center; font-size: 9px; letter-spacing: .13em; color: #a7c0ff; margin-bottom: 20px; }\r\n#ok3d-project .okp-result-intro { color: #a8b3ca; font-size: 13px; line-height: 1.9; margin-top: 16px; }\r\n#ok3d-project .okp-deliverables { margin-top: 25px; }\r\n#ok3d-project .okp-deliverable { display: grid; grid-template-columns: 22px minmax(0,1fr); gap: 15px; padding: 18px 0; border-top: 1px solid var(--okp-line); }\r\n#ok3d-project .okp-deliverable-number { font: 400 11px\/1.8 var(--okp-display); color: #9eb9ff; }\r\n#ok3d-project .okp-deliverable h3 { font: 500 14px\/1.5 var(--okp-font); letter-spacing: -.01em; }\r\n#ok3d-project .okp-deliverable p { color: #a3afc6; font-size: 11px; line-height: 1.85; margin-top: 6px; }\r\n#ok3d-project .okp-result-note { padding: 17px 19px; border-left: 2px solid #8eacff70; background: #648cff09; margin: 22px 0; color: #a8b5cf; font-size: 11px; line-height: 1.9; }\r\n#ok3d-project .okp-result-note strong { display: block; color: #dce6ff; font-size: 12px; font-weight: 500; margin-bottom: 5px; }\r\n#ok3d-project .okp-result-note p + p { margin-top: 8px; }\r\n#ok3d-project .okp-small-note { margin-top: 12px; font-size: 10px; text-align: center; color: #96a4bf; line-height: 1.8; }\r\n#ok3d-project .okp-actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 10px 23px; margin-top: 15px; }\r\n#ok3d-project .okp-brief-details { margin-top: 24px; margin-bottom: 24px; border: 1px solid var(--okp-line); border-radius: 5px; }\r\n#ok3d-project .okp-brief-details summary { cursor: pointer; padding: 13px 16px; font-size: 11px; color: #bccbea; }\r\n#ok3d-project .okp-brief-details pre { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0; padding: 0 16px 18px; font: 400 11px\/1.9 var(--okp-font); color: #a5b4d1; background: transparent; }\r\n#ok3d-project .okp-form { position: relative; margin-top: 24px; }\r\n#ok3d-project .okp-form-fields { display: grid; gap: 20px; border: 0; padding: 0; min-width: 0; }\r\n#ok3d-project .okp-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }\r\n#ok3d-project .okp-field { display: flex; flex-direction: column; gap: 9px; font-size: 11px; color: #c6d1e8; font-weight: 400; }\r\n#ok3d-project .okp-field small { font-size: 10px; color: #94a2bd; }\r\n#ok3d-project .okp-field input, #ok3d-project .okp-field textarea { width: 100%; max-width: 100%; border: 1px solid #a0b9ed33; border-radius: 4px; background: #080d1690; min-height: 46px; padding: 12px 13px; font-size: 13px; line-height: 1.7; transition: border-color .2s,background .2s; }\r\n#ok3d-project .okp-field input:hover, #ok3d-project .okp-field textarea:hover { border-color: #a0b9ed66; }\r\n#ok3d-project .okp-field input:focus, #ok3d-project .okp-field textarea:focus { border-color: #96b3ff; background: #111b2c; }\r\n#ok3d-project .okp-field textarea { min-height: 115px; resize: vertical; }\r\n#ok3d-project .okp-field :is(input,textarea)::placeholder { color: #8997b2; opacity: 1; }\r\n#ok3d-project .okp-honeypot { position: absolute !important; width: 1px !important; height: 1px !important; opacity: 0; overflow: hidden; pointer-events: none; left: -9999px; }\r\n#ok3d-project .okp-privacy { font-size: 10px; color: #96a6c2; line-height: 1.9; margin-top: 20px; }\r\n#ok3d-project .okp-privacy a { text-decoration: underline; text-underline-offset: 3px; }\r\n#ok3d-project .okp-submit { margin-top: 22px; }\r\n#ok3d-project .okp-form-status { margin-top: 16px; font-size: 12px; line-height: 1.85; color: #afc6ff; }\r\n#ok3d-project .okp-form-status.is-error { color: #f3bdb2; }\r\n#ok3d-project .okp-fallback { border: 1px solid #a0b9ed33; border-radius: 5px; padding: 15px 17px; margin-top: 15px; font-size: 11px; color: #b8c5df; line-height: 1.8; }\r\n#ok3d-project .okp-fallback a { text-decoration: underline; text-underline-offset: 3px; color: #b1c7ff; }\r\n#ok3d-project .okp-success-icon { display: grid; place-items: center; width: 50px; height: 50px; border: 1px solid #a2beff80; border-radius: 50%; color: #b3caff; font-size: 22px; margin-bottom: 24px; background: #648cff12; }\r\n#ok3d-project .okp-toast { position: fixed; bottom: max(22px,env(safe-area-inset-bottom)); left: 50%; width: max-content; max-width: calc(100vw - 40px); transform: translate(-50%,12px); pointer-events: none; opacity: 0; z-index: 10001; border: 1px solid #7e9fde70; background: #152035; color: #e2ecff; box-shadow: 0 10px 40px #0006; border-radius: 6px; padding: 13px 18px; font-size: 12px; line-height: 1.7; transition: opacity .2s,transform .2s; }\r\n#ok3d-project .okp-toast.is-visible { opacity: 1; transform: translate(-50%,0); }\r\n#ok3d-project .okp-copy-area { display: block; width: 100%; min-height: 180px; margin-top: 20px; font-size: 11px; background: #0b111d; padding: 13px; border: 1px solid #7e9fde70; border-radius: 5px; }\r\n\r\n@media (min-width:1500px) {\r\n  #ok3d-project .okp-workspace { grid-template-columns: minmax(0,1fr) 350px; gap: 36px; }\r\n  #ok3d-project .okp-option { min-height: 154px; }\r\n}\r\n@media (max-width:1100px) {\r\n  #ok3d-project .okp-workspace { grid-template-columns: minmax(0,1fr) 270px; gap: 20px; }\r\n  #ok3d-project .okp-panel { padding: 28px; }\r\n  #ok3d-project .okp-step { flex-direction: column; gap: 4px; font-size: 9px; padding-block: 12px; }\r\n  #ok3d-project .okp-sidebar { padding: 24px 20px 18px; }\r\n  #ok3d-project .okp-summary-row { grid-template-columns: 65px minmax(0,1fr); gap: 8px; }\r\n  #ok3d-project .okp-hero-grid { grid-template-columns: 1.7fr 1fr; gap: 20px; }\r\n  #ok3d-project h1 { font-size: clamp(46px,6vw,65px); }\r\n}\r\n@media (max-width:900px) {\r\n  #ok3d-project .okp-workspace { grid-template-columns: minmax(0,1fr); }\r\n  #ok3d-project .okp-sidebar { position: static; }\r\n  #ok3d-project .okp-sidebar h2 { font-size: 25px; }\r\n  #ok3d-project .okp-sidebar h2 br { display: none; }\r\n  #ok3d-project .okp-summary { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 0 25px; }\r\n  #ok3d-project .okp-summary-row { display: block; }\r\n  #ok3d-project .okp-summary-row dd { text-align: left; font-size: 11px; margin-top: 5px; }\r\n  #ok3d-project .okp-sidebar-note { max-width: 460px; }\r\n  #ok3d-project .okp-step { flex-direction: row; font-size: 11px; gap: 8px; }\r\n  #ok3d-project .okp-art { opacity: .85; }\r\n  #ok3d-project .okp-section-label > span + span { display: none; }\r\n}\r\n@media (max-width:700px) {\r\n  #ok3d-project { --okp-header-offset: 78px; }\r\n  #ok3d-project .okp-hero { padding-top: calc(var(--okp-header-offset) + 43px); }\r\n  #ok3d-project .okp-hero-grid { display: block; padding-bottom: 32px; }\r\n  #ok3d-project h1 { font-size: clamp(42px,8.2vw,58px); margin-top: 21px; }\r\n  #ok3d-project .okp-art { display: none; }\r\n  #ok3d-project .okp-lead { font-size: 13px; margin-top: 22px; max-width: 470px; }\r\n  #ok3d-project .okp-desktop-break { display: none; }\r\n  #ok3d-project .okp-hero-meta { font-size: 9px; gap: 9px; margin-top: 22px; }\r\n  #ok3d-project .okp-kicker { font-size: 9px; letter-spacing: .1em; }\r\n  #ok3d-project .okp-hero-bottom { padding-block: 17px; }\r\n  #ok3d-project .okp-hero-bottom > span:first-child { display: none; }\r\n  #ok3d-project .okp-hero-bottom a { font-size: 10px; }\r\n  #ok3d-project .okp-body { padding-top: 30px; }\r\n  #ok3d-project .okp-section-label { margin-bottom: 15px; font-size: 8px; }\r\n  #ok3d-project .okp-workspace { scroll-margin-top: 94px; }\r\n  #ok3d-project .okp-step-nav { padding-inline: 8px; }\r\n  #ok3d-project .okp-step { flex-direction: column; font-size: 8px; gap: 4px; min-height: 61px; padding: 10px 2px; }\r\n  #ok3d-project .okp-step-num { font-size: 10px; }\r\n  #ok3d-project .okp-panel { padding: 24px 20px; min-height: 0; }\r\n  #ok3d-project .okp-panel-top .okp-kicker { font-size: 8px; letter-spacing: .1em; }\r\n  #ok3d-project .okp-progress { margin-bottom: 24px; }\r\n  #ok3d-project .okp-panel h2 { font-size: 28px; }\r\n  #ok3d-project .okp-question-note { font-size: 11px; margin-bottom: 22px; }\r\n  #ok3d-project .okp-options { gap: 10px; }\r\n  #ok3d-project .okp-option { min-height: 151px; padding: 17px 13px; }\r\n  #ok3d-project .okp-option-title { font-size: 12px; padding: 0; }\r\n  #ok3d-project .okp-option-description { font-size: 10px; }\r\n  #ok3d-project .okp-option-icon { width: 22px; height: 22px; margin-bottom: 14px; }\r\n  #ok3d-project .okp-check { top: 12px; right: 10px; width: 13px; height: 13px; font-size: 8px; }\r\n  #ok3d-project .okp-tip { font-size: 10px; margin-top: 18px; }\r\n  #ok3d-project .okp-navigation { padding-top: 20px; margin-top: 23px; gap: 10px; }\r\n  #ok3d-project .okp-navigation .okp-btn { gap: 16px; }\r\n  #ok3d-project .okp-btn { font-size: 11px; padding: 13px 16px; }\r\n  #ok3d-project .okp-sidebar { padding: 24px 22px 17px; }\r\n  #ok3d-project .okp-summary { grid-template-columns: repeat(2,minmax(0,1fr)); gap: 0 20px; }\r\n  #ok3d-project .okp-summary-intro { max-width: 340px; }\r\n  #ok3d-project .okp-summary-head { margin-bottom: 17px; }\r\n  #ok3d-project .okp-direct { display: block; padding: 29px 0; margin-top: 30px; }\r\n  #ok3d-project .okp-direct > a { display: inline-flex; margin-top: 21px; font-size: 27px; }\r\n  #ok3d-project .okp-direct .okp-kicker { font-size: 8px; }\r\n  #ok3d-project .okp-direct p { font-size: 11px; }\r\n  #ok3d-project .okp-bottom-note { align-items: flex-start; font-size: 9px; }\r\n  #ok3d-project .okp-bottom-note > span { max-width: 200px; }\r\n  #ok3d-project .okp-field-row { grid-template-columns: 1fr; gap: 20px; }\r\n  #ok3d-project .okp-field input, #ok3d-project .okp-field textarea { font-size: 16px; }\r\n  #ok3d-project .okp-result-intro { font-size: 12px; }\r\n}\r\n@media (max-width:370px) {\r\n  #ok3d-project { --okp-gutter: 16px; }\r\n  #ok3d-project .okp-panel { padding-inline: 16px; }\r\n  #ok3d-project h1 { font-size: 39px; }\r\n  #ok3d-project .okp-options { grid-template-columns: 1fr; }\r\n  #ok3d-project .okp-option { min-height: 120px; }\r\n  #ok3d-project .okp-hero-meta { display: block; line-height: 2; }\r\n  #ok3d-project .okp-hero-meta i { display: none; }\r\n  #ok3d-project .okp-hero-meta span { display: block; }\r\n}\r\n@media (prefers-reduced-motion:reduce) {\r\n  #ok3d-project *, #ok3d-project *::before, #ok3d-project *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }\r\n}\r\n\r\n\r\n\/* Pleine largeur m\u00eame lorsque le widget est dans un conteneur Elementor \u00e9troit. *\/\r\n#ok3d-project[data-layout=\"full\"]{width:var(--okp-viewport,100%);max-width:none!important;margin-left:var(--okp-offset,0px);margin-right:0}\r\n#ok3d-project .okp-origin{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:24px;padding:14px 18px;border:1px solid #648cff44;border-radius:8px;background:#648cff0d;font-size:12px;color:#bdcfff;flex-wrap:wrap}\r\n#ok3d-project .okp-origin a{text-decoration:underline;text-underline-offset:4px;min-height:36px;display:flex;align-items:center}\r\n@media(max-width:700px){#ok3d-project .okp-field input,#ok3d-project .okp-field textarea{font-size:16px}#ok3d-project .okp-origin{font-size:12px}}\r\n<\/style>\r\n<!-- OK3D \u2014 Configurateur. Conserver le header et le footer globaux du site. -->\r\n<section data-layout=\"full\" id=\"ok3d-project\" aria-labelledby=\"okp-title\">\r\n  <div class=\"okp-hero\">\r\n    <div class=\"okp-wrap\">\r\n      <div class=\"okp-hero-grid\">\r\n        <div class=\"okp-hero-copy\">\r\n          <p class=\"okp-kicker\"><span class=\"okp-dot\" aria-hidden=\"true\"><\/span> OK3D \/ VOTRE PROCHAIN PROJET<\/p>\r\n          <h1 id=\"okp-title\">Une id\u00e9e.<br><span>Le d\u00e9but d\u2019un projet.<\/span><\/h1>\r\n          <p class=\"okp-lead\">Des visuels produit, une animation, un espace \u00e0 r\u00e9v\u00e9ler.<br class=\"okp-desktop-break\"> Trouvons ensemble la bonne direction pour votre projet 3D.<\/p>\r\n          <div class=\"okp-hero-meta\"><span>6 questions pour poser les bases<\/span><i aria-hidden=\"true\"><\/i><span>Sans inscription ni engagement<\/span><\/div>\r\n        <\/div>\r\n        <div class=\"okp-art\" aria-hidden=\"true\">\r\n          <div class=\"okp-art-halo\"><\/div>\r\n          <svg class=\"okp-art-svg\" viewBox=\"0 0 360 300\" fill=\"none\">\r\n            <defs>\r\n              <linearGradient id=\"okp-face-a\" x1=\"80\" y1=\"90\" x2=\"260\" y2=\"220\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#789dff\" stop-opacity=\".34\"\/><stop offset=\"1\" stop-color=\"#648cff\" stop-opacity=\".04\"\/><\/linearGradient>\r\n              <linearGradient id=\"okp-face-b\" x1=\"180\" y1=\"40\" x2=\"180\" y2=\"250\" gradientUnits=\"userSpaceOnUse\"><stop stop-color=\"#a4bfff\" stop-opacity=\".28\"\/><stop offset=\"1\" stop-color=\"#648cff\" stop-opacity=\".02\"\/><\/linearGradient>\r\n            <\/defs>\r\n            <ellipse cx=\"180\" cy=\"155\" rx=\"153\" ry=\"59\" stroke=\"#819ef9\" stroke-opacity=\".18\" transform=\"rotate(-28 180 155)\"\/>\r\n            <ellipse cx=\"180\" cy=\"155\" rx=\"153\" ry=\"59\" stroke=\"#819ef9\" stroke-opacity=\".12\" transform=\"rotate(28 180 155)\"\/>\r\n            <path d=\"M180 40 273 93v109l-93 54-93-54V93Z\" stroke=\"#a7bdff\" stroke-opacity=\".7\"\/>\r\n            <path d=\"m87 93 93 54 93-54-93-53Z\" fill=\"url(#okp-face-b)\"\/>\r\n            <path d=\"m87 93 93 54v109l-93-54Z\" fill=\"url(#okp-face-a)\"\/>\r\n            <path d=\"m180 147 93-54v109l-93 54Z\" fill=\"#648cff\" fill-opacity=\".06\"\/>\r\n            <path d=\"m87 93 93 54 93-54M180 147v109\" stroke=\"#c1d2ff\" stroke-opacity=\".85\"\/>\r\n            <path d=\"M180 40v108M87 202l93-54 93 54\" stroke=\"#648cff\" stroke-opacity=\".25\" stroke-dasharray=\"3 5\"\/>\r\n            <path d=\"m180 76 62 36v72l-62 36-62-36v-72Z\" stroke=\"#92b0ff\" stroke-opacity=\".38\"\/>\r\n            <path d=\"m118 112 62 36 62-36M180 148v72\" stroke=\"#92b0ff\" stroke-opacity=\".38\"\/>\r\n            <circle cx=\"180\" cy=\"147\" r=\"3.5\" fill=\"#d3dfff\"\/><circle cx=\"87\" cy=\"93\" r=\"2\" fill=\"#93b0ff\"\/><circle cx=\"273\" cy=\"202\" r=\"2\" fill=\"#93b0ff\"\/>\r\n            <path d=\"M25 48h20M35 38v20M306 249h20M316 239v20\" stroke=\"#8aa7f3\" stroke-opacity=\".6\"\/>\r\n            <path d=\"M270 73h44M48 225h44\" stroke=\"#8aa7f3\" stroke-opacity=\".35\"\/>\r\n          <\/svg>\r\n          <span class=\"okp-art-caption\">L\u2019INTENTION PREND DU VOLUME.<\/span>\r\n        <\/div>\r\n      <\/div>\r\n      <div class=\"okp-hero-bottom\"><span>DE L\u2019ID\u00c9E \u00c0 L\u2019IMAGE.<\/span><a href=\"#okp-workspace\">Commen\u00e7ons par l\u2019essentiel <span aria-hidden=\"true\">\u2193<\/span><\/a><span class=\"okp-hero-index\">01 \u2014 06<\/span><\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"okp-body\">\r\n    <div class=\"okp-wrap\">\r\n      <div class=\"okp-section-label\"><span>01 \/ D\u00c9FINIR VOTRE PROJET<\/span><span>Votre brief se construit au fil de vos r\u00e9ponses.<\/span><\/div>\r\n      <div id=\"okp-workspace\" class=\"okp-workspace\">\r\n        <div class=\"okp-editor\">\r\n          <nav class=\"okp-step-nav\" aria-label=\"\u00c9tapes du configurateur\" id=\"okp-steps\"><\/nav>\r\n          <div id=\"okp-panel\" class=\"okp-panel\">\r\n            <noscript><h2>Construisons votre projet.<\/h2><p>Activez JavaScript pour utiliser le configurateur, ou contactez directement le studio : <a href=\"mailto:contact@ok3d.fr\">contact@ok3d.fr<\/a>.<\/p><\/noscript>\r\n          <\/div>\r\n        <\/div>\r\n        <aside class=\"okp-sidebar\" aria-label=\"R\u00e9capitulatif de votre projet\">\r\n          <div class=\"okp-summary-head\"><p class=\"okp-kicker\">VOTRE BRIEF<\/p><span class=\"okp-summary-count\" id=\"okp-count\">0 \/ 6<\/span><\/div>\r\n          <h2>Les premi\u00e8res<br>lignes du projet.<\/h2>\r\n          <p class=\"okp-summary-intro\">Vos intentions, vos supports, vos priorit\u00e9s. Une base pour cr\u00e9er juste.<\/p>\r\n          <dl class=\"okp-summary\" id=\"okp-summary\"><\/dl>\r\n          <div class=\"okp-sidebar-note\"><span aria-hidden=\"true\">\u21b3<\/span><p>\u00c0 la fin, une premi\u00e8re recommandation et un brief pr\u00eat \u00e0 transmettre.<\/p><\/div>\r\n          <button type=\"button\" class=\"okp-reset\" id=\"okp-reset\">Recommencer<\/button>\r\n        <\/aside>\r\n      <\/div>\r\n      <div class=\"okp-direct\"><div><span class=\"okp-kicker\">VOUS PR\u00c9F\u00c9REZ \u00c9CHANGER DIRECTEMENT ?<\/span><p>Une conversation peut aussi \u00eatre le point de d\u00e9part.<\/p><\/div><a href=\"mailto:contact@ok3d.fr\">contact@ok3d.fr <span aria-hidden=\"true\">\u2197<\/span><\/a><\/div>\r\n      <div class=\"okp-bottom-note\"><span>Une recommandation indicative. Un devis toujours sur mesure.<\/span><a href=\"https:\/\/www.ok3d.fr\/politique-de-confidentialite\/\" target=\"_blank\" rel=\"noopener\">Confidentialit\u00e9 <span aria-hidden=\"true\">\u2197<\/span><\/a><\/div>\r\n    <\/div>\r\n  <\/div>\r\n  <div class=\"okp-toast\" id=\"okp-toast\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\"><\/div>\r\n<\/section>\r\n\r\n<script>\r\n(() => {\r\n'use strict';\r\nconst root = document.getElementById('ok3d-project');\r\nif (!root || root.dataset.okpReady === 'true') return;\r\nroot.dataset.okpReady = 'true';\r\n\r\nconst ICON_PATHS = {\r\n  \"spark\": \"<path d=\\\"m12 2 2.4 7.6L22 12l-7.6 2.4L12 22l-2.4-7.6L2 12l7.6-2.4Z\\\"\/>\",\r\n  \"box\": \"<path d=\\\"m12 2 9 5v10l-9 5-9-5V7Z\\\"\/><path d=\\\"m3 7 9 5 9-5M12 12v10M7.5 4.5l9 5\\\"\/>\",\r\n  \"play\": \"<rect x=\\\"2\\\" y=\\\"4\\\" width=\\\"20\\\" height=\\\"16\\\" rx=\\\"3\\\"\/><path d=\\\"m10 8 6 4-6 4Z\\\"\/>\",\r\n  \"cart\": \"<path d=\\\"M2 3h3l3 13h11l3-9H6\\\"\/><circle cx=\\\"9\\\" cy=\\\"21\\\" r=\\\"1\\\"\/><circle cx=\\\"19\\\" cy=\\\"21\\\" r=\\\"1\\\"\/>\",\r\n  \"idea\": \"<path d=\\\"M8 17c0-3-3-3.8-3-8a7 7 0 1 1 14 0c0 4.2-3 5-3 8M8 18h8M9 22h6\\\"\/>\",\r\n  \"space\": \"<path d=\\\"M3 21V5l9-3 9 3v16H3ZM12 2v19M3 12l9-3 9 3\\\"\/>\",\r\n  \"file\": \"<path d=\\\"M5 2h9l5 5v15H5ZM14 2v6h5M8 12h8M8 16h8\\\"\/>\",\r\n  \"image\": \"<rect x=\\\"2\\\" y=\\\"3\\\" width=\\\"20\\\" height=\\\"18\\\" rx=\\\"2\\\"\/><circle cx=\\\"8\\\" cy=\\\"8\\\" r=\\\"2\\\"\/><path d=\\\"m2 18 6-6 4 4 4-5 6 7\\\"\/>\",\r\n  \"screen\": \"<rect x=\\\"2\\\" y=\\\"3\\\" width=\\\"20\\\" height=\\\"14\\\" rx=\\\"2\\\"\/><path d=\\\"M8 22h8M12 17v5\\\"\/>\",\r\n  \"mobile\": \"<rect x=\\\"6\\\" y=\\\"1\\\" width=\\\"12\\\" height=\\\"22\\\" rx=\\\"2\\\"\/><path d=\\\"M10 18h4\\\"\/>\",\r\n  \"clock\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\"\/><path d=\\\"M12 5v7l4 3\\\"\/>\",\r\n  \"target\": \"<circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"10\\\"\/><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"6\\\"\/><circle cx=\\\"12\\\" cy=\\\"12\\\" r=\\\"2\\\"\/>\",\r\n  \"calendar\": \"<rect x=\\\"3\\\" y=\\\"5\\\" width=\\\"18\\\" height=\\\"17\\\" rx=\\\"2\\\"\/><path d=\\\"M7 2v6M17 2v6M3 11h18M8 15h2M14 15h2M8 18h2\\\"\/>\",\r\n  \"layers\": \"<path d=\\\"m12 2 10 6-10 6L2 8ZM2 12l10 6 10-6M2 16l10 6 10-6\\\"\/>\",\r\n  \"chat\": \"<path d=\\\"M22 11a9 9 0 0 1-9 9H8l-6 3 2-6a9 9 0 1 1 18-6Z\\\"\/>\",\r\n  \"flag\": \"<path d=\\\"M4 22V3m0 0c5-4 11 4 16 0v12c-5 4-11-4-16 0\\\"\/>\",\r\n  \"wallet\": \"<rect x=\\\"2\\\" y=\\\"5\\\" width=\\\"20\\\" height=\\\"16\\\" rx=\\\"2\\\"\/><path d=\\\"M2 7V4l15-3v4M16 11h6v5h-6Z\\\"\/>\"\r\n};\r\n\r\nconst STEPS = [\r\n  {\r\n    \"key\": \"goal\",\r\n    \"label\": \"Objectif\",\r\n    \"title\": \"Qu\u2019aimeriez-vous accomplir ?\",\r\n    \"note\": \"Choisissez votre objectif principal. La proposition partira de votre besoin.\",\r\n    \"options\": [\r\n      [\r\n        \"launch\",\r\n        \"Lancer un produit\",\r\n        \"Cr\u00e9er l\u2019envie et r\u00e9v\u00e9ler une nouveaut\u00e9.\",\r\n        \"spark\"\r\n      ],\r\n      [\r\n        \"sell\",\r\n        \"Mieux pr\u00e9senter un produit\",\r\n        \"Des visuels clairs pour convaincre et vendre.\",\r\n        \"cart\"\r\n      ],\r\n      [\r\n        \"explain\",\r\n        \"Expliquer simplement\",\r\n        \"Rendre un fonctionnement ou une id\u00e9e accessible.\",\r\n        \"play\"\r\n      ],\r\n      [\r\n        \"space\",\r\n        \"Pr\u00e9senter un espace\",\r\n        \"Donner \u00e0 voir un lieu, un stand ou un am\u00e9nagement.\",\r\n        \"space\"\r\n      ]\r\n    ],\r\n    \"hint\": \"Pas besoin de conna\u00eetre les termes techniques : partez de votre objectif.\"\r\n  },\r\n  {\r\n    \"key\": \"subject\",\r\n    \"label\": \"Sujet\",\r\n    \"title\": \"Qu\u2019allons-nous mettre en sc\u00e8ne ?\",\r\n    \"note\": \"Choisissez le sujet principal de votre projet.\",\r\n    \"options\": [\r\n      [\r\n        \"product\",\r\n        \"Un produit ou un objet\",\r\n        \"Mobilier, cosm\u00e9tique, \u00e9quipement, objet\u2026\",\r\n        \"box\"\r\n      ],\r\n      [\r\n        \"packaging\",\r\n        \"Un packaging\",\r\n        \"Bouteille, coffret, \u00e9tiquette, emballage\u2026\",\r\n        \"layers\"\r\n      ],\r\n      [\r\n        \"environment\",\r\n        \"Un espace ou un lieu\",\r\n        \"Architecture, showroom, stand, d\u00e9cor\u2026\",\r\n        \"space\"\r\n      ],\r\n      [\r\n        \"service\",\r\n        \"Un service ou un concept\",\r\n        \"Processus, innovation, message de marque\u2026\",\r\n        \"idea\"\r\n      ]\r\n    ],\r\n    \"hint\": \"Vous avez plusieurs sujets ? Vous pourrez les pr\u00e9ciser dans votre demande.\"\r\n  },\r\n  {\r\n    \"key\": \"assets\",\r\n    \"label\": \"\u00c9l\u00e9ments\",\r\n    \"title\": \"De quoi disposez-vous d\u00e9j\u00e0 ?\",\r\n    \"note\": \"Plusieurs r\u00e9ponses possibles. Une simple id\u00e9e suffit pour commencer.\",\r\n    \"multi\": true,\r\n    \"options\": [\r\n      [\r\n        \"model\",\r\n        \"Un fichier 3D\",\r\n        \"Un mod\u00e8le existant, \u00e0 v\u00e9rifier et pr\u00e9parer.\",\r\n        \"box\"\r\n      ],\r\n      [\r\n        \"plans\",\r\n        \"Des plans ou des dimensions\",\r\n        \"Plans techniques, cotes ou croquis.\",\r\n        \"file\"\r\n      ],\r\n      [\r\n        \"photos\",\r\n        \"Des photos ou r\u00e9f\u00e9rences\",\r\n        \"Produit, inspirations ou univers de marque.\",\r\n        \"image\"\r\n      ],\r\n      [\r\n        \"nothing\",\r\n        \"L\u2019id\u00e9e, pour le moment\",\r\n        \"Tout reste \u00e0 construire ensemble.\",\r\n        \"idea\"\r\n      ]\r\n    ],\r\n    \"exclusive\": \"nothing\",\r\n    \"hint\": \"Ces \u00e9l\u00e9ments servent \u00e0 estimer le travail de cr\u00e9ation. Aucun fichier \u00e0 importer ici.\"\r\n  },\r\n  {\r\n    \"key\": \"channels\",\r\n    \"label\": \"Supports\",\r\n    \"title\": \"O\u00f9 vos visuels seront-ils diffus\u00e9s ?\",\r\n    \"note\": \"S\u00e9lectionnez tous les supports envisag\u00e9s.\",\r\n    \"multi\": true,\r\n    \"options\": [\r\n      [\r\n        \"web\",\r\n        \"Site & e-commerce\",\r\n        \"Fiches produit, page de lancement, site vitrine.\",\r\n        \"screen\"\r\n      ],\r\n      [\r\n        \"social\",\r\n        \"R\u00e9seaux sociaux & publicit\u00e9\",\r\n        \"Contenus courts et formats verticaux ou carr\u00e9s.\",\r\n        \"mobile\"\r\n      ],\r\n      [\r\n        \"event\",\r\n        \"Salon & pr\u00e9sentation\",\r\n        \"\u00c9cran, stand, d\u00e9monstration commerciale.\",\r\n        \"play\"\r\n      ],\r\n      [\r\n        \"print\",\r\n        \"Impression & \u00e9dition\",\r\n        \"Catalogue, affiche ou brochure.\",\r\n        \"image\"\r\n      ]\r\n    ],\r\n    \"hint\": \"Le bon cadrage et les bons formats se pr\u00e9voient d\u00e8s le d\u00e9but du projet.\"\r\n  },\r\n  {\r\n    \"key\": \"timing\",\r\n    \"label\": \"Calendrier\",\r\n    \"title\": \"Quel est votre horizon ?\",\r\n    \"note\": \"Un premier rep\u00e8re, \u00e0 confirmer ensemble selon le p\u00e9rim\u00e8tre.\",\r\n    \"options\": [\r\n      [\r\n        \"urgent\",\r\n        \"D\u00e8s que possible\",\r\n        \"Moins de 2 semaines, sous r\u00e9serve de faisabilit\u00e9.\",\r\n        \"clock\"\r\n      ],\r\n      [\r\n        \"month\",\r\n        \"Dans le mois\",\r\n        \"Une \u00e9ch\u00e9ance proche \u00e0 organiser ensemble.\",\r\n        \"calendar\"\r\n      ],\r\n      [\r\n        \"quarter\",\r\n        \"Dans 1 \u00e0 3 mois\",\r\n        \"Le temps de construire le projet sereinement.\",\r\n        \"flag\"\r\n      ],\r\n      [\r\n        \"flexible\",\r\n        \"Je suis flexible\",\r\n        \"Je pr\u00e9pare mon projet, sans date pr\u00e9cise.\",\r\n        \"chat\"\r\n      ]\r\n    ],\r\n    \"hint\": \"Vous pourrez indiquer une date exacte ou une contrainte de lancement dans le brief.\"\r\n  },\r\n  {\r\n    \"key\": \"budget\",\r\n    \"label\": \"Budget\",\r\n    \"title\": \"Quelle enveloppe envisagez-vous ?\",\r\n    \"note\": \"Un budget indicatif HT pour adapter la proposition \u00e0 vos priorit\u00e9s.\",\r\n    \"options\": [\r\n      [\r\n        \"small\",\r\n        \"Moins de 1 000 \u20ac\",\r\n        \"Un besoin cibl\u00e9, \u00e0 cadrer pr\u00e9cis\u00e9ment.\",\r\n        \"wallet\"\r\n      ],\r\n      [\r\n        \"medium\",\r\n        \"1 000 \u00e0 2 500 \u20ac\",\r\n        \"Une premi\u00e8re enveloppe de production.\",\r\n        \"wallet\"\r\n      ],\r\n      [\r\n        \"large\",\r\n        \"2 500 \u00e0 5 000 \u20ac\",\r\n        \"Un projet avec plusieurs livrables possibles.\",\r\n        \"layers\"\r\n      ],\r\n      [\r\n        \"xl\",\r\n        \"5 000 \u00e0 10 000 \u20ac\",\r\n        \"Un dispositif plus complet.\",\r\n        \"layers\"\r\n      ],\r\n      [\r\n        \"premium\",\r\n        \"Plus de 10 000 \u20ac\",\r\n        \"Un projet ambitieux, \u00e0 construire sur mesure.\",\r\n        \"spark\"\r\n      ],\r\n      [\r\n        \"unknown\",\r\n        \"\u00c0 d\u00e9finir ensemble\",\r\n        \"J\u2019aimerais d\u2019abord \u00eatre conseill\u00e9.\",\r\n        \"chat\"\r\n      ]\r\n    ],\r\n    \"hint\": \"Votre enveloppe nous aide \u00e0 prioriser les livrables. Le prix sera confirm\u00e9 dans un devis personnalis\u00e9.\"\r\n  }\r\n];\r\n\r\n\/* OK3D \/ Configurateur v2. Aucun secret ou service externe c\u00f4t\u00e9 navigateur. *\/\r\nconst CONFIG = Object.freeze({\r\n  email: 'contact@ok3d.fr',\r\n  endpoint: '\/wp-json\/ok3d\/v1\/devis',\r\n  privacy: 'https:\/\/www.ok3d.fr\/politique-de-confidentialite\/',\r\n  storageKey: 'ok3d-project-configurator-v2',\r\n  timeoutMs: 15000\r\n});\r\n\r\nconst panel = root.querySelector('#okp-panel');\r\nconst nav = root.querySelector('#okp-steps');\r\nconst summary = root.querySelector('#okp-summary');\r\nconst workspace = root.querySelector('#okp-workspace');\r\nconst resetButton = root.querySelector('#okp-reset');\r\nconst toast = root.querySelector('#okp-toast');\r\nconst nativeSend = ['ok3d.fr', 'www.ok3d.fr'].includes(window.location.hostname);\r\nconst entryParams = new URLSearchParams(window.location.search);\r\nconst entryFromKeystroke = entryParams.get('source') === 'keystroke';\r\nconst entrySoftwares = ['Illustrator','Photoshop','InDesign','After Effects','Figma','Blender','Cinema 4D','Maya','3ds Max','ZBrush','Substance 3D Painter'];\r\nconst entrySoftware = entrySoftwares.includes(entryParams.get('logiciel')) ? entryParams.get('logiciel') : '';\r\nif(entryFromKeystroke){\r\n  const banner=document.createElement('div');banner.className='okp-origin';\r\n  const text=document.createElement('span');text.textContent='Bienvenue depuis Keystroke'+(entrySoftware?' \u00b7 '+entrySoftware:'')+'. Parlons maintenant de votre projet.';\r\n  const link=document.createElement('a');link.href='https:\/\/www.ok3d.fr\/keystroke\/';link.textContent='Retour \u00e0 Keystroke \u2197';\r\n  banner.append(text,link);root.querySelector('.okp-hero-copy').append(banner);\r\n}\r\nconst reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');\r\n\r\nlet state = { step: 0, answers: {} };\r\nlet contact = { nom: '', email: '', societe: '', projet: '' };\r\nlet isSending = false;\r\nlet isSent = false;\r\nlet resetArmed = false;\r\nlet resetTimer;\r\nlet toastTimer;\r\n\r\nfunction escapeHTML(value) {\r\n  return String(value ?? '').replace(\/[&<>\"']\/g, character => ({\r\n    '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;'\r\n  })[character]);\r\n}\r\n\r\nfunction icon(name) {\r\n  return '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">' +\r\n    (ICON_PATHS[name] || ICON_PATHS.box) + '<\/svg>';\r\n}\r\n\r\nfunction arrow() {\r\n  return '<svg viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\" aria-hidden=\"true\"><path d=\"M4 16 16 4M4 4h12v12\"\/><\/svg>';\r\n}\r\n\r\nfunction answered(step) {\r\n  const answer = state.answers[step.key];\r\n  return step.multi ? Array.isArray(answer) && answer.length > 0 : Boolean(answer);\r\n}\r\n\r\nfunction answerLabels(key) {\r\n  const step = STEPS.find(item => item.key === key);\r\n  const answer = state.answers[key];\r\n  return step.options\r\n    .filter(option => Array.isArray(answer) ? answer.includes(option[0]) : answer === option[0])\r\n    .map(option => option[1]).join(', ');\r\n}\r\n\r\n\/* Les coordonn\u00e9es ne sont jamais conserv\u00e9es dans sessionStorage. *\/\r\nfunction persist() {\r\n  try {\r\n    sessionStorage.setItem(CONFIG.storageKey, JSON.stringify({\r\n      version: 2, step: Math.min(state.step, 6), answers: state.answers\r\n    }));\r\n  } catch (_) { \/* Le parcours reste utilisable si le stockage est bloqu\u00e9. *\/ }\r\n}\r\n\r\nfunction restore() {\r\n  try {\r\n    const saved = JSON.parse(sessionStorage.getItem(CONFIG.storageKey));\r\n    if (!saved || saved.version !== 2 || !saved.answers || typeof saved.answers !== 'object') return;\r\n    for (const step of STEPS) {\r\n      const valid = new Set(step.options.map(option => option[0]));\r\n      const answer = saved.answers[step.key];\r\n      if (step.multi && Array.isArray(answer)) {\r\n        const selected = [...new Set(answer.filter(value => valid.has(value)))];\r\n        state.answers[step.key] = step.exclusive && selected.includes(step.exclusive)\r\n          ? [step.exclusive] : selected;\r\n      } else if (!step.multi && valid.has(answer)) {\r\n        state.answers[step.key] = answer;\r\n      }\r\n    }\r\n    const missing = STEPS.findIndex(step => !answered(step));\r\n    const wanted = Number.isInteger(saved.step) ? Math.max(0, Math.min(6, saved.step)) : 0;\r\n    state.step = Math.min(wanted, missing === -1 ? 6 : missing);\r\n  } catch (_) { \/* Donn\u00e9es de session absentes ou invalides : d\u00e9part \u00e0 z\u00e9ro. *\/ }\r\n}\r\n\r\nfunction recommendation() {\r\n  const a = state.answers;\r\n  let title, introduction, deliverables;\r\n\r\n  if (a.subject === 'environment') {\r\n    title = 'Faire exister votre espace.';\r\n    introduction = 'Une mise en sc\u00e8ne 3D pour rendre votre lieu ou votre am\u00e9nagement concret, avant m\u00eame sa r\u00e9alisation.';\r\n    deliverables = [\r\n      ['Construire la bonne perspective', 'D\u00e9finir les points de vue et les volumes \u00e0 partir de vos plans, cotes et r\u00e9f\u00e9rences.'],\r\n      ['Cr\u00e9er les images du lieu', 'Travailler les mat\u00e9riaux, les lumi\u00e8res et l\u2019ambiance pour raconter l\u2019espace avec justesse.'],\r\n      ['Explorer le mouvement, si utile', 'Envisager une visite anim\u00e9e ou une s\u00e9quence de pr\u00e9sentation selon vos supports et votre budget.']\r\n    ];\r\n  } else if (a.subject === 'service') {\r\n    title = 'Rendre votre id\u00e9e \u00e9vidente.';\r\n    introduction = 'Un r\u00e9cit visuel pour transformer votre message en une histoire claire, accessible et m\u00e9morable.';\r\n    deliverables = [\r\n      ['Structurer votre message', 'D\u00e9finir les id\u00e9es essentielles, le sc\u00e9nario et une direction artistique adapt\u00e9e \u00e0 votre marque.'],\r\n      ['Trouver le bon langage visuel', 'Choisir entre motion design et animation 3D selon ce qu\u2019il faut montrer, expliquer ou faire ressentir.'],\r\n      ['Pr\u00e9parer les bonnes d\u00e9clinaisons', 'Adapter le rythme, la dur\u00e9e et les formats aux supports retenus.']\r\n    ];\r\n  } else if (a.goal === 'explain') {\r\n    title = 'R\u00e9v\u00e9ler ce qui fait la diff\u00e9rence.';\r\n    introduction = 'Une d\u00e9monstration visuelle pour montrer le fonctionnement, les d\u00e9tails ou les b\u00e9n\u00e9fices de votre produit.';\r\n    deliverables = [\r\n      ['Poser un d\u00e9roul\u00e9 clair', 'Construire un storyboard autour des messages et des gestes essentiels.'],\r\n      ['Montrer ce que l\u2019on ne voit pas', 'Pr\u00e9voir les vues de d\u00e9tail, mouvements et \u00e9ventuels \u00e9clat\u00e9s techniques utiles \u00e0 la compr\u00e9hension.'],\r\n      ['D\u00e9cliner la d\u00e9monstration', 'Identifier les s\u00e9quences et les images fixes qui pourront enrichir vos autres supports.']\r\n    ];\r\n  } else if (a.goal === 'sell') {\r\n    title = 'Votre produit, sous le bon angle.';\r\n    introduction = 'Des images pr\u00e9cises et coh\u00e9rentes pour pr\u00e9senter votre produit, rassurer et faciliter sa d\u00e9couverte.';\r\n    deliverables = [\r\n      ['Cr\u00e9er une base produit fid\u00e8le', 'Pr\u00e9parer ou mod\u00e9liser le produit avec une attention port\u00e9e aux proportions, aux mat\u00e9riaux et aux finitions.'],\r\n      ['D\u00e9finir les vues essentielles', 'Choisir les cadrages, d\u00e9tails et variantes utiles \u00e0 votre pr\u00e9sentation commerciale.'],\r\n      ['Enrichir l\u2019univers du produit', '\u00c9tudier une mise en situation ou une animation courte si elle apporte une valeur r\u00e9elle au projet.']\r\n    ];\r\n  } else if (a.goal === 'space') {\r\n    title = 'Installer votre produit dans son univers.';\r\n    introduction = 'Une mise en situation pour donner du contexte \u00e0 votre produit ou \u00e0 votre packaging et rendre son usage plus tangible.';\r\n    deliverables = [\r\n      ['Imaginer la mise en sc\u00e8ne', 'D\u00e9finir le d\u00e9cor, les cadrages et la place du produit dans l\u2019image.'],\r\n      ['Donner du caract\u00e8re \u00e0 la mati\u00e8re', 'Travailler l\u2019\u00e9clairage, les textures et les d\u00e9tails qui rendent l\u2019ensemble convaincant.'],\r\n      ['Pr\u00e9voir les bonnes d\u00e9clinaisons', 'S\u00e9lectionner les vues et les formats adapt\u00e9s \u00e0 vos supports de diffusion.']\r\n    ];\r\n  } else {\r\n    title = 'Donner de l\u2019impact \u00e0 votre lancement.';\r\n    introduction = 'Un univers visuel coh\u00e9rent pour r\u00e9v\u00e9ler votre nouveaut\u00e9 et accompagner sa d\u00e9couverte sur vos diff\u00e9rents supports.';\r\n    deliverables = [\r\n      ['D\u00e9finir l\u2019image du lancement', 'Construire une direction artistique et une composition qui mettent votre produit au premier plan.'],\r\n      ['Cr\u00e9er les vues compl\u00e9mentaires', 'Choisir les angles et les d\u00e9tails qui racontent le produit et enrichissent sa pr\u00e9sentation.'],\r\n      ['\u00c9tudier une r\u00e9v\u00e9lation anim\u00e9e', 'Envisager une courte s\u00e9quence de lancement si votre budget et votre calendrier le permettent.']\r\n    ];\r\n  }\r\n\r\n  if (a.budget === 'small') {\r\n    deliverables = [deliverables[0], [\r\n      a.subject === 'service' || a.goal === 'explain' ? 'Cibler un premier contenu explicatif' : 'Prioriser un premier visuel',\r\n      'R\u00e9duire le p\u00e9rim\u00e8tre \u00e0 l\u2019essentiel. Le format et la faisabilit\u00e9 seront d\u00e9finis avant de proposer un prix.'\r\n    ]];\r\n  }\r\n\r\n  const assets = a.assets || [];\r\n  const preparation = assets.includes('model')\r\n    ? 'Votre fichier 3D sera v\u00e9rifi\u00e9 avant production : sa pr\u00e9sence ne garantit pas qu\u2019il soit directement exploitable.'\r\n    : assets.includes('nothing')\r\n      ? 'Une premi\u00e8re phase de cadrage permettra de r\u00e9unir les r\u00e9f\u00e9rences et les informations n\u00e9cessaires \u00e0 la cr\u00e9ation.'\r\n      : 'Vos plans, photos et r\u00e9f\u00e9rences serviront \u00e0 cadrer la mod\u00e9lisation et le niveau de fid\u00e9lit\u00e9 attendu.';\r\n\r\n  const formatMap = {\r\n    web: 'exports optimis\u00e9s pour le web',\r\n    social: 'd\u00e9clinaisons carr\u00e9es ou verticales',\r\n    event: 'formats adapt\u00e9s aux \u00e9crans de diffusion',\r\n    print: 'exports haute d\u00e9finition selon le format d\u2019impression'\r\n  };\r\n  const formats = (a.channels || []).map(channel => formatMap[channel]).filter(Boolean).join(' ; ');\r\n  const budget = a.budget === 'small'\r\n    ? 'Votre enveloppe invite \u00e0 privil\u00e9gier un livrable cibl\u00e9. Une sc\u00e8ne complexe ou une animation compl\u00e8te pourra demander un budget sup\u00e9rieur.'\r\n    : a.budget === 'unknown'\r\n      ? 'Votre enveloppe sera d\u00e9finie ensemble, \u00e0 partir des priorit\u00e9s, de la complexit\u00e9 et du nombre de livrables.'\r\n      : 'Votre enveloppe envisag\u00e9e : ' + answerLabels('budget') + ' HT. Elle ne constitue pas un tarif OK3D : le montant sera confirm\u00e9 dans un devis personnalis\u00e9.';\r\n  const timing = a.timing === 'urgent'\r\n    ? 'Votre \u00e9ch\u00e9ance est courte : la disponibilit\u00e9 et la faisabilit\u00e9 devront \u00eatre confirm\u00e9es avant tout engagement.'\r\n    : '';\r\n\r\n  return { title, introduction, deliverables, preparation, formats, budget, timing };\r\n}\r\n\r\nfunction buildBrief(includeContact = true) {\r\n  const complete = STEPS.every(answered);\r\n  const result = complete ? recommendation() : null;\r\n  const lines = ['BRIEF DE PROJET \u2014 OK3D', '', ...STEPS.map(step => step.label + ' : ' + (answerLabels(step.key) || '\u00c0 pr\u00e9ciser'))];\r\n  if(entryFromKeystroke) lines.push('', 'D\u00c9COUVERTE DU STUDIO', 'Keystroke OK3D'+(entrySoftware?' \u2014 logiciel consult\u00e9 : '+entrySoftware:''));\r\n  if (result) {\r\n    lines.push('', 'PREMI\u00c8RE DIRECTION', result.title, result.introduction,\r\n      ...result.deliverables.map(item => '\u2022 ' + item[0] + ' \u2014 ' + item[1]),\r\n      '', 'PR\u00c9PARATION', result.preparation, '', 'DIFFUSION', result.formats,\r\n      '', 'CADRAGE', result.budget);\r\n    if (result.timing) lines.push(result.timing);\r\n  }\r\n  if (includeContact) {\r\n    lines.push('', 'COORDONN\u00c9ES', 'Nom : ' + (contact.nom || '\u00c0 pr\u00e9ciser'),\r\n      'Email : ' + (contact.email || '\u00c0 pr\u00e9ciser'), 'Entreprise : ' + (contact.societe || 'Non renseign\u00e9e'),\r\n      '', 'PR\u00c9CISIONS', contact.projet || '\u00c0 pr\u00e9ciser ensemble.');\r\n  }\r\n  lines.push('', 'Recommandation indicative. Le contenu et le tarif feront l\u2019objet d\u2019un devis personnalis\u00e9.');\r\n  return lines.join('\\n');\r\n}\r\n\r\nfunction payload() {\r\n  return {\r\n    nom: contact.nom,\r\n    email: contact.email,\r\n    societe: contact.societe,\r\n    tel: '', ref: '',\r\n    services: ['3D \/ Animation'],\r\n    projet: buildBrief(false) + '\\n\\nPR\u00c9CISIONS DU CLIENT\\n' + (contact.projet || '\u00c0 pr\u00e9ciser ensemble.'),\r\n    budget: answerLabels('budget'),\r\n    delai: answerLabels('timing'),\r\n    website: ''\r\n  };\r\n}\r\n\r\nfunction mailtoURL() {\r\n  return 'mailto:' + CONFIG.email + '?subject=' + encodeURIComponent('Demande de devis \u2014 ' + (contact.societe || contact.nom || 'Projet 3D')) +\r\n    '&body=' + encodeURIComponent('Bonjour J\u00e9r\u00e9my,\\n\\nJe souhaite \u00e9changer sur le projet suivant.\\n\\n' + buildBrief() + '\\n\\nMerci et \u00e0 bient\u00f4t,\\n' + contact.nom);\r\n}\r\n\r\nfunction notify(message) {\r\n  clearTimeout(toastTimer);\r\n  toast.textContent = message;\r\n  toast.classList.add('is-visible');\r\n  toastTimer = setTimeout(() => toast.classList.remove('is-visible'), 5000);\r\n}\r\n\r\nfunction captureContact() {\r\n  const form = panel.querySelector('#okp-contact');\r\n  if (!form) return;\r\n  for (const key of Object.keys(contact)) contact[key] = form.elements.namedItem(key).value.trim();\r\n}\r\n\r\nfunction updateChrome() {\r\n  nav.innerHTML = STEPS.map((step, index) => {\r\n    const available = index <= state.step || STEPS.slice(0, index).every(answered);\r\n    const current = state.step === index;\r\n    return '<button type=\"button\" class=\"okp-step ' + (answered(step) && !current ? 'is-done' : '') + '\" data-step=\"' + index + '\"' +\r\n      (current ? ' aria-current=\"step\"' : '') + (!available || isSending ? ' disabled' : '') +\r\n      '><span class=\"okp-step-num\">' + (answered(step) && !current ? '\u2713' : String(index + 1).padStart(2, '0')) +\r\n      '<\/span><span>' + escapeHTML(step.label) + '<\/span><\/button>';\r\n  }).join('');\r\n  summary.innerHTML = STEPS.map(step => '<div class=\"okp-summary-row\"><dt>' + escapeHTML(step.label) + '<\/dt><dd class=\"' +\r\n    (!answered(step) ? 'is-empty' : '') + '\">' + escapeHTML(answerLabels(step.key) || '\u00c0 pr\u00e9ciser') + '<\/dd><\/div>').join('');\r\n  root.querySelector('#okp-count').textContent = STEPS.filter(answered).length + ' \/ 6';\r\n  resetButton.disabled = isSending;\r\n}\r\n\r\nfunction questionHTML() {\r\n  const step = STEPS[state.step];\r\n  const options = step.options.map(option => {\r\n    const selected = step.multi\r\n      ? (state.answers[step.key] || []).includes(option[0])\r\n      : state.answers[step.key] === option[0];\r\n    return '<label class=\"okp-option ' + (selected ? 'is-selected' : '') + '\">' +\r\n      '<input type=\"' + (step.multi ? 'checkbox' : 'radio') + '\" name=\"okp-' + step.key + '\" value=\"' + option[0] + '\"' + (selected ? ' checked' : '') + '>' +\r\n      '<span class=\"okp-option-icon\">' + icon(option[3]) + '<\/span>' +\r\n      '<span class=\"okp-option-title\">' + escapeHTML(option[1]) + '<\/span>' +\r\n      '<span class=\"okp-option-description\">' + escapeHTML(option[2]) + '<\/span>' +\r\n      '<span class=\"okp-check\" aria-hidden=\"true\">\u2713<\/span><\/label>';\r\n  }).join('');\r\n\r\n  return '<div class=\"okp-panel-top\"><span class=\"okp-kicker\">' + escapeHTML(step.label) + ' \/ POSONS LES BASES<\/span>' +\r\n    '<span class=\"okp-step-counter\">0' + (state.step + 1) + ' \/ 06<\/span><\/div>' +\r\n    '<div class=\"okp-progress\" role=\"progressbar\" aria-label=\"\u00c9tape du parcours\" aria-valuemin=\"1\" aria-valuemax=\"6\" aria-valuenow=\"' + (state.step + 1) + '\">' +\r\n    '<div class=\"okp-progress-fill\" style=\"width:' + ((state.step + 1) \/ 6 * 100) + '%\"><\/div><\/div>' +\r\n    '<h2 id=\"okp-question\" tabindex=\"-1\">' + escapeHTML(step.title) + '<\/h2>' +\r\n    '<p id=\"okp-question-description\" class=\"okp-question-note\">' + escapeHTML(step.note) + '<\/p>' +\r\n    '<fieldset class=\"okp-options ' + (step.multi ? 'is-multiple' : '') + '\" aria-labelledby=\"okp-question\" aria-describedby=\"okp-question-description\">' + options + '<\/fieldset>' +\r\n    '<div class=\"okp-tip\"><span aria-hidden=\"true\">\u21b3<\/span><p>' + escapeHTML(step.hint) + '<\/p><\/div>' +\r\n    '<div class=\"okp-navigation\"><button type=\"button\" class=\"okp-text-btn okp-back\" data-action=\"back\"' + (state.step === 0 ? ' style=\"visibility:hidden\" tabindex=\"-1\"' : '') + '>\u2190 Retour<\/button>' +\r\n    '<button type=\"button\" class=\"okp-btn\" data-action=\"next\"' + (!answered(step) ? ' disabled' : '') + '>' +\r\n    (state.step === 5 ? 'Voir ma recommandation' : 'Continuer') + arrow() + '<\/button><\/div>';\r\n}\r\n\r\nfunction resultHTML() {\r\n  const result = recommendation();\r\n  return '<span class=\"okp-result-label\">\u2713 UNE PREMI\u00c8RE DIRECTION POUR VOTRE PROJET<\/span>' +\r\n    '<h2 tabindex=\"-1\">' + escapeHTML(result.title) + '<\/h2>' +\r\n    '<p class=\"okp-result-intro\">' + escapeHTML(result.introduction) + '<\/p>' +\r\n    '<div class=\"okp-deliverables\">' + result.deliverables.map((item, index) =>\r\n      '<div class=\"okp-deliverable\"><span class=\"okp-deliverable-number\">0' + (index + 1) + '<\/span><div><h3>' +\r\n      escapeHTML(item[0]) + '<\/h3><p>' + escapeHTML(item[1]) + '<\/p><\/div><\/div>'\r\n    ).join('') + '<\/div>' +\r\n    '<div class=\"okp-tip\"><span aria-hidden=\"true\">\u21b3<\/span><p>' + escapeHTML(result.preparation) + '<\/p><\/div>' +\r\n    '<div class=\"okp-result-note\"><strong>Un p\u00e9rim\u00e8tre \u00e0 construire ensemble.<\/strong><p>' + escapeHTML(result.budget) +\r\n    '<\/p><p>Diffusion : ' + escapeHTML(result.formats) + '.<\/p>' + (result.timing ? '<p>' + escapeHTML(result.timing) + '<\/p>' : '') + '<\/div>' +\r\n    '<button type=\"button\" class=\"okp-btn is-full\" data-action=\"contact\">Recevoir une proposition sur mesure' + arrow() + '<\/button>' +\r\n    '<p class=\"okp-small-note\">Sans engagement. Vous \u00e9changez directement avec le studio.<\/p>' +\r\n    '<div class=\"okp-actions\"><button type=\"button\" class=\"okp-text-btn\" data-action=\"copy\">Copier le brief<\/button>' +\r\n    '<button type=\"button\" class=\"okp-text-btn\" data-action=\"download\">T\u00e9l\u00e9charger le brief \u2193<\/button>' +\r\n    '<button type=\"button\" class=\"okp-text-btn\" data-action=\"edit\">Modifier mes r\u00e9ponses<\/button><\/div>';\r\n}\r\n\r\nfunction contactHTML() {\r\n  const buttonLabel = nativeSend ? 'Envoyer mon brief \u00e0 OK3D' : 'Ouvrir mon email de demande';\r\n  const sendNote = nativeSend\r\n    ? 'Ces informations servent uniquement \u00e0 r\u00e9pondre \u00e0 votre demande. Vos coordonn\u00e9es ne sont pas enregistr\u00e9es dans le navigateur par ce module.'\r\n    : 'Ce bouton ouvre votre messagerie avec votre brief pr\u00e9rempli. Vous relisez et envoyez vous-m\u00eame le message \u00e0 ' + CONFIG.email + '.';\r\n  return '<span class=\"okp-result-label\">02 \/ PASSER DE L\u2019ID\u00c9E AU PROJET<\/span>' +\r\n    '<h2 tabindex=\"-1\">Et si on cr\u00e9ait la suite ?<\/h2>' +\r\n    '<p class=\"okp-result-intro\">Les grandes lignes sont pos\u00e9es. Ajoutez vos coordonn\u00e9es et, si vous le souhaitez, quelques pr\u00e9cisions pour pr\u00e9parer notre \u00e9change.<\/p>' +\r\n    '<details class=\"okp-brief-details\"><summary>Relire le brief qui sera transmis<\/summary><pre>' + escapeHTML(buildBrief(false)) + '<\/pre><\/details>' +\r\n    '<form id=\"okp-contact\" class=\"okp-form\"><fieldset class=\"okp-form-fields\">' +\r\n    '<div class=\"okp-field-row\"><label class=\"okp-field\"><span>Votre nom *<\/span><input name=\"nom\" autocomplete=\"name\" required minlength=\"2\" maxlength=\"100\" placeholder=\"Pr\u00e9nom et nom\" value=\"' + escapeHTML(contact.nom) + '\"><\/label>' +\r\n    '<label class=\"okp-field\"><span>Votre email *<\/span><input type=\"email\" name=\"email\" autocomplete=\"email\" required maxlength=\"160\" placeholder=\"vous@entreprise.fr\" value=\"' + escapeHTML(contact.email) + '\"><\/label><\/div>' +\r\n    '<label class=\"okp-field\"><span>Entreprise <small>(facultatif)<\/small><\/span><input name=\"societe\" autocomplete=\"organization\" maxlength=\"160\" placeholder=\"Votre marque ou votre entreprise\" value=\"' + escapeHTML(contact.societe) + '\"><\/label>' +\r\n    '<label class=\"okp-field\"><span>Votre projet en quelques mots <small>(facultatif)<\/small><\/span><textarea name=\"projet\" maxlength=\"2000\" placeholder=\"Nombre de produits, livrables souhait\u00e9s, date pr\u00e9cise, liens de r\u00e9f\u00e9rence\u2026\">' + escapeHTML(contact.projet) + '<\/textarea><\/label>' +\r\n    '<div class=\"okp-honeypot\" aria-hidden=\"true\"><label>Ne pas remplir ce champ<input name=\"website\" type=\"text\" tabindex=\"-1\" autocomplete=\"off\"><\/label><\/div>' +\r\n    '<\/fieldset><p class=\"okp-privacy\">' + escapeHTML(sendNote) + ' <a href=\"' + CONFIG.privacy + '\" target=\"_blank\" rel=\"noopener\">Confidentialit\u00e9<\/a>.<\/p>' +\r\n    '<button class=\"okp-btn is-full okp-submit\" type=\"submit\" id=\"okp-send\">' + buttonLabel + arrow() + '<\/button>' +\r\n    '<div id=\"okp-form-status\" class=\"okp-form-status\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\"><\/div>' +\r\n    '<div id=\"okp-fallback\" class=\"okp-fallback\" hidden><p>Vous pouvez aussi <a href=\"' + escapeHTML(mailtoURL()) + '\" id=\"okp-email-link\">pr\u00e9parer un email<\/a> ou copier votre brief et l\u2019adresser \u00e0 ' + CONFIG.email + '.<\/p>' +\r\n    '<button class=\"okp-text-btn\" type=\"button\" data-action=\"copy\">Copier le brief complet<\/button><\/div><\/form>' +\r\n    '<div class=\"okp-actions\"><button class=\"okp-text-btn\" type=\"button\" data-action=\"back\">\u2190 Ma recommandation<\/button>' +\r\n    '<button class=\"okp-text-btn\" type=\"button\" data-action=\"download\">T\u00e9l\u00e9charger le brief \u2193<\/button><\/div>';\r\n}\r\n\r\nfunction successHTML() {\r\n  return '<span class=\"okp-success-icon\" aria-hidden=\"true\">\u2713<\/span><span class=\"okp-result-label\">LE PROJET EST ENTRE DE BONNES MAINS<\/span>' +\r\n    '<h2 tabindex=\"-1\">Merci pour votre confiance.<\/h2>' +\r\n    '<p class=\"okp-result-intro\">Votre demande a bien \u00e9t\u00e9 transmise \u00e0 OK3D. Je prendrai connaissance de votre brief pour revenir vers vous avec les prochaines \u00e9tapes.<\/p>' +\r\n    '<div class=\"okp-result-note\"><strong>Et maintenant ?<\/strong><p>Nous pr\u00e9ciserons ensemble le p\u00e9rim\u00e8tre, les \u00e9l\u00e9ments disponibles et le calendrier avant de finaliser votre devis.<\/p><\/div>' +\r\n    '<a class=\"okp-btn is-full\" href=\"https:\/\/www.ok3d.fr\/projets\/\">D\u00e9couvrir les r\u00e9alisations du studio' + arrow() + '<\/a>' +\r\n    '<div class=\"okp-actions\"><button type=\"button\" class=\"okp-text-btn\" data-action=\"download\">Conserver mon brief \u2193<\/button><\/div>';\r\n}\r\n\r\nfunction render(focus = false) {\r\n  updateChrome();\r\n  panel.innerHTML = isSent ? successHTML() : state.step < 6 ? questionHTML() : state.step === 6 ? resultHTML() : contactHTML();\r\n  persist();\r\n  if (focus) {\r\n    panel.querySelector('h2')?.focus({ preventScroll: true });\r\n    workspace.scrollIntoView({ block: 'start', behavior: reducedMotion.matches ? 'auto' : 'smooth' });\r\n  }\r\n}\r\n\r\nfunction updateSelection(input) {\r\n  const step = STEPS[state.step];\r\n  if (!step) return;\r\n  if (step.multi) {\r\n    let selected = Array.isArray(state.answers[step.key]) ? [...state.answers[step.key]] : [];\r\n    if (input.checked) {\r\n      selected = input.value === step.exclusive\r\n        ? [step.exclusive]\r\n        : [...selected.filter(value => value !== step.exclusive), input.value];\r\n    } else {\r\n      selected = selected.filter(value => value !== input.value);\r\n    }\r\n    state.answers[step.key] = [...new Set(selected)];\r\n  } else {\r\n    state.answers[step.key] = input.value;\r\n  }\r\n  panel.querySelectorAll('.okp-option input').forEach(element => {\r\n    const checked = step.multi ? state.answers[step.key].includes(element.value) : state.answers[step.key] === element.value;\r\n    element.checked = checked;\r\n    element.closest('.okp-option').classList.toggle('is-selected', checked);\r\n  });\r\n  panel.querySelector('[data-action=\"next\"]').disabled = !answered(step);\r\n  updateChrome();\r\n  persist();\r\n}\r\n\r\nasync function copyBrief() {\r\n  captureContact();\r\n  try {\r\n    await navigator.clipboard.writeText(buildBrief());\r\n    notify('Votre brief est copi\u00e9. Vous pouvez le coller dans votre message.');\r\n  } catch (_) {\r\n    panel.querySelector('.okp-copy-area')?.remove();\r\n    const area = document.createElement('textarea');\r\n    area.className = 'okp-copy-area';\r\n    area.readOnly = true;\r\n    area.setAttribute('aria-label', 'Votre brief \u00e0 copier manuellement');\r\n    area.value = buildBrief();\r\n    panel.append(area);\r\n    area.focus();\r\n    area.select();\r\n    notify('Le brief est s\u00e9lectionn\u00e9. Copiez-le avec le menu ou votre clavier.');\r\n  }\r\n}\r\n\r\nfunction downloadBrief() {\r\n  captureContact();\r\n  const blob = new Blob(['\\uFEFF' + buildBrief()], { type: 'text\/plain;charset=utf-8' });\r\n  const url = URL.createObjectURL(blob);\r\n  const link = document.createElement('a');\r\n  link.href = url;\r\n  link.download = 'Mon-projet-OK3D.txt';\r\n  link.hidden = true;\r\n  root.append(link);\r\n  link.click();\r\n  link.remove();\r\n  setTimeout(() => URL.revokeObjectURL(url), 1000);\r\n}\r\n\r\nasync function submit(form) {\r\n  if (isSending || isSent || !form.reportValidity()) return;\r\n  captureContact();\r\n  if (form.elements.namedItem('website').value) return;\r\n  const status = panel.querySelector('#okp-form-status');\r\n  if (contact.nom.length < 2 || !contact.email) {\r\n    status.textContent = 'Merci de renseigner votre nom et une adresse email valide.';\r\n    status.classList.add('is-error');\r\n    return;\r\n  }\r\n  const fallback = panel.querySelector('#okp-fallback');\r\n  panel.querySelector('#okp-email-link').href = mailtoURL();\r\n  if (!nativeSend) {\r\n    window.location.href = mailtoURL();\r\n    status.textContent = 'Votre messagerie a \u00e9t\u00e9 sollicit\u00e9e. Aucun message n\u2019a \u00e9t\u00e9 envoy\u00e9 automatiquement. Si rien ne s\u2019ouvre, utilisez les options ci-dessous.';\r\n    status.classList.remove('is-error');\r\n    fallback.hidden = false;\r\n    return;\r\n  }\r\n\r\n  const button = panel.querySelector('#okp-send');\r\n  const fields = form.querySelector('.okp-form-fields');\r\n  const originalButton = button.innerHTML;\r\n  isSending = true;\r\n  button.disabled = true;\r\n  fields.disabled = true;\r\n  button.textContent = 'Envoi en cours\u2026';\r\n  form.setAttribute('aria-busy', 'true');\r\n  panel.querySelectorAll('[data-action]').forEach(element => element.disabled = true);\r\n  status.textContent = '';\r\n  status.classList.remove('is-error');\r\n  fallback.hidden = true;\r\n  updateChrome();\r\n\r\n  const controller = new AbortController();\r\n  const timeout = setTimeout(() => controller.abort(), CONFIG.timeoutMs);\r\n  try {\r\n    const response = await fetch(CONFIG.endpoint, {\r\n      method: 'POST', credentials: 'same-origin',\r\n      headers: { 'Content-Type': 'application\/json', 'Accept': 'application\/json' },\r\n      body: JSON.stringify(payload()), signal: controller.signal\r\n    });\r\n    const data = await response.json();\r\n    if (!response.ok || !data.success) throw new Error('Transmission non confirm\u00e9e');\r\n    isSent = true;\r\n  } catch (_) {\r\n    status.textContent = 'La r\u00e9ception de votre demande n\u2019a pas pu \u00eatre confirm\u00e9e. Vos informations sont conserv\u00e9es sur cette page. Vous pouvez nous contacter par email en pr\u00e9cisant cette tentative.';\r\n    status.classList.add('is-error');\r\n    fallback.hidden = false;\r\n  } finally {\r\n    clearTimeout(timeout);\r\n    isSending = false;\r\n    if (isSent) {\r\n      render(true);\r\n    } else {\r\n      fields.disabled = false;\r\n      button.disabled = false;\r\n      button.innerHTML = originalButton;\r\n      panel.querySelectorAll('[data-action]').forEach(element => element.disabled = false);\r\n      form.removeAttribute('aria-busy');\r\n      updateChrome();\r\n    }\r\n  }\r\n}\r\n\r\nroot.addEventListener('change', event => {\r\n  if (!isSending && event.target.matches('.okp-option input')) updateSelection(event.target);\r\n});\r\n\r\nroot.addEventListener('click', event => {\r\n  if (isSending) return;\r\n  const stepButton = event.target.closest('[data-step]');\r\n  if (stepButton && !stepButton.disabled) {\r\n    captureContact();\r\n    state.step = Number(stepButton.dataset.step);\r\n    isSent = false;\r\n    render(true);\r\n    return;\r\n  }\r\n  const button = event.target.closest('[data-action]');\r\n  if (!button) return;\r\n  const action = button.dataset.action;\r\n  if (action === 'copy') { copyBrief(); return; }\r\n  if (action === 'download') { downloadBrief(); return; }\r\n  captureContact();\r\n  if (action === 'next' && state.step < 6 && answered(STEPS[state.step])) state.step++;\r\n  else if (action === 'back') state.step = Math.max(0, state.step - 1);\r\n  else if (action === 'contact') state.step = 7;\r\n  else if (action === 'edit') state.step = 0;\r\n  else return;\r\n  render(true);\r\n});\r\n\r\nroot.addEventListener('submit', event => {\r\n  if (event.target.id !== 'okp-contact') return;\r\n  event.preventDefault();\r\n  submit(event.target);\r\n});\r\n\r\nresetButton.addEventListener('click', () => {\r\n  if (isSending) return;\r\n  if (!resetArmed) {\r\n    resetArmed = true;\r\n    resetButton.textContent = 'Confirmer la remise \u00e0 z\u00e9ro ?';\r\n    resetTimer = setTimeout(() => {\r\n      resetArmed = false;\r\n      resetButton.textContent = 'Recommencer';\r\n    }, 5000);\r\n    return;\r\n  }\r\n  clearTimeout(resetTimer);\r\n  resetArmed = false;\r\n  resetButton.textContent = 'Recommencer';\r\n  state = { step: 0, answers: {} };\r\n  contact = { nom: '', email: '', societe: '', projet: '' };\r\n  isSent = false;\r\n  render(true);\r\n});\r\n\r\n\/* Largeur synchronis\u00e9e avec la zone visible, sans masquer le d\u00e9bordement du site. *\/\r\nlet layoutFrame=0;\r\nfunction fitLayout(){\r\n  if(!root.isConnected||root.dataset.layout!=='full')return;\r\n  root.style.setProperty('--okp-viewport',document.documentElement.clientWidth+'px');\r\n  const left=root.getBoundingClientRect().left, margin=parseFloat(getComputedStyle(root).marginLeft)||0;\r\n  if(Math.abs(left)>.5)root.style.setProperty('--okp-offset',(margin-left)+'px');\r\n}\r\nfunction scheduleLayout(){cancelAnimationFrame(layoutFrame);layoutFrame=requestAnimationFrame(fitLayout)}\r\nwindow.addEventListener('resize',scheduleLayout,{passive:true});\r\nif(typeof ResizeObserver!=='undefined'){const observer=new ResizeObserver(scheduleLayout);observer.observe(root.parentElement);observer.observe(document.documentElement)}\r\nscheduleLayout();\r\nrestore();\r\nrender();\r\n\r\n})();\r\n\r\n<\/script>\t\t\t\t<\/div>\n\t\t\n<\/div>\n\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>OK3D \/ VOTRE PROCHAIN PROJET Une id\u00e9e.Le d\u00e9but d\u2019un projet. Des visuels produit, une animation, un espace \u00e0 r\u00e9v\u00e9ler. Trouvons ensemble la bonne direction pour votre projet 3D. 6 questions pour poser les basesSans inscription ni engagement L\u2019INTENTION PREND DU VOLUME. DE L\u2019ID\u00c9E \u00c0 L\u2019IMAGE.Commen\u00e7ons par l\u2019essentiel \u219301 \u2014 06 01 \/ D\u00c9FINIR VOTRE PROJETVotre [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-15663","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/pages\/15663","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/comments?post=15663"}],"version-history":[{"count":8,"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/pages\/15663\/revisions"}],"predecessor-version":[{"id":15720,"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/pages\/15663\/revisions\/15720"}],"wp:attachment":[{"href":"https:\/\/www.ok3d.fr\/en\/wp-json\/wp\/v2\/media?parent=15663"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}