const { useState, useEffect, useRef } = React;

const BRAND = 'The Blobs';

function Landing({ onLaunch, tweaks }) {
  return (
    <div className="landing" style={{
      '--accent': tweaks.accent,
      '--bg': tweaks.bg,
      '--ink': tweaks.ink,
      '--font-display': tweaks.fontDisplay,
      '--font-ui': tweaks.fontUi,
    }}>
      <Nav onLaunch={onLaunch} />
      <Hero onLaunch={onLaunch} tweaks={tweaks} />
      <HowItWorks tweaks={tweaks} />
      <DetectionModes />
      <EffectChain />
      <Features tweaks={tweaks} />
      <CtaBand onLaunch={onLaunch} />
      <Footer />
    </div>
  );
}

function BrandMark({ size = 20 }) {
  return (
    <svg viewBox="0 0 24 24" width={size} height={size}>
      <rect x="2" y="2" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.5"/>
      <line x1="2" y1="12" x2="22" y2="12" stroke="currentColor" strokeWidth="0.75"/>
      <line x1="12" y1="2" x2="12" y2="22" stroke="currentColor" strokeWidth="0.75"/>
    </svg>
  );
}

function Nav({ onLaunch }) {
  return (
    <header className="nav">
      <div className="nav-inner">
        <div className="brand">
          <span className="brand-mark" aria-hidden><BrandMark /></span>
          <span className="brand-name">{BRAND}</span>
        </div>
        <nav className="nav-links">
          <a href="#how">How it works</a>
          <a href="#modes">Detection</a>
          <a href="#effects">Effects</a>
          <a href="#features">Layers</a>
          <a href="https://github.com" target="_blank" rel="noreferrer">GitHub</a>
        </nav>
        <button className="btn btn-primary" onClick={onLaunch}>Launch app</button>
      </div>
    </header>
  );
}

const BG_PRESETS = [
  { id: 'synthetic', label: 'Synthetic', url: null },
  { id: 'street',    label: 'Street',    url: 'https://picsum.photos/id/1011/1200/720' },
  { id: 'dance',     label: 'Dance',     url: 'https://picsum.photos/id/1025/1200/720' },
  { id: 'city',      label: 'City',      url: 'https://picsum.photos/id/1043/1200/720' },
  { id: 'forest',    label: 'Forest',    url: 'https://picsum.photos/id/1018/1200/720' },
];

