Style Keycloak PatternFly markup in login theme

Pages we don't override with a custom .ftl (change password, OTP,
verify email, required actions, etc.) render their inner form
with Keycloak's stock PatternFly/Bootstrap classes. The brutalist
card shell was styled but the fields inside were not.

Add resources/css/brutalist.css with targeted overrides on
.pf-c-form-control, .pf-c-button, .pf-c-input-group, .checkbox,
.form-group, alerts and headings, then link it from template.ftl
so every Keycloak auto-generated page inherits the E-Cosplay look
without touching each individual .ftl file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-04-10 16:10:55 +02:00
parent b6dde137b4
commit 1ed5c020b1
2 changed files with 278 additions and 0 deletions

View File

@@ -0,0 +1,277 @@
/* ============================================================
E-Cosplay brutalist overrides for default Keycloak markup
------------------------------------------------------------
The shell (card, header, marquee, footer) is rendered by our
template.ftl. Pages that we do NOT override (change password,
OTP, verify email, required actions, etc.) reuse Keycloak's
stock PatternFly/Bootstrap markup for their inner form. This
file restyles those classes so everything inside the card
matches the brutalist identity without having to override
every single .ftl file.
============================================================ */
/* Layout: kill Bootstrap grid side-padding that breaks our card */
.form-group {
margin-bottom: 1.5rem;
}
.form-group > div[class*="col-"] {
padding-left: 0 !important;
padding-right: 0 !important;
float: none !important;
width: 100% !important;
}
.form-horizontal {
margin: 0;
}
/* ---------- Labels ---------- */
.pf-c-form__label,
.pf-c-form__label-text,
label {
display: block;
font-weight: 900 !important;
text-transform: uppercase !important;
letter-spacing: 0.1em;
font-size: 11px;
color: #111827 !important;
margin-bottom: 0.5rem;
font-style: normal !important;
}
/* ---------- Inputs ---------- */
.pf-c-form-control,
input[type="text"],
input[type="email"],
input[type="password"],
input[type="tel"],
input[type="number"],
input[type="url"],
select,
textarea {
width: 100% !important;
padding: 14px 16px !important;
background: #ffffff !important;
color: #111827 !important;
border: 4px solid #111827 !important;
border-radius: 0 !important;
font-weight: 700 !important;
font-style: normal !important;
font-size: 16px !important;
line-height: 1.4 !important;
box-shadow: none !important;
outline: none !important;
transition: all 0.15s ease !important;
height: auto !important;
}
.pf-c-form-control:focus,
input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="tel"]:focus,
input[type="number"]:focus,
input[type="url"]:focus,
select:focus,
textarea:focus {
background: #fef9c3 !important;
box-shadow: 6px 6px 0 #4f46e5 !important;
outline: none !important;
}
.pf-c-form-control[aria-invalid="true"] {
border-color: #dc2626 !important;
background: #fee2e2 !important;
}
/* ---------- Input group (password reveal button etc.) ---------- */
.pf-c-input-group {
display: flex !important;
align-items: stretch !important;
gap: 0 !important;
width: 100%;
}
.pf-c-input-group > .pf-c-form-control,
.pf-c-input-group > input {
flex: 1 1 auto !important;
}
.pf-c-input-group > .pf-c-button.pf-m-control {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
min-width: 56px !important;
padding: 0 18px !important;
background: #111827 !important;
color: #ffffff !important;
border: 4px solid #111827 !important;
border-left: 0 !important;
border-radius: 0 !important;
font-weight: 900 !important;
cursor: pointer !important;
box-shadow: none !important;
transform: none !important;
letter-spacing: 0 !important;
font-style: normal !important;
text-transform: none !important;
}
.pf-c-input-group > .pf-c-button.pf-m-control:hover {
background: #4f46e5 !important;
}
/* ---------- Buttons (primary / default / cancel) ---------- */
.pf-c-button,
input[type="submit"],
button[type="submit"],
button[type="button"].btn,
a.btn {
display: inline-block;
padding: 16px 28px !important;
font-weight: 900 !important;
text-transform: uppercase !important;
letter-spacing: 0.12em !important;
font-style: italic !important;
font-size: 14px !important;
line-height: 1 !important;
border: 4px solid #111827 !important;
border-radius: 0 !important;
cursor: pointer !important;
transition: all 0.15s ease !important;
text-decoration: none !important;
}
.pf-c-button.pf-m-primary,
input.pf-m-primary,
input[type="submit"].pf-m-primary,
input[type="submit"].btn-primary,
button.btn-primary {
background: #4f46e5 !important;
color: #ffffff !important;
box-shadow: 8px 8px 0 rgba(0, 0, 0, 1) !important;
}
.pf-c-button.pf-m-primary:hover,
input[type="submit"].pf-m-primary:hover,
button.btn-primary:hover {
box-shadow: none !important;
transform: translate(4px, 4px) !important;
background: #4338ca !important;
}
.pf-c-button.btn-default,
.pf-c-button.btn-secondary,
button.btn-default,
button.btn-secondary,
input[type="submit"].btn-default {
background: #ffffff !important;
color: #111827 !important;
box-shadow: 8px 8px 0 rgba(0, 0, 0, 1) !important;
}
.pf-c-button.btn-default:hover,
button.btn-default:hover {
background: #facc15 !important;
box-shadow: none !important;
transform: translate(4px, 4px) !important;
}
/* Avoid the input-group eye button inheriting the primary style above */
.pf-c-input-group .pf-c-button.pf-m-control {
padding: 0 18px !important;
font-size: 14px !important;
letter-spacing: 0 !important;
text-transform: none !important;
font-style: normal !important;
}
/* ---------- Checkboxes ---------- */
.checkbox {
margin: 1rem 0 !important;
}
.checkbox label {
display: flex !important;
align-items: center !important;
gap: 12px !important;
cursor: pointer !important;
font-size: 11px !important;
margin: 0 !important;
}
input[type="checkbox"],
input[type="radio"] {
width: 20px !important;
height: 20px !important;
margin: 0 !important;
border: 4px solid #111827 !important;
accent-color: #4f46e5 !important;
cursor: pointer !important;
}
/* ---------- Button row ---------- */
#kc-form-buttons {
display: flex !important;
gap: 12px !important;
flex-wrap: wrap !important;
margin-top: 1.5rem !important;
}
#kc-form-buttons > .pf-c-button,
#kc-form-buttons > input[type="submit"],
#kc-form-buttons > button {
flex: 1 1 160px;
}
/* ---------- Alerts / messages ---------- */
.alert,
.pf-c-alert {
border: 4px solid #111827 !important;
border-radius: 0 !important;
box-shadow: 6px 6px 0 rgba(0, 0, 0, 1) !important;
padding: 14px 18px !important;
font-weight: 800 !important;
margin-bottom: 1.5rem !important;
}
.alert-success,
.pf-c-alert.pf-m-success {
background: #bbf7d0 !important;
}
.alert-warning,
.pf-c-alert.pf-m-warning {
background: #fde68a !important;
}
.alert-danger,
.alert-error,
.pf-c-alert.pf-m-danger {
background: #fecaca !important;
}
.alert-info,
.pf-c-alert.pf-m-info {
background: #c7d2fe !important;
}
/* ---------- Links ---------- */
a {
color: #4f46e5 !important;
text-decoration: underline !important;
text-decoration-thickness: 3px !important;
text-underline-offset: 4px !important;
font-weight: 800 !important;
}
a:hover {
color: #111827 !important;
}
/* ---------- Headings inside the card ---------- */
.pf-c-title,
#kc-page-title,
h1, h2, h3 {
font-weight: 900 !important;
text-transform: uppercase !important;
font-style: italic !important;
letter-spacing: -0.02em !important;
color: #111827 !important;
}

View File

@@ -7,6 +7,7 @@
<meta name="robots" content="noindex, nofollow">
<title>${msg("loginTitle",(realm.displayName!''))}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="${url.resourcesPath}/css/brutalist.css">
<style>
@keyframes marquee {
0% { transform: translateX(0); }