// app.jsx — PM Portfolio for Ionut "Johnny" Pogacean
// NASA Graphics Standards Manual (1976) × Linear restraint.

const { useState, useEffect, useRef, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "auto",
  "displayFont": "helvetica",
  "grain": 0.05,
  "marqueeSpeed": 60
} /*EDITMODE-END*/;

// Resolve "auto" → "light"/"dark" based on local hour.
// Day: 07:00–18:59. Night: 19:00–06:59.
function resolveTheme(theme) {
  if (theme === "light" || theme === "dark") return theme;
  const h = new Date().getHours();
  return h >= 7 && h < 19 ? "light" : "dark";
}

// ── Content ──────────────────────────────────────────────────────────────────

const NAME = "Ionuț \u201CJohnny\u201D Pogăcean";
const NAME_DISPLAY = ["IONUȚ", "POGĂCEAN"];
const YEAR_EST = "2016";
const EMAIL = "ionut.pogacean@gmail.com";

const POSITIONING = [
"Product manager for live media platforms. The newsroom tools, real-time graphics, and editorial systems global broadcasters use to ship moments to millions of viewers.",
"Twenty years across Vizrt, Sky, and Fonn Group. Engineer before product."];


const TOOLS = [
"AHA", "JIRA", "CONFLUENCE", "FIGMA", "NOTION",
"LOOKER", "SQL", "UNREAL ENGINE", "VIZ ENGINE", "AWS", "ANSIBLE"];


const PROJECTS = [
{ no: "01", title: "Premier League Workflow Delivery", company: "Fonn Group", year: "2026",
  outcome: "Owning end-to-end delivery for Premier League and Sky News UK 2030 workflow deployments.",
  detail: "Translating complex broadcast requirements into structured delivery plans and measurable milestones. Acting as the primary bridge between client stakeholders and engineering, ensuring editorial priorities drive solution design over purely technical constraints." },
{ no: "02", title: "Editorial \u0026 Control Solutions", company: "Vizrt", year: "2025",
  outcome: "Grew ARR 35% and the active customer base from 60 to 180+ enterprise users (3\u00d7).",
  detail: "Senior PM for the newsroom and control room tools used daily by broadcasters worldwide. Drove the strategy and vision for the portfolio, prioritising features through direct customer feedback loops and adoption analytics. Led cross-functional teams across product, engineering, design, QA, and marketing." },
{ no: "03", title: "Virtual Productions on AWS", company: "Sky UK", year: "2021",
  outcome: "Spearheaded cloud and on-prem virtual production deployments; reduced support calls 25% via playbooks.",
  detail: "Designed automated workflows via Ansible, significantly reducing spin-up time and manual setup. Built technical playbooks and SOPs that freed teams to focus on product improvement over incident response." },
{ no: "04", title: "Sky News US Election 2020", company: "Sky UK", year: "2020",
  outcome: "Shaped the on-air experience watched by millions, integrating real-time data, on-screen graphics, and AR.",
  detail: "Led the project delivery team responsible for architecture and deployment of real-time broadcast graphics solutions. Ensured reliability at scale during peak audience moments, working alongside editorial, design, and data teams." },
{ no: "05", title: "Premier League Matchday Visuals", company: "Sky UK", year: "2019",
  outcome: "Delivered the matchday visual experience for millions of Sky Sports viewers.",
  detail: "Integrated Unreal Engine, Viz Engine, and optical tracking to enhance storytelling and engagement. Deployable virtual set, on-screen graphics, and live data integration for the Premier League season." },
{ no: "06", title: "Eastern Europe Support Operations", company: "Vizrt", year: "2016",
  outcome: "Led support across 18 countries; delivered 25+ major implementation projects.",
  detail: "Managed a team of engineers across system installs, upgrades, training, and live support. Acted as regional liaison to Vizrt R\u0026D, ensuring customer feedback informed product development." }];


