// Landing page sections and event pages

const EVENTS = [
  {
    id: 'hackathon',
    label: 'HACK',
    title: 'HACKATHON',
    subtitle: 'MIT Reality Hack × WebZero',
    blurb: '5 days of live build · The Seoul App handed to the city.',
    accent: '#ff2e4d',
    meta: ['5 DAYS · LIVE', 'FLOOR B · LAYER41', 'SEP 28 → OCT 02'],
    photo: null,
    youtube: 'JSooX30awrQ',
    deep: {
      hero: 'They build live. For five days.',
      keywords: ['MIT REALITY HACK', 'WEBZERO', 'AR / XR', 'WEBXR', 'REACT NATIVE', 'LIVE DEMO DAY', 'OPEN SOURCE', 'GAMIFIED'],
      special: {
        type: 'note',
        tag: 'OUTPUT',
        title: 'The Seoul App',
        text: 'A gamified cultural platform that bridges physical event ↔ digital extension. Built live on the Chanoirs App tech foundation. Real-world actions trigger digital rewards. AR/XR experiences built on-site, in real time. At the end, the app is handed over to Seoul cultural community to keep running.',
      },
      cta: 'STUFF WE\'VE SHIPPED',
    },
    portfolio: [
      { year: '2024', name: 'MIT REALITY HACK', desc: 'Builder track · MIT Media Lab · 5-day live build' },
      { year: '2024', name: 'ETHCC BRUSSELS', desc: '4 brand events · 2,500+ attendees' },
      { year: '2025', name: 'CANNES', desc: '20+ sponsors · 50+ artists · 50+ speakers' },
    ],
  },
  {
    id: 'esport',
    label: 'ESPORT',
    title: 'ESPORT',
    subtitle: 'Excalibur Tournament',
    blurb: 'A game they have never played. No practice. Pure instinct.',
    accent: '#f7d046',
    meta: ['3 DAYS', 'PRIZE TBC', 'FLOOR A · MAIN HALL'],
    photo: 'assets/event-esport.png',
    deep: {
      hero: 'A game they have never played.',
      keywords: ['EXCALIBUR', '3 DAYS', '2,000+ ON-SITE', '50,000+ ONLINE', 'TWITCH · YOUTUBE', 'GLENN LEE · KR LIAISON', 'SURPRISE REVEAL', 'AUDIENCE CHALLENGES'],
      special: {
        type: 'note',
        tag: 'THE FORMAT',
        title: 'Game revealed on stage.',
        text: 'Players arrive knowing nothing. The game is revealed on stage day 1. Practice, brackets, finals — all within 3 days. Produced by Excalibur. Local gaming-culture liaison: Sang Joon (Glenn) Lee.',
      },
      cta: 'GAMES WE\'VE BROKEN',
    },
    portfolio: [
      { year: '2024', name: 'EXCALIBUR LAUNCH', desc: 'First tournament · proof of format' },
      { year: '2025', name: 'CANNES PARTIES', desc: '6+ parties · live-streamed' },
    ],
  },
  {
    id: 'art-show',
    label: 'ART',
    title: 'ART SHOW',
    subtitle: 'Into Existence · Korea ↔ Europe',
    blurb: 'The fact of materializing an idea. Two scenes, one container.',
    accent: '#8be4c9',
    meta: ['4 KR ARTISTS', '4 EU ARTISTS', '1,500 M² · 3 LEVELS'],
    photo: null,
    iframe: 'https://lumalabs.ai/embed/9f95e6a2-81d6-4ae7-9f18-922954f41d6c?mode=sparkles&background=%23000000&color=%23ffffff&showTitle=true&loadBg=true&logoPosition=bottom-left&infoPosition=bottom-right&cinematicVideo=undefined&showMenu=false',
    deep: {
      hero: 'Into Existence.',
      keywords: ['UNITED FREAKS WORLD WIDE', 'NOT A DIALOGUE · A COLLISION', 'VOLUMETRIC LIGHT', 'SALVAGED MATTER', 'COLLECTOR ACCESS', 'SPACE M GALLERY', 'TRINITY GALLERY'],
      special: {
        type: 'roster',
        tag: 'ARTISTS · DIRECTION ARTISTIQUE',
        headliner: { name: 'Aaron Fowler', role: 'HEADLINER · USA / NEW YORK', desc: 'Large-scale mixed-media installations made from found materials, recycled car parts, salvaged memory.', photo: 'assets/artist-aaron-fowler.jpg' },
        roster: [
          { name: 'Kimchi & Chips', country: 'KOREA', role: 'Primary curators · volumetric light' },
          { name: 'Junsoo Kim', country: 'KOREA', role: 'Artist' },
          { name: 'Studio Locus Solus', country: 'KOREA', role: 'Artist' },
          { name: 'Jaewon Kang', country: 'KOREA', role: 'Artist' },
          { name: 'Antoine Grenez', country: 'BELGIUM', role: 'Artist' },
          { name: 'Mia Von Dalz', country: 'EUROPE', role: 'Artist' },
          { name: 'Peter Emanuelov', country: 'EUROPE', role: 'Artist' },
        ],
      },
      cta: 'WALLS WE\'VE HUNG',
    },
    portfolio: [
      { year: '2024', name: 'BRUSSELS · ETHCC', desc: 'Volumetric installation · Aaron Fowler showcase' },
      { year: '2024', name: 'MIAMI ART BASEL', desc: 'Brand activation during art week' },
      { year: '2025', name: 'CANNES', desc: '50+ artists curated · 4 brand exhibitions' },
    ],
  },
  {
    id: 'party',
    label: 'PARTY',
    title: 'PARTY',
    subtitle: 'HighTech Seoul × Quincy',
    blurb: 'Closing night. 1,000 attendees. 9m ceiling. Open till sunrise.',
    accent: '#c4a2ff',
    meta: ['1,000 ATTENDEES', 'LINE-UP TBC', 'OPEN TILL SUNRISE'],
    photo: 'assets/event-party.jpg',
    deep: {
      hero: 'Final convergence.',
      keywords: ['QUINCY · HIGHTECH SEOUL', '9M CEILING', 'FUNKTION-ONE', 'AR / XR LAYERS', 'OPEN TILL SUNRISE', 'BRAND TAKEOVERS', 'KR + INTL LINE-UP'],
      special: {
        type: 'roster',
        tag: 'PAST QUINCY ARTISTS · KR + INTL',
        headliner: { name: 'Quincy / HighTech Seoul', role: 'DIRECTION', desc: 'Seoul\'s benchmark for international techno booking and industrial-venue production. Past curation has hosted top international acts and broken Korean techno talent on world stages.', photo: 'assets/quincy-hightech.png' },
        roster: [
          { name: 'Charlotte de Witte', country: 'BE', role: 'Past Quincy headliner' },
          { name: 'Amelie Lens', country: 'BE', role: 'Past Quincy show' },
          { name: '999999999', country: 'IT', role: 'Past Quincy show' },
          { name: 'I Hate Models', country: 'FR', role: 'Past Quincy show' },
          { name: 'Peggy Gou', country: 'KR', role: 'Past Korean show' },
          { name: 'Seoul Community DJs', country: 'KR', role: 'Local rotation TBC' },
        ],
      },
      cta: 'DANCEFLOORS WE\'VE BURNED',
    },
    portfolio: [
      { year: '2024', name: 'BRUSSELS NIGHTS', desc: 'Industrial-venue techno — 5,500+ visitors' },
      { year: '2025', name: 'CANNES PARTIES', desc: '6+ parties · open till sunrise' },
      { year: 'PAST', name: 'BOILER ROOM CHINA', desc: 'Reference: extended-format streaming event in industrial venue' },
    ],
  },
];

