/* ============================================================
   Lectual — System A marketing/onboarding shared atoms
   Exports to window for cross-file (Babel) use.
   ============================================================ */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---------------- brand atoms ---------------- */
function Echo({ size = 22, light }) {
  return (
    <span className="echo" style={{ fontSize: size, color: light ? '#F4EEE2' : 'var(--ink)' }}>
      Lectua<span className="gl"><span className="sh" aria-hidden="true">l</span><span className="fg" style={{ color: 'var(--accent)' }}>l</span></span>
    </span>
  );
}
function AppMark({ s = 40 }) {
  return (
    <span className="appmark" style={{ width: s, height: s }}>
      <svg width={s * 0.58} height={s * 0.58} viewBox="0 0 32 32" aria-hidden="true">
        <path d="M10 7v18h8" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="square" />
        <path d="M16 7v18h8" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="square" opacity=".42" />
      </svg>
    </span>
  );
}

const bandColor = (v) => (v >= 70 ? 'var(--protected)' : v >= 45 ? 'var(--accent)' : 'var(--warning)');
const bandName = (v) => (v >= 85 ? 'Excellent' : v >= 70 ? 'Strong' : v >= 45 ? 'Needs work' : 'At risk');

function Gauge({ value, size = 132, stroke = 13, label = '/ 100', animate = true }) {
  const r = (size - stroke) / 2, C = 2 * Math.PI * r;
  // Rest at the final value so a throttled rAF (hidden tab / mid-transition mount)
  // never leaves it stuck at 0; if rAF runs, the first tick dips low and counts up.
  const [disp, setDisp] = useState(value);
  useEffect(() => {
    if (!animate) { setDisp(value); return; }
    let raf; const start = performance.now(), dur = 1050;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / dur), e = 1 - Math.pow(1 - p, 3);
      setDisp(Math.round(value * e));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [value, animate]);
  return (
    <div className="gauge" style={{ width: size, height: size }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--border-2)" strokeWidth={stroke} />
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={bandColor(value)} strokeWidth={stroke}
          strokeLinecap="round" strokeDasharray={C} strokeDashoffset={C * (1 - disp / 100)} style={{ transition: 'stroke .3s' }} />
      </svg>
      <div className="gv"><b style={{ fontSize: size * 0.3 }}>{disp}</b><span>{label}</span></div>
    </div>
  );
}

