What changed, and why
Every page's footer showed Privacy ยท Terms ยท Disclaimer ยท Contact, and all four were href="#" placeholders โ on a product that takes real money through Stripe. No policy document existed anywhere, and there was no support address for refund or account help. Issue #234 flagged it after an adversarial review.
This PR publishes the three documents as static pages (/terms, /privacy, /disclaimer), points the footer at them, and shows the support address. The blast radius is deliberately small: three new prose-only pages, the footer component, one new constant, and a handful of corrected comments elsewhere. No game logic, no store, no server route changes.
The documents are the risky part, because a legal page that misdescribes the product is a defect you can't lint for. Every product claim in them was grounded in the code first, then adversarially fact-checked against it by an independent review pass; three claims failed that check and were corrected before this landed (see the last section).
One address, one constant
The support address appears in the footer and in all three documents. It lives once, in utils/site-meta.ts โ the module that already owns the brand strings โ so the footer and the three documents can't drift apart.
The one new export. Everything else in the file is untouched.
utils/site-meta.ts ยท 87 lines
โฏ 26 lines hidden (lines 1โ26)
โฏ 56 lines hidden (lines 32โ87)
hello@playeverwhen.com matches the production domain. The drafts this work started from predated the domain move and said everwhen.gg, which resolves to nothing; that address appears nowhere in the shipped pages.
Terms of Service: the document states what the code does
The page is static prose in the house idiom โ hairline sections, serif headings, existing utility classes only. The text is the finalized agreement: Two Ls LLC (Minnesota), 18+, Hennepin County courts, a $50 / trailing-12-months liability cap. Three spots deserve a reviewer's attention.
Accounts (ยง3) describes sign-in as it actually works: a third-party provider (Google or Discord), never a password. AI content (ยง5) carries the no-reliance core: outputs are fiction, not fact, not advice. Payments (ยง9) speaks the game's own vocabulary โ runs and one-time packs, never "plays" โ and settles the refund policy: final except where law requires, discretionary otherwise, with the EU/UK immediate-delivery withdrawal acknowledgment.
ยง3 Accounts and ยง9 Runs, purchases, and payments. Expand the fold to read the full document โ the whole agreement is in this file.
pages/terms.vue ยท 432 lines
โฏ 63 lines hidden (lines 1โ63)
โฏ 172 lines hidden (lines 79โ250)
โฏ 136 lines hidden (lines 297โ432)
Privacy Policy: precise about moderation, providers, and cookies
Same idiom, thirteen sections. The novel parts are the ones a generic template can't write: how player text flows through AI providers, and what the moderation stack actually screens.
Section 4 names the flow exactly. Inputs go to Anthropic (or OpenAI, if generation is routed there); both the player's messages and the core per-turn responses pass through OpenAI's moderation endpoint plus an Anthropic model. And it names the cut honestly: derived narration like the run's chronicle is composed from already-screened turns and is not separately screened โ which is the repo's documented moderation boundary, not an oversight.
ยง4 AI processing (with the chronicle cut named) and the ยง5 provider list. The full policy is in the fold.
pages/privacy.vue ยท 431 lines
โฏ 158 lines hidden (lines 1โ158)
โฏ 38 lines hidden (lines 208โ245)
โฏ 168 lines hidden (lines 264โ431)
The Disclaimer page
A one-screen, plain-language restatement of the Terms' fiction and no-reliance clauses (ยง4, ยง5, ยง10): portrayals of real people are invented, AI output can be wrong, nothing is advice, don't type personal information. It exists for the visitor who lands on a shared run and will never read a 17-section agreement.
Short enough to read whole โ expand for the full page.
pages/disclaimer.vue ยท 109 lines
Comment drift fixed, and how this was verified
Publishing a policy makes stale comments visible: the repo treats a comment that contradicts shipped fact as a bug to fix in the same PR. Four lines qualified โ three "magic link" references from before sign-in went OAuth-only, and a color-mode comment claiming cookie persistence when the module persists to localStorage (which the privacy page now states).
Both corrected comments; the config values are untouched.
nuxt.config.ts ยท 109 lines
โฏ 23 lines hidden (lines 1โ23)
โฏ 18 lines hidden (lines 31โ48)
โฏ 56 lines hidden (lines 54โ109)
Verification, in order: eslint clean on every changed file, format:check clean, nuxt typecheck clean, and the unit suite green at 1350/1350 across 134 files. Then the app was booted and all five affected routes screenshotted in light and dark, at 375 and 1280 widths, and at tall and short heights for the /play guard.
The independent adversarial pass reviewed the documents against the code, refute-first. It confirmed eleven claims and killed three: the "automatic fallback" wording (no such mechanism), a blanket "responses are checked" claim (the chronicle is a documented moderation cut, now named), and "game state in localStorage" (run drafts persist server-side in Supabase). It also tightened the OAuth-profile disclosure, reassigned hosting from Supabase to DigitalOcean, and flagged the desk-footer squeeze that the max-height guard now handles.