// CaseStudyCadillac.jsx — Cadillac × US Open 2025 case study.
// Wrapped in IIFE so internals (CS, helper components) don't collide with
// other case studies. Uses the same editorial layout language as
// CaseStudy23Springs / CaseStudy299Park.

;(function () {

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

// ============ SOURCE CONTENT ============
const CS = {
  slug: 'cadillac-us-open-2025',
  title: 'Cadillac — US OPEN 2025',
  subtitle: 'A brand activation for Cadillac at the 2025 US Open — an AI-powered photobooth, a takeaway moment, a mosaic wall, and stadium graphics.',
  client: 'Cadillac',
  agency: 'Jack Morton',
  studio: 'Volvox Labs',
  year: 2025,
  location: 'New York, NY',
  format: 'Brand pop-up · interactive · supporting content',
  role: 'Creative Direction · Art / Motion Direction',

  lead: "Cadillac's 2025 US Open Pop-up Booth pairs interactive moments with broadcast-grade graphics. Visitors meet an AI photobooth that translates them into a graphic portrait inspired from the US Open original graphics, leave with a personalized takeaway, contribute to a continuous mosaic of fan portraits, and see the campaign expressed at stadium scale.",

  concept: [
    'A brand activation built around participation. Each touchpoint asks the audience to step in — to be photographed, to take something with them, to leave a piece of themselves on the wall, to see the campaign at the scale of the event itself.',
    'Four blocks, one campaign. Interactive at the personal scale, ambient at the stadium scale — a single visual language stretched across all.',
  ],

  blocks: [
    {
      no: '02',
      key: 'photobooth',
      eyebrow: '02 — The AI-Powered Photobooth',
      title: 'The AI-Powered Photobooth.',
      body: [
        'A single-step capture, an AI-driven render. Visitors step into the OPTIQ booth, and a portrait is generated in real time — translating their likeness into a stylized Cadillac campaign frame.',
        'The booth is built as a self-contained piece of architecture: an LED-lined doorway, a single screen, a single seat, a single moment. Designed to read as a Cadillac object at the same time as it reads as a photobooth.',
      ],
      video: 'site/assets/02_PROJECT/2025/CADILLAC_2025/VIDEO/ai-photobooth-1.mp4',
      cornerTl: 'BLOCK 02 / PHOTOBOOTH',
      cornerBr: 'OPTIQ',
      extraStills: [
        'site/assets/02_PROJECT/2025/CADILLAC_2025/ai-photobooth-2.jpg',
        'site/assets/02_PROJECT/2025/CADILLAC_2025/ai-photobooth-3.jpg',
      ],
    },
    {
      no: '03',
      key: 'takeaway',
      eyebrow: '03 — The Takeaway',
      title: 'The Takeaway.',
      body: [
        "Every visitor leaves with their portrait — generated, sent, saved. The takeaway extends the activation past the booth and into the fan's own feed, family, conversation.",
        'Share-able without diluting the brand: personal in feel, distinctly Cadillac in form.',
      ],
      cornerTl: 'BLOCK 03 / TAKEAWAY',
      cornerBr: 'PRINT · DIGITAL',
      videos: [
        { src: 'site/assets/02_PROJECT/2025/CADILLAC_2025/VIDEO/takeaway-cadillac-1.mp4', aspectRatio: '16/9' },
        { src: 'site/assets/02_PROJECT/2025/CADILLAC_2025/VIDEO/250627_Cadi_Net_r4-3_9x16.mp4', aspectRatio: '9/16' },
      ],
    },
    {
      no: '04',
      key: 'mosaic',
      eyebrow: '04 — The Mosaic Wall',
      title: 'The Mosaic Wall.',
      body: [
        'Each portrait generated at the booth becomes one tile in a continuous wall. The mosaic grows across the duration of the Open — every fan contributes, every face reads.',
        'A live system: new captures populate the grid, older captures cycle, the wall is never the same twice. The collective portrait of the tournament, told in Cadillac frames.',
      ],
      video: 'site/assets/02_PROJECT/2025/CADILLAC_2025/VIDEO/mosaic-touch-1.mp4',
      cornerTl: 'BLOCK 04 / MOSAIC',
      cornerBr: 'LIVE GRID',
      extraVideos: [
        'site/assets/02_PROJECT/2025/CADILLAC_2025/VIDEO/mosaic-2.mp4',
        'site/assets/02_PROJECT/2025/CADILLAC_2025/VIDEO/mosaic-3.mp4',
      ],
    },
    {
      no: '05',
      key: 'stadium',
      eyebrow: '05 — Stadium Takeover Graphics',
      title: 'Stadium Takeover Graphics.',
      body: [
        'The campaign at venue scale. LED ribbons, jumbotron beauty shots, lower-thirds, transitional stings — a full graphics package that holds the brand voice across every surface in the stadium.',
        'Built to read at distance and through broadcast. The same language as the booth and the mosaic, scaled up and rhythm-tuned for live moments between points.',
      ],
      video: 'site/assets/02_PROJECT/2025/CADILLAC_2025/VIDEO/stadium-2.mp4',
      cornerTl: 'BLOCK 05 / STADIUM',
      cornerBr: 'BROADCAST · LED',
    },
  ],

  credits: [
    { role: 'Client',                       who: 'Cadillac' },
    { role: 'Agency',                       who: 'Jack Morton' },
    { divider: true },
    { role: 'Studio',                       who: 'Volvox Labs' },
    { role: 'Project Lead',                 who: 'Michael Schneider' },
    { role: 'Creative Direction',           who: 'Kamil Nawratil · Pasakorn Nontananadh' },
    { role: 'Art Direction',                who: 'Pasakorn Nontananadh' },
    { role: 'Motion Design',                who: 'Preto HF' },
    { role: 'Technical Director',           who: 'Matt Ross' },
    { role: 'Sound Composition',            who: 'Javier Cruz' },
    { role: 'Creative Technologist',        who: 'Javier Cruz · Webb Hunt' },
    { role: 'TouchDesigner Development',    who: 'Javier Cruz · Wenyi Zhang · Matt Ross' },
    { role: 'Software Developer',           who: 'Vio Zhu' },
    { role: 'Physical Design Lead',         who: 'Zyia Zhang' },
    { role: 'Director of Production',       who: 'Gilad Dor' },
    { role: 'Producer',                     who: 'Caroline Rojek' },
    { role: 'Project Management',           who: 'Carmen Mouynes' },
    { role: 'Fabrication Assist',           who: 'Jake Abraham · Elias Griffin · Vaughn Hunt · Kiril Bejoulev' },
  ],
};

// =====================================================================
// Shared atoms — scoped to this IIFE so they don't collide with other
// case study files that define the same names.
// =====================================================================

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>
  );
}

