<script lang="ts">
  import Header from '../../../lib/components/layout/Header.svelte';
  import PageHeader from '../../../lib/components/layout/PageHeader.svelte';
  import { nostrClient } from '../../../lib/services/nostr/nostr-client.js';
  import { relayManager } from '../../../lib/services/nostr/relay-manager.js';
  import { onMount } from 'svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import type { NostrEvent } from '../../../lib/types/nostr.js';
  import { nip19 } from 'nostr-tools';
  import { fetchGitRepo, extractGitUrls, isGraspUrl, convertSshToHttps, type GitRepoInfo, type GitFile } from '../../../lib/services/content/git-repo-fetcher.js';
  import FileExplorer from '../../../lib/components/content/FileExplorer.svelte';
  import { marked } from 'marked';
  import Asciidoctor from 'asciidoctor';
  import { KIND } from '../../../lib/types/kind-lookup.js';
  import FeedPost from '../../../lib/modules/feed/FeedPost.svelte';
  import { sanitizeHtml } from '../../../lib/services/security/sanitizer.js';
  import ProfileBadge from '../../../lib/components/layout/ProfileBadge.svelte';
  import MarkdownRenderer from '../../../lib/components/content/MarkdownRenderer.svelte';
  import { signAndPublish } from '../../../lib/services/nostr/auth-handler.js';
  import { sessionManager } from '../../../lib/services/auth/session-manager.js';
  import { cacheEvent, getEventsByKind } from '../../../lib/services/cache/event-cache.js';
  import EventMenu from '../../../lib/components/EventMenu.svelte';
  import { fetchProfiles } from '../../../lib/services/user-data.js';
  import Icon from '../../../lib/components/ui/Icon.svelte';

  let naddr = $derived($page.params.naddr);
  let repoEvent = $state<NostrEvent | null>(null);
  let gitRepo = $state<GitRepoInfo | null>(null);
  let loading = $state(true);
  let loadingGitRepo = $state(false);
  let gitRepoFetchAttempted = $state(false); // Track if we've already attempted to fetch (even if failed)
  let activeTab = $state<'metadata' | 'about' | 'repository' | 'issues' | 'documentation'>('metadata');
  let issues = $state<NostrEvent[]>([]);
  let issueComments = $state<Map<string, NostrEvent[]>>(new Map());
  let issueStatuses = $state<Map<string, NostrEvent>>(new Map());
  let loadingIssues = $state(false);
  let loadingIssueData = $state(false); // Statuses, comments, profiles
  let documentationEvents = $state<Map<string, NostrEvent>>(new Map());
  let changingStatus = $state<Map<string, boolean>>(new Map()); // Track which issues are having status changed
  let statusFilter = $state<string | null>(null); // Filter issues by status: null = all, 'open', 'resolved', 'closed', 'draft'
  let issuesPage = $state(1); // Current page for pagination
  const ISSUES_PER_PAGE = 20; // Number of issues to show per page

  const asciidoctor = Asciidoctor();

  let loadingRepo = $state(false); // Guard to prevent concurrent loads

  // Initialize activeTab from URL parameter
  function getTabFromUrl(): 'metadata' | 'about' | 'repository' | 'issues' | 'documentation' {
    const tabParam = $page.url.searchParams.get('tab');
    const validTabs: Array<'metadata' | 'about' | 'repository' | 'issues' | 'documentation'> = ['metadata', 'about', 'repository', 'issues', 'documentation'];
    if (tabParam && validTabs.includes(tabParam as any)) {
      return tabParam as 'metadata' | 'about' | 'repository' | 'issues' | 'documentation';
    }
    return 'metadata'; // Default
  }

  // Update activeTab when URL changes
  $effect(() => {
    const urlTab = getTabFromUrl();
    if (urlTab !== activeTab) {
      activeTab = urlTab;
    }
  });

  // Function to change tab and update URL
  function setActiveTab(tab: 'metadata' | 'about' | 'repository' | 'issues' | 'documentation') {
    activeTab = tab;
    const url = new URL($page.url);
    url.searchParams.set('tab', tab);
    goto(url.pathname + url.search, { replaceState: true, noScroll: true });
  }

  onMount(async () => {
    await nostrClient.initialize();
    // Initialize tab from URL
    activeTab = getTabFromUrl();
    // Don't call loadRepo here - let $effect handle it
  });

  // Track the last naddr we loaded to prevent duplicate loads
  let lastLoadedNaddr = $state<string | null>(null);

  $effect(() => {
    if (naddr && !loadingRepo && naddr !== lastLoadedNaddr) {
      // Reset git repo state when naddr changes
      gitRepo = null;
      gitRepoFetchAttempted = false;
      lastLoadedNaddr = naddr;
      loadCachedRepo();
      loadRepo();
    }
  });

  // Load git repo when repository or about tab is clicked (about tab needs README)
  $effect(() => {
    if ((activeTab === 'repository' || activeTab === 'about') && repoEvent && !gitRepo && !loadingGitRepo && !gitRepoFetchAttempted) {
      loadGitRepo();
    }
  });

  async function loadGitRepo() {
    if (!repoEvent || loadingGitRepo || gitRepo || gitRepoFetchAttempted) return;
    
    loadingGitRepo = true;
    gitRepoFetchAttempted = true; // Mark as attempted immediately to prevent re-triggering
    try {
      const gitUrls = extractGitUrls(repoEvent);
      
      // Prioritize GRASP clones if multiple URLs exist
      let prioritizedUrls = gitUrls;
      if (gitUrls.length > 1) {
        const graspUrls = gitUrls.filter(url => isGraspUrl(url));
        const nonGraspUrls = gitUrls.filter(url => !isGraspUrl(url));
        // Put GRASP URLs first
        prioritizedUrls = [...graspUrls, ...nonGraspUrls];
      }
      
      if (prioritizedUrls.length > 0) {
        // Try each URL until one works
        for (const url of prioritizedUrls) {
          try {
            const repo = await fetchGitRepo(url);
            if (repo) {
              gitRepo = repo;
              break; // Success, stop trying other URLs
            }
          } catch (error) {
            // Failed to fetch git repo - continue to next URL
            console.warn(`Failed to fetch repo from ${url}:`, error);
          }
        }
      }
    } catch (error) {
      // Failed to load git repo
    } finally {
      loadingGitRepo = false;
    }
  }

  async function loadCachedRepo() {
    if (!naddr) return;
    
    try {
      // Decode naddr
      let decoded;
      try {
        decoded = nip19.decode(naddr);
      } catch (decodeError) {
        return; // Can't decode, skip cache check
      }

      if (decoded.type !== 'naddr') {
        return;
      }

      const naddrData = decoded.data as { kind: number; pubkey: string; identifier?: string; relays?: string[] };
      const kind = naddrData.kind;
      const pubkey = naddrData.pubkey;
      const dTag = naddrData.identifier || '';

      // Check cache for repo events of this kind
      const cachedEvents = await getEventsByKind(kind, 1000);
      
      // Find the matching repo event (by pubkey and d-tag)
      const matchingEvent = cachedEvents.find(event => {
        if (event.pubkey !== pubkey) return false;
        const eventDTag = event.tags.find(t => t[0] === 'd')?.[1] || '';
        return eventDTag === dTag;
      });

      if (matchingEvent) {
        repoEvent = matchingEvent;
        loading = false; // Show cached data immediately
        
        // Load maintainer profiles immediately from cache
        loadMaintainerProfiles();
        
        // Load issues and documentation in background (but not git repo - wait for tab click)
        Promise.all([
          loadIssues(),
          loadDocumentation()
        ]).catch(err => {
          // Cache error (non-critical)
        });
      }
    } catch (error) {
      // Cache error (non-critical)
    }
  }

  async function loadRepo() {
    if (!naddr || loadingRepo) {
      if (!naddr) {
        // Missing naddr parameter
      }
      if (!repoEvent) {
        loading = false;
      }
      return;
    }
    
    // Only show loading spinner if we don't have cached data
    const hasCachedData = repoEvent !== null;
    if (!hasCachedData) {
      loading = true;
    }
    
    loadingRepo = true;
    try {
      // Decode naddr
      let decoded;
      try {
        decoded = nip19.decode(naddr);
      } catch (decodeError) {
        // Invalid naddr format
        if (!hasCachedData) {
          loading = false;
        }
        return;
      }

      if (decoded.type !== 'naddr') {
        // Invalid naddr type
        if (!hasCachedData) {
          loading = false;
        }
        return;
      }

      const naddrData = decoded.data as { kind: number; pubkey: string; identifier?: string; relays?: string[] };
      const kind = naddrData.kind;
      const pubkey = naddrData.pubkey;
      const dTag = naddrData.identifier || '';


      // Fetch the repo announcement event
      // Merge naddr relays with standard profile relays (naddr relays are additional hints, not replacements)
      const standardRelays = relayManager.getProfileReadRelays();
      const naddrRelays = naddrData.relays || [];
      const relays = [...new Set([...standardRelays, ...naddrRelays])]; // Deduplicate


      // Step 1: Fetch the repo event by ID (using kind, author, and d-tag)
      const events = await nostrClient.fetchEvents(
        [{ kinds: [kind], authors: [pubkey], '#d': [dTag], limit: 1 }],
        relays,
        { useCache: 'cache-first', cacheResults: true }
      );


      if (events.length > 0) {
        const newRepoEvent = events[0];
        // Only update if it's actually different (prevents unnecessary re-renders)
        if (!repoEvent || repoEvent.id !== newRepoEvent.id) {
          repoEvent = newRepoEvent;
        }
        
        // Don't fetch git repo here - wait until user clicks on repository tab
        // This prevents rate limiting from GitHub/GitLab/Gitea

        // Load maintainer profiles immediately from cache
        loadMaintainerProfiles();

        // Step 2: Batch load all related data in parallel (only if not already loaded from cache)
        if (issues.length === 0 && documentationEvents.size === 0) {
          await Promise.all([
            loadIssues(),           // Batch fetch issues, statuses, comments, and profiles
            loadDocumentation()     // Load documentation events
          ]);
        }
      } else {
        // Repo event not found
        if (!hasCachedData) {
          loading = false;
        }
      }
    } catch (error) {
      // Failed to load repo
      if (!hasCachedData) {
        loading = false;
      }
    } finally {
      loading = false;
      loadingRepo = false;
    }
  }

  // Helper function to filter issues that match this repo
  function filterMatchingIssues(issueEvents: NostrEvent[]): NostrEvent[] {
    if (!repoEvent) return [];
    
    const gitUrls = extractGitUrls(repoEvent);
    const dTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'd')?.[1] || '';
    const repoATag = dTag ? `${repoEvent.kind}:${repoEvent.pubkey}:${dTag}` : null;
    const repoEventId = repoEvent.id;
    
    return issueEvents.filter(issue => {
      // Check if issue references this repo via 'a' tag
      if (repoATag) {
        const aTags = issue.tags.filter(t => t[0] === 'a').map(t => t[1]);
        if (aTags.includes(repoATag)) {
          return true;
        }
      }
      
      // Check if issue references this repo via 'e' tag
      const eTags = issue.tags.filter(t => t[0] === 'e').map(t => t[1]);
      if (eTags.includes(repoEventId)) {
        return true;
      }
      
      // Check if issue references this repo via 'r' tag (git URLs)
      const rTags = issue.tags.filter(t => t[0] === 'r').map(t => t[1]);
      for (const gitUrl of gitUrls) {
        if (rTags.includes(gitUrl)) {
          return true;
        }
      }
      
      return false;
    });
  }

  // Helper function to merge new issues into existing list (deduplicate and sort)
  function mergeIssues(newIssues: NostrEvent[]): void {
    const existingIds = new Set(issues.map(i => i.id));
    const uniqueNewIssues = newIssues.filter(i => !existingIds.has(i.id));
    
    if (uniqueNewIssues.length > 0) {
      issues = [...issues, ...uniqueNewIssues]
        .sort((a, b) => b.created_at - a.created_at);
    }
  }

  async function loadIssues() {
    if (!repoEvent) return;

    loadingIssues = true;
    try {
      const gitUrls = extractGitUrls(repoEvent);
      const relays = relayManager.getProfileReadRelays();

      // Step 1: Load cached issues immediately (cache-first)
      const cachedIssues = await getEventsByKind(KIND.ISSUE, 500); // Get more than needed to filter
      const matchingCachedIssues = filterMatchingIssues(cachedIssues);
      
      // Show cached issues immediately
      if (matchingCachedIssues.length > 0) {
        issues = matchingCachedIssues.sort((a, b) => b.created_at - a.created_at);
        loadingIssues = false; // Show cached issues immediately, don't wait for relays
      }

      // Step 2: Fetch from relays in background and update progressively
      const filters: any[] = [];
      
      // Search for issues that reference the repo event ID
      filters.push({ '#e': [repoEvent.id], kinds: [KIND.ISSUE], limit: 100 });

      // Search for issues that reference the repo using 'a' tag (NIP-34 format: kind:pubkey:d-tag)
      const dTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'd')?.[1] || '';
      if (dTag) {
        const aTagValue = `${repoEvent.kind}:${repoEvent.pubkey}:${dTag}`;
        filters.push({ '#a': [aTagValue], kinds: [KIND.ISSUE], limit: 100 });
      }

      // Also search for issues with git URLs in tags (batch all URLs in one filter)
      if (gitUrls.length > 0) {
        filters.push({ '#r': gitUrls, kinds: [KIND.ISSUE], limit: 100 });
      }

      // Search for issues by the repo author (issues might be created by repo maintainers)
      filters.push({ authors: [repoEvent.pubkey], kinds: [KIND.ISSUE], limit: 100 });

      // Fetch from relays in parallel, updating issues as they arrive
      const fetchPromises = filters.map(async (filter) => {
        try {
          const events = await nostrClient.fetchEvents([filter], relays, { 
            useCache: 'cache-first', // Still use cache, but we already showed cached above
            cacheResults: true 
          });
          
          // Filter and merge new issues as they arrive
          const matchingEvents = filterMatchingIssues(events);
          if (matchingEvents.length > 0) {
            mergeIssues(matchingEvents);
          }
        } catch (error) {
          // Individual filter failures are non-critical
          console.warn('Failed to fetch issues for filter:', filter, error);
        }
      });

      // Wait for all fetches to complete, but UI already shows cached issues
      await Promise.allSettled(fetchPromises);
      
      // Final sort after all fetches complete
      issues = [...issues].sort((a, b) => b.created_at - a.created_at);
      loadingIssues = false;

      // Load statuses, comments, and profiles in background (don't wait)
      // This allows the UI to show issues immediately
      loadingIssueData = true;
      Promise.all([
        loadIssueStatuses(),
        loadIssueComments(),
        loadAllProfiles()
      ]).finally(() => {
        loadingIssueData = false;
      }).catch(() => {
        // Background loading errors are non-critical
        loadingIssueData = false;
      });
    } catch (error) {
      // Failed to load issues
      loadingIssues = false;
    }
  }

  async function loadIssueStatuses(forceNetwork = false) {
    if (issues.length === 0) return;

    try {
      const relays = relayManager.getProfileReadRelays();
      
      // Sort issues by newest first (created_at descending)
      const sortedIssues = [...issues].sort((a, b) => b.created_at - a.created_at);
      
      // Process in batches of 50, starting with newest issues first
      const BATCH_SIZE = 50;
      const statusMap = new Map<string, NostrEvent>();
      const statusesByIssue = new Map<string, Map<string, NostrEvent>>(); // issueId -> pubkey -> status
      
      for (let i = 0; i < sortedIssues.length; i += BATCH_SIZE) {
        const batch = sortedIssues.slice(i, i + BATCH_SIZE);
        const issueIds = batch.map(issue => issue.id);
        
        // Status events are different kinds: 1630 (Open), 1631 (Applied/Merged/Resolved), 1632 (Closed), 1633 (Draft)
        // They have "e" tags pointing to issues with marker "root"
        // Use 'relay-first' when forcing network fetch (e.g., after status change) to bypass cached empty results
        const statuses = await nostrClient.fetchEvents(
          [{ 
            '#e': issueIds, 
            kinds: [KIND.STATUS_OPEN, KIND.STATUS_APPLIED, KIND.STATUS_CLOSED, KIND.STATUS_DRAFT], 
            limit: 200 
          }],
          relays,
          { useCache: forceNetwork ? 'relay-first' : 'cache-first', cacheResults: true }
        );
        
        // Process statuses for this batch
        for (const status of statuses) {
          // Find the "e" tag with marker "root" (or just the first "e" tag if no marker)
          // Handle both 'e' and 'E' tags (case-insensitive)
          const eTag = status.tags.find(t => (t[0] === 'e' || t[0] === 'E') && (t.length < 3 || t[2] === 'root'));
          const fallbackETag = status.tags.find(t => t[0] === 'e' || t[0] === 'E');
          const issueId = (eTag && eTag[1] && issueIds.includes(eTag[1])) 
            ? eTag[1] 
            : (fallbackETag && fallbackETag[1] && issueIds.includes(fallbackETag[1]))
              ? fallbackETag[1]
              : null;
          
          if (issueId) {
            // Group by issue and pubkey (replaceable events)
            if (!statusesByIssue.has(issueId)) {
              statusesByIssue.set(issueId, new Map());
            }
            const pubkeyMap = statusesByIssue.get(issueId)!;
            const existing = pubkeyMap.get(status.pubkey);
            if (!existing || status.created_at > existing.created_at) {
              pubkeyMap.set(status.pubkey, status);
            }
          }
        }
        
        // Update statusMap after each batch (so UI can show statuses progressively)
        for (const [issueId, pubkeyMap] of statusesByIssue.entries()) {
          let latestStatus: NostrEvent | null = null;
          for (const status of pubkeyMap.values()) {
            if (!latestStatus || status.created_at > latestStatus.created_at) {
              latestStatus = status;
            }
          }
          if (latestStatus) {
            statusMap.set(issueId, latestStatus);
          }
        }
        
        // Merge with existing state to preserve any local updates that haven't propagated yet
        // Keep the newer status for each issue
        const mergedStatuses = new Map(issueStatuses);
        for (const [issueId, newStatus] of statusMap.entries()) {
          const existingStatus = mergedStatuses.get(issueId);
          if (!existingStatus || newStatus.created_at > existingStatus.created_at) {
            mergedStatuses.set(issueId, newStatus);
          }
        }
        
        // Update state after each batch so newest issues show statuses first
        issueStatuses = mergedStatuses;
      }
    } catch (error) {
      // Failed to load issue statuses
    }
  }

  async function changeIssueStatus(issueId: string, newStatus: string) {
    const session = sessionManager.getSession();
    if (!session) {
      alert('Please log in to change issue status');
      return;
    }

    changingStatus.set(issueId, true);

    try {
      // Get the issue event to extract repository info
      const issue = issues.find(i => i.id === issueId);
      if (!issue) {
        alert('Issue not found');
        return;
      }

      // Get the repo event to extract owner and repo ID
      const repoOwner = repoEvent?.pubkey || '';
      const repoDTag = repoEvent?.tags.find(t => t[0] === 'd')?.[1] || '';
      
      // Build tags according to NIP-34 spec
      const tags: string[][] = [
        ['e', issueId, '', 'root'], // Reference to the issue with "root" marker
        ['p', repoOwner], // Repository owner
        ['p', issue.pubkey], // Root event author
      ];

      // Add optional tags for improved subscription filter efficiency
      if (repoEvent && repoDTag) {
        tags.push(['a', `${KIND.REPO_ANNOUNCEMENT}:${repoOwner}:${repoDTag}`]);
      }

      // Get git repo URLs for 'r' tags (optional - requires commit IDs)
      // For now, we'll skip 'r' tags as they require the earliest unique commit ID
      // which would need to be fetched from the git repository

      const statusKind = getKindFromStatus(newStatus);
      
      const event: Omit<NostrEvent, 'sig' | 'id'> = {
        kind: statusKind, // Status is determined by the kind
        pubkey: session.pubkey,
        created_at: Math.floor(Date.now() / 1000),
        tags: tags,
        content: '' // Optional markdown text
      };

      // Sign the event first so we can cache it
      const signedEvent = await sessionManager.signEvent(event);
      
      // Cache the event immediately
      await cacheEvent(signedEvent);
      
      // Update local state immediately with the cached event (before publishing)
      // This ensures the UI updates right away, even if publishing is slow
      issueStatuses.set(issueId, signedEvent);
      issueStatuses = new Map(issueStatuses); // Trigger reactivity
      
      // Refresh the view immediately using cache-first to show the newly cached event
      // This ensures the cached event is displayed right away
      loadIssueStatuses(false).catch(() => {
        // Non-critical - status is already updated locally
      });
      
      // Publish to relays in background (don't wait for it)
      const relays = relayManager.getProfileReadRelays();
      signAndPublish(event, relays).then((result) => {
        if (result.success.length === 0 && result.failed.length > 0) {
          console.warn('Failed to publish status change to some relays:', result.failed);
          // Don't show alert - event is cached and will sync eventually
        }
        // Optionally reload from network to get any other updates from relays
        // Use a small delay to allow the event to propagate
        setTimeout(() => {
          loadIssueStatuses(true).catch(() => {
            // Non-critical - status is already updated locally
          });
        }, 1000);
      }).catch((error) => {
        console.error('Error publishing status change:', error);
        // Don't show alert - event is cached and will sync eventually
      });
    } catch (error) {
      // Failed to change issue status
      alert('Error changing issue status: ' + (error instanceof Error ? error.message : String(error)));
    } finally {
      changingStatus.set(issueId, false);
    }
  }

  function getStatusFromKind(kind: number): string {
    switch (kind) {
      case KIND.STATUS_OPEN:
        return 'open';
      case KIND.STATUS_APPLIED:
        return 'resolved'; // For issues, 1631 means "Resolved"
      case KIND.STATUS_CLOSED:
        return 'closed';
      case KIND.STATUS_DRAFT:
        return 'draft';
      default:
        return 'open';
    }
  }

  function getCurrentStatus(issueId: string): string {
    const status = issueStatuses.get(issueId);
    if (!status) {
      // Default to 'open' if no status event exists
      return 'open';
    }
    
    // Status is determined by the kind of the event
    return getStatusFromKind(status.kind);
  }

  function getKindFromStatus(status: string): number {
    switch (status) {
      case 'open':
        return KIND.STATUS_OPEN;
      case 'resolved':
      case 'applied':
      case 'merged':
        return KIND.STATUS_APPLIED;
      case 'closed':
        return KIND.STATUS_CLOSED;
      case 'draft':
        return KIND.STATUS_DRAFT;
      default:
        return KIND.STATUS_OPEN;
    }
  }

  const availableStatuses = ['open', 'resolved', 'closed', 'draft'];

  // Filter issues by status
  let filteredIssues = $derived.by(() => {
    let filtered = issues;
    if (statusFilter) {
      filtered = issues.filter(issue => getCurrentStatus(issue.id) === statusFilter);
    }
    return filtered;
  });

  // Paginated issues
  let paginatedIssues = $derived.by(() => {
    const start = (issuesPage - 1) * ISSUES_PER_PAGE;
    const end = start + ISSUES_PER_PAGE;
    return filteredIssues.slice(start, end);
  });

  let totalPages = $derived.by(() => {
    return Math.ceil(filteredIssues.length / ISSUES_PER_PAGE);
  });

  // Reset to page 1 when filter changes
  $effect(() => {
    if (statusFilter !== null) {
      issuesPage = 1;
    }
  });

  async function loadIssueComments() {
    if (issues.length === 0) return;

    try {
      const relays = relayManager.getCommentReadRelays();
      
      // Sort issues by newest first (created_at descending)
      const sortedIssues = [...issues].sort((a, b) => b.created_at - a.created_at);
      
      // Get all issue IDs upfront for cache lookup
      const allIssueIds = new Set(sortedIssues.map(issue => issue.id));
      
      // Step 1: Load ALL cached comments first (before any relay fetches)
      const cachedComments = await getEventsByKind(KIND.COMMENT, 1000); // Get a large number to cover all comments
      const commentsMap = new Map<string, NostrEvent[]>();
      
      // Process cached comments immediately
      for (const comment of cachedComments) {
        // Check for both lowercase 'e' and uppercase 'E' tags
        const eTag = comment.tags.find(t => t[0] === 'e' || t[0] === 'E');
        if (eTag && eTag[1] && allIssueIds.has(eTag[1])) {
          const issueId = eTag[1];
          if (!commentsMap.has(issueId)) {
            commentsMap.set(issueId, []);
          }
          commentsMap.get(issueId)!.push(comment);
        }
      }
      
      // Update state immediately with cached comments
      issueComments = new Map(commentsMap);
      
      // Step 2: Process in batches of 50, fetching from relays for any missing comments
      const BATCH_SIZE = 50;
      
      for (let i = 0; i < sortedIssues.length; i += BATCH_SIZE) {
        const batch = sortedIssues.slice(i, i + BATCH_SIZE);
        const issueIds = batch.map(issue => issue.id);
        
        // Fetch comments for this batch from relays (will also check cache, but we already loaded cache above)
        const comments = await nostrClient.fetchEvents(
          [{ '#e': issueIds, kinds: [KIND.COMMENT], limit: 500 }],
          relays,
          { useCache: 'cache-first', cacheResults: true } // Prioritize cache
        );

        // Merge new comments into the map (deduplicate by event ID)
        const existingCommentIds = new Set(
          Array.from(commentsMap.values()).flat().map(c => c.id)
        );
        
        for (const comment of comments) {
          // Skip if we already have this comment from cache
          if (existingCommentIds.has(comment.id)) continue;
          
          // Check for both lowercase 'e' and uppercase 'E' tags
          const eTag = comment.tags.find(t => t[0] === 'e' || t[0] === 'E');
          if (eTag && eTag[1]) {
            const issueId = eTag[1];
            if (!commentsMap.has(issueId)) {
              commentsMap.set(issueId, []);
            }
            commentsMap.get(issueId)!.push(comment);
          }
        }
        
        // Update state after each batch so newest issues show comments first
        issueComments = new Map(commentsMap);
      }
    } catch (error) {
      // Failed to load issue comments
    }
  }

  // Load maintainer profiles immediately from cache
  async function loadMaintainerProfiles() {
    if (!repoEvent) return;

    try {
      const pubkeys = new Set<string>();
      
      // Add repo owner and maintainers
      pubkeys.add(repoEvent.pubkey);
      const maintainers = getMaintainers();
      maintainers.forEach(m => pubkeys.add(m));

      if (pubkeys.size === 0) return;

      const uniquePubkeys = Array.from(pubkeys);

      // Fetch profiles (will use cache first, then fetch from network if needed)
      const relays = relayManager.getProfileReadRelays();
      await fetchProfiles(uniquePubkeys, relays);
    } catch (error) {
      // Failed to load profiles - non-critical
    }
  }

  async function loadAllProfiles() {
    if (issues.length === 0) return;

    try {
      // Collect all unique pubkeys from:
      // 1. Issue authors
      // 2. Comment authors
      // 3. Status authors
      // 4. Repository owner and maintainers
      const pubkeys = new Set<string>();

      // Add repo owner and maintainers
      if (repoEvent) {
        pubkeys.add(repoEvent.pubkey);
        const maintainers = getMaintainers();
        maintainers.forEach(m => pubkeys.add(m));
      }

      // Add issue authors
      issues.forEach(issue => pubkeys.add(issue.pubkey));

      // Add comment authors
      for (const comments of issueComments.values()) {
        comments.forEach(comment => pubkeys.add(comment.pubkey));
      }

      // Add status authors
      for (const status of issueStatuses.values()) {
        pubkeys.add(status.pubkey);
      }

      const uniquePubkeys = Array.from(pubkeys);

      // Batch fetch all profiles at once
      const relays = relayManager.getProfileReadRelays();
      await fetchProfiles(uniquePubkeys, relays);

    } catch (error) {
      // Failed to load profiles
      // Don't throw - profile loading is best effort
    }
  }

  async function loadDocumentation() {
    if (!repoEvent) return;

    try {
      const docs = getDocumentation();
      if (docs.length === 0) return;

      const relays = relayManager.getProfileReadRelays();
      const docMap = new Map<string, NostrEvent>();

      for (const doc of docs) {
        try {
          let kind: number;
          let pubkey: string;
          let dTag: string;
          
          // If we already have the parsed components, use them
          if (doc.kind && doc.pubkey && doc.dTag !== undefined) {
            kind = doc.kind;
            pubkey = doc.pubkey;
            dTag = doc.dTag;
          } else {
            // Otherwise, try to decode the naddr
            try {
              const decoded = nip19.decode(doc.naddr);
              if (decoded.type !== 'naddr') {
                // Invalid documentation naddr format
                continue;
              }

              const naddrData = decoded.data as { kind: number; pubkey: string; identifier?: string; relays?: string[] };
              kind = naddrData.kind;
              pubkey = naddrData.pubkey;
              dTag = naddrData.identifier || '';
            } catch (decodeError) {
              // Failed to decode documentation naddr
              continue;
            }
          }

          // Merge relays
          const docRelays = doc.relay ? [doc.relay] : [];
          const standardRelays = relayManager.getProfileReadRelays();
          const allRelays = [...new Set([...standardRelays, ...docRelays])];

          // Fetch the documentation event
          const events = await nostrClient.fetchEvents(
            [{ kinds: [kind], authors: [pubkey], '#d': [dTag], limit: 1 }],
            allRelays,
            { useCache: 'cache-first', cacheResults: true }
          );

          if (events.length > 0) {
            docMap.set(doc.naddr, events[0]);
          }
        } catch (error) {
          // Failed to load documentation
        }
      }

      documentationEvents = docMap;
    } catch (error) {
      // Failed to load documentation
    }
  }

  function getRepoATag(): string | null {
    if (!repoEvent) return null;
    const dTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'd')?.[1] || '';
    if (dTag) {
      return `${repoEvent.kind}:${repoEvent.pubkey}:${dTag}`;
    }
    return null;
  }

  function getRepoName(): string {
    try {
      if (!repoEvent) return 'Repository';
      
      if (!Array.isArray(repoEvent.tags)) return 'Repository';
      
      const nameTag = repoEvent.tags.find(t => Array.isArray(t) && (t[0] === 'name' || t[0] === 'title'));
      if (nameTag && nameTag[1]) return String(nameTag[1]);
      
      if (repoEvent.content) {
        try {
          const content = JSON.parse(repoEvent.content);
          if (content && typeof content === 'object') {
            if (content.name) return String(content.name);
            if (content.title) return String(content.title);
          }
        } catch {
          // Not JSON, ignore
        }
      }
      
      const dTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'd');
      if (dTag && dTag[1]) return String(dTag[1]);
      
      return gitRepo?.name || 'Repository';
    } catch (error) {
      // Failed to get repo name
      return 'Repository';
    }
  }

  function getRepoDescription(): string {
    try {
      if (!repoEvent) return '';
      
      if (!Array.isArray(repoEvent.tags)) return '';
      
      const descTag = repoEvent.tags.find(t => Array.isArray(t) && (t[0] === 'description' || t[0] === 'summary'));
      if (descTag && descTag[1]) return String(descTag[1]);
      
      if (repoEvent.content) {
        try {
          const content = JSON.parse(repoEvent.content);
          if (content && typeof content === 'object' && content.description) {
            return String(content.description);
          }
        } catch {
          // Not JSON, ignore
        }
      }
      
      return gitRepo?.description || '';
    } catch (error) {
      // Failed to get repo description
      return '';
    }
  }

  function getWebUrls(): string[] {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return [];
    return repoEvent.tags
      .filter(t => Array.isArray(t) && t[0] === 'web' && t[1])
      .map(t => String(t[1]));
  }

  function getCloneUrls(): string[] {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return [];
    return repoEvent.tags
      .filter(t => Array.isArray(t) && t[0] === 'clone' && t[1])
      .map(t => {
        const url = String(t[1]);
        // Convert SSH URLs to HTTPS
        if (url.startsWith('git@')) {
          const httpsUrl = convertSshToHttps(url);
          return httpsUrl || url; // Fallback to original if conversion fails
        }
        return url;
      });
  }

  function getRelays(): string[] {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return [];
    const relayTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'relays');
    if (relayTag && relayTag.length > 1) {
      return relayTag.slice(1).filter(r => r && typeof r === 'string') as string[];
    }
    return [];
  }

  function getMaintainers(): string[] {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return [];
    const maintainerTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'maintainers');
    if (maintainerTag && maintainerTag.length > 1) {
      return maintainerTag.slice(1).filter(m => m && typeof m === 'string') as string[];
    }
    return [];
  }

  function getDocumentation(): Array<{ naddr: string; relay?: string; kind?: number; pubkey?: string; dTag?: string }> {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return [];
    return repoEvent.tags
      .filter(t => Array.isArray(t) && t[0] === 'documentation' && t[1])
      .map(t => {
        const docValue = String(t[1]);
        const relay = t[2] ? String(t[2]) : undefined;
        
        // Check if it's already a bech32 naddr
        if (docValue.startsWith('naddr1')) {
          return { naddr: docValue, relay };
        }
        
        // Otherwise, it might be in format "kind:pubkey:d-tag"
        const parts = docValue.split(':');
        if (parts.length >= 3) {
          const kind = parseInt(parts[0], 10);
          const pubkey = parts[1];
          const dTag = parts.slice(2).join(':'); // In case d-tag contains colons
          
          // Construct naddr
          try {
            const naddr = nip19.naddrEncode({
              kind,
              pubkey,
              identifier: dTag,
              relays: relay ? [relay] : []
            });
            return { naddr, relay, kind, pubkey, dTag };
          } catch (error) {
            // Failed to encode naddr
            return { naddr: docValue, relay, kind, pubkey, dTag };
          }
        }
        
        // Fallback: return as-is
        return { naddr: docValue, relay };
      });
  }

  function getImageUrl(): string | null {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return null;
    const imageTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'image' && t[1]);
    return imageTag?.[1] || null;
  }

  function getBannerUrl(): string | null {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return null;
    const bannerTag = repoEvent.tags.find(t => Array.isArray(t) && t[0] === 'banner' && t[1]);
    return bannerTag?.[1] || null;
  }

  function isPrimary(): boolean {
    if (!repoEvent || !Array.isArray(repoEvent.tags)) return false;
    return repoEvent.tags.some(t => Array.isArray(t) && t[0] === 'primary');
  }

  function formatNpub(pubkey: string): string {
    try {
      return nip19.npubEncode(pubkey);
    } catch {
      return pubkey.slice(0, 16) + '...';
    }
  }

  function extractRelayDomain(relayUrl: string): string {
    try {
      // Remove protocol (wss://, ws://, https://, http://)
      const url = relayUrl.replace(/^(wss?|https?):\/\//, '');
      // Remove path and port if present
      const domain = url.split('/')[0].split(':')[0];
      return domain;
    } catch {
      return relayUrl;
    }
  }

  function renderReadme(content: string, format: 'markdown' | 'asciidoc'): string {
    let html: string;
    if (format === 'asciidoc') {
      const result = asciidoctor.convert(content, { safe: 'safe', attributes: { showtitle: true } });
      html = typeof result === 'string' ? result : String(result);
    } else {
      html = marked.parse(content) as string;
    }
    // Sanitize the HTML output
    html = sanitizeHtml(html);
    
    // Process relative image and link paths for GitLab repos
    if (gitRepo && gitRepo.url) {
      html = processRelativePaths(html, gitRepo);
    }
    
    return html;
  }

  function processRelativePaths(html: string, repo: GitRepoInfo): string {
    // Extract Git URL info
    if (!repoEvent) return html;
    const gitUrls = extractGitUrls(repoEvent);
    if (gitUrls.length === 0) return html;
    
    const gitUrl = gitUrls[0];
    const urlObj = new URL(gitUrl);
    const host = urlObj.origin;
    const pathParts = urlObj.pathname.split('/').filter(p => p);
    
    // Determine platform and extract owner/repo
    let owner: string;
    let repoName: string;
    let baseUrl: string;
    let defaultBranch: string;
    
    if (host.includes('github.com')) {
      // GitHub: /owner/repo.git or /owner/repo
      if (pathParts.length >= 2) {
        owner = pathParts[0];
        repoName = pathParts[1].replace(/\.git$/, '');
        baseUrl = 'https://api.github.com';
        defaultBranch = repo.defaultBranch || 'main';
      } else {
        return html; // Can't parse, return as-is
      }
    } else if (host.includes('gitlab.com') || host.includes('gitea.com') || host.includes('codeberg.org')) {
      // GitLab/Gitea: /owner/repo.git or /owner/repo
      if (pathParts.length >= 2) {
        owner = pathParts[0];
        repoName = pathParts[1].replace(/\.git$/, '');
        if (host.includes('gitlab.com')) {
          baseUrl = 'https://gitlab.com/api/v4';
        } else if (host.includes('gitea.com')) {
          baseUrl = `${host}/api/v1`;
        } else if (host.includes('codeberg.org')) {
          baseUrl = 'https://codeberg.org/api/v1';
        } else {
          baseUrl = `${host}/api/v1`;
        }
        defaultBranch = repo.defaultBranch || 'master';
      } else {
        return html; // Can't parse, return as-is
      }
    } else {
      return html; // Unknown platform, return as-is
    }
    
    const projectPath = `${owner}/${repoName}`;
    const encodedPath = encodeURIComponent(projectPath);
    
    // Process img src attributes
    html = html.replace(/<img([^>]*)\ssrc=["']([^"']+)["']([^>]*)>/gi, (match, before, src, after) => {
      // Skip if already absolute URL
      if (src.startsWith('http://') || src.startsWith('https://') || src.startsWith('data:') || src.startsWith('#')) {
        return match;
      }
      
      // Convert relative path to GitLab raw file URL
      const filePath = src.startsWith('/') ? src.slice(1) : src;
      let rawUrl: string;
      
      if (host.includes('github.com')) {
        rawUrl = `https://raw.githubusercontent.com/${projectPath}/${defaultBranch}/${filePath}`;
      } else if (host.includes('gitlab.com')) {
        rawUrl = `/api/gitea-proxy/projects/${encodedPath}/repository/files/${encodeURIComponent(filePath)}/raw?baseUrl=${encodeURIComponent(baseUrl)}&ref=${defaultBranch}`;
      } else {
        // Gitea/Codeberg
        rawUrl = `/api/gitea-proxy/repos/${encodedPath}/raw/${encodeURIComponent(filePath)}?baseUrl=${encodeURIComponent(baseUrl)}&ref=${defaultBranch}`;
      }
      
      return `<img${before} src="${rawUrl}"${after}>`;
    });
    
    // Process a href attributes (for relative links to files)
    html = html.replace(/<a([^>]*)\shref=["']([^"']+)["']([^>]*)>/gi, (match, before, href, after) => {
      // Skip if already absolute URL, anchor, or mailto
      if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('#') || href.startsWith('mailto:')) {
        return match;
      }
      
      // Only convert relative paths that look like file paths (have extensions or are in common directories)
      const isFile = /\.(md|txt|adoc|rst|png|jpg|jpeg|gif|svg|pdf|zip|tar|gz)$/i.test(href) || 
                     /^(resources|assets|images|img|docs|files)\//i.test(href);
      
      if (!isFile) {
        return match; // Probably a relative anchor or page link, leave as-is
      }
      
      // Convert relative path to GitLab raw file URL
      const filePath = href.startsWith('/') ? href.slice(1) : href;
      let rawUrl: string;
      
      if (host.includes('github.com')) {
        rawUrl = `https://raw.githubusercontent.com/${projectPath}/${defaultBranch}/${filePath}`;
      } else if (host.includes('gitlab.com')) {
        rawUrl = `/api/gitea-proxy/projects/${encodedPath}/repository/files/${encodeURIComponent(filePath)}/raw?baseUrl=${encodeURIComponent(baseUrl)}&ref=${defaultBranch}`;
      } else {
        // Gitea/Codeberg
        rawUrl = `/api/gitea-proxy/repos/${encodedPath}/raw/${encodeURIComponent(filePath)}?baseUrl=${encodeURIComponent(baseUrl)}&ref=${defaultBranch}`;
      }
      
      return `<a${before} href="${rawUrl}"${after}>`;
    });
    
    return html;
  }

  function getFileTree(files: GitFile[]): any {
    const tree: any = {};
    
    for (const file of files) {
      const parts = file.path.split('/').filter(p => p); // Remove empty parts
      let current = tree;
      
      for (let i = 0; i < parts.length; i++) {
        const part = parts[i];
        if (i === parts.length - 1) {
          // File
          current[part] = file;
        } else {
          // Directory
          if (!current[part] || current[part].path) {
            // Create directory if it doesn't exist or if it's currently a file (shouldn't happen)
            current[part] = {};
          }
          current = current[part];
        }
      }
    }
    
    return tree;
  }

  function renderFileTree(tree: any, level = 0): string {
    if (!tree || typeof tree !== 'object') return '';
    
    let result = '';
    const entries = Object.entries(tree).sort(([a, valA], [b, valB]) => {
      const aIsFile = valA && typeof valA === 'object' && 'path' in valA;
      const bIsFile = valB && typeof valB === 'object' && 'path' in valB;
      const aIsDir = valA && typeof valA === 'object' && !('path' in valA);
      const bIsDir = valB && typeof valB === 'object' && !('path' in valB);
      if (aIsDir && !bIsDir) return -1;
      if (!aIsDir && bIsDir) return 1;
      return a.localeCompare(b);
    });

    for (const [name, value] of entries) {
      if (!value || typeof value !== 'object') continue;
      
      const indent = '  '.repeat(level);
      if ('path' in value) {
        // File
        result += `${indent}📄 ${name}\n`;
      } else {
        // Directory
        result += `${indent}📁 ${name}/\n`;
        result += renderFileTree(value, level + 1);
      }
    }
    
    return result;
  }
