{"version":3,"file":"link-analysis.cjs","sources":["../src/components/Tooltip.tsx","../src/components/GraphVisualization.tsx","../src/utils/normalize.ts","../src/utils/detachedNodes.ts","../src/contexts/ThemeContext.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport type { Node, Edge } from '../types/graph';\n\ninterface TooltipProps {\n  visible: boolean;\n  x: number;\n  y: number;\n  node?: Node;\n  edge?: Edge;\n  content?: React.ReactNode;\n  idAttr?: string;\n  pinned?: boolean;\n  onClose?: () => void;\n}\n\nconst NODE_FIELD_MAPPINGS: { key: string; label: string }[] = [\n  { key: 'first_name', label: 'First Name' },\n  { key: 'middle_name', label: 'Middle Name' },\n  { key: 'last_name', label: 'Last Name' },\n  { key: 'nick_name', label: 'Nick Name' },\n  { key: 'national_id', label: 'National ID' },\n  { key: 'phone_number', label: 'Phone Number' },\n  { key: 'family_name', label: 'Family Name' },\n  { key: 'gender', label: 'Gender' },\n  { key: 'height', label: 'Height' },\n  { key: 'weight', label: 'Weight' },\n  { key: 'face_colour', label: 'Face Colour' },\n  { key: 'eye_colour', label: 'Eye Colour' },\n  { key: 'physical_injury', label: 'Physical Injury' },\n  { key: 'birth_date', label: 'Birth Date' },\n  { key: 'education_status', label: 'Education' },\n  { key: 'background_history', label: 'Background' },\n  { key: 'marriage_status', label: 'Marital Status' },\n  { key: 'job_status', label: 'Job Status' },\n  { key: 'target_details', label: 'Target Details' },\n  { key: 'status', label: 'Status' },\n  { key: 'approved_date', label: 'Approved Date' },\n  { key: 'rejected_date', label: 'Rejected Date' },\n  { key: 'comment', label: 'Comment' },\n  { key: 'created_at', label: 'Created At' },\n  { key: 'updated_at', label: 'Updated At' },\n  { key: 'is_active', label: 'Active' },\n  { key: 'target_person', label: 'Target Person' },\n];\n\nconst Tooltip: React.FC<TooltipProps> = ({ visible, x, y, node, edge, content, idAttr, pinned = false, onClose }) => {\n  const [position, setPosition] = useState({ x, y });\n\n  useEffect(() => {\n    if (!visible) return;\n\n    // Adjust position to keep tooltip in viewport\n    const tooltip = document.getElementById(idAttr || 'graph-tooltip');\n    if (tooltip) {\n      const rect = tooltip.getBoundingClientRect();\n      const viewportWidth = window.innerWidth;\n      const viewportHeight = window.innerHeight;\n      \n      let adjustedX = x;\n      let adjustedY = y;\n\n      // Adjust horizontal position\n      if (x + rect.width > viewportWidth - 20) {\n        adjustedX = x - rect.width - 10;\n      }\n      \n      // Adjust vertical position\n      if (y + rect.height > viewportHeight - 20) {\n        adjustedY = y - rect.height - 10;\n      }\n\n      setPosition({ x: adjustedX, y: adjustedY });\n    } else {\n      setPosition({ x, y });\n    }\n  }, [visible, x, y, idAttr]);\n\n  if (!visible || (!node && !edge && !content)) return null;\n\n  const formatDate = (dateString?: string) => {\n    if (!dateString) return 'N/A';\n    return new Date(dateString).toLocaleDateString('en-US', {\n      year: 'numeric',\n      month: 'short',\n      day: 'numeric'\n    });\n  };\n\n  const renderNodeTooltip = (node: Node) => {\n    const missingFields = []\n    if (!node.type) missingFields.push('Type')\n    if (!node.metadata?.category) missingFields.push('Category')\n    if (!node.metadata?.description) missingFields.push('Description')\n    if (!node.image) missingFields.push('Image')\n\n    // Check if this is a virtual node for isolated edges\n    const isVirtualNode = node.metadata?.isVirtual\n    const isFloatingEdge = node.metadata?.isFloating\n\n    const propertySource = {\n      ...(node.metadata?.properties || {}),\n      ...(node.data || {}),\n    };\n\n    const detailEntries = NODE_FIELD_MAPPINGS.map(({ key, label }) => {\n      const value = propertySource?.[key];\n      if (value === null || value === undefined || value === '') {\n        return null;\n      }\n      return {\n        key,\n        label,\n        value,\n      };\n    }).filter(Boolean) as { key: string; label: string; value: any }[];\n\n    const renderValue = (val: any) => {\n      if (val === null || val === undefined) return 'N/A';\n      if (typeof val === 'boolean') return val ? 'Yes' : 'No';\n      if (val instanceof Date) return formatDate(val.toString());\n      if (typeof val === 'object') return JSON.stringify(val);\n      return String(val);\n    };\n\n    return (\n      <div className=\"relative bg-theme-card border border-theme-border rounded-lg shadow-lg p-4 max-w-xs z-50\">\n        {pinned && onClose && (\n          <button\n            onClick={onClose}\n            className=\"absolute top-2 right-2 text-theme-text-secondary hover:text-theme-text transition-colors text-xs\"\n            aria-label=\"Close tooltip\"\n          >\n            ✕\n          </button>\n        )}\n        <div className=\"flex items-start space-x-3 mb-3\">\n          {isVirtualNode ? (\n            <div className={`w-12 h-12 rounded-full flex items-center justify-center text-white text-lg font-bold flex-shrink-0 ${\n              isFloatingEdge ? 'bg-gray-800 border-2 border-gray-600' : 'bg-black border-2 border-red-500 border-dotted'\n            }`}>\n              {isFloatingEdge ? '●' : '⚠️'}\n            </div>\n          ) : node.image ? (\n            <img \n              src={node.image} \n              alt={node.label}\n              className=\"w-12 h-12 rounded-full object-cover flex-shrink-0\"\n              onError={(e) => {\n                (e.target as HTMLImageElement).style.display = 'none';\n              }}\n            />\n          ) : (\n            <div className=\"w-12 h-12 rounded-full bg-theme-bg-secondary flex items-center justify-center text-theme-text-secondary text-lg font-bold flex-shrink-0\">\n              {node.label.charAt(0).toUpperCase()}\n            </div>\n          )}\n          <div className=\"flex-1 min-w-0\">\n            <h3 className=\"font-semibold text-theme-text text-sm truncate\">{node.label}</h3>\n            <div className=\"flex items-center space-x-2 mt-1\">\n              {isVirtualNode ? (\n                <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${\n                  isFloatingEdge ? 'bg-gray-200 text-gray-800' : 'bg-red-100 text-red-800'\n                }`}>\n                  {isFloatingEdge ? 'Floating Edge' : 'Missing Node'}\n                </span>\n              ) : (\n                <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${\n                  node.type \n                    ? 'bg-theme-info/10 text-theme-info' \n                    : 'bg-theme-warning/10 text-theme-warning'\n                }`}>\n                  {node.type || 'No Type'}\n                </span>\n              )}\n              {node.metadata?.category ? (\n                <span className=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-theme-success/10 text-theme-success\">\n                  {node.metadata.category}\n                </span>\n              ) : (\n                <span className=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-theme-warning/10 text-theme-warning\">\n                  No Category\n                </span>\n              )}\n            </div>\n          </div>\n        </div>\n      \n        {isVirtualNode ? (\n          <div className=\"mb-3 p-3 bg-gray-50 rounded border border-gray-200\">\n            {isFloatingEdge ? (\n              <>\n                <div className=\"text-sm text-gray-800 font-medium mb-2\">● Floating Edge</div>\n                <p className=\"text-sm text-gray-700 mb-2\">\n                  {node.metadata?.hasEmptyFields \n                    ? 'This edge has empty source and target fields'\n                    : 'This edge has no connected nodes'\n                  }\n                </p>\n                <div className=\"text-xs text-gray-600\">\n                  <div><strong>Label:</strong> {node.metadata?.edgeLabel || 'No label'}</div>\n                  <div><strong>Source:</strong> {node.metadata?.originalSource || 'empty'} (missing)</div>\n                  <div><strong>Target:</strong> {node.metadata?.originalTarget || 'empty'} (missing)</div>\n                </div>\n              </>\n            ) : (\n              <>\n                <div className=\"text-sm text-red-800 font-medium mb-2\">⚠️ Isolated Edge Detected</div>\n                <p className=\"text-sm text-red-700 mb-2\">{node.metadata?.description}</p>\n                <div className=\"text-xs text-red-600\">\n                  <div><strong>Original ID:</strong> {node.metadata?.originalId}</div>\n                  <div><strong>Edge ID:</strong> {node.metadata?.edgeId}</div>\n                  <div><strong>Edge Label:</strong> {node.metadata?.edgeLabel || 'No label'}</div>\n                </div>\n              </>\n            )}\n          </div>\n        ) : node.metadata?.description ? (\n          <div className=\"mb-3\">\n            <p className=\"text-sm text-theme-text\">{node.metadata.description}</p>\n          </div>\n        ) : (\n          <div className=\"mb-3 p-2 bg-theme-warning/10 rounded border border-theme-warning/20\">\n            <p className=\"text-xs text-theme-warning\">⚠️ No description provided</p>\n          </div>\n        )}\n        \n        {node.metadata?.tags && node.metadata.tags.length > 0 ? (\n          <div className=\"mb-3\">\n            <p className=\"text-xs font-medium text-theme-text mb-1\">Tags:</p>\n            <div className=\"flex flex-wrap gap-1\">\n              {node.metadata.tags.map(tag => (\n                <span \n                  key={tag} \n                  className=\"inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-theme-bg-secondary text-theme-text-secondary\"\n                >\n                  {tag}\n                </span>\n              ))}\n            </div>\n          </div>\n        ) : (\n          <div className=\"mb-3 p-2 bg-theme-info/10 rounded border border-theme-info/20\">\n            <p className=\"text-xs text-theme-info\">ℹ️ No tags added</p>\n          </div>\n        )}\n\n        {missingFields.length > 0 && (\n          <div className=\"mb-3 p-2 bg-theme-warning/10 rounded border border-theme-warning/20\">\n            <p className=\"text-xs font-medium text-theme-warning mb-1\">Missing Information:</p>\n            <div className=\"flex flex-wrap gap-1\">\n              {missingFields.map(field => (\n                <span \n                  key={field} \n                  className=\"inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-theme-warning/20 text-theme-warning\"\n                >\n                  {field}\n                </span>\n              ))}\n            </div>\n          </div>\n        )}\n        \n        {detailEntries.length > 0 && (\n          <div className=\"mb-3\">\n            <p className=\"text-xs font-medium text-theme-text mb-1\">Details</p>\n            <div className=\"space-y-1 text-xs text-theme-text-secondary max-h-48 overflow-y-auto pr-1\">\n              {detailEntries.map(({ key, label, value }) => (\n                <div key={key} className=\"flex justify-between gap-2\">\n                  <span className=\"font-medium text-theme-text\">{label}:</span>\n                  <span className=\"text-right truncate flex-1\">{renderValue(value)}</span>\n                </div>\n              ))}\n            </div>\n          </div>\n        )}\n\n        <div className=\"border-t border-theme-border pt-2 mt-2 text-xs text-theme-text-secondary\">\n          <div className=\"flex justify-between items-center\">\n            <span>ID: {node.id}</span>\n            {node.metadata?.createdAt && (\n              <span>Created: {formatDate(node.metadata.createdAt)}</span>\n            )}\n          </div>\n          {node.metadata?.updatedAt && (\n            <div className=\"mt-1\">\n              <span>Updated: {formatDate(node.metadata.updatedAt)}</span>\n            </div>\n          )}\n        </div>\n      </div>\n    );\n  };\n\n  const renderEdgeTooltip = (edge: Edge) => {\n    const missingFields = []\n    if (!edge.label) missingFields.push('Label')\n\n    // Check if this is an isolated edge\n    const isIsolated = (edge as any).isIsolated\n\n    return (\n      <div className=\"relative bg-theme-card border border-theme-border rounded-lg shadow-lg p-3 max-w-xs z-50\">\n        {pinned && onClose && (\n          <button\n            onClick={onClose}\n            className=\"absolute top-2 right-2 text-theme-text-secondary hover:text-theme-text transition-colors text-xs\"\n            aria-label=\"Close tooltip\"\n          >\n            ✕\n          </button>\n        )}\n        <div className=\"mb-2\">\n          <h3 className=\"font-semibold text-theme-text text-sm\">Connection</h3>\n          <div className=\"text-sm text-theme-text mt-1\">\n            <span className=\"font-medium\">{edge.source}</span>\n            {edge.label ? (\n              <>\n                <span className=\"mx-2 text-theme-text-secondary\">→</span>\n                <span className=\"italic text-theme-accent\">{edge.label}</span>\n                <span className=\"mx-2 text-theme-text-secondary\">→</span>\n              </>\n            ) : (\n              <>\n                <span className=\"mx-2 text-theme-text-secondary\">→</span>\n                <span className=\"italic text-theme-warning\">No Label</span>\n                <span className=\"mx-2 text-theme-text-secondary\">→</span>\n              </>\n            )}\n            <span className=\"font-medium\">{edge.target}</span>\n          </div>\n          {isIsolated && (\n            <div className=\"mt-2 p-2 bg-red-50 rounded border border-red-200\">\n              <div className=\"text-xs text-red-800 font-medium\">⚠️ Isolated Edge</div>\n              <div className=\"text-xs text-red-600 mt-1\">\n                This edge references nodes that don't exist in the dataset\n              </div>\n            </div>\n          )}\n        </div>\n        \n        {edge.weight !== undefined ? (\n          <div className=\"mb-2\">\n            <span className=\"text-xs font-medium text-theme-text\">Weight: </span>\n            <span className=\"text-xs text-theme-text-secondary\">{edge.weight}</span>\n          </div>\n        ) : (\n          <div className=\"mb-2 p-2 bg-theme-info/10 rounded border border-theme-info/20\">\n            <p className=\"text-xs text-theme-info\">ℹ️ No weight specified</p>\n          </div>\n        )}\n\n        {missingFields.length > 0 && (\n          <div className=\"mb-2 p-2 bg-theme-warning/10 rounded border border-theme-warning/20\">\n            <p className=\"text-xs font-medium text-theme-warning mb-1\">Missing Information:</p>\n            <div className=\"flex flex-wrap gap-1\">\n              {missingFields.map(field => (\n                <span \n                  key={field} \n                  className=\"inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-theme-warning/20 text-theme-warning\"\n                >\n                  {field}\n                </span>\n              ))}\n            </div>\n          </div>\n        )}\n        \n        <div className=\"border-t border-theme-border pt-2 text-xs text-theme-text-secondary\">\n          <span>Edge ID: {edge.id}</span>\n        </div>\n        \n        {edge.data && Object.keys(edge.data).length > 0 ? (\n          <div className=\"mt-2 pt-2 border-t border-theme-border\">\n            <p className=\"text-xs font-medium text-theme-text mb-1\">Additional Data:</p>\n            <div className=\"text-xs text-theme-text-secondary\">\n              {Object.entries(edge.data).map(([key, value]) => (\n                <div key={key} className=\"flex justify-between\">\n                  <span className=\"capitalize\">{key}:</span>\n                  <span className=\"ml-2 truncate\">{String(value)}</span>\n                </div>\n              ))}\n            </div>\n          </div>\n        ) : (\n          <div className=\"mt-2 pt-2 border-t border-theme-border\">\n            <p className=\"text-xs text-theme-info\">ℹ️ No additional data</p>\n          </div>\n        )}\n      </div>\n    );\n  };\n\n  return (\n    <div\n      id={idAttr || 'graph-tooltip'}\n      className=\"fixed z-50\"\n      style={{\n        left: `${position.x + 10}px`,\n        top: `${position.y + 10}px`,\n        transform: visible ? 'translateY(0) opacity(1)' : 'translateY(-10px) opacity(0)',\n        transition: 'all 0.2s ease-out',\n        pointerEvents: pinned ? 'auto' : 'none',\n      }}\n    >\n      {node ? renderNodeTooltip(node) : edge ? renderEdgeTooltip(edge) : content ? (\n        <div className=\"bg-white border border-gray-300 rounded-lg shadow-lg p-4 max-w-sm z-50 relative\">\n          {pinned && onClose && (\n            <button\n              onClick={onClose}\n              className=\"absolute top-2 right-2 text-gray-500 hover:text-gray-800 text-xs\"\n              aria-label=\"Close tooltip\"\n            >\n              ✕\n            </button>\n          )}\n          {content}\n        </div>\n      ) : null}\n    </div>\n  );\n};\n\nexport default Tooltip; ","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport CytoscapeComponent from 'react-cytoscapejs';\nimport cytoscape from 'cytoscape';\nimport coseBilkent from 'cytoscape-cose-bilkent';\nimport cola from 'cytoscape-cola';\nimport avsdf from 'cytoscape-avsdf';\nimport type { GraphData, GraphLayoutOptions, Node, Edge, DetachedNodesFilter } from '../types/graph';\nimport Tooltip from './Tooltip';\n\ninterface GraphVisualizationProps {\n  data: GraphData;\n  layout?: GraphLayoutOptions;\n  style?: React.CSSProperties;\n  selectedNodeIds?: string[];\n  onNodeClick?: (nodeId: string) => void;\n  onEdgeClick?: (edgeId: string) => void;\n  onSelectionChange?: (selectedNodeIds: string[]) => void;\n  includeFilters?: string[];\n  excludeFilters?: string[];\n  onIncludeFiltersChange?: (values: string[]) => void;\n  onExcludeFiltersChange?: (values: string[]) => void;\n  graphFilter?: DetachedNodesFilter;\n  onGraphFilterChange?: (next: DetachedNodesFilter) => void;\n  filterOptions?: {\n    categories: string[];\n    types: string[];\n    tags?: string[];\n  };\n  layoutOptions?: { name: string; description: string; config: GraphLayoutOptions }[];\n  selectedLayoutName?: string;\n  onLayoutSelect?: (name: string) => void;\n  onOpenDataManager?: () => void;\n}\n\nconst defaultLayout: GraphLayoutOptions = {\n  name: 'cose',\n  animate: true,\n  padding: 50,\n  nodeSpacing: 100,\n  edgeLength: 200,\n};\n\nconst defaultStyle: React.CSSProperties = {\n  width: '100%',\n  height: '600px',\n  border: 'none',\n  borderRadius: '8px',\n  backgroundColor: 'transparent',\n};\n\n// Neo4j-inspired color palette\nconst nodeTypeColors: Record<string, string> = {\n  person: '#5dade2',       // Steel blue\n  organization: '#58d68d', // Mint green\n  website: '#f4d03f',      // Golden\n  user: '#af7ac5',         // Lavender\n  location: '#ec7063',     // Coral\n  phone: '#3498db',\n  default: '#5dade2',\n};\n\nconst neoColors = {\n  background: '#07111f',\n  grid: 'rgba(255, 255, 255, 0.04)',\n  nodeLabel: '#ecf0f1',\n  nodeHalo: '#66e0ff',\n  nodeBorder: '#102337',\n  edgeDefault: '#7fb3d5',\n  edgeHover: '#f8c471',\n  edgeSelected: '#f1948a',\n  missing: '#f5b041',\n  virtual: '#95a5a6',\n};\n\nconst identifierKeys = ['phone_number', 'phoneNumber', 'phone', 'msisdn', 'target_person'];\n\nconst createIdentifierVariants = (value: unknown): string[] => {\n  if (value === null || value === undefined) return [];\n  const raw = String(value).trim();\n  if (!raw) return [];\n  const lower = raw.toLowerCase();\n  const digits = raw.replace(/[^0-9+]/g, '');\n  const variants = new Set<string>([lower]);\n  if (digits && digits !== lower) {\n    variants.add(digits);\n  }\n  return Array.from(variants);\n};\n\nconst buildIdentifierSetFromNode = (node: Node): Set<string> => {\n  const identifiers = new Set<string>();\n  const add = (value: unknown) => {\n    createIdentifierVariants(value).forEach((variant) => identifiers.add(variant));\n  };\n\n  add(node.id);\n  add(node.label);\n  add(node.type);\n  add(node.metadata?.category);\n  add(node.metadata?.primaryPhone);\n  node.metadata?.phoneAliases?.forEach(add);\n\n  const metaProps = node.metadata?.properties || {};\n  identifierKeys.forEach((key) => add((metaProps as Record<string, any>)[key]));\n\n  const nodeData = node.data || {};\n  identifierKeys.forEach((key) => add((nodeData as Record<string, any>)[key]));\n\n  return identifiers;\n};\n\ncytoscape.use(coseBilkent);\ncytoscape.use(cola);\ncytoscape.use(avsdf);\n\nconst GraphVisualization: React.FC<GraphVisualizationProps> = ({\n  data,\n  layout = defaultLayout,\n  style = defaultStyle,\n  selectedNodeIds,\n  onNodeClick,\n  onEdgeClick,\n  onSelectionChange,\n  includeFilters = [],\n  excludeFilters = [],\n  onIncludeFiltersChange,\n  onExcludeFiltersChange,\n  graphFilter,\n  onGraphFilterChange,\n  filterOptions,\n  layoutOptions,\n  selectedLayoutName,\n  onLayoutSelect,\n  onOpenDataManager,\n}) => {\n  const cyRef = useRef<cytoscape.Core | null>(null);\n  const [zoomLevel, setZoomLevel] = useState(1);\n  const [searchQuery, setSearchQuery] = useState('');\n  const [searchResults, setSearchResults] = useState<Node[]>([]);\n  const [highlightedNodeId, setHighlightedNodeId] = useState<string | null>(null);\n  const [mousePosition, setMousePosition] = useState<{ x: number; y: number } | null>(null);\n  const [showHelpPanel, setShowHelpPanel] = useState(false);\n  const [isFullscreen, setIsFullscreen] = useState(false);\n  const canvasRef = useRef<HTMLDivElement | null>(null);\n  const [showFilterOverlay, setShowFilterOverlay] = useState(true);\n  const [includeInput, setIncludeInput] = useState('');\n  const [excludeInput, setExcludeInput] = useState('');\n  const [controlTab, setControlTab] = useState<'basic' | 'advanced'>('basic');\n  const nodeIdentifierMap = useMemo(() => {\n    const map = new Map<string, Set<string>>();\n    data.nodes.forEach((node) => {\n      map.set(node.id, buildIdentifierSetFromNode(node));\n    });\n    return map;\n  }, [data.nodes]);\n\n  const getNodesMatchingValue = useCallback(\n    (value: string) => {\n      const variants = createIdentifierVariants(value);\n      if (variants.length === 0) return [];\n      return data.nodes.filter((node) => {\n        const identifiers = nodeIdentifierMap.get(node.id);\n        if (!identifiers) return false;\n        return variants.some((variant) => identifiers.has(variant));\n      });\n    },\n    [data.nodes, nodeIdentifierMap]\n  );\n\n  const includeSummaries = useMemo(\n    () =>\n      includeFilters.map((value) => ({\n        value,\n        nodes: getNodesMatchingValue(value),\n      })),\n    [includeFilters, getNodesMatchingValue]\n  );\n\n  const excludeSummaries = useMemo(\n    () =>\n      excludeFilters.map((value) => ({\n        value,\n        nodes: getNodesMatchingValue(value),\n      })),\n    [excludeFilters, getNodesMatchingValue]\n  );\n\n  const currentFilter = graphFilter || {};\n  const filterOptionsSafe = filterOptions || { categories: [], types: [], tags: [] };\n  const filtersEnabled = !!onGraphFilterChange;\n\n  const updateGraphFilter = (patch: Partial<DetachedNodesFilter>) => {\n    if (!onGraphFilterChange) return;\n    onGraphFilterChange({\n      ...currentFilter,\n      ...patch,\n    });\n  };\n\n  const handleIncludeSubmit = () => {\n    addFilterValue(includeInput, includeFilters, onIncludeFiltersChange, () => setIncludeInput(''));\n  };\n\n  const handleExcludeSubmit = () => {\n    addFilterValue(excludeInput, excludeFilters, onExcludeFiltersChange, () => setExcludeInput(''));\n  };\n\n  const handleIncludeKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n    if (event.key === 'Enter' || event.key === ',') {\n      event.preventDefault();\n      handleIncludeSubmit();\n    }\n  };\n\n  const handleExcludeKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n    if (event.key === 'Enter' || event.key === ',') {\n      event.preventDefault();\n      handleExcludeSubmit();\n    }\n  };\n\n  \n  // Tooltip state\n  const [tooltip, setTooltip] = useState<{\n    visible: boolean;\n    x: number;\n    y: number;\n    node?: Node;\n    edge?: Edge;\n    pinned: boolean;\n  }>({\n    visible: false,\n    x: 0,\n    y: 0,\n    pinned: false,\n  });\n\n  const hideTooltip = (force = false) => {\n    setTooltip(prev => {\n      if (!force && prev.pinned) {\n        return prev;\n      }\n      return {\n        visible: false,\n        x: prev.x,\n        y: prev.y,\n        pinned: false,\n        node: undefined,\n        edge: undefined,\n      };\n    });\n  };\n\n  const addFilterValue = (\n    value: string,\n    current: string[],\n    setter?: (values: string[]) => void,\n    resetInput?: () => void,\n  ) => {\n    if (!setter) return;\n    const normalized = value.trim();\n    if (!normalized) return;\n    const exists = current.some(v => v.toLowerCase() === normalized.toLowerCase());\n    if (exists) {\n      resetInput?.();\n      return;\n    }\n    setter([...current, normalized]);\n    resetInput?.();\n  };\n\n  const removeFilterValue = (\n    value: string,\n    current: string[],\n    setter?: (values: string[]) => void,\n  ) => {\n    if (!setter) return;\n    setter(current.filter(v => v !== value));\n  };\n\n  // Create sets/maps for node bookkeeping\n  const existingNodeIds = new Set(data.nodes.map(node => node.id))\n  const augmentedNodeIds = new Set(existingNodeIds)\n  const detailNodeMap = new Map<string, cytoscape.ElementDefinition>()\n  \n  const getDetailNodeId = (detail: string, role?: 'source' | 'target') => {\n    const clean = detail.trim()\n    if (!clean) return null\n    const safe = clean.replace(/[^a-zA-Z0-9+.-]/g, '_')\n    const nodeId = `cdr-${safe}`\n    const existing = detailNodeMap.get(nodeId)\n    if (existing) {\n      if (role) {\n        const roles = new Set(existing.data.roles || [])\n        roles.add(role)\n        existing.data.roles = Array.from(roles)\n      }\n      return nodeId\n    }\n\n    const roles = role ? [role] : []\n    detailNodeMap.set(nodeId, {\n      data: {\n        id: nodeId,\n        label: clean,\n        nodeType: 'cdr',\n        detail: clean,\n        roles,\n        hasImage: false,\n        backgroundColor: '#1f3a5f',\n        missingFields: [],\n        hasMissingInfo: false,\n      },\n      classes: 'cdr-node virtual-node'\n    })\n    augmentedNodeIds.add(nodeId)\n    return nodeId\n  }\n  \n  // Find isolated edges (only when explicit node ids reference missing nodes)\n  const isolatedEdges = data.edges.filter(edge => {\n    const hasExplicitSource = !!(edge.source && edge.source.trim() !== '')\n    const hasExplicitTarget = !!(edge.target && edge.target.trim() !== '')\n    const missingSource = hasExplicitSource && !existingNodeIds.has(edge.source!)\n    const missingTarget = hasExplicitTarget && !existingNodeIds.has(edge.target!)\n    return missingSource || missingTarget\n  })\n  \n  // Create virtual nodes for isolated edges\n  const virtualNodes = isolatedEdges.map((edge) => {\n    const isSourceMissing = !existingNodeIds.has(edge.source)\n    const isTargetMissing = !existingNodeIds.has(edge.target)\n    \n    // Create virtual nodes for missing source/target\n    const virtualNodes = []\n    \n    if (isSourceMissing) {\n      virtualNodes.push({\n        id: `virtual-source-${edge.source}`,\n        label: `Missing: ${edge.source}`,\n        type: 'isolated-edge-source',\n        metadata: {\n          originalId: edge.source,\n          edgeId: edge.id,\n          edgeLabel: edge.label,\n          isVirtual: true,\n          description: `This node is referenced by edge \"${edge.label || 'unnamed'}\" but doesn't exist in the dataset.`\n        },\n        classes: 'isolated-edge-node virtual-node'\n      })\n    }\n    \n    if (isTargetMissing) {\n      virtualNodes.push({\n        id: `virtual-target-${edge.target}`,\n        label: `Missing: ${edge.target}`,\n        type: 'isolated-edge-target',\n        metadata: {\n          originalId: edge.target,\n          edgeId: edge.id,\n          edgeLabel: edge.label,\n          isVirtual: true,\n          description: `This node is referenced by edge \"${edge.label || 'unnamed'}\" but doesn't exist in the dataset.`\n        },\n        classes: 'isolated-edge-node virtual-node'\n      })\n    }\n    \n    return virtualNodes\n  }).flat()\n\n  const unmatchedEdges: Edge[] = []\n  \n  const processedEdges = data.edges.map((edge, index) => {\n    const trimmedSource = edge.source?.trim() || ''\n    const trimmedTarget = edge.target?.trim() || ''\n    \n    let sourceId: string | null = trimmedSource || null\n    let targetId: string | null = trimmedTarget || null\n    \n    if (!sourceId && edge.source_detail) {\n      sourceId = getDetailNodeId(edge.source_detail, 'source')\n    }\n    \n    if (!targetId && edge.target_detail) {\n      targetId = getDetailNodeId(edge.target_detail, 'target')\n    }\n    \n    if (!sourceId || !targetId) {\n      unmatchedEdges.push(edge)\n      return null\n    }\n    \n    const missingFields: string[] = []\n    if (!edge.label) missingFields.push('label')\n    \n    const isIsolated = !augmentedNodeIds.has(sourceId) || !augmentedNodeIds.has(targetId)\n    \n    const validEdgeId = edge.id && edge.id.trim() !== '' ? edge.id : `edge-${index}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n    \n    return {\n      originalEdge: edge,\n      elementData: {\n        ...edge,\n        id: validEdgeId,\n        source: sourceId,\n        target: targetId,\n        hasMissingInfo: missingFields.length > 0,\n        missingFields,\n        isIsolated,\n        interactionCount: 1,\n      },\n      classNames: [\n        missingFields.length > 0 ? 'has-missing-info' : 'complete-info',\n        isIsolated ? 'isolated-edge' : 'connected-edge'\n      ].join(' '),\n    }\n  }).filter(Boolean) as {\n    originalEdge: Edge\n    elementData: Edge & {\n      hasMissingInfo: boolean\n      missingFields: string[]\n      isIsolated: boolean\n      interactionCount: number\n    }\n    classNames: string\n  }[]\n\n  const aggregationMap = new Map<string, typeof processedEdges>()\n  processedEdges.forEach(edge => {\n    const key = `${edge.elementData.source}||${edge.elementData.target}`\n    const existing = aggregationMap.get(key) || []\n    existing.push(edge)\n    aggregationMap.set(key, existing)\n  })\n\n  const aggregatedEdges = Array.from(aggregationMap.values()).map((group, index) => {\n    const base = group[0]\n    const interactionCount = group.length\n    const combinedLabels = group\n      .map(item => item.originalEdge.label)\n      .filter((label): label is string => Boolean(label))\n    const aggregatedLabel =\n      interactionCount > 1\n        ? `${combinedLabels[0] || base.originalEdge.label || 'Interactions'} (${interactionCount})`\n        : combinedLabels[0] || base.originalEdge.label || ''\n    const description =\n      interactionCount > 1\n        ? `${interactionCount} interactions between ${base.elementData.source} and ${base.elementData.target}`\n        : base.originalEdge.label || 'Interaction'\n    \n    return {\n      data: {\n        ...base.elementData,\n        id:\n          interactionCount === 1\n            ? base.elementData.id\n            : `${base.elementData.source}-${base.elementData.target}-bundle-${index}`,\n        label: aggregatedLabel,\n        interactionCount,\n        interactionDescription: description,\n        aggregatedEdgeIds: group.map(item => item.elementData.id),\n        aggregatedLabels: combinedLabels,\n      },\n      classes: [\n        base.classNames,\n        interactionCount > 1 ? 'multiple-interactions' : '',\n      ]\n        .filter(Boolean)\n        .join(' '),\n    } as cytoscape.ElementDefinition\n  })\n\n  const reciprocalMap = new Map<string, cytoscape.ElementDefinition[]>()\n  aggregatedEdges.forEach(edge => {\n    const source = String(edge.data.source)\n    const target = String(edge.data.target)\n    const key = [source, target].sort().join('::')\n    const existing = reciprocalMap.get(key) || []\n    existing.push(edge)\n    reciprocalMap.set(key, existing)\n  })\n\n  reciprocalMap.forEach(edges => {\n    if (edges.length < 2) return\n    edges.forEach(edge => {\n      const existingClasses = edge.classes || []\n      const classes = Array.isArray(existingClasses)\n        ? [...existingClasses]\n        : String(existingClasses)\n            .split(' ')\n            .filter(Boolean)\n      classes.push('reciprocal-edge')\n      const source = String(edge.data.source)\n      const target = String(edge.data.target)\n      if (source.localeCompare(target) < 0) {\n        classes.push('reciprocal-forward')\n      } else {\n        classes.push('reciprocal-backward')\n      }\n      edge.classes = Array.from(new Set(classes)).join(' ')\n      edge.data = {\n        ...edge.data,\n        isReciprocal: true,\n        reciprocalKey: [source, target].sort().join('::'),\n      }\n    })\n  })\n  \n  const detailNodes = Array.from(detailNodeMap.values()).map(node => ({\n    data: node.data,\n    classes: `${node.classes} complete-info`,\n  }))\n  \n  // Create simple dark circles for completely floating edges (no ids or details)\n  const floatingVirtualNodes = unmatchedEdges.map((edge, index) => {\n    const hasEmptySource = (!edge.source || edge.source.trim() === '') && (!edge.source_detail || edge.source_detail.trim() === '')\n    const hasEmptyTarget = (!edge.target || edge.target.trim() === '') && (!edge.target_detail || edge.target_detail.trim() === '')\n    const hasEmptyBoth = hasEmptySource && hasEmptyTarget\n    \n    const validEdgeId = edge.id && edge.id.trim() !== '' ? edge.id : `floating-edge-${index}`\n    \n    return {\n      id: `floating-${validEdgeId}`,\n      label: edge.label || 'unnamed',\n      type: 'floating-edge',\n      metadata: {\n        originalEdgeId: edge.id,\n        originalSource: edge.source_detail || edge.source || 'empty',\n        originalTarget: edge.target_detail || edge.target || 'empty',\n        edgeLabel: edge.label,\n        isVirtual: true,\n        isFloating: true,\n        hasEmptyFields: hasEmptyBoth,\n        description: hasEmptyBoth \n          ? `Floating edge: ${edge.label || 'unnamed'} (no caller/callee detail)`\n          : `Floating edge: ${edge.label || 'unnamed'}`\n      },\n      classes: 'floating-edge-node'\n    }\n  })\n\n  const elements = [\n    // Regular nodes\n    ...data.nodes.map((node) => {\n      const missingFields = []\n      if (!node.type) missingFields.push('type')\n      if (!node.metadata?.category) missingFields.push('category')\n      if (!node.metadata?.description) missingFields.push('description')\n      if (!node.image) missingFields.push('image')\n\n      // Ensure node has a valid ID\n      const validNodeId = node.id && node.id.trim() !== '' ? node.id : `node-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\n\n      return {\n      data: { \n        ...node,\n          id: validNodeId,\n        // Add computed properties for styling\n        nodeType: node.type || 'default',\n        hasImage: !!node.image,\n        backgroundColor: nodeTypeColors[node.type || 'default'] || nodeTypeColors.default,\n          missingFields: missingFields,\n          hasMissingInfo: missingFields.length > 0,\n      },\n      classes: [\n        node.type ? node.type : 'default',\n          node.image ? 'has-image' : 'no-image',\n          missingFields.length > 0 ? 'has-missing-info' : 'complete-info'\n      ].join(' '),\n      }\n    }),\n    // Detail nodes synthesized from CDR data\n    ...detailNodes,\n    // Virtual nodes for isolated edges\n    ...virtualNodes.map((node) => ({\n      data: {\n        ...node,\n        nodeType: 'isolated-edge',\n        backgroundColor: '#000000',\n        hasImage: false,\n        missingFields: ['node'],\n        hasMissingInfo: true,\n      },\n      classes: 'isolated-edge-node virtual-node has-missing-info'\n    })),\n    // Virtual nodes for floating edges\n    ...floatingVirtualNodes.map((node) => ({\n      data: {\n        ...node,\n        nodeType: 'floating-edge',\n        backgroundColor: '#000000',\n        hasImage: false,\n        missingFields: ['edge'],\n        hasMissingInfo: true,\n      },\n      classes: 'floating-edge-node virtual-node has-missing-info'\n    })),\n    // Directional edges (including synthesized detail endpoints)\n    ...aggregatedEdges,\n  ];\n\n  const stylesheet: cytoscape.StylesheetCSS[] = [\n    {\n      selector: 'node',\n      css: {\n        'label': 'data(label)',\n        'color': neoColors.nodeLabel,\n        'text-valign': 'bottom',\n        'text-halign': 'center',\n        'font-size': '12px',\n        'font-weight': 600,\n        'text-outline-width': 3,\n        'text-outline-color': 'rgba(7, 17, 31, 0.85)',\n        'text-margin-y': 10,\n        'width': 65,\n        'height': 65,\n        'background-color': 'data(backgroundColor)',\n        'border-width': 3,\n        'border-color': neoColors.nodeBorder,\n        'border-opacity': 0.9,\n        'background-opacity': 0.92,\n        'shadow-blur': 20,\n        'shadow-color': 'rgba(102, 224, 255, 0.25)',\n        'shadow-offset-x': 0,\n        'shadow-offset-y': 0,\n        'transition-property': 'background-color, border-width, width, height, color, shadow-blur',\n        'transition-duration': '160ms',\n      },\n    },\n    {\n      selector: 'node.has-image',\n      css: {\n        'background-image': 'data(image)',\n        'background-fit': 'cover',\n        'background-opacity': 1,\n        'shape': 'ellipse',\n        'border-width': 3,\n        'border-color': '#ffffff1f',\n      },\n    },\n    {\n      selector: 'node.no-image',\n      css: {\n        'text-valign': 'center',\n        'text-margin-y': 0,\n      },\n    },\n    {\n      selector: 'node.person',\n      css: {\n        'shape': 'ellipse',\n      },\n    },\n    {\n      selector: 'node.organization',\n      css: {\n        'shape': 'round-rectangle',\n        'border-radius': 12,\n      },\n    },\n    {\n      selector: 'node.website',\n      css: {\n        'shape': 'diamond',\n      },\n    },\n    {\n      selector: 'node.user',\n      css: {\n        'shape': 'octagon',\n      },\n    },\n    {\n      selector: 'node.location',\n      css: {\n        'shape': 'vee',\n      },\n    },\n    {\n      selector: 'node.phone',\n      css: {\n        'shape': 'hexagon',\n        'width': 55,\n        'height': 55,\n      },\n    },\n    {\n      selector: 'node.cdr-node',\n      css: {\n        'shape': 'round-rectangle',\n        'width': 50,\n        'height': 28,\n        'background-color': '#1f3a5f',\n        'border-color': '#7fb3d5',\n        'border-width': 2,\n        'color': '#d6eaf8',\n        'font-size': '10px',\n        'text-valign': 'center',\n        'text-margin-y': 0,\n      },\n    },\n    {\n      selector: 'node:hover',\n      css: {\n        'width': 75,\n        'height': 75,\n        'border-width': 4,\n        'border-color': neoColors.nodeHalo,\n        'shadow-blur': 30,\n        'shadow-color': 'rgba(102, 224, 255, 0.4)',\n        'color': '#ffffff',\n        'font-size': '13px',\n      },\n    },\n    {\n      selector: 'node:selected',\n      css: {\n        'width': 78,\n        'height': 78,\n        'border-width': 5,\n        'border-color': neoColors.nodeHalo,\n        'background-color': 'data(backgroundColor)',\n        'shadow-blur': 35,\n        'shadow-color': 'rgba(255, 197, 120, 0.55)',\n        'color': '#ffffff',\n        'font-size': '13px',\n      },\n    },\n    {\n      selector: 'node.multi-selected',\n      css: {\n        'border-color': '#8e44ad',\n        'border-width': 4,\n      },\n    },\n    {\n      selector: 'node.has-missing-info',\n      css: {\n        'border-style': 'dashed',\n        'border-color': neoColors.missing,\n        'border-width': 3,\n        'background-opacity': 0.85,\n      },\n    },\n    {\n      selector: 'node.complete-info',\n      css: {\n        'border-style': 'solid',\n        'border-color': '#d0e8ff',\n      },\n    },\n    {\n      selector: 'node.isolated-edge-node',\n      css: {\n        'background-color': '#142034',\n        'border-color': neoColors.missing,\n        'border-width': 2,\n        'width': 22,\n        'height': 22,\n        'color': neoColors.missing,\n        'font-size': 9,\n        'text-outline-width': 2,\n      },\n    },\n    {\n      selector: 'node.virtual-node',\n      css: {\n        'background-color': '#0e1828',\n        'border-color': neoColors.virtual,\n        'border-style': 'dotted',\n        'border-width': 2,\n        'width': 24,\n        'height': 24,\n      },\n    },\n    {\n      selector: 'node.floating-edge-node',\n      css: {\n        'background-color': '#0e1828',\n        'border-color': neoColors.missing,\n        'border-width': 3,\n        'width': 36,\n        'height': 36,\n        'label': 'data(label)',\n        'color': neoColors.nodeLabel,\n        'text-outline-width': 2,\n        'text-outline-color': 'rgba(7, 17, 31, 0.9)',\n        'font-size': 10,\n        'font-weight': 600,\n      },\n    },\n    {\n      selector: 'node.highlighted',\n      css: {\n        'border-color': neoColors.nodeHalo,\n        'border-width': 5,\n        'shadow-blur': 40,\n        'shadow-color': 'rgba(102, 224, 255, 0.6)',\n      },\n    },\n    {\n      selector: 'edge',\n      css: {\n        'width': 1.8,\n        'line-color': neoColors.edgeDefault,\n        'target-arrow-color': neoColors.edgeDefault,\n        'target-arrow-shape': 'triangle',\n        'curve-style': 'bezier',\n        'opacity': 0.7,\n        'label': 'data(label)',\n        'font-size': 9,\n        'font-weight': 500,\n        'text-background-color': 'rgba(4, 9, 16, 0.8)',\n        'text-background-opacity': 0.8,\n        'text-background-padding': '2px',\n        'text-border-width': 0,\n        'color': '#d6eaf8',\n      },\n    },\n    {\n      selector: 'edge:hover',\n      css: {\n        'width': 3,\n        'line-color': neoColors.edgeHover,\n        'target-arrow-color': neoColors.edgeHover,\n        'opacity': 1,\n        'color': neoColors.edgeHover,\n        'text-background-opacity': 1,\n      },\n    },\n    {\n      selector: 'edge:selected',\n      css: {\n        'width': 3.5,\n        'line-color': neoColors.edgeSelected,\n        'target-arrow-color': neoColors.edgeSelected,\n        'color': neoColors.edgeSelected,\n        'opacity': 1,\n      },\n    },\n    {\n      selector: 'edge.has-missing-info',\n      css: {\n        'line-style': 'dashed',\n        'line-color': neoColors.missing,\n        'target-arrow-color': neoColors.missing,\n      },\n    },\n    {\n      selector: 'edge.isolated-edge',\n      css: {\n        'line-style': 'dotted',\n        'line-color': '#d98880',\n        'target-arrow-color': '#d98880',\n        'opacity': 0.6,\n      },\n    },\n    {\n      selector: 'edge.connected-edge',\n      css: {\n        'line-style': 'solid',\n      },\n    },\n    {\n      selector: 'edge.multiple-interactions',\n      css: {\n        'width': 3,\n        'color': '#f5b041',\n        'line-color': '#f5b041',\n        'target-arrow-color': '#f5b041',\n        'font-weight': 600,\n      },\n    },\n    {\n      selector: 'edge.reciprocal-edge',\n      css: {\n        'curve-style': 'unbundled-bezier',\n        'control-point-step-size': 50,\n        'opacity': 0.95,\n      },\n    },\n    {\n      selector: 'edge.reciprocal-forward',\n      css: {\n        'control-point-distance': 60,\n        'control-point-weight': 0.8,\n      },\n    },\n    {\n      selector: 'edge.reciprocal-backward',\n      css: {\n        'control-point-distance': -60,\n        'control-point-weight': 0.2,\n      },\n    },\n  ] as any;\n\n  // Center and fit the graph\n  const centerGraph = () => {\n    if (cyRef.current) {\n      cyRef.current.fit(undefined, 50); // 50px padding\n      cyRef.current.center();\n      updateZoomLevel();\n    }\n  };\n\n  // Zoom controls\n  const zoomIn = () => {\n    if (cyRef.current) {\n      cyRef.current.zoom(cyRef.current.zoom() * 1.2);\n      updateZoomLevel();\n    }\n  };\n\n  const zoomOut = () => {\n    if (cyRef.current) {\n      cyRef.current.zoom(cyRef.current.zoom() * 0.8);\n      updateZoomLevel();\n    }\n  };\n\n  const resetZoom = () => {\n    if (cyRef.current) {\n      cyRef.current.fit(undefined, 50);\n      updateZoomLevel();\n    }\n  };\n\n  const updateZoomLevel = () => {\n    if (cyRef.current) {\n      setZoomLevel(cyRef.current.zoom());\n    }\n  };\n\n  // Fit to selection\n  const fitToSelection = () => {\n    if (cyRef.current) {\n      const selected = cyRef.current.$('node:selected');\n      if (selected.length > 0) {\n        cyRef.current.fit(selected, 50);\n        updateZoomLevel();\n      } else {\n        centerGraph();\n      }\n    }\n  };\n\n  // Navigate to specific node\n  const navigateToNode = (nodeId: string) => {\n    if (cyRef.current) {\n      const node = cyRef.current.$(`#${nodeId}`);\n      if (node.length > 0) {\n        cyRef.current.fit(node, 100);\n        node.select();\n        onNodeClick?.(nodeId);\n        handleSelectionChange();\n        updateZoomLevel();\n        // Highlight briefly\n        setHighlightedNodeId(nodeId);\n        setTimeout(() => setHighlightedNodeId(null), 2000);\n      }\n    }\n  };\n\n  // Search nodes\n  useEffect(() => {\n    if (searchQuery.trim()) {\n      const query = searchQuery.toLowerCase();\n      const results = data.nodes.filter(node => \n        node.label?.toLowerCase().includes(query) ||\n        node.id.toLowerCase().includes(query) ||\n        node.type?.toLowerCase().includes(query) ||\n        node.metadata?.category?.toLowerCase().includes(query)\n      );\n      setSearchResults(results);\n    } else {\n      setSearchResults([]);\n    }\n  }, [searchQuery, data.nodes]);\n\n  // Handle selection changes\n  const handleSelectionChange = () => {\n    if (cyRef.current && onSelectionChange) {\n      const selectedNodes = cyRef.current.$('node:selected');\n      const selectedIds = selectedNodes.map(node => node.id());\n      onSelectionChange(selectedIds);\n    }\n  };\n\n  useEffect(() => {\n    if (cyRef.current) {\n      const cy = cyRef.current;\n      \n      console.log('GraphVisualization: Initializing canvas with', {\n        nodes: data.nodes.length,\n        edges: data.edges.length,\n        layout: layout.name\n      });\n\n      // Enable various selection modes\n      cy.boxSelectionEnabled(true);\n      cy.userPanningEnabled(true);\n      cy.userZoomingEnabled(true);\n\n      // Event handlers\n      cy.on('tap', 'node', (evt) => {\n        const node = evt.target;\n        const originalEvent = evt.originalEvent;\n        const renderedPosition = node.renderedPosition();\n        const containerOffset = cy.container()?.getBoundingClientRect() || { left: 0, top: 0 };\n        \n        // Handle multi-selection with Ctrl/Cmd key\n        if (originalEvent?.ctrlKey || originalEvent?.metaKey) {\n          if (node.selected()) {\n            node.unselect();\n          } else {\n            node.select();\n          }\n          hideTooltip();\n        } else {\n          // Single selection - clear others and select this one\n          cy.$('node:selected').unselect();\n          node.select();\n          onNodeClick?.(node.id());\n\n          const nodeData = data.nodes.find(n => n.id === node.id());\n          if (nodeData) {\n            setTooltip({\n              visible: true,\n              x: containerOffset.left + renderedPosition.x,\n              y: containerOffset.top + renderedPosition.y,\n              node: nodeData,\n              edge: undefined,\n              pinned: true,\n            });\n          }\n        }\n        \n        handleSelectionChange();\n      });\n\n      cy.on('tap', 'edge', (evt) => {\n        const edge = evt.target;\n        const originalEvent = evt.originalEvent;\n        \n        if (originalEvent?.ctrlKey || originalEvent?.metaKey) {\n          if (edge.selected()) {\n            edge.unselect();\n          } else {\n            edge.select();\n          }\n        } else {\n          cy.$('edge:selected').unselect();\n          edge.select();\n          onEdgeClick?.(edge.id());\n        }\n      });\n\n      // Clear selection when clicking empty space (without Ctrl/Cmd)\n      cy.on('tap', (evt) => {\n        if (evt.target === cy) {\n          const originalEvent = evt.originalEvent;\n          if (!originalEvent?.ctrlKey && !originalEvent?.metaKey) {\n            cy.$(':selected').unselect();\n            handleSelectionChange();\n            hideTooltip(true);\n          }\n        }\n      });\n\n      // Handle box selection\n      cy.on('boxend', () => {\n        handleSelectionChange();\n      });\n\n      // Tooltip event handlers\n      cy.on('mouseover', 'node', (evt) => {\n        const node = evt.target;\n        const renderedPosition = node.renderedPosition();\n        const containerOffset = cy.container()?.getBoundingClientRect() || { left: 0, top: 0 };\n        \n        // Prefer real node data; fallback to virtual node's embedded metadata to show edge info for floating nodes\n        const nodeData = data.nodes.find(n => n.id === node.id());\n        if (nodeData) {\n          setTooltip(prev => {\n            if (prev.pinned) return prev;\n            return {\n            visible: true,\n            x: containerOffset.left + renderedPosition.x,\n            y: containerOffset.top + renderedPosition.y,\n            node: nodeData,\n              edge: undefined,\n              pinned: false,\n            };\n          });\n        } else {\n          // Virtual node path (e.g., floating-edge-node). Build a minimal pseudo-edge from node data to show details\n          const nd = node.data();\n          const pseudoEdge = {\n            id: String(nd?.metadata?.originalEdgeId || nd?.id || ''),\n            source: String(nd?.metadata?.originalSource || ''),\n            target: String(nd?.metadata?.originalTarget || ''),\n            label: String(nd?.metadata?.edgeLabel || nd?.label || ''),\n            data: nd?.metadata ? { ...nd.metadata } : undefined,\n          } as Edge;\n          setTooltip(prev => {\n            if (prev.pinned) return prev;\n            return {\n            visible: true,\n            x: containerOffset.left + renderedPosition.x,\n            y: containerOffset.top + renderedPosition.y,\n              node: undefined,\n            edge: pseudoEdge,\n              pinned: false,\n            };\n          });\n        }\n      });\n\n      cy.on('mouseout', 'node', () => {\n        setTooltip(prev => prev.pinned ? prev : { ...prev, visible: false, node: undefined, edge: prev.edge, pinned: false });\n      });\n\n      cy.on('mouseover', 'edge', (evt) => {\n        const edge = evt.target;\n        const renderedMidpoint = edge.renderedMidpoint();\n        const containerOffset = cy.container()?.getBoundingClientRect() || { left: 0, top: 0 };\n        \n        const edgeData = data.edges.find(e => e.id === edge.id());\n        if (edgeData) {\n          setTooltip(prev => {\n            if (prev.pinned) return prev;\n            return {\n            visible: true,\n            x: containerOffset.left + renderedMidpoint.x,\n            y: containerOffset.top + renderedMidpoint.y,\n              node: undefined,\n            edge: edgeData,\n              pinned: false,\n            };\n          });\n        }\n      });\n\n      cy.on('mouseout', 'edge', () => {\n        setTooltip(prev => prev.pinned ? prev : { ...prev, visible: false, edge: undefined, pinned: false });\n      });\n\n      // Hide tooltip on pan/zoom\n      cy.on('pan zoom', () => {\n        setTooltip(prev => (prev.pinned ? prev : { ...prev, visible: false, pinned: false }));\n        updateZoomLevel();\n      });\n\n      // Track zoom changes\n      cy.on('zoom', () => {\n        updateZoomLevel();\n      });\n\n      // Handle keyboard shortcuts\n      const handleKeyDown = (event: KeyboardEvent) => {\n        // Allow search input to work normally\n        if ((event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) && \n            !(event.key === 'Enter' && (event.target as HTMLElement).id === 'node-search')) {\n          return;\n        }\n\n        switch (event.key.toLowerCase()) {\n          case 'a':\n            if (event.ctrlKey || event.metaKey) {\n              event.preventDefault();\n              cy.$('node').select();\n              handleSelectionChange();\n            }\n            break;\n          case 'escape':\n            if (isFullscreen) {\n              toggleFullscreen();\n            } else {\n            cy.$(':selected').unselect();\n            handleSelectionChange();\n              setSearchQuery('');\n              setSearchResults([]);\n            }\n            break;\n          case 'f':\n            if (event.ctrlKey || event.metaKey) {\n              event.preventDefault();\n              centerGraph();\n            }\n            break;\n          case '=':\n          case '+':\n            if (event.ctrlKey || event.metaKey) {\n              event.preventDefault();\n              zoomIn();\n            }\n            break;\n          case '-':\n          case '_':\n            if (event.ctrlKey || event.metaKey) {\n              event.preventDefault();\n              zoomOut();\n            }\n            break;\n          case '0':\n            if (event.ctrlKey || event.metaKey) {\n              event.preventDefault();\n              resetZoom();\n            }\n            break;\n          case 'f11':\n            event.preventDefault();\n            toggleFullscreen();\n            break;\n          case 'enter':\n            if ((event.target as HTMLElement).id === 'node-search' && searchResults.length > 0) {\n              event.preventDefault();\n              navigateToNode(searchResults[0].id);\n            }\n            break;\n          case '/':\n            if (!event.ctrlKey && !event.metaKey) {\n              event.preventDefault();\n              document.getElementById('node-search')?.focus();\n            }\n            break;\n          case 'delete':\n          case 'backspace':\n            if (event.ctrlKey || event.metaKey) {\n              event.preventDefault();\n              // Could implement node deletion here if needed\n              console.log('Delete selected nodes:', cy.$('node:selected').map(n => n.id()));\n            }\n            break;\n        }\n      };\n\n      document.addEventListener('keydown', handleKeyDown);\n\n      // Auto-center graph when data changes\n      if (data.nodes.length > 0) {\n        // Small delay to ensure layout is applied\n        setTimeout(() => {\n          centerGraph();\n        }, 100);\n      }\n\n      // Hide tooltip on window scroll/resize\n      const handleWindowEvent = () => {\n        setTooltip(prev => (prev.pinned ? prev : { ...prev, visible: false, pinned: false }));\n      };\n\n      window.addEventListener('scroll', handleWindowEvent);\n      window.addEventListener('resize', handleWindowEvent);\n\n      return () => {\n        cy.removeAllListeners();\n        document.removeEventListener('keydown', handleKeyDown);\n        window.removeEventListener('scroll', handleWindowEvent);\n        window.removeEventListener('resize', handleWindowEvent);\n      };\n    }\n  }, [onNodeClick, onEdgeClick, onSelectionChange, data]);\n\n  // Re-center when layout changes\n  useEffect(() => {\n    if (cyRef.current && data.nodes.length > 0) {\n      setTimeout(() => {\n        centerGraph();\n      }, 200);\n    }\n  }, [layout]);\n\n  // Sync external selectedNodeIds with graph selection\n  useEffect(() => {\n    if (cyRef.current && selectedNodeIds) {\n      const cy = cyRef.current;\n      \n      // Clear current selection\n      cy.$(':selected').unselect();\n      \n      // Select nodes based on selectedNodeIds\n      selectedNodeIds.forEach(nodeId => {\n        const node = cy.$(`#${nodeId}`);\n        if (node.length > 0) {\n          node.select();\n        }\n      });\n    }\n  }, [selectedNodeIds]);\n\n  // Apply highlighting to searched/highlighted nodes\n  useEffect(() => {\n    if (cyRef.current) {\n      const cy = cyRef.current;\n      \n      // Remove all highlights\n      cy.$('node').removeClass('highlighted');\n      \n      // Add highlight to searched nodes\n      searchResults.forEach(node => {\n        const cyNode = cy.$(`#${node.id}`);\n        if (cyNode.length > 0) {\n          cyNode.addClass('highlighted');\n        }\n      });\n      \n      // Add highlight to manually highlighted node\n      if (highlightedNodeId) {\n        const cyNode = cy.$(`#${highlightedNodeId}`);\n        if (cyNode.length > 0) {\n          cyNode.addClass('highlighted');\n        }\n      }\n    }\n  }, [searchResults, highlightedNodeId, data.nodes]);\n\n  // Initialize zoom level after graph loads\n  useEffect(() => {\n    if (cyRef.current && data.nodes.length > 0) {\n      const timeoutId = setTimeout(() => {\n        updateZoomLevel();\n      }, 100);\n      return () => clearTimeout(timeoutId);\n    }\n  }, [data.nodes.length]);\n\n  // Handle mouse movement for illuminating effect\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (canvasRef.current) {\n      const rect = canvasRef.current.getBoundingClientRect();\n      setMousePosition({\n        x: e.clientX - rect.left,\n        y: e.clientY - rect.top,\n      });\n    }\n  };\n\n  const handleMouseLeave = () => {\n    setMousePosition(null);\n  };\n\n  // Fullscreen functionality\n  const toggleFullscreen = async () => {\n    if (!canvasRef.current) return;\n\n    try {\n      const isCurrentlyFullscreen = !!(document.fullscreenElement || \n        (document as any).webkitFullscreenElement ||\n        (document as any).mozFullScreenElement ||\n        (document as any).msFullscreenElement);\n\n      if (!isCurrentlyFullscreen) {\n        // Enter fullscreen\n        if (canvasRef.current.requestFullscreen) {\n          await canvasRef.current.requestFullscreen();\n        } else if ((canvasRef.current as any).webkitRequestFullscreen) {\n          await (canvasRef.current as any).webkitRequestFullscreen();\n        } else if ((canvasRef.current as any).mozRequestFullScreen) {\n          await (canvasRef.current as any).mozRequestFullScreen();\n        } else if ((canvasRef.current as any).msRequestFullscreen) {\n          await (canvasRef.current as any).msRequestFullscreen();\n        }\n      } else {\n        // Exit fullscreen\n        if (document.exitFullscreen) {\n          await document.exitFullscreen();\n        } else if ((document as any).webkitExitFullscreen) {\n          await (document as any).webkitExitFullscreen();\n        } else if ((document as any).mozCancelFullScreen) {\n          await (document as any).mozCancelFullScreen();\n        } else if ((document as any).msExitFullscreen) {\n          await (document as any).msExitFullscreen();\n        }\n      }\n    } catch (error) {\n      console.error('Error toggling fullscreen:', error);\n    }\n  };\n\n  // Listen for fullscreen changes and resize canvas\n  useEffect(() => {\n    const handleFullscreenChange = () => {\n      const nowFullscreen = !!(document.fullscreenElement || \n        (document as any).webkitFullscreenElement || \n        (document as any).mozFullScreenElement ||\n        (document as any).msFullscreenElement);\n      \n      setIsFullscreen(nowFullscreen);\n      \n      // Resize canvas when entering/exiting fullscreen\n      if (cyRef.current) {\n        setTimeout(() => {\n          if (cyRef.current) {\n            cyRef.current.resize();\n            if (data.nodes.length > 0) {\n              cyRef.current.fit(undefined, 50);\n              cyRef.current.center();\n              updateZoomLevel();\n            }\n          }\n        }, 100);\n      }\n    };\n\n    document.addEventListener('fullscreenchange', handleFullscreenChange);\n    document.addEventListener('webkitfullscreenchange', handleFullscreenChange);\n    document.addEventListener('mozfullscreenchange', handleFullscreenChange);\n    document.addEventListener('MSFullscreenChange', handleFullscreenChange);\n\n    return () => {\n      document.removeEventListener('fullscreenchange', handleFullscreenChange);\n      document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);\n      document.removeEventListener('mozfullscreenchange', handleFullscreenChange);\n      document.removeEventListener('MSFullscreenChange', handleFullscreenChange);\n    };\n  }, [data.nodes.length]);\n\n  return (\n    <div \n      ref={canvasRef}\n      className={`relative w-full h-full ${isFullscreen ? 'fixed inset-0 z-50 bg-theme-bg-secondary' : ''}`}\n      id=\"graph-canvas\" \n      style={{ minHeight: isFullscreen ? '100vh' : '400px' }}\n      role=\"application\"\n      aria-label=\"Interactive network graph visualization\"\n      aria-live=\"polite\"\n      onMouseMove={handleMouseMove}\n      onMouseLeave={handleMouseLeave}\n    >\n      {/* Neo4j-inspired depth background */}\n      <div \n        className={`absolute inset-0 ${isFullscreen ? 'rounded-none' : 'rounded-lg'} overflow-hidden`}\n        style={{\n          background: `\n            radial-gradient(circle at 20% 20%, rgba(102, 224, 255, 0.15) 0%, transparent 40%),\n            radial-gradient(circle at 80% 15%, rgba(245, 176, 65, 0.15) 0%, transparent 35%),\n            linear-gradient(135deg, #050c16 0%, #0f1b2d 55%, #081225 100%)\n          `,\n          backgroundSize: '100% 100%',\n          border: isFullscreen ? 'none' : '1px solid rgba(255, 255, 255, 0.08)',\n        }}\n      />\n      \n      {/* Soft grid overlay */}\n      <div \n        className=\"absolute inset-0 pointer-events-none\"\n        style={{\n          backgroundImage: `\n            linear-gradient(${neoColors.grid} 1px, transparent 1px),\n            linear-gradient(90deg, ${neoColors.grid} 1px, transparent 1px)\n          `,\n          backgroundSize: '50px 50px',\n          opacity: 0.35,\n        }}\n      />\n      \n      {/* Corner frame markers */}\n      <div className=\"absolute top-0 left-0 w-8 h-8 border-t-2 border-l-2 border-[#66e0ff] opacity-25\" />\n      <div className=\"absolute top-0 right-0 w-8 h-8 border-t-2 border-r-2 border-[#66e0ff] opacity-25\" />\n      <div className=\"absolute bottom-0 left-0 w-8 h-8 border-b-2 border-l-2 border-[#66e0ff] opacity-25\" />\n      <div className=\"absolute bottom-0 right-0 w-8 h-8 border-b-2 border-r-2 border-[#66e0ff] opacity-25\" />\n      \n      {/* Mouse spotlight */}\n      {mousePosition && (\n        <div\n          className=\"absolute pointer-events-none transition-opacity duration-300\"\n          style={{\n            left: mousePosition.x - 200,\n            top: mousePosition.y - 200,\n            width: '400px',\n            height: '400px',\n            background: `radial-gradient(\n              circle,\n              rgba(102, 224, 255, 0.18) 0%,\n              rgba(72, 201, 176, 0.08) 30%,\n              rgba(102, 224, 255, 0.04) 55%,\n              transparent 70%\n            )`,\n            borderRadius: '50%',\n            filter: 'blur(40px)',\n            zIndex: 0,\n            opacity: 1,\n          }}\n        />\n      )}\n      \n      {/* Secondary glow */}\n      {mousePosition && (\n        <div\n          className=\"absolute pointer-events-none transition-opacity duration-200\"\n          style={{\n            left: mousePosition.x - 100,\n            top: mousePosition.y - 100,\n            width: '200px',\n            height: '200px',\n            background: `radial-gradient(\n              circle,\n              rgba(245, 208, 63, 0.12) 0%,\n              rgba(95, 189, 255, 0.08) 45%,\n              transparent 70%\n            )`,\n            borderRadius: '50%',\n            filter: 'blur(20px)',\n            zIndex: 0,\n            opacity: 0.8,\n          }}\n        />\n      )}\n\n      <CytoscapeComponent\n        elements={elements}\n        layout={layout}\n        stylesheet={stylesheet}\n        style={{\n          ...style,\n          backgroundColor: 'transparent',\n          position: 'relative',\n          zIndex: 1,\n          width: '100%',\n          height: isFullscreen ? '100vh' : style.height || '600px',\n        }}\n        cy={(cy: cytoscape.Core) => {\n          cyRef.current = cy;\n          console.log('Cytoscape canvas initialized:', cy);\n          \n          // Set canvas background to transparent\n          const container = cy.container();\n          if (container) {\n            container.style.backgroundColor = 'transparent';\n          }\n        }}\n      />\n      \n      {/* Command Center */}\n      <div\n        className=\"absolute top-2 left-2 bg-theme-card rounded-lg shadow-lg border border-theme-border p-2 space-y-2 z-20 max-w-[280px]\"\n        data-tour=\"command-center\"\n      >\n        <div className=\"flex items-center gap-1 border-b border-theme-border pb-2\">\n          {(['basic', 'advanced'] as const).map(tab => (\n            <button\n              key={tab}\n              type=\"button\"\n              onClick={() => setControlTab(tab)}\n              className={`flex-1 px-2 py-1 text-xs font-semibold rounded ${\n                controlTab === tab ? 'bg-theme-accent text-white' : 'text-theme-text-secondary hover:text-theme-text'\n              }`}\n            >\n              {tab === 'basic' ? 'Basic' : 'Advanced'}\n            </button>\n          ))}\n        </div>\n\n        {controlTab === 'basic' ? (\n          <>\n            {/* Search */}\n            <div className=\"relative\">\n              <input\n                id=\"node-search\"\n                type=\"text\"\n                value={searchQuery}\n                onChange={(e) => setSearchQuery(e.target.value)}\n                placeholder=\"Search nodes (/)\"\n                className=\"w-full px-2 py-1 text-xs border border-theme-border bg-theme-bg-secondary text-theme-text rounded focus:outline-none focus:ring-2 focus:ring-theme-accent\"\n                aria-label=\"Search nodes in graph\"\n                aria-describedby=\"search-results-count\"\n              />\n              {searchResults.length > 0 && (\n                <div className=\"absolute top-full left-0 right-0 mt-1 bg-theme-card border border-theme-border rounded shadow-lg max-h-48 overflow-y-auto z-30\">\n                  {searchResults.slice(0, 5).map((node) => (\n                    <button\n                      key={node.id}\n                      onClick={() => navigateToNode(node.id)}\n                      className=\"w-full px-2 py-1 text-left text-xs hover:bg-theme-card-hover text-theme-text flex items-center justify-between\"\n                      aria-label={`Navigate to node ${node.label}`}\n                    >\n                      <span className=\"truncate\">{node.label || node.id}</span>\n                      <span className=\"text-theme-text-secondary ml-2\">{node.type}</span>\n                    </button>\n                  ))}\n                  {searchResults.length > 5 && (\n                    <div className=\"px-2 py-1 text-xs text-theme-text-secondary text-center\">\n                      +{searchResults.length - 5} more\n                    </div>\n                  )}\n                </div>\n              )}\n              <span id=\"search-results-count\" className=\"sr-only\">\n                {searchResults.length > 0 ? `${searchResults.length} results found` : ''}\n              </span>\n            </div>\n\n            {/* Zoom Controls */}\n            <div className=\"flex items-center space-x-1 border-t border-theme-border pt-2\">\n              <button\n                onClick={zoomOut}\n                className=\"flex items-center justify-center w-7 h-7 text-xs font-medium text-theme-text hover:bg-theme-card-hover rounded transition-colors\"\n                title=\"Zoom Out (Ctrl+-)\"\n                aria-label=\"Zoom out\"\n                aria-keyshortcuts=\"Ctrl+-\"\n              >\n                <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                  <path fillRule=\"evenodd\" d=\"M3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z\" clipRule=\"evenodd\" />\n                </svg>\n              </button>\n              <button\n                onClick={resetZoom}\n                className=\"flex items-center justify-center w-7 h-7 text-xs font-medium text-theme-text hover:bg-theme-card-hover rounded transition-colors\"\n                title=\"Reset Zoom (Ctrl+0)\"\n                aria-label=\"Reset zoom to fit\"\n                aria-keyshortcuts=\"Ctrl+0\"\n              >\n                <span className=\"text-xs\">{(zoomLevel * 100).toFixed(0)}%</span>\n              </button>\n              <button\n                onClick={zoomIn}\n                className=\"flex items-center justify-center w-7 h-7 text-xs font-medium text-theme-text hover:bg-theme-card-hover rounded transition-colors\"\n                title=\"Zoom In (Ctrl++)\"\n                aria-label=\"Zoom in\"\n                aria-keyshortcuts=\"Ctrl++\"\n              >\n                <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                  <path fillRule=\"evenodd\" d=\"M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z\" clipRule=\"evenodd\" />\n                </svg>\n              </button>\n            </div>\n\n            {/* Navigation Controls */}\n            <div className=\"flex flex-col space-y-1 border-t border-theme-border pt-2\">\n              <button\n                onClick={toggleFullscreen}\n                className=\"flex items-center space-x-1 px-2 py-1 text-xs font-medium text-theme-text hover:bg-theme-card-hover rounded transition-colors\"\n                title={isFullscreen ? \"Exit Fullscreen (F11)\" : \"Enter Fullscreen (F11)\"}\n                aria-label={isFullscreen ? \"Exit fullscreen\" : \"Enter fullscreen\"}\n                aria-keyshortcuts=\"F11\"\n              >\n                {isFullscreen ? (\n                  <svg className=\"w-3 h-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                    <path fillRule=\"evenodd\" d=\"M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z\" clipRule=\"evenodd\" />\n                  </svg>\n                ) : (\n                  <svg className=\"w-3 h-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                    <path d=\"M3 4a1 1 0 011-1h4a1 1 0 010 2H6.414l2.293 2.293a1 1 0 01-1.414 1.414L5 6.414V8a1 1 0 01-2 0V4zM17 4a1 1 0 00-1-1h-4a1 1 0 100 2h1.586l-2.293 2.293a1 1 0 101.414 1.414L15 6.414V8a1 1 0 002 0V4zM3 16a1 1 0 001 1h4a1 1 0 100-2H6.414l-2.293-2.293a1 1 0 10-1.414-1.414L5 13.586V12a1 1 0 10-2 0v4zM17 16a1 1 0 01-1 1h-4a1 1 0 110-2h1.586l-2.293-2.293a1 1 0 111.414-1.414L15 13.586V12a1 1 0 112 0v4z\" />\n                  </svg>\n                )}\n                <span>{isFullscreen ? 'Exit' : 'Fullscreen'}</span>\n              </button>\n              <button\n                onClick={centerGraph}\n                className=\"flex items-center space-x-1 px-2 py-1 text-xs font-medium text-theme-text hover:bg-theme-card-hover rounded transition-colors\"\n                title=\"Center Graph (Ctrl+F)\"\n                aria-label=\"Center and fit graph\"\n                aria-keyshortcuts=\"Ctrl+F\"\n              >\n                <svg className=\"w-3 h-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                  <path fillRule=\"evenodd\" d=\"M3 4a1 1 0 011-1h4a1 1 0 010 2H6.414l2.293 2.293a1 1 0 11-1.414 1.414L5 6.414V8a1 1 0 01-2 0V4zM17 4a1 1 0 01-1 1h-1.586l-2.293 2.293a1 1 0 01-1.414-1.414L12.586 4H12a1 1 0 010-2h4a1 1 0 011 1v4a1 1 0 01-2 0V4zM3 16a1 1 0 001 1v-1.586l2.293-2.293a1 1 0 011.414 1.414L5.414 17H8a1 1 0 010 2H4a1 1 0 01-1-1v-4a1 1 0 012 0v2zM17 16a1 1 0 01-1-1v1.586l-2.293-2.293a1 1 0 00-1.414 1.414L14.586 17H12a1 1 0 000 2h4a1 1 0 001-1v-4a1 1 0 00-2 0v2z\" clipRule=\"evenodd\" />\n                </svg>\n                <span>Center</span>\n              </button>\n              <button\n                onClick={fitToSelection}\n                className=\"flex items-center space-x-1 px-2 py-1 text-xs font-medium text-theme-text hover:bg-theme-card-hover rounded transition-colors\"\n                title=\"Fit to Selection\"\n                aria-label=\"Fit view to selected nodes\"\n              >\n                <svg className=\"w-3 h-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                  <path fillRule=\"evenodd\" d=\"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z\" clipRule=\"evenodd\" />\n                </svg>\n                <span>Fit</span>\n              </button>\n              <button\n                onClick={() => {\n                  if (cyRef.current) {\n                    cyRef.current.$(':selected').unselect();\n                    handleSelectionChange();\n                  }\n                }}\n                className=\"flex items-center space-x-1 px-2 py-1 text-xs font-medium text-theme-text hover:bg-theme-card-hover rounded transition-colors\"\n                title=\"Clear Selection (Esc)\"\n                aria-label=\"Clear all selections\"\n                aria-keyshortcuts=\"Escape\"\n              >\n                <svg className=\"w-3 h-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                  <path fillRule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clipRule=\"evenodd\" />\n                </svg>\n                <span>Clear</span>\n              </button>\n            </div>\n          </>\n        ) : (\n          <div className=\"space-y-3 text-[11px] text-theme-text\">\n            {(onOpenDataManager || (layoutOptions && layoutOptions.length > 0)) && (\n              <div className=\"grid grid-cols-2 gap-2\">\n                {onOpenDataManager && (\n                  <button\n                    type=\"button\"\n                    onClick={onOpenDataManager}\n                    id=\"btn-manage-data\"\n                    className=\"px-2 py-1.5 text-xs font-semibold rounded bg-theme-accent text-white hover:bg-theme-accent-hover transition-colors\"\n                  >\n                    Manage Data\n                  </button>\n                )}\n                {layoutOptions && layoutOptions.length > 0 && (\n                  <select\n                    id=\"layout-select\"\n                    value={selectedLayoutName || layoutOptions[0].name}\n                    onChange={(e) => onLayoutSelect?.(e.target.value)}\n                    className=\"px-2 py-1.5 text-xs rounded border border-theme-border bg-theme-bg-secondary text-theme-text\"\n                  >\n                    {layoutOptions.map(option => (\n                      <option key={option.name} value={option.name}>\n                        {option.name}\n                      </option>\n                    ))}\n                  </select>\n                )}\n              </div>\n            )}\n\n            <div className=\"space-y-1 bg-theme-bg-secondary/50 rounded-md p-2 border border-theme-border/70\">\n              <input\n                type=\"text\"\n                placeholder=\"Search label, desc, tag...\"\n                value={currentFilter.searchTerm || ''}\n                onChange={(e) => updateGraphFilter({ searchTerm: e.target.value || undefined })}\n                disabled={!filtersEnabled}\n                className=\"w-full px-1.5 py-0.5 rounded border border-theme-border bg-theme-card text-theme-text focus:border-theme-accent disabled:opacity-60\"\n              />\n              <select\n                value={currentFilter.category || ''}\n                onChange={(e) => updateGraphFilter({ category: e.target.value || undefined })}\n                disabled={!filtersEnabled}\n                className=\"w-full px-1.5 py-0.5 rounded border border-theme-border bg-theme-card text-theme-text focus:border-theme-accent disabled:opacity-60\"\n              >\n                <option value=\"\">All categories</option>\n                {filterOptionsSafe.categories.map((c) => (\n                  <option key={c} value={c}>{c}</option>\n                ))}\n              </select>\n              <select\n                value={currentFilter.type || ''}\n                onChange={(e) => updateGraphFilter({ type: e.target.value || undefined })}\n                disabled={!filtersEnabled}\n                className=\"w-full px-1.5 py-0.5 rounded border border-theme-border bg-theme-card text-theme-text focus:border-theme-accent disabled:opacity-60\"\n              >\n                <option value=\"\">All types</option>\n                {filterOptionsSafe.types.map((t) => (\n                  <option key={t} value={t}>{t}</option>\n                ))}\n              </select>\n              <input\n                type=\"text\"\n                placeholder=\"tags: a,b,c\"\n                value={(currentFilter.tags || []).join(',')}\n                onChange={(e) => {\n                  const raw = e.target.value;\n                  const tags = raw.split(',').map(tag => tag.trim()).filter(Boolean);\n                  updateGraphFilter({ tags: tags.length > 0 ? tags : undefined });\n                }}\n                disabled={!filtersEnabled}\n                className=\"w-full px-1.5 py-0.5 rounded border border-theme-border bg-theme-card text-theme-text focus:border-theme-accent disabled:opacity-60\"\n              />\n            </div>\n\n            <div className=\"space-y-2 border-t border-theme-border pt-2\">\n              <div className=\"flex items-center justify-between\">\n                <span className=\"text-[11px] font-semibold uppercase tracking-wide text-theme-text\">Include / Exclude</span>\n                <button\n                  type=\"button\"\n                  onClick={() => setShowFilterOverlay(!showFilterOverlay)}\n                  className=\"text-theme-text-secondary hover:text-theme-text text-[11px]\"\n                >\n                  {showFilterOverlay ? 'Hide' : 'Show'}\n                </button>\n              </div>\n\n              {showFilterOverlay && (\n                <div className=\"space-y-3\">\n                  <div className=\"bg-theme-bg-secondary/50 rounded-md p-2 border border-theme-border/70 space-y-1\">\n                    <div className=\"flex items-center justify-between\">\n                      <span className=\"font-semibold\">Include ({includeFilters.length})</span>\n                      {!!includeFilters.length && (\n                        <button\n                          type=\"button\"\n                          onClick={() => onIncludeFiltersChange?.([])}\n                          disabled={!onIncludeFiltersChange}\n                          className=\"text-theme-text-secondary hover:text-theme-text disabled:opacity-50\"\n                        >\n                          Clear\n                        </button>\n                      )}\n                    </div>\n                    <div className=\"flex flex-wrap gap-1 min-h-[20px]\">\n                      {includeFilters.length === 0 ? (\n                        <span className=\"text-theme-text-secondary\">Showing all nodes</span>\n                      ) : (\n                        includeFilters.map(value => (\n                          <span\n                            key={value}\n                            className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full bg-theme-accent/15 text-theme-text border border-theme-accent/40\"\n                          >\n                            <span className=\"truncate max-w-[110px]\" title={value}>{value}</span>\n                            <button\n                              type=\"button\"\n                              onClick={() => removeFilterValue(value, includeFilters, onIncludeFiltersChange)}\n                              className=\"text-theme-text-secondary hover:text-theme-text\"\n                              aria-label={`Remove include ${value}`}\n                            >\n                              ✕\n                            </button>\n                          </span>\n                        ))\n                      )}\n                    </div>\n                    <div className=\"flex items-center gap-1\">\n                      <input\n                        type=\"text\"\n                        value={includeInput}\n                        onChange={(e) => setIncludeInput(e.target.value)}\n                        onKeyDown={handleIncludeKeyDown}\n                        placeholder=\"Phone or ID\"\n                        disabled={!onIncludeFiltersChange}\n                        className=\"flex-1 px-1.5 py-0.5 rounded border border-theme-border bg-theme-card text-theme-text focus:border-theme-accent disabled:opacity-60\"\n                      />\n                      <button\n                        type=\"button\"\n                        onClick={handleIncludeSubmit}\n                        disabled={!onIncludeFiltersChange || !includeInput.trim()}\n                        className=\"px-2 py-0.5 rounded bg-theme-accent text-white font-semibold disabled:opacity-50 disabled:cursor-not-allowed\"\n                      >\n                        +\n                      </button>\n                    </div>\n                    {includeSummaries.length > 0 && (\n                      <div className=\"max-h-20 overflow-y-auto rounded bg-theme-card/50 border border-theme-border/60 divide-y divide-theme-border/40 mt-1\">\n                        {includeSummaries.map(({ value, nodes }) => (\n                          <div key={`include-summary-${value}`} className=\"py-1 px-1.5\">\n                            <p className=\"font-medium truncate\">{value}</p>\n                            {nodes.length > 0 ? (\n                              <div className=\"flex flex-wrap gap-1 text-theme-text-secondary\">\n                                {nodes.slice(0, 2).map(node => (\n                                  <span key={node.id} className=\"px-1 py-0.5 rounded bg-theme-bg-secondary\">\n                                    {node.label}\n                                  </span>\n                                ))}\n                                {nodes.length > 2 && <span>+{nodes.length - 2} more</span>}\n                              </div>\n                            ) : (\n                              <p className=\"text-theme-warning\">No matches in current data</p>\n                            )}\n                          </div>\n                        ))}\n                      </div>\n                    )}\n                  </div>\n\n                  <div className=\"bg-theme-bg-secondary/50 rounded-md p-2 border border-theme-border/70 space-y-1\">\n                    <div className=\"flex items-center justify-between\">\n                      <span className=\"font-semibold\">Exclude ({excludeFilters.length})</span>\n                      {!!excludeFilters.length && (\n                        <button\n                          type=\"button\"\n                          onClick={() => onExcludeFiltersChange?.([])}\n                          disabled={!onExcludeFiltersChange}\n                          className=\"text-theme-text-secondary hover:text-theme-text disabled:opacity-50\"\n                        >\n                          Clear\n                        </button>\n                      )}\n                    </div>\n                    <div className=\"flex flex-wrap gap-1 min-h-[20px]\">\n                      {excludeFilters.length === 0 ? (\n                        <span className=\"text-theme-text-secondary\">Nothing excluded</span>\n                      ) : (\n                        excludeFilters.map(value => (\n                          <span\n                            key={value}\n                            className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full bg-theme-warning/15 text-theme-text border border-theme-warning/40\"\n                          >\n                            <span className=\"truncate max-w-[110px]\" title={value}>{value}</span>\n                            <button\n                              type=\"button\"\n                              onClick={() => removeFilterValue(value, excludeFilters, onExcludeFiltersChange)}\n                              className=\"text-theme-text-secondary hover:text-theme-text\"\n                              aria-label={`Remove exclude ${value}`}\n                            >\n                              ✕\n                            </button>\n                          </span>\n                        ))\n                      )}\n                    </div>\n                    <div className=\"flex items-center gap-1\">\n                      <input\n                        type=\"text\"\n                        value={excludeInput}\n                        onChange={(e) => setExcludeInput(e.target.value)}\n                        onKeyDown={handleExcludeKeyDown}\n                        placeholder=\"Phone or ID\"\n                        disabled={!onExcludeFiltersChange}\n                        className=\"flex-1 px-1.5 py-0.5 rounded border border-theme-border bg-theme-card text-theme-text focus:border-theme-accent disabled:opacity-60\"\n                      />\n                      <button\n                        type=\"button\"\n                        onClick={handleExcludeSubmit}\n                        disabled={!onExcludeFiltersChange || !excludeInput.trim()}\n                        className=\"px-2 py-0.5 rounded bg-theme-warning text-gray-900 font-semibold disabled:opacity-50 disabled:cursor-not-allowed\"\n                      >\n                        +\n                      </button>\n                    </div>\n                    {excludeSummaries.length > 0 && (\n                      <div className=\"max-h-20 overflow-y-auto rounded bg-theme-card/50 border border-theme-border/60 divide-y divide-theme-border/40 mt-1\">\n                        {excludeSummaries.map(({ value, nodes }) => (\n                          <div key={`exclude-summary-${value}`} className=\"py-1 px-1.5\">\n                            <p className=\"font-medium truncate\">{value}</p>\n                            {nodes.length > 0 ? (\n                              <div className=\"flex flex-wrap gap-1 text-theme-text-secondary\">\n                                {nodes.slice(0, 2).map(node => (\n                                  <span key={node.id} className=\"px-1 py-0.5 rounded bg-theme-warning/20 text-theme-text\">\n                                    {node.label}\n                                  </span>\n                                ))}\n                                {nodes.length > 2 && <span>+{nodes.length - 2} more</span>}\n                              </div>\n                            ) : (\n                              <p className=\"text-theme-text-secondary\">Hidden or not present</p>\n                            )}\n                          </div>\n                        ))}\n                      </div>\n                    )}\n                  </div>\n                </div>\n              )}\n            </div>\n          </div>\n        )}\n      </div>\n\n      {/* Toggleable Help Panel */}\n      {showHelpPanel && (\n        <div className=\"absolute bottom-2 left-2 bg-theme-card rounded-lg shadow-lg border border-theme-border p-2 text-xs text-theme-text-secondary max-w-xs z-30\">\n          <div className=\"flex items-center justify-between mb-2\">\n            <div className=\"font-semibold text-theme-text\">Navigation Guide</div>\n            <button\n              onClick={() => setShowHelpPanel(false)}\n              className=\"text-theme-text-secondary hover:text-theme-text transition-colors\"\n              aria-label=\"Hide navigation guide\"\n              title=\"Hide\"\n            >\n              <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n                <path fillRule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clipRule=\"evenodd\" />\n              </svg>\n            </button>\n          </div>\n        <div className=\"space-y-1\">\n            <div className=\"font-semibold text-theme-text mb-1\">Navigation</div>\n            <div>🔍 <strong>Search:</strong> Press / to search nodes</div>\n            <div>🔎 <strong>Zoom:</strong> Ctrl++ / Ctrl+- or mouse wheel</div>\n            <div>🎯 <strong>Reset:</strong> Ctrl+0 to reset zoom</div>\n            <div>📐 <strong>Center:</strong> Ctrl+F to center view</div>\n            <div className=\"pt-1 border-t border-theme-border mt-1 font-semibold text-theme-text\">Selection</div>\n          <div>💡 <strong>Multi-select:</strong> Ctrl+Click nodes</div>\n          <div>📦 <strong>Box select:</strong> Drag to select area</div>\n          <div>⌨️ <strong>Select all:</strong> Ctrl+A</div>\n            <div>❌ <strong>Clear:</strong> Esc to clear selection</div>\n            <div className=\"pt-1 border-t border-theme-border mt-1 font-semibold text-theme-text\">Visual Cues</div>\n            <div>⚠️ <strong>Dashed:</strong> Missing information</div>\n            <div>✅ <strong>Solid:</strong> Complete data</div>\n            <div>🖱️ <strong>Hover:</strong> See node/edge details</div>\n        </div>\n      </div>\n      )}\n      \n      {/* Help Panel Toggle Button (when hidden) */}\n      {!showHelpPanel && (\n        <button\n          onClick={() => setShowHelpPanel(true)}\n          className=\"absolute bottom-2 left-2 bg-theme-card hover:bg-theme-card-hover rounded-lg shadow-lg border border-theme-border p-2 text-xs text-theme-text-secondary hover:text-theme-text transition-colors z-30\"\n          aria-label=\"Show navigation guide\"\n          title=\"Show Navigation Guide\"\n        >\n          <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n            <path fillRule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z\" clipRule=\"evenodd\" />\n          </svg>\n        </button>\n      )}\n\n      {/* Tooltip */}\n      <Tooltip\n        visible={tooltip.visible}\n        x={tooltip.x}\n        y={tooltip.y}\n        node={tooltip.node}\n        edge={tooltip.edge}\n        pinned={tooltip.pinned}\n        onClose={() => hideTooltip(true)}\n      />\n    </div>\n  );\n};\n\nexport default GraphVisualization; ","import type { GraphData, Node, Edge } from '../types/graph'\n\nfunction generateId(prefix: string): string {\n  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n}\n\nfunction coerceStringId(value: unknown, fallbackPrefix: string): string {\n  const s = value == null ? '' : String(value).trim()\n  if (!s || s === '-' || s === 'null' || s === 'undefined') {\n    return generateId(fallbackPrefix)\n  }\n  return s\n}\n\nfunction buildLabel(record: any): string {\n  const parts: string[] = []\n  if (record.first_name) parts.push(String(record.first_name))\n  if (record.middle_name) parts.push(String(record.middle_name))\n  if (record.last_name) parts.push(String(record.last_name))\n  const full = parts.join(' ').trim()\n  if (full) return full\n  if (record.nick_name) return String(record.nick_name)\n  if (record.national_id) return String(record.national_id)\n  if (record.target_id != null) return String(record.target_id)\n  return 'Unnamed'\n}\n\nfunction isAlreadyGraphData(data: any): data is GraphData {\n  return data && Array.isArray(data.nodes) && Array.isArray(data.edges) &&\n    (data.nodes.length === 0 || typeof data.nodes[0]?.id !== 'undefined')\n}\n\nconst PHONE_KEYS = [\n  'phone_number',\n  'phoneNumber',\n  'phone',\n  'msisdn',\n  'source_detail',\n  'target_detail',\n]\n\nconst normalizePhoneValue = (value: string) => value.replace(/[^\\d+]/g, '')\nconst sanitizeId = (value: string) => value.replace(/[^a-zA-Z0-9_\\-:]/g, '_')\n\nconst findPhone = (record: any): string | null => {\n  for (const key of PHONE_KEYS) {\n    const raw = record?.[key]\n    if (raw == null) continue\n    const trimmed = String(raw).trim()\n    if (trimmed) return trimmed\n  }\n  return null\n}\n\nconst mergeMetadata = (existing?: Node['metadata'], incoming?: Node['metadata']): Node['metadata'] => {\n  if (!existing) return incoming\n  if (!incoming) return existing\n  return {\n    ...existing,\n    ...incoming,\n    tags: Array.from(new Set([...(existing.tags || []), ...(incoming.tags || [])])),\n    properties: {\n      ...(existing.properties || {}),\n      ...(incoming.properties || {}),\n    },\n    phoneAliases: Array.from(\n      new Set([...(existing.phoneAliases || []), ...(incoming.phoneAliases || [])])\n    ),\n  }\n}\n\n// Accepts multiple shapes and returns GraphData with safe IDs and fields coerced to strings\nexport function normalizeToGraphData(input: any): GraphData {\n  // If API wraps data under .data\n  const raw: any = input && input.data ? input.data : input\n\n  if (isAlreadyGraphData(raw)) {\n    // Ensure basic coercions (ids as strings, empty source/target allowed)\n    const nodes: Node[] = (raw.nodes || []).map((n: any) => {\n      const id = coerceStringId(n.id, 'node')\n      return {\n        id,\n        label: n.label || id,\n        type: n.type,\n        image: n.image,\n        metadata: n.metadata,\n        data: n.data,\n      }\n    })\n    const edges: Edge[] = (raw.edges || []).map((e: any) => {\n      const id = coerceStringId(e.id, 'edge')\n      const source = e.source == null ? '' : String(e.source)\n      const target = e.target == null ? '' : String(e.target)\n      return { id, source, target, label: e.label, weight: e.weight, data: e.data }\n    })\n    return { nodes, edges }\n  }\n\n  // New API shape example: { status, nodes: [{ target_id, ... }], edges: [{ id:'-', source:null, target:null, ... }] }\n  if (raw && Array.isArray(raw.nodes) && Array.isArray(raw.edges)) {\n    const canonicalNodes = new Map<string, Node>()\n    const aliasToCanonical = new Map<string, string>()\n    const phoneLookup = new Map<string, { id: string; label: string; raw: string }>()\n\n    const registerAlias = (alias: string | number | null | undefined, canonicalId: string) => {\n      if (alias == null) return\n      const value = String(alias).trim()\n      if (!value) return\n      aliasToCanonical.set(value, canonicalId)\n      aliasToCanonical.set(sanitizeId(value), canonicalId)\n    }\n\n    const getOrCreatePhoneId = (rawPhone: string) => {\n      const normalized = normalizePhoneValue(rawPhone.trim())\n      if (!normalized) return null\n      const existing = phoneLookup.get(normalized)\n      if (existing) return existing\n      const canonicalId = `phone-${sanitizeId(normalized)}`\n      const label = rawPhone.trim() || normalized\n      const payload = { id: canonicalId, label, raw: rawPhone.trim() || normalized }\n      phoneLookup.set(normalized, payload)\n      return payload\n    }\n\n    const ensureNode = (canonicalId: string, nodeData: Partial<Node>) => {\n      const incoming: Node = {\n        id: canonicalId,\n        label: nodeData.label || canonicalId,\n        type: nodeData.type || 'entity',\n        image: nodeData.image,\n        metadata: nodeData.metadata,\n        data: nodeData.data,\n      }\n\n      if (!canonicalNodes.has(canonicalId)) {\n        canonicalNodes.set(canonicalId, incoming)\n        return\n      }\n\n      const existing = canonicalNodes.get(canonicalId)!\n      canonicalNodes.set(canonicalId, {\n        ...existing,\n        label:\n          existing.label === existing.id && incoming.label\n            ? incoming.label\n            : existing.label || incoming.label || canonicalId,\n        type: incoming.type || existing.type,\n        image: existing.image || incoming.image,\n        metadata: mergeMetadata(existing.metadata, incoming.metadata),\n        data: {\n          ...(existing.data || {}),\n          ...(incoming.data || {}),\n        },\n      })\n    }\n\n    const ensurePhoneNode = (rawPhone: string, context?: Partial<Node>) => {\n      const payload = getOrCreatePhoneId(rawPhone)\n      if (!payload) return null\n      const metadata: Node['metadata'] = {\n        ...(context?.metadata || {}),\n        primaryPhone: rawPhone.trim(),\n        phoneAliases: Array.from(\n          new Set([...(context?.metadata?.phoneAliases || []), rawPhone.trim()])\n        ),\n        properties: {\n          ...(context?.metadata?.properties || {}),\n          phone_number: rawPhone.trim(),\n        },\n        synthetic: context?.metadata?.synthetic ?? context?.metadata?.isVirtual ?? false,\n      }\n      ensureNode(payload.id, {\n        id: payload.id,\n        label: context?.label || payload.label,\n        type: context?.type || 'phone',\n        metadata,\n        data: {\n          ...(context?.data || {}),\n          phone_number: rawPhone.trim(),\n        },\n      })\n      registerAlias(rawPhone, payload.id)\n      registerAlias(normalizePhoneValue(rawPhone), payload.id)\n      return payload.id\n    }\n\n    const resolveAlias = (value: any): string | null => {\n      if (value == null) return null\n      const str = String(value).trim()\n      if (!str) return null\n      if (aliasToCanonical.has(str)) return aliasToCanonical.get(str)!\n      const sanitized = sanitizeId(str)\n      if (aliasToCanonical.has(sanitized)) return aliasToCanonical.get(sanitized)!\n      if (canonicalNodes.has(str)) return str\n      return null\n    }\n\n    // Process base nodes and index aliases/phones\n    raw.nodes.forEach((record: any) => {\n      const phone = findPhone(record)\n      const fallbackId = coerceStringId(record.id ?? record.target_id, 'node')\n      let canonicalId = fallbackId\n\n      if (phone) {\n        const phoneInfo = getOrCreatePhoneId(phone)\n        if (phoneInfo) {\n          canonicalId = phoneInfo.id\n          registerAlias(phone, canonicalId)\n          registerAlias(normalizePhoneValue(phone), canonicalId)\n        }\n      } else {\n        canonicalId = sanitizeId(fallbackId)\n      }\n\n      registerAlias(record.id, canonicalId)\n      registerAlias(record.target_id, canonicalId)\n      registerAlias(canonicalId, canonicalId)\n\n      ensureNode(canonicalId, {\n        id: canonicalId,\n        label: buildLabel(record) || (phone || canonicalId),\n        type: record.type || (phone ? 'person' : 'entity'),\n        image: record.image_path || record.image || undefined,\n        metadata: {\n          properties: { ...record },\n          primaryPhone: phone || undefined,\n          phoneAliases: phone ? [phone] : undefined,\n          canonicalId,\n        },\n        data: { ...record, canonicalId },\n      })\n    })\n\n    const ensureGenericNode = (value: string) => {\n      const alias = resolveAlias(value)\n      if (alias) return alias\n      const sanitized = sanitizeId(value)\n      ensureNode(sanitized, {\n        id: sanitized,\n        label: value,\n        type: 'entity',\n        metadata: {\n          properties: { placeholderFrom: 'edge' },\n        },\n        data: {\n          placeholderFrom: 'edge',\n        },\n      })\n      registerAlias(value, sanitized)\n      return sanitized\n    }\n\n    const resolveFromDetail = (detail?: string | null) => {\n      if (!detail) return null\n      const phoneId = ensurePhoneNode(detail, {\n        label: detail,\n        type: 'phone',\n        metadata: {\n          synthetic: true,\n          isVirtual: true,\n        },\n      })\n      return phoneId\n    }\n\n    const edges: Edge[] = raw.edges.map((entry: any, idx: number) => {\n      const edgeId = coerceStringId(entry.id, 'edge')\n      let sourceId =\n        resolveFromDetail(entry.source_detail) ||\n        resolveAlias(entry.source) ||\n        (entry.source ? ensureGenericNode(String(entry.source)) : '')\n      let targetId =\n        resolveFromDetail(entry.target_detail) ||\n        resolveAlias(entry.target) ||\n        (entry.target ? ensureGenericNode(String(entry.target)) : '')\n\n      if (!sourceId && entry.source_detail) {\n        sourceId = ensureGenericNode(entry.source_detail)\n      }\n      if (!targetId && entry.target_detail) {\n        targetId = ensureGenericNode(entry.target_detail)\n      }\n\n      const data = { ...entry }\n      if (entry.source_detail != null) data.source_detail = entry.source_detail\n      if (entry.target_detail != null) data.target_detail = entry.target_detail\n\n      return {\n        id: edgeId || `edge-${idx}`,\n        source: sourceId || '',\n        target: targetId || '',\n        label: entry.label || entry.type || entry.relationship || undefined,\n        data,\n      }\n    })\n\n    const nodes = Array.from(canonicalNodes.values())\n    return { nodes, edges }\n  }\n\n  throw new Error('Unsupported data format: expected { nodes, edges } or API response with nodes/edges')\n}\n\n\n","import type { Node, Edge, DetachedNodeGroup, DetachedNodesFilter, OrganizationMode } from '../types/graph';\n\n/**\n * Identifies nodes that have no connections (edges)\n */\nexport function getDetachedNodes(nodes: Node[], edges: Edge[]): Node[] {\n  const connectedNodeIds = new Set<string>();\n  \n  // Collect all node IDs that appear in edges\n  edges.forEach(edge => {\n    connectedNodeIds.add(edge.source);\n    connectedNodeIds.add(edge.target);\n  });\n  \n  // Return nodes that are not in the connected set\n  return nodes.filter(node => !connectedNodeIds.has(node.id));\n}\n\n/**\n * Filters detached nodes based on provided criteria\n */\nconst normalizeValue = (value: unknown): string[] => {\n  if (value === null || value === undefined) return []\n  const raw = String(value).trim()\n  if (!raw) return []\n  const lower = raw.toLowerCase()\n  const digits = raw.replace(/[^0-9+]/g, '')\n  const variants = new Set<string>([lower])\n  if (digits && digits !== lower) {\n    variants.add(digits)\n  }\n  return Array.from(variants)\n}\n\nconst collectNodeIdentifiers = (node: Node): Set<string> => {\n  const identifiers = new Set<string>()\n  const push = (value: unknown) => {\n    normalizeValue(value).forEach(val => identifiers.add(val))\n  }\n\n  push(node.id)\n  push(node.label)\n  push(node.type)\n  push(node.metadata?.category)\n  push(node.metadata?.primaryPhone)\n  node.metadata?.phoneAliases?.forEach(push)\n\n  const properties = node.metadata?.properties || {}\n  push(properties.phone_number)\n  push(properties.phoneNumber)\n  push(properties.phone)\n  push(properties.msisdn)\n  push(properties.target_person)\n\n  const data = node.data || {}\n  push(data.phone_number)\n  push(data.phoneNumber)\n  push(data.phone)\n  push(data.msisdn)\n\n  return identifiers\n}\n\nconst matchesTerm = (identifiers: Set<string>, term: string): boolean => {\n  const normalized = normalizeValue(term)\n  if (normalized.length === 0) return false\n  return normalized.some(value => identifiers.has(value))\n}\n\nexport function filterDetachedNodes(nodes: Node[], filter: DetachedNodesFilter): Node[] {\n  return nodes.filter(node => {\n    const identifiers = collectNodeIdentifiers(node)\n\n    if (filter.includeValues && filter.includeValues.length > 0) {\n      const hasMatch = filter.includeValues.some(term => matchesTerm(identifiers, term))\n      if (!hasMatch) return false\n    }\n\n    if (filter.excludeValues && filter.excludeValues.length > 0) {\n      const isExcluded = filter.excludeValues.some(term => matchesTerm(identifiers, term))\n      if (isExcluded) return false\n    }\n\n    // Category filter\n    if (filter.category) {\n      const nodeCategory = node.metadata?.category || 'uncategorized';\n      if (nodeCategory !== filter.category) return false;\n    }\n    \n    // Type filter\n    if (filter.type) {\n      const nodeType = node.type || 'unknown';\n      if (nodeType !== filter.type) return false;\n    }\n    \n    // Tags filter\n    if (filter.tags && filter.tags.length > 0) {\n      const nodeTags = node.metadata?.tags || [];\n      const hasMatchingTag = filter.tags.some(tag => nodeTags.includes(tag));\n      if (!hasMatchingTag) return false;\n    }\n    \n    // Search term filter\n    if (filter.searchTerm) {\n      const searchTerm = filter.searchTerm.toLowerCase();\n      const matchesLabel = node.label.toLowerCase().includes(searchTerm);\n      const matchesDescription = node.metadata?.description?.toLowerCase().includes(searchTerm) || false;\n      const matchesTags = node.metadata?.tags?.some(tag => tag.toLowerCase().includes(searchTerm)) || false;\n      const matchesIdentifiers = matchesTerm(identifiers, searchTerm);\n      if (!matchesLabel && !matchesDescription && !matchesTags && !matchesIdentifiers) return false;\n    }\n    \n    return true;\n  });\n}\n\n/**\n * Groups detached nodes by the specified organization mode\n */\nexport function groupDetachedNodes(nodes: Node[], organizationMode: OrganizationMode): DetachedNodeGroup[] {\n  const groups = new Map<string, Node[]>();\n  \n  nodes.forEach(node => {\n    let groupKey: string;\n    \n    switch (organizationMode) {\n      case 'category':\n        groupKey = node.metadata?.category || 'uncategorized';\n        break;\n      case 'type':\n        groupKey = node.type || 'unknown';\n        break;\n      case 'tags':\n        const primaryTag = node.metadata?.tags?.[0] || 'untagged';\n        groupKey = primaryTag;\n        break;\n      case 'alphabetical':\n        groupKey = node.label.charAt(0).toUpperCase();\n        break;\n      case 'date':\n        const date = node.metadata?.createdAt;\n        if (date) {\n          const dateObj = new Date(date);\n          groupKey = dateObj.toISOString().split('T')[0]; // YYYY-MM-DD\n        } else {\n          groupKey = 'no date';\n        }\n        break;\n      default:\n        groupKey = 'all';\n    }\n    \n    if (!groups.has(groupKey)) {\n      groups.set(groupKey, []);\n    }\n    groups.get(groupKey)!.push(node);\n  });\n  \n  // Convert to DetachedNodeGroup array and sort\n  const result = Array.from(groups.entries()).map(([category, nodes]) => ({\n    category,\n    nodes: sortNodesInGroup(nodes, organizationMode),\n    count: nodes.length,\n  }));\n  \n  // Sort groups by category name\n  return result.sort((a, b) => {\n    // Special handling for certain categories\n    if (a.category === 'uncategorized') return 1;\n    if (b.category === 'uncategorized') return -1;\n    if (a.category === 'unknown') return 1;\n    if (b.category === 'unknown') return -1;\n    if (a.category === 'untagged') return 1;\n    if (b.category === 'untagged') return -1;\n    if (a.category === 'no date') return 1;\n    if (b.category === 'no date') return -1;\n    \n    return a.category.localeCompare(b.category);\n  });\n}\n\n/**\n * Sorts nodes within a group based on organization mode\n */\nfunction sortNodesInGroup(nodes: Node[], organizationMode: OrganizationMode): Node[] {\n  return [...nodes].sort((a, b) => {\n    switch (organizationMode) {\n      case 'date':\n        const dateA = a.metadata?.createdAt ? new Date(a.metadata.createdAt).getTime() : 0;\n        const dateB = b.metadata?.createdAt ? new Date(b.metadata.createdAt).getTime() : 0;\n        return dateB - dateA; // Most recent first\n      case 'alphabetical':\n      case 'category':\n      case 'type':\n      case 'tags':\n      default:\n        return a.label.localeCompare(b.label);\n    }\n  });\n}\n\n/**\n * Gets unique values for filter options\n */\nexport function getFilterOptions(nodes: Node[]) {\n  const categories = new Set<string>();\n  const types = new Set<string>();\n  const tags = new Set<string>();\n  \n  nodes.forEach(node => {\n    categories.add(node.metadata?.category || 'uncategorized');\n    types.add(node.type || 'unknown');\n    node.metadata?.tags?.forEach(tag => tags.add(tag));\n  });\n  \n  return {\n    categories: Array.from(categories).sort(),\n    types: Array.from(types).sort(),\n    tags: Array.from(tags).sort(),\n  };\n}\n\n/**\n * Bulk updates category for multiple nodes\n */\nexport function bulkUpdateNodeCategory(nodes: Node[], nodeIds: string[], newCategory: string): Node[] {\n  return nodes.map(node => {\n    if (nodeIds.includes(node.id)) {\n      return {\n        ...node,\n        metadata: {\n          ...node.metadata,\n          category: newCategory,\n          updatedAt: new Date().toISOString(),\n        },\n      };\n    }\n    return node;\n  });\n}\n\n/**\n * Bulk updates type for multiple nodes\n */\nexport function bulkUpdateNodeType(nodes: Node[], nodeIds: string[], newType: string): Node[] {\n  return nodes.map(node => {\n    if (nodeIds.includes(node.id)) {\n      return {\n        ...node,\n        type: newType,\n        metadata: {\n          ...node.metadata,\n          updatedAt: new Date().toISOString(),\n        },\n      };\n    }\n    return node;\n  });\n}\n\n/**\n * Adds tags to multiple nodes\n */\nexport function bulkAddTags(nodes: Node[], nodeIds: string[], newTags: string[]): Node[] {\n  return nodes.map(node => {\n    if (nodeIds.includes(node.id)) {\n      const existingTags = node.metadata?.tags || [];\n      const updatedTags = [...new Set([...existingTags, ...newTags])]; // Remove duplicates\n      return {\n        ...node,\n        metadata: {\n          ...node.metadata,\n          tags: updatedTags,\n          updatedAt: new Date().toISOString(),\n        },\n      };\n    }\n    return node;\n  });\n} ","import React, { createContext, useContext, useEffect, useState } from 'react'\n\nexport type Theme = 'light' | 'dark' | 'system'\n\ninterface ThemeContextType {\n  theme: Theme\n  setTheme: (theme: Theme) => void\n  isDark: boolean\n}\n\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined)\n\nexport const useTheme = () => {\n  const context = useContext(ThemeContext)\n  if (context === undefined) {\n    throw new Error('useTheme must be used within a ThemeProvider')\n  }\n  return context\n}\n\ninterface ThemeProviderProps {\n  children: React.ReactNode\n}\n\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {\n  const [theme, setTheme] = useState<Theme>(() => {\n    const saved = localStorage.getItem('la-theme')\n    return (saved as Theme) || 'system'\n  })\n\n  const [isDark, setIsDark] = useState(() => {\n    if (theme === 'dark') return true\n    if (theme === 'light') return false\n    return window.matchMedia('(prefers-color-scheme: dark)').matches\n  })\n\n  useEffect(() => {\n    const updateTheme = () => {\n      if (theme === 'system') {\n        setIsDark(window.matchMedia('(prefers-color-scheme: dark)').matches)\n      } else {\n        setIsDark(theme === 'dark')\n      }\n    }\n\n    updateTheme()\n    localStorage.setItem('la-theme', theme)\n\n    if (theme === 'system') {\n      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n      mediaQuery.addEventListener('change', updateTheme)\n      return () => mediaQuery.removeEventListener('change', updateTheme)\n    }\n  }, [theme])\n\n  useEffect(() => {\n    const root = document.documentElement\n    root.classList.remove('light', 'dark')\n    root.classList.add(isDark ? 'dark' : 'light')\n  }, [isDark])\n\n  return (\n    <ThemeContext.Provider value={{ theme, setTheme, isDark }}>\n      {children}\n    </ThemeContext.Provider>\n  )\n}\n"],"names":["NODE_FIELD_MAPPINGS","Tooltip","visible","x","y","node","edge","content","idAttr","pinned","onClose","position","setPosition","useState","useEffect","tooltip","rect","viewportWidth","viewportHeight","adjustedX","adjustedY","formatDate","dateString","renderNodeTooltip","missingFields","isVirtualNode","isFloatingEdge","propertySource","detailEntries","key","label","value","renderValue","val","jsxs","jsx","e","Fragment","tag","field","renderEdgeTooltip","isIsolated","defaultLayout","defaultStyle","nodeTypeColors","neoColors","identifierKeys","createIdentifierVariants","raw","lower","digits","variants","buildIdentifierSetFromNode","identifiers","add","variant","_a","_b","_d","_c","metaProps","_e","nodeData","cytoscape","coseBilkent","cola","avsdf","GraphVisualization","data","layout","style","selectedNodeIds","onNodeClick","onEdgeClick","onSelectionChange","includeFilters","excludeFilters","onIncludeFiltersChange","onExcludeFiltersChange","graphFilter","onGraphFilterChange","filterOptions","layoutOptions","selectedLayoutName","onLayoutSelect","onOpenDataManager","cyRef","useRef","zoomLevel","setZoomLevel","searchQuery","setSearchQuery","searchResults","setSearchResults","highlightedNodeId","setHighlightedNodeId","mousePosition","setMousePosition","showHelpPanel","setShowHelpPanel","isFullscreen","setIsFullscreen","canvasRef","showFilterOverlay","setShowFilterOverlay","includeInput","setIncludeInput","excludeInput","setExcludeInput","controlTab","setControlTab","nodeIdentifierMap","useMemo","map","getNodesMatchingValue","useCallback","includeSummaries","excludeSummaries","currentFilter","filterOptionsSafe","filtersEnabled","updateGraphFilter","patch","handleIncludeSubmit","addFilterValue","handleExcludeSubmit","handleIncludeKeyDown","event","handleExcludeKeyDown","setTooltip","hideTooltip","force","prev","current","setter","resetInput","normalized","v","removeFilterValue","existingNodeIds","augmentedNodeIds","detailNodeMap","getDetailNodeId","detail","role","clean","nodeId","existing","roles","virtualNodes","hasExplicitSource","hasExplicitTarget","missingSource","missingTarget","isSourceMissing","isTargetMissing","unmatchedEdges","processedEdges","index","trimmedSource","trimmedTarget","sourceId","targetId","validEdgeId","aggregationMap","aggregatedEdges","group","base","interactionCount","combinedLabels","item","aggregatedLabel","description","reciprocalMap","source","target","edges","existingClasses","classes","detailNodes","floatingVirtualNodes","hasEmptySource","hasEmptyTarget","hasEmptyBoth","elements","validNodeId","stylesheet","centerGraph","updateZoomLevel","zoomIn","zoomOut","resetZoom","fitToSelection","selected","navigateToNode","handleSelectionChange","query","results","selectedIds","cy","evt","originalEvent","renderedPosition","containerOffset","n","nd","pseudoEdge","renderedMidpoint","edgeData","handleKeyDown","toggleFullscreen","handleWindowEvent","cyNode","timeoutId","handleMouseMove","handleMouseLeave","error","handleFullscreenChange","nowFullscreen","CytoscapeComponent","container","tab","option","c","t","tags","nodes","generateId","prefix","coerceStringId","fallbackPrefix","s","buildLabel","record","parts","full","isAlreadyGraphData","PHONE_KEYS","normalizePhoneValue","sanitizeId","findPhone","trimmed","mergeMetadata","incoming","normalizeToGraphData","input","id","canonicalNodes","aliasToCanonical","phoneLookup","registerAlias","alias","canonicalId","getOrCreatePhoneId","rawPhone","payload","ensureNode","ensurePhoneNode","context","metadata","resolveAlias","str","sanitized","phone","fallbackId","phoneInfo","ensureGenericNode","resolveFromDetail","entry","idx","edgeId","normalizeValue","collectNodeIdentifiers","push","properties","matchesTerm","term","filterDetachedNodes","filter","nodeTags","searchTerm","matchesLabel","matchesDescription","matchesTags","_f","matchesIdentifiers","getFilterOptions","categories","types","ThemeContext","createContext","useTheme","useContext","ThemeProvider","children","theme","setTheme","isDark","setIsDark","updateTheme","mediaQuery","root"],"mappings":"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,iBAAkB,GAClB,qBAAsB,IACtB,cAAe,GACf,eAAgB,4BAChB,kBAAmB,EACnB,kBAAmB,EACnB,sBAAuB,oEACvB,sBAAuB,OACzB,CACF,EACA,CACE,SAAU,iBACV,IAAK,CACH,mBAAoB,cACpB,iBAAkB,QAClB,qBAAsB,EACtB,MAAS,UACT,eAAgB,EAChB,eAAgB,WAClB,CACF,EACA,CACE,SAAU,gBACV,IAAK,CACH,cAAe,SACf,gBAAiB,CACnB,CACF,EACA,CACE,SAAU,cACV,IAAK,CACH,MAAS,SACX,CACF,EACA,CACE,SAAU,oBACV,IAAK,CACH,MAAS,kBACT,gBAAiB,EACnB,CACF,EACA,CACE,SAAU,eACV,IAAK,CACH,MAAS,SACX,CACF,EACA,CACE,SAAU,YACV,IAAK,CACH,MAAS,SACX,CACF,EACA,CACE,SAAU,gBACV,IAAK,CACH,MAAS,KACX,CACF,EACA,CACE,SAAU,aACV,IAAK,CACH,MAAS,UACT,MAAS,GACT,OAAU,EACZ,CACF,EACA,CACE,SAAU,gBACV,IAAK,CACH,MAAS,kBACT,MAAS,GACT,OAAU,GACV,mBAAoB,UACpB,eAAgB,UAChB,eAAgB,EAChB,MAAS,UACT,YAAa,OACb,cAAe,SACf,gBAAiB,CACnB,CACF,EACA,CACE,SAAU,aACV,IAAK,CACH,MAAS,GACT,OAAU,GACV,eAAgB,EAChB,eAAgBA,EAAU,SAC1B,cAAe,GACf,eAAgB,2BAChB,MAAS,UACT,YAAa,MACf,CACF,EACA,CACE,SAAU,gBACV,IAAK,CACH,MAAS,GACT,OAAU,GACV,eAAgB,EAChB,eAAgBA,EAAU,SAC1B,mBAAoB,wBACpB,cAAe,GACf,eAAgB,4BAChB,MAAS,UACT,YAAa,MACf,CACF,EACA,CACE,SAAU,sBACV,IAAK,CACH,eAAgB,UAChB,eAAgB,CAClB,CACF,EACA,CACE,SAAU,wBACV,IAAK,CACH,eAAgB,SAChB,eAAgBA,EAAU,QAC1B,eAAgB,EAChB,qBAAsB,GACxB,CACF,EACA,CACE,SAAU,qBACV,IAAK,CACH,eAAgB,QAChB,eAAgB,SAClB,CACF,EACA,CACE,SAAU,0BACV,IAAK,CACH,mBAAoB,UACpB,eAAgBA,EAAU,QAC1B,eAAgB,EAChB,MAAS,GACT,OAAU,GACV,MAASA,EAAU,QACnB,YAAa,EACb,qBAAsB,CACxB,CACF,EACA,CACE,SAAU,oBACV,IAAK,CACH,mBAAoB,UACpB,eAAgBA,EAAU,QAC1B,eAAgB,SAChB,eAAgB,EAChB,MAAS,GACT,OAAU,EACZ,CACF,EACA,CACE,SAAU,0BACV,IAAK,CACH,mBAAoB,UACpB,eAAgBA,EAAU,QAC1B,eAAgB,EAChB,MAAS,GACT,OAAU,GACV,MAAS,cACT,MAASA,EAAU,UACnB,qBAAsB,EACtB,qBAAsB,uBACtB,YAAa,GACb,cAAe,GACjB,CACF,EACA,CACE,SAAU,mBACV,IAAK,CACH,eAAgBA,EAAU,SAC1B,eAAgB,EAChB,cAAe,GACf,eAAgB,0BAClB,CACF,EACA,CACE,SAAU,OACV,IAAK,CACH,MAAS,IACT,aAAcA,EAAU,YACxB,qBAAsBA,EAAU,YAChC,qBAAsB,WACtB,cAAe,SACf,QAAW,GACX,MAAS,cACT,YAAa,EACb,cAAe,IACf,wBAAyB,sBACzB,0BAA2B,GAC3B,0BAA2B,MAC3B,oBAAqB,EACrB,MAAS,SACX,CACF,EACA,CACE,SAAU,aACV,IAAK,CACH,MAAS,EACT,aAAcA,EAAU,UACxB,qBAAsBA,EAAU,UAChC,QAAW,EACX,MAASA,EAAU,UACnB,0BAA2B,CAC7B,CACF,EACA,CACE,SAAU,gBACV,IAAK,CACH,MAAS,IACT,aAAcA,EAAU,aACxB,qBAAsBA,EAAU,aAChC,MAASA,EAAU,aACnB,QAAW,CACb,CACF,EACA,CACE,SAAU,wBACV,IAAK,CACH,aAAc,SACd,aAAcA,EAAU,QACxB,qBAAsBA,EAAU,OAClC,CACF,EACA,CACE,SAAU,qBACV,IAAK,CACH,aAAc,SACd,aAAc,UACd,qBAAsB,UACtB,QAAW,EACb,CACF,EACA,CACE,SAAU,sBACV,IAAK,CACH,aAAc,OAChB,CACF,EACA,CACE,SAAU,6BACV,IAAK,CACH,MAAS,EACT,MAAS,UACT,aAAc,UACd,qBAAsB,UACtB,cAAe,GACjB,CACF,EACA,CACE,SAAU,uBACV,IAAK,CACH,cAAe,mBACf,0BAA2B,GAC3B,QAAW,GACb,CACF,EACA,CACE,SAAU,0BACV,IAAK,CACH,yBAA0B,GAC1B,uBAAwB,EAC1B,CACF,EACA,CACE,SAAU,2BACV,IAAK,CACH,yBAA0B,IAC1B,uBAAwB,EAC1B,CACF,CAAA,EAII8I,GAAc,IAAM,CACpBrG,EAAM,UACFA,EAAA,QAAQ,IAAI,OAAW,EAAE,EAC/BA,EAAM,QAAQ,SACEsG,IAClB,EAIIC,GAAS,IAAM,CACfvG,EAAM,UACRA,EAAM,QAAQ,KAAKA,EAAM,QAAQ,KAAA,EAAS,GAAG,EAC7BsG,IAClB,EAGIE,GAAU,IAAM,CAChBxG,EAAM,UACRA,EAAM,QAAQ,KAAKA,EAAM,QAAQ,KAAA,EAAS,EAAG,EAC7BsG,IAClB,EAGIG,GAAY,IAAM,CAClBzG,EAAM,UACFA,EAAA,QAAQ,IAAI,OAAW,EAAE,EACfsG,IAClB,EAGIA,EAAkB,IAAM,CACxBtG,EAAM,SACKG,EAAAH,EAAM,QAAQ,KAAM,CAAA,CACnC,EAII0G,GAAiB,IAAM,CAC3B,GAAI1G,EAAM,QAAS,CACjB,MAAM2G,EAAW3G,EAAM,QAAQ,EAAE,eAAe,EAC5C2G,EAAS,OAAS,GACd3G,EAAA,QAAQ,IAAI2G,EAAU,EAAE,EACdL,KAEJD,IAEhB,CAAA,EAIIO,GAAkBhD,GAAmB,CACzC,GAAI5D,EAAM,QAAS,CACjB,MAAMjF,EAAOiF,EAAM,QAAQ,EAAE,IAAI4D,CAAM,EAAE,EACrC7I,EAAK,OAAS,IACViF,EAAA,QAAQ,IAAIjF,EAAM,GAAG,EAC3BA,EAAK,OAAO,EACZmE,GAAA,MAAAA,EAAc0E,GACQiD,IACNP,IAEhB7F,GAAqBmD,CAAM,EAC3B,WAAW,IAAMnD,GAAqB,IAAI,EAAG,GAAI,EAErD,CAAA,EAIFjF,EAAAA,UAAU,IAAM,CACV,GAAA4E,EAAY,OAAQ,CAChB,MAAA0G,EAAQ1G,EAAY,cACpB2G,EAAUjI,EAAK,MAAM,OACzB/D,GAAA,aAAA,QAAAmD,EAAAnD,EAAK,QAAL,YAAAmD,EAAY,cAAc,SAAS4I,KACnC/L,EAAK,GAAG,YAAY,EAAE,SAAS+L,CAAK,KACpC3I,EAAApD,EAAK,OAAL,YAAAoD,EAAW,cAAc,SAAS2I,OAClC1I,GAAAC,EAAAtD,EAAK,WAAL,YAAAsD,EAAe,WAAf,YAAAD,EAAyB,cAAc,SAAS0I,IAAK,EAEvDvG,EAAiBwG,CAAO,CAAA,MAExBxG,EAAiB,CAAE,CAAA,CAEpB,EAAA,CAACH,EAAatB,EAAK,KAAK,CAAC,EAG5B,MAAM+H,EAAwB,IAAM,CAC9B,GAAA7G,EAAM,SAAWZ,EAAmB,CAEtC,MAAM4H,EADgBhH,EAAM,QAAQ,EAAE,eAAe,EACnB,IAAYjF,GAAAA,EAAK,IAAI,EACvDqE,EAAkB4H,CAAW,CAC/B,CAAA,EAGFxL,EAAAA,UAAU,IAAM,CACd,GAAIwE,EAAM,QAAS,CACjB,MAAMiH,EAAKjH,EAAM,QAEjB,QAAQ,IAAI,+CAAgD,CAC1D,MAAOlB,EAAK,MAAM,OAClB,MAAOA,EAAK,MAAM,OAClB,OAAQC,EAAO,IAAA,CAChB,EAGDkI,EAAG,oBAAoB,EAAI,EAC3BA,EAAG,mBAAmB,EAAI,EAC1BA,EAAG,mBAAmB,EAAI,EAG1BA,EAAG,GAAG,MAAO,OAASC,GAAQ,OAC5B,MAAMnM,EAAOmM,EAAI,OACXC,EAAgBD,EAAI,cACpBE,EAAmBrM,EAAK,mBACxBsM,IAAkBnJ,EAAA+I,EAAG,UAAA,IAAH,YAAA/I,EAAgB,0BAA2B,CAAE,KAAM,EAAG,IAAK,GAG/E,GAAAiJ,GAAA,MAAAA,EAAe,SAAWA,GAAA,MAAAA,EAAe,QACvCpM,EAAK,WACPA,EAAK,SAAS,EAEdA,EAAK,OAAO,EAEF6H,SACP,CAEFqE,EAAA,EAAE,eAAe,EAAE,SAAS,EAC/BlM,EAAK,OAAO,EACEmE,GAAA,MAAAA,EAAAnE,EAAK,MAEb,MAAAyD,EAAWM,EAAK,MAAM,QAAUwI,EAAE,KAAOvM,EAAK,GAAI,CAAA,EACpDyD,GACSmE,EAAA,CACT,QAAS,GACT,EAAG0E,EAAgB,KAAOD,EAAiB,EAC3C,EAAGC,EAAgB,IAAMD,EAAiB,EAC1C,KAAM5I,EACN,KAAM,OACN,OAAQ,EAAA,CACT,CAEL,CAEsBqI,GAAA,CACvB,EAEDI,EAAG,GAAG,MAAO,OAASC,GAAQ,CAC5B,MAAMlM,EAAOkM,EAAI,OACXC,EAAgBD,EAAI,cAEtBC,GAAA,MAAAA,EAAe,SAAWA,GAAA,MAAAA,EAAe,QACvCnM,EAAK,WACPA,EAAK,SAAS,EAEdA,EAAK,OAAO,GAGXiM,EAAA,EAAE,eAAe,EAAE,SAAS,EAC/BjM,EAAK,OAAO,EACEmE,GAAA,MAAAA,EAAAnE,EAAK,MACrB,CACD,EAGEiM,EAAA,GAAG,MAAQC,GAAQ,CAChB,GAAAA,EAAI,SAAWD,EAAI,CACrB,MAAME,EAAgBD,EAAI,cACtB,EAACC,GAAA,MAAAA,EAAe,UAAW,EAACA,GAAA,MAAAA,EAAe,WAC1CF,EAAA,EAAE,WAAW,EAAE,SAAS,EACLJ,IACtBjE,GAAY,EAAI,EAEpB,CAAA,CACD,EAGEqE,EAAA,GAAG,SAAU,IAAM,CACEJ,GAAA,CACvB,EAGDI,EAAG,GAAG,YAAa,OAASC,GAAQ,iBAClC,MAAMnM,EAAOmM,EAAI,OACXE,EAAmBrM,EAAK,mBACxBsM,IAAkBnJ,EAAA+I,EAAG,UAAA,IAAH,YAAA/I,EAAgB,0BAA2B,CAAE,KAAM,EAAG,IAAK,GAG7EM,EAAWM,EAAK,MAAM,QAAUwI,EAAE,KAAOvM,EAAK,GAAI,CAAA,EACxD,GAAIyD,EACFmE,EAAmBG,GACbA,EAAK,OAAeA,EACjB,CACP,QAAS,GACT,EAAGuE,EAAgB,KAAOD,EAAiB,EAC3C,EAAGC,EAAgB,IAAMD,EAAiB,EAC1C,KAAM5I,EACJ,KAAM,OACN,OAAQ,EAAA,CAEX,MACI,CAEC,MAAA+I,EAAKxM,EAAK,OACVyM,GAAa,CACjB,GAAI,SAAOrJ,EAAAoJ,GAAA,YAAAA,EAAI,WAAJ,YAAApJ,EAAc,kBAAkBoJ,GAAA,YAAAA,EAAI,KAAM,EAAE,EACvD,OAAQ,SAAOlJ,EAAAkJ,GAAA,YAAAA,EAAI,WAAJ,YAAAlJ,EAAc,iBAAkB,EAAE,EACjD,OAAQ,SAAOD,GAAAmJ,GAAA,YAAAA,EAAI,WAAJ,YAAAnJ,GAAc,iBAAkB,EAAE,EACjD,MAAO,SAAOG,GAAAgJ,GAAA,YAAAA,EAAI,WAAJ,YAAAhJ,GAAc,aAAagJ,GAAA,YAAAA,EAAI,QAAS,EAAE,EACxD,KAAMA,GAAA,MAAAA,EAAI,SAAW,CAAE,GAAGA,EAAG,QAAa,EAAA,MAAA,EAE5C5E,EAAmBG,IACbA,GAAK,OAAeA,GACjB,CACP,QAAS,GACT,EAAGuE,EAAgB,KAAOD,EAAiB,EAC3C,EAAGC,EAAgB,IAAMD,EAAiB,EACxC,KAAM,OACR,KAAMI,GACJ,OAAQ,EAAA,CAEX,CACH,CAAA,CACD,EAEEP,EAAA,GAAG,WAAY,OAAQ,IAAM,CAC9BtE,KAAmBG,EAAK,OAASA,EAAO,CAAE,GAAGA,EAAM,QAAS,GAAO,KAAM,OAAW,KAAMA,EAAK,KAAM,OAAQ,GAAO,CAAA,CACrH,EAEDmE,EAAG,GAAG,YAAa,OAASC,GAAQ,OAClC,MAAMlM,EAAOkM,EAAI,OACXO,EAAmBzM,EAAK,mBACxBqM,IAAkBnJ,EAAA+I,EAAG,UAAA,IAAH,YAAA/I,EAAgB,0BAA2B,CAAE,KAAM,EAAG,IAAK,GAE7EwJ,EAAW5I,EAAK,MAAM,QAAUhC,EAAE,KAAO9B,EAAK,GAAI,CAAA,EACpD0M,GACF/E,EAAmBG,GACbA,EAAK,OAAeA,EACjB,CACP,QAAS,GACT,EAAGuE,EAAgB,KAAOI,EAAiB,EAC3C,EAAGJ,EAAgB,IAAMI,EAAiB,EACxC,KAAM,OACR,KAAMC,EACJ,OAAQ,EAAA,CAEX,CACH,CACD,EAEET,EAAA,GAAG,WAAY,OAAQ,IAAM,CAC9BtE,EAAmBG,GAAAA,EAAK,OAASA,EAAO,CAAE,GAAGA,EAAM,QAAS,GAAO,KAAM,OAAW,OAAQ,GAAO,CAAA,CACpG,EAGEmE,EAAA,GAAG,WAAY,IAAM,CACXtE,EAAAG,GAASA,EAAK,OAASA,EAAO,CAAE,GAAGA,EAAM,QAAS,GAAO,OAAQ,EAAQ,CAAA,EACpEwD,GAAA,CACjB,EAGEW,EAAA,GAAG,OAAQ,IAAM,CACFX,GAAA,CACjB,EAGK,MAAAqB,EAAiBlF,GAAyB,OAE9C,GAAK,GAAAA,EAAM,kBAAkB,kBAAoBA,EAAM,kBAAkB,sBACrE,EAAEA,EAAM,MAAQ,SAAYA,EAAM,OAAuB,KAAO,gBAI5D,OAAAA,EAAM,IAAI,YAAe,EAAA,CAC/B,IAAK,KACCA,EAAM,SAAWA,EAAM,WACzBA,EAAM,eAAe,EAClBwE,EAAA,EAAE,MAAM,EAAE,OAAO,EACEJ,KAExB,MACF,IAAK,SACC/F,EACe8G,MAEhBX,EAAA,EAAE,WAAW,EAAE,SAAS,EACLJ,IACpBxG,EAAe,EAAE,EACjBE,EAAiB,CAAE,CAAA,GAErB,MACF,IAAK,KACCkC,EAAM,SAAWA,EAAM,WACzBA,EAAM,eAAe,EACT4D,MAEd,MACF,IAAK,IACL,IAAK,KACC5D,EAAM,SAAWA,EAAM,WACzBA,EAAM,eAAe,EACd8D,MAET,MACF,IAAK,IACL,IAAK,KACC9D,EAAM,SAAWA,EAAM,WACzBA,EAAM,eAAe,EACb+D,MAEV,MACF,IAAK,KACC/D,EAAM,SAAWA,EAAM,WACzBA,EAAM,eAAe,EACXgE,MAEZ,MACF,IAAK,MACHhE,EAAM,eAAe,EACJmF,KACjB,MACF,IAAK,QACEnF,EAAM,OAAuB,KAAO,eAAiBnC,EAAc,OAAS,IAC/EmC,EAAM,eAAe,EACNmE,GAAAtG,EAAc,CAAC,EAAE,EAAE,GAEpC,MACF,IAAK,IACC,CAACmC,EAAM,SAAW,CAACA,EAAM,UAC3BA,EAAM,eAAe,GACZvE,EAAA,SAAA,eAAe,aAAa,IAA5B,MAAAA,EAA+B,SAE1C,MACF,IAAK,SACL,IAAK,aACCuE,EAAM,SAAWA,EAAM,WACzBA,EAAM,eAAe,EAEb,QAAA,IAAI,yBAA0BwE,EAAG,EAAE,eAAe,EAAE,IAASK,GAAAA,EAAE,GAAG,CAAC,CAAC,GAE9E,KACJ,CAAA,EAGO,SAAA,iBAAiB,UAAWK,CAAa,EAG9C7I,EAAK,MAAM,OAAS,GAEtB,WAAW,IAAM,CACHuH,MACX,GAAG,EAIR,MAAMwB,EAAoB,IAAM,CACnBlF,EAAAG,GAASA,EAAK,OAASA,EAAO,CAAE,GAAGA,EAAM,QAAS,GAAO,OAAQ,EAAQ,CAAA,CAAA,EAG/E,cAAA,iBAAiB,SAAU+E,CAAiB,EAC5C,OAAA,iBAAiB,SAAUA,CAAiB,EAE5C,IAAM,CACXZ,EAAG,mBAAmB,EACb,SAAA,oBAAoB,UAAWU,CAAa,EAC9C,OAAA,oBAAoB,SAAUE,CAAiB,EAC/C,OAAA,oBAAoB,SAAUA,CAAiB,CAAA,CAE1D,GACC,CAAC3I,EAAaC,EAAaC,EAAmBN,CAAI,CAAC,EAGtDtD,EAAAA,UAAU,IAAM,CACVwE,EAAM,SAAWlB,EAAK,MAAM,OAAS,GACvC,WAAW,IAAM,CACHuH,MACX,GAAG,CACR,EACC,CAACtH,CAAM,CAAC,EAGXvD,EAAAA,UAAU,IAAM,CACV,GAAAwE,EAAM,SAAWf,EAAiB,CACpC,MAAMgI,EAAKjH,EAAM,QAGdiH,EAAA,EAAE,WAAW,EAAE,SAAS,EAG3BhI,EAAgB,QAAkB2E,GAAA,CAChC,MAAM7I,EAAOkM,EAAG,EAAE,IAAIrD,CAAM,EAAE,EAC1B7I,EAAK,OAAS,GAChBA,EAAK,OAAO,CACd,CACD,CACH,CAAA,EACC,CAACkE,CAAe,CAAC,EAGpBzD,EAAAA,UAAU,IAAM,CACd,GAAIwE,EAAM,QAAS,CACjB,MAAMiH,EAAKjH,EAAM,QAcjB,GAXAiH,EAAG,EAAE,MAAM,EAAE,YAAY,aAAa,EAGtC3G,EAAc,QAAgBvF,GAAA,CAC5B,MAAM+M,EAASb,EAAG,EAAE,IAAIlM,EAAK,EAAE,EAAE,EAC7B+M,EAAO,OAAS,GAClBA,EAAO,SAAS,aAAa,CAC/B,CACD,EAGGtH,EAAmB,CACrB,MAAMsH,EAASb,EAAG,EAAE,IAAIzG,CAAiB,EAAE,EACvCsH,EAAO,OAAS,GAClBA,EAAO,SAAS,aAAa,CAEjC,CACF,GACC,CAACxH,EAAeE,EAAmB1B,EAAK,KAAK,CAAC,EAGjDtD,EAAAA,UAAU,IAAM,CACd,GAAIwE,EAAM,SAAWlB,EAAK,MAAM,OAAS,EAAG,CACpC,MAAAiJ,EAAY,WAAW,IAAM,CACjBzB,KACf,GAAG,EACC,MAAA,IAAM,aAAayB,CAAS,CACrC,CACC,EAAA,CAACjJ,EAAK,MAAM,MAAM,CAAC,EAGhB,MAAAkJ,GAAmB,GAAwC,CAC/D,GAAIhH,EAAU,QAAS,CACf,MAAAtF,EAAOsF,EAAU,QAAQ,sBAAsB,EACpCL,GAAA,CACf,EAAG,EAAE,QAAUjF,EAAK,KACpB,EAAG,EAAE,QAAUA,EAAK,GAAA,CACrB,CACH,CAAA,EAGIuM,GAAmB,IAAM,CAC7BtH,GAAiB,IAAI,CAAA,EAIjBiH,GAAmB,SAAY,CACnC,GAAK5G,EAAU,QAEX,GAAA,CAC4B,CAAC,EAAE,SAAS,mBACvC,SAAiB,yBACjB,SAAiB,sBACjB,SAAiB,qBAed,SAAS,eACX,MAAM,SAAS,iBACL,SAAiB,qBAC3B,MAAO,SAAiB,uBACd,SAAiB,oBAC3B,MAAO,SAAiB,sBACd,SAAiB,kBAC3B,MAAO,SAAiB,mBAlBtBA,EAAU,QAAQ,kBACd,MAAAA,EAAU,QAAQ,oBACdA,EAAU,QAAgB,wBAC7B,MAAAA,EAAU,QAAgB,0BACvBA,EAAU,QAAgB,qBAC7B,MAAAA,EAAU,QAAgB,uBACvBA,EAAU,QAAgB,qBAC7B,MAAAA,EAAU,QAAgB,4BAc9BkH,EAAO,CACN,QAAA,MAAM,6BAA8BA,CAAK,CACnD,CAAA,EAIF1M,OAAAA,EAAAA,UAAU,IAAM,CACd,MAAM2M,EAAyB,IAAM,CAC7B,MAAAC,EAAgB,CAAC,EAAE,SAAS,mBAC/B,SAAiB,yBACjB,SAAiB,sBACjB,SAAiB,qBAEpBrH,GAAgBqH,CAAa,EAGzBpI,EAAM,SACR,WAAW,IAAM,CACXA,EAAM,UACRA,EAAM,QAAQ,SACVlB,EAAK,MAAM,OAAS,IAChBkB,EAAA,QAAQ,IAAI,OAAW,EAAE,EAC/BA,EAAM,QAAQ,SACEsG,OAGnB,GAAG,CACR,EAGO,gBAAA,iBAAiB,mBAAoB6B,CAAsB,EAC3D,SAAA,iBAAiB,yBAA0BA,CAAsB,EACjE,SAAA,iBAAiB,sBAAuBA,CAAsB,EAC9D,SAAA,iBAAiB,qBAAsBA,CAAsB,EAE/D,IAAM,CACF,SAAA,oBAAoB,mBAAoBA,CAAsB,EAC9D,SAAA,oBAAoB,yBAA0BA,CAAsB,EACpE,SAAA,oBAAoB,sBAAuBA,CAAsB,EACjE,SAAA,oBAAoB,qBAAsBA,CAAsB,CAAA,CAE1E,EAAA,CAACrJ,EAAK,MAAM,MAAM,CAAC,EAGpBlC,EAAA,KAAC,MAAA,CACC,IAAKoE,EACL,UAAW,0BAA0BF,EAAe,2CAA6C,EAAE,GACnG,GAAG,eACH,MAAO,CAAE,UAAWA,EAAe,QAAU,OAAQ,EACrD,KAAK,cACL,aAAW,0CACX,YAAU,SACV,YAAakH,GACb,aAAcC,GAGd,SAAA,CAAApL,EAAA,IAAC,MAAA,CACC,UAAW,oBAAoBiE,EAAe,eAAiB,YAAY,mBAC3E,MAAO,CACL,WAAY;AAAA;AAAA;AAAA;AAAA,YAKZ,eAAgB,YAChB,OAAQA,EAAe,OAAS,qCAClC,CAAA,CACF,EAGAjE,EAAA,IAAC,MAAA,CACC,UAAU,uCACV,MAAO,CACL,gBAAiB;AAAA,8BACGU,EAAU,IAAI;AAAA,qCACPA,EAAU,IAAI;AAAA,YAEzC,eAAgB,YAChB,QAAS,GACX,CAAA,CACF,EAGAV,EAAAA,IAAC,MAAI,CAAA,UAAU,iFAAkF,CAAA,EACjGA,EAAAA,IAAC,MAAI,CAAA,UAAU,kFAAmF,CAAA,EAClGA,EAAAA,IAAC,MAAI,CAAA,UAAU,oFAAqF,CAAA,EACpGA,EAAAA,IAAC,MAAI,CAAA,UAAU,qFAAsF,CAAA,EAGpG6D,GACC7D,EAAA,IAAC,MAAA,CACC,UAAU,+DACV,MAAO,CACL,KAAM6D,EAAc,EAAI,IACxB,IAAKA,EAAc,EAAI,IACvB,MAAO,QACP,OAAQ,QACR,WAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAOZ,aAAc,MACd,OAAQ,aACR,OAAQ,EACR,QAAS,CACX,CAAA,CACF,EAIDA,GACC7D,EAAA,IAAC,MAAA,CACC,UAAU,+DACV,MAAO,CACL,KAAM6D,EAAc,EAAI,IACxB,IAAKA,EAAc,EAAI,IACvB,MAAO,QACP,OAAQ,QACR,WAAY;AAAA;AAAA;AAAA;AAAA;AAAA,eAMZ,aAAc,MACd,OAAQ,aACR,OAAQ,EACR,QAAS,EACX,CAAA,CACF,EAGF7D,EAAA,IAACwL,GAAA,CACC,SAAAnC,GACA,OAAAnH,EACA,WAAAqH,GACA,MAAO,CACL,GAAGpH,EACH,gBAAiB,cACjB,SAAU,WACV,OAAQ,EACR,MAAO,OACP,OAAQ8B,EAAe,QAAU9B,EAAM,QAAU,OACnD,EACA,GAAKiI,GAAuB,CAC1BjH,EAAM,QAAUiH,EACR,QAAA,IAAI,gCAAiCA,CAAE,EAGzC,MAAAqB,EAAYrB,EAAG,YACjBqB,IACFA,EAAU,MAAM,gBAAkB,cAEtC,CAAA,CACF,EAGA1L,EAAA,KAAC,MAAA,CACC,UAAU,uHACV,YAAU,iBAEV,SAAA,CAACC,EAAAA,IAAA,MAAA,CAAI,UAAU,4DACX,SAAA,CAAC,QAAS,UAAU,EAAY,IAChC0L,GAAA1L,EAAA,IAAC,SAAA,CAEC,KAAK,SACL,QAAS,IAAM2E,EAAc+G,CAAG,EAChC,UAAW,kDACThH,IAAegH,EAAM,6BAA+B,iDACtD,GAEC,SAAAA,IAAQ,QAAU,QAAU,UAAA,EAPxBA,CASR,CAAA,EACH,EAEChH,IAAe,QAGZ3E,EAAAA,KAAAG,EAAA,SAAA,CAAA,SAAA,CAACH,EAAAA,KAAA,MAAA,CAAI,UAAU,WACb,SAAA,CAAAC,EAAA,IAAC,QAAA,CACC,GAAG,cACH,KAAK,OACL,MAAOuD,EACP,SAAW,GAAMC,EAAe,EAAE,OAAO,KAAK,EAC9C,YAAY,mBACZ,UAAU,4JACV,aAAW,wBACX,mBAAiB,sBAAA,CACnB,EACCC,EAAc,OAAS,GACrB1D,EAAA,KAAA,MAAA,CAAI,UAAU,iIACZ,SAAA,CAAA0D,EAAc,MAAM,EAAG,CAAC,EAAE,IAAKvF,GAC9B6B,EAAA,KAAC,SAAA,CAEC,QAAS,IAAMgK,GAAe7L,EAAK,EAAE,EACrC,UAAU,iHACV,aAAY,oBAAoBA,EAAK,KAAK,GAE1C,SAAA,CAAA8B,MAAC,QAAK,UAAU,WAAY,SAAK9B,EAAA,OAASA,EAAK,GAAG,EACjD8B,EAAA,IAAA,OAAA,CAAK,UAAU,iCAAkC,WAAK,KAAK,CAAA,CAAA,EANvD9B,EAAK,EAAA,CAQb,EACAuF,EAAc,OAAS,GACrB1D,EAAA,KAAA,MAAA,CAAI,UAAU,0DAA0D,SAAA,CAAA,IACrE0D,EAAc,OAAS,EAAE,OAAA,EAC7B,CAAA,EAEJ,EAEDzD,EAAA,IAAA,OAAA,CAAK,GAAG,uBAAuB,UAAU,UACvC,SAAcyD,EAAA,OAAS,EAAI,GAAGA,EAAc,MAAM,iBAAmB,GACxE,CAAA,EACF,EAGA1D,EAAAA,KAAC,MAAI,CAAA,UAAU,gEACb,SAAA,CAAAC,EAAA,IAAC,SAAA,CACC,QAAS2J,GACT,UAAU,mIACV,MAAM,oBACN,aAAW,WACX,oBAAkB,SAElB,eAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAAC3J,EAAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,mDAAmD,SAAS,SAAU,CAAA,EACnG,CAAA,CACF,EACAA,EAAA,IAAC,SAAA,CACC,QAAS4J,GACT,UAAU,mIACV,MAAM,sBACN,aAAW,oBACX,oBAAkB,SAElB,SAAA7J,EAAA,KAAC,OAAK,CAAA,UAAU,UAAY,SAAA,EAAYsD,EAAA,KAAK,QAAQ,CAAC,EAAE,GAAA,EAAC,CAAA,CAC3D,EACArD,EAAA,IAAC,SAAA,CACC,QAAS0J,GACT,UAAU,mIACV,MAAM,mBACN,aAAW,UACX,oBAAkB,SAElB,eAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAAC1J,EAAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,wFAAwF,SAAS,SAAU,CAAA,EACxI,CAAA,CACF,CAAA,EACF,EAGAD,EAAAA,KAAC,MAAI,CAAA,UAAU,4DACb,SAAA,CAAAA,EAAA,KAAC,SAAA,CACC,QAASgL,GACT,UAAU,gIACV,MAAO9G,EAAe,wBAA0B,yBAChD,aAAYA,EAAe,kBAAoB,mBAC/C,oBAAkB,MAEjB,SAAA,CAAAA,EACEjE,EAAA,IAAA,MAAA,CAAI,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAACA,EAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,uSAAuS,SAAS,SAAU,CAAA,CAAA,CACvV,EAEAA,MAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAAAA,MAAC,OAAK,CAAA,EAAE,2YAA4Y,CAAA,EACtZ,EAEDA,EAAA,IAAA,OAAA,CAAM,SAAeiE,EAAA,OAAS,aAAa,CAAA,CAAA,CAC9C,EACAlE,EAAA,KAAC,SAAA,CACC,QAASyJ,GACT,UAAU,gIACV,MAAM,wBACN,aAAW,uBACX,oBAAkB,SAElB,SAAA,CAAAxJ,MAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAACA,EAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,0bAA0b,SAAS,SAAU,CAAA,EAC1e,EACAA,EAAAA,IAAC,QAAK,SAAM,QAAA,CAAA,CAAA,CAAA,CACd,EACAD,EAAA,KAAC,SAAA,CACC,QAAS8J,GACT,UAAU,gIACV,MAAM,mBACN,aAAW,6BAEX,SAAA,CAAA7J,MAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAACA,EAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,mHAAmH,SAAS,SAAU,CAAA,EACnK,EACAA,EAAAA,IAAC,QAAK,SAAG,KAAA,CAAA,CAAA,CAAA,CACX,EACAD,EAAA,KAAC,SAAA,CACC,QAAS,IAAM,CACToD,EAAM,UACRA,EAAM,QAAQ,EAAE,WAAW,EAAE,SAAS,EAChB6G,IAE1B,EACA,UAAU,gIACV,MAAM,wBACN,aAAW,uBACX,oBAAkB,SAElB,SAAA,CAAAhK,MAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAACA,EAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,qMAAqM,SAAS,SAAU,CAAA,EACrP,EACAA,EAAAA,IAAC,QAAK,SAAK,OAAA,CAAA,CAAA,CAAA,CACb,CAAA,EACF,CAAA,CACF,CAAA,EAEAD,EAAAA,KAAC,MAAI,CAAA,UAAU,wCACX,SAAA,EAAAmD,GAAsBH,GAAiBA,EAAc,OAAS,IAC7DhD,EAAA,KAAA,MAAA,CAAI,UAAU,yBACZ,SAAA,CACCmD,GAAAlD,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASkD,EACT,GAAG,kBACH,UAAU,qHACX,SAAA,aAAA,CAED,EAEDH,GAAiBA,EAAc,OAAS,GACvC/C,EAAA,IAAC,SAAA,CACC,GAAG,gBACH,MAAOgD,GAAsBD,EAAc,CAAC,EAAE,KAC9C,SAAW,GAAME,GAAA,YAAAA,EAAiB,EAAE,OAAO,OAC3C,UAAU,+FAET,SAAcF,EAAA,IACb4I,GAAA3L,EAAAA,IAAC,SAAyB,CAAA,MAAO2L,EAAO,KACrC,SAAOA,EAAA,IAAA,EADGA,EAAO,IAEpB,CACD,CAAA,CACH,CAAA,EAEJ,EAGF5L,EAAAA,KAAC,MAAI,CAAA,UAAU,kFACb,SAAA,CAAAC,EAAA,IAAC,QAAA,CACC,KAAK,OACL,YAAY,6BACZ,MAAOmF,GAAc,YAAc,GACnC,SAAW,GAAMG,GAAkB,CAAE,WAAY,EAAE,OAAO,OAAS,OAAW,EAC9E,SAAU,CAACD,GACX,UAAU,qIAAA,CACZ,EACAtF,EAAA,KAAC,SAAA,CACC,MAAOoF,GAAc,UAAY,GACjC,SAAW,GAAMG,GAAkB,CAAE,SAAU,EAAE,OAAO,OAAS,OAAW,EAC5E,SAAU,CAACD,GACX,UAAU,sIAEV,SAAA,CAACrF,EAAA,IAAA,SAAA,CAAO,MAAM,GAAG,SAAc,iBAAA,EAC9BoF,GAAkB,WAAW,IAAKwG,GAChC5L,EAAAA,IAAA,SAAA,CAAe,MAAO4L,EAAI,SAAdA,CAAA,EAAAA,CAAgB,CAC9B,CAAA,CAAA,CACH,EACA7L,EAAA,KAAC,SAAA,CACC,MAAOoF,GAAc,MAAQ,GAC7B,SAAW,GAAMG,GAAkB,CAAE,KAAM,EAAE,OAAO,OAAS,OAAW,EACxE,SAAU,CAACD,GACX,UAAU,sIAEV,SAAA,CAACrF,EAAA,IAAA,SAAA,CAAO,MAAM,GAAG,SAAS,YAAA,EACzBoF,GAAkB,MAAM,IAAKyG,GAC3B7L,EAAAA,IAAA,SAAA,CAAe,MAAO6L,EAAI,SAAdA,CAAA,EAAAA,CAAgB,CAC9B,CAAA,CAAA,CACH,EACA7L,EAAA,IAAC,QAAA,CACC,KAAK,OACL,YAAY,cACZ,OAAQmF,GAAc,MAAQ,CAAA,GAAI,KAAK,GAAG,EAC1C,SAAW,GAAM,CAEf,MAAM2G,EADM,EAAE,OAAO,MACJ,MAAM,GAAG,EAAE,IAAW3L,GAAAA,EAAI,KAAK,CAAC,EAAE,OAAO,OAAO,EACjEmF,GAAkB,CAAE,KAAMwG,EAAK,OAAS,EAAIA,EAAO,OAAW,CAChE,EACA,SAAU,CAACzG,GACX,UAAU,qIAAA,CACZ,CAAA,EACF,EAEAtF,EAAAA,KAAC,MAAI,CAAA,UAAU,8CACb,SAAA,CAACA,EAAAA,KAAA,MAAA,CAAI,UAAU,oCACb,SAAA,CAACC,EAAA,IAAA,OAAA,CAAK,UAAU,oEAAoE,SAAiB,oBAAA,EACrGA,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAMqE,GAAqB,CAACD,CAAiB,EACtD,UAAU,8DAET,WAAoB,OAAS,MAAA,CAChC,CAAA,EACF,EAECA,GACCrE,EAAA,KAAC,MAAI,CAAA,UAAU,YACb,SAAA,CAACA,EAAAA,KAAA,MAAA,CAAI,UAAU,kFACb,SAAA,CAACA,EAAAA,KAAA,MAAA,CAAI,UAAU,oCACb,SAAA,CAACA,EAAAA,KAAA,OAAA,CAAK,UAAU,gBAAgB,SAAA,CAAA,YAAUyC,EAAe,OAAO,GAAA,EAAC,EAChE,CAAC,CAACA,EAAe,QAChBxC,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAM0C,GAAA,YAAAA,EAAyB,IACxC,SAAU,CAACA,EACX,UAAU,sEACX,SAAA,OAAA,CAED,CAAA,EAEJ,EACC1C,MAAA,MAAA,CAAI,UAAU,oCACZ,WAAe,SAAW,EACxBA,EAAA,IAAA,OAAA,CAAK,UAAU,4BAA4B,SAAA,mBAAA,CAAiB,EAE7DwC,EAAe,IACb5C,GAAAG,EAAA,KAAC,OAAA,CAEC,UAAU,6HAEV,SAAA,CAAAC,MAAC,OAAK,CAAA,UAAU,yBAAyB,MAAOJ,EAAQ,SAAMA,EAAA,EAC9DI,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAMuG,GAAkB3G,EAAO4C,EAAgBE,CAAsB,EAC9E,UAAU,kDACV,aAAY,kBAAkB9C,CAAK,GACpC,SAAA,GAAA,CAED,CAAA,CAAA,EAXKA,CAaR,CAAA,EAEL,EACAG,EAAAA,KAAC,MAAI,CAAA,UAAU,0BACb,SAAA,CAAAC,EAAA,IAAC,QAAA,CACC,KAAK,OACL,MAAOsE,EACP,SAAW,GAAMC,GAAgB,EAAE,OAAO,KAAK,EAC/C,UAAWoB,GACX,YAAY,cACZ,SAAU,CAACjD,EACX,UAAU,qIAAA,CACZ,EACA1C,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASwF,GACT,SAAU,CAAC9C,GAA0B,CAAC4B,EAAa,KAAK,EACxD,UAAU,+GACX,SAAA,GAAA,CAED,CAAA,EACF,EACCW,GAAiB,OAAS,GACxBjF,EAAA,IAAA,MAAA,CAAI,UAAU,uHACZ,SAAAiF,GAAiB,IAAI,CAAC,CAAE,MAAArF,EAAO,MAAAmM,KAC7BhM,EAAAA,KAAA,MAAA,CAAqC,UAAU,cAC9C,SAAA,CAACC,EAAA,IAAA,IAAA,CAAE,UAAU,uBAAwB,SAAMJ,EAAA,EAC1CmM,EAAM,OAAS,EACbhM,EAAA,KAAA,MAAA,CAAI,UAAU,iDACZ,SAAA,CAAAgM,EAAM,MAAM,EAAG,CAAC,EAAE,IACjB7N,GAAA8B,MAAC,OAAmB,CAAA,UAAU,4CAC3B,SAAA9B,EAAK,OADGA,EAAK,EAEhB,CACD,EACA6N,EAAM,OAAS,GAAKhM,EAAA,KAAC,OAAK,CAAA,SAAA,CAAA,IAAEgM,EAAM,OAAS,EAAE,OAAA,EAAK,CAAA,EACrD,EAEA/L,EAAA,IAAC,IAAE,CAAA,UAAU,qBAAqB,SAA0B,6BAAA,CAAA,CAAA,EAZtD,mBAAmBJ,CAAK,EAclC,CACD,CACH,CAAA,CAAA,EAEJ,EAEAG,EAAAA,KAAC,MAAI,CAAA,UAAU,kFACb,SAAA,CAACA,EAAAA,KAAA,MAAA,CAAI,UAAU,oCACb,SAAA,CAACA,EAAAA,KAAA,OAAA,CAAK,UAAU,gBAAgB,SAAA,CAAA,YAAU0C,EAAe,OAAO,GAAA,EAAC,EAChE,CAAC,CAACA,EAAe,QAChBzC,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAM2C,GAAA,YAAAA,EAAyB,IACxC,SAAU,CAACA,EACX,UAAU,sEACX,SAAA,OAAA,CAED,CAAA,EAEJ,EACC3C,MAAA,MAAA,CAAI,UAAU,oCACZ,WAAe,SAAW,EACxBA,EAAA,IAAA,OAAA,CAAK,UAAU,4BAA4B,SAAA,kBAAA,CAAgB,EAE5DyC,EAAe,IACb7C,GAAAG,EAAA,KAAC,OAAA,CAEC,UAAU,+HAEV,SAAA,CAAAC,MAAC,OAAK,CAAA,UAAU,yBAAyB,MAAOJ,EAAQ,SAAMA,EAAA,EAC9DI,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAMuG,GAAkB3G,EAAO6C,EAAgBE,CAAsB,EAC9E,UAAU,kDACV,aAAY,kBAAkB/C,CAAK,GACpC,SAAA,GAAA,CAED,CAAA,CAAA,EAXKA,CAaR,CAAA,EAEL,EACAG,EAAAA,KAAC,MAAI,CAAA,UAAU,0BACb,SAAA,CAAAC,EAAA,IAAC,QAAA,CACC,KAAK,OACL,MAAOwE,EACP,SAAW,GAAMC,EAAgB,EAAE,OAAO,KAAK,EAC/C,UAAWoB,GACX,YAAY,cACZ,SAAU,CAAClD,EACX,UAAU,qIAAA,CACZ,EACA3C,EAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS0F,GACT,SAAU,CAAC/C,GAA0B,CAAC6B,EAAa,KAAK,EACxD,UAAU,mHACX,SAAA,GAAA,CAED,CAAA,EACF,EACCU,GAAiB,OAAS,GACxBlF,EAAA,IAAA,MAAA,CAAI,UAAU,uHACZ,SAAAkF,GAAiB,IAAI,CAAC,CAAE,MAAAtF,EAAO,MAAAmM,KAC7BhM,EAAAA,KAAA,MAAA,CAAqC,UAAU,cAC9C,SAAA,CAACC,EAAA,IAAA,IAAA,CAAE,UAAU,uBAAwB,SAAMJ,EAAA,EAC1CmM,EAAM,OAAS,EACbhM,EAAA,KAAA,MAAA,CAAI,UAAU,iDACZ,SAAA,CAAAgM,EAAM,MAAM,EAAG,CAAC,EAAE,IACjB7N,GAAA8B,MAAC,OAAmB,CAAA,UAAU,0DAC3B,SAAA9B,EAAK,OADGA,EAAK,EAEhB,CACD,EACA6N,EAAM,OAAS,GAAKhM,EAAA,KAAC,OAAK,CAAA,SAAA,CAAA,IAAEgM,EAAM,OAAS,EAAE,OAAA,EAAK,CAAA,EACrD,EAEA/L,EAAA,IAAC,IAAE,CAAA,UAAU,4BAA4B,SAAqB,wBAAA,CAAA,CAAA,EAZxD,mBAAmBJ,CAAK,EAclC,CACD,CACH,CAAA,CAAA,EAEJ,CAAA,EACF,CAAA,EAEJ,CAAA,EACF,CAAA,CAAA,CAEJ,EAGCmE,IACChE,EAAA,KAAC,MAAI,CAAA,UAAU,6IACb,SAAA,CAACA,EAAAA,KAAA,MAAA,CAAI,UAAU,yCACb,SAAA,CAACC,EAAA,IAAA,MAAA,CAAI,UAAU,gCAAgC,SAAgB,mBAAA,EAC/DA,EAAA,IAAC,SAAA,CACC,QAAS,IAAMgE,GAAiB,EAAK,EACrC,UAAU,oEACV,aAAW,wBACX,MAAM,OAEN,eAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAAChE,EAAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,qMAAqM,SAAS,SAAU,CAAA,EACrP,CAAA,CACF,CAAA,EACF,EACFD,EAAAA,KAAC,MAAI,CAAA,UAAU,YACX,SAAA,CAACC,EAAA,IAAA,MAAA,CAAI,UAAU,qCAAqC,SAAU,aAAA,SAC7D,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAO,SAAA,CAAA,EAAS,0BAAA,EAAwB,SACvD,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAK,OAAA,CAAA,EAAS,iCAAA,EAA+B,SAC5D,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAM,QAAA,CAAA,EAAS,uBAAA,EAAqB,SACnD,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAO,SAAA,CAAA,EAAS,wBAAA,EAAsB,EACrDA,EAAA,IAAA,MAAA,CAAI,UAAU,uEAAuE,SAAS,YAAA,SAChG,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAa,eAAA,CAAA,EAAS,mBAAA,EAAiB,SACtD,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAW,aAAA,CAAA,EAAS,sBAAA,EAAoB,SACvD,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAW,aAAA,CAAA,EAAS,SAAA,EAAO,SACxC,MAAI,CAAA,SAAA,CAAA,KAAEA,EAAAA,IAAC,UAAO,SAAM,QAAA,CAAA,EAAS,yBAAA,EAAuB,EACpDA,EAAA,IAAA,MAAA,CAAI,UAAU,uEAAuE,SAAW,cAAA,SAChG,MAAI,CAAA,SAAA,CAAA,MAAGA,EAAAA,IAAC,UAAO,SAAO,SAAA,CAAA,EAAS,sBAAA,EAAoB,SACnD,MAAI,CAAA,SAAA,CAAA,KAAEA,EAAAA,IAAC,UAAO,SAAM,QAAA,CAAA,EAAS,gBAAA,EAAc,SAC3C,MAAI,CAAA,SAAA,CAAA,OAAIA,EAAAA,IAAC,UAAO,SAAM,QAAA,CAAA,EAAS,wBAAA,EAAsB,CAAA,EAC1D,CAAA,EACF,EAIC,CAAC+D,IACA/D,EAAA,IAAC,SAAA,CACC,QAAS,IAAMgE,GAAiB,EAAI,EACpC,UAAU,sMACV,aAAW,wBACX,MAAM,wBAEN,eAAC,MAAI,CAAA,UAAU,UAAU,KAAK,eAAe,QAAQ,YACnD,SAAChE,EAAAA,IAAA,OAAA,CAAK,SAAS,UAAU,EAAE,yLAAyL,SAAS,SAAU,CAAA,EACzO,CAAA,CACF,EAIFA,EAAA,IAAClC,GAAA,CACC,QAASc,EAAQ,QACjB,EAAGA,EAAQ,EACX,EAAGA,EAAQ,EACX,KAAMA,EAAQ,KACd,KAAMA,EAAQ,KACd,OAAQA,EAAQ,OAChB,QAAS,IAAMmH,GAAY,EAAI,CAAA,CACjC,CAAA,CAAA,CAAA,CAGN,ECn9DA,SAASiG,GAAWC,EAAwB,CAC1C,MAAO,GAAGA,CAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,CAAC,EAC1E,CAEA,SAASC,GAAetM,EAAgBuM,EAAgC,CACtE,MAAMC,EAAIxM,GAAS,KAAO,GAAK,OAAOA,CAAK,EAAE,OAC7C,MAAI,CAACwM,GAAKA,IAAM,KAAOA,IAAM,QAAUA,IAAM,YACpCJ,GAAWG,CAAc,EAE3BC,CACT,CAEA,SAASC,GAAWC,EAAqB,CACvC,MAAMC,EAAkB,CAAA,EACpBD,EAAO,YAAYC,EAAM,KAAK,OAAOD,EAAO,UAAU,CAAC,EACvDA,EAAO,aAAaC,EAAM,KAAK,OAAOD,EAAO,WAAW,CAAC,EACzDA,EAAO,WAAWC,EAAM,KAAK,OAAOD,EAAO,SAAS,CAAC,EACzD,MAAME,EAAOD,EAAM,KAAK,GAAG,EAAE,KAAK,EAC9B,OAAAC,IACAF,EAAO,UAAkB,OAAOA,EAAO,SAAS,EAChDA,EAAO,YAAoB,OAAOA,EAAO,WAAW,EACpDA,EAAO,WAAa,KAAa,OAAOA,EAAO,SAAS,EACrD,UACT,CAEA,SAASG,GAAmBxK,EAA8B,OACjD,OAAAA,GAAQ,MAAM,QAAQA,EAAK,KAAK,GAAK,MAAM,QAAQA,EAAK,KAAK,IACjEA,EAAK,MAAM,SAAW,GAAK,QAAOZ,EAAAY,EAAK,MAAM,CAAC,IAAZ,YAAAZ,EAAe,IAAO,IAC7D,CAEA,MAAMqL,GAAa,CACjB,eACA,cACA,QACA,SACA,gBACA,eACF,EAEMC,GAAuB/M,GAAkBA,EAAM,QAAQ,UAAW,EAAE,EACpEgN,GAAchN,GAAkBA,EAAM,QAAQ,oBAAqB,GAAG,EAEtEiN,GAAaP,GAA+B,CAChD,UAAW5M,KAAOgN,GAAY,CACtB,MAAA7L,EAAMyL,GAAA,YAAAA,EAAS5M,GACrB,GAAImB,GAAO,KAAM,SACjB,MAAMiM,EAAU,OAAOjM,CAAG,EAAE,KAAK,EAC7B,GAAAiM,EAAgB,OAAAA,CACtB,CACO,OAAA,IACT,EAEMC,GAAgB,CAAC/F,EAA6BgG,IAC7ChG,EACAgG,EACE,CACL,GAAGhG,EACH,GAAGgG,EACH,KAAM,MAAM,KAAS,IAAA,IAAI,CAAC,GAAIhG,EAAS,MAAQ,GAAK,GAAIgG,EAAS,MAAQ,CAAA,CAAG,CAAC,CAAC,EAC9E,WAAY,CACV,GAAIhG,EAAS,YAAc,CAAC,EAC5B,GAAIgG,EAAS,YAAc,CAAC,CAC9B,EACA,aAAc,MAAM,KACd,IAAA,IAAI,CAAC,GAAIhG,EAAS,cAAgB,CAAC,EAAI,GAAIgG,EAAS,cAAgB,CAAA,CAAG,CAAC,CAC9E,CAAA,EAXoBhG,EADAgG,EAiBjB,SAASC,GAAqBC,EAAuB,CAE1D,MAAMrM,EAAWqM,GAASA,EAAM,KAAOA,EAAM,KAAOA,EAEhD,GAAAT,GAAmB5L,CAAG,EAAG,CAE3B,MAAMkL,GAAiBlL,EAAI,OAAS,CAAA,GAAI,IAAK4J,GAAW,CACtD,MAAM0C,EAAKjB,GAAezB,EAAE,GAAI,MAAM,EAC/B,MAAA,CACL,GAAA0C,EACA,MAAO1C,EAAE,OAAS0C,EAClB,KAAM1C,EAAE,KACR,MAAOA,EAAE,MACT,SAAUA,EAAE,SACZ,KAAMA,EAAE,IAAA,CACV,CACD,EACK5B,GAAiBhI,EAAI,OAAS,CAAA,GAAI,IAAKZ,GAAW,CACtD,MAAMkN,EAAKjB,GAAejM,EAAE,GAAI,MAAM,EAChC0I,EAAS1I,EAAE,QAAU,KAAO,GAAK,OAAOA,EAAE,MAAM,EAChD2I,EAAS3I,EAAE,QAAU,KAAO,GAAK,OAAOA,EAAE,MAAM,EACtD,MAAO,CAAE,GAAAkN,EAAI,OAAAxE,EAAQ,OAAAC,EAAQ,MAAO3I,EAAE,MAAO,OAAQA,EAAE,OAAQ,KAAMA,EAAE,IAAK,CAAA,CAC7E,EACM,MAAA,CAAE,MAAA8L,EAAO,MAAAlD,EAClB,CAGI,GAAAhI,GAAO,MAAM,QAAQA,EAAI,KAAK,GAAK,MAAM,QAAQA,EAAI,KAAK,EAAG,CACzD,MAAAuM,MAAqB,IACrBC,MAAuB,IACvBC,MAAkB,IAElBC,EAAgB,CAACC,EAA2CC,IAAwB,CACxF,GAAID,GAAS,KAAM,OACnB,MAAM5N,EAAQ,OAAO4N,CAAK,EAAE,KAAK,EAC5B5N,IACYyN,EAAA,IAAIzN,EAAO6N,CAAW,EACvCJ,EAAiB,IAAIT,GAAWhN,CAAK,EAAG6N,CAAW,EAAA,EAG/CC,EAAsBC,GAAqB,CAC/C,MAAMtH,EAAasG,GAAoBgB,EAAS,KAAM,CAAA,EACtD,GAAI,CAACtH,EAAmB,OAAA,KAClB,MAAAW,EAAWsG,EAAY,IAAIjH,CAAU,EACvC,GAAAW,EAAiB,OAAAA,EACrB,MAAMyG,EAAc,SAASb,GAAWvG,CAAU,CAAC,GAC7C1G,EAAQgO,EAAS,KAAA,GAAUtH,EAC3BuH,EAAU,CAAE,GAAIH,EAAa,MAAA9N,EAAO,IAAKgO,EAAS,QAAUtH,GACtD,OAAAiH,EAAA,IAAIjH,EAAYuH,CAAO,EAC5BA,CAAA,EAGHC,EAAa,CAACJ,EAAqB9L,IAA4B,CACnE,MAAMqL,EAAiB,CACrB,GAAIS,EACJ,MAAO9L,EAAS,OAAS8L,EACzB,KAAM9L,EAAS,MAAQ,SACvB,MAAOA,EAAS,MAChB,SAAUA,EAAS,SACnB,KAAMA,EAAS,IAAA,EAGjB,GAAI,CAACyL,EAAe,IAAIK,CAAW,EAAG,CACrBL,EAAA,IAAIK,EAAaT,CAAQ,EACxC,MACF,CAEM,MAAAhG,EAAWoG,EAAe,IAAIK,CAAW,EAC/CL,EAAe,IAAIK,EAAa,CAC9B,GAAGzG,EACH,MACEA,EAAS,QAAUA,EAAS,IAAMgG,EAAS,MACvCA,EAAS,MACThG,EAAS,OAASgG,EAAS,OAASS,EAC1C,KAAMT,EAAS,MAAQhG,EAAS,KAChC,MAAOA,EAAS,OAASgG,EAAS,MAClC,SAAUD,GAAc/F,EAAS,SAAUgG,EAAS,QAAQ,EAC5D,KAAM,CACJ,GAAIhG,EAAS,MAAQ,CAAC,EACtB,GAAIgG,EAAS,MAAQ,CAAC,CACxB,CAAA,CACD,CAAA,EAGGc,EAAkB,CAACH,EAAkBI,IAA4B,aAC/D,MAAAH,EAAUF,EAAmBC,CAAQ,EAC3C,GAAI,CAACC,EAAgB,OAAA,KACrB,MAAMI,EAA6B,CACjC,IAAID,GAAA,YAAAA,EAAS,WAAY,CAAC,EAC1B,aAAcJ,EAAS,KAAK,EAC5B,aAAc,MAAM,KACd,IAAA,IAAI,CAAC,KAAItM,EAAA0M,GAAA,YAAAA,EAAS,WAAT,YAAA1M,EAAmB,eAAgB,GAAKsM,EAAS,KAAK,CAAC,CAAC,CACvE,EACA,WAAY,CACV,KAAIrM,EAAAyM,GAAA,YAAAA,EAAS,WAAT,YAAAzM,EAAmB,aAAc,CAAC,EACtC,aAAcqM,EAAS,KAAK,CAC9B,EACA,YAAWnM,EAAAuM,GAAA,YAAAA,EAAS,WAAT,YAAAvM,EAAmB,cAAaD,EAAAwM,GAAA,YAAAA,EAAS,WAAT,YAAAxM,EAAmB,YAAa,EAAA,EAE7E,OAAAsM,EAAWD,EAAQ,GAAI,CACrB,GAAIA,EAAQ,GACZ,OAAOG,GAAA,YAAAA,EAAS,QAASH,EAAQ,MACjC,MAAMG,GAAA,YAAAA,EAAS,OAAQ,QACvB,SAAAC,EACA,KAAM,CACJ,IAAID,GAAA,YAAAA,EAAS,OAAQ,CAAC,EACtB,aAAcJ,EAAS,KAAK,CAC9B,CAAA,CACD,EACaJ,EAAAI,EAAUC,EAAQ,EAAE,EAClCL,EAAcZ,GAAoBgB,CAAQ,EAAGC,EAAQ,EAAE,EAChDA,EAAQ,EAAA,EAGXK,EAAgBrO,GAA8B,CAClD,GAAIA,GAAS,KAAa,OAAA,KAC1B,MAAMsO,EAAM,OAAOtO,CAAK,EAAE,KAAK,EAC/B,GAAI,CAACsO,EAAY,OAAA,KACb,GAAAb,EAAiB,IAAIa,CAAG,EAAU,OAAAb,EAAiB,IAAIa,CAAG,EACxD,MAAAC,EAAYvB,GAAWsB,CAAG,EAC5B,OAAAb,EAAiB,IAAIc,CAAS,EAAUd,EAAiB,IAAIc,CAAS,EACtEf,EAAe,IAAIc,CAAG,EAAUA,EAC7B,IAAA,EAILrN,EAAA,MAAM,QAASyL,GAAgB,CAC3B,MAAA8B,EAAQvB,GAAUP,CAAM,EACxB+B,EAAanC,GAAeI,EAAO,IAAMA,EAAO,UAAW,MAAM,EACvE,IAAImB,EAAcY,EAElB,GAAID,EAAO,CACH,MAAAE,EAAYZ,EAAmBU,CAAK,EACtCE,IACFb,EAAca,EAAU,GACxBf,EAAca,EAAOX,CAAW,EAClBF,EAAAZ,GAAoByB,CAAK,EAAGX,CAAW,EACvD,MAEAA,EAAcb,GAAWyB,CAAU,EAGvBd,EAAAjB,EAAO,GAAImB,CAAW,EACtBF,EAAAjB,EAAO,UAAWmB,CAAW,EAC3CF,EAAcE,EAAaA,CAAW,EAEtCI,EAAWJ,EAAa,CACtB,GAAIA,EACJ,MAAOpB,GAAWC,CAAM,GAAM8B,GAASX,EACvC,KAAMnB,EAAO,OAAS8B,EAAQ,SAAW,UACzC,MAAO9B,EAAO,YAAcA,EAAO,OAAS,OAC5C,SAAU,CACR,WAAY,CAAE,GAAGA,CAAO,EACxB,aAAc8B,GAAS,OACvB,aAAcA,EAAQ,CAACA,CAAK,EAAI,OAChC,YAAAX,CACF,EACA,KAAM,CAAE,GAAGnB,EAAQ,YAAAmB,CAAY,CAAA,CAChC,CAAA,CACF,EAEK,MAAAc,EAAqB3O,GAAkB,CACrC,MAAA4N,EAAQS,EAAarO,CAAK,EAC5B,GAAA4N,EAAc,OAAAA,EACZ,MAAAW,EAAYvB,GAAWhN,CAAK,EAClC,OAAAiO,EAAWM,EAAW,CACpB,GAAIA,EACJ,MAAOvO,EACP,KAAM,SACN,SAAU,CACR,WAAY,CAAE,gBAAiB,MAAO,CACxC,EACA,KAAM,CACJ,gBAAiB,MACnB,CAAA,CACD,EACD2N,EAAc3N,EAAOuO,CAAS,EACvBA,CAAA,EAGHK,EAAqB5H,GACpBA,EACWkH,EAAgBlH,EAAQ,CACtC,MAAOA,EACP,KAAM,QACN,SAAU,CACR,UAAW,GACX,UAAW,EACb,CAAA,CACD,EARmB,KAYhBiC,EAAgBhI,EAAI,MAAM,IAAI,CAAC4N,EAAYC,IAAgB,CAC/D,MAAMC,EAASzC,GAAeuC,EAAM,GAAI,MAAM,EAC9C,IAAI3G,EACF0G,EAAkBC,EAAM,aAAa,GACrCR,EAAaQ,EAAM,MAAM,IACxBA,EAAM,OAASF,EAAkB,OAAOE,EAAM,MAAM,CAAC,EAAI,IACxD1G,EACFyG,EAAkBC,EAAM,aAAa,GACrCR,EAAaQ,EAAM,MAAM,IACxBA,EAAM,OAASF,EAAkB,OAAOE,EAAM,MAAM,CAAC,EAAI,IAExD,CAAC3G,GAAY2G,EAAM,gBACV3G,EAAAyG,EAAkBE,EAAM,aAAa,GAE9C,CAAC1G,GAAY0G,EAAM,gBACV1G,EAAAwG,EAAkBE,EAAM,aAAa,GAG5C,MAAAxM,EAAO,CAAE,GAAGwM,GAClB,OAAIA,EAAM,eAAiB,OAAMxM,EAAK,cAAgBwM,EAAM,eACxDA,EAAM,eAAiB,OAAMxM,EAAK,cAAgBwM,EAAM,eAErD,CACL,GAAIE,GAAU,QAAQD,CAAG,GACzB,OAAQ5G,GAAY,GACpB,OAAQC,GAAY,GACpB,MAAO0G,EAAM,OAASA,EAAM,MAAQA,EAAM,cAAgB,OAC1D,KAAAxM,CAAA,CACF,CACD,EAGM,MAAA,CAAE,MADK,MAAM,KAAKmL,EAAe,OAAQ,CAAA,EAChC,MAAAvE,EAClB,CAEM,MAAA,IAAI,MAAM,qFAAqF,CACvG,CCxRA,MAAM+F,GAAkBhP,GAA6B,CAC/C,GAAAA,GAAU,KAA6B,MAAO,GAClD,MAAMiB,EAAM,OAAOjB,CAAK,EAAE,KAAK,EAC/B,GAAI,CAACiB,EAAK,MAAO,GACX,MAAAC,EAAQD,EAAI,cACZE,EAASF,EAAI,QAAQ,WAAY,EAAE,EACnCG,EAAW,IAAI,IAAY,CAACF,CAAK,CAAC,EACpC,OAAAC,GAAUA,IAAWD,GACvBE,EAAS,IAAID,CAAM,EAEd,MAAM,KAAKC,CAAQ,CAC5B,EAEM6N,GAA0B3Q,GAA4B,eACpD,MAAAgD,MAAkB,IAClB4N,EAAQlP,GAAmB,CAC/BgP,GAAehP,CAAK,EAAE,WAAesB,EAAY,IAAIpB,CAAG,CAAC,CAAA,EAG3DgP,EAAK5Q,EAAK,EAAE,EACZ4Q,EAAK5Q,EAAK,KAAK,EACf4Q,EAAK5Q,EAAK,IAAI,EACT4Q,GAAAzN,EAAAnD,EAAK,WAAL,YAAAmD,EAAe,QAAQ,EACvByN,GAAAxN,EAAApD,EAAK,WAAL,YAAAoD,EAAe,YAAY,GAC3BC,GAAAC,EAAAtD,EAAA,WAAA,YAAAsD,EAAU,eAAV,MAAAD,EAAwB,QAAQuN,GAErC,MAAMC,IAAarN,EAAAxD,EAAK,WAAL,YAAAwD,EAAe,aAAc,CAAA,EAChDoN,EAAKC,EAAW,YAAY,EAC5BD,EAAKC,EAAW,WAAW,EAC3BD,EAAKC,EAAW,KAAK,EACrBD,EAAKC,EAAW,MAAM,EACtBD,EAAKC,EAAW,aAAa,EAEvB,MAAA9M,EAAO/D,EAAK,MAAQ,GAC1B,OAAA4Q,EAAK7M,EAAK,YAAY,EACtB6M,EAAK7M,EAAK,WAAW,EACrB6M,EAAK7M,EAAK,KAAK,EACf6M,EAAK7M,EAAK,MAAM,EAETf,CACT,EAEM8N,GAAc,CAAC9N,EAA0B+N,IAA0B,CACjE,MAAA5I,EAAauI,GAAeK,CAAI,EACtC,OAAI5I,EAAW,SAAW,EAAU,GAC7BA,EAAW,KAAKzG,GAASsB,EAAY,IAAItB,CAAK,CAAC,CACxD,EAEgB,SAAAsP,GAAoBnD,EAAeoD,EAAqC,CAC/E,OAAApD,EAAM,OAAe7N,GAAA,iBACpB,MAAAgD,EAAc2N,GAAuB3Q,CAAI,EAmB/C,GAjBIiR,EAAO,eAAiBA,EAAO,cAAc,OAAS,GAEpD,CADaA,EAAO,cAAc,QAAaH,GAAY9N,EAAa+N,CAAI,CAAC,GAI/EE,EAAO,eAAiBA,EAAO,cAAc,OAAS,GACrCA,EAAO,cAAc,QAAaH,GAAY9N,EAAa+N,CAAI,CAAC,GAKjFE,EAAO,aACY9N,EAAAnD,EAAK,WAAL,YAAAmD,EAAe,WAAY,mBAC3B8N,EAAO,UAI1BA,EAAO,OACQjR,EAAK,MAAQ,aACbiR,EAAO,KAAa,MAAA,GAIvC,GAAIA,EAAO,MAAQA,EAAO,KAAK,OAAS,EAAG,CACzC,MAAMC,IAAW9N,EAAApD,EAAK,WAAL,YAAAoD,EAAe,OAAQ,CAAA,EAExC,GAAI,CADmB6N,EAAO,KAAK,QAAYC,EAAS,SAASjP,CAAG,CAAC,EACzC,MAAA,EAC9B,CAGA,GAAIgP,EAAO,WAAY,CACf,MAAAE,EAAaF,EAAO,WAAW,YAAY,EAC3CG,EAAepR,EAAK,MAAM,YAAY,EAAE,SAASmR,CAAU,EAC3DE,IAAqBhO,GAAAC,EAAAtD,EAAK,WAAL,YAAAsD,EAAe,cAAf,YAAAD,EAA4B,cAAc,SAAS8N,KAAe,GACvFG,IAAcC,GAAA/N,EAAAxD,EAAK,WAAL,YAAAwD,EAAe,OAAf,YAAA+N,EAAqB,KAAKtP,GAAOA,EAAI,YAAA,EAAc,SAASkP,CAAU,KAAM,GAC1FK,EAAqBV,GAAY9N,EAAamO,CAAU,EAC9D,GAAI,CAACC,GAAgB,CAACC,GAAsB,CAACC,GAAe,CAACE,EAA2B,MAAA,EAC1F,CAEO,MAAA,EAAA,CACR,CACH,CA0FO,SAASC,GAAiB5D,EAAe,CACxC,MAAA6D,MAAiB,IACjBC,MAAY,IACZ/D,MAAW,IAEjB,OAAAC,EAAM,QAAgB7N,GAAA,WACpB0R,EAAW,MAAIvO,EAAAnD,EAAK,WAAL,YAAAmD,EAAe,WAAY,eAAe,EACnDwO,EAAA,IAAI3R,EAAK,MAAQ,SAAS,GAChCsD,GAAAF,EAAApD,EAAK,WAAL,YAAAoD,EAAe,OAAf,MAAAE,EAAqB,WAAesK,EAAK,IAAI3L,CAAG,EAAC,CAClD,EAEM,CACL,WAAY,MAAM,KAAKyP,CAAU,EAAE,KAAK,EACxC,MAAO,MAAM,KAAKC,CAAK,EAAE,KAAK,EAC9B,KAAM,MAAM,KAAK/D,CAAI,EAAE,KAAK,CAAA,CAEhC,CClNA,MAAMgE,GAAeC,EAAAA,cAA4C,MAAS,EAE7DC,GAAW,IAAM,CACtB,MAAAjC,EAAUkC,aAAWH,EAAY,EACvC,GAAI/B,IAAY,OACR,MAAA,IAAI,MAAM,8CAA8C,EAEzD,OAAAA,CACT,EAMamC,GAA8C,CAAC,CAAE,SAAAC,KAAe,CAC3E,KAAM,CAACC,EAAOC,CAAQ,EAAI3R,WAAgB,IAC1B,aAAa,QAAQ,UAAU,GAClB,QAC5B,EAEK,CAAC4R,EAAQC,CAAS,EAAI7R,WAAS,IAC/B0R,IAAU,OAAe,GACzBA,IAAU,QAAgB,GACvB,OAAO,WAAW,8BAA8B,EAAE,OAC1D,EAEDzR,OAAAA,EAAAA,UAAU,IAAM,CACd,MAAM6R,EAAc,IAAM,CAEtBD,EADEH,IAAU,SACF,OAAO,WAAW,8BAA8B,EAAE,QAElDA,IAAU,MAF+C,CAGrE,EAMF,GAHYI,IACC,aAAA,QAAQ,WAAYJ,CAAK,EAElCA,IAAU,SAAU,CAChB,MAAAK,EAAa,OAAO,WAAW,8BAA8B,EACxD,OAAAA,EAAA,iBAAiB,SAAUD,CAAW,EAC1C,IAAMC,EAAW,oBAAoB,SAAUD,CAAW,CACnE,CAAA,EACC,CAACJ,CAAK,CAAC,EAEVzR,EAAAA,UAAU,IAAM,CACd,MAAM+R,EAAO,SAAS,gBACjBA,EAAA,UAAU,OAAO,QAAS,MAAM,EACrCA,EAAK,UAAU,IAAIJ,EAAS,OAAS,OAAO,CAAA,EAC3C,CAACA,CAAM,CAAC,EAGTtQ,MAAC8P,GAAa,SAAb,CAAsB,MAAO,CAAE,MAAAM,EAAO,SAAAC,EAAU,OAAAC,GAC9C,SAAAH,CACH,CAAA,CAEJ"}