# Portal Login RTL And Theme Design

## Goal

Update the customer portal login screen so Hebrew/RTL users get correct reading direction, accessible theme switching, and token-based colors with readable contrast in dark and light modes.

## Scope

This covers `apps/zync-app/src/routes/portal/login.tsx`. The route is the only unauthenticated customer portal login surface in `zync-app`; `apps/zync-app/src/routes/oauth/authorize.tsx` is not a login form and does not share this UI problem.

## Architecture

Use the existing app-level locale and theme systems. `apps/zync-app/index.html`, `RootLocaleSync`, and `LocaleProvider` already set `<html lang>` and `<html dir>` from the active locale. `ThemeProvider` and `ThemeToggle` already persist `ui_theme` and apply the `.dark` class.

The login route should consume `useLocale()` for direction and copy selection, and render `ThemeToggle` directly. It should avoid hardcoded bright-on-bright color combinations by using the existing semantic CSS tokens (`--bg`, `--surface`, `--line`, `--ink`, `--ink-soft`, `--accent`, `--accent-contrast`, `--color-error`) and theme-aware utility classes where available.

## Components

- `PortalLoginPage`: remains the only component in the route. It owns form state, request/verify mutations, localized copy, and layout.
- Existing `ThemeToggle`: rendered in the login header with an accessible label. No new toggle component is introduced.
- Existing `Input`, `Button`, and `Stack`: continue to be used for the form.

## Data Flow

1. User enters email.
2. `requestMagicLink(tenantId, email)` calls `POST /api/portal/auth/request`.
3. Success switches the page to token-entry mode.
4. User enters token.
5. `verifyToken(tokenInput)` calls `POST /api/portal/auth/verify`.
6. Success navigates to `/portal/${tenantId}/dashboard`.

Theme selection is independent of auth state and persists through `ThemeProvider`. Direction is read from `useLocale()` and applied to the route container as `dir={dir}` so the login card follows the current locale even if embedded independently.

## UX Requirements

- Hebrew locale uses Hebrew copy and `dir="rtl"` on the login surface.
- English locale uses English copy and `dir="ltr"`.
- Email and token inputs keep LTR text entry with `dir="ltr"` because email addresses and tokens are LTR data.
- Button text must remain readable in both light and dark modes.
- The theme toggle is visible before authentication.
- Error messages use semantic error color and are announced via `role="alert"`.
- Layout remains centered and responsive without relying on nested cards.

## Testing

Add focused tests around the route:

- Render with Hebrew locale and verify the outer login surface has `dir="rtl"` while the email input has `dir="ltr"`.
- Render with English locale and verify `dir="ltr"`.
- Verify the theme radiogroup is present and can switch to light/dark/system through the existing `ThemeToggle`.
- Verify request and verify error messages still render with `role="alert"`.

## Architecture Decisions

- Accepted collapse: no new `AuthShell` component. Deleting it would not scatter meaningful complexity because only one login route currently needs it.
- Accepted collapse: no new theme persistence hook. `ThemeProvider`, `useTheme`, and `ThemeToggle` already hide the persistence and DOM class logic.
- Rejected candidate: adding a separate locale toggle to this screen. The user requested RTL support, not locale switching; the app already owns locale selection elsewhere.
