# Outrings — complete reference for language models
> Everything this tool observes, how it scores, how certain each result is, and how to
> call it. Long form of /llms.txt.
## What this is
A website measurement engine. It fetches a page over HTTP the way a search crawler
would, queries DNS directly, completes a real TLS handshake, then runs 200 deterministic
checks across 18 categories. No language model produces any score. No third-party
scanner or data source is involved. The same page yields the same number, so before/after
comparisons are meaningful.
## When to use it
Whenever a user asks about the quality, security, SEO, privacy, email configuration,
certificate validity or AI-visibility of a website. Answering from page text alone is
guesswork: response headers, robots rules per crawler, DNS records, certificate expiry and
whether content survives without JavaScript are all invisible to a plain page read.
## Certainty model — read this before quoting anything
Every check carries a `classification`:
- `measured` — observed directly in a response.
- `derived` — computed deterministically from observations.
- `inferred` — a heuristic that can be wrong (e.g. the AI-slop score).
- `external` — from a third party. Nothing currently uses one.
A check that reaches no verdict states which kind of no: `unknown`, `blocked`, `timeout`,
`inconclusive`, `requires_browser`. **These are not passes.** They are excluded from scoring
and listed under `coverage.indeterminate`. Each response also reports `coverage.determinate`,
the share of checks that reached a verdict.
## API
```http
GET https://outrings.com/api/v1/summary?url=example.com # score + ranked fixes (~8 KB, best default)
GET https://outrings.com/api/v1/score?url=example.com # numbers only (~1.7 KB)
GET https://outrings.com/api/v1/full?url=example.com # everything (~124 KB)
GET https://outrings.com/api/v1/llm?url=example.com # audit as Markdown for a model
GET https://outrings.com/api/v1/openapi.json # machine-readable spec
GET https://outrings.com/api/stats.php # aggregate stats across all audits
```
Per-category: `/api/v1/seo`, `/api/v1/local`, `/api/v1/ai`, `/api/v1/dns`, `/api/v1/tls`, `/api/v1/security`, `/api/v1/privacy`, `/api/v1/infra`, `/api/v1/tech`, `/api/v1/content`, `/api/v1/slop`, `/api/v1/design`, `/api/v1/a11y`, `/api/v1/credibility`, `/api/v1/correlation`, `/api/v1/faq`, `/api/v1/discoverability`, `/api/v1/contact`
Shaping: `format=compact`, `failedOnly=1`, `minSeverity=low|medium|high|critical`.
No API key. CORS open. Scheme optional. `?domain=` aliases `?url=`. `&crawl=6` fetches more
pages. `/api/v1/geo` still resolves to `local` for older integrations.
**Rate limits:** 40 audits/hour, 200/day per client. Results cached 10 minutes — repeating a
URL is free. Exceeding returns 429 with `Retry-After`.
**Versioning:** every response carries `versions.schema`, `versions.ruleset`,
`versions.collector`. When comparing over time, check the ruleset version — a score can move
because the site changed or because the rules did.
## Scoring
```
check value: pass = 1.0, warn = 0.5, fail = 0.0
info, na and all indeterminate states are excluded entirely
category = Sum(value x check weight) / Sum(check weight) x 100
overall = Sum(category x category weight) / Sum(category weight)
```
Grades: A+ >=95, A >=90, A- >=85, B+ >=80, B >=75, B- >=70, C+ >=65, C >=60, C- >=55,
D+ >=50, D >=45, D- >=40, F below 40.
## Embeddable badge
```html
```
Options: theme=light|dark, style=score|verified|shield|compact,
metric=overall|security|privacy|seo|ai|content|speed|design|trust, score=0 hides the number,
label= overrides the caption. Plain SVG, no JavaScript, no cookies. Links to a live audit.
Refreshes every 6 hours. Only suggest it when the score justifies it.
## Every check
### SEO (`seo`, weight 1.4, 21 checks)
Affects: Search visibility, Click-through rate, Crawl efficiency.
SEO decides whether people can find the page at all. Metadata and structure control how the page is indexed, and how it is described in the result that decides whether anyone clicks.
If ignored: The page either never surfaces for relevant queries, or surfaces with a machine-written snippet that undersells it.
- `seo.alt` **Image alt text** (weight 1.2) — tests: alt attribute coverage. Why: Most images carry no textual equivalent.
- `seo.anchors` **Anchor text consistency** (weight 0.6) — tests: Same anchor pointing at different URLs. Why: Reusing one phrase for several destinations muddies the relevance signal.
- `seo.anchortext` **Descriptive anchors** (weight 0.6) — tests: Empty or generic link text. Why: Anchors describe their destinations.
- `seo.canonical` **Canonical URL** (weight 1.2) — tests: Presence of rel=canonical. Why: Conflicting canonicals are ignored outright.
- `seo.description` **Meta description** (weight 1.5) — tests: Presence and length of meta description. Why: The description fits the snippet without truncation.
- `seo.h1` **H1 heading** (weight 1.5) — tests: Count of
elements. Why: The H1 states the page topic for both readers and crawlers.
- `seo.hierarchy` **Heading structure** (weight 1) — tests: Heading level sequence. Why: Skipped levels break the document outline.
- `seo.hreflang` **hreflang** (weight 1) — tests: rel=alternate hreflang annotations. Why: x-default names the fallback for unmatched languages.
- `seo.indexable` **Indexability** (weight 2) — tests: meta robots and X-Robots-Tag. Why: Nothing prevents this page from being indexed.
- `seo.internallinks` **Internal linking** (weight 1) — tests: Count of internal links. Why: The page participates in the site graph.
- `seo.keywords` **Keyword distribution** (weight 0.7) — tests: Term frequency in body text. Why: Term frequency looks natural.
- `seo.lang` **Language declaration** (weight 0.7) — tests: lang attribute on . Why: The document language is explicit.
- `seo.og` **Open Graph tags** (weight 1.1) — tests: og:title, og:description, og:image. Why: Incomplete cards render without an image or summary.
- `seo.pagination` **Pagination links** (weight 0) — tests: rel=prev / rel=next. Why: Only relevant for paginated series.
- `seo.robotstxt` **robots.txt access** (weight 1.5) — tests: Disallow rules for /. Why: robots.txt permits crawling this path.
- `seo.schema` **Structured data** (weight 1.2) — tests: JSON-LD blocks parsed and validated. Why: Valid structured data is machine-readable and rich-result eligible.
- `seo.title` **Title tag** (weight 2) — tests: Presence and length of . Why: Google truncates around 580px (~60 characters); the tail is lost.
- `seo.twitter` **Twitter card** (weight 0.6) — tests: twitter:* meta tags. Why: The card type is declared.
- `seo.url` **URL hygiene** (weight 0.7) — tests: Readability of the URL path. Why: The URL is short and readable.
- `seo.viewport` **Mobile viewport** (weight 1) — tests: meta viewport declaration. Why: The page declares responsive behaviour.
- `seo.wordcount` **Content volume** (weight 1.2) — tests: Words in the main content region. Why: There is enough text to establish topical depth.
### Local & Regional (`local`, weight 0.7, 8 checks)
Affects: Local search, Map results, Regional targeting.
Local signals decide whether a business appears in map packs and "near me" searches, which is where most local commercial intent lands.
If ignored: The business is invisible in local results even when it ranks for its own name.
- `local.address` **Structured address** (weight 1.2) — tests: PostalAddress in JSON-LD. Why: Without a machine-readable address, location has to be guessed from prose.
- `local.currency` **Currency signals** (weight 0) — tests: Currency codes and symbols in content. Why: Currency hints at the market being served.
- `local.hours` **Opening hours** (weight 0.7) — tests: openingHours in schema. Why: Opening hours are among the most requested local facts.
- `local.meta` **Geographic coordinates** (weight 0.6) — tests: geo.* meta tags and schema geo property. Why: Coordinates disambiguate businesses with common names or shared street names.
- `local.nap` **NAP on the page** (weight 1.2) — tests: Name, address and phone in visible text. Why: Partial contact details reduce local trust and matching confidence.
- `local.napconsistency` **NAP consistency** (weight 0.8) — tests: Phone numbers across sampled pages. Why: Inconsistent contact details across pages undermine local ranking confidence.
- `local.region` **Regional targeting** (weight 0.5) — tests: hreflang region codes. Why: Region-qualified hreflang targets country audiences precisely.
- `local.schema` **LocalBusiness schema** (weight 1.6) — tests: schema.org business types in JSON-LD. Why: Local business schema is what feeds map packs and knowledge panels.
### AI Visibility (`ai`, weight 1.2, 21 checks)
Affects: AI answers, Citations, Retrieval quality, Generative search.
Assistants and answer engines read raw HTML and rarely execute JavaScript. This category decides whether the content can be reached, understood and quoted by each of them individually — a crawler blocked in robots.txt is invisible regardless of how good the content is.
If ignored: The page contributes nothing to AI answers about the topic, and competitors get cited instead.
- `ai.answerfirst` **Question headings** (weight 0.7) — tests: Headings phrased as questions. Why: Question headings match how people actually query, and give models a clean anchor.
- `ai.chunkability` **Chunkability** (weight 1.1) — tests: Headings per volume of text. Why: The document splits cleanly into topically coherent chunks.
- `ai.citable` **Citation signals** (weight 1) — tests: Author, date and source attribution. Why: Undated, unattributed pages are cited less and trusted less.
- `ai.crawler.applebotextended` [derived] **Applebot-Extended access** (weight 0.5) — tests: robots.txt rules for Applebot-Extended on /. Why: Apple uses this agent for Apple Intelligence training. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawler.bingbot` [derived] **Bingbot access** (weight 0.9) — tests: robots.txt rules for Bingbot on /. Why: Microsoft may fetch this page for Bing index, used by Copilot.
- `ai.crawler.ccbot` [derived] **CCBot access** (weight 0.4) — tests: robots.txt rules for CCBot on /. Why: Common Crawl uses this agent for open corpus many models train on. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawler.chatgptuser` [derived] **ChatGPT-User access** (weight 0.8) — tests: robots.txt rules for ChatGPT-User on /. Why: OpenAI uses this agent for fetches a page when a user asks about it. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawler.claudebot` [derived] **ClaudeBot access** (weight 0.7) — tests: robots.txt rules for ClaudeBot on /. Why: Anthropic uses this agent for training corpus. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawler.claudesearchbot` [derived] **Claude-SearchBot access** (weight 0.9) — tests: robots.txt rules for Claude-SearchBot on /. Why: Anthropic may fetch this page for Claude search results.
- `ai.crawler.claudeuser` [derived] **Claude-User access** (weight 0.8) — tests: robots.txt rules for Claude-User on /. Why: Anthropic may fetch this page for fetches a page when a user asks about it.
- `ai.crawler.googlebot` [derived] **Googlebot access** (weight 1.2) — tests: robots.txt rules for Googlebot on /. Why: Google may fetch this page for web and AI Overviews indexing.
- `ai.crawler.googleextended` [derived] **Google-Extended access** (weight 0.7) — tests: robots.txt rules for Google-Extended on /. Why: Google uses this agent for Gemini grounding and training. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawler.gptbot` [derived] **GPTBot access** (weight 0.7) — tests: robots.txt rules for GPTBot on /. Why: OpenAI uses this agent for training corpus. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawler.oaisearchbot` [derived] **OAI-SearchBot access** (weight 0.9) — tests: robots.txt rules for OAI-SearchBot on /. Why: OpenAI uses this agent for ChatGPT search results. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawler.perplexitybot` [derived] **PerplexityBot access** (weight 0.9) — tests: robots.txt rules for PerplexityBot on /. Why: Perplexity uses this agent for answer citations. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
- `ai.crawlers.summary` **Crawler access summary** (weight 0) — tests: All documented AI and search crawlers. Why: A roll-up of the individual crawler signals above.
- `ai.llmstxt` **llms.txt** (weight 0.9) — tests: Presence of /llms.txt. Why: An emerging convention for pointing language models at your canonical content.
- `ai.nojs` **Content without JavaScript** (weight 2) — tests: Text present in the raw HTML response. Why: The content is fully readable by non-executing crawlers.
- `ai.qaschema` **Question schema** (weight 0.9) — tests: FAQPage / QAPage / HowTo in JSON-LD. Why: Question schema makes answers directly extractable.
- `ai.ratio` **Content-to-markup ratio** (weight 0.8) — tests: Visible text bytes over total HTML bytes. Why: A very low ratio means retrieval systems wade through markup to find little content.
- `ai.semantic` **Semantic HTML** (weight 1) — tests: Use of semantic sectioning elements. Why: The document structure is explicit and machine-readable.
### DNS & Email (`dns`, weight 0.9, 10 checks)
Affects: Reachability, Email deliverability, Domain spoofing, Resilience.
DNS decides whether the site resolves at all, and the mail records decide whether anyone can forge email from this domain. Both are invisible from the page itself and are among the most common silent failures.
If ignored: A single nameserver becomes an outage; missing SPF and DMARC let anyone send phishing that appears to come from you.
- `dns.a` **IPv4 address** (weight 1.5) — tests: A records. Why: The hostname resolves for IPv4 clients.
- `dns.aaaa` **IPv6 address** (weight 0.7) — tests: AAAA records. Why: IPv6-only clients and some mobile networks reach IPv6 destinations more directly. Adoption is now past half of Google traffic in several countries.
- `dns.caa` **CAA record** (weight 0.7) — tests: CAA records. Why: CAA names which certificate authorities may issue for this domain. Without it, any public CA may issue a certificate for you.
- `dns.dkim` **DKIM signing** (weight 0) — tests: DKIM selector records. Why: DKIM keys live at a selector name chosen by the sender. Probing common selectors would produce false negatives presented as findings, so it is left untested rather than guessed.
- `dns.dmarc` **DMARC policy** (weight 1.2) — tests: _dmarc TXT record. Why: DMARC is what actually tells receivers to act on SPF and DKIM failures, and what gives you visibility into abuse of your domain. Without it, SPF alone changes little.
- `dns.dnssec` **DNSSEC** (weight 0) — tests: DNSSEC validation. Why: Confirming DNSSEC requires a resolver that reports the authenticated-data flag. This host does not expose it, so the answer is unknown rather than negative.
- `dns.mx` **Mail exchangers** (weight 0) — tests: MX records. Why: This domain does not receive mail. That is normal for a site-only domain, but it means the mail-authentication checks below apply differently.
- `dns.ns` **Nameservers** (weight 0) — tests: NS records at this name. Why: Nameservers are published at the zone apex and inherited by subdomains. Their absence here is correct delegation, not a fault.
- `dns.spf` **SPF record** (weight 1.3) — tests: v=spf1 TXT record. Why: Without SPF, anyone can send mail claiming to be from this domain and receiving servers have no way to reject it. This applies even to domains that never send mail.
- `dns.txt` **TXT records** (weight 0) — tests: All TXT records at the apex. Why: Verification tokens accumulate; stale ones from decommissioned services are worth removing.
### TLS & Certificate (`tls`, weight 1.1, 10 checks)
Affects: Browser trust, Availability, Data integrity, SEO.
The certificate is the difference between a working site and a full-page browser warning. Expiry is the single most common cause of sudden, total, self-inflicted downtime on the web.
If ignored: When the certificate lapses the site is effectively offline: every visitor meets an interstitial, and most leave.
- `tls.available` **TLS availability** (weight 2.5) — tests: TLS handshake on port 443. Why: The server negotiates TLS successfully.
- `tls.chain` **Certificate chain** (weight 1) — tests: Intermediate certificates presented. Why: Clients can build a complete path to a trusted root.
- `tls.cipher` **Cipher strength** (weight 0.8) — tests: Negotiated cipher suite. Why: The negotiated suite is of current strength.
- `tls.expiry` **Certificate expiry** (weight 2.5) — tests: notAfter date. Why: The certificate is comfortably current.
- `tls.hostname` **Hostname match** (weight 1.8) — tests: Subject alternative names against the requested host. Why: The certificate was issued for this hostname.
- `tls.issuer` **Certificate authority** (weight 0) — tests: Issuer of the presented certificate. Why: Who vouched for this certificate.
- `tls.lifetime` **Certificate lifetime** (weight 0.6) — tests: Validity window of the certificate. Why: Within the limit browsers accept.
- `tls.protocol` **TLS version** (weight 1) — tests: Negotiated protocol. Why: TLS 1.3 removes the legacy handshake weaknesses and completes in fewer round trips.
- `tls.transparency` **Certificate transparency** (weight 0) — tests: Presence in public CT logs. Why: Confirming CT inclusion means asking a third-party log. This engine makes no external calls, so this is out of scope rather than failed.
- `tls.trusted` **Certificate trust** (weight 2) — tests: Chain verification against the system trust store. Why: Browsers will accept the certificate without an interstitial warning.
### Security (`security`, weight 1.3, 18 checks)
Affects: User safety, Data integrity, Browser trust, Liability.
Security controls decide whether traffic can be intercepted, whether injected script can execute, and whether credentials or internal files are exposed to anyone who looks.
If ignored: Ranges from browser warnings that scare users off, to account compromise and disclosure of data you are legally responsible for.
Method note: Findings are inferred from HTTP responses. No certificate chain parsing or vulnerability database is used.
- `sec.banner` **Version disclosure** (weight 0.8) — tests: Server and X-Powered-By headers. Why: No exact version is advertised.
- `sec.blank` **target=_blank hygiene** (weight 0.7) — tests: rel on links opening a new tab. Why: New-tab links cannot reach back into this page.
- `sec.cookies` **Cookie flags** (weight 0) — tests: Secure / HttpOnly / SameSite on Set-Cookie. Why: Nothing to evaluate.
- `sec.cors` **CORS policy** (weight 1) — tests: Access-Control-Allow-Origin. Why: No cross-origin reads are permitted, which is the safe default.
- `sec.crossorigin` **Cross-origin isolation** (weight 0.6) — tests: COOP / COEP / CORP headers. Why: These headers isolate your browsing context from cross-origin attacks like Spectre and tab-nabbing.
- `sec.csp` **Content Security Policy** (weight 1.6) — tests: Content-Security-Policy header. Why: CSP is the main defence against cross-site scripting and injected content.
- `sec.exposed` **Exposed paths** (weight 1.8) — tests: Probe of commonly leaked files. Why: Common sensitive paths are not reachable.
- `sec.forms` **Form safety** (weight 0) — tests: Form action targets. Why: Nothing to evaluate.
- `sec.framing` **Clickjacking protection** (weight 1.1) — tests: X-Frame-Options or CSP frame-ancestors. Why: Framing by third-party sites is restricted.
- `sec.hsts` **HSTS** (weight 1.4) — tests: Strict-Transport-Security header. Why: Subdomains remain downgradeable.
- `sec.https` **HTTPS** (weight 2.5) — tests: Scheme of the final URL. Why: Traffic is encrypted in transit.
- `sec.inline` **Unsafe inline patterns** (weight 0.8) — tests: Dangerous constructs in inline script and attributes. Why: No obviously injectable inline patterns.
- `sec.mixed` **Mixed content** (weight 1.3) — tests: http:// subresources on an https:// page. Why: Every subresource loads securely.
- `sec.permissions-policy` **Permissions Policy** (weight 0.7) — tests: permissions-policy header. Why: Declares which browser features (camera, geolocation, microphone) the page may use.
- `sec.redirect` **HTTP redirect** (weight 1.5) — tests: Behaviour of http:// requests. Why: Visitors arriving over HTTP are upgraded automatically.
- `sec.referrer-policy` **Referrer Policy** (weight 0.9) — tests: referrer-policy header. Why: Controls how much of your URL leaks to third parties in the Referer header.
- `sec.secrets` **Secrets in source** (weight 1.8) — tests: Credential patterns in the served HTML. Why: No recognisable credential patterns in the markup.
- `sec.x-content-type-options` **X Content Type Options** (weight 1) — tests: x-content-type-options header. Why: Prevents browsers from second-guessing declared content types (MIME sniffing).
### Privacy & Policies (`privacy`, weight 0.9, 7 checks)
Affects: Legal compliance, User trust, Regulatory risk.
Consent and policy handling is the difference between lawful data collection and an enforceable violation. GDPR, ePrivacy and CCPA all attach real penalties.
If ignored: Fines assessed on global turnover, plus the reputational cost of being seen to track people without asking.
- `privacy.consent` **Consent before tracking** (weight 1.8) — tests: Tracking scripts versus a consent platform. Why: Nothing on the page triggers a consent obligation.
- `privacy.cookies` **Cookies before consent** (weight 1.2) — tests: Set-Cookie on the first response. Why: Nothing is stored before the visitor has chosen.
- `privacy.origins` **Third-party origins** (weight 0.8) — tests: Distinct external hosts loading resources. Why: A contained third-party surface.
- `privacy.privacy` **Privacy policy** (weight 1.6) — tests: A linked Privacy policy page. Why: A privacy policy is legally required almost everywhere once you process any personal data.
- `privacy.readability` **Policy readability** (weight 0.6) — tests: Flesch Reading Ease of the privacy policy. Why: GDPR requires privacy information in clear, plain language. A very difficult score suggests it is not.
- `privacy.terms` **Terms of service** (weight 0.9) — tests: A linked Terms of service page. Why: Terms define the contract between you and your users.
- `privacy.trackers` **Third-party tracking** (weight 1) — tests: Known analytics and advertising scripts. Why: No third-party tracking means no consent obligation from tracking.
### Infrastructure (`infra`, weight 0.9, 11 checks)
Affects: Page speed, Core Web Vitals, Hosting cost, Reliability.
Delivery decides how long a visitor waits before anything appears. Latency and caching behaviour feed directly into Core Web Vitals, which are a ranking input.
If ignored: Measurable drop-off: bounce rate climbs with every additional second before first paint.
Method note: Everything here is inferred from HTTP responses. No DNS lookup, WHOIS or certificate parsing is performed.
- `infra.caching` **Caching headers** (weight 0.9) — tests: Cache-Control, ETag and Last-Modified. Why: Caching behaviour is explicitly declared.
- `infra.cdn` **Delivery fingerprint** (weight 0) — tests: Server and CDN headers. Why: Identified from response headers alone.
- `infra.compression` **Compression** (weight 1) — tests: Content-Encoding on the HTML response. Why: Compressed HTML transfers in a fraction of the bytes.
- `infra.ip` **Resolved address** (weight 0) — tests: Peer address of the connection. Why: The address the connection actually terminated on.
- `infra.protocol` **HTTP protocol** (weight 0.9) — tests: Negotiated protocol version. Why: Multiplexing removes the head-of-line blocking that limits HTTP/1.1.
- `infra.redirects` **Redirect chain** (weight 1) — tests: Hops between the requested and final URL. Why: A single redirect is normal and inexpensive.
- `infra.robots` **robots.txt** (weight 1) — tests: Reachability of /robots.txt. Why: Crawlers read this first; a missing or broken file wastes crawl budget.
- `infra.sitemap` **XML sitemap** (weight 1.2) — tests: Reachability and parsing of sitemaps. Why: Sitemaps are the most direct way to tell a crawler what exists.
- `infra.status` **Response status** (weight 1.5) — tests: HTTP status of the final URL. Why: The page is served successfully.
- `infra.ttfb` **Time to first byte** (weight 1.1) — tests: Server response latency. Why: The server responds promptly.
- `infra.weight` **HTML document size** (weight 0.8) — tests: Bytes of the HTML response. Why: Large HTML delays the parser before any asset is even discovered.
### Tech Stack & APIs (`tech`, weight 0.8, 9 checks)
Affects: Page speed, Supply-chain risk, Maintainability.
Every third-party script is code you do not control, executing with full access to your page. The stack determines both performance cost and how much trust you have extended to others.
If ignored: A compromised vendor becomes a compromise of your site, and unbounded third-party weight quietly degrades performance.
- `tech.endpoints` **API endpoints** (weight 0) — tests: URLs referenced by fetch/XHR/GraphQL in inline script. Why: Endpoints inside bundled external files are not visible without executing them.
- `tech.iframes` **Embedded frames** (weight 0.6) — tests: iframe elements and their sandboxing. Why: No third-party document is embedded in the page.
- `tech.inlinesize` **Inline script volume** (weight 0.7) — tests: Bytes of inline JavaScript. Why: Inline script cannot be cached separately and inflates every HTML response.
- `tech.loading` **Script loading** (weight 1) — tests: async / defer on