/* lawandeconomics.ch — landing v2 */
const { useState, useEffect, useRef, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "paper": "#ffffff",
  "gutter": "#ffffff",
  "plusDensity": 8,
  "plusOpacity": 0.08,
  "ink": "#1a1a1f",
  "accent": "#4a4fb5",
  "titleFont": "Fraunces",
  "labelFont": "Inter",
  "lineColor": "#e8e8eb",
  "categoryStrip": "#fafafa",
  "palette": ["#e85d5d","#d4a23a","#6fa97c","#6a8fd9","#a07a55","#8b6fb8"],
  "titleAccentWord": "facilement",
  "showCardArt": true,
  "cardGap": 18,
  "outerPadding": 24
}/*EDITMODE-END*/;

const DARK_OVERRIDES = {
  paper:         "#0e0e12",
  gutter:        "#09090c",
  ink:           "#dddde8",
  accent:        "#8287e2",
  lineColor:     "#242430",
  categoryStrip: "#13131a",
};

/* Banknote palettes */
const PALETTES = {
  pastel:  ["#ec8a8a","#e0bd6c","#9bc7a6","#9cb8e0","#bd9c7e","#b7a3d3"],
  banknote:["#e85d5d","#d4a23a","#6fa97c","#6a8fd9","#a07a55","#8b6fb8"],
  vivid:   ["#d83838","#d18a18","#3a8f55","#3963c4","#8a5a2b","#6a48a8"],
  mono:    ["#444","#666","#555","#3a3a3a","#5a5a5a","#4a4a4a"],
};
const CAT_KEYS = ["Fiscalité","International","Économie","Politiques","Droit","Arbitrage"];

/* ============ Plus pattern ============ */
function PlusPattern({ density, opacity, color }) {
  const id = `plus-${density}-${opacity}`;
  return (
    <svg width="100%" height="100%" style={{ display: "block", opacity }}>
      <defs>
        <pattern id={id} width={density} height={density} patternUnits="userSpaceOnUse">
          <path
            d={`M ${density / 2} ${density / 2 - 1.5} L ${density / 2} ${density / 2 + 1.5} M ${density / 2 - 1.5} ${density / 2} L ${density / 2 + 1.5} ${density / 2}`}
            stroke={color}
            strokeWidth="0.55"
            strokeLinecap="round"
          />
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill={`url(#${id})`} />
    </svg>
  );
}

