/* Resources / Blog — listing + article pages, mirrors hifi-usecases.jsx pattern */

const RESOURCES_CATEGORIES = (lang) => [
  { slug: 'all', label: lang === 'fr' ? 'Tous' : 'All', tint: '#E1FF6C' },
  { slug: 'outbound', label: 'Outbound', tint: '#E1FF6C' },
  { slug: 'revops', label: 'RevOps', tint: '#B8D4A8' },
  { slug: 'gtm-strategy', label: 'GTM Strategy', tint: '#F4E89B' },
  { slug: 'tooling', label: 'Tooling', tint: '#D6CFC2' }
];

const RESOURCES_DATA = (lang) => window.SITE_TEXTS[lang].resources_cards;

const RESOURCE_DETAIL_DATA = (lang) => window.SITE_TEXTS[lang].resources_articles;

const _RESOURCE_DETAIL_DATA_UNUSED = (lang) => ({
  'intent-data-2026': {
    slug: 'intent-data-2026',
    category: 'outbound',
    eyebrow: lang === 'fr' ? 'Article · Outbound' : 'Article · Outbound',
    title: lang === 'fr'
      ? 'Intent data en 2026 : ce qui marche vraiment'
      : 'Intent data in 2026: what actually works',
    lede: lang === 'fr'
      ? "L'intent data est partout. Mais entre les promesses des vendors et la réalité opérationnelle, il y a un gouffre. Voici ce qu'on a appris en déployant des dizaines de stacks d'intent data chez nos clients."
      : 'Intent data is everywhere. But between vendor promises and operational reality, there is a gulf. Here is what we learned deploying dozens of intent data stacks for our clients.',
    author: 'Antoine Guiné',
    authorRole: lang === 'fr' ? 'Fondateur @Upscale, GTM Engineer' : 'Founder @Upscale, GTM Engineer',
    date: lang === 'fr' ? '12 mai 2026' : 'May 12, 2026',
    readingTime: lang === 'fr' ? '6 min de lecture' : '6 min read',
    sections: [
      {
        kind: 'paragraphs',
        h2: lang === 'fr' ? 'Le problème avec l\'intent data' : 'The problem with intent data',
        body: [
          lang === 'fr'
            ? "La plupart des équipes pensent qu'acheter une licence Bombora ou 6sense suffit. C'est faux. Sans une couche de scoring contextuelle et un routage propre vers le CRM, vous recevez juste du bruit."
            : 'Most teams think buying a Bombora or 6sense license is enough. It is not. Without a contextual scoring layer and clean CRM routing, you just receive noise.',
          lang === 'fr'
            ? "Le vrai gain vient de la combinaison entre signaux first-party (votre site, votre produit) et third-party (intent vendors). Mal combinés, ils s'annulent."
            : 'The real win comes from combining first-party signals (your site, your product) with third-party (intent vendors). Poorly combined, they cancel each other out.'
        ],
        bullets: [
          lang === 'fr' ? "First-party : visites pages pricing, démos abandonnées, pings produit." : 'First-party: pricing page visits, abandoned demos, product pings.',
          lang === 'fr' ? "Third-party : recherches Bombora, hiring signals, funding rounds." : 'Third-party: Bombora searches, hiring signals, funding rounds.',
          lang === 'fr' ? "Internal : score persona × score compte × récence du signal." : 'Internal: persona score × account score × signal recency.'
        ]
      },
      {
        kind: 'paragraphs',
        h2: lang === 'fr' ? 'Notre stack recommandée' : 'Our recommended stack',
        body: [
          lang === 'fr'
            ? "Nous combinons généralement TheirStack pour la détection technographique, Pronto pour les signaux de hiring/funding, et Clay pour orchestrer le scoring final avant push CRM."
            : 'We typically combine TheirStack for technographic detection, Pronto for hiring/funding signals, and Clay to orchestrate the final scoring before CRM push.'
        ]
      },
      {
        kind: 'quote',
        text: lang === 'fr'
          ? "Une stack d'intent data sans scoring, c'est un firehose. Vous recevez tout, vous traitez rien."
          : 'An intent data stack without scoring is a firehose. You receive everything, you process nothing.',
        attribution: 'Antoine Guiné'
      }
    ]
  },
  'crm-source-of-truth': {
    slug: 'crm-source-of-truth',
    category: 'revops',
    eyebrow: lang === 'fr' ? 'Article · RevOps' : 'Article · RevOps',
    title: lang === 'fr'
      ? 'Faire de votre CRM la seule source de vérité'
      : 'Making your CRM the single source of truth',
    lede: lang === 'fr'
      ? "Un CRM mal architecturé devient un cimetière de données. Voici les 4 étapes qu'on applique systématiquement pour le transformer en colonne vertébrale opérationnelle."
      : 'A poorly architected CRM becomes a data graveyard. Here are the 4 steps we systematically apply to turn it into the operational backbone.',
    author: 'Antoine Guiné',
    authorRole: lang === 'fr' ? 'Fondateur @Upscale, GTM Engineer' : 'Founder @Upscale, GTM Engineer',
    date: lang === 'fr' ? '28 avril 2026' : 'April 28, 2026',
    readingTime: lang === 'fr' ? '8 min de lecture' : '8 min read',
    sections: [
      {
        kind: 'paragraphs',
        h2: lang === 'fr' ? 'Étape 1 — Définir le schéma minimal' : 'Step 1 — Define the minimal schema',
        body: [
          lang === 'fr'
            ? "Avant tout sync, posez-vous la question : quels champs sont vraiment utilisés pour décider ? Si un champ n'est pas filtré dans un report ou un workflow, il dégrade votre data."
            : 'Before any sync, ask yourself: which fields are actually used to decide? If a field is never filtered in a report or workflow, it degrades your data.'
        ]
      },
      {
        kind: 'paragraphs',
        h2: lang === 'fr' ? 'Étape 2 — Centraliser l\'enrichissement' : 'Step 2 — Centralize enrichment',
        body: [
          lang === 'fr'
            ? "Tous vos outils d'enrichissement (Cargo, CompanyEnrich, Apollo) doivent écrire dans un seul flux orchestré par Clay ou n8n. Sinon vous obtenez 3 versions du même contact."
            : 'All your enrichment tools (Cargo, CompanyEnrich, Apollo) should write to a single orchestrated flow via Clay or n8n. Otherwise you end up with 3 versions of the same contact.'
        ],
        bullets: [
          lang === 'fr' ? "Une seule source d'écriture par champ critique." : 'One source of truth per critical field.',
          lang === 'fr' ? "Logging des changements pour audit." : 'Change logging for audit.',
          lang === 'fr' ? "Règles de priorité explicites en cas de conflit." : 'Explicit priority rules on conflict.'
        ]
      }
    ]
  },
  'sales-machine-blueprint': {
    slug: 'sales-machine-blueprint',
    category: 'gtm-strategy',
    eyebrow: lang === 'fr' ? 'Article · GTM Strategy' : 'Article · GTM Strategy',
    title: lang === 'fr'
      ? "Blueprint d'une sales machine B2B en 90 jours"
      : 'Blueprint of a B2B sales machine in 90 days',
    lede: lang === 'fr'
      ? "C'est l'architecture exacte qu'on déploie chez nos clients. Workflows, scoring, routage, nurturing : tout est documenté. Voici ce qu'il faut savoir avant de se lancer."
      : 'This is the exact architecture we deploy with our clients. Workflows, scoring, routing, nurturing: everything is documented. Here is what you need to know before starting.',
    author: 'Antoine Guiné',
    authorRole: lang === 'fr' ? 'Fondateur @Upscale, GTM Engineer' : 'Founder @Upscale, GTM Engineer',
    date: lang === 'fr' ? '15 avril 2026' : 'April 15, 2026',
    readingTime: lang === 'fr' ? '12 min de lecture' : '12 min read',
    sections: [
      {
        kind: 'paragraphs',
        h2: lang === 'fr' ? 'Les 5 piliers' : 'The 5 pillars',
        body: [
          lang === 'fr'
            ? "Une sales machine performante repose sur 5 piliers indissociables. Si l'un est faible, l'ensemble s'effondre."
            : 'A performant sales machine rests on 5 inseparable pillars. If one is weak, the whole collapses.'
        ],
        bullets: [
          lang === 'fr' ? 'Sourcing — comment vous générez votre TAM addressable.' : 'Sourcing — how you generate your addressable TAM.',
          lang === 'fr' ? 'Enrichissement — la qualité des données comportementales.' : 'Enrichment — the quality of behavioral data.',
          lang === 'fr' ? 'Copywriting — personnalisation à scale sans dégradation.' : 'Copywriting — personalization at scale without degradation.',
          lang === 'fr' ? 'Diffusion — infra mail propre et séquences signal-based.' : 'Outreach — clean mail infra and signal-based sequences.',
          lang === 'fr' ? 'Scoring & routage — du lead engagé au RDV qualifié.' : 'Scoring & routing — from engaged lead to qualified meeting.'
        ]
      },
      {
        kind: 'quote',
        text: lang === 'fr'
          ? "Le volume sans personnalisation = burn-out de votre marque. La personnalisation sans volume = pas d'impact."
          : 'Volume without personalization = brand burn-out. Personalization without volume = no impact.',
        attribution: 'Antoine Guiné'
      }
    ]
  }
}); // end _RESOURCE_DETAIL_DATA_UNUSED

