/* global React, ReactDOM */
const { useState, useMemo, useEffect } = React;

// ──────────────────────────────────────────────────────────────────
// Portrait — press photo when available, otherwise an initials tile.
// Initials tiles use a deterministic duotone derived from the talent ID.
// ──────────────────────────────────────────────────────────────────
const TALENT_PHOTOS = {
  // ── LOS ANGELES ───────────────────────────────────────────────
  beckyg:           { src: 'talent-photos/beckyg.jpg',           pos: '50% 40%' },
  youngmiko:        { src: 'talent-photos/youngmiko.jpg',        pos: '50% 25%' },
  juniorh:          { src: 'talent-photos/juniorh.jpg',          pos: '50% 25%' },
  carinleon:        { src: 'talent-photos/carinleon.jpg',        pos: '50% 30%' },
  snowthaproduct:   { src: 'talent-photos/snowthaproduct.jpg',   pos: '50% 25%' },
  ivancornejo:      { src: 'talent-photos/ivancornejo.jpg',      pos: '55% 35%' },
  frankiequinones:  { src: 'talent-photos/frankiequinones.jpg',  pos: '50% 30%' },
  doncheto:         { src: 'talent-photos/doncheto.jpg',         pos: '50% 40%' },
  cuco:             { src: 'talent-photos/cuco.jpg',             pos: '50% 30%' },
  theesacredsouls:  { src: 'talent-photos/theesacredsouls.jpg',  pos: '50% 50%' },
  // ── SF / BAY AREA ─────────────────────────────────────────────
  missfoodie:       { src: 'talent-photos/missfoodie.jpg',       pos: '50% 25%' },
  ashleymonique:    { src: 'talent-photos/ashleymonique.jpg',    pos: '50% 40%' },
  claudia:          { src: 'talent-photos/claudia.jpeg',         pos: '50% 45%' },
  chulitavinyl:     { src: 'talent-photos/chulitavinyl.webp',    pos: '50% 35%' },
  ladona:           { src: 'talent-photos/ladona.jpeg',          pos: '50% 30%' },
  turbosonidero:    { src: 'talent-photos/turbosonidero.png',    pos: '50% 40%' },
  dianagameros:     { src: 'talent-photos/dianagameros.jpg',     pos: '55% 40%' },
  lamisanegra:      { src: 'talent-photos/lamisanegra.jpg',      pos: '50% 45%' },
  karlielema:       { src: 'talent-photos/karlielema.webp',      pos: '50% 25%' },
  delaciio:         { src: 'talent-photos/delaciio.jpg',         pos: '50% 35%' },
  sonidoclash:      { src: 'talent-photos/sonidoclash.jpg',      pos: '50% 35%' },
  // ── SACRAMENTO ────────────────────────────────────────────────
  daviankimbrough:  { src: 'talent-photos/daviankimbrough.jpg',  pos: '50% 25%' },
  eslabonarmado:    { src: 'talent-photos/eslabonarmado.jpg',    pos: '50% 30%' },
  claveespecial:    { src: 'talent-photos/claveespecial.jpg',    pos: '50% 25%' },
  talibelico:       { src: 'talent-photos/talibelico.jpg',       pos: '50% 45%' },
  felipeesparza:    { src: 'talent-photos/felipeesparza.jpg',    pos: '55% 35%' },
  eatwcass:         { src: 'talent-photos/eatwcass.jpg',         pos: '50% 30%' },
  // ── FRESNO ────────────────────────────────────────────────────
  leogonzalez:      { src: 'talent-photos/leogonzalez.jpg',      pos: '50% 35%' },
  yahritza:         { src: 'talent-photos/yahritza.jpg',         pos: '60% 40%' },
  marccastro:       { src: 'talent-photos/marccastro.jpg',       pos: '50% 30%' },
  helenochoa:       { src: 'talent-photos/helenochoa.jpg',       pos: '50% 25%' },
  kanerodriguez:    { src: 'talent-photos/kanerodriguez.jpg',    pos: '50% 25%' },
  andresdelights:   { src: 'talent-photos/andresdelights.jpeg', pos: '30% 30%' },
  conexiondivina:   { src: 'talent-photos/conexiondivina.jpg',   pos: '50% 40%' },
  titodoublep:      { src: 'talent-photos/titodoublep.webp',     pos: '50% 25%' },
  // ── SAN DIEGO ─────────────────────────────────────────────────
  chuckylozano:     { src: 'talent-photos/chuckylozano.jpg',     pos: '50% 25%' },
  lilrob:           { src: 'talent-photos/lilrob.jpg',           pos: '50% 40%' },
  priscila:         { src: 'talent-photos/priscila.jpg',         pos: '55% 25%' },
  santamykah:       { src: 'talent-photos/santamykah.jpeg',     pos: '50% 30%' },
  caliburrito:      { src: 'talent-photos/caliburrito.jpg',      pos: '50% 40%' },
  nortecbf:         { src: 'talent-photos/nortecbf.webp',        pos: '50% 35%' },
  memothemafioso:   { src: 'talent-photos/memothemafioso.jpg',   pos: '50% 35%' },
  juancirerol:      { src: 'talent-photos/juancirerol.jpg',      pos: '50% 25%' },
  sewloka:          { src: 'talent-photos/sewloka.webp',         pos: '50% 25%' },
};
// ──────────────────────────────────────────────────────────────────
const PALETTES = [
  ['#000DFF', '#FFFFFF'], // electric / white
  ['#000000', '#F8F8F8'], // black / off-white
  ['#DC3545', '#000000'], // red / black
  ['#000DFF', '#000000'], // electric / black
  ['#0008CC', '#FFFFFF'], // deep electric / white
  ['#111111', '#FFFFFF'], // dark / white
  ['#000000', '#000DFF'], // black / electric
];

