const { useState, useEffect, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroStyle": "diagram",
  "mapStyle": "world",
  "showCounter": true
}/*EDITMODE-END*/;

// ============ ICONS ============
const Icon = {
  Arrow: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <path d="M5 12 H19 M13 6 L19 12 L13 18" stroke="currentColor" strokeWidth="1.8" strokeLinecap="square" strokeLinejoin="miter"/>
    </svg>
  ),
  Check: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <path d="M5 12 L10 17 L19 7" stroke="currentColor" strokeWidth="2.2" strokeLinecap="square" strokeLinejoin="miter"/>
    </svg>
  ),
  Menu: (p) => (
    <svg viewBox="0 0 24 24" fill="none" {...p}>
      <line x1="4" y1="6" x2="20" y2="6" stroke="currentColor" strokeWidth="1.8"/>
      <line x1="4" y1="12" x2="20" y2="12" stroke="currentColor" strokeWidth="1.8"/>
      <line x1="4" y1="18" x2="20" y2="18" stroke="currentColor" strokeWidth="1.8"/>
    </svg>
  ),
  Card: (p) => (
    <svg viewBox="0 0 48 48" fill="none" {...p}>
      <path d="M12 6 H30 L36 12 V42 H12 Z" stroke="currentColor" strokeWidth="2"/>
      <rect x="16" y="14" width="16" height="6" stroke="currentColor" strokeWidth="1.5"/>
      <line x1="18" y1="17" x2="30" y2="17" stroke="currentColor" strokeWidth="3"/>
    </svg>
  ),
  Shield: (p) => (
    <svg viewBox="0 0 48 48" fill="none" {...p}>
      <path d="M24 4 L42 10 V24 C42 34 34 41 24 44 C14 41 6 34 6 24 V10 Z" stroke="currentColor" strokeWidth="2.5"/>
      <path d="M16 24 L22 30 L33 18" stroke="currentColor" strokeWidth="3" strokeLinecap="square"/>
    </svg>
  ),
  Stack: (p) => (
    <svg viewBox="0 0 48 48" fill="none" {...p}>
      <path d="M24 6 L42 14 L24 22 L6 14 Z" stroke="currentColor" strokeWidth="2"/>
      <path d="M6 22 L24 30 L42 22" stroke="currentColor" strokeWidth="2"/>
      <path d="M6 30 L24 38 L42 30" stroke="currentColor" strokeWidth="2"/>
    </svg>
  ),
  Cpu: (p) => (
    <svg viewBox="0 0 48 48" fill="none" {...p}>
      <rect x="12" y="12" width="24" height="24" stroke="currentColor" strokeWidth="2"/>
      <rect x="18" y="18" width="12" height="12" stroke="currentColor" strokeWidth="1.5"/>
      {[0,1,2].map(i => (
        <React.Fragment key={i}>
          <line x1={16+i*6} y1="6" x2={16+i*6} y2="12" stroke="currentColor" strokeWidth="1.5"/>
          <line x1={16+i*6} y1="36" x2={16+i*6} y2="42" stroke="currentColor" strokeWidth="1.5"/>
          <line x1="6" y1={16+i*6} x2="12" y2={16+i*6} stroke="currentColor" strokeWidth="1.5"/>
          <line x1="36" y1={16+i*6} x2="42" y2={16+i*6} stroke="currentColor" strokeWidth="1.5"/>
        </React.Fragment>
      ))}
    </svg>
  ),
  Globe: (p) => (
    <svg viewBox="0 0 48 48" fill="none" {...p}>
      <circle cx="24" cy="24" r="18" stroke="currentColor" strokeWidth="2"/>
      <ellipse cx="24" cy="24" rx="8" ry="18" stroke="currentColor" strokeWidth="1.5"/>
      <line x1="6" y1="24" x2="42" y2="24" stroke="currentColor" strokeWidth="1.5"/>
    </svg>
  ),
  Cloud: (p) => (
    <svg viewBox="0 0 48 48" fill="none" {...p}>
      <path d="M14 34 C8 34 6 30 6 26 C6 22 9 18 14 18 C15 13 19 10 24 10 C30 10 34 14 35 19 C40 19 42 22 42 26 C42 30 39 34 34 34 Z" stroke="currentColor" strokeWidth="2"/>
      <path d="M19 28 L24 33 L29 28" stroke="currentColor" strokeWidth="2.5"/>
      <line x1="24" y1="22" x2="24" y2="32" stroke="currentColor" strokeWidth="2.5"/>
    </svg>
  ),
  Folder: (p) => (
    <svg viewBox="0 0 16 16" fill="none" {...p}>
      <path d="M1 4 H6 L7.5 5.5 H15 V13 H1 Z" stroke="currentColor" strokeWidth="1" fill="none"/>
    </svg>
  ),
  File: (p) => (
    <svg viewBox="0 0 16 16" fill="none" {...p}>
      <path d="M3 1 H10 L13 4 V15 H3 Z" stroke="currentColor" strokeWidth="1"/>
      <path d="M10 1 V4 H13" stroke="currentColor" strokeWidth="1"/>
    </svg>
  ),
};

