276 lines
14 KiB
HTML
276 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>🎯 GO 100% · 3 actions finales Yacine</title>
|
||
<style>
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#0a0e1a;color:#e2e8f0;min-height:100vh;padding:40px 20px}
|
||
.wrap{max-width:900px;margin:0 auto}
|
||
h1{font-size:28px;margin-bottom:8px;background:linear-gradient(135deg,#10b981,#06b6d4);-webkit-background-clip:text;-webkit-text-fill-color:transparent;font-weight:800}
|
||
.sub{color:#94a3b8;font-size:14px;margin-bottom:32px}
|
||
.progress{background:#0f172a;border:1px solid #1e293b;border-radius:12px;padding:16px;margin-bottom:24px;display:flex;align-items:center;gap:16px}
|
||
.progress .bar{flex:1;background:#1e293b;height:8px;border-radius:4px;overflow:hidden}
|
||
.progress .fill{background:linear-gradient(90deg,#10b981,#06b6d4);height:100%;transition:width .6s}
|
||
.progress .pct{font-weight:800;font-size:22px;color:#10b981}
|
||
.card{background:#0f172a;border:1px solid #1e293b;border-radius:14px;padding:24px;margin-bottom:16px;transition:all .3s}
|
||
.card.done{opacity:.55;border-color:#10b981}
|
||
.card .head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px;flex-wrap:wrap;gap:10px}
|
||
.card h2{font-size:18px;color:#f1f5f9;font-weight:700}
|
||
.tag{font-size:11px;padding:3px 10px;border-radius:99px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}
|
||
.tag.critical{background:rgba(244,63,94,.15);color:#fb7185}
|
||
.tag.high{background:rgba(251,191,36,.15);color:#fbbf24}
|
||
.impact{color:#10b981;font-weight:700;font-size:13px}
|
||
.desc{color:#94a3b8;font-size:13px;line-height:1.6;margin:12px 0}
|
||
.steps{background:#050914;border-radius:8px;padding:14px;margin:10px 0;font-size:12.5px;line-height:1.7;color:#cbd5e1}
|
||
.steps strong{color:#e2e8f0}
|
||
.steps code{background:#1e293b;padding:2px 6px;border-radius:4px;font-family:ui-monospace,monospace;color:#5eead4;font-size:11.5px}
|
||
.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
|
||
.btn{padding:10px 18px;border-radius:8px;text-decoration:none;font-weight:600;font-size:13px;display:inline-flex;align-items:center;gap:8px;transition:all .2s;border:none;cursor:pointer;color:#fff}
|
||
.btn.primary{background:linear-gradient(135deg,#10b981,#06b6d4)}
|
||
.btn.primary:hover{transform:translateY(-1px);box-shadow:0 6px 16px rgba(16,185,129,.35)}
|
||
.btn.sec{background:#1e293b;color:#cbd5e1;border:1px solid #334155}
|
||
.btn.sec:hover{background:#334155}
|
||
.btn.done{background:#065f46;color:#6ee7b7}
|
||
.copy{background:#1e293b;color:#7dd3fc;border:1px solid #334155}
|
||
.tip{background:rgba(14,165,233,.08);border-left:3px solid #0ea5e9;padding:10px 14px;border-radius:0 8px 8px 0;margin-top:10px;font-size:12px;color:#bae6fd}
|
||
.draft{background:#050914;border:1px dashed #334155;border-radius:8px;padding:14px;margin-top:10px;font-size:12px;color:#cbd5e1;line-height:1.6;white-space:pre-wrap;max-height:240px;overflow:auto}
|
||
.footer{text-align:center;margin-top:40px;color:#475569;font-size:12px}
|
||
.footer a{color:#5eead4;text-decoration:none}
|
||
.done-check{color:#10b981;font-size:18px}
|
||
@media(max-width:600px){body{padding:20px 12px}h1{font-size:22px}.card{padding:16px}}
|
||
</style>
|
||
<!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-144052 -->
|
||
<style id="doctrine60-ux-direct">
|
||
|
||
/* DOCTRINE-60-UX-ENRICH injected-direct */
|
||
body::before {
|
||
content: '';
|
||
position: fixed;
|
||
top: 0; left: 0; width: 100vw; height: 100vh;
|
||
background: radial-gradient(circle at 50% 50%, rgba(100,180,255,0.08), transparent 60%);
|
||
pointer-events: none;
|
||
z-index: -1;
|
||
}
|
||
.card, .kpi, .panel, .btn {
|
||
transition: all 0.3s cubic-bezier(0.2,0,0.1,1);
|
||
}
|
||
.card:hover, .kpi:hover, .panel:hover {
|
||
box-shadow: 0 4px 20px rgba(100,180,255,0.2);
|
||
border-color: rgba(100,180,255,0.5);
|
||
}
|
||
@keyframes pulseD60 {
|
||
0%,100% { opacity: 1; transform: scale(1); }
|
||
50% { opacity: 0.7; transform: scale(1.05); }
|
||
}
|
||
.pulse, .live-indicator, .active, .online {
|
||
animation: pulseD60 3s ease-in-out infinite;
|
||
}
|
||
.modal, .chat, .speech, .overlay {
|
||
backdrop-filter: blur(12px);
|
||
-webkit-backdrop-filter: blur(12px);
|
||
}
|
||
.enter-stagger {
|
||
animation: enterStagD60 0.5s cubic-bezier(0.2,0,0.1,1) forwards;
|
||
}
|
||
@keyframes enterStagD60 {
|
||
from { opacity: 0; transform: translateY(20px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
</style>
|
||
<!-- DOCTRINE-222-KILL-PULSED60 -->
|
||
<style>
|
||
@keyframes pulseD60 { 0%,100%,50% { opacity: 1; transform: scale(1); } }
|
||
.pulse, .live-indicator, .active, .online { animation: none !important; }
|
||
</style>
|
||
<!-- END-DOCTRINE-222 -->
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<h1>🎯 GO 100% · 3 actions finales</h1>
|
||
<p class="sub">Les 3 derniers items du plan V71 bloqués — tous Yacine-only par design. Tout est pré-préparé ci-dessous. Chrono : <strong>5 minutes</strong>.</p>
|
||
|
||
<div class="progress">
|
||
<div class="pct" id="pct">0%</div>
|
||
<div class="bar"><div class="fill" id="fill" style="width:0%"></div></div>
|
||
<div style="color:#64748b;font-size:12px" id="counter">0/3 done</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<div class="card" id="card1">
|
||
<div class="head">
|
||
<div>
|
||
<h2>1️⃣ Kaouther Ethica · Contre-offre 3 paliers (280k€ Q1 renewal)</h2>
|
||
<div class="impact">💰 Impact : 280 000€ renewal Ethica Q1 · renégociation 0,8 → 1,0-1,5 DH/contact</div>
|
||
</div>
|
||
<span class="tag critical">CRITICAL · DP-P0-1</span>
|
||
</div>
|
||
|
||
<div class="desc">
|
||
Kaouther Najar (Groupe Ethica) demande <strong>0,8 DH/contact</strong>. Nous répondons avec 3 paliers selon volume d'engagement :
|
||
<strong>1,5 DH</strong> (< 50k contacts) · <strong>1,2 DH</strong> (50-150k) · <strong>1,0 DH</strong> (> 150k + engagement 12 mois).
|
||
</div>
|
||
|
||
<div class="steps">
|
||
<strong>3 étapes · 2 minutes :</strong><br>
|
||
① Clic "Ouvrir draft pré-rédigé" → la page s'ouvre avec email formaté<br>
|
||
② Clic "Ouvrir Gmail" → Gmail s'ouvre avec TO + subject + body pré-remplis<br>
|
||
③ Relis · signe · <strong>Envoyer</strong>
|
||
</div>
|
||
|
||
<div class="draft" id="draft1">Bonjour Kaouther,
|
||
|
||
Merci pour ton retour sur la proposition Ethica Q1 2026.
|
||
|
||
Nous comprenons la contrainte sur 0,8 DH/contact. Notre structure de coûts (146K HCPs validés Maghreb · infra IA souveraine · consent RGPD complet · PMTA 97% inbox) ne permet pas ce tarif sur volumes standards.
|
||
|
||
En revanche, nous pouvons proposer 3 paliers alignés sur l'engagement volume :
|
||
|
||
• Palier 1 — jusqu'à 50 000 contacts : 1,5 DH/contact
|
||
• Palier 2 — 50 000 à 150 000 contacts : 1,2 DH/contact
|
||
• Palier 3 — > 150 000 contacts + engagement 12 mois : 1,0 DH/contact
|
||
|
||
Cette structure permet de débloquer le volume tout en préservant la qualité (deliverability 97% O365 · tracking ADX · opt-in double confirmation).
|
||
|
||
Je te propose un call 30min cette semaine pour affiner les volumes cibles Q1-Q2. Mardi 14h ou mercredi 10h te conviendraient ?
|
||
|
||
Bien cordialement,
|
||
Yacine Mahboub
|
||
Partner & Founder · WEVAL Consulting</div>
|
||
|
||
<div class="actions">
|
||
<a class="btn primary" href="/kaouther-compose.html" target="_blank">📧 Ouvrir draft pré-rédigé</a>
|
||
<a class="btn sec" target="_blank" href="https://mail.google.com/mail/?view=cm&fs=1&to=kaouther.najar@ethica.ma&su=Ethica%20Q1%202026%20-%20Contre-offre%203%20paliers%20volumes%20engagement&body=Bonjour%20Kaouther%2C%0A%0AMerci%20pour%20ton%20retour%20sur%20la%20proposition%20Ethica%20Q1%202026.%0A%0ANous%20comprenons%20la%20contrainte%20sur%200%2C8%20DH%2Fcontact.%20Notre%20structure%20de%20co%C3%BBts%20%28146K%20HCPs%20valid%C3%A9s%20Maghreb%20%C2%B7%20infra%20IA%20souveraine%20%C2%B7%20consent%20RGPD%20complet%20%C2%B7%20PMTA%2097%25%20inbox%29%20ne%20permet%20pas%20ce%20tarif%20sur%20volumes%20standards.%0A%0AEn%20revanche%2C%20nous%20pouvons%20proposer%203%20paliers%20align%C3%A9s%20sur%20l%27engagement%20volume%20%3A%0A%0A%E2%80%A2%20Palier%201%20%E2%80%94%20jusqu%27%C3%A0%2050%20000%20contacts%20%3A%201%2C5%20DH%2Fcontact%0A%E2%80%A2%20Palier%202%20%E2%80%94%2050%20000%20%C3%A0%20150%20000%20contacts%20%3A%201%2C2%20DH%2Fcontact%0A%E2%80%A2%20Palier%203%20%E2%80%94%20%3E%20150%20000%20contacts%20%2B%20engagement%2012%20mois%20%3A%201%2C0%20DH%2Fcontact%0A%0ACette%20structure%20permet%20de%20d%C3%A9bloquer%20le%20volume%20tout%20en%20pr%C3%A9servant%20la%20qualit%C3%A9.%0A%0AJe%20te%20propose%20un%20call%2030min%20cette%20semaine%20pour%20affiner%20les%20volumes%20cibles%20Q1-Q2.%20Mardi%2014h%20ou%20mercredi%2010h%20te%20conviendraient%20%3F%0A%0ABien%20cordialement%2C%0AYacine%20Mahboub%0APartner%20%26%20Founder%20%C2%B7%20WEVAL%20Consulting">📬 Ouvrir Gmail (tout pré-rempli)</a>
|
||
<button class="btn copy" onclick="navigator.clipboard.writeText(document.getElementById('draft1').textContent);this.textContent='✓ Copié'">📋 Copier le body</button>
|
||
<button class="btn done" onclick="markDone(1)">✓ J'ai envoyé</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<div class="card" id="card2">
|
||
<div class="head">
|
||
<div>
|
||
<h2>2️⃣ Azure AD · Re-register 3 tenants expirés</h2>
|
||
<div class="impact">🔐 Impact : Re-active Microsoft Graph API · 604 comptes O365 · 9 tenants · 288 domaines vérifiés</div>
|
||
</div>
|
||
<span class="tag high">HIGH · DP-P0-2</span>
|
||
</div>
|
||
|
||
<div class="desc">
|
||
3 tenants Azure AD sont en état expiré (admin consent lapsed). Il faut :
|
||
re-consent admin pour les 3 apps Microsoft Graph + mettre à jour `GRAPH_CLIENT_ID` et `TENANT_ID` dans `/etc/weval/secrets.env`.
|
||
</div>
|
||
|
||
<div class="steps">
|
||
<strong>Étapes · 1-2 minutes :</strong><br>
|
||
① <a href="https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview" target="_blank" style="color:#5eead4">Ouvrir portail Azure AD</a> → "App registrations" → identifier les 3 apps expirées<br>
|
||
② Pour chaque app : <code>Authentication → Grant admin consent for ...</code><br>
|
||
③ Copier les 3 Client IDs + Tenant IDs → me les envoyer, je les ajoute à secrets.env
|
||
</div>
|
||
|
||
<div class="tip">
|
||
💡 Une fois que tu m'envoies les IDs, je fais : <code>sudo sh -c 'echo "GRAPH_CLIENT_ID_1=..." >> /etc/weval/secrets.env'</code> puis je re-teste Graph API.
|
||
</div>
|
||
|
||
<div class="actions">
|
||
<a class="btn primary" href="https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview" target="_blank">☁️ Ouvrir Azure AD Portal</a>
|
||
<a class="btn sec" href="https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade" target="_blank">📋 App registrations</a>
|
||
<button class="btn done" onclick="markDone(2)">✓ Fait, IDs envoyés</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<div class="card" id="card3">
|
||
<div class="head">
|
||
<div>
|
||
<h2>3️⃣ OVH · SMS credentials renewal</h2>
|
||
<div class="impact">📱 Impact : SMS 2FA + alerts critical · compte Wevalconsulting</div>
|
||
</div>
|
||
<span class="tag high">HIGH · DP-P0-3</span>
|
||
</div>
|
||
|
||
<div class="desc">
|
||
Les credentials OVH SMS API ont expiré. Il faut générer un nouveau token OVH avec droits <code>GET /sms/*</code> et <code>POST /sms/*</code>.
|
||
</div>
|
||
|
||
<div class="steps">
|
||
<strong>Étapes · 1 minute :</strong><br>
|
||
① <a href="https://www.ovh.com/auth/api/createToken?GET=/sms/*&POST=/sms/*&PUT=/sms/*&DELETE=/sms/*" target="_blank" style="color:#5eead4">Créer token OVH (lien pré-configuré avec droits SMS)</a><br>
|
||
② Login compte Wevalconsulting<br>
|
||
③ Copier les 3 tokens générés (Application Key + Secret + Consumer Key) → me les envoyer
|
||
</div>
|
||
|
||
<div class="tip">
|
||
💡 Le lien ci-dessus est pré-configuré avec les droits exacts nécessaires (GET/POST/PUT/DELETE sur /sms/*). Tu n'as qu'à valider le formulaire.
|
||
</div>
|
||
|
||
<div class="actions">
|
||
<a class="btn primary" href="https://www.ovh.com/auth/api/createToken?GET=/sms/*&POST=/sms/*&PUT=/sms/*&DELETE=/sms/*" target="_blank">🔑 Créer token OVH SMS (pré-configuré)</a>
|
||
<a class="btn sec" href="https://www.ovh.com/manager/#/dashboard" target="_blank">🏠 OVH Manager</a>
|
||
<button class="btn done" onclick="markDone(3)">✓ Fait, tokens envoyés</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer">
|
||
Plan V71 · 25 items · 22 done · après ces 3 actions → <strong style="color:#10b981">25/25 = 100%</strong><br>
|
||
<a href="/weval-technology-platform.html">← WTP</a> · <a href="/owner-actions-tracker.html">Owner Actions Tracker</a> · <a href="/api/wevia-v71-risk-halu-plan.php" target="_blank">Plan V71 JSON</a>
|
||
</div>
|
||
|
||
</div>
|
||
<script>
|
||
function markDone(n){
|
||
const card = document.getElementById('card'+n);
|
||
card.classList.add('done');
|
||
const doneBtn = card.querySelector('.btn.done');
|
||
doneBtn.textContent = '✓ Complété';
|
||
doneBtn.disabled = true;
|
||
updateProgress();
|
||
try{
|
||
let state = JSON.parse(localStorage.getItem('go100pct') || '{}');
|
||
state[n] = true;
|
||
localStorage.setItem('go100pct', JSON.stringify(state));
|
||
}catch(e){}
|
||
}
|
||
function updateProgress(){
|
||
const done = document.querySelectorAll('.card.done').length;
|
||
const pct = Math.round((done/3)*100);
|
||
document.getElementById('pct').textContent = pct + '%';
|
||
document.getElementById('fill').style.width = pct + '%';
|
||
document.getElementById('counter').textContent = done + '/3 done';
|
||
if(pct === 100){
|
||
document.getElementById('pct').textContent = '🏆 100%';
|
||
alert('🏆 GO 100% atteint ! Plan V71 complet. Envoie les credentials quand tu les as, je les wire.');
|
||
}
|
||
}
|
||
// Restore state
|
||
try{
|
||
const state = JSON.parse(localStorage.getItem('go100pct') || '{}');
|
||
Object.keys(state).forEach(k=>{if(state[k]) markDone(parseInt(k))});
|
||
}catch(e){}
|
||
</script>
|
||
|
||
<script src="/api/a11y-auto-enhancer.js" defer></script>
|
||
<!-- WTP_UDOCK_V1 (Opus 21-avr t34final) --><script src="/wtp-unified-dock.js" defer></script>
|
||
<script src="/opus-antioverlap-doctrine.js?v=1777045903" defer></script>
|
||
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-direct">
|
||
|
||
// DOCTRINE-60-UX-JS staggered entrance
|
||
(function(){
|
||
if (!('IntersectionObserver' in window)) return;
|
||
const obs = new IntersectionObserver((entries) => {
|
||
entries.forEach((e, i) => {
|
||
if (e.isIntersecting) {
|
||
setTimeout(() => e.target.classList.add('enter-stagger'), i * 80);
|
||
obs.unobserve(e.target);
|
||
}
|
||
});
|
||
});
|
||
document.querySelectorAll('.card, .kpi, .panel').forEach(el => obs.observe(el));
|
||
})();
|
||
|
||
</script>
|
||
</body>
|
||
</html>
|