// blog.jsx — Apple-style horizontal carousel + modal
// Tailwind CSS for all blog-specific styles.

// ── Palette per category ─────────────────────────────────────────
const BLOG_PALETTE = {
  'Confidentialité': { bg: '#1d3a8a', fg: '#fafaf7', accent: '#d97706', accent2: 'rgba(217,119,6,0.18)' },
  'NAS & sync':      { bg: '#0e1624', fg: '#fafaf7', accent: '#7aa3ff', accent2: 'rgba(122,163,255,0.15)' },
  'Hors-ligne':      { bg: '#111318', fg: '#fafaf7', accent: '#7aa3ff', accent2: 'rgba(122,163,255,0.12)' },
  'Anticipation':    { bg: '#eef2ff', fg: '#1a1a1a', accent: '#1d3a8a', accent2: 'rgba(29,58,138,0.1)' },
  'Récits':          { bg: '#fdf6ec', fg: '#1a1a1a', accent: '#d97706', accent2: 'rgba(217,119,6,0.12)' },
  'Pratique':        { bg: '#f0f4ff', fg: '#1a1a1a', accent: '#1d3a8a', accent2: 'rgba(29,58,138,0.08)' },
};

// ── SVG illustrations — one per article, themed & pertinent ──────
function ArticleIllustration({ slug, palette }) {
  const { fg, accent, accent2, bg } = palette;
  const dark = bg.startsWith('#0') || bg.startsWith('#1');

  const ill = {
    // Shield with lock — data privacy
    'donnees-budget-hors-cloud': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Shield */}
        <path d="M80 22 L112 36 L112 68 C112 90 80 110 80 110 C80 110 48 90 48 68 L48 36 Z"
          stroke={accent} strokeWidth="2.5" fill={dark ? 'rgba(255,255,255,0.04)' : 'rgba(29,58,138,0.06)'}/>
        {/* Lock body */}
        <rect x="67" y="64" width="26" height="22" rx="4" stroke={fg} strokeWidth="2" fill="none" opacity="0.9"/>
        {/* Lock shackle */}
        <path d="M71 64 V58 A9 9 0 0 1 89 58 V64" stroke={fg} strokeWidth="2" fill="none" opacity="0.9"/>
        {/* Keyhole */}
        <circle cx="80" cy="73" r="3" fill={accent}/>
        <rect x="78.5" y="74.5" width="3" height="6" rx="1.5" fill={accent}/>
      </svg>
    ),
    // NAS tower with signals
    'synology-ds224-guide': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* NAS body */}
        <rect x="54" y="30" width="52" height="72" rx="6" stroke={accent} strokeWidth="2.5"
          fill={dark ? 'rgba(255,255,255,0.04)' : 'rgba(29,58,138,0.06)'}/>
        {/* Drive bays */}
        {[0,1,2,3].map(i => (
          <rect key={i} x="62" y={42 + i * 14} width="36" height="9" rx="2.5"
            stroke={fg} strokeWidth="1.5" fill="none" opacity={0.7 - i*0.1}/>
        ))}
        {/* Activity LEDs */}
        {[0,1].map(i => (
          <circle key={i} cx={68 + i*6} cy="106" r="2.5" fill={i===0 ? accent : fg} opacity="0.9"/>
        ))}
        {/* Wifi arcs */}
        <path d="M104 52 Q116 52 116 68" stroke={accent} strokeWidth="2" fill="none" opacity="0.6" strokeLinecap="round"/>
        <path d="M104 45 Q124 45 124 68" stroke={accent} strokeWidth="1.5" fill="none" opacity="0.35" strokeLinecap="round"/>
      </svg>
    ),
    // Phone with offline badge
    'offline-first-promesse': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Phone */}
        <rect x="56" y="24" width="48" height="84" rx="9" stroke={accent} strokeWidth="2.5"
          fill={dark ? 'rgba(255,255,255,0.04)' : 'rgba(29,58,138,0.06)'}/>
        {/* Screen */}
        <rect x="62" y="34" width="36" height="58" rx="4" fill={dark ? 'rgba(255,255,255,0.06)' : 'rgba(29,58,138,0.07)'}/>
        {/* Home bar */}
        <rect x="72" y="100" width="16" height="3" rx="1.5" fill={fg} opacity="0.5"/>
        {/* Wifi crossed */}
        <path d="M72 62 Q80 54 88 62" stroke={fg} strokeWidth="2" fill="none" opacity="0.5" strokeLinecap="round"/>
        <path d="M68 57 Q80 46 92 57" stroke={fg} strokeWidth="1.8" fill="none" opacity="0.3" strokeLinecap="round"/>
        <line x1="68" y1="48" x2="92" y2="72" stroke={accent} strokeWidth="2.2" strokeLinecap="round"/>
        {/* Check badge */}
        <circle cx="104" cy="100" r="13" fill={accent}/>
        <path d="M98 100 L102 104 L110 96" stroke="#fff" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    ),
    // Calendar with trend line
    'decouvert-defaut-information': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Card */}
        <rect x="34" y="34" width="92" height="72" rx="8" stroke={accent} strokeWidth="2.5"
          fill={dark ? 'rgba(255,255,255,0.04)' : 'rgba(29,58,138,0.06)'}/>
        {/* Header bar */}
        <rect x="34" y="34" width="92" height="18" rx="8" fill={accent} opacity="0.18"/>
        <rect x="34" y="44" width="92" height="8" fill={accent} opacity="0.18"/>
        {/* Calendar pins */}
        <rect x="54" y="28" width="5" height="14" rx="2.5" fill={accent}/>
        <rect x="101" y="28" width="5" height="14" rx="2.5" fill={accent}/>
        {/* Trend line going up then dipping */}
        <polyline points="46,88 60,78 74,72 88,76 102,65 116,58"
          stroke={accent} strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
        {/* Alert dot at dip */}
        <circle cx="88" cy="76" r="4.5" fill={accent}/>
        <circle cx="88" cy="76" r="8" stroke={accent} strokeWidth="1.5" opacity="0.4" fill="none"/>
      </svg>
    ),
    // Spreadsheet transforming into app
    'marc-quitte-excel': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Old doc */}
        <rect x="32" y="36" width="40" height="52" rx="5" stroke={fg} strokeWidth="2" fill="none" opacity="0.4"/>
        {[0,1,2,3].map(i => (
          <line key={i} x1="39" y1={50 + i*10} x2="65" y2={50 + i*10}
            stroke={fg} strokeWidth="1.2" opacity={0.3}/>
        ))}
        {/* Arrow */}
        <path d="M78 70 L90 70" stroke={accent} strokeWidth="2.5" strokeLinecap="round"/>
        <path d="M87 66 L91 70 L87 74" stroke={accent} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
        {/* New app screen */}
        <rect x="94" y="28" width="42" height="72" rx="8" stroke={accent} strokeWidth="2.5"
          fill={dark ? 'rgba(255,255,255,0.06)' : 'rgba(29,58,138,0.07)'}/>
        {/* Progress bars */}
        <rect x="100" y="40" width="30" height="4" rx="2" fill={accent} opacity="0.25"/>
        <rect x="100" y="40" width="22" height="4" rx="2" fill={accent} opacity="0.8"/>
        <rect x="100" y="52" width="30" height="4" rx="2" fill={accent} opacity="0.25"/>
        <rect x="100" y="52" width="28" height="4" rx="2" fill={fg} opacity="0.5"/>
        <rect x="100" y="64" width="30" height="4" rx="2" fill={accent} opacity="0.25"/>
        <rect x="100" y="64" width="14" height="4" rx="2" fill={accent} opacity="0.7"/>
        {/* Check */}
        <circle cx="115" cy="85" r="10" fill={accent} opacity="0.9"/>
        <path d="M110 85 L113.5 88.5 L120 82" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    ),
    // Eye / magnifier on data
    'ce-que-banque-sait': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Eye outline */}
        <path d="M30 70 Q55 36 80 36 Q105 36 130 70 Q105 104 80 104 Q55 104 30 70Z"
          stroke={accent} strokeWidth="2.5" fill="none"/>
        {/* Iris */}
        <circle cx="80" cy="70" r="18" stroke={accent} strokeWidth="2.5" fill={accent2}/>
        {/* Pupil */}
        <circle cx="80" cy="70" r="9" fill={accent}/>
        {/* Reflection */}
        <circle cx="85" cy="65" r="3" fill={dark ? 'rgba(255,255,255,0.5)' : 'rgba(255,255,255,0.8)'}/>
        {/* Cross-out slash */}
        <line x1="44" y1="34" x2="116" y2="106" stroke={dark ? 'rgba(255,100,80,0.7)' : 'rgba(180,50,30,0.55)'} strokeWidth="3" strokeLinecap="round"/>
      </svg>
    ),
    // Multiple NAS brands connected
    'synology-qnap-truenas-compatibilite': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Central node */}
        <circle cx="80" cy="70" r="12" fill={accent} opacity="0.9"/>
        <circle cx="80" cy="70" r="18" stroke={accent} strokeWidth="1.5" opacity="0.3" fill="none"/>
        {/* Satellite devices */}
        {[
          [80, 32], [112, 52], [112, 88], [80, 108], [48, 88], [48, 52]
        ].map(([x, y], i) => (
          <g key={i}>
            <line x1="80" y1="70" x2={x} y2={y}
              stroke={accent} strokeWidth="1.5" opacity="0.4" strokeDasharray="3 3"/>
            <rect x={x-9} y={y-7} width="18" height="14" rx="3"
              stroke={fg} strokeWidth="1.8" fill="none" opacity="0.6"/>
          </g>
        ))}
        {/* Check in center */}
        <path d="M75 70 L78.5 73.5 L85 67" stroke="#fff" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    ),
    // Phone with map pin / mountains
    'budgi-sans-reseau-patagonie': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Mountains */}
        <path d="M24 108 L52 64 L72 90 L90 52 L116 90 L136 108 Z"
          fill={accent} opacity="0.18"/>
        <path d="M24 108 L52 64 L72 90 L90 52 L116 90 L136 108"
          stroke={accent} strokeWidth="2.5" fill="none" strokeLinejoin="round" strokeLinecap="round"/>
        {/* Phone outline */}
        <rect x="62" y="20" width="36" height="60" rx="7" stroke={fg} strokeWidth="2.2"
          fill={dark ? 'rgba(0,0,0,0.35)' : 'rgba(255,255,255,0.7)'}/>
        {/* No-wifi icon */}
        <line x1="72" y1="36" x2="88" y2="52" stroke={accent} strokeWidth="2" strokeLinecap="round"/>
        <path d="M70 42 Q80 34 90 42" stroke={fg} strokeWidth="1.8" fill="none" opacity="0.4" strokeLinecap="round"/>
        {/* Battery full */}
        <rect x="70" y="60" width="20" height="10" rx="2" stroke={fg} strokeWidth="1.5" fill="none" opacity="0.7"/>
        <rect x="72" y="62" width="16" height="6" rx="1" fill={accent} opacity="0.8"/>
        <rect x="90" y="63" width="3" height="4" rx="1" fill={fg} opacity="0.5"/>
      </svg>
    ),
    // Subscriptions / recurring circles
    'recurrences-masquees-abonnements': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Refresh/loop arrow */}
        <path d="M80 36 A34 34 0 1 1 48 62" stroke={accent} strokeWidth="3" fill="none" strokeLinecap="round"/>
        <path d="M42 52 L48 62 L58 56" stroke={accent} strokeWidth="3" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
        {/* Coins dropping */}
        <circle cx="80" cy="70" r="10" stroke={fg} strokeWidth="2" fill={accent} opacity="0.85"/>
        <text x="80" y="75" textAnchor="middle" fill="#fff"
          fontSize="12" fontWeight="700" fontFamily="DM Sans, system-ui">€</text>
        {/* Small coins floating */}
        {[[54,52,7],[108,56,6],[60,96,5],[104,94,6]].map(([x,y,r],i) => (
          <circle key={i} cx={x} cy={y} r={r} fill={accent} opacity={0.35 + i*0.1}/>
        ))}
      </svg>
    ),
    // Chart going up / observation effect
    'retrouver-2400-euros': (
      <svg viewBox="0 0 160 140" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full">
        <circle cx="80" cy="70" r="52" fill={accent2}/>
        {/* Chart area */}
        <rect x="36" y="36" width="88" height="68" rx="7"
          stroke={accent} strokeWidth="2"
          fill={dark ? 'rgba(255,255,255,0.03)' : 'rgba(29,58,138,0.05)'}/>
        {/* Grid lines */}
        {[58,72,86].map(y => (
          <line key={y} x1="44" y1={y} x2="116" y2={y}
            stroke={fg} strokeWidth="0.8" opacity="0.15"/>
        ))}
        {/* Bars going up */}
        {[[50,88,20,'0.5'],[64,78,30,'0.6'],[78,64,44,'0.8'],[92,52,56,'0.9'],[106,42,62,'1']].map(([x,y,h,op], i) => (
          <rect key={i} x={x} y={y} width="12" height={h} rx="3"
            fill={accent} opacity={op}/>
        ))}
        {/* Trend arrow */}
        <path d="M48 88 L112 44" stroke={accent} strokeWidth="2" strokeDasharray="4 3" opacity="0.6"/>
        <path d="M107 40 L113 44 L109 50" stroke={accent} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    ),
  };

  return (
    <div className="w-full h-full flex items-center justify-center p-6">
      {ill[slug] || (
        // Fallback — simple abstract shape
        <svg viewBox="0 0 160 140" fill="none" className="w-full h-full">
          <circle cx="80" cy="70" r="52" fill={accent2}/>
          <circle cx="80" cy="70" r="28" stroke={accent} strokeWidth="2.5" fill="none"/>
          <circle cx="80" cy="70" r="10" fill={accent} opacity="0.8"/>
        </svg>
      )}
    </div>
  );
}

