diff --git a/apps/web/src/lib/components/recal/left/elements/EventCard.svelte b/apps/web/src/lib/components/recal/left/elements/EventCard.svelte
index e50775e7..dd0a5c4f 100644
--- a/apps/web/src/lib/components/recal/left/elements/EventCard.svelte
+++ b/apps/web/src/lib/components/recal/left/elements/EventCard.svelte
@@ -49,7 +49,7 @@
{customEvent.title}
diff --git a/apps/web/src/lib/components/recal/modals/AdvancedSearch.svelte b/apps/web/src/lib/components/recal/modals/AdvancedSearch.svelte
index b8f1f765..de5f2973 100644
--- a/apps/web/src/lib/components/recal/modals/AdvancedSearch.svelte
+++ b/apps/web/src/lib/components/recal/modals/AdvancedSearch.svelte
@@ -248,17 +248,21 @@
diff --git a/apps/web/src/lib/scripts/ReCal+/palettes.ts b/apps/web/src/lib/scripts/ReCal+/palettes.ts
index c912eb2c..6f83cae7 100644
--- a/apps/web/src/lib/scripts/ReCal+/palettes.ts
+++ b/apps/web/src/lib/scripts/ReCal+/palettes.ts
@@ -1,183 +1,253 @@
// Credits: https://coolors.co/palettes/popular/7%20colors
import type { CalColors } from "$lib/stores/styles";
-// Title -> CalColors
-export const colorPalettes: Record = {
+export type Palette = {
+ colors: CalColors;
+ bgLight: string; // hex color for light mode background
+ bgDark: string; // hex color for dark mode background
+};
+
+// Title -> Palette
+export const colorPalettes: Record = {
Bright: {
- "-1": "#a8a8a8",
- "0": "#9ee09e",
- "1": "#feb44d",
- "2": "#9fc2d0",
- "3": "#fcfc7d",
- "4": "#ff6461",
- "5": "#ff99cc",
- "6": "#cc99c8",
- "E": "#e0e8f0"
+ colors: {
+ "-1": "#a8a8a8",
+ "0": "#9ee09e",
+ "1": "#feb44d",
+ "2": "#9fc2d0",
+ "3": "#fcfc7d",
+ "4": "#ff6461",
+ "5": "#ff99cc",
+ "6": "#cc99c8",
+ "E": "#e0e8f0"
+ },
+ bgLight: "#ffffff",
+ bgDark: "#18181b"
},
// From the original ReCal
Legacy: {
- "-1": "#e6e6e6",
- "0": "#D0DECF",
- "1": "#d5dcec",
- "2": "#ebd2db",
- "3": "#faf4cb",
- "4": "#e7dcce",
- "5": "#d1e7e4",
- "6": "#dcd5e2",
- "E": "#e6e8f0"
+ colors: {
+ "-1": "#e6e6e6",
+ "0": "#D0DECF",
+ "1": "#d5dcec",
+ "2": "#ebd2db",
+ "3": "#faf4cb",
+ "4": "#e7dcce",
+ "5": "#d1e7e4",
+ "6": "#dcd5e2",
+ "E": "#e6e8f0"
+ },
+ bgLight: "#fafaf8",
+ bgDark: "#18181b"
},
Coastal: {
- "-1": "#e6e6e6",
- "0": "#b8e0d2",
- "1": "#d6eadf",
- "2": "#eac4d5",
- "3": "#f9e2ae",
- "4": "#95d5b2",
- "5": "#a2d2ff",
- "6": "#cdb4db",
- "E": "#f0f9f4"
+ colors: {
+ "-1": "#e6e6e6",
+ "0": "#b8e0d2",
+ "1": "#d6eadf",
+ "2": "#eac4d5",
+ "3": "#f9e2ae",
+ "4": "#95d5b2",
+ "5": "#a2d2ff",
+ "6": "#cdb4db",
+ "E": "#f0f9f4"
+ },
+ bgLight: "#f8fcfa",
+ bgDark: "#18181b"
},
Sunset: {
- "-1": "#e6e6e6",
- "0": "#ffecd2",
- "1": "#ffd6a5",
- "2": "#fdcfe8",
- "3": "#fff5ba",
- "4": "#c8f7dc",
- "5": "#d4e4f7",
- "6": "#e8d4f7",
- "E": "#fff8f0"
+ colors: {
+ "-1": "#e6e6e6",
+ "0": "#ffecd2",
+ "1": "#ffd6a5",
+ "2": "#fdcfe8",
+ "3": "#fff5ba",
+ "4": "#c8f7dc",
+ "5": "#d4e4f7",
+ "6": "#e8d4f7",
+ "E": "#fff8f0"
+ },
+ bgLight: "#fffcf8",
+ bgDark: "#18181b"
},
Crayon: {
- "-1": "#e6e6e6",
- "0": "#ffadad",
- "1": "#ffd6a5",
- "2": "#fdffb6",
- "3": "#caffbf",
- "4": "#9bf6ff",
- "5": "#a0c4ff",
- "6": "#bdb2ff",
- "E": "#fff0f0"
+ colors: {
+ "-1": "#e6e6e6",
+ "0": "#ffadad",
+ "1": "#ffd6a5",
+ "2": "#fdffb6",
+ "3": "#caffbf",
+ "4": "#9bf6ff",
+ "5": "#a0c4ff",
+ "6": "#bdb2ff",
+ "E": "#fff0f0"
+ },
+ bgLight: "#fffefa",
+ bgDark: "#18181b"
},
Minty: {
- "-1": "#e6e6e6",
- "0": "#84ffc9",
- "1": "#8af2d2",
- "2": "#91e5db",
- "3": "#97d9e4",
- "4": "#9dcced",
- "5": "#a4bff6",
- "6": "#aab2ff",
- "E": "#e6fff0"
+ colors: {
+ "-1": "#e6e6e6",
+ "0": "#84ffc9",
+ "1": "#8af2d2",
+ "2": "#91e5db",
+ "3": "#97d9e4",
+ "4": "#9dcced",
+ "5": "#a4bff6",
+ "6": "#aab2ff",
+ "E": "#e6fff0"
+ },
+ bgLight: "#f2fcf9",
+ bgDark: "#152224"
},
Sweet: {
- "-1": "#e6e6e6",
- "0": "#f5cbd9",
- "1": "#eeccde",
- "2": "#e7cce4",
- "3": "#e0cde9",
- "4": "#d8ceee",
- "5": "#d1cef4",
- "6": "#cacff9",
- "E": "#fdf0ff"
+ colors: {
+ "-1": "#e6e6e6",
+ "0": "#f5cbd9",
+ "1": "#eeccde",
+ "2": "#e7cce4",
+ "3": "#e0cde9",
+ "4": "#d8ceee",
+ "5": "#d1cef4",
+ "6": "#cacff9",
+ "E": "#fdf0ff"
+ },
+ bgLight: "#fbf7fd",
+ bgDark: "#231e29"
},
Pearl: {
- "-1": "#e6e6e6",
- "0": "#e9b7ce",
- "1": "#e5c1d4",
- "2": "#e2cbda",
- "3": "#ded5e0",
- "4": "#dadfe5",
- "5": "#d7e9eb",
- "6": "#d3f3f1",
- "E": "#fff5f0"
+ colors: {
+ "-1": "#e6e6e6",
+ "0": "#e9b7ce",
+ "1": "#e5c1d4",
+ "2": "#e2cbda",
+ "3": "#ded5e0",
+ "4": "#dadfe5",
+ "5": "#d7e9eb",
+ "6": "#d3f3f1",
+ "E": "#fff5f0"
+ },
+ bgLight: "#fffaf8",
+ bgDark: "#18181b"
},
- Forest: {
- "-1": "#A8A8A8",
- "0": "#A8B1A9",
- "1": "#B1BAA9",
- "2": "#C0BDA8",
- "3": "#909D88",
- "4": "#A7AFAC",
- "5": "#E4DED3",
- "6": "#D3D0C8",
- "E": "#f0f5e6"
+ Book: {
+ colors: {
+ "-1": "#c4b8a8",
+ "0": "#d4c4a8",
+ "1": "#c9b896",
+ "2": "#e8dcc8",
+ "3": "#d9cdb5",
+ "4": "#c4b090",
+ "5": "#bfad8f",
+ "6": "#d0c4ac",
+ "E": "#e5dbc8"
+ },
+ bgLight: "#f5f0e6",
+ bgDark: "#2a2520"
},
Slate: {
- "-1": "#A8A8A8",
- "0": "#b9c6cb",
- "1": "#a7b7bd",
- "2": "#eef2f3",
- "3": "#dce3e6",
- "4": "#cad4d8",
- "5": "#95a8b0",
- "6": "#8399a2",
- "E": "#f0f5f7"
+ colors: {
+ "-1": "#A8A8A8",
+ "0": "#b9c6cb",
+ "1": "#a7b7bd",
+ "2": "#eef2f3",
+ "3": "#dce3e6",
+ "4": "#cad4d8",
+ "5": "#95a8b0",
+ "6": "#8399a2",
+ "E": "#f0f5f7"
+ },
+ bgLight: "#f1f5f8",
+ bgDark: "#1b2126"
},
Aurora: {
- "-1": "#A8A8A8",
- "0": "#1a5c5c",
- "1": "#6b4a0a",
- "2": "#6b1a4a",
- "3": "#1a5c2e",
- "4": "#6b3a1a",
- "5": "#1a3a6b",
- "6": "#4a1a6b",
- "E": "#1a2a3a"
+ colors: {
+ "-1": "#A8A8A8",
+ "0": "#1a5c5c",
+ "1": "#6b4a0a",
+ "2": "#6b1a4a",
+ "3": "#1a5c2e",
+ "4": "#6b3a1a",
+ "5": "#1a3a6b",
+ "6": "#4a1a6b",
+ "E": "#1a2a3a"
+ },
+ bgLight: "#ffffff",
+ bgDark: "#0f1419"
},
Crimson: {
- "-1": "#A8A8A8",
- "0": "#4a0d1c",
- "1": "#5c1024",
- "2": "#6e132c",
- "3": "#801634",
- "4": "#92193c",
- "5": "#a41c44",
- "6": "#b61f4c",
- "E": "#2e0812"
+ colors: {
+ "-1": "#A8A8A8",
+ "0": "#4a0d1c",
+ "1": "#5c1024",
+ "2": "#6e132c",
+ "3": "#801634",
+ "4": "#92193c",
+ "5": "#a41c44",
+ "6": "#b61f4c",
+ "E": "#2e0812"
+ },
+ bgLight: "#ffffff",
+ bgDark: "#1a0a0f"
},
Pixel: {
- "-1": "#A8A8A8",
- "0": "#8a004d",
- "1": "#005c99",
- "2": "#007040",
- "3": "#99005c",
- "4": "#00668a",
- "5": "#008050",
- "6": "#a3005c",
- "E": "#1a1a2e"
+ colors: {
+ "-1": "#A8A8A8",
+ "0": "#8a004d",
+ "1": "#005c99",
+ "2": "#007040",
+ "3": "#99005c",
+ "4": "#00668a",
+ "5": "#008050",
+ "6": "#a3005c",
+ "E": "#1a1a2e"
+ },
+ bgLight: "#ffffff",
+ bgDark: "#0d0d1a"
},
Midnight: {
- "-1": "#A8A8A8",
- "0": "#1a5568",
- "1": "#1a4a5a",
- "2": "#255060",
- "3": "#2a4578",
- "4": "#3a3a72",
- "5": "#453580",
- "6": "#503570",
- "E": "#1a3246"
+ colors: {
+ "-1": "#A8A8A8",
+ "0": "#1a5568",
+ "1": "#1a4a5a",
+ "2": "#255060",
+ "3": "#2a4578",
+ "4": "#3a3a72",
+ "5": "#453580",
+ "6": "#503570",
+ "E": "#1a3246"
+ },
+ bgLight: "#ffffff",
+ bgDark: "#0a1520"
},
Cobalt: {
- "-1": "#A8A8A8",
- "0": "#3f004d",
- "1": "#350455",
- "2": "#2a085c",
- "3": "#200c64",
- "4": "#15106b",
- "5": "#0b1473",
- "6": "#00187a",
- "E": "#2a0033"
+ colors: {
+ "-1": "#A8A8A8",
+ "0": "#3f004d",
+ "1": "#350455",
+ "2": "#2a085c",
+ "3": "#200c64",
+ "4": "#15106b",
+ "5": "#0b1473",
+ "6": "#00187a",
+ "E": "#2a0033"
+ },
+ bgLight: "#ffffff",
+ bgDark: "#0d0515"
},
Shadow: {
- "-1": "#A8A8A8",
- "0": "#2a454b",
- "1": "#253e45",
- "2": "#21373f",
- "3": "#1c3139",
- "4": "#172a32",
- "5": "#13232c",
- "6": "#0e1c26",
- "E": "#1c2f34"
+ colors: {
+ "-1": "#A8A8A8",
+ "0": "#2a454b",
+ "1": "#253e45",
+ "2": "#21373f",
+ "3": "#1c3139",
+ "4": "#172a32",
+ "5": "#13232c",
+ "6": "#0e1c26",
+ "E": "#1c2f34"
+ },
+ bgLight: "#ffffff",
+ bgDark: "#0a1214"
}
};
diff --git a/apps/web/src/lib/scripts/convert.ts b/apps/web/src/lib/scripts/convert.ts
index 865c1a16..0b407fa4 100644
--- a/apps/web/src/lib/scripts/convert.ts
+++ b/apps/web/src/lib/scripts/convert.ts
@@ -325,6 +325,27 @@ const rgbToHSL = (hex: string) => {
return `hsl(${hVal}, ${sVal}%, ${lVal}%)`;
};
+/**
+ * Converts an HSL color to RGB components string (for CSS rgba usage)
+ * @param hsl
+ * @returns RGB components string like "255, 149, 0"
+ */
+const hslToRGBComponents = (hsl: string): string => {
+ // eslint-disable-next-line prefer-const
+ let [h, s, l] = hsl.split(",").map(x => parseInt(x.replace(/\D/g, "")));
+
+ l /= 100;
+ const a = (s * Math.min(l, 1 - l)) / 100;
+
+ const f = (n: number) => {
+ const k = (n + h / 30) % 12;
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
+ return Math.round(255 * color);
+ };
+
+ return `${f(0)}, ${f(8)}, ${f(4)}`;
+};
+
//----------------------------------------------------------------------
// TODO Refactor
@@ -339,5 +360,6 @@ export {
normalizeText,
darkenHSL,
hslToRGB,
+ hslToRGBComponents,
rgbToHSL
};
diff --git a/apps/web/src/lib/stores/styles.ts b/apps/web/src/lib/stores/styles.ts
index b8929a48..f6e20246 100644
--- a/apps/web/src/lib/stores/styles.ts
+++ b/apps/web/src/lib/stores/styles.ts
@@ -2,6 +2,305 @@ import { darkenHSL, rgbToHSL } from "$lib/scripts/convert";
import { colorPalettes } from "$lib/scripts/ReCal+/palettes";
import { get, writable } from "svelte/store";
+//----------------------------------------------------------------------
+// Background Colors
+//----------------------------------------------------------------------
+
+export type BgColors = {
+ light: string; // HSL string
+ dark: string; // HSL string
+};
+
+export const DEFAULT_BG_COLORS: BgColors = {
+ light: "hsl(0, 0%, 100%)", // white
+ dark: "hsl(240, 6%, 10%)" // zinc-900
+};
+
+const initializeBgColors = (): BgColors => {
+ if (typeof window === "undefined") return DEFAULT_BG_COLORS;
+
+ const stored = localStorage.getItem("bgColors");
+ if (!stored) {
+ localStorage.setItem("bgColors", JSON.stringify(DEFAULT_BG_COLORS));
+ return DEFAULT_BG_COLORS;
+ }
+
+ try {
+ const parsed = JSON.parse(stored);
+ if (parsed.light && parsed.dark) {
+ return parsed;
+ }
+ } catch {
+ // Invalid JSON, reset to defaults
+ }
+
+ localStorage.setItem("bgColors", JSON.stringify(DEFAULT_BG_COLORS));
+ return DEFAULT_BG_COLORS;
+};
+
+const {
+ subscribe: bgSubscribe,
+ update: bgUpdate,
+ set: bgSet
+} = writable(initializeBgColors());
+
+export const bgColors = {
+ subscribe: bgSubscribe,
+ update: bgUpdate,
+ set: (value: BgColors) => {
+ bgSet(value);
+ localStorage.setItem("bgColors", JSON.stringify(value));
+ }
+};
+
+//----------------------------------------------------------------------
+// Background Effects (Noise + Glows)
+//----------------------------------------------------------------------
+
+export type GradientShape = "circle" | "ellipse";
+
+export type GradientConfig = {
+ id: string;
+ color: string; // HSL string
+ x: number; // Position X (0-100%)
+ y: number; // Position Y (0-100%)
+ size: number; // Radius (10-100%)
+ opacity: number; // Individual opacity (0-1)
+ shape: GradientShape;
+ blur: number; // Fade amount (10-100%)
+};
+
+export type GlowsConfig = {
+ enabled: boolean;
+ gradients: GradientConfig[];
+ globalOpacity: number; // Master opacity (0-1)
+ darkModeIntensity: number; // Dark mode multiplier
+};
+
+export type BackgroundEffects = {
+ noise: {
+ enabled: boolean;
+ opacity: number; // 0-1
+ baseFrequency: number; // default 1.5
+ };
+ glows: GlowsConfig;
+};
+
+export const MAX_GRADIENTS = 10;
+
+export const generateGradientId = (): string => {
+ return `grad_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+};
+
+export const createGradient = (
+ overrides?: Partial
+): GradientConfig => {
+ return {
+ id: generateGradientId(),
+ color: "hsl(36, 100%, 50%)",
+ x: 50,
+ y: 50,
+ size: 30,
+ opacity: 1,
+ shape: "ellipse",
+ blur: 30,
+ ...overrides
+ };
+};
+
+export const DEFAULT_GRADIENTS: GradientConfig[] = [
+ {
+ id: "default_1",
+ color: "hsl(36, 100%, 50%)", // orange
+ x: 0,
+ y: 15,
+ size: 30,
+ opacity: 1,
+ shape: "ellipse",
+ blur: 30
+ },
+ {
+ id: "default_2",
+ color: "hsl(211, 100%, 50%)", // blue
+ x: 100,
+ y: 30,
+ size: 40,
+ opacity: 1,
+ shape: "ellipse",
+ blur: 40
+ }
+];
+
+export const DEFAULT_BG_EFFECTS: BackgroundEffects = {
+ noise: {
+ enabled: false,
+ opacity: 0.5,
+ baseFrequency: 1.5
+ },
+ glows: {
+ enabled: false,
+ gradients: [...DEFAULT_GRADIENTS],
+ globalOpacity: 0.15,
+ darkModeIntensity: 1.33
+ }
+};
+
+const initializeBgEffects = (): BackgroundEffects => {
+ if (typeof window === "undefined") return DEFAULT_BG_EFFECTS;
+
+ const stored = localStorage.getItem("bgEffects");
+ if (!stored) {
+ localStorage.setItem("bgEffects", JSON.stringify(DEFAULT_BG_EFFECTS));
+ return DEFAULT_BG_EFFECTS;
+ }
+
+ try {
+ const parsed = JSON.parse(stored);
+ // Validate structure
+ if (parsed.noise && parsed.glows) {
+ // Check if old format (has color1/color2 instead of gradients array)
+ if (!Array.isArray(parsed.glows.gradients) && parsed.glows.color1) {
+ // Migrate old format to new format
+ const migratedGradients: GradientConfig[] = [
+ {
+ id: "migrated_1",
+ color: parsed.glows.color1 ?? "hsl(36, 100%, 50%)",
+ x: 0,
+ y: 15,
+ size: 30,
+ opacity: 1,
+ shape: "ellipse",
+ blur: 30
+ },
+ {
+ id: "migrated_2",
+ color: parsed.glows.color2 ?? "hsl(211, 100%, 50%)",
+ x: 100,
+ y: 30,
+ size: 40,
+ opacity: 1,
+ shape: "ellipse",
+ blur: 40
+ }
+ ];
+
+ const migrated: BackgroundEffects = {
+ noise: {
+ enabled:
+ parsed.noise.enabled ??
+ DEFAULT_BG_EFFECTS.noise.enabled,
+ opacity:
+ parsed.noise.opacity ??
+ DEFAULT_BG_EFFECTS.noise.opacity,
+ baseFrequency:
+ parsed.noise.baseFrequency ??
+ DEFAULT_BG_EFFECTS.noise.baseFrequency
+ },
+ glows: {
+ enabled:
+ parsed.glows.enabled ??
+ DEFAULT_BG_EFFECTS.glows.enabled,
+ gradients: migratedGradients,
+ globalOpacity:
+ parsed.glows.opacity ??
+ DEFAULT_BG_EFFECTS.glows.globalOpacity,
+ darkModeIntensity:
+ DEFAULT_BG_EFFECTS.glows.darkModeIntensity
+ }
+ };
+ localStorage.setItem("bgEffects", JSON.stringify(migrated));
+ return migrated;
+ }
+
+ // New format - validate and return
+ return {
+ noise: {
+ enabled:
+ parsed.noise.enabled ??
+ DEFAULT_BG_EFFECTS.noise.enabled,
+ opacity:
+ parsed.noise.opacity ??
+ DEFAULT_BG_EFFECTS.noise.opacity,
+ baseFrequency:
+ parsed.noise.baseFrequency ??
+ DEFAULT_BG_EFFECTS.noise.baseFrequency
+ },
+ glows: {
+ enabled:
+ parsed.glows.enabled ??
+ DEFAULT_BG_EFFECTS.glows.enabled,
+ gradients:
+ parsed.glows.gradients ??
+ DEFAULT_BG_EFFECTS.glows.gradients,
+ globalOpacity:
+ parsed.glows.globalOpacity ??
+ DEFAULT_BG_EFFECTS.glows.globalOpacity,
+ darkModeIntensity:
+ parsed.glows.darkModeIntensity ??
+ DEFAULT_BG_EFFECTS.glows.darkModeIntensity
+ }
+ };
+ }
+ } catch {
+ // Invalid JSON, reset to defaults
+ }
+
+ localStorage.setItem("bgEffects", JSON.stringify(DEFAULT_BG_EFFECTS));
+ return DEFAULT_BG_EFFECTS;
+};
+
+const {
+ subscribe: effectsSubscribe,
+ update: effectsUpdate,
+ set: effectsSet
+} = writable(initializeBgEffects());
+
+export const bgEffects = {
+ subscribe: effectsSubscribe,
+ update: effectsUpdate,
+ set: (value: BackgroundEffects) => {
+ effectsSet(value);
+ localStorage.setItem("bgEffects", JSON.stringify(value));
+ }
+};
+
+//----------------------------------------------------------------------
+// Font
+//----------------------------------------------------------------------
+
+export type FontFamily =
+ | "Lato"
+ | "Roboto"
+ | "Playfair Display"
+ | "JetBrains Mono";
+
+export const FONT_OPTIONS: { name: FontFamily; fallback: string }[] = [
+ { name: "Lato", fallback: "sans-serif" },
+ { name: "Roboto", fallback: "sans-serif" },
+ { name: "Playfair Display", fallback: "serif" },
+ { name: "JetBrains Mono", fallback: "monospace" }
+];
+
+export const DEFAULT_FONT: FontFamily = "Lato";
+
+function createFontStore() {
+ const store = writable(
+ typeof window !== "undefined"
+ ? (localStorage.getItem("appFont") as FontFamily) || DEFAULT_FONT
+ : DEFAULT_FONT
+ );
+
+ return {
+ subscribe: store.subscribe,
+ set: (value: FontFamily) => {
+ store.set(value);
+ localStorage.setItem("appFont", value);
+ }
+ };
+}
+
+export const appFont = createFontStore();
+
//----------------------------------------------------------------------
// General
//----------------------------------------------------------------------
@@ -130,7 +429,7 @@ const initializeCalColors = (): CalColors => {
if (!("E" in parsedColors)) {
for (const key in colorPalettes) {
const palette = colorPalettes[key];
- const hslPalette = Object.entries(palette)
+ const hslPalette = Object.entries(palette.colors)
.map(([key, value]) => [key, rgbToHSL(value)])
.reduce(
(acc, [key, value]) => ({ ...acc, [key]: value }),
diff --git a/apps/web/src/routes/(apps)/+layout.svelte b/apps/web/src/routes/(apps)/+layout.svelte
index b1bb5124..e8dfc362 100644
--- a/apps/web/src/routes/(apps)/+layout.svelte
+++ b/apps/web/src/routes/(apps)/+layout.svelte
@@ -10,7 +10,16 @@
-
+
+
+
diff --git a/apps/web/src/routes/(apps)/recalplus/+page.svelte b/apps/web/src/routes/(apps)/recalplus/+page.svelte
index 2495c818..a49ef140 100644
--- a/apps/web/src/routes/(apps)/recalplus/+page.svelte
+++ b/apps/web/src/routes/(apps)/recalplus/+page.svelte
@@ -142,8 +142,7 @@
+ class="flex flex-col flex-1 w-full max-w-[1500px] mx-auto max-h-screen overflow-clip">
diff --git a/apps/web/src/routes/(apps)/reqtree/+page.svelte b/apps/web/src/routes/(apps)/reqtree/+page.svelte
index a8633831..661a1364 100644
--- a/apps/web/src/routes/(apps)/reqtree/+page.svelte
+++ b/apps/web/src/routes/(apps)/reqtree/+page.svelte
@@ -9,7 +9,7 @@
+ class="flex-1 w-full max-w-[1500px] mx-auto dark:text-white max-h-screen overflow-clip">
ReqTree
diff --git a/apps/web/src/routes/+layout.svelte b/apps/web/src/routes/+layout.svelte
index 90033539..f598a013 100644
--- a/apps/web/src/routes/+layout.svelte
+++ b/apps/web/src/routes/+layout.svelte
@@ -1,10 +1,44 @@
-
-