---
name: semantic-html
description: "Audits existing HTML for semantic problems and fixes them in small approved batches without breaking styling, scripts, tests or analytics. Runs a read-only standard-library checker that flags clickable divs, links used as buttons, unnamed buttons and links, nested controls, skipped headings, missing main landmark, missing lang, unlabelled navs and images without alt, then applies fixed decision rules for links versus buttons, landmarks, headings, alt text, lists, tables and ARIA, and verifies with the checker, a keyboard pass and a screen reader spot check. Works on plain HTML and rendered React, Vue, Svelte or Angular output. Use whenever someone asks to audit or refactor markup, fix div soup, review a pull request for semantic HTML, choose between a link and a button, fix heading order or landmarks, or add alt text. Do NOT use for form labels, autocomplete or validation (use html-forms), full WCAG or colour-contrast audits, legal conformance statements, SEO metadata or CSS layout."
license: CC-BY-4.0
metadata:
  author: Afeez Adebayo
  author_url: https://afeezadebayo.com
  author_linkedin: https://www.linkedin.com/in/afeez-adebayo/
  author_x: https://x.com/za_icon
  source: https://afeezadebayo.com/skills-md/frontend-development/html-semantics/semantic-html/
  category: frontend-development
  subcategory: html-semantics
  version: "1.0.0"
  created: "2026-10-23"
  updated: "2026-10-23"
---

# Semantic HTML: Audit and Fix Markup Without Breaking the Page

Most markup problems are invisible to the person who wrote them. A `div` with a click handler works with a mouse. A link with `href="#"` opens the chat window. A heading chosen for its font size looks right. Each one fails for keyboard and screen reader users, and each one is easy to miss in review.

This skill makes an agent audit existing HTML, choose the right element for each problem with fixed decision rules, and change the markup in small, approved batches that keep the page's styling, scripts and tracking working. It runs a short read-only checker first, so the work starts from a list of line numbers instead of a guess.

It works on plain HTML and on the rendered output of any framework. Framework notes and tool facts sit in the appendix.

## When to use this skill, and when not to

Use it when the user wants to:

- Audit a page, template or component for semantic problems: missing landmarks, skipped headings, clickable `div`s, links used as buttons, unnamed buttons, missing `alt`.
- Refactor "div soup" into meaningful elements.
- Review a pull request or generated UI code for markup quality.
- Decide between `<a>` and `<button>`, `section` and `div`, or a list and plain paragraphs.

Do not use it for these jobs:

| Request | Use instead |
|---|---|
| Labels, autocomplete, validation and errors in forms | `html-forms.md` |
| Colour contrast, focus styling, motion, or a full WCAG audit | An accessibility audit skill. This skill covers markup only |
| Page titles, meta descriptions and structured data for search | `title-tags-meta-descriptions.md`, `structured-data.md` |
| Visual layout and CSS architecture | Not covered |

## Guardrails that apply to every run

1. **Propose, then change.** The agent reports and proposes first. It edits files only after the user approves a batch, and only on a branch or working copy under version control. It never commits to the main branch, pushes, merges or deploys.
2. **Batches stay small.** At most 10 files or 30 element changes per batch (defaults). Each batch is shown as a diff before it is applied.
3. **Behaviour is preserved.** Every element swap is checked against the CSS selectors, scripts, tests and analytics triggers that target it (step 5). If a swap would break one and the fix is outside the files in scope, the agent stops and asks.
4. **Native before ARIA.** The agent does not add a `role` to make a non-interactive element behave like a control when a native element exists.
5. **Personal data and secrets.** Rendered HTML from logged-in pages can hold names, emails, account numbers, CSRF tokens in hidden inputs and API keys in inline scripts. Run the checker locally. Before sharing any HTML with an external service or pasting it into a prompt, remove inline scripts and the values of hidden inputs, and ask the user. Reports quote line numbers and element names, not page text.
6. **Nothing is invented.** Thresholds in this file are labelled defaults. Tool facts carry a source and the date read. Version-dependent facts carry **verify before relying on this**.
7. **Not legal advice.** The skill improves markup. It does not certify conformance with WCAG or any accessibility law. If the user needs a compliance statement, route it to a qualified human auditor.
8. **Scope boundary.** The agent refuses to rewrite copy, redesign layouts, remove content, or add ARIA to hide a problem it was asked to fix.

