// `window.INKStudioDesignSystem_0136e3` comes from a separately-loaded
// script (_ds_bundle.js). Destructuring straight off it used to throw the
// instant that script failed to load (a real, network-dependent failure —
// near-impossible to hit on localhost, entirely possible in production) —
// that throw aborted the REST of this file's top-level code too, including
// COPY's own assignment further down, while Header/Footer's function
// declarations still got hoisted onto window regardless. The result: a
// live Header with no working COPY, crashing on COPY.nav the moment React
// rendered it, which took the whole tree down. Falling back to `{}` here
// keeps that destructure from ever throwing, so COPY (and everything else
// in this file) always finishes initializing correctly either way.
const DS = window.INKStudioDesignSystem_0136e3 || {};
const { Logo, Kicker, Button, NavBar, Rule, Tag, Icon, NavLink } = DS;

// A standalone literal (never derived from COPY) that Header falls back to
// if COPY.nav is ever unavailable for any reason — belt-and-suspenders
// alongside the DS guard above, so Header specifically can never crash on
// this regardless of what else changes upstream.
const NAV_FALLBACK = { en: ["Work", "Services", "Studio", "Contact"], ar: ["الأعمال", "الخدمات", "الاستوديو", "تواصل"] };
const COPY = {
  nav: NAV_FALLBACK,
};

// Single source of truth for INK Studio's real business/contact details and
// for the stable service identifiers used to deep-link between Home,
// Services and Contact. `key` matches the id already used internally by
// the Services quadrant grid and by Contact's `svc` selection state
// (media/motion/print/custom3d); `slug` is the URL-safe anchor used for
// in-page navigation (#media-production etc.). Change contact details or
// add a service ONLY here — every page reads from this list.
const BUSINESS = {
  vat: "314276173700003",
  whatsappDisplay: "+966 57 355 7596",
  whatsappDigits: "966573557596", // wa.me wants digits only, no "+"
  email: "inkstudio.ksa@gmail.com",
  instagramHandle: "inkstudiosa",
  tiktokHandle: "inkstudiosa",
  studio: { en: "Dhahran, Saudi Arabia", ar: "الظهران، المملكة العربية السعودية" },
};
const whatsappHref = (text) => `https://wa.me/${BUSINESS.whatsappDigits}${text ? `?text=${encodeURIComponent(text)}` : ""}`;
const emailHref = () => `mailto:${BUSINESS.email}`;
const instagramHref = () => `https://instagram.com/${BUSINESS.instagramHandle}`;
const tiktokHref = () => `https://www.tiktok.com/@${BUSINESS.tiktokHandle}`;

const SERVICE_LIST = [
  { key: "media", slug: "media-production", en: "Media Production", ar: "إنتاج إعلامي" },
  { key: "motion", slug: "motion-animation", en: "Motion & Animation", ar: "موشن وأنيميشن" },
  { key: "print", slug: "print-merchandise", en: "Print & Merchandise", ar: "طباعة ومنتجات" },
  { key: "custom3d", slug: "3d-custom", en: "3D Printing & Custom Objects", ar: "طباعة ثلاثية الأبعاد ومنتجات مخصصة" },
];

// The ONE "how we work" process, shared by Home and Services (and echoed
// as a short arrow-chain on Studio) so the four steps can't drift apart
// again. Each entry is [title, description]; values (not just labels) are
// swapped per language, matching the pattern already used for BUDGET/
// TIMING options elsewhere.
const PROCESS_STEPS = {
  en: [
    ["Brief", "One message with the idea is enough to begin."],
    ["Direction", "Concept, references and one clear plan."],
    ["Production", "Design, shoot, print or fabricate — under one direction."],
    ["Delivery", "The finished pieces, ready to go where they need to go."],
  ],
  ar: [
    ["الفكرة", "رسالة واحدة تحمل الفكرة كافية لنبدأ."],
    ["التوجيه", "مفهوم، مراجع، وخطة واضحة واحدة."],
    ["الإنتاج", "نصمم، نصور، نطبع أو نصنع — تحت توجّه واحد."],
    ["التسليم", "النتيجة النهائية جاهزة لتصل إلى حيث تحتاجها."],
  ],
};
function processSteps(ar) { return ar ? PROCESS_STEPS.ar : PROCESS_STEPS.en; }

