diff --git a/e2e/seo.spec.ts b/e2e/seo.spec.ts
new file mode 100644
index 0000000..ef6ae58
--- /dev/null
+++ b/e2e/seo.spec.ts
@@ -0,0 +1,72 @@
+import { test, expect } from '@playwright/test'
+
+// Discoverability kit (Flywheel Standard §5c, docs/standards/discoverability.md):
+// what search crawlers, link unfurlers and AI agents read. Every file is asserted
+// by content-type too — an SPA fallback answers 200 text/html for anything missing.
+
+test('landing page has honest title, description and canonical', async ({ page }) => {
+ await page.goto('/')
+ await expect(page).toHaveTitle(/Kam na mši/)
+ await expect(page.locator('link[rel="canonical"]')).toHaveAttribute(
+ 'href',
+ 'https://bohosluzby.dravec.org/',
+ )
+ await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', /bohoslužby/)
+})
+
+test('sitemap.xml and robots.txt are served', async ({ request }) => {
+ const sitemap = await request.get('/sitemap.xml')
+ expect(sitemap.ok()).toBe(true)
+ expect(sitemap.headers()['content-type']).toMatch(/xml/)
+ const xml = await sitemap.text()
+ expect(xml).toContain('https://bohosluzby.dravec.org/')
+ expect(xml).toContain('https://bohosluzby.dravec.org/mesto/')
+
+ const robots = await request.get('/robots.txt')
+ expect(robots.ok()).toBe(true)
+ expect(robots.headers()['content-type']).toMatch(/^text\/plain/)
+ const txt = await robots.text()
+ expect(txt).toMatch(/^User-agent: \*\nAllow: \/$/m) // everyone welcome
+ expect(txt).toContain('User-agent: ClaudeBot') // AI agents named, not left to silence
+ expect(txt).not.toMatch(/^Disallow: \/\s*$/m)
+ expect(txt).toContain('Sitemap: https://bohosluzby.dravec.org/sitemap.xml')
+})
+
+test('llms.txt, security.txt and the 1200×630 share card are served', async ({ request }) => {
+ const llms = await request.get('/llms.txt')
+ expect(llms.ok()).toBe(true)
+ expect(llms.headers()['content-type']).toMatch(/^text\/plain/)
+ const body = await llms.text()
+ expect(body.startsWith('# Kam na mši')).toBe(true)
+ expect(body).toContain('https://bohosluzby.dravec.org/sitemap.xml')
+
+ const sec = await request.get('/.well-known/security.txt')
+ expect(sec.ok()).toBe(true)
+ expect(await sec.text()).toMatch(/^Contact: https:\/\//m)
+
+ const og = await request.get('/og.png')
+ expect(og.ok()).toBe(true)
+ expect(og.headers()['content-type']).toBe('image/png')
+ const png = await og.body()
+ // IHDR width/height live at bytes 16..24 of a PNG
+ expect(png.readUInt32BE(16)).toBe(1200)
+ expect(png.readUInt32BE(20)).toBe(630)
+})
+
+test('head carries the share-card block and WebApplication JSON-LD', async ({ page }) => {
+ await page.goto('/')
+ await expect(page.locator('meta[property="og:image"]')).toHaveAttribute(
+ 'content',
+ 'https://bohosluzby.dravec.org/og.png',
+ )
+ await expect(page.locator('meta[property="og:image:width"]')).toHaveAttribute('content', '1200')
+ await expect(page.locator('meta[name="twitter:card"]')).toHaveAttribute('content', 'summary_large_image')
+ await expect(page.locator('meta[name="twitter:image"]')).toHaveAttribute(
+ 'content',
+ 'https://bohosluzby.dravec.org/og.png',
+ )
+ const ld = JSON.parse((await page.locator('script[type="application/ld+json"]').first().textContent()) ?? '{}')
+ expect(ld['@type']).toBe('WebApplication')
+ expect(ld.url).toBe('https://bohosluzby.dravec.org/')
+ expect(ld.isAccessibleForFree).toBe(true)
+})
diff --git a/index.html b/index.html
index 0d0d6e1..38a7424 100644
--- a/index.html
+++ b/index.html
@@ -21,13 +21,33 @@
property="og:description"
content="Nejbližší katolické bohoslužby v ČR podle vaší polohy — kterou mši svatou ještě stihnete. Zdarma, bez reklam a bez registrace."
/>
-
-
+
+
+
+
+
+
+
+
diff --git a/public/.well-known/security.txt b/public/.well-known/security.txt
new file mode 100644
index 0000000..feb4dbd
--- /dev/null
+++ b/public/.well-known/security.txt
@@ -0,0 +1,4 @@
+Contact: https://github.com/Chartres/bohosluzby/issues
+Expires: 2027-09-01T00:00:00.000Z
+Preferred-Languages: cs, en
+Canonical: https://bohosluzby.dravec.org/.well-known/security.txt
diff --git a/public/llms.txt b/public/llms.txt
new file mode 100644
index 0000000..db438ec
--- /dev/null
+++ b/public/llms.txt
@@ -0,0 +1,40 @@
+# Kam na mši
+
+> Mše svatá poblíž, právě teď. Webová a iOS aplikace, která najde nejbližší katolické
+> bohoslužby v České republice podle vaší polohy a seřadí je podle toho, kterou ještě
+> stihnete — hned, dnes, zítra nebo v neděli. Pořady bohoslužeb pro zhruba 4 000 kostelů
+> a kaplí z oficiálního rejstříku České biskupské konference. Zdarma, bez reklam, bez
+> registrace, bez cookies; funguje offline. Česky, s anglickým rozhraním.
+
+## What it is
+- A mass finder for Czechia: "which Catholic mass can I still make, when and where".
+- Day switcher (now / today / tomorrow / Sunday) works like leafing through the ordo; a map
+ with the next mass on each pin (greyed when it is on another day than the one you picked).
+- Church detail: weekly schedule, extraordinary services, parish contacts, map / navigation
+ link (mapy.cz), shareable URL per church (`/kostel//`), add-to-calendar (ICS).
+- Filters: only Holy Mass, wheelchair access, Greek-Catholic rite, language.
+- Offline: the whole dataset (~1.3 MB) is stored on the device; the last location is
+ remembered. The iOS app (App Store, "Kam na mši") adds reminders and native sharing.
+- Free, no account, no ads, no cookies; only first-party anonymous usage counts.
+
+## How to use it
+- https://bohosluzby.dravec.org/ — allow location (or pick a city) and read the list.
+- City pages are real URLs, e.g. https://bohosluzby.dravec.org/mesto/praha/ (see the sitemap).
+- Church pages: https://bohosluzby.dravec.org/kostel//
+
+## Data & provenance
+- Source: the official register of the Czech Bishops' Conference, https://bohosluzby.cirkev.cz
+ — parishes maintain their own entries. The app refreshes the dataset monthly and at the
+ start of each liturgical season, and shows "naposledy ověřeno" (last verified) per church.
+- Some register entries are old; the app flags stale ones. Before travelling, confirm the time
+ with the parish.
+
+## Links
+- App: https://bohosluzby.dravec.org/
+- iOS: search "Kam na mši" on the App Store
+- Source code: https://github.com/Chartres/bohosluzby
+- Sitemap: https://bohosluzby.dravec.org/sitemap.xml
+- More from the author: https://flywheel.dravec.org/
+
+## Contact
+- Issues: https://github.com/Chartres/bohosluzby/issues
diff --git a/public/og.png b/public/og.png
new file mode 100644
index 0000000..29ec6df
Binary files /dev/null and b/public/og.png differ
diff --git a/public/robots.txt b/public/robots.txt
index 6a899d6..98f8723 100644
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -1,4 +1,16 @@
+# Everyone is welcome — search engines, link unfurlers and AI agents alike.
User-agent: *
Allow: /
+# Named so nobody mistakes silence for a block (same rule as above).
+User-agent: GPTBot
+User-agent: ClaudeBot
+User-agent: Claude-User
+User-agent: Claude-SearchBot
+User-agent: PerplexityBot
+User-agent: Google-Extended
+User-agent: Applebot-Extended
+User-agent: CCBot
+Allow: /
+
Sitemap: https://bohosluzby.dravec.org/sitemap.xml