## Inputs the agent must have before starting

Ask for what is missing in one message and wait. Do not proceed on assumptions.

| # | Input | What to ask if missing |
|---|---|---|
| 1 | Target | "Which pages, templates or components should I check? Paths or URLs, please." |
| 2 | Stack | "Is this plain HTML, a server template (for example Django, Rails, Twig) or a framework (React, Vue, Svelte, Angular)?" |
| 3 | Rendered output | "Can you save the rendered HTML of each page (browser Save As, or the element's outer HTML from devtools)? The checker reads rendered HTML most reliably." |
| 4 | Safety net | "Is the code in version control, and can I work on a branch?" |
| 5 | Dependants | "Do any CSS files, scripts, tests or tag manager triggers target these elements by tag or class?" |
| 6 | Logged-in pages | "Do any pages show personal or account data when rendered?" |
| 7 | Test tools | "Can you run Python 3 locally, and do you have axe or another automated checker available?" |

If input 4 is no, the agent stops after the report and proposes changes as text only.

## Workflow

### Step 0: Confirm scope and safety

1. Confirm inputs 1 to 7.
2. Confirm the branch. Record the commit the work starts from.
3. Tell the user what will happen: check, triage, decisions, a change plan, approved batches, verification, report.
4. Gate 1: wait for a yes.

### Step 1: Run the checker

1. Save `scripts/semantic_check.py` from this skill folder. It uses only the Python standard library, reads files and writes nothing.
2. Run it on the rendered HTML: `python3 scripts/semantic_check.py page.html`.
3. If only templates are available, run it on them and add "templates only, rendered output not checked" to the report. Template syntax can hide or invent elements.
4. Keep the output. It is the baseline for step 7.

The checker reports these codes. Each line gives the file, line number, level and code.

| Code | Level | Meaning |
|---|---|---|
| `click-on-non-interactive` | error | A `div`, `span`, `li`, `td`, `p`, `img`, `section` or `article` has `onclick`, `@click`, `v-on:click`, `(click)` or `on:click` |
| `link-used-as-button` | error | `href` is empty, `#` or `javascript:` |
| `link-without-href` | error | `<a>` with no `href` cannot take keyboard focus |
| `button-without-name`, `a-without-name` | error | No text, image `alt`, `aria-label`, `aria-labelledby` or `title` |
| `nested-interactive` | error | A link or button inside another link or button |
| `img-missing-alt` | error | `<img>` with no `alt` attribute at all |
| `heading-skip` | error | A heading jumps down more than one level |
| `main-count` | error | Not exactly one `main` landmark |
| `missing-lang` | error | `<html>` has no `lang` |
| `no-h1` | warn | No `h1` on the page |
| `unlabelled-nav` | warn | More than one `nav` and at least one has no label |
| `role-on-non-interactive` | warn | `role="button"` or `role="link"` on a non-interactive element |
| `positive-tabindex` | warn | `tabindex` above 0 changes the tab order |

The checker cannot judge meaning. It does not know whether a heading describes its section or whether `alt` text is useful. Steps 3 and 7 cover that.

### Step 2: Triage

Sort every flag into one of four priority groups. Fix in this order.

| Priority | Codes | Why first |
|---|---|---|
| P1: controls | `click-on-non-interactive`, `link-used-as-button`, `link-without-href`, `*-without-name`, `nested-interactive` | Keyboard and screen reader users cannot reach or understand the control |
| P2: page structure | `main-count`, `missing-lang`, `heading-skip`, `no-h1`, `unlabelled-nav` | Users cannot move around the page or hear it in the right language |
| P3: images | `img-missing-alt` | Content or function is missing for screen reader users |
| P4: order | `positive-tabindex`, `role-on-non-interactive` | Behaviour is unexpected but usually still usable |

Form fields go to `html-forms.md`. List them in the report and do not fix them here.

### Step 3: Decide the element

Use these rules. They are deterministic: the same situation always gets the same element.

**Controls.**

