{"id":2451,"date":"2024-08-08T16:45:49","date_gmt":"2024-08-08T16:45:49","guid":{"rendered":"https:\/\/www.zlati.legal\/?p=2451"},"modified":"2025-12-29T07:54:37","modified_gmt":"2025-12-29T07:54:37","slug":"fraude-si-infractiuni-bancare","status":"publish","type":"post","link":"https:\/\/zic.legal\/ro\/fraude-si-infractiuni-bancare\/","title":{"rendered":"Fraude \u0219i infrac\u021biuni bancare"},"content":{"rendered":"<div id=\"zic-website-spoofing-v2\" class=\"zic2\" data-zic2=\"1\">\r\n  <!-- Skip Link for Keyboard Navigation -->\r\n  <a href=\"#zic2v2-url-input\" class=\"zic2__skipLink\">\r\n    Sari la formularul de verificare\r\n  <\/a>\r\n\r\n  <!-- Screen Reader Status Announcements -->\r\n  <div class=\"zic2__srStatus\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-sr-status><\/div>\r\n\r\n  <div class=\"zic2__wrap\">\r\n    <!-- Header -->\r\n    <header class=\"zic2__hero\">\r\n      <div class=\"zic2__brandbar\">\r\n        <div class=\"zic2__mark\" aria-hidden=\"true\">\r\n          <svg width=\"20\" height=\"20\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n            <circle cx=\"11\" cy=\"11\" r=\"8\"\/>\r\n            <path d=\"M21 21l-4.35-4.35\"\/>\r\n          <\/svg>\r\n        <\/div>\r\n        <div class=\"zic2__headerText\">\r\n          <h2 class=\"zic2__title\" data-i18n=\"title\">Verificare website spoofing<\/h2>\r\n          <p class=\"zic2__subtitle\" data-i18n=\"subtitle\">Detecteaz\u0103 link-uri suspecte \u0219i tentative de phishing<\/p>\r\n        <\/div>\r\n        <button type=\"button\" class=\"zic2__themeBtn\" data-action=\"toggleTheme\" title=\"Toggle dark mode\" aria-label=\"Switch to dark mode\" aria-pressed=\"false\">\r\n          <svg class=\"zic2__themeIcon zic2__themeIcon--sun\" width=\"18\" height=\"18\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"5\"\/><line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\"\/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\"\/><line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\"\/><line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\"\/><line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\"\/><line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\"\/><line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\"\/><line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\"\/><\/svg>\r\n          <svg class=\"zic2__themeIcon zic2__themeIcon--moon\" width=\"18\" height=\"18\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\"\/><\/svg>\r\n        <\/button>\r\n        <button type=\"button\" class=\"zic2__langBtn\" data-action=\"toggleLang\" title=\"Switch language\" aria-label=\"Switch to English\">\r\n          <span data-i18n=\"langSwitch\">EN<\/span>\r\n        <\/button>\r\n        <div class=\"zic2__version\">v4.1<\/div>\r\n      <\/div>\r\n    <\/header>\r\n\r\n    <!-- Formula info -->\r\n    <div class=\"zic2__formula\">\r\n      <div class=\"zic2__formulaIcon\">\r\n        <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n          <circle cx=\"12\" cy=\"12\" r=\"10\"\/>\r\n          <path d=\"M12 16v-4\"\/>\r\n          <path d=\"M12 8h.01\"\/>\r\n        <\/svg>\r\n      <\/div>\r\n      <div class=\"zic2__formulaText\" data-i18n-html=\"formula\">\r\n        <strong>Cum func\u021bioneaz\u0103:<\/strong> Analiz\u0103m URL-ul pentru typosquatting, caractere Unicode suspecte, extensii de domeniu riscante \u0219i alte indicii de phishing. Verific\u0103m suplimentar prin <strong>5 surse externe<\/strong>: Google Safe Browsing, VirusTotal, URLhaus, urlscan.io \u0219i PhishTank.\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Card: Input URL -->\r\n    <section class=\"zic2__card\" aria-labelledby=\"zic2-sec-input\">\r\n      <div class=\"zic2__cardHeader\">\r\n        <div class=\"zic2__cardIcon zic2__cardIcon--purple\">\r\n          <svg width=\"18\" height=\"18\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n            <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\r\n            <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\r\n          <\/svg>\r\n        <\/div>\r\n        <h3 id=\"zic2-sec-input\" class=\"zic2__cardTitle\" data-i18n=\"inputTitle\">Link de verificat<\/h3>\r\n      <\/div>\r\n\r\n      <!-- Batch Mode Toggle -->\r\n      <div class=\"zic2__batchToggle\">\r\n        <label class=\"zic2__checkboxLabel\" for=\"zic2-batch-mode\">\r\n          <input type=\"checkbox\" id=\"zic2-batch-mode\" class=\"zic2__checkbox\" data-field=\"batchMode\" aria-describedby=\"zic2-batch-desc\" \/>\r\n          <span class=\"zic2__checkboxText\" data-i18n=\"batchMode\">Mod batch (verific\u0103 multiple URL-uri)<\/span>\r\n        <\/label>\r\n      <\/div>\r\n\r\n      <!-- Single URL Input -->\r\n      <div class=\"zic2__field\" data-single-input>\r\n        <label class=\"zic2__label\" for=\"zic2v2-url-input\" data-i18n=\"inputLabel\">Introdu link-ul website-ului<\/label>\r\n        <input type=\"text\" id=\"zic2v2-url-input\" class=\"zic2__input\" data-field=\"urlInput\" data-i18n-placeholder=\"inputPlaceholder\" placeholder=\"https:\/\/example.com\" maxlength=\"2048\" autocomplete=\"off\" \/>\r\n      <\/div>\r\n\r\n      <!-- Batch URL Input (hidden by default) -->\r\n      <div class=\"zic2__field is-hidden\" data-batch-input>\r\n        <label class=\"zic2__label\" for=\"zic2v2-url-batch\" data-i18n=\"batchLabel\">Introdu URL-urile (unul pe linie, max 10)<\/label>\r\n        <textarea id=\"zic2v2-url-batch\" class=\"zic2__input\" data-field=\"urlBatch\" rows=\"6\" style=\"resize: vertical; font-family: monospace; font-size: 13px;\" placeholder=\"https:\/\/example1.com&#10;https:\/\/example2.com&#10;https:\/\/example3.com\"><\/textarea>\r\n      <\/div>\r\n\r\n      <!-- Hint -->\r\n      <div class=\"zic2__hint\" style=\"margin-top: 16px;\">\r\n        <svg width=\"14\" height=\"14\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"\/><path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"\/><path d=\"M12 17h.01\"\/><\/svg>\r\n        <span data-i18n=\"hint\">Copiaz\u0103 link-ul direct din email, mesaj sau bara de adrese a browser-ului.<\/span>\r\n      <\/div>\r\n\r\n      <!-- QR Code Upload -->\r\n      <div class=\"zic2__qrUpload\" style=\"margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--zic-border);\">\r\n        <label style=\"display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--zic-muted); margin-bottom: 8px;\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n            <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"\/>\r\n            <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"\/>\r\n            <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"\/>\r\n            <rect x=\"14\" y=\"14\" width=\"3\" height=\"3\"\/>\r\n            <rect x=\"18\" y=\"14\" width=\"3\" height=\"3\"\/>\r\n            <rect x=\"14\" y=\"18\" width=\"3\" height=\"3\"\/>\r\n            <rect x=\"18\" y=\"18\" width=\"3\" height=\"3\"\/>\r\n          <\/svg>\r\n          <span data-i18n=\"qrLabel\">Sau \u00eencarc\u0103 un cod QR cu un link<\/span>\r\n        <\/label>\r\n        <input type=\"file\" id=\"zic2-qr-upload\" data-field=\"qrUpload\" accept=\"image\/*\" style=\"display: none;\" \/>\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary\" style=\"width: 100%;\" onclick=\"document.getElementById('zic2-qr-upload').click();\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n            <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"\/>\r\n            <polyline points=\"17 8 12 3 7 8\"\/>\r\n            <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"\/>\r\n          <\/svg>\r\n          <span data-i18n=\"qrUploadBtn\">\u00cencarc\u0103 imagine QR<\/span>\r\n        <\/button>\r\n        <div class=\"zic2__qrStatus is-hidden\" data-qr-status style=\"margin-top: 8px; padding: 8px; border-radius: 6px; font-size: 13px;\"><\/div>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- Actions -->\r\n    <div class=\"zic2__actions\">\r\n      <button type=\"button\" class=\"zic2__btn zic2__btn--primary zic2__btn--large\" data-action=\"analyze\">\r\n        <svg width=\"18\" height=\"18\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\">\r\n          <circle cx=\"11\" cy=\"11\" r=\"8\"\/>\r\n          <path d=\"M21 21l-4.35-4.35\"\/>\r\n        <\/svg>\r\n        <span data-i18n=\"btnAnalyze\">Verific\u0103 link<\/span>\r\n      <\/button>\r\n      <button type=\"button\" class=\"zic2__btn zic2__btn--secondary\" data-action=\"reset\">\r\n        <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"\/><path d=\"M3 3v5h5\"\/><\/svg>\r\n        <span data-i18n=\"btnReset\">\u0218terge<\/span>\r\n      <\/button>\r\n      <button type=\"button\" class=\"zic2__btn zic2__btn--success\" data-action=\"example\">\r\n        <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><polyline points=\"14 2 14 8 20 8\"\/><\/svg>\r\n        <span data-i18n=\"btnExample\">Exemplu suspect<\/span>\r\n      <\/button>\r\n    <\/div>\r\n\r\n    <!-- Error -->\r\n    <div class=\"zic2__error is-hidden\" role=\"alert\" aria-live=\"polite\" data-errors><\/div>\r\n\r\n    <!-- Loading Overlay -->\r\n    <div class=\"zic2__loading is-hidden\" data-loading>\r\n      <div class=\"zic2__loadingContent\">\r\n        <div class=\"zic2__loadingSpinner\"><\/div>\r\n        <div class=\"zic2__loadingText\" data-i18n=\"loadingText\">Se verific\u0103 URL-ul...<\/div>\r\n\r\n        <!-- Step-by-step progress indicator -->\r\n        <div class=\"zic2__loadingSteps\" data-loading-steps>\r\n          <div class=\"zic2__loadingStep\" data-step=\"local\">\r\n            <span class=\"zic2__stepIcon\" data-step-icon><\/span>\r\n            <span class=\"zic2__stepText\" data-i18n=\"loadingLocal\">Analiz\u0103 local\u0103<\/span>\r\n          <\/div>\r\n          <div class=\"zic2__loadingStep\" data-step=\"google\">\r\n            <span class=\"zic2__stepIcon\" data-step-icon><\/span>\r\n            <span class=\"zic2__stepText\" data-i18n=\"loadingGoogle\">Google Safe Browsing<\/span>\r\n          <\/div>\r\n          <div class=\"zic2__loadingStep\" data-step=\"virustotal\">\r\n            <span class=\"zic2__stepIcon\" data-step-icon><\/span>\r\n            <span class=\"zic2__stepText\" data-i18n=\"loadingVT\">VirusTotal<\/span>\r\n          <\/div>\r\n          <div class=\"zic2__loadingStep\" data-step=\"urlhaus\">\r\n            <span class=\"zic2__stepIcon\" data-step-icon><\/span>\r\n            <span class=\"zic2__stepText\" data-i18n=\"loadingURLhaus\">URLhaus<\/span>\r\n          <\/div>\r\n          <div class=\"zic2__loadingStep\" data-step=\"urlscan\">\r\n            <span class=\"zic2__stepIcon\" data-step-icon><\/span>\r\n            <span class=\"zic2__stepText\" data-i18n=\"loadingUrlscan\">urlscan.io<\/span>\r\n          <\/div>\r\n          <div class=\"zic2__loadingStep\" data-step=\"phishtank\">\r\n            <span class=\"zic2__stepIcon\" data-step-icon><\/span>\r\n            <span class=\"zic2__stepText\" data-i18n=\"loadingPhishtank\">PhishTank<\/span>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- Progress bar -->\r\n        <div class=\"zic2__loadingProgress\">\r\n          <div class=\"zic2__progressBar\" data-progress-bar><\/div>\r\n        <\/div>\r\n        <div class=\"zic2__loadingPercent\" data-loading-percent>0%<\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Result: Score -->\r\n    <section class=\"zic2__card zic2__scoreCard is-hidden\" data-score-card aria-live=\"polite\">\r\n      <div class=\"zic2__analyzedUrl\" data-analyzed-url><\/div>\r\n      <div class=\"zic2__scoreDisplay\" data-score-display>\r\n        <div class=\"zic2__scoreCircle\" data-score-circle>\r\n          <span class=\"zic2__scoreNumber\" data-score-number>0<\/span>\r\n          <span class=\"zic2__scoreLabel\" data-i18n=\"scoreLabel\">din 100<\/span>\r\n        <\/div>\r\n        <div class=\"zic2__scoreText\" data-score-text><\/div>\r\n        <div class=\"zic2__scoreDesc\" data-score-desc><\/div>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- Result: Analysis Cards -->\r\n    <section class=\"zic2__card is-hidden\" data-checks-card aria-labelledby=\"zic2-sec-checks\">\r\n      <div class=\"zic2__cardHeader\">\r\n        <div class=\"zic2__cardIcon zic2__cardIcon--blue\">\r\n          <svg width=\"18\" height=\"18\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n            <path d=\"M9 11l3 3L22 4\"\/>\r\n            <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"\/>\r\n          <\/svg>\r\n        <\/div>\r\n        <h3 id=\"zic2-sec-checks\" class=\"zic2__cardTitle\" data-i18n=\"resultsTitle\">Rezultate analiz\u0103<\/h3>\r\n      <\/div>\r\n      <div class=\"zic2__checksList\" data-checks-list><\/div>\r\n\r\n      <!-- API Status Indicator -->\r\n      <div class=\"zic2__apiStatus is-hidden\" data-api-status>\r\n        <div class=\"zic2__apiStatusTitle\" data-i18n=\"apiStatusTitle\">Verific\u0103ri externe (5 surse):<\/div>\r\n        <div class=\"zic2__apiStatusList\">\r\n          <span class=\"zic2__apiItem\" data-api=\"google\">\r\n            <span class=\"zic2__apiDot zic2__apiDot--pending\"><\/span>\r\n            Google Safe Browsing\r\n          <\/span>\r\n          <span class=\"zic2__apiItem\" data-api=\"virustotal\">\r\n            <span class=\"zic2__apiDot zic2__apiDot--pending\"><\/span>\r\n            VirusTotal\r\n          <\/span>\r\n          <span class=\"zic2__apiItem\" data-api=\"urlhaus\">\r\n            <span class=\"zic2__apiDot zic2__apiDot--pending\"><\/span>\r\n            URLhaus\r\n          <\/span>\r\n          <span class=\"zic2__apiItem\" data-api=\"urlscan\">\r\n            <span class=\"zic2__apiDot zic2__apiDot--pending\"><\/span>\r\n            urlscan.io\r\n          <\/span>\r\n          <span class=\"zic2__apiItem\" data-api=\"phishtank\">\r\n            <span class=\"zic2__apiDot zic2__apiDot--pending\"><\/span>\r\n            PhishTank\r\n          <\/span>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- Export Buttons -->\r\n      <div class=\"zic2__exportButtons is-hidden\" data-export-buttons>\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary zic2__btn--sm\" data-action=\"exportJSON\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><polyline points=\"14 2 14 8 20 8\"\/><\/svg>\r\n          JSON\r\n        <\/button>\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary zic2__btn--sm\" data-action=\"exportCSV\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><polyline points=\"14 2 14 8 20 8\"\/><\/svg>\r\n          CSV\r\n        <\/button>\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary zic2__btn--sm\" data-action=\"copyResults\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"\/><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"\/><\/svg>\r\n          <span data-i18n=\"copyResults\">Copiaz\u0103<\/span>\r\n        <\/button>\r\n        <span class=\"zic2__exportSep\"><\/span>\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary zic2__btn--sm\" data-action=\"shareLink\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/><\/svg>\r\n          <span data-i18n=\"shareLink\">Copiaz\u0103 link<\/span>\r\n        <\/button>\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary zic2__btn--sm\" data-action=\"printReport\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"6 9 6 2 18 2 18 9\"\/><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"\/><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"\/><\/svg>\r\n          <span data-i18n=\"printReport\">Printeaz\u0103<\/span>\r\n        <\/button>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- Batch Results Table (hidden by default) -->\r\n    <section class=\"zic2__card is-hidden\" data-batch-results aria-labelledby=\"zic2-sec-batch\">\r\n      <div class=\"zic2__cardHeader\">\r\n        <div class=\"zic2__cardIcon zic2__cardIcon--purple\">\r\n          <svg width=\"18\" height=\"18\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n            <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"\/>\r\n            <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"\/>\r\n            <line x1=\"9\" y1=\"21\" x2=\"9\" y2=\"9\"\/>\r\n          <\/svg>\r\n        <\/div>\r\n        <h3 id=\"zic2-sec-batch\" class=\"zic2__cardTitle\" data-i18n=\"batchResultsTitle\">Rezultate batch<\/h3>\r\n      <\/div>\r\n      <div class=\"zic2__batchTable\" data-batch-table>\r\n        <table class=\"zic2__table\">\r\n          <thead>\r\n            <tr>\r\n              <th>#<\/th>\r\n              <th>URL<\/th>\r\n              <th data-i18n=\"batchScore\">Scor<\/th>\r\n              <th data-i18n=\"batchRisk\">Risc<\/th>\r\n              <th data-i18n=\"batchIssues\">Probleme<\/th>\r\n            <\/tr>\r\n          <\/thead>\r\n          <tbody data-batch-tbody><\/tbody>\r\n        <\/table>\r\n      <\/div>\r\n      <!-- Batch Export Buttons -->\r\n      <div class=\"zic2__exportButtons\">\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary zic2__btn--sm\" data-action=\"exportBatchJSON\">\r\n          JSON\r\n        <\/button>\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary zic2__btn--sm\" data-action=\"exportBatchCSV\">\r\n          CSV\r\n        <\/button>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- History Section -->\r\n    <section class=\"zic2__card is-hidden\" data-history-section aria-labelledby=\"zic2-sec-history\">\r\n      <div class=\"zic2__cardHeader\" style=\"cursor: pointer;\" data-action=\"toggleHistory\">\r\n        <div class=\"zic2__cardIcon zic2__cardIcon--purple\">\r\n          <svg width=\"18\" height=\"18\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n            <circle cx=\"12\" cy=\"12\" r=\"10\"\/>\r\n            <polyline points=\"12 6 12 12 16 14\"\/>\r\n          <\/svg>\r\n        <\/div>\r\n        <h3 id=\"zic2-sec-history\" class=\"zic2__cardTitle\" data-i18n=\"historyTitle\">Istoric verific\u0103ri<\/h3>\r\n        <span style=\"margin-left: auto; font-size: 12px; color: var(--zic-text-muted);\" data-history-count><\/span>\r\n      <\/div>\r\n      <div class=\"zic2__historyList\" data-history-list style=\"max-height: 300px; overflow-y: auto;\"><\/div>\r\n      <div style=\"margin-top: 12px; display: flex; gap: 8px;\">\r\n        <button type=\"button\" class=\"zic2__btn zic2__btn--secondary\" data-action=\"clearHistory\" style=\"font-size: 12px; padding: 6px 10px;\">\r\n          <svg width=\"12\" height=\"12\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 6h18\"\/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"\/><\/svg>\r\n          <span data-i18n=\"clearHistory\">\u0218terge istoric<\/span>\r\n        <\/button>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- Show History Button -->\r\n    <div style=\"text-align: center; margin: 16px 0;\">\r\n      <button type=\"button\" class=\"zic2__btn zic2__btn--secondary\" data-action=\"showHistory\" style=\"font-size: 13px;\">\r\n        <svg width=\"14\" height=\"14\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"\/><polyline points=\"12 6 12 12 16 14\"\/><\/svg>\r\n        <span data-i18n=\"viewHistory\">Vezi istoric<\/span>\r\n        <span data-history-badge style=\"background: var(--zic-primary); color: white; padding: 2px 6px; border-radius: 10px; font-size: 11px; margin-left: 4px;\"><\/span>\r\n      <\/button>\r\n    <\/div>\r\n\r\n    <!-- Disclaimer -->\r\n    <div class=\"zic2__disclaimer\">\r\n      <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"\/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"\/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"\/><\/svg>\r\n      <div data-i18n-html=\"disclaimer\">\r\n        <strong>Disclaimer:<\/strong> Aceast\u0103 analiz\u0103 este orientativ\u0103 \u0219i combin\u0103 verific\u0103ri locale cu 5 servicii externe (Google Safe Browsing, VirusTotal, URLhaus, urlscan.io, PhishTank). Nu \u00eenlocuie\u0219te o verificare profesional\u0103 de securitate, precum cea oferit\u0103 de <a href=\"https:\/\/cyberopsnetwork.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">CyberOps Network<\/a> \u2013 partenerii ZIC.legal.\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Interpretation Guide -->\r\n    <section class=\"zic2__guide\" style=\"margin-top: 16px;\">\r\n      <details class=\"zic2__guideDetails\">\r\n        <summary class=\"zic2__guideSummary\">\r\n          <svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n            <circle cx=\"12\" cy=\"12\" r=\"10\"\/>\r\n            <path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"\/>\r\n            <path d=\"M12 17h.01\"\/>\r\n          <\/svg>\r\n          <span data-i18n=\"guideTitle\">Ce \u00eenseamn\u0103 rezultatele?<\/span>\r\n          <svg class=\"zic2__guideChevron\" width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"6 9 12 15 18 9\"\/><\/svg>\r\n        <\/summary>\r\n        <div class=\"zic2__guideContent\">\r\n          <div class=\"zic2__guideSection\">\r\n            <h4 data-i18n=\"guideScoreTitle\">&#x1f4ca; Scorul de \u00eencredere (0-100)<\/h4>\r\n            <ul>\r\n              <li><strong style=\"color: var(--zic-safe);\">80-100:<\/strong> <span data-i18n=\"guideScoreSafe\">Risc sc\u0103zut - link probabil sigur<\/span><\/li>\r\n              <li><strong style=\"color: var(--zic-warning);\">50-79:<\/strong> <span data-i18n=\"guideScoreWarning\">Verificare manual\u0103 recomandat\u0103<\/span><\/li>\r\n              <li><strong style=\"color: var(--zic-danger);\">0-49:<\/strong> <span data-i18n=\"guideScoreDanger\">Risc ridicat - NU accesa!<\/span><\/li>\r\n            <\/ul>\r\n          <\/div>\r\n          <div class=\"zic2__guideSection\">\r\n            <h4 data-i18n=\"guideChecksTitle\">&#x1f50d; Tipuri de verific\u0103ri<\/h4>\r\n            <ul>\r\n              <li><strong data-i18n=\"guideTyposquat\">Typosquatting:<\/strong> <span data-i18n=\"guideTyposquatDesc\">Domeniu care imit\u0103 un brand cunoscut (ex: gooogle.com)<\/span><\/li>\r\n              <li><strong data-i18n=\"guideHttps\">HTTPS:<\/strong> <span data-i18n=\"guideHttpsDesc\">Conexiune securizat\u0103 - lipsa poate indica risc<\/span><\/li>\r\n              <li><strong data-i18n=\"guideUnicode\">Unicode suspect:<\/strong> <span data-i18n=\"guideUnicodeDesc\">Caractere care arat\u0103 ca litere normale dar sunt diferite<\/span><\/li>\r\n              <li><strong data-i18n=\"guideTld\">TLD suspect:<\/strong> <span data-i18n=\"guideTldDesc\">Extensii precum .tk, .xyz, .ml sunt frecvent abuzate<\/span><\/li>\r\n              <li><strong data-i18n=\"guideKeywords\">Cuvinte cheie:<\/strong> <span data-i18n=\"guideKeywordsDesc\">Termeni precum \"login\", \"verify\", \"secure\" \u00een URL-uri suspecte<\/span><\/li>\r\n            <\/ul>\r\n          <\/div>\r\n          <div class=\"zic2__guideSection\">\r\n            <h4 data-i18n=\"guideApisTitle\">&#x1f310; Verific\u0103ri externe<\/h4>\r\n            <ul>\r\n              <li><strong>Google Safe Browsing:<\/strong> <span data-i18n=\"guideGsb\">Baz\u0103 de date Google cu site-uri periculoase<\/span><\/li>\r\n              <li><strong>VirusTotal:<\/strong> <span data-i18n=\"guideVt\">Scanare cu 70+ motoare antivirus<\/span><\/li>\r\n              <li><strong>URLhaus:<\/strong> <span data-i18n=\"guideUrlhaus\">Baz\u0103 de date specialiazat\u0103 \u00een malware<\/span><\/li>\r\n              <li><strong>urlscan.io:<\/strong> <span data-i18n=\"guideUrlscan\">Analiz\u0103 comportamental\u0103 a site-ului<\/span><\/li>\r\n              <li><strong>PhishTank:<\/strong> <span data-i18n=\"guidePhishtank\">Comunitate care raporteaz\u0103 phishing<\/span><\/li>\r\n            <\/ul>\r\n          <\/div>\r\n          <div class=\"zic2__guideSection\">\r\n            <h4 data-i18n=\"guideActionsTitle\">&#x2705; Ce s\u0103 faci<\/h4>\r\n            <ul>\r\n              <li data-i18n=\"guideAction1\">Dac\u0103 scorul e sub 40: NU accesa link-ul<\/li>\r\n              <li data-i18n=\"guideAction2\">Verific\u0103 manual adresa \u00eenainte de a introduce date personale<\/li>\r\n              <li data-i18n=\"guideAction3\">Dac\u0103 ai dubii, contacteaz\u0103 direct organiza\u021bia pe canalele oficiale<\/li>\r\n              <li data-i18n=\"guideAction4\">Raporteaz\u0103 link-urile de phishing la poli\u021bie sau CERT-RO<\/li>\r\n            <\/ul>\r\n          <\/div>\r\n        <\/div>\r\n      <\/details>\r\n    <\/section>\r\n\r\n    <!-- Footer -->\r\n    <footer class=\"zic2__footer\">\r\n      <a href=\"https:\/\/zic.legal\/ro\/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"zic2__footerLink\">\r\n        &copy; 2025 ZIC Legal\r\n      <\/a>\r\n    <\/footer>\r\n  <\/div>\r\n<\/div>\r\n\r\n<style>\r\n\/* ============================================================\r\n   ZIC Calculator v2.1 - Website Spoofing Checker ENHANCED\r\n   Theme: Purple\/Mov | Fully Responsive | Optimized for WPCode\r\n   SECURITY VERSION - All XSS vulnerabilities patched\r\n   ENHANCED: 4 External API Sources with CORS proxy support\r\n   ============================================================ *\/\r\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&display=swap');\r\n\r\n\/* === CSS Variables === *\/\r\n#zic-website-spoofing-v2 {\r\n  --zic-primary: #8980f5;\r\n  --zic-primary-dark: #7370e0;\r\n  --zic-primary-light: rgba(137,128,245,.08);\r\n  --zic-primary-border: rgba(137,128,245,.25);\r\n\r\n  --zic-secondary: #308c97;\r\n  --zic-secondary-light: rgba(48,140,151,.08);\r\n\r\n  --zic-success: #10B981;\r\n  --zic-success-light: rgba(16,185,129,.08);\r\n  --zic-success-border: rgba(16,185,129,.25);\r\n\r\n  --zic-danger: #EF4444;\r\n  --zic-danger-light: rgba(239,68,68,.08);\r\n  --zic-danger-border: rgba(239,68,68,.25);\r\n\r\n  --zic-warning: #F59E0B;\r\n  --zic-warning-light: rgba(245,158,11,.08);\r\n  --zic-warning-border: rgba(245,158,11,.25);\r\n\r\n  --zic-blue: #3B82F6;\r\n  --zic-blue-light: rgba(59,130,246,.08);\r\n  --zic-blue-border: rgba(59,130,246,.25);\r\n\r\n  --zic-ink: #1c1c1c;\r\n  --zic-ink-light: #323232;\r\n  --zic-muted: #5B6370;\r\n  --zic-light: #9CA3AF;\r\n\r\n  --zic-bg: #fcfcfc;\r\n  --zic-surface: #FFFFFF;\r\n  --zic-border: #E5E7EB;\r\n\r\n  --zic-shadow-sm: 0 1px 2px rgba(0,0,0,.05);\r\n  --zic-shadow: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -1px rgba(0,0,0,.06);\r\n  --zic-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -2px rgba(0,0,0,.05);\r\n\r\n  --zic-radius: 16px;\r\n  --zic-radius-sm: 12px;\r\n  --zic-radius-xs: 8px;\r\n\r\n  --zic-transition: 150ms ease;\r\n  --zic-duration-fast: 150ms;\r\n  --zic-duration-normal: 250ms;\r\n  --zic-duration-slow: 400ms;\r\n  --zic-ease-out: cubic-bezier(0.16, 1, 0.3, 1);\r\n\r\n  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n  color: var(--zic-ink);\r\n  line-height: 1.6;\r\n  -webkit-font-smoothing: antialiased;\r\n}\r\n\r\n\/* Respect reduced motion preference *\/\r\n@media (prefers-reduced-motion: reduce) {\r\n  #zic-website-spoofing-v2 *,\r\n  #zic-website-spoofing-v2 *::before,\r\n  #zic-website-spoofing-v2 *::after {\r\n    animation-duration: 0.01ms !important;\r\n    transition-duration: 0.01ms !important;\r\n  }\r\n}\r\n\r\n\/* === Dark Mode (v4.1) === *\/\r\n@media (prefers-color-scheme: dark) {\r\n  #zic-website-spoofing-v2:not([data-theme=\"light\"]) {\r\n    --zic-ink: #f0f0f5;\r\n    --zic-ink-light: #d8d8e8;\r\n    --zic-muted: #9898b0;\r\n    --zic-light: #6a6a80;\r\n\r\n    --zic-bg: #121218;\r\n    --zic-surface: #1e1e2a;\r\n    --zic-border: #2e2e40;\r\n\r\n    --zic-primary-light: rgba(137,128,245,.15);\r\n    --zic-primary-border: rgba(137,128,245,.35);\r\n\r\n    --zic-success-light: rgba(16,185,129,.15);\r\n    --zic-danger-light: rgba(239,68,68,.15);\r\n    --zic-warning-light: rgba(245,158,11,.15);\r\n    --zic-blue-light: rgba(59,130,246,.15);\r\n\r\n    --zic-shadow-sm: 0 1px 2px rgba(0,0,0,.3);\r\n    --zic-shadow: 0 4px 6px -1px rgba(0,0,0,.4), 0 2px 4px -1px rgba(0,0,0,.3);\r\n    --zic-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.5), 0 4px 6px -2px rgba(0,0,0,.4);\r\n  }\r\n}\r\n\r\n\/* Manual dark mode override *\/\r\n#zic-website-spoofing-v2[data-theme=\"dark\"] {\r\n  --zic-ink: #f0f0f5;\r\n  --zic-ink-light: #d8d8e8;\r\n  --zic-muted: #9898b0;\r\n  --zic-light: #6a6a80;\r\n\r\n  --zic-bg: #121218;\r\n  --zic-surface: #1e1e2a;\r\n  --zic-border: #2e2e40;\r\n\r\n  --zic-primary-light: rgba(137,128,245,.15);\r\n  --zic-primary-border: rgba(137,128,245,.35);\r\n\r\n  --zic-success-light: rgba(16,185,129,.15);\r\n  --zic-danger-light: rgba(239,68,68,.15);\r\n  --zic-warning-light: rgba(245,158,11,.15);\r\n  --zic-blue-light: rgba(59,130,246,.15);\r\n\r\n  --zic-shadow-sm: 0 1px 2px rgba(0,0,0,.3);\r\n  --zic-shadow: 0 4px 6px -1px rgba(0,0,0,.4), 0 2px 4px -1px rgba(0,0,0,.3);\r\n  --zic-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.5), 0 4px 6px -2px rgba(0,0,0,.4);\r\n}\r\n\r\n\/* === Accessibility: Skip Link === *\/\r\n#zic-website-spoofing-v2 .zic2__skipLink {\r\n  position: absolute;\r\n  left: -9999px;\r\n  top: auto;\r\n  z-index: 9999;\r\n  padding: 12px 24px;\r\n  background: var(--zic-primary);\r\n  color: #fff;\r\n  font-weight: 600;\r\n  font-size: 14px;\r\n  border-radius: var(--zic-radius-sm);\r\n  text-decoration: none;\r\n  box-shadow: var(--zic-shadow-lg);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__skipLink:focus {\r\n  left: 16px;\r\n  top: 16px;\r\n  outline: 3px solid var(--zic-ink);\r\n  outline-offset: 2px;\r\n}\r\n\r\n\/* === Accessibility: Screen Reader Only === *\/\r\n#zic-website-spoofing-v2 .zic2__srStatus {\r\n  position: absolute;\r\n  width: 1px;\r\n  height: 1px;\r\n  padding: 0;\r\n  margin: -1px;\r\n  overflow: hidden;\r\n  clip: rect(0, 0, 0, 0);\r\n  white-space: nowrap;\r\n  border: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 *,\r\n#zic-website-spoofing-v2 *::before,\r\n#zic-website-spoofing-v2 *::after {\r\n  box-sizing: border-box;\r\n}\r\n\r\n\/* === WordPress\/Avada Override Protection === *\/\r\n#zic-website-spoofing-v2 input[type=\"text\"],\r\n#zic-website-spoofing-v2 input[type=\"url\"] {\r\n  -webkit-appearance: none !important;\r\n  -moz-appearance: none !important;\r\n  appearance: none !important;\r\n  background-image: none !important;\r\n  box-shadow: none !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 button:not(.zic2__btn--primary) {\r\n  background-image: none !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 button {\r\n  text-shadow: none !important;\r\n  letter-spacing: normal !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 h2,\r\n#zic-website-spoofing-v2 h3 {\r\n  text-transform: none !important;\r\n  letter-spacing: normal !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 a {\r\n  text-decoration: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 a:hover {\r\n  text-decoration: underline;\r\n}\r\n\r\n\/* === Layout === *\/\r\n#zic-website-spoofing-v2 .zic2__wrap {\r\n  max-width: 720px;\r\n  margin: 0 auto;\r\n  padding: 16px;\r\n}\r\n\r\n\/* === Header === *\/\r\n#zic-website-spoofing-v2 .zic2__hero {\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__brandbar {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 14px;\r\n  background: linear-gradient(135deg, var(--zic-primary), var(--zic-primary-dark));\r\n  border-radius: var(--zic-radius);\r\n  padding: 20px;\r\n  color: #fff;\r\n  box-shadow: var(--zic-shadow-lg);\r\n  position: relative;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__version {\r\n  position: absolute;\r\n  top: 12px;\r\n  right: 16px;\r\n  background: rgba(255,255,255,.2);\r\n  padding: 4px 10px;\r\n  border-radius: 20px;\r\n  font-size: 11px;\r\n  font-weight: 700;\r\n  letter-spacing: 0.5px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__langBtn {\r\n  position: absolute;\r\n  top: 12px;\r\n  right: 70px;\r\n  background: rgba(255,255,255,.25);\r\n  border: 1px solid rgba(255,255,255,.3);\r\n  padding: 4px 10px;\r\n  border-radius: 20px;\r\n  font-size: 11px;\r\n  font-weight: 700;\r\n  letter-spacing: 0.5px;\r\n  color: #fff;\r\n  cursor: pointer;\r\n  transition: all var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__langBtn:hover {\r\n  background: rgba(255,255,255,.35);\r\n  transform: scale(1.05);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__langBtn:focus-visible {\r\n  outline: 2px solid #fff;\r\n  outline-offset: 2px;\r\n}\r\n\r\n\/* === Theme Toggle Button (v4.1) === *\/\r\n#zic-website-spoofing-v2 .zic2__themeBtn {\r\n  position: absolute;\r\n  top: 12px;\r\n  right: 115px;\r\n  background: rgba(255,255,255,.2);\r\n  border: none;\r\n  border-radius: 8px;\r\n  padding: 8px;\r\n  min-width: 44px;\r\n  min-height: 44px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  color: #fff;\r\n  cursor: pointer;\r\n  transition: all var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeBtn:hover {\r\n  background: rgba(255,255,255,.35);\r\n  transform: scale(1.05);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeBtn:focus-visible {\r\n  outline: 2px solid #fff;\r\n  outline-offset: 2px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeIcon {\r\n  transition: opacity var(--zic-duration-fast) ease, transform var(--zic-duration-fast) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeIcon--moon {\r\n  position: absolute;\r\n  opacity: 0;\r\n  transform: rotate(-90deg);\r\n}\r\n\r\n\/* Dark mode: show moon, hide sun *\/\r\n#zic-website-spoofing-v2[data-theme=\"dark\"] .zic2__themeIcon--sun {\r\n  opacity: 0;\r\n  transform: rotate(90deg);\r\n}\r\n\r\n#zic-website-spoofing-v2[data-theme=\"dark\"] .zic2__themeIcon--moon {\r\n  opacity: 1;\r\n  transform: rotate(0);\r\n}\r\n\r\n\/* Auto dark mode via media query *\/\r\n@media (prefers-color-scheme: dark) {\r\n  #zic-website-spoofing-v2:not([data-theme=\"light\"]) .zic2__themeIcon--sun {\r\n    opacity: 0;\r\n    transform: rotate(90deg);\r\n  }\r\n  #zic-website-spoofing-v2:not([data-theme=\"light\"]) .zic2__themeIcon--moon {\r\n    opacity: 1;\r\n    transform: rotate(0);\r\n  }\r\n}\r\n\r\n\/* === Touch Targets & Checkbox (v4.1 - WCAG 2.5.5) === *\/\r\n#zic-website-spoofing-v2 .zic2__batchToggle {\r\n  margin-bottom: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkboxLabel {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 10px;\r\n  padding: 10px 12px;\r\n  margin: -10px -12px;\r\n  cursor: pointer;\r\n  font-size: 14px;\r\n  border-radius: var(--zic-radius-xs);\r\n  transition: background-color var(--zic-duration-fast) ease;\r\n  min-height: 44px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkboxLabel:hover {\r\n  background: var(--zic-primary-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkbox {\r\n  appearance: none;\r\n  -webkit-appearance: none;\r\n  width: 22px;\r\n  height: 22px;\r\n  border: 2px solid var(--zic-border);\r\n  border-radius: 6px;\r\n  background: var(--zic-surface);\r\n  cursor: pointer;\r\n  transition: all var(--zic-duration-fast) ease;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkbox:checked {\r\n  background: var(--zic-primary);\r\n  border-color: var(--zic-primary);\r\n  background-image: url(\"data:image\/svg+xml,%3Csvg viewBox='0 0 16 16' fill='white' xmlns='http:\/\/www.w3.org\/2000\/svg'%3E%3Cpath d='M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 111.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z'\/%3E%3C\/svg%3E\");\r\n  background-size: 14px;\r\n  background-repeat: no-repeat;\r\n  background-position: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkbox:focus-visible {\r\n  outline: 3px solid var(--zic-primary);\r\n  outline-offset: 2px;\r\n  box-shadow: 0 0 0 6px rgba(137,128,245,.15);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkboxText {\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__mark {\r\n  width: 48px;\r\n  height: 48px;\r\n  background: rgba(255,255,255,.2);\r\n  border-radius: 12px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__headerText {\r\n  flex: 1;\r\n  min-width: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__title {\r\n  margin: 0;\r\n  font-size: 20px;\r\n  font-weight: 700;\r\n  line-height: 1.2;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__subtitle {\r\n  margin: 4px 0 0;\r\n  font-size: 14px;\r\n  opacity: 0.9;\r\n}\r\n\r\n\/* === Formula Box === *\/\r\n#zic-website-spoofing-v2 .zic2__formula {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 10px;\r\n  background: var(--zic-primary-light);\r\n  border: 1px solid var(--zic-primary-border);\r\n  border-radius: var(--zic-radius-sm);\r\n  padding: 12px 14px;\r\n  margin-bottom: 16px;\r\n  font-size: 14px;\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__formulaIcon {\r\n  color: var(--zic-primary-dark);\r\n  flex-shrink: 0;\r\n  margin-top: 1px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__formulaText strong {\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Cards === *\/\r\n#zic-website-spoofing-v2 .zic2__card {\r\n  background: var(--zic-surface);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius);\r\n  padding: 20px;\r\n  margin-bottom: 16px;\r\n  box-shadow: var(--zic-shadow-sm);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardHeader {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 12px;\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon {\r\n  width: 36px;\r\n  height: 36px;\r\n  border-radius: 10px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--purple {\r\n  background: var(--zic-primary-light);\r\n  color: var(--zic-primary-dark);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--green {\r\n  background: var(--zic-success-light);\r\n  color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--warning {\r\n  background: var(--zic-warning-light);\r\n  color: var(--zic-warning);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--blue {\r\n  background: var(--zic-blue-light);\r\n  color: var(--zic-blue);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--danger {\r\n  background: var(--zic-danger-light);\r\n  color: var(--zic-danger);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardTitle {\r\n  margin: 0;\r\n  font-size: 17px;\r\n  font-weight: 700;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Form Elements === *\/\r\n#zic-website-spoofing-v2 .zic2__field {\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 4px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__label {\r\n  font-size: 12px;\r\n  font-weight: 600;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input {\r\n  width: 100%;\r\n  padding: 14px 16px;\r\n  font-size: 15px;\r\n  color: var(--zic-ink);\r\n  background: var(--zic-surface);\r\n  border: 2px solid var(--zic-border);\r\n  border-radius: var(--zic-radius-xs);\r\n  outline: none;\r\n  transition: border-color var(--zic-transition), box-shadow var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input:focus {\r\n  border-color: var(--zic-primary);\r\n  box-shadow: 0 0 0 3px var(--zic-primary-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input:focus-visible {\r\n  outline: 3px solid var(--zic-primary);\r\n  outline-offset: 2px;\r\n  box-shadow: 0 0 0 6px rgba(137,128,245,.15);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input::placeholder {\r\n  color: var(--zic-light);\r\n}\r\n\r\n\/* === Buttons === *\/\r\n#zic-website-spoofing-v2 .zic2__actions {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 10px;\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__actions .zic2__btn--primary {\r\n  flex: 1;\r\n  min-width: 200px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  gap: 6px;\r\n  padding: 10px 16px;\r\n  font-size: 14px;\r\n  font-weight: 600;\r\n  border-radius: var(--zic-radius-sm);\r\n  border: 1px solid transparent;\r\n  cursor: pointer;\r\n  transition: all var(--zic-transition);\r\n  white-space: nowrap;\r\n  text-decoration: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:focus {\r\n  box-shadow: 0 0 0 3px var(--zic-primary-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:focus-visible {\r\n  outline: 3px solid var(--zic-primary);\r\n  outline-offset: 2px;\r\n  box-shadow: 0 0 0 6px rgba(137,128,245,.2);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:active {\r\n  transform: translateY(1px);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--primary {\r\n  background: linear-gradient(135deg, var(--zic-primary), var(--zic-primary-dark));\r\n  color: #fff;\r\n  box-shadow: 0 4px 14px rgba(138,136,255,.35);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--primary:hover {\r\n  box-shadow: 0 6px 20px rgba(138,136,255,.45);\r\n  transform: translateY(-1px);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--large {\r\n  padding: 14px 24px;\r\n  font-size: 15px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--secondary {\r\n  background: var(--zic-surface);\r\n  border-color: var(--zic-border);\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--secondary:hover {\r\n  background: var(--zic-bg);\r\n  border-color: var(--zic-primary-border);\r\n  color: var(--zic-primary-dark);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--sm {\r\n  font-size: 13px;\r\n  padding: 10px 14px;\r\n  min-height: 44px;\r\n  gap: 6px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__exportButtons {\r\n  margin-top: 16px;\r\n  padding-top: 16px;\r\n  border-top: 1px solid var(--zic-primary-border);\r\n  display: flex;\r\n  gap: 10px;\r\n  flex-wrap: wrap;\r\n  align-items: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__exportSep {\r\n  width: 1px;\r\n  height: 24px;\r\n  background: var(--zic-border);\r\n  margin: 0 4px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn.is-success {\r\n  background: var(--zic-success-light);\r\n  border-color: var(--zic-success);\r\n  color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__sharedNote {\r\n  background: var(--zic-warning-light);\r\n  border: 1px solid var(--zic-warning);\r\n  border-radius: var(--zic-radius);\r\n  padding: 12px 16px;\r\n  margin-bottom: 16px;\r\n  font-size: 13px;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Batch Table (v4.1) === *\/\r\n#zic-website-spoofing-v2 .zic2__batchTable {\r\n  overflow-x: auto;\r\n  margin-top: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table {\r\n  width: 100%;\r\n  border-collapse: collapse;\r\n  font-size: 13px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table thead tr {\r\n  background: var(--zic-primary-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table th {\r\n  padding: 10px;\r\n  text-align: left;\r\n  border-bottom: 2px solid var(--zic-primary-border);\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table th:nth-child(3),\r\n#zic-website-spoofing-v2 .zic2__table th:nth-child(4) {\r\n  text-align: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table td {\r\n  padding: 10px;\r\n  border-bottom: 1px solid var(--zic-border);\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table td:nth-child(2) {\r\n  max-width: 300px;\r\n  overflow: hidden;\r\n  text-overflow: ellipsis;\r\n  white-space: nowrap;\r\n  font-family: monospace;\r\n  font-size: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table td:nth-child(3),\r\n#zic-website-spoofing-v2 .zic2__table td:nth-child(4) {\r\n  text-align: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--success {\r\n  background: var(--zic-warning-light);\r\n  border-color: var(--zic-warning-border);\r\n  color: #92400E;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--success:hover {\r\n  background: rgba(245,158,11,.15);\r\n}\r\n\r\n\/* === Hint === *\/\r\n#zic-website-spoofing-v2 .zic2__hint {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 8px;\r\n  padding: 10px 12px;\r\n  background: var(--zic-bg);\r\n  border-radius: var(--zic-radius-xs);\r\n  font-size: 12px;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__hint svg {\r\n  flex-shrink: 0;\r\n  margin-top: 1px;\r\n}\r\n\r\n\/* === Error === *\/\r\n#zic-website-spoofing-v2 .zic2__error {\r\n  margin-bottom: 16px;\r\n  padding: 12px;\r\n  background: var(--zic-danger-light);\r\n  border: 1px solid var(--zic-danger-border);\r\n  border-radius: var(--zic-radius-xs);\r\n  color: var(--zic-danger);\r\n  font-size: 13px;\r\n  font-weight: 500;\r\n}\r\n\r\n\/* === Score Card === *\/\r\n#zic-website-spoofing-v2 .zic2__scoreCard {\r\n  padding: 0;\r\n  overflow: hidden;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__analyzedUrl {\r\n  background: var(--zic-bg);\r\n  padding: 12px 20px;\r\n  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\r\n  font-size: 13px;\r\n  color: var(--zic-ink-light);\r\n  word-break: break-all;\r\n  border-bottom: 1px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay {\r\n  text-align: center;\r\n  padding: 30px 20px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay.score-safe {\r\n  background: linear-gradient(135deg, rgba(16,185,129,.05), rgba(16,185,129,.12));\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay.score-warning {\r\n  background: linear-gradient(135deg, rgba(245,158,11,.05), rgba(245,158,11,.12));\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay.score-danger {\r\n  background: linear-gradient(135deg, rgba(239,68,68,.05), rgba(239,68,68,.12));\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle {\r\n  width: 100px;\r\n  height: 100px;\r\n  border-radius: 50%;\r\n  display: inline-flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n  justify-content: center;\r\n  color: white;\r\n  font-weight: bold;\r\n  margin-bottom: 16px;\r\n  box-shadow: 0 4px 15px rgba(0,0,0,.2);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle.score-safe {\r\n  background: linear-gradient(135deg, #11998e, #38ef7d);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle.score-warning {\r\n  background: linear-gradient(135deg, #F59E0B, #FBBF24);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle.score-danger {\r\n  background: linear-gradient(135deg, #cb2d3e, #ef473a);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreNumber {\r\n  font-size: 32px;\r\n  line-height: 1;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreLabel {\r\n  font-size: 11px;\r\n  opacity: 0.9;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreText {\r\n  font-size: 20px;\r\n  font-weight: 700;\r\n  margin-bottom: 5px;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDesc {\r\n  font-size: 14px;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n\/* === Checks List === *\/\r\n#zic-website-spoofing-v2 .zic2__checksList {\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 8px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 12px;\r\n  padding: 14px;\r\n  background: var(--zic-bg);\r\n  border-radius: var(--zic-radius-xs);\r\n  border-left: 4px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-pass {\r\n  border-left-color: var(--zic-success);\r\n  background: var(--zic-success-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-fail {\r\n  border-left-color: var(--zic-danger);\r\n  background: var(--zic-danger-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-warn {\r\n  border-left-color: var(--zic-warning);\r\n  background: var(--zic-warning-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkIcon {\r\n  width: 24px;\r\n  height: 24px;\r\n  border-radius: 50%;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  flex-shrink: 0;\r\n  font-size: 12px;\r\n  font-weight: 700;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-pass .zic2__checkIcon {\r\n  background: var(--zic-success);\r\n  color: white;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-fail .zic2__checkIcon {\r\n  background: var(--zic-danger);\r\n  color: white;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-warn .zic2__checkIcon {\r\n  background: var(--zic-warning);\r\n  color: white;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkContent {\r\n  flex: 1;\r\n  min-width: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkTitle {\r\n  font-weight: 600;\r\n  font-size: 14px;\r\n  color: var(--zic-ink);\r\n  margin-bottom: 2px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkDesc {\r\n  font-size: 13px;\r\n  color: var(--zic-ink-light);\r\n  line-height: 1.4;\r\n}\r\n\r\n\/* === Disclaimer === *\/\r\n#zic-website-spoofing-v2 .zic2__disclaimer {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 10px;\r\n  padding: 14px;\r\n  background: var(--zic-bg);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius-sm);\r\n  font-size: 12px;\r\n  color: var(--zic-muted);\r\n  line-height: 1.5;\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__disclaimer svg {\r\n  flex-shrink: 0;\r\n  color: var(--zic-warning);\r\n  margin-top: 1px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__disclaimer strong {\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n\/* === Interpretation Guide === *\/\r\n#zic-website-spoofing-v2 .zic2__guideDetails {\r\n  background: var(--zic-surface);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius-sm);\r\n  overflow: hidden;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSummary {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 8px;\r\n  padding: 12px 16px;\r\n  cursor: pointer;\r\n  font-size: 14px;\r\n  font-weight: 500;\r\n  color: var(--zic-ink-light);\r\n  background: var(--zic-bg);\r\n  list-style: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSummary::-webkit-details-marker {\r\n  display: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSummary svg:first-child {\r\n  color: var(--zic-primary);\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideChevron {\r\n  margin-left: auto;\r\n  transition: transform var(--zic-duration-fast) ease;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideDetails[open] .zic2__guideChevron {\r\n  transform: rotate(180deg);\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n  #zic-website-spoofing-v2 .zic2__guideChevron {\r\n    transition: none;\r\n  }\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideContent {\r\n  padding: 16px;\r\n  border-top: 1px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection {\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection:last-child {\r\n  margin-bottom: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection h4 {\r\n  font-size: 14px;\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n  margin: 0 0 8px 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection ul {\r\n  margin: 0;\r\n  padding-left: 20px;\r\n  font-size: 13px;\r\n  line-height: 1.6;\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection li {\r\n  margin-bottom: 4px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection strong {\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Footer === *\/\r\n#zic-website-spoofing-v2 .zic2__footer {\r\n  text-align: center;\r\n  padding: 8px 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__footerLink {\r\n  color: var(--zic-primary-dark);\r\n  text-decoration: none;\r\n  font-size: 13px;\r\n  font-weight: 600;\r\n  transition: color var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__footerLink:hover {\r\n  color: var(--zic-primary);\r\n  text-decoration: underline;\r\n}\r\n\r\n\/* === Utility === *\/\r\n#zic-website-spoofing-v2 .is-hidden {\r\n  display: none !important;\r\n}\r\n\r\n\/* === Loading Spinner === *\/\r\n@keyframes zic-spin {\r\n  0% { transform: rotate(0deg); }\r\n  100% { transform: rotate(360deg); }\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__spinner {\r\n  animation: zic-spin 1s linear infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:disabled {\r\n  opacity: 0.7;\r\n  cursor: not-allowed;\r\n  transform: none !important;\r\n}\r\n\r\n\/* === API Status Indicator === *\/\r\n#zic-website-spoofing-v2 .zic2__apiStatus {\r\n  margin-top: 16px;\r\n  padding-top: 16px;\r\n  border-top: 1px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiStatusTitle {\r\n  font-size: 12px;\r\n  font-weight: 600;\r\n  color: var(--zic-muted);\r\n  margin-bottom: 8px;\r\n  text-transform: uppercase;\r\n  letter-spacing: 0.5px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiStatusList {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiItem {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 6px;\r\n  font-size: 13px;\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot {\r\n  width: 8px;\r\n  height: 8px;\r\n  border-radius: 50%;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--pending {\r\n  background-color: var(--zic-light);\r\n  animation: zic-pulse 1.5s ease-in-out infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--success {\r\n  background-color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--error {\r\n  background-color: var(--zic-danger);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--warning {\r\n  background-color: var(--zic-warning);\r\n}\r\n\r\n@keyframes zic-pulse {\r\n  0%, 100% { opacity: 1; }\r\n  50% { opacity: 0.4; }\r\n}\r\n\r\n\/* === RESPONSIVE === *\/\r\n@media (min-width: 640px) {\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    padding: 24px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 24px;\r\n  }\r\n}\r\n\r\n@media (min-width: 768px) {\r\n  #zic-website-spoofing-v2 .zic2__card {\r\n    padding: 24px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__brandbar {\r\n    padding: 24px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__mark {\r\n    width: 56px;\r\n    height: 56px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 26px;\r\n  }\r\n}\r\n\r\n\/* Large screens (1024px+) *\/\r\n@media (min-width: 1024px) {\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    max-width: 900px;\r\n  }\r\n}\r\n\r\n@media (max-width: 500px) {\r\n  #zic-website-spoofing-v2 .zic2__actions {\r\n    flex-direction: column;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__actions .zic2__btn {\r\n    width: 100%;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__apiStatusList {\r\n    flex-direction: column;\r\n    gap: 8px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle {\r\n    width: 80px;\r\n    height: 80px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreNumber {\r\n    font-size: 26px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreLabel {\r\n    font-size: 10px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 18px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__subtitle {\r\n    font-size: 13px;\r\n  }\r\n}\r\n\r\n\/* Large phones (501-639px) - fills responsive gap *\/\r\n@media (min-width: 501px) and (max-width: 639px) {\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    padding: 20px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__card {\r\n    padding: 20px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 20px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle {\r\n    width: 90px;\r\n    height: 90px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreNumber {\r\n    font-size: 28px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__apiStatusList {\r\n    flex-wrap: wrap;\r\n    gap: 10px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__apiStatus {\r\n    flex: 1 1 calc(50% - 5px);\r\n    min-width: 140px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__checkItem {\r\n    padding: 14px 16px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__loadingStep {\r\n    font-size: 13px;\r\n  }\r\n}\r\n\r\n\/* Print styles *\/\r\n@media print {\r\n  \/* Hide interactive elements *\/\r\n  #zic-website-spoofing-v2 .zic2__actions,\r\n  #zic-website-spoofing-v2 .zic2__hint,\r\n  #zic-website-spoofing-v2 .zic2__footer,\r\n  #zic-website-spoofing-v2 .zic2__loading,\r\n  #zic-website-spoofing-v2 .zic2__langBtn,\r\n  #zic-website-spoofing-v2 .zic2__themeBtn,\r\n  #zic-website-spoofing-v2 .zic2__history,\r\n  #zic-website-spoofing-v2 .zic2__qrWrapper,\r\n  #zic-website-spoofing-v2 .zic2__exportWrapper,\r\n  #zic-website-spoofing-v2 [data-action],\r\n  #zic-website-spoofing-v2 .zic2__batchMode {\r\n    display: none !important;\r\n  }\r\n\r\n  \/* Reset backgrounds for print *\/\r\n  #zic-website-spoofing-v2 {\r\n    background: white !important;\r\n    color: #111 !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    max-width: 100% !important;\r\n    padding: 0 !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__card {\r\n    box-shadow: none !important;\r\n    border: 1px solid #ccc !important;\r\n    break-inside: avoid;\r\n    background: white !important;\r\n    margin-bottom: 16px;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__brandbar {\r\n    background: white !important;\r\n    border-bottom: 2px solid #111 !important;\r\n    padding: 16px 0 !important;\r\n  }\r\n\r\n  \/* Print header *\/\r\n  #zic-website-spoofing-v2 .zic2__brandbar::before {\r\n    content: \"Raport Verificare Website - ZIC.legal\";\r\n    display: block;\r\n    font-size: 10px;\r\n    color: #666;\r\n    text-transform: uppercase;\r\n    letter-spacing: 1px;\r\n    margin-bottom: 8px;\r\n  }\r\n\r\n  \/* Show timestamp on results *\/\r\n  #zic-website-spoofing-v2 .zic2__scoreCard::after {\r\n    content: \"Generat: \" attr(data-print-timestamp);\r\n    display: block;\r\n    font-size: 11px;\r\n    color: #666;\r\n    margin-top: 16px;\r\n    padding-top: 8px;\r\n    border-top: 1px solid #eee;\r\n  }\r\n\r\n  \/* Preserve colors for score circle *\/\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle {\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle.score-safe {\r\n    background: var(--zic-success) !important;\r\n    color: white !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle.score-warning {\r\n    background: var(--zic-warning) !important;\r\n    color: white !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle.score-danger {\r\n    background: var(--zic-danger) !important;\r\n    color: white !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  \/* Preserve status colors *\/\r\n  #zic-website-spoofing-v2 .zic2__checkItem,\r\n  #zic-website-spoofing-v2 .zic2__apiStatus {\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  \/* Expand all results details *\/\r\n  #zic-website-spoofing-v2 .zic2__checkItem details {\r\n    display: block !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__checkItem details[open] summary ~ * {\r\n    display: block !important;\r\n  }\r\n\r\n  \/* Input field styling for print *\/\r\n  #zic-website-spoofing-v2 .zic2__input {\r\n    border: 1px solid #ccc !important;\r\n    background: #f9f9f9 !important;\r\n  }\r\n\r\n  \/* Disclaimer visibility *\/\r\n  #zic-website-spoofing-v2 .zic2__disclaimer {\r\n    border: 1px solid #ddd !important;\r\n    background: #f5f5f5 !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  \/* Page breaks *\/\r\n  #zic-website-spoofing-v2 .zic2__scoreCard {\r\n    break-before: avoid;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__checkList {\r\n    break-inside: avoid;\r\n  }\r\n}\r\n\r\n\/* === Loading Overlay === *\/\r\n#zic-website-spoofing-v2 .zic2__loading {\r\n  background: var(--zic-surface);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius);\r\n  padding: 40px 20px;\r\n  margin-bottom: 16px;\r\n  box-shadow: var(--zic-shadow);\r\n  text-align: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingContent {\r\n  display: flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n  gap: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingSpinner {\r\n  width: 48px;\r\n  height: 48px;\r\n  border: 4px solid var(--zic-border);\r\n  border-top-color: var(--zic-primary);\r\n  border-radius: 50%;\r\n  animation: zic-spin 1s linear infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingText {\r\n  font-size: 18px;\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingSubtext {\r\n  font-size: 14px;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n\/* === Loading Steps Indicator (v4.1) === *\/\r\n#zic-website-spoofing-v2 .zic2__loadingSteps {\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 8px;\r\n  margin-top: 8px;\r\n  text-align: left;\r\n  width: 100%;\r\n  max-width: 260px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 10px;\r\n  font-size: 13px;\r\n  color: var(--zic-muted);\r\n  transition: color var(--zic-duration-fast) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-active {\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-done {\r\n  color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-failed {\r\n  color: var(--zic-danger);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-timeout {\r\n  color: var(--zic-warning);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__stepIcon {\r\n  width: 18px;\r\n  height: 18px;\r\n  border-radius: 50%;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  font-size: 10px;\r\n  font-weight: 700;\r\n  flex-shrink: 0;\r\n  background: var(--zic-border);\r\n  color: var(--zic-muted);\r\n  transition: all var(--zic-duration-fast) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-active .zic2__stepIcon {\r\n  background: var(--zic-primary-light);\r\n  border: 2px solid var(--zic-primary);\r\n  animation: zic-pulse 1s ease-in-out infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-done .zic2__stepIcon {\r\n  background: var(--zic-success);\r\n  color: #fff;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-failed .zic2__stepIcon {\r\n  background: var(--zic-danger);\r\n  color: #fff;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-timeout .zic2__stepIcon {\r\n  background: var(--zic-warning);\r\n  color: #fff;\r\n}\r\n\r\n\/* Progress bar *\/\r\n#zic-website-spoofing-v2 .zic2__loadingProgress {\r\n  width: 100%;\r\n  max-width: 260px;\r\n  height: 6px;\r\n  background: var(--zic-border);\r\n  border-radius: 3px;\r\n  margin-top: 12px;\r\n  overflow: hidden;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__progressBar {\r\n  height: 100%;\r\n  width: 0%;\r\n  background: linear-gradient(90deg, var(--zic-primary), var(--zic-success));\r\n  border-radius: 3px;\r\n  transition: width var(--zic-duration-normal) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingPercent {\r\n  font-size: 14px;\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n  margin-top: 4px;\r\n}\r\n\r\n\/* Reduced motion *\/\r\n@media (prefers-reduced-motion: reduce) {\r\n  #zic-website-spoofing-v2 .zic2__loadingStep.is-active .zic2__stepIcon {\r\n    animation: none;\r\n  }\r\n}\r\n<\/style>\r\n\r\n<!-- jsQR Library for QR Code Scanning -->\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/jsqr@1.4.0\/dist\/jsQR.min.js\"><\/script>\r\n\r\n<script>\r\n(function() {\r\n  'use strict';\r\n\r\n  const ROOT_ID = 'zic-website-spoofing-v2';\r\n  const root = document.getElementById(ROOT_ID);\r\n  if (!root) return;\r\n\r\n  \/\/ === INTERNATIONALIZATION (i18n) ===\r\n  const LANG = {\r\n    ro: {\r\n      \/\/ Header\r\n      title: 'Verificare website spoofing',\r\n      subtitle: 'Detecteaz\u0103 link-uri suspecte \u0219i tentative de phishing',\r\n      langSwitch: 'EN',\r\n      \/\/ Formula\r\n      formula: '<strong>Cum func\u021bioneaz\u0103:<\/strong> Analiz\u0103m URL-ul pentru typosquatting, caractere Unicode suspecte, extensii de domeniu riscante \u0219i alte indicii de phishing. Verific\u0103m suplimentar prin <strong>5 surse externe<\/strong>: Google Safe Browsing, VirusTotal, URLhaus, urlscan.io \u0219i PhishTank.',\r\n      \/\/ Input\r\n      inputTitle: 'Link de verificat',\r\n      inputLabel: 'Introdu link-ul website-ului',\r\n      inputPlaceholder: 'https:\/\/example.com',\r\n      hint: 'Copiaz\u0103 link-ul direct din email, mesaj sau bara de adrese a browser-ului.',\r\n      \/\/ QR Code\r\n      qrLabel: 'Sau \u00eencarc\u0103 un cod QR cu un link',\r\n      qrUploadBtn: '\u00cencarc\u0103 imagine QR',\r\n      \/\/ Buttons\r\n      btnAnalyze: 'Verific\u0103 link',\r\n      btnAnalyzing: 'Se verific\u0103...',\r\n      btnReset: '\u0218terge',\r\n      btnExample: 'Exemplu suspect',\r\n      \/\/ Loading\r\n      loadingText: 'Se verific\u0103 URL-ul...',\r\n      loadingSub: 'Interog\u0103m 5 baze de date de securitate',\r\n      loadingLocal: 'Analiz\u0103 local\u0103',\r\n      loadingGoogle: 'Google Safe Browsing',\r\n      loadingVT: 'VirusTotal',\r\n      loadingURLhaus: 'URLhaus',\r\n      loadingUrlscan: 'urlscan.io',\r\n      loadingPhishtank: 'PhishTank',\r\n      \/\/ Results\r\n      scoreLabel: 'din 100',\r\n      resultsTitle: 'Rezultate analiz\u0103',\r\n      apiStatusTitle: 'Verific\u0103ri externe (5 surse):',\r\n      \/\/ Score texts\r\n      scoreSafe: 'Risc sc\u0103zut',\r\n      scoreWarning: 'Aten\u021bie necesar\u0103',\r\n      scoreDanger: 'Risc ridicat',\r\n      descSafe: 'Link-ul pare a fi legitim. Nu s-au detectat semne de phishing.',\r\n      descWarning: 'Au fost detectate unele probleme. Verific\u0103 manual \u00eenainte de a accesa.',\r\n      descDanger: 'Multiple semne de fraudare detectate. Nu accesa acest link!',\r\n      \/\/ Disclaimer\r\n      disclaimer: '<strong>Disclaimer:<\/strong> Aceast\u0103 analiz\u0103 este orientativ\u0103 \u0219i combin\u0103 verific\u0103ri locale cu 5 servicii externe (Google Safe Browsing, VirusTotal, URLhaus, urlscan.io, PhishTank). Nu \u00eenlocuie\u0219te o verificare profesional\u0103 de securitate, precum cea oferit\u0103 de <a href=\"https:\/\/cyberopsnetwork.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">CyberOps Network<\/a> \u2013 partenerii ZIC.legal.',\r\n      \/\/ Errors\r\n      errorEmpty: 'Te rug\u0103m s\u0103 introduci un link pentru verificare.',\r\n      errorTooLong: 'URL-ul este prea lung. Limita este de {max} caractere.',\r\n      errorDangerous: 'URL-ul con\u021bine caractere sau scheme periculoase.',\r\n      errorInvalid: 'Link-ul introdus nu este valid. Te rug\u0103m verific\u0103 formatul.',\r\n      errorGeneral: 'A ap\u0103rut o eroare la analiz\u0103. V\u0103 rug\u0103m \u00eencerca\u021bi din nou.',\r\n      \/\/ Check results\r\n      checkHttpsPass: 'Conexiune HTTPS',\r\n      checkHttpsPassDesc: 'Site-ul folose\u0219te protocol securizat HTTPS.',\r\n      checkHttpsFail: 'Lips\u0103 HTTPS',\r\n      checkHttpsFailDesc: 'Site-ul nu folose\u0219te HTTPS. Datele nu sunt criptate!',\r\n      checkUnicodePass: 'Caractere legitime',\r\n      checkUnicodePassDesc: 'Nu s-au detectat caractere Unicode suspecte \u00een domeniu.',\r\n      checkUnicodeFail: 'Caractere Unicode suspecte',\r\n      checkUnicodeFailDesc: 'Domeniul con\u021bine caractere care imit\u0103 litere latine. Forma real\u0103: \"{domain}\"',\r\n      \/\/ API results\r\n      googleOk: 'Google Safe Browsing: OK',\r\n      googleOkDesc: 'URL-ul nu este raportat \u00een baza de date Google.',\r\n      googleFail: 'Google Safe Browsing: PERICOL',\r\n      googleFailDesc: 'Google a detectat: {threats}. NU accesa\u021bi acest link!',\r\n      vtOk: 'VirusTotal: curat',\r\n      vtOkDesc: 'Niciun motor antivirus nu a detectat amenin\u021b\u0103ri.',\r\n      vtFail: 'VirusTotal: DETEC\u021aII',\r\n      vtFailDesc: '{count} motoare antivirus au detectat amenin\u021b\u0103ri.',\r\n      urlhausOk: 'URLhaus: curat',\r\n      urlhausOkDesc: 'URL-ul nu apare \u00een baza de date URLhaus.',\r\n      urlhausFail: 'URLhaus: MALWARE',\r\n      urlhausFailDesc: 'URL-ul este \u00een baza de date URLhaus. Tip: {threat}.',\r\n      urlscanOk: 'urlscan.io: OK',\r\n      urlscanOkDesc: 'Nicio amenin\u021bare detectat\u0103{scans}.',\r\n      urlscanFail: 'urlscan.io: SUSPECT',\r\n      urlscanFailDesc: 'Domeniul a fost marcat ca mali\u021bios. Verdicts: {verdicts}',\r\n      phishtankOk: 'PhishTank: OK',\r\n      phishtankOkDesc: 'URL-ul nu este \u00een baza de date PhishTank (Cisco Talos).',\r\n      phishtankFail: 'PhishTank: PHISHING CONFIRMAT',\r\n      phishtankFailDesc: 'URL-ul este \u00een baza de date PhishTank ca site de phishing verificat!',\r\n      \/\/ Local checks\r\n      typosquatTitle: 'Typosquatting detectat',\r\n      typosquatDouble: 'Typosquatting prin litere duble',\r\n      typosquatVisual: 'Typosquatting vizual',\r\n      typosquatSubst: 'Typosquatting prin substitu\u021bie',\r\n      typosquatHyphen: 'Brand fragmentat cu cratime',\r\n      typosquatKeyboard: 'Eroare tastare detectat\u0103',\r\n      typosquatSimilarity: 'Similaritate suspect\u0103',\r\n      typosquatRepetition: 'Litere repetate',\r\n      typosquatOmission: 'Caracter lips\u0103',\r\n      typosquatTransposition: 'Litere inversate',\r\n      typosquatVowelSwap: 'Vocale substituite',\r\n      typosquatDesc: 'Domeniul seam\u0103n\u0103 suspect cu brandul \"{brand}\".',\r\n      brandWrongTld: 'Brand pe TLD gre\u0219it',\r\n      brandOk: 'Brand recunoscut',\r\n      brandOkDesc: 'Domeniul corespunde unui brand cunoscut.',\r\n      noTyposquat: 'F\u0103r\u0103 typosquatting detectat',\r\n      noTyposquatDesc: 'Domeniul nu pare s\u0103 imite branduri cunoscute.',\r\n      suspiciousTld: 'Extensie domeniu suspect\u0103',\r\n      suspiciousTldDesc: 'Domeniul folose\u0219te o extensie frecvent asociat\u0103 cu site-uri frauduloase.',\r\n      tldOk: 'Extensie domeniu OK',\r\n      tldOkDesc: 'Extensia domeniului nu ridic\u0103 suspiciuni.',\r\n      multiSubdomain: 'Subdomain-uri multiple',\r\n      multiSubdomainDesc: 'Domeniul are {count} subdomain-uri.',\r\n      subdomainOk: 'Structur\u0103 domeniu normal\u0103',\r\n      subdomainOkDesc: 'Num\u0103rul de subdomain-uri este normal.',\r\n      phishKeywords: 'Cuvinte cheie phishing',\r\n      phishKeywordsDesc: 'URL-ul con\u021bine termeni suspec\u021bi: \"{keywords}\"',\r\n      sensitiveTerm: 'Termen sensibil \u00een URL',\r\n      sensitiveTermDesc: 'URL-ul con\u021bine termenul \"{keyword}\".',\r\n      noSuspiciousTerms: 'URL f\u0103r\u0103 termeni suspec\u021bi',\r\n      noSuspiciousTermsDesc: 'Nu s-au detectat cuvinte cheie asociate cu phishing.',\r\n      longDomain: 'Domeniu foarte lung',\r\n      longDomainDesc: 'Domeniul are {length} caractere.',\r\n      domainLengthOk: 'Lungime domeniu OK',\r\n      domainLengthOkDesc: 'Lungimea domeniului este normal\u0103.',\r\n      ipAddress: 'Adres\u0103 IP \u00een loc de domeniu',\r\n      ipAddressDesc: 'URL-ul folose\u0219te o adres\u0103 IP direct\u0103.',\r\n      nonStandardPort: 'Port non-standard',\r\n      nonStandardPortDesc: 'URL-ul folose\u0219te portul {port}.',\r\n      idnDomain: 'Domeniu interna\u021bional (IDN\/Punycode)',\r\n      idnDomainDesc: 'Domeniul folose\u0219te caractere interna\u021bionale codificate.',\r\n      unusualChars: 'Caractere neobi\u0219nuite',\r\n      unusualCharsDesc: 'Domeniul con\u021bine caractere speciale neobi\u0219nuite.',\r\n      brandInSubdomain: 'Brand \u00een subdomain',\r\n      brandInSubdomainDesc: 'Un brand cunoscut apare \u00een subdomain dar nu \u00een domeniul principal.',\r\n      \/\/ Interpretation Guide\r\n      guideTitle: 'Ce \u00eenseamn\u0103 rezultatele?',\r\n      guideScoreTitle: '&#x1f4ca; Scorul de \u00eencredere (0-100)',\r\n      guideScoreSafe: 'Risc sc\u0103zut - link probabil sigur',\r\n      guideScoreWarning: 'Verificare manual\u0103 recomandat\u0103',\r\n      guideScoreDanger: 'Risc ridicat - NU accesa!',\r\n      guideChecksTitle: '&#x1f50d; Tipuri de verific\u0103ri',\r\n      guideTyposquat: 'Typosquatting:',\r\n      guideTyposquatDesc: 'Domeniu care imit\u0103 un brand cunoscut (ex: gooogle.com)',\r\n      guideHttps: 'HTTPS:',\r\n      guideHttpsDesc: 'Conexiune securizat\u0103 - lipsa poate indica risc',\r\n      guideUnicode: 'Unicode suspect:',\r\n      guideUnicodeDesc: 'Caractere care arat\u0103 ca litere normale dar sunt diferite',\r\n      guideTld: 'TLD suspect:',\r\n      guideTldDesc: 'Extensii precum .tk, .xyz, .ml sunt frecvent abuzate',\r\n      guideKeywords: 'Cuvinte cheie:',\r\n      guideKeywordsDesc: 'Termeni precum \"login\", \"verify\", \"secure\" \u00een URL-uri suspecte',\r\n      guideApisTitle: '&#x1f310; Verific\u0103ri externe',\r\n      guideGsb: 'Baz\u0103 de date Google cu site-uri periculoase',\r\n      guideVt: 'Scanare cu 70+ motoare antivirus',\r\n      guideUrlhaus: 'Baz\u0103 de date specializat\u0103 \u00een malware',\r\n      guideUrlscan: 'Analiz\u0103 comportamental\u0103 a site-ului',\r\n      guidePhishtank: 'Comunitate care raporteaz\u0103 phishing',\r\n      guideActionsTitle: '&#x2705; Ce s\u0103 faci',\r\n      guideAction1: 'Dac\u0103 scorul e sub 40: NU accesa link-ul',\r\n      guideAction2: 'Verific\u0103 manual adresa \u00eenainte de a introduce date personale',\r\n      guideAction3: 'Dac\u0103 ai dubii, contacteaz\u0103 direct organiza\u021bia pe canalele oficiale',\r\n      guideAction4: 'Raporteaz\u0103 link-urile de phishing la poli\u021bie sau CERT-RO',\r\n      \/\/ Theme\r\n      themeLight: 'Comut\u0103 pe mod luminos',\r\n      themeDark: 'Comut\u0103 pe mod \u00eentunecat',\r\n      \/\/ Share\r\n      shareLink: 'Copiaz\u0103 link',\r\n      shareLinkCopied: 'Link copiat!',\r\n      printReport: 'Printeaz\u0103',\r\n      \/\/ Batch\r\n      batchTruncated: 'Doar primele {count} URL-uri din {total} vor fi procesate.'\r\n    },\r\n    en: {\r\n      \/\/ Header\r\n      title: 'Website spoofing check',\r\n      subtitle: 'Detect suspicious links and phishing attempts',\r\n      langSwitch: 'RO',\r\n      \/\/ Formula\r\n      formula: '<strong>How it works:<\/strong> We analyse the URL for typosquatting, suspicious Unicode characters, risky domain extensions, and other phishing indicators. We additionally verify through <strong>5 external sources<\/strong>: Google Safe Browsing, VirusTotal, URLhaus, urlscan.io, and PhishTank.',\r\n      \/\/ Input\r\n      inputTitle: 'Link to check',\r\n      inputLabel: 'Enter the website link',\r\n      inputPlaceholder: 'https:\/\/example.com',\r\n      hint: 'Copy the link directly from email, message, or browser address bar.',\r\n      \/\/ QR Code\r\n      qrLabel: 'Or upload a QR code with a link',\r\n      qrUploadBtn: 'Upload QR image',\r\n      \/\/ Buttons\r\n      btnAnalyze: 'Check link',\r\n      btnAnalyzing: 'Checking...',\r\n      btnReset: 'Clear',\r\n      btnExample: 'Suspicious example',\r\n      \/\/ Loading\r\n      loadingText: 'Checking URL...',\r\n      loadingSub: 'Querying 5 security databases',\r\n      loadingLocal: 'Local analysis',\r\n      loadingGoogle: 'Google Safe Browsing',\r\n      loadingVT: 'VirusTotal',\r\n      loadingURLhaus: 'URLhaus',\r\n      loadingUrlscan: 'urlscan.io',\r\n      loadingPhishtank: 'PhishTank',\r\n      \/\/ Results\r\n      scoreLabel: 'out of 100',\r\n      resultsTitle: 'Analysis results',\r\n      apiStatusTitle: 'External checks (5 sources):',\r\n      \/\/ Score texts\r\n      scoreSafe: 'Low risk',\r\n      scoreWarning: 'Caution required',\r\n      scoreDanger: 'High risk',\r\n      descSafe: 'The link appears to be legitimate. No signs of phishing detected.',\r\n      descWarning: 'Some issues detected. Verify manually before accessing.',\r\n      descDanger: 'Multiple fraud signs detected. Do not access this link!',\r\n      \/\/ Disclaimer\r\n      disclaimer: '<strong>Disclaimer:<\/strong> This analysis is indicative and combines local checks with 5 external services (Google Safe Browsing, VirusTotal, URLhaus, urlscan.io, PhishTank). It does not replace a professional security assessment, such as that offered by <a href=\"https:\/\/cyberopsnetwork.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">CyberOps Network<\/a> \u2013 ZIC.legal partners.',\r\n      \/\/ Errors\r\n      errorEmpty: 'Please enter a link to check.',\r\n      errorTooLong: 'URL is too long. Maximum is {max} characters.',\r\n      errorDangerous: 'URL contains dangerous characters or schemes.',\r\n      errorInvalid: 'The entered link is not valid. Please check the format.',\r\n      errorGeneral: 'An error occurred during analysis. Please try again.',\r\n      \/\/ Check results\r\n      checkHttpsPass: 'HTTPS connection',\r\n      checkHttpsPassDesc: 'The site uses secure HTTPS protocol.',\r\n      checkHttpsFail: 'Missing HTTPS',\r\n      checkHttpsFailDesc: 'The site does not use HTTPS. Data is not encrypted!',\r\n      checkUnicodePass: 'Legitimate characters',\r\n      checkUnicodePassDesc: 'No suspicious Unicode characters detected in domain.',\r\n      checkUnicodeFail: 'Suspicious Unicode characters',\r\n      checkUnicodeFailDesc: 'The domain contains characters mimicking Latin letters. Real form: \"{domain}\"',\r\n      \/\/ API results\r\n      googleOk: 'Google Safe Browsing: OK',\r\n      googleOkDesc: 'URL is not reported in Google database.',\r\n      googleFail: 'Google Safe Browsing: DANGER',\r\n      googleFailDesc: 'Google detected: {threats}. DO NOT access this link!',\r\n      vtOk: 'VirusTotal: clean',\r\n      vtOkDesc: 'No antivirus engine detected threats.',\r\n      vtFail: 'VirusTotal: DETECTIONS',\r\n      vtFailDesc: '{count} antivirus engines detected threats.',\r\n      urlhausOk: 'URLhaus: clean',\r\n      urlhausOkDesc: 'URL is not in URLhaus database.',\r\n      urlhausFail: 'URLhaus: MALWARE',\r\n      urlhausFailDesc: 'URL is in URLhaus database. Type: {threat}.',\r\n      urlscanOk: 'urlscan.io: OK',\r\n      urlscanOkDesc: 'No threats detected{scans}.',\r\n      urlscanFail: 'urlscan.io: SUSPECT',\r\n      urlscanFailDesc: 'Domain was marked as malicious. Verdicts: {verdicts}',\r\n      phishtankOk: 'PhishTank: OK',\r\n      phishtankOkDesc: 'URL is not in PhishTank database (Cisco Talos).',\r\n      phishtankFail: 'PhishTank: PHISHING CONFIRMED',\r\n      phishtankFailDesc: 'URL is in PhishTank database as verified phishing site!',\r\n      \/\/ Local checks\r\n      typosquatTitle: 'Typosquatting detected',\r\n      typosquatDouble: 'Double letter typosquatting',\r\n      typosquatVisual: 'Visual typosquatting',\r\n      typosquatSubst: 'Substitution typosquatting',\r\n      typosquatHyphen: 'Hyphen-fragmented brand',\r\n      typosquatKeyboard: 'Keyboard typo detected',\r\n      typosquatSimilarity: 'Suspicious similarity',\r\n      typosquatRepetition: 'Repeated letters',\r\n      typosquatOmission: 'Missing character',\r\n      typosquatTransposition: 'Swapped letters',\r\n      typosquatVowelSwap: 'Vowel substitution',\r\n      typosquatDesc: 'Domain suspiciously resembles the brand \"{brand}\".',\r\n      brandWrongTld: 'Brand on wrong TLD',\r\n      brandOk: 'Recognised brand',\r\n      brandOkDesc: 'Domain corresponds to a known brand.',\r\n      noTyposquat: 'No typosquatting detected',\r\n      noTyposquatDesc: 'Domain does not appear to mimic known brands.',\r\n      suspiciousTld: 'Suspicious domain extension',\r\n      suspiciousTldDesc: 'Domain uses an extension frequently associated with fraudulent sites.',\r\n      tldOk: 'Domain extension OK',\r\n      tldOkDesc: 'Domain extension does not raise suspicions.',\r\n      multiSubdomain: 'Multiple subdomains',\r\n      multiSubdomainDesc: 'Domain has {count} subdomains.',\r\n      subdomainOk: 'Normal domain structure',\r\n      subdomainOkDesc: 'Number of subdomains is normal.',\r\n      phishKeywords: 'Phishing keywords',\r\n      phishKeywordsDesc: 'URL contains suspicious terms: \"{keywords}\"',\r\n      sensitiveTerm: 'Sensitive term in URL',\r\n      sensitiveTermDesc: 'URL contains the term \"{keyword}\".',\r\n      noSuspiciousTerms: 'URL without suspicious terms',\r\n      noSuspiciousTermsDesc: 'No keywords associated with phishing detected.',\r\n      longDomain: 'Very long domain',\r\n      longDomainDesc: 'Domain has {length} characters.',\r\n      domainLengthOk: 'Domain length OK',\r\n      domainLengthOkDesc: 'Domain length is normal.',\r\n      ipAddress: 'IP address instead of domain',\r\n      ipAddressDesc: 'URL uses a direct IP address.',\r\n      nonStandardPort: 'Non-standard port',\r\n      nonStandardPortDesc: 'URL uses port {port}.',\r\n      idnDomain: 'International domain (IDN\/Punycode)',\r\n      idnDomainDesc: 'Domain uses encoded international characters.',\r\n      unusualChars: 'Unusual characters',\r\n      unusualCharsDesc: 'Domain contains unusual special characters.',\r\n      brandInSubdomain: 'Brand in subdomain',\r\n      brandInSubdomainDesc: 'A known brand appears in subdomain but not in main domain.',\r\n      \/\/ Interpretation Guide\r\n      guideTitle: 'What do the results mean?',\r\n      guideScoreTitle: '&#x1f4ca; Trust Score (0-100)',\r\n      guideScoreSafe: 'Low risk - link is probably safe',\r\n      guideScoreWarning: 'Manual verification recommended',\r\n      guideScoreDanger: 'High risk - DO NOT access!',\r\n      guideChecksTitle: '&#x1f50d; Types of checks',\r\n      guideTyposquat: 'Typosquatting:',\r\n      guideTyposquatDesc: 'Domain that mimics a known brand (e.g., gooogle.com)',\r\n      guideHttps: 'HTTPS:',\r\n      guideHttpsDesc: 'Secure connection - absence may indicate risk',\r\n      guideUnicode: 'Suspicious Unicode:',\r\n      guideUnicodeDesc: 'Characters that look like normal letters but are different',\r\n      guideTld: 'Suspicious TLD:',\r\n      guideTldDesc: 'Extensions like .tk, .xyz, .ml are frequently abused',\r\n      guideKeywords: 'Keywords:',\r\n      guideKeywordsDesc: 'Terms like \"login\", \"verify\", \"secure\" in suspicious URLs',\r\n      guideApisTitle: '&#x1f310; External checks',\r\n      guideGsb: 'Google database of dangerous sites',\r\n      guideVt: 'Scan with 70+ antivirus engines',\r\n      guideUrlhaus: 'Database specialized in malware',\r\n      guideUrlscan: 'Behavioral analysis of the site',\r\n      guidePhishtank: 'Community reporting phishing',\r\n      guideActionsTitle: '&#x2705; What to do',\r\n      guideAction1: 'If score is below 40: DO NOT access the link',\r\n      guideAction2: 'Manually verify the address before entering personal data',\r\n      guideAction3: 'If in doubt, contact the organization directly through official channels',\r\n      guideAction4: 'Report phishing links to police or your local CERT',\r\n      \/\/ Theme\r\n      themeLight: 'Switch to light mode',\r\n      themeDark: 'Switch to dark mode',\r\n      \/\/ Share\r\n      shareLink: 'Copy link',\r\n      shareLinkCopied: 'Link copied!',\r\n      printReport: 'Print',\r\n      \/\/ Batch\r\n      batchTruncated: 'Only the first {count} of {total} URLs will be processed.'\r\n    }\r\n  };\r\n\r\n  \/\/ Detect browser language, default to Romanian\r\n  let currentLang = navigator.language.startsWith('ro') ? 'ro' : 'en';\r\n\r\n  \/\/ Get translation\r\n  function t(key, replacements = {}) {\r\n    let text = LANG[currentLang][key] || LANG['ro'][key] || key;\r\n    for (const [placeholder, value] of Object.entries(replacements)) {\r\n      text = text.replace('{' + placeholder + '}', value);\r\n    }\r\n    return text;\r\n  }\r\n\r\n  \/\/ Apply translations to all elements with data-i18n attributes\r\n  function applyTranslations() {\r\n    \/\/ Text content\r\n    root.querySelectorAll('[data-i18n]').forEach(el => {\r\n      const key = el.getAttribute('data-i18n');\r\n      if (LANG[currentLang][key]) {\r\n        el.textContent = LANG[currentLang][key];\r\n      }\r\n    });\r\n    \/\/ HTML content\r\n    root.querySelectorAll('[data-i18n-html]').forEach(el => {\r\n      const key = el.getAttribute('data-i18n-html');\r\n      if (LANG[currentLang][key]) {\r\n        el.innerHTML = LANG[currentLang][key];\r\n      }\r\n    });\r\n    \/\/ Placeholders\r\n    root.querySelectorAll('[data-i18n-placeholder]').forEach(el => {\r\n      const key = el.getAttribute('data-i18n-placeholder');\r\n      if (LANG[currentLang][key]) {\r\n        el.placeholder = LANG[currentLang][key];\r\n      }\r\n    });\r\n  }\r\n\r\n  \/\/ Toggle language\r\n  function toggleLanguage() {\r\n    currentLang = currentLang === 'ro' ? 'en' : 'ro';\r\n    applyTranslations();\r\n  }\r\n\r\n  \/\/ === THEME MANAGEMENT ===\r\n  const THEME_KEY = 'zic-theme';\r\n  const themeBtn = root.querySelector('[data-action=\"toggleTheme\"]');\r\n\r\n  \/\/ Detect system preference\r\n  function getSystemTheme() {\r\n    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n  }\r\n\r\n  \/\/ Get current theme (stored > system)\r\n  function getCurrentTheme() {\r\n    return localStorage.getItem(THEME_KEY) || null;\r\n  }\r\n\r\n  \/\/ Apply theme to root element\r\n  function applyTheme(theme) {\r\n    if (theme) {\r\n      root.setAttribute('data-theme', theme);\r\n    } else {\r\n      root.removeAttribute('data-theme');\r\n    }\r\n    updateThemeButton(theme || getSystemTheme());\r\n  }\r\n\r\n  \/\/ Update button aria-label and pressed state\r\n  function updateThemeButton(activeTheme) {\r\n    if (!themeBtn) return;\r\n    const isDark = activeTheme === 'dark';\r\n    themeBtn.setAttribute('aria-pressed', isDark.toString());\r\n    themeBtn.setAttribute('aria-label', t(isDark ? 'themeLight' : 'themeDark'));\r\n  }\r\n\r\n  \/\/ Toggle between themes\r\n  function toggleTheme() {\r\n    const current = getCurrentTheme();\r\n    const systemTheme = getSystemTheme();\r\n    let newTheme;\r\n\r\n    if (current === null) {\r\n      \/\/ No preference stored, switch from system default\r\n      newTheme = systemTheme === 'dark' ? 'light' : 'dark';\r\n    } else {\r\n      \/\/ Toggle stored preference\r\n      newTheme = current === 'dark' ? 'light' : 'dark';\r\n    }\r\n\r\n    localStorage.setItem(THEME_KEY, newTheme);\r\n    applyTheme(newTheme);\r\n  }\r\n\r\n  \/\/ Listen for system theme changes\r\n  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {\r\n    \/\/ Only react if no manual override stored\r\n    if (!getCurrentTheme()) {\r\n      updateThemeButton(e.matches ? 'dark' : 'light');\r\n    }\r\n  });\r\n\r\n  \/\/ Initialize theme on load\r\n  applyTheme(getCurrentTheme());\r\n\r\n  \/\/ === CSS VARIABLE HELPERS ===\r\n  function getCssVar(name) {\r\n    return getComputedStyle(root).getPropertyValue('--zic-' + name).trim();\r\n  }\r\n\r\n  function getRiskColors() {\r\n    return {\r\n      safe: getCssVar('success'),\r\n      warning: getCssVar('warning'),\r\n      danger: getCssVar('danger')\r\n    };\r\n  }\r\n\r\n  \/\/ === SECURITY: Maximum input length to prevent DoS ===\r\n  const MAX_URL_LENGTH = 2048;\r\n\r\n  \/\/ === SECURITY: Rate limiting to prevent abuse ===\r\n  let lastAnalysisTime = 0;\r\n  const MIN_ANALYSIS_INTERVAL = 500;\r\n\r\n  \/\/ === SCORE THRESHOLDS ===\r\n  const SCORE_THRESHOLDS = {\r\n    safe: 80,      \/\/ 80-100 = risc sc\u0103zut\r\n    warning: 50    \/\/ 50-79 = aten\u021bie, 0-49 = pericol\r\n  };\r\n\r\n  \/\/ === BATCH LIMIT ===\r\n  const BATCH_LIMIT = 10;\r\n\r\n  \/\/ === Cloudflare Worker Proxy pentru API-uri fara CORS ===\r\n  \/\/ IMPORTANT: Inlocuieste cu URL-ul tau de Cloudflare Worker dupa deploy!\r\n  \/\/ Exemplu: 'https:\/\/zic-security-proxy.YOUR-SUBDOMAIN.workers.dev'\r\n  const CLOUDFLARE_PROXY = 'https:\/\/zic-security-proxy.red-tooth-f5c5.workers.dev';\r\n\r\n  \/\/ === API CONFIGURATION ===\r\n  \/\/ SECURITATE: Toate API keys sunt acum \u00een Cloudflare Worker (backend)\r\n  \/\/ Nu mai sunt expuse \u00een codul client\r\n  const API_CONFIG = {\r\n    \/\/ Google Safe Browsing API - prin Cloudflare Worker proxy (API key \u00een backend)\r\n    GOOGLE_SAFE_BROWSING: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ VirusTotal API - prin Cloudflare Worker proxy\r\n    VIRUSTOTAL: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ IPQualityScore API - prin Cloudflare Worker proxy\r\n    IPQUALITYSCORE: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ URLhaus - prin Cloudflare Worker proxy\r\n    URLHAUS: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ urlscan.io - prin Cloudflare Worker proxy\r\n    URLSCAN: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ PhishTank - prin Cloudflare Worker proxy\r\n    PHISHTANK: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ PhishStats - DEZACTIVAT (server down\/timeout)\r\n    PHISHSTATS: {\r\n      enabled: false,\r\n      useProxy: true\r\n    },\r\n    \/\/ === NOI VERIFIC\u0102RI v3 ===\r\n    \/\/ DNS Analysis - verific\u0103 DNS records\r\n    DNS: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ GeoIP - loca\u021bia serverului\r\n    GEOIP: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ WHOIS - v\u00e2rsta domeniului\r\n    WHOIS: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ SSL Certificate validation\r\n    SSL: {\r\n      enabled: true,\r\n      useProxy: true\r\n    }\r\n  };\r\n\r\n  \/\/ === SECURITY: HTML Entity Encoding ===\r\n  function escapeHtml(text) {\r\n    if (typeof text !== 'string') return '';\r\n    const map = {\r\n      '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;',\r\n      \"'\": '&#039;', '\/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;'\r\n    };\r\n    return text.replace(\/[&<>\"'`=\\\/]\/g, s => map[s]);\r\n  }\r\n\r\n  \/\/ === ACCESSIBILITY: Screen Reader Announcements ===\r\n  function announceToSR(message, priority = 'polite') {\r\n    const srContainer = root.querySelector('[data-sr-status]');\r\n    if (!srContainer) return;\r\n    srContainer.setAttribute('aria-live', priority);\r\n    srContainer.textContent = '';\r\n    \/\/ Force reflow for announcement\r\n    requestAnimationFrame(() => {\r\n      srContainer.textContent = message;\r\n    });\r\n  }\r\n\r\n  function sanitizeInput(input) {\r\n    if (typeof input !== 'string') return '';\r\n    return input.replace(\/\\0\/g, '').replace(\/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]\/g, '').trim().substring(0, MAX_URL_LENGTH);\r\n  }\r\n\r\n  function validateStatus(status) {\r\n    const allowedStatuses = ['pass', 'warn', 'fail'];\r\n    return allowedStatuses.includes(status) ? status : 'warn';\r\n  }\r\n\r\n  function containsDangerousPatterns(url) {\r\n    if (typeof url !== 'string') return true;\r\n    const dangerousPatterns = [\/^javascript:\/i, \/^data:\/i, \/^vbscript:\/i, \/^file:\/i, \/&#\/, \/%00\/, \/\\x00\/];\r\n    return dangerousPatterns.some(pattern => pattern.test(url));\r\n  }\r\n\r\n  const $ = (sel) => root.querySelector(sel);\r\n\r\n  const elements = {\r\n    urlInput: $('[data-field=\"urlInput\"]'),\r\n    errors: $('[data-errors]'),\r\n    scoreCard: $('[data-score-card]'),\r\n    analyzedUrl: $('[data-analyzed-url]'),\r\n    scoreDisplay: $('[data-score-display]'),\r\n    scoreCircle: $('[data-score-circle]'),\r\n    scoreNumber: $('[data-score-number]'),\r\n    scoreText: $('[data-score-text]'),\r\n    scoreDesc: $('[data-score-desc]'),\r\n    checksCard: $('[data-checks-card]'),\r\n    checksList: $('[data-checks-list]'),\r\n    apiStatus: $('[data-api-status]'),\r\n    loading: $('[data-loading]'),\r\n    apiGoogle: $('[data-api=\"google\"]'),\r\n    apiVirusTotal: $('[data-api=\"virustotal\"]'),\r\n    apiURLhaus: $('[data-api=\"urlhaus\"]'),\r\n    apiUrlscan: $('[data-api=\"urlscan\"]'),\r\n    apiPhishTank: $('[data-api=\"phishtank\"]'),\r\n    \/\/ Batch mode elements\r\n    batchMode: $('[data-field=\"batchMode\"]'),\r\n    singleInput: $('[data-single-input]'),\r\n    batchInput: $('[data-batch-input]'),\r\n    urlBatch: $('[data-field=\"urlBatch\"]'),\r\n    batchResults: $('[data-batch-results]'),\r\n    batchTbody: $('[data-batch-tbody]'),\r\n    exportButtons: $('[data-export-buttons]'),\r\n    \/\/ History elements\r\n    historySection: $('[data-history-section]'),\r\n    historyList: $('[data-history-list]'),\r\n    historyCount: $('[data-history-count]'),\r\n    historyBadge: $('[data-history-badge]'),\r\n    \/\/ QR Code elements\r\n    qrUpload: $('[data-field=\"qrUpload\"]'),\r\n    qrStatus: $('[data-qr-status]')\r\n  };\r\n\r\n  \/\/ Store last analysis for export\r\n  let lastAnalysis = null;\r\n  let lastBatchResults = [];\r\n\r\n  \/\/ === Loading Steps Tracking (v4.1) ===\r\n  const LOADING_STEPS = ['local', 'google', 'virustotal', 'urlhaus', 'urlscan', 'phishtank'];\r\n  let completedSteps = 0;\r\n\r\n  function updateLoadingStep(stepName, status) {\r\n    const stepEl = root.querySelector('[data-step=\"' + stepName + '\"]');\r\n    if (!stepEl) return;\r\n\r\n    const icon = stepEl.querySelector('[data-step-icon]');\r\n    stepEl.classList.remove('is-active', 'is-done', 'is-failed', 'is-timeout');\r\n\r\n    switch (status) {\r\n      case 'checking':\r\n        stepEl.classList.add('is-active');\r\n        if (icon) icon.textContent = '';\r\n        break;\r\n      case 'done':\r\n        stepEl.classList.add('is-done');\r\n        if (icon) icon.textContent = '\u2713';\r\n        completedSteps++;\r\n        updateLoadingProgress();\r\n        break;\r\n      case 'failed':\r\n        stepEl.classList.add('is-failed');\r\n        if (icon) icon.textContent = '\u2715';\r\n        completedSteps++;\r\n        updateLoadingProgress();\r\n        break;\r\n      case 'timeout':\r\n        stepEl.classList.add('is-timeout');\r\n        if (icon) icon.textContent = '!';\r\n        completedSteps++;\r\n        updateLoadingProgress();\r\n        break;\r\n    }\r\n  }\r\n\r\n  function updateLoadingProgress() {\r\n    const progressBar = root.querySelector('[data-progress-bar]');\r\n    const percentEl = root.querySelector('[data-loading-percent]');\r\n    const percent = Math.round((completedSteps \/ LOADING_STEPS.length) * 100);\r\n\r\n    if (progressBar) progressBar.style.width = percent + '%';\r\n    if (percentEl) percentEl.textContent = percent + '%';\r\n  }\r\n\r\n  function resetLoadingSteps() {\r\n    completedSteps = 0;\r\n    LOADING_STEPS.forEach(function(step) {\r\n      const stepEl = root.querySelector('[data-step=\"' + step + '\"]');\r\n      if (stepEl) {\r\n        stepEl.classList.remove('is-active', 'is-done', 'is-failed', 'is-timeout');\r\n        const icon = stepEl.querySelector('[data-step-icon]');\r\n        if (icon) icon.textContent = '';\r\n      }\r\n    });\r\n    updateLoadingProgress();\r\n  }\r\n\r\n  function updateApiStatus(apiElement, status) {\r\n    if (!apiElement) return;\r\n    const dot = apiElement.querySelector('.zic2__apiDot');\r\n    if (!dot) return;\r\n    dot.className = 'zic2__apiDot';\r\n    dot.classList.add('zic2__apiDot--' + status);\r\n  }\r\n\r\n  function resetApiStatus() {\r\n    updateApiStatus(elements.apiGoogle, 'pending');\r\n    updateApiStatus(elements.apiVirusTotal, 'pending');\r\n    updateApiStatus(elements.apiURLhaus, 'pending');\r\n    updateApiStatus(elements.apiUrlscan, 'pending');\r\n    updateApiStatus(elements.apiPhishTank, 'pending');\r\n  }\r\n\r\n  \/\/ === Known Brands Database ===\r\n  const knownBrands = Object.freeze([\r\n    'google', 'facebook', 'amazon', 'apple', 'microsoft', 'netflix', 'paypal',\r\n    'instagram', 'twitter', 'linkedin', 'whatsapp', 'telegram', 'yahoo', 'outlook',\r\n    'dropbox', 'adobe', 'spotify', 'uber', 'airbnb', 'booking', 'ebay', 'alibaba',\r\n    'walmart', 'target', 'bestbuy', 'costco', 'ikea', 'samsung', 'sony',\r\n    'chase', 'bankofamerica', 'wellsfargo', 'citibank', 'capitalone', 'americanexpress',\r\n    'visa', 'mastercard', 'stripe', 'venmo', 'coinbase', 'binance', 'blockchain',\r\n    'dhl', 'fedex', 'ups', 'usps', 'hbo', 'disney',\r\n    'youtube', 'tiktok', 'snapchat', 'pinterest', 'reddit', 'twitch', 'discord',\r\n    'zoom', 'slack', 'github', 'gitlab', 'wordpress', 'shopify', 'cloudflare', 'godaddy',\r\n    'bancatransilvania', 'btrl', 'raiffeisen', 'raiffeisenbank', 'bcr', 'brd', 'ing', 'ingbank',\r\n    'unicredit', 'cec', 'cecbank', 'alphabank', 'otpbank', 'otp', 'libra', 'librabank',\r\n    'garanti', 'intesa', 'firstbank', 'patria', 'patriabank', 'crediteurope', 'exim', 'eximbank',\r\n    'revolut', 'wise', 'tradeville', 'bvb',\r\n    'emag', 'altex', 'pcgarage', 'evomag', 'cel', 'mediagalaxy', 'flanco', 'domo', 'dedeman',\r\n    'leroy', 'leroymerlin', 'jysk', 'mobexpert', 'vivre', 'bonami', 'elefant', 'libris',\r\n    'carturesti', 'pepita', 'notino', 'douglas', 'sephora', 'fashiondays', 'aboutyou',\r\n    'answear', 'modivo', 'epantofi', 'sportisimo', 'decathlon', 'intersport', 'hervis',\r\n    'olx', 'publi24', 'autovit', 'storia', 'imobiliare', 'lajumate',\r\n    'orange', 'vodafone', 'digi', 'rcs', 'telekom', 'cosmote', 'enel', 'engie', 'eon',\r\n    'electrica', 'hidroelectrica', 'delgaz', 'distrigaz', 'apanova',\r\n    'fancourier', 'cargus', 'sameday', 'dpd', 'gls', 'urgentcargus', 'postaromana',\r\n    'cfr', 'tarom', 'wizz', 'wizzair', 'blueair', 'ryanair', 'flixbus',\r\n    'anaf', 'ghiseul', 'rovinieta', 'drpciv', 'cnas', 'ajofm', 'onrc', 'efactura', 'roalert',\r\n    'tazz', 'foodpanda', 'glovo', 'bolt', 'kaufland', 'lidl', 'carrefour', 'auchan',\r\n    'mega', 'megaimage', 'profi', 'penny', 'cora', 'selgros', 'metro',\r\n    'payu', 'netopia', 'mobilpay', 'smartbill', 'oblio', 'facturis', 'gomag'\r\n  ]);\r\n\r\n  \/\/ === ENHANCED HOMOGLYPH DATABASE v4.0 ===\r\n  \/\/ Covers: Cyrillic, Greek, Armenian, Math Alphanumeric, Fullwidth, Common substitutions\r\n  const homoglyphs = Object.freeze({\r\n    \/\/ Cyrillic lookalikes\r\n    '\\u0430': 'a', '\\u0435': 'e', '\\u043e': 'o', '\\u0440': 'p', '\\u0441': 'c', '\\u0445': 'x', '\\u0443': 'y',\r\n    '\\u0456': 'i', '\\u0458': 'j', '\\u0455': 's', '\\u0501': 'd', '\\u0261': 'g', '\\u0578': 'n', '\\u057d': 'u',\r\n    '\\u04bd': 'e', '\\u0432': 'b', '\\u043d': 'h', '\\u043a': 'k', '\\u043c': 'm', '\\u0442': 't',\r\n    '\\u0410': 'a', '\\u0412': 'b', '\\u0415': 'e', '\\u041a': 'k', '\\u041c': 'm', '\\u041d': 'h',\r\n    '\\u041e': 'o', '\\u0420': 'p', '\\u0421': 'c', '\\u0422': 't', '\\u0425': 'x', '\\u0443': 'y',\r\n    \/\/ Greek lookalikes\r\n    '\\u03b1': 'a', '\\u03b2': 'b', '\\u03b5': 'e', '\\u03b7': 'n', '\\u03b9': 'i', '\\u03ba': 'k',\r\n    '\\u03bd': 'v', '\\u03bf': 'o', '\\u03c1': 'p', '\\u03c3': 'o', '\\u03c4': 't', '\\u03c5': 'u',\r\n    '\\u03c7': 'x', '\\u03c9': 'w', '\\u0391': 'a', '\\u0392': 'b', '\\u0395': 'e', '\\u0397': 'h',\r\n    '\\u0399': 'i', '\\u039a': 'k', '\\u039c': 'm', '\\u039d': 'n', '\\u039f': 'o', '\\u03a1': 'p',\r\n    '\\u03a4': 't', '\\u03a7': 'x', '\\u03a5': 'y', '\\u03a9': 'w',\r\n    \/\/ Armenian lookalikes\r\n    '\\u0561': 'a', '\\u0562': 'b', '\\u0565': 'e', '\\u0568': 'n', '\\u056b': 'h', '\\u0570': 'h',\r\n    '\\u0571': 'j', '\\u0575': 'n', '\\u0578': 'n', '\\u057a': 'n', '\\u057c': 'o', '\\u057d': 'u',\r\n    \/\/ Math alphanumeric (script, bold, italic variants)\r\n    '\\u{1D41A}': 'a', '\\u{1D41B}': 'b', '\\u{1D41C}': 'c', '\\u{1D41D}': 'd', '\\u{1D41E}': 'e',\r\n    '\\u{1D41F}': 'f', '\\u{1D420}': 'g', '\\u{1D421}': 'h', '\\u{1D422}': 'i', '\\u{1D423}': 'j',\r\n    '\\u{1D424}': 'k', '\\u{1D425}': 'l', '\\u{1D426}': 'm', '\\u{1D427}': 'n', '\\u{1D428}': 'o',\r\n    '\\u{1D429}': 'p', '\\u{1D42A}': 'q', '\\u{1D42B}': 'r', '\\u{1D42C}': 's', '\\u{1D42D}': 't',\r\n    '\\u{1D42E}': 'u', '\\u{1D42F}': 'v', '\\u{1D430}': 'w', '\\u{1D42F}': 'x', '\\u{1D432}': 'y',\r\n    '\\u{1D433}': 'z',\r\n    \/\/ Fullwidth forms (CJK compatibility)\r\n    '\\uFF41': 'a', '\\uFF42': 'b', '\\uFF43': 'c', '\\uFF44': 'd', '\\uFF45': 'e', '\\uFF46': 'f',\r\n    '\\uFF47': 'g', '\\uFF48': 'h', '\\uFF49': 'i', '\\uFF4A': 'j', '\\uFF4B': 'k', '\\uFF4C': 'l',\r\n    '\\uFF4D': 'm', '\\uFF4E': 'n', '\\uFF4F': 'o', '\\uFF50': 'p', '\\uFF51': 'q', '\\uFF52': 'r',\r\n    '\\uFF53': 's', '\\uFF54': 't', '\\uFF55': 'u', '\\uFF56': 'v', '\\uFF57': 'w', '\\uFF58': 'x',\r\n    '\\uFF59': 'y', '\\uFF5A': 'z',\r\n    \/\/ Superscript\/subscript\r\n    '\\u1D43': 'a', '\\u1D47': 'b', '\\u1D48': 'd', '\\u1D49': 'e', '\\u1D4D': 'g', '\\u02B0': 'h',\r\n    '\\u2071': 'i', '\\u02B2': 'j', '\\u1D4F': 'k', '\\u02E1': 'l', '\\u1D50': 'm', '\\u207F': 'n',\r\n    '\\u1D52': 'o', '\\u1D56': 'p', '\\u02B3': 'r', '\\u02E2': 's', '\\u1D57': 't', '\\u1D58': 'u',\r\n    '\\u1D5B': 'v', '\\u02B7': 'w', '\\u02E3': 'x', '\\u02B8': 'y',\r\n    \/\/ IPA extensions\r\n    '\\u0251': 'a', '\\u0185': 'b', '\\u0269': 'l', '\\u028f': 'y', '\\u0254': 'c', '\\u0256': 'd',\r\n    '\\u025b': 'e', '\\u0263': 'g', '\\u026a': 'i', '\\u026f': 'm', '\\u0273': 'n', '\\u0275': 'o',\r\n    '\\u0279': 'r', '\\u0283': 's', '\\u0288': 't', '\\u028a': 'u', '\\u028b': 'v', '\\u0290': 'z',\r\n    \/\/ Common number\/symbol substitutions\r\n    '0': 'o', '1': 'l', '3': 'e', '4': 'a', '5': 's', '8': 'b', '9': 'g',\r\n    '@': 'a', '$': 's', '!': 'i', '|': 'l', '(': 'c', ')': 'd',\r\n    \/\/ Latin Extended lookalikes\r\n    '\\u0101': 'a', '\\u0103': 'a', '\\u00e0': 'a', '\\u00e1': 'a', '\\u00e2': 'a', '\\u00e3': 'a', '\\u00e4': 'a',\r\n    '\\u0113': 'e', '\\u0115': 'e', '\\u00e8': 'e', '\\u00e9': 'e', '\\u00ea': 'e', '\\u00eb': 'e',\r\n    '\\u012b': 'i', '\\u012d': 'i', '\\u00ec': 'i', '\\u00ed': 'i', '\\u00ee': 'i', '\\u00ef': 'i',\r\n    '\\u014d': 'o', '\\u014f': 'o', '\\u00f2': 'o', '\\u00f3': 'o', '\\u00f4': 'o', '\\u00f5': 'o', '\\u00f6': 'o',\r\n    '\\u016b': 'u', '\\u016d': 'u', '\\u00f9': 'u', '\\u00fa': 'u', '\\u00fb': 'u', '\\u00fc': 'u'\r\n  });\r\n\r\n  \/\/ Script ranges for detection logging\r\n  const SCRIPT_RANGES = {\r\n    cyrillic: { start: 0x0400, end: 0x04FF, name: 'Cyrillic' },\r\n    greek: { start: 0x0370, end: 0x03FF, name: 'Greek' },\r\n    armenian: { start: 0x0530, end: 0x058F, name: 'Armenian' },\r\n    mathAlphanumeric: { start: 0x1D400, end: 0x1D7FF, name: 'Math Alphanumeric' },\r\n    fullWidth: { start: 0xFF00, end: 0xFFEF, name: 'Fullwidth Forms' }\r\n  };\r\n\r\n  \/\/ Detect which scripts are present in a string\r\n  function detectScripts(str) {\r\n    const detected = new Set();\r\n    for (const char of str) {\r\n      const code = char.codePointAt(0);\r\n      for (const [script, range] of Object.entries(SCRIPT_RANGES)) {\r\n        if (code >= range.start && code <= range.end) {\r\n          detected.add(range.name);\r\n        }\r\n      }\r\n    }\r\n    return detected;\r\n  }\r\n\r\n  const suspiciousTLDs = Object.freeze([\r\n    '.tk', '.ml', '.ga', '.cf', '.gq', '.xyz', '.top', '.work', '.click',\r\n    '.link', '.buzz', '.monster', '.rest', '.icu', '.surf'\r\n  ]);\r\n\r\n  const romanianBrandsRequiringRO = Object.freeze([\r\n    'bancatransilvania', 'btrl', 'raiffeisen', 'raiffeisenbank', 'bcr', 'brd',\r\n    'unicredit', 'cec', 'cecbank', 'alphabank', 'otpbank', 'otp', 'libra', 'librabank',\r\n    'garanti', 'intesa', 'firstbank', 'patria', 'patriabank', 'crediteurope', 'exim', 'eximbank',\r\n    'anaf', 'ghiseul', 'rovinieta', 'drpciv', 'cnas', 'ajofm', 'onrc', 'efactura', 'roalert',\r\n    'emag', 'altex', 'pcgarage', 'evomag', 'cel', 'mediagalaxy', 'flanco', 'domo', 'dedeman',\r\n    'elefant', 'libris', 'carturesti',\r\n    'digi', 'rcs', 'telekom', 'cosmote', 'enel', 'engie', 'eon', 'electrica', 'hidroelectrica',\r\n    'delgaz', 'distrigaz', 'apanova',\r\n    'fancourier', 'cargus', 'sameday', 'urgentcargus', 'postaromana', 'cfr', 'tarom',\r\n    'olx', 'publi24', 'autovit', 'storia', 'imobiliare', 'lajumate',\r\n    'netopia', 'mobilpay', 'smartbill', 'oblio', 'facturis', 'gomag', 'megaimage'\r\n  ]);\r\n\r\n  const internationalBrandTLDs = Object.freeze({\r\n    'google': ['.com', '.ro', '.de', '.fr', '.co.uk', '.es', '.it'],\r\n    'gmail': ['.com'], 'youtube': ['.com'], 'facebook': ['.com'], 'instagram': ['.com'],\r\n    'whatsapp': ['.com'], 'microsoft': ['.com'], 'outlook': ['.com'], 'hotmail': ['.com'],\r\n    'apple': ['.com'], 'icloud': ['.com'],\r\n    'amazon': ['.com', '.de', '.co.uk', '.fr', '.es', '.it', '.ro'],\r\n    'paypal': ['.com'], 'stripe': ['.com'], 'twitter': ['.com'], 'linkedin': ['.com'],\r\n    'tiktok': ['.com'], 'snapchat': ['.com'], 'pinterest': ['.com'], 'reddit': ['.com'],\r\n    'discord': ['.com', '.gg'], 'twitch': ['.tv'], 'netflix': ['.com'], 'spotify': ['.com'],\r\n    'hbo': ['.com'], 'disney': ['.com'], 'github': ['.com'], 'gitlab': ['.com'],\r\n    'dropbox': ['.com'], 'adobe': ['.com'], 'zoom': ['.us'], 'slack': ['.com'],\r\n    'ebay': ['.com', '.de', '.co.uk', '.fr', '.es', '.it', '.ro'],\r\n    'alibaba': ['.com'], 'chase': ['.com'], 'visa': ['.com'], 'mastercard': ['.com'],\r\n    'coinbase': ['.com'], 'binance': ['.com'], 'booking': ['.com'], 'airbnb': ['.com'],\r\n    'dhl': ['.com', '.de', '.ro'], 'fedex': ['.com'], 'ups': ['.com']\r\n  });\r\n\r\n  const phishingKeywords = Object.freeze([\r\n    'login', 'signin', 'sign-in', 'log-in', 'secure', 'security', 'verify',\r\n    'verification', 'account', 'update', 'confirm', 'password', 'credential',\r\n    'suspend', 'suspended', 'locked', 'unlock', 'restore', 'recover', 'recovery',\r\n    'urgent', 'immediate', 'alert', 'warning', 'limited', 'expire', 'expired',\r\n    'validate', 'authenticate', 'banking', 'wallet', 'payment', 'invoice',\r\n    'refund', 'prize', 'winner', 'congratulation', 'selected', 'lucky',\r\n    'conectare', 'autentificare', 'parola', 'cont', 'verifica', 'verificare',\r\n    'actualizare', 'blocat', 'deblocare', 'recuperare', 'urgent', 'plata',\r\n    'factura', 'ramburs', 'castigator', 'premiu', 'felicitari'\r\n  ]);\r\n\r\n  \/\/ === Helper Functions ===\r\n  function normalizeForComparison(str) {\r\n    if (typeof str !== 'string') return '';\r\n    let normalized = str.toLowerCase();\r\n    for (const [homoglyph, letter] of Object.entries(homoglyphs)) {\r\n      normalized = normalized.split(homoglyph).join(letter);\r\n    }\r\n    return normalized;\r\n  }\r\n\r\n  function normalizeTyposquatting(str) {\r\n    if (typeof str !== 'string') return '';\r\n    return str.toLowerCase()\r\n      .replace(\/1\/g, 'l').replace(\/0\/g, 'o').replace(\/3\/g, 'e')\r\n      .replace(\/4\/g, 'a').replace(\/5\/g, 's').replace(\/\\$\/g, 's')\r\n      .replace(\/@\/g, 'a').replace(\/!\/g, 'i').replace(\/\\|\/g, 'l');\r\n  }\r\n\r\n  function findBrandWithSubstitutions(domain) {\r\n    const domainLower = domain.toLowerCase();\r\n    const normalizedDomain = normalizeTyposquatting(domainLower);\r\n    const results = [];\r\n\r\n    for (const brand of knownBrands) {\r\n      if (normalizedDomain.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'substitution', description: 'Domeniul contine caractere substituate care formeaza \"' + brand + '\"' });\r\n        continue;\r\n      }\r\n\r\n      const withIL = domainLower.replace(\/ll\/g, 'il');\r\n      const withLI = domainLower.replace(\/ll\/g, 'li');\r\n      const withM = domainLower.replace(\/rn\/g, 'm');\r\n      const withW = domainLower.replace(\/vv\/g, 'w');\r\n\r\n      if (withIL.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'double_letter', substitution: 'll \u2192 il', description: 'Domeniul imita \"' + brand + '\" folosind \"ll\" in loc de \"il\"' });\r\n      } else if (withLI.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'double_letter', substitution: 'll \u2192 li', description: 'Domeniul imita \"' + brand + '\" folosind \"ll\" in loc de \"li\"' });\r\n      } else if (withM.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'visual_trick', substitution: 'rn \u2192 m', description: 'Domeniul imita \"' + brand + '\" folosind \"rn\" care arata ca \"m\"' });\r\n      } else if (withW.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'visual_trick', substitution: 'vv \u2192 w', description: 'Domeniul imita \"' + brand + '\" folosind \"vv\" care arata ca \"w\"' });\r\n      }\r\n    }\r\n    return results;\r\n  }\r\n\r\n  function checkWithoutHyphens(domain) {\r\n    const domainLower = domain.toLowerCase();\r\n    const withoutHyphens = domainLower.replace(\/-\/g, '');\r\n    const results = [];\r\n\r\n    let domainName = domainLower.startsWith('www.') ? domainLower.substring(4) : domainLower;\r\n    const domainNameWithoutTLD = domainName.split('.')[0] || '';\r\n\r\n    if (knownBrands.includes(domainNameWithoutTLD)) return results;\r\n\r\n    for (const brand of knownBrands) {\r\n      if (brand.includes('-')) continue;\r\n      if (withoutHyphens.includes(brand) && !domainLower.replace(\/[^a-z]\/g, '').startsWith(brand)) {\r\n        const brandPattern = brand.split('').join('-?');\r\n        const regex = new RegExp(brandPattern);\r\n        if (regex.test(domainLower) && domainLower.includes('-')) {\r\n          results.push({ brand, description: 'Brandul \"' + brand + '\" este fragmentat cu cratime pentru a evita detectia' });\r\n        }\r\n      }\r\n    }\r\n    return results;\r\n  }\r\n\r\n  function levenshteinDistance(str1, str2) {\r\n    if (typeof str1 !== 'string' || typeof str2 !== 'string') return Infinity;\r\n    const s1 = str1.substring(0, 100), s2 = str2.substring(0, 100);\r\n    const m = s1.length, n = s2.length;\r\n    const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));\r\n    for (let i = 0; i <= m; i++) dp[i][0] = i;\r\n    for (let j = 0; j <= n; j++) dp[0][j] = j;\r\n    for (let i = 1; i <= m; i++) {\r\n      for (let j = 1; j <= n; j++) {\r\n        dp[i][j] = s1[i - 1] === s2[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);\r\n      }\r\n    }\r\n    return dp[m][n];\r\n  }\r\n\r\n  \/\/ === Advanced Typosquatting Algorithms (v4.0) ===\r\n\r\n  \/\/ Jaro-Winkler similarity - better for prefix matching (brand spoofing)\r\n  function jaroWinklerSimilarity(s1, s2) {\r\n    if (typeof s1 !== 'string' || typeof s2 !== 'string') return 0;\r\n    if (s1 === s2) return 1;\r\n    s1 = s1.substring(0, 100);\r\n    s2 = s2.substring(0, 100);\r\n\r\n    const len1 = s1.length, len2 = s2.length;\r\n    if (len1 === 0 || len2 === 0) return 0;\r\n\r\n    const matchWindow = Math.floor(Math.max(len1, len2) \/ 2) - 1;\r\n    const s1Matches = new Array(len1).fill(false);\r\n    const s2Matches = new Array(len2).fill(false);\r\n\r\n    let matches = 0;\r\n    let transpositions = 0;\r\n\r\n    \/\/ Find matches\r\n    for (let i = 0; i < len1; i++) {\r\n      const start = Math.max(0, i - matchWindow);\r\n      const end = Math.min(i + matchWindow + 1, len2);\r\n      for (let j = start; j < end; j++) {\r\n        if (s2Matches[j] || s1[i] !== s2[j]) continue;\r\n        s1Matches[i] = true;\r\n        s2Matches[j] = true;\r\n        matches++;\r\n        break;\r\n      }\r\n    }\r\n\r\n    if (matches === 0) return 0;\r\n\r\n    \/\/ Count transpositions\r\n    let k = 0;\r\n    for (let i = 0; i < len1; i++) {\r\n      if (!s1Matches[i]) continue;\r\n      while (!s2Matches[k]) k++;\r\n      if (s1[i] !== s2[k]) transpositions++;\r\n      k++;\r\n    }\r\n\r\n    const jaro = (matches \/ len1 + matches \/ len2 + (matches - transpositions \/ 2) \/ matches) \/ 3;\r\n\r\n    \/\/ Winkler modification: boost for common prefix\r\n    let prefix = 0;\r\n    for (let i = 0; i < Math.min(4, Math.min(len1, len2)); i++) {\r\n      if (s1[i] === s2[i]) prefix++;\r\n      else break;\r\n    }\r\n\r\n    return jaro + prefix * 0.1 * (1 - jaro);\r\n  }\r\n\r\n  \/\/ Keyboard proximity map (QWERTY layout)\r\n  const KEYBOARD_NEIGHBORS = Object.freeze({\r\n    'q': ['w', 'a', '1', '2'],\r\n    'w': ['q', 'e', 'a', 's', '2', '3'],\r\n    'e': ['w', 'r', 's', 'd', '3', '4'],\r\n    'r': ['e', 't', 'd', 'f', '4', '5'],\r\n    't': ['r', 'y', 'f', 'g', '5', '6'],\r\n    'y': ['t', 'u', 'g', 'h', '6', '7'],\r\n    'u': ['y', 'i', 'h', 'j', '7', '8'],\r\n    'i': ['u', 'o', 'j', 'k', '8', '9'],\r\n    'o': ['i', 'p', 'k', 'l', '9', '0'],\r\n    'p': ['o', 'l', '0'],\r\n    'a': ['q', 'w', 's', 'z'],\r\n    's': ['a', 'w', 'e', 'd', 'z', 'x'],\r\n    'd': ['s', 'e', 'r', 'f', 'x', 'c'],\r\n    'f': ['d', 'r', 't', 'g', 'c', 'v'],\r\n    'g': ['f', 't', 'y', 'h', 'v', 'b'],\r\n    'h': ['g', 'y', 'u', 'j', 'b', 'n'],\r\n    'j': ['h', 'u', 'i', 'k', 'n', 'm'],\r\n    'k': ['j', 'i', 'o', 'l', 'm'],\r\n    'l': ['k', 'o', 'p'],\r\n    'z': ['a', 's', 'x'],\r\n    'x': ['z', 's', 'd', 'c'],\r\n    'c': ['x', 'd', 'f', 'v'],\r\n    'v': ['c', 'f', 'g', 'b'],\r\n    'b': ['v', 'g', 'h', 'n'],\r\n    'n': ['b', 'h', 'j', 'm'],\r\n    'm': ['n', 'j', 'k'],\r\n    '1': ['2', 'q'],\r\n    '2': ['1', '3', 'q', 'w'],\r\n    '3': ['2', '4', 'w', 'e'],\r\n    '4': ['3', '5', 'e', 'r'],\r\n    '5': ['4', '6', 'r', 't'],\r\n    '6': ['5', '7', 't', 'y'],\r\n    '7': ['6', '8', 'y', 'u'],\r\n    '8': ['7', '9', 'u', 'i'],\r\n    '9': ['8', '0', 'i', 'o'],\r\n    '0': ['9', 'o', 'p']\r\n  });\r\n\r\n  function isKeyboardNeighbor(char1, char2) {\r\n    const c1 = char1.toLowerCase(), c2 = char2.toLowerCase();\r\n    return KEYBOARD_NEIGHBORS[c1]?.includes(c2) || false;\r\n  }\r\n\r\n  \/\/ Detect \"fat finger\" typos using keyboard proximity\r\n  function detectKeyboardTypo(domain, brand) {\r\n    if (domain.length !== brand.length) return null;\r\n    let typoCount = 0;\r\n    let typoPositions = [];\r\n\r\n    for (let i = 0; i < domain.length; i++) {\r\n      if (domain[i] !== brand[i]) {\r\n        if (isKeyboardNeighbor(domain[i], brand[i])) {\r\n          typoCount++;\r\n          typoPositions.push(i);\r\n        } else {\r\n          return null; \/\/ Non-keyboard typo\r\n        }\r\n      }\r\n    }\r\n\r\n    if (typoCount > 0 && typoCount <= 2) {\r\n      return {\r\n        brand,\r\n        typoCount,\r\n        typoPositions,\r\n        type: 'keyboard_typo',\r\n        description: 'Posibil\u0103 eroare de tastare: \"' + domain + '\" vs \"' + brand + '\" (taste adiacente)'\r\n      };\r\n    }\r\n    return null;\r\n  }\r\n\r\n  \/\/ Pattern detection: repetition (gooogle), omission (gogle), transposition (googel), vowel swap (guugle)\r\n  const VOWELS = new Set(['a', 'e', 'i', 'o', 'u']);\r\n\r\n  function detectRepetition(domain, brand) {\r\n    \/\/ Check if domain has repeated chars that brand doesn't\r\n    const domainCollapsed = domain.replace(\/(.)\\1+\/g, '$1');\r\n    if (domainCollapsed === brand && domain !== brand) {\r\n      return {\r\n        brand,\r\n        type: 'repetition',\r\n        description: 'Litere repetate detectate: \"' + domain + '\" \u2192 \"' + brand + '\"'\r\n      };\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function detectOmission(domain, brand) {\r\n    \/\/ Check if domain is brand with one char removed\r\n    if (domain.length !== brand.length - 1) return null;\r\n    for (let i = 0; i < brand.length; i++) {\r\n      const modified = brand.slice(0, i) + brand.slice(i + 1);\r\n      if (modified === domain) {\r\n        return {\r\n          brand,\r\n          type: 'omission',\r\n          description: 'Caracter lips\u0103: \"' + domain + '\" (lipse\u0219te \"' + brand[i] + '\" din \"' + brand + '\")'\r\n        };\r\n      }\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function detectTransposition(domain, brand) {\r\n    \/\/ Check if domain is brand with two adjacent chars swapped\r\n    if (domain.length !== brand.length) return null;\r\n    let diffCount = 0;\r\n    let diffPositions = [];\r\n    for (let i = 0; i < domain.length; i++) {\r\n      if (domain[i] !== brand[i]) {\r\n        diffCount++;\r\n        diffPositions.push(i);\r\n      }\r\n    }\r\n    if (diffCount === 2 && diffPositions[1] === diffPositions[0] + 1) {\r\n      if (domain[diffPositions[0]] === brand[diffPositions[1]] &&\r\n          domain[diffPositions[1]] === brand[diffPositions[0]]) {\r\n        return {\r\n          brand,\r\n          type: 'transposition',\r\n          description: 'Litere inversate: \"' + domain + '\" vs \"' + brand + '\"'\r\n        };\r\n      }\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function detectVowelSwap(domain, brand) {\r\n    \/\/ Check if domain differs only by vowel substitution\r\n    if (domain.length !== brand.length) return null;\r\n    let vowelSwaps = 0;\r\n    let otherDiffs = 0;\r\n    for (let i = 0; i < domain.length; i++) {\r\n      if (domain[i] !== brand[i]) {\r\n        if (VOWELS.has(domain[i]) && VOWELS.has(brand[i])) {\r\n          vowelSwaps++;\r\n        } else {\r\n          otherDiffs++;\r\n        }\r\n      }\r\n    }\r\n    if (vowelSwaps > 0 && vowelSwaps <= 2 && otherDiffs === 0) {\r\n      return {\r\n        brand,\r\n        type: 'vowel_swap',\r\n        description: 'Vocale substituite: \"' + domain + '\" vs \"' + brand + '\"'\r\n      };\r\n    }\r\n    return null;\r\n  }\r\n\r\n  \/\/ Combined advanced typosquatting check\r\n  function advancedTyposquatCheck(domain, brands) {\r\n    const results = [];\r\n    const domainLower = domain.toLowerCase();\r\n\r\n    for (const brand of brands) {\r\n      \/\/ Skip exact matches\r\n      if (domainLower === brand) continue;\r\n\r\n      \/\/ 1. Jaro-Winkler (prefix-focused similarity)\r\n      const jwScore = jaroWinklerSimilarity(domainLower, brand);\r\n      if (jwScore >= 0.85 && jwScore < 1) {\r\n        results.push({\r\n          brand,\r\n          score: jwScore,\r\n          type: 'jaro_winkler',\r\n          description: 'Similaritate ridicat\u0103 (' + Math.round(jwScore * 100) + '%) cu brandul \"' + brand + '\"'\r\n        });\r\n        continue;\r\n      }\r\n\r\n      \/\/ 2. Keyboard proximity typo\r\n      const keyboardMatch = detectKeyboardTypo(domainLower, brand);\r\n      if (keyboardMatch) {\r\n        results.push(keyboardMatch);\r\n        continue;\r\n      }\r\n\r\n      \/\/ 3. Pattern detection\r\n      const repetition = detectRepetition(domainLower, brand);\r\n      if (repetition) { results.push(repetition); continue; }\r\n\r\n      const omission = detectOmission(domainLower, brand);\r\n      if (omission) { results.push(omission); continue; }\r\n\r\n      const transposition = detectTransposition(domainLower, brand);\r\n      if (transposition) { results.push(transposition); continue; }\r\n\r\n      const vowelSwap = detectVowelSwap(domainLower, brand);\r\n      if (vowelSwap) { results.push(vowelSwap); continue; }\r\n    }\r\n\r\n    \/\/ Sort by score (Jaro-Winkler) descending\r\n    return results.sort((a, b) => (b.score || 0) - (a.score || 0));\r\n  }\r\n\r\n  \/\/ === API Response Cache (v4.0) ===\r\n  const CACHE_CONFIG = {\r\n    PREFIX: 'zic_api_cache_',\r\n    TTL: {\r\n      google: 60 * 60 * 1000,       \/\/ 1 hour\r\n      virustotal: 60 * 60 * 1000,   \/\/ 1 hour\r\n      urlhaus: 30 * 60 * 1000,      \/\/ 30 minutes (updates frequently)\r\n      urlscan: 2 * 60 * 60 * 1000,  \/\/ 2 hours\r\n      phishtank: 30 * 60 * 1000,    \/\/ 30 minutes\r\n      whois: 24 * 60 * 60 * 1000,   \/\/ 24 hours (rarely changes)\r\n      geoip: 24 * 60 * 60 * 1000,   \/\/ 24 hours\r\n      dns: 6 * 60 * 60 * 1000,      \/\/ 6 hours\r\n      ssl: 24 * 60 * 60 * 1000      \/\/ 24 hours\r\n    },\r\n    MAX_ENTRIES: 200\r\n  };\r\n\r\n  const apiCache = {\r\n    _hash(str) {\r\n      let hash = 0;\r\n      for (let i = 0; i < str.length; i++) {\r\n        const char = str.charCodeAt(i);\r\n        hash = ((hash << 5) - hash) + char;\r\n        hash = hash & hash;\r\n      }\r\n      return Math.abs(hash).toString(36);\r\n    },\r\n\r\n    _getKey(apiName, url) {\r\n      return CACHE_CONFIG.PREFIX + apiName + '_' + this._hash(url);\r\n    },\r\n\r\n    get(apiName, url) {\r\n      try {\r\n        const key = this._getKey(apiName, url);\r\n        const cached = localStorage.getItem(key);\r\n        if (!cached) return null;\r\n\r\n        const { data, timestamp } = JSON.parse(cached);\r\n        const ttl = CACHE_CONFIG.TTL[apiName] || 60 * 60 * 1000;\r\n\r\n        if (Date.now() - timestamp > ttl) {\r\n          localStorage.removeItem(key);\r\n          return null;\r\n        }\r\n\r\n        return { ...data, fromCache: true };\r\n      } catch (e) {\r\n        return null;\r\n      }\r\n    },\r\n\r\n    set(apiName, url, data) {\r\n      try {\r\n        \/\/ Don't cache errors\r\n        if (data.error || !data.checked) return;\r\n\r\n        const key = this._getKey(apiName, url);\r\n        const entry = {\r\n          data: data,\r\n          timestamp: Date.now()\r\n        };\r\n        localStorage.setItem(key, JSON.stringify(entry));\r\n        this._enforceMaxEntries();\r\n      } catch (e) {\r\n        \/\/ localStorage full - clean old entries\r\n        this._cleanOldest(50);\r\n      }\r\n    },\r\n\r\n    _enforceMaxEntries() {\r\n      const entries = [];\r\n      const prefix = CACHE_CONFIG.PREFIX;\r\n\r\n      for (let i = 0; i < localStorage.length; i++) {\r\n        const key = localStorage.key(i);\r\n        if (key && key.startsWith(prefix)) {\r\n          try {\r\n            const { timestamp } = JSON.parse(localStorage.getItem(key));\r\n            entries.push({ key, timestamp });\r\n          } catch (e) {}\r\n        }\r\n      }\r\n\r\n      if (entries.length > CACHE_CONFIG.MAX_ENTRIES) {\r\n        entries.sort((a, b) => a.timestamp - b.timestamp);\r\n        const toRemove = entries.slice(0, entries.length - CACHE_CONFIG.MAX_ENTRIES);\r\n        toRemove.forEach(e => localStorage.removeItem(e.key));\r\n      }\r\n    },\r\n\r\n    _cleanOldest(count) {\r\n      const entries = [];\r\n      const prefix = CACHE_CONFIG.PREFIX;\r\n\r\n      for (let i = 0; i < localStorage.length; i++) {\r\n        const key = localStorage.key(i);\r\n        if (key && key.startsWith(prefix)) {\r\n          try {\r\n            const { timestamp } = JSON.parse(localStorage.getItem(key));\r\n            entries.push({ key, timestamp });\r\n          } catch (e) {\r\n            localStorage.removeItem(key);\r\n          }\r\n        }\r\n      }\r\n\r\n      entries.sort((a, b) => a.timestamp - b.timestamp);\r\n      entries.slice(0, count).forEach(e => localStorage.removeItem(e.key));\r\n    }\r\n  };\r\n\r\n  \/\/ === API Timeout Handler (v4.0) ===\r\n  const API_TIMEOUTS = {\r\n    google: 8000,\r\n    virustotal: 10000,\r\n    urlhaus: 5000,\r\n    urlscan: 8000,\r\n    phishtank: 8000,\r\n    whois: 12000,\r\n    geoip: 5000,\r\n    dns: 5000,\r\n    ssl: 15000,\r\n    default: 10000\r\n  };\r\n\r\n  async function fetchWithTimeout(url, options = {}, apiName = 'default') {\r\n    const timeout = API_TIMEOUTS[apiName] || API_TIMEOUTS.default;\r\n    const controller = new AbortController();\r\n    const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n    try {\r\n      const response = await fetch(url, {\r\n        ...options,\r\n        signal: controller.signal\r\n      });\r\n      clearTimeout(timeoutId);\r\n      return response;\r\n    } catch (error) {\r\n      clearTimeout(timeoutId);\r\n      if (error.name === 'AbortError') {\r\n        throw new Error('Timeout after ' + timeout + 'ms');\r\n      }\r\n      throw error;\r\n    }\r\n  }\r\n\r\n  \/\/ === API Functions ===\r\n\r\n  \/\/ Google Safe Browsing - prin Cloudflare Worker proxy (API key securizat\u0103 \u00een backend)\r\n  async function checkGoogleSafeBrowsing(url) {\r\n    if (!API_CONFIG.GOOGLE_SAFE_BROWSING.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('google', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      const response = await fetchWithTimeout(\r\n        CLOUDFLARE_PROXY + '\/google-safebrowsing?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } },\r\n        'google'\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      const result = {\r\n        checked: data.checked || false,\r\n        safe: data.safe !== false,\r\n        threats: data.threats || [],\r\n        source: data.source || 'Google Safe Browsing'\r\n      };\r\n\r\n      \/\/ Cache successful result\r\n      apiCache.set('google', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('Google Safe Browsing check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ VirusTotal - prin Cloudflare Worker proxy\r\n  async function checkVirusTotal(url) {\r\n    if (!API_CONFIG.VIRUSTOTAL.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('virustotal', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      const response = await fetchWithTimeout(\r\n        CLOUDFLARE_PROXY + '\/virustotal?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } },\r\n        'virustotal'\r\n      );\r\n\r\n      if (!response.ok) {\r\n        return { checked: false, error: 'API error: ' + response.status };\r\n      }\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      let result;\r\n      const stats = data.data?.attributes?.last_analysis_stats;\r\n      if (stats) {\r\n        const malicious = stats.malicious || 0;\r\n        const suspicious = stats.suspicious || 0;\r\n        const total = Object.values(stats).reduce((a, b) => a + b, 0);\r\n        result = { checked: true, safe: malicious === 0 && suspicious === 0, malicious, suspicious, total, source: 'VirusTotal' };\r\n      } else {\r\n        result = { checked: true, safe: true, source: 'VirusTotal' };\r\n      }\r\n\r\n      apiCache.set('virustotal', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('VirusTotal check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ IPQualityScore - prin Cloudflare Worker proxy\r\n  async function checkIPQualityScore(url) {\r\n    if (!API_CONFIG.IPQUALITYSCORE.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/ipqs?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      if (data.success) {\r\n        return {\r\n          checked: true,\r\n          safe: !data.unsafe && !data.phishing && !data.malware,\r\n          riskScore: data.risk_score || 0,\r\n          phishing: data.phishing || false,\r\n          malware: data.malware || false,\r\n          suspicious: data.suspicious || false,\r\n          source: 'IPQualityScore'\r\n        };\r\n      }\r\n      return { checked: false, error: data.message || 'Unknown error' };\r\n    } catch (error) {\r\n      console.warn('IPQualityScore check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ URLhaus - prin Cloudflare Worker proxy (cu fallback la API direct CORS-enabled)\r\n  async function checkURLhaus(url) {\r\n    if (!API_CONFIG.URLHAUS.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('urlhaus', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      \/\/ Try direct API first (URLhaus supports CORS)\r\n      let response;\r\n      try {\r\n        response = await fetchWithTimeout('https:\/\/urlhaus-api.abuse.ch\/v1\/url\/', {\r\n          method: 'POST',\r\n          headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n          body: 'url=' + encodeURIComponent(url)\r\n        }, 'urlhaus');\r\n      } catch (directError) {\r\n        \/\/ Fallback to proxy if direct fails\r\n        response = await fetchWithTimeout(CLOUDFLARE_PROXY + '\/urlhaus', {\r\n          method: 'POST',\r\n          headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n          body: 'url=' + encodeURIComponent(url)\r\n        }, 'urlhaus');\r\n      }\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      let result;\r\n      if (data.query_status === 'ok') {\r\n        result = {\r\n          checked: true,\r\n          safe: false,\r\n          threat: data.threat || 'malware',\r\n          tags: data.tags || [],\r\n          dateAdded: data.date_added,\r\n          source: 'URLhaus (abuse.ch)'\r\n        };\r\n      } else if (data.query_status === 'no_results') {\r\n        result = { checked: true, safe: true, source: 'URLhaus (abuse.ch)' };\r\n      } else {\r\n        return { checked: false, error: data.query_status };\r\n      }\r\n\r\n      apiCache.set('urlhaus', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('URLhaus check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ urlscan.io - prin Cloudflare Worker proxy\r\n  async function checkUrlscan(url) {\r\n    if (!API_CONFIG.URLSCAN.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/urlscan?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        safe: !data.malicious,\r\n        found: data.found || false,\r\n        total: data.total || 0,\r\n        verdicts: data.verdicts || [],\r\n        source: 'urlscan.io'\r\n      };\r\n    } catch (error) {\r\n      console.warn('urlscan.io check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ PhishTank - prin Cloudflare Worker proxy\r\n  async function checkPhishTank(url) {\r\n    if (!API_CONFIG.PHISHTANK.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('phishtank', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      const response = await fetchWithTimeout(CLOUDFLARE_PROXY + '\/phishtank', {\r\n        method: 'POST',\r\n        headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n        body: 'url=' + encodeURIComponent(url)\r\n      }, 'phishtank');\r\n\r\n      if (!response.ok) {\r\n        if (response.status === 429) {\r\n          return { checked: false, error: 'Rate limit exceeded' };\r\n        }\r\n        return { checked: false, error: 'API error: ' + response.status };\r\n      }\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      const result = {\r\n        checked: true,\r\n        safe: !data.in_database || !data.verified,\r\n        inDatabase: data.in_database || false,\r\n        verified: data.verified || false,\r\n        phishId: data.phish_id,\r\n        source: 'PhishTank (Cisco)'\r\n      };\r\n\r\n      apiCache.set('phishtank', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('PhishTank check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ PhishStats - prin Cloudflare Worker proxy\r\n  async function checkPhishStats(url) {\r\n    if (!API_CONFIG.PHISHSTATS.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/phishstats?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        safe: !data.malicious,\r\n        found: data.found || false,\r\n        total: data.total || 0,\r\n        threats: data.threats || [],\r\n        source: 'PhishStats'\r\n      };\r\n    } catch (error) {\r\n      console.warn('PhishStats check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ === NOI VERIFIC\u0102RI v3 ===\r\n\r\n  \/\/ DNS Analysis - verific\u0103 DNS records\r\n  async function checkDNS(url) {\r\n    if (!API_CONFIG.DNS.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/dns?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      \/\/ Analiz\u0103: domeniu f\u0103r\u0103 MX records sau f\u0103r\u0103 SPF poate fi suspect\r\n      const suspicious = !data.analysis?.hasMailServers && !data.analysis?.hasSpf;\r\n\r\n      return {\r\n        checked: true,\r\n        domain: data.domain,\r\n        records: data.records,\r\n        analysis: data.analysis,\r\n        suspicious: suspicious,\r\n        source: 'DNS Analysis'\r\n      };\r\n    } catch (error) {\r\n      console.warn('DNS check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ GeoIP - loca\u021bia serverului\r\n  async function checkGeoIP(url) {\r\n    if (!API_CONFIG.GEOIP.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/geoip?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        ip: data.ip,\r\n        location: data.location,\r\n        network: data.network,\r\n        source: 'GeoIP'\r\n      };\r\n    } catch (error) {\r\n      console.warn('GeoIP check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ WHOIS - v\u00e2rsta domeniului\r\n  async function checkWHOIS(url) {\r\n    if (!API_CONFIG.WHOIS.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/whois?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error && !data.dates) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        domain: data.domain,\r\n        dates: data.dates,\r\n        registrar: data.registrar,\r\n        analysis: data.analysis,\r\n        source: 'WHOIS'\r\n      };\r\n    } catch (error) {\r\n      console.warn('WHOIS check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ SSL Certificate validation\r\n  async function checkSSL(url) {\r\n    if (!API_CONFIG.SSL.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/ssl?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      \/\/ SSL Labs poate returna 'analyzing' dac\u0103 verificarea e \u00een curs\r\n      if (data.status === 'analyzing') {\r\n        return {\r\n          checked: true,\r\n          analyzing: true,\r\n          message: data.message,\r\n          source: 'SSL Labs'\r\n        };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        domain: data.domain,\r\n        grade: data.grade,\r\n        hasWarnings: data.hasWarnings,\r\n        cert: data.cert,\r\n        analysis: data.analysis,\r\n        source: 'SSL Labs'\r\n      };\r\n    } catch (error) {\r\n      console.warn('SSL check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ Run all API checks (include noile verific\u0103ri v3)\r\n  async function runAPIChecks(url) {\r\n    \/\/ Helper to wrap API call with step tracking\r\n    async function trackStep(stepName, apiCall) {\r\n      updateLoadingStep(stepName, 'checking');\r\n      try {\r\n        const result = await apiCall;\r\n        updateLoadingStep(stepName, result.checked ? 'done' : (result.timeout ? 'timeout' : 'failed'));\r\n        return result;\r\n      } catch (e) {\r\n        updateLoadingStep(stepName, 'failed');\r\n        return { checked: false, error: e.message };\r\n      }\r\n    }\r\n\r\n    \/\/ Verific\u0103ri de securitate principale (cu step tracking)\r\n    const [googleResult, vtResult, urlhausResult, urlscanResult, phishtankResult] = await Promise.all([\r\n      trackStep('google', checkGoogleSafeBrowsing(url)),\r\n      trackStep('virustotal', checkVirusTotal(url)),\r\n      trackStep('urlhaus', checkURLhaus(url)),\r\n      trackStep('urlscan', checkUrlscan(url)),\r\n      trackStep('phishtank', checkPhishTank(url))\r\n    ]);\r\n\r\n    \/\/ Verific\u0103ri noi v3 (run \u00een paralel)\r\n    const [dnsResult, geoipResult, whoisResult, sslResult] = await Promise.all([\r\n      checkDNS(url),\r\n      checkGeoIP(url),\r\n      checkWHOIS(url),\r\n      checkSSL(url)\r\n    ]);\r\n\r\n    return {\r\n      googleSafeBrowsing: googleResult,\r\n      virusTotal: vtResult,\r\n      urlhaus: urlhausResult,\r\n      urlscan: urlscanResult,\r\n      phishtank: phishtankResult,\r\n      \/\/ Noile verific\u0103ri\r\n      dns: dnsResult,\r\n      geoip: geoipResult,\r\n      whois: whoisResult,\r\n      ssl: sslResult\r\n    };\r\n  }\r\n\r\n  function extractDomain(url) {\r\n    try {\r\n      let cleanUrl = sanitizeInput(url);\r\n      if (!cleanUrl) return { valid: false };\r\n      if (\/^(javascript|data|vbscript|file):\/i.test(cleanUrl)) return { valid: false };\r\n      if (!cleanUrl.match(\/^https?:\\\/\\\/\/i)) cleanUrl = 'https:\/\/' + cleanUrl;\r\n      const urlObj = new URL(cleanUrl);\r\n      if (urlObj.protocol !== 'https:' && urlObj.protocol !== 'http:') return { valid: false };\r\n      return {\r\n        full: urlObj.hostname,\r\n        pathname: urlObj.pathname,\r\n        search: urlObj.search,\r\n        protocol: urlObj.protocol,\r\n        port: urlObj.port,\r\n        valid: true\r\n      };\r\n    } catch (e) {\r\n      return { valid: false };\r\n    }\r\n  }\r\n\r\n  \/\/ === Local Analysis ===\r\n  function analyzeURL(url) {\r\n    const domainInfo = extractDomain(url);\r\n    if (!domainInfo.valid) return { valid: false };\r\n\r\n    const checks = [];\r\n    let totalScore = 100;\r\n\r\n    \/\/ 1. HTTPS Check\r\n    if (domainInfo.protocol === 'https:') {\r\n      checks.push({ status: 'pass', title: t('checkHttpsPass'), description: t('checkHttpsPassDesc') });\r\n    } else {\r\n      checks.push({ status: 'fail', title: t('checkHttpsFail'), description: t('checkHttpsFailDesc') });\r\n      totalScore -= 20;\r\n    }\r\n\r\n    \/\/ 2. Homograph Attack (Enhanced v4.0 with script detection)\r\n    const originalDomain = domainInfo.full;\r\n    const normalizedDomain = normalizeForComparison(originalDomain);\r\n    const detectedScriptsSet = detectScripts(originalDomain);\r\n    const hasNonLatinScripts = detectedScriptsSet.size > 0;\r\n\r\n    if (originalDomain.toLowerCase() !== normalizedDomain || hasNonLatinScripts) {\r\n      const scriptsArray = Array.from(detectedScriptsSet);\r\n      const scriptsInfo = scriptsArray.length > 0\r\n        ? (currentLang === 'ro'\r\n          ? ` Script-uri detectate: ${scriptsArray.join(', ')}.`\r\n          : ` Detected scripts: ${scriptsArray.join(', ')}.`)\r\n        : '';\r\n      const description = t('checkUnicodeFailDesc', { domain: normalizedDomain }) + scriptsInfo;\r\n      checks.push({ status: 'fail', title: t('checkUnicodeFail'), description });\r\n      \/\/ Mixed scripts (e.g., Cyrillic + Latin) are more dangerous\r\n      totalScore -= hasNonLatinScripts && scriptsArray.length > 1 ? 45 : 35;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('checkUnicodePass'), description: t('checkUnicodePassDesc') });\r\n    }\r\n\r\n    \/\/ 3. Typosquatting Detection\r\n    let domainForCheck = normalizedDomain.toLowerCase();\r\n    if (domainForCheck.startsWith('www.')) domainForCheck = domainForCheck.substring(4);\r\n    const domainWithoutTLD = domainForCheck.split('.')[0] || '';\r\n    const fullDomainLower = domainInfo.full.toLowerCase();\r\n    let typosquatMatch = null, typosquatDetails = null, typosquatType = null;\r\n\r\n    \/\/ 3a. Character substitution\r\n    const substitutionMatches = findBrandWithSubstitutions(fullDomainLower);\r\n    if (substitutionMatches.length > 0) {\r\n      typosquatMatch = substitutionMatches[0].brand;\r\n      typosquatDetails = substitutionMatches[0].description;\r\n      typosquatType = substitutionMatches[0].type;\r\n    }\r\n\r\n    \/\/ 3b. Hyphen fragmented\r\n    if (!typosquatMatch) {\r\n      const hyphenMatches = checkWithoutHyphens(fullDomainLower);\r\n      if (hyphenMatches.length > 0) {\r\n        typosquatMatch = hyphenMatches[0].brand;\r\n        typosquatDetails = hyphenMatches[0].description;\r\n        typosquatType = 'hyphen_fragmented';\r\n      }\r\n    }\r\n\r\n    \/\/ 3c. Levenshtein distance\r\n    if (!typosquatMatch) {\r\n      for (const brand of knownBrands) {\r\n        const maxAllowedDistance = brand.length <= 4 ? 1 : 2;\r\n        if (Math.abs(domainWithoutTLD.length - brand.length) > 3) continue;\r\n        const distance = levenshteinDistance(domainWithoutTLD, brand);\r\n        if (distance > 0 && distance <= maxAllowedDistance && distance \/ Math.max(domainWithoutTLD.length, brand.length) < 0.4) {\r\n          typosquatMatch = brand;\r\n          typosquatType = 'levenshtein';\r\n          typosquatDetails = 'Domeniul difera prin ' + distance + ' caracter(e) de brandul \"' + brand + '\".';\r\n          break;\r\n        }\r\n        if (domainWithoutTLD.includes(brand) && domainWithoutTLD !== brand && brand.length >= 4 && domainWithoutTLD.length - brand.length <= 5) {\r\n          typosquatMatch = brand;\r\n          typosquatType = 'brand_extended';\r\n          typosquatDetails = 'Domeniul contine brandul \"' + brand + '\" cu caractere aditionale.';\r\n          break;\r\n        }\r\n      }\r\n    }\r\n\r\n    \/\/ 3d. Normalized typosquatting\r\n    if (!typosquatMatch) {\r\n      const normalizedTypo = normalizeTyposquatting(domainWithoutTLD);\r\n      if (normalizedTypo !== domainWithoutTLD) {\r\n        for (const brand of knownBrands) {\r\n          if (normalizedTypo === brand || normalizedTypo.includes(brand)) {\r\n            typosquatMatch = brand;\r\n            typosquatType = 'char_substitution';\r\n            typosquatDetails = 'Domeniul foloseste cifre sau simboluri pentru a imita \"' + brand + '\".';\r\n            break;\r\n          }\r\n        }\r\n      }\r\n    }\r\n\r\n    \/\/ 3e. Advanced typosquatting (Jaro-Winkler, keyboard proximity, patterns)\r\n    if (!typosquatMatch) {\r\n      const advancedMatches = advancedTyposquatCheck(domainWithoutTLD, knownBrands);\r\n      if (advancedMatches.length > 0) {\r\n        typosquatMatch = advancedMatches[0].brand;\r\n        typosquatDetails = advancedMatches[0].description;\r\n        typosquatType = advancedMatches[0].type;\r\n      }\r\n    }\r\n\r\n    if (typosquatMatch && !knownBrands.includes(domainWithoutTLD)) {\r\n      let title = t('typosquatTitle');\r\n      let description = typosquatDetails || t('typosquatDesc', { brand: typosquatMatch });\r\n      if (typosquatType === 'double_letter') { title = t('typosquatDouble'); }\r\n      else if (typosquatType === 'visual_trick') { title = t('typosquatVisual'); }\r\n      else if (typosquatType === 'char_substitution') { title = t('typosquatSubst'); }\r\n      else if (typosquatType === 'hyphen_fragmented') { title = t('typosquatHyphen'); }\r\n      else if (typosquatType === 'keyboard_typo') { title = t('typosquatKeyboard'); }\r\n      else if (typosquatType === 'jaro_winkler') { title = t('typosquatSimilarity'); }\r\n      else if (typosquatType === 'repetition') { title = t('typosquatRepetition'); }\r\n      else if (typosquatType === 'omission') { title = t('typosquatOmission'); }\r\n      else if (typosquatType === 'transposition') { title = t('typosquatTransposition'); }\r\n      else if (typosquatType === 'vowel_swap') { title = t('typosquatVowelSwap'); }\r\n      checks.push({ status: 'fail', title, description });\r\n      totalScore -= 35;\r\n    } else if (knownBrands.includes(domainWithoutTLD)) {\r\n      const isRomanianBrand = romanianBrandsRequiringRO.includes(domainWithoutTLD);\r\n      const isInternationalBrand = internationalBrandTLDs.hasOwnProperty(domainWithoutTLD);\r\n      const domainTLD = '.' + domainInfo.full.split('.').pop().toLowerCase();\r\n      const isOnRoTLD = domainTLD === '.ro' || domainInfo.full.toLowerCase().includes('.gov.ro');\r\n      let brandTLDIssue = false, brandTLDMessage = '';\r\n\r\n      if (isRomanianBrand && !isOnRoTLD) {\r\n        brandTLDIssue = true;\r\n        brandTLDMessage = currentLang === 'ro'\r\n          ? 'ATEN\u021aIE: \"' + domainWithoutTLD + '\" este un brand rom\u00e2nesc care ar trebui s\u0103 fie pe .ro, nu pe \"' + domainTLD + '\".'\r\n          : 'WARNING: \"' + domainWithoutTLD + '\" is a Romanian brand that should be on .ro, not on \"' + domainTLD + '\".';\r\n      } else if (isInternationalBrand) {\r\n        const allowedTLDs = internationalBrandTLDs[domainWithoutTLD];\r\n        if (!allowedTLDs.some(tld => domainInfo.full.toLowerCase().endsWith(tld))) {\r\n          brandTLDIssue = true;\r\n          brandTLDMessage = currentLang === 'ro'\r\n            ? 'ATEN\u021aIE: \"' + domainWithoutTLD + '\" ar trebui s\u0103 fie pe ' + allowedTLDs.slice(0, 3).join(', ') + '.'\r\n            : 'WARNING: \"' + domainWithoutTLD + '\" should be on ' + allowedTLDs.slice(0, 3).join(', ') + '.';\r\n        }\r\n      }\r\n\r\n      if (brandTLDIssue) {\r\n        checks.push({ status: 'fail', title: t('brandWrongTld'), description: brandTLDMessage });\r\n        totalScore -= 40;\r\n      } else {\r\n        checks.push({ status: 'pass', title: t('brandOk'), description: t('brandOkDesc') });\r\n      }\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('noTyposquat'), description: t('noTyposquatDesc') });\r\n    }\r\n\r\n    \/\/ 4. Suspicious TLD\r\n    if (suspiciousTLDs.some(tld => domainInfo.full.toLowerCase().endsWith(tld))) {\r\n      checks.push({ status: 'warn', title: t('suspiciousTld'), description: t('suspiciousTldDesc') });\r\n      totalScore -= 15;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('tldOk'), description: t('tldOkDesc') });\r\n    }\r\n\r\n    \/\/ 5. Excessive subdomains\r\n    const subdomainCount = Math.max(0, domainInfo.full.split('.').length - 2);\r\n    if (subdomainCount > 2) {\r\n      checks.push({ status: 'warn', title: t('multiSubdomain'), description: t('multiSubdomainDesc', { count: subdomainCount }) });\r\n      totalScore -= 10;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('subdomainOk'), description: t('subdomainOkDesc') });\r\n    }\r\n\r\n    \/\/ 6. Phishing keywords\r\n    const fullUrl = (domainInfo.full + domainInfo.pathname + domainInfo.search).toLowerCase();\r\n    const foundKeywords = phishingKeywords.filter(kw => fullUrl.includes(kw));\r\n    if (foundKeywords.length >= 2) {\r\n      checks.push({ status: 'fail', title: t('phishKeywords'), description: t('phishKeywordsDesc', { keywords: foundKeywords.slice(0, 3).join('\", \"') }) });\r\n      totalScore -= 20;\r\n    } else if (foundKeywords.length === 1) {\r\n      checks.push({ status: 'warn', title: t('sensitiveTerm'), description: t('sensitiveTermDesc', { keyword: foundKeywords[0] }) });\r\n      totalScore -= 5;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('noSuspiciousTerms'), description: t('noSuspiciousTermsDesc') });\r\n    }\r\n\r\n    \/\/ 7. Domain length\r\n    if (domainInfo.full.length > 40) {\r\n      checks.push({ status: 'warn', title: t('longDomain'), description: t('longDomainDesc', { length: domainInfo.full.length }) });\r\n      totalScore -= 10;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('domainLengthOk'), description: t('domainLengthOkDesc') });\r\n    }\r\n\r\n    \/\/ 8. IP instead of domain\r\n    if (\/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$\/.test(domainInfo.full)) {\r\n      checks.push({ status: 'fail', title: t('ipAddress'), description: t('ipAddressDesc') });\r\n      totalScore -= 25;\r\n    }\r\n\r\n    \/\/ 9. Non-standard port\r\n    if (domainInfo.port && domainInfo.port !== '80' && domainInfo.port !== '443') {\r\n      checks.push({ status: 'warn', title: t('nonStandardPort'), description: t('nonStandardPortDesc', { port: domainInfo.port }) });\r\n      totalScore -= 10;\r\n    }\r\n\r\n    \/\/ 10. Punycode\/IDN\r\n    if (domainInfo.full.startsWith('xn--') || domainInfo.full.includes('.xn--')) {\r\n      checks.push({ status: 'warn', title: t('idnDomain'), description: t('idnDomainDesc') });\r\n      totalScore -= 15;\r\n    }\r\n\r\n    \/\/ 11. Suspicious characters\r\n    if (\/--|__|[!@#$%^&*()+=]\/.test(domainInfo.full)) {\r\n      checks.push({ status: 'warn', title: t('unusualChars'), description: t('unusualCharsDesc') });\r\n      totalScore -= 10;\r\n    }\r\n\r\n    \/\/ 12. Brand in subdomain\r\n    const allParts = domainInfo.full.split('.');\r\n    const subdomains = allParts.length > 2 ? allParts.slice(0, -2) : [];\r\n    const mainDomain = allParts.length >= 2 ? allParts[allParts.length - 2] : (allParts[0] || '');\r\n    const brandInSubdomain = subdomains.length > 0 && knownBrands.some(brand => subdomains.some(sub => sub.includes(brand)));\r\n    if (brandInSubdomain && !knownBrands.includes(mainDomain)) {\r\n      checks.push({ status: 'fail', title: t('brandInSubdomain'), description: t('brandInSubdomainDesc') });\r\n      totalScore -= 25;\r\n    }\r\n\r\n    totalScore = Math.max(0, Math.min(100, totalScore));\r\n    let riskLevel = totalScore >= SCORE_THRESHOLDS.safe ? 'safe' : totalScore >= SCORE_THRESHOLDS.warning ? 'warning' : 'danger';\r\n\r\n    return { valid: true, url: sanitizeInput(url), score: totalScore, riskLevel, checks };\r\n  }\r\n\r\n  \/\/ === DOM Manipulation ===\r\n  function createCheckItem(check) {\r\n    const validStatus = validateStatus(check.status);\r\n    const item = document.createElement('div');\r\n    item.className = 'zic2__checkItem status-' + validStatus;\r\n\r\n    const iconDiv = document.createElement('div');\r\n    iconDiv.className = 'zic2__checkIcon';\r\n    iconDiv.textContent = validStatus === 'pass' ? '\\u2713' : validStatus === 'warn' ? '!' : '\\u2717';\r\n\r\n    const contentDiv = document.createElement('div');\r\n    contentDiv.className = 'zic2__checkContent';\r\n\r\n    const titleDiv = document.createElement('div');\r\n    titleDiv.className = 'zic2__checkTitle';\r\n    titleDiv.textContent = check.title || '';\r\n\r\n    const descDiv = document.createElement('div');\r\n    descDiv.className = 'zic2__checkDesc';\r\n    descDiv.textContent = check.description || '';\r\n\r\n    contentDiv.appendChild(titleDiv);\r\n    contentDiv.appendChild(descDiv);\r\n    item.appendChild(iconDiv);\r\n    item.appendChild(contentDiv);\r\n    return item;\r\n  }\r\n\r\n  function displayResults(analysis) {\r\n    \/\/ Store for export\r\n    lastAnalysis = analysis;\r\n\r\n    \/\/ Save to history\r\n    saveToHistory(analysis);\r\n\r\n    \/\/ Set timestamp for print\r\n    const now = new Date();\r\n    const timestamp = now.toLocaleDateString(currentLang === 'ro' ? 'ro-RO' : 'en-GB', {\r\n      year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit'\r\n    });\r\n    elements.scoreCard.setAttribute('data-print-timestamp', timestamp);\r\n\r\n    elements.analyzedUrl.textContent = analysis.url;\r\n    elements.scoreNumber.textContent = String(analysis.score);\r\n\r\n    const validRiskLevels = ['safe', 'warning', 'danger'];\r\n    const safeRiskLevel = validRiskLevels.includes(analysis.riskLevel) ? analysis.riskLevel : 'warning';\r\n\r\n    elements.scoreCircle.className = 'zic2__scoreCircle score-' + safeRiskLevel;\r\n    elements.scoreDisplay.className = 'zic2__scoreDisplay score-' + safeRiskLevel;\r\n\r\n    if (safeRiskLevel === 'safe') {\r\n      elements.scoreText.textContent = t('scoreSafe');\r\n      elements.scoreDesc.textContent = t('descSafe');\r\n    } else if (safeRiskLevel === 'warning') {\r\n      elements.scoreText.textContent = t('scoreWarning');\r\n      elements.scoreDesc.textContent = t('descWarning');\r\n    } else {\r\n      elements.scoreText.textContent = t('scoreDanger');\r\n      elements.scoreDesc.textContent = t('descDanger');\r\n    }\r\n\r\n    elements.scoreCard.classList.remove('is-hidden');\r\n\r\n    const order = { fail: 0, warn: 1, pass: 2 };\r\n    analysis.checks.sort((a, b) => (order[a.status] || 1) - (order[b.status] || 1));\r\n\r\n    while (elements.checksList.firstChild) {\r\n      elements.checksList.removeChild(elements.checksList.firstChild);\r\n    }\r\n\r\n    for (const check of analysis.checks) {\r\n      elements.checksList.appendChild(createCheckItem(check));\r\n    }\r\n\r\n    elements.checksCard.classList.remove('is-hidden');\r\n\r\n    \/\/ Show export buttons\r\n    if (elements.exportButtons) {\r\n      elements.exportButtons.classList.remove('is-hidden');\r\n    }\r\n\r\n    setTimeout(() => elements.scoreCard.scrollIntoView({ behavior: 'smooth', block: 'nearest' }), 100);\r\n  }\r\n\r\n  \/\/ === Actions ===\r\n  let isAnalyzing = false;\r\n\r\n  async function analyze() {\r\n    if (isAnalyzing) return;\r\n\r\n    const now = Date.now();\r\n    if (now - lastAnalysisTime < MIN_ANALYSIS_INTERVAL) return;\r\n    lastAnalysisTime = now;\r\n\r\n    const rawUrl = elements.urlInput.value;\r\n    const url = sanitizeInput(rawUrl);\r\n\r\n    if (!url) {\r\n      elements.errors.textContent = t('errorEmpty');\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    if (rawUrl.length > MAX_URL_LENGTH) {\r\n      elements.errors.textContent = t('errorTooLong', { max: MAX_URL_LENGTH });\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    if (containsDangerousPatterns(rawUrl)) {\r\n      elements.errors.textContent = t('errorDangerous');\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    elements.errors.classList.add('is-hidden');\r\n    isAnalyzing = true;\r\n\r\n    \/\/ Announce to screen readers that analysis is starting\r\n    announceToSR(currentLang === 'ro' ? 'Se verific\u0103 URL-ul...' : 'Analyzing URL...');\r\n\r\n    const analyzeBtn = root.querySelector('[data-action=\"analyze\"]');\r\n    const originalBtnText = analyzeBtn ? analyzeBtn.innerHTML : '';\r\n    if (analyzeBtn) {\r\n      analyzeBtn.innerHTML = '<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" class=\"zic2__spinner\"><circle cx=\"12\" cy=\"12\" r=\"10\" stroke-dasharray=\"32\" stroke-dashoffset=\"12\"\/><\/svg> ' + t('btnAnalyzing');\r\n      analyzeBtn.disabled = true;\r\n    }\r\n\r\n    \/\/ Show loading indicator and reset steps\r\n    if (elements.loading) {\r\n      elements.loading.classList.remove('is-hidden');\r\n      resetLoadingSteps();\r\n      updateLoadingStep('local', 'checking');\r\n    }\r\n\r\n    try {\r\n      const analysis = analyzeURL(url);\r\n      updateLoadingStep('local', 'done');\r\n\r\n      if (!analysis.valid) {\r\n        elements.errors.textContent = t('errorInvalid');\r\n        elements.errors.classList.remove('is-hidden');\r\n        if (elements.loading) elements.loading.classList.add('is-hidden');\r\n        return;\r\n      }\r\n\r\n      let fullUrl = url;\r\n      if (!fullUrl.match(\/^https?:\\\/\\\/\/i)) fullUrl = 'https:\/\/' + fullUrl;\r\n\r\n      const apiChecksPromise = runAPIChecks(fullUrl);\r\n      displayResults(analysis);\r\n\r\n      if (elements.apiStatus) {\r\n        elements.apiStatus.classList.remove('is-hidden');\r\n        resetApiStatus();\r\n      }\r\n\r\n      const apiResults = await apiChecksPromise;\r\n\r\n      \/\/ Process Google Safe Browsing\r\n      if (apiResults.googleSafeBrowsing.checked) {\r\n        if (!apiResults.googleSafeBrowsing.safe) {\r\n          const threats = apiResults.googleSafeBrowsing.threats || [currentLang === 'ro' ? 'Amenin\u021bare detectat\u0103' : 'Threat detected'];\r\n          analysis.checks.unshift({ status: 'fail', title: t('googleFail'), description: t('googleFailDesc', { threats: threats.join(', ') }) });\r\n          analysis.score = Math.max(0, analysis.score - 40);\r\n          updateApiStatus(elements.apiGoogle, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('googleOk'), description: t('googleOkDesc') });\r\n          updateApiStatus(elements.apiGoogle, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiGoogle, 'error');\r\n      }\r\n\r\n      \/\/ Process VirusTotal\r\n      if (apiResults.virusTotal.checked) {\r\n        if (!apiResults.virusTotal.safe) {\r\n          analysis.checks.unshift({ status: 'fail', title: t('vtFail'), description: t('vtFailDesc', { count: apiResults.virusTotal.malicious }) });\r\n          analysis.score = Math.max(0, analysis.score - 30);\r\n          updateApiStatus(elements.apiVirusTotal, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('vtOk'), description: t('vtOkDesc') });\r\n          updateApiStatus(elements.apiVirusTotal, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiVirusTotal, 'error');\r\n      }\r\n\r\n      \/\/ Process URLhaus\r\n      if (apiResults.urlhaus.checked) {\r\n        if (!apiResults.urlhaus.safe) {\r\n          analysis.checks.unshift({ status: 'fail', title: t('urlhausFail'), description: t('urlhausFailDesc', { threat: apiResults.urlhaus.threat || (currentLang === 'ro' ? 'necunoscut' : 'unknown') }) });\r\n          analysis.score = Math.max(0, analysis.score - 35);\r\n          updateApiStatus(elements.apiURLhaus, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('urlhausOk'), description: t('urlhausOkDesc') });\r\n          updateApiStatus(elements.apiURLhaus, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiURLhaus, 'error');\r\n      }\r\n\r\n      \/\/ Process urlscan.io\r\n      if (apiResults.urlscan.checked) {\r\n        if (!apiResults.urlscan.safe) {\r\n          const verdicts = apiResults.urlscan.verdicts || [];\r\n          analysis.checks.unshift({ status: 'fail', title: t('urlscanFail'), description: t('urlscanFailDesc', { verdicts: verdicts.join(', ') || 'suspect' }) });\r\n          analysis.score = Math.max(0, analysis.score - 25);\r\n          updateApiStatus(elements.apiUrlscan, 'warning');\r\n        } else {\r\n          const totalScans = apiResults.urlscan.total || 0;\r\n          const scansText = totalScans > 0 ? (currentLang === 'ro' ? ' (' + totalScans + ' scan\u0103ri anterioare)' : ' (' + totalScans + ' previous scans)') : '';\r\n          analysis.checks.push({ status: 'pass', title: t('urlscanOk'), description: t('urlscanOkDesc', { scans: scansText }) });\r\n          updateApiStatus(elements.apiUrlscan, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiUrlscan, 'error');\r\n      }\r\n\r\n      \/\/ Process PhishTank\r\n      if (apiResults.phishtank.checked) {\r\n        if (!apiResults.phishtank.safe) {\r\n          analysis.checks.unshift({ status: 'fail', title: t('phishtankFail'), description: t('phishtankFailDesc') });\r\n          analysis.score = Math.max(0, analysis.score - 40);\r\n          updateApiStatus(elements.apiPhishTank, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('phishtankOk'), description: t('phishtankOkDesc') });\r\n          updateApiStatus(elements.apiPhishTank, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiPhishTank, 'error');\r\n      }\r\n\r\n      \/\/ === NOI VERIFIC\u0102RI v3 ===\r\n\r\n      \/\/ Process WHOIS (v\u00e2rsta domeniului)\r\n      if (apiResults.whois && apiResults.whois.checked) {\r\n        const whoisData = apiResults.whois;\r\n        if (whoisData.analysis?.isNew) {\r\n          \/\/ Domeniu < 30 zile = foarte suspect\r\n          analysis.checks.unshift({\r\n            status: 'fail',\r\n            title: currentLang === 'ro' ? 'Domeniu foarte nou' : 'Very new domain',\r\n            description: currentLang === 'ro'\r\n              ? `Domeniul a fost creat acum ${whoisData.dates.ageInDays} zile. Domeniile noi sunt frecvent folosite pentru phishing.`\r\n              : `Domain was created ${whoisData.dates.ageInDays} days ago. New domains are frequently used for phishing.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 25);\r\n        } else if (whoisData.analysis?.isYoung) {\r\n          \/\/ Domeniu < 1 an = aten\u021bie\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'Domeniu relativ nou' : 'Relatively new domain',\r\n            description: currentLang === 'ro'\r\n              ? `Domeniul a fost creat acum ${whoisData.dates.ageInDays} zile (sub 1 an). Verific\u0103 legitimitatea.`\r\n              : `Domain was created ${whoisData.dates.ageInDays} days ago (under 1 year). Verify legitimacy.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 10);\r\n        } else if (whoisData.dates?.ageInDays) {\r\n          \/\/ Domeniu vechi = bun semn\r\n          const years = Math.floor(whoisData.dates.ageInDays \/ 365);\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'Domeniu vechi' : 'Established domain',\r\n            description: currentLang === 'ro'\r\n              ? `Domeniul are ${years} an${years !== 1 ? 'i' : ''} vechime. Registrar: ${whoisData.registrar || 'necunoscut'}`\r\n              : `Domain is ${years} year${years !== 1 ? 's' : ''} old. Registrar: ${whoisData.registrar || 'unknown'}`\r\n          });\r\n        }\r\n      }\r\n\r\n      \/\/ Process GeoIP (loca\u021bia serverului)\r\n      if (apiResults.geoip && apiResults.geoip.checked) {\r\n        const geoData = apiResults.geoip;\r\n        const location = geoData.location;\r\n\r\n        \/\/ Verific\u0103 dac\u0103 e brand rom\u00e2nesc pe server din afara UE\r\n        const euCountries = ['RO', 'DE', 'FR', 'NL', 'BE', 'AT', 'PL', 'CZ', 'HU', 'IT', 'ES', 'PT', 'IE', 'SE', 'FI', 'DK', 'BG', 'HR', 'SK', 'SI', 'LT', 'LV', 'EE', 'CY', 'MT', 'LU', 'GR'];\r\n        const suspiciousCountries = ['CN', 'RU', 'KP', 'IR'];\r\n\r\n        if (suspiciousCountries.includes(location?.countryCode)) {\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'Server \u00een \u021bar\u0103 suspect\u0103' : 'Server in suspicious country',\r\n            description: currentLang === 'ro'\r\n              ? `Serverul este localizat \u00een ${location.country}. Acest lucru poate fi suspect pentru site-uri care pretind a fi rom\u00e2ne\u0219ti sau occidentale.`\r\n              : `Server is located in ${location.country}. This may be suspicious for sites claiming to be Romanian or Western.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 15);\r\n        } else {\r\n          \/\/ Informa\u021bie neutr\u0103 despre loca\u021bie\r\n          const isHosting = geoData.network?.isHosting ? (currentLang === 'ro' ? ' (hosting\/cloud)' : ' (hosting\/cloud)') : '';\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'Loca\u021bie server' : 'Server location',\r\n            description: currentLang === 'ro'\r\n              ? `Server \u00een ${location.country} (${location.city || 'N\/A'})${isHosting}. ISP: ${geoData.network?.isp || 'N\/A'}`\r\n              : `Server in ${location.country} (${location.city || 'N\/A'})${isHosting}. ISP: ${geoData.network?.isp || 'N\/A'}`\r\n          });\r\n        }\r\n      }\r\n\r\n      \/\/ Process DNS (verificare DNS records)\r\n      if (apiResults.dns && apiResults.dns.checked) {\r\n        const dnsData = apiResults.dns;\r\n        const analysis_dns = dnsData.analysis;\r\n\r\n        if (!analysis_dns?.hasIpAddresses) {\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'DNS: f\u0103r\u0103 IP' : 'DNS: no IP',\r\n            description: currentLang === 'ro'\r\n              ? 'Domeniul nu are \u00eenregistr\u0103ri DNS A. Poate fi un domeniu parcat sau nefunc\u021bional.'\r\n              : 'Domain has no A DNS records. May be a parked or non-functional domain.'\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 10);\r\n        } else if (!analysis_dns?.hasMailServers && !analysis_dns?.hasSpf) {\r\n          \/\/ F\u0103r\u0103 MX \u0219i f\u0103r\u0103 SPF = probabil nu e un business legitim\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'DNS: configurare minim\u0103' : 'DNS: minimal setup',\r\n            description: currentLang === 'ro'\r\n              ? 'Domeniul nu are server de email (MX) sau protec\u021bie SPF. Companiile legitime au de obicei aceste configur\u0103ri.'\r\n              : 'Domain has no email server (MX) or SPF protection. Legitimate companies usually have these configured.'\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 5);\r\n        }\r\n      }\r\n\r\n      \/\/ Process SSL (certificat SSL)\r\n      if (apiResults.ssl && apiResults.ssl.checked && !apiResults.ssl.analyzing) {\r\n        const sslData = apiResults.ssl;\r\n\r\n        if (sslData.analysis?.isGradeF || sslData.grade === 'F') {\r\n          analysis.checks.unshift({\r\n            status: 'fail',\r\n            title: currentLang === 'ro' ? 'SSL: Certificat problematic' : 'SSL: Problematic certificate',\r\n            description: currentLang === 'ro'\r\n              ? `Certificatul SSL are probleme grave (grad ${sslData.grade}). Conexiunea nu este sigur\u0103.`\r\n              : `SSL certificate has serious issues (grade ${sslData.grade}). Connection is not secure.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 20);\r\n        } else if (sslData.analysis?.isGradeA) {\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'SSL: Certificat excelent' : 'SSL: Excellent certificate',\r\n            description: currentLang === 'ro'\r\n              ? `Certificat SSL valid (grad ${sslData.grade}). Emis de: ${sslData.cert?.issuer || 'N\/A'}`\r\n              : `Valid SSL certificate (grade ${sslData.grade}). Issued by: ${sslData.cert?.issuer || 'N\/A'}`\r\n          });\r\n        } else if (sslData.grade) {\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'SSL: Certificat valid' : 'SSL: Valid certificate',\r\n            description: currentLang === 'ro'\r\n              ? `Certificat SSL valid (grad ${sslData.grade}). Emis de: ${sslData.cert?.issuer || 'N\/A'}`\r\n              : `Valid SSL certificate (grade ${sslData.grade}). Issued by: ${sslData.cert?.issuer || 'N\/A'}`\r\n          });\r\n        }\r\n      }\r\n\r\n      \/\/ Recalculate risk level\r\n      analysis.riskLevel = analysis.score >= SCORE_THRESHOLDS.safe ? 'safe' : analysis.score >= SCORE_THRESHOLDS.warning ? 'warning' : 'danger';\r\n      displayResults(analysis);\r\n\r\n      \/\/ Announce result to screen readers\r\n      const riskLabel = analysis.riskLevel === 'danger'\r\n        ? (currentLang === 'ro' ? 'Periculos' : 'Dangerous')\r\n        : analysis.riskLevel === 'warning'\r\n          ? (currentLang === 'ro' ? 'Aten\u021bie' : 'Warning')\r\n          : (currentLang === 'ro' ? 'Sigur' : 'Safe');\r\n      announceToSR(\r\n        currentLang === 'ro'\r\n          ? `Analiz\u0103 complet\u0103. Scor: ${analysis.score} din 100. Nivel de risc: ${riskLabel}.`\r\n          : `Analysis complete. Score: ${analysis.score} out of 100. Risk level: ${riskLabel}.`,\r\n        analysis.riskLevel === 'danger' ? 'assertive' : 'polite'\r\n      );\r\n\r\n    } catch (error) {\r\n      console.error('Analysis error:', error);\r\n      elements.errors.textContent = t('errorGeneral');\r\n      elements.errors.classList.remove('is-hidden');\r\n    } finally {\r\n      isAnalyzing = false;\r\n      \/\/ Hide loading indicator\r\n      if (elements.loading) {\r\n        elements.loading.classList.add('is-hidden');\r\n      }\r\n      if (analyzeBtn) {\r\n        analyzeBtn.innerHTML = originalBtnText;\r\n        analyzeBtn.disabled = false;\r\n      }\r\n    }\r\n  }\r\n\r\n  function reset() {\r\n    elements.urlInput.value = '';\r\n    if (elements.urlBatch) elements.urlBatch.value = '';\r\n    elements.errors.classList.add('is-hidden');\r\n    elements.errors.textContent = '';\r\n    elements.scoreCard.classList.add('is-hidden');\r\n    elements.checksCard.classList.add('is-hidden');\r\n    if (elements.apiStatus) elements.apiStatus.classList.add('is-hidden');\r\n    if (elements.loading) elements.loading.classList.add('is-hidden');\r\n    if (elements.exportButtons) elements.exportButtons.classList.add('is-hidden');\r\n    if (elements.batchResults) elements.batchResults.classList.add('is-hidden');\r\n    while (elements.checksList.firstChild) elements.checksList.removeChild(elements.checksList.firstChild);\r\n    if (elements.batchTbody) while (elements.batchTbody.firstChild) elements.batchTbody.removeChild(elements.batchTbody.firstChild);\r\n    lastAnalysis = null;\r\n    lastBatchResults = [];\r\n    elements.urlInput.focus();\r\n  }\r\n\r\n  \/\/ === BATCH MODE ===\r\n  function toggleBatchMode() {\r\n    const isBatch = elements.batchMode?.checked;\r\n    if (elements.singleInput) elements.singleInput.classList.toggle('is-hidden', isBatch);\r\n    if (elements.batchInput) elements.batchInput.classList.toggle('is-hidden', !isBatch);\r\n  }\r\n\r\n  async function analyzeBatch() {\r\n    const batchText = elements.urlBatch?.value || '';\r\n    const allUrls = batchText.split('\\n').map(u => u.trim()).filter(u => u.length > 0);\r\n    const urls = allUrls.slice(0, BATCH_LIMIT);\r\n\r\n    if (urls.length === 0) {\r\n      elements.errors.textContent = currentLang === 'ro' ? 'Introdu cel pu\u021bin un URL.' : 'Enter at least one URL.';\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    \/\/ Show warning if URLs were truncated\r\n    if (allUrls.length > BATCH_LIMIT) {\r\n      const warningMsg = t('batchTruncated', { count: BATCH_LIMIT, total: allUrls.length });\r\n      elements.errors.textContent = warningMsg;\r\n      elements.errors.classList.remove('is-hidden');\r\n      elements.errors.style.background = 'var(--zic-warning-light)';\r\n      elements.errors.style.borderColor = 'var(--zic-warning)';\r\n      elements.errors.style.color = 'var(--zic-ink)';\r\n    } else {\r\n      elements.errors.classList.add('is-hidden');\r\n      elements.errors.style.background = '';\r\n      elements.errors.style.borderColor = '';\r\n      elements.errors.style.color = '';\r\n    }\r\n\r\n    if (elements.loading) {\r\n      const loadingText = elements.loading.querySelector('.zic2__loadingText');\r\n      const loadingSub = elements.loading.querySelector('.zic2__loadingSubtext');\r\n      if (loadingText) loadingText.textContent = currentLang === 'ro' ? `Se verific\u0103 ${urls.length} URL-uri...` : `Checking ${urls.length} URLs...`;\r\n      if (loadingSub) loadingSub.textContent = currentLang === 'ro' ? 'Acest proces poate dura c\u00e2teva minute' : 'This may take a few minutes';\r\n      elements.loading.classList.remove('is-hidden');\r\n    }\r\n\r\n    \/\/ Don't hide errors if we just showed a truncation warning\r\n    if (allUrls.length <= BATCH_LIMIT) {\r\n      elements.errors.classList.add('is-hidden');\r\n    }\r\n    elements.scoreCard.classList.add('is-hidden');\r\n    elements.checksCard.classList.add('is-hidden');\r\n    lastBatchResults = [];\r\n\r\n    try {\r\n      for (let i = 0; i < urls.length; i++) {\r\n        const url = urls[i];\r\n        try {\r\n          let fullUrl = sanitizeInput(url);\r\n          if (!fullUrl.match(\/^https?:\\\/\\\/\/i)) fullUrl = 'https:\/\/' + fullUrl;\r\n\r\n          const extraction = extractDomain(fullUrl);\r\n          if (!extraction.valid) {\r\n            lastBatchResults.push({ url: url, score: 0, riskLevel: 'danger', error: currentLang === 'ro' ? 'URL invalid' : 'Invalid URL', checks: [] });\r\n            continue;\r\n          }\r\n\r\n          const analysis = analyzeUrlLocally(extraction);\r\n          analysis.url = fullUrl;\r\n          const apiResults = await runAPIChecks(fullUrl);\r\n\r\n          if (apiResults.googleSafeBrowsing?.checked && !apiResults.googleSafeBrowsing.safe) analysis.score = Math.max(0, analysis.score - 40);\r\n          if (apiResults.virusTotal?.checked && !apiResults.virusTotal.safe) analysis.score = Math.max(0, analysis.score - 30);\r\n          if (apiResults.urlhaus?.checked && !apiResults.urlhaus.safe) analysis.score = Math.max(0, analysis.score - 35);\r\n          if (apiResults.whois?.checked && apiResults.whois.analysis?.isNew) analysis.score = Math.max(0, analysis.score - 25);\r\n\r\n          analysis.riskLevel = analysis.score >= SCORE_THRESHOLDS.safe ? 'safe' : analysis.score >= SCORE_THRESHOLDS.warning ? 'warning' : 'danger';\r\n          lastBatchResults.push(analysis);\r\n        } catch (err) {\r\n          lastBatchResults.push({ url: url, score: 0, riskLevel: 'danger', error: err.message, checks: [] });\r\n        }\r\n      }\r\n      displayBatchResults();\r\n    } catch (error) {\r\n      console.error('Batch analysis error:', error);\r\n      elements.errors.textContent = currentLang === 'ro' ? 'Eroare \u00een analiza batch.' : 'Batch analysis error.';\r\n      elements.errors.classList.remove('is-hidden');\r\n    } finally {\r\n      if (elements.loading) elements.loading.classList.add('is-hidden');\r\n    }\r\n  }\r\n\r\n  function displayBatchResults() {\r\n    if (!elements.batchTbody || lastBatchResults.length === 0) return;\r\n    while (elements.batchTbody.firstChild) elements.batchTbody.removeChild(elements.batchTbody.firstChild);\r\n\r\n    const riskColors = getRiskColors();\r\n    const riskLabels = { safe: currentLang === 'ro' ? 'Sigur' : 'Safe', warning: currentLang === 'ro' ? 'Aten\u021bie' : 'Warning', danger: currentLang === 'ro' ? 'Pericol' : 'Danger' };\r\n\r\n    lastBatchResults.forEach((result, idx) => {\r\n      const tr = document.createElement('tr');\r\n      tr.style.borderBottom = '1px solid rgba(138, 136, 255, 0.1)';\r\n\r\n      const failChecks = result.checks?.filter(c => c.status === 'fail').map(c => c.title).slice(0, 3) || [];\r\n      const issues = result.error || failChecks.join(', ') || (currentLang === 'ro' ? 'Nicio problem\u0103' : 'No issues');\r\n\r\n      \/\/ Create cells safely with textContent\r\n      const tdNum = document.createElement('td');\r\n      tdNum.style.cssText = 'padding: 10px; font-weight: 600;';\r\n      tdNum.textContent = String(idx + 1);\r\n\r\n      const tdUrl = document.createElement('td');\r\n      tdUrl.style.cssText = 'padding: 10px; max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;';\r\n      tdUrl.title = result.url;\r\n      tdUrl.textContent = result.url;\r\n\r\n      const tdScore = document.createElement('td');\r\n      tdScore.style.cssText = 'padding: 10px; text-align: center; font-weight: 700;';\r\n      tdScore.style.color = riskColors[result.riskLevel];\r\n      tdScore.textContent = String(result.score);\r\n\r\n      const tdRisk = document.createElement('td');\r\n      tdRisk.style.cssText = 'padding: 10px; text-align: center;';\r\n      const riskSpan = document.createElement('span');\r\n      riskSpan.style.cssText = `background: ${riskColors[result.riskLevel]}20; color: ${riskColors[result.riskLevel]}; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 600;`;\r\n      riskSpan.textContent = riskLabels[result.riskLevel];\r\n      tdRisk.appendChild(riskSpan);\r\n\r\n      const tdIssues = document.createElement('td');\r\n      tdIssues.style.cssText = 'padding: 10px; font-size: 12px;';\r\n      if (result.error) tdIssues.style.color = '#ef4444';\r\n      tdIssues.textContent = issues;\r\n\r\n      tr.appendChild(tdNum);\r\n      tr.appendChild(tdUrl);\r\n      tr.appendChild(tdScore);\r\n      tr.appendChild(tdRisk);\r\n      tr.appendChild(tdIssues);\r\n      elements.batchTbody.appendChild(tr);\r\n    });\r\n\r\n    elements.batchResults.classList.remove('is-hidden');\r\n  }\r\n\r\n  \/\/ === EXPORT FUNCTIONS ===\r\n  function exportJSON(data, filename) {\r\n    const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application\/json' });\r\n    const url = URL.createObjectURL(blob);\r\n    const a = document.createElement('a');\r\n    a.href = url;\r\n    a.download = filename;\r\n    document.body.appendChild(a);\r\n    a.click();\r\n    document.body.removeChild(a);\r\n    URL.revokeObjectURL(url);\r\n  }\r\n\r\n  function exportCSV(data, filename) {\r\n    let csv = '';\r\n    if (Array.isArray(data)) {\r\n      csv = 'Nr,URL,Scor,Risc,Probleme\\n';\r\n      data.forEach((r, i) => {\r\n        const issues = r.error || r.checks?.filter(c => c.status === 'fail').map(c => c.title).join('; ') || '';\r\n        csv += `${i + 1},\"${r.url}\",${r.score},${r.riskLevel},\"${issues}\"\\n`;\r\n      });\r\n    } else {\r\n      csv = 'URL,Scor,Risc,Verificare,Status,Detalii\\n';\r\n      data.checks?.forEach(c => {\r\n        csv += `\"${data.url}\",${data.score},${data.riskLevel},\"${c.title}\",${c.status},\"${(c.description || '').replace(\/\"\/g, '\"\"')}\"\\n`;\r\n      });\r\n    }\r\n    const blob = new Blob([csv], { type: 'text\/csv;charset=utf-8;' });\r\n    const url = URL.createObjectURL(blob);\r\n    const a = document.createElement('a');\r\n    a.href = url;\r\n    a.download = filename;\r\n    document.body.appendChild(a);\r\n    a.click();\r\n    document.body.removeChild(a);\r\n    URL.revokeObjectURL(url);\r\n  }\r\n\r\n  function copyResultsToClipboard() {\r\n    if (!lastAnalysis) return;\r\n    let text = `=== ZIC Security Check ===\\nURL: ${lastAnalysis.url}\\nScor: ${lastAnalysis.score}\/100 (${lastAnalysis.riskLevel})\\n\\nVerific\u0103ri:\\n`;\r\n    lastAnalysis.checks?.forEach(c => {\r\n      const icon = c.status === 'pass' ? '\u2713' : c.status === 'fail' ? '\u2717' : '&#x26a0;';\r\n      text += `${icon} ${c.title}\\n`;\r\n    });\r\n    navigator.clipboard.writeText(text).then(() => {\r\n      alert(currentLang === 'ro' ? 'Rezultatele au fost copiate!' : 'Results copied!');\r\n    }).catch(err => console.error('Copy failed:', err));\r\n  }\r\n\r\n  \/\/ === SHARE FUNCTIONS ===\r\n  function shareResultLink(button) {\r\n    if (!lastAnalysis) return;\r\n\r\n    \/\/ Compress minimal result data to share\r\n    const shareData = {\r\n      u: lastAnalysis.url,\r\n      s: lastAnalysis.score,\r\n      r: lastAnalysis.riskLevel,\r\n      t: Date.now()\r\n    };\r\n\r\n    try {\r\n      \/\/ Encode to base64 for URL safety\r\n      const encoded = btoa(JSON.stringify(shareData));\r\n      const shareUrl = window.location.origin + window.location.pathname + '#share=' + encoded;\r\n\r\n      \/\/ Copy to clipboard\r\n      navigator.clipboard.writeText(shareUrl).then(() => {\r\n        \/\/ Show feedback\r\n        const originalText = button.querySelector('[data-i18n=\"shareLink\"]');\r\n        if (originalText) {\r\n          const original = originalText.textContent;\r\n          originalText.textContent = t('shareLinkCopied');\r\n          button.classList.add('is-success');\r\n          setTimeout(() => {\r\n            originalText.textContent = original;\r\n            button.classList.remove('is-success');\r\n          }, 2000);\r\n        }\r\n      }).catch(err => {\r\n        console.error('Share link copy failed:', err);\r\n        alert(currentLang === 'ro' ? 'Nu s-a putut copia link-ul' : 'Could not copy link');\r\n      });\r\n    } catch (e) {\r\n      console.error('Share encoding failed:', e);\r\n    }\r\n  }\r\n\r\n  \/\/ Check for shared results on page load\r\n  function loadSharedResults() {\r\n    const hash = window.location.hash;\r\n    if (!hash.startsWith('#share=')) return;\r\n\r\n    try {\r\n      const encoded = hash.slice(7);\r\n      const shareData = JSON.parse(atob(encoded));\r\n\r\n      if (shareData.u && typeof shareData.s === 'number') {\r\n        \/\/ Pre-fill the URL and show a minimal result display\r\n        elements.urlInput.value = shareData.u;\r\n\r\n        \/\/ Create a minimal analysis object for display\r\n        const sharedAnalysis = {\r\n          url: shareData.u,\r\n          score: shareData.s,\r\n          riskLevel: shareData.r || (shareData.s >= 70 ? 'safe' : shareData.s >= 40 ? 'warning' : 'danger'),\r\n          checks: [],\r\n          apiResults: {},\r\n          timestamp: shareData.t\r\n        };\r\n\r\n        \/\/ Display shared results with a note\r\n        displayResults(sharedAnalysis);\r\n\r\n        \/\/ Add shared indicator\r\n        const note = document.createElement('p');\r\n        note.className = 'zic2__sharedNote';\r\n        note.textContent = currentLang === 'ro'\r\n          ? '&#x26a0; Acesta este un rezultat partajat. Ruleaz\u0103 o verificare nou\u0103 pentru rezultate complete.'\r\n          : '&#x26a0; This is a shared result. Run a new check for complete results.';\r\n        elements.scoreCard.insertBefore(note, elements.scoreCard.firstChild);\r\n      }\r\n    } catch (e) {\r\n      console.error('Invalid share data:', e);\r\n    }\r\n  }\r\n\r\n  \/\/ === HISTORY FUNCTIONS ===\r\n  const HISTORY_KEY = 'zic_spoofing_history';\r\n  const MAX_HISTORY = 50;\r\n  const HISTORY_MAX_AGE_DAYS = 30;\r\n\r\n  function getHistory() {\r\n    try {\r\n      const history = JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]');\r\n      \/\/ Sort by timestamp descending (newest first)\r\n      return history.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));\r\n    } catch (e) {\r\n      return [];\r\n    }\r\n  }\r\n\r\n  function cleanOldHistory() {\r\n    try {\r\n      const history = JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]');\r\n      const cutoff = Date.now() - (HISTORY_MAX_AGE_DAYS * 24 * 60 * 60 * 1000);\r\n      const cleaned = history.filter(item => (item.timestamp || 0) > cutoff);\r\n      if (cleaned.length !== history.length) {\r\n        localStorage.setItem(HISTORY_KEY, JSON.stringify(cleaned.slice(0, MAX_HISTORY)));\r\n        return true;\r\n      }\r\n      return false;\r\n    } catch (e) {\r\n      return false;\r\n    }\r\n  }\r\n\r\n  function saveToHistory(analysis) {\r\n    if (!analysis?.url) return;\r\n    try {\r\n      const history = getHistory();\r\n      history.unshift({\r\n        url: analysis.url,\r\n        score: analysis.score,\r\n        riskLevel: analysis.riskLevel,\r\n        timestamp: Date.now(),\r\n        checksCount: analysis.checks?.length || 0,\r\n        failCount: analysis.checks?.filter(c => c.status === 'fail').length || 0\r\n      });\r\n      localStorage.setItem(HISTORY_KEY, JSON.stringify(history.slice(0, MAX_HISTORY)));\r\n      updateHistoryBadge();\r\n    } catch (e) {\r\n      console.warn('Could not save to history:', e);\r\n    }\r\n  }\r\n\r\n  function updateHistoryBadge() {\r\n    const history = getHistory();\r\n    if (elements.historyBadge) {\r\n      elements.historyBadge.textContent = history.length > 0 ? String(history.length) : '';\r\n      elements.historyBadge.style.display = history.length > 0 ? 'inline' : 'none';\r\n    }\r\n    if (elements.historyCount) {\r\n      elements.historyCount.textContent = history.length > 0 ? `(${history.length})` : '';\r\n    }\r\n  }\r\n\r\n  function displayHistory() {\r\n    const history = getHistory();\r\n    if (!elements.historyList) return;\r\n\r\n    while (elements.historyList.firstChild) elements.historyList.removeChild(elements.historyList.firstChild);\r\n\r\n    if (history.length === 0) {\r\n      const emptyMsg = document.createElement('div');\r\n      emptyMsg.style.cssText = 'padding: 20px; text-align: center; color: var(--zic-text-muted); font-size: 13px;';\r\n      emptyMsg.textContent = currentLang === 'ro' ? 'Nu exist\u0103 verific\u0103ri anterioare.' : 'No previous checks.';\r\n      elements.historyList.appendChild(emptyMsg);\r\n      return;\r\n    }\r\n\r\n    const riskColors = getRiskColors();\r\n\r\n    history.forEach((item, idx) => {\r\n      const div = document.createElement('div');\r\n      div.style.cssText = 'padding: 10px 12px; border-bottom: 1px solid rgba(138, 136, 255, 0.1); display: flex; align-items: center; gap: 10px; cursor: pointer;';\r\n      div.addEventListener('click', () => {\r\n        elements.urlInput.value = item.url;\r\n        if (elements.batchMode) elements.batchMode.checked = false;\r\n        toggleBatchMode();\r\n        elements.historySection?.classList.add('is-hidden');\r\n      });\r\n\r\n      const scoreSpan = document.createElement('span');\r\n      scoreSpan.style.cssText = `min-width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; background: ${riskColors[item.riskLevel]}20; color: ${riskColors[item.riskLevel]};`;\r\n      scoreSpan.textContent = String(item.score);\r\n\r\n      const infoDiv = document.createElement('div');\r\n      infoDiv.style.cssText = 'flex: 1; min-width: 0;';\r\n\r\n      const urlDiv = document.createElement('div');\r\n      urlDiv.style.cssText = 'font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;';\r\n      urlDiv.textContent = item.url;\r\n      urlDiv.title = item.url;\r\n\r\n      const metaDiv = document.createElement('div');\r\n      metaDiv.style.cssText = 'font-size: 11px; color: var(--zic-text-muted); margin-top: 2px;';\r\n      const date = new Date(item.timestamp);\r\n      metaDiv.textContent = date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\r\n      if (item.failCount > 0) metaDiv.textContent += ` \u2022 ${item.failCount} ${currentLang === 'ro' ? 'probleme' : 'issues'}`;\r\n\r\n      infoDiv.appendChild(urlDiv);\r\n      infoDiv.appendChild(metaDiv);\r\n      div.appendChild(scoreSpan);\r\n      div.appendChild(infoDiv);\r\n      elements.historyList.appendChild(div);\r\n    });\r\n  }\r\n\r\n  function showHistory() {\r\n    displayHistory();\r\n    elements.historySection?.classList.remove('is-hidden');\r\n    elements.historySection?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\r\n  }\r\n\r\n  function clearHistory() {\r\n    if (!confirm(currentLang === 'ro' ? '\u0218tergi tot istoricul?' : 'Clear all history?')) return;\r\n    try {\r\n      localStorage.removeItem(HISTORY_KEY);\r\n      updateHistoryBadge();\r\n      displayHistory();\r\n    } catch (e) {\r\n      console.warn('Could not clear history:', e);\r\n    }\r\n  }\r\n\r\n  \/\/ QR Code Processing\r\n  function processQRCode(file) {\r\n    if (!file || !file.type.startsWith('image\/')) {\r\n      showQRStatus('error', currentLang === 'ro' ? 'Fi\u0219ier invalid. \u00cencarc\u0103 o imagine.' : 'Invalid file. Please upload an image.');\r\n      return;\r\n    }\r\n\r\n    showQRStatus('loading', currentLang === 'ro' ? 'Se proceseaz\u0103 codul QR...' : 'Processing QR code...');\r\n\r\n    const reader = new FileReader();\r\n    reader.onload = function(e) {\r\n      const img = new Image();\r\n      img.onload = function() {\r\n        const canvas = document.createElement('canvas');\r\n        const ctx = canvas.getContext('2d');\r\n        canvas.width = img.width;\r\n        canvas.height = img.height;\r\n        ctx.drawImage(img, 0, 0);\r\n\r\n        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n\r\n        if (typeof jsQR === 'undefined') {\r\n          showQRStatus('error', currentLang === 'ro' ? 'Biblioteca QR nu este \u00eenc\u0103rcat\u0103.' : 'QR library not loaded.');\r\n          return;\r\n        }\r\n\r\n        const code = jsQR(imageData.data, imageData.width, imageData.height);\r\n\r\n        if (code && code.data) {\r\n          const detectedUrl = code.data.trim();\r\n          \/\/ Check if it looks like a URL\r\n          if (detectedUrl.match(\/^https?:\\\/\\\/\/i) || detectedUrl.match(\/^www\\.\/i)) {\r\n            elements.urlInput.value = detectedUrl;\r\n            showQRStatus('success', currentLang === 'ro'\r\n              ? `URL detectat: ${truncateUrl(detectedUrl, 50)}`\r\n              : `URL detected: ${truncateUrl(detectedUrl, 50)}`);\r\n          } else {\r\n            showQRStatus('warning', currentLang === 'ro'\r\n              ? `Text detectat (nu e URL): ${truncateUrl(detectedUrl, 40)}`\r\n              : `Text detected (not URL): ${truncateUrl(detectedUrl, 40)}`);\r\n          }\r\n        } else {\r\n          showQRStatus('error', currentLang === 'ro'\r\n            ? 'Nu s-a g\u0103sit niciun cod QR \u00een imagine.'\r\n            : 'No QR code found in image.');\r\n        }\r\n      };\r\n      img.onerror = function() {\r\n        showQRStatus('error', currentLang === 'ro' ? 'Nu s-a putut \u00eenc\u0103rca imaginea.' : 'Could not load image.');\r\n      };\r\n      img.src = e.target.result;\r\n    };\r\n    reader.onerror = function() {\r\n      showQRStatus('error', currentLang === 'ro' ? 'Eroare la citirea fi\u0219ierului.' : 'Error reading file.');\r\n    };\r\n    reader.readAsDataURL(file);\r\n  }\r\n\r\n  function truncateUrl(url, maxLen) {\r\n    return url.length > maxLen ? url.substring(0, maxLen) + '...' : url;\r\n  }\r\n\r\n  function showQRStatus(type, message) {\r\n    if (!elements.qrStatus) return;\r\n    elements.qrStatus.classList.remove('is-hidden');\r\n    elements.qrStatus.textContent = message;\r\n    elements.qrStatus.style.background = type === 'success' ? 'var(--zic-safe-bg)' :\r\n                                          type === 'error' ? 'var(--zic-danger-bg)' :\r\n                                          type === 'warning' ? 'var(--zic-warning-bg)' :\r\n                                          'var(--zic-surface)';\r\n    elements.qrStatus.style.color = type === 'success' ? 'var(--zic-safe)' :\r\n                                     type === 'error' ? 'var(--zic-danger)' :\r\n                                     type === 'warning' ? 'var(--zic-warning)' :\r\n                                     'var(--zic-muted)';\r\n  }\r\n\r\n  function loadExample() {\r\n    const examples = [\r\n      'https:\/\/www.bancatransllvania.ro\/autentificare',\r\n      'https:\/\/paypa1-secure-login.suspicious-site.tk\/verify-account',\r\n      'https:\/\/secure.ernag-verificare.xyz\/cont',\r\n      'https:\/\/www.raiffelsen.ro\/login',\r\n      'https:\/\/anaf.gov.ro.verificare-ramburs.tk\/urgent'\r\n    ];\r\n    elements.urlInput.value = examples[Math.floor(Math.random() * examples.length)];\r\n  }\r\n\r\n  const VALID_ACTIONS = ['analyze', 'reset', 'example', 'toggleLang', 'toggleTheme', 'exportJSON', 'exportCSV', 'copyResults', 'exportBatchJSON', 'exportBatchCSV', 'showHistory', 'clearHistory', 'shareLink', 'printReport'];\r\n\r\n  function handleClick(e) {\r\n    const button = e.target.closest('[data-action]');\r\n    if (!button) return;\r\n    const action = button.dataset.action;\r\n    if (!VALID_ACTIONS.includes(action)) return;\r\n\r\n    if (action === 'analyze') {\r\n      if (elements.batchMode?.checked) analyzeBatch();\r\n      else analyze();\r\n    }\r\n    else if (action === 'reset') reset();\r\n    else if (action === 'example') loadExample();\r\n    else if (action === 'toggleLang') toggleLanguage();\r\n    else if (action === 'toggleTheme') toggleTheme();\r\n    else if (action === 'exportJSON' && lastAnalysis) exportJSON(lastAnalysis, `zic-security-${Date.now()}.json`);\r\n    else if (action === 'exportCSV' && lastAnalysis) exportCSV(lastAnalysis, `zic-security-${Date.now()}.csv`);\r\n    else if (action === 'copyResults') copyResultsToClipboard();\r\n    else if (action === 'exportBatchJSON' && lastBatchResults.length) exportJSON(lastBatchResults, `zic-batch-${Date.now()}.json`);\r\n    else if (action === 'exportBatchCSV' && lastBatchResults.length) exportCSV(lastBatchResults, `zic-batch-${Date.now()}.csv`);\r\n    else if (action === 'showHistory') showHistory();\r\n    else if (action === 'clearHistory') clearHistory();\r\n    else if (action === 'shareLink') shareResultLink(button);\r\n    else if (action === 'printReport') window.print();\r\n  }\r\n\r\n  function handleKeypress(e) {\r\n    if (e.key === 'Enter' && e.target === elements.urlInput) {\r\n      e.preventDefault();\r\n      analyze();\r\n    }\r\n  }\r\n\r\n  function init() {\r\n    if (!root || !elements.urlInput) {\r\n      console.error('ZIC Website Spoofing v2: Required elements not found');\r\n      return;\r\n    }\r\n    \/\/ Apply initial translations based on browser language\r\n    applyTranslations();\r\n\r\n    \/\/ Check for shared results in URL hash\r\n    loadSharedResults();\r\n\r\n    root.addEventListener('click', handleClick);\r\n    root.addEventListener('keypress', handleKeypress);\r\n\r\n    \/\/ Batch mode toggle listener\r\n    if (elements.batchMode) {\r\n      elements.batchMode.addEventListener('change', toggleBatchMode);\r\n    }\r\n\r\n    \/\/ Initialize history badge\r\n    updateHistoryBadge();\r\n\r\n    \/\/ QR Code upload listener\r\n    if (elements.qrUpload) {\r\n      elements.qrUpload.addEventListener('change', function(e) {\r\n        if (e.target.files && e.target.files[0]) {\r\n          processQRCode(e.target.files[0]);\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  if (document.readyState === 'loading') {\r\n    document.addEventListener('DOMContentLoaded', init);\r\n  } else {\r\n    init();\r\n  }\r\n})();\r\n<\/script>\r\n<\/div>\r\n\n\n\n<p class=\"whitespace-pre-wrap break-words\">Fraudele \u0219i infrac\u021biunile bancare reprezint\u0103 o problem\u0103 serioas\u0103 \u0219i deosebit de actual\u0103, av\u00e2nd poten\u021bialul de a afecta at\u00e2t persoanele fizice, c\u00e2t \u0219i companiile. Prin urmare, este important s\u0103 fi\u021bi con\u0219tient de riscuri \u0219i s\u0103 lua\u021bi m\u0103suri pentru a v\u0103 proteja de conduitele infrac\u021bionale devenite deja tradi\u021bionale. \u00cen acest articol voi analiza cele mai des \u00eent\u00e2lnite conduite infrac\u021bionale (pentru infrac\u021biuni informatice \u00een general, vezi <a href=\"https:\/\/zic.legal\/ro\/infractiuni-informatice-in-romania\/\">aici<\/a>), oferind acolo unde este cazul inclusiv m\u0103suri de preven\u021bie.<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Clonarea cardurilor la bancomat<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">Una dintre metodele folosite de infractori este clonarea cardurilor bancare la bancomate (ATM-uri). Ace\u0219tia instaleaz\u0103 dispozitive speciale la bancomate, numite <a href=\"https:\/\/zic.legal\/ro\/recursul-in-interesul-legii-nr-15-2013-folosirea-cardului-bancar-si-a-dispozitivului-tip-skimmer-la-bancomat\/\">skimmere<\/a>, care copiaz\u0103 datele de pe banda magnetic\u0103 a cardului atunci c\u00e2nd acesta este introdus \u00een bancomat. Ulterior, infractorii folosesc datele copiate de pe banda magnetic\u0103 pentru a crea carduri clonate (contraf\u0103cute) \u0219i a efectua tranzac\u021bii frauduloase.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Pentru a v\u0103 proteja \u00eempotriva clon\u0103rii cardurilor, examina\u021bi \u00eentotdeauna cu aten\u021bie bancomatele \u00eenainte de a v\u0103 introduce cardul. Dac\u0103 observa\u021bi orice dispozitiv suspect sau semne de manipulare (de exemplu, zg\u00e2rieturi \u00een zona \u00een care trebuie introdus cardul), nu folosi\u021bi acel bancomat \u0219i raporta\u021bi aceast\u0103 problem\u0103 b\u0103ncii. De asemenea, acoperi\u021bi \u00eentotdeauna tastatura c\u00e2nd introduce\u021bi codul PIN, pentru a \u00eempiedica eventualele camere ascunse s\u0103 v\u0103 surprind\u0103 codul PIN. Este posibil ca infractorii s\u0103 plaseze o tastatur\u0103 fals\u0103 peste tastatura bancomatului. Verifica\u021bi a\u0219adar \u00een ce m\u0103sur\u0103 tastatura are un &#8220;joc&#8221;, pentru a determina \u00een ce m\u0103sur\u0103 aceasta este autentic\u0103.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Dac\u0103 nu folosi\u021bi cardul dec\u00e2t pentru pl\u0103\u021bi la POS sau online \u0219i ave\u021bi posibilitatea de a bloca retragerile de la ATM (cum se poate proceda \u00een cazul unor servicii bancare precum Revolut), este recomandat s\u0103 bloca\u021bi aceast\u0103 func\u021bionalitate pentru a reduce riscul de fraud\u0103 \u00een cazul \u00een care cardul dumneavoastr\u0103 este clonat.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Este important s\u0103 re\u021bine\u021bi c\u0103 recent au \u00eenceput s\u0103 fie montate dispozitive tip skimmer inclusiv la terminalele POS. A\u0219adar, nu trebuie s\u0103 considera\u021bi c\u0103 atunci c\u00e2nd efectua\u021bi pl\u0103\u021bi cu cardul la POS, sunte\u021bi \u00een perfect\u0103 siguran\u021b\u0103. Fi\u021bi vigilent \u0219i verifica\u021bi \u00eentotdeauna terminalul POS \u00eenainte de a v\u0103 introduce cardul. Dac\u0103 observa\u021bi orice semn de manipulare sau dac\u0103 dispozitivul pare a fi modificat \u00een vreun fel, nu folosi\u021bi acel terminal POS.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">O alt\u0103 m\u0103sur\u0103 de precau\u021bie este utilizarea func\u021biei contactless la terminal POS, f\u0103r\u0103 folosirea bandei magnetice. Cardurile cu cip EMV sunt mult mai greu de clonat, deoarece datele sunt criptate \u0219i autentificate la fiecare tranzac\u021bie. Multe \u021b\u0103ri au adoptat deja tehnologia EMV ca standard pentru cardurile de plat\u0103, dar este important s\u0103 v\u0103 asigura\u021bi c\u0103 at\u00e2t cardul dumneavoastr\u0103, c\u00e2t \u0219i terminalele pe care le folosi\u021bi sunt compatibile EMV.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">\u00cen cele din urm\u0103, monitorizarea regulat\u0103 a tranzac\u021biilor contului dumneavoastr\u0103 este esen\u021bial\u0103. Verifica\u021bi-v\u0103 extrasele de cont \u00een mod regulat \u0219i raporta\u021bi imediat orice tranzac\u021bie suspect\u0103 sau nerecunoscut\u0103 b\u0103ncii dumneavoastr\u0103. Cu c\u00e2t raporta\u021bi mai repede o poten\u021bial\u0103 tranzac\u021bie frauduloas\u0103, cu at\u00e2t mai mari sunt \u0219ansele de a limita daunele \u0219i de a recupera eventualele fonduri pierdute.<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Phishing pentru ob\u021binerea datelor de card<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">O alt\u0103 metod\u0103 frecvent\u0103 este <a href=\"https:\/\/zic.legal\/ro\/email-spoofing-cum-identifici-un-email-fals\/\">phishingul<\/a>, prin care infractorii \u00eencearc\u0103 s\u0103 v\u0103 p\u0103c\u0103leasc\u0103 s\u0103 le dezv\u0103lui\u021bi informa\u021biile confiden\u021biale, cum ar fi datele cardului sau datele de autentificare pentru serviciile bancare online. De obicei, acest lucru se face prin e-mailuri sau site-uri web contraf\u0103cute care par a fi de la institu\u021bia dumneavoastr\u0103 bancar\u0103 sau de la o alt\u0103 institu\u021bie de \u00eencredere.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Pentru a v\u0103 proteja \u00eempotriva phishingului, fi\u021bi \u00eentotdeauna precaut cu e-mailurile sau site-urile web care v\u0103 cer informa\u021bii sensibile. Institu\u021biile bancare nu v\u0103 vor solicita niciodat\u0103 s\u0103 v\u0103 confirma\u021bi datele de autentificare sau ale cardului prin e-mail. Dac\u0103 ave\u021bi dubii, contacta\u021bi banca direct folosind un num\u0103r de telefon oficial. De asemenea, asigura\u021bi-v\u0103 c\u0103 site-urile web bancare pe care le accesa\u021bi folosesc criptare SSL (adic\u0103 \u00eencep cu &#8220;https:\/\/&#8221;).<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Este important de men\u021bionat c\u0103, pentru unele pl\u0103\u021bi online, nu este \u00eentotdeauna necesar codul CVV (codul de securitate de pe spatele cardului). De exemplu, pl\u0103\u021bile recurente sau abonamentele pot fi ini\u021biate f\u0103r\u0103 a introduce codul CVV de fiecare dat\u0103. Prin urmare, chiar dac\u0103 infractorii nu au acces la codul CVV, ei pot efectua \u00een continuare anumite tranzac\u021bii frauduloase folosind datele cardului ob\u021binute \u00een mod fraudulos.<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Folosirea unor programe informatice pentru accesul la distan\u021b\u0103<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">Infractorii pot folosi, de asemenea, programe mali\u021bioase (malware) pentru a ob\u021bine acces de la distan\u021b\u0103 la dispozitivele dumneavoastr\u0103. Odat\u0103 ce un dispozitiv este compromis, infractorii pot folosi accesul pentru a v\u0103 accesa serviciile bancare online \u0219i a efectua tranzac\u021bii neautorizate.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Ace\u0219tia pot folosi chiar programe informatice legitime precum AnyDesk sau TeamViewer. Atacatorii pot \u00eencerca s\u0103 v\u0103 conving\u0103 s\u0103 instala\u021bi aceste programe sub diverse pretexte, pentru a prelua controlul asupra dispozitivului de\u021binut de c\u0103tre dumneavoastr\u0103. Este important s\u0103 nu accepta\u021bi niciodat\u0103 instalarea unor astfel de programe la solicitarea unor persoane necunoscute.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Pentru a v\u0103 proteja \u00eempotriva malware-ului, asigura\u021bi-v\u0103 c\u0103 ave\u021bi instalat un program antivirus de \u00eencredere \u0219i c\u0103 acesta este actualizat. Evita\u021bi s\u0103 face\u021bi clic pe linkuri sau s\u0103 desc\u0103rca\u021bi ata\u0219amente din e-mailuri suspecte. De asemenea, activa\u021bi autentificarea cu doi factori (2FA\/MFA) pentru serviciile bancare online ori de c\u00e2te ori este posibil, deoarece acest lucru adaug\u0103 un element suplimentar de securitate.<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Pagini web contraf\u0103cute<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">Un alt mod de operare este crearea de pagini web contraf\u0103cute care imit\u0103 site-urile oficiale ale institu\u021biilor bancare. Infractorii v\u0103 pot trimite un e-mail sau un mesaj text cu un link c\u0103tre aceste site-uri false, \u00eencerc\u00e2nd s\u0103 v\u0103 p\u0103c\u0103leasc\u0103 s\u0103 introduce\u021bi acolo datele de autentificare.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Fi\u021bi \u00eentotdeauna atent la adresa URL a oric\u0103rui site web bancar pe care \u00eel accesa\u021bi. Paginile web legitime vor avea un certificat SSL valid (indicat de un lac\u0103t \u00een bara de adrese) \u0219i o adres\u0103 URL care corespunde exact cu domeniul oficial al b\u0103ncii. Dac\u0103 ave\u021bi dubii, introduce\u021bi manual adresa URL a b\u0103ncii \u00een browser, \u00een loc s\u0103 face\u021bi clic pe linkuri din e-mailuri sau mesaje.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">De asemenea, este recomandat s\u0103 c\u0103uta\u021bi informa\u021bii despre domeniul web. Dac\u0103 observa\u021bi c\u0103 domeniul a fost activat recent, este mai prudent s\u0103 evita\u021bi folosirea acelei pagini web. Pute\u021bi verifica v\u00e2rsta \u0219i informa\u021biile despre un domeniu .ro folosind serviciul WHOIS al <a href=\"https:\/\/www.rotld.ro\/home\/\" target=\"_blank\" rel=\"noopener\">RoTLD<\/a> (Registrul Rom\u00e2n de Domenii .ro) sau, pentru domenii .com, pute\u021bi folosi servicii WHOIS publice precum <a href=\"https:\/\/who.is\/\" target=\"_blank\" rel=\"noopener\">whois.is<\/a>.<\/p>\n<p>\u00a0<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Fraude cu credite bancare<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">Creditele bancare pot fi ob\u021binute \u00een mod fraudulos prin intermediul serviciilor de internet banking sau mobile banking, atunci c\u00e2nd atacatorul dob\u00e2nde\u0219te acces de la distan\u021b\u0103 la dispozitivul victimei pe care sunt instalate aceste aplica\u021bii. \u00cen acest caz, discut\u0103m despre ob\u021binerea unui credit bancar prin uzurparea identit\u0103\u021bii victimei.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Pentru a preveni acest tip de fraud\u0103, monitoriza\u021bi-v\u0103 cu aten\u021bie conturile bancare \u0219i rapoartele de credit. Dac\u0103 observa\u021bi orice activitate suspect\u0103, cum ar fi cereri de credit pe care nu le-a\u021bi ini\u021biat, contacta\u021bi imediat institu\u021bia bancar\u0103 \u0219i institu\u021biile de raportare a creditelor.<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Folosirea cardurilor furate pentru pl\u0103\u021bi offline<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">Infractorii pot folosi carduri bancare furate pentru a efectua pl\u0103\u021bi offline. Este important de men\u021bionat c\u0103, \u00een unele cazuri, pl\u0103\u021bile la POS pot fi efectuate chiar dac\u0103 nu exist\u0103 suficiente fonduri disponibile \u00een cont. Aceasta se datoreaz\u0103 faptului c\u0103 unele tranzac\u021bii offline pot fi procesate f\u0103r\u0103 verificarea imediat\u0103 a soldului. Infractorii pot profita de aceast\u0103 caracteristic\u0103 pentru a face achizi\u021bii frauduloase \u00eenainte ca banca s\u0103 detecteze activitatea neobi\u0219nuit\u0103.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">De asemenea, pentru pl\u0103\u021bile la POS sub un anumit cuantum (variabil \u00een func\u021bie de institu\u021bia bancar\u0103 \u0219i de \u021bar\u0103), introducerea codului PIN nu este \u00eentotdeauna necesar\u0103. Aceasta \u00eenseamn\u0103 c\u0103, dac\u0103 un infractor intr\u0103 \u00een posesia unui card fizic furat, poate efectua achizi\u021bii mai mici f\u0103r\u0103 a fi necesar\u0103 introducerea codului PIN.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Pentru a v\u0103 proteja, raporta\u021bi imediat orice card pierdut sau furat institu\u021biei dumneavoastr\u0103 bancare, astfel \u00eenc\u00e2t acesta s\u0103 poat\u0103 fi blocat. De asemenea, monitoriza\u021bi-v\u0103 cu aten\u021bie extrasele de cont pentru orice tranzac\u021bii nerecunoscute.<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Ce pot face victimele<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">Dac\u0103 a\u021bi c\u0103zut victim\u0103 unei fraude sau infrac\u021biuni bancare, iat\u0103 c\u00e2\u021biva pa\u0219i pe care \u00eei pute\u021bi urma:<\/p>\n<ol class=\"-mt-1 list-decimal space-y-2 pl-8\">\n<li class=\"whitespace-normal break-words\">Contacta\u021bi imediat institu\u021bia bancar\u0103 pentru a bloca cardul sau opera\u021biunea ini\u021biat\u0103 \u00een mod fraudulos. Cu c\u00e2t ac\u021biona\u021bi mai repede, cu at\u00e2t mai mari sunt \u0219ansele de a preveni sau limita daunele.<\/li>\n<li class=\"whitespace-normal break-words\">Contacta\u021bi un avocat specializat \u00een drept penal \u0219i criminalitate informatic\u0103. Acesta v\u0103 poate oferi sfaturi cu privire la pa\u0219ii legali de urmat \u0219i v\u0103 pot ajuta s\u0103 depune\u021bi o pl\u00e2ngere penal\u0103. Este important s\u0103 sesiza\u021bi de \u00eendat\u0103 organele de urm\u0103rire penal\u0103 pentru a cre\u0219te \u0219ansele de a-i identifica pe infractori \u0219i de a recupera fondurile sustrase.<\/li>\n<li class=\"whitespace-normal break-words\">Dac\u0103 au fost utilizate carduri bancare \u00een mod fraudulos, pute\u021bi \u00eencerca s\u0103 recupera\u021bi sumele de bani prin procedura de refuz la plat\u0103 (<a href=\"https:\/\/www.wall-street.ro\/articol\/Finante-Banci\/252704\/chargeback-sau-superputerea-cardului-tau-care-te-ajuta-sa-iti-recuperezi-banii.html\" target=\"_blank\" rel=\"noopener\">chargeback<\/a>). Aceast\u0103 procedur\u0103 v\u0103 permite s\u0103 contesta\u021bi tranzac\u021biile neautorizate direct la institu\u021bia bancar\u0103 emitent\u0103 a cardului. Banca va investiga apoi cazul \u0219i, dac\u0103 frauda este dovedit\u0103, v\u0103 poate rambursa fondurile.<\/li>\n<\/ol>\n<p class=\"whitespace-pre-wrap break-words\">Aminti\u021bi-v\u0103, cu c\u00e2t ac\u021biona\u021bi mai repede, cu at\u00e2t mai bine. Nu ezita\u021bi s\u0103 cere\u021bi ajutor de la profesioni\u0219ti, fie c\u0103 este vorba de institu\u021bia bancar\u0103, de organele de aplicare a legii sau de avoca\u021bi specializa\u021bi.<\/p>\n<h3 class=\"font-600 text-xl font-bold\">Concluzie<\/h3>\n<p class=\"whitespace-pre-wrap break-words\">Fraudele \u0219i infrac\u021biunile bancare pot avea consecin\u021be grave, dar prin con\u0219tientizarea modurilor de operare comune \u0219i prin luarea m\u0103surilor adecvate de precau\u021bie, pute\u021bi diminua toate aceste riscuri. Aminti\u021bi-v\u0103 s\u0103 fi\u021bi \u00eentotdeauna vigilent \u00een ceea ce prive\u0219te informa\u021biile dumneavoastr\u0103 financiare \u0219i nu ezita\u021bi s\u0103 raporta\u021bi orice activitate suspect\u0103 institu\u021biilor financiare \u0219i autorit\u0103\u021bilor de aplicare a legii.<\/p>\n<p class=\"whitespace-pre-wrap break-words\">Dac\u0103 a\u021bi fost victima unei fraude sau infrac\u021biuni bancare, sau dac\u0103 sunte\u021bi acuzat de o astfel de infrac\u021biune, este important s\u0103 cere\u021bi asisten\u021b\u0103 juridic\u0103 de specialitate. Un avocat specializat \u00een drept penal \u0219i criminalitate informatic\u0103 v\u0103 poate oferi \u00eendrumarea \u0219i reprezentarea necesare pentru a v\u0103 proteja drepturile \u0219i interesele.<\/p>\n<h3><strong>Informa\u021bii suplimentare<\/strong><\/h3>\n<p>Acest material are un scop pur informativ \u0219i educa\u021bional, con\u021binutul acestuia neput\u00e2nd fi asimilat unei forme de consultan\u021b\u0103 juridic\u0103 \u00een materie penal\u0103. Pentru a \u00een\u021belege cu exactitate ce drepturi sau obliga\u021bii ai \u00eentr-o anumit\u0103 procedur\u0103 penal\u0103, este important s\u0103 consul\u021bi un avocat specializat \u00een dreptul penal.<\/p>\n<p><a href=\"https:\/\/zic.legal\/ro\/team\/zlatigeorge\/\" target=\"_blank\" rel=\"noopener\">George Zlati\u00a0<\/a>este avocat \u0219i lector universitar. Acesta este titular al disciplinei\u00a0<em>Criminalitate informatic\u0103\u00a0<\/em>la nivel de masterat, av\u00e2nd de asemenea un doctorat pe criminalitate informatic\u0103. Specializarea acestuia este criminalitatea informatic\u0103 \u0219i tehnologia blockchain.<\/p>","protected":false},"excerpt":{"rendered":"<p>Fraudele \u0219i infrac\u021biunile bancare reprezint\u0103 o problem\u0103 serioas\u0103 \u0219i deosebit de actual\u0103, av\u00e2nd poten\u021bialul de a afecta at\u00e2t persoanele fizice, c\u00e2t \u0219i companiile. Prin urmare, este important s\u0103 fi\u021bi con\u0219tient de riscuri \u0219i s\u0103 lua\u021bi m\u0103suri pentru a v\u0103 proteja de conduitele infrac\u021bionale devenite deja tradi\u021bionale. \u00cen acest articol voi analiza cele  [&#8230;]<\/p>","protected":false},"author":2,"featured_media":4040,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[4,47,48],"class_list":["post-2451","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cybercrime","tag-avocat-george-zlati","tag-fraude-bancare","tag-infractiuni-bancare"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Fraude \u0219i infrac\u021biuni bancare | ZIC Legal<\/title>\n<meta name=\"description\" content=\"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zic.legal\/ro\/fraude-si-infractiuni-bancare\/\" \/>\n<meta property=\"og:locale\" content=\"ro_RO\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Fraude \u0219i infrac\u021biuni bancare\" \/>\n<meta property=\"og:description\" content=\"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zic.legal\/ro\/fraude-si-infractiuni-bancare\/\" \/>\n<meta property=\"og:site_name\" content=\"ZIC Legal\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/profile.php?id=61573624655319\" \/>\n<meta property=\"article:published_time\" content=\"2024-08-08T16:45:49+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-12-29T07:54:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"George Zlati\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Fraude \u0219i infrac\u021biuni bancare\" \/>\n<meta name=\"twitter:description\" content=\"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja\" \/>\n<meta name=\"twitter:label1\" content=\"Scris de\" \/>\n\t<meta name=\"twitter:data1\" content=\"George Zlati\" \/>\n\t<meta name=\"twitter:label2\" content=\"Timp estimat pentru citire\" \/>\n\t<meta name=\"twitter:data2\" content=\"1 minut\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/\"},\"author\":{\"name\":\"George Zlati\",\"@id\":\"https:\/\/zic.legal\/#\/schema\/person\/cffc51a7df5926dd9954aeb3bbbcc303\"},\"headline\":\"Fraude \u0219i infrac\u021biuni bancare\",\"datePublished\":\"2024-08-08T16:45:49+00:00\",\"dateModified\":\"2025-12-29T07:54:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/\"},\"wordCount\":1886,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/zic.legal\/#organization\"},\"image\":{\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp\",\"keywords\":[\"avocat George Zlati\",\"fraude bancare\",\"infractiuni bancare\"],\"articleSection\":[\"Criminalitate informatic\u0103\"],\"inLanguage\":\"ro-RO\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/\",\"url\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/\",\"name\":\"Fraude \u0219i infrac\u021biuni bancare | ZIC Legal\",\"isPartOf\":{\"@id\":\"https:\/\/zic.legal\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp\",\"datePublished\":\"2024-08-08T16:45:49+00:00\",\"dateModified\":\"2025-12-29T07:54:37+00:00\",\"description\":\"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja\",\"breadcrumb\":{\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#breadcrumb\"},\"inLanguage\":\"ro-RO\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ro-RO\",\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage\",\"url\":\"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp\",\"contentUrl\":\"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp\",\"width\":1536,\"height\":1024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/zic.legal\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Fraude \u0219i infrac\u021biuni bancare\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/zic.legal\/#website\",\"url\":\"https:\/\/zic.legal\/\",\"name\":\"Zlati Ionescu Chiperi SCA\",\"description\":\"Not another brick in the law\",\"publisher\":{\"@id\":\"https:\/\/zic.legal\/#organization\"},\"alternateName\":\"Zlati Ionescu Chiperi - SCA\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/zic.legal\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ro-RO\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/zic.legal\/#organization\",\"name\":\"Zlati Ionescu Chiperi SCA\",\"url\":\"https:\/\/zic.legal\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ro-RO\",\"@id\":\"https:\/\/zic.legal\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/zic.legal\/wp-content\/uploads\/2025\/02\/Logo-Color-RGB@0.5x.png\",\"contentUrl\":\"https:\/\/zic.legal\/wp-content\/uploads\/2025\/02\/Logo-Color-RGB@0.5x.png\",\"width\":306,\"height\":306,\"caption\":\"Zlati Ionescu Chiperi SCA\"},\"image\":{\"@id\":\"https:\/\/zic.legal\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/profile.php?id=61573624655319\",\"https:\/\/www.linkedin.com\/company\/zic-legal\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/zic.legal\/#\/schema\/person\/cffc51a7df5926dd9954aeb3bbbcc303\",\"name\":\"George Zlati\",\"url\":\"https:\/\/zic.legal\/ro\/author\/zlatigeorge\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Fraude \u0219i infrac\u021biuni bancare | ZIC Legal","description":"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zic.legal\/ro\/fraude-si-infractiuni-bancare\/","og_locale":"ro_RO","og_type":"article","og_title":"Fraude \u0219i infrac\u021biuni bancare","og_description":"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja","og_url":"https:\/\/zic.legal\/ro\/fraude-si-infractiuni-bancare\/","og_site_name":"ZIC Legal","article_publisher":"https:\/\/www.facebook.com\/profile.php?id=61573624655319","article_published_time":"2024-08-08T16:45:49+00:00","article_modified_time":"2025-12-29T07:54:37+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp","type":"image\/webp"}],"author":"George Zlati","twitter_card":"summary_large_image","twitter_title":"Fraude \u0219i infrac\u021biuni bancare","twitter_description":"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja","twitter_misc":{"Scris de":"George Zlati","Timp estimat pentru citire":"1 minut"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#article","isPartOf":{"@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/"},"author":{"name":"George Zlati","@id":"https:\/\/zic.legal\/#\/schema\/person\/cffc51a7df5926dd9954aeb3bbbcc303"},"headline":"Fraude \u0219i infrac\u021biuni bancare","datePublished":"2024-08-08T16:45:49+00:00","dateModified":"2025-12-29T07:54:37+00:00","mainEntityOfPage":{"@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/"},"wordCount":1886,"commentCount":0,"publisher":{"@id":"https:\/\/zic.legal\/#organization"},"image":{"@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage"},"thumbnailUrl":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp","keywords":["avocat George Zlati","fraude bancare","infractiuni bancare"],"articleSection":["Criminalitate informatic\u0103"],"inLanguage":"ro-RO","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/","url":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/","name":"Fraude \u0219i infrac\u021biuni bancare | ZIC Legal","isPartOf":{"@id":"https:\/\/zic.legal\/#website"},"primaryImageOfPage":{"@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage"},"image":{"@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage"},"thumbnailUrl":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp","datePublished":"2024-08-08T16:45:49+00:00","dateModified":"2025-12-29T07:54:37+00:00","description":"Ce trebuie s\u0103 cuno\u0219ti despre fraudele \u0219i infrac\u021biunile bancare. Vezi principalele conduite infrac\u021bionale \u0219i cum te po\u021bi proteja","breadcrumb":{"@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#breadcrumb"},"inLanguage":"ro-RO","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/"]}]},{"@type":"ImageObject","inLanguage":"ro-RO","@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#primaryimage","url":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp","contentUrl":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp","width":1536,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/zic.legal\/fraude-si-infractiuni-bancare\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zic.legal\/"},{"@type":"ListItem","position":2,"name":"Fraude \u0219i infrac\u021biuni bancare"}]},{"@type":"WebSite","@id":"https:\/\/zic.legal\/#website","url":"https:\/\/zic.legal\/","name":"Zlati Ionescu Chiperi SCA","description":"Not another brick in the law","publisher":{"@id":"https:\/\/zic.legal\/#organization"},"alternateName":"Zlati Ionescu Chiperi - SCA","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zic.legal\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ro-RO"},{"@type":"Organization","@id":"https:\/\/zic.legal\/#organization","name":"Zlati Ionescu Chiperi SCA","url":"https:\/\/zic.legal\/","logo":{"@type":"ImageObject","inLanguage":"ro-RO","@id":"https:\/\/zic.legal\/#\/schema\/logo\/image\/","url":"https:\/\/zic.legal\/wp-content\/uploads\/2025\/02\/Logo-Color-RGB@0.5x.png","contentUrl":"https:\/\/zic.legal\/wp-content\/uploads\/2025\/02\/Logo-Color-RGB@0.5x.png","width":306,"height":306,"caption":"Zlati Ionescu Chiperi SCA"},"image":{"@id":"https:\/\/zic.legal\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/profile.php?id=61573624655319","https:\/\/www.linkedin.com\/company\/zic-legal\/"]},{"@type":"Person","@id":"https:\/\/zic.legal\/#\/schema\/person\/cffc51a7df5926dd9954aeb3bbbcc303","name":"George Zlati","url":"https:\/\/zic.legal\/ro\/author\/zlatigeorge\/"}]}},"jetpack_featured_media_url":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/08\/fraude_bancare-1.webp","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2451","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/comments?post=2451"}],"version-history":[{"count":2,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2451\/revisions"}],"predecessor-version":[{"id":4098,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2451\/revisions\/4098"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/media\/4040"}],"wp:attachment":[{"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/media?parent=2451"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/categories?post=2451"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/tags?post=2451"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}