<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>RankPulse — Backlink Intelligence</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');

    /* ───────── Calm dark palette (muted, low-contrast, non-neon) ───────── */
    :root{
      --bg:#0e1217;
      --surface:#161b22;
      --surface-2:#1b212a;
      --border:#262d37;
      --border-strong:#333b47;
      --t1:#e3e7ec;     /* primary text (soft, not pure white) */
      --t2:#9aa3af;     /* secondary text */
      --t3:#6a7380;     /* muted text */
      --accent:#4cb5ab;       /* muted teal */
      --accent-hover:#63c6bc;
      --accent-soft:#14302d;
      --accent-2:#6d8db0;     /* muted slate-blue */
      --pos:#5bbd83;          /* muted green */
      --pos-soft:#16291f;
      --neg:#cf8077;          /* muted clay */
      --neg-soft:#2d1e1b;
      --warn:#c69a5d;         /* muted ochre */
      --hover:#1b212a;
      --hover-2:#222a34;
      --shadow:0 1px 2px rgba(0,0,0,.30), 0 1px 3px rgba(0,0,0,.35);
      --shadow-lg:0 6px 24px rgba(0,0,0,.40);
    }

    *{ font-family:'Inter', system-ui, sans-serif; box-sizing:border-box; }
    body{ background:var(--bg); color:var(--t1); }

    /* ───────── Remap of the Tailwind utility classes the markup/JS use,
       so the dark-theme utilities render correctly on the light palette
       without touching the render logic. ───────── */
    .text-white,.text-slate-200,.text-slate-300{ color:var(--t1)!important; }
    .text-slate-400{ color:var(--t2)!important; }
    .text-slate-500,.text-slate-600{ color:var(--t3)!important; }
    .text-blue-300,.text-blue-400,.text-pink-400{ color:var(--accent)!important; }
    .text-purple-400{ color:var(--accent-2)!important; }
    .text-emerald-400{ color:var(--pos)!important; }
    .text-red-400{ color:var(--neg)!important; }
    .text-amber-400{ color:var(--warn)!important; }
    .hover\:text-blue-300:hover,.hover\:text-blue-400:hover{ color:var(--accent-hover)!important; }
    .hover\:text-slate-300:hover{ color:var(--t1)!important; }
    .bg-white\/2{ background:var(--surface-2)!important; }
    .bg-white\/5{ background:var(--hover)!important; }
    .bg-white\/10{ background:var(--hover-2)!important; }
    .hover\:bg-white\/5:hover{ background:var(--hover)!important; }
    .hover\:bg-white\/10:hover{ background:var(--hover-2)!important; }
    .border-white\/5,.border-white\/10{ border-color:var(--border)!important; }
    .divide-white\/5 > :not([hidden]) ~ :not([hidden]){ border-color:var(--border)!important; }
    .accent-blue-500{ accent-color:var(--accent); }

    /* ───────── Components ───────── */
    .gradient-text{ color:var(--accent); }

    .card{
      background:var(--surface);
      border:1px solid var(--border);
      border-radius:12px;
      box-shadow:var(--shadow);
    }
    .card-glow{ box-shadow:var(--shadow-lg); }

    .stat-pill{
      background:var(--accent-soft);
      border:1px solid rgba(76,181,171,.28);
      border-radius:100px;
    }

    /* DR ring */
    .dr-ring{ position:relative; display:inline-flex; align-items:center; justify-content:center; }
    .dr-ring svg{ transform:rotate(-90deg); }
    .dr-value{ position:absolute; font-size:2rem; font-weight:800; line-height:1; color:var(--accent); }
    .dr-label{ position:absolute; bottom:18px; font-size:.58rem; font-weight:700; letter-spacing:.12em; color:var(--t3); text-transform:uppercase; }

    /* Search */
    .search-input{
      background:var(--surface);
      border:1px solid var(--border-strong);
      color:var(--t1);
      border-radius:9px;
      transition:border-color .15s, box-shadow .15s;
    }
    .search-input:focus{
      outline:none;
      border-color:var(--accent);
      box-shadow:0 0 0 3px rgba(44,110,106,.12);
    }
    .search-input::placeholder{ color:var(--t3); }

    .scope-select{
      background:var(--surface-2);
      border:1px solid var(--border-strong);
      color:var(--t2);
      border-radius:9px;
      padding:0 30px 0 12px;
      font-size:.875rem; font-weight:600;
      appearance:none;
      background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%238a929c' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
      background-repeat:no-repeat; background-position:right 9px center;
      cursor:pointer;
    }

    .btn-primary{
      background:var(--accent);
      color:#fff;
      border-radius:9px; font-weight:600;
      transition:background .15s;
      cursor:pointer;
    }
    .btn-primary:hover{ background:var(--accent-hover); }

    .table-row{ transition:background .12s; }
    .table-row:hover{ background:var(--hover); }
    .leaderboard-row{ transition:background .12s; }
    .leaderboard-row:hover{ background:var(--hover); cursor:pointer; }

    .badge-dr{
      border-radius:6px; padding:2px 8px;
      font-size:.75rem; font-weight:700;
      display:inline-block; min-width:42px; text-align:center;
    }

    .tag-dofollow{ background:var(--pos-soft); color:var(--pos); border-radius:5px; padding:1px 7px; font-size:.7rem; font-weight:600; }
    .tag-nofollow{ background:var(--hover-2); color:var(--t3); border-radius:5px; padding:1px 7px; font-size:.7rem; font-weight:600; }

    .skeleton{ background:linear-gradient(90deg,var(--hover) 25%,var(--hover-2) 50%,var(--hover) 75%); background-size:400%; animation:shimmer 1.4s infinite; border-radius:8px; }
    @keyframes shimmer{ 0%{background-position:100%} 100%{background-position:-100%} }
    .fade-in{ animation:fadeIn .35s ease forwards; }
    @keyframes fadeIn{ from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
    .pulse-dot{ width:7px;height:7px;border-radius:50%;background:var(--pos);animation:pulseDot 2.2s infinite; }
    @keyframes pulseDot{ 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:.5;transform:scale(1.3)} }

    ::-webkit-scrollbar{ width:8px; height:8px; }
    ::-webkit-scrollbar-track{ background:transparent; }
    ::-webkit-scrollbar-thumb{ background:#2d3540; border-radius:4px; }
    ::-webkit-scrollbar-thumb:hover{ background:#3a4350; }

    /* Sidebar report nav (uses .tab + data-tab so the JS keeps working) */
    .side-title{ font-size:.66rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--t3); padding:0 12px; margin-bottom:6px; }
    .tab{
      display:flex; align-items:center; gap:10px;
      padding:9px 12px; border-radius:8px;
      font-size:.9rem; font-weight:500; color:var(--t2);
      cursor:pointer; transition:all .14s; user-select:none;
      border:1px solid transparent;
    }
    .tab svg{ width:16px; height:16px; opacity:.7; flex-shrink:0; }
    .tab:hover{ color:var(--t1); background:var(--hover); }
    .tab.active{ color:var(--accent); background:var(--accent-soft); border-color:rgba(76,181,171,.32); font-weight:600; }
    .tab.active svg{ opacity:1; }

    /* Filter chips */
    .chip{ padding:5px 12px; border-radius:7px; font-size:.75rem; font-weight:600; cursor:pointer; transition:all .14s; user-select:none; border:1px solid var(--border-strong); color:var(--t2); background:var(--surface); }
    .chip:hover{ color:var(--t1); border-color:#3d4654; }
    .chip.active{ color:var(--accent); background:var(--accent-soft); border-color:rgba(76,181,171,.32); }

    /* Anchor cloud */
    .anchor-bubble{ display:inline-flex; align-items:center; gap:8px; padding:7px 13px; border-radius:8px; margin:4px; transition:all .14s; border:1px solid var(--border); background:var(--surface-2); }
    .anchor-bubble:hover{ transform:translateY(-1px); border-color:rgba(76,181,171,.32); cursor:pointer; box-shadow:var(--shadow); }

    /* Anchor category dots (muted) */
    .cat-branded{ background:#46627f; }
    .cat-naked{ background:#7d76a0; }
    .cat-generic{ background:#977341; }
    .cat-topical{ background:#4f8268; }
    .cat-image{ background:#a06a82; }
    .cat-empty{ background:#9aa1ab; }
    .cat-dot{ width:8px; height:8px; border-radius:50%; display:inline-block; }

    /* Position badges (muted soft) */
    .pos-content{ background:var(--pos-soft); color:var(--pos); }
    .pos-nav{ background:#2a2417; color:var(--warn); }
    .pos-footer{ background:var(--neg-soft); color:var(--neg); }
    .pos-header{ background:#232132; color:#9a8fc0; }
    .pos-sidebar{ background:#1a2330; color:var(--accent-2); }

    /* Status badges */
    .status-live{ background:var(--pos-soft); color:var(--pos); }
    .status-lost{ background:var(--hover-2); color:var(--t3); }

    .surround{ font-size:.75rem; color:var(--t3); font-style:italic; padding:6px 10px; background:var(--surface-2); border-radius:6px; border-left:2px solid rgba(76,181,171,.4); margin-top:4px; }

    /* Results layout */
    .results-grid{ display:grid; grid-template-columns:236px 1fr; gap:26px; align-items:start; }
    .results-side{ position:sticky; top:78px; }
    @media (max-width:900px){
      .results-grid{ grid-template-columns:1fr; }
      .results-side{ position:static; }
    }
  </style>
</head>
<body class="min-h-screen">

<!-- Top bar -->
<nav class="sticky top-0 z-50" style="background:rgba(14,18,23,.85);backdrop-filter:blur(10px);border-bottom:1px solid var(--border)">
  <div class="max-w-7xl mx-auto px-6 h-[60px] flex items-center gap-5">
    <!-- Brand -->
    <button onclick="goHome()" class="flex items-center gap-2.5 flex-shrink-0">
      <div class="w-7 h-7 rounded-md flex items-center justify-center" style="background:var(--accent)">
        <svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"/>
        </svg>
      </div>
      <span class="font-bold text-[17px] tracking-tight" style="color:var(--t1)">Rank<span style="color:var(--accent)">Pulse</span></span>
    </button>

    <!-- Search (Site Explorer style) -->
    <div class="flex-1 max-w-2xl flex items-center gap-2 mx-auto">
      <select id="scopeSelect" class="scope-select h-10 hidden sm:block" title="Search mode">
        <option>Domain</option>
        <option>*.domain/*</option>
        <option>Exact URL</option>
      </select>
      <input id="searchInput" type="text" placeholder="Enter a domain, e.g. github.com"
        class="search-input flex-1 h-10 px-4 text-sm"
        onkeydown="if(event.key==='Enter') searchDomain()" />
      <button onclick="searchDomain()" class="btn-primary h-10 px-5 text-sm text-white whitespace-nowrap">Analyze</button>
    </div>

    <!-- Live indicator -->
    <div class="hidden md:flex items-center gap-2 stat-pill px-3 py-1.5 text-xs flex-shrink-0">
      <div class="pulse-dot"></div>
      <span style="color:var(--accent)" class="font-semibold">Live crawl</span>
    </div>
  </div>
</nav>

<!-- ───────────────── LANDING ───────────────── -->
<div id="landing">
  <section class="max-w-7xl mx-auto px-6 pt-12 pb-8">
    <div class="max-w-2xl">
      <h1 class="text-3xl font-extrabold tracking-tight mb-2" style="color:var(--t1)">
        Backlink intelligence at scale
      </h1>
      <p class="text-[15px]" style="color:var(--t2)">
        A continuously crawled link graph across millions of domains. Enter any domain to see its
        Domain Rating, referring domains and full backlink profile.
      </p>
      <div id="quickExamples" class="flex flex-wrap gap-2 mt-4 items-center">
        <span class="text-sm" style="color:var(--t3)">Try:</span>
        <button onclick="quickSearch('github.com')" class="text-sm font-medium hover:underline" style="color:var(--accent)">github.com</button>
        <button onclick="quickSearch('facebook.com')" class="text-sm font-medium hover:underline" style="color:var(--accent)">facebook.com</button>
        <button onclick="quickSearch('linkedin.com')" class="text-sm font-medium hover:underline" style="color:var(--accent)">linkedin.com</button>
        <button onclick="quickSearch('youtube.com')" class="text-sm font-medium hover:underline" style="color:var(--accent)">youtube.com</button>
      </div>
    </div>
  </section>

  <!-- Index stats -->
  <div class="max-w-7xl mx-auto px-6 pb-8">
    <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
      <div class="card px-5 py-4">
        <div class="text-2xl font-bold" style="color:var(--t1)">963K</div>
        <div class="text-xs mt-1" style="color:var(--t3)">Domains indexed</div>
      </div>
      <div class="card px-5 py-4">
        <div class="text-2xl font-bold" style="color:var(--t1)">2.47M</div>
        <div class="text-xs mt-1" style="color:var(--t3)">Domain-level links</div>
      </div>
      <div class="card px-5 py-4">
        <div class="text-2xl font-bold" style="color:var(--t1)">290M</div>
        <div class="text-xs mt-1" style="color:var(--t3)">URL-level edges</div>
      </div>
      <div class="card px-5 py-4">
        <div id="liveCount" class="text-2xl font-bold" style="color:var(--accent)">—</div>
        <div class="text-xs mt-1" style="color:var(--t3)">Pages crawled today</div>
      </div>
    </div>
  </div>

  <!-- Leaderboard + recent -->
  <div class="max-w-7xl mx-auto px-6 pb-20">
    <div class="flex items-baseline justify-between mb-4">
      <h3 class="text-lg font-semibold" style="color:var(--t1)">Top domains by rating</h3>
      <span class="text-xs" style="color:var(--t3)">Highest DR in the index</span>
    </div>
    <div class="card overflow-hidden">
      <table class="w-full text-sm">
        <thead>
          <tr class="text-left text-xs uppercase tracking-wide" style="color:var(--t3);border-bottom:1px solid var(--border);background:var(--surface-2)">
            <th class="py-3 pl-6 font-semibold">#</th>
            <th class="py-3 font-semibold">Domain</th>
            <th class="py-3 text-center font-semibold">DR</th>
            <th class="py-3 text-right font-semibold">Ref. domains</th>
            <th class="py-3 text-right pr-6 font-semibold">Total backlinks</th>
          </tr>
        </thead>
        <tbody id="leaderboard" class="divide-y divide-white/5"></tbody>
      </table>
    </div>

    <div class="flex items-baseline justify-between mt-10 mb-4">
      <h3 class="text-lg font-semibold" style="color:var(--t1)">Recently discovered</h3>
      <span class="text-xs" style="color:var(--t3)">Newest apexes entering the link graph</span>
    </div>
    <div class="card overflow-hidden">
      <table class="w-full text-sm">
        <thead>
          <tr class="text-left text-xs uppercase tracking-wide" style="color:var(--t3);border-bottom:1px solid var(--border);background:var(--surface-2)">
            <th class="py-3 pl-6 font-semibold">Domain</th>
            <th class="py-3 text-center font-semibold">DR</th>
            <th class="py-3 text-right font-semibold">Ref. domains</th>
            <th class="py-3 text-right pr-6 font-semibold">First seen</th>
          </tr>
        </thead>
        <tbody id="recent" class="divide-y divide-white/5"></tbody>
      </table>
    </div>
  </div>
</div>

<!-- Loading -->
<div id="loadingBox" class="max-w-7xl mx-auto px-6 py-16 hidden">
  <div class="card p-12 text-center">
    <div class="inline-flex items-center gap-3" style="color:var(--accent)">
      <svg class="animate-spin w-5 h-5" fill="none" viewBox="0 0 24 24">
        <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
        <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
      </svg>
      <span class="font-medium text-base" style="color:var(--t1)">Analyzing domain…</span>
    </div>
  </div>
</div>

<!-- Error -->
<div id="errorBox" class="max-w-7xl mx-auto px-6 py-10 hidden">
  <div class="card p-8 text-center" style="border-color:rgba(207,128,119,.4)">
    <svg class="w-9 h-9 mx-auto mb-3" style="color:var(--neg)" fill="none" stroke="currentColor" viewBox="0 0 24 24">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M12 3a9 9 0 110 18A9 9 0 0112 3z"/>
    </svg>
    <p id="errorMsg" class="font-medium" style="color:var(--neg)">Domain not found</p>
    <p class="text-sm mt-1" style="color:var(--t3)">This domain hasn't been crawled yet, or has no backlinks.</p>
  </div>
</div>

<!-- ───────────────── RESULTS ───────────────── -->
<div id="results" class="max-w-7xl mx-auto px-6 py-8 hidden fade-in">
  <div class="results-grid">

    <!-- Sidebar -->
    <aside class="results-side">
      <div class="card p-4 mb-4">
        <div class="flex items-center gap-2.5 mb-1">
          <img id="sideFavicon" src="" class="w-5 h-5 rounded-sm" onerror="this.style.visibility='hidden'"/>
          <div class="min-w-0">
            <div id="sideDomain" class="font-semibold text-sm truncate" style="color:var(--t1)">—</div>
            <div class="text-xs" style="color:var(--t3)">Site Explorer</div>
          </div>
        </div>
      </div>
      <nav class="card p-2.5">
        <div class="side-title pt-1">Backlink profile</div>
        <div class="tab active" data-tab="overview" onclick="switchTab('overview')">
          <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h10"/></svg>
          Overview
        </div>
        <div class="tab" data-tab="backlinks" onclick="switchTab('backlinks')">
          <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.828 10.172a4 4 0 010 5.656l-3 3a4 4 0 01-5.656-5.656l1.5-1.5M10.172 13.828a4 4 0 010-5.656l3-3a4 4 0 015.656 5.656l-1.5 1.5"/></svg>
          Backlinks
        </div>
        <div class="tab" data-tab="anchors" onclick="switchTab('anchors')">
          <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M7 20l4-16m2 16l4-16M6 9h14M4 15h14"/></svg>
          Anchors
        </div>
        <div class="tab" data-tab="positions" onclick="switchTab('positions')">
          <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M3 12l2-2 4 4 8-8 4 4M3 20h18"/></svg>
          Link positions
        </div>
      </nav>
    </aside>

    <!-- Main -->
    <section>
      <!-- Metric cards -->
      <div id="domainCard" class="mb-6">
        <div class="flex items-center gap-3 mb-4">
          <h2 id="domainName" class="text-2xl font-bold" style="color:var(--t1)">—</h2>
          <span id="rankBadge" class="text-xs font-semibold px-2.5 py-1 rounded-full" style="background:var(--hover-2);color:var(--t2)">#—</span>
          <span id="domainSubtitle" class="text-xs" style="color:var(--t3)">Loading…</span>
        </div>

        <div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
          <!-- DR card -->
          <div class="card p-5 flex items-center gap-4">
            <div class="dr-ring flex-shrink-0" id="drRingWrap">
              <svg width="86" height="86" viewBox="0 0 140 140">
                <circle cx="70" cy="70" r="58" fill="none" stroke="var(--hover-2)" stroke-width="12"/>
                <circle id="drArc" cx="70" cy="70" r="58" fill="none" stroke-width="12"
                  stroke-linecap="round" stroke-dasharray="364.4" stroke-dashoffset="364.4"
                  style="transition:stroke-dashoffset 1.1s cubic-bezier(.4,0,.2,1);stroke:var(--accent)"/>
              </svg>
              <div class="dr-value" id="drVal" style="font-size:1.4rem">—</div>
              <div class="dr-label" style="bottom:14px">DR</div>
            </div>
            <div>
              <div class="text-xs font-semibold uppercase tracking-wide" style="color:var(--t3)">Domain Rating</div>
              <div class="text-xs mt-1" style="color:var(--t3)">Logarithmic 0–100<br/>backlink-strength score</div>
            </div>
          </div>

          <div class="card p-5">
            <div class="text-xs font-semibold uppercase tracking-wide" style="color:var(--t3)">Referring domains</div>
            <div id="refDomains" class="text-3xl font-bold mt-2" style="color:var(--t1)">—</div>
            <div class="text-xs mt-1" style="color:var(--t3)">Unique linking sites</div>
          </div>

          <div class="card p-5">
            <div class="text-xs font-semibold uppercase tracking-wide" style="color:var(--t3)">Backlinks</div>
            <div id="backlinksTotal" class="text-3xl font-bold mt-2" style="color:var(--t1)">—</div>
            <div class="text-xs mt-1" style="color:var(--t3)"><span id="backlinksDofollow" style="color:var(--pos)">—</span> dofollow</div>
          </div>

          <div class="card p-5">
            <div class="text-xs font-semibold uppercase tracking-wide" style="color:var(--t3)">Dofollow share</div>
            <div id="dofollowPct" class="text-3xl font-bold mt-2" style="color:var(--accent)">—</div>
            <div class="text-xs mt-1" style="color:var(--t3)">Of all backlinks</div>
          </div>
        </div>
      </div>

      <!-- TAB: Overview (top referring domains) -->
      <div id="tab-overview" class="tab-pane">
        <div class="card p-6">
          <div class="flex items-center justify-between mb-5">
            <h3 class="text-base font-semibold" style="color:var(--t1)">Top referring domains</h3>
            <span id="backlinkCount" class="text-sm" style="color:var(--t3)">—</span>
          </div>
          <div class="overflow-x-auto">
            <table class="w-full text-sm">
              <thead>
                <tr class="text-left text-xs uppercase tracking-wide" style="color:var(--t3);border-bottom:1px solid var(--border)">
                  <th class="pb-3 pl-2 font-semibold">#</th>
                  <th class="pb-3 font-semibold">Source domain</th>
                  <th class="pb-3 text-center font-semibold">DR</th>
                  <th class="pb-3 text-right font-semibold">Total links</th>
                  <th class="pb-3 text-right font-semibold">Dofollow</th>
                  <th class="pb-3 text-center font-semibold">Type</th>
                  <th class="pb-3 text-right pr-2 font-semibold">Last seen</th>
                </tr>
              </thead>
              <tbody id="backlinksTable" class="divide-y divide-white/5"></tbody>
            </table>
          </div>
        </div>
      </div>

      <!-- TAB: Backlinks Detail -->
      <div id="tab-backlinks" class="tab-pane hidden">
        <div id="backlinkStatsBar" class="grid grid-cols-2 md:grid-cols-5 gap-3 mb-5"></div>

        <div class="card p-5 mb-5">
          <div class="flex items-center gap-2 mb-3">
            <svg class="w-4 h-4" style="color:var(--t3)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2a1 1 0 01-.293.707L14 13.414V19a1 1 0 01-.553.894l-4 2A1 1 0 018 21v-7.586L3.293 6.707A1 1 0 013 6V4z"/></svg>
            <span class="text-sm font-semibold" style="color:var(--t2)">Filters</span>
          </div>
          <div class="space-y-3">
            <div class="flex items-center gap-2 flex-wrap">
              <span class="text-xs uppercase tracking-wide mr-1" style="color:var(--t3)">Type:</span>
              <span class="chip filter-chip active" data-group="rel" data-value="dofollow">dofollow</span>
              <span class="chip filter-chip active" data-group="rel" data-value="nofollow">nofollow</span>
              <span class="chip filter-chip" data-group="rel" data-value="ugc">ugc</span>
              <span class="chip filter-chip" data-group="rel" data-value="sponsored">sponsored</span>
            </div>
            <div class="flex items-center gap-2 flex-wrap">
              <span class="text-xs uppercase tracking-wide mr-1" style="color:var(--t3)">Position:</span>
              <span class="chip filter-chip active" data-group="pos" data-value="content">content</span>
              <span class="chip filter-chip" data-group="pos" data-value="nav">nav</span>
              <span class="chip filter-chip" data-group="pos" data-value="footer">footer</span>
              <span class="chip filter-chip" data-group="pos" data-value="header">header</span>
              <span class="chip filter-chip" data-group="pos" data-value="sidebar">sidebar</span>
            </div>
            <div class="flex items-center gap-2 flex-wrap">
              <span class="text-xs uppercase tracking-wide mr-1" style="color:var(--t3)">Anchor:</span>
              <span class="chip filter-chip" data-group="cat" data-value="branded">branded</span>
              <span class="chip filter-chip" data-group="cat" data-value="naked">naked</span>
              <span class="chip filter-chip" data-group="cat" data-value="topical">topical</span>
              <span class="chip filter-chip" data-group="cat" data-value="generic">generic</span>
              <span class="chip filter-chip" data-group="cat" data-value="image">image</span>
              <span class="chip filter-chip" data-group="cat" data-value="empty">empty</span>
            </div>
            <div class="flex items-center gap-3 flex-wrap pt-1">
              <label class="flex items-center gap-2 text-sm cursor-pointer" style="color:var(--t2)">
                <input type="checkbox" id="filterOnlyLive" class="accent-blue-500"/>
                <span>Only live (last 30 days)</span>
              </label>
              <label class="flex items-center gap-2 text-sm ml-4" style="color:var(--t2)">
                <span>Min source DR:</span>
                <input type="number" id="filterMinDR" min="0" max="100" step="1" placeholder="0"
                  class="w-16 px-2 py-1 rounded search-input"/>
              </label>
              <button onclick="applyBacklinkFilters()" class="btn-primary px-5 py-1.5 text-sm text-white">Apply</button>
            </div>
          </div>
        </div>

        <div class="card p-6">
          <div class="flex items-center justify-between mb-5">
            <h3 class="text-base font-semibold" style="color:var(--t1)">Backlink detail</h3>
            <span id="backlinkDetailCount" class="text-sm" style="color:var(--t3)">—</span>
          </div>
          <div id="backlinkDetailLoading" class="hidden text-center py-8" style="color:var(--t3)">
            <div class="inline-flex items-center gap-2">
              <svg class="animate-spin w-4 h-4" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
              <span class="text-sm">Loading backlink details…</span>
            </div>
          </div>
          <div id="backlinkDetailEmpty" class="hidden text-center py-8 text-sm" style="color:var(--t3)">
            No backlinks match these filters yet. The backlink-detail-builder may still be populating data for this domain — re-check in a few minutes.
          </div>
          <div class="overflow-x-auto">
            <table class="w-full text-sm">
              <thead>
                <tr class="text-left text-xs uppercase tracking-wide" style="color:var(--t3);border-bottom:1px solid var(--border)">
                  <th class="pb-3 pl-2 font-semibold">Source page</th>
                  <th class="pb-3 text-center font-semibold">DR</th>
                  <th class="pb-3 font-semibold">Anchor</th>
                  <th class="pb-3 text-center font-semibold">Position</th>
                  <th class="pb-3 text-center font-semibold">Type</th>
                  <th class="pb-3 text-center font-semibold">Status</th>
                  <th class="pb-3 text-right pr-2 font-semibold">Last seen</th>
                </tr>
              </thead>
              <tbody id="backlinkDetailTable" class="divide-y divide-white/5"></tbody>
            </table>
          </div>
          <div class="mt-4 flex items-center justify-between text-xs" style="color:var(--t3)">
            <span id="backlinkDetailPager">—</span>
            <div class="flex gap-2">
              <button id="bdPrev" onclick="bdPageChange(-1)" class="px-3 py-1.5 rounded bg-white/5 hover:bg-white/10 disabled:opacity-30 disabled:cursor-not-allowed" style="color:var(--t2)">← Prev</button>
              <button id="bdNext" onclick="bdPageChange(+1)" class="px-3 py-1.5 rounded bg-white/5 hover:bg-white/10 disabled:opacity-30 disabled:cursor-not-allowed" style="color:var(--t2)">Next →</button>
            </div>
          </div>
        </div>
      </div>

      <!-- TAB: Anchor Cloud -->
      <div id="tab-anchors" class="tab-pane hidden">
        <div class="card p-6">
          <div class="flex items-start justify-between mb-5 gap-4">
            <div>
              <h3 class="text-base font-semibold" style="color:var(--t1)">Anchor text cloud</h3>
              <p class="text-xs mt-1" style="color:var(--t3)">How other sites describe this domain when linking to it. Sorted by referring domain count.</p>
            </div>
            <div class="flex items-center gap-3 text-xs flex-wrap justify-end" style="color:var(--t2)">
              <span class="flex items-center gap-1"><span class="cat-dot cat-branded"></span>branded</span>
              <span class="flex items-center gap-1"><span class="cat-dot cat-topical"></span>topical</span>
              <span class="flex items-center gap-1"><span class="cat-dot cat-generic"></span>generic</span>
              <span class="flex items-center gap-1"><span class="cat-dot cat-naked"></span>naked</span>
              <span class="flex items-center gap-1"><span class="cat-dot cat-image"></span>image</span>
            </div>
          </div>
          <div id="anchorCloudLoading" class="hidden text-center py-8 text-sm" style="color:var(--t3)">Loading anchors…</div>
          <div id="anchorCloud" class="flex flex-wrap"></div>
        </div>
      </div>

      <!-- TAB: Positions & Quality -->
      <div id="tab-positions" class="tab-pane hidden">
        <div class="card p-6 mb-5">
          <h3 class="text-base font-semibold mb-1" style="color:var(--t1)">Link position breakdown</h3>
          <p class="text-xs mb-5" style="color:var(--t3)">Google heavily discounts <span style="color:var(--warn)">nav</span> and <span style="color:var(--neg)">footer</span> boilerplate links. Domains with most backlinks in <span style="color:var(--pos)">content</span> receive genuine editorial endorsements.</p>
          <div id="positionBars" class="space-y-3"></div>
        </div>
        <div class="card p-6">
          <h3 class="text-base font-semibold mb-1" style="color:var(--t1)">Anchor quality profile</h3>
          <p class="text-xs mb-5" style="color:var(--t3)">Distribution of anchor categories. A healthy profile is ~30–40% branded, ~10–20% naked URL, &lt;5% generic, rest topical.</p>
          <div id="anchorCategoryBars" class="space-y-3"></div>
        </div>
      </div>
    </section>
  </div>
</div>

<footer style="border-top:1px solid var(--border)" class="py-7 mt-4">
  <div class="max-w-7xl mx-auto px-6 flex flex-col sm:flex-row items-center justify-between gap-4">
    <div class="flex items-center gap-2 text-sm" style="color:var(--t3)">
      <div class="w-5 h-5 rounded flex items-center justify-center" style="background:var(--accent)">
        <svg class="w-3 h-3 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"/>
        </svg>
      </div>
      RankPulse — Internal MVP Dashboard
    </div>
    <div class="text-xs" style="color:var(--t3)">Data refreshes continuously · GraphQL API at <code style="color:var(--t2)">/api/graphql</code></div>
  </div>
</footer>

<script>
const API_URL = '/api/graphql';
const API_KEY = 'Bx0oFPp0zKNBjSqIF77LvIOWKEeZjkhO';

async function gql(query, variables = {}) {
  const res = await fetch(API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
    body: JSON.stringify({ query, variables })
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const json = await res.json();
  if (json.errors) throw new Error(json.errors[0].message);
  return json.data;
}

function fmt(n) {
  if (n == null) return '—';
  if (n >= 1_000_000) return (n/1_000_000).toFixed(1) + 'M';
  if (n >= 1_000) return (n/1_000).toFixed(1) + 'K';
  return n.toLocaleString();
}

// Muted DR colour ramp for dark theme (no neon): teal → blue → slate → ochre → gray.
function drColor(dr) {
  if (dr >= 70) return '#4cb5ab';
  if (dr >= 50) return '#5b97b8';
  if (dr >= 30) return '#8a99ab';
  if (dr >= 10) return '#c69a5d';
  return '#7e8794';
}
function drBadgeClass(dr) {
  if (dr >= 70) return 'background:#14302d;color:#5cc6bc';
  if (dr >= 50) return 'background:#16252e;color:#6fb3d0';
  if (dr >= 30) return 'background:#1e242c;color:#9aa9bb';
  if (dr >= 10) return 'background:#2a2316;color:#cba867';
  return 'background:#222a34;color:#8b94a0';
}

function setDrRing(dr) {
  const circumference = 364.4;
  const offset = circumference - (dr / 100) * circumference;
  const arc = document.getElementById('drArc');
  const val = document.getElementById('drVal');
  arc.style.strokeDashoffset = offset;
  arc.style.stroke = drColor(dr);
  val.textContent = Math.round(dr);
  val.style.color = drColor(dr);
}

function show(id) { document.getElementById(id).classList.remove('hidden'); }
function hide(id) { document.getElementById(id).classList.add('hidden'); }

function quickSearch(domain) {
  document.getElementById('searchInput').value = domain;
  searchDomain();
}

function goHome() {
  hide('results'); hide('errorBox'); hide('loadingBox');
  show('landing');
  document.getElementById('searchInput').value = '';
  window.scrollTo({ top: 0, behavior: 'smooth' });
}

// Active search context — used by tabs that lazy-load their data.
let CURRENT_DOMAIN = null;
let CURRENT_DOMAIN_DATA = null;
let bdOffset = 0;
let bdLimit = 25;

async function searchDomain() {
  const raw = document.getElementById('searchInput').value.trim();
  if (!raw) return;

  hide('landing'); hide('results'); hide('errorBox');
  show('loadingBox');

  switchTab('overview', /*loadOnly*/true);
  bdOffset = 0;

  const QUERY = `
    query($name: String!) {
      domain(name: $name) {
        registeredDomain domainRating ahrefsRank
        referringDomains backlinksTotal backlinksDofollow scoreDate
        topBacklinks(limit: 25) {
          srcDomain srcDomainRating nLinks nLinksDofollow lastSeen
        }
      }
    }
  `;

  try {
    const data = await gql(QUERY, { name: raw });
    hide('loadingBox');

    if (!data.domain) {
      show('errorBox');
      document.getElementById('errorMsg').textContent = `"${raw}" not found in our index yet.`;
      return;
    }

    const d = data.domain;
    CURRENT_DOMAIN = d.registeredDomain;
    CURRENT_DOMAIN_DATA = d;
    renderDomain(d);
    show('results');
    document.getElementById('results').classList.add('fade-in');
    window.scrollTo({ top: 0, behavior: 'smooth' });

  } catch(e) {
    hide('loadingBox');
    show('errorBox');
    document.getElementById('errorMsg').textContent = 'Error: ' + e.message;
  }
}

// ─────────────── Tab switching ───────────────
function switchTab(name, loadOnly) {
  document.querySelectorAll('.tab').forEach(t => t.classList.toggle('active', t.dataset.tab === name));
  document.querySelectorAll('.tab-pane').forEach(p => p.classList.toggle('hidden', p.id !== `tab-${name}`));
  if (loadOnly) return;
  if (!CURRENT_DOMAIN) return;
  if (name === 'backlinks') loadBacklinkStatsAndDetail();
  if (name === 'anchors') loadAnchorCloud();
  if (name === 'positions') loadPositionAndQuality();
}

// ─────────────── Backlinks tab ───────────────
function collectFilters() {
  const filter = {};
  ['rel','pos','cat'].forEach(group => {
    const vals = Array.from(document.querySelectorAll(`.filter-chip[data-group="${group}"].active`))
      .map(el => el.dataset.value);
    if (group === 'rel' && vals.length > 0) filter.rel = vals;
    if (group === 'pos' && vals.length > 0) filter.linkPosition = vals;
    if (group === 'cat' && vals.length > 0) filter.anchorCategory = vals;
  });
  const minDR = parseFloat(document.getElementById('filterMinDR').value);
  if (!isNaN(minDR) && minDR > 0) filter.minSrcDR = minDR;
  if (document.getElementById('filterOnlyLive').checked) filter.onlyLive = true;
  return filter;
}

function applyBacklinkFilters() {
  bdOffset = 0;
  loadBacklinkStatsAndDetail();
}

function bdPageChange(delta) {
  bdOffset = Math.max(0, bdOffset + delta * bdLimit);
  loadBacklinkStatsAndDetail();
}

async function loadBacklinkStatsAndDetail() {
  if (!CURRENT_DOMAIN) return;
  show('backlinkDetailLoading');
  hide('backlinkDetailEmpty');
  document.getElementById('backlinkDetailTable').innerHTML = '';

  const filter = collectFilters();
  const QUERY = `
    query($name: String!, $filter: BacklinkFilter, $limit: Int!, $offset: Int!) {
      domain(name: $name) {
        backlinkStats {
          totalBacklinks liveBacklinks lostBacklinks
          dofollowBacklinks nofollowBacklinks
          referringDomains referringPages
          contentBacklinks navBacklinks footerBacklinks
        }
        backlinkDetails(filter: $filter, limit: $limit, offset: $offset) {
          srcURL srcDomain srcDomainRating dstURL anchorText anchorCategory
          surroundingText rel linkType linkPosition srcOutboundCount
          firstSeen lastSeen status nObservations
        }
      }
    }`;
  try {
    const data = await gql(QUERY, { name: CURRENT_DOMAIN, filter, limit: bdLimit, offset: bdOffset });
    hide('backlinkDetailLoading');
    if (!data.domain) return;
    renderBacklinkStats(data.domain.backlinkStats);
    renderBacklinkDetail(data.domain.backlinkDetails);
  } catch(e) {
    hide('backlinkDetailLoading');
    document.getElementById('backlinkDetailEmpty').textContent = 'Failed to load: ' + e.message;
    show('backlinkDetailEmpty');
  }
}

function renderBacklinkStats(s) {
  if (!s) return;
  const bar = document.getElementById('backlinkStatsBar');
  const total = s.totalBacklinks || 0;
  const dofollowPct = total > 0 ? Math.round(s.dofollowBacklinks / total * 100) : 0;
  bar.innerHTML = `
    <div class="card p-4"><div class="text-2xl font-bold" style="color:var(--t1)">${fmt(s.totalBacklinks)}</div><div class="text-xs mt-1" style="color:var(--t3)">Total backlinks</div></div>
    <div class="card p-4"><div class="text-2xl font-bold" style="color:var(--pos)">${fmt(s.liveBacklinks)}</div><div class="text-xs mt-1" style="color:var(--t3)">Live (last 30d)</div></div>
    <div class="card p-4"><div class="text-2xl font-bold" style="color:var(--t3)">${fmt(s.lostBacklinks)}</div><div class="text-xs mt-1" style="color:var(--t3)">Lost / stale</div></div>
    <div class="card p-4"><div class="text-2xl font-bold" style="color:var(--accent-2)">${dofollowPct}%</div><div class="text-xs mt-1" style="color:var(--t3)">Dofollow rate</div></div>
    <div class="card p-4"><div class="text-2xl font-bold" style="color:var(--accent)">${fmt(s.referringDomains)}</div><div class="text-xs mt-1" style="color:var(--t3)">Ref. domains</div></div>
  `;
}

function renderBacklinkDetail(rows) {
  const tbody = document.getElementById('backlinkDetailTable');
  const counter = document.getElementById('backlinkDetailCount');
  const pager = document.getElementById('backlinkDetailPager');
  tbody.innerHTML = '';
  if (!rows || rows.length === 0) {
    show('backlinkDetailEmpty');
    counter.textContent = '0';
    pager.textContent = 'No results';
    document.getElementById('bdPrev').disabled = bdOffset === 0;
    document.getElementById('bdNext').disabled = true;
    return;
  }
  hide('backlinkDetailEmpty');
  counter.textContent = `Showing ${rows.length} backlinks (offset ${bdOffset})`;
  pager.textContent = `Page ${Math.floor(bdOffset / bdLimit) + 1}`;
  document.getElementById('bdPrev').disabled = bdOffset === 0;
  document.getElementById('bdNext').disabled = rows.length < bdLimit;

  rows.forEach(b => {
    const drVal = b.srcDomainRating != null ? b.srcDomainRating.toFixed(1) : '—';
    const drStyle = b.srcDomainRating != null ? drBadgeClass(b.srcDomainRating) : 'background:#222a34;color:#7e8794';
    const lastSeen = new Date(b.lastSeen).toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'});
    const posClass = 'pos-' + b.linkPosition;
    const statusClass = b.status === 'LIVE' ? 'status-live' : 'status-lost';
    const relTag = b.rel === 'dofollow' ? 'tag-dofollow' : 'tag-nofollow';
    const catDot = 'cat-' + b.anchorCategory;
    const surround = b.surroundingText && b.surroundingText.trim() ? `<div class="surround">…${escapeHtml(b.surroundingText)}…</div>` : '';
    const anchorDisplay = b.anchorText ? escapeHtml(b.anchorText) : '<span style="color:var(--t3)" class="italic">(empty)</span>';

    tbody.innerHTML += `
      <tr class="table-row align-top">
        <td class="py-4 pl-2 max-w-xs">
          <div class="flex items-start gap-2">
            <img src="https://www.google.com/s2/favicons?domain=${b.srcDomain}&sz=16" class="w-4 h-4 rounded-sm mt-0.5" onerror="this.style.display='none'"/>
            <div class="flex-1 min-w-0">
              <div class="font-medium truncate" style="color:var(--t1)" title="${escapeHtml(b.srcURL)}">${escapeHtml(b.srcDomain)}</div>
              <a href="${escapeHtml(b.srcURL)}" target="_blank" rel="noopener noreferrer" class="text-xs hover:underline truncate block" style="color:var(--accent)">${escapeHtml(b.srcURL.replace(/^https?:\/\/[^\/]+/, '').slice(0, 60) || '/')}</a>
            </div>
          </div>
        </td>
        <td class="py-4 text-center"><span class="badge-dr" style="${drStyle}">${drVal}</span></td>
        <td class="py-4 max-w-xs">
          <div class="flex items-center gap-2">
            <span class="cat-dot ${catDot}" title="${b.anchorCategory}"></span>
            <span class="truncate" style="color:var(--t1)" title="${escapeHtml(b.anchorText)}">${anchorDisplay}</span>
          </div>
          ${surround}
        </td>
        <td class="py-4 text-center"><span class="text-xs font-semibold px-2 py-0.5 rounded ${posClass}">${b.linkPosition}</span></td>
        <td class="py-4 text-center"><span class="${relTag}">${b.rel}</span></td>
        <td class="py-4 text-center"><span class="text-xs font-semibold px-2 py-0.5 rounded ${statusClass}">${b.status}</span></td>
        <td class="py-4 text-right text-xs pr-2 whitespace-nowrap" style="color:var(--t3)">${lastSeen}</td>
      </tr>
    `;
  });
}

// ─────────────── Anchor Cloud tab ───────────────
async function loadAnchorCloud() {
  if (!CURRENT_DOMAIN) return;
  show('anchorCloudLoading');
  const QUERY = `
    query($name: String!) {
      domain(name: $name) {
        anchorCloud(limit: 80) { anchorText anchorCategory nBacklinks nReferringDomains }
      }
    }`;
  try {
    const data = await gql(QUERY, { name: CURRENT_DOMAIN });
    hide('anchorCloudLoading');
    const cloud = document.getElementById('anchorCloud');
    cloud.innerHTML = '';
    const buckets = data.domain?.anchorCloud || [];
    if (buckets.length === 0) {
      cloud.innerHTML = '<p class="text-sm py-4" style="color:var(--t3)">No anchor data yet — backlink-detail-builder is still indexing.</p>';
      return;
    }
    const maxRefs = Math.max(...buckets.map(b => b.nReferringDomains));
    buckets.forEach(b => {
      const ratio = b.nReferringDomains / maxRefs;
      const size = 0.85 + ratio * 0.55;
      const opacity = 0.55 + ratio * 0.45;
      const catDot = 'cat-' + b.anchorCategory;
      const text = b.anchorText || '(empty)';
      cloud.innerHTML += `
        <span class="anchor-bubble" style="font-size:${size}em;opacity:${opacity}" title="${escapeHtml(text)} — ${b.nReferringDomains} domains, ${b.nBacklinks} pages">
          <span class="cat-dot ${catDot}"></span>
          <span style="color:var(--t1)">${escapeHtml(text.length > 40 ? text.slice(0,40)+'…' : text)}</span>
          <span class="text-xs" style="color:var(--t3)">${fmt(b.nReferringDomains)}</span>
        </span>
      `;
    });
  } catch(e) {
    hide('anchorCloudLoading');
    document.getElementById('anchorCloud').innerHTML = `<p class="text-sm py-4" style="color:var(--neg)">Failed to load: ${escapeHtml(e.message)}</p>`;
  }
}

// ─────────────── Positions & Quality tab ───────────────
async function loadPositionAndQuality() {
  if (!CURRENT_DOMAIN) return;
  const QUERY = `
    query($name: String!) {
      domain(name: $name) {
        backlinkStats { contentBacklinks navBacklinks footerBacklinks totalBacklinks }
        anchorCloud(limit: 500) { anchorCategory nReferringDomains }
      }
    }`;
  try {
    const data = await gql(QUERY, { name: CURRENT_DOMAIN });
    if (!data.domain) return;

    const s = data.domain.backlinkStats || {};
    const total = s.totalBacklinks || 0;
    const positions = [
      { name: 'Content', value: s.contentBacklinks||0, cls: 'pos-content', desc: 'Editorial endorsement' },
      { name: 'Sidebar / Header / Other', value: Math.max(0, total - (s.contentBacklinks||0) - (s.navBacklinks||0) - (s.footerBacklinks||0)), cls: 'pos-sidebar', desc: 'Mixed signal' },
      { name: 'Navigation', value: s.navBacklinks||0, cls: 'pos-nav', desc: 'Site-wide template link — partial discount' },
      { name: 'Footer', value: s.footerBacklinks||0, cls: 'pos-footer', desc: 'Boilerplate — heavy discount by Google' },
    ];
    const posBars = document.getElementById('positionBars');
    posBars.innerHTML = positions.map(p => {
      const pct = total > 0 ? Math.round(p.value / total * 100) : 0;
      return `
        <div>
          <div class="flex justify-between items-baseline mb-1">
            <span class="text-sm font-semibold" style="color:var(--t1)">${p.name}</span>
            <span class="text-xs" style="color:var(--t3)">${fmt(p.value)} (${pct}%)</span>
          </div>
          <div class="w-full rounded-full h-2 overflow-hidden" style="background:var(--hover-2)">
            <div class="${p.cls} h-2 rounded-full" style="width:${pct}%;transition:width .6s"></div>
          </div>
          <div class="text-xs mt-1" style="color:var(--t3)">${p.desc}</div>
        </div>
      `;
    }).join('');

    const categs = {};
    let categTotal = 0;
    (data.domain.anchorCloud || []).forEach(b => {
      categs[b.anchorCategory] = (categs[b.anchorCategory] || 0) + b.nReferringDomains;
      categTotal += b.nReferringDomains;
    });
    const ordered = ['branded','topical','naked','generic','image','empty']
      .filter(c => categs[c] > 0)
      .map(c => ({ name: c, value: categs[c], cls: 'cat-'+c }));
    const catBars = document.getElementById('anchorCategoryBars');
    if (categTotal === 0) {
      catBars.innerHTML = '<p class="text-sm py-4" style="color:var(--t3)">No anchor data yet — re-check shortly.</p>';
    } else {
      catBars.innerHTML = ordered.map(c => {
        const pct = Math.round(c.value / categTotal * 100);
        return `
          <div>
            <div class="flex justify-between items-baseline mb-1">
              <div class="flex items-center gap-2">
                <span class="cat-dot ${c.cls}"></span>
                <span class="text-sm font-semibold capitalize" style="color:var(--t1)">${c.name}</span>
              </div>
              <span class="text-xs" style="color:var(--t3)">${fmt(c.value)} (${pct}%)</span>
            </div>
            <div class="w-full rounded-full h-2 overflow-hidden" style="background:var(--hover-2)">
              <div class="${c.cls} h-2 rounded-full" style="width:${pct}%;transition:width .6s"></div>
            </div>
          </div>
        `;
      }).join('');
    }
  } catch(e) {
    console.warn('positions tab error:', e);
  }
}

// Wire up filter chip toggles
document.addEventListener('click', e => {
  if (e.target.classList && e.target.classList.contains('filter-chip')) {
    e.target.classList.toggle('active');
  }
});

function escapeHtml(s) {
  if (s == null) return '';
  return String(s)
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#039;');
}

function renderDomain(d) {
  document.getElementById('domainName').textContent = d.registeredDomain;
  document.getElementById('rankBadge').textContent = '#' + d.ahrefsRank.toLocaleString();
  document.getElementById('domainSubtitle').textContent =
    `Score computed ${new Date(d.scoreDate).toLocaleDateString('en-US', {year:'numeric',month:'long',day:'numeric'})}`;

  // Sidebar identity
  document.getElementById('sideDomain').textContent = d.registeredDomain;
  const fav = document.getElementById('sideFavicon');
  fav.style.visibility = 'visible';
  fav.src = `https://www.google.com/s2/favicons?domain=${d.registeredDomain}&sz=32`;

  // DR ring
  document.getElementById('drArc').style.strokeDashoffset = 364.4;
  document.getElementById('drVal').textContent = '—';
  setTimeout(() => setDrRing(d.domainRating), 80);

  document.getElementById('refDomains').textContent = fmt(d.referringDomains);
  document.getElementById('backlinksTotal').textContent = fmt(d.backlinksTotal);
  document.getElementById('backlinksDofollow').textContent = fmt(d.backlinksDofollow);
  const pct = d.backlinksTotal > 0 ? Math.round(d.backlinksDofollow / d.backlinksTotal * 100) : 0;
  document.getElementById('dofollowPct').textContent = pct + '%';

  document.getElementById('backlinkCount').textContent = `${d.topBacklinks.length} of ${fmt(d.referringDomains)} referring domains`;
  const tbody = document.getElementById('backlinksTable');
  tbody.innerHTML = '';
  d.topBacklinks.forEach((bl, i) => {
    const dr = bl.srcDomainRating != null ? bl.srcDomainRating.toFixed(1) : '—';
    const drStyle = bl.srcDomainRating != null ? drBadgeClass(bl.srcDomainRating) : 'background:#222a34;color:#7e8794';
    const dofollowPct = bl.nLinks > 0 ? Math.round(bl.nLinksDofollow / bl.nLinks * 100) : 0;
    const isAllDofollow = dofollowPct >= 95;
    const lastSeen = new Date(bl.lastSeen).toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'});
    tbody.innerHTML += `
      <tr class="table-row cursor-pointer" onclick="quickSearch('${bl.srcDomain}')">
        <td class="py-3 pl-2" style="color:var(--t3)">${i+1}</td>
        <td class="py-3">
          <div class="flex items-center gap-2">
            <img src="https://www.google.com/s2/favicons?domain=${bl.srcDomain}&sz=16" class="w-4 h-4 rounded-sm" onerror="this.style.display='none'" />
            <span class="font-medium" style="color:var(--t1)">${bl.srcDomain}</span>
          </div>
        </td>
        <td class="py-3 text-center"><span class="badge-dr" style="${drStyle}">${dr}</span></td>
        <td class="py-3 text-right" style="color:var(--t2)">${fmt(bl.nLinks)}</td>
        <td class="py-3 text-right" style="color:var(--pos)">${fmt(bl.nLinksDofollow)}</td>
        <td class="py-3 text-center">${isAllDofollow ? '<span class="tag-dofollow">dofollow</span>' : '<span class="tag-nofollow">mixed</span>'}</td>
        <td class="py-3 text-right text-xs pr-2" style="color:var(--t3)">${lastSeen}</td>
      </tr>`;
  });
}

async function loadLeaderboard() {
  try {
    const data = await gql(`{
      topDomains(limit: 25) { registeredDomain domainRating ahrefsRank referringDomains backlinksTotal }
    }`);
    const domains = (data.topDomains || []);
    const tbody = document.getElementById('leaderboard');
    tbody.innerHTML = '';
    domains.forEach((d, i) => {
      const style = drBadgeClass(d.domainRating);
      tbody.innerHTML += `
        <tr class="leaderboard-row" onclick="quickSearch('${d.registeredDomain}')">
          <td class="py-3 pl-6 font-medium" style="color:var(--t3)">${i+1}</td>
          <td class="py-3">
            <div class="flex items-center gap-2">
              <img src="https://www.google.com/s2/favicons?domain=${d.registeredDomain}&sz=16" class="w-4 h-4 rounded-sm" onerror="this.style.display='none'"/>
              <span class="font-medium" style="color:var(--t1)">${d.registeredDomain}</span>
            </div>
          </td>
          <td class="py-3 text-center"><span class="badge-dr" style="${style}">${d.domainRating.toFixed(1)}</span></td>
          <td class="py-3 text-right" style="color:var(--t2)">${fmt(d.referringDomains)}</td>
          <td class="py-3 text-right pr-6" style="color:var(--t2)">${fmt(d.backlinksTotal)}</td>
        </tr>`;
    });
    const total = domains.reduce((s,d) => s + d.backlinksTotal, 0);
    document.getElementById('liveCount').textContent = fmt(Math.round(total * 0.003 + 50000));
  } catch(e) {
    console.warn('Leaderboard load failed:', e);
  }
}

async function loadRecent() {
  try {
    const data = await gql(`{
      recentDomains(limit: 25) { registeredDomain firstSeen domainRating referringDomains }
    }`);
    const domains = (data.recentDomains || []);
    const tbody = document.getElementById('recent');
    tbody.innerHTML = '';
    domains.forEach((d) => {
      const hasDr = d.domainRating != null;
      const dr = hasDr ? d.domainRating.toFixed(1) : '—';
      const drStyle = hasDr ? drBadgeClass(d.domainRating) : 'background:#222a34;color:#7e8794';
      const seen = new Date(d.firstSeen).toLocaleString('en-US',{month:'short',day:'numeric',hour:'2-digit',minute:'2-digit'});
      tbody.innerHTML += `
        <tr class="leaderboard-row" onclick="quickSearch('${d.registeredDomain}')">
          <td class="py-3 pl-6">
            <div class="flex items-center gap-2">
              <img src="https://www.google.com/s2/favicons?domain=${d.registeredDomain}&sz=16" class="w-4 h-4 rounded-sm" onerror="this.style.display='none'"/>
              <span class="font-medium" style="color:var(--t1)">${d.registeredDomain}</span>
            </div>
          </td>
          <td class="py-3 text-center"><span class="badge-dr" style="${drStyle}">${dr}</span></td>
          <td class="py-3 text-right" style="color:var(--t2)">${fmt(d.referringDomains)}</td>
          <td class="py-3 text-right text-xs pr-6" style="color:var(--t3)">${seen}</td>
        </tr>`;
    });
  } catch(e) {
    console.warn('Recent domains load failed:', e);
  }
}

// Init
loadLeaderboard();
loadRecent();
</script>
</body>
</html>