| Situation | Element |
|---|---|
| It changes the URL or loads another page or file | `<a href="real-url">` |
| It does something on this page (opens a dialog, adds to basket, toggles a panel) | `<button type="button">` |
| It submits a form | `<button type="submit">` |
| It shows and hides a section of content with no script needed | `<details>` and `<summary>` |
| It must look like a link but performs an action | `<button type="button">` styled as a link |
| It must look like a button but goes to another page | `<a href>` styled as a button |

The test is "does the URL change?" A link changes the URL. A button does not. Never put a button inside a link, or a link inside a button: pick one element from the table.

**Landmarks.**

| Region | Element | Rule |
|---|---|---|
| Main content | `<main>` | Exactly one per page |
| Site header | `<header>` | Top level of `body`, not inside `main` or `article` |
| Site footer | `<footer>` | Top level of `body` |
| Navigation blocks | `<nav>` | If there is more than one, give each a distinct `aria-label` such as "Main" and "Legal" |
| Related content beside the main content | `<aside>` | Only for content that makes sense apart from the main content |
| A self-contained item (post, product card that stands alone, comment) | `<article>` | It would make sense if lifted on its own |
| A themed group with its own heading | `<section>` | Only when it has a heading. Otherwise use `<div>` |

**Headings.**

1. One `h1` per page, naming what the page is about (default rule).
2. Never skip a level going down: `h2` follows `h1`, `h3` follows `h2`. Going back up any number of levels is fine.
3. Choose the level by the section's place in the outline, never by font size. Change the size in CSS.
4. A heading must describe the content beneath it. A styled sentence that introduces no section is a paragraph.

Do not rely on sectioning elements to change heading levels. The WHATWG spec replaced its outline algorithm in 2022 because no browser implemented it, so an `h1` inside a `section` is still read as an `h1`.

**Images.**

| Image role | `alt` |
|---|---|
| Carries information | Describe the information, not the picture: "Sales doubled between 2024 and 2025" |
| Decorative | `alt=""`, so screen readers skip it |
| The only content of a link or button | Describe the action or destination: "Close", "Home" |
| A complex chart or diagram | A short `alt`, with the full description or data in nearby text |

Never remove the `alt` attribute to mark an image as decorative. A missing `alt` and an empty `alt` behave differently.

**Lists and tables.**

- Items of the same kind in a row or column (menu links, features, steps) go in `ul` or `ol`. A card grid does not need to be a list unless the count or order helps the user.
- A table holds data with rows and columns. Use `th` with `scope="col"` or `scope="row"`. If a table is only for layout, replace it with CSS.

**ARIA.**

1. If a native element does the job, use it and add no role.
2. Add ARIA only for patterns with no native element (tabs, a combobox), and then the element must also get the keyboard behaviour the role promises.
3. `aria-label` on a button or link is for an icon-only control. Do not use it to override visible text.

### Step 4: Write the change plan

For every flag, write one row: file and line, current element, new element, reason (a rule from step 3), and dependants found in step 5. Group the rows into batches of at most 10 files or 30 changes.

### Step 5: Check dependants before each swap

Search the codebase for every tag and class involved. Use the commands in the Templates section.

| Dependant | What breaks | What to do |
|---|---|---|
| CSS selectors by tag (`div.card`, `nav > div`) | Styling disappears | Update the selector in the same batch |
| Button default styles | The new button shows a grey box | Add the button reset from the Templates section |
| Scripts that query by tag or check `tagName` | Handlers stop firing | Update the selector. Keep the class names |
| Event handlers on the old element | Double handling, or Enter fires twice | Remove the manual keyboard handler when moving to a native button |
| `<button>` inside a `<form>` | It submits the form | Always set `type="button"` unless it submits |
| Tests that select by tag or text | Tests fail | Update selectors. Prefer selecting by role and name |
| Tag manager triggers (click classes, element selectors) | Analytics events stop | List them for the user. The agent does not change tag manager settings |

If a dependant sits outside the files in scope, stop and ask the user before changing it.

### Step 6: Apply one batch at a time

1. Show the diff for the batch.
2. Gate 2: wait for a yes for this batch.
3. Apply the batch on the branch.
4. Run step 7 before the next batch.

### Step 7: Verify

