// App — editorial fractional directory. Landing (/) gates entry; /directory is the unlocked page.
const { useState, useMemo, useEffect } = React;

const DIRECTORY_PATH = '/directory.html';
const HOME_PATH = '/';

const isDirectoryRoute = () => {
  const p = (window.location.pathname || '').toLowerCase();
  return p === '/directory' || p === '/directory.html' || p.endsWith('/directory') || p.endsWith('/directory.html');
};

/* -------------------- TICKER -------------------- */
function Ticker() {
  const items = [
    { c: 'green',  t: '136 OPERATORS · 92 AVAILABLE NOW' },
    { c: 'purple', t: 'CPO · CTO · CMO · CFO · GC · COO · REVOPS' },
    { c: 'orange', t: 'UPDATED 11 MIN AGO' },
    { c: 'green',  t: '48H AVG. FIRST INTRO' },
    { c: 'purple', t: 'ACCEPTANCE RATE — 12.4%' },
    { c: 'orange', t: 'FOUNDER REFERENCES REQUIRED — 3+' },
    { c: 'green',  t: 'NO GHOST LISTINGS · NO RECRUITERS' },
    { c: 'purple', t: 'RATES $195 – $400 / HR' },
  ];
  const stream = [...items, ...items, ...items];
  return (
    <div className="ticker">
      <div className="ticker-track">
        {stream.map((it, i) => (
          <span key={i}><span className={`dot ${it.c}`} />{it.t}</span>
        ))}
      </div>
    </div>
  );
}

/* -------------------- NAV -------------------- */
function Nav({ links, ctaHref = '#apply' }) {
  return (
    <nav className="nav">
      <div className="nav-inner">
        <a href={HOME_PATH} className="brand-mark" style={{textDecoration:'none', color:'inherit'}}>
          <div className="brand-logo">F</div>
          <div className="brand">
            <span className="brand-eyebrow">DARING · VENTURES · 2026</span>
            <span className="brand-name">Fractional Directory</span>
          </div>
        </a>
        <div className="nav-links">
          {links.map(l => (
            <a key={l.href} href={l.href}>{l.label}</a>
          ))}
        </div>
        <div className="nav-right">
          <div className="nav-meta">
            <div>VOL.&nbsp;III · ISSUE&nbsp;04</div>
            <div>est.&nbsp;MMXXIV</div>
          </div>
          <a href={ctaHref} className="nav-cta">Apply to be listed
            <svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M3 8h10m0 0L9 4m4 4l-4 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>
          </a>
        </div>
      </div>
    </nav>
  );
}