// Media rail used by each block: image with corner meta if image is set,
// side-by-side videos if `videos` is set, gradient + placeholder otherwise.
function BlockMedia({ block }) {
  const placeholderGradient = 'radial-gradient(ellipse at 50% 50%, #1a1a1a 0%, #0a0b0d 60%, #050505 100%)';

  if (block.videos && block.videos.length > 0) {
    // Column weights = aspect (W/H), so cells are wider when their video is wider.
    // Combined with aspectRatio on each cell, all cells resolve to the same height.
    const cols = block.videos.map(v => {
      const [w, h] = (v.aspectRatio || '16/9').split('/').map(Number);
      return `${w / h}fr`;
    }).join(' ');
    return (
      <div style={{
        maxWidth: 1280, margin: '0 auto',
        display: 'grid', gridTemplateColumns: cols, gap: 16,
        alignItems: 'start',
      }}>
        {block.videos.map((v, i) => (
          <Reveal key={v.src} y={20} delay={i * 100}>
            <div style={{
              borderRadius: 16, overflow: 'hidden',
              background: '#0a0b0d',
              border: '1px solid var(--ak-line)',
              position: 'relative',
              aspectRatio: v.aspectRatio || '16/9',
            }}>
              <video
                src={v.src}
                autoPlay
                loop
                muted
                playsInline
                style={{
                  width: '100%', height: '100%',
                  objectFit: 'cover',
                  display: 'block',
                }}
              />
            </div>
          </Reveal>
        ))}
      </div>
    );
  }

  const hasMedia = block.image || block.video;

  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: hasMedia ? undefined : '16/9',
      }}>
        {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 }}>06 — 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 (matches CaseStudyA from sibling files)