function Frame({ ratio = "4 / 3", label, tone = "sand", src, video, children, style, fit = "cover", position = "50% 50%", mediaBox }) {
  const [hover, setHover] = React.useState(false);
  const bg = tone === "ink" ? "var(--ink-900)" : tone === "accent" ? "var(--vermilion-500)" : "var(--sand-200)";
  const filled = src || video;
  const contain = fit === "contain";
  const objectPosition = position || "50% 50%";
  // mediaBox (optional): an explicit {width,height} percentage pair — see
  // mediaZoomBox in Home.jsx for the derivation — that overrides the
  // default edge-to-edge inset:0 sizing with a smaller, centered box.
  // Used ONLY for the handful of assets whose default cover-crop cuts off
  // meaningful composition on the fixed master frame: the asset is still
  // never stretched (mediaZoomBox preserves its own aspect ratio exactly),
  // it's just rendered a bit smaller within the card so more of it is
  // visible, revealing a sliver of the card's own background at the edges
  // rather than the frame itself changing shape.
  const mediaStyle = mediaBox
    ? { position: "absolute", top: "50%", left: "50%", width: mediaBox.width, height: mediaBox.height, transform: `translate(-50%, -50%) scale(${hover ? 1.06 : 1})`, transition: "transform 520ms var(--ease-out)", objectFit: "contain" }
    : { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: contain ? "contain" : "cover", objectPosition, transform: contain ? "scale(1)" : hover ? "scale(1.06)" : "scale(1)", transition: "transform 520ms var(--ease-out)" };
  return (
    <div onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} style={{ position: "relative", aspectRatio: ratio, background: bg, border: "var(--rule-weight-strong) solid var(--border-strong)", borderRadius: "var(--radius-lg)", display: "flex", alignItems: "flex-end", justifyContent: "space-between", padding: "var(--space-4)", overflow: "hidden", cursor: filled ? "pointer" : "default", ...style }}>
      {/* Real object-fit (not an approximated background-size percentage)
          so the box's own aspect ratio never has to match the asset's own
          dimensions — "cover" always fills the frame edge to edge with no
          letterboxing, cropping via `position` (a per-asset focal point)
          rather than distorting/stretching. */}
      {src ? <img src={src} alt="" style={mediaStyle} /> : null}
      {video ? (
        // `poster` matters more here than it usually would: this box also
        // renders `src` as a plain <img> right below the video (so a
        // caller always has a still to show if it opts out of video —
        // see Home.jsx's diff<=1 gating), and a <video> with no poster
        // paints as an opaque black rect the instant it mounts, on top of
        // that already-loaded image, until its own first frame decodes.
        // That black flash — not a genuinely missing asset — is what read
        // as "the center project image is temporarily missing/blank" in
        // the mobile work viewer: a freshly-mounted <video> (a new
        // element, even for a src the browser already has cached bytes
        // for) still has to open the media pipeline and decode a first
        // frame before it has anything to paint. Giving it the same still
        // as its poster means there is never a frame with nothing (or
        // black) where the image was.
        <video autoPlay muted loop playsInline preload="metadata" poster={src} style={mediaStyle}>
          <source src={video} type="video/mp4" />
          <source src={video.replace(/\.mp4$/, ".webm")} type="video/webm" />
        </video>
      ) : null}
      {filled ? <div style={{ position: "absolute", inset: 0, background: "linear-gradient(180deg, transparent 55%, rgba(17,17,18,0.66) 100%)", opacity: hover ? 1 : 0, transition: "opacity 320ms var(--ease-standard)" }} /> : null}
      {filled ? (
        <span className="ink-label" style={{ position: "relative", color: "var(--paper-000)", opacity: hover ? 1 : 0, transform: hover ? "translateY(0)" : "translateY(8px)", transition: "opacity 320ms var(--ease-standard), transform 320ms var(--ease-standard)" }}>{label}</span>
      ) : (children ?? <span className="ink-label" style={{ color: tone === "sand" ? "var(--ink-500)" : "var(--paper-000)" }}>{label}</span>)}
      {filled || children ? null : <Icon name="image" size={16} color={tone === "sand" ? "var(--ink-400)" : "var(--paper-000)"} />}
      {video ? <span className="ink-label" style={{ position: "absolute", top: "var(--space-4)", insetInlineStart: "var(--space-4)", display: "inline-flex", alignItems: "center", gap: "var(--space-2)", color: "var(--paper-000)", background: "rgba(17,17,18,0.5)", borderRadius: "var(--radius-pill)", padding: "4px var(--space-3)" }}><Icon name="play" size={12} color="var(--paper-000)" />Motion</span> : null}
    </div>
  );
}

