| 9111 | _ndLastIsp = data.results || []; |
| 9112 | if (!_ndLastIsp.length) { |
| 9113 | out.innerHTML = '<p class="text-sm text-gray-400">No interfaces with a usable address to query.</p>'; |
| 9114 | return; |
| 9115 | } |
| 9116 | const vpnCell = (r) => { |
| 9117 | if (r.iface_is_vpn) return '<span class="text-amber-300">🔒 ' + escapeHtml(r.vpn_kind || 'tunnel') + '</span>'; |
| 9118 | if (r.tor_exit) return '<span class="text-amber-300">🧅 Tor exit</span>'; |
| 9119 | if (r.vpn_ip_match) return '<span class="text-amber-300">🔒 yes (known VPN IP)</span>'; |
| 9120 | if (r.vpn_provider) return '<span class="text-amber-300">🔒 likely (' + escapeHtml(r.vpn_provider) + ')</span>'; |
| 9121 | if (r.vpn_ip_match === false) return '<span class="text-gray-500">no</span>'; |
| 9122 | // IP-range list unavailable: only the weaker name/Tor checks ran |
| 9123 | return '<span class="text-gray-500" title="known-VPN IP list not synced yet — name and Tor checks only">no</span>'; |
| 9124 | }; |
| 9125 | const ispCell = (r) => { |