// CaseStudyJacksonWang.jsx — Jackson Wang│Magical Portal case study.
// Wrapped in IIFE so internals (CS, helper components) don't collide with
// other case studies. Same editorial layout language as the other case
// studies in this codebase.

;(function () {

const { useState: useStateCS, useEffect: useEffectCS, useRef: useRefCS } = React;

// ============ SOURCE CONTENT ============
const CS = {
  slug: 'jackson-wang-magical-portal',
  title: 'Jackson Wang│Magical portal',
  subtitle: "A pop-up installation built for Jackson Wang's 2023 US Tour — an immersive portal into the world he's built.",
  client: 'Microsoft',
  artist: 'Jackson Wang',
  label: '88 Rising',
  studio: 'Volvox Labs',
  year: 2023,
  format: 'Pop-up installation · interactive · generative',
  role: 'Creative Direction · Art / Motion Direction · UX/UI',

  lead: "A traveling pop-up that drops fans inside Jackson Wang's MAGIC MAN universe. Visitors step through a custom-built portal into worlds they already know — the dark, magical landscapes pulled straight from his music videos — and leave with a take-home artifact of his world.",

  blocks: [
    {
      no: '01',
      key: 'magic-man',
      eyebrow: '01 — Magic Man',
      title: 'Magic Man.',
      body: [
        "Anchored in the visual language of Jackson Wang's MAGIC MAN album. Type, color, motion, and sound are all keyed to the record — a one-to-one translation from the artwork into a physical space fans can walk into.",
        'A briefing room before the journey: an introduction to the world and the rules, set to the album as score.',
      ],
      image: 'site/assets/02_PROJECT/2023/JACKSON%20WANG/12984.jpg',
      cornerTl: 'BLOCK 01 / MAGIC MAN',
      cornerBr: 'ALBUM IDENTITY',
    },
    {
      no: '02',
      key: 'world-building',
      eyebrow: '02 — World Building',
      title: 'World Building.',
      body: [
        "A sequence of three stylized environments drawn directly from Jackson Wang's MAGIC MAN universe — Blow, Cruel, and Come Alive. Each room is its own beat in the journey: distinct enough to stand alone, consistent enough to feel like one place.",
        'Working from original production source files used in the music videos themselves, the Volvox Labs team extended each world beyond the screen — rebuilding them as extended spaces beyond the portal where fans step into the imagery they already know by heart.',
      ],
      worlds: [
        {
          label: 'WORLD 01',
          title: 'Cruel',
          vimeo: 'https://player.vimeo.com/video/879434759?h=eafc910b16&autoplay=1&loop=1&muted=1&background=1',
          aspect: '16/9',
          stills: [
            'site/assets/02_PROJECT/2023/JACKSON%20WANG/MV5BYWMxZTAxZDEtNjZlNy00NTg3LWE0NjctZWExZDc1NDYzNmQxXkEyXkFqcGc%40._V1_.jpg',
            'site/assets/02_PROJECT/2023/JACKSON%20WANG/Screenshot%202026-05-01%20161745.png',
          ],
          cornerTl: 'BLOCK 02 / WORLDS',
          cornerBr: 'ENVIRONMENTS',
        },
        {
          label: 'WORLD 02',
          title: 'Blow',
          vimeo: 'https://player.vimeo.com/video/879434570?h=ec496b1dab&autoplay=1&loop=1&muted=1&background=1',
          aspect: '16/9',
          stills: [
            'site/assets/02_PROJECT/2023/JACKSON%20WANG/magic-man-experience-2.jpg',
            'site/assets/02_PROJECT/2023/JACKSON%20WANG/Screenshot%202026-05-01%20171222.png',
          ],
          cornerTl: 'BLOCK 02 / WORLDS',
          cornerBr: 'ENVIRONMENTS',
        },
        {
          label: 'WORLD 03',
          title: 'Come Alive',
          vimeo: 'https://player.vimeo.com/video/879434679?h=c064de1729&autoplay=1&loop=1&muted=1&background=1',
          aspect: '16/9',
          stills: [
            'site/assets/02_PROJECT/2023/JACKSON%20WANG/Screenshot%202026-05-01%20161405.png',
            'site/assets/02_PROJECT/2023/JACKSON%20WANG/Screenshot%202026-05-01%20160024.png',
          ],
          cornerTl: 'BLOCK 02 / WORLDS',
          cornerBr: 'ENVIRONMENTS',
        },
      ],
      subblocks: [
        {
          title: 'Distinct Interactive FX',
          body: 'Each world responds to the people in it. Movement is tracked in real time, triggering scene-specific FX that match the language of that environment — so every visitor leaves a different trace through the space.',
          vimeo: 'https://player.vimeo.com/video/822054517?autoplay=1&loop=1&muted=1&background=1',
          aspect: '16/9',
        },
      ],
    },
    {
      no: '03',
      key: 'magic-elevator',
      eyebrow: '03 — The Magic Elevator',
      title: 'The Magic Elevator.',
      body: [
        'A custom-built elevator as the connective device between worlds. Step in, the doors close, the floor changes — open them and the world has shifted. Architecture and content tuned together so the transition reads as a single moment.',
      ],
      vimeo: 'https://player.vimeo.com/video/822054761?autoplay=1&loop=1&muted=1&background=1',
      stills: [
        'site/assets/02_PROJECT/2023/JACKSON%20WANG/Screenshot%202026-05-01%20171720.png',
      ],
      cornerTl: 'BLOCK 03 / ELEVATOR',
      cornerBr: 'INTERACTIVE',
    },
    {
      no: '04',
      key: 'ai-takeaway',
      eyebrow: "04 — Microsoft's Cognitive Services",
      title: 'Microsoft’s Cognitive Services: Ai Takeaway.',
      body: [
        "Microsoft Cognitive Services drives the AI takeaway moment — visitors are captured, processed, and rendered back as a personalized portrait inside the MAGIC MAN visual system.",
        'A real-time pipeline: capture, process, generate, deliver — within the rhythm of the queue. Visitors leave with a keepsake that lives on their phones, in their feeds, and past the night of the show.',
      ],
      vimeo: 'https://player.vimeo.com/video/844391297?h=9630abacf6&autoplay=1&loop=1&muted=1&background=1',
      cornerTl: 'BLOCK 04 / AI TAKEAWAY',
      cornerBr: 'MICROSOFT · COGNITIVE',
    },
  ],

  credits: [
    { role: 'Artist',                   who: 'Jackson Wang' },
    { role: 'Label',                    who: '88 Rising' },
    { role: 'Client',                   who: 'Microsoft' },
    { role: 'Creative Direction Label', who: 'Brandon Mai' },
    { divider: true },
    { role: 'Studio',                   who: 'Volvox Labs' },
    { role: 'Creative Direction',       who: 'Pasakorn Nontananadh' },
    { role: 'Motion Design',            who: 'Siriphong Tipayakesorn' },
    { role: 'Technical Direction',      who: 'Ben Forest' },
    { role: 'Creative Technologist',    who: 'Matt Ross' },
    { role: 'Sound Composition',        who: 'Javier Cruz' },
    { role: 'Production',               who: 'Gilad Dor' },
    { role: 'Visual FX',                who: 'Chatrin Samanchuen · Sophia Holland' },
    { role: 'BTS Director',             who: 'Rodrigo Olivar' },
  ],
};

// =====================================================================
// Shared atoms — scoped to this IIFE.
// =====================================================================

function MonoLabel({ children, dim, size = 11, style }) {
  return (
    <div style={{
      fontFamily: "'JetBrains Mono', SFMono-Regular, Menlo, monospace",
      fontSize: size, letterSpacing: '0.16em',
      color: dim ? 'var(--ak-fg-2)' : 'var(--ak-fg)',
      textTransform: 'uppercase',
      ...style,
    }}>{children}</div>
  );
}

const proseP = {
  fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
  fontSize: 17, lineHeight: 1.55, letterSpacing: '-0.005em',
  fontWeight: 400, color: 'var(--ak-fg-2)',
  margin: '20px 0 0',
};

function ProseSection({ eyebrow, title, children, dark }) {
  return (
    <section style={{
      padding: '120px 32px',
      background: dark ? 'var(--ak-bg-3)' : 'var(--ak-bg)',
      color: dark ? 'var(--ak-fg-on3)' : 'var(--ak-fg)',
      borderTop: '1px solid var(--ak-line)',
    }}>
      <div style={{ maxWidth: 1280, margin: '0 auto', display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: 64, alignItems: 'start' }}>
        <Reveal>
          <MonoLabel dim>{eyebrow}</MonoLabel>
          <h2 style={{
            fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
            fontSize: 'clamp(36px, 4vw, 56px)', lineHeight: 1.05,
            letterSpacing: '-0.02em', fontWeight: 400,
            margin: '20px 0 0',
            color: dark ? 'var(--ak-fg-on3)' : 'var(--ak-fg)',
            textWrap: 'balance',
          }}>
            {title}
          </h2>
        </Reveal>
        <Reveal y={28} delay={120} style={{ marginTop: 14 }}>
          <div style={{ color: dark ? 'var(--ak-fg-2-on3)' : 'var(--ak-fg-2)' }}>
            {children}
          </div>
        </Reveal>
      </div>
    </section>
  );
}

function CornerMeta({ tl, br }) {
  return (
    <>
      {tl && (
        <div style={{
          position: 'absolute', top: 16, right: 16,
          fontFamily: "'JetBrains Mono', monospace", fontSize: 10,
          letterSpacing: '0.14em', color: 'rgba(255,255,255,0.7)',
          textTransform: 'uppercase',
        }}>{tl}</div>
      )}
      {br && (
        <div style={{
          position: 'absolute', bottom: 16, right: 16,
          fontFamily: "'JetBrains Mono', monospace", fontSize: 10,
          letterSpacing: '0.14em', color: 'rgba(255,255,255,0.7)',
          textTransform: 'uppercase',
        }}>{br}</div>
      )}
    </>
  );
}

function PlaceholderTag({ children }) {
  return (
    <div style={{
      position: 'absolute', top: 16, left: 16,
      padding: '5px 10px',
      background: 'rgba(255,255,255,0.92)', color: '#0a0b0d',
      borderRadius: 999,
      fontFamily: "'JetBrains Mono', monospace",
      fontSize: 9, letterSpacing: '0.14em', fontWeight: 600,
      textTransform: 'uppercase',
    }}>
      [ placeholder ] {children}
    </div>
  );
}

function BlockMedia({ block }) {
  const placeholderGradient = 'radial-gradient(ellipse at 50% 50%, #1a1a1a 0%, #0a0b0d 60%, #050505 100%)';
  const hasMedia = block.image || block.video || block.vimeo;

  // worlds branch — stacked, repeatable: each world renders
  //   [label + title] → [big 16:9 video] → [2 stills side-by-side]
  if (block.worlds && block.worlds.length) {
    return (
      <div style={{ maxWidth: 1280, margin: '0 auto' }}>
        {block.worlds.map((w, wi) => {
          const stills = w.stills || [];
          const hasMedia = w.vimeo || w.video || w.image;
          return (
            <div key={wi} style={{ marginTop: wi === 0 ? 0 : 96 }}>
              <Reveal>
                <div style={{ marginBottom: hasMedia ? 32 : 0 }}>
                  {w.label && <MonoLabel dim>{w.label}</MonoLabel>}
                  <h3 style={{
                    fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
                    fontSize: 'clamp(36px, 4vw, 56px)', lineHeight: 1.05,
                    letterSpacing: '-0.02em', fontWeight: 400,
                    margin: w.label ? '20px 0 0' : 0,
                    textWrap: 'balance',
                  }}>
                    {w.title}
                  </h3>
                </div>
              </Reveal>

              {hasMedia && (
                <Reveal y={20}>
                  <div style={{
                    position: 'relative', overflow: 'hidden', borderRadius: 16,
                    background: '#0a0b0d',
                    border: '1px solid var(--ak-line)',
                    aspectRatio: w.aspect || '16/9',
                    width: '100%',
                  }}>
                    {w.vimeo ? (
                      <iframe
                        src={w.vimeo}
                        title={w.title}
                        frameBorder="0"
                        referrerPolicy="strict-origin-when-cross-origin"
                        allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share"
                        allowFullScreen
                        style={{
                          position: 'absolute', top: 0, left: 0,
                          width: '100%', height: '100%',
                          border: 0,
                        }}
                      />
                    ) : w.video ? (
                      <video src={w.video} autoPlay loop muted playsInline
                        style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                    ) : (
                      <img src={w.image} alt={w.title}
                        style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                    )}
                    <CornerMeta tl={w.cornerTl} br={w.cornerBr} />
                  </div>
                </Reveal>
              )}

              {stills.length > 0 && (
                <div style={{
                  display: 'grid',
                  gridTemplateColumns: `repeat(${Math.min(stills.length, 2)}, 1fr)`,
                  gap: 16,
                  marginTop: 16,
                }}>
                  {stills.slice(0, 2).map((src, i) => (
                    <Reveal key={src} y={20} delay={i * 100}>
                      <div style={{
                        position: 'relative', overflow: 'hidden',
                        aspectRatio: '16/9',
                        borderRadius: 12,
                        background: '#0a0b0d',
                        border: '1px solid var(--ak-line)',
                      }}>
                        <img src={src} alt={`${w.title} still ${i + 1}`}
                          style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                      </div>
                    </Reveal>
                  ))}
                </div>
              )}
            </div>
          );
        })}
      </div>
    );
  }

  return (
    <Reveal y={20}>
      <div style={{
        maxWidth: 1280, margin: '0 auto',
        borderRadius: 16, overflow: 'hidden',
        background: '#0a0b0d',
        border: '1px solid var(--ak-line)',
        position: 'relative',
        aspectRatio: block.vimeo ? '16/9' : (hasMedia ? undefined : '16/9'),
      }}>
        {block.vimeo ? (
          <iframe
            src={block.vimeo}
            title={block.title}
            frameBorder="0"
            referrerPolicy="strict-origin-when-cross-origin"
            allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share"
            allowFullScreen
            style={{
              position: 'absolute', top: 0, left: 0,
              width: '100%', height: '100%',
              border: 0,
            }}
          />
        ) : block.video ? (
          <video
            src={block.video}
            autoPlay
            loop
            muted
            playsInline
            style={{ width: '100%', height: 'auto', display: 'block' }}
          />
        ) : block.image ? (
          <img src={block.image} alt={block.title}
            style={{ width: '100%', height: 'auto', display: 'block' }} />
        ) : (
          <div style={{ position: 'absolute', inset: 0, background: placeholderGradient }} />
        )}
        {!hasMedia && <PlaceholderTag>{block.key}</PlaceholderTag>}
        <CornerMeta tl={block.cornerTl} br={block.cornerBr} />
      </div>
    </Reveal>
  );
}

function CreditsBlock() {
  return (
    <section style={{
      padding: '72px 32px',
      background: 'var(--ak-bg)',
      borderTop: '1px solid var(--ak-line)',
    }}>
      <div style={{ maxWidth: 768, margin: '0 auto' }}>
        <Reveal>
          <MonoLabel dim style={{ marginBottom: 28 }}>05 — Credits</MonoLabel>
        </Reveal>
        <Reveal y={20} delay={120}>
          <table style={{
            width: '100%', borderCollapse: 'collapse',
            fontFamily: "'JetBrains Mono', monospace", fontSize: 10, letterSpacing: '0.04em',
          }}>
            <tbody>
              {CS.credits.map((row, i) => {
                if (row.divider) {
                  return (
                    <tr key={i}><td colSpan="2" style={{ height: 14 }} /></tr>
                  );
                }
                return (
                  <tr key={i} style={{ borderTop: '1px solid var(--ak-line)' }}>
                    <td style={{ padding: '10px 10px 10px 0', color: 'var(--ak-fg-2)', textTransform: 'uppercase', whiteSpace: 'nowrap', verticalAlign: 'top', width: 220 }}>{row.role}</td>
                    <td style={{ padding: '10px 0', color: 'var(--ak-fg)' }}>{row.who}</td>
                  </tr>
                );
              })}
              <tr style={{ borderTop: '1px solid var(--ak-line)' }}><td colSpan="2" style={{ height: 0 }} /></tr>
            </tbody>
          </table>
        </Reveal>
      </div>
    </section>
  );
}

// =====================================================================
// CASE STUDY — editorial long-form
// =====================================================================

function CaseStudyA({ onNavigate }) {
  return (
    <div style={{ background: 'var(--ak-bg)', color: 'var(--ak-fg)' }}>

      {/* HERO */}
      <section style={{ padding: '40px 32px 24px', borderBottom: '1px solid var(--ak-line)' }}>
        <div style={{ maxWidth: 1280, margin: '0 auto' }}>
          <Reveal y={20}>
            <button onClick={() => onNavigate && onNavigate('work')}
              style={{
                background: 'transparent', border: 'none', padding: 0, cursor: 'pointer',
                fontFamily: "'JetBrains Mono', monospace", fontSize: 12,
                letterSpacing: '0.14em', textTransform: 'uppercase',
                color: 'var(--ak-fg-2)',
                display: 'inline-flex', alignItems: 'center', gap: 8,
                marginBottom: 24,
                transition: 'color 200ms cubic-bezier(0.2,0.6,0.2,1)',
              }}
              onMouseEnter={(e) => { e.currentTarget.style.color = 'var(--ak-fg)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.color = 'var(--ak-fg-2)'; }}>
              <span style={{ display: 'inline-block', transition: 'transform 240ms cubic-bezier(0.2,0.6,0.2,1)' }}>←</span>
              back to work
            </button>
          </Reveal>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 48, alignItems: 'end', marginTop: 0 }}>
            <Reveal y={32}>
              <h1 style={{
                fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
                fontSize: 'clamp(48px, 6vw, 88px)',
                lineHeight: 0.92,
                letterSpacing: '-0.04em',
                fontWeight: 400,
                margin: 0,
              }}>
                Jackson Wang<br />Magical portal<span style={{ color: 'var(--ak-blue, #0052ff)' }}>.</span>
              </h1>
            </Reveal>
            <Reveal y={32} delay={120}>
              <p style={{
                fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
                fontSize: 16, lineHeight: 1.4, letterSpacing: '-0.005em',
                color: 'var(--ak-fg)', margin: 0, maxWidth: 460,
              }}>
                {CS.subtitle}
              </p>
            </Reveal>
          </div>
        </div>
      </section>

      {/* HERO MEDIA */}
      <section style={{ padding: '0 32px', background: 'var(--ak-bg)' }}>
        <Reveal y={20}>
          <div style={{
            maxWidth: 1280, margin: '20px auto 0',
            borderRadius: 16, overflow: 'hidden',
            background: '#0a0b0d',
            border: '1px solid var(--ak-line)',
            position: 'relative',
          }}>
            <video
              src="site/assets/02_PROJECT/2023/JACKSON%20WANG/VDO/magicman_experience-1080p%20(1).mp4"
              autoPlay
              loop
              muted
              playsInline
              style={{ width: '100%', height: 'auto', display: 'block' }}
            />
            <CornerMeta tl="JACKSON WANG / MAGIC MAN" br={`POP-UP · ${CS.year}`} />
          </div>
        </Reveal>
      </section>

      {/* AT A GLANCE STRIP */}
      <section style={{ padding: '64px 32px 32px' }}>
        <div style={{ maxWidth: 1280, margin: '0 auto',
          display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 24,
          paddingTop: 32, borderTop: '1px solid var(--ak-line)',
        }}>
          {[
            ['artist', CS.artist],
            ['label',  CS.label],
            ['client', CS.client],
            ['studio', CS.studio],
            ['year',   CS.year],
            ['role',   CS.role],
          ].map(([k, v], i) => (
            <Reveal key={k} delay={i * 50}>
              <MonoLabel dim style={{ marginBottom: 10 }}>{k}</MonoLabel>
              <div style={{ fontSize: 15, lineHeight: 1.4, letterSpacing: '-0.005em' }}>{v}</div>
            </Reveal>
          ))}
        </div>
      </section>

      {/* LEAD */}
      <section style={{ padding: '48px 32px 96px' }}>
        <div style={{ maxWidth: 920, margin: '0 auto' }}>
          <Reveal>
            <p style={{
              fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
              fontSize: 28, lineHeight: 1.32, letterSpacing: '-0.015em',
              fontWeight: 400, color: 'var(--ak-fg)', margin: 0,
              textWrap: 'balance',
            }}>
              {CS.lead}
            </p>
          </Reveal>
        </div>
      </section>

      {/* INDIVIDUAL BLOCKS */}
      {CS.blocks.map((b) => (
        <React.Fragment key={b.key}>
          <ProseSection eyebrow={b.eyebrow} title={b.title}>
            {b.body.map((p, i) => (
              <p key={i} style={proseP}>{p}</p>
            ))}
          </ProseSection>
          <section style={{ padding: '0 32px 120px', background: 'var(--ak-bg)' }}>
            {b.mediaTiles && b.mediaTiles.length > 0 && (
              <div style={{
                maxWidth: 1280, margin: '0 auto 64px',
                display: 'grid',
                gridTemplateColumns: `repeat(${b.mediaTiles.length}, 1fr)`,
                gap: 16,
              }}>
                {b.mediaTiles.map((tile, i) => (
                  <Reveal key={i} y={20} delay={i * 100}>
                    <div>
                      <div style={{
                        position: 'relative', overflow: 'hidden',
                        aspectRatio: '16/9', borderRadius: 12,
                        background: '#0a0b0d',
                        border: '1px solid var(--ak-line)',
                      }}>
                        {tile.vimeo ? (
                          <iframe
                            src={tile.vimeo}
                            title={tile.title}
                            frameBorder="0"
                            referrerPolicy="strict-origin-when-cross-origin"
                            allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share"
                            allowFullScreen
                            style={{
                              position: 'absolute', top: 0, left: 0,
                              width: '100%', height: '100%',
                              border: 0,
                            }}
                          />
                        ) : tile.video ? (
                          <video src={tile.video} autoPlay loop muted playsInline
                            style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                        ) : tile.image ? (
                          <img src={tile.image} alt={tile.title}
                            style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                        ) : null}
                      </div>
                      <h4 style={{
                        fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
                        fontSize: 18, lineHeight: 1.2, letterSpacing: '-0.01em',
                        fontWeight: 400, margin: '16px 0 0',
                        color: 'var(--ak-fg)',
                      }}>
                        {tile.title}
                      </h4>
                      {tile.body && (
                        <p style={{ ...proseP, marginTop: 8, fontSize: 14, lineHeight: 1.5 }}>
                          {tile.body}
                        </p>
                      )}
                    </div>
                  </Reveal>
                ))}
              </div>
            )}
            <BlockMedia block={b} />
            {!b.mediaTitle && b.stills && b.stills.length > 0 && (
              <div style={{
                maxWidth: 1280, margin: '16px auto 0',
                display: 'grid',
                gridTemplateColumns: `repeat(${Math.min(b.stills.length, 2)}, 1fr)`,
                gap: 16,
              }}>
                {b.stills.map((src, i) => (
                  <Reveal key={src} y={20} delay={i * 100}>
                    <div style={{
                      position: 'relative', overflow: 'hidden',
                      aspectRatio: '16/9', borderRadius: 12,
                      background: '#0a0b0d',
                      border: '1px solid var(--ak-line)',
                    }}>
                      <img src={src} alt={`${b.title} still ${i + 1}`}
                        style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                    </div>
                  </Reveal>
                ))}
              </div>
            )}
            {b.subblocks && b.subblocks.length > 0 && (
              <div style={{
                maxWidth: 1280, margin: '64px auto 0',
                display: 'grid', gap: 32,
              }}>
                {b.subblocks.map((sub, i) => (
                  <div key={i}>
                    <div style={{
                      display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: 64,
                      alignItems: 'start',
                    }}>
                      <Reveal>
                        <h3 style={{
                          fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
                          fontSize: 'clamp(22px, 2.2vw, 30px)', lineHeight: 1.1,
                          letterSpacing: '-0.015em', fontWeight: 400,
                          margin: 0,
                          textWrap: 'balance',
                        }}>
                          {sub.title}
                        </h3>
                      </Reveal>
                      <Reveal y={28} delay={120}>
                        <p style={{ ...proseP, marginTop: 0 }}>{sub.body}</p>
                      </Reveal>
                    </div>
                    {(sub.vimeo || sub.video || sub.image) && (
                      <Reveal y={20} style={{ marginTop: 32 }}>
                        <div style={{
                          position: 'relative', overflow: 'hidden', borderRadius: 16,
                          background: '#0a0b0d',
                          border: '1px solid var(--ak-line)',
                          aspectRatio: sub.aspect || '16/9',
                          width: '100%',
                        }}>
                          {sub.vimeo ? (
                            <iframe
                              src={sub.vimeo}
                              title={sub.title}
                              frameBorder="0"
                              referrerPolicy="strict-origin-when-cross-origin"
                              allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share"
                              allowFullScreen
                              style={{
                                position: 'absolute', top: 0, left: 0,
                                width: '100%', height: '100%',
                                border: 0,
                              }}
                            />
                          ) : sub.video ? (
                            <video src={sub.video} autoPlay loop muted playsInline
                              style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                          ) : (
                            <img src={sub.image} alt={sub.title}
                              style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                          )}
                        </div>
                      </Reveal>
                    )}
                  </div>
                ))}
              </div>
            )}
          </section>
        </React.Fragment>
      ))}

      {/* CREDITS */}
      <CreditsBlock />

    </div>
  );
}

window.CaseStudyJacksonWang = CaseStudyA;

})();
