---
// src/components/KnowledgeGraph.astro
// Enhanced interactive visualization of content connections using Cytoscape.js

export interface GraphNode {
  id: string;
  label: string;
  type: 'post' | 'tag' | 'category'; // Node types to distinguish posts from tags
  category?: string;
  tags?: string[];
  url?: string; // URL for linking
}

export interface GraphEdge {
  source: string;
  target: string;
  type: 'post-tag' | 'post-category' | 'post-post'; // Edge types
  strength?: number;
}

export interface GraphData {
  nodes: GraphNode[];
  edges: GraphEdge[];
}

interface Props {
  graphData: GraphData;
  height?: string; // e.g., '500px'
  width?: string; // e.g., '100%'
  initialFilter?: string; // Optional initial filter
  isMinimal?: boolean; // For smaller/simpler graphs inline in posts
}

const { graphData, height = "400px", width = "100%", initialFilter = "all", isMinimal = false } = Astro.props;

// Generate colors based on node types
const nodeTypeColors = {
  'post': '#3B82F6', // Blue for posts
  'tag': '#10B981',  // Green for tags
  'category': '#8B5CF6' // Purple for categories
};

// Generate predefined colors for categories
const predefinedColors = { 
  'Kubernetes': '#326CE5', 'Docker': '#2496ED', 'DevOps': '#FF6F61',
  'Homelab': '#06B6D4', 'Networking': '#9333EA', 'Infrastructure': '#10B981',
  'Automation': '#F59E0B', 'Security': '#EF4444', 'Monitoring': '#6366F1',
  'Storage': '#8B5CF6', 'Obsidian': '#7C3AED', 'Tutorial': '#3B82F6',
  'Uncategorized': '#A0AEC0'
};

// Calculate node sizes
const nodeSizes = {};
const minSize = 15; const maxSize = 35;
const degreeMap = new Map();
graphData.nodes.forEach(node => degreeMap.set(node.id, 0));
graphData.edges.forEach(edge => {
  degreeMap.set(edge.source, (degreeMap.get(edge.source) || 0) + 1);
  degreeMap.set(edge.target, (degreeMap.get(edge.target) || 0) + 1);
});
const maxDegree = Math.max(...Array.from(degreeMap.values()), 1);
graphData.nodes.forEach(node => {
  const degree = degreeMap.get(node.id) || 0;
  // Make tags slightly smaller than posts by default
  const baseSize = node.type === 'post' ? minSize : minSize * 0.8;
  const normalizedSize = maxDegree === 0 ? 0.5 : degree / maxDegree;
  nodeSizes[node.id] = baseSize + normalizedSize * (maxSize - minSize);
});

// Count node types for legend
const nodeTypeCounts = {
  post: graphData.nodes.filter(node => node.type === 'post').length,
  tag: graphData.nodes.filter(node => node.type === 'tag').length,
  category: graphData.nodes.filter(node => node.type === 'category').length
};

// Determine layout settings based on minimal mode
const layoutSettings = isMinimal ? {
  name: 'cose',
  idealEdgeLength: 60,
  nodeOverlap: 20,
  refresh: 20,
  fit: true,
  padding: 20,
  randomize: false,
  componentSpacing: 60,
  nodeRepulsion: 800000,
  edgeElasticity: 150,
  nestingFactor: 7,
  gravity: 25,
  numIter: 1500,
  initialTemp: 200,
  coolingFactor: 0.95,
  minTemp: 1.0,
  animate: true,
  animationDuration: 800
} : {
  name: 'cose',
  idealEdgeLength: 75,
  nodeOverlap: 30,
  refresh: 20,
  fit: true,
  padding: 30,
  randomize: false,
  componentSpacing: 60,
  nodeRepulsion: 1000000,
  edgeElasticity: 150,
  nestingFactor: 7,
  gravity: 30,
  numIter: 2000,
  initialTemp: 250,
  coolingFactor: 0.95,
  minTemp: 1.0,
  animate: true,
  animationDuration: 800
};

// Default physics settings
const defaultPhysics = {
  nodeRepulsion: 9000,
  edgeElasticity: 50,
  gravity: 10,
  linkDistance: 100,
  nodeSize: 1.0,
  linkThickness: 1.0
};
---

<!-- Include Cytoscape via CDN with is:inline to ensure it loads before the script runs -->
<script src="https://unpkg.com/cytoscape@3.25.0/dist/cytoscape.min.js" is:inline></script>

