diff --git a/components/layout/floating-controls.tsx b/components/layout/floating-controls.tsx
deleted file mode 100644
index b3f05ec..0000000
--- a/components/layout/floating-controls.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-"use client";
-
-import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
-import { Plus, ShieldCheck } from "lucide-react";
-import { useLocale, useTranslations } from "next-intl";
-import { useState, type ReactNode } from "react";
-
-import { LocaleToggle } from "@/components/layout/locale-toggle";
-import { SoundToggle } from "@/components/sound-toggle";
-import { ThemeToggle } from "@/components/theme-toggle";
-import { buildAdminUrl } from "@/lib/admin-routing";
-import type { AppLocale } from "@/lib/locale";
-import { cn } from "@/lib/utils";
-
-type FloatingControlsProps = {
- locale: string;
- defaultLocale: AppLocale;
- isSuperAdmin?: boolean;
-};
-
-const pill =
- "flex h-11 w-11 items-center justify-center rounded-full border border-border/60 bg-background/85 text-foreground/80 shadow-panel backdrop-blur-chrome transition-colors hover:bg-accent hover:text-foreground";
-
-/** Radius (px) of the arc the items fan out along. */
-const RADIUS = 92;
-
-export function FloatingControls({
- locale,
- defaultLocale,
- isSuperAdmin = false,
-}: FloatingControlsProps) {
- const [open, setOpen] = useState(false);
- const t = useTranslations("navigation");
- const activeLocale = useLocale();
- const isRtl = activeLocale === "ar";
- const reducedMotion = useReducedMotion();
-
- const controls: ReactNode[] = [
- ,
- ,
- ,
- ];
-
- if (isSuperAdmin) {
- controls.push(
-
-
- ,
- );
- }
-
- const count = controls.length;
- // Fan the items across a quarter arc from "up" (90°) to "sideways" (180°),
- // mirrored for RTL so they always spread away from the corner into the page.
- const startAngle = 94;
- const endAngle = 176;
- const positionFor = (index: number) => {
- const angle = count === 1 ? 135 : startAngle + ((endAngle - startAngle) * index) / (count - 1);
- const radians = (angle * Math.PI) / 180;
- return {
- x: (isRtl ? -1 : 1) * Math.cos(radians) * RADIUS,
- y: -Math.sin(radians) * RADIUS,
- };
- };
-
- return (
-
-
-
- {open ? (
- <>
- {/* click-away scrim */}
- setOpen(false)}
- initial={{ opacity: 0 }}
- animate={{ opacity: 1 }}
- exit={{ opacity: 0 }}
- className="fixed inset-0 -z-10 cursor-default bg-transparent"
- />
- {controls.map((control, index) => {
- const { x, y } = positionFor(index);
- return (
-
- {control}
-
- );
- })}
- >
- ) : null}
-
-
- {/* trigger */}
-
-
-
- );
-}
diff --git a/components/layout/site-dock.tsx b/components/layout/site-dock.tsx
index aea5c41..3ee148b 100644
--- a/components/layout/site-dock.tsx
+++ b/components/layout/site-dock.tsx
@@ -1,12 +1,16 @@
"use client";
+import { ShieldCheck } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useLocale, useTranslations } from "next-intl";
-import { FloatingControls } from "@/components/layout/floating-controls";
+import { LocaleToggle } from "@/components/layout/locale-toggle";
+import { SoundToggle } from "@/components/sound-toggle";
+import { ThemeToggle } from "@/components/theme-toggle";
import { Dock, DockIcon } from "@/components/ui/dock";
+import { buildAdminUrl } from "@/lib/admin-routing";
import { getLocalizedPath, stripLocalePrefix, type AppLocale } from "@/lib/locale";
import { cn } from "@/lib/utils";
@@ -37,6 +41,13 @@ const navItems: NavItem[] = [
{ key: "contact", path: "/contact" },
];
+// Graphite squircle that matches the SVG page icons, used for the live control
+// tiles (theme / sound / language / admin) so the whole dock reads as one set.
+const controlTile =
+ "group relative overflow-visible rounded-[26%] bg-gradient-to-b from-[#3f4551] to-[#191d24] shadow-[0_6px_14px_-6px_rgba(0,0,0,0.5)] ring-1 ring-white/10 transition-shadow duration-200 hover:shadow-[0_10px_22px_-8px_rgba(0,0,0,0.6)]";
+const controlButton =
+ "h-full w-full rounded-[inherit] border-0 bg-transparent text-white hover:bg-white/10 hover:text-white";
+
function isNavItemActive(currentPath: string, itemPath: string) {
if (itemPath === "/") {
return currentPath === "/";
@@ -53,96 +64,148 @@ export function SiteDock({ defaultLocale, isSuperAdmin = false }: SiteDockProps)
const homeHref = getLocalizedPath(locale, "/", defaultLocale);
return (
- <>
- {/* ===== Bottom dock (Magic UI) — primary navigation ===== */}
-
+
-
- {/* Logo — first icon in the dock (fixed src, no theme swap → no flash) */}
-
-
+
+
+
+
+
+
+
+
+ {/* ── Pages ── */}
+ {navItems.map(({ key, path, disabled }) => {
+ const itemPath = path || "/";
+ const isActive = isNavItemActive(currentPath, itemPath);
+ const label = t(key);
+ const src = `/dock/${key}${isActive ? "-active" : ""}.svg`;
+
+ const icon = (
+
+ );
+
+ return (
+
-
-
-
+ {disabled ? (
+
+ {icon}
+
+ ) : (
+
+ {icon}
+
+ )}
+
+
+ );
+ })}
+
+
+
+ {/* ── Settings (live controls) ── */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {isSuperAdmin ? (
+
+
+
+
+
+
+ ) : null}
+
+
+ );
+}
-
+function DockSeparator() {
+ return ;
+}
- {navItems.map(({ key, path, disabled }) => {
- const itemPath = path || "/";
- const isActive = isNavItemActive(currentPath, itemPath);
- const label = t(key);
- const src = `/dock/${key}${isActive ? "-active" : ""}.svg`;
-
- const icon = (
-
- );
-
- return (
-
- {disabled ? (
-
- {icon}
-
- ) : (
-
- {icon}
-
- )}
-
-
-
- );
- })}
-
-
-
- {/* ===== Corner controls — theme / language / sound / admin ===== */}
-
- >
+function TileGloss() {
+ return (
+
);
}