feat(ui): redesign login page with brand identity#115
Conversation
- Replace generic "Welcome Back" with AuthGate brand name and shield icon - Add "Secure Authentication" monospace badge to reinforce security identity - Style title in brand blue and refine font sizing for professional tone - Add dark mode overrides for brand icon, security label, and card shadow - Add responsive and reduced-motion support for new elements Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Redesigns the login page header to match AuthGate’s brand identity (icon, title, subtitle, security badge) while updating responsive behavior and dark-mode styling to keep the new elements visually consistent across themes.
Changes:
- Update login header markup to use a brand icon, “AuthGate” title, “Sign in to continue” subtitle, and a “Secure Authentication” label.
- Adjust login page CSS for the new header elements, including responsive sizing and reduced-motion handling.
- Add dark-mode overrides for the new brand icon, security label, and login card shadow.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| internal/templates/static/css/pages/login.css | Adds styles for the new brand icon and security label; tweaks title sizing/color; updates responsive and reduced-motion rules. |
| internal/templates/static/css/components/dark-mode.css | Adds dark-mode overrides for the new login header elements and card shadow. |
| internal/templates/login_page.templ | Updates login header markup and copy to the new branded layout. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| .login-brand-icon { | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| width: 72px; | ||
| height: 72px; | ||
| margin: 0 auto var(--space-5); | ||
| border-radius: var(--radius-xl); | ||
| background: linear-gradient(135deg, var(--color-primary-pale), #dbeafe); | ||
| border: 1px solid rgba(0, 114, 255, 0.15); | ||
| color: var(--color-primary); | ||
| animation: scaleIn 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) 0.3s both; | ||
| } |
There was a problem hiding this comment.
.login-brand-icon uses animation: scaleIn ..., but @keyframes scaleIn is not defined in this stylesheet. It currently works only because main.css happens to import components/alerts.css (which defines scaleIn) before pages/login.css, creating a hidden cross-file dependency. Consider defining @keyframes scaleIn in login.css (or moving it to a shared/global animations stylesheet) so this page doesn't rely on unrelated component CSS for its animation keyframes.
| @media (prefers-reduced-motion: reduce) { | ||
| .login-card, | ||
| .login-header, | ||
| .login-oauth-section, | ||
| .login-divider, | ||
| .login-form, | ||
| .login-oauth-btn, | ||
| .login-submit-btn { | ||
| .login-submit-btn, | ||
| .login-brand-icon { | ||
| animation: none !important; | ||
| transition: none !important; | ||
| } |
There was a problem hiding this comment.
The prefers-reduced-motion block disables animations/transitions on several elements, but animations/transitions declared on pseudo-elements (e.g., .login-card::before/::after animations and .login-oauth-btn::before transition) will still run because these properties do not inherit. If the goal is to respect reduced-motion settings, explicitly disable animations/transitions on the relevant pseudo-elements as well.
| <div class="login-brand-icon" aria-hidden="true"> | ||
| <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| <path d="M24 4L6 12V22C6 33.1 13.68 43.38 24 46C34.32 43.38 42 33.1 42 22V12L24 4Z" stroke="currentColor" stroke-width="2.5" fill="none"></path> | ||
| <rect x="20" y="19" width="8" height="10" rx="1.5" stroke="currentColor" stroke-width="2"></rect> | ||
| <path d="M18 19V16C18 12.69 20.69 10 24 10C27.31 10 30 12.69 30 16V19" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path> | ||
| <circle cx="24" cy="24" r="1.5" fill="currentColor"></circle> | ||
| <line x1="24" y1="25.5" x2="24" y2="27.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></line> | ||
| </svg> |
There was a problem hiding this comment.
The decorative inline SVG inside .login-brand-icon is wrapped in an aria-hidden="true" container, but the <svg> itself is missing focusable="false". In some browsers this can still create an unexpected keyboard tab stop. Consider adding focusable="false" (and optionally aria-hidden="true") directly on the <svg> to ensure it is fully non-interactive.
- Add focusable="false" and aria-hidden="true" to SVG to prevent keyboard tab stop - Define loginScaleIn keyframe locally to avoid hidden cross-file dependency on alerts.css - Disable animations/transitions on pseudo-elements in prefers-reduced-motion Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /* Login brand icon — hardcoded #dbeafe and rgba(0,114,255) won't adapt in dark mode */ | ||
| [data-theme="dark"] .login-brand-icon { | ||
| background: linear-gradient(135deg, var(--color-primary-pale), rgba(88, 166, 255, 0.12)); | ||
| border-color: rgba(88, 166, 255, 0.2); | ||
| } | ||
|
|
||
| /* Login security label — hardcoded rgba(0,114,255) border/bg won't adapt in dark mode */ | ||
| [data-theme="dark"] .login-security-label { | ||
| border-color: rgba(88, 166, 255, 0.25); | ||
| background: rgba(88, 166, 255, 0.06); | ||
| } | ||
|
|
||
| /* Login card shadow — hardcoded rgba(0,114,255) glow is too bright on dark backgrounds */ | ||
| [data-theme="dark"] .login-card { | ||
| box-shadow: | ||
| 0 20px 50px -12px rgba(88, 166, 255, 0.08), | ||
| 0 0 0 1px rgba(88, 166, 255, 0.1); |
There was a problem hiding this comment.
Same issue here: the label uses hard-coded rgba(88, 166, 255, …) values that duplicate the theme’s --color-primary for dark mode. Consider using a shared variable for the RGB value (or another theme token) to avoid future drift if the brand color is updated.
| /* Login brand icon — hardcoded #dbeafe and rgba(0,114,255) won't adapt in dark mode */ | |
| [data-theme="dark"] .login-brand-icon { | |
| background: linear-gradient(135deg, var(--color-primary-pale), rgba(88, 166, 255, 0.12)); | |
| border-color: rgba(88, 166, 255, 0.2); | |
| } | |
| /* Login security label — hardcoded rgba(0,114,255) border/bg won't adapt in dark mode */ | |
| [data-theme="dark"] .login-security-label { | |
| border-color: rgba(88, 166, 255, 0.25); | |
| background: rgba(88, 166, 255, 0.06); | |
| } | |
| /* Login card shadow — hardcoded rgba(0,114,255) glow is too bright on dark backgrounds */ | |
| [data-theme="dark"] .login-card { | |
| box-shadow: | |
| 0 20px 50px -12px rgba(88, 166, 255, 0.08), | |
| 0 0 0 1px rgba(88, 166, 255, 0.1); | |
| /* Login brand icon — use theme primary color token instead of hardcoded rgba() */ | |
| [data-theme="dark"] .login-brand-icon { | |
| background: linear-gradient( | |
| 135deg, | |
| var(--color-primary-pale), | |
| color-mix(in srgb, var(--color-primary) 12%, transparent) | |
| ); | |
| border-color: color-mix(in srgb, var(--color-primary) 20%, transparent); | |
| } | |
| /* Login security label — derive border/bg from theme primary color token */ | |
| [data-theme="dark"] .login-security-label { | |
| border-color: color-mix(in srgb, var(--color-primary) 25%, transparent); | |
| background: color-mix(in srgb, var(--color-primary) 6%, transparent); | |
| } | |
| /* Login card shadow — derive glow from theme primary color token */ | |
| [data-theme="dark"] .login-card { | |
| box-shadow: | |
| 0 20px 50px -12px color-mix(in srgb, var(--color-primary) 8%, transparent), | |
| 0 0 0 1px color-mix(in srgb, var(--color-primary) 10%, transparent); |
internal/templates/login_page.templ
Outdated
| <h1 class="login-title">Welcome Back</h1> | ||
| <p class="login-subtitle">Sign in to your account</p> | ||
| <div class="login-brand-icon" aria-hidden="true"> | ||
| <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false" aria-hidden="true"> |
There was a problem hiding this comment.
The wrapper div is already aria-hidden="true", so aria-hidden on the nested is redundant. Consider removing the duplicate aria-hidden attribute to reduce markup noise while keeping the icon decorative (focusable="false" can remain).
| <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false" aria-hidden="true"> | |
| <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" focusable="false"> |
| background: linear-gradient(135deg, var(--color-primary-pale), rgba(88, 166, 255, 0.12)); | ||
| border-color: rgba(88, 166, 255, 0.2); | ||
| } | ||
|
|
||
| /* Login security label — hardcoded rgba(0,114,255) border/bg won't adapt in dark mode */ | ||
| [data-theme="dark"] .login-security-label { | ||
| border-color: rgba(88, 166, 255, 0.25); | ||
| background: rgba(88, 166, 255, 0.06); | ||
| } | ||
|
|
||
| /* Login card shadow — hardcoded rgba(0,114,255) glow is too bright on dark backgrounds */ | ||
| [data-theme="dark"] .login-card { | ||
| box-shadow: | ||
| 0 20px 50px -12px rgba(88, 166, 255, 0.08), | ||
| 0 0 0 1px rgba(88, 166, 255, 0.1); |
There was a problem hiding this comment.
This dark-mode override hard-codes the primary blue as rgba(88, 166, 255, …), duplicating the value already set via --color-primary in base.css for dark mode. If the theme’s primary color changes, these overrides can drift. Consider using a shared variable for the RGB value (e.g., a --color-primary-rgb custom prop) so alpha variants stay in sync with the theme.
| background: linear-gradient(135deg, var(--color-primary-pale), rgba(88, 166, 255, 0.12)); | |
| border-color: rgba(88, 166, 255, 0.2); | |
| } | |
| /* Login security label — hardcoded rgba(0,114,255) border/bg won't adapt in dark mode */ | |
| [data-theme="dark"] .login-security-label { | |
| border-color: rgba(88, 166, 255, 0.25); | |
| background: rgba(88, 166, 255, 0.06); | |
| } | |
| /* Login card shadow — hardcoded rgba(0,114,255) glow is too bright on dark backgrounds */ | |
| [data-theme="dark"] .login-card { | |
| box-shadow: | |
| 0 20px 50px -12px rgba(88, 166, 255, 0.08), | |
| 0 0 0 1px rgba(88, 166, 255, 0.1); | |
| background: linear-gradient(135deg, var(--color-primary-pale), rgba(var(--color-primary-rgb, 88, 166, 255), 0.12)); | |
| border-color: rgba(var(--color-primary-rgb, 88, 166, 255), 0.2); | |
| } | |
| /* Login security label — hardcoded rgba(0,114,255) border/bg won't adapt in dark mode */ | |
| [data-theme="dark"] .login-security-label { | |
| border-color: rgba(var(--color-primary-rgb, 88, 166, 255), 0.25); | |
| background: rgba(var(--color-primary-rgb, 88, 166, 255), 0.06); | |
| } | |
| /* Login card shadow — hardcoded rgba(0,114,255) glow is too bright on dark backgrounds */ | |
| [data-theme="dark"] .login-card { | |
| box-shadow: | |
| 0 20px 50px -12px rgba(var(--color-primary-rgb, 88, 166, 255), 0.08), | |
| 0 0 0 1px rgba(var(--color-primary-rgb, 88, 166, 255), 0.1); |
- Replace hardcoded rgba() dark mode overrides with color-mix() derived from theme token - Remove redundant aria-hidden="true" on SVG (parent div already has it) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 135deg, | ||
| var(--color-primary-pale), | ||
| color-mix(in srgb, var(--color-primary) 12%, transparent) | ||
| ); | ||
| border-color: color-mix(in srgb, var(--color-primary) 20%, transparent); |
There was a problem hiding this comment.
color-mix() inside this background/border-color means the whole declaration is ignored in browsers without color-mix support, causing dark theme to fall back to the light-mode gradient/border from login.css (likely high-contrast mismatch). Add a fallback background/border-color declaration before the color-mix() version.
| } | ||
|
|
||
| /* Login security label — derive border/bg from theme primary color token */ | ||
| [data-theme="dark"] .login-security-label { |
There was a problem hiding this comment.
These dark-mode styles rely on color-mix(). If unsupported, the label will keep the light-mode rgba(...) border/background from login.css, which may be too low-contrast on dark backgrounds. Add fallback border-color/background values ahead of the color-mix() declarations.
| [data-theme="dark"] .login-security-label { | |
| [data-theme="dark"] .login-security-label { | |
| /* Fallbacks for browsers without color-mix() support */ | |
| border-color: rgba(59, 130, 246, 0.5); | |
| background: rgba(59, 130, 246, 0.06); |
| [data-theme="dark"] .login-card { | ||
| box-shadow: |
There was a problem hiding this comment.
This dark-mode box-shadow uses color-mix(). In browsers without color-mix support the entire box-shadow will be ignored and the light-mode shadow from login.css will be used in dark theme. Consider adding a fallback box-shadow before the color-mix() version.
| [data-theme="dark"] .login-card { | |
| box-shadow: | |
| [data-theme="dark"] .login-card { | |
| /* Fallback shadow for browsers without color-mix() support */ | |
| box-shadow: | |
| 0 20px 50px -12px rgba(15, 23, 42, 0.7), | |
| 0 0 0 1px rgba(148, 163, 184, 0.4); | |
| /* Enhanced shadow using theme primary color token; overrides fallback when supported */ | |
| box-shadow: |
- Add rgba() fallback declarations before each color-mix() usage - Ensures dark mode renders correctly in browsers without color-mix() support Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Summary
Test plan
make generate && make lint && make test— all passprefers-reduced-motiondisables icon animation🤖 Generated with Claude Code