/* global React, Icon, WORK, REEL_URL, REEL_WORK, WatchReelButton, CLIENT_LOGOS, slugForWork */
const { useState, useEffect, useRef } = React;

// ===================================================================
// Hero — Marquee variant
// ===================================================================
function HeroMarquee({ onGoto }) {
  return (
    <section className="hero-marquee">
      <div className="blob" />
      <div className="blob blob-2" />
      <div className="marquee-row r1">
        <div className="marquee-track">
          <span>Detail</span><span className="star"><Icon name="star" size={64} /></span>
          <span>driven</span><span>works</span><span className="star"><Icon name="star" size={64} /></span>
          <span>Detail</span><span className="star"><Icon name="star" size={64} /></span>
          <span>driven</span><span>works</span><span className="star"><Icon name="star" size={64} /></span>
        </div>
      </div>
      <div className="marquee-row r2 italic">
        <div className="marquee-track">
          <span>Commercial</span><span>—</span>
          <span>Brand Videos</span><span>—</span>
          <span>Social Content</span><span>—</span>
          <span>Live Events</span><span>—</span>
          <span>Commercial</span><span>—</span>
          <span>Brand Videos</span><span>—</span>
          <span>Social Content</span><span>—</span>
          <span>Live Events</span><span>—</span>
        </div>
      </div>
      <div className="container">
        <div className="hero-meta">
          <p className="lead">A boutique production company in Acton, West London. We make creative <em>corporate</em> and <em>commercial</em> video for brands and agencies.</p>
          <div className="stats">
            <div className="stat"><div className="num">120+</div><div className="lbl">Projects</div></div>
            <div className="stat"><div className="num">8 yrs</div><div className="lbl">In business</div></div>
            <div className="stat"><div className="num">W3</div><div className="lbl">London studio</div></div>
          </div>
          <div className="actions">
            <button className="btn-pri" onClick={() => onGoto('contact')} data-hover="Send"><span>Start a project</span><Icon name="arrow-right" /></button>
            <WatchReelButton className="btn-ghost"/>
          </div>
        </div>
      </div>
    </section>);

}

// ===================================================================
// Hero — Stacked variant
// ===================================================================
function HeroStacked({ onGoto }) {
  return (
    <section className="hero-stacked">
      <div className="blob" style={{ position: 'absolute', width: 1100, height: 1100, borderRadius: '50%', filter: 'blur(120px)', background: 'radial-gradient(circle at 30% 30%, var(--vf-blue) 0%, var(--vf-blue-800) 40%, transparent 70%)', opacity: 0.55, left: -300, top: -200, pointerEvents: 'none' }} />
      <div className="blob blob-2" style={{ position: 'absolute', width: 700, height: 700, borderRadius: '50%', filter: 'blur(120px)', background: 'radial-gradient(circle, var(--vf-blue-500) 0%, var(--vf-blue-900) 60%, transparent 80%)', opacity: 0.4, right: -100, top: 100, pointerEvents: 'none' }} />
      <div className="container">
        <div className="hero-stacked-grid">
          <div>
            <div className="eyebrow"><span className="idx">VF—01</span> Boutique film studio · Acton, W3</div>
            <h1 style={{ marginTop: 24 }}>Detail <em>driven</em><br />works.</h1>
            <p>Elevate your brand through powerful visuals and captivating narratives. Commercials, brand videos, social content and live events — made by a small team that handles brief through to grade.</p>
            <div style={{ display: 'flex', gap: 12, marginTop: 36 }}>
              <button className="btn-pri" onClick={() => onGoto('contact')} data-hover="Send"><span>Say hello</span><Icon name="arrow-right" /></button>
              <WatchReelButton className="btn-sec"><Icon name="play-line" /> Watch reel</WatchReelButton>
            </div>
          </div>
          <div className="hero-stack-cards">
            <div className="float-card fc-1" data-hover="Play">
              <div className="thumb" style={{ backgroundImage: 'url(assets/work-isamaya.jpg)' }}>
                <div className="play" />
              </div>
              <div className="meta">Isamaya</div>
              <h4>Spring Lookbook</h4>
            </div>
            <div className="float-card fc-2" data-hover="Play">
              <div className="thumb" style={{ backgroundImage: 'url(assets/work-lent.jpg)' }}>
                <div className="play" />
              </div>
              <div className="meta">Lent</div>
              <h4>I Fly Away</h4>
            </div>
            <div className="float-card fc-3" data-hover="Play">
              <div className="thumb" style={{ backgroundImage: 'url(assets/work-tearfund.jpg)' }}>
                <div className="play" />
              </div>
              <div className="meta">Tearfund</div>
              <h4>Frames</h4>
            </div>
          </div>
        </div>
      </div>
    </section>);

}