function useInView(threshold = 0.16) {
  const ref = React.useRef(null);
  const [inView, setInView] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setInView(true); obs.disconnect(); } }, { threshold });
    obs.observe(el);
    return () => obs.disconnect();
  }, []);
  return [ref, inView];
}

function Reveal({ children, delay = 0, y = 22, as: As = "div", style, ...rest }) {
  const [ref, inView] = useInView();
  return (
    <As ref={ref} style={{ opacity: inView ? 1 : 0, transform: inView ? "translateY(0)" : `translateY(${y}px)`, transition: `opacity 640ms var(--ease-out) ${delay}ms, transform 640ms var(--ease-out) ${delay}ms`, ...style }} {...rest}>
      {children}
    </As>
  );
}

function CountUp({ to, suffix = "", duration = 1100 }) {
  const [ref, inView] = useInView(0.5);
  const [n, setN] = React.useState(0);
  React.useEffect(() => {
    if (!inView) return;
    let raf, start;
    const step = (t) => { if (!start) start = t; const p = Math.min(1, (t - start) / duration); setN(Math.round(to * (1 - Math.pow(1 - p, 3)))); if (p < 1) raf = requestAnimationFrame(step); };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [inView]);
  return <span ref={ref}>{n}{suffix}</span>;
}

function TiltCard({ children, style, ...rest }) {
  const ref = React.useRef(null);
  const [t, setT] = React.useState({ rx: 0, ry: 0, mx: 50, my: 50 });
  const onMove = (e) => {
    const r = ref.current.getBoundingClientRect();
    const px = (e.clientX - r.left) / r.width, py = (e.clientY - r.top) / r.height;
    setT({ rx: (0.5 - py) * 7, ry: (px - 0.5) * 7, mx: px * 100, my: py * 100 });
  };
  const reset = () => setT({ rx: 0, ry: 0, mx: 50, my: 50 });
  return (
    <div ref={ref} onMouseMove={onMove} onMouseLeave={reset} style={{ position: "relative", transform: `perspective(900px) rotateX(${t.rx}deg) rotateY(${t.ry}deg)`, transition: "transform 280ms var(--ease-out)", ...style }} {...rest}>
      <div style={{ position: "absolute", inset: 0, borderRadius: "inherit", pointerEvents: "none", opacity: t.rx || t.ry ? 1 : 0, transition: "opacity 280ms", background: `radial-gradient(circle at ${t.mx}% ${t.my}%, rgba(226,58,24,0.14), transparent 60%)` }} />
      {children}
    </div>
  );
}

function Cursor() {
  const dot = React.useRef(null);
  const state = React.useRef({ x: 0, y: 0, tx: 0, ty: 0, active: false, started: false });
  // A mouse-follow dot has nothing to follow on a touchscreen, but this
  // component was mounted once, globally, in index.html with no device
  // check at all — meaning its rAF loop ran unconditionally, forever, on
  // every page load, writing a `transform` on every single frame whether
  // or not a mouse ever moved. That's a sitewide, always-on 60fps
  // main-thread cost stacking on top of everything else on the page (the
  // Contact form's own typing stutter was one visible symptom, but this
  // ran the same way on every route). Skipping the whole effect — and the
  // otherwise-invisible DOM node — on narrow removes it everywhere it
  // could never have been visible anyway.
  const narrow = useIsNarrow();
  React.useEffect(() => {
    if (narrow) return;
    const move = (e) => { state.current.tx = e.clientX; state.current.ty = e.clientY; if (!state.current.started) { state.current.x = e.clientX; state.current.y = e.clientY; state.current.started = true; } };
    const over = (e) => { if (e.target.closest && e.target.closest("button,a,[data-cursor]")) state.current.active = true; };
    const out = (e) => { if (e.target.closest && e.target.closest("button,a,[data-cursor]")) state.current.active = false; };
    window.addEventListener("mousemove", move);
    document.addEventListener("mouseover", over);
    document.addEventListener("mouseout", out);
    let raf;
    const loop = () => {
      const s = state.current;
      s.x += (s.tx - s.x) * 0.18; s.y += (s.ty - s.y) * 0.18;
      if (dot.current) { dot.current.style.transform = `translate(${s.x - 16}px, ${s.y - 16}px) scale(${s.active ? 1.7 : 1})`; dot.current.classList.toggle("cur-active", s.active); }
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => { window.removeEventListener("mousemove", move); document.removeEventListener("mouseover", over); document.removeEventListener("mouseout", out); cancelAnimationFrame(raf); };
  }, [narrow]);
  if (narrow) return null;
  return <div ref={dot} className="ink-cursor" aria-hidden="true" />;
}

// `decor` is an optional purely-decorative node (background blobs/icons,
// see HomeMobileDecor in Home.jsx) painted behind the section's real
// content — absolutely positioned across the section's own full padded
// box, zIndex 0, while the real content sits in its own zIndex:1 layer
// above it. Omitted by default, so every existing caller is unaffected.
function Section({ index, title, children, style, decor }) {
  return (
    <section style={{ position: "relative", padding: "var(--space-10) var(--page-margin)", borderTop: "var(--rule-weight-strong) solid var(--border-strong)", ...style }}>
      {decor ? <div aria-hidden="true" style={{ position: "absolute", inset: 0, zIndex: 0, overflow: "hidden", pointerEvents: "none" }}>{decor}</div> : null}
      <div style={{ position: "relative", zIndex: 1, maxWidth: "var(--container-max)", margin: "0 auto" }}>
        {title ? (
          <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: "var(--space-6)", marginBottom: "var(--space-8)" }}>
            <Kicker index={index}>{title}</Kicker>
          </div>
        ) : null}
        {children}
      </div>
    </section>
  );
}