/* ============ Engraving art for cards ============ */
function EngravingArt({ variant, color }) {
  const c = color;
  const uid = `${variant}${color.replace("#", "")}`;
  if (variant === 0) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        <defs>
          <clipPath id={`cp${uid}a`}><rect x="15" y="10" width="110" height="105" /></clipPath>
          <clipPath id={`cp${uid}b`}><rect x="135" y="65" width="110" height="105" /></clipPath>
        </defs>
        <g clipPath={`url(#cp${uid}a)`}>
          {Array.from({length:36}, (_,i) => <line key={i} x1={-5+i*4.5} y1={10} x2={-35+i*4.5} y2={115} stroke={c} strokeWidth="0.4" opacity="0.5" />)}
        </g>
        <g clipPath={`url(#cp${uid}b)`}>
          {Array.from({length:36}, (_,i) => <line key={i} x1={125+i*4.5} y1={65} x2={95+i*4.5} y2={170} stroke={c} strokeWidth="0.4" opacity="0.38" />)}
        </g>
        <rect x="15" y="10" width="110" height="105" fill="none" stroke={c} strokeWidth="0.85" opacity="0.9" />
        <rect x="135" y="65" width="110" height="105" fill="none" stroke={c} strokeWidth="0.85" opacity="0.9" />
      </svg>
    );
  }
  if (variant === 1) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        {Array.from({length:8}, (_,i) => (
          <circle key={i} cx="90" cy="95" r={(i+1)*10} fill="none" stroke={c} strokeWidth="0.45" opacity={0.9-i*0.09} />
        ))}
        {Array.from({length:14}, (_,i) => {
          const a = (i/14)*Math.PI*2;
          return <line key={i} x1={90+Math.cos(a)*82} y1={95+Math.sin(a)*82} x2={90+Math.cos(a)*110} y2={95+Math.sin(a)*110} stroke={c} strokeWidth="0.55" opacity="0.6" />;
        })}
        <circle cx="90" cy="95" r="5" fill={c} opacity="0.85" />
      </svg>
    );
  }
  if (variant === 2) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        {Array.from({length:16}, (_,i) => [
          <line key={`a${i}`} x1={30+i*3} y1={90} x2={100+i*3} y2={28} stroke={c} strokeWidth="0.38" opacity={0.22+i*0.025} />,
          <line key={`b${i}`} x1={30+i*3} y1={90} x2={100+i*3} y2={152} stroke={c} strokeWidth="0.38" opacity={0.22+i*0.025} />
        ])}
        <path d="M 30 90 L 200 28" stroke={c} strokeWidth="1.1" fill="none" opacity="0.88" />
        <path d="M 30 90 L 200 152" stroke={c} strokeWidth="1.1" fill="none" opacity="0.88" />
        <circle cx="30" cy="90" r="4.5" fill={c} opacity="0.8" />
        <circle cx="200" cy="28" r="3" fill="none" stroke={c} strokeWidth="0.9" opacity="0.75" />
        <circle cx="200" cy="152" r="3" fill="none" stroke={c} strokeWidth="0.9" opacity="0.75" />
      </svg>
    );
  }
  if (variant === 3) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        {Array.from({length:10}, (_,i) => <line key={`l${i}`} x1={54+i*4} y1={102} x2={54+i*4} y2={120} stroke={c} strokeWidth="0.35" opacity="0.45" />)}
        {Array.from({length:10}, (_,i) => <line key={`r${i}`} x1={166+i*4} y1={102} x2={166+i*4} y2={120} stroke={c} strokeWidth="0.35" opacity="0.45" />)}
        <line x1="130" y1="20" x2="130" y2="160" stroke={c} strokeWidth="0.7" opacity="0.7" />
        <line x1="55" y1="60" x2="205" y2="60" stroke={c} strokeWidth="0.8" opacity="0.8" />
        <line x1="55" y1="60" x2="72" y2="100" stroke={c} strokeWidth="0.65" opacity="0.7" />
        <line x1="205" y1="60" x2="188" y2="100" stroke={c} strokeWidth="0.65" opacity="0.7" />
        <rect x="52" y="100" width="44" height="22" fill="none" stroke={c} strokeWidth="0.65" opacity="0.75" />
        <rect x="164" y="100" width="44" height="22" fill="none" stroke={c} strokeWidth="0.65" opacity="0.75" />
        <circle cx="130" cy="22" r="4.5" fill={c} opacity="0.75" />
      </svg>
    );
  }
  if (variant === 4) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        {Array.from({length:6}, (_,i) => (
          <rect key={i} x={18+i*17} y={12+i*12} width={224-i*34} height={156-i*24} fill="none" stroke={c} strokeWidth="0.5" opacity={0.85-i*0.1} />
        ))}
        <circle cx="130" cy="90" r="18" fill="none" stroke={c} strokeWidth="0.8" opacity="0.88" />
        <circle cx="130" cy="90" r="5" fill={c} opacity="0.82" />
      </svg>
    );
  }
  if (variant === 5) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        <ellipse cx="130" cy="90" rx="95" ry="78" fill="none" stroke={c} strokeWidth="0.85" opacity="0.88" />
        {[-70,-35,0,35,70].map((shift, i) => {
          const ry2 = Math.sqrt(Math.max(1, 78*78 - shift*shift));
          return <ellipse key={i} cx="130" cy={90+shift} rx={ry2*95/78} ry={Math.max(2,ry2*0.18)} fill="none" stroke={c} strokeWidth="0.42" opacity="0.48" />;
        })}
        {[0,1,2,3,4].map(i => (
          <ellipse key={i} cx="130" cy="90" rx={Math.max(1, Math.sin((i/5)*Math.PI)*95)} ry="78" fill="none" stroke={c} strokeWidth="0.42" opacity="0.45" />
        ))}
      </svg>
    );
  }
  if (variant === 6) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        <defs>
          <clipPath id={`cp${uid}a`}><circle cx="95" cy="90" r="68" /></clipPath>
          <clipPath id={`cp${uid}b`}><circle cx="165" cy="90" r="68" /></clipPath>
        </defs>
        <g clipPath={`url(#cp${uid}a)`}>
          {Array.from({length:32}, (_,i) => <line key={i} x1={15+i*4.5} y1={20} x2={-5+i*4.5} y2={160} stroke={c} strokeWidth="0.38" opacity="0.45" />)}
        </g>
        <g clipPath={`url(#cp${uid}b)`}>
          {Array.from({length:32}, (_,i) => <line key={i} x1={95+i*4.5} y1={20} x2={75+i*4.5} y2={160} stroke={c} strokeWidth="0.38" opacity="0.35" />)}
        </g>
        <circle cx="95" cy="90" r="68" fill="none" stroke={c} strokeWidth="0.88" opacity="0.88" />
        <circle cx="165" cy="90" r="68" fill="none" stroke={c} strokeWidth="0.88" opacity="0.88" />
      </svg>
    );
  }
  if (variant === 7) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        {Array.from({length:20}, (_,i) => (
          <line key={i} x1={130-(18+i*11)/2} y1={18+i*8} x2={130+(18+i*11)/2} y2={18+i*8} stroke={c} strokeWidth="0.5" opacity={0.28+(i/19)*0.55} />
        ))}
        <path d="M 130 12 L 248 175 L 12 175 Z" fill="none" stroke={c} strokeWidth="1" opacity="0.88" />
        <circle cx="130" cy="16" r="4.5" fill={c} opacity="0.78" />
      </svg>
    );
  }
  if (variant === 8) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        <path d="M 20 165 Q 130 10 240 165" fill="none" stroke={c} strokeWidth="1.1" opacity="0.9" />
        {Array.from({length:5}, (_,i) => (
          <path key={i} d={`M ${20+i*14} ${165-i*5} Q 130 ${10+i*18} ${240-i*14} ${165-i*5}`} fill="none" stroke={c} strokeWidth="0.38" opacity={0.48-i*0.07} />
        ))}
        <line x1="20" y1="165" x2="240" y2="165" stroke={c} strokeWidth="0.6" opacity="0.5" />
        {Array.from({length:18}, (_,i) => (
          <line key={i} x1={22+i*12} y1={165} x2={22+i*12} y2={158} stroke={c} strokeWidth="0.4" opacity="0.4" />
        ))}
        <circle cx="130" cy="68" r="4" fill={c} opacity="0.72" />
      </svg>
    );
  }
  if (variant === 9) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        {Array.from({length:15}, (_,i) => (
          <line key={i} x1={38+i*13} y1={28} x2={38+i*13} y2={158} stroke={c} strokeWidth="0.3" opacity="0.22" />
        ))}
        <rect x="38" y="28" width="184" height="130" fill="none" stroke={c} strokeWidth="0.88" opacity="0.88" />
        {Array.from({length:15}, (_,i) => {
          const col = i % 5, row = Math.floor(i / 5);
          return <rect key={i} x={50+col*32} y={45+row*32} width="16" height="20" fill="none" stroke={c} strokeWidth="0.4" opacity="0.55" />;
        })}
        <rect x="108" y="118" width="44" height="40" fill="none" stroke={c} strokeWidth="0.6" opacity="0.65" />
        <line x1="130" y1="12" x2="130" y2="28" stroke={c} strokeWidth="0.7" opacity="0.65" />
        <line x1="115" y1="12" x2="145" y2="12" stroke={c} strokeWidth="0.7" opacity="0.65" />
      </svg>
    );
  }
  if (variant === 10) {
    return (
      <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
        <path d="M 35 62 Q 130 24 225 62" fill="none" stroke={c} strokeWidth="1.1" opacity="0.88" />
        <polyline points="213,52 225,62 213,70" fill="none" stroke={c} strokeWidth="1.1" opacity="0.88" />
        <path d="M 225 118 Q 130 156 35 118" fill="none" stroke={c} strokeWidth="1.1" opacity="0.88" />
        <polyline points="47,110 35,118 47,126" fill="none" stroke={c} strokeWidth="1.1" opacity="0.88" />
        {Array.from({length:3}, (_,i) => [
          <path key={`u${i}`} d={`M ${35+i*10} ${62+i*5} Q 130 ${24+i*10} ${225-i*10} ${62+i*5}`} fill="none" stroke={c} strokeWidth="0.32" opacity={0.3-i*0.08} />,
          <path key={`d${i}`} d={`M ${225-i*10} ${118-i*5} Q 130 ${156-i*10} ${35+i*10} ${118-i*5}`} fill="none" stroke={c} strokeWidth="0.32" opacity={0.3-i*0.08} />
        ])}
      </svg>
    );
  }
  return (
    <svg viewBox="0 0 260 180" preserveAspectRatio="xMidYMid meet" width="100%" height="100%">
      <rect x="40" y="40" width="180" height="100" fill="none" stroke={c} strokeWidth="0.8" opacity="0.7" />
    </svg>
  );
}