</script>

<Header />

<main class="container mx-auto px-4 py-8">
  {#if loading}
    <div class="loading-state">
      <p class="text-fog-text dark:text-fog-dark-text">Loading repository...</p>
    </div>
  {:else if !repoEvent}
    <div class="empty-state">
      <p class="text-fog-text dark:text-fog-dark-text">Repository not found.</p>
    </div>
  {:else}
    {#if getBannerUrl()}
      <div class="repo-banner-container">
        <img src={getBannerUrl()!} alt="{getRepoName()} banner" class="repo-banner" />
      </div>
    {/if}
    <PageHeader title={getRepoName()} onRefresh={loadRepo} refreshLoading={loading || loadingRepo} />
    <div class="repo-header mb-6">
      <div class="repo-header-top">
        {#if getImageUrl()}
          <div class="repo-profile-image-container">
            <img src={getImageUrl()!} alt="{getRepoName()}" class="repo-profile-image" />
          </div>
        {/if}
        <div class="repo-title-section">
          <div class="repo-title-row">
            {#if repoEvent}
              <EventMenu event={repoEvent} showContentActions={true} />
            {/if}
          </div>
          {#if gitRepo?.usingGitHubToken}
            <div class="github-token-notice mb-4 p-3 bg-fog-highlight dark:bg-fog-dark-highlight border border-fog-border dark:border-fog-dark-border rounded text-sm text-fog-text dark:text-fog-dark-text">
              <Icon name="key" size={16} class="inline mr-2" />
              Using your saved GitHub API token for authenticated requests
            </div>
          {/if}
          {#if getRepoDescription()}
            <p class="text-fog-text-light dark:text-fog-dark-text-light mb-4">
              {getRepoDescription()}
            </p>
          {/if}
        </div>
      </div>
      
      <!-- Tabs -->
      <div class="tabs">
        <button
          class="tab-button"
          class:active={activeTab === 'metadata'}
          onclick={() => setActiveTab('metadata')}
        >
          Metadata
        </button>
        <button
          class="tab-button"
          class:active={activeTab === 'about'}
          onclick={() => setActiveTab('about')}
        >
          About
        </button>
        <button
          class="tab-button"
          class:active={activeTab === 'repository'}
          onclick={() => setActiveTab('repository')}
        >
          Repository
        </button>
        <button
          class="tab-button"
          class:active={activeTab === 'issues'}
          onclick={() => setActiveTab('issues')}
        >
          Issues {issues.length > 0 ? `(${issues.length})` : ''}
        </button>
        {#if getDocumentation().length > 0}
          <button
            class="tab-button"
            class:active={activeTab === 'documentation'}
            onclick={() => setActiveTab('documentation')}
          >
            Documentation
          </button>
        {/if}
      </div>
    </div>

    <!-- Tab Content -->
    <div class="tab-content">
      {#if activeTab === 'metadata'}
        <div class="metadata-tab">
          <!-- Repository Metadata -->
          <div class="repo-meta-section">
            <!-- Event ID and Naddr -->
            <div class="metadata-item mb-4">
              <strong class="metadata-label">Event ID:</strong>
              <div class="metadata-value">
                <code class="event-id">{repoEvent.id}</code>
              </div>
            </div>
            <div class="metadata-item mb-4">
              <strong class="metadata-label">Naddr:</strong>
              <div class="metadata-value">
                <code class="naddr-code">{naddr}</code>
              </div>
            </div>

            <!-- Links -->
            <div class="metadata-item mb-4">
              <strong class="metadata-label">Links:</strong>
              <div class="metadata-value">
                {#if gitRepo?.url}
                  <a href={gitRepo.url} target="_blank" rel="noopener noreferrer" class="metadata-link">
                    {gitRepo.url}
                  </a>
                {/if}
                {#each getWebUrls() as webUrl}
                  <a href={webUrl} target="_blank" rel="noopener noreferrer" class="metadata-link">
                    {webUrl}
                  </a>
                {/each}
              </div>
            </div>

            <!-- Clone URLs -->
            {#if getCloneUrls().length > 0}
              <div class="metadata-item mb-4">
                <strong class="metadata-label">Clone URLs:</strong>
                <div class="metadata-value">
                  {#each getCloneUrls() as cloneUrl}
                    <code class="clone-url">{cloneUrl}</code>
                  {/each}
                </div>
              </div>
            {/if}

            <!-- Relays -->
            {#if getRelays().length > 0}
              <div class="metadata-item mb-4">
                <strong class="metadata-label">Relays:</strong>
                <div class="metadata-value">
                  {#each getRelays() as relay}
                    {@const domain = extractRelayDomain(relay)}
                    <a href="/feed/relay/{domain}" class="relay-link">
                      {relay}
                    </a>
                  {/each}
                </div>
              </div>
            {/if}

            <!-- Maintainers -->
            {#if getMaintainers().length > 0}
              <div class="metadata-item mb-4">
                <strong class="metadata-label">Maintainers:</strong>
                <div class="metadata-value maintainers-list">
                  {#each getMaintainers() as maintainer}
                    <div class="maintainer-item" class:is-owner={maintainer === repoEvent.pubkey}>
                      <ProfileBadge pubkey={maintainer} inline={true} />
                    </div>
                  {/each}
                </div>
              </div>
            {/if}

            <!-- Primary Badge -->
            {#if isPrimary()}
              <div class="metadata-item mb-4">
                <span class="primary-badge">Primary Repository</span>
              </div>
            {/if}
          </div>
        </div>
      {:else if activeTab === 'about'}
        <div class="about-tab">
          <!-- README -->
          {#if gitRepo?.readme}
            <div class="readme-container">
              {@html renderReadme(gitRepo.readme.content, gitRepo.readme.format)}
            </div>
          {:else}
            <div class="empty-state">
              <p class="text-fog-text dark:text-fog-dark-text">No README found.</p>
            </div>
          {/if}
        </div>
      {:else if activeTab === 'repository'}
        <div class="repository-tab">
          {#if loadingGitRepo}
            <div class="loading-state">
              <p class="text-fog-text dark:text-fog-dark-text">Loading repository data...</p>
            </div>
          {:else if gitRepo}
            <!-- Branch and Commit Info -->
            <div class="repo-info-section mb-6">
              <h2 class="text-xl font-bold text-fog-text dark:text-fog-dark-text mb-4">
                Latest Commit
              </h2>
              {#if gitRepo.commits.length > 0}
                <div class="commit-card">
                  <div class="commit-header">
                    <span class="commit-sha">{gitRepo.commits[0].sha.slice(0, 7)}</span>
                    <span class="commit-message">{gitRepo.commits[0].message}</span>
                  </div>
                  <div class="commit-meta">
                    <span>{gitRepo.commits[0].author}</span>
                    <span>{new Date(gitRepo.commits[0].date).toLocaleString()}</span>
                  </div>
                </div>
              {/if}

              <h2 class="text-xl font-bold text-fog-text dark:text-fog-dark-text mb-4 mt-6">
                Branches
              </h2>
              <div class="branches-list">
                {#each gitRepo.branches as branch}
                  <div class="branch-item" class:default={branch.name === gitRepo.defaultBranch}>
                    <span class="branch-name">{branch.name}</span>
                    {#if branch.name === gitRepo.defaultBranch}
                      <span class="branch-badge">default</span>
                    {/if}
                    <span class="branch-commit">{branch.commit.sha.slice(0, 7)}</span>
                    <span class="branch-message">{branch.commit.message}</span>
                  </div>
                {/each}
              </div>
            </div>

            <!-- File Structure -->
            <div class="file-structure-section">
              <h2 class="text-xl font-bold text-fog-text dark:text-fog-dark-text mb-4">
                File Structure
              </h2>
              {#if gitRepo.files.length > 0}
                <FileExplorer files={gitRepo.files} repoInfo={gitRepo} />
              {:else}
                <div class="empty-state">
                  <p class="text-fog-text dark:text-fog-dark-text">No files found.</p>
                </div>
              {/if}
            </div>
          {:else}
            <div class="empty-state">
              <p class="text-fog-text dark:text-fog-dark-text">Git repository data not available.</p>
            </div>
          {/if}
        </div>
      {:else if activeTab === 'issues'}
        <div class="issues-tab">
          {#if loadingIssues}
            <div class="loading-state">
              <p class="text-fog-text dark:text-fog-dark-text">Loading issues...</p>
            </div>
          {:else if issues.length > 0}
            <div class="issues-filter">
              <div class="issues-filter-left">
                <label for="status-filter" class="filter-label">Filter by status:</label>
                <select
                  id="status-filter"
                  value={statusFilter || 'all'}
                  onchange={(e) => {
                    const value = (e.target as HTMLSelectElement).value;
                    statusFilter = value === 'all' ? null : value;
                  }}
                  class="status-filter-select"
                >
                  <option value="all">All</option>
                  {#each availableStatuses as statusOption}
                    <option value={statusOption}>{statusOption}</option>
                  {/each}
                </select>
                <span class="filter-count">
                  {#if statusFilter}
                    Showing {filteredIssues.length} of {issues.length} issues
                  {:else}
                    {issues.length} {issues.length === 1 ? 'issue' : 'issues'}
                  {/if}
                  {#if loadingIssueData}
                    <span class="loading-indicator"> (loading details...)</span>
                  {/if}
                </span>
              </div>
              {#if sessionManager.getSession()}
                {@const repoATag = getRepoATag()}
                <a href="/write?kind={KIND.ISSUE}{repoATag ? `&a=${encodeURIComponent(repoATag)}` : ''}" class="see-more-events-btn-header" title="Create a new issue">
                  <Icon name="edit" size={16} />
                  <span>New Issue</span>
                </a>
              {/if}
            </div>
            <div class="issues-list">
              {#if filteredIssues.length > 0}
                {#each paginatedIssues as issue}
                {@const currentStatus = getCurrentStatus(issue.id)}
                {@const isChanging = changingStatus.get(issue.id) || false}
                {@const isLoggedIn = !!sessionManager.getSession()}
                <div class="issue-item">
                  <div class="issue-header">
                    <div class="issue-status-control">
                      <label for="status-{issue.id}" class="status-label">Status:</label>
                      <select
                        id="status-{issue.id}"
                        value={currentStatus}
                        onchange={(e) => {
                          const newStatus = (e.target as HTMLSelectElement).value;
                          if (newStatus !== currentStatus) {
                            changeIssueStatus(issue.id, newStatus);
                          }
                        }}
                        disabled={isChanging || !isLoggedIn}
                        class="status-select"
                        class:open={currentStatus === 'open'}
                        class:closed={currentStatus === 'closed'}
                        class:resolved={currentStatus === 'resolved'}
                        class:draft={currentStatus === 'draft'}
                      >
                        {#each availableStatuses as statusOption}
                          <option value={statusOption} selected={statusOption === currentStatus}>
                            {statusOption}
                          </option>
                        {/each}
                        {#if !availableStatuses.includes(currentStatus)}
                          <option value={currentStatus} selected>{currentStatus}</option>
                        {/if}
                      </select>
                      {#if isChanging}
                        <span class="status-changing">Updating...</span>
                      {/if}
                    </div>
                  </div>
                  <FeedPost post={issue} />
                  {#if issueComments.has(issue.id)}
                    <div class="issue-comments">
                      <h3 class="comments-header">Comments ({issueComments.get(issue.id)!.length})</h3>
                      {#each issueComments.get(issue.id)! as comment}
                        <div class="comment-item">
                          <FeedPost post={comment} />
                        </div>
                      {/each}
                    </div>
                  {/if}
                </div>
                {/each}
                
                <!-- Pagination controls -->
                {#if totalPages > 1}
                  <div class="pagination pagination-bottom">
                    <button
                      onclick={() => issuesPage = Math.max(1, issuesPage - 1)}
                      disabled={issuesPage === 1}
                      class="pagination-button"
                      aria-label="Previous page"
                    >
                      Previous
                    </button>
                    <span class="pagination-info">
                      Page {issuesPage} of {totalPages} ({filteredIssues.length} {filteredIssues.length === 1 ? 'issue' : 'issues'})
                    </span>
                    <button
                      onclick={() => issuesPage = Math.min(totalPages, issuesPage + 1)}
                      disabled={issuesPage === totalPages}
                      class="pagination-button"
                      aria-label="Next page"
                    >
                      Next
                    </button>
                  </div>
                {/if}
              {:else}
                <div class="empty-state">
                  <p class="text-fog-text dark:text-fog-dark-text">No issues found with status "{statusFilter}".</p>
                  {#if sessionManager.getSession()}
                    {@const repoATag = getRepoATag()}
                    <a href="/write?kind={KIND.ISSUE}{repoATag ? `&a=${encodeURIComponent(repoATag)}` : ''}" class="see-more-events-btn-header" title="Create a new issue">
                      <Icon name="edit" size={16} />
                      <span>New Issue</span>
                    </a>
                  {/if}
                </div>
              {/if}
            </div>
          {:else}
            <div class="empty-state">
              <p class="text-fog-text dark:text-fog-dark-text">No issues found.</p>
              {#if sessionManager.getSession()}
                {@const repoATag = getRepoATag()}
                <a href="/write?kind={KIND.ISSUE}{repoATag ? `&a=${encodeURIComponent(repoATag)}` : ''}" class="see-more-events-btn-header" title="Create a new issue">
                  <Icon name="edit" size={16} />
                  <span>New Issue</span>
                </a>
              {/if}
            </div>
          {/if}
        </div>
      {:else if activeTab === 'documentation'}
        <div class="documentation-tab">
          {#if documentationEvents.size > 0}
            <div class="documentation-list">
              {#each Array.from(documentationEvents.entries()) as [docNaddr, docEvent]}
                <div class="documentation-item">
                  <div class="doc-header">
                    <div class="doc-meta">
                      <span class="doc-kind">Kind {docEvent.kind}</span>
                      <a href="/event/{docEvent.id}" onclick={(e) => { e.preventDefault(); sessionStorage.setItem('aitherboard_preloadedEvent', JSON.stringify(docEvent)); goto(`/event/${docEvent.id}`); }} class="doc-event-link">View Event</a>
                      <EventMenu event={docEvent} showContentActions={true} />
                    </div>
                  </div>
                  <div class="doc-content">
                    {#if docEvent.kind === KIND.LONG_FORM_NOTE || docEvent.kind === KIND.SHORT_TEXT_NOTE}
                      <MarkdownRenderer content={docEvent.content} event={docEvent} />
                    {:else}
                      <!-- Try to detect if it's asciidoc or markdown -->
                      {@const isAsciidoc = docEvent.content.includes('= ') || docEvent.content.includes('== ') || docEvent.tags.some(t => Array.isArray(t) && t[0] === 'format' && t[1] === 'asciidoc')}
                      {#if isAsciidoc}
                        <div class="readme-container">
                          {@html renderReadme(docEvent.content, 'asciidoc')}
                        </div>
                      {:else}
                        <MarkdownRenderer content={docEvent.content} event={docEvent} />
                      {/if}
                    {/if}
                  </div>
                </div>
              {/each}
            </div>
          {:else}
            <div class="empty-state">
              <p class="text-fog-text dark:text-fog-dark-text">No documentation found.</p>
            </div>
          {/if}
        </div>
      {/if}
    </div>
  {/if}
</main>

<style>

  .loading-state,
  .empty-state {
    padding: 2rem;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
  }

  .repo-banner-container {
    width: 100%;
    height: 300px;
    overflow: hidden;
    border-radius: 0.5rem;
    margin-bottom: 2rem;
    background: var(--fog-highlight, #f3f4f6);
    display: flex;
    align-items: center;
    justify-content: center;
  }

  :global(.dark) .repo-banner-container {
    background: var(--fog-dark-highlight, #475569);
  }

  .repo-banner {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 0.5rem;
  }

  .repo-header {
    border-bottom: 1px solid var(--fog-border, #e5e7eb);
    padding-bottom: 1rem;
  }

  :global(.dark) .repo-header {
    border-bottom-color: var(--fog-dark-border, #374151);
  }

  .repo-header-top {
    display: flex;
    align-items: flex-start;
    gap: 1.5rem;
    flex-wrap: wrap;
  }

  .repo-profile-image-container {
    flex-shrink: 0;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    overflow: hidden;
    background: var(--fog-highlight, #f3f4f6);
    border: 2px solid var(--fog-border, #e5e7eb);
    display: flex;
    align-items: center;
    justify-content: center;
  }

  :global(.dark) .repo-profile-image-container {
    background: var(--fog-dark-highlight, #475569);
    border-color: var(--fog-dark-border, #374151);
  }

  .repo-profile-image {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }

  .repo-title-section {
    flex: 1;
    min-width: 0;
  }

  .repo-title-row {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    justify-content: space-between;
    flex-wrap: wrap;
  }




  .tabs {
    display: flex;
    gap: 0.5rem;
    border-bottom: 1px solid var(--fog-border, #e5e7eb);
    flex-wrap: wrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }

  :global(.dark) .tabs {
    border-bottom-color: var(--fog-dark-border, #374151);
  }

  .tab-button {
    padding: 0.75rem 1.25rem;
    border: none;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: var(--fog-text-light, #52667a);
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
    white-space: nowrap;
    min-height: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  :global(.dark) .tab-button {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .tab-button:hover {
    color: var(--fog-text, #1f2937);
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .tab-button:hover {
    color: var(--fog-dark-text, #f9fafb);
    background: var(--fog-dark-highlight, #475569);
  }

  .tab-button.active {
    color: var(--fog-text, #1f2937);
    border-bottom-color: var(--fog-accent, #64748b);
    background: var(--fog-highlight, #f3f4f6);
    font-weight: 600;
  }

  :global(.dark) .tab-button.active {
    color: var(--fog-dark-text, #f9fafb);
    border-bottom-color: var(--fog-dark-accent, #94a3b8);
    background: var(--fog-dark-highlight, #475569);
  }

  .tab-button:focus {
    outline: 2px solid var(--fog-accent, #64748b);
    outline-offset: 2px;
  }

  :global(.dark) .tab-button:focus {
    outline-color: var(--fog-dark-accent, #94a3b8);
  }

  @media (max-width: 640px) {
    .tabs {
      gap: 0.25rem;
      padding-bottom: 0.5rem;
    }

    .tab-button {
      padding: 0.5rem 0.75rem;
      font-size: 0.8125rem;
      min-height: 2.5rem;
    }
  }


  .tab-content {
    margin-top: 2rem;
  }

  .readme-container {
    padding: 1.5rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.5rem;
    background: var(--fog-post, #ffffff);
  }

  :global(.dark) .readme-container {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
  }

  .readme-container :global(h1),
  .readme-container :global(h2),
  .readme-container :global(h3) {
    color: var(--fog-text, #1f2937);
    margin-top: 1.5rem;
    margin-bottom: 0.75rem;
  }

  :global(.dark) .readme-container :global(h1),
  :global(.dark) .readme-container :global(h2),
  :global(.dark) .readme-container :global(h3) {
    color: var(--fog-dark-text, #f9fafb);
  }

  .readme-container :global(p) {
    color: var(--fog-text, #1f2937);
    line-height: 1.6;
    margin-bottom: 1rem;
  }

  :global(.dark) .readme-container :global(p) {
    color: var(--fog-dark-text, #f9fafb);
  }

  .readme-container :global(code) {
    background: var(--fog-highlight, #f3f4f6);
    padding: 0.125rem 0.25rem;
    border-radius: 0.25rem;
    font-family: monospace;
    color: var(--fog-text, #1f2937);
  }

  :global(.dark) .readme-container :global(code) {
    background: var(--fog-dark-highlight, #475569);
    color: var(--fog-dark-text, #f9fafb);
  }

  /* Code blocks with highlight.js are styled by vs2015 theme */
  /* Pre blocks for non-highlighted code */
  .readme-container :global(pre) {
    padding: 1rem;
    border-radius: 0.5rem;
    overflow-x: auto;
    /* Background will be overridden by vs2015 theme for hljs code blocks */
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .readme-container :global(pre) {
    background: var(--fog-dark-highlight, #475569);
  }

  .commit-card {
    padding: 1rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.5rem;
    background: var(--fog-post, #ffffff);
  }

  :global(.dark) .commit-card {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
  }

  .commit-header {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 0.5rem;
  }

  .commit-sha {
    font-family: monospace;
    color: var(--fog-accent, #64748b);
    font-size: 0.875rem;
  }

  :global(.dark) .commit-sha {
    color: var(--fog-dark-accent, #94a3b8);
  }

  .commit-message {
    color: var(--fog-text, #1f2937);
    font-weight: 500;
  }

  :global(.dark) .commit-message {
    color: var(--fog-dark-text, #f9fafb);
  }

  .commit-meta {
    display: flex;
    gap: 1rem;
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
  }

  :global(.dark) .commit-meta {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .branches-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  .branch-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.375rem;
    background: var(--fog-post, #ffffff);
  }

  :global(.dark) .branch-item {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
  }

  .branch-item.default {
    border-color: var(--fog-accent, #64748b);
  }

  :global(.dark) .branch-item.default {
    border-color: var(--fog-dark-accent, #94a3b8);
  }

  .branch-name {
    font-weight: 500;
    color: var(--fog-text, #1f2937);
  }

  :global(.dark) .branch-name {
    color: var(--fog-dark-text, #f9fafb);
  }

  .branch-badge {
    font-size: 0.75rem;
    padding: 0.125rem 0.5rem;
    border-radius: 0.25rem;
    background: var(--fog-accent, #64748b);
    color: white;
  }

  :global(.dark) .branch-badge {
    background: var(--fog-dark-accent, #94a3b8);
  }

  .branch-commit {
    font-family: monospace;
    font-size: 0.875rem;
    color: var(--fog-accent, #64748b);
  }

  :global(.dark) .branch-commit {
    color: var(--fog-dark-accent, #94a3b8);
  }

  .branch-message {
    flex: 1;
    color: var(--fog-text-light, #52667a);
    font-size: 0.875rem;
  }

  :global(.dark) .branch-message {
    color: var(--fog-dark-text-light, #a8b8d0);
  }


  .issues-filter {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
    padding: 1rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.5rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    flex-wrap: wrap;
  }

  :global(.dark) .issues-filter {
    background: var(--fog-dark-highlight, #475569);
    border-color: var(--fog-dark-border, #374151);
  }

  .issues-filter-left {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    flex: 1;
  }

  .filter-label {
    font-weight: 500;
    color: var(--fog-text, #1f2937);
    font-size: 0.875rem;
  }

  :global(.dark) .filter-label {
    color: var(--fog-dark-text, #f9fafb);
  }

  .status-filter-select {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.375rem;
    background: var(--fog-post, #ffffff);
    color: var(--fog-text, #1f2937);
    font-size: 0.875rem;
    cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
  }

  :global(.dark) .status-filter-select {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
    color: var(--fog-dark-text, #f9fafb);
  }

  .status-filter-select:hover {
    border-color: var(--fog-accent, #64748b);
  }

  :global(.dark) .status-filter-select:hover {
    border-color: var(--fog-dark-accent, #94a3b8);
  }

  .status-filter-select:focus {
    outline: none;
    border-color: var(--fog-accent, #64748b);
    box-shadow: 0 0 0 3px rgba(100, 116, 139, 0.1);
  }

  :global(.dark) .status-filter-select:focus {
    border-color: var(--fog-dark-accent, #94a3b8);
    box-shadow: 0 0 0 3px rgba(148, 163, 184, 0.2);
  }

  .filter-count {
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
  }

  :global(.dark) .filter-count {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .see-more-events-btn-header {
    padding: 0.5rem 1rem;
    border: 1px solid var(--fog-border, #cbd5e1);
    border-radius: 4px;
    background: var(--fog-post, #ffffff);
    color: var(--fog-text, #1e293b);
    cursor: pointer;
    transition: all 0.2s;
    white-space: nowrap;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
  }

  .see-more-events-btn-header:hover:not(:disabled) {
    background: var(--fog-highlight, #f1f5f9);
    border-color: var(--fog-accent, #94a3b8);
  }

  .see-more-events-btn-header:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  :global(.dark) .see-more-events-btn-header {
    background: var(--fog-dark-post, #334155);
    border-color: var(--fog-dark-border, #475569);
    color: var(--fog-dark-text, #f1f5f9);
  }

  :global(.dark) .see-more-events-btn-header:hover:not(:disabled) {
    background: var(--fog-dark-highlight, #475569);
    border-color: var(--fog-dark-accent, #64748b);
  }

  .issues-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }

  .issue-item {
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.5rem;
    padding: 1rem;
    background: var(--fog-post, #ffffff);
  }

  :global(.dark) .issue-item {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
  }

  .issue-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
    padding: 0.75rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.375rem;
  }

  :global(.dark) .issue-header {
    background: var(--fog-dark-highlight, #475569);
  }

  .issue-status-control {
    display: flex;
    align-items: center;
    gap: 0.75rem;
  }

  .status-label {
    font-weight: 600;
    color: var(--fog-text, #1f2937);
    font-size: 0.875rem;
  }

  :global(.dark) .status-label {
    color: var(--fog-dark-text, #f9fafb);
  }

  .status-select {
    padding: 0.5rem 1rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.375rem;
    background: var(--fog-post, #ffffff);
    color: var(--fog-text, #1f2937);
    font-size: 0.875rem;
    cursor: pointer;
    transition: all 0.2s;
    min-width: 120px;
  }

  :global(.dark) .status-select {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
    color: var(--fog-dark-text, #f9fafb);
  }

  .status-select:hover:not(:disabled) {
    border-color: var(--fog-accent, #64748b);
  }

  :global(.dark) .status-select:hover:not(:disabled) {
    border-color: var(--fog-dark-accent, #94a3b8);
  }

  .status-select:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }

  .status-select.open {
    border-color: #10b981;
    background: #d1fae5;
    color: #065f46;
  }

  :global(.dark) .status-select.open {
    border-color: #10b981;
    background: #064e3b;
    color: #a7f3d0;
  }

  .status-select.closed {
    border-color: #ef4444;
    background: #fee2e2;
    color: #991b1b;
  }

  :global(.dark) .status-select.closed {
    border-color: #ef4444;
    background: #7f1d1d;
    color: #fecaca;
  }

  .status-select.resolved {
    border-color: #3b82f6;
    background: #dbeafe;
    color: #1e40af;
  }

  :global(.dark) .status-select.resolved {
    border-color: #3b82f6;
    background: #1e3a8a;
    color: #bfdbfe;
  }

  .status-select.draft {
    border-color: #8b5cf6;
    background: #ede9fe;
    color: #5b21b6;
  }

  :global(.dark) .status-select.draft {
    border-color: #8b5cf6;
    background: #4c1d95;
    color: #ddd6fe;
  }

  .status-changing {
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
    font-style: italic;
  }

  :global(.dark) .status-changing {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .issue-comments {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .issue-comments {
    border-top-color: var(--fog-dark-border, #374151);
  }

  .comments-header {
    font-size: 1rem;
    font-weight: 600;
    color: var(--fog-text, #1f2937);
    margin-bottom: 0.75rem;
  }

  :global(.dark) .comments-header {
    color: var(--fog-dark-text, #f9fafb);
  }

  .comment-item {
    margin-top: 0.75rem;
    padding-left: 1rem;
    border-left: 2px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .comment-item {
    border-left-color: var(--fog-dark-border, #374151);
  }


  .repo-meta-section {
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.5rem;
    padding: 1.5rem;
    background: var(--fog-post, #ffffff);
    overflow-wrap: break-word;
    word-wrap: break-word;
  }

  :global(.dark) .repo-meta-section {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
  }

  .metadata-value {
    word-break: break-word;
    overflow-wrap: break-word;
    max-width: 100%;
  }


  .metadata-item {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  .metadata-label {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--fog-text, #1f2937);
  }

  :global(.dark) .metadata-label {
    color: var(--fog-dark-text, #f9fafb);
  }

  .metadata-value {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    font-size: 0.875rem;
    word-break: break-word;
    overflow-wrap: break-word;
    max-width: 100%;
  }

  .clone-url {
    font-family: monospace;
    padding: 0.25rem 0.5rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.25rem;
    color: var(--fog-text, #1f2937);
    word-break: break-all;
    word-wrap: break-word;
    overflow-wrap: break-word;
    display: block;
    max-width: 100%;
    overflow: hidden;
    margin-bottom: 0.5rem;
  }

  :global(.dark) .clone-url {
    background: var(--fog-dark-highlight, #475569);
    color: var(--fog-dark-text, #f9fafb);
  }

  .relay-link {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.25rem;
    color: var(--fog-accent, #64748b);
    font-size: 0.875rem;
    text-decoration: none;
    word-break: break-all;
    word-wrap: break-word;
    overflow-wrap: break-word;
    max-width: 100%;
    margin-bottom: 0.5rem;
    transition: background 0.2s;
  }

  :global(.dark) .relay-link {
    background: var(--fog-dark-highlight, #475569);
    color: var(--fog-dark-accent, #94a3b8);
  }

  .relay-link:hover {
    background: var(--fog-accent, #64748b);
    color: white;
    text-decoration: none;
  }

  :global(.dark) .relay-link:hover {
    background: var(--fog-dark-accent, #94a3b8);
    color: var(--fog-dark-text, #f9fafb);
  }


  .primary-badge {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    background: var(--fog-accent, #64748b);
    color: white;
    border-radius: 0.375rem;
    font-size: 0.875rem;
    font-weight: 500;
  }

  :global(.dark) .primary-badge {
    background: var(--fog-dark-accent, #94a3b8);
  }

  .event-id,
  .naddr-code {
    font-family: monospace;
    font-size: 0.875rem;
    padding: 0.25rem 0.5rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.25rem;
    color: var(--fog-text, #1f2937);
    word-break: break-all;
    word-wrap: break-word;
    overflow-wrap: break-word;
    display: block;
    max-width: 100%;
    overflow: hidden;
  }

  :global(.dark) .event-id,
  :global(.dark) .naddr-code {
    background: var(--fog-dark-highlight, #475569);
    color: var(--fog-dark-text, #f9fafb);
  }

  .metadata-link {
    color: var(--fog-accent, #64748b);
    text-decoration: none;
    word-break: break-all;
    word-wrap: break-word;
    overflow-wrap: break-word;
    display: block;
    max-width: 100%;
  }

  :global(.dark) .metadata-link {
    color: var(--fog-dark-accent, #94a3b8);
  }

  .metadata-link:hover {
    text-decoration: underline;
  }

  .maintainers-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  .maintainer-item {
    padding: 0.5rem;
    border-radius: 0.375rem;
    transition: background 0.2s;
  }

  .maintainer-item.is-owner {
    background: var(--fog-highlight, #f3f4f6);
    border: 1px solid var(--fog-accent, #64748b);
  }

  :global(.dark) .maintainer-item.is-owner {
    background: var(--fog-dark-highlight, #475569);
    border-color: var(--fog-dark-accent, #94a3b8);
  }

  .documentation-list {
    display: flex;
    flex-direction: column;
    gap: 2rem;
  }

  .documentation-item {
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.5rem;
    padding: 1.5rem;
    background: var(--fog-post, #ffffff);
  }

  :global(.dark) .documentation-item {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
  }

  .doc-header {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    margin-bottom: 1rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .doc-header {
    border-bottom-color: var(--fog-dark-border, #374151);
  }

  .doc-meta {
    display: flex;
    gap: 1rem;
    align-items: center;
    font-size: 0.875rem;
  }

  @media (max-width: 640px) {
    .doc-header {
      justify-content: flex-start;
    }

    .doc-meta {
      flex-direction: column;
      align-items: flex-start;
      gap: 0.5rem;
    }
  }

  .doc-kind {
    color: var(--fog-text-light, #52667a);
    padding: 0.25rem 0.5rem;
    border-radius: 0.25rem;
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .doc-kind {
    color: var(--fog-dark-text-light, #a8b8d0);
    background: var(--fog-dark-highlight, #475569);
  }

  .doc-event-link {
    color: var(--fog-accent, #64748b);
    text-decoration: none;
  }

  :global(.dark) .doc-event-link {
    color: var(--fog-dark-accent, #94a3b8);
  }

  .doc-event-link:hover {
    text-decoration: underline;
  }

  .doc-content {
    margin-top: 1rem;
  }

  .pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-top: 2rem;
    padding: 1rem;
    border-top: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .pagination {
    border-top-color: var(--fog-dark-border, #374151);
  }

  .pagination-button {
    padding: 0.5rem 1rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.375rem;
    background: var(--fog-post, #ffffff);
    color: var(--fog-text, #1f2937);
    font-size: 0.875rem;
    cursor: pointer;
    transition: all 0.2s;
  }

  .pagination-button:hover:not(:disabled) {
    background: var(--fog-highlight, #f3f4f6);
    border-color: var(--fog-accent, #64748b);
  }

  .pagination-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  :global(.dark) .pagination-button {
    border-color: var(--fog-dark-border, #374151);
    background: var(--fog-dark-post, #1f2937);
    color: var(--fog-dark-text, #f9fafb);
  }

  :global(.dark) .pagination-button:hover:not(:disabled) {
    background: var(--fog-dark-highlight, #475569);
    border-color: var(--fog-dark-accent, #94a3b8);
  }

  .pagination-info {
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
  }

  :global(.dark) .pagination-info {
    color: var(--fog-dark-text-light, #a8b8d0);
  }
</style>
