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