feat(admin): read live back-office data in every console view

Models, pipelines, users, subscriptions, usage, audit log, ads, and releases
still rendered placeholder or duplicated implementations from the earlier
admin split. They now read the live back-office API, share one sidebar and
console theme, and the license issuer dialog uses the rotated signing key.
This commit is contained in:
Yun Chan 2026-09-16 23:24:35 +09:00
parent cfc58458a8
commit 5aa268970a
23 changed files with 187 additions and 174 deletions

View file

@ -99,7 +99,7 @@ function RewardKpis({ stats }: { stats: AdRewardStats }): React.ReactElement {
>
{card.title}
</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '22px', fontWeight: 700, color: C.bright, lineHeight: 1.25 }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '22px', fontWeight: 500, color: C.bright, lineHeight: 1.25 }}>
{card.value}
</Typography>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '11px', color: C.dim, mt: 0.5 }}>{card.subtext}</Typography>

View file

@ -71,7 +71,7 @@ export default async function AuditLogDetailPage({ params }: PageProps): Promise
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #3b82f6 0%, #8b5cf6 100%)',
background: 'linear-gradient(180deg, var(--d3-accent-main) 0%, var(--d3-tag-purple) 100%)',
}}
/>
<Box>
@ -131,7 +131,7 @@ export default async function AuditLogDetailPage({ params }: PageProps): Promise
sx={{
p: 2,
borderRadius: '12px',
bgcolor: 'rgba(10, 17, 31, 0.7)',
bgcolor: 'var(--d3-bg-inset-soft)',
border: `1px solid ${C.border}`,
fontFamily: FONT_SANS,
fontSize: '13px',

View file

@ -72,7 +72,7 @@ export default async function AuditLogPage({ searchParams }: PageProps): Promise
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #60a5fa 0%, #3b82f6 100%)',
background: 'linear-gradient(180deg, var(--d3-accent-light) 0%, var(--d3-accent-main) 100%)',
}}
/>
<Box>
@ -182,7 +182,7 @@ export default async function AuditLogPage({ searchParams }: PageProps): Promise
borderRadius: '8px',
textTransform: 'none',
px: 1.5,
'&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight },
'&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight },
}}
>
Inspect →

View file

