/* ============================================================
   Kevin Charboneau — Portfolio · shared data, icons, hooks
   Exposed on window for the section + app modules.
   ============================================================ */
const { useState, useEffect, useRef, useLayoutEffect, useCallback } = React;

/* ---- Icons (Lucide-style, 1.7 stroke) ---- */
const Icon = {
  arrowUR: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M7 17 17 7"/><path d="M8 7h9v9"/></svg>),
  arrowR: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg>),
  arrowL: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M19 12H5"/><path d="m11 18-6-6 6-6"/></svg>),
  mail: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>),
  linkedin: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-4 0v7h-4v-7a6 6 0 0 1 6-6z"/><rect x="2" y="9" width="4" height="12"/><circle cx="4" cy="4" r="2"/></svg>),

  /* ---- About list glyphs (Lucide-style, 1.7 stroke) ---- */
  rocket: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>),
  penTool: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="13.5" cy="6.5" r=".9" fill="currentColor" stroke="none"/><circle cx="17.5" cy="10.5" r=".9" fill="currentColor" stroke="none"/><circle cx="8.5" cy="7.5" r=".9" fill="currentColor" stroke="none"/><circle cx="6.5" cy="12.5" r=".9" fill="currentColor" stroke="none"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/></svg>),
  sparkles: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .962 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.962 0z"/><path d="M20 3v4"/><path d="M22 5h-4"/><path d="M4 17v2"/><path d="M5 18H3"/></svg>),
  compass: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M2 22 C 3.5 16 1.5 5 8 5 C 15 5 14.5 16 9 14.5 C 4.5 13.3 8.5 6.5 14 11 C 19.5 15.5 17 22 11 20.5 C 7.5 19.6 10 13.5 15.5 15.5 C 20 17 21 11 21.5 2"/></svg>),
  whistle: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M21 9 L21 12.5 L16.5 12.5 A5 5 0 1 1 12 9 Z"/><path d="M12 9 L21 9"/><path d="M8 6 7 3.4"/><path d="M11 5.2 11 2.6"/><path d="M14 6 15 3.4"/></svg>),
  target: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><g transform="rotate(40 12 12)"><rect x="9.5" y="3" width="5" height="8" rx="2"/><path d="M9.5 11 12 21 14.5 11Z"/></g></svg>),
  razor: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><g transform="rotate(45 12 12)"><rect x="8" y="2.4" width="8" height="3" rx="1.3"/><path d="M9 5.4 L15 5.4 L17 11 L12 22 L7 11 Z"/><circle cx="12" cy="12" r="1.6"/><path d="M12 13.6 L12 22"/></g></svg>),
  swap: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="4"/><path d="M5.5 21c0-3.6 2.9-6.5 6.5-6.5s6.5 2.9 6.5 6.5"/><path d="M12 7V1.8"/><path d="M10 3.8 12 1.8 14 3.8"/><path d="M6.3 7.5 3.4 4.6"/><path d="M3.4 7.1 3.4 4.6 5.9 4.6"/><path d="M17.7 7.5 20.6 4.6"/><path d="M20.6 7.1 20.6 4.6 18.1 4.6"/></svg>),
  sprout: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M7 20h10"/><path d="M10 20c5.5-2.5.8-6.4 3-10"/><path d="M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z"/><path d="M14.1 6a7 7 0 0 0-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z"/></svg>),
  x: (p) => (<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>),
  play: (p) => (<svg viewBox="0 0 24 24" fill="currentColor" stroke="none" {...p}><path d="M8 5.5v13a1 1 0 0 0 1.52.86l10.5-6.5a1 1 0 0 0 0-1.72L9.52 4.64A1 1 0 0 0 8 5.5z"/></svg>),
};

