diff --git a/server.ts b/server.ts
index 6bfa6e3..7d01e5b 100644
--- a/server.ts
+++ b/server.ts
@@ -129,10 +129,19 @@ function buildConfigScript(config: StationConfig): string {
return ``;
}
+/** Build a gradient CSS value from three color stops. */
+function gradient(from: string, mid: string, to: string): string {
+ return `linear-gradient(135deg, ${from} 0%, ${mid} 40%, ${to} 100%)`;
+}
+
/**
* Build inline CSS custom properties on `:root` so the first paint carries
* the correct color scheme — eliminates the color flash that occurs when
* ThemeService.apply() runs asynchronously after the API call.
+ *
+ * Includes both flat color properties AND derived gradient variables
+ * (--sky-gradient, --sunset-gradient, --mixed-gradient) so components
+ * using var() for backgrounds render correctly on the very first paint.
*/
function buildThemeStyle(config: StationConfig): string {
const props: string[] = [];
@@ -144,6 +153,15 @@ function buildThemeStyle(config: StationConfig): string {
}
}
+ // Derived gradients — mirror the same formulas ThemeService.apply() uses.
+ // These must be injected server-side; otherwise components referencing
+ // var(--sky-gradient) etc. fall back to their SCSS build-time defaults
+ // on first paint, causing a visible color flash.
+ const cp = (field: keyof StationConfig): string => (config as any)[field] || '';
+ props.push(`--sky-gradient: ${gradient(cp('color_primary_dark'), cp('color_primary'), cp('color_primary_light'))}`);
+ props.push(`--sunset-gradient: ${gradient(cp('color_accent_dark'), cp('color_accent'), cp('color_accent_light'))}`);
+ props.push(`--mixed-gradient: linear-gradient(135deg, ${cp('color_primary_dark')} 0%, ${cp('color_primary')} 50%, ${cp('color_accent')} 100%)`);
+
if (props.length === 0) return '';
const css = `:root{${props.join(';')}}`;
diff --git a/src/app/about/about.component.scss b/src/app/about/about.component.scss
index 2e38f57..bcb91b2 100644
--- a/src/app/about/about.component.scss
+++ b/src/app/about/about.component.scss
@@ -213,7 +213,7 @@
.about-cta {
text-align: center;
padding: $spacing-2xl $spacing-lg;
- background: $mixed-gradient;
+ background: var(--mixed-gradient);
border-radius: $radius-xl;
color: var(--color-white);
diff --git a/src/app/events/events.component.scss b/src/app/events/events.component.scss
index 7e0a16f..5fa4529 100644
--- a/src/app/events/events.component.scss
+++ b/src/app/events/events.component.scss
@@ -34,7 +34,7 @@
.event-date {
flex-shrink: 0;
- background: $mixed-gradient;
+ background: var(--mixed-gradient);
color: var(--color-white);
display: flex;
flex-direction: column;
diff --git a/src/app/login/login.component.scss b/src/app/login/login.component.scss
index b74bb98..dea9a2f 100644
--- a/src/app/login/login.component.scss
+++ b/src/app/login/login.component.scss
@@ -4,7 +4,7 @@
.login-section {
@include flex-center;
min-height: calc(100vh - 80px);
- background: $sky-gradient;
+ background: var(--sky-gradient);
padding: $spacing-xl;
}
@@ -21,13 +21,13 @@
h1 {
font-family: $font-heading;
- color: $primary-blue;
+ color: var(--color-primary);
margin: $spacing-sm 0 $spacing-xs;
font-size: 1.75rem;
}
p {
- color: $neutral-medium;
+ color: var(--color-medium);
font-size: 0.9rem;
}
}
@@ -49,14 +49,14 @@
display: block;
font-size: 0.875rem;
font-weight: 600;
- color: $neutral-dark;
+ color: var(--color-dark);
margin-bottom: $spacing-xs;
}
input {
width: 100%;
padding: $spacing-sm $spacing-md;
- border: 1px solid $neutral-light;
+ border: 1px solid var(--color-light);
border-radius: $radius-md;
font-size: 1rem;
transition: border-color $transition-fast;
@@ -64,7 +64,7 @@
&:focus {
outline: none;
- border-color: $primary-blue;
+ border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba($primary-blue, 0.15);
}
}
@@ -72,7 +72,7 @@
.login-error {
background: rgba($danger-red, 0.1);
- color: $danger-red;
+ color: var(--color-danger);
padding: $spacing-sm $spacing-md;
border-radius: $radius-md;
font-size: 0.875rem;
@@ -81,7 +81,7 @@
}
.btn-login {
- @include button-style($primary-blue, $neutral-white, $primary-blue-light);
+ @include button-style(var(--color-primary), var(--color-white), var(--color-primary-light));
width: 100%;
padding: $spacing-sm $spacing-lg;
margin-top: $spacing-sm;
diff --git a/src/styles/_themes.scss b/src/styles/_themes.scss
index e16b59c..c5cc93b 100644
--- a/src/styles/_themes.scss
+++ b/src/styles/_themes.scss
@@ -3,33 +3,15 @@
// ========== CSS Custom Properties (exposed to the browser) ==========
// These map SCSS variables to CSS custom properties so Angular components
// can consume them via var() at runtime.
+//
+// COLOR variables (color_*, gradient_*) are NOT set here anymore.
+// They are injected at runtime by the SSR server as an inline