const BIO = [
"Specialism is real-time media platforms and broadcast technology. I work close to the engineering, the editorial workflows, and the live operations: writing specs that hold up under pressure, partnering on architecture before it ships, and translating complex technical capabilities into scalable tools that broadcasters use daily.",
"Strongest on customer-driven roadmaps inside enterprise B2B SaaS, on legacy modernisation where downtime is not an option, and on the connective tissue between editorial intent and the systems that put it on screen. Comfortable when the answer is months of unglamorous infrastructure followed by one week of visible impact.",
"Romanian, based in London. Engineer by training, product by trade. Twenty years inside live television leaves you with strong opinions about latency and very little patience for vague language."];


const SKILLS = [
["DOMAIN", "Broadcast, live media, B2B SaaS"],
["STACK", "Aha! \u00b7 Jira \u00b7 SQL \u00b7 Figma \u00b7 Notion"],
["METHOD", "Discovery, JTBD, OKRs, roadmapping"],
["SHIPPED", "35% ARR \u00b7 200% customer growth"],
["TEAMS", "Cross-functional product, eng, design, QA"],
["LANGUAGES", "EN \u00b7 RO \u00b7 FR"],
["BASED", "London, UK"],
["EST.", "2016"]];


const NOW = [
{ label: "WORKING ON", text: "Premier League and Sky News UK 2030 workflow deployments at Fonn Group." },
{ label: "BUILDING", text: "A terminal app for running commands across multiple servers in parallel." },
{ label: "RE-READING", text: "Empowered \u2014 Marty Cagan." },
{ label: "EXPLORING", text: "AI automation in everyday product work." }];


const LINKS = [
{ label: "LINKEDIN", href: "https://linkedin.com/in/ionutpogacean" },
{ label: "EMAIL", href: "mailto:ionut.pogacean@gmail.com" },
{ label: "CV", href: "#" }];


const LAST_UPDATED = "MAY 2026";

const FONTS = {
  helvetica: '"Helvetica Neue", "Helvetica", "Arial", system-ui, sans-serif',
  inter: '"Inter Tight", "Inter", system-ui, sans-serif',
  sohne: '"Space Grotesk", "Inter Tight", system-ui, sans-serif'
};

// ── Helpers ──────────────────────────────────────────────────────────────────

function CornerBrackets({ size = 14, inset = 0 }) {
  const s = size;
  const off = inset;
  const armV = { position: "absolute", background: "currentColor", width: 1, height: s };
  const armH = { position: "absolute", background: "currentColor", width: s, height: 1 };
  const wrap = (pos) => ({ position: "absolute", width: s, height: s, pointerEvents: "none", ...pos });
  return (
    <React.Fragment>
      <div style={wrap({ top: off, left: off })}>
        <div style={{ ...armV, top: 0, left: 0 }} />
        <div style={{ ...armH, top: 0, left: 0 }} />
      </div>
      <div style={wrap({ top: off, right: off })}>
        <div style={{ ...armV, top: 0, right: 0 }} />
        <div style={{ ...armH, top: 0, right: 0 }} />
      </div>
      <div style={wrap({ bottom: off, left: off })}>
        <div style={{ ...armV, bottom: 0, left: 0 }} />
        <div style={{ ...armH, bottom: 0, left: 0 }} />
      </div>
      <div style={wrap({ bottom: off, right: off })}>
        <div style={{ ...armV, bottom: 0, right: 0 }} />
        <div style={{ ...armH, bottom: 0, right: 0 }} />
      </div>
    </React.Fragment>);

}

function NoiseOverlay({ opacity }) {
  return (
    <svg aria-hidden="true" style={{
      position: "fixed", inset: 0, width: "100%", height: "100%",
      pointerEvents: "none", opacity, mixBlendMode: "multiply", zIndex: 1
    }}>
      <filter id="pmnoise">
        <feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
        <feColorMatrix values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.55 0" />
      </filter>
      <rect width="100%" height="100%" filter="url(#pmnoise)" />
    </svg>);

}

function SectionNo({ n, label }) {
  return (
    <div className="sectno mono">
      <span>{n}</span>
      <span className="sectno-slash">/</span>
      <span>{label}</span>
    </div>);

}

// ── Sections ─────────────────────────────────────────────────────────────────

