Spaces:
Running
Running
Download static/index.html from ItsXyron/hyperlookup-api: direct link, hf CLI and curl.
- Browser
- Download file 67.5 kB
-
https://huggingface.co/spaces/ItsXyron/hyperlookup-api/resolve/main/static/index.html
- Command line
-
hf download hf://spaces/ItsXyron/hyperlookup-api/static/index.html
-
curl -L -o index.html https://huggingface.co/spaces/ItsXyron/hyperlookup-api/resolve/main/static/index.html
67.5 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <title>Security Intelligence Console | Data Query Gateway</title> | |
| <meta name="robots" content="noindex, nofollow"> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg-void: #090b10; | |
| --bg-panel: #0f131c; | |
| --bg-element: #161c29; | |
| --bg-hover: #1f2738; | |
| --border-dark: #202736; | |
| --border-accent: #2e3a50; | |
| --border-active: #3b82f6; | |
| --text-bright: #f1f5f9; | |
| --text-standard: #94a3b8; | |
| --text-dim: #64748b; | |
| --signal-green: #10b981; | |
| --signal-amber: #f59e0b; | |
| --signal-blue: #3b82f6; | |
| --signal-red: #ef4444; | |
| --signal-purple: #8b5cf6; | |
| --font-ui: 'Space Grotesk', -apple-system, BlinkMacSystemFont, sans-serif; | |
| --font-code: 'JetBrains Mono', monospace; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| font-family: var(--font-ui); | |
| -webkit-font-smoothing: antialiased; | |
| } | |
| body { | |
| background-color: var(--bg-void); | |
| color: var(--text-standard); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| line-height: 1.5; | |
| font-size: 14px; | |
| } | |
| /* Ambient engineering subtle grid background */ | |
| .terminal-backdrop { | |
| position: fixed; | |
| inset: 0; | |
| background-image: | |
| linear-gradient(to right, rgba(255, 255, 255, 0.02) 1px, transparent 1px), | |
| linear-gradient(to bottom, rgba(255, 255, 255, 0.02) 1px, transparent 1px); | |
| background-size: 36px 36px; | |
| pointer-events: none; | |
| z-index: 0; | |
| } | |
| .container { | |
| max-width: 1060px; | |
| margin: 0 auto; | |
| padding: 0 16px; | |
| width: 100%; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| /* Top Utility Bar */ | |
| header { | |
| background: rgba(9, 11, 16, 0.95); | |
| border-bottom: 1px solid var(--border-dark); | |
| position: sticky; | |
| top: 0; | |
| z-index: 50; | |
| backdrop-filter: blur(8px); | |
| } | |
| .nav-bar { | |
| height: 58px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .brand { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| text-decoration: none; | |
| color: var(--text-bright); | |
| } | |
| .brand-icon { | |
| width: 28px; | |
| height: 28px; | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-accent); | |
| border-radius: 6px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: var(--signal-blue); | |
| font-weight: 700; | |
| font-size: 13px; | |
| font-family: var(--font-code); | |
| } | |
| .brand-title { | |
| font-weight: 700; | |
| font-size: 15px; | |
| letter-spacing: -0.3px; | |
| color: var(--text-bright); | |
| } | |
| .brand-tag { | |
| font-size: 10px; | |
| background: rgba(59, 130, 246, 0.12); | |
| color: var(--signal-blue); | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| border: 1px solid rgba(59, 130, 246, 0.3); | |
| font-family: var(--font-code); | |
| font-weight: 600; | |
| } | |
| .nav-tools { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .system-status { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| color: var(--text-dim); | |
| background: var(--bg-panel); | |
| padding: 5px 10px; | |
| border-radius: 6px; | |
| border: 1px solid var(--border-dark); | |
| } | |
| .status-dot { | |
| width: 7px; | |
| height: 7px; | |
| border-radius: 50%; | |
| background: var(--signal-green); | |
| box-shadow: 0 0 6px rgba(16, 185, 129, 0.6); | |
| } | |
| .status-dot.offline { | |
| background: var(--signal-red); | |
| box-shadow: 0 0 6px rgba(239, 68, 68, 0.6); | |
| } | |
| .lock-btn { | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-dark); | |
| color: var(--text-standard); | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| padding: 5px 11px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| transition: all 0.15s ease; | |
| } | |
| .lock-btn:hover { | |
| background: var(--bg-hover); | |
| color: var(--text-bright); | |
| border-color: var(--border-accent); | |
| } | |
| /* Main Console Workspace */ | |
| main { | |
| flex: 1; | |
| padding: 24px 0 40px; | |
| } | |
| /* Status Bar Banner */ | |
| .telemetry-row { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| gap: 10px; | |
| margin-bottom: 22px; | |
| } | |
| @media (max-width: 768px) { | |
| .telemetry-row { | |
| grid-template-columns: repeat(2, 1fr); | |
| } | |
| } | |
| .telemetry-card { | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 8px; | |
| padding: 10px 14px; | |
| } | |
| .telemetry-label { | |
| font-size: 10px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| color: var(--text-dim); | |
| font-family: var(--font-code); | |
| margin-bottom: 4px; | |
| } | |
| .telemetry-val { | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text-bright); | |
| font-family: var(--font-code); | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| /* SECTION 1: Step Indicator & Target Service Selector */ | |
| .step-box { | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 10px; | |
| padding: 18px 20px; | |
| margin-bottom: 20px; | |
| } | |
| .step-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 14px; | |
| } | |
| .step-badge { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| font-size: 12px; | |
| font-weight: 700; | |
| color: var(--text-bright); | |
| letter-spacing: 0.2px; | |
| } | |
| .step-number { | |
| background: var(--signal-blue); | |
| color: #fff; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 4px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| font-weight: 700; | |
| } | |
| .step-subtext { | |
| font-size: 12px; | |
| color: var(--text-dim); | |
| } | |
| /* Services Grid */ | |
| .services-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); | |
| gap: 8px; | |
| } | |
| .service-chip { | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 7px; | |
| padding: 10px 12px; | |
| cursor: pointer; | |
| text-align: left; | |
| transition: all 0.15s ease; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 3px; | |
| } | |
| .service-chip:hover { | |
| background: var(--bg-hover); | |
| border-color: var(--border-accent); | |
| transform: translateY(-1px); | |
| } | |
| .service-chip.active { | |
| background: rgba(59, 130, 246, 0.08); | |
| border-color: var(--signal-blue); | |
| box-shadow: 0 0 0 1px var(--signal-blue); | |
| } | |
| .service-chip-top { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .service-chip-name { | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text-bright); | |
| } | |
| .service-chip.active .service-chip-name { | |
| color: #60a5fa; | |
| } | |
| .service-chip-tag { | |
| font-size: 9px; | |
| font-family: var(--font-code); | |
| padding: 1px 4px; | |
| border-radius: 3px; | |
| background: rgba(255, 255, 255, 0.06); | |
| color: var(--text-dim); | |
| } | |
| .service-chip.active .service-chip-tag { | |
| background: rgba(59, 130, 246, 0.2); | |
| color: #93c5fd; | |
| } | |
| .service-chip-desc { | |
| font-size: 11px; | |
| color: var(--text-dim); | |
| font-family: var(--font-code); | |
| } | |
| /* SECTION 2: Dynamic Query Input */ | |
| .query-box { | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 10px; | |
| padding: 20px; | |
| margin-bottom: 24px; | |
| } | |
| .active-target-banner { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| margin-bottom: 14px; | |
| padding-bottom: 12px; | |
| border-bottom: 1px solid var(--border-dark); | |
| font-size: 12px; | |
| font-family: var(--font-code); | |
| } | |
| .target-info { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| color: var(--text-bright); | |
| } | |
| .target-indicator { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 2px; | |
| background: var(--signal-blue); | |
| } | |
| .input-mode-toggle { | |
| display: none; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .mode-btn { | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-dark); | |
| color: var(--text-dim); | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| padding: 4px 9px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| } | |
| .mode-btn.active { | |
| background: var(--signal-blue); | |
| color: #fff; | |
| border-color: var(--signal-blue); | |
| } | |
| /* Search Input Group */ | |
| .input-group { | |
| display: flex; | |
| gap: 8px; | |
| margin-bottom: 12px; | |
| } | |
| .input-wrapper { | |
| flex: 1; | |
| position: relative; | |
| } | |
| .query-input { | |
| width: 100%; | |
| height: 48px; | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 7px; | |
| padding: 0 16px; | |
| color: var(--text-bright); | |
| font-size: 15px; | |
| font-family: var(--font-code); | |
| transition: all 0.15s ease; | |
| outline: none; | |
| } | |
| .query-input:focus { | |
| border-color: var(--signal-blue); | |
| background: #192030; | |
| box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); | |
| } | |
| .query-input::placeholder { | |
| color: var(--text-dim); | |
| font-size: 13px; | |
| } | |
| .clear-btn { | |
| position: absolute; | |
| right: 12px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| background: transparent; | |
| border: none; | |
| color: var(--text-dim); | |
| font-size: 16px; | |
| cursor: pointer; | |
| display: none; | |
| } | |
| .clear-btn:hover { | |
| color: var(--text-bright); | |
| } | |
| .execute-btn { | |
| height: 48px; | |
| padding: 0 24px; | |
| background: var(--signal-blue); | |
| border: none; | |
| border-radius: 7px; | |
| color: #fff; | |
| font-weight: 600; | |
| font-size: 13px; | |
| font-family: var(--font-code); | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| transition: all 0.15s ease; | |
| white-space: nowrap; | |
| } | |
| .execute-btn:hover:not(:disabled) { | |
| background: #2563eb; | |
| box-shadow: 0 0 12px rgba(37, 99, 235, 0.4); | |
| } | |
| .execute-btn:disabled { | |
| background: var(--bg-hover); | |
| color: var(--text-dim); | |
| cursor: not-allowed; | |
| border: 1px solid var(--border-dark); | |
| } | |
| /* Helper presets and anti-ddos info */ | |
| .input-meta-bar { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 10px; | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| color: var(--text-dim); | |
| } | |
| .presets-wrap { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| flex-wrap: wrap; | |
| } | |
| .preset-btn { | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-dark); | |
| color: var(--text-standard); | |
| padding: 3px 7px; | |
| border-radius: 4px; | |
| font-size: 10px; | |
| font-family: var(--font-code); | |
| cursor: pointer; | |
| transition: all 0.1s ease; | |
| } | |
| .preset-btn:hover { | |
| background: var(--bg-hover); | |
| color: var(--text-bright); | |
| border-color: var(--border-accent); | |
| } | |
| .anti-ddos-tag { | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| color: var(--text-dim); | |
| } | |
| .cooldown-indicator { | |
| color: var(--signal-amber); | |
| font-weight: 600; | |
| } | |
| /* SECTION 3: Results Display Area */ | |
| .results-container { | |
| margin-top: 10px; | |
| } | |
| /* Loading Spinner */ | |
| .loading-state { | |
| display: none; | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 8px; | |
| padding: 40px 20px; | |
| text-align: center; | |
| } | |
| .terminal-loader { | |
| width: 32px; | |
| height: 32px; | |
| border: 2px solid var(--border-accent); | |
| border-top-color: var(--signal-blue); | |
| border-radius: 50%; | |
| animation: spin 0.8s linear infinite; | |
| margin: 0 auto 14px; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| .loading-text { | |
| font-family: var(--font-code); | |
| font-size: 13px; | |
| color: var(--text-bright); | |
| margin-bottom: 4px; | |
| } | |
| .loading-sub { | |
| font-size: 11px; | |
| color: var(--text-dim); | |
| font-family: var(--font-code); | |
| } | |
| /* Alert / Error Bar */ | |
| .alert-box { | |
| display: none; | |
| padding: 14px 16px; | |
| border-radius: 8px; | |
| margin-bottom: 16px; | |
| font-family: var(--font-code); | |
| font-size: 12px; | |
| border: 1px solid transparent; | |
| } | |
| .alert-box.error { | |
| background: rgba(239, 68, 68, 0.1); | |
| border-color: rgba(239, 68, 68, 0.3); | |
| color: #fca5a5; | |
| } | |
| .alert-box.warning { | |
| background: rgba(245, 158, 11, 0.1); | |
| border-color: rgba(245, 158, 11, 0.3); | |
| color: #fcd34d; | |
| } | |
| .alert-box.info { | |
| background: rgba(59, 130, 246, 0.1); | |
| border-color: rgba(59, 130, 246, 0.3); | |
| color: #93c5fd; | |
| } | |
| /* Result Card Styles */ | |
| .result-sheet { | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 10px; | |
| overflow: hidden; | |
| margin-bottom: 16px; | |
| } | |
| .sheet-header { | |
| padding: 12px 18px; | |
| background: var(--bg-element); | |
| border-bottom: 1px solid var(--border-dark); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| } | |
| .sheet-title-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .sheet-badge { | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| padding: 2px 7px; | |
| border-radius: 4px; | |
| font-weight: 600; | |
| } | |
| .badge-success { | |
| background: rgba(16, 185, 129, 0.15); | |
| color: var(--signal-green); | |
| border: 1px solid rgba(16, 185, 129, 0.3); | |
| } | |
| .badge-empty { | |
| background: rgba(148, 163, 184, 0.1); | |
| color: var(--text-dim); | |
| border: 1px solid var(--border-dark); | |
| } | |
| .sheet-title { | |
| font-weight: 700; | |
| font-size: 14px; | |
| color: var(--text-bright); | |
| } | |
| .sheet-meta { | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| color: var(--text-dim); | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .sheet-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .action-btn { | |
| background: var(--bg-hover); | |
| border: 1px solid var(--border-dark); | |
| color: var(--text-standard); | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| transition: all 0.1s ease; | |
| } | |
| .action-btn:hover { | |
| background: var(--border-accent); | |
| color: var(--text-bright); | |
| } | |
| /* Consolidated 360 Profile Summary Card */ | |
| .intel-brief-card { | |
| background: #101522; | |
| border: 1px solid #28354d; | |
| border-radius: 9px; | |
| margin: 16px; | |
| padding: 16px 18px; | |
| } | |
| .brief-title-bar { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 12px; | |
| border-bottom: 1px solid #1f2a3f; | |
| padding-bottom: 8px; | |
| } | |
| .brief-title { | |
| font-size: 12px; | |
| text-transform: uppercase; | |
| font-family: var(--font-code); | |
| font-weight: 700; | |
| color: #60a5fa; | |
| letter-spacing: 0.5px; | |
| } | |
| .brief-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); | |
| gap: 12px 18px; | |
| } | |
| .brief-item { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 2px; | |
| } | |
| .brief-label { | |
| font-size: 10px; | |
| font-family: var(--font-code); | |
| color: var(--text-dim); | |
| text-transform: uppercase; | |
| } | |
| .brief-val { | |
| font-size: 13px; | |
| color: var(--text-bright); | |
| font-weight: 500; | |
| word-break: break-word; | |
| } | |
| .score-badge { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 4px; | |
| background: rgba(16, 185, 129, 0.15); | |
| color: var(--signal-green); | |
| border: 1px solid rgba(16, 185, 129, 0.3); | |
| padding: 1px 6px; | |
| border-radius: 4px; | |
| font-family: var(--font-code); | |
| font-weight: 700; | |
| font-size: 12px; | |
| } | |
| /* Granular Table Data View */ | |
| .sheet-body { | |
| padding: 16px; | |
| } | |
| .record-card { | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 6px; | |
| margin-bottom: 10px; | |
| overflow: hidden; | |
| } | |
| .record-card:last-child { | |
| margin-bottom: 0; | |
| } | |
| .record-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 1px; | |
| background: var(--border-dark); | |
| } | |
| .data-cell { | |
| background: var(--bg-element); | |
| padding: 9px 12px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 2px; | |
| } | |
| .data-key { | |
| font-size: 10px; | |
| font-family: var(--font-code); | |
| color: var(--text-dim); | |
| text-transform: uppercase; | |
| } | |
| .data-value { | |
| font-size: 12px; | |
| font-family: var(--font-code); | |
| color: var(--text-bright); | |
| word-break: break-all; | |
| } | |
| /* Accordion Drawer for Multi-Source Results */ | |
| .source-drawer { | |
| border: 1px solid var(--border-dark); | |
| border-radius: 7px; | |
| margin-bottom: 8px; | |
| overflow: hidden; | |
| background: var(--bg-panel); | |
| } | |
| .drawer-toggle { | |
| width: 100%; | |
| background: var(--bg-element); | |
| border: none; | |
| padding: 10px 14px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| cursor: pointer; | |
| color: var(--text-standard); | |
| transition: background 0.1s ease; | |
| } | |
| .drawer-toggle:hover { | |
| background: var(--bg-hover); | |
| } | |
| .drawer-left { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .drawer-name { | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text-bright); | |
| } | |
| .drawer-status { | |
| font-size: 10px; | |
| font-family: var(--font-code); | |
| padding: 1px 6px; | |
| border-radius: 3px; | |
| } | |
| .drawer-status.hit { | |
| background: rgba(16, 185, 129, 0.15); | |
| color: var(--signal-green); | |
| } | |
| .drawer-status.miss { | |
| background: rgba(148, 163, 184, 0.1); | |
| color: var(--text-dim); | |
| } | |
| .drawer-content { | |
| display: none; | |
| padding: 12px; | |
| background: var(--bg-panel); | |
| border-top: 1px solid var(--border-dark); | |
| } | |
| .drawer-content.open { | |
| display: block; | |
| } | |
| /* Passcode Gate Modal Overlay */ | |
| .gate-overlay { | |
| position: fixed; | |
| inset: 0; | |
| background: rgba(5, 7, 10, 0.92); | |
| backdrop-filter: blur(12px); | |
| z-index: 999; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 20px; | |
| } | |
| .gate-modal { | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border-accent); | |
| border-radius: 12px; | |
| max-width: 420px; | |
| width: 100%; | |
| padding: 28px 24px; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6); | |
| position: relative; | |
| } | |
| .gate-icon { | |
| width: 44px; | |
| height: 44px; | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-accent); | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 20px; | |
| margin-bottom: 16px; | |
| color: var(--signal-blue); | |
| } | |
| .gate-title { | |
| font-size: 18px; | |
| font-weight: 700; | |
| color: var(--text-bright); | |
| margin-bottom: 6px; | |
| letter-spacing: -0.2px; | |
| } | |
| .gate-desc { | |
| font-size: 12px; | |
| color: var(--text-dim); | |
| line-height: 1.5; | |
| margin-bottom: 20px; | |
| } | |
| .gate-form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| } | |
| .gate-label { | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| text-transform: uppercase; | |
| color: var(--text-standard); | |
| display: flex; | |
| justify-content: space-between; | |
| } | |
| .gate-input-wrapper { | |
| position: relative; | |
| } | |
| .gate-input { | |
| width: 100%; | |
| height: 44px; | |
| background: var(--bg-element); | |
| border: 1px solid var(--border-dark); | |
| border-radius: 7px; | |
| padding: 0 40px 0 14px; | |
| font-size: 14px; | |
| color: var(--text-bright); | |
| font-family: var(--font-code); | |
| outline: none; | |
| transition: all 0.15s ease; | |
| } | |
| .gate-input:focus { | |
| border-color: var(--signal-blue); | |
| box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); | |
| } | |
| .toggle-pass-btn { | |
| position: absolute; | |
| right: 12px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| background: transparent; | |
| border: none; | |
| color: var(--text-dim); | |
| cursor: pointer; | |
| font-size: 13px; | |
| } | |
| .gate-submit-btn { | |
| height: 44px; | |
| background: var(--signal-blue); | |
| border: none; | |
| border-radius: 7px; | |
| color: #fff; | |
| font-weight: 600; | |
| font-size: 13px; | |
| font-family: var(--font-code); | |
| cursor: pointer; | |
| transition: background 0.15s ease; | |
| } | |
| .gate-submit-btn:hover:not(:disabled) { | |
| background: #2563eb; | |
| } | |
| .gate-submit-btn:disabled { | |
| background: var(--bg-hover); | |
| color: var(--text-dim); | |
| cursor: not-allowed; | |
| } | |
| .gate-alert { | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| color: var(--signal-red); | |
| background: rgba(239, 68, 68, 0.1); | |
| border: 1px solid rgba(239, 68, 68, 0.3); | |
| padding: 8px 10px; | |
| border-radius: 5px; | |
| display: none; | |
| } | |
| .remember-session-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| font-size: 11px; | |
| color: var(--text-dim); | |
| margin-top: 4px; | |
| } | |
| .remember-session-row input { | |
| accent-color: var(--signal-blue); | |
| cursor: pointer; | |
| } | |
| /* Toast Notification */ | |
| .toast-box { | |
| position: fixed; | |
| bottom: 24px; | |
| right: 24px; | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border-accent); | |
| color: var(--text-bright); | |
| padding: 10px 16px; | |
| border-radius: 7px; | |
| font-size: 12px; | |
| font-family: var(--font-code); | |
| box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); | |
| z-index: 1000; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| transform: translateY(100px); | |
| opacity: 0; | |
| transition: all 0.25s ease; | |
| pointer-events: none; | |
| } | |
| .toast-box.show { | |
| transform: translateY(0); | |
| opacity: 1; | |
| } | |
| /* Footer */ | |
| footer { | |
| border-top: 1px solid var(--border-dark); | |
| padding: 16px 0; | |
| font-size: 11px; | |
| font-family: var(--font-code); | |
| color: var(--text-dim); | |
| } | |
| .footer-row { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Ambient Grid --> | |
| <div class="terminal-backdrop"></div> | |
| <!-- Security Passcode Gate Overlay --> | |
| <div id="gateOverlay" class="gate-overlay"> | |
| <div class="gate-modal"> | |
| <div class="gate-icon">🔒</div> | |
| <h1 class="gate-title">Security Clearance Gate</h1> | |
| <p class="gate-desc"> | |
| Access to the partitioned directory query gateway requires terminal authorization passcode or API key. | |
| <br> | |
| <span style="color: var(--text-bright); display: inline-block; margin-top: 6px;">Need an Access Passcode or API Key? Contact <a href="https://t.me/its_Xyron" target="_blank" style="color: #60a5fa; text-decoration: none; font-weight: 600;">@its_Xyron</a> on Telegram.</span> | |
| </p> | |
| <form id="gateForm" class="gate-form" onsubmit="event.preventDefault(); verifyPasscode();"> | |
| <label class="gate-label" for="passcodeInput"> | |
| <span>Passcode or API Key</span> | |
| <span id="lockoutTimer" style="color: var(--signal-amber); display: none;">LOCKED (45s)</span> | |
| </label> | |
| <div class="gate-input-wrapper"> | |
| <input type="password" id="passcodeInput" class="gate-input" placeholder="Enter authorization key..." autocomplete="off" autofocus> | |
| <button type="button" class="toggle-pass-btn" onclick="togglePassVisibility()" title="Show/Hide">👁</button> | |
| </div> | |
| <div id="gateAlert" class="gate-alert"></div> | |
| <div class="remember-session-row"> | |
| <input type="checkbox" id="rememberSession" checked> | |
| <label for="rememberSession">Keep session active on this device</label> | |
| </div> | |
| <button type="submit" id="gateSubmitBtn" class="gate-submit-btn">Unlock Console</button> | |
| </form> | |
| </div> | |
| </div> | |
| <!-- Top Navigation Header --> | |
| <header> | |
| <div class="container"> | |
| <div class="nav-bar"> | |
| <div class="brand"> | |
| <div class="brand-icon">XY</div> | |
| <div> | |
| <span class="brand-title">Directory Gateway</span> | |
| <span class="brand-tag">v2.4 Core</span> | |
| </div> | |
| </div> | |
| <div class="nav-tools"> | |
| <div class="system-status"> | |
| <span id="statusIndicator" class="status-dot"></span> | |
| <span id="statusText">ONLINE</span> | |
| </div> | |
| <button class="lock-btn" onclick="lockConsole()"> | |
| <span>🔒</span> | |
| <span>Lock</span> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Main Console --> | |
| <main> | |
| <div class="container"> | |
| <!-- Telemetry Stats Row --> | |
| <div class="telemetry-row"> | |
| <div class="telemetry-card"> | |
| <div class="telemetry-label">Active Records Indexed</div> | |
| <div class="telemetry-val" id="totalRecordsStat">478.8M+ Records</div> | |
| </div> | |
| <div class="telemetry-card"> | |
| <div class="telemetry-label">Cluster Engine</div> | |
| <div class="telemetry-val">DuckDB Vectorized Core</div> | |
| </div> | |
| <div class="telemetry-card"> | |
| <div class="telemetry-label">Active Services</div> | |
| <div class="telemetry-val">15 Search Nodes</div> | |
| </div> | |
| <div class="telemetry-card"> | |
| <div class="telemetry-label">Session Clearance</div> | |
| <div class="telemetry-val" id="sessionClearanceVal"> | |
| <span style="color: var(--signal-green); font-size: 11px;">●</span> | |
| <span id="authTierLabel">VERIFIED</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- STEP 1: SERVICE SELECTOR FIRST --> | |
| <section class="step-box"> | |
| <div class="step-header"> | |
| <div class="step-badge"> | |
| <span class="step-number">1</span> | |
| <span>Select Target Database / Service</span> | |
| </div> | |
| <span class="step-subtext">Choose target source before entering query</span> | |
| </div> | |
| <div class="services-grid" id="servicesGrid"> | |
| <!-- Combined 360 --> | |
| <div class="service-chip active" data-service="combined" onclick="selectService('combined')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">⚡ 360° Combined</span> | |
| <span class="service-chip-tag">PARALLEL</span> | |
| </div> | |
| <div class="service-chip-desc">8-DB Cross Search</div> | |
| </div> | |
| <!-- Truecaller --> | |
| <div class="service-chip" data-service="truecaller" onclick="selectService('truecaller')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">📞 Truecaller</span> | |
| <span class="service-chip-tag">285M</span> | |
| </div> | |
| <div class="service-chip-desc">Telecom Master</div> | |
| </div> | |
| <!-- Airtel India --> | |
| <div class="service-chip" data-service="airtel" onclick="selectService('airtel')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">📶 Airtel India</span> | |
| <span class="service-chip-tag">73M</span> | |
| </div> | |
| <div class="service-chip-desc">SIM & Circle DB</div> | |
| </div> | |
| <!-- HDFC Bank --> | |
| <div class="service-chip" data-service="hdfc" onclick="selectService('hdfc')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">🏦 HDFC Bank</span> | |
| <span class="service-chip-tag">11.3M</span> | |
| </div> | |
| <div class="service-chip-desc">CIBIL & Loans</div> | |
| </div> | |
| <!-- Telegram --> | |
| <div class="service-chip" data-service="telegram" onclick="selectService('telegram')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">📱 Telegram</span> | |
| <span class="service-chip-tag">65M</span> | |
| </div> | |
| <div class="service-chip-desc">User ID & Phone</div> | |
| </div> | |
| <!-- BSNL India --> | |
| <div class="service-chip" data-service="bsnl" onclick="selectService('bsnl')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">☎ BSNL India</span> | |
| <span class="service-chip-tag">18.1M</span> | |
| </div> | |
| <div class="service-chip-desc">Wireline & Mobile</div> | |
| </div> | |
| <!-- Paytm --> | |
| <div class="service-chip" data-service="paytm" onclick="selectService('paytm')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">💳 Paytm Core</span> | |
| <span class="service-chip-tag">2.95M</span> | |
| </div> | |
| <div class="service-chip-desc">KYC & Banking</div> | |
| </div> | |
| <!-- Flipkart --> | |
| <div class="service-chip" data-service="flipkart" onclick="selectService('flipkart')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">🛍 Flipkart</span> | |
| <span class="service-chip-tag">926K</span> | |
| </div> | |
| <div class="service-chip-desc">E-Commerce Address</div> | |
| </div> | |
| <!-- Instagram --> | |
| <div class="service-chip" data-service="instagram" onclick="selectService('instagram')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">📸 Instagram</span> | |
| <span class="service-chip-tag">16.7M</span> | |
| </div> | |
| <div class="service-chip-desc">Phone or Username</div> | |
| </div> | |
| <!-- Twitter --> | |
| <div class="service-chip" data-service="twitter" onclick="selectService('twitter')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">🐦 Twitter / X</span> | |
| <span class="service-chip-tag">5.48M</span> | |
| </div> | |
| <div class="service-chip-desc">ID or Handle</div> | |
| </div> | |
| <!-- Telecom Phone 2.5B --> | |
| <div class="service-chip" data-service="phone" onclick="selectService('phone')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">📞 Telecom Phone</span> | |
| <span class="service-chip-tag">2.5B</span> | |
| </div> | |
| <div class="service-chip-desc">National Subscribers</div> | |
| </div> | |
| <!-- Aadhaar Core --> | |
| <div class="service-chip" data-service="aadhar" onclick="selectService('aadhar')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">🪚 Aadhaar Core</span> | |
| <span class="service-chip-tag">UID</span> | |
| </div> | |
| <div class="service-chip-desc">12-Digit Registry</div> | |
| </div> | |
| <!-- Aadhaar Family Linkage --> | |
| <div class="service-chip" data-service="family" onclick="selectService('family')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">👪 Aadhaar Family</span> | |
| <span class="service-chip-tag">LINKAGE</span> | |
| </div> | |
| <div class="service-chip-desc">Family & Relations</div> | |
| </div> | |
| <!-- SBI POSP & Banking Master --> | |
| <div class="service-chip" data-service="sbi" onclick="selectService('sbi')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">🏛 SBI POSP & Bank</span> | |
| <span class="service-chip-tag">BANKING</span> | |
| </div> | |
| <div class="service-chip-desc">SBI, OLX & Muthoot</div> | |
| </div> | |
| <!-- IND Admissions & KYC Master --> | |
| <div class="service-chip" data-service="ind" onclick="selectService('ind')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">🎓 IND Admissions & KYC</span> | |
| <span class="service-chip-tag">KYC / 686K</span> | |
| </div> | |
| <div class="service-chip-desc">HR, KC, Colleges & Banks</div> | |
| </div> | |
| <!-- UPI & VPA 360 Resolver --> | |
| <div class="service-chip" data-service="upi" onclick="selectService('upi')"> | |
| <div class="service-chip-top"> | |
| <span class="service-chip-name">💳 UPI & VPA 360°</span> | |
| <span class="service-chip-tag">RESOLVER</span> | |
| </div> | |
| <div class="service-chip-desc">UPI ID to Num & KYC</div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- STEP 2: DYNAMIC QUERY INPUT BAR --> | |
| <section class="query-box"> | |
| <div class="active-target-banner"> | |
| <div class="target-info"> | |
| <span class="target-indicator"></span> | |
| <span id="activeServiceLabel">ACTIVE TARGET: COMBINED 360° PARALLEL</span> | |
| </div> | |
| <!-- Sub-mode toggles for Instagram / Twitter --> | |
| <div id="subModeToggle" class="input-mode-toggle"> | |
| <button type="button" id="modeBtn1" class="mode-btn active" onclick="setSubMode('phone')">Phone</button> | |
| <button type="button" id="modeBtn2" class="mode-btn" onclick="setSubMode('user')">Username</button> | |
| </div> | |
| </div> | |
| <form id="searchForm" onsubmit="event.preventDefault(); submitQuery();"> | |
| <div class="input-group"> | |
| <div class="input-wrapper"> | |
| <input | |
| type="text" | |
| id="queryInput" | |
| class="query-input" | |
| placeholder="Enter 10-digit Indian Mobile Number (e.g. 9876543210)..." | |
| autocomplete="off" | |
| maxlength="64" | |
| required | |
| > | |
| <button type="button" id="clearInputBtn" class="clear-btn" onclick="clearInput()" title="Clear">×</button> | |
| </div> | |
| <button type="submit" id="executeBtn" class="execute-btn"> | |
| <span id="btnSpinner" style="display: none;">⏳</span> | |
| <span id="btnText">EXECUTE QUERY</span> | |
| </button> | |
| </div> | |
| </form> | |
| <div class="input-meta-bar"> | |
| <div class="presets-wrap"> | |
| <span>Quick Samples:</span> | |
| <div id="quickPresets"> | |
| <!-- Dynamically populated per service --> | |
| </div> | |
| </div> | |
| <div class="anti-ddos-tag"> | |
| <span>Client Throttle: 2.0s</span> | |
| <span id="cooldownText" class="cooldown-indicator"></span> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- RESULTS PRESENTATION --> | |
| <section class="results-container"> | |
| <!-- Error & Warning Alert Box --> | |
| <div id="alertBox" class="alert-box"></div> | |
| <!-- Terminal Loader --> | |
| <div id="loadingState" class="loading-state"> | |
| <div class="terminal-loader"></div> | |
| <div class="loading-text" id="loadingHeadline">Routing query to target partition index...</div> | |
| <div class="loading-sub">Executing vectorized columnar scan with DuckDB</div> | |
| </div> | |
| <!-- Result Viewport --> | |
| <div id="resultsViewport"></div> | |
| </section> | |
| </div> | |
| </main> | |
| <!-- Toast Notification --> | |
| <div id="toastBox" class="toast-box"> | |
| <span id="toastIcon">✅</span> | |
| <span id="toastMsg">Record copied to clipboard</span> | |
| </div> | |
| <!-- Footer --> | |
| <footer> | |
| <div class="container"> | |
| <div class="footer-row"> | |
| <div>High-Performance Columnar Query Console • Security Level: Internal</div> | |
| <div>Indexed Records: 478.8M+ • Zero Leakage Protocol • Key Access: <a href="https://t.me/its_Xyron" target="_blank" style="color: #60a5fa; text-decoration: none;">@its_Xyron</a></div> | |
| </div> | |
| </div> | |
| </footer> | |
| <script> | |
| /* Security and Service Configuration */ | |
| const AUTH_PASSCODE = "XYRON-2026"; | |
| const SESSION_STORAGE_KEY = "xyron_term_auth"; | |
| const SESSION_API_KEY = "xyron_api_key"; | |
| // Application State | |
| let currentService = "combined"; | |
| let currentSubMode = "phone"; | |
| let isRequestInProgress = false; | |
| let cooldownTimer = null; | |
| let abortController = null; | |
| let failedAttempts = 0; | |
| let isLockedOut = false; | |
| // Service definitions with validation and presets | |
| const SERVICE_DEFS = { | |
| combined: { | |
| label: "TARGET: COMBINED 360° PARALLEL SEARCH", | |
| placeholder: "Enter 10-digit Indian Mobile (e.g. 9876543210) for 8-DB scan...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9876543210", "9812345678", "9123456789"], | |
| hasSubMode: false | |
| }, | |
| truecaller: { | |
| label: "TARGET: TRUECALLER 285M TELECOM DB", | |
| placeholder: "Enter 10-digit Indian Mobile Number...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9876543210", "9820012345", "9988776655"], | |
| hasSubMode: false | |
| }, | |
| airtel: { | |
| label: "TARGET: AIRTEL INDIA 73M MASTER DB", | |
| placeholder: "Enter 10-digit Airtel / Mobile Number...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9810012345", "9845012345", "9890012345"], | |
| hasSubMode: false | |
| }, | |
| hdfc: { | |
| label: "TARGET: HDFC BANK CORE & CIBIL DB", | |
| placeholder: "Enter 10-digit Mobile Number for CIBIL/Loan check...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9820123456", "9811122233", "9844055667"], | |
| hasSubMode: false | |
| }, | |
| telegram: { | |
| label: "TARGET: TELEGRAM GLOBAL 65M MASTER DB", | |
| placeholder: "Enter Telegram User ID (e.g. 74252719) or Phone...", | |
| inputType: "text", | |
| maxLength: 16, | |
| presets: ["74252719", "12345678", "9876543210"], | |
| hasSubMode: false | |
| }, | |
| bsnl: { | |
| label: "TARGET: BSNL NATIONAL 18.1M MASTER DB", | |
| placeholder: "Enter 10-digit BSNL Mobile or Landline...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9415012345", "9435012345", "9444012345"], | |
| hasSubMode: false | |
| }, | |
| paytm: { | |
| label: "TARGET: PAYTM INDIA 2.95M KYC DB", | |
| placeholder: "Enter 10-digit Paytm Registered Mobile...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9876543210", "9711012345", "9818012345"], | |
| hasSubMode: false | |
| }, | |
| flipkart: { | |
| label: "TARGET: FLIPKART INDIA 926K ACCOUNTS DB", | |
| placeholder: "Enter 10-digit Flipkart Account Mobile...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9876543210", "9899012345", "9821012345"], | |
| hasSubMode: false | |
| }, | |
| instagram: { | |
| label: "TARGET: INSTAGRAM 16.7M OSINT DB", | |
| placeholder: "Enter 10-digit Phone or @username...", | |
| inputType: "text", | |
| maxLength: 32, | |
| presets: ["aditya", "rohit", "9876543210"], | |
| hasSubMode: true, | |
| mode1: "Phone", | |
| mode2: "Username" | |
| }, | |
| twitter: { | |
| label: "TARGET: TWITTER / X 5.48M ACCOUNTS DB", | |
| placeholder: "Enter Twitter Numeric User ID or Handle...", | |
| inputType: "text", | |
| maxLength: 32, | |
| presets: ["44196397", "123456", "aditya"], | |
| hasSubMode: true, | |
| mode1: "User ID", | |
| mode2: "Handle" | |
| }, | |
| phone: { | |
| label: "TARGET: TELECOM 2.5B NATIONAL REGISTRY", | |
| placeholder: "Enter 10-digit Indian Mobile Number...", | |
| inputType: "tel", | |
| maxLength: 10, | |
| presets: ["9910415684", "9876543210", "9810012345"], | |
| hasSubMode: false | |
| }, | |
| aadhar: { | |
| label: "TARGET: AADHAAR 12-DIGIT REGISTRY", | |
| placeholder: "Enter 12-digit Aadhaar Number (digits only)...", | |
| inputType: "text", | |
| maxLength: 12, | |
| presets: ["234567890123", "987654321098"], | |
| hasSubMode: false | |
| }, | |
| family: { | |
| label: "TARGET: AADHAAR FAMILY & HOUSEHOLD LINKAGE", | |
| placeholder: "Enter 12-digit Aadhaar UID or 10-digit Mobile...", | |
| inputType: "text", | |
| maxLength: 14, | |
| presets: ["234567890123", "9910415684"], | |
| hasSubMode: false | |
| }, | |
| sbi: { | |
| label: "TARGET: SBI POSP & INDIAN BANKING MASTER DB", | |
| placeholder: "Enter Phone, Aadhaar, PAN, Name, or Email...", | |
| inputType: "text", | |
| maxLength: 32, | |
| presets: ["9910415684", "nehacarstreet1@gmail.com", "Carstreet naraina"], | |
| hasSubMode: false | |
| }, | |
| ind: { | |
| label: "TARGET: IND ADMISSIONS, EDUCATION & KYC MASTER DB", | |
| placeholder: "Enter Phone, Email, Aadhaar, PAN, or Name...", | |
| inputType: "text", | |
| maxLength: 40, | |
| presets: ["9769009011", "9699616059", "AVI.ALWAYSWITHU@GMAIL.COM"], | |
| hasSubMode: false | |
| }, | |
| upi: { | |
| label: "TARGET: UPI ID & VPA 360° OSINT RESOLVER", | |
| placeholder: "Enter UPI ID (e.g. 9826287975@paytm) or 10-digit Mobile...", | |
| inputType: "text", | |
| maxLength: 48, | |
| presets: ["9826287975@paytm", "9769009011@okhdfcbank", "9826287975"], | |
| hasSubMode: false | |
| } | |
| }; | |
| /* Initialization */ | |
| document.addEventListener("DOMContentLoaded", () => { | |
| checkStoredAuth(); | |
| setupInputListeners(); | |
| selectService("combined"); | |
| renderPresets("combined"); | |
| }); | |
| /* Authorization and Passcode Verification */ | |
| function checkStoredAuth() { | |
| const stored = localStorage.getItem(SESSION_STORAGE_KEY) || sessionStorage.getItem(SESSION_STORAGE_KEY); | |
| if (stored === "authenticated") { | |
| document.getElementById("gateOverlay").style.display = "none"; | |
| document.getElementById("authTierLabel").textContent = "AUTHORIZED"; | |
| } else { | |
| document.getElementById("gateOverlay").style.display = "flex"; | |
| } | |
| } | |
| function verifyPasscode() { | |
| if (isLockedOut) return; | |
| const input = document.getElementById("passcodeInput").value.trim(); | |
| const alertEl = document.getElementById("gateAlert"); | |
| const remember = document.getElementById("rememberSession").checked; | |
| // Accepted keys: Primary Passcode, Lowercase variant, or Master Admin Key | |
| if ( | |
| input === AUTH_PASSCODE || | |
| input.toLowerCase() === AUTH_PASSCODE.toLowerCase() || | |
| input === "secretz_master_admin_2026" || | |
| input.startsWith("sk_live_") | |
| ) { | |
| alertEl.style.display = "none"; | |
| failedAttempts = 0; | |
| if (remember) { | |
| localStorage.setItem(SESSION_STORAGE_KEY, "authenticated"); | |
| if (input.startsWith("sk_live_") || input === "secretz_master_admin_2026") { | |
| localStorage.setItem(SESSION_API_KEY, input); | |
| } | |
| } else { | |
| sessionStorage.setItem(SESSION_STORAGE_KEY, "authenticated"); | |
| if (input.startsWith("sk_live_") || input === "secretz_master_admin_2026") { | |
| sessionStorage.setItem(SESSION_API_KEY, input); | |
| } | |
| } | |
| document.getElementById("gateOverlay").style.display = "none"; | |
| document.getElementById("authTierLabel").textContent = input.startsWith("sk_live_") ? "API_KEY" : "AUTHORIZED"; | |
| showToast("Access Granted. Security clearance verified.", "✅"); | |
| } else { | |
| failedAttempts++; | |
| alertEl.textContent = `Access Denied: Invalid credentials (${failedAttempts}/3 attempts)`; | |
| alertEl.style.display = "block"; | |
| if (failedAttempts >= 3) { | |
| triggerLockout(45); | |
| } | |
| } | |
| } | |
| function triggerLockout(seconds) { | |
| isLockedOut = true; | |
| const btn = document.getElementById("gateSubmitBtn"); | |
| const input = document.getElementById("passcodeInput"); | |
| const timerEl = document.getElementById("lockoutTimer"); | |
| const alertEl = document.getElementById("gateAlert"); | |
| btn.disabled = true; | |
| input.disabled = true; | |
| timerEl.style.display = "inline"; | |
| let remaining = seconds; | |
| alertEl.textContent = "Anti-Brute-Force Lockout triggered. Please wait."; | |
| const interval = setInterval(() => { | |
| remaining--; | |
| timerEl.textContent = `LOCKED (${remaining}s)`; | |
| if (remaining <= 0) { | |
| clearInterval(interval); | |
| isLockedOut = false; | |
| btn.disabled = false; | |
| input.disabled = false; | |
| timerEl.style.display = "none"; | |
| alertEl.style.display = "none"; | |
| failedAttempts = 0; | |
| } | |
| }, 1000); | |
| } | |
| function togglePassVisibility() { | |
| const input = document.getElementById("passcodeInput"); | |
| input.type = input.type === "password" ? "text" : "password"; | |
| } | |
| function lockConsole() { | |
| localStorage.removeItem(SESSION_STORAGE_KEY); | |
| sessionStorage.removeItem(SESSION_STORAGE_KEY); | |
| document.getElementById("passcodeInput").value = ""; | |
| document.getElementById("gateAlert").style.display = "none"; | |
| document.getElementById("gateOverlay").style.display = "flex"; | |
| showToast("Console locked.", "🔒"); | |
| } | |
| /* STEP 1: Service Selection */ | |
| function selectService(serviceKey) { | |
| if (!SERVICE_DEFS[serviceKey]) return; | |
| currentService = serviceKey; | |
| // Update active chip UI | |
| document.querySelectorAll(".service-chip").forEach(el => { | |
| if (el.getAttribute("data-service") === serviceKey) { | |
| el.classList.add("active"); | |
| } else { | |
| el.classList.remove("active"); | |
| } | |
| }); | |
| const def = SERVICE_DEFS[serviceKey]; | |
| document.getElementById("activeServiceLabel").textContent = def.label; | |
| const input = document.getElementById("queryInput"); | |
| input.placeholder = def.placeholder; | |
| input.maxLength = def.maxLength; | |
| input.value = ""; | |
| document.getElementById("clearInputBtn").style.display = "none"; | |
| // Sub-mode visibility | |
| const subToggle = document.getElementById("subModeToggle"); | |
| if (def.hasSubMode) { | |
| subToggle.style.display = "flex"; | |
| document.getElementById("modeBtn1").textContent = def.mode1; | |
| document.getElementById("modeBtn2").textContent = def.mode2; | |
| setSubMode("phone"); | |
| } else { | |
| subToggle.style.display = "none"; | |
| } | |
| renderPresets(serviceKey); | |
| clearAlert(); | |
| input.focus(); | |
| } | |
| function setSubMode(mode) { | |
| currentSubMode = mode; | |
| const b1 = document.getElementById("modeBtn1"); | |
| const b2 = document.getElementById("modeBtn2"); | |
| const input = document.getElementById("queryInput"); | |
| if (mode === "phone") { | |
| b1.classList.add("active"); | |
| b2.classList.remove("active"); | |
| input.placeholder = "Enter 10-digit mobile number..."; | |
| } else { | |
| b2.classList.add("active"); | |
| b1.classList.remove("active"); | |
| input.placeholder = currentService === "twitter" ? "Enter @handle or user_id..." : "Enter @username without @..."; | |
| } | |
| input.focus(); | |
| } | |
| function renderPresets(serviceKey) { | |
| const wrap = document.getElementById("quickPresets"); | |
| wrap.innerHTML = ""; | |
| const presets = SERVICE_DEFS[serviceKey]?.presets || []; | |
| presets.forEach(p => { | |
| const btn = document.createElement("button"); | |
| btn.type = "button"; | |
| btn.className = "preset-btn"; | |
| btn.textContent = p; | |
| btn.onclick = () => { | |
| document.getElementById("queryInput").value = p; | |
| document.getElementById("clearInputBtn").style.display = "block"; | |
| document.getElementById("queryInput").focus(); | |
| }; | |
| wrap.appendChild(btn); | |
| }); | |
| } | |
| function setupInputListeners() { | |
| const input = document.getElementById("queryInput"); | |
| const clearBtn = document.getElementById("clearInputBtn"); | |
| input.addEventListener("input", () => { | |
| clearBtn.style.display = input.value.length > 0 ? "block" : "none"; | |
| }); | |
| // Keyboard shortcuts | |
| document.addEventListener("keydown", (e) => { | |
| if (e.key === "/" && document.activeElement !== input) { | |
| e.preventDefault(); | |
| input.focus(); | |
| } else if (e.key === "Escape") { | |
| clearInput(); | |
| } | |
| }); | |
| } | |
| function clearInput() { | |
| const input = document.getElementById("queryInput"); | |
| input.value = ""; | |
| document.getElementById("clearInputBtn").style.display = "none"; | |
| input.focus(); | |
| } | |
| /* Anti-DDoS Throttling & Query Dispatcher */ | |
| async function submitQuery() { | |
| if (isRequestInProgress) return; | |
| const rawInput = document.getElementById("queryInput").value.trim(); | |
| if (!rawInput) return; | |
| // Abort previous in-flight request if any | |
| if (abortController) { | |
| abortController.abort(); | |
| } | |
| abortController = new AbortController(); | |
| // Client-Side Input Sanitization | |
| const cleanInput = rawInput.replace(/[<>'"`;]/g, ""); | |
| // Endpoint Resolution based on Selected Service | |
| let endpoint = ""; | |
| const apiKey = localStorage.getItem(SESSION_API_KEY) || sessionStorage.getItem(SESSION_API_KEY) || ""; | |
| switch (currentService) { | |
| case "combined": | |
| endpoint = `/api/combined/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "truecaller": | |
| endpoint = `/api/truecaller/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "airtel": | |
| endpoint = `/api/airtel/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "hdfc": | |
| endpoint = `/api/hdfc/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "telegram": | |
| endpoint = `/api/telegram/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "bsnl": | |
| endpoint = `/api/bsnl/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "paytm": | |
| endpoint = `/api/paytm/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "flipkart": | |
| endpoint = `/api/flipkart/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "instagram": | |
| endpoint = `/api/instagram/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "twitter": | |
| endpoint = `/api/twitter/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "phone": | |
| endpoint = `/api/phone/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "aadhar": | |
| endpoint = `/api/aadhar/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "family": | |
| endpoint = `/api/family/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "sbi": | |
| endpoint = `/api/sbi/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "ind": | |
| endpoint = `/api/ind/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| case "upi": | |
| endpoint = `/api/upi/${encodeURIComponent(cleanInput)}`; | |
| break; | |
| default: | |
| endpoint = `/api/lookup?q=${encodeURIComponent(cleanInput)}`; | |
| } | |
| // Add auth header or query param if available | |
| let headers = {}; | |
| if (apiKey) { | |
| headers["X-API-Key"] = apiKey; | |
| } | |
| setLoading(true); | |
| clearAlert(); | |
| const startTime = performance.now(); | |
| try { | |
| const response = await fetch(endpoint, { | |
| headers: headers, | |
| signal: abortController.signal | |
| }); | |
| const elapsedMs = Math.round(performance.now() - startTime); | |
| if (response.status === 429) { | |
| const errData = await response.json().catch(() => ({ detail: "Rate limit reached." })); | |
| showAlert((errData.detail || "Rate limit reached.") + " Contact @its_Xyron on Telegram for an unrestricted Access Key.", "warning"); | |
| enforceCooldown(5); | |
| return; | |
| } | |
| if (!response.ok) { | |
| const errData = await response.json().catch(() => ({ detail: "Request failed." })); | |
| showAlert(errData.detail || `Server returned HTTP ${response.status}`, "error"); | |
| return; | |
| } | |
| const data = await response.json(); | |
| renderResults(data, elapsedMs); | |
| // Enforce anti-DDoS 2.0s cooldown | |
| enforceCooldown(2.0); | |
| } catch (err) { | |
| if (err.name === "AbortError") { | |
| // Intentionally aborted | |
| return; | |
| } | |
| showAlert("Connection error: Gateway request failed. Check network or server status.", "error"); | |
| } finally { | |
| setLoading(false); | |
| } | |
| } | |
| function enforceCooldown(seconds) { | |
| const btn = document.getElementById("executeBtn"); | |
| const cdText = document.getElementById("cooldownText"); | |
| btn.disabled = true; | |
| let left = seconds; | |
| cdText.textContent = `(${left.toFixed(1)}s lock)`; | |
| if (cooldownTimer) clearInterval(cooldownTimer); | |
| cooldownTimer = setInterval(() => { | |
| left -= 0.5; | |
| if (left <= 0) { | |
| clearInterval(cooldownTimer); | |
| btn.disabled = false; | |
| cdText.textContent = ""; | |
| } else { | |
| cdText.textContent = `(${left.toFixed(1)}s lock)`; | |
| } | |
| }, 500); | |
| } | |
| function setLoading(isLoading) { | |
| isRequestInProgress = isLoading; | |
| const loader = document.getElementById("loadingState"); | |
| const btnText = document.getElementById("btnText"); | |
| const btnSpinner = document.getElementById("btnSpinner"); | |
| const executeBtn = document.getElementById("executeBtn"); | |
| if (isLoading) { | |
| loader.style.display = "block"; | |
| btnText.textContent = "QUERYING..."; | |
| btnSpinner.style.display = "inline"; | |
| executeBtn.disabled = true; | |
| } else { | |
| loader.style.display = "none"; | |
| btnText.textContent = "EXECUTE QUERY"; | |
| btnSpinner.style.display = "none"; | |
| } | |
| } | |
| function showAlert(msg, type = "error") { | |
| const box = document.getElementById("alertBox"); | |
| box.textContent = msg; | |
| box.className = `alert-box ${type}`; | |
| box.style.display = "block"; | |
| } | |
| function clearAlert() { | |
| const box = document.getElementById("alertBox"); | |
| box.style.display = "none"; | |
| box.textContent = ""; | |
| } | |
| /* Clean Result Rendering - ZERO Backend Numbers or Partition Filenames */ | |
| function renderResults(data, clientElapsedMs) { | |
| const viewport = document.getElementById("resultsViewport"); | |
| viewport.innerHTML = ""; | |
| if (!data) { | |
| showAlert("No data received from gateway node.", "warning"); | |
| return; | |
| } | |
| // 1. COMBINED 360 PARALLEL RESULT VIEW | |
| if (currentService === "combined" && data.consolidated_summary) { | |
| renderCombinedView(viewport, data, clientElapsedMs); | |
| return; | |
| } | |
| // 2. SINGLE SERVICE RESULT VIEW | |
| renderSingleServiceView(viewport, data, clientElapsedMs); | |
| } | |
| function renderCombinedView(container, data, clientElapsedMs) { | |
| const sum = data.consolidated_summary || {}; | |
| const latency = data.latency_ms || clientElapsedMs; | |
| const hits = data.total_sources_hit || 0; | |
| const totalQueried = data.total_sources_queried || 8; | |
| const card = document.createElement("div"); | |
| card.className = "result-sheet"; | |
| // Card Header | |
| card.innerHTML = ` | |
| <div class="sheet-header"> | |
| <div class="sheet-title-group"> | |
| <span class="sheet-badge ${hits > 0 ? 'badge-success' : 'badge-empty'}"> | |
| ${hits > 0 ? 'VERIFIED MATCH' : 'NO RECORD'} | |
| </span> | |
| <span class="sheet-title">Consolidated Intelligence Dossier</span> | |
| </div> | |
| <div class="sheet-meta"> | |
| <span>Sources Hit: ${hits}/${totalQueried}</span> | |
| <span>Latency: ${latency}ms</span> | |
| </div> | |
| <div class="sheet-actions"> | |
| <button class="action-btn" onclick="copyJson(this)">Copy JSON</button> | |
| </div> | |
| </div> | |
| `; | |
| // Intel Briefing Box | |
| const brief = document.createElement("div"); | |
| brief.className = "intel-brief-card"; | |
| const namesStr = sum.names_found?.length ? sum.names_found.join(" / ") : "Unverified"; | |
| const primaryLoc = sum.locations_identified?.length ? sum.locations_identified[0] : "Not Specified"; | |
| const carrierStr = sum.carriers_identified?.length ? sum.carriers_identified.join(", ") : "Telecom Node"; | |
| const emailsStr = sum.emails_found?.length ? sum.emails_found.join(", ") : "None on record"; | |
| const cibilVal = sum.cibil_score || sum.highmark_score || null; | |
| brief.innerHTML = ` | |
| <div class="brief-title-bar"> | |
| <span class="brief-title">⚡ Primary Intelligence Summary</span> | |
| <span style="font-family: var(--font-code); font-size: 11px; color: var(--text-dim);">${data.formatted_phone || data.query}</span> | |
| </div> | |
| <div class="brief-grid"> | |
| <div class="brief-item"> | |
| <span class="brief-label">Primary Subscriber Name</span> | |
| <span class="brief-val" style="color: #60a5fa; font-weight: 700;">${escapeHtml(namesStr)}</span> | |
| </div> | |
| <div class="brief-item"> | |
| <span class="brief-label">Registered Location / Circle</span> | |
| <span class="brief-val">${escapeHtml(primaryLoc)}</span> | |
| </div> | |
| <div class="brief-item"> | |
| <span class="brief-label">Carrier & Routing</span> | |
| <span class="brief-val">${escapeHtml(carrierStr)}</span> | |
| </div> | |
| <div class="brief-item"> | |
| <span class="brief-label">Email Accounts Found</span> | |
| <span class="brief-val">${escapeHtml(emailsStr)}</span> | |
| </div> | |
| ${cibilVal ? ` | |
| <div class="brief-item"> | |
| <span class="brief-label">Credit Bureau Score</span> | |
| <span class="brief-val"> | |
| <span class="score-badge">✔ ${escapeHtml(String(cibilVal))} Score</span> | |
| </span> | |
| </div> | |
| ` : ''} | |
| ${sum.instagram_usernames?.length ? ` | |
| <div class="brief-item"> | |
| <span class="brief-label">Linked Instagram</span> | |
| <span class="brief-val" style="color: #e879f9;">@${escapeHtml(sum.instagram_usernames.join(", @"))}</span> | |
| </div> | |
| ` : ''} | |
| </div> | |
| `; | |
| card.appendChild(brief); | |
| // Accordion for Sub-Databases | |
| const body = document.createElement("div"); | |
| body.className = "sheet-body"; | |
| const sourceTitles = { | |
| truecaller: "Truecaller Telecom DB (285M)", | |
| airtel: "Airtel India Subscriber DB (73M)", | |
| hdfc: "HDFC Banking & Loan DB (11.3M)", | |
| sbi: "SBI POSP & Indian Banking DB", | |
| ind: "IND Admissions, Colleges & KYC Master (686K)", | |
| bsnl: "BSNL National DB (18.1M)", | |
| paytm: "Paytm Payments Core (2.95M)", | |
| flipkart: "Flipkart Logistics Accounts (926K)", | |
| instagram: "Instagram Social Graph (16.7M)", | |
| telecom_db: "Telecom Circle Registry" | |
| }; | |
| const sources = data.sources || {}; | |
| for (const [key, sData] of Object.entries(sources)) { | |
| const isHit = sData.status === "success" || sData.success === true || (sData.records && sData.records.length > 0); | |
| const drawer = document.createElement("div"); | |
| drawer.className = "source-drawer"; | |
| const title = sourceTitles[key] || key.toUpperCase(); | |
| drawer.innerHTML = ` | |
| <button type="button" class="drawer-toggle" onclick="toggleDrawer(this)"> | |
| <div class="drawer-left"> | |
| <span class="drawer-name">${title}</span> | |
| <span class="drawer-status ${isHit ? 'hit' : 'miss'}">${isHit ? 'RECORD FOUND' : 'NO RECORD'}</span> | |
| </div> | |
| <span style="font-family: var(--font-code); font-size: 11px;">${isHit ? '▼ Inspect' : '—'}</span> | |
| </button> | |
| <div class="drawer-content"> | |
| ${isHit ? renderRecordCards(sData.records || [sData]) : '<div style="color: var(--text-dim); font-size: 12px; font-family: var(--font-code);">No matching entries located in this segment.</div>'} | |
| </div> | |
| `; | |
| body.appendChild(drawer); | |
| } | |
| card.appendChild(body); | |
| card._rawJson = data; | |
| container.appendChild(card); | |
| } | |
| function renderSingleServiceView(container, data, clientElapsedMs) { | |
| const records = data.records || (data.user_id ? [data] : []); | |
| const count = records.length; | |
| const isSuccess = data.status === "success" || data.success === true || count > 0; | |
| const latency = data.latency_ms || clientElapsedMs; | |
| const card = document.createElement("div"); | |
| card.className = "result-sheet"; | |
| card.innerHTML = ` | |
| <div class="sheet-header"> | |
| <div class="sheet-title-group"> | |
| <span class="sheet-badge ${isSuccess ? 'badge-success' : 'badge-empty'}"> | |
| ${isSuccess ? 'CONFIRMED' : 'NO RECORD'} | |
| </span> | |
| <span class="sheet-title">${escapeHtml(data.database || SERVICE_DEFS[currentService].label.replace("TARGET: ", ""))}</span> | |
| </div> | |
| <div class="sheet-meta"> | |
| <span>Matches: ${count}</span> | |
| <span>Latency: ${latency}ms</span> | |
| </div> | |
| <div class="sheet-actions"> | |
| <button class="action-btn" onclick="copyJson(this)">Copy JSON</button> | |
| </div> | |
| </div> | |
| <div class="sheet-body"> | |
| ${isSuccess && count > 0 ? renderRecordCards(records) : ` | |
| <div style="padding: 24px; text-align: center; color: var(--text-dim); font-family: var(--font-code); font-size: 13px;"> | |
| No records found for identifier: <strong style="color: var(--text-bright);">${escapeHtml(data.query || data.mobile || data.user_id || "specified query")}</strong> | |
| </div> | |
| `} | |
| </div> | |
| `; | |
| card._rawJson = data; | |
| container.appendChild(card); | |
| } | |
| function renderRecordCards(records) { | |
| if (!records || !records.length) return ""; | |
| // Blacklist of internal keys that should NEVER be rendered in UI | |
| const blacklist = new Set([ | |
| "target_partition", "partition", "url", "file", | |
| "min_mobile", "max_mobile", "min_phone", "max_phone", | |
| "min_id", "max_id", "clean_num" | |
| ]); | |
| return records.map((rec, idx) => { | |
| const cells = Object.entries(rec) | |
| .filter(([k, v]) => !blacklist.has(k) && v !== null && v !== "" && v !== "None") | |
| .map(([k, v]) => ` | |
| <div class="data-cell"> | |
| <span class="data-key">${formatKeyName(k)}</span> | |
| <span class="data-value">${escapeHtml(String(v))}</span> | |
| </div> | |
| `).join(""); | |
| return ` | |
| <div class="record-card"> | |
| <div class="record-grid"> | |
| ${cells || '<div class="data-cell"><span class="data-value">No detailed attributes</span></div>'} | |
| </div> | |
| </div> | |
| `; | |
| }).join(""); | |
| } | |
| function formatKeyName(key) { | |
| const mapping = { | |
| name: "Full Name", | |
| mobile: "Phone Number", | |
| phone: "Phone Number", | |
| phoneNumber: "Phone Number", | |
| carrier: "Telecom Operator", | |
| address: "Registered Address", | |
| district: "District", | |
| town: "Town / City", | |
| city: "City", | |
| state: "State", | |
| pincode: "PIN Code", | |
| email: "Email Address", | |
| gender: "Gender", | |
| cibil: "CIBIL Score", | |
| highmark_score: "Highmark Score", | |
| bank: "Banking Institution", | |
| branch: "Branch Name", | |
| status: "Application Status", | |
| approved_amount: "Approved Limit", | |
| applied_amount: "Requested Limit", | |
| finance_amount: "Financed Sum", | |
| product_type: "Facility Type", | |
| card_category: "Card Category", | |
| login_date: "Verification Date", | |
| fathersName: "Father's Name", | |
| aadharNumber: "Aadhaar UID", | |
| user_id: "Account Identifier", | |
| username: "Profile Username", | |
| screen_name: "Screen Name / Handle", | |
| followers_count: "Followers", | |
| friends_count: "Following", | |
| created_at: "Profile Created", | |
| verified: "Verification Badge", | |
| country: "Country Circle", | |
| formatted_phone: "International Phone" | |
| }; | |
| return mapping[key] || key.replace(/_/g, " ").toUpperCase(); | |
| } | |
| function toggleDrawer(btn) { | |
| const content = btn.nextElementSibling; | |
| if (content) { | |
| content.classList.toggle("open"); | |
| } | |
| } | |
| function copyJson(btn) { | |
| const card = btn.closest(".result-sheet"); | |
| if (card && card._rawJson) { | |
| // Deep copy and sanitize before putting in user clipboard | |
| const sanitized = JSON.parse(JSON.stringify(card._rawJson)); | |
| delete sanitized.target_partition; | |
| delete sanitized.partition; | |
| navigator.clipboard.writeText(JSON.stringify(sanitized, null, 2)) | |
| .then(() => showToast("Record JSON copied to clipboard", "📋")) | |
| .catch(() => showToast("Failed to copy", "❌")); | |
| } | |
| } | |
| function showToast(msg, icon = "✅") { | |
| const box = document.getElementById("toastBox"); | |
| document.getElementById("toastMsg").textContent = msg; | |
| document.getElementById("toastIcon").textContent = icon; | |
| box.classList.add("show"); | |
| setTimeout(() => box.classList.remove("show"), 2400); | |
| } | |
| function escapeHtml(str) { | |
| if (!str) return ""; | |
| return String(str) | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">") | |
| .replace(/"/g, """) | |
| .replace(/'/g, "'"); | |
| } | |
| </script> | |
| </body> | |
| </html> | |