// CV — interactive app
const { useState, useEffect, useRef } = React;

const D = window.CV_DATA;

// ————— Tweak defaults (persisted by the host) —————
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#8b103d",
  "typeStyle": "sans",
  "density": "comfortable",
  "dark": false,
  "showPhoto": true
} /*EDITMODE-END*/;

const ACCENTS = [
{ name: "Wine", val: "#8b103d" },
{ name: "Ocean", val: "#0a527f" },
{ name: "Forest", val: "#2b5a3e" },
{ name: "Copper", val: "#b55a2a" },
{ name: "Ink", val: "#1a1a1a" },
{ name: "Pink", val: "#d2477a" }];


const DENSITIES = {
  cozy: { label: "Cozy", v: 0.75 },
  comfortable: { label: "Comfortable", v: 1.0 },
  generous: { label: "Generous", v: 1.3 }
};

const TYPE_STYLES = {
  sans: { label: "Sans", cls: "" },
  editorial: { label: "Editorial", cls: "serif-display" },
  classical: { label: "Classical", cls: "all-serif" },
  mono: { label: "Technical", cls: "mono-labels" }
};

// ————— Icons —————
const Ico = {
  Mail: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><rect x="3" y="5" width="18" height="14" rx="1.5" /><path d="M3 7l9 6 9-6" /></svg>,
  Link: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><path d="M10 14a3.5 3.5 0 0 1 0-5l3-3a3.5 3.5 0 0 1 5 5l-1.5 1.5" /><path d="M14 10a3.5 3.5 0 0 1 0 5l-3 3a3.5 3.5 0 0 1-5-5l1.5-1.5" /></svg>,
  At: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><circle cx="12" cy="12" r="4" /><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8" /></svg>,
  Play: () => <svg width="30" height="30" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z" /></svg>,
  Print: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><rect x="6" y="3" width="12" height="6" /><path d="M6 17H4a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2" /><rect x="6" y="14" width="12" height="7" /></svg>,
  Sparkle: () => <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l1.6 5.6L19 9l-5.4 1.4L12 16l-1.6-5.6L5 9l5.4-1.4z" /></svg>
};

// ————— Tweaks panel —————
function TweaksPanel({ open, onClose, tweaks, setTweak }) {
  if (!open) return null;
  return (
    <aside className="tweaks">
      <header>
        <span>Tweaks</span>
        <button aria-label="Close" onClick={onClose}>×</button>
      </header>

      <section>
        <h4>Accent</h4>
        <div className="swatches">
          {ACCENTS.map((a) =>
          <button key={a.val} className="swatch"
          title={a.name}
          aria-pressed={tweaks.accent === a.val}
          onClick={() => setTweak('accent', a.val)}
          style={{ background: a.val }} />
          )}
        </div>
      </section>

      <section>
        <h4>Type</h4>
        <div className="pill-opts">
          {Object.entries(TYPE_STYLES).map(([k, v]) =>
          <button key={k} className="pill-opt"
          aria-pressed={tweaks.typeStyle === k}
          onClick={() => setTweak('typeStyle', k)}>{v.label}</button>
          )}
        </div>
      </section>

      <section>
        <h4>Density</h4>
        <div className="pill-opts">
          {Object.entries(DENSITIES).map(([k, v]) =>
          <button key={k} className="pill-opt"
          aria-pressed={tweaks.density === k}
          onClick={() => setTweak('density', k)}>{v.label}</button>
          )}
        </div>
      </section>

      <section>
        <div className="toggle-row">
          <span>Dark mode</span>
          <button className="switch"
          aria-pressed={tweaks.dark}
          onClick={() => setTweak('dark', !tweaks.dark)} />
        </div>
      </section>

      <section>
        <div className="toggle-row">
          <span>Show portrait</span>
          <button className="switch"
          aria-pressed={tweaks.showPhoto}
          onClick={() => setTweak('showPhoto', !tweaks.showPhoto)} />
        </div>
      </section>
    </aside>);

}

// ————— Sections —————
function Hero({ showPhoto }) {
  return (
    <section className="hero" id="intro">
      <div>
        <div className="eyebrow">CV · 2026 Edition</div>
        <h1>{D.name.split(' ')[0]}<br />{D.name.split(' ').slice(1).join(' ')} <em>—</em></h1>
        <p className="lede">{D.tagline}.</p>
        <dl className="hero-meta">
          {D.heroMeta.map((m) =>
          <div key={m.k}>
              <dt className="mono-ish">{m.k}</dt>
              <dd>{m.v}</dd>
            </div>
          )}
        </dl>
      </div>
      {showPhoto &&
      <div className="portrait-wrap">
          <img src="assets/portrait.jpg" alt="Magnus Westerberg" />
          <div className="portrait-tag mono-ish">
            <b>Photo</b> · Peter Knutsson
          </div>
        </div>
      }
    </section>);

}