// ===================================================================
// Hero — Reel variant (full-bleed BTS image)
// ===================================================================
function HeroReel({ onGoto }) {
  const [reelOpen, setReelOpen] = useState(false);
  return (
    <React.Fragment>
      <section className="hero-reel">
        <div className="reel-bg">
          <iframe
            className="reel-bg-video"
            src="https://iframe.mediadelivery.net/embed/653743/c48a2278-d069-4456-976c-c775bb412d05?autoplay=true&loop=true&muted=true&preload=true&responsive=true"
            allow="autoplay"
            aria-hidden="true"
            title="Valley Films hero reel"
            frameBorder="0"
          />
        </div>
        <div className="reel-overlay" />
        <div className="reel-frame-corners"><span /><span /></div>
        <div className="hero-reel-content">
          <div className="container">
            <div>
              <button
                type="button"
                className="eyebrow eyebrow-reel-link"
                onClick={() => setReelOpen(true)}
                style={{ marginBottom: 24 }}
                aria-label="Play Valley Films reel">
                <span className="idx">VF—01</span> Reel
              </button>
              <h1>Detail <em>driven</em> works for brands & agencies.</h1>
            </div>
          </div>
        </div>
      </section>
      {reelOpen && <WorkPlayer work={REEL_WORK} onClose={() => setReelOpen(false)} />}
    </React.Fragment>);

}

function Hero({ variant, onGoto }) {
  if (variant === 'stacked') return <HeroStacked onGoto={onGoto} />;
  if (variant === 'reel') return <HeroReel onGoto={onGoto} />;
  return <HeroMarquee onGoto={onGoto} />;
}

