A full, self-assessed run through specification.website's technical checklist for what a good website does: every one of its 172 items, checked against this site.
What is specification.website?
specification.website is an open, community-maintained checklist of the technical details that make a good website:
things like a correct <title> tag, working search-engine discovery, color
contrast, security headers, and how legible a site is to the AI agents more people now use to
find things. Each of its 172 items links back to the actual standard behind it, a WHATWG or
W3C specification, an IETF RFC, or WCAG, rather than someone's opinion of best practice.
Most of these items are invisible to a visitor scrolling the page, but they're exactly what
decides whether this site loads fast, works for people with disabilities, keeps visitor data
private, and gets read correctly by both search engines and AI tools. The kevinyoung.net
website is checked against this exact checklist. This page is the result: every item, one
row each, with an honest status.
How this page is scored
specification.website tags every item Required, Recommended, Optional, or Avoid (shown as
the small badge next to each item's name), and this page weights the score to match: a
pass is worth 3 points on a Required or Avoid item, 2 on a Recommended one, and 1 on an
Optional one, since a missing <title> tag matters a lot more than missing
IndexNow support. A partial is worth half of whatever that item's pass is worth, and a fail
is always 0, regardless of tier. Items that don't apply to a site like this one (an OAuth
item on a site with no logins, say) are left out of the score entirely rather than counted
against it. Add up the points earned, divide by the points possible for the items that
actually applied, and that's the percentage at the bottom of the table.
Worth being skeptical of: this audit was done by Claude, the AI assistant that
built most of this site, using its own knowledge of the codebase plus live checks against the
published site. It is not an independent, third-party audit, and a person has not re-verified
every row by hand. Read it as a detailed, honest self-assessment, not a certification.
Status key
PassPass: fully meets the item.
PartialPartial: some of it is done, or done a different way than the spec describes.
FailFail: applies to this site and isn't done.
Not applicableNot applicable: the item doesn't apply to a site like this one.
92.0%
268.5 of 292 applicable points across all 172 checklist items
Foundations
40 / 41 (98%)
specification.website checklist results for Foundations
Status
Checklist item
How kevinyoung.net did
Pass
RequiredThe HTML doctype
<!doctype html> is the first line of every prerendered page.
Pass
RequiredThe lang attribute on <html>
html lang is set per language (en, es, pt) and kept in sync during client-side navigation.
Pass
Required<meta charset>
UTF-8 is declared first in <head>, before any other tag.
Pass
Required<meta viewport>
width=device-width, initial-scale=1, and user scaling is never disabled.
Pass
RequiredThe <title> element
Every page gets one unique <title> from Seo.svelte, separate from its <h1>.
Pass
Recommended<meta name="description">
Every page has its own hand-written description, authored as a direct answer to what the page is.
Pass
RecommendedCanonical URL (rel="canonical")
Every page self-canonicalizes, and reposts point their canonical at the original source instead.
Pass
RecommendedFavicons and app icons
Ships an .ico, 16/32px PNGs, an apple-touch-icon, a manifest with both any and maskable icons (see Web app manifest below), and now a 27 KB static/favicon.svg (a low-poly vector trace of the same photo Kevin generated and hand-optimized, further reduced from 105 KB via SVGO), linked before the .ico so SVG-supporting browsers prefer it. A first vectorization attempt was too heavy to ship (827 KB, 1,481 paths tracing full photographic detail); a lower-fidelity re-trace plus lossless SVGO optimization (whitespace, redundant attributes, integer coordinate rounding) got it to a size actually worth serving, confirmed readable down to 32px.
Pass
Recommended<meta name="theme-color">
Set to match --c-page exactly for the active theme: resolved before first paint by the same inline bootstrap script that sets data-theme, and updated live when the reader toggles the theme.
Pass
Recommended<meta name="color-scheme">
Set as a CSS property tied to the dark-mode toggle, so it changes with the theme rather than sitting as a static tag.
Pass
RecommendedOpen Graph protocol
og:title, og:description, og:image, og:url, og:type and og:locale are set on every page, with alternates for the other two languages.
Pass
RecommendedFeed discovery with rel="alternate"
Every page links to the per-language RSS feed with <link rel="alternate" type="application/rss+xml">.
Pass
RecommendedFeed content hygiene
The feed has a self-referencing atom:link, a stable non-permalink guid per item, and a ttl declaring how often it changes. Confirmed valid by the W3C Feed Validator for all three languages.
Pass
RecommendedPopover API
The Display settings panel and the cookie banner are popover="manual" elements: the browser puts them in the top layer (no z-index) and showPopover()/hidePopover() follow the panels' own state (src/lib/DisplaySettingsPanel.svelte, ConsentBanner.svelte). Manual, not auto, on purpose: the page behind them must stay usable, so the site keeps its own Escape and outside-click handling. Browsers without the API still show them as fixed boxes.
Fail
OptionalWebSub: push notification for feeds
No WebSub hub is advertised for the RSS feed, so subscribers still have to poll for updates rather than being pushed them.
Pass
RecommendedCSS anchor positioning
The Display settings panel is positioned under the button that opened it with position-anchor and anchor(bottom) (src/styles/panels.css). Checked in Chromium: at the largest text size the header grows and the panel moves with it. Where the button is gone (phones open it from the menu, which closes) or anchor positioning is unsupported, the old fixed position applies. Horizontal placement stays fixed to the right edge.
Pass
RecommendedBalanced text wrapping
text-wrap: balance applies to every h1, h2 and h3 sitewide, not just the two About page headings that had it before.
Pass
RecommendedCSS container queries
The Work page's brand-card grids size their columns off the grid's own rendered width (container-type: inline-size plus @container) rather than the viewport. Today that behaves the same as the viewport breakpoints it replaced, since the surrounding .frame tracks viewport width almost 1:1; the win is that the grid would keep sizing correctly if it were ever reused somewhere narrower than the viewport, which a media query can't do. The rest of the site's layout still runs on ordinary viewport breakpoints, which remain the right tool for page-level layout.
Pass
OptionalInvoker commands
The header search button uses command="show-modal" commandfor="search-dialog" and the dialog's close button uses command="close". Once the page has loaded, SearchDialog takes those commands over (it listens for the command event and stops the default action) so the panel, scroll lock and focus stay in step; before that, the browser opens the dialog itself and the page adopts it when it loads. Tested in Chromium 141: click, Escape, Ctrl+K, the mobile menu path and opening before hydration, with no console warnings. Browsers without invoker commands fall back to the click handlers. The Display settings panel and cookie banner still open from JavaScript, because they are popovers with their own state.
Not applicable
Optional_for-sale DNS records
kevinyoung.net is Kevin's own personal site and is not for sale.
SEO
27 / 27 (100%)
specification.website checklist results for SEO
Status
Checklist item
How kevinyoung.net did
Pass
Recommendedrobots.txt
A plain-text robots.txt at the root allows all crawlers and points to the sitemap.
Pass
RecommendedXML sitemaps
sitemap.xml lists every canonical URL with hreflang alternates, generated fresh on every build.
Not applicable
RecommendedSitemap index files
The sitemap holds 45 URLs, far under the 50,000-URL point where an index file would matter.
Not applicable
OptionalImage and video sitemap extensions
Every image is in plain, server-rendered HTML a crawler can already reach directly; nothing is hidden behind client-side JavaScript or an uncrawlable CDN.
Pass
RecommendedURL structure
URLs are lowercase, hyphenated and shallow (e.g. /writing/never-old-learn), with identical slugs across all three languages.
Pass
RequiredRedirects (301/302/308)
The only redirect-like rule on the site (the /es/ and /pt/ 404 rewrites) returns the correct status, and no redirect chains exist anywhere.
Pass
RecommendedServer-side rendering
The whole site is statically prerendered at build time; every page arrives fully formed in the first response, nothing waits on client-side JavaScript.
Pass
AvoidSoft 404s
An unknown URL returns a real 404 status, confirmed live, not a 200 with a "not found" message.
Pass
RequiredMeta robots and X-Robots-Tag
Public pages index by default; noindex is set explicitly on Search, the 404 pages, and the generated text and Markdown copies.
Pass
RequiredHeading hierarchy
One h1 per page, checked in the accessibility audit, with semantic (not styled-only) headings throughout.
Pass
RecommendedInternal linking
Nav, footer, breadcrumbs and in-content links (brand cards, project links, related posts) all tie pages together.
Pass
RecommendedStructured data (JSON-LD)
Person, WebSite, page-type (WebPage/AboutPage/CollectionPage/BlogPosting) and BreadcrumbList JSON-LD are emitted on every indexable page.
Pass
RecommendedBreadcrumbs
Both halves are covered: a visible breadcrumb trail plus matching BreadcrumbList JSON-LD, the visible half added in this audit.
Pass
OptionalIndexNow
Enabled via Cloudflare's Crawler Hints (Kevin's own dashboard setting, not code in this repo): with traffic proxied through Cloudflare, it automatically pings IndexNow-participating search engines (Bing, Yandex, Naver, Seznam) whenever cached content changes, the same mechanism this item is checking for.
Accessibility
60 / 63 (95%)
specification.website checklist results for Accessibility
Status
Checklist item
How kevinyoung.net did
Pass
RequiredColour contrast
Audited with axe-core across every page, both themes, at desktop width and 375px, as recorded on the Accessibility policy page.
Fail
OptionalAutomatic contrasting colour
Text-on-brand-color pairings are hand-picked (a fixed dark ink color) rather than computed with the CSS contrast-color() function.
Pass
RecommendedForced colours mode
Tested with Chromium's forced-colors emulation on Home, Work, a post and Contact, plus the Display settings panel and cookie banner. That test found buttons and cards losing their edges, so a forced-colors block in src/styles/modern.css now gives buttons and cards a real border in system colors and hides the decorative circles. Emulation is not the same as Windows High Contrast on real hardware, which has not been tried.
Pass
RequiredImage alt text
Every img has an alt attribute; a dedicated quality pass found and fixed two weak ones (a post featured image labelled with the post title instead of what the photo shows) and confirmed the rest are genuinely descriptive.
Pass
RequiredForm labels
Every input this codebase controls (the search box) is properly labelled. The Contact and Speaking pages embed Meteor Forms' and Cal.com's own forms in an iframe; their internal labelling is a different origin's markup, not this site's, the same way a linked-to page's accessibility isn't scored as part of this one.
Pass
RequiredKeyboard navigation
A keyboard-only walkthrough (skip link, header controls, mobile menu, search dialog, FAQ disclosure, cookie banner, Display settings panel) found and fixed one real bug: opening Display settings left focus behind on the trigger, so Tab skipped straight past the now-open panel to the next header button instead of into it (it is mounted after Footer, far from its trigger in DOM order). It now moves focus to the panel heading on open, matching the cookie banner's existing pattern.
Pass
RequiredVisible focus indicators
A two-ring :focus-visible outline is defined sitewide, with an optional thicker "enhanced focus" mode.
Pass
RecommendedFocus not obscured
Checked directly at phone width: with the cookie banner or Display settings panel open, several footer links (Cookie settings, the policy links, the text-only-version link) were completely hidden behind the fixed panel with no way to scroll them into view, since the document was already at max scroll. Both panels now measure their own rendered height and reserve that much extra scroll room (and matching scroll-padding-bottom) while open, confirmed against the same links: none end up fully hidden any more, in either panel, and the reserved space disappears again on close.
Pass
RequiredSkip links
A "Skip to main content" link is the first focusable element on every page.
Partial
RecommendedThe inert attribute
The native search dialog gets this for free from showModal(); the custom Display settings and cookie banner panels do not inert the rest of the page, relying on visual layering instead.
Pass
RequiredSemantic HTML and landmarks
header, nav, main and footer are used throughout, confirmed during the axe-core audit.
Pass
RecommendedARIA: first rule of ARIA
Native elements are preferred everywhere; ARIA is added only where nothing native fits, such as the custom panels.
Pass
RequiredDescriptive link text
Links describe their destination ("Read the original," "See all posts in English"); generic "click here" text is not used.
Pass
AvoidEmpty links and buttons
Every icon-only control (search, theme toggle, close buttons) carries an aria-label or visually hidden text.
Not applicable
RequiredAccessible form errors
This site has no form of its own that produces a validation error; the Contact and Speaking page forms are entirely Meteor Forms' and Cal.com's own embedded UI.
Pass
RecommendedStatus messages
Confirmed in SearchPanel.svelte: the result-count text sits in its own role="status" aria-live="polite" element, separate from the results list, so a screen reader announces count changes without the results themselves needing to be re-read.
Not applicable
RecommendedAccessible authentication
There are no accounts or logins anywhere on this site.
Not applicable
RecommendedRedundant entry
There is no multi-step process anywhere on the site that would ask for the same information twice.
Pass
RecommendedConsistent help
Search, Display settings, the theme toggle, and now Cookie settings, all sit in the same header or footer position on every page.
Pass
RequiredDocument and parts language
html lang is always set correctly per language; the site's content does not currently mix languages mid-paragraph.
Pass
RequiredReduced motion
prefers-reduced-motion is respected sitewide, and the site has little decorative animation to begin with.
Pass
AvoidAccessibility overlays
No third-party accessibility widget is used; the Display settings panel is this site's own first-party code, not a bolted-on overlay.
Not applicable
RequiredCaptions and transcripts
The site has no video or audio content.
Pass
RequiredAccessible data tables
Markdown tables get a focusable, scrollable wrapper, scope="col" on every header cell, and an sr-only caption drawn from the heading that introduces the table, all applied automatically by rehype-table-scroll.ts so future tables get them for free.
Pass
RequiredTouch target size
Interactive elements meet the 24 by 24 CSS px minimum sitewide, checked during the layout audit.
Not applicable
RecommendedDragging movements
The one candidate, the Writing carousel, uses native browser scrolling with arrow-button alternatives, not a custom drag gesture, so there is no drag-only interaction to provide an alternative for.
Pass
RecommendedHidden until found
The About page's "Training and courses" disclosure and the Contact page's FAQ accordions are plain native <details>, which auto-expands for find-in-page and fragment navigation on its own (Chrome 97+, Firefox 139+, Safari 26.2) without needing hidden="until-found" (a separate mechanism for hand-hidden, non-<details> content, which this site does not use).
Pass
RecommendedMobile-friendly form inputs
This site's own search input is a plain, correctly-typed text field, the only input this codebase controls. The embedded Meteor Forms and Cal.com forms' input types are a different origin's markup, the same reasoning as Form labels above.
Pass
RecommendedNative interactive elements
button, a, details, a native modal dialog (search) and native popovers (Display settings, cookie banner) are used throughout; nothing is built from clickable divs.
Partial
RecommendedCSS state and relational selectors
:has() and :focus-within are in use (the search field ring, filter chips that style themselves from their checkbox). :user-invalid is not, because the site has no form fields with validation; the contact form is a hosted iframe.
Security
32 / 40 (80%)
specification.website checklist results for Security
Status
Checklist item
How kevinyoung.net did
Pass
RequiredHTTPS and TLS
Served over HTTPS everywhere via Cloudflare and Netlify; plain HTTP redirects to HTTPS.
Pass
RequiredHSTS (Strict-Transport-Security)
Sent with a one-year max-age and includeSubDomains, confirmed live, set through the Cloudflare dashboard.
Pass
RecommendedMixed content and upgrade-insecure-requests
Every subresource loads over HTTPS, and the CSP's upgrade-insecure-requests directive is a safety net.
Pass
RecommendedContent Security Policy (CSP)
Confirmed live and working against production: the cal.com booking widget and Meteor Forms iframe both render and function correctly. It needs 'unsafe-inline' for script-src and style-src on this fully static site, and Cloudflare's own auto-injected analytics beacon is (harmlessly) blocked, since it isn't in the allowlist.
Fail
RecommendedReporting API (Reporting-Endpoints)
No Reporting-Endpoints header is set; there is no third-party collector configured yet to receive CSP or COOP violation reports.
Pass
Recommended/.well-known/security.txt
Published with a contact address and an expiry date.
Pass
RequiredX-Content-Type-Options: nosniff
nosniff is sent on every response.
Pass
RequiredClickjacking protection
Both X-Frame-Options: SAMEORIGIN and the modern CSP frame-ancestors 'self' are set.
Not applicable
RecommendedFetch Metadata request headers
Not applicable: Sec-Fetch-* headers are read by server code to reject cross-site requests, and this is a static site with no server code and no state-changing endpoints. Reclassified from fail to not applicable with Kevin's approval on September 29, 2026. Netlify edge code could read them, but there would be nothing to protect.
Cross-Origin-Opener-Policy: same-origin is set; COEP and CORP were deliberately left out, since COEP could break the cal.com and Google Analytics scripts the site depends on.
Pass
RecommendedReferrer-Policy
strict-origin-when-cross-origin is sent on every response.
Pass
RecommendedPermissions-Policy
Camera, microphone and geolocation are all turned off sitewide.
Fail
RecommendedSubresource Integrity (SRI)
Not used for the cal.com embed script or Google Analytics' gtag.js: both are unversioned third-party scripts that change without notice, so a pinned hash would break on their next deploy, not this site's.
Fail
OptionalDigest Fields
Not implemented.
Fail
RecommendedTrusted Types
Not implemented yet, deliberately: it would stack a second, unverified enforcement layer on top of a CSP that itself has not been confirmed working in production.
Pass
AvoidX-XSS-Protection
Correctly not sent; this dead header is left out, and CSP is relied on instead.
This site sets no cookies of its own at all (theme, Display settings and consent state all live in localStorage), so there is nothing here for this codebase to misconfigure. Google Analytics' cookies, loaded only after consent, are Google's to configure.
Not applicable
OptionalClear-Site-Data
There is no login, logout, or other event on this site that would need to wipe a visitor's storage.
Pass
RecommendedDNS CAA records
issue and issuewild records are published for every CA Cloudflare's Universal SSL can use (Let's Encrypt, Google Trust Services, SSL.com, Sectigo), confirmed live; Cloudflare automatically supplemented a couple more (Comodo, DigiCert) on its own.
Pass
OptionalDNSSEC
Enabled in Cloudflare, with the DS record published at the registrar; confirmed live with a valid RRSIG on the signed answer.
Well-Known URIs
6 / 6 (100%)
specification.website checklist results for Well-Known URIs
Status
Checklist item
How kevinyoung.net did
Pass
RecommendedWell-known URIs
/.well-known/ is used correctly, for security.txt and gpc.json.
Not applicable
Optional/.well-known/change-password
The site has no user accounts, so there is no change-password page to point to.
Not applicable
Optional/.well-known/webauthn
The site does not use passkeys.
Not applicable
Optional/.well-known/openid-configuration
This site is not an OpenID Connect identity provider.
Not applicable
Optional/.well-known/oauth-authorization-server
This site does not run an OAuth authorization server.
Not applicable
Optional/.well-known/oauth-protected-resource
This site exposes no OAuth-protected API.
Pass
Optional/.well-known/gpc.json
Declares that Global Privacy Control is recognized and honored.
Pass
Recommended/.well-known/api-catalog
Published per RFC 9727, as a Linkset (RFC 9264) JSON document listing the sitemap, llms.txt, llms-full.txt and RSS feed for every language, plus robots.txt, with a matching Link: rel="api-catalog" response header sitewide.
Not applicable
Optional/.well-known/webfinger
Not a Fediverse-connected site.
Not applicable
Optional/.well-known/apple-app-site-association
There is no companion iOS app.
Not applicable
Optional/.well-known/assetlinks.json
There is no companion Android app.
Not applicable
Optional/.well-known/nodeinfo
Not a federated platform.
Pass
Optional/.well-known/traffic-advice
Published at /.well-known/traffic-advice (application/trafficadvice+json) with fraction 1.0 for prefetch-proxy, meaning prefetch traffic is welcome. That matches the prefetch speculation rules already in app.html and the AI policy stance of being read.
Agent Readiness
21 / 24 (88%)
specification.website checklist results for Agent Readiness
Status
Checklist item
How kevinyoung.net did
Pass
RecommendedAgent readiness (overview)
Stable URLs, JSON-LD, robots controls and several machine-readable endpoints are all in place, making this one of the stronger categories on this site.
Pass
Recommended/llms.txt
Published per language, listing every top-level page, post and brand with a description.
Pass
Optional/llms-full.txt
Published per language, concatenating every page's Markdown into one file.
Pass
RecommendedPer-page Markdown source endpoints
Every page is available as raw Markdown at a matching .md URL, plus a <link rel="alternate" type="text/markdown">.
Pass
Recommendedrobots.txt for AI crawlers
Kevin's stated position: this is a personal-brand site, so being read, cited and trained on by AI is the point, the same way being indexed by a search engine is. robots.txt now names GPTBot, ClaudeBot, Google-Extended, CCBot, PerplexityBot and others explicitly with Allow: /, instead of relying on the silent User-agent: * default.
Pass
OptionalContent Signals in robots.txt
A Content-Signal: search=yes, ai-input=yes, ai-train=yes line on the User-agent: * block matches the same welcoming stance.
Pass
OptionalTDM reservation (TDMRep)
Published as tdm-reservation: 0 (rights not reserved) in a response header, a meta tag and /.well-known/tdmrep.json, to match robots.txt (Content-Signal ai-train=yes) and the AI policy page, which now says so in all three languages.
Fail
OptionalWeb Bot Auth: verifiable bot identity
Not implemented; no bot is currently allowed or blocked by signed identity.
Pass
RequiredStable URLs
Slugs are permanent and identical across all three languages; nothing has been renamed or broken since launch.
Pass
RecommendedStructured data for agents
The same JSON-LD used for search engines is available to agents: Person, WebSite, page types, and breadcrumbs.
Pass
RecommendedMachine-readable formats
RSS, llms.txt, llms-full.txt and per-page Markdown are all offered alongside the HTML.
Pass
RecommendedHTTP Link headers for discovery
sitemap.xml, llms.txt and rss.xml are now also advertised via a real HTTP Link response header (netlify.toml), language-matched for the /es/ and /pt/ trees, for agents that check headers without parsing the page body.
Not applicable
OptionalMCP and tool discovery
This is a static content site with nothing queryable or actionable to expose as a tool, and no server to run an MCP endpoint on.
Not applicable
OptionalA2A agent cards
The site has no agentic behaviour of its own for another agent to delegate to.
Not applicable
RecommendedAgent Skills discovery
Checked against Cloudflare's own draft RFC (github.com/cloudflare/agent-skills-discovery-rfc): it defines a /.well-known/agent-skills/index.json listing actual scoped instructions/tools an agent can load. This is a static personal-brand site with no such skill or tool to register, the same reasoning as the na status on MCP and tool discovery and A2A agent cards above; publishing an empty or fabricated index would misrepresent what this site offers.
Pass
OptionalDNS for AI Discovery (DNS-AID)
An _index._agents HTTPS record points at kevinyoung.net with the recommended alpn, port and mandatory parameters, confirmed live and DNSSEC-signed.
Not applicable
OptionalAgentic Resource Discovery (ARD)
There are no MCP servers or A2A agents on this domain to catalog.
Fail
OptionalNLWeb: conversational interface discovery
Not implemented; this static site has no natural-language query endpoint to advertise.
Fail
OptionalWebMCP: browser-native tools for agents
Not implemented; there is no in-page tool yet worth exposing to a browser-resident agent.
Not applicable
OptionalOpen Knowledge Format (OKF) bundle
llms-full.txt already serves the "ingest everything in one fetch" purpose OKF targets, at a fraction of the complexity, for a site this size.
Not applicable
OptionalSchemamap
This is specification.website's own proposed, not-yet-adopted convention with no external standard behind it yet.
Performance
41.5 / 49 (85%)
specification.website checklist results for Performance
Status
Checklist item
How kevinyoung.net did
Partial
RequiredCore Web Vitals (LCP, INP, CLS)
Measured with PageSpeed Insights (Lighthouse 13.5) against production, Sep 28, 2026, before and after fixing the image-delivery gap below. No field data exists either way (Chrome UX Report: "No Data", not enough real-user traffic for a site this size). Before: desktop LCP 1.8s, mobile LCP 4.9s, image-delivery opportunity 2,047 KiB, total page weight flagged at 2.7 MB. After re-optimizing the ten post featured images (AVIF/WebP via <picture>, see the Performance section below): desktop LCP nearly halved to 0.9s, mobile Speed Index dropped from 4.2s to 2.5s, the image-delivery opportunity shrank 79% to 430 KiB (now just the hero portrait and a few already-optimized photos wanting slightly tighter sizing, not a format problem), and the "enormous network payload" warning is gone entirely. Mobile LCP barely moved (4.9s to 4.6s, still over Google's 2.5s "good" threshold) despite those other gains, and mobile Performance only ticked up one point (79 to 80); read as lab-run noise from a single throttled run against a live edge network rather than the fix not working, given how much moved everywhere else. CLS (0.000 to 0.001) and TBT (0ms) stayed excellent throughout, on both form factors. Left as partial, not pass: mobile LCP still misses the "good" bar under worst-case simulated conditions and there's still no field data to say real users fare better.
Pass
RequiredImage optimisation
Every photo ships as AVIF and WebP with a jpg or png fallback. Most carry explicit width and height; the ten post featured images (added later, see the Core Web Vitals note above) don't, since two of their three render contexts force a fixed aspect-ratio box in CSS regardless, and CLS was already 0.000-0.001 before they existed. A responsive srcset (multiple widths for different screens) was deliberately skipped: it would add build complexity for savings a single well-chosen size mostly already captures.
Pass
RecommendedLazy loading images, iframes, and video
loading="lazy" is set on every below-the-fold image; the LCP hero images are correctly left eager.
Pass
RecommendedPreload, prefetch, preconnect
The LCP hero image is preloaded, format-matched to the picture element's first source, and third-party origins that load unconditionally (cal.com, Meteor Forms) are preconnected.
Fail
Optional103 Early Hints
Root cause found: Cloudflare's Early Hints replays a Link header from a cached copy of the page, but this site's HTML is intentionally Cache-Control: max-age=0 (cf-cache-status: DYNAMIC), so Cloudflare has nothing cached to replay it from. The Link header itself is confirmed sent correctly; getting an actual 103 would mean making the HTML edge-cacheable, a bigger caching-strategy tradeoff, not done here.
Pass
RequiredCache-Control headers
Hashed build assets get a one-year immutable cache; HTML gets a short, must-revalidate policy, confirmed live.
Pass
RecommendedVary: the cache key contract
Vary: Accept-Encoding is sent, confirmed live, without over-listing headers that would fragment the cache.
No ETag or Last-Modified header is sent on the live HTML response, so every request re-downloads the full body instead of getting a 304.
Pass
RecommendedNo-Vary-Search response header
No-Vary-Search: params is sent sitewide: every page is static prerendered HTML whose content never changes based on a query string (the search page reads ?q=/§ion= client-side, after load), so caches and BFCache can safely treat any two URLs differing only by query params as the same page.
Pass
RequiredCompression (gzip, brotli, zstd)
Brotli is confirmed live (content-encoding: br).
Pass
RecommendedWeb font loading
Fonts are self-hosted WOFF2 with font-display: swap. A post-build step (scripts/preload-fonts.mjs) finds the content-hashed Fraunces and Figtree files and adds a preload link for the subsets each page's language uses. The optional reading fonts in Display settings are not preloaded, so they cost nothing for readers who don't choose them.
Partial
RecommendedCritical CSS and render-blocking resources
Vite and SvelteKit code-split CSS per route automatically, but no manual critical-CSS extraction or inlining has been added on top of that.
Pass
RecommendedScript loading: defer, async, module
Vite emits type="module" for the app bundle; the Google Analytics and cal.com scripts are injected as async.
Pass
RecommendedHTTP/2 and HTTP/3
Confirmed live: HTTP/2 at minimum, with alt-svc advertising HTTP/3.
Pass
AvoidHTTP/1.1 workarounds: sharding, sprites, and bundling
No domain sharding or image sprites are used anywhere.
Pass
RecommendedSpeculation Rules
A sitewide prefetch ruleset (moderate eagerness, same-origin only) was added in this round of work.
Partial
RecommendedResource hints overview
Four of the five hints are used, each for the job the checklist gives it: modulepreload (automatic from SvelteKit), preload (the two fonts and the hero image), preconnect (cal.com on Speaking and Meteor Forms on Contact, where they are certain to be requested) and prefetch (a sitewide speculation-rules ruleset rather than link rel=prefetch). dns-prefetch is not used. The checklist's own example for it is analytics that may or may not fire, which is exactly Google Analytics here. It was left out because a DNS lookup would happen before the visitor has consented; that reasoning is arguable, since a lookup sends far less than a connection does, so this stays partial until it is decided either way.
Pass
OptionalView Transitions
A short crossfade runs on in-app navigation (startViewTransition in GlobalLayout) and on full page loads (@view-transition in src/styles/modern.css). Both are skipped for prefers-reduced-motion and for Simplified view.
Pass
RecommendedBack/forward cache (BFCache)
No unload or beforeunload handlers exist anywhere in the codebase, and the live site's Cache-Control (public, max-age=0, must-revalidate) does not include no-store, the two most common blockers. The Speaking and Contact pages' third-party iframes (cal.com, Meteor Forms) are outside this codebase's control and were not checked.
Pass
OptionalVisibility-aware rendering
content-visibility: auto with a reserved size (contain-intrinsic-size) is set on the below-the-fold Home sections and the footer, so the browser skips laying them out until they near the viewport. Checked that card hover shadows and in-page find are not clipped.
Pass
OptionalCSS containment
Cards use contain: layout style, so their hover animation cannot trigger layout work elsewhere. Paint containment is left off on purpose because it would clip the card glow. The deferred Home sections and footer get paint containment through content-visibility.
Pass
OptionalScroll-driven animations
Posts show a thin reading-progress bar driven by animation-timeline: scroll(), with no JavaScript. It only appears where the feature is supported and motion is allowed, is hidden from assistive technology and Simplified view, and is redundant with the scrollbar.
Pass
RecommendedScrollbar gutter
scrollbar-gutter: stable is set on html sitewide, so gaining or losing a scrollbar no longer shifts content.
Pass
RecommendedDynamic viewport units (dvh, svh, lvh)
The remaining full-height and viewport-relative rules (the layout's min-height, the search dialog's margin, the reading ruler's default position) now use dvh instead of plain vh.
Fail
OptionalCompression Dictionary Transport
Not implemented; a newer technique with limited hosting support at this stage.
Not applicable
OptionalServer-Timing header
This is a fully static site with no backend request processing to measure and report on.
Privacy
13 / 14 (93%)
specification.website checklist results for Privacy
Status
Checklist item
How kevinyoung.net did
Pass
RequiredPrivacy policy
A plain-language policy covers what is collected, Google Analytics, the cookie banner, GPC, and every third party (Cal.com, Meteor Forms, Netlify), in all three languages.
Pass
RequiredCookie consent
A default-deny banner blocks Google Analytics until a visitor explicitly accepts, built in this round of work.
Pass
RecommendedGlobal Privacy Control (GPC)
Honored automatically: a GPC signal turns analytics off with no banner shown and nothing written to storage, and /.well-known/gpc.json declares this.
Pass
RecommendedThird-party scripts and privacy
The only third-party scripts (Google Analytics, cal.com) are consent-gated or page-specific, and both are listed explicitly in the CSP allowlist and the Privacy policy.
Not applicable
OptionalStorage Access API
This site has no embedded cross-site content of its own that would need to request its own cookies.
Partial
RecommendedPrivacy-respecting analytics
Google Analytics is used rather than a cookieless, EU-hosted alternative, but it is now fully consent-gated and GPC-aware, which addresses the consent half of this item even though the tool itself is not the more private option the spec favors.
Pass
RecommendedData minimisation
Only what is needed is collected: no accounts, no combining analytics with other data, and the Contact form only sends what a visitor types into it.
Resilience
8 / 8 (100%)
specification.website checklist results for Resilience
Status
Checklist item
How kevinyoung.net did
Pass
RequiredCustom error pages (404, 500)
A real 404 page returns the correct status, explains what happened in plain language, and links back into the site, confirmed live.
Not applicable
RecommendedMaintenance pages and 503
The site has no planned-maintenance workflow; Netlify keeps serving the last successful build, so there is no maintenance state to design a page for.
Pass
RecommendedGraceful degradation when JavaScript fails
Tested with JavaScript switched off on all 46 pages in the sitemap: each has one h1, its content, no hidden text and no sideways scroll. That test found dead buttons (menu, search, Display settings, theme, carousel arrows, post filters, Cookie settings) and no header navigation, so those controls are now hidden until a script confirms it is running and a plain link row replaces the menu. Search, Display settings and cal.com booking still need JavaScript by nature.
Pass
OptionalOffline support and service workers
A small service worker (static/sw.js, registered in production by GlobalLayout) keeps one offline page and shows it, in English, Spanish and Portuguese, when a page request fails for lack of a connection. Tested in Chromium by stopping the server after the worker took control: every navigation showed the offline page. It caches nothing else, so it cannot serve stale pages, and sw.js is served with no-cache. The Privacy policy says the offline page is stored on the device.
Pass
RecommendedWeb app manifest
site.webmanifest has a name, theme and background color, and now lists both purpose: "any" and purpose: "maskable" icons: the maskable pair are freshly generated, shrinking the existing circular photo crop onto a full-bleed same-color background so the face sits inside the maskable safe zone instead of touching the canvas edge.
Not applicable
RecommendedMonitoring and uptime
This is a hosting and operations decision for Kevin to make, not something the codebase itself can implement.
Not applicable
OptionalDeprecation and Sunset
This site has no API endpoints being retired that clients would need advance warning about.
Not applicable
RecommendedRedirect-By header
There are no genuine HTTP redirects (3xx) configured anywhere on this site right now for the header to attach to.
Internationalisation
20 / 20 (100%)
specification.website checklist results for Internationalisation
Status
Checklist item
How kevinyoung.net did
Pass
RecommendedInternational URL structure
One consistent pattern (subdirectory: /es/, /pt/) is used everywhere, with no mixing of country-domain or subdomain approaches.
Pass
Recommendedhreflang for language and regional URLs
Reciprocal hreflang alternates, plus x-default, are set on every page that has translations, both in <head> and in the sitemap.
Pass
RecommendedLocalised page metadata
Title, description, Open Graph, JSON-LD and breadcrumbs are all translated per language, not just the visible body text.
Pass
Optionalhreflang in XML sitemaps
The sitemap declares language alternates with xhtml:link, not only in the HTML head.
Pass
AvoidAvoid automatic IP-based language redirects
There is no IP- or Accept-Language-based redirect anywhere; visitors choose their language explicitly.
Pass
Requiredlang attribute on inline content
The document-level lang is always correct, and the site's content does not mix languages mid-paragraph anywhere, so there is no inline foreign-language text that would need its own lang attribute. Revisit if a future post ever quotes another language inline.
Pass
Optionaltranslate attribute for untranslatable content
Brand and project names are wrapped or marked translate="no" everywhere they appear as visible text: Markdown pages and posts (text, link text, headings, raw HTML), and every dictionary string through tn() and tnHtml() in src/lib/i18n/translate-no.ts. A scan of all built pages found no unmarked brand name in visible text. Not covered: names inside alt text and aria-labels, and the text-only and Markdown copies.
Pass
RecommendedLanguage switcher
Lists each language by its own name (English, Español, Português) with the correct lang attribute, with no flags.
Not applicable
RecommendedRTL and bidirectional text
The site only serves English, Spanish and Portuguese, none of which are right-to-left languages.
Not applicable
OptionalWriting modes and CJK line breaking
The site serves no Chinese, Japanese, Korean or vertical-script content.
Pass
RecommendedLocale-aware content
Dates are formatted per locale through a shared date helper built on the Intl API.
Pass
RecommendedPlural rules and grammatical number
Result counts are chosen with Intl.PluralRules (src/lib/i18n/plural.ts) using each language's own CLDR rules and formatted with Intl.NumberFormat, so no count logic is hard-coded per language. Only the one and other forms are authored; that covers every count this site shows in English, Spanish and Portuguese.
Not applicable
OptionalInternationalised Domain Names (IDN)
kevinyoung.net is a plain ASCII domain name.
92.0%
Overall score: 268.5 of 292 applicable points (-120 of 172 items were not applicable and don't count toward or against the score)