Audit

20260713T121009Z-1f44

← Back to demoplayandnopecom
Audited URL
https://demo.playandnope.com/
Timestamp
2026-07-13T12:11:39.688Z
Kind
single
Pages
1
Audit summary
https://demo.playandnope.com/
Pagespeed scores
Other checks
LLM Report

Weighted audit summary

82
Overall site quality
Needs Improvementhigh confidence

PSI mobile 99 and desktop 99 indicate excellent performance with LCP 1.8 s and CLS 0.014. Accessibility is strong with 0 axe violations, though W3C reports 10 errors including invalid ARIA attributes and semantic issues. Security is the primary weakness: HTTP does not redirect to HTTPS and the Security Headers grade is 20/100 due to missing HSTS and weak CSP. Console errors indicate a broken third-party script (CookieYes). The overall score reflects high technical quality in rendering and a11y, penalized significantly for transport security configuration.

Audit Report: Tere tulemast Paws N' Play veebilehele! — gotoAndPlay Demo WordPress Base

Website: https://demo.playandnope.com/
Date: 2026-07-13

Overall Score: 82 / 100
Status: 🟡 Needs Improvement
Confidence: high
Audit Coverage: 100% — all sources returned data

Summary

PSI mobile 99 and desktop 99 indicate excellent performance with LCP 1.8 s and CLS 0.014. Accessibility is strong with 0 axe violations, though W3C reports 10 errors including invalid ARIA attributes and semantic issues. Security is the primary weakness: HTTP does not redirect to HTTPS and the Security Headers grade is 20/100 due to missing HSTS and weak CSP. Console errors indicate a broken third-party script (CookieYes). The overall score reflects high technical quality in rendering and a11y, penalized significantly for transport security configuration.

PageSpeed Insights — Mobile vs Desktop

Lower is worse for Performance; higher is worse for LCP and CLS. Worse value is bolded.

Strategy Performance (M / D) LCP (M / D) CLS (M / D)
Mobile vs Desktop 99 / 99 1.82 s / 795 ms 0.014 / 0.003

Optimization Checklist

4 of 6 passing — 4 pass · 1 warn · 1 fail · 1 n/a

Item Status Detail
Page caching plugin / CDN active Pass Caching plugin detected (WP Rocket)
Images lazy-loaded Pass All non-hero raster images use loading="lazy".
Hero image eagerly loaded Fail 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".
Hero is a real <img> (not a CSS background-image) N/A No CSS background-images detected on raster-image-eligible elements.
Responsive images (srcset / <picture>) Pass 20/20 raster images use srcset or <picture> (100%).
Reasonable number of image sizes Pass 48 distinct srcset widths.
JS scripts not blocking in <head> Warn 1 render-blocking script in <head>. Move to footer or add defer/async.

Fixes

Priority 1: Critical

Immediate action — impacts user experience, search rankings, or site safety.

1A. Force HTTPS Redirect

  • Impact: Transport security, MITM protection
  • Problem: http://demo.playandnope.com/ does not redirect to HTTPS, leaving users vulnerable to interception on the initial request.
  • Solution: Configure the web server (Apache/Nginx) to return a 301 redirect for all HTTP traffic to HTTPS:
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

1B. Add HSTS Header

  • Impact: Security Headers grade, browser enforcement
  • Problem: strict-transport-security is missing; grade is 20/100. HSTS prevents protocol downgrade attacks.
  • Solution: Add the following header with max-age >= 1 year:
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    

Priority 2: Important

Essential for compliance, user reach, and search visibility.

2A. Fix W3C Validation Errors

  • Impact: Accessibility, SEO, Standards compliance
  • Problem: 10 errors found including invalid aria-expanded (empty value), target on <span>, and script defer misuse.
  • Solution:
    • Set aria-expanded="true" or "false" (not empty) on buttons.
    • Remove target from <span>; move to <a> if needed.
    • Remove defer from <script type="text/rocketlazyloadscript"> or change type to valid MIME.