// ===================================================================
// Client strip — repeating logo marquee. Each logo, if it matches a client
// in WORK, is clickable and notifies the parent page to filter the work
// grid to that client's productions. (Was: opened the most recent video.)
// ===================================================================
function ClientStrip({ onSelectClient }) {
  // Case-insensitive match against the logo's display name PLUS any aliases
  // (e.g. an "MWS" logo can declare aliases ['MatchWornShirt', 'Frame the Game B.V.']
  // so it matches a Notion client recorded under the parent legal entity).
  // Exact match wins; otherwise substring either direction.
  // Returns the first matching WORK entry (= most recent in array order).
  const matchVideo = (logo) => {
    const candidates = [logo.name, ...(logo.aliases || [])].map((s) => s.toLowerCase());
    let exact, substr;
    for (const w of WORK) {
      const cname = (w.client || '').toLowerCase();
      if (candidates.includes(cname)) { exact = w; break; }
      if (!substr && candidates.some((c) => cname.includes(c) || c.includes(cname))) substr = w;
    }
    return exact || substr || null;
  };

  const items = CLIENT_LOGOS.map((c) => ({ ...c, video: matchVideo(c) }));

  const renderItem = (c, i) => {
    const interactive = !!c.video;
    const select = () => interactive && onSelectClient && onSelectClient(c.video.client);
    return (
      <span
        key={`${c.name}-${i}`}
        className={`item logo-item${interactive ? ' is-interactive' : ''}`}
        onClick={select}
        role={interactive ? 'button' : undefined}
        tabIndex={interactive ? 0 : undefined}
        aria-label={interactive ? `Filter work by ${c.video.client}` : c.name}
        onKeyDown={interactive ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); select(); } } : undefined}
        data-hover={interactive ? 'Filter' : undefined}>
        <img src={c.logo} alt={c.name} loading="lazy" />
      </span>);
  };

  // Render N identical sets so the marquee can translate by exactly
  // 1/N and loop seamlessly. N=4 keeps coverage even on wide displays
  // (3 sets give ~1900px of content; viewports above ~2000px would otherwise
  // show a momentary gap).
  const SETS = 4;

  // rAF-driven marquee. Hand-rolled instead of CSS animation so the speed
  // can be smoothly interpolated when the pointer enters/leaves — a CSS
  // `animation-duration` swap is discrete and produces a visible jump as
  // the browser re-derives current progress for the new timeline. With a
  // JS loop we lerp the current speed toward a target each frame, so the
  // motion just glides into the slower rate without skipping.
  const stripRef = useRef(null);
  const trackRef = useRef(null);
  useEffect(() => {
    const strip = stripRef.current;
    const track = trackRef.current;
    if (!strip || !track) return;

    // Width of one set + the trailing 80px gap. We only ever wrap by this
    // amount, so seams are invisible regardless of how many sets render.
    let setW = 0;
    const measure = () => {
      const set = track.querySelector('.client-strip-set');
      if (set) setW = set.getBoundingClientRect().width;
    };
    measure();
    window.addEventListener('resize', measure);

    // Speed in px/ms. Tuned to roughly match the previous CSS keyframes
    // (50s for one full set on desktop, 32s on mobile). We re-evaluate
    // baseSpeed() inside the loop so a viewport rotation/resize picks up
    // the new cadence without remounting.
    const baseSpeed = () => (window.innerWidth < 760 ? 0.10 : 0.06);
    const HOVER_FACTOR = 0.18; // ~5.5x slower while hovered
    let target = baseSpeed();
    let speed = target;
    let pos = 0;
    let last = performance.now();

    const onEnter = () => { target = baseSpeed() * HOVER_FACTOR; };
    const onLeave = () => { target = baseSpeed(); };
    strip.addEventListener('mouseenter', onEnter);
    strip.addEventListener('mouseleave', onLeave);

    let raf;
    const loop = (t) => {
      const dt = Math.min(48, t - last); // clamp dt so a tab-switch resume doesn't lurch
      last = t;
      // Half-life ~200ms — fast enough to feel responsive, slow enough to feel like a glide.
      const k = 1 - Math.pow(0.001, dt / 1000);
      speed += (target - speed) * k;
      pos -= speed * dt;
      if (setW > 0) {
        // Wrap by exactly one set so the next copy lines up with no jump.
        while (-pos >= setW) pos += setW;
      }
      track.style.transform = `translate3d(${pos}px, 0, 0)`;
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('resize', measure);
      strip.removeEventListener('mouseenter', onEnter);
      strip.removeEventListener('mouseleave', onLeave);
    };
  }, []);

  return (
    <div className="client-strip" ref={stripRef}>
      <div className="client-strip-track" ref={trackRef}>
        {Array.from({ length: SETS }, (_, n) => (
          <span key={n} className="client-strip-set" aria-hidden={n > 0 ? true : undefined}>
            {items.map((c, i) => renderItem(c, n * 1000 + i))}
          </span>
        ))}
      </div>
    </div>);

}

// ===================================================================
// Work index — FilmLaab-style numbered list with hover preview
// ===================================================================
function WorkIndex({ items }) {
  const [hover, setHover] = useState(null);
  const [pos, setPos] = useState({ x: 0, y: 0 });
  return (
    <div className="work-index" onMouseLeave={() => setHover(null)} onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}>
      {items.map((w, i) =>
      <div key={w.id}
      className="work-row"
      onMouseEnter={() => setHover(w)}
      data-hover="Open">
          <div className="idx">W—{String(i + 1).padStart(2, '0')}</div>
          <div className="title">{w.title}</div>
          <div className="client">{w.client}</div>
          <div className="tags">{w.tags.map((t) => <span key={t} className="tag">{t}</span>)}</div>
          <div className="arrow"><Icon name="arrow-up-right" /></div>
        </div>
      )}
      <div className={`work-preview ${hover ? 'is-visible' : ''}`}
      style={{ left: pos.x, top: pos.y, backgroundImage: hover ? `url(${hover.img})` : 'none' }} />
    </div>);

}

