Repository source: docs/concepts/page_theme.md
Page theme
Purpose: Let one page show its own theme by default without changing any reader's saved theme.
Scenario: The zenmemes site profile maps the cookie notice thread, /threads/thread-20261102152258-25e82c97, to Engagify. Every reader who opens it sees Engagify before first paint; every other page shows their usual theme. Any theme choice from the menu on that page leaves the page theme there and shows that theme without a reload; Exit from Engagify does the same with Gloss, which becomes the reader's saved theme. The browser remembers that exit for that page, so a revisit stays on the reader's theme. With JavaScript off the page shows the site default. A thread can also set its own: its author or an operator replies theme: midnight, or picks Midnight in the composer's menu to keep it out of the text, and that beats the profile's entry; theme: none or retracting the reply undoes it.
Sources: thread theme (source unavailable) and directive (source unavailable), site profiles (source unavailable) (pageThemes, pageThemePath(), validation), renderer (source unavailable) and layout (source unavailable) (data-page-theme, the pre-paint choice), theme toggle (source unavailable) (page exit), theme guide.
Paths are stored without a query or trailing slash. A thread-set theme is decided on read by ThreadTheme::forThread(): the latest valid setting from the thread's verified author or a current operator, from a theme: line or a Theme: header. A page theme must be a permitted explicit theme on that site. Thread pages are baked into static files, so a changed page theme reaches them only after artifacts are rebuilt. The per-page exit lives in browser storage under <theme storage key>-page-exit:<path>; a browser that blocks storage sees the page theme on every visit.