function Hero({ onLaunch, tweaks }) {
  const [bgPreset, setBgPreset] = useState('synthetic');
  const [customUrl, setCustomUrl] = useState(null);
  const [bgImage, setBgImage] = useState(null);
  const [blobCount, setBlobCount] = useState(14);
  const [persistence, setPersistence] = useState(0.97);

  // Resolve the current URL: custom upload wins, otherwise the preset
  const currentUrl = customUrl || BG_PRESETS.find((p) => p.id === bgPreset)?.url || null;

  // Load the image whenever URL changes
  useEffect(() => {
    if (!currentUrl) { setBgImage(null); return; }
    const img = new Image();
    // crossOrigin so drawImage works without tainting
    img.crossOrigin = 'anonymous';
    let cancelled = false;
    img.onload = () => { if (!cancelled) setBgImage(img); };
    img.onerror = () => {
      // Fall back to non-crossOrigin on error (some hosts don't send CORS headers; tainted canvas is fine for display)
      if (cancelled) return;
      const retry = new Image();
      retry.onload = () => { if (!cancelled) setBgImage(retry); };
      retry.src = currentUrl;
    };
    img.src = currentUrl;
    return () => { cancelled = true; };
  }, [currentUrl]);

  const handleUpload = (e) => {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    const url = URL.createObjectURL(f);
    setCustomUrl(url);
    setBgPreset('__custom__');
  };

  return (
    <section className="hero">
      <div className="hero-copy">
        <div className="eyebrow">
          <span className="eyebrow-dot" /> Real-time motion &middot; TouchDesigner in your browser
        </div>
        <h1 className="display">
          Turn any video<br/>
          into a living<br/>
          <em>instrument.</em>
        </h1>
        <p className="lede">
          16 ways to find motion. 50+ effects to paint it. All running in real time.
          Feedback loops, pixel sorts, fluid sim, ASCII, VHS, halftone, kaleidoscope.
          No plugins. No code.
        </p>
        <div className="hero-cta">
          <button className="btn btn-primary btn-lg" onClick={onLaunch}>
            Launch app
            <ArrowRight />
          </button>
          <span className="hero-meta">Runs in your browser &middot; free</span>
        </div>
      </div>
      <div className="hero-stage-wrap">
        <div className="hero-stage">
          <div className="hero-stage-frame">
            <Demo
              width={1200}
              height={720}
              blobCount={blobCount}
              accent={tweaks.demoAccent}
              backdrop="video"
              backgroundImage={bgImage}
              layers={{
                wireframes: { enabled: true, style: 'cross' },
                filled: { enabled: true, opacity: 0.08 },
                lines: { enabled: true, curved: false },
                labels: { enabled: true, displayMode: 'both' },
                dots: { enabled: true, color: '#ff3b30', radius: 2.5, offsetX: -10 },
                trails: { enabled: true, persistence, feedbackScale: 1.003, feedbackBlur: 0.5 },
                grid: { enabled: false },
              }}
            />
            <div className="hero-corner tl">REC &middot; 01</div>
            <div className="hero-corner tr">24 &middot; 1280x720</div>
            <div className="hero-corner bl">THE BLOBS &middot; V1.0</div>
            <div className="hero-corner br">60 fps</div>
          </div>
        </div>
        <div className="hero-panel">
          <div className="hp-row">
            <span className="hp-label">Source</span>
            <div className="hp-presets">
              {BG_PRESETS.map((p) => (
                <button
                  key={p.id}
                  className={`hp-chip ${bgPreset === p.id && !customUrl ? 'on' : ''}`}
                  onClick={() => { setCustomUrl(null); setBgPreset(p.id); }}
                >{p.label}</button>
              ))}
              {customUrl && (
                <button className="hp-chip on" onClick={() => setCustomUrl(null)} title="Your uploaded image · click to remove">Custom</button>
              )}
              <label className="hp-chip hp-upload">
                Upload
                <input type="file" accept="image/*" onChange={handleUpload} hidden />
              </label>
            </div>
          </div>
          <div className="hp-row hp-sliders">
            <label className="hp-slider">
              <span className="hp-label">Blobs</span>
              <input
                type="range" min="4" max="24" step="1"
                value={blobCount}
                onChange={(e) => setBlobCount(parseInt(e.target.value, 10))}
              />
              <span className="hp-val">{blobCount}</span>
            </label>
            <label className="hp-slider">
              <span className="hp-label">Trails</span>
              <input
                type="range" min="0.85" max="0.99" step="0.005"
                value={persistence}
                onChange={(e) => setPersistence(parseFloat(e.target.value))}
              />
              <span className="hp-val">{persistence.toFixed(2)}</span>
            </label>
          </div>
        </div>
      </div>
    </section>
  );
}

function HowItWorks({ tweaks }) {
  const [step, setStep] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setStep((s) => (s + 1) % 3), 2800);
    return () => clearInterval(id);
  }, []);
  const steps = [
    {
      title: 'Watch',
      body: 'Compare each frame of your video to earlier ones. Pre-blur, threshold, invert &mdash; tune how sensitive the eye is.',
    },
    {
      title: 'Detect',
      body: 'Pick one of 16 ways to find motion &mdash; classic difference, edge contour, heat signature, particle swarm, ghost layer, ASCII track, fake depth map&hellip;',
    },
    {
      title: 'Paint',
      body: 'Stack 50+ effects &mdash; feedback, glitch, dither, stylize. Arrange the chain like a modular synth.',
    },
  ];
  return (
    <section id="how" className="how">
      <div className="section-head">
        <div className="section-kicker">01 &nbsp;/&nbsp; How it works</div>
        <h2 className="section-title">Three steps.<br/>No math required.</h2>
      </div>
      <div className="how-grid">
        <div className="how-stage">
          <HowStage step={step} tweaks={tweaks} />
        </div>
        <ol className="how-steps">
          {steps.map((s, i) => (
            <li
              key={i}
              className={`how-step ${i === step ? 'active' : ''}`}
              onMouseEnter={() => setStep(i)}
            >
              <div className="how-step-num">{String(i + 1).padStart(2, '0')}</div>
              <div className="how-step-body">
                <h3>{s.title}</h3>
                <p dangerouslySetInnerHTML={{ __html: s.body }} />
              </div>
            </li>
          ))}
        </ol>
      </div>
    </section>
  );
}

