diff --git a/docs/redesign/phase-7/COMMITS.md b/docs/redesign/phase-7/COMMITS.md
index 462c0c2..bd5429f 100644
--- a/docs/redesign/phase-7/COMMITS.md
+++ b/docs/redesign/phase-7/COMMITS.md
@@ -2,11 +2,11 @@
Every completed checkpoint or coherent repair is committed and pushed normally to `codex/ui-redesign-phase4`, with immediate direct remote=HEAD verification. Production main remains `27657f31131cd95d42f0e1290853ec9c9b3959a4`; no force push, main push or automatic deployment.
-Entry is the completed Phase6 successor receipt `b5319981ad3d1bd635daff861453d23c0de5320b`. Its [historical ledger](../phase-6/COMMITS.md) retains P6-05 `4669fb42e604c4728e8c420846ba78f298a8d90c` and original runtime provenance. Application source is unchanged from P6-03 `bd47214bdcd74336788dca0f294b8ddb9403cac1`; measured export `2LDblja_XnSBWSuY6ys_V`.
+Entry is the completed Phase6 successor receipt `b5319981ad3d1bd635daff861453d23c0de5320b`. Its [historical ledger](../phase-6/COMMITS.md) retains P6-05 `4669fb42e604c4728e8c420846ba78f298a8d90c` and original runtime provenance. At P7-00 entry, application source was unchanged from P6-03 `bd47214bdcd74336788dca0f294b8ddb9403cac1`; inherited measured export `2LDblja_XnSBWSuY6ys_V`. Later migration rows record their own changed source/build identity.
| Logical unit | Commit | Validation / push receipt |
|---|---|---|
-| P7-00 inventory, preservation/debt and unchanged-source baseline | PENDING — coordinator records actual hash after normal push | [P7-00](p7-00/README.md), [fresh finite baseline](p7-00/evidence/baseline.json); inherited runtime explicitly separated. P7-01 page changes wait for this push/remote verification |
+| P7-00 inventory, preservation/debt and unchanged-source baseline | `27c54146ad6f9059295d169b533db7b1b6689210` | [P7-00](p7-00/README.md), [fresh finite baseline](p7-00/evidence/baseline.json) and [static checks](p7-00/evidence/static-checks.json); inherited runtime explicitly separated. Normal development push verified2026-10-11 14:44:45UTC: localHEAD=origin=live development27c5414; local/origin/live main unchanged27657f3; clean worktree. P7-01 entry dependency satisfied |
Hashes and remote receipts are appended by a successor to avoid self-referential commit hashes. Each row records actual commands/results, source scope, remaining conditions, normal push and immediate direct remote identity; partial or blocked evidence is recorded without inventing success. Subsequent receipt metadata is a separately reviewable documentation unit, with its own hash reported after push rather than an endless receipt chain.
diff --git a/docs/redesign/phase-7/p7-01/README.md b/docs/redesign/phase-7/p7-01/README.md
new file mode 100644
index 0000000..2a18be0
--- /dev/null
+++ b/docs/redesign/phase-7/p7-01/README.md
@@ -0,0 +1,90 @@
+# P7-01 — Authentication and account-security presentation
+
+**Status: public authentication sub-slice CONDITIONAL GO; account-security implementation/acceptance PENDING.** This is the bounded execution/acceptance plan from the [approved handoff](../../phase-6/p6-05/PHASE7_HANDOFF.md). P7-00 `27c54146ad6f9059295d169b533db7b1b6689210` is pushed and direct development/localHEAD/origin equality verified at2026-10-11 14:44:45UTC; main unchanged and worktree clean at entry. Its [baseline](../p7-00/evidence/baseline.json) and [ledger](../COMMITS.md) satisfy entry. No new routes, identity/provider protocols or capability activation are included. Public source/results below are measured before their commit; the parent records its push receipt separately. This sub-slice does not complete P7-01.
+
+## Baseline and bounded commit scope
+
+The inherited accepted runtime baseline is backend1,033, frontend521/85, ordinary browser159, sidecar49 and separate existing security/HTTP/fidelity lanes. P7-00 performed fresh identity/routes/matrix/static checks only. New affected runtime evidence begins here; every count delta must identify actual added/removed cases and avoid adding focused subsets to full totals.
+
+| Coherent commit boundary within P7-01 | Existing source owners | Allowed presentation scope / exclusions |
+|---|---|---|
+| Public authentication | [Login/Register](../../../../job-tracker-ui/src/views/LoginPage.tsx), [Forgot](../../../../job-tracker-ui/src/views/ForgotPasswordPage.tsx), [Reset](../../../../job-tracker-ui/src/views/ResetPasswordPage.tsx), [Verify/email-change](../../../../job-tracker-ui/src/views/VerifyEmailPage.tsx), [Microsoft relink](../../../../job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx) | Reuse existing shared page/forms/state/error patterns; coherent headings/names/labels/focus, responsive layout and translated feedback. Preserve safe from/query/hash/state, remember-me, registration/verification/token/Turnstile/2FA and provider exchange semantics |
+| Account identity/security | [Profile](../../../../job-tracker-ui/src/views/ProfilePage.tsx), [AuthStatus](../../../../job-tracker-ui/src/components/AuthStatusCard.tsx), [2FA](../../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx), [Sessions](../../../../job-tracker-ui/src/components/SessionsSettingsCard.tsx) | Shared theme/section hierarchy, honest status/error/retry, dialog-local failure, locale dates and long metadata reflow. Preserve identity-only profile payload/local preference ownership, avatar/crop/remove, email confirmation/password, recovery/trusted-device/current-session/revoke semantics |
+| Shared provider consumers affected by either boundary | [Google](../../../../job-tracker-ui/src/components/GoogleAuthCard.tsx), [Microsoft](../../../../job-tracker-ui/src/components/MicrosoftAuthCard.tsx) | Real consumers are LoginPage sign-in presentation and ProfilePage account-link presentation. Prove both after shared changes; preserve link password, popup origin/state, cancellation/no-exchange, safe return and unlink guards. Mailbox grants remain separate |
+
+The exact checkpoint remains P7-01; these are reviewable commit boundaries, not additional phases. Account changes follow the public-auth commit to avoid conflicting shared-provider edits. Keep existing save/fetch/security owners; no dead-code cleanup or backend concurrency/provider redesign hidden in presentation.
+
+## Read-only source findings to reproduce before repair
+
+| Observation at entry | Bounded correction candidate / required proof |
+|---|---|
+| TwoFactorSettingsCard status GET catches failure into null; null then selects Enable2FA action as though disabled | Distinct pending/known/failed status and deliberate retry; no misleading enabled/disabled assertion or setup action while unknown. Request counts, known enabled/disabled branch and failure→retry readback tests |
+| Sessions revoke-others failure sets the global error rendered outside the still-open confirmation dialog | Durable alert inside that dialog, retained confirmation/retry/cancel and focus; no background-isolation workaround or automatic resend/revoke |
+| AuthStatus signed-in sentence is a literal English sentence; account/security/provider dates use host-default locale | Existing i18n interpolation/natural EN/NB wording and explicit UI-locale date formatting; test actual two locales with fixed timestamps and shared provider presentations |
+| Account child card headings default from typography variant; shell already owns page h1 and Profile has explicit contextual headings | Use existing section primitives and explicit contextual levels/names; prove loaded full hierarchy and preserve field/action names. Do not add a second h1/main |
+| Profile load/avatar/remove/save/password errors still use raw response/message stringification, while email-change paths use shared helper | Reuse getApiErrorMessage with translated caller fallback and structured server explanations where reproduced; retained draft/local state and deliberate successful recovery. Do not change payload/save semantics |
+| Trusted-device/session metadata uses absolute secondary-action list layout | Verify long device names/dates at320/390 and keyboard/zoom before any reflow repair; source layout alone is not measured overflow evidence |
+
+Installed MUI Dialog generates aria-labelledby and DialogTitle inherits its ID. Missing explicit ID props alone do not establish an unnamed-dialog defect; actual named-dialog/description/focus/error tests determine whether a repair is required. Preserve recovery confirmation before dismissing codes, password/code clearing and no automatic sensitive action on entry.
+
+## Required automated and native evidence
+
+| Scope | Existing anchors / additions needed |
+|---|---|
+| Local auth and safe navigation | [Login tests](../../../../job-tracker-ui/src/login-page.test.tsx), [Verify tests](../../../../job-tracker-ui/src/verify-email-page.test.tsx), [native auth return/expiry](../../../../job-tracker-ui/e2e/analytics-auth-repair.spec.ts). Exercise login/register/reset/verify/relink loaded/error/expired/used-token states, remember-me, recovery/rate-limit and unsafe/nested return rejection without route/protocol changes |
+| Account identity versus Career | [Profile tests](../../../../job-tracker-ui/src/profile-page.test.tsx), [native account isolation](../../../../job-tracker-ui/e2e/account-isolation.spec.ts). Add identity-only save payload/readback, no canonical Career/CV/sibling write, local-only vs external read-only rules, pending email request/cancel/password failure/retry and owner-switch disposal |
+| 2FA status/confirm/recovery/devices | [2FA tests](../../../../job-tracker-ui/src/two-factor-settings.test.tsx) currently cover enable→recovery and wrong-password disable. Add unknown/error/retry, known status, recovery acknowledgment/clear/cancel, trusted-device error/revoke and actual named modal trap/return; no real authenticator qualification claim |
+| Sessions and sign-out | Add focused real Sessions/AuthStatus tests for load failure/retry, remote vs current revoke, canceled revoke-others/no-write, failed confirm within modal and deliberate retry/readback. Preserve clearAuthClientState/private-tree disposal with [session-boundary tests](../../../../job-tracker-ui/src/session-boundary.test.ts) |
+| Shared providers | Current Login tests exercise real Google/Microsoft components under mocked external exchange; Profile tests mock Google. Add real account-link/unlink presentation/negative-path coverage so Login success cannot stand in for Profile compatibility. No actual provider call without separate authority |
+| Responsive/localised/accessibility | EN/NB, light/dark,320/360–390/768/1024/1280/1440/wide representative states, long labels/device names, actual relevant zoom, keyboard/focus/errors/loading/retry and dialog state. Capture DOM names, root overflow, screenshot and axe contexts; use current theme/page/i18n owners |
+
+Use owned synthetic fixtures and actual mutation/no-write/readback assertions. Run appropriate affected unit/native tests, app/browser TypeScript, lint/build and finite docs/secret/whitespace checks. A broader full runtime gate is required at P7-12; extra runs here need a new change/failure/unresolved concern. Preserve ordinary P2-D01, existing auth/tenant/AI/frozen/output guards and original PDF oracles.
+
+## Acceptance and remaining gates
+
+- Public/auth and account commits have bounded diffs, real consumer regression, exact commands/results/count deltas, source identity and retained intermediate failures. Commit/push each completed unit and record immediate direct remote=HEAD in the ledger.
+- Existing32 routes/aliases/search/history/state remain; no weakened authentication/authorization, canonical mutation, duplicate provider exchange/save owner or silent sensitive-action semantics change.
+- EN/NB/theme/responsive names/headings/error/retry/focus behavior is verified in actual representative native states, with axe incomplete/violation contexts retained rather than disabled.
+- Applicable E01–E06/E09 and shared E07/E08 plus S03 boundaries remain in the [57 matrix](../PRESERVATION.md). Finite scoped repairs do not upgrade whole groups without missing mandatory evidence.
+- Actual mail/OAuth/Turnstile/authenticator/device/reader results and M01–M12 remain explicit when unavailable. M13/P5-13 remains deferred do-not-execute. Keep all [debt](../DEBT.md), production NO-GO and main unchanged; no Phase8 customization.
+
+## Public authentication implementation and acceptance
+
+The [public evidence manifest](evidence/public-auth-results.json) records the fresh final commands, source/export identity, all 61 affected unit assertions, 22 native assertions, two isolated SMTP workflows, 22 all-enabled axe attachments, exact geometry, image hashes and retained intermediate attempts. Public UI runtime files are copied to the immutable `.artifacts/phase7/p7-01/public-final/` snapshot before account runs reuse the runner lanes; affected-unit/backend artifacts retain their unique original paths. Only manifest file references were rebased: raw reports retain original absolute execution/attachment paths internally, and commands, times, results and measured SHA256 values are unchanged. Portable PNG references resolve to the snapshot. The six public source files use UTF-8/LF normalization so their hashes remain stable when Git stages LF. The manifest is written with LF; no commit hash is inferred from its own contents.
+
+The five existing view owners now use [AuthPageFrame](../../../../job-tracker-ui/src/layout/AuthPageFrame.tsx), the existing PageHeader/theme spacing and a bounded 520px form width. Each public page owns one named main landmark/H1. Recovery forms have durable page feedback, labelled local validation, focus on the failed field, retained input and explicit resubmission. Verification/email-change loading and success have named dynamic status; invalid/missing token pages retain a usable recovery action. Long action labels wrap at narrow widths. Existing route, command, token, Turnstile, remember-me, provider and safe-return owners remain in place.
+
+Visual review of the first passing export found registration describing its password as “Current password.” Two ordinary password-intent unit cases reproduced the mismatch; registration now uses the existing “New password”/“Nytt passord” key while preserving `new-password` autocomplete. The final export and native/recovery runs below include that repair. No new translation key or hard-coded product string was required.
+
+| Fresh bounded evidence | Observed final result | Scope / count explanation |
+|---|---|---|
+| Affected public Jest files | **61/61**, four suites, zero failure/pending | Existing Login33 and Verify4 retained; Microsoft relink1→2; new public-presentation22. Compared with the inherited affected38 cases, +23 cases/+1 suite. This is not a fresh full frontend run |
+| Ordinary public native pack | **22/22**, zero skip/flaky/unexpected/retry | Fifteen finite presentation samples, two keyboard recovery/prefill/validation workflows, three real invalid-token HTTP400 workflows and two failed-login→explicit-success/return-context workflows. Fresh2026-10-11 18:40:40–18:41:10UTC |
+| Isolated actual Identity + loopback SMTP pack | **2/2**, zero skip/flaky/unexpected/retry | Missing-token/no-write plus real registration202, delivered verification link204, invalid link400, password-reset delivery/reset204/replay400, old password/session rejection and protected return. Fresh18:41:10–18:41:23UTC; separate from the22 ordinary cases |
+| Loopback SMTP fixture helper | **6/6**, zero fail/cancel/skip/todo | Fragmented commands/dot stuffing, envelope reset, oversize rejection, quoted-printable UTF-8, folded base64 and unsupported-MIME handling. Separate tooling cases |
+| Backend auth/security subset | **87/87**, zero failed/not-executed | Auth/session/local identity/context/2FA/email-ownership/authorization contracts at unchanged backend source; a subset of inherited1,033, not an additive total |
+| App and browser TypeScript, lint, production frontend build | **All exit0** | Final sequence18:40:04–18:40:39UTC; lint retains zero-warning policy. Browser config contents and command/log hashes are portable in the manifest |
+
+Authoritative final build ID is `rd_SQeVLwVwER9VMCc6XL`. Canonical public six-file source digest is `b330b233508ad5202a1f622ade4464103f7a986ee53648c8f16047f2a1d32586`; the manifest records each file and its precise ordered digest algorithm. Static export74 files have measured raw-file digest `dff031a52740a09359715a31456c9cec70f5aae6f9932c018af078215e973d67`. These identify the tested public working tree, not a newly deployed or remotely pushed identity. P7-00 remains the recorded entry commit until a successor push receipt is recorded in the ledger.
+
+### Responsive, localisation and visual evidence
+
+The native pack actually covers EN/NB and light/dark across320,360,390,768,1024,1280,1440 and1920px; the 1280×320 registration sample exercises short landscape height. It includes ready, registration-disabled, missing-link, local-validation, actual HTTP400 and actual HTTP401 states. Each of22 scans records one H1, named main and exact visible-control geometry; root/main overflow is0 throughout and visible controls remain within viewport tolerance. Public forms have no density control, so Comfortable/Compact is explicitly not applicable here. This is a finite sampling plan, not every route×theme×language×breakpoint combination, physical orientation or browser zoom acceptance.
+
+The parent opened the **eight exact final presentation-matrix PNGs** with `view_image`: login NB/dark320; registration NB/light390 and NB/dark1280×320; forgot EN/dark360; reset EN/light320; verify NB/dark390; email-change EN/dark1024; Microsoft relink EN/dark1440. Final registration images visibly say “Nytt passord.” The reviewed samples have calm shared framing and reachable/wrapped labels/actions, with no new observed app-chrome overflow. The manifest records those eight exact raw PNG hashes. Other workflow screenshots were captured and hashed; individual visual inspection is not claimed for them.
+
+The22 all-enabled axe scans contain **0 violation nodes and31 incomplete nodes**, all `color-contrast`. Every retained check says the background could not be determined because another element overlaps it. Contexts include outlined empty/filled form inputs and two primary-button nodes in failed-login states. Exact targets, HTML, check IDs/messages/data, context and geometry are retained in the manifest; complete raw attachments remain embedded in the hashed native report. Reflow and zero reported violations do not prove contrast. **M11** must qualify contextual contrast/forced colors; M09 must qualify spoken names/errors/state and possible duplicate route/error announcements. Browser zoom, human screen reader and physical/software-keyboard qualification remain unverified. No axe tag/rule was suppressed to obtain these results.
+
+Frontend-owned copy uses the existing EN/NB keys. Actual invalid-token responses include existing server-authored English “Invalid or expired link.”/“Invalid email or token.” in NB samples; this is retained as a localisation qualification, not presented as translated server feedback. Actual external OAuth, Turnstile and production email delivery remain unqualified; the SMTP run uses the real application mail/Identity path against an owned local capture server, not an external service.
+
+### Retained failures and preservation
+
+The first SMTP attempt passed0/2 because strict alert selectors also matched the established route announcer. The second passed1/2 because the fixture expected direct login where the protected-route handoff actually opens the existing Landing page. Scoped-main alert assertions and following that actual Landing handoff fixed the test assumptions; no product change was made for these failures. The third passed2/2 before the label repair, and the fresh final run passed2/2 after it. Their reports/logs/command records and whole output folders are retained under `.artifacts/phase7/p7-01/public-final/attempts/`; the manifest resolves archived attachment paths to their retained folders rather than later output files.
+
+Intermediate public unit attempts are also retained, including the59-case run with one failure, the later59/59 run, and the password-label diagnostic RED with1 pass/1 failure/20 unselected pending cases. The final61-case affected run has zero pending/failure; diagnostic `testNamePattern` selection is not used for final acceptance. The first passing22-case public native run remains historical evidence and did not excuse the visually identified label defect.
+
+The finite public checks preserve E01–E06/E09 and E07/E08/S03 boundaries, exact safe return/query/hash handling, real token failure/replay and old-session rejection. Backend routes/protocols and established link/exchange guards are retained. All **57 groups remain56 PARTIAL + C11 DEFERRED**, and all32 routes remain retained with their existing qualifications. No whole-group upgrade or fresh full frontend/backend/browser/fidelity acceptance is inferred from these subsets. Ordinary P2-D01 remains required by the inherited baseline and future integrated gate; it was not rerun in this public pack.
+
+Public sub-slice acceptance is **CONDITIONAL GO** for its completed development commit, with M01–M12, server-error language/reader/contrast/provider qualifications and inherited debt carried. **Production remains NO-GO**, main unchanged; M13/P5-13 remains deferred do-not-execute. Commit/push/remote receipt and finite hygiene checks are recorded by the parent in the ledger before account product work proceeds.
+
+Account/security acceptance is **PENDING**: five new account-presentation RED cases and12 real-provider cases are prepared (eight existing provider behaviors pass; four provider presentation cases fail), plus six meaningful native account cases not yet executed. The parent owns those product repairs and the later fresh affected build/native evidence. This public result neither completes P7-01 nor changes the approved checkpoint order.
diff --git a/docs/redesign/phase-7/p7-01/evidence/public-auth-results.json b/docs/redesign/phase-7/p7-01/evidence/public-auth-results.json
new file mode 100644
index 0000000..6362c9b
--- /dev/null
+++ b/docs/redesign/phase-7/p7-01/evidence/public-auth-results.json
@@ -0,0 +1,6360 @@
+{
+ "schemaVersion": 1,
+ "checkpoint": "P7-01",
+ "slice": "Public authentication presentation",
+ "collectedUtc": "2026-10-11T18:46:34.391008+00:00",
+ "acceptance": "CONDITIONAL_GO_PUBLIC_SUBSLICE",
+ "wholeCheckpointAcceptance": "PENDING_ACCOUNT_IMPLEMENTATION_AND_ACCEPTANCE",
+ "production": "NO-GO; main unchanged; no deployment",
+ "phase7Readiness": "Conditional development authorization; mandatory manual/production/withheld-AI gates retained",
+ "identity": {
+ "developmentBranch": "codex/ui-redesign-phase4",
+ "entryCommit": "27c54146ad6f9059295d169b533db7b1b6689210",
+ "currentHeadObserved": "27c54146ad6f9059295d169b533db7b1b6689210",
+ "qualification": "Measured working-tree public source, no eventual commit self-reference or inferred remote receipt",
+ "publicSourceFiles": [
+ {
+ "path": "job-tracker-ui/src/views/LoginPage.tsx",
+ "sha256": "3120b4e29d6ebf980e92742b68f12d45ec0f0ecbda12ba81a1f3c1ac24a716de",
+ "bytes": 13880,
+ "hashPolicy": "UTF-8 text with CRLF normalized to LF"
+ },
+ {
+ "path": "job-tracker-ui/src/views/ForgotPasswordPage.tsx",
+ "sha256": "662cd57f46fce43aa8c61d8ea8629ab76c5df34a3a9fc1a822fe64fb726206ad",
+ "bytes": 3601,
+ "hashPolicy": "UTF-8 text with CRLF normalized to LF"
+ },
+ {
+ "path": "job-tracker-ui/src/views/ResetPasswordPage.tsx",
+ "sha256": "33cb1f86b6b9f3254b5287e20f912c9f13236626d1ee8f9e5e40e88b535fbf51",
+ "bytes": 4750,
+ "hashPolicy": "UTF-8 text with CRLF normalized to LF"
+ },
+ {
+ "path": "job-tracker-ui/src/views/VerifyEmailPage.tsx",
+ "sha256": "90274cf2885ad80fbd16073e2750a8a3a53061c5fc35d877441e8efc1515e2d0",
+ "bytes": 2619,
+ "hashPolicy": "UTF-8 text with CRLF normalized to LF"
+ },
+ {
+ "path": "job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx",
+ "sha256": "88cfd80f0f743e20889a665261111a40e977c6a8ebdf0715aba255c01e1fef16",
+ "bytes": 2990,
+ "hashPolicy": "UTF-8 text with CRLF normalized to LF"
+ },
+ {
+ "path": "job-tracker-ui/src/layout/AuthPageFrame.tsx",
+ "sha256": "cdd4b0f238d1c5dffdb13fd0f0dd0ea08f89238ccd83858e10eed58a0a8911a7",
+ "bytes": 1021,
+ "hashPolicy": "UTF-8 text with CRLF normalized to LF"
+ }
+ ],
+ "publicSourceSha256Lf": "b330b233508ad5202a1f622ade4464103f7a986ee53648c8f16047f2a1d32586",
+ "publicSourceAlgorithm": "SHA256 of ordered path + TAB + canonical-LF file SHA256 + LF records",
+ "buildId": "rd_SQeVLwVwER9VMCc6XL",
+ "buildIdRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/BUILD_ID",
+ "sha256": "3b9a7dfe22d00b2ea2b367484f524ba84ad775388e54714d70bb5813ef00c595",
+ "bytes": 21,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "staticExportFileCount": 74,
+ "staticExportSha256": "dff031a52740a09359715a31456c9cec70f5aae6f9932c018af078215e973d67",
+ "staticExportAlgorithm": "SHA256 of sorted repository-relative path + TAB + raw exported file SHA256 + LF records",
+ "finalFreezeConfirmedByParent": true
+ },
+ "environment": {
+ "osObserved": "Windows-11-10.0.26200-SP0",
+ "localOnly": true,
+ "nativeBrowser": "Chromium",
+ "appliedRunnerEnvironment": {
+ "NEXT_PUBLIC_API_BASE_URL": "http://localhost:5302/api",
+ "NEXT_TELEMETRY_DISABLED": "1",
+ "DOTNET_ROOT": "C:/Users/Connor/.dotnet",
+ "DOTNET_HOST_PATH": "C:/Users/Connor/.dotnet/dotnet.exe",
+ "PLAYWRIGHT_STATIC_EXPORT": "true",
+ "PLAYWRIGHT_PREBUILT_EXPORT": "true",
+ "PLAYWRIGHT_REUSE_SERVERS": "false",
+ "Workers__SavedJobSearchAlertsEnabled": "false",
+ "CV_FIDELITY_OUTPUT": ".artifacts/phase7/current/ui/fidelity",
+ "CV_SETTINGS_FIDELITY_OUTPUT": ".artifacts/phase7/current/ui/settings-fidelity"
+ },
+ "runnerRaw": {
+ "path": ".artifacts/phase7/current/run-ui.py",
+ "sha256": "95c479462812f91be97a07865764b76e7cd4e251edb0cf871ae945147fbb606d",
+ "bytes": 3737,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "browserTypeScriptConfig": {
+ "raw": {
+ "path": ".artifacts/phase7/e2e-tsconfig.json",
+ "sha256": "55fa6fffaed1e76a32657edfffcc501cd8bd87330bda2c3a3944f8f89d4019e2",
+ "bytes": 572,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "contents": "{\n \"extends\": \"../../job-tracker-ui/tsconfig.json\",\n \"compilerOptions\": {\n \"incremental\": false,\n \"types\": [\"node\", \"jest\"],\n \"typeRoots\": [\"../../job-tracker-ui/node_modules/@types\"]\n },\n \"include\": [\n \"../../job-tracker-ui/e2e/**/*.ts\",\n \"../../job-tracker-ui/ai-tests/**/*.ts\",\n \"../../job-tracker-ui/auth-tests/**/*.ts\",\n \"../../job-tracker-ui/playwright.*.config.ts\",\n \"../../job-tracker-ui/src/mui-theme.d.ts\",\n \"../../docs/redesign/phase-5/p5-15/p5-15-01/diagnostics/**/*.ts\"\n ],\n \"exclude\": [\"../../job-tracker-ui/node_modules\"]\n}\n"
+ },
+ "SMTPConfiguration": {
+ "path": "job-tracker-ui/playwright.auth-recovery.config.ts",
+ "sha256": "e1398a2ca5da83ae4fcb5f7486025ad57972d1c8c9e59f5045cc0fc4771ffb46",
+ "bytes": 2514,
+ "hashPolicy": "UTF-8 text with CRLF normalized to LF"
+ },
+ "SMTPQualification": "Fresh synthetic SQLite/keys, loopback SMTP capture, actual app Identity tokens/mail/reset/session revocation; production mail/OAuth/Turnstile disabled, no real provider call"
+ },
+ "commands": {
+ "typecheck": {
+ "record": {
+ "name": "typecheck",
+ "command": [
+ "rtk",
+ "proxy",
+ "npm.cmd",
+ "run",
+ "typecheck"
+ ],
+ "startedUtc": "2026-10-11T18:40:04.381270+00:00",
+ "finishedUtc": "2026-10-11T18:40:13.702467+00:00",
+ "exitCode": 0
+ },
+ "recordRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/typecheck-command.json",
+ "sha256": "ec09944c3564073f9fc5053cb04b709238d9b3517d932f87ef6bfd87769985f3",
+ "bytes": 247,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "logRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/typecheck.log",
+ "sha256": "89b0ec97b537eca6560c13ca2dfea9e3a97dd1bb35580c4ff39d2462db25e080",
+ "bytes": 148,
+ "hashPolicy": "Exact measured raw bytes"
+ }
+ },
+ "browser-typecheck": {
+ "record": {
+ "name": "browser-typecheck",
+ "command": [
+ "rtk",
+ "proxy",
+ "npm.cmd",
+ "exec",
+ "tsc",
+ "--",
+ "--project",
+ "../.artifacts/phase7/e2e-tsconfig.json",
+ "--noEmit"
+ ],
+ "startedUtc": "2026-10-11T18:40:13.704966+00:00",
+ "finishedUtc": "2026-10-11T18:40:17.223050+00:00",
+ "exitCode": 0
+ },
+ "recordRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/browser-typecheck-command.json",
+ "sha256": "f521fa7034e2a4a13271c2290d64aa5ab6cf70ec3069193b0dbe0581d362f71d",
+ "bytes": 343,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "logRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/browser-typecheck.log",
+ "sha256": "d2993bc68ad9a63f711c8f5473155e2ba00fdcd461220cc3849185f2f9ad93e6",
+ "bytes": 78,
+ "hashPolicy": "Exact measured raw bytes"
+ }
+ },
+ "lint": {
+ "record": {
+ "name": "lint",
+ "command": [
+ "rtk",
+ "proxy",
+ "npm.cmd",
+ "run",
+ "lint"
+ ],
+ "startedUtc": "2026-10-11T18:40:17.225515+00:00",
+ "finishedUtc": "2026-10-11T18:40:33.244235+00:00",
+ "exitCode": 0
+ },
+ "recordRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/lint-command.json",
+ "sha256": "9942a5aabf7a93ba5150d8fb705c3641c6187892a1db213a31086c000959e9d1",
+ "bytes": 237,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "logRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/lint.log",
+ "sha256": "b040dbeca9b4adb3f6f4c25ac49de0d37e921375b2d9b57e87b542a10f599913",
+ "bytes": 136,
+ "hashPolicy": "Exact measured raw bytes"
+ }
+ },
+ "build": {
+ "record": {
+ "name": "build",
+ "command": [
+ "rtk",
+ "proxy",
+ "npm.cmd",
+ "run",
+ "build"
+ ],
+ "startedUtc": "2026-10-11T18:40:33.246731+00:00",
+ "finishedUtc": "2026-10-11T18:40:39.963279+00:00",
+ "exitCode": 0
+ },
+ "recordRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/build-command.json",
+ "sha256": "e3fcd7fee126f082d52489ce5ce70f42cacf9b542a49228957e25ac979cf38a4",
+ "bytes": 239,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "logRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/build.log",
+ "sha256": "ace43e7ab44772d78e3802b2b305d89fbd69febe25843ee41610de9671b3f030",
+ "bytes": 670,
+ "hashPolicy": "Exact measured raw bytes"
+ }
+ },
+ "smtp-fixture": {
+ "record": {
+ "name": "smtp-fixture",
+ "command": [
+ "rtk",
+ "proxy",
+ "node",
+ "--test",
+ "scripts/localSMTPfixture.test.mjs"
+ ],
+ "startedUtc": "2026-10-11T18:38:47.568488+00:00",
+ "finishedUtc": "2026-10-11T18:38:47.841554+00:00",
+ "exitCode": 0
+ },
+ "recordRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/smtp-fixture-command.json",
+ "sha256": "155a2822339d2fa288781cd3ba82973c3ac9b9a81ac689f64d735cf59ee4578f",
+ "bytes": 274,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "logRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/smtp-fixture.log",
+ "sha256": "21ab3459c6263f849416bb3ec1284146164b8b218f2b2c16a7cb94b2877e23ec",
+ "bytes": 712,
+ "hashPolicy": "Exact measured raw bytes"
+ }
+ }
+ },
+ "focusedUnit": {
+ "raw": {
+ "path": ".artifacts/phase7/current/unit/public-password-label-green-20261011T183907Z.json",
+ "sha256": "19eb766e24079444a713e1ebe0b398289b2160223c86b393d45aaab1a906258e",
+ "bytes": 26508,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "startedUnixMs": 1791743948118,
+ "passed": 61,
+ "failed": 0,
+ "pending": 0,
+ "total": 61,
+ "suites": 4,
+ "cases": [
+ {
+ "name": "public auth presentation names the password field for login intent and retains its autocomplete contract",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation names the password field for register intent and retains its autocomplete contract",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation provides one named main landmark and H1 for password request",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation provides one named main landmark and H1 for password reset",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation provides one named main landmark and H1 for email verification",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation provides one named main landmark and H1 for email change",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation provides one named main landmark and H1 for Microsoft recovery",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation announces the pending confirmation without an unnamed progressbar: false",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation announces the pending confirmation without an unnamed progressbar: true",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation retains the entered reset email and a durable error in the page when the command fails",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation retains both new-password fields and the decoded recovery token after a rejected reset",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation keeps a rejected local sign-in beside the retained fields without navigating",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation keeps the reset-request action name while announcing an in-flight command",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation announces an in-flight local sign-in while preserving its action name",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation announces a pending password save without changing its payload or successful destination",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation focuses the first invalid local-login field and associates its explanation",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation focuses the invalid new password without losing confirmation input",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation focuses and explains the invalid reset-request email without sending a command",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation replaces previous reset-request success when a later request fails",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation does not assert optional authentication while login configuration is unresolved",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation does not assert optional authentication while register configuration is unresolved",
+ "status": "passed"
+ },
+ {
+ "name": "public auth presentation offers a read-only configuration retry while retaining entered sign-in fields",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage provides a main landmark and level-one heading for login",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage provides a main landmark and level-one heading for register",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage renders a dedicated registration screen and explains when registration is disabled",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage renders one conventional sign-in card with enabled provider alternatives",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage accepts a username and reports invalid credentials without changing routes",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage handles Microsoft cancellation without exchanging or navigating",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage completes the Microsoft provider return through the hardened exchange endpoint",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage completes a Google credential return without account-linking copy",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage posts remember-me preference without storing an auth token in browser storage",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage does not complete login when registration requires email verification",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage rejects an unsafe post-login redirect path",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"https://evil.example/analytics\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"//evil.example/analytics\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/\\t/evil.example\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/%2f%2fevil.example\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/%252f%252fevil.example\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/%5cevil.example\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/analytics?months=%ZZ\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/jobs/../login\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/%6cogin\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/register\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/analytics%0a\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/analytics?months=6\\n\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/LOGIN\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage uses the safe fallback for the untrusted return target \"/%4cOGIN\"",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage preserves encoded internal query and fragment without decoding the navigation target",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage restores valid owned-workspace navigation context separately from the sign-in destination",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage does not replay an unsafe nested return context after authentication",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage abandons prior return context on the established account/session disposal entry",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage opens the separate forgot-password page with the typed email prefilled",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage shows the 2FA code step when login requires two-factor, then proceeds like a normal login on success",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage shows a clear message when the 2FA challenge is rate-limited",
+ "status": "passed"
+ },
+ {
+ "name": "LoginPage offers a resend-verification action when login reports the account is not verified",
+ "status": "passed"
+ },
+ {
+ "name": "VerifyEmailPage confirms the account and shows success when the link is valid",
+ "status": "passed"
+ },
+ {
+ "name": "VerifyEmailPage shows an error when the link is invalid or expired",
+ "status": "passed"
+ },
+ {
+ "name": "VerifyEmailPage shows an error without calling the API when the link is missing userId/token",
+ "status": "passed"
+ },
+ {
+ "name": "VerifyEmailPage confirms a pending email change and requires a fresh sign-in",
+ "status": "passed"
+ },
+ {
+ "name": "legacy Microsoft recovery requires the emailed proof and a fresh matching Microsoft token",
+ "status": "passed"
+ },
+ {
+ "name": "pending Microsoft recovery keeps a named action and announces progress before the real confirmation boundary",
+ "status": "passed"
+ }
+ ]
+ },
+ "nativePublic": {
+ "command": {
+ "name": "auth",
+ "command": [
+ "rtk",
+ "proxy",
+ "node",
+ "node_modules/@playwright/test/cli.js",
+ "test",
+ "e2e/phase7-authentication.spec.ts",
+ "--grep",
+ "public",
+ "--retries=0",
+ "--reporter=list,json",
+ "--output=E:\\Storage\\Projects\\Active\\Job tracker\\.artifacts\\phase7\\current\\ui\\auth-results"
+ ],
+ "startedUtc": "2026-10-11T18:40:39.968796+00:00",
+ "finishedUtc": "2026-10-11T18:41:10.212431+00:00",
+ "exitCode": 0,
+ "stats": {
+ "startTime": "2026-10-11T18:40:40.482Z",
+ "duration": 29658.595,
+ "expected": 22,
+ "skipped": 0,
+ "unexpected": 0,
+ "flaky": 0
+ }
+ },
+ "commandRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/auth-command.json",
+ "sha256": "2f9818509196a29ff4c94d39763eb941efa957cef52ffc079a0a585b888f6dc5",
+ "bytes": 667,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "reportRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/auth.json",
+ "sha256": "56125fb7953ac8c36a6d42c1e1a8e45e061f7e34276f091cea6f5bb23625d65a",
+ "bytes": 3782886,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "logRaw": {
+ "path": ".artifacts/phase7/p7-01/public-final/auth.log",
+ "sha256": "8b8e79bba89ab30125a65a7d97f2f660d4ee5addaa2f17bfd0a19ce1fdc0d8c4",
+ "bytes": 4061,
+ "hashPolicy": "Exact measured raw bytes"
+ },
+ "stats": {
+ "startTime": "2026-10-11T18:40:40.482Z",
+ "duration": 29658.595,
+ "expected": 22,
+ "skipped": 0,
+ "unexpected": 0,
+ "flaky": 0
+ },
+ "cases": [
+ {
+ "title": "[P7-01 public/auth] /login nb/dark 320x740: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 1035
+ },
+ {
+ "title": "[P7-01 public/auth] /login en/light 1280x900: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 921
+ },
+ {
+ "title": "[P7-01 public/auth] /register nb/light 390x844: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 977
+ },
+ {
+ "title": "[P7-01 public/auth] /register en/dark 1440x900: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 937
+ },
+ {
+ "title": "[P7-01 public/auth] /forgot-password en/dark 360x740: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 909
+ },
+ {
+ "title": "[P7-01 public/auth] /forgot-password nb/light 1024x768: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 851
+ },
+ {
+ "title": "[P7-01 public/auth] /reset-password en/light 320x740: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 916
+ },
+ {
+ "title": "[P7-01 public/auth] /reset-password nb/dark 768x1024: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 932
+ },
+ {
+ "title": "[P7-01 public/auth] /verify-email en/light 1920x1080: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 862
+ },
+ {
+ "title": "[P7-01 public/auth] /verify-email nb/dark 390x844: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 848
+ },
+ {
+ "title": "[P7-01 public/auth] /confirm-email-change en/dark 1024x768: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 863
+ },
+ {
+ "title": "[P7-01 public/auth] /confirm-email-change nb/light 768x1024: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 843
+ },
+ {
+ "title": "[P7-01 public/auth] /microsoft-legacy-relink nb/light 1280x900: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 855
+ },
+ {
+ "title": "[P7-01 public/auth] /microsoft-legacy-relink en/dark 1440x900: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 886
+ },
+ {
+ "title": "[P7-01 public/auth] /register nb/dark 1280x320: landmarks, labels and reflow",
+ "file": "phase7-authentication.spec.ts",
+ "line": 85,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 963
+ },
+ {
+ "title": "[P7-01 public/auth] en keyboard recovery entry preserves the prefill, validates locally and returns focus to sign-in",
+ "file": "phase7-authentication.spec.ts",
+ "line": 114,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 1072
+ },
+ {
+ "title": "[P7-01 public/auth] nb keyboard recovery entry preserves the prefill, validates locally and returns focus to sign-in",
+ "file": "phase7-authentication.spec.ts",
+ "line": 114,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 1032
+ },
+ {
+ "title": "[P7-01 public/auth] real /auth/verify-email invalid-token rejection retains a usable page",
+ "file": "phase7-authentication.spec.ts",
+ "line": 149,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 1000
+ },
+ {
+ "title": "[P7-01 public/auth] real /auth/email-change/confirm invalid-token rejection retains a usable page",
+ "file": "phase7-authentication.spec.ts",
+ "line": 149,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 931
+ },
+ {
+ "title": "[P7-01 public/auth] real /auth/reset-password invalid-token rejection retains a usable page",
+ "file": "phase7-authentication.spec.ts",
+ "line": 149,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 1068
+ },
+ {
+ "title": "[P7-01 public/auth] en rejected sign-in retains credentials and the exact protected return route",
+ "file": "phase7-authentication.spec.ts",
+ "line": 186,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 1977
+ },
+ {
+ "title": "[P7-01 public/auth] nb rejected sign-in retains credentials and the exact protected return route",
+ "file": "phase7-authentication.spec.ts",
+ "line": 186,
+ "expectedStatus": "passed",
+ "project": "chromium",
+ "resultStatuses": [
+ "passed"
+ ],
+ "retries": [
+ 0
+ ],
+ "durationMs": 1709
+ }
+ ],
+ "axeScans": [
+ {
+ "test": "[P7-01 public/auth] /login nb/dark 320x740: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "36105550b3f71a94ce0d042881679513669ee70f1112d2f42607bf384c829606",
+ "bytes": 155615
+ },
+ "context": {
+ "path": "/login",
+ "title": "signInTitle",
+ "language": "nb",
+ "mode": "dark",
+ "width": 320,
+ "height": 740,
+ "screenshot": true,
+ "state": "ready",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 320,
+ "viewportHeight": 740,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 126.25,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "text",
+ "text": "",
+ "left": 43,
+ "right": 277,
+ "width": 234,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 43,
+ "right": 277,
+ "width": 234,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "checkbox",
+ "text": "",
+ "left": 22,
+ "right": 64,
+ "width": 42,
+ "height": 42
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Glemt passord?",
+ "left": 193.5625,
+ "right": 287,
+ "width": 93.4375,
+ "height": 42
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Logg inn",
+ "left": 198.65625,
+ "right": 287,
+ "width": 88.34375,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Fortsett med Google",
+ "left": 33,
+ "right": 287,
+ "width": 254,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Fortsett med Microsoft",
+ "left": 33,
+ "right": 287,
+ "width": 254,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 320,
+ "windowHeight": 740,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_5_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 2
+ },
+ {
+ "test": "[P7-01 public/auth] /login en/light 1280x900: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "836104700e4d84242ae71dea62d9fcff26b8049ebd7f70ac016713b4e95b2d6f",
+ "bytes": 156060
+ },
+ "context": {
+ "path": "/login",
+ "title": "signInTitle",
+ "language": "en",
+ "mode": "light",
+ "width": 1280,
+ "height": 900,
+ "state": "ready",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1280,
+ "viewportHeight": 900,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 222.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "text",
+ "text": "",
+ "left": 411,
+ "right": 869,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 411,
+ "right": 869,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "checkbox",
+ "text": "",
+ "left": 390,
+ "right": 432,
+ "width": 42,
+ "height": 42
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Forgot password?",
+ "left": 771.3125,
+ "right": 879,
+ "width": 107.6875,
+ "height": 30.75
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Sign in",
+ "left": 803.015625,
+ "right": 879,
+ "width": 75.984375,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Continue with Google",
+ "left": 401,
+ "right": 879,
+ "width": 478,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Continue with Microsoft",
+ "left": 401,
+ "right": 879,
+ "width": 478,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1280,
+ "windowHeight": 900,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_5_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 2
+ },
+ {
+ "test": "[P7-01 public/auth] /register nb/light 390x844: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "fe0c297344c630d13cb2cefcded76ac977454835f26c16268df44d7cfb2e142f",
+ "bytes": 153600
+ },
+ "context": {
+ "path": "/register",
+ "title": "createAccount",
+ "language": "nb",
+ "mode": "light",
+ "width": 390,
+ "height": 844,
+ "screenshot": true,
+ "state": "registration-disabled",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 390,
+ "viewportHeight": 844,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 221.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 43,
+ "right": 347,
+ "width": 304,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 43,
+ "right": 347,
+ "width": 304,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 43,
+ "right": 347,
+ "width": 304,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Tilbake til innlogging",
+ "left": 33,
+ "right": 166.4375,
+ "width": 133.4375,
+ "height": 30.75
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Opprett konto",
+ "left": 232.828125,
+ "right": 357,
+ "width": 124.171875,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 390,
+ "windowHeight": 844,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_5_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_6_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 3
+ },
+ {
+ "test": "[P7-01 public/auth] /register en/dark 1440x900: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "7aff8d9d2271e4a64181c11eb3f92ea898412c8f6121b36d769a74b621cb440b",
+ "bytes": 153528
+ },
+ "context": {
+ "path": "/register",
+ "title": "createAccount",
+ "language": "en",
+ "mode": "dark",
+ "width": 1440,
+ "height": 900,
+ "state": "registration-disabled",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1440,
+ "viewportHeight": 900,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 262.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 491,
+ "right": 949,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 491,
+ "right": 949,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 491,
+ "right": 949,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Back to login",
+ "left": 481,
+ "right": 565.609375,
+ "width": 84.609375,
+ "height": 30.75
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Create account",
+ "left": 829.90625,
+ "right": 959,
+ "width": 129.09375,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1440,
+ "windowHeight": 900,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_5_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_6_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 3
+ },
+ {
+ "test": "[P7-01 public/auth] /forgot-password en/dark 360x740: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "2ac1cb084f099227edbd57888888e3935411c2766928e8672d51236819a1b4df",
+ "bytes": 112126
+ },
+ "context": {
+ "path": "/forgot-password",
+ "title": "forgotPasswordTitle",
+ "language": "en",
+ "mode": "dark",
+ "width": 360,
+ "height": 740,
+ "screenshot": true,
+ "state": "ready",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 360,
+ "viewportHeight": 740,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 269.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 43,
+ "right": 317,
+ "width": 274,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Back to login",
+ "left": 67.703125,
+ "right": 187.296875,
+ "width": 119.59375,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Send reset link",
+ "left": 195.296875,
+ "right": 327,
+ "width": 131.703125,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 360,
+ "windowHeight": 740,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 1
+ },
+ {
+ "test": "[P7-01 public/auth] /forgot-password nb/light 1024x768: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "529e99aff04dae255fa88ec690bda41a13e4af1d7a947f4e4261e85df04fa4f8",
+ "bytes": 112217
+ },
+ "context": {
+ "path": "/forgot-password",
+ "title": "forgotPasswordTitle",
+ "language": "nb",
+ "mode": "light",
+ "width": 1024,
+ "height": 768,
+ "state": "ready",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1024,
+ "viewportHeight": 768,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 281.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 283,
+ "right": 741,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Tilbake til innlogging",
+ "left": 397.625,
+ "right": 567.09375,
+ "width": 169.46875,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Send nullstillingslenke",
+ "left": 575.09375,
+ "right": 751,
+ "width": 175.90625,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1024,
+ "windowHeight": 768,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 1
+ },
+ {
+ "test": "[P7-01 public/auth] /reset-password en/light 320x740: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "98de569213c6d526446c96f6edb6bb8a5cea899191d6d3112b51fb7af5cbffa7",
+ "bytes": 153735
+ },
+ "context": {
+ "path": "/reset-password",
+ "title": "resetPasswordTitle",
+ "language": "en",
+ "mode": "light",
+ "width": 320,
+ "height": 740,
+ "screenshot": true,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 320,
+ "viewportHeight": 740,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 154.5,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 43,
+ "right": 277,
+ "width": 234,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 43,
+ "right": 277,
+ "width": 234,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 43,
+ "right": 277,
+ "width": 234,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Back to login",
+ "left": 167.40625,
+ "right": 287,
+ "width": 119.59375,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Update password",
+ "left": 145.15625,
+ "right": 287,
+ "width": 141.84375,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 320,
+ "windowHeight": 740,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_5_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_6_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 3
+ },
+ {
+ "test": "[P7-01 public/auth] /reset-password nb/dark 768x1024: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "22ff81c149b4357dbb0265f770ae61f33de9c86179026afe43d125bcaa1bef31",
+ "bytes": 153215
+ },
+ "context": {
+ "path": "/reset-password",
+ "title": "resetPasswordTitle",
+ "language": "nb",
+ "mode": "dark",
+ "width": 768,
+ "height": 1024,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 768,
+ "viewportHeight": 1024,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 324.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 155,
+ "right": 613,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 155,
+ "right": 613,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 155,
+ "right": 613,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Tilbake til innlogging",
+ "left": 299.875,
+ "right": 469.34375,
+ "width": 169.46875,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Oppdater passord",
+ "left": 477.34375,
+ "right": 623,
+ "width": 145.65625,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 768,
+ "windowHeight": 1024,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_5_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_6_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 3
+ },
+ {
+ "test": "[P7-01 public/auth] /verify-email en/light 1920x1080: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "46f1f839097cbac05ae348e4d656f3ad202e6359ac9097e65006bd6936f74a65",
+ "bytes": 96524
+ },
+ "context": {
+ "path": "/verify-email",
+ "title": "verifyEmailTitle",
+ "language": "en",
+ "mode": "light",
+ "width": 1920,
+ "height": 1080,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1920,
+ "viewportHeight": 1080,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 457.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Back to login",
+ "left": 1079.40625,
+ "right": 1199,
+ "width": 119.59375,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1920,
+ "windowHeight": 1080,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [],
+ "violationsNodes": 0,
+ "incompleteNodes": 0
+ },
+ {
+ "test": "[P7-01 public/auth] /verify-email nb/dark 390x844: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "f7d3670933d975eed13353494d62419cf74509a50afdb4e19e7d62db2c87ff73",
+ "bytes": 96590
+ },
+ "context": {
+ "path": "/verify-email",
+ "title": "verifyEmailTitle",
+ "language": "nb",
+ "mode": "dark",
+ "width": 390,
+ "height": 844,
+ "screenshot": true,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 390,
+ "viewportHeight": 844,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 341.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Tilbake til innlogging",
+ "left": 187.53125,
+ "right": 357,
+ "width": 169.46875,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 390,
+ "windowHeight": 844,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [],
+ "violationsNodes": 0,
+ "incompleteNodes": 0
+ },
+ {
+ "test": "[P7-01 public/auth] /confirm-email-change en/dark 1024x768: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "d12ddfb5a5721f62a8b02b359b0cb6571ab796c580c5d03e365a13462ce8bfd4",
+ "bytes": 96625
+ },
+ "context": {
+ "path": "/confirm-email-change",
+ "title": "confirmEmailChangeTitle",
+ "language": "en",
+ "mode": "dark",
+ "width": 1024,
+ "height": 768,
+ "screenshot": true,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1024,
+ "viewportHeight": 768,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 301.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Back to login",
+ "left": 631.40625,
+ "right": 751,
+ "width": 119.59375,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1024,
+ "windowHeight": 768,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [],
+ "violationsNodes": 0,
+ "incompleteNodes": 0
+ },
+ {
+ "test": "[P7-01 public/auth] /confirm-email-change nb/light 768x1024: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "01198fc809e90fe3a3ba868560da0ea451c4316d99a1687b98789b24ddaf24b3",
+ "bytes": 96713
+ },
+ "context": {
+ "path": "/confirm-email-change",
+ "title": "confirmEmailChangeTitle",
+ "language": "nb",
+ "mode": "light",
+ "width": 768,
+ "height": 1024,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 768,
+ "viewportHeight": 1024,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 429.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Tilbake til innlogging",
+ "left": 453.53125,
+ "right": 623,
+ "width": 169.46875,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 768,
+ "windowHeight": 1024,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [],
+ "violationsNodes": 0,
+ "incompleteNodes": 0
+ },
+ {
+ "test": "[P7-01 public/auth] /microsoft-legacy-relink nb/light 1280x900: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "46bd516a1264629e6c41691869ce9d5aa9e48d36baaf36e394259ceda5f4d11a",
+ "bytes": 104409
+ },
+ "context": {
+ "path": "/microsoft-legacy-relink",
+ "title": "microsoftLegacyRelinkTitle",
+ "language": "nb",
+ "mode": "light",
+ "width": 1280,
+ "height": 900,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1280,
+ "viewportHeight": 900,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 334.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Tilbake til innlogging",
+ "left": 538.46875,
+ "right": 691.9375,
+ "width": 153.46875,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Fortsett med Microsoft",
+ "left": 699.9375,
+ "right": 879,
+ "width": 179.0625,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1280,
+ "windowHeight": 900,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [],
+ "violationsNodes": 0,
+ "incompleteNodes": 0
+ },
+ {
+ "test": "[P7-01 public/auth] /microsoft-legacy-relink en/dark 1440x900: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "660bd988651b7056ed6aab306be0dcfeacaba8156003a2fde00fc7d4f65c36c6",
+ "bytes": 104331
+ },
+ "context": {
+ "path": "/microsoft-legacy-relink",
+ "title": "microsoftLegacyRelinkTitle",
+ "language": "en",
+ "mode": "dark",
+ "width": 1440,
+ "height": 900,
+ "screenshot": true,
+ "state": "missing-link",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1440,
+ "viewportHeight": 900,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 341.75,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Back to login",
+ "left": 658.6875,
+ "right": 762.28125,
+ "width": 103.59375,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Continue with Microsoft",
+ "left": 770.28125,
+ "right": 959,
+ "width": 188.71875,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1440,
+ "windowHeight": 900,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [],
+ "violationsNodes": 0,
+ "incompleteNodes": 0
+ },
+ {
+ "test": "[P7-01 public/auth] /register nb/dark 1280x320: landmarks, labels and reflow",
+ "attachment": "public-auth-presentation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "3d413f1ca998d2fa836a3ac88ece276fb7ae01ef1a1a341a9e038ebc86b37d3c",
+ "bytes": 153580
+ },
+ "context": {
+ "path": "/register",
+ "title": "createAccount",
+ "language": "nb",
+ "mode": "dark",
+ "width": 1280,
+ "height": 320,
+ "screenshot": true,
+ "state": "registration-disabled",
+ "density": "not-applicable",
+ "browserZoom": "not-measured"
+ },
+ "geometry": {
+ "viewportWidth": 1280,
+ "viewportHeight": 320,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 45,
+ "mainName": "_r_3_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 411,
+ "right": 869,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 411,
+ "right": 869,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "INPUT",
+ "type": "password",
+ "text": "",
+ "left": 411,
+ "right": 869,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Tilbake til innlogging",
+ "left": 401,
+ "right": 534.4375,
+ "width": 133.4375,
+ "height": 30.75
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Opprett konto",
+ "left": 754.828125,
+ "right": 879,
+ "width": 124.171875,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1280,
+ "windowHeight": 320,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_4_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_5_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_6_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ }
+ ]
+ }
+ ],
+ "violationsNodes": 0,
+ "incompleteNodes": 3
+ },
+ {
+ "test": "[P7-01 public/auth] en keyboard recovery entry preserves the prefill, validates locally and returns focus to sign-in",
+ "attachment": "public-auth-reset-request-validation-all-enabled-axe",
+ "raw": {
+ "storage": "Base64 attachment in raw report",
+ "sha256": "b20e7c0dec003fd31dd14bc5ebee4f1e033d1c31bb6ff4cde1b429c247259de0",
+ "bytes": 115730
+ },
+ "context": {
+ "language": "en",
+ "mode": "light",
+ "width": 1280,
+ "height": 900,
+ "route": "/forgot-password",
+ "state": "client-validation",
+ "requests": []
+ },
+ "geometry": {
+ "viewportWidth": 1280,
+ "viewportHeight": 900,
+ "pageOverflow": 0,
+ "mainOverflow": 0,
+ "headingTop": 347.75,
+ "mainName": "_r_c_",
+ "h1Count": 1,
+ "controls": [
+ {
+ "tag": "INPUT",
+ "type": "email",
+ "text": "",
+ "left": 411,
+ "right": 869,
+ "width": 458,
+ "height": 38.125
+ },
+ {
+ "tag": "BUTTON",
+ "type": "button",
+ "text": "Back to login",
+ "left": 619.703125,
+ "right": 739.296875,
+ "width": 119.59375,
+ "height": 36.5
+ },
+ {
+ "tag": "BUTTON",
+ "type": "submit",
+ "text": "Send reset link",
+ "left": 747.296875,
+ "right": 879,
+ "width": 131.703125,
+ "height": 36.5
+ }
+ ]
+ },
+ "engine": {
+ "name": "axe-core",
+ "version": "4.13.0"
+ },
+ "environment": {
+ "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36",
+ "windowWidth": 1280,
+ "windowHeight": 900,
+ "orientationAngle": 0,
+ "orientationType": "landscape-primary"
+ },
+ "toolOptions": {
+ "reporter": "v1"
+ },
+ "violations": [],
+ "incomplete": [
+ {
+ "id": "color-contrast",
+ "impact": "serious",
+ "tags": [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1"
+ ],
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "nodes": [
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "",
+ "target": [
+ "#_r_d_"
+ ],
+ "failureSummary": "Fix any of the following:\n Element's background color could not be determined because it is overlapped by another element"
+ },
+ {
+ "any": [
+ {
+ "id": "color-contrast",
+ "data": {
+ "contrastRatio": 0,
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": "bgOverlap",
+ "expectedContrastRatio": "4.5:1"
+ },
+ "relatedNodes": [],
+ "impact": "serious",
+ "message": "Element's background color could not be determined because it is overlapped by another element"
+ }
+ ],
+ "all": [],
+ "none": [],
+ "impact": "serious",
+ "html": "
)}
-
+
{registerMode ? t("createAccount") : t("signInTitle")}
+ {loading || resendingVerification ? {t("loading")} : null}
{!registerMode && (cfg?.googleEnabled || cfg?.microsoftEnabled) ? (
@@ -274,7 +281,6 @@ export default function LoginPage({ initialMode = "login" }: { initialMode?: "lo
) : null}
>
)}
-
-
+
);
}
diff --git a/job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx b/job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx
index 71a2671..49518de 100644
--- a/job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx
+++ b/job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx
@@ -1,11 +1,12 @@
import React, { useState } from "react";
-import { Alert, Box, Button, CircularProgress, Paper, Typography } from "@mui/material";
+import { Alert, Box, Button, CircularProgress, Typography } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { api, getApiErrorMessage } from "../api";
import { getMicrosoftMsalInstance } from "../components/MicrosoftAuthCard";
import { useI18n } from "../i18n/I18nProvider";
+import AuthPageFrame from "../layout/AuthPageFrame";
export default function MicrosoftLegacyRelinkPage() {
const { t } = useI18n();
@@ -45,22 +46,19 @@ export default function MicrosoftLegacyRelinkPage() {
}
return (
-
-
- {t("microsoftLegacyRelinkTitle")}
- {t("microsoftLegacyRelinkBody")}
+
{missing ? {t("microsoftLegacyRelinkMissing")} : null}
{error ? {error} : null}
- {success ? {t("microsoftLegacyRelinkSuccess")} : null}
-
+ {success ? {t("microsoftLegacyRelinkSuccess")} : null}
+ button": { maxWidth: "100%", whiteSpace: "normal", overflowWrap: "anywhere" } }}>
navigate("/login")}>{t("backToLogin")}
{!success ? (
- void confirm()}>
- {working ? : t("continueWithMicrosoft")}
+ : undefined} onClick={() => void confirm()}>
+ {t("continueWithMicrosoft")}
) : null}
-
-
+ {working ? {t("loading")} : null}
+
);
}
diff --git a/job-tracker-ui/src/views/ResetPasswordPage.tsx b/job-tracker-ui/src/views/ResetPasswordPage.tsx
index e0b29bd..f34f498 100644
--- a/job-tracker-ui/src/views/ResetPasswordPage.tsx
+++ b/job-tracker-ui/src/views/ResetPasswordPage.tsx
@@ -1,12 +1,13 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useRef, useState } from "react";
-import { Alert, Box, Button, Paper, TextField, Typography } from "@mui/material";
+import { Alert, Box, Button, TextField, Typography } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { api, getApiErrorMessage } from "../api";
import { useToast } from "../toast";
import { useI18n } from "../i18n/I18nProvider";
+import AuthPageFrame from "../layout/AuthPageFrame";
export default function ResetPasswordPage() {
const { toast } = useToast();
@@ -19,6 +20,9 @@ export default function ResetPasswordPage() {
const [confirmPassword, setConfirmPassword] = useState("");
const [loading, setLoading] = useState(false);
const [fieldErrors, setFieldErrors] = useState<{ newPassword?: string; confirmPassword?: string }>({});
+ const [submitError, setSubmitError] = useState(null);
+ const passwordRef = useRef(null);
+ const confirmPasswordRef = useRef(null);
useEffect(() => {
const params = new URLSearchParams(window.location.search);
@@ -29,25 +33,7 @@ export default function ResetPasswordPage() {
const missingResetInfo = !email || !token;
return (
-
-
-
- {t("resetPasswordTitle")}
-
-
- {t("resetPasswordBody")}
-
-
+
{
@@ -60,8 +46,12 @@ export default function ResetPasswordPage() {
if (!newPassword || newPassword.length < 8) errors.newPassword = t("passwordTooShort");
if (confirmPassword !== newPassword) errors.confirmPassword = t("passwordsDoNotMatch");
setFieldErrors(errors);
- if (Object.keys(errors).length > 0) return;
+ if (Object.keys(errors).length > 0) {
+ (errors.newPassword ? passwordRef : confirmPasswordRef).current?.focus();
+ return;
+ }
+ setSubmitError(null);
setLoading(true);
api
.post("/auth/reset-password", { email, token, newPassword })
@@ -70,13 +60,14 @@ export default function ResetPasswordPage() {
navigate("/login", { replace: true });
})
.catch((e2: any) => {
- toast(getApiErrorMessage(e2, t("resetFailed")), "error");
+ setSubmitError(getApiErrorMessage(e2, t("resetFailed")));
})
.finally(() => setLoading(false));
}}
sx={{ display: "flex", flexDirection: "column", gap: 1.5 }}
>
{missingResetInfo ? {t("missingResetLinkInfo")} : null}
+ {submitError ? {submitError} : null}
setEmail(e.target.value)} disabled={!missingResetInfo} fullWidth />
{ setNewPassword(e.target.value); setFieldErrors((f) => ({ ...f, newPassword: undefined, confirmPassword: undefined })); }}
autoComplete="new-password"
+ inputRef={passwordRef}
error={Boolean(fieldErrors.newPassword)}
helperText={fieldErrors.newPassword || t("passwordTooShort")}
fullWidth
@@ -94,21 +86,22 @@ export default function ResetPasswordPage() {
value={confirmPassword}
onChange={(e) => { setConfirmPassword(e.target.value); setFieldErrors((f) => ({ ...f, confirmPassword: undefined })); }}
autoComplete="new-password"
+ inputRef={confirmPasswordRef}
error={Boolean(fieldErrors.confirmPassword)}
helperText={fieldErrors.confirmPassword}
fullWidth
/>
-
+ button": { maxWidth: "100%", whiteSpace: "normal", overflowWrap: "anywhere" } }}>
navigate("/login")} disabled={loading}>
{t("backToLogin")}
-
+
{t("updatePassword")}
+ {loading ? {t("saving")} : null}
-
-
+
);
}
diff --git a/job-tracker-ui/src/views/VerifyEmailPage.tsx b/job-tracker-ui/src/views/VerifyEmailPage.tsx
index 015507e..9e55730 100644
--- a/job-tracker-ui/src/views/VerifyEmailPage.tsx
+++ b/job-tracker-ui/src/views/VerifyEmailPage.tsx
@@ -1,11 +1,12 @@
import React, { useEffect, useState } from "react";
-import { Alert, Box, Button, CircularProgress, Paper, Typography } from "@mui/material";
+import { Alert, Box, Button, CircularProgress, Typography } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { api, getApiErrorMessage } from "../api";
import { useI18n } from "../i18n/I18nProvider";
+import AuthPageFrame from "../layout/AuthPageFrame";
type Status = "verifying" | "success" | "error";
@@ -38,39 +39,23 @@ export default function VerifyEmailPage({ emailChange = false }: { emailChange?:
}, [emailChange, t]);
return (
-
-
-
- {t(emailChange ? "confirmEmailChangeTitle" : "verifyEmailTitle")}
-
-
-
+
+
{status === "verifying" && (
-
-
+
+
{t(emailChange ? "confirmEmailChangeVerifying" : "verifyEmailVerifying")}
)}
- {status === "success" && {t(emailChange ? "confirmEmailChangeSuccess" : "verifyEmailSuccess")}}
+ {status === "success" && {t(emailChange ? "confirmEmailChangeSuccess" : "verifyEmailSuccess")}}
{status === "error" && {errorMessage}}
-
+ button": { maxWidth: "100%", whiteSpace: "normal", overflowWrap: "anywhere" } }}>
navigate("/login")}>
{t("backToLogin")}
-
-
+
);
}