const CAT_ANIMS = ['bounce', 'shake', 'spin', 'flip', 'tilt', 'zoom', 'wiggle', 'flop'];

function Hero({ theme }) {
  const [catAnim, setCatAnim] = React.useState(null);

  const pokeKitty = () => {
    const a = CAT_ANIMS[Math.floor(Math.random() * CAT_ANIMS.length)];
    setCatAnim(null);
    requestAnimationFrame(() => setCatAnim(a));
  };

  return (
    <section className="hero" data-screen-label="Hero">
      <div className="hero-bg" aria-hidden="true">
        <img src="assets/layer41.jpg" alt=""/>
        <span className="hero-bg-tag">LAYER41 · STUDIO 41 · PLUSJUN · SEOUL</span>
      </div>
      <div className="hero-grid">
        <div className="hero-left">
          <div className="kicker">
            <span className="dot"/> SEP 28 — OCT 02 · 2026 · LAYER41 SEOUL
          </div>
          <h1 className="hero-title">
            <span>DIGITAL</span>
            <span className="outline">AF</span>
            <span className="kr">하나됨</span>
          </h1>
          <p className="hero-tagline">
            DigitalAF offer a platform for talks and events exploring the dynamic interplay of Gaming, On-Chain Experiences, Web3 Communities and Art within the decentralized culture.
          </p>
        </div>
        <div className="hero-right">
          <div className="hero-cat wireframe-cat" onClick={pokeKitty} title="poke me">
            <div
              className={`hero-cat-inner${catAnim ? ` cat-anim-${catAnim}` : ''}`}
              onAnimationEnd={() => setCatAnim(null)}
            >
              <CatProwl size={300} color="var(--fg)"/>
            </div>
          </div>
          <div className="hero-stats-block">
            <div className="hero-stats">
              <div><b>5,000+</b><span>Attendees</span></div>
              <div><b>8</b><span>Artists</span></div>
              <div><b>5</b><span>Days</span></div>
              <div><b>1,500 M²</b><span>Venue · 3 levels</span></div>
            </div>
            <a className="btn primary big hero-enter" href="#events">ENTER THE BUILDING <span>→</span></a>
          </div>
        </div>
      </div>
      <MarqueeBand/>
    </section>
  );
}

function SiteRedTrail() {
  // Walking trail of cat footprints — dense from the cat to the manifesto title, sparser after
  const [anchors, setAnchors] = React.useState(null);

  React.useEffect(() => {
    const compute = () => {
      const cat = document.querySelector('.hero-cat');
      const marquee = document.querySelector('.marquee-band');
      if (!cat) return;
      const catRect = cat.getBoundingClientRect();
      const startTop  = ((catRect.bottom + window.scrollY - 12) / window.innerHeight) * 100;
      const startLeft = ((catRect.left + catRect.width / 2) / window.innerWidth) * 100;
      let denseEnd = startTop + 60;
      if (marquee) {
        const mRect = marquee.getBoundingClientRect();
        denseEnd = ((mRect.bottom + window.scrollY) / window.innerHeight) * 100;
      }
      const endTop = Math.max(denseEnd + 100, (document.body.scrollHeight / window.innerHeight) * 100 - 30);
      setAnchors({ startTop, startLeft, denseEnd, endTop });
    };
    requestAnimationFrame(() => requestAnimationFrame(compute));
    window.addEventListener('resize', compute);
    return () => window.removeEventListener('resize', compute);
  }, []);

  if (!anchors) return null;

  const { startTop, startLeft, denseEnd, endTop } = anchors;
  const DENSE_STEPS = 28;   // cat → "ONE FOR ALL, ALL FOR ONE" (paired walking)
  const SITE_STEPS  = 28;   // manifesto → bottom (single trail)

  // Build the paw entries.
  // In the dense section, alternate between PAIRED steps (two close paws — front+back)
  // and SINGLE steps. This mimics how a real cat leaves overlapping pairs of prints.
  const paws = [];
  for (let i = 0; i < DENSE_STEPS; i++) {
    const t = DENSE_STEPS === 1 ? 0 : i / (DENSE_STEPS - 1);
    const top = startTop + t * (denseEnd - startTop);
    paws.push({ top, partner: false });
    if (i % 2 === 0) {
      // partner paw — slightly behind and to the opposite side
      paws.push({ top: top + 1.4, partner: true });
    }
  }
  for (let i = 0; i < SITE_STEPS; i++) {
    const t = (i + 1) / SITE_STEPS;
    paws.push({ top: denseEnd + t * (endTop - denseEnd), partner: false });
  }

  return (
    <div className="red-paw-trail" aria-hidden="true">
      {paws.map((p, i) => {
        const waveT = (p.top - startTop) / (endTop - startTop);
        const phase = waveT * Math.PI * 3;
        const x = 50 + (startLeft - 50) * Math.cos(phase);
        const side = i % 2 === 0 ? -1 : 1;
        // partner paws sit on the opposite side of the main paw → they form a "pair"
        const lateralSide = p.partner ? -side : side;
        const left = x + lateralSide * 1.6;
        const slope = -Math.sin(phase);
        const rot = 180 + slope * 35 + (p.partner ? -8 : 0);
        const size = 16 + (i % 3) * 4;
        const above = i % 2 === 0;
        return (
          <div
            key={i}
            className={`red-paw ${above ? 'paw-above' : 'paw-below'}`}
            style={{
              top: `${p.top}vh`,
              left: `${left}vw`,
              transform: `translate(-50%, -50%) rotate(${rot}deg)`,
              opacity: above ? 0.42 : 0.7,
              animationDelay: `${(i * 0.07).toFixed(2)}s`,
              zIndex: above ? 5 : 1,
            }}
          >
            <PawPrint size={size} color="var(--accent)"/>
          </div>
        );
      })}
    </div>
  );
}