// =====================================================================

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,
              }}>
                Cadillac<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/2025/CADILLAC_2025/VIDEO/header_1.mp4"
              autoPlay
              loop
              muted
              playsInline
              style={{ width: '100%', height: 'auto', display: 'block' }}
            />
            <CornerMeta tl="CADILLAC / US OPEN 2025" br={`BRAND 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)',
        }}>
          {[
            ['client',   CS.client],
            ['agency',   CS.agency],
            ['studio',   CS.studio],
            ['year',     CS.year],
            ['location', CS.location],
            ['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>

      {/* CONCEPT */}
      <ProseSection eyebrow="01 — Concept" title="Engaged throught the whole process of creation and creativity">
        {CS.concept.map((p, i) => (
          <p key={i} style={proseP}>{p}</p>
        ))}
      </ProseSection>

      {/* CONCEPT GALLERY — 2x2 grid of installation photos */}
      <section style={{ padding: '0 32px 120px', background: 'var(--ak-bg)' }}>
        <div style={{
          maxWidth: 1280, margin: '0 auto',
          display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 16,
        }}>
          {[
            'site/assets/02_PROJECT/2025/CADILLAC_2025/establish1.jpg',
            'site/assets/02_PROJECT/2025/CADILLAC_2025/mosaic3.jpg',
            'site/assets/02_PROJECT/2025/CADILLAC_2025/CADI-USOPEN-2025.00_20_07_17.Still001.jpg',
            'site/assets/02_PROJECT/2025/CADILLAC_2025/establish2.jpg',
          ].map((src, i) => (
            <Reveal key={src} y={20} delay={i * 80}>
              <div style={{
                position: 'relative', overflow: 'hidden',
                aspectRatio: '16/9', borderRadius: 12,
                background: '#0a0b0d',
                border: '1px solid var(--ak-line)',
              }}>
                <img src={src} alt={`Cadillac US Open install — ${i + 1}`}
                  style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
              </div>
            </Reveal>
          ))}
        </div>
      </section>

      {/* BLOCKS INDEX — overview list of the four named blocks */}
      <section style={{ padding: '120px 32px 0', background: 'var(--ak-bg)', borderTop: '1px solid var(--ak-line)' }}>
        <div style={{ maxWidth: 1280, margin: '0 auto' }}>
          <Reveal>
            <MonoLabel dim>Index</MonoLabel>
            <h2 style={{
              fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
              fontSize: 'clamp(40px, 5vw, 64px)', lineHeight: 1.0,
              letterSpacing: '-0.02em', fontWeight: 400, margin: '20px 0 48px',
              maxWidth: 900,
            }}>
              Four blocks across the activation.
            </h2>
          </Reveal>
          <Reveal y={20} delay={120}>
            <ol style={{
              listStyle: 'none', padding: 0, margin: 0,
              display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 24,
              borderTop: '1px solid var(--ak-line)',
            }}>
              {CS.blocks.map((b) => (
                <li key={b.key} style={{
                  paddingTop: 20,
                  borderTop: '2px solid var(--ak-fg)',
                  marginTop: -1,
                }}>
                  <MonoLabel dim style={{ marginBottom: 12 }}>{`Block ${b.no}`}</MonoLabel>
                  <div style={{
                    fontFamily: "'PP Neue Montreal', 'Geist', system-ui, sans-serif",
                    fontSize: 22, lineHeight: 1.15, letterSpacing: '-0.015em',
                    fontWeight: 400, color: 'var(--ak-fg)',
                  }}>
                    {b.title.replace(/\.$/, '')}
                  </div>
                </li>
              ))}
            </ol>
          </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)' }}>
            <BlockMedia block={b} />
            {b.extraStills && b.extraStills.length > 0 && (
              <div style={{
                maxWidth: 1280, margin: '16px auto 0',
                display: 'grid',
                gridTemplateColumns: `repeat(${Math.min(b.extraStills.length, 2)}, 1fr)`,
                gap: 16,
              }}>
                {b.extraStills.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.extraVideos && b.extraVideos.length > 0 && (
              <div style={{
                maxWidth: 1280, margin: '16px auto 0',
                display: 'grid',
                gridTemplateColumns: `repeat(${Math.min(b.extraVideos.length, 2)}, 1fr)`,
                gap: 16,
              }}>
                {b.extraVideos.map((src, i) => (
                  <Reveal key={src} y={20} delay={i * 100}>
                    <div style={{
                      position: 'relative', overflow: 'hidden',
                      borderRadius: 12,
                      background: '#0a0b0d',
                      border: '1px solid var(--ak-line)',
                    }}>
                      <video
                        src={src}
                        autoPlay
                        loop
                        muted
                        playsInline
                        style={{ width: '100%', height: 'auto', display: 'block' }}
                      />
                    </div>
                  </Reveal>
                ))}
              </div>
            )}
          </section>
        </React.Fragment>
      ))}

      {/* CREDITS */}
      <CreditsBlock />

    </div>
  );
}

window.CaseStudyCadillac = CaseStudyA;

})();