function hashIdx(id, mod) {
  let h = 0;
  for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) >>> 0;
  return h % mod;
}

function initialsOf(name) {
  return name
    .replace(/["'.]/g, '')
    .replace(/\(.*?\)/g, '')
    .split(/\s+/)
    .filter(Boolean)
    .slice(0, 2)
    .map(p => p[0])
    .join('')
    .toUpperCase();
}

function Portrait({ talent, size = 'md' }) {
  const [bg, fg] = PALETTES[hashIdx(talent.id, PALETTES.length)];
  const fontSize = size === 'lg' ? '88px' : size === 'sm' ? '28px' : '56px';
  const photoEntry = TALENT_PHOTOS[talent.id];
  return (
    <div className="portrait" style={{ background: bg, color: fg }}>
      {photoEntry ? (
        <img
          className="portrait__img"
          src={photoEntry.src}
          alt={talent.name}
          loading="lazy"
          style={{ objectPosition: photoEntry.pos || '50% 30%' }}
        />
      ) : (
        <span className="portrait__initials" style={{ fontSize }}>{initialsOf(talent.name)}</span>
      )}
      <span className="portrait__handle">{talent.handle}</span>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────
// Signal-strength dot bar — 3-step (LOW / MED / HIGH).
// Used for Draw and Sustained Relevance.
// ──────────────────────────────────────────────────────────────────
function Signal({ value, label }) {
  const level = value === 'HIGH' ? 3 : value === 'MED' ? 2 : value === 'LOW' ? 1 : 0;
  return (
    <div className="signal" title={`${label}: ${value}`}>
      <span className="signal__label">{label}</span>
      <span className="signal__dots">
        {[1, 2, 3].map(i => (
          <span key={i} className={`signal__dot ${i <= level ? 'is-on' : ''}`} />
        ))}
      </span>
      <span className="signal__value">{value}</span>
    </div>
  );
}

// Mini sentiment bar (no labels) — for card footers.
function MiniSentiment({ s }) {
  return (
    <div className="mini-sentiment" title={`${s.pos}% positive · ${s.neu}% neutral · ${s.neg}% risk`}>
      <span className="mini-sentiment__pos" style={{ flex: s.pos }} />
      <span className="mini-sentiment__neu" style={{ flex: s.neu }} />
      <span className="mini-sentiment__neg" style={{ flex: s.neg }} />
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────
// Header / Nav
// ──────────────────────────────────────────────────────────────────
function AnnouncementBar() {
  return (
    <div className="ig-announce">
      <span className="ig-announce__text">
        ASON × 20FT BEAR — Got Milk? × World Cup 2026 California Slate
      </span>
    </div>
  );
}

function Nav() {
  return (
    <nav className="ig-nav">
      <div className="ig-nav__left">
        <a href="#" className="ig-nav__brand">
          <span className="ig-nav__brand-mark" aria-hidden="true">●</span>
          <span className="ig-nav__brand-word">GOT MILK?</span>
          <span className="ig-nav__brand-sep">/</span>
          <span className="ig-nav__brand-sub">World Cup 2026 Slate</span>
        </a>
        <ul className="ig-nav__links">
          <li><a href="#findings" className="ig-nav__link">Frame</a></li>
          <li><a href="#cities" className="ig-nav__link">Cities</a></li>
          <li><a href="#archive" className="ig-nav__link">Archive</a></li>
          <li><a href="#sustained" className="ig-nav__link">Sustained Play</a></li>
        </ul>
      </div>
      <div className="ig-nav__right">
        <span className="ig-nav__meta">May 26, 2026</span>
      </div>
    </nav>
  );
}

// ──────────────────────────────────────────────────────────────────
// Hero
// ──────────────────────────────────────────────────────────────────
function Hero() {
  const total = window.TALENT_SLATE.filter(t => t.tier !== 'PARTNERSHIP').length;
  return (
    <header className="hero">
      <div className="hero__inner">
        <div className="hero__bar" />
        <p className="hero__overline">Talent Strategy · Prepared by ASON Solutions</p>
        <h1 className="hero__title">
          Got Milk?<br />
          × 2026 World Cup<br />
          <span className="hero__title-accent">California Viewing Party Series</span>
        </h1>
        <p className="hero__lede">
          A 5-city Latin-audience talent slate built from cultural intelligence first, with the
          September 2025 &ldquo;Real Is Back&rdquo; campaign as the lens.
          {' '}<strong>{total}</strong> candidates across LA, SF/Bay, Sacramento, Fresno, and San Diego.
        </p>
        <dl className="hero__meta">
          <div><dt>Prepared for</dt><dd>Got Milk?</dd></div>
          <div><dt>Cities</dt><dd>5 active markets</dd></div>
          <div><dt>Window</dt><dd>June 11 — July 4, 2026</dd></div>
          <div><dt>Slate</dt><dd>{total} entries</dd></div>
        </dl>
      </div>
    </header>
  );
}

// ──────────────────────────────────────────────────────────────────
// Strategic Findings
// ──────────────────────────────────────────────────────────────────
function Findings() {
  return (
    <section id="findings" className="findings">
      <div className="section-head">
        <p className="section-eyebrow">The Frame</p>
        <h2 className="section-title">Four findings that reshape this brief.</h2>
        <p className="section-lede">
          Before the talent slate. Got Milk?'s current position with Latin audiences,
          women's-sport DNA, brand-voice pivot, and budget realism shape every recommendation that follows.
        </p>
      </div>
      <article className="finding finding--hero">
        <div className="finding__num">{window.FINDINGS[0].num}</div>
        <div className="finding__body">
          <h3 className="finding__headline">{window.FINDINGS[0].headline}</h3>
          <p className="finding__detail">{window.FINDINGS[0].detail}</p>
          <p className="finding__implication">
            <span className="finding__implication-arrow">→</span> {window.FINDINGS[0].implication}
          </p>
        </div>
      </article>

      <div className="findings__grid">
        {window.FINDINGS.slice(1).map(f => (
          <article key={f.num} className="finding">
            <div className="finding__num">{f.num}</div>
            <h3 className="finding__headline">{f.headline}</h3>
            <p className="finding__detail">{f.detail}</p>
            <p className="finding__implication">
              <span className="finding__implication-arrow">→</span> {f.implication}
            </p>
          </article>
        ))}
      </div>
    </section>
  );
}

// ──────────────────────────────────────────────────────────────────
// City switcher + tactical lineup
// ──────────────────────────────────────────────────────────────────
function CityTabs({ active, onJump }) {
  return (
    <div className="city-tabs" role="tablist">
      {window.CITIES.map((c, i) => (
        <button
          key={c.id}
          role="tab"
          aria-selected={active === c.id}
          className={`city-tab ${active === c.id ? 'is-active' : ''}`}
          onClick={() => onJump(c.id)}
        >
          <span className="city-tab__num">{String(i + 1).padStart(2, '0')}</span>
          <span className="city-tab__label">{c.label}</span>
          <span className="city-tab__date">{c.date}</span>
        </button>
      ))}
    </div>
  );
}

function CityBriefing({ city, talents }) {
  const breakdown = useMemo(() => {
    const b = { T1: 0, T2: 0, T3: 0, PARTNERSHIP: 0 };
    talents.forEach(t => { b[t.tier] = (b[t.tier] || 0) + 1; });
    return b;
  }, [talents]);

  return (
    <div className="briefing">
      <div className="briefing__top">
        <p className="briefing__eyebrow">Match Day · {city.date}</p>
        <h3 className="briefing__name">{city.label}</h3>
        <div className="briefing__stat">
          <span className="briefing__stat-num">{city.mexOrigin}</span>
          <span className="briefing__stat-label">Mexican-origin of Latino population</span>
        </div>
        <div className="briefing__breakdown">
          {[
            ['T1', 'Mega'],
            ['T2', 'Mid'],
            ['T3', 'Micro'],
          ].map(([k, lbl]) => (
            <div key={k} className="briefing__brk">
              <span className={`tier-pill tier-${k.toLowerCase()}`}>{lbl}</span>
              <span className="briefing__brk-num">{breakdown[k] || 0}</span>
            </div>
          ))}
        </div>
      </div>
      <dl className="briefing__rows">
        <div><dt>Scene</dt><dd>{city.scene}</dd></div>
        <div><dt>Venue anchor</dt><dd>{city.venue}</dd></div>
        <div><dt>Strategic shape</dt><dd>{city.strategy}</dd></div>
      </dl>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────
// Lineup grid card — enriched with category badge, draw/sustained
// signal bars, and a mini sentiment bar.
// ──────────────────────────────────────────────────────────────────
function tierLabel(t) {
  return t === 'T1' ? 'T1 · Mega'
    : t === 'T2' ? 'T2 · Mid'
    : t === 'T3' ? 'T3 · Micro'
    : 'Partnership';
}

function dairyLabel(d) {
  return d === 'pass' ? 'Pass · clear'
    : d === 'flag' ? 'Flag · verify'
    : 'Exclude · risk';
}

function LineupCard({ talent, onOpen, isApproved, onToggleApprove }) {
  return (
    <article className={`lineup-card ${isApproved ? 'is-approved' : ''} ${talent.tier === 'PARTNERSHIP' ? 'is-partnership' : ''}`}>
      <button className="lineup-card__img" onClick={() => onOpen(talent)} aria-label={`Inspect ${talent.name}`}>
        <Portrait talent={talent} />
      </button>
      <div className="lineup-card__body">
        <div className="lineup-card__meta">
          <span className={`tier-pill tier-${talent.tier.toLowerCase()}`}>{tierLabel(talent.tier)}</span>
          <span className="lineup-card__rank">{talent.rank === 'PP' ? 'Partner' : `#${talent.rank}`}</span>
        </div>
        <h4 className="lineup-card__name">{talent.name}</h4>
        <p className="lineup-card__type">{talent.type}</p>
        <div className="lineup-card__reach">
          <div>
            <span className="lineup-card__reach-num">{talent.reach}</span>
            <span className="lineup-card__reach-label">IG reach</span>
          </div>
          <span className={`dairy dairy--${talent.dairy}`}>
            {talent.dairy === 'pass' ? 'Dairy ✓' : talent.dairy === 'flag' ? 'Flag' : 'Exclude'}
          </span>
        </div>
        <p className="lineup-card__pitch">{talent.whyThem}</p>
        <div className="lineup-card__actions">
          <button className="btn btn--outline" onClick={() => onOpen(talent)}>PROFILE</button>
          <a
            className="btn btn--outline"
            href={talent.link}
            target="_blank"
            rel="noopener noreferrer"
            onClick={(e) => e.stopPropagation()}
          >
            IG
          </a>
        </div>
      </div>
    </article>
  );
}

function Lineup({ talents, onOpen, approvedSet, onToggleApprove }) {
  if (!talents.length) {
    return <div className="lineup-empty">No candidates match the current filters.</div>;
  }

  const regular = talents.filter(t => t.tier !== 'PARTNERSHIP');

  return (
    <div className="lineup-grid">
      {regular.map(t => (
        <LineupCard
          key={t.id} talent={t} onOpen={onOpen}
          isApproved={approvedSet.has(t.id)} onToggleApprove={onToggleApprove}
        />
      ))}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────
// Inspector slideover
// ──────────────────────────────────────────────────────────────────
function Inspector({ talent, onClose, isApproved, onToggleApprove }) {
  useEffect(() => {
    if (!talent) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [talent, onClose]);

  if (!talent) return null;
  const s = talent.sentiment;
  const cat = window.CATEGORIES[talent.category] || { label: '—' };
  const city = window.CITIES.find(c => c.id === talent.city);

  return (
    <div className="inspector__scrim" onClick={onClose}>
      <aside className="inspector" onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true">
        <button className="inspector__close" onClick={onClose} aria-label="Close inspector">×</button>

        <div className="inspector__cover">
          <Portrait talent={talent} size="lg" />
        </div>

        <div className="inspector__body">
          <p className="inspector__eyebrow">
            <span className={`tier-pill tier-${talent.tier.toLowerCase()}`}>{tierLabel(talent.tier)}</span>
            <span className="inspector__rank">{talent.rank === 'PP' ? 'Partnership play' : `Rank #${talent.rank}`} · {city && city.label}</span>
          </p>
          <h2 className="inspector__name">{talent.name}</h2>
          <a className="inspector__handle" href={talent.link} target="_blank" rel="noreferrer">{talent.handle} ↗</a>

          <div className="inspector__stats">
            <div><dt>IG Reach</dt><dd>{talent.reach}</dd></div>
            <div><dt>Category</dt><dd>{cat.label}</dd></div>
            <div><dt>Register</dt><dd>{talent.register}</dd></div>
            <div><dt>Type</dt><dd>{talent.type.replace(/^[^·]+·\s*/, '')}</dd></div>
          </div>

          <div className="inspector__signals">
            <Signal value={talent.draw} label="Draw" />
            <Signal value={talent.sustain} label="Sustained Relevance" />
            <div className="signal">
              <span className="signal__label">Dairy</span>
              <span className="signal__dots" />
              <span className={`signal__value dairy--${talent.dairy}`}>{dairyLabel(talent.dairy)}</span>
            </div>
          </div>

          {talent.dairyNote && (
            <div className={`inspector__note inspector__note--${talent.dairy}`}>
              <p className="inspector__note-label">Dairy note</p>
              <p>{talent.dairyNote}</p>
            </div>
          )}

          <section className="inspector__section">
            <p className="inspector__section-title">Why them</p>
            <p className="inspector__body-text">{talent.whyThem}</p>
          </section>

          <section className="inspector__section">
            <p className="inspector__section-title inspector__section-title--muted">Friction points</p>
            <p className="inspector__body-text inspector__body-text--muted">{talent.whyNot}</p>
          </section>

          <section className="inspector__section">
            <p className="inspector__section-title">Audience signal · IG comments</p>
            <p className="inspector__meta">{talent.coverage}</p>
            <div className="sentiment-bar">
              <div className="sentiment-bar__pos" style={{ width: `${s.pos}%` }} />
              <div className="sentiment-bar__neu" style={{ width: `${s.neu}%` }} />
              <div className="sentiment-bar__neg" style={{ width: `${s.neg}%` }} />
            </div>
            <div className="sentiment-legend">
              <span><i className="dot dot--pos" /> {s.pos}% positive</span>
              <span><i className="dot dot--neu" /> {s.neu}% neutral</span>
              <span><i className="dot dot--neg" /> {s.neg}% risk</span>
            </div>
            <p className="inspector__theme">Top theme · <strong>{talent.topTheme}</strong></p>
            <blockquote className="inspector__quote">"{talent.quote}"</blockquote>
          </section>

        </div>
      </aside>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────
// Archive
// ──────────────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────────────
// Archive — pure handle directory: a quick-access social-media index
// of every candidate, grouped by city. Each row deep-links to the
// talent's IG; the inspector still opens on the name button.
// ─────────────────────────────────────────────────────────────────
function Archive({ onOpen }) {
  const [q, setQ] = useState('');

  const byCity = useMemo(() => {
    const m = {};
    window.CITIES.forEach(c => { m[c.id] = []; });
    window.TALENT_SLATE.forEach(t => {
      if (t.tier === 'PARTNERSHIP') return;
      if (q) {
        const needle = q.toLowerCase();
        const hay = `${t.name} ${t.handle} ${t.type}`.toLowerCase();
        if (!hay.includes(needle)) return;
      }
      (m[t.city] || (m[t.city] = [])).push(t);
    });
    Object.keys(m).forEach(cid => {
      m[cid].sort((a, b) => {
        const ax = a.rank === 'PP' ? 999 : Number(a.rank);
        const bx = b.rank === 'PP' ? 999 : Number(b.rank);
        return ax - bx;
      });
    });
    return m;
  }, [q]);

  const total = useMemo(
    () => Object.values(byCity).reduce((n, list) => n + list.length, 0),
    [byCity]
  );

  return (
    <section id="archive" className="archive">
      <div className="section-head">
        <p className="section-eyebrow">The Archive</p>
        <h2 className="section-title">Quick links · social handles.</h2>
        <p className="section-lede">
          Every candidate, grouped by city. Click any row to jump straight to their
          Instagram. Use the search to find someone fast.
        </p>
      </div>

      <div className="archive__controls">
        <input
          type="search"
          className="archive__search"
          placeholder="Search name, handle, or type…"
          value={q}
          onChange={(e) => setQ(e.target.value)}
        />
        {q && (
          <button className="archive__reset" onClick={() => setQ('')}>Clear</button>
        )}
      </div>

      <p className="archive__count">
        <strong>{total}</strong> candidates across <strong>{window.CITIES.length}</strong> cities
      </p>

      <div className="archive__cities">
        {window.CITIES.map((c) => {
          const list = byCity[c.id] || [];
          if (!list.length) return null;
          return (
            <div key={c.id} className="archive__city">
              <div className="archive__city-head">
                <h3 className="archive__city-name">{c.label}</h3>
                <span className="archive__city-meta">{c.date} · {list.length} {list.length === 1 ? 'pick' : 'picks'}</span>
              </div>
              <ul className="archive__list">
                {list.map((t) => (
                  <li key={t.id} className="archive__row">
                    <a
                      className="archive__row-link"
                      href={t.link}
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      <span className="archive__row-rank">{String(t.rank).padStart(2, '0')}</span>
                      <span className={`archive__row-tier tier-${t.tier.toLowerCase()}`}>{t.tier}</span>
                      <span className="archive__row-name">{t.name}</span>
                      <span className="archive__row-handle">{t.handle}</span>
                      <span className="archive__row-reach">{t.reach}</span>
                    </a>
                    <button
                      className="archive__row-inspect"
                      onClick={() => onOpen(t)}
                      aria-label={`Profile for ${t.name}`}
                    >
                      Profile
                    </button>
                  </li>
                ))}
              </ul>
            </div>
          );
        })}
      </div>
    </section>
  );
}

// ──────────────────────────────────────────────────────────────────
// Sustained Relevance
// ──────────────────────────────────────────────────────────────────
// ──────────────────────────────────────────────────────────────────
// Closing slide — full-bleed cover image + sign-off
// ──────────────────────────────────────────────────────────────────
function Closing() {
  return (
    <section className="closing" aria-label="Closing">
      <div className="closing__inner">
        <p className="closing__overline">KICKOFF →</p>
        <h2 className="closing__title">
          First touch June 11.<br />
          <span className="closing__title-accent">Then the year.</span>
        </h2>
        <p className="closing__lede">
          Five matchdays. Five cultural rooms. One year-round dialogue with
          Latin California — built on cultural intelligence, not adjacency.
        </p>
        <dl className="closing__meta">
          <div>
            <dt>Presented by</dt>
            <dd><a href="mailto:claire@20ftbearmedia.com">Claire Mara Takamatsu</a> · 20ft Bear</dd>
          </div>
          <div>
            <dt>For</dt>
            <dd>Got Milk?</dd>
          </div>
          <div>
            <dt>Window</dt>
            <dd>June 11 — July 4, 2026</dd>
          </div>
        </dl>
      </div>
    </section>
  );
}

function Sustained() {
  return (
    <section id="sustained" className="sustained">
      <div className="sustained__inner">
        <div className="section-head section-head--inverse">
          <p className="section-eyebrow section-eyebrow--inverse">The Sustained Play</p>
          <h2 className="section-title section-title--inverse">A 12-month relationship, not a transaction.</h2>
          <p className="section-lede section-lede--inverse">
            Got Milk?'s compound value lies in treating this series as the opening door to an
            authentic year-round dialogue with Latin California. Each booking should open the next, not close one.
          </p>
        </div>

        <div className="sustained__phases">
          <article className="phase">
            <p className="phase__num">Phase 01 · Hyperlocal launch</p>
            <h3 className="phase__title">Civic anchors first.</h3>
            <p className="phase__body">
              Inject bespoke community assets — <strong>Sew Loka</strong>, <strong>Ale Gonzalez</strong>,
              <strong> Andre's Delights</strong> — into the high-visibility viewing parties.
              Watch-party catering and merch double as instant PR assets.
            </p>
          </article>
          <article className="phase">
            <p className="phase__num">Phase 02 · Sierreño heritage</p>
            <h3 className="phase__title">The Central Valley moat.</h3>
            <p className="phase__body">
              Activate <strong>Eslabón Armado</strong> and Central Valley farmworker voices
              representing the deep agricultural engine of the state — the literal dairy belt is the talent.
            </p>
          </article>
          <article className="phase">
            <p className="phase__num">Phase 03 · Multi-gen trust</p>
            <h3 className="phase__title">Sustained platforms.</h3>
            <p className="phase__body">
              Partner with <strong>Chulita Vinyl Club</strong>, <strong>Don Cheto</strong>, and
              regional radio anchors for continuous monthly cultural interaction.
              These are the year-round amplifiers.
            </p>
          </article>
        </div>

        <p className="sustained__pull">
          &ldquo;A single tier-1 headliner fee buys awareness but doesn&rsquo;t compound.
          Each booking should open a door, not close a transaction.&rdquo;
        </p>
      </div>
    </section>
  );
}

// ──────────────────────────────────────────────────────────────────
// Toast
// ──────────────────────────────────────────────────────────────────
function Toast({ message, onClose }) {
  useEffect(() => {
    if (!message) return;
    const t = setTimeout(onClose, 3500);
    return () => clearTimeout(t);
  }, [message, onClose]);
  if (!message) return null;
  return <div className="toast">{message}</div>;
}

// ──────────────────────────────────────────────────────────────────
// Root
// ──────────────────────────────────────────────────────────────────
function App() {
  const [inspecting, setInspecting] = useState(null);
  const [approved, setApproved] = useState([]);
  const [toast, setToast] = useState('');
  const [activeCity, setActiveCity] = useState('la');

  const approvedSet = useMemo(() => new Set(approved.map(t => t.id)), [approved]);

  // Group talent by city, sorted: regular ranks first, partnerships last.
  const cityRoster = useMemo(() => {
    const m = {};
    window.CITIES.forEach(c => { m[c.id] = []; });
    window.TALENT_SLATE.forEach(t => { (m[t.city] || (m[t.city] = [])).push(t); });
    Object.keys(m).forEach(cid => {
      m[cid].sort((a, b) => {
        const ax = a.rank === 'PP' ? 999 : parseInt(a.rank, 10);
        const bx = b.rank === 'PP' ? 999 : parseInt(b.rank, 10);
        return ax - bx;
      });
    });
    return m;
  }, []);

  // Smooth-scroll to a city block; the IntersectionObserver below
  // updates `activeCity` as the user scrolls.
  const jumpToCity = (id) => {
    const el = document.getElementById(`city-${id}`);
    if (!el) return;
    const offset = 80;
    const top = el.getBoundingClientRect().top + window.scrollY - offset;
    window.scrollTo({ top, behavior: 'smooth' });
  };

  useEffect(() => {
    if (typeof IntersectionObserver === 'undefined') return;
    const obs = new IntersectionObserver((entries) => {
      // Pick the entry closest to the top of the viewport.
      const visible = entries
        .filter(e => e.isIntersecting)
        .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
      if (visible.length) {
        const id = visible[0].target.id.replace(/^city-/, '');
        setActiveCity(id);
      }
    }, { rootMargin: '-30% 0px -55% 0px', threshold: 0 });
    window.CITIES.forEach(c => {
      const el = document.getElementById(`city-${c.id}`);
      if (el) obs.observe(el);
    });
    return () => obs.disconnect();
  }, []);

  const toggleApprove = (t) => {
    setApproved(prev => {
      const exists = prev.some(x => x.id === t.id);
      if (exists) {
        setToast(`Removed ${t.name} from docket.`);
        return prev.filter(x => x.id !== t.id);
      }
      setToast(`Added ${t.name} to docket.`);
      return [...prev, t];
    });
  };

  const exportDocket = () => {
    if (!approved.length) {
      setToast('Docket is empty — approve some candidates first.');
      return;
    }
    const txt = approved.map(t => {
      const c = window.CITIES.find(x => x.id === t.city);
      return `${t.name} (${t.handle}) — ${c.label} · ${t.tier} · ${t.reach}`;
    }).join('\n');
    navigator.clipboard.writeText(txt).then(() => {
      setToast(`Docket copied — ${approved.length} candidates.`);
    }).catch(() => {
      setToast('Copy failed — see console for docket text.');
      // eslint-disable-next-line no-console
      console.log(txt);
    });
  };

  return (
    <React.Fragment>
      <AnnouncementBar />
      <Nav />
      <main>
        <Hero />
        <Findings />

        <section id="cities" className="cities">
          <div className="section-head">
            <p className="section-eyebrow">The Cities</p>
            <h2 className="section-title">Five matchdays. Five rooms.</h2>
            <p className="section-lede">
              Each city has its own scene, venue anchor, and strategic shape. Lineups
              are tactical — not the most-famous list, the most-credible one. Click any
              card to inspect a talent's full cultural audit, sentiment score, and
              dairy-safety profile.
            </p>
          </div>

          <CityTabs active={activeCity} onJump={jumpToCity} />

          {window.CITIES.map((c, i) => (
            <div
              key={c.id}
              id={`city-${c.id}`}
              className="city-block"
              data-screen-label={`City ${String(i + 1).padStart(2, '0')} · ${c.label}`}
            >
              <CityBriefing city={c} talents={cityRoster[c.id]} />
              <Lineup
                talents={cityRoster[c.id]}
                onOpen={setInspecting}
                approvedSet={approvedSet}
                onToggleApprove={toggleApprove}
              />
            </div>
          ))}
        </section>

        <Archive onOpen={setInspecting} />

        <Sustained />
        <Closing />
      </main>

      <footer className="ig-footer ig-footer--minimal">
        <div className="ig-footer__inner">
          <div className="ig-footer__bottom">
            <p className="ig-footer__copy">
              © 2026 <a href="https://ason.solutions" target="_blank" rel="noopener">ASON.SOLUTIONS</a> · <a href="mailto:build@ason.solutions">build@ason.solutions</a>
            </p>
            <div className="ig-footer__legal">
              <span>May 26, 2026</span>
              <span>Internal Working Document</span>
            </div>
          </div>
        </div>
      </footer>

      <Inspector
        talent={inspecting}
        onClose={() => setInspecting(null)}
        isApproved={inspecting && approvedSet.has(inspecting.id)}
        onToggleApprove={toggleApprove}
      />
      <Toast message={toast} onClose={() => setToast('')} />
    </React.Fragment>
  );
}

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