/* =============================================================================
* UltiSuite — habillage des flows Authentik (login / signup / recovery / MFA)
* -----------------------------------------------------------------------------
* Injection : ce fichier est monté sur /web/dist/custom.css dans le conteneur
* authentik-server (cf. deploy/docker-compose.yml). Authentik le sert avec
* l'attribut `data-inject` :
*
* Le bundle flow récupère le texte de chaque `link[data-inject]` et l'adopte
* (adoptedStyleSheets) dans le shadow root de CHAQUE composant Lit/PatternFly.
* => nos sélecteurs `.pf-c-*` atteignent l'intérieur des web components.
*
* Conséquences (shadow DOM) :
* - Les variables custom (`:root`) cascadent via héritage dans tous les roots.
* - Les sélecteurs descendants NE TRAVERSENT PAS les frontières de shadow root.
* Pour cibler le chrome porté par l'executor on utilise `:host([flowslug=…])`
* (l'hôte du shadow root de l'executor est ``).
* - Les éléments internes d'une étape (formulaire, champs, bouton) vivent dans
* le shadow root `` : on les style globalement (look partagé).
*
* Carte de la structure (flow login `default-authentication-flow`) :
* ak-flow-executor[flowslug] (shadow #1)
* .pf-c-background-image ← fond plein écran
* .pf-c-login.stacked > .ak-login-container
* .pf-c-login__main ← LA CARTE
* .pf-c-login__main-header.pf-c-brand.ak-brand > img ← logo
* ak-stage-identification (shadow #2)
* header.pf-c-login__main-header > h1.pf-c-title ← titre
* .pf-c-login__main-body > form.pf-c-form
* ak-form-element.pf-c-form__group (shadow #3 : label) + input.pf-c-form-control
* .pf-c-form__group.pf-m-action > button.pf-c-button.pf-m-primary
* footer.pf-c-login__main-footer
* .pf-c-login__main-footer-band > p > a#enroll ← "Créer un compte"
* .pf-c-login__footer ← "Powered by authentik" (masqué)
* ========================================================================== */
/* ---- Angle animé pour les anneaux arc-en-ciel (carte + bouton) ---------- */
@property --ulti-ring-angle {
syntax: "";
inherits: true;
initial-value: 145deg;
}
/* ---- Jetons de design (repris de .ultimail-login du frontend) ----------- */
:root {
--ulti-bg: #f7f8fc;
--ulti-line: rgba(21, 24, 30, 0.07);
--ulti-glow-a: #4f6df5;
--ulti-glow-b: #9a5cf0;
--ulti-glow-c: #1fb6c9;
--ulti-card-glass: rgba(255, 255, 255, 0.62);
--ulti-card-border: rgba(21, 24, 30, 0.1);
--ulti-card-highlight: rgba(255, 255, 255, 0.72);
--ulti-text: #3c4043;
--ulti-text-strong: #202124;
--ulti-text-muted: #5f6368;
--ulti-link: #1a73e8;
--ulti-input-bg: #ffffff;
--ulti-input-border: rgba(21, 24, 30, 0.16);
--ulti-rainbow: conic-gradient(
from var(--ulti-ring-angle),
#1a73e8,
#34a853,
#fbbc04,
#ea4335,
#1a73e8
);
/* Remplace l'accent corail Authentik (#fd4b2d) — utilisé pour les scrollbars. */
--ulti-scrollbar-thumb: color-mix(in srgb, var(--ulti-text-muted) 55%, transparent);
--ulti-scrollbar-thumb-hover: color-mix(in srgb, var(--ulti-text-muted) 75%, transparent);
--ak-accent: var(--ulti-scrollbar-thumb);
/* Boutons primaires — gris neutre */
--ulti-btn-primary-bg: #f4f4f5;
--ulti-btn-primary-fg: #18181b;
--ulti-btn-primary-bg-hover: #e4e4e7;
--ulti-btn-primary-border: color-mix(in srgb, var(--ulti-text-strong) 14%, transparent);
--ulti-btn-primary-border-width: 2px;
--ulti-btn-primary-border-hover: color-mix(in srgb, var(--ulti-text-muted) 42%, transparent);
--ulti-btn-primary-shadow: none;
--ulti-btn-primary-shadow-hover: none;
--ulti-btn-primary-ring: color-mix(in srgb, var(--ulti-text-muted) 35%, transparent);
--ulti-link-ui: var(--ulti-text-muted);
--ulti-link-ui-hover: var(--ulti-text);
--pf-global--link--Color: var(--ulti-link-ui);
--pf-global--link--Color--hover: var(--ulti-link-ui-hover);
--pf-global--link--Color--light: var(--ulti-link-ui);
--pf-global--link--Color--dark: var(--ulti-link-ui-hover);
--ulti-card-backdrop: blur(16px) saturate(1.2);
}
@media (prefers-color-scheme: dark) {
:root {
--ulti-bg: #0b0d12;
--ulti-line: rgba(238, 240, 246, 0.08);
--ulti-glow-a: #5d7bff;
--ulti-glow-b: #a86bff;
--ulti-glow-c: #2cc8dc;
--ulti-card-glass: rgba(30, 30, 33, 0.96);
--ulti-card-border: rgba(255, 255, 255, 0.1);
--ulti-card-highlight: rgba(255, 255, 255, 0.06);
--ulti-card-backdrop: blur(12px);
--ulti-text: #e8eaed;
--ulti-text-strong: #ffffff;
--ulti-text-muted: #bdc1c6;
--ulti-link: #8ab4f8;
--ulti-input-bg: rgba(0, 0, 0, 0.25);
--ulti-input-border: rgba(255, 255, 255, 0.14);
--ulti-scrollbar-thumb: color-mix(in srgb, var(--ulti-text-muted) 50%, transparent);
--ulti-scrollbar-thumb-hover: color-mix(in srgb, var(--ulti-text-muted) 70%, transparent);
--ak-accent: var(--ulti-scrollbar-thumb);
--ulti-btn-primary-bg: #18181b;
--ulti-btn-primary-fg: var(--ulti-text-strong);
--ulti-btn-primary-bg-hover: #242428;
--ulti-btn-primary-border-width: 1px;
--ulti-btn-primary-border: rgba(255, 255, 255, 0.32);
--ulti-btn-primary-border-hover: rgba(255, 255, 255, 0.44);
--ulti-btn-primary-shadow: none;
--ulti-btn-primary-shadow-hover: none;
--ulti-btn-primary-ring: color-mix(in srgb, var(--ulti-text-muted) 42%, transparent);
--ulti-link-ui: color-mix(in srgb, var(--ulti-text-muted) 92%, var(--ulti-text));
--ulti-link-ui-hover: var(--ulti-text-strong);
}
}
/* Scrollbars — Authentik défaut utilise var(--ak-accent) corail sur le thumb. */
html {
scrollbar-width: thin;
scrollbar-color: var(--ulti-scrollbar-thumb) transparent;
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: var(--ulti-scrollbar-thumb);
border-radius: 9999px;
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--ulti-scrollbar-thumb-hover);
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
background-color: transparent;
}
/* ===========================================================================
* 1. FOND — remplace la photo de route Authentik par l'aurore UltiSuite
* ======================================================================== */
html,
body {
background: var(--ulti-bg) !important;
overflow-x: hidden;
min-height: 100dvh;
}
/* PatternFly laisse .pf-c-background-image à hauteur 0 en mode stacked — on la fixe
* en plein écran pour que l'aurore / la grille soient visibles. */
.pf-c-background-image {
position: fixed;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
min-height: 100dvh;
overflow: hidden;
pointer-events: none;
background-color: var(--ulti-bg) !important;
background-image:
radial-gradient(
40rem 36rem at 18% 8%,
color-mix(in oklab, var(--ulti-glow-a) 60%, transparent),
transparent 58%
),
radial-gradient(
36rem 34rem at 84% 6%,
color-mix(in oklab, var(--ulti-glow-b) 55%, transparent),
transparent 60%
),
radial-gradient(
40rem 36rem at 50% 104%,
color-mix(in oklab, var(--ulti-glow-c) 55%, transparent),
transparent 60%
),
radial-gradient(
60% 50% at 50% 42%,
color-mix(in oklab, var(--ulti-glow-a) 14%, transparent),
transparent 70%
) !important;
background-repeat: no-repeat !important;
background-size: cover !important;
filter: none !important;
animation: ulti-aurora-drift 28s ease-in-out infinite alternate;
}
/* Orbe flottante A (cf. .ultimail-login-orb--a) */
.pf-c-background-image::before {
content: "";
position: absolute;
z-index: 0;
width: 40rem;
height: 40rem;
top: -16rem;
left: -12rem;
border-radius: 9999px;
pointer-events: none;
background: radial-gradient(
circle at 30% 30%,
color-mix(in oklab, var(--ulti-glow-a) 85%, transparent),
transparent 65%
);
filter: blur(90px);
opacity: 0.5;
will-change: transform;
animation: ulti-orb-drift-a 26s ease-in-out infinite alternate;
}
@media (prefers-color-scheme: dark) {
.pf-c-background-image::before {
opacity: 0.42;
}
}
@media (max-width: 639px) {
.pf-c-background-image::before {
width: 28rem;
height: 28rem;
top: -10rem;
left: -8rem;
filter: blur(70px);
}
.pf-c-background-image {
background-image:
radial-gradient(
120% 80% at 10% 0%,
color-mix(in oklab, var(--ulti-glow-a) 55%, transparent),
transparent 55%
),
radial-gradient(
100% 70% at 95% 8%,
color-mix(in oklab, var(--ulti-glow-b) 50%, transparent),
transparent 58%
),
radial-gradient(
120% 80% at 50% 100%,
color-mix(in oklab, var(--ulti-glow-c) 50%, transparent),
transparent 60%
),
radial-gradient(
90% 60% at 50% 45%,
color-mix(in oklab, var(--ulti-glow-a) 16%, transparent),
transparent 72%
) !important;
}
}
/* Les filtres SVG / images PatternFly du fond ne servent plus. */
.pf-c-background-image > * {
display: none !important;
}
/* Grille fine masquée par un dégradé radial (cf. .ultimail-login-backdrop). */
.pf-c-background-image::after {
content: "";
position: absolute;
z-index: 1;
inset: 0;
pointer-events: none;
background-image:
linear-gradient(to right, var(--ulti-line) 1px, transparent 1px),
linear-gradient(to bottom, var(--ulti-line) 1px, transparent 1px);
background-size: 56px 56px;
-webkit-mask-image: radial-gradient(
ellipse 80% 70% at 50% 42%,
black 28%,
transparent 80%
);
mask-image: radial-gradient(
ellipse 80% 70% at 50% 42%,
black 28%,
transparent 80%
);
}
/* ===========================================================================
* 2. MISE EN PAGE — carte centrée, chrome transparent devant le fond fixe
* ======================================================================== */
.pf-c-page__drawer,
.pf-c-drawer,
.pf-c-drawer__main,
.pf-c-drawer__content,
.pf-c-drawer__body {
position: relative;
z-index: 1;
background: transparent !important;
}
.pf-c-login.stacked {
box-sizing: border-box;
width: 100%;
min-height: 100dvh !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
padding: max(1rem, env(safe-area-inset-top)) 1rem max(1rem, env(safe-area-inset-bottom)) !important;
}
.pf-c-login.stacked .ak-login-container {
width: 100%;
max-width: min(26rem, 100%);
margin-inline: auto;
flex: 0 1 auto;
display: flex;
flex-direction: column;
justify-content: center;
}
.pf-c-login__main {
position: relative;
isolation: isolate;
box-sizing: border-box;
width: 100%;
max-width: 100%;
/* visible : le hover du bouton (translateY + ombre) ne doit pas être rogné */
overflow: visible;
padding: 1.5rem 2rem 1.25rem !important;
border-radius: 2.25rem !important;
background: var(--ulti-card-glass) !important;
border: 1px solid var(--ulti-card-border) !important;
box-shadow:
inset 0 1px 0 var(--ulti-card-highlight),
0 16px 44px -16px rgba(0, 0, 0, 0.28) !important;
-webkit-backdrop-filter: var(--ulti-card-backdrop, blur(16px) saturate(1.2));
backdrop-filter: var(--ulti-card-backdrop, blur(16px) saturate(1.2));
}
/* Anneau arc-en-ciel confiné au bord via masque (padding ring). */
.pf-c-login__main::before {
content: "";
position: absolute;
inset: 0;
z-index: 3;
border-radius: inherit;
padding: 2.5px;
background: var(--ulti-rainbow);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
mask-composite: exclude;
pointer-events: none;
animation: ulti-ring-spin 9s linear infinite;
}
/* Logo UltiSuite (header executor) — variante thème via content:url(). */
.pf-c-login__main-header.pf-c-brand,
.ak-brand {
padding-top: 0.25rem !important;
padding-bottom: 0.75rem !important;
margin-bottom: 0 !important;
}
.pf-c-login__main-header.pf-c-brand img,
.ak-brand img,
.pf-c-brand img {
max-height: 52px;
width: auto;
max-width: min(280px, 78vw);
content: url("/auth/static/dist/assets/branding/ultisuite-logo-light.png");
}
@media (prefers-color-scheme: dark) {
.pf-c-login__main-header.pf-c-brand img,
.ak-brand img,
.pf-c-brand img {
content: url("/auth/static/dist/assets/branding/ultisuite-logo-dark.png");
}
}
/* ===========================================================================
* 3. TITRE + DESCRIPTION DE L'ÉTAPE
* ======================================================================== */
.pf-c-login__main-body,
.pf-c-login__main-header {
background: transparent !important;
}
/* Titre d'étape (identification, mot de passe, etc.) — pas le bandeau logo */
.pf-c-login__main-header:not(.pf-c-brand):not(.ak-brand) {
padding: 0 0 1rem !important;
margin: 0 !important;
}
.pf-c-title {
text-align: center;
color: var(--ulti-text-strong) !important;
font-weight: 600 !important;
margin: 0 !important;
line-height: 1.35 !important;
}
.pf-c-title.pf-m-3xl {
font-size: 1.125rem !important;
}
/* Bandeau utilisateur (avatar + « Pas vous ? ») sur l'étape mot de passe */
.pf-c-login__main-body .pf-c-login__main-header,
.pf-c-form .pf-c-login__main-header {
padding: 0 0 1rem !important;
}
/* ===========================================================================
* 4. FORMULAIRE — labels, champs (.pf-c-form-control)
* ======================================================================== */
.pf-c-form {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
column-gap: 0.75rem;
row-gap: 0;
align-items: center;
}
.pf-c-form > ak-form-static,
.pf-c-form > input,
.pf-c-form > ak-flow-input-password,
.pf-c-form > ak-form-element,
.pf-c-form > .pf-c-form__group:not(.pf-m-action),
.pf-c-form > p {
grid-column: 1 / -1;
}
/* Mot de passe oublié + bouton : même ligne, lien à gauche / bouton à droite */
.pf-c-form > a:has(+ .pf-c-form__group.pf-m-action) {
grid-column: 1;
justify-self: start;
align-self: center;
margin: 0.175rem 0 0.25rem !important;
}
.pf-c-form > a + .pf-c-form__group.pf-m-action {
grid-column: 2;
justify-self: end;
align-self: center;
margin: 0.175rem 0 0.25rem !important;
}
/* Bouton seul (sans lien juste avant) */
.pf-c-form > .pf-c-form__group.pf-m-action {
grid-column: 2;
margin: 0.175rem 0 0.25rem !important;
}
.pf-c-form__group {
margin-bottom: 0.5rem !important;
}
/* Liens auxiliaires (mot de passe oublié, « Pas vous ? », inscription…) */
.pf-c-login__main a,
.pf-c-form a,
ak-form-static a {
color: var(--ulti-link-ui) !important;
font-size: 0.8125rem;
font-weight: 500;
text-decoration: underline;
text-underline-offset: 0.15em;
transition: color 0.18s ease;
}
.pf-c-login__main a:hover,
.pf-c-form a:hover,
ak-form-static a:hover {
color: var(--ulti-link-ui-hover) !important;
}
.pf-c-form__group.pf-m-action {
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
overflow: visible !important;
display: var(--ulti-action-group-display, block);
justify-content: var(--ulti-action-group-justify, normal);
}
.pf-c-login__main-body {
padding: 0 !important;
overflow: visible !important;
}
.pf-c-form__label-text {
color: var(--ulti-text-muted) !important;
font-size: 0.8rem;
font-weight: 500;
}
.pf-c-form__label-required {
color: var(--ulti-link) !important;
}
.pf-c-form-control {
height: 2.6rem;
padding: 0 0.85rem !important;
font-size: 0.9rem !important;
color: var(--ulti-text) !important;
background: var(--ulti-input-bg) !important;
border: 1px solid var(--ulti-input-border) !important;
border-radius: 0.6rem !important;
box-shadow: none !important;
transition:
border-color 0.18s ease,
box-shadow 0.18s ease;
}
.pf-c-form-control:hover {
border-color: color-mix(in srgb, var(--ulti-link) 45%, var(--ulti-input-border)) !important;
}
.pf-c-form-control:focus,
.pf-c-form-control:focus-visible {
border-color: var(--ulti-link) !important;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--ulti-link) 25%, transparent) !important;
outline: none !important;
}
/* ===========================================================================
* 4b. TEXTES D'AIDE / DESCRIPTION D'ÉTAPE
* -----------------------------------------------------------------------------
* Les étapes prompt/identification injectent des paragraphes bruts dans le
* corps (description de l'étape, suffixe de domaine "@ultisuite.fr", aide de
* champ). Sans règle ils héritent de la couleur PatternFly par défaut — peu
* lisible en sombre. On les aligne sur le texte atténué partagé.
* (Recovery : description "Enter the email…". Enrollment : "@ultisuite.fr".)
* ======================================================================== */
.pf-c-login__main-body > p,
.pf-c-form > p,
.pf-c-form__helper-text {
color: var(--ulti-text-muted) !important;
font-size: 0.85rem;
line-height: 1.45;
}
/* Suffixe de domaine d'enrollment : rapproché du champ e-mail qu'il complète. */
.pf-c-form > p {
margin-top: -0.35rem !important;
margin-bottom: 0.125rem !important;
}
/* ===========================================================================
* 4c. INSCRIPTION (ulti-enrollment) — e-mail suffixé, mots de passe
* ======================================================================== */
ak-flow-executor[flowslug="ulti-enrollment"] ak-form-element:has(input[name="password"]).pf-c-form__group,
ak-flow-executor[flowslug="ulti-enrollment"] ak-form-element:has(input[name="password"]) .pf-c-form__group {
margin-bottom: 0.175rem !important;
}
ak-flow-executor[flowslug="ulti-enrollment"] .ulti-password-strength {
grid-column: 1 / -1;
margin: 0.125rem 0 0.075rem !important;
}
ak-flow-executor[flowslug="ulti-enrollment"] ak-form-element:has(input[name="password_repeat"]).pf-c-form__group,
ak-flow-executor[flowslug="ulti-enrollment"] ak-form-element:has(input[name="password_repeat"]) .pf-c-form__group {
margin-bottom: 0.25rem !important;
}
ak-flow-executor[flowslug="ulti-enrollment"] .ulti-password-match {
grid-column: 1 / -1;
margin: 0.075rem 0 0.175rem !important;
}
ak-flow-executor[flowslug="ulti-enrollment"] .ulti-email-availability {
grid-column: 1 / -1;
margin: 0.075rem 0 0.175rem !important;
font-size: 0.75rem;
line-height: 1.4;
}
.ulti-email-availability.muted,
.ulti-email-availability.checking {
color: var(--ulti-text-muted) !important;
}
.ulti-email-availability.ok {
color: #10b981 !important;
}
.ulti-email-availability.bad {
color: #ef4444 !important;
}
.pf-c-button.pf-m-primary:disabled,
.pf-c-button.pf-m-primary[disabled] {
opacity: 0.55;
cursor: not-allowed;
}
.ulti-email-input-group {
display: flex;
align-items: stretch;
width: 100%;
}
.ulti-email-input-group input[name="username"] {
flex: 1 1 auto;
min-width: 0;
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
border-right: none !important;
}
.ulti-email-suffix {
display: flex;
align-items: center;
flex: 0 0 auto;
padding: 0 0.75rem;
border: 1px solid var(--ulti-input-border);
border-left: none;
border-radius: 0 0.375rem 0.375rem 0;
background: color-mix(in srgb, var(--ulti-input-bg) 90%, var(--ulti-text-muted));
color: var(--ulti-text-muted);
font-size: 0.9375rem;
white-space: nowrap;
user-select: none;
}
.ulti-password-wrap {
position: relative;
width: 100%;
}
.ulti-password-input {
width: 100%;
padding-right: 2.5rem !important;
}
.ulti-password-toggle {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 2.5rem;
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
border: none;
background: transparent;
color: var(--ulti-text-muted);
cursor: pointer;
border-radius: 0 0.375rem 0.375rem 0;
transition: color 0.15s ease;
}
.ulti-password-toggle:hover {
color: var(--ulti-text-strong);
}
.ulti-password-toggle:focus-visible {
outline: none;
box-shadow: 0 0 0 2px var(--ulti-btn-primary-ring);
}
.ulti-password-strength-bars {
display: flex;
gap: 0.25rem;
}
.ulti-password-strength-bars span {
flex: 1;
height: 0.25rem;
border-radius: 999px;
background: color-mix(in srgb, var(--ulti-text-muted) 22%, transparent);
transition: background-color 0.15s ease;
}
.ulti-password-strength-bars span.active.weak {
background: #ef4444;
}
.ulti-password-strength-bars span.active.fair {
background: #f59e0b;
}
.ulti-password-strength-bars span.active.good {
background: #10b981;
}
.ulti-password-strength-bars span.active.strong {
background: #059669;
}
.ulti-password-strength-label {
margin: 0.175rem 0 0 !important;
font-size: 0.75rem;
color: var(--ulti-text-muted) !important;
}
.ulti-password-strength-label strong {
color: var(--ulti-text-strong);
font-weight: 600;
}
.ulti-password-match {
font-size: 0.75rem;
}
.ulti-password-match.ok {
color: #10b981 !important;
}
.ulti-password-match.bad {
color: #ef4444 !important;
}
/* ===========================================================================
* 5. BOUTONS PRIMAIRES — gris neutre, bordure 2px
* ======================================================================== */
ak-flow-executor[flowslug="default-authentication-flow"],
ak-flow-executor[flowslug="ulti-enrollment"],
ak-flow-executor[flowslug="ulti-recovery"] {
--ulti-action-group-display: flex;
--ulti-action-group-justify: flex-end;
--ulti-primary-btn-width: auto;
--ulti-primary-btn-height: 2.625rem;
--ulti-primary-btn-min-height: 2.625rem;
--ulti-primary-btn-padding: 0 1rem;
--ulti-primary-btn-radius: 0.6rem;
--ulti-primary-btn-font-size: 0.9375rem;
--ulti-primary-btn-weight: 600;
}
.pf-c-button.pf-m-primary {
display: var(--ulti-primary-btn-display, inline-flex);
align-items: center;
justify-content: center;
box-sizing: border-box;
width: var(--ulti-primary-btn-width, auto);
height: var(--ulti-primary-btn-height, auto);
min-height: var(--ulti-primary-btn-min-height, 2.25rem);
margin: 0 !important;
padding: var(--ulti-primary-btn-padding, 0.4375rem 0.875rem) !important;
border: var(--ulti-btn-primary-border-width, 2px) solid var(--ulti-btn-primary-border, transparent) !important;
border-radius: var(--ulti-primary-btn-radius, 0.375rem) !important;
font-size: var(--ulti-primary-btn-font-size, 0.9375rem) !important;
font-weight: var(--ulti-primary-btn-weight, 600) !important;
line-height: 1 !important;
letter-spacing: normal;
color: var(--ulti-btn-primary-fg) !important;
text-shadow: none;
background-color: var(--ulti-btn-primary-bg) !important;
background-image: none !important;
box-shadow: var(--ulti-btn-primary-shadow, none) !important;
transition:
background-color 0.18s ease,
border-color 0.18s ease,
opacity 0.15s ease;
}
.pf-c-button.pf-m-primary:hover {
background-color: var(--ulti-btn-primary-bg-hover) !important;
border-color: var(--ulti-btn-primary-border-hover) !important;
}
.pf-c-button.pf-m-primary:active {
opacity: 0.94;
}
.pf-c-button.pf-m-primary:focus-visible {
outline: none !important;
border-color: var(--ulti-btn-primary-border-hover) !important;
box-shadow: 0 0 0 3px var(--ulti-btn-primary-ring) !important;
}
.pf-c-form__group.pf-m-action .pf-c-button.pf-m-primary {
width: var(--ulti-primary-btn-width, 100%) !important;
max-width: 100%;
}
/* Overlay de chargement Authentik (après « Continuer ») — aligné sur la carte. */
ak-loading-overlay {
position: absolute !important;
inset: 0 !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
margin: 0 !important;
border-radius: inherit !important;
background: color-mix(in srgb, var(--ulti-card-glass) 82%, transparent) !important;
-webkit-backdrop-filter: blur(6px) saturate(1.2);
backdrop-filter: blur(6px) saturate(1.2);
display: flex !important;
align-items: center !important;
justify-content: center !important;
z-index: 10;
}
ak-loading-overlay .pf-c-empty-state {
padding: 0 !important;
background: transparent !important;
}
ak-loading-overlay .pf-c-spinner {
--pf-c-spinner--Color: var(--ulti-link);
}
/* ===========================================================================
* 6. PIED DE CARTE — bande "Créer un compte" / liens auxiliaires
* ======================================================================== */
.pf-c-login__main-footer {
background: transparent !important;
}
.pf-c-login__main-footer-band {
margin-top: 0.5rem !important;
padding: 0.875rem 0 0.25rem !important;
background: transparent !important;
border: 0 !important;
text-align: center;
}
/* Liens auxiliaires (mot de passe oublié, inscription, etc.) */
.pf-c-login__main-footer-links {
margin: 0.15rem 0 0 !important;
padding: 0 !important;
list-style: none !important;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.15rem;
}
.pf-c-login__main-footer-links li {
margin: 0 !important;
padding: 0 !important;
}
.pf-c-login__main-footer-band-item {
color: var(--ulti-text-muted) !important;
font-size: 0.85rem;
}
/* ===========================================================================
* 7. MASQUAGE DU BRANDING AUTHENTIK
* ======================================================================== */
.pf-c-login__footer,
ak-branding-footer,
.pf-c-login__footer-text,
a[href*="goauthentik.io"],
a[href*="authentik.io"] {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
}
ak-flow-executor::part(footer) {
display: none !important;
}
/* ===========================================================================
* 8. MODE EMBARQUÉ — surfaces Authentik intégrées en iframe dans UltiSuite
* -----------------------------------------------------------------------------
* Deux familles de surfaces sont embarquées dans le panneau « réglages »
* d'UltiSuite (chrome Authentik masqué → seul le panneau utile reste visible) :
*
* A) La SPA user-settings : `/auth/if/user/#/settings;{"page":""}`
* Hôtes : → (shadow)
* → (shadow) → (shadow) .
* Pages deep-linkables via le hash (ex. `#/settings;{"page":"page-mfa"}`) :
* • MFA / authentificateurs : page-mfa →
* • Sessions actives : page-sessions →
* (autres : page-details, page-consents, page-sources, page-tokens)
*
* B) Les flows de configuration MFA, ouverts en plein écran depuis le menu
* « Enroll » de la page MFA (configure flow → ) :
* • default-authenticator-totp-setup
* • default-authenticator-webauthn-setup
* • default-authenticator-static-setup
* • default-password-change (bouton « Change password », page-details)
* • ulti-post-migration-security (blueprint 04 — sécuriser le compte)
*
* HYPOTHÈSE DE SCOPING (assumée, cf. brief) : la SPA user-settings n'est JAMAIS
* montrée en standalone aux utilisateurs finaux — uniquement embarquée dans
* UltiSuite. On dépouille donc son chrome INCONDITIONNELLEMENT, mais en scopant
* aux hôtes de l'INTERFACE UTILISATEUR (`ak-interface-user-presentation`,
* `ak-user-settings`, `ak-user-*-list/mfa`) afin de NE PAS toucher :
* - l'interface ADMIN (`if/admin`, hôtes `ak-interface-admin*`) ;
* - les FLOWS de login/signup/recovery (carte + branding conservés).
* Les flows de config MFA listés en B) ne sont atteints QUE depuis les réglages
* (le login garde son slug `default-authentication-flow`) → strip sûr.
*
* NOTE Firefox : la règle 8.3 (masquage de la nav d'onglets) repose sur
* `:host-context()`, non implémenté par Firefox. Cibles principales (Chrome,
* Edge, WebView Android, WKWebView/WebKitGTK de Tauri) OK ; sous Firefox la
* barre d'onglets verticale resterait visible (dégradation, pas de casse).
* ======================================================================== */
/* ---- 8.1 SPA : masquage du chrome global (header, fond, marges) --------- */
/* Hôte = (porte le shadow contenant header
* + fond + drawer). Scope strict : n'atteint pas l'admin ni les flows. */
:host(ak-interface-user-presentation) .pf-c-page__header,
:host(ak-interface-user-presentation) .background-wrapper {
display: none !important;
}
:host(ak-interface-user-presentation) .pf-c-page,
:host(ak-interface-user-presentation) .pf-c-page__drawer,
:host(ak-interface-user-presentation) .pf-c-drawer,
:host(ak-interface-user-presentation) .pf-c-drawer__main,
:host(ak-interface-user-presentation) .pf-c-drawer__content,
:host(ak-interface-user-presentation) .pf-c-drawer__body {
background: transparent !important;
}
:host(ak-interface-user-presentation) .pf-c-page__main {
margin: 0 !important;
padding: 0 !important;
}
/* ---- 8.2 SPA : page de réglages à plat (transparente, sans marges) ------ */
:host(ak-user-settings) .pf-c-page,
:host(ak-user-settings) .pf-c-page__main {
background: transparent !important;
padding: 0 !important;
margin: 0 !important;
}
:host(ak-user-settings) .pf-c-page__main-section {
padding: 0 !important;
background: transparent !important;
}
/* La carte qui enveloppe chaque panneau (MFA / sessions) devient le panneau
* UltiSuite lui-même : fond/ombre/bordure retirés pour fondre dans l'iframe. */
:host(ak-user-settings) .pf-c-card {
background: transparent !important;
box-shadow: none !important;
border: 0 !important;
border-radius: 0 !important;
}
:host(ak-user-settings) .pf-c-card__body {
padding: 0 !important;
}
/* ---- 8.3 SPA : masquage de la barre d'onglets verticale (cf. NOTE) ------ */
/* est générique (réutilisé par l'admin) : on le restreint au seul
* réglage utilisateur via :host-context(ak-user-settings). Le panneau actif
* (slot page-*) reste affiché ; seule la nav latérale disparaît. */
:host-context(ak-user-settings) .pf-c-tabs.pf-m-vertical {
display: none !important;
}
/* ---- 8.4 SPA : look UltiSuite des listes MFA & sessions ----------------- */
/* Scopé aux hôtes propres à l'interface utilisateur (jamais en admin/flows). */
:host(ak-user-settings-mfa) .pf-c-table,
:host(ak-user-session-list) .pf-c-table {
background: transparent !important;
color: var(--ulti-text) !important;
}
:host(ak-user-settings-mfa) .pf-c-table th,
:host(ak-user-settings-mfa) .pf-c-table td,
:host(ak-user-session-list) .pf-c-table th,
:host(ak-user-session-list) .pf-c-table td {
color: var(--ulti-text) !important;
border-color: var(--ulti-line) !important;
}
:host(ak-user-settings-mfa) .pf-c-table th,
:host(ak-user-session-list) .pf-c-table th {
color: var(--ulti-text-muted) !important;
}
:host(ak-user-settings-mfa) .pf-c-toolbar,
:host(ak-user-session-list) .pf-c-toolbar {
background: transparent !important;
padding-inline: 0 !important;
}
/* Boutons réglages / MFA */
:host(ak-user-settings-mfa) .pf-c-dropdown__toggle.pf-m-primary,
:host(ak-user-settings) .pf-c-button.pf-m-primary,
:host(ak-user-settings-mfa) .pf-c-button.pf-m-primary,
:host(ak-user-session-list) .pf-c-button.pf-m-primary {
border-radius: 0.375rem !important;
padding: 0.4375rem 0.875rem !important;
}
:host(ak-user-settings-mfa) .pf-c-dropdown__toggle.pf-m-primary {
border: 0 !important;
}
/* ---- 8.5 Flows de configuration MFA / sécurité : chrome dépouillé ------- */
/* Mêmes effets que l'ancien stub, appliqués aux VRAIS slugs embarqués. */
:host([flowslug="default-authenticator-totp-setup"]) .pf-c-background-image,
:host([flowslug="default-authenticator-totp-setup"]) .pf-c-login__footer,
:host([flowslug="default-authenticator-totp-setup"]) .pf-c-login__main-header.pf-c-brand,
:host([flowslug="default-authenticator-webauthn-setup"]) .pf-c-background-image,
:host([flowslug="default-authenticator-webauthn-setup"]) .pf-c-login__footer,
:host([flowslug="default-authenticator-webauthn-setup"]) .pf-c-login__main-header.pf-c-brand,
:host([flowslug="default-authenticator-static-setup"]) .pf-c-background-image,
:host([flowslug="default-authenticator-static-setup"]) .pf-c-login__footer,
:host([flowslug="default-authenticator-static-setup"]) .pf-c-login__main-header.pf-c-brand,
:host([flowslug="default-password-change"]) .pf-c-background-image,
:host([flowslug="default-password-change"]) .pf-c-login__footer,
:host([flowslug="default-password-change"]) .pf-c-login__main-header.pf-c-brand,
:host([flowslug="ulti-post-migration-security"]) .pf-c-background-image,
:host([flowslug="ulti-post-migration-security"]) .pf-c-login__footer,
:host([flowslug="ulti-post-migration-security"]) .pf-c-login__main-header.pf-c-brand {
display: none !important;
}
:host([flowslug="default-authenticator-totp-setup"]) .pf-c-login.stacked,
:host([flowslug="default-authenticator-webauthn-setup"]) .pf-c-login.stacked,
:host([flowslug="default-authenticator-static-setup"]) .pf-c-login.stacked,
:host([flowslug="default-password-change"]) .pf-c-login.stacked,
:host([flowslug="ulti-post-migration-security"]) .pf-c-login.stacked {
background: transparent !important;
}
:host([flowslug="default-authenticator-totp-setup"]) .pf-c-login.stacked .ak-login-container,
:host([flowslug="default-authenticator-webauthn-setup"]) .pf-c-login.stacked .ak-login-container,
:host([flowslug="default-authenticator-static-setup"]) .pf-c-login.stacked .ak-login-container,
:host([flowslug="default-password-change"]) .pf-c-login.stacked .ak-login-container,
:host([flowslug="ulti-post-migration-security"]) .pf-c-login.stacked .ak-login-container {
max-width: none !important;
margin: 0 !important;
}
:host([flowslug="default-authenticator-totp-setup"]) .pf-c-login__main,
:host([flowslug="default-authenticator-webauthn-setup"]) .pf-c-login__main,
:host([flowslug="default-authenticator-static-setup"]) .pf-c-login__main,
:host([flowslug="default-password-change"]) .pf-c-login__main,
:host([flowslug="ulti-post-migration-security"]) .pf-c-login__main {
max-width: none !important;
padding: 0 !important;
border: 0 !important;
border-radius: 0 !important;
background: transparent !important;
box-shadow: none !important;
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
:host([flowslug="default-authenticator-totp-setup"]) .pf-c-login__main::before,
:host([flowslug="default-authenticator-webauthn-setup"]) .pf-c-login__main::before,
:host([flowslug="default-authenticator-static-setup"]) .pf-c-login__main::before,
:host([flowslug="default-password-change"]) .pf-c-login__main::before,
:host([flowslug="ulti-post-migration-security"]) .pf-c-login__main::before {
display: none !important;
}
/* ===========================================================================
* 9. ANIMATIONS / ACCESSIBILITÉ
* ======================================================================== */
@keyframes ulti-ring-spin {
to {
--ulti-ring-angle: 505deg;
}
}
@keyframes ulti-aurora-drift {
from {
background-size: 100% 100%, 100% 100%, 100% 100%, 100% 100%;
}
to {
background-size: 112% 108%, 108% 112%, 110% 105%, 106% 104%;
}
}
@keyframes ulti-orb-drift-a {
from {
transform: translate3d(0, 0, 0) scale(1);
}
to {
transform: translate3d(6rem, 4rem, 0) scale(1.12);
}
}
/* Évite le rognage du bouton / ombre de carte par les conteneurs PatternFly */
.pf-c-login.stacked,
.pf-c-login.stacked .ak-login-container,
.pf-c-page__drawer .pf-c-drawer__body,
.pf-c-page__drawer .pf-c-drawer__content {
overflow: visible !important;
}
@media (max-width: 639px) {
.pf-c-login__main {
padding: 1.25rem 1.25rem 1rem !important;
border-radius: 1.75rem !important;
}
.pf-c-login__main-header.pf-c-brand img,
.ak-brand img,
.pf-c-brand img {
max-height: 44px;
max-width: min(240px, 72vw);
}
.pf-c-title.pf-m-3xl {
font-size: 1.05rem !important;
}
.pf-c-form-control {
height: 2.75rem;
font-size: 16px !important; /* évite le zoom iOS */
}
ak-flow-executor[flowslug="default-authentication-flow"],
ak-flow-executor[flowslug="ulti-enrollment"],
ak-flow-executor[flowslug="ulti-recovery"] {
--ulti-primary-btn-height: 2.625rem;
--ulti-primary-btn-min-height: 2.625rem;
}
}
@media (prefers-reduced-motion: reduce) {
.pf-c-background-image,
.pf-c-background-image::before {
animation: none !important;
}
.pf-c-login__main::before {
animation: none !important;
}
}