/* -------------------- HERO -------------------- */
function Hero({ onScrollToDirectory, counts }) {
  const roleOrder = ['Product', 'Engineering', 'Marketing', 'Finance', 'Legal', 'Operations', 'Sales'];
  return (
    <section className="hero">
      <div className="hero-grid" />
      <div className="collage brain" />
      <div className="collage hands" />
      <div className="hero-inner">
        <div className="hero-left">
          <div className="hero-meta-row">
            <span className="pill"><span className="dot" />Live — 92 available this week</span>
            <span>A curated index, maintained by hand</span>
            <span>№ 00136</span>
          </div>
          <h1 className="hero-title">
            <span className="line">The fractionals</span>
            <span className="line"><span className="it">founders</span> <span className="bold">actually</span></span>
            <span className="line"><span className="hero-tape">recommend</span><span className="it" style={{color:'rgba(253,252,230,0.55)'}}>.</span></span>
          </h1>

          <div className="hero-sub-row">
            <div className="hero-kicker">
              A directory of
              <span className="bignum">vetted<br/>operators</span>
              for early-stage<br/>founders.
            </div>
            <p className="hero-sub">
              No recruiter lists, no LinkedIn scraping, no ghost jobs. Everyone
              on this page was <span className="u">referenced by a founder who built something real</span>,
              interviewed by us, and shipped work we'd bet money on. We reject 87% of applicants.
            </p>
          </div>

          <div className="hero-ctas">
            <button className="btn btn-primary" onClick={onScrollToDirectory}>
              Enter the directory
              <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8h10m0 0L9 4m4 4l-4 4" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>
            </button>
            <a href="#apply" className="btn btn-ghost">
              I'm a fractional
              <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8h10m0 0L9 4m4 4l-4 4" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>
            </a>
          </div>
        </div>

        <div className="hero-right">
          <div className="index-card">
            <div className="index-card-head">
              <span>The Index · 2026</span>
              <span className="stamp">VETTED</span>
            </div>
            <h3>What you'll find inside, by role count.</h3>
            <ol className="index-list">
              {roleOrder.map((r, i) => (
                <li key={r}>
                  <span className="num">{String(i+1).padStart(2,'0')}</span>
                  <span className="role">{r === 'Operations' ? 'Ops / People' : r === 'Sales' ? 'Sales / RevOps' : r}</span>
                  <span className="count">×{counts[r] ?? 0}</span>
                </li>
              ))}
            </ol>
            <div className="index-card-foot">
              <span>Total ——— 136</span>
              <span className="corner">Free to read</span>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* -------------------- MARQUEE STRIP -------------------- */
function Strip() {
  const items = [
    "Saved us a full-time hire we weren't ready for",
    "Rewrote our landing page in 48 hours",
    "Finally — finance I don't have to translate",
    "Told me to kill the feature. He was right.",
    "Quietly made our Series A happen",
    "The best PM work I've seen at this stage",
    "Installed the whole function and left a playbook",
  ];
  const stream = [...items, ...items];
  return (
    <div className="strip">
      <div className="marquee">
        {stream.map((t, i) => (
          <span key={i}>“{t}” <span className="sep" style={{marginLeft:18}}>◆&nbsp;&nbsp;FOUNDER&nbsp;&nbsp;◆</span></span>
        ))}
      </div>
    </div>
  );
}

/* -------------------- DIRECTORY HEAD -------------------- */
function DirectoryHead({ filteredCount, active }) {
  return (
    <div className="directory-head">
      <h2>
        <span className="stroked">The</span> <em>Directory</em>
      </h2>
      <div className="meta">
        <div>Showing</div>
        <div className="big">{filteredCount} {active === 'All' ? 'operators' : `in ${active}`}</div>
        <div>Sorted by availability ↓</div>
      </div>
    </div>
  );
}

/* -------------------- FILTER BAR -------------------- */
function FilterBar({ active, setActive, query, setQuery, counts, onlyAvailable, setOnlyAvailable }) {
  return (
    <div className="filter-bar">
      <div className="filter-inner">
        <div className="search">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>
          <input placeholder="Search names, skills, companies…" value={query} onChange={e => setQuery(e.target.value)}/>
          {query && <button onClick={()=>setQuery('')} aria-label="clear" style={{color:'var(--ink-2)',fontSize:20,lineHeight:1,fontFamily:'serif'}}>×</button>}
        </div>
        <div className="chips">
          {window.ROLES.map(r => (
            <button key={r.key} className={`chip ${active === r.key ? 'active' : ''}`} onClick={() => setActive(r.key)}>
              {r.label}<span className="count">{counts[r.key] ?? 0}</span>
            </button>
          ))}
        </div>
        <div className="filter-extra">
          <button className="sort-toggle" onClick={() => setOnlyAvailable(v => !v)}>
            <span style={{width:8,height:8,borderRadius:'50%',background: onlyAvailable ? 'var(--green)' : 'transparent', border:'1px solid currentColor'}}/>
            Available only
          </button>
        </div>
      </div>
    </div>
  );
}

/* -------------------- CARD -------------------- */
function Card({ f, idx, onClick, isDark }) {
  return (
    <div className={`card ${f.feature ? 'feature' : ''}`} onClick={onClick}>
      <span className="card-num">№ {String(idx + 1).padStart(3, '0')}</span>
      {f.flag && (
        <div className={`card-flag ${f.flag === 'HOT' ? 'orange' : f.flag === 'TOP PICK' ? 'purple' : f.flag === 'SERIES A' ? 'yellow' : ''}`}>{f.flag}</div>
      )}
      <div className="card-top">
        <div className="avatar" style={{ background: `linear-gradient(135deg, ${f.accent}26, ${f.accent}55)`, color: f.accent }}>
          <span style={{ position: 'relative', zIndex: 1 }}>{f.initials}</span>
          <div className="halftone" />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div className="card-name">{f.name}</div>
          <div className="card-company">{f.company}</div>
        </div>
      </div>
      <p className="card-desc">{f.blurb}</p>
      <div className="card-tags">
        {f.tags.slice(0, 3).map(t => <span key={t} className="tag">{t}</span>)}
      </div>
      <div className="card-meta">
        <div className={`availability ${f.available ? '' : 'booked'}`}>
          <span className="pulse" />
          {f.available ? `Avail · ${f.slots} slot${f.slots !== 1 ? 's' : ''}` : 'Booked'}
        </div>
        <div className="rate">${f.rate}<span> /hr</span></div>
      </div>
      <button className="card-cta">
        View profile
        <span>→</span>
      </button>
    </div>
  );
}

/* -------------------- ROLE SECTION -------------------- */
function RoleSection({ role, idx, fractionals, onCardClick, globalIdx, dark }) {
  const roleMeta = window.ROLES.find(r => r.key === role);
  if (!fractionals.length) return null;
  const sectionLabels = {
    Product: { big: 'Prod', it: 'uct', stroked: 'Prod' },
    Engineering: { big: 'Engin', it: 'eering', stroked: 'Engin' },
    Marketing: { big: 'Mark', it: 'eting', stroked: 'Mark' },
    Finance: { big: 'Fin', it: 'ance', stroked: 'Fin' },
    Legal: { big: 'Le', it: 'gal', stroked: 'Le' },
    Operations: { big: 'Ops', it: ' · People', stroked: 'Ops' },
    Sales: { big: 'Sales', it: ' · RevOps', stroked: 'Sales' },
  };
  const label = sectionLabels[role] || { big: role, it: '', stroked: role };

  const needsFillers = Math.max(0, 3 - (fractionals.length % 3 || 3)) % 3;

  return (
    <section className={`role-section ${dark ? 'dark' : idx % 2 === 1 ? 'tinted' : ''}`} id={`role-${role.toLowerCase()}`}>
      <div className="role-inner">
        <div className="role-head">
          <div>
            <div className="role-eyebrow">
              <span>№ {String(idx + 1).padStart(2, '0')} of 07</span>
              <span className="num">{String(fractionals.length).padStart(2,'0')}</span>
              <span>listings</span>
            </div>
            <h3 className="role-title-big">
              <span className="stroked">{label.stroked}</span><em>{label.it.replace(label.stroked,'')}</em>
            </h3>
          </div>
          <div className="role-desc">
            <span className="lead">{role === 'Product' ? 'The ones who ask the uncomfortable questions.' :
              role === 'Engineering' ? "The architects who leave a blueprint, not a dependency." :
              role === 'Marketing' ? 'The ones who hire CMO and write like founders.' :
              role === 'Finance' ? 'Both sides of the term sheet.' :
              role === 'Legal' ? 'The pre-Series A hygiene investors grade you on.' :
              role === 'Operations' ? 'The plumbing. Invisible until it breaks.' :
              'From founder-led to a team that does it without you.'}</span>
            {roleMeta?.desc}
          </div>
        </div>

        <div className="cards-grid">
          {fractionals.map((f, i) => (
            <Card key={f.name} f={f} idx={globalIdx + i} onClick={() => onCardClick(f)} isDark={dark} />
          ))}
          {[...Array(needsFillers)].map((_, i) => (
            <div key={'f'+i} className="card-empty">
              <div style={{textAlign:'center', lineHeight: 1.8}}>
                <div style={{fontSize:24, fontFamily:'Fraunces, serif', fontStyle:'italic', color:'var(--ink-2)', textTransform:'none', letterSpacing:'-0.02em'}}>slot open</div>
                <div style={{marginTop:8}}>Apply →</div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* -------------------- PULL QUOTE -------------------- */
function PullQuote() {
  return (
    <section className="pullquote" id="manifesto">
      <div className="pullquote-inner">
        <span className="pullquote-mark">“</span>
        <p>
          We built this because the <span className="highlight">best fractionals</span> are
          hidden — trapped in group chats, referral DMs, and
          founders' <em>"I know a guy"</em> text threads.<br/>
          <span style={{color:'var(--ink-2)'}}>So we pulled the thread.</span>
        </p>
        <div className="pullquote-attr">Daring Ventures · Manifesto, v2</div>
      </div>
    </section>
  );
}

/* -------------------- GATE / SUBSCRIBE -------------------- */
function SubscribeGate() {
  const [email, setEmail] = useState('');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  const onSubmit = async (e) => {
    e.preventDefault();
    const trimmed = email.trim();
    if (!trimmed) return;
    setError(null);
    setBusy(true);
    try {
      const res = await fetch('/api/subscribe', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ email: trimmed }),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) {
        window.location.href = DIRECTORY_PATH;
        return;
      }
      setError(
        data.error ||
          (res.status === 503 ? 'Signup is not available yet.' : 'Something went wrong. Try again.'),
      );
      setBusy(false);
    } catch (_) {
      setError('Network error. Try again.');
      setBusy(false);
    }
  };

  return (
    <section className="gate" id="subscribe">
      <div className="gate-inner">
        <div>
          <div className="gate-eyebrow">№ 02 — Access</div>
          <h2 className="gate-title">
            <span className="stroked">Free</span> <em>to read.</em><br/>
            Email to <em>unlock</em>.
          </h2>
          <p className="gate-note">
            You&apos;re seeing a preview. Drop your email to unlock the full 136,
            hourly rates, direct intros, and a monthly founder-fractional letter from Daring Ventures. No spam. No password.
          </p>
          <form className="gate-form" onSubmit={onSubmit}>
            <input
              type="email"
              required
              placeholder="you@startup.com"
              value={email}
              onChange={(e) => { setEmail(e.target.value); if (error) setError(null); }}
              disabled={busy}
            />
            <button type="submit" disabled={busy}>
              {busy ? '…' : 'Get access →'}
            </button>
          </form>
          {error && (
            <p className="gate-error" role="alert">{error}</p>
          )}
          <div className="gate-subnote">Already a subscriber? Use the same email. We&apos;ll recognize you.</div>
        </div>
        <div className="gate-right">
          <div className="ripped-note">
            Hire <span className="hl">someone good</span><br/>
            <span className="circle-word">before</span> they&rsquo;re the person<br/>
            who should&rsquo;ve been hired <span className="u-wav">six months ago</span>.
          </div>
          <div className="stamp-card">
            <div><span className="k">vetted_by:</span> <span className="v">founders</span></div>
            <div><span className="k">references:</span> <span className="v">≥ 3</span></div>
            <div><span className="k">ghost_jobs:</span> <span className="v">0</span></div>
            <div className="divider" />
            <div><span className="k">rate_card:</span> <span className="v">transparent</span></div>
            <div><span className="k">intro_time:</span> <span className="v">&lt; 48h</span></div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* -------------------- APPLY CTA -------------------- */
function ApplyCTA() {
  return (
    <section className="apply" id="apply">
      <div className="apply-grid" />
      <div className="apply-inner">
        <div className="apply-top">
          <h2 className="apply-title">
            <span className="stroked">Are&nbsp;you</span><br/>
            <em>actually</em> good?
          </h2>
          <div className="apply-right">
            <span className="lead">Then we want you on the list.</span>
            We accept ~12% of applicants. We'll ask for three founder references,
            a case study, and what you'd charge a friend. The list stays high-signal
            so founders keep coming back.
          </div>
        </div>
        <div className="apply-bar">
          <div className="apply-stat">
            <div className="big"><em>12.4%</em></div>
            <div className="lbl">Acceptance rate</div>
          </div>
          <div className="apply-stat">
            <div className="big">3<em>+</em></div>
            <div className="lbl">Founder references required</div>
          </div>
          <div className="apply-stat">
            <div className="big">0<em>%</em></div>
            <div className="lbl">Commission taken</div>
          </div>
          <div className="apply-ctas">
            <a href="#" className="btn btn-purple">Apply
              <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8h10m0 0L9 4m4 4l-4 4" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>
            </a>
            <a href="#" className="btn btn-ghost">Read the bar</a>
          </div>
        </div>
      </div>
    </section>
  );
}

/* -------------------- DRAWER -------------------- */
function Drawer({ f, onClose }) {
  useEffect(() => {
    const handler = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [onClose]);
  const open = !!f;
  return (
    <>
      <div className={`drawer-overlay ${open ? 'open' : ''}`} onClick={onClose} />
      <aside className={`drawer ${open ? 'open' : ''}`} role="dialog" aria-hidden={!open}>
        {f && <>
          <div className="drawer-head">
            <div className="mono" style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--ink-2)' }}>
              Profile · {f.role}
            </div>
            <button className="drawer-close" onClick={onClose} aria-label="Close">
              <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
            </button>
          </div>
          <div className="drawer-body">
            <div className="drawer-hero">
              <div className="avatar" style={{ background: `linear-gradient(135deg, ${f.accent}33, ${f.accent}66)`, color: f.accent, borderColor: f.accent }}>
                <span style={{ position: 'relative', zIndex: 1 }}>{f.initials}</span>
                <div className="halftone" />
              </div>
              <div>
                <div className="mono" style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--ink-2)' }}>
                  {f.company}
                </div>
                <h2>{f.name}</h2>
                <div className="meta">
                  <span>{f.role}</span>
                  <span className="rate-big">${f.rate}/hr</span>
                  <span>{f.hours}</span>
                </div>
              </div>
            </div>

            <div className={`availability ${f.available ? '' : 'booked'}`} style={{ padding: '10px 14px', background: 'var(--cream-2)', display: 'inline-flex' }}>
              <span className="pulse" />
              {f.available ? `Available now · ${f.slots} slot${f.slots !== 1 ? 's' : ''}` : 'Fully booked through Q2'}
            </div>

            <div className="drawer-section">
              <h4>// About</h4>
              <p>{f.bio}</p>
            </div>

            <div className="drawer-section">
              <h4>// Specializes in</h4>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 12 }}>
                {f.tags.map(t => <span key={t} className="tag" style={{ fontSize: 12, padding: '5px 10px' }}>{t}</span>)}
              </div>
            </div>

            <div className="drawer-section">
              <h4>// By the numbers</h4>
              <div className="drawer-stats">
                <div className="drawer-stat"><div className="v">{f.years}<span style={{fontSize:18}}>y</span></div><div className="l">Operating</div></div>
                <div className="drawer-stat"><div className="v">{f.engagements}</div><div className="l">Engagements</div></div>
                <div className="drawer-stat"><div className="v" style={{fontSize:22}}>{f.hours}</div><div className="l">Capacity</div></div>
              </div>
            </div>

            <div className="drawer-section">
              <h4>// Founder-recommended by</h4>
              <p style={{ fontStyle: 'italic' }}>
                "Quietly one of the best hires we made before we knew we could make hires. Changed the trajectory of the team."
                <br/><span style={{ fontStyle: 'normal', fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--ink-2)', letterSpacing: '0.06em', textTransform: 'uppercase', display:'inline-block', marginTop: 8 }}>— anonymized founder, seed-stage AI co.</span>
              </p>
            </div>
          </div>
          <div className="drawer-footer">
            <button className="btn btn-ghost" style={{ border: '1px solid var(--ink)', color: 'var(--ink)' }}>Save</button>
            <button className="btn btn-purple">Request intro
              <svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M3 8h10m0 0L9 4m4 4l-4 4" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>
            </button>
          </div>
        </>}
      </aside>
    </>
  );
}

/* -------------------- TWEAKS -------------------- */
function TweaksPanel({ settings, setSettings }) {
  const [open, setOpen] = useState(false);
  useEffect(() => {
    const handler = (e) => {
      if (e.data?.type === '__activate_edit_mode') setOpen(true);
      if (e.data?.type === '__deactivate_edit_mode') setOpen(false);
    };
    window.addEventListener('message', handler);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', handler);
  }, []);

  const update = (key, val) => {
    const next = { ...settings, [key]: val };
    setSettings(next);
    window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [key]: val } }, '*');
  };

  return (
    <div id="tweaks-panel" className={open ? 'open' : ''}>
      <h5>Tweaks</h5>
      <label>Accent
        <input type="color" value={settings.accent} onChange={e => update('accent', e.target.value)} />
      </label>
      <label>Highlight
        <input type="color" value={settings.highlight} onChange={e => update('highlight', e.target.value)} />
      </label>
      <label>Hero headline
        <select value={settings.heroStyle} onChange={e => update('heroStyle', e.target.value)}>
          <option value="editorial">Editorial</option>
          <option value="all-caps">ALL CAPS</option>
          <option value="quiet">Quiet</option>
        </select>
      </label>
      <label>Card hover
        <select value={settings.cardHover} onChange={e => update('cardHover', e.target.value)}>
          <option value="invert">Invert</option>
          <option value="lift">Lift</option>
          <option value="none">None</option>
        </select>
      </label>
    </div>
  );
}

/* -------------------- FOOTER -------------------- */
function Footer({ variant = 'landing' }) {
  const browseLinks = variant === 'directory'
    ? [
        { href: '#role-product', label: 'Product' },
        { href: '#role-engineering', label: 'Engineering' },
        { href: '#role-marketing', label: 'Marketing' },
        { href: '#role-finance', label: 'Finance' },
        { href: '#role-sales', label: 'Sales / RevOps' },
      ]
    : [
        { href: HOME_PATH + '#manifesto', label: 'Manifesto' },
        { href: HOME_PATH + '#subscribe', label: 'Get access' },
      ];
  return (
    <footer>
      <div className="footer-inner">
        <div className="footer-brand">
          <h3><em>Fractional</em><br/>Directory</h3>
          <p>A small, opinionated index of senior operators — hand-maintained by Daring Ventures for founders worth their time.</p>
        </div>
        <div className="footer-col">
          <h5>Browse</h5>
          {browseLinks.map(l => <a key={l.href} href={l.href}>{l.label}</a>)}
        </div>
        <div className="footer-col">
          <h5>Directory</h5>
          {variant === 'directory' ? <a href="#apply">Apply to be listed</a> : <a href={DIRECTORY_PATH + '#apply'}>Apply to be listed</a>}
          {variant === 'directory' ? <a href={HOME_PATH + '#subscribe'}>Subscribe</a> : <a href="#subscribe">Subscribe</a>}
          {variant === 'directory' ? <a href={HOME_PATH + '#manifesto'}>Manifesto</a> : <a href="#manifesto">Manifesto</a>}
          <a href="#">FAQ</a>
        </div>
        <div className="footer-col">
          <h5>Daring Ventures</h5>
          <a href="#">Portfolio</a>
          <a href="#">Writing</a>
          <a href="#">Contact</a>
          <a href="#">RSS</a>
        </div>
      </div>
      <div className="footer-bottom">
        <div>© 2026 Daring Ventures · Vol. III · Issue 04</div>
        <div style={{display:'flex', gap: 20}}>
          <a href="#">Privacy</a>
          <a href="#">Terms</a>
          <a href="#">Colophon</a>
        </div>
      </div>
    </footer>
  );
}

/* -------------------- THEME (shared) -------------------- */
function useTheme() {
  const [settings, setSettings] = useState(/*EDITMODE-BEGIN*/{
    "accent": "#8F17FE",
    "highlight": "#FFD84D",
    "heroStyle": "editorial",
    "cardHover": "invert"
  }/*EDITMODE-END*/);

  useEffect(() => {
    document.documentElement.style.setProperty('--purple', settings.accent);
    document.documentElement.style.setProperty('--yellow', settings.highlight);
    if (settings.heroStyle === 'all-caps') document.body.classList.add('hero-caps');
    else document.body.classList.remove('hero-caps');
    if (settings.cardHover === 'lift') document.body.classList.add('hover-lift');
    else document.body.classList.remove('hover-lift');
    if (settings.cardHover === 'none') document.body.classList.add('hover-none');
    else document.body.classList.remove('hover-none');
  }, [settings]);

  return [settings, setSettings];
}

/* -------------------- LANDING (gated entry) -------------------- */
function Landing() {
  const [settings, setSettings] = useTheme();

  const counts = useMemo(() => {
    const c = { All: window.FRACTIONALS.length };
    window.FRACTIONALS.forEach(f => { c[f.role] = (c[f.role] || 0) + 1; });
    return c;
  }, []);

  const scrollToSubscribe = () => {
    document.getElementById('subscribe')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <>
      <Ticker/>
      <Nav
        links={[
          { href: '#manifesto', label: 'Manifesto' },
          { href: '#subscribe', label: 'Get access' },
        ]}
      />
      <Hero onScrollToDirectory={scrollToSubscribe} counts={counts}/>
      <PullQuote/>
      <SubscribeGate/>
      <Footer variant="landing"/>
      <TweaksPanel settings={settings} setSettings={setSettings}/>
    </>
  );
}

/* -------------------- DIRECTORY (unlocked) -------------------- */
function Directory() {
  const [settings, setSettings] = useTheme();
  const [active, setActive] = useState('All');
  const [query, setQuery] = useState('');
  const [onlyAvailable, setOnlyAvailable] = useState(false);
  const [selected, setSelected] = useState(null);
  const [authState, setAuthState] = useState('checking'); // 'checking' | 'ok' | 'denied'

  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const res = await fetch('/api/session', { credentials: 'include' });
        const data = await res.json().catch(() => ({}));
        if (cancelled) return;
        if (data && data.unlocked) {
          setAuthState('ok');
        } else {
          setAuthState('denied');
          window.location.replace(HOME_PATH);
        }
      } catch (_) {
        if (cancelled) return;
        setAuthState('denied');
        window.location.replace(HOME_PATH);
      }
    })();
    return () => { cancelled = true; };
  }, []);

  const filtered = useMemo(() => {
    return window.FRACTIONALS.filter(f => {
      const matchRole = active === 'All' || f.role === active;
      const q = query.toLowerCase().trim();
      const matchQ = !q || f.name.toLowerCase().includes(q) || f.company.toLowerCase().includes(q) ||
        f.tags.some(t => t.toLowerCase().includes(q)) || f.blurb.toLowerCase().includes(q);
      const matchAvail = !onlyAvailable || f.available;
      return matchRole && matchQ && matchAvail;
    });
  }, [active, query, onlyAvailable]);

  const counts = useMemo(() => {
    const c = { All: window.FRACTIONALS.length };
    window.FRACTIONALS.forEach(f => { c[f.role] = (c[f.role] || 0) + 1; });
    return c;
  }, []);

  const rolesToShow = active === 'All'
    ? window.ROLES.filter(r => r.key !== 'All').map(r => r.key)
    : [active];

  if (authState !== 'ok') {
    return (
      <div style={{
        minHeight: '100vh',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontFamily: 'JetBrains Mono, monospace',
        fontSize: 12,
        letterSpacing: '0.14em',
        textTransform: 'uppercase',
        color: 'var(--ink-2)',
        background: 'var(--cream)',
      }}>
        {authState === 'denied' ? 'Redirecting…' : 'Verifying access…'}
      </div>
    );
  }

  let running = 0;

  return (
    <>
      <Ticker/>
      <Nav
        links={[
          { href: '#directory', label: 'Directory' },
          { href: HOME_PATH + '#manifesto', label: 'Manifesto' },
          { href: '#apply', label: 'For Fractionals' },
        ]}
      />
      <div id="directory" style={{paddingTop: 24}}>
        <DirectoryHead filteredCount={filtered.length} active={active}/>
        <FilterBar
          active={active}
          setActive={setActive}
          query={query}
          setQuery={setQuery}
          counts={counts}
          onlyAvailable={onlyAvailable}
          setOnlyAvailable={setOnlyAvailable}
        />
        {filtered.length === 0 ? (
          <section className="role-section">
            <div className="role-inner">
              <div style={{padding:'80px 0',textAlign:'center',fontFamily:'Fraunces,serif',fontStyle:'italic',fontSize:32,color:'var(--ink-2)'}}>
                No matches. Try another role.
              </div>
            </div>
          </section>
        ) : (
          rolesToShow.map((role, i) => {
            const items = filtered.filter(f => f.role === role);
            const el = (
              <RoleSection
                key={role}
                role={role}
                idx={i}
                fractionals={items}
                onCardClick={setSelected}
                globalIdx={running}
                dark={i === 1}
              />
            );
            running += items.length;
            return el;
          })
        )}
      </div>
      <ApplyCTA/>
      <Footer variant="directory"/>
      <Drawer f={selected} onClose={() => setSelected(null)}/>
      <TweaksPanel settings={settings} setSettings={setSettings}/>
    </>
  );
}

/* -------------------- ROOT (path-based router) -------------------- */
function Root() {
  return isDirectoryRoute() ? <Directory/> : <Landing/>;
}

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