`:'';
return `
`;
}
function animMobBlock(id){
const obs=new IntersectionObserver((es)=>{es.forEach(e=>{ if(!e.isIntersecting)return;
e.target.querySelectorAll('.ssp-mc').forEach((c,i)=>setTimeout(()=>{ c.classList.add('in');
const f=c.querySelector('.ssp-mc-fill'); if(f) setTimeout(()=>f.style.width=f.dataset.w+'%',150); }, i*120));
obs.unobserve(e.target);
});},{threshold:.1});
const el=document.getElementById(id); if(el)obs.observe(el);
}
/* ============ VIZ 01 — WAVE (conservée) ============ */
(function(){
const svg=d3.select('#sspWave'); const W=1100,H=520,m={t:40,r:140,b:50,l:60};
const years=[2019,2020,2021,2022,2023,2024,2025,2026];
const gdp=[100,93,99,101.5,103.0,103.8,104.4,104.9];
const cap=[100,92,95,95.6,95.4,95.0,94.8,94.6];
const x=d3.scalePoint().domain(years).range([m.l,W-m.r]);
const y=d3.scaleLinear().domain([88,108]).range([H-m.b,m.t]);
[90,95,100,105].forEach(v=>{ svg.append('line').attr('x1',m.l).attr('x2',W-m.r).attr('y1',y(v)).attr('y2',y(v)).attr('stroke',C.ink).attr('stroke-opacity',.08);
svg.append('text').attr('x',m.l-10).attr('y',y(v)+4).attr('text-anchor','end').attr('font-family',MONO).attr('font-size',10).attr('fill',C.mute).text(v); });
svg.append('line').attr('x1',m.l).attr('x2',W-m.r).attr('y1',y(100)).attr('y2',y(100)).attr('stroke',C.blueSoft).attr('stroke-dasharray','2 5').attr('stroke-opacity',.5);
svg.append('text').attr('x',W-m.r).attr('y',y(100)-6).attr('text-anchor','end').attr('font-family',MONO).attr('font-size',9).attr('fill',C.blueSoft).text('NIVEAU 2019');
years.forEach(yr=> svg.append('text').attr('x',x(yr)).attr('y',H-m.b+20).attr('text-anchor','middle').attr('font-family',MONO).attr('font-size',10).attr('fill',C.mute).text(yr) );
const lineG=d3.line().x((d,i)=>x(years[i])).y(d=>y(d)).curve(d3.curveMonotoneX);
const areaCap=d3.area().x((d,i)=>x(years[i])).y0(y(100)).y1(d=>y(d)).curve(d3.curveMonotoneX);
const clip=svg.append('clipPath').attr('id','sspWaveClip'); const clipRect=clip.append('rect').attr('x',m.l).attr('y',m.t).attr('width',0).attr('height',H);
svg.append('path').datum(cap).attr('d',areaCap).attr('fill',C.red).attr('opacity',.10).attr('clip-path','url(#sspWaveClip)');
const pGdp=svg.append('path').datum(gdp).attr('fill','none').attr('stroke',C.gold).attr('stroke-width',3).attr('d',lineG);
const pCap=svg.append('path').datum(cap).attr('fill','none').attr('stroke',C.red).attr('stroke-width',3).attr('d',lineG);
[pGdp,pCap].forEach(p=>{ const L=p.node().getTotalLength(); p.attr('stroke-dasharray',L).attr('stroke-dashoffset',L); });
const lgG=svg.append('text').attr('x',x(2026)+8).attr('y',y(gdp[7])).attr('font-family',SERIF).attr('font-style','italic').attr('font-size',14).attr('font-weight',600).attr('fill',C.goldDeep).attr('opacity',0).text('PIB affiché');
const lgC=svg.append('text').attr('x',x(2026)+8).attr('y',y(cap[7])+4).attr('font-family',SERIF).attr('font-style','italic').attr('font-size',14).attr('font-weight',600).attr('fill',C.red).attr('opacity',0).text('PIB / habitant');
onView('#sspWave',()=>{
pGdp.transition().duration(1800).ease(d3.easeCubicInOut).attr('stroke-dashoffset',0);
pCap.transition().duration(1800).delay(300).ease(d3.easeCubicInOut).attr('stroke-dashoffset',0);
clipRect.transition().duration(2000).delay(400).attr('width',W);
lgG.transition().delay(1900).duration(500).attr('opacity',1);
lgC.transition().delay(2100).duration(500).attr('opacity',1);
});
document.getElementById('mobWave').innerHTML =
mcCard('PIB affiché · 2026','104,9 (base 100 = 2019)','La croissance officielle ~2,6 % résulte surtout d\'un effet de rattrapage statistique sur des bases déprimées.',C.gold,98)+
mcCard('PIB réel par habitant · 2026','94,6 — sous le niveau 2019','Le revenu par tête n\'a jamais retrouvé son niveau d\'avant-pandémie : la « reprise » masque une stagnation profonde.',C.red,76);
animMobBlock('mobWave');
})();
/* ============ VIZ 02 — BASKET (barres divergentes animées) ============ */
(function(){
const svg=d3.select('#sspBasket'); const W=1100,H=480,m={t:60,r:60,b:50,l:240};
const rows=[
{name:'Protéines animales',a:42,b:27,col:C.red},
{name:'Céréales & féculents',a:28,b:46,col:C.gold},
{name:'Fruits, légumes, autres',a:30,b:27,col:C.blueSoft}
];
const x=d3.scaleLinear().domain([0,50]).range([m.l,W-m.r]);
const bh=46, gap=40;
svg.append('text').attr('x',m.l).attr('y',34).attr('font-family',MONO).attr('font-size',11).attr('letter-spacing','.15em').attr('fill',C.mute).text('PART DU PANIER (%) — ◇ AVANT ● SOUS CONTRAINTE 2026');
[0,10,20,30,40,50].forEach(v=>{ svg.append('line').attr('x1',x(v)).attr('x2',x(v)).attr('y1',m.t-8).attr('y2',H-m.b).attr('stroke',C.ink).attr('stroke-opacity',.07);
svg.append('text').attr('x',x(v)).attr('y',H-m.b+20).attr('text-anchor','middle').attr('font-family',MONO).attr('font-size',10).attr('fill',C.mute).text(v); });
rows.forEach((r,i)=>{
const yc=m.t+i*(bh+gap)+bh/2;
svg.append('text').attr('x',m.l-16).attr('y',yc+5).attr('text-anchor','end').attr('font-family',SERIF).attr('font-style','italic').attr('font-size',18).attr('font-weight',600).attr('fill',C.ink).text(r.name);
// ghost "avant"
svg.append('rect').attr('x',m.l).attr('y',yc-bh/2).attr('height',bh).attr('width',x(r.a)-m.l).attr('fill','none').attr('stroke',r.col).attr('stroke-dasharray','4 4').attr('stroke-opacity',.6);
svg.append('text').attr('x',x(r.a)+6).attr('y',yc-12).attr('font-family',MONO).attr('font-size',11).attr('fill',C.mute).attr('class','bk-a-'+i).attr('opacity',0).text('◇ '+r.a+'%');
// bar "après" animée
const bar=svg.append('rect').attr('x',m.l).attr('y',yc-bh/2).attr('height',bh).attr('width',0).attr('fill',r.col).attr('opacity',.9).attr('class','bk-bar-'+i);
const val=svg.append('text').attr('x',m.l+6).attr('y',yc+5).attr('font-family',MONO).attr('font-size',13).attr('font-weight',700).attr('fill',C.paper).attr('opacity',0).attr('class','bk-v-'+i).text(r.b+'%');
const delta=r.b-r.a;
svg.append('text').attr('x',W-m.r).attr('y',yc+5).attr('text-anchor','end').attr('font-family',SERIF).attr('font-style','italic').attr('font-size',16).attr('font-weight',600).attr('fill',delta>=0?C.gold:C.red).attr('opacity',0).attr('class','bk-d-'+i).text((delta>=0?'+':'')+delta+' pts');
onView('#sspBasket',()=>{
bar.transition().duration(1400).delay(i*250).ease(d3.easeCubicInOut).attr('width',x(r.b)-m.l);
svg.select('.bk-v-'+i).transition().delay(i*250+700).duration(400).attr('opacity',1);
svg.select('.bk-a-'+i).transition().delay(i*250+300).duration(400).attr('opacity',1);
svg.select('.bk-d-'+i).transition().delay(i*250+1100).duration(400).attr('opacity',1);
});
});
document.getElementById('mobBasket').innerHTML =
mcCard('Protéines animales','42 % → 27 %','La consommation de viande et de produits laitiers recule sous la pression budgétaire.',C.red,27)+
mcCard('Céréales & féculents','28 % → 46 %','Les ménages se rabattent sur des produits moins coûteux mais moins nutritifs.',C.gold,46)+
mcCard('Fruits, légumes, autres','30 % → 27 %','Une bascule anthropologique du régime alimentaire, pas seulement économique.',C.blueSoft,27);
animMobBlock('mobBasket');
})();
/* ============ VIZ 03 — CROWDING (barres empilées : où va le crédit) ============ */
(function(){
const svg=d3.select('#sspCrowd'); const W=1100,H=500,m={t:56,r:40,b:56,l:60};
const years=[2018,2020,2022,2024,2026];
const state=[42,50,58,65,71];
const x=d3.scalePoint().domain(years).range([m.l+40,W-m.r-120]).padding(0.5);
const y=d3.scaleLinear().domain([0,100]).range([H-m.b,m.t]);
const bw=72;
// axes
[0,25,50,75,100].forEach(v=>{ svg.append('line').attr('x1',m.l).attr('x2',W-m.r-120).attr('y1',y(v)).attr('y2',y(v)).attr('stroke',C.ink).attr('stroke-opacity',.08);
svg.append('text').attr('x',m.l-10).attr('y',y(v)+4).attr('text-anchor','end').attr('font-family',MONO).attr('font-size',10).attr('fill',C.mute).text(v+'%'); });
svg.append('text').attr('x',m.l).attr('y',32).attr('font-family',MONO).attr('font-size',11).attr('letter-spacing','.15em').attr('fill',C.mute).text('RÉPARTITION DU CRÉDIT BANCAIRE (%)');
years.forEach((yr,i)=>{
const cxb=x(yr);
svg.append('text').attr('x',cxb).attr('y',H-m.b+22).attr('text-anchor','middle').attr('font-family',MONO).attr('font-size',11).attr('fill',C.ink).attr('font-weight',i===years.length-1?700:400).text(yr);
// segment PME (bas) + segment État (haut), animés
const prodPct=100-state[i];
const rProd=svg.append('rect').attr('x',cxb-bw/2).attr('y',y(0)).attr('width',bw).attr('height',0).attr('fill',C.goldSoft).attr('opacity',.85);
const rState=svg.append('rect').attr('x',cxb-bw/2).attr('y',y(0)).attr('width',bw).attr('height',0).attr('fill',C.red).attr('opacity',.9);
const tState=svg.append('text').attr('x',cxb).attr('y',y(0)).attr('text-anchor','middle').attr('font-family',MONO).attr('font-size',12).attr('font-weight',700).attr('fill',C.paper).attr('opacity',0).text(state[i]+'%');
onView('#sspCrowd',()=>{
rProd.transition().duration(1100).delay(i*150).ease(d3.easeCubicOut)
.attr('y',y(prodPct)).attr('height',y(0)-y(prodPct));
rState.transition().duration(1100).delay(i*150+250).ease(d3.easeCubicOut)
.attr('y',y(100)).attr('height',y(prodPct)-y(100));
tState.transition().delay(i*150+900).duration(400).attr('opacity',1).attr('y',y(100)+ (y(prodPct)-y(100))/2 +4);
});
});
// légende latérale
const lg=svg.append('g').attr('transform',`translate(${W-m.r-100},${m.t+10})`);
[['État & entreprises publiques',C.red],['Économie productive (PME)',C.goldSoft]].forEach((d,i)=>{
const gy=i*34; lg.append('rect').attr('y',gy).attr('width',16).attr('height',16).attr('fill',d[1]).attr('opacity',.9);
lg.append('text').attr('x',22).attr('y',gy+9).attr('dominant-baseline','middle').attr('font-family',SERIF).attr('font-style','italic').attr('font-size',15).attr('font-weight',600).attr('fill',C.ink).text(d[0]);
});
lg.append('text').attr('y',92).attr('font-family',SANS).attr('font-size',11).attr('fill',C.mute).text('42 % → 71 % capté');
lg.append('text').attr('y',108).attr('font-family',SANS).attr('font-size',11).attr('fill',C.mute).text('par l\'État en 8 ans');
document.getElementById('mobCrowd').innerHTML =
mcCard('2018 · État & EP','42 % du crédit bancaire','Le système bancaire finance encore largement l\'économie productive.',C.red,42)+
mcCard('2026 · État & EP','71 % du crédit bancaire','L\'État absorbe une part croissante des ressources : effet d\'éviction sur les PME.',C.red,71)+
mcCard('2026 · Économie productive','29 % seulement','Les PME se heurtent à un rationnement implicite du crédit.',C.goldSoft,29);
animMobBlock('mobCrowd');
})();
/* ============ VIZ 04 — CASCADE (onde de choc) ============ */
(function(){
const svg=d3.select('#sspCascade'); const W=1100,H=520;
const steps=[
['Choc des prix','de l\'énergie',C.gold],
['Déficit','budgétaire',C.goldDeep],
['Pression sur','les réserves',C.blueSoft],
['Hausse des','coûts industriels',C.blue],
['Inflation','alimentaire',C.redSoft],
['Tension','sociale',C.red]
];
const n=steps.length, cw=(W-120)/n, top=120;
const defs=svg.append('defs');
defs.append('marker').attr('id','sspCasArrow').attr('viewBox','0 0 10 10').attr('refX',9).attr('refY',5).attr('markerWidth',7).attr('markerHeight',7).attr('orient','auto').append('path').attr('d','M0,0 L10,5 L0,10 Z').attr('fill',C.mute);
steps.forEach((s,i)=>{
const xx=60+cw*i+cw/2, yStep=top+i*46;
const g=svg.append('g').attr('class','cas-'+i).attr('transform',`translate(${xx},${yStep})`).attr('opacity',0);
g.append('rect').attr('x',-cw*0.42).attr('y',-32).attr('width',cw*0.84).attr('height',64).attr('rx',4).attr('fill',C.paper).attr('stroke',s[2]).attr('stroke-width',2);
g.append('rect').attr('x',-cw*0.42).attr('y',-32).attr('width',5).attr('height',64).attr('fill',s[2]);
g.append('text').attr('text-anchor','middle').attr('y',-4).attr('font-family',SERIF).attr('font-style','italic').attr('font-size',15).attr('font-weight',600).attr('fill',C.ink).text(s[0]);
g.append('text').attr('text-anchor','middle').attr('y',15).attr('font-family',SERIF).attr('font-style','italic').attr('font-size',15).attr('font-weight',600).attr('fill',C.ink).text(s[1]);
g.append('text').attr('text-anchor','middle').attr('y',-44).attr('font-family',MONO).attr('font-size',11).attr('fill',s[2]).attr('font-weight',700).text((i+1).toString().padStart(2,'0'));
if(i{
steps.forEach((s,i)=>{
svg.select('.cas-'+i).transition().duration(500).delay(i*320).attr('opacity',1);
if(i
mcCard('Maillon '+(i+1).toString().padStart(2,'0'), s[0]+' '+s[1].toLowerCase(),
i===0?'Le déclencheur extérieur : la hausse durable du baril et du gaz importés.':
i===n-1?'Le terme de la chaîne : carburants, transports et pouvoir d\'achat sous tension.':
'Maillon intermédiaire de la propagation, que le budget de l\'État ne peut plus amortir.', s[2], null)
).join('');
animMobBlock('mobCascade');
})();
/* ============ VIZ 05 — WEB (réseau radial des médiations qui se rompt) ============ */
(function(){
const svg=d3.select('#sspWeb'); const W=1100,H=560,cx=W/2,cy=H/2-10,R=190;
const ring=['UGTT','Partis','Patronat','Société civile','Coll. locales','Médias','Associations'];
const N=ring.length;
const defs=svg.append('defs');
const glow=defs.append('radialGradient').attr('id','sspHubGlow');
glow.append('stop').attr('offset','0%').attr('stop-color',C.red).attr('stop-opacity',.35);
glow.append('stop').attr('offset','100%').attr('stop-color',C.red).attr('stop-opacity',0);
svg.append('circle').attr('cx',cx).attr('cy',cy).attr('r',R*0.9).attr('fill','url(#sspHubGlow)');
const nodes=ring.map((l,i)=>{ const a=i/N*6.283-Math.PI/2; return {l,a,x0:cx+Math.cos(a)*R,y0:cy+Math.sin(a)*R}; });
// liens : rayon État→nœud + arcs entre voisins (le maillage social)
const links=[];
nodes.forEach((n,i)=>{ links.push({type:'spoke',i}); links.push({type:'arc',i,j:(i+1)%N}); });
const linkSel=svg.append('g').selectAll('path').data(links).enter().append('path')
.attr('fill','none').attr('stroke',C.gold).attr('stroke-width',2).attr('stroke-opacity',0);
// hub central (État)
const hub=svg.append('g').attr('transform',`translate(${cx},${cy})`).attr('opacity',0);
hub.append('circle').attr('r',26).attr('fill',C.red).attr('stroke',C.paper).attr('stroke-width',3);
hub.append('text').attr('text-anchor','middle').attr('dominant-baseline','middle').attr('font-family',SERIF).attr('font-style','italic').attr('font-weight',700).attr('font-size',18).attr('fill',C.paper).text('État');
const nodeSel=svg.append('g').selectAll('g').data(nodes).enter().append('g').attr('opacity',0).attr('transform',d=>`translate(${d.x0},${d.y0})`);
nodeSel.append('circle').attr('r',12).attr('fill',C.gold).attr('stroke',C.paper).attr('stroke-width',2);
nodeSel.append('text').attr('text-anchor','middle').attr('y',d=>Math.sin(d.a)<0?-22:30).attr('font-family',SERIF).attr('font-style','italic').attr('font-weight',600).attr('font-size',15).attr('fill',C.ink).text(d=>d.l);
function geom(decay){
// decay 0 → cohésion ; 1 → délitement (nœuds repoussés, liens distendus)
const yMax = H-46; // garde-fou : ne pas descendre sur la légende du bas
return nodes.map(n=>{ const r=R*(1+decay*0.34); const drift=(Math.sin(n.a*3)*decay*22);
const x=cx+Math.cos(n.a)*r+drift;
const y=Math.min(yMax, cy+Math.sin(n.a)*r);
return {x, y}; });
}
function render(decay){
const pos=geom(decay);
nodeSel.attr('transform',(d,i)=>`translate(${pos[i].x},${pos[i].y})`);
linkSel
.attr('d',d=>{
if(d.type==='spoke'){ const p=pos[d.i];
const mx=(cx+p.x)/2+Math.sin(d.i)*decay*30, my=(cy+p.y)/2;
return `M ${cx} ${cy} Q ${mx} ${my} ${p.x} ${p.y}`; }
const a=pos[d.i], b=pos[d.j];
const mx=(a.x+b.x)/2, my=(a.y+b.y)/2 - (1-decay)*30; // courbure qui s'aplatit
return `M ${a.x} ${a.y} Q ${mx} ${my} ${b.x} ${b.y}`;
})
.attr('stroke-opacity',d=> (d.type==='arc'?0.7:0.55)*(1-decay*0.85))
.attr('stroke-width',2*(1-decay*0.6))
.attr('stroke-dasharray',d=> decay>0.4 ? `${2+decay*4} ${decay*9}` : 'none');
}
render(0);
onView('#sspWeb',()=>{
hub.transition().duration(700).attr('opacity',1);
nodeSel.transition().duration(700).delay((d,i)=>i*70).attr('opacity',1);
linkSel.transition().duration(900).delay(500).attr('stroke-opacity',d=>d.type==='arc'?0.7:0.55);
if(!reduced){
ScrollTrigger.create({trigger:'#sspWeb',start:'top 65%',end:'bottom 25%',scrub:true,
onUpdate:self=>render(self.progress)});
}
});
svg.append('text').attr('x',cx).attr('y',H-14).attr('text-anchor','middle').attr('font-family',MONO).attr('font-size',10).attr('letter-spacing','.12em').attr('fill',C.mute).attr('opacity',0).attr('class','web-cap').text('MAILLAGE COHÉSIF → LIENS DISTENDUS, AU FIL DU DÉFILEMENT');
onView('#sspWeb',()=>svg.select('.web-cap').transition().delay(1200).duration(600).attr('opacity',1));
document.getElementById('mobWeb').innerHTML =
mcCard('Hier','Un maillage cohésif','L\'État au centre, relié à des institutions intermédiaires solides qui transformaient les tensions en négociations.',C.gold,82)+
mcCard('Aujourd\'hui','Des liens distendus','UGTT au rôle réduit, partis discrédités, collectivités affaiblies, société civile sous pression.',C.red,32)+
mcCard('Conséquence','Gouvernabilité en érosion','Les frustrations ne sont plus absorbées : elles s\'accumulent silencieusement.',C.redSoft,58);
animMobBlock('mobWeb');
})();
/* ============ VIZ 06 — RADAR ============ */
(function(){
const svg=d3.select('#sspRadar'); const W=900,H=620,cx=W/2,cy=H/2+10,maxR=190;
const data=[
{axis:'Stagnation',val:.82},{axis:'Énergie',val:.88},{axis:'Alimentaire',val:.60},
{axis:'Bancaire',val:.78},{axis:'Monnaie',val:.72},{axis:'Services publics',val:.70},{axis:'Médiations',val:.83}
];
const N=data.length;
svg.append('text').attr('x',cx).attr('y',26).attr('text-anchor','middle').attr('font-family',MONO).attr('font-size',10).attr('letter-spacing','.25em').attr('fill',C.mute).text('SURFACE DE VULNÉRABILITÉ');
[.25,.5,.75,1].forEach(t=>{ const pts=[]; for(let i=0;i<=N;i++){const a=(i%N)/N*6.283-Math.PI/2; pts.push([cx+Math.cos(a)*maxR*t,cy+Math.sin(a)*maxR*t]);}
svg.append('path').attr('d',d3.line()(pts)).attr('fill','none').attr('stroke',C.ink).attr('stroke-opacity',.1).attr('stroke-dasharray','2 4'); });
data.forEach((d,i)=>{ const a=i/N*6.283-Math.PI/2;
svg.append('line').attr('x1',cx).attr('y1',cy).attr('x2',cx+Math.cos(a)*maxR).attr('y2',cy+Math.sin(a)*maxR).attr('stroke',C.ink).attr('stroke-opacity',.1);
const lr=maxR+30, lx=cx+Math.cos(a)*lr, ly=cy+Math.sin(a)*lr;
svg.append('text').attr('x',lx).attr('y',ly).attr('text-anchor','middle').attr('dominant-baseline','middle').attr('font-family',SERIF).attr('font-style','italic').attr('font-size',15).attr('font-weight',600).attr('fill',C.ink).text(d.axis); });
function poly(s){ return data.map((d,i)=>{const a=i/N*6.283-Math.PI/2,r=d.val*maxR*s; return `${i?'L':'M'} ${cx+Math.cos(a)*r} ${cy+Math.sin(a)*r}`;}).join(' ')+' Z'; }
const path=svg.append('path').attr('d',poly(0)).attr('fill',C.red).attr('fill-opacity',.22).attr('stroke',C.red).attr('stroke-width',2.5);
const dots=data.map(()=>svg.append('circle').attr('r',4).attr('fill',C.gold).attr('cx',cx).attr('cy',cy));
onView('#sspRadar',()=>{
const o={s:0}; gsap.to(o,{s:1,duration:1.6,ease:'power3.out',onUpdate:()=>{ path.attr('d',poly(o.s));
data.forEach((d,i)=>{const a=i/N*6.283-Math.PI/2,r=d.val*maxR*o.s; dots[i].attr('cx',cx+Math.cos(a)*r).attr('cy',cy+Math.sin(a)*r);}); }});
});
document.getElementById('mobRadar').innerHTML = data.map(d=>
mcCard('Axe de fragilité', d.axis, 'Intensité estimée de la vulnérabilité sur cet axe systémique.', d.val>.8?C.red:(d.val>.7?C.redSoft:C.gold), Math.round(d.val*100))
).join('') + mcCard('Lecture d\'ensemble','Le risque est systémique','Aucun axe ne suffit isolément à provoquer la rupture ; c\'est leur superposition qui réduit la résilience.',C.ink,90);
animMobBlock('mobRadar');
})();
setTimeout(()=>{ if(window.ScrollTrigger) ScrollTrigger.refresh(); }, 800);
})();