Keycloak theme for the sign-in and sign-out pages (PD-23, PD-26)

Realm petrolyst's login theme, on Keycloak's unstyled base: a slate panel with the logo and its line
beside the form on a soft card; on a phone a slate band above it; light and dark. Satoshi stays out
of Git by its licence (build.sh). The README adds the install steps. Not deployed.

Bands: none (identity theme).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nasim SadatandClaude Opus 5.5 committed 2026-10-31 01:29:57 +01:00
1 parent d95e6e184a
commit 89b1709fd9
16 files changed
+835

No files matched your search

@@ -0,0 +1,237 @@
/* Petrolyst's sign-in pages. Colours and type come from the brand tokens (css/brand/), light and dark; the form sits on a soft card
beside the dark slate shell, which is the same in both (PD-26), as on the website and in the app. */
@font-face {
font-family: "Inter";
src: url("../fonts/inter-latin-wght-normal.woff2") format("woff2");
font-weight: 100 900;
font-display: swap;
}
/* Fetched at build time and never committed: Satoshi's licence forbids distributing the files (build.sh). Without it, Inter takes over. */
@font-face {
font-family: "Satoshi";
src: url("../fonts/Satoshi-Variable.woff2") format("woff2");
font-weight: 300 900;
font-display: swap;
}
* { box-sizing: border-box; }
html { color-scheme: light; }
body {
margin: 0;
min-height: 100vh;
background: var(--surface-subtle);
color: var(--text-primary);
font-family: var(--font-ui);
font-size: var(--text-body);
line-height: 1.5;
}
.pl-page {
min-height: 100vh;
display: flex;
flex-direction: column;
width: 100%;
max-width: 448px;
margin: 0 auto;
padding: 0 var(--space-6, 24px) var(--space-8, 32px);
}
/* The logo; the realm's name is left out (messages: loginTitleHtml). On a phone a slate band, like the website's header; wide, the panel holds it. */
.pl-header {
display: flex;
align-items: center;
height: 64px;
margin: 0 calc(var(--space-6, 24px) * -1) var(--space-8, 32px);
padding: 0 var(--space-6, 24px);
background: var(--surface-chrome);
border-bottom: 1px solid var(--border-chrome);
}
#kc-header-wrapper {
width: 160px;
height: 22px;
background: url("../img/petrolyst_wordmark_white_y.svg") left center / contain no-repeat;
}
.pl-card {
padding: var(--space-6, 24px);
background: var(--surface-card);
border-radius: var(--radius-md);
box-shadow: var(--shadow-card);
}
#kc-page-title {
margin: 0 0 var(--space-6, 24px);
font-family: var(--font-display);
font-size: var(--text-h3);
font-weight: 400;
line-height: 1.2;
}
/* --- The form --- */
.pl-group { margin-bottom: var(--space-5, 20px); }
.pl-label,
#kc-content label {
display: block;
margin-bottom: var(--space-2, 8px);
font-size: var(--text-ui);
font-weight: 600;
}
.pl-input,
#kc-content input[type="text"],
#kc-content input[type="password"],
#kc-content input[type="email"] {
width: 100%;
min-height: 44px;
padding: 10px 14px;
border: 1px solid var(--border-control);
border-radius: var(--radius-sm);
background: var(--surface-card);
color: var(--text-primary);
font: inherit;
}
.pl-input:focus,
#kc-content input:focus-visible,
.pl-eye:focus-visible,
.pl-btn:focus-visible,
#kc-content a:focus-visible {
outline: 2px solid var(--action-primary);
outline-offset: 2px;
}
.pl-input[aria-invalid="true"] { border-color: var(--status-critical); }
.pl-input-group { position: relative; }
.pl-input-group .pl-input { padding-right: 48px; }
.pl-eye {
position: absolute;
top: 0;
right: 0;
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
border: 0;
border-radius: var(--radius-sm);
background: transparent;
color: var(--text-secondary);
cursor: pointer;
}
.pl-eye:hover { color: var(--text-primary); }
.pl-icon {
display: inline-block;
width: 18px;
height: 18px;
background: currentColor;
-webkit-mask: var(--pl-icon) center / contain no-repeat;
mask: var(--pl-icon) center / contain no-repeat;
}
.pl-icon-show { --pl-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); }
.pl-icon-hide { --pl-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.9 4.2A10 10 0 0 1 12 4c6.5 0 10 8 10 8a17 17 0 0 1-2.2 3.3M6.6 6.6A17 17 0 0 0 2 12s3.5 8 10 8a10 10 0 0 0 5.4-1.6M2 2l20 20M9.9 9.9a3 3 0 0 0 4.2 4.2'/%3E%3C/svg%3E"); }
.pl-icon-restart { --pl-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 12a9 9 0 1 0 3-6.7L3 8'/%3E%3Cpath d='M3 3v5h5'/%3E%3C/svg%3E"); }
.pl-settings { margin-bottom: 0; font-size: var(--text-ui); }
#kc-form-buttons { margin: var(--space-5, 20px) 0 0; }
.pl-settings a,
#kc-content a {
color: var(--action-primary);
font-weight: 600;
text-decoration: none;
}
#kc-content a:hover { text-decoration: underline; }
#kc-form-options .checkbox label { display: inline-flex; align-items: center; gap: var(--space-2, 8px); font-weight: 400; margin: 0; }
.pl-btn,
#kc-content input[type="submit"] {
min-height: 44px;
padding: 10px 24px;
border: 1px solid var(--border-control);
border-radius: var(--radius-pill);
background: transparent;
color: var(--text-primary);
font: inherit;
font-size: var(--text-ui);
font-weight: 600;
cursor: pointer;
}
.pl-btn-primary,
#kc-content input[type="submit"].pl-btn-primary {
border-color: var(--action-primary);
background: var(--action-primary);
color: var(--action-primary-foreground);
}
.pl-btn-primary:hover { background: var(--action-primary-hover); border-color: var(--action-primary-hover); }
.pl-btn-primary:active { background: var(--action-primary-active); border-color: var(--action-primary-active); }
.pl-btn-primary:disabled { opacity: 0.6; cursor: default; }
.pl-btn-block { width: 100%; }
/* --- Messages --- */
.pl-alert {
display: flex;
gap: var(--space-2, 8px);
margin-bottom: var(--space-5, 20px);
padding: 12px 14px;
border: 1px solid var(--border-default);
border-left-width: 3px;
border-radius: var(--radius-sm);
background: var(--surface-subtle);
font-size: var(--text-ui);
}
.pl-alert.alert-error { border-left-color: var(--status-critical); }
.pl-alert.alert-warning { border-left-color: var(--status-warning, var(--border-strong)); }
.pl-alert.alert-success { border-left-color: var(--action-primary); }
.pl-alert.alert-info { border-left-color: var(--action-primary); }
.pl-field-error {
display: block;
margin-top: var(--space-2, 8px);
color: var(--status-critical);
font-size: var(--text-ui);
}
.instruction,
#kc-content p { color: var(--text-secondary); margin: 0 0 var(--space-5, 20px); }
#kc-content p:last-child { margin-bottom: 0; }
#kc-content ol, #kc-content ul { color: var(--text-secondary); padding-left: 20px; }
#kc-content li { margin-bottom: var(--space-3, 12px); }
#kc-content ul ul { margin-top: var(--space-2, 8px); }
/* The user's name on later steps, with the way back to the start. */
#kc-username { display: flex; align-items: center; justify-content: space-between; margin: 0 0 var(--space-5, 20px); font-size: var(--text-ui); font-weight: 600; }
#kc-attempted-username { margin: 0; }
#reset-login { display: inline-flex; color: var(--text-secondary); }
.kc-tooltip-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
#kc-info { margin-top: var(--space-5, 20px); font-size: var(--text-ui); color: var(--text-secondary); }
.subtitle { font-size: var(--text-caption); color: var(--text-muted); }
.required { color: var(--status-critical); }
.clearfix { clear: both; }
/* --- Dark --- */
@media (prefers-color-scheme: dark) {
html { color-scheme: dark; }
}
/* --- Wide: the slate panel with the logo, the form on its card beside it. The logo appears once, so the form's own is hidden. --- */
@media (min-width: 64rem) {
body::before {
content: "";
position: fixed;
inset: 0 50% 0 0;
background:
url("../img/petrolyst_logo_white_y.svg") center / clamp(300px, 30vw, 480px) auto no-repeat,
radial-gradient(ellipse 34vw 40vw at 50% 50%, color-mix(in srgb, var(--petroleum-500) 45%, transparent) 0%, color-mix(in srgb, var(--petroleum-500) 20%, transparent) 45%, transparent 100%),
var(--surface-chrome);
}
.pl-page {
position: relative;
z-index: 1;
justify-content: center;
width: 50%;
max-width: none;
margin: 0 0 0 50%;
padding: var(--space-8, 32px) clamp(48px, 7vw, 128px);
}
.pl-header { display: none; }
.pl-card { padding: var(--space-8, 32px); }
}