import { createTheme } from '@mui/material/styles'; import type { Shadows } from '@mui/material/styles'; import { getCssVar, CSS_VAR_FALLBACKS } from './css-vars'; /** * MUI adapter over the CSS-variable token file (src/styles/theme.css). * Mirrors shoc-frontend-new dev src/lib/theme/mui-theme.ts (ADR 0003). * Token changes are values-only edits in theme.css — never here. */ declare module '@mui/material/styles' { interface Palette { header: Palette['primary']; } interface PaletteOptions { header?: PaletteOptions['primary']; } } const v = (name: string, fallback: string) => getCssVar(name, fallback); const primary = v('--primary', CSS_VAR_FALLBACKS.primary); const primaryHover = v('--primary-hover', CSS_VAR_FALLBACKS.primaryHover); const primaryForeground = v('--primary-foreground', CSS_VAR_FALLBACKS.primaryForeground); const destructive = v('--destructive', CSS_VAR_FALLBACKS.destructive); const success = v('--success', CSS_VAR_FALLBACKS.success); const warning = v('--warning', CSS_VAR_FALLBACKS.warning); const background = v('--background', CSS_VAR_FALLBACKS.background); const foreground = v('--foreground', CSS_VAR_FALLBACKS.foreground); const border = v('--border', CSS_VAR_FALLBACKS.border); const muted = v('--muted', CSS_VAR_FALLBACKS.muted); const mutedForeground = v('--muted-foreground', CSS_VAR_FALLBACKS.mutedForeground); const inputBackground = v('--input-background', CSS_VAR_FALLBACKS.inputBackground); const ring = v('--ring', CSS_VAR_FALLBACKS.ring); const bgPage = v('--color-bg-page', CSS_VAR_FALLBACKS.bgPage); const radius = parseInt(v('--radius', `${CSS_VAR_FALLBACKS.radius}px`), 10); const headerEnd = v('--color-header-bg-end', CSS_VAR_FALLBACKS.headerEnd); const headerText = v('--color-header-text', CSS_VAR_FALLBACKS.headerText); const shadowSm = v('--shadow-sm', '0 1px 3px rgba(22, 30, 56, 0.06), 0 1px 2px rgba(22, 30, 56, 0.04)'); const shadowMd = v('--shadow-md', '0 4px 6px -1px rgba(22, 30, 56, 0.08), 0 2px 4px -2px rgba(22, 30, 56, 0.06)'); const shadowLg = v('--shadow-lg', '0 10px 15px -3px rgba(22, 30, 56, 0.1), 0 4px 6px -4px rgba(22, 30, 56, 0.08)'); const fontSans = '"DM Sans", ui-sans-serif, system-ui, sans-serif'; const fontDisplay = '"Montserrat", ui-sans-serif, system-ui, sans-serif'; // MUI's 25-slot elevation tuple, fully overridden: 0=none, 1–2=sm, 3–5=md, 6+=lg. const shadows = [ 'none', shadowSm, shadowSm, shadowMd, shadowMd, shadowMd, ...Array(19).fill(shadowLg), ] as Shadows; export const muiTheme = createTheme({ palette: { mode: 'light', primary: { main: primary, dark: primaryHover, contrastText: primaryForeground, }, // Repurposed as the muted/neutral swatch (SHOC convention), not a brand color. secondary: { main: muted, contrastText: foreground, }, error: { main: destructive, contrastText: '#ffffff', }, success: { main: success, contrastText: '#ffffff', }, warning: { main: warning, contrastText: '#ffffff', }, background: { default: bgPage, paper: background, }, text: { primary: foreground, secondary: mutedForeground, }, divider: border, header: { main: headerEnd, contrastText: headerText, }, }, typography: { fontFamily: fontSans, fontSize: 14, fontWeightRegular: 400, fontWeightMedium: 500, fontWeightBold: 600, h1: { fontFamily: fontDisplay, fontWeight: 800, fontSize: '1.75rem', lineHeight: 1.25 }, h2: { fontFamily: fontDisplay, fontWeight: 700, fontSize: '1.375rem', lineHeight: 1.25 }, h3: { fontFamily: fontDisplay, fontWeight: 600, fontSize: '1.125rem', lineHeight: 1.25 }, h4: { fontFamily: fontDisplay, fontWeight: 600, fontSize: '1rem', lineHeight: 1.25 }, h5: { fontFamily: fontDisplay, fontWeight: 600, fontSize: '0.875rem', lineHeight: 1.25 }, h6: { fontFamily: fontDisplay, fontWeight: 600, fontSize: '0.8125rem', lineHeight: 1.25 }, subtitle1: { fontWeight: 600, fontSize: '1rem' }, subtitle2: { fontWeight: 500, fontSize: '0.875rem', color: mutedForeground }, body1: { fontSize: '0.875rem', lineHeight: 1.5 }, body2: { fontSize: '0.8125rem', lineHeight: 1.5, color: mutedForeground }, caption: { fontSize: '0.75rem', color: mutedForeground }, button: { textTransform: 'none' as const, fontWeight: 600, fontSize: '0.875rem' }, overline: { fontSize: '0.6875rem', fontWeight: 600, letterSpacing: '0.08em', textTransform: 'uppercase' as const, color: mutedForeground, }, }, shape: { borderRadius: radius, }, shadows, components: { MuiCssBaseline: { styleOverrides: { body: { fontSize: 14, backgroundColor: bgPage, color: foreground, }, }, }, MuiButton: { defaultProps: { disableElevation: true, }, styleOverrides: { root: { borderRadius: 'var(--radius-md)', textTransform: 'none' as const, fontWeight: 600, fontSize: '0.875rem', transition: 'background-color var(--duration-fast) var(--ease-default), box-shadow var(--duration-fast) var(--ease-default)', '&:focus-visible': { outline: `2px solid ${ring}`, outlineOffset: 2, }, // MUI v9: containedPrimary slot removed — class selector instead '&.MuiButton-containedPrimary:hover': { backgroundColor: primaryHover, }, }, outlined: { borderColor: border, '&:hover': { borderColor: 'var(--border-hover)', backgroundColor: 'var(--secondary)', }, }, }, }, MuiTextField: { defaultProps: { size: 'small' as const, }, }, MuiOutlinedInput: { styleOverrides: { root: { backgroundColor: inputBackground, borderRadius: 'var(--radius-md)', '& .MuiOutlinedInput-notchedOutline': { borderColor: border, }, '&:hover .MuiOutlinedInput-notchedOutline': { borderColor: 'var(--border-hover)', }, '&.Mui-focused': { boxShadow: `0 0 0 3px color-mix(in srgb, ${ring} 25%, transparent)`, }, '&.Mui-focused .MuiOutlinedInput-notchedOutline': { borderColor: ring, borderWidth: 2, }, }, input: { padding: '8.5px 13px', fontSize: '0.875rem', '&.MuiOutlinedInput-inputAdornedEnd': { paddingRight: 40, }, }, }, }, MuiTableCell: { styleOverrides: { root: { fontSize: '0.875rem', borderColor: border, padding: '10px 16px', }, head: { fontWeight: 600, backgroundColor: 'var(--color-bg-muted)', color: foreground, }, }, }, MuiTableRow: { styleOverrides: { root: { '&:last-child .MuiTableCell-root': { borderBottom: 0, }, }, }, }, MuiChip: { styleOverrides: { root: { borderRadius: 'var(--radius-sm)', fontWeight: 500, fontSize: '0.75rem', }, outlined: { borderColor: border, }, }, }, MuiPaper: { defaultProps: { elevation: 0, }, styleOverrides: { root: { backgroundImage: 'none', borderRadius: radius, }, outlined: { borderColor: border, }, }, }, MuiDialog: { styleOverrides: { paper: { borderRadius: 'var(--radius-xl)', boxShadow: shadowLg, }, }, }, MuiAlert: { styleOverrides: { root: { borderRadius: 'var(--radius-md)', fontSize: '0.875rem', // MUI v9: standard* slots removed — class selectors instead '&.MuiAlert-standardSuccess': { backgroundColor: 'var(--status-completed-bg)', color: 'var(--status-completed-text)', }, '&.MuiAlert-standardError': { backgroundColor: 'var(--doc-no-bg)', color: 'var(--doc-no-text)', }, '&.MuiAlert-standardWarning': { backgroundColor: 'var(--status-pending-bg)', color: 'var(--status-pending-text)', }, '&.MuiAlert-standardInfo': { backgroundColor: 'var(--color-primary-tint)', color: 'var(--sidebar-accent-foreground)', }, }, }, }, }, });