function HowStage({ step, tweaks }) {
  return (
    <div className="how-stage-inner">
      <div className={`how-frame ${step >= 0 ? 'on' : ''}`}>
        <div className="how-frame-label">frame t</div>
        <div className="how-frame-dot" style={{ left: '30%', top: '40%' }} />
      </div>
      <div className={`how-frame ${step >= 0 ? 'on' : ''}`}>
        <div className="how-frame-label">frame t&minus;1</div>
        <div className="how-frame-dot" style={{ left: '55%', top: '55%' }} />
      </div>
      <div className={`how-diff ${step >= 1 ? 'on' : ''}`}>
        <div className="how-frame-label">detect</div>
        <div className="how-diff-patch" />
      </div>
      <div className={`how-output ${step >= 2 ? 'on' : ''}`}>
        <div className="how-frame-label">paint</div>
        <div className="how-output-box">
          <div className="how-output-cross" />
          <div className="how-output-cross vert" />
          <div className="how-output-label">b42  0.43, 0.58</div>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Detection modes — 16 ways to find motion
// ============================================================

function DetectionModes() {
  const modes = [
    { name: 'Standard Difference', desc: 'Classic frame diff. The honest default.', glyph: 'diff' },
    { name: 'Edge Contour', desc: 'Sobel pre-filter. Thin, drawn outlines.', glyph: 'contour' },
    { name: 'Optical Dense', desc: 'Three-frame weighted blend. Smooth, merged blobs.', glyph: 'dense' },
    { name: 'Heat Signature', desc: 'Temporal heat map. Motion intensity as color.', glyph: 'heat' },
    { name: 'Particle Swarm', desc: 'Random sampling. Organic particle cloud.', glyph: 'swarm' },
    { name: 'Voronoi Zones', desc: 'Blob-seeded tessellation. Cellular structure.', glyph: 'voronoi' },
    { name: 'Ghost Layer', desc: 'Persistent fades of past positions.', glyph: 'ghost' },
    { name: 'Time Echo', desc: 'Stacked echoes with hue shift. Muybridge mode.', glyph: 'echo' },
    { name: 'Motion Accumulate', desc: 'Never clears. Long-exposure density map.', glyph: 'accumulate' },
    { name: 'Scanline Detect', desc: 'Interlaced scanline mask. Retro CRT.', glyph: 'scanline' },
    { name: 'Dot Matrix', desc: 'Grid quantization. LED halftone look.', glyph: 'dotmatrix' },
    { name: 'ASCII Track', desc: 'Difference mapped to characters.', glyph: 'ascii' },
    { name: 'Blueprint Grid', desc: 'Grid-snapped coords with dimension tags.', glyph: 'blueprint' },
    { name: 'Frequency Split', desc: 'Dual-band detection, each in its own color.', glyph: 'freq' },
    { name: 'Fake Depth Map', desc: 'Vertical position + motion as pseudo-3D.', glyph: 'depth' },
    { name: 'Inverted Space', desc: 'Tracks stillness instead of motion.', glyph: 'invert' },
  ];
  return (
    <section id="modes" className="modes">
      <div className="section-head">
        <div className="section-kicker">02 &nbsp;/&nbsp; 16 ways to find motion</div>
        <h2 className="section-title">Pick a lens.</h2>
      </div>
      <div className="modes-grid">
        {modes.map((m, i) => (
          <article key={i} className="mode-card">
            <div className="mode-preview"><ModeGlyph kind={m.glyph} /></div>
            <div className="mode-body">
              <h3>{m.name}</h3>
              <p>{m.desc}</p>
            </div>
          </article>
        ))}
      </div>
    </section>
  );
}

function ModeGlyph({ kind }) {
  const stroke = 'rgba(255,255,255,0.85)';
  const soft = 'rgba(255,255,255,0.35)';
  switch (kind) {
    case 'diff':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <rect x="18" y="16" width="28" height="22" stroke={stroke} fill="none"/>
          <rect x="28" y="26" width="28" height="22" stroke={stroke} fill="none"/>
          <rect x="70" y="22" width="32" height="30" stroke={stroke} fill="none" strokeDasharray="2 3"/>
        </svg>
      );
    case 'contour':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <path d="M20 40 C 30 20, 50 20, 60 36 S 100 48, 104 30" stroke={stroke} fill="none" strokeDasharray="1 2"/>
          <path d="M20 48 C 32 32, 52 28, 62 44 S 100 56, 108 38" stroke={soft} fill="none" strokeDasharray="1 2"/>
        </svg>
      );
    case 'dense':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <ellipse cx="48" cy="36" rx="24" ry="16" fill="rgba(255,255,255,0.08)" stroke={stroke}/>
          <ellipse cx="72" cy="40" rx="20" ry="14" fill="rgba(255,255,255,0.12)" stroke={soft}/>
        </svg>
      );
    case 'heat':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <defs><radialGradient id="h1"><stop offset="0%" stopColor="#ffb366"/><stop offset="60%" stopColor="#ff3b30" stopOpacity="0.5"/><stop offset="100%" stopColor="#ff3b30" stopOpacity="0"/></radialGradient></defs>
          <circle cx="50" cy="36" r="28" fill="url(#h1)"/>
          <circle cx="80" cy="44" r="18" fill="url(#h1)" opacity="0.6"/>
        </svg>
      );
    case 'swarm':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          {Array.from({ length: 40 }).map((_, i) => (
            <circle key={i} cx={10 + ((i * 37) % 100)} cy={6 + ((i * 53) % 60)} r="1.2" fill={stroke}/>
          ))}
        </svg>
      );
    case 'voronoi':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <g stroke={stroke} fill="none">
            <polygon points="20,10 60,14 54,40 22,46"/>
            <polygon points="60,14 100,18 92,42 54,40"/>
            <polygon points="22,46 54,40 58,66 26,62"/>
            <polygon points="54,40 92,42 96,66 58,66"/>
          </g>
        </svg>
      );
    case 'ghost':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <rect x="26" y="28" width="22" height="18" stroke={stroke} fill="none" opacity="1"/>
          <rect x="46" y="32" width="22" height="18" stroke={stroke} fill="none" opacity="0.5"/>
          <rect x="66" y="36" width="22" height="18" stroke={stroke} fill="none" opacity="0.25"/>
          <rect x="86" y="40" width="22" height="18" stroke={stroke} fill="none" opacity="0.12"/>
        </svg>
      );
    case 'echo':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <circle cx="30" cy="36" r="10" stroke="#ff5a36" fill="none"/>
          <circle cx="50" cy="36" r="10" stroke="#ffd60a" fill="none" opacity="0.8"/>
          <circle cx="70" cy="36" r="10" stroke="#00d3a7" fill="none" opacity="0.7"/>
          <circle cx="90" cy="36" r="10" stroke="#3b82f6" fill="none" opacity="0.5"/>
        </svg>
      );
    case 'accumulate':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <path d="M14 56 Q 30 20, 56 46 T 104 28" stroke={stroke} fill="none" strokeWidth="1.5"/>
          <path d="M14 58 Q 32 24, 58 48 T 106 32" stroke={soft} fill="none"/>
          <path d="M14 60 Q 34 28, 60 50 T 108 36" stroke="rgba(255,255,255,0.18)" fill="none"/>
        </svg>
      );
    case 'scanline':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          {Array.from({ length: 14 }).map((_, i) => (
            <line key={i} x1="10" y1={6 + i * 4.5} x2="110" y2={6 + i * 4.5} stroke={i % 2 === 0 ? stroke : 'transparent'} strokeWidth="1"/>
          ))}
          <rect x="40" y="24" width="30" height="24" fill="rgba(255,255,255,0.12)" stroke={stroke}/>
        </svg>
      );
    case 'dotmatrix':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          {Array.from({ length: 6 }).flatMap((_, r) =>
            Array.from({ length: 12 }).map((_, c) => (
              <circle key={`${r}-${c}`} cx={10 + c * 9} cy={10 + r * 10} r="1.4" fill={(r + c) % 3 === 0 ? stroke : soft}/>
            ))
          )}
        </svg>
      );
    case 'ascii':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <text x="10" y="20" fontFamily="monospace" fontSize="9" fill={stroke} letterSpacing="1">.  . : ; i * % # @</text>
          <text x="10" y="36" fontFamily="monospace" fontSize="9" fill={stroke} letterSpacing="1">: ; i * % # @ @ # %</text>
          <text x="10" y="52" fontFamily="monospace" fontSize="9" fill={stroke} letterSpacing="1">i * % # @ # % * i ;</text>
          <text x="10" y="66" fontFamily="monospace" fontSize="9" fill={soft} letterSpacing="1">. : ; i * ; i : . .</text>
        </svg>
      );
    case 'blueprint':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <g stroke={soft}>
            {Array.from({ length: 10 }).map((_, i) => <line key={`v${i}`} x1={10 + i * 11} y1="6" x2={10 + i * 11} y2="66" strokeWidth="0.5"/>)}
            {Array.from({ length: 6 }).map((_, i) => <line key={`h${i}`} x1="10" y1={8 + i * 11} x2="110" y2={8 + i * 11} strokeWidth="0.5"/>)}
          </g>
          <rect x="44" y="22" width="44" height="28" stroke={stroke} fill="none"/>
          <text x="44" y="18" fontFamily="monospace" fontSize="7" fill={stroke}>44×28</text>
        </svg>
      );
    case 'freq':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <path d="M10 48 Q 25 28, 40 48 T 70 48 T 100 48" stroke="#ff5a36" fill="none"/>
          <path d="M10 50 q 6 -4, 12 0 t 12 0 t 12 0 t 12 0 t 12 0 t 12 0 t 12 0 t 12 0" stroke="#3b82f6" fill="none"/>
        </svg>
      );
    case 'depth':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <rect x="14" y="46" width="16" height="14" stroke={stroke} fill="none"/>
          <rect x="40" y="38" width="22" height="20" stroke={stroke} fill="none"/>
          <rect x="72" y="26" width="30" height="28" stroke={stroke} fill="none"/>
        </svg>
      );
    case 'invert':
      return (
        <svg viewBox="0 0 120 72" className="glyph">
          <rect x="4" y="4" width="112" height="64" fill={stroke}/>
          <rect x="32" y="20" width="22" height="20" fill="#0a0a0a"/>
          <rect x="64" y="28" width="28" height="22" fill="#0a0a0a"/>
        </svg>
      );
    default: return null;
  }
}

