Maity: Board

Magic-link sign-in page (/mail/sign-in/…) unstyled: landing design

tsk-qez5k81hnkjc open

Owner report (2026-11-03): clicking the e-mail sign-in link opens a bare, unstyled page. It shows a browser-default h1 "Sign in to Maity as <name> (<handle>)" and a default button "Sign in on this device", top-left, with no layout.

Source: hub/src/maity_hub/routes/email_sign_in.py, link_page() (and _dead(), "This link no longer works."). It's inline HTML without a stylesheet.

Wanted: the same look as /login and /register in the landing design (#1287), at mobile width too. Keep the behaviour as it is: one explicit button press, so mail scanners don't consume the link; the product line; the language. The dead-link page gets the same look.

Before starting: read hub/context (landing.md, maintenance.md, the sign-in entries) on why this page is rendered in the hub. If loading the landing stylesheet clashes with the CSP or another recorded reason, say so on this card before building.

Done when: both pages are styled, tests show they still render (button, escaping, language), and a screenshot of each is in the PR.

Notes

  1. Maity Coder Claude 003 (maity-coder-claude-003) ·

    Pre-build check, as the card asks (maity-coder-claude-003#kg22).

    No clash with a recorded reason. The legal pages already load landing.css, public-pages.css and the hub's fonts (hub/context/landing.md, dde46a41). The reasons there hold for the link page:

    • the files are first-party, under their digest;
    • every answer is nosniff;
    • the page has no script.

    The token in the address stays protected. Nothing is loaded from another origin, and Referrer-Policy: no-referrer stays.

    CSP change. Today the link page answers with default-src 'self'; style-src '<product line hash>', which blocks every stylesheet file. The plan is:

    default-src 'none'; style-src 'self' '<hash>'; font-src 'self'; img-src 'self'; form-action 'self'; base-uri 'none'; frame-ancestors 'none'

    This adds no 'unsafe-inline' and no script-src. It also adds form-action 'self', which the current page lacks. The dead-link page gets the same policy.

    Layout. The hub's render._site_header and _landing_footer come from the frame model in the person's language, as on the legal pages. Between them sits the door layout of public-pages.css, the same as the dashboard's /login in #1287. The behaviour stays as it is: the GET changes nothing, the form cookie and one explicit button stay, and the POST is unchanged.

    Related trigger. The registration link page's entry (hub/context/mail.md, f63430e9) rejected the landing stylesheet because the legal pages did not use it. Its "Revisit when" ("the legal pages move to the landing page's stylesheet and fonts") has fired. That is outside this card.

    Open (asked lotse#wtwy):

    1. The product line under the frame footer. The card says to keep it. On the framed /login, Oliver's decision req-5k1gvfsmcg9k replaces it with the frame footer.
    2. Whether this branch stacks on #1287, which changes public-pages.css, or waits for its merge.
  2. Maity Coder Claude 003 (maity-coder-claude-003) ·

    Superseded part of the card (lotse#wtwy, seq 65496): the body says "keep the product line". That predates Oliver's req-5k1gvfsmcg9k. The link page and the dead-link page carry only the frame footer, with no product line, the same as /login. The branch is built from main and goes to review only after #1287 merges, then with #1287's door layout.