const resourcesArticleByCategory = (categorySlug, lang) => {
  const all = RESOURCES_DATA(lang);
  if (!categorySlug || categorySlug === 'all') return all;
  return all.filter(a => a.category === categorySlug);
};

const ResourcesHero = ({ lang }) => {
  return (
    <section className="u-section" style={{
      paddingTop: 100, paddingBottom: 60,
      position: 'relative',
      overflow: 'hidden'
    }}>
      <div style={{
        position: 'absolute', top: -80, right: -80,
        width: 380, height: 380,
        background: 'radial-gradient(circle, rgba(225,255,108,0.55) 0%, rgba(225,255,108,0) 70%)',
        pointerEvents: 'none'
      }}></div>

      <div className="u-container" style={{ position: 'relative' }}>
        <p className="u-eyebrow" style={{ marginBottom: 18 }}>
          — {window.SITE_TEXTS[lang].resources_hero.eyebrow}
        </p>
        <h1 style={{
          fontSize: 76,
          letterSpacing: '-0.025em',
          lineHeight: 1.02,
          marginBottom: 24,
          maxWidth: 920
        }}>
          {window.SITE_TEXTS[lang].resources_hero.h1a}{' '}
          <span style={{
            fontFamily: 'var(--font-display)',
            fontStyle: 'italic',
            fontWeight: 400
          }}>{window.SITE_TEXTS[lang].resources_hero.h1b}</span>.
        </h1>
        <p style={{
          fontSize: 18,
          lineHeight: 1.55,
          color: 'var(--gray-4)',
          maxWidth: 620,
          marginBottom: 0
        }}>
          {window.SITE_TEXTS[lang].resources_hero.sub}
        </p>
      </div>
    </section>
  );
};