2B. Resolve Console Error (CookieYes)

  • Impact: Reliability, Third-party script execution
  • Problem: Console logs 403 error for cdn-cookieyes.com/client_data/.../script.js (net::ERR_ABORTED).
  • Solution: Verify CookieYes configuration or update the script ID in the WordPress plugin settings. If the script is no longer needed, remove the snippet from the theme or plugin.

Priority 3: Best Practice

Recommended for long-term maintainability.

3A. Optimize Hero Image Loading

  • Impact: LCP, Core Web Vitals
  • Problem: Optimization Checklist flags hero image has loading="lazy", which can delay LCP despite current 1.8 s score.
  • Solution: Remove loading="lazy" from the LCP element (hero image) and add fetchpriority="high":
    <img src="hero.jpg" alt="..." fetchpriority="high" width="..." height="...">
    

3B. Disambiguate Link Text

  • Impact: Accessibility, SEO
  • Problem: Vague link text repeated: "loe rohkem" (read more) ×3, "koerte rühmatreeningud" ×3.
  • Solution: Make link text unique per context or add aria-label:
    <a href="/dogs-training" aria-label="Koerte rühmatreeningud">Loe rohkem</a>
    
▸Raw Markdown sent to the LLM
# Audit — https://demo.playandnope.com/

Run: 2026-07-13T12:10:09.058Z

## Audit Coverage
**100%** of audit sources returned data.

_All sources OK._

## Methodology

Each tool below contributes data to a single overall 0–100 site quality score. Performance dominates the weighting (~40%), followed by accessibility (~30%), image assets (~15%), and SEO/security (~15%). These weights are informative — the score is judged holistically, not from a fixed formula.

Severity scale in `priorities[]`:
- **high** — blocking issue / vulnerability / fail.
- **medium** — significant degradation.
- **low** — minor improvement.

Each tool section below lists: scores → priority fixes → findings → manual checks the tool cannot verify.

## Site Signals (inferred)

Heuristic site-shape signals derived from the audit data. Use these to calibrate the priority of security-header recommendations (see system rubric). Override when the evidence is clearly wrong.

- Auth surface: no
- Payments: no
- User-generated content: no
- E-commerce: no

## PageSpeed Insights
_Captured in 15170 ms (mobile + desktop in parallel)._

**Lighthouse scores (mobile vs desktop; worse value bolded):**
| Category | Mobile | Desktop |
| --- | --- | --- |
| Performance | 99 | 99 |
| Accessibility | 100 | 100 |
| Best Practices | 96 | 96 |
| SEO | 92 | 92 |

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **1.8 s** | 0.8 s |
| CLS | **0.014** | 0.003 |
| TBT | 0 ms | 0 ms |
| FCP | **1.67 s** | 755 ms |
| Speed Index | **1.67 s** | 755 ms |
| TTFB | 3 ms | 3 ms |

### Priority fixes
1. **image-delivery-insight** (medium) — Est savings of 34 KiB
2. **network-dependency-tree-insight** (high)
3. **render-blocking-insight** (high) — Est savings of 200 ms
4. **unused-css-rules** (medium) — Est savings of 21 KiB

### Findings (mobile)

#### Layout-shift sources
- div#page > div.main > main#main > div#section-669a6c258a5526-76547752 — shift 0.014

#### DOM size
- Total nodes: 0

#### Failing modeled audits
- SEO: `robotsTxt`
- SEO: `tapTargets`
- SEO: `structuredData`
- Best Practices: `errorsInConsole`

#### All failing PSI audits (sorted by weight × failure margin)
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `errors-in-console` (best-practices, score 0.00, weight 1) — Browser errors were logged to the console
- `robots-txt` (seo, score 0.00, weight 1) — robots.txt is not valid