<div class="graph-container-wrapper" style={`width: ${width}; height: ${height};`} data-minimal={isMinimal}>
  <!-- Fullscreen Toggle Button -->
  <button id="fullscreen-toggle" class="fullscreen-toggle" aria-label="Toggle fullscreen">
    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path>
    </svg>
  </button>
  
  <!-- Settings Toggle Button -->
  <button id="toggle-settings" class="settings-toggle" aria-label="Graph settings">
    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <circle cx="12" cy="12" r="3"></circle>
      <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
    </svg>
  </button>
  
  <!-- Settings Panel (always visible in fullscreen) -->
  <div id="settings-panel" class="settings-panel">
    <h3 class="settings-title">Graph Settings</h3>
    
    <div class="settings-section">
      <h4 class="settings-section-title">Display</h4>
      
      <div class="settings-group">
        <label class="settings-label">Node Size: <span id="node-size-value">1.0</span></label>
        <input type="range" id="node-size" class="settings-slider" min="0.5" max="2.0" step="0.1" value="1.0">
      </div>
      
      <div class="settings-group">
        <label class="settings-label">Link Thickness: <span id="link-thickness-value">1.0</span></label>
        <input type="range" id="link-thickness" class="settings-slider" min="0.5" max="2.0" step="0.1" value="1.0">
      </div>
      
      <div class="settings-group">
        <label class="settings-label">Link Distance: <span id="link-distance-value">100</span></label>
        <input type="range" id="link-distance" class="settings-slider" min="50" max="200" step="10" value="100">
      </div>
      
      <div class="settings-group checkbox-group">
        <input type="checkbox" id="show-labels" class="settings-checkbox" checked>
        <label for="show-labels" class="settings-checkbox-label">Show Labels</label>
      </div>
      
      <div class="settings-group checkbox-group">
        <input type="checkbox" id="show-arrows" class="settings-checkbox" checked>
        <label for="show-arrows" class="settings-checkbox-label">Show Arrows</label>
      </div>
    </div>
    
    <div class="settings-section">
      <h4 class="settings-section-title">Physics</h4>
      
      <div class="settings-group">
        <label class="settings-label">Node Repulsion: <span id="repulsion-value">9000</span></label>
        <input type="range" id="node-repulsion" class="settings-slider" min="1000" max="20000" step="1000" value="9000">
      </div>
      
      <div class="settings-group">
        <label class="settings-label">Edge Elasticity: <span id="elasticity-value">50</span></label>
        <input type="range" id="edge-elasticity" class="settings-slider" min="10" max="100" step="5" value="50">
      </div>
      
      <div class="settings-group">
        <label class="settings-label">Gravity: <span id="gravity-value">10</span></label>
        <input type="range" id="gravity" class="settings-slider" min="0" max="50" step="5" value="10">
      </div>
    </div>
    
    <div class="settings-actions">
      <button id="apply-settings" class="settings-button apply-button">Apply</button>
      <button id="reset-settings" class="settings-button reset-button">Reset</button>
    </div>
  </div>

  <!-- Graph Instructions -->
  {!isMinimal && (
    <div class="graph-instructions">
      <details class="instructions-details">
        <summary class="instructions-summary">How to use the Knowledge Graph</summary>
        <div class="instructions-content">
          <p>This Knowledge Graph visualizes connections between blog content:</p>
          <ul>
            <li><span class="node-example post-node"></span> <strong>Posts</strong> - Blog articles (circle nodes)</li>
            <li><span class="node-example tag-node"></span> <strong>Tags</strong> - Content topics (diamond nodes)</li>
          </ul>
          <p>Interactions:</p>
          <ul>
            <li>Click a node to see its connections and details</li>
            <li>Click a tag node to filter posts by that tag</li>
            <li>Click a post node to highlight that specific post</li>
            <li>Use mouse wheel to zoom in/out and drag to pan</li>
            <li>Click an empty area to reset the view</li>
          </ul>
        </div>
      </details>
    </div>
  )}

  <!-- Loading Animation -->
  <div id="graph-loading" class="graph-loading">
    <div class="loading-spinner">
      <div class="spinner-ring"></div>
      <div class="spinner-ring"></div>
      <div class="spinner-ring"></div>
    </div>
    <div class="loading-text">Initializing Knowledge Graph...</div>
  </div>

  <!-- Cytoscape Container -->
  <div id="knowledge-graph" class="graph-container"></div>

  <!-- Node Details Panel -->
  <div id="node-details" class="node-details">
    <div class="node-details-header">
      <h3 id="node-title" class="node-title">Node Title</h3>
      <button id="close-details" class="close-button" aria-label="Close details">
        <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
      </button>
    </div>
    <div id="node-type" class="node-type">
      <span class="type-value">Type</span>
    </div>
    <div id="node-category" class="node-category">
      <span class="category-label">Category:</span>
      <span class="category-value">Category Name</span>
    </div>
    <div id="node-tags" class="node-tags">
      <span class="tags-label">Tags:</span>
      <div class="tags-container">
        <!-- Tags populated by JS -->
      </div>
    </div>
    <div id="node-connections" class="node-connections">
      <span class="connections-label">Connections:</span>
      <ul class="connections-list">
        <!-- Connections populated by JS -->
      </ul>
    </div>
    <a href="#" id="node-link" class="node-link" target="_self" rel="noopener noreferrer">View Content</a>
  </div>

  <!-- Graph Controls (only in full mode) -->
  {!isMinimal && (
    <div class="graph-controls">
      <div class="graph-filters">
        <button class="graph-filter active" data-filter="all" style="--filter-color: var(--accent-primary);">All</button>
        <button class="graph-filter" data-filter="posts" style="--filter-color: #3B82F6;">Posts ({nodeTypeCounts.post})</button>
        <button class="graph-filter" data-filter="tags" style="--filter-color: #10B981;">Tags ({nodeTypeCounts.tag})</button>
      </div>
      <div class="graph-actions">
        <button id="zoom-in" class="graph-action" aria-label="Zoom In">
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
        </button>
        <button id="zoom-out" class="graph-action" aria-label="Zoom Out">
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line></svg>
        </button>
        <button id="reset-graph" class="graph-action" aria-label="Reset View">
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 2v6h6"></path><path d="M21 12A9 9 0 0 0 6 5.3L3 8"></path><path d="M21 22v-6h-6"></path><path d="M3 12a9 9 0 0 0 15 6.7l3-2.7"></path></svg>
        </button>
      </div>
    </div>
  )}

  <!-- Exit Fullscreen Button (only visible in fullscreen) -->
  <button id="exit-fullscreen" class="exit-fullscreen-button">
    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <path d="M15 3h6v6"></path>
      <path d="M9 21H3v-6"></path>
      <path d="M21 3l-7 7"></path>
      <path d="M3 21l7-7"></path>
    </svg>
    Exit Fullscreen
  </button>
</div>

<!-- Mini Graph Component for inline use in posts -->
{isMinimal && (
  <div class="mini-graph-controls">
    <button id="mini-zoom-in" class="mini-graph-action" aria-label="Zoom In">+</button>
    <button id="mini-zoom-out" class="mini-graph-action" aria-label="Zoom Out">−</button>
    <button id="mini-reset" class="mini-graph-action" aria-label="Reset View">
      <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 2v6h6"></path><path d="M21 12A9 9 0 0 0 6 5.3L3 8"></path><path d="M21 22v-6h-6"></path><path d="M3 12a9 9 0 0 0 15 6.7l3-2.7"></path></svg>
    </button>
  </div>
)}