1. **Checker.** Re-run `semantic_check.py`. Every flag fixed in the batch must be gone, and no new error may appear.
2. **Keyboard.** Using only the keyboard, Tab through the changed area. Every control receives focus in reading order with a visible focus indicator. Enter activates links. Enter and Space activate buttons.
3. **Screen reader spot check.** Open the headings list and the landmarks list in a screen reader (the rotor in VoiceOver, the elements list in NVDA). Headings form a sensible outline. There is one main region and each navigation has a distinct name.
4. **Automated rules.** Run axe or the team's equivalent on the changed pages. Zero new violations.
5. **Visual.** Compare screenshots before and after. Layout must not shift unless the user approved it.
6. **Tests.** The project's existing tests pass.

Automated checks find only a share of problems. The WebAIM Million 2026 report counted detectable failures on 95.9% of one million home pages and put full conformance at below 4.1%, because only automatically detectable failures were counted. Steps 7.2 and 7.3 are not optional.

### Step 8: Report

Use the report template. State what changed, what is left, what was handed to `html-forms.md`, and what was not checked.

## Worked example

The page below is invented. The checker output is real: it was produced by running the script in this skill on these files.

**Input.** A pricing page, plain HTML, under version control. No CSS targets `div.card` by tag. A tag manager trigger listens for clicks on `.card`.

```html
<!doctype html>
<html>
<head><title>Plans</title></head>
<body>
<div class="top">
  <nav><a href="/">Home</a> <a href="/pricing">Pricing</a></nav>
</div>
<div class="content">
  <h1>Choose a plan</h1>
  <h3>Monthly</h3>
  <div class="card" onclick="selectPlan('pro')">Pro plan</div>
  <a href="#" onclick="openChat()">Talk to sales</a>
  <button class="icon-close"><svg aria-hidden="true"></svg></button>
  <img src="/badge.png">
  <a href="/terms"><button>Read terms</button></a>
</div>
<div class="footer"><nav><a href="/privacy">Privacy</a></nav></div>
</body>
</html>
```

**Step 1, checker output** (tabs shown as spaces):

```
before.html:1   error  main-count                0 main landmarks; expected 1
before.html:1   error  missing-lang              <html> has no lang
before.html:1   warn   unlabelled-nav            2 nav elements, not all labelled
before.html:10  error  heading-skip              h1 followed by h3
before.html:11  error  click-on-non-interactive  <div> has a click handler; use <button> or <a href>
before.html:12  error  link-used-as-button       href="#"; actions belong in <button>
before.html:13  error  button-without-name       no text, alt or aria-label
before.html:14  error  img-missing-alt           /badge.png
before.html:15  error  nested-interactive        <button> inside another link or button
before.html: 8 errors, 1 warnings
```

**Steps 2 and 3, decisions.**

| Line | Decision | Rule |
|---|---|---|
| 11 | `<button type="button" class="card">` | Selecting a plan stays on the page |
| 12 | `<button type="button">` styled as a link | Opening chat does not change the URL |
| 13 | `aria-label="Close"` | Icon-only control |
| 15 | Keep the link, drop the inner button | "Read terms" goes to another page |
| 10 | `h3` becomes `h2` | No skipped levels |
| 14 | `alt=""` | The user confirms the badge is decorative |
| Structure | `header`, `main`, `footer`; `lang="en-GB"`; navs labelled "Main" and "Legal" | Landmark rules |

**Step 5, dependants.** The `.card` class stays, so the tag manager trigger keeps firing. The agent lists it anyway for the user to confirm. The new buttons get the reset styles. `selectPlan` and `openChat` move from inline attributes to listeners on `data-plan` and `data-action`, so the agent shows that script change in the same batch.

**After (one batch, approved):**

```html
<!doctype html>
<html lang="en-GB">
<head><title>Plans</title></head>
<body>
<header>
  <nav aria-label="Main"><a href="/">Home</a> <a href="/pricing">Pricing</a></nav>
</header>
<main>
  <h1>Choose a plan</h1>
  <h2>Monthly</h2>
  <button type="button" class="card" data-plan="pro">Pro plan</button>
  <button type="button" class="link-style" data-action="chat">Talk to sales</button>
  <button type="button" class="icon-close" aria-label="Close"><svg aria-hidden="true"></svg></button>
  <img src="/badge.png" alt="">
  <a href="/terms">Read terms</a>
</main>
<footer><nav aria-label="Legal"><a href="/privacy">Privacy</a></nav></footer>
</body>
</html>
```