// ── Individual carousel card ──────────────────────────────────────
function BlogCarouselCard({ post, onOpen }) {
  const palette = BLOG_PALETTE[post.category] || BLOG_PALETTE['Anticipation'];

  return (
    // No overflow-hidden on article — lets scale breathe without clipping.
    // overflow-hidden only on inner zones (illustration, text).
    <article
      style={{
        position: 'relative',
        flexShrink: 0,
        width: 'clamp(280px, 26vw, 320px)',
        background: 'var(--paper)',
        borderRadius: 20,
        boxShadow: '0 2px 12px rgba(0,0,0,0.07)',
        cursor: 'pointer',
        // Scale the whole card — no clipping because no overflow:hidden on article
        transition: 'transform 0.45s cubic-bezier(.2,.8,.2,1), box-shadow 0.45s ease',
        transformOrigin: 'center center',
      }}
      onClick={() => onOpen(post)}
      onMouseEnter={e => {
        e.currentTarget.style.transform = 'scale(1.04)';
        e.currentTarget.style.boxShadow = '0 16px 48px rgba(0,0,0,0.14)';
      }}
      onMouseLeave={e => {
        e.currentTarget.style.transform = 'scale(1)';
        e.currentTarget.style.boxShadow = '0 2px 12px rgba(0,0,0,0.07)';
      }}
    >
      {/* Illustration zone — rounded top corners, overflow hidden only here */}
      <div
        style={{
          height: 'clamp(220px, 24vw, 290px)',
          background: palette.bg,
          borderRadius: '20px 20px 0 0',
          overflow: 'hidden',
          position: 'relative',
        }}
      >
        <ArticleIllustration slug={post.slug} palette={palette} />
      </div>

      {/* Text — rounded bottom corners */}
      <div style={{
        padding: '18px 20px 20px',
        display: 'flex', flexDirection: 'column', gap: 8,
        borderRadius: '0 0 20px 20px',
        background: 'var(--paper)',
        overflow: 'hidden',
      }}>
        <div className="text-[10px] font-semibold tracking-[0.16em] uppercase"
          style={{ color: palette.accent }}>
          {post.category}
        </div>
        <h3
          className="text-[16px] leading-snug text-ink line-clamp-2"
          style={{ fontFamily: 'Fraunces, Georgia, serif', fontWeight: 400, letterSpacing: '-0.015em' }}
        >
          {post.title}
        </h3>
        <p className="text-[13px] leading-relaxed text-ink/50 line-clamp-2 mt-0.5">
          {post.excerpt}
        </p>
        <div className="flex items-center gap-2 mt-1 text-[11px] text-ink/40">
          <span>{post.date}</span>
          <span className="w-1 h-1 rounded-full bg-current opacity-60" />
          <span>{post.readTime}</span>
        </div>
      </div>

      {/* [+] button */}
      <button
        onClick={(e) => { e.stopPropagation(); onOpen(post); }}
        className="absolute bottom-4 right-4 w-7 h-7 rounded-full
                   bg-black/6 hover:bg-navy hover:text-white text-ink/40
                   flex items-center justify-center text-[18px] font-light leading-none
                   transition-all duration-200"
        aria-label={`Ouvrir ${post.title}`}
      >
        +
      </button>
    </article>
  );
}

