Cloudflare's brand guidelines flag a hand-written "Protected by
Cloudflare" text label as misleading — replace with their official
badge PNG (public/badges/cloudflare-protected.png), same fixed-size
<img> pattern already used for AiDisclosureBadge.
Adds public/llms.txt (llms.txt spec: H1 + summary + linked sections)
describing the product for AI agents/crawlers -- usage-focused only, no
internal vendor/infra details.
Also fixes proxy.ts's middleware matcher, which excludes common static
file extensions from Clerk's auth gate but was missing .txt -- every
request to /llms.txt (and any future .txt file, e.g. robots.txt) was
being redirected to the Clerk sign-in page instead of served. No app
route under src/app uses a .txt path, so this only affects genuinely
static files in public/.
SpeedUp-Plan (Gitea #28) -- last remaining Lighthouse finding.
The old public/app-preview-mobile.png was exactly 327x714px -- 1:1 with
its CSS display size, so retina displays (2x/3x DPR) had no headroom and
Lighthouse flagged it as "serves images with low resolution"
(image-size-responsive, SpeedUp-Plan P2).
Replaced with a fresh feed screenshot supplied by the user, center-cropped
to the same 327:714 aspect ratio and delivered at 981x2142 (3x) as WebP
(~193 KB) so next/image's built-in optimizer has real headroom to generate
a proper srcset instead of upscaling a 1x source.
Owners can now optionally mark uploaded content as AI_MODIFIED or
AI_GENERATED (mutually exclusive, defaults to NONE) across every upload
surface — photo posts, video posts, milestones, stories, and pet avatars.
Once set, the choice is owner-immutable; only a moderator can correct it
via a new admin.setAiDisclosure mutation (Posts admin page), which
requires a reason and writes to ModerationLog like every other
moderation action.
The disclosure renders as a UI-only overlay badge (the two provided
label assets) wherever the content is shown — feed, post detail, story
viewer, milestone cards, and the pet profile avatar — never baked into
the image pixels.
New shared components: AiDisclosureSelect (the 3-way picker used in all
five upload forms) and AiDisclosureBadge (the overlay renderer).
Gitea #11 follow-up comment: the phone mockup previously showed the
desktop feed layout squeezed into a phone bezel. Swaps in an actual
mobile-view screenshot (portrait, bottom tab bar) so the mockup reads
as a real app screen. Repositions the three floating badges to clear
the screenshot's own header and tab bar, since the new portrait image
is much taller than the old near-square desktop capture.
Replaces the sharp-stitched sidebar+feed composite with a cleaner
screenshot the user captured directly, and switches the Image from
fill+aspect-[16/10] (cropping) to its natural 872x926 size since the
new capture has a different aspect ratio and shouldn't be cropped.
Regional-indicator flag emoji render as bare "GB"/"DE" text on stock
Windows (no color-flag font substitution), which defeated the point
of switching from text labels to flags — swaps in small inline SVG
flag components instead, guaranteed to render everywhere.
Also re-crops the app-preview screenshot: the original had a wide
empty gap between the sidebar and the feed column baked into the
capture (an artifact of the live app's centered-column layout at that
viewport width). Stitches the sidebar and feed regions together
tightly via sharp instead.
The new public landing page (/) was hero-only — missing a language
switcher, legal links, and anything showing what the product actually
looks like. Adds:
- A slim header with the wordmark and a flag-based language switcher
(LanguageSwitcher now shows 🇬🇧/🇩🇪 instead of English/Deutsch text,
used here and everywhere else it's already mounted)
- An app-preview section: a real screenshot of the live feed inside a
browser-chrome mockup card
- A 4-item feature overview (pet-first profiles, posts/stories/video,
health tracking, pet-to-pet messaging)
- A footer with Impressum/Datenschutz/AGB links, matching what the
authenticated sidebar already links to