function MarqueeBand() {
  return (
    <div className="marquee marquee-band">
      <div className="marquee-inner">
        {Array.from({length: 4}).map((_, i) => (
          <span key={i}>AARON FOWLER · KIMCHI & CHIPS · ANTOINE GRENEZ · MIA VON DALZ · PETER EMANUELOV · JUNSOO KIM · STUDIO LOCUS SOLUS · JAEWON KANG · MIT REALITY HACK · WEBZERO · EXCALIBUR · HIGHTECH SEOUL · QUINCY · CHANOIRS · </span>
        ))}
      </div>
    </div>
  );
}

function ManifestoSection() {
  return (
    <section className="manifesto" data-screen-label="Manifesto">
      <div className="section-head">
        <span className="num">01</span>
        <span className="label">WHAT 하나됨 · HANADUM</span>
      </div>
      <h2 className="section-title">One for all, <span className="accent">all for one</span>.</h2>
      <div className="manifesto-body">
        <p>There are places where things don't mix. Where art stays in its square. Where technology stays in its conference room. Where gaming stays in its arena. Where music stays in its club. Separate worlds. Separate generations.</p>
        <p className="manifesto-lead">하나됨 means unity. Not the unity of sameness. The unity that happens when different minds share a space, a culture, a past, and something starts to be created. Something that couldn't exist alone.</p>
      </div>
    </section>
  );
}

function TrackRecordSection() {
  return (
    <section className="trackrecord" data-screen-label="Track Record">
      <div className="section-head">
        <span className="num">02</span>
        <span className="label">PREVIOUSLY</span>
      </div>
      <h2 className="section-title">Five years of building <span className="accent">what's next</span>.</h2>
      <div className="tr-grid">
        <div className="tr-edition">
          <div className="tr-tag">2022 · BASEL</div>
          <div className="tr-edition-sub">Art Basel Edition</div>
          <div className="tr-stats tr-stats-4">
            <div><b>11</b><span>EU Artists</span></div>
            <div><b>1,800</b><span>Attendees</span></div>
            <div><b>2</b><span>Parties</span></div>
            <div><b>5</b><span>Days</span></div>
          </div>
        </div>
        <div className="tr-edition">
          <div className="tr-tag">2023 · MIT</div>
          <div className="tr-edition-sub">MIT Media Labs Hackathon</div>
          <div className="tr-stats tr-stats-4">
            <div><b>600</b><span>Hackers</span></div>
            <div><b>15</b><span>Sponsors</span></div>
            <div><b>6</b><span>Artists</span></div>
            <div><b>4</b><span>Days</span></div>
          </div>
        </div>
        <div className="tr-edition tr-edition-wide">
          <div className="tr-tag">2024 · BRUSSELS</div>
          <div className="tr-edition-sub">Digital AF · EthCC Edition</div>
          <div className="tr-stats tr-stats-4">
            <div><b>5,500+</b><span>Visitors</span></div>
            <div><b>20+</b><span>Sponsors</span></div>
            <div><b>50+</b><span>Artists</span></div>
            <div><b>50+</b><span>Speakers</span></div>
            <div><b>6+</b><span>Parties</span></div>
            <div><b>5</b><span>Days</span></div>
          </div>
        </div>
        <div className="tr-edition tr-edition-wide">
          <div className="tr-tag">2025–26 · CANNES</div>
          <div className="tr-edition-sub">EthCC Main Stage · Brand Experiences</div>
          <div className="tr-stats tr-stats-4">
            <div><b>8,000+</b><span>EthCC Attendees</span></div>
            <div><b>60+</b><span>Countries</span></div>
            <div><b>4</b><span>Brand Events</span></div>
            <div><b>2,500+</b><span>Attendees</span></div>
          </div>
        </div>
      </div>
      <div className="tr-cta">BASEL · MIT · BRUSSELS · CANNES · SEOUL — NOW SCALING TO ASIA →</div>
    </section>
  );
}

