Professional SEO audit tool - analyzes on-page SEO, technical issues, content quality, structured data, and provides actionable recommendations
Size
108.5 KB
Version
1.2.19
Created
Dec 2, 2025
Updated
10 days ago
1// ==UserScript==
2// @name SEO Audit Pro - Complete Site Analysis
3// @description Professional SEO audit tool - analyzes on-page SEO, technical issues, content quality, structured data, and provides actionable recommendations
4// @version 1.2.19
5// @match https://www.medreviews.co.il/*
6// @match https://medreviews.co.il/*
7// @match https://developers.google.com/*
8// @match https://www.catef4u.com/*
9// @match https://catef4u.com/*
10// @grant GM.xmlhttpRequest
11// ==/UserScript==
12(function() {
13 'use strict';
14
15 // ===== GOOGLE DOCUMENTATION LINKS =====
16 const GOOGLE_DOCS = {
17 coreWebVitals: 'https://web.dev/vitals/',
18 lcp: 'https://web.dev/lcp/',
19 inp: 'https://web.dev/inp/',
20 cls: 'https://web.dev/cls/',
21 fcp: 'https://web.dev/fcp/',
22 ttfb: 'https://web.dev/ttfb/',
23 titleTag: 'https://developers.google.com/search/docs/appearance/title-link',
24 metaDescription: 'https://developers.google.com/search/docs/appearance/snippet',
25 headings: 'https://developers.google.com/search/docs/appearance/structured-data/article',
26 canonical: 'https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls',
27 openGraph: 'https://ogp.me/',
28 mobileFirst: 'https://developers.google.com/search/mobile-sites/mobile-first-indexing',
29 viewport: 'https://developers.google.com/search/docs/crawling-indexing/mobile/mobile-sites-mobile-first-indexing',
30 https: 'https://developers.google.com/search/docs/crawling-indexing/https',
31 structuredData: 'https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data',
32 richResults: 'https://search.google.com/test/rich-results',
33 robotsTxt: 'https://developers.google.com/search/docs/crawling-indexing/robots/intro',
34 sitemap: 'https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview',
35 imageAlt: 'https://developers.google.com/search/docs/appearance/google-images',
36 pagespeed: 'https://pagespeed.web.dev/',
37 searchConsole: 'https://search.google.com/search-console'
38 };
39
40 // ===== PREMIUM CONFIGURATION =====
41 const CONFIG = {
42 version: '4.0.0',
43 name: 'SEO Audit Pro - Ultimate Premium Edition',
44 maxScore: 100,
45 cacheExpiry: 300000, // 5 minutes
46 categories: {
47 onPage: { weight: 15, icon: '📄', color: '#667eea', gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
48 technical: { weight: 15, icon: '🔧', color: '#f093fb', gradient: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
49 content: { weight: 12, icon: '📝', color: '#4facfe', gradient: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' },
50 structure: { weight: 12, icon: '🏗️', color: '#43e97b', gradient: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)' },
51 performance: { weight: 15, icon: '⚡', color: '#fa709a', gradient: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' },
52 crawlability: { weight: 8, icon: '🤖', color: '#30cfd0', gradient: 'linear-gradient(135deg, #30cfd0 0%, #330867 100%)' },
53 images: { weight: 8, icon: '🖼️', color: '#a8edea', gradient: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)' },
54 mobile: { weight: 8, icon: '📱', color: '#fda085', gradient: 'linear-gradient(135deg, #fda085 0%, #f6d365 100%)' },
55 security: { weight: 7, icon: '🔒', color: '#f093fb', gradient: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' }
56 },
57 coreWebVitals: {
58 lcp: { good: 2500, needsImprovement: 4000, name: 'LCP', description: 'Largest Contentful Paint' },
59 inp: { good: 200, needsImprovement: 500, name: 'INP', description: 'Interaction to Next Paint' },
60 cls: { good: 0.1, needsImprovement: 0.25, name: 'CLS', description: 'Cumulative Layout Shift' },
61 fcp: { good: 1800, needsImprovement: 3000, name: 'FCP', description: 'First Contentful Paint' },
62 ttfb: { good: 800, needsImprovement: 1800, name: 'TTFB', description: 'Time to First Byte' }
63 }
64 };
65
66 // ===== TRANSLATIONS =====
67 const TRANSLATIONS = {
68 en: {
69 title: 'SEO Audit Pro v4.0',
70 subtitle: 'Ultimate Premium Edition - Google Guidelines',
71 runningAudit: 'Running comprehensive SEO audit...',
72 analyzingDetails: 'Analyzing Core Web Vitals, Mobile-First, Security, and more...',
73 overallScore: 'Overall Score',
74 criticalIssues: 'Critical Issues',
75 warnings: 'Warnings',
76 passed: 'Passed',
77 coreWebVitals: 'Core Web Vitals',
78 aiRecommendations: 'AI-Powered Recommendations',
79 categoryScores: 'Category Scores',
80 rerunAudit: 'Re-run Audit',
81 exportReport: 'Export Report',
82 exportPDF: 'Export PDF',
83 priority: 'Priority',
84 effort: 'Effort',
85 impact: 'Impact',
86 recommendation: 'Recommendation',
87 description: 'Description',
88 issues: 'issues',
89 good: 'good',
90 needsImprovement: 'needs improvement',
91 poor: 'poor',
92 excellent: 'Excellent',
93 goodLabel: 'Good',
94 needsWork: 'Needs Work',
95 poorLabel: 'Poor',
96 high: 'High',
97 medium: 'Medium',
98 low: 'Low',
99 changeLanguage: 'עברית',
100 analyzing: 'Analyzing',
101 complete: 'Complete',
102 learnMore: 'Learn More',
103 googleDocs: 'Google Documentation',
104 filterAll: 'All',
105 filterCritical: 'Critical',
106 filterWarnings: 'Warnings',
107 filterPassed: 'Passed',
108 searchPlaceholder: 'Search issues...',
109 expandAll: 'Expand All',
110 collapseAll: 'Collapse All',
111 coreWebVitalsTooltip: 'Core Web Vitals are Google\'s official metrics for measuring user experience. These metrics are ranking factors that directly impact your search visibility.',
112 aiRecommendationsTooltip: 'AI-powered analysis providing prioritized, actionable recommendations based on Google\'s SEO guidelines.',
113 categories: {
114 onPage: {
115 name: 'On-Page SEO',
116 tooltip: 'Based on Google\'s official guidelines for title tags, meta descriptions, headings, and structured content.'
117 },
118 technical: {
119 name: 'Technical SEO',
120 tooltip: 'Validates technical requirements according to Google Search Central documentation.'
121 },
122 content: {
123 name: 'Content Quality',
124 tooltip: 'Analyzes content based on Google\'s quality guidelines and helpful content system.'
125 },
126 structure: {
127 name: 'Site Structure',
128 tooltip: 'Examines URL structure and site hierarchy per Google\'s best practices.'
129 },
130 performance: {
131 name: 'Performance & Core Web Vitals',
132 tooltip: 'Measures Google\'s official Core Web Vitals metrics (LCP, INP, CLS, FCP, TTFB).'
133 },
134 crawlability: {
135 name: 'Crawlability',
136 tooltip: 'Checks robots.txt and sitemap.xml according to Google Search Console guidelines.'
137 },
138 images: {
139 name: 'Images & Media',
140 tooltip: 'Validates image optimization per Google Images best practices.'
141 },
142 mobile: {
143 name: 'Mobile-First',
144 tooltip: 'Tests mobile usability according to Google\'s mobile-first indexing requirements.'
145 },
146 security: {
147 name: 'Security',
148 tooltip: 'Verifies HTTPS and security requirements per Google\'s security guidelines.'
149 }
150 }
151 },
152 he: {
153 title: 'SEO Audit Pro v4.0',
154 subtitle: 'מהדורת פרימיום אולטימטיבית - הנחיות Google',
155 runningAudit: 'מריץ ביקורת SEO מקיפה...',
156 analyzingDetails: 'מנתח Core Web Vitals, Mobile-First, אבטחה ועוד...',
157 overallScore: 'ציון כללי',
158 criticalIssues: 'בעיות קריטיות',
159 warnings: 'אזהרות',
160 passed: 'עבר בהצלחה',
161 coreWebVitals: 'Core Web Vitals',
162 aiRecommendations: 'המלצות AI',
163 categoryScores: 'ציוני קטגוריות',
164 rerunAudit: 'הרץ ביקורת מחדש',
165 exportReport: 'ייצא דוח',
166 exportPDF: 'ייצא PDF',
167 priority: 'עדיפות',
168 effort: 'מאמץ',
169 impact: 'השפעה',
170 recommendation: 'המלצה',
171 description: 'תיאור',
172 issues: 'בעיות',
173 good: 'טוב',
174 needsImprovement: 'דורש שיפור',
175 poor: 'גרוע',
176 excellent: 'מצוין',
177 goodLabel: 'טוב',
178 needsWork: 'דורש עבודה',
179 poorLabel: 'גרוע',
180 high: 'גבוה',
181 medium: 'בינוני',
182 low: 'נמוך',
183 changeLanguage: 'English',
184 analyzing: 'מנתח',
185 complete: 'הושלם',
186 learnMore: 'למד עוד',
187 googleDocs: 'תיעוד Google',
188 filterAll: 'הכל',
189 filterCritical: 'קריטי',
190 filterWarnings: 'אזהרות',
191 filterPassed: 'עבר',
192 searchPlaceholder: 'חפש בעיות...',
193 expandAll: 'הרחב הכל',
194 collapseAll: 'כווץ הכל',
195 coreWebVitalsTooltip: 'Core Web Vitals הם המטריקות הרשמיות של Google למדידת חוויית משתמש. מטריקות אלו הן גורמי דירוג שמשפיעים ישירות על הנראות בחיפוש.',
196 aiRecommendationsTooltip: 'ניתוח מבוסס AI המספק המלצות מתועדפות וניתנות לביצוע על בסיס הנחיות ה-SEO של Google.',
197 categories: {
198 onPage: {
199 name: 'SEO בדף',
200 tooltip: 'מבוסס על ההנחיות הרשמיות של Google לתגי כותרת, תיאורי מטא, כותרות ותוכן מובנה.'
201 },
202 technical: {
203 name: 'SEO טכני',
204 tooltip: 'מאמת דרישות טכניות לפי תיעוד Google Search Central.'
205 },
206 content: {
207 name: 'איכות תוכן',
208 tooltip: 'מנתח תוכן על בסיס הנחיות האיכות של Google ומערכת התוכן המועיל.'
209 },
210 structure: {
211 name: 'מבנה אתר',
212 tooltip: 'בוחן מבנה URL והיררכיית אתר לפי שיטות העבודה המומלצות של Google.'
213 },
214 performance: {
215 name: 'ביצועים ו-Core Web Vitals',
216 tooltip: 'מודד את המטריקות הרשמיות של Google Core Web Vitals (LCP, INP, CLS, FCP, TTFB).'
217 },
218 crawlability: {
219 name: 'יכולת סריקה',
220 tooltip: 'בודק robots.txt ו-sitemap.xml לפי הנחיות Google Search Console.'
221 },
222 images: {
223 name: 'תמונות ומדיה',
224 tooltip: 'מאמת אופטימיזציה של תמונות לפי שיטות העבודה המומלצות של Google Images.'
225 },
226 mobile: {
227 name: 'Mobile-First',
228 tooltip: 'בודק שימושיות במובייל לפי דרישות ה-mobile-first indexing של Google.'
229 },
230 security: {
231 name: 'אבטחה',
232 tooltip: 'מאמת HTTPS ודרישות אבטחה לפי הנחיות האבטחה של Google.'
233 }
234 }
235 }
236 };
237
238 // ===== GLOBAL STATE =====
239 let currentLanguage = 'en';
240 let currentFilter = 'all';
241 let searchQuery = '';
242 let auditResults = {
243 scores: {},
244 issues: [],
245 warnings: [],
246 passed: [],
247 timestamp: null,
248 url: window.location.href,
249 coreWebVitals: {},
250 aiRecommendations: [],
251 cache: {}
252 };
253 let performanceObservers = [];
254
255 // ===== UTILITY FUNCTIONS =====
256 async function loadLanguage() {
257 try {
258 const savedLang = await GM.getValue('seo_audit_language', 'en');
259 currentLanguage = savedLang;
260 } catch (e) {
261 console.log('Could not load language preference:', e);
262 currentLanguage = 'en';
263 }
264 }
265
266 async function saveLanguage(lang) {
267 try {
268 await GM.setValue('seo_audit_language', lang);
269 currentLanguage = lang;
270 } catch (e) {
271 console.log('Could not save language preference:', e);
272 }
273 }
274
275 function t(key) {
276 const keys = key.split('.');
277 let value = TRANSLATIONS[currentLanguage];
278 for (const k of keys) {
279 value = value?.[k];
280 }
281 return value || key;
282 }
283
284 function calculateScore(passed, total) {
285 if (total === 0) return 100;
286 return Math.round((passed / total) * 100);
287 }
288
289 function getScoreColor(score) {
290 if (score >= 90) return '#0cce6b';
291 if (score >= 70) return '#ffa400';
292 if (score >= 50) return '#ff8c00';
293 return '#ff4e42';
294 }
295
296 function getScoreLabel(score) {
297 if (score >= 90) return t('excellent');
298 if (score >= 70) return t('goodLabel');
299 if (score >= 50) return t('needsWork');
300 return t('poorLabel');
301 }
302
303 function getCWVStatus(value, metric) {
304 const thresholds = CONFIG.coreWebVitals[metric];
305 if (!thresholds) return 'unknown';
306 if (value <= thresholds.good) return 'good';
307 if (value <= thresholds.needsImprovement) return 'needs-improvement';
308 return 'poor';
309 }
310
311 function getCWVColor(status) {
312 if (status === 'good') return '#0cce6b';
313 if (status === 'needs-improvement') return '#ffa400';
314 return '#ff4e42';
315 }
316
317 // ===== ENHANCED CORE WEB VITALS ANALYSIS =====
318 async function analyzeCoreWebVitals() {
319 console.log('⚡ Starting Enhanced Core Web Vitals Analysis...');
320 const issues = [];
321 const warnings = [];
322 const passed = [];
323
324 try {
325 const perfData = window.performance;
326 const navigation = perfData.getEntriesByType('navigation')[0];
327 const paintEntries = perfData.getEntriesByType('paint');
328
329 // TTFB - Time to First Byte
330 if (navigation) {
331 const ttfb = navigation.responseStart - navigation.requestStart;
332 auditResults.coreWebVitals.ttfb = Math.round(ttfb);
333 const ttfbStatus = getCWVStatus(ttfb, 'ttfb');
334
335 if (ttfbStatus === 'good') {
336 passed.push({
337 category: 'performance',
338 title: 'TTFB (Time to First Byte)',
339 description: `Excellent TTFB: ${Math.round(ttfb)}ms (< 800ms is good)`,
340 source: GOOGLE_DOCS.ttfb
341 });
342 } else if (ttfbStatus === 'needs-improvement') {
343 warnings.push({
344 category: 'performance',
345 severity: 'warning',
346 title: 'TTFB Needs Improvement',
347 description: `TTFB is ${Math.round(ttfb)}ms. Target: < 800ms`,
348 recommendation: 'Optimize server response time. Consider using a CDN, enabling caching, and optimizing database queries.',
349 source: GOOGLE_DOCS.ttfb
350 });
351 } else {
352 issues.push({
353 category: 'performance',
354 severity: 'high',
355 title: 'Poor TTFB',
356 description: `TTFB is ${Math.round(ttfb)}ms. This is too slow (> 1800ms).`,
357 recommendation: 'Critical: Improve server performance immediately. Check hosting, enable caching, use CDN, optimize backend code.',
358 source: GOOGLE_DOCS.ttfb
359 });
360 }
361 }
362
363 // FCP - First Contentful Paint
364 const fcpEntry = paintEntries.find(entry => entry.name === 'first-contentful-paint');
365 if (fcpEntry) {
366 const fcp = fcpEntry.startTime;
367 auditResults.coreWebVitals.fcp = Math.round(fcp);
368 const fcpStatus = getCWVStatus(fcp, 'fcp');
369
370 if (fcpStatus === 'good') {
371 passed.push({
372 category: 'performance',
373 title: 'FCP (First Contentful Paint)',
374 description: `Excellent FCP: ${Math.round(fcp)}ms (< 1.8s is good)`,
375 source: GOOGLE_DOCS.fcp
376 });
377 } else if (fcpStatus === 'needs-improvement') {
378 warnings.push({
379 category: 'performance',
380 severity: 'warning',
381 title: 'FCP Needs Improvement',
382 description: `FCP is ${Math.round(fcp)}ms. Target: < 1800ms`,
383 recommendation: 'Optimize render-blocking resources, reduce server response time, and minimize CSS/JS.',
384 source: GOOGLE_DOCS.fcp
385 });
386 } else {
387 issues.push({
388 category: 'performance',
389 severity: 'high',
390 title: 'Poor FCP',
391 description: `FCP is ${Math.round(fcp)}ms. Users see content too slowly (> 3s).`,
392 recommendation: 'Critical: Eliminate render-blocking resources, optimize critical rendering path, use resource hints.',
393 source: GOOGLE_DOCS.fcp
394 });
395 }
396 }
397
398 // LCP - Largest Contentful Paint (Real-time observation)
399 if ('PerformanceObserver' in window) {
400 try {
401 const lcpObserver = new PerformanceObserver((list) => {
402 const entries = list.getEntries();
403 const lastEntry = entries[entries.length - 1];
404 const lcp = lastEntry.renderTime || lastEntry.loadTime;
405 auditResults.coreWebVitals.lcp = Math.round(lcp);
406 });
407 lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
408 performanceObservers.push(lcpObserver);
409 } catch (e) {
410 console.log('LCP observation not available:', e);
411 }
412 }
413
414 // CLS - Cumulative Layout Shift (Real-time observation)
415 if ('PerformanceObserver' in window) {
416 try {
417 let clsValue = 0;
418 const clsObserver = new PerformanceObserver((list) => {
419 for (const entry of list.getEntries()) {
420 if (!entry.hadRecentInput) {
421 clsValue += entry.value;
422 }
423 }
424 auditResults.coreWebVitals.cls = clsValue.toFixed(3);
425 });
426 clsObserver.observe({ type: 'layout-shift', buffered: true });
427 performanceObservers.push(clsObserver);
428 } catch (e) {
429 console.log('CLS observation not available:', e);
430 }
431 }
432
433 // INP - Interaction to Next Paint (Real-time observation)
434 if ('PerformanceObserver' in window) {
435 try {
436 let maxInp = 0;
437 const inpObserver = new PerformanceObserver((list) => {
438 for (const entry of list.getEntries()) {
439 const inp = entry.processingStart - entry.startTime;
440 if (inp > maxInp) maxInp = inp;
441 }
442 if (maxInp > 0) {
443 auditResults.coreWebVitals.inp = Math.round(maxInp);
444 }
445 });
446 inpObserver.observe({ type: 'event', buffered: true, durationThreshold: 16 });
447 performanceObservers.push(inpObserver);
448 } catch (e) {
449 console.log('INP observation not available:', e);
450 }
451 }
452
453 } catch {
454 console.log('Error analyzing Core Web Vitals');
455 }
456
457 return { issues, warnings, passed };
458 }
459
460 // ===== ENHANCED ON-PAGE SEO ANALYSIS =====
461 function analyzeOnPageSEO() {
462 console.log('📄 Starting Enhanced On-Page SEO Analysis...');
463 const issues = [];
464 const warnings = [];
465 const passed = [];
466
467 // Title Tag Analysis
468 const titleTag = document.querySelector('title');
469 const titleText = titleTag ? titleTag.textContent.trim() : '';
470
471 if (!titleTag || !titleText) {
472 issues.push({
473 category: 'onPage',
474 severity: 'critical',
475 title: 'Missing Title Tag',
476 description: 'Your page is missing a <title> tag. This is critical for SEO.',
477 recommendation: 'Add a unique, descriptive title tag (50-60 characters) that includes your target keywords.',
478 source: GOOGLE_DOCS.titleTag
479 });
480 } else {
481 const titleLength = titleText.length;
482
483 if (titleLength < 30) {
484 warnings.push({
485 category: 'onPage',
486 severity: 'warning',
487 title: 'Title Tag Too Short',
488 description: `Your title tag is only ${titleLength} characters. Recommended: 50-60 characters.`,
489 recommendation: 'Expand your title to include more descriptive keywords and context.',
490 source: GOOGLE_DOCS.titleTag
491 });
492 } else if (titleLength > 60) {
493 warnings.push({
494 category: 'onPage',
495 severity: 'warning',
496 title: 'Title Tag Too Long',
497 description: `Your title tag is ${titleLength} characters. It may be truncated in search results.`,
498 recommendation: 'Shorten your title to 50-60 characters to avoid truncation.',
499 source: GOOGLE_DOCS.titleTag
500 });
501 } else {
502 passed.push({
503 category: 'onPage',
504 title: 'Title Tag Length',
505 description: `Title tag is ${titleLength} characters - optimal length.`,
506 source: GOOGLE_DOCS.titleTag
507 });
508 }
509 }
510
511 // Meta Description Analysis
512 const metaDesc = document.querySelector('meta[name="description"]');
513 if (!metaDesc || !metaDesc.content.trim()) {
514 issues.push({
515 category: 'onPage',
516 severity: 'high',
517 title: 'Missing Meta Description',
518 description: 'Your page is missing a meta description. This affects click-through rates.',
519 recommendation: 'Add a compelling meta description (150-160 characters) that summarizes your page content.',
520 source: GOOGLE_DOCS.metaDescription
521 });
522 } else {
523 const descLength = metaDesc.content.trim().length;
524
525 if (descLength >= 120 && descLength <= 160) {
526 passed.push({
527 category: 'onPage',
528 title: 'Meta Description Length',
529 description: `Meta description is ${descLength} characters - optimal length.`,
530 source: GOOGLE_DOCS.metaDescription
531 });
532 } else if (descLength < 120) {
533 warnings.push({
534 category: 'onPage',
535 severity: 'warning',
536 title: 'Meta Description Too Short',
537 description: `Your meta description is only ${descLength} characters. Recommended: 150-160 characters.`,
538 recommendation: 'Expand your meta description to provide more context and improve CTR.',
539 source: GOOGLE_DOCS.metaDescription
540 });
541 } else {
542 warnings.push({
543 category: 'onPage',
544 severity: 'warning',
545 title: 'Meta Description Too Long',
546 description: `Your meta description is ${descLength} characters. It may be truncated in search results.`,
547 recommendation: 'Shorten your meta description to 150-160 characters.',
548 source: GOOGLE_DOCS.metaDescription
549 });
550 }
551 }
552
553 // H1 Tag Analysis
554 const h1Tags = document.querySelectorAll('h1');
555 if (h1Tags.length === 0) {
556 issues.push({
557 category: 'onPage',
558 severity: 'high',
559 title: 'Missing H1 Tag',
560 description: 'Your page has no H1 heading. This is important for SEO and accessibility.',
561 recommendation: 'Add a single, descriptive H1 tag that clearly describes the page content.',
562 source: GOOGLE_DOCS.headings
563 });
564 } else if (h1Tags.length > 1) {
565 warnings.push({
566 category: 'onPage',
567 severity: 'warning',
568 title: 'Multiple H1 Tags',
569 description: `Your page has ${h1Tags.length} H1 tags. Best practice is to use only one H1 per page.`,
570 recommendation: 'Use only one H1 tag for the main heading, and use H2-H6 for subheadings.',
571 source: GOOGLE_DOCS.headings
572 });
573 } else {
574 passed.push({
575 category: 'onPage',
576 title: 'H1 Tag Present',
577 description: 'Page has a single, descriptive H1 tag.',
578 source: GOOGLE_DOCS.headings
579 });
580 }
581
582 // Canonical Tag Analysis
583 const canonical = document.querySelector('link[rel="canonical"]');
584 if (!canonical) {
585 warnings.push({
586 category: 'onPage',
587 severity: 'warning',
588 title: 'Missing Canonical Tag',
589 description: 'This page doesn\'t have a canonical tag.',
590 recommendation: 'Add a canonical tag to prevent duplicate content issues.',
591 source: GOOGLE_DOCS.canonical
592 });
593 } else {
594 passed.push({
595 category: 'onPage',
596 title: 'Canonical Tag',
597 description: 'Canonical tag is present.',
598 source: GOOGLE_DOCS.canonical
599 });
600 }
601
602 // Open Graph Tags Analysis
603 const ogTitle = document.querySelector('meta[property="og:title"]');
604 const ogDescription = document.querySelector('meta[property="og:description"]');
605 const ogImage = document.querySelector('meta[property="og:image"]');
606
607 if (!ogTitle || !ogDescription || !ogImage) {
608 warnings.push({
609 category: 'onPage',
610 severity: 'warning',
611 title: 'Incomplete Open Graph Tags',
612 description: 'Missing some Open Graph tags for social media sharing.',
613 recommendation: 'Add og:title, og:description, and og:image for better social media appearance.',
614 source: GOOGLE_DOCS.openGraph
615 });
616 } else {
617 passed.push({
618 category: 'onPage',
619 title: 'Open Graph Tags',
620 description: 'Complete Open Graph tags present for social sharing.',
621 source: GOOGLE_DOCS.openGraph
622 });
623 }
624
625 return { issues, warnings, passed };
626 }
627
628 // ===== ENHANCED MOBILE-FIRST ANALYSIS =====
629 function analyzeMobileFirst() {
630 console.log('📱 Starting Enhanced Mobile-First Analysis...');
631 const issues = [];
632 const warnings = [];
633 const passed = [];
634
635 // Viewport Meta Tag
636 const viewport = document.querySelector('meta[name="viewport"]');
637 if (!viewport) {
638 issues.push({
639 category: 'mobile',
640 severity: 'critical',
641 title: 'Missing Viewport Meta Tag',
642 description: 'Page is missing viewport meta tag - critical for mobile.',
643 recommendation: 'Add: <meta name="viewport" content="width=device-width, initial-scale=1">',
644 source: GOOGLE_DOCS.viewport
645 });
646 } else {
647 const content = viewport.content.toLowerCase();
648 if (content.includes('width=device-width')) {
649 passed.push({
650 category: 'mobile',
651 title: 'Mobile Viewport Configured',
652 description: 'Viewport is properly configured for mobile devices.',
653 source: GOOGLE_DOCS.viewport
654 });
655 }
656 }
657
658 // Touch Target Sizes
659 const clickableElements = document.querySelectorAll('a, button, input[type="button"], input[type="submit"], [role="button"]');
660 let smallTouchTargets = 0;
661
662 clickableElements.forEach(el => {
663 const rect = el.getBoundingClientRect();
664 const size = Math.min(rect.width, rect.height);
665 if (size > 0 && size < 44) {
666 smallTouchTargets++;
667 }
668 });
669
670 if (smallTouchTargets > 0) {
671 warnings.push({
672 category: 'mobile',
673 severity: 'warning',
674 title: 'Small Touch Targets',
675 description: `Found ${smallTouchTargets} touch targets smaller than 44x44px.`,
676 recommendation: 'Increase size of buttons and links to at least 44x44px for better mobile usability.',
677 source: GOOGLE_DOCS.mobileFirst
678 });
679 } else if (clickableElements.length > 0) {
680 passed.push({
681 category: 'mobile',
682 title: 'Touch Target Sizes',
683 description: 'All touch targets are adequately sized for mobile.',
684 source: GOOGLE_DOCS.mobileFirst
685 });
686 }
687
688 // Font Size Analysis
689 const bodyFontSize = window.getComputedStyle(document.body).fontSize;
690 const fontSize = parseInt(bodyFontSize);
691
692 if (fontSize < 16) {
693 warnings.push({
694 category: 'mobile',
695 severity: 'warning',
696 title: 'Small Font Size',
697 description: `Body font size is ${fontSize}px. Recommended: 16px or larger for mobile readability.`,
698 recommendation: 'Increase base font size to at least 16px for better mobile readability.',
699 source: GOOGLE_DOCS.mobileFirst
700 });
701 } else {
702 passed.push({
703 category: 'mobile',
704 title: 'Font Size',
705 description: `Font size is ${fontSize}px - good for mobile readability.`,
706 source: GOOGLE_DOCS.mobileFirst
707 });
708 }
709
710 return { issues, warnings, passed };
711 }
712
713 // ===== ENHANCED SECURITY ANALYSIS =====
714 function analyzeSecurity() {
715 console.log('🔒 Starting Enhanced Security Analysis...');
716 const issues = [];
717 const warnings = [];
718 const passed = [];
719
720 // HTTPS Check
721 if (window.location.protocol !== 'https:') {
722 issues.push({
723 category: 'security',
724 severity: 'critical',
725 title: 'Not Using HTTPS',
726 description: 'Site is not using HTTPS - major security and SEO issue.',
727 recommendation: 'Install SSL certificate immediately and redirect all HTTP traffic to HTTPS.',
728 source: GOOGLE_DOCS.https
729 });
730 } else {
731 passed.push({
732 category: 'security',
733 title: 'HTTPS Enabled',
734 description: 'Site is using secure HTTPS protocol.',
735 source: GOOGLE_DOCS.https
736 });
737 }
738
739 // Mixed Content Check
740 const httpResources = [];
741 document.querySelectorAll('img[src^="http:"], script[src^="http:"], link[href^="http:"], iframe[src^="http:"]').forEach(el => {
742 httpResources.push(el.src || el.href);
743 });
744
745 if (httpResources.length > 0) {
746 issues.push({
747 category: 'security',
748 severity: 'high',
749 title: 'Mixed Content Detected',
750 description: `Found ${httpResources.length} insecure resources loaded over HTTP.`,
751 recommendation: 'Update all resource URLs to HTTPS to prevent security warnings.',
752 source: GOOGLE_DOCS.https
753 });
754 } else if (window.location.protocol === 'https:') {
755 passed.push({
756 category: 'security',
757 title: 'No Mixed Content',
758 description: 'All resources are loaded securely over HTTPS.',
759 source: GOOGLE_DOCS.https
760 });
761 }
762
763 return { issues, warnings, passed };
764 }
765
766 // ===== ENHANCED STRUCTURED DATA ANALYSIS =====
767 function analyzeStructuredData() {
768 console.log('🏗️ Starting Enhanced Structured Data Analysis...');
769 const issues = [];
770 const warnings = [];
771 const passed = [];
772
773 const jsonLdScripts = document.querySelectorAll('script[type="application/ld+json"]');
774 const foundSchemas = [];
775 let hasErrors = false;
776
777 if (jsonLdScripts.length === 0) {
778 warnings.push({
779 category: 'structure',
780 severity: 'warning',
781 title: 'No Structured Data Found',
782 description: 'Page doesn\'t have any JSON-LD structured data.',
783 recommendation: 'Add structured data (Schema.org) to help search engines understand your content better.',
784 source: GOOGLE_DOCS.structuredData
785 });
786 } else {
787 jsonLdScripts.forEach(script => {
788 try {
789 const data = JSON.parse(script.textContent);
790 const type = data['@type'] || (data['@graph'] && data['@graph'][0] && data['@graph'][0]['@type']);
791 if (type) {
792 foundSchemas.push(type);
793 }
794 } catch {
795 hasErrors = true;
796 warnings.push({
797 category: 'structure',
798 severity: 'warning',
799 title: 'Invalid JSON-LD',
800 description: 'Found JSON-LD script with invalid JSON syntax.',
801 recommendation: 'Fix JSON syntax errors in structured data.',
802 source: GOOGLE_DOCS.richResults
803 });
804 }
805 });
806
807 if (foundSchemas.length > 0 && !hasErrors) {
808 passed.push({
809 category: 'structure',
810 title: 'Structured Data Present',
811 description: `Found structured data: ${[...new Set(foundSchemas)].join(', ')}`,
812 source: GOOGLE_DOCS.structuredData
813 });
814 }
815 }
816
817 return { issues, warnings, passed };
818 }
819
820 // ===== ENHANCED TECHNICAL SEO ANALYSIS =====
821 function analyzeTechnicalSEO() {
822 console.log('🔧 Starting Enhanced Technical SEO Analysis...');
823 const issues = [];
824 const warnings = [];
825 const passed = [];
826
827 // Viewport Meta Tag
828 const viewport = document.querySelector('meta[name="viewport"]');
829 if (!viewport) {
830 issues.push({
831 category: 'technical',
832 severity: 'high',
833 title: 'Missing Viewport Meta Tag',
834 description: 'Page is missing viewport meta tag. This affects mobile usability.',
835 recommendation: 'Add: <meta name="viewport" content="width=device-width, initial-scale=1">',
836 source: GOOGLE_DOCS.viewport
837 });
838 } else {
839 passed.push({
840 category: 'technical',
841 title: 'Viewport Meta Tag',
842 description: 'Viewport meta tag is properly configured.',
843 source: GOOGLE_DOCS.viewport
844 });
845 }
846
847 // Language Declaration
848 const htmlLang = document.documentElement.lang;
849 if (!htmlLang) {
850 warnings.push({
851 category: 'technical',
852 severity: 'warning',
853 title: 'Missing Language Declaration',
854 description: 'HTML tag is missing lang attribute.',
855 recommendation: 'Add lang attribute to <html> tag (e.g., lang="he" for Hebrew, lang="en" for English).',
856 source: 'https://developers.google.com/search/docs/specialty/international/localized-versions'
857 });
858 } else {
859 passed.push({
860 category: 'technical',
861 title: 'Language Declaration',
862 description: `Page language is declared as: ${htmlLang}`,
863 source: 'https://developers.google.com/search/docs/specialty/international/localized-versions'
864 });
865 }
866
867 // Charset Declaration
868 const charset = document.querySelector('meta[charset]');
869 if (!charset) {
870 warnings.push({
871 category: 'technical',
872 severity: 'warning',
873 title: 'Missing Charset Declaration',
874 description: 'Page is missing charset meta tag.',
875 recommendation: 'Add: <meta charset="UTF-8"> in the <head> section.',
876 source: 'https://developers.google.com/search/docs/crawling-indexing/valid-page-metadata'
877 });
878 } else {
879 passed.push({
880 category: 'technical',
881 title: 'Charset Declaration',
882 description: 'Character encoding is properly set to UTF-8.',
883 source: 'https://developers.google.com/search/docs/crawling-indexing/valid-page-metadata'
884 });
885 }
886
887 // DOCTYPE Check
888 const doctype = document.doctype;
889 if (!doctype) {
890 warnings.push({
891 category: 'technical',
892 severity: 'warning',
893 title: 'Missing DOCTYPE',
894 description: 'Page is missing DOCTYPE declaration.',
895 recommendation: 'Add <!DOCTYPE html> at the beginning of your HTML document.',
896 source: 'https://developers.google.com/search/docs/crawling-indexing/valid-page-metadata'
897 });
898 } else {
899 passed.push({
900 category: 'technical',
901 title: 'DOCTYPE Declaration',
902 description: 'DOCTYPE is properly declared.',
903 source: 'https://developers.google.com/search/docs/crawling-indexing/valid-page-metadata'
904 });
905 }
906
907 return { issues, warnings, passed };
908 }
909
910 // ===== ENHANCED CONTENT QUALITY ANALYSIS =====
911 function analyzeContentQuality() {
912 console.log('📝 Starting Enhanced Content Quality Analysis...');
913 const issues = [];
914 const warnings = [];
915 const passed = [];
916
917 const mainContent = document.querySelector('main, article, [role="main"], .content, #content') || document.body;
918 const textContent = mainContent.textContent.trim();
919 const wordCount = textContent.split(/\s+/).filter(word => word.length > 0).length;
920
921 // Word Count Analysis
922 if (wordCount < 300) {
923 issues.push({
924 category: 'content',
925 severity: 'high',
926 title: 'Thin Content',
927 description: `Page has only ${wordCount} words. This is considered thin content.`,
928 recommendation: 'Add more comprehensive, valuable content. Aim for at least 300-500 words.',
929 source: 'https://developers.google.com/search/docs/fundamentals/creating-helpful-content'
930 });
931 } else if (wordCount < 500) {
932 warnings.push({
933 category: 'content',
934 severity: 'warning',
935 title: 'Low Word Count',
936 description: `Page has ${wordCount} words. Consider adding more content.`,
937 recommendation: 'Expand your content to provide more value and context. Aim for 500+ words.',
938 source: 'https://developers.google.com/search/docs/fundamentals/creating-helpful-content'
939 });
940 } else {
941 passed.push({
942 category: 'content',
943 title: 'Sufficient Content Length',
944 description: `Page has ${wordCount} words - good content depth.`,
945 source: 'https://developers.google.com/search/docs/fundamentals/creating-helpful-content'
946 });
947 }
948
949 // Heading Structure Analysis
950 const headings = {
951 h1: document.querySelectorAll('h1').length,
952 h2: document.querySelectorAll('h2').length,
953 h3: document.querySelectorAll('h3').length,
954 h4: document.querySelectorAll('h4').length,
955 h5: document.querySelectorAll('h5').length,
956 h6: document.querySelectorAll('h6').length
957 };
958
959 const totalHeadings = Object.values(headings).reduce((a, b) => a + b, 0);
960
961 if (totalHeadings === 0) {
962 warnings.push({
963 category: 'content',
964 severity: 'warning',
965 title: 'No Heading Structure',
966 description: 'Page has no heading tags (H1-H6).',
967 recommendation: 'Add proper heading structure to organize your content and improve SEO.',
968 source: GOOGLE_DOCS.headings
969 });
970 } else if (headings.h2 === 0 && wordCount > 300) {
971 warnings.push({
972 category: 'content',
973 severity: 'warning',
974 title: 'Missing H2 Headings',
975 description: 'Page has no H2 headings to structure content.',
976 recommendation: 'Add H2 headings to break up content and improve readability.',
977 source: GOOGLE_DOCS.headings
978 });
979 } else {
980 passed.push({
981 category: 'content',
982 title: 'Heading Structure',
983 description: `Page has proper heading structure with ${totalHeadings} headings.`,
984 source: GOOGLE_DOCS.headings
985 });
986 }
987
988 return { issues, warnings, passed };
989 }
990
991 // ===== ENHANCED IMAGE OPTIMIZATION ANALYSIS =====
992 function analyzeImageOptimization() {
993 console.log('🖼️ Starting Enhanced Image Optimization Analysis...');
994 const issues = [];
995 const warnings = [];
996 const passed = [];
997
998 const images = document.querySelectorAll('img');
999 let imagesWithoutAlt = 0;
1000 let modernFormats = 0;
1001 let lazyLoadedImages = 0;
1002
1003 images.forEach(img => {
1004 // Alt text check
1005 if (!img.hasAttribute('alt')) {
1006 imagesWithoutAlt++;
1007 }
1008
1009 // Modern format check (WebP, AVIF)
1010 const src = img.src || img.dataset.src || '';
1011 if (src.includes('.webp') || src.includes('.avif')) {
1012 modernFormats++;
1013 }
1014
1015 // Lazy loading check
1016 if (img.loading === 'lazy' || img.dataset.src) {
1017 lazyLoadedImages++;
1018 }
1019 });
1020
1021 // Alt Text Analysis
1022 if (images.length > 0) {
1023 if (imagesWithoutAlt > 0) {
1024 warnings.push({
1025 category: 'images',
1026 severity: 'warning',
1027 title: 'Images Missing Alt Text',
1028 description: `${imagesWithoutAlt} out of ${images.length} images are missing alt text.`,
1029 recommendation: 'Add descriptive alt text to all images for SEO and accessibility.',
1030 source: GOOGLE_DOCS.imageAlt
1031 });
1032 } else {
1033 passed.push({
1034 category: 'images',
1035 title: 'All Images Have Alt Text',
1036 description: `All ${images.length} images have proper alt text.`,
1037 source: GOOGLE_DOCS.imageAlt
1038 });
1039 }
1040
1041 // Modern Format Analysis
1042 if (modernFormats === 0 && images.length > 0) {
1043 warnings.push({
1044 category: 'images',
1045 severity: 'warning',
1046 title: 'No Modern Image Formats',
1047 description: 'No images using modern formats (WebP, AVIF).',
1048 recommendation: 'Convert images to WebP or AVIF for better compression and faster loading.',
1049 source: 'https://web.dev/uses-webp-images/'
1050 });
1051 } else if (modernFormats > 0) {
1052 passed.push({
1053 category: 'images',
1054 title: 'Modern Image Formats',
1055 description: `${modernFormats} images using modern formats (WebP/AVIF).`,
1056 source: 'https://web.dev/uses-webp-images/'
1057 });
1058 }
1059
1060 // Lazy Loading Analysis
1061 if (lazyLoadedImages === 0 && images.length > 5) {
1062 warnings.push({
1063 category: 'images',
1064 severity: 'warning',
1065 title: 'No Lazy Loading',
1066 description: 'Images are not using lazy loading.',
1067 recommendation: 'Add loading="lazy" attribute to images below the fold to improve page speed.',
1068 source: 'https://web.dev/browser-level-image-lazy-loading/'
1069 });
1070 } else if (lazyLoadedImages > 0) {
1071 passed.push({
1072 category: 'images',
1073 title: 'Lazy Loading Enabled',
1074 description: `${lazyLoadedImages} images using lazy loading.`,
1075 source: 'https://web.dev/browser-level-image-lazy-loading/'
1076 });
1077 }
1078 }
1079
1080 return { issues, warnings, passed };
1081 }
1082
1083 // ===== ENHANCED ROBOTS & SITEMAP ANALYSIS =====
1084 async function analyzeRobotsAndSitemap() {
1085 console.log('🤖 Starting Enhanced Robots.txt & Sitemap Analysis...');
1086 const issues = [];
1087 const warnings = [];
1088 const passed = [];
1089
1090 // Robots.txt Check
1091 try {
1092 const robotsUrl = `${window.location.origin}/robots.txt`;
1093 const robotsResponse = await GM.xmlhttpRequest({
1094 method: 'GET',
1095 url: robotsUrl,
1096 timeout: 5000
1097 });
1098
1099 if (robotsResponse.status === 200) {
1100 passed.push({
1101 category: 'crawlability',
1102 title: 'Robots.txt Found',
1103 description: 'Site has a robots.txt file.',
1104 source: GOOGLE_DOCS.robotsTxt
1105 });
1106
1107 // Check for sitemap reference in robots.txt
1108 if (robotsResponse.responseText.toLowerCase().includes('sitemap:')) {
1109 passed.push({
1110 category: 'crawlability',
1111 title: 'Sitemap in Robots.txt',
1112 description: 'Robots.txt references sitemap location.',
1113 source: GOOGLE_DOCS.robotsTxt
1114 });
1115 }
1116 } else {
1117 warnings.push({
1118 category: 'crawlability',
1119 severity: 'warning',
1120 title: 'No Robots.txt File',
1121 description: 'Site doesn\'t have a robots.txt file.',
1122 recommendation: 'Create a robots.txt file to guide search engine crawlers.',
1123 source: GOOGLE_DOCS.robotsTxt
1124 });
1125 }
1126 } catch {
1127 warnings.push({
1128 category: 'crawlability',
1129 severity: 'warning',
1130 title: 'Could Not Check Robots.txt',
1131 description: 'Unable to verify robots.txt file.',
1132 recommendation: 'Manually verify that robots.txt exists and is accessible.',
1133 source: GOOGLE_DOCS.robotsTxt
1134 });
1135 }
1136
1137 // Sitemap.xml Check
1138 try {
1139 const sitemapUrl = `${window.location.origin}/sitemap.xml`;
1140 const sitemapResponse = await GM.xmlhttpRequest({
1141 method: 'GET',
1142 url: sitemapUrl,
1143 timeout: 5000
1144 });
1145
1146 if (sitemapResponse.status === 200) {
1147 passed.push({
1148 category: 'crawlability',
1149 title: 'Sitemap.xml Found',
1150 description: 'Site has a sitemap.xml file.',
1151 source: GOOGLE_DOCS.sitemap
1152 });
1153 } else {
1154 warnings.push({
1155 category: 'crawlability',
1156 severity: 'warning',
1157 title: 'No Sitemap.xml File',
1158 description: 'Site doesn\'t have a sitemap.xml file.',
1159 recommendation: 'Create an XML sitemap to help search engines discover your pages.',
1160 source: GOOGLE_DOCS.sitemap
1161 });
1162 }
1163 } catch {
1164 warnings.push({
1165 category: 'crawlability',
1166 severity: 'warning',
1167 title: 'Could Not Check Sitemap',
1168 description: 'Unable to verify sitemap.xml file.',
1169 recommendation: 'Manually verify that sitemap.xml exists and is accessible.',
1170 source: GOOGLE_DOCS.sitemap
1171 });
1172 }
1173
1174 return { issues, warnings, passed };
1175 }
1176
1177 // ===== ENHANCED URL STRUCTURE ANALYSIS =====
1178 function analyzeURLStructure() {
1179 console.log('🔗 Starting Enhanced URL Structure Analysis...');
1180 const issues = [];
1181 const warnings = [];
1182 const passed = [];
1183
1184 const currentUrl = window.location.href;
1185 const pathname = window.location.pathname;
1186
1187 // URL Length Check
1188 if (currentUrl.length > 100) {
1189 warnings.push({
1190 category: 'structure',
1191 severity: 'warning',
1192 title: 'Long URL',
1193 description: `URL is ${currentUrl.length} characters long. Shorter URLs are better for SEO.`,
1194 recommendation: 'Keep URLs under 100 characters when possible.',
1195 source: 'https://developers.google.com/search/docs/crawling-indexing/url-structure'
1196 });
1197 } else {
1198 passed.push({
1199 category: 'structure',
1200 title: 'URL Length',
1201 description: `URL is ${currentUrl.length} characters - good length.`,
1202 source: 'https://developers.google.com/search/docs/crawling-indexing/url-structure'
1203 });
1204 }
1205
1206 // Underscore Check
1207 if (pathname.includes('_')) {
1208 warnings.push({
1209 category: 'structure',
1210 severity: 'warning',
1211 title: 'Underscores in URL',
1212 description: 'URL uses underscores (_) instead of hyphens (-).',
1213 recommendation: 'Use hyphens (-) instead of underscores in URLs.',
1214 source: 'https://developers.google.com/search/docs/crawling-indexing/url-structure'
1215 });
1216 }
1217
1218 // Lowercase Check
1219 if (pathname !== pathname.toLowerCase()) {
1220 warnings.push({
1221 category: 'structure',
1222 severity: 'warning',
1223 title: 'Uppercase Letters in URL',
1224 description: 'URL contains uppercase letters.',
1225 recommendation: 'Use lowercase letters consistently in URLs.',
1226 source: 'https://developers.google.com/search/docs/crawling-indexing/url-structure'
1227 });
1228 } else {
1229 passed.push({
1230 category: 'structure',
1231 title: 'Lowercase URL',
1232 description: 'URL uses lowercase letters consistently.',
1233 source: 'https://developers.google.com/search/docs/crawling-indexing/url-structure'
1234 });
1235 }
1236
1237 // URL Parameters Check
1238 const urlParams = new URLSearchParams(window.location.search);
1239 const paramCount = Array.from(urlParams).length;
1240
1241 if (paramCount > 3) {
1242 warnings.push({
1243 category: 'structure',
1244 severity: 'warning',
1245 title: 'Too Many URL Parameters',
1246 description: `URL has ${paramCount} parameters. This can affect crawlability.`,
1247 recommendation: 'Minimize URL parameters or use URL rewriting for cleaner URLs.',
1248 source: 'https://developers.google.com/search/docs/crawling-indexing/url-structure'
1249 });
1250 }
1251
1252 return { issues, warnings, passed };
1253 }
1254
1255 // ===== AI RECOMMENDATIONS WITH CACHING =====
1256 async function generateAIRecommendations() {
1257 console.log('🤖 Generating AI-Powered Recommendations...');
1258
1259 try {
1260 // Check cache first
1261 const cacheKey = `ai_recommendations_${window.location.hostname}`;
1262 const cachedData = await GM.getValue(cacheKey);
1263
1264 if (cachedData) {
1265 const cached = JSON.parse(cachedData);
1266 const cacheAge = Date.now() - cached.timestamp;
1267
1268 if (cacheAge < CONFIG.cacheExpiry) {
1269 console.log('✅ Using cached AI recommendations');
1270 auditResults.aiRecommendations = cached.recommendations;
1271 return;
1272 }
1273 }
1274
1275 const summary = {
1276 url: auditResults.url,
1277 overallScore: auditResults.scores.overall,
1278 criticalIssues: auditResults.issues.length,
1279 warnings: auditResults.warnings.length,
1280 topIssues: auditResults.issues.slice(0, 5).map(i => i.title),
1281 topWarnings: auditResults.warnings.slice(0, 5).map(w => w.title),
1282 coreWebVitals: auditResults.coreWebVitals
1283 };
1284
1285 const prompt = `You are an SEO expert. Analyze this website audit and provide 3-5 prioritized, actionable recommendations based on Google's official SEO guidelines:
1286
1287Audit Summary:
1288- URL: ${summary.url}
1289- Overall Score: ${summary.overallScore}/100
1290- Critical Issues: ${summary.criticalIssues}
1291- Warnings: ${summary.warnings}
1292- Top Issues: ${summary.topIssues.join(', ')}
1293- Core Web Vitals: LCP=${summary.coreWebVitals.lcp}ms, INP=${summary.coreWebVitals.inp}ms, CLS=${summary.coreWebVitals.cls}
1294
1295Provide specific, prioritized recommendations focusing on quick wins and high-impact improvements according to Google Search Central guidelines.`;
1296
1297 const aiResponse = await RM.aiCall(prompt, {
1298 type: 'json_schema',
1299 json_schema: {
1300 name: 'seo_recommendations',
1301 schema: {
1302 type: 'object',
1303 properties: {
1304 recommendations: {
1305 type: 'array',
1306 items: {
1307 type: 'object',
1308 properties: {
1309 priority: { type: 'string', enum: ['high', 'medium', 'low'] },
1310 title: { type: 'string' },
1311 description: { type: 'string' },
1312 impact: { type: 'string' },
1313 effort: { type: 'string', enum: ['low', 'medium', 'high'] }
1314 },
1315 required: ['priority', 'title', 'description', 'impact', 'effort']
1316 }
1317 }
1318 },
1319 required: ['recommendations']
1320 }
1321 }
1322 });
1323
1324 auditResults.aiRecommendations = aiResponse.recommendations || [];
1325
1326 // Cache the results
1327 await GM.setValue(cacheKey, JSON.stringify({
1328 timestamp: Date.now(),
1329 recommendations: auditResults.aiRecommendations
1330 }));
1331
1332 console.log('✅ AI Recommendations generated and cached:', auditResults.aiRecommendations);
1333
1334 } catch {
1335 console.log('Error generating AI recommendations');
1336 auditResults.aiRecommendations = [];
1337 }
1338 }
1339
1340 // ===== MAIN AUDIT FUNCTION WITH PROGRESS TRACKING =====
1341 async function runFullAudit(progressCallback) {
1342 console.log('🚀 Starting Full SEO Audit...');
1343 auditResults.timestamp = new Date().toISOString();
1344 auditResults.issues = [];
1345 auditResults.warnings = [];
1346 auditResults.passed = [];
1347
1348 const modules = [
1349 { name: 'Core Web Vitals', fn: analyzeCoreWebVitals },
1350 { name: 'On-Page SEO', fn: analyzeOnPageSEO },
1351 { name: 'Mobile-First', fn: analyzeMobileFirst },
1352 { name: 'Security', fn: analyzeSecurity },
1353 { name: 'Structured Data', fn: analyzeStructuredData },
1354 { name: 'Technical SEO', fn: analyzeTechnicalSEO },
1355 { name: 'Content Quality', fn: analyzeContentQuality },
1356 { name: 'Image Optimization', fn: analyzeImageOptimization },
1357 { name: 'Robots & Sitemap', fn: analyzeRobotsAndSitemap },
1358 { name: 'URL Structure', fn: analyzeURLStructure }
1359 ];
1360
1361 const results = [];
1362
1363 for (let i = 0; i < modules.length; i++) {
1364 const module = modules[i];
1365 if (progressCallback) {
1366 progressCallback(module.name, (i / modules.length) * 100);
1367 }
1368
1369 try {
1370 const result = await module.fn();
1371 results.push(result);
1372 } catch {
1373 console.log(`Error in ${module.name}`);
1374 }
1375 }
1376
1377 // Combine all results
1378 results.forEach(result => {
1379 auditResults.issues.push(...result.issues);
1380 auditResults.warnings.push(...result.warnings);
1381 auditResults.passed.push(...result.passed);
1382 });
1383
1384 // Calculate scores by category
1385 const categories = Object.keys(CONFIG.categories);
1386 categories.forEach(category => {
1387 const categoryIssues = auditResults.issues.filter(i => i.category === category);
1388 const categoryWarnings = auditResults.warnings.filter(w => w.category === category);
1389 const categoryPassed = auditResults.passed.filter(p => p.category === category);
1390
1391 const total = categoryIssues.length + categoryWarnings.length + categoryPassed.length;
1392 const passed = categoryPassed.length + (categoryWarnings.length * 0.5);
1393
1394 auditResults.scores[category] = calculateScore(passed, total);
1395 });
1396
1397 // Calculate overall score
1398 let overallScore = 0;
1399 let totalWeight = 0;
1400 Object.keys(CONFIG.categories).forEach(category => {
1401 const weight = CONFIG.categories[category].weight;
1402 const score = auditResults.scores[category] || 0;
1403 overallScore += score * weight;
1404 totalWeight += weight;
1405 });
1406 auditResults.scores.overall = Math.round(overallScore / totalWeight);
1407
1408 // Generate AI recommendations
1409 if (progressCallback) {
1410 progressCallback('AI Recommendations', 95);
1411 }
1412 await generateAIRecommendations();
1413
1414 if (progressCallback) {
1415 progressCallback('Complete', 100);
1416 }
1417
1418 console.log('✅ SEO Audit Complete!', auditResults);
1419 return auditResults;
1420 }
1421
1422 // ===== PREMIUM UI CREATION =====
1423 function createAuditUI() {
1424 const existingPanel = document.getElementById('seo-audit-panel');
1425 if (existingPanel) {
1426 existingPanel.remove();
1427 }
1428
1429 const panel = document.createElement('div');
1430 panel.id = 'seo-audit-panel';
1431 panel.innerHTML = `
1432 <div class="seo-audit-header">
1433 <div class="seo-audit-title">
1434 <span class="seo-audit-icon">🔍</span>
1435 <div class="seo-audit-title-text">
1436 <div>${t('title')}</div>
1437 <div class="seo-audit-subtitle">${t('subtitle')}</div>
1438 </div>
1439 </div>
1440 <div class="seo-audit-actions">
1441 <button id="seo-audit-minimize" class="seo-audit-btn-icon" title="Minimize">−</button>
1442 <button id="seo-audit-close" class="seo-audit-btn-icon" title="Close">×</button>
1443 </div>
1444 </div>
1445 <div class="seo-audit-content">
1446 <div class="seo-audit-loading">
1447 <div class="seo-audit-spinner"></div>
1448 <p class="seo-audit-loading-text">${t('runningAudit')}</p>
1449 <p class="seo-audit-loading-detail">${t('analyzingDetails')}</p>
1450 <div class="seo-audit-progress-bar">
1451 <div class="seo-audit-progress-fill" id="seo-audit-progress"></div>
1452 </div>
1453 <p class="seo-audit-progress-text" id="seo-audit-progress-text">${t('analyzing')}...</p>
1454 </div>
1455 </div>
1456 `;
1457
1458 document.body.appendChild(panel);
1459
1460 document.getElementById('seo-audit-close').addEventListener('click', () => {
1461 panel.classList.add('seo-audit-closing');
1462 setTimeout(() => panel.remove(), 300);
1463 });
1464
1465 document.getElementById('seo-audit-minimize').addEventListener('click', () => {
1466 panel.classList.toggle('minimized');
1467 });
1468
1469 makeDraggable(panel);
1470
1471 return panel;
1472 }
1473
1474 function makeDraggable(element) {
1475 const header = element.querySelector('.seo-audit-header');
1476 let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
1477
1478 header.onmousedown = dragMouseDown;
1479
1480 function dragMouseDown(e) {
1481 if (e.target.closest('.seo-audit-btn-icon')) return;
1482 e.preventDefault();
1483 pos3 = e.clientX;
1484 pos4 = e.clientY;
1485 document.onmouseup = closeDragElement;
1486 document.onmousemove = elementDrag;
1487 }
1488
1489 function elementDrag(e) {
1490 e.preventDefault();
1491 pos1 = pos3 - e.clientX;
1492 pos2 = pos4 - e.clientY;
1493 pos3 = e.clientX;
1494 pos4 = e.clientY;
1495 element.style.top = (element.offsetTop - pos2) + 'px';
1496 element.style.left = (element.offsetLeft - pos1) + 'px';
1497 element.style.right = 'auto';
1498 element.style.bottom = 'auto';
1499 }
1500
1501 function closeDragElement() {
1502 document.onmouseup = null;
1503 document.onmousemove = null;
1504 }
1505 }
1506
1507 function displayResults(results) {
1508 const panel = document.getElementById('seo-audit-panel');
1509 if (!panel) return;
1510
1511 const content = panel.querySelector('.seo-audit-content');
1512 const overallScore = results.scores.overall;
1513 const scoreColor = getScoreColor(overallScore);
1514 const scoreLabel = getScoreLabel(overallScore);
1515
1516 // Core Web Vitals Section with Enhanced Design
1517 const cwvSection = results.coreWebVitals && Object.keys(results.coreWebVitals).length > 0 ? `
1518 <div class="seo-audit-cwv-section">
1519 <h3 class="seo-audit-section-title">
1520 ⚡ ${t('coreWebVitals')}
1521 <span class="seo-audit-section-tooltip" data-tooltip="${t('coreWebVitalsTooltip')}">?</span>
1522 <a href="${GOOGLE_DOCS.coreWebVitals}" target="_blank" class="seo-audit-docs-link" title="${t('googleDocs')}">📖</a>
1523 </h3>
1524 <div class="seo-audit-cwv-grid">
1525 ${Object.keys(CONFIG.coreWebVitals).map(metric => {
1526 const value = results.coreWebVitals[metric];
1527 if (!value) return '';
1528 const status = getCWVStatus(value, metric);
1529 const color = getCWVColor(status);
1530 const config = CONFIG.coreWebVitals[metric];
1531 return `
1532 <div class="seo-audit-cwv-item" style="border-color: ${color}">
1533 <div class="seo-audit-cwv-label">${config.name}</div>
1534 <div class="seo-audit-cwv-value">${metric === 'cls' ? value : value + 'ms'}</div>
1535 <div class="seo-audit-cwv-status" style="color: ${color}">${t(status)}</div>
1536 <div class="seo-audit-cwv-description">${config.description}</div>
1537 </div>
1538 `;
1539 }).join('')}
1540 </div>
1541 </div>
1542 ` : '';
1543
1544 // AI Recommendations Section with Enhanced Design
1545 const aiSection = results.aiRecommendations && results.aiRecommendations.length > 0 ? `
1546 <div class="seo-audit-ai-section">
1547 <h3 class="seo-audit-section-title">
1548 🤖 ${t('aiRecommendations')}
1549 <span class="seo-audit-section-tooltip" data-tooltip="${t('aiRecommendationsTooltip')}">?</span>
1550 </h3>
1551 <div class="seo-audit-ai-recommendations">
1552 ${results.aiRecommendations.map(rec => `
1553 <div class="seo-audit-ai-rec seo-audit-ai-rec-${rec.priority}">
1554 <div class="seo-audit-ai-rec-header">
1555 <span class="seo-audit-ai-rec-priority">${t(rec.priority).toUpperCase()}</span>
1556 <span class="seo-audit-ai-rec-effort">${t('effort')}: ${t(rec.effort)}</span>
1557 </div>
1558 <div class="seo-audit-ai-rec-title">${rec.title}</div>
1559 <div class="seo-audit-ai-rec-description">${rec.description}</div>
1560 <div class="seo-audit-ai-rec-impact"><strong>${t('impact')}:</strong> ${rec.impact}</div>
1561 </div>
1562 `).join('')}
1563 </div>
1564 </div>
1565 ` : '';
1566
1567 // Filter and Search Controls
1568 const controlsSection = `
1569 <div class="seo-audit-controls">
1570 <div class="seo-audit-filter-buttons">
1571 <button class="seo-audit-filter-btn active" data-filter="all">${t('filterAll')}</button>
1572 <button class="seo-audit-filter-btn" data-filter="critical">${t('filterCritical')}</button>
1573 <button class="seo-audit-filter-btn" data-filter="warnings">${t('filterWarnings')}</button>
1574 <button class="seo-audit-filter-btn" data-filter="passed">${t('filterPassed')}</button>
1575 </div>
1576 <div class="seo-audit-search-box">
1577 <input type="text" id="seo-audit-search" placeholder="${t('searchPlaceholder')}" />
1578 <span class="seo-audit-search-icon">🔍</span>
1579 </div>
1580 <div class="seo-audit-expand-controls">
1581 <button id="seo-audit-expand-all" class="seo-audit-expand-btn">${t('expandAll')}</button>
1582 <button id="seo-audit-collapse-all" class="seo-audit-expand-btn">${t('collapseAll')}</button>
1583 </div>
1584 </div>
1585 `;
1586
1587 content.innerHTML = `
1588 <div class="seo-audit-score-section">
1589 <div class="seo-audit-score-circle" style="border-color: ${scoreColor};">
1590 <svg class="seo-audit-score-ring" viewBox="0 0 100 100">
1591 <circle class="seo-audit-score-ring-bg" cx="50" cy="50" r="45"></circle>
1592 <circle class="seo-audit-score-ring-fill" cx="50" cy="50" r="45"
1593 style="stroke: ${scoreColor}; stroke-dashoffset: ${283 - (283 * overallScore) / 100}"></circle>
1594 </svg>
1595 <div class="seo-audit-score-value" style="color: ${scoreColor};">${overallScore}</div>
1596 <div class="seo-audit-score-label">${scoreLabel}</div>
1597 </div>
1598 <div class="seo-audit-summary">
1599 <div class="seo-audit-summary-item critical">
1600 <span class="seo-audit-summary-count">${results.issues.length}</span>
1601 <span class="seo-audit-summary-label">${t('criticalIssues')}</span>
1602 </div>
1603 <div class="seo-audit-summary-item warning">
1604 <span class="seo-audit-summary-count">${results.warnings.length}</span>
1605 <span class="seo-audit-summary-label">${t('warnings')}</span>
1606 </div>
1607 <div class="seo-audit-summary-item passed">
1608 <span class="seo-audit-summary-count">${results.passed.length}</span>
1609 <span class="seo-audit-summary-label">${t('passed')}</span>
1610 </div>
1611 </div>
1612 </div>
1613
1614 ${cwvSection}
1615 ${aiSection}
1616 ${controlsSection}
1617
1618 <div class="seo-audit-categories">
1619 <h3 class="seo-audit-section-title">📊 ${t('categoryScores')}</h3>
1620 ${Object.keys(CONFIG.categories).map(category => {
1621 const score = results.scores[category] || 0;
1622 const color = getScoreColor(score);
1623 const categoryInfo = CONFIG.categories[category];
1624 const categoryIssues = results.issues.filter(i => i.category === category);
1625 const categoryWarnings = results.warnings.filter(w => w.category === category);
1626
1627 return `
1628 <div class="seo-audit-category" data-category="${category}">
1629 <div class="seo-audit-category-header">
1630 <div class="seo-audit-category-info">
1631 <span class="seo-audit-category-icon">${categoryInfo.icon}</span>
1632 <span class="seo-audit-category-name">${t(`categories.${category}.name`)}</span>
1633 <span class="seo-audit-category-tooltip" data-tooltip="${t(`categories.${category}.tooltip`)}">?</span>
1634 <span class="seo-audit-category-details">${categoryIssues.length} ${t('issues')} • ${categoryWarnings.length} ${t('warnings')}</span>
1635 </div>
1636 <div class="seo-audit-category-score" style="color: ${color};">${score}</div>
1637 </div>
1638 <div class="seo-audit-category-bar">
1639 <div class="seo-audit-category-bar-fill" style="width: ${score}%; background: ${categoryInfo.gradient};"></div>
1640 </div>
1641 <div class="seo-audit-category-content" data-category-content="${category}">
1642 ${categoryIssues.length > 0 ? `
1643 <div class="seo-audit-category-section">
1644 <div class="seo-audit-category-section-title">🔴 ${t('criticalIssues')} (${categoryIssues.length})</div>
1645 ${categoryIssues.map(issue => `
1646 <div class="seo-audit-item seo-audit-item-critical" data-item-type="critical">
1647 <div class="seo-audit-item-header">
1648 <span class="seo-audit-item-icon">🔴</span>
1649 <span class="seo-audit-item-title">${issue.title}</span>
1650 </div>
1651 <div class="seo-audit-item-description">${issue.description}</div>
1652 <div class="seo-audit-item-recommendation">
1653 <strong>💡 ${t('recommendation')}:</strong> ${issue.recommendation}
1654 </div>
1655 ${issue.source ? `<div class="seo-audit-item-source">
1656 <a href="${issue.source}" target="_blank" class="seo-audit-source-link">📖 ${t('learnMore')}</a>
1657 </div>` : ''}
1658 </div>
1659 `).join('')}
1660 </div>
1661 ` : ''}
1662
1663 ${categoryWarnings.length > 0 ? `
1664 <div class="seo-audit-category-section">
1665 <div class="seo-audit-category-section-title">🟡 ${t('warnings')} (${categoryWarnings.length})</div>
1666 ${categoryWarnings.map(warning => `
1667 <div class="seo-audit-item seo-audit-item-warning" data-item-type="warning">
1668 <div class="seo-audit-item-header">
1669 <span class="seo-audit-item-icon">🟡</span>
1670 <span class="seo-audit-item-title">${warning.title}</span>
1671 </div>
1672 <div class="seo-audit-item-description">${warning.description}</div>
1673 <div class="seo-audit-item-recommendation">
1674 <strong>💡 ${t('recommendation')}:</strong> ${warning.recommendation}
1675 </div>
1676 ${warning.source ? `<div class="seo-audit-item-source">
1677 <a href="${warning.source}" target="_blank" class="seo-audit-source-link">📖 ${t('learnMore')}</a>
1678 </div>` : ''}
1679 </div>
1680 `).join('')}
1681 </div>
1682 ` : ''}
1683 </div>
1684 </div>
1685 `;
1686 }).join('')}
1687 </div>
1688
1689 <div class="seo-audit-footer">
1690 <button id="seo-audit-rerun" class="seo-audit-btn-primary">🔄 ${t('rerunAudit')}</button>
1691 <button id="seo-audit-export" class="seo-audit-btn-secondary">📥 ${t('exportReport')}</button>
1692 <button id="seo-audit-lang-toggle" class="seo-audit-btn-lang">${t('changeLanguage')}</button>
1693 </div>
1694 `;
1695
1696 // Add event listeners
1697 document.getElementById('seo-audit-rerun').addEventListener('click', async () => {
1698 content.innerHTML = `
1699 <div class="seo-audit-loading">
1700 <div class="seo-audit-spinner"></div>
1701 <p class="seo-audit-loading-text">${t('runningAudit')}</p>
1702 <p class="seo-audit-loading-detail">${t('analyzingDetails')}</p>
1703 <div class="seo-audit-progress-bar">
1704 <div class="seo-audit-progress-fill" id="seo-audit-progress"></div>
1705 </div>
1706 <p class="seo-audit-progress-text" id="seo-audit-progress-text">${t('analyzing')}...</p>
1707 </div>
1708 `;
1709 const results = await runFullAudit(updateProgress);
1710 displayResults(results);
1711 });
1712
1713 document.getElementById('seo-audit-export').addEventListener('click', () => {
1714 exportReport(results);
1715 });
1716
1717 document.getElementById('seo-audit-lang-toggle').addEventListener('click', async () => {
1718 const newLang = currentLanguage === 'en' ? 'he' : 'en';
1719 await saveLanguage(newLang);
1720 displayResults(results);
1721 });
1722
1723 // Filter buttons
1724 const filterButtons = content.querySelectorAll('.seo-audit-filter-btn');
1725 filterButtons.forEach(btn => {
1726 btn.addEventListener('click', function() {
1727 filterButtons.forEach(b => b.classList.remove('active'));
1728 this.classList.add('active');
1729 currentFilter = this.dataset.filter;
1730 applyFilters();
1731 });
1732 });
1733
1734 // Search functionality
1735 const searchInput = document.getElementById('seo-audit-search');
1736 searchInput.addEventListener('input', function() {
1737 searchQuery = this.value.toLowerCase();
1738 applyFilters();
1739 });
1740
1741 // Expand/Collapse all
1742 document.getElementById('seo-audit-expand-all').addEventListener('click', () => {
1743 content.querySelectorAll('.seo-audit-category').forEach(cat => {
1744 cat.classList.add('expanded');
1745 });
1746 });
1747
1748 document.getElementById('seo-audit-collapse-all').addEventListener('click', () => {
1749 content.querySelectorAll('.seo-audit-category').forEach(cat => {
1750 cat.classList.remove('expanded');
1751 });
1752 });
1753
1754 // Category expand/collapse
1755 const categoryHeaders = content.querySelectorAll('.seo-audit-category-header');
1756 categoryHeaders.forEach(header => {
1757 header.addEventListener('click', function() {
1758 const categoryElement = this.closest('.seo-audit-category');
1759 categoryElement.classList.toggle('expanded');
1760 });
1761 });
1762
1763 // Tooltip functionality
1764 setupTooltips(content);
1765 }
1766
1767 function applyFilters() {
1768 const categories = document.querySelectorAll('.seo-audit-category');
1769
1770 categories.forEach(category => {
1771 const items = category.querySelectorAll('.seo-audit-item');
1772 let visibleCount = 0;
1773
1774 items.forEach(item => {
1775 const itemType = item.dataset.itemType;
1776 const itemText = item.textContent.toLowerCase();
1777
1778 let matchesFilter = currentFilter === 'all' ||
1779 (currentFilter === 'critical' && itemType === 'critical') ||
1780 (currentFilter === 'warnings' && itemType === 'warning');
1781
1782 let matchesSearch = searchQuery === '' || itemText.includes(searchQuery);
1783
1784 if (matchesFilter && matchesSearch) {
1785 item.style.display = 'block';
1786 visibleCount++;
1787 } else {
1788 item.style.display = 'none';
1789 }
1790 });
1791
1792 // Hide category if no visible items
1793 if (visibleCount === 0) {
1794 category.style.display = 'none';
1795 } else {
1796 category.style.display = 'block';
1797 }
1798 });
1799 }
1800
1801 function setupTooltips(container) {
1802 const tooltips = container.querySelectorAll('.seo-audit-category-tooltip, .seo-audit-section-tooltip');
1803 tooltips.forEach(tooltip => {
1804 tooltip.addEventListener('mouseenter', function() {
1805 const tooltipText = this.dataset.tooltip;
1806 const tooltipEl = document.createElement('div');
1807 tooltipEl.className = 'seo-audit-tooltip-popup';
1808 tooltipEl.textContent = tooltipText;
1809
1810 const rect = this.getBoundingClientRect();
1811 tooltipEl.style.cssText = `
1812 position: fixed;
1813 left: ${rect.left}px;
1814 top: ${rect.bottom + 10}px;
1815 max-width: 300px;
1816 background: #333;
1817 color: white;
1818 padding: 12px;
1819 border-radius: 8px;
1820 font-size: 12px;
1821 line-height: 1.5;
1822 z-index: 1000000;
1823 box-shadow: 0 4px 12px rgba(0,0,0,0.3);
1824 animation: seo-audit-tooltip-fade-in 0.2s ease;
1825 `;
1826 document.body.appendChild(tooltipEl);
1827 this.tooltipElement = tooltipEl;
1828
1829 // Adjust position if tooltip goes off screen
1830 const tooltipRect = tooltipEl.getBoundingClientRect();
1831 if (tooltipRect.right > window.innerWidth) {
1832 tooltipEl.style.left = (window.innerWidth - tooltipRect.width - 10) + 'px';
1833 }
1834 if (tooltipRect.bottom > window.innerHeight) {
1835 tooltipEl.style.top = (rect.top - tooltipRect.height - 10) + 'px';
1836 }
1837 });
1838
1839 tooltip.addEventListener('mouseleave', function() {
1840 if (this.tooltipElement) {
1841 this.tooltipElement.remove();
1842 this.tooltipElement = null;
1843 }
1844 });
1845 });
1846 }
1847
1848 function updateProgress(moduleName, progress) {
1849 const progressBar = document.getElementById('seo-audit-progress');
1850 const progressText = document.getElementById('seo-audit-progress-text');
1851
1852 if (progressBar) {
1853 progressBar.style.width = progress + '%';
1854 }
1855
1856 if (progressText) {
1857 progressText.textContent = `${t('analyzing')} ${moduleName}...`;
1858 }
1859 }
1860
1861 function exportReport(results) {
1862 const report = {
1863 version: CONFIG.version,
1864 url: results.url,
1865 timestamp: results.timestamp,
1866 overallScore: results.scores.overall,
1867 categoryScores: results.scores,
1868 coreWebVitals: results.coreWebVitals,
1869 aiRecommendations: results.aiRecommendations,
1870 summary: {
1871 issues: results.issues.length,
1872 warnings: results.warnings.length,
1873 passed: results.passed.length
1874 },
1875 issues: results.issues,
1876 warnings: results.warnings,
1877 passed: results.passed
1878 };
1879
1880 const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' });
1881 const url = URL.createObjectURL(blob);
1882 const a = document.createElement('a');
1883 a.href = url;
1884 a.download = `seo-audit-pro-${new Date().toISOString().split('T')[0]}.json`;
1885 document.body.appendChild(a);
1886 a.click();
1887 document.body.removeChild(a);
1888 URL.revokeObjectURL(url);
1889
1890 console.log('📥 SEO Audit Pro report exported!');
1891 }
1892
1893 function addStyles() {
1894 const styles = `
1895 @keyframes seo-audit-fade-in {
1896 from { opacity: 0; transform: translateY(-10px); }
1897 to { opacity: 1; transform: translateY(0); }
1898 }
1899
1900 @keyframes seo-audit-tooltip-fade-in {
1901 from { opacity: 0; transform: scale(0.95); }
1902 to { opacity: 1; transform: scale(1); }
1903 }
1904
1905 @keyframes seo-audit-spin {
1906 0% { transform: rotate(0deg); }
1907 100% { transform: rotate(360deg); }
1908 }
1909
1910 @keyframes seo-audit-pulse {
1911 0%, 100% { opacity: 1; }
1912 50% { opacity: 0.5; }
1913 }
1914
1915 @keyframes seo-audit-slide-in {
1916 from { transform: translateX(-10px); opacity: 0; }
1917 to { transform: translateX(0); opacity: 1; }
1918 }
1919
1920 #seo-audit-panel {
1921 position: fixed;
1922 top: 20px;
1923 right: 20px;
1924 width: 720px;
1925 max-height: 90vh;
1926 background: #ffffff;
1927 border-radius: 20px;
1928 box-shadow: 0 25px 70px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(0, 0, 0, 0.05);
1929 z-index: 999999;
1930 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
1931 display: flex;
1932 flex-direction: column;
1933 overflow: hidden;
1934 animation: seo-audit-fade-in 0.4s cubic-bezier(0.16, 1, 0.3, 1);
1935 }
1936
1937 #seo-audit-panel.minimized {
1938 height: 60px;
1939 }
1940
1941 #seo-audit-panel.minimized .seo-audit-content {
1942 display: none;
1943 }
1944
1945 #seo-audit-panel.seo-audit-closing {
1946 animation: seo-audit-fade-in 0.3s ease reverse;
1947 }
1948
1949 .seo-audit-header {
1950 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1951 color: white;
1952 padding: 18px 24px;
1953 display: flex;
1954 justify-content: space-between;
1955 align-items: center;
1956 cursor: move;
1957 user-select: none;
1958 border-radius: 20px 20px 0 0;
1959 }
1960
1961 .seo-audit-title {
1962 display: flex;
1963 align-items: center;
1964 gap: 14px;
1965 }
1966
1967 .seo-audit-title-text {
1968 display: flex;
1969 flex-direction: column;
1970 gap: 3px;
1971 }
1972
1973 .seo-audit-subtitle {
1974 font-size: 11px;
1975 opacity: 0.95;
1976 font-weight: 400;
1977 }
1978
1979 .seo-audit-icon {
1980 font-size: 26px;
1981 }
1982
1983 .seo-audit-actions {
1984 display: flex;
1985 gap: 10px;
1986 }
1987
1988 .seo-audit-btn-icon {
1989 background: rgba(255, 255, 255, 0.2);
1990 border: none;
1991 color: white;
1992 width: 32px;
1993 height: 32px;
1994 border-radius: 8px;
1995 cursor: pointer;
1996 font-size: 20px;
1997 display: flex;
1998 align-items: center;
1999 justify-content: center;
2000 transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
2001 }
2002
2003 .seo-audit-btn-icon:hover {
2004 background: rgba(255, 255, 255, 0.3);
2005 transform: scale(1.1);
2006 }
2007
2008 .seo-audit-content {
2009 flex: 1;
2010 overflow-y: auto;
2011 padding: 24px;
2012 background: #f8f9fa;
2013 }
2014
2015 .seo-audit-loading {
2016 display: flex;
2017 flex-direction: column;
2018 align-items: center;
2019 justify-content: center;
2020 padding: 50px 20px;
2021 text-align: center;
2022 }
2023
2024 .seo-audit-spinner {
2025 width: 60px;
2026 height: 60px;
2027 border: 6px solid #f3f3f3;
2028 border-top: 6px solid #667eea;
2029 border-radius: 50%;
2030 animation: seo-audit-spin 1s linear infinite;
2031 margin-bottom: 24px;
2032 }
2033
2034 .seo-audit-loading-text {
2035 font-size: 18px;
2036 font-weight: 600;
2037 color: #333;
2038 margin-bottom: 10px;
2039 }
2040
2041 .seo-audit-loading-detail {
2042 font-size: 14px;
2043 color: #888;
2044 margin-bottom: 24px;
2045 }
2046
2047 .seo-audit-progress-bar {
2048 width: 100%;
2049 height: 8px;
2050 background: #e0e0e0;
2051 border-radius: 4px;
2052 overflow: hidden;
2053 margin-bottom: 14px;
2054 }
2055
2056 .seo-audit-progress-fill {
2057 height: 100%;
2058 background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
2059 transition: width 0.3s ease;
2060 width: 0%;
2061 }
2062
2063 .seo-audit-progress-text {
2064 font-size: 13px;
2065 color: #666;
2066 animation: seo-audit-pulse 1.5s ease-in-out infinite;
2067 }
2068
2069 .seo-audit-score-section {
2070 display: flex;
2071 align-items: center;
2072 gap: 28px;
2073 margin-bottom: 28px;
2074 padding: 28px;
2075 background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
2076 border-radius: 16px;
2077 box-shadow: 0 4px 12px rgba(0,0,0,0.08);
2078 }
2079
2080 .seo-audit-score-circle {
2081 width: 140px;
2082 height: 140px;
2083 position: relative;
2084 flex-shrink: 0;
2085 }
2086
2087 .seo-audit-score-ring {
2088 width: 100%;
2089 height: 100%;
2090 transform: rotate(-90deg);
2091 }
2092
2093 .seo-audit-score-ring-bg {
2094 fill: none;
2095 stroke: #e0e0e0;
2096 stroke-width: 10;
2097 }
2098
2099 .seo-audit-score-ring-fill {
2100 fill: none;
2101 stroke-width: 10;
2102 stroke-dasharray: 283;
2103 stroke-dashoffset: 283;
2104 transition: stroke-dashoffset 1.5s cubic-bezier(0.16, 1, 0.3, 1);
2105 stroke-linecap: round;
2106 }
2107
2108 .seo-audit-score-value {
2109 position: absolute;
2110 top: 50%;
2111 left: 50%;
2112 transform: translate(-50%, -50%);
2113 font-size: 42px;
2114 font-weight: 700;
2115 line-height: 1;
2116 }
2117
2118 .seo-audit-score-label {
2119 position: absolute;
2120 top: 68%;
2121 left: 50%;
2122 transform: translateX(-50%);
2123 font-size: 13px;
2124 color: #666;
2125 font-weight: 500;
2126 }
2127
2128 .seo-audit-section-title {
2129 font-size: 17px;
2130 font-weight: 700;
2131 color: #333;
2132 margin-bottom: 18px;
2133 padding-bottom: 10px;
2134 border-bottom: 2px solid #e0e0e0;
2135 display: flex;
2136 align-items: center;
2137 gap: 10px;
2138 }
2139
2140 .seo-audit-section-tooltip {
2141 width: 22px;
2142 height: 22px;
2143 border-radius: 50%;
2144 background: #667eea;
2145 color: white;
2146 display: flex;
2147 align-items: center;
2148 justify-content: center;
2149 font-size: 14px;
2150 font-weight: 700;
2151 cursor: help;
2152 flex-shrink: 0;
2153 transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
2154 }
2155
2156 .seo-audit-section-tooltip:hover {
2157 background: #764ba2;
2158 transform: scale(1.15);
2159 }
2160
2161 .seo-audit-docs-link {
2162 margin-left: auto;
2163 font-size: 18px;
2164 text-decoration: none;
2165 opacity: 0.8;
2166 transition: all 0.2s;
2167 }
2168
2169 .seo-audit-docs-link:hover {
2170 opacity: 1;
2171 transform: scale(1.1);
2172 }
2173
2174 .seo-audit-cwv-section {
2175 margin-bottom: 28px;
2176 padding: 24px;
2177 background: white;
2178 border-radius: 16px;
2179 box-shadow: 0 4px 12px rgba(0,0,0,0.06);
2180 }
2181
2182 .seo-audit-cwv-grid {
2183 display: grid;
2184 grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
2185 gap: 16px;
2186 }
2187
2188 .seo-audit-cwv-item {
2189 padding: 20px 14px;
2190 background: #f9f9f9;
2191 border-radius: 12px;
2192 border-left: 5px solid;
2193 text-align: center;
2194 transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
2195 }
2196
2197 .seo-audit-cwv-item:hover {
2198 transform: translateY(-5px);
2199 box-shadow: 0 8px 20px rgba(0,0,0,0.1);
2200 }
2201
2202 .seo-audit-cwv-label {
2203 font-size: 12px;
2204 font-weight: 700;
2205 color: #666;
2206 margin-bottom: 10px;
2207 text-transform: uppercase;
2208 letter-spacing: 0.8px;
2209 }
2210
2211 .seo-audit-cwv-value {
2212 font-size: 26px;
2213 font-weight: 700;
2214 color: #333;
2215 margin-bottom: 6px;
2216 }
2217
2218 .seo-audit-cwv-status {
2219 font-size: 11px;
2220 text-transform: uppercase;
2221 font-weight: 600;
2222 margin-bottom: 6px;
2223 }
2224
2225 .seo-audit-cwv-description {
2226 font-size: 10px;
2227 color: #888;
2228 margin-top: 6px;
2229 }
2230
2231 .seo-audit-ai-section {
2232 margin-bottom: 28px;
2233 padding: 24px;
2234 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2235 border-radius: 16px;
2236 color: white;
2237 box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
2238 }
2239
2240 .seo-audit-ai-section .seo-audit-section-title {
2241 color: white;
2242 border-bottom-color: rgba(255, 255, 255, 0.3);
2243 }
2244
2245 .seo-audit-ai-section .seo-audit-section-tooltip {
2246 background: rgba(255, 255, 255, 0.3);
2247 }
2248
2249 .seo-audit-ai-section .seo-audit-section-tooltip:hover {
2250 background: rgba(255, 255, 255, 0.5);
2251 }
2252
2253 .seo-audit-ai-recommendations {
2254 display: flex;
2255 flex-direction: column;
2256 gap: 14px;
2257 }
2258
2259 .seo-audit-ai-rec {
2260 padding: 18px;
2261 background: rgba(255, 255, 255, 0.97);
2262 border-radius: 12px;
2263 border-left: 5px solid;
2264 color: #333;
2265 transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
2266 animation: seo-audit-slide-in 0.4s ease;
2267 }
2268
2269 .seo-audit-ai-rec:hover {
2270 transform: translateX(8px);
2271 box-shadow: 0 6px 16px rgba(0,0,0,0.15);
2272 }
2273
2274 .seo-audit-ai-rec-high {
2275 border-left-color: #ff4e42;
2276 }
2277
2278 .seo-audit-ai-rec-medium {
2279 border-left-color: #ffa400;
2280 }
2281
2282 .seo-audit-ai-rec-low {
2283 border-left-color: #0cce6b;
2284 }
2285
2286 .seo-audit-ai-rec-header {
2287 display: flex;
2288 justify-content: space-between;
2289 align-items: center;
2290 margin-bottom: 10px;
2291 }
2292
2293 .seo-audit-ai-rec-priority {
2294 font-size: 11px;
2295 font-weight: 700;
2296 padding: 5px 10px;
2297 background: rgba(0, 0, 0, 0.1);
2298 border-radius: 6px;
2299 letter-spacing: 0.8px;
2300 }
2301
2302 .seo-audit-ai-rec-effort {
2303 font-size: 12px;
2304 color: #666;
2305 font-weight: 500;
2306 }
2307
2308 .seo-audit-ai-rec-title {
2309 font-size: 16px;
2310 font-weight: 600;
2311 color: #333;
2312 margin-bottom: 10px;
2313 }
2314
2315 .seo-audit-ai-rec-description {
2316 font-size: 14px;
2317 color: #555;
2318 line-height: 1.7;
2319 margin-bottom: 10px;
2320 }
2321
2322 .seo-audit-ai-rec-impact {
2323 font-size: 13px;
2324 color: #666;
2325 }
2326
2327 .seo-audit-controls {
2328 margin-bottom: 24px;
2329 padding: 20px;
2330 background: white;
2331 border-radius: 16px;
2332 box-shadow: 0 4px 12px rgba(0,0,0,0.06);
2333 }
2334
2335 .seo-audit-filter-buttons {
2336 display: flex;
2337 gap: 10px;
2338 margin-bottom: 16px;
2339 flex-wrap: wrap;
2340 }
2341
2342 .seo-audit-filter-btn {
2343 padding: 10px 18px;
2344 border: 2px solid #e0e0e0;
2345 background: white;
2346 border-radius: 10px;
2347 font-size: 13px;
2348 font-weight: 600;
2349 cursor: pointer;
2350 transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
2351 color: #666;
2352 }
2353
2354 .seo-audit-filter-btn:hover {
2355 border-color: #667eea;
2356 color: #667eea;
2357 transform: translateY(-2px);
2358 }
2359
2360 .seo-audit-filter-btn.active {
2361 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2362 color: white;
2363 border-color: transparent;
2364 }
2365
2366 .seo-audit-search-box {
2367 position: relative;
2368 margin-bottom: 16px;
2369 }
2370
2371 .seo-audit-search-box input {
2372 width: 100%;
2373 padding: 12px 40px 12px 16px;
2374 border: 2px solid #e0e0e0;
2375 border-radius: 10px;
2376 font-size: 14px;
2377 transition: all 0.2s;
2378 }
2379
2380 .seo-audit-search-box input:focus {
2381 outline: none;
2382 border-color: #667eea;
2383 box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
2384 }
2385
2386 .seo-audit-search-icon {
2387 position: absolute;
2388 right: 14px;
2389 top: 50%;
2390 transform: translateY(-50%);
2391 font-size: 16px;
2392 opacity: 0.5;
2393 }
2394
2395 .seo-audit-expand-controls {
2396 display: flex;
2397 gap: 10px;
2398 }
2399
2400 .seo-audit-expand-btn {
2401 flex: 1;
2402 padding: 10px;
2403 border: 2px solid #e0e0e0;
2404 background: white;
2405 border-radius: 10px;
2406 font-size: 13px;
2407 font-weight: 600;
2408 cursor: pointer;
2409 transition: all 0.2s;
2410 color: #666;
2411 }
2412
2413 .seo-audit-expand-btn:hover {
2414 border-color: #667eea;
2415 color: #667eea;
2416 transform: translateY(-2px);
2417 }
2418
2419 .seo-audit-categories {
2420 margin-bottom: 28px;
2421 }
2422
2423 .seo-audit-category {
2424 margin-bottom: 18px;
2425 background: white;
2426 border-radius: 16px;
2427 overflow: hidden;
2428 box-shadow: 0 4px 12px rgba(0,0,0,0.06);
2429 transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
2430 }
2431
2432 .seo-audit-category:hover {
2433 box-shadow: 0 8px 20px rgba(0,0,0,0.12);
2434 transform: translateY(-2px);
2435 }
2436
2437 .seo-audit-category-header {
2438 display: flex;
2439 justify-content: space-between;
2440 align-items: center;
2441 padding: 18px 24px;
2442 cursor: pointer;
2443 transition: background 0.2s;
2444 }
2445
2446 .seo-audit-category-header:hover {
2447 background: #f9f9f9;
2448 }
2449
2450 .seo-audit-category-info {
2451 display: flex;
2452 align-items: center;
2453 gap: 12px;
2454 flex: 1;
2455 }
2456
2457 .seo-audit-category-icon {
2458 font-size: 22px;
2459 }
2460
2461 .seo-audit-category-name {
2462 font-size: 16px;
2463 font-weight: 600;
2464 color: #333;
2465 }
2466
2467 .seo-audit-category-tooltip {
2468 width: 20px;
2469 height: 20px;
2470 border-radius: 50%;
2471 background: #667eea;
2472 color: white;
2473 display: flex;
2474 align-items: center;
2475 justify-content: center;
2476 font-size: 13px;
2477 font-weight: 700;
2478 cursor: help;
2479 flex-shrink: 0;
2480 transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
2481 }
2482
2483 .seo-audit-category-tooltip:hover {
2484 background: #764ba2;
2485 transform: scale(1.15);
2486 }
2487
2488 .seo-audit-category-details {
2489 font-size: 12px;
2490 color: #888;
2491 margin-left: 10px;
2492 }
2493
2494 .seo-audit-category-score {
2495 font-size: 28px;
2496 font-weight: 700;
2497 margin-right: 14px;
2498 }
2499
2500 .seo-audit-category-bar {
2501 height: 8px;
2502 background: #e0e0e0;
2503 overflow: hidden;
2504 }
2505
2506 .seo-audit-category-bar-fill {
2507 height: 100%;
2508 transition: width 0.8s cubic-bezier(0.16, 1, 0.3, 1);
2509 }
2510
2511 .seo-audit-category-content {
2512 display: none;
2513 padding: 24px;
2514 background: #f9f9f9;
2515 border-top: 1px solid #e0e0e0;
2516 }
2517
2518 .seo-audit-category.expanded .seo-audit-category-content {
2519 display: block;
2520 animation: seo-audit-fade-in 0.4s ease;
2521 }
2522
2523 .seo-audit-category-section {
2524 margin-bottom: 24px;
2525 }
2526
2527 .seo-audit-category-section:last-child {
2528 margin-bottom: 0;
2529 }
2530
2531 .seo-audit-category-section-title {
2532 font-size: 14px;
2533 font-weight: 600;
2534 color: #333;
2535 margin-bottom: 14px;
2536 }
2537
2538 .seo-audit-item {
2539 background: white;
2540 border-left: 5px solid;
2541 padding: 18px;
2542 margin-bottom: 14px;
2543 border-radius: 12px;
2544 transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
2545 animation: seo-audit-slide-in 0.3s ease;
2546 }
2547
2548 .seo-audit-item:hover {
2549 transform: translateX(5px);
2550 box-shadow: 0 6px 16px rgba(0,0,0,0.1);
2551 }
2552
2553 .seo-audit-item-critical {
2554 border-left-color: #ff4e42;
2555 }
2556
2557 .seo-audit-item-warning {
2558 border-left-color: #ffa400;
2559 }
2560
2561 .seo-audit-item-header {
2562 display: flex;
2563 align-items: center;
2564 gap: 10px;
2565 margin-bottom: 10px;
2566 }
2567
2568 .seo-audit-item-icon {
2569 font-size: 18px;
2570 }
2571
2572 .seo-audit-item-title {
2573 font-weight: 600;
2574 font-size: 15px;
2575 color: #333;
2576 }
2577
2578 .seo-audit-item-description {
2579 font-size: 14px;
2580 color: #666;
2581 margin-bottom: 10px;
2582 line-height: 1.7;
2583 }
2584
2585 .seo-audit-item-recommendation {
2586 font-size: 14px;
2587 color: #444;
2588 background: rgba(0, 0, 0, 0.05);
2589 padding: 12px 14px;
2590 border-radius: 8px;
2591 line-height: 1.7;
2592 margin-bottom: 10px;
2593 }
2594
2595 .seo-audit-item-source {
2596 margin-top: 10px;
2597 }
2598
2599 .seo-audit-source-link {
2600 display: inline-flex;
2601 align-items: center;
2602 gap: 5px;
2603 font-size: 13px;
2604 color: #667eea;
2605 text-decoration: none;
2606 font-weight: 600;
2607 transition: all 0.2s;
2608 }
2609
2610 .seo-audit-source-link:hover {
2611 color: #764ba2;
2612 text-decoration: underline;
2613 transform: translateX(3px);
2614 }
2615
2616 .seo-audit-footer {
2617 display: flex;
2618 gap: 14px;
2619 padding: 18px 24px;
2620 border-top: 1px solid #e0e0e0;
2621 background: white;
2622 border-radius: 0 0 20px 20px;
2623 }
2624
2625 .seo-audit-btn-primary,
2626 .seo-audit-btn-secondary,
2627 .seo-audit-btn-lang {
2628 padding: 14px 20px;
2629 border: none;
2630 border-radius: 10px;
2631 font-size: 14px;
2632 font-weight: 600;
2633 cursor: pointer;
2634 transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
2635 }
2636
2637 .seo-audit-btn-primary {
2638 flex: 1;
2639 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2640 color: white;
2641 }
2642
2643 .seo-audit-btn-primary:hover {
2644 transform: translateY(-3px);
2645 box-shadow: 0 8px 20px rgba(102, 126, 234, 0.5);
2646 }
2647
2648 .seo-audit-btn-secondary {
2649 flex: 1;
2650 background: white;
2651 color: #667eea;
2652 border: 2px solid #667eea;
2653 }
2654
2655 .seo-audit-btn-secondary:hover {
2656 background: #667eea;
2657 color: white;
2658 transform: translateY(-3px);
2659 box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
2660 }
2661
2662 .seo-audit-btn-lang {
2663 background: #f0f0f0;
2664 color: #333;
2665 padding: 14px 24px;
2666 }
2667
2668 .seo-audit-btn-lang:hover {
2669 background: #e0e0e0;
2670 transform: translateY(-3px);
2671 }
2672
2673 .seo-audit-content::-webkit-scrollbar {
2674 width: 10px;
2675 }
2676
2677 .seo-audit-content::-webkit-scrollbar-track {
2678 background: #f1f1f1;
2679 border-radius: 5px;
2680 }
2681
2682 .seo-audit-content::-webkit-scrollbar-thumb {
2683 background: #888;
2684 border-radius: 5px;
2685 }
2686
2687 .seo-audit-content::-webkit-scrollbar-thumb:hover {
2688 background: #555;
2689 }
2690
2691 .seo-audit-summary {
2692 flex: 1;
2693 display: flex;
2694 gap: 18px;
2695 }
2696
2697 .seo-audit-summary-item {
2698 flex: 1;
2699 text-align: center;
2700 padding: 14px;
2701 background: white;
2702 border-radius: 12px;
2703 box-shadow: 0 4px 8px rgba(0,0,0,0.1);
2704 transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
2705 }
2706
2707 .seo-audit-summary-item:hover {
2708 transform: translateY(-3px);
2709 box-shadow: 0 8px 16px rgba(0,0,0,0.15);
2710 }
2711
2712 .seo-audit-summary-count {
2713 display: block;
2714 font-size: 28px;
2715 font-weight: 700;
2716 margin-bottom: 5px;
2717 }
2718
2719 .seo-audit-summary-item.critical .seo-audit-summary-count {
2720 color: #ff4e42;
2721 }
2722
2723 .seo-audit-summary-item.warning .seo-audit-summary-count {
2724 color: #ffa400;
2725 }
2726
2727 .seo-audit-summary-item.passed .seo-audit-summary-count {
2728 color: #0cce6b;
2729 }
2730
2731 .seo-audit-summary-label {
2732 font-size: 12px;
2733 color: #666;
2734 text-transform: uppercase;
2735 letter-spacing: 0.8px;
2736 font-weight: 600;
2737 }
2738 `;
2739
2740 const styleElement = document.createElement('style');
2741 styleElement.textContent = styles;
2742 document.head.appendChild(styleElement);
2743 }
2744
2745 async function init() {
2746 console.log('🚀 SEO Audit Pro v4.0 - Ultimate Premium Edition initialized');
2747
2748 await loadLanguage();
2749 addStyles();
2750
2751 if (document.readyState === 'loading') {
2752 document.addEventListener('DOMContentLoaded', startAudit);
2753 } else {
2754 startAudit();
2755 }
2756 }
2757
2758 async function startAudit() {
2759 createAuditUI();
2760 await new Promise(resolve => setTimeout(resolve, 1000));
2761 const results = await runFullAudit(updateProgress);
2762 displayResults(results);
2763 }
2764
2765 init();
2766
2767})();