/* ---------------- icon set ---------------- */
const sv = (p, sw = 2) => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">{p}</svg>;
const Ico = {
  check:    sv(<><path d="M5 12l4 4 10-10" /></>),
  arrow:    sv(<><path d="M5 12h14M13 6l6 6-6 6" /></>),
  shield:   sv(<><path d="M12 3l8 3v6c0 4.5-3.2 7.5-8 9-4.8-1.5-8-4.5-8-9V6z" /><path d="M9 12l2 2 4-4" /></>),
  lock:     sv(<><rect x="4" y="11" width="16" height="9" rx="2" /><path d="M8 11V8a4 4 0 0 1 8 0v3" /></>),
  spark:    sv(<><path d="M12 3l1.7 4.5L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.5z" /></>),
  bolt:     sv(<><path d="M13 2L4 14h7l-1 8 9-12h-7z" /></>),
  search:   sv(<><circle cx="11" cy="11" r="7" /><path d="M21 21l-4-4" /></>),
  tag:      sv(<><path d="M3 11l8-8 9 9-8 8z" /><circle cx="8" cy="8" r="1.5" /></>),
  mail:     sv(<><rect x="3" y="5" width="18" height="14" rx="2" /><path d="M3 7l9 6 9-6" /></>),
  doc:      sv(<><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" /><path d="M14 3v6h6" /></>),
  building: sv(<><rect x="4" y="3" width="16" height="18" rx="1" /><path d="M9 7h.01M15 7h.01M9 11h.01M15 11h.01M9 15h6v6H9z" /></>),
  chart:    sv(<><path d="M4 20V10M10 20V4M16 20v-7M22 20H2" /></>),
  clock:    sv(<><circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" /></>),
  alert:    sv(<><path d="M12 3l9 16H3z" /><path d="M12 10v4M12 17v.01" /></>),
  plus:     sv(<><path d="M12 5v14M5 12h14" /></>),
  x:        sv(<><path d="M6 6l12 12M18 6L6 18" /></>),
  link:     sv(<><path d="M10 13a5 5 0 0 0 7 0l2-2a5 5 0 0 0-7-7l-1 1M14 11a5 5 0 0 0-7 0l-2 2a5 5 0 0 0 7 7l1-1" /></>),
  download: sv(<><path d="M12 3v12M7 11l5 4 5-4M5 21h14" /></>),
  users:    sv(<><circle cx="9" cy="8" r="3.4" /><path d="M3 20c0-3.3 2.7-5 6-5s6 1.7 6 5" /><path d="M16 5.5a3 3 0 0 1 0 6M21 20c0-2.6-1.6-4.2-4-4.8" /></>),
  cal:      sv(<><rect x="3" y="4" width="18" height="17" rx="2" /><path d="M3 9h18M8 2v4M16 2v4" /></>),
  palette:  sv(<><path d="M12 3a9 9 0 1 0 0 18c1 0 1.5-.8 1.5-1.6 0-.5-.3-.9-.5-1.3-.2-.4-.4-.7-.4-1.1 0-.8.7-1.5 1.5-1.5H16a5 5 0 0 0 5-5c0-4.4-4-7.5-9-7.5z" /><circle cx="7.5" cy="11" r="1.1" fill="currentColor" stroke="none" /><circle cx="12" cy="7.5" r="1.1" fill="currentColor" stroke="none" /><circle cx="16.5" cy="11" r="1.1" fill="currentColor" stroke="none" /></>),
  type:     sv(<><path d="M4 6V4h16v2M9 20h6M12 4v16" /></>),
  globe:    sv(<><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3c2.5 2.5 2.5 15 0 18M12 3c-2.5 2.5-2.5 15 0 18" /></>),
  sliders:  sv(<><path d="M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6" /></>),
  layers:   sv(<><path d="M12 3l9 5-9 5-9-5z" /><path d="M3 13l9 5 9-5" /></>),
  briefcase:sv(<><rect x="3" y="7" width="18" height="13" rx="2" /><path d="M8 7V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M3 12h18" /></>),
  route:    sv(<><circle cx="6" cy="19" r="2.5" /><circle cx="18" cy="5" r="2.5" /><path d="M9 18h6a3 3 0 0 0 0-6H9a3 3 0 0 1 0-6" /></>),
  vault:    sv(<><rect x="3" y="4" width="18" height="16" rx="2" /><circle cx="12" cy="12" r="4" /><path d="M12 9v1M12 14v1M9.5 12h1M13.5 12h1" /></>),
  refresh:  sv(<><path d="M21 12a9 9 0 1 1-3-6.7L21 8M21 3v5h-5" /></>),
};

/* ---------------- mood (atmosphere) ---------------- */
const MOODS = {
  warm: { '--paper': '#F7F2E9', '--paper-2': '#FBF7EF', '--surface': '#FFFFFF', '--ink': '#1B1815', '--ink-2': '#57514A', '--ink-3': '#8B8275', '--border': '#E7DFCF', '--border-2': '#DAD0BC', '--accent': '#2F5BE6', '--accent-press': '#2348BE', '--accent-soft': '#E6ECFB', '--on-accent': '#FFFFFF', '--protected': '#1B6B4C', '--protected-bg': '#E1F0E6', '--warning': '#9C6209', '--warning-bg': '#F7EAD0', '--danger': '#B23B2E' },
  cool: { '--paper': '#EDF0F4', '--paper-2': '#F5F7FA', '--surface': '#FFFFFF', '--ink': '#161A21', '--ink-2': '#4B515C', '--ink-3': '#858C98', '--border': '#E0E4EA', '--border-2': '#CDD3DC', '--accent': '#2F5BE6', '--accent-press': '#2348BE', '--accent-soft': '#E6ECF8', '--on-accent': '#FFFFFF', '--protected': '#0E7C5A', '--protected-bg': '#DBF0E7', '--warning': '#B0700C', '--warning-bg': '#F6EAD2', '--danger': '#C8392C' },
  dark: { '--paper': '#14110D', '--paper-2': '#1B1711', '--surface': '#221D15', '--ink': '#F4EEE2', '--ink-2': '#B8B0A0', '--ink-3': '#837A6B', '--border': '#2F291F', '--border-2': '#423A2C', '--accent': '#6E8DF6', '--accent-press': '#5877E0', '--accent-soft': '#20283F', '--on-accent': '#0E1530', '--protected': '#62CD98', '--protected-bg': '#143329', '--warning': '#E0A23C', '--warning-bg': '#372B14', '--danger': '#E5705F' },
};
function applyMood(m) {
  const map = MOODS[m] || MOODS.warm;
  const s = document.documentElement.style;
  Object.entries(map).forEach(([k, v]) => s.setProperty(k, v));
}

/* ---------------- edit-mode host bridge (for Tweaks) ---------------- */
function useEditMode() {
  const [on, setOn] = useState(false);
  useEffect(() => {
    const onMsg = (e) => {
      const t = e.data && e.data.type;
      if (t === '__activate_edit_mode') setOn(true);
      else if (t === '__deactivate_edit_mode') setOn(false);
    };
    window.addEventListener('message', onMsg);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', onMsg);
  }, []);
  const dismiss = () => { setOn(false); window.parent.postMessage({ type: '__edit_mode_dismissed' }, '*'); };
  return [on, dismiss];
}
function pushTweak(edits) { window.parent.postMessage({ type: '__edit_mode_set_keys', edits }, '*'); }

/* scroll reveal hook */
function useReveal() {
  useEffect(() => {
    const els = [...document.querySelectorAll('.reveal')];
    if (!els.length) return;
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (reduce || !('IntersectionObserver' in window)) { els.forEach((e) => e.classList.add('in')); return; }
    document.documentElement.classList.add('js-anim');
    const reveal = (e) => e.classList.add('in');
    const io = new IntersectionObserver((ents) => {
      ents.forEach((en) => { if (en.isIntersecting) { reveal(en.target); io.unobserve(en.target); } });
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    // Reveal anything already in/above the viewport on first paint, observe the rest.
    const vh = window.innerHeight || 800;
    els.forEach((e) => { if (e.getBoundingClientRect().top < vh * 0.92) reveal(e); else io.observe(e); });
    // Safety net: never let an element stay hidden if the observer misses it.
    const t = setTimeout(() => els.forEach(reveal), 1200);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
}

/* ---------------- shared nav + footer ---------------- */
function Nav({ active, links }) {
  const ls = links || [
    { t: 'Platform', href: '#platform' },
    { t: 'For founders', href: '#founders' },
    { t: 'For firms', href: '#firms' },
    { t: 'Pricing', href: '#pricing' },
  ];
  return (
    <div className="nav"><div className="wrap">
      <a href="Lectual Marketing Home.html" style={{ textDecoration: 'none', display: 'flex' }}><Echo size={21} /></a>
      <div className="links">
        {ls.map((l) => <a key={l.t} href={l.href} className={active === l.t ? 'on' : ''}>{l.t}</a>)}
      </div>
      <div className="right">
        <a className="signin" href="#">Sign in</a>
        <a className="btn btn-primary btn-sm" href="Lectual Public Audit.html">Audit my firm free</a>
      </div>
    </div></div>
  );
}

function Footer() {
  return (
    <footer><div className="wrap">
      <div className="foot-grid">
        <div style={{ maxWidth: 290 }}>
          <Echo size={22} />
          <p style={{ fontSize: 14, color: 'var(--ink-3)', marginTop: 14, lineHeight: 1.5 }}>
            The intellectual-property platform for founders and the boutique firms that protect them.
          </p>
          <div className="trustline" style={{ marginTop: 18 }}>{Ico.lock} SOC 2 Type II · AES-256 at rest</div>
        </div>
        <div className="foot-cols">
          <div className="col"><h5>Founders</h5><a href="Lectual Founder Landing.html">Readiness check</a><a href="Lectual Founder App.html">The Vault</a><a href="#">Attorney matching</a><a href="#">Learning center</a></div>
          <div className="col"><h5>Firms</h5><a href="Lectual Public Audit.html">Free CRM audit</a><a href="Lectual Attorney CRM.html">The CRM</a><a href="Lectual Onboarding.html">Get set up</a><a href="#">White-label funnel</a></div>
          <div className="col"><h5>Company</h5><a href="Lectual Brand System.html">Brand system</a><a href="#">About Oath</a><a href="#">Security</a><a href="#">Contact</a></div>
        </div>
      </div>
      <div className="foot-legal">
        <span>© 2026 Lectual · a product of Oath Innovation Inc</span>
        <span className="pill">{Ico.shield} Not a law firm</span>
        <span className="pill">Information, not legal advice</span>
      </div>
    </div></footer>
  );
}

Object.assign(window, {
  Echo, AppMark, Gauge, bandColor, bandName, Ico,
  MOODS, applyMood, useEditMode, pushTweak, useReveal, Nav, Footer,
});