// ── Modal ─────────────────────────────────────────────────────────
function BlogModal({ post, onClose }) {
  const [visible, setVisible] = React.useState(false);
  const palette = BLOG_PALETTE[post.category] || BLOG_PALETTE['Anticipation'];
  const href = `../blog/${post.slug}.html`;

  React.useEffect(() => {
    const t = requestAnimationFrame(() => setVisible(true));
    return () => cancelAnimationFrame(t);
  }, []);

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') handleClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = ''; };
  }, []);

  const handleClose = () => {
    setVisible(false);
    setTimeout(onClose, 260);
  };

  return (
    <div
      onClick={handleClose}
      className="fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-10"
      style={{
        background: 'rgba(0,0,0,0.42)',
        backdropFilter: `blur(${visible ? '22px' : '0px'})`,
        WebkitBackdropFilter: `blur(${visible ? '22px' : '0px'})`,
        opacity: visible ? 1 : 0,
        transition: 'opacity 0.26s ease, backdrop-filter 0.26s ease',
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        className="relative bg-white rounded-4xl overflow-hidden w-full max-w-lg
                   max-h-[86vh] flex flex-col shadow-2xl"
        style={{
          transform: visible ? 'scale(1) translateY(0)' : 'scale(0.93) translateY(28px)',
          opacity: visible ? 1 : 0,
          transition: 'transform 0.34s cubic-bezier(.2,.8,.2,1), opacity 0.26s ease',
        }}
      >
        {/* Illustration banner */}
        <div className="relative h-32 flex-shrink-0" style={{ background: palette.bg }}>
          <ArticleIllustration slug={post.slug} palette={palette} />
        </div>

        {/* Content */}
        <div className="overflow-y-auto px-7 pt-5 pb-7 flex flex-col gap-3">
          <div className="flex items-center gap-2 text-[11px] text-ink/40">
            <span style={{ color: palette.accent, fontWeight: 600, fontSize: 10,
              letterSpacing: '0.14em', textTransform: 'uppercase' }}>
              {post.category}
            </span>
            <span className="w-1 h-1 rounded-full bg-current opacity-50" />
            <span>{post.date}</span>
            <span className="w-1 h-1 rounded-full bg-current opacity-50" />
            <span>{post.readTime} de lecture</span>
          </div>

          <h2
            className="text-[20px] leading-snug text-ink"
            style={{ fontFamily: 'Fraunces, Georgia, serif', fontWeight: 400, letterSpacing: '-0.016em' }}
          >
            {post.title}
          </h2>

          <p className="text-[14.5px] leading-relaxed text-ink/60 border-l-2 pl-4"
            style={{ borderColor: palette.accent + '55' }}>
            {post.excerpt}
          </p>

          <a
            href={href}
            className="mt-3 inline-flex items-center gap-2 text-white text-[13px] font-medium
                       px-5 py-2.5 rounded-full self-start transition-opacity duration-200 hover:opacity-85"
            style={{ background: palette.accent === '#7aa3ff' ? '#1d3a8a' : palette.accent }}
          >
            Lire l'article complet
            <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
              <path d="M2 6h8M7 2.5l3.5 3.5L7 9.5"
                stroke="currentColor" strokeWidth="1.6"
                strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
          </a>
        </div>

        {/* Close × */}
        <button
          onClick={handleClose}
          className="absolute top-3.5 right-3.5 w-8 h-8 rounded-full
                     bg-black/18 hover:bg-black/32 text-white
                     flex items-center justify-center transition-colors duration-150"
          aria-label="Fermer"
        >
          <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
            <path d="M1 1l8 8M9 1l-8 8" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/>
          </svg>
        </button>
      </div>
    </div>
  );
}

// ── Blog section ─────────────────────────────────────────────────
function Blog() {
  const cats     = window.BG_DATA.BLOG_CATEGORIES;
  const allPosts = window.BG_DATA.BLOG_POSTS;

  const [filter,   setFilter]   = React.useState('Tous');
  const [openPost, setOpenPost] = React.useState(null);
  const scrollRef = React.useRef(null);
  const pillsRef  = React.useRef(null);
  // CSS value matching exactly what .container does — no JS needed for default.
  // On very wide screens: (100vw - 1240px)/2 + pad-x. On narrow: pad-x.
  const [leftPad, setLeftPad] = React.useState('max(var(--pad-x), calc((100vw - var(--maxw)) / 2 + var(--pad-x)))');

  const posts = filter === 'Tous'
    ? allPosts
    : allPosts.filter(p => p.category === filter);

  // Once rendered, measure the actual pixel value from the pills and lock it in.
  // This guarantees pixel-perfect alignment even if CSS variables differ.
  React.useEffect(() => {
    const measure = () => {
      if (!pillsRef.current) return;
      const rect = pillsRef.current.getBoundingClientRect();
      if (rect.left > 0) setLeftPad(Math.round(rect.left));
    };
    const t1 = requestAnimationFrame(measure);
    const t2 = setTimeout(measure, 200);
    window.addEventListener('resize', () => {
      // On resize go back to CSS formula first, then re-measure
      setLeftPad('max(var(--pad-x), calc((100vw - var(--maxw)) / 2 + var(--pad-x)))');
      setTimeout(measure, 100);
    });
    return () => { cancelAnimationFrame(t1); clearTimeout(t2); };
  }, []);

  const scroll = (dir) => {
    const el = scrollRef.current;
    if (!el) return;
    const card = el.querySelector('article');
    const cardW = card ? card.offsetWidth + 20 : 320;
    el.scrollBy({ left: dir * cardW, behavior: 'smooth' });
  };

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollLeft = 0;
  }, [filter]);

  const ArrowBtn = ({ dir, d }) => (
    <button
      onClick={() => scroll(dir)}
      style={{
        width: 36, height: 36, borderRadius: '50%',
        border: '1.5px solid var(--ink-line)',
        background: 'var(--paper)', cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        transition: 'background .2s, border-color .2s, color .2s',
        color: 'var(--ink-2)', flexShrink: 0,
      }}
      onMouseEnter={e => {
        e.currentTarget.style.background = 'var(--ink)';
        e.currentTarget.style.borderColor = 'var(--ink)';
        e.currentTarget.style.color = 'var(--paper)';
      }}
      onMouseLeave={e => {
        e.currentTarget.style.background = 'var(--paper)';
        e.currentTarget.style.borderColor = 'var(--ink-line)';
        e.currentTarget.style.color = 'var(--ink-2)';
      }}
    >
      <svg width="13" height="13" viewBox="0 0 14 14" fill="none">
        <path d={d} stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    </button>
  );

  return (
    <section id="blog" style={{
      padding: 'clamp(80px,10vw,130px) 0',
      background: 'var(--paper)',
      borderTop: '1px solid var(--ink-line-soft)',
    }}>

      {/* ── Header — standard container ── */}
      <div className="container">
        <div className="reveal" style={{ marginBottom: 6 }}>
          <span className="eyebrow"><span className="dot" />Le journal</span>
        </div>
        <h2 className="h-section reveal delay-1" style={{ margin: '14px 0 24px' }}>
          Lectures pour <em>esprits posés.</em>
        </h2>

        {/* Pills — ref here: no transforms, exact content-left position */}
        <div ref={pillsRef} style={{
          display: 'flex', flexWrap: 'wrap', gap: 8, marginBottom: 32,
        }}>
          {cats.map(c => {
            const active = c === filter;
            return (
              <button key={c} onClick={() => setFilter(c)} style={{
                padding: '7px 16px', borderRadius: 999,
                border: `1.5px solid ${active ? 'var(--ink)' : 'var(--ink-line)'}`,
                background: active ? 'var(--ink)' : 'transparent',
                color: active ? 'var(--paper)' : 'var(--ink-2)',
                fontFamily: 'var(--sans)', fontWeight: 500, fontSize: 13,
                cursor: 'pointer', transition: 'all .2s ease',
              }}>
                {c}
              </button>
            );
          })}
        </div>
      </div>

      {/* ── Carousel ─────────────────────────────────────────────
          overflowX:clip on outer → hides scrollbar & right overflow
          overflowY:visible on both → cards scale without being clipped
          paddingLeft = leftPad (measured from pills left edge above)   */}
      <div style={{ overflowX: 'clip', overflowY: 'visible' }}>
        <div
          ref={scrollRef}
          style={{
            display: 'flex',
            gap: 20,
            overflowX: 'auto',
            overflowY: 'visible',
            paddingTop: 20,
            paddingBottom: 28,
            paddingLeft:  leftPad,
            paddingRight: leftPad,
            scrollSnapType: 'none',
            scrollbarWidth: 'none',
            WebkitOverflowScrolling: 'touch',
          }}
        >
          {posts.map(post => (
            <BlogCarouselCard key={post.id} post={post} onOpen={setOpenPost} />
          ))}
          <div style={{ flexShrink: 0, width: 4 }} />
        </div>
      </div>

      {/* ── Arrows — bottom right, Apple style ── */}
      <div className="container" style={{ marginTop: 16 }}>
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
          <ArrowBtn dir={-1} d="M9 2L4 7l5 5" />
          <ArrowBtn dir={1}  d="M5 2l5 5-5 5" />
        </div>
      </div>

      {openPost && <BlogModal post={openPost} onClose={() => setOpenPost(null)} />}

      <style>{`
        #blog div[style*="overflow-x: auto"]::-webkit-scrollbar,
        #blog div[style*="overflow-x:auto"]::-webkit-scrollbar { display: none; }
      `}</style>
    </section>
  );
}

Object.assign(window, { Blog });