**Step 7, checker output:** `after.html: 0 errors, 0 warnings`. The user then runs the keyboard and screen reader checks and confirms them. The report lists one item for the user: confirm the `.card` click trigger still fires in the tag manager preview.

## Templates

### Checker

`scripts/semantic_check.py` ships with this skill. Usage:

```
python3 scripts/semantic_check.py page.html other.html
```

It exits with status 1 if any error is found, so it can run in CI. Read it before running it.

### Finding dependants

```
grep -rnE "div\.card|\.card\b" --include=*.css --include=*.scss src/
grep -rnE "querySelector(All)?\(['\"][^'\"]*card|tagName" --include=*.js --include=*.ts src/
grep -rnE "getByText|querySelector|\.card" --include=*.test.* --include=*.spec.* .
```

Replace `card` with the class or tag being changed.

### Button reset

```css
button.link-style,
button.card {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: pointer;
}
button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
```

### Keyboard check

```
[ ] Tab reaches every control in the changed area, in reading order
[ ] Focus is visible on every control
[ ] Enter follows every link
[ ] Enter and Space activate every button
[ ] No control is reached that should not be (hidden, decorative)
[ ] Shift+Tab moves back in the same order
```

### Report

```
SEMANTIC HTML REPORT: [files], [date], branch [name] from [commit]

Baseline: [n] errors, [n] warnings
Fixed this run: [n] (P1 [n], P2 [n], P3 [n], P4 [n])
Remaining: [list with reason]
Handed to html-forms: [n] form fields
Dependants changed: [CSS, scripts, tests]
Dependants for the user: [tag manager triggers, files out of scope]
Verification: checker [0 errors], keyboard [pass/fail], screen reader [pass/fail],
              automated rules [n new violations], visual [no shift], tests [pass]
Not checked: [rendered output, colour contrast, focus styles beyond changed area]
This report is not a statement of WCAG or legal conformance.
```

### Starting prompt

```
Use the semantic-html skill on [files]. The stack is [stack]. Work on the
branch [name]. Start with the checker and a change plan, and do not edit
anything until I approve a batch.
```

## Failure modes and anti-patterns

| # | Failure | How to spot it | What to do instead |
|---|---|---|---|
| 1 | ARIA patched onto a `div` | `role="button"` and `tabindex="0"` added, but no Enter or Space handling and no disabled state | Replace with `<button type="button">` and a style reset. A native button brings focus, keyboard activation and form behaviour |
| 2 | Heading levels picked for size | `h4` used because it "looks right"; the checker flags `heading-skip` | Pick the level from the outline. Move size into CSS classes |
| 3 | A swap breaks styling, scripts or tracking | Visual diff shows a grey box; a click handler stops; an analytics event stops | Run step 5 before each swap. Keep class names. List tag manager triggers for the user |
| 4 | An automated pass treated as done | The report says "0 errors" and nobody used a keyboard | Run steps 7.2 and 7.3 every time. The checker and axe catch only what can be detected by rule |
| 5 | Links and buttons mixed up | A button inside a link, `href="#"` for actions, a `<button>` that navigates with script | Ask "does the URL change?" and use the table in step 3 |

## Quality bar

Check every item before handing over.

1. The user approved gate 1, and the work is on a named branch.
2. The baseline checker output is saved and quoted in the report.
3. Every flag is in a priority group, fixed, handed to `html-forms.md`, or listed as remaining with a reason.
4. Every element decision cites a rule from step 3.
5. Every batch had at most 10 files or 30 changes and was approved before it was applied.
6. Every `<button>` added has an explicit `type`.
7. Dependants were searched for each changed tag and class, and the result is in the report.
8. The checker shows zero errors in the changed files, with no new errors elsewhere.
9. The keyboard check was run on the changed area and its result is recorded.
10. No `role` was added where a native element exists.
11. No page text, hidden input value or inline script content appears in the report.
12. The report says it is not a conformance statement.

## Cost and effort

The checker runs locally and makes no network calls. The agent reads its output and only the lines it flags, so token use grows with the number of problems, not the size of the page. The cheaper path for a large site is to check templates or shared components first, because one fix there repairs every page that uses them.

## Handoffs to related skills