### Manual checks
- Real-device behavior on slow 3G / low-tier mobile hardware (Lighthouse is throttled simulation).
- Sustained INP under typical user interaction, not just initial load.
- CrUX data interpretation if site is low-traffic and field data falls back to origin or is missing.

## Security Headers & HTTP
_Captured in 82 ms._

**Transport:**
- Final URL: https://demo.playandnope.com/
- Status: 200
- Redirected: false
- HTTPS redirect: ✗ http://demo.playandnope.com/ does not redirect to HTTPS (target: none)

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Mon, 13 Jul 2026 08:01:07 GMT
- expires: Mon, 13 Jul 2026 12:10:09 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: n/a
- Decoded body: 126.5 KB

### Priority fixes
1. **HTTP does not redirect to HTTPS** (high) — http://demo.playandnope.com/ does not redirect to HTTPS
2. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
3. **content-security-policy weak** (high) — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
4. **x-content-type-options missing** (medium) — Send X-Content-Type-Options: nosniff
5. **referrer-policy missing** (low) — Set a Referrer-Policy such as strict-origin-when-cross-origin
6. **permissions-policy missing** (low) — Declare Permissions-Policy to disable unused features
7. **cross-origin-opener-policy missing** (low) — Set COOP to same-origin to isolate browsing context
8. **cross-origin-resource-policy missing** (low) — Set CORP to same-origin or same-site to prevent cross-origin reads
9. **x-permitted-cross-domain-policies missing** (low) — Set to none to prevent Flash/PDF cross-domain requests
10. **server header discloses technology** (low) — Server: Apache

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (weak, high) `frame-ancestors 'self';` — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
- **x-frame-options** (present, medium) `SAMEORIGIN`
- **x-content-type-options** (missing, medium)
- **referrer-policy** (missing, low)
- **permissions-policy** (missing, low)
- **cross-origin-opener-policy** (missing, low)
- **cross-origin-resource-policy** (missing, low)
- **x-permitted-cross-domain-policies** (missing, low)

#### Info disclosure
- Server: `Apache`


#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
date: Mon, 13 Jul 2026 12:10:09 GMT
expires: Mon, 13 Jul 2026 12:10:09 GMT
keep-alive: timeout=5, max=100
last-modified: Mon, 13 Jul 2026 08:01:07 GMT
server: Apache
transfer-encoding: chunked
upgrade: h2,h2c
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
```

### Manual checks
- Cookie attributes set via JavaScript (not visible in HTTP response).
- CORS preflight behavior under non-GET methods (only GET response headers checked).
- HSTS preload list inclusion (check hstspreload.org).
- WAF / DDoS posture beyond what static headers reveal.

## W3C HTML Validator
_Captured in 862 ms._

**Scoring:** 10 errors · 9 warnings · 40 cosmetic (suppressed)

### Priority fixes
1. **Bad value “” for attribute “aria-expanded” on element “button”.** (medium) — x4, first at line 1312
2. **A “script” element with a “type” attribute whose value is neither a JavaScript MIME type, “module”, “importmap”, nor “speculationrules” (i.e., a data block) must not have a “defer” attribute.** (medium) — x3, first at line 1595
3. **Attribute “target” not allowed on element “span” at this point.** (medium) — x2, first at line 418
4. **Attribute “area-hidden” not allowed on element “form” at this point.** (medium) — x1, first at line 468

### Issue groups
- (×1) [warning] The “type” attribute is unnecessary for JavaScript resources. — first at line 33 `banner --><script id="cookieyes" type="text/javascript" src="https://cdn-cookiey`
- (×2) [error] Attribute “target” not allowed on element “span” at this point. — first at line 418 `<span class="header-navigation__link" target="_self">Koerad`
- (×1) [error] Attribute “area-hidden” not allowed on element “form” at this point. — first at line 468 `<form id="header-search" class="header__search-form" area-hidden="true" role="se`
- (×4) [warning] Article lacks heading. Consider using “h2”-“h6” elements to add identifying headings to all articles. — first at line 1084 `<article class="card carousel__card">
    <`