<script define:vars={{ graphData, nodeTypeColors, nodeSizes, predefinedColors, initialFilter, layoutSettings, defaultPhysics, isMinimal }}>
  // Initialize the graph when the DOM is ready
  function initializeGraph() {
    // Check if Cytoscape is loaded
    if (typeof cytoscape === 'undefined') {
      console.error("Cytoscape library not loaded. Make sure it's included via the script tag.");
      const loadingEl = document.getElementById('graph-loading');
      if(loadingEl) loadingEl.innerHTML = "<p>Error: Cytoscape library not loaded.</p>";
      return; 
    }

    const loadingEl = document.getElementById('graph-loading');
    const nodeDetailsEl = document.getElementById('node-details');
    const closeDetailsBtn = document.getElementById('close-details');
    const graphContainer = document.getElementById('knowledge-graph');
    const graphWrapper = document.querySelector('.graph-container-wrapper');
    const settingsPanel = document.getElementById('settings-panel');
    const settingsToggle = document.getElementById('toggle-settings');
    const fullscreenToggle = document.getElementById('fullscreen-toggle');
    const exitFullscreenBtn = document.getElementById('exit-fullscreen');
    const applySettingsBtn = document.getElementById('apply-settings');
    const resetSettingsBtn = document.getElementById('reset-settings');

    if (!graphContainer) {
        console.error("Knowledge graph container not found!");
        return;
    }
    if (!graphData || !graphData.nodes) {
        console.error("Graph data is missing or invalid.");
        if(loadingEl) loadingEl.innerHTML = "<p>Error loading graph data.</p>";
        return;
    }

    // Format data for Cytoscape
    const elements = [];
    
    // Add nodes with appropriate styling based on type
    graphData.nodes.forEach(node => {
      let nodeColor;
      
      if (node.type === 'post') {
        // Posts get category color if available
        nodeColor = node.category && predefinedColors[node.category] 
          ? predefinedColors[node.category] 
          : nodeTypeColors['post'];
      } else {
        // Tags and categories get their type color
        nodeColor = nodeTypeColors[node.type];
      }
      
      elements.push({
        data: {
          id: node.id,
          label: node.label,
          type: node.type,
          category: node.category || '',
          tags: node.tags || [],
          size: nodeSizes[node.id] || 25, 
          color: nodeColor, 
          url: node.url || '#'
        }
      });
    });
    
    // Add edges
    graphData.edges.forEach((edge, index) => {
      if (graphData.nodes.some(n => n.id === edge.source) && graphData.nodes.some(n => n.id === edge.target)) {
          elements.push({
            data: { 
              id: `e${index}`, 
              source: edge.source, 
              target: edge.target, 
              type: edge.type || 'post-tag',
              weight: edge.strength || 1 
            }
          });
      } else {
          console.warn(`Skipping edge e${index} due to missing node: ${edge.source} -> ${edge.target}`);
      }
    });

    // Physics settings for the graph
    const physicsSettings = {
      nodeRepulsion: defaultPhysics.nodeRepulsion,
      edgeElasticity: defaultPhysics.edgeElasticity,
      gravity: defaultPhysics.gravity,
      linkDistance: defaultPhysics.linkDistance,
      nodeSize: defaultPhysics.nodeSize,
      linkThickness: defaultPhysics.linkThickness,
      showLabels: true,
      showArrows: true
    };

    // Initialize Cytoscape
    const cy = cytoscape({
      container: graphContainer,
      elements: elements,
      style: [ 
         // Base node styles
         { selector: 'node', style: { 
             'background-color': 'data(color)', 
             'label': 'data(label)', 
             'width': 'data(size)', 
             'height': 'data(size)', 
             'font-size': '10px', 
             'color': '#E2E8F0', 
             'text-valign': 'bottom', 
             'text-halign': 'center', 
             'text-margin-y': '7px', 
             'text-background-opacity': 0.7, 
             'text-background-color': '#0F1219', 
             'text-background-padding': '3px', 
             'text-background-shape': 'roundrectangle', 
             'text-max-width': '120px', 
             'text-wrap': 'ellipsis', 
             'text-overflow-wrap': 'anywhere', 
             'border-width': '2px', 
             'border-color': '#0F1219', 
             'border-opacity': 0.8, 
             'z-index': 10,
             'text-outline-width': 1, 
             'text-outline-color': '#000', 
             'text-outline-opacity': 0.5
         }},
         // Post node specific styles
         { selector: 'node[type="post"]', style: {
             'shape': 'ellipse',
             'border-width': '2px'
         }},
         // Tag node specific styles
         { selector: 'node[type="tag"]', style: {
             'shape': 'diamond',
             'border-width': '1px',
             'border-color': '#10B981',
             'border-opacity': 0.9
         }},
         // Category node specific styles
         { selector: 'node[type="category"]', style: {
             'shape': 'hexagon',
             'border-width': '1px'
         }},
         // Edge styles
         { selector: 'edge', style: { 
             'width': 'mapData(weight, 1, 10, 1, 3)', 
             'line-color': 'rgba(226, 232, 240, 0.2)', 
             'curve-style': 'bezier', 
             'opacity': 0.6, 
             'z-index': 1,
             'target-arrow-shape': 'triangle',
             'target-arrow-color': 'rgba(226, 232, 240, 0.2)'
         }},
         // Post-tag edge specific styles
         { selector: 'edge[type="post-tag"]', style: {
             'line-color': 'rgba(16, 185, 129, 0.4)',
             'line-style': 'dashed',
             'target-arrow-color': 'rgba(16, 185, 129, 0.4)'
         }},
         // Post-post edge specific styles
         { selector: 'edge[type="post-post"]', style: {
             'line-color': 'rgba(59, 130, 246, 0.4)',
             'line-style': 'solid',
             'target-arrow-color': 'rgba(59, 130, 246, 0.4)'
         }},
         // Selection and hover styles
         { selector: '.highlighted', style: { 'background-color': 'data(color)', 'border-color': '#FFFFFF', 'border-width': '3px', 'color': '#FFFFFF', 'text-background-opacity': 0.9, 'opacity': 1, 'z-index': 20 } },
         { selector: '.filtered', style: { 'background-color': 'data(color)', 'border-color': '#FFFFFF', 'border-width': '2px', 'color': '#FFFFFF', 'text-background-opacity': 0.8, 'opacity': 0.8, 'z-index': 15 } },
         { selector: '.faded', style: { 'opacity': 0.15, 'text-opacity': 0.3, 'background-opacity': 0.3, 'z-index': 1 } }, 
         { selector: 'node:selected', style: { 'border-width': '4px', 'border-color': '#FFFFFF', 'border-opacity': 1, 'background-color': 'data(color)', 'text-opacity': 1, 'color': '#FFFFFF', 'z-index': 30 } },
         { selector: 'edge:selected', style: { 'width': 'mapData(weight, 1, 10, 2, 6)', 'line-color': '#FFFFFF', 'opacity': 1, 'z-index': 30 } },
         // Styles for dragging effects
         { selector: 'node.grabbed', style: {
             'border-width': '3px',
             'border-color': '#FFFFFF',
             'border-opacity': 1
         }}
      ],
      layout: layoutSettings,
      zoom: 1, minZoom: 0.1, maxZoom: 3, zoomingEnabled: true, userZoomingEnabled: true, panningEnabled: true, userPanningEnabled: true, boxSelectionEnabled: false,
    });

    // Store cy in window for access from other functions
    window.cy = cy;

    // Add Obsidian-like dragging behavior
    cy.on('dragfree', 'node', function(evt){
      const node = evt.target;
      setTimeout(() => {
        node.unlock(); // Unlock after drag complete
      }, 50);
    });

    // Function to update physics settings
    function updatePhysics(settings) {
      // Update node sizes
      cy.nodes().forEach(node => {
        const baseSize = node.data('size');
        node.style('width', baseSize * settings.nodeSize);
        node.style('height', baseSize * settings.nodeSize);
      });
      
      // Update edge thickness
      cy.edges().forEach(edge => {
        const baseWidth = edge.style('width');
        edge.style('width', parseFloat(baseWidth) * settings.linkThickness);
      });
      
      // Update label visibility
      if (settings.showLabels) {
        cy.nodes().style('label', 'data(label)');
      } else {
        cy.nodes().style('label', '');
      }
      
      // Update arrow visibility
      if (settings.showArrows) {
        cy.edges().style('target-arrow-shape', 'triangle');
      } else {
        cy.edges().style('target-arrow-shape', 'none');
      }
      
      // Run layout with updated physics settings
      cy.layout({
        name: 'cose',
        idealEdgeLength: settings.linkDistance,
        nodeOverlap: 30,
        refresh: 20,
        fit: false, // Don't fit to viewport to maintain current view
        padding: 40,
        randomize: false,
        componentSpacing: 120,
        nodeRepulsion: settings.nodeRepulsion,
        edgeElasticity: settings.edgeElasticity,
        nestingFactor: 5,
        gravity: settings.gravity,
        numIter: 1000,
        initialTemp: 200,
        coolingFactor: 0.95,
        minTemp: 1.0,
        animate: true
      }).run();
    }
    
    // Expose physics settings to global scope for external controls
    window.graphPhysics = {
      settings: physicsSettings,
      update: updatePhysics
    };

    // Hide loading screen
    if (loadingEl) {
      setTimeout(() => { loadingEl.classList.add('hidden'); }, 500); 
    }

    // --- Interactions ---
    let hoverTimeout;
    
    cy.on('mouseover', 'node', function(e) {
        const node = e.target;
        clearTimeout(hoverTimeout); 
        node.addClass('highlighted');
        node.connectedEdges().addClass('highlighted');
        graphContainer.style.cursor = 'pointer'; 
    });

    cy.on('mouseout', 'node', function(e) {
        const node = e.target;
        hoverTimeout = setTimeout(() => {
            if (!node.selected()) {
                node.removeClass('highlighted');
                node.connectedEdges().removeClass('highlighted');
            }
        }, 100);
        graphContainer.style.cursor = 'default'; 
    });

    cy.on('tap', 'node', function(e) {
      const node = e.target;
      const nodeData = node.data();
      
      if (nodeDetailsEl && !isMinimal) {
          // Set node title
          document.getElementById('node-title').textContent = nodeData.label;
          
          // Set node type
          const nodeTypeEl = document.getElementById('node-type').querySelector('.type-value') || 
                             document.getElementById('node-type');
          nodeTypeEl.textContent = nodeData.type.charAt(0).toUpperCase() + nodeData.type.slice(1);
          nodeTypeEl.className = `type-value ${nodeData.type}-type`;
          
          // Set category if it's a post
          const categorySection = document.getElementById('node-category');
          if (nodeData.type === 'post' && nodeData.category) {
              categorySection.style.display = 'block';
              const categoryEl = categorySection.querySelector('.category-value');
              categoryEl.textContent = nodeData.category;
              // Use category colors
              const catColor = predefinedColors[nodeData.category] || 'var(--text-secondary)'; 
              categoryEl.style.backgroundColor = `${catColor}33`; // Add alpha
              categoryEl.style.color = catColor;
          } else {
              categorySection.style.display = 'none';
          }
          
          // Set tags if it's a post
          const tagsSection = document.getElementById('node-tags');
          const tagsContainer = tagsSection.querySelector('.tags-container');
          
          if (nodeData.type === 'post' && nodeData.tags && nodeData.tags.length > 0) {
              tagsSection.style.display = 'block';
              tagsContainer.innerHTML = '';
              nodeData.tags.forEach(tag => {
                const tagEl = document.createElement('span');
                tagEl.className = 'tag';
                tagEl.textContent = tag;
                tagEl.addEventListener('click', () => {
                  // Find the tag node and trigger its selection
                  const tagNode = cy.getElementById(`tag-${tag}`);
                  if (tagNode.length > 0) {
                    tagNode.trigger('tap');
                  }
                  
                  // Try to find and click tag filter button
                  try {
                    const tagFilterBtn = Array.from(
                      document.querySelectorAll('.tag-filter-btn')
                    ).find(btn => btn.dataset.tag === tag);
                    
                    if (tagFilterBtn) {
                      tagFilterBtn.click();
                    }
                  } catch (e) {
                    console.log('Tag filter button not found');
                  }
                });
                tagsContainer.appendChild(tagEl);
              });
          } else {
              tagsSection.style.display = 'none';
          }
          
          // Set connections
          const connectionsList = document.getElementById('node-connections').querySelector('.connections-list');
          connectionsList.innerHTML = '';
          const connectedNodes = node.neighborhood('node');
          if (connectedNodes.length > 0) {
            connectedNodes.forEach(connectedNode => {
              const connectedData = connectedNode.data();
              const listItem = document.createElement('li');
              const link = document.createElement('a');
              link.href = '#'; 
              link.textContent = connectedData.label;
              link.dataset.id = connectedData.id;
              link.addEventListener('click', (evt) => {
                evt.preventDefault();
                cy.$(':selected').unselect(); 
                const targetNode = cy.getElementById(connectedData.id);
                if (targetNode) {
                    targetNode.select(); 
                    cy.animate({ center: { eles: targetNode }, zoom: cy.zoom() }, { duration: 300 }); 
                    targetNode.trigger('tap'); 
                }
              });
              listItem.appendChild(link);
              connectionsList.appendChild(listItem);
            });
          } else {
            connectionsList.innerHTML = '<li>No connections</li>';
          }
          
          // Set link text and URL based on node type
          const nodeLink = document.getElementById('node-link');
          if (nodeData.type === 'post') {
            nodeLink.textContent = 'Read Article';
          } else if (nodeData.type === 'tag') {
            nodeLink.textContent = 'Browse Tag';
          } else {
            nodeLink.textContent = 'View Content';
          }
          nodeLink.href = nodeData.url;
          
          nodeDetailsEl.classList.add('active');
      }
      
      // In minimal mode, just make the clicked node navigate to the relevant page
      if (isMinimal && nodeData.url && nodeData.url !== '#') {
        window.location.href = nodeData.url;
        return;
      }
      
      // Highlight the node and its connections, fade everything else
      cy.elements().removeClass('highlighted').removeClass('faded'); 
      node.addClass('highlighted');
      node.neighborhood().addClass('highlighted');
      cy.elements().difference(node.neighborhood().union(node)).addClass('faded');
      
      // If it's a tag node, try to trigger the corresponding tag filter
      if (nodeData.type === 'tag' && !isMinimal) {
        const tagName = nodeData.label;
        try {
          // Find and click the corresponding tag filter button
          const tagFilterBtn = Array.from(
            document.querySelectorAll('.tag-filter-btn')
          ).find(btn => btn.dataset.tag === tagName);
          
          if (tagFilterBtn) {
            tagFilterBtn.click();
          }
          
          // Scroll to the blog section
          const blogSection = document.querySelector('.blog-posts-section');
          if (blogSection) {
            blogSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
          }
        } catch (e) {
          console.log('Tag filter button not found or blog section not found');
        }
      }
    });

    cy.on('tap', function(e) {
      if (e.target === cy) { 
        if (nodeDetailsEl) nodeDetailsEl.classList.remove('active');
        cy.elements().removeClass('selected highlighted faded');
      }
    });

    if (closeDetailsBtn) {
      closeDetailsBtn.addEventListener('click', () => {
        if (nodeDetailsEl) nodeDetailsEl.classList.remove('active');
        cy.$(':selected').unselect();
        cy.elements().removeClass('highlighted faded');
      });
    }

    // Filter graph by node type
    const filterButtons = document.querySelectorAll('.graph-filter');
    filterButtons.forEach(button => {
      button.addEventListener('click', () => {
        filterButtons.forEach(btn => btn.classList.remove('active'));
        button.classList.add('active');
        const filter = button.dataset.filter;
        
        if (filter === 'all') {
          cy.elements().removeClass('faded highlighted filtered');
        } else if (filter === 'posts') {
          cy.elements().addClass('faded').removeClass('highlighted filtered');
          const postNodes = cy.nodes().filter(node => node.data('type') === 'post');
          postNodes.removeClass('faded').addClass('filtered');
        } else if (filter === 'tags') {
          cy.elements().addClass('faded').removeClass('highlighted filtered');
          const tagNodes = cy.nodes().filter(node => node.data('type') === 'tag');
          tagNodes.removeClass('faded').addClass('filtered');
        }
      });
    });

    // Zoom controls for both normal and minimal modes
    const zoomInBtn = isMinimal ? document.getElementById('mini-zoom-in') : document.getElementById('zoom-in');
    const zoomOutBtn = isMinimal ? document.getElementById('mini-zoom-out') : document.getElementById('zoom-out');
    const resetBtn = isMinimal ? document.getElementById('mini-reset') : document.getElementById('reset-graph');
    
    if (zoomInBtn) zoomInBtn.addEventListener('click', () => cy.zoom(cy.zoom() * 1.2));
    if (zoomOutBtn) zoomOutBtn.addEventListener('click', () => cy.zoom(cy.zoom() / 1.2));
    
    // Reset button functionality
    if (resetBtn) {
      resetBtn.addEventListener('click', () => {
        // Reset zoom and position
        cy.fit(null, 30);
        // Reset all filters and highlighting
        cy.elements().removeClass('faded highlighted filtered');
        // Reset active filter buttons
        if (!isMinimal) {
          const allFilterButton = document.querySelector('.graph-filter[data-filter="all"]');
          if (allFilterButton) allFilterButton.click();
          // Close node details panel if open
          if (nodeDetailsEl) nodeDetailsEl.classList.remove('active');
          // Reset any selected nodes
          cy.$(':selected').unselect();
        }
      });
    }

    // Settings toggle functionality
    if (settingsToggle && settingsPanel) {
      settingsToggle.addEventListener('click', () => {
        settingsPanel.classList.toggle('active');
      });
      
      // Initialize settings values from defaults
      document.getElementById('node-repulsion').value = physicsSettings.nodeRepulsion;
      document.getElementById('repulsion-value').textContent = physicsSettings.nodeRepulsion;
      
      document.getElementById('edge-elasticity').value = physicsSettings.edgeElasticity;
      document.getElementById('elasticity-value').textContent = physicsSettings.edgeElasticity;
      
      document.getElementById('gravity').value = physicsSettings.gravity;
      document.getElementById('gravity-value').textContent = physicsSettings.gravity;
      
      document.getElementById('node-size').value = physicsSettings.nodeSize;
      document.getElementById('node-size-value').textContent = physicsSettings.nodeSize;
      
      document.getElementById('link-thickness').value = physicsSettings.linkThickness;
      document.getElementById('link-thickness-value').textContent = physicsSettings.linkThickness;
      
      document.getElementById('link-distance').value = physicsSettings.linkDistance;
      document.getElementById('link-distance-value').textContent = physicsSettings.linkDistance;
      
      document.getElementById('show-labels').checked = physicsSettings.showLabels;
      document.getElementById('show-arrows').checked = physicsSettings.showArrows;
      
      // Update displayed values as sliders change
      document.getElementById('node-repulsion').addEventListener('input', e => {
        document.getElementById('repulsion-value').textContent = e.target.value;
      });
      
      document.getElementById('edge-elasticity').addEventListener('input', e => {
        document.getElementById('elasticity-value').textContent = e.target.value;
      });
      
      document.getElementById('gravity').addEventListener('input', e => {
        document.getElementById('gravity-value').textContent = e.target.value;
      });
      
      document.getElementById('node-size').addEventListener('input', e => {
        document.getElementById('node-size-value').textContent = e.target.value;
      });
      
      document.getElementById('link-thickness').addEventListener('input', e => {
        document.getElementById('link-thickness-value').textContent = e.target.value;
      });
      
      document.getElementById('link-distance').addEventListener('input', e => {
        document.getElementById('link-distance-value').textContent = e.target.value;
      });
      
      // Apply settings button
      applySettingsBtn.addEventListener('click', () => {
        // Update physics settings from form values
        physicsSettings.nodeRepulsion = parseInt(document.getElementById('node-repulsion').value);
        physicsSettings.edgeElasticity = parseInt(document.getElementById('edge-elasticity').value);
        physicsSettings.gravity = parseInt(document.getElementById('gravity').value);
        physicsSettings.nodeSize = parseFloat(document.getElementById('node-size').value);
        physicsSettings.linkThickness = parseFloat(document.getElementById('link-thickness').value);
        physicsSettings.linkDistance = parseInt(document.getElementById('link-distance').value);
        physicsSettings.showLabels = document.getElementById('show-labels').checked;
        physicsSettings.showArrows = document.getElementById('show-arrows').checked;
        
        // Apply settings
        updatePhysics(physicsSettings);
        
        // Hide settings panel if not in fullscreen
        if (!document.fullscreenElement) {
          settingsPanel.classList.remove('active');
        }
      });
      
      // Reset settings button
      resetSettingsBtn.addEventListener('click', () => {
        // Reset values to defaults
        document.getElementById('node-repulsion').value = defaultPhysics.nodeRepulsion;
        document.getElementById('repulsion-value').textContent = defaultPhysics.nodeRepulsion;
        
        document.getElementById('edge-elasticity').value = defaultPhysics.edgeElasticity;
        document.getElementById('elasticity-value').textContent = defaultPhysics.edgeElasticity;
        
        document.getElementById('gravity').value = defaultPhysics.gravity;
        document.getElementById('gravity-value').textContent = defaultPhysics.gravity;
        
        document.getElementById('node-size').value = defaultPhysics.nodeSize;
        document.getElementById('node-size-value').textContent = defaultPhysics.nodeSize;
        
        document.getElementById('link-thickness').value = defaultPhysics.linkThickness;
        document.getElementById('link-thickness-value').textContent = defaultPhysics.linkThickness;
        
        document.getElementById('link-distance').value = defaultPhysics.linkDistance;
        document.getElementById('link-distance-value').textContent = defaultPhysics.linkDistance;
        
        document.getElementById('show-labels').checked = true;
        document.getElementById('show-arrows').checked = true;
        
        // Reset settings in memory
        Object.assign(physicsSettings, {
          nodeRepulsion: defaultPhysics.nodeRepulsion,
          edgeElasticity: defaultPhysics.edgeElasticity,
          gravity: defaultPhysics.gravity,
          nodeSize: defaultPhysics.nodeSize,
          linkThickness: defaultPhysics.linkThickness,
          linkDistance: defaultPhysics.linkDistance,
          showLabels: true,
          showArrows: true
        });
        
        // Apply reset settings
        updatePhysics(physicsSettings);
      });
    }

    // Add mouse wheel zoom controls
    cy.on('zoom', function() {
      if (cy.zoom() > 1.5) {
        cy.style().selector('node').style({ 'text-max-width': '150px', 'font-size': '12px' }).update();
      } else {
        cy.style().selector('node').style({ 'text-max-width': '120px', 'font-size': '10px' }).update();
      }
    });
    
    // Apply initial filter if specified in full mode
    if (initialFilter && initialFilter !== 'all' && !isMinimal) {
      const filterButton = document.querySelector(`.graph-filter[data-filter="${initialFilter}"]`);
      if (filterButton) {
        setTimeout(() => filterButton.click(), 500);
      }
    }
    
    // Fullscreen functionality
    if (fullscreenToggle && graphWrapper) {
      fullscreenToggle.addEventListener('click', () => {
        if (!document.fullscreenElement) {
          graphWrapper.requestFullscreen().catch(err => {
            console.error(`Error attempting to enable fullscreen mode: ${err.message}`);
          });
        } else {
          document.exitFullscreen();
        }
      });
    }
    
    // Exit fullscreen button (visible only in fullscreen mode)
    if (exitFullscreenBtn) {
      exitFullscreenBtn.addEventListener('click', () => {
        if (document.fullscreenElement) {
          document.exitFullscreen();
        }
      });
    }
    
    // Handle fullscreen changes
    document.addEventListener('fullscreenchange', () => {
      if (document.fullscreenElement === graphWrapper) {
        // Entered fullscreen
        graphWrapper.classList.add('fullscreen');
        if (settingsPanel) settingsPanel.classList.add('fullscreen-visible');
        if (exitFullscreenBtn) exitFullscreenBtn.classList.add('visible');
      } else {
        // Exited fullscreen
        graphWrapper.classList.remove('fullscreen');
        if (settingsPanel) {
          settingsPanel.classList.remove('fullscreen-visible');
          settingsPanel.classList.remove('active');
        }
        if (exitFullscreenBtn) exitFullscreenBtn.classList.remove('visible');
      }
      
      // Resize graph after a short delay to allow transition
      setTimeout(() => {
        cy.resize();
        cy.fit();
      }, 200);
    });
    
    // Connect search input if it exists
    const searchInput = document.getElementById('search-input');
    if (searchInput && !isMinimal) {
      searchInput.addEventListener('input', e => {
        const term = e.target.value.toLowerCase();
        
        if (!term) {
          // Reset graph view if search is cleared
          cy.elements().removeClass('highlighted faded filtered');
          const allFilterBtn = document.querySelector('.graph-filter[data-filter="all"]');
          if (allFilterBtn) allFilterBtn.click();
          return;
        }
        
        // Reset previous filters
        cy.elements().addClass('faded').removeClass('highlighted filtered');
        
        // Find nodes that match the search term
        const matchingNodes = cy.nodes().filter(node => {
          const label = node.data('label').toLowerCase();
          return label.includes(term);
        });
        
        if (matchingNodes.length) {
          matchingNodes.removeClass('faded').addClass('highlighted');
          matchingNodes.connectedEdges().removeClass('faded');
        }
      });
    }
    
    // Connect tag filter buttons if they exist
    const tagFilterButtons = document.querySelectorAll('.tag-filter-btn');
    if (tagFilterButtons.length && !isMinimal) {
      tagFilterButtons.forEach(btn => {
        btn.addEventListener('click', () => {
          const tagName = btn.dataset.tag;
          
          if (tagName === 'all') {
            // Reset graph view if "All" is selected
            cy.elements().removeClass('highlighted faded filtered');
            const allFilterBtn = document.querySelector('.graph-filter[data-filter="all"]');
            if (allFilterBtn) allFilterBtn.click();
            return;
          }
          
          // Find the tag node
          const tagNode = cy.nodes().filter(node => 
            node.data('type') === 'tag' && 
            node.data('label') === tagName
          );
          
          if (tagNode.length) {
            // Highlight this tag and connected posts in the graph
            cy.elements().addClass('faded').removeClass('highlighted filtered');
            tagNode.removeClass('faded').addClass('highlighted');
            
            // Get connected posts
            const connectedPosts = tagNode.neighborhood('node[type="post"]');
            connectedPosts.removeClass('faded').addClass('filtered');
            
            // Highlight connecting edges
            tagNode.connectedEdges().removeClass('faded').addClass('highlighted');
          }
        });
      });
    }

    // Add Obsidian-like dragging behavior
    cy.on('drag', 'node', function(evt){
      const node = evt.target;
      node.lock(); // Lock node during drag
      
      // Get immediate neighbors
      const directNeighbors = node.neighborhood('node');
      
      // Apply a gentle pull to immediate neighbors
      if (directNeighbors.length > 0) {
        directNeighbors.forEach(neighbor => {
          if (!neighbor.grabbed()) {
            // Calculate distance and direction
            const dx = node.position('x') - neighbor.position('x');
            const dy = node.position('y') - neighbor.position('y');
            const distance = Math.sqrt(dx*dx + dy*dy);
            
            // Apply gentle force (stronger for closer nodes)
            const pullFactor = Math.min(0.05, 10/distance);
            neighbor.position({
              x: neighbor.position('x') + dx * pullFactor,
              y: neighbor.position('y') + dy * pullFactor
            });
          }
        });
      }
    });
        
    cy.on('dragfree', 'node', function(evt){
      const node = evt.target;
      setTimeout(() => {
        node.unlock(); // Unlock after drag complete
      }, 50);
    });
    
    // Dispatch graphReady event for external listeners
    document.dispatchEvent(new CustomEvent('graphReady', { detail: { cy } }));
  }

  // Initialize graph on DOMContentLoaded or if already loaded
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initializeGraph);
  } else {
    initializeGraph();
  }