function Hero({ marqueeSpeed }) {
  return (
    <section id="hero" className="band hero" data-screen-label="01 Hero">
      <CornerBrackets size={16} inset={24} />
      <SectionNo n="00" label="INDEX" />
      <div className="hero-mono mono">
        PRODUCT MANAGER &middot; LONDON &middot; EST. {YEAR_EST}
      </div>
      <h1 className="hero-name">
        <span className="hero-line">{NAME_DISPLAY[0]}</span>
        <span className="hero-line hero-accent" style={{ width: "1164px", fontSize: "200px" }}>{NAME_DISPLAY[1]}</span>
      </h1>
      <div className="hero-positioning">
        <p>{POSITIONING[0]}</p>
        <p>{POSITIONING[1]}</p>
      </div>
      <div className="hero-meta mono">
        <div><span className="dim">FILE</span>&nbsp;&nbsp;PORTFOLIO / 2026</div>
        <div><span className="dim">REV.</span>&nbsp;&nbsp;14</div>
        <div><span className="dim">SHEET</span>&nbsp;&nbsp;01 OF 05</div>
      </div>
      <Marquee items={TOOLS} speed={marqueeSpeed} />
    </section>);

}

function Marquee({ items, speed }) {
  const duration = Math.max(15, 9000 / speed);
  const repeated = [...items, ...items, ...items];
  return (
    <div className="marquee" aria-hidden="true">
      <div className="marquee-track mono" style={{ animationDuration: `${duration}s` }}>
        {repeated.map((t, i) =>
        <span key={i} className="marquee-item">
            <span>{t}</span>
            <span className="marquee-dot">&middot;</span>
          </span>
        )}
      </div>
    </div>);

}

function Work() {
  const [hover, setHover] = useState(null);
  return (
    <section id="work" className="band work" data-screen-label="02 Work">
      <SectionNo n="01" label="WORK" />
      <h2 className="band-title">Selected work</h2>
      <p className="band-deck">Six projects, 2019&ndash;2025. One-line outcomes; ask for the long version.</p>
      <ol className="work-list">
        {PROJECTS.map((p, i) =>
        <li key={p.no}
        className={`work-row ${hover === i ? "is-hover" : ""}`}
        onMouseEnter={() => setHover(i)}
        onMouseLeave={() => setHover(null)}
        onFocus={() => setHover(i)}
        onBlur={() => setHover(null)}
        tabIndex={0}>
            <CornerBrackets size={10} inset={0} />
            <div className="work-no mono">{p.no}</div>
            <div className="work-main">
              <div className="work-head">
                <h3 className="work-title">{p.title}</h3>
                <div className="work-company mono">{p.company}</div>
              </div>
              <div className="work-outcome">{p.outcome}</div>
              <div className="work-detail">{p.detail}</div>
            </div>
            <div className="work-thumb" aria-hidden="true">
              <Thumb i={i} />
            </div>
            <div className="work-year mono">{p.year}</div>
          </li>
        )}
      </ol>
    </section>);

}