function Intro() {
  return (
    <section className="block" id="intro-block" data-screen-label="01 Intro">
      <div className="section-head">
        <div className="num mono-ish">01 / Intro</div>
        <div>
          <h2>A <span className="pill">CX & Tech</span> perspective at the heart of every engagement.</h2>
          <p>More than two decades of shipping product, developing experiences and leading cross-functional teams of teams.</p>
        </div>
      </div>

      <div className="intro-grid">
        <div className="spacer"></div>
        <div className="intro-body">
          {D.intro.map((p, i) =>
          <p key={i}>{i === 0 ? <><strong>{p.split('.')[0]}.</strong>{p.slice(p.indexOf('.') + 1)}</> : p}</p>
          )}
        </div>
        <aside className="pull-card">
          <div className="watch" aria-label="Apple Watch · CX animation">
            <iframe src={`watch.html?v=${Date.now()}`} title="Watch animation" loading="lazy" scrolling="no"></iframe>
          </div>
          <div className="body">
            <div className="label mono-ish">{D.pull.label}</div>
            <blockquote>"{D.pull.quote}"</blockquote>
          </div>
        </aside>
      </div>
    </section>);

}

function Resume() {
  const [activeLecture, setActiveLecture] = useState(false);
  return (
    <section className="block" id="resume" data-screen-label="02 Resume">
      <div className="section-head">
        <div className="num mono-ish">02 / Resume</div>
        <div>
          <h2>Continuous <span className="pill" style={{ background: 'var(--beige)' }}>innovation</span>, not phase-based delivery.</h2>
          <p>Leading cross-functional teams — and teams of teams — in developing outstanding, innovative work. Part inspirator, part facilitator, part coach.</p>
        </div>
      </div>

      <div className="values-block">
        <div className="num mono-ish" style={{ paddingTop: '10px' }}>Four things to expect</div>
        <div className="values">
          {D.values.map((v) =>
          <div className="value" key={v.n}>
            <div className="num">{v.n}</div>
            <h3>{v.t}</h3>
            <p>{v.d}</p>
          </div>
        )}
        </div>
      </div>

      <div className="contexts">
        <div className="num mono-ish" style={{ paddingTop: '10px' }}>Contexts</div>
        <div className="contexts-grid">
          {D.contexts.map((c) =>
          <article className={`context-card ${c.k}`} key={c.city}>
              <span className="chip mono-ish">{c.tag}</span>
              <div className="city">{c.city}</div>
              <p>{c.body}</p>
            </article>
          )}
        </div>
      </div>

      <div className="lecture">
        <div className="media" style={{ backgroundImage: "url(assets/lecture.png)" }}>
          <button className="play" aria-label="Play lecture" onClick={() => setActiveLecture(true)}>
            <span className="play-btn"><Ico.Play /></span>
          </button>
        </div>
        <div className="copy">
          <div className="eyebrow mono-ish">Lecture · {D.lecture.duration}</div>
          <h3>{D.lecture.title}</h3>
          <p>{D.lecture.body}</p>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '.12em', textTransform: 'uppercase', color: 'rgba(255,255,255,.5)', marginTop: 8 }}>
            {D.lecture.venue} · KTH · MITx · Hyper Island · Stockholm School of Economics
          </div>
        </div>
      </div>
    </section>);

}

function CVTimeline() {
  return (
    <section className="block" id="cv" data-screen-label="03 CV">
      <div className="section-head">
        <div className="num mono-ish">03 / Vitae</div>
        <div>
          <h2>Creative <em style={{ fontStyle: 'italic', fontFamily: 'Fraunces, Georgia, serif', fontWeight: 400, color: 'var(--accent)' }}>vitae</em>.</h2>
          <p>Long and deep experience of developing concepts, products, experiences and strategy.</p>
        </div>
      </div>

      <div className="timeline">
        <div className="num mono-ish" style={{ paddingTop: '10px' }}></div>
        <div className="timeline-list">
          {[...D.jobs].reverse().map((j) =>
          <article className="job" key={j.n}>
              <div className="job-num">{j.n}</div>
              <div className="job-years mono-ish">{j.years}</div>
              <div className="job-role">
                <h3>{j.role}</h3>
                <div className="where">{j.where}.</div>
              </div>
              <div className="job-city mono-ish">{j.city}</div>
            </article>
          )}
        </div>
      </div>

      <div className="edu">
        <div className="num mono-ish" style={{ padding: 0 }}>Education</div>
        <div className="edu-img" style={{ backgroundImage: "url(assets/education.png)" }}></div>
        <div className="edu-body">
          <h3>BA in Communications, Berghs — plus.</h3>
          {D.education.map((e, i) => <p key={i}>· {e}</p>)}
        </div>
      </div>
    </section>);

}

