{"id":1148,"date":"2026-10-27T15:57:11","date_gmt":"2026-10-27T14:57:11","guid":{"rendered":"https:\/\/www.hashdezo.fr\/index.php\/alm-escape\/"},"modified":"2026-10-27T15:57:11","modified_gmt":"2026-10-27T14:57:11","slug":"alm-escape","status":"publish","type":"page","link":"https:\/\/www.hashdezo.fr\/index.php\/alm-escape\/","title":{"rendered":"ALM Escape"},"content":{"rendered":"\n<div class=\"hz-alm-escape\" style=\"width:100%;max-width:1280px;margin:0 auto;padding:8px 0 40px\"><iframe id=\"hz-escape-frame\" title=\"ALM Escape, escape game SAP Cloud ALM\" scrolling=\"no\" style=\"display:block;width:100%;height:900px;border:0;background:#FAF9F6\"><\/iframe><\/div>\n<script type=\"text\/plain\" id=\"hz-escape-src\">\n<!doctype html><html lang=\"fr\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>ALM Escape<\/title>\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"stylesheet\" href=\"https:\/\/fonts.googleapis.com\/css2?family=IBM+Plex+Mono:wght@400;500;600&#038;family=Schibsted+Grotesk:wght@400;500;600;700;800&#038;display=swap\">\n<style>\n\/* Layout : une salle de bascule vue de face (sc\u00e8ne 16\/9), objets cliquables, barre d'inventaire dessous. Page cr\u00e8me HASHdezO, salle encre, accent or. Un seul look assum\u00e9. *\/\n:root{\n  --ink:#141412; --panel:#1C1C1A; --tube:#2E2E2A; --line-dk:#3A3A36;\n  --cream:#FAF9F6; --paper:#EDEBE5; --line:#E2E0DA;\n  --gold:#E7B84A; --gold-pale:#F6EBCB;\n  --grey:#6B6A64; --mute:#9C9A92; --soft:#C9C6BC;\n  --ok:#5BBF7A; --ko:#E0675B; --blue:#4F9BD9;\n  --prepare:#E7B84A; --explore:#4F9BD9; --realize:#1FA38C; --deploy:#D9483B;\n  --f-display:'Schibsted Grotesk','Helvetica Neue',Arial,sans-serif;\n  --f-mono:'IBM Plex Mono',ui-monospace,'SFMono-Regular',Menlo,monospace;\n  color-scheme:light;\n}\nhtml,body{background:var(--cream);color:var(--ink)}\nbody{font-family:var(--f-display);-webkit-font-smoothing:antialiased;\n  padding-left:max(16px,env(safe-area-inset-left,0px));padding-right:max(16px,env(safe-area-inset-right,0px));padding-block:18px 32px}\n*{box-sizing:border-box}\n[hidden]{display:none!important}\nbutton,select{font:inherit;color:inherit}\n.wrap{max-width:1240px;margin:0 auto;display:flex;flex-direction:column;gap:14px}\nheader{display:flex;justify-content:space-between;align-items:baseline;gap:12px;flex-wrap:wrap}\n.brand{font-weight:800;font-size:22px;letter-spacing:-.03em}\n.brand span{background:linear-gradient(transparent 62%,var(--gold) 62%)}\n.mono{font-family:var(--f-mono);font-size:12px;color:var(--grey)}\n\n.game{position:relative;background:var(--ink);color:var(--cream);border-radius:10px;padding:14px;display:flex;flex-direction:column;gap:12px;overflow:hidden}\n.hud{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;padding:2px 4px}\n.hud .title{font-weight:800;font-size:18px;letter-spacing:-.02em}\n.hud .title em{font-style:normal;color:var(--gold)}\n.hudr{display:flex;gap:18px;align-items:center}\n.clock{font:700 28px var(--f-mono);font-variant-numeric:tabular-nums;letter-spacing:.02em}\n.clock.warn{color:var(--ko)}\n.lab{font:500 10px var(--f-mono);color:var(--mute);text-transform:uppercase;letter-spacing:.1em}\n.kv{display:flex;flex-direction:column;align-items:flex-end;gap:2px}\n.kv b{font:700 16px var(--f-mono);font-variant-numeric:tabular-nums}\n\n\/* scene *\/\n.scene{position:relative;aspect-ratio:16\/8.2;max-width:100%;border-radius:6px;overflow:hidden;\n  background:linear-gradient(180deg,#232320 0%,#1E1E1B 64%,#2A2925 64%,#2A2925 100%)}\n.scene:before{content:'';position:absolute;left:0;right:0;top:64%;height:2px;background:#3A3A36}\n.scene .lamp{position:absolute;top:0;width:22%;height:70%;background:radial-gradient(ellipse at top,rgba(231,184,74,.10),transparent 70%);pointer-events:none}\n.walltext{position:absolute;left:3%;top:4%;font:500 11px var(--f-mono);color:#55534D;letter-spacing:.14em;text-transform:uppercase}\n.obj{position:absolute;border:0;padding:0;background:none;cursor:pointer;text-align:left;transition:transform .15s,filter .15s}\n.obj:hover{transform:translateY(-3px);filter:brightness(1.15)}\n.obj .lbl{position:absolute;left:50%;bottom:-26px;transform:translateX(-50%);white-space:nowrap;font:600 11px var(--f-mono);color:var(--soft);background:rgba(20,20,18,.85);padding:3px 8px;border-radius:999px;border:1px solid var(--line-dk)}\n.obj:hover .lbl{color:var(--gold);border-color:var(--gold)}\n.obj.done .lbl{color:var(--ok);border-color:var(--ok)}\n.obj .chk{position:absolute;top:-10px;right:-10px;width:26px;height:26px;border-radius:50%;background:var(--ok);color:var(--ink);font:800 15px\/26px var(--f-display);text-align:center;display:none;box-shadow:0 2px 8px rgba(0,0,0,.4)}\n.obj.done .chk{display:block}\n\/* whiteboard *\/\n.wb{left:4%;top:13%;width:25%;height:40%;background:#F4F2EC;border:6px solid #8E8B82;border-radius:4px;box-shadow:0 10px 24px rgba(0,0,0,.4)}\n.wb .in{position:absolute;inset:10% 8%;display:flex;flex-direction:column;gap:8%}\n.wb .ln{height:6%;background:#C9C6BC;border-radius:4px}\n.wb .ln.s{width:60%}.wb .ln.m{width:80%}\n.wb .postit{position:absolute;width:20%;aspect-ratio:1;box-shadow:2px 3px 6px rgba(0,0,0,.25)}\n.wb .h{position:absolute;left:8%;top:6%;font:700 clamp(10px,1.2vw,15px) var(--f-display);color:#3A3A36}\n\/* cabinet *\/\n.cab{left:33%;top:18%;width:12%;height:62%;background:linear-gradient(90deg,#3A3A36,#46453F);border-radius:4px;box-shadow:0 10px 24px rgba(0,0,0,.45)}\n.cab .dr{position:absolute;left:8%;right:8%;height:28%;border:2px solid #2A2925;border-radius:3px;background:#4C4B45}\n.cab .dr:after{content:'';position:absolute;left:35%;right:35%;top:44%;height:10%;background:#9C9A92;border-radius:2px}\n.cab .dr:nth-child(1){top:4%}.cab .dr:nth-child(2){top:36%}.cab .dr:nth-child(3){top:68%}\n.cab .tagx{position:absolute;left:50%;top:-14%;transform:translateX(-50%);font:700 clamp(9px,1vw,12px) var(--f-mono);color:var(--explore);white-space:nowrap}\n\/* desk + laptop *\/\n.desk{position:absolute;left:48%;top:56%;width:28%;height:6%;background:#5A5850;border-radius:3px;box-shadow:0 10px 18px rgba(0,0,0,.4)}\n.desk:before,.desk:after{content:'';position:absolute;top:100%;width:5%;height:420%;background:#4A4943}\n.desk:before{left:6%}.desk:after{right:6%}\n.lap{left:53%;top:36%;width:16%;height:20%}\n.lap .scr{position:absolute;left:8%;right:8%;top:0;height:84%;background:#0E1A22;border:4px solid #3A3A36;border-radius:4px 4px 0 0;overflow:hidden}\n.lap .scr i{position:absolute;left:10%;height:7%;background:var(--realize);border-radius:2px;opacity:.8}\n.lap .base{position:absolute;left:0;right:0;bottom:0;height:16%;background:#5E5C55;border-radius:0 0 6px 6px}\n\/* deploy screen *\/\n.dep{left:51%;top:7%;width:22%;height:24%;background:#0E1A22;border:5px solid #3A3A36;border-radius:4px;box-shadow:0 10px 24px rgba(0,0,0,.45)}\n.dep .row{position:absolute;left:8%;right:8%;display:flex;gap:6%;align-items:center}\n.dep .dot{width:10%;aspect-ratio:1;border-radius:50%}\n.dep .bar{flex:1;height:30%;min-height:5px;background:#2E3A42;border-radius:3px}\n.dep .t{position:absolute;left:8%;top:8%;font:600 clamp(8px,.9vw,11px) var(--f-mono);color:var(--deploy);letter-spacing:.08em}\n\/* door *\/\n.door{left:80%;top:10%;width:15%;height:72%;background:linear-gradient(90deg,#2F2E2A,#3A3934);border:5px solid #4A4943;border-bottom:0;border-radius:4px 4px 0 0;box-shadow:0 0 0 2px #232320 inset}\n.door .sign{position:absolute;left:10%;right:10%;top:7%;padding:6% 0;text-align:center;background:var(--ko);color:#fff;font:800 clamp(9px,1.1vw,14px) var(--f-display);letter-spacing:.06em;border-radius:3px}\n.door.open .sign{background:var(--ok);color:var(--ink)}\n.door .pad{position:absolute;right:10%;top:44%;width:34%;aspect-ratio:3\/4;background:#1A1A18;border:2px solid #55534D;border-radius:4px;display:grid;grid-template-columns:repeat(3,1fr);gap:8%;padding:12%}\n.door .pad i{background:#55534D;border-radius:2px}\n.door .handle{position:absolute;left:10%;top:52%;width:22%;height:3%;background:#9C9A92;border-radius:3px}\n\/* plant + clock decor *\/\n.plant{position:absolute;left:28%;top:58%;width:4%;height:22%}\n.plant:before{content:'';position:absolute;left:10%;right:10%;bottom:0;height:35%;background:#5A5850;border-radius:2px 2px 6px 6px}\n.plant:after{content:'';position:absolute;left:-30%;right:-30%;bottom:30%;height:75%;background:radial-gradient(circle at 50% 70%,#2F6B46 0 45%,transparent 46%),radial-gradient(circle at 25% 40%,#3B8257 0 30%,transparent 31%),radial-gradient(circle at 75% 35%,#3B8257 0 30%,transparent 31%)}\n.wallclock{position:absolute;left:75.6%;top:16%;width:4.4%;aspect-ratio:1;border-radius:50%;border:3px solid #55534D;background:#F4F2EC}\n.wallclock:before,.wallclock:after{content:'';position:absolute;left:50%;top:50%;width:3px;background:#141412;transform-origin:50% 100%;border-radius:2px}\n.wallclock:before{height:32%;transform:translate(-50%,-100%) rotate(180deg)}\n.wallclock:after{height:42%;transform:translate(-50%,-100%) rotate(0deg)}\n\n\/* inventory *\/\n.inv{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding:2px 4px}\n.inv .slots{display:flex;gap:10px;flex-wrap:wrap}\n.note{width:96px;height:64px;border-radius:4px;background:var(--tube);border:1px dashed var(--line-dk);display:flex;flex-direction:column;justify-content:center;align-items:center;gap:2px;color:var(--mute);font:11px var(--f-mono)}\n.note.got{background:var(--gold-pale);border:0;color:var(--ink);box-shadow:2px 3px 8px rgba(0,0,0,.35);transform:rotate(-2deg)}\n.note.got:nth-child(even){transform:rotate(2deg)}\n.note b{font:800 26px var(--f-display);line-height:1}\n.note span{font:600 10px var(--f-mono);text-transform:uppercase;letter-spacing:.08em}\n.note span i{display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:4px;vertical-align:0}\n.joule{margin-left:auto;font:600 14px var(--f-display);padding:10px 16px;border-radius:999px;border:1px solid #55534D;background:transparent;color:var(--cream);cursor:pointer;display:flex;align-items:center;gap:8px}\n.joule:hover{border-color:var(--gold);color:var(--gold)}\n.joule .star{width:14px;height:14px;background:var(--gold);clip-path:polygon(50% 0,61% 39%,100% 50%,61% 61%,50% 100%,39% 61%,0 50%,39% 39%)}\n.toast{position:absolute;left:50%;bottom:96px;transform:translateX(-50%);background:var(--gold);color:var(--ink);font:600 14px\/1.3 var(--f-display);padding:10px 18px;border-radius:999px;z-index:20;box-shadow:0 8px 24px rgba(0,0,0,.4);max-width:80%;text-align:center}\n.toast small{display:block;font:500 11px var(--f-mono)}\n\n\/* modal *\/\n.modal{position:absolute;inset:0;background:rgba(20,20,18,.82);display:flex;justify-content:center;align-items:center;padding:24px;z-index:10}\n.box{position:relative;width:min(860px,100%);max-height:100%;overflow:auto;background:var(--cream);color:var(--ink);border-radius:10px;padding:26px 28px 24px;display:flex;flex-direction:column;gap:16px;box-shadow:0 20px 60px rgba(0,0,0,.5)}\n.box .close{position:absolute;top:14px;right:14px;width:34px;height:34px;border-radius:50%;border:1px solid var(--line);background:#fff;cursor:pointer;font:600 18px\/1 var(--f-display)}\n.box .close:hover{border-color:var(--ink)}\n.box .ey{font:500 12px var(--f-mono);color:var(--grey);display:flex;gap:10px;align-items:center;flex-wrap:wrap}\n.pill{font:600 10px var(--f-mono);text-transform:uppercase;letter-spacing:.08em;padding:3px 8px;border-radius:999px;color:var(--ink)}\n.box h2{margin:0;font-size:28px;font-weight:800;letter-spacing:-.025em;line-height:1.08;padding-right:40px;text-wrap:balance}\n.box p{margin:0;font-size:15px;line-height:1.55;color:#3A3A36;max-width:70ch}\n.box .alm{font:12px\/1.5 var(--f-mono);color:var(--grey);border-left:3px solid var(--gold);padding-left:10px}\n.actions{display:flex;gap:12px;align-items:center;flex-wrap:wrap}\n.btn{font:600 15px\/1.2 var(--f-display);padding:12px 22px;border-radius:999px;border:1px solid var(--ink);background:var(--ink);color:var(--cream);cursor:pointer}\n.btn:hover{background:#3A3A36}\n.btn.gold{background:var(--gold);border-color:var(--gold);color:var(--ink)}\n.btn.gold:hover{background:var(--gold-pale)}\n.btn.ghost{background:transparent;color:var(--ink)}\n.btn.ghost:hover{background:var(--paper)}\n.btn:disabled{opacity:.4;cursor:default}\n.fb{font:600 13px var(--f-mono);min-height:20px}\n.fb.ko{color:#B23B30}.fb.ok{color:#2E7D4A}\n.joulehint{background:#fff;border:1px solid var(--line);border-radius:8px;padding:12px 14px;font-size:14px;line-height:1.5;display:flex;gap:10px}\n.joulehint .star{flex:0 0 14px;height:14px;margin-top:3px;background:var(--gold);clip-path:polygon(50% 0,61% 39%,100% 50%,61% 61%,50% 100%,39% 61%,0 50%,39% 39%)}\n\/* p1 *\/\n.slots5{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px}\n.slot{height:64px;border-radius:6px;border:2px dashed #CFCCC4;background:#fff;display:flex;flex-direction:column;justify-content:center;align-items:center;cursor:pointer;font:700 15px var(--f-display)}\n.slot small{font:500 10px var(--f-mono);color:var(--grey)}\n.slot.fill{border-style:solid;border-color:var(--ink)}\n.chips{display:flex;gap:10px;flex-wrap:wrap}\n.chipb{padding:12px 18px;border-radius:6px;border:1px solid var(--ink);background:var(--gold-pale);cursor:pointer;font:700 15px var(--f-display)}\n.chipb:hover{background:var(--gold)}\n\/* tables *\/\n.tbl{width:100%;border-collapse:collapse;font-size:14px}\n.tbl th{font:500 11px var(--f-mono);color:var(--grey);text-transform:uppercase;letter-spacing:.06em;text-align:left;padding:8px 10px;border-bottom:1px solid var(--ink)}\n.tbl td{padding:10px;border-bottom:1px solid var(--line);vertical-align:middle}\n.tbl td.id{font:600 12px var(--f-mono);white-space:nowrap}\n.tbl select{padding:8px 10px;border-radius:6px;border:1px solid #CFCCC4;background:#fff;min-width:180px}\n.st{font:600 11px var(--f-mono);padding:3px 8px;border-radius:999px;white-space:nowrap}\n.st.ok{background:#DCF0E2;color:#2E7D4A}.st.ko{background:#F8DEDA;color:#B23B30}.st.wait{background:#F6EBCB;color:#6B5418}\n.cols2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.3fr);gap:20px}\n.reqbtns{display:flex;gap:8px;flex-wrap:wrap}\n.reqbtns button{font:600 13px var(--f-mono);padding:10px 14px;border-radius:6px;border:1px solid var(--ink);background:#fff;cursor:pointer}\n.reqbtns button:hover{background:var(--gold-pale)}\n.tblwrap{overflow-x:auto}\n\/* p4 *\/\n.feats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}\n.feat{background:#fff;border:1px solid var(--line);border-radius:8px;padding:14px;display:flex;flex-direction:column;gap:10px}\n.feat h4{margin:0;font-size:16px;font-weight:700}\n.feat .fid{font:600 11px var(--f-mono);color:var(--grey)}\n.feat dl{margin:0;display:grid;grid-template-columns:auto 1fr;gap:6px 12px;font-size:13px;align-items:center}\n.feat dt{font:500 11px var(--f-mono);color:var(--grey)}\n.feat dd{margin:0}\n\/* reward *\/\n.reward{display:flex;gap:18px;align-items:center;background:var(--gold-pale);border-radius:8px;padding:16px}\n.reward .big{width:84px;height:84px;border-radius:6px;background:#FFF3C9;box-shadow:3px 4px 10px rgba(0,0,0,.18);display:flex;flex-direction:column;align-items:center;justify-content:center;transform:rotate(-3deg)}\n.reward .big b{font:800 40px var(--f-display);line-height:1}\n.reward .big span{font:600 10px var(--f-mono);text-transform:uppercase}\n\/* keypad *\/\n.code{display:flex;gap:10px}\n.code span{width:58px;height:70px;border-radius:6px;border:2px solid var(--ink);background:#fff;display:flex;align-items:center;justify-content:center;font:800 34px var(--f-mono)}\n.keys{display:grid;grid-template-columns:repeat(5,56px);gap:8px}\n.keys button{height:48px;border-radius:6px;border:1px solid var(--ink);background:#fff;cursor:pointer;font:700 18px var(--f-mono)}\n.keys button:hover{background:var(--gold-pale)}\n.keys button.wide{grid-column:span 2;font:600 13px var(--f-display)}\n\n\/* full overlays *\/\n.ov{position:absolute;inset:0;background:rgba(20,20,18,.95);display:flex;justify-content:center;align-items:center;padding:36px;z-index:30;overflow:auto}\n.ov .inner{max-width:820px;width:100%;display:flex;flex-direction:column;gap:16px;align-items:flex-start}\n.eyebrow{font:500 12px var(--f-mono);color:var(--gold);letter-spacing:.04em}\n.ov h1{margin:0;font-size:64px;font-weight:800;letter-spacing:-.04em;line-height:.95}\n.ov h1 em{font-style:normal;color:var(--gold)}\n.ov h2{margin:0;font-size:38px;font-weight:800;letter-spacing:-.03em;line-height:1.04;text-wrap:balance}\n.ov p{margin:0;font-size:16px;line-height:1.55;color:#D8D5CC;max-width:62ch}\n.ov p.punch{color:var(--cream);font-weight:600;font-size:18px}\n.ov .btn.gold{font-size:16px;padding:13px 26px}\n.ov .btn.ghost{color:var(--cream);border-color:#55534D}\n.ov .btn.ghost:hover{background:var(--line-dk)}\n.brief{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 28px;width:100%}\n.brief div{padding:10px 0;border-top:1px solid var(--line-dk);display:flex;flex-direction:column;gap:2px}\n.brief b{font-size:15px}\n.brief span{font-size:14px;color:#C9C6BC;line-height:1.45}\n.stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;width:100%;border-top:1px solid var(--line-dk);padding-top:12px}\n.stats b{display:block;font-size:30px;font-weight:800;font-variant-numeric:tabular-nums}\n.stats span{font:10px var(--f-mono);color:var(--mute);text-transform:uppercase;letter-spacing:.06em}\n.recap{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 24px;width:100%}\n.recap div{display:flex;gap:10px;align-items:baseline;padding:8px 0;border-top:1px solid var(--line-dk);font-size:14px;color:#D8D5CC}\n.recap i{flex:0 0 10px;height:10px;border-radius:2px}\n.cta{display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--line-dk);padding-top:12px;width:100%}\n.cta a{color:var(--gold);font-weight:600;text-decoration:none;border-bottom:2px solid var(--gold);align-self:flex-start}\n.cta .mono{color:var(--soft);user-select:text}\n:focus-visible{outline:2px solid var(--gold);outline-offset:3px}\n@media (max-width:900px){.cols2,.feats,.brief,.recap{grid-template-columns:minmax(0,1fr)}.ov h1{font-size:44px}.slots5{grid-template-columns:repeat(3,minmax(0,1fr))}}\n@media (prefers-reduced-motion:reduce){.obj{transition:none}}\n<\/style>\n<style>html,body{margin:0}[hidden]{display:none!important}img{max-width:100%}<\/style><\/head><body>\n\n<div class=\"wrap\">\n\n  <section class=\"game\" id=\"game\" aria-label=\"Escape game ALM Escape\">\n    <div class=\"hud\">\n      <div class=\"title\">ALM <em>Escape<\/em> \u00b7 Salle de bascule<\/div>\n      <div class=\"hudr\">\n        <div class=\"kv\"><span class=\"lab\">\u00c9nigmes<\/span><b id=\"solvedK\">0 \/ 4<\/b><\/div>\n        <div class=\"kv\"><span class=\"lab\">Indices Joule<\/span><b id=\"hintsK\">0<\/b><\/div>\n        <div class=\"kv\"><span class=\"lab\">Avant le go-live<\/span><span class=\"clock\" id=\"clock\">15:00<\/span><\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"scene\" id=\"scene\">\n      <span class=\"lamp\" style=\"left:6%\"><\/span><span class=\"lamp\" style=\"left:50%\"><\/span>\n      <span class=\"walltext\">War room \u00b7 projet S\/4HANA \u00b7 go-live ce soir 22 h<\/span>\n      <span class=\"wallclock\" aria-hidden=\"true\"><\/span>\n      <button class=\"obj wb\" data-p=\"p1\" aria-label=\"Tableau blanc : plan projet\">\n        <span class=\"h\">Plan projet<\/span>\n        <span class=\"postit\" style=\"left:12%;top:34%;background:#F6EBCB;transform:rotate(-4deg)\"><\/span>\n        <span class=\"postit\" style=\"left:38%;top:30%;background:#CFE3F5;transform:rotate(3deg)\"><\/span>\n        <span class=\"postit\" style=\"left:64%;top:36%;background:#CDEBE2;transform:rotate(-2deg)\"><\/span>\n        <span class=\"postit\" style=\"left:26%;top:64%;background:#F6D3CE;transform:rotate(5deg)\"><\/span>\n        <span class=\"postit\" style=\"left:54%;top:66%;background:#EDEBE5;transform:rotate(-3deg)\"><\/span>\n        <span class=\"lbl\">Tableau du plan projet<\/span><span class=\"chk\">\u2713<\/span>\n      <\/button>\n      <span class=\"plant\" aria-hidden=\"true\"><\/span>\n      <button class=\"obj cab\" data-p=\"p2\" aria-label=\"Armoire : exigences\">\n        <span class=\"tagx\">EXIGENCES<\/span><span class=\"dr\"><\/span><span class=\"dr\"><\/span><span class=\"dr\"><\/span>\n        <span class=\"lbl\">Armoire des exigences<\/span><span class=\"chk\">\u2713<\/span>\n      <\/button>\n      <button class=\"obj dep\" data-p=\"p4\" aria-label=\"\u00c9cran : mise en production\">\n        <span class=\"t\">MISE EN PRODUCTION<\/span>\n        <span class=\"row\" style=\"top:32%\"><span class=\"dot\" style=\"background:#5BBF7A\"><\/span><span class=\"bar\"><\/span><\/span>\n        <span class=\"row\" style=\"top:52%\"><span class=\"dot\" style=\"background:#E7B84A\"><\/span><span class=\"bar\"><\/span><\/span>\n        <span class=\"row\" style=\"top:72%\"><span class=\"dot\" style=\"background:#E0675B\"><\/span><span class=\"bar\"><\/span><\/span>\n        <span class=\"lbl\">\u00c9cran de d\u00e9ploiement<\/span><span class=\"chk\">\u2713<\/span>\n      <\/button>\n      <span class=\"desk\" aria-hidden=\"true\"><\/span>\n      <button class=\"obj lap\" data-p=\"p3\" aria-label=\"Ordinateur : tests\">\n        <span class=\"scr\"><i style=\"top:14%;width:60%\"><\/i><i style=\"top:32%;width:44%\"><\/i><i style=\"top:50%;width:70%\"><\/i><i style=\"top:68%;width:36%;background:#E0675B\"><\/i><\/span>\n        <span class=\"base\"><\/span>\n        <span class=\"lbl\">Portable du test manager<\/span><span class=\"chk\">\u2713<\/span>\n      <\/button>\n      <button class=\"obj door\" id=\"door\" data-p=\"door\" aria-label=\"Porte de la salle de bascule\">\n        <span class=\"sign\" id=\"doorSign\">GO-LIVE<\/span>\n        <span class=\"pad\"><i><\/i><i><\/i><i><\/i><i><\/i><i><\/i><i><\/i><i><\/i><i><\/i><i><\/i><\/span>\n        <span class=\"handle\"><\/span>\n        <span class=\"lbl\">Porte de bascule<\/span>\n      <\/button>\n    <\/div>\n\n    <div class=\"inv\">\n      <span class=\"lab\">Notes trouv\u00e9es<\/span>\n      <div class=\"slots\" id=\"slots\"><\/div>\n      <button class=\"joule\" id=\"jouleBtn\" title=\"Un indice co\u00fbte 60 secondes\"><span class=\"star\"><\/span>Demander \u00e0 Joule \u00b7 \u221260 s<\/button>\n    <\/div>\n\n    <div class=\"modal\" id=\"modal\" hidden><\/div>\n    <div class=\"ov\" id=\"ov\"><\/div>\n    <div class=\"toast\" id=\"toast\" hidden><\/div>\n  <\/section>\n\n  <div style=\"display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap\">\n    <span class=\"mono\">Clique sur les objets de la salle \u00b7 un indice Joule co\u00fbte 60 secondes<\/span>\n    <span class=\"mono\">Client, projet et donn\u00e9es fictifs<\/span>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n'use strict';\nvar $=function(id){return document.getElementById(id)};\nfunction esc(s){return String(s).replace(\/[&<>\"]\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;'}[c]})}\nfunction shuffle(a){a=a.slice();for(var i=a.length-1;i>0;i--){var j=Math.random()*(i+1)|0,t=a[i];a[i]=a[j];a[j]=t}return a}\nfunction rnd(n){return Math.random()*n|0}\n\nvar DURATION=15*60, PENALTY_HINT=60, PENALTY_CODE=30;\nvar PHASE={\n  p1:{key:'prepare',name:'Prepare',color:'#E7B84A'},\n  p2:{key:'explore',name:'Explore',color:'#4F9BD9'},\n  p3:{key:'realize',name:'Realize',color:'#1FA38C'},\n  p4:{key:'deploy',name:'Deploy',color:'#D9483B'}\n};\nvar ORDER=['p1','p2','p3','p4'];\n\n\/* ---------- puzzle data ---------- *\/\nvar PHASES5=['Prepare','Explore','Realize','Deploy','Run'];\nvar PROCS=['Order-to-Cash','Procure-to-Pay','Record-to-Report','Plan-to-Produce'];\nvar REQS=[\n  {id:'REQ-01',t:'Facturer automatiquement les commandes livr\u00e9es',p:'Order-to-Cash'},\n  {id:'REQ-02',t:'Rapprocher commande, r\u00e9ception et facture fournisseur',p:'Procure-to-Pay'},\n  {id:'REQ-03',t:'Cl\u00f4turer les comptes du mois en 4 jours ouvr\u00e9s',p:'Record-to-Report'},\n  {id:'REQ-04',t:'Planifier la production \u00e0 partir des pr\u00e9visions de ventes',p:'Plan-to-Produce'},\n  {id:'REQ-05',t:'Bloquer une commande client au-del\u00e0 de l\u2019encours autoris\u00e9',p:'Order-to-Cash'}\n];\nvar FEAT_NAMES=['Facturation export','Rapprochement \u00e0 trois voies','Cl\u00f4ture acc\u00e9l\u00e9r\u00e9e','Planification MRP'];\n\nvar G=null, tick=null;\nfunction newGame(){\n  var code={}; ORDER.forEach(function(p){code[p]=1+rnd(9)});\n  \/\/ p3: one requirement without test\n  var uncovered=REQS[rnd(REQS.length)].id;\n  var tcs=[], n=1;\n  REQS.forEach(function(r){\n    if(r.id===uncovered)return;\n    var k=1+rnd(2);\n    for(var i=0;i<k;i++)tcs.push({id:'',req:r.id,st:Math.random()<.15?'wait':'ok'});\n  });\n  tcs=shuffle(tcs).map(function(t){t.id='TC-'+String(n++).padStart(2,'0');return t});\n  \/\/ make sure at most one \"wait\"\n  \/\/ p4: roles\n  var names=shuffle(FEAT_NAMES), roles=['ok','dep','test','appr'], ids=shuffle(['F-101','F-102','F-103','F-104']);\n  var feats=roles.map(function(r,i){return {id:ids[i],name:names[i],role:r}});\n  var apprF=feats.filter(function(f){return f.role==='appr'})[0];\n  feats.forEach(function(f){\n    f.tests=f.role==='test'?'1 \u00e9chec':'R\u00e9ussis';\n    f.appr=f.role==='appr'?'En attente':'Approuv\u00e9e';\n    f.tr=f.role==='test'?'Import\u00e9s en QAS':'Import\u00e9s en QAS';\n    f.dep=f.role==='dep'?apprF.id+' \u00b7 '+apprF.name:'Aucune';\n  });\n  feats=shuffle(feats);\n  G={code:code,solved:{},hints:0,penalty:0,start:0,running:false,over:false,uncovered:uncovered,tcs:tcs,feats:feats,\n     found:[],p1slots:[null,null,null,null,null],p1pool:shuffle(PHASES5),p2sel:{},hinted:{},opened:null,codeIn:'',wrongCodes:0};\n  renderInv(); renderHud(); markScene();\n}\n\n\/* ---------- timer ---------- *\/\nfunction elapsed(){return G.running?(Date.now()-G.start)\/1000+G.penalty:G.penalty}\nfunction remaining(){return Math.max(0,DURATION-elapsed())}\nfunction fmt(s){s=Math.ceil(s);return String(Math.floor(s\/60)).padStart(2,'0')+':'+String(s%60).padStart(2,'0')}\nfunction renderHud(){\n  var r=remaining();\n  $('clock').textContent=fmt(r); $('clock').classList.toggle('warn',r<120);\n  $('solvedK').textContent=Object.keys(G.solved).length+' \/ 4';\n  $('hintsK').textContent=G.hints;\n}\nfunction startClock(){G.start=Date.now();G.running=true;clearInterval(tick);tick=setInterval(function(){renderHud();if(G.running&#038;&#038;remaining()<=0)timeUp()},250)}\n\n\/* ---------- inventory &#038; scene ---------- *\/\nfunction renderInv(){\n  var list=G.found.concat(ORDER.filter(function(p){return G.found.indexOf(p)<0}));\n  $('slots').innerHTML=list.map(function(p){\n    if(!G.solved[p])return '<div class=\"note\">?<\/div>';\n    var ph=PHASE[p];\n    return '<div class=\"note got\"><b>'+G.code[p]+'<\/b><span><i style=\"background:'+ph.color+'\"><\/i>'+ph.name+'<\/span><\/div>';\n  }).join('');\n}\nfunction markScene(){\n  Array.prototype.forEach.call(document.querySelectorAll('.obj[data-p]'),function(b){\n    var p=b.getAttribute('data-p'); b.classList.toggle('done',!!G.solved[p]);\n  });\n}\n\n\/* ---------- modal ---------- *\/\nvar modal=$('modal');\nfunction openModal(html){var p=G.opened,showJ=p&&!G.solved[p]&&!G.hinted[p];modal.innerHTML='<div class=\"box\" role=\"dialog\" aria-modal=\"true\"><button class=\"close\" id=\"mClose\" aria-label=\"Fermer\">\u00d7<\/button>'+html+(showJ?'<div class=\"actions\" id=\"mJouleRow\"><button class=\"btn ghost\" id=\"mJoule\"><span class=\"star\" style=\"display:inline-block;width:12px;height:12px;margin-right:8px;background:var(--gold);clip-path:polygon(50% 0,61% 39%,100% 50%,61% 61%,50% 100%,39% 61%,0 50%,39% 39%)\"><\/span>Demander un indice \u00e0 Joule \u00b7 \u221260 s<\/button><\/div>':'')+'<\/div>';modal.hidden=false;$('mClose').onclick=closeModal;if($('mJoule'))$('mJoule').onclick=askJoule;var f=modal.querySelector('[data-focus]');if(f)setTimeout(function(){f.focus({preventScroll:true})},30)}\nfunction closeModal(){modal.hidden=true;G.opened=null}\nfunction head(p,title,feature){\n  var ph=PHASE[p];\n  return '<div class=\"ey\"><span class=\"pill\" style=\"background:'+ph.color+'\">'+ph.name+'<\/span><span>'+esc(feature)+'<\/span><\/div><h2>'+esc(title)+'<\/h2>';\n}\nfunction hintBox(p){return G.hinted[p]?'<div class=\"joulehint\"><span class=\"star\"><\/span><span>'+esc(HINTS[p])+'<\/span><\/div>':''}\nfunction rewardHtml(p,line){\n  var ph=PHASE[p];\n  return '<div class=\"reward\"><div class=\"big\"><b>'+G.code[p]+'<\/b><span style=\"color:'+ph.color+'\">'+ph.name+'<\/span><\/div><div><p><b>Note trouv\u00e9e.<\/b> '+esc(line)+'<\/p><\/div><\/div>';\n}\nfunction solve(p,line){\n  if(G.solved[p])return;\n  G.solved[p]=true; G.found.push(p); renderInv(); renderHud(); markScene();\n  var jr=$('mJouleRow');if(jr)jr.remove();\n  var fb=modal.querySelector('.solvezone'); if(fb)fb.innerHTML=rewardHtml(p,line);\n  toast('Note trouv\u00e9e : '+PHASE[p].name+' \u00b7 '+G.code[p],'Elle rejoint tes notes en bas de l\u2019\u00e9cran');\n  if(Object.keys(G.solved).length===4)setTimeout(function(){toast('Les 4 notes sont r\u00e9unies','Direction la porte de bascule')},2600);\n}\n\nvar HINTS={\n  p1:'Un projet SAP Activate commence par la pr\u00e9paration et se termine par l\u2019exploitation en production.',\n  p2:'Order-to-Cash va de la commande client jusqu\u2019\u00e0 l\u2019encaissement. Deux exigences en font partie.',\n  p3:'Pour chaque exigence, cherche au moins un cas de test qui la cite dans la colonne \u00ab Couvre \u00bb.',\n  p4:'Pour partir en production, il faut des tests r\u00e9ussis, une approbation, et aucune d\u00e9pendance encore bloqu\u00e9e.',\n  door:'Range tes notes dans l\u2019ordre des phases du projet : Prepare, Explore, Realize, Deploy.'\n};\n\n\/* ---------- P1 : plan projet ---------- *\/\nfunction openP1(){\n  G.opened='p1';\n  var done=G.solved.p1;\n  openModal(head('p1','Remets le plan projet dans l\u2019ordre','Project & Task Management')+\n    '<p>Le tableau a \u00e9t\u00e9 effac\u00e9 \u00e0 moiti\u00e9. Le chef de projet structurait tout selon les phases SAP Activate, comme dans Cloud ALM. Replace les 5 phases dans le bon ordre.<\/p>'+\n    '<div class=\"slots5\" id=\"p1slots\"><\/div>'+\n    '<div class=\"chips\" id=\"p1pool\"><\/div>'+\n    '<div class=\"actions\"><button class=\"btn gold\" id=\"p1ok\" data-focus'+(done?' disabled':'')+'>Valider le plan<\/button><button class=\"btn ghost\" id=\"p1reset\"'+(done?' disabled':'')+'>Tout reprendre<\/button><span class=\"fb\" id=\"p1fb\"><\/span><\/div>'+\n    hintBox('p1')+\n    '<div class=\"solvezone\">'+(done?rewardHtml('p1',LINES.p1):'')+'<\/div>'+\n    '<p class=\"alm\">Dans Cloud ALM, chaque projet suit ces phases, avec ses t\u00e2ches, ses responsables et ses jalons.<\/p>');\n  drawP1();\n  $('p1ok').onclick=function(){\n    if(G.p1slots.indexOf(null)>=0){fb('p1fb','Place les 5 phases avant de valider.',false);return}\n    var good=G.p1slots.filter(function(v,i){return v===PHASES5[i]}).length;\n    if(good===5){solve('p1',LINES.p1);fb('p1fb','Plan r\u00e9tabli.',true);$('p1ok').disabled=true;$('p1reset').disabled=true;drawP1()}\n    else fb('p1fb',good+' phase'+(good>1?'s':'')+' sur 5 \u00e0 la bonne place.',false);\n  };\n  $('p1reset').onclick=function(){G.p1slots=[null,null,null,null,null];G.p1pool=shuffle(PHASES5);drawP1();fb('p1fb','',true)};\n}\nfunction drawP1(){\n  var done=G.solved.p1; var sl=done?PHASES5:G.p1slots;\n  $('p1slots').innerHTML=sl.map(function(v,i){return '<button class=\"slot'+(v?' fill':'')+'\" data-i=\"'+i+'\"><small>Phase '+(i+1)+'<\/small>'+(v?esc(v):'')+'<\/button>'}).join('');\n  var used=G.p1slots.filter(Boolean);\n  $('p1pool').innerHTML=done?'':G.p1pool.filter(function(v){return used.indexOf(v)<0}).map(function(v){return '<button class=\"chipb\" data-v=\"'+esc(v)+'\">'+esc(v)+'<\/button>'}).join('');\n  if(done)return;\n  Array.prototype.forEach.call($('p1pool').querySelectorAll('.chipb'),function(b){b.onclick=function(){var k=G.p1slots.indexOf(null);if(k>=0){G.p1slots[k]=b.getAttribute('data-v');drawP1()}}});\n  Array.prototype.forEach.call($('p1slots').querySelectorAll('.slot'),function(b){b.onclick=function(){G.p1slots[+b.getAttribute('data-i')]=null;drawP1()}});\n}\n\n\/* ---------- P2 : exigences ---------- *\/\nfunction openP2(){\n  G.opened='p2'; var done=G.solved.p2;\n  openModal(head('p2','Rattache chaque exigence \u00e0 son processus','Requirements')+\n    '<p>Dans l\u2019armoire, les fiches d\u2019exigences issues des ateliers Fit-to-Standard sont en vrac. Chacune doit \u00eatre rattach\u00e9e au bon processus de bout en bout.<\/p>'+\n    '<div class=\"tblwrap\"><table class=\"tbl\"><thead><tr><th>Exigence<\/th><th>Description<\/th><th>Processus<\/th><\/tr><\/thead><tbody>'+\n    REQS.map(function(r){\n      var v=done?r.p:(G.p2sel[r.id]||'');\n      return '<tr><td class=\"id\">'+r.id+'<\/td><td>'+esc(r.t)+'<\/td><td><select data-r=\"'+r.id+'\"'+(done?' disabled':'')+' aria-label=\"Processus pour '+r.id+'\"><option value=\"\">Choisir\u2026<\/option>'+\n        PROCS.map(function(p){return '<option'+(p===v?' selected':'')+'>'+p+'<\/option>'}).join('')+'<\/select><\/td><\/tr>';\n    }).join('')+'<\/tbody><\/table><\/div>'+\n    '<div class=\"actions\"><button class=\"btn gold\" id=\"p2ok\" data-focus'+(done?' disabled':'')+'>Valider les rattachements<\/button><span class=\"fb\" id=\"p2fb\"><\/span><\/div>'+\n    hintBox('p2')+\n    '<div class=\"solvezone\">'+(done?rewardHtml('p2',LINES.p2):'')+'<\/div>'+\n    '<p class=\"alm\">Dans Cloud ALM, les exigences sont reli\u00e9es aux processus et suivies jusqu\u2019\u00e0 leur r\u00e9alisation.<\/p>');\n  Array.prototype.forEach.call(modal.querySelectorAll('select'),function(s){s.onchange=function(){G.p2sel[s.getAttribute('data-r')]=s.value}});\n  $('p2ok').onclick=function(){\n    var empty=REQS.filter(function(r){return !G.p2sel[r.id]}).length;\n    if(empty){fb('p2fb','Il reste '+empty+' exigence'+(empty>1?'s':'')+' sans processus.',false);return}\n    var bad=REQS.filter(function(r){return G.p2sel[r.id]!==r.p}).length;\n    if(!bad){solve('p2',LINES.p2);fb('p2fb','Toutes les exigences sont rattach\u00e9es.',true);$('p2ok').disabled=true;Array.prototype.forEach.call(modal.querySelectorAll('select'),function(s){s.disabled=true})}\n    else fb('p2fb',bad+' rattachement'+(bad>1?'s':'')+' incorrect'+(bad>1?'s':'')+'.',false);\n  };\n}\n\n\/* ---------- P3 : tests ---------- *\/\nfunction openP3(){\n  G.opened='p3'; var done=G.solved.p3;\n  var stl={ok:['ok','R\u00e9ussi'],wait:['wait','En cours']};\n  openModal(head('p3','Trouve l\u2019exigence qui n\u2019est pas test\u00e9e','Test Management \u00b7 Traceability')+\n    '<p>Le test manager a laiss\u00e9 son rapport ouvert. Le go-live est bloqu\u00e9 : une exigence n\u2019est couverte par aucun cas de test. Laquelle ?<\/p>'+\n    '<div class=\"cols2\"><div class=\"tblwrap\"><table class=\"tbl\"><thead><tr><th>Exigence<\/th><th>Description<\/th><\/tr><\/thead><tbody>'+\n      REQS.map(function(r){return '<tr><td class=\"id\">'+r.id+'<\/td><td>'+esc(r.t)+'<\/td><\/tr>'}).join('')+\n    '<\/tbody><\/table><\/div><div class=\"tblwrap\"><table class=\"tbl\"><thead><tr><th>Cas de test<\/th><th>Couvre<\/th><th>Statut<\/th><\/tr><\/thead><tbody>'+\n      G.tcs.map(function(t){var s=stl[t.st];return '<tr><td class=\"id\">'+t.id+'<\/td><td class=\"id\">'+t.req+'<\/td><td><span class=\"st '+s[0]+'\">'+s[1]+'<\/span><\/td><\/tr>'}).join('')+\n    '<\/tbody><\/table><\/div><\/div>'+\n    '<div class=\"actions\"><span class=\"lab\" style=\"color:var(--grey)\">Exigence non couverte :<\/span><div class=\"reqbtns\" id=\"p3btns\">'+\n      REQS.map(function(r){return '<button data-r=\"'+r.id+'\"'+(done?' disabled':'')+'>'+r.id+'<\/button>'}).join('')+\n    '<\/div><\/div><span class=\"fb\" id=\"p3fb\"><\/span>'+\n    hintBox('p3')+\n    '<div class=\"solvezone\">'+(done?rewardHtml('p3',LINES.p3):'')+'<\/div>'+\n    '<p class=\"alm\">Dans Cloud ALM, la tra\u00e7abilit\u00e9 relie chaque exigence \u00e0 ses cas de test et \u00e0 leurs r\u00e9sultats. Un trou de couverture se voit avant le go-live.<\/p>');\n  Array.prototype.forEach.call($('p3btns').querySelectorAll('button'),function(b){b.onclick=function(){\n    var r=b.getAttribute('data-r');\n    if(r===G.uncovered){solve('p3',LINES.p3);fb('p3fb','Exact. Un cas de test est cr\u00e9\u00e9 et ex\u00e9cut\u00e9 pour '+r+'.',true);Array.prototype.forEach.call($('p3btns').querySelectorAll('button'),function(x){x.disabled=true})}\n    else{var c=G.tcs.filter(function(t){return t.req===r}).map(function(t){return t.id});fb('p3fb',r+' est couverte par '+c.join(', ')+'.',false)}\n  }});\n}\n\n\/* ---------- P4 : d\u00e9ploiement ---------- *\/\nfunction openP4(){\n  G.opened='p4'; var done=G.solved.p4;\n  function cls(v,good){return '<span class=\"st '+(v===good||v==='Aucune'?'ok':(v==='En attente'?'wait':'ko'))+'\">'+esc(v)+'<\/span>'}\n  openModal(head('p4','Une seule fonctionnalit\u00e9 peut partir ce soir','Change & Deployment Management')+\n    '<p>Le comit\u00e9 de changement n\u2019autorise qu\u2019un d\u00e9ploiement avant 22 h. Choisis la fonctionnalit\u00e9 pr\u00eate pour la production.<\/p>'+\n    '<div class=\"feats\">'+G.feats.map(function(f){\n      return '<div class=\"feat\"><div><span class=\"fid\">'+f.id+'<\/span><h4>'+esc(f.name)+'<\/h4><\/div><dl>'+\n        '<dt>Tests<\/dt><dd>'+cls(f.tests,'R\u00e9ussis')+'<\/dd>'+\n        '<dt>Approbation<\/dt><dd>'+cls(f.appr,'Approuv\u00e9e')+'<\/dd>'+\n        '<dt>Transports<\/dt><dd><span class=\"st ok\">'+esc(f.tr)+'<\/span><\/dd>'+\n        '<dt>D\u00e9pend de<\/dt><dd>'+(f.dep==='Aucune'?'<span class=\"st ok\">Aucune<\/span>':'<span class=\"st wait\">'+esc(f.dep)+'<\/span>')+'<\/dd>'+\n        '<\/dl><button class=\"btn\" data-f=\"'+f.id+'\"'+(done?' disabled':'')+'>D\u00e9ployer '+f.id+'<\/button><\/div>';\n    }).join('')+'<\/div>'+\n    '<span class=\"fb\" id=\"p4fb\"><\/span>'+\n    hintBox('p4')+\n    '<div class=\"solvezone\">'+(done?rewardHtml('p4',LINES.p4):'')+'<\/div>'+\n    '<p class=\"alm\">Dans Cloud ALM, chaque fonctionnalit\u00e9 porte ses tests, son approbation et ses transports. Le passage en production se d\u00e9cide sur des faits.<\/p>');\n  Array.prototype.forEach.call(modal.querySelectorAll('.feat .btn'),function(b){b.onclick=function(){\n    var f=G.feats.filter(function(x){return x.id===b.getAttribute('data-f')})[0];\n    if(f.role==='ok'){solve('p4',LINES.p4);fb('p4fb',f.id+' d\u00e9ploy\u00e9e en production.',true);Array.prototype.forEach.call(modal.querySelectorAll('.feat .btn'),function(x){x.disabled=true})}\n    else fb('p4fb',{test:f.id+' a un test en \u00e9chec. On ne d\u00e9ploie pas un \u00e9chec.',appr:f.id+' attend encore son approbation.',dep:f.id+' d\u00e9pend d\u2019une fonctionnalit\u00e9 qui n\u2019est pas approuv\u00e9e.'}[f.role],false);\n  }});\n}\n\nvar LINES={\n  p1:'Le plan est en place : la phase Prepare donne le premier chiffre.',\n  p2:'Les exigences sont rattach\u00e9es : la phase Explore donne ce chiffre.',\n  p3:'La couverture de tests est compl\u00e8te : la phase Realize donne ce chiffre.',\n  p4:'La fonctionnalit\u00e9 est en production : la phase Deploy donne ce chiffre.'\n};\n\n\/* ---------- door ---------- *\/\nfunction openDoor(){\n  G.opened='door';\n  var n=Object.keys(G.solved).length;\n  openModal('<div class=\"ey\"><span class=\"pill\" style=\"background:var(--gold)\">Go-live<\/span><span>Porte de la salle de bascule<\/span><\/div><h2>Saisis le code \u00e0 4 chiffres<\/h2>'+\n    '<p>Une \u00e9tiquette est coll\u00e9e sous le clavier : \u00ab Le code suit le cycle du projet. \u00bb Tu as '+n+' note'+(n>1?'s':'')+' sur 4. Un code faux co\u00fbte 30 secondes.<\/p>'+\n    '<div class=\"slots\" style=\"display:flex;gap:10px;flex-wrap:wrap\">'+G.found.map(function(p){var ph=PHASE[p];return '<div class=\"note got\"><b>'+G.code[p]+'<\/b><span><i style=\"background:'+ph.color+'\"><\/i>'+ph.name+'<\/span><\/div>'}).join('')+'<\/div>'+\n    '<div class=\"code\" id=\"codeView\"><\/div>'+\n    '<div class=\"keys\" id=\"keys\">'+[1,2,3,4,5,6,7,8,9].map(function(d){return '<button data-d=\"'+d+'\">'+d+'<\/button>'}).join('')+\n      '<button class=\"wide\" data-d=\"del\">Effacer<\/button><button class=\"wide\" data-d=\"ok\" style=\"background:var(--gold)\">Valider<\/button><\/div>'+\n    '<span class=\"fb\" id=\"dfb\"><\/span>'+hintBox('door'));\n  G.codeIn=''; drawCode();\n  Array.prototype.forEach.call($('keys').querySelectorAll('button'),function(b){b.onclick=function(){\n    var d=b.getAttribute('data-d');\n    if(d==='del')G.codeIn=G.codeIn.slice(0,-1);\n    else if(d==='ok')return tryCode();\n    else if(G.codeIn.length<4)G.codeIn+=d;\n    drawCode();\n  }});\n}\nfunction drawCode(){var h='';for(var i=0;i<4;i++)h+='<span>'+(G.codeIn[i]||'')+'<\/span>';$('codeView').innerHTML=h}\nfunction tryCode(){\n  if(G.codeIn.length<4){fb('dfb','Il faut 4 chiffres.',false);return}\n  var good=ORDER.map(function(p){return G.code[p]}).join('');\n  if(G.codeIn===good){win()}\n  else{G.penalty+=PENALTY_CODE;G.wrongCodes++;renderHud();fb('dfb','Code refus\u00e9. \u221230 secondes.',false);G.codeIn='';drawCode();if(remaining()<=0)timeUp()}\n}\n\n\/* ---------- joule ---------- *\/\nfunction askJoule(){\n  if(!G.running)return;\n  var p=G.opened;\n  if(!p){toast('Joule','Ouvre une \u00e9nigme pour demander un indice dessus');return}\n  if(G.hinted[p]||G.solved[p]){toast('Joule','Tu as d\u00e9j\u00e0 l\u2019indice pour cette \u00e9nigme');return}\n  G.hinted[p]=true;G.hints++;G.penalty+=PENALTY_HINT;renderHud();\n  var box=modal.querySelector('.box'); var zone=modal.querySelector('.solvezone')||$('dfb');\n  var div=document.createElement('div');div.className='joulehint';div.innerHTML='<span class=\"star\"><\/span><span>'+esc(HINTS[p])+'<\/span>';\n  zone.parentNode.insertBefore(div,zone);\n  var jr=$('mJouleRow');if(jr)jr.remove();\n  if(remaining()<=0)timeUp();\n}\n$('jouleBtn').onclick=askJoule;\n\n\/* ---------- helpers ---------- *\/\nfunction fb(id,t,ok){var e=$(id);if(!e)return;e.textContent=t;e.className='fb '+(ok?'ok':'ko')}\nvar toastT=0;\nfunction toast(a,b){var t=$('toast');t.innerHTML=esc(a)+(b?'<small>'+esc(b)+'<\/small>':'');t.hidden=false;clearTimeout(toastT);toastT=setTimeout(function(){t.hidden=true},2600)}\n\n\/* ---------- overlays ---------- *\/\nvar ov=$('ov');\nfunction showOv(h){ov.innerHTML='<div class=\"inner\">'+h+'<\/div>';ov.hidden=false;var f=ov.querySelector('[data-focus]');if(f)setTimeout(function(){f.focus({preventScroll:true})},30)}\nfunction noKeyboard(){try{return !matchMedia('(any-pointer: fine)').matches}catch(e){return false}}\nfunction showStart(){\n  newGame();\n  if(noKeyboard()){showOv('<span class=\"eyebrow\">D\u00e9monstrateur SAP Cloud ALM<\/span><h1>ALM <em>Escape<\/em><\/h1><p>Cet escape game se joue sur ordinateur, \u00e0 la souris. Ouvre cette page sur un PC.<\/p>');return}\n  showOv('<span class=\"eyebrow\">Escape game \u00b7 SAP Cloud ALM Implementation<\/span><h1>ALM <em>Escape<\/em><\/h1>'+\n    '<p>Vendredi, 21 h 45. Le go-live S\/4HANA de ton client est \u00e0 22 h. Le chef de projet est parti en cong\u00e9s et la salle de bascule est verrouill\u00e9e par un code \u00e0 4 chiffres.<\/p>'+\n    '<p>Tout le projet est dans Cloud ALM. Remets-le d\u2019aplomb, une \u00e9nigme par phase, et retrouve le code avant le go-live.<\/p>'+\n    '<div class=\"brief\">'+\n      '<div><b>4 \u00e9nigmes<\/b><span>Plan projet, exigences, tests, mise en production. Chacune donne une note avec un chiffre.<\/span><\/div>'+\n      '<div><b>15 minutes<\/b><span>Le chrono tourne d\u00e8s que tu entres. Un code faux co\u00fbte 30 secondes.<\/span><\/div>'+\n      '<div><b>Joule<\/b><span>L\u2019assistant IA donne un indice sur l\u2019\u00e9nigme ouverte. Chaque indice co\u00fbte 60 secondes.<\/span><\/div>'+\n      '<div><b>La porte<\/b><span>Quand tu penses avoir le code, clique sur la porte de bascule.<\/span><\/div>'+\n    '<\/div>'+\n    '<button class=\"btn gold\" id=\"bStart\" data-focus>Entrer dans la salle<\/button>');\n  $('bStart').onclick=function(){ov.hidden=true;startClock()};\n}\nfunction recapHtml(){\n  return '<div class=\"recap\">'+[\n    ['#E7B84A','Project & Task Management','phases, t\u00e2ches et jalons du projet'],\n    ['#4F9BD9','Requirements','exigences reli\u00e9es aux processus'],\n    ['#1FA38C','Test Management et tra\u00e7abilit\u00e9','chaque exigence couverte par un test'],\n    ['#D9483B','Change & Deployment','d\u00e9ployer sur des faits, pas sur des promesses']\n  ].map(function(r){return '<div><i style=\"background:'+r[0]+'\"><\/i><span><b style=\"color:var(--cream)\">'+r[1]+'<\/b> : '+r[2]+'<\/span><\/div>'}).join('')+'<\/div>';\n}\nfunction endCta(){return '<div class=\"cta\"><a href=\"https:\/\/www.hashdezo.fr\/index.php\/contact\/\" target=\"_blank\" rel=\"noopener\">R\u00e9server un diagnostic Cloud ALM \u00b7 30 min, gratuit<\/a><span class=\"mono\">sebastien@hashdezo.fr \u00b7 +33 6 22 61 65 16<\/span><\/div>'}\nfunction win(){\n  G.running=false; G.over=true; clearInterval(tick); closeModal();\n  $('door').classList.add('open'); $('doorSign').textContent='OUVERT';\n  var used=Math.min(DURATION,elapsed()), left=remaining();\n  setTimeout(function(){\n    showOv('<span class=\"eyebrow\">Porte ouverte \u00b7 go-live lanc\u00e9<\/span><h2>Tu as sauv\u00e9 le go-live avec '+fmt(left)+' d\u2019avance<\/h2>'+\n      '<div class=\"stats\"><div><b>'+fmt(used)+'<\/b><span>Temps utilis\u00e9<\/span><\/div><div><b>'+G.hints+'<\/b><span>Indices Joule<\/span><\/div><div><b>'+G.wrongCodes+'<\/b><span>Codes refus\u00e9s<\/span><\/div><\/div>'+\n      '<p>Les 4 salles de ce jeu sont 4 \u00e9crans d\u2019un m\u00eame outil. Dans Cloud ALM, le plan, les exigences, les tests et les d\u00e9ploiements sont reli\u00e9s entre eux.<\/p>'+\n      recapHtml()+\n      '<p class=\"punch\">Ton go-live ne devrait pas d\u00e9pendre d\u2019un tableau blanc effac\u00e9.<\/p>'+endCta()+\n      '<button class=\"btn gold\" id=\"bAgain\" data-focus>Rejouer<\/button>');\n    $('bAgain').onclick=showStart;\n  },900);\n}\nfunction timeUp(){\n  if(G.over)return;\n  G.running=false; G.over=true; clearInterval(tick); closeModal(); renderHud();\n  var n=Object.keys(G.solved).length;\n  showOv('<span class=\"eyebrow\">22 h \u00b7 temps \u00e9coul\u00e9<\/span><h2>Le go-live est report\u00e9<\/h2>'+\n    '<p>Tu as r\u00e9solu '+n+' \u00e9nigme'+(n>1?'s':'')+' sur 4. Sans une vue claire du projet, chaque information se cherche \u00e0 la main et le temps file.<\/p>'+\n    recapHtml()+\n    '<p class=\"punch\">Avec Cloud ALM, ces 4 r\u00e9ponses sont au m\u00eame endroit.<\/p>'+endCta()+\n    '<button class=\"btn gold\" id=\"bAgain\" data-focus>Rejouer<\/button>');\n  $('bAgain').onclick=showStart;\n}\n\n\/* ---------- input ---------- *\/\nArray.prototype.forEach.call(document.querySelectorAll('.obj[data-p]'),function(b){\n  b.addEventListener('click',function(){\n    if(!G.running)return;\n    var p=b.getAttribute('data-p');\n    ({p1:openP1,p2:openP2,p3:openP3,p4:openP4,door:openDoor})[p]();\n  });\n});\ndocument.addEventListener('keydown',function(e){\n  if(e.key==='Escape'&&!modal.hidden){closeModal()}\n  if(G&&G.opened==='door'&&!modal.hidden){\n    if(\/^[1-9]$\/.test(e.key)&&G.codeIn.length<4){G.codeIn+=e.key;drawCode()}\n    else if(e.key==='Backspace'){G.codeIn=G.codeIn.slice(0,-1);drawCode()}\n    else if(e.key==='Enter'){tryCode()}\n  }\n});\n\nshowStart();\n})();\n<\\\/script>\n\n<\/body><\/html>\n<\/script>\n<script>(function(){var t=document.getElementById('hz-escape-src'),f=document.getElementById('hz-escape-frame');if(!t||!f)return;f.srcdoc=t.textContent.replace(\/&#0?38;\/g,'&').replace(\/<\\\\\\\/script>\/g,'<\/'+'script>');function fit(){try{var d=f.contentDocument;if(d&&d.body){f.style.height=Math.max(600,d.documentElement.scrollHeight)+'px'}}catch(e){}}f.addEventListener('load',function(){fit();try{new ResizeObserver(fit).observe(f.contentDocument.body)}catch(e){setInterval(fit,1000)}});window.addEventListener('resize',function(){setTimeout(fit,150)});})();<\/script>\n\n\n\n<link rel='stylesheet' href='https:\/\/fonts.googleapis.com\/css2?family=Schibsted+Grotesk:wght@400;500;600;700&#038;family=IBM+Plex+Mono:wght@400;500&#038;display=swap'><div class='hzr' style='--hx:clamp(24px,4.5vw,64px);max-width:1440px;margin:48px auto 0;background:#FAF9F6;font-family:\"Schibsted Grotesk\",sans-serif;color:#141412'><footer class='hz-ft'><div><img src='https:\/\/www.hashdezo.fr\/wp-content\/uploads\/2020\/03\/Logo.jpg' alt='HASHdezO'><span class='t'>Conseil, r\u00e9alisation et formation SAP Cloud.<\/span><a href='https:\/\/support.sap.com\/en\/alm\/partners\/partner-powered-calm.html' target='_blank' rel='noopener' style='display:block;align-self:flex-start;margin-top:14px'><img src='https:\/\/www.hashdezo.fr\/wp-content\/uploads\/2026\/10\/powered-by-sap-cloud-alm.png' alt='Partner powered by SAP Cloud ALM' width='110' height='51' style='width:110px;height:auto;mix-blend-mode:normal;display:block'><\/a><\/div><div><span class='hz-m'>#HashALM<\/span><a href='\/index.php\/confluencealm\/'>Les 5 offres Cloud ALM<\/a><a href='\/index.php\/alm-escape\/'>ALM Escape<\/a><a href='\/index.php\/alm-runner\/'>ALM Runner<\/a><\/div><div><span class='hz-m'>Expertises<\/span><a href='\/index.php\/sap-rise-with-sap\/'>Cloud ERP &amp; RISE<\/a><a href='\/index.php\/offres\/'>SAP BTP<\/a><a href='\/index.php\/sapbw4hana\/'>Data &amp; Analytics<\/a><\/div><div><span class='hz-m'>Cabinet<\/span><a href='\/index.php\/nous\/'>\u00c0 propos<\/a><a href='\/index.php\/bibliotheque-cloud-alm\/'>Biblioth\u00e8que<\/a><a href='\/index.php\/paroles-d-experts\/'>Paroles d'experts<\/a><a href='\/index.php\/contact\/'>Contact<\/a><\/div><div><span class='hz-m'>Contact<\/span><a href='mailto:contact@hashdezo.fr'>contact@hashdezo.fr<\/a><a href='tel:+33622616516'>+33 6 22 61 65 16<\/a><span>229 rue Saint-Honor\u00e9, 75001 Paris<\/span><\/div><\/footer><div class='hz-fb'><span class='hz-m'>Certifi\u00e9 RISE with SAP \u00b7 SAP Cloud ALM \u00b7 Architecte SAP BTP \u00b7 SAP Integration Suite<\/span><span>\u00a9 2026 HASHdezO \u00b7 <a href='\/index.php\/mentions-legales\/' style='color:inherit'>Mentions l\u00e9gales<\/a><\/span><\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Conseil, r\u00e9alisation et formation SAP Cloud. #HashALMLes 5 offres Cloud ALMALM EscapeALM Runner ExpertisesCloud ERP &amp; RISESAP BTPData &amp; Analytics Cabinet\u00c0 proposBiblioth\u00e8queParoles d&rsquo;expertsContact Contactcontact@hashdezo.fr+33 6 22 61 65 16229 rue Saint-Honor\u00e9, 75001 Paris Certifi\u00e9 RISE with SAP \u00b7 SAP Cloud ALM \u00b7 Architecte SAP BTP \u00b7 SAP Integration Suite\u00a9 2026 HASHdezO \u00b7 Mentions l\u00e9gales<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"neve_meta_sidebar":"full-width","neve_meta_container":"full-width","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"on","neve_meta_disable_title":"on","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"class_list":["post-1148","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.hashdezo.fr\/index.php\/wp-json\/wp\/v2\/pages\/1148","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hashdezo.fr\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.hashdezo.fr\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.hashdezo.fr\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hashdezo.fr\/index.php\/wp-json\/wp\/v2\/comments?post=1148"}],"version-history":[{"count":0,"href":"https:\/\/www.hashdezo.fr\/index.php\/wp-json\/wp\/v2\/pages\/1148\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.hashdezo.fr\/index.php\/wp-json\/wp\/v2\/media?parent=1148"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}