const ResourcesGrid = ({ lang }) => {
  const [activeCat, setActiveCat] = useState('all');
  const categories = RESOURCES_CATEGORIES(lang);
  const articles = resourcesArticleByCategory(activeCat, lang);

  return (
    <section className="u-section" style={{ paddingTop: 0, paddingBottom: 100 }}>
      <div className="u-container">
        {/* Category filter */}
        <div style={{
          display: 'flex',
          gap: 8,
          flexWrap: 'wrap',
          marginBottom: 40,
          paddingBottom: 24,
          borderBottom: '1px solid var(--line)'
        }}>
          {categories.map((c) => {
            const isActive = activeCat === c.slug;
            return (
              <button
                key={c.slug}
                type="button"
                onClick={() => setActiveCat(c.slug)}
                style={{
                  padding: '8px 16px',
                  borderRadius: 999,
                  border: '1px solid var(--line)',
                  background: isActive ? 'var(--ink)' : 'transparent',
                  color: isActive ? 'var(--bg)' : 'var(--ink)',
                  fontSize: 13,
                  fontFamily: 'var(--font-mono)',
                  textTransform: 'uppercase',
                  letterSpacing: '0.04em',
                  cursor: 'pointer',
                  transition: 'background .18s ease, color .18s ease'
                }}
              >{c.label}</button>
            );
          })}
        </div>

        {articles.length === 0 ? (
          <p style={{ fontSize: 16, color: 'var(--gray-4)', textAlign: 'center', padding: '40px 0' }}>
            {lang === 'fr' ? 'Aucun article dans cette catégorie.' : 'No articles in this category.'}
          </p>
        ) : (
          <div style={{
            display: 'grid',
            gridTemplateColumns: 'repeat(auto-fill, minmax(340px, 1fr))',
            gap: 24
          }}>
            {articles.map((a) => {
              const cat = categories.find(c => c.slug === a.category) || { label: a.category, tint: '#E1FF6C' };
              return (
              <a
                key={a.slug}
                href={`#/ressources/${a.slug}`}
                onClick={(e) => { e.preventDefault(); window.location.hash = `/ressources/${a.slug}`; window.scrollTo({ top: 0, behavior: 'auto' }); }}
                style={{
                  display: 'block',
                  background: 'var(--paper)',
                  border: '1px solid var(--line)',
                  borderRadius: 24,
                  overflow: 'hidden',
                  textDecoration: 'none',
                  color: 'inherit',
                  transition: 'transform .25s ease, box-shadow .25s ease'
                }}
                onMouseEnter={(e) => {
                  e.currentTarget.style.transform = 'translateY(-2px)';
                  e.currentTarget.style.boxShadow = '0 18px 40px -22px rgba(28,29,31,0.18)';
                }}
                onMouseLeave={(e) => {
                  e.currentTarget.style.transform = 'translateY(0)';
                  e.currentTarget.style.boxShadow = 'none';
                }}
              >
                <div style={{
                  position: 'relative',
                  background: cat.tint,
                  padding: '24px',
                  minHeight: 80,
                  display: 'flex',
                  alignItems: 'center'
                }}>
                  <div style={{
                    position: 'absolute', inset: 0,
                    backgroundImage: 'linear-gradient(rgba(28,29,31,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(28,29,31,0.05) 1px, transparent 1px)',
                    backgroundSize: '24px 24px',
                    opacity: 0.5,
                    pointerEvents: 'none'
                  }}></div>
                  <span style={{
                    position: 'relative',
                    display: 'inline-flex',
                    padding: '5px 12px',
                    borderRadius: 999,
                    background: 'var(--paper)',
                    border: '1px solid rgba(28,29,31,0.08)',
                    fontSize: 11,
                    fontFamily: 'var(--font-mono)',
                    textTransform: 'uppercase',
                    letterSpacing: '0.06em',
                    color: 'var(--ink)'
                  }}>
                    {cat.label}
                  </span>
                </div>

                <div style={{ padding: '24px 28px 28px' }}>
                  <p style={{
                    fontSize: 11,
                    fontFamily: 'var(--font-mono)',
                    textTransform: 'uppercase',
                    letterSpacing: '0.06em',
                    color: 'var(--gray-3)',
                    marginBottom: 12
                  }}>{a.date} · {a.readingTime}</p>
                  <h3 style={{
                    fontSize: 22,
                    letterSpacing: '-0.015em',
                    lineHeight: 1.2,
                    marginBottom: 12,
                    color: 'var(--ink)'
                  }}>{a.title}</h3>
                  <p style={{
                    fontSize: 14,
                    lineHeight: 1.55,
                    color: 'var(--gray-4)',
                    marginBottom: 16
                  }}>{a.excerpt}</p>
                  <p style={{
                    fontSize: 13,
                    fontFamily: 'var(--font-mono)',
                    color: 'var(--ink)'
                  }}>{lang === 'fr' ? 'Lire l\'article' : 'Read article'} →</p>
                </div>
              </a>
              );
            })}
          </div>
        )}
      </div>
    </section>
  );
};

/* ---- Sub-resources icons ---- */
const IconStack = () => (
  <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <path d="M12 2 2 7l10 5 10-5-10-5Z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/>
  </svg>
);
const IconMail = () => (
  <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>
  </svg>
);
const IconPlay = () => (
  <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <circle cx="12" cy="12" r="10"/><polygon points="10 8 16 12 10 16 10 8"/>
  </svg>
);

const SUB_RESOURCES = (lang) => [
  {
    label: 'TOOLING',
    title: 'Best GTM Stack 2026',
    desc: lang === 'fr'
      ? "Notre sélection des meilleurs outils GTM, testés en conditions réelles chez nos clients."
      : "Our curated selection of the best GTM tools, tested in real client environments.",
    cta: lang === 'fr' ? 'Voir la sélection' : 'View selection',
    tint: '#E1FF6C',
    href: '#',
    icon: <IconStack />,
  },
  {
    label: 'NEWSLETTER',
    title: lang === 'fr' ? 'Newsletter Upscale' : 'Upscale Newsletter',
    desc: lang === 'fr'
      ? "Les meilleurs insights GTM chaque semaine. Rejoins 2 000+ leaders B2B."
      : "The best GTM insights every week. Join 2,000+ B2B leaders.",
    cta: lang === 'fr' ? "S'inscrire" : 'Subscribe',
    tint: '#F4E89B',
    href: '#',
    icon: <IconMail />,
  },
  {
    label: lang === 'fr' ? 'VIDÉOS' : 'VIDEOS',
    title: lang === 'fr' ? 'Vidéos GTM' : 'GTM Videos',
    desc: lang === 'fr'
      ? "Formats courts et actionnables sur l'outbound, le copywriting et le RevOps."
      : "Short, actionable formats on outbound, copywriting and RevOps.",
    cta: lang === 'fr' ? 'Regarder' : 'Watch',
    tint: '#D6CFC2',
    href: '#',
    icon: <IconPlay />,
  },
];

const SubResourcesSection = ({ lang }) => {
  const items = SUB_RESOURCES(lang);
  return (
    <section style={{ paddingBottom: 60 }}>
      <div className="u-container">
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20 }}>
          {items.map((it, i) => (
            <a
              key={i}
              href={it.href}
              style={{
                display: 'block',
                background: 'var(--paper)',
                border: '1px solid var(--line)',
                borderRadius: 24,
                overflow: 'hidden',
                textDecoration: 'none',
                color: 'inherit',
                transition: 'transform .25s ease, box-shadow .25s ease',
              }}
              onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 18px 40px -22px rgba(28,29,31,0.18)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }}
            >
              {/* Coloured banner */}
              <div style={{
                background: it.tint,
                minHeight: 80,
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'space-between',
                padding: '20px 24px',
                position: 'relative',
              }}>
                <div style={{
                  position: 'absolute', inset: 0,
                  backgroundImage: 'linear-gradient(rgba(28,29,31,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(28,29,31,0.05) 1px, transparent 1px)',
                  backgroundSize: '24px 24px',
                  opacity: 0.5,
                  pointerEvents: 'none'
                }}></div>
                <span style={{
                  position: 'relative',
                  display: 'inline-flex',
                  padding: '5px 12px',
                  borderRadius: 999,
                  background: 'var(--paper)',
                  border: '1px solid rgba(28,29,31,0.08)',
                  fontSize: 11,
                  fontFamily: 'var(--font-mono)',
                  textTransform: 'uppercase',
                  letterSpacing: '0.06em',
                  color: 'var(--ink)'
                }}>{it.label}</span>
                <span style={{ position: 'relative', color: 'rgba(28,29,31,0.55)' }}>{it.icon}</span>
              </div>
              {/* Body */}
              <div style={{ padding: '22px 26px 26px' }}>
                <h3 style={{ fontSize: 20, letterSpacing: '-0.015em', lineHeight: 1.2, marginBottom: 8 }}>{it.title}</h3>
                <p style={{ fontSize: 14, lineHeight: 1.55, color: 'var(--gray-4)', marginBottom: 18 }}>{it.desc}</p>
                <p style={{ fontSize: 13, fontFamily: 'var(--font-mono)', color: 'var(--ink)' }}>{it.cta} →</p>
              </div>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
};