/* ---- Projects (6, vertical carousel) ---- */
const PROJECTS = [
  {
    slug: "ray-ban-display",
    org: "Meta · Wearables & AR",
    title: "Meta Ray‑Ban Display",
    kicker: "AI Experiences",
    year: "2024 — 2026",
    role: "Design Lead // Manager",
    img: "assets/port/work-arview.jpg",
    video: "assets/meta-rayban-display.mp4",
    tags: ["On-lens HUD", "Proactive AI", "0→1"],
    blurb: "__3 years leading design on a true **world's first**.__ Fashion-forward eyewear that packs a full-color in-lens display, AI assistant, camera, and speakers- all driven by a novel and discreet neural interface.",
    lede: "A display you forget you're wearing. I led design across the first consumer-ready in-lens HUD — proactive, glanceable, and out of the way.",
    facts: [["Role", "Design Lead / Manager"], ["Years", "2024 — 2026"], ["Scope", "End-to-end HUD system"], ["Team", "Design + AI + Hardware"]],
    sections: [
      { h: "The bet", p: "An on-lens display only works if it disappears when you don't need it. The whole system had to feel like a sixth sense, not a screen — surfacing the right glance at the right moment and then getting out of the way." },
      { h: "What I led", p: "A comprehensive surface spanning the assistant, everyday utilities and ambient widgets, designed for legibility on a tiny transparent canvas in any lighting." },
      { h: "The result", p: "A coherent on-lens language now shared across the wearables portfolio — calm typography, motion that respects attention, and interaction models tuned for hands-busy, eyes-up moments." },
    ],
    features: [
      { name: "Navigation & local search - __critically acclaimed hit!__", role: "Led", media: "assets/MRBD_Navigation.mp4" },
      { name: "Meta AI Assistant", role: "Led", media: "assets/MRBD_MetaAI.mp4" },
      { name: "Neural handwriting input", role: "Led", media: "assets/MRBD_Handwriting.mp4" },
      { name: "Teleprompter", role: "Led", media: ["assets/MRBD_Teleprompter0.webp", "assets/MRBD_Teleprompter1.mp4", "assets/MRBD_Teleprompter2.mp4"] },
      { name: "Music, audiobooks & podcasts", role: "Led", media: "assets/MRBD_Music.mp4" },
      { name: "Widgets: sports, weather, stocks, calendar", role: "Led", media: "assets/MRBD_Widgets.mp4" },
    ],
  },
  {
    slug: "ray-ban-meta",
    org: "Meta · AI Glasses",
    title: "Ray‑Ban Meta",
    kicker: "Camera, audio & Meta AI",
    year: "2021 — 2025",
    role: "Design Lead // Manager",
    img: "assets/imagery/render-glass-shape.jpg",
    video: "uploads/RBM Hero Vid Trimmed.mp4",
    tags: ["Multimodal AI", "Capture", "Audio"],
    blurb: "__Our **breakout hit!** I led Design from day-zero.__ First-ever wearable with a built-in multimodal AI assistant. Record sales proved mainstream demand for AI wearables.",
    lede: "The glasses that made wearable AI mainstream. I led design across capture, audio and the multimodal Meta AI assistant.",
    facts: [["Role", "Design Manager"], ["Years", "2021 — 2025"], ["Scope", "Capture · Audio · AI"], ["Reach", "Flagship consumer line"]],
    features: [
      { name: "Custom partnership integrations w/ Spotify, Strava, Apple Music, Amazon Music, Shazam, Audible, Calm and iHeart", role: "Led" },
      { name: "Livestreaming to Instagram", role: "Led" },
      { name: "Turn-by-turn audio navigation", role: "Led" },
      { name: "Video Calling via WhatsApp and Messenger", role: "Led" },
      { name: "Sharing from glasses to Instagram & Facebook", role: "Led" },
      { name: "Automatic media montages, photo & video capture", role: "Led" },
    ],
    sections: [
      { h: "An assistant you talk to", p: "Designing voice-first, screen-less interaction meant rethinking feedback, trust and confirmation entirely — the product had to be understandable with your eyes on the world." },
      { h: "Craft at scale", p: "Every micro-interaction — a capture chime, an LED, a latency budget — shaped how trustworthy the product felt. I led the team that obsessed over those details." },
    ],
  },
  {
    slug: "orion",
    org: "Meta · Reality Labs",
    title: "AR Spatial Web Browser",
    kicker: "North-star wearable",
    year: "2024",
    role: "Design Manager",
    img: "assets/orion-header.jpg",
    tags: ["True AR", "Prototype", "Spatial"],
    blurb: "Widely called the __most advanced AR glasses ever made__, Orion was the first true holographic world-anchored AR experience in an untethered glasses form factor.\n\nI led design for the Spatial Web Browser, charting the first steps toward an ambient internet seamlessly blending with the physical world around you.\n\nOur spatial browser was the __most retentive__ and __most engaging__ feature of the entire device (via usage metrics).",
    lede: "True augmented reality in a form factor you'd actually wear. I helped define the spatial interaction model from concept to working prototype.",
    facts: [["Role", "Design Lead"], ["Years", "2022 — 2024"], ["Scope", "Spatial interaction"], ["Stage", "Concept → prototype"]],
    hideAch: true,
    sections: [
      { h: "Designing for space", p: "Orion meant designing for a canvas with no edges — content anchored to the world, to the body, and to the hand. We built an interaction grammar that felt physical and forgiving." },
      { h: "From concept to prototype", p: "I partnered across hardware, input and AI to turn a north-star vision into something you could put on your face and use — pressure-testing every assumption against real optics and real ergonomics." },
    ],
  },
  {
    slug: "ray-ban-stories",
    org: "Meta · Gen 1",
    title: "Ray‑Ban Stories",
    kicker: "Where it started",
    year: "2021 — 2022",
    role: "Design Manager",
    img: "assets/imagery/devices-card.jpg",
    video: "assets/ray-ban-stories.mp4",
    tags: ["First gen", "Capture", "0→1"],
    blurb: "The smart glasses that started it all. The first collaboration to put dual cameras, open-ear audio, and hands-free capture into genuinely stylish, everyday Ray-Ban frames - proving that fashion-forward was essential in establishing product market fit for this new wearable tech category.\n\nI led design for Media Experiences, founded the Sharing feature team (across Meta), and __shipped Meta's first-ever wearable AI consumer experience__.",
    lede: "Where the category started. I helped establish the capture model and companion experience that the whole line was built on.",
    facts: [["Role", "Design Manager"], ["Years", "2021 — 2022"], ["Scope", "Capture · Companion app"], ["Stage", "0 → 1"]],
    hideAch: true,
    sections: [
      { h: "Defining the basics", p: "First-gen meant inventing the vocabulary: how you capture, how you know it worked, how content moves from glasses to phone. We set defaults that still hold up." },
    ],
  },
  {
    slug: "facebook-groups",
    org: "Meta · Community",
    title: "Facebook Groups",
    kicker: "Community for billions",
    year: "2018 — 2021",
    role: "Design Manager",
    img: "assets/imagery/sculpture-artwork.jpg",
    video: "uploads/Facebook Groups trimmed.mp4",
    videoStart: 0,
    tags: ["1.8B people", "Community", "Leadership"],
    blurb: "Launched and optimized an __entirely new surface within Facebook__, reshaping how more than a __billion people__ find and discover community centered around what makes each of us unique.",
    lede: "Community for nearly two billion people, redesigned around belonging. I grew and led the design team through its biggest era.",
    facts: [["Role", "Design Manager"], ["Years", "2018 — 2021"], ["Scope", "Community product"], ["Reach", "1.8B monthly"]],
    achievements: [
      { metric: "7x", label: "Growth attributed to new design" },
      { metric: "1B", label: "Monthly reach world-wide" },
    ],
    sections: [
      { h: "Belonging at scale", p: "Designing for 1.8 billion people means every change ripples across cultures and contexts. We anchored decisions in belonging, not engagement — and built a team that could hold that standard." },
    ],
  },
  {
    slug: "facebook-ads",
    org: "Meta · Ads Platform",
    title: "Facebook Ads Platform",
    kicker: "The tools that fund the open internet",
    year: "2015 — 2018",
    role: "Staff Product Designer",
    img: "uploads/722shots_so.png",
    video: "uploads/256_720x30_shots_so.mp4",
    noLoop: true,
    tags: ["Enterprise", "Systems", "Scale"],
    blurb: "Built measurement tools to help businesses find the causal effect of their ad spend, debunking proxy metrics that fueled the AdTech industry. Giving __superpowers__ to your favorite boutique, restaurant or brand; helping them __discover actionable insights__ to grow their business.",
    lede: "The tools that fund the open internet. I owned advertiser surfaces across campaign creation, targeting and measurement.",
    facts: [["Role", "Sr. Product Designer"], ["Years", "2015 — 2018"], ["Scope", "Advertiser surfaces"], ["Domain", "Enterprise complexity"]],
    features: [
      { name: "Conversion Lift — redesigned complex data science tools to be broadly accessible", role: "Led" },
      { name: "Redesigned account creation, __eliminating 400,000 fraudulent impressions__ per month", role: "Led" },
      { name: "Cross-platform reach and frequency tools", role: "Led" },
      { name: "Facebook's 1st Political Ads format", role: "Led" },
    ],
    sections: [
      { h: "Enterprise complexity, simplified", p: "Dense, high-stakes workflows for professionals who live in the tool all day. I learned to simplify ferocious complexity without dumbing it down — a skill that's been in my DNA ever since." },
    ],
  },
  {
    slug: "before-meta",
    kind: "before",
    img: "uploads/BeforeMeta.png",
    org: "Earlier career",
    title: "Before Meta",
    kicker: "Where it began",
    year: "Before 2015",
    blurb: "My career took off at the dawn of smart phones, a wild west of design experiments trying to understand the most intuitive patterns for humans to interact with this new computing platform.\n\nSince then, I've also had the opportunity to serve as the top design leader for successful startups; collaboratively and strategically influencing key product decisions we bet the entire company on.",
    companies: [
      { name: "Inside Social", sub: "Organic social attribution startup", role: "Head of Design", years: "20XX — 20XX", logo: "assets/inside-social.svg" },
      { name: "Capital One", sub: "Consumer banking app", role: "Sr. Product Designer", years: "20XX — 20XX", logo: "assets/capone.svg" },
      { name: "Adaptive Data", sub: "Machine learning startup", role: "Principal Designer", years: "20XX — 20XX", logo: "assets/adaptive-data.svg" },
      { name: "T-Mobile", sub: "Launched some of the first flagship devices of the mobile computing era", role: "Sr. Product Designer", years: "20XX — 20XX", logo: "assets/tmo.svg" },
    ],
  },
];