function Thumb({ i }) {
  const variants = [
  <svg viewBox="0 0 80 60" key={0}>
      <circle cx="40" cy="30" r="22" fill="none" stroke="currentColor" strokeWidth="0.6" />
      <circle cx="40" cy="30" r="14" fill="none" stroke="currentColor" strokeWidth="0.6" />
      <circle cx="40" cy="30" r="6" fill="currentColor" />
      <line x1="4" y1="30" x2="76" y2="30" stroke="currentColor" strokeWidth="0.4" strokeDasharray="2 2" />
    </svg>,
  <svg viewBox="0 0 80 60" key={1}>
      <polygon points="8,8 72,8 50,32 50,52 30,52 30,32" fill="none" stroke="currentColor" strokeWidth="0.6" />
      <line x1="8" y1="20" x2="72" y2="20" stroke="currentColor" strokeWidth="0.4" />
      <line x1="14" y1="14" x2="66" y2="14" stroke="currentColor" strokeWidth="0.3" />
    </svg>,
  <svg viewBox="0 0 80 60" key={2}>
      <rect x="6" y="14" width="14" height="32" fill="none" stroke="currentColor" strokeWidth="0.6" />
      <rect x="22" y="20" width="14" height="26" fill="none" stroke="currentColor" strokeWidth="0.6" />
      <rect x="38" y="10" width="14" height="36" fill="currentColor" />
      <rect x="54" y="22" width="14" height="24" fill="none" stroke="currentColor" strokeWidth="0.6" />
      <line x1="4" y1="46" x2="76" y2="46" stroke="currentColor" strokeWidth="0.4" />
    </svg>,
  <svg viewBox="0 0 80 60" key={3}>
      <rect x="6" y="8" width="68" height="44" fill="none" stroke="currentColor" strokeWidth="0.6" />
      {[0, 1, 2].map((r) =>
    [0, 1, 2, 3].map((c) =>
    <rect key={`${r}-${c}`} x={10 + c * 16} y={12 + r * 12} width="12" height="8"
    fill={r === 1 && c === 2 ? "currentColor" : "none"}
    stroke="currentColor" strokeWidth="0.3" />
    )
    )}
    </svg>,
  <svg viewBox="0 0 80 60" key={4}>
      <line x1="8" y1="50" x2="72" y2="50" stroke="currentColor" strokeWidth="0.4" />
      <line x1="8" y1="50" x2="8" y2="8" stroke="currentColor" strokeWidth="0.4" />
      {[[14, 42], [20, 36], [28, 30], [36, 38], [42, 22], [48, 26], [54, 16], [60, 20], [66, 12]].map(([x, y], j) =>
    <circle key={j} cx={x} cy={y} r="1.2" fill="currentColor" />
    )}
      <line x1="10" y1="48" x2="70" y2="14" stroke="currentColor" strokeWidth="0.4" strokeDasharray="2 2" />
    </svg>,
  <svg viewBox="0 0 80 60" key={5}>
      {[0, 1, 2, 3].map((j) =>
    <React.Fragment key={j}>
          <rect x={6 + j * 18} y="22" width="14" height="16"
      fill={j === 2 ? "currentColor" : "none"} stroke="currentColor" strokeWidth="0.6" />
          {j < 3 && <line x1={20 + j * 18} y1="30" x2={24 + j * 18} y2="30" stroke="currentColor" strokeWidth="0.4" />}
        </React.Fragment>
    )}
    </svg>];

  return variants[i % variants.length];
}

function About() {
  return (
    <section id="about" className="band about alt" data-screen-label="03 About">
      <SectionNo n="02" label="ABOUT" />
      <h2 className="band-title">About</h2>
      <div className="about-grid">
        <div className="portrait">
          <CornerBrackets size={12} inset={0} />
          <image-slot
            id="portrait"
            class="portrait-img"
            shape="rect"
            fit="contain"
            placeholder="Drop portrait">
          </image-slot>
          <div className="portrait-cap mono">JOHNNY</div>
        </div>
        <div className="bio">
          {BIO.map((p, i) =>
          <p key={i} className={i === 1 ? "bio-emph" : ""}>{p}</p>
          )}
          <div className="skills">
            <div className="skills-head mono">
              <span>SPECIFICATIONS</span>
              <span className="dim">REV. 14 / {LAST_UPDATED}</span>
            </div>
            <dl className="skills-list mono">
              {SKILLS.map(([k, v]) =>
              <div key={k} className="skills-row">
                  <dt>{k}</dt>
                  <dd>{v}</dd>
                </div>
              )}
            </dl>
          </div>
        </div>
      </div>
    </section>);

}

function NowSection() {
  return (
    <section id="now" className="band now" data-screen-label="04 Now">
      <SectionNo n="03" label="NOW" />
      <h2 className="band-title">Now</h2>
      <p className="band-deck">As of {LAST_UPDATED.toLowerCase()}.</p>
      <ul className="now-list">
        {NOW.map((row) =>
        <li key={row.label} className="now-row">
            <span className="now-label mono">{row.label}</span>
            <span className="now-text">{row.text}</span>
          </li>
        )}
      </ul>
    </section>);

}

