import { alpha, createTheme, darken, lighten } from "@mui/material/styles"; type PaletteLike = Record; // Single global brand accent -- matches the dark sidebar/landing page indigo used throughout // the app. Not user-configurable; see jobbjakt-nextjs-migration memory / UI rework notes. const ACCENT = "#6366F1"; function buildPrimary(main: string) { return { lighter: lighten(main, 0.82), light: lighten(main, 0.56), main, dark: darken(main, 0.22), darker: darken(main, 0.72), }; } function buildLightPalette(): PaletteLike { const textPrimary = "#1B1B1F"; const textSecondary = "#46464F"; const secondaryMain = "#5A5C78"; const divider = "#EFEDF4"; const background = "#FFFFFF"; const disabled = "#777680"; const disabledBackground = "#E4E1E6"; return { primary: buildPrimary(ACCENT), secondary: { lighter: "#E0E0FF", light: "#C3C4E4", main: secondaryMain, dark: "#43455F", darker: "#171A31", }, error: { lighter: "#FFEDEA", light: "#FFDAD6", main: "#DE3730", dark: "#BA1A1A", darker: "#690005", }, warning: { lighter: "#FFEEE1", light: "#FFDCBE", main: "#AE6600", dark: "#8B5000", darker: "#4A2800", }, success: { lighter: "#DCFCE7", light: "#BBF7D0", main: "#16A34A", dark: "#15803D", darker: "#14532D", }, info: { lighter: "#D4F7FF", light: "#A1EFFF", main: "#008394", dark: "#006876", darker: "#00363E", }, grey: { 50: "#FBF8FF", 100: "#F5F2FA", 200: divider, 300: "#EAE7EF", 400: disabledBackground, 500: "#DBD9E0", 600: "#C7C5D0", 700: disabled, 800: textSecondary, 900: textPrimary, }, text: { primary: textPrimary, secondary: textSecondary, disabled, }, divider, // Soft grey app background with white paper gives the layered dashboard look // from the product mockups; cards/inputs (paper) sit above it. background: { default: "#F4F6FB", paper: background }, action: { hover: alpha(ACCENT, 0.05), disabled: alpha(disabled, 0.6), disabledBackground: alpha(disabledBackground, 0.9), }, }; } function buildDarkPalette(): PaletteLike { const bg = "#0B0B0E"; const paper = "#111116"; const divider = alpha("#FFFFFF", 0.10); const textPrimary = "#EAEAF2"; const textSecondary = alpha(textPrimary, 0.72); const secondaryMain = "#A4A6C8"; const disabled = alpha(textPrimary, 0.5); const disabledBackground = alpha("#FFFFFF", 0.08); return { primary: buildPrimary(ACCENT), secondary: { lighter: alpha(secondaryMain, 0.22), light: alpha(secondaryMain, 0.14), main: secondaryMain, dark: alpha(secondaryMain, 0.8), darker: alpha(secondaryMain, 0.95), }, error: { lighter: alpha("#DE3730", 0.18), light: alpha("#DE3730", 0.12), main: "#FF5A52", dark: "#FF3B33", darker: "#FFC2BE", }, warning: { lighter: alpha("#AE6600", 0.18), light: alpha("#AE6600", 0.12), main: "#FFB14A", dark: "#FF9A1F", darker: "#FFE1B8", }, success: { lighter: alpha("#16A34A", 0.18), light: alpha("#16A34A", 0.12), main: "#4ADE80", dark: "#22C55E", darker: "#BBF7D0", }, info: { lighter: alpha("#008394", 0.18), light: alpha("#008394", 0.12), main: "#22D3EE", dark: "#06B6D4", darker: "#BAF3FF", }, grey: { 50: bg, 100: "#0F0F13", 200: "#15151B", 300: "#1C1C24", 400: "#23232D", 500: "#2D2D3A", 600: "#3A3A4A", 700: "#4A4A5D", 800: "#B8B8C6", 900: textPrimary, }, text: { primary: textPrimary, secondary: textSecondary, disabled, }, divider, background: { default: bg, paper }, action: { hover: alpha(ACCENT, 0.16), disabled: alpha("#FFFFFF", 0.5), disabledBackground, }, }; } function buildCustomShadows(palette: any) { const shadowColor = palette.text.primary; const primaryColor = palette.primary.main; return { button: `0px 0.711px 1.422px 0px ${alpha(shadowColor, 0.05)}`, // Mockup cards float on the grey page background with no visible border, just a soft, // fairly generous shadow (dashboard stat tiles, pipeline columns' cards, job-workspace // panels) -- the old 1px "section" shadow read as flat/bordered rather than elevated. section: `0px 1px 2px 0px ${alpha(shadowColor, 0.04)}, 0px 8px 24px -12px ${alpha(shadowColor, 0.12)}`, tooltip: `0px 12px 16px -4px ${alpha(shadowColor, 0.08)}, 0px 4px 6px -2px ${alpha(shadowColor, 0.03)}`, focus: `0px 0px 0px 3px ${alpha(primaryColor, 0.2)}`, // Gradient CTA (mockup's "Tailor my CV" / "See the interface tour" buttons) gets its own // colored glow instead of the flat neutral button shadow. gradientButton: `0px 4px 14px -4px ${alpha(primaryColor, 0.45)}`, }; } // Mockup's signature AI/primary-action gradient (dashboard "Tailor my CV", landing "See the // interface tour"). Exported so every gradient CTA across the app stays pixel-identical // instead of each screen inventing its own two-color mix -- consumed via // (src/components/GradientButton.tsx), not applied as a MUI Button variant (MUI's variant // override machinery needs TS module augmentation for a genuinely new variant name; a plain // wrapper component is far less code for the same result). export const GRADIENT_CTA = "linear-gradient(90deg, #6366F1 0%, #22D3EE 100%)"; function buildTypography() { return { fontFamily: "'Archivo', system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif", letterSpacing: 0, // Mockup headings (F:\Pictures\website\jobtracker\new) are bold/black-weight display // type ("Dashboard", "One workspace for the whole search") -- 500 across the board read // as noticeably lighter/flatter than that reference. h1-h4 (page titles, hero, section // headers) go heavy; h5/h6 (card titles, in-context labels) stay a lighter semibold so // dense screens don't turn into a wall of black text. h1: { fontWeight: 800, fontSize: 36, lineHeight: "40px", letterSpacing: "-0.02em" }, h2: { fontWeight: 800, fontSize: 30, lineHeight: "34px", letterSpacing: "-0.02em" }, h3: { fontWeight: 800, fontSize: 26, lineHeight: "30px", letterSpacing: "-0.01em" }, h4: { fontWeight: 700, fontSize: 22, lineHeight: "26px", letterSpacing: "-0.01em" }, h5: { fontWeight: 700, fontSize: 18, lineHeight: "22px" }, h6: { fontWeight: 600, fontSize: 16, lineHeight: "20px" }, subtitle1: { fontWeight: 600, fontSize: 14, lineHeight: "18px" }, subtitle2: { fontWeight: 600, fontSize: 13, lineHeight: "17px" }, body1: { fontWeight: 400, fontSize: 14, lineHeight: "18px" }, body2: { fontWeight: 400, fontSize: 13, lineHeight: "17px" }, caption: { fontWeight: 400, fontSize: 12, lineHeight: "16px", letterSpacing: 0 }, overline: { fontWeight: 700, fontSize: 11, lineHeight: "14px", letterSpacing: "0.08em", textTransform: "uppercase" as const }, caption1: { fontWeight: 500, fontSize: 12, lineHeight: "16px", letterSpacing: 0 }, button: { textTransform: "capitalize" as const, fontWeight: 600 }, }; } export const getTheme = (_mode: "light" | "dark") => { const lightPalette = buildLightPalette(); const darkPalette = buildDarkPalette(); const theme = createTheme({ breakpoints: { values: { xs: 0, sm: 768, md: 1024, lg: 1266, xl: 1440, }, }, cssVariables: { cssVarPrefix: "", colorSchemeSelector: "data-color-scheme", }, colorSchemes: { light: { palette: lightPalette, customShadows: buildCustomShadows(lightPalette) }, dark: { palette: darkPalette, customShadows: buildCustomShadows(darkPalette) }, }, // Mockup radius reads noticeably rounder than the previous 10/8px defaults across cards, // stat tiles, kanban cards and buttons. shape: { borderRadius: 14 }, typography: buildTypography() as any, } as any) as any; theme.components = { MuiCssBaseline: { styleOverrides: { body: { WebkitFontSmoothing: "antialiased", MozOsxFontSmoothing: "grayscale", }, }, }, MuiPaper: { defaultProps: { elevation: 0 }, styleOverrides: { root: ({ theme }: any) => ({ border: `1px solid ${theme.vars.palette.divider}`, boxShadow: "none", backgroundImage: "none", }), }, }, MuiCard: { defaultProps: { elevation: 0 }, styleOverrides: { root: ({ theme }: any) => ({ // No border -- mockup cards float on the grey page background purely via shadow. border: "none", borderRadius: 16, backgroundImage: "none", boxShadow: theme.vars.customShadows.section, }), }, }, MuiButton: { defaultProps: { disableFocusRipple: true }, styleOverrides: { root: ({ theme }: any) => ({ borderRadius: 10, boxShadow: theme.vars.customShadows.button, "&:hover": { boxShadow: theme.vars.customShadows.button }, }), }, }, MuiTextField: { defaultProps: { size: "small", variant: "outlined", }, }, MuiOutlinedInput: { defaultProps: { size: "small" }, styleOverrides: { root: ({ theme }: any) => ({ borderRadius: 8, boxShadow: theme.vars.customShadows.button, background: theme.vars.palette.background.default, paddingLeft: 10, paddingRight: 10, minHeight: 42, display: "flex", alignItems: "center", "&.Mui-disabled": { cursor: "not-allowed", input: { cursor: "not-allowed" }, "& .MuiOutlinedInput-notchedOutline": { borderColor: theme.vars.palette.divider }, }, }), notchedOutline: ({ theme }: any) => ({ borderColor: theme.vars.palette.divider }), multiline: { padding: 10, alignItems: "flex-start", minHeight: "unset", }, input: { paddingLeft: 0, paddingRight: 0, paddingTop: 9, paddingBottom: 9, lineHeight: 1.45, display: "flex", alignItems: "center", }, inputMultiline: { paddingTop: 0, paddingBottom: 0, lineHeight: 1.5, }, }, }, MuiInputBase: { styleOverrides: { input: { "&::placeholder": { opacity: 0.72, }, }, inputMultiline: { "&::placeholder": { opacity: 0.72, }, }, }, }, MuiListItemButton: { styleOverrides: { root: ({ theme }: any) => ({ borderRadius: 8, "&.Mui-selected": { backgroundColor: theme.vars.palette.action.hover, }, }), }, }, MuiTableCell: { styleOverrides: { head: ({ theme }: any) => ({ fontWeight: 600, color: theme.vars.palette.text.primary, background: theme.vars.palette.grey[100], }), root: { paddingTop: 10, paddingBottom: 10, }, }, }, } as any; return theme; };