// ============ NAV ============
function Nav({ scrolled }) {
  const [menuOpen, setMenuOpen] = useState(false);
  useEffect(() => {
    document.body.style.overflow = menuOpen ? 'hidden' : '';
    return () => { document.body.style.overflow = ''; };
  }, [menuOpen]);
  const closeMenu = () => setMenuOpen(false);
  const scrollTop = (e) => { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); closeMenu(); };
  return (
    <header className={`nav ${scrolled ? 'nav--solid' : 'nav--floating'}`}>
      <div className="nav__inner">
        <a href="/" className="nav__logo" aria-label="Ages Productions home">
          <img src="assets/logo-primary.png" alt="Ages Productions"/>
        </a>
        <nav className="nav__links">
          <a href="/" className="nav__link">Home</a>
          <a href="#" className="nav__link nav__link--active" onClick={(e) => { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); }}>Media Workflow</a>
          <a href="Ages Productions Self-Shoot.html" className="nav__link">Self-Shoot Systems</a>
          <a href="Ages Productions About.html" className="nav__link">About</a>
          <a href="Ages Productions Use Cases.html" className="nav__link">Use Cases</a>
          <a href="Ages Productions Contact.html" className="nav__link">Contact</a>
        </nav>
        <div className="nav__cta"></div>
        <button className="nav__menu" aria-label={menuOpen ? "Close menu" : "Open menu"} aria-expanded={menuOpen} onClick={() => setMenuOpen(o => !o)}>
          {menuOpen
            ? <svg viewBox="0 0 24 24" width="22" height="22" fill="none"><line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" strokeWidth="1.8"/><line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" strokeWidth="1.8"/></svg>
            : <Icon.Menu width="22" height="22"/>}
        </button>
      </div>
      <div className={`nav__drawer ${menuOpen ? 'nav__drawer--open' : ''}`} aria-hidden={!menuOpen}>
        <div className="nav__drawer-inner">
            <a href="/" className="nav__drawer-link" onClick={closeMenu}>Home</a>
            <a href="#" className={`nav__drawer-link nav__drawer-link--active`} onClick={scrollTop}>Media Workflow</a>
            <a href="Ages Productions Self-Shoot.html" className="nav__drawer-link" onClick={closeMenu}>Self-Shoot Systems</a>
            <a href="Ages Productions About.html" className="nav__drawer-link" onClick={closeMenu}>About</a>
            <a href="Ages Productions Use Cases.html" className="nav__drawer-link" onClick={closeMenu}>Use Cases</a>
            <a href="Ages Productions Contact.html" className="nav__drawer-link" onClick={closeMenu}>Contact</a>
        </div>
      </div>
    </header>
  );
}