// ============================================================
// Effect chain — 52 effects in 5 categories
// ============================================================

function EffectChain() {
  const categories = [
    {
      name: 'Utility',
      effects: ['Optical Flow', 'Pseudo-Depth', 'Edge Detection'],
    },
    {
      name: 'Feedback & Time',
      effects: [
        'Enhanced Feedback', 'Slit-Scan', 'Time-Slice', 'TAA Jitter',
        'Particle Trails', 'Boid Flocking', 'Fluid Simulation',
        'Datamosh', 'Delta Feedback', 'Buffer Shuffle',
        'Temporal Bit-Crush', 'Edge Decay', 'Rhythmic Stutter', 'Droste Zoom',
      ],
    },
    {
      name: 'Color & Tone',
      effects: [
        'Color Threshold', 'Invert', 'Color Grade', 'Bit-Depth Crush',
        'Quantized Banding', 'Bayer Dithering', 'Solarize', 'Posterize', 'DuoTone',
      ],
    },
    {
      name: 'Distortion & Glitch',
      effects: [
        'Chromatic Aberration', 'UV Corruption', 'Displacement Sort',
        'Liquid Glass', 'Pixel Sort', 'Glitch Blocks', 'Channel Shift',
        'Channel Swap', 'Wave Distortion', 'Domain Warp', 'Displacement Map',
        'Kaleidoscope', 'Pixelate', 'Polar Pixelate', 'Melt', 'Wobble',
        'Shake', 'Bulge', 'Slices', 'Stretch', 'Blob Displacement',
      ],
    },
    {
      name: 'Stylize & Render',
      effects: [
        'HDR Bloom', 'Analog Film', 'SDF Glow', 'Digital Voxelization',
        'Photo-Mosaic', 'Iridescence', 'Halftone Neo-Print', 'ASCII Render',
        'Edge Particles', 'Point Dissolve', 'Voronoi Cells', 'CRT Monitor',
        'Dot Matrix', 'Soft Glitch', 'Hard Glitch', 'Light Streak',
        'Bad TV', 'VHS',
      ],
    },
  ];
  const total = categories.reduce((n, c) => n + c.effects.length, 0);
  return (
    <section id="effects" className="effects">
      <div className="section-head">
        <div className="section-kicker">03 &nbsp;/&nbsp; The chain</div>
        <h2 className="section-title">{total} effects.<br/>Stack them like modules.</h2>
      </div>
      <div className="effects-chain">
        {categories.map((cat, i) => (
          <div key={i} className="effect-col">
            <h4>{String(i + 1).padStart(2, '0')} &middot; {cat.name}</h4>
            <ul>
              {cat.effects.map((e) => <li key={e}>{e}</li>)}
            </ul>
          </div>
        ))}
      </div>
      <p className="effects-note">
        Route motion through any combination &mdash; ordered, live, every parameter modulable.
        Audio-reactive on kick / mid / high bands. Save chains as presets.
      </p>
    </section>
  );
}