// ===================================================================
// Bunny pull-zone hostname for the Valley Films stream library 653743.
// Used to derive hover-preview asset URLs from any embed/play URL. Same
// library = same pull zone = same prefix for every video.
//
// `bunnyMp4Url` returns one of Bunny's MP4-fallback renditions (480p by
// default — sharp enough for a tile-sized hover, ~1–3 MB, only fetched
// when a user lingers on a tile). The full set Bunny serves when "MP4
// fallback" is enabled in the library Encoding settings:
//   play_240p.mp4, play_360p.mp4, play_480p.mp4, play_720p.mp4, play_1080p.mp4
// `bunnyPreviewUrl` is kept around for the touch-device fallback (it
// renders the static animated webp instead of fetching real video).
// ===================================================================
const BUNNY_PULL_ZONE = 'https://vz-c00d983c-d04.b-cdn.net';
function bunnyGuid(url) {
  const m = (url || '').match(/(?:embed|play)\/\d+\/([0-9a-f-]+)/i);
  return m ? m[1] : null;
}
function bunnyPreviewUrl(url) {
  const id = bunnyGuid(url);
  return id ? `${BUNNY_PULL_ZONE}/${id}/preview.webp` : null;
}
function bunnyMp4Url(url, res = '480p') {
  const id = bunnyGuid(url);
  return id ? `${BUNNY_PULL_ZONE}/${id}/play_${res}.mp4` : null;
}

// True on devices with a real mouse (fine pointer + hover). We gate the
// video-on-hover behaviour behind this so iOS / Android / touchscreens
// don't auto-fetch ~MB MP4s when a finger brushes past a tile.
const supportsHoverPreview = () =>
  typeof window !== 'undefined' &&
  window.matchMedia &&
  window.matchMedia('(hover: hover) and (pointer: fine)').matches;

// ===================================================================
// Tile hover preview — replaces the old preview.webp <img>. Mounts a
// muted <video> with preload="none" so nothing loads until the user
// actually hovers. We wait ~120ms before play to filter out the
// micro-hovers as the pointer crosses the grid; otherwise every tile
// in the path would trigger a fetch.
//
// On touch devices (no hover support) we render the static preview.webp
// instead — same fade-in feel, zero video bandwidth on mobile.
// ===================================================================
function TileHoverPreview({ mp4Src, webpSrc, isHovered }) {
  const videoRef = useRef(null);
  const [playReady, setPlayReady] = useState(false);
  // Capture the hover-capability once, on mount — matchMedia changes are
  // exceedingly rare in practice and re-evaluating per render is wasted work.
  const canHover = useRef(supportsHoverPreview()).current;

  useEffect(() => {
    if (!canHover) return;
    const v = videoRef.current;
    if (!v) return;
    if (isHovered) {
      // Brief delay so a fast pass over the grid doesn't fire a play() on
      // every tile in the path. If the user leaves before 120ms is up,
      // we never even start fetching.
      const t = setTimeout(() => {
        // Lazy-attach src on first hover. After that the browser caches
        // the file, so subsequent hovers play instantly.
        if (!v.src && mp4Src) v.src = mp4Src;
        const p = v.play();
        if (p && typeof p.catch === 'function') p.catch(() => { /* autoplay blocked — fine */ });
        setPlayReady(true);
      }, 120);
      return () => clearTimeout(t);
    } else {
      v.pause();
      // Don't reset currentTime — if the user comes back the loop resumes
      // mid-frame, which feels more alive than restarting from 0.
      setPlayReady(false);
    }
  }, [isHovered, mp4Src, canHover]);

  if (!canHover) {
    // Touch / coarse-pointer fallback — keep the lightweight webp.
    return webpSrc ? (
      <img className="tile-bg-preview" src={webpSrc} alt="" aria-hidden="true" loading="lazy" />
    ) : null;
  }

  if (!mp4Src) return null;
  return (
    <video
      ref={videoRef}
      className={`tile-bg-preview tile-bg-video${playReady ? ' is-playing' : ''}`}
      muted
      loop
      playsInline
      preload="none"
      aria-hidden="true"
      tabIndex={-1}
    />);

}

