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.
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 */
}
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.
| 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… |
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.
| # | Label | Icon | State |
|---|---|---|---|
| 1 | HOME | House glyph | Static / non-interactive |
| 2 | JUMPSEAT | Seat glyph | Static / non-interactive |
| 3 | KCM | Person glyph | Static / non-interactive |
| 4 | FTDT | Clock glyph | Static / non-interactive |
| 5 | MY MEC | Circle glyph | Static / non-interactive |
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.
All classes live in wwwroot/css/alpa-components.css.
| Class | Role | Key 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 |
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> element — never a <div> or <span> as a fake field.type attribute: text, email, or password as appropriate.autocomplete to the appropriate value (username, email, current-password, etc.).disabled or readonly on scaffold inputs.disabled on any button or link-button at scaffold stage.@onclick handlers or no handler at all — that is fine.<div> for a <button>.<input type="checkbox"> — not a styled <div>.disabled.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);
}
| Item | Status | Notes |
|---|---|---|
| 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-height → height; 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 |