/* ============ Featured carousel art ============ */
function CarouselArt({ slide, color, ink }) {
  if (slide === 0) {
    return (
      <svg viewBox="0 0 320 200" width="100%" height="100%">
        <line x1="0" y1="100" x2="320" y2="100" stroke={ink} strokeWidth="0.4" strokeDasharray="2 3" opacity="0.5" />
        <line x1="160" y1="20" x2="160" y2="180" stroke={ink} strokeWidth="0.4" strokeDasharray="2 3" opacity="0.5" />
        <circle cx="125" cy="100" r="62" fill="none" stroke={ink} strokeWidth="0.9" />
        <circle cx="195" cy="100" r="62" fill="none" stroke={ink} strokeWidth="0.9" />
        <path d="M 160 41 A 62 62 0 0 1 160 159 A 62 62 0 0 1 160 41 Z" fill={color} opacity="0.55" />
        <text x="105" y="96" textAnchor="middle" fontSize="11" fontFamily="Inter" fontWeight="500" fill={ink}>Pays A</text>
        <text x="105" y="113" textAnchor="middle" fontSize="9" fontFamily="Inter" fill={ink} opacity="0.6">Imposition</text>
        <text x="215" y="96" textAnchor="middle" fontSize="11" fontFamily="Inter" fontWeight="500" fill={ink}>Pays B</text>
        <text x="215" y="113" textAnchor="middle" fontSize="9" fontFamily="Inter" fill={ink} opacity="0.6">Imposition</text>
      </svg>
    );
  }
  if (slide === 1) {
    return (
      <svg viewBox="0 0 320 200" width="100%" height="100%">
        <line x1="40" y1="100" x2="135" y2="100" stroke={ink} strokeWidth="1.2" />
        <line x1="185" y1="100" x2="280" y2="100" stroke={ink} strokeWidth="1.2" strokeDasharray="3 3" />
        <polygon points="160,55 195,100 160,145 125,100" fill={color} opacity="0.7" />
        <text x="160" y="106" textAnchor="middle" fontSize="20" fontFamily="Fraunces" fill="#fff">!</text>
        <text x="40" y="135" fontSize="10" fontFamily="Inter" fill={ink} opacity="0.6">Obligation</text>
        <text x="280" y="135" textAnchor="end" fontSize="10" fontFamily="Inter" fill={ink} opacity="0.6">Exonération</text>
      </svg>
    );
  }
  if (slide === 2) {
    return (
      <svg viewBox="0 0 320 200" width="100%" height="100%">
        <rect x="50" y="70" width="220" height="60" fill={color} opacity="0.18" />
        {[60, 130, 200, 260].map((x, i) => (
          <g key={i}>
            <circle cx={x} cy="100" r="20" fill="#fff" stroke={ink} strokeWidth="1" />
            <text x={x} y="104" textAnchor="middle" fontSize="11" fontFamily="Inter" fontWeight="500" fill={ink}>{i + 1}</text>
            {i < 3 && <line x1={x + 22} y1="100" x2={x + 50} y2="100" stroke={ink} strokeWidth="1" strokeDasharray="2 2" />}
          </g>
        ))}
      </svg>
    );
  }
  if (slide === 3) {
    return (
      <svg viewBox="0 0 320 200" width="100%" height="100%">
        <rect x="50" y="60" width="100" height="100" fill="none" stroke={ink} strokeWidth="1" />
        <rect x="170" y="60" width="100" height="100" fill={color} opacity="0.55" />
        <line x1="150" y1="110" x2="170" y2="110" stroke={ink} strokeWidth="1" />
        <polyline points="166,106 172,110 166,114" fill="none" stroke={ink} strokeWidth="1" />
        <text x="100" y="180" textAnchor="middle" fontSize="10" fontFamily="Inter" fill={ink} opacity="0.6">Société A</text>
        <text x="220" y="180" textAnchor="middle" fontSize="10" fontFamily="Inter" fill={ink} opacity="0.6">Société B</text>
      </svg>
    );
  }
  return null;
}

/* ============ Theme toggler ============ */
function ThemeToggler({ isDark, onToggle, t }) {
  return (
    <button
      onClick={onToggle}
      style={{
        background: "transparent", border: 0,
        borderLeft: `1px solid ${t.lineColor}`,
        cursor: "pointer", padding: 0,
        display: "flex", alignItems: "center", justifyContent: "center",
        width: 60, color: t.ink,
        transition: "color 400ms",
      }}
      aria-label={isDark ? "Mode jour" : "Mode nuit"}
    >
      <svg
        width="19" height="19" viewBox="0 0 24 24"
        fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"
        style={{
          transform: isDark ? "rotate(210deg)" : "rotate(0deg)",
          transition: "transform 600ms cubic-bezier(.34,1.3,.64,1)",
        }}
      >
        {/* Moon */}
        <path
          d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
          style={{ opacity: isDark ? 1 : 0, transition: "opacity 350ms" }}
        />
        {/* Sun disk */}
        <circle
          cx="12" cy="12" r="4.8"
          fill="currentColor" stroke="none"
          style={{ opacity: isDark ? 0 : 1, transition: "opacity 350ms" }}
        />
        {/* Rays */}
        {[0,45,90,135,180,225,270,315].map((deg, i) => {
          const r = Math.PI * deg / 180;
          const x1 = 12 + Math.cos(r) * 7;
          const y1 = 12 + Math.sin(r) * 7;
          const x2 = 12 + Math.cos(r) * 9.2;
          const y2 = 12 + Math.sin(r) * 9.2;
          return (
            <line key={i} x1={x1} y1={y1} x2={x2} y2={y2}
              style={{ opacity: isDark ? 0 : 1, transition: `opacity 300ms ${i * 20}ms` }}
            />
          );
        })}
      </svg>
    </button>
  );
}

/* ============ Header ============ */
function Header({ t, isDark, onToggle }) {
  return (
    <header style={{
      borderBottom: `1px solid ${t.lineColor}`,
      display: "grid",
      gridTemplateColumns: "1fr auto 60px 60px 60px",
      alignItems: "stretch",
      background: t.paper,
      transition: "background 400ms, border-color 400ms",
    }}>
      <div style={{ padding: "26px 28px", display: "flex", alignItems: "center" }}>
        <a href="#" style={{ textDecoration: "none", color: t.ink, fontSize: 16, letterSpacing: "-0.01em", fontWeight: 500, transition: "color 400ms" }}>
          lawandeconomics<span style={{ opacity: 0.45 }}>.ch</span>
        </a>
      </div>
      <nav style={{ display: "flex", alignItems: "center", gap: 36, padding: "0 28px" }}>
        {["Concepts", "Thématiques", "À propos", "Ressources"].map(n => (
          <a key={n} href="#" className="nav-link" style={{
            textDecoration: "none", color: t.ink, fontSize: 10.5,
            letterSpacing: "0.18em", textTransform: "uppercase", fontWeight: 500,
            position: "relative", padding: "4px 0", transition: "color 400ms",
          }}>{n}</a>
        ))}
      </nav>
      <button className="icon-btn" style={iconBtn(t)}>
        <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
          <circle cx="10.5" cy="10.5" r="6.5" />
          <path d="M15 15 L20 20" strokeLinecap="round" />
        </svg>
      </button>
      <ThemeToggler isDark={isDark} onToggle={onToggle} t={t} />
      <button className="icon-btn" style={{ ...iconBtn(t), borderLeft: `1px solid ${t.lineColor}` }}>
        <svg width="18" height="14" viewBox="0 0 24 18" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round">
          <line x1="2" y1="3" x2="22" y2="3" />
          <line x1="2" y1="9" x2="22" y2="9" />
          <line x1="2" y1="15" x2="22" y2="15" />
        </svg>
      </button>
    </header>
  );
}
const iconBtn = (t) => ({
  background: "transparent", border: 0, borderLeft: `1px solid ${t.lineColor}`,
  cursor: "pointer", color: t.ink, display: "flex", alignItems: "center", justifyContent: "center",
});

