diff --git a/keycloak/themes/certifai/login/resources/css/login.css b/keycloak/themes/certifai/login/resources/css/login.css index c8123a2..2533515 100644 --- a/keycloak/themes/certifai/login/resources/css/login.css +++ b/keycloak/themes/certifai/login/resources/css/login.css @@ -75,6 +75,7 @@ /* ===== Base Page ===== */ html.login-pf { background-color: var(--cai-bg-body) !important; + background-image: none !important; } html.login-pf body { @@ -469,38 +470,146 @@ input.pf-c-button.pf-m-primary:hover, /* ===== Social Login / Identity Providers ===== */ #kc-social-providers { - margin-top: 20px; - padding-top: 20px; - border-top: 1px solid var(--cai-border-primary); + margin-top: 24px !important; + padding-top: 20px !important; + border-top: 1px solid var(--cai-border-primary) !important; } -#kc-social-providers ul { - list-style: none; - padding: 0; - margin: 0; +/* Social
separator */ +#kc-social-providers > hr { + border: none !important; + border-top: 1px solid var(--cai-border-primary) !important; + margin: 0 0 16px 0 !important; } +/* "Or sign in with" heading - subtle divider text */ +#kc-social-providers h2, +#kc-social-providers > h2, +#kc-social-providers h4 { + font-family: 'Inter', sans-serif !important; + font-size: 12px !important; + font-weight: 500 !important; + color: var(--cai-text-faint) !important; + text-transform: uppercase !important; + letter-spacing: 0.08em !important; + text-align: center !important; + margin: 0 0 16px 0 !important; + padding: 0 !important; +} + +/* Social button list - stacked full-width + * Production uses: ul.pf-c-login__main-footer-links.kc-social-links + * PF4 sets flex-direction:row on this - we must override with high specificity */ +#kc-social-providers ul.pf-c-login__main-footer-links, +#kc-social-providers ul.kc-social-links, +#kc-social-providers ul, +#kc-social-providers ol { + list-style: none !important; + padding: 0 !important; + margin: 0 !important; + display: flex !important; + flex-direction: column !important; + gap: 10px !important; + width: 100% !important; +} + +#kc-social-providers ul.pf-c-login__main-footer-links > li, +#kc-social-providers ul.kc-social-links > li, #kc-social-providers li { - margin-bottom: 8px; + margin: 0 !important; + padding: 0 !important; + width: 100% !important; + flex: none !important; + display: block !important; } +/* Social login buttons - full-width stacked with icon + label + * Production uses: a.pf-c-button.pf-m-control.pf-m-block.kc-social-item + * Must override .pf-c-button.pf-m-control (password toggle uses same classes) */ +#kc-social-providers a.pf-c-button.pf-m-control, +#kc-social-providers a.kc-social-item, +#kc-social-providers a.pf-m-block, #kc-social-providers a, -#kc-social-providers .pf-c-button { - background-color: var(--cai-bg-surface) !important; +#kc-social-providers .zocial { + background-color: var(--cai-bg-input) !important; border: 1px solid var(--cai-border-secondary) !important; + border-top: 1px solid var(--cai-border-secondary) !important; + border-left: 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; + padding: 12px 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + gap: 10px !important; + width: 100% !important; + box-sizing: border-box !important; + text-align: center !important; + font-family: 'Inter', sans-serif !important; font-size: 14px !important; font-weight: 500 !important; - transition: border-color 0.15s ease !important; + text-decoration: none !important; + transition: border-color 0.2s ease, background-color 0.2s ease, + box-shadow 0.2s ease, transform 0.15s ease !important; + white-space: nowrap !important; } +#kc-social-providers a.pf-c-button.pf-m-control:hover, +#kc-social-providers a.kc-social-item:hover, #kc-social-providers a:hover, -#kc-social-providers .pf-c-button:hover { +#kc-social-providers .zocial:hover { border-color: var(--cai-accent) !important; + background-color: rgba(145, 164, 210, 0.06) !important; + box-shadow: 0 0 16px rgba(145, 164, 210, 0.12) !important; + color: var(--cai-text-heading) !important; + transform: translateY(-1px) !important; +} + +/* Provider icons inside social buttons */ +#kc-social-providers .kc-social-provider-logo, +#kc-social-providers i.fa, +#kc-social-providers .kc-social-icon-text { + color: var(--cai-accent) !important; + font-size: 16px !important; + flex-shrink: 0 !important; +} + +/* Provider text label */ +#kc-social-providers .kc-social-provider-name { + font-family: 'Inter', sans-serif !important; + font-size: 14px !important; + font-weight: 500 !important; +} + +/* Grid layout for social providers (some themes use .kc-social-grid) */ +.kc-social-grid { + display: flex !important; + flex-direction: column !important; + gap: 10px !important; +} + +.kc-social-grid > div { + width: 100% !important; + max-width: none !important; + flex: none !important; +} + +/* PF v5 grid layout override */ +.pf-v5-l-grid.pf-m-gutter { + display: flex !important; + flex-direction: column !important; + gap: 10px !important; +} + +.pf-v5-l-grid__item { + width: 100% !important; + max-width: none !important; + flex: none !important; +} + +/* Social section separator */ +#kc-social-providers::before { + content: none; } /* ===== Form Buttons Row ===== */ @@ -581,3 +690,244 @@ input.pf-c-button.pf-m-primary:hover, max-width: 440px; margin: 0 auto !important; } + +/* ===== Legal Footer (injected by footer.js) ===== */ +.cai-legal-footer { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + margin-top: 24px; + padding: 0; +} + +.cai-legal-link { + font-family: 'Inter', sans-serif; + font-size: 12px; + color: var(--cai-text-faint) !important; + text-decoration: none !important; + transition: color 0.15s ease; +} + +.cai-legal-link:hover { + color: var(--cai-text-muted) !important; +} + +.cai-legal-sep { + font-size: 10px; + color: var(--cai-text-faint); + opacity: 0.5; +} + +/* ===== PF v5 Social Provider Overrides ===== */ +/* Production may use keycloak.v2 (PF v5) classes */ +.pf-v5-c-login__main-footer { + padding: 0 32px 28px !important; + background: transparent !important; +} + +.pf-v5-c-login__main-footer-band { + background-color: var(--cai-bg-surface) !important; + border-top: 1px solid var(--cai-border-primary) !important; + padding: 16px 32px !important; + text-align: center !important; + border-radius: 0 0 12px 12px !important; +} + +.pf-v5-c-login__main-footer-band-item { + font-size: 14px !important; + color: var(--cai-text-muted) !important; +} + +/* PF v5 social buttons */ +.pf-v5-c-login__main-footer-links-item a, +.pf-v5-c-button.pf-m-secondary.pf-m-block { + 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; + font-weight: 500 !important; + padding: 12px 16px !important; + width: 100% !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + gap: 10px !important; + transition: border-color 0.2s ease, background-color 0.2s ease, + box-shadow 0.2s ease, transform 0.15s ease !important; +} + +.pf-v5-c-login__main-footer-links-item a:hover, +.pf-v5-c-button.pf-m-secondary.pf-m-block:hover { + border-color: var(--cai-accent) !important; + background-color: rgba(145, 164, 210, 0.06) !important; + box-shadow: 0 0 16px rgba(145, 164, 210, 0.12) !important; + color: var(--cai-text-heading) !important; + transform: translateY(-1px) !important; +} + +/* PF v5 social footer links list - stacked */ +.pf-v5-c-login__main-footer-links { + display: flex !important; + flex-direction: column !important; + gap: 10px !important; + list-style: none !important; + padding: 0 !important; +} + +.pf-v5-c-login__main-footer-links-item { + width: 100% !important; +} + +/* PF v5 main container and card */ +.pf-v5-c-login { + 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; +} + +.pf-v5-c-login::before { + background-image: none !important; +} + +.pf-v5-c-login__container { + max-width: 440px !important; +} + +.pf-v5-c-login__header { + text-align: center !important; + margin-bottom: 32px !important; +} + +.pf-v5-c-brand { + font-family: 'Space Grotesk', sans-serif !important; + font-size: 28px !important; + font-weight: 700 !important; + color: var(--cai-text-heading) !important; +} + +.pf-v5-c-login__main { + background-color: var(--cai-bg-card) !important; + border: 1px solid var(--cai-border-secondary) !important; + border-radius: 12px !important; + animation: cardGlow 6s ease-in-out infinite !important; + overflow: hidden !important; + position: relative !important; +} + +.pf-v5-c-login__main::before { + content: '' !important; + position: absolute !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: linear-gradient(90deg, transparent, var(--cai-brand-indigo), + var(--cai-brand-teal), var(--cai-accent-secondary), transparent) !important; + opacity: 0.5 !important; +} + +.pf-v5-c-login__main-header { + padding: 28px 32px 0 !important; + background: transparent !important; +} + +.pf-v5-c-login__main-header .pf-v5-c-title { + font-family: 'Space Grotesk', sans-serif !important; + font-size: 22px !important; + font-weight: 600 !important; + color: var(--cai-text-heading) !important; +} + +.pf-v5-c-login__main-body { + padding: 24px 32px !important; +} + +/* PF v5 form controls */ +.pf-v5-c-form-control { + 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; +} + +.pf-v5-c-form-control:focus-within { + 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; +} + +.pf-v5-c-form__label-text { + font-family: 'Inter', sans-serif !important; + font-size: 13px !important; + font-weight: 500 !important; + color: var(--cai-text-muted) !important; +} + +/* PF v5 primary button */ +.pf-v5-c-button.pf-m-primary { + 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; + box-shadow: 0 2px 12px rgba(109, 133, 198, 0.2) !important; +} + +.pf-v5-c-button.pf-m-primary:hover { + opacity: 0.95; + box-shadow: 0 4px 20px rgba(109, 133, 198, 0.35) !important; +} + +/* PF v5 links */ +.pf-v5-c-login a, +.pf-v5-c-login__main a, +.pf-v5-c-button.pf-m-link { + color: var(--cai-accent) !important; + text-decoration: none !important; +} + +.pf-v5-c-login a:hover, +.pf-v5-c-button.pf-m-link:hover { + color: var(--cai-accent-secondary) !important; +} + +/* PF v5 alerts */ +.pf-v5-c-alert.pf-m-inline { + 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; +} + +/* PF v5 input group (password) */ +.pf-v5-c-input-group { + background: transparent !important; + border-radius: 8px !important; + overflow: hidden !important; +} + +.pf-v5-c-button.pf-m-control { + background-color: var(--cai-bg-surface) !important; + color: var(--cai-text-muted) !important; + border: 1px solid var(--cai-border-secondary) !important; + border-left: 1px solid var(--cai-border-primary) !important; + border-radius: 0 8px 8px 0 !important; +} + +.pf-v5-c-button.pf-m-control:hover { + color: var(--cai-accent) !important; + background-color: rgba(145, 164, 210, 0.08) !important; +} diff --git a/keycloak/themes/certifai/login/resources/js/footer.js b/keycloak/themes/certifai/login/resources/js/footer.js new file mode 100644 index 0000000..e131ef4 --- /dev/null +++ b/keycloak/themes/certifai/login/resources/js/footer.js @@ -0,0 +1,44 @@ +/** + * CERTifAI Keycloak Theme - Footer Injection + * + * Injects legal footer links (Privacy Policy, Impressum) below the login card. + * Uses the APP_BASE_URL from the page's redirect_uri to construct absolute links, + * falling back to relative paths if unavailable. + */ +(function () { + "use strict"; + + document.addEventListener("DOMContentLoaded", function () { + // Derive the app base URL from the OAuth redirect_uri parameter + var appBase = ""; + try { + var params = new URLSearchParams(window.location.search); + var redirectUri = params.get("redirect_uri"); + if (redirectUri) { + var url = new URL(redirectUri); + appBase = url.origin; + } + } catch (_) { + // Ignore parse errors; links will be relative + } + + // Build the footer element + var footer = document.createElement("div"); + footer.className = "cai-legal-footer"; + footer.innerHTML = + '' + + "Privacy Policy" + + "" + + '|' + + '' + + "Impressum" + + ""; + + // Insert after the card or at the end of .login-pf-page / .pf-v5-c-login__container + var card = document.querySelector(".card-pf") || + document.querySelector(".pf-v5-c-login__main"); + if (card && card.parentNode) { + card.parentNode.insertBefore(footer, card.nextSibling); + } + }); +})(); diff --git a/keycloak/themes/certifai/login/theme.properties b/keycloak/themes/certifai/login/theme.properties index bb5f523..e52debd 100644 --- a/keycloak/themes/certifai/login/theme.properties +++ b/keycloak/themes/certifai/login/theme.properties @@ -1,3 +1,4 @@ parent=keycloak import=common/keycloak styles=css/login.css +scripts=js/footer.js