# Navbar Gooey Bloom

> A glass navbar whose hover highlight is liquid: a lime pool stretches from link to link with a droplet dragging behind, while the label inverts to ink. Menus swell out of a drop into one gooey panel that leans toward its trigger and morphs between layouts, and inside it a lime blob flows from icon to icon.

A shadcn/ui block from the [@tween-ui](https://tween-ui.vercel.app/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/tween-ui/navbar-gooey-bloom).

- Page, with a live preview: https://shadcn.exchange/r/tween-ui/navbar-gooey-bloom
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/tween-ui/navbar-gooey-bloom-light-775aee00f7ca1227.png
- Registry item: https://tween-ui.vercel.app/r/navbar-gooey-bloom.json
- Listed: 2026-10-25, source last changed 2026-10-25

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/tween-ui/navbar-gooey-bloom.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@gsap/react`, `gsap`
- Registry items: `https://tween-ui.vercel.app/r/dot-bloom-button.json`

## Notes from the registry

Docs, props and examples: https://tween-ui.vercel.app/block/navbar-gooey-bloom
Pass `menus` (a `label` plus `columns` and an optional `feature`, or just an `href` for a plain link) and put your page inside as `children`. The goo filter is generated per instance, so several bars can share a page.

## Files

### `components/tweenui/navbar-gooey-bloom.tsx`

```tsx
'use client';

import {
  useCallback,
  useEffect,
  useId,
  useRef,
  useState,
  type ComponentPropsWithoutRef,
  type MouseEventHandler,
  type ReactNode,
} from 'react';
import { useGSAP } from '@gsap/react';
import gsap from 'gsap';
import { cn } from '@/lib/utils';
import DotBloomButton from './dot-bloom-button';

gsap.registerPlugin(useGSAP);

const prefersReducedMotion = () =>
  typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

export type NavbarGooeyBloomIcon =
  'bloom' | 'drop' | 'orbit' | 'spark' | 'layers' | 'wave' | 'bolt' | 'shield';

export interface NavbarGooeyBloomLink {
  label: string;
  href: string;
  description?: string;
  icon?: NavbarGooeyBloomIcon;
}

export interface NavbarGooeyBloomFeature {
  title: string;
  description: string;
  href: string;
  cta?: string;
  image?: string;
}

export interface NavbarGooeyBloomMenu {
  label: string;
  href?: string;
  columns?: NavbarGooeyBloomLink[][];
  feature?: NavbarGooeyBloomFeature;
}

export interface NavbarGooeyBloomProps extends Omit<
  ComponentPropsWithoutRef<'section'>,
  'children'
> {
  brand?: string;
  logo?: ReactNode;
  homeHref?: string;
  menus?: NavbarGooeyBloomMenu[];
  currentHref?: string;
  actionLabel?: string;
  onActionClick?: MouseEventHandler<HTMLButtonElement>;
  children?: ReactNode;
}

const CLOSE_DELAY = 160;
const HOVER_INTENT = 70;
const HIDE_AFTER = 220;
const PANEL_GAP = 12;
const PANEL_RADIUS = 26;
const DROP_SIZE = 22;
const EDGE_LEAD = 520;
const EDGE_TRAIL = 170;
const TAIL_PULL = 110;
const PANEL_LEAD = 300;
const PANEL_TRAIL = 140;
const PANEL_PULL = 260;
const BUMP_RADIUS = 14;
const BUMP_RISE = 6;
const BUMP_PULL = 150;
const ICON_SIZE = 32;
const ICON_DROP = 14;
const SCROLL_TOLERANCE = 6;
const DESKTOP_QUERY = '(min-width: 1024px)';

const CONTAINER = 'mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8';
const EASE_OUT_EXPO = 'ease-[cubic-bezier(0.16,1,0.3,1)]';
const focusRing =
  'focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#c6f56f]';

const TWEEN_MARK = (
  <svg aria-hidden="true" viewBox="0 0 24 24" className="size-7 shrink-0">
    <rect width="24" height="24" rx="6" fill="#045f64" />
    <path
      d="M5 19 C 9.5 8.9, 5 5, 19 5"
      fill="none"
      stroke="#c6f56f"
      strokeWidth="2"
      strokeLinecap="round"
    />
    <circle cx="19" cy="5" r="1.8" fill="#c6f56f" />
  </svg>
);

const ICON_PATHS: Record<NavbarGooeyBloomIcon, ReactNode> = {
  bloom: (
    <>
      <circle cx="12" cy="9" r="3.6" />
      <circle cx="8.6" cy="15" r="3.6" />
      <circle cx="15.4" cy="15" r="3.6" />
    </>
  ),
  drop: <path d="M12 3.5c3.2 3.4 5.5 6 5.5 9a5.5 5.5 0 1 1-11 0c0-3 2.3-5.6 5.5-9Z" />,
  orbit: (
    <>
      <circle cx="12" cy="12" r="3.1" />
      <ellipse cx="12" cy="12" rx="9" ry="4.4" transform="rotate(-24 12 12)" />
    </>
  ),
  spark: <path d="M12 3.5l2 6.5 6.5 2-6.5 2-2 6.5-2-6.5-6.5-2 6.5-2 2-6.5Z" />,
  layers: (
    <>
      <path d="M12 4 4 8.5l8 4.5 8-4.5L12 4Z" />
      <path d="m4 12.5 8 4.5 8-4.5" />
    </>
  ),
  wave: <path d="M3 13.5c2-3.6 4-3.6 6 0s4 3.6 6 0 4-3.6 6 0" />,
  bolt: <path d="M13.5 3 6 13.5h5l-1 7.5 8-11h-5l.5-7Z" />,
  shield: <path d="M12 3.5 19 6v6c0 4.2-3 7-7 8.5-4-1.5-7-4.3-7-8.5V6l7-2.5Z" />,
};

const DEFAULT_MENUS: NavbarGooeyBloomMenu[] = [
  {
    label: 'Work',
    columns: [
      [
        {
          label: 'Case studies',
          href: '#',
          description: 'Shipped products, start to finish.',
          icon: 'bloom',
        },
        {
          label: 'Experiments',
          href: '#',
          description: 'Small ideas, pushed too far.',
          icon: 'spark',
        },
        {
          label: 'Playground',
          href: '#',
          description: 'Live code you can poke at.',
          icon: 'orbit',
        },
        {
          label: 'Archive',
          href: '#',
          description: 'Everything since 2019.',
          icon: 'layers',
        },
      ],
      [
        {
          label: 'Motion kit',
          href: '#',
          description: 'Easing, springs and timing.',
          icon: 'wave',
        },
        {
          label: 'Interface kit',
          href: '#',
          description: 'Bars, panels and overlays.',
          icon: 'drop',
        },
        {
          label: 'Brand systems',
          href: '#',
          description: 'Marks that know how to move.',
          icon: 'shield',
        },
        {
          label: 'Performance',
          href: '#',
          description: 'Sixty frames, no excuses.',
          icon: 'bolt',
        },
      ],
    ],
    feature: {
      title: 'Bloom 2.0',
      description: 'The metaball engine under this bar, documented end to end.',
      href: '#',
      cta: 'Read the notes',
    },
  },
  {
    label: 'Components',
    columns: [
      [
        {
          label: 'Navbars',
          href: '/components',
          description: 'Eleven ways to hold a menu.',
          icon: 'layers',
        },
        {
          label: 'Buttons',
          href: '/components',
          description: 'Press, roll, bloom.',
          icon: 'drop',
        },
        {
          label: 'Carousels',
          href: '/components',
          description: 'Arcs, shutters and reels.',
          icon: 'orbit',
        },
        {
          label: 'Loaders',
          href: '/components',
          description: 'Waiting, but on purpose.',
          icon: 'spark',
        },
        {
          label: 'Type',
          href: '/components',
          description: 'Letters that misbehave.',
          icon: 'wave',
        },
      ],
    ],
  },
  {
    label: 'Studio',
    columns: [
      [
        { label: 'About', href: '#', description: 'Four people, one room.', icon: 'bloom' },
        { label: 'Team', href: '#', description: 'Who makes what.', icon: 'shield' },
        { label: 'Careers', href: '#', description: 'Two seats open.', icon: 'bolt' },
        { label: 'Press', href: '#', description: 'Logos and words.', icon: 'layers' },
      ],
      [
        { label: 'Contact', href: '#', description: 'Say hello properly.', icon: 'drop' },
        {
          label: 'Changelog',
          href: '#',
          description: 'What moved this week.',
          icon: 'wave',
        },
        { label: 'License', href: '#', description: 'What you may ship.', icon: 'orbit' },
        {
          label: 'Support',
          href: '#',
          description: 'We answer on weekdays.',
          icon: 'spark',
        },
      ],
    ],
  },
  { label: 'Journal', href: '#' },
];

const cleanHref = (href: string) => href.split(/[?#]/)[0]?.replace(/\/+$/, '') || '/';

const isExternal = (href: string) => /^https?:/.test(href);

const externalProps = (href: string) =>
  isExternal(href) ? { target: '_blank', rel: 'noopener noreferrer' } : {};

const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);

const panelWidth = (menu: NavbarGooeyBloomMenu) => {
  const columns = menu.columns?.length ?? 0;
  if (menu.feature) return columns > 1 ? 880 : 720;
  return columns > 1 ? 720 : 360;
};

const panelGrid = (menu: NavbarGooeyBloomMenu) => {
  const columns = menu.columns?.length ?? 0;
  if (menu.feature) return columns > 1 ? 'grid-cols-[1fr_1fr_15rem]' : 'grid-cols-[1fr_15rem]';
  return columns > 1 ? 'grid-cols-2' : 'grid-cols-1';
};

interface Spring {
  x: number;
  v: number;
  t: number;
}

interface GooMotion {
  left: Spring;
  right: Spring;
  tail: Spring;
  panelLeft: Spring;
  panelRight: Spring;
  panelHeight: Spring;
  bump: Spring;
  rowTop: Spring;
  rowBottom: Spring;
  rowLeft: Spring;
  rowWidth: Spring;
  iconTop: Spring;
  iconBottom: Spring;
  iconTail: Spring;
  iconOffset: number;
  look: { scale: number; alpha: number };
  hover: { alpha: number };
  pillShown: boolean;
  panelShown: boolean;
  hoverShown: boolean;
  barBottom: number;
  awake: boolean;
}

const spring = (): Spring => ({ x: 0, v: 0, t: 0 });

const place = (target: Spring, value: number) => {
  target.x = value;
  target.v = 0;
  target.t = value;
};

const snap = (target: Spring) => {
  target.x = target.t;
  target.v = 0;
};

const stepSpring = (target: Spring, stiffness: number, dt: number) => {
  const force = stiffness * (target.t - target.x) - 2 * Math.sqrt(stiffness) * target.v;
  target.v += force * dt;
  target.x += target.v * dt;
};

const atRest = (target: Spring, epsilon: number) =>
  Math.abs(target.t - target.x) < epsilon && Math.abs(target.v) < epsilon;

const createMotion = (): GooMotion => ({
  left: spring(),
  right: spring(),
  tail: spring(),
  panelLeft: spring(),
  panelRight: spring(),
  panelHeight: spring(),
  bump: spring(),
  rowTop: spring(),
  rowBottom: spring(),
  rowLeft: spring(),
  rowWidth: spring(),
  iconTop: spring(),
  iconBottom: spring(),
  iconTail: spring(),
  iconOffset: 0,
  look: { scale: 0.4, alpha: 0 },
  hover: { alpha: 0 },
  pillShown: false,
  panelShown: false,
  hoverShown: false,
  barBottom: 60,
  awake: false,
});

const springsOf = (motion: GooMotion) => [
  motion.left,
  motion.right,
  motion.tail,
  motion.panelLeft,
  motion.panelRight,
  motion.panelHeight,
  motion.bump,
  motion.rowTop,
  motion.rowBottom,
  motion.rowLeft,
  motion.rowWidth,
  motion.iconTop,
  motion.iconBottom,
  motion.iconTail,
];

const settleMotion = (motion: GooMotion) => {
  const center = (motion.left.t + motion.right.t) / 2;
  motion.tail.t = center;
  motion.bump.t = center;
  motion.iconTail.t = (motion.iconTop.t + motion.iconBottom.t) / 2;
  springsOf(motion).forEach(snap);
};

const motionAtRest = (motion: GooMotion) =>
  springsOf(motion).every((item) => atRest(item, 0.05)) &&
  !gsap.isTweening(motion.look) &&
  !gsap.isTweening(motion.hover);

const steer = (start: Spring, end: Spring) => {
  const heading = start.t + end.t - start.x - end.x;
  return {
    start: heading > 1 ? EDGE_TRAIL : EDGE_LEAD,
    end: heading < -1 ? EDGE_TRAIL : EDGE_LEAD,
  };
};

const px = (value: number) => Math.round(value * 100) / 100;

const roundedRect = (left: number, right: number, top: number, height: number) => {
  const radius = px(Math.max(0, Math.min(PANEL_RADIUS, (right - left) / 2, height / 2)));
  const bottom = px(top + height);
  const l = px(left);
  const r = px(right);
  return `M${px(l + radius)},${top}H${px(r - radius)}A${radius},${radius} 0 0 1 ${r},${px(top + radius)}V${px(bottom - radius)}A${radius},${radius} 0 0 1 ${px(r - radius)},${bottom}H${px(l + radius)}A${radius},${radius} 0 0 1 ${l},${px(bottom - radius)}V${px(top + radius)}A${radius},${radius} 0 0 1 ${px(l + radius)},${top}Z`;
};

const ArrowIcon = ({ className }: { className?: string }) => {
  return (
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.8"
      strokeLinecap="round"
      strokeLinejoin="round"
      className={className}
    >
      <path d="M5 12h13M13 6l6 6-6 6" />
    </svg>
  );
};

const ChevronIcon = ({ className }: { className?: string }) => {
  return (
    <svg aria-hidden="true" viewBox="0 0 10 6" fill="none" className={className}>
      <path
        d="M1 1l4 4 4-4"
        stroke="currentColor"
        strokeWidth="1.4"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
};

const MenuGlyph = ({ icon, className }: { icon: NavbarGooeyBloomIcon; className?: string }) => {
  return (
    <svg
      aria-hidden="true"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      className={className}
    >
      {ICON_PATHS[icon]}
    </svg>
  );
};

const FeatureArt = () => {
  const rawId = useId().replace(/[^a-zA-Z0-9_-]/g, '');
  const gooId = `feature-goo-${rawId}`;
  const limeId = `feature-lime-${rawId}`;

  return (
    <span aria-hidden="true" className="absolute inset-0 overflow-hidden bg-[#081f1a]">
      <span className="absolute inset-0 bg-[radial-gradient(120%_130%_at_50%_-10%,#17493c,#081f1a_70%)]" />
      <span className="absolute inset-0 [background-image:radial-gradient(rgb(159_212_214/0.16)_1px,transparent_1px)] [mask-image:radial-gradient(72%_72%_at_50%_50%,#000,transparent)] [background-size:10px_10px] opacity-60" />
      <span className="absolute top-1/2 left-1/2 size-32 -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#c6f56f]/15 blur-2xl" />
      <svg viewBox="0 0 240 112" className="absolute inset-0 size-full">
        <defs>
          <filter id={gooId} x="-25%" y="-80%" width="150%" height="260%">
            <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur" />
            <feColorMatrix
              in="blur"
              mode="matrix"
              values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7"
              result="goo"
            />
            <feBlend in="SourceGraphic" in2="goo" />
          </filter>
          <linearGradient id={limeId} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor="#e9ffc2" />
            <stop offset="0.45" stopColor="#c6f56f" />
            <stop offset="1" stopColor="#a6df58" />
          </linearGradient>
        </defs>
        <g stroke="#9fd4d6" fill="none">
          <ellipse cx="120" cy="56" rx="88" ry="30" strokeOpacity="0.14" />
          <ellipse cx="120" cy="56" rx="62" ry="42" strokeOpacity="0.07" />
        </g>
        <g filter={`url(#${gooId})`} fill={`url(#${limeId})`}>
          <rect x="74" y="42" width="84" height="30" rx="15" />
          <circle cx="66" cy="60" r="8.5" />
          <circle cx="162" cy="52" r="7" />
          <circle cx="168" cy="63" r="4.5" />
        </g>
      </svg>
    </span>
  );
};