/* ============ Hero ============ */
const HERO_CAT_NAMES = ["Fiscalité", "International", "Économie", "Politiques", "Droit", "Arbitrage"];
const SCROLL_COLS = [
  {
    duration: 22,
    delay: "0s",
    cards: [
      { catIdx: 0, title: "Prix de transfert", desc: "Fixation des prix entre sociétés d'un même groupe.", art: 2 },
      { catIdx: 4, title: "Force majeure", desc: "Un événement imprévisible qui exonère une partie.", art: 1 },
      { catIdx: 2, title: "Coût d'opportunité", desc: "La valeur de la meilleure alternative à laquelle on renonce.", art: 3 },
    ],
  },
  {
    duration: 17,
    delay: "-7s",
    cards: [
      { catIdx: 5, title: "Lex mercatoria", desc: "Corpus de règles commerciales internationales.", art: 4 },
      { catIdx: 1, title: "BEPS — Action 14", desc: "Mécanismes de résolution des différends fiscaux.", art: 5 },
      { catIdx: 3, title: "Subsidiarité", desc: "Ne déléguer que ce qu'un niveau supérieur fait mieux.", art: 7 },
    ],
  },
];

function HeroScrollCard({ f, t }) {
  const color = t.palette[f.catIdx];
  const cat = HERO_CAT_NAMES[f.catIdx];
  return (
    <div style={{
      border: `1px solid ${t.lineColor}`,
      borderTop: `2px solid ${color}`,
      background: t.paper,
      overflow: "hidden",
      marginBottom: 12,
      flexShrink: 0,
      boxShadow: "0 1px 3px rgba(0,0,0,0.04), 0 4px 14px rgba(0,0,0,0.05)",
    }}>
      <div style={{ height: 72, overflow: "hidden", borderBottom: `1px solid ${t.lineColor}` }}>
        <EngravingArt variant={f.art} color={color} />
      </div>
      <div style={{ padding: "11px 13px 14px" }}>
        <div style={{ color, fontSize: 8.5, textTransform: "uppercase", letterSpacing: "0.2em", fontWeight: 600, marginBottom: 6 }}>{cat}</div>
        <div style={{ fontSize: 14, fontFamily: `"${t.titleFont}", serif`, lineHeight: 1.2, color: t.ink }}>{f.title}</div>
        <div style={{ marginTop: 7, fontSize: 11, lineHeight: 1.5, color: t.ink, opacity: 0.55 }}>{f.desc}</div>
      </div>
    </div>
  );
}