function WhatWellDoSection() {
  return (
    <section className="whatwell" data-screen-label="What We'll Do">
      <div className="section-head">
        <span className="num">03</span>
        <span className="label">WHAT WE'LL DO</span>
      </div>
      <h2 className="section-title">Plugged into <span className="accent">Korea Blockchain Week</span>.</h2>
      <p className="whatwell-intro">
        Korea Blockchain Week 2026 brings the global Web3 / culture / builder crowd to Seoul.
        Digital AF Seoul converts that attention into a five-day cultural convergence — and stays
        on after KBW closes, to host the long-form moment.
      </p>

      <div className="whatwell-grid">
        <div className="whatwell-card ww-kbw">
          <div className="ww-tag">THE MOMENT</div>
          <h3>Korea Blockchain Week 2026</h3>
          <div className="ww-meta">SEP 1 → SEP 7 · SEOUL</div>
          <ul className="ww-stats">
            <li><b>15,000+</b><span>Attendees</span></li>
            <li><b>200+</b><span>Speakers</span></li>
            <li><b>80+</b><span>Countries</span></li>
            <li><b>7</b><span>Days</span></li>
          </ul>
          <p className="ww-text">Highest concentration of builders, investors, collectors and creators that Seoul sees all year.</p>
        </div>

        <div className="whatwell-card ww-daf">
          <div className="ww-tag">OUR RESPONSE</div>
          <h3>Digital AF Seoul</h3>
          <div className="ww-meta">SEP 28 → OCT 02 · LAYER41</div>
          <ul className="ww-stats">
            <li><b>5</b><span>Days</span></li>
            <li><b>4</b><span>Disciplines</span></li>
            <li><b>5,000+</b><span>Attendees / day</span></li>
            <li><b>1,500m²</b><span>Venue · 3 levels</span></li>
          </ul>
          <p className="ww-text">We extend Seoul's attention window — turning a tech week into a multi-disciplinary cultural moment.</p>
        </div>
      </div>

      <div className="whatwell-flow">
        <div className="ww-flow-step">
          <span className="ww-flow-num">01</span>
          <span className="ww-flow-label">KBW lands in Seoul</span>
        </div>
        <span className="ww-flow-sep">→</span>
        <div className="ww-flow-step">
          <span className="ww-flow-num">02</span>
          <span className="ww-flow-label">3 weeks of warm-up</span>
        </div>
        <span className="ww-flow-sep">→</span>
        <div className="ww-flow-step">
          <span className="ww-flow-num">03</span>
          <span className="ww-flow-label">DAF takes Layer41 for 5 days</span>
        </div>
        <span className="ww-flow-sep">→</span>
        <div className="ww-flow-step">
          <span className="ww-flow-num">04</span>
          <span className="ww-flow-label">12-month afterlife</span>
        </div>
      </div>
    </section>
  );
}