/* ---- Inline SVG (fetch + inject so currentColor works; mask-image is
   unreliable in this sandbox). Cached + prefetched. ---- */
const __svgCache = {};
function prefetchSvg(src) {
  if (__svgCache[src]) return __svgCache[src];
  __svgCache[src] = fetch(src).then((r) => r.text()).then((txt) => {
    // normalize: fill currentColor, fluid sizing
    txt = txt.replace(/\swidth="[^"]*"/, "").replace(/\sheight="[^"]*"/, "");
    txt = txt.replace("<svg ", '<svg preserveAspectRatio="xMidYMid meet" style="width:100%;height:100%;display:block" ');
    return txt;
  }).catch(() => "");
  return __svgCache[src];
}
["assets/port/kevin-display.svg", "assets/port/logo-kevin.svg", "assets/port/logo-charboneau.svg"].forEach(prefetchSvg);

function InlineSvg({ src, className, style, label }) {
  const [html, setHtml] = useState(__svgCache[src] && __svgCache[src].__resolved || "");
  useEffect(() => {
    let alive = true;
    prefetchSvg(src).then((t) => { if (alive) setHtml(t); });
    return () => { alive = false; };
  }, [src]);
  return (
    <span className={className} style={style} role={label ? "img" : "presentation"}
      aria-label={label || undefined} aria-hidden={label ? undefined : true}
      dangerouslySetInnerHTML={{ __html: html }} />
  );
}

/* ---- Scroll reveal: visible at rest, animate in when entering view ---- */
function useReveal(dep) {
  useEffect(() => {
    const vh = () => window.innerHeight || 800;
    // Reveal any element once its top crosses 92% of the viewport. A plain
    // scroll check (rAF-throttled) is used instead of IntersectionObserver
    // because IO can miss elements on fast scrolls / programmatic jumps,
    // which left sections (e.g. Achievements) stuck at opacity:0.
    const check = () => {
      const limit = vh() * 0.92;
      document.querySelectorAll(".reveal:not(.is-in)").forEach((e) => {
        if (e.getBoundingClientRect().top < limit) e.classList.add("is-in");
      });
    };
    check();
    let raf = 0;
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(() => { raf = 0; check(); }); };
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    // Re-check after layout settles (pinned carousel changes page height).
    const t = setTimeout(check, 150);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      clearTimeout(t);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [dep]);
}

Object.assign(window, { Icon, PROJECTS, useReveal, InlineSvg });
