File size: 3,940 Bytes
963e554
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
 * Shared design tokens + theme factory for Sensorflow Studio.
 *
 * Semantic color tokens (success / warn / danger / info / neutral) are the
 * single source of truth for state coloring across pages — use these instead
 * of ad-hoc hex values in new code. Existing pages keep their local palettes;
 * the values here intentionally match the established dark-theme colors so
 * adoption is a no-op visually.
 */
import { createTheme, type Theme } from '@mui/material/styles';

export const tokens = {
  color: {
    success: '#66bb6a',
    successBg: 'rgba(102,187,106,0.12)',
    successStrong: '#1b5e20',
    warn: '#f9a825',
    warnBg: 'rgba(249,168,37,0.12)',
    danger: '#ef5350',
    dangerBg: 'rgba(239,83,80,0.14)',
    dangerStrong: '#b71c1c',
    info: '#4fc3f7',
    infoBg: 'rgba(79,195,247,0.12)',
    neutral: '#8a949e',
    neutralBg: 'rgba(138,148,158,0.12)',
    text: '#e6e9ec',
    textDim: '#aab4be',
    textFaint: '#5c6873',
    surface: '#161b21',
    surfaceRaised: '#1b222a',
    surfaceSunken: '#12171d',
    canvas: '#101418',
    border: '#232a31',
    borderStrong: '#2f3944',
  },
  motion: {
    fast: '120ms cubic-bezier(0.4, 0, 0.2, 1)',
    normal: '200ms cubic-bezier(0.4, 0, 0.2, 1)',
    slow: '320ms cubic-bezier(0.4, 0, 0.2, 1)',
  },
  radius: { sm: 4, md: 8, lg: 12 },
  elevation: {
    raised: '0 2px 10px rgba(0,0,0,0.35)',
    overlay: '0 6px 24px rgba(0,0,0,0.5)',
  },
} as const;

/** Color for a signed delta where positive = good (e.g. recall delta). */
export function deltaColor(delta: number, higherIsBetter = true, eps = 1e-9): string {
  if (Math.abs(delta) < eps) return tokens.color.neutral;
  const improved = higherIsBetter ? delta > 0 : delta < 0;
  return improved ? tokens.color.success : tokens.color.danger;
}

/** Traffic-light color for pass/block/unknown-style verdicts. */
export function verdictColor(v: string | null | undefined): string {
  const s = (v ?? '').toUpperCase();
  if (['PASS', 'PROMOTE', 'RELEASE_READY', 'CALIBRATED', 'ALLOW', 'OK'].includes(s)) return tokens.color.success;
  if (['BLOCK', 'BLOCKED', 'FAIL', 'REGRESSION', 'MISCALIBRATED', 'DO_NOT_PROMOTE', 'PERCEPTION_FAILURE'].includes(s))
    return tokens.color.danger;
  if (['WARN', 'INSUFFICIENT_EVIDENCE', 'DEGRADED', 'NEVER_RUN'].includes(s)) return tokens.color.warn;
  return tokens.color.neutral;
}

export function buildTheme(): Theme {
  return createTheme({
    palette: {
      mode: 'dark',
      background: { default: tokens.color.canvas, paper: tokens.color.surface },
      primary: { main: tokens.color.info },
      success: { main: tokens.color.success },
      warning: { main: tokens.color.warn },
      error: { main: tokens.color.danger },
      info: { main: tokens.color.info },
      divider: tokens.color.border,
    },
    typography: {
      fontFamily: "'Inter', 'Helvetica Neue', Arial, sans-serif",
    },
    components: {
      MuiButtonBase: {
        styleOverrides: {
          root: {
            // Keyboard-focus visibility: a clear outline that never shows on mouse click.
            '&.Mui-focusVisible': {
              outline: `2px solid ${tokens.color.info}`,
              outlineOffset: 1,
            },
          },
        },
      },
      MuiButton: {
        styleOverrides: {
          root: { transition: `background-color ${tokens.motion.fast}, border-color ${tokens.motion.fast}, color ${tokens.motion.fast}` },
        },
      },
      MuiCard: {
        styleOverrides: {
          root: { transition: `border-color ${tokens.motion.normal}, box-shadow ${tokens.motion.normal}` },
        },
      },
      MuiChip: {
        styleOverrides: {
          root: { transition: `background-color ${tokens.motion.fast}` },
        },
      },
      MuiSkeleton: {
        defaultProps: { animation: 'wave' },
        styleOverrides: {
          root: { backgroundColor: 'rgba(138,148,158,0.09)' },
        },
      },
    },
  });
}