// ============================================================
// Core layers — the output of blob tracking, under the chain
// ============================================================

function Features({ tweaks }) {
  const features = [
    {
      title: 'Wireframes',
      body: 'Cross, outline, or corner-bracket. Mark every patch of motion.',
      preview: <FeatureDemo layers={{ wireframes: { enabled: true, style: 'cross' } }} seed={3} />,
    },
    {
      title: 'Trails',
      body: 'Fading echoes with scale + blur feedback. Painterly sweeps.',
      preview: <FeatureDemo layers={{ wireframes: { enabled: true }, trails: { enabled: true, persistence: 0.95, feedbackScale: 1.01, feedbackBlur: 1 }, lines: { enabled: false }, labels: { enabled: false } }} seed={7} />,
    },
    {
      title: 'Connections',
      body: 'Straight, curved, or dotted lines between nearby blobs.',
      preview: <FeatureDemo layers={{ wireframes: { enabled: false }, labels: { enabled: false }, lines: { enabled: true, curved: true, maxPer: 4, maxDistance: 0.4 }, dots: { enabled: true, color: '#ffffff', radius: 2 } }} seed={9} />,
    },
    {
      title: 'Labels',
      body: 'ID, coordinates, or both. Monospace, pixel-sharp.',
      preview: <FeatureDemo layers={{ wireframes: { enabled: true, style: 'bracket' }, lines: { enabled: false }, labels: { enabled: true, displayMode: 'both', fontSize: 10 } }} seed={11} />,
    },
  ];
  return (
    <section id="features" className="features">
      <div className="section-head">
        <div className="section-kicker">04 &nbsp;/&nbsp; Core layers</div>
        <h2 className="section-title">Four layers<br/>under the chain.</h2>
      </div>
      <div className="feature-grid layers-4">
        {features.map((f, i) => (
          <article key={i} className="feature-card">
            <div className="feature-preview">{f.preview}</div>
            <div className="feature-body">
              <h3>{f.title}</h3>
              <p>{f.body}</p>
            </div>
          </article>
        ))}
      </div>
    </section>
  );
}