const SamplePage = () => {
  return (
    <div id="top" className="[container-type:size] relative h-full overflow-hidden bg-[#03110f]">
      <span
        aria-hidden="true"
        className="pointer-events-none absolute inset-0 bg-[radial-gradient(46%_60%_at_50%_-10%,rgb(198_245_111/0.12),transparent_70%),radial-gradient(50%_60%_at_90%_20%,rgb(4_95_100/0.55),transparent_72%),radial-gradient(45%_55%_at_4%_60%,rgb(4_95_100/0.3),transparent_70%)]"
      />
      <span
        aria-hidden="true"
        className="pointer-events-none absolute inset-0 bg-[repeating-linear-gradient(90deg,rgb(159_212_214/0.05)_0_1px,transparent_1px_56px),repeating-linear-gradient(0deg,rgb(159_212_214/0.04)_0_1px,transparent_1px_56px)] [mask-image:radial-gradient(ellipse_70%_60%_at_50%_30%,black,transparent)]"
      />

      <section className="relative mx-auto flex h-full max-w-7xl flex-col justify-center px-4 pt-[clamp(5rem,16cqh,8rem)] pb-[clamp(1.5rem,5cqh,3.5rem)] sm:px-6 lg:px-8">
        <p className="inline-flex w-fit items-center gap-2.5 rounded-full bg-white/[0.04] py-[clamp(0.4rem,1.1cqh,0.55rem)] pr-4 pl-2.5 text-[10px] leading-none font-medium tracking-[0.22em] text-[#9fd4d6] uppercase ring-1 ring-white/10">
          <span
            aria-hidden="true"
            className="size-2 rounded-full bg-[#c6f56f] shadow-[0_0_6px_#c6f56f,0_0_16px_#c6f56f]"
          />
          Metaball navigation
        </p>
        <h2 className="mt-[clamp(1.1rem,3.4cqh,1.75rem)] max-w-[36rem] text-[clamp(2.35rem,7.8cqh,4.75rem)] leading-[0.95] font-medium tracking-[-0.045em] text-balance text-[#e8f3f2]">
          The menu that <span className="text-[#c6f56f]">melts</span> between links.
        </h2>
        <p className="mt-[clamp(0.9rem,2.4cqh,1.5rem)] max-w-[36rem] text-[clamp(0.84rem,1.9cqh,1rem)] leading-relaxed text-pretty text-[#9fd4d6]/70">
          Point at a link. A pool of lime stretches across the bar, sheds a few droplets on the way,
          and settles under the label. Open a menu and the card below re-forms around it.
        </p>
        <div className="mt-[clamp(1.4rem,4cqh,2.25rem)] flex flex-wrap items-center gap-3">
          <a
            href="#top"
            className={cn(
              'inline-flex h-[clamp(2.5rem,6.2cqh,2.75rem)] items-center gap-2 rounded-full bg-[#c6f56f] px-[clamp(1rem,2.4cqh,1.25rem)] text-[clamp(0.82rem,1.8cqh,0.875rem)] font-medium text-[#03110f] transition-transform duration-300 active:scale-[0.97]',
              EASE_OUT_EXPO,
              focusRing
            )}
          >
            See it again
            <ArrowIcon className="size-4" />
          </a>
          <a
            href="#top"
            className={cn(
              'inline-flex h-[clamp(2.5rem,6.2cqh,2.75rem)] items-center rounded-full border border-[#9fd4d6]/20 px-[clamp(1rem,2.4cqh,1.25rem)] text-[clamp(0.82rem,1.8cqh,0.875rem)] text-[#e8f3f2]/80 transition-colors duration-300 hover:border-[#9fd4d6]/45 hover:text-[#e8f3f2]',
              focusRing
            )}
          >
            Read the props
          </a>
        </div>
      </section>
    </div>
  );
};

