{"id":2434,"date":"2024-07-12T13:00:52","date_gmt":"2024-07-12T13:00:52","guid":{"rendered":"https:\/\/www.zlati.legal\/?p=2434"},"modified":"2026-06-07T15:08:47","modified_gmt":"2026-06-07T15:08:47","slug":"email-spoofing-cum-identifici-un-email-fals","status":"publish","type":"post","link":"https:\/\/zic.legal\/ro\/email-spoofing-cum-identifici-un-email-fals\/","title":{"rendered":"Falsificarea e-mailurilor. Cum identifici un email fals"},"content":{"rendered":"\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Email spoofing-ul (simularea po\u0219tei electronice) reprezint\u0103 un mod de operare utilizat frecvent \u00een atacurile de phishing \u0219i alte tipuri de fraude online. Aceast\u0103 metod\u0103 implic\u0103 falsificarea adresei de expeditor a unui email pentru a p\u0103rea c\u0103 provine dintr-o surs\u0103 de \u00eencredere &#8211; banc\u0103, furnizor de servicii, institu\u021bie public\u0103, cuno\u0219tin\u021b\u0103 etc. Prin urmare, identificarea email spoofing-ului este important\u0103 pentru a ne proteja \u00eempotriva acestor atacuri. \u00cen acest ghid, vom explora metodele prin care pute\u021bi identifica \u00een ce m\u0103sur\u0103 sunte\u021bi \u021binta unui astfel de atac informatic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Am dezvoltat un instrument de verificare a email spoofing-ului pe care \u00eel pute\u021bi accesa <a class=\"underline\" href=\"#spoofing\">aici<\/a>. Acest instrument v\u0103 permite s\u0103 introduce\u021bi headerul unui email \u0219i s\u0103 verifica\u021bi instant dac\u0103 exist\u0103 suspiciuni de spoofing.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Examinarea atent\u0103 a adresei expeditorului<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Prima \u0219i cea mai simpl\u0103 metod\u0103 de depistare a email spoofing-ului este examinarea atent\u0103 a adresei expeditorului. Atacatorii folosesc de cele mai multe ori adrese care par legitime la prima vedere, dar care \u00een realitate difer\u0103 subtil. Iat\u0103 c\u00e2teva exemple relevante pentru Rom\u00e2nia:<\/p>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>suport@bcr-r0.ro \u00een loc de suport@bcr.ro<\/li>\n\n\n\n<li>info@ing-romania.com \u00een loc de info@ing.ro<\/li>\n\n\n\n<li>contact@bt-online.ro \u00een loc de contact@btrl.ro<\/li>\n\n\n\n<li>suport@emag-online.ro \u00een loc de suport@emag.ro<\/li>\n\n\n\n<li>info@olx-romania.com \u00een loc de info@olx.ro<\/li>\n\n\n\n<li>contact@dedeman-shop.ro \u00een loc de contact@dedeman.ro<\/li>\n\n\n\n<li>suport@vodafone-ro.com \u00een loc de suport@vodafone.ro<\/li>\n\n\n\n<li>info@orange-romania.ro \u00een loc de info@orange.ro<\/li>\n\n\n\n<li>contact@telekom-ro.com \u00een loc de contact@telekom.ro<\/li>\n<\/ul>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Ori de c\u00e2te ori primi\u021bi un email ce pare a fi de la o companie sau institu\u021bie public\u0103 cunoscut\u0103, verifica\u021bi autenticitatea adresei expeditorului. Pentru aceasta:<\/p>\n\n\n\n<ol class=\"wp-block-list -mt-1 list-decimal space-y-2 pl-8\">\n<li>Accesa\u021bi site-ul web oficial al organiza\u021biei respective. Trebuie totu\u0219i s\u0103 verifica\u021bi cu aten\u021bie pagina web accesat\u0103, pentru a nu interac\u021biona cu o pagin\u0103 web contraf\u0103cut\u0103 (clonat\u0103).<\/li>\n\n\n\n<li>Naviga\u021bi la sec\u021biunea de contact sau suport.<\/li>\n\n\n\n<li>Compara\u021bi adresa de email afi\u0219at\u0103 pe site cu cea din emailul primit.<\/li>\n\n\n\n<li>Asigura\u021bi-v\u0103 c\u0103 domeniul (partea de dup\u0103 @) corespunde exact cu cel oficial.<\/li>\n<\/ol>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Aceast\u0103 practic\u0103 v\u0103 ajut\u0103 s\u0103 identifica\u021bi rapid tentativele de email spoofing, oferindu-v\u0103 o metod\u0103 sigur\u0103 de a confirma legitimitatea coresponden\u021bei primite. Dac\u0103 observa\u021bi discrepan\u021be, trata\u021bi emailul cu suspiciune \u0219i contacta\u021bi direct compania sau institu\u021bia public\u0103 folosind detaliile de pagina lor web.<\/p>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Fi\u021bi de asemenea aten\u021bi la urm\u0103toarele tactici folosite de atacatori:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Substituirea caracterelor sau ad\u0103ugarea de cuvinte suplimentare:<\/h4>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>Folosirea cifrei &#8220;0&#8221; \u00een loc de litera &#8220;o&#8221; (exemplu: v0dafone.ro)<\/li>\n\n\n\n<li>\u00cenlocuirea literei &#8220;i&#8221; cu &#8220;1&#8221; (exemplu: d1gi.ro)<\/li>\n\n\n\n<li>Utilizarea caracterului &#8220;rn&#8221; pentru a imita &#8220;m&#8221; (exemplu: romtelecorn.ro)<\/li>\n\n\n\n<li>&#8220;-online&#8221;, &#8220;-shop&#8221;, &#8220;-romania&#8221; ad\u0103ugate la numele domeniului legitim<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Modificarea extensiei domeniului:<\/h4>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>Folosirea .com \u00een loc de .ro sau invers<\/li>\n\n\n\n<li>Utilizarea extensiilor mai pu\u021bin comune precum .org, .net, .io sau .info<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Gre\u0219eli inten\u021bionate de ortografie:<\/h4>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>&#8220;bancpost&#8221; scris ca &#8220;banckpost&#8221;<\/li>\n\n\n\n<li>&#8220;transilvania&#8221; scris ca &#8220;translivania&#8221;<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Subdomenii \u00een\u0219el\u0103toare sau inversarea ordinii cuvintelor:<\/h4>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>emag.domeniu-fals.ro \u00een loc de emag.ro<\/li>\n\n\n\n<li>anaf.gov.impozite.ro \u00een loc de anaf.ro<\/li>\n\n\n\n<li>info@romana-posta.ro \u00een loc de info@posta-romana.ro<\/li>\n<\/ul>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Pentru a v\u0103 proteja, este esen\u021bial s\u0103 verifica\u021bi cu aten\u021bie fiecare parte a adresei de email, inclusiv numele utilizatorului (partea dinaintea @) \u0219i domeniul (partea de dup\u0103 @). Dac\u0103 ave\u021bi dubii, nu ezita\u021bi s\u0103 contacta\u021bi direct institu\u021bia sau compania respectiv\u0103 folosind informa\u021biile de contact oficiale de pe pagina lor web.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Analiza headerelor emailului<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Headerele emailului con\u021bin informa\u021bii detaliate despre traseul mesajului \u0219i pot oferi indicii importante despre autenticitatea sa. Pentru a vizualiza headerele complete:<\/p>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>\u00cen Gmail: deschide\u021bi emailul \u0219i selecta\u021bi &#8220;Afi\u0219are original&#8221; din meniul cu trei puncte (vezi detalii <a href=\"https:\/\/support.google.com\/mail\/answer\/29436?hl=en\" target=\"_blank\" rel=\"noopener\">aici<\/a>).<\/li>\n\n\n\n<li>\u00cen Outlook web: deschide\u021bi emailul \u0219i selecteaz\u0103 &#8220;Vizualizare mesaj&#8221; ap\u0103s\u00e2nd pe cele trei puncte din partea de sus.<\/li>\n\n\n\n<li>\u00cen Outlook desktop: deschide\u021bi emailul, selecta\u021bi fila &#8220;Fi\u0219ier&#8221;, apoi &#8220;Propriet\u0103\u021bi&#8221; \u0219i ve\u021bi vedea headerele \u00een sec\u021biunea &#8220;Internet Headers&#8221;.<\/li>\n\n\n\n<li>\u00cen Yahoo mail: deschide\u021bi emailul \u0219i selecta\u021bi &#8220;vizualizare surs\u0103 vrut\u0103&#8221; ap\u0103s\u00e2nd pe cele trei puncte din col\u021bul din dreapta.<\/li>\n<\/ul>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">C\u0103uta\u021bi inconsisten\u021be \u00eentre c\u00e2mpurile &#8220;From:&#8221;, &#8220;Return-Path:&#8221; \u0219i &#8220;Received:&#8221;. \u00centr-un email legitim, aceste informa\u021bii ar trebui s\u0103 fie coerente. Dac\u0103 nu \u0219ti\u021bi cum s\u0103 citi\u021bi headerul&nbsp; unui email, pute\u021bi s\u0103 da\u021bi copy-paste la con\u021binut \u00een <a href=\"https:\/\/mxtoolbox.com\/EmailHeaders.aspx\" target=\"_blank\" rel=\"noopener\">MX Toolbox<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Verificarea autentific\u0103rii emailului<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Emailurile autentice folosesc adesea protocoale de autentificare precum SPF (Sender Policy Framework), DKIM (DomainKeys Identified Mail) \u0219i DMARC (Domain-based Message Authentication, Reporting and Conformance). Verifica\u021bi dac\u0103 aceste protocoale sunt prezente \u0219i valide \u00een headerele emailului.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Utilizarea instrumentelor online de analiz\u0103<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Exist\u0103 diverse instrumente online care pot ajuta la analiza emailurilor suspecte:<\/p>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li><a href=\"https:\/\/mxtoolbox.com\/EmailHeaders.aspx\" target=\"_blank\" rel=\"noopener\">MXToolbox<\/a>: Ofer\u0103 o serie de instrumente pentru analiza headerelor de email.<\/li>\n\n\n\n<li><a href=\"https:\/\/www.ipqualityscore.com\/\" target=\"_blank\" rel=\"noopener\">IPQualityScore<\/a>: Poate verifica adresele IP \u0219i domeniile pentru a detecta poten\u021biale surse de spam sau phishing.<\/li>\n\n\n\n<li><a class=\"underline\" href=\"https:\/\/toolbox.googleapps.com\/apps\/messageheader\/\" target=\"_blank\" rel=\"noopener\">Email Header Analyser<\/a>: Instrument dezvoltat de Google pentru analiza headerelor de email.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Verificarea con\u021binutului \u0219i contextului<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Pe l\u00e2ng\u0103 aspectele tehnice, analiza\u021bi con\u021binutul \u0219i contextul emailului:<\/p>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>Exist\u0103 erori gramaticale sau de ortografie neobi\u0219nuite? Trebuie totu\u0219i \u021binut cont c\u0103 atacatorii folosesc \u00een prezent inteligen\u021ba artificial\u0103 pentru a genera con\u021binut care corespunde normelor gramaticale.&nbsp;<\/li>\n\n\n\n<li>Emailul creeaz\u0103 un sentiment de urgen\u021b\u0103 nejustificat? Emailurile de phishing creeaz\u0103 adesea un sentiment de urgen\u021b\u0103 nejustificat, cer\u00e2ndu-v\u0103 s\u0103 ac\u021biona\u021bi imediat.<\/li>\n\n\n\n<li>Vi se cere s\u0103 furniza\u021bi informa\u021bii sensibile sau s\u0103 face\u021bi clic pe linkuri suspecte? Institu\u021biile legitime nu solicit\u0103 niciodat\u0103 prin email date confiden\u021biale precum parole, PIN-uri sau informa\u021bii complete despre carduri. De asemenea, verifica\u021bi \u00eentotdeauna URL-urile \u00eenainte de a face clic, plas\u00e2nd cursorul peste link pentru a vedea adresa real\u0103 &#8211; utiliza\u021bi servicii precum <a class=\"underline\" href=\"https:\/\/www.virustotal.com\/\" target=\"_blank\" rel=\"noopener\">VirusTotal<\/a> pentru a verifica linkuri suspecte.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Implementarea de solu\u021bii de securitate email<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Pentru o protec\u021bie mai robust\u0103, considera\u021bi implementarea unor solu\u021bii de securitate email precum:<\/p>\n\n\n\n<ul class=\"wp-block-list -mt-1 list-disc space-y-2 pl-8\">\n<li>Filtre anti-spam avansate<\/li>\n\n\n\n<li>Solu\u021bii de securitate email bazate pe cloud<\/li>\n\n\n\n<li>Sisteme de prevenire a pierderii de date (DLP)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading whitespace-pre-wrap break-words\">Implica\u021bii legale<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">\u00cen Rom\u00e2nia, conduita tip email spoofing poate constitui infrac\u021biunea de <a href=\"https:\/\/zic.legal\/infractiuni-informatice-in-romania\/\">fals informatic<\/a>, prev\u0103zut\u0103 la articolul 325 din Codul Penal:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Fapta de a introduce, modifica sau \u0219terge, f\u0103r\u0103 drept, date informatice ori de a restric\u021biona, f\u0103r\u0103 drept, accesul la aceste date, rezult\u00e2nd date necorespunz\u0103toare adev\u0103rului, \u00een scopul de a fi utilizate \u00een vederea producerii unei consecin\u021be juridice, constituie infrac\u021biune \u0219i se pedepse\u0219te cu \u00eenchisoarea de la unu la 5 ani.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Este important de men\u021bionat c\u0103, potrivit <a href=\"https:\/\/legislatie.just.ro\/Public\/DetaliiDocumentAfis\/238047\" target=\"_blank\" rel=\"noopener\">Deciziei nr. 4\/2021 a \u00cenaltei Cur\u021bi de Casa\u021bie \u0219i Justi\u021bie<\/a>, crearea de conturi false pe re\u021belele de socializare reprezint\u0103 un furt de identitate ce intr\u0103 sub inciden\u021ba falsului informatic. Aceast\u0103 decizie obligatorie poate fi extins\u0103 \u0219i asupra email spoofing-ului.<\/p>\n\n\n<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\" 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\n<h3 class=\"wp-block-heading whitespace-pre-wrap break-words\">Concluzie<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words wp-block-paragraph\">Depistarea email spoofing-ului necesit\u0103 o combina\u021bie de vigilen\u021b\u0103, cuno\u0219tin\u021be tehnice \u0219i utilizarea instrumentelor potrivite. Prin aplicarea metodelor descrise mai sus \u0219i men\u021binerea unei atitudini critice fa\u021b\u0103 de emailurile primite, pute\u021bi reduce semnificativ riscul de a c\u0103dea victim\u0103 acestor atacuri.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Informa\u021bii suplimentare<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">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\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/zic.legal\/team\/zlatigeorge\/\" target=\"_blank\" rel=\"noopener\">George Zlati&nbsp;<\/a>este avocat \u0219i lector universitar. Acesta este titular al disciplinei&nbsp;<em><a href=\"https:\/\/zic.legal\/arii-de-practica\/criminalitate-informatica\/\">Criminalitate informatic\u0103<\/a>&nbsp;<\/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>\n","protected":false},"excerpt":{"rendered":"<p>Email spoofing-ul (simularea po\u0219tei electronice) reprezint\u0103 un mod de operare utilizat frecvent \u00een atacurile de phishing \u0219i alte tipuri de fraude online. Aceast\u0103 metod\u0103 implic\u0103 falsificarea adresei de expeditor a unui email pentru a p\u0103rea c\u0103 provine dintr-o surs\u0103 de \u00eencredere &#8211; banc\u0103, furnizor de servicii, institu\u021bie public\u0103, cuno\u0219tin\u021b\u0103 etc. Prin urmare,  [&#8230;]<\/p>\n","protected":false},"author":8,"featured_media":4044,"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,43,44],"class_list":["post-2434","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cybercrime","tag-avocat-george-zlati","tag-email-spoofing","tag-fals-informatic"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Email spoofing. Cum identifici un email fals | ZIC Legal<\/title>\n<meta name=\"description\" content=\"Descoperi\u021bi cum s\u0103 identifica\u021bi \u0219i s\u0103 preveni\u021bi email spoofing-ul, o metod\u0103 frecvent\u0103 \u00een atacurile de phishing.\" \/>\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\/email-spoofing-cum-identifici-un-email-fals\/\" \/>\n<meta property=\"og:locale\" content=\"ro_RO\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Email spoofing. Cum identifici un email fals\" \/>\n<meta property=\"og:description\" content=\"Email spoofing-ul reprezint\u0103 o tehnic\u0103 frecvent utilizat\u0103 \u00een atacurile de phishing \u0219i alte tipuri de fraude online.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zic.legal\/ro\/email-spoofing-cum-identifici-un-email-fals\/\" \/>\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-07-12T13:00:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-07T15:08:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/zic.legal\/wp-content\/uploads\/2024\/07\/spoofing.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: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=\"5 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/\"},\"author\":{\"name\":\"George Zlati\",\"@id\":\"https:\\\/\\\/zic.legal\\\/#\\\/schema\\\/person\\\/aae0a83a43928bb0743a63e0a3343e65\"},\"headline\":\"Email spoofing. Cum identifici un email fals\",\"datePublished\":\"2024-07-12T13:00:52+00:00\",\"dateModified\":\"2026-06-07T15:08:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/\"},\"wordCount\":1309,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/zic.legal\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/email_phishing.webp\",\"keywords\":[\"avocat George Zlati\",\"email spoofing\",\"fals informatic\"],\"articleSection\":[\"Criminalitate informatic\u0103\"],\"inLanguage\":\"ro-RO\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/\",\"url\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/\",\"name\":\"Email spoofing. Cum identifici un email fals | ZIC Legal\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/zic.legal\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/email_phishing.webp\",\"datePublished\":\"2024-07-12T13:00:52+00:00\",\"dateModified\":\"2026-06-07T15:08:47+00:00\",\"description\":\"Descoperi\u021bi cum s\u0103 identifica\u021bi \u0219i s\u0103 preveni\u021bi email spoofing-ul, o metod\u0103 frecvent\u0103 \u00een atacurile de phishing.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#breadcrumb\"},\"inLanguage\":\"ro-RO\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ro-RO\",\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#primaryimage\",\"url\":\"https:\\\/\\\/zic.legal\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/email_phishing.webp\",\"contentUrl\":\"https:\\\/\\\/zic.legal\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/email_phishing.webp\",\"width\":1536,\"height\":1024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/zic.legal\\\/email-spoofing-cum-identifici-un-email-fals\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/zic.legal\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Email spoofing. Cum identifici un email fals\"}]},{\"@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\\\/\",\"https:\\\/\\\/www.wikidata.org\\\/wiki\\\/Q139905998\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/zic.legal\\\/#\\\/schema\\\/person\\\/aae0a83a43928bb0743a63e0a3343e65\",\"name\":\"George Zlati\",\"description\":\"George Zlati este avocat \u0219i lector universitar. Acesta este titular al disciplinei Criminalitate informatic\u0103 la nivel de masterat, av\u00e2nd de asemenea un doctorat pe criminalitate informatic\u0103. Specializarea acestuia este criminalitatea informatic\u0103 \u0219i tehnologia blockchain. Mail: george.zlati@zic.legal | Tel: +40 748 149 840\",\"sameAs\":[\"https:\\\/\\\/www.wikidata.org\\\/wiki\\\/Q127327895\",\"https:\\\/\\\/orcid.org\\\/0009-0009-0424-8488\",\"https:\\\/\\\/isni.org\\\/isni\\\/0000000496723288\",\"https:\\\/\\\/linkedin.com\\\/in\\\/george-m-r-zlati\",\"https:\\\/\\\/scholar.google.com\\\/citations?user=MNBiligAAAAJ\",\"https:\\\/\\\/www.researchgate.net\\\/profile\\\/George-Zlati\",\"https:\\\/\\\/uab-ro.academia.edu\\\/GeorgeZlati\",\"https:\\\/\\\/www.youtube.com\\\/@PenalmenteRelevant\",\"https:\\\/\\\/profesionisti.juridice.ro\\\/george-zlati\",\"https:\\\/\\\/www.avocatura.com\\\/av.24029-zlati-michail-george-rudolf.html\",\"https:\\\/\\\/www.ecba.org\\\/contactslist\\\/contact-details.php?idreg=720200074\",\"https:\\\/\\\/www.efcl.eu\\\/efclmemberlist\\\/contact-details.php?idreg=720200074\"],\"jobTitle\":\"Avocat partener, drept penal al afacerilor si criminalitate informatica\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Falsificarea e-mailurilor. Cum identifici un email fals | ZIC Legal","description":"Descoperi\u021bi cum s\u0103 identifica\u021bi \u0219i s\u0103 preveni\u021bi email spoofing-ul, o urm\u0103toarea frecvent\u0103 \u00een atacurile de phishing.","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\/email-spoofing-cum-identifici-un-email-fals\/","og_locale":"ro_RO","og_type":"article","og_title":"Email spoofing. Cum identifici un email fals","og_description":"Email spoofing-ul reprezint\u0103 o tehnic\u0103 frecvent utilizat\u0103 \u00een atacurile de phishing \u0219i alte tipuri de fraude online.","og_url":"https:\/\/zic.legal\/ro\/email-spoofing-cum-identifici-un-email-fals\/","og_site_name":"ZIC Legal","article_publisher":"https:\/\/www.facebook.com\/profile.php?id=61573624655319","article_published_time":"2024-07-12T13:00:52+00:00","article_modified_time":"2026-06-07T15:08:47+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/07\/spoofing.webp","type":"image\/webp"}],"author":"George Zlati","twitter_card":"summary_large_image","twitter_misc":{"Scris de":"George Zlati","Timp estimat pentru citire":"5 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#article","isPartOf":{"@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/"},"author":{"name":"George Zlati","@id":"https:\/\/zic.legal\/#\/schema\/person\/aae0a83a43928bb0743a63e0a3343e65"},"headline":"Email spoofing. Cum identifici un email fals","datePublished":"2024-07-12T13:00:52+00:00","dateModified":"2026-06-07T15:08:47+00:00","mainEntityOfPage":{"@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/"},"wordCount":1309,"commentCount":0,"publisher":{"@id":"https:\/\/zic.legal\/#organization"},"image":{"@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#primaryimage"},"thumbnailUrl":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/07\/email_phishing.webp","keywords":["avocat George Zlati","email spoofing","fals informatic"],"articleSection":["Criminalitate informatic\u0103"],"inLanguage":"ro-RO","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/","url":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/","name":"Falsificarea e-mailurilor. Cum identifici un email fals | ZIC Legal","isPartOf":{"@id":"https:\/\/zic.legal\/#website"},"primaryImageOfPage":{"@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#primaryimage"},"image":{"@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#primaryimage"},"thumbnailUrl":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/07\/email_phishing.webp","datePublished":"2024-07-12T13:00:52+00:00","dateModified":"2026-06-07T15:08:47+00:00","description":"Descoperi\u021bi cum s\u0103 identifica\u021bi \u0219i s\u0103 preveni\u021bi email spoofing-ul, o urm\u0103toarea frecvent\u0103 \u00een atacurile de phishing.","breadcrumb":{"@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#breadcrumb"},"inLanguage":"ro-RO","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/"]}]},{"@type":"ImageObject","inLanguage":"ro-RO","@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#primaryimage","url":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/07\/email_phishing.webp","contentUrl":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/07\/email_phishing.webp","width":1536,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/zic.legal\/email-spoofing-cum-identifici-un-email-fals\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zic.legal\/"},{"@type":"ListItem","position":2,"name":"Email spoofing. Cum identifici un email fals"}]},{"@type":"WebSite","@id":"https:\/\/zic.legal\/#website","url":"https:\/\/zic.legal\/","name":"Zlati Ionescu Chiperi SCA","description":"Nu \u00eenc\u0103 o c\u0103r\u0103mid\u0103 \u00een lege","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\/","https:\/\/www.wikidata.org\/wiki\/Q139905998"]},{"@type":"Person","@id":"https:\/\/zic.legal\/#\/schema\/person\/aae0a83a43928bb0743a63e0a3343e65","name":"George Zlati","description":"George Zlati este avocat \u0219i lector universitar. Acesta este titular al disciplinei Criminalitate informatic\u0103 la nivelul de masterat, av\u00e2nd de asemenea un doctorat pe criminalitate informatic\u0103. Specializarea acesteia este criminalitatea informatic\u0103 \u0219i tehnologia blockchain. Mail: george.zlati@zic.legal | Tel: +40 748 149 840","sameAs":["https:\/\/www.wikidata.org\/wiki\/Q127327895","https:\/\/orcid.org\/0009-0009-0424-8488","https:\/\/isni.org\/isni\/0000000496723288","https:\/\/linkedin.com\/in\/george-m-r-zlati","https:\/\/scholar.google.com\/citations?user=MNBiligAAAAJ","https:\/\/www.researchgate.net\/profile\/George-Zlati","https:\/\/uab-ro.academia.edu\/GeorgeZlati","https:\/\/www.youtube.com\/@PenalmenteRelevant","https:\/\/profesionisti.juridice.ro\/george-zlati","https:\/\/www.avocatura.com\/av.24029-zlati-michail-george-rudolf.html","https:\/\/www.ecba.org\/contactslist\/contact-details.php?idreg=720200074","https:\/\/www.efcl.eu\/efclmemberlist\/contact-details.php?idreg=720200074"],"jobTitle":"Avocat partener, drept penal al afacerilor si criminalitate informatica"}]}},"jetpack_featured_media_url":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/07\/email_phishing.webp","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2434","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\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/comments?post=2434"}],"version-history":[{"count":13,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2434\/revisions"}],"predecessor-version":[{"id":4445,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2434\/revisions\/4445"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/media\/4044"}],"wp:attachment":[{"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/media?parent=2434"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/categories?post=2434"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/tags?post=2434"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}