function Footer({ lang, setPage }) {
  const ar = lang === "ar";
  const linkStyle = { fontSize: "var(--size-body-sm)", color: "var(--paper-100)", textDecoration: "none", fontFamily: ar ? "var(--font-arabic)" : "var(--font-body)" };
  const nav = (page) => (e) => { e.preventDefault(); setPage && setPage(page); };
  const navService = (svcKey) => (e) => { e.preventDefault(); setPage && setPage("Services", { service: svcKey }); };

  const studioGroup = [
    { label: ar ? "عن الاستوديو" : "About / Studio", onClick: nav("Studio") },
  ];
  const servicesGroup = SERVICE_LIST.map((s) => ({
    label: ar ? s.ar : s.en,
    onClick: navService(s.key),
  }));
  const contactGroup = [
    { label: ar ? "واتساب" : "WhatsApp", href: whatsappHref(), aria: ar ? "تواصل مع إنك ستوديو عبر واتساب" : "Contact INK Studio on WhatsApp" },
    { label: BUSINESS.email, href: emailHref(), aria: ar ? "راسل إنك ستوديو عبر البريد الإلكتروني" : "Email INK Studio" },
    { label: ar ? "إنستغرام" : "Instagram", href: instagramHref(), aria: ar ? "إنك ستوديو على إنستغرام" : "INK Studio on Instagram" },
    { label: ar ? "تيك توك" : "TikTok", href: tiktokHref(), aria: ar ? "إنك ستوديو على تيك توك" : "INK Studio on TikTok" },
  ];

  const groups = [
    { h: ar ? "الاستوديو" : "Studio", items: studioGroup },
    { h: ar ? "الخدمات" : "Services", items: servicesGroup },
    { h: ar ? "تواصل" : "Contact", items: contactGroup },
  ];

  return (
    <footer data-theme="ink" style={{ background: "var(--surface-page)", color: "var(--text-body)", padding: "var(--space-9) var(--page-margin) var(--space-7)" }}>
      <div style={{ maxWidth: "var(--container-max)", margin: "0 auto" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: "var(--space-8)", flexWrap: "wrap" }}>
          <div style={{ maxWidth: "34ch" }}>
            <Logo variant="white" height={44} assetBase="assets" />
            <p style={{ marginTop: "var(--space-5)", fontSize: "var(--size-body-sm)", color: "var(--ink-300)", fontFamily: ar ? "var(--font-arabic)" : "var(--font-body)" }}>
              {ar ? "استوديو إبداعي متعدد التخصصات في المملكة العربية السعودية. من الفكرة إلى التنفيذ." : "A multidisciplinary creative studio in Saudi Arabia. Concept to execution, under one direction."}
            </p>
          </div>
          <div style={{ display: "flex", gap: "var(--space-9)", flexWrap: "wrap" }}>
            {groups.map((g) => (
              <div key={g.h} style={{ display: "flex", flexDirection: "column", gap: "var(--space-3)" }}>
                <span className="ink-label" style={{ color: "var(--saffron-500)" }}>{g.h}</span>
                {g.items.map((it) =>
                  it.href ? (
                    <a key={it.label} href={it.href} target="_blank" rel="noopener noreferrer" aria-label={it.aria} style={linkStyle}>{it.label}</a>
                  ) : (
                    <a key={it.label} href="#" onClick={it.onClick} style={linkStyle}>{it.label}</a>
                  )
                )}
              </div>
            ))}
          </div>
        </div>
        <div style={{ marginTop: "var(--space-8)", paddingTop: "var(--space-5)", borderTop: "var(--rule-weight) solid var(--ink-700)", display: "flex", justifyContent: "space-between", gap: "var(--space-5)", flexWrap: "wrap" }}>
          <span className="ink-spec" style={{ color: "var(--ink-400)" }}>{ar ? "© 2026 إنك ستوديو · الظهران، المملكة العربية السعودية" : "© 2026 INK Studio · Dhahran, KSA"}</span>
          <span className="ink-spec" style={{ color: "var(--ink-400)" }}>{ar ? `الرقم الضريبي ${BUSINESS.vat}` : `VAT No. ${BUSINESS.vat}`}</span>
        </div>
      </div>
    </footer>
  );
}