// ============ HERO — animated diagram ============
function Hero() {
  return (
    <section className="mw-hero">
      <div className="mw-hero__bg" aria-hidden="true">
        <div className="mw-hero__grid"></div>
      </div>
      <div className="mw-hero__inner container">
        <div className="mw-hero__copy">
          <div className="hero__eyebrow">
            <span className="dot"></span>
            <span>MEDIA WORKFLOW</span>
            <span className="hero__eyebrow-sub">Field → Post · 50TB / day</span>
          </div>
          <h1 className="mw-hero__title">
            Every card.<br/>
            <span className="text-blue-light">Every checksum.</span><br/>
            Every clip accounted for.
          </h1>
          <p className="mw-hero__lede">
            High-volume Reality TV media management — verified offloads, redundant backups,
            organized reports, and clean handoffs from set to post. Now with remote &amp; cloud
            delivery built in.
          </p>
          <div className="mw-hero__cta">
            <a href="Ages Productions Contact.html" className="btn btn--primary">
              <span>Build a Media Plan</span>
              <Icon.Arrow width="18" height="18"/>
            </a>
            <a href="#capabilities" className="btn btn--outline-light">
              <span>See capabilities</span>
            </a>
          </div>
        </div>

        {/* Diagram */}
        <div className="mw-hero__diagram" aria-hidden="true">
          <div className="diag">
            <div className="diag__node diag__node--field">
              <span className="diag__label">FIELD</span>
              <span className="diag__count">8 CAMS</span>
            </div>
            <div className="diag__line"><span className="diag__pulse"></span></div>
            <div className="diag__node diag__node--bay">
              <span className="diag__label">DIT BAY</span>
              <span className="diag__count">11.42 TB</span>
            </div>
            <div className="diag__line"><span className="diag__pulse" style={{animationDelay:'0.6s'}}></span></div>
            <div className="diag__node diag__node--cloud">
              <span className="diag__label">POST</span>
              <span className="diag__count">PROXIES</span>
            </div>

            <div className="diag__readout">
              <div><em>OFFLOAD</em><span className="green">VERIFIED</span></div>
              <div><em>BACKUP</em><span className="green">MIRROR ✓</span></div>
              <div><em>UPLOAD</em><span className="blue">612 GB → S3</span></div>
              <div><em>STATUS</em><span>DAY 27 / S04</span></div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ============ STAT TICKER ============
function StatTicker() {
  const [vals, setVals] = useState({ tb: 0, cards: 0, sites: 0, checksum: 0 });
  const ref = useRef(null);
  useEffect(() => {
    const obs = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        const targets = { tb: 50, cards: 80, sites: 4, checksum: 100 };
        const dur = 1400;
        const start = performance.now();
        const tick = (now) => {
          const p = Math.min(1, (now - start) / dur);
          const e = 1 - Math.pow(1 - p, 3);
          setVals({
            tb: Math.round(targets.tb * e),
            cards: Math.round(targets.cards * e),
            sites: Math.round(targets.sites * e),
            checksum: Math.round(targets.checksum * e),
          });
          if (p < 1) requestAnimationFrame(tick);
        };
        requestAnimationFrame(tick);
        obs.disconnect();
      }
    }, { threshold: 0.4 });
    if (ref.current) obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  const stats = [
    { v: vals.tb, suf: 'TB', label: 'DAILY OFFLOAD CAPACITY' },
    { v: vals.cards, suf: '/day', label: 'CARDS HANDLED PER SHOOT DAY' },
    { v: vals.sites, suf: 'SITES', label: 'CONCURRENT CITY TRANSFERS' },
    { v: vals.checksum, suf: '%', label: 'CHECKSUM-VERIFIED' },
  ];
  return (
    <section className="counter" ref={ref}>
      <div className="container">
        <div className="counter__grid">
          {stats.map((s, i) => (
            <div className="counter__cell" key={i}>
              <div className="counter__num">{s.v}<span className="counter__suf">{s.suf}</span></div>
              <div className="counter__label">{s.label}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ============ PROBLEM ============
function Problem() {
  const pains = [
    "Cards arrive faster than the bay can offload them.",
    "Notes from set don't survive the handoff to post.",
    "Three teams disagree on what was actually shot today.",
    "A clip looks fine on the drive but won't play back — caught in post, not on set.",
    "Proxies for editorial show up half a day late, every day.",
  ];
  return (
    <section className="mw-problem" id="problem">
      <div className="container mw-problem__grid">
        <div>
          <span className="section-label">[01]&nbsp;&nbsp;THE PROBLEM</span>
          <h2 className="h-display">
            Reality TV is not a one-camera movie set.<br/>
            <span className="text-blue">Most workflows aren't built for it.</span>
          </h2>
        </div>
        <div className="mw-problem__body">
          <p>
            High-volume, unpredictable, multi-camera, multi-location, deadline-driven. Most data
            services are built around copying cards. Reality TV needs more — speed, organization,
            tracking, and communication that match the volume coming off set.
          </p>
          <ul className="mw-problem__list">
            {pains.map((p, i) => (
              <li key={i}>
                <span className="mw-problem__bullet">!</span>
                <span>{p}</span>
              </li>
            ))}
          </ul>
          <p className="mw-problem__pull">
            That's the gap Ages Productions is built to close.
          </p>
        </div>
      </div>
    </section>
  );
}

// ============ CAPABILITIES GRID ============
function Capabilities() {
  const caps = [
    { icon: Icon.Cpu, title: "AI-Assisted Logging", desc: "Automatic metadata extraction and logging into your media log style — clean, consistent, and ready to hand to post." },
    { icon: Icon.Stack, title: "High-Volume Offloads", desc: "50 TB per day handled comfortably with multi-bay parallel ingest and verified throughput. We can scale higher when the production calls for it." },
    { icon: Icon.Globe, title: "Concurrent City Transfers", desc: "Multiple cities running in parallel, syncing back to a single source of truth with no manual reconciliation." },
    { icon: Icon.Cloud, title: "Cross-Country & International", desc: "Workflows designed for productions shooting across borders — chain-of-custody never breaks." },
    { icon: Icon.Card, title: "Proxy Transcoding for NLE", desc: "Editorial-ready proxies generated on the fly. Avid, Premiere, and Resolve workflows supported." },
    { icon: Icon.Shield, title: "Checksum Verification", desc: "Every byte verified twice. Redundant backups, drive labeling, organized folders, and clear issue reports." },
  ];
  return (
    <section className="mw-cap" id="capabilities">
      <div className="container">
        <div className="mw-cap__head">
          <span className="section-label">[02]&nbsp;&nbsp;CAPABILITIES</span>
          <h2 className="h-display">
            Built for high data volume<br/>
            <span className="text-blue">Reality TV media management.</span>
          </h2>
          <p className="mw-cap__lede">
            Most people can copy cards. Fewer people can keep a high-volume daily workflow
            organized, verified, tracked, and ready for post.
          </p>
        </div>
        <div className="mw-cap__grid">
          {caps.map((c, i) => (
            <div className="mw-cap__cell" key={i}>
              <div className="mw-cap__num">{String(i+1).padStart(2,'0')}</div>
              <div className="mw-cap__icon"><c.icon width="44" height="44"/></div>
              <div className="mw-cap__title">{c.title}</div>
              <p className="mw-cap__desc">{c.desc}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ============ FOLDER TREE ============
function FolderTree() {
  const tree = [
    { type: 'folder', label: 'PROD_2241_S04', depth: 0 },
    { type: 'folder', label: '_DOCS', depth: 1, meta: 'wrap reports + logs' },
    { type: 'folder', label: 'DAY_27', depth: 1, hot: true },
    { type: 'folder', label: 'CAM_A', depth: 2, meta: '4 cards · 3.2 TB' },
    { type: 'folder', label: 'CAM_B', depth: 2, meta: '3 cards · 2.4 TB' },
    { type: 'folder', label: 'CAM_C — PTZ', depth: 2, meta: '2 cards · 1.1 TB' },
    { type: 'folder', label: 'CAM_D — CAR RIG', depth: 2, meta: '2 cards · 1.6 TB · ⚑ flagged' },
    { type: 'folder', label: 'GOPROS', depth: 2, meta: '6 cards · 1.8 TB' },
    { type: 'folder', label: 'CAST_PHONES', depth: 2, meta: '4 phones · 0.6 TB' },
    { type: 'folder', label: '_PROXIES', depth: 2, meta: 'NLE-ready · 612 GB' },
    { type: 'folder', label: '_BACKUP_LTO', depth: 2, meta: 'mirror verified ✓' },
    { type: 'file', label: 'WRAP_DAY27.pdf', depth: 1, meta: '21:42 PT' },
    { type: 'file', label: 'CHECKSUM_DAY27.txt', depth: 1, meta: 'sha256 · 11.42 TB' },
  ];
  return (
    <section className="mw-tree">
      <div className="container mw-tree__grid">
        <div>
          <span className="section-label">[03]&nbsp;&nbsp;FOLDER STRUCTURE</span>
          <h2 className="h-display">
            Clean folders.<br/>
            <span className="text-blue">No detective work for post.</span>
          </h2>
          <p className="mw-tree__lede">
            Every shoot day lands in a predictable structure: cameras, proxies, mirror, wrap
            report, and a checksum manifest. Post knows where everything lives before they open
            the drive.
          </p>
          <div className="mw-tree__legend">
            <span><span className="mw-tree__chip mw-tree__chip--hot"></span>Active day</span>
            <span><span className="mw-tree__chip mw-tree__chip--ok"></span>Verified</span>
            <span><span className="mw-tree__chip mw-tree__chip--warn"></span>Flagged for review</span>
          </div>
        </div>
        <div className="mw-tree__panel">
          <div className="mw-tree__head">
            <span>// ON-PREM FIELD STORAGE · 03</span>
            <span>11.42 TB · DAY 27 / S04</span>
          </div>
          <ul className="mw-tree__list">
            {tree.map((n, i) => (
              <li key={i} className={`mw-tree__row ${n.hot ? 'mw-tree__row--hot' : ''}`} style={{ paddingLeft: `${n.depth * 22 + 16}px` }}>
                <span className="mw-tree__icon">
                  {n.type === 'folder' ? <Icon.Folder width="14" height="14"/> : <Icon.File width="14" height="14"/>}
                </span>
                <span className="mw-tree__label">{n.label}</span>
                {n.meta && <span className="mw-tree__meta">{n.meta}</span>}
              </li>
            ))}
          </ul>
        </div>
      </div>
    </section>
  );
}

// ============ REMOTE & CLOUD SUB-SECTION ============
function RemoteCloud({ mapStyle }) {
  // Routing diagram — hub-and-spoke with origin at center.
  const hub = { x: 500, y: 250, name: "AGES PRODUCTIONS", role: "ORIGIN HUB" };
  const cities = [
    { name: "LOS ANGELES",    x: 165, y: 130, role: "FIELD",   state: "live",   tag: "OFFLOAD · 11.4 TB" },
    { name: "NEW YORK",       x: 165, y: 370, role: "DIT BAY", state: "live",   tag: "PROXY · 612 GB" },
    { name: "LONDON",         x: 835, y: 130, role: "POST",    state: "synced", tag: "S3 · MIRROR ✓" },
    { name: "BERLIN",         x: 835, y: 250, role: "POST",    state: "queued", tag: "QUEUED · 2.1 TB" },
    { name: "SYDNEY",         x: 835, y: 370, role: "FIELD",   state: "synced", tag: "DAILY SYNC ✓" },
  ];
  return (
    <section className="mw-cloud" id="remote-cloud">
      <div className="container">
        <div className="mw-cloud__head">
          <span className="section-label section-label--light">[04]&nbsp;&nbsp;REMOTE &amp; CLOUD DELIVERY</span>
          <h2 className="h-display mw-cloud__title">
            Editorial access<br/>
            <span className="text-blue-light">while you're still shooting.</span>
          </h2>
          <p className="mw-cloud__lede">
            For productions that need post moving in parallel with the field. Daily proxy uploads,
            secured on-prem access, S3 / object cloud transfer support, upload tracking, and remote
            post coordination — built into the same workflow.
          </p>
        </div>

        {/* World map */}
        <div className="mw-map">
          <div className="mw-map__head">
            <span>// ACTIVE TRANSFERS · LIVE</span>
            <span className="mw-map__dot mw-map__dot--live"></span>
            <span>3 sites streaming · 2 queued</span>
          </div>
          <svg viewBox="0 0 1000 500" className="mw-map__svg" aria-hidden="true">
            <defs>
              <pattern id="grid" x="0" y="0" width="40" height="40" patternUnits="userSpaceOnUse">
                <path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.04)" strokeWidth="1"/>
              </pattern>
              <linearGradient id="link" x1="0" x2="1" y1="0" y2="0">
                <stop offset="0" stopColor="#7A9BC2" stopOpacity="0.15"/>
                <stop offset="0.5" stopColor="#7A9BC2" stopOpacity="0.9"/>
                <stop offset="1" stopColor="#7A9BC2" stopOpacity="0.15"/>
              </linearGradient>
              <radialGradient id="hubGlow" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0" stopColor="#7A9BC2" stopOpacity="0.4"/>
                <stop offset="1" stopColor="#7A9BC2" stopOpacity="0"/>
              </radialGradient>
              <filter id="whiteOut" colorInterpolationFilters="sRGB">
                <feColorMatrix type="matrix" values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1   0 0 0 1 0"/>
              </filter>
            </defs>
            <rect x="0" y="0" width="1000" height="500" fill="url(#grid)"/>

            {/* center crosshair frame */}
            <g stroke="rgba(255,255,255,0.08)" strokeWidth="1" fill="none">
              <circle cx={hub.x} cy={hub.y} r="80" strokeDasharray="3 5"/>
              <circle cx={hub.x} cy={hub.y} r="140" strokeDasharray="2 8"/>
              <line x1="0" y1={hub.y} x2="1000" y2={hub.y} strokeDasharray="2 6"/>
              <line x1={hub.x} y1="0" x2={hub.x} y2="500" strokeDasharray="2 6"/>
            </g>

            {/* hub glow */}
            <circle cx={hub.x} cy={hub.y} r="120" fill="url(#hubGlow)"/>

            {/* spoke links from hub to each city */}
            {cities.map((c, i) => {
              // Find edge of hub box to start from, not corner
              const hubW = 200, hubH = 70;
              const dx = c.x - hub.x, dy = c.y - hub.y;
              const angle = Math.atan2(dy, dx);
              // Determine which edge to exit from
              const t = Math.min(Math.abs((hubW/2) / Math.cos(angle)), Math.abs((hubH/2) / Math.sin(angle)));
              const sx = hub.x + Math.cos(angle) * t;
              const sy = hub.y + Math.sin(angle) * t;
              const path = `M ${sx} ${sy} L ${c.x} ${c.y}`;
              const isQueued = c.state === 'queued';
              return (
                <g key={`l${i}`}>
                  <path
                    d={path}
                    stroke={isQueued ? '#E5A152' : 'url(#link)'}
                    strokeWidth="1.5"
                    fill="none"
                    strokeDasharray={isQueued ? '6 6' : 'none'}
                    opacity={isQueued ? 0.7 : 1}
                  >
                    {isQueued && (
                      <animate attributeName="stroke-dashoffset" from="0" to="-24" dur="1.5s" repeatCount="indefinite"/>
                    )}
                  </path>
                  {!isQueued && (
                    <circle r="3.5" fill="#7A9BC2">
                      <animateMotion dur={`${3 + i * 0.4}s`} repeatCount="indefinite" path={path}/>
                    </circle>
                  )}
                </g>
              );
            })}

            {/* hub node — sized to fit logo + text */}
            <g>
              <rect x={hub.x - 100} y={hub.y - 35} width="200" height="70" fill="#14171B" stroke="#7A9BC2" strokeWidth="1.5"/>
              <image href="assets/logo-primary.png" x={hub.x - 80} y={hub.y - 24} width="160" height="36" preserveAspectRatio="xMidYMid meet" filter="url(#whiteOut)"/>
              <text x={hub.x} y={hub.y + 28} textAnchor="middle" fontFamily="JetBrains Mono" fontSize="9" fill="#7A9BC2" letterSpacing="2.5">ORIGIN HUB</text>
            </g>

            {/* city nodes */}
            {cities.map((c, i) => {
              const isLeft = c.x < hub.x;
              const labelX = isLeft ? c.x - 18 : c.x + 18;
              const anchor = isLeft ? "end" : "start";
              const pinColor = c.state === 'live' ? '#5DCE8A' : c.state === 'queued' ? '#E5A152' : '#7A9BC2';
              return (
                <g key={`c${i}`}>
                  <circle cx={c.x} cy={c.y} r="16" fill="rgba(53,92,132,0.18)">
                    <animate attributeName="r" values="16;26;16" dur="2.8s" repeatCount="indefinite" begin={`${i * 0.45}s`}/>
                    <animate attributeName="opacity" values="0.6;0;0.6" dur="2.8s" repeatCount="indefinite" begin={`${i * 0.45}s`}/>
                  </circle>
                  <circle cx={c.x} cy={c.y} r="8" fill={pinColor}/>
                  <circle cx={c.x} cy={c.y} r="8" fill="none" stroke="#fff" strokeWidth="1.4"/>
                  <text x={labelX} y={c.y - 6} textAnchor={anchor} fontFamily="JetBrains Mono" fontSize="12" fill="#fff" letterSpacing="1.5">{c.name}</text>
                  <text x={labelX} y={c.y + 10} textAnchor={anchor} fontFamily="JetBrains Mono" fontSize="10" fill="rgba(255,255,255,0.5)" letterSpacing="1.2">{c.role}</text>
                  <text x={labelX} y={c.y + 24} textAnchor={anchor} fontFamily="JetBrains Mono" fontSize="9" fill={pinColor} letterSpacing="1">{c.tag}</text>
                </g>
              );
            })}
          </svg>
        </div>

        {/* Cloud features */}
        <div className="mw-cloud__features">
          {[
            { num: '01', title: 'Daily proxy uploads', desc: 'Source footage transcoded to NLE-ready proxies on a daily cadence. Synced to remote post during international productions so editors are never waiting on media.' },
            { num: '02', title: 'Secured on-prem access', desc: 'Direct access to source drives without compromising chain-of-custody. Audited, logged, revocable.' },
            { num: '03', title: 'S3 / object transfer', desc: 'Native support for AWS S3 and S3-compatible providers. Multipart, resumable, encrypted in flight and at rest.' },
            { num: '04', title: 'Upload tracking', desc: 'Live state per file: queued, in flight, synced, failed. Production sees the truth, not a promise.' },
          ].map((f, i) => (
            <div className="mw-cloud__feat" key={i}>
              <div className="mw-cloud__feat-num">{f.num}</div>
              <div className="mw-cloud__feat-title">{f.title}</div>
              <p className="mw-cloud__feat-desc">{f.desc}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ============ FINAL CTA ============
function FinalCTA() {
  return (
    <section className="cta" id="cta">
      <div className="cta__bg" aria-hidden="true"></div>
      <div className="container cta__inner">
        <span className="section-label">[05]&nbsp;&nbsp;NEXT STEP</span>
        <h2 className="cta__title">
          Build a workflow<br/>that keeps your media moving.
        </h2>
        <p className="cta__lede">
          On-set media management, remote post delivery, cast phone workflows, or a better
          production-to-post handoff — Ages Productions can build a workflow that fits your show.
        </p>
        <div className="cta__buttons">
          <a href="Ages Productions Contact.html" className="btn btn--primary btn--lg">
            <span>Build a Media Management Plan</span>
            <Icon.Arrow width="20" height="20"/>
          </a>
        </div>
      </div>
    </section>
  );
}

// ============ FOOTER ============
function Footer() {
  return (
    <footer className="footer">
      <div className="container footer__inner">
        <div className="footer__brand">
          <img src="assets/logo-primary.png" alt="Ages Productions" className="footer__logo"/>
          <p className="footer__tag">Field-to-post media workflow management for high-volume Reality TV productions.</p>
        </div>
        <div className="footer__cols">
          <div>
            <h6>SERVICES</h6>
            <a href="#" onClick={(e) => { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); }}>Media Workflow</a>
            <a href="Ages Productions Self-Shoot.html">Self-Shoot Systems</a>
            <a href="Ages Productions Media Workflow.html#remote-cloud">Remote Delivery</a>
          </div>
          <div>
            <h6>COMPANY</h6>
            <a href="Ages Productions About.html">About</a>
            <a href="Ages Productions Use Cases.html">Use Cases</a>
            <a href="Ages Productions Contact.html">Contact</a>
          </div>
          <div>
            <h6>CONTACT</h6>
            <a href="Ages Productions Contact.html">Build a Media Plan</a>
            <span className="footer__loc">Miami · Worldwide</span>
          </div>
        </div>
      </div>
      <div className="footer__bar">
        <span>© 2026 Ages Productions. All rights reserved.</span>
        <span>v1.0 · Field → Post</span>
      </div>
    </footer>
  );
}

// ============ APP ============
function MWApp() {
  const [t, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 40);
    window.addEventListener('scroll', onScroll);
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  return (
    <div className="app">
      <Nav scrolled={scrolled}/>
      <Hero/>
      {t.showCounter && <StatTicker/>}
      <Problem/>
      <Capabilities/>
      <FolderTree/>
      <RemoteCloud mapStyle={t.mapStyle}/>
      <FinalCTA/>
      <Footer/>

      <window.TweaksPanel title="Tweaks">
        <window.TweakSection title="Hero">
          <window.TweakRadio
            label="Style"
            value={t.heroStyle}
            options={[
              { value: 'diagram', label: 'Diagram' },
              { value: 'minimal', label: 'Minimal' },
            ]}
            onChange={v => setTweak('heroStyle', v)}
          />
        </window.TweakSection>
        <window.TweakSection title="Sections">
          <window.TweakToggle
            label="Stat counter"
            value={t.showCounter}
            onChange={v => setTweak('showCounter', v)}
          />
        </window.TweakSection>
      </window.TweaksPanel>
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<MWApp/>);