@ -345,7 +345,7 @@ export default function ServiceModelsPage(): React.ReactElement {
width: 4,
height: 34,
borderRadius: '999px',
background: 'linear-gradient(180deg, #06b6d4 0%, #8b5cf6 50%, #3b82f6 100%)',
background: 'linear-gradient(180deg, var(--d3-tag-cyan) 0%, var(--d3-tag-purple) 50%, var(--d3-accent-main) 100%)',
}}
/>
<Box>
@ -457,8 +457,8 @@ export default function ServiceModelsPage(): React.ReactElement {
width: 44,
height: 44,
borderRadius: '12px',
bgcolor: 'rgba(6, 182, 212, 0.15)',
border: '1px solid rgba(6, 182, 212, 0.3)',
bgcolor: 'var(--d3-tag-cyan)',
border: '1px solid var(--d3-tag-cyan)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
@ -483,7 +483,7 @@ export default function ServiceModelsPage(): React.ReactElement {
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '11px', color: C.cyanLight, bgcolor: 'rgba(6, 182, 212, 0.1)', px: 1.5, py: 0.75, borderRadius: '8px', border: `1px solid ${C.borderHl}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '11px', color: C.cyanLight, bgcolor: 'var(--d3-tag-cyan)', px: 1.5, py: 0.75, borderRadius: '8px', border: `1px solid ${C.borderHl}` }}>
🛡️ Auto Failover Route: {sttEndpoints.map((e) => e.providerType).join(' ➔ ')}
</Typography>
</Box>
@ -530,7 +530,7 @@ export default function ServiceModelsPage(): React.ReactElement {
</Box>
) : (
sttEndpoints.map((ep) => (
<Box component="tr" key={ep.id} sx={{ bgcolor: ep.isDefault ? 'rgba(59, 130, 246, 0.05)' : 'transparent' }}>
<Box component="tr" key={ep.id} sx={{ bgcolor: ep.isDefault ? 'var(--d3-accent-glow)' : 'transparent' }}>
<Box component="td" sx={{ fontFamily: FONT_MONO, fontSize: '12px', color: C.cyanLight, fontWeight: 500 }}>
#{ep.fallbackPriority}
</Box>
@ -556,7 +556,7 @@ export default function ServiceModelsPage(): React.ReactElement {
</Box>
<Box component="td">
{ep.isDefault ? (
<Box component="span" sx={{ px: 1, py: 0.3, borderRadius: '4px', bgcolor: 'rgba(34, 197, 94, 0.2)', color: C.green400, fontSize: '10px', fontWeight: 500 }}>
<Box component="span" sx={{ px: 1, py: 0.3, borderRadius: '4px', bgcolor: 'var(--d3-status-success)', color: C.green400, fontSize: '10px', fontWeight: 500 }}>
⭐ DEFAULT
</Box>
) : (
@ -576,10 +576,10 @@ export default function ServiceModelsPage(): React.ReactElement {
fontFamily: FONT_SANS,
fontSize: '10px',
color: C.green400,
borderColor: 'rgba(34, 197, 94, 0.4)',
borderColor: 'var(--d3-status-success)',
px: 1,
py: 0.25,
'&:hover': { bgcolor: 'rgba(34, 197, 94, 0.15)', borderColor: C.green400 },
'&:hover': { bgcolor: 'var(--d3-status-success)', borderColor: C.green400 },
}}
>
Set Default
@ -596,7 +596,7 @@ export default function ServiceModelsPage(): React.ReactElement {
borderColor: C.borderHl,
px: 1,
py: 0.25,
'&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight },
'&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight },
}}
>
{sttPingStatus[ep.id] || '⚡ Test'}
@ -676,7 +676,7 @@ export default function ServiceModelsPage(): React.ReactElement {
<Box component="td" sx={{ fontFamily: FONT_MONO, fontSize: '12px', color: C.bright, fontWeight: 600 }}>
{ep.modelId}
{ep.isDefault && (
<Box component="span" sx={{ ml: 1, px: 0.75, py: 0.1, borderRadius: '4px', bgcolor: 'rgba(59, 130, 246, 0.2)', color: C.cyanLight, fontSize: '9px' }}>
<Box component="span" sx={{ ml: 1, px: 0.75, py: 0.1, borderRadius: '4px', bgcolor: 'var(--d3-accent-glow)', color: C.cyanLight, fontSize: '9px' }}>
DEFAULT
</Box>
)}
@ -716,7 +716,7 @@ export default function ServiceModelsPage(): React.ReactElement {
borderColor: C.borderHl,
px: 1,
py: 0.25,
'&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight },
'&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight },
}}
>
Delete
@ -740,11 +740,11 @@ export default function ServiceModelsPage(): React.ReactElement {
fullWidth
PaperProps={{
sx: {
bgcolor: 'rgba(17, 26, 48, 0.95)',
bgcolor: 'var(--d3-bg-card-soft)',
backdropFilter: 'blur(32px)',
border: `1px solid ${C.borderHl}`,
borderRadius: '20px',
boxShadow: '0 24px 60px rgba(3, 7, 18, 0.8)',
boxShadow: '0 24px 60px var(--d3-scrim)',
},
}}
>
@ -772,7 +772,7 @@ export default function ServiceModelsPage(): React.ReactElement {
if (preset.prompt) setSttPrompt(preset.prompt)
}}
sx={{
bgcolor: 'rgba(10, 17, 31, 0.7)',
bgcolor: 'var(--d3-bg-inset-soft)',
color: C.bright,
borderRadius: '10px',
'& fieldset': { borderColor: C.border },
@ -796,7 +796,7 @@ export default function ServiceModelsPage(): React.ReactElement {
size="small"
placeholder="e.g. Groq Whisper LPU Fast"
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -807,7 +807,7 @@ export default function ServiceModelsPage(): React.ReactElement {
label="Provider Type"
onChange={(e) => setSttProviderType(e.target.value as STTProviderCategory)}
sx={{
bgcolor: 'rgba(10, 17, 31, 0.7)',
bgcolor: 'var(--d3-bg-inset-soft)',
color: C.bright,
borderRadius: '10px',
'& fieldset': { borderColor: C.border },
@ -834,7 +834,7 @@ export default function ServiceModelsPage(): React.ReactElement {
size="small"
placeholder="https://api.groq.com/openai/v1/audio/transcriptions"
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -849,7 +849,7 @@ export default function ServiceModelsPage(): React.ReactElement {
size="small"
placeholder={sttEditingId ? '•••••••• (변경 시 입력)' : 'gsk_... or sk-... or token'}
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -862,7 +862,7 @@ export default function ServiceModelsPage(): React.ReactElement {
size="small"
placeholder="e.g. whisper-large-v3-turbo, nova-3"
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -876,7 +876,7 @@ export default function ServiceModelsPage(): React.ReactElement {
label="Dispatch Method"
onChange={(e) => setSttMethod(e.target.value as SttProviderEndpoint['method'])}
sx={{
bgcolor: 'rgba(10, 17, 31, 0.7)',
bgcolor: 'var(--d3-bg-inset-soft)',
color: C.bright,
borderRadius: '10px',
'& fieldset': { borderColor: C.border },
@ -897,7 +897,7 @@ export default function ServiceModelsPage(): React.ReactElement {
size="small"
placeholder="ko, en, auto"
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -911,7 +911,7 @@ export default function ServiceModelsPage(): React.ReactElement {
required
size="small"
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -926,7 +926,7 @@ export default function ServiceModelsPage(): React.ReactElement {
required
size="small"
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -937,7 +937,7 @@ export default function ServiceModelsPage(): React.ReactElement {
size="small"
placeholder="e.g. D3RO, Kubernetes, React, LLM"
sx={{
'& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' },
'& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' },
'& .MuiInputLabel-root': { color: C.dim },
}}
/>
@ -950,11 +950,11 @@ export default function ServiceModelsPage(): React.ReactElement {
required
helperText="변경 사유를 3자 이상 입력하세요."
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' } }}
/>
{/* Test Connection Inside Modal */}
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.6)', border: `1px solid ${C.border}`, display: 'flex', flexDirection: 'column', gap: 1.5 }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}`, display: 'flex', flexDirection: 'column', gap: 1.5 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '13px', fontWeight: 600, color: C.bright }}>
Live Connection Test (Synthetic Audio Ping)
@ -970,7 +970,7 @@ export default function ServiceModelsPage(): React.ReactElement {
color: C.bright,
borderColor: C.borderHl,
textTransform: 'none',
'&:hover': { borderColor: C.accentLight, bgcolor: 'rgba(59, 130, 246, 0.15)' },
'&:hover': { borderColor: C.accentLight, bgcolor: 'var(--d3-accent-glow)' },
}}
>
{testingInModal ? <CircularProgress size={14} sx={{ color: C.bright, mr: 1 }} /> : null}
@ -985,8 +985,8 @@ export default function ServiceModelsPage(): React.ReactElement {
sx={{
fontFamily: FONT_SANS,
fontSize: '12px',
borderColor: sttTestModalResult.success ? 'rgba(34, 197, 94, 0.5)' : 'rgba(239, 68, 68, 0.5)',
color: sttTestModalResult.success ? C.green400 : '#f87171',
borderColor: sttTestModalResult.success ? 'var(--d3-status-success)' : 'var(--d3-status-danger)',
color: sttTestModalResult.success ? C.green400 : 'var(--d3-status-danger)',
}}
>
{sttTestModalResult.message}
@ -1013,11 +1013,11 @@ export default function ServiceModelsPage(): React.ReactElement {
fullWidth
PaperProps={{
sx: {
bgcolor: 'rgba(17, 26, 48, 0.95)',
bgcolor: 'var(--d3-bg-card-soft)',
backdropFilter: 'blur(32px)',
border: `1px solid ${C.borderHl}`,
borderRadius: '20px',
boxShadow: '0 24px 60px rgba(3, 7, 18, 0.8)',
boxShadow: '0 24px 60px var(--d3-scrim)',
},
}}
>
@ -1042,7 +1042,7 @@ export default function ServiceModelsPage(): React.ReactElement {
setLlmCompletionCost(preset.completionCost)
}}
sx={{
bgcolor: 'rgba(10, 17, 31, 0.7)',
bgcolor: 'var(--d3-bg-inset-soft)',
color: C.bright,
borderRadius: '10px',
'& fieldset': { borderColor: C.border },
@ -1062,7 +1062,7 @@ export default function ServiceModelsPage(): React.ReactElement {
required
fullWidth
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
/>
<TextField
label="Display Name"
@ -1071,7 +1071,7 @@ export default function ServiceModelsPage(): React.ReactElement {
required
fullWidth
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' } }}
/>
<FormControl fullWidth size="small">
<InputLabel sx={{ color: C.dim }}>Provider Category</InputLabel>
@ -1079,7 +1079,7 @@ export default function ServiceModelsPage(): React.ReactElement {
value={llmProvider}
label="Provider Category"
onChange={(e) => setLlmProvider(e.target.value)}
sx={{ bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' }}
sx={{ bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' }}
>
<MenuItem value="Local Sidecar">Local Sidecar</MenuItem>
<MenuItem value="Ollama Local">Ollama Local Engine</MenuItem>
@ -1095,7 +1095,7 @@ export default function ServiceModelsPage(): React.ReactElement {
required
fullWidth
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
/>
<TextField
label="API Key (Optional)"
@ -1104,7 +1104,7 @@ export default function ServiceModelsPage(): React.ReactElement {
onChange={(e) => setLlmApiKey(e.target.value)}
fullWidth
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
/>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 2 }}>
<TextField
@ -1115,7 +1115,7 @@ export default function ServiceModelsPage(): React.ReactElement {
onChange={(e) => setLlmPromptCost(e.target.value)}
required
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
/>
<TextField
label="Completion Cost ($/1K)"
@ -1125,7 +1125,7 @@ export default function ServiceModelsPage(): React.ReactElement {
onChange={(e) => setLlmCompletionCost(e.target.value)}
required
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }}
/>
</Box>
<TextField
@ -1135,7 +1135,7 @@ export default function ServiceModelsPage(): React.ReactElement {
required
helperText="생성 사유를 3자 이상 입력하세요."
size="small"
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' } }}
sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' } }}
/>
</DialogContent>
<DialogActions sx={{ px: 3, pb: 3, pt: 1, borderTop: `1px solid ${C.border}` }}>

View file

@ -128,7 +128,7 @@ export default async function AdminOverviewPage(): Promise<React.ReactElement> {
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #06b6d4 0%, #3b82f6 50%, #8b5cf6 100%)',
background: 'linear-gradient(180deg, var(--d3-tag-cyan) 0%, var(--d3-accent-main) 50%, var(--d3-tag-purple) 100%)',
}}
/>
<Box>
@ -174,11 +174,11 @@ export default async function AdminOverviewPage(): Promise<React.ReactElement> {
fontSize: '12px',
color: C.bright,
borderColor: C.borderHl,
bgcolor: 'rgba(17, 26, 48, 0.6)',
bgcolor: 'var(--d3-bg-card-soft)',
borderRadius: '10px',
textTransform: 'none',
px: 2,
'&:hover': { borderColor: C.accentLight, bgcolor: 'rgba(26, 38, 68, 0.8)' },
'&:hover': { borderColor: C.accentLight, bgcolor: 'var(--d3-bg-raised-soft)' },
}}
>
View Pipelines Console →
@ -352,12 +352,12 @@ export default async function AdminOverviewPage(): Promise<React.ReactElement> {
sx={{
p: 2,
borderRadius: '14px',
bgcolor: 'rgba(10, 17, 31, 0.65)',
bgcolor: 'var(--d3-bg-inset-soft)',
border: `1px solid ${C.border}`,
transition: 'all 0.2s ease',
'&:hover': {
borderColor: C.accentLight,
bgcolor: 'rgba(17, 26, 48, 0.8)',
bgcolor: 'var(--d3-bg-card-soft)',
transform: 'translateY(-2px)',
},
}}
@ -371,8 +371,8 @@ export default async function AdminOverviewPage(): Promise<React.ReactElement> {
width: 8,
height: 8,
borderRadius: '50%',
bgcolor: node.status === 'operational' ? '#10b981' : node.status === 'degraded' ? '#f59e0b' : '#ef4444',
boxShadow: `0 0 8px ${node.status === 'operational' ? '#10b981' : node.status === 'degraded' ? '#f59e0b' : '#ef4444'}`,
bgcolor: node.status === 'operational' ? 'var(--d3-status-success)' : node.status === 'degraded' ? 'var(--d3-status-warning)' : 'var(--d3-status-danger)',
boxShadow: `0 0 8px ${node.status === 'operational' ? 'var(--d3-status-success)' : node.status === 'degraded' ? 'var(--d3-status-warning)' : 'var(--d3-status-danger)'}`,
}}
/>
</Box>

View file

@ -44,7 +44,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
width: 4,
height: 28,
borderRadius: '999px',
background: 'linear-gradient(180deg, #06b6d4 0%, #3b82f6 100%)',
background: 'linear-gradient(180deg, var(--d3-tag-cyan) 0%, var(--d3-accent-main) 100%)',
}}
/>
<Box>
@ -89,11 +89,11 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
fontSize: '12px',
color: C.bright,
borderColor: C.borderHl,
bgcolor: 'rgba(17, 26, 48, 0.6)',
bgcolor: 'var(--d3-bg-card-soft)',
borderRadius: '10px',
textTransform: 'none',
px: 2,
'&:hover': { borderColor: C.accentLight, bgcolor: 'rgba(26, 38, 68, 0.8)' },
'&:hover': { borderColor: C.accentLight, bgcolor: 'var(--d3-bg-raised-soft)' },
}}
>
⚡ Run Diagnostic Ping
@ -129,19 +129,19 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 1.5, mb: 2.5 }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>AVG LATENCY</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.bright }}>
{whisper.avgLatencyMs}ms
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>SPEEDUP FACTOR</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.green400 }}>
{whisper.speedupFactor}
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>GPU VRAM</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.cyanLight }}>
{whisper.gpuVramUsage}
@ -149,7 +149,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.5)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '12px', color: C.text, lineHeight: 1.6 }}>
• <strong>Dual-Condition Flush:</strong> Audio buffer flushes parallel with model warm-up.<br />
• <strong>Realtime Streaming:</strong> {whisper.partialStreamingFps} fps interim partial transcription in RecordingTip popup.<br />
@ -182,19 +182,19 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 1.5, mb: 2.5 }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>THROUGHPUT</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.bright }}>
{ollama.tokensPerSecond} tok/s
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>CONTEXT LIMIT</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.cyanLight }}>
{ollama.activeContextLimit}
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>VRAM OCCUPANCY</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.purple400 }}>
{ollama.vramAllocated}
@ -202,7 +202,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.5)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '12px', color: C.text, lineHeight: 1.6 }}>
• <strong>Loaded Models:</strong> {ollama.loadedModels.join(', ')}<br />
• <strong>NDJSON Streaming:</strong> Zero-latency token streaming for Auto Polish & AI Chat.<br />
@ -238,19 +238,19 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 1.5, mb: 2.5 }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>LIVE STREAMS</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.orange400 }}>
{realtimeVoice.activeStreams} Active
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>AUDIO RTT</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.bright }}>
{realtimeVoice.avgAudioRttMs}ms
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>LOCAL FALLBACK</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.green400 }}>
{realtimeVoice.localFallbackRate}
@ -258,7 +258,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.5)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '12px', color: C.text, lineHeight: 1.6 }}>
• <strong>Ultra-low Latency:</strong> Full-duplex bidirectional voice-to-voice stream.<br />
• <strong>Auto Failover:</strong> Drops gracefully to Local STT + Ollama + TTS if network drops.<br />
@ -291,19 +291,19 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 1.5, mb: 2.5 }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>INDEXED DOCS</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.bright }}>
{ragVector.indexedDocuments.toLocaleString()}
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>VECTOR CHUNKS</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.cyanLight }}>
{ragVector.totalVectorChunks.toLocaleString()}
</Typography>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>SEARCH HIT RATE</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '16px', fontWeight: 500, color: C.green400 }}>
{ragVector.topHitRatePercent}%
@ -311,7 +311,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
</Box>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'rgba(10, 17, 31, 0.5)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 1.5, borderRadius: '10px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '12px', color: C.text, lineHeight: 1.6 }}>
• <strong>Local Vector Store:</strong> Zero-cloud-leakage SQLite embeddings with cosine similarity.<br />
• <strong>Average Search Latency:</strong> {ragVector.avgSearchLatencyMs}ms per 512-dim query.<br />
@ -345,7 +345,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(4, 1fr)' }, gap: 2, mb: 3 }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>SPEAKER ACCURACY</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '20px', fontWeight: 500, color: C.green400 }}>
{meetingIntelligence.speakerAccuracyPercent}%
@ -354,7 +354,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
Pyannote + LLM Consensus
</Typography>
</Box>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>ACTIVE MEETINGS</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '20px', fontWeight: 500, color: C.cyanLight }}>
{meetingIntelligence.activeMeetingSessions} Live
@ -363,7 +363,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
Realtime Captions & Record
</Typography>
</Box>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>TEMPLATES TODAY</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '20px', fontWeight: 500, color: C.purple400 }}>
{meetingIntelligence.templatesGeneratedToday} Docs
@ -372,7 +372,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
Summary, Action Items, Jira
</Typography>
</Box>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '10px', color: C.dim }}>MINDMAP EXPORTS</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '20px', fontWeight: 500, color: C.orange400 }}>
{meetingIntelligence.mindmapsExported} Maps
@ -383,7 +383,7 @@ export default async function PipelinesPage(): Promise<React.ReactElement> {
</Box>
</Box>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.5)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '13px', color: C.text, lineHeight: 1.7 }}>
• <strong>Speaker Attribution Architecture:</strong> Hybrid pipeline combining Pyannote 3.1 voiceprint embeddings with LLM conversational speaker inference.<br />
• <strong>Multi-Document Synthesis (Phase 14.5):</strong> Simultaneous generation of Executive Summary, Action Item Checklist, Jira Issue Drafts, and Interactive Markdown Mindmaps.<br />

