diff --git a/src/components/RadialMenu.jsx b/src/components/RadialMenu.jsx
index b0da0f4..3079791 100644
--- a/src/components/RadialMenu.jsx
+++ b/src/components/RadialMenu.jsx
@@ -1,357 +1,362 @@
-import { useEffect, useRef, useCallback } from 'react'
-import { createPortal } from 'react-dom'
-
-/**
- * RadialMenu - ATAK-style radial context menu
- * Themed to match Navi light/dark palette using CSS custom properties.
- *
- * Props:
- * - open: boolean
- * - x, y: screen coordinates of trigger point
- * - lat, lon: geographic coordinates
- * - wedges: array of { id, label, icon: LucideIcon, onSelect, requiresAuth? }
- * - centerLabel: string (coords by default, replaced by reverse-geocode async)
- * - onDismiss: callback when menu should close
- */
-export default function RadialMenu({
- open,
- x,
- y,
- lat,
- lon,
- wedges = [],
- centerLabel,
- onDismiss,
-}) {
- const containerRef = useRef(null)
- const activeWedgeRef = useRef(null)
-
- // Geometry constants
- const outerRadius = 80
- const innerRadius = 40
- const wedgeCount = wedges.length || 6
- const wedgeAngle = 360 / wedgeCount
-
- // Handle escape key
- useEffect(() => {
- if (!open) return
- const handleKey = (e) => {
- if (e.key === 'Escape') {
- onDismiss?.()
- }
- }
- window.addEventListener('keydown', handleKey)
- return () => window.removeEventListener('keydown', handleKey)
- }, [open, onDismiss])
-
- // Calculate which wedge the pointer is over
- const getWedgeAtPoint = useCallback((clientX, clientY) => {
- const dx = clientX - x
- const dy = clientY - y
- const dist = Math.sqrt(dx * dx + dy * dy)
-
- // Inside inner radius = center (no wedge)
- if (dist < innerRadius) return null
- // Outside outer radius = no wedge
- if (dist > outerRadius + 20) return null
-
- // Calculate angle (0 = top, clockwise)
- let angle = Math.atan2(dx, -dy) * (180 / Math.PI)
- if (angle < 0) angle += 360
-
- // Find which wedge
- const wedgeIndex = Math.floor(angle / wedgeAngle)
- return wedges[wedgeIndex] || null
- }, [x, y, wedges, wedgeAngle])
-
- // Handle mouse/touch move for highlighting
- const handlePointerMove = useCallback((e) => {
- const clientX = e.touches ? e.touches[0].clientX : e.clientX
- const clientY = e.touches ? e.touches[0].clientY : e.clientY
- activeWedgeRef.current = getWedgeAtPoint(clientX, clientY)
- // Force re-render for highlight
- containerRef.current?.querySelectorAll('.radial-wedge').forEach((el, i) => {
- if (wedges[i] && wedges[i].id === activeWedgeRef.current?.id) {
- el.classList.add('active')
- } else {
- el.classList.remove('active')
- }
- })
- }, [getWedgeAtPoint, wedges])
-
- // Handle release
- const handlePointerUp = useCallback((e) => {
- const clientX = e.changedTouches ? e.changedTouches[0].clientX : e.clientX
- const clientY = e.changedTouches ? e.changedTouches[0].clientY : e.clientY
- const wedge = getWedgeAtPoint(clientX, clientY)
-
- if (wedge) {
- wedge.onSelect?.({ lat, lon })
- }
- onDismiss?.()
- }, [getWedgeAtPoint, lat, lon, onDismiss])
-
- // Handle backdrop click (dismiss menu)
- const handleBackdropClick = useCallback((e) => {
- e.stopPropagation()
- onDismiss?.()
- }, [onDismiss])
-
- // Prevent menu container clicks from reaching backdrop
- const handleContainerClick = useCallback((e) => {
- e.stopPropagation()
- }, [])
-
- // Generate wedge paths
- const generateWedgePath = (index) => {
- const startAngle = (index * wedgeAngle - 90) * (Math.PI / 180)
- const endAngle = ((index + 1) * wedgeAngle - 90) * (Math.PI / 180)
-
- const x1 = innerRadius * Math.cos(startAngle)
- const y1 = innerRadius * Math.sin(startAngle)
- const x2 = outerRadius * Math.cos(startAngle)
- const y2 = outerRadius * Math.sin(startAngle)
- const x3 = outerRadius * Math.cos(endAngle)
- const y3 = outerRadius * Math.sin(endAngle)
- const x4 = innerRadius * Math.cos(endAngle)
- const y4 = innerRadius * Math.sin(endAngle)
-
- return `M ${x1} ${y1} L ${x2} ${y2} A ${outerRadius} ${outerRadius} 0 0 1 ${x3} ${y3} L ${x4} ${y4} A ${innerRadius} ${innerRadius} 0 0 0 ${x1} ${y1} Z`
- }
-
- // Calculate icon position for each wedge
- const getIconPosition = (index) => {
- const midAngle = ((index + 0.5) * wedgeAngle - 90) * (Math.PI / 180)
- const r = (innerRadius + outerRadius) / 2
- return {
- x: r * Math.cos(midAngle),
- y: r * Math.sin(midAngle),
- }
- }
-
- if (!open) return null
-
- // Clamp position to viewport
- const padding = outerRadius + 20
- const clampedX = Math.max(padding, Math.min(window.innerWidth - padding, x))
- const clampedY = Math.max(padding, Math.min(window.innerHeight - padding, y))
-
- const content = (
- <>
- {/* Full-screen backdrop for dismiss — matches modal overlay opacity */}
-
-
- {/* Radial menu container */}
-
-
-
-
-
- >
- )
-
- return createPortal(content, document.body)
-}
+import { useEffect, useRef, useCallback } from 'react'
+import { createPortal } from 'react-dom'
+import { useStore } from '../store'
+
+/**
+ * RadialMenu - ATAK-style radial context menu
+ * Themed to match Navi light/dark palette using CSS custom properties.
+ *
+ * Props:
+ * - open: boolean
+ * - x, y: screen coordinates of trigger point
+ * - lat, lon: geographic coordinates
+ * - wedges: array of { id, label, icon: LucideIcon, onSelect, requiresAuth? }
+ * - centerLabel: string (coords by default, replaced by reverse-geocode async)
+ * - onDismiss: callback when menu should close
+ */
+export default function RadialMenu({
+ open,
+ x,
+ y,
+ lat,
+ lon,
+ wedges = [],
+ centerLabel,
+ onDismiss,
+}) {
+ const containerRef = useRef(null)
+ const activeWedgeRef = useRef(null)
+ const auth = useStore((s) => s.auth)
+ const isAuthenticated = auth?.authenticated ?? false
+
+ // Geometry constants
+ const outerRadius = 80
+ const innerRadius = 40
+ const wedgeCount = wedges.length || 6
+ const wedgeAngle = 360 / wedgeCount
+
+ // Handle escape key
+ useEffect(() => {
+ if (!open) return
+ const handleKey = (e) => {
+ if (e.key === 'Escape') {
+ onDismiss?.()
+ }
+ }
+ window.addEventListener('keydown', handleKey)
+ return () => window.removeEventListener('keydown', handleKey)
+ }, [open, onDismiss])
+
+ // Calculate which wedge the pointer is over
+ const getWedgeAtPoint = useCallback((clientX, clientY) => {
+ const dx = clientX - x
+ const dy = clientY - y
+ const dist = Math.sqrt(dx * dx + dy * dy)
+
+ // Inside inner radius = center (no wedge)
+ if (dist < innerRadius) return null
+ // Outside outer radius = no wedge
+ if (dist > outerRadius + 20) return null
+
+ // Calculate angle (0 = top, clockwise)
+ let angle = Math.atan2(dx, -dy) * (180 / Math.PI)
+ if (angle < 0) angle += 360
+
+ // Find which wedge
+ const wedgeIndex = Math.floor(angle / wedgeAngle)
+ return wedges[wedgeIndex] || null
+ }, [x, y, wedges, wedgeAngle])
+
+ // Handle mouse/touch move for highlighting
+ const handlePointerMove = useCallback((e) => {
+ const clientX = e.touches ? e.touches[0].clientX : e.clientX
+ const clientY = e.touches ? e.touches[0].clientY : e.clientY
+ activeWedgeRef.current = getWedgeAtPoint(clientX, clientY)
+ // Force re-render for highlight
+ containerRef.current?.querySelectorAll('.radial-wedge').forEach((el, i) => {
+ if (wedges[i] && wedges[i].id === activeWedgeRef.current?.id) {
+ el.classList.add('active')
+ } else {
+ el.classList.remove('active')
+ }
+ })
+ }, [getWedgeAtPoint, wedges])
+
+ // Handle release
+ const handlePointerUp = useCallback((e) => {
+ const clientX = e.changedTouches ? e.changedTouches[0].clientX : e.clientX
+ const clientY = e.changedTouches ? e.changedTouches[0].clientY : e.clientY
+ const wedge = getWedgeAtPoint(clientX, clientY)
+
+ if (wedge) {
+ wedge.onSelect?.({ lat, lon })
+ }
+ onDismiss?.()
+ }, [getWedgeAtPoint, lat, lon, onDismiss])
+
+ // Handle backdrop click (dismiss menu)
+ const handleBackdropClick = useCallback((e) => {
+ e.stopPropagation()
+ onDismiss?.()
+ }, [onDismiss])
+
+ // Prevent menu container clicks from reaching backdrop
+ const handleContainerClick = useCallback((e) => {
+ e.stopPropagation()
+ }, [])
+
+ // Generate wedge paths
+ const generateWedgePath = (index) => {
+ const startAngle = (index * wedgeAngle - 90) * (Math.PI / 180)
+ const endAngle = ((index + 1) * wedgeAngle - 90) * (Math.PI / 180)
+
+ const x1 = innerRadius * Math.cos(startAngle)
+ const y1 = innerRadius * Math.sin(startAngle)
+ const x2 = outerRadius * Math.cos(startAngle)
+ const y2 = outerRadius * Math.sin(startAngle)
+ const x3 = outerRadius * Math.cos(endAngle)
+ const y3 = outerRadius * Math.sin(endAngle)
+ const x4 = innerRadius * Math.cos(endAngle)
+ const y4 = innerRadius * Math.sin(endAngle)
+
+ return `M ${x1} ${y1} L ${x2} ${y2} A ${outerRadius} ${outerRadius} 0 0 1 ${x3} ${y3} L ${x4} ${y4} A ${innerRadius} ${innerRadius} 0 0 0 ${x1} ${y1} Z`
+ }
+
+ // Calculate icon position for each wedge
+ const getIconPosition = (index) => {
+ const midAngle = ((index + 0.5) * wedgeAngle - 90) * (Math.PI / 180)
+ const r = (innerRadius + outerRadius) / 2
+ return {
+ x: r * Math.cos(midAngle),
+ y: r * Math.sin(midAngle),
+ }
+ }
+
+ if (!open) return null
+
+ // Clamp position to viewport
+ const padding = outerRadius + 20
+ const clampedX = Math.max(padding, Math.min(window.innerWidth - padding, x))
+ const clampedY = Math.max(padding, Math.min(window.innerHeight - padding, y))
+
+ const content = (
+ <>
+ {/* Full-screen backdrop for dismiss — matches modal overlay opacity */}
+
+
+ {/* Radial menu container */}
+
+
+
+
+
+ >
+ )
+
+ return createPortal(content, document.body)
+}