function SeoulNetworkSection() {
  const contacts = [
    { name: 'MIT', role: 'INSTITUTION',     desc: 'Massachusetts Institute of Technology · home of Media Lab and Reality Hack.' },
    { name: 'Chanoirs App', role: 'BUILDER', desc: 'Cultural platform for Brussels venues, commissioned by the City of Brussels.' },
    { name: 'Permit', role: 'COLLECTIVE',    desc: 'Seoul collective turning unconventional spaces into the city\'s most coveted dancefloors.' },
    { name: 'HighTech Seoul', role: 'PARTY DIRECTION', desc: 'High-Tech Seoul gathers techno legends and local forces across three stages.' },
    { name: 'Hadone', role: 'ARTIST',        desc: 'France\'s rising techno force, blending raw 90\'s energy with cutting-edge sound.' },
    { name: 'Henry Simon', role: 'INSTITUTION', desc: 'Former Minister of Culture of Brussels.' },
    { name: 'Grida', role: 'CURATOR',        desc: 'Curator of Korean Blockchain Week.' },
  ];

  const W = 1700, H = 660, cx = W / 2, cy = H / 2, rx = 420, ry = 230;

  return (
    <section className="seoul-network" data-screen-label="Seoul Network">
      <div className="section-head">
        <span className="num">04</span>
        <span className="label">COLLABORATORS · 2026</span>
      </div>
      <h2 className="section-title">Who? <span className="accent">One roof.</span></h2>

      <p className="seoul-network-intro">
        Institutions · Artists · Builders · Brands. Our 2026 collaborators sharing the Layer41 container.
      </p>

      <div className="seoul-web">
        <svg viewBox={`0 0 ${W} ${H}`} role="img" aria-label="Seoul partner network">
          <ellipse cx={cx} cy={cy} rx={rx} ry={ry} fill="none" stroke="var(--line)" strokeDasharray="2 8" opacity="0.5"/>
          <ellipse cx={cx} cy={cy} rx={rx * 0.62} ry={ry * 0.62} fill="none" stroke="var(--line)" strokeDasharray="2 8" opacity="0.3"/>

          {contacts.map((c, i) => {
            const ang = (i / contacts.length) * Math.PI * 2 - Math.PI / 2;
            const x = cx + Math.cos(ang) * rx;
            const y = cy + Math.sin(ang) * ry;
            return (
              <line
                key={`l-${i}`}
                x1={cx} y1={cy} x2={x} y2={y}
                stroke="var(--accent)" strokeWidth="1.2" opacity="0.45"
                strokeDasharray="4 6"
                className="seoul-line"
                style={{ animationDelay: `${i * 0.18}s` }}
              />
            );
          })}

          {contacts.map((c, i) => {
            const ang = (i / contacts.length) * Math.PI * 2 - Math.PI / 2;
            const x = cx + Math.cos(ang) * rx;
            const y = cy + Math.sin(ang) * ry;
            const lx = cx + Math.cos(ang) * (rx + 36);
            const ly = cy + Math.sin(ang) * (ry + 50);
            const cosA = Math.cos(ang);
            const sinA = Math.sin(ang);
            let anchor = 'middle';
            if (cosA > 0.2) anchor = 'start';
            else if (cosA < -0.2) anchor = 'end';
            let dyOffset = 6;
            if (sinA < -0.6) dyOffset = -10;
            else if (sinA > 0.6) dyOffset = 26;
            return (
              <g key={`n-${i}`} className="seoul-node" style={{ animationDelay: `${i * 0.25}s` }}>
                <circle cx={x} cy={y} r="20" fill="none" stroke="var(--accent)" strokeWidth="1" opacity="0.35"/>
                <circle cx={x} cy={y} r="11" fill="var(--bg)" stroke="var(--accent)" strokeWidth="1.5"/>
                <circle cx={x} cy={y} r="4" fill="var(--accent)"/>
                <text
                  x={lx} y={ly + dyOffset}
                  textAnchor={anchor}
                  fill="var(--fg)"
                  fontFamily="Anton, sans-serif"
                  fontSize="26"
                  letterSpacing="0.5"
                >{c.name}</text>
                <text
                  x={lx} y={ly + dyOffset + 20}
                  textAnchor={anchor}
                  fill="var(--accent)"
                  fontFamily="'JetBrains Mono', monospace"
                  fontSize="13"
                  letterSpacing="2"
                >{c.role}</text>
              </g>
            );
          })}

          <g className="seoul-hub">
            <circle cx={cx} cy={cy} r="86" fill="none" stroke="var(--accent)" strokeWidth="1" opacity="0.2"/>
            <circle cx={cx} cy={cy} r="72" fill="none" stroke="var(--accent)" strokeWidth="1" opacity="0.4"/>
            <circle cx={cx} cy={cy} r="58" fill="var(--accent)"/>
            <text x={cx} y={cy - 4} textAnchor="middle" fill="#0a0a0a" fontFamily="Anton, sans-serif" fontSize="20" letterSpacing="0.5">DIGITAL AF</text>
            <text x={cx} y={cy + 22} textAnchor="middle" fill="#0a0a0a" fontFamily="'Black Han Sans', 'Noto Sans KR', sans-serif" fontSize="22">하나됨</text>
          </g>
        </svg>
      </div>

      <div className="seoul-list">
        {contacts.map((c, i) => (
          <div className="sn-item" key={i}>
            <span className="sn-num">{String(i+1).padStart(2,'0')}</span>
            <div className="sn-info">
              <div className="sn-head">
                <span className="sn-name">{c.name}</span>
                <span className="sn-role">{c.role}</span>
              </div>
              <p className="sn-desc">{c.desc}</p>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

function VenueSection() {
  return (
    <section className="venue" data-screen-label="Venue">
      <div className="section-head">
        <span className="num">05</span>
        <span className="label">WHERE · LAYER41</span>
      </div>
      <h2 className="section-title">The <span className="accent">container</span>.</h2>
      <div className="venue-gallery">
        <div className="venue-photo venue-photo-main">
          <img src="assets/venue-main.jpg" alt="Layer41 main hall — 9m ceiling, mezzanine"/>
          <span className="venue-tag">MAIN HALL · 9m CEILING</span>
        </div>
        <div className="venue-photo venue-photo-side">
          <img src="assets/venue-side.jpg" alt="Layer41 connected levels view"/>
          <span className="venue-tag">3 CONNECTED LEVELS</span>
        </div>
        <div className="venue-photo venue-photo-plan">
          <img src="assets/venue-plan.jpg" alt="Layer41 architectural elevation"/>
          <span className="venue-tag">ELEVATION · A / B / C</span>
        </div>
      </div>
      <div className="venue-info">
        <div className="venue-sub">Industrial steel factory · converted into cultural venue · used by international luxury brands</div>
        <ul className="venue-stats">
          <li><b>~1,500 m²</b><span>Total surface</span></li>
          <li><b>3</b><span>Connected levels (A · B · C)</span></li>
          <li><b>9 m</b><span>Main hall ceiling</span></li>
          <li><b>5,000+</b><span>Capacity / day</span></li>
        </ul>
        <p className="venue-text">
          We use Layer41's three levels to enable vertical circulation and overlapping experiences —
          art, hackathon, esport and party coexisting inside one industrial container.
        </p>
      </div>
    </section>
  );
}

function EventsSection() {
  const [portfolioFor, setPortfolioFor] = React.useState(null);
  return (
    <section className="events" id="events" data-screen-label="Events">
      <div className="section-head">
        <span className="num">06</span>
        <span className="label">THE FOUR FLOORS</span>
      </div>
      <h2 className="section-title">What's in the <span className="accent">building</span>.</h2>
      <div className="events-grid">
        {EVENTS.map((e, i) => (
          <EventCard key={e.id} event={e} idx={i} onCta={() => setPortfolioFor(e)}/>
        ))}
      </div>
      {portfolioFor && <PortfolioModal event={portfolioFor} onClose={() => setPortfolioFor(null)}/>}
    </section>
  );
}

function EventCard({ event, idx, onCta }) {
  const cats = [
    <CatProwl size={120} color="var(--fg)"/>,
    <CatRun size={140} color="var(--fg)"/>,
    <CatSit size={120} color="var(--fg)"/>,
    <CatTag size={120} color="var(--fg)"/>,
  ];
  return (
    <article
      id={`event-${event.id}`}
      className="event-card"
      style={{'--card-accent': event.accent}}
    >
      <div className="ec-top">
        <span className="ec-num">0{idx+1}</span>
        <span className="ec-label">{event.label}</span>
      </div>

      <div className="ec-photo">
        {event.youtube ? (
          <iframe
            className="ec-photo-iframe"
            src={`https://www.youtube.com/embed/${event.youtube}?autoplay=1&mute=1&loop=1&playlist=${event.youtube}&controls=1&modestbranding=1&rel=0`}
            title={event.title}
            frameBorder="0"
            allow="autoplay; encrypted-media; picture-in-picture"
            allowFullScreen
            loading="lazy"
          />
        ) : event.iframe ? (
          <iframe
            className="ec-photo-iframe"
            src={event.iframe}
            title={event.title}
            frameBorder="0"
            allow="autoplay; fullscreen; xr-spatial-tracking"
            allowFullScreen
            loading="lazy"
          />
        ) : event.photo ? (
          <img src={event.photo} alt={event.title}/>
        ) : (
          <div className={`ec-photo-fallback ${idx % 2 === 1 ? 'wireframe-cat' : ''}`}>
            {cats[idx]}
            <span className="ec-photo-tbd">PHOTO · TBC</span>
          </div>
        )}
        <span className="ec-photo-corner">{event.label}</span>
      </div>

      <div className="ec-body">
        <h3 className="ec-title">{event.title}</h3>
        <div className="ec-sub">{event.subtitle}</div>
        <p className="ec-blurb">{event.blurb}</p>
        <ul className="ec-meta">
          {event.meta.map((m, j) => <li key={j}>{m}</li>)}
        </ul>
      </div>

      <div className="ec-deep">
        <p className="ec-deep-hero">{event.deep.hero}</p>
        <div className="ec-keywords">
          {event.deep.keywords.map((kw, j) => (
            <span className="ec-kw" key={j}>{kw}</span>
          ))}
        </div>
        {event.deep.special && <EventSpecial special={event.deep.special} accent={event.accent}/>}
        <button className="ec-deep-cta" onClick={onCta} style={{background: event.accent}}>
          {event.deep.cta} →
        </button>
      </div>
    </article>
  );
}

function EventSpecial({ special, accent }) {
  if (special.type === 'app') {
    return (
      <div className="ec-special ec-special-app">
        <div className="ec-special-tag">{special.tag}</div>
        <h4 className="ec-special-title">{special.title}</h4>
        <p className="ec-special-text">{special.text}</p>
        <div className="ec-special-video">
          {special.youtube ? (
            <iframe
              src={`https://www.youtube.com/embed/${special.youtube}?autoplay=1&mute=1&loop=1&playlist=${special.youtube}&controls=1&modestbranding=1&rel=0`}
              title={special.title}
              frameBorder="0"
              allow="autoplay; encrypted-media; picture-in-picture"
              allowFullScreen
              loading="lazy"
            />
          ) : (
            <div className="ec-video-placeholder">
              <span className="ec-video-label">▶ DEMO REEL</span>
              <span className="ec-video-note">{special.videoNote}</span>
            </div>
          )}
        </div>
        {special.videoNote && special.youtube && (
          <span className="ec-video-note">{special.videoNote}</span>
        )}
      </div>
    );
  }
  if (special.type === 'note') {
    return (
      <div className="ec-special ec-special-note">
        <div className="ec-special-tag">{special.tag}</div>
        <h4 className="ec-special-title">{special.title}</h4>
        <p className="ec-special-text">{special.text}</p>
      </div>
    );
  }
  if (special.type === 'roster') {
    return (
      <div className="ec-special ec-special-roster">
        <div className="ec-special-tag">{special.tag}</div>
        <div className="ec-roster-headliner">
          <div className="ec-roster-photo">
            {special.headliner.photo ? (
              <img src={special.headliner.photo} alt={special.headliner.name}/>
            ) : (
              <span className="ec-photo-tbd">PHOTO · TBC</span>
            )}
          </div>
          <div className="ec-roster-info">
            <div className="ec-roster-role">{special.headliner.role}</div>
            <div className="ec-roster-name">{special.headliner.name}</div>
            <p className="ec-roster-desc">{special.headliner.desc}</p>
          </div>
        </div>
        <ul className="ec-roster-list">
          {special.roster.map((r, j) => (
            <li key={j}>
              <span className="ec-roster-country">{r.country}</span>
              <span className="ec-roster-rname">{r.name}</span>
              <span className="ec-roster-rrole">{r.role}</span>
            </li>
          ))}
        </ul>
        {special.footnote && <div className="ec-roster-footnote">{special.footnote}</div>}
      </div>
    );
  }
  return null;
}

function PortfolioModal({ event, onClose }) {
  React.useEffect(() => {
    const orig = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => { document.body.style.overflow = orig; window.removeEventListener('keydown', onKey); };
  }, [onClose]);
  return (
    <div className="portfolio-overlay" onClick={onClose}>
      <div className="portfolio-modal" onClick={(e) => e.stopPropagation()} style={{'--card-accent': event.accent}}>
        <button className="portfolio-close" onClick={onClose} aria-label="Close">×</button>
        <div className="portfolio-head">
          <span className="portfolio-tag" style={{color: event.accent}}>{event.label} · PORTFOLIO</span>
          <h3 className="portfolio-title">Past experiences.</h3>
          <p className="portfolio-sub">What we've already built that informs {event.title} in Seoul.</p>
        </div>
        <ul className="portfolio-list">
          {event.portfolio.map((p, j) => (
            <li className="portfolio-item" key={j}>
              <span className="portfolio-year">{p.year}</span>
              <span className="portfolio-name">{p.name}</span>
              <span className="portfolio-desc">{p.desc}</span>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

const TIMETABLE_DAYS = [
  { day: 'MON', date: 'Sep 28' },
  { day: 'TUE', date: 'Sep 29' },
  { day: 'WED', date: 'Sep 30' },
  { day: 'THU', date: 'Oct 01' },
  { day: 'FRI', date: 'Oct 02' },
];

const TIMETABLE_REAL = [
  { time: '09:00', label: 'MORNING',   cells: ['Opening',       'Press preview',           '—',                'Closing brunch',                       '—'] },
  { time: '14:00', label: 'AFTERNOON', cells: ['Art walk',      'Hackathon D1 · Esport D1', 'Talks',            'Esport D2 · Brand activations',        'Esport Final · Open day · Press tour'] },
  { time: '19:00', label: 'EVENING',   cells: ['Welcome party', 'Artist talks',             'Hackathon Demo',   'Awards night',                         'Pre-party'] },
  { time: '00:00', label: 'NIGHT',     cells: ['Opening party', 'DJ TBC',                   'DJ TBC',           'DJ TBC',                               'Closing party · Until sunrise'] },
];

const FAKE_POOL = [
  'How to Become Elon Musk',
  'How to Bury a Body w/ Anthropic',
  'TED: You Won\'t Have to Work Anymore',
  'Better Art than Da Vinci w/ ChatGPT 2.0',
  'Hack the CIA w/ Claude Code',
  'AI Agents to Replace All Your Employees',
  '€1 Bn/month w/ $20 sub feat. Anthropic',
  'Build Your Own AI to Replace AI ft. Claude',
  'How to Create Bad Buzz ft. Grok',
  'Lose More $$$ than Meta on Metaverse',
  'TED: Your Personal Value is Worth Nothing',
  'BDSM Session',
  'Eating Plastic Workshop',
  'ISIS Keynote',
  'Round Table Monsanto',
  'Cooking Lesson for Women',
  '1000 Blind People in the Dark',
  'Fart Concerto',
  '5h Straight Finger Clapping',
  'Cult Initiation',
  'Cosmic Despair Session',
  'Pre-Apocalypse Drinks',
  'Opening Hallucinations',
  'Existential Crisis',
];

function TimelineSection() {
  const [psych, setPsych] = React.useState(false);
  const [shuffleSeed, setShuffleSeed] = React.useState(0);

  // Reshuffle the fake events every 1.6s while psych is on
  React.useEffect(() => {
    if (!psych) return;
    const id = setInterval(() => setShuffleSeed(s => s + 1), 4500);
    return () => clearInterval(id);
  }, [psych]);

  const fakeRows = React.useMemo(() => {
    const shuffled = [...FAKE_POOL].sort(() => Math.random() - 0.5);
    return TIMETABLE_REAL.map((row, ri) => ({
      time: row.time,
      label: row.label,
      cells: Array.from({ length: 5 }, (_, ci) => shuffled[(ri * 5 + ci) % shuffled.length]),
    }));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [shuffleSeed, psych]);

  const rows = psych ? fakeRows : TIMETABLE_REAL;
  return (
    <section className="timeline" data-screen-label="Timetable">
      <div className="section-head">
        <span className="num">07</span>
        <span className="label">FIVE DAYS · ONE CONTINUOUS FORMAT</span>
      </div>
      <h2 className="section-title">Everything, <span className="accent">simultaneously</span>.</h2>

      <div className={`timetable${psych ? ' psyched' : ''}`}>
        <div className="tt-corner">TIME</div>
        {TIMETABLE_DAYS.map((d, i) => (
          <div className="tt-day" key={i}>
            <span className="tt-day-name">{d.day}</span>
            <span className="tt-day-date">{d.date}</span>
          </div>
        ))}
        {rows.map((row, ri) => (
          <React.Fragment key={`${psych}-${ri}`}>
            <div className="tt-time">
              <span className="tt-time-num">{row.time}</span>
              <span className="tt-time-label">{row.label}</span>
            </div>
            {row.cells.map((cell, ci) => (
              <div className="tt-cell" key={ci}>{cell}</div>
            ))}
          </React.Fragment>
        ))}
      </div>

      <div className="tt-footer">PROGRAMS OVERLAP. AUDIENCES MIX. THE SPACE IS OPEN ALL 5 DAYS.</div>

      <button
        className={`timeline-psych-toggle${psych ? ' on' : ''}`}
        onClick={() => setPsych(p => !p)}
        title={psych ? 'Restore reality' : 'Do not click'}
      >
        {psych ? '↺ RESTORE REALITY' : '⚠ DO NOT CLICK'}
      </button>
    </section>
  );
}

function LegacySection() {
  return (
    <section className="legacy" data-screen-label="Legacy">
      <div className="section-head">
        <span className="num">08</span>
        <span className="label">AFTER OCT 02</span>
      </div>
      <h2 className="section-title">To be <span className="accent">continued</span>.</h2>
      <p className="legacy-intro">The event lasts five days. The legacy lasts years. Here's what stays after the doors close.</p>
      <div className="legacy-grid">
        <div className="legacy-card">
          <span className="legacy-tag">EXHIBITION</span>
          <h3>The art tours.</h3>
          <p>The full exhibition travels to partner galleries in Europe and Asia after Seoul. Each artwork keeps circulating. New cities, new collectors, new press.</p>
        </div>
        <div className="legacy-card">
          <span className="legacy-tag">TECHNOLOGY</span>
          <h3>The app lives in Seoul.</h3>
          <p>The platform built by the hackathon is handed over to Seoul's cultural clubs. An open tool they keep running, long after we're gone.</p>
        </div>
        <div className="legacy-card">
          <span className="legacy-tag">KNOWLEDGE</span>
          <h3>Talks & recordings.</h3>
          <p>Public conferences, panels and workshops recorded on site. Real know-how, released as open educational content for the community.</p>
        </div>
      </div>
      <div className="legacy-foot">THE AFTERLIFE IS THE STRATEGY.</div>
    </section>
  );
}

const STRATEGIC_CARDS = [
  {
    label: 'VENUE CARD',
    title: 'Layer41 — Studio 41 (Plusjun)',
    sub: 'Industrial steel factory converted into cultural space',
    bullets: [
      '~1,500 m² across 3 connected levels (A / B / C)',
      '9 m ceiling main hall',
      'Proven use by global luxury brands',
    ],
    role: 'The venue is the container of the system. It enables vertical circulation, overlapping experiences, and coexistence of all formats.',
  },
  {
    label: 'TIMING CARD',
    title: 'Korea Blockchain Week 2026',
    sub: '15,000+ attendees · 200+ speakers · 7 days · Sept 1–7, 2026',
    bullets: [
      'Global audience from 80+ countries',
      'High concentration of builders, investors, and creators',
    ],
    role: 'We plug into an existing moment of attention and density.',
  },
  {
    label: 'ART & CURATION CARD',
    title: 'Kimchi & Chips × Aaron Fowler',
    sub: 'Mimi Son & Elliot Woods — primary curators',
    bullets: [
      'Korean artists: Junsoo Kim · Studio Locus Solus · Jaewon Kang',
      'European headliner: Aaron Fowler (USA / New York)',
      'European artists: Antoine Grenez (BE) · Mia Von Dalz · Peter Emanuelov',
    ],
    role: 'Cultural legitimacy, collector entry point, Europe ↔ Korea bridge.',
  },
  {
    label: 'COLLECTORS / MARKET CARD',
    title: 'Space M Gallery — Min Kyo Kim',
    sub: 'Strong local gallery with corporate reach',
    bullets: [
      'Direct access to collectors',
      'Corporate connections',
      'On-site collector hospitality',
    ],
    role: 'Monetization layer bridging art, brands, and collectors.',
  },
  {
    label: 'HACKERS CARD',
    title: 'MIT Reality Hack × WebZero',
    sub: 'The Seoul App — gamified cultural platform',
    bullets: [
      'Developed by MIT Reality Hack builders',
      'Technical infrastructure by WebZero',
      'Live build over 5 days, handed to Seoul cultural community',
    ],
    role: 'Engagement engine bridging digital ↔ physical experiences.',
  },
  {
    label: 'ESPORT CARD',
    title: 'Excalibur Tournament',
    sub: '3-day competition · game revealed on stage',
    bullets: [
      'Players compete on a game they have never played',
      'Local contact: Sang Joon (Glenn) Lee',
      '2,000+ on-site target · 50,000+ online via Twitch & YouTube',
    ],
    role: 'Large-scale audience energy anchoring gaming culture.',
  },
  {
    label: 'PARTY CARD',
    title: 'HighTech Seoul — Quincy',
    sub: 'Closing night · 5,000+ expected · open till sunrise',
    bullets: [
      'International + Korean line-up — TBC',
      'Direction: Quincy / HighTech Seoul (city benchmark for techno)',
      'AR/XR layers · brand takeovers running through the night',
    ],
    role: 'Final convergence moment · social and emotional peak.',
  },
  {
    label: 'PRODUCTION CARD',
    title: 'C2 ArtTechnolozy',
    sub: 'Scenography & immersive production',
    bullets: [
      'PyeongChang Olympics (1,200+ drone show)',
      'PUBG Global Championship stadium (10,000 capacity)',
      'AR/XR integration & full-venue LED programming',
    ],
    role: 'Scenography execution, AR/XR integration, coherence assurance.',
  },
  {
    label: 'BONUS CARD',
    title: 'Trinity Gallery — Irene Yu',
    sub: 'Pre/post event amplification',
    bullets: [
      'Before: Frieze Seoul (Sept 6–9) featuring Aaron Fowler',
      'After: retrospective exhibition (Oct 10 → Nov 15)',
    ],
    role: 'Collector positioning and international art circuit integration.',
  },
];

function PartnersSection() {
  return (
    <section className="partners" data-screen-label="Partners">
      <div className="section-head">
        <span className="num">09</span>
        <span className="label">THE SYSTEM · STRATEGIC CARDS</span>
      </div>
      <h2 className="section-title">The cards we <span className="accent">already hold</span>.</h2>
      <div className="strat-grid">
        {STRATEGIC_CARDS.map((c, i) => (
          <article className="strat-card" key={i}>
            <div className="strat-top">
              <span className="strat-num">{String(i+1).padStart(2,'0')}</span>
              <span className="strat-label">{c.label}</span>
            </div>
            <h3 className="strat-title">{c.title}</h3>
            <div className="strat-sub">{c.sub}</div>
            <ul className="strat-bullets">
              {c.bullets.map((b, j) => <li key={j}>{b}</li>)}
            </ul>
            <div className="strat-role">
              <span className="strat-role-tag">STRATEGIC ROLE</span>
              <p>{c.role}</p>
            </div>
          </article>
        ))}
      </div>
    </section>
  );
}

function ContactSection() {
  const [sent, setSent] = React.useState(false);
  return (
    <section className="contact" id="contact" data-screen-label="Contact">
      <div className="section-head">
        <span className="num">10</span>
        <span className="label">CONTACT US</span>
      </div>
      <div className="contact-grid">
        <div>
          <h2 className="section-title">Come <span className="accent">help us build</span> the container.</h2>
          <p className="contact-sub">Sponsors, artists, builders, DJs, collectors, chaos-makers. The event is 90% locked. The remaining 10% is interesting.</p>
          <div className="contact-channels">
            <div><span className="cc-label">EMAIL</span><a href="mailto:chenoz.pa@hotmail.fr">chenoz.pa@hotmail.fr</a></div>
            <div><span className="cc-label">PHONE / WA</span><a href="tel:+33647879698">+33 6 47 87 96 98</a></div>
            <div><span className="cc-label">SITE</span><a href="https://digitalaf.xyz" target="_blank" rel="noreferrer">digitalaf.xyz</a></div>
            <div><span className="cc-label">INSTAGRAM</span><a href="https://instagram.com/digitalaf" target="_blank" rel="noreferrer">@digitalaf</a></div>
          </div>
        </div>
        <form className="contact-form" onSubmit={(e) => { e.preventDefault(); setSent(true); }}>
          <label>NAME <input required placeholder="who are you"/></label>
          <label>EMAIL <input type="email" required placeholder="you@domain.com"/></label>
          <label>I'M HERE AS
            <select>
              <option>A sponsor</option>
              <option>An artist</option>
              <option>A hacker / builder</option>
              <option>A DJ / promoter</option>
              <option>A collector</option>
              <option>Press</option>
              <option>Just curious</option>
            </select>
          </label>
          <label>MESSAGE <textarea required rows="4" placeholder="one paragraph, no deck needed"/></label>
          <button type="submit" className="btn primary">
            {sent ? 'SENT — WE\'LL REPLY.' : 'SEND →'}
          </button>
        </form>
      </div>
      <div className="footer-foot">
        <div className="ff-left">
          <CatTag size={28} color="var(--fg)"/>
          <span>DIGITAL AF · SEOUL · 하나됨 · 2026</span>
        </div>
        <div className="ff-right">
          <span>© CHANOIRS COLLECTIVE</span>
          <span>·</span>
          <span>BRUSSELS ↔ SEOUL</span>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { EVENTS, Hero, SiteRedTrail, MarqueeBand, ManifestoSection, TrackRecordSection, WhatWellDoSection, SeoulNetworkSection, VenueSection, EventsSection, TimelineSection, LegacySection, PartnersSection, ContactSection });
