210 lines
6.5 KiB
CSS
210 lines
6.5 KiB
CSS
/**
|
||
* Glassmorphism / Liquid Glass theme tokens
|
||
*
|
||
* Isolated module: all glass-specific tokens and utilities live here.
|
||
* Changing upstream Keycloakify or shadcn files should not affect this file,
|
||
* and changes here are intentionally scoped to the login theme.
|
||
*/
|
||
|
||
:root {
|
||
/* Blur radius — keep between 10–20px for GPU/UX balance */
|
||
--glass-blur: 14px;
|
||
--glass-blur-heavy: 20px;
|
||
|
||
/*
|
||
* Light theme glass tokens.
|
||
* Higher opacity than typical Dribbble glass so the card is readable
|
||
* and clearly separated from the animated background.
|
||
*/
|
||
--glass-bg: hsla(0 0% 100% / 0.42);
|
||
--glass-bg-solid: hsla(0 0% 100% / 0.82);
|
||
--glass-bg-scrim: hsla(0 0% 100% / 0.62);
|
||
--glass-border: hsla(0 0% 100% / 0.58);
|
||
--glass-border-highlight: hsla(0 0% 100% / 0.85);
|
||
--glass-shadow: 0 14px 44px hsla(220 40% 16% / 0.18);
|
||
--glass-shadow-elevated: 0 24px 64px hsla(220 40% 12% / 0.24);
|
||
|
||
/* Ambient background blobs — saturated and fairly opaque so the glass has something to refract */
|
||
--glass-ambient-1: hsla(250 85% 62% / 0.55);
|
||
--glass-ambient-2: hsla(320 80% 58% / 0.5);
|
||
--glass-ambient-3: hsla(190 90% 52% / 0.48);
|
||
--glass-ambient-4: hsla(40 95% 58% / 0.42);
|
||
|
||
/* Text stability on busy backgrounds */
|
||
--glass-text-shadow: 0 1px 2px hsla(0 0% 0% / 0.1);
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
/* Dark glass needs to be noticeably darker/tinted or it disappears on a dark page */
|
||
--glass-bg: hsla(220 20% 14% / 0.62);
|
||
--glass-bg-solid: hsla(220 20% 10% / 0.9);
|
||
--glass-bg-scrim: hsla(220 20% 8% / 0.78);
|
||
--glass-border: hsla(0 0% 100% / 0.18);
|
||
--glass-border-highlight: hsla(0 0% 100% / 0.32);
|
||
--glass-shadow: 0 14px 44px hsla(0 0% 0% / 0.45);
|
||
--glass-shadow-elevated: 0 24px 64px hsla(0 0% 0% / 0.55);
|
||
|
||
/* Dark-mode blobs: still vivid but not overwhelming */
|
||
--glass-ambient-1: hsla(250 85% 58% / 0.4);
|
||
--glass-ambient-2: hsla(320 80% 55% / 0.36);
|
||
--glass-ambient-3: hsla(190 90% 50% / 0.36);
|
||
--glass-ambient-4: hsla(40 95% 55% / 0.3);
|
||
|
||
--glass-text-shadow: 0 1px 3px hsla(0 0% 0% / 0.4);
|
||
}
|
||
}
|
||
|
||
/* Reduced transparency: make glass almost opaque and drop the blur */
|
||
@media (prefers-reduced-transparency: reduce) {
|
||
:root {
|
||
--glass-bg: hsla(0 0% 100% / 0.95);
|
||
--glass-bg-solid: hsla(0 0% 100% / 0.99);
|
||
--glass-bg-scrim: hsla(0 0% 100% / 0.99);
|
||
--glass-border: hsla(0 0% 0% / 0.14);
|
||
--glass-border-highlight: hsla(0 0% 0% / 0.1);
|
||
--glass-blur: 2px;
|
||
--glass-blur-heavy: 2px;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
--glass-bg: hsla(220 20% 8% / 0.97);
|
||
--glass-bg-solid: hsla(220 20% 6% / 0.99);
|
||
--glass-bg-scrim: hsla(220 20% 6% / 0.99);
|
||
--glass-border: hsla(0 0% 100% / 0.14);
|
||
--glass-border-highlight: hsla(0 0% 100% / 0.1);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Base glass layer — use for cards, panels, overlays */
|
||
.glass {
|
||
/* Tinted fill plus a subtle top-left sheen to mimic physical glass */
|
||
background: linear-gradient(
|
||
145deg,
|
||
hsla(0 0% 100% / 0.22) 0%,
|
||
hsla(0 0% 100% / 0.06) 55%,
|
||
hsla(0 0% 100% / 0.14) 100%
|
||
),
|
||
var(--glass-bg);
|
||
backdrop-filter: blur(var(--glass-blur)) saturate(145%);
|
||
-webkit-backdrop-filter: blur(var(--glass-blur)) saturate(145%);
|
||
border: 1px solid var(--glass-border);
|
||
box-shadow:
|
||
inset 0 1px 0 0 var(--glass-border-highlight),
|
||
inset 0 0 0 1px hsla(0 0% 100% / 0.04),
|
||
var(--glass-shadow);
|
||
border-radius: 1rem;
|
||
}
|
||
|
||
/* More opaque glass — used behind dense text or form sections */
|
||
.glass-solid {
|
||
background: linear-gradient(
|
||
145deg,
|
||
hsla(0 0% 100% / 0.18) 0%,
|
||
hsla(0 0% 100% / 0.04) 55%,
|
||
hsla(0 0% 100% / 0.1) 100%
|
||
),
|
||
var(--glass-bg-solid);
|
||
backdrop-filter: blur(var(--glass-blur-heavy)) saturate(125%);
|
||
-webkit-backdrop-filter: blur(var(--glass-blur-heavy)) saturate(125%);
|
||
border: 1px solid var(--glass-border);
|
||
box-shadow:
|
||
inset 0 1px 0 0 var(--glass-border-highlight),
|
||
inset 0 0 0 1px hsla(0 0% 100% / 0.04),
|
||
var(--glass-shadow);
|
||
border-radius: 0.875rem;
|
||
}
|
||
|
||
/* Scrim gradient for text protection on glass surfaces */
|
||
.glass-scrim {
|
||
background: linear-gradient(
|
||
180deg,
|
||
var(--glass-bg-scrim) 0%,
|
||
color-mix(in oklab, var(--glass-bg-scrim) 85%, transparent) 100%
|
||
);
|
||
}
|
||
|
||
/* Fallback for browsers without backdrop-filter support */
|
||
@supports not (backdrop-filter: blur(12px)) {
|
||
.glass {
|
||
background: var(--glass-bg-solid);
|
||
backdrop-filter: none;
|
||
-webkit-backdrop-filter: none;
|
||
}
|
||
|
||
.glass-solid {
|
||
backdrop-filter: none;
|
||
-webkit-backdrop-filter: none;
|
||
}
|
||
}
|
||
|
||
/* Ambient background blobs — keep some definition so the glass can refract them */
|
||
.glass-ambient-blob {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
filter: blur(44px);
|
||
opacity: 0.85;
|
||
will-change: transform, opacity;
|
||
animation: glass-float 20s ease-in-out infinite alternate;
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.glass-ambient-blob {
|
||
animation: none;
|
||
opacity: 0.6;
|
||
}
|
||
}
|
||
|
||
@keyframes glass-float {
|
||
0% {
|
||
transform: translate3d(0, 0, 0) scale(1);
|
||
}
|
||
|
||
100% {
|
||
transform: translate3d(30px, -40px, 0) scale(1.15);
|
||
}
|
||
}
|
||
|
||
/* Extra mesh layer behind the card: sharper color bands for stronger refraction */
|
||
.glass-ambient-mesh {
|
||
position: absolute;
|
||
inset: 0;
|
||
opacity: 0.7;
|
||
background: radial-gradient(
|
||
circle at 20% 30%,
|
||
var(--glass-ambient-1) 0%,
|
||
transparent 45%
|
||
),
|
||
radial-gradient(circle at 80% 20%, var(--glass-ambient-2) 0%, transparent 40%),
|
||
radial-gradient(circle at 60% 80%, var(--glass-ambient-3) 0%, transparent 45%),
|
||
radial-gradient(circle at 30% 75%, var(--glass-ambient-4) 0%, transparent 40%);
|
||
filter: blur(28px);
|
||
will-change: transform;
|
||
animation: glass-mesh-drift 30s ease-in-out infinite alternate;
|
||
pointer-events: none;
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.glass-ambient-mesh {
|
||
animation: none;
|
||
opacity: 0.5;
|
||
}
|
||
}
|
||
|
||
@keyframes glass-mesh-drift {
|
||
0% {
|
||
transform: scale(1) translate3d(0, 0, 0);
|
||
}
|
||
|
||
100% {
|
||
transform: scale(1.08) translate3d(-20px, 10px, 0);
|
||
}
|
||
}
|
||
|
||
/* Text stability helper */
|
||
.glass-text-stable {
|
||
text-shadow: var(--glass-text-shadow);
|
||
}
|