function Contact() {
  return (
    <section id="contact" className="band contact alt" data-screen-label="05 Contact">
      <SectionNo n="04" label="CONTACT" />
      <h2 className="band-title">Get in touch</h2>
      <a className="email" href={`mailto:${EMAIL}`}>
        <span>{EMAIL}</span>
        <span className="email-arrow">&#8599;</span>
      </a>
      <div className="links mono">
        {LINKS.map((l, i) =>
        <a key={l.label} href={l.href} className="link-pill">
            <span className="link-no">{String(i + 1).padStart(2, "0")}</span>
            <span>{l.label}</span>
            <span className="link-arrow">&#8599;</span>
          </a>
        )}
      </div>
      <footer className="footer mono">
        <div>&copy; {NAME.toUpperCase()} &middot; LONDON</div>
        <div>LAST UPDATED {LAST_UPDATED}</div>
        <div className="footer-meta">SHEET 05 OF 05 &middot; END</div>
      </footer>
    </section>);

}

function Nav() {
  return (
    <nav className="nav mono">
      <a href="#hero" className="nav-name">{NAME.toUpperCase()}</a>
      <ul>
        <li><a href="#work">01 WORK</a></li>
        <li><a href="#about">02 ABOUT</a></li>
        <li><a href="#now">03 NOW</a></li>
        <li><a href="#contact">04 CONTACT</a></li>
      </ul>
    </nav>);

}

// ── App ──────────────────────────────────────────────────────────────────────

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [resolved, setResolved] = useState(() => resolveTheme(t.theme));

  useEffect(() => {
    const update = () => setResolved(resolveTheme(t.theme));
    update();
    const id = setInterval(update, 60_000);
    return () => clearInterval(id);
  }, [t.theme]);

  useEffect(() => {
    const root = document.documentElement;
    if (resolved === "dark") {
      root.style.setProperty("--bg", "#10131A");
      root.style.setProperty("--bg-alt", "#171B23");
      root.style.setProperty("--ink", "#DDE2EA");
      root.style.setProperty("--ink-mute", "#7A7E86");
      root.style.setProperty("--rule", "rgba(221,226,234,0.14)");
    } else {
      root.style.setProperty("--bg", "#E2E2DA");
      root.style.setProperty("--bg-alt", "#D6D6CD");
      root.style.setProperty("--ink", "#0A0A0C");
      root.style.setProperty("--ink-mute", "#6A6A66");
      root.style.setProperty("--rule", "rgba(10,10,12,0.14)");
    }
    root.style.setProperty("--font-display", FONTS[t.displayFont] || FONTS.helvetica);
  }, [resolved, t.displayFont]);

  const autoLabel = (() => {
    if (t.theme !== "auto") return null;
    const h = new Date().getHours();
    return `Auto \u2014 ${resolved} (local ${String(h).padStart(2, "0")}:00)`;
  })();

  return (
    <div className="page">
      <NoiseOverlay opacity={t.grain} />
      <Nav />
      <main>
        <Hero marqueeSpeed={t.marqueeSpeed} />
        <Work />
        <About />
        <NowSection />
        <Contact />
      </main>
      <TweaksPanel>
        <TweakSection label="Theme" />
        <TweakRadio label="Mode" value={t.theme}
        options={[
        { value: "auto", label: "Auto" },
        { value: "light", label: "Day" },
        { value: "dark", label: "Night" }]
        }
        onChange={(v) => setTweak("theme", v)} />
        {autoLabel &&
        <div className="mono" style={{
          fontSize: 9, letterSpacing: "0.1em",
          color: "rgba(41,38,27,.55)", marginTop: -2
        }}>{autoLabel}</div>
        }
        <TweakSection label="Type" />
        <TweakRadio label="Display" value={t.displayFont}
        options={[
        { value: "helvetica", label: "Helv." },
        { value: "inter", label: "Inter" },
        { value: "sohne", label: "S\u00f6hne" }]
        }
        onChange={(v) => setTweak("displayFont", v)} />
        <TweakSection label="Texture" />
        <TweakSlider label="Grain" value={t.grain} min={0} max={0.18} step={0.01}
        format={(v) => `${Math.round(v * 100)}%`}
        onChange={(v) => setTweak("grain", v)} />
        <TweakSection label="Motion" />
        <TweakSlider label="Marquee speed" value={t.marqueeSpeed}
        min={20} max={140} step={5}
        format={(v) => `${v}`}
        onChange={(v) => setTweak("marqueeSpeed", v)} />
      </TweaksPanel>
    </div>);

}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);