// MEMORI — FAQ + CTAs + Footer
// Detect base path: '' from root, '../' from articles/ subfolder
const _FOOTER_BASE = window.location.pathname.includes('/articles/') ? '../' : '';
function Faq() {
const items = [
{ q: "Combien ça coûte ?", a: "L'accompagnement démarre à partir de 500€. Le tarif varie en fonction du besoin, de la fréquence de publication et des options sélectionnées." },
{ q: "Sous combien de temps voit-on des résultats ?", a: "Cela dépend de beaucoup de variables : d'où vous partez, votre nombre d'abonnés, votre légitimité sur le marché, est-ce que vous prenez déjà la parole ou non, etc... Nous pourrons vous donner une réponse après un premier appel, une fois que nous aurons ces informations." },
{ q: "Quel niveau d'implication est attendu de ma part ?", a: "30 minutes à 1h tous les 15 jours pour l'interview. Plus une validation des posts avant publication. Tout le reste : veille, rédaction, publication, growth, extraction de leads, reporting est porté par nos soins." },
{ q: "En quoi est-ce différent d'un freelance ou d'un community manager ?", a: "Un freelance produit du contenu. Un CM gère un calendrier. MEMORI construit une marque. Nous travaillons sur la stratégie éditoriale, la voix, le positionnement, la lead gen et le profil. C'est comme un cabinet de conseil, avec une exécution opérationnelle intégrée. Nous mettons un point d'honneur sur la stratégie en fonction des objectifs." },
{ q: "À qui appartient le contenu publié ?", a: "Les posts publiés sous votre nom vous appartiennent intégralement et à vie. Aucune clause d'exclusivité ne vous lie à MEMORI à ce sujet." },
{ q: "Quelle est la durée d'engagement ?", a: "Il n'y a aucun engagement. Si vous n'aimez pas notre travail, vous êtes libres de partir quand vous le souhaitez." },
{ q: "Comment se passe l'onboarding ?", a: "Semaine 1-2 : audit profil + interviews de cadrage + refonte profil livrée + stratégie de contenu validée. Semaine 3 : on active le run mensuel et on publie les premiers posts." },
];
const [open, setOpen] = React.useState(0);
return (
§ 06 : Questions
Questions fréquentes.
{items.map((it, i) => (
{it.a}
))}
);
}
// Text scramble helper — vanilla React, no deps
const SCRAMBLE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function ScrambleText({ text, trigger, duration = 1.4, speed = 0.032 }) {
const [display, setDisplay] = React.useState(text);
const animating = React.useRef(false);
React.useEffect(() => {
if (!trigger || animating.current) return;
animating.current = true;
const steps = Math.floor(duration / speed);
let step = 0;
const id = setInterval(() => {
const progress = step / steps;
let s = '';
for (let i = 0; i < text.length; i++) {
if (text[i] === ' ' || text[i] === '-') { s += text[i]; continue; }
if (progress * text.length > i) {
s += text[i];
} else {
s += SCRAMBLE_CHARS[Math.floor(Math.random() * SCRAMBLE_CHARS.length)];
}
}
setDisplay(s);
step++;
if (step > steps) {
clearInterval(id);
setDisplay(text);
animating.current = false;
}
}, speed * 1000);
return () => clearInterval(id);
}, [trigger]);
return display;
}
function CtaBanner() {
const [visible, setVisible] = React.useState(false);
const ref = React.useRef(null);
React.useEffect(() => {
const io = new IntersectionObserver(([e]) => {
if (e.isIntersecting) { setVisible(true); io.disconnect(); }
}, { threshold: 0.4 });
if (ref.current) io.observe(ref.current);
return () => io.disconnect();
}, []);
return (