</script>

<style>
  /* Graph Container Styles */
  .graph-container-wrapper { 
    position: relative; 
    width: 100%; 
    height: 400px; 
    min-height: 300px; 
    margin-bottom: 1.5rem;
    aspect-ratio: 1/1; /* Keep it square */
  }
  
  /* For minimal mode (used in posts) */
  .graph-container-wrapper[data-minimal="true"] {
    border-radius: 8px;
    border: 1px solid var(--card-border);
    overflow: hidden;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
    margin-bottom: 1.5rem;
  }
  
  .graph-container { 
    position: absolute; 
    top: 0; 
    left: 0; 
    width: 100%; 
    height: 100%; 
    border-radius: 12px; 
    overflow: hidden; 
    border: 1px solid var(--card-border); 
    background: rgba(15, 23, 42, 0.2); 
    backdrop-filter: blur(5px); 
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15); 
  }
  
  #knowledge-graph { 
    width: 100%; 
    height: 100%; 
    z-index: 1; 
  }
  
  /* Loading Animation */
  .graph-loading { 
    position: absolute; 
    top: 0; 
    left: 0; 
    width: 100%; 
    height: 100%; 
    display: flex; 
    flex-direction: column; 
    align-items: center; 
    justify-content: center; 
    background: rgba(15, 23, 42, 0.7); 
    z-index: 10; 
    transition: opacity 0.5s ease, visibility 0.5s ease; 
    border-radius: 12px;
  }
  
  .graph-loading.hidden { 
    opacity: 0; 
    visibility: hidden; 
  }
  
  .loading-spinner { 
    position: relative; 
    width: 80px; 
    height: 80px; 
    margin-bottom: 1rem; 
  }
  
  .spinner-ring { 
    position: absolute; 
    width: 100%; 
    height: 100%; 
    border-radius: 50%; 
    border: 3px solid transparent; 
    border-top-color: var(--accent-primary); 
    animation: spin 1.5s linear infinite; 
  }
  
  .spinner-ring:nth-child(2) { 
    width: calc(100% - 15px); 
    height: calc(100% - 15px); 
    top: 7.5px; 
    left: 7.5px; 
    border-top-color: var(--accent-secondary); 
    animation-duration: 2s; 
    animation-direction: reverse; 
  }
  
  .spinner-ring:nth-child(3) { 
    width: calc(100% - 30px); 
    height: calc(100% - 30px); 
    top: 15px; 
    left: 15px; 
    border-top-color: var(--accent-tertiary); 
    animation-duration: 2.5s; 
  }
  
  @keyframes spin { 
    0% { transform: rotate(0deg); } 
    100% { transform: rotate(360deg); } 
  }
  
  .loading-text { 
    color: var(--text-primary); 
    font-family: var(--font-mono); 
    font-size: 1rem; 
    letter-spacing: 0.05em; 
  }
  
  /* Node Details Panel */
  .node-details { 
    position: absolute; 
    top: 20px; 
    right: 20px; 
    width: 300px; 
    background: var(--bg-secondary); 
    border: 1px solid var(--card-border); 
    border-radius: 10px; 
    padding: 1.5rem; 
    z-index: 5; 
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); 
    transform: translateX(120%); 
    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); 
    opacity: 0; 
    backdrop-filter: blur(10px); 
  }
  
  .node-details.active { 
    transform: translateX(0); 
    opacity: 1; 
  }
  
  .node-details-header { 
    display: flex; 
    justify-content: space-between; 
    align-items: flex-start; 
    margin-bottom: 1rem; 
  }
  
  .node-title { 
    font-size: 1.2rem; 
    margin: 0; 
    color: var(--text-primary); 
    font-weight: 600; 
    line-height: 1.3; 
  }
  
  .close-button { 
    background: none; 
    border: none; 
    color: var(--text-secondary); 
    cursor: pointer; 
    padding: 5px; 
    border-radius: 50%; 
    display: flex; 
    align-items: center; 
    justify-content: center; 
    transition: all 0.2s ease; 
  }
  
  .close-button:hover { 
    color: var(--text-primary); 
    background: rgba(255, 255, 255, 0.1); 
  }
  
  .node-type {
    margin-bottom: 1rem;
  }
  
  .type-value {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    border-radius: 20px;
    font-size: 0.85rem;
    font-weight: 500;
  }
  
  .post-type {
    background-color: rgba(59, 130, 246, 0.15);
    color: #3B82F6;
  }
  
  .tag-type {
    background-color: rgba(16, 185, 129, 0.15);
    color: #10B981;
  }
  
  .category-type {
    background-color: rgba(139, 92, 246, 0.15);
    color: #8B5CF6;
  }
  
  .node-category, .node-tags, .node-connections { 
    margin-bottom: 1.25rem; 
  }
  
  .category-label, .tags-label, .connections-label { 
    display: block; 
    color: var(--text-secondary); 
    font-size: 0.85rem; 
    margin-bottom: 0.5rem; 
    font-family: var(--font-mono); 
  }
  
  .category-value { 
    display: inline-block; 
    padding: 0.25rem 0.75rem; 
    border-radius: 20px; 
    font-size: 0.85rem; 
    font-family: var(--font-mono); 
  }
  
  .tags-container { 
    display: flex; 
    flex-wrap: wrap; 
    gap: 0.5rem; 
  }
  
  .tag { 
    background: rgba(16, 185, 129, 0.1); 
    color: #10B981; 
    padding: 0.25rem 0.5rem; 
    border-radius: 4px; 
    font-size: 0.75rem; 
    cursor: pointer;
    transition: all 0.2s ease;
  }
  
  .tag:hover {
    background: rgba(16, 185, 129, 0.2);
    transform: translateY(-2px);
  }
  
  .connections-list { 
    padding-left: 0; 
    list-style: none; 
    margin: 0; 
    max-height: 150px; 
    overflow-y: auto; 
  }
  
  .connections-list li { 
    color: var(--text-secondary); 
    font-size: 0.9rem; 
    margin-bottom: 0.5rem; 
  }
  
  .connections-list a { 
    color: var(--accent-primary); 
    text-decoration: none; 
    transition: color 0.2s ease; 
  }
  
  .connections-list a:hover { 
    color: var(--accent-secondary); 
    text-decoration: underline; 
  }
  
  .node-link { 
    display: block; 
    background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary)); 
    color: var(--bg-primary); 
    font-weight: 500; 
    padding: 0.6rem 1.25rem; 
    border-radius: 6px; 
    text-decoration: none; 
    text-align: center; 
    transition: all 0.3s ease; 
    box-shadow: 0 4px 10px rgba(6, 182, 212, 0.2); 
    margin-top: 1rem; 
  }
  
  .node-link:hover { 
    transform: translateY(-2px); 
    box-shadow: 0 6px 15px rgba(6, 182, 212, 0.3); 
  }
  
  /* Graph Controls */
  .graph-controls { 
    position: absolute; 
    bottom: 20px; 
    left: 50%; 
    transform: translateX(-50%); 
    display: flex; 
    flex-direction: column; 
    gap: 1rem; 
    z-index: 5; 
  }
  
  .graph-filters { 
    display: flex; 
    flex-wrap: wrap; 
    gap: 0.5rem; 
    justify-content: center; 
    padding: 0.75rem; 
    background: rgba(15, 23, 42, 0.7); 
    backdrop-filter: blur(10px); 
    border-radius: 30px; 
    border: 1px solid var(--border-primary); 
  }
  
  .graph-filter { 
    background: rgba(226, 232, 240, 0.05); 
    color: var(--text-secondary); 
    border: 1px solid var(--border-secondary); 
    padding: 0.4rem 0.8rem; 
    border-radius: 30px; 
    font-size: 0.8rem; 
    cursor: pointer; 
    transition: all 0.2s ease; 
    font-family: var(--font-mono); 
    position: relative; 
    overflow: hidden; 
  }
  
  .graph-filter::before { 
    content: ''; 
    position: absolute; 
    top: 0; 
    left: 0; 
    width: 0; 
    height: 100%; 
    background: var(--filter-color, 'transparent'); 
    opacity: 0.15; 
    transition: width 0.3s ease; 
  }
  
  .graph-filter:hover::before { 
    width: 100%; 
  }
  
  .graph-filter:hover { 
    color: var(--text-primary); 
    border-color: var(--filter-color, rgba(56, 189, 248, 0.4)); 
    transform: translateY(-2px); 
  }
  
  .graph-filter.active { 
    background-color: var(--filter-color, var(--accent-primary)); 
    color: var(--bg-primary); 
    border-color: var(--filter-color, var(--accent-primary)); 
    font-weight: 600; 
  }
  
  .graph-filter.active::before { 
    width: 100%; 
    opacity: 0.2; 
  }
  
  .graph-actions { 
    display: flex; 
    justify-content: center; 
    gap: 0.75rem; 
  }
  
  .graph-action { 
    width: 36px; 
    height: 36px; 
    border-radius: 50%; 
    background: var(--bg-secondary); 
    border: 1px solid var(--border-primary); 
    color: var(--text-secondary); 
    display: flex; 
    align-items: center; 
    justify-content: center; 
    cursor: pointer; 
    transition: all 0.2s ease; 
  }
  
  .graph-action:hover { 
    color: var(--text-primary); 
    background: var(--bg-tertiary); 
    transform: translateY(-2px); 
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); 
  }
  
  /* Graph Instructions */
  .graph-instructions {
    margin-bottom: 1rem;
    width: 100%;
    position: relative;
    z-index: 5; /* Make sure this is above the graph */
  }
  
  .instructions-details {
    background: rgba(15, 23, 42, 0.7);
    border-radius: 8px;
    border: 1px solid var(--border-primary);
    overflow: hidden;
    transition: all 0.3s ease;
    backdrop-filter: blur(10px);
  }
  
  .instructions-details[open] {
    padding-bottom: 1rem;
  }
  
  .instructions-summary {
    padding: 0.75rem 1rem;
    cursor: pointer;
    color: var(--text-primary);
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    position: relative;
    z-index: 6;
  }
  
  .instructions-summary::before {
    content: "ℹ️";
    font-size: 1rem;
  }
  
  .instructions-content {
    padding: 0.5rem 1rem 1rem;
    color: var(--text-primary);
    line-height: 1.5;
    max-width: 800px;
    position: relative;
    z-index: 6;
  }
  
  .instructions-content p {
    margin-bottom: 0.5rem;
  }
  
  .instructions-content ul {
    padding-left: 1.5rem;
    margin: 0.5rem 0 1rem;
  }
  
  .node-example {
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: 0.25rem;
    vertical-align: middle;
  }
  
  .post-node {
    background-color: #3B82F6;
    border-radius: 50%;
  }
  
  .tag-node {
    background-color: #10B981;
    transform: rotate(45deg);
  }
  
  /* Settings Panel */
  .settings-toggle {
    position: absolute;
    top: 10px;
    left: 10px;
    background: rgba(20, 30, 50, 0.7);
    border: none;
    border-radius: 4px;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.8);
    cursor: pointer;
    z-index: 10;
    transition: all 0.2s ease;
  }
  
  .settings-toggle:hover {
    background: rgba(20, 30, 50, 0.9);
    color: white;
  }
  
  .settings-panel {
    position: absolute;
    top: 50px;
    left: 10px;
    background: rgba(15, 23, 42, 0.95);
    border-radius: 8px;
    padding: 16px;
    width: 300px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    z-index: 20;
    display: none;
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: var(--text-primary);
    max-height: calc(100% - 70px);
    overflow-y: auto;
  }
  
  .settings-panel.active,
  .settings-panel.fullscreen-visible {
    display: block;
  }
  
  .settings-title {
    font-size: 1.2rem;
    margin: 0 0 16px 0;
    padding-bottom: 8px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  }
  
  .settings-section {
    margin-bottom: 16px;
  }
  
  .settings-section-title {
    font-size: 0.9rem;
    font-weight: 600;
    margin: 0 0 12px 0;
    color: var(--accent-primary);
  }
  
  .settings-group {
    margin-bottom: 12px;
  }
  
  .settings-label {
    display: block;
    margin-bottom: 4px;
    color: rgba(255, 255, 255, 0.8);
    font-size: 14px;
  }
  
  .settings-slider {
    width: 100%;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 3px;
    outline: none;
  }
  
  .settings-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    background: var(--accent-primary);
    border-radius: 50%;
    cursor: pointer;
  }
  
  .settings-slider::-moz-range-thumb {
    width: 16px;
    height: 16px;
    background: var(--accent-primary);
    border-radius: 50%;
    cursor: pointer;
    border: none;
  }
  
  .checkbox-group {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  
  .settings-checkbox {
    width: 16px;
    height: 16px;
    cursor: pointer;
  }
  
  .settings-checkbox-label {
    font-size: 14px;
    cursor: pointer;
  }
  
  .settings-actions {
    display: flex;
    gap: 8px;
    margin-top: 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    padding-top: 16px;
  }
  
  .settings-button {
    flex: 1;
    padding: 8px 16px;
    border-radius: 4px;
    font-size: 14px;
    cursor: pointer;
    border: none;
    transition: all 0.2s ease;
  }
  
  .apply-button {
    background: var(--accent-primary);
    color: white;
  }
  
  .apply-button:hover {
    background: var(--accent-secondary);
  }
  
  .reset-button {
    background: rgba(255, 255, 255, 0.1);
    color: white;
  }
  
  .reset-button:hover {
    background: rgba(255, 255, 255, 0.2);
  }

  /* Fullscreen Toggle Button */
  .fullscreen-toggle {
    position: absolute;
    top: 10px;
    right: 10px;
    background: rgba(20, 30, 50, 0.7);
    border: none;
    border-radius: 4px;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.8);
    cursor: pointer;
    z-index: 10;
    transition: all 0.2s ease;
  }
  
  .fullscreen-toggle:hover {
    background: rgba(20, 30, 50, 0.9);
    color: white;
  }
  
  /* Exit Fullscreen Button */
  .exit-fullscreen-button {
    position: fixed;
    top: 16px;
    right: 16px;
    background: rgba(20, 30, 50, 0.8);
    color: white;
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    cursor: pointer;
    z-index: 9999;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
  }
  
  .exit-fullscreen-button.visible {
    opacity: 1;
    visibility: visible;
  }
  
  .exit-fullscreen-button:hover {
    background: rgba(20, 30, 50, 1);
    transform: translateY(-2px);
  }
  
  /* Fullscreen Mode */
  .graph-container-wrapper.fullscreen {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw !important;
    height: 100vh !important;
    margin: 0;
    z-index: 9000;
    background: var(--bg-primary);
    border-radius: 0;
  }
  
  .graph-container-wrapper.fullscreen .graph-container {
    border-radius: 0;
    border: none;
  }
  
  .graph-container-wrapper.fullscreen .settings-panel {
    position: fixed;
    top: 20px;
    left: 20px;
    max-height: calc(100vh - 40px);
  }
  
  /* Mini Graph Controls for Embedded Mode */
  .mini-graph-controls {
    position: absolute;
    bottom: 10px;
    right: 10px;
    display: flex;
    gap: 8px;
    z-index: 10;
  }
  
  .mini-graph-action {
    width: 24px;
    height: 24px;
    border-radius: 4px;
    background: rgba(15, 23, 42, 0.7);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    cursor: pointer;
    transition: all 0.2s ease;
  }
  
  .mini-graph-action:hover {
    background: rgba(15, 23, 42, 0.9);
    transform: translateY(-2px);
  }
  
  /* Media Queries */
  @media screen and (max-width: 768px) {
    .node-details { 
      width: 85%; 
      max-width: 300px; 
      left: 50%; 
      right: auto; 
      transform: translate(-50%, 120%); 
      bottom: 20px; 
      top: auto; 
    }
    
    .node-details.active { 
      transform: translate(-50%, 0); 
    }
    
    .graph-instructions {
      margin-bottom: 0.5rem;
    }
    
    .graph-controls { 
      bottom: 10px; 
    }
    
    .graph-filters {
      padding: 0.5rem;
    }
    
    .graph-filter {
      padding: 0.3rem 0.6rem;
      font-size: 0.75rem;
    }
    
    .settings-panel {
      width: 250px;
      left: 50%;
      transform: translateX(-50%);
    }
  }
  
  @media screen and (max-width: 480px) {
    .settings-panel {
      width: calc(100% - 40px);
    }
    
    .graph-container-wrapper[data-minimal="true"] {
      height: 300px;
    }
  }
</style>