function FeatureDemo({ layers, seed }) {
  return (
    <div style={{ width: '100%', height: '100%' }}>
      <Demo
        width={400} height={240} blobCount={7}
        accent="#ffffff" backdrop="video" speed={0.9} seed={seed}
        layers={layers}
      />
    </div>
  );
}

function CtaBand({ onLaunch }) {
  return (
    <section className="cta-band">
      <div className="cta-inner">
        <h2 className="cta-title">Ready to route motion<br/>through 50+ effects?</h2>
        <button className="btn btn-primary btn-lg" onClick={onLaunch}>
          Launch app
          <ArrowRight />
        </button>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer className="footer">
      <div className="footer-inner">
        <div className="footer-left">
          <div className="brand">
            <span className="brand-mark" aria-hidden><BrandMark size={16} /></span>
            <span className="brand-name">{BRAND}</span>
          </div>
          <p className="footer-tag">Real-time motion, run through TouchDesigner-flavored effects.</p>
        </div>
        <div className="footer-right">
          <a href="https://github.com" target="_blank" rel="noreferrer">GitHub</a>
          <a href="#how">How it works</a>
          <a href="#modes">Detection</a>
          <a href="#effects">Effects</a>
          <span className="footer-cred">Made with TouchDesigner energy.</span>
        </div>
      </div>
    </footer>
  );
}

function ArrowRight() {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden>
      <path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

window.Landing = Landing;