function HeroScrollColumns({ t }) {
  return (
    <div style={{
      display: "flex",
      gap: 12,
      height: "100%",
      overflow: "hidden",
      padding: "0 20px",
      maskImage: "linear-gradient(to bottom, transparent 0%, black 12%, black 88%, transparent 100%)",
      WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, black 12%, black 88%, transparent 100%)",
    }}>
      {SCROLL_COLS.map((col, ci) => (
        <div key={ci} style={{ flex: 1, overflow: "hidden" }}>
          <div style={{
            display: "flex",
            flexDirection: "column",
            animation: `scrollHero ${col.duration}s linear infinite`,
            animationDelay: col.delay,
          }}>
            {[0, 1].map(rep => (
              <React.Fragment key={rep}>
                {col.cards.map((f, i) => (
                  <HeroScrollCard key={`${rep}-${i}`} f={f} t={t} />
                ))}
              </React.Fragment>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

function Hero({ t }) {
  return (
    <section style={{
      display: "grid",
      gridTemplateColumns: "1fr 1fr",
      borderBottom: `1px solid ${t.lineColor}`,
      background: t.paper,
      height: 380,
      overflow: "hidden",
    }}>
      {/* Left */}
      <div style={{ padding: "36px 48px 28px", display: "flex", flexDirection: "column", borderRight: `1px solid ${t.lineColor}` }}>
        <div>
          <div style={{ color: t.accent, fontSize: 11, letterSpacing: "0.22em", textTransform: "uppercase", fontWeight: 600, marginBottom: 16 }}>
            Law and Economics
          </div>
          <h1 style={{
            fontFamily: `"${t.titleFont}", "Times New Roman", serif`,
            fontWeight: 400,
            fontSize: 54,
            lineHeight: 1.04,
            letterSpacing: "-0.02em",
            margin: 0,
            color: t.ink,
          }}>
            <div>Idée complexe,</div>
            <div>expliquer{" "}
              <span style={{ color: t.accent, fontStyle: "italic" }}>facilement.</span>
            </div>
          </h1>
          <div style={{ width: 72, height: 2, background: t.accent, marginTop: 16, marginBottom: 14 }} />
          <p style={{ maxWidth: 360, color: t.ink, opacity: 0.7, fontSize: 14, lineHeight: 1.7, margin: 0 }}>
            Des notions clés de droit, d'économie et de fiscalité expliquées en carrousels visuels et interactifs.
          </p>
        </div>
        <a href="#" className="cta-link" style={{
          marginTop: 24, display: "inline-flex", alignItems: "center", gap: 14,
          color: t.accent, textDecoration: "none",
          fontSize: 11, letterSpacing: "0.22em", textTransform: "uppercase", fontWeight: 600,
          paddingBottom: 14, alignSelf: "flex-start",
          borderBottom: `1px solid ${t.accent}`,
          position: "relative",
        }}>
          <span>Explorer les concepts</span>
          <svg className="cta-arrow" width="22" height="10" viewBox="0 0 22 10" fill="none" stroke="currentColor" strokeWidth="1.2">
            <line x1="0" y1="5" x2="20" y2="5" />
            <polyline points="16,1 20,5 16,9" fill="none" />
          </svg>
        </a>
      </div>

      {/* Right: scrolling card columns */}
      <div style={{ overflow: "hidden", height: "100%" }}>
        <HeroScrollColumns t={t} />
      </div>
    </section>
  );
}

function FeaturedCard({ slide, setSlide, cur, total, t }) {
  return (
    <div key={slide} className="featured-fade" style={{
      border: `1px solid ${t.lineColor}`,
      background: t.paper,
      padding: "24px 28px 20px",
      display: "flex",
      flexDirection: "column",
      minHeight: 580,
    }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 28 }}>
        <span style={{ color: cur.color, fontSize: 10.5, letterSpacing: "0.22em", textTransform: "uppercase", fontWeight: 600 }}>{cur.kind}</span>
        <span style={{ color: t.ink, opacity: 0.4, fontSize: 11, fontFamily: "JetBrains Mono, monospace" }}>{String(slide + 1).padStart(2, "0")}</span>
      </div>
      <h2 style={{
        fontFamily: `"${t.titleFont}", serif`, fontWeight: 400, fontSize: 30, lineHeight: 1.13,
        letterSpacing: "-0.015em", margin: 0, color: t.ink, whiteSpace: "pre-line",
      }}>{cur.title}</h2>
      <p style={{ marginTop: 16, color: t.ink, opacity: 0.65, fontSize: 13.5, lineHeight: 1.6, maxWidth: 320 }}>
        {cur.desc}
      </p>
      <div style={{ flex: 1, minHeight: 200, marginTop: 24, marginBottom: 14, display: "flex", alignItems: "center", justifyContent: "center" }}>
        <CarouselArt slide={cur.art} color={cur.color} ink={t.ink} />
      </div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", paddingTop: 16, borderTop: `1px solid ${t.lineColor}` }}>
        <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
          <span style={{ fontSize: 11, fontFamily: "JetBrains Mono, monospace", color: t.ink, opacity: 0.5 }}>
            {String(slide + 1).padStart(2, "0")} / {String(total).padStart(2, "0")}
          </span>
          <div style={{ display: "flex", gap: 4 }}>
            {Array.from({ length: total }).map((_, i) => (
              <button key={i} onClick={() => setSlide(i)} style={{
                width: i === slide ? 26 : 10, height: 2,
                background: i === slide ? t.ink : t.lineColor,
                border: 0, cursor: "pointer", padding: 0, transition: "width 220ms ease",
              }} />
            ))}
          </div>
        </div>
        <div style={{ display: "flex", border: `1px solid ${t.lineColor}` }}>
          <button onClick={() => setSlide((slide - 1 + total) % total)} className="nav-btn" style={navBtn(t)}>
            <svg width="14" height="10" viewBox="0 0 16 12" fill="none" stroke="currentColor" strokeWidth="1.3">
              <polyline points="6,1 1,6 6,11" /><line x1="1" y1="6" x2="14" y2="6" />
            </svg>
          </button>
          <button onClick={() => setSlide((slide + 1) % total)} className="nav-btn" style={{ ...navBtn(t), borderLeft: `1px solid ${t.lineColor}` }}>
            <svg width="14" height="10" viewBox="0 0 16 12" fill="none" stroke="currentColor" strokeWidth="1.3">
              <line x1="2" y1="6" x2="15" y2="6" /><polyline points="10,1 15,6 10,11" />
            </svg>
          </button>
        </div>
      </div>
    </div>
  );
}

const navBtn = (t) => ({
  width: 40, height: 32, background: "transparent", border: 0, cursor: "pointer",
  display: "flex", alignItems: "center", justifyContent: "center", color: t.ink,
  transition: "background 160ms",
});

function StackArt({ color }) {
  const lines = [];
  for (let i = 0; i < 22; i++) {
    const x = i * 1.2;
    lines.push(<line key={i} x1={x} y1={-10} x2={x + 4} y2={310} stroke={color} strokeWidth="0.4" opacity={0.5 + (i % 3) * 0.12} />);
  }
  return (
    <svg viewBox="0 0 24 300" preserveAspectRatio="none" width="100%" height="100%" style={{ display: "block", position: "absolute", inset: 0 }}>
      <defs>
        <linearGradient id={`g-${color.replace("#","")}`} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.05" />
          <stop offset="50%" stopColor={color} stopOpacity="0.5" />
          <stop offset="100%" stopColor={color} stopOpacity="0.05" />
        </linearGradient>
      </defs>
      <rect x="0" y="0" width="24" height="300" fill={`url(#g-${color.replace("#","")})`} />
      {lines}
    </svg>
  );
}

/* ============ Categories ============ */
function CategoryIcon({ kind, ink }) {
  const sw = 1;
  if (kind === "fiscalite") {
    const dots = [];
    for (let y = 0; y < 4; y++)
      for (let x = 0; x < 6; x++) dots.push(<circle key={`${x}-${y}`} cx={6 + x * 6} cy={6 + y * 6} r="0.9" fill={ink} />);
    return <svg viewBox="0 0 40 30" width="40" height="30">{dots}</svg>;
  }
  if (kind === "economie") return (
    <svg viewBox="0 0 40 30" width="40" height="30">
      <rect x="4" y="18" width="6" height="10" fill="none" stroke={ink} strokeWidth={sw} />
      <rect x="14" y="12" width="6" height="16" fill="none" stroke={ink} strokeWidth={sw} />
      <rect x="24" y="6" width="6" height="22" fill="none" stroke={ink} strokeWidth={sw} />
    </svg>
  );
  if (kind === "droit") return (
    <svg viewBox="0 0 40 30" width="40" height="30">
      <line x1="6" y1="8" x2="34" y2="8" stroke={ink} strokeWidth={sw} />
      <line x1="6" y1="15" x2="34" y2="15" stroke={ink} strokeWidth={sw} />
      <line x1="6" y1="22" x2="34" y2="22" stroke={ink} strokeWidth={sw} />
    </svg>
  );
  if (kind === "international") return (
    <svg viewBox="0 0 40 30" width="40" height="30">
      <circle cx="20" cy="15" r="11" fill="none" stroke={ink} strokeWidth={sw} />
      <ellipse cx="20" cy="15" rx="5" ry="11" fill="none" stroke={ink} strokeWidth={sw} />
      <line x1="9" y1="15" x2="31" y2="15" stroke={ink} strokeWidth={sw} />
    </svg>
  );
  if (kind === "politiques") {
    const dots = [];
    for (let y = 0; y < 4; y++)
      for (let x = 0; x < 4; x++) dots.push(<circle key={`${x}-${y}`} cx={10 + x * 6} cy={6 + y * 6} r="0.9" fill={ink} />);
    return <svg viewBox="0 0 40 30" width="40" height="30">{dots}</svg>;
  }
  if (kind === "arbitrage") return (
    <svg viewBox="0 0 40 30" width="40" height="30">
      <line x1="20" y1="4" x2="20" y2="26" stroke={ink} strokeWidth={sw} />
      <line x1="6" y1="12" x2="34" y2="12" stroke={ink} strokeWidth={sw} />
      <polygon points="6,12 2,20 10,20" fill="none" stroke={ink} strokeWidth={sw} />
      <polygon points="34,12 30,20 38,20" fill="none" stroke={ink} strokeWidth={sw} />
    </svg>
  );
  return null;
}

function Categories({ t }) {
  const items = [
    { key: "fiscalite", label: "Fiscalité", count: 24, color: t.palette[0] },
    { key: "international", label: "International", count: 15, color: t.palette[1] },
    { key: "economie", label: "Économie", count: 18, color: t.palette[2] },
    { key: "politiques", label: "Politiques publiques", count: 12, color: t.palette[3] },
    { key: "droit", label: "Droit", count: 22, color: t.palette[4] },
    { key: "arbitrage", label: "Arbitrage", count: 9, color: t.palette[5] },
  ];
  return (
    <section style={{
      background: t.categoryStrip,
      borderBottom: `1px solid ${t.lineColor}`,
      display: "grid",
      gridTemplateColumns: `repeat(${items.length}, 1fr)`,
    }}>
      {items.map((c, i) => (
        <a key={c.key} href="#" className="cat-tile" style={{
          padding: "40px 26px 32px",
          textDecoration: "none",
          color: t.ink,
          borderRight: i < items.length - 1 ? `1px solid ${t.lineColor}` : 0,
          display: "flex", flexDirection: "column", gap: 24,
          transition: "background 200ms",
          position: "relative",
        }}>
          <CategoryIcon kind={c.key} ink={t.ink} />
          <div>
            <div style={{ fontSize: 14.5, fontWeight: 500, letterSpacing: "-0.005em" }}>{c.label}</div>
            <div style={{ fontSize: 11, color: t.ink, opacity: 0.5, marginTop: 6, fontFamily: "JetBrains Mono, monospace" }}>{c.count} concepts</div>
          </div>
          <div className="cat-bar" style={{ position: "absolute", left: 0, bottom: 0, height: 2, width: 0, background: c.color, transition: "width 280ms ease" }} />
        </a>
      ))}
    </section>
  );
}

/* ============ Publications ============ */
function buildPublications(palette) {
  const C = {
    Fiscalité: palette[0], International: palette[1], Économie: palette[2],
    Politiques: palette[3], Droit: palette[4], Arbitrage: palette[5],
  };
  return [
    { cat: "Droit", color: C.Droit, title: "Force majeure", desc: "Un événement imprévisible qui exonère une partie de ses obligations.", art: 0 },
    { cat: "Économie", color: C.Économie, title: "Coût d'opportunité", desc: "La valeur de la meilleure alternative à laquelle on renonce.", art: 1 },
    { cat: "Fiscalité", color: C.Fiscalité, title: "Prix de transfert", desc: "Fixation des prix dans les transactions entre sociétés d'un même groupe.", art: 2 },
    { cat: "Arbitrage", color: C.Arbitrage, title: "Clause de la nation\nla plus favorisée", desc: "Accorder à un partenaire le même avantage qu'à tout autre.", art: 3 },

    { cat: "Droit", color: C.Droit, title: "Personnalité juridique", desc: "Aptitude à être titulaire de droits et d'obligations.", art: 4 },
    { cat: "International", color: C.International, title: "BEPS — Action 14", desc: "Améliorer le règlement des différends entre États.", art: 5 },
    { cat: "Fiscalité", color: C.Fiscalité, title: "Convention de\ndouble imposition", desc: "Accord bilatéral pour éviter qu'un revenu soit imposé deux fois.", art: 6 },
    { cat: "Politiques publiques", color: C.Politiques, title: "Principe de subsidiarité", desc: "Ne déléguer à un niveau supérieur que ce qu'il fait mieux.", art: 7 },

    { cat: "International", color: C.International, title: "Procédure amiable", desc: "Mécanisme de résolution conventionnel entre administrations fiscales.", art: 8 },
    { cat: "Fiscalité", color: C.Fiscalité, title: "Établissement stable", desc: "Présence économique permanente déclenchant l'imposition locale.", art: 9 },
    { cat: "Économie", color: C.Économie, title: "Théorème de Coase", desc: "Allocation efficace des droits via la négociation, sans coût de transaction.", art: 10 },
    { cat: "Arbitrage", color: C.Arbitrage, title: "Lex mercatoria", desc: "Corpus de règles d'usage commercial international entre opérateurs privés.", art: 0 },
  ];
}

function Publications({ t }) {
  const pubs = useMemo(() => buildPublications(t.palette), [t.palette]);
  return (
    <section style={{ background: t.paper, borderBottom: `1px solid ${t.lineColor}` }}>
      <div style={{
        padding: `48px ${t.outerPadding + 8}px 32px`,
        display: "flex", justifyContent: "space-between", alignItems: "flex-end",
      }}>
        <h2 style={{
          fontFamily: `"${t.titleFont}", serif`, fontWeight: 400,
          fontSize: 38, lineHeight: 1.05, letterSpacing: "-0.02em",
          margin: 0, color: t.ink,
        }}>
          Dernières publications.
        </h2>
        <a href="#" className="see-all" style={{
          textDecoration: "none", color: t.ink, fontSize: 10, letterSpacing: "0.22em",
          textTransform: "uppercase", fontWeight: 600, display: "inline-flex", alignItems: "center", gap: 10,
          opacity: 0.65, paddingBottom: 4,
        }}>
          Voir tout
          <svg className="cta-arrow" width="18" height="8" viewBox="0 0 18 8" fill="none" stroke="currentColor" strokeWidth="1.2">
            <line x1="0" y1="4" x2="16" y2="4" />
            <polyline points="12,1 16,4 12,7" />
          </svg>
        </a>
      </div>

      <div style={{
        display: "grid",
        gridTemplateColumns: "repeat(4, 1fr)",
        gap: t.cardGap,
        padding: `0 ${t.outerPadding}px ${t.outerPadding}px`,
      }}>
        {pubs.map((p, i) => (
          <a key={i} href="#" className="pub-card" style={{
            textDecoration: "none", color: t.ink,
            background: t.paper,
            border: `1px solid ${t.lineColor}`,
            borderTop: `2px solid ${p.color}`,
            padding: "22px 24px 52px",
            display: "flex", flexDirection: "column", gap: 12,
            minHeight: 380, position: "relative",
            transition: "border-color 220ms ease",
            boxShadow: "0 1px 3px rgba(0,0,0,0.04), 0 6px 20px rgba(0,0,0,0.05)",
          }}>
            <div style={{ color: p.color, fontSize: 10.5, letterSpacing: "0.22em", textTransform: "uppercase", fontWeight: 600 }}>{p.cat}</div>
            <h3 style={{
              fontFamily: `"${t.titleFont}", serif`, fontWeight: 400, fontSize: 22,
              lineHeight: 1.16, letterSpacing: "-0.01em", margin: 0,
              whiteSpace: "pre-line", color: t.ink,
            }}>{p.title}</h3>
            <p style={{ margin: 0, color: t.ink, opacity: 0.65, fontSize: 12.5, lineHeight: 1.55 }}>{p.desc}</p>
            {t.showCardArt && (
              <div style={{ flex: 1, marginTop: 10, minHeight: 130, display: "flex", alignItems: "flex-end" }}>
                <div style={{ width: "100%", aspectRatio: "1.5 / 1" }}>
                  <EngravingArt variant={p.art} color={p.color} />
                </div>
              </div>
            )}
            <div className="pub-arrow" style={{
              position: "absolute", bottom: 18, right: 22,
              transition: "transform 240ms ease",
            }}>
              <svg width="22" height="10" viewBox="0 0 22 10" fill="none" stroke="currentColor" strokeWidth="1.2">
                <line x1="0" y1="5" x2="20" y2="5" />
                <polyline points="16,1 20,5 16,9" fill="none" />
              </svg>
            </div>
          </a>
        ))}
      </div>
    </section>
  );
}

/* ============ Manifeste ============ */
const MANIFESTE_POINTS = [
  {
    num: "01",
    title: "Densité visuelle",
    body: "Une diapositive condense ce qu'un long article dilue. La cognition spatiale fait le reste — une image vaut mille mots de doctrine.",
  },
  {
    num: "02",
    title: "Mémorisation accrue",
    body: "Le format séquentiel mobilise la mémoire de travail bien mieux qu'un texte continu. Une notion par slide, ancrée par le visuel.",
  },
  {
    num: "03",
    title: "Référence rapide",
    body: "Chaque fiche est une unité atomique citable, partageable, archivable. Pas de scroll fatigue, pas de contenu dilué.",
  },
  {
    num: "04",
    title: "Rigueur académique",
    body: "Sources primaires citées, doctrine référencée, jurisprudence indexée. Le fond sans le format blog.",
  },
];

function Manifeste({ t }) {
  return (
    <section style={{
      background: t.categoryStrip,
      borderBottom: `1px solid ${t.lineColor}`,
    }}>
      <div style={{
        display: "grid",
        gridTemplateColumns: "1fr 1.875fr",
        borderBottom: `1px solid ${t.lineColor}`,
      }}>
        {/* Left — texte principal */}
        <div style={{
          padding: "64px 52px",
          borderRight: `1px solid ${t.lineColor}`,
          display: "flex", flexDirection: "column", justifyContent: "center", gap: 24,
        }}>
          <h2 style={{
            fontFamily: `"${t.titleFont}", serif`, fontWeight: 400,
            fontSize: 42, lineHeight: 1.06, letterSpacing: "-0.02em",
            margin: 0, color: t.ink,
          }}>
            Pourquoi le format<br />
            <span style={{ color: t.accent, fontStyle: "italic" }}>carrousel</span> ?
          </h2>
          <p style={{ margin: 0, fontSize: 14.5, lineHeight: 1.7, color: t.ink, opacity: 0.65, maxWidth: 380 }}>
            Les longs articles ne sont plus lus. Les fiches visuelles, oui. Le format carrousel impose la rigueur : une idée par slide, une source par citation, une notion par fiche.
          </p>
          <blockquote style={{
            margin: "8px 0 0", padding: "14px 0 0",
            borderTop: `1px solid ${t.lineColor}`,
            fontSize: 12.5, fontFamily: "JetBrains Mono, monospace",
            color: t.ink, opacity: 0.5, letterSpacing: "0.02em",
            fontStyle: "normal",
          }}>
            « La densité visuelle est l'arme moderne de la doctrine. »
          </blockquote>
        </div>

        {/* Right — 4 points en grille */}
        <div style={{
          display: "grid",
          gridTemplateColumns: "1fr 1fr",
          borderLeft: 0,
        }}>
          {MANIFESTE_POINTS.map((pt, i) => (
            <div key={pt.num} style={{
              padding: "40px 36px",
              borderRight: i % 2 === 0 ? `1px solid ${t.lineColor}` : 0,
              borderBottom: i < 2 ? `1px solid ${t.lineColor}` : 0,
              background: t.paper,
            }}>
              <div style={{ fontSize: 10, fontFamily: "JetBrains Mono, monospace", color: t.accent, letterSpacing: "0.1em", marginBottom: 18, opacity: 0.9 }}>
                {pt.num} —
              </div>
              <h3 style={{
                fontFamily: `"${t.titleFont}", serif`, fontWeight: 400,
                fontSize: 20, lineHeight: 1.15, letterSpacing: "-0.01em",
                margin: "0 0 12px", color: t.ink,
              }}>
                {pt.title}
              </h3>
              <p style={{ margin: 0, fontSize: 13, lineHeight: 1.6, color: t.ink, opacity: 0.6 }}>
                {pt.body}
              </p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ============ Footer ============ */
const FOOTER_COLS = [
  {
    label: "Thématiques",
    links: [
      "Fiscalité internationale",
      "Arbitrage & MAP",
      "Analyse économique du droit",
      "Droit international",
      "Politiques publiques",
      "Droit suisse",
    ],
  },
  {
    label: "Ressources",
    links: [
      "Index des concepts",
      "Bibliographie",
      "Citations & DOI",
      "Publications LinkedIn",
      "Glossaire",
    ],
  },
  {
    label: "À propos",
    links: [
      "Le projet",
      "Recherche doctorale",
      "Méthodologie",
      "Contact",
      "Mentions légales",
      "Licence CC BY-NC 4.0",
    ],
  },
];

function Footer({ t }) {
  const linkStyle = {
    display: "block", textDecoration: "none", color: t.ink,
    fontSize: 13, lineHeight: 1, paddingBottom: 12,
    opacity: 0.6, transition: "opacity 180ms",
  };
  const headStyle = {
    fontSize: 9.5, letterSpacing: "0.18em", textTransform: "uppercase",
    fontWeight: 600, color: t.ink, opacity: 0.35,
    fontFamily: "JetBrains Mono, monospace", marginBottom: 20,
  };
  return (
    <footer style={{ background: t.paper, borderTop: `1px solid ${t.lineColor}` }}>
      {/* Main footer grid */}
      <div style={{
        display: "grid",
        gridTemplateColumns: "1.6fr 1fr 1fr 1fr",
        borderBottom: `1px solid ${t.lineColor}`,
      }}>
        {/* Brand column */}
        <div style={{ padding: "52px 48px 52px 36px", borderRight: `1px solid ${t.lineColor}`, display: "flex", flexDirection: "column", gap: 0 }}>
          <div style={{ fontSize: 15, fontWeight: 500, letterSpacing: "-0.01em", color: t.ink, marginBottom: 6 }}>
            lawandeconomics<span style={{ opacity: 0.4 }}>.ch</span>
          </div>
          <p style={{ margin: "16px 0 0", fontSize: 13.5, lineHeight: 1.65, color: t.ink, opacity: 0.6, maxWidth: 300 }}>
            Plateforme de vulgarisation juridique et économique. Des notions clés du droit et de l'économie expliquées en carrousels visuels, en appui à la recherche doctorale.
          </p>
          <div style={{ display: "flex", gap: 16, marginTop: 28 }}>
            <SocialIcon kind="linkedin" ink={t.ink} />
            <SocialIcon kind="instagram" ink={t.ink} />
            <SocialIcon kind="x" ink={t.ink} />
            <SocialIcon kind="mail" ink={t.ink} />
          </div>
          <div style={{ marginTop: "auto", paddingTop: 36 }}>
            <a href="#" className="btn-primary" style={{
              background: t.ink, color: t.paper, textDecoration: "none",
              padding: "12px 20px", fontSize: 10, letterSpacing: "0.2em", textTransform: "uppercase",
              fontWeight: 600, display: "inline-flex", alignItems: "center", gap: 12,
              border: `1px solid ${t.ink}`,
            }}>
              <span>Explorer les concepts</span>
              <svg className="cta-arrow" width="18" height="8" viewBox="0 0 18 8" fill="none" stroke="currentColor" strokeWidth="1.2">
                <line x1="0" y1="4" x2="16" y2="4" /><polyline points="12,1 16,4 12,7" />
              </svg>
            </a>
          </div>
        </div>

        {/* Link columns */}
        {FOOTER_COLS.map((col, ci) => (
          <div key={ci} style={{
            padding: "52px 32px",
            borderRight: ci < FOOTER_COLS.length - 1 ? `1px solid ${t.lineColor}` : 0,
          }}>
            <div style={headStyle}>{col.label}</div>
            <nav>
              {col.links.map((lnk, li) => (
                <a key={li} href="#" className="footer-link" style={linkStyle}>{lnk}</a>
              ))}
            </nav>
          </div>
        ))}
      </div>

      {/* Bottom bar */}
      <div style={{
        padding: "16px 36px",
        display: "flex", justifyContent: "space-between", alignItems: "center",
        fontSize: 10.5, color: t.ink, opacity: 0.4,
        fontFamily: "JetBrains Mono, monospace", letterSpacing: "0.04em",
      }}>
        <span>© 2026 LAWANDECONOMICS.CH — GENÈVE, SUISSE</span>
        <span>LICENCE CC BY-NC 4.0</span>
      </div>
    </footer>
  );
}

function SocialIcon({ kind, ink }) {
  if (kind === "linkedin") return (
    <a href="#" className="soc" aria-label="LinkedIn"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={ink} strokeWidth="1.4">
      <rect x="3" y="3" width="18" height="18" rx="1" />
      <path d="M7 10v7 M7 7v.01" strokeLinecap="round" />
      <path d="M11 17v-4 a2 2 0 0 1 4 0 v4 M11 10v7" />
    </svg></a>
  );
  if (kind === "instagram") return (
    <a href="#" className="soc" aria-label="Instagram"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={ink} strokeWidth="1.4">
      <rect x="3" y="3" width="18" height="18" rx="4" />
      <circle cx="12" cy="12" r="4" />
      <circle cx="17.5" cy="6.5" r="0.8" fill={ink} />
    </svg></a>
  );
  if (kind === "x") return (
    <a href="#" className="soc" aria-label="X"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={ink} strokeWidth="1.4">
      <line x1="4" y1="4" x2="20" y2="20" /><line x1="20" y1="4" x2="4" y2="20" />
    </svg></a>
  );
  if (kind === "mail") return (
    <a href="#" className="soc" aria-label="Email"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={ink} strokeWidth="1.4">
      <rect x="3" y="5" width="18" height="14" rx="0.5" />
      <polyline points="3,7 12,14 21,7" />
    </svg></a>
  );
  return null;
}

/* ============ App ============ */
function App() {
  const [isDark, setIsDark] = useState(false);
  const t = isDark ? { ...TWEAK_DEFAULTS, ...DARK_OVERRIDES } : TWEAK_DEFAULTS;

  const accent = t.accent, ink = t.ink, line = t.lineColor;
  const css = `
    @keyframes fadeUp { from { opacity:0; transform: translateY(8px) } to { opacity:1; transform: translateY(0) } }
    @keyframes scrollHero { from { transform: translateY(0); } to { transform: translateY(-50%); } }
    .featured-fade { animation: fadeUp 380ms ease both; }
    section, header, footer, nav, div, a, p, h1, h2, h3, span, button {
      transition: background-color 400ms, border-color 400ms, color 400ms;
    }
    .nav-link::after {
      content:""; position:absolute; left:0; bottom:0; height:1px; width:0;
      background:${accent}; transition: width 240ms ease;
    }
    .nav-link:hover { color:${accent}; }
    .nav-link:hover::after { width:100%; }
    .cta-link .cta-arrow { transition: transform 240ms ease; }
    .cta-link:hover .cta-arrow { transform: translateX(6px); }
    .cta-link:hover { letter-spacing: 0.24em; }
    .see-all .cta-arrow { transition: transform 240ms ease; }
    .see-all:hover .cta-arrow { transform: translateX(5px); }
    .icon-btn { transition: background 180ms; }
    .icon-btn:hover { background: ${line}; }
    .nav-btn:hover { background:${line}; }
    .next-card:hover { border-color:${ink}; }
    .pub-card:hover { border-color:${ink}; }
    .pub-card:hover .pub-arrow { transform: translateX(5px); }
    .cat-tile:hover .cat-bar { width: 100%; }
    .btn-primary:hover .cta-arrow { transform: translateX(5px); }
    .btn-secondary:hover { background:${line}; }
    .btn-secondary:hover .cta-arrow { transform: translateX(5px); }
    .soc:hover { opacity: 0.6; }
    .footer-link:hover { opacity: 1 !important; }
  `;

  return (
    <div style={{
      display: "grid",
      gridTemplateColumns: "var(--gut) 1fr var(--gut)",
      "--gut": "44px",
      minHeight: "100vh",
      background: t.gutter,
      color: t.ink,
    }}>
      <style>{css}</style>

      {/* Side gutters with plus pattern */}
      <div style={{ position: "sticky", top: 0, height: "100vh", overflow: "hidden" }}>
        <PlusPattern density={t.plusDensity} opacity={t.plusOpacity} color={ink} />
      </div>

      <main style={{ background: t.paper, borderLeft: `1px solid ${t.lineColor}`, borderRight: `1px solid ${t.lineColor}`, transition: "background 400ms, border-color 400ms" }}>
        <Header t={t} isDark={isDark} onToggle={() => setIsDark(d => !d)} />
        <Hero t={t} />
        <Categories t={t} />
        <Publications t={t} />
        <Manifeste t={t} />
        <Footer t={t} />
      </main>

      <div style={{ position: "sticky", top: 0, height: "100vh", overflow: "hidden" }}>
        <PlusPattern density={t.plusDensity} opacity={t.plusOpacity} color={ink} />
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
