
const { useState, useEffect, useLayoutEffect, useRef, useCallback } = React;

const INK = "#1d1d1f";
const SLATE = "#6e6e73";
const BG = "#ffffff";
const ACCENT = "#0071e3";
const BORDER = "#d2d2d7";
const SF =
  '"Avenir Next", -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Helvetica, Arial, sans-serif';

const RESUME_URL =
  "https://drive.google.com/file/d/1rG79K9M5a8J8Gx1czumg1dPcMSFCxkp_/view?usp=sharing";
const CONTACT_EMAIL = "jwaliman@uw.edu";
const LINKEDIN_URL = "https://linkedin.com/in/josephinewaliman";
/** Pacific — same civil offset as Seattle. */
const FOOTER_TIME_ZONE = "America/Los_Angeles";
const FOOTER_CLOCK_PLACE = "Seattle";

/** Floating nav — equal space above/below glass chip; keep in sync with site-design-system.css */
const SITE_NAV_FLOAT_PAD_PX = 9;
const SITE_NAV_CHIP_PAD_Y_PX = 8;
const SITE_NAV_ROW_MIN_PX = 52;
const SITE_NAV_TOTAL_PX =
  SITE_NAV_FLOAT_PAD_PX +
  SITE_NAV_CHIP_PAD_Y_PX +
  SITE_NAV_ROW_MIN_PX +
  SITE_NAV_CHIP_PAD_Y_PX +
  SITE_NAV_FLOAT_PAD_PX;
/** Header primary links + footer chrome (keep in sync with `--ds-text-nav` in site-design-system.css) */
const SITE_CHROME_FONT_PX = 17;

function buildNavLinks(bp) {
  const workHrefClean = `${bp}index.html#work`;
  const aboutHref = `${bp}about.html`;
  return [
    { kind: "work", label: "Work", href: workHrefClean, active: () => isHomePage() || isWorkCasePage() },
    { kind: "link", label: "About", href: aboutHref, active: () => isAboutPage() },
    {
      kind: "resume",
      label: "Resume",
      href: RESUME_URL,
      external: true,
      active: () => false,
    },
  ];
}

