{"id":2434,"date":"2024-07-12T13:00:52","date_gmt":"2024-07-12T13:00:52","guid":{"rendered":"https:\/\/www.zlati.legal\/?p=2434"},"modified":"2025-12-29T07:52:40","modified_gmt":"2025-12-29T07:52:40","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":"Email spoofing. Cum identifici un email fals"},"content":{"rendered":"<p class=\"whitespace-pre-wrap break-words\">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>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\">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\">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\">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\">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\">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\">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\">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\">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\">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\">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\">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\">\u00cen Rom\u00e2nia, conduita tip email spoofing poate constitui infrac\u021biunea de fals informatic, 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\">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\">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\/ro\/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"zic2__footerLink\">\r\n        &copy; 2025 ZIC Legal\r\n      <\/a>\r\n    <\/footer>\r\n  <\/div>\r\n<\/div>\r\n\r\n<style>\r\n\/* ============================================================\r\n   ZIC Calculator v2.1 - Website Spoofing Checker ENHANCED\r\n   Theme: Purple\/Mov | Fully Responsive | Optimized for WPCode\r\n   SECURITY VERSION - All XSS vulnerabilities patched\r\n   ENHANCED: 4 External API Sources with CORS proxy support\r\n   ============================================================ *\/\r\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&display=swap');\r\n\r\n\/* === CSS Variables === *\/\r\n#zic-website-spoofing-v2 {\r\n  --zic-primary: #8980f5;\r\n  --zic-primary-dark: #7370e0;\r\n  --zic-primary-light: rgba(137,128,245,.08);\r\n  --zic-primary-border: rgba(137,128,245,.25);\r\n\r\n  --zic-secondary: #308c97;\r\n  --zic-secondary-light: rgba(48,140,151,.08);\r\n\r\n  --zic-success: #10B981;\r\n  --zic-success-light: rgba(16,185,129,.08);\r\n  --zic-success-border: rgba(16,185,129,.25);\r\n\r\n  --zic-danger: #EF4444;\r\n  --zic-danger-light: rgba(239,68,68,.08);\r\n  --zic-danger-border: rgba(239,68,68,.25);\r\n\r\n  --zic-warning: #F59E0B;\r\n  --zic-warning-light: rgba(245,158,11,.08);\r\n  --zic-warning-border: rgba(245,158,11,.25);\r\n\r\n  --zic-blue: #3B82F6;\r\n  --zic-blue-light: rgba(59,130,246,.08);\r\n  --zic-blue-border: rgba(59,130,246,.25);\r\n\r\n  --zic-ink: #1c1c1c;\r\n  --zic-ink-light: #323232;\r\n  --zic-muted: #5B6370;\r\n  --zic-light: #9CA3AF;\r\n\r\n  --zic-bg: #fcfcfc;\r\n  --zic-surface: #FFFFFF;\r\n  --zic-border: #E5E7EB;\r\n\r\n  --zic-shadow-sm: 0 1px 2px rgba(0,0,0,.05);\r\n  --zic-shadow: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -1px rgba(0,0,0,.06);\r\n  --zic-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -2px rgba(0,0,0,.05);\r\n\r\n  --zic-radius: 16px;\r\n  --zic-radius-sm: 12px;\r\n  --zic-radius-xs: 8px;\r\n\r\n  --zic-transition: 150ms ease;\r\n  --zic-duration-fast: 150ms;\r\n  --zic-duration-normal: 250ms;\r\n  --zic-duration-slow: 400ms;\r\n  --zic-ease-out: cubic-bezier(0.16, 1, 0.3, 1);\r\n\r\n  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n  color: var(--zic-ink);\r\n  line-height: 1.6;\r\n  -webkit-font-smoothing: antialiased;\r\n}\r\n\r\n\/* Respect reduced motion preference *\/\r\n@media (prefers-reduced-motion: reduce) {\r\n  #zic-website-spoofing-v2 *,\r\n  #zic-website-spoofing-v2 *::before,\r\n  #zic-website-spoofing-v2 *::after {\r\n    animation-duration: 0.01ms !important;\r\n    transition-duration: 0.01ms !important;\r\n  }\r\n}\r\n\r\n\/* === Dark Mode (v4.1) === *\/\r\n@media (prefers-color-scheme: dark) {\r\n  #zic-website-spoofing-v2:not([data-theme=\"light\"]) {\r\n    --zic-ink: #f0f0f5;\r\n    --zic-ink-light: #d8d8e8;\r\n    --zic-muted: #9898b0;\r\n    --zic-light: #6a6a80;\r\n\r\n    --zic-bg: #121218;\r\n    --zic-surface: #1e1e2a;\r\n    --zic-border: #2e2e40;\r\n\r\n    --zic-primary-light: rgba(137,128,245,.15);\r\n    --zic-primary-border: rgba(137,128,245,.35);\r\n\r\n    --zic-success-light: rgba(16,185,129,.15);\r\n    --zic-danger-light: rgba(239,68,68,.15);\r\n    --zic-warning-light: rgba(245,158,11,.15);\r\n    --zic-blue-light: rgba(59,130,246,.15);\r\n\r\n    --zic-shadow-sm: 0 1px 2px rgba(0,0,0,.3);\r\n    --zic-shadow: 0 4px 6px -1px rgba(0,0,0,.4), 0 2px 4px -1px rgba(0,0,0,.3);\r\n    --zic-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.5), 0 4px 6px -2px rgba(0,0,0,.4);\r\n  }\r\n}\r\n\r\n\/* Manual dark mode override *\/\r\n#zic-website-spoofing-v2[data-theme=\"dark\"] {\r\n  --zic-ink: #f0f0f5;\r\n  --zic-ink-light: #d8d8e8;\r\n  --zic-muted: #9898b0;\r\n  --zic-light: #6a6a80;\r\n\r\n  --zic-bg: #121218;\r\n  --zic-surface: #1e1e2a;\r\n  --zic-border: #2e2e40;\r\n\r\n  --zic-primary-light: rgba(137,128,245,.15);\r\n  --zic-primary-border: rgba(137,128,245,.35);\r\n\r\n  --zic-success-light: rgba(16,185,129,.15);\r\n  --zic-danger-light: rgba(239,68,68,.15);\r\n  --zic-warning-light: rgba(245,158,11,.15);\r\n  --zic-blue-light: rgba(59,130,246,.15);\r\n\r\n  --zic-shadow-sm: 0 1px 2px rgba(0,0,0,.3);\r\n  --zic-shadow: 0 4px 6px -1px rgba(0,0,0,.4), 0 2px 4px -1px rgba(0,0,0,.3);\r\n  --zic-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.5), 0 4px 6px -2px rgba(0,0,0,.4);\r\n}\r\n\r\n\/* === Accessibility: Skip Link === *\/\r\n#zic-website-spoofing-v2 .zic2__skipLink {\r\n  position: absolute;\r\n  left: -9999px;\r\n  top: auto;\r\n  z-index: 9999;\r\n  padding: 12px 24px;\r\n  background: var(--zic-primary);\r\n  color: #fff;\r\n  font-weight: 600;\r\n  font-size: 14px;\r\n  border-radius: var(--zic-radius-sm);\r\n  text-decoration: none;\r\n  box-shadow: var(--zic-shadow-lg);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__skipLink:focus {\r\n  left: 16px;\r\n  top: 16px;\r\n  outline: 3px solid var(--zic-ink);\r\n  outline-offset: 2px;\r\n}\r\n\r\n\/* === Accessibility: Screen Reader Only === *\/\r\n#zic-website-spoofing-v2 .zic2__srStatus {\r\n  position: absolute;\r\n  width: 1px;\r\n  height: 1px;\r\n  padding: 0;\r\n  margin: -1px;\r\n  overflow: hidden;\r\n  clip: rect(0, 0, 0, 0);\r\n  white-space: nowrap;\r\n  border: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 *,\r\n#zic-website-spoofing-v2 *::before,\r\n#zic-website-spoofing-v2 *::after {\r\n  box-sizing: border-box;\r\n}\r\n\r\n\/* === WordPress\/Avada Override Protection === *\/\r\n#zic-website-spoofing-v2 input[type=\"text\"],\r\n#zic-website-spoofing-v2 input[type=\"url\"] {\r\n  -webkit-appearance: none !important;\r\n  -moz-appearance: none !important;\r\n  appearance: none !important;\r\n  background-image: none !important;\r\n  box-shadow: none !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 button:not(.zic2__btn--primary) {\r\n  background-image: none !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 button {\r\n  text-shadow: none !important;\r\n  letter-spacing: normal !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 h2,\r\n#zic-website-spoofing-v2 h3 {\r\n  text-transform: none !important;\r\n  letter-spacing: normal !important;\r\n}\r\n\r\n#zic-website-spoofing-v2 a {\r\n  text-decoration: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 a:hover {\r\n  text-decoration: underline;\r\n}\r\n\r\n\/* === Layout === *\/\r\n#zic-website-spoofing-v2 .zic2__wrap {\r\n  max-width: 720px;\r\n  margin: 0 auto;\r\n  padding: 16px;\r\n}\r\n\r\n\/* === Header === *\/\r\n#zic-website-spoofing-v2 .zic2__hero {\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__brandbar {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 14px;\r\n  background: linear-gradient(135deg, var(--zic-primary), var(--zic-primary-dark));\r\n  border-radius: var(--zic-radius);\r\n  padding: 20px;\r\n  color: #fff;\r\n  box-shadow: var(--zic-shadow-lg);\r\n  position: relative;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__version {\r\n  position: absolute;\r\n  top: 12px;\r\n  right: 16px;\r\n  background: rgba(255,255,255,.2);\r\n  padding: 4px 10px;\r\n  border-radius: 20px;\r\n  font-size: 11px;\r\n  font-weight: 700;\r\n  letter-spacing: 0.5px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__langBtn {\r\n  position: absolute;\r\n  top: 12px;\r\n  right: 70px;\r\n  background: rgba(255,255,255,.25);\r\n  border: 1px solid rgba(255,255,255,.3);\r\n  padding: 4px 10px;\r\n  border-radius: 20px;\r\n  font-size: 11px;\r\n  font-weight: 700;\r\n  letter-spacing: 0.5px;\r\n  color: #fff;\r\n  cursor: pointer;\r\n  transition: all var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__langBtn:hover {\r\n  background: rgba(255,255,255,.35);\r\n  transform: scale(1.05);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__langBtn:focus-visible {\r\n  outline: 2px solid #fff;\r\n  outline-offset: 2px;\r\n}\r\n\r\n\/* === Theme Toggle Button (v4.1) === *\/\r\n#zic-website-spoofing-v2 .zic2__themeBtn {\r\n  position: absolute;\r\n  top: 12px;\r\n  right: 115px;\r\n  background: rgba(255,255,255,.2);\r\n  border: none;\r\n  border-radius: 8px;\r\n  padding: 8px;\r\n  min-width: 44px;\r\n  min-height: 44px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  color: #fff;\r\n  cursor: pointer;\r\n  transition: all var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeBtn:hover {\r\n  background: rgba(255,255,255,.35);\r\n  transform: scale(1.05);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeBtn:focus-visible {\r\n  outline: 2px solid #fff;\r\n  outline-offset: 2px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeIcon {\r\n  transition: opacity var(--zic-duration-fast) ease, transform var(--zic-duration-fast) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__themeIcon--moon {\r\n  position: absolute;\r\n  opacity: 0;\r\n  transform: rotate(-90deg);\r\n}\r\n\r\n\/* Dark mode: show moon, hide sun *\/\r\n#zic-website-spoofing-v2[data-theme=\"dark\"] .zic2__themeIcon--sun {\r\n  opacity: 0;\r\n  transform: rotate(90deg);\r\n}\r\n\r\n#zic-website-spoofing-v2[data-theme=\"dark\"] .zic2__themeIcon--moon {\r\n  opacity: 1;\r\n  transform: rotate(0);\r\n}\r\n\r\n\/* Auto dark mode via media query *\/\r\n@media (prefers-color-scheme: dark) {\r\n  #zic-website-spoofing-v2:not([data-theme=\"light\"]) .zic2__themeIcon--sun {\r\n    opacity: 0;\r\n    transform: rotate(90deg);\r\n  }\r\n  #zic-website-spoofing-v2:not([data-theme=\"light\"]) .zic2__themeIcon--moon {\r\n    opacity: 1;\r\n    transform: rotate(0);\r\n  }\r\n}\r\n\r\n\/* === Touch Targets & Checkbox (v4.1 - WCAG 2.5.5) === *\/\r\n#zic-website-spoofing-v2 .zic2__batchToggle {\r\n  margin-bottom: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkboxLabel {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 10px;\r\n  padding: 10px 12px;\r\n  margin: -10px -12px;\r\n  cursor: pointer;\r\n  font-size: 14px;\r\n  border-radius: var(--zic-radius-xs);\r\n  transition: background-color var(--zic-duration-fast) ease;\r\n  min-height: 44px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkboxLabel:hover {\r\n  background: var(--zic-primary-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkbox {\r\n  appearance: none;\r\n  -webkit-appearance: none;\r\n  width: 22px;\r\n  height: 22px;\r\n  border: 2px solid var(--zic-border);\r\n  border-radius: 6px;\r\n  background: var(--zic-surface);\r\n  cursor: pointer;\r\n  transition: all var(--zic-duration-fast) ease;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkbox:checked {\r\n  background: var(--zic-primary);\r\n  border-color: var(--zic-primary);\r\n  background-image: url(\"data:image\/svg+xml,%3Csvg viewBox='0 0 16 16' fill='white' xmlns='http:\/\/www.w3.org\/2000\/svg'%3E%3Cpath d='M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 111.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z'\/%3E%3C\/svg%3E\");\r\n  background-size: 14px;\r\n  background-repeat: no-repeat;\r\n  background-position: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkbox:focus-visible {\r\n  outline: 3px solid var(--zic-primary);\r\n  outline-offset: 2px;\r\n  box-shadow: 0 0 0 6px rgba(137,128,245,.15);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkboxText {\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__mark {\r\n  width: 48px;\r\n  height: 48px;\r\n  background: rgba(255,255,255,.2);\r\n  border-radius: 12px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__headerText {\r\n  flex: 1;\r\n  min-width: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__title {\r\n  margin: 0;\r\n  font-size: 20px;\r\n  font-weight: 700;\r\n  line-height: 1.2;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__subtitle {\r\n  margin: 4px 0 0;\r\n  font-size: 14px;\r\n  opacity: 0.9;\r\n}\r\n\r\n\/* === Formula Box === *\/\r\n#zic-website-spoofing-v2 .zic2__formula {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 10px;\r\n  background: var(--zic-primary-light);\r\n  border: 1px solid var(--zic-primary-border);\r\n  border-radius: var(--zic-radius-sm);\r\n  padding: 12px 14px;\r\n  margin-bottom: 16px;\r\n  font-size: 14px;\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__formulaIcon {\r\n  color: var(--zic-primary-dark);\r\n  flex-shrink: 0;\r\n  margin-top: 1px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__formulaText strong {\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Cards === *\/\r\n#zic-website-spoofing-v2 .zic2__card {\r\n  background: var(--zic-surface);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius);\r\n  padding: 20px;\r\n  margin-bottom: 16px;\r\n  box-shadow: var(--zic-shadow-sm);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardHeader {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 12px;\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon {\r\n  width: 36px;\r\n  height: 36px;\r\n  border-radius: 10px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--purple {\r\n  background: var(--zic-primary-light);\r\n  color: var(--zic-primary-dark);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--green {\r\n  background: var(--zic-success-light);\r\n  color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--warning {\r\n  background: var(--zic-warning-light);\r\n  color: var(--zic-warning);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--blue {\r\n  background: var(--zic-blue-light);\r\n  color: var(--zic-blue);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardIcon--danger {\r\n  background: var(--zic-danger-light);\r\n  color: var(--zic-danger);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__cardTitle {\r\n  margin: 0;\r\n  font-size: 17px;\r\n  font-weight: 700;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Form Elements === *\/\r\n#zic-website-spoofing-v2 .zic2__field {\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 4px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__label {\r\n  font-size: 12px;\r\n  font-weight: 600;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input {\r\n  width: 100%;\r\n  padding: 14px 16px;\r\n  font-size: 15px;\r\n  color: var(--zic-ink);\r\n  background: var(--zic-surface);\r\n  border: 2px solid var(--zic-border);\r\n  border-radius: var(--zic-radius-xs);\r\n  outline: none;\r\n  transition: border-color var(--zic-transition), box-shadow var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input:focus {\r\n  border-color: var(--zic-primary);\r\n  box-shadow: 0 0 0 3px var(--zic-primary-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input:focus-visible {\r\n  outline: 3px solid var(--zic-primary);\r\n  outline-offset: 2px;\r\n  box-shadow: 0 0 0 6px rgba(137,128,245,.15);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__input::placeholder {\r\n  color: var(--zic-light);\r\n}\r\n\r\n\/* === Buttons === *\/\r\n#zic-website-spoofing-v2 .zic2__actions {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 10px;\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__actions .zic2__btn--primary {\r\n  flex: 1;\r\n  min-width: 200px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  gap: 6px;\r\n  padding: 10px 16px;\r\n  font-size: 14px;\r\n  font-weight: 600;\r\n  border-radius: var(--zic-radius-sm);\r\n  border: 1px solid transparent;\r\n  cursor: pointer;\r\n  transition: all var(--zic-transition);\r\n  white-space: nowrap;\r\n  text-decoration: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:focus {\r\n  box-shadow: 0 0 0 3px var(--zic-primary-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:focus-visible {\r\n  outline: 3px solid var(--zic-primary);\r\n  outline-offset: 2px;\r\n  box-shadow: 0 0 0 6px rgba(137,128,245,.2);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:active {\r\n  transform: translateY(1px);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--primary {\r\n  background: linear-gradient(135deg, var(--zic-primary), var(--zic-primary-dark));\r\n  color: #fff;\r\n  box-shadow: 0 4px 14px rgba(138,136,255,.35);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--primary:hover {\r\n  box-shadow: 0 6px 20px rgba(138,136,255,.45);\r\n  transform: translateY(-1px);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--large {\r\n  padding: 14px 24px;\r\n  font-size: 15px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--secondary {\r\n  background: var(--zic-surface);\r\n  border-color: var(--zic-border);\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--secondary:hover {\r\n  background: var(--zic-bg);\r\n  border-color: var(--zic-primary-border);\r\n  color: var(--zic-primary-dark);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--sm {\r\n  font-size: 13px;\r\n  padding: 10px 14px;\r\n  min-height: 44px;\r\n  gap: 6px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__exportButtons {\r\n  margin-top: 16px;\r\n  padding-top: 16px;\r\n  border-top: 1px solid var(--zic-primary-border);\r\n  display: flex;\r\n  gap: 10px;\r\n  flex-wrap: wrap;\r\n  align-items: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__exportSep {\r\n  width: 1px;\r\n  height: 24px;\r\n  background: var(--zic-border);\r\n  margin: 0 4px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn.is-success {\r\n  background: var(--zic-success-light);\r\n  border-color: var(--zic-success);\r\n  color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__sharedNote {\r\n  background: var(--zic-warning-light);\r\n  border: 1px solid var(--zic-warning);\r\n  border-radius: var(--zic-radius);\r\n  padding: 12px 16px;\r\n  margin-bottom: 16px;\r\n  font-size: 13px;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Batch Table (v4.1) === *\/\r\n#zic-website-spoofing-v2 .zic2__batchTable {\r\n  overflow-x: auto;\r\n  margin-top: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table {\r\n  width: 100%;\r\n  border-collapse: collapse;\r\n  font-size: 13px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table thead tr {\r\n  background: var(--zic-primary-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table th {\r\n  padding: 10px;\r\n  text-align: left;\r\n  border-bottom: 2px solid var(--zic-primary-border);\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table th:nth-child(3),\r\n#zic-website-spoofing-v2 .zic2__table th:nth-child(4) {\r\n  text-align: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table td {\r\n  padding: 10px;\r\n  border-bottom: 1px solid var(--zic-border);\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table td:nth-child(2) {\r\n  max-width: 300px;\r\n  overflow: hidden;\r\n  text-overflow: ellipsis;\r\n  white-space: nowrap;\r\n  font-family: monospace;\r\n  font-size: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__table td:nth-child(3),\r\n#zic-website-spoofing-v2 .zic2__table td:nth-child(4) {\r\n  text-align: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--success {\r\n  background: var(--zic-warning-light);\r\n  border-color: var(--zic-warning-border);\r\n  color: #92400E;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn--success:hover {\r\n  background: rgba(245,158,11,.15);\r\n}\r\n\r\n\/* === Hint === *\/\r\n#zic-website-spoofing-v2 .zic2__hint {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 8px;\r\n  padding: 10px 12px;\r\n  background: var(--zic-bg);\r\n  border-radius: var(--zic-radius-xs);\r\n  font-size: 12px;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__hint svg {\r\n  flex-shrink: 0;\r\n  margin-top: 1px;\r\n}\r\n\r\n\/* === Error === *\/\r\n#zic-website-spoofing-v2 .zic2__error {\r\n  margin-bottom: 16px;\r\n  padding: 12px;\r\n  background: var(--zic-danger-light);\r\n  border: 1px solid var(--zic-danger-border);\r\n  border-radius: var(--zic-radius-xs);\r\n  color: var(--zic-danger);\r\n  font-size: 13px;\r\n  font-weight: 500;\r\n}\r\n\r\n\/* === Score Card === *\/\r\n#zic-website-spoofing-v2 .zic2__scoreCard {\r\n  padding: 0;\r\n  overflow: hidden;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__analyzedUrl {\r\n  background: var(--zic-bg);\r\n  padding: 12px 20px;\r\n  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\r\n  font-size: 13px;\r\n  color: var(--zic-ink-light);\r\n  word-break: break-all;\r\n  border-bottom: 1px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay {\r\n  text-align: center;\r\n  padding: 30px 20px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay.score-safe {\r\n  background: linear-gradient(135deg, rgba(16,185,129,.05), rgba(16,185,129,.12));\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay.score-warning {\r\n  background: linear-gradient(135deg, rgba(245,158,11,.05), rgba(245,158,11,.12));\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDisplay.score-danger {\r\n  background: linear-gradient(135deg, rgba(239,68,68,.05), rgba(239,68,68,.12));\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle {\r\n  width: 100px;\r\n  height: 100px;\r\n  border-radius: 50%;\r\n  display: inline-flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n  justify-content: center;\r\n  color: white;\r\n  font-weight: bold;\r\n  margin-bottom: 16px;\r\n  box-shadow: 0 4px 15px rgba(0,0,0,.2);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle.score-safe {\r\n  background: linear-gradient(135deg, #11998e, #38ef7d);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle.score-warning {\r\n  background: linear-gradient(135deg, #F59E0B, #FBBF24);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreCircle.score-danger {\r\n  background: linear-gradient(135deg, #cb2d3e, #ef473a);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreNumber {\r\n  font-size: 32px;\r\n  line-height: 1;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreLabel {\r\n  font-size: 11px;\r\n  opacity: 0.9;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreText {\r\n  font-size: 20px;\r\n  font-weight: 700;\r\n  margin-bottom: 5px;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__scoreDesc {\r\n  font-size: 14px;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n\/* === Checks List === *\/\r\n#zic-website-spoofing-v2 .zic2__checksList {\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 8px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 12px;\r\n  padding: 14px;\r\n  background: var(--zic-bg);\r\n  border-radius: var(--zic-radius-xs);\r\n  border-left: 4px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-pass {\r\n  border-left-color: var(--zic-success);\r\n  background: var(--zic-success-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-fail {\r\n  border-left-color: var(--zic-danger);\r\n  background: var(--zic-danger-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-warn {\r\n  border-left-color: var(--zic-warning);\r\n  background: var(--zic-warning-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkIcon {\r\n  width: 24px;\r\n  height: 24px;\r\n  border-radius: 50%;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  flex-shrink: 0;\r\n  font-size: 12px;\r\n  font-weight: 700;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-pass .zic2__checkIcon {\r\n  background: var(--zic-success);\r\n  color: white;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-fail .zic2__checkIcon {\r\n  background: var(--zic-danger);\r\n  color: white;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkItem.status-warn .zic2__checkIcon {\r\n  background: var(--zic-warning);\r\n  color: white;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkContent {\r\n  flex: 1;\r\n  min-width: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkTitle {\r\n  font-weight: 600;\r\n  font-size: 14px;\r\n  color: var(--zic-ink);\r\n  margin-bottom: 2px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__checkDesc {\r\n  font-size: 13px;\r\n  color: var(--zic-ink-light);\r\n  line-height: 1.4;\r\n}\r\n\r\n\/* === Disclaimer === *\/\r\n#zic-website-spoofing-v2 .zic2__disclaimer {\r\n  display: flex;\r\n  align-items: flex-start;\r\n  gap: 10px;\r\n  padding: 14px;\r\n  background: var(--zic-bg);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius-sm);\r\n  font-size: 12px;\r\n  color: var(--zic-muted);\r\n  line-height: 1.5;\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__disclaimer svg {\r\n  flex-shrink: 0;\r\n  color: var(--zic-warning);\r\n  margin-top: 1px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__disclaimer strong {\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n\/* === Interpretation Guide === *\/\r\n#zic-website-spoofing-v2 .zic2__guideDetails {\r\n  background: var(--zic-surface);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius-sm);\r\n  overflow: hidden;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSummary {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 8px;\r\n  padding: 12px 16px;\r\n  cursor: pointer;\r\n  font-size: 14px;\r\n  font-weight: 500;\r\n  color: var(--zic-ink-light);\r\n  background: var(--zic-bg);\r\n  list-style: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSummary::-webkit-details-marker {\r\n  display: none;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSummary svg:first-child {\r\n  color: var(--zic-primary);\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideChevron {\r\n  margin-left: auto;\r\n  transition: transform var(--zic-duration-fast) ease;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideDetails[open] .zic2__guideChevron {\r\n  transform: rotate(180deg);\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n  #zic-website-spoofing-v2 .zic2__guideChevron {\r\n    transition: none;\r\n  }\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideContent {\r\n  padding: 16px;\r\n  border-top: 1px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection {\r\n  margin-bottom: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection:last-child {\r\n  margin-bottom: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection h4 {\r\n  font-size: 14px;\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n  margin: 0 0 8px 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection ul {\r\n  margin: 0;\r\n  padding-left: 20px;\r\n  font-size: 13px;\r\n  line-height: 1.6;\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection li {\r\n  margin-bottom: 4px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__guideSection strong {\r\n  color: var(--zic-ink);\r\n}\r\n\r\n\/* === Footer === *\/\r\n#zic-website-spoofing-v2 .zic2__footer {\r\n  text-align: center;\r\n  padding: 8px 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__footerLink {\r\n  color: var(--zic-primary-dark);\r\n  text-decoration: none;\r\n  font-size: 13px;\r\n  font-weight: 600;\r\n  transition: color var(--zic-transition);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__footerLink:hover {\r\n  color: var(--zic-primary);\r\n  text-decoration: underline;\r\n}\r\n\r\n\/* === Utility === *\/\r\n#zic-website-spoofing-v2 .is-hidden {\r\n  display: none !important;\r\n}\r\n\r\n\/* === Loading Spinner === *\/\r\n@keyframes zic-spin {\r\n  0% { transform: rotate(0deg); }\r\n  100% { transform: rotate(360deg); }\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__spinner {\r\n  animation: zic-spin 1s linear infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__btn:disabled {\r\n  opacity: 0.7;\r\n  cursor: not-allowed;\r\n  transform: none !important;\r\n}\r\n\r\n\/* === API Status Indicator === *\/\r\n#zic-website-spoofing-v2 .zic2__apiStatus {\r\n  margin-top: 16px;\r\n  padding-top: 16px;\r\n  border-top: 1px solid var(--zic-border);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiStatusTitle {\r\n  font-size: 12px;\r\n  font-weight: 600;\r\n  color: var(--zic-muted);\r\n  margin-bottom: 8px;\r\n  text-transform: uppercase;\r\n  letter-spacing: 0.5px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiStatusList {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 12px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiItem {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  gap: 6px;\r\n  font-size: 13px;\r\n  color: var(--zic-ink-light);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot {\r\n  width: 8px;\r\n  height: 8px;\r\n  border-radius: 50%;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--pending {\r\n  background-color: var(--zic-light);\r\n  animation: zic-pulse 1.5s ease-in-out infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--success {\r\n  background-color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--error {\r\n  background-color: var(--zic-danger);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__apiDot--warning {\r\n  background-color: var(--zic-warning);\r\n}\r\n\r\n@keyframes zic-pulse {\r\n  0%, 100% { opacity: 1; }\r\n  50% { opacity: 0.4; }\r\n}\r\n\r\n\/* === RESPONSIVE === *\/\r\n@media (min-width: 640px) {\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    padding: 24px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 24px;\r\n  }\r\n}\r\n\r\n@media (min-width: 768px) {\r\n  #zic-website-spoofing-v2 .zic2__card {\r\n    padding: 24px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__brandbar {\r\n    padding: 24px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__mark {\r\n    width: 56px;\r\n    height: 56px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 26px;\r\n  }\r\n}\r\n\r\n\/* Large screens (1024px+) *\/\r\n@media (min-width: 1024px) {\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    max-width: 900px;\r\n  }\r\n}\r\n\r\n@media (max-width: 500px) {\r\n  #zic-website-spoofing-v2 .zic2__actions {\r\n    flex-direction: column;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__actions .zic2__btn {\r\n    width: 100%;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__apiStatusList {\r\n    flex-direction: column;\r\n    gap: 8px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle {\r\n    width: 80px;\r\n    height: 80px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreNumber {\r\n    font-size: 26px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreLabel {\r\n    font-size: 10px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 18px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__subtitle {\r\n    font-size: 13px;\r\n  }\r\n}\r\n\r\n\/* Large phones (501-639px) - fills responsive gap *\/\r\n@media (min-width: 501px) and (max-width: 639px) {\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    padding: 20px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__card {\r\n    padding: 20px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__title {\r\n    font-size: 20px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle {\r\n    width: 90px;\r\n    height: 90px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__scoreNumber {\r\n    font-size: 28px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__apiStatusList {\r\n    flex-wrap: wrap;\r\n    gap: 10px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__apiStatus {\r\n    flex: 1 1 calc(50% - 5px);\r\n    min-width: 140px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__checkItem {\r\n    padding: 14px 16px;\r\n  }\r\n  #zic-website-spoofing-v2 .zic2__loadingStep {\r\n    font-size: 13px;\r\n  }\r\n}\r\n\r\n\/* Print styles *\/\r\n@media print {\r\n  \/* Hide interactive elements *\/\r\n  #zic-website-spoofing-v2 .zic2__actions,\r\n  #zic-website-spoofing-v2 .zic2__hint,\r\n  #zic-website-spoofing-v2 .zic2__footer,\r\n  #zic-website-spoofing-v2 .zic2__loading,\r\n  #zic-website-spoofing-v2 .zic2__langBtn,\r\n  #zic-website-spoofing-v2 .zic2__themeBtn,\r\n  #zic-website-spoofing-v2 .zic2__history,\r\n  #zic-website-spoofing-v2 .zic2__qrWrapper,\r\n  #zic-website-spoofing-v2 .zic2__exportWrapper,\r\n  #zic-website-spoofing-v2 [data-action],\r\n  #zic-website-spoofing-v2 .zic2__batchMode {\r\n    display: none !important;\r\n  }\r\n\r\n  \/* Reset backgrounds for print *\/\r\n  #zic-website-spoofing-v2 {\r\n    background: white !important;\r\n    color: #111 !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__wrap {\r\n    max-width: 100% !important;\r\n    padding: 0 !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__card {\r\n    box-shadow: none !important;\r\n    border: 1px solid #ccc !important;\r\n    break-inside: avoid;\r\n    background: white !important;\r\n    margin-bottom: 16px;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__brandbar {\r\n    background: white !important;\r\n    border-bottom: 2px solid #111 !important;\r\n    padding: 16px 0 !important;\r\n  }\r\n\r\n  \/* Print header *\/\r\n  #zic-website-spoofing-v2 .zic2__brandbar::before {\r\n    content: \"Raport Verificare Website - ZIC.legal\";\r\n    display: block;\r\n    font-size: 10px;\r\n    color: #666;\r\n    text-transform: uppercase;\r\n    letter-spacing: 1px;\r\n    margin-bottom: 8px;\r\n  }\r\n\r\n  \/* Show timestamp on results *\/\r\n  #zic-website-spoofing-v2 .zic2__scoreCard::after {\r\n    content: \"Generat: \" attr(data-print-timestamp);\r\n    display: block;\r\n    font-size: 11px;\r\n    color: #666;\r\n    margin-top: 16px;\r\n    padding-top: 8px;\r\n    border-top: 1px solid #eee;\r\n  }\r\n\r\n  \/* Preserve colors for score circle *\/\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle {\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle.score-safe {\r\n    background: var(--zic-success) !important;\r\n    color: white !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle.score-warning {\r\n    background: var(--zic-warning) !important;\r\n    color: white !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__scoreCircle.score-danger {\r\n    background: var(--zic-danger) !important;\r\n    color: white !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  \/* Preserve status colors *\/\r\n  #zic-website-spoofing-v2 .zic2__checkItem,\r\n  #zic-website-spoofing-v2 .zic2__apiStatus {\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  \/* Expand all results details *\/\r\n  #zic-website-spoofing-v2 .zic2__checkItem details {\r\n    display: block !important;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__checkItem details[open] summary ~ * {\r\n    display: block !important;\r\n  }\r\n\r\n  \/* Input field styling for print *\/\r\n  #zic-website-spoofing-v2 .zic2__input {\r\n    border: 1px solid #ccc !important;\r\n    background: #f9f9f9 !important;\r\n  }\r\n\r\n  \/* Disclaimer visibility *\/\r\n  #zic-website-spoofing-v2 .zic2__disclaimer {\r\n    border: 1px solid #ddd !important;\r\n    background: #f5f5f5 !important;\r\n    print-color-adjust: exact !important;\r\n    -webkit-print-color-adjust: exact !important;\r\n  }\r\n\r\n  \/* Page breaks *\/\r\n  #zic-website-spoofing-v2 .zic2__scoreCard {\r\n    break-before: avoid;\r\n  }\r\n\r\n  #zic-website-spoofing-v2 .zic2__checkList {\r\n    break-inside: avoid;\r\n  }\r\n}\r\n\r\n\/* === Loading Overlay === *\/\r\n#zic-website-spoofing-v2 .zic2__loading {\r\n  background: var(--zic-surface);\r\n  border: 1px solid var(--zic-border);\r\n  border-radius: var(--zic-radius);\r\n  padding: 40px 20px;\r\n  margin-bottom: 16px;\r\n  box-shadow: var(--zic-shadow);\r\n  text-align: center;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingContent {\r\n  display: flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n  gap: 16px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingSpinner {\r\n  width: 48px;\r\n  height: 48px;\r\n  border: 4px solid var(--zic-border);\r\n  border-top-color: var(--zic-primary);\r\n  border-radius: 50%;\r\n  animation: zic-spin 1s linear infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingText {\r\n  font-size: 18px;\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingSubtext {\r\n  font-size: 14px;\r\n  color: var(--zic-muted);\r\n}\r\n\r\n\/* === Loading Steps Indicator (v4.1) === *\/\r\n#zic-website-spoofing-v2 .zic2__loadingSteps {\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 8px;\r\n  margin-top: 8px;\r\n  text-align: left;\r\n  width: 100%;\r\n  max-width: 260px;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 10px;\r\n  font-size: 13px;\r\n  color: var(--zic-muted);\r\n  transition: color var(--zic-duration-fast) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-active {\r\n  color: var(--zic-ink);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-done {\r\n  color: var(--zic-success);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-failed {\r\n  color: var(--zic-danger);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-timeout {\r\n  color: var(--zic-warning);\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__stepIcon {\r\n  width: 18px;\r\n  height: 18px;\r\n  border-radius: 50%;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  font-size: 10px;\r\n  font-weight: 700;\r\n  flex-shrink: 0;\r\n  background: var(--zic-border);\r\n  color: var(--zic-muted);\r\n  transition: all var(--zic-duration-fast) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-active .zic2__stepIcon {\r\n  background: var(--zic-primary-light);\r\n  border: 2px solid var(--zic-primary);\r\n  animation: zic-pulse 1s ease-in-out infinite;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-done .zic2__stepIcon {\r\n  background: var(--zic-success);\r\n  color: #fff;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-failed .zic2__stepIcon {\r\n  background: var(--zic-danger);\r\n  color: #fff;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingStep.is-timeout .zic2__stepIcon {\r\n  background: var(--zic-warning);\r\n  color: #fff;\r\n}\r\n\r\n\/* Progress bar *\/\r\n#zic-website-spoofing-v2 .zic2__loadingProgress {\r\n  width: 100%;\r\n  max-width: 260px;\r\n  height: 6px;\r\n  background: var(--zic-border);\r\n  border-radius: 3px;\r\n  margin-top: 12px;\r\n  overflow: hidden;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__progressBar {\r\n  height: 100%;\r\n  width: 0%;\r\n  background: linear-gradient(90deg, var(--zic-primary), var(--zic-success));\r\n  border-radius: 3px;\r\n  transition: width var(--zic-duration-normal) ease;\r\n}\r\n\r\n#zic-website-spoofing-v2 .zic2__loadingPercent {\r\n  font-size: 14px;\r\n  font-weight: 600;\r\n  color: var(--zic-ink);\r\n  margin-top: 4px;\r\n}\r\n\r\n\/* Reduced motion *\/\r\n@media (prefers-reduced-motion: reduce) {\r\n  #zic-website-spoofing-v2 .zic2__loadingStep.is-active .zic2__stepIcon {\r\n    animation: none;\r\n  }\r\n}\r\n<\/style>\r\n\r\n<!-- jsQR Library for QR Code Scanning -->\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/jsqr@1.4.0\/dist\/jsQR.min.js\"><\/script>\r\n\r\n<script>\r\n(function() {\r\n  'use strict';\r\n\r\n  const ROOT_ID = 'zic-website-spoofing-v2';\r\n  const root = document.getElementById(ROOT_ID);\r\n  if (!root) return;\r\n\r\n  \/\/ === INTERNATIONALIZATION (i18n) ===\r\n  const LANG = {\r\n    ro: {\r\n      \/\/ Header\r\n      title: 'Verificare website spoofing',\r\n      subtitle: 'Detecteaz\u0103 link-uri suspecte \u0219i tentative de phishing',\r\n      langSwitch: 'EN',\r\n      \/\/ Formula\r\n      formula: '<strong>Cum func\u021bioneaz\u0103:<\/strong> Analiz\u0103m URL-ul pentru typosquatting, caractere Unicode suspecte, extensii de domeniu riscante \u0219i alte indicii de phishing. Verific\u0103m suplimentar prin <strong>5 surse externe<\/strong>: Google Safe Browsing, VirusTotal, URLhaus, urlscan.io \u0219i PhishTank.',\r\n      \/\/ Input\r\n      inputTitle: 'Link de verificat',\r\n      inputLabel: 'Introdu link-ul website-ului',\r\n      inputPlaceholder: 'https:\/\/example.com',\r\n      hint: 'Copiaz\u0103 link-ul direct din email, mesaj sau bara de adrese a browser-ului.',\r\n      \/\/ QR Code\r\n      qrLabel: 'Sau \u00eencarc\u0103 un cod QR cu un link',\r\n      qrUploadBtn: '\u00cencarc\u0103 imagine QR',\r\n      \/\/ Buttons\r\n      btnAnalyze: 'Verific\u0103 link',\r\n      btnAnalyzing: 'Se verific\u0103...',\r\n      btnReset: '\u0218terge',\r\n      btnExample: 'Exemplu suspect',\r\n      \/\/ Loading\r\n      loadingText: 'Se verific\u0103 URL-ul...',\r\n      loadingSub: 'Interog\u0103m 5 baze de date de securitate',\r\n      loadingLocal: 'Analiz\u0103 local\u0103',\r\n      loadingGoogle: 'Google Safe Browsing',\r\n      loadingVT: 'VirusTotal',\r\n      loadingURLhaus: 'URLhaus',\r\n      loadingUrlscan: 'urlscan.io',\r\n      loadingPhishtank: 'PhishTank',\r\n      \/\/ Results\r\n      scoreLabel: 'din 100',\r\n      resultsTitle: 'Rezultate analiz\u0103',\r\n      apiStatusTitle: 'Verific\u0103ri externe (5 surse):',\r\n      \/\/ Score texts\r\n      scoreSafe: 'Risc sc\u0103zut',\r\n      scoreWarning: 'Aten\u021bie necesar\u0103',\r\n      scoreDanger: 'Risc ridicat',\r\n      descSafe: 'Link-ul pare a fi legitim. Nu s-au detectat semne de phishing.',\r\n      descWarning: 'Au fost detectate unele probleme. Verific\u0103 manual \u00eenainte de a accesa.',\r\n      descDanger: 'Multiple semne de fraudare detectate. Nu accesa acest link!',\r\n      \/\/ Disclaimer\r\n      disclaimer: '<strong>Disclaimer:<\/strong> Aceast\u0103 analiz\u0103 este orientativ\u0103 \u0219i combin\u0103 verific\u0103ri locale cu 5 servicii externe (Google Safe Browsing, VirusTotal, URLhaus, urlscan.io, PhishTank). Nu \u00eenlocuie\u0219te o verificare profesional\u0103 de securitate, precum cea oferit\u0103 de <a href=\"https:\/\/cyberopsnetwork.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">CyberOps Network<\/a> \u2013 partenerii ZIC.legal.',\r\n      \/\/ Errors\r\n      errorEmpty: 'Te rug\u0103m s\u0103 introduci un link pentru verificare.',\r\n      errorTooLong: 'URL-ul este prea lung. Limita este de {max} caractere.',\r\n      errorDangerous: 'URL-ul con\u021bine caractere sau scheme periculoase.',\r\n      errorInvalid: 'Link-ul introdus nu este valid. Te rug\u0103m verific\u0103 formatul.',\r\n      errorGeneral: 'A ap\u0103rut o eroare la analiz\u0103. V\u0103 rug\u0103m \u00eencerca\u021bi din nou.',\r\n      \/\/ Check results\r\n      checkHttpsPass: 'Conexiune HTTPS',\r\n      checkHttpsPassDesc: 'Site-ul folose\u0219te protocol securizat HTTPS.',\r\n      checkHttpsFail: 'Lips\u0103 HTTPS',\r\n      checkHttpsFailDesc: 'Site-ul nu folose\u0219te HTTPS. Datele nu sunt criptate!',\r\n      checkUnicodePass: 'Caractere legitime',\r\n      checkUnicodePassDesc: 'Nu s-au detectat caractere Unicode suspecte \u00een domeniu.',\r\n      checkUnicodeFail: 'Caractere Unicode suspecte',\r\n      checkUnicodeFailDesc: 'Domeniul con\u021bine caractere care imit\u0103 litere latine. Forma real\u0103: \"{domain}\"',\r\n      \/\/ API results\r\n      googleOk: 'Google Safe Browsing: OK',\r\n      googleOkDesc: 'URL-ul nu este raportat \u00een baza de date Google.',\r\n      googleFail: 'Google Safe Browsing: PERICOL',\r\n      googleFailDesc: 'Google a detectat: {threats}. NU accesa\u021bi acest link!',\r\n      vtOk: 'VirusTotal: curat',\r\n      vtOkDesc: 'Niciun motor antivirus nu a detectat amenin\u021b\u0103ri.',\r\n      vtFail: 'VirusTotal: DETEC\u021aII',\r\n      vtFailDesc: '{count} motoare antivirus au detectat amenin\u021b\u0103ri.',\r\n      urlhausOk: 'URLhaus: curat',\r\n      urlhausOkDesc: 'URL-ul nu apare \u00een baza de date URLhaus.',\r\n      urlhausFail: 'URLhaus: MALWARE',\r\n      urlhausFailDesc: 'URL-ul este \u00een baza de date URLhaus. Tip: {threat}.',\r\n      urlscanOk: 'urlscan.io: OK',\r\n      urlscanOkDesc: 'Nicio amenin\u021bare detectat\u0103{scans}.',\r\n      urlscanFail: 'urlscan.io: SUSPECT',\r\n      urlscanFailDesc: 'Domeniul a fost marcat ca mali\u021bios. Verdicts: {verdicts}',\r\n      phishtankOk: 'PhishTank: OK',\r\n      phishtankOkDesc: 'URL-ul nu este \u00een baza de date PhishTank (Cisco Talos).',\r\n      phishtankFail: 'PhishTank: PHISHING CONFIRMAT',\r\n      phishtankFailDesc: 'URL-ul este \u00een baza de date PhishTank ca site de phishing verificat!',\r\n      \/\/ Local checks\r\n      typosquatTitle: 'Typosquatting detectat',\r\n      typosquatDouble: 'Typosquatting prin litere duble',\r\n      typosquatVisual: 'Typosquatting vizual',\r\n      typosquatSubst: 'Typosquatting prin substitu\u021bie',\r\n      typosquatHyphen: 'Brand fragmentat cu cratime',\r\n      typosquatKeyboard: 'Eroare tastare detectat\u0103',\r\n      typosquatSimilarity: 'Similaritate suspect\u0103',\r\n      typosquatRepetition: 'Litere repetate',\r\n      typosquatOmission: 'Caracter lips\u0103',\r\n      typosquatTransposition: 'Litere inversate',\r\n      typosquatVowelSwap: 'Vocale substituite',\r\n      typosquatDesc: 'Domeniul seam\u0103n\u0103 suspect cu brandul \"{brand}\".',\r\n      brandWrongTld: 'Brand pe TLD gre\u0219it',\r\n      brandOk: 'Brand recunoscut',\r\n      brandOkDesc: 'Domeniul corespunde unui brand cunoscut.',\r\n      noTyposquat: 'F\u0103r\u0103 typosquatting detectat',\r\n      noTyposquatDesc: 'Domeniul nu pare s\u0103 imite branduri cunoscute.',\r\n      suspiciousTld: 'Extensie domeniu suspect\u0103',\r\n      suspiciousTldDesc: 'Domeniul folose\u0219te o extensie frecvent asociat\u0103 cu site-uri frauduloase.',\r\n      tldOk: 'Extensie domeniu OK',\r\n      tldOkDesc: 'Extensia domeniului nu ridic\u0103 suspiciuni.',\r\n      multiSubdomain: 'Subdomain-uri multiple',\r\n      multiSubdomainDesc: 'Domeniul are {count} subdomain-uri.',\r\n      subdomainOk: 'Structur\u0103 domeniu normal\u0103',\r\n      subdomainOkDesc: 'Num\u0103rul de subdomain-uri este normal.',\r\n      phishKeywords: 'Cuvinte cheie phishing',\r\n      phishKeywordsDesc: 'URL-ul con\u021bine termeni suspec\u021bi: \"{keywords}\"',\r\n      sensitiveTerm: 'Termen sensibil \u00een URL',\r\n      sensitiveTermDesc: 'URL-ul con\u021bine termenul \"{keyword}\".',\r\n      noSuspiciousTerms: 'URL f\u0103r\u0103 termeni suspec\u021bi',\r\n      noSuspiciousTermsDesc: 'Nu s-au detectat cuvinte cheie asociate cu phishing.',\r\n      longDomain: 'Domeniu foarte lung',\r\n      longDomainDesc: 'Domeniul are {length} caractere.',\r\n      domainLengthOk: 'Lungime domeniu OK',\r\n      domainLengthOkDesc: 'Lungimea domeniului este normal\u0103.',\r\n      ipAddress: 'Adres\u0103 IP \u00een loc de domeniu',\r\n      ipAddressDesc: 'URL-ul folose\u0219te o adres\u0103 IP direct\u0103.',\r\n      nonStandardPort: 'Port non-standard',\r\n      nonStandardPortDesc: 'URL-ul folose\u0219te portul {port}.',\r\n      idnDomain: 'Domeniu interna\u021bional (IDN\/Punycode)',\r\n      idnDomainDesc: 'Domeniul folose\u0219te caractere interna\u021bionale codificate.',\r\n      unusualChars: 'Caractere neobi\u0219nuite',\r\n      unusualCharsDesc: 'Domeniul con\u021bine caractere speciale neobi\u0219nuite.',\r\n      brandInSubdomain: 'Brand \u00een subdomain',\r\n      brandInSubdomainDesc: 'Un brand cunoscut apare \u00een subdomain dar nu \u00een domeniul principal.',\r\n      \/\/ Interpretation Guide\r\n      guideTitle: 'Ce \u00eenseamn\u0103 rezultatele?',\r\n      guideScoreTitle: '&#x1f4ca; Scorul de \u00eencredere (0-100)',\r\n      guideScoreSafe: 'Risc sc\u0103zut - link probabil sigur',\r\n      guideScoreWarning: 'Verificare manual\u0103 recomandat\u0103',\r\n      guideScoreDanger: 'Risc ridicat - NU accesa!',\r\n      guideChecksTitle: '&#x1f50d; Tipuri de verific\u0103ri',\r\n      guideTyposquat: 'Typosquatting:',\r\n      guideTyposquatDesc: 'Domeniu care imit\u0103 un brand cunoscut (ex: gooogle.com)',\r\n      guideHttps: 'HTTPS:',\r\n      guideHttpsDesc: 'Conexiune securizat\u0103 - lipsa poate indica risc',\r\n      guideUnicode: 'Unicode suspect:',\r\n      guideUnicodeDesc: 'Caractere care arat\u0103 ca litere normale dar sunt diferite',\r\n      guideTld: 'TLD suspect:',\r\n      guideTldDesc: 'Extensii precum .tk, .xyz, .ml sunt frecvent abuzate',\r\n      guideKeywords: 'Cuvinte cheie:',\r\n      guideKeywordsDesc: 'Termeni precum \"login\", \"verify\", \"secure\" \u00een URL-uri suspecte',\r\n      guideApisTitle: '&#x1f310; Verific\u0103ri externe',\r\n      guideGsb: 'Baz\u0103 de date Google cu site-uri periculoase',\r\n      guideVt: 'Scanare cu 70+ motoare antivirus',\r\n      guideUrlhaus: 'Baz\u0103 de date specializat\u0103 \u00een malware',\r\n      guideUrlscan: 'Analiz\u0103 comportamental\u0103 a site-ului',\r\n      guidePhishtank: 'Comunitate care raporteaz\u0103 phishing',\r\n      guideActionsTitle: '&#x2705; Ce s\u0103 faci',\r\n      guideAction1: 'Dac\u0103 scorul e sub 40: NU accesa link-ul',\r\n      guideAction2: 'Verific\u0103 manual adresa \u00eenainte de a introduce date personale',\r\n      guideAction3: 'Dac\u0103 ai dubii, contacteaz\u0103 direct organiza\u021bia pe canalele oficiale',\r\n      guideAction4: 'Raporteaz\u0103 link-urile de phishing la poli\u021bie sau CERT-RO',\r\n      \/\/ Theme\r\n      themeLight: 'Comut\u0103 pe mod luminos',\r\n      themeDark: 'Comut\u0103 pe mod \u00eentunecat',\r\n      \/\/ Share\r\n      shareLink: 'Copiaz\u0103 link',\r\n      shareLinkCopied: 'Link copiat!',\r\n      printReport: 'Printeaz\u0103',\r\n      \/\/ Batch\r\n      batchTruncated: 'Doar primele {count} URL-uri din {total} vor fi procesate.'\r\n    },\r\n    en: {\r\n      \/\/ Header\r\n      title: 'Website spoofing check',\r\n      subtitle: 'Detect suspicious links and phishing attempts',\r\n      langSwitch: 'RO',\r\n      \/\/ Formula\r\n      formula: '<strong>How it works:<\/strong> We analyse the URL for typosquatting, suspicious Unicode characters, risky domain extensions, and other phishing indicators. We additionally verify through <strong>5 external sources<\/strong>: Google Safe Browsing, VirusTotal, URLhaus, urlscan.io, and PhishTank.',\r\n      \/\/ Input\r\n      inputTitle: 'Link to check',\r\n      inputLabel: 'Enter the website link',\r\n      inputPlaceholder: 'https:\/\/example.com',\r\n      hint: 'Copy the link directly from email, message, or browser address bar.',\r\n      \/\/ QR Code\r\n      qrLabel: 'Or upload a QR code with a link',\r\n      qrUploadBtn: 'Upload QR image',\r\n      \/\/ Buttons\r\n      btnAnalyze: 'Check link',\r\n      btnAnalyzing: 'Checking...',\r\n      btnReset: 'Clear',\r\n      btnExample: 'Suspicious example',\r\n      \/\/ Loading\r\n      loadingText: 'Checking URL...',\r\n      loadingSub: 'Querying 5 security databases',\r\n      loadingLocal: 'Local analysis',\r\n      loadingGoogle: 'Google Safe Browsing',\r\n      loadingVT: 'VirusTotal',\r\n      loadingURLhaus: 'URLhaus',\r\n      loadingUrlscan: 'urlscan.io',\r\n      loadingPhishtank: 'PhishTank',\r\n      \/\/ Results\r\n      scoreLabel: 'out of 100',\r\n      resultsTitle: 'Analysis results',\r\n      apiStatusTitle: 'External checks (5 sources):',\r\n      \/\/ Score texts\r\n      scoreSafe: 'Low risk',\r\n      scoreWarning: 'Caution required',\r\n      scoreDanger: 'High risk',\r\n      descSafe: 'The link appears to be legitimate. No signs of phishing detected.',\r\n      descWarning: 'Some issues detected. Verify manually before accessing.',\r\n      descDanger: 'Multiple fraud signs detected. Do not access this link!',\r\n      \/\/ Disclaimer\r\n      disclaimer: '<strong>Disclaimer:<\/strong> This analysis is indicative and combines local checks with 5 external services (Google Safe Browsing, VirusTotal, URLhaus, urlscan.io, PhishTank). It does not replace a professional security assessment, such as that offered by <a href=\"https:\/\/cyberopsnetwork.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">CyberOps Network<\/a> \u2013 ZIC.legal partners.',\r\n      \/\/ Errors\r\n      errorEmpty: 'Please enter a link to check.',\r\n      errorTooLong: 'URL is too long. Maximum is {max} characters.',\r\n      errorDangerous: 'URL contains dangerous characters or schemes.',\r\n      errorInvalid: 'The entered link is not valid. Please check the format.',\r\n      errorGeneral: 'An error occurred during analysis. Please try again.',\r\n      \/\/ Check results\r\n      checkHttpsPass: 'HTTPS connection',\r\n      checkHttpsPassDesc: 'The site uses secure HTTPS protocol.',\r\n      checkHttpsFail: 'Missing HTTPS',\r\n      checkHttpsFailDesc: 'The site does not use HTTPS. Data is not encrypted!',\r\n      checkUnicodePass: 'Legitimate characters',\r\n      checkUnicodePassDesc: 'No suspicious Unicode characters detected in domain.',\r\n      checkUnicodeFail: 'Suspicious Unicode characters',\r\n      checkUnicodeFailDesc: 'The domain contains characters mimicking Latin letters. Real form: \"{domain}\"',\r\n      \/\/ API results\r\n      googleOk: 'Google Safe Browsing: OK',\r\n      googleOkDesc: 'URL is not reported in Google database.',\r\n      googleFail: 'Google Safe Browsing: DANGER',\r\n      googleFailDesc: 'Google detected: {threats}. DO NOT access this link!',\r\n      vtOk: 'VirusTotal: clean',\r\n      vtOkDesc: 'No antivirus engine detected threats.',\r\n      vtFail: 'VirusTotal: DETECTIONS',\r\n      vtFailDesc: '{count} antivirus engines detected threats.',\r\n      urlhausOk: 'URLhaus: clean',\r\n      urlhausOkDesc: 'URL is not in URLhaus database.',\r\n      urlhausFail: 'URLhaus: MALWARE',\r\n      urlhausFailDesc: 'URL is in URLhaus database. Type: {threat}.',\r\n      urlscanOk: 'urlscan.io: OK',\r\n      urlscanOkDesc: 'No threats detected{scans}.',\r\n      urlscanFail: 'urlscan.io: SUSPECT',\r\n      urlscanFailDesc: 'Domain was marked as malicious. Verdicts: {verdicts}',\r\n      phishtankOk: 'PhishTank: OK',\r\n      phishtankOkDesc: 'URL is not in PhishTank database (Cisco Talos).',\r\n      phishtankFail: 'PhishTank: PHISHING CONFIRMED',\r\n      phishtankFailDesc: 'URL is in PhishTank database as verified phishing site!',\r\n      \/\/ Local checks\r\n      typosquatTitle: 'Typosquatting detected',\r\n      typosquatDouble: 'Double letter typosquatting',\r\n      typosquatVisual: 'Visual typosquatting',\r\n      typosquatSubst: 'Substitution typosquatting',\r\n      typosquatHyphen: 'Hyphen-fragmented brand',\r\n      typosquatKeyboard: 'Keyboard typo detected',\r\n      typosquatSimilarity: 'Suspicious similarity',\r\n      typosquatRepetition: 'Repeated letters',\r\n      typosquatOmission: 'Missing character',\r\n      typosquatTransposition: 'Swapped letters',\r\n      typosquatVowelSwap: 'Vowel substitution',\r\n      typosquatDesc: 'Domain suspiciously resembles the brand \"{brand}\".',\r\n      brandWrongTld: 'Brand on wrong TLD',\r\n      brandOk: 'Recognised brand',\r\n      brandOkDesc: 'Domain corresponds to a known brand.',\r\n      noTyposquat: 'No typosquatting detected',\r\n      noTyposquatDesc: 'Domain does not appear to mimic known brands.',\r\n      suspiciousTld: 'Suspicious domain extension',\r\n      suspiciousTldDesc: 'Domain uses an extension frequently associated with fraudulent sites.',\r\n      tldOk: 'Domain extension OK',\r\n      tldOkDesc: 'Domain extension does not raise suspicions.',\r\n      multiSubdomain: 'Multiple subdomains',\r\n      multiSubdomainDesc: 'Domain has {count} subdomains.',\r\n      subdomainOk: 'Normal domain structure',\r\n      subdomainOkDesc: 'Number of subdomains is normal.',\r\n      phishKeywords: 'Phishing keywords',\r\n      phishKeywordsDesc: 'URL contains suspicious terms: \"{keywords}\"',\r\n      sensitiveTerm: 'Sensitive term in URL',\r\n      sensitiveTermDesc: 'URL contains the term \"{keyword}\".',\r\n      noSuspiciousTerms: 'URL without suspicious terms',\r\n      noSuspiciousTermsDesc: 'No keywords associated with phishing detected.',\r\n      longDomain: 'Very long domain',\r\n      longDomainDesc: 'Domain has {length} characters.',\r\n      domainLengthOk: 'Domain length OK',\r\n      domainLengthOkDesc: 'Domain length is normal.',\r\n      ipAddress: 'IP address instead of domain',\r\n      ipAddressDesc: 'URL uses a direct IP address.',\r\n      nonStandardPort: 'Non-standard port',\r\n      nonStandardPortDesc: 'URL uses port {port}.',\r\n      idnDomain: 'International domain (IDN\/Punycode)',\r\n      idnDomainDesc: 'Domain uses encoded international characters.',\r\n      unusualChars: 'Unusual characters',\r\n      unusualCharsDesc: 'Domain contains unusual special characters.',\r\n      brandInSubdomain: 'Brand in subdomain',\r\n      brandInSubdomainDesc: 'A known brand appears in subdomain but not in main domain.',\r\n      \/\/ Interpretation Guide\r\n      guideTitle: 'What do the results mean?',\r\n      guideScoreTitle: '&#x1f4ca; Trust Score (0-100)',\r\n      guideScoreSafe: 'Low risk - link is probably safe',\r\n      guideScoreWarning: 'Manual verification recommended',\r\n      guideScoreDanger: 'High risk - DO NOT access!',\r\n      guideChecksTitle: '&#x1f50d; Types of checks',\r\n      guideTyposquat: 'Typosquatting:',\r\n      guideTyposquatDesc: 'Domain that mimics a known brand (e.g., gooogle.com)',\r\n      guideHttps: 'HTTPS:',\r\n      guideHttpsDesc: 'Secure connection - absence may indicate risk',\r\n      guideUnicode: 'Suspicious Unicode:',\r\n      guideUnicodeDesc: 'Characters that look like normal letters but are different',\r\n      guideTld: 'Suspicious TLD:',\r\n      guideTldDesc: 'Extensions like .tk, .xyz, .ml are frequently abused',\r\n      guideKeywords: 'Keywords:',\r\n      guideKeywordsDesc: 'Terms like \"login\", \"verify\", \"secure\" in suspicious URLs',\r\n      guideApisTitle: '&#x1f310; External checks',\r\n      guideGsb: 'Google database of dangerous sites',\r\n      guideVt: 'Scan with 70+ antivirus engines',\r\n      guideUrlhaus: 'Database specialized in malware',\r\n      guideUrlscan: 'Behavioral analysis of the site',\r\n      guidePhishtank: 'Community reporting phishing',\r\n      guideActionsTitle: '&#x2705; What to do',\r\n      guideAction1: 'If score is below 40: DO NOT access the link',\r\n      guideAction2: 'Manually verify the address before entering personal data',\r\n      guideAction3: 'If in doubt, contact the organization directly through official channels',\r\n      guideAction4: 'Report phishing links to police or your local CERT',\r\n      \/\/ Theme\r\n      themeLight: 'Switch to light mode',\r\n      themeDark: 'Switch to dark mode',\r\n      \/\/ Share\r\n      shareLink: 'Copy link',\r\n      shareLinkCopied: 'Link copied!',\r\n      printReport: 'Print',\r\n      \/\/ Batch\r\n      batchTruncated: 'Only the first {count} of {total} URLs will be processed.'\r\n    }\r\n  };\r\n\r\n  \/\/ Detect browser language, default to Romanian\r\n  let currentLang = navigator.language.startsWith('ro') ? 'ro' : 'en';\r\n\r\n  \/\/ Get translation\r\n  function t(key, replacements = {}) {\r\n    let text = LANG[currentLang][key] || LANG['ro'][key] || key;\r\n    for (const [placeholder, value] of Object.entries(replacements)) {\r\n      text = text.replace('{' + placeholder + '}', value);\r\n    }\r\n    return text;\r\n  }\r\n\r\n  \/\/ Apply translations to all elements with data-i18n attributes\r\n  function applyTranslations() {\r\n    \/\/ Text content\r\n    root.querySelectorAll('[data-i18n]').forEach(el => {\r\n      const key = el.getAttribute('data-i18n');\r\n      if (LANG[currentLang][key]) {\r\n        el.textContent = LANG[currentLang][key];\r\n      }\r\n    });\r\n    \/\/ HTML content\r\n    root.querySelectorAll('[data-i18n-html]').forEach(el => {\r\n      const key = el.getAttribute('data-i18n-html');\r\n      if (LANG[currentLang][key]) {\r\n        el.innerHTML = LANG[currentLang][key];\r\n      }\r\n    });\r\n    \/\/ Placeholders\r\n    root.querySelectorAll('[data-i18n-placeholder]').forEach(el => {\r\n      const key = el.getAttribute('data-i18n-placeholder');\r\n      if (LANG[currentLang][key]) {\r\n        el.placeholder = LANG[currentLang][key];\r\n      }\r\n    });\r\n  }\r\n\r\n  \/\/ Toggle language\r\n  function toggleLanguage() {\r\n    currentLang = currentLang === 'ro' ? 'en' : 'ro';\r\n    applyTranslations();\r\n  }\r\n\r\n  \/\/ === THEME MANAGEMENT ===\r\n  const THEME_KEY = 'zic-theme';\r\n  const themeBtn = root.querySelector('[data-action=\"toggleTheme\"]');\r\n\r\n  \/\/ Detect system preference\r\n  function getSystemTheme() {\r\n    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n  }\r\n\r\n  \/\/ Get current theme (stored > system)\r\n  function getCurrentTheme() {\r\n    return localStorage.getItem(THEME_KEY) || null;\r\n  }\r\n\r\n  \/\/ Apply theme to root element\r\n  function applyTheme(theme) {\r\n    if (theme) {\r\n      root.setAttribute('data-theme', theme);\r\n    } else {\r\n      root.removeAttribute('data-theme');\r\n    }\r\n    updateThemeButton(theme || getSystemTheme());\r\n  }\r\n\r\n  \/\/ Update button aria-label and pressed state\r\n  function updateThemeButton(activeTheme) {\r\n    if (!themeBtn) return;\r\n    const isDark = activeTheme === 'dark';\r\n    themeBtn.setAttribute('aria-pressed', isDark.toString());\r\n    themeBtn.setAttribute('aria-label', t(isDark ? 'themeLight' : 'themeDark'));\r\n  }\r\n\r\n  \/\/ Toggle between themes\r\n  function toggleTheme() {\r\n    const current = getCurrentTheme();\r\n    const systemTheme = getSystemTheme();\r\n    let newTheme;\r\n\r\n    if (current === null) {\r\n      \/\/ No preference stored, switch from system default\r\n      newTheme = systemTheme === 'dark' ? 'light' : 'dark';\r\n    } else {\r\n      \/\/ Toggle stored preference\r\n      newTheme = current === 'dark' ? 'light' : 'dark';\r\n    }\r\n\r\n    localStorage.setItem(THEME_KEY, newTheme);\r\n    applyTheme(newTheme);\r\n  }\r\n\r\n  \/\/ Listen for system theme changes\r\n  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {\r\n    \/\/ Only react if no manual override stored\r\n    if (!getCurrentTheme()) {\r\n      updateThemeButton(e.matches ? 'dark' : 'light');\r\n    }\r\n  });\r\n\r\n  \/\/ Initialize theme on load\r\n  applyTheme(getCurrentTheme());\r\n\r\n  \/\/ === CSS VARIABLE HELPERS ===\r\n  function getCssVar(name) {\r\n    return getComputedStyle(root).getPropertyValue('--zic-' + name).trim();\r\n  }\r\n\r\n  function getRiskColors() {\r\n    return {\r\n      safe: getCssVar('success'),\r\n      warning: getCssVar('warning'),\r\n      danger: getCssVar('danger')\r\n    };\r\n  }\r\n\r\n  \/\/ === SECURITY: Maximum input length to prevent DoS ===\r\n  const MAX_URL_LENGTH = 2048;\r\n\r\n  \/\/ === SECURITY: Rate limiting to prevent abuse ===\r\n  let lastAnalysisTime = 0;\r\n  const MIN_ANALYSIS_INTERVAL = 500;\r\n\r\n  \/\/ === SCORE THRESHOLDS ===\r\n  const SCORE_THRESHOLDS = {\r\n    safe: 80,      \/\/ 80-100 = risc sc\u0103zut\r\n    warning: 50    \/\/ 50-79 = aten\u021bie, 0-49 = pericol\r\n  };\r\n\r\n  \/\/ === BATCH LIMIT ===\r\n  const BATCH_LIMIT = 10;\r\n\r\n  \/\/ === Cloudflare Worker Proxy pentru API-uri fara CORS ===\r\n  \/\/ IMPORTANT: Inlocuieste cu URL-ul tau de Cloudflare Worker dupa deploy!\r\n  \/\/ Exemplu: 'https:\/\/zic-security-proxy.YOUR-SUBDOMAIN.workers.dev'\r\n  const CLOUDFLARE_PROXY = 'https:\/\/zic-security-proxy.red-tooth-f5c5.workers.dev';\r\n\r\n  \/\/ === API CONFIGURATION ===\r\n  \/\/ SECURITATE: Toate API keys sunt acum \u00een Cloudflare Worker (backend)\r\n  \/\/ Nu mai sunt expuse \u00een codul client\r\n  const API_CONFIG = {\r\n    \/\/ Google Safe Browsing API - prin Cloudflare Worker proxy (API key \u00een backend)\r\n    GOOGLE_SAFE_BROWSING: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ VirusTotal API - prin Cloudflare Worker proxy\r\n    VIRUSTOTAL: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ IPQualityScore API - prin Cloudflare Worker proxy\r\n    IPQUALITYSCORE: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ URLhaus - prin Cloudflare Worker proxy\r\n    URLHAUS: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ urlscan.io - prin Cloudflare Worker proxy\r\n    URLSCAN: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ PhishTank - prin Cloudflare Worker proxy\r\n    PHISHTANK: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ PhishStats - DEZACTIVAT (server down\/timeout)\r\n    PHISHSTATS: {\r\n      enabled: false,\r\n      useProxy: true\r\n    },\r\n    \/\/ === NOI VERIFIC\u0102RI v3 ===\r\n    \/\/ DNS Analysis - verific\u0103 DNS records\r\n    DNS: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ GeoIP - loca\u021bia serverului\r\n    GEOIP: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ WHOIS - v\u00e2rsta domeniului\r\n    WHOIS: {\r\n      enabled: true,\r\n      useProxy: true\r\n    },\r\n    \/\/ SSL Certificate validation\r\n    SSL: {\r\n      enabled: true,\r\n      useProxy: true\r\n    }\r\n  };\r\n\r\n  \/\/ === SECURITY: HTML Entity Encoding ===\r\n  function escapeHtml(text) {\r\n    if (typeof text !== 'string') return '';\r\n    const map = {\r\n      '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;',\r\n      \"'\": '&#039;', '\/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;'\r\n    };\r\n    return text.replace(\/[&<>\"'`=\\\/]\/g, s => map[s]);\r\n  }\r\n\r\n  \/\/ === ACCESSIBILITY: Screen Reader Announcements ===\r\n  function announceToSR(message, priority = 'polite') {\r\n    const srContainer = root.querySelector('[data-sr-status]');\r\n    if (!srContainer) return;\r\n    srContainer.setAttribute('aria-live', priority);\r\n    srContainer.textContent = '';\r\n    \/\/ Force reflow for announcement\r\n    requestAnimationFrame(() => {\r\n      srContainer.textContent = message;\r\n    });\r\n  }\r\n\r\n  function sanitizeInput(input) {\r\n    if (typeof input !== 'string') return '';\r\n    return input.replace(\/\\0\/g, '').replace(\/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]\/g, '').trim().substring(0, MAX_URL_LENGTH);\r\n  }\r\n\r\n  function validateStatus(status) {\r\n    const allowedStatuses = ['pass', 'warn', 'fail'];\r\n    return allowedStatuses.includes(status) ? status : 'warn';\r\n  }\r\n\r\n  function containsDangerousPatterns(url) {\r\n    if (typeof url !== 'string') return true;\r\n    const dangerousPatterns = [\/^javascript:\/i, \/^data:\/i, \/^vbscript:\/i, \/^file:\/i, \/&#\/, \/%00\/, \/\\x00\/];\r\n    return dangerousPatterns.some(pattern => pattern.test(url));\r\n  }\r\n\r\n  const $ = (sel) => root.querySelector(sel);\r\n\r\n  const elements = {\r\n    urlInput: $('[data-field=\"urlInput\"]'),\r\n    errors: $('[data-errors]'),\r\n    scoreCard: $('[data-score-card]'),\r\n    analyzedUrl: $('[data-analyzed-url]'),\r\n    scoreDisplay: $('[data-score-display]'),\r\n    scoreCircle: $('[data-score-circle]'),\r\n    scoreNumber: $('[data-score-number]'),\r\n    scoreText: $('[data-score-text]'),\r\n    scoreDesc: $('[data-score-desc]'),\r\n    checksCard: $('[data-checks-card]'),\r\n    checksList: $('[data-checks-list]'),\r\n    apiStatus: $('[data-api-status]'),\r\n    loading: $('[data-loading]'),\r\n    apiGoogle: $('[data-api=\"google\"]'),\r\n    apiVirusTotal: $('[data-api=\"virustotal\"]'),\r\n    apiURLhaus: $('[data-api=\"urlhaus\"]'),\r\n    apiUrlscan: $('[data-api=\"urlscan\"]'),\r\n    apiPhishTank: $('[data-api=\"phishtank\"]'),\r\n    \/\/ Batch mode elements\r\n    batchMode: $('[data-field=\"batchMode\"]'),\r\n    singleInput: $('[data-single-input]'),\r\n    batchInput: $('[data-batch-input]'),\r\n    urlBatch: $('[data-field=\"urlBatch\"]'),\r\n    batchResults: $('[data-batch-results]'),\r\n    batchTbody: $('[data-batch-tbody]'),\r\n    exportButtons: $('[data-export-buttons]'),\r\n    \/\/ History elements\r\n    historySection: $('[data-history-section]'),\r\n    historyList: $('[data-history-list]'),\r\n    historyCount: $('[data-history-count]'),\r\n    historyBadge: $('[data-history-badge]'),\r\n    \/\/ QR Code elements\r\n    qrUpload: $('[data-field=\"qrUpload\"]'),\r\n    qrStatus: $('[data-qr-status]')\r\n  };\r\n\r\n  \/\/ Store last analysis for export\r\n  let lastAnalysis = null;\r\n  let lastBatchResults = [];\r\n\r\n  \/\/ === Loading Steps Tracking (v4.1) ===\r\n  const LOADING_STEPS = ['local', 'google', 'virustotal', 'urlhaus', 'urlscan', 'phishtank'];\r\n  let completedSteps = 0;\r\n\r\n  function updateLoadingStep(stepName, status) {\r\n    const stepEl = root.querySelector('[data-step=\"' + stepName + '\"]');\r\n    if (!stepEl) return;\r\n\r\n    const icon = stepEl.querySelector('[data-step-icon]');\r\n    stepEl.classList.remove('is-active', 'is-done', 'is-failed', 'is-timeout');\r\n\r\n    switch (status) {\r\n      case 'checking':\r\n        stepEl.classList.add('is-active');\r\n        if (icon) icon.textContent = '';\r\n        break;\r\n      case 'done':\r\n        stepEl.classList.add('is-done');\r\n        if (icon) icon.textContent = '\u2713';\r\n        completedSteps++;\r\n        updateLoadingProgress();\r\n        break;\r\n      case 'failed':\r\n        stepEl.classList.add('is-failed');\r\n        if (icon) icon.textContent = '\u2715';\r\n        completedSteps++;\r\n        updateLoadingProgress();\r\n        break;\r\n      case 'timeout':\r\n        stepEl.classList.add('is-timeout');\r\n        if (icon) icon.textContent = '!';\r\n        completedSteps++;\r\n        updateLoadingProgress();\r\n        break;\r\n    }\r\n  }\r\n\r\n  function updateLoadingProgress() {\r\n    const progressBar = root.querySelector('[data-progress-bar]');\r\n    const percentEl = root.querySelector('[data-loading-percent]');\r\n    const percent = Math.round((completedSteps \/ LOADING_STEPS.length) * 100);\r\n\r\n    if (progressBar) progressBar.style.width = percent + '%';\r\n    if (percentEl) percentEl.textContent = percent + '%';\r\n  }\r\n\r\n  function resetLoadingSteps() {\r\n    completedSteps = 0;\r\n    LOADING_STEPS.forEach(function(step) {\r\n      const stepEl = root.querySelector('[data-step=\"' + step + '\"]');\r\n      if (stepEl) {\r\n        stepEl.classList.remove('is-active', 'is-done', 'is-failed', 'is-timeout');\r\n        const icon = stepEl.querySelector('[data-step-icon]');\r\n        if (icon) icon.textContent = '';\r\n      }\r\n    });\r\n    updateLoadingProgress();\r\n  }\r\n\r\n  function updateApiStatus(apiElement, status) {\r\n    if (!apiElement) return;\r\n    const dot = apiElement.querySelector('.zic2__apiDot');\r\n    if (!dot) return;\r\n    dot.className = 'zic2__apiDot';\r\n    dot.classList.add('zic2__apiDot--' + status);\r\n  }\r\n\r\n  function resetApiStatus() {\r\n    updateApiStatus(elements.apiGoogle, 'pending');\r\n    updateApiStatus(elements.apiVirusTotal, 'pending');\r\n    updateApiStatus(elements.apiURLhaus, 'pending');\r\n    updateApiStatus(elements.apiUrlscan, 'pending');\r\n    updateApiStatus(elements.apiPhishTank, 'pending');\r\n  }\r\n\r\n  \/\/ === Known Brands Database ===\r\n  const knownBrands = Object.freeze([\r\n    'google', 'facebook', 'amazon', 'apple', 'microsoft', 'netflix', 'paypal',\r\n    'instagram', 'twitter', 'linkedin', 'whatsapp', 'telegram', 'yahoo', 'outlook',\r\n    'dropbox', 'adobe', 'spotify', 'uber', 'airbnb', 'booking', 'ebay', 'alibaba',\r\n    'walmart', 'target', 'bestbuy', 'costco', 'ikea', 'samsung', 'sony',\r\n    'chase', 'bankofamerica', 'wellsfargo', 'citibank', 'capitalone', 'americanexpress',\r\n    'visa', 'mastercard', 'stripe', 'venmo', 'coinbase', 'binance', 'blockchain',\r\n    'dhl', 'fedex', 'ups', 'usps', 'hbo', 'disney',\r\n    'youtube', 'tiktok', 'snapchat', 'pinterest', 'reddit', 'twitch', 'discord',\r\n    'zoom', 'slack', 'github', 'gitlab', 'wordpress', 'shopify', 'cloudflare', 'godaddy',\r\n    'bancatransilvania', 'btrl', 'raiffeisen', 'raiffeisenbank', 'bcr', 'brd', 'ing', 'ingbank',\r\n    'unicredit', 'cec', 'cecbank', 'alphabank', 'otpbank', 'otp', 'libra', 'librabank',\r\n    'garanti', 'intesa', 'firstbank', 'patria', 'patriabank', 'crediteurope', 'exim', 'eximbank',\r\n    'revolut', 'wise', 'tradeville', 'bvb',\r\n    'emag', 'altex', 'pcgarage', 'evomag', 'cel', 'mediagalaxy', 'flanco', 'domo', 'dedeman',\r\n    'leroy', 'leroymerlin', 'jysk', 'mobexpert', 'vivre', 'bonami', 'elefant', 'libris',\r\n    'carturesti', 'pepita', 'notino', 'douglas', 'sephora', 'fashiondays', 'aboutyou',\r\n    'answear', 'modivo', 'epantofi', 'sportisimo', 'decathlon', 'intersport', 'hervis',\r\n    'olx', 'publi24', 'autovit', 'storia', 'imobiliare', 'lajumate',\r\n    'orange', 'vodafone', 'digi', 'rcs', 'telekom', 'cosmote', 'enel', 'engie', 'eon',\r\n    'electrica', 'hidroelectrica', 'delgaz', 'distrigaz', 'apanova',\r\n    'fancourier', 'cargus', 'sameday', 'dpd', 'gls', 'urgentcargus', 'postaromana',\r\n    'cfr', 'tarom', 'wizz', 'wizzair', 'blueair', 'ryanair', 'flixbus',\r\n    'anaf', 'ghiseul', 'rovinieta', 'drpciv', 'cnas', 'ajofm', 'onrc', 'efactura', 'roalert',\r\n    'tazz', 'foodpanda', 'glovo', 'bolt', 'kaufland', 'lidl', 'carrefour', 'auchan',\r\n    'mega', 'megaimage', 'profi', 'penny', 'cora', 'selgros', 'metro',\r\n    'payu', 'netopia', 'mobilpay', 'smartbill', 'oblio', 'facturis', 'gomag'\r\n  ]);\r\n\r\n  \/\/ === ENHANCED HOMOGLYPH DATABASE v4.0 ===\r\n  \/\/ Covers: Cyrillic, Greek, Armenian, Math Alphanumeric, Fullwidth, Common substitutions\r\n  const homoglyphs = Object.freeze({\r\n    \/\/ Cyrillic lookalikes\r\n    '\\u0430': 'a', '\\u0435': 'e', '\\u043e': 'o', '\\u0440': 'p', '\\u0441': 'c', '\\u0445': 'x', '\\u0443': 'y',\r\n    '\\u0456': 'i', '\\u0458': 'j', '\\u0455': 's', '\\u0501': 'd', '\\u0261': 'g', '\\u0578': 'n', '\\u057d': 'u',\r\n    '\\u04bd': 'e', '\\u0432': 'b', '\\u043d': 'h', '\\u043a': 'k', '\\u043c': 'm', '\\u0442': 't',\r\n    '\\u0410': 'a', '\\u0412': 'b', '\\u0415': 'e', '\\u041a': 'k', '\\u041c': 'm', '\\u041d': 'h',\r\n    '\\u041e': 'o', '\\u0420': 'p', '\\u0421': 'c', '\\u0422': 't', '\\u0425': 'x', '\\u0443': 'y',\r\n    \/\/ Greek lookalikes\r\n    '\\u03b1': 'a', '\\u03b2': 'b', '\\u03b5': 'e', '\\u03b7': 'n', '\\u03b9': 'i', '\\u03ba': 'k',\r\n    '\\u03bd': 'v', '\\u03bf': 'o', '\\u03c1': 'p', '\\u03c3': 'o', '\\u03c4': 't', '\\u03c5': 'u',\r\n    '\\u03c7': 'x', '\\u03c9': 'w', '\\u0391': 'a', '\\u0392': 'b', '\\u0395': 'e', '\\u0397': 'h',\r\n    '\\u0399': 'i', '\\u039a': 'k', '\\u039c': 'm', '\\u039d': 'n', '\\u039f': 'o', '\\u03a1': 'p',\r\n    '\\u03a4': 't', '\\u03a7': 'x', '\\u03a5': 'y', '\\u03a9': 'w',\r\n    \/\/ Armenian lookalikes\r\n    '\\u0561': 'a', '\\u0562': 'b', '\\u0565': 'e', '\\u0568': 'n', '\\u056b': 'h', '\\u0570': 'h',\r\n    '\\u0571': 'j', '\\u0575': 'n', '\\u0578': 'n', '\\u057a': 'n', '\\u057c': 'o', '\\u057d': 'u',\r\n    \/\/ Math alphanumeric (script, bold, italic variants)\r\n    '\\u{1D41A}': 'a', '\\u{1D41B}': 'b', '\\u{1D41C}': 'c', '\\u{1D41D}': 'd', '\\u{1D41E}': 'e',\r\n    '\\u{1D41F}': 'f', '\\u{1D420}': 'g', '\\u{1D421}': 'h', '\\u{1D422}': 'i', '\\u{1D423}': 'j',\r\n    '\\u{1D424}': 'k', '\\u{1D425}': 'l', '\\u{1D426}': 'm', '\\u{1D427}': 'n', '\\u{1D428}': 'o',\r\n    '\\u{1D429}': 'p', '\\u{1D42A}': 'q', '\\u{1D42B}': 'r', '\\u{1D42C}': 's', '\\u{1D42D}': 't',\r\n    '\\u{1D42E}': 'u', '\\u{1D42F}': 'v', '\\u{1D430}': 'w', '\\u{1D42F}': 'x', '\\u{1D432}': 'y',\r\n    '\\u{1D433}': 'z',\r\n    \/\/ Fullwidth forms (CJK compatibility)\r\n    '\\uFF41': 'a', '\\uFF42': 'b', '\\uFF43': 'c', '\\uFF44': 'd', '\\uFF45': 'e', '\\uFF46': 'f',\r\n    '\\uFF47': 'g', '\\uFF48': 'h', '\\uFF49': 'i', '\\uFF4A': 'j', '\\uFF4B': 'k', '\\uFF4C': 'l',\r\n    '\\uFF4D': 'm', '\\uFF4E': 'n', '\\uFF4F': 'o', '\\uFF50': 'p', '\\uFF51': 'q', '\\uFF52': 'r',\r\n    '\\uFF53': 's', '\\uFF54': 't', '\\uFF55': 'u', '\\uFF56': 'v', '\\uFF57': 'w', '\\uFF58': 'x',\r\n    '\\uFF59': 'y', '\\uFF5A': 'z',\r\n    \/\/ Superscript\/subscript\r\n    '\\u1D43': 'a', '\\u1D47': 'b', '\\u1D48': 'd', '\\u1D49': 'e', '\\u1D4D': 'g', '\\u02B0': 'h',\r\n    '\\u2071': 'i', '\\u02B2': 'j', '\\u1D4F': 'k', '\\u02E1': 'l', '\\u1D50': 'm', '\\u207F': 'n',\r\n    '\\u1D52': 'o', '\\u1D56': 'p', '\\u02B3': 'r', '\\u02E2': 's', '\\u1D57': 't', '\\u1D58': 'u',\r\n    '\\u1D5B': 'v', '\\u02B7': 'w', '\\u02E3': 'x', '\\u02B8': 'y',\r\n    \/\/ IPA extensions\r\n    '\\u0251': 'a', '\\u0185': 'b', '\\u0269': 'l', '\\u028f': 'y', '\\u0254': 'c', '\\u0256': 'd',\r\n    '\\u025b': 'e', '\\u0263': 'g', '\\u026a': 'i', '\\u026f': 'm', '\\u0273': 'n', '\\u0275': 'o',\r\n    '\\u0279': 'r', '\\u0283': 's', '\\u0288': 't', '\\u028a': 'u', '\\u028b': 'v', '\\u0290': 'z',\r\n    \/\/ Common number\/symbol substitutions\r\n    '0': 'o', '1': 'l', '3': 'e', '4': 'a', '5': 's', '8': 'b', '9': 'g',\r\n    '@': 'a', '$': 's', '!': 'i', '|': 'l', '(': 'c', ')': 'd',\r\n    \/\/ Latin Extended lookalikes\r\n    '\\u0101': 'a', '\\u0103': 'a', '\\u00e0': 'a', '\\u00e1': 'a', '\\u00e2': 'a', '\\u00e3': 'a', '\\u00e4': 'a',\r\n    '\\u0113': 'e', '\\u0115': 'e', '\\u00e8': 'e', '\\u00e9': 'e', '\\u00ea': 'e', '\\u00eb': 'e',\r\n    '\\u012b': 'i', '\\u012d': 'i', '\\u00ec': 'i', '\\u00ed': 'i', '\\u00ee': 'i', '\\u00ef': 'i',\r\n    '\\u014d': 'o', '\\u014f': 'o', '\\u00f2': 'o', '\\u00f3': 'o', '\\u00f4': 'o', '\\u00f5': 'o', '\\u00f6': 'o',\r\n    '\\u016b': 'u', '\\u016d': 'u', '\\u00f9': 'u', '\\u00fa': 'u', '\\u00fb': 'u', '\\u00fc': 'u'\r\n  });\r\n\r\n  \/\/ Script ranges for detection logging\r\n  const SCRIPT_RANGES = {\r\n    cyrillic: { start: 0x0400, end: 0x04FF, name: 'Cyrillic' },\r\n    greek: { start: 0x0370, end: 0x03FF, name: 'Greek' },\r\n    armenian: { start: 0x0530, end: 0x058F, name: 'Armenian' },\r\n    mathAlphanumeric: { start: 0x1D400, end: 0x1D7FF, name: 'Math Alphanumeric' },\r\n    fullWidth: { start: 0xFF00, end: 0xFFEF, name: 'Fullwidth Forms' }\r\n  };\r\n\r\n  \/\/ Detect which scripts are present in a string\r\n  function detectScripts(str) {\r\n    const detected = new Set();\r\n    for (const char of str) {\r\n      const code = char.codePointAt(0);\r\n      for (const [script, range] of Object.entries(SCRIPT_RANGES)) {\r\n        if (code >= range.start && code <= range.end) {\r\n          detected.add(range.name);\r\n        }\r\n      }\r\n    }\r\n    return detected;\r\n  }\r\n\r\n  const suspiciousTLDs = Object.freeze([\r\n    '.tk', '.ml', '.ga', '.cf', '.gq', '.xyz', '.top', '.work', '.click',\r\n    '.link', '.buzz', '.monster', '.rest', '.icu', '.surf'\r\n  ]);\r\n\r\n  const romanianBrandsRequiringRO = Object.freeze([\r\n    'bancatransilvania', 'btrl', 'raiffeisen', 'raiffeisenbank', 'bcr', 'brd',\r\n    'unicredit', 'cec', 'cecbank', 'alphabank', 'otpbank', 'otp', 'libra', 'librabank',\r\n    'garanti', 'intesa', 'firstbank', 'patria', 'patriabank', 'crediteurope', 'exim', 'eximbank',\r\n    'anaf', 'ghiseul', 'rovinieta', 'drpciv', 'cnas', 'ajofm', 'onrc', 'efactura', 'roalert',\r\n    'emag', 'altex', 'pcgarage', 'evomag', 'cel', 'mediagalaxy', 'flanco', 'domo', 'dedeman',\r\n    'elefant', 'libris', 'carturesti',\r\n    'digi', 'rcs', 'telekom', 'cosmote', 'enel', 'engie', 'eon', 'electrica', 'hidroelectrica',\r\n    'delgaz', 'distrigaz', 'apanova',\r\n    'fancourier', 'cargus', 'sameday', 'urgentcargus', 'postaromana', 'cfr', 'tarom',\r\n    'olx', 'publi24', 'autovit', 'storia', 'imobiliare', 'lajumate',\r\n    'netopia', 'mobilpay', 'smartbill', 'oblio', 'facturis', 'gomag', 'megaimage'\r\n  ]);\r\n\r\n  const internationalBrandTLDs = Object.freeze({\r\n    'google': ['.com', '.ro', '.de', '.fr', '.co.uk', '.es', '.it'],\r\n    'gmail': ['.com'], 'youtube': ['.com'], 'facebook': ['.com'], 'instagram': ['.com'],\r\n    'whatsapp': ['.com'], 'microsoft': ['.com'], 'outlook': ['.com'], 'hotmail': ['.com'],\r\n    'apple': ['.com'], 'icloud': ['.com'],\r\n    'amazon': ['.com', '.de', '.co.uk', '.fr', '.es', '.it', '.ro'],\r\n    'paypal': ['.com'], 'stripe': ['.com'], 'twitter': ['.com'], 'linkedin': ['.com'],\r\n    'tiktok': ['.com'], 'snapchat': ['.com'], 'pinterest': ['.com'], 'reddit': ['.com'],\r\n    'discord': ['.com', '.gg'], 'twitch': ['.tv'], 'netflix': ['.com'], 'spotify': ['.com'],\r\n    'hbo': ['.com'], 'disney': ['.com'], 'github': ['.com'], 'gitlab': ['.com'],\r\n    'dropbox': ['.com'], 'adobe': ['.com'], 'zoom': ['.us'], 'slack': ['.com'],\r\n    'ebay': ['.com', '.de', '.co.uk', '.fr', '.es', '.it', '.ro'],\r\n    'alibaba': ['.com'], 'chase': ['.com'], 'visa': ['.com'], 'mastercard': ['.com'],\r\n    'coinbase': ['.com'], 'binance': ['.com'], 'booking': ['.com'], 'airbnb': ['.com'],\r\n    'dhl': ['.com', '.de', '.ro'], 'fedex': ['.com'], 'ups': ['.com']\r\n  });\r\n\r\n  const phishingKeywords = Object.freeze([\r\n    'login', 'signin', 'sign-in', 'log-in', 'secure', 'security', 'verify',\r\n    'verification', 'account', 'update', 'confirm', 'password', 'credential',\r\n    'suspend', 'suspended', 'locked', 'unlock', 'restore', 'recover', 'recovery',\r\n    'urgent', 'immediate', 'alert', 'warning', 'limited', 'expire', 'expired',\r\n    'validate', 'authenticate', 'banking', 'wallet', 'payment', 'invoice',\r\n    'refund', 'prize', 'winner', 'congratulation', 'selected', 'lucky',\r\n    'conectare', 'autentificare', 'parola', 'cont', 'verifica', 'verificare',\r\n    'actualizare', 'blocat', 'deblocare', 'recuperare', 'urgent', 'plata',\r\n    'factura', 'ramburs', 'castigator', 'premiu', 'felicitari'\r\n  ]);\r\n\r\n  \/\/ === Helper Functions ===\r\n  function normalizeForComparison(str) {\r\n    if (typeof str !== 'string') return '';\r\n    let normalized = str.toLowerCase();\r\n    for (const [homoglyph, letter] of Object.entries(homoglyphs)) {\r\n      normalized = normalized.split(homoglyph).join(letter);\r\n    }\r\n    return normalized;\r\n  }\r\n\r\n  function normalizeTyposquatting(str) {\r\n    if (typeof str !== 'string') return '';\r\n    return str.toLowerCase()\r\n      .replace(\/1\/g, 'l').replace(\/0\/g, 'o').replace(\/3\/g, 'e')\r\n      .replace(\/4\/g, 'a').replace(\/5\/g, 's').replace(\/\\$\/g, 's')\r\n      .replace(\/@\/g, 'a').replace(\/!\/g, 'i').replace(\/\\|\/g, 'l');\r\n  }\r\n\r\n  function findBrandWithSubstitutions(domain) {\r\n    const domainLower = domain.toLowerCase();\r\n    const normalizedDomain = normalizeTyposquatting(domainLower);\r\n    const results = [];\r\n\r\n    for (const brand of knownBrands) {\r\n      if (normalizedDomain.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'substitution', description: 'Domeniul contine caractere substituate care formeaza \"' + brand + '\"' });\r\n        continue;\r\n      }\r\n\r\n      const withIL = domainLower.replace(\/ll\/g, 'il');\r\n      const withLI = domainLower.replace(\/ll\/g, 'li');\r\n      const withM = domainLower.replace(\/rn\/g, 'm');\r\n      const withW = domainLower.replace(\/vv\/g, 'w');\r\n\r\n      if (withIL.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'double_letter', substitution: 'll \u2192 il', description: 'Domeniul imita \"' + brand + '\" folosind \"ll\" in loc de \"il\"' });\r\n      } else if (withLI.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'double_letter', substitution: 'll \u2192 li', description: 'Domeniul imita \"' + brand + '\" folosind \"ll\" in loc de \"li\"' });\r\n      } else if (withM.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'visual_trick', substitution: 'rn \u2192 m', description: 'Domeniul imita \"' + brand + '\" folosind \"rn\" care arata ca \"m\"' });\r\n      } else if (withW.includes(brand) && !domainLower.includes(brand)) {\r\n        results.push({ brand, type: 'visual_trick', substitution: 'vv \u2192 w', description: 'Domeniul imita \"' + brand + '\" folosind \"vv\" care arata ca \"w\"' });\r\n      }\r\n    }\r\n    return results;\r\n  }\r\n\r\n  function checkWithoutHyphens(domain) {\r\n    const domainLower = domain.toLowerCase();\r\n    const withoutHyphens = domainLower.replace(\/-\/g, '');\r\n    const results = [];\r\n\r\n    let domainName = domainLower.startsWith('www.') ? domainLower.substring(4) : domainLower;\r\n    const domainNameWithoutTLD = domainName.split('.')[0] || '';\r\n\r\n    if (knownBrands.includes(domainNameWithoutTLD)) return results;\r\n\r\n    for (const brand of knownBrands) {\r\n      if (brand.includes('-')) continue;\r\n      if (withoutHyphens.includes(brand) && !domainLower.replace(\/[^a-z]\/g, '').startsWith(brand)) {\r\n        const brandPattern = brand.split('').join('-?');\r\n        const regex = new RegExp(brandPattern);\r\n        if (regex.test(domainLower) && domainLower.includes('-')) {\r\n          results.push({ brand, description: 'Brandul \"' + brand + '\" este fragmentat cu cratime pentru a evita detectia' });\r\n        }\r\n      }\r\n    }\r\n    return results;\r\n  }\r\n\r\n  function levenshteinDistance(str1, str2) {\r\n    if (typeof str1 !== 'string' || typeof str2 !== 'string') return Infinity;\r\n    const s1 = str1.substring(0, 100), s2 = str2.substring(0, 100);\r\n    const m = s1.length, n = s2.length;\r\n    const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));\r\n    for (let i = 0; i <= m; i++) dp[i][0] = i;\r\n    for (let j = 0; j <= n; j++) dp[0][j] = j;\r\n    for (let i = 1; i <= m; i++) {\r\n      for (let j = 1; j <= n; j++) {\r\n        dp[i][j] = s1[i - 1] === s2[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);\r\n      }\r\n    }\r\n    return dp[m][n];\r\n  }\r\n\r\n  \/\/ === Advanced Typosquatting Algorithms (v4.0) ===\r\n\r\n  \/\/ Jaro-Winkler similarity - better for prefix matching (brand spoofing)\r\n  function jaroWinklerSimilarity(s1, s2) {\r\n    if (typeof s1 !== 'string' || typeof s2 !== 'string') return 0;\r\n    if (s1 === s2) return 1;\r\n    s1 = s1.substring(0, 100);\r\n    s2 = s2.substring(0, 100);\r\n\r\n    const len1 = s1.length, len2 = s2.length;\r\n    if (len1 === 0 || len2 === 0) return 0;\r\n\r\n    const matchWindow = Math.floor(Math.max(len1, len2) \/ 2) - 1;\r\n    const s1Matches = new Array(len1).fill(false);\r\n    const s2Matches = new Array(len2).fill(false);\r\n\r\n    let matches = 0;\r\n    let transpositions = 0;\r\n\r\n    \/\/ Find matches\r\n    for (let i = 0; i < len1; i++) {\r\n      const start = Math.max(0, i - matchWindow);\r\n      const end = Math.min(i + matchWindow + 1, len2);\r\n      for (let j = start; j < end; j++) {\r\n        if (s2Matches[j] || s1[i] !== s2[j]) continue;\r\n        s1Matches[i] = true;\r\n        s2Matches[j] = true;\r\n        matches++;\r\n        break;\r\n      }\r\n    }\r\n\r\n    if (matches === 0) return 0;\r\n\r\n    \/\/ Count transpositions\r\n    let k = 0;\r\n    for (let i = 0; i < len1; i++) {\r\n      if (!s1Matches[i]) continue;\r\n      while (!s2Matches[k]) k++;\r\n      if (s1[i] !== s2[k]) transpositions++;\r\n      k++;\r\n    }\r\n\r\n    const jaro = (matches \/ len1 + matches \/ len2 + (matches - transpositions \/ 2) \/ matches) \/ 3;\r\n\r\n    \/\/ Winkler modification: boost for common prefix\r\n    let prefix = 0;\r\n    for (let i = 0; i < Math.min(4, Math.min(len1, len2)); i++) {\r\n      if (s1[i] === s2[i]) prefix++;\r\n      else break;\r\n    }\r\n\r\n    return jaro + prefix * 0.1 * (1 - jaro);\r\n  }\r\n\r\n  \/\/ Keyboard proximity map (QWERTY layout)\r\n  const KEYBOARD_NEIGHBORS = Object.freeze({\r\n    'q': ['w', 'a', '1', '2'],\r\n    'w': ['q', 'e', 'a', 's', '2', '3'],\r\n    'e': ['w', 'r', 's', 'd', '3', '4'],\r\n    'r': ['e', 't', 'd', 'f', '4', '5'],\r\n    't': ['r', 'y', 'f', 'g', '5', '6'],\r\n    'y': ['t', 'u', 'g', 'h', '6', '7'],\r\n    'u': ['y', 'i', 'h', 'j', '7', '8'],\r\n    'i': ['u', 'o', 'j', 'k', '8', '9'],\r\n    'o': ['i', 'p', 'k', 'l', '9', '0'],\r\n    'p': ['o', 'l', '0'],\r\n    'a': ['q', 'w', 's', 'z'],\r\n    's': ['a', 'w', 'e', 'd', 'z', 'x'],\r\n    'd': ['s', 'e', 'r', 'f', 'x', 'c'],\r\n    'f': ['d', 'r', 't', 'g', 'c', 'v'],\r\n    'g': ['f', 't', 'y', 'h', 'v', 'b'],\r\n    'h': ['g', 'y', 'u', 'j', 'b', 'n'],\r\n    'j': ['h', 'u', 'i', 'k', 'n', 'm'],\r\n    'k': ['j', 'i', 'o', 'l', 'm'],\r\n    'l': ['k', 'o', 'p'],\r\n    'z': ['a', 's', 'x'],\r\n    'x': ['z', 's', 'd', 'c'],\r\n    'c': ['x', 'd', 'f', 'v'],\r\n    'v': ['c', 'f', 'g', 'b'],\r\n    'b': ['v', 'g', 'h', 'n'],\r\n    'n': ['b', 'h', 'j', 'm'],\r\n    'm': ['n', 'j', 'k'],\r\n    '1': ['2', 'q'],\r\n    '2': ['1', '3', 'q', 'w'],\r\n    '3': ['2', '4', 'w', 'e'],\r\n    '4': ['3', '5', 'e', 'r'],\r\n    '5': ['4', '6', 'r', 't'],\r\n    '6': ['5', '7', 't', 'y'],\r\n    '7': ['6', '8', 'y', 'u'],\r\n    '8': ['7', '9', 'u', 'i'],\r\n    '9': ['8', '0', 'i', 'o'],\r\n    '0': ['9', 'o', 'p']\r\n  });\r\n\r\n  function isKeyboardNeighbor(char1, char2) {\r\n    const c1 = char1.toLowerCase(), c2 = char2.toLowerCase();\r\n    return KEYBOARD_NEIGHBORS[c1]?.includes(c2) || false;\r\n  }\r\n\r\n  \/\/ Detect \"fat finger\" typos using keyboard proximity\r\n  function detectKeyboardTypo(domain, brand) {\r\n    if (domain.length !== brand.length) return null;\r\n    let typoCount = 0;\r\n    let typoPositions = [];\r\n\r\n    for (let i = 0; i < domain.length; i++) {\r\n      if (domain[i] !== brand[i]) {\r\n        if (isKeyboardNeighbor(domain[i], brand[i])) {\r\n          typoCount++;\r\n          typoPositions.push(i);\r\n        } else {\r\n          return null; \/\/ Non-keyboard typo\r\n        }\r\n      }\r\n    }\r\n\r\n    if (typoCount > 0 && typoCount <= 2) {\r\n      return {\r\n        brand,\r\n        typoCount,\r\n        typoPositions,\r\n        type: 'keyboard_typo',\r\n        description: 'Posibil\u0103 eroare de tastare: \"' + domain + '\" vs \"' + brand + '\" (taste adiacente)'\r\n      };\r\n    }\r\n    return null;\r\n  }\r\n\r\n  \/\/ Pattern detection: repetition (gooogle), omission (gogle), transposition (googel), vowel swap (guugle)\r\n  const VOWELS = new Set(['a', 'e', 'i', 'o', 'u']);\r\n\r\n  function detectRepetition(domain, brand) {\r\n    \/\/ Check if domain has repeated chars that brand doesn't\r\n    const domainCollapsed = domain.replace(\/(.)\\1+\/g, '$1');\r\n    if (domainCollapsed === brand && domain !== brand) {\r\n      return {\r\n        brand,\r\n        type: 'repetition',\r\n        description: 'Litere repetate detectate: \"' + domain + '\" \u2192 \"' + brand + '\"'\r\n      };\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function detectOmission(domain, brand) {\r\n    \/\/ Check if domain is brand with one char removed\r\n    if (domain.length !== brand.length - 1) return null;\r\n    for (let i = 0; i < brand.length; i++) {\r\n      const modified = brand.slice(0, i) + brand.slice(i + 1);\r\n      if (modified === domain) {\r\n        return {\r\n          brand,\r\n          type: 'omission',\r\n          description: 'Caracter lips\u0103: \"' + domain + '\" (lipse\u0219te \"' + brand[i] + '\" din \"' + brand + '\")'\r\n        };\r\n      }\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function detectTransposition(domain, brand) {\r\n    \/\/ Check if domain is brand with two adjacent chars swapped\r\n    if (domain.length !== brand.length) return null;\r\n    let diffCount = 0;\r\n    let diffPositions = [];\r\n    for (let i = 0; i < domain.length; i++) {\r\n      if (domain[i] !== brand[i]) {\r\n        diffCount++;\r\n        diffPositions.push(i);\r\n      }\r\n    }\r\n    if (diffCount === 2 && diffPositions[1] === diffPositions[0] + 1) {\r\n      if (domain[diffPositions[0]] === brand[diffPositions[1]] &&\r\n          domain[diffPositions[1]] === brand[diffPositions[0]]) {\r\n        return {\r\n          brand,\r\n          type: 'transposition',\r\n          description: 'Litere inversate: \"' + domain + '\" vs \"' + brand + '\"'\r\n        };\r\n      }\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function detectVowelSwap(domain, brand) {\r\n    \/\/ Check if domain differs only by vowel substitution\r\n    if (domain.length !== brand.length) return null;\r\n    let vowelSwaps = 0;\r\n    let otherDiffs = 0;\r\n    for (let i = 0; i < domain.length; i++) {\r\n      if (domain[i] !== brand[i]) {\r\n        if (VOWELS.has(domain[i]) && VOWELS.has(brand[i])) {\r\n          vowelSwaps++;\r\n        } else {\r\n          otherDiffs++;\r\n        }\r\n      }\r\n    }\r\n    if (vowelSwaps > 0 && vowelSwaps <= 2 && otherDiffs === 0) {\r\n      return {\r\n        brand,\r\n        type: 'vowel_swap',\r\n        description: 'Vocale substituite: \"' + domain + '\" vs \"' + brand + '\"'\r\n      };\r\n    }\r\n    return null;\r\n  }\r\n\r\n  \/\/ Combined advanced typosquatting check\r\n  function advancedTyposquatCheck(domain, brands) {\r\n    const results = [];\r\n    const domainLower = domain.toLowerCase();\r\n\r\n    for (const brand of brands) {\r\n      \/\/ Skip exact matches\r\n      if (domainLower === brand) continue;\r\n\r\n      \/\/ 1. Jaro-Winkler (prefix-focused similarity)\r\n      const jwScore = jaroWinklerSimilarity(domainLower, brand);\r\n      if (jwScore >= 0.85 && jwScore < 1) {\r\n        results.push({\r\n          brand,\r\n          score: jwScore,\r\n          type: 'jaro_winkler',\r\n          description: 'Similaritate ridicat\u0103 (' + Math.round(jwScore * 100) + '%) cu brandul \"' + brand + '\"'\r\n        });\r\n        continue;\r\n      }\r\n\r\n      \/\/ 2. Keyboard proximity typo\r\n      const keyboardMatch = detectKeyboardTypo(domainLower, brand);\r\n      if (keyboardMatch) {\r\n        results.push(keyboardMatch);\r\n        continue;\r\n      }\r\n\r\n      \/\/ 3. Pattern detection\r\n      const repetition = detectRepetition(domainLower, brand);\r\n      if (repetition) { results.push(repetition); continue; }\r\n\r\n      const omission = detectOmission(domainLower, brand);\r\n      if (omission) { results.push(omission); continue; }\r\n\r\n      const transposition = detectTransposition(domainLower, brand);\r\n      if (transposition) { results.push(transposition); continue; }\r\n\r\n      const vowelSwap = detectVowelSwap(domainLower, brand);\r\n      if (vowelSwap) { results.push(vowelSwap); continue; }\r\n    }\r\n\r\n    \/\/ Sort by score (Jaro-Winkler) descending\r\n    return results.sort((a, b) => (b.score || 0) - (a.score || 0));\r\n  }\r\n\r\n  \/\/ === API Response Cache (v4.0) ===\r\n  const CACHE_CONFIG = {\r\n    PREFIX: 'zic_api_cache_',\r\n    TTL: {\r\n      google: 60 * 60 * 1000,       \/\/ 1 hour\r\n      virustotal: 60 * 60 * 1000,   \/\/ 1 hour\r\n      urlhaus: 30 * 60 * 1000,      \/\/ 30 minutes (updates frequently)\r\n      urlscan: 2 * 60 * 60 * 1000,  \/\/ 2 hours\r\n      phishtank: 30 * 60 * 1000,    \/\/ 30 minutes\r\n      whois: 24 * 60 * 60 * 1000,   \/\/ 24 hours (rarely changes)\r\n      geoip: 24 * 60 * 60 * 1000,   \/\/ 24 hours\r\n      dns: 6 * 60 * 60 * 1000,      \/\/ 6 hours\r\n      ssl: 24 * 60 * 60 * 1000      \/\/ 24 hours\r\n    },\r\n    MAX_ENTRIES: 200\r\n  };\r\n\r\n  const apiCache = {\r\n    _hash(str) {\r\n      let hash = 0;\r\n      for (let i = 0; i < str.length; i++) {\r\n        const char = str.charCodeAt(i);\r\n        hash = ((hash << 5) - hash) + char;\r\n        hash = hash & hash;\r\n      }\r\n      return Math.abs(hash).toString(36);\r\n    },\r\n\r\n    _getKey(apiName, url) {\r\n      return CACHE_CONFIG.PREFIX + apiName + '_' + this._hash(url);\r\n    },\r\n\r\n    get(apiName, url) {\r\n      try {\r\n        const key = this._getKey(apiName, url);\r\n        const cached = localStorage.getItem(key);\r\n        if (!cached) return null;\r\n\r\n        const { data, timestamp } = JSON.parse(cached);\r\n        const ttl = CACHE_CONFIG.TTL[apiName] || 60 * 60 * 1000;\r\n\r\n        if (Date.now() - timestamp > ttl) {\r\n          localStorage.removeItem(key);\r\n          return null;\r\n        }\r\n\r\n        return { ...data, fromCache: true };\r\n      } catch (e) {\r\n        return null;\r\n      }\r\n    },\r\n\r\n    set(apiName, url, data) {\r\n      try {\r\n        \/\/ Don't cache errors\r\n        if (data.error || !data.checked) return;\r\n\r\n        const key = this._getKey(apiName, url);\r\n        const entry = {\r\n          data: data,\r\n          timestamp: Date.now()\r\n        };\r\n        localStorage.setItem(key, JSON.stringify(entry));\r\n        this._enforceMaxEntries();\r\n      } catch (e) {\r\n        \/\/ localStorage full - clean old entries\r\n        this._cleanOldest(50);\r\n      }\r\n    },\r\n\r\n    _enforceMaxEntries() {\r\n      const entries = [];\r\n      const prefix = CACHE_CONFIG.PREFIX;\r\n\r\n      for (let i = 0; i < localStorage.length; i++) {\r\n        const key = localStorage.key(i);\r\n        if (key && key.startsWith(prefix)) {\r\n          try {\r\n            const { timestamp } = JSON.parse(localStorage.getItem(key));\r\n            entries.push({ key, timestamp });\r\n          } catch (e) {}\r\n        }\r\n      }\r\n\r\n      if (entries.length > CACHE_CONFIG.MAX_ENTRIES) {\r\n        entries.sort((a, b) => a.timestamp - b.timestamp);\r\n        const toRemove = entries.slice(0, entries.length - CACHE_CONFIG.MAX_ENTRIES);\r\n        toRemove.forEach(e => localStorage.removeItem(e.key));\r\n      }\r\n    },\r\n\r\n    _cleanOldest(count) {\r\n      const entries = [];\r\n      const prefix = CACHE_CONFIG.PREFIX;\r\n\r\n      for (let i = 0; i < localStorage.length; i++) {\r\n        const key = localStorage.key(i);\r\n        if (key && key.startsWith(prefix)) {\r\n          try {\r\n            const { timestamp } = JSON.parse(localStorage.getItem(key));\r\n            entries.push({ key, timestamp });\r\n          } catch (e) {\r\n            localStorage.removeItem(key);\r\n          }\r\n        }\r\n      }\r\n\r\n      entries.sort((a, b) => a.timestamp - b.timestamp);\r\n      entries.slice(0, count).forEach(e => localStorage.removeItem(e.key));\r\n    }\r\n  };\r\n\r\n  \/\/ === API Timeout Handler (v4.0) ===\r\n  const API_TIMEOUTS = {\r\n    google: 8000,\r\n    virustotal: 10000,\r\n    urlhaus: 5000,\r\n    urlscan: 8000,\r\n    phishtank: 8000,\r\n    whois: 12000,\r\n    geoip: 5000,\r\n    dns: 5000,\r\n    ssl: 15000,\r\n    default: 10000\r\n  };\r\n\r\n  async function fetchWithTimeout(url, options = {}, apiName = 'default') {\r\n    const timeout = API_TIMEOUTS[apiName] || API_TIMEOUTS.default;\r\n    const controller = new AbortController();\r\n    const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n    try {\r\n      const response = await fetch(url, {\r\n        ...options,\r\n        signal: controller.signal\r\n      });\r\n      clearTimeout(timeoutId);\r\n      return response;\r\n    } catch (error) {\r\n      clearTimeout(timeoutId);\r\n      if (error.name === 'AbortError') {\r\n        throw new Error('Timeout after ' + timeout + 'ms');\r\n      }\r\n      throw error;\r\n    }\r\n  }\r\n\r\n  \/\/ === API Functions ===\r\n\r\n  \/\/ Google Safe Browsing - prin Cloudflare Worker proxy (API key securizat\u0103 \u00een backend)\r\n  async function checkGoogleSafeBrowsing(url) {\r\n    if (!API_CONFIG.GOOGLE_SAFE_BROWSING.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('google', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      const response = await fetchWithTimeout(\r\n        CLOUDFLARE_PROXY + '\/google-safebrowsing?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } },\r\n        'google'\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      const result = {\r\n        checked: data.checked || false,\r\n        safe: data.safe !== false,\r\n        threats: data.threats || [],\r\n        source: data.source || 'Google Safe Browsing'\r\n      };\r\n\r\n      \/\/ Cache successful result\r\n      apiCache.set('google', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('Google Safe Browsing check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ VirusTotal - prin Cloudflare Worker proxy\r\n  async function checkVirusTotal(url) {\r\n    if (!API_CONFIG.VIRUSTOTAL.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('virustotal', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      const response = await fetchWithTimeout(\r\n        CLOUDFLARE_PROXY + '\/virustotal?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } },\r\n        'virustotal'\r\n      );\r\n\r\n      if (!response.ok) {\r\n        return { checked: false, error: 'API error: ' + response.status };\r\n      }\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      let result;\r\n      const stats = data.data?.attributes?.last_analysis_stats;\r\n      if (stats) {\r\n        const malicious = stats.malicious || 0;\r\n        const suspicious = stats.suspicious || 0;\r\n        const total = Object.values(stats).reduce((a, b) => a + b, 0);\r\n        result = { checked: true, safe: malicious === 0 && suspicious === 0, malicious, suspicious, total, source: 'VirusTotal' };\r\n      } else {\r\n        result = { checked: true, safe: true, source: 'VirusTotal' };\r\n      }\r\n\r\n      apiCache.set('virustotal', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('VirusTotal check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ IPQualityScore - prin Cloudflare Worker proxy\r\n  async function checkIPQualityScore(url) {\r\n    if (!API_CONFIG.IPQUALITYSCORE.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/ipqs?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      if (data.success) {\r\n        return {\r\n          checked: true,\r\n          safe: !data.unsafe && !data.phishing && !data.malware,\r\n          riskScore: data.risk_score || 0,\r\n          phishing: data.phishing || false,\r\n          malware: data.malware || false,\r\n          suspicious: data.suspicious || false,\r\n          source: 'IPQualityScore'\r\n        };\r\n      }\r\n      return { checked: false, error: data.message || 'Unknown error' };\r\n    } catch (error) {\r\n      console.warn('IPQualityScore check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ URLhaus - prin Cloudflare Worker proxy (cu fallback la API direct CORS-enabled)\r\n  async function checkURLhaus(url) {\r\n    if (!API_CONFIG.URLHAUS.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('urlhaus', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      \/\/ Try direct API first (URLhaus supports CORS)\r\n      let response;\r\n      try {\r\n        response = await fetchWithTimeout('https:\/\/urlhaus-api.abuse.ch\/v1\/url\/', {\r\n          method: 'POST',\r\n          headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n          body: 'url=' + encodeURIComponent(url)\r\n        }, 'urlhaus');\r\n      } catch (directError) {\r\n        \/\/ Fallback to proxy if direct fails\r\n        response = await fetchWithTimeout(CLOUDFLARE_PROXY + '\/urlhaus', {\r\n          method: 'POST',\r\n          headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n          body: 'url=' + encodeURIComponent(url)\r\n        }, 'urlhaus');\r\n      }\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      let result;\r\n      if (data.query_status === 'ok') {\r\n        result = {\r\n          checked: true,\r\n          safe: false,\r\n          threat: data.threat || 'malware',\r\n          tags: data.tags || [],\r\n          dateAdded: data.date_added,\r\n          source: 'URLhaus (abuse.ch)'\r\n        };\r\n      } else if (data.query_status === 'no_results') {\r\n        result = { checked: true, safe: true, source: 'URLhaus (abuse.ch)' };\r\n      } else {\r\n        return { checked: false, error: data.query_status };\r\n      }\r\n\r\n      apiCache.set('urlhaus', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('URLhaus check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ urlscan.io - prin Cloudflare Worker proxy\r\n  async function checkUrlscan(url) {\r\n    if (!API_CONFIG.URLSCAN.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/urlscan?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        safe: !data.malicious,\r\n        found: data.found || false,\r\n        total: data.total || 0,\r\n        verdicts: data.verdicts || [],\r\n        source: 'urlscan.io'\r\n      };\r\n    } catch (error) {\r\n      console.warn('urlscan.io check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ PhishTank - prin Cloudflare Worker proxy\r\n  async function checkPhishTank(url) {\r\n    if (!API_CONFIG.PHISHTANK.enabled) {\r\n      return { checked: false };\r\n    }\r\n\r\n    \/\/ Check cache first\r\n    const cached = apiCache.get('phishtank', url);\r\n    if (cached) return cached;\r\n\r\n    try {\r\n      const response = await fetchWithTimeout(CLOUDFLARE_PROXY + '\/phishtank', {\r\n        method: 'POST',\r\n        headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n        body: 'url=' + encodeURIComponent(url)\r\n      }, 'phishtank');\r\n\r\n      if (!response.ok) {\r\n        if (response.status === 429) {\r\n          return { checked: false, error: 'Rate limit exceeded' };\r\n        }\r\n        return { checked: false, error: 'API error: ' + response.status };\r\n      }\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      const result = {\r\n        checked: true,\r\n        safe: !data.in_database || !data.verified,\r\n        inDatabase: data.in_database || false,\r\n        verified: data.verified || false,\r\n        phishId: data.phish_id,\r\n        source: 'PhishTank (Cisco)'\r\n      };\r\n\r\n      apiCache.set('phishtank', url, result);\r\n      return result;\r\n    } catch (error) {\r\n      console.warn('PhishTank check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ PhishStats - prin Cloudflare Worker proxy\r\n  async function checkPhishStats(url) {\r\n    if (!API_CONFIG.PHISHSTATS.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/phishstats?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        safe: !data.malicious,\r\n        found: data.found || false,\r\n        total: data.total || 0,\r\n        threats: data.threats || [],\r\n        source: 'PhishStats'\r\n      };\r\n    } catch (error) {\r\n      console.warn('PhishStats check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ === NOI VERIFIC\u0102RI v3 ===\r\n\r\n  \/\/ DNS Analysis - verific\u0103 DNS records\r\n  async function checkDNS(url) {\r\n    if (!API_CONFIG.DNS.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/dns?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      \/\/ Analiz\u0103: domeniu f\u0103r\u0103 MX records sau f\u0103r\u0103 SPF poate fi suspect\r\n      const suspicious = !data.analysis?.hasMailServers && !data.analysis?.hasSpf;\r\n\r\n      return {\r\n        checked: true,\r\n        domain: data.domain,\r\n        records: data.records,\r\n        analysis: data.analysis,\r\n        suspicious: suspicious,\r\n        source: 'DNS Analysis'\r\n      };\r\n    } catch (error) {\r\n      console.warn('DNS check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ GeoIP - loca\u021bia serverului\r\n  async function checkGeoIP(url) {\r\n    if (!API_CONFIG.GEOIP.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/geoip?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        ip: data.ip,\r\n        location: data.location,\r\n        network: data.network,\r\n        source: 'GeoIP'\r\n      };\r\n    } catch (error) {\r\n      console.warn('GeoIP check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ WHOIS - v\u00e2rsta domeniului\r\n  async function checkWHOIS(url) {\r\n    if (!API_CONFIG.WHOIS.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/whois?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error && !data.dates) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        domain: data.domain,\r\n        dates: data.dates,\r\n        registrar: data.registrar,\r\n        analysis: data.analysis,\r\n        source: 'WHOIS'\r\n      };\r\n    } catch (error) {\r\n      console.warn('WHOIS check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ SSL Certificate validation\r\n  async function checkSSL(url) {\r\n    if (!API_CONFIG.SSL.enabled) {\r\n      return { checked: false };\r\n    }\r\n    try {\r\n      const response = await fetch(\r\n        CLOUDFLARE_PROXY + '\/ssl?url=' + encodeURIComponent(url),\r\n        { method: 'GET', headers: { 'Accept': 'application\/json' } }\r\n      );\r\n\r\n      if (!response.ok) return { checked: false, error: 'API error: ' + response.status };\r\n\r\n      const data = await response.json();\r\n\r\n      if (data.error) {\r\n        return { checked: false, error: data.error };\r\n      }\r\n\r\n      \/\/ SSL Labs poate returna 'analyzing' dac\u0103 verificarea e \u00een curs\r\n      if (data.status === 'analyzing') {\r\n        return {\r\n          checked: true,\r\n          analyzing: true,\r\n          message: data.message,\r\n          source: 'SSL Labs'\r\n        };\r\n      }\r\n\r\n      return {\r\n        checked: true,\r\n        domain: data.domain,\r\n        grade: data.grade,\r\n        hasWarnings: data.hasWarnings,\r\n        cert: data.cert,\r\n        analysis: data.analysis,\r\n        source: 'SSL Labs'\r\n      };\r\n    } catch (error) {\r\n      console.warn('SSL check failed:', error);\r\n      return { checked: false, error: error.message };\r\n    }\r\n  }\r\n\r\n  \/\/ Run all API checks (include noile verific\u0103ri v3)\r\n  async function runAPIChecks(url) {\r\n    \/\/ Helper to wrap API call with step tracking\r\n    async function trackStep(stepName, apiCall) {\r\n      updateLoadingStep(stepName, 'checking');\r\n      try {\r\n        const result = await apiCall;\r\n        updateLoadingStep(stepName, result.checked ? 'done' : (result.timeout ? 'timeout' : 'failed'));\r\n        return result;\r\n      } catch (e) {\r\n        updateLoadingStep(stepName, 'failed');\r\n        return { checked: false, error: e.message };\r\n      }\r\n    }\r\n\r\n    \/\/ Verific\u0103ri de securitate principale (cu step tracking)\r\n    const [googleResult, vtResult, urlhausResult, urlscanResult, phishtankResult] = await Promise.all([\r\n      trackStep('google', checkGoogleSafeBrowsing(url)),\r\n      trackStep('virustotal', checkVirusTotal(url)),\r\n      trackStep('urlhaus', checkURLhaus(url)),\r\n      trackStep('urlscan', checkUrlscan(url)),\r\n      trackStep('phishtank', checkPhishTank(url))\r\n    ]);\r\n\r\n    \/\/ Verific\u0103ri noi v3 (run \u00een paralel)\r\n    const [dnsResult, geoipResult, whoisResult, sslResult] = await Promise.all([\r\n      checkDNS(url),\r\n      checkGeoIP(url),\r\n      checkWHOIS(url),\r\n      checkSSL(url)\r\n    ]);\r\n\r\n    return {\r\n      googleSafeBrowsing: googleResult,\r\n      virusTotal: vtResult,\r\n      urlhaus: urlhausResult,\r\n      urlscan: urlscanResult,\r\n      phishtank: phishtankResult,\r\n      \/\/ Noile verific\u0103ri\r\n      dns: dnsResult,\r\n      geoip: geoipResult,\r\n      whois: whoisResult,\r\n      ssl: sslResult\r\n    };\r\n  }\r\n\r\n  function extractDomain(url) {\r\n    try {\r\n      let cleanUrl = sanitizeInput(url);\r\n      if (!cleanUrl) return { valid: false };\r\n      if (\/^(javascript|data|vbscript|file):\/i.test(cleanUrl)) return { valid: false };\r\n      if (!cleanUrl.match(\/^https?:\\\/\\\/\/i)) cleanUrl = 'https:\/\/' + cleanUrl;\r\n      const urlObj = new URL(cleanUrl);\r\n      if (urlObj.protocol !== 'https:' && urlObj.protocol !== 'http:') return { valid: false };\r\n      return {\r\n        full: urlObj.hostname,\r\n        pathname: urlObj.pathname,\r\n        search: urlObj.search,\r\n        protocol: urlObj.protocol,\r\n        port: urlObj.port,\r\n        valid: true\r\n      };\r\n    } catch (e) {\r\n      return { valid: false };\r\n    }\r\n  }\r\n\r\n  \/\/ === Local Analysis ===\r\n  function analyzeURL(url) {\r\n    const domainInfo = extractDomain(url);\r\n    if (!domainInfo.valid) return { valid: false };\r\n\r\n    const checks = [];\r\n    let totalScore = 100;\r\n\r\n    \/\/ 1. HTTPS Check\r\n    if (domainInfo.protocol === 'https:') {\r\n      checks.push({ status: 'pass', title: t('checkHttpsPass'), description: t('checkHttpsPassDesc') });\r\n    } else {\r\n      checks.push({ status: 'fail', title: t('checkHttpsFail'), description: t('checkHttpsFailDesc') });\r\n      totalScore -= 20;\r\n    }\r\n\r\n    \/\/ 2. Homograph Attack (Enhanced v4.0 with script detection)\r\n    const originalDomain = domainInfo.full;\r\n    const normalizedDomain = normalizeForComparison(originalDomain);\r\n    const detectedScriptsSet = detectScripts(originalDomain);\r\n    const hasNonLatinScripts = detectedScriptsSet.size > 0;\r\n\r\n    if (originalDomain.toLowerCase() !== normalizedDomain || hasNonLatinScripts) {\r\n      const scriptsArray = Array.from(detectedScriptsSet);\r\n      const scriptsInfo = scriptsArray.length > 0\r\n        ? (currentLang === 'ro'\r\n          ? ` Script-uri detectate: ${scriptsArray.join(', ')}.`\r\n          : ` Detected scripts: ${scriptsArray.join(', ')}.`)\r\n        : '';\r\n      const description = t('checkUnicodeFailDesc', { domain: normalizedDomain }) + scriptsInfo;\r\n      checks.push({ status: 'fail', title: t('checkUnicodeFail'), description });\r\n      \/\/ Mixed scripts (e.g., Cyrillic + Latin) are more dangerous\r\n      totalScore -= hasNonLatinScripts && scriptsArray.length > 1 ? 45 : 35;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('checkUnicodePass'), description: t('checkUnicodePassDesc') });\r\n    }\r\n\r\n    \/\/ 3. Typosquatting Detection\r\n    let domainForCheck = normalizedDomain.toLowerCase();\r\n    if (domainForCheck.startsWith('www.')) domainForCheck = domainForCheck.substring(4);\r\n    const domainWithoutTLD = domainForCheck.split('.')[0] || '';\r\n    const fullDomainLower = domainInfo.full.toLowerCase();\r\n    let typosquatMatch = null, typosquatDetails = null, typosquatType = null;\r\n\r\n    \/\/ 3a. Character substitution\r\n    const substitutionMatches = findBrandWithSubstitutions(fullDomainLower);\r\n    if (substitutionMatches.length > 0) {\r\n      typosquatMatch = substitutionMatches[0].brand;\r\n      typosquatDetails = substitutionMatches[0].description;\r\n      typosquatType = substitutionMatches[0].type;\r\n    }\r\n\r\n    \/\/ 3b. Hyphen fragmented\r\n    if (!typosquatMatch) {\r\n      const hyphenMatches = checkWithoutHyphens(fullDomainLower);\r\n      if (hyphenMatches.length > 0) {\r\n        typosquatMatch = hyphenMatches[0].brand;\r\n        typosquatDetails = hyphenMatches[0].description;\r\n        typosquatType = 'hyphen_fragmented';\r\n      }\r\n    }\r\n\r\n    \/\/ 3c. Levenshtein distance\r\n    if (!typosquatMatch) {\r\n      for (const brand of knownBrands) {\r\n        const maxAllowedDistance = brand.length <= 4 ? 1 : 2;\r\n        if (Math.abs(domainWithoutTLD.length - brand.length) > 3) continue;\r\n        const distance = levenshteinDistance(domainWithoutTLD, brand);\r\n        if (distance > 0 && distance <= maxAllowedDistance && distance \/ Math.max(domainWithoutTLD.length, brand.length) < 0.4) {\r\n          typosquatMatch = brand;\r\n          typosquatType = 'levenshtein';\r\n          typosquatDetails = 'Domeniul difera prin ' + distance + ' caracter(e) de brandul \"' + brand + '\".';\r\n          break;\r\n        }\r\n        if (domainWithoutTLD.includes(brand) && domainWithoutTLD !== brand && brand.length >= 4 && domainWithoutTLD.length - brand.length <= 5) {\r\n          typosquatMatch = brand;\r\n          typosquatType = 'brand_extended';\r\n          typosquatDetails = 'Domeniul contine brandul \"' + brand + '\" cu caractere aditionale.';\r\n          break;\r\n        }\r\n      }\r\n    }\r\n\r\n    \/\/ 3d. Normalized typosquatting\r\n    if (!typosquatMatch) {\r\n      const normalizedTypo = normalizeTyposquatting(domainWithoutTLD);\r\n      if (normalizedTypo !== domainWithoutTLD) {\r\n        for (const brand of knownBrands) {\r\n          if (normalizedTypo === brand || normalizedTypo.includes(brand)) {\r\n            typosquatMatch = brand;\r\n            typosquatType = 'char_substitution';\r\n            typosquatDetails = 'Domeniul foloseste cifre sau simboluri pentru a imita \"' + brand + '\".';\r\n            break;\r\n          }\r\n        }\r\n      }\r\n    }\r\n\r\n    \/\/ 3e. Advanced typosquatting (Jaro-Winkler, keyboard proximity, patterns)\r\n    if (!typosquatMatch) {\r\n      const advancedMatches = advancedTyposquatCheck(domainWithoutTLD, knownBrands);\r\n      if (advancedMatches.length > 0) {\r\n        typosquatMatch = advancedMatches[0].brand;\r\n        typosquatDetails = advancedMatches[0].description;\r\n        typosquatType = advancedMatches[0].type;\r\n      }\r\n    }\r\n\r\n    if (typosquatMatch && !knownBrands.includes(domainWithoutTLD)) {\r\n      let title = t('typosquatTitle');\r\n      let description = typosquatDetails || t('typosquatDesc', { brand: typosquatMatch });\r\n      if (typosquatType === 'double_letter') { title = t('typosquatDouble'); }\r\n      else if (typosquatType === 'visual_trick') { title = t('typosquatVisual'); }\r\n      else if (typosquatType === 'char_substitution') { title = t('typosquatSubst'); }\r\n      else if (typosquatType === 'hyphen_fragmented') { title = t('typosquatHyphen'); }\r\n      else if (typosquatType === 'keyboard_typo') { title = t('typosquatKeyboard'); }\r\n      else if (typosquatType === 'jaro_winkler') { title = t('typosquatSimilarity'); }\r\n      else if (typosquatType === 'repetition') { title = t('typosquatRepetition'); }\r\n      else if (typosquatType === 'omission') { title = t('typosquatOmission'); }\r\n      else if (typosquatType === 'transposition') { title = t('typosquatTransposition'); }\r\n      else if (typosquatType === 'vowel_swap') { title = t('typosquatVowelSwap'); }\r\n      checks.push({ status: 'fail', title, description });\r\n      totalScore -= 35;\r\n    } else if (knownBrands.includes(domainWithoutTLD)) {\r\n      const isRomanianBrand = romanianBrandsRequiringRO.includes(domainWithoutTLD);\r\n      const isInternationalBrand = internationalBrandTLDs.hasOwnProperty(domainWithoutTLD);\r\n      const domainTLD = '.' + domainInfo.full.split('.').pop().toLowerCase();\r\n      const isOnRoTLD = domainTLD === '.ro' || domainInfo.full.toLowerCase().includes('.gov.ro');\r\n      let brandTLDIssue = false, brandTLDMessage = '';\r\n\r\n      if (isRomanianBrand && !isOnRoTLD) {\r\n        brandTLDIssue = true;\r\n        brandTLDMessage = currentLang === 'ro'\r\n          ? 'ATEN\u021aIE: \"' + domainWithoutTLD + '\" este un brand rom\u00e2nesc care ar trebui s\u0103 fie pe .ro, nu pe \"' + domainTLD + '\".'\r\n          : 'WARNING: \"' + domainWithoutTLD + '\" is a Romanian brand that should be on .ro, not on \"' + domainTLD + '\".';\r\n      } else if (isInternationalBrand) {\r\n        const allowedTLDs = internationalBrandTLDs[domainWithoutTLD];\r\n        if (!allowedTLDs.some(tld => domainInfo.full.toLowerCase().endsWith(tld))) {\r\n          brandTLDIssue = true;\r\n          brandTLDMessage = currentLang === 'ro'\r\n            ? 'ATEN\u021aIE: \"' + domainWithoutTLD + '\" ar trebui s\u0103 fie pe ' + allowedTLDs.slice(0, 3).join(', ') + '.'\r\n            : 'WARNING: \"' + domainWithoutTLD + '\" should be on ' + allowedTLDs.slice(0, 3).join(', ') + '.';\r\n        }\r\n      }\r\n\r\n      if (brandTLDIssue) {\r\n        checks.push({ status: 'fail', title: t('brandWrongTld'), description: brandTLDMessage });\r\n        totalScore -= 40;\r\n      } else {\r\n        checks.push({ status: 'pass', title: t('brandOk'), description: t('brandOkDesc') });\r\n      }\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('noTyposquat'), description: t('noTyposquatDesc') });\r\n    }\r\n\r\n    \/\/ 4. Suspicious TLD\r\n    if (suspiciousTLDs.some(tld => domainInfo.full.toLowerCase().endsWith(tld))) {\r\n      checks.push({ status: 'warn', title: t('suspiciousTld'), description: t('suspiciousTldDesc') });\r\n      totalScore -= 15;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('tldOk'), description: t('tldOkDesc') });\r\n    }\r\n\r\n    \/\/ 5. Excessive subdomains\r\n    const subdomainCount = Math.max(0, domainInfo.full.split('.').length - 2);\r\n    if (subdomainCount > 2) {\r\n      checks.push({ status: 'warn', title: t('multiSubdomain'), description: t('multiSubdomainDesc', { count: subdomainCount }) });\r\n      totalScore -= 10;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('subdomainOk'), description: t('subdomainOkDesc') });\r\n    }\r\n\r\n    \/\/ 6. Phishing keywords\r\n    const fullUrl = (domainInfo.full + domainInfo.pathname + domainInfo.search).toLowerCase();\r\n    const foundKeywords = phishingKeywords.filter(kw => fullUrl.includes(kw));\r\n    if (foundKeywords.length >= 2) {\r\n      checks.push({ status: 'fail', title: t('phishKeywords'), description: t('phishKeywordsDesc', { keywords: foundKeywords.slice(0, 3).join('\", \"') }) });\r\n      totalScore -= 20;\r\n    } else if (foundKeywords.length === 1) {\r\n      checks.push({ status: 'warn', title: t('sensitiveTerm'), description: t('sensitiveTermDesc', { keyword: foundKeywords[0] }) });\r\n      totalScore -= 5;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('noSuspiciousTerms'), description: t('noSuspiciousTermsDesc') });\r\n    }\r\n\r\n    \/\/ 7. Domain length\r\n    if (domainInfo.full.length > 40) {\r\n      checks.push({ status: 'warn', title: t('longDomain'), description: t('longDomainDesc', { length: domainInfo.full.length }) });\r\n      totalScore -= 10;\r\n    } else {\r\n      checks.push({ status: 'pass', title: t('domainLengthOk'), description: t('domainLengthOkDesc') });\r\n    }\r\n\r\n    \/\/ 8. IP instead of domain\r\n    if (\/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$\/.test(domainInfo.full)) {\r\n      checks.push({ status: 'fail', title: t('ipAddress'), description: t('ipAddressDesc') });\r\n      totalScore -= 25;\r\n    }\r\n\r\n    \/\/ 9. Non-standard port\r\n    if (domainInfo.port && domainInfo.port !== '80' && domainInfo.port !== '443') {\r\n      checks.push({ status: 'warn', title: t('nonStandardPort'), description: t('nonStandardPortDesc', { port: domainInfo.port }) });\r\n      totalScore -= 10;\r\n    }\r\n\r\n    \/\/ 10. Punycode\/IDN\r\n    if (domainInfo.full.startsWith('xn--') || domainInfo.full.includes('.xn--')) {\r\n      checks.push({ status: 'warn', title: t('idnDomain'), description: t('idnDomainDesc') });\r\n      totalScore -= 15;\r\n    }\r\n\r\n    \/\/ 11. Suspicious characters\r\n    if (\/--|__|[!@#$%^&*()+=]\/.test(domainInfo.full)) {\r\n      checks.push({ status: 'warn', title: t('unusualChars'), description: t('unusualCharsDesc') });\r\n      totalScore -= 10;\r\n    }\r\n\r\n    \/\/ 12. Brand in subdomain\r\n    const allParts = domainInfo.full.split('.');\r\n    const subdomains = allParts.length > 2 ? allParts.slice(0, -2) : [];\r\n    const mainDomain = allParts.length >= 2 ? allParts[allParts.length - 2] : (allParts[0] || '');\r\n    const brandInSubdomain = subdomains.length > 0 && knownBrands.some(brand => subdomains.some(sub => sub.includes(brand)));\r\n    if (brandInSubdomain && !knownBrands.includes(mainDomain)) {\r\n      checks.push({ status: 'fail', title: t('brandInSubdomain'), description: t('brandInSubdomainDesc') });\r\n      totalScore -= 25;\r\n    }\r\n\r\n    totalScore = Math.max(0, Math.min(100, totalScore));\r\n    let riskLevel = totalScore >= SCORE_THRESHOLDS.safe ? 'safe' : totalScore >= SCORE_THRESHOLDS.warning ? 'warning' : 'danger';\r\n\r\n    return { valid: true, url: sanitizeInput(url), score: totalScore, riskLevel, checks };\r\n  }\r\n\r\n  \/\/ === DOM Manipulation ===\r\n  function createCheckItem(check) {\r\n    const validStatus = validateStatus(check.status);\r\n    const item = document.createElement('div');\r\n    item.className = 'zic2__checkItem status-' + validStatus;\r\n\r\n    const iconDiv = document.createElement('div');\r\n    iconDiv.className = 'zic2__checkIcon';\r\n    iconDiv.textContent = validStatus === 'pass' ? '\\u2713' : validStatus === 'warn' ? '!' : '\\u2717';\r\n\r\n    const contentDiv = document.createElement('div');\r\n    contentDiv.className = 'zic2__checkContent';\r\n\r\n    const titleDiv = document.createElement('div');\r\n    titleDiv.className = 'zic2__checkTitle';\r\n    titleDiv.textContent = check.title || '';\r\n\r\n    const descDiv = document.createElement('div');\r\n    descDiv.className = 'zic2__checkDesc';\r\n    descDiv.textContent = check.description || '';\r\n\r\n    contentDiv.appendChild(titleDiv);\r\n    contentDiv.appendChild(descDiv);\r\n    item.appendChild(iconDiv);\r\n    item.appendChild(contentDiv);\r\n    return item;\r\n  }\r\n\r\n  function displayResults(analysis) {\r\n    \/\/ Store for export\r\n    lastAnalysis = analysis;\r\n\r\n    \/\/ Save to history\r\n    saveToHistory(analysis);\r\n\r\n    \/\/ Set timestamp for print\r\n    const now = new Date();\r\n    const timestamp = now.toLocaleDateString(currentLang === 'ro' ? 'ro-RO' : 'en-GB', {\r\n      year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit'\r\n    });\r\n    elements.scoreCard.setAttribute('data-print-timestamp', timestamp);\r\n\r\n    elements.analyzedUrl.textContent = analysis.url;\r\n    elements.scoreNumber.textContent = String(analysis.score);\r\n\r\n    const validRiskLevels = ['safe', 'warning', 'danger'];\r\n    const safeRiskLevel = validRiskLevels.includes(analysis.riskLevel) ? analysis.riskLevel : 'warning';\r\n\r\n    elements.scoreCircle.className = 'zic2__scoreCircle score-' + safeRiskLevel;\r\n    elements.scoreDisplay.className = 'zic2__scoreDisplay score-' + safeRiskLevel;\r\n\r\n    if (safeRiskLevel === 'safe') {\r\n      elements.scoreText.textContent = t('scoreSafe');\r\n      elements.scoreDesc.textContent = t('descSafe');\r\n    } else if (safeRiskLevel === 'warning') {\r\n      elements.scoreText.textContent = t('scoreWarning');\r\n      elements.scoreDesc.textContent = t('descWarning');\r\n    } else {\r\n      elements.scoreText.textContent = t('scoreDanger');\r\n      elements.scoreDesc.textContent = t('descDanger');\r\n    }\r\n\r\n    elements.scoreCard.classList.remove('is-hidden');\r\n\r\n    const order = { fail: 0, warn: 1, pass: 2 };\r\n    analysis.checks.sort((a, b) => (order[a.status] || 1) - (order[b.status] || 1));\r\n\r\n    while (elements.checksList.firstChild) {\r\n      elements.checksList.removeChild(elements.checksList.firstChild);\r\n    }\r\n\r\n    for (const check of analysis.checks) {\r\n      elements.checksList.appendChild(createCheckItem(check));\r\n    }\r\n\r\n    elements.checksCard.classList.remove('is-hidden');\r\n\r\n    \/\/ Show export buttons\r\n    if (elements.exportButtons) {\r\n      elements.exportButtons.classList.remove('is-hidden');\r\n    }\r\n\r\n    setTimeout(() => elements.scoreCard.scrollIntoView({ behavior: 'smooth', block: 'nearest' }), 100);\r\n  }\r\n\r\n  \/\/ === Actions ===\r\n  let isAnalyzing = false;\r\n\r\n  async function analyze() {\r\n    if (isAnalyzing) return;\r\n\r\n    const now = Date.now();\r\n    if (now - lastAnalysisTime < MIN_ANALYSIS_INTERVAL) return;\r\n    lastAnalysisTime = now;\r\n\r\n    const rawUrl = elements.urlInput.value;\r\n    const url = sanitizeInput(rawUrl);\r\n\r\n    if (!url) {\r\n      elements.errors.textContent = t('errorEmpty');\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    if (rawUrl.length > MAX_URL_LENGTH) {\r\n      elements.errors.textContent = t('errorTooLong', { max: MAX_URL_LENGTH });\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    if (containsDangerousPatterns(rawUrl)) {\r\n      elements.errors.textContent = t('errorDangerous');\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    elements.errors.classList.add('is-hidden');\r\n    isAnalyzing = true;\r\n\r\n    \/\/ Announce to screen readers that analysis is starting\r\n    announceToSR(currentLang === 'ro' ? 'Se verific\u0103 URL-ul...' : 'Analyzing URL...');\r\n\r\n    const analyzeBtn = root.querySelector('[data-action=\"analyze\"]');\r\n    const originalBtnText = analyzeBtn ? analyzeBtn.innerHTML : '';\r\n    if (analyzeBtn) {\r\n      analyzeBtn.innerHTML = '<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" class=\"zic2__spinner\"><circle cx=\"12\" cy=\"12\" r=\"10\" stroke-dasharray=\"32\" stroke-dashoffset=\"12\"\/><\/svg> ' + t('btnAnalyzing');\r\n      analyzeBtn.disabled = true;\r\n    }\r\n\r\n    \/\/ Show loading indicator and reset steps\r\n    if (elements.loading) {\r\n      elements.loading.classList.remove('is-hidden');\r\n      resetLoadingSteps();\r\n      updateLoadingStep('local', 'checking');\r\n    }\r\n\r\n    try {\r\n      const analysis = analyzeURL(url);\r\n      updateLoadingStep('local', 'done');\r\n\r\n      if (!analysis.valid) {\r\n        elements.errors.textContent = t('errorInvalid');\r\n        elements.errors.classList.remove('is-hidden');\r\n        if (elements.loading) elements.loading.classList.add('is-hidden');\r\n        return;\r\n      }\r\n\r\n      let fullUrl = url;\r\n      if (!fullUrl.match(\/^https?:\\\/\\\/\/i)) fullUrl = 'https:\/\/' + fullUrl;\r\n\r\n      const apiChecksPromise = runAPIChecks(fullUrl);\r\n      displayResults(analysis);\r\n\r\n      if (elements.apiStatus) {\r\n        elements.apiStatus.classList.remove('is-hidden');\r\n        resetApiStatus();\r\n      }\r\n\r\n      const apiResults = await apiChecksPromise;\r\n\r\n      \/\/ Process Google Safe Browsing\r\n      if (apiResults.googleSafeBrowsing.checked) {\r\n        if (!apiResults.googleSafeBrowsing.safe) {\r\n          const threats = apiResults.googleSafeBrowsing.threats || [currentLang === 'ro' ? 'Amenin\u021bare detectat\u0103' : 'Threat detected'];\r\n          analysis.checks.unshift({ status: 'fail', title: t('googleFail'), description: t('googleFailDesc', { threats: threats.join(', ') }) });\r\n          analysis.score = Math.max(0, analysis.score - 40);\r\n          updateApiStatus(elements.apiGoogle, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('googleOk'), description: t('googleOkDesc') });\r\n          updateApiStatus(elements.apiGoogle, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiGoogle, 'error');\r\n      }\r\n\r\n      \/\/ Process VirusTotal\r\n      if (apiResults.virusTotal.checked) {\r\n        if (!apiResults.virusTotal.safe) {\r\n          analysis.checks.unshift({ status: 'fail', title: t('vtFail'), description: t('vtFailDesc', { count: apiResults.virusTotal.malicious }) });\r\n          analysis.score = Math.max(0, analysis.score - 30);\r\n          updateApiStatus(elements.apiVirusTotal, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('vtOk'), description: t('vtOkDesc') });\r\n          updateApiStatus(elements.apiVirusTotal, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiVirusTotal, 'error');\r\n      }\r\n\r\n      \/\/ Process URLhaus\r\n      if (apiResults.urlhaus.checked) {\r\n        if (!apiResults.urlhaus.safe) {\r\n          analysis.checks.unshift({ status: 'fail', title: t('urlhausFail'), description: t('urlhausFailDesc', { threat: apiResults.urlhaus.threat || (currentLang === 'ro' ? 'necunoscut' : 'unknown') }) });\r\n          analysis.score = Math.max(0, analysis.score - 35);\r\n          updateApiStatus(elements.apiURLhaus, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('urlhausOk'), description: t('urlhausOkDesc') });\r\n          updateApiStatus(elements.apiURLhaus, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiURLhaus, 'error');\r\n      }\r\n\r\n      \/\/ Process urlscan.io\r\n      if (apiResults.urlscan.checked) {\r\n        if (!apiResults.urlscan.safe) {\r\n          const verdicts = apiResults.urlscan.verdicts || [];\r\n          analysis.checks.unshift({ status: 'fail', title: t('urlscanFail'), description: t('urlscanFailDesc', { verdicts: verdicts.join(', ') || 'suspect' }) });\r\n          analysis.score = Math.max(0, analysis.score - 25);\r\n          updateApiStatus(elements.apiUrlscan, 'warning');\r\n        } else {\r\n          const totalScans = apiResults.urlscan.total || 0;\r\n          const scansText = totalScans > 0 ? (currentLang === 'ro' ? ' (' + totalScans + ' scan\u0103ri anterioare)' : ' (' + totalScans + ' previous scans)') : '';\r\n          analysis.checks.push({ status: 'pass', title: t('urlscanOk'), description: t('urlscanOkDesc', { scans: scansText }) });\r\n          updateApiStatus(elements.apiUrlscan, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiUrlscan, 'error');\r\n      }\r\n\r\n      \/\/ Process PhishTank\r\n      if (apiResults.phishtank.checked) {\r\n        if (!apiResults.phishtank.safe) {\r\n          analysis.checks.unshift({ status: 'fail', title: t('phishtankFail'), description: t('phishtankFailDesc') });\r\n          analysis.score = Math.max(0, analysis.score - 40);\r\n          updateApiStatus(elements.apiPhishTank, 'warning');\r\n        } else {\r\n          analysis.checks.push({ status: 'pass', title: t('phishtankOk'), description: t('phishtankOkDesc') });\r\n          updateApiStatus(elements.apiPhishTank, 'success');\r\n        }\r\n      } else {\r\n        updateApiStatus(elements.apiPhishTank, 'error');\r\n      }\r\n\r\n      \/\/ === NOI VERIFIC\u0102RI v3 ===\r\n\r\n      \/\/ Process WHOIS (v\u00e2rsta domeniului)\r\n      if (apiResults.whois && apiResults.whois.checked) {\r\n        const whoisData = apiResults.whois;\r\n        if (whoisData.analysis?.isNew) {\r\n          \/\/ Domeniu < 30 zile = foarte suspect\r\n          analysis.checks.unshift({\r\n            status: 'fail',\r\n            title: currentLang === 'ro' ? 'Domeniu foarte nou' : 'Very new domain',\r\n            description: currentLang === 'ro'\r\n              ? `Domeniul a fost creat acum ${whoisData.dates.ageInDays} zile. Domeniile noi sunt frecvent folosite pentru phishing.`\r\n              : `Domain was created ${whoisData.dates.ageInDays} days ago. New domains are frequently used for phishing.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 25);\r\n        } else if (whoisData.analysis?.isYoung) {\r\n          \/\/ Domeniu < 1 an = aten\u021bie\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'Domeniu relativ nou' : 'Relatively new domain',\r\n            description: currentLang === 'ro'\r\n              ? `Domeniul a fost creat acum ${whoisData.dates.ageInDays} zile (sub 1 an). Verific\u0103 legitimitatea.`\r\n              : `Domain was created ${whoisData.dates.ageInDays} days ago (under 1 year). Verify legitimacy.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 10);\r\n        } else if (whoisData.dates?.ageInDays) {\r\n          \/\/ Domeniu vechi = bun semn\r\n          const years = Math.floor(whoisData.dates.ageInDays \/ 365);\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'Domeniu vechi' : 'Established domain',\r\n            description: currentLang === 'ro'\r\n              ? `Domeniul are ${years} an${years !== 1 ? 'i' : ''} vechime. Registrar: ${whoisData.registrar || 'necunoscut'}`\r\n              : `Domain is ${years} year${years !== 1 ? 's' : ''} old. Registrar: ${whoisData.registrar || 'unknown'}`\r\n          });\r\n        }\r\n      }\r\n\r\n      \/\/ Process GeoIP (loca\u021bia serverului)\r\n      if (apiResults.geoip && apiResults.geoip.checked) {\r\n        const geoData = apiResults.geoip;\r\n        const location = geoData.location;\r\n\r\n        \/\/ Verific\u0103 dac\u0103 e brand rom\u00e2nesc pe server din afara UE\r\n        const euCountries = ['RO', 'DE', 'FR', 'NL', 'BE', 'AT', 'PL', 'CZ', 'HU', 'IT', 'ES', 'PT', 'IE', 'SE', 'FI', 'DK', 'BG', 'HR', 'SK', 'SI', 'LT', 'LV', 'EE', 'CY', 'MT', 'LU', 'GR'];\r\n        const suspiciousCountries = ['CN', 'RU', 'KP', 'IR'];\r\n\r\n        if (suspiciousCountries.includes(location?.countryCode)) {\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'Server \u00een \u021bar\u0103 suspect\u0103' : 'Server in suspicious country',\r\n            description: currentLang === 'ro'\r\n              ? `Serverul este localizat \u00een ${location.country}. Acest lucru poate fi suspect pentru site-uri care pretind a fi rom\u00e2ne\u0219ti sau occidentale.`\r\n              : `Server is located in ${location.country}. This may be suspicious for sites claiming to be Romanian or Western.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 15);\r\n        } else {\r\n          \/\/ Informa\u021bie neutr\u0103 despre loca\u021bie\r\n          const isHosting = geoData.network?.isHosting ? (currentLang === 'ro' ? ' (hosting\/cloud)' : ' (hosting\/cloud)') : '';\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'Loca\u021bie server' : 'Server location',\r\n            description: currentLang === 'ro'\r\n              ? `Server \u00een ${location.country} (${location.city || 'N\/A'})${isHosting}. ISP: ${geoData.network?.isp || 'N\/A'}`\r\n              : `Server in ${location.country} (${location.city || 'N\/A'})${isHosting}. ISP: ${geoData.network?.isp || 'N\/A'}`\r\n          });\r\n        }\r\n      }\r\n\r\n      \/\/ Process DNS (verificare DNS records)\r\n      if (apiResults.dns && apiResults.dns.checked) {\r\n        const dnsData = apiResults.dns;\r\n        const analysis_dns = dnsData.analysis;\r\n\r\n        if (!analysis_dns?.hasIpAddresses) {\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'DNS: f\u0103r\u0103 IP' : 'DNS: no IP',\r\n            description: currentLang === 'ro'\r\n              ? 'Domeniul nu are \u00eenregistr\u0103ri DNS A. Poate fi un domeniu parcat sau nefunc\u021bional.'\r\n              : 'Domain has no A DNS records. May be a parked or non-functional domain.'\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 10);\r\n        } else if (!analysis_dns?.hasMailServers && !analysis_dns?.hasSpf) {\r\n          \/\/ F\u0103r\u0103 MX \u0219i f\u0103r\u0103 SPF = probabil nu e un business legitim\r\n          analysis.checks.push({\r\n            status: 'warn',\r\n            title: currentLang === 'ro' ? 'DNS: configurare minim\u0103' : 'DNS: minimal setup',\r\n            description: currentLang === 'ro'\r\n              ? 'Domeniul nu are server de email (MX) sau protec\u021bie SPF. Companiile legitime au de obicei aceste configur\u0103ri.'\r\n              : 'Domain has no email server (MX) or SPF protection. Legitimate companies usually have these configured.'\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 5);\r\n        }\r\n      }\r\n\r\n      \/\/ Process SSL (certificat SSL)\r\n      if (apiResults.ssl && apiResults.ssl.checked && !apiResults.ssl.analyzing) {\r\n        const sslData = apiResults.ssl;\r\n\r\n        if (sslData.analysis?.isGradeF || sslData.grade === 'F') {\r\n          analysis.checks.unshift({\r\n            status: 'fail',\r\n            title: currentLang === 'ro' ? 'SSL: Certificat problematic' : 'SSL: Problematic certificate',\r\n            description: currentLang === 'ro'\r\n              ? `Certificatul SSL are probleme grave (grad ${sslData.grade}). Conexiunea nu este sigur\u0103.`\r\n              : `SSL certificate has serious issues (grade ${sslData.grade}). Connection is not secure.`\r\n          });\r\n          analysis.score = Math.max(0, analysis.score - 20);\r\n        } else if (sslData.analysis?.isGradeA) {\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'SSL: Certificat excelent' : 'SSL: Excellent certificate',\r\n            description: currentLang === 'ro'\r\n              ? `Certificat SSL valid (grad ${sslData.grade}). Emis de: ${sslData.cert?.issuer || 'N\/A'}`\r\n              : `Valid SSL certificate (grade ${sslData.grade}). Issued by: ${sslData.cert?.issuer || 'N\/A'}`\r\n          });\r\n        } else if (sslData.grade) {\r\n          analysis.checks.push({\r\n            status: 'pass',\r\n            title: currentLang === 'ro' ? 'SSL: Certificat valid' : 'SSL: Valid certificate',\r\n            description: currentLang === 'ro'\r\n              ? `Certificat SSL valid (grad ${sslData.grade}). Emis de: ${sslData.cert?.issuer || 'N\/A'}`\r\n              : `Valid SSL certificate (grade ${sslData.grade}). Issued by: ${sslData.cert?.issuer || 'N\/A'}`\r\n          });\r\n        }\r\n      }\r\n\r\n      \/\/ Recalculate risk level\r\n      analysis.riskLevel = analysis.score >= SCORE_THRESHOLDS.safe ? 'safe' : analysis.score >= SCORE_THRESHOLDS.warning ? 'warning' : 'danger';\r\n      displayResults(analysis);\r\n\r\n      \/\/ Announce result to screen readers\r\n      const riskLabel = analysis.riskLevel === 'danger'\r\n        ? (currentLang === 'ro' ? 'Periculos' : 'Dangerous')\r\n        : analysis.riskLevel === 'warning'\r\n          ? (currentLang === 'ro' ? 'Aten\u021bie' : 'Warning')\r\n          : (currentLang === 'ro' ? 'Sigur' : 'Safe');\r\n      announceToSR(\r\n        currentLang === 'ro'\r\n          ? `Analiz\u0103 complet\u0103. Scor: ${analysis.score} din 100. Nivel de risc: ${riskLabel}.`\r\n          : `Analysis complete. Score: ${analysis.score} out of 100. Risk level: ${riskLabel}.`,\r\n        analysis.riskLevel === 'danger' ? 'assertive' : 'polite'\r\n      );\r\n\r\n    } catch (error) {\r\n      console.error('Analysis error:', error);\r\n      elements.errors.textContent = t('errorGeneral');\r\n      elements.errors.classList.remove('is-hidden');\r\n    } finally {\r\n      isAnalyzing = false;\r\n      \/\/ Hide loading indicator\r\n      if (elements.loading) {\r\n        elements.loading.classList.add('is-hidden');\r\n      }\r\n      if (analyzeBtn) {\r\n        analyzeBtn.innerHTML = originalBtnText;\r\n        analyzeBtn.disabled = false;\r\n      }\r\n    }\r\n  }\r\n\r\n  function reset() {\r\n    elements.urlInput.value = '';\r\n    if (elements.urlBatch) elements.urlBatch.value = '';\r\n    elements.errors.classList.add('is-hidden');\r\n    elements.errors.textContent = '';\r\n    elements.scoreCard.classList.add('is-hidden');\r\n    elements.checksCard.classList.add('is-hidden');\r\n    if (elements.apiStatus) elements.apiStatus.classList.add('is-hidden');\r\n    if (elements.loading) elements.loading.classList.add('is-hidden');\r\n    if (elements.exportButtons) elements.exportButtons.classList.add('is-hidden');\r\n    if (elements.batchResults) elements.batchResults.classList.add('is-hidden');\r\n    while (elements.checksList.firstChild) elements.checksList.removeChild(elements.checksList.firstChild);\r\n    if (elements.batchTbody) while (elements.batchTbody.firstChild) elements.batchTbody.removeChild(elements.batchTbody.firstChild);\r\n    lastAnalysis = null;\r\n    lastBatchResults = [];\r\n    elements.urlInput.focus();\r\n  }\r\n\r\n  \/\/ === BATCH MODE ===\r\n  function toggleBatchMode() {\r\n    const isBatch = elements.batchMode?.checked;\r\n    if (elements.singleInput) elements.singleInput.classList.toggle('is-hidden', isBatch);\r\n    if (elements.batchInput) elements.batchInput.classList.toggle('is-hidden', !isBatch);\r\n  }\r\n\r\n  async function analyzeBatch() {\r\n    const batchText = elements.urlBatch?.value || '';\r\n    const allUrls = batchText.split('\\n').map(u => u.trim()).filter(u => u.length > 0);\r\n    const urls = allUrls.slice(0, BATCH_LIMIT);\r\n\r\n    if (urls.length === 0) {\r\n      elements.errors.textContent = currentLang === 'ro' ? 'Introdu cel pu\u021bin un URL.' : 'Enter at least one URL.';\r\n      elements.errors.classList.remove('is-hidden');\r\n      return;\r\n    }\r\n\r\n    \/\/ Show warning if URLs were truncated\r\n    if (allUrls.length > BATCH_LIMIT) {\r\n      const warningMsg = t('batchTruncated', { count: BATCH_LIMIT, total: allUrls.length });\r\n      elements.errors.textContent = warningMsg;\r\n      elements.errors.classList.remove('is-hidden');\r\n      elements.errors.style.background = 'var(--zic-warning-light)';\r\n      elements.errors.style.borderColor = 'var(--zic-warning)';\r\n      elements.errors.style.color = 'var(--zic-ink)';\r\n    } else {\r\n      elements.errors.classList.add('is-hidden');\r\n      elements.errors.style.background = '';\r\n      elements.errors.style.borderColor = '';\r\n      elements.errors.style.color = '';\r\n    }\r\n\r\n    if (elements.loading) {\r\n      const loadingText = elements.loading.querySelector('.zic2__loadingText');\r\n      const loadingSub = elements.loading.querySelector('.zic2__loadingSubtext');\r\n      if (loadingText) loadingText.textContent = currentLang === 'ro' ? `Se verific\u0103 ${urls.length} URL-uri...` : `Checking ${urls.length} URLs...`;\r\n      if (loadingSub) loadingSub.textContent = currentLang === 'ro' ? 'Acest proces poate dura c\u00e2teva minute' : 'This may take a few minutes';\r\n      elements.loading.classList.remove('is-hidden');\r\n    }\r\n\r\n    \/\/ Don't hide errors if we just showed a truncation warning\r\n    if (allUrls.length <= BATCH_LIMIT) {\r\n      elements.errors.classList.add('is-hidden');\r\n    }\r\n    elements.scoreCard.classList.add('is-hidden');\r\n    elements.checksCard.classList.add('is-hidden');\r\n    lastBatchResults = [];\r\n\r\n    try {\r\n      for (let i = 0; i < urls.length; i++) {\r\n        const url = urls[i];\r\n        try {\r\n          let fullUrl = sanitizeInput(url);\r\n          if (!fullUrl.match(\/^https?:\\\/\\\/\/i)) fullUrl = 'https:\/\/' + fullUrl;\r\n\r\n          const extraction = extractDomain(fullUrl);\r\n          if (!extraction.valid) {\r\n            lastBatchResults.push({ url: url, score: 0, riskLevel: 'danger', error: currentLang === 'ro' ? 'URL invalid' : 'Invalid URL', checks: [] });\r\n            continue;\r\n          }\r\n\r\n          const analysis = analyzeUrlLocally(extraction);\r\n          analysis.url = fullUrl;\r\n          const apiResults = await runAPIChecks(fullUrl);\r\n\r\n          if (apiResults.googleSafeBrowsing?.checked && !apiResults.googleSafeBrowsing.safe) analysis.score = Math.max(0, analysis.score - 40);\r\n          if (apiResults.virusTotal?.checked && !apiResults.virusTotal.safe) analysis.score = Math.max(0, analysis.score - 30);\r\n          if (apiResults.urlhaus?.checked && !apiResults.urlhaus.safe) analysis.score = Math.max(0, analysis.score - 35);\r\n          if (apiResults.whois?.checked && apiResults.whois.analysis?.isNew) analysis.score = Math.max(0, analysis.score - 25);\r\n\r\n          analysis.riskLevel = analysis.score >= SCORE_THRESHOLDS.safe ? 'safe' : analysis.score >= SCORE_THRESHOLDS.warning ? 'warning' : 'danger';\r\n          lastBatchResults.push(analysis);\r\n        } catch (err) {\r\n          lastBatchResults.push({ url: url, score: 0, riskLevel: 'danger', error: err.message, checks: [] });\r\n        }\r\n      }\r\n      displayBatchResults();\r\n    } catch (error) {\r\n      console.error('Batch analysis error:', error);\r\n      elements.errors.textContent = currentLang === 'ro' ? 'Eroare \u00een analiza batch.' : 'Batch analysis error.';\r\n      elements.errors.classList.remove('is-hidden');\r\n    } finally {\r\n      if (elements.loading) elements.loading.classList.add('is-hidden');\r\n    }\r\n  }\r\n\r\n  function displayBatchResults() {\r\n    if (!elements.batchTbody || lastBatchResults.length === 0) return;\r\n    while (elements.batchTbody.firstChild) elements.batchTbody.removeChild(elements.batchTbody.firstChild);\r\n\r\n    const riskColors = getRiskColors();\r\n    const riskLabels = { safe: currentLang === 'ro' ? 'Sigur' : 'Safe', warning: currentLang === 'ro' ? 'Aten\u021bie' : 'Warning', danger: currentLang === 'ro' ? 'Pericol' : 'Danger' };\r\n\r\n    lastBatchResults.forEach((result, idx) => {\r\n      const tr = document.createElement('tr');\r\n      tr.style.borderBottom = '1px solid rgba(138, 136, 255, 0.1)';\r\n\r\n      const failChecks = result.checks?.filter(c => c.status === 'fail').map(c => c.title).slice(0, 3) || [];\r\n      const issues = result.error || failChecks.join(', ') || (currentLang === 'ro' ? 'Nicio problem\u0103' : 'No issues');\r\n\r\n      \/\/ Create cells safely with textContent\r\n      const tdNum = document.createElement('td');\r\n      tdNum.style.cssText = 'padding: 10px; font-weight: 600;';\r\n      tdNum.textContent = String(idx + 1);\r\n\r\n      const tdUrl = document.createElement('td');\r\n      tdUrl.style.cssText = 'padding: 10px; max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;';\r\n      tdUrl.title = result.url;\r\n      tdUrl.textContent = result.url;\r\n\r\n      const tdScore = document.createElement('td');\r\n      tdScore.style.cssText = 'padding: 10px; text-align: center; font-weight: 700;';\r\n      tdScore.style.color = riskColors[result.riskLevel];\r\n      tdScore.textContent = String(result.score);\r\n\r\n      const tdRisk = document.createElement('td');\r\n      tdRisk.style.cssText = 'padding: 10px; text-align: center;';\r\n      const riskSpan = document.createElement('span');\r\n      riskSpan.style.cssText = `background: ${riskColors[result.riskLevel]}20; color: ${riskColors[result.riskLevel]}; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 600;`;\r\n      riskSpan.textContent = riskLabels[result.riskLevel];\r\n      tdRisk.appendChild(riskSpan);\r\n\r\n      const tdIssues = document.createElement('td');\r\n      tdIssues.style.cssText = 'padding: 10px; font-size: 12px;';\r\n      if (result.error) tdIssues.style.color = '#ef4444';\r\n      tdIssues.textContent = issues;\r\n\r\n      tr.appendChild(tdNum);\r\n      tr.appendChild(tdUrl);\r\n      tr.appendChild(tdScore);\r\n      tr.appendChild(tdRisk);\r\n      tr.appendChild(tdIssues);\r\n      elements.batchTbody.appendChild(tr);\r\n    });\r\n\r\n    elements.batchResults.classList.remove('is-hidden');\r\n  }\r\n\r\n  \/\/ === EXPORT FUNCTIONS ===\r\n  function exportJSON(data, filename) {\r\n    const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application\/json' });\r\n    const url = URL.createObjectURL(blob);\r\n    const a = document.createElement('a');\r\n    a.href = url;\r\n    a.download = filename;\r\n    document.body.appendChild(a);\r\n    a.click();\r\n    document.body.removeChild(a);\r\n    URL.revokeObjectURL(url);\r\n  }\r\n\r\n  function exportCSV(data, filename) {\r\n    let csv = '';\r\n    if (Array.isArray(data)) {\r\n      csv = 'Nr,URL,Scor,Risc,Probleme\\n';\r\n      data.forEach((r, i) => {\r\n        const issues = r.error || r.checks?.filter(c => c.status === 'fail').map(c => c.title).join('; ') || '';\r\n        csv += `${i + 1},\"${r.url}\",${r.score},${r.riskLevel},\"${issues}\"\\n`;\r\n      });\r\n    } else {\r\n      csv = 'URL,Scor,Risc,Verificare,Status,Detalii\\n';\r\n      data.checks?.forEach(c => {\r\n        csv += `\"${data.url}\",${data.score},${data.riskLevel},\"${c.title}\",${c.status},\"${(c.description || '').replace(\/\"\/g, '\"\"')}\"\\n`;\r\n      });\r\n    }\r\n    const blob = new Blob([csv], { type: 'text\/csv;charset=utf-8;' });\r\n    const url = URL.createObjectURL(blob);\r\n    const a = document.createElement('a');\r\n    a.href = url;\r\n    a.download = filename;\r\n    document.body.appendChild(a);\r\n    a.click();\r\n    document.body.removeChild(a);\r\n    URL.revokeObjectURL(url);\r\n  }\r\n\r\n  function copyResultsToClipboard() {\r\n    if (!lastAnalysis) return;\r\n    let text = `=== ZIC Security Check ===\\nURL: ${lastAnalysis.url}\\nScor: ${lastAnalysis.score}\/100 (${lastAnalysis.riskLevel})\\n\\nVerific\u0103ri:\\n`;\r\n    lastAnalysis.checks?.forEach(c => {\r\n      const icon = c.status === 'pass' ? '\u2713' : c.status === 'fail' ? '\u2717' : '&#x26a0;';\r\n      text += `${icon} ${c.title}\\n`;\r\n    });\r\n    navigator.clipboard.writeText(text).then(() => {\r\n      alert(currentLang === 'ro' ? 'Rezultatele au fost copiate!' : 'Results copied!');\r\n    }).catch(err => console.error('Copy failed:', err));\r\n  }\r\n\r\n  \/\/ === SHARE FUNCTIONS ===\r\n  function shareResultLink(button) {\r\n    if (!lastAnalysis) return;\r\n\r\n    \/\/ Compress minimal result data to share\r\n    const shareData = {\r\n      u: lastAnalysis.url,\r\n      s: lastAnalysis.score,\r\n      r: lastAnalysis.riskLevel,\r\n      t: Date.now()\r\n    };\r\n\r\n    try {\r\n      \/\/ Encode to base64 for URL safety\r\n      const encoded = btoa(JSON.stringify(shareData));\r\n      const shareUrl = window.location.origin + window.location.pathname + '#share=' + encoded;\r\n\r\n      \/\/ Copy to clipboard\r\n      navigator.clipboard.writeText(shareUrl).then(() => {\r\n        \/\/ Show feedback\r\n        const originalText = button.querySelector('[data-i18n=\"shareLink\"]');\r\n        if (originalText) {\r\n          const original = originalText.textContent;\r\n          originalText.textContent = t('shareLinkCopied');\r\n          button.classList.add('is-success');\r\n          setTimeout(() => {\r\n            originalText.textContent = original;\r\n            button.classList.remove('is-success');\r\n          }, 2000);\r\n        }\r\n      }).catch(err => {\r\n        console.error('Share link copy failed:', err);\r\n        alert(currentLang === 'ro' ? 'Nu s-a putut copia link-ul' : 'Could not copy link');\r\n      });\r\n    } catch (e) {\r\n      console.error('Share encoding failed:', e);\r\n    }\r\n  }\r\n\r\n  \/\/ Check for shared results on page load\r\n  function loadSharedResults() {\r\n    const hash = window.location.hash;\r\n    if (!hash.startsWith('#share=')) return;\r\n\r\n    try {\r\n      const encoded = hash.slice(7);\r\n      const shareData = JSON.parse(atob(encoded));\r\n\r\n      if (shareData.u && typeof shareData.s === 'number') {\r\n        \/\/ Pre-fill the URL and show a minimal result display\r\n        elements.urlInput.value = shareData.u;\r\n\r\n        \/\/ Create a minimal analysis object for display\r\n        const sharedAnalysis = {\r\n          url: shareData.u,\r\n          score: shareData.s,\r\n          riskLevel: shareData.r || (shareData.s >= 70 ? 'safe' : shareData.s >= 40 ? 'warning' : 'danger'),\r\n          checks: [],\r\n          apiResults: {},\r\n          timestamp: shareData.t\r\n        };\r\n\r\n        \/\/ Display shared results with a note\r\n        displayResults(sharedAnalysis);\r\n\r\n        \/\/ Add shared indicator\r\n        const note = document.createElement('p');\r\n        note.className = 'zic2__sharedNote';\r\n        note.textContent = currentLang === 'ro'\r\n          ? '&#x26a0; Acesta este un rezultat partajat. Ruleaz\u0103 o verificare nou\u0103 pentru rezultate complete.'\r\n          : '&#x26a0; This is a shared result. Run a new check for complete results.';\r\n        elements.scoreCard.insertBefore(note, elements.scoreCard.firstChild);\r\n      }\r\n    } catch (e) {\r\n      console.error('Invalid share data:', e);\r\n    }\r\n  }\r\n\r\n  \/\/ === HISTORY FUNCTIONS ===\r\n  const HISTORY_KEY = 'zic_spoofing_history';\r\n  const MAX_HISTORY = 50;\r\n  const HISTORY_MAX_AGE_DAYS = 30;\r\n\r\n  function getHistory() {\r\n    try {\r\n      const history = JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]');\r\n      \/\/ Sort by timestamp descending (newest first)\r\n      return history.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));\r\n    } catch (e) {\r\n      return [];\r\n    }\r\n  }\r\n\r\n  function cleanOldHistory() {\r\n    try {\r\n      const history = JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]');\r\n      const cutoff = Date.now() - (HISTORY_MAX_AGE_DAYS * 24 * 60 * 60 * 1000);\r\n      const cleaned = history.filter(item => (item.timestamp || 0) > cutoff);\r\n      if (cleaned.length !== history.length) {\r\n        localStorage.setItem(HISTORY_KEY, JSON.stringify(cleaned.slice(0, MAX_HISTORY)));\r\n        return true;\r\n      }\r\n      return false;\r\n    } catch (e) {\r\n      return false;\r\n    }\r\n  }\r\n\r\n  function saveToHistory(analysis) {\r\n    if (!analysis?.url) return;\r\n    try {\r\n      const history = getHistory();\r\n      history.unshift({\r\n        url: analysis.url,\r\n        score: analysis.score,\r\n        riskLevel: analysis.riskLevel,\r\n        timestamp: Date.now(),\r\n        checksCount: analysis.checks?.length || 0,\r\n        failCount: analysis.checks?.filter(c => c.status === 'fail').length || 0\r\n      });\r\n      localStorage.setItem(HISTORY_KEY, JSON.stringify(history.slice(0, MAX_HISTORY)));\r\n      updateHistoryBadge();\r\n    } catch (e) {\r\n      console.warn('Could not save to history:', e);\r\n    }\r\n  }\r\n\r\n  function updateHistoryBadge() {\r\n    const history = getHistory();\r\n    if (elements.historyBadge) {\r\n      elements.historyBadge.textContent = history.length > 0 ? String(history.length) : '';\r\n      elements.historyBadge.style.display = history.length > 0 ? 'inline' : 'none';\r\n    }\r\n    if (elements.historyCount) {\r\n      elements.historyCount.textContent = history.length > 0 ? `(${history.length})` : '';\r\n    }\r\n  }\r\n\r\n  function displayHistory() {\r\n    const history = getHistory();\r\n    if (!elements.historyList) return;\r\n\r\n    while (elements.historyList.firstChild) elements.historyList.removeChild(elements.historyList.firstChild);\r\n\r\n    if (history.length === 0) {\r\n      const emptyMsg = document.createElement('div');\r\n      emptyMsg.style.cssText = 'padding: 20px; text-align: center; color: var(--zic-text-muted); font-size: 13px;';\r\n      emptyMsg.textContent = currentLang === 'ro' ? 'Nu exist\u0103 verific\u0103ri anterioare.' : 'No previous checks.';\r\n      elements.historyList.appendChild(emptyMsg);\r\n      return;\r\n    }\r\n\r\n    const riskColors = getRiskColors();\r\n\r\n    history.forEach((item, idx) => {\r\n      const div = document.createElement('div');\r\n      div.style.cssText = 'padding: 10px 12px; border-bottom: 1px solid rgba(138, 136, 255, 0.1); display: flex; align-items: center; gap: 10px; cursor: pointer;';\r\n      div.addEventListener('click', () => {\r\n        elements.urlInput.value = item.url;\r\n        if (elements.batchMode) elements.batchMode.checked = false;\r\n        toggleBatchMode();\r\n        elements.historySection?.classList.add('is-hidden');\r\n      });\r\n\r\n      const scoreSpan = document.createElement('span');\r\n      scoreSpan.style.cssText = `min-width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; background: ${riskColors[item.riskLevel]}20; color: ${riskColors[item.riskLevel]};`;\r\n      scoreSpan.textContent = String(item.score);\r\n\r\n      const infoDiv = document.createElement('div');\r\n      infoDiv.style.cssText = 'flex: 1; min-width: 0;';\r\n\r\n      const urlDiv = document.createElement('div');\r\n      urlDiv.style.cssText = 'font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;';\r\n      urlDiv.textContent = item.url;\r\n      urlDiv.title = item.url;\r\n\r\n      const metaDiv = document.createElement('div');\r\n      metaDiv.style.cssText = 'font-size: 11px; color: var(--zic-text-muted); margin-top: 2px;';\r\n      const date = new Date(item.timestamp);\r\n      metaDiv.textContent = date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\r\n      if (item.failCount > 0) metaDiv.textContent += ` \u2022 ${item.failCount} ${currentLang === 'ro' ? 'probleme' : 'issues'}`;\r\n\r\n      infoDiv.appendChild(urlDiv);\r\n      infoDiv.appendChild(metaDiv);\r\n      div.appendChild(scoreSpan);\r\n      div.appendChild(infoDiv);\r\n      elements.historyList.appendChild(div);\r\n    });\r\n  }\r\n\r\n  function showHistory() {\r\n    displayHistory();\r\n    elements.historySection?.classList.remove('is-hidden');\r\n    elements.historySection?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\r\n  }\r\n\r\n  function clearHistory() {\r\n    if (!confirm(currentLang === 'ro' ? '\u0218tergi tot istoricul?' : 'Clear all history?')) return;\r\n    try {\r\n      localStorage.removeItem(HISTORY_KEY);\r\n      updateHistoryBadge();\r\n      displayHistory();\r\n    } catch (e) {\r\n      console.warn('Could not clear history:', e);\r\n    }\r\n  }\r\n\r\n  \/\/ QR Code Processing\r\n  function processQRCode(file) {\r\n    if (!file || !file.type.startsWith('image\/')) {\r\n      showQRStatus('error', currentLang === 'ro' ? 'Fi\u0219ier invalid. \u00cencarc\u0103 o imagine.' : 'Invalid file. Please upload an image.');\r\n      return;\r\n    }\r\n\r\n    showQRStatus('loading', currentLang === 'ro' ? 'Se proceseaz\u0103 codul QR...' : 'Processing QR code...');\r\n\r\n    const reader = new FileReader();\r\n    reader.onload = function(e) {\r\n      const img = new Image();\r\n      img.onload = function() {\r\n        const canvas = document.createElement('canvas');\r\n        const ctx = canvas.getContext('2d');\r\n        canvas.width = img.width;\r\n        canvas.height = img.height;\r\n        ctx.drawImage(img, 0, 0);\r\n\r\n        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n\r\n        if (typeof jsQR === 'undefined') {\r\n          showQRStatus('error', currentLang === 'ro' ? 'Biblioteca QR nu este \u00eenc\u0103rcat\u0103.' : 'QR library not loaded.');\r\n          return;\r\n        }\r\n\r\n        const code = jsQR(imageData.data, imageData.width, imageData.height);\r\n\r\n        if (code && code.data) {\r\n          const detectedUrl = code.data.trim();\r\n          \/\/ Check if it looks like a URL\r\n          if (detectedUrl.match(\/^https?:\\\/\\\/\/i) || detectedUrl.match(\/^www\\.\/i)) {\r\n            elements.urlInput.value = detectedUrl;\r\n            showQRStatus('success', currentLang === 'ro'\r\n              ? `URL detectat: ${truncateUrl(detectedUrl, 50)}`\r\n              : `URL detected: ${truncateUrl(detectedUrl, 50)}`);\r\n          } else {\r\n            showQRStatus('warning', currentLang === 'ro'\r\n              ? `Text detectat (nu e URL): ${truncateUrl(detectedUrl, 40)}`\r\n              : `Text detected (not URL): ${truncateUrl(detectedUrl, 40)}`);\r\n          }\r\n        } else {\r\n          showQRStatus('error', currentLang === 'ro'\r\n            ? 'Nu s-a g\u0103sit niciun cod QR \u00een imagine.'\r\n            : 'No QR code found in image.');\r\n        }\r\n      };\r\n      img.onerror = function() {\r\n        showQRStatus('error', currentLang === 'ro' ? 'Nu s-a putut \u00eenc\u0103rca imaginea.' : 'Could not load image.');\r\n      };\r\n      img.src = e.target.result;\r\n    };\r\n    reader.onerror = function() {\r\n      showQRStatus('error', currentLang === 'ro' ? 'Eroare la citirea fi\u0219ierului.' : 'Error reading file.');\r\n    };\r\n    reader.readAsDataURL(file);\r\n  }\r\n\r\n  function truncateUrl(url, maxLen) {\r\n    return url.length > maxLen ? url.substring(0, maxLen) + '...' : url;\r\n  }\r\n\r\n  function showQRStatus(type, message) {\r\n    if (!elements.qrStatus) return;\r\n    elements.qrStatus.classList.remove('is-hidden');\r\n    elements.qrStatus.textContent = message;\r\n    elements.qrStatus.style.background = type === 'success' ? 'var(--zic-safe-bg)' :\r\n                                          type === 'error' ? 'var(--zic-danger-bg)' :\r\n                                          type === 'warning' ? 'var(--zic-warning-bg)' :\r\n                                          'var(--zic-surface)';\r\n    elements.qrStatus.style.color = type === 'success' ? 'var(--zic-safe)' :\r\n                                     type === 'error' ? 'var(--zic-danger)' :\r\n                                     type === 'warning' ? 'var(--zic-warning)' :\r\n                                     'var(--zic-muted)';\r\n  }\r\n\r\n  function loadExample() {\r\n    const examples = [\r\n      'https:\/\/www.bancatransllvania.ro\/autentificare',\r\n      'https:\/\/paypa1-secure-login.suspicious-site.tk\/verify-account',\r\n      'https:\/\/secure.ernag-verificare.xyz\/cont',\r\n      'https:\/\/www.raiffelsen.ro\/login',\r\n      'https:\/\/anaf.gov.ro.verificare-ramburs.tk\/urgent'\r\n    ];\r\n    elements.urlInput.value = examples[Math.floor(Math.random() * examples.length)];\r\n  }\r\n\r\n  const VALID_ACTIONS = ['analyze', 'reset', 'example', 'toggleLang', 'toggleTheme', 'exportJSON', 'exportCSV', 'copyResults', 'exportBatchJSON', 'exportBatchCSV', 'showHistory', 'clearHistory', 'shareLink', 'printReport'];\r\n\r\n  function handleClick(e) {\r\n    const button = e.target.closest('[data-action]');\r\n    if (!button) return;\r\n    const action = button.dataset.action;\r\n    if (!VALID_ACTIONS.includes(action)) return;\r\n\r\n    if (action === 'analyze') {\r\n      if (elements.batchMode?.checked) analyzeBatch();\r\n      else analyze();\r\n    }\r\n    else if (action === 'reset') reset();\r\n    else if (action === 'example') loadExample();\r\n    else if (action === 'toggleLang') toggleLanguage();\r\n    else if (action === 'toggleTheme') toggleTheme();\r\n    else if (action === 'exportJSON' && lastAnalysis) exportJSON(lastAnalysis, `zic-security-${Date.now()}.json`);\r\n    else if (action === 'exportCSV' && lastAnalysis) exportCSV(lastAnalysis, `zic-security-${Date.now()}.csv`);\r\n    else if (action === 'copyResults') copyResultsToClipboard();\r\n    else if (action === 'exportBatchJSON' && lastBatchResults.length) exportJSON(lastBatchResults, `zic-batch-${Date.now()}.json`);\r\n    else if (action === 'exportBatchCSV' && lastBatchResults.length) exportCSV(lastBatchResults, `zic-batch-${Date.now()}.csv`);\r\n    else if (action === 'showHistory') showHistory();\r\n    else if (action === 'clearHistory') clearHistory();\r\n    else if (action === 'shareLink') shareResultLink(button);\r\n    else if (action === 'printReport') window.print();\r\n  }\r\n\r\n  function handleKeypress(e) {\r\n    if (e.key === 'Enter' && e.target === elements.urlInput) {\r\n      e.preventDefault();\r\n      analyze();\r\n    }\r\n  }\r\n\r\n  function init() {\r\n    if (!root || !elements.urlInput) {\r\n      console.error('ZIC Website Spoofing v2: Required elements not found');\r\n      return;\r\n    }\r\n    \/\/ Apply initial translations based on browser language\r\n    applyTranslations();\r\n\r\n    \/\/ Check for shared results in URL hash\r\n    loadSharedResults();\r\n\r\n    root.addEventListener('click', handleClick);\r\n    root.addEventListener('keypress', handleKeypress);\r\n\r\n    \/\/ Batch mode toggle listener\r\n    if (elements.batchMode) {\r\n      elements.batchMode.addEventListener('change', toggleBatchMode);\r\n    }\r\n\r\n    \/\/ Initialize history badge\r\n    updateHistoryBadge();\r\n\r\n    \/\/ QR Code upload listener\r\n    if (elements.qrUpload) {\r\n      elements.qrUpload.addEventListener('change', function(e) {\r\n        if (e.target.files && e.target.files[0]) {\r\n          processQRCode(e.target.files[0]);\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  if (document.readyState === 'loading') {\r\n    document.addEventListener('DOMContentLoaded', init);\r\n  } else {\r\n    init();\r\n  }\r\n})();\r\n<\/script>\r\n<\/div>\r\n\n\n\n\n<h3 class=\"wp-block-heading whitespace-pre-wrap break-words\">Concluzie<\/h3>\n\n\n\n<p class=\"whitespace-pre-wrap break-words\">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>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><a href=\"https:\/\/zic.legal\/ro\/team\/zlatigeorge\/\" target=\"_blank\" rel=\"noopener\">George Zlati&nbsp;<\/a>este avocat \u0219i lector universitar. Acesta este titular al disciplinei&nbsp;<em>Criminalitate informatic\u0103&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>","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>","protected":false},"author":2,"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 v26.8 - 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=\"2025-12-29T07:52:40+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\/cffc51a7df5926dd9954aeb3bbbcc303\"},\"headline\":\"Email spoofing. Cum identifici un email fals\",\"datePublished\":\"2024-07-12T13:00:52+00:00\",\"dateModified\":\"2025-12-29T07:52:40+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\":\"2025-12-29T07:52:40+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\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/zic.legal\/#\/schema\/person\/cffc51a7df5926dd9954aeb3bbbcc303\",\"name\":\"George Zlati\",\"url\":\"https:\/\/zic.legal\/ro\/author\/zlatigeorge\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Email spoofing. Cum identifici un email fals | ZIC Legal","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.","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":"2025-12-29T07:52:40+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\/cffc51a7df5926dd9954aeb3bbbcc303"},"headline":"Email spoofing. Cum identifici un email fals","datePublished":"2024-07-12T13:00:52+00:00","dateModified":"2025-12-29T07:52:40+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":"2025-12-29T07:52:40+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\/"]},{"@type":"Person","@id":"https:\/\/zic.legal\/#\/schema\/person\/cffc51a7df5926dd9954aeb3bbbcc303","name":"George Zlati","url":"https:\/\/zic.legal\/ro\/author\/zlatigeorge\/"}]}},"jetpack_featured_media_url":"https:\/\/zic.legal\/wp-content\/uploads\/2024\/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\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/comments?post=2434"}],"version-history":[{"count":12,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2434\/revisions"}],"predecessor-version":[{"id":4097,"href":"https:\/\/zic.legal\/ro\/wp-json\/wp\/v2\/posts\/2434\/revisions\/4097"}],"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}]}}