{"url":"https://larsen.ee/","date":"2026-06-10","siteName":"Larsen - The Coolest Accommodation in Tallinn","overall":47,"reasoning":"Site overall 47 is the mean of 5 pages. Scores range 42 (https://larsen.ee/) → 52 (https://larsen.ee/terms-of-service). Weakest page: Mobile PSI performance is critically low at 35 with an 18.9 s LCP, despite decent field data, indicating severe lab bottlenecks. The 69 MB total page weight (55 MB media) is unsustainable for mobile users and directly drives the TBT and LCP failures. Accessibility is blocked by 2 critical axe violations and 11 W3C errors including buttons inside anchors. Security headers are weak (HSTS/CSP) though no auth/payments exist, and image optimization is missing entirely (no srcset).","confidence":"high","fixes":[{"priority":1,"title":"Reduce page weight from 69 MB to under 5 MB","impact":"LCP, TBT, Mobile Performance","problem":"Total page weight is 69 MB with 55 MB media and 1.3 MB unused JS (app-8897...), causing 18.9 s LCP and 1.03 s TBT on mobile.","solution":"- Remove unused JavaScript bundles (1.3 MB).\n- Compress and resize media assets (55 MB) to WebP/AVIF.\n- Implement lazy loading for off-screen media.\n- Use a CDN with edge caching to reduce TTFB."},{"priority":1,"title":"Fix critical accessibility violations","impact":"WCAG Compliance, SEO","problem":"axe-core reports 2 critical violations: `button-name` (slider dots) and `image-alt` (Co-Liv image). W3C reports 5 errors of `button` inside `a`.","solution":"- Add `aria-label` to slider dot buttons.\n- Add descriptive `alt` text to the Co-Liv image.\n- Refactor HTML to remove `button` elements nested inside `a` tags (use `button` alone or `a` alone)."},{"priority":1,"title":"Optimize images to reduce page weight and LCP","impact":"LCP, Page Weight, CLS","problem":"Images consume 3.75 MB (82% of 4.6 MB total weight); LCP is 6.9 s on mobile. 8 images lack srcset/width/height, and 5 are not lazy-loaded.","solution":"1. Convert all raster images to WebP/AVIF.\n2. Add `srcset` and `sizes` attributes for responsive loading.\n3. Add `width` and `height` attributes to prevent CLS.\n4. Add `loading=\"lazy\"` to non-hero images.\n5. Use `fetchpriority=\"high\"` on the LCP hero image."},{"priority":1,"title":"Strengthen Security Headers (CSP & HSTS)","impact":"XSS Defense, Transport Security","problem":"Security grade is 40/100. HSTS max-age is too short (15552000s) and missing `includeSubDomains`. CSP only sets `frame-ancestors` (missing `default-src`). Site signals indicate User-Generated Content is present, elevating XSS risk.","solution":"1. Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n2. Implement strict CSP with nonce/hash: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none';`.\n3. Add `X-Frame-Options: SAMEORIGIN` as fallback."},{"priority":1,"title":"Fix Core Web Vitals (LCP/FCP) and Reduce JavaScript","impact":"Performance, LCP, FCP, TBT","problem":"Mobile LCP is 20.6 s and FCP is 10.65 s; 1.4 MB of unused JavaScript identified (e.g., app-889782a39d4314ef1bf6.js).","solution":"1. **Defer/Remove Unused JS:** Audit and remove the 1.4 MB `app-*.js` bundle or split it. Use `defer` for non-critical scripts.\n2. **Fix Hero Image:** Ensure the LCP image (likely the hero) uses `loading=\"eager\"` (or omit) and `fetchpriority=\"high\"`.\n3. **Preload Critical Resources:** Add `<link rel=\"preload\">` for the hero image and critical CSS."},{"priority":1,"title":"Resolve Critical Accessibility Violations","impact":"WCAG 2.1, Screen Reader Usability","problem":"axe-core reports 1 critical (`image-alt`) and 3 serious violations (`html-has-lang`, `color-contrast`, `link-name`).","solution":"1. **Add `lang` attribute:** `<html lang=\"en\">`.\n2. **Fix Image Alt:** Add descriptive `alt` text to all content images (e.g., `Co-Liv.png`).\n3. **Fix Contrast:** Ensure text/background contrast ratio ≥ 4.5:1.\n4. **Label Links:** Add `aria-label` to icon links (e.g., Facebook, Instagram) that lack visible text."},{"priority":1,"title":"Reduce JavaScript bundle size and eliminate unused code","impact":"LCP, TBT, FCP, Performance Score","problem":"1398 KB wasted JavaScript (app-889782a39d4314ef1bf6.js) contributes to 756 ms TBT and 4.2 s LCP on mobile.","solution":"- Implement code splitting to load only necessary JS for the Terms page.\n- Tree-shake unused dependencies.\n- Defer non-critical third-party scripts (GTM, PostHog) until after interaction."},{"priority":1,"title":"Fix critical accessibility violations and document structure","impact":"WCAG 2.1 A/AA Compliance, Screen Reader Usability","problem":"1 critical `image-alt` violation, 2 serious violations (`html-has-lang`, `link-name`), and missing `<h1>` heading.","solution":"- Add `lang=\"en\"` to `<html>` tag.\n- Add descriptive `alt` text to all images (e.g., `alt=\"Larsen Hotel Logo\"`).\n- Add a single `<h1>` element describing the page (e.g., `<h1>Terms of Service</h1>`).\n- Ensure all links have discernible text or `aria-label`."},{"priority":1,"title":"Strengthen Security Headers (HSTS and CSP)","impact":"Transport Security, XSS Defense","problem":"HSTS max-age is too short (15552000s) and missing directives; CSP lacks `default-src` despite UGC signals.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Implement strict CSP with nonce/hash: `default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`.\n- Add `X-Frame-Options: SAMEORIGIN` as fallback."},{"priority":1,"title":"Reduce page weight and fix LCP","impact":"Performance, LCP, FCP, TBT","problem":"Mobile Performance is 43/100; LCP is 18.9s; total page weight is 69MB (56MB media, 12MB images).","solution":"- Compress and resize media assets (videos/images) aggressively.\n- Implement lazy loading for below-fold content.\n- Remove unused JavaScript (1.37MB wasted in `app-889782a39d4314ef1bf6.js`).\n- Enable HTTP/2 or HTTP/3 server push for critical resources."},{"priority":1,"title":"Strengthen Content Security Policy (CSP)","impact":"XSS protection, Data integrity","problem":"CSP is present but weak (only `frame-ancestors` set); site has user-generated content (reviews), elevating XSS risk per the rubric.","solution":"- Implement a strict CSP with `default-src 'self'`.\n- Use nonces or hashes for inline scripts.\n- Add `object-src 'none'` and `base-uri 'none'`.\n- Example: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`"},{"priority":2,"title":"Strengthen security headers (HSTS, CSP)","impact":"Transport security, XSS defense","problem":"HSTS max-age is too short (15552000s) and missing directives; CSP lacks `default-src`. UGC signal is present but no auth/payments.","solution":"```\nStrict-Transport-Security: max-age=31536000; includeSubDomains; preload\nContent-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}' 'strict-dynamic';\n```"},{"priority":2,"title":"Implement responsive images (srcset)","impact":"Page weight, CLS, Mobile Performance","problem":"16/16 raster images lack `srcset` and `width/height` attributes, preventing browser optimization and risking layout shifts.","solution":"- Generate multiple image sizes (e.g., 400w, 800w, 1200w).\n- Add `srcset` and `sizes` attributes to `<img>` tags.\n- Add explicit `width` and `height` to reserve space."},{"priority":2,"title":"Reduce JavaScript Bundle Size and Unused Code","impact":"TBT, FCP, TTI","problem":"1397 KB of unused JavaScript detected in `app-889782a39d4314ef1bf6.js`. Multiple third-party scripts (GTM, GA, PostHog) contribute to long tasks (179 ms, 114 ms).","solution":"1. Code-split the main bundle to defer non-critical JS.\n2. Audit third-party scripts; remove unused tracking pixels (e.g., duplicate GTM/GA instances).\n3. Load non-critical scripts with `defer` or `async`.\n4. Implement resource hints (`preconnect`) for critical third-party origins."},{"priority":2,"title":"Implement Proper Caching Policy","impact":"Repeat Visit Performance, TTFB","problem":"Security Headers report shows `cache-control: not set`. Caching behavior is unpredictable, forcing re-downloads on repeat visits.","solution":"1. Set `Cache-Control: public, max-age=31536000, immutable` for static assets (images, CSS, JS).\n2. Set `Cache-Control: no-cache, must-revalidate` for HTML documents to ensure freshness.\n3. Ensure Vary header is set correctly for content negotiation."},{"priority":2,"title":"Fix W3C HTML Validation Errors","impact":"SEO, Rendering Consistency","problem":"18 W3C errors including obsolete `<font>` tags, duplicate IDs, and `<button>` inside `<a>`.","solution":"1. **Replace `<font>`:** Use CSS for styling (color, size).\n2. **Fix Structure:** Ensure `<button>` is not nested inside `<a>` tags.\n3. **Unique IDs:** Ensure `id=\"what-are-the-prices...\"` is unique across the page.\n4. **Charset:** Move `<meta charset=\"UTF-8\">` to the first 1024 bytes of the document."},{"priority":2,"title":"Optimize Image Delivery","impact":"Page Weight, CLS, LCP","problem":"3 images lack `width/height` (risk of CLS) and `srcset` (no responsive sizing). Hero image incorrectly lazy-loaded.","solution":"1. **Add Dimensions:** Specify `width` and `height` attributes on all `<img>` tags.\n2. **Responsive Images:** Implement `srcset` or `<picture>` for different viewport sizes.\n3. **Hero Image:** Remove `loading=\"lazy\"` from the LCP element."},{"priority":2,"title":"Optimize Hero Image and Add Responsive Variants","impact":"LCP, CLS, Data Usage","problem":"Hero image uses `loading=\"lazy\"` (delays LCP) and all 3 images lack `srcset` or explicit dimensions.","solution":"- Remove `loading=\"lazy\"` from the hero image; add `fetchpriority=\"high\"`.\n- Generate WebP/AVIF variants and implement `<picture>` with `srcset`.\n- Add `width` and `height` attributes to reserve space and prevent CLS."},{"priority":2,"title":"Fix HSTS and missing security headers","impact":"Transport security, Clickjacking protection","problem":"HSTS max-age is too short (15552000s) and missing `includeSubDomains`; `X-Frame-Options` is missing.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Add `X-Frame-Options: SAMEORIGIN` (or rely on CSP `frame-ancestors`).\n- Add `Permissions-Policy` to disable unused features."},{"priority":2,"title":"Optimize images for responsive delivery","impact":"LCP, Data usage, CLS","problem":"16 images lack `srcset`/`sizes`; 16 lack explicit `width`/`height`; 4 missing `loading=\"lazy\"`.","solution":"- Generate WebP/AVIF variants and serve via `<picture>` or `srcset`.\n- Add `width` and `height` attributes to reserve space.\n- Add `loading=\"lazy\"` to non-hero images.\n- Fix the 1 image missing `alt` text."},{"priority":2,"title":"Correct HTML structure and semantics","impact":"SEO, Accessibility, W3C validation","problem":"W3C reports 11 errors including `button` inside `a` (x5), heading skips (h2→h4), and missing `lang`.","solution":"- Remove `<button>` elements nested inside `<a>` tags; use `<a>` with `role=\"button\"` or separate elements.\n- Fix heading hierarchy (h2 → h3, not h2 → h4).\n- Add `lang=\"et\"` to `<html>`.\n- Add a skip-to-content link for keyboard navigation."},{"priority":3,"title":"Fix SEO and HTML structure issues","impact":"Search visibility, Accessibility","problem":"Missing `lang` attribute, `canonical` tag, and 11 W3C errors including heading skips (h2→h4).","solution":"- Add `<html lang=\"en\">`.\n- Add `<link rel=\"canonical\" href=\"...\">`.\n- Fix heading hierarchy to not skip levels (h2 → h3)."},{"priority":3,"title":"Improve SEO Metadata and Structure","impact":"Search Visibility, Indexing","problem":"HTML Inventory shows missing `canonical` tag, `robots` meta, and JSON-LD structured data. W3C validator notes missing `lang` attribute.","solution":"1. Add `<link rel=\"canonical\" href=\"https://larsen.ee/about\">`.\n2. Add `<meta name=\"robots\" content=\"index, follow\">`.\n3. Implement JSON-LD for `LocalBusiness` or `Hotel` schema.\n4. Add Twitter Card meta tags for social sharing."},{"priority":3,"title":"Enable Proper Caching and SEO Metadata","impact":"Repeat Visit Performance, Search Visibility","problem":"No `Cache-Control` header (unpredictable caching), missing `canonical` tag, missing `robots.txt`.","solution":"1. **Cache-Control:** Set `Cache-Control: public, max-age=31536000` for static assets.\n2. **Canonical:** Add `<link rel=\"canonical\" href=\"https://larsen.ee/faq\">`.\n3. **Robots:** Ensure `robots.txt` exists and allows crawling."},{"priority":3,"title":"Add Missing SEO Metadata and Caching","impact":"Search Visibility, Repeat Load Performance","problem":"Missing `meta description`, `canonical`, and `robots` tags; no explicit `Cache-Control` header.","solution":"- Add `<meta name=\"description\" content=\"...\">` and `<link rel=\"canonical\" href=\"...\">`.\n- Configure server to send `Cache-Control: public, max-age=31536000` for static assets.\n- Ensure Terms page is crawlable (check `robots.txt`)."}],"coverage":{"pct":100,"missing":[]},"siteSummary":{"pagesAudited":5,"pagesAttempted":5,"urls":["https://larsen.ee/","https://larsen.ee/about","https://larsen.ee/faq","https://larsen.ee/terms-of-service","https://larsen.ee/et"]},"psiSnapshot":{"rows":[{"pageUrl":"https://larsen.ee/","perfMobile":35,"perfDesktop":54,"lcpMobileMs":18904.504505928613,"lcpDesktopMs":4711.040222463926,"clsMobile":0.002829,"clsDesktop":0.000343},{"pageUrl":"https://larsen.ee/about","perfMobile":53,"perfDesktop":54,"lcpMobileMs":6927.018467860079,"lcpDesktopMs":3924.0830851470328,"clsMobile":0.137266,"clsDesktop":0.000213},{"pageUrl":"https://larsen.ee/faq","perfMobile":42,"perfDesktop":51,"lcpMobileMs":20618.38288641178,"lcpDesktopMs":3134.020980152155,"clsMobile":0,"clsDesktop":0.000213},{"pageUrl":"https://larsen.ee/terms-of-service","perfMobile":60,"perfDesktop":57,"lcpMobileMs":4203.526765303555,"lcpDesktopMs":2761.0379324095948,"clsMobile":0.001451,"clsDesktop":0.06324800000000001},{"pageUrl":"https://larsen.ee/et","perfMobile":43,"perfDesktop":55,"lcpMobileMs":18905.06553323205,"lcpDesktopMs":4713,"clsMobile":0.001323,"clsDesktop":0.000566}]},"optimizationChecklist":{"items":[{"id":"caching","title":"Page caching plugin / CDN active","status":"fail","detail":"No WordPress cache plugin marker or CDN edge cache detected on the document response.","evidence":[]},{"id":"lazyload","title":"Images lazy-loaded","status":"fail","detail":"5 of 7 non-hero raster images are not lazy-loaded (threshold: 2).","evidence":["https://larsen.ee/images/features/about_and_contact/2.jpg","https://larsen.ee/images/features/about_and_contact/3.jpg","https://larsen.ee/images/features/about_and_contact/4.jpg","https://larsen.ee/images/features/about_and_contact/5.jpg","https://larsen.ee/client/Co-Liv.e0807b70.png"]},{"id":"heroEager","title":"Hero image eagerly loaded","status":"fail","detail":"Hero image has loading=\"lazy\", which delays LCP (inferred from DOM order/size — Lighthouse LCP element unavailable). Use loading=\"eager\" (or omit loading) and add fetchpriority=\"high\".","evidence":["hero: …256x0/filters:quality(90)/https://larsen.ee/production/media/2024/07/karl.png","loading: lazy","fetchpriority: (not set)"]},{"id":"heroBackground","title":"Hero is a real <img> (not a CSS background-image)","status":"warn","detail":"Hero element uses a CSS background-image (no image-set() variants), so the browser always loads the original asset regardless of viewport — there is no srcset equivalent. Move the hero to a real <img> with srcset/sizes (or <picture>) so smaller viewports can fetch a smaller file.","evidence":["selector: div.buildings-map__map-overlay","url: https://larsen.ee/client/Tallinn.d777459c.png","box: 520×1021px"]},{"id":"responsive","title":"Responsive images (srcset / <picture>)","status":"fail","detail":"16/16 raster images lack srcset and are not inside <picture>.","evidence":["https://larsen.ee/images/uus-logota-larsen-video-2-thumbnail.jpg","…ers:quality(90)/https://larsen.ee/production/media/2023/11/maja-fasssad-2.jpg","…:quality(90)/https://larsen.ee/production/media/2025/03/rocca-house-drone.png","…filters:quality(90)/https://larsen.ee/production/media/2021/12/img-1042-1.jpg","…ality(90)/https://larsen.ee/production/media/2024/09/dji-0044-enhanced-nr.jpg"]},{"id":"imageSizes","title":"Reasonable number of image sizes","status":"fail","detail":"No raster images use srcset; browsers cannot pick an optimally sized variant.","evidence":[]},{"id":"scriptsFooter","title":"JS scripts not blocking in <head>","status":"pass","detail":"No render-blocking scripts in <head>.","evidence":[]}],"summary":{"passed":1,"warned":1,"failed":5,"notApplicable":0},"priorities":[{"title":"Page caching plugin / CDN active","severity":"high","detail":"No WordPress cache plugin marker or CDN edge cache detected on the document response."},{"title":"Responsive images (srcset / <picture>)","severity":"high","detail":"16/16 raster images lack srcset and are not inside <picture>."},{"title":"Reasonable number of image sizes","severity":"high","detail":"No raster images use srcset; browsers cannot pick an optimally sized variant."},{"title":"Images lazy-loaded","severity":"medium","detail":"3 of 15 non-hero raster images are not lazy-loaded."},{"title":"Hero image eagerly loaded","severity":"medium","detail":"Hero image has no explicit loading or fetchpriority (inferred from DOM order/size — Lighthouse LCP element unavailable). Browser default is eager but adding fetchpriority=\"high\" helps LCP."},{"title":"Hero is a real <img> (not a CSS background-image)","severity":"medium","detail":"Hero element uses a CSS background-image (no image-set() variants), so the browser always loads the original asset regardless of viewport — there is no srcset equivalent. Move the hero to a real <img> with srcset/sizes (or <picture>) so smaller viewports can fetch a smaller file."}]},"perPageOverall":[{"url":"https://larsen.ee/","overall":42,"reasoning":"Mobile PSI performance is critically low at 35 with an 18.9 s LCP, despite decent field data, indicating severe lab bottlenecks. The 69 MB total page weight (55 MB media) is unsustainable for mobile users and directly drives the TBT and LCP failures. Accessibility is blocked by 2 critical axe violations and 11 W3C errors including buttons inside anchors. Security headers are weak (HSTS/CSP) though no auth/payments exist, and image optimization is missing entirely (no srcset).","confidence":"high","fixes":[{"priority":1,"title":"Reduce page weight from 69 MB to under 5 MB","impact":"LCP, TBT, Mobile Performance","problem":"Total page weight is 69 MB with 55 MB media and 1.3 MB unused JS (app-8897...), causing 18.9 s LCP and 1.03 s TBT on mobile.","solution":"- Remove unused JavaScript bundles (1.3 MB).\n- Compress and resize media assets (55 MB) to WebP/AVIF.\n- Implement lazy loading for off-screen media.\n- Use a CDN with edge caching to reduce TTFB."},{"priority":1,"title":"Fix critical accessibility violations","impact":"WCAG Compliance, SEO","problem":"axe-core reports 2 critical violations: `button-name` (slider dots) and `image-alt` (Co-Liv image). W3C reports 5 errors of `button` inside `a`.","solution":"- Add `aria-label` to slider dot buttons.\n- Add descriptive `alt` text to the Co-Liv image.\n- Refactor HTML to remove `button` elements nested inside `a` tags (use `button` alone or `a` alone)."},{"priority":2,"title":"Strengthen security headers (HSTS, CSP)","impact":"Transport security, XSS defense","problem":"HSTS max-age is too short (15552000s) and missing directives; CSP lacks `default-src`. UGC signal is present but no auth/payments.","solution":"```\nStrict-Transport-Security: max-age=31536000; includeSubDomains; preload\nContent-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}' 'strict-dynamic';\n```"},{"priority":2,"title":"Implement responsive images (srcset)","impact":"Page weight, CLS, Mobile Performance","problem":"16/16 raster images lack `srcset` and `width/height` attributes, preventing browser optimization and risking layout shifts.","solution":"- Generate multiple image sizes (e.g., 400w, 800w, 1200w).\n- Add `srcset` and `sizes` attributes to `<img>` tags.\n- Add explicit `width` and `height` to reserve space."},{"priority":3,"title":"Fix SEO and HTML structure issues","impact":"Search visibility, Accessibility","problem":"Missing `lang` attribute, `canonical` tag, and 11 W3C errors including heading skips (h2→h4).","solution":"- Add `<html lang=\"en\">`.\n- Add `<link rel=\"canonical\" href=\"...\">`.\n- Fix heading hierarchy to not skip levels (h2 → h3)."}]},{"url":"https://larsen.ee/about","overall":52,"reasoning":"Mobile performance is critically low (53/100) with an LCP of 6.9 s, driven by 3.75 MB of images (82% of total page weight) and 1.4 MB of unused JavaScript. Security headers are weak (40/100) with missing HSTS directives and a permissive CSP, which is high-risk given the site signals indicate user-generated content. Accessibility has critical failures (image-alt) and serious issues (contrast, lang) despite an 82/100 PSI score. SEO is decent (91/100) but lacks canonical tags and structured data. Confidence is high as all audit tools returned complete data.","confidence":"high","fixes":[{"priority":1,"title":"Optimize images to reduce page weight and LCP","impact":"LCP, Page Weight, CLS","problem":"Images consume 3.75 MB (82% of 4.6 MB total weight); LCP is 6.9 s on mobile. 8 images lack srcset/width/height, and 5 are not lazy-loaded.","solution":"1. Convert all raster images to WebP/AVIF.\n2. Add `srcset` and `sizes` attributes for responsive loading.\n3. Add `width` and `height` attributes to prevent CLS.\n4. Add `loading=\"lazy\"` to non-hero images.\n5. Use `fetchpriority=\"high\"` on the LCP hero image."},{"priority":1,"title":"Strengthen Security Headers (CSP & HSTS)","impact":"XSS Defense, Transport Security","problem":"Security grade is 40/100. HSTS max-age is too short (15552000s) and missing `includeSubDomains`. CSP only sets `frame-ancestors` (missing `default-src`). Site signals indicate User-Generated Content is present, elevating XSS risk.","solution":"1. Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n2. Implement strict CSP with nonce/hash: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none';`.\n3. Add `X-Frame-Options: SAMEORIGIN` as fallback."},{"priority":1,"title":"Fix Critical Accessibility Violations","impact":"WCAG Compliance, Screen Reader Support","problem":"axe-core reports 1 critical violation (image-alt) and 3 serious violations (color-contrast, html-has-lang, link-name). W3C validator confirms 2 img elements missing alt attributes.","solution":"1. Add descriptive `alt` text to all content images (e.g., `alt=\"Larsen house exterior\"`).\n2. Add `lang=\"en\"` to the `<html>` tag.\n3. Ensure link text is discernible (add `aria-label` to icon links).\n4. Adjust CSS to meet 4.5:1 contrast ratio for `.text` elements."},{"priority":2,"title":"Reduce JavaScript Bundle Size and Unused Code","impact":"TBT, FCP, TTI","problem":"1397 KB of unused JavaScript detected in `app-889782a39d4314ef1bf6.js`. Multiple third-party scripts (GTM, GA, PostHog) contribute to long tasks (179 ms, 114 ms).","solution":"1. Code-split the main bundle to defer non-critical JS.\n2. Audit third-party scripts; remove unused tracking pixels (e.g., duplicate GTM/GA instances).\n3. Load non-critical scripts with `defer` or `async`.\n4. Implement resource hints (`preconnect`) for critical third-party origins."},{"priority":2,"title":"Implement Proper Caching Policy","impact":"Repeat Visit Performance, TTFB","problem":"Security Headers report shows `cache-control: not set`. Caching behavior is unpredictable, forcing re-downloads on repeat visits.","solution":"1. Set `Cache-Control: public, max-age=31536000, immutable` for static assets (images, CSS, JS).\n2. Set `Cache-Control: no-cache, must-revalidate` for HTML documents to ensure freshness.\n3. Ensure Vary header is set correctly for content negotiation."},{"priority":3,"title":"Improve SEO Metadata and Structure","impact":"Search Visibility, Indexing","problem":"HTML Inventory shows missing `canonical` tag, `robots` meta, and JSON-LD structured data. W3C validator notes missing `lang` attribute.","solution":"1. Add `<link rel=\"canonical\" href=\"https://larsen.ee/about\">`.\n2. Add `<meta name=\"robots\" content=\"index, follow\">`.\n3. Implement JSON-LD for `LocalBusiness` or `Hotel` schema.\n4. Add Twitter Card meta tags for social sharing."}]},{"url":"https://larsen.ee/faq","overall":45,"reasoning":"Mobile performance is critically low (42/100) with an LCP of 20.6 s and FCP of 10.65 s, primarily due to 1.4 MB of unused JavaScript and a lazy-loaded hero image. Accessibility has 7 violations including 1 critical (image-alt) and 3 serious (lang, contrast, link-name), dragging down the score despite a PSI score of 80. Security headers are weak (40/100) with missing HSTS directives and a permissive CSP, which is risky given the inferred user-generated content signal. HTML validity is poor with 18 W3C errors including obsolete tags and structural issues. The combination of catastrophic load times and critical accessibility/security gaps places this site in the 'Poor' band.","confidence":"high","fixes":[{"priority":1,"title":"Fix Core Web Vitals (LCP/FCP) and Reduce JavaScript","impact":"Performance, LCP, FCP, TBT","problem":"Mobile LCP is 20.6 s and FCP is 10.65 s; 1.4 MB of unused JavaScript identified (e.g., app-889782a39d4314ef1bf6.js).","solution":"1. **Defer/Remove Unused JS:** Audit and remove the 1.4 MB `app-*.js` bundle or split it. Use `defer` for non-critical scripts.\n2. **Fix Hero Image:** Ensure the LCP image (likely the hero) uses `loading=\"eager\"` (or omit) and `fetchpriority=\"high\"`.\n3. **Preload Critical Resources:** Add `<link rel=\"preload\">` for the hero image and critical CSS."},{"priority":1,"title":"Resolve Critical Accessibility Violations","impact":"WCAG 2.1, Screen Reader Usability","problem":"axe-core reports 1 critical (`image-alt`) and 3 serious violations (`html-has-lang`, `color-contrast`, `link-name`).","solution":"1. **Add `lang` attribute:** `<html lang=\"en\">`.\n2. **Fix Image Alt:** Add descriptive `alt` text to all content images (e.g., `Co-Liv.png`).\n3. **Fix Contrast:** Ensure text/background contrast ratio ≥ 4.5:1.\n4. **Label Links:** Add `aria-label` to icon links (e.g., Facebook, Instagram) that lack visible text."},{"priority":1,"title":"Strengthen Security Headers (CSP & HSTS)","impact":"XSS Protection, Transport Security","problem":"Security grade 40/100. HSTS max-age too short (15552000s), missing `includeSubDomains`. CSP is weak (missing `default-src`). UGC signal is 'yes'.","solution":"1. **HSTS:** `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`.\n2. **CSP:** Implement a strict CSP with `default-src 'self'` and nonce-based script execution to mitigate XSS risks from user content.\n3. **X-Frame-Options:** Add `X-Frame-Options: SAMEORIGIN` (or rely on CSP `frame-ancestors`)."},{"priority":2,"title":"Fix W3C HTML Validation Errors","impact":"SEO, Rendering Consistency","problem":"18 W3C errors including obsolete `<font>` tags, duplicate IDs, and `<button>` inside `<a>`.","solution":"1. **Replace `<font>`:** Use CSS for styling (color, size).\n2. **Fix Structure:** Ensure `<button>` is not nested inside `<a>` tags.\n3. **Unique IDs:** Ensure `id=\"what-are-the-prices...\"` is unique across the page.\n4. **Charset:** Move `<meta charset=\"UTF-8\">` to the first 1024 bytes of the document."},{"priority":2,"title":"Optimize Image Delivery","impact":"Page Weight, CLS, LCP","problem":"3 images lack `width/height` (risk of CLS) and `srcset` (no responsive sizing). Hero image incorrectly lazy-loaded.","solution":"1. **Add Dimensions:** Specify `width` and `height` attributes on all `<img>` tags.\n2. **Responsive Images:** Implement `srcset` or `<picture>` for different viewport sizes.\n3. **Hero Image:** Remove `loading=\"lazy\"` from the LCP element."},{"priority":3,"title":"Enable Proper Caching and SEO Metadata","impact":"Repeat Visit Performance, Search Visibility","problem":"No `Cache-Control` header (unpredictable caching), missing `canonical` tag, missing `robots.txt`.","solution":"1. **Cache-Control:** Set `Cache-Control: public, max-age=31536000` for static assets.\n2. **Canonical:** Add `<link rel=\"canonical\" href=\"https://larsen.ee/faq\">`.\n3. **Robots:** Ensure `robots.txt` exists and allows crawling."}]},{"url":"https://larsen.ee/terms-of-service","overall":52,"reasoning":"Mobile performance (60) is dragged down by LCP 4.2 s and TBT 756 ms due to 1.4 MB of JavaScript and a lazy-loaded hero image. Accessibility has critical failures including missing `lang` attribute and `h1` heading alongside 1 critical image-alt violation. Security headers are weak (40/100) with insufficient HSTS age and incomplete CSP despite user-generated content signals. Image optimization is poor with hero lazy-loading and no responsive variants. SEO metadata is largely absent.","confidence":"high","fixes":[{"priority":1,"title":"Reduce JavaScript bundle size and eliminate unused code","impact":"LCP, TBT, FCP, Performance Score","problem":"1398 KB wasted JavaScript (app-889782a39d4314ef1bf6.js) contributes to 756 ms TBT and 4.2 s LCP on mobile.","solution":"- Implement code splitting to load only necessary JS for the Terms page.\n- Tree-shake unused dependencies.\n- Defer non-critical third-party scripts (GTM, PostHog) until after interaction."},{"priority":1,"title":"Fix critical accessibility violations and document structure","impact":"WCAG 2.1 A/AA Compliance, Screen Reader Usability","problem":"1 critical `image-alt` violation, 2 serious violations (`html-has-lang`, `link-name`), and missing `<h1>` heading.","solution":"- Add `lang=\"en\"` to `<html>` tag.\n- Add descriptive `alt` text to all images (e.g., `alt=\"Larsen Hotel Logo\"`).\n- Add a single `<h1>` element describing the page (e.g., `<h1>Terms of Service</h1>`).\n- Ensure all links have discernible text or `aria-label`."},{"priority":1,"title":"Strengthen Security Headers (HSTS and CSP)","impact":"Transport Security, XSS Defense","problem":"HSTS max-age is too short (15552000s) and missing directives; CSP lacks `default-src` despite UGC signals.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Implement strict CSP with nonce/hash: `default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`.\n- Add `X-Frame-Options: SAMEORIGIN` as fallback."},{"priority":2,"title":"Optimize Hero Image and Add Responsive Variants","impact":"LCP, CLS, Data Usage","problem":"Hero image uses `loading=\"lazy\"` (delays LCP) and all 3 images lack `srcset` or explicit dimensions.","solution":"- Remove `loading=\"lazy\"` from the hero image; add `fetchpriority=\"high\"`.\n- Generate WebP/AVIF variants and implement `<picture>` with `srcset`.\n- Add `width` and `height` attributes to reserve space and prevent CLS."},{"priority":3,"title":"Add Missing SEO Metadata and Caching","impact":"Search Visibility, Repeat Load Performance","problem":"Missing `meta description`, `canonical`, and `robots` tags; no explicit `Cache-Control` header.","solution":"- Add `<meta name=\"description\" content=\"...\">` and `<link rel=\"canonical\" href=\"...\">`.\n- Configure server to send `Cache-Control: public, max-age=31536000` for static assets.\n- Ensure Terms page is crawlable (check `robots.txt`)."}]},{"url":"https://larsen.ee/et","overall":45,"reasoning":"Mobile performance is critically low at 43/100 with an LCP of 18.9s and a total page weight of 69MB, which severely degrades user experience. Accessibility is compromised by two critical axe violations (button-name, image-alt) and a missing `lang` attribute. Security headers are weak (HSTS max-age too short, CSP missing default-src), and the presence of user-generated content elevates CSP to a Priority 1 fix per the rubric. W3C validation shows 11 errors including invalid nesting (button inside anchor) and heading hierarchy skips. Despite HTTPS being present, the combination of catastrophic performance and critical accessibility failures places this site in the 'Poor' band.","confidence":"high","fixes":[{"priority":1,"title":"Reduce page weight and fix LCP","impact":"Performance, LCP, FCP, TBT","problem":"Mobile Performance is 43/100; LCP is 18.9s; total page weight is 69MB (56MB media, 12MB images).","solution":"- Compress and resize media assets (videos/images) aggressively.\n- Implement lazy loading for below-fold content.\n- Remove unused JavaScript (1.37MB wasted in `app-889782a39d4314ef1bf6.js`).\n- Enable HTTP/2 or HTTP/3 server push for critical resources."},{"priority":1,"title":"Fix critical accessibility violations","impact":"WCAG 2.1 A/AA compliance, Screen Reader usability","problem":"axe-core reports 2 critical violations: `button-name` (slider dots lack text) and `image-alt` (images missing alt text).","solution":"- Add `aria-label` or visible text to all slider dot buttons.\n- Ensure every `<img>` has a descriptive `alt` attribute (or `alt=\"\"` if decorative).\n- Add `lang=\"et\"` to the `<html>` tag."},{"priority":1,"title":"Strengthen Content Security Policy (CSP)","impact":"XSS protection, Data integrity","problem":"CSP is present but weak (only `frame-ancestors` set); site has user-generated content (reviews), elevating XSS risk per the rubric.","solution":"- Implement a strict CSP with `default-src 'self'`.\n- Use nonces or hashes for inline scripts.\n- Add `object-src 'none'` and `base-uri 'none'`.\n- Example: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`"},{"priority":2,"title":"Fix HSTS and missing security headers","impact":"Transport security, Clickjacking protection","problem":"HSTS max-age is too short (15552000s) and missing `includeSubDomains`; `X-Frame-Options` is missing.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Add `X-Frame-Options: SAMEORIGIN` (or rely on CSP `frame-ancestors`).\n- Add `Permissions-Policy` to disable unused features."},{"priority":2,"title":"Optimize images for responsive delivery","impact":"LCP, Data usage, CLS","problem":"16 images lack `srcset`/`sizes`; 16 lack explicit `width`/`height`; 4 missing `loading=\"lazy\"`.","solution":"- Generate WebP/AVIF variants and serve via `<picture>` or `srcset`.\n- Add `width` and `height` attributes to reserve space.\n- Add `loading=\"lazy\"` to non-hero images.\n- Fix the 1 image missing `alt` text."},{"priority":2,"title":"Correct HTML structure and semantics","impact":"SEO, Accessibility, W3C validation","problem":"W3C reports 11 errors including `button` inside `a` (x5), heading skips (h2→h4), and missing `lang`.","solution":"- Remove `<button>` elements nested inside `<a>` tags; use `<a>` with `role=\"button\"` or separate elements.\n- Fix heading hierarchy (h2 → h3, not h2 → h4).\n- Add `lang=\"et\"` to `<html>`.\n- Add a skip-to-content link for keyboard navigation."}]}]}