function Footer() {
  return (
    <footer id="contact" data-screen-label="04 Contact">
      <div className="footer-inner">
        <div className="footer-grid">
          <div className="num mono-ish" style={{ color: 'rgba(255,255,255,.4)', paddingTop: '20px' }}>04 / Contact</div>
          <h2>Let's <em>talk.</em></h2>
          <div className="contact-list">
            <a className="contact-row" href={`mailto:${D.email}`}><span className="icn"><Ico.Mail /></span>{D.email}</a>
            <a className="contact-row" href={`https://${D.linkedin}`} target="_blank" rel="noopener"><span className="icn"><Ico.Link /></span>{D.linkedin}</a>
            <a className="contact-row" href={`https://${D.web}`} target="_blank" rel="noopener"><span className="icn"><Ico.Link /></span>{D.web}</a>
            <a className="contact-row" href="#"><span className="icn"><Ico.At /></span>{D.twitter}</a>
          </div>
        </div>
        <div className="footer-meta mono-ish">
          <span>© 2026 · Magnus Westerberg</span>
          <span>Built on nextversion.org</span>
        </div>
      </div>
    </footer>);

}

// ————— App —————
function App() {
  const [tweaks, setTweaks] = useState(TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = useState(false);
  const [active, setActive] = useState('intro');
  const sections = useRef({});

  const setTweak = (k, v) => {
    const next = { ...tweaks, [k]: v };
    setTweaks(next);
    window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [k]: v } }, '*');
  };

  // Apply tweaks to root
  useEffect(() => {
    const root = document.documentElement;
    root.style.setProperty('--accent', tweaks.accent);
    root.style.setProperty('--density', DENSITIES[tweaks.density]?.v ?? 1);
    root.classList.toggle('dark', !!tweaks.dark);
    ['serif-display', 'all-serif', 'mono-labels'].forEach((c) => root.classList.remove(c));
    const cls = TYPE_STYLES[tweaks.typeStyle]?.cls;
    if (cls) root.classList.add(cls);
  }, [tweaks]);

  // Edit mode toggle
  useEffect(() => {
    const onMsg = (e) => {
      const d = e.data || {};
      if (d.type === '__activate_edit_mode') setTweaksOpen(true);
      if (d.type === '__deactivate_edit_mode') setTweaksOpen(false);
    };
    window.addEventListener('message', onMsg);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', onMsg);
  }, []);

  // Scroll-spy
  useEffect(() => {
    const ids = ['intro', 'resume', 'cv', 'contact'];
    const onScroll = () => {
      let cur = 'intro';
      for (const id of ids) {
        const el = document.getElementById(id);
        if (!el) continue;
        const r = el.getBoundingClientRect();
        if (r.top <= 140) cur = id;
      }
      setActive(cur);
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  const [menuOpen, setMenuOpen] = React.useState(false);

  React.useEffect(() => {
    if (!menuOpen) return;
    const close = (e) => {
      if (!e.target.closest('.mobile-menu') && !e.target.closest('.menu-toggle')) {
        setMenuOpen(false);
      }
    };
    document.addEventListener('click', close);
    return () => document.removeEventListener('click', close);
  }, [menuOpen]);

  const go = (id) => (e) => {
    e.preventDefault();
    setMenuOpen(false);
    const el = document.getElementById(id);
    if (el) window.scrollTo({ top: el.offsetTop - 64, behavior: 'smooth' });
  };

  const handlePrint = () => {
    setMenuOpen(false);
    window.print();
  };

  return (
    <>
      <header className="topbar">
        <div className="topbar-inner">
          <div className="brand">
            <span className="brand-dot"></span>
            Magnus Westerberg
          </div>
          <nav className="topnav">
            <button aria-current={active === 'intro'} onClick={go('intro')}>Intro</button>
            <button aria-current={active === 'resume'} onClick={go('resume')}>Resume</button>
            <button aria-current={active === 'cv'} onClick={go('cv')}>CV</button>
            <a className="navlink" href="interview.html">Interview me</a>
            <button aria-current={active === 'contact'} onClick={go('contact')}>Contact</button>
          </nav>
          <button className="cta" onClick={handlePrint}>
            <Ico.Print /> Save PDF
          </button>
          <button
            className="menu-toggle"
            aria-label="Open menu"
            aria-expanded={menuOpen}
            onClick={() => setMenuOpen(v => !v)}
          >
            {menuOpen ? (
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M6 6l12 12M6 18L18 6"/></svg>
            ) : (
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg>
            )}
          </button>
          <div className={"mobile-menu" + (menuOpen ? " open" : "")} role="menu">
            <button aria-current={active === 'intro'} onClick={go('intro')}>Intro</button>
            <button aria-current={active === 'resume'} onClick={go('resume')}>Resume</button>
            <button aria-current={active === 'cv'} onClick={go('cv')}>CV</button>
            <a className="navlink" href="interview.html">Interview me</a>
            <button aria-current={active === 'contact'} onClick={go('contact')}>Contact</button>
            <div className="menu-divider"></div>
            <button className="menu-pdf" onClick={handlePrint}>
              <Ico.Print /> Save PDF
            </button>
          </div>
        </div>
      </header>

      <div className="page">
        <Hero showPhoto={tweaks.showPhoto} />
        <Intro />
        <Resume />
        <CVTimeline />
      </div>
      <Footer />

      <TweaksPanel
        open={tweaksOpen}
        onClose={() => setTweaksOpen(false)}
        tweaks={tweaks}
        setTweak={setTweak} />
      
    </>);

}

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