// ===================================================================
// Work grid — alt view. URL-driven: /work/:slug opens the player modal.
// ===================================================================
function WorkGrid({ items, workSlug }) {
  // Ranking drives both sort order and tile size. High → top + full-width;
  // Medium → middle + half-width; Low → bottom + third-width.
  // Row-aware packer: ranks bias the order (High → Medium → Low, ties keep
  // their incoming order), then we partition into rows of 1, 2 or 3 items
  // using a vocabulary that always sums to 12 cols. The result: bottom row
  // is always full, AND high-rank items naturally land in bigger slots
  // because rank-sorted items get placed first. Within a 2-item row,
  // mixed ranks → [8, 4] (asymmetric, more visual interest); equal ranks
  // → [6, 6]. Mobile (<900px) collapses everything to full-width via
  // existing CSS, so the packer's output sizes don't need responsive
  // adjustments.
  const RANK_WEIGHT = { High: 3, Medium: 2, Low: 1 };
  const ranked = [...items]
    .map((w, i) => ({ w, i, weight: RANK_WEIGHT[w.ranking] ?? 2 }))
    .sort((a, b) => b.weight - a.weight || a.i - b.i)
    .map(({ w }) => w);
  const ROW_PATTERNS = {
    1: [1],
    2: [2],
    3: [3],
    4: [1, 3],
    5: [2, 3],
    6: [1, 2, 3],
    7: [1, 3, 3],
    8: [1, 2, 2, 3],
    9: [1, 2, 3, 3],
    10: [1, 3, 3, 3],
    11: [2, 3, 3, 3],
    12: [1, 2, 3, 3, 3],
  };
  const partition = (n) =>
    n <= 0 ? [] :
    n <= 12 ? ROW_PATTERNS[n] :
    [...ROW_PATTERNS[12], ...partition(n - 12)];
  const sized = [];
  let rIdx = 0;
  for (const rowSize of partition(ranked.length)) {
    if (rowSize === 1) {
      sized.push({ w: ranked[rIdx], col: 12 });
      rIdx += 1;
    } else if (rowSize === 2) {
      const a = ranked[rIdx];
      const b = ranked[rIdx + 1];
      const mixed = a.ranking !== b.ranking;
      sized.push({ w: a, col: mixed ? 8 : 6 });
      sized.push({ w: b, col: mixed ? 4 : 6 });
      rIdx += 2;
    } else {
      sized.push({ w: ranked[rIdx], col: 4 });
      sized.push({ w: ranked[rIdx + 1], col: 4 });
      sized.push({ w: ranked[rIdx + 2], col: 4 });
      rIdx += 3;
    }
  }
  const active = workSlug ? items.find((w) => slugForWork(w) === workSlug) : null;
  // Closing the modal: pop history. If the user landed direct on /work/foo
  // (no in-app history), fall back to pushing /.
  const closePlayer = () => {
    if (window.history.length > 1) {
      window.history.back();
    } else {
      window.history.pushState(null, '', '/');
      window.dispatchEvent(new PopStateEvent('popstate'));
    }
  };
  return (
    <React.Fragment>
      <div className="work-grid">
        {sized.map(({ w, col }) => (
          <WorkTile key={w.id} w={w} col={col} />
        ))}
      </div>
      {active && <WorkPlayer work={active} onClose={closePlayer} />}
    </React.Fragment>);

}

// ===================================================================
// Single tile — extracted so each one can own its hover state. That
// state drives TileHoverPreview, which lazy-loads the real MP4 from
// Bunny when the pointer settles on a tile (fine-pointer devices only;
// touch devices get the static webp).
// ===================================================================
function WorkTile({ w, col }) {
  const [hovered, setHovered] = useState(false);
  const duration = (w.tags || []).find((t) => /^\d+:\d+$/.test(t));
  const chips = [w.type, duration].filter(Boolean);
  const size = `col-${col}`;
  const href = `/work/${slugForWork(w)}`;
  const mp4Src = bunnyMp4Url(w.videoUrl, '480p');
  const webpSrc = bunnyPreviewUrl(w.videoUrl);

  return (
    <a
      href={href}
      className={`tile ${size}`}
      data-hover="Play"
      aria-label={`${w.client} — ${w.title}`}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      onFocus={() => setHovered(true)}
      onBlur={() => setHovered(false)}>
      <div className="tile-bg" style={{ backgroundImage: `url(${w.img})` }} />
      <TileHoverPreview mp4Src={mp4Src} webpSrc={webpSrc} isHovered={hovered} />
      <div className="tile-meta-top">
        <span className="num">{w.client}</span>
        <span className="tile-play-btn" aria-hidden="true">
          <svg viewBox="0 0 14 14" width="12" height="12">
            <path d="M3 1.5 L12 7 L3 12.5 Z" fill="currentColor" />
          </svg>
        </span>
      </div>
      <div className="tile-content">
        <div className="chips">
          {chips.map((c) => <span key={`${w.id}-${c}`} className="chip">{c}</span>)}
        </div>
        <h3 className="title">{w.title}</h3>
      </div>
    </a>);

}