function IconExternalUpRight() {
  return (
    <svg width="13" height="13" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden style={{ display: "inline-block", verticalAlign: "0.08em", marginLeft: 5 }}>
      <path d="M1.5 10.5L10.5 1.5M10.5 1.5H4M10.5 1.5V8" stroke="currentColor" strokeWidth="1.35" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function IconChevronLeft() {
  return (
    <svg width="17" height="17" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden style={{ flexShrink: 0 }}>
      <path d="M7.25 2.25L3.25 6l4 3.75" stroke="currentColor" strokeWidth="1.35" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function normalizedPath() {
  return (location.pathname || "").replace(/\\/g, "/");
}

function currentFilename() {
  const segs = normalizedPath().split("/").filter(Boolean);
  return segs.length ? segs[segs.length - 1].toLowerCase() : "";
}

function isHomePage() {
  const f = currentFilename();
  return f === "index.html" || f === "";
}

function isAboutPage() {
  const f = currentFilename();
  return f === "about.html" || f === "about";
}

function isWorkCasePage() {
  const p = normalizedPath();
  if (/(^|\/)work\/[^/]+\.html$/i.test(p)) return true;
  const m = p.match(/\/work\/([^/?#]+)$/i);
  return !!(m && m[1] && !m[1].includes("."));
}

/** Full floating nav (Back + Work / About / Resume). Google Maps and other case studies may stay compact. */
function isWideCaseStudyNavPage() {
  if (!isWorkCasePage()) return false;
  const f = currentFilename();
  return (
    f === "nimbus.html" ||
    f === "nimbus" ||
    f === "penni.html" ||
    f === "penni" ||
    f === "grab-a-seat.html" ||
    f === "grab-a-seat"
  );
}

function IconMail() {
  return (
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden>
      <rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" strokeWidth="1.5" />
      <path d="M3 7l9 6 9-6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function IconLinkedIn() {
  return (
    <svg width="22" height="22" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden>
      <path
        fill="currentColor"
        d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
      />
    </svg>
  );
}

function goToWorkSection(e) {
  if (!isHomePage()) return;
  e.preventDefault();
  const el = document.getElementById("work");
  if (el) el.scrollIntoView({ behavior: "smooth" });
  let path = location.pathname.replace(/\/?index\.html$/i, "/");
  if (path === "//") path = "/";
  if (path !== "/" && !path.endsWith("/")) path += "/";
  history.replaceState(null, "", path + location.search);
}

function hourInTimeZone(date, timeZone) {
  const parts = new Intl.DateTimeFormat("en-US", {
    timeZone,
    hour: "numeric",
    hour12: false,
  }).formatToParts(date);
  const h = parts.find((p) => p.type === "hour");
  return h ? parseInt(h.value, 10) : 0;
}

/** Sun vs moon follows civil day/night in the footer timezone (reference-style). */
function isFooterDayIcon(date, timeZone) {
  const h = hourInTimeZone(date, timeZone);
  return h >= 7 && h < 19;
}

function formatFooterClockLine(date, timeZone, place) {
  const time = date.toLocaleTimeString("en-US", {
    hour: "numeric",
    minute: "2-digit",
    hour12: true,
    timeZone,
  });
  return `${time}, ${place}`;
}

/** Tiny corner-arrow on email hover (liumichelle.com footer). */
function IconEmailCornerArrow() {
  return (
    <svg width="0.55em" height="0.55em" viewBox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden style={{ verticalAlign: "0.06em", display: "inline-block" }}>
      <path d="M0.928172 8.30395L0.0001719 7.35995L7.04017 0.319951L7.98417 1.26395L0.928172 8.30395ZM1.96817 1.35995V-4.95911e-05H8.30417L7.80817 1.34395L1.96817 1.35995ZM6.94417 6.33595L6.96017 0.479951L8.30417 -4.95911e-05V6.33595H6.94417Z" fill="currentColor" />
    </svg>
  );
}

/** LinkedIn — iOS-style app icon (squircle + brand blue). */
function IconLinkedInFooter() {
  return (
    <svg width="40" height="40" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden className="mlf-social-svg mlf-social-svg--linkedin">
      <rect width="24" height="24" rx="5.375" fill="#0A66C2" />
      <path fill="#fff" fillRule="evenodd" clipRule="evenodd" d="M8 7.2c-.83 0-1.5.67-1.5 1.5S7.17 10.2 8 10.2s1.5-.67 1.5-1.5S8.83 7.2 8 7.2Zm-1.38 3.4h2.77v7.4H6.62v-7.4Zm4.23 0h2.65v1.01h.04c.37-.7 1.27-1.44 2.62-1.44 2.8 0 3.32 1.85 3.32 4.25v3.57h-2.77v-3.35c0-1-.02-2.29-1.4-2.29-1.4 0-1.61 1.1-1.61 2.23v3.41h-2.77v-7.39Z" />
    </svg>
  );
}

function IconSun() {
  return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden>
      <circle cx="12" cy="12" r="4" stroke="currentColor" strokeWidth="1.4" />
      <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" />
    </svg>
  );
}

function IconMoon() {
  return (
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden>
      <path d="M21 14.5A8.5 8.5 0 0110.5 4 8.5 8.5 0 0012 21a8.5 8.5 0 009-6.5z" stroke="currentColor" strokeWidth="1.35" strokeLinejoin="round" />
    </svg>
  );
}

async function copyTextToClipboard(text) {
  try {
    if (navigator.clipboard && window.isSecureContext) {
      await navigator.clipboard.writeText(text);
      return true;
    }
    const ta = document.createElement("textarea");
    ta.value = text;
    ta.setAttribute("readonly", "");
    ta.style.position = "fixed";
    ta.style.left = "-9999px";
    document.body.appendChild(ta);
    ta.select();
    const ok = document.execCommand("copy");
    document.body.removeChild(ta);
    return ok;
  } catch (_) {
    return false;
  }
}

function GlobalNav({ basePath = "" }) {
  const [scrolled, setScrolled] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const [hoverIndex, setHoverIndex] = useState(null);
  const [pill, setPill] = useState({ left: 0, top: 0, width: 0, height: 0 });
  const [overlayPill, setOverlayPill] = useState({
    left: 0,
    top: 0,
    width: 0,
    height: 0,
    opacity: 0,
  });
  const [readProgress, setReadProgress] = useState(0);
  const wrapRef = useRef(null);
  const itemRefs = useRef([]);
  const overlayWrapRef = useRef(null);
  const overlayItemRefs = useRef([]);
  const targetIndexRef = useRef(0);
  const bp = basePath || "";
  const onCaseStudy = isWorkCasePage();
  const caseStudyCompactNav = onCaseStudy && !isWideCaseStudyNavPage();

  useEffect(() => {
    const onScroll = () => {
      setScrolled(window.scrollY > SITE_NAV_ROW_MIN_PX * 0.65);
      if (!isWorkCasePage()) return;
      const doc = document.documentElement;
      const maxScroll = doc.scrollHeight - window.innerHeight;
      let pct = 100;
      if (maxScroll > 1) {
        pct = Math.min(100, Math.max(0, (window.scrollY / maxScroll) * 100));
      } else {
        pct = window.scrollY > 0 ? 100 : 0;
      }
      setReadProgress(pct);
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
    };
  }, []);

  useEffect(() => {
    document.body.style.overflow = menuOpen ? "hidden" : "";
    return () => { document.body.style.overflow = ""; };
  }, [menuOpen]);

  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") setMenuOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const links = buildNavLinks(bp);

  const activeIndex = links.findIndex((l) => l.active());
  const fallbackActive = activeIndex >= 0 ? activeIndex : 0;
  const targetIndex = hoverIndex !== null ? hoverIndex : fallbackActive;
  targetIndexRef.current = targetIndex;

  const syncPill = useCallback(() => {
    const wrap = wrapRef.current;
    const idx = targetIndexRef.current;
    const el = itemRefs.current[idx];
    if (!wrap || !el) return;
    const wr = wrap.getBoundingClientRect();
    const r = el.getBoundingClientRect();
    setPill({
      left: r.left - wr.left,
      top: r.top - wr.top,
      width: r.width,
      height: r.height,
    });
  }, []);

  const syncOverlayPill = useCallback(() => {
    if (!menuOpen || caseStudyCompactNav) {
      setOverlayPill({ left: 0, top: 0, width: 0, height: 0, opacity: 0 });
      return;
    }
    const wrap = overlayWrapRef.current;
    const idx = targetIndexRef.current;
    const el = overlayItemRefs.current[idx];
    if (!wrap || !el) return;
    const wr = wrap.getBoundingClientRect();
    const r = el.getBoundingClientRect();
    setOverlayPill({
      left: r.left - wr.left,
      top: r.top - wr.top,
      width: r.width,
      height: r.height,
      opacity: r.width > 0 ? 1 : 0,
    });
  }, [menuOpen, caseStudyCompactNav]);

  useLayoutEffect(() => {
    const id = requestAnimationFrame(() => syncPill());
    return () => cancelAnimationFrame(id);
  }, [targetIndex, bp, syncPill]);

  useLayoutEffect(() => {
    if (!menuOpen) {
      const id = requestAnimationFrame(() => syncPill());
      return () => cancelAnimationFrame(id);
    }
  }, [menuOpen, syncPill]);

  useEffect(() => {
    const wrap = wrapRef.current;
    if (!wrap || typeof ResizeObserver === "undefined") return undefined;
    const ro = new ResizeObserver(() => syncPill());
    ro.observe(wrap);
    window.addEventListener("resize", syncPill);
    return () => {
      ro.disconnect();
      window.removeEventListener("resize", syncPill);
    };
  }, [syncPill]);

  useLayoutEffect(() => {
    if (!menuOpen || caseStudyCompactNav) return;
    const id = requestAnimationFrame(() => syncOverlayPill());
    return () => cancelAnimationFrame(id);
  }, [menuOpen, targetIndex, bp, caseStudyCompactNav, syncOverlayPill]);

  useEffect(() => {
    const wrap = overlayWrapRef.current;
    if (!wrap || !menuOpen || caseStudyCompactNav || typeof ResizeObserver === "undefined") return undefined;
    const ro = new ResizeObserver(() => syncOverlayPill());
    ro.observe(wrap);
    window.addEventListener("resize", syncOverlayPill);
    syncOverlayPill();
    return () => {
      ro.disconnect();
      window.removeEventListener("resize", syncOverlayPill);
    };
  }, [menuOpen, caseStudyCompactNav, syncOverlayPill]);

  const chipBg = scrolled
    ? "rgba(252, 252, 254, 0.88)"
    : "rgba(255, 255, 255, 0.58)";
  const chipBorder = scrolled
    ? "1px solid rgba(210, 210, 215, 0.72)"
    : "1px solid rgba(255, 255, 255, 0.95)";
  const chipShadow = scrolled
    ? "0 14px 46px rgba(20, 42, 62, 0.11), 0 3px 14px rgba(0, 0, 0, 0.06), inset 0 1px 0 rgba(255, 255, 255, 0.92)"
    : "0 10px 40px rgba(20, 42, 62, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04), inset 0 1px 0 rgba(255, 255, 255, 0.85)";

  return (
    <React.Fragment>
      <style>{`
        .gnav-shell {
          pointer-events: none;
        }
        .gnav-shell .gnav-chip,
        .gnav-shell .gnav-inner,
        .gnav-shell a,
        .gnav-shell button {
          pointer-events: auto;
        }
        .gnav-chip {
          position: relative;
          display: inline-flex;
          align-items: center;
          box-sizing: border-box;
          backdrop-filter: blur(22px) saturate(180%);
          -webkit-backdrop-filter: blur(22px) saturate(180%);
          transition:
            background 0.32s cubic-bezier(0.25, 0.1, 0.25, 1),
            border-color 0.32s ease,
            box-shadow 0.32s ease;
        }
        .gnav-chip--wide {
          width: min(920px, calc(100vw - 2 * max(1.25rem, min(5vw, 4rem))));
        }
        .gnav-chip--tight {
          width: auto;
          max-width: calc(100vw - 2 * max(1.25rem, min(5vw, 4rem)));
        }
        .gnav-inner {
          width: 100%;
          display: flex;
          align-items: center;
          justify-content: center;
          position: relative;
          padding: 0 clamp(10px, 1.8vw, 22px);
          box-sizing: border-box;
          min-height: ${SITE_NAV_ROW_MIN_PX}px;
        }
        .gnav-links {
          position: relative;
          display: flex;
          gap: 10px;
          align-items: center;
          justify-content: center;
        }
        .gnav-pill {
          position: absolute;
          z-index: 0;
          border-radius: 9999px;
          background: rgba(0, 0, 0, 0.075);
          pointer-events: none;
          transition:
            left 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            width 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            top 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            height 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            opacity 0.2s ease;
        }
        @media (prefers-reduced-motion: reduce) {
          .gnav-pill { transition-duration: 0.01ms !important; }
        }
        .gnav-link-slot { position: relative; z-index: 1; }
        .gnav-hamburger { display: none; position: absolute; right: clamp(6px, 1.2vw, 14px); top: 50%; transform: translateY(-50%); }
        .gnav-overlay-links-wrap {
          position: relative;
          display: flex;
          flex-direction: column;
          align-items: stretch;
          gap: 16px;
          min-width: min(280px, calc(100vw - 48px));
        }
        .gnav-overlay-pill {
          position: absolute;
          z-index: 0;
          border-radius: 9999px;
          background: rgba(0, 0, 0, 0.075);
          pointer-events: none;
          transition:
            left 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            width 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            top 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            height 0.28s cubic-bezier(0.25, 0.1, 0.25, 1),
            opacity 0.2s ease;
        }
        .gnav-overlay-row {
          position: relative;
          z-index: 1;
        }
        @media (prefers-reduced-motion: reduce) {
          .gnav-overlay-pill { transition-duration: 0.01ms !important; }
        }
        @media (max-width: 768px) {
          .gnav-links { display: none; }
          .gnav-hamburger {
            display: flex !important;
            position: fixed !important;
            top: max(10px, env(safe-area-inset-top, 0px));
            right: max(12px, env(safe-area-inset-right, 0px));
            left: auto !important;
            transform: none !important;
            z-index: 1002;
          }
          .gnav-inner { padding: 0 clamp(8px, 2vw, 16px) !important; }
          .gnav-inner--case { padding-right: clamp(8px, 2vw, 16px) !important; }
          .gnav-chip--wide {
            width: min(100vw - 2 * max(1rem, min(4vw, 1.5rem)), calc(100vw - 2 * max(1.25rem, min(5vw, 4rem))));
          }
        }
        @media (min-width: 769px) and (max-width: 1024px) {
          .gnav-inner { padding: 0 clamp(14px, 2.2vw, 20px) !important; }
        }
        .gnav-link:focus-visible {
          outline: 2px solid ${ACCENT};
          outline-offset: 2px;
          border-radius: 9999px;
        }
        .gnav-overlay-link:focus-visible {
          outline: 2px solid ${ACCENT};
          outline-offset: 4px;
          border-radius: 2px;
        }
        .gnav-inner--case {
          justify-content: flex-start;
        }
        .gnav-inner--case .gnav-links {
          position: absolute;
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
        }
        .gnav-back-slot {
          flex-shrink: 0;
          display: flex;
          align-items: center;
          margin-right: 6px;
        }
        .gnav-back {
          display: inline-flex;
          align-items: center;
          gap: 8px;
          font-family: ${SF};
          font-size: ${SITE_CHROME_FONT_PX}px;
          font-weight: 500;
          letter-spacing: -0.014em;
          color: #86868b;
          text-decoration: none;
          padding: 10px 14px 10px 10px;
          border-radius: 9999px;
          transition: color 0.2s ease, background 0.2s ease;
          z-index: 5;
          position: relative;
        }
        .gnav-back:hover {
          color: ${INK};
          background: rgba(0, 0, 0, 0.045);
        }
        .gnav-back:focus-visible {
          outline: 2px solid ${ACCENT};
          outline-offset: 2px;
          border-radius: 9999px;
        }
        .gnav-read-progress {
          position: absolute;
          left: 14px;
          right: 14px;
          bottom: 8px;
          height: 2px;
          pointer-events: none;
          z-index: 6;
          background: rgba(0, 0, 0, 0.055);
          border-radius: 9999px;
          overflow: hidden;
        }
        .gnav-read-progress__fill {
          height: 100%;
          width: 0%;
          max-width: 100%;
          border-radius: 9999px;
          background: linear-gradient(
            90deg,
            rgba(0, 113, 227, 0.42) 0%,
            rgba(130, 185, 225, 0.5) 45%,
            rgba(27, 77, 62, 0.48) 100%
          );
          box-shadow: 0 0 12px rgba(0, 113, 227, 0.15);
          transition: width 0.14s ease-out;
        }
        @media (prefers-reduced-motion: reduce) {
          .gnav-read-progress__fill { transition: none; }
        }
      `}</style>

      <nav
        className="gnav-shell"
        style={{
          position: "fixed",
          top: 0,
          left: 0,
          width: "100%",
          minHeight: SITE_NAV_TOTAL_PX,
          paddingTop: SITE_NAV_FLOAT_PAD_PX,
          paddingBottom: SITE_NAV_FLOAT_PAD_PX,
          height: "auto",
          zIndex: 1000,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          background: "transparent",
          boxSizing: "border-box",
        }}
      >
        <div
          className={
            "gnav-chip" +
            (onCaseStudy && !caseStudyCompactNav ? " gnav-chip--wide" : " gnav-chip--tight")
          }
          style={{
            paddingTop: SITE_NAV_CHIP_PAD_Y_PX,
            paddingBottom: SITE_NAV_CHIP_PAD_Y_PX,
            paddingLeft: 4,
            paddingRight: 4,
            borderRadius: 9999,
            background: chipBg,
            border: chipBorder,
            boxShadow: chipShadow,
          }}
        >
          <div className={"gnav-inner" + (onCaseStudy ? " gnav-inner--case" : "")}>
            {onCaseStudy ? (
              <div className="gnav-back-slot">
                <a href={`${bp}index.html#work`} className="gnav-back">
                  <IconChevronLeft />
                  Back
                </a>
              </div>
            ) : null}
            {!caseStudyCompactNav ? (
              <React.Fragment>
                <div
                  ref={wrapRef}
                  className="gnav-links"
                  onMouseLeave={() => setHoverIndex(null)}
                >
                  <div
                    className="gnav-pill"
                    aria-hidden
                    style={{
                      left: pill.left,
                      top: pill.top,
                      width: pill.width,
                      height: pill.height,
                      opacity: pill.width > 0 ? 1 : 0,
                    }}
                  />
                  {links.map((link, i) => {
                    const emphasized = targetIndex === i;
                    const linkStyle = {
                      fontFamily: SF,
                      fontSize: SITE_CHROME_FONT_PX,
                      fontWeight: 500,
                      letterSpacing: "-0.014em",
                      color: emphasized ? INK : "#86868b",
                      textDecoration: "none",
                      padding: "11px 22px",
                      borderRadius: 9999,
                      transition: "color 0.22s cubic-bezier(0.25, 0.1, 0.25, 1)",
                      display: "inline-flex",
                      alignItems: "center",
                      position: "relative",
                      zIndex: 1,
                    };
                    if (link.kind === "resume") {
                      return (
                        <span key="resume" className="gnav-link-slot">
                          <a
                            href={link.href}
                            className="gnav-link"
                            target="_blank"
                            rel="noopener noreferrer"
                            ref={(node) => { itemRefs.current[i] = node; }}
                            style={linkStyle}
                            onMouseEnter={() => setHoverIndex(i)}
                          >
                            {link.label}
                            <IconExternalUpRight />
                          </a>
                        </span>
                      );
                    }
                    if (link.kind === "work") {
                      return (
                        <span key="work" className="gnav-link-slot">
                          <a
                            href={link.href}
                            className="gnav-link"
                            ref={(node) => { itemRefs.current[i] = node; }}
                            onClick={goToWorkSection}
                            style={linkStyle}
                            onMouseEnter={() => setHoverIndex(i)}
                          >{link.label}</a>
                        </span>
                      );
                    }
                    return (
                      <span key={link.label} className="gnav-link-slot">
                        <a
                          href={link.href}
                          className="gnav-link"
                          ref={(node) => { itemRefs.current[i] = node; }}
                          style={linkStyle}
                          onMouseEnter={() => setHoverIndex(i)}
                        >{link.label}</a>
                      </span>
                    );
                  })}
                </div>

                <button className="gnav-hamburger gnav-link"
                  type="button"
                  onClick={() => {
                    setHoverIndex(null);
                    setMenuOpen(true);
                  }}
                  aria-label="Open navigation"
                  aria-expanded={menuOpen}
                  style={{
                    background: "none", border: "none", cursor: "pointer",
                    padding: "13px", display: "none",
                    flexDirection: "column", gap: 4, alignItems: "center",
                    justifyContent: "center", width: 44, height: 44, borderRadius: 4,
                  }}>
                  {[0,1,2].map(i => (
                    <span key={i} style={{ width: 18, height: 1.5, background: INK, display: "block" }} />
                  ))}
                </button>
              </React.Fragment>
            ) : null}
            {onCaseStudy && !isWideCaseStudyNavPage() ? (
              <div
                className="gnav-read-progress"
                role="progressbar"
                aria-valuemin={0}
                aria-valuemax={100}
                aria-valuenow={Math.round(readProgress)}
                aria-label="Progress through this case study"
              >
                <div className="gnav-read-progress__fill" style={{ width: `${readProgress}%` }} />
              </div>
            ) : null}
          </div>
        </div>
      </nav>

      {menuOpen && (
        <div style={{
          position: "fixed", inset: 0, zIndex: 1100,
          background: "rgba(255,255,255,0.82)",
          backdropFilter: "blur(24px) saturate(180%)",
          WebkitBackdropFilter: "blur(24px) saturate(180%)",
          display: "flex", flexDirection: "column",
          alignItems: "center", justifyContent: "center",
          animation: "fadeInDown 250ms ease-out forwards",
        }}>
          <style>{`
            @keyframes fadeInDown {
              from { opacity:0; transform: translateY(-8px); }
              to   { opacity:1; transform: translateY(0); }
            }
          `}</style>
          <button type="button" onClick={() => setMenuOpen(false)}
            aria-label="Close navigation"
            style={{
              position: "fixed",
              top: "max(10px, env(safe-area-inset-top, 0px))",
              right: "max(12px, env(safe-area-inset-right, 0px))",
              width: 44, height: 44, background: "none", border: "none",
              cursor: "pointer", fontSize: 18, color: INK,
              display: "flex", alignItems: "center", justifyContent: "center",
              borderRadius: 4,
              zIndex: 1101,
            }}>✕</button>
          <div style={{ display: "flex", flexDirection: "column", gap: 48, alignItems: "center" }}>
            {onCaseStudy ? (
              <a
                href={`${bp}index.html#work`}
                className="gnav-overlay-link"
                onClick={() => setMenuOpen(false)}
                style={{
                  fontFamily: SF,
                  fontWeight: 600,
                  fontSize: 26,
                  letterSpacing: "-0.02em",
                  color: INK,
                  textDecoration: "none",
                  display: "inline-flex",
                  alignItems: "center",
                  gap: 8,
                }}
              >
                <IconChevronLeft />
                Back
              </a>
            ) : null}
            {!caseStudyCompactNav ? (
              <div
                ref={overlayWrapRef}
                className="gnav-overlay-links-wrap"
                onMouseLeave={() => setHoverIndex(null)}
              >
                <div
                  className="gnav-overlay-pill"
                  aria-hidden
                  style={{
                    left: overlayPill.left,
                    top: overlayPill.top,
                    width: overlayPill.width,
                    height: overlayPill.height,
                    opacity: overlayPill.opacity,
                  }}
                />
                {links.map((link, i) => {
                  const emphasized = targetIndex === i;
                  const rowStyle = {
                    padding: "14px 28px",
                    borderRadius: 9999,
                    alignSelf: "center",
                  };
                  const anchorBase = {
                    fontFamily: SF,
                    fontWeight: 600,
                    fontSize: 26,
                    letterSpacing: "-0.02em",
                    color: emphasized ? INK : "#86868b",
                    textDecoration: "none",
                    transition: "color 0.22s cubic-bezier(0.25, 0.1, 0.25, 1)",
                    display: "inline-flex",
                    alignItems: "center",
                    gap: 6,
                  };
                  const rowHandlers = {
                    onMouseEnter: () => setHoverIndex(i),
                    onFocus: () => setHoverIndex(i),
                  };
                  if (link.kind === "resume") {
                    return (
                      <div
                        key="resume"
                        className="gnav-overlay-row"
                        style={rowStyle}
                        ref={(node) => { overlayItemRefs.current[i] = node; }}
                        {...rowHandlers}
                      >
                        <a href={link.href} className="gnav-overlay-link"
                          target="_blank"
                          rel="noopener noreferrer"
                          onClick={() => setMenuOpen(false)}
                          style={anchorBase}
                        >
                          {link.label}
                          <IconExternalUpRight />
                        </a>
                      </div>
                    );
                  }
                  if (link.kind === "work") {
                    return (
                      <div
                        key="work"
                        className="gnav-overlay-row"
                        style={rowStyle}
                        ref={(node) => { overlayItemRefs.current[i] = node; }}
                        {...rowHandlers}
                      >
                        <a href={link.href} className="gnav-overlay-link"
                          onClick={(e) => { goToWorkSection(e); setMenuOpen(false); }}
                          style={{ ...anchorBase, gap: 0 }}
                        >{link.label}</a>
                      </div>
                    );
                  }
                  return (
                    <div
                      key={link.label}
                      className="gnav-overlay-row"
                      style={rowStyle}
                      ref={(node) => { overlayItemRefs.current[i] = node; }}
                      {...rowHandlers}
                    >
                      <a href={link.href} className="gnav-overlay-link"
                        onClick={() => setMenuOpen(false)}
                        style={{ ...anchorBase, gap: 0 }}
                      >{link.label}</a>
                    </div>
                  );
                })}
              </div>
            ) : null}
          </div>
        </div>
      )}
    </React.Fragment>
  );
}


function GlobalFooter({ basePath = "" }) {
  const bp = basePath || "";
  const homeHref = `${bp}index.html`;
  const [now, setNow] = useState(() => new Date());

  useEffect(() => {
    setNow(new Date());
    const id = setInterval(() => setNow(new Date()), 15000);
    return () => clearInterval(id);
  }, []);

  const showDayIcon = isFooterDayIcon(now, FOOTER_TIME_ZONE);
  const clockLine = formatFooterClockLine(now, FOOTER_TIME_ZONE, FOOTER_CLOCK_PLACE);
  const headerNavLinks = buildNavLinks(bp);

  return (
    <footer
      className="mlf-root"
      style={{
        position: "relative",
        zIndex: 20,
        width: "100%",
        background: BG,
        boxSizing: "border-box",
      }}
    >
      <style>{`
        .mlf-root { --mlf-gray-400: #9ca3af; --mlf-gray-500: #6b7280; --mlf-gray-600: #4b5563; --mlf-brand: #374151; --mlf-locale: #b5bcc5; }
        .mlf-inner {
          max-width: var(--ds-shell-max);
          margin: 0 auto;
          padding: 28px var(--ds-page-pad-x) 40px;
          box-sizing: border-box;
        }
        @media (min-width: 769px) {
          .mlf-inner { padding: 28px var(--ds-page-pad-x) 56px; }
        }
        .mlf-grid {
          display: grid;
          grid-template-columns: repeat(4, minmax(0, 1fr));
          gap: 20px;
          width: 100%;
          align-items: start;
        }
        @media (max-width: 768px) {
          .mlf-grid {
            display: flex;
            flex-direction: column;
            gap: 28px;
            align-items: flex-start;
          }
          .mlf-col-spacer { display: none !important; }
          .mlf-col-brand { order: 1; }
          .mlf-col-contact { order: 2; }
          .mlf-col-nav { order: 3; }
        }
        .mlf-brand {
          display: inline-flex;
          align-items: baseline;
          text-decoration: none;
          transition: opacity 0.2s ease;
        }
        .mlf-brand:hover { opacity: 0.8; }
        .mlf-brand-names {
          font-family: ${SF};
          font-weight: 500;
          font-size: clamp(1.75rem, 3.5vw, 2.3625rem);
          letter-spacing: -0.035em;
          line-height: 1;
          color: var(--mlf-brand);
          margin: 0;
          text-transform: lowercase;
          display: flex;
          flex-direction: row;
          flex-wrap: nowrap;
          align-items: baseline;
          gap: 0.28em;
          white-space: nowrap;
          font-variation-settings: normal;
        }
        .mlf-brand-word {
          flex-shrink: 0;
        }
        .mlf-clock-row {
          display: flex;
          flex-direction: row;
          align-items: center;
          gap: 10px;
          margin-top: 14px;
          padding: 0;
          margin-bottom: 0;
          margin-left: 0;
          margin-right: 0;
          font-family: ${SF};
          font-size: var(--ds-text-nav);
          font-weight: 400;
          line-height: calc(var(--ds-text-nav) * 1.35);
          color: var(--mlf-locale);
          font-variant-numeric: tabular-nums;
        }
        .mlf-clock-icon {
          display: inline-flex;
          flex-shrink: 0;
          color: inherit;
        }
        .mlf-clock-icon svg {
          display: block;
          width: calc(var(--ds-text-nav) + 1px);
          height: calc(var(--ds-text-nav) + 1px);
        }
        .mlf-clock-text {
          flex: 0 1 auto;
        }
        .mlf-col-nav {
          display: flex;
          flex-direction: column;
          gap: 8px;
          align-items: flex-start;
        }
        .mlf-nav-link {
          font-family: ${SF};
          font-size: var(--ds-text-nav);
          font-weight: 500;
          letter-spacing: -0.014em;
          line-height: 1.25rem;
          color: #86868b;
          text-decoration: none;
          padding: 2px 4px;
          margin: 0 -4px;
          border-radius: 999px;
          transition: color 0.2s ease;
          white-space: nowrap;
        }
        .mlf-nav-link--ink { color: ${INK}; }
        .mlf-nav-link:hover { color: #3b82f6; }
        .mlf-nav-link:focus-visible {
          outline: 2px solid ${ACCENT};
          outline-offset: 2px;
        }
        .mlf-col-contact {
          display: flex;
          flex-direction: column;
          gap: 16px;
          align-items: flex-end;
          text-align: right;
        }
        @media (max-width: 768px) {
          .mlf-col-contact {
            align-items: flex-start;
            text-align: left;
            width: 100%;
          }
        }
        .mlf-lead {
          font-family: ${SF};
          font-size: var(--ds-text-nav);
          font-weight: 400;
          line-height: calc(var(--ds-text-nav) * 1.35);
          color: #9ca3af;
          margin: 0;
        }
        .mlf-email-wrap {
          margin: 0;
          line-height: 1.5rem;
        }
        .mlf-email {
          font-family: ${SF};
          font-size: var(--ds-text-nav);
          font-weight: 500;
          color: var(--mlf-gray-600);
          text-decoration: none;
          word-break: break-all;
          transition: color 0.2s ease;
          display: inline-flex;
          align-items: baseline;
          flex-wrap: wrap;
          gap: 0;
        }
        .mlf-email:hover { color: #3b82f6; }
        .mlf-email-arrow {
          font-family: ${SF};
          font-weight: 700;
          margin-left: 4px;
          opacity: 0;
          transition: opacity 0.15s ease-out;
          display: inline-flex;
          align-items: baseline;
          color: inherit;
        }
        .mlf-email:hover .mlf-email-arrow { opacity: 1; }
        .mlf-social-row {
          display: flex;
          flex-direction: row;
          align-items: center;
          gap: 24px;
        }
        .mlf-social {
          display: flex;
          align-items: center;
          justify-content: center;
          color: #c4c9d0;
          transition: transform 0.2s ease, filter 0.2s ease;
          border-radius: 12px;
        }
        .mlf-social--linkedin:hover {
          filter: brightness(1.08);
          transform: translateY(-2px) scale(1.02);
        }
        .mlf-social:not(.mlf-social--linkedin):hover { color: #3b82f6; transform: translateY(-1px); }
        .mlf-social:focus-visible {
          outline: 2px solid ${ACCENT};
          outline-offset: 4px;
        }
      `}</style>
      <div className="mlf-inner">
        <div className="mlf-grid">
          <div className="mlf-col-brand">
            <a href={homeHref} className="mlf-brand">
              <p className="mlf-brand-names">
                <span className="mlf-brand-word">josephine</span>
                <span className="mlf-brand-word">waliman</span>
              </p>
            </a>
            <div className="mlf-clock-row" aria-live="polite">
              <span className="mlf-clock-icon" aria-hidden="true">{showDayIcon ? <IconSun /> : <IconMoon />}</span>
              <span className="mlf-clock-text">{clockLine}</span>
            </div>
          </div>
          <div aria-hidden="true" className="mlf-col-spacer" />
          <nav className="mlf-col-nav" aria-label="Site">
            {headerNavLinks.map((link) => {
              const emphasized = link.active();
              const kindClass = emphasized ? " mlf-nav-link--ink" : "";
              if (link.kind === "resume") {
                return (
                  <a
                    key="resume"
                    href={link.href}
                    target="_blank"
                    rel="noopener noreferrer"
                    className={"mlf-nav-link" + kindClass}
                    style={{
                      display: "inline-flex",
                      alignItems: "center",
                      gap: 5,
                    }}
                  >
                    {link.label}
                    <IconExternalUpRight />
                  </a>
                );
              }
              if (link.kind === "work") {
                return (
                  <a
                    key="work"
                    href={link.href}
                    onClick={goToWorkSection}
                    className={"mlf-nav-link" + kindClass}
                  >
                    {link.label}
                  </a>
                );
              }
              return (
                <a key={link.label} href={link.href} className={"mlf-nav-link" + kindClass}>
                  {link.label}
                </a>
              );
            })}
          </nav>
          <div className="mlf-col-contact">
            <div>
              <p className="mlf-lead">Let&apos;s work together!</p>
              <p className="mlf-email-wrap">
                <a className="mlf-email" href={`mailto:${CONTACT_EMAIL}`}>
                  <span>{CONTACT_EMAIL}</span>
                  <span className="mlf-email-arrow" aria-hidden="true">
                    <IconEmailCornerArrow />
                  </span>
                </a>
              </p>
            </div>
            <div className="mlf-social-row">
              <a
                href={LINKEDIN_URL}
                target="_blank"
                rel="noopener noreferrer"
                className="mlf-social mlf-social--linkedin"
                aria-label="Josephine Waliman on LinkedIn"
              >
                <IconLinkedInFooter />
              </a>
            </div>
          </div>
        </div>
      </div>
    </footer>
  );
}

Object.assign(window, { GlobalNav, GlobalFooter });
