diff --git a/frontend/src/app/components/Layout/UpdateReadyPill.tsx b/frontend/src/app/components/Layout/UpdateReadyPill.tsx
index a9ad459f..8466b3d3 100644
--- a/frontend/src/app/components/Layout/UpdateReadyPill.tsx
+++ b/frontend/src/app/components/Layout/UpdateReadyPill.tsx
@@ -4,19 +4,19 @@ import Grow from '@mui/material/Grow';
import Typography from '@mui/material/Typography';
import CircularProgress from '@mui/material/CircularProgress';
import RestartAltIcon from '@mui/icons-material/RestartAlt';
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import CloseIcon from '@mui/icons-material/Close';
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
import { setInstalling } from '@/shared/state/updateSlice';
-import { useClaudeTokens, useThemeMode } from '@/shared/styles/ThemeContext';
+import { useClaudeTokens } from '@/shared/styles/ThemeContext';
const UPDATE_DISMISS_KEY = 'openswarm-update-dismissed';
-// Chrome/Claude-style: the download already ran silently (autoDownload in main.js), so the only
-// state worth pixels is "ready". One pill, top-right, above the frameless-window drag strip that
-// used to swallow the old banner button's clicks.
+// Claude-desktop-style quiet card, not a colored capsule: the download already ran silently
+// (autoDownload in main.js), so the only state worth pixels is "ready". Top-right, above the
+// frameless-window drag strip that used to swallow the old banner button's clicks.
const UpdateReadyPill: React.FC = () => {
const c = useClaudeTokens();
- const { mode } = useThemeMode();
const dispatch = useAppDispatch();
const updateStatus = useAppSelector((s) => s.update.status);
const availableVersion = useAppSelector((s) => s.update.availableVersion);
@@ -54,7 +54,6 @@ const UpdateReadyPill: React.FC = () => {
onClick={handleInstall}
role="button"
aria-label={availableVersion ? `Restart to update to ${availableVersion}` : 'Restart to update'}
- title={availableVersion ? `OpenSwarm ${availableVersion} downloaded` : 'Update downloaded'}
sx={{
position: 'fixed',
top: 34,
@@ -64,44 +63,79 @@ const UpdateReadyPill: React.FC = () => {
WebkitAppRegion: 'no-drag',
display: 'flex',
alignItems: 'center',
- gap: 0.75,
- height: 30,
+ gap: 1.25,
pl: 1.25,
- pr: 1,
- borderRadius: 999,
- // Success green, NOT the accent: every other pill on the shell is accent-colored, and an update call-to-action that matches New-dashboard reads as furniture (Chrome's update pill is green for the same reason). Dark mode's lighter green needs dark text.
- bgcolor: c.status.success,
- color: mode === 'dark' ? 'rgba(0,0,0,0.85)' : '#fff',
- boxShadow: `0 0 0 3px ${c.status.success}40, 0 8px 24px rgba(0,0,0,0.35)`,
+ pr: 1.5,
+ py: 1,
+ borderRadius: '12px',
+ bgcolor: c.bg.surface,
+ border: `1px solid ${hovered ? c.border.strong : c.border.medium}`,
+ boxShadow: hovered ? c.shadow.lg : c.shadow.md,
cursor: installing ? 'default' : 'pointer',
userSelect: 'none',
- transition: 'filter 0.2s ease, transform 0.15s ease',
- '&:hover': { filter: installing ? 'none' : 'brightness(1.12)' },
- '&:active': { transform: installing ? 'none' : 'scale(0.97)' },
+ transition: 'box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease',
+ transform: hovered && !installing ? 'translateY(-1px)' : 'none',
}}
>
+
+
+
+
+
+ {installing ? 'Restarting…' : 'Restart to update'}
+
+
+ {availableVersion ? `v${availableVersion} ready` : 'New version ready'}
+
+
{installing
- ?
- : }
-
- {installing ? 'Restarting…' : 'Restart to update'}
-
+ ?
+ : (
+
+ )}
{!installing && (