// ===================================================================
// Work mini-player — opens on tile click
// ===================================================================
function WorkPlayer({ work, onClose }) {
  const [shared, setShared] = useState(false);
  useEffect(() => {
    const FOCUSABLE = 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"]), input, textarea, select';
    const onKey = (e) => {
      if (e.key === 'Escape') { onClose(); return; }
      if (e.key !== 'Tab') return;
      const modal = document.querySelector('.vf-player-shell');
      if (!modal) return;
      const items = [...modal.querySelectorAll(FOCUSABLE)].filter(el => !el.hidden && el.offsetParent !== null);
      if (!items.length) return;
      const first = items[0], last = items[items.length - 1];
      if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
      else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
    };
    window.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    const focusInModal = setTimeout(() => {
      const closeBtn = document.querySelector('.vf-player-shell .player-close, .vf-player-shell button');
      closeBtn && closeBtn.focus();
    }, 0);
    return () => {
      clearTimeout(focusInModal);
      window.removeEventListener('keydown', onKey);
      document.body.style.overflow = '';
    };
  }, [onClose]);
  const duration = (work.tags || []).find((t) => /^\d+:\d+$/.test(t));
  const videoUrl = work.videoUrl || REEL_URL;
  // Normalise Bunny Stream player URLs to their iframe embed equivalent.
  // player.mediadelivery.net/play/{lib}/{guid} → iframe.mediadelivery.net/embed/{lib}/{guid}
  const bunnyMatch = videoUrl.match(/^https?:\/\/(?:player|iframe)\.mediadelivery\.net\/(?:play|embed)\/(\d+)\/([0-9a-f-]+)/i);
  const isBunny = !!bunnyMatch;
  const baseEmbed = isBunny
    ? `https://iframe.mediadelivery.net/embed/${bunnyMatch[1]}/${bunnyMatch[2]}`
    : videoUrl;
  const autoplayParams = isBunny
    ? 'autoplay=true&preload=true'
    : 'autoplay=1&title=0&byline=0&portrait=0';
  const embedSrc = baseEmbed.includes('?') ? baseEmbed : `${baseEmbed}?${autoplayParams}`;
  const onShare = async () => {
    const url = window.location.href;
    try {
      if (navigator.share) {
        await navigator.share({ title: `${work.client} — ${work.title}`, url });
      } else {
        await navigator.clipboard.writeText(url);
        setShared(true);
        setTimeout(() => setShared(false), 1800);
      }
    } catch { /* user-cancelled or unsupported */ }
  };
  return (
    <div className="vf-player" onClick={onClose}>
      <div className="vf-player-shell" onClick={(e) => e.stopPropagation()}>
        <div className="vf-player-head">
          <div className="vf-player-meta">
            <span className="vf-player-type">{work.type}</span>
            {duration && <><span className="vf-player-sep">·</span><span>{duration}</span></>}
          </div>
          <button className="vf-player-close" type="button" onClick={onClose} aria-label="Close" data-hover="Close">
            <svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true">
              <path d="M3 3 L13 13 M13 3 L3 13" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
            </svg>
          </button>
        </div>
        <div className="vf-player-stage">
          <iframe
            className="vf-player-frame"
            src={embedSrc}
            title={`${work.client} — ${work.title}`}
            allow="autoplay; fullscreen; picture-in-picture"
            allowFullScreen
            frameBorder="0"
          />
        </div>
        <div className="vf-player-foot">
          <div className="vf-player-titles">
            <div className="vf-player-client">{work.client}</div>
            <h2 className="vf-player-title">{work.title}</h2>
            {work.description && <p className="vf-player-desc">{work.description}</p>}
          </div>
          <div className="vf-player-actions">
            <button className="vf-player-action" type="button" data-hover="Share" onClick={onShare}>
              {shared ? 'Link copied' : 'Share'}
            </button>
          </div>
        </div>
      </div>
    </div>);

}

Object.assign(window, { Hero, ClientStrip, WorkIndex, WorkGrid, WorkPlayer });