const NavbarGooeyBloom = ({
  brand = 'Tween UI',
  logo = TWEEN_MARK,
  homeHref = '/',
  menus = DEFAULT_MENUS,
  currentHref = '/',
  actionLabel = 'Get started',
  onActionClick,
  children,
  className,
  ...props
}: NavbarGooeyBloomProps) => {
  const [openKey, setOpenKey] = useState<string | null>(null);
  const [mobileOpen, setMobileOpen] = useState(false);
  const [accordion, setAccordion] = useState<string | null>(null);

  const rawId = useId().replace(/[^a-zA-Z0-9_-]/g, '');
  const gooId = `goo-${rawId}`;
  const linkGooId = `link-goo-${rawId}`;
  const panelGooId = `panel-goo-${rawId}`;
  const panelId = `panel-${rawId}`;
  const mobileId = `mobile-${rawId}`;

  const rootRef = useRef<HTMLElement>(null);
  const barRef = useRef<HTMLDivElement>(null);
  const shellRef = useRef<HTMLDivElement>(null);
  const scrollerRef = useRef<HTMLDivElement>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  const bodyRef = useRef<HTMLDivElement>(null);
  const shapeRef = useRef<SVGPathElement>(null);
  const bumpRef = useRef<SVGCircleElement>(null);
  const hoverRef = useRef<{ row: HTMLElement; blob: HTMLElement; drop: HTMLElement } | null>(null);
  const pillRef = useRef<HTMLSpanElement>(null);
  const coreRef = useRef<HTMLSpanElement>(null);
  const dropRef = useRef<HTMLSpanElement>(null);
  const inkRefs = useRef<Array<HTMLSpanElement | null>>([]);
  const inkBoxes = useRef<Array<{ left: number; width: number } | null>>([]);
  const motion = useRef<GooMotion>(createMotion());
  const activeRef = useRef<HTMLElement | null>(null);
  const sectionRefs = useRef<Record<string, HTMLDivElement | null>>({});
  const triggerRefs = useRef<Record<string, HTMLButtonElement | null>>({});
  const closeTimer = useRef<number | null>(null);
  const hoverTimer = useRef<number | null>(null);
  const pendingHover = useRef<{ menu: NavbarGooeyBloomMenu; el: HTMLElement } | null>(null);
  const pointerPos = useRef({ x: 0, y: 0 });
  const mobileRef = useRef<HTMLDivElement>(null);
  const toggleRef = useRef<HTMLButtonElement>(null);
  const mobileCloseRef = useRef<HTMLButtonElement>(null);
  const openRef = useRef<string | null>(null);
  const skipFocusOpen = useRef(false);

  const current = (href: string) => {
    if (href.startsWith('#')) return false;
    const link = cleanHref(href);
    const page = cleanHref(currentHref);
    return link === page || (link !== '/' && page.startsWith(`${link}/`));
  };

  const { contextSafe } = useGSAP(
    () => {
      if (prefersReducedMotion()) return;
      const bar = barRef.current;
      if (!bar) return;
      const intro = bar.querySelectorAll('[data-intro]');
      gsap.fromTo(
        bar,
        { y: -28, autoAlpha: 0 },
        {
          y: 0,
          autoAlpha: 1,
          duration: 1,
          ease: 'expo.out',
          clearProps: 'transform,opacity,visibility',
        }
      );
      gsap.fromTo(
        intro,
        { y: -8, autoAlpha: 0 },
        {
          y: 0,
          autoAlpha: 1,
          duration: 0.7,
          ease: 'power3.out',
          stagger: 0.06,
          delay: 0.12,
          clearProps: 'transform,opacity,visibility',
        }
      );
    },
    { scope: rootRef }
  );

  const measureInk = useCallback(() => {
    const bar = barRef.current;
    if (!bar) return;
    const barRect = bar.getBoundingClientRect();
    inkRefs.current.forEach((ink, index) => {
      const host = ink?.parentElement;
      if (!host) return;
      const box = host.getBoundingClientRect();
      inkBoxes.current[index] = { left: box.left - barRect.left, width: box.width };
    });
  }, []);

  const draw = useCallback(() => {
    const m = motion.current;
    const left = m.left.x;
    const right = m.right.x;
    const width = Math.max(right - left, 0);
    const stretch = width - (m.right.t - m.left.t);
    const thin = 1 - clamp(stretch / 320, 0, 0.18);
    const { scale, alpha } = m.look;
    const pill = pillRef.current;
    const core = coreRef.current;
    const drop = dropRef.current;

    if (pill && core && drop) {
      pill.style.width = `${width}px`;
      pill.style.transform = `translate3d(${left}px,0,0)`;
      pill.style.opacity = `${alpha}`;
      core.style.transform = `scale(${scale},${scale * thin})`;
      drop.style.transform = `translate3d(${m.tail.x - DROP_SIZE / 2}px,0,0) scale(${scale})`;
      drop.style.opacity = `${alpha}`;
    }

    inkRefs.current.forEach((ink, index) => {
      const box = inkBoxes.current[index];
      if (!ink || !box) return;
      const start = clamp(left - box.left, 0, box.width);
      const end = clamp(right - box.left, 0, box.width);
      ink.style.clipPath = `inset(-4px ${box.width - end}px -4px ${start}px)`;
      ink.style.opacity = `${alpha}`;
    });

    const hover = hoverRef.current;
    if (hover) {
      const alpha = m.hover.alpha;
      const iconHeight = Math.max(m.iconBottom.x - m.iconTop.x, 0);
      const iconStretch = iconHeight - (m.iconBottom.t - m.iconTop.t);
      const iconWidth = ICON_SIZE * (1 - clamp(iconStretch / 160, 0, 0.3));
      const iconX = m.rowLeft.x + m.iconOffset;
      hover.row.style.transform = `translate3d(${m.rowLeft.x}px,${m.rowTop.x}px,0)`;
      hover.row.style.width = `${Math.max(m.rowWidth.x, 0)}px`;
      hover.row.style.height = `${Math.max(m.rowBottom.x - m.rowTop.x, 0)}px`;
      hover.row.style.opacity = `${alpha}`;
      hover.blob.style.transform = `translate3d(${iconX + (ICON_SIZE - iconWidth) / 2}px,${m.iconTop.x}px,0)`;
      hover.blob.style.width = `${iconWidth}px`;
      hover.blob.style.height = `${iconHeight}px`;
      hover.blob.style.opacity = `${alpha}`;
      hover.drop.style.transform = `translate3d(${iconX + (ICON_SIZE - ICON_DROP) / 2}px,${m.iconTail.x - ICON_DROP / 2}px,0)`;
      hover.drop.style.opacity = `${alpha}`;
    }

    const shape = shapeRef.current;
    const bump = bumpRef.current;
    const body = bodyRef.current;
    if (!m.panelShown || !shape || !bump || !body) return;
    const top = m.barBottom + PANEL_GAP;
    const height = Math.max(m.panelHeight.x, 0);
    const panelWidth = Math.max(m.panelRight.x - m.panelLeft.x, 0);
    const bumpRadius = Math.max(0, Math.min(BUMP_RADIUS, panelWidth / 4, height / 3));
    shape.setAttribute('d', roundedRect(m.panelLeft.x, m.panelRight.x, top, height));
    const edge = Math.min(PANEL_RADIUS, panelWidth / 2) + bumpRadius;
    const bumpX =
      panelWidth > edge * 2
        ? clamp(m.bump.x, m.panelLeft.x + edge, m.panelRight.x - edge)
        : m.panelLeft.x + panelWidth / 2;
    bump.setAttribute('cx', `${px(bumpX)}`);
    bump.setAttribute('cy', `${px(top + bumpRadius - BUMP_RISE * (bumpRadius / BUMP_RADIUS))}`);
    bump.setAttribute('r', `${px(bumpRadius)}`);
    body.style.top = `${top}px`;
    body.style.clipPath = `path('${roundedRect(m.panelLeft.x, m.panelRight.x, 0, height)}')`;
  }, []);

  useEffect(() => {
    const tick = (_time: number, deltaTime: number) => {
      const m = motion.current;
      if (!m.awake) return;
      const elapsed = Math.min(deltaTime / 1000, 0.05);
      const steps = Math.max(1, Math.ceil(elapsed * 120));
      const dt = elapsed / steps;
      const pill = steer(m.left, m.right);
      const row = steer(m.rowTop, m.rowBottom);
      const icon = steer(m.iconTop, m.iconBottom);
      const panelHeading = m.panelLeft.t + m.panelRight.t - m.panelLeft.x - m.panelRight.x;
      const panelLeftPull = panelHeading > 1 ? PANEL_TRAIL : PANEL_LEAD;
      const panelRightPull = panelHeading < -1 ? PANEL_TRAIL : PANEL_LEAD;

      for (let step = 0; step < steps; step += 1) {
        stepSpring(m.left, pill.start, dt);
        stepSpring(m.right, pill.end, dt);
        const center = (m.left.x + m.right.x) / 2;
        m.tail.t = center;
        stepSpring(m.tail, TAIL_PULL, dt);
        if (m.panelShown) {
          m.bump.t = center;
          stepSpring(m.panelLeft, panelLeftPull, dt);
          stepSpring(m.panelRight, panelRightPull, dt);
          stepSpring(m.panelHeight, PANEL_PULL, dt);
          stepSpring(m.bump, BUMP_PULL, dt);
        }
        stepSpring(m.rowTop, row.start, dt);
        stepSpring(m.rowBottom, row.end, dt);
        stepSpring(m.rowLeft, EDGE_LEAD, dt);
        stepSpring(m.rowWidth, EDGE_LEAD, dt);
        stepSpring(m.iconTop, icon.start, dt);
        stepSpring(m.iconBottom, icon.end, dt);
        m.iconTail.t = (m.iconTop.x + m.iconBottom.x) / 2;
        stepSpring(m.iconTail, TAIL_PULL, dt);
      }

      const center = (m.left.x + m.right.x) / 2;
      m.tail.x = m.right.x - m.left.x > 4 ? clamp(m.tail.x, m.left.x + 2, m.right.x - 2) : center;
      m.iconTail.x = clamp(m.iconTail.x, m.iconTop.x - 2, m.iconBottom.x + 2);

      if (motionAtRest(m)) {
        settleMotion(m);
        m.awake = false;
      }
      draw();
    };

    gsap.ticker.add(tick);
    return () => gsap.ticker.remove(tick);
  }, [draw]);

  const hideBlob = contextSafe(() => {
    const m = motion.current;
    if (!m.pillShown) return;
    m.pillShown = false;
    const center = (m.left.t + m.right.t) / 2;
    m.left.t = center - 20;
    m.right.t = center + 20;
    gsap.killTweensOf(m.look);
    if (prefersReducedMotion()) {
      m.look.scale = 0.4;
      m.look.alpha = 0;
      settleMotion(m);
      draw();
      return;
    }
    gsap.to(m.look, { scale: 0.4, alpha: 0, duration: 0.32, ease: 'power2.inOut' });
    m.awake = true;
  });

  const moveBlob = contextSafe((el: HTMLElement) => {
    const bar = barRef.current;
    if (!bar) return;
    const m = motion.current;
    const base = bar.getBoundingClientRect();
    const box = el.getBoundingClientRect();
    const left = box.left - base.left;
    const center = left + box.width / 2;
    activeRef.current = el;
    measureInk();
    gsap.killTweensOf(m.look);

    if (!m.pillShown && m.look.alpha < 0.05) {
      place(m.left, center - 20);
      place(m.right, center + 20);
      place(m.tail, center);
      m.look.scale = 0.4;
    }
    m.pillShown = true;
    m.left.t = left;
    m.right.t = left + box.width;

    if (prefersReducedMotion()) {
      m.look.scale = 1;
      m.look.alpha = 1;
      settleMotion(m);
      draw();
      return;
    }
    gsap.to(m.look, { scale: 1, alpha: 1, duration: 0.45, ease: 'power3.out' });
    m.awake = true;
  });

  const resetHover = () => {
    const m = motion.current;
    const hover = hoverRef.current;
    gsap.killTweensOf(m.hover);
    m.hover.alpha = 0;
    m.hoverShown = false;
    hoverRef.current = null;
    if (hover) gsap.set([hover.row, hover.blob, hover.drop], { opacity: 0 });
  };

  const moveHover = contextSafe((link: HTMLElement) => {
    const section = link.closest<HTMLElement>('[data-section]');
    const icon = link.querySelector<HTMLElement>('[data-icon]');
    const row = section?.querySelector<HTMLElement>('[data-hover-row]');
    const blob = section?.querySelector<HTMLElement>('[data-hover-blob]');
    const drop = section?.querySelector<HTMLElement>('[data-hover-drop]');
    if (!section || !icon || !row || !blob || !drop) return;

    const m = motion.current;
    if (hoverRef.current && hoverRef.current.row !== row) resetHover();
    const fresh = !hoverRef.current || (!m.hoverShown && m.hover.alpha < 0.05);
    hoverRef.current = { row, blob, drop };

    const base = section.getBoundingClientRect();
    const box = link.getBoundingClientRect();
    const tile = icon.getBoundingClientRect();
    const top = box.top - base.top;
    const left = box.left - base.left;
    const iconTop = tile.top - base.top;
    const iconCenter = iconTop + tile.height / 2;
    m.iconOffset = tile.left - box.left;
    gsap.killTweensOf(m.hover);

    if (fresh) {
      place(m.rowTop, top);
      place(m.rowBottom, top + box.height);
      place(m.rowLeft, left);
      place(m.rowWidth, box.width);
      place(m.iconTop, iconCenter - 4);
      place(m.iconBottom, iconCenter + 4);
      place(m.iconTail, iconCenter);
    }
    m.hoverShown = true;
    m.rowTop.t = top;
    m.rowBottom.t = top + box.height;
    m.rowLeft.t = left;
    m.rowWidth.t = box.width;
    m.iconTop.t = iconTop;
    m.iconBottom.t = iconTop + tile.height;

    if (prefersReducedMotion()) {
      m.hover.alpha = 1;
      settleMotion(m);
      draw();
      return;
    }
    gsap.to(m.hover, { alpha: 1, duration: 0.3, ease: 'power2.out' });
    m.awake = true;
  });

  const hideHover = contextSafe(() => {
    const m = motion.current;
    if (!m.hoverShown) return;
    m.hoverShown = false;
    const center = (m.iconTop.t + m.iconBottom.t) / 2;
    m.iconTop.t = center - 4;
    m.iconBottom.t = center + 4;
    gsap.killTweensOf(m.hover);
    if (prefersReducedMotion()) {
      m.hover.alpha = 0;
      settleMotion(m);
      draw();
      return;
    }
    gsap.to(m.hover, { alpha: 0, duration: 0.28, ease: 'power2.out' });
    m.awake = true;
  });

  const getLayout = useCallback((trigger: HTMLElement, section: HTMLElement) => {
    const bar = barRef.current;
    const width = section.offsetWidth;
    const height = section.offsetHeight;
    if (!bar) return { left: 0, width, height, center: width / 2 };
    const barRect = bar.getBoundingClientRect();
    const triggerRect = trigger.getBoundingClientRect();
    const center = triggerRect.left - barRect.left + triggerRect.width / 2;
    const min = 8 - barRect.left;
    const max = window.innerWidth - 8 - width - barRect.left;
    return { left: clamp(center - width / 2, Math.min(min, max), max), width, height, center };
  }, []);

  const sectionNodes = () =>
    Object.values(sectionRefs.current).filter((node): node is HTMLDivElement => Boolean(node));

  const openMenu = contextSafe((menu: NavbarGooeyBloomMenu, trigger: HTMLElement) => {
    const section = sectionRefs.current[menu.label];
    const panel = panelRef.current;
    const shell = shellRef.current;
    if (!section || !panel || !shell) return;
    if (openRef.current === menu.label) return;

    const previous = openRef.current;
    const previousSection = previous ? sectionRefs.current[previous] : null;
    openRef.current = menu.label;
    setOpenKey(menu.label);

    const m = motion.current;
    const layout = getLayout(trigger, section);
    const reduced = prefersReducedMotion();
    const items = section.querySelectorAll('[data-item]');
    m.barBottom = shell.offsetHeight;
    resetHover();

    gsap.killTweensOf([panel, ...sectionNodes()]);
    sectionNodes().forEach((node) => {
      if (node !== section && node !== previousSection) gsap.set(node, { opacity: 0 });
    });
    gsap.set(section, { left: layout.left, opacity: 1 });
    gsap.set(panel, { opacity: 1 });

    if (!m.panelShown) {
      place(m.panelLeft, layout.center - 12);
      place(m.panelRight, layout.center + 12);
      place(m.panelHeight, 24);
      place(m.bump, layout.center);
      m.panelShown = true;
    }
    m.panelLeft.t = layout.left;
    m.panelRight.t = layout.left + layout.width;
    m.panelHeight.t = layout.height;

    if (reduced) {
      if (previousSection && previousSection !== section) {
        gsap.set(previousSection, { opacity: 0 });
      }
      gsap.set(items, { y: 0, opacity: 1 });
      settleMotion(m);
      draw();
      return;
    }

    m.awake = true;
    if (previousSection && previousSection !== section) {
      gsap.to(previousSection, { opacity: 0, duration: 0.14, ease: 'power2.out' });
    }
    if (items.length) {
      gsap.fromTo(
        items,
        { y: 10, opacity: 0 },
        {
          y: 0,
          opacity: 1,
          duration: 0.42,
          ease: 'power3.out',
          stagger: 0.02,
          delay: previous ? 0.05 : 0.12,
          overwrite: 'auto',
        }
      );
    }
  });

  const closeMenu = contextSafe((options?: { clearHighlight?: boolean }) => {
    cancelHover();
    if (options?.clearHighlight) {
      hideBlob();
    }
    if (!openRef.current) return;
    openRef.current = null;
    setOpenKey(null);
    setAccordion(null);

    const panel = panelRef.current;
    if (!panel) return;
    const m = motion.current;
    const sections = sectionNodes();
    const center = (m.left.t + m.right.t) / 2;
    gsap.killTweensOf([panel, ...sections]);
    m.panelLeft.t = center - 12;
    m.panelRight.t = center + 12;
    m.panelHeight.t = 24;

    const finish = () => {
      m.panelShown = false;
      resetHover();
      gsap.set(sections, { opacity: 0 });
      gsap.set(panel, { opacity: 0 });
    };

    if (prefersReducedMotion()) {
      finish();
      return;
    }
    m.awake = true;
    gsap.to(sections, { opacity: 0, duration: 0.12, ease: 'power2.out' });
    gsap.to(panel, {
      opacity: 0,
      duration: 0.24,
      delay: 0.08,
      ease: 'power2.in',
      onComplete: finish,
    });
  });

  const cancelClose = () => {
    if (closeTimer.current !== null) {
      window.clearTimeout(closeTimer.current);
      closeTimer.current = null;
    }
  };

  const scheduleClose = contextSafe(() => {
    cancelHover();
    cancelClose();
    closeTimer.current = window.setTimeout(() => {
      const bar = barRef.current;
      if (bar) {
        const rect = bar.getBoundingClientRect();
        const { x, y } = pointerPos.current;
        if (
          x >= rect.left - 2 &&
          x <= rect.right + 2 &&
          y >= rect.top - 2 &&
          y <= rect.bottom + 2
        ) {
          return;
        }
      }
      closeMenu({ clearHighlight: true });
    }, CLOSE_DELAY);
  });

  const cancelHover = () => {
    if (hoverTimer.current !== null) {
      window.clearTimeout(hoverTimer.current);
      hoverTimer.current = null;
    }
    pendingHover.current = null;
  };

  const handleTriggerEnter = (menu: NavbarGooeyBloomMenu, el: HTMLElement) => {
    cancelClose();
    moveBlob(el);
    pendingHover.current = { menu, el };
    if (hoverTimer.current !== null) window.clearTimeout(hoverTimer.current);
    hoverTimer.current = window.setTimeout(() => {
      hoverTimer.current = null;
      const next = pendingHover.current;
      pendingHover.current = null;
      if (!next) return;
      if (next.menu.columns?.length) openMenu(next.menu, next.el);
      else closeMenu();
    }, HOVER_INTENT);
  };

  useEffect(() => {
    const scroller = scrollerRef.current;
    const bar = barRef.current;
    if (!scroller || !bar) return;
    let last = scroller.scrollTop;
    let hidden = false;

    const onScroll = () => {
      const y = scroller.scrollTop;
      const delta = y - last;
      if (Math.abs(delta) < SCROLL_TOLERANCE) return;
      last = y;
      const next = delta > 0 && y > HIDE_AFTER && !openRef.current;
      if (next === hidden) return;
      hidden = next;
      gsap.to(bar, {
        yPercent: next ? -170 : 0,
        duration: prefersReducedMotion() ? 0 : next ? 0.5 : 0.7,
        ease: next ? 'power3.in' : 'expo.out',
        overwrite: 'auto',
      });
    };

    scroller.addEventListener('scroll', onScroll, { passive: true });
    return () => scroller.removeEventListener('scroll', onScroll);
  }, []);

  useEffect(() => {
    const onResize = () => {
      const bar = barRef.current;
      const shell = shellRef.current;
      if (!bar || !shell) return;
      const m = motion.current;
      measureInk();
      const active = activeRef.current;
      if (active && m.pillShown) {
        const base = bar.getBoundingClientRect();
        const box = active.getBoundingClientRect();
        m.left.t = box.left - base.left;
        m.right.t = m.left.t + box.width;
      }
      const key = openRef.current;
      const section = key ? sectionRefs.current[key] : null;
      const trigger = key ? triggerRefs.current[key] : null;
      if (section && trigger) {
        const layout = getLayout(trigger, section);
        m.barBottom = shell.offsetHeight;
        m.panelLeft.t = layout.left;
        m.panelRight.t = layout.left + layout.width;
        m.panelHeight.t = layout.height;
        gsap.set(section, { left: layout.left });
      }
      settleMotion(m);
      draw();
    };

    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, [draw, getLayout, measureInk]);

  useEffect(() => {
    if (!openKey) return;
    const desktop = window.matchMedia(DESKTOP_QUERY);

    const onKeyDown = (event: KeyboardEvent) => {
      if (event.key !== 'Escape') return;
      const key = openRef.current;
      closeMenu({ clearHighlight: true });
      if (key) {
        skipFocusOpen.current = true;
        triggerRefs.current[key]?.focus();
        skipFocusOpen.current = false;
      }
    };

    const onPointerDown = (event: PointerEvent) => {
      if (!barRef.current?.contains(event.target as Node)) {
        closeMenu({ clearHighlight: true });
      }
    };

    const onDesktopChange = (event: MediaQueryListEvent) => {
      if (!event.matches) closeMenu({ clearHighlight: true });
    };

    document.addEventListener('keydown', onKeyDown);
    document.addEventListener('pointerdown', onPointerDown);
    desktop.addEventListener('change', onDesktopChange);
    return () => {
      document.removeEventListener('keydown', onKeyDown);
      document.removeEventListener('pointerdown', onPointerDown);
      desktop.removeEventListener('change', onDesktopChange);
    };
  }, [openKey, closeMenu]);

  useEffect(() => {
    const menu = mobileRef.current;
    if (!menu) return;
    const reduced = prefersReducedMotion();
    const items = menu.querySelectorAll('[data-mobile-item]');

    if (mobileOpen) {
      gsap.set(menu, { visibility: 'visible' });
      gsap.fromTo(
        menu,
        { opacity: 0 },
        { opacity: 1, duration: reduced ? 0 : 0.28, ease: 'power2.out' }
      );
      gsap.fromTo(
        items,
        { y: 22, opacity: 0 },
        {
          y: 0,
          opacity: 1,
          duration: reduced ? 0 : 0.45,
          ease: 'power3.out',
          stagger: reduced ? 0 : 0.035,
          delay: reduced ? 0 : 0.08,
        }
      );
      mobileCloseRef.current?.focus();
    } else {
      gsap.to(menu, {
        opacity: 0,
        duration: reduced ? 0 : 0.22,
        ease: 'power2.out',
        onComplete: () => gsap.set(menu, { visibility: 'hidden' }),
      });
    }
  }, [mobileOpen]);

  useEffect(() => {
    if (!mobileOpen) return;
    const desktop = window.matchMedia(DESKTOP_QUERY);
    const onKeyDown = (event: KeyboardEvent) => {
      if (event.key !== 'Escape') return;
      setMobileOpen(false);
      toggleRef.current?.focus();
    };
    const onChange = (event: MediaQueryListEvent) => {
      if (event.matches) setMobileOpen(false);
    };
    document.addEventListener('keydown', onKeyDown);
    desktop.addEventListener('change', onChange);
    return () => {
      document.removeEventListener('keydown', onKeyDown);
      desktop.removeEventListener('change', onChange);
    };
  }, [mobileOpen]);

  useEffect(() => {
    return () => {
      cancelClose();
      if (hoverTimer.current !== null) window.clearTimeout(hoverTimer.current);
      pendingHover.current = null;
    };
  }, []);

  return (
    <section
      ref={rootRef}
      aria-label={`${brand} site`}
      className={cn(
        'relative isolate h-svh w-full overflow-hidden bg-[#03110f] text-[#e8f3f2]',
        className
      )}
      {...props}
    >
      <svg aria-hidden="true" className="pointer-events-none absolute size-0">
        <defs>
          <filter
            id={gooId}
            x="-40%"
            y="-250%"
            width="180%"
            height="600%"
            colorInterpolationFilters="sRGB"
          >
            <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur" />
            <feColorMatrix
              in="blur"
              mode="matrix"
              values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 22 -9"
              result="goo"
            />
            <feBlend in="SourceGraphic" in2="goo" />
          </filter>
          <filter
            id={linkGooId}
            x="-10%"
            y="-10%"
            width="120%"
            height="120%"
            colorInterpolationFilters="sRGB"
          >
            <feGaussianBlur in="SourceGraphic" stdDeviation="3.5" result="blur" />
            <feColorMatrix
              in="blur"
              mode="matrix"
              values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 20 -8"
              result="goo"
            />
            <feComposite in="SourceGraphic" in2="goo" operator="atop" />
          </filter>
          <filter
            id={panelGooId}
            x="-15%"
            y="-15%"
            width="130%"
            height="130%"
            colorInterpolationFilters="sRGB"
          >
            <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="blur" />
            <feColorMatrix
              in="blur"
              mode="matrix"
              values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 22 -10"
            />
          </filter>
        </defs>
      </svg>

      <header
        className={cn(CONTAINER, 'pointer-events-none absolute inset-x-0 top-0 z-30 pt-5')}
        onBlur={(event) => {
          if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {
            closeMenu({ clearHighlight: true });
          }
        }}
      >
        <div
          ref={barRef}
          className="pointer-events-auto relative mx-auto w-full max-w-[26rem] md:max-w-[40rem] lg:max-w-[61.25rem] xl:max-w-[73.75rem]"
        >
          <div
            ref={shellRef}
            onPointerEnter={cancelClose}
            onPointerLeave={(event) => {
              pointerPos.current = { x: event.clientX, y: event.clientY };
              scheduleClose();
              if (!openRef.current) hideBlob();
            }}
            className="relative flex h-15 items-center justify-between gap-3 rounded-full border border-[#9fd4d6]/12 bg-[#071d1b]/70 px-3 shadow-[0_24px_60px_-32px_rgb(0_0_0/0.95)] backdrop-blur-xl"
          >
            <span
              aria-hidden="true"
              className="pointer-events-none absolute inset-0 overflow-hidden rounded-full"
            >
              <span
                className="absolute inset-0"
                style={{
                  filter: `url(#${gooId}) drop-shadow(0 0 14px rgb(198 245 111 / 0.2))`,
                }}
              >
                <span
                  ref={pillRef}
                  className="absolute top-1/2 left-0 h-10 w-0 -translate-y-1/2 opacity-0"
                >
                  <span
                    ref={coreRef}
                    className="block size-full rounded-full bg-[radial-gradient(120%_160%_at_30%_0%,#eaffc4,#c6f56f_48%,#a8e35a)]"
                  />
                </span>
                <span
                  ref={dropRef}
                  style={{ width: DROP_SIZE, height: DROP_SIZE }}
                  className="absolute top-1/2 left-0 -translate-y-1/2 rounded-full bg-[#c6f56f] opacity-0"
                />
              </span>
            </span>

            <a
              href={homeHref}
              data-intro=""
              aria-label={`${brand} home`}
              className={cn(
                'relative z-10 flex shrink-0 items-center gap-2.5 rounded-full pr-1',
                focusRing
              )}
            >
              {logo}
              <span className="hidden text-[17px] font-medium tracking-tight sm:block">
                {brand}
              </span>
            </a>

            <nav aria-label="Primary" className="pointer-events-auto relative hidden lg:block">
              <ul className="relative z-10 flex items-center">
                {menus.map((menu, index) => {
                  const panelMenu = Boolean(menu.columns?.length);
                  const isOpen = openKey === menu.label;
                  const labelClass = cn(
                    'relative flex h-10 items-center rounded-full px-3.5 text-[13.5px] font-medium tracking-[-0.01em] transition-colors duration-200 text-[#e8f3f2]/75 hover:text-[#e8f3f2]'
                  );
                  const chevronClass = cn(
                    'w-[9px] transition-transform duration-400',
                    EASE_OUT_EXPO,
                    isOpen && 'rotate-180'
                  );

                  return (
                    <li key={menu.label} className="relative">
                      {panelMenu ? (
                        <button
                          ref={(node) => {
                            triggerRefs.current[menu.label] = node;
                          }}
                          type="button"
                          aria-expanded={isOpen}
                          aria-controls={panelId}
                          aria-haspopup="true"
                          onPointerEnter={(event) => handleTriggerEnter(menu, event.currentTarget)}
                          onFocus={(event) => {
                            cancelHover();
                            moveBlob(event.currentTarget);
                            if (skipFocusOpen.current) {
                              skipFocusOpen.current = false;
                              return;
                            }
                            openMenu(menu, event.currentTarget);
                          }}
                          onClick={() => {
                            const trigger = triggerRefs.current[menu.label];
                            if (!trigger) return;
                            if (isOpen) closeMenu();
                            else openMenu(menu, trigger);
                          }}
                          className={cn(labelClass, 'cursor-pointer', focusRing)}
                        >
                          <span className="relative flex items-center gap-1.5">
                            <span>{menu.label}</span>
                            <ChevronIcon className={chevronClass} />
                            <span
                              aria-hidden="true"
                              ref={(node) => {
                                inkRefs.current[index] = node;
                              }}
                              style={{ clipPath: 'inset(0 100% 0 0)' }}
                              className="pointer-events-none absolute inset-0 flex items-center gap-1.5 text-[#03110f] opacity-0"
                            >
                              {menu.label}
                              <ChevronIcon className={chevronClass} />
                            </span>
                          </span>
                        </button>
                      ) : (
                        <a
                          href={menu.href ?? '#'}
                          {...externalProps(menu.href ?? '')}
                          aria-current={menu.href && current(menu.href) ? 'page' : undefined}
                          onPointerEnter={(event) => handleTriggerEnter(menu, event.currentTarget)}
                          onFocus={(event) => {
                            cancelHover();
                            moveBlob(event.currentTarget);
                            closeMenu();
                          }}
                          className={cn(labelClass, focusRing)}
                        >
                          <span className="relative block">
                            {menu.label}
                            <span
                              aria-hidden="true"
                              ref={(node) => {
                                inkRefs.current[index] = node;
                              }}
                              style={{ clipPath: 'inset(0 100% 0 0)' }}
                              className="pointer-events-none absolute inset-0 block text-[#03110f] opacity-0"
                            >
                              {menu.label}
                            </span>
                          </span>
                        </a>
                      )}
                    </li>
                  );
                })}
              </ul>
            </nav>

            <div data-intro="" className="relative z-10 flex shrink-0 items-center gap-2">
              <DotBloomButton
                variant="secondary"
                onClick={onActionClick}
                className="hidden h-10 rounded-full px-4 text-[12.5px] focus-visible:ring-[#c6f56f] focus-visible:ring-offset-[#071d1b] sm:inline-flex"
              >
                {actionLabel}
              </DotBloomButton>

              <button
                ref={toggleRef}
                type="button"
                aria-label={mobileOpen ? 'Close menu' : 'Open menu'}
                aria-expanded={mobileOpen}
                aria-controls={mobileId}
                onClick={() => setMobileOpen((value) => !value)}
                className={cn(
                  'grid size-10 cursor-pointer place-items-center rounded-full border border-[#9fd4d6]/15 bg-white/[0.03] lg:hidden',
                  focusRing
                )}
              >
                <span aria-hidden="true" className="relative block h-2.5 w-5">
                  <span
                    className={cn(
                      'absolute inset-x-0 top-0 h-px bg-[#e8f3f2] transition-transform duration-500 motion-reduce:transition-none',
                      EASE_OUT_EXPO,
                      mobileOpen && 'translate-y-[4.5px] rotate-45'
                    )}
                  />
                  <span
                    className={cn(
                      'absolute inset-x-0 bottom-0 h-px bg-[#e8f3f2] transition-transform duration-500 motion-reduce:transition-none',
                      EASE_OUT_EXPO,
                      mobileOpen && '-translate-y-[4.5px] -rotate-45'
                    )}
                  />
                </span>
              </button>
            </div>
          </div>

          <div
            ref={panelRef}
            id={panelId}
            inert={!openKey}
            onPointerEnter={cancelClose}
            onPointerLeave={scheduleClose}
            className="pointer-events-none absolute inset-x-0 top-0 z-40 h-0 opacity-0"
          >
            <svg
              aria-hidden="true"
              className="absolute top-0 left-0 h-[44rem] w-full overflow-visible"
              style={{
                filter:
                  'drop-shadow(0 0 0.6px rgb(159 212 214 / 0.45)) drop-shadow(0 32px 40px rgb(0 0 0 / 0.55))',
              }}
            >
              <g
                filter={`url(#${panelGooId})`}
                fill="#071d1b"
                className={openKey ? 'pointer-events-auto' : 'pointer-events-none'}
              >
                <path ref={shapeRef} />
                <circle ref={bumpRef} r="0" />
              </g>
            </svg>
            <div
              ref={bodyRef}
              className={cn(
                'absolute top-0 left-0',
                openKey ? 'pointer-events-auto' : 'pointer-events-none'
              )}
            >
              {menus.map((menu) => {
                if (!menu.columns?.length) return null;
                const width = panelWidth(menu);

                return (
                  <div
                    key={menu.label}
                    ref={(node) => {
                      sectionRefs.current[menu.label] = node;
                    }}
                    data-section=""
                    inert={openKey !== menu.label}
                    onPointerLeave={hideHover}
                    style={{ width }}
                    className={cn(
                      'absolute top-0 left-0 p-2.5 opacity-0',
                      openKey === menu.label ? 'pointer-events-auto' : 'pointer-events-none'
                    )}
                  >
                    <span aria-hidden="true" className="pointer-events-none absolute inset-0">
                      <span
                        data-hover-row=""
                        className="absolute top-0 left-0 rounded-2xl bg-[radial-gradient(140%_120%_at_0%_50%,rgb(198_245_111/0.12),transparent_60%),linear-gradient(#0c2924,#0c2924)] opacity-0 shadow-[inset_0_1px_0_rgb(232_243_242/0.06)]"
                      />
                      <span className="absolute inset-0" style={{ filter: `url(#${linkGooId})` }}>
                        <span
                          data-hover-blob=""
                          className="absolute top-0 left-0 rounded-[11px] bg-[#c6f56f] opacity-0"
                        />
                        <span
                          data-hover-drop=""
                          style={{ width: ICON_DROP, height: ICON_DROP }}
                          className="absolute top-0 left-0 rounded-full bg-[#c6f56f] opacity-0"
                        />
                      </span>
                    </span>
                    <div className={cn('relative grid gap-2.5', panelGrid(menu))}>
                      {menu.columns.map((column, columnIndex) => (
                        <ul key={columnIndex} className="flex flex-col">
                          {column.map((link) => (
                            <li key={`${link.label}-${link.href}`} data-item="">
                              <a
                                href={link.href}
                                {...externalProps(link.href)}
                                aria-current={current(link.href) ? 'page' : undefined}
                                onClick={() => closeMenu()}
                                onPointerEnter={(event) => moveHover(event.currentTarget)}
                                onFocus={(event) => moveHover(event.currentTarget)}
                                className={cn(
                                  'group/link relative flex items-start gap-3 rounded-2xl p-2.5',
                                  focusRing
                                )}
                              >
                                <span
                                  data-icon=""
                                  className="mt-0.5 grid size-8 shrink-0 place-items-center rounded-[11px] border border-[#9fd4d6]/12 bg-[#0a2420]/45 text-[#c6f56f] transition-[color,background-color,border-color] duration-300 group-hover/link:border-transparent group-hover/link:bg-transparent group-hover/link:text-[#03110f] group-hover/link:delay-75 group-focus-visible/link:border-transparent group-focus-visible/link:bg-transparent group-focus-visible/link:text-[#03110f]"
                                >
                                  <MenuGlyph icon={link.icon ?? 'bloom'} className="size-4" />
                                </span>
                                <span
                                  className={cn(
                                    'min-w-0 transition-transform duration-500 group-hover/link:translate-x-1',
                                    EASE_OUT_EXPO
                                  )}
                                >
                                  <span className="flex items-center gap-1.5 text-[13.5px] leading-tight font-medium text-[#e8f3f2]">
                                    {link.label}
                                    <ArrowIcon
                                      className={cn(
                                        'size-3 -translate-x-1 text-[#c6f56f] opacity-0 transition-[opacity,translate] duration-500 group-hover/link:translate-x-0 group-hover/link:opacity-100',
                                        EASE_OUT_EXPO
                                      )}
                                    />
                                  </span>
                                  {link.description ? (
                                    <span className="mt-1 block text-[12.5px] leading-snug text-[#9fd4d6]/60 transition-colors duration-300 group-hover/link:text-[#9fd4d6]/85">
                                      {link.description}
                                    </span>
                                  ) : null}
                                </span>
                              </a>
                            </li>
                          ))}
                        </ul>
                      ))}

                      {menu.feature ? (
                        <div
                          data-item=""
                          onPointerEnter={hideHover}
                          className="flex flex-col overflow-hidden rounded-2xl border border-[#9fd4d6]/12 bg-[#0a2420]"
                        >
                          <div className="relative h-28 shrink-0 overflow-hidden">
                            {menu.feature.image ? (
                              <img
                                src={menu.feature.image}
                                alt=""
                                className="size-full object-cover"
                                loading="lazy"
                              />
                            ) : (
                              <FeatureArt />
                            )}
                          </div>
                          <div className="flex flex-1 flex-col p-3">
                            <p className="text-[13px] font-medium">{menu.feature.title}</p>
                            <p className="mt-1 text-[12px] leading-snug text-[#9fd4d6]/60">
                              {menu.feature.description}
                            </p>
                            <a
                              href={menu.feature.href}
                              {...externalProps(menu.feature.href)}
                              onClick={() => closeMenu()}
                              className={cn(
                                'group/feature mt-auto inline-flex items-center gap-1.5 pt-3 text-[12px] font-medium text-[#c6f56f]',
                                focusRing
                              )}
                            >
                              {menu.feature.cta ?? 'Explore'}
                              <ArrowIcon className="size-3.5 transition-transform duration-300 group-hover/feature:translate-x-0.5" />
                            </a>
                          </div>
                        </div>
                      ) : null}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        </div>
      </header>

      <div
        ref={scrollerRef}
        inert={mobileOpen}
        data-lenis-prevent=""
        className="absolute inset-0 z-10 [scrollbar-width:none] overflow-y-auto [&::-webkit-scrollbar]:hidden"
      >
        {children ?? <SamplePage />}
      </div>

      <div
        ref={mobileRef}
        id={mobileId}
        inert={!mobileOpen}
        className="invisible fixed inset-0 z-50 flex flex-col bg-[#04140f] lg:hidden"
      >
        <div className="flex items-center justify-between px-4 pt-5 pb-4 sm:px-6">
          <a href={homeHref} className={cn('flex items-center gap-2.5 rounded-full', focusRing)}>
            {logo}
            <span className="text-[17px] font-medium tracking-tight">{brand}</span>
          </a>
          <button
            ref={mobileCloseRef}
            type="button"
            aria-label="Close menu"
            onClick={() => {
              setMobileOpen(false);
              toggleRef.current?.focus();
            }}
            className={cn(
              'grid size-10 cursor-pointer place-items-center rounded-full border border-[#9fd4d6]/15 bg-white/[0.04]',
              focusRing
            )}
          >
            <svg aria-hidden="true" viewBox="0 0 24 24" className="size-4" fill="none">
              <path
                d="M6 6l12 12M18 6L6 18"
                stroke="currentColor"
                strokeWidth="1.4"
                strokeLinecap="round"
              />
            </svg>
          </button>
        </div>

        <div className="min-h-0 flex-1 overflow-y-auto px-4 pb-8 sm:px-6">
          <ul className="flex flex-col">
            {menus.map((menu) => {
              const panelMenu = Boolean(menu.columns?.length);
              const isOpen = accordion === menu.label;
              const links = menu.columns?.flat() ?? [];
              const contentId = `${mobileId}-${menu.label.replace(/[^a-zA-Z0-9]/g, '')}`;

              return (
                <li
                  key={menu.label}
                  data-mobile-item=""
                  className="border-b border-[#9fd4d6]/10 last:border-b-0"
                >
                  {panelMenu ? (
                    <>
                      <button
                        type="button"
                        aria-expanded={isOpen}
                        aria-controls={contentId}
                        onClick={() => setAccordion(isOpen ? null : menu.label)}
                        className={cn(
                          'flex w-full cursor-pointer items-center justify-between py-4 text-left',
                          focusRing
                        )}
                      >
                        <span className="text-[26px] leading-none font-medium tracking-[-0.03em]">
                          {menu.label}
                        </span>
                        <ChevronIcon
                          className={cn(
                            'w-3 text-[#c6f56f] transition-transform duration-300',
                            isOpen && 'rotate-180'
                          )}
                        />
                      </button>
                      <div
                        id={contentId}
                        inert={!isOpen}
                        className={cn(
                          'grid transition-[grid-template-rows] duration-400 motion-reduce:transition-none',
                          EASE_OUT_EXPO,
                          isOpen ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'
                        )}
                      >
                        <div className="overflow-hidden">
                          <ul className="flex flex-col gap-1 pb-3">
                            {links.map((link) => (
                              <li key={`${link.label}-${link.href}`}>
                                <a
                                  href={link.href}
                                  {...externalProps(link.href)}
                                  onClick={() => setMobileOpen(false)}
                                  className={cn(
                                    'flex items-center gap-3 rounded-xl px-2 py-2.5 text-[15px] text-[#e8f3f2]/75',
                                    focusRing
                                  )}
                                >
                                  <MenuGlyph
                                    icon={link.icon ?? 'bloom'}
                                    className="size-4 text-[#c6f56f]"
                                  />
                                  {link.label}
                                </a>
                              </li>
                            ))}
                          </ul>
                        </div>
                      </div>
                    </>
                  ) : (
                    <a
                      href={menu.href ?? '#'}
                      {...externalProps(menu.href ?? '')}
                      onClick={() => setMobileOpen(false)}
                      className={cn(
                        'block py-4 text-[26px] leading-none font-medium tracking-[-0.03em]',
                        focusRing
                      )}
                    >
                      {menu.label}
                    </a>
                  )}
                </li>
              );
            })}
          </ul>

          <div data-mobile-item="" className="mt-6">
            <DotBloomButton
              variant="secondary"
              onClick={(event) => {
                setMobileOpen(false);
                onActionClick?.(event);
              }}
              className="h-12 w-full rounded-full focus-visible:ring-[#c6f56f] focus-visible:ring-offset-[#04140f]"
            >
              {actionLabel}
            </DotBloomButton>
          </div>
        </div>
      </div>
    </section>
  );
};

export default NavbarGooeyBloom;
```