// Below this width, NavBar's own fixed single-row flex layout (logo + all
// nav items + lang toggle + CTA, no wrap) cannot fit and overflows the
// viewport horizontally — confirmed via direct measurement at 390px
// (items spilling ~155px past the viewport edge). NavBar itself comes from
// the prebuilt design-system bundle and isn't ours to restructure, so the
// fix stays entirely in what Header hands it: below the breakpoint, collapse
// the nav items and the lang/CTA cluster into a single compact menu toggle,
// and render the actual links in a simple full-width dropdown underneath.
const HEADER_NARROW_BREAKPOINT = 760;

function Header({ page, setPage, lang, setLang }) {
  const ar = lang === "ar";
  const navCopy = (COPY && COPY.nav) || NAV_FALLBACK;
  const items = navCopy.en.map((en, i) => ({ value: en, label: lang === "ar" ? navCopy.ar[i] : en }));
  const [scrolled, setScrolled] = React.useState(false);
  const [menuOpen, setMenuOpen] = React.useState(false);
  const narrow = useIsNarrow(HEADER_NARROW_BREAKPOINT);
  const reduced = useReducedMotion();
  // The panel stays mounted a beat after menuOpen flips false so the close
  // transition can actually play, and mounts one frame BEFORE its "open"
  // visual state so the open transition has a closed state to animate
  // from (React would otherwise commit mount+open in the same paint,
  // leaving nothing for the CSS transition to run between).
  const [menuRendered, setMenuRendered] = React.useState(false);
  const [menuVisualOpen, setMenuVisualOpen] = React.useState(false);
  const MENU_ANIM_MS = 360;
  React.useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 12);
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  React.useEffect(() => { setMenuOpen(false); }, [page, narrow]);
  React.useEffect(() => {
    if (!menuOpen) return;
    const onKey = (e) => { if (e.key === "Escape") setMenuOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [menuOpen]);
  React.useEffect(() => {
    if (menuOpen) {
      setMenuRendered(true);
      if (reduced) { setMenuVisualOpen(true); return; }
      const raf = requestAnimationFrame(() => setMenuVisualOpen(true));
      return () => cancelAnimationFrame(raf);
    }
    setMenuVisualOpen(false);
    if (reduced) { setMenuRendered(false); return; }
    const t = setTimeout(() => setMenuRendered(false), MENU_ANIM_MS);
    return () => clearTimeout(t);
  }, [menuOpen, reduced]);
  const go = (p, opts) => { setMenuOpen(false); setPage(p, opts); };
  return (
    <div style={{ position: "sticky", top: 0, zIndex: 20, background: "var(--surface-page)", boxShadow: scrolled ? "var(--shadow-md)" : "none", transition: "box-shadow 320ms var(--ease-standard)" }}>
      <NavBar
        logo={<span onClick={() => go("Home")} style={{ cursor: "pointer" }}><Logo height={30} assetBase="assets" /></span>}
        items={narrow ? [] : items}
        active={page}
        onNavigate={go}
        style={{ padding: narrow || scrolled ? "var(--space-3) var(--page-margin)" : "var(--space-4) var(--page-margin)", borderBottom: menuOpen ? 0 : (scrolled ? "var(--rule-weight) solid var(--border-hairline)" : "var(--rule-weight-strong) solid var(--border-strong)"), transition: "padding 320ms var(--ease-standard), border-color 320ms var(--ease-standard)" }}
        right={
          narrow ? (
            <button data-cursor onClick={() => setMenuOpen((v) => !v)} aria-label={ar ? "القائمة" : "Menu"} aria-expanded={menuOpen} aria-controls="ink-mobile-menu" style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", width: 40, height: 40, background: "none", border: "var(--rule-weight-strong) solid var(--border-strong)", borderRadius: "var(--radius-pill)", cursor: "pointer", color: "var(--text-body)" }}>
              <Icon name={menuOpen ? "x" : "menu"} size={18} />
            </button>
          ) : (
            <>
              <button data-cursor onClick={() => setLang(lang === "en" ? "ar" : "en")} className="ink-label" style={{ background: "none", border: "var(--rule-weight-strong) solid var(--border-strong)", borderRadius: "var(--radius-pill)", padding: "6px var(--space-4)", cursor: "pointer" }}>
                {lang === "en" ? "ع" : "EN"}
              </button>
              <Button size="sm" variant="accent" iconRight="arrow-up-right" onClick={() => go("Contact")}>
                {lang === "ar" ? "ابدأ مشروع" : "Start a project"}
              </Button>
            </>
          )
        }
      />
      {narrow && menuRendered ? (
        // Wrapper takes over the panel's old `position:absolute; top:100%`
        // placement, and the panel itself becomes a normal (relative) child
        // of it — purely so its height matches the panel's own real
        // content height, letting the ink-edge decoration below use plain
        // percentage `top` values that land exactly on the panel's
        // (percentage-based, via clip-path) reveal boundary at every
        // instant, with no per-frame JS measurement. The ink edge must be
        // a SIBLING of the panel rather than a child of it — a child would
        // inherit the panel's own clip-path and have its drip tendrils cut
        // off by the exact boundary they're meant to hang below.
        <div style={{ position: "absolute", insetInlineStart: 0, insetInlineEnd: 0, top: "100%" }}>
        <div
          id="ink-mobile-menu"
          role="navigation"
          aria-label={ar ? "التنقل" : "Navigation"}
          style={{
            position: "relative",
            background: "var(--surface-page)", borderBottom: "var(--rule-weight-strong) solid var(--border-strong)",
            padding: "var(--space-5) var(--page-margin) var(--space-6)", display: "flex", flexDirection: "column", gap: "var(--space-5)",
            transformOrigin: "top",
            clipPath: menuVisualOpen ? "inset(0 0 0% 0)" : "inset(0 0 100% 0)",
            opacity: menuVisualOpen ? 1 : 0,
            transition: reduced ? "none" : `clip-path ${MENU_ANIM_MS}ms cubic-bezier(0.65,0,0.35,1), opacity ${Math.round(MENU_ANIM_MS * 0.7)}ms ease`,
          }}
        >
          {/* A short ink-stroke draws in under the toggle as the panel
              opens — the same "graphic wipe" language as the site's other
              clip-path reveals, never literal dripping ink. */}
          <div aria-hidden="true" style={{
            height: 2, width: 44, background: "var(--text-body)",
            transform: menuVisualOpen ? "scaleX(1)" : "scaleX(0)",
            transformOrigin: ar ? "right" : "left",
            transition: reduced ? "none" : `transform ${Math.round(MENU_ANIM_MS * 0.85)}ms cubic-bezier(0.22,1,0.36,1) ${Math.round(MENU_ANIM_MS * 0.1)}ms`,
          }} />
          <nav style={{ display: "flex", flexDirection: "column", gap: "var(--space-4)" }}>
            {items.map((it, i) => (
              <button
                key={it.value}
                onClick={() => go(it.value)}
                className="ink-label"
                style={{
                  textAlign: ar ? "right" : "left", background: "none", border: 0, padding: 0, cursor: "pointer",
                  color: it.value === page ? "var(--text-body)" : "var(--text-muted)", fontSize: "var(--size-body)",
                  opacity: menuVisualOpen ? 1 : 0,
                  transform: menuVisualOpen ? "translateY(0)" : "translateY(8px)",
                  transition: reduced ? "none" : `opacity 240ms ease ${60 + i * 35}ms, transform 320ms cubic-bezier(0.22,1,0.36,1) ${60 + i * 35}ms`,
                }}
              >
                {it.label}
              </button>
            ))}
          </nav>
          <div style={{
            display: "flex", alignItems: "center", gap: "var(--space-4)",
            opacity: menuVisualOpen ? 1 : 0,
            transform: menuVisualOpen ? "translateY(0)" : "translateY(8px)",
            transition: reduced ? "none" : `opacity 240ms ease ${60 + items.length * 35}ms, transform 320ms cubic-bezier(0.22,1,0.36,1) ${60 + items.length * 35}ms`,
          }}>
            <button data-cursor onClick={() => setLang(lang === "en" ? "ar" : "en")} className="ink-label" style={{ background: "none", border: "var(--rule-weight-strong) solid var(--border-strong)", borderRadius: "var(--radius-pill)", padding: "6px var(--space-4)", cursor: "pointer" }}>
              {lang === "en" ? "ع" : "EN"}
            </button>
            <Button size="sm" variant="accent" iconRight="arrow-up-right" onClick={() => go("Contact")} style={{ flex: 1 }}>
              {lang === "ar" ? "ابدأ مشروع" : "Start a project"}
            </Button>
          </div>
        </div>
        {/* The wet-ink leading edge: a restrained, editorial stand-in for
            "the menu sheet's edge briefly behaves like ink" — never a
            literal fluid sim (see this task's own "fake it efficiently"
            instruction). A single static SVG path (a gentle wave with two
            small drip points) whose `top` tracks the SAME percentage,
            duration and easing as the panel's own clip-path reveal above,
            so it rides the actual moving boundary with no JS measurement
            or rAF loop — just two parallel CSS transitions on the same
            timeline. Sitting OUTSIDE the panel (a sibling, not a child)
            is what lets the drips hang below the current boundary without
            being cut off by the panel's own clip-path. Opacity fades out
            with a delay equal to the sweep's own duration on the way in
            (so it's visible for the whole sweep, then settles away once
            open — "mostly settle back into the clean existing menu
            geometry"), and fades back in immediately on the way out
            (reappearing the instant the retraction starts). */}
        {!reduced ? (
          <svg
            aria-hidden="true"
            viewBox="0 0 400 36"
            preserveAspectRatio="none"
            style={{
              position: "absolute", insetInlineStart: 0, insetInlineEnd: 0,
              top: menuVisualOpen ? "100%" : "0%",
              width: "100%", height: 30, marginTop: -8,
              opacity: menuVisualOpen ? 0 : 1,
              transition: menuVisualOpen
                ? `top ${MENU_ANIM_MS}ms cubic-bezier(0.65,0,0.35,1), opacity 220ms ease ${MENU_ANIM_MS}ms`
                : `top ${MENU_ANIM_MS}ms cubic-bezier(0.65,0,0.35,1), opacity 160ms ease`,
              pointerEvents: "none",
            }}
          >
            <path
              d="M0,0 H400 V8 C378,6 366,16 350,14 C332,12 330,24 322,30 C316,34 308,33 306,26 C304,18 296,10 280,9 C250,7 224,15 198,10 C176,6 168,17 158,24 C152,28 144,26 143,19 C142,12 136,7 118,7 C90,7 66,14 40,9 C26,6 12,9 0,8 Z"
              fill="var(--surface-page)"
            />
          </svg>
        ) : null}
        </div>
      ) : null}
    </div>
  );
}

Object.assign(window, { Frame, Section, Footer, Header, COPY, DS, Reveal, CountUp, TiltCard, Cursor, useInView, BUSINESS, SERVICE_LIST, whatsappHref, emailHref, instagramHref, tiktokHref, PROCESS_STEPS, processSteps });
