feat(auth): add custom Keycloak login theme matching dashboard
Branded Keycloak login page with CERTifAI dark theme: indigo/teal color palette, Inter + Space Grotesk fonts, animated background gradients, card glow, logo float, and button shimmer effects. Overrides PatternFly v4 defaults including autofill color fix. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -12,9 +12,11 @@
|
|||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# Keycloak runtime data (but keep realm-export.json)
|
# Keycloak runtime data (but keep config and theme)
|
||||||
keycloak/*
|
keycloak/*
|
||||||
!keycloak/realm-export.json
|
!keycloak/realm-export.json
|
||||||
|
!keycloak/themes/
|
||||||
|
!keycloak/themes/**
|
||||||
|
|
||||||
# Node modules
|
# Node modules
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ services:
|
|||||||
- --import-realm
|
- --import-realm
|
||||||
volumes:
|
volumes:
|
||||||
- ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json:ro
|
- ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json:ro
|
||||||
|
- ./keycloak/themes/certifai:/opt/keycloak/themes/certifai:ro
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health/ready"]
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health/ready"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"loginWithEmailAllowed": true,
|
"loginWithEmailAllowed": true,
|
||||||
"duplicateEmailsAllowed": false,
|
"duplicateEmailsAllowed": false,
|
||||||
"resetPasswordAllowed": true,
|
"resetPasswordAllowed": true,
|
||||||
|
"loginTheme": "certifai",
|
||||||
"editUsernameAllowed": false,
|
"editUsernameAllowed": false,
|
||||||
"bruteForceProtected": true,
|
"bruteForceProtected": true,
|
||||||
"permanentLockout": false,
|
"permanentLockout": false,
|
||||||
|
|||||||
583
keycloak/themes/certifai/login/resources/css/login.css
Normal file
583
keycloak/themes/certifai/login/resources/css/login.css
Normal file
@@ -0,0 +1,583 @@
|
|||||||
|
/* CERTifAI Keycloak Login Theme
|
||||||
|
* Overrides PatternFly v4 / legacy Keycloak classes to match the dashboard.
|
||||||
|
*
|
||||||
|
* Actual page structure (Keycloak 26 with parent=keycloak):
|
||||||
|
* html.login-pf > body
|
||||||
|
* div.login-pf-page
|
||||||
|
* div#kc-header.login-pf-page-header
|
||||||
|
* div#kc-header-wrapper
|
||||||
|
* div.card-pf
|
||||||
|
* header.login-pf-header > h1#kc-page-title
|
||||||
|
* div#kc-content > div#kc-content-wrapper
|
||||||
|
* form#kc-form-login
|
||||||
|
* .form-group (email)
|
||||||
|
* .form-group (password + .pf-c-input-group)
|
||||||
|
* .form-group.login-pf-settings (forgot pwd)
|
||||||
|
* .form-group #kc-form-buttons (submit: input#kc-login.pf-c-button.pf-m-primary)
|
||||||
|
* div#kc-info.login-pf-signup (register link)
|
||||||
|
*
|
||||||
|
* Classes used: pf-c-* (PF v4), login-pf-*, card-pf, form-group
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ===== Google Fonts ===== */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Space+Grotesk:wght@500;600;700&display=swap');
|
||||||
|
|
||||||
|
/* ===== CSS Variables ===== */
|
||||||
|
:root {
|
||||||
|
--cai-bg-body: #0f1116;
|
||||||
|
--cai-bg-card: #1a1d26;
|
||||||
|
--cai-bg-surface: #1e222d;
|
||||||
|
--cai-bg-input: #12141a;
|
||||||
|
--cai-text-primary: #e2e8f0;
|
||||||
|
--cai-text-heading: #f1f5f9;
|
||||||
|
--cai-text-muted: #8892a8;
|
||||||
|
--cai-text-faint: #5a6478;
|
||||||
|
--cai-border-primary: #1e222d;
|
||||||
|
--cai-border-secondary: #2a2f3d;
|
||||||
|
--cai-accent: #91a4d2;
|
||||||
|
--cai-accent-secondary: #6d85c6;
|
||||||
|
--cai-brand-indigo: #4B3FE0;
|
||||||
|
--cai-brand-teal: #38B2AC;
|
||||||
|
--cai-error: #f87171;
|
||||||
|
--cai-success: #4ade80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Animations ===== */
|
||||||
|
|
||||||
|
/* Slow-moving ambient gradient behind the page */
|
||||||
|
@keyframes ambientShift {
|
||||||
|
0% { background-position: 0% 0%; }
|
||||||
|
25% { background-position: 100% 50%; }
|
||||||
|
50% { background-position: 50% 100%; }
|
||||||
|
75% { background-position: 0% 50%; }
|
||||||
|
100% { background-position: 0% 0%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subtle glow pulse on the card */
|
||||||
|
@keyframes cardGlow {
|
||||||
|
0%, 100% { box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 0 60px rgba(75, 63, 224, 0.04); }
|
||||||
|
50% { box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 0 80px rgba(56, 178, 172, 0.06); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gentle float for the logo */
|
||||||
|
@keyframes logoFloat {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-4px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient shimmer on the button */
|
||||||
|
@keyframes buttonShimmer {
|
||||||
|
0% { background-position: 0% 50%; }
|
||||||
|
50% { background-position: 100% 50%; }
|
||||||
|
100% { background-position: 0% 50%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Base Page ===== */
|
||||||
|
html.login-pf {
|
||||||
|
background-color: var(--cai-bg-body) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.login-pf body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse at 20% 20%, rgba(75, 63, 224, 0.07) 0%, transparent 50%),
|
||||||
|
radial-gradient(ellipse at 80% 80%, rgba(56, 178, 172, 0.05) 0%, transparent 50%),
|
||||||
|
radial-gradient(ellipse at 50% 50%, rgba(109, 133, 198, 0.03) 0%, transparent 70%),
|
||||||
|
var(--cai-bg-body) !important;
|
||||||
|
background-size: 200% 200%, 200% 200%, 100% 100%, 100% 100% !important;
|
||||||
|
animation: ambientShift 20s ease-in-out infinite !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Page Layout ===== */
|
||||||
|
.login-pf-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 40px 24px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Header (Logo + Realm Name) ===== */
|
||||||
|
#kc-header.login-pf-page-header {
|
||||||
|
background: transparent !important;
|
||||||
|
background-image: none !important;
|
||||||
|
padding: 0 0 32px !important;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 440px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-header-wrapper {
|
||||||
|
font-family: 'Space Grotesk', sans-serif !important;
|
||||||
|
font-size: 28px !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
color: var(--cai-text-heading) !important;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
text-transform: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo via ::before pseudo-element */
|
||||||
|
#kc-header-wrapper::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
background-image: url('../img/logo.svg');
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
animation: logoFloat 4s ease-in-out infinite;
|
||||||
|
filter: drop-shadow(0 0 12px rgba(75, 63, 224, 0.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Login Card ===== */
|
||||||
|
.card-pf {
|
||||||
|
background-color: var(--cai-bg-card) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
max-width: 440px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 32px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
animation: cardGlow 6s ease-in-out infinite;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subtle gradient border effect on the card via ::before overlay */
|
||||||
|
.card-pf::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
var(--cai-brand-indigo),
|
||||||
|
var(--cai-brand-teal),
|
||||||
|
var(--cai-accent-secondary),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Card Header (Sign In Title) ===== */
|
||||||
|
.login-pf-header {
|
||||||
|
border-bottom: none !important;
|
||||||
|
padding: 0 0 24px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-page-title {
|
||||||
|
font-family: 'Space Grotesk', sans-serif !important;
|
||||||
|
font-size: 22px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
color: var(--cai-text-heading) !important;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Form Groups ===== */
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Labels ===== */
|
||||||
|
.pf-c-form__label,
|
||||||
|
.pf-c-form__label-text,
|
||||||
|
.login-pf-page .form-group label,
|
||||||
|
.card-pf label {
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
margin-bottom: 6px !important;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Text Inputs ===== */
|
||||||
|
.pf-c-form-control,
|
||||||
|
.login-pf-page .form-control,
|
||||||
|
.card-pf input[type="text"],
|
||||||
|
.card-pf input[type="password"],
|
||||||
|
.card-pf input[type="email"] {
|
||||||
|
background-color: var(--cai-bg-input) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
padding: 10px 14px !important;
|
||||||
|
height: auto !important;
|
||||||
|
line-height: 1.5 !important;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-form-control:focus,
|
||||||
|
.pf-c-form-control:focus-within,
|
||||||
|
.card-pf input[type="text"]:focus,
|
||||||
|
.card-pf input[type="password"]:focus,
|
||||||
|
.card-pf input[type="email"]:focus {
|
||||||
|
border-color: var(--cai-accent) !important;
|
||||||
|
box-shadow: 0 0 0 1px var(--cai-accent), 0 0 12px rgba(145, 164, 210, 0.1) !important;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-form-control::placeholder,
|
||||||
|
.card-pf input::placeholder {
|
||||||
|
color: var(--cai-text-faint) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override browser autofill yellow background */
|
||||||
|
input:-webkit-autofill,
|
||||||
|
input:-webkit-autofill:hover,
|
||||||
|
input:-webkit-autofill:focus,
|
||||||
|
input:-webkit-autofill:active {
|
||||||
|
-webkit-box-shadow: 0 0 0 9999px var(--cai-bg-input) inset !important;
|
||||||
|
-webkit-text-fill-color: var(--cai-text-primary) !important;
|
||||||
|
caret-color: var(--cai-text-primary) !important;
|
||||||
|
transition: background-color 5000s ease-in-out 0s !important;
|
||||||
|
background-color: var(--cai-bg-input) !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox autofill override */
|
||||||
|
input:autofill {
|
||||||
|
background-color: var(--cai-bg-input) !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
border-color: var(--cai-border-secondary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Additional specificity for autofill inside input-group */
|
||||||
|
.pf-c-input-group input:-webkit-autofill,
|
||||||
|
.card-pf input:-webkit-autofill,
|
||||||
|
.form-group input:-webkit-autofill,
|
||||||
|
#username:-webkit-autofill,
|
||||||
|
#password:-webkit-autofill {
|
||||||
|
-webkit-box-shadow: 0 0 0 9999px var(--cai-bg-input) inset !important;
|
||||||
|
-webkit-text-fill-color: var(--cai-text-primary) !important;
|
||||||
|
background-color: var(--cai-bg-input) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Password Input Group ===== */
|
||||||
|
/* FIX: The .pf-c-input-group has white bg from PF4, causing white corners
|
||||||
|
* behind the rounded child elements. Set transparent + matching border-radius. */
|
||||||
|
.pf-c-input-group {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: stretch !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
background: transparent !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-input-group > .pf-c-form-control,
|
||||||
|
.pf-c-input-group > input.pf-c-form-control,
|
||||||
|
.pf-c-input-group > input[type="password"],
|
||||||
|
#password {
|
||||||
|
border-radius: 8px 0 0 8px !important;
|
||||||
|
border-right: none !important;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Password visibility toggle */
|
||||||
|
.pf-c-button.pf-m-control,
|
||||||
|
.pf-c-input-group > .pf-c-button.pf-m-control {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
border-top: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-right: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-bottom: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-left: 1px solid var(--cai-border-primary) !important;
|
||||||
|
border-radius: 0 8px 8px 0 !important;
|
||||||
|
padding: 0 14px !important;
|
||||||
|
transition: color 0.2s ease, background-color 0.2s ease !important;
|
||||||
|
line-height: 1 !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-button.pf-m-control:hover,
|
||||||
|
.pf-c-input-group > .pf-c-button.pf-m-control:hover {
|
||||||
|
color: var(--cai-accent) !important;
|
||||||
|
background-color: rgba(145, 164, 210, 0.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-button.pf-m-control:focus,
|
||||||
|
.pf-c-input-group > .pf-c-button.pf-m-control:focus {
|
||||||
|
box-shadow: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Primary Button (Sign In) ===== */
|
||||||
|
.pf-c-button.pf-m-primary,
|
||||||
|
input.pf-c-button.pf-m-primary,
|
||||||
|
#kc-login {
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
var(--cai-accent),
|
||||||
|
var(--cai-accent-secondary),
|
||||||
|
var(--cai-brand-indigo),
|
||||||
|
var(--cai-accent-secondary),
|
||||||
|
var(--cai-accent)) !important;
|
||||||
|
background-size: 300% 100% !important;
|
||||||
|
animation: buttonShimmer 6s ease-in-out infinite !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: #0a0c10 !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
padding: 12px 20px !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
transition: opacity 0.15s ease, box-shadow 0.2s ease !important;
|
||||||
|
text-shadow: none !important;
|
||||||
|
box-shadow: 0 2px 12px rgba(109, 133, 198, 0.2) !important;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-button.pf-m-primary:hover,
|
||||||
|
input.pf-c-button.pf-m-primary:hover,
|
||||||
|
#kc-login:hover {
|
||||||
|
opacity: 0.95;
|
||||||
|
box-shadow: 0 4px 20px rgba(109, 133, 198, 0.35) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-button.pf-m-primary:focus,
|
||||||
|
#kc-login:focus {
|
||||||
|
box-shadow: 0 0 0 2px var(--cai-accent), 0 4px 20px rgba(109, 133, 198, 0.3) !important;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Links ===== */
|
||||||
|
.login-pf-page a,
|
||||||
|
.card-pf a {
|
||||||
|
color: var(--cai-accent) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
transition: color 0.15s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-pf-page a:hover,
|
||||||
|
.card-pf a:hover {
|
||||||
|
color: var(--cai-accent-secondary) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forgot Password link */
|
||||||
|
.login-pf-settings {
|
||||||
|
text-align: right;
|
||||||
|
margin-bottom: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-pf-settings a {
|
||||||
|
font-size: 13px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Registration / Info Section ===== */
|
||||||
|
#kc-info.login-pf-signup {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
border-top: 1px solid var(--cai-border-primary) !important;
|
||||||
|
padding: 16px 32px !important;
|
||||||
|
margin: 0 -32px -32px !important;
|
||||||
|
border-radius: 0 0 12px 12px !important;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-info-wrapper,
|
||||||
|
#kc-registration {
|
||||||
|
font-size: 14px !important;
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-registration span {
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Alert / Error Messages ===== */
|
||||||
|
.alert,
|
||||||
|
.pf-c-alert {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
padding: 12px 16px !important;
|
||||||
|
margin-bottom: 16px !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-error,
|
||||||
|
.alert-warning,
|
||||||
|
.pf-c-alert.pf-m-danger,
|
||||||
|
.pf-c-alert.pf-m-warning {
|
||||||
|
border-color: var(--cai-error) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-error .kc-feedback-text,
|
||||||
|
.pf-c-alert .pf-c-alert__title {
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
border-color: var(--cai-success) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Checkboxes (Remember Me) ===== */
|
||||||
|
.pf-c-check,
|
||||||
|
.login-pf-page .checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-check__label,
|
||||||
|
.login-pf-page .checkbox label {
|
||||||
|
font-size: 13px !important;
|
||||||
|
color: var(--cai-text-muted) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-c-check__input,
|
||||||
|
.login-pf-page input[type="checkbox"] {
|
||||||
|
accent-color: var(--cai-accent);
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Select / Dropdown ===== */
|
||||||
|
.card-pf select,
|
||||||
|
.login-pf-page select {
|
||||||
|
background-color: var(--cai-bg-input) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
padding: 10px 14px !important;
|
||||||
|
font-family: 'Inter', sans-serif !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Social Login / Identity Providers ===== */
|
||||||
|
#kc-social-providers {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid var(--cai-border-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-social-providers ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-social-providers li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-social-providers a,
|
||||||
|
#kc-social-providers .pf-c-button {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
padding: 10px 16px !important;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
transition: border-color 0.15s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-social-providers a:hover,
|
||||||
|
#kc-social-providers .pf-c-button:hover {
|
||||||
|
border-color: var(--cai-accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Form Buttons Row ===== */
|
||||||
|
#kc-form-buttons {
|
||||||
|
margin-top: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-form-options {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tooltip ===== */
|
||||||
|
.kc-tooltip-text {
|
||||||
|
background-color: var(--cai-bg-surface) !important;
|
||||||
|
color: var(--cai-text-primary) !important;
|
||||||
|
border: 1px solid var(--cai-border-secondary) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Scrollbar ===== */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--cai-bg-body);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--cai-border-secondary);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--cai-text-faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Responsive ===== */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.login-pf-page {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-pf {
|
||||||
|
padding: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-header-wrapper {
|
||||||
|
font-size: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-header-wrapper::before {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-info.login-pf-signup {
|
||||||
|
margin: 0 -24px -24px !important;
|
||||||
|
padding: 16px 24px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Override PatternFly background images ===== */
|
||||||
|
.login-pf-page .login-pf-page-header,
|
||||||
|
.login-pf body {
|
||||||
|
background-image: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove any PF4 container-fluid stretching */
|
||||||
|
.container-fluid {
|
||||||
|
padding: 0 !important;
|
||||||
|
max-width: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the card doesn't stretch full width */
|
||||||
|
.login-pf-page > .card-pf {
|
||||||
|
max-width: 440px;
|
||||||
|
margin: 0 auto !important;
|
||||||
|
}
|
||||||
25
keycloak/themes/certifai/login/resources/img/logo.svg
Normal file
25
keycloak/themes/certifai/login/resources/img/logo.svg
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
|
||||||
|
<!-- Shield body -->
|
||||||
|
<path d="M32 4L8 16v16c0 14.4 10.24 27.2 24 32 13.76-4.8 24-17.6 24-32V16L32 4z"
|
||||||
|
fill="#4B3FE0" fill-opacity="0.12" stroke="#4B3FE0" stroke-width="2"
|
||||||
|
stroke-linejoin="round"/>
|
||||||
|
<!-- Inner shield highlight -->
|
||||||
|
<path d="M32 10L14 19v11c0 11.6 7.68 22 18 26 10.32-4 18-14.4 18-26V19L32 10z"
|
||||||
|
fill="none" stroke="#4B3FE0" stroke-width="1" stroke-opacity="0.3"
|
||||||
|
stroke-linejoin="round"/>
|
||||||
|
<!-- Neural network nodes -->
|
||||||
|
<circle cx="32" cy="24" r="3.5" fill="#38B2AC"/>
|
||||||
|
<circle cx="22" cy="36" r="3" fill="#38B2AC"/>
|
||||||
|
<circle cx="42" cy="36" r="3" fill="#38B2AC"/>
|
||||||
|
<circle cx="27" cy="48" r="2.5" fill="#38B2AC" fill-opacity="0.7"/>
|
||||||
|
<circle cx="37" cy="48" r="2.5" fill="#38B2AC" fill-opacity="0.7"/>
|
||||||
|
<!-- Neural network edges -->
|
||||||
|
<line x1="32" y1="24" x2="22" y2="36" stroke="#38B2AC" stroke-width="1.2" stroke-opacity="0.6"/>
|
||||||
|
<line x1="32" y1="24" x2="42" y2="36" stroke="#38B2AC" stroke-width="1.2" stroke-opacity="0.6"/>
|
||||||
|
<line x1="22" y1="36" x2="27" y2="48" stroke="#38B2AC" stroke-width="1" stroke-opacity="0.4"/>
|
||||||
|
<line x1="22" y1="36" x2="37" y2="48" stroke="#38B2AC" stroke-width="1" stroke-opacity="0.4"/>
|
||||||
|
<line x1="42" y1="36" x2="27" y2="48" stroke="#38B2AC" stroke-width="1" stroke-opacity="0.4"/>
|
||||||
|
<line x1="42" y1="36" x2="37" y2="48" stroke="#38B2AC" stroke-width="1" stroke-opacity="0.4"/>
|
||||||
|
<!-- Cross edge for connectivity -->
|
||||||
|
<line x1="22" y1="36" x2="42" y2="36" stroke="#38B2AC" stroke-width="0.8" stroke-opacity="0.3"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
3
keycloak/themes/certifai/login/theme.properties
Normal file
3
keycloak/themes/certifai/login/theme.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
parent=keycloak
|
||||||
|
import=common/keycloak
|
||||||
|
styles=css/login.css
|
||||||
Reference in New Issue
Block a user