feat: vignettes wireframe SVG des 31 layouts dans la galerie + favicon

This commit is contained in:
2026-07-16 19:31:14 +02:00
parent 2d06f95978
commit 10ca7ec7ad
3 changed files with 539 additions and 1 deletions
+6
View File
@@ -6,6 +6,7 @@ depuis layouts_v2.yaml. Relancer après tout ajout de layout.
Usage : python3 build_gallery.py → produit index.html Usage : python3 build_gallery.py → produit index.html
""" """
import yaml import yaml
import wireframes
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
@@ -35,6 +36,7 @@ def card(name, cfg):
hint = " ".join(cfg.get("agent_hint", "").split()) hint = " ".join(cfg.get("agent_hint", "").split())
champs = ", ".join(cfg.get("champs", [])) champs = ", ".join(cfg.get("champs", []))
requis = ", ".join(cfg.get("champs_requis", [])) requis = ", ".join(cfg.get("champs_requis", []))
thumb = wireframes.svg_for(name, mode)
mode_badge = { mode_badge = {
"light": ("Clair", "#f4f1ec", NAVY), "light": ("Clair", "#f4f1ec", NAVY),
"dark": ("Sombre", NAVY, "#ffffff"), "dark": ("Sombre", NAVY, "#ffffff"),
@@ -46,6 +48,7 @@ def card(name, cfg):
<span class="lcode">{lid}</span> <span class="lcode">{lid}</span>
<span class="lmode" style="background:{mode_badge[1]};color:{mode_badge[2]}">{mode_badge[0]}</span> <span class="lmode" style="background:{mode_badge[1]};color:{mode_badge[2]}">{mode_badge[0]}</span>
</div> </div>
<div class="wf-thumb">{thumb}</div>
<h3>{name}</h3> <h3>{name}</h3>
<p class="hint">{hint}</p> <p class="hint">{hint}</p>
<div class="fields"> <div class="fields">
@@ -82,6 +85,7 @@ html = f"""<!DOCTYPE html>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Sliding Design System v2 — Pernod Ricard</title> <title>Sliding Design System v2 — Pernod Ricard</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
<style> <style>
@@ -113,6 +117,8 @@ h1{{font-family:Cambria,serif;font-size:60px;font-weight:700;line-height:1.05;le
.lg{{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px}} .lg{{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px}}
.lc{{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)}} .lc{{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)}}
.lc:hover{{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)}} .lc:hover{{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)}}
.wf-thumb{{margin:0 0 14px;border:1px solid #ECE9E2;border-radius:8px;overflow:hidden;background:#fff}}
.wf-thumb svg{{display:block;width:100%;height:auto}}
.lc-head{{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}} .lc-head{{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}}
.lcode{{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace}} .lcode{{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace}}
.lmode{{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em}} .lmode{{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em}}
+35 -1
View File
@@ -4,6 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Sliding Design System v2 — Pernod Ricard</title> <title>Sliding Design System v2 — Pernod Ricard</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
<style> <style>
@@ -35,6 +36,8 @@ h1{font-family:Cambria,serif;font-size:60px;font-weight:700;line-height:1.05;let
.lg{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px} .lg{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px}
.lc{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)} .lc{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)}
.lc:hover{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)} .lc:hover{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)}
.wf-thumb{margin:0 0 14px;border:1px solid #ECE9E2;border-radius:8px;overflow:hidden;background:#fff}
.wf-thumb svg{display:block;width:100%;height:auto}
.lc-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px} .lc-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}
.lcode{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace} .lcode{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace}
.lmode{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em} .lmode{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em}
@@ -79,6 +82,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L01</span> <span class="lcode">L01</span>
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span> <span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><circle cx="300" cy="20" r="46" fill="#10204D" opacity="1.0"/><circle cx="288" cy="150" r="30" fill="#F4795B" opacity="0.9"/><circle cx="250" cy="150" r="14" fill="#8FA9D0" opacity="1.0"/><rect x="20" y="74" width="40" height="4" rx="1" fill="#F4795B" opacity="1.0"/><rect x="20" y="88" width="150" height="16" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="20" y="120" width="96" height="8" rx="2" fill="#8FA9D0" opacity="1.0"/></svg></div>
<h3>cover_split</h3> <h3>cover_split</h3>
<p class="hint">Slide de couverture. titre = titre de la présentation, sous_titre = tagline en une phrase.</p> <p class="hint">Slide de couverture. titre = titre de la présentation, sous_titre = tagline en une phrase.</p>
<div class="fields"> <div class="fields">
@@ -100,6 +104,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L05</span> <span class="lcode">L05</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="160" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="54" width="96" height="108" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="36" cy="74" r="9" fill="#061033" opacity="1.0"/><rect x="32" y="96" width="72" height="7" rx="3" fill="#46505A" opacity="1.0"/><rect x="32" y="112" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="124" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="136" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="112" y="54" width="96" height="108" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="128" cy="74" r="9" fill="#061033" opacity="1.0"/><rect x="124" y="96" width="72" height="7" rx="3" fill="#46505A" opacity="1.0"/><rect x="124" y="112" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="124" y="124" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="124" y="136" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="204" y="54" width="96" height="108" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="220" cy="74" r="9" fill="#061033" opacity="1.0"/><rect x="216" y="96" width="72" height="7" rx="3" fill="#46505A" opacity="1.0"/><rect x="216" y="112" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="216" y="124" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="216" y="136" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="54" width="96" height="4" rx="2" fill="#F4795B" opacity="1.0"/></svg></div>
<h3>executive_summary</h3> <h3>executive_summary</h3>
<p class="hint">Synthèse SCR. Titre = So What. 3 cartes pleine largeur : situation, complication, resolution (1-2 phrases chacune).</p> <p class="hint">Synthèse SCR. Titre = So What. 3 cartes pleine largeur : situation, complication, resolution (1-2 phrases chacune).</p>
<div class="fields"> <div class="fields">
@@ -121,6 +126,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L03</span> <span class="lcode">L03</span>
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span> <span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><circle cx="300" cy="150" r="40" fill="#10204D" opacity="1.0"/><rect x="20" y="78" width="20" height="20" rx="2" fill="#F4795B" opacity="1.0"/><rect x="20" y="104" width="130" height="14" rx="2" fill="#FFFFFF" opacity="1.0"/></svg></div>
<h3>section_divider</h3> <h3>section_divider</h3>
<p class="hint">Transition de section. titre = nom de la section. Le numéro est incrémenté automatiquement par le moteur.</p> <p class="hint">Transition de section. titre = nom de la section. Le numéro est incrémenté automatiquement par le moteur.</p>
<div class="fields"> <div class="fields">
@@ -134,6 +140,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L40</span> <span class="lcode">L40</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><circle cx="32" cy="52" r="10" fill="#061033" opacity="1.0"/><rect x="50" y="47" width="180" height="9" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="230" y="47" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/><circle cx="32" cy="84" r="10" fill="#F4795B" opacity="1.0"/><rect x="50" y="79" width="180" height="9" rx="3" fill="#061033" opacity="1.0"/><rect x="230" y="79" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/><circle cx="32" cy="116" r="10" fill="#061033" opacity="1.0"/><rect x="50" y="111" width="180" height="9" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="230" y="111" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/><circle cx="32" cy="148" r="10" fill="#061033" opacity="1.0"/><rect x="50" y="143" width="180" height="9" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="230" y="143" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/></svg></div>
<h3>agenda</h3> <h3>agenda</h3>
<p class="hint">Sommaire du deck : à placer en slide 2 pour toute présentation de plus de 15 minutes. sections = liste de {label, numero?, duree?, actif?}, 2 à 8 entrées. actif: true met la section en corail (utile pour les rappels d'agenda en cours de deck). duree (ex "10 min") s'affiche à droite en discret.</p> <p class="hint">Sommaire du deck : à placer en slide 2 pour toute présentation de plus de 15 minutes. sections = liste de {label, numero?, duree?, actif?}, 2 à 8 entrées. actif: true met la section en corail (utile pour les rappels d'agenda en cours de deck). duree (ex "10 min") s'affiche à droite en discret.</p>
<div class="fields"> <div class="fields">
@@ -155,6 +162,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L10</span> <span class="lcode">L10</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="90" y="66" width="140" height="40" rx="4" fill="#F4795B" opacity="1.0"/><rect x="110" y="116" width="100" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="134" y="132" width="52" height="5" rx="2" fill="#C9CDD3" opacity="0.6"/></svg></div>
<h3>big_stat</h3> <h3>big_stat</h3>
<p class="hint">Un chiffre héro plein écran. valeur = le chiffre (ex "78%"), description = ce qu'il signifie, source = référence.</p> <p class="hint">Un chiffre héro plein écran. valeur = le chiffre (ex "78%"), description = ce qu'il signifie, source = référence.</p>
<div class="fields"> <div class="fields">
@@ -168,6 +176,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L09</span> <span class="lcode">L09</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="56" width="96" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="32" y="74" width="50" height="22" rx="3" fill="#F4795B" opacity="1.0"/><rect x="32" y="104" width="70" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="32" y="118" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="112" y="56" width="96" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="124" y="74" width="50" height="22" rx="3" fill="#061033" opacity="1.0"/><rect x="124" y="104" width="70" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="124" y="118" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="204" y="56" width="96" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="216" y="74" width="50" height="22" rx="3" fill="#061033" opacity="1.0"/><rect x="216" y="104" width="70" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="216" y="118" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>kpi_grid</h3> <h3>kpi_grid</h3>
<p class="hint">2 à 6 cartes KPI. items = [{label, valeur, description}]. valeur en grand corail, label en en-tête, description en source.</p> <p class="hint">2 à 6 cartes KPI. items = [{label, valeur, description}]. valeur en grand corail, label en en-tête, description en source.</p>
<div class="fields"> <div class="fields">
@@ -181,6 +190,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L42</span> <span class="lcode">L42</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="40" y="110" width="32" height="40" rx="2" fill="#061033" opacity="1.0"/><rect x="92" y="80" width="32" height="70" rx="2" fill="#061033" opacity="1.0"/><rect x="144" y="95" width="32" height="55" rx="2" fill="#061033" opacity="1.0"/><rect x="196" y="60" width="32" height="90" rx="2" fill="#061033" opacity="1.0"/><rect x="248" y="88" width="32" height="62" rx="2" fill="#061033" opacity="1.0"/><rect x="30" y="150" width="270" height="2" rx="0" fill="#46505A" opacity="1.0"/></svg></div>
<h3>bar_chart</h3> <h3>bar_chart</h3>
<p class="hint">Comparaison de valeurs par catégories — graphique NATIF éditable. Max 8 catégories × 3 séries. series = liste de {label, values} ; values = nombres SANS guillemets, alignés sur categories. horizontal: true pour des barres (libellés longs). unite (ex M€) et source optionnels. Couleurs imposées : navy, coral, glacier.</p> <p class="hint">Comparaison de valeurs par catégories — graphique NATIF éditable. Max 8 catégories × 3 séries. series = liste de {label, values} ; values = nombres SANS guillemets, alignés sur categories. horizontal: true pour des barres (libellés longs). unite (ex M€) et source optionnels. Couleurs imposées : navy, coral, glacier.</p>
<div class="fields"> <div class="fields">
@@ -194,6 +204,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L43</span> <span class="lcode">L43</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="30" y="150" width="270" height="2" rx="0" fill="#46505A" opacity="1.0"/><polyline points="40,130 100,96 160,110 220,70 288,84" fill="none" stroke="#061033" stroke-width="2.5"/><circle cx="288" cy="84" r="5" fill="#F4795B" opacity="1.0"/></svg></div>
<h3>line_chart</h3> <h3>line_chart</h3>
<p class="hint">Évolution temporelle — graphique NATIF éditable. Max 12 points × 3 séries. points_x = libellés d'axe (mois, années...) ; series = {label, values}, nombres sans guillemets. Le dernier point de la première série est automatiquement mis en valeur (corail).</p> <p class="hint">Évolution temporelle — graphique NATIF éditable. Max 12 points × 3 séries. points_x = libellés d'axe (mois, années...) ; series = {label, values}, nombres sans guillemets. Le dernier point de la première série est automatiquement mis en valeur (corail).</p>
<div class="fields"> <div class="fields">
@@ -207,6 +218,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L44</span> <span class="lcode">L44</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="110" height="12" rx="2" fill="#061033" opacity="1.0"/><circle cx="100" cy="106" r="40" fill="none" stroke="#061033" stroke-width="18"/><path d="M100 66 A40 40 0 0 1 138 118" fill="none" stroke="#F4795B" stroke-width="18"/><circle cx="210" cy="84" r="6" fill="#061033" opacity="1.0"/><rect x="224" y="80" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="108" r="6" fill="#F4795B" opacity="1.0"/><rect x="224" y="104" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="132" r="6" fill="#8FA9D0" opacity="1.0"/><rect x="224" y="128" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>donut_split</h3> <h3>donut_split</h3>
<p class="hint">Répartition d'un tout : anneau à gauche + légende détaillée à droite. 2 à 6 segments = {label, valeur} (nombres sans guillemets). valeur_centrale (optionnelle) s'affiche au centre de l'anneau (ex : total « 120 M€ »). Couleurs = cycle PR imposé.</p> <p class="hint">Répartition d'un tout : anneau à gauche + légende détaillée à droite. 2 à 6 segments = {label, valeur} (nombres sans guillemets). valeur_centrale (optionnelle) s'affiche au centre de l'anneau (ex : total « 120 M€ »). Couleurs = cycle PR imposé.</p>
<div class="fields"> <div class="fields">
@@ -220,6 +232,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L45</span> <span class="lcode">L45</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="30" y="150" width="270" height="2" rx="0" fill="#46505A" opacity="1.0"/><rect x="40" y="80" width="34" height="70" rx="2" fill="#061033" opacity="1.0"/><rect x="94" y="80" width="34" height="34" rx="2" fill="#F4795B" opacity="1.0"/><rect x="148" y="60" width="34" height="40" rx="2" fill="#F4795B" opacity="1.0"/><rect x="202" y="44" width="34" height="30" rx="2" fill="#F4795B" opacity="1.0"/><rect x="256" y="60" width="34" height="90" rx="2" fill="#061033" opacity="1.0"/></svg></div>
<h3>waterfall</h3> <h3>waterfall</h3>
<p class="hint">Pont de valeur (waterfall) : expliquer un écart entre deux montants par des variations successives. depart et arrivee = {label, valeur} ; marches = liste de {label, delta} SIGNÉ (positif ou négatif, max 8). Le moteur calcule les cumuls — ne jamais fournir de cumul. Idéal pour : évolution de budget, pont d'effectifs, décomposition d'un résultat.</p> <p class="hint">Pont de valeur (waterfall) : expliquer un écart entre deux montants par des variations successives. depart et arrivee = {label, valeur} ; marches = liste de {label, delta} SIGNÉ (positif ou négatif, max 8). Le moteur calcule les cumuls — ne jamais fournir de cumul. Idéal pour : évolution de budget, pont d'effectifs, décomposition d'un résultat.</p>
<div class="fields"> <div class="fields">
@@ -241,6 +254,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L07</span> <span class="lcode">L07</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="170" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="44" width="132" height="120" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="20" y="44" width="132" height="26" rx="6" fill="#061033" opacity="1.0"/><rect x="20" y="58" width="132" height="12" rx="0" fill="#061033" opacity="1.0"/><rect x="32" y="52" width="70" height="10" rx="3" fill="#FFFFFF" opacity="1.0"/><rect x="32" y="84" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="99" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="114" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="129" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="168" y="44" width="132" height="120" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="168" y="44" width="132" height="26" rx="6" fill="#F4795B" opacity="1.0"/><rect x="168" y="58" width="132" height="12" rx="0" fill="#F4795B" opacity="1.0"/><rect x="180" y="52" width="70" height="10" rx="3" fill="#FFFFFF" opacity="1.0"/><rect x="180" y="84" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="99" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="114" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="129" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>two_cols_text</h3> <h3>two_cols_text</h3>
<p class="hint">Deux colonnes en cartes avec en-tête coloré. left/right = {titre, bullets[]}. Gauche = navy, droite = corail.</p> <p class="hint">Deux colonnes en cartes avec en-tête coloré. left/right = {titre, bullets[]}. Gauche = navy, droite = corail.</p>
<div class="fields"> <div class="fields">
@@ -254,6 +268,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L34</span> <span class="lcode">L34</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="48" width="280" height="20" rx="4" fill="#061033" opacity="1.0"/><rect x="24" y="52" width="84" height="12" rx="2" fill="#FFFFFF" opacity="0.5"/><rect x="116" y="52" width="84" height="12" rx="2" fill="#FFFFFF" opacity="0.5"/><rect x="208" y="52" width="84" height="12" rx="2" fill="#FFFFFF" opacity="0.5"/><rect x="20" y="72" width="280" height="18" rx="2" fill="#FFFFFF" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="77" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="77" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="77" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="94" width="280" height="18" rx="2" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="99" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="99" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="99" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="116" width="280" height="18" rx="2" fill="#FFFFFF" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="121" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="121" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="121" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="138" width="280" height="18" rx="2" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="143" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="143" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="143" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>comparison_table</h3> <h3>comparison_table</h3>
<p class="hint">Tableau structuré multi-critères. headers = liste de colonnes (1ère = critères). rows = [{label, values: []}] ou listes plates. Max 5 colonnes, 8 lignes.</p> <p class="hint">Tableau structuré multi-critères. headers = liste de colonnes (1ère = critères). rows = [{label, values: []}] ou listes plates. Max 5 colonnes, 8 lignes.</p>
<div class="fields"> <div class="fields">
@@ -267,6 +282,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L46</span> <span class="lcode">L46</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="60" y="54" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="106" y="54" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="152" y="54" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="198" y="54" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="244" y="54" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="58" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="80" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="106" y="80" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="152" y="80" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="198" y="80" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="244" y="80" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="20" y="84" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="106" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="106" y="106" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="152" y="106" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="198" y="106" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="244" y="106" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="20" y="110" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="132" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="106" y="132" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="152" y="132" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="198" y="132" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="244" y="132" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="20" y="136" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>heatmap_table</h3> <h3>heatmap_table</h3>
<p class="hint">Tableau à intensité : évaluer plusieurs items sur plusieurs critères. headers = colonnes (max 6) ; rows = {label, scores} avec score ENTIER de 0 (faible) à 4 (fort), max 8 lignes. Le moteur traduit chaque score en teinte de navy — aucune autre donnée. Idéal pour : maturité, couverture fonctionnelle, cartographie de risques.</p> <p class="hint">Tableau à intensité : évaluer plusieurs items sur plusieurs critères. headers = colonnes (max 6) ; rows = {label, scores} avec score ENTIER de 0 (faible) à 4 (fort), max 8 lignes. Le moteur traduit chaque score en teinte de navy — aucune autre donnée. Idéal pour : maturité, couverture fonctionnelle, cartographie de risques.</p>
<div class="fields"> <div class="fields">
@@ -288,6 +304,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L08</span> <span class="lcode">L08</span>
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span> <span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="40" y="70" width="240" height="14" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="70" y="92" width="180" height="14" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="130" y="120" width="60" height="6" rx="2" fill="#F4795B" opacity="1.0"/></svg></div>
<h3>key_message</h3> <h3>key_message</h3>
<p class="hint">Message clé en citation plein écran. message = la phrase forte, detail = sous-texte optionnel.</p> <p class="hint">Message clé en citation plein écran. message = la phrase forte, detail = sous-texte optionnel.</p>
<div class="fields"> <div class="fields">
@@ -309,6 +326,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L17</span> <span class="lcode">L17</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="130" height="12" rx="2" fill="#061033" opacity="1.0"/><circle cx="144" cy="108" r="22" fill="#061033" opacity="1.0"/><circle cx="93" cy="137" r="22" fill="#46505A" opacity="1.0"/><circle cx="93" cy="79" r="22" fill="#8FA9D0" opacity="1.0"/><circle cx="110" cy="108" r="14" fill="#F4795B" opacity="1.0"/><circle cx="210" cy="70" r="6" fill="#061033" opacity="1.0"/><rect x="224" y="66" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="100" r="6" fill="#46505A" opacity="1.0"/><rect x="224" y="96" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="130" r="6" fill="#8FA9D0" opacity="1.0"/><rect x="224" y="126" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>circular_diagram</h3> <h3>circular_diagram</h3>
<p class="hint">3 à 6 valeurs en cercles + légende à droite. segments = [{label, description, couleur?}].</p> <p class="hint">3 à 6 valeurs en cercles + légende à droite. segments = [{label, description, couleur?}].</p>
<div class="fields"> <div class="fields">
@@ -322,6 +340,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L41</span> <span class="lcode">L41</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="110" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="115" y="132" width="90" height="20" rx="2" fill="#F4795B" opacity="1.0"/><rect x="85" y="108" width="150" height="20" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="55" y="84" width="210" height="20" rx="2" fill="#46505A" opacity="1.0"/><rect x="25" y="60" width="270" height="20" rx="2" fill="#061033" opacity="1.0"/></svg></div>
<h3>pyramid</h3> <h3>pyramid</h3>
<p class="hint">Argumentation pyramidale : la conclusion au sommet, les fondations à la base. niveaux = liste de {label, description?}, EXACTEMENT 3 ou 4 niveaux, du sommet vers la base. Largeurs d'étages fixes gérées par le moteur. Idéal pour : message clé et ses appuis, hiérarchie stratégie/tactiques/moyens.</p> <p class="hint">Argumentation pyramidale : la conclusion au sommet, les fondations à la base. niveaux = liste de {label, description?}, EXACTEMENT 3 ou 4 niveaux, du sommet vers la base. Largeurs d'étages fixes gérées par le moteur. Idéal pour : message clé et ses appuis, hiérarchie stratégie/tactiques/moyens.</p>
<div class="fields"> <div class="fields">
@@ -343,6 +362,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L06</span> <span class="lcode">L06</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="66" width="8" height="8" rx="1" fill="#F4795B" opacity="1.0"/><rect x="38" y="66" width="250" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="94" width="8" height="8" rx="1" fill="#F4795B" opacity="1.0"/><rect x="38" y="94" width="250" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="122" width="8" height="8" rx="1" fill="#F4795B" opacity="1.0"/><rect x="38" y="122" width="250" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>default_bullets</h3> <h3>default_bullets</h3>
<p class="hint">Liste de points clés. Si texte au format "Mot : explication", le moteur met le mot en gras navy. Max 5 bullets. bullets = [{niveau, texte}].</p> <p class="hint">Liste de points clés. Si texte au format "Mot : explication", le moteur met le mot en gras navy. Max 5 bullets. bullets = [{niveau, texte}].</p>
<div class="fields"> <div class="fields">
@@ -364,6 +384,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L19</span> <span class="lcode">L19</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="52" width="280" height="28" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="38" cy="66" r="11" fill="#061033" opacity="1.0"/><rect x="60" y="62" width="200" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="86" width="280" height="28" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="38" cy="100" r="11" fill="#061033" opacity="1.0"/><rect x="60" y="96" width="200" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="120" width="280" height="28" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="38" cy="134" r="11" fill="#061033" opacity="1.0"/><rect x="60" y="130" width="200" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>numbered_steps</h3> <h3>numbered_steps</h3>
<p class="hint">Étapes en cartes pleine largeur avec badge rond numéroté. steps = [{numero, titre, description}].</p> <p class="hint">Étapes en cartes pleine largeur avec badge rond numéroté. steps = [{numero, titre, description}].</p>
<div class="fields"> <div class="fields">
@@ -377,6 +398,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L36</span> <span class="lcode">L36</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><polygon points="20,80 90,80 106,104 90,128 20,128 36,104" fill="#061033"/><polygon points="120,80 190,80 206,104 190,128 120,128 136,104" fill="#F4795B"/><polygon points="220,80 290,80 306,104 290,128 220,128 236,104" fill="#061033"/></svg></div>
<h3>process_arrow</h3> <h3>process_arrow</h3>
<p class="hint">Flux horizontal de 3 à 6 étapes. steps = [{titre, description}]. Badges numérotés corail, couleurs cycle alternées. Max 6 étapes.</p> <p class="hint">Flux horizontal de 3 à 6 étapes. steps = [{titre, description}]. Badges numérotés corail, couleurs cycle alternées. Max 6 étapes.</p>
<div class="fields"> <div class="fields">
@@ -390,6 +412,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L47</span> <span class="lcode">L47</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="110" height="12" rx="2" fill="#061033" opacity="1.0"/><polygon points="40.0,58 280.0,58 266.0,80 54.0,80" fill="#061033"/><polygon points="70.0,84 250.0,84 236.0,106 84.0,106" fill="#10204D"/><polygon points="100.0,110 220.0,110 206.0,132 114.0,132" fill="#8FA9D0"/><polygon points="125.0,136 195.0,136 181.0,158 139.0,158" fill="#F4795B"/></svg></div>
<h3>funnel</h3> <h3>funnel</h3>
<p class="hint">Entonnoir de conversion : volumes décroissants d'étape en étape. etapes = {label, valeur, description?} du haut vers le bas, 3 à 5 étages. Largeurs proportionnelles aux valeurs (plancher de lisibilité), dernier étage corail. Idéal pour : pipeline commercial, adoption, qualification progressive.</p> <p class="hint">Entonnoir de conversion : volumes décroissants d'étape en étape. etapes = {label, valeur, description?} du haut vers le bas, 3 à 5 étages. Largeurs proportionnelles aux valeurs (plancher de lisibilité), dernier étage corail. Idéal pour : pipeline commercial, adoption, qualification progressive.</p>
<div class="fields"> <div class="fields">
@@ -411,6 +434,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L23</span> <span class="lcode">L23</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="74" width="96" height="44" rx="6" fill="#061033" opacity="1.0"/><rect x="116" y="94" width="16" height="4" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="40" y="126" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="112" y="74" width="96" height="44" rx="6" fill="#46505A" opacity="1.0"/><rect x="208" y="94" width="16" height="4" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="132" y="126" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="204" y="74" width="96" height="44" rx="6" fill="#8FA9D0" opacity="1.0"/><rect x="224" y="126" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>phases_timeline</h3> <h3>phases_timeline</h3>
<p class="hint">Phases reliées par une ligne pointillée. phases = [{label, periode}]. Couleurs du cycle theme.</p> <p class="hint">Phases reliées par une ligne pointillée. phases = [{label, periode}]. Couleurs du cycle theme.</p>
<div class="fields"> <div class="fields">
@@ -424,6 +448,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L32</span> <span class="lcode">L32</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="56" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="130" y="56" width="120" height="12" rx="3" fill="#061033" opacity="1.0"/><rect x="20" y="82" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="82" width="90" height="12" rx="3" fill="#46505A" opacity="1.0"/><rect x="20" y="108" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="240" y="108" width="100" height="12" rx="3" fill="#061033" opacity="1.0"/><rect x="20" y="134" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="160" y="134" width="130" height="12" rx="3" fill="#8FA9D0" opacity="1.0"/></svg></div>
<h3>gantt_timeline</h3> <h3>gantt_timeline</h3>
<p class="hint">Gantt par workstreams. periods = liste de labels (ex ["Juin","Juil"]). workstreams = [{label, tasks: [{label, start, end}]}]. start/end = index dans periods (0-based). Max 3 workstreams, 4 tâches chacun.</p> <p class="hint">Gantt par workstreams. periods = liste de labels (ex ["Juin","Juil"]). workstreams = [{label, tasks: [{label, start, end}]}]. start/end = index dans periods (0-based). Max 3 workstreams, 4 tâches chacun.</p>
<div class="fields"> <div class="fields">
@@ -445,6 +470,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L28</span> <span class="lcode">L28</span>
<span class="lmode" style="background:#8FA9D0;color:#061033">Panel</span> <span class="lmode" style="background:#8FA9D0;color:#061033">Panel</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="48" width="190" height="116" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="20" y="48" width="190" height="6" rx="3" fill="#F4795B" opacity="1.0"/><circle cx="40" cy="72" r="10" fill="#061033" opacity="1.0"/><rect x="60" y="66" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="82" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="98" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="114" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="228" y="48" width="72" height="116" rx="6" fill="#061033" opacity="1.0"/><rect x="240" y="70" width="48" height="8" rx="3" fill="#8FA9D0" opacity="1.0"/><rect x="240" y="92" width="48" height="7" rx="3" fill="#33436A" opacity="1.0"/><rect x="240" y="105" width="48" height="7" rx="3" fill="#33436A" opacity="1.0"/><rect x="240" y="118" width="48" height="7" rx="3" fill="#33436A" opacity="1.0"/></svg></div>
<h3>recommendation_card</h3> <h3>recommendation_card</h3>
<p class="hint">Carte de recommandation. Sidebar = numero + titre + cta. Corps = headline + bullets.</p> <p class="hint">Carte de recommandation. Sidebar = numero + titre + cta. Corps = headline + bullets.</p>
<div class="fields"> <div class="fields">
@@ -466,6 +492,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L30</span> <span class="lcode">L30</span>
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span> <span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><circle cx="300" cy="24" r="40" fill="#F4795B" opacity="0.9"/><circle cx="30" cy="150" r="46" fill="#10204D" opacity="1.0"/><rect x="96" y="74" width="128" height="14" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="120" y="100" width="80" height="8" rx="2" fill="#8FA9D0" opacity="1.0"/></svg></div>
<h3>end_slide</h3> <h3>end_slide</h3>
<p class="hint">Slide de fin. message = phrase de conclusion.</p> <p class="hint">Slide de fin. message = phrase de conclusion.</p>
<div class="fields"> <div class="fields">
@@ -487,6 +514,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L31</span> <span class="lcode">L31</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="50" width="120" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="20" y="50" width="120" height="6" rx="3" fill="#061033" opacity="1.0"/><rect x="32" y="70" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="86" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="102" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="118" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="176" y="50" width="120" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="176" y="50" width="120" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="188" y="70" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="188" y="86" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="188" y="102" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="188" y="118" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="160" cy="100" r="10" fill="#F4795B" opacity="1.0"/></svg></div>
<h3>from_to_pairs</h3> <h3>from_to_pairs</h3>
<p class="hint">Transformation avant/après en paires alignées. pairs = [{from, to}]. label_from/label_to = en-têtes colonnes. Max 5 paires. Idéal pour tangibiliser un changement.</p> <p class="hint">Transformation avant/après en paires alignées. pairs = [{from, to}]. label_from/label_to = en-têtes colonnes. Max 5 paires. Idéal pour tangibiliser un changement.</p>
<div class="fields"> <div class="fields">
@@ -508,6 +536,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L33</span> <span class="lcode">L33</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="130" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="100" width="280" height="3" rx="0" fill="#061033" opacity="1.0"/><circle cx="40" cy="101" r="7" fill="#061033" opacity="1.0"/><rect x="20" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/><circle cx="120" cy="101" r="7" fill="#F4795B" opacity="1.0"/><rect x="100" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/><circle cx="200" cy="101" r="7" fill="#061033" opacity="1.0"/><rect x="180" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/><circle cx="280" cy="101" r="7" fill="#061033" opacity="1.0"/><rect x="260" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>yearly_timeline</h3> <h3>yearly_timeline</h3>
<p class="hint">Frise chronologique horizontale. milestones = [{annee, label, actif?}]. actif = true pour le jalon courant (corail). Labels alternent haut/bas. Max 6 jalons.</p> <p class="hint">Frise chronologique horizontale. milestones = [{annee, label, actif?}]. actif = true pour le jalon courant (corail). Labels alternent haut/bas. Max 6 jalons.</p>
<div class="fields"> <div class="fields">
@@ -529,6 +558,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L35</span> <span class="lcode">L35</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="48" width="280" height="18" rx="4" fill="#061033" opacity="1.0"/><rect x="20" y="70" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="78" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="78" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="78" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="78" r="7" fill="#8FA9D0" opacity="0.85"/><rect x="20" y="92" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="100" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="100" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="100" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="100" r="7" fill="#8FA9D0" opacity="0.85"/><rect x="20" y="114" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="122" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="122" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="122" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="122" r="7" fill="#8FA9D0" opacity="0.85"/><rect x="20" y="136" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="144" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="144" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="144" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="144" r="7" fill="#8FA9D0" opacity="0.85"/></svg></div>
<h3>raci_table</h3> <h3>raci_table</h3>
<p class="hint">Matrice RACI. roles = liste de rôles. tasks = [{label, raci: [R/A/C/I]}]. R=Responsable(corail), A=Autorité(navy), C=Consulté(slate), I=Informé(muted). Max 4 rôles, 8 tâches.</p> <p class="hint">Matrice RACI. roles = liste de rôles. tasks = [{label, raci: [R/A/C/I]}]. R=Responsable(corail), A=Autorité(navy), C=Consulté(slate), I=Informé(muted). Max 4 rôles, 8 tâches.</p>
<div class="fields"> <div class="fields">
@@ -550,6 +580,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L37</span> <span class="lcode">L37</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="130" y="52" width="60" height="26" rx="4" fill="#061033" opacity="1.0"/><rect x="60" y="120" width="56" height="26" rx="4" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><line x1="160" y1="78" x2="88" y2="120" stroke="#061033" stroke-width="1.5"/><rect x="140" y="120" width="56" height="26" rx="4" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><line x1="160" y1="78" x2="168" y2="120" stroke="#061033" stroke-width="1.5"/><rect x="220" y="120" width="56" height="26" rx="4" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><line x1="160" y1="78" x2="248" y2="120" stroke="#061033" stroke-width="1.5"/></svg></div>
<h3>org_chart</h3> <h3>org_chart</h3>
<p class="hint">Organigramme hiérarchique max 3 niveaux. root = {label, children: [{label, children?: [{label}]}]}. Max 4 enfants directs, 3 petits-enfants par enfant.</p> <p class="hint">Organigramme hiérarchique max 3 niveaux. root = {label, children: [{label, children?: [{label}]}]}. Max 4 enfants directs, 3 petits-enfants par enfant.</p>
<div class="fields"> <div class="fields">
@@ -571,6 +602,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L38</span> <span class="lcode">L38</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><line x1="160" y1="46" x2="160" y2="170" stroke="#46505A" stroke-width="1.5"/><line x1="24" y1="108" x2="296" y2="108" stroke="#46505A" stroke-width="1.5"/><circle cx="92" cy="78" r="16" fill="#061033" opacity="0.9"/><circle cx="228" cy="78" r="16" fill="#F4795B" opacity="0.9"/><circle cx="92" cy="140" r="16" fill="#46505A" opacity="0.9"/><circle cx="228" cy="140" r="16" fill="#8FA9D0" opacity="0.9"/></svg></div>
<h3>matrix_2x2</h3> <h3>matrix_2x2</h3>
<p class="hint">Matrice effort/impact. axis_x/axis_y = {label, low, high}. quadrants = {top_left, top_right, bottom_left, bottom_right}. items = [{label, x, y}] avec x/y de 0 à 100. Max 8 items.</p> <p class="hint">Matrice effort/impact. axis_x/axis_y = {label, low, high}. quadrants = {top_left, top_right, bottom_left, bottom_right}. items = [{label, x, y}] avec x/y de 0 à 100. Max 8 items.</p>
<div class="fields"> <div class="fields">
@@ -592,6 +624,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L50</span> <span class="lcode">L50</span>
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span> <span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="44" width="130" height="120" rx="4" fill="#8FA9D0" opacity="0.5"/><line x1="20" y1="164" x2="150" y2="44" stroke="#8FA9D0" stroke-width="1.5"/><line x1="20" y1="44" x2="150" y2="164" stroke="#8FA9D0" stroke-width="1.5"/><rect x="168" y="44" width="130" height="14" rx="2" fill="#061033" opacity="1.0"/><circle cx="176" cy="78" r="3" fill="#F4795B" opacity="1.0"/><rect x="184" y="74" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="184" y="91" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="184" y="108" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="184" y="125" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
<h3>image_split</h3> <h3>image_split</h3>
<p class="hint">Image d'appui sur 40 % de la slide (side: left par défaut, right possible) + titre et points clés (max 4 bullets). À utiliser quand une image du dossier assets/ du projet illustre le propos ; image = nom de fichier exact tel que listé par /lire. legende (optionnelle) s'affiche sur un bandeau navy sous l'image.</p> <p class="hint">Image d'appui sur 40 % de la slide (side: left par défaut, right possible) + titre et points clés (max 4 bullets). À utiliser quand une image du dossier assets/ du projet illustre le propos ; image = nom de fichier exact tel que listé par /lire. legende (optionnelle) s'affiche sur un bandeau navy sous l'image.</p>
<div class="fields"> <div class="fields">
@@ -605,6 +638,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
<span class="lcode">L51</span> <span class="lcode">L51</span>
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span> <span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
</div> </div>
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="0" y="0" width="320" height="180" rx="4" fill="#8FA9D0" opacity="0.5"/><line x1="0" y1="180" x2="320" y2="0" stroke="#8FA9D0" stroke-width="1.5"/><line x1="0" y1="0" x2="320" y2="180" stroke="#8FA9D0" stroke-width="1.5"/><rect x="0" y="120" width="320" height="60" rx="0" fill="#061033" opacity="0.82"/><rect x="20" y="134" width="150" height="12" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="20" y="152" width="90" height="7" rx="2" fill="#8FA9D0" opacity="1.0"/></svg></div>
<h3>image_full</h3> <h3>image_full</h3>
<p class="hint">Ouverture de chapitre visuelle : image plein cadre + voile navy + titre display blanc. Alternative à section_divider quand un asset du projet s'y prête. image = nom de fichier exact de assets/.</p> <p class="hint">Ouverture de chapitre visuelle : image plein cadre + voile navy + titre display blanc. Alternative à section_divider quand un asset du projet s'y prête. image = nom de fichier exact de assets/.</p>
<div class="fields"> <div class="fields">
@@ -614,7 +648,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
</div></div> </div></div>
</section> </section>
<footer> <footer>
Généré automatiquement depuis layouts_v2.yaml · 13/07/2026 · 31 layouts Généré automatiquement depuis layouts_v2.yaml · 16/07/2026 · 31 layouts
</footer> </footer>
</body> </body>
</html> </html>
+498
View File
@@ -0,0 +1,498 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
wireframes.py Vignettes SVG des layouts (Sliding Design System)
=================================================================
Schémas grosse maille, aux couleurs de la charte, FIDÈLES à la
structure de chaque _render_* du moteur (cartes, bandeaux navy/coral,
cercles, colonnes, barres, badges). Pur Python/SVG : aucune
dépendance, aucun LibreOffice, régénérable en une fraction de seconde.
API : svg_for(layout_name, mode) -> str (SVG inline, viewBox 320x180).
Un layout inconnu retombe sur un gabarit générique titre + lignes.
Consommé par build_gallery.py (vignette dans chaque fiche).
"""
# ── Charte ───────────────────────────────────────────────────────────────────
NAVY = "#061033"
NAVY2 = "#10204D"
CORAL = "#F4795B"
GLACIER = "#8FA9D0"
SLATE = "#46505A"
CARD = "#F4F1EC"
BODY = "#2B3440"
MUTED = "#C9CDD3"
WHITE = "#FFFFFF"
W, H = 320, 180
MX = 20 # marge horizontale de la zone utile
# ── Primitives ───────────────────────────────────────────────────────────────
def _r(x, y, w, h, fill, rad=0, op=1.0, stroke=None):
s = f' stroke="{stroke}" stroke-width="1"' if stroke else ""
return (f'<rect x="{x:.0f}" y="{y:.0f}" width="{w:.0f}" '
f'height="{h:.0f}" rx="{rad}" fill="{fill}" '
f'opacity="{op}"{s}/>')
def _c(cx, cy, rad, fill, op=1.0):
return (f'<circle cx="{cx:.0f}" cy="{cy:.0f}" r="{rad:.0f}" '
f'fill="{fill}" opacity="{op}"/>')
def _title_bar(y=16, w=150, c=NAVY):
return _r(MX, y, w, 12, c, rad=2)
def _lines(x, y, w, n, gap=13, c=MUTED, first=None, fw=None):
out = []
for i in range(n):
cc = first if (first and i == 0) else c
ww = (fw or w) if (fw and i == 0) else w
out.append(_r(x, y + i * gap, ww, 7, cc, rad=3))
return "".join(out)
def _img_zone(x, y, w, h, mode="light"):
"""Zone image : aplat glacier clair + diagonale (convention wireframe)."""
fill = GLACIER
return (_r(x, y, w, h, fill, rad=4, op=0.5)
+ f'<line x1="{x:.0f}" y1="{y+h:.0f}" x2="{x+w:.0f}" '
f'y2="{y:.0f}" stroke="{GLACIER}" stroke-width="1.5"/>'
+ f'<line x1="{x:.0f}" y1="{y:.0f}" x2="{x+w:.0f}" '
f'y2="{y+h:.0f}" stroke="{GLACIER}" stroke-width="1.5"/>')
def _frame(mode, body):
bg = NAVY if mode == "dark" else ("#EEF1F6" if mode == "panel"
else WHITE)
return (f'<svg xmlns="http://www.w3.org/2000/svg" '
f'viewBox="0 0 {W} {H}" class="wf">'
f'{_r(0, 0, W, H, bg, rad=8)}'
f'<rect x="0.5" y="0.5" width="{W-1}" height="{H-1}" rx="8" '
f'fill="none" stroke="#E3E0D9"/>{body}</svg>')
def _title_light(mode):
return WHITE if mode == "dark" else NAVY
# ── Archétypes (fidèles aux _render_*) ───────────────────────────────────────
def _wf_cover(mode):
# cover_split : fond navy, cercles décoratifs coin, filet coral, titre
b = [_c(300, 20, 46, NAVY2), _c(288, 150, 30, CORAL, 0.9),
_c(250, 150, 14, GLACIER),
_r(MX, 74, 40, 4, CORAL, rad=1),
_r(MX, 88, 150, 16, WHITE, rad=2),
_r(MX, 120, 96, 8, GLACIER, rad=2)]
return _frame("dark", "".join(b))
def _wf_section(mode):
# section_divider : navy, gros numéro fantôme, titre
b = [_c(300, 150, 40, NAVY2),
_r(MX, 78, 20, 20, CORAL, rad=2),
_r(MX, 104, 130, 14, WHITE, rad=2)]
return _frame("dark", "".join(b))
def _wf_end(mode):
b = [_c(300, 24, 40, CORAL, 0.9), _c(30, 150, 46, NAVY2),
_r(96, 74, 128, 14, WHITE, rad=2),
_r(120, 100, 80, 8, GLACIER, rad=2)]
return _frame("dark", "".join(b))
def _wf_big_stat(mode):
tl = _title_light(mode)
# titre en haut ; chiffre coral CENTRÉ (H et V) ; desc + source
# centrées dessous — cf _render_big_stat (align CENTER, _cy).
b = [_title_bar(w=120, c=tl),
_r(90, 66, 140, 40, CORAL, rad=4), # chiffre héros, centré
_r(110, 116, 100, 8, MUTED, rad=3), # description centrée
_r(134, 132, 52, 5, MUTED, rad=2, op=0.6)] # source centrée
return _frame(mode, "".join(b))
def _wf_key_message(mode):
# key_message : fond navy, grande phrase centrée
b = [_r(40, 70, 240, 14, WHITE, rad=2),
_r(70, 92, 180, 14, GLACIER, rad=2),
_r(130, 120, 60, 6, CORAL, rad=2)]
return _frame("dark", "".join(b))
def _wf_bullets(mode):
tl = _title_light(mode)
# titre en haut ; puces CARRÉES coral + texte, bloc centré vertical.
# Pas de barre latérale (cf _render_default_bullets).
b = [_title_bar(c=tl)]
for y in (66, 94, 122):
b.append(_r(MX, y, 8, 8, CORAL, rad=1)) # square_mark coral
b.append(_r(MX + 18, y, 250, 8, MUTED, rad=3))
return _frame(mode, "".join(b))
def _wf_two_cols(mode):
b = [_title_bar(w=170)]
cw, xs, acc = 132, (MX, 168), (NAVY, CORAL)
for i in range(2):
x = xs[i]
b.append(_r(x, 44, cw, 120, CARD, rad=6))
b.append(_r(x, 44, cw, 26, acc[i], rad=6))
b.append(_r(x, 58, cw, 12, acc[i]))
b.append(_r(x + 12, 52, 70, 10, WHITE, rad=3))
b.append(_lines(x + 12, 84, 100, 4, gap=15))
return _frame("light", "".join(b))
def _wf_from_to(mode):
b = [_title_bar(w=150)]
for i, (x, c) in enumerate(((MX, NAVY), (176, SLATE))):
b.append(_r(x, 50, 120, 100, CARD, rad=6))
b.append(_r(x, 50, 120, 6, c, rad=3))
b.append(_lines(x + 12, 70, 90, 4, gap=16))
b.append(_c(160, 100, 10, CORAL)) # flèche/pivot central
return _frame("light", "".join(b))
def _wf_exec_summary(mode):
b = [_title_bar(w=160)]
for i, x in enumerate((MX, 112, 204)):
b.append(_r(x, 54, 96, 108, CARD, rad=6))
b.append(_c(x + 16, 74, 9, NAVY))
b.append(_r(x + 12, 96, 72, 7, SLATE, rad=3))
b.append(_lines(x + 12, 112, 72, 3, gap=12))
b.append(_r(MX, 54, 96, 4, CORAL, rad=2)) # 1re carte accentuée
return _frame("light", "".join(b))
def _wf_kpi_grid(mode):
b = [_title_bar(w=120)]
xs = (MX, 112, 204)
for i, x in enumerate(xs):
b.append(_r(x, 56, 96, 100, CARD, rad=6))
b.append(_r(x + 12, 74, 50, 22, CORAL if i == 0 else NAVY,
rad=3))
b.append(_r(x + 12, 104, 70, 6, SLATE, rad=3))
b.append(_r(x + 12, 118, 56, 6, MUTED, rad=3))
return _frame("light", "".join(b))
def _wf_numbered_steps(mode):
b = [_title_bar(w=150)]
for i, y in enumerate((52, 86, 120)):
b.append(_r(MX, y, 280, 28, CARD, rad=6))
b.append(_c(MX + 18, y + 14, 11, NAVY))
b.append(_r(MX + 40, y + 10, 200, 8, MUTED, rad=3))
return _frame("light", "".join(b))
def _wf_agenda(mode):
b = [_title_bar(w=140)]
for i, y in enumerate((52, 84, 116, 148)):
active = (i == 1)
b.append(_c(MX + 12, y, 10, CORAL if active else NAVY))
b.append(_r(MX + 30, y - 5, 180, 9,
NAVY if active else MUTED, rad=3))
b.append(_r(230, y - 5, 60, 9, MUTED, rad=3, op=0.6))
return _frame("light", "".join(b))
def _wf_circular(mode):
tl = _title_light(mode)
b = [_title_bar(w=130, c=tl)]
cx, cy = 110, 108
for ang, c in ((0, NAVY), (120, SLATE), (240, GLACIER)):
import math
x = cx + 34 * math.cos(math.radians(ang))
y = cy + 34 * math.sin(math.radians(ang))
b.append(_c(x, y, 22, c))
b.append(_c(cx, cy, 14, CORAL))
# légende
for i, y in enumerate((70, 100, 130)):
b.append(_c(210, y, 6, (NAVY, SLATE, GLACIER)[i]))
b.append(_r(224, y - 4, 76, 7, MUTED, rad=3))
return _frame(mode, "".join(b))
def _wf_recommendation(mode):
b = [_title_bar(w=150),
_r(MX, 48, 190, 116, CARD, rad=6),
_r(MX, 48, 190, 6, CORAL, rad=3),
_c(MX + 20, 72, 10, NAVY),
_lines(MX + 40, 66, 130, 4, gap=16),
_r(228, 48, 72, 116, NAVY, rad=6), # panneau latéral navy
_r(240, 70, 48, 8, GLACIER, rad=3),
_lines(240, 92, 48, 3, gap=13, c="#33436A")]
return _frame("light", "".join(b))
def _wf_phases_timeline(mode):
b = [_title_bar(w=150)]
for i, x in enumerate((MX, 112, 204)):
c = (NAVY, SLATE, GLACIER)[i]
b.append(_r(x, 74, 96, 44, c, rad=6))
if i < 2:
b.append(_r(x + 96, 94, 16, 4, MUTED, rad=2))
b.append(_r(x + 20, 126, 56, 6, MUTED, rad=3))
return _frame("light", "".join(b))
def _wf_gantt(mode):
b = [_title_bar(w=140)]
rows = ((40, 120, NAVY), (90, 90, SLATE), (150, 100, NAVY),
(70, 130, GLACIER))
for i, (x, w, c) in enumerate(rows):
y = 56 + i * 26
b.append(_r(MX, y, 60, 10, MUTED, rad=2)) # label
b.append(_r(90 + x, y, w, 12, c, rad=3)) # barre
return _frame("light", "".join(b))
def _wf_yearly(mode):
b = [_title_bar(w=130),
_r(MX, 100, 280, 3, NAVY)] # ligne de temps
for i, x in enumerate((40, 120, 200, 280)):
b.append(_c(x, 101, 7, CORAL if i == 1 else NAVY))
b.append(_r(x - 20, 116, 40, 6, MUTED, rad=2))
return _frame("light", "".join(b))
def _wf_comparison(mode):
b = [_title_bar(w=150), _r(MX, 48, 280, 20, NAVY, rad=4)] # entête
for j in range(3):
b.append(_r(MX + 4 + j * 92, 52, 84, 12, WHITE, rad=2,
op=0.5))
for i in range(4):
y = 72 + i * 22
b.append(_r(MX, y, 280, 18, CARD if i % 2 else WHITE, rad=2,
stroke="#E3E0D9"))
for j in range(3):
b.append(_r(MX + 10 + j * 92, y + 5, 64, 7, MUTED, rad=2))
return _frame("light", "".join(b))
def _wf_raci(mode):
b = [_title_bar(w=120), _r(MX, 48, 280, 18, NAVY, rad=4)]
letters = (NAVY, CORAL, SLATE, GLACIER)
for i in range(4):
y = 70 + i * 22
b.append(_r(MX, y, 80, 16, CARD, rad=2))
for j in range(4):
b.append(_c(130 + j * 44, y + 8, 7, letters[j], 0.85))
return _frame("light", "".join(b))
def _wf_process_arrow(mode):
b = [_title_bar(w=140)]
for i, x in enumerate((MX, 120, 220)):
c = CORAL if i == 1 else NAVY
b.append(f'<polygon points="{x},80 {x+70},80 {x+86},104 '
f'{x+70},128 {x},128 {x+16},104" fill="{c}"/>')
return _frame("light", "".join(b))
def _wf_org_chart(mode):
b = [_title_bar(w=120),
_r(130, 52, 60, 26, NAVY, rad=4)]
for x in (60, 140, 220):
b.append(_r(x, 120, 56, 26, CARD, rad=4, stroke="#E3E0D9"))
b.append(f'<line x1="160" y1="78" x2="{x+28}" y2="120" '
f'stroke="{NAVY}" stroke-width="1.5"/>')
return _frame("light", "".join(b))
def _wf_matrix(mode):
tl = _title_light(mode)
b = [_title_bar(w=120, c=tl),
f'<line x1="160" y1="46" x2="160" y2="170" stroke="{SLATE}" '
f'stroke-width="1.5"/>',
f'<line x1="24" y1="108" x2="296" y2="108" stroke="{SLATE}" '
f'stroke-width="1.5"/>']
quad = ((92, 78, NAVY), (228, 78, CORAL),
(92, 140, SLATE), (228, 140, GLACIER))
for cx, cy, c in quad:
b.append(_c(cx, cy, 16, c, 0.9))
return _frame(mode, "".join(b))
def _wf_image_split(mode):
b = [_img_zone(MX, 44, 130, 120),
_r(168, 44, 130, 14, NAVY, rad=2),
_c(176, 78, 3, CORAL),
_lines(184, 74, 108, 4, gap=17)]
return _frame("light", "".join(b))
def _wf_image_full(mode):
b = [_img_zone(0, 0, W, H),
_r(0, 120, W, 60, NAVY, rad=0, op=0.82),
_r(MX, 134, 150, 12, WHITE, rad=2),
_r(MX, 152, 90, 7, GLACIER, rad=2)]
return _frame("light", "".join(b))
def _wf_bar_chart(mode):
b = [_title_bar(w=120)]
vals = (40, 70, 55, 90, 62)
for i, v in enumerate(vals):
x = 40 + i * 52
b.append(_r(x, 150 - v, 32, v, NAVY, rad=2))
b.append(_r(30, 150, 270, 2, SLATE))
return _frame("light", "".join(b))
def _wf_line_chart(mode):
b = [_title_bar(w=120), _r(30, 150, 270, 2, SLATE)]
pts = [(40, 130), (100, 96), (160, 110), (220, 70), (288, 84)]
path = " ".join(f"{x},{y}" for x, y in pts)
b.append(f'<polyline points="{path}" fill="none" stroke="{NAVY}" '
f'stroke-width="2.5"/>')
b.append(_c(288, 84, 5, CORAL))
return _frame("light", "".join(b))
def _wf_donut(mode):
tl = _title_light(mode)
b = [_title_bar(w=110, c=tl)]
b.append(f'<circle cx="100" cy="106" r="40" fill="none" '
f'stroke="{NAVY}" stroke-width="18"/>')
b.append(f'<path d="M100 66 A40 40 0 0 1 138 118" fill="none" '
f'stroke="{CORAL}" stroke-width="18"/>')
for i, y in enumerate((84, 108, 132)):
b.append(_c(210, y, 6, (NAVY, CORAL, GLACIER)[i]))
b.append(_r(224, y - 4, 76, 7, MUTED, rad=3))
return _frame(mode, "".join(b))
def _wf_waterfall(mode):
b = [_title_bar(w=140), _r(30, 150, 270, 2, SLATE)]
# colonnes cumulées : base navy, deltas coral, total navy
cols = ((40, 150 - 70, 70, NAVY), (94, 80, 34, CORAL),
(148, 60, 40, CORAL), (202, 44, 30, CORAL),
(256, 150 - 90, 90, NAVY))
for x, y, h, c in cols:
b.append(_r(x, y, 34, h, c, rad=2))
return _frame("light", "".join(b))
def _wf_heatmap(mode):
b = [_title_bar(w=120)]
import random
random.seed(3)
shades = ["#D6DCEA", "#9FB0D0", GLACIER, NAVY2, NAVY]
for r in range(4):
for cix in range(5):
b.append(_r(60 + cix * 46, 54 + r * 26, 42, 22,
shades[(r + cix) % 5], rad=2))
b.append(_r(MX, 58 + r * 26, 32, 12, MUTED, rad=2))
return _frame("light", "".join(b))
def _wf_funnel(mode):
b = [_title_bar(w=110)]
widths = (240, 180, 120, 70)
cols = (NAVY, NAVY2, GLACIER, CORAL)
for i, w in enumerate(widths):
x = (W - w) / 2
b.append(f'<polygon points="{x},{58+i*26} {x+w},{58+i*26} '
f'{x+w-14},{80+i*26} {x+14},{80+i*26}" '
f'fill="{cols[i]}"/>')
return _frame("light", "".join(b))
def _wf_pyramid(mode):
b = [_title_bar(w=110)]
widths = (90, 150, 210, 270)
cols = (CORAL, GLACIER, SLATE, NAVY)
for i, w in enumerate(widths):
x = (W - w) / 2
b.append(_r(x, 132 - i * 24, w, 20, cols[i], rad=2))
return _frame("light", "".join(b))
def _wf_generic(mode):
tl = _title_light(mode)
return _frame(mode, _title_bar(c=tl) + _lines(MX, 50, 240, 5,
gap=18))
# ── Mapping layout → archétype ───────────────────────────────────────────────
_MAP = {
"cover_split": _wf_cover,
"section_divider": _wf_section,
"end_slide": _wf_end,
"big_stat": _wf_big_stat,
"key_message": _wf_key_message,
"default_bullets": _wf_bullets,
"two_cols_text": _wf_two_cols,
"from_to_pairs": _wf_from_to,
"executive_summary": _wf_exec_summary,
"kpi_grid": _wf_kpi_grid,
"numbered_steps": _wf_numbered_steps,
"agenda": _wf_agenda,
"circular_diagram": _wf_circular,
"recommendation_card": _wf_recommendation,
"phases_timeline": _wf_phases_timeline,
"gantt_timeline": _wf_gantt,
"yearly_timeline": _wf_yearly,
"comparison_table": _wf_comparison,
"raci_table": _wf_raci,
"process_arrow": _wf_process_arrow,
"org_chart": _wf_org_chart,
"matrix_2x2": _wf_matrix,
"image_split": _wf_image_split,
"image_full": _wf_image_full,
"bar_chart": _wf_bar_chart,
"line_chart": _wf_line_chart,
"donut_split": _wf_donut,
"waterfall": _wf_waterfall,
"heatmap_table": _wf_heatmap,
"funnel": _wf_funnel,
"pyramid": _wf_pyramid,
# freeform : pas de structure fixe → gabarit générique
"freeform": _wf_generic,
}
def svg_for(layout_name, mode="light"):
fn = _MAP.get(layout_name, _wf_generic)
try:
return fn(mode)
except Exception:
return _wf_generic(mode)
def known():
return set(_MAP)
if __name__ == "__main__":
# Auto-test : rend tous les archétypes dans un HTML de contrôle
import yaml
import os
try:
L = yaml.safe_load(open("layouts_v2.yaml",
encoding="utf-8"))["layouts"]
names = list(L)
except Exception:
names = list(_MAP)
cells = "".join(
f'<figure style="margin:8px;display:inline-block;width:240px">'
f'{svg_for(n)}<figcaption style="font:12px sans-serif;'
f'text-align:center">{n}</figcaption></figure>'
for n in names)
open("_wireframes_preview.html", "w").write(
f"<!doctype html><meta charset=utf-8><body "
f"style='background:#FAF9F7'>{cells}</body>")
missing = [n for n in names if n not in _MAP]
print("layouts:", len(names), "| mappés:",
len([n for n in names if n in _MAP]),
"| génériques:", missing or "aucun")
print("Contrôle visuel : _wireframes_preview.html")