const ResourcesPage = ({ lang }) => {
  return (
    <>
      <ResourcesHero lang={lang} />
      <ResourcesGrid lang={lang} />
      <CtaFinal lang={lang} />
    </>
  );
};

window.ResourcesPage = ResourcesPage;

// ===================== Article page =====================

const ResourceArticleHero = ({ data, lang }) => {
  return (
    <section className="u-section" style={{
      paddingTop: 80, paddingBottom: 56,
      position: 'relative',
      overflow: 'hidden'
    }}>
      <div style={{
        position: 'absolute', top: -100, right: -120,
        width: 460, height: 460,
        background: 'radial-gradient(circle, rgba(225,255,108,0.55) 0%, rgba(225,255,108,0) 70%)',
        pointerEvents: 'none'
      }}></div>

      <div className="u-container" style={{ position: 'relative' }}>
        <a
          href="#/ressources"
          onClick={(e) => { e.preventDefault(); window.location.hash = '/ressources'; window.scrollTo({ top: 0, behavior: 'auto' }); }}
          style={{
            display: 'inline-flex', alignItems: 'center', gap: 8,
            fontSize: 13,
            fontFamily: 'var(--font-mono)',
            color: 'var(--gray-4)',
            marginBottom: 32,
            cursor: 'pointer'
          }}
        >
          <span style={{ fontSize: 14 }}>←</span>
          {lang === 'fr' ? 'Tous les articles' : 'All articles'}
        </a>

        {(() => {
          const parts = (data.eyebrow || '').split(' · ');
          const type = parts[0] || 'Article';
          const cat  = parts[1] || '';
          const TINTS = { 'Outbound': '#E1FF6C', 'RevOps': '#B8D4A8', 'GTM Strategy': '#F4E89B', 'Tooling': '#D6CFC2' };
          const tint = TINTS[cat] || '#E8E8E4';
          return (
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 20 }}>
              <span style={{
                fontSize: 11, fontFamily: 'var(--font-mono)', textTransform: 'uppercase',
                letterSpacing: '0.08em', color: 'var(--gray-3)'
              }}>{type}</span>
              {cat && <>
                <span style={{ color: 'var(--gray-3)', fontSize: 11 }}>·</span>
                <span style={{
                  display: 'inline-block',
                  padding: '3px 10px',
                  borderRadius: 20,
                  background: tint,
                  fontSize: 11,
                  fontFamily: 'var(--font-mono)',
                  fontWeight: 600,
                  letterSpacing: '0.05em',
                  textTransform: 'uppercase',
                  color: 'rgba(28,29,31,0.75)'
                }}>{cat}</span>
              </>}
            </div>
          );
        })()}

        <h1 style={{
          fontSize: 64,
          letterSpacing: '-0.025em',
          lineHeight: 1.05,
          marginBottom: 52,
          maxWidth: 880
        }}>{data.title}</h1>

        <p style={{
          fontSize: 16,
          lineHeight: 1.65,
          color: 'var(--gray-3)',
          maxWidth: 680,
          marginBottom: 40
        }}>{data.lede}</p>

        <div style={{
          display: 'flex',
          flexWrap: 'wrap',
          gap: 28,
          padding: '20px 0',
          borderTop: '1px solid var(--line)',
          borderBottom: '1px solid var(--line)'
        }}>
          {/* Author with avatar */}
          <div>
            <p style={{
              fontSize: 11,
              fontFamily: 'var(--font-mono)',
              textTransform: 'uppercase',
              letterSpacing: '0.06em',
              color: 'var(--gray-3)',
              marginBottom: 4
            }}>{lang === 'fr' ? 'Auteur' : 'Author'}</p>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, minHeight: 28 }}>
              <img
                src="https://lh3.googleusercontent.com/d/1oBYRUOMr9gC-FIzqlUI7Hu3g1NGfG0xH=s0"
                alt="Antoine Guiné"
                style={{ width: 28, height: 28, borderRadius: '50%', objectFit: 'cover', flexShrink: 0 }}
              />
              <span style={{ fontSize: 14, fontWeight: 500, color: 'var(--ink)' }}>{data.author.split(' ')[0]}</span>
            </div>
          </div>
          {/* Date + reading time */}
          {[
            [lang === 'fr' ? 'Publié le' : 'Published', data.date],
            [lang === 'fr' ? 'Lecture' : 'Reading', data.readingTime]
          ].map(([l, v], i) => (
            <div key={i}>
              <p style={{
                fontSize: 11,
                fontFamily: 'var(--font-mono)',
                textTransform: 'uppercase',
                letterSpacing: '0.06em',
                color: 'var(--gray-3)',
                marginBottom: 4
              }}>{l}</p>
              <div style={{ display: 'flex', alignItems: 'center', minHeight: 28 }}>
                <p style={{ fontSize: 14, fontWeight: 500, color: 'var(--ink)' }}>{v}</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
};

const ResourceParagraph = ({ children }) => (
  <p style={{
    fontSize: 17,
    lineHeight: 1.65,
    color: 'var(--ink-soft)',
    marginBottom: 18
  }}>{children}</p>
);

const ResourceBullets = ({ items }) => (
  <ul style={{
    listStyle: 'none',
    margin: '4px 0 22px',
    padding: 0
  }}>
    {items.map((it, i) => (
      <li key={i} style={{
        fontSize: 17,
        lineHeight: 1.6,
        color: 'var(--ink-soft)',
        marginBottom: 10,
        paddingLeft: 22,
        position: 'relative'
      }}>
        <span style={{
          position: 'absolute', left: 0, top: 10,
          width: 6, height: 6, borderRadius: '50%',
          background: 'var(--accent-edge)'
        }}></span>
        {it}
      </li>
    ))}
  </ul>
);

const ResourceCallout = ({ text }) => (
  <div style={{
    margin: '6px 0 22px',
    padding: '14px 18px',
    background: 'var(--bg-2)',
    border: '1px solid var(--line)',
    borderLeft: '3px solid var(--accent-edge)',
    borderRadius: 10,
    fontSize: 15,
    lineHeight: 1.55,
    color: 'var(--ink-soft)'
  }}>{text}</div>
);

const ResourceTable = ({ columns, rows }) => (
  <div style={{ margin: '6px 0 24px', overflowX: 'auto' }}>
    <table style={{
      width: '100%',
      borderCollapse: 'collapse',
      fontSize: 15,
      border: '1px solid var(--line)',
      borderRadius: 10,
      overflow: 'hidden'
    }}>
      <thead>
        <tr style={{ background: 'var(--paper)', borderBottom: '1px solid var(--line)' }}>
          {columns.map((col, i) => (
            <th key={i} style={{
              padding: '10px 16px',
              textAlign: 'left',
              fontSize: 11,
              fontFamily: 'var(--font-mono)',
              textTransform: 'uppercase',
              letterSpacing: '0.06em',
              color: 'var(--gray-3)',
              fontWeight: 500
            }}>{col}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {rows.map((row, i) => (
          <tr key={i} style={{ borderBottom: i < rows.length - 1 ? '1px solid var(--line)' : 'none', background: i % 2 === 0 ? 'transparent' : 'var(--bg-2)' }}>
            {row.map((cell, j) => (
              <td key={j} style={{
                padding: '10px 16px',
                color: 'var(--ink-soft)',
                fontWeight: j === 1 ? 600 : 400
              }}>{cell}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  </div>
);

const ResourceImage = ({ src, alt, caption, maxWidth }) => (
  <div style={{ margin: '10px 0 28px', maxWidth: maxWidth || '100%' }}>
    <div style={{ borderRadius: 10, overflow: 'hidden', border: '1px solid var(--line)' }}>
      <img src={src} alt={alt || ''} style={{ display: 'block', width: '100%', height: 'auto' }} />
    </div>
    {caption && <p style={{ marginTop: 10, fontSize: 13, fontFamily: 'var(--font-mono)', color: 'var(--gray-3)', textAlign: 'center' }}>{caption}</p>}
  </div>
);

const ResourceEmbed = ({ src, title }) => {
  const [height, setHeight] = React.useState(200);
  const ref = React.useRef(null);

  const syncHeight = React.useCallback(() => {
    try {
      const doc = ref.current && ref.current.contentDocument;
      if (doc) {
        const h = doc.documentElement.scrollHeight || doc.body.scrollHeight;
        if (h > 50) setHeight(h);
      }
    } catch(e) {}
  }, []);

  const handleLoad = React.useCallback(() => {
    syncHeight();
    try {
      const win = ref.current && ref.current.contentWindow;
      if (win) {
        win.addEventListener('resize', syncHeight);
        if (win.ResizeObserver) {
          const ro = new win.ResizeObserver(syncHeight);
          ro.observe(ref.current.contentDocument.documentElement);
        }
      }
    } catch(e) {}
    // Re-check after fonts/images settle
    setTimeout(syncHeight, 300);
    setTimeout(syncHeight, 800);
  }, [syncHeight]);

  return (
    <div style={{ margin: '10px 0 28px', borderRadius: 10, overflow: 'hidden', border: '1px solid var(--line)' }}>
      <iframe
        ref={ref}
        src={src}
        onLoad={handleLoad}
        scrolling="no"
        style={{ width: '100%', height, display: 'block', border: 'none' }}
        title={title || 'embed'}
      />
    </div>
  );
};

const renderResourceBodyItem = (it, i) => {
  if (typeof it === 'string') return <ResourceParagraph key={i}>{it}</ResourceParagraph>;
  if (it.kind === 'bullets') return <ResourceBullets key={i} items={it.items} />;
  if (it.kind === 'callout') return <ResourceCallout key={i} text={it.text} />;
  if (it.kind === 'table') return <ResourceTable key={i} columns={it.columns} rows={it.rows} />;
  if (it.kind === 'image') return <ResourceImage key={i} src={it.src} alt={it.alt} caption={it.caption} maxWidth={it.maxWidth} />;
  if (it.kind === 'embed') return <ResourceEmbed key={i} src={it.src} title={it.title} />;
  return null;
};

const ResourceArticleSection = ({ section, lang }) => {
  const containerStyle = { maxWidth: 720, margin: '0 auto' };

  if (section.kind === 'paragraphs') {
    return (
      <section className="u-section" style={{ paddingTop: 32, paddingBottom: 16 }}>
        <div className="u-container">
          <div style={containerStyle}>
            {section.h2 && (
              <h2 style={{
                fontSize: 32,
                letterSpacing: '-0.02em',
                marginBottom: 18,
                color: 'var(--ink)'
              }}>{section.h2}</h2>
            )}
            {section.body && section.body.map((it, i) => renderResourceBodyItem(it, i))}
            {section.bullets && <ResourceBullets items={section.bullets} />}
          </div>
        </div>
      </section>
    );
  }

  if (section.kind === 'cta') {
    return (
      <section style={{ paddingTop: 12, paddingBottom: 12 }}>
        <div className="u-container">
          <div style={containerStyle}>
            <div style={{ background: '#E1FF6C', borderRadius: 10, padding: '20px 28px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
              <div>
                {section.title && <p style={{ fontWeight: 700, fontSize: 16, color: 'var(--ink)', marginBottom: 4 }}>{section.title}</p>}
                {section.subtitle && <p style={{ fontSize: 14, color: 'rgba(11,13,15,0.7)' }}>{section.subtitle}</p>}
              </div>
              <a data-cal-link="antoineguine/appel-de-decouverte-website" data-cal-namespace="appel-de-decouverte-website" data-cal-config='{"layout":"month_view","useSlotsViewOnSmallScreen":"true"}' style={{ display: 'inline-block', background: 'var(--ink)', color: '#fff', padding: '10px 20px', borderRadius: 8, fontSize: 14, fontWeight: 600, textDecoration: 'none', cursor: 'pointer', whiteSpace: 'nowrap', flexShrink: 0 }}>Réserver un créneau →</a>
            </div>
          </div>
        </div>
      </section>
    );
  }

  if (section.kind === 'quote') {
    return (
      <section className="u-section" style={{ paddingTop: 28, paddingBottom: 28 }}>
        <div className="u-container">
          <figure style={{ ...containerStyle, margin: '0 auto' }}>
            <blockquote style={{
              fontFamily: 'var(--font-display)',
              fontStyle: 'italic',
              fontSize: 28,
              lineHeight: 1.35,
              color: 'var(--ink)',
              padding: '24px 0 18px',
              borderLeft: '3px solid var(--accent-edge)',
              paddingLeft: 24,
              margin: 0
            }}>{section.text}</blockquote>
            {section.attribution && (
              <figcaption style={{
                fontSize: 13,
                fontFamily: 'var(--font-mono)',
                color: 'var(--gray-3)',
                paddingLeft: 24,
                marginTop: 8
              }}>— {section.attribution}</figcaption>
            )}
          </figure>
        </div>
      </section>
    );
  }

  return null;
};

const ResourceRelated = ({ currentSlug, lang }) => {
  const all = RESOURCES_DATA(lang).filter(a => a.slug !== currentSlug).slice(0, 2);
  if (all.length === 0) return null;
  const categories = RESOURCES_CATEGORIES(lang);

  return (
    <section className="u-section" style={{ paddingTop: 80, paddingBottom: 60 }}>
      <div className="u-container">
        <p className="u-eyebrow" style={{ marginBottom: 24 }}>
          — {lang === 'fr' ? 'À lire ensuite' : 'Read next'}
        </p>
        <div style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))',
          gap: 24
        }}>
          {all.map((a) => (
            <a
              key={a.slug}
              href={`#/ressources/${a.slug}`}
              onClick={(e) => { e.preventDefault(); window.location.hash = `/ressources/${a.slug}`; window.scrollTo({ top: 0, behavior: 'auto' }); }}
              style={{
                display: 'block',
                background: 'var(--paper)',
                border: '1px solid var(--line)',
                borderRadius: 20,
                padding: 24,
                textDecoration: 'none',
                color: 'inherit',
                transition: 'transform .25s ease, box-shadow .25s ease'
              }}
              onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 18px 40px -22px rgba(28,29,31,0.18)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }}
            >
              <p style={{
                fontSize: 11,
                fontFamily: 'var(--font-mono)',
                textTransform: 'uppercase',
                letterSpacing: '0.06em',
                color: 'var(--gray-3)',
                marginBottom: 10
              }}>{(categories.find(c => c.slug === a.category) || { label: a.category }).label} · {a.date}</p>
              <h3 style={{
                fontSize: 20,
                letterSpacing: '-0.015em',
                lineHeight: 1.25,
                marginBottom: 10,
                color: 'var(--ink)'
              }}>{a.title}</h3>
              <p style={{
                fontSize: 14,
                lineHeight: 1.55,
                color: 'var(--gray-4)'
              }}>{a.excerpt}</p>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
};

const ResourcePage = ({ slug, lang }) => {
  const data = RESOURCE_DETAIL_DATA(lang)[slug];
  if (!data) {
    return (
      <section className="u-section" style={{ paddingTop: 120, paddingBottom: 120 }}>
        <div className="u-container" style={{ textAlign: 'center' }}>
          <p className="u-eyebrow" style={{ marginBottom: 14 }}>404</p>
          <h1 style={{ fontSize: 48, marginBottom: 18 }}>
            {lang === 'fr' ? 'Article introuvable' : 'Article not found'}
          </h1>
          <a
            href="#/ressources"
            onClick={(e) => { e.preventDefault(); window.location.hash = '/ressources'; window.scrollTo({ top: 0 }); }}
            className="u-btn u-btn-primary"
            style={{ padding: '12px 22px', fontSize: 15, marginTop: 12 }}
          >{lang === 'fr' ? 'Voir toutes les ressources' : 'See all resources'} →</a>
        </div>
      </section>
    );
  }
  return (
    <>
      <ResourceArticleHero data={data} lang={lang} />
      {data.sections.map((s, i) => (
        <ResourceArticleSection key={i} section={s} lang={lang} />
      ))}
      <ResourceRelated currentSlug={slug} lang={lang} />
      <CtaFinal lang={lang} />
      <CaseStudyStickyCta lang={lang} />
    </>
  );
};

window.ResourcePage = ResourcePage;

/* ─── Newsletter Page ──────────────────────────────────────────── */
const RSS_FEED_URL = 'https://rss.beehiiv.com/feeds/taexU5J7XH.xml';
const RSS_PROXY    = 'https://corsproxy.io/?url=' + encodeURIComponent(RSS_FEED_URL);

const formatRSSDate = (dateStr, lang) => {
  try {
    const d = new Date(dateStr);
    return d.toLocaleDateString(lang === 'fr' ? 'fr-FR' : 'en-GB', { day: 'numeric', month: 'short', year: 'numeric' });
  } catch(_) { return dateStr; }
};

const parseRSSItems = (xmlText, lang) => {
  const parser = new DOMParser();
  const doc = parser.parseFromString(xmlText, 'text/xml');
  return Array.from(doc.querySelectorAll('item')).slice(0, 8).map(item => {
    // <link> is awkward in XML — prefer guid which is always the permalink on Beehiiv
    const guid = item.querySelector('guid')?.textContent?.trim() || '#';
    const title = item.querySelector('title')?.textContent?.trim() || '';
    const pubDate = item.querySelector('pubDate')?.textContent?.trim() || '';
    const description = item.querySelector('description')?.textContent?.trim() || '';
    return { title, link: guid, date: formatRSSDate(pubDate, lang), description };
  });
};

const NewsletterPage = ({ lang }) => {
  const [email, setEmail] = React.useState('');
  const [sent, setSent] = React.useState(false);
  const [submitting, setSubmitting] = React.useState(false);
  const [submitError, setSubmitError] = React.useState(false);
  const [issues, setIssues] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [fetchError, setFetchError] = React.useState(false);

  React.useEffect(() => {
    let cancelled = false;
    const load = (url) =>
      fetch(url)
        .then(r => { if (!r.ok) throw new Error(r.status); return r.text(); })
        .then(text => {
          if (cancelled) return;
          const parsed = parseRSSItems(text, lang);
          setIssues(parsed);
          setLoading(false);
        });

    load(RSS_FEED_URL)
      .catch(() => load(RSS_PROXY))
      .catch(() => { if (!cancelled) { setFetchError(true); setLoading(false); } });

    return () => { cancelled = true; };
  }, [lang]);

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!email.trim()) return;
    setSubmitting(true);
    setSubmitError(false);
    try {
      await window.beehiivSubscribe(email.trim(), {
        utm_source: 'upscale-homepage',
        utm_medium: 'newsletter-page',
        utm_campaign: 'newsletter',
      });
      setSent(true);
    } catch (_) {
      setSubmitError(true);
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <>
      {/* Hero */}
      <section style={{ paddingTop: 100, paddingBottom: 72, position: 'relative', overflow: 'hidden', borderBottom: '1px solid var(--line)' }}>
        {/* Ray lines — same as homepage hero */}
        <svg aria-hidden="true" preserveAspectRatio="none" viewBox="0 0 100 100"
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 0 }}>
          <defs>
            <linearGradient id="nl-ray-fade" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="50">
              <stop offset="0%" stopColor="rgb(28,29,31)" stopOpacity="0.05" />
              <stop offset="100%" stopColor="rgb(28,29,31)" stopOpacity="0" />
            </linearGradient>
          </defs>
          {[-3, -1, 1, 3].map(i => (
            <line key={i} x1="50" y1="130" x2={50 + i * 18} y2="-10"
              stroke="url(#nl-ray-fade)" strokeWidth="1" vectorEffect="non-scaling-stroke" />
          ))}
        </svg>

        <div className="u-container" style={{ maxWidth: 720, position: 'relative', zIndex: 1 }}>
          <span className="u-chip u-chip-accent" style={{ marginBottom: 22 }}>
            <span className="u-dot" style={{ background: 'var(--ink)' }}></span>
            {lang === 'fr' ? 'Newsletter GTM' : 'GTM Newsletter'}
          </span>
          <h1 style={{ fontSize: 'clamp(36px, 6vw, 64px)', lineHeight: 1.02, letterSpacing: '-0.03em', marginBottom: 20 }}>
            {lang === 'fr' ? 'La newsletter GTM ' : 'The GTM newsletter '}
            <span style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic', fontWeight: 400 }}>
              {lang === 'fr' ? 'numéro #1 en France.' : '#1 in France.'}
            </span>
          </h1>
          <p style={{ fontSize: 18, color: 'var(--gray-4)', lineHeight: 1.6, marginBottom: 40, maxWidth: 560 }}>
            {lang === 'fr'
              ? 'Use cases clients, méthodes et stratégies. Une édition par semaine, lue par +2 000 équipes B2B.'
              : 'Client use cases, methods and strategies. One issue per week, read by 2,000+ B2B teams.'}
          </p>

          {/* Signup form */}
          {sent ? (
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: 12, padding: '16px 24px', background: 'var(--paper)', border: '1px solid var(--line)', borderRadius: 14 }}>
              <span style={{ width: 24, height: 24, borderRadius: '50%', background: 'var(--accent)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                <svg width="12" height="12" viewBox="0 0 10 10" fill="none"><path d="M1.5 5L3.8 7.5L8.5 2.5" stroke="var(--ink)" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>
              </span>
              <span style={{ fontSize: 16, fontWeight: 600, color: 'var(--ink)' }}>
                {lang === 'fr' ? 'Tu es inscrit·e !' : "You're subscribed!"}
              </span>
            </div>
          ) : (
            <>
              <form onSubmit={handleSubmit} style={{ display: 'flex', gap: 10, maxWidth: 480, flexWrap: 'wrap' }}>
                <input
                  type="email" required value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  placeholder={lang === 'fr' ? 'ton@email.com' : 'your@email.com'}
                  style={{
                    flex: 1, minWidth: 200, height: 48, padding: '0 18px',
                    borderRadius: 12, border: '1px solid var(--line)',
                    background: 'var(--paper)', color: 'var(--ink)',
                    fontSize: 15, fontFamily: 'var(--font-sans)', outline: 'none', minWidth: 0,
                  }}
                />
                <button type="submit" disabled={submitting} className="u-btn u-btn-primary" style={{ height: 48, padding: '0 24px', fontSize: 15, borderRadius: 12, flexShrink: 0, opacity: submitting ? 0.7 : 1 }}>
                  {submitting ? '...' : (lang === 'fr' ? "S'inscrire" : 'Subscribe') + ' →'}
                </button>
              </form>
              {submitError && (
                <p style={{ marginTop: 8, fontSize: 13, color: '#E53935' }}>
                  {lang === 'fr' ? 'Une erreur est survenue, réessaie.' : 'Something went wrong, please try again.'}
                </p>
              )}
            </>
          )}
          <p style={{ marginTop: 14, fontSize: 13, color: 'var(--gray-3)' }}>
            {lang === 'fr' ? 'Gratuit · Désinscription en 1 clic' : 'Free · Unsubscribe anytime'}
          </p>
        </div>
      </section>

      {/* Issues list from RSS */}
      <section style={{ paddingTop: 72, paddingBottom: 100 }}>
        <div className="u-container" style={{ maxWidth: 720 }}>
          <h2 style={{ fontSize: 28, marginBottom: 32 }}>
            {lang === 'fr' ? 'Dernières éditions' : 'Recent issues'}
          </h2>

          {loading && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
              {[1,2,3,4].map(i => (
                <div key={i} style={{ padding: '20px 0', borderBottom: '1px solid var(--line)', display: 'flex', gap: 16, alignItems: 'center' }}>
                  <div style={{ flex: 1, height: 14, background: 'var(--line)', borderRadius: 6, animation: 'shimmer 1.4s ease-in-out infinite' }}></div>
                  <div style={{ width: 80, height: 14, background: 'var(--line)', borderRadius: 6, animation: 'shimmer 1.4s ease-in-out infinite' }}></div>
                </div>
              ))}
            </div>
          )}

          {!loading && fetchError && (
            <p style={{ color: 'var(--gray-3)', fontSize: 14 }}>
              {lang === 'fr' ? 'Impossible de charger les éditions pour l\'instant.' : 'Could not load issues right now.'}
            </p>
          )}

          {!loading && !fetchError && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
              {issues.map((iss, i) => (
                <a
                  key={i}
                  href={iss.link}
                  target="_blank"
                  rel="noopener noreferrer"
                  style={{
                    display: 'flex', alignItems: 'center', gap: 20,
                    padding: '22px 0',
                    borderBottom: '1px solid var(--line)',
                    textDecoration: 'none',
                    transition: 'background 0.15s',
                  }}
                  onMouseEnter={e => e.currentTarget.style.background = 'transparent'}
                >
                  <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--gray-2)', minWidth: 28, userSelect: 'none' }}>
                    {String(issues.length - i).padStart(2, '0')}
                  </span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <p style={{ fontSize: 16, fontWeight: 600, color: 'var(--ink)', marginBottom: 4, lineHeight: 1.4 }}>{iss.title}</p>
                    {iss.description && (
                      <p style={{ fontSize: 13, color: 'var(--gray-4)', lineHeight: 1.5, marginBottom: 4, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{iss.description}</p>
                    )}
                    <p style={{ fontSize: 12, color: 'var(--gray-3)', fontFamily: 'var(--font-mono)' }}>{iss.date}</p>
                  </div>
                  <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="var(--gray-2)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}>
                    <path d="M3 8h10M9 4l4 4-4 4"/>
                  </svg>
                </a>
              ))}
            </div>
          )}

          <div style={{ marginTop: 56, textAlign: 'center' }}>
            <a
              href="#"
              onClick={(e) => { e.preventDefault(); window.location.hash = ''; window.scrollTo({ top: 0, behavior: 'auto' }); }}
              className="u-btn u-btn-ghost"
              style={{ padding: '12px 24px', fontSize: 14 }}
            >
              ← {lang === 'fr' ? 'Retour à l\'accueil' : 'Back to home'}
            </a>
          </div>
        </div>
      </section>

      <CtaFinal lang={lang} />
    </>
  );
};

window.NewsletterPage = NewsletterPage;

// ----------------- Legal pages (Mentions légales · Politique de confidentialité)
const LegalLayout = ({ lang, eyebrow, title, updated, sections }) => (
  <>
    <section style={{ paddingTop: 100, paddingBottom: 48, borderBottom: '1px solid var(--line)' }}>
      <div className="u-container" style={{ maxWidth: 760 }}>
        <span className="u-chip u-chip-accent" style={{ marginBottom: 22 }}>
          <span className="u-dot" style={{ background: 'var(--ink)' }}></span>
          {eyebrow}
        </span>
        <h1 style={{ fontSize: 'clamp(34px, 5.5vw, 56px)', lineHeight: 1.05, letterSpacing: '-0.03em', marginBottom: updated ? 16 : 0 }}>
          {title}
        </h1>
        {updated && (
          <p style={{ fontSize: 14, color: 'var(--gray-3)', fontFamily: 'var(--font-mono)' }}>{updated}</p>
        )}
      </div>
    </section>

    <section style={{ paddingTop: 56, paddingBottom: 80 }}>
      <div className="u-container" style={{ maxWidth: 760 }}>
        {sections.map((s, i) => (
          <div key={i} style={{ marginBottom: 40 }}>
            <h2 style={{ fontSize: 22, fontWeight: 600, marginBottom: 14, letterSpacing: '-0.01em' }}>{s.h}</h2>
            {s.blocks.map((b, j) => Array.isArray(b) ? (
              <ul key={j} style={{ margin: '0 0 14px', paddingLeft: 20, color: 'var(--gray-4)', fontSize: 15.5, lineHeight: 1.7 }}>
                {b.map((li, k) => <li key={k} style={{ marginBottom: 7 }}>{li}</li>)}
              </ul>
            ) : (
              <p key={j} style={{ fontSize: 15.5, color: 'var(--gray-4)', lineHeight: 1.75, marginBottom: 12, whiteSpace: 'pre-line' }}>{b}</p>
            ))}
          </div>
        ))}

        <div style={{ marginTop: 24 }}>
          <a
            href="#"
            onClick={(e) => { e.preventDefault(); window.location.hash = ''; window.scrollTo({ top: 0, behavior: 'auto' }); }}
            className="u-btn u-btn-ghost"
            style={{ padding: '12px 24px', fontSize: 14 }}
          >
            ← {lang === 'fr' ? 'Retour à l\'accueil' : 'Back to home'}
          </a>
        </div>
      </div>
    </section>

    <CtaFinal lang={lang} />
  </>
);

const LegalNoticePage = ({ lang }) => (
  <LegalLayout
    lang={lang}
    eyebrow={lang === 'fr' ? 'Informations légales' : 'Legal'}
    title="Mentions légales"
    sections={[
      { h: "Éditeur du site", blocks: [
        "Le présent site est édité par :",
        "Monsieur Antoine Guiné\nSIREN : 882 986 391\nAdresse : 229 BURIN, 56130 SAINT-DOLAY, France\nTéléphone : –\nEmail : antoineguine.exeed@gmail.com"
      ]},
      { h: "Directeur de la publication", blocks: [
        "Monsieur Antoine Guiné"
      ]},
      { h: "Propriété intellectuelle", blocks: [
        "Tous les éléments présents sur le site (textes, images, vidéos, graphismes, logo, etc.) sont la propriété exclusive de l’éditeur, sauf mention contraire. Toute reproduction, diffusion ou modification est interdite sans autorisation préalable."
      ]},
      { h: "Hébergement", blocks: [
        "Le site est hébergé par : Framer B.V.\nSingel 258, 1016 AB Amsterdam, Pays-Bas",
        "Les données sont hébergées sur les serveurs d’Amazon Web Services (AWS), situés aux États-Unis. Framer applique un chiffrement AES 256, une transmission sécurisée via TLS, et est conforme aux normes ISO 27001, SOC 2 et aux clauses contractuelles types de la Commission européenne."
      ]},
      { h: "Responsabilité", blocks: [
        "L’éditeur met en œuvre les moyens nécessaires pour assurer l’exactitude des informations publiées sur le site. Cependant, il ne saurait être tenu responsable des éventuelles erreurs, omissions ou indisponibilités temporaires.\nLes liens externes présents sur le site n’engagent pas la responsabilité de l’éditeur."
      ]},
      { h: "Droit applicable", blocks: [
        "Le présent site est soumis au droit français. En cas de litige, les tribunaux compétents seront ceux du ressort de Vannes."
      ]}
    ]}
  />
);

const PrivacyPolicyPage = ({ lang }) => (
  <LegalLayout
    lang={lang}
    eyebrow={lang === 'fr' ? 'Vie privée' : 'Privacy'}
    title="Politique de confidentialité"
    updated="Dernière mise à jour : 03 Juillet 2025"
    sections={[
      { h: "Responsable du traitement", blocks: [
        "Monsieur Antoine Guiné\nSIREN : 882 986 391\n229 BURIN, 56130 SAINT-DOLAY, France"
      ]},
      { h: "Données collectées", blocks: [
        "Les données suivantes peuvent être collectées :",
        [
          "Adresse e-mail, uniquement si vous la communiquez via un formulaire",
          "Aucune donnée sensible ou indirecte n’est collectée",
          "Aucun cookie de suivi, publicitaire ou analytique n’est utilisé"
        ]
      ]},
      { h: "Utilisation des données", blocks: [
        "Les données sont utilisées uniquement pour :",
        [
          "Vous répondre suite à une demande",
          "Vous envoyer des communications si vous avez donné votre consentement"
        ]
      ]},
      { h: "Base légale du traitement", blocks: [
        "Le traitement repose sur votre consentement explicite. Ce consentement peut être retiré à tout moment."
      ]},
      { h: "Durée de conservation", blocks: [
        "Les données sont conservées jusqu’à 12 mois après la dernière interaction ou supprimées sur simple demande."
      ]},
      { h: "Sécurité", blocks: [
        "Les données sont hébergées par Framer (via AWS) avec les mesures de sécurité suivantes :",
        [
          "Chiffrement AES 256 des données au repos",
          "Chiffrement TLS pour les données en transit",
          "Conformité aux normes ISO 27001 et SOC 2"
        ]
      ]},
      { h: "Destinataires", blocks: [
        "Les données sont exclusivement traitées par Monsieur Antoine Guiné. Elles ne sont ni cédées, ni vendues à des tiers."
      ]},
      { h: "Droits des utilisateurs", blocks: [
        "Conformément au RGPD, vous disposez des droits suivants :",
        [
          "Accès à vos données",
          "Rectification ou suppression",
          "Opposition ou limitation du traitement",
          "Portabilité des données",
          "Retrait du consentement",
          "Réclamation auprès de la CNIL"
        ]
      ]},
      { h: "Exercice des droits", blocks: [
        "Vous pouvez exercer vos droits par courrier à l’adresse indiquée ci-dessus."
      ]},
      { h: "Modifications", blocks: [
        "Cette politique peut être modifiée à tout moment. La version la plus récente est toujours disponible sur ce site."
      ]}
    ]}
  />
);

window.LegalNoticePage = LegalNoticePage;
window.PrivacyPolicyPage = PrivacyPolicyPage;
