← Back to Index

Login Screen

Blazor Hybrid spec for the ALPA member login and non-member login screens (AB#1821 / AB#2174). Covers layout, pinned bottom navigation, component slots, and variant differences.

Figma node: 5387:32346 (member login) · Razor pages: Components/Pages/LoginPage.razor, Components/Pages/LoginNonMembersPage.razor · Routes: /login (member), /login/non-members (non-member) · Branch: feat/AB1821-login-scaffold-01

Layout Contract

Pinned bottom navigation — required on all screens. The bottom tab bar must always remain visible and anchored to the bottom of the viewport regardless of page content height or scroll position. Only the content area between the nav header and the bottom nav bar scrolls. This is a hard requirement; screens that allow the nav bar to scroll out of view fail the layout spec.

CSS pattern

The outer screen container must use height: 100vh (exact viewport height) with overflow: hidden. The scrollable content slot uses flex: 1 1 auto; overflow-y: auto. The bottom nav uses flex-shrink: 0. Never use min-height: 100vh on the outer container — it allows the container to grow past the viewport, which causes the nav bar to scroll away with the content.

/* ✅ Correct — outer shell is exactly viewport height */
.screen {
    display: flex;
    flex-direction: column;
    height: 100vh;       /* NOT min-height */
    overflow: hidden;    /* prevents outer scroll; only .content scrolls */
}

.content {
    flex: 1 1 auto;
    overflow-y: auto;    /* only this region scrolls */
}

.bottom-nav {
    flex-shrink: 0;      /* always pinned; never compressed */
}

/* ❌ Wrong — container grows with content; nav scrolls away */
.screen {
    display: flex;
    flex-direction: column;
    min-height: 100vh;   /* BAD */
}

Layer stack (top → bottom)

┌─────────────────────────────────────┐ │ Status bar spacer (54 px iOS) │ flex-shrink: 0 │ Nav title row (44 px) │ flex-shrink: 0 ├─────────────────────────────────────┤ │ │ │ Scrollable content │ flex: 1 1 auto │ (logo, fields, buttons, footer) │ overflow-y: auto │ │ ├─────────────────────────────────────┤ │ Bottom tab bar (≈ 72 px + safe) │ flex-shrink: 0 ← ALWAYS PINNED └─────────────────────────────────────┘

This pattern applies to every Blazor Hybrid screen that includes a bottom nav bar, not just the login screens. Future screens must follow the same contract.

Screen Variants

Slot Member Login (/login) Non-Member Login (/login/non-members)
Nav title Log In Log In
Logo ALPA globe mark (129 × 129 px) ALPA globe mark (129 × 129 px)
Field 1 label Member Number or ALPA Email Email Address
Field 2 label Password Password
Primary CTA ALPA MEMBERS LOG IN (action-button style) LOG IN (action-button style)
Secondary button NON-MEMBERS LOG IN (outline) ALPA MEMBERS LOG IN (outline)
Create account link CREATE ALPA ACCOUNT (underline) (not present)
Remember Me row ✓ present ✓ present
FORGOT PASSWORD? ✓ present ✓ present
Footer help text Having trouble accessing your account? Click here… Having trouble accessing your account? Click here…

Bottom Navigation Bar

The bottom tab bar is a static display fixture on the login screens — tabs are not interactive until the user authenticates. It shows the five primary sections so the user understands where they are in the app structure.

#LabelIconState
1HOMEHouse glyphStatic / non-interactive
2JUMPSEATSeat glyphStatic / non-interactive
3KCMPerson glyphStatic / non-interactive
4FTDTClock glyphStatic / non-interactive
5MY MECCircle glyphStatic / non-interactive
Safe area note. On devices with a home indicator (iPhone X+), add padding-bottom: env(safe-area-inset-bottom) to the bottom nav bar so content is not obscured by the home indicator. The BlazorWebView in MAUI handles the outer safe area by default, but the inner nav bar still needs explicit padding if it sits flush at the bottom.

CSS Class Reference

All classes live in wwwroot/css/alpa-components.css.

ClassRoleKey constraint
.alpa-login-screen Outer shell — full viewport height: 100vh; overflow: hidden
.alpa-login-statusbar iOS status bar spacer height: 54 px; flex-shrink: 0
.alpa-login-nav Nav title row height: 44 px; flex-shrink: 0
.alpa-login-content Scrollable content region flex: 1 1 auto; overflow-y: auto
.alpa-login-bottom-nav Pinned bottom tab bar flex-shrink: 0 — never compresses
.alpa-login-fields Form fields group width: 100%; flex-direction: column; gap: 16 px
.alpa-login-outline-btn Secondary outline button border: 2 px solid navy; full-width
.alpa-login-underline-btn Tertiary underline link-button text-decoration: underline; no border/background

Scaffolding Rules for Agents

Scaffolds must be interactive — never use disabled. Every scaffold page delivered by an agent must have fully interactive HTML elements. Users (and other agents) test scaffolds by tapping buttons, focusing inputs, and scrolling. A scaffold with disabled attributes or non-input placeholders (e.g. <div> instead of <input>) cannot be tested and is incomplete. No ViewModel wiring is needed at scaffold stage, but the HTML must respond to user interaction.

Input fields

Buttons and links

Checkboxes and toggles

CSS input reset

Always apply the following resets on <input> elements to neutralise browser defaults inside the WebView:

input.alpa-login-input {
    outline: none;
    -webkit-appearance: none;
    appearance: none;
    border-radius: 0;
}
input.alpa-login-input:focus {
    outline: none;
    border-color: var(--alpa-blue);
}

Implementation Status

ItemStatusNotes
Interactive scaffold — member login ✓ Done Commits be267c28 + cac2954f — real inputs, no disabled attrs, no ViewModel wiring
Interactive scaffold — non-member login ✓ Done Commits be267c28 + cac2954f
Bottom nav pinned (height: 100vh) ✓ Done Fixed from min-heightheight; overflow: hidden added
ViewModel wiring — authentication Planned AB#2174 — gated on Presentation Extraction (AB#2087)
Field validation / error states Planned AB#2174
Keyboard avoidance (form scroll) Planned Ensure .alpa-login-content scrolls up when soft keyboard appears
Safe-area bottom padding Planned Add env(safe-area-inset-bottom) to .alpa-login-bottom-nav padding