`html-forms.md` handles every form field the checker or triage surfaces. `core-web-vitals.md` and `javascript-seo.md` cover performance and rendering for search. `structured-data.md` covers schema markup. `ai-evals-testing.md` helps if the team wants to test an agent's markup output at scale.

## Appendix: tool-specific notes

Every fact below was read on 23 October 2026. **Verify before relying on this**: tools and rules change.

### Frameworks

- The checker uses Python's `html.parser`, which lowercases attribute names, so React's `onClick` is read as `onclick`. It also recognises Vue's `@click` and `v-on:click`, Svelte's `on:click` and Angular's `(click)`.
- JSX and template syntax can confuse an HTML parser. Prefer the rendered HTML. When you must check templates, treat results as a first pass.
- Svelte and Vue components keep their directives when an element changes. Keep bindings, keys and component boundaries intact.

### axe-core

Deque's rule `button-name` (axe-core 4.11) checks that buttons and elements with `role="button"` have an accessible name. It maps to WCAG 4.1.2 Name, Role, Value (Level A) and is rated critical impact. Fixes it accepts: inner text, a non-empty `aria-label`, or `aria-labelledby` pointing at text. Input buttons are covered by a separate rule, `input-button-name`.

### WHATWG outline algorithm

The HTML spec replaced its document outline algorithm with one based on heading levels in 2022 (WHATWG pull request 7829, reported by Bruce Lawson on 7 July 2022). No browser had implemented the old algorithm, so nesting an `h1` in `section` never changed its level.

### Claude Agent Skills

Anthropic limits `name` to 64 characters and `description` to 1,024. Claude Code documents `disable-model-invocation: true` for skills with side effects, so they run only when the user calls them. This skill edits files, so that setting suits teams that want manual control. Install skills only from sources you trust.

## Sources

Last verified 23 October 2026 for every source below, except where a date says otherwise.

- WebAIM, The WebAIM Million (2026 report, February 2026 data): https://webaim.org/projects/million/. Failure rates and the ARIA error correlation.
- W3C WAI, Page Structure tutorial: https://www.w3.org/WAI/tutorials/page-structure/. Regions, labels, headings and WCAG mapping.
- W3C WAI, Forms tutorial (updated 27 March 2026): https://www.w3.org/WAI/tutorials/forms/. Used for the handoff boundary.
- Deque University, axe rule button-name (axe-core 4.11): https://dequeuniversity.com/rules/axe/4.11/button-name.
- Bruce Lawson, Why the HTML outlining algorithm was removed from the spec (7 July 2022): https://brucelawson.co.uk/2022/why-the-html-outlining-algorithm-was-removed-from-the-spec-the-truth-will-shock-you/.
- Ben Myers, post on clickable divs (30 September 2019): https://benmyers.dev/blog/clickable-divs/. Everything a clickable `div` needs.
- GrahamTheDev, They...just...won't...learn (27 May 2021, edited 17 December 2021): https://dev.to/grahamthedev/they-just-won-t-learn-a-button-is-a-lt-button-gt-accessibility-rants-k1b. The URL-change rule and why developers reach for `div`s.
- joabgonzalez, ai-agents-skills, html skill (via skills.cat): https://skills.cat/skills/joabgonzalez/ai-agents-skills/html. Rival implementation.
- stolinski, s-stack, html skill (via skillselion): https://skillselion.com/skills/stolinski/s-stack/html. Rival implementation.
- 5dlabs, cto-agents, web-design-guidelines (via skills.sh): https://www.skills.sh/5dlabs/cto-agents/web-design-guidelines. Rival listing, rules not visible.
- Anthropic, Agent Skills best practices (read 22 October 2026): https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices.
- Claude Code documentation, Skills (read 22 October 2026): https://code.claude.com/docs/en/skills.

---
Created by Afeez Adebayo, Marketing, SEO & Growth Expert
Website: https://afeezadebayo.com
LinkedIn: https://www.linkedin.com/in/afeez-adebayo/
X: https://x.com/za_icon
Source: https://afeezadebayo.com/skills-md/frontend-development/html-semantics/semantic-html/

Licence: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). You may copy, share and adapt this skill, including for commercial use, as long as you credit Afeez Adebayo and link to the source URL above. Keep this notice in any copy or adapted version.
