"use client" import * as React from "react" import { useReducedMotion } from "motion/react" import { useTheme } from "@exxatdesignux/ui/hooks/use-color-scheme" import { LEO_BLOB_ANIM_RATE, type LeoBlobAnimationSpeed, } from "@/lib/leo-ambience" import { cn } from "@/lib/utils" export type BlobIntensity = "high" | "normal" export type AnimatedBlobBackgroundProps = { className?: string intensity?: BlobIntensity /** When false, unmounts entirely (saves GPU while Leo is hidden). */ enabled?: boolean /** When true, blobs animate faster (thinking / analyzing). */ thinking?: boolean /** Float / think keyframes. Honours prefers-reduced-motion. */ animate?: boolean /** * Run the entrance spread + one gentle float cycle, then settle. * Used on short-lived surfaces (What's new Leo cards) where an infinite * drift would keep competing with the copy. */ playOnce?: boolean animationSpeed?: LeoBlobAnimationSpeed /** * `bar` — compact wash sized for a search / composer pill (blobs live inside * the rounded shell). `default` — full-panel hero / rail wash. */ density?: "default" | "bar" /** Soft sheen sweep (bar density + thinking only). Default true. */ sheen?: boolean /** * Free placement for bar blobs only (px). Applied on each blob’s position * shell — never on a full-bleed layer — so the pill chrome stays put. */ offsetX?: number offsetY?: number } /** * Bar lobes are sized and centred as a share of the pill width so they keep the * same overlap at any pill size. Neighbouring lobes overlap by ~20% of the pill * — enough that the wash reads as one field with three hot spots rather than * three detached circles. */ const BAR_LOBES = [ { slot: 1 as const, centerPct: 24, widthPct: 54, heightClass: "h-32" }, { slot: 3 as const, centerPct: 50, widthPct: 46, heightClass: "h-24" }, { slot: 2 as const, centerPct: 76, widthPct: 52, heightClass: "h-28" }, ] function BarBlob({ slot, centerPct, widthPct, heightClass, offsetX, offsetY, opacity, blurClass, }: { slot: 1 | 2 | 3 centerPct: number widthPct: number heightClass: string offsetX: number offsetY: number opacity: number blurClass: string }) { // Placement on the position shell; keyframes run on the core (transform). const positionStyle: React.CSSProperties = { opacity, top: "50%", left: `${centerPct}%`, width: `${widthPct}%`, transform: `translate(calc(-50% + ${offsetX}px), calc(-50% + ${offsetY}px))`, } return (