View file

@ -165,7 +165,7 @@ function KpiCards({ hub }: { hub: ReleaseHub }): React.ReactElement {
>
{card.title}
</Typography>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '22px', fontWeight: 700, color: C.bright, lineHeight: 1.25 }}>
<Typography sx={{ fontFamily: FONT_MONO, fontSize: '22px', fontWeight: 500, color: C.bright, lineHeight: 1.25 }}>
{card.value}
</Typography>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '11px', color: C.dim, mt: 0.5 }}>{card.subtext}</Typography>

View file

@ -80,7 +80,7 @@ export default async function SubscriptionDetailPage({ params }: PageProps): Pro
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #a855f7 0%, #3b82f6 100%)',
background: 'linear-gradient(180deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)',
}}
/>
<Box>

View file

@ -31,7 +31,7 @@ export function NewSubscriptionClient({ initialUserId }: NewSubscriptionClientPr
placeholder="Supabase user UUID"
sx={{
'& .MuiOutlinedInput-root': {
bgcolor: 'rgba(10, 17, 31, 0.7)',
bgcolor: 'var(--d3-bg-inset-soft)',
color: C.bright,
borderRadius: '10px',
fontFamily: FONT_MONO,

View file

@ -39,7 +39,7 @@ export default async function NewSubscriptionPage({ searchParams }: PageProps):
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #a855f7 0%, #3b82f6 100%)',
background: 'linear-gradient(180deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)',
}}
/>
<Box>

View file

@ -115,7 +115,7 @@ export default async function AdminSubscriptionsPage({ searchParams }: PageProps
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #a855f7 0%, #3b82f6 100%)',
background: 'linear-gradient(180deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)',
}}
/>
<Box>
@ -305,7 +305,7 @@ export default async function AdminSubscriptionsPage({ searchParams }: PageProps
borderRadius: '8px',
textTransform: 'none',
px: 1.5,
'&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight },
'&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight },
}}
>
Edit →