- (×4) [error] Bad value “” for attribute “aria-expanded” on element “button”. — first at line 1312 `<button
                    aria-controls="accordion-mis-on-paws-n-play-panel"
 `
- (×4) [warning] Section lacks heading. Consider using “h2”-“h6” elements to add identifying headings to all sections, or else use a “div” element instead for any cases where no heading is needed. — first at line 1325 `<section
                    aria-labelledby="accordion-mis-on-paws-n-play-heade`
- (×3) [error] A “script” element with a “type” attribute whose value is neither a JavaScript MIME type, “module”, “importmap”, nor “speculationrules” (i.e., a data block) must not have a “defer” attribute. — first at line 1595 `</script>
<script type="text/rocketlazyloadscript" data-wp-strategy="defer" defe`

### Manual checks
- Whether each `<section>` / `<article>` wraps semantically meaningful content.
- Language tag accuracy for multi-language pages or quoted content.
- Whether structural choices align with the document outline algorithm in screen readers.

## axe-core (Accessibility)
_Captured in 1860 ms._

**Scoring:** 0 violations · 44 passes · critical 0 · serious 0 · moderate 0 · minor 0

### Incomplete (axe could not determine)
- [ARIA attributes must conform to valid values](https://dequeuniversity.com/rules/axe/4.11/aria-valid-attr-value?application=playwright) — 4 nodes

### Manual checks
- Keyboard-only navigation flow + visible focus indicators on every interactive element.
- Screen reader output (NVDA, VoiceOver) for actual auditory experience.
- Modal focus trapping and restoration on close.
- Touch target sizes (44×44 px minimum per WCAG 2.5.8).
- Color contrast for elements with alpha-transparency or gradients (axe skips these).

## Browser Runtime
_Captured in 1872 ms._

**Capture summary:** 1 console events · 0 mixed-content requests · 32 network requests · 602.9 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| image | 17 | 461.9 KB |
| font | 2 | 81.5 KB |
| stylesheet | 5 | 31.7 KB |
| script | 5 | 23.7 KB |
| other | 1 | 4.1 KB |
| document | 1 | 0 B |
| xhr | 1 | 0 B |

**Third-party origins (by bytes):**
- https://fonts.gstatic.com — 2 requests, 81.5 KB
- https://cdn.jsdelivr.net — 2 requests, 13.2 KB
- https://fonts.googleapis.com — 2 requests, 0 B
- https://cdn-cookieyes.com — 1 request, 0 B

**Slowest requests (top 5):**
- https://cdn-cookieyes.com/client_data/29b8e2e5821bed2234ee953c/script.js (script) — 124 ms, 0 B
- https://demo.playandnope.com/wp-content/plugins/wp-rocket/assets/js/wpr-beacon.min.js (script) — 92 ms, 7.9 KB
- https://demo.playandnope.com/wp-content/themes/wordpress-base/inc/theme/js/core.370dc6350c7d77f5.js (script) — 88 ms, 2.6 KB
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (script) — 83 ms, 10.1 KB
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (script) — 73 ms, 3.0 KB

### Priority fixes
1. **failed request** (medium) — script: https://cdn-cookieyes.com/client_data/29b8e2e5821bed2234ee953c/script.js — net::ERR_ABORTED
2. **console error** (medium) — Failed to load resource: the server responded with a status of 403 ()

### Findings

#### Failed requests
- script: https://cdn-cookieyes.com/client_data/29b8e2e5821bed2234ee953c/script.js — net::ERR_ABORTED

#### Console events
- [error] Failed to load resource: the server responded with a status of 403 () (https://cdn-cookieyes.com/client_data/29b8e2e5821bed2234ee953c/script.js)

### Manual checks
- Console output during user interaction (load-only capture).
- Behavior on slow networks and constrained devices.
- WebGL / canvas FPS profiling via DevTools Layers panel.
- Service worker / cache behavior on repeat visits.

## HTML Inventory
_Captured in 1872 ms._

**Document:**
- Lang: et
- Title: Tere tulemast Paws N' Play veebilehele! — gotoAndPlay Demo WordPress Base
- Canonical: https://demo.playandnope.com/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 124950

**Meta tags:**
- Description: Paws N’ Play on koht, kus loomaarmastajad saavad uurida võimalusi, kuidas lemmikloom saab elada täisväärtuslikku, mängulist ja tervislikku elu.
- Robots: follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 13 (og:locale, og:type, og:title, og:description, og:url, og:site_name, og:updated_time, og:image, og:image:secure_url, og:image:width, og:image:height, og:image:alt, og:image:type)
- Twitter tags: 8
- hreflang:
  - en → http://demo.playandnope.com/en/
  - et → http://demo.playandnope.com/
  - x-default → http://demo.playandnope.com/
- JSON-LD: 1 blocks (1 valid) — types: Unknown

**Heading outline:**
- Counts: h1 ×1, h2 ×3, h3 ×8, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: Tere tulemast Paws N’ Play veebilehele!
  - h2: Loomaomanikule
  - h3: Avastama
  - h3: Koeraomanikule
  - h3: Värskele loomaomanikule
  - h3: Toidu- ja veevajadused
  - h3: Hügieen ja hooldus
  - h3: Tervis
  - h3: Füüsiline ja vaimne stimulatsioon
  - h3: Sotsialiseerumine ja tähelepanu
  - h2: Uudised
  - h2: Korduma kippuvad küsimused

**Landmarks:**
- nav: present
- main: present
- header: present
- footer: present
- Skip-to-content link: present

**Scripts:** 23 total — 3 defer, 1 async, 1 render-blocking. Speculation rules: yes.

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (defer)
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (defer)
- https://cdn-cookieyes.com/client_data/29b8e2e5821bed2234ee953c/script.js
- https://demo.playandnope.com/wp-content/themes/wordpress-base/inc/theme/js/core.370dc6350c7d77f5.js (defer)
- https://demo.playandnope.com/wp-content/plugins/wp-rocket/assets/js/wpr-beacon.min.js (async)

**Stylesheets:** 5 external, 3 inline (9.4 KB)

**Images:** 20 total — **0 without alt**, **0 without width/height**, 0 without loading="lazy"

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| content/uploads/2024/06/6027eb05ed4efb000419981a-155x155.png | _(empty)_ | 155×155 | lazy | ✓ |
| content/uploads/2024/06/6027edfeed4efb0004199826-280x138.png | _(empty)_ | 280×138 | lazy | ✓ |
| content/uploads/2024/06/6027f14eed4efb0004199839-242x155.png | _(empty)_ | 242×155 | lazy | ✓ |
| content/uploads/2024/06/6027f242ed4efb000419983e-280x139.png | _(empty)_ | 280×139 | lazy | ✓ |
| content/uploads/2024/06/6027ecebed4efb0004199821-280x149.png | _(empty)_ | 280×149 | lazy | ✓ |
| 5647e48451dac28def9d4150b4d24-removebg-preview-1-233x155.png | _(empty)_ | 233×155 | lazy | ✓ |
| 5f2a034cbe55634ea49e13518b4-removebg-preview-1-1-233x155.png | _(empty)_ | 233×155 | lazy | ✓ |
| 2024/06/attachment_33573462-removebg-preview-1-1-155x155.png | _(empty)_ | 155×155 | lazy | ✓ |
| -content/uploads/2024/06/6027ed7eed4efb0004199823-280x75.png | _(empty)_ | 280×75 | lazy | ✓ |
| -content/uploads/2024/06/6027efe7ed4efb0004199832-280x61.png | _(empty)_ | 280×61 | lazy | ✓ |
| -content/uploads/2024/06/6027eae1ed4efb0004199819-280x41.png | _(empty)_ | 280×41 | lazy | ✓ |
| /wp-content/uploads/2024/07/royal-canin-logo-svg-280x106.png | _(empty)_ | 280×106 | lazy | ✓ |
| s/2024/07/41644975_232057294130286_8841412687386948258_n.jpg | _(empty)_ | 667×834 | lazy | ✓ |
| ayandnope.com/wp-content/uploads/2024/07/img_4145-scaled.jpg | _(empty)_ | 1920×2560 | lazy | ✓ |
| ayandnope.com/wp-content/uploads/2024/11/img_5959-scaled.jpg | _(empty)_ | 1920×2560 | lazy | ✓ |

**Links:** 47 anchors — 8 external, 1 preconnect, 1 preload.

Vague repeated link text:
- "koerte rühmatreeningud" ×3
- "kasside rühmatreeningud" ×3
- "loe rohkem" ×3
- "paws n' play" ×2
- "teenused" ×2
- "uudised" ×2
- "tiim" ×2
- "kontakt" ×2
- "koerad" ×2
- "kassid" ×2

**Forms:**
Form 1:
- search — labeled

### Priority fixes
1. **Vague link text repeated** (medium) — "loe rohkem" ×3

### Manual checks
- Visual rendering of detected mojibake (browser may auto-correct for display).
- Whether decorative images correctly use empty `alt=""` (vs. content images missing it).
- Whether headings reflect actual document hierarchy semantically.
- Whether vague link text is disambiguated by `aria-label` or surrounding context.

## Optimized-Web Checklist
_Captured in 0 ms._

**Summary:** 4 pass · 1 warn · 1 fail · 1 n/a

**Checklist:**
| Item | Status | Detail |
| --- | --- | --- |
| Page caching plugin / CDN active | ✓ pass | Caching plugin detected (WP Rocket) |
| Images lazy-loaded | ✓ pass | All non-hero raster images use loading="lazy". |
| Hero image eagerly loaded | ✗ fail | 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". |
| Hero is a real <img> (not a CSS background-image) | – n/a | No CSS background-images detected on raster-image-eligible elements. |
| Responsive images (srcset / <picture>) | ✓ pass | 20/20 raster images use srcset or <picture> (100%). |
| Reasonable number of image sizes | ✓ pass | 48 distinct srcset widths. |
| JS scripts not blocking in <head> | ! warn | 1 render-blocking script in <head>. Move to footer or add defer/async. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23`
- Hero image eagerly loaded:
  - `hero: …ayandnope.com/wp-content/uploads/2024/06/6027eb05ed4efb000419981a-155x155.png`
  - `loading: lazy`
  - `fetchpriority: (not set)`
- Reasonable number of image sizes:
  - `widths: 100, 116, 124, 150, 155, 200, 225, 233, 240, 242, 248, 280, 300, 310, 324, 400, 410, 483, 500, 510, 512, 560, 600, 626, 648, 667, 700, 768, 800, 840, 959, 972, 1024, 1120, 1152, 1284, 1296, 1400, 1440, 1472, 1536, 1680, 1920, 1944, 1960, 2048, 2240, 2560`
- JS scripts not blocking in <head>:
  - `https://cdn-cookieyes.com/client_data/29b8e2e5821bed2234ee953c/script.js`

### Priority fixes
1. **Hero image eagerly loaded** (high) — 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".
2. **JS scripts not blocking in <head>** (medium) — 1 render-blocking script in <head>. Move to footer or add defer/async.

### Manual checks
- Cart / checkout / logged-in pages must bypass the page cache or load dynamic regions via AJAX.
- Verify the cache is warmed for the canonical URL on initial deploy (first visitor should not pay the cold-start cost).
- Inspect "hero" image visually — heuristic above picks the first/largest <img>, which may not match the actual LCP element on JS-heavy pages.
- Confirm scripts marked as defer/async actually tolerate deferred execution (some legacy snippets break when reordered).