View file

@ -84,7 +84,7 @@ export default async function AdminUsagePage(): Promise<React.ReactElement> {
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #10b981 0%, #3b82f6 100%)',
background: 'linear-gradient(180deg, var(--d3-status-success) 0%, var(--d3-accent-main) 100%)',
}}
/>
<Box>
@ -221,12 +221,12 @@ export default async function AdminUsagePage(): Promise<React.ReactElement> {
{(f.totalCalls ?? f.callCount ?? 0).toLocaleString()} calls ({(f.percentage ?? 10).toFixed(1)}%) • ${(f.estimatedCostUsd ?? f.totalCost).toFixed(2)}
</Typography>
</Box>
<Box sx={{ width: '100%', height: 8, bgcolor: 'rgba(10, 17, 31, 0.8)', borderRadius: '999px', overflow: 'hidden', border: `1px solid ${C.border}` }}>
<Box sx={{ width: '100%', height: 8, bgcolor: 'var(--d3-bg-inset-soft)', borderRadius: '999px', overflow: 'hidden', border: `1px solid ${C.border}` }}>
<Box
sx={{
width: `${f.percentage ?? 10}%`,
height: '100%',
background: 'linear-gradient(90deg, #06b6d4 0%, #3b82f6 50%, #8b5cf6 100%)',
background: 'linear-gradient(90deg, var(--d3-tag-cyan) 0%, var(--d3-accent-main) 50%, var(--d3-tag-purple) 100%)',
borderRadius: '999px',
transition: 'width 0.8s cubic-bezier(0.16, 1, 0.3, 1)',
}}

View file

@ -84,7 +84,7 @@ export default async function AdminUserDetailPage({ params }: PageProps): Promis
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #3b82f6 0%, #8b5cf6 100%)',
background: 'linear-gradient(180deg, var(--d3-accent-main) 0%, var(--d3-tag-purple) 100%)',
}}
/>
<Box>
@ -138,15 +138,15 @@ export default async function AdminUserDetailPage({ params }: PageProps): Promis
height: 48,
borderRadius: '14px',
background: isProPlus
? 'linear-gradient(135deg, #a855f7 0%, #3b82f6 100%)'
: 'linear-gradient(135deg, #10b981 0%, #3b82f6 100%)',
? 'linear-gradient(135deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)'
: 'linear-gradient(135deg, var(--d3-status-success) 0%, var(--d3-accent-main) 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#ffffff',
color: 'var(--d3-text-inverse)',
fontWeight: 500,
fontSize: '20px',
boxShadow: '0 0 20px rgba(59, 130, 246, 0.4)',
boxShadow: '0 0 20px var(--d3-accent-glow)',
}}
>
{((profile.name as string) || (profile.email as string) || '?').charAt(0).toUpperCase()}
@ -188,7 +188,7 @@ export default async function AdminUserDetailPage({ params }: PageProps): Promis
<Row label="Cancel Scheduled" value={sub?.cancel_at ? new Date(sub.cancel_at as string).toLocaleDateString() : 'Not scheduled'} />
</Box>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '12px', fontWeight: 600, color: C.bright, mb: 1 }}>
Entitlement source
</Typography>
@ -200,7 +200,7 @@ export default async function AdminUserDetailPage({ params }: PageProps): Promis
</Box>
{/* Tier-based Enabled Features */}
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'rgba(10, 17, 31, 0.7)', border: `1px solid ${C.border}` }}>
<Box sx={{ p: 2, borderRadius: '12px', bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}` }}>
<Typography sx={{ fontFamily: FONT_SANS, fontSize: '12px', fontWeight: 600, color: C.bright, mb: 1 }}>
Enabled Features
</Typography>

View file

@ -68,7 +68,7 @@ export default async function AdminUsersPage({ searchParams }: PageProps): Promi
width: 4,
height: 32,
borderRadius: '999px',
background: 'linear-gradient(180deg, #3b82f6 0%, #8b5cf6 100%)',
background: 'linear-gradient(180deg, var(--d3-accent-main) 0%, var(--d3-tag-purple) 100%)',
}}
/>
<Box>
@ -163,17 +163,17 @@ export default async function AdminUsersPage({ searchParams }: PageProps): Promi
height: 34,
borderRadius: '10px',
background: isProPlus
? 'linear-gradient(135deg, #a855f7 0%, #3b82f6 100%)'
? 'linear-gradient(135deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)'
: isPro
? 'linear-gradient(135deg, #10b981 0%, #3b82f6 100%)'
: 'linear-gradient(135deg, #64748b 0%, #475569 100%)',
? 'linear-gradient(135deg, var(--d3-status-success) 0%, var(--d3-accent-main) 100%)'
: 'linear-gradient(135deg, var(--d3-text-label) 0%, var(--d3-text-label) 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#ffffff',
color: 'var(--d3-text-inverse)',
fontWeight: 500,
fontSize: '13px',
boxShadow: isProPlus ? '0 0 12px rgba(168, 85, 247, 0.4)' : 'none',
boxShadow: isProPlus ? '0 0 12px var(--d3-tag-purple)' : 'none',
}}
>
{u.name.charAt(0)}
@ -238,7 +238,7 @@ export default async function AdminUsersPage({ searchParams }: PageProps): Promi
borderRadius: '8px',
textTransform: 'none',
px: 1.5,
'&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight },
'&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight },
}}
>
Manage →