Explorar el Código

fix(ui): resolve light-theme low-contrast semantic text app-wide (#1909)

    The app was built dark-first, so hundreds of hardcoded Tailwind semantic
    text/icon utilities at light shades (text-amber-400, text-blue-300, ...) had
    no dark: variant. With darkMode:'class' they applied in light theme too,
    producing washed-out text on pale tints and white cards — including the three
    reported spots (AMS Drying banner, Archives no-3MF warning, debug-logging
    banner). Give each a theme-aware pair: a darker readable shade in light theme
    with the original pinned to dark:, so dark theme is unchanged. ~100 files.

    The bambu-* CSS-variable palette (self-correcting) and the dark-only SpoolBuddy
    kiosk are left untouched. Plain text-white is already theme-aware via the
    existing index.css .text-white override, so it needed no changes.
maziggy hace 2 meses
padre
commit
56185d2bac
Se han modificado 100 ficheros con 774 adiciones y 774 borrados
  1. 2 2
      frontend/src/components/AMSHistoryModal.tsx
  2. 13 13
      frontend/src/components/APIBrowser.tsx
  3. 2 2
      frontend/src/components/AddExternalLinkModal.tsx
  4. 2 2
      frontend/src/components/AddNotificationModal.tsx
  5. 7 7
      frontend/src/components/AddSmartPlugModal.tsx
  6. 1 1
      frontend/src/components/AlertModal.tsx
  7. 1 1
      frontend/src/components/ApiKeyQRCodeModal.tsx
  8. 1 1
      frontend/src/components/AssignSpoolModal.tsx
  9. 3 3
      frontend/src/components/BackupModal.tsx
  10. 1 1
      frontend/src/components/BatchProjectModal.tsx
  11. 1 1
      frontend/src/components/BatchTagModal.tsx
  12. 1 1
      frontend/src/components/BulkEditSpoolsModal.tsx
  13. 3 3
      frontend/src/components/CalendarView.tsx
  14. 3 3
      frontend/src/components/CameraDiagnoseModal.tsx
  15. 2 2
      frontend/src/components/ColorCatalogSettings.tsx
  16. 4 4
      frontend/src/components/CompactHistoryRow.tsx
  17. 7 7
      frontend/src/components/CompareArchivesModal.tsx
  18. 12 12
      frontend/src/components/ConfigureAmsSlotModal.tsx
  19. 2 2
      frontend/src/components/ConfirmModal.tsx
  20. 5 5
      frontend/src/components/ConnectionDiagnostic.tsx
  21. 2 2
      frontend/src/components/ContextMenu.tsx
  22. 3 3
      frontend/src/components/CreateUserAdvancedAuthModal.tsx
  23. 6 6
      frontend/src/components/EmailSettings.tsx
  24. 1 1
      frontend/src/components/EmbeddedCameraViewer.tsx
  25. 1 1
      frontend/src/components/ExternalLinksSettings.tsx
  26. 9 9
      frontend/src/components/FailureDetectionSettings.tsx
  27. 2 2
      frontend/src/components/FilamentHoverCard.tsx
  28. 1 1
      frontend/src/components/FileManagerModal.tsx
  29. 15 15
      frontend/src/components/FileUploadModal.tsx
  30. 1 1
      frontend/src/components/FolderReadmePanel.tsx
  31. 25 25
      frontend/src/components/ForecastPanel.tsx
  32. 26 26
      frontend/src/components/GitHubBackupSettings.tsx
  33. 5 5
      frontend/src/components/HMSErrorModal.tsx
  34. 3 3
      frontend/src/components/HeaterHistoryModal.tsx
  35. 6 6
      frontend/src/components/LDAPSettings.tsx
  36. 9 9
      frontend/src/components/Layout.tsx
  37. 3 3
      frontend/src/components/LdapUserPicker.tsx
  38. 1 1
      frontend/src/components/LibraryTagsModal.tsx
  39. 5 5
      frontend/src/components/LocalProfilesView.tsx
  40. 1 1
      frontend/src/components/LocationsModal.tsx
  41. 1 1
      frontend/src/components/LogViewer.tsx
  42. 12 12
      frontend/src/components/NotificationLogViewer.tsx
  43. 24 24
      frontend/src/components/NotificationProviderCard.tsx
  44. 2 2
      frontend/src/components/NotificationTemplateEditor.tsx
  45. 10 10
      frontend/src/components/OIDCProviderSettings.tsx
  46. 3 3
      frontend/src/components/OrcaCloudProfilesView.tsx
  47. 4 4
      frontend/src/components/OrcaCloudView.tsx
  48. 1 1
      frontend/src/components/PendingUploadsPanel.tsx
  49. 1 1
      frontend/src/components/PrintLogTable.tsx
  50. 7 7
      frontend/src/components/PrintModal/FilamentMapping.tsx
  51. 1 1
      frontend/src/components/PrintModal/FilamentOverride.tsx
  52. 1 1
      frontend/src/components/PrintModal/PlateSelector.tsx
  53. 1 1
      frontend/src/components/PrintModal/PrintOptions.tsx
  54. 11 11
      frontend/src/components/PrintModal/PrinterSelector.tsx
  55. 1 1
      frontend/src/components/PrintModal/ScheduleOptions.tsx
  56. 7 7
      frontend/src/components/PrintModal/index.tsx
  57. 1 1
      frontend/src/components/PrinterInfoModal.tsx
  58. 2 2
      frontend/src/components/PrinterQueueWidget.tsx
  59. 1 1
      frontend/src/components/ProjectPageModal.tsx
  60. 3 3
      frontend/src/components/QueueStatsBar.tsx
  61. 2 2
      frontend/src/components/QueueTimelineView.tsx
  62. 3 3
      frontend/src/components/RestoreModal.tsx
  63. 2 2
      frontend/src/components/RunWithPipelineModal.tsx
  64. 12 12
      frontend/src/components/SecurityStatusCard.tsx
  65. 2 2
      frontend/src/components/SkipObjectsModal.tsx
  66. 3 3
      frontend/src/components/SliceModal.tsx
  67. 10 10
      frontend/src/components/SlicerPipelinesPanel.tsx
  68. 13 13
      frontend/src/components/SmartPlugCard.tsx
  69. 2 2
      frontend/src/components/SpoolCatalogSettings.tsx
  70. 9 9
      frontend/src/components/SpoolCsvImportModal.tsx
  71. 2 2
      frontend/src/components/SpoolFormModal.tsx
  72. 3 3
      frontend/src/components/SpoolUsageHistory.tsx
  73. 17 17
      frontend/src/components/SpoolmanSettings.tsx
  74. 6 6
      frontend/src/components/SwitchbarPopover.tsx
  75. 4 4
      frontend/src/components/SystemHealthPanel.tsx
  76. 2 2
      frontend/src/components/TagManagementModal.tsx
  77. 2 2
      frontend/src/components/TimelapseEditorModal.tsx
  78. 9 9
      frontend/src/components/TwoFactorSettings.tsx
  79. 4 4
      frontend/src/components/UploadModal.tsx
  80. 9 9
      frontend/src/components/VirtualPrinterCard.tsx
  81. 5 5
      frontend/src/components/VirtualPrinterDiagnosticModal.tsx
  82. 2 2
      frontend/src/components/VirtualPrinterList.tsx
  83. 10 10
      frontend/src/components/VirtualPrinterSettings.tsx
  84. 1 1
      frontend/src/components/spool-form/ColorSection.tsx
  85. 4 4
      frontend/src/components/spool-form/FilamentSection.tsx
  86. 26 26
      frontend/src/pages/ArchivesPage.tsx
  87. 5 5
      frontend/src/pages/CameraTokensPage.tsx
  88. 16 16
      frontend/src/pages/FileManagerPage.tsx
  89. 1 1
      frontend/src/pages/GroupEditPage.tsx
  90. 23 23
      frontend/src/pages/InventoryPage.tsx
  91. 1 1
      frontend/src/pages/LoginPage.tsx
  92. 15 15
      frontend/src/pages/MaintenancePage.tsx
  93. 5 5
      frontend/src/pages/NotificationsPage.tsx
  94. 6 6
      frontend/src/pages/PipelineRunsPage.tsx
  95. 84 84
      frontend/src/pages/PrintersPage.tsx
  96. 25 25
      frontend/src/pages/ProfilesPage.tsx
  97. 15 15
      frontend/src/pages/ProjectDetailPage.tsx
  98. 9 9
      frontend/src/pages/ProjectsPage.tsx
  99. 38 38
      frontend/src/pages/QueuePage.tsx
  100. 75 75
      frontend/src/pages/SettingsPage.tsx

+ 2 - 2
frontend/src/components/AMSHistoryModal.tsx

@@ -136,8 +136,8 @@ export function AMSHistoryModal({
   const tempTrend = getTrend(chartData.map(d => d.temperature));
 
   const TrendIcon = ({ trend }: { trend: string }) => {
-    if (trend === 'up') return <TrendingUp className="w-4 h-4 text-red-400" />;
-    if (trend === 'down') return <TrendingDown className="w-4 h-4 text-green-400" />;
+    if (trend === 'up') return <TrendingUp className="w-4 h-4 text-red-600 dark:text-red-400" />;
+    if (trend === 'down') return <TrendingDown className="w-4 h-4 text-green-600 dark:text-green-400" />;
     return <Minus className="w-4 h-4 text-gray-400 dark:text-bambu-gray" />;
   };
 

+ 13 - 13
frontend/src/components/APIBrowser.tsx

@@ -70,11 +70,11 @@ interface APIResponse {
 }
 
 const METHOD_COLORS: Record<string, string> = {
-  get: 'bg-blue-500/20 text-blue-400 border-blue-500/30',
-  post: 'bg-green-500/20 text-green-400 border-green-500/30',
-  put: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30',
-  patch: 'bg-orange-500/20 text-orange-400 border-orange-500/30',
-  delete: 'bg-red-500/20 text-red-400 border-red-500/30',
+  get: 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 border-blue-300 dark:border-blue-500/30',
+  post: 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 border-green-300 dark:border-green-500/30',
+  put: 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 border-yellow-300 dark:border-yellow-500/30',
+  patch: 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 border-orange-300 dark:border-orange-500/30',
+  delete: 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 border-red-300 dark:border-red-500/30',
 };
 
 function resolveRef(schema: OpenAPISchema, ref: string): SchemaSpec {
@@ -340,7 +340,7 @@ function EndpointItem({ path, method, spec, schema, apiKey }: EndpointItemProps)
                   <div key={param.name} className="flex items-center gap-2">
                     <label className="text-sm text-bambu-gray w-32 flex-shrink-0">
                       {param.name}
-                      {param.required && <span className="text-red-400 ml-1">*</span>}
+                      {param.required && <span className="text-red-700 dark:text-red-400 ml-1">*</span>}
                     </label>
                     <input
                       type="text"
@@ -364,7 +364,7 @@ function EndpointItem({ path, method, spec, schema, apiKey }: EndpointItemProps)
                   <div key={param.name} className="flex items-center gap-2">
                     <label className="text-sm text-bambu-gray w-32 flex-shrink-0">
                       {param.name}
-                      {param.required && <span className="text-red-400 ml-1">*</span>}
+                      {param.required && <span className="text-red-700 dark:text-red-400 ml-1">*</span>}
                     </label>
                     {param.schema?.enum ? (
                       <select
@@ -417,7 +417,7 @@ function EndpointItem({ path, method, spec, schema, apiKey }: EndpointItemProps)
               Execute
             </Button>
             {missingParams.length > 0 && (
-              <span className="text-xs text-yellow-400 flex items-center gap-1">
+              <span className="text-xs text-yellow-700 dark:text-yellow-400 flex items-center gap-1">
                 <AlertCircle className="w-3 h-3" />
                 Fill in: {missingParams.join(', ')}
               </span>
@@ -432,10 +432,10 @@ function EndpointItem({ path, method, spec, schema, apiKey }: EndpointItemProps)
                   Response
                   <span className={`px-2 py-0.5 text-xs rounded ${
                     response.status >= 200 && response.status < 300
-                      ? 'bg-green-500/20 text-green-400'
+                      ? 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400'
                       : response.status >= 400
-                        ? 'bg-red-500/20 text-red-400'
-                        : 'bg-yellow-500/20 text-yellow-400'
+                        ? 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400'
+                        : 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400'
                   }`}>
                     {response.status} {response.statusText}
                   </span>
@@ -443,7 +443,7 @@ function EndpointItem({ path, method, spec, schema, apiKey }: EndpointItemProps)
                 </h4>
                 <Button variant="secondary" size="sm" onClick={copyResponse}>
                   {copied ? (
-                    <CheckCircle className="w-3 h-3 text-green-400" />
+                    <CheckCircle className="w-3 h-3 text-green-600 dark:text-green-400" />
                   ) : (
                     <Copy className="w-3 h-3" />
                   )}
@@ -501,7 +501,7 @@ export function APIBrowser({ apiKey = '' }: APIBrowserProps) {
     return (
       <Card>
         <CardContent className="py-8">
-          <div className="text-center text-red-400">
+          <div className="text-center text-red-700 dark:text-red-400">
             <AlertCircle className="w-12 h-12 mx-auto mb-3 opacity-50" />
             <p>Failed to load API schema</p>
             <p className="text-sm text-bambu-gray mt-1">{error}</p>

+ 2 - 2
frontend/src/components/AddExternalLinkModal.tsx

@@ -187,7 +187,7 @@ export function AddExternalLinkModal({ link, onClose }: AddExternalLinkModalProp
         {/* Form */}
         <form onSubmit={handleSubmit} className="p-6 space-y-4">
           {error && (
-            <div className="p-3 bg-red-500/20 border border-red-500/50 rounded-lg text-sm text-red-400">
+            <div className="p-3 bg-red-100 dark:bg-red-500/20 border border-red-300 dark:border-red-500/50 rounded-lg text-sm text-red-700 dark:text-red-400">
               {error}
             </div>
           )}
@@ -256,7 +256,7 @@ export function AddExternalLinkModal({ link, onClose }: AddExternalLinkModalProp
                     <button
                       type="button"
                       onClick={handleRemoveCustomIcon}
-                      className="p-1 text-red-400 hover:text-red-300 transition-colors"
+                      className="p-1 text-red-700 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 transition-colors"
                       title="Remove custom icon"
                     >
                       <Trash2 className="w-4 h-4" />

+ 2 - 2
frontend/src/components/AddNotificationModal.tsx

@@ -284,7 +284,7 @@ export function AddNotificationModal({ provider, onClose }: AddNotificationModal
         {/* Form */}
         <form onSubmit={handleSubmit} className="p-6 space-y-4">
           {error && (
-            <div className="p-3 bg-red-500/20 border border-red-500/50 rounded-lg text-sm text-red-400">
+            <div className="p-3 bg-red-100 dark:bg-red-500/20 border border-red-300 dark:border-red-500/50 rounded-lg text-sm text-red-700 dark:text-red-400">
               {error}
             </div>
           )}
@@ -392,7 +392,7 @@ export function AddNotificationModal({ provider, onClose }: AddNotificationModal
             <div className={`p-3 rounded-lg flex items-center gap-2 ${
               testResult.success
                 ? 'bg-bambu-green/20 border border-bambu-green/50 text-bambu-green'
-                : 'bg-red-500/20 border border-red-500/50 text-red-400'
+                : 'bg-red-100 dark:bg-red-500/20 border border-red-300 dark:border-red-500/50 text-red-700 dark:text-red-400'
             }`}>
               {testResult.success ? (
                 <>

+ 7 - 7
frontend/src/components/AddSmartPlugModal.tsx

@@ -431,7 +431,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
         {/* Form */}
         <form onSubmit={handleSubmit} className="p-6 space-y-4 overflow-y-auto">
           {error && (
-            <div className="p-3 bg-red-500/20 border border-red-500/50 rounded-lg text-sm text-red-400">
+            <div className="p-3 bg-red-100 dark:bg-red-500/20 border border-red-400 dark:border-red-500/50 rounded-lg text-sm text-red-700 dark:text-red-400">
               {error}
             </div>
           )}
@@ -585,7 +585,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
               {/* HA not configured */}
               {!haConfigured && (
                 <div className="space-y-3">
-                  <div className="p-3 bg-yellow-500/20 border border-yellow-500/50 rounded-lg text-sm text-yellow-400">
+                  <div className="p-3 bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-400 dark:border-yellow-500/50 rounded-lg text-sm text-yellow-700 dark:text-yellow-400">
                     {t('smartPlugs.haNotConfigured')}{' '}
                     <span className="font-medium">{t('smartPlugs.haSettingsPath')}</span>
                   </div>
@@ -612,7 +612,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
                   )}
 
                   {haEntitiesError && (
-                    <div className="p-3 bg-red-500/20 border border-red-500/50 rounded-lg text-sm text-red-400">
+                    <div className="p-3 bg-red-100 dark:bg-red-500/20 border border-red-400 dark:border-red-500/50 rounded-lg text-sm text-red-700 dark:text-red-400">
                       {t('smartPlugs.failedToLoadEntities', { error: (haEntitiesError as Error).message })}
                     </div>
                   )}
@@ -988,7 +988,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
             <div className="space-y-3">
               {/* MQTT broker not configured */}
               {!settings?.mqtt_broker && (
-                <div className="p-3 bg-yellow-500/20 border border-yellow-500/50 rounded-lg text-sm text-yellow-400">
+                <div className="p-3 bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-400 dark:border-yellow-500/50 rounded-lg text-sm text-yellow-700 dark:text-yellow-400">
                   {t('smartPlugs.mqttNotConfigured')}{' '}
                   <span className="font-medium">{t('smartPlugs.mqttSettingsPath')}</span>
                   {' '}{t('smartPlugs.mqttNotConfiguredSuffix')}
@@ -998,7 +998,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
               {/* MQTT broker configured - show fields */}
               {settings?.mqtt_broker && (
                 <>
-                  <div className="p-3 bg-blue-500/10 border border-blue-500/30 rounded-lg text-sm text-blue-300">
+                  <div className="p-3 bg-blue-50 dark:bg-blue-500/10 border border-blue-300 dark:border-blue-500/30 rounded-lg text-sm text-blue-700 dark:text-blue-300">
                     <p className="font-medium mb-1">{t('smartPlugs.monitorOnly')}</p>
                     <p className="text-xs opacity-80">
                       {t('smartPlugs.mqttMonitorOnlyDescription')}
@@ -1346,7 +1346,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
                 </div>
               )}
               {testResult && (
-                <div className={`flex items-center gap-2 text-sm ${testResult.success ? 'text-green-400' : 'text-red-400'}`}>
+                <div className={`flex items-center gap-2 text-sm ${testResult.success ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'}`}>
                   {testResult.success ? <CheckCircle className="w-4 h-4" /> : <WifiOff className="w-4 h-4" />}
                   {testResult.success ? t('smartPlugs.connectionSuccess') : t('smartPlugs.addSmartPlug.connectionFailed')}
                 </div>
@@ -1391,7 +1391,7 @@ export function AddSmartPlugModal({ plug, onClose }: AddSmartPlugModalProps) {
             <div className={`p-3 rounded-lg flex items-center gap-2 ${
               testResult.success
                 ? 'bg-bambu-green/20 border border-bambu-green/50 text-bambu-green'
-                : 'bg-red-500/20 border border-red-500/50 text-red-400'
+                : 'bg-red-100 dark:bg-red-500/20 border border-red-400 dark:border-red-500/50 text-red-700 dark:text-red-400'
             }`}>
               {testResult.success ? (
                 <>

+ 1 - 1
frontend/src/components/AlertModal.tsx

@@ -42,7 +42,7 @@ export function AlertModal({
     return () => window.removeEventListener('keydown', handleKeyDown);
   }, [onClose]);
 
-  const iconColor = variant === 'warning' ? 'text-yellow-400' : 'text-red-400';
+  const iconColor = variant === 'warning' ? 'text-yellow-600 dark:text-yellow-400' : 'text-red-600 dark:text-red-400';
 
   return (
     <div

+ 1 - 1
frontend/src/components/ApiKeyQRCodeModal.tsx

@@ -56,7 +56,7 @@ export function ApiKeyQRCodeModal({ apiKey, baseUrl, onClose }: ApiKeyQRCodeModa
           <div className="bg-white p-4 rounded-lg mb-4">
             <QRCodeSVG value={payload} size={256} />
           </div>
-          <div className="flex items-start gap-2 text-xs text-amber-400 mb-4">
+          <div className="flex items-start gap-2 text-xs text-amber-700 dark:text-amber-400 mb-4">
             <AlertTriangle className="w-4 h-4 flex-shrink-0 mt-0.5" />
             <span>{t('settings.apiKeyQrWarning')}</span>
           </div>

+ 1 - 1
frontend/src/components/AssignSpoolModal.tsx

@@ -572,7 +572,7 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr
 
 
         {assignMutation.isError && (
-          <div className="mx-4 mb-4 p-2 bg-red-500/20 border border-red-500/50 rounded text-sm text-red-400">
+          <div className="mx-4 mb-4 p-2 bg-red-100 dark:bg-red-500/20 border border-red-300 dark:border-red-500/50 rounded text-sm text-red-700 dark:text-red-400">
             {(assignMutation.error as Error).message}
           </div>
         )}

+ 3 - 3
frontend/src/components/BackupModal.tsx

@@ -271,10 +271,10 @@ export function BackupModal({ onClose, onExport }: BackupModalProps) {
 
           {/* Archive warning */}
           {selected.archives && (
-            <div className="mx-4 mb-2 p-3 rounded-lg bg-yellow-500/10 border border-yellow-500/30">
+            <div className="mx-4 mb-2 p-3 rounded-lg bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30">
               <div className="flex items-start gap-2 text-sm">
                 <Archive className="w-4 h-4 text-yellow-500 mt-0.5 flex-shrink-0" />
-                <div className="text-yellow-200 dark:text-yellow-200 text-yellow-700">
+                <div className="text-yellow-700 dark:text-yellow-200">
                   <span className="font-medium">ZIP file will be created.</span>
                   <span className="text-yellow-600 dark:text-yellow-200/70"> Includes all 3MF files, thumbnails, timelapses, and photos. This may take a while and result in a large file.</span>
                 </div>
@@ -296,7 +296,7 @@ export function BackupModal({ onClose, onExport }: BackupModalProps) {
                 <Toggle checked={includeAccessCodes} onChange={setIncludeAccessCodes} />
               </div>
               {includeAccessCodes && (
-                <div className="mt-2 p-2 rounded bg-orange-500/10 border border-orange-500/30">
+                <div className="mt-2 p-2 rounded bg-orange-50 dark:bg-orange-500/10 border border-orange-300 dark:border-orange-500/30">
                   <div className="flex items-start gap-2 text-xs">
                     <AlertTriangle className="w-3 h-3 text-orange-500 dark:text-orange-400 mt-0.5 flex-shrink-0" />
                     <span className="text-orange-700 dark:text-orange-200">

+ 1 - 1
frontend/src/components/BatchProjectModal.tsx

@@ -129,7 +129,7 @@ export function BatchProjectModal({ selectedIds, onClose }: BatchProjectModalPro
                   className="w-full flex items-center gap-3 p-3 rounded-lg bg-bambu-dark hover:bg-bambu-dark-tertiary border border-bambu-dark-tertiary transition-colors text-left disabled:opacity-50"
                 >
                   <div className="w-8 h-8 rounded-full bg-red-500/20 flex items-center justify-center shrink-0">
-                    <XCircle className="w-4 h-4 text-red-400" />
+                    <XCircle className="w-4 h-4 text-red-600 dark:text-red-400" />
                   </div>
                   <div className="min-w-0 flex-1">
                     <p className="text-white font-medium">Remove from project</p>

+ 1 - 1
frontend/src/components/BatchTagModal.tsx

@@ -187,7 +187,7 @@ export function BatchTagModal({ selectedIds, existingTags, onClose }: BatchTagMo
                     <span
                       key={tag}
                       className={`px-2 py-1 rounded text-sm flex items-center gap-1 ${
-                        mode === 'add' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
+                        mode === 'add' ? 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400' : 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400'
                       }`}
                     >
                       {tag}

+ 1 - 1
frontend/src/components/BulkEditSpoolsModal.tsx

@@ -417,7 +417,7 @@ export function BulkEditSpoolsModal({
             />
           </div>
           {isInvalid && (
-            <p className="mt-1 text-xs text-red-400">{t('inventory.bulk.invalidHex')}</p>
+            <p className="mt-1 text-xs text-red-600 dark:text-red-400">{t('inventory.bulk.invalidHex')}</p>
           )}
         </div>
       );

+ 3 - 3
frontend/src/components/CalendarView.tsx

@@ -192,7 +192,7 @@ export function CalendarView({ archives, onArchiveClick, highlightedArchiveId }:
               <div className="text-xs text-bambu-gray">Prints this month</div>
             </div>
             <div>
-              <div className="text-2xl font-bold text-green-400">
+              <div className="text-2xl font-bold text-green-700 dark:text-green-400">
                 {archives.filter(a => {
                   const d = parseUTCDate(a.completed_at || a.created_at) || new Date();
                   return d.getMonth() === currentMonth && d.getFullYear() === currentYear && a.status === 'completed';
@@ -201,7 +201,7 @@ export function CalendarView({ archives, onArchiveClick, highlightedArchiveId }:
               <div className="text-xs text-bambu-gray">Successful</div>
             </div>
             <div>
-              <div className="text-2xl font-bold text-red-400">
+              <div className="text-2xl font-bold text-red-700 dark:text-red-400">
                 {archives.filter(a => {
                   const d = parseUTCDate(a.completed_at || a.created_at) || new Date();
                   return d.getMonth() === currentMonth && d.getFullYear() === currentYear && a.status === 'failed';
@@ -257,7 +257,7 @@ export function CalendarView({ archives, onArchiveClick, highlightedArchiveId }:
                         {archive.print_name || archive.filename}
                       </p>
                       <div className="flex items-center gap-2 text-xs">
-                        <span className={archive.status === 'failed' ? 'text-red-400' : 'text-green-400'}>
+                        <span className={archive.status === 'failed' ? 'text-red-700 dark:text-red-400' : 'text-green-700 dark:text-green-400'}>
                           {archive.status === 'failed' ? 'Failed' : 'Completed'}
                         </span>
                         {archive.filament_color && (

+ 3 - 3
frontend/src/components/CameraDiagnoseModal.tsx

@@ -12,7 +12,7 @@ interface CameraDiagnoseModalProps {
 
 function StageIcon({ status }: { status: CameraDiagnoseStage['status'] }) {
   if (status === 'ok') return <CheckCircle2 className="w-5 h-5 text-bambu-green flex-shrink-0" />;
-  if (status === 'failed') return <XCircle className="w-5 h-5 text-red-400 flex-shrink-0" />;
+  if (status === 'failed') return <XCircle className="w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0" />;
   return <MinusCircle className="w-5 h-5 text-bambu-gray flex-shrink-0" />;
 }
 
@@ -77,7 +77,7 @@ export function CameraDiagnoseModal({ printerId, printerName, onClose }: CameraD
           )}
 
           {diagnose.isError && (
-            <div className="rounded-lg bg-red-500/10 border border-red-500/30 px-4 py-3 text-sm text-red-300">
+            <div className="rounded-lg bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 px-4 py-3 text-sm text-red-700 dark:text-red-300">
               {t('camera.diagnose.runFailed', { error: (diagnose.error as Error).message })}
             </div>
           )}
@@ -112,7 +112,7 @@ export function CameraDiagnoseModal({ printerId, printerName, onClose }: CameraD
                 className={
                   result.overall_status === 'ok'
                     ? 'rounded-lg bg-bambu-green/10 border border-bambu-green/30 px-4 py-3 text-sm text-bambu-green'
-                    : 'rounded-lg bg-red-500/10 border border-red-500/30 px-4 py-3 text-sm text-red-300'
+                    : 'rounded-lg bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 px-4 py-3 text-sm text-red-700 dark:text-red-300'
                 }
               >
                 {t(`camera.diagnose.summary.${result.summary_code}`, {

+ 2 - 2
frontend/src/components/ColorCatalogSettings.tsx

@@ -381,8 +381,8 @@ export function ColorCatalogSettings() {
           </button>
         </div>
         {selectedIds.size > 0 && (
-          <div className="flex items-center gap-2 mt-2 px-3 py-2 bg-red-500/10 border border-red-500/30 rounded-lg">
-            <span className="text-sm text-red-400">
+          <div className="flex items-center gap-2 mt-2 px-3 py-2 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded-lg">
+            <span className="text-sm text-red-700 dark:text-red-400">
               {t('settings.colorCatalog.selectedCount', { count: selectedIds.size })}
             </span>
             <button

+ 4 - 4
frontend/src/components/CompactHistoryRow.tsx

@@ -18,9 +18,9 @@ import type { PrintQueueItem, Permission } from '../api/client';
 import { Button } from './Button';
 
 const STATUS_CONFIG = {
-  completed: { icon: CheckCircle, color: 'text-emerald-400', border: 'border-l-emerald-500' },
-  failed: { icon: XCircle, color: 'text-red-400', border: 'border-l-red-500' },
-  skipped: { icon: SkipForward, color: 'text-orange-400', border: 'border-l-gray-500' },
+  completed: { icon: CheckCircle, color: 'text-emerald-600 dark:text-emerald-400', border: 'border-l-emerald-500' },
+  failed: { icon: XCircle, color: 'text-red-600 dark:text-red-400', border: 'border-l-red-500' },
+  skipped: { icon: SkipForward, color: 'text-orange-600 dark:text-orange-400', border: 'border-l-gray-500' },
   cancelled: { icon: Ban, color: 'text-gray-400', border: 'border-l-gray-500' },
 } as const;
 
@@ -182,7 +182,7 @@ export function CompactHistoryRow({
 
       {/* Error message — only rendered on failed/skipped rows. */}
       {showErrorMessage && (
-        <div className="mt-1 ml-[3.25rem] flex items-start gap-1 text-xs text-red-400">
+        <div className="mt-1 ml-[3.25rem] flex items-start gap-1 text-xs text-red-700 dark:text-red-400">
           <AlertCircle className="w-3 h-3 mt-0.5 shrink-0" />
           <span className="break-words">{item.error_message}</span>
         </div>

+ 7 - 7
frontend/src/components/CompareArchivesModal.tsx

@@ -48,7 +48,7 @@ export function CompareArchivesModal({ archiveIds, onClose }: CompareArchivesMod
               <Loader2 className="w-8 h-8 text-bambu-green animate-spin" />
             </div>
           ) : error ? (
-            <div className="text-center py-12 text-red-400">
+            <div className="text-center py-12 text-red-700 dark:text-red-400">
               <AlertTriangle className="w-12 h-12 mx-auto mb-4 opacity-50" />
               <p>Failed to load comparison</p>
               <p className="text-sm text-bambu-gray mt-2">
@@ -109,9 +109,9 @@ function ComparisonContent({ comparison }: { comparison: ArchiveComparison }) {
                 <td className="py-2 pr-4 text-sm">
                   <div className="flex items-center gap-2">
                     {field.has_difference && (
-                      <AlertTriangle className="w-3 h-3 text-yellow-400 flex-shrink-0" />
+                      <AlertTriangle className="w-3 h-3 text-yellow-600 dark:text-yellow-400 flex-shrink-0" />
                     )}
-                    <span className={field.has_difference ? 'text-yellow-400' : 'text-bambu-gray'}>
+                    <span className={field.has_difference ? 'text-yellow-700 dark:text-yellow-400' : 'text-bambu-gray'}>
                       {field.label}
                     </span>
                   </div>
@@ -132,15 +132,15 @@ function ComparisonContent({ comparison }: { comparison: ArchiveComparison }) {
 
       {/* Differences Summary */}
       {comparison.differences.length > 0 && (
-        <div className="p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg">
-          <h4 className="text-sm font-medium text-yellow-400 mb-2 flex items-center gap-2">
+        <div className="p-4 bg-yellow-50 border border-yellow-300 dark:bg-yellow-500/10 dark:border-yellow-500/30 rounded-lg">
+          <h4 className="text-sm font-medium text-yellow-700 dark:text-yellow-400 mb-2 flex items-center gap-2">
             <AlertTriangle className="w-4 h-4" />
             {comparison.differences.length} Difference{comparison.differences.length > 1 ? 's' : ''} Found
           </h4>
           <ul className="text-sm text-white/80 space-y-1">
             {comparison.differences.slice(0, 5).map((diff) => (
               <li key={diff.field}>
-                <span className="text-yellow-400">{diff.label}</span>: {diff.values.join(' vs ')} {diff.unit || ''}
+                <span className="text-yellow-700 dark:text-yellow-400">{diff.label}</span>: {diff.values.join(' vs ')} {diff.unit || ''}
               </li>
             ))}
             {comparison.differences.length > 5 && (
@@ -163,7 +163,7 @@ function ComparisonContent({ comparison }: { comparison: ArchiveComparison }) {
             <span className="text-bambu-green">
               {comparison.success_correlation.successful_count} successful
             </span>
-            <span className="text-red-400">
+            <span className="text-red-700 dark:text-red-400">
               {comparison.success_correlation.failed_count} failed
             </span>
           </div>

+ 12 - 12
frontend/src/components/ConfigureAmsSlotModal.tsx

@@ -1163,7 +1163,7 @@ export function ConfigureAmsSlotModal({
               {/* Left column: Filament preset list (takes full height) */}
               <div className="w-1/2 flex flex-col min-h-0">
                 <label className="block text-sm text-bambu-gray mb-2">
-                  {t('configureAmsSlot.filamentProfile')} <span className="text-red-400">*</span>
+                  {t('configureAmsSlot.filamentProfile')} <span className="text-red-600 dark:text-red-400">*</span>
                 </label>
                 <input
                   type="text"
@@ -1195,12 +1195,12 @@ export function ConfigureAmsSlotModal({
                           <span className="text-white text-sm truncate group-hover:whitespace-normal group-hover:break-all" title={preset.name}>{preset.name}</span>
                           <div className="flex items-center gap-1 flex-shrink-0">
                             {preset.source === 'local' && (
-                              <span className="text-xs px-1.5 py-0.5 rounded bg-green-500/20 text-green-400">
+                              <span className="text-xs px-1.5 py-0.5 rounded bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400">
                                 {t('profiles.localProfiles.badge')}
                               </span>
                             )}
                             {preset.source === 'orca_cloud' && (
-                              <span className="text-xs px-1.5 py-0.5 rounded bg-purple-500/20 text-purple-400">
+                              <span className="text-xs px-1.5 py-0.5 rounded bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400">
                                 {t('configureAmsSlot.orcaCloud')}
                               </span>
                             )}
@@ -1210,7 +1210,7 @@ export function ConfigureAmsSlotModal({
                               </span>
                             )}
                             {preset.source === 'builtin' && (
-                              <span className="text-xs px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-400">
+                              <span className="text-xs px-1.5 py-0.5 rounded bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400">
                                 {t('configureAmsSlot.builtin')}
                               </span>
                             )}
@@ -1258,7 +1258,7 @@ export function ConfigureAmsSlotModal({
                       {t('configureAmsSlot.noMatchingKProfiles')}
                     </p>
                   ) : (
-                    <span className="inline-block text-xs px-2 py-1 rounded bg-amber-500/20 text-amber-400 border border-amber-500/30">
+                    <span className="inline-block text-xs px-2 py-1 rounded bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 border border-amber-300 dark:border-amber-500/30">
                       {t('configureAmsSlot.selectFilamentFirst')}
                     </span>
                   )}
@@ -1402,7 +1402,7 @@ export function ConfigureAmsSlotModal({
               {/* Filament Profile Select */}
               <div>
                 <label className="block text-sm text-bambu-gray mb-2">
-                  {t('configureAmsSlot.filamentProfile')} <span className="text-red-400">*</span>
+                  {t('configureAmsSlot.filamentProfile')} <span className="text-red-600 dark:text-red-400">*</span>
                 </label>
                 <div className="relative">
                   <input
@@ -1435,12 +1435,12 @@ export function ConfigureAmsSlotModal({
                             <span className="text-white text-sm truncate group-hover:whitespace-normal group-hover:break-all" title={preset.name}>{preset.name}</span>
                             <div className="flex items-center gap-1 flex-shrink-0">
                               {preset.source === 'local' && (
-                                <span className="text-xs px-1.5 py-0.5 rounded bg-green-500/20 text-green-400">
+                                <span className="text-xs px-1.5 py-0.5 rounded bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400">
                                   {t('profiles.localProfiles.badge')}
                                 </span>
                               )}
                               {preset.source === 'orca_cloud' && (
-                                <span className="text-xs px-1.5 py-0.5 rounded bg-purple-500/20 text-purple-400">
+                                <span className="text-xs px-1.5 py-0.5 rounded bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400">
                                   {t('configureAmsSlot.orcaCloud')}
                                 </span>
                               )}
@@ -1450,7 +1450,7 @@ export function ConfigureAmsSlotModal({
                                 </span>
                               )}
                               {preset.source === 'builtin' && (
-                                <span className="text-xs px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-400">
+                                <span className="text-xs px-1.5 py-0.5 rounded bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400">
                                   {t('configureAmsSlot.builtin')}
                                 </span>
                               )}
@@ -1497,7 +1497,7 @@ export function ConfigureAmsSlotModal({
                     {t('configureAmsSlot.noMatchingKProfiles')}
                   </p>
                 ) : (
-                  <span className="inline-block text-xs px-2 py-1 rounded bg-amber-500/20 text-amber-400 border border-amber-500/30">
+                  <span className="inline-block text-xs px-2 py-1 rounded bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 border border-amber-300 dark:border-amber-500/30">
                     {t('configureAmsSlot.selectFilamentFirst')}
                   </span>
                 )}
@@ -1653,7 +1653,7 @@ export function ConfigureAmsSlotModal({
             variant="secondary"
             onClick={() => resetMutation.mutate()}
             disabled={resetMutation.isPending || configureMutation.isPending}
-            className="text-red-400 hover:text-red-300 hover:bg-red-500/10"
+            className="text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 hover:bg-red-50 dark:hover:bg-red-500/10"
           >
             {resetMutation.isPending ? (
               <>
@@ -1693,7 +1693,7 @@ export function ConfigureAmsSlotModal({
 
         {/* Error */}
         {(configureMutation.isError || resetMutation.isError) && (
-          <div className="mx-4 mb-4 p-2 bg-red-500/20 border border-red-500/50 rounded text-sm text-red-400">
+          <div className="mx-4 mb-4 p-2 bg-red-100 dark:bg-red-500/20 border border-red-300 dark:border-red-500/50 rounded text-sm text-red-700 dark:text-red-400">
             {(configureMutation.error as Error)?.message || (resetMutation.error as Error)?.message}
           </div>
         )}

+ 2 - 2
frontend/src/components/ConfirmModal.tsx

@@ -63,11 +63,11 @@ export function ConfirmModal({
 
   const variantStyles = {
     danger: {
-      icon: 'text-red-400',
+      icon: 'text-red-600 dark:text-red-400',
       button: 'bg-red-500 hover:bg-red-600',
     },
     warning: {
-      icon: 'text-yellow-400',
+      icon: 'text-yellow-600 dark:text-yellow-400',
       button: 'bg-yellow-500 hover:bg-yellow-600 text-black',
     },
     default: {

+ 5 - 5
frontend/src/components/ConnectionDiagnostic.tsx

@@ -19,8 +19,8 @@ import {
 
 function StatusIcon({ status }: { status: DiagnosticStatus }) {
   if (status === 'pass') return <CheckCircle2 className="w-5 h-5 text-bambu-green flex-shrink-0" />;
-  if (status === 'fail') return <XCircle className="w-5 h-5 text-red-400 flex-shrink-0" />;
-  if (status === 'warn') return <AlertTriangle className="w-5 h-5 text-amber-400 flex-shrink-0" />;
+  if (status === 'fail') return <XCircle className="w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0" />;
+  if (status === 'warn') return <AlertTriangle className="w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0" />;
   return <MinusCircle className="w-5 h-5 text-bambu-gray flex-shrink-0" />;
 }
 
@@ -36,8 +36,8 @@ export function DiagnosticChecklist({ result }: { result: PrinterDiagnosticResul
     result.overall === 'ok'
       ? 'bg-bambu-green/10 border-bambu-green/30 text-bambu-green'
       : result.overall === 'warnings'
-        ? 'bg-amber-500/10 border-amber-500/30 text-amber-300'
-        : 'bg-red-500/10 border-red-500/30 text-red-300';
+        ? 'bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-300'
+        : 'bg-red-50 dark:bg-red-500/10 border-red-300 dark:border-red-500/30 text-red-700 dark:text-red-300';
 
   const renderCheck = (check: DiagnosticCheck) => {
     const params =
@@ -189,7 +189,7 @@ export function ConnectionDiagnosticModal(props: ConnectionDiagnosticModalProps)
           )}
 
           {diagnose.isError && (
-            <div className="rounded-lg bg-red-500/10 border border-red-500/30 px-4 py-3 text-sm text-red-300">
+            <div className="rounded-lg bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 px-4 py-3 text-sm text-red-700 dark:text-red-300">
               {t('diagnostic.runFailed', { error: (diagnose.error as Error).message })}
             </div>
           )}

+ 2 - 2
frontend/src/components/ContextMenu.tsx

@@ -99,7 +99,7 @@ function SubmenuPanel({
             subItem.disabled
               ? 'text-bambu-gray cursor-not-allowed'
               : subItem.danger
-              ? 'text-red-400 hover:bg-red-400/10'
+              ? 'text-red-700 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-400/10'
               : 'text-white hover:bg-bambu-dark-tertiary'
           }`}
         >
@@ -269,7 +269,7 @@ export function ContextMenu({ x, y, items, onClose }: ContextMenuProps) {
                 item.disabled
                   ? 'text-bambu-gray cursor-not-allowed'
                   : item.danger
-                  ? 'text-red-400 hover:bg-red-400/10'
+                  ? 'text-red-700 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-400/10'
                   : 'text-white hover:bg-bambu-dark-tertiary'
               } ${hasSubmenu && activeSubmenu === index ? 'bg-bambu-dark-tertiary' : ''}`}
             >

+ 3 - 3
frontend/src/components/CreateUserAdvancedAuthModal.tsx

@@ -137,7 +137,7 @@ export function CreateUserAdvancedAuthModal({
             {/* Username Field */}
             <div>
               <label className="block text-sm font-medium text-white mb-2">
-                {t('users.form.username')} <span className="text-red-400">*</span>
+                {t('users.form.username')} <span className="text-red-600 dark:text-red-400">*</span>
               </label>
               <input
                 type="text"
@@ -153,7 +153,7 @@ export function CreateUserAdvancedAuthModal({
             {/* Email Field */}
             <div>
               <label className="block text-sm font-medium text-white mb-2">
-                {t('users.form.email') || 'Email'} <span className="text-red-400">*</span>
+                {t('users.form.email') || 'Email'} <span className="text-red-600 dark:text-red-400">*</span>
               </label>
               <input
                 type="email"
@@ -191,7 +191,7 @@ export function CreateUserAdvancedAuthModal({
                     />
                     <span className="text-sm text-white">{group.name}</span>
                     {group.is_system && (
-                      <span className="text-xs text-yellow-400">({t('users.system')})</span>
+                      <span className="text-xs text-yellow-700 dark:text-yellow-400">({t('users.system')})</span>
                     )}
                   </label>
                 ))}

+ 6 - 6
frontend/src/components/EmailSettings.tsx

@@ -207,14 +207,14 @@ export function EmailSettings() {
         <CardContent>
           <div className="space-y-3">
             {advancedEnabled ? (
-              <div className="bg-green-500/10 border border-green-500/30 rounded-lg p-4">
+              <div className="bg-green-50 dark:bg-green-500/10 border border-green-300 dark:border-green-500/30 rounded-lg p-4">
                 <div className="flex items-start gap-3">
-                  <CheckCircle className="w-5 h-5 text-green-400 mt-0.5 flex-shrink-0" />
+                  <CheckCircle className="w-5 h-5 text-green-600 dark:text-green-400 mt-0.5 flex-shrink-0" />
                   <div className="space-y-2">
                     <p className="text-white font-medium">
                       {t('settings.email.advancedAuthEnabled') || 'Advanced Authentication is enabled'}
                     </p>
-                    <ul className="text-sm text-green-300 space-y-1 list-disc list-inside">
+                    <ul className="text-sm text-green-700 dark:text-green-300 space-y-1 list-disc list-inside">
                       <li>{t('settings.email.feature1') || 'Passwords are auto-generated and emailed to new users'}</li>
                       <li>{t('settings.email.feature2') || 'Users can login with username or email'}</li>
                       <li>{t('settings.email.feature3') || 'Forgot password feature is available'}</li>
@@ -224,14 +224,14 @@ export function EmailSettings() {
                 </div>
               </div>
             ) : (
-              <div className="bg-yellow-500/10 border border-yellow-500/30 rounded-lg p-4">
+              <div className="bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30 rounded-lg p-4">
                 <div className="flex items-start gap-3">
-                  <AlertTriangle className="w-5 h-5 text-yellow-400 mt-0.5 flex-shrink-0" />
+                  <AlertTriangle className="w-5 h-5 text-yellow-600 dark:text-yellow-400 mt-0.5 flex-shrink-0" />
                   <div className="space-y-2">
                     <p className="text-white font-medium">
                       {t('settings.email.advancedAuthDisabled') || 'Advanced Authentication is disabled'}
                     </p>
-                    <p className="text-sm text-yellow-300">
+                    <p className="text-sm text-yellow-700 dark:text-yellow-300">
                       {t('settings.email.advancedAuthDisabledDesc') || 'Enable advanced authentication to activate email-based features for user management.'}
                     </p>
                   </div>

+ 1 - 1
frontend/src/components/EmbeddedCameraViewer.tsx

@@ -644,7 +644,7 @@ export function EmbeddedCameraViewer({ printerId, printerName, viewerIndex = 0,
             className="p-1 hover:bg-red-500/20 rounded"
             title="Close"
           >
-            <X className="w-3.5 h-3.5 text-bambu-gray hover:text-red-400" />
+            <X className="w-3.5 h-3.5 text-bambu-gray hover:text-red-600 dark:hover:text-red-400" />
           </button>
         </div>
       </div>

+ 1 - 1
frontend/src/components/ExternalLinksSettings.tsx

@@ -337,7 +337,7 @@ export function ExternalLinksSettings() {
                       <button
                         onClick={() => handleDelete(link)}
                         disabled={deleteMutation.isPending}
-                        className="p-2 rounded-lg hover:bg-red-500/20 text-bambu-gray hover:text-red-400 transition-colors disabled:opacity-50"
+                        className="p-2 rounded-lg hover:bg-red-100 dark:hover:bg-red-500/20 text-bambu-gray hover:text-red-900 dark:hover:text-red-400 transition-colors disabled:opacity-50"
                         title={t('externalLinks.deleteLink')}
                       >
                         <Trash2 className="w-4 h-4" />

+ 9 - 9
frontend/src/components/FailureDetectionSettings.tsx

@@ -163,7 +163,7 @@ export function FailureDetectionSettings() {
               {testResult && (
                 <div
                   className={`flex items-start gap-2 mt-2 text-sm ${
-                    testResult.ok ? 'text-green-400' : 'text-red-400'
+                    testResult.ok ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'
                   }`}
                 >
                   {testResult.ok ? <Check className="w-4 h-4 mt-0.5" /> : <X className="w-4 h-4 mt-0.5" />}
@@ -222,7 +222,7 @@ export function FailureDetectionSettings() {
             </div>
 
             {status && !status.external_url_configured && enabled && (
-              <div className="flex items-start gap-2 p-3 bg-amber-900/30 border border-amber-700 rounded text-sm text-amber-200">
+              <div className="flex items-start gap-2 p-3 bg-amber-50 dark:bg-amber-900/30 border border-amber-300 dark:border-amber-700 rounded text-sm text-amber-800 dark:text-amber-200">
                 <AlertTriangle className="w-4 h-4 mt-0.5 flex-shrink-0" />
                 <div>
                   <div className="font-medium">{t('failureDetection.externalUrlMissing')}</div>
@@ -282,7 +282,7 @@ export function FailureDetectionSettings() {
               <div className="space-y-3 text-sm">
                 <div className="flex justify-between">
                   <span className="text-bambu-gray">{t('failureDetection.serviceRunning')}</span>
-                  <span className={status.is_running ? 'text-green-400' : 'text-red-400'}>
+                  <span className={status.is_running ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'}>
                     {status.is_running ? t('common.yes') : t('common.no')}
                   </span>
                 </div>
@@ -293,7 +293,7 @@ export function FailureDetectionSettings() {
                   </span>
                 </div>
                 {status.last_error && (
-                  <div className="flex items-start gap-2 text-red-400">
+                  <div className="flex items-start gap-2 text-red-700 dark:text-red-400">
                     <X className="w-4 h-4 mt-0.5 flex-shrink-0" />
                     <span className="break-words">{status.last_error}</span>
                   </div>
@@ -308,10 +308,10 @@ export function FailureDetectionSettings() {
                         const printer = printers?.find((p) => String(p.id) === pid);
                         const colorClass =
                           info.class === 'failure'
-                            ? 'text-red-400'
+                            ? 'text-red-700 dark:text-red-400'
                             : info.class === 'warning'
-                              ? 'text-amber-400'
-                              : 'text-green-400';
+                              ? 'text-amber-700 dark:text-amber-400'
+                              : 'text-green-700 dark:text-green-400';
                         return (
                           <div key={pid} className="flex justify-between">
                             <span className="text-white">{printer?.name ?? `Printer ${pid}`}</span>
@@ -350,9 +350,9 @@ export function FailureDetectionSettings() {
                   const printer = printers?.find((p) => p.id === ev.printer_id);
                   const colorClass =
                     ev.class === 'failure'
-                      ? 'text-red-400'
+                      ? 'text-red-700 dark:text-red-400'
                       : ev.class === 'warning'
-                        ? 'text-amber-400'
+                        ? 'text-amber-700 dark:text-amber-400'
                         : 'text-bambu-gray';
                   return (
                     <div key={idx} className="flex justify-between gap-2 py-1 border-b border-gray-800">

+ 2 - 2
frontend/src/components/FilamentHoverCard.tsx

@@ -395,7 +395,7 @@ export function FilamentHoverCard({ data, children, disabled, className = '', sp
                             e.stopPropagation();
                             inventory.onUnassignSpool?.();
                           }}
-                          className="w-full flex items-center justify-center gap-1.5 px-2 py-1.5 text-xs font-medium rounded transition-colors bg-red-500/20 hover:bg-red-500/30 text-red-400"
+                          className="w-full flex items-center justify-center gap-1.5 px-2 py-1.5 text-xs font-medium rounded transition-colors bg-red-100 dark:bg-red-500/20 hover:bg-red-200 dark:hover:bg-red-500/30 text-red-700 dark:text-red-400"
                         >
                           <Unlink className="w-3.5 h-3.5" />
                           {t('inventory.unassignSpool')}
@@ -488,7 +488,7 @@ export function FilamentHoverCard({ data, children, disabled, className = '', sp
                     spoolman?.onUnlinkSpool?.();
                     setShowUnlinkConfirm(false);
                   }}
-                  className="flex-1 px-3 py-2 text-sm font-medium rounded transition-colors bg-red-500/20 hover:bg-red-500/30 text-red-400"
+                  className="flex-1 px-3 py-2 text-sm font-medium rounded transition-colors bg-red-100 dark:bg-red-500/20 hover:bg-red-200 dark:hover:bg-red-500/30 text-red-700 dark:text-red-400"
                 >
                   {t('inventory.unassignSpool')}
                 </button>

+ 1 - 1
frontend/src/components/FileManagerModal.tsx

@@ -702,7 +702,7 @@ export function FileManagerModal({ printerId, printerName, onClose }: FileManage
               variant="secondary"
               disabled={selectedFiles.size === 0 || deleteMutation.isPending}
               onClick={handleDelete}
-              className="text-red-400 hover:text-red-300"
+              className="text-red-700 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300"
             >
               {deleteMutation.isPending ? (
                 <Loader2 className="w-4 h-4 animate-spin" />

+ 15 - 15
frontend/src/components/FileUploadModal.tsx

@@ -215,12 +215,12 @@ export function FileUploadModal({ folderId, onClose, onUploadComplete, onFileUpl
 
           {/* ZIP Options */}
           {hasZipFiles && (
-            <div className="p-3 bg-blue-500/10 border border-blue-500/30 rounded-lg">
+            <div className="p-3 bg-blue-50 dark:bg-blue-500/10 border border-blue-300 dark:border-blue-500/30 rounded-lg">
               <div className="flex items-start gap-3">
-                <ArchiveIcon className="w-5 h-5 text-blue-400 mt-0.5 flex-shrink-0" />
+                <ArchiveIcon className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
                 <div className="flex-1">
-                  <p className="text-sm text-blue-300 font-medium">{t('fileManager.zipFilesDetected')}</p>
-                  <p className="text-xs text-blue-300/70 mt-1">
+                  <p className="text-sm text-blue-700 dark:text-blue-300 font-medium">{t('fileManager.zipFilesDetected')}</p>
+                  <p className="text-xs text-blue-700/80 dark:text-blue-300/70 mt-1">
                     {t('fileManager.zipExtractOptions')}
                   </p>
                   <label className="flex items-center gap-2 mt-2 cursor-pointer">
@@ -248,12 +248,12 @@ export function FileUploadModal({ folderId, onClose, onUploadComplete, onFileUpl
 
           {/* 3MF File Info */}
           {has3mfFiles && (
-            <div className="p-3 bg-purple-500/10 border border-purple-500/30 rounded-lg">
+            <div className="p-3 bg-purple-50 dark:bg-purple-500/10 border border-purple-300 dark:border-purple-500/30 rounded-lg">
               <div className="flex items-start gap-3">
-                <Printer className="w-5 h-5 text-purple-400 mt-0.5 flex-shrink-0" />
+                <Printer className="w-5 h-5 text-purple-600 dark:text-purple-400 mt-0.5 flex-shrink-0" />
                 <div className="flex-1">
-                  <p className="text-sm text-purple-300 font-medium">{t('fileManager.threemfDetected')}</p>
-                  <p className="text-xs text-purple-300/70 mt-1">
+                  <p className="text-sm text-purple-700 dark:text-purple-300 font-medium">{t('fileManager.threemfDetected')}</p>
+                  <p className="text-xs text-purple-700/80 dark:text-purple-300/70 mt-1">
                     {t('fileManager.threemfExtractionInfo')}
                   </p>
                 </div>
@@ -296,7 +296,7 @@ export function FileUploadModal({ folderId, onClose, onUploadComplete, onFileUpl
                   className="flex items-center gap-3 p-2 bg-bambu-dark rounded-lg"
                 >
                   {uploadFile.isZip ? (
-                    <ArchiveIcon className="w-4 h-4 text-blue-400 flex-shrink-0" />
+                    <ArchiveIcon className="w-4 h-4 text-blue-600 dark:text-blue-400 flex-shrink-0" />
                   ) : (
                     <File className="w-4 h-4 text-bambu-gray flex-shrink-0" />
                   )}
@@ -305,10 +305,10 @@ export function FileUploadModal({ folderId, onClose, onUploadComplete, onFileUpl
                     <p className="text-xs text-bambu-gray">
                       {(uploadFile.file.size / 1024 / 1024).toFixed(2)} MB
                       {uploadFile.isZip && uploadFile.status === 'pending' && (
-                        <span className="text-blue-400 ml-2">• {t('fileManager.willBeExtracted')}</span>
+                        <span className="text-blue-700 dark:text-blue-400 ml-2">• {t('fileManager.willBeExtracted')}</span>
                       )}
                       {uploadFile.extractedCount !== undefined && (
-                        <span className="text-green-400 ml-2">• {t('fileManager.filesExtracted', { count: uploadFile.extractedCount })}</span>
+                        <span className="text-green-700 dark:text-green-400 ml-2">• {t('fileManager.filesExtracted', { count: uploadFile.extractedCount })}</span>
                       )}
                     </p>
                     {/* #1401: errors render inline rather than as a hover-only
@@ -316,7 +316,7 @@ export function FileUploadModal({ folderId, onClose, onUploadComplete, onFileUpl
                         actual fix (re-export as .gcode.3mf) — useless if the
                         user can't read them. */}
                     {uploadFile.status === 'error' && uploadFile.error && (
-                      <p className="text-xs text-red-400 mt-1 break-words">{uploadFile.error}</p>
+                      <p className="text-xs text-red-700 dark:text-red-400 mt-1 break-words">{uploadFile.error}</p>
                     )}
                   </div>
                   {uploadFile.status === 'pending' && (
@@ -345,10 +345,10 @@ export function FileUploadModal({ folderId, onClose, onUploadComplete, onFileUpl
 
           {/* Compatibility Error */}
           {uploadError && (
-            <div className="p-3 bg-red-500/10 border border-red-500/30 rounded-lg">
+            <div className="p-3 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded-lg">
               <div className="flex items-start gap-3">
-                <XCircle className="w-5 h-5 text-red-400 mt-0.5 flex-shrink-0" />
-                <p className="text-sm text-red-300">{uploadError}</p>
+                <XCircle className="w-5 h-5 text-red-600 dark:text-red-400 mt-0.5 flex-shrink-0" />
+                <p className="text-sm text-red-700 dark:text-red-300">{uploadError}</p>
               </div>
             </div>
           )}

+ 1 - 1
frontend/src/components/FolderReadmePanel.tsx

@@ -42,7 +42,7 @@ export function FolderReadmePanel({ folderId }: FolderReadmePanelProps) {
             {data.filename}
           </span>
           {data.truncated && (
-            <span className="text-xs px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-400 flex-shrink-0">
+            <span className="text-xs px-1.5 py-0.5 rounded bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 flex-shrink-0">
               {t('fileManager.readme.truncated')}
             </span>
           )}

+ 25 - 25
frontend/src/components/ForecastPanel.tsx

@@ -387,8 +387,8 @@ export function ForecastPanel({ spools }: { spools: InventorySpool[] }) {
             onClick={() => setAlertsOpen((o) => !o)}
             className={`flex items-center gap-2 px-3 py-1.5 rounded-lg border text-sm font-medium transition-colors ${
               alerts.some((f) => f.stockBreakAlert)
-                ? 'bg-red-500/15 border-red-500/30 text-red-300 hover:bg-red-500/25'
-                : 'bg-yellow-500/15 border-yellow-500/30 text-yellow-300 hover:bg-yellow-500/25'
+                ? 'bg-red-100 dark:bg-red-500/15 border-red-300 dark:border-red-500/30 text-red-700 dark:text-red-300 hover:bg-red-200 dark:hover:bg-red-500/25'
+                : 'bg-yellow-100 dark:bg-yellow-500/15 border-yellow-300 dark:border-yellow-500/30 text-yellow-700 dark:text-yellow-300 hover:bg-yellow-200 dark:hover:bg-yellow-500/25'
             }`}
           >
             <AlertTriangle className="w-4 h-4" />
@@ -617,7 +617,7 @@ function AlertBanner({ forecast: f, onCart }: { forecast: SkuForecast; onCart: (
 
   return (
     <div className={`flex items-center gap-3 px-4 py-3 rounded-lg border text-sm ${
-      isBreak ? 'bg-red-500/10 border-red-500/30 text-red-300' : 'bg-yellow-500/10 border-yellow-500/30 text-yellow-300'
+      isBreak ? 'bg-red-50 dark:bg-red-500/10 border-red-300 dark:border-red-500/30 text-red-700 dark:text-red-300' : 'bg-yellow-50 dark:bg-yellow-500/10 border-yellow-300 dark:border-yellow-500/30 text-yellow-700 dark:text-yellow-300'
     }`}>
       <AlertTriangle className="w-4 h-4 flex-shrink-0" />
       <div className="flex-1 min-w-0">
@@ -876,10 +876,10 @@ function ForecastRow({
 
   const daysColor = snoozed ? 'text-bambu-gray'
     : f.daysRemaining === null ? 'text-bambu-gray'
-    : f.stockBreakAlert ? 'text-red-400'
-    : f.reorderAlert ? 'text-yellow-400'
-    : f.daysRemaining < 30 ? 'text-yellow-400'
-    : 'text-green-400';
+    : f.stockBreakAlert ? 'text-red-700 dark:text-red-400'
+    : f.reorderAlert ? 'text-yellow-700 dark:text-yellow-400'
+    : f.daysRemaining < 30 ? 'text-yellow-700 dark:text-yellow-400'
+    : 'text-green-700 dark:text-green-400';
 
   function upsert(lead: number, marginVal: number, marginUnitArg: 'days' | 'g', alertsSnoozed = snoozed) {
     upsertMutation.mutate({ material: f.group.material, subtype: f.group.subtype, brand: f.group.brand, color_name: f.group.colorName, lead_time_days: lead, safety_margin_value: marginVal, safety_margin_unit: marginUnitArg, alerts_snoozed: alertsSnoozed });
@@ -893,7 +893,7 @@ function ForecastRow({
   const tierBadge = f.rateTier === 'history'
     ? <span className="inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-bambu-green/15 text-bambu-green"><span className="w-1.5 h-1.5 rounded-full bg-bambu-green" />{t('forecast.trend')}</span>
     : f.rateTier === 'delta'
-    ? <span className="inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-blue-400/15 text-blue-400"><span className="w-1.5 h-1.5 rounded-full bg-blue-400" />{t('forecast.estimated')}</span>
+    ? <span className="inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-blue-100 dark:bg-blue-400/15 text-blue-700 dark:text-blue-400"><span className="w-1.5 h-1.5 rounded-full bg-blue-400" />{t('forecast.estimated')}</span>
     : <span className="inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-bambu-dark-tertiary text-bambu-gray/60"><span className="w-1.5 h-1.5 rounded-full bg-bambu-gray/40" />{t('forecast.noData')}</span>;
 
   const rowAlertBorder = snoozed ? '' : f.stockBreakAlert ? 'bg-red-500/5' : f.reorderAlert ? 'bg-yellow-500/5' : '';
@@ -959,7 +959,7 @@ function ForecastRow({
 
         {/* Reorder by */}
         <td className="px-4 py-3">
-          <span className={`text-sm ${!snoozed && f.reorderAlert ? 'text-yellow-400' : 'text-bambu-gray'}`}>
+          <span className={`text-sm ${!snoozed && f.reorderAlert ? 'text-yellow-700 dark:text-yellow-400' : 'text-bambu-gray'}`}>
             {f.reorderTriggerDate ? formatDate(f.reorderTriggerDate) : '—'}
           </span>
         </td>
@@ -977,16 +977,16 @@ function ForecastRow({
               </button>
             )}
             {!snoozed && (f.stockBreakAlert ? (
-              <AlertTriangle className="w-4 h-4 text-red-400" aria-label={t('forecast.stockBreakRisk')} />
+              <AlertTriangle className="w-4 h-4 text-red-600 dark:text-red-400" aria-label={t('forecast.stockBreakRisk')} />
             ) : f.reorderAlert ? (
-              <AlertTriangle className="w-4 h-4 text-yellow-400" aria-label={t('forecast.reorderNow')} />
+              <AlertTriangle className="w-4 h-4 text-yellow-600 dark:text-yellow-400" aria-label={t('forecast.reorderNow')} />
             ) : f.daysRemaining !== null ? (
               <Check className="w-4 h-4 text-bambu-green/50" />
             ) : null)}
             {canWrite && (
               <button
                 onClick={toggleSnooze}
-                className={`p-1 rounded transition-colors ${snoozed ? 'text-amber-400/80 hover:text-amber-300' : 'text-slate-400 hover:text-white'}`}
+                className={`p-1 rounded transition-colors ${snoozed ? 'text-amber-600/80 dark:text-amber-400/80 hover:text-amber-700 dark:hover:text-amber-300' : 'text-slate-400 hover:text-white'}`}
                 title={t(snoozed ? 'forecast.alertsEnabled' : 'forecast.alertsSnoozed')}
               >
                 <BellOff className="w-3.5 h-3.5" />
@@ -1390,7 +1390,7 @@ function ShoppingListPanel({
                 {t('forecast.downloadCsv')}
               </button>
               {canWrite && (
-                <button onClick={onClear} className="text-xs text-red-400 hover:text-red-300 transition-colors px-2 py-1 rounded border border-red-500/20 hover:bg-red-500/10">
+                <button onClick={onClear} className="text-xs text-red-700 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 transition-colors px-2 py-1 rounded border border-red-200 dark:border-red-500/20 hover:bg-red-50 dark:hover:bg-red-500/10">
                   {t('forecast.clearAll')}
                 </button>
               )}
@@ -1444,7 +1444,7 @@ function ShoppingListPanel({
                       <div className="flex items-center gap-2">
                         <span className="text-sm text-white">{lbl}</span>
                         {hasBreak && !isPurchased && (
-                          <AlertTriangle className="w-3.5 h-3.5 text-red-400 flex-shrink-0" aria-label={t('forecast.stockBreakBefore')} />
+                          <AlertTriangle className="w-3.5 h-3.5 text-red-600 dark:text-red-400 flex-shrink-0" aria-label={t('forecast.stockBreakBefore')} />
                         )}
                       </div>
                     </td>
@@ -1468,7 +1468,7 @@ function ShoppingListPanel({
                     <td className="px-4 py-2.5">
                       <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${
                         isReceived ? 'bg-bambu-green/20 text-bambu-green' :
-                        isPurchased ? 'bg-blue-400/20 text-blue-400' :
+                        isPurchased ? 'bg-blue-100 dark:bg-blue-400/20 text-blue-700 dark:text-blue-400' :
                         'bg-bambu-dark-tertiary text-bambu-gray'
                       }`}>
                         {isReceived ? t('forecast.received') : isPurchased ? t('forecast.purchased') : t('forecast.pending')}
@@ -1490,8 +1490,8 @@ function ShoppingListPanel({
                               title={isPurchased ? t('forecast.resetToPending') : t('forecast.markPurchased')}
                               className={`p-1.5 rounded transition-colors disabled:opacity-30 ${
                                 isPurchased
-                                  ? 'text-blue-400 hover:text-blue-300'
-                                  : 'text-blue-400/50 hover:text-blue-400'
+                                  ? 'text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300'
+                                  : 'text-blue-600/50 dark:text-blue-400/50 hover:text-blue-600 dark:hover:text-blue-400'
                               }`}
                             >
                               {isPurchased ? <RotateCcw className="w-4 h-4" /> : <CreditCard className="w-4 h-4" />}
@@ -1508,7 +1508,7 @@ function ShoppingListPanel({
                             {/* Delete */}
                             <button
                               onClick={() => onRemove(item.id)}
-                              className="p-1 text-bambu-gray hover:text-red-400 transition-colors"
+                              className="p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors"
                               title={t('forecast.remove')}
                             >
                               <Trash2 className="w-3.5 h-3.5" />
@@ -1608,14 +1608,14 @@ function CartLogisticsRow({
       <div className="flex items-center justify-between mb-3">
         <div className="flex items-center gap-2 min-w-0">
           {hasBreak
-            ? <AlertTriangle className="w-4 h-4 text-red-400 flex-shrink-0" />
+            ? <AlertTriangle className="w-4 h-4 text-red-600 dark:text-red-400 flex-shrink-0" />
             : <Check className="w-4 h-4 text-bambu-green/60 flex-shrink-0" />
           }
           <span className="text-sm font-medium text-white truncate">{label}</span>
           <span className="text-xs text-bambu-gray flex-shrink-0">{t('forecast.spoolCount', { count: item.quantity_spools })} ordered</span>
         </div>
         {canWrite && (
-          <button onClick={onRemove} className="p-1 text-bambu-gray hover:text-red-400 transition-colors flex-shrink-0">
+          <button onClick={onRemove} className="p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors flex-shrink-0">
             <Trash2 className="w-3.5 h-3.5" />
           </button>
         )}
@@ -1623,7 +1623,7 @@ function CartLogisticsRow({
 
       {/* Break alert */}
       {hasBreak && (
-        <div className="mb-3 px-3 py-2 rounded-lg bg-red-500/10 border border-red-500/20 text-xs text-red-300">
+        <div className="mb-3 px-3 py-2 rounded-lg bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/20 text-xs text-red-700 dark:text-red-300">
           <span className="font-medium">{t('forecast.stockBreakIn', { days: stockBreaksAt })}</span>
           {' '}{t('forecast.stockRunsOutBefore', { lt: f!.effectiveLeadTimeDays })}
           {f!.dailyRateG !== null && (
@@ -1657,9 +1657,9 @@ function CartLogisticsRow({
               <div className="text-xs text-bambu-gray mb-0.5">{t('forecast.safetyMarginLabel')}</div>
               <div className="text-sm font-semibold text-white">{Math.round(f.safetyStockG)}g</div>
             </div>
-            <div className={`rounded-lg px-2.5 py-2 text-center ${hasBreak ? 'bg-red-500/15' : 'bg-bambu-dark-tertiary/40'}`}>
+            <div className={`rounded-lg px-2.5 py-2 text-center ${hasBreak ? 'bg-red-100 dark:bg-red-500/15' : 'bg-bambu-dark-tertiary/40'}`}>
               <div className="text-xs text-bambu-gray mb-0.5">{t('forecast.daysLeft')}</div>
-              <div className={`text-sm font-semibold ${hasBreak ? 'text-red-400' : 'text-green-400'}`}>
+              <div className={`text-sm font-semibold ${hasBreak ? 'text-red-700 dark:text-red-400' : 'text-green-700 dark:text-green-400'}`}>
                 {f.daysRemaining ?? '—'}d
               </div>
             </div>
@@ -1771,7 +1771,7 @@ function CartLogisticsRow({
             <span className="flex items-center gap-1"><span className="inline-block w-4 border-t-2 border-yellow-400 border-dashed" /> {t('forecast.ropLabel')}</span>
             <span className="flex items-center gap-1"><span className="inline-block w-4 border-t border-bambu-gray border-dashed" /> {t('forecast.safetyStockLegend')}</span>
             <span className="flex items-center gap-1"><span className="inline-block w-4 border-t-2 border-blue-400 border-dashed" /> {t('forecast.stockArrivalLegend')}</span>
-            {hasBreak && <span className="flex items-center gap-1 text-red-400"><span className="inline-block w-4 border-t-2 border-red-400" /> {t('forecast.stockoutLegend')}</span>}
+            {hasBreak && <span className="flex items-center gap-1 text-red-700 dark:text-red-400"><span className="inline-block w-4 border-t-2 border-red-400" /> {t('forecast.stockoutLegend')}</span>}
           </div>
         </>
       ) : null}
@@ -1870,7 +1870,7 @@ function AddToCartModal({
                   <span className="text-xs text-bambu-gray">at {f.dailyRateG.toFixed(1)}g/day</span>
                 </div>
               ) : (
-                <div className="text-xs text-yellow-400 px-1">{t('forecast.noUsageQty')}</div>
+                <div className="text-xs text-yellow-700 dark:text-yellow-400 px-1">{t('forecast.noUsageQty')}</div>
               )}
             </div>
           )}

+ 26 - 26
frontend/src/components/GitHubBackupSettings.tsx

@@ -56,10 +56,10 @@ function StatusBadge({ status }: StatusBadgeProps) {
   if (!status) return null;
 
   const styles: Record<string, string> = {
-    success: 'bg-green-500/20 text-green-400',
-    failed: 'bg-red-500/20 text-red-400',
-    skipped: 'bg-yellow-500/20 text-yellow-400',
-    running: 'bg-blue-500/20 text-blue-400',
+    success: 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400',
+    failed: 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400',
+    skipped: 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400',
+    running: 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400',
   };
 
   const icons: Record<string, React.ReactNode> = {
@@ -658,7 +658,7 @@ export function GitHubBackupSettings() {
                 {/* Access Token */}
                 <div>
                   <label className="block text-sm text-bambu-gray mb-1">
-                    {t('backup.personalAccessToken')} {config?.has_token && <span className="text-green-400">{t('backup.tokenSaved')}</span>}
+                    {t('backup.personalAccessToken')} {config?.has_token && <span className="text-green-700 dark:text-green-400">{t('backup.tokenSaved')}</span>}
                   </label>
                   <input
                     type="password"
@@ -722,13 +722,13 @@ export function GitHubBackupSettings() {
                     <div className="flex items-center gap-2">
                       <span className={`text-sm ${noPrintersConnected ? 'text-bambu-gray' : 'text-white'}`}>{t('backup.kProfiles')}</span>
                       {noPrintersConnected && (
-                        <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-yellow-500/20 text-yellow-400">
+                        <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400">
                           <AlertTriangle className="w-3 h-3" />
                           {t('backup.noPrintersConnected')}
                         </span>
                       )}
                       {somePrintersDisconnected && (
-                        <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-yellow-500/20 text-yellow-400">
+                        <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400">
                           <AlertTriangle className="w-3 h-3" />
                           {t('backup.printersConnected', { connected: connectedPrinters, total: totalPrinters })}
                         </span>
@@ -749,7 +749,7 @@ export function GitHubBackupSettings() {
                     <div className="flex items-center gap-2">
                       <span className={`text-sm ${cloudStatus?.is_authenticated ? 'text-white' : 'text-bambu-gray'}`}>{t('backup.cloudProfiles')}</span>
                       {!cloudStatus?.is_authenticated && (
-                        <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-yellow-500/20 text-yellow-400">
+                        <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400">
                           <AlertTriangle className="w-3 h-3" />
                           {t('backup.cloudLoginRequiredShort')}
                         </span>
@@ -825,7 +825,7 @@ export function GitHubBackupSettings() {
                   messages (e.g. the "repository is not private" guard)
                   readable instead of clipped to a toast. */}
               {saveError && (
-                <div className="text-sm text-red-400 bg-red-500/10 border border-red-500/30 rounded p-3 flex items-start gap-2">
+                <div className="text-sm text-red-700 dark:text-red-400 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded p-3 flex items-start gap-2">
                   <XCircle className="w-4 h-4 mt-0.5 shrink-0" />
                   <div className="flex-1 leading-relaxed whitespace-pre-wrap break-words">{saveError}</div>
                   <button
@@ -842,18 +842,18 @@ export function GitHubBackupSettings() {
               {/* Test result */}
               {testResult && (
                 <div className="space-y-1.5">
-                  <div className={`text-sm flex items-center gap-1 ${testResult.success ? 'text-green-400' : 'text-red-400'}`}>
+                  <div className={`text-sm flex items-center gap-1 ${testResult.success ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'}`}>
                     {testResult.success ? <CheckCircle className="w-4 h-4" /> : <XCircle className="w-4 h-4" />}
                     {testResult.message}
                   </div>
                   {testResult.success && testResult.isPrivate === true && (
-                    <div className="text-xs flex items-center gap-1 text-green-400">
+                    <div className="text-xs flex items-center gap-1 text-green-700 dark:text-green-400">
                       <CheckCircle className="w-3.5 h-3.5" />
                       {t('backup.repoIsPrivate', 'Repository is private — safe to back up to.')}
                     </div>
                   )}
                   {testResult.success && testResult.isPrivate === false && (
-                    <div className="text-xs text-red-400 bg-red-500/10 border border-red-500/30 rounded p-2 flex items-start gap-1.5">
+                    <div className="text-xs text-red-700 dark:text-red-400 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded p-2 flex items-start gap-1.5">
                       <XCircle className="w-4 h-4 mt-0.5 shrink-0" />
                       <span>
                         {t(
@@ -864,7 +864,7 @@ export function GitHubBackupSettings() {
                     </div>
                   )}
                   {testResult.success && testResult.isPrivate === null && (
-                    <div className="text-xs text-yellow-400 bg-yellow-500/10 border border-yellow-500/30 rounded p-2 flex items-start gap-1.5">
+                    <div className="text-xs text-yellow-700 dark:text-yellow-400 bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30 rounded p-2 flex items-start gap-1.5">
                       <XCircle className="w-4 h-4 mt-0.5 shrink-0" />
                       <span>
                         {t(
@@ -1087,14 +1087,14 @@ export function GitHubBackupSettings() {
 
             {/* Restore result message */}
             {restoreResult && (
-              <div className={`p-3 rounded-lg ${restoreResult.success ? 'bg-green-500/10 border border-green-500/30' : 'bg-red-500/10 border border-red-500/30'}`}>
+              <div className={`p-3 rounded-lg ${restoreResult.success ? 'bg-green-50 dark:bg-green-500/10 border border-green-300 dark:border-green-500/30' : 'bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30'}`}>
                 <div className="flex items-start gap-2 text-sm">
                   {restoreResult.success ? (
-                    <CheckCircle className="w-4 h-4 text-green-400 mt-0.5 flex-shrink-0" />
+                    <CheckCircle className="w-4 h-4 text-green-600 dark:text-green-400 mt-0.5 flex-shrink-0" />
                   ) : (
-                    <XCircle className="w-4 h-4 text-red-400 mt-0.5 flex-shrink-0" />
+                    <XCircle className="w-4 h-4 text-red-600 dark:text-red-400 mt-0.5 flex-shrink-0" />
                   )}
-                  <div className={restoreResult.success ? 'text-green-200' : 'text-red-200'}>
+                  <div className={restoreResult.success ? 'text-green-800 dark:text-green-200' : 'text-red-800 dark:text-red-200'}>
                     {restoreResult.message}
                     {restoreResult.success && (
                       <div className="mt-2">
@@ -1113,12 +1113,12 @@ export function GitHubBackupSettings() {
             )}
 
             {/* Warning */}
-            <div className="p-3 rounded-lg bg-yellow-500/10 border border-yellow-500/30">
+            <div className="p-3 rounded-lg bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30">
               <div className="flex items-start gap-2 text-sm">
-                <AlertTriangle className="w-4 h-4 text-yellow-400 mt-0.5 flex-shrink-0" />
-                <div className="text-yellow-200">
+                <AlertTriangle className="w-4 h-4 text-yellow-600 dark:text-yellow-400 mt-0.5 flex-shrink-0" />
+                <div className="text-yellow-800 dark:text-yellow-200">
                   <span className="font-medium">{t('backup.restoreReplacesAll')}</span>{' '}
-                  <span className="text-yellow-200/70">{t('backup.restoreReplacesAllDetail')}</span>
+                  <span className="text-yellow-800/80 dark:text-yellow-200/70">{t('backup.restoreReplacesAllDetail')}</span>
                 </div>
               </div>
             </div>
@@ -1318,14 +1318,14 @@ export function GitHubBackupSettings() {
                               <Download className="w-3.5 h-3.5" />
                             </button>
                             <button
-                              className="text-bambu-gray hover:text-yellow-400 p-1"
+                              className="text-bambu-gray hover:text-yellow-600 dark:hover:text-yellow-400 p-1"
                               title={t('backup.restore')}
                               onClick={() => setRestoreConfirmFile(file.filename)}
                             >
                               <RotateCcw className="w-3.5 h-3.5" />
                             </button>
                             <button
-                              className="text-bambu-gray hover:text-red-400 p-1"
+                              className="text-bambu-gray hover:text-red-600 dark:hover:text-red-400 p-1"
                               onClick={() => setDeleteConfirmFile(file.filename)}
                               title={t('backup.deleteBackup')}
                             >
@@ -1425,10 +1425,10 @@ export function GitHubBackupSettings() {
             <p className="text-bambu-gray mb-4">
               {operationStatus || (isExporting ? t('backup.preparing') : t('backup.processing'))}
             </p>
-            <div className="p-3 rounded-lg bg-yellow-500/10 border border-yellow-500/30">
+            <div className="p-3 rounded-lg bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30">
               <div className="flex items-start gap-2 text-sm">
-                <AlertTriangle className="w-4 h-4 text-yellow-400 mt-0.5 flex-shrink-0" />
-                <p className="text-yellow-200 text-left">
+                <AlertTriangle className="w-4 h-4 text-yellow-600 dark:text-yellow-400 mt-0.5 flex-shrink-0" />
+                <p className="text-yellow-800 dark:text-yellow-200 text-left">
                   {t('backup.doNotClosePage')}
                 </p>
               </div>

+ 5 - 5
frontend/src/components/HMSErrorModal.tsx

@@ -879,12 +879,12 @@ function getSeverityInfo(severity: number): { label: string; color: string; bgCo
     case 1:
       return { label: 'Fatal', color: 'text-red-500', bgColor: 'bg-red-500/20', Icon: AlertTriangle };
     case 2:
-      return { label: 'Serious', color: 'text-red-400', bgColor: 'bg-red-500/15', Icon: AlertTriangle };
+      return { label: 'Serious', color: 'text-red-700 dark:text-red-400', bgColor: 'bg-red-100 dark:bg-red-500/15', Icon: AlertTriangle };
     case 3:
-      return { label: 'Warning', color: 'text-orange-400', bgColor: 'bg-orange-500/20', Icon: AlertCircle };
+      return { label: 'Warning', color: 'text-orange-700 dark:text-orange-400', bgColor: 'bg-orange-100 dark:bg-orange-500/20', Icon: AlertCircle };
     case 4:
     default:
-      return { label: 'Info', color: 'text-blue-400', bgColor: 'bg-blue-500/20', Icon: Info };
+      return { label: 'Info', color: 'text-blue-700 dark:text-blue-400', bgColor: 'bg-blue-100 dark:bg-blue-500/20', Icon: Info };
   }
 }
 
@@ -979,7 +979,7 @@ export function HMSErrorModal({ printerName, errors, onClose, printerId, hasPerm
         {/* Header */}
         <div className="flex items-center justify-between p-4 border-b border-bambu-dark-tertiary">
           <div className="flex items-center gap-2">
-            <AlertTriangle className="w-5 h-5 text-orange-400" />
+            <AlertTriangle className="w-5 h-5 text-orange-600 dark:text-orange-400" />
             <h2 className="text-lg font-semibold text-white">{t('hmsErrors.title', { name: printerName })}</h2>
           </div>
           <button
@@ -1089,7 +1089,7 @@ export function HMSErrorModal({ printerName, errors, onClose, printerId, hasPerm
             <button
               onClick={() => clearMutation.mutate()}
               disabled={!hasPermission('printers:control') || clearMutation.isPending}
-              className="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg bg-red-500/20 text-red-400 hover:bg-red-500/30 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0"
+              className="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 hover:bg-red-200 dark:hover:bg-red-500/30 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0"
             >
               {clearMutation.isPending ? (
                 <Loader2 className="w-4 h-4 animate-spin" />

+ 3 - 3
frontend/src/components/HeaterHistoryModal.tsx

@@ -134,8 +134,8 @@ export function HeaterHistoryModal({
   const trend = getTrend(chartData.map(d => d.value));
 
   const TrendIcon = ({ trend }: { trend: string }) => {
-    if (trend === 'up') return <TrendingUp className="w-4 h-4 text-red-400" />;
-    if (trend === 'down') return <TrendingDown className="w-4 h-4 text-green-400" />;
+    if (trend === 'up') return <TrendingUp className="w-4 h-4 text-red-600 dark:text-red-400" />;
+    if (trend === 'down') return <TrendingDown className="w-4 h-4 text-green-600 dark:text-green-400" />;
     return <Minus className="w-4 h-4 text-gray-400 dark:text-bambu-gray" />;
   };
 
@@ -264,7 +264,7 @@ export function HeaterHistoryModal({
                 {t('common.loading', 'Loading...')}
               </div>
             ) : error ? (
-              <div className="h-64 flex items-center justify-center text-red-400">
+              <div className="h-64 flex items-center justify-center text-red-700 dark:text-red-400">
                 {t('printers.heaterHistory.error', 'Failed to load history')}
               </div>
             ) : chartData.length === 0 ? (

+ 6 - 6
frontend/src/components/LDAPSettings.tsx

@@ -205,14 +205,14 @@ export function LDAPSettings() {
         </CardHeader>
         <CardContent>
           {ldapEnabled ? (
-            <div className="bg-green-500/10 border border-green-500/30 rounded-lg p-4">
+            <div className="bg-green-50 dark:bg-green-500/10 border border-green-300 dark:border-green-500/30 rounded-lg p-4">
               <div className="flex items-start gap-3">
-                <CheckCircle className="w-5 h-5 text-green-400 mt-0.5 flex-shrink-0" />
+                <CheckCircle className="w-5 h-5 text-green-600 dark:text-green-400 mt-0.5 flex-shrink-0" />
                 <div className="space-y-2">
                   <p className="text-white font-medium">
                     {t('settings.ldap.enabledDesc') || 'LDAP authentication is enabled'}
                   </p>
-                  <ul className="text-sm text-green-300 space-y-1 list-disc list-inside">
+                  <ul className="text-sm text-green-700 dark:text-green-300 space-y-1 list-disc list-inside">
                     <li>{t('settings.ldap.feature1') || 'Users can login with LDAP credentials'}</li>
                     <li>{t('settings.ldap.feature2') || 'Local admin account remains as fallback'}</li>
                     <li>{t('settings.ldap.feature3') || 'LDAP groups are mapped to BamBuddy groups on login'}</li>
@@ -221,14 +221,14 @@ export function LDAPSettings() {
               </div>
             </div>
           ) : (
-            <div className="bg-yellow-500/10 border border-yellow-500/30 rounded-lg p-4">
+            <div className="bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30 rounded-lg p-4">
               <div className="flex items-start gap-3">
-                <AlertTriangle className="w-5 h-5 text-yellow-400 mt-0.5 flex-shrink-0" />
+                <AlertTriangle className="w-5 h-5 text-yellow-600 dark:text-yellow-400 mt-0.5 flex-shrink-0" />
                 <div>
                   <p className="text-white font-medium">
                     {t('settings.ldap.disabledDesc') || 'LDAP authentication is disabled'}
                   </p>
-                  <p className="text-sm text-yellow-300 mt-1">
+                  <p className="text-sm text-yellow-700 dark:text-yellow-300 mt-1">
                     {t('settings.ldap.disabledHint') || 'Configure and save LDAP settings below, then enable.'}
                   </p>
                 </div>

+ 9 - 9
frontend/src/components/Layout.tsx

@@ -843,20 +843,20 @@ export function Layout() {
       }`}>
         {/* Debug logging indicator */}
         {debugLoggingState?.enabled && (
-          <div className="bg-amber-500/20 border-b border-amber-500/30 px-4 py-2 flex items-center justify-between">
+          <div className="bg-amber-100 dark:bg-amber-500/20 border-b border-amber-300 dark:border-amber-500/30 px-4 py-2 flex items-center justify-between">
             <div className="flex items-center gap-2 text-sm">
               <Bug className="w-4 h-4 text-amber-500 animate-pulse" />
-              <span className="text-amber-200">
+              <span className="text-amber-800 dark:text-amber-200">
                 {t('support.debugLoggingActive', { defaultValue: 'Debug logging is active' })}
                 {debugDuration !== null && (
-                  <span className="text-amber-300/70 ml-2">
+                  <span className="text-amber-700/80 dark:text-amber-300/70 ml-2">
                     ({Math.floor(debugDuration / 60)}m {debugDuration % 60}s)
                   </span>
                 )}
               </span>
               <button
                 onClick={() => navigate('/system')}
-                className="text-amber-400 hover:text-amber-300 font-medium underline ml-2"
+                className="text-amber-700 dark:text-amber-400 hover:text-amber-900 dark:hover:text-amber-300 font-medium underline ml-2"
               >
                 {t('support.manageLogs', { defaultValue: 'Manage' })}
               </button>
@@ -864,10 +864,10 @@ export function Layout() {
           </div>
         )}
         {devModeWarnings && devModeWarnings.length > 0 && (
-          <div className="bg-orange-500/20 border-b border-orange-500/30 px-4 py-2 flex items-center justify-between">
+          <div className="bg-orange-100 dark:bg-orange-500/20 border-b border-orange-300 dark:border-orange-500/30 px-4 py-2 flex items-center justify-between">
             <div className="flex items-center gap-2 text-sm">
               <ShieldAlert className="w-4 h-4 text-orange-500" />
-              <span className="text-orange-200">
+              <span className="text-orange-800 dark:text-orange-200">
                 {t('printers.developerModeWarning', {
                   names: devModeWarnings.map(w => w.name).join(', '),
                   defaultValue: `Developer LAN mode is not enabled on: ${devModeWarnings.map(w => w.name).join(', ')}. Some features may not work.`
@@ -875,7 +875,7 @@ export function Layout() {
               </span>
               <a href="https://wiki.bambulab.com/en/knowledge-sharing/enable-developer-mode"
                  target="_blank" rel="noopener noreferrer"
-                 className="text-orange-400 hover:text-orange-300 font-medium underline ml-2">
+                 className="text-orange-700 dark:text-orange-400 hover:text-orange-900 dark:hover:text-orange-300 font-medium underline ml-2">
                 {t('printers.howToEnable', { defaultValue: 'How to enable' })}
               </a>
             </div>
@@ -944,7 +944,7 @@ export function Layout() {
                   <path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
                 </svg>
               </div>
-              <h2 className="text-xl font-bold text-yellow-400 mb-2">
+              <h2 className="text-xl font-bold text-yellow-700 dark:text-yellow-400 mb-2">
                 {t('plateAlert.title')}
               </h2>
               <p className="text-lg text-white mb-2">
@@ -1052,7 +1052,7 @@ export function Layout() {
                     minLength={6}
                   />
                   {changePasswordData.confirmPassword && changePasswordData.newPassword !== changePasswordData.confirmPassword && (
-                    <p className="text-red-400 text-xs mt-1">{t('changePassword.passwordsDoNotMatch')}</p>
+                    <p className="text-red-700 dark:text-red-400 text-xs mt-1">{t('changePassword.passwordsDoNotMatch')}</p>
                   )}
                 </div>
               </div>

+ 3 - 3
frontend/src/components/LdapUserPicker.tsx

@@ -115,7 +115,7 @@ export function LdapUserPicker({ onSuccess }: LdapUserPickerProps) {
         )}
 
         {searchQuery.isError && (
-          <div className="px-3 py-4 text-sm text-red-400">
+          <div className="px-3 py-4 text-sm text-red-700 dark:text-red-400">
             {searchQuery.error instanceof Error ? searchQuery.error.message : t('users.modal.ldapSearchError')}
           </div>
         )}
@@ -159,8 +159,8 @@ export function LdapUserPicker({ onSuccess }: LdapUserPickerProps) {
 
       {/* Error from the provision mutation */}
       {errorMessage && (
-        <div className="bg-red-500/10 border border-red-500/30 rounded-lg p-3">
-          <p className="text-sm text-red-400">{errorMessage}</p>
+        <div className="bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded-lg p-3">
+          <p className="text-sm text-red-700 dark:text-red-400">{errorMessage}</p>
         </div>
       )}
 

+ 1 - 1
frontend/src/components/LibraryTagsModal.tsx

@@ -206,7 +206,7 @@ export function LibraryTagsModal({ open, onClose, onPickTag }: LibraryTagsModalP
                         </button>
                         <button
                           type="button"
-                          className="p-1.5 text-bambu-gray hover:text-red-400 rounded"
+                          className="p-1.5 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 rounded"
                           onClick={() => setDeleteTarget(tag)}
                           title={t('common.delete')}
                           aria-label={t('fileManager.tags.deleteAria', { name: tag.name })}

+ 5 - 5
frontend/src/components/LocalProfilesView.tsx

@@ -127,7 +127,7 @@ function PresetCard({
               {vendor && (
                 <span className="text-xs text-bambu-gray">{vendor}</span>
               )}
-              <span className="text-xs px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400">
+              <span className="text-xs px-1.5 py-0.5 rounded bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400">
                 {t('profiles.localProfiles.badge')}
               </span>
             </div>
@@ -138,7 +138,7 @@ function PresetCard({
             {hasPermission('settings:update') && (
               <button
                 onClick={() => onDelete(preset.id)}
-                className="p-1 text-bambu-gray hover:text-red-400 transition-colors"
+                className="p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors"
                 title={t('profiles.localProfiles.delete')}
               >
                 <Trash2 className="w-3.5 h-3.5" />
@@ -443,7 +443,7 @@ export function LocalProfilesView() {
           {processes.length > 0 && (
             <div>
               <div className="flex items-center gap-2 mb-3">
-                <Layers className="w-4 h-4 text-blue-400" />
+                <Layers className="w-4 h-4 text-blue-600 dark:text-blue-400" />
                 <h3 className="text-sm font-medium text-white">
                   {t('profiles.localProfiles.process')}
                 </h3>
@@ -467,7 +467,7 @@ export function LocalProfilesView() {
           {printers.length > 0 && (
             <div>
               <div className="flex items-center gap-2 mb-3">
-                <Settings2 className="w-4 h-4 text-orange-400" />
+                <Settings2 className="w-4 h-4 text-orange-600 dark:text-orange-400" />
                 <h3 className="text-sm font-medium text-white">
                   {t('profiles.localProfiles.printer')}
                 </h3>
@@ -494,7 +494,7 @@ export function LocalProfilesView() {
         <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
           <div className="bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg p-6 max-w-sm mx-4">
             <div className="flex items-center gap-2 mb-3">
-              <AlertCircle className="w-5 h-5 text-red-400" />
+              <AlertCircle className="w-5 h-5 text-red-600 dark:text-red-400" />
               <h3 className="text-white font-medium">{t('profiles.localProfiles.deleteConfirmTitle')}</h3>
             </div>
             <p className="text-sm text-bambu-gray mb-4">{t('profiles.localProfiles.deleteConfirm')}</p>

+ 1 - 1
frontend/src/components/LocationsModal.tsx

@@ -200,7 +200,7 @@ export function LocationsModal({ open, onClose, onPickLocation }: LocationsModal
                         </button>
                         <button
                           type="button"
-                          className="p-1.5 text-bambu-gray hover:text-red-400 rounded disabled:opacity-40"
+                          className="p-1.5 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 rounded disabled:opacity-40"
                           disabled={loc.spool_count > 0}
                           onClick={() => setDeleteTarget(loc)}
                           title={loc.spool_count > 0 ? t('locations.deleteBlocked') : t('common.delete')}

+ 1 - 1
frontend/src/components/LogViewer.tsx

@@ -162,7 +162,7 @@ export function LogViewer() {
                     e.stopPropagation();
                     setIsStreaming(false);
                   }}
-                  className="flex items-center gap-1.5 px-3 py-1.5 text-sm bg-red-500/20 text-red-400 hover:bg-red-500/30 rounded transition-colors"
+                  className="flex items-center gap-1.5 px-3 py-1.5 text-sm bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 hover:bg-red-200 dark:hover:bg-red-500/30 rounded transition-colors"
                 >
                   <Square className="w-4 h-4" />
                   Stop

+ 12 - 12
frontend/src/components/NotificationLogViewer.tsx

@@ -9,15 +9,15 @@ import { Button } from './Button';
 import { useToast } from '../contexts/ToastContext';
 
 const EVENT_COLORS: Record<string, string> = {
-  print_start: 'text-blue-400',
+  print_start: 'text-blue-700 dark:text-blue-400',
   print_complete: 'text-bambu-green',
-  print_failed: 'text-red-400',
-  print_stopped: 'text-orange-400',
-  print_progress: 'text-yellow-400',
+  print_failed: 'text-red-700 dark:text-red-400',
+  print_stopped: 'text-orange-700 dark:text-orange-400',
+  print_progress: 'text-yellow-700 dark:text-yellow-400',
   printer_offline: 'text-gray-400',
-  printer_error: 'text-rose-400',
-  filament_low: 'text-cyan-400',
-  maintenance_due: 'text-purple-400',
+  printer_error: 'text-rose-700 dark:text-rose-400',
+  filament_low: 'text-cyan-700 dark:text-cyan-400',
+  maintenance_due: 'text-purple-700 dark:text-purple-400',
   test: 'text-bambu-gray',
 };
 
@@ -108,7 +108,7 @@ export function NotificationLogViewer({ onClose }: NotificationLogViewerProps) {
                 {t('notifications.statsSent', { count: stats.success_count })}
               </span>
               {stats.failure_count > 0 && (
-                <span className="flex items-center gap-1 text-red-400">
+                <span className="flex items-center gap-1 text-red-700 dark:text-red-400">
                   <XCircle className="w-4 h-4" />
                   {t('notifications.statsFailed', { count: stats.failure_count })}
                 </span>
@@ -161,7 +161,7 @@ export function NotificationLogViewer({ onClose }: NotificationLogViewerProps) {
             variant="secondary"
             onClick={() => clearMutation.mutate()}
             disabled={clearMutation.isPending}
-            className="text-red-400 hover:text-red-300"
+            className="text-red-700 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300"
           >
             {clearMutation.isPending ? (
               <Loader2 className="w-4 h-4 animate-spin" />
@@ -234,7 +234,7 @@ function LogEntry({
         {log.success ? (
           <CheckCircle className="w-4 h-4 text-bambu-green shrink-0" />
         ) : (
-          <XCircle className="w-4 h-4 text-red-400 shrink-0" />
+          <XCircle className="w-4 h-4 text-red-600 dark:text-red-400 shrink-0" />
         )}
 
         <span className={`text-xs font-medium ${EVENT_COLORS[log.event_type] || 'text-bambu-gray'}`}>
@@ -274,8 +274,8 @@ function LogEntry({
           </div>
           {!log.success && log.error_message && (
             <div>
-              <p className="text-xs text-red-400 mb-1">{t('notifications.logError')}</p>
-              <p className="text-sm text-red-300">{log.error_message}</p>
+              <p className="text-xs text-red-700 dark:text-red-400 mb-1">{t('notifications.logError')}</p>
+              <p className="text-sm text-red-700 dark:text-red-300">{log.error_message}</p>
             </div>
           )}
           <div className="flex gap-4 text-xs text-bambu-gray pt-1">

+ 24 - 24
frontend/src/components/NotificationProviderCard.tsx

@@ -115,73 +115,73 @@ export function NotificationProviderCard({ provider, onEdit }: NotificationProvi
           {/* Event summary - show all event tags */}
           <div className="mb-3 flex flex-wrap gap-1">
             {provider.on_print_start && (
-              <span className="px-2 py-0.5 bg-blue-500/20 text-blue-400 text-xs rounded">{t('notifications.start')}</span>
+              <span className="px-2 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 text-xs rounded">{t('notifications.start')}</span>
             )}
             {provider.on_plate_not_empty && (
-              <span className="px-2 py-0.5 bg-rose-600/20 text-rose-300 text-xs rounded">{t('notifications.plateCheck')}</span>
+              <span className="px-2 py-0.5 bg-rose-100 dark:bg-rose-600/20 text-rose-700 dark:text-rose-300 text-xs rounded">{t('notifications.plateCheck')}</span>
             )}
             {provider.on_print_complete && (
               <span className="px-2 py-0.5 bg-bambu-green/20 text-bambu-green text-xs rounded">{t('notifications.complete')}</span>
             )}
             {provider.on_print_failed && (
-              <span className="px-2 py-0.5 bg-red-500/20 text-red-400 text-xs rounded">{t('notifications.failed')}</span>
+              <span className="px-2 py-0.5 bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 text-xs rounded">{t('notifications.failed')}</span>
             )}
             {provider.on_print_stopped && (
-              <span className="px-2 py-0.5 bg-orange-500/20 text-orange-400 text-xs rounded">{t('notifications.stopped')}</span>
+              <span className="px-2 py-0.5 bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 text-xs rounded">{t('notifications.stopped')}</span>
             )}
             {provider.on_print_progress && (
-              <span className="px-2 py-0.5 bg-yellow-500/20 text-yellow-400 text-xs rounded">{t('notifications.progress')}</span>
+              <span className="px-2 py-0.5 bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 text-xs rounded">{t('notifications.progress')}</span>
             )}
             {provider.on_printer_offline && (
               <span className="px-2 py-0.5 bg-gray-500/20 text-gray-400 text-xs rounded">{t('notifications.offline')}</span>
             )}
             {provider.on_printer_error && (
-              <span className="px-2 py-0.5 bg-rose-500/20 text-rose-400 text-xs rounded">{t('notifications.error')}</span>
+              <span className="px-2 py-0.5 bg-rose-100 dark:bg-rose-500/20 text-rose-700 dark:text-rose-400 text-xs rounded">{t('notifications.error')}</span>
             )}
             {provider.on_ai_failure_detection && (
-              <span className="px-2 py-0.5 bg-fuchsia-500/20 text-fuchsia-300 text-xs rounded">{t('notifications.aiFailureDetection')}</span>
+              <span className="px-2 py-0.5 bg-fuchsia-100 dark:bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 text-xs rounded">{t('notifications.aiFailureDetection')}</span>
             )}
             {provider.on_filament_low && (
-              <span className="px-2 py-0.5 bg-cyan-500/20 text-cyan-400 text-xs rounded">{t('notifications.lowFilament')}</span>
+              <span className="px-2 py-0.5 bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-400 text-xs rounded">{t('notifications.lowFilament')}</span>
             )}
             {provider.on_maintenance_due && (
-              <span className="px-2 py-0.5 bg-purple-500/20 text-purple-400 text-xs rounded">{t('notifications.maintenance')}</span>
+              <span className="px-2 py-0.5 bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 text-xs rounded">{t('notifications.maintenance')}</span>
             )}
             {provider.on_ams_humidity_high && (
-              <span className="px-2 py-0.5 bg-blue-600/20 text-blue-300 text-xs rounded">{t('notifications.amsHumidity')}</span>
+              <span className="px-2 py-0.5 bg-blue-100 dark:bg-blue-600/20 text-blue-700 dark:text-blue-300 text-xs rounded">{t('notifications.amsHumidity')}</span>
             )}
             {provider.on_ams_temperature_high && (
-              <span className="px-2 py-0.5 bg-orange-600/20 text-orange-300 text-xs rounded">{t('notifications.amsTemp')}</span>
+              <span className="px-2 py-0.5 bg-orange-100 dark:bg-orange-600/20 text-orange-700 dark:text-orange-300 text-xs rounded">{t('notifications.amsTemp')}</span>
             )}
             {provider.on_ams_ht_humidity_high && (
-              <span className="px-2 py-0.5 bg-cyan-600/20 text-cyan-300 text-xs rounded">{t('notifications.amsHtHumidity')}</span>
+              <span className="px-2 py-0.5 bg-cyan-100 dark:bg-cyan-600/20 text-cyan-700 dark:text-cyan-300 text-xs rounded">{t('notifications.amsHtHumidity')}</span>
             )}
             {provider.on_ams_ht_temperature_high && (
-              <span className="px-2 py-0.5 bg-amber-600/20 text-amber-300 text-xs rounded">{t('notifications.amsHtTemp')}</span>
+              <span className="px-2 py-0.5 bg-amber-100 dark:bg-amber-600/20 text-amber-700 dark:text-amber-300 text-xs rounded">{t('notifications.amsHtTemp')}</span>
             )}
             {provider.on_bed_cooled && (
-              <span className="px-2 py-0.5 bg-teal-500/20 text-teal-400 text-xs rounded">{t('notifications.bedCooled')}</span>
+              <span className="px-2 py-0.5 bg-teal-100 dark:bg-teal-500/20 text-teal-700 dark:text-teal-400 text-xs rounded">{t('notifications.bedCooled')}</span>
             )}
             {provider.on_first_layer_complete && (
-              <span className="px-2 py-0.5 bg-emerald-600/20 text-emerald-300 text-xs rounded">{t('notifications.firstLayer')}</span>
+              <span className="px-2 py-0.5 bg-emerald-100 dark:bg-emerald-600/20 text-emerald-700 dark:text-emerald-300 text-xs rounded">{t('notifications.firstLayer')}</span>
             )}
             {provider.on_print_missing_spool_assignment && (
-              <span className="px-2 py-0.5 bg-amber-500/20 text-amber-300 text-xs rounded">{t('notifications.missingSpoolAssignmentLabel')}</span>
+              <span className="px-2 py-0.5 bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-300 text-xs rounded">{t('notifications.missingSpoolAssignmentLabel')}</span>
             )}
             {provider.on_stock_reorder_alert && (
-              <span className="px-2 py-0.5 bg-lime-500/20 text-lime-400 text-xs rounded">{t('notifications.stockReorderAlert')}</span>
+              <span className="px-2 py-0.5 bg-lime-100 dark:bg-lime-500/20 text-lime-700 dark:text-lime-400 text-xs rounded">{t('notifications.stockReorderAlert')}</span>
             )}
             {provider.on_stock_break_alert && (
-              <span className="px-2 py-0.5 bg-red-600/20 text-red-300 text-xs rounded">{t('notifications.stockBreakAlert')}</span>
+              <span className="px-2 py-0.5 bg-red-100 dark:bg-red-600/20 text-red-700 dark:text-red-300 text-xs rounded">{t('notifications.stockBreakAlert')}</span>
             )}
             {provider.quiet_hours_enabled && (
-              <span className="px-2 py-0.5 bg-indigo-500/20 text-indigo-400 text-xs rounded flex items-center gap-1">
+              <span className="px-2 py-0.5 bg-indigo-100 dark:bg-indigo-500/20 text-indigo-700 dark:text-indigo-400 text-xs rounded flex items-center gap-1">
                 <Moon className="w-3 h-3" />
                 {t('notifications.quiet')}
               </span>
             )}
             {provider.daily_digest_enabled && (
-              <span className="px-2 py-0.5 bg-emerald-500/20 text-emerald-400 text-xs rounded flex items-center gap-1">
+              <span className="px-2 py-0.5 bg-emerald-100 dark:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400 text-xs rounded flex items-center gap-1">
                 <Calendar className="w-3 h-3" />
                 {t('notifications.digest', { time: provider.daily_digest_time })}
               </span>
@@ -214,7 +214,7 @@ export function NotificationProviderCard({ provider, onEdit }: NotificationProvi
             <div className={`mb-3 p-2 rounded-lg flex items-center gap-2 text-sm ${
               testResult.success
                 ? 'bg-bambu-green/20 text-bambu-green'
-                : 'bg-red-500/20 text-red-400'
+                : 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400'
             }`}>
               {testResult.success ? (
                 <CheckCircle className="w-4 h-4" />
@@ -567,7 +567,7 @@ export function NotificationProviderCard({ provider, onEdit }: NotificationProvi
               <div className="space-y-2">
                 <div className="flex items-center justify-between">
                   <div className="flex items-center gap-2">
-                    <Moon className="w-4 h-4 text-purple-400" />
+                    <Moon className="w-4 h-4 text-purple-600 dark:text-purple-400" />
                     <p className="text-sm text-white">{t('notifications.quietHours')}</p>
                   </div>
                   <Toggle
@@ -594,7 +594,7 @@ export function NotificationProviderCard({ provider, onEdit }: NotificationProvi
               <div className="space-y-2">
                 <div className="flex items-center justify-between">
                   <div className="flex items-center gap-2">
-                    <Calendar className="w-4 h-4 text-emerald-400" />
+                    <Calendar className="w-4 h-4 text-emerald-600 dark:text-emerald-400" />
                     <p className="text-sm text-white">{t('notifications.dailyDigest')}</p>
                   </div>
                   <Toggle
@@ -632,7 +632,7 @@ export function NotificationProviderCard({ provider, onEdit }: NotificationProvi
                   size="sm"
                   variant="secondary"
                   onClick={() => setShowDeleteConfirm(true)}
-                  className="text-red-400 hover:text-red-300"
+                  className="text-red-700 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300"
                 >
                   <Trash2 className="w-4 h-4" />
                 </Button>

+ 2 - 2
frontend/src/components/NotificationTemplateEditor.tsx

@@ -136,7 +136,7 @@ export function NotificationTemplateEditor({ template, onClose }: NotificationTe
         {/* Content */}
         <form onSubmit={handleSubmit} className="flex-1 overflow-y-auto p-4 space-y-4">
           {error && (
-            <div className="p-3 bg-red-500/20 border border-red-500/50 rounded text-red-400 text-sm">
+            <div className="p-3 bg-red-100 dark:bg-red-500/20 border border-red-300 dark:border-red-500/50 rounded text-red-700 dark:text-red-400 text-sm">
               {error}
             </div>
           )}
@@ -245,7 +245,7 @@ export function NotificationTemplateEditor({ template, onClose }: NotificationTe
             variant="ghost"
             onClick={() => resetMutation.mutate()}
             disabled={resetMutation.isPending}
-            className="text-orange-400 hover:text-orange-300"
+            className="text-orange-600 dark:text-orange-400 hover:text-orange-700 dark:hover:text-orange-300"
           >
             {resetMutation.isPending ? (
               <Loader2 className="w-4 h-4 animate-spin mr-2" />

+ 10 - 10
frontend/src/components/OIDCProviderSettings.tsx

@@ -69,7 +69,7 @@ function ProviderForm({
     requireEmailVerifiedDesc = t('settings.oidc.form.requireEmailVerifiedDesc');
   } else {
     requireEmailVerifiedDesc = (
-      <span className="text-red-400">{t('settings.oidc.form.requireEmailVerifiedWarning')}</span>
+      <span className="text-red-700 dark:text-red-400">{t('settings.oidc.form.requireEmailVerifiedWarning')}</span>
     );
   }
 
@@ -77,21 +77,21 @@ function ProviderForm({
     <div className="space-y-4">
       <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
         <div>
-          <label className={labelCls}>{t('settings.oidc.form.name')} <span className="text-red-400">*</span></label>
+          <label className={labelCls}>{t('settings.oidc.form.name')} <span className="text-red-700 dark:text-red-400">*</span></label>
           <input className={inputCls} value={form.name} onChange={(e) => set('name', e.target.value)} placeholder="Google" />
         </div>
         <div>
-          <label className={labelCls}>{t('settings.oidc.form.issuerUrl')} <span className="text-red-400">*</span></label>
+          <label className={labelCls}>{t('settings.oidc.form.issuerUrl')} <span className="text-red-700 dark:text-red-400">*</span></label>
           <input className={inputCls} value={form.issuer_url} onChange={(e) => set('issuer_url', e.target.value)} placeholder="https://accounts.google.com" />
         </div>
         <div>
-          <label className={labelCls}>{t('settings.oidc.form.clientId')} <span className="text-red-400">*</span></label>
+          <label className={labelCls}>{t('settings.oidc.form.clientId')} <span className="text-red-700 dark:text-red-400">*</span></label>
           <input className={inputCls} value={form.client_id} onChange={(e) => set('client_id', e.target.value)} placeholder="your-client-id" />
         </div>
         <div>
           <label className={labelCls}>
             {t('settings.oidc.form.clientSecret')}
-            {!isEdit && <span className="text-red-400"> *</span>}
+            {!isEdit && <span className="text-red-700 dark:text-red-400"> *</span>}
             {isEdit && <span className="text-bambu-gray text-xs ml-1">({t('settings.oidc.form.secretHint')})</span>}
           </label>
           <input
@@ -169,7 +169,7 @@ function ProviderForm({
         />
         <p className="text-bambu-gray text-xs mt-1">{t('settings.oidc.form.emailClaimDesc')}</p>
         {autoLinkOn && form.email_claim !== 'email' && (
-          <p className="text-yellow-400 text-xs mt-1">{t('settings.oidc.form.emailClaimCustomClaimAutoLinkWarning')}</p>
+          <p className="text-yellow-700 dark:text-yellow-400 text-xs mt-1">{t('settings.oidc.form.emailClaimCustomClaimAutoLinkWarning')}</p>
         )}
       </div>
 
@@ -378,7 +378,7 @@ export function OIDCProviderSettings() {
                 <div className="flex items-center gap-2">
                   <h4 className="text-white font-medium">{provider.name}</h4>
                   {provider.is_enabled ? (
-                    <span className="flex items-center gap-1 text-xs text-green-400 bg-green-400/10 px-2 py-0.5 rounded-full">
+                    <span className="flex items-center gap-1 text-xs text-green-700 dark:text-green-400 bg-green-50 dark:bg-green-400/10 px-2 py-0.5 rounded-full">
                       <Check className="w-3 h-3" /> {t('common.enabled')}
                     </span>
                   ) : (
@@ -478,13 +478,13 @@ export function OIDCProviderSettings() {
                 </div>
                 <div>
                   <dt className="text-bambu-gray">{t('settings.oidc.form.autoCreate')}</dt>
-                  <dd className={provider.auto_create_users ? 'text-green-400' : 'text-bambu-gray'}>
+                  <dd className={provider.auto_create_users ? 'text-green-700 dark:text-green-400' : 'text-bambu-gray'}>
                     {provider.auto_create_users ? t('common.yes') : t('common.no')}
                   </dd>
                 </div>
                 <div>
                   <dt className="text-bambu-gray">{t('settings.oidc.form.autoLink')}</dt>
-                  <dd className={provider.auto_link_existing_accounts ? 'text-green-400' : 'text-bambu-gray'}>
+                  <dd className={provider.auto_link_existing_accounts ? 'text-green-700 dark:text-green-400' : 'text-bambu-gray'}>
                     {provider.auto_link_existing_accounts ? t('common.yes') : t('common.no')}
                   </dd>
                 </div>
@@ -494,7 +494,7 @@ export function OIDCProviderSettings() {
                 </div>
                 <div>
                   <dt className="text-bambu-gray">{t('settings.oidc.form.requireEmailVerified')}</dt>
-                  <dd className={provider.require_email_verified ? 'text-green-400' : 'text-red-400'}>
+                  <dd className={provider.require_email_verified ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'}>
                     {provider.require_email_verified ? t('common.yes') : t('common.no')}
                   </dd>
                 </div>

+ 3 - 3
frontend/src/components/OrcaCloudProfilesView.tsx

@@ -257,21 +257,21 @@ export function OrcaCloudProfilesView({
       ) : (
         <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
           <PresetColumn
-            icon={<Droplet className="w-4 h-4 text-amber-400" />}
+            icon={<Droplet className="w-4 h-4 text-amber-600 dark:text-amber-400" />}
             title={t('profiles.cloudView.columns.filament')}
             presets={presetsByType('filament')}
             emptyText={t('profiles.cloudView.noFilamentPresets')}
             onSelect={setSelectedSetting}
           />
           <PresetColumn
-            icon={<Settings2 className="w-4 h-4 text-blue-400" />}
+            icon={<Settings2 className="w-4 h-4 text-blue-600 dark:text-blue-400" />}
             title={t('profiles.cloudView.columns.process')}
             presets={presetsByType('process')}
             emptyText={t('profiles.cloudView.noProcessPresets')}
             onSelect={setSelectedSetting}
           />
           <PresetColumn
-            icon={<PrinterIcon className="w-4 h-4 text-purple-400" />}
+            icon={<PrinterIcon className="w-4 h-4 text-purple-600 dark:text-purple-400" />}
             title={t('profiles.cloudView.columns.printer')}
             presets={presetsByType('printer')}
             emptyText={t('profiles.cloudView.noPrinterPresets')}

+ 4 - 4
frontend/src/components/OrcaCloudView.tsx

@@ -387,10 +387,10 @@ function PasteCard({
             <p className="text-base text-white pt-0.5">{t('profiles.orcaCloud.paste.step1')}</p>
           </li>
           <li className="flex gap-3">
-            <span className="flex-shrink-0 w-7 h-7 rounded-full bg-amber-500/20 text-amber-400 text-sm font-bold flex items-center justify-center">2</span>
+            <span className="flex-shrink-0 w-7 h-7 rounded-full bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 text-sm font-bold flex items-center justify-center">2</span>
             <div className="flex-1 p-3 bg-amber-500/10 border border-amber-500/40 rounded">
               <div className="flex items-start gap-2">
-                <AlertTriangle className="w-5 h-5 text-amber-400 flex-shrink-0 mt-0.5" />
+                <AlertTriangle className="w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
                 <p className="text-base text-white font-medium">{t('profiles.orcaCloud.paste.step2')}</p>
               </div>
             </div>
@@ -426,7 +426,7 @@ function PasteCard({
             disabled={isFinishing}
           />
           {pasteError && (
-            <p className="mt-2 text-sm text-red-400 flex items-center gap-2">
+            <p className="mt-2 text-sm text-red-700 dark:text-red-400 flex items-center gap-2">
               <AlertCircle className="w-4 h-4" />
               {pasteError}
             </p>
@@ -499,7 +499,7 @@ function PasswordCard({
             />
           </div>
           {passwordError && (
-            <p className="text-sm text-red-400 flex items-center gap-2">
+            <p className="text-sm text-red-700 dark:text-red-400 flex items-center gap-2">
               <AlertCircle className="w-4 h-4" />
               {passwordError}
             </p>

+ 1 - 1
frontend/src/components/PendingUploadsPanel.tsx

@@ -102,7 +102,7 @@ function PendingUploadItem({
               {isDiscarding ? (
                 <Loader2 className="w-4 h-4 animate-spin" />
               ) : (
-                <Trash2 className="w-4 h-4 text-red-400" />
+                <Trash2 className="w-4 h-4 text-red-600 dark:text-red-400" />
               )}
             </Button>
           </div>

+ 1 - 1
frontend/src/components/PrintLogTable.tsx

@@ -64,7 +64,7 @@ export function PrintLogTable({ archiveId }: PrintLogTableProps) {
               run.status === 'completed'
                 ? 'text-bambu-green'
                 : run.status === 'failed'
-                  ? 'text-red-400'
+                  ? 'text-red-700 dark:text-red-400'
                   : 'text-bambu-gray';
             return (
               <tr

+ 7 - 7
frontend/src/components/PrintModal/FilamentMapping.tsx

@@ -194,9 +194,9 @@ export function FilamentMapping({
         <Circle className="w-4 h-4" fill={statusColor} stroke="none" />
         <span>{t('printModal.filamentMapping')}</span>
         {hasTypeMismatch ? (
-          <span className="text-xs text-orange-400">(Type not found)</span>
+          <span className="text-xs text-orange-700 dark:text-orange-400">(Type not found)</span>
         ) : hasColorMismatch ? (
-          <span className="text-xs text-yellow-400">(Color mismatch)</span>
+          <span className="text-xs text-yellow-700 dark:text-yellow-400">(Color mismatch)</span>
         ) : (
           <span className="text-xs text-bambu-green">(Ready)</span>
         )}
@@ -264,8 +264,8 @@ export function FilamentMapping({
                     item.status === 'match'
                       ? 'border-bambu-green/50 text-bambu-green'
                       : item.status === 'type_only'
-                      ? 'border-yellow-400/50 text-yellow-400'
-                      : 'border-orange-400/50 text-orange-400'
+                      ? 'border-yellow-500 dark:border-yellow-400/50 text-yellow-700 dark:text-yellow-400'
+                      : 'border-orange-500 dark:border-orange-400/50 text-orange-700 dark:text-orange-400'
                   } ${item.isManual ? 'ring-1 ring-blue-400/50' : ''}`}
                   title={item.isManual ? 'Manually selected' : 'Auto-matched'}
                 >
@@ -315,11 +315,11 @@ export function FilamentMapping({
                   <Check className="w-3 h-3 text-bambu-green" />
                 ) : item.status === 'type_only' ? (
                   <span title="Same type, different color">
-                    <AlertTriangle className="w-3 h-3 text-yellow-400" />
+                    <AlertTriangle className="w-3 h-3 text-yellow-600 dark:text-yellow-400" />
                   </span>
                 ) : (
                   <span title="Filament type not loaded">
-                    <AlertTriangle className="w-3 h-3 text-orange-400" />
+                    <AlertTriangle className="w-3 h-3 text-orange-600 dark:text-orange-400" />
                   </span>
                 )}
               </div>
@@ -346,7 +346,7 @@ export function FilamentMapping({
             </span>
           </div>
           {hasTypeMismatch && (
-            <p className="text-xs text-orange-400 mt-2">Required filament type not found in printer.</p>
+            <p className="text-xs text-orange-700 dark:text-orange-400 mt-2">Required filament type not found in printer.</p>
           )}
         </div>
       )}

+ 1 - 1
frontend/src/components/PrintModal/FilamentOverride.tsx

@@ -118,7 +118,7 @@ export function FilamentOverride({
                   disabled={compatible.length === 0}
                   className={`flex-1 px-2 py-1 rounded border text-xs bg-bambu-dark-secondary focus:outline-none focus:ring-1 focus:ring-bambu-green ${
                     isOverridden
-                      ? 'border-blue-400/50 text-blue-400'
+                      ? 'border-blue-500/50 dark:border-blue-400/50 text-blue-700 dark:text-blue-400'
                       : 'border-bambu-gray/30 text-bambu-gray'
                   }`}
                 >

+ 1 - 1
frontend/src/components/PrintModal/PlateSelector.tsx

@@ -35,7 +35,7 @@ export function PlateSelector({
         <Layers className="w-4 h-4 text-bambu-gray" />
         <span className="text-sm text-bambu-gray">Select Plate{multiSelect ? 's' : ''} to Print</span>
         {selectedPlates.size === 0 && (
-          <span className="text-xs text-orange-400 flex items-center gap-1">
+          <span className="text-xs text-orange-700 dark:text-orange-400 flex items-center gap-1">
             <AlertTriangle className="w-3 h-3" />
             Selection required
           </span>

+ 1 - 1
frontend/src/components/PrintModal/PrintOptions.tsx

@@ -109,7 +109,7 @@ export function PrintOptionsPanel({
               bypasses the per-filament-type derivation. */}
           <div className="pt-2 mt-1 border-t border-bambu-dark-tertiary/60">
             <div className="flex items-center gap-2 mb-1.5">
-              <Flame className="w-3.5 h-3.5 text-amber-400" />
+              <Flame className="w-3.5 h-3.5 text-amber-600 dark:text-amber-400" />
               <span className="text-sm text-white">{t('settings.preheatTitle', 'Preheat & Heat Soak')}</span>
             </div>
             <p className="text-xs text-bambu-gray mb-2">

+ 11 - 11
frontend/src/components/PrintModal/PrinterSelector.tsx

@@ -171,8 +171,8 @@ function InlineMappingEditor({
               status === 'match'
                 ? 'border-bambu-green/50 text-bambu-green'
                 : status === 'type_only'
-                ? 'border-yellow-400/50 text-yellow-400'
-                : 'border-orange-400/50 text-orange-400'
+                ? 'border-yellow-500 dark:border-yellow-400/50 text-yellow-700 dark:text-yellow-400'
+                : 'border-orange-500 dark:border-orange-400/50 text-orange-700 dark:text-orange-400'
             } ${isManual ? 'ring-1 ring-blue-400/50' : ''}`}
             title={isManual ? 'Manually selected' : 'Auto-matched'}
           >
@@ -190,11 +190,11 @@ function InlineMappingEditor({
             <Check className="w-3 h-3 text-bambu-green" />
           ) : status === 'type_only' ? (
             <span title="Same type, different color">
-              <AlertTriangle className="w-3 h-3 text-yellow-400" />
+              <AlertTriangle className="w-3 h-3 text-yellow-600 dark:text-yellow-400" />
             </span>
           ) : (
             <span title="Filament type not loaded">
-              <AlertTriangle className="w-3 h-3 text-orange-400" />
+              <AlertTriangle className="w-3 h-3 text-orange-600 dark:text-orange-400" />
             </span>
           )}
         </div>
@@ -330,7 +330,7 @@ export function PrinterSelector({
 
   if (displayPrinters.length === 0) {
     return (
-      <div className="flex items-center gap-2 text-red-400 text-sm mb-4">
+      <div className="flex items-center gap-2 text-red-700 dark:text-red-400 text-sm mb-4">
         <AlertCircle className="w-4 h-4" />
         No {showInactive ? '' : 'active '}printers available
       </div>
@@ -562,7 +562,7 @@ export function PrinterSelector({
               {stateLabel && (
                 <span className={`text-xs px-2 py-0.5 rounded-full ${
                   busy
-                    ? 'bg-yellow-500/20 text-yellow-400'
+                    ? 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400'
                     : 'bg-bambu-green/20 text-bambu-green'
                 }`}>
                   {stateLabel}
@@ -606,8 +606,8 @@ export function PrinterSelector({
                     mappingResult.matchStatus === 'full'
                       ? 'text-bambu-green'
                       : mappingResult.matchStatus === 'partial'
-                      ? 'text-yellow-400'
-                      : 'text-orange-400'
+                      ? 'text-yellow-700 dark:text-yellow-400'
+                      : 'text-orange-700 dark:text-orange-400'
                   }`}>
                     ({mappingResult.exactMatches}/{mappingResult.totalSlots} matched)
                   </span>
@@ -654,7 +654,7 @@ export function PrinterSelector({
           onClick={() => setShowAllPrinters(true)}
           className="text-xs text-bambu-gray hover:text-white transition-colors mt-2 flex items-center gap-1"
         >
-          <AlertTriangle className="w-3 h-3 text-yellow-400" />
+          <AlertTriangle className="w-3 h-3 text-yellow-600 dark:text-yellow-400" />
           {hiddenPrinterCount} other printer{hiddenPrinterCount > 1 ? 's' : ''} hidden (different model) —
           <span className="underline">show all</span>
         </button>
@@ -673,7 +673,7 @@ export function PrinterSelector({
 
       {/* Warning when no printer selected (only in printer mode) */}
       {assignmentMode === 'printer' && selectedCount === 0 && (
-        <p className="text-xs text-orange-400 mt-1 flex items-center gap-1">
+        <p className="text-xs text-orange-700 dark:text-orange-400 mt-1 flex items-center gap-1">
           <AlertCircle className="w-3 h-3" />
           Select at least one printer
         </p>
@@ -681,7 +681,7 @@ export function PrinterSelector({
 
       {/* Warning when no model selected (only in model mode) */}
       {assignmentMode === 'model' && !targetModel && (
-        <p className="text-xs text-orange-400 mt-1 flex items-center gap-1">
+        <p className="text-xs text-orange-700 dark:text-orange-400 mt-1 flex items-center gap-1">
           <AlertCircle className="w-3 h-3" />
           Select a target printer model
         </p>

+ 1 - 1
frontend/src/components/PrintModal/ScheduleOptions.tsx

@@ -219,7 +219,7 @@ export function ScheduleOptionsPanel({
             </div>
           </div>
           {(!isDateValid || !isTimeValid) && (
-            <p className="mt-1 text-xs text-red-400">
+            <p className="mt-1 text-xs text-red-700 dark:text-red-400">
               {t('printModal.invalidDateTime')}
             </p>
           )}

+ 7 - 7
frontend/src/components/PrintModal/index.tsx

@@ -1127,9 +1127,9 @@ export function PrintModal({
               const selectedPrinter = printers?.find(p => p.id === selectedPrinters[0]);
               if (selectedPrinter && selectedPrinter.model && slicedForModel !== selectedPrinter.model) {
                 return (
-                  <div className="p-3 mb-2 bg-yellow-500/10 border border-yellow-500/30 rounded-lg flex items-center gap-2">
-                    <AlertTriangle className="w-4 h-4 text-yellow-400 flex-shrink-0" />
-                    <span className="text-sm text-yellow-400">
+                  <div className="p-3 mb-2 bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30 rounded-lg flex items-center gap-2">
+                    <AlertTriangle className="w-4 h-4 text-yellow-600 dark:text-yellow-400 flex-shrink-0" />
+                    <span className="text-sm text-yellow-700 dark:text-yellow-400">
                       File was sliced for {slicedForModel}, but printing on {selectedPrinter.model}
                     </span>
                   </div>
@@ -1140,9 +1140,9 @@ export function PrintModal({
 
             {/* Warning when archive data couldn't be loaded */}
             {archiveDataMissing && (
-              <div className="flex items-start gap-2 p-3 mb-2 bg-orange-500/10 border border-orange-500/30 rounded-lg text-sm">
-                <AlertCircle className="w-4 h-4 text-orange-400 mt-0.5 flex-shrink-0" />
-                <p className="text-orange-400">
+              <div className="flex items-start gap-2 p-3 mb-2 bg-orange-50 dark:bg-orange-500/10 border border-orange-300 dark:border-orange-500/30 rounded-lg text-sm">
+                <AlertCircle className="w-4 h-4 text-orange-600 dark:text-orange-400 mt-0.5 flex-shrink-0" />
+                <p className="text-orange-700 dark:text-orange-400">
                   Archive data unavailable. The source file may have been deleted. Filament mapping is disabled.
                 </p>
               </div>
@@ -1212,7 +1212,7 @@ export function PrintModal({
 
             {/* Error message */}
             {updateQueueMutation.isError && (
-              <div className="mb-4 p-3 bg-red-500/20 border border-red-500/50 rounded-lg text-sm text-red-400">
+              <div className="mb-4 p-3 bg-red-100 dark:bg-red-500/20 border border-red-500/50 rounded-lg text-sm text-red-700 dark:text-red-400">
                 {(updateQueueMutation.error as Error)?.message || 'Failed to complete operation'}
               </div>
             )}

+ 1 - 1
frontend/src/components/PrinterInfoModal.tsx

@@ -86,7 +86,7 @@ export function PrinterInfoModal({ printer, status, totalPrintHours, onClose }:
       <span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-medium ${
         status?.connected
           ? 'bg-bambu-green/20 text-bambu-green'
-          : 'bg-red-500/20 text-red-400'
+          : 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400'
       }`}>
         <span className={`w-1.5 h-1.5 rounded-full ${status?.connected ? 'bg-bambu-green' : 'bg-red-400'}`} />
         {status?.connected ? t('printers.status.available') : t('printers.status.offline')}

+ 2 - 2
frontend/src/components/PrinterQueueWidget.tsx

@@ -48,7 +48,7 @@ export function PrinterQueueWidget({ printerId, printerModel, loadedFilamentType
     >
       <div className="flex items-center justify-between gap-3">
         <div className="flex items-center gap-3 min-w-0 flex-1">
-          <Calendar className="w-5 h-5 text-yellow-400 flex-shrink-0" />
+          <Calendar className="w-5 h-5 text-yellow-600 dark:text-yellow-400 flex-shrink-0" />
           <div className="min-w-0 flex-1">
             <p className="text-xs text-bambu-gray">{t('queue.nextInQueue')}</p>
             <p className="text-sm text-white truncate">
@@ -62,7 +62,7 @@ export function PrinterQueueWidget({ printerId, printerModel, loadedFilamentType
             {nextItem?.scheduled_time ? formatRelativeTime(nextItem.scheduled_time, 'system', t) : t('time.waiting')}
           </span>
           {totalPending > 1 && (
-            <span className="text-xs px-1.5 py-0.5 bg-yellow-400/20 text-yellow-400 rounded">
+            <span className="text-xs px-1.5 py-0.5 bg-yellow-100 dark:bg-yellow-400/20 text-yellow-700 dark:text-yellow-400 rounded">
               +{totalPending - 1}
             </span>
           )}

+ 1 - 1
frontend/src/components/ProjectPageModal.tsx

@@ -174,7 +174,7 @@ export function ProjectPageModal({ archiveId, archiveName, onClose }: ProjectPag
           )}
 
           {error && (
-            <div className="text-red-400 text-center py-12">
+            <div className="text-red-700 dark:text-red-400 text-center py-12">
               Failed to load project page data
             </div>
           )}

+ 3 - 3
frontend/src/components/QueueStatsBar.tsx

@@ -22,10 +22,10 @@ export function QueueStatsBar({
   t: (key: string) => string;
 }) {
   const stats = [
-    { icon: Play, value: activeCount, label: t('queue.summary.printing'), color: 'text-blue-400' },
-    { icon: Clock, value: pendingCount, label: t('queue.summary.queued'), color: 'text-yellow-400' },
+    { icon: Play, value: activeCount, label: t('queue.summary.printing'), color: 'text-blue-600 dark:text-blue-400' },
+    { icon: Clock, value: pendingCount, label: t('queue.summary.queued'), color: 'text-yellow-600 dark:text-yellow-400' },
     { icon: Timer, value: formatDuration(totalTime), label: t('queue.summary.totalTime'), color: 'text-bambu-green' },
-    { icon: Weight, value: formatWeight(totalWeight), label: t('queue.summary.totalWeight'), color: 'text-purple-400' },
+    { icon: Weight, value: formatWeight(totalWeight), label: t('queue.summary.totalWeight'), color: 'text-purple-600 dark:text-purple-400' },
     { icon: CheckCircle, value: historyCount, label: t('queue.summary.history'), color: 'text-bambu-gray' },
   ];
 

+ 2 - 2
frontend/src/components/QueueTimelineView.tsx

@@ -353,9 +353,9 @@ export function QueueTimelineView({
                   <div className="w-32 sm:w-40 shrink-0 px-3 py-3 border-r border-bambu-dark-tertiary flex items-center gap-2">
                     <PrinterIcon className={`w-3.5 h-3.5 shrink-0 ${
                       lane.printerId == null && lane.targetModel == null
-                        ? 'text-orange-400'
+                        ? 'text-orange-600 dark:text-orange-400'
                         : lane.targetModel
-                          ? 'text-blue-400'
+                          ? 'text-blue-600 dark:text-blue-400'
                           : 'text-bambu-green'
                     }`} />
                     <span className="text-sm text-white truncate">{lane.label}</span>

+ 3 - 3
frontend/src/components/RestoreModal.tsx

@@ -212,7 +212,7 @@ export function RestoreModal({ onClose, onRestore, onSuccess }: RestoreModalProp
                     <div>
                       <p className="text-white font-medium flex items-center gap-2">
                         {overwrite ? (
-                          <RefreshCw className="w-4 h-4 text-orange-400" />
+                          <RefreshCw className="w-4 h-4 text-orange-600 dark:text-orange-400" />
                         ) : (
                           <SkipForward className="w-4 h-4 text-bambu-gray" />
                         )}
@@ -361,8 +361,8 @@ export function RestoreModal({ onClose, onRestore, onSuccess }: RestoreModalProp
                       <AlertTriangle className="w-4 h-4 text-orange-500" />
                       {t('backup.newApiKeysGenerated')}
                     </h4>
-                    <div className="p-3 rounded bg-orange-500/10 border border-orange-500/30">
-                      <p className="text-xs text-orange-200 mb-2">
+                    <div className="p-3 rounded bg-orange-50 dark:bg-orange-500/10 border border-orange-300 dark:border-orange-500/30">
+                      <p className="text-xs text-orange-800 dark:text-orange-200 mb-2">
                         {t('backup.keysShownOnce')}
                       </p>
                       <div className="space-y-2">

+ 2 - 2
frontend/src/components/RunWithPipelineModal.tsx

@@ -266,7 +266,7 @@ function PickStep({
                     ) : targetName ? (
                       <span>{targetName}</span>
                     ) : (
-                      <span className="text-amber-400">
+                      <span className="text-amber-700 dark:text-amber-400">
                         {t('library.runWithPipeline.noTarget', 'No target printer set')}
                       </span>
                     )}
@@ -323,7 +323,7 @@ function ConfirmStep({
       <ul className="space-y-1.5">
         {report.issues.map((issue, idx) => (
           <li key={idx} className="flex items-start gap-2 text-xs">
-            <AlertTriangle className="w-3.5 h-3.5 text-amber-400 flex-shrink-0 mt-0.5" />
+            <AlertTriangle className="w-3.5 h-3.5 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
             <span className="text-bambu-gray">
               <IssueText issue={issue} />
             </span>

+ 12 - 12
frontend/src/components/SecurityStatusCard.tsx

@@ -80,14 +80,14 @@ export function SecurityStatusCard() {
           </div>
         </CardHeader>
         <CardContent>
-          <div className="text-red-400" data-testid="encryption-error">{t('common.errorLoading')}</div>
+          <div className="text-red-700 dark:text-red-400" data-testid="encryption-error">{t('common.errorLoading')}</div>
           {/* S5: manual recovery button — the bounded auto-retry above stops
               after 3 consecutive failures so the operator needs an explicit
               way to reset polling without reloading the whole page. */}
           <button
             type="button"
             onClick={() => refetch()}
-            className="mt-2 text-sm text-blue-400 underline hover:text-blue-300"
+            className="mt-2 text-sm text-blue-700 dark:text-blue-400 underline hover:text-blue-800 dark:hover:text-blue-300"
             data-testid="encryption-retry-button"
           >
             {t('common.retry')}
@@ -109,23 +109,23 @@ export function SecurityStatusCard() {
   let statusBody: string;
 
   if (data.decryption_broken) {
-    severityClasses = 'bg-red-500/20 border-red-500/50 text-red-400';
-    icon = <XCircle className="text-red-400" size={20} />;
+    severityClasses = 'bg-red-100 dark:bg-red-500/20 border-red-400 dark:border-red-500/50 text-red-700 dark:text-red-400';
+    icon = <XCircle className="text-red-600 dark:text-red-400" size={20} />;
     statusLabel = t('settings.encryption.decryptionBrokenTitle');
     statusBody = t('settings.encryption.decryptionBrokenError', { count: totalEncrypted });
   } else if (data.key_source === 'generated') {
-    severityClasses = 'bg-amber-500/10 border-amber-500/30 text-amber-400';
-    icon = <ShieldCheck className="text-amber-400" size={20} />;
+    severityClasses = 'bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400';
+    icon = <ShieldCheck className="text-amber-600 dark:text-amber-400" size={20} />;
     statusLabel = t('settings.encryption.enabledGenerated');
     statusBody = t('settings.encryption.backupHint');
   } else if (totalLegacy > 0) {
-    severityClasses = 'bg-amber-500/10 border-amber-500/30 text-amber-400';
-    icon = <AlertTriangle className="text-amber-400" size={20} />;
+    severityClasses = 'bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400';
+    icon = <AlertTriangle className="text-amber-600 dark:text-amber-400" size={20} />;
     statusLabel = data.key_source === 'env' ? t('settings.encryption.enabledFromEnv') : t('settings.encryption.enabledFromFile');
     statusBody = t('settings.encryption.legacyRowsWarning', { count: totalLegacy });
   } else if (data.key_configured) {
-    severityClasses = 'bg-green-500/20 border-green-500/30 text-green-400';
-    icon = <ShieldCheck className="text-green-400" size={20} />;
+    severityClasses = 'bg-green-100 dark:bg-green-500/20 border-green-300 dark:border-green-500/30 text-green-700 dark:text-green-400';
+    icon = <ShieldCheck className="text-green-600 dark:text-green-400" size={20} />;
     statusLabel = data.key_source === 'env' ? t('settings.encryption.enabledFromEnv') : t('settings.encryption.enabledFromFile');
     statusBody = t('settings.encryption.allEncrypted');
   } else {
@@ -157,7 +157,7 @@ export function SecurityStatusCard() {
         </div>
         {showConcurrentLegacyWarning && (
           <div
-            className="mt-2 p-3 border rounded-lg bg-amber-500/10 border-amber-500/30 text-amber-400"
+            className="mt-2 p-3 border rounded-lg bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400"
             data-testid="encryption-legacy-warning"
           >
             <p className="text-sm">{t('settings.encryption.legacyRowsWarning', { count: totalLegacy })}</p>
@@ -165,7 +165,7 @@ export function SecurityStatusCard() {
         )}
         {data.migration_error_count > 0 && (
           <div
-            className="mt-2 p-3 border rounded-lg bg-amber-500/10 border-amber-500/30 text-amber-400"
+            className="mt-2 p-3 border rounded-lg bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-400"
             data-testid="encryption-migration-warning"
           >
             <p className="text-sm">

+ 2 - 2
frontend/src/components/SkipObjectsModal.tsx

@@ -240,7 +240,7 @@ export function SkipObjectsModal({ printerId, isOpen, onClose }: SkipObjectsModa
                       <span className={`text-lg font-mono font-bold ${obj.skipped ? 'text-red-500 dark:text-red-400' : 'text-green-600 dark:text-bambu-green'}`}>
                         {obj.id}
                       </span>
-                      <span className={`text-[8px] uppercase tracking-wider ${obj.skipped ? 'text-red-400/60' : 'text-green-500/60 dark:text-bambu-green/60'}`}>
+                      <span className={`text-[8px] uppercase tracking-wider ${obj.skipped ? 'text-red-700/70 dark:text-red-400/60' : 'text-green-500/60 dark:text-bambu-green/60'}`}>
                         ID
                       </span>
                     </div>
@@ -251,7 +251,7 @@ export function SkipObjectsModal({ printerId, isOpen, onClose }: SkipObjectsModa
                         {obj.name}
                       </span>
                       {obj.skipped && (
-                        <span className="text-[10px] text-red-400/60">{t('printers.willBeSkipped')}</span>
+                        <span className="text-[10px] text-red-700/70 dark:text-red-400/60">{t('printers.willBeSkipped')}</span>
                       )}
                     </div>
 

+ 3 - 3
frontend/src/components/SliceModal.tsx

@@ -557,7 +557,7 @@ export function SliceModal({ source, onClose }: SliceModalProps) {
           )}
 
           {presetsQuery.isError && (
-            <div className="text-sm text-red-400" role="alert">
+            <div className="text-sm text-red-700 dark:text-red-400" role="alert">
               {t(
                 'slice.presetsLoadFailed',
                 'Failed to load presets. Open Settings → Profiles to import them, or sign in to Bambu Cloud.',
@@ -787,7 +787,7 @@ export function SliceModal({ source, onClose }: SliceModalProps) {
           )}
 
           {errorMessage && (
-            <div className="text-sm text-red-400 bg-red-900/20 border border-red-900/40 rounded p-2" role="alert">
+            <div className="text-sm text-red-700 dark:text-red-400 bg-red-900/20 border border-red-900/40 rounded p-2" role="alert">
               {errorMessage}
             </div>
           )}
@@ -892,7 +892,7 @@ function CloudStatusBanner({
 
   const tones: Record<'expired' | 'unreachable', { tone: string; icon: typeof Cloud }> = {
     expired: {
-      tone: 'border-amber-700/40 bg-amber-900/20 text-amber-200',
+      tone: 'border-amber-300 dark:border-amber-700/40 bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-200',
       icon: CloudOff,
     },
     unreachable: {

+ 10 - 10
frontend/src/components/SlicerPipelinesPanel.tsx

@@ -180,7 +180,7 @@ export function SlicerPipelinesPanel() {
           </div>
         )}
         {error && (
-          <div className="text-sm text-red-400">
+          <div className="text-sm text-red-700 dark:text-red-400">
             {t('settings.pipelines.loadError', 'Could not load pipelines.')}
           </div>
         )}
@@ -532,7 +532,7 @@ function PipelineRow({
                 <span
                   className={`text-xs px-1.5 py-0.5 rounded inline-flex items-center gap-1 ${
                     needsTarget
-                      ? 'bg-amber-500/15 text-amber-400'
+                      ? 'bg-amber-100 dark:bg-amber-500/15 text-amber-700 dark:text-amber-400'
                       : 'bg-bambu-dark-tertiary text-bambu-gray'
                   }`}
                 >
@@ -597,7 +597,7 @@ function PipelineRow({
                 onClick={onDelete}
                 disabled={deleting}
                 aria-label={t('settings.pipelines.action.delete', 'Delete')}
-                className="p-1.5 text-bambu-gray hover:text-red-400 hover:bg-bambu-dark-tertiary rounded disabled:opacity-50"
+                className="p-1.5 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 hover:bg-bambu-dark-tertiary rounded disabled:opacity-50"
               >
                 <Trash2 className="w-4 h-4" />
               </button>
@@ -689,7 +689,7 @@ function PipelineRow({
       )}
 
       {needsTarget && !editing && (
-        <div className="mt-2 flex items-center gap-1.5 text-xs text-amber-400">
+        <div className="mt-2 flex items-center gap-1.5 text-xs text-amber-700 dark:text-amber-400">
           <AlertTriangle className="w-3.5 h-3.5" />
           {t(
             'settings.pipelines.noTargetWarning',
@@ -699,7 +699,7 @@ function PipelineRow({
       )}
 
       {hasStaleRef && !editing && (
-        <div className="mt-2 flex items-center gap-1.5 text-xs text-amber-400">
+        <div className="mt-2 flex items-center gap-1.5 text-xs text-amber-700 dark:text-amber-400">
           <AlertTriangle className="w-3.5 h-3.5" />
           {t(
             'settings.pipelines.staleWarning',
@@ -715,12 +715,12 @@ function RunStatusBadge({ status }: { status: PipelineRun['status'] }) {
   const { t } = useTranslation();
   const colourClass: Record<PipelineRun['status'], string> = {
     queued: 'text-bambu-gray',
-    slicing: 'text-blue-400',
-    dispatching: 'text-blue-400',
+    slicing: 'text-blue-700 dark:text-blue-400',
+    dispatching: 'text-blue-700 dark:text-blue-400',
     in_progress: 'text-bambu-green',
     completed: 'text-bambu-green',
-    failed: 'text-red-400',
-    partial_failure: 'text-amber-400',
+    failed: 'text-red-700 dark:text-red-400',
+    partial_failure: 'text-amber-700 dark:text-amber-400',
     cancelled: 'text-bambu-gray',
   };
   return (
@@ -745,7 +745,7 @@ function PresetLine({
       {name ? (
         <span className="text-white">{name}</span>
       ) : (
-        <span className="text-amber-400">[{SOURCE_LABEL[ref.source]} #{ref.id}]</span>
+        <span className="text-amber-700 dark:text-amber-400">[{SOURCE_LABEL[ref.source]} #{ref.id}]</span>
       )}
     </div>
   );

+ 13 - 13
frontend/src/components/SmartPlugCard.tsx

@@ -126,17 +126,17 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
             <div className="flex items-center gap-3 min-w-0 flex-1">
               <div className={`p-2 rounded-lg flex-shrink-0 ${
                 plug.plug_type === 'mqtt'
-                  ? (isReachable ? 'bg-teal-500/20' : 'bg-red-500/20')
-                  : (isReachable ? (isOn ? 'bg-bambu-green/20' : 'bg-bambu-dark') : 'bg-red-500/20')
+                  ? (isReachable ? 'bg-teal-100 dark:bg-teal-500/20' : 'bg-red-100 dark:bg-red-500/20')
+                  : (isReachable ? (isOn ? 'bg-bambu-green/20' : 'bg-bambu-dark') : 'bg-red-100 dark:bg-red-500/20')
               }`}>
                 {plug.plug_type === 'mqtt' ? (
-                  <Radio className={`w-5 h-5 ${isReachable ? 'text-teal-400' : 'text-red-400'}`} />
+                  <Radio className={`w-5 h-5 ${isReachable ? 'text-teal-600 dark:text-teal-400' : 'text-red-600 dark:text-red-400'}`} />
                 ) : plug.plug_type === 'homeassistant' ? (
-                  <Home className={`w-5 h-5 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-400'}`} />
+                  <Home className={`w-5 h-5 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-600 dark:text-red-400'}`} />
                 ) : plug.plug_type === 'rest' ? (
-                  <Globe className={`w-5 h-5 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-400'}`} />
+                  <Globe className={`w-5 h-5 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-600 dark:text-red-400'}`} />
                 ) : (
-                  <Plug className={`w-5 h-5 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-400'}`} />
+                  <Plug className={`w-5 h-5 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-600 dark:text-red-400'}`} />
                 )}
               </div>
               <div className="min-w-0">
@@ -157,19 +157,19 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
               ) : plug.plug_type === 'mqtt' ? (
                 /* MQTT plugs - show badge and checkmark when receiving data */
                 <div className="flex items-center gap-1.5 text-sm whitespace-nowrap">
-                  <span className="px-1.5 py-0.5 bg-teal-500/20 text-teal-400 text-[10px] font-medium rounded flex-shrink-0">MQTT</span>
+                  <span className="px-1.5 py-0.5 bg-teal-100 dark:bg-teal-500/20 text-teal-700 dark:text-teal-400 text-[10px] font-medium rounded flex-shrink-0">MQTT</span>
                   {isReachable && <span className="text-status-ok">✓</span>}
                 </div>
               ) : plug.plug_type === 'homeassistant' ? (
                 <div className="flex items-center gap-1 text-sm">
-                  <span className="px-1 py-0.5 bg-blue-500/20 text-blue-400 text-[10px] font-medium rounded">HA</span>
+                  <span className="px-1 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 text-[10px] font-medium rounded">HA</span>
                   <span className={isReachable ? (isOn ? 'text-status-ok' : 'text-bambu-gray') : 'text-status-error'}>
                     {isReachable ? (status?.state || '?') : t('smartPlugs.offline')}
                   </span>
                 </div>
               ) : plug.plug_type === 'rest' ? (
                 <div className="flex items-center gap-1 text-sm">
-                  <span className="px-1 py-0.5 bg-purple-500/20 text-purple-400 text-[10px] font-medium rounded">REST</span>
+                  <span className="px-1 py-0.5 bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 text-[10px] font-medium rounded">REST</span>
                   <span className={isReachable ? (isOn ? 'text-status-ok' : 'text-bambu-gray') : 'text-status-error'}>
                     {isReachable ? (status?.state || '?') : t('smartPlugs.offline')}
                   </span>
@@ -214,19 +214,19 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
           {(plug.power_alert_enabled || plug.schedule_enabled || plug.plug_type === 'mqtt') && (
             <div className="flex flex-wrap gap-1.5 mb-3">
               {plug.plug_type === 'mqtt' && (
-                <span className="flex items-center gap-1 px-2 py-0.5 bg-teal-500/20 text-teal-400 text-xs rounded-full">
+                <span className="flex items-center gap-1 px-2 py-0.5 bg-teal-100 dark:bg-teal-500/20 text-teal-700 dark:text-teal-400 text-xs rounded-full">
                   <Eye className="w-3 h-3" />
                   {t('smartPlugs.monitorOnly')}
                 </span>
               )}
               {plug.power_alert_enabled && (
-                <span className="flex items-center gap-1 px-2 py-0.5 bg-yellow-500/20 text-yellow-400 text-xs rounded-full">
+                <span className="flex items-center gap-1 px-2 py-0.5 bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 text-xs rounded-full">
                   <Bell className="w-3 h-3" />
                   {t('smartPlugs.alerts')}
                 </span>
               )}
               {plug.schedule_enabled && (
-                <span className="flex items-center gap-1 px-2 py-0.5 bg-blue-500/20 text-blue-400 text-xs rounded-full">
+                <span className="flex items-center gap-1 px-2 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 text-xs rounded-full">
                   <Calendar className="w-3 h-3" />
                   {plug.schedule_on_time && plug.schedule_off_time
                     ? `${plug.schedule_on_time} - ${plug.schedule_off_time}`
@@ -503,7 +503,7 @@ export function SmartPlugCard({ plug, onEdit }: SmartPlugCardProps) {
                   size="sm"
                   variant="secondary"
                   onClick={() => setShowDeleteConfirm(true)}
-                  className="text-red-400 hover:text-red-300"
+                  className="text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300"
                 >
                   <Trash2 className="w-4 h-4" />
                 </Button>

+ 2 - 2
frontend/src/components/SpoolCatalogSettings.tsx

@@ -255,8 +255,8 @@ export function SpoolCatalogSettings() {
         </div>
 
         {selectedIds.size > 0 && (
-          <div className="flex items-center gap-2 mt-2 px-3 py-2 bg-red-500/10 border border-red-500/30 rounded-lg">
-            <span className="text-sm text-red-400">
+          <div className="flex items-center gap-2 mt-2 px-3 py-2 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded-lg">
+            <span className="text-sm text-red-700 dark:text-red-400">
               {t('settings.catalog.selectedCount', { count: selectedIds.size })}
             </span>
             <button

+ 9 - 9
frontend/src/components/SpoolCsvImportModal.tsx

@@ -125,9 +125,9 @@ export function SpoolCsvImportModal({ onClose, onImported }: SpoolCsvImportModal
           )}
 
           {error && (
-            <div className="p-3 bg-red-500/10 border border-red-500/30 rounded-lg flex items-start gap-3">
-              <XCircle className="w-5 h-5 text-red-400 mt-0.5 flex-shrink-0" />
-              <p className="text-sm text-red-300 break-words">{error}</p>
+            <div className="p-3 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded-lg flex items-start gap-3">
+              <XCircle className="w-5 h-5 text-red-600 dark:text-red-400 mt-0.5 flex-shrink-0" />
+              <p className="text-sm text-red-700 dark:text-red-300 break-words">{error}</p>
             </div>
           )}
 
@@ -135,10 +135,10 @@ export function SpoolCsvImportModal({ onClose, onImported }: SpoolCsvImportModal
             <>
               {/* Summary */}
               <div className="flex flex-wrap gap-3 text-sm">
-                <span className="px-2 py-1 rounded bg-green-500/10 text-green-400">
+                <span className="px-2 py-1 rounded bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400">
                   {t('inventory.csv.validCount', '{{count}} valid', { count: preview.valid_count })}
                 </span>
-                <span className="px-2 py-1 rounded bg-red-500/10 text-red-400">
+                <span className="px-2 py-1 rounded bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400">
                   {t('inventory.csv.errorCount', '{{count}} error', { count: preview.error_count })}
                 </span>
                 <span className="px-2 py-1 rounded bg-bambu-dark text-bambu-gray">
@@ -147,9 +147,9 @@ export function SpoolCsvImportModal({ onClose, onImported }: SpoolCsvImportModal
               </div>
 
               {preview.warnings.length > 0 && (
-                <div className="p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg space-y-1">
+                <div className="p-3 bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30 rounded-lg space-y-1">
                   {preview.warnings.map((w, i) => (
-                    <p key={i} className="text-xs text-yellow-300">{w}</p>
+                    <p key={i} className="text-xs text-yellow-700 dark:text-yellow-300">{w}</p>
                   ))}
                 </div>
               )}
@@ -176,7 +176,7 @@ export function SpoolCsvImportModal({ onClose, onImported }: SpoolCsvImportModal
                               <div className="flex items-center gap-1.5">
                                 {statusIcon(row.status)}
                                 {row.status === 'error' && row.reason && (
-                                  <span className="text-xs text-red-400 break-words">{row.reason}</span>
+                                  <span className="text-xs text-red-700 dark:text-red-400 break-words">{row.reason}</span>
                                 )}
                               </div>
                             </td>
@@ -203,7 +203,7 @@ export function SpoolCsvImportModal({ onClose, onImported }: SpoolCsvImportModal
                                 )}
                                 {row.duplicate_of_existing && (
                                   <span title={t('inventory.csv.duplicateExisting', 'A spool with this material, brand and color already exists — it will still be imported as a new spool')}>
-                                    <Copy className="w-3.5 h-3.5 text-amber-400 flex-shrink-0" />
+                                    <Copy className="w-3.5 h-3.5 text-amber-600 dark:text-amber-400 flex-shrink-0" />
                                   </span>
                                 )}
                               </div>

+ 2 - 2
frontend/src/components/SpoolFormModal.tsx

@@ -817,7 +817,7 @@ export function SpoolFormModal({
         {mode === 'create' && (
           <div className="flex items-center justify-between px-4 py-2 border-b border-bambu-dark-tertiary flex-shrink-0">
             <div className="flex items-center gap-2">
-              <Zap className="w-4 h-4 text-amber-400" />
+              <Zap className="w-4 h-4 text-amber-600 dark:text-amber-400" />
               <span className="text-sm text-white">{t('inventory.quickAdd')}</span>
             </div>
             <button
@@ -880,7 +880,7 @@ export function SpoolFormModal({
               {spoolmanMode && !isEditing && (
                 <div>
                   {filamentsError ? (
-                    <p className="text-sm text-red-400 px-1">{t('inventory.spoolmanCatalogLoadFailed')}</p>
+                    <p className="text-sm text-red-700 dark:text-red-400 px-1">{t('inventory.spoolmanCatalogLoadFailed')}</p>
                   ) : (
                     <SpoolmanFilamentPicker
                       filaments={spoolmanFilaments}

+ 3 - 3
frontend/src/components/SpoolUsageHistory.tsx

@@ -19,8 +19,8 @@ interface SpoolUsageHistoryProps {
 
 const STATUS_COLORS: Record<string, string> = {
   completed: 'text-bambu-green',
-  failed: 'text-red-400',
-  aborted: 'text-yellow-400',
+  failed: 'text-red-700 dark:text-red-400',
+  aborted: 'text-yellow-700 dark:text-yellow-400',
 };
 
 export function SpoolUsageHistory({ spoolId }: SpoolUsageHistoryProps) {
@@ -67,7 +67,7 @@ export function SpoolUsageHistory({ spoolId }: SpoolUsageHistoryProps) {
           size="sm"
           onClick={() => clearMutation.mutate()}
           disabled={clearMutation.isPending}
-          className="text-xs text-bambu-gray hover:text-red-400"
+          className="text-xs text-bambu-gray hover:text-red-700 dark:hover:text-red-400"
         >
           <Trash2 className="w-3 h-3 mr-1" />
           {t('inventory.clearHistory')}

+ 17 - 17
frontend/src/components/SpoolmanSettings.tsx

@@ -345,18 +345,18 @@ export function SpoolmanSettings() {
         {localEnabled && (
           <div className="space-y-4">
             {/* Info banner about sync requirements */}
-            <div className="p-3 bg-blue-500/10 border border-blue-500/30 rounded-lg">
+            <div className="p-3 bg-blue-50 dark:bg-blue-500/10 border border-blue-300 dark:border-blue-500/30 rounded-lg">
               <div className="flex gap-2">
-                <Info className="w-4 h-4 text-blue-400 flex-shrink-0 mt-0.5" />
-                <div className="text-xs text-blue-300">
+                <Info className="w-4 h-4 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" />
+                <div className="text-xs text-blue-700 dark:text-blue-300">
                   <p className="font-medium mb-1">{t('settings.howSyncWorks')}</p>
-                  <ul className="list-disc list-inside space-y-0.5 text-blue-300/80">
+                  <ul className="list-disc list-inside space-y-0.5 text-blue-700/90 dark:text-blue-300/80">
                     <li>{t('settings.syncInfoRfidOnly')}</li>
                     <li>{t('settings.syncInfoAutoCreate')}</li>
                     <li>{t('settings.syncInfoThirdPartySkipped')}</li>
                   </ul>
                   <p className="font-medium mt-2 mb-1">{t('settings.linkingExistingSpools')}</p>
-                  <p className="text-blue-300/80">
+                  <p className="text-blue-700/90 dark:text-blue-300/80">
                     {t('settings.linkingExistingSpoolsDesc')}
                   </p>
                 </div>
@@ -495,7 +495,7 @@ export function SpoolmanSettings() {
 
               {/* Error display */}
               {(connectMutation.isError || disconnectMutation.isError) && (
-                <div className="mb-3 p-2 bg-red-500/20 border border-red-500/50 rounded text-sm text-red-400">
+                <div className="mb-3 p-2 bg-red-100 dark:bg-red-500/20 border border-red-300 dark:border-red-500/50 rounded text-sm text-red-700 dark:text-red-400">
                   {((connectMutation.error || disconnectMutation.error) as Error).message}
                 </div>
               )}
@@ -576,8 +576,8 @@ export function SpoolmanSettings() {
                   <div
                     className={`p-2 rounded text-sm ${
                       syncResult.success
-                        ? 'bg-green-500/20 border border-green-500/50 text-green-400'
-                        : 'bg-yellow-500/20 border border-yellow-500/50 text-yellow-400'
+                        ? 'bg-green-100 dark:bg-green-500/20 border border-green-300 dark:border-green-500/50 text-green-700 dark:text-green-400'
+                        : 'bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-300 dark:border-yellow-500/50 text-yellow-700 dark:text-yellow-400'
                     }`}
                   >
                     {syncResult.success
@@ -587,8 +587,8 @@ export function SpoolmanSettings() {
 
                   {/* Skipped spools */}
                   {syncResult.skipped_count > 0 && (
-                    <div className="p-2 bg-amber-500/10 border border-amber-500/30 rounded text-sm">
-                      <div className="flex items-center justify-between text-amber-400 mb-1">
+                    <div className="p-2 bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 rounded text-sm">
+                      <div className="flex items-center justify-between text-amber-700 dark:text-amber-400 mb-1">
                         <div className="flex items-center gap-1.5">
                           <AlertTriangle className="w-3.5 h-3.5" />
                           <span className="font-medium">
@@ -598,13 +598,13 @@ export function SpoolmanSettings() {
                         {syncResult.skipped_count > 5 && (
                           <button
                             onClick={() => setShowAllSkipped(!showAllSkipped)}
-                            className="text-xs text-amber-400 hover:text-amber-300 underline"
+                            className="text-xs text-amber-700 dark:text-amber-400 hover:text-amber-800 dark:hover:text-amber-300 underline"
                           >
                             {showAllSkipped ? 'Show less' : 'Show all'}
                           </button>
                         )}
                       </div>
-                      <ul className="text-xs text-amber-300/80 space-y-0.5">
+                      <ul className="text-xs text-amber-700/90 dark:text-amber-300/80 space-y-0.5">
                         {(showAllSkipped ? syncResult.skipped : syncResult.skipped.slice(0, 5)).map((s, i) => (
                           <li key={i} className="flex items-center gap-2">
                             {s.color && (
@@ -614,11 +614,11 @@ export function SpoolmanSettings() {
                               />
                             )}
                             <span>{s.location}</span>
-                            <span className="text-amber-300/60">- {s.reason}</span>
+                            <span className="text-amber-700/70 dark:text-amber-300/60">- {s.reason}</span>
                           </li>
                         ))}
                         {!showAllSkipped && syncResult.skipped_count > 5 && (
-                          <li className="text-amber-300/60 italic">
+                          <li className="text-amber-700/70 dark:text-amber-300/60 italic">
                             ...and {syncResult.skipped_count - 5} more
                           </li>
                         )}
@@ -628,9 +628,9 @@ export function SpoolmanSettings() {
 
                   {/* Errors */}
                   {syncResult.errors.length > 0 && (
-                    <div className="p-2 bg-red-500/10 border border-red-500/30 rounded text-sm">
-                      <div className="text-red-400 font-medium mb-1">Errors:</div>
-                      <ul className="text-xs text-red-300/80 space-y-0.5">
+                    <div className="p-2 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded text-sm">
+                      <div className="text-red-700 dark:text-red-400 font-medium mb-1">Errors:</div>
+                      <ul className="text-xs text-red-700/90 dark:text-red-300/80 space-y-0.5">
                         {syncResult.errors.map((err, i) => (
                           <li key={i}>{err}</li>
                         ))}

+ 6 - 6
frontend/src/components/SwitchbarPopover.tsx

@@ -53,9 +53,9 @@ function SwitchItem({ plug }: { plug: SmartPlug }) {
               : (isReachable ? (isOn ? 'bg-bambu-green/20' : 'bg-bambu-dark') : 'bg-red-500/20')
           }`}>
             {isMqtt ? (
-              <Radio className={`w-4 h-4 ${isReachable ? 'text-teal-400' : 'text-red-400'}`} />
+              <Radio className={`w-4 h-4 ${isReachable ? 'text-teal-600 dark:text-teal-400' : 'text-red-600 dark:text-red-400'}`} />
             ) : (
-              <Plug className={`w-4 h-4 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-400'}`} />
+              <Plug className={`w-4 h-4 ${isReachable ? (isOn ? 'text-bambu-green' : 'text-bambu-gray') : 'text-red-600 dark:text-red-400'}`} />
             )}
           </div>
           <div>
@@ -67,8 +67,8 @@ function SwitchItem({ plug }: { plug: SmartPlug }) {
                 /* MQTT plugs show power and monitor-only indicator */
                 isReachable ? (
                   <>
-                    <Zap className="w-3 h-3 text-teal-400" />
-                    <span className="text-teal-400">{Math.round(status?.energy?.power ?? 0)}W</span>
+                    <Zap className="w-3 h-3 text-teal-600 dark:text-teal-400" />
+                    <span className="text-teal-700 dark:text-teal-400">{Math.round(status?.energy?.power ?? 0)}W</span>
                     <span className="text-bambu-gray mx-1">|</span>
                     <Eye className="w-3 h-3 text-bambu-gray" />
                     <span className="text-bambu-gray">Monitor</span>
@@ -86,8 +86,8 @@ function SwitchItem({ plug }: { plug: SmartPlug }) {
                   {status?.energy?.power !== null && status?.energy?.power !== undefined && (
                     <>
                       <span className="text-bambu-gray mx-1">|</span>
-                      <Zap className="w-3 h-3 text-yellow-400" />
-                      <span className="text-yellow-400">{Math.round(status.energy.power)}W</span>
+                      <Zap className="w-3 h-3 text-yellow-600 dark:text-yellow-400" />
+                      <span className="text-yellow-700 dark:text-yellow-400">{Math.round(status.energy.power)}W</span>
                     </>
                   )}
                 </>

+ 4 - 4
frontend/src/components/SystemHealthPanel.tsx

@@ -7,8 +7,8 @@ const WIKI_TROUBLESHOOTING = 'https://wiki.bambuddy.cool/reference/troubleshooti
 
 const CATEGORY_META: Record<LogFindingCategory, { icon: ElementType; badgeClass: string }> = {
   layer8: { icon: Wrench, badgeClass: 'bg-bambu-green/15 text-bambu-green border-bambu-green/30' },
-  environment: { icon: ServerCog, badgeClass: 'bg-amber-500/15 text-amber-300 border-amber-500/30' },
-  bug: { icon: Bug, badgeClass: 'bg-red-500/15 text-red-300 border-red-500/30' },
+  environment: { icon: ServerCog, badgeClass: 'bg-amber-100 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300 border-amber-300 dark:border-amber-500/30' },
+  bug: { icon: Bug, badgeClass: 'bg-red-100 dark:bg-red-500/15 text-red-700 dark:text-red-300 border-red-300 dark:border-red-500/30' },
 };
 
 /**
@@ -25,7 +25,7 @@ function FindingCard({ finding }: { finding: LogFinding }) {
   const meta = CATEGORY_META[finding.category] ?? CATEGORY_META.bug;
   const CategoryIcon = meta.icon;
   const SeverityIcon = finding.severity === 'error' ? XCircle : AlertTriangle;
-  const severityColor = finding.severity === 'error' ? 'text-red-400' : 'text-amber-400';
+  const severityColor = finding.severity === 'error' ? 'text-red-600 dark:text-red-400' : 'text-amber-600 dark:text-amber-400';
 
   return (
     <div className="bg-bambu-dark rounded-lg border border-bambu-dark-tertiary p-4 space-y-2">
@@ -82,7 +82,7 @@ export function SystemHealthPanel({ result }: { result: SystemHealthResult }) {
 
   if (!result.log_available) {
     return (
-      <div className="rounded-lg bg-amber-500/10 border border-amber-500/30 px-4 py-3 text-sm text-amber-300">
+      <div className="rounded-lg bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 px-4 py-3 text-sm text-amber-700 dark:text-amber-300">
         {t('systemHealth.logUnavailable')}
       </div>
     );

+ 2 - 2
frontend/src/components/TagManagementModal.tsx

@@ -223,7 +223,7 @@ export function TagManagementModal({ onClose }: TagManagementModalProps) {
                     ) : deleteConfirm === tag.name ? (
                       // Delete confirmation
                       <div className="flex-1 flex items-center gap-2">
-                        <AlertTriangle className="w-4 h-4 text-yellow-400 flex-shrink-0" />
+                        <AlertTriangle className="w-4 h-4 text-yellow-600 dark:text-yellow-400 flex-shrink-0" />
                         <span className="text-sm text-bambu-gray-light flex-1">
                           Delete "{tag.name}" from {tag.count} archive{tag.count !== 1 ? 's' : ''}?
                         </span>
@@ -267,7 +267,7 @@ export function TagManagementModal({ onClose }: TagManagementModalProps) {
                           </button>
                           <button
                             onClick={() => confirmDelete(tag.name)}
-                            className="p-1.5 rounded hover:bg-bambu-dark text-bambu-gray hover:text-red-400 transition-colors"
+                            className="p-1.5 rounded hover:bg-bambu-dark text-bambu-gray hover:text-red-700 dark:hover:text-red-400 transition-colors"
                             title="Delete tag"
                           >
                             <Trash2 className="w-4 h-4" />

+ 2 - 2
frontend/src/components/TimelapseEditorModal.tsx

@@ -491,9 +491,9 @@ export function TimelapseEditorModal({
 
                 <button
                   onClick={removeAudio}
-                  className="p-2 hover:bg-red-500/20 rounded transition-colors"
+                  className="p-2 hover:bg-red-100 dark:hover:bg-red-500/20 rounded transition-colors"
                 >
-                  <Trash2 className="w-4 h-4 text-red-400" />
+                  <Trash2 className="w-4 h-4 text-red-600 dark:text-red-400" />
                 </button>
               </div>
             ) : (

+ 9 - 9
frontend/src/components/TwoFactorSettings.tsx

@@ -46,8 +46,8 @@ function BackupCodesDisplay({ codes, onDone }: { codes: string[]; onDone: () =>
 
   return (
     <div className="space-y-4">
-      <div className="bg-amber-500/10 border border-amber-500/30 rounded-lg p-4">
-        <p className="text-amber-400 text-sm font-medium">{t('settings.twoFa.backupCodesWarning')}</p>
+      <div className="bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 rounded-lg p-4">
+        <p className="text-amber-700 dark:text-amber-400 text-sm font-medium">{t('settings.twoFa.backupCodesWarning')}</p>
       </div>
       <div className="grid grid-cols-2 gap-2">
         {codes.map((code, index) => (
@@ -289,8 +289,8 @@ export function TwoFactorSettings() {
       <Card id="card-2fa-totp">
         <CardHeader>
           <div className="flex items-center gap-3">
-            <div className={`w-10 h-10 rounded-full flex items-center justify-center ${status?.totp_enabled ? 'bg-green-500/20' : 'bg-gray-500/20'}`}>
-              <Smartphone className={`w-5 h-5 ${status?.totp_enabled ? 'text-green-400' : 'text-gray-400'}`} />
+            <div className={`w-10 h-10 rounded-full flex items-center justify-center ${status?.totp_enabled ? 'bg-green-100 dark:bg-green-500/20' : 'bg-gray-500/20'}`}>
+              <Smartphone className={`w-5 h-5 ${status?.totp_enabled ? 'text-green-600 dark:text-green-400' : 'text-gray-400'}`} />
             </div>
             <div>
               <h3 className="text-white font-semibold">{t('settings.twoFa.totpTitle')}</h3>
@@ -298,7 +298,7 @@ export function TwoFactorSettings() {
             </div>
             <div className="ml-auto">
               {status?.totp_enabled ? (
-                <span className="flex items-center gap-1 text-green-400 text-sm font-medium">
+                <span className="flex items-center gap-1 text-green-700 dark:text-green-400 text-sm font-medium">
                   <ShieldCheck className="w-4 h-4" /> {t('common.enabled')}
                 </span>
               ) : (
@@ -394,8 +394,8 @@ export function TwoFactorSettings() {
       <Card id="card-2fa-emailotp">
         <CardHeader>
           <div className="flex items-center gap-3">
-            <div className={`w-10 h-10 rounded-full flex items-center justify-center ${status?.email_otp_enabled ? 'bg-green-500/20' : 'bg-gray-500/20'}`}>
-              <Mail className={`w-5 h-5 ${status?.email_otp_enabled ? 'text-green-400' : 'text-gray-400'}`} />
+            <div className={`w-10 h-10 rounded-full flex items-center justify-center ${status?.email_otp_enabled ? 'bg-green-100 dark:bg-green-500/20' : 'bg-gray-500/20'}`}>
+              <Mail className={`w-5 h-5 ${status?.email_otp_enabled ? 'text-green-600 dark:text-green-400' : 'text-gray-400'}`} />
             </div>
             <div className="flex-1">
               <h3 className="text-white font-semibold">{t('settings.twoFa.emailOtpTitle')}</h3>
@@ -408,7 +408,7 @@ export function TwoFactorSettings() {
             {/* Show status badge; enable/disable handled in CardContent */}
             <div className="ml-auto">
               {status?.email_otp_enabled ? (
-                <span className="flex items-center gap-1 text-green-400 text-sm font-medium">
+                <span className="flex items-center gap-1 text-green-700 dark:text-green-400 text-sm font-medium">
                   <ShieldCheck className="w-4 h-4" /> {t('common.enabled')}
                 </span>
               ) : (
@@ -421,7 +421,7 @@ export function TwoFactorSettings() {
         </CardHeader>
         <CardContent>
           {!hasEmail ? (
-            <p className="text-amber-400 text-sm">{t('settings.twoFa.addEmailFirst')}</p>
+            <p className="text-amber-700 dark:text-amber-400 text-sm">{t('settings.twoFa.addEmailFirst')}</p>
           ) : emailSetupToken ? (
             /* Step 2: enter the code that was sent to the email */
             <div className="space-y-4">

+ 4 - 4
frontend/src/components/UploadModal.tsx

@@ -222,7 +222,7 @@ export function UploadModal({ onClose, initialFiles }: UploadModalProps) {
                     {f.status === 'pending' && (
                       <button
                         onClick={() => removeFile(index)}
-                        className="text-bambu-gray hover:text-red-400 transition-colors"
+                        className="text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors"
                         disabled={isUploading}
                       >
                         <X className="w-4 h-4" />
@@ -236,8 +236,8 @@ export function UploadModal({ onClose, initialFiles }: UploadModalProps) {
                     )}
                     {f.status === 'error' && (
                       <div className="flex items-center gap-2">
-                        <span className="text-xs text-red-400">{f.error}</span>
-                        <AlertCircle className="w-4 h-4 text-red-400" />
+                        <span className="text-xs text-red-700 dark:text-red-400">{f.error}</span>
+                        <AlertCircle className="w-4 h-4 text-red-600 dark:text-red-400" />
                       </div>
                     )}
                   </div>
@@ -253,7 +253,7 @@ export function UploadModal({ onClose, initialFiles }: UploadModalProps) {
                 <p className="text-sm text-white">
                   <span className="text-bambu-green">{uploadResult.uploaded}</span> {t('uploadModal.uploaded')}
                   {uploadResult.failed > 0 && (
-                    <>, <span className="text-red-400">{uploadResult.failed}</span> {t('uploadModal.failed')}</>
+                    <>, <span className="text-red-700 dark:text-red-400">{uploadResult.failed}</span> {t('uploadModal.failed')}</>
                   )}
                 </p>
               </div>

+ 9 - 9
frontend/src/components/VirtualPrinterCard.tsx

@@ -318,7 +318,7 @@ export function VirtualPrinterCard({ printer, models }: VirtualPrinterCardProps)
               </button>
               <button
                 onClick={() => setShowDeleteConfirm(true)}
-                className="p-1.5 text-bambu-gray hover:text-red-400 transition-colors flex-shrink-0"
+                className="p-1.5 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors flex-shrink-0"
                 title={t('common.delete')}
               >
                 <Trash2 className="w-4 h-4" />
@@ -329,7 +329,7 @@ export function VirtualPrinterCard({ printer, models }: VirtualPrinterCardProps)
                 Shown only when this VP is marked Tailscale-exposed AND the daemon is up. */}
             <div className="flex items-center gap-2 -mt-2">
               {tailscaleFqdn && (
-                <span className="flex items-center gap-1 text-green-400/70 min-w-0">
+                <span className="flex items-center gap-1 text-green-700/80 dark:text-green-400/70 min-w-0">
                   <ShieldCheck className="w-3.5 h-3.5 flex-shrink-0" />
                   <span className="font-mono text-xs truncate">
                     {tailscaleIp ? `${tailscaleIp} (${tailscaleFqdn})` : tailscaleFqdn}
@@ -521,8 +521,8 @@ export function VirtualPrinterCard({ printer, models }: VirtualPrinterCardProps)
             {/* Proxy mode: hint about using target printer's access code */}
             {localMode === 'proxy' && (
               <div className="pt-2 border-t border-bambu-dark-tertiary">
-                <div className="flex items-start gap-2 p-2 rounded bg-blue-500/10 border border-blue-500/30">
-                  <Info className="w-4 h-4 text-blue-400 flex-shrink-0 mt-0.5" />
+                <div className="flex items-start gap-2 p-2 rounded bg-blue-50 border border-blue-300 dark:bg-blue-500/10 dark:border-blue-500/30">
+                  <Info className="w-4 h-4 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" />
                   <p className="text-xs text-bambu-gray">
                     {t('virtualPrinter.proxy.accessCodeHint')}
                   </p>
@@ -536,17 +536,17 @@ export function VirtualPrinterCard({ printer, models }: VirtualPrinterCardProps)
                 <div className="flex items-center gap-2 mb-2">
                   <div className="text-white text-sm font-medium">{t('virtualPrinter.accessCode.title')}</div>
                   {inheritsAccessCodeFromTarget ? (
-                    <span className="flex items-center gap-1 text-xs text-blue-400">
+                    <span className="flex items-center gap-1 text-xs text-blue-700 dark:text-blue-400">
                       <Info className="w-3 h-3" />
                       {t('virtualPrinter.accessCode.inheritedFromTarget')}
                     </span>
                   ) : printer.access_code_set ? (
-                    <span className="flex items-center gap-1 text-xs text-green-400">
+                    <span className="flex items-center gap-1 text-xs text-green-700 dark:text-green-400">
                       <Check className="w-3 h-3" />
                       {t('virtualPrinter.accessCode.isSet')}
                     </span>
                   ) : (
-                    <span className="flex items-center gap-1 text-xs text-yellow-400">
+                    <span className="flex items-center gap-1 text-xs text-yellow-700 dark:text-yellow-400">
                       <AlertTriangle className="w-3 h-3" />
                       {t('virtualPrinter.accessCode.notSet')}
                     </span>
@@ -603,7 +603,7 @@ export function VirtualPrinterCard({ printer, models }: VirtualPrinterCardProps)
                     </div>
                     {localAccessCode && (
                       <p className="text-xs text-bambu-gray mt-1">
-                        <span className={localAccessCode.length === 8 ? 'text-green-400' : 'text-yellow-400'}>
+                        <span className={localAccessCode.length === 8 ? 'text-green-700 dark:text-green-400' : 'text-yellow-700 dark:text-yellow-400'}>
                           {t('virtualPrinter.accessCode.charCount', { count: localAccessCode.length })}
                         </span>
                       </p>
@@ -666,7 +666,7 @@ export function VirtualPrinterCard({ printer, models }: VirtualPrinterCardProps)
               <div className="flex items-center gap-2 mb-1">
                 <div className="text-white text-sm font-medium">{t('virtualPrinter.remoteInterface.title')}</div>
                 {localRemoteInterfaceIp ? (
-                  <span className="flex items-center gap-1 text-xs text-green-400"><Check className="w-3 h-3" /></span>
+                  <span className="flex items-center gap-1 text-xs text-green-700 dark:text-green-400"><Check className="w-3 h-3" /></span>
                 ) : (
                   <span className="flex items-center gap-1 text-xs text-bambu-gray" title={t('virtualPrinter.remoteInterface.optional')}><Info className="w-3 h-3" /></span>
                 )}

+ 5 - 5
frontend/src/components/VirtualPrinterDiagnosticModal.tsx

@@ -19,8 +19,8 @@ import {
 
 function StatusIcon({ status }: { status: VPDiagnosticStatus }) {
   if (status === 'pass') return <CheckCircle2 className="w-5 h-5 text-bambu-green flex-shrink-0" />;
-  if (status === 'fail') return <XCircle className="w-5 h-5 text-red-400 flex-shrink-0" />;
-  if (status === 'warn') return <AlertTriangle className="w-5 h-5 text-amber-400 flex-shrink-0" />;
+  if (status === 'fail') return <XCircle className="w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0" />;
+  if (status === 'warn') return <AlertTriangle className="w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0" />;
   return <MinusCircle className="w-5 h-5 text-bambu-gray flex-shrink-0" />;
 }
 
@@ -64,8 +64,8 @@ export function VirtualPrinterDiagnosticModal({
     result?.overall === 'ok'
       ? 'bg-bambu-green/10 border-bambu-green/30 text-bambu-green'
       : result?.overall === 'warnings'
-        ? 'bg-amber-500/10 border-amber-500/30 text-amber-300'
-        : 'bg-red-500/10 border-red-500/30 text-red-300';
+        ? 'bg-amber-50 dark:bg-amber-500/10 border-amber-300 dark:border-amber-500/30 text-amber-700 dark:text-amber-300'
+        : 'bg-red-50 dark:bg-red-500/10 border-red-300 dark:border-red-500/30 text-red-700 dark:text-red-300';
 
   const renderCheck = (check: VPDiagnosticCheck) => {
     const detail = t(`vpDiagnostic.check.${check.id}.${check.status}`, {
@@ -123,7 +123,7 @@ export function VirtualPrinterDiagnosticModal({
           )}
 
           {diagnose.isError && (
-            <div className="rounded-lg bg-red-500/10 border border-red-500/30 px-4 py-3 text-sm text-red-300">
+            <div className="rounded-lg bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 px-4 py-3 text-sm text-red-700 dark:text-red-300">
               {t('vpDiagnostic.runFailed', { error: (diagnose.error as Error).message })}
             </div>
           )}

+ 2 - 2
frontend/src/components/VirtualPrinterList.tsx

@@ -96,7 +96,7 @@ export function VirtualPrinterList() {
                   href="https://wiki.bambuddy.cool/features/virtual-printer/"
                   target="_blank"
                   rel="noopener noreferrer"
-                  className="inline-flex items-center gap-1.5 mt-2 px-3 py-1.5 bg-yellow-500/20 border border-yellow-500/50 rounded text-yellow-400 hover:bg-yellow-500/30 transition-colors text-xs"
+                  className="inline-flex items-center gap-1.5 mt-2 px-3 py-1.5 bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-500/50 rounded text-yellow-700 dark:text-yellow-400 hover:bg-yellow-500/30 transition-colors text-xs"
                 >
                   <ExternalLink className="w-3 h-3" />
                   {t('virtualPrinter.setupRequired.readGuide')}
@@ -109,7 +109,7 @@ export function VirtualPrinterList() {
         <Card className="lg:col-span-2">
           <CardContent className="py-3 px-4">
             <div className="flex items-start gap-2">
-              <Info className="w-4 h-4 text-blue-400 flex-shrink-0 mt-0.5" />
+              <Info className="w-4 h-4 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" />
               <div className="text-xs text-bambu-gray">
                 <p className="text-white font-medium mb-1">{t('virtualPrinter.howItWorks.title')}</p>
                 <ul className="space-y-1 list-disc list-inside">

+ 10 - 10
frontend/src/components/VirtualPrinterSettings.tsx

@@ -192,7 +192,7 @@ export function VirtualPrinterSettings() {
               <h2 className="text-lg font-semibold text-white">{t('virtualPrinter.title')}</h2>
             </div>
             {status && (
-              <div className={`flex items-center gap-2 text-sm ${isRunning ? 'text-green-400' : 'text-bambu-gray'}`}>
+              <div className={`flex items-center gap-2 text-sm ${isRunning ? 'text-green-700 dark:text-green-400' : 'text-bambu-gray'}`}>
                 <span className={`w-2 h-2 rounded-full ${isRunning ? 'bg-green-400 animate-pulse' : 'bg-gray-500'}`} />
                 {isRunning ? t('virtualPrinter.running') : t('virtualPrinter.stopped')}
               </div>
@@ -272,12 +272,12 @@ export function VirtualPrinterSettings() {
               <div className="text-white font-medium mb-2">{t('virtualPrinter.accessCode.title')}</div>
               <div className="text-sm text-bambu-gray mb-3">
                 {settings?.access_code_set ? (
-                  <span className="flex items-center gap-1 text-green-400">
+                  <span className="flex items-center gap-1 text-green-700 dark:text-green-400">
                     <Check className="w-4 h-4" />
                     {t('virtualPrinter.accessCode.isSet')}
                   </span>
                 ) : (
-                  <span className="flex items-center gap-1 text-yellow-400">
+                  <span className="flex items-center gap-1 text-yellow-700 dark:text-yellow-400">
                     <AlertTriangle className="w-4 h-4" />
                     {t('virtualPrinter.accessCode.notSet')}
                   </span>
@@ -311,7 +311,7 @@ export function VirtualPrinterSettings() {
               <p className="text-xs text-bambu-gray mt-2">
                 {t('virtualPrinter.accessCode.hint')}
                 {localAccessCode && (
-                  <span className={localAccessCode.length === 8 ? 'text-green-400' : 'text-yellow-400'}>
+                  <span className={localAccessCode.length === 8 ? 'text-green-700 dark:text-green-400' : 'text-yellow-700 dark:text-yellow-400'}>
                     {' '}{t('virtualPrinter.accessCode.charCount', { count: localAccessCode.length })}
                   </span>
                 )}
@@ -325,12 +325,12 @@ export function VirtualPrinterSettings() {
               <div className="text-white font-medium mb-2">{t('virtualPrinter.targetPrinter.title')}</div>
               <div className="text-sm text-bambu-gray mb-3">
                 {localTargetPrinterId ? (
-                  <span className="flex items-center gap-1 text-green-400">
+                  <span className="flex items-center gap-1 text-green-700 dark:text-green-400">
                     <Check className="w-4 h-4" />
                     {t('virtualPrinter.targetPrinter.configured')}
                   </span>
                 ) : (
-                  <span className="flex items-center gap-1 text-yellow-400">
+                  <span className="flex items-center gap-1 text-yellow-700 dark:text-yellow-400">
                     <AlertTriangle className="w-4 h-4" />
                     {t('virtualPrinter.targetPrinter.notConfigured')}
                   </span>
@@ -361,7 +361,7 @@ export function VirtualPrinterSettings() {
                 {t('virtualPrinter.targetPrinter.hint')}
               </p>
               {!printers?.length && (
-                <p className="text-xs text-yellow-400 mt-2">
+                <p className="text-xs text-yellow-700 dark:text-yellow-400 mt-2">
                   <AlertTriangle className="w-3 h-3 inline mr-1" />
                   {t('virtualPrinter.targetPrinter.noPrinters')}
                 </p>
@@ -375,7 +375,7 @@ export function VirtualPrinterSettings() {
               <div className="text-white font-medium mb-2">{t('virtualPrinter.remoteInterface.title')}</div>
               <div className="text-sm text-bambu-gray mb-3">
                 {localRemoteInterfaceIp ? (
-                  <span className="flex items-center gap-1 text-green-400">
+                  <span className="flex items-center gap-1 text-green-700 dark:text-green-400">
                     <Check className="w-4 h-4" />
                     {t('virtualPrinter.remoteInterface.configured')}
                   </span>
@@ -487,7 +487,7 @@ export function VirtualPrinterSettings() {
                   href="https://wiki.bambuddy.cool/features/virtual-printer/"
                   target="_blank"
                   rel="noopener noreferrer"
-                  className="inline-flex items-center gap-2 px-4 py-2 bg-yellow-500/20 border border-yellow-500/50 rounded-md text-yellow-400 hover:bg-yellow-500/30 transition-colors"
+                  className="inline-flex items-center gap-2 px-4 py-2 bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-500/50 rounded-md text-yellow-700 dark:text-yellow-400 hover:bg-yellow-500/30 transition-colors"
                 >
                   <ExternalLink className="w-4 h-4" />
                   {t('virtualPrinter.setupRequired.readGuide')}
@@ -501,7 +501,7 @@ export function VirtualPrinterSettings() {
         <Card>
           <CardContent className="py-4">
             <div className="flex items-start gap-3">
-              <Info className="w-5 h-5 text-blue-400 flex-shrink-0 mt-0.5" />
+              <Info className="w-5 h-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" />
               <div className="text-sm text-bambu-gray">
                 <p className="mb-2">
                   <strong className="text-white">{localMode === 'proxy' ? t('virtualPrinter.howItWorks.titleProxy') : t('virtualPrinter.howItWorks.title')}:</strong>

+ 1 - 1
frontend/src/components/spool-form/ColorSection.tsx

@@ -495,7 +495,7 @@ export function ColorSection({
             data-testid="extra-colors-input"
           />
           {extraColorsErrors.length > 0 && (
-            <p className="text-xs text-red-400 mt-1">
+            <p className="text-xs text-red-700 dark:text-red-400 mt-1">
               {t('inventory.extraColorsInvalid', { tokens: extraColorsErrors.join(', ') })}
             </p>
           )}

+ 4 - 4
frontend/src/components/spool-form/FilamentSection.tsx

@@ -186,7 +186,7 @@ export function FilamentSection({
             </div>
           )}
           {errors?.slicer_filament && (
-            <p className="mt-1 text-xs text-red-400">{errors.slicer_filament}</p>
+            <p className="mt-1 text-xs text-red-700 dark:text-red-400">{errors.slicer_filament}</p>
           )}
         </div>
       )}
@@ -250,7 +250,7 @@ export function FilamentSection({
           )}
         </div>
         {errors?.material && (
-          <p className="mt-1 text-xs text-red-400">{errors.material}</p>
+          <p className="mt-1 text-xs text-red-700 dark:text-red-400">{errors.material}</p>
         )}
       </div>
 
@@ -315,7 +315,7 @@ export function FilamentSection({
             )}
           </div>
           {errors?.brand && (
-            <p className="mt-1 text-xs text-red-400">{errors.brand}</p>
+            <p className="mt-1 text-xs text-red-700 dark:text-red-400">{errors.brand}</p>
           )}
       </div>
 
@@ -379,7 +379,7 @@ export function FilamentSection({
             )}
           </div>
           {errors?.subtype && (
-            <p className="mt-1 text-xs text-red-400">{errors.subtype}</p>
+            <p className="mt-1 text-xs text-red-700 dark:text-red-400">{errors.subtype}</p>
           )}
       </div>
 

+ 26 - 26
frontend/src/pages/ArchivesPage.tsx

@@ -973,7 +973,7 @@ function ArchiveCard({
             className={`text-[10px] px-1.5 py-0.5 rounded font-medium ${
               isSlicedFile(archive)
                 ? 'bg-bambu-green/20 text-bambu-green'
-                : 'bg-orange-500/20 text-orange-400'
+                : 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400'
             }`}
             title={
               isSlicedFile(archive)
@@ -1039,8 +1039,8 @@ function ArchiveCard({
                   archive.time_accuracy >= 95 && archive.time_accuracy <= 105
                     ? 'bg-bambu-green/20 text-bambu-green'
                     : archive.time_accuracy > 105
-                      ? 'bg-blue-500/20 text-blue-400'
-                      : 'bg-orange-500/20 text-orange-400'
+                      ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400'
+                      : 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400'
                 }`}>
                   {archive.time_accuracy > 100 ? '+' : ''}{(archive.time_accuracy - 100).toFixed(0)}%
                 </span>
@@ -1113,7 +1113,7 @@ function ArchiveCard({
           <div className="flex flex-wrap items-center gap-1.5 mb-3">
             {archive.notes && (
               <div
-                className="flex items-center gap-1 px-1.5 py-0.5 bg-blue-500/20 text-blue-400 rounded text-xs"
+                className="flex items-center gap-1 px-1.5 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 rounded text-xs"
                 title={archive.notes}
               >
                 <StickyNote className="w-3 h-3" />
@@ -1240,7 +1240,7 @@ function ArchiveCard({
             disabled={!canModify('archives', 'delete', archive.created_by_id)}
             title={!canModify('archives', 'delete', archive.created_by_id) ? t('archives.card.noPermissionDelete') : t('archives.card.delete')}
           >
-            <Trash2 className="w-3 h-3 sm:w-4 sm:h-4 text-red-400" />
+            <Trash2 className="w-3 h-3 sm:w-4 sm:h-4 text-red-600 dark:text-red-400" />
           </Button>
         </div>
       </CardContent>
@@ -1325,8 +1325,8 @@ function ArchiveCard({
             <div
               className={
                 (deleteImpactQuery.data?.currently_printing ?? 0) > 0
-                  ? 'text-sm text-red-400 mb-2'
-                  : 'text-sm text-amber-400 mb-2'
+                  ? 'text-sm text-red-600 dark:text-red-400 mb-2'
+                  : 'text-sm text-amber-600 dark:text-amber-400 mb-2'
               }
             >
               {(deleteImpactQuery.data?.currently_printing ?? 0) > 0
@@ -2139,7 +2139,7 @@ function ArchiveListRow({
                 title={t('archives.card.openFolder', { name: linkedFolders[0].name })}
                 onClick={(e) => e.stopPropagation()}
               >
-                <FolderOpen className="w-3.5 h-3.5 text-yellow-400" />
+                <FolderOpen className="w-3.5 h-3.5 text-yellow-600 dark:text-yellow-400" />
               </Link>
             )}
           </div>
@@ -2255,7 +2255,7 @@ function ArchiveListRow({
             disabled={!canModify('archives', 'delete', archive.created_by_id)}
             title={!canModify('archives', 'delete', archive.created_by_id) ? t('archives.card.noPermissionDelete') : t('archives.card.delete')}
           >
-            <Trash2 className="w-4 h-4 text-red-400" />
+            <Trash2 className="w-4 h-4 text-red-600 dark:text-red-400" />
           </Button>
           <Button
             variant="ghost"
@@ -2351,8 +2351,8 @@ function ArchiveListRow({
             <div
               className={
                 (deleteImpactQuery.data?.currently_printing ?? 0) > 0
-                  ? 'text-sm text-red-400 mb-2'
-                  : 'text-sm text-amber-400 mb-2'
+                  ? 'text-sm text-red-600 dark:text-red-400 mb-2'
+                  : 'text-sm text-amber-600 dark:text-amber-400 mb-2'
               }
             >
               {(deleteImpactQuery.data?.currently_printing ?? 0) > 0
@@ -3272,19 +3272,19 @@ export function ArchivesPage() {
       )}
 
       {no3MFWarning?.has_fallback && !no3MFWarningDismissed && (
-        <div className="mb-6 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-3 flex items-start gap-3">
-          <AlertCircle className="w-5 h-5 text-amber-400 flex-shrink-0 mt-0.5" />
+        <div className="mb-6 rounded-lg border border-amber-300 dark:border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 px-4 py-3 flex items-start gap-3">
+          <AlertCircle className="w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
           <div className="flex-1 min-w-0">
-            <div className="text-sm font-medium text-amber-200">
+            <div className="text-sm font-medium text-amber-900 dark:text-amber-200">
               {t('archives.no3mfBanner.title')}
             </div>
-            <div className="text-xs text-amber-200/80 mt-1">
+            <div className="text-xs text-amber-800/90 dark:text-amber-200/80 mt-1">
               {t('archives.no3mfBanner.body')}{' '}
               <a
                 href="https://wiki.bambuddy.cool/getting-started/#step-4-enable-store-sent-files-on-external-storage"
                 target="_blank"
                 rel="noreferrer"
-                className="underline hover:text-amber-100 inline-flex items-center gap-1"
+                className="underline hover:text-amber-900 dark:hover:text-amber-100 inline-flex items-center gap-1"
               >
                 {t('archives.no3mfBanner.docsLink')}
                 <ExternalLink className="w-3 h-3" />
@@ -3293,7 +3293,7 @@ export function ArchivesPage() {
           </div>
           <button
             onClick={dismissNo3MFWarning}
-            className="text-amber-200/60 hover:text-amber-200 flex-shrink-0 p-1 -m-1"
+            className="text-amber-800/70 dark:text-amber-200/60 hover:text-amber-900 dark:hover:text-amber-200 flex-shrink-0 p-1 -m-1"
             title={t('archives.no3mfBanner.dismissLabel')}
             aria-label={t('archives.no3mfBanner.dismissLabel')}
           >
@@ -3542,7 +3542,7 @@ export function ArchivesPage() {
               onClick={() => setFilterFavorites(!filterFavorites)}
               className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${
                 filterFavorites
-                  ? 'bg-yellow-500/20 border-yellow-500 text-yellow-400'
+                  ? 'bg-yellow-100 dark:bg-yellow-500/20 border-yellow-500 text-yellow-700 dark:text-yellow-400'
                   : 'bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white'
               }`}
               title={filterFavorites ? t('archives.showAll') : t('archives.showFavoritesOnly')}
@@ -3554,7 +3554,7 @@ export function ArchivesPage() {
               onClick={() => setHideFailed(!hideFailed)}
               className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${
                 hideFailed
-                  ? 'bg-red-500/20 border-red-500 text-red-400'
+                  ? 'bg-red-100 dark:bg-red-500/20 border-red-500 text-red-700 dark:text-red-400'
                   : 'bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white'
               }`}
               title={hideFailed ? t('archives.showFailedPrints') : t('archives.hideFailedPrints')}
@@ -3566,7 +3566,7 @@ export function ArchivesPage() {
               onClick={() => setHideDuplicates(!hideDuplicates)}
               className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors flex-shrink-0 ${
                 hideDuplicates
-                  ? 'bg-purple-500/20 border-purple-500 text-purple-400'
+                  ? 'bg-purple-100 dark:bg-purple-500/20 border-purple-500 text-purple-700 dark:text-purple-400'
                   : 'bg-bambu-dark border-bambu-dark-tertiary text-bambu-gray hover:text-white'
               }`}
               title={t('archives.hideDuplicates')}
@@ -3914,11 +3914,11 @@ export function ArchivesPage() {
                           <td className="px-4 py-3 text-bambu-gray-light">{entry.created_by_username || '—'}</td>
                           <td className="px-4 py-3">
                             <span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${
-                              entry.status === 'completed' ? 'bg-green-500/20 text-green-400' :
-                              entry.status === 'failed' ? 'bg-red-500/20 text-red-400' :
-                              entry.status === 'stopped' ? 'bg-yellow-500/20 text-yellow-400' :
-                              entry.status === 'cancelled' ? 'bg-orange-500/20 text-orange-400' :
-                              entry.status === 'skipped' ? 'bg-blue-500/20 text-blue-400' :
+                              entry.status === 'completed' ? 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400' :
+                              entry.status === 'failed' ? 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400' :
+                              entry.status === 'stopped' ? 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400' :
+                              entry.status === 'cancelled' ? 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400' :
+                              entry.status === 'skipped' ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400' :
                               'bg-gray-500/20 text-gray-400'
                             }`}>
                               {entry.status}
@@ -3988,7 +3988,7 @@ export function ArchivesPage() {
                                     ? t('archives.log.deleteEntryTitle')
                                     : t('archives.permission.noDelete')
                                 }
-                                className="text-bambu-gray hover:text-red-400 disabled:opacity-40 disabled:hover:text-bambu-gray transition-colors"
+                                className="text-bambu-gray hover:text-red-600 dark:hover:text-red-400 disabled:opacity-40 disabled:hover:text-bambu-gray transition-colors"
                               >
                                 <Trash2 className="w-4 h-4" />
                               </button>

+ 5 - 5
frontend/src/pages/CameraTokensPage.tsx

@@ -141,7 +141,7 @@ function ConfirmRevokeModal({ token, onConfirm, onCancel }: ConfirmRevokeModalPr
     >
       <div className="bg-bambu-dark-secondary rounded-lg p-6 max-w-md w-full border border-red-500/40">
         <div className="flex items-start gap-3 mb-4">
-          <AlertTriangle className="w-6 h-6 text-red-400 flex-shrink-0 mt-0.5" />
+          <AlertTriangle className="w-6 h-6 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5" />
           <div>
             <h2 className="text-lg font-semibold text-white">
               {t('cameraTokens.confirmRevoke.title', 'Revoke this token?')}
@@ -217,7 +217,7 @@ function JustCreatedModal({ token, onClose }: JustCreatedModalProps) {
     <div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50 p-4">
       <div className="bg-bambu-dark-secondary rounded-lg p-6 max-w-2xl w-full border border-bambu-green/40">
         <div className="flex items-start gap-3 mb-4">
-          <AlertTriangle className="w-6 h-6 text-yellow-400 flex-shrink-0 mt-0.5" />
+          <AlertTriangle className="w-6 h-6 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5" />
           <div>
             <h2 className="text-lg font-semibold text-white">
               {t('cameraTokens.created.title', 'Token created — copy it now')}
@@ -273,10 +273,10 @@ function TokenRow({ token, showOwner, ownerLabel, onRevoke }: TokenRowProps) {
       {showOwner && <td className="py-3 px-3 text-bambu-gray">{ownerLabel}</td>}
       <td className="py-3 px-3 text-bambu-gray font-mono text-xs">{token.lookup_prefix}…</td>
       <td className="py-3 px-3 text-bambu-gray">{formatDate(token.created_at)}</td>
-      <td className={`py-3 px-3 ${expired ? 'text-red-400' : 'text-bambu-gray'}`}>
+      <td className={`py-3 px-3 ${expired ? 'text-red-700 dark:text-red-400' : 'text-bambu-gray'}`}>
         {formatDate(token.expires_at)}
         {expired && (
-          <span className="ml-2 px-2 py-0.5 text-xs bg-red-500/20 text-red-300 rounded">
+          <span className="ml-2 px-2 py-0.5 text-xs bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-300 rounded">
             {t('cameraTokens.list.expired', 'Expired')}
           </span>
         )}
@@ -286,7 +286,7 @@ function TokenRow({ token, showOwner, ownerLabel, onRevoke }: TokenRowProps) {
         <button
           type="button"
           onClick={() => onRevoke(token.id)}
-          className="inline-flex items-center gap-1 px-2 py-1 text-sm text-red-400 hover:text-red-300"
+          className="inline-flex items-center gap-1 px-2 py-1 text-sm text-red-700 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300"
           title={t('cameraTokens.list.revoke', 'Revoke')}
         >
           <Trash2 className="w-4 h-4" />

+ 16 - 16
frontend/src/pages/FileManagerPage.tsx

@@ -294,7 +294,7 @@ function RenameModal({ type, currentName, onClose, onSave, isLoading, t }: Renam
               )}
             </div>
             {filenameError && (
-              <p className="mt-1 text-xs text-red-400">{filenameError}</p>
+              <p className="mt-1 text-xs text-red-700 dark:text-red-400">{filenameError}</p>
             )}
           </div>
           <div className="flex justify-end gap-2 pt-2">
@@ -593,7 +593,7 @@ function FolderTreeItem({ folder, selectedFolderId, onSelect, onDelete, onLink,
           <div className="w-4.5" />
         )}
         {isExternal ? (
-          <FolderSymlink className="w-4 h-4 text-purple-400 flex-shrink-0" />
+          <FolderSymlink className="w-4 h-4 text-purple-600 dark:text-purple-400 flex-shrink-0" />
         ) : (
           <FolderOpen className="w-4 h-4 text-bambu-green flex-shrink-0" />
         )}
@@ -602,7 +602,7 @@ function FolderTreeItem({ folder, selectedFolderId, onSelect, onDelete, onLink,
         {isLinked && (
           <button
             onClick={(e) => { e.stopPropagation(); onLink(folder); }}
-            className="flex-shrink-0 flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400 hover:bg-blue-500/30 transition-colors"
+            className="flex-shrink-0 flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 hover:bg-blue-200 dark:hover:bg-blue-500/30 transition-colors"
             title={`${folder.project_name ? `Project: ${folder.project_name}` : `Archive: ${folder.archive_name}`} (click to change)`}
           >
             <Link2 className="w-3 h-3" />
@@ -616,7 +616,7 @@ function FolderTreeItem({ folder, selectedFolderId, onSelect, onDelete, onLink,
         {/* Read-only indicator for external folders */}
         {isExternal && folder.external_readonly && (
           <span title={t('fileManager.readOnly')}>
-            <Lock className="w-3 h-3 text-amber-400 flex-shrink-0" />
+            <Lock className="w-3 h-3 text-amber-600 dark:text-amber-400 flex-shrink-0" />
           </span>
         )}
         {folder.file_count > 0 && (
@@ -668,7 +668,7 @@ function FolderTreeItem({ folder, selectedFolderId, onSelect, onDelete, onLink,
                 </button>
                 <button
                   className={`w-full px-3 py-1.5 text-left text-sm flex items-center gap-2 ${
-                    hasPermission('library:delete_all') ? 'text-red-400 hover:bg-bambu-dark' : 'text-bambu-gray cursor-not-allowed'
+                    hasPermission('library:delete_all') ? 'text-red-700 dark:text-red-400 hover:bg-bambu-dark' : 'text-bambu-gray cursor-not-allowed'
                   }`}
                   onClick={() => { if (hasPermission('library:delete_all')) { onDelete(folder.id); setShowActions(false); } }}
                   disabled={!hasPermission('library:delete_all')}
@@ -932,7 +932,7 @@ function FileCard({ file, isSelected, isMobile, onSelect, onDelete, onDownload,
               )}
               <button
                 className={`w-full px-3 py-1.5 text-left text-sm flex items-center gap-2 ${
-                  canModify('library', 'delete', file.created_by_id) ? 'text-red-400 hover:bg-bambu-dark' : 'text-bambu-gray cursor-not-allowed'
+                  canModify('library', 'delete', file.created_by_id) ? 'text-red-700 dark:text-red-400 hover:bg-bambu-dark' : 'text-bambu-gray cursor-not-allowed'
                 }`}
                 onClick={() => { if (canModify('library', 'delete', file.created_by_id)) { onDelete(file.id); setShowActions(false); } }}
                 disabled={!canModify('library', 'delete', file.created_by_id)}
@@ -1723,12 +1723,12 @@ export function FileManagerPage() {
             <span className="text-white font-medium">{stats.total_files}</span>
           </div>
           <div className="flex items-center gap-2 text-sm">
-            <FolderOpen className="w-4 h-4 text-blue-400" />
+            <FolderOpen className="w-4 h-4 text-blue-600 dark:text-blue-400" />
             <span className="text-bambu-gray">{t('fileManager.folders')}:</span>
             <span className="text-white font-medium">{stats.total_folders}</span>
           </div>
           <div className="flex items-center gap-2 text-sm">
-            <HardDrive className="w-4 h-4 text-amber-400" />
+            <HardDrive className="w-4 h-4 text-amber-600 dark:text-amber-400" />
             <span className="text-bambu-gray">{t('fileManager.size')}:</span>
             <span className="text-white font-medium">{formatFileSize(stats.total_size_bytes)}</span>
           </div>
@@ -1909,7 +1909,7 @@ export function FileManagerPage() {
                   setTopLevelView('external');
                 }}
               >
-                <FolderSymlink className="w-4 h-4 text-purple-400" />
+                <FolderSymlink className="w-4 h-4 text-purple-600 dark:text-purple-400" />
                 <span className="text-sm">{t('fileManager.allExternal')}</span>
               </div>
             )}
@@ -1983,13 +1983,13 @@ export function FileManagerPage() {
           )}
           {/* External folder info bar */}
           {selectedFolder?.is_external && (
-            <div className="flex items-center gap-3 mb-4 p-3 bg-purple-500/10 border border-purple-500/30 rounded-lg">
-              <FolderSymlink className="w-5 h-5 text-purple-400 flex-shrink-0" />
+            <div className="flex items-center gap-3 mb-4 p-3 bg-purple-50 dark:bg-purple-500/10 border border-purple-300 dark:border-purple-500/30 rounded-lg">
+              <FolderSymlink className="w-5 h-5 text-purple-600 dark:text-purple-400 flex-shrink-0" />
               <div className="flex-1 min-w-0">
                 <div className="flex items-center gap-2">
-                  <span className="text-sm font-medium text-purple-300">{t('fileManager.externalFolder')}</span>
+                  <span className="text-sm font-medium text-purple-700 dark:text-purple-300">{t('fileManager.externalFolder')}</span>
                   {selectedFolder.external_readonly && (
-                    <span className="text-xs px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-400 flex items-center gap-1">
+                    <span className="text-xs px-1.5 py-0.5 rounded bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 flex items-center gap-1">
                       <Lock className="w-3 h-3" />
                       {t('fileManager.readOnly')}
                     </span>
@@ -2398,8 +2398,8 @@ export function FileManagerPage() {
                     <div>
                       <span className={`text-xs px-1.5 py-0.5 rounded font-medium ${
                         file.file_type === '3mf' ? 'bg-bambu-green/20 text-bambu-green'
-                        : (file.file_type === 'gcode' || file.file_type === 'gcode.3mf') ? 'bg-blue-500/20 text-blue-400'
-                        : file.file_type === 'stl' ? 'bg-purple-500/20 text-purple-400'
+                        : (file.file_type === 'gcode' || file.file_type === 'gcode.3mf') ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400'
+                        : file.file_type === 'stl' ? 'bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400'
                         : 'bg-bambu-gray/20 text-bambu-gray'
                       }`}>
                         {file.file_type.toUpperCase()}
@@ -2542,7 +2542,7 @@ export function FileManagerPage() {
                         onClick={() => canModify('library', 'delete', file.created_by_id) && setDeleteConfirm({ type: 'file', id: file.id })}
                         className={`p-1.5 rounded transition-colors ${
                           canModify('library', 'delete', file.created_by_id)
-                            ? 'hover:bg-bambu-dark text-bambu-gray hover:text-red-400'
+                            ? 'hover:bg-bambu-dark text-bambu-gray hover:text-red-700 dark:hover:text-red-400'
                             : 'text-bambu-gray/50 cursor-not-allowed'
                         }`}
                         title={canModify('library', 'delete', file.created_by_id) ? t('common.delete') : t('fileManager.noPermissionDeleteFile')}

+ 1 - 1
frontend/src/pages/GroupEditPage.tsx

@@ -176,7 +176,7 @@ export function GroupEditPage() {
 
       {/* System group warning */}
       {isEditing && groupData?.is_system && (
-        <div className="flex items-center gap-3 px-4 py-3 rounded-lg bg-yellow-500/10 border border-yellow-500/20 text-yellow-400 text-sm">
+        <div className="flex items-center gap-3 px-4 py-3 rounded-lg bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/20 text-yellow-700 dark:text-yellow-400 text-sm">
           <AlertTriangle className="w-4 h-4 shrink-0" />
           {t('groups.form.systemGroupWarning')}
         </div>

+ 23 - 23
frontend/src/pages/InventoryPage.tsx

@@ -132,14 +132,14 @@ function formatWeight(g: number, useKg = false): string {
 
 // Material color mapping for pills
 const MATERIAL_COLORS: Record<string, string> = {
-  PLA: 'bg-green-500/20 text-green-400',
-  ABS: 'bg-red-500/20 text-red-400',
-  PETG: 'bg-blue-500/20 text-blue-400',
-  TPU: 'bg-purple-500/20 text-purple-400',
-  ASA: 'bg-orange-500/20 text-orange-400',
-  PA: 'bg-yellow-500/20 text-yellow-400',
-  PC: 'bg-cyan-500/20 text-cyan-400',
-  PET: 'bg-sky-500/20 text-sky-400',
+  PLA: 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400',
+  ABS: 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400',
+  PETG: 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400',
+  TPU: 'bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400',
+  ASA: 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400',
+  PA: 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400',
+  PC: 'bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-400',
+  PET: 'bg-sky-100 dark:bg-sky-500/20 text-sky-700 dark:text-sky-400',
 };
 
 type TFn = (key: string, opts?: Record<string, unknown>) => string;
@@ -257,7 +257,7 @@ const columnCells: Record<string, (ctx: CellCtx) => ReactNode> = {
     const isHt = !isExternal && assignment.ams_id >= 128;
     const slotLabel = formatSlotLabel(assignment.ams_id, assignment.tray_id, isHt, isExternal);
     return (
-      <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-purple-500/20 text-purple-400">
+      <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400">
         {printerLabel} {slotLabel}{assignment.ams_label ? ` (${assignment.ams_label})` : ''}
       </span>
     );
@@ -265,7 +265,7 @@ const columnCells: Record<string, (ctx: CellCtx) => ReactNode> = {
   storage_location: ({ spool }) => {
     if (!spool.storage_location) return <span className="text-sm text-bambu-gray">-</span>;
     return (
-      <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-blue-500/20 text-blue-400">
+      <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400">
         {spool.storage_location}
       </span>
     );
@@ -321,7 +321,7 @@ const columnCells: Record<string, (ctx: CellCtx) => ReactNode> = {
   stock: ({ spool, t }) => {
     if (!spool.slicer_filament) {
       return (
-        <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-amber-500/20 text-amber-400">
+        <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400">
           {t('inventory.stock')}
         </span>
       );
@@ -373,7 +373,7 @@ const columnCells: Record<string, (ctx: CellCtx) => ReactNode> = {
 
     return (
       <div
-        className={`flex items-center gap-1 text-sm font-medium ${isMatch ? 'text-green-400' : 'text-yellow-400'}`}
+        className={`flex items-center gap-1 text-sm font-medium ${isMatch ? 'text-green-700 dark:text-green-400' : 'text-yellow-700 dark:text-yellow-400'}`}
         title={tooltip}
       >
         <span>{Math.round(scaleWeight)}g</span>
@@ -1380,13 +1380,13 @@ function InventoryPage({ spoolmanMode = false, spoolmanModeReady = true }: { spo
           <div className="bg-bambu-dark-secondary rounded-lg p-4">
             <div className="flex items-center justify-between gap-2 mb-1">
               <div className="flex items-center gap-2">
-                <TrendingDown className="w-4 h-4 text-blue-400" />
+                <TrendingDown className="w-4 h-4 text-blue-600 dark:text-blue-400" />
                 <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.totalConsumed')}</span>
               </div>
               {stats.totalConsumed > 0 && resetableSpoolIds.length > 0 && (
                 <button
                   onClick={() => setConfirmAction({ type: 'reset-all-consumed-counters' })}
-                  className="p-1 text-bambu-gray hover:text-red-400 rounded transition-colors"
+                  className="p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 rounded transition-colors"
                   title={t('inventory.resetAllConsumedCountersTooltip')}
                   aria-label={t('inventory.resetAllConsumedCounters')}
                 >
@@ -1401,7 +1401,7 @@ function InventoryPage({ spoolmanMode = false, spoolmanModeReady = true }: { spo
           {/* By Material */}
           <div className="bg-bambu-dark-secondary rounded-lg p-4">
             <div className="flex items-center gap-2 mb-1">
-              <Layers className="w-4 h-4 text-green-400" />
+              <Layers className="w-4 h-4 text-green-600 dark:text-green-400" />
               <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.byMaterial')}</span>
             </div>
             <div className="flex flex-wrap gap-1.5 mt-1">
@@ -1419,7 +1419,7 @@ function InventoryPage({ spoolmanMode = false, spoolmanModeReady = true }: { spo
           {/* In Printer */}
           <div className="bg-bambu-dark-secondary rounded-lg p-4">
             <div className="flex items-center gap-2 mb-1">
-              <Printer className="w-4 h-4 text-purple-400" />
+              <Printer className="w-4 h-4 text-purple-600 dark:text-purple-400" />
               <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.inPrinter')}</span>
             </div>
             <div className="text-xl font-bold text-white">{inPrinterCount}</div>
@@ -1429,10 +1429,10 @@ function InventoryPage({ spoolmanMode = false, spoolmanModeReady = true }: { spo
           {/* Low Stock */}
           <div className="bg-bambu-dark-secondary rounded-lg p-4">
             <div className="flex items-center gap-2 mb-1">
-              <AlertTriangle className="w-4 h-4 text-yellow-400" />
+              <AlertTriangle className="w-4 h-4 text-yellow-600 dark:text-yellow-400" />
               <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.lowStock')}</span>
             </div>
-            <div className={`text-xl font-bold ${stats.lowStock > 0 ? 'text-yellow-400' : 'text-white'}`}>{stats.lowStock}</div>
+            <div className={`text-xl font-bold ${stats.lowStock > 0 ? 'text-yellow-700 dark:text-yellow-400' : 'text-white'}`}>{stats.lowStock}</div>
             <div className="text-xs text-bambu-gray mt-1 flex items-center gap-2">
               {showThresholdInput ? (
                 <form
@@ -1646,7 +1646,7 @@ function InventoryPage({ spoolmanMode = false, spoolmanModeReady = true }: { spo
             onClick={() => { setUsageFilter('lowstock'); resetPage(); }}
             className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium transition-colors ${
               usageFilter === 'lowstock'
-                ? 'bg-yellow-500/20 text-yellow-400'
+                ? 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400'
                 : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
             }`}
           >
@@ -1671,7 +1671,7 @@ function InventoryPage({ spoolmanMode = false, spoolmanModeReady = true }: { spo
             onClick={() => { setStockFilter('stock'); resetPage(); }}
             className={`px-3 py-1.5 text-xs font-medium transition-colors ${
               stockFilter === 'stock'
-                ? 'bg-amber-500/20 text-amber-400'
+                ? 'bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400'
                 : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
             }`}
           >
@@ -2582,7 +2582,7 @@ function SpoolTableRow({
             // archived consumed weight now counts in "Total Consumed", so
             // the user needs a way to zero an archived spool's tracking
             // counter individually without having to un-archive it first.
-            <button onClick={onResetConsumedCounter} className="p-1.5 text-bambu-gray hover:text-orange-400 rounded transition-colors" title={t('inventory.resetConsumedCounterTooltip')}>
+            <button onClick={onResetConsumedCounter} className="p-1.5 text-bambu-gray hover:text-orange-600 dark:hover:text-orange-400 rounded transition-colors" title={t('inventory.resetConsumedCounterTooltip')}>
               <Eraser className="w-4 h-4" />
             </button>
           )}
@@ -2591,11 +2591,11 @@ function SpoolTableRow({
               <RotateCcw className="w-4 h-4" />
             </button>
           ) : (
-            <button onClick={onArchive} className="p-1.5 text-bambu-gray hover:text-yellow-400 rounded transition-colors" title={t('inventory.archive')}>
+            <button onClick={onArchive} className="p-1.5 text-bambu-gray hover:text-yellow-600 dark:hover:text-yellow-400 rounded transition-colors" title={t('inventory.archive')}>
               <Archive className="w-4 h-4" />
             </button>
           )}
-          <button onClick={onDelete} className="p-1.5 text-bambu-gray hover:text-red-400 rounded transition-colors" title={t('common.delete')}>
+          <button onClick={onDelete} className="p-1.5 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 rounded transition-colors" title={t('common.delete')}>
             <Trash2 className="w-4 h-4" />
           </button>
         </div>

+ 1 - 1
frontend/src/pages/LoginPage.tsx

@@ -704,7 +704,7 @@ export function LoginPage() {
         </div>
 
         {showAutologinBanner && (
-          <div className="mt-6 rounded-lg border border-amber-500/40 bg-amber-500/10 px-4 py-3 text-sm text-amber-200">
+          <div className="mt-6 rounded-lg border border-amber-300 dark:border-amber-500/40 bg-amber-50 dark:bg-amber-500/10 px-4 py-3 text-sm text-amber-800 dark:text-amber-200">
             {t('login.autologinFailed')}
           </div>
         )}

+ 15 - 15
frontend/src/pages/MaintenancePage.tsx

@@ -159,8 +159,8 @@ function MaintenanceCard({
 
   const getStatusColor = () => {
     if (!item.enabled) return 'text-bambu-gray';
-    if (item.is_due) return 'text-red-400';
-    if (item.is_warning) return 'text-amber-400';
+    if (item.is_due) return 'text-red-700 dark:text-red-400';
+    if (item.is_warning) return 'text-amber-700 dark:text-amber-400';
     return 'text-bambu-green';
   };
 
@@ -333,13 +333,13 @@ function PrinterSection({
             <h2 className="text-xl font-semibold text-white">{overview.printer_name}</h2>
             <div className="flex items-center gap-2">
               {overview.due_count > 0 && (
-                <span className="px-2.5 py-1 bg-red-500/20 text-red-400 text-xs font-medium rounded-full flex items-center gap-1.5">
+                <span className="px-2.5 py-1 bg-red-100 text-red-700 dark:bg-red-500/20 dark:text-red-400 text-xs font-medium rounded-full flex items-center gap-1.5">
                   <AlertTriangle className="w-3 h-3" />
                   {t('maintenance.overdueCount', { count: overview.due_count })}
                 </span>
               )}
               {overview.warning_count > 0 && (
-                <span className="px-2.5 py-1 bg-amber-500/20 text-amber-400 text-xs font-medium rounded-full flex items-center gap-1.5">
+                <span className="px-2.5 py-1 bg-amber-100 text-amber-700 dark:bg-amber-500/20 dark:text-amber-400 text-xs font-medium rounded-full flex items-center gap-1.5">
                   <Clock className="w-3 h-3" />
                   {t('maintenance.dueSoonCount', { count: overview.warning_count })}
                 </span>
@@ -417,14 +417,14 @@ function PrinterSection({
               }`}>
                 {(() => {
                   const Icon = getIcon(nextTask.maintenance_type_icon);
-                  return <Icon className={`w-4 h-4 ${nextTask.is_due ? 'text-red-400' : 'text-amber-400'}`} />;
+                  return <Icon className={`w-4 h-4 ${nextTask.is_due ? 'text-red-600 dark:text-red-400' : 'text-amber-600 dark:text-amber-400'}`} />;
                 })()}
               </div>
               <div>
-                <div className={`text-sm font-medium ${nextTask.is_due ? 'text-red-400' : 'text-amber-400'}`}>
+                <div className={`text-sm font-medium ${nextTask.is_due ? 'text-red-700 dark:text-red-400' : 'text-amber-700 dark:text-amber-400'}`}>
                   {nextTask.maintenance_type_name}
                 </div>
-                <div className={`text-xs ${nextTask.is_due ? 'text-red-400/70' : 'text-amber-400/70'}`}>
+                <div className={`text-xs ${nextTask.is_due ? 'text-red-700/80 dark:text-red-400/70' : 'text-amber-700/80 dark:text-amber-400/70'}`}>
                   {nextTask.is_due ? t('common.overdue') : t('maintenance.dueSoon')}
                 </div>
               </div>
@@ -736,7 +736,7 @@ function SettingsSection({
                     ))}
                   </div>
                   {selectedPrinters.size === 0 && (
-                    <p className="text-xs text-orange-400 mt-1">{t('maintenance.selectAtLeastOnePrinter')}</p>
+                    <p className="text-xs text-orange-700 dark:text-orange-400 mt-1">{t('maintenance.selectAtLeastOnePrinter')}</p>
                   )}
                 </div>
                 <div className="mt-4 flex justify-end gap-2">
@@ -778,7 +778,7 @@ function SettingsSection({
                     }}
                     disabled={!hasPermission('maintenance:delete')}
                     title={!hasPermission('maintenance:delete') ? t('maintenance.noPermissionDeleteTypes') : undefined}
-                    className={`p-2 rounded-lg hover:bg-bambu-dark text-bambu-gray hover:text-red-400 transition-colors ${!hasPermission('maintenance:delete') ? 'opacity-50 cursor-not-allowed' : ''}`}
+                    className={`p-2 rounded-lg hover:bg-bambu-dark text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors ${!hasPermission('maintenance:delete') ? 'opacity-50 cursor-not-allowed' : ''}`}
                   >
                     <Trash2 className="w-4 h-4" />
                   </button>
@@ -887,7 +887,7 @@ function SettingsSection({
                     className={`px-2 py-1 rounded-lg border transition-colors flex items-center gap-1 ${
                       assignedPrinters.length > 0
                         ? 'border-bambu-green/50 bg-bambu-green/10 text-bambu-green hover:bg-bambu-green/20'
-                        : 'border-orange-400/50 bg-orange-400/10 text-orange-400 hover:bg-orange-400/20'
+                        : 'border-orange-300 bg-orange-50 text-orange-700 hover:bg-orange-100 dark:border-orange-400/50 dark:bg-orange-400/10 dark:text-orange-400 dark:hover:bg-orange-400/20'
                     }`}
                     title={t('maintenance.printersAssignedClick', { count: assignedPrinters.length })}
                   >
@@ -911,7 +911,7 @@ function SettingsSection({
                     }}
                     disabled={!hasPermission('maintenance:delete')}
                     title={!hasPermission('maintenance:delete') ? t('maintenance.noPermissionDeleteTypes') : undefined}
-                    className={`p-2 rounded-lg hover:bg-bambu-dark text-bambu-gray hover:text-red-400 transition-colors ${!hasPermission('maintenance:delete') ? 'opacity-50 cursor-not-allowed' : ''}`}
+                    className={`p-2 rounded-lg hover:bg-bambu-dark text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors ${!hasPermission('maintenance:delete') ? 'opacity-50 cursor-not-allowed' : ''}`}
                   >
                     <Trash2 className="w-4 h-4" />
                   </button>
@@ -922,7 +922,7 @@ function SettingsSection({
                   <div className="mt-3 pt-3 border-t border-bambu-dark-tertiary">
                     <p className="text-xs text-bambu-gray mb-2">{t('maintenance.assignedToPrinters')}</p>
                     {assignedPrinters.length === 0 ? (
-                      <p className="text-xs text-orange-400">{t('maintenance.noPrintersAssigned')}</p>
+                      <p className="text-xs text-orange-700 dark:text-orange-400">{t('maintenance.noPrintersAssigned')}</p>
                     ) : (
                       <div className="flex flex-wrap gap-1 mb-2">
                         {assignedPrinters.map(p => (
@@ -935,7 +935,7 @@ function SettingsSection({
                               onClick={() => p.itemId && onRemoveItem(p.itemId)}
                               disabled={!hasPermission('maintenance:delete')}
                               title={!hasPermission('maintenance:delete') ? t('maintenance.noPermissionRemovePrinter') : t('maintenance.removeFromPrinter')}
-                              className={`ml-1 ${hasPermission('maintenance:delete') ? 'hover:text-red-400' : 'opacity-50 cursor-not-allowed'}`}
+                              className={`ml-1 ${hasPermission('maintenance:delete') ? 'hover:text-red-600 dark:hover:text-red-400' : 'opacity-50 cursor-not-allowed'}`}
                             >
                               ×
                             </button>
@@ -1238,9 +1238,9 @@ export function MaintenancePage() {
         <p className="text-bambu-gray mt-1">
           {activeTab === 'status' ? (
             <>
-              {totalDue > 0 && <span className="text-red-400">{t('maintenance.dueCount', { count: totalDue })}</span>}
+              {totalDue > 0 && <span className="text-red-700 dark:text-red-400">{t('maintenance.dueCount', { count: totalDue })}</span>}
               {totalDue > 0 && totalWarning > 0 && ' · '}
-              {totalWarning > 0 && <span className="text-amber-400">{t('maintenance.warningCount', { count: totalWarning })}</span>}
+              {totalWarning > 0 && <span className="text-amber-700 dark:text-amber-400">{t('maintenance.warningCount', { count: totalWarning })}</span>}
               {totalDue === 0 && totalWarning === 0 && <span className="text-bambu-green">{t('maintenance.allOk')}</span>}
             </>
           ) : (

+ 5 - 5
frontend/src/pages/NotificationsPage.tsx

@@ -102,11 +102,11 @@ export function NotificationsPage() {
       </div>
 
       {/* Info card */}
-      <Card className="mb-6 border-blue-500/30 bg-blue-500/5">
+      <Card className="mb-6 border-blue-300 bg-blue-50 dark:border-blue-500/30 dark:bg-blue-500/5">
         <CardContent className="py-4">
           <div className="flex items-start gap-3">
-            <div className="w-10 h-10 rounded-full flex items-center justify-center bg-blue-500/20 flex-shrink-0">
-              <Mail className="w-5 h-5 text-blue-400" />
+            <div className="w-10 h-10 rounded-full flex items-center justify-center bg-blue-100 dark:bg-blue-500/20 flex-shrink-0">
+              <Mail className="w-5 h-5 text-blue-600 dark:text-blue-400" />
             </div>
             <div>
               <h3 className="text-white font-medium">{t('notifications.userEmail.emailNotifications')}</h3>
@@ -114,11 +114,11 @@ export function NotificationsPage() {
                 {t('notifications.userEmail.emailNotificationsDesc')}
               </p>
               {user?.email ? (
-                <p className="text-sm text-blue-400 mt-2">
+                <p className="text-sm text-blue-700 dark:text-blue-400 mt-2">
                   {t('notifications.userEmail.sendingTo')}: <strong>{user.email}</strong>
                 </p>
               ) : (
-                <p className="text-sm text-yellow-400 mt-2">
+                <p className="text-sm text-yellow-700 dark:text-yellow-400 mt-2">
                   {t('notifications.userEmail.noEmailWarning')}
                 </p>
               )}

+ 6 - 6
frontend/src/pages/PipelineRunsPage.tsx

@@ -268,7 +268,7 @@ export function PipelineRunsView() {
             type="button"
             onClick={() => setShowClearConfirm(true)}
             disabled={total === 0}
-            className="flex items-center gap-1 px-2 py-1 text-red-400 hover:bg-red-500/10 rounded disabled:opacity-50 disabled:cursor-not-allowed"
+            className="flex items-center gap-1 px-2 py-1 text-red-700 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-500/10 rounded disabled:opacity-50 disabled:cursor-not-allowed"
           >
             <Trash2 className="w-3 h-3" />
             {t('pipelineRuns.clearLog', 'Clear log')}
@@ -291,7 +291,7 @@ export function PipelineRunsView() {
             onClick={(e) => e.stopPropagation()}
           >
             <h3 className="text-base font-semibold text-white flex items-center gap-2">
-              <Trash2 className="w-4 h-4 text-red-400" />
+              <Trash2 className="w-4 h-4 text-red-600 dark:text-red-400" />
               {t('pipelineRuns.clearConfirmTitle', 'Clear log?')}
             </h3>
             <p className="text-sm text-bambu-gray mt-2">
@@ -490,7 +490,7 @@ function RunRow({
                 {run.copies_failed > 0 && (
                   <>
                     <span className="text-bambu-gray/40">·</span>
-                    <span className="text-red-400">
+                    <span className="text-red-700 dark:text-red-400">
                       {t('pipelineRuns.failedCount', '{{n}} failed', { n: run.copies_failed })}
                     </span>
                   </>
@@ -506,7 +506,7 @@ function RunRow({
               onClick={onCancel}
               disabled={cancelling}
               aria-label={t('common.cancel', 'Cancel')}
-              className="text-xs px-2 py-1 text-red-400 hover:bg-red-500/10 rounded disabled:opacity-50 flex items-center gap-1"
+              className="text-xs px-2 py-1 text-red-700 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-500/10 rounded disabled:opacity-50 flex items-center gap-1"
             >
               <X className="w-3 h-3" />
               {t('common.cancel', 'Cancel')}
@@ -542,7 +542,7 @@ function RunRow({
                   </span>
                 )}
                 {job.error_message && (
-                  <span className="text-red-400 truncate" title={job.error_message}>
+                  <span className="text-red-700 dark:text-red-400 truncate" title={job.error_message}>
                     {job.error_message}
                   </span>
                 )}
@@ -550,7 +550,7 @@ function RunRow({
             ))}
           </div>
           {run.error_message && !userCancelled && (
-            <div className="text-xs text-red-400 mt-2 pt-2 border-t border-bambu-dark-tertiary">
+            <div className="text-xs text-red-700 dark:text-red-400 mt-2 pt-2 border-t border-bambu-dark-tertiary">
               {run.error_message}
             </div>
           )}

+ 84 - 84
frontend/src/pages/PrintersPage.tsx

@@ -412,7 +412,7 @@ function DualNozzleHoverCard({ leftSlot, rightSlot, activeNozzle, filamentInfo,
     const filamentName = slot.filament_id ? filamentInfo?.[slot.filament_id]?.name : undefined;
     return (
       <div className="flex-1 space-y-1.5">
-        <div className={`text-[10px] font-bold pb-1 border-b border-bambu-dark-tertiary/50 ${isActive ? 'text-amber-400' : 'text-bambu-gray'}`}>
+        <div className={`text-[10px] font-bold pb-1 border-b border-bambu-dark-tertiary/50 ${isActive ? 'text-amber-700 dark:text-amber-400' : 'text-bambu-gray'}`}>
           {side === 'L' ? t('common.left') : t('common.right')}
         </div>
         {slot.nozzle_diameter && (
@@ -716,8 +716,8 @@ function AmsBackupBadge({ state, onClick }: AmsBackupBadgeProps) {
   let title: string;
   if (state === true) {
     className += known
-      ? 'bg-blue-500/20 text-blue-400 hover:bg-blue-500/30 cursor-pointer'
-      : 'bg-blue-500/20 text-blue-400 cursor-default';
+      ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 hover:bg-blue-500/30 cursor-pointer'
+      : 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 cursor-default';
     title = t('printers.amsBackup.titleOn');
   } else if (state === false) {
     className += known
@@ -1347,9 +1347,9 @@ function NozzleTemperatureControlBox({
   };
 
   return (
-    <div className={`rounded-lg border p-2 ${isActive ? 'border-amber-400/60 bg-amber-400/10' : 'border-bambu-dark-tertiary bg-bambu-dark'}`}>
+    <div className={`rounded-lg border p-2 ${isActive ? 'border-amber-500/60 dark:border-amber-400/60 bg-amber-50 dark:bg-amber-400/10' : 'border-bambu-dark-tertiary bg-bambu-dark'}`}>
       <div className="mb-1.5 flex items-center justify-between gap-2">
-        <span className={`text-xs font-medium ${isActive ? 'text-amber-300' : 'text-white'}`}>{label}</span>
+        <span className={`text-xs font-medium ${isActive ? 'text-amber-700 dark:text-amber-300' : 'text-white'}`}>{label}</span>
         <span className="text-[10px] text-bambu-gray">
           {Math.round(current ?? 0)}°C
           {target !== undefined ? ` / ${Math.round(target)}°` : ''}
@@ -1682,7 +1682,7 @@ export function AmsNameHoverCard({
               {canEdit && (
                 <div className="space-y-1">
                   {saveError && (
-                    <p className="text-[10px] text-red-400 break-words">{saveError}</p>
+                    <p className="text-[10px] text-red-700 dark:text-red-400 break-words">{saveError}</p>
                   )}
                   <div className="flex gap-1 justify-end">
                     <button
@@ -2140,13 +2140,13 @@ function PrinterCard({
     if (isPrintingOrPaused) {
       return {
         label: t('printers.plateStatus.inUse'),
-        className: 'bg-blue-500/20 text-blue-400',
+        className: 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400',
       };
     }
     if (status.awaiting_plate_clear) {
       return {
         label: t('printers.plateStatus.notCleared'),
-        className: 'bg-yellow-500/20 text-yellow-400',
+        className: 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400',
       };
     }
     return {
@@ -3089,8 +3089,8 @@ function PrinterCard({
           <button
             className={`w-full px-4 py-2 text-left text-sm flex items-center gap-2 ${
               hasPermission('printers:delete')
-                ? 'text-red-400 hover:bg-bambu-dark-tertiary'
-                : 'text-red-400/50 cursor-not-allowed'
+                ? 'text-red-700 dark:text-red-400 hover:bg-bambu-dark-tertiary'
+                : 'text-red-700/50 dark:text-red-400/50 cursor-not-allowed'
             }`}
             onClick={() => {
               if (!hasPermission('printers:delete')) return;
@@ -3138,7 +3138,7 @@ function PrinterCard({
               ? 'bg-bambu-green/10 border-bambu-green/50'
               : canDrop
                 ? 'bg-bambu-green/10 border-bambu-green'
-                : 'bg-red-500/10 border-red-500/50'
+                : 'bg-red-50 dark:bg-red-500/10 border-red-300 dark:border-red-500/50'
           }`}
         >
           <div className="text-center">
@@ -3154,8 +3154,8 @@ function PrinterCard({
               </>
             ) : (
               <>
-                <X className="w-8 h-8 mx-auto mb-2 text-red-400" />
-                <p className="text-sm font-medium text-red-400">{t('printers.cannotPrint', 'Printer busy')}</p>
+                <X className="w-8 h-8 mx-auto mb-2 text-red-600 dark:text-red-400" />
+                <p className="text-sm font-medium text-red-700 dark:text-red-400">{t('printers.cannotPrint', 'Printer busy')}</p>
               </>
             )}
           </div>
@@ -3208,7 +3208,7 @@ function PrinterCard({
                       onClick={() => clearPlateMutation.mutate()}
                       disabled={clearPlateMutation.isPending || !hasPermission('printers:clear_plate')}
                       aria-label={t('printers.plateStatus.markCleared')}
-                      className="inline-flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-md bg-yellow-500/20 border border-yellow-400/40 text-yellow-400 hover:bg-yellow-500/30 transition-colors disabled:opacity-50"
+                      className="inline-flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-md bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-300 dark:border-yellow-400/40 text-yellow-700 dark:text-yellow-400 hover:bg-yellow-500/30 transition-colors disabled:opacity-50"
                       title={!hasPermission('printers:clear_plate') ? t('printers.permission.noControl') : t('printers.plateStatus.markCleared')}
                     >
                       {clearPlateMutation.isPending ? (
@@ -3250,7 +3250,7 @@ function PrinterCard({
                   maintenance UI. */}
               {printer.is_active === false ? (
                 <span
-                  className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs bg-amber-500/20 text-amber-400"
+                  className="flex items-center gap-1.5 px-2 py-1 rounded-full text-xs bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400"
                   title={t('printers.maintenance.subtitle')}
                 >
                   <Wrench className="w-3 h-3" />
@@ -3360,7 +3360,7 @@ function PrinterCard({
               {queueCount > 0 && (
                 <button
                   onClick={() => navigate('/queue')}
-                  className="flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-indigo-500/20 text-indigo-400 hover:opacity-80 transition-opacity"
+                  className="flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-indigo-100 dark:bg-indigo-500/20 text-indigo-700 dark:text-indigo-400 hover:opacity-80 transition-opacity"
                   title={t('printers.queue.inQueue', { count: queueCount })}
                 >
                   <Layers className="w-3 h-3" />
@@ -3373,7 +3373,7 @@ function PrinterCard({
                   onClick={() => setShowFirmwareModal(true)}
                   className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs hover:opacity-80 transition-opacity ${
                     firmwareInfo.update_available
-                      ? 'bg-orange-500/20 text-orange-400'
+                      ? 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400'
                       : 'bg-status-ok/20 text-status-ok'
                   }`}
                   title={
@@ -3397,7 +3397,7 @@ function PrinterCard({
                 <span
                   className={`flex items-center px-2 py-1 rounded-full text-xs ${
                     status.door_open
-                      ? 'bg-yellow-500/20 text-yellow-400'
+                      ? 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400'
                       : 'bg-status-ok/20 text-status-ok'
                   }`}
                   title={status.door_open ? t('printers.door.open') : t('printers.door.closed')}
@@ -3416,8 +3416,8 @@ function PrinterCard({
             <Card className="w-full max-w-md mx-4">
               <CardContent>
                 <div className="flex items-start gap-3 mb-4">
-                  <div className="p-2 rounded-full bg-red-500/20">
-                    <AlertTriangle className="w-5 h-5 text-red-400" />
+                  <div className="p-2 rounded-full bg-red-100 dark:bg-red-500/20">
+                    <AlertTriangle className="w-5 h-5 text-red-600 dark:text-red-400" />
                   </div>
                   <div>
                     <h3 className="text-lg font-semibold text-white">{t('printers.confirm.deleteTitle')}</h3>
@@ -3481,9 +3481,9 @@ function PrinterCard({
           // out-of-service.
           <>
             {viewMode === 'compact' ? (
-              <div className="mt-2 flex items-center gap-2 px-2 py-1.5 rounded-full bg-amber-500/15 border border-amber-500/30">
-                <Wrench className="w-3 h-3 text-amber-400 shrink-0" />
-                <span className="text-[11px] text-amber-400 font-medium truncate">
+              <div className="mt-2 flex items-center gap-2 px-2 py-1.5 rounded-full bg-amber-50 dark:bg-amber-500/15 border border-amber-300 dark:border-amber-500/30">
+                <Wrench className="w-3 h-3 text-amber-600 dark:text-amber-400 shrink-0" />
+                <span className="text-[11px] text-amber-700 dark:text-amber-400 font-medium truncate">
                   {t('printers.maintenance.pillLabel')}
                 </span>
               </div>
@@ -3495,10 +3495,10 @@ function PrinterCard({
                   </span>
                   <div className="flex-1 h-[2px] bg-bambu-dark-tertiary" />
                 </div>
-                <div className="p-3 bg-amber-500/10 border border-amber-500/30 rounded-[10px] flex items-center gap-3">
-                  <Wrench className="w-6 h-6 text-amber-400 shrink-0" />
+                <div className="p-3 bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 rounded-[10px] flex items-center gap-3">
+                  <Wrench className="w-6 h-6 text-amber-600 dark:text-amber-400 shrink-0" />
                   <div className="flex-1 min-w-0">
-                    <p className="text-sm text-amber-400 font-medium">
+                    <p className="text-sm text-amber-700 dark:text-amber-400 font-medium">
                       {t('printers.maintenance.title')}
                     </p>
                     <p className="text-xs text-bambu-gray mt-0.5">
@@ -3715,14 +3715,14 @@ function PrinterCard({
                   label: t('printers.fans.partCooling'),
                   value: status.cooling_fan_speed ?? 0,
                   Icon: Fan,
-                  activeClass: 'text-cyan-400',
+                  activeClass: 'text-cyan-600 dark:text-cyan-400',
                 },
                 {
                   key: 'aux',
                   label: t('printers.fans.auxiliary'),
                   value: status.big_fan1_speed ?? 0,
                   Icon: Wind,
-                  activeClass: 'text-blue-400',
+                  activeClass: 'text-blue-600 dark:text-blue-400',
                 },
                 ...(hasChamberFan
                   ? [
@@ -3731,7 +3731,7 @@ function PrinterCard({
                         label: t('printers.fans.chamber'),
                         value: status.big_fan2_speed ?? 0,
                         Icon: AirVent,
-                        activeClass: 'text-green-400',
+                        activeClass: 'text-green-600 dark:text-green-400',
                       },
                     ]
                   : []),
@@ -3921,13 +3921,13 @@ function PrinterCard({
                           title={canUseStatusControls ? t('printers.activeNozzle', { nozzle: activeNozzle === 'L' ? t('common.left') : t('common.right') }) : statusControlTitle}
                           onClick={() => canUseStatusControls && setStatusControlMenu(statusControlMenu === 'nozzle-select' ? null : 'nozzle-select')}
                         >
-                          <NozzleIcon className="w-3.5 h-3.5 mb-0.5 text-amber-400" />
+                          <NozzleIcon className="w-3.5 h-3.5 mb-0.5 text-amber-600 dark:text-amber-400" />
                           <div className="flex items-center gap-2">
-                            <span className={`text-[11px] font-bold ${activeNozzle === 'L' ? 'text-amber-400' : 'text-gray-500'}`}>
+                            <span className={`text-[11px] font-bold ${activeNozzle === 'L' ? 'text-amber-700 dark:text-amber-400' : 'text-gray-500'}`}>
                               L{leftNozzleSlot?.nozzle_diameter ? ` ${leftNozzleSlot.nozzle_diameter}` : ''}
                             </span>
                             <span className="text-[9px] text-bambu-gray/40">·</span>
-                            <span className={`text-[11px] font-bold ${activeNozzle === 'R' ? 'text-amber-400' : 'text-gray-500'}`}>
+                            <span className={`text-[11px] font-bold ${activeNozzle === 'R' ? 'text-amber-700 dark:text-amber-400' : 'text-gray-500'}`}>
                               R{rightNozzleSlot?.nozzle_diameter ? ` ${rightNozzleSlot.nozzle_diameter}` : ''}
                             </span>
                           </div>
@@ -3996,7 +3996,7 @@ function PrinterCard({
                 type="button"
                 onClick={() => clearPlateMutation.mutate()}
                 disabled={clearPlateMutation.isPending || !hasPermission('printers:clear_plate')}
-                className="mt-2 w-full inline-flex items-center justify-center gap-2 px-3 py-1.5 rounded-lg bg-yellow-500/20 border border-yellow-400/40 text-yellow-400 hover:bg-yellow-500/30 transition-colors text-xs font-medium disabled:opacity-50"
+                className="mt-2 w-full inline-flex items-center justify-center gap-2 px-3 py-1.5 rounded-lg bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-300 dark:border-yellow-400/40 text-yellow-700 dark:text-yellow-400 hover:bg-yellow-500/30 transition-colors text-xs font-medium disabled:opacity-50"
                 title={!hasPermission('printers:clear_plate') ? t('printers.permission.noControl') : t('printers.plateStatus.markCleared')}
               >
                 {clearPlateMutation.isPending ? (
@@ -4037,7 +4037,7 @@ function PrinterCard({
                         disabled={!status.connected || chamberLightMutation.isPending || !hasPermission('printers:control')}
                         className={`${iconControlClass} ${
                           status.chamber_light
-                            ? 'bg-yellow-500/10 text-yellow-400 hover:bg-yellow-500/20'
+                            ? 'bg-yellow-50 dark:bg-yellow-500/10 text-yellow-700 dark:text-yellow-400 hover:bg-yellow-500/20'
                             : 'bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white'
                         }`}
                         title={!hasPermission('printers:control') ? t('printers.permission.noControl') : (status.chamber_light ? t('printers.chamberLightOff') : t('printers.chamberLightOn'))}
@@ -4049,8 +4049,8 @@ function PrinterCard({
                       {(['P2S', 'X2D', 'H2D', 'H2C', 'H2S'].includes(printer.model ?? '')) && (() => {
                         const isHeating = status.airduct_mode === 1;
                         const Icon = isHeating ? Flame : Snowflake;
-                        const color = isHeating ? 'text-orange-400' : 'text-sky-400';
-                        const bg = isHeating ? 'bg-orange-500/10 text-orange-400 hover:bg-orange-500/20' : 'bg-sky-500/10 text-sky-400 hover:bg-sky-500/20';
+                        const color = isHeating ? 'text-orange-600 dark:text-orange-400' : 'text-sky-600 dark:text-sky-400';
+                        const bg = isHeating ? 'bg-orange-50 dark:bg-orange-500/10 text-orange-700 dark:text-orange-400 hover:bg-orange-500/20' : 'bg-sky-50 dark:bg-sky-500/10 text-sky-700 dark:text-sky-400 hover:bg-sky-500/20';
                         return (
                           <div className="relative">
                             <button
@@ -4097,7 +4097,7 @@ function PrinterCard({
                         const canControl = hasPermission('printers:control');
                         const disabled = isPrinting || !canControl;
                         const bambuIsPlateBelow = true; // positive Z moves plate away from nozzle
-                        const jogButtonClass = 'flex h-8 w-8 items-center justify-center rounded bg-indigo-500/15 text-indigo-300 transition-colors hover:bg-indigo-500/30 disabled:cursor-not-allowed disabled:opacity-50';
+                        const jogButtonClass = 'flex h-8 w-8 items-center justify-center rounded bg-indigo-100 dark:bg-indigo-500/15 text-indigo-700 dark:text-indigo-300 transition-colors hover:bg-indigo-200 dark:hover:bg-indigo-500/30 disabled:cursor-not-allowed disabled:opacity-50';
                         const requestZJog = (direction: 1 | -1) => {
                           const signed = direction * bedJogStep * (bambuIsPlateBelow ? 1 : -1);
                           const warnedKey = `bambuddy.bedJog.warned.${printer.id}`;
@@ -4125,7 +4125,7 @@ function PrinterCard({
                               className={`${iconControlClass} ${
                                 disabled
                                   ? 'bg-bambu-dark text-bambu-gray/50 cursor-not-allowed'
-                                  : 'bg-indigo-500/10 text-indigo-400 hover:bg-indigo-500/20'
+                                  : 'bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-400 hover:bg-indigo-500/20'
                               }`}
                               title={!canControl ? t('printers.permission.noControl') : isPrinting ? t('printers.bedJog.disabledWhilePrinting') : t('printers.bedJog.title')}
                             >
@@ -4268,7 +4268,7 @@ function PrinterCard({
                           disabled={!status.connected || plateDetectionMutation.isPending || !hasPermission('printers:update')}
                           className={`${iconControlClass} rounded-r-none ${
                             printer.plate_detection_enabled
-                              ? 'bg-green-500/10 text-green-400 hover:bg-green-500/20'
+                              ? 'bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 hover:bg-green-500/20'
                               : 'bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white'
                           }`}
                           title={!hasPermission('printers:update') ? t('printers.plateDetection.noPermission') : (printer.plate_detection_enabled ? t('printers.plateDetection.enabledClick') : t('printers.plateDetection.disabledClick'))}
@@ -4284,7 +4284,7 @@ function PrinterCard({
                           disabled={!status.connected || isCheckingPlate || !hasPermission('printers:update')}
                           className={`flex h-8 w-8 items-center justify-center rounded-r-lg border-l border-bambu-dark-tertiary transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${
                             printer.plate_detection_enabled
-                              ? 'bg-green-500/10 text-green-400 hover:bg-green-500/20'
+                              ? 'bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 hover:bg-green-500/20'
                               : 'bg-bambu-dark text-bambu-gray/50 hover:bg-bambu-dark-tertiary hover:text-white'
                           }`}
                           title={!hasPermission('printers:update') ? t('printers.plateDetection.noPermission') : t('printers.plateDetection.manageCalibration')}
@@ -4306,7 +4306,7 @@ function PrinterCard({
                             disabled={!isPrinting || !hasPermission('printers:control')}
                             className={`${iconControlClass} ${
                               isPrinting
-                                ? 'bg-amber-500/10 text-amber-400 hover:bg-amber-500/20'
+                                ? 'bg-amber-50 dark:bg-amber-500/10 text-amber-700 dark:text-amber-400 hover:bg-amber-500/20'
                                 : 'bg-bambu-dark text-bambu-gray/50 cursor-not-allowed'
                             }`}
                             title={isPrinting ? t('printers.speed.title') : undefined}
@@ -4361,7 +4361,7 @@ function PrinterCard({
                             ? unavailablePrintActionClass
                             : isPaused
                               ? 'bg-bambu-green/20 text-bambu-green hover:bg-bambu-green/30'
-                              : 'bg-yellow-500/20 text-yellow-400 hover:bg-yellow-500/30'
+                              : 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 hover:bg-yellow-500/30'
                           }
                         `}
                         title={!hasPermission('printers:control') ? t('printers.permission.noControl') : (isPaused ? t('printers.resume') : t('printers.pause'))}
@@ -4383,7 +4383,7 @@ function PrinterCard({
                           ${printControlClass}
                           ${stopUnavailable
                             ? unavailablePrintActionClass
-                            : 'bg-red-500/20 text-red-400 hover:bg-red-500/30'
+                            : 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 hover:bg-red-500/30'
                           }
                         `}
                         title={!hasPermission('printers:control') ? t('printers.permission.noControl') : t('printers.stop')}
@@ -4527,7 +4527,7 @@ function PrinterCard({
                                       }}
                                       className={`ml-1 flex items-center gap-0.5 px-1 py-0.5 rounded text-[9px] transition-colors ${
                                         ams.dry_time > 0
-                                          ? 'bg-amber-500/20 text-amber-400'
+                                          ? 'bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400'
                                           : ams.dry_sf_reason?.length
                                             ? 'bg-bambu-dark text-bambu-gray/50 cursor-not-allowed'
                                             : 'bg-bambu-dark text-bambu-gray hover:text-white hover:bg-bambu-dark/80'
@@ -4542,15 +4542,15 @@ function PrinterCard({
                             </div>
                             {/* Drying status bar */}
                             {ams.dry_time > 0 && (
-                              <div className="flex items-center gap-2 rounded-lg bg-amber-500/10 px-2 py-1 text-[9px]">
-                                <Flame className="w-3 h-3 text-amber-400 shrink-0" />
-                                <span className="text-amber-400 font-medium">{t('printers.drying.active')}</span>
+                              <div className="flex items-center gap-2 rounded-lg bg-amber-50 dark:bg-amber-500/10 px-2 py-1 text-[9px]">
+                                <Flame className="w-3 h-3 text-amber-600 dark:text-amber-400 shrink-0" />
+                                <span className="text-amber-700 dark:text-amber-400 font-medium">{t('printers.drying.active')}</span>
                                 {ams.dry_filament && ams.dry_target_temp != null && (
-                                  <span className="text-amber-300/70">
+                                  <span className="text-amber-700/80 dark:text-amber-300/70">
                                     {t('printers.drying.targetSummary', { filament: ams.dry_filament, temp: ams.dry_target_temp })}
                                   </span>
                                 )}
-                                <span className="text-amber-300/70">
+                                <span className="text-amber-700/80 dark:text-amber-300/70">
                                   {t('printers.drying.timeRemaining', {
                                     time: ams.dry_time >= 60
                                       ? `${Math.floor(ams.dry_time / 60)}h ${ams.dry_time % 60}m`
@@ -4560,7 +4560,7 @@ function PrinterCard({
                                 <button
                                   onClick={() => stopDryingMutation.mutate(ams.id)}
                                   disabled={stopDryingMutation.isPending}
-                                  className="ml-auto text-amber-400 hover:text-amber-300 transition-colors disabled:opacity-50"
+                                  className="ml-auto text-amber-700 dark:text-amber-400 hover:text-amber-900 dark:hover:text-amber-300 transition-colors disabled:opacity-50"
                                   title={t('printers.drying.stop')}
                                 >
                                   <X className="w-3 h-3" />
@@ -5013,7 +5013,7 @@ function PrinterCard({
                                     }}
                                     className={`flex items-center gap-0.5 px-1 py-0.5 rounded text-[9px] transition-colors ${
                                       ams.dry_time > 0
-                                        ? 'bg-amber-500/20 text-amber-400'
+                                        ? 'bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400'
                                         : 'bg-bambu-dark text-bambu-gray hover:text-white hover:bg-bambu-dark/80'
                                     }`}
                                     title={ams.dry_time > 0 ? t('printers.drying.stop') : t('printers.drying.start')}
@@ -5025,14 +5025,14 @@ function PrinterCard({
                             </div>
                             {/* HT AMS drying status bar */}
                             {ams.dry_time > 0 && (
-                              <div className="flex items-center gap-1.5 overflow-hidden whitespace-nowrap rounded-lg bg-amber-500/10 px-2 py-1 text-[9px]">
-                                <Flame className="w-3 h-3 text-amber-400 shrink-0" />
+                              <div className="flex items-center gap-1.5 overflow-hidden whitespace-nowrap rounded-lg bg-amber-50 dark:bg-amber-500/10 px-2 py-1 text-[9px]">
+                                <Flame className="w-3 h-3 text-amber-600 dark:text-amber-400 shrink-0" />
                                 {ams.dry_filament && ams.dry_target_temp != null && (
-                                  <span className="text-amber-300/70 text-[8px] truncate">
+                                  <span className="text-amber-700/80 dark:text-amber-300/70 text-[8px] truncate">
                                     {t('printers.drying.targetSummary', { filament: ams.dry_filament, temp: ams.dry_target_temp })}
                                   </span>
                                 )}
-                                <span className="text-amber-300/70 text-[8px] truncate">
+                                <span className="text-amber-700/80 dark:text-amber-300/70 text-[8px] truncate">
                                   {ams.dry_time >= 60
                                     ? `${Math.floor(ams.dry_time / 60)}h ${ams.dry_time % 60}m`
                                     : `${ams.dry_time}m`}
@@ -5040,7 +5040,7 @@ function PrinterCard({
                                 <button
                                   onClick={() => stopDryingMutation.mutate(ams.id)}
                                   disabled={stopDryingMutation.isPending}
-                                  className="ml-auto text-amber-400 hover:text-amber-300 transition-colors disabled:opacity-50 shrink-0"
+                                  className="ml-auto text-amber-700 dark:text-amber-400 hover:text-amber-900 dark:hover:text-amber-300 transition-colors disabled:opacity-50 shrink-0"
                                   title={t('printers.drying.stop')}
                                 >
                                   <X className="w-3 h-3" />
@@ -5551,7 +5551,7 @@ function PrinterCard({
             {/* HA entity buttons row */}
             {scriptPlugs && scriptPlugs.length > 0 && (
               <div className="flex items-center gap-2 mt-2">
-                <Home className="w-3.5 h-3.5 text-blue-400 flex-shrink-0" />
+                <Home className="w-3.5 h-3.5 text-blue-600 dark:text-blue-400 flex-shrink-0" />
                 <span className="text-xs text-bambu-gray">HA:</span>
                 <div className="h-[2px] w-5 bg-bambu-dark-tertiary/50" />
                 <div className="flex flex-wrap gap-1">
@@ -5569,7 +5569,7 @@ function PrinterCard({
                         }}
                         disabled={runScriptMutation.isPending}
                         title={`${isScript ? 'Run' : 'Toggle'} ${script.ha_entity_id}`}
-                        className="px-2 py-0.5 text-xs bg-blue-500/20 text-blue-400 hover:bg-blue-500/30 rounded transition-colors flex items-center gap-1"
+                        className="px-2 py-0.5 text-xs bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 hover:bg-blue-500/30 rounded transition-colors flex items-center gap-1"
                       >
                         <Play className="w-2.5 h-2.5" />
                         {script.name}
@@ -5759,8 +5759,8 @@ function PrinterCard({
             <div className="p-4 space-y-4">
               {plateCheckResult.needs_calibration ? (
                 <>
-                  <div className="p-3 rounded-lg bg-blue-500/20 border border-blue-500/50">
-                    <p className="font-medium text-blue-400">
+                  <div className="p-3 rounded-lg bg-blue-100 dark:bg-blue-500/20 border border-blue-300 dark:border-blue-500/50">
+                    <p className="font-medium text-blue-700 dark:text-blue-400">
                       {t('printers.plateDetection.calibrationRequired')}
                     </p>
                     <p className="text-sm text-bambu-gray mt-1" dangerouslySetInnerHTML={{ __html: t('printers.plateDetection.calibrationInstructions') }} />
@@ -5772,8 +5772,8 @@ function PrinterCard({
                 </>
               ) : (
                 <>
-                  <div className={`p-3 rounded-lg ${plateCheckResult.is_empty ? 'bg-green-500/20 border border-green-500/50' : 'bg-yellow-500/20 border border-yellow-500/50'}`}>
-                    <p className={`font-medium ${plateCheckResult.is_empty ? 'text-green-400' : 'text-yellow-400'}`}>
+                  <div className={`p-3 rounded-lg ${plateCheckResult.is_empty ? 'bg-green-100 dark:bg-green-500/20 border border-green-300 dark:border-green-500/50' : 'bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-300 dark:border-yellow-500/50'}`}>
+                    <p className={`font-medium ${plateCheckResult.is_empty ? 'text-green-700 dark:text-green-400' : 'text-yellow-700 dark:text-yellow-400'}`}>
                       {plateCheckResult.is_empty ? t('printers.plateDetection.plateEmpty') : t('printers.plateDetection.objectsDetected')}
                     </p>
                     <p className="text-sm text-bambu-gray mt-1">
@@ -6120,7 +6120,7 @@ function PrinterCard({
         <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 p-4">
           <div className="bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg shadow-xl w-full max-w-sm p-5">
             <div className="flex items-start gap-3 mb-4">
-              <AlertTriangle className="w-5 h-5 text-yellow-400 flex-shrink-0 mt-0.5" />
+              <AlertTriangle className="w-5 h-5 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5" />
               <div>
                 <h3 className="text-sm font-semibold text-white mb-1">
                   {t('printers.bedJog.notHomedTitle')}
@@ -6147,7 +6147,7 @@ function PrinterCard({
                   bedJogMutation.mutate({ distance: d, force: true });
                   setShowNotHomedModal(null);
                 }}
-                className="w-full px-3 py-2 rounded-lg text-xs font-medium bg-yellow-500/20 text-yellow-400 hover:bg-yellow-500/30 transition-colors"
+                className="w-full px-3 py-2 rounded-lg text-xs font-medium bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 hover:bg-yellow-500/30 transition-colors"
               >
                 {t('printers.bedJog.moveAnyway')}
               </button>
@@ -6764,7 +6764,7 @@ export function AddPrinterModal({
             </Button>
 
             {discoveryError && (
-              <div className="mt-2 text-sm text-red-400">{discoveryError}</div>
+              <div className="mt-2 text-sm text-red-700 dark:text-red-400">{discoveryError}</div>
             )}
 
             {newPrinters.length > 0 && (
@@ -6925,10 +6925,10 @@ export function AddPrinterModal({
               {t('diagnostic.runButton')}
             </button>
             {saveWarning ? (
-              <div className="rounded-lg bg-amber-500/10 border border-amber-500/30 p-3 space-y-3">
+              <div className="rounded-lg bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 p-3 space-y-3">
                 <div className="flex items-start gap-2">
-                  <AlertTriangle className="w-4 h-4 mt-0.5 flex-shrink-0 text-amber-400" />
-                  <p className="text-sm text-amber-300">{t('printers.addPreflight.warning')}</p>
+                  <AlertTriangle className="w-4 h-4 mt-0.5 flex-shrink-0 text-amber-600 dark:text-amber-400" />
+                  <p className="text-sm text-amber-700 dark:text-amber-300">{t('printers.addPreflight.warning')}</p>
                 </div>
                 <DiagnosticChecklist result={saveWarning} />
                 <div className="flex gap-3">
@@ -7051,9 +7051,9 @@ function FirmwareUpdateModal({
       <Card className="w-full max-w-md mx-4">
         <CardContent>
           <div className="flex items-start gap-3 mb-4">
-            <div className={`p-2 rounded-full ${firmwareInfo.update_available ? 'bg-orange-500/20' : 'bg-status-ok/20'}`}>
+            <div className={`p-2 rounded-full ${firmwareInfo.update_available ? 'bg-orange-100 dark:bg-orange-500/20' : 'bg-status-ok/20'}`}>
               {firmwareInfo.update_available
-                ? <Download className="w-5 h-5 text-orange-400" />
+                ? <Download className="w-5 h-5 text-orange-600 dark:text-orange-400" />
                 : <CheckCircle className="w-5 h-5 text-status-ok" />}
             </div>
             <div className="flex-1">
@@ -7085,12 +7085,12 @@ function FirmwareUpdateModal({
                 {showSecondLine && (
                   <div className="flex justify-between items-center text-sm mt-1">
                     <span className="text-bambu-gray">{t('printers.firmwareModal.latestVersion')}</span>
-                    <span className="text-orange-400 font-mono">{displayVersion}</span>
+                    <span className="text-orange-700 dark:text-orange-400 font-mono">{displayVersion}</span>
                   </div>
                 )}
                 {displayNotes && (
                   <details className="mt-3 text-sm" open={!showSecondLine} key={displayVersion ?? 'none'}>
-                    <summary className={`cursor-pointer hover:underline ${showSecondLine ? 'text-orange-400' : 'text-status-ok'}`}>
+                    <summary className={`cursor-pointer hover:underline ${showSecondLine ? 'text-orange-700 dark:text-orange-400' : 'text-status-ok'}`}>
                       {t('printers.firmwareModal.releaseNotes')}
                     </summary>
                     <div className="mt-2 text-bambu-gray text-xs max-h-40 overflow-y-auto whitespace-pre-wrap">
@@ -7121,8 +7121,8 @@ function FirmwareUpdateModal({
                   const relClass = isCurrent
                     ? 'text-bambu-gray'
                     : cmp > 0
-                      ? 'text-orange-400'
-                      : 'text-blue-400';
+                      ? 'text-orange-700 dark:text-orange-400'
+                      : 'text-blue-700 dark:text-blue-400';
                   return (
                     <button
                       key={v.version}
@@ -7130,7 +7130,7 @@ function FirmwareUpdateModal({
                       disabled={!v.file_available || !canUpdate || isCurrent}
                       onClick={() => setSelectedVersion(v.version)}
                       className={`w-full text-left px-3 py-2 text-sm flex items-center justify-between gap-2 transition-colors ${
-                        isSelected ? 'bg-orange-500/10' : 'hover:bg-bambu-dark'
+                        isSelected ? 'bg-orange-50 dark:bg-orange-500/10' : 'hover:bg-bambu-dark'
                       } ${!v.file_available || !canUpdate || isCurrent ? 'opacity-60 cursor-not-allowed' : 'cursor-pointer'}`}
                     >
                       <div className="flex items-center gap-2 min-w-0">
@@ -7139,7 +7139,7 @@ function FirmwareUpdateModal({
                       </div>
                       <span className={`text-xs px-2 py-0.5 rounded-full ${
                         isCurrent
-                          ? 'bg-blue-500/15 text-blue-400 border border-blue-500/30'
+                          ? 'bg-blue-50 dark:bg-blue-500/15 text-blue-700 dark:text-blue-400 border border-blue-300 dark:border-blue-500/30'
                           : v.file_available
                             ? 'bg-bambu-green/15 text-bambu-green border border-bambu-green/30'
                             : 'bg-bambu-gray/10 text-bambu-gray border border-bambu-gray/30'
@@ -7173,7 +7173,7 @@ function FirmwareUpdateModal({
               ) : (
                 <div className="space-y-1">
                   {prepareInfo.errors.map((error, i) => (
-                    <div key={i} className="flex items-center gap-2 text-red-400 text-sm">
+                    <div key={i} className="flex items-center gap-2 text-red-700 dark:text-red-400 text-sm">
                       <AlertCircle className="w-4 h-4 flex-shrink-0" />
                       {error}
                     </div>
@@ -7201,7 +7201,7 @@ function FirmwareUpdateModal({
               </div>
               <p className="text-xs text-bambu-gray mt-1">{uploadStatus.message}</p>
               {uploadStatus.error && (
-                <p className="text-xs text-red-400 mt-1">{uploadStatus.error}</p>
+                <p className="text-xs text-red-700 dark:text-red-400 mt-1">{uploadStatus.error}</p>
               )}
             </div>
           )}
@@ -7459,7 +7459,7 @@ function EditPrinterModal({
                   className="rounded border-bambu-dark-tertiary bg-bambu-dark text-amber-400 focus:ring-amber-400"
                 />
                 <label htmlFor="edit_maintenance_mode" className="text-sm text-bambu-gray flex items-center gap-1.5">
-                  <Wrench className="w-3.5 h-3.5 text-amber-400" />
+                  <Wrench className="w-3.5 h-3.5 text-amber-600 dark:text-amber-400" />
                   {t('printers.maintenance.editFieldLabel')}
                 </label>
               </div>
@@ -7468,10 +7468,10 @@ function EditPrinterModal({
               </p>
             </div>
             {saveWarning ? (
-              <div className="rounded-lg bg-amber-500/10 border border-amber-500/30 p-3 space-y-3">
+              <div className="rounded-lg bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 p-3 space-y-3">
                 <div className="flex items-start gap-2">
-                  <AlertTriangle className="w-4 h-4 mt-0.5 flex-shrink-0 text-amber-400" />
-                  <p className="text-sm text-amber-300">{t('printers.addPreflight.warning')}</p>
+                  <AlertTriangle className="w-4 h-4 mt-0.5 flex-shrink-0 text-amber-600 dark:text-amber-400" />
+                  <p className="text-sm text-amber-700 dark:text-amber-300">{t('printers.addPreflight.warning')}</p>
                 </div>
                 <DiagnosticChecklist result={saveWarning} />
                 <div className="flex gap-3">
@@ -7557,13 +7557,13 @@ function PowerDropdownItem({
   return (
     <div className="flex items-center justify-between px-3 py-2 hover:bg-gray-100 dark:hover:bg-bambu-dark-tertiary">
       <div className="flex items-center gap-2 min-w-0">
-        <span className="text-sm text-gray-900 dark:text-white truncate">{printer.name}</span>
+        <span className="text-sm text-white truncate">{printer.name}</span>
         {plugStatus && (
           <span
             className={`text-xs px-1.5 py-0.5 rounded ${
               plugStatus.state === 'ON'
                 ? 'bg-bambu-green/20 text-bambu-green'
-                : 'bg-red-500/20 text-red-400'
+                : 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400'
             }`}
           >
             {plugStatus.state || '?'}

+ 25 - 25
frontend/src/pages/ProfilesPage.tsx

@@ -600,7 +600,7 @@ function PresetDetailModal({
           {/* Footer */}
           {showDeleteConfirm ? (
             <div className="flex-shrink-0 p-4 border-t border-bambu-dark-tertiary bg-red-500/5">
-              <div className="flex items-center gap-2 mb-3 text-red-400">
+              <div className="flex items-center gap-2 mb-3 text-red-700 dark:text-red-400">
                 <AlertTriangle className="w-5 h-5" />
                 <span className="font-medium">{t('profiles.presets.deleteConfirm')}</span>
               </div>
@@ -770,9 +770,9 @@ function TemplatesModal({
   };
 
   const typeLabels = {
-    filament: { label: t('profiles.presets.types.filament'), icon: Droplet, color: 'text-amber-400' },
-    print: { label: t('profiles.presets.types.process'), icon: Settings2, color: 'text-blue-400' },
-    printer: { label: t('profiles.presets.types.printer'), icon: PrinterIcon, color: 'text-purple-400' },
+    filament: { label: t('profiles.presets.types.filament'), icon: Droplet, color: 'text-amber-600 dark:text-amber-400' },
+    print: { label: t('profiles.presets.types.process'), icon: Settings2, color: 'text-blue-600 dark:text-blue-400' },
+    printer: { label: t('profiles.presets.types.printer'), icon: PrinterIcon, color: 'text-purple-600 dark:text-purple-400' },
   };
 
   const templateToDelete = deleteConfirmId ? templates.find(tpl => tpl.id === deleteConfirmId) : null;
@@ -803,7 +803,7 @@ function TemplatesModal({
             <CardContent className="p-6">
               <div className="flex items-center gap-3 mb-4">
                 <div className="p-2 bg-red-500/20 rounded-lg">
-                  <AlertTriangle className="w-6 h-6 text-red-400" />
+                  <AlertTriangle className="w-6 h-6 text-red-600 dark:text-red-400" />
                 </div>
                 <div>
                   <h3 className="text-lg font-semibold text-white">{t('profiles.templates.deleteTitle')}</h3>
@@ -832,7 +832,7 @@ function TemplatesModal({
           {/* Header */}
           <div className="flex items-center justify-between p-4 border-b border-bambu-dark-tertiary">
             <h2 className="text-lg font-semibold text-white flex items-center gap-2">
-              <Sparkles className="w-5 h-5 text-amber-400" />
+              <Sparkles className="w-5 h-5 text-amber-600 dark:text-amber-400" />
               {t('profiles.templates.title')}
             </h2>
             <button onClick={onClose} className="text-bambu-gray hover:text-white">
@@ -909,7 +909,7 @@ function TemplatesModal({
                             }`}
                           />
                           {editSettingsError && (
-                            <p className="text-xs text-red-400 mt-1">{editSettingsError}</p>
+                            <p className="text-xs text-red-700 dark:text-red-400 mt-1">{editSettingsError}</p>
                           )}
                         </div>
                         <div className="flex gap-2">
@@ -964,7 +964,7 @@ function TemplatesModal({
                       </button>
                       <button
                         onClick={() => setDeleteConfirmId(template.id)}
-                        className="p-1 text-bambu-gray hover:text-red-400"
+                        className="p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400"
                         title={t('common.delete')}
                       >
                         <Trash2 className="w-4 h-4" />
@@ -1117,7 +1117,7 @@ function DiffModal({
           {/* Header */}
           <div className="flex-shrink-0 flex items-center justify-between p-4 border-b border-bambu-dark-tertiary">
             <h2 className="text-lg font-semibold text-white flex items-center gap-2">
-              <GitCompare className="w-5 h-5 text-blue-400" />
+              <GitCompare className="w-5 h-5 text-blue-600 dark:text-blue-400" />
               {t('profiles.diff.title')}
             </h2>
             <button onClick={onClose} className="text-bambu-gray hover:text-white">
@@ -1140,15 +1140,15 @@ function DiffModal({
           {/* Stats and filters */}
           <div className="flex-shrink-0 flex items-center justify-between p-4 border-b border-bambu-dark-tertiary">
             <div className="flex items-center gap-4 text-sm">
-              <span className="flex items-center gap-1 text-green-400">
+              <span className="flex items-center gap-1 text-green-700 dark:text-green-400">
                 <PlusIcon className="w-3.5 h-3.5" />
                 {stats.added} {t('profiles.diff.added')}
               </span>
-              <span className="flex items-center gap-1 text-red-400">
+              <span className="flex items-center gap-1 text-red-700 dark:text-red-400">
                 <MinusIcon className="w-3.5 h-3.5" />
                 {stats.removed} {t('profiles.diff.removed')}
               </span>
-              <span className="flex items-center gap-1 text-amber-400">
+              <span className="flex items-center gap-1 text-amber-700 dark:text-amber-400">
                 <ArrowRight className="w-3.5 h-3.5" />
                 {stats.changed} {t('profiles.diff.changed')}
               </span>
@@ -1221,9 +1221,9 @@ function DiffModal({
                     }[entry.status];
 
                     const statusIcon = {
-                      added: <PlusIcon className="w-3.5 h-3.5 text-green-400" />,
-                      removed: <MinusIcon className="w-3.5 h-3.5 text-red-400" />,
-                      changed: <ArrowRight className="w-3.5 h-3.5 text-amber-400" />,
+                      added: <PlusIcon className="w-3.5 h-3.5 text-green-600 dark:text-green-400" />,
+                      removed: <MinusIcon className="w-3.5 h-3.5 text-red-600 dark:text-red-400" />,
+                      changed: <ArrowRight className="w-3.5 h-3.5 text-amber-600 dark:text-amber-400" />,
                       same: <Equal className="w-3.5 h-3.5 text-bambu-gray-dark" />,
                     }[entry.status];
 
@@ -1237,7 +1237,7 @@ function DiffModal({
                         </td>
                         <td className="p-3">
                           <span className={`text-sm font-mono break-all ${
-                            entry.status === 'removed' ? 'text-red-300' :
+                            entry.status === 'removed' ? 'text-red-700 dark:text-red-300' :
                             entry.status === 'changed' ? 'text-white' : 'text-bambu-gray'
                           }`}>
                             {formatValue(entry.left)}
@@ -1245,7 +1245,7 @@ function DiffModal({
                         </td>
                         <td className="p-3">
                           <span className={`text-sm font-mono break-all ${
-                            entry.status === 'added' ? 'text-green-300' :
+                            entry.status === 'added' ? 'text-green-700 dark:text-green-300' :
                             entry.status === 'changed' ? 'text-white' : 'text-bambu-gray'
                           }`}>
                             {formatValue(entry.right)}
@@ -1839,7 +1839,7 @@ function CreatePresetModal({
             >
               <Code className="w-4 h-4" />
               JSON
-              {jsonError && <AlertCircle className="w-3 h-3 text-red-400" />}
+              {jsonError && <AlertCircle className="w-3 h-3 text-red-600 dark:text-red-400" />}
             </button>
             <div className="flex-1 max-[640px]:hidden" />
             <button
@@ -1908,7 +1908,7 @@ function CreatePresetModal({
                 <div>
                   <div className="flex items-center justify-between mb-3">
                     <h3 className="text-sm font-medium text-white flex items-center gap-2">
-                      <Sparkles className="w-4 h-4 text-amber-400" />
+                      <Sparkles className="w-4 h-4 text-amber-600 dark:text-amber-400" />
                       {t('profiles.templates.title')}
                     </h3>
                     {Object.keys(settingsObj).filter(k => k !== 'inherits').length > 0 && (
@@ -2155,7 +2155,7 @@ function CreatePresetModal({
                               </div>
                               <button
                                 onClick={() => updateField(key, undefined)}
-                                className="p-1 text-bambu-gray hover:text-red-400 transition-colors"
+                                className="p-1 text-bambu-gray hover:text-red-600 dark:hover:text-red-400 transition-colors"
                               >
                                 <X className="w-4 h-4" />
                               </button>
@@ -2202,7 +2202,7 @@ function CreatePresetModal({
             {activeTab === 'json' && (
               <div className="space-y-2">
                 {jsonError && (
-                  <div className="flex items-center gap-2 text-red-400 text-sm">
+                  <div className="flex items-center gap-2 text-red-700 dark:text-red-400 text-sm">
                     <AlertCircle className="w-4 h-4" />
                     {jsonError}
                   </div>
@@ -2592,7 +2592,7 @@ function CloudProfilesView({
         <div className="mb-4 p-3 bg-blue-500/10 border border-blue-500/30 rounded-lg">
           <div className="flex items-center justify-between">
             <div className="flex items-center gap-4">
-              <GitCompare className="w-5 h-5 text-blue-400" />
+              <GitCompare className="w-5 h-5 text-blue-600 dark:text-blue-400" />
               <span className="text-white font-medium">{t('profiles.cloudView.compareMode')}</span>
               <span className="text-bambu-gray">
                 {compareSelection[0]
@@ -2669,7 +2669,7 @@ function CloudProfilesView({
           {/* Filament Column */}
           <div>
             <div className="flex items-center gap-2 mb-3 px-1">
-              <Droplet className="w-4 h-4 text-amber-400" />
+              <Droplet className="w-4 h-4 text-amber-600 dark:text-amber-400" />
               <h3 className="text-sm font-medium text-bambu-gray">{t('profiles.cloudView.columns.filament')}</h3>
               <span className="text-xs text-bambu-gray-dark">
                 ({filteredPresets.filter(p => p.type === 'filament').length})
@@ -2700,7 +2700,7 @@ function CloudProfilesView({
           {/* Process Column */}
           <div>
             <div className="flex items-center gap-2 mb-3 px-1">
-              <Settings2 className="w-4 h-4 text-blue-400" />
+              <Settings2 className="w-4 h-4 text-blue-600 dark:text-blue-400" />
               <h3 className="text-sm font-medium text-bambu-gray">{t('profiles.cloudView.columns.process')}</h3>
               <span className="text-xs text-bambu-gray-dark">
                 ({filteredPresets.filter(p => p.type === 'process').length})
@@ -2731,7 +2731,7 @@ function CloudProfilesView({
           {/* Printer Column */}
           <div>
             <div className="flex items-center gap-2 mb-3 px-1">
-              <PrinterIcon className="w-4 h-4 text-purple-400" />
+              <PrinterIcon className="w-4 h-4 text-purple-600 dark:text-purple-400" />
               <h3 className="text-sm font-medium text-bambu-gray">{t('profiles.cloudView.columns.printer')}</h3>
               <span className="text-xs text-bambu-gray-dark">
                 ({filteredPresets.filter(p => p.type === 'printer').length})

+ 15 - 15
frontend/src/pages/ProjectDetailPage.tsx

@@ -66,7 +66,7 @@ type TFunction = (key: string, options?: Record<string, unknown>) => string;
 function StatusBadge({ status, t }: { status: string; t: TFunction }) {
   const colors = {
     active: 'bg-bambu-green/20 text-bambu-green',
-    completed: 'bg-blue-500/20 text-blue-400',
+    completed: 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400',
     archived: 'bg-bambu-gray/20 text-bambu-gray',
   };
   const color = colors[status as keyof typeof colors] || colors.active;
@@ -172,9 +172,9 @@ function ArchiveGrid({ archives, t }: { archives: Archive[]; t: TFunction }) {
 function PriorityBadge({ priority, t }: { priority: string; t: TFunction }) {
   const config = {
     low: { color: 'bg-gray-500/20 text-gray-400', label: t('projectDetail.priority.low') },
-    normal: { color: 'bg-blue-500/20 text-blue-400', label: t('projectDetail.priority.normal') },
-    high: { color: 'bg-orange-500/20 text-orange-400', label: t('projectDetail.priority.high') },
-    urgent: { color: 'bg-red-500/20 text-red-400', label: t('projectDetail.priority.urgent') },
+    normal: { color: 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400', label: t('projectDetail.priority.normal') },
+    high: { color: 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400', label: t('projectDetail.priority.high') },
+    urgent: { color: 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400', label: t('projectDetail.priority.urgent') },
   };
   const { color, label } = config[priority as keyof typeof config] || config.normal;
 
@@ -193,9 +193,9 @@ function getDueDateStatus(dateString: string | null, t: TFunction): { color: str
   const now = new Date();
   const diffDays = Math.ceil((dueDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
 
-  if (diffDays < 0) return { color: 'text-red-400', label: t('projectDetail.dueDate.overdue') };
-  if (diffDays === 0) return { color: 'text-orange-400', label: t('projectDetail.dueDate.today') };
-  if (diffDays <= 3) return { color: 'text-yellow-400', label: t('projectDetail.dueDate.daysLeft', { count: diffDays }) };
+  if (diffDays < 0) return { color: 'text-red-700 dark:text-red-400', label: t('projectDetail.dueDate.overdue') };
+  if (diffDays === 0) return { color: 'text-orange-700 dark:text-orange-400', label: t('projectDetail.dueDate.today') };
+  if (diffDays <= 3) return { color: 'text-yellow-700 dark:text-yellow-400', label: t('projectDetail.dueDate.daysLeft', { count: diffDays }) };
   return { color: 'text-bambu-gray', label: t('projectDetail.dueDate.daysLeft', { count: diffDays }) };
 }
 
@@ -627,13 +627,13 @@ export function ProjectDetailPage() {
             icon={Clock}
             label={t('projectDetail.stats.printTime')}
             value={formatDurationFromHours(stats.total_print_time_hours)}
-            color="text-yellow-400"
+            color="text-yellow-600 dark:text-yellow-400"
           />
           <StatCard
             icon={Printer}
             label={t('projectDetail.stats.filamentUsed')}
             value={formatFilament(stats.total_filament_grams)}
-            color="text-purple-400"
+            color="text-purple-600 dark:text-purple-400"
           />
         </div>
       )}
@@ -692,7 +692,7 @@ export function ProjectDetailPage() {
                     <p className="text-sm text-bambu-gray">
                       {t('projectDetail.cost.total')}: <span className="text-white font-semibold">{currency}{project.budget.toFixed(2)}</span>
                     </p>
-                    <p className={`text-sm ${remaining >= 0 ? 'text-bambu-green' : 'text-red-400'}`}>
+                    <p className={`text-sm ${remaining >= 0 ? 'text-bambu-green' : 'text-red-700 dark:text-red-400'}`}>
                       {t('projectDetail.cost.remaining')}: <span className="font-semibold">{currency}{remaining.toFixed(2)}</span>
                     </p>
                   </div>
@@ -727,7 +727,7 @@ export function ProjectDetailPage() {
                     <span className={`text-xs px-2 py-0.5 rounded ${
                       child.status === 'completed' ? 'bg-status-ok/20 text-status-ok' :
                       child.status === 'archived' ? 'bg-bambu-gray/20 text-bambu-gray' :
-                      'bg-blue-500/20 text-blue-400'
+                      'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400'
                     }`}>
                       {child.status}
                     </span>
@@ -946,7 +946,7 @@ export function ProjectDetailPage() {
                                 </p>
                                 <span className={`text-xs px-1.5 py-0.5 rounded font-medium ${
                                   file.file_type === '3mf' ? 'bg-bambu-green/20 text-bambu-green'
-                                  : (file.file_type === 'gcode' || file.file_type === 'gcode.3mf') ? 'bg-blue-500/20 text-blue-400'
+                                  : (file.file_type === 'gcode' || file.file_type === 'gcode.3mf') ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400'
                                   : 'bg-bambu-gray/20 text-bambu-gray'
                                 }`}>
                                   {file.file_type.toUpperCase()}
@@ -1221,7 +1221,7 @@ export function ProjectDetailPage() {
                             href={item.sourcing_url}
                             target="_blank"
                             rel="noopener noreferrer"
-                            className="flex items-center gap-1 mt-1 text-xs text-blue-400 hover:text-blue-300 transition-colors"
+                            className="flex items-center gap-1 mt-1 text-xs text-blue-700 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 transition-colors"
                             onClick={(e) => e.stopPropagation()}
                           >
                             <ExternalLink className="w-3 h-3 shrink-0" />
@@ -1286,7 +1286,7 @@ export function ProjectDetailPage() {
                   <div className={`w-8 h-8 rounded-full flex items-center justify-center shrink-0 ${
                     event.event_type === 'print_completed' ? 'bg-status-ok/20 text-status-ok' :
                     event.event_type === 'print_failed' ? 'bg-status-error/20 text-status-error' :
-                    event.event_type === 'print_started' ? 'bg-yellow-500/20 text-yellow-400' :
+                    event.event_type === 'print_started' ? 'bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400' :
                     'bg-bambu-dark-tertiary text-bambu-gray'
                   }`}>
                     {event.event_type === 'print_completed' && <CheckCircle className="w-4 h-4" />}
@@ -1351,7 +1351,7 @@ export function ProjectDetailPage() {
             </div>
             <div className="flex items-center gap-4 text-sm">
               {stats.in_progress_prints > 0 && (
-                <span className="text-yellow-400">
+                <span className="text-yellow-700 dark:text-yellow-400">
                   {t('projectDetail.queue.printing', { count: stats.in_progress_prints })}
                 </span>
               )}

+ 9 - 9
frontend/src/pages/ProjectsPage.tsx

@@ -188,7 +188,7 @@ export function ProjectModal({ project, onClose, onSave, isLoading, currencySymb
               placeholder={t('projects.urlPlaceholder')}
               maxLength={2048}
             />
-            {urlError && <p className="text-xs text-red-400 mt-1">{urlError}</p>}
+            {urlError && <p className="text-xs text-red-600 dark:text-red-400 mt-1">{urlError}</p>}
           </div>
 
           {/* #1155: Cover image — only available when editing an existing project,
@@ -514,7 +514,7 @@ function ProjectCard({ project, onClick, onEdit, onDelete, hasPermission, t }: P
   const getStatusConfig = () => {
     if (isCompleted) return { icon: CheckCircle2, color: 'text-bambu-green', bg: 'bg-bambu-green/10' };
     if (isArchived) return { icon: Archive, color: 'text-bambu-gray', bg: 'bg-bambu-gray/10' };
-    if (project.queue_count > 0) return { icon: Clock, color: 'text-blue-400', bg: 'bg-blue-400/10' };
+    if (project.queue_count > 0) return { icon: Clock, color: 'text-blue-600 dark:text-blue-400', bg: 'bg-blue-50 dark:bg-blue-400/10' };
     return { icon: FolderKanban, color: 'text-bambu-gray', bg: 'bg-bambu-gray/10' };
   };
   const statusConfig = getStatusConfig();
@@ -679,7 +679,7 @@ function ProjectCard({ project, onClick, onEdit, onDelete, hasPermission, t }: P
                   </button>
                   <button
                     className={`w-full px-3 py-2 text-left text-sm flex items-center gap-2 ${
-                      hasPermission('projects:delete') ? 'text-red-400 hover:bg-bambu-dark' : 'text-bambu-gray cursor-not-allowed'
+                      hasPermission('projects:delete') ? 'text-red-600 dark:text-red-400 hover:bg-bambu-dark' : 'text-bambu-gray cursor-not-allowed'
                     }`}
                     onClick={() => { if (hasPermission('projects:delete')) { onDelete(); setShowActions(false); } }}
                     disabled={!hasPermission('projects:delete')}
@@ -746,7 +746,7 @@ function ProjectCard({ project, onClick, onEdit, onDelete, hasPermission, t }: P
               )}
               {/* Failed count */}
               {project.failed_count > 0 && (
-                <div className="text-xs text-red-400">
+                <div className="text-xs text-red-600 dark:text-red-400">
                   {project.failed_count} {t('projects.failed')}
                 </div>
               )}
@@ -760,13 +760,13 @@ function ProjectCard({ project, onClick, onEdit, onDelete, hasPermission, t }: P
                 </div>
               )}
               {project.failed_count > 0 && (
-                <div className="flex items-center gap-1.5 text-red-400">
+                <div className="flex items-center gap-1.5 text-red-600 dark:text-red-400">
                   <AlertTriangle className="w-3.5 h-3.5" />
                   <span>{project.failed_count} {t('projects.failed')}</span>
                 </div>
               )}
               {project.queue_count > 0 && (
-                <div className="flex items-center gap-1.5 text-blue-400">
+                <div className="flex items-center gap-1.5 text-blue-600 dark:text-blue-400">
                   <Clock className="w-3.5 h-3.5" />
                   <span>{project.queue_count} {t('projects.inQueue')}</span>
                 </div>
@@ -820,7 +820,7 @@ function ProjectCard({ project, onClick, onEdit, onDelete, hasPermission, t }: P
         <div className="flex items-center justify-between pt-3 border-t border-bambu-dark-tertiary">
           <div className="flex items-center gap-4 text-xs text-bambu-gray">
             <div className="flex items-center gap-1.5" title={t('projects.printJobs')}>
-              <Layers className="w-3.5 h-3.5 text-blue-400" />
+              <Layers className="w-3.5 h-3.5 text-blue-600 dark:text-blue-400" />
               <span>{project.archive_count} {t('projects.plates')}</span>
             </div>
             <div className="flex items-center gap-1.5" title={t('projects.partsPrinted')}>
@@ -828,13 +828,13 @@ function ProjectCard({ project, onClick, onEdit, onDelete, hasPermission, t }: P
               <span>{project.completed_count} {t('projects.parts')}</span>
             </div>
             {project.failed_count > 0 && (
-              <div className="flex items-center gap-1.5 text-red-400" title={t('projects.failedParts')}>
+              <div className="flex items-center gap-1.5 text-red-600 dark:text-red-400" title={t('projects.failedParts')}>
                 <AlertTriangle className="w-3.5 h-3.5" />
                 <span>{project.failed_count}</span>
               </div>
             )}
             {project.queue_count > 0 && (
-              <div className="flex items-center gap-1.5 text-yellow-400" title={t('projects.inQueue')}>
+              <div className="flex items-center gap-1.5 text-yellow-600 dark:text-yellow-400" title={t('projects.inQueue')}>
                 <ListTodo className="w-3.5 h-3.5" />
                 <span>{project.queue_count}</span>
               </div>

+ 38 - 38
frontend/src/pages/QueuePage.tsx

@@ -85,7 +85,7 @@ function StatusBadge({ status, waitingReason, printerState, t }: { status: Print
   // Special case: pending with waiting_reason shows as "Waiting"
   if (status === 'pending' && waitingReason) {
     return (
-      <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium border text-purple-400 bg-purple-400/10 border-purple-400/20">
+      <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium border text-purple-700 dark:text-purple-400 bg-purple-50 dark:bg-purple-400/10 border-purple-200 dark:border-purple-400/20">
         <Clock className="w-3.5 h-3.5" />
         {t('queue.status.waiting')}
       </span>
@@ -95,7 +95,7 @@ function StatusBadge({ status, waitingReason, printerState, t }: { status: Print
   // Special case: printing but printer is paused
   if (status === 'printing' && printerState === 'PAUSE') {
     return (
-      <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium border text-yellow-400 bg-yellow-400/10 border-yellow-400/20">
+      <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium border text-yellow-700 dark:text-yellow-400 bg-yellow-50 dark:bg-yellow-400/10 border-yellow-200 dark:border-yellow-400/20">
         <Pause className="w-3.5 h-3.5" />
         {t('queue.status.paused')}
       </span>
@@ -104,10 +104,10 @@ function StatusBadge({ status, waitingReason, printerState, t }: { status: Print
 
   const config = {
     pending: { icon: Clock, color: 'text-status-warning bg-status-warning/10 border-status-warning/20', label: t('queue.status.pending') },
-    printing: { icon: Play, color: 'text-blue-400 bg-blue-400/10 border-blue-400/20', label: t('queue.status.printing') },
+    printing: { icon: Play, color: 'text-blue-700 dark:text-blue-400 bg-blue-50 dark:bg-blue-400/10 border-blue-200 dark:border-blue-400/20', label: t('queue.status.printing') },
     completed: { icon: CheckCircle, color: 'text-status-ok bg-status-ok/10 border-status-ok/20', label: t('queue.status.completed') },
     failed: { icon: XCircle, color: 'text-status-error bg-status-error/10 border-status-error/20', label: t('queue.status.failed') },
-    skipped: { icon: SkipForward, color: 'text-orange-400 bg-orange-400/10 border-orange-400/20', label: t('queue.status.skipped') },
+    skipped: { icon: SkipForward, color: 'text-orange-700 dark:text-orange-400 bg-orange-50 dark:bg-orange-400/10 border-orange-200 dark:border-orange-400/20', label: t('queue.status.skipped') },
     cancelled: { icon: X, color: 'text-gray-400 bg-gray-400/10 border-gray-400/20', label: t('queue.status.cancelled') },
   };
 
@@ -284,7 +284,7 @@ function TriStateToggle({
         <button
           onClick={() => onChange(false)}
           disabled={disabled}
-          className={`px-2 py-1 text-xs rounded ${value === false ? 'bg-red-500/20 text-red-400' : 'text-bambu-gray hover:text-white'} disabled:cursor-not-allowed`}
+          className={`px-2 py-1 text-xs rounded ${value === false ? 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400' : 'text-bambu-gray hover:text-white'} disabled:cursor-not-allowed`}
         >
           {t('common.off')}
         </button>
@@ -504,14 +504,14 @@ function SortableQueueItem({
               </Link>
             ) : null}
             {item.batch_name && (
-              <span className="flex-shrink-0 px-1.5 py-0.5 text-[10px] sm:text-xs bg-cyan-500/20 text-cyan-300 rounded border border-cyan-500/30">
+              <span className="flex-shrink-0 px-1.5 py-0.5 text-[10px] sm:text-xs bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 rounded border border-cyan-300 dark:border-cyan-500/30">
                 {item.batch_name}
               </span>
             )}
           </div>
 
           <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs sm:text-sm text-bambu-gray">
-            <span className={`flex items-center gap-1 sm:gap-1.5 ${item.printer_id === null && !item.target_model ? 'text-orange-400' : ''} ${item.target_model && !item.printer_id ? 'text-blue-400' : ''}`}>
+            <span className={`flex items-center gap-1 sm:gap-1.5 ${item.printer_id === null && !item.target_model ? 'text-orange-700 dark:text-orange-400' : ''} ${item.target_model && !item.printer_id ? 'text-blue-700 dark:text-blue-400' : ''}`}>
               <Printer className="w-3 h-3 sm:w-3.5 sm:h-3.5" />
               <span className="truncate max-w-[120px] sm:max-w-none">
               {item.target_model && !item.printer_id
@@ -567,24 +567,24 @@ function SortableQueueItem({
           {/* Options badges */}
           <div className="flex flex-wrap items-center gap-1.5 sm:gap-2 mt-1.5 sm:mt-2">
             {item.manual_start && (
-              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-purple-500/10 text-purple-400 rounded-full border border-purple-500/20 flex items-center gap-1">
+              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-400 rounded-full border border-purple-200 dark:border-purple-500/20 flex items-center gap-1">
                 <Hand className="w-2.5 h-2.5 sm:w-3 sm:h-3" />
                 {t('queue.badges.staged')}
               </span>
             )}
             {item.require_previous_success && (
-              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-orange-500/10 text-orange-400 rounded-full border border-orange-500/20">
+              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-orange-50 dark:bg-orange-500/10 text-orange-700 dark:text-orange-400 rounded-full border border-orange-200 dark:border-orange-500/20">
                 {t('queue.badges.requiresPrevious')}
               </span>
             )}
             {item.auto_off_after && (
-              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-blue-500/10 text-blue-400 rounded-full border border-blue-500/20 flex items-center gap-1">
+              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 rounded-full border border-blue-200 dark:border-blue-500/20 flex items-center gap-1">
                 <Power className="w-2.5 h-2.5 sm:w-3 sm:h-3" />
                 {t('queue.badges.autoPowerOff')}
               </span>
             )}
             {item.gcode_injection && (
-              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-emerald-500/10 text-emerald-400 rounded-full border border-emerald-500/20 flex items-center gap-1">
+              <span className="text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 bg-emerald-50 dark:bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 rounded-full border border-emerald-200 dark:border-emerald-500/20 flex items-center gap-1">
                 <Code className="w-2.5 h-2.5 sm:w-3 sm:h-3" />
                 {t('queue.badges.gcodeInjection')}
               </span>
@@ -638,7 +638,7 @@ function SortableQueueItem({
 
           {/* Waiting reason for model-based assignments */}
           {item.waiting_reason && item.status === 'pending' && (
-            <p className="text-[10px] sm:text-xs text-purple-400 mt-1.5 sm:mt-2 flex items-start gap-1">
+            <p className="text-[10px] sm:text-xs text-purple-700 dark:text-purple-400 mt-1.5 sm:mt-2 flex items-start gap-1">
               <AlertCircle className="w-3 h-3 mt-0.5 flex-shrink-0" />
               <span>{item.waiting_reason}</span>
             </p>
@@ -647,7 +647,7 @@ function SortableQueueItem({
           {/* Filament-short flag from the dispatch pre-flight (#1496). */}
           {item.filament_short && item.status === 'pending' && (
             <p
-              className="text-[10px] sm:text-xs text-yellow-400 mt-1.5 sm:mt-2 flex items-start gap-1"
+              className="text-[10px] sm:text-xs text-yellow-700 dark:text-yellow-400 mt-1.5 sm:mt-2 flex items-start gap-1"
               title={t('queue.filamentShort.rowTooltip')}
             >
               <AlertCircle className="w-3 h-3 mt-0.5 flex-shrink-0" />
@@ -657,7 +657,7 @@ function SortableQueueItem({
 
           {/* Error message */}
           {item.error_message && (
-            <p className="text-[10px] sm:text-xs text-red-400 mt-1.5 sm:mt-2 flex items-center gap-1">
+            <p className="text-[10px] sm:text-xs text-red-700 dark:text-red-400 mt-1.5 sm:mt-2 flex items-center gap-1">
               <AlertCircle className="w-3 h-3" />
               {item.error_message}
             </p>
@@ -676,7 +676,7 @@ function SortableQueueItem({
                 onClick={onStop}
                 disabled={!canModify('queue', 'update', item.created_by_id)}
                 title={!canModify('queue', 'update', item.created_by_id) ? t('queue.permissions.noStopPrint') : t('queue.actions.stopPrint')}
-                className="text-red-400 hover:text-red-300 hover:bg-red-500/10 p-1.5 sm:p-2"
+                className="text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 hover:bg-red-50 dark:hover:bg-red-500/10 p-1.5 sm:p-2"
               >
                 <StopCircle className="w-4 h-4" />
               </Button>
@@ -711,7 +711,7 @@ function SortableQueueItem({
                   onClick={onCancel}
                   disabled={!canModify('queue', 'delete', item.created_by_id)}
                   title={!canModify('queue', 'delete', item.created_by_id) ? t('queue.permissions.noCancel') : t('common.cancel')}
-                  className="text-red-400 hover:text-red-300 hover:bg-red-500/10 p-1.5 sm:p-2"
+                  className="text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 hover:bg-red-50 dark:hover:bg-red-500/10 p-1.5 sm:p-2"
                 >
                   <X className="w-4 h-4" />
                 </Button>
@@ -914,15 +914,15 @@ function SortableBatchRow({
         </button>
         <div className="w-10 h-10 sm:w-12 sm:h-12 flex-shrink-0 bg-bambu-dark rounded-lg flex items-center justify-center">
           {collapsed ? (
-            <Package className="w-5 h-5 text-cyan-300" />
+            <Package className="w-5 h-5 text-cyan-700 dark:text-cyan-300" />
           ) : (
-            <PackageOpen className="w-5 h-5 text-cyan-300" />
+            <PackageOpen className="w-5 h-5 text-cyan-700 dark:text-cyan-300" />
           )}
         </div>
         <div className="flex-1 min-w-0">
           <div className="flex items-center gap-2 mb-1">
             <p className="text-sm sm:text-base text-white font-medium truncate">{batchRow.batchName}</p>
-            <span className="flex-shrink-0 px-1.5 py-0.5 text-[10px] sm:text-xs bg-cyan-500/15 text-cyan-300 rounded border border-cyan-500/30">
+            <span className="flex-shrink-0 px-1.5 py-0.5 text-[10px] sm:text-xs bg-cyan-100 dark:bg-cyan-500/15 text-cyan-700 dark:text-cyan-300 rounded border border-cyan-300 dark:border-cyan-500/30">
               {t('queue.batch.label', { count: agg.count })}
             </span>
           </div>
@@ -940,7 +940,7 @@ function SortableBatchRow({
               </span>
             )}
             {pendingChildren > 0 && rollupStatus === 'pending' && (
-              <span className="flex items-center gap-1 sm:gap-1.5 text-yellow-400">
+              <span className="flex items-center gap-1 sm:gap-1.5 text-yellow-700 dark:text-yellow-400">
                 <Clock className="w-3 h-3 sm:w-3.5 sm:h-3.5" />
                 {t('queue.batch.pendingCount', { count: pendingChildren })}
               </span>
@@ -954,7 +954,7 @@ function SortableBatchRow({
               size="sm"
               onClick={onUngroup}
               title={t('queue.batch.ungroup')}
-              className="text-cyan-300 hover:text-cyan-200 hover:bg-cyan-500/10 p-1.5 sm:p-2"
+              className="text-cyan-700 dark:text-cyan-300 hover:text-cyan-900 dark:hover:text-cyan-200 hover:bg-cyan-50 dark:hover:bg-cyan-500/10 p-1.5 sm:p-2"
             >
               <Ungroup className="w-4 h-4" />
             </Button>
@@ -1133,28 +1133,28 @@ function HistorySection({
                   <ChevronDown className="w-4 h-4 text-bambu-gray shrink-0" />
                 )}
                 {collapsed ? (
-                  <Package className="w-5 h-5 text-cyan-300 shrink-0" />
+                  <Package className="w-5 h-5 text-cyan-700 dark:text-cyan-300 shrink-0" />
                 ) : (
-                  <PackageOpen className="w-5 h-5 text-cyan-300 shrink-0" />
+                  <PackageOpen className="w-5 h-5 text-cyan-700 dark:text-cyan-300 shrink-0" />
                 )}
                 <span className="text-sm text-white font-medium truncate min-w-0 flex-1">
                   {row.batchName}
                 </span>
                 <div className="flex items-center gap-2 text-xs text-bambu-gray shrink-0">
                   {completed > 0 && (
-                    <span className="flex items-center gap-1 text-emerald-400">
+                    <span className="flex items-center gap-1 text-emerald-700 dark:text-emerald-400">
                       <CheckCircle className="w-3 h-3" />
                       {completed}
                     </span>
                   )}
                   {failed > 0 && (
-                    <span className="flex items-center gap-1 text-red-400">
+                    <span className="flex items-center gap-1 text-red-700 dark:text-red-400">
                       <XCircle className="w-3 h-3" />
                       {failed}
                     </span>
                   )}
                   {skipped > 0 && (
-                    <span className="flex items-center gap-1 text-orange-400">
+                    <span className="flex items-center gap-1 text-orange-700 dark:text-orange-400">
                       <SkipForward className="w-3 h-3" />
                       {skipped}
                     </span>
@@ -1972,17 +1972,17 @@ export function QueuePage() {
           {gateBlockedPrinters.map(({ printerId, printerName, skippedCount }) => (
             <div
               key={printerId}
-              className="flex items-center gap-3 px-4 py-3 bg-orange-500/10 border border-orange-500/30 rounded-lg"
+              className="flex items-center gap-3 px-4 py-3 bg-orange-50 dark:bg-orange-500/10 border border-orange-300 dark:border-orange-500/30 rounded-lg"
             >
-              <AlertCircle className="w-5 h-5 text-orange-400 flex-shrink-0" />
+              <AlertCircle className="w-5 h-5 text-orange-600 dark:text-orange-400 flex-shrink-0" />
               <div className="flex-1 min-w-0">
-                <div className="text-sm text-orange-200">
+                <div className="text-sm text-orange-800 dark:text-orange-200">
                   {t('queue.resumeAfterFailure.banner', {
                     printer: printerName,
                     count: skippedCount,
                   })}
                 </div>
-                <div className="text-xs text-orange-200/70 mt-0.5">
+                <div className="text-xs text-orange-800/80 dark:text-orange-200/70 mt-0.5">
                   {t('queue.resumeAfterFailure.bannerHint')}
                 </div>
               </div>
@@ -1990,7 +1990,7 @@ export function QueuePage() {
                 onClick={() =>
                   setResumeConfirm({ printerId, printerName, skippedCount })
                 }
-                className="flex items-center gap-1.5 px-3 py-1.5 bg-orange-500/20 hover:bg-orange-500/30 text-orange-100 text-sm rounded-md border border-orange-500/40 transition-colors flex-shrink-0"
+                className="flex items-center gap-1.5 px-3 py-1.5 bg-orange-100 dark:bg-orange-500/20 hover:bg-orange-200 dark:hover:bg-orange-500/30 text-orange-900 dark:text-orange-100 text-sm rounded-md border border-orange-300 dark:border-orange-500/40 transition-colors flex-shrink-0"
               >
                 <PlayCircle className="w-4 h-4" />
                 {t('queue.resumeAfterFailure.button')}
@@ -2195,7 +2195,7 @@ export function QueuePage() {
             <div>
               <div className="flex flex-wrap items-center justify-between gap-2 mb-3 sm:mb-4">
                 <h2 className="text-base sm:text-lg font-semibold text-white flex items-center gap-2">
-                  <Clock className="w-4 h-4 sm:w-5 sm:h-5 text-yellow-400" />
+                  <Clock className="w-4 h-4 sm:w-5 sm:h-5 text-yellow-600 dark:text-yellow-400" />
                   {t('queue.sections.queued')}
                   <span className="text-xs sm:text-sm font-normal text-bambu-gray">
                     ({t('queue.itemCount', { count: pendingItems.length })})
@@ -2253,7 +2253,7 @@ export function QueuePage() {
                         variant="ghost"
                         size="sm"
                         onClick={() => setGroupBatchModal(true)}
-                        className="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm text-cyan-300 hover:text-cyan-200"
+                        className="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm text-cyan-700 dark:text-cyan-300 hover:text-cyan-900 dark:hover:text-cyan-200"
                         title={t('queue.batch.groupAsBatch')}
                       >
                         <Package className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
@@ -2275,7 +2275,7 @@ export function QueuePage() {
                       variant="ghost"
                       size="sm"
                       onClick={() => bulkCancelMutation.mutate(selectedItems)}
-                      className="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm text-red-400 hover:text-red-300"
+                      className="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300"
                       disabled={bulkCancelMutation.isPending || !hasAnyPermission('queue:delete_own', 'queue:delete_all')}
                       title={!hasAnyPermission('queue:delete_own', 'queue:delete_all') ? t('queue.permissions.noCancelItems') : t('queue.bulkEdit.cancelSelected')}
                     >
@@ -2325,7 +2325,7 @@ export function QueuePage() {
                         return (
                           <div key={bucket.key}>
                             <div className="flex items-center gap-3 px-3 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-t-lg">
-                              <Printer className={`w-4 h-4 ${bucket.isUnassigned ? 'text-orange-400' : bucket.targetModel ? 'text-blue-400' : 'text-bambu-green'}`} />
+                              <Printer className={`w-4 h-4 ${bucket.isUnassigned ? 'text-orange-600 dark:text-orange-400' : bucket.targetModel ? 'text-blue-600 dark:text-blue-400' : 'text-bambu-green'}`} />
                               <span className="font-semibold text-white text-sm">{bucket.label}</span>
                               <span className="text-xs text-bambu-gray flex flex-wrap gap-x-3">
                                 <span>{t('queue.itemCount', { count: agg.count })}</span>
@@ -2371,7 +2371,7 @@ export function QueuePage() {
                       const name = siblings[0].batch_name || t('queue.batch.defaultName');
                       return (
                         <div className="flex items-center gap-3 px-3 py-2 bg-bambu-dark-secondary border-2 border-cyan-400 rounded-lg shadow-2xl">
-                          <Package className="w-4 h-4 text-cyan-300" />
+                          <Package className="w-4 h-4 text-cyan-700 dark:text-cyan-300" />
                           <span className="text-sm text-white font-medium">
                             {t('queue.dragGhost.batch', {
                               defaultValue: '{{name}} ({{count}} copies)',
@@ -2386,7 +2386,7 @@ export function QueuePage() {
                     if (typeof activeDragId === 'number' && selectedItems.includes(activeDragId) && selectedItems.length > 1) {
                       return (
                         <div className="flex items-center gap-3 px-3 py-2 bg-bambu-dark-secondary border-2 border-cyan-400 rounded-lg shadow-2xl">
-                          <Package className="w-4 h-4 text-cyan-300" />
+                          <Package className="w-4 h-4 text-cyan-700 dark:text-cyan-300" />
                           <span className="text-sm text-white font-medium">
                             {t('queue.dragGhost.multiCount', { count: selectedItems.length })}
                           </span>
@@ -2582,7 +2582,7 @@ function GroupBatchModal({ itemCount, defaultName, isSaving, onSave, onClose, t
     <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
       <div className="bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-xl p-6 w-full max-w-md">
         <h3 className="text-lg font-semibold text-white mb-2 flex items-center gap-2">
-          <Package className="w-5 h-5 text-cyan-300" />
+          <Package className="w-5 h-5 text-cyan-700 dark:text-cyan-300" />
           {t('queue.batch.groupAsBatch')}
         </h3>
         <p className="text-sm text-bambu-gray mb-4">

+ 75 - 75
frontend/src/pages/SettingsPage.tsx

@@ -2375,7 +2375,7 @@ export function SettingsPage() {
                       <div className="mt-2 text-xs text-bambu-gray">
                         {t('settings.storageUsageTotal', 'Total')}: <span className="text-white">{storageUsage.total_formatted}</span>
                         {storageUsage.scan_errors > 0 && (
-                          <span className="ml-2 text-amber-400">
+                          <span className="ml-2 text-amber-700 dark:text-amber-400">
                             {t('settings.storageUsageErrors', 'Scan errors')}: {storageUsage.scan_errors}
                           </span>
                         )}
@@ -2575,7 +2575,7 @@ export function SettingsPage() {
                         {updateStatus.message}
                       </div>
                     ) : updateStatus?.status === 'error' ? (
-                      <div className="mt-3 p-2 bg-red-500/20 rounded text-sm text-red-400">
+                      <div className="mt-3 p-2 bg-red-100 dark:bg-red-500/20 rounded text-sm text-red-700 dark:text-red-400">
                         {updateStatus.error || updateStatus.message}
                       </div>
                     ) : updateCheck?.is_ha_addon ? (
@@ -2624,7 +2624,7 @@ export function SettingsPage() {
                     )}
                   </div>
                 ) : updateCheck?.error ? (
-                  <div className="mt-2 p-2 bg-red-500/10 border border-red-500/30 rounded text-sm text-red-400">
+                  <div className="mt-2 p-2 bg-red-50 dark:bg-red-500/10 border border-red-300 dark:border-red-500/30 rounded text-sm text-red-700 dark:text-red-400">
                     {t('settings.failedToCheckUpdates', { error: updateCheck.error })}
                   </div>
                 ) : updateCheck && !updateCheck.update_available ? (
@@ -2652,7 +2652,7 @@ export function SettingsPage() {
           <Card id="card-externalurl">
             <CardHeader>
               <h2 className="text-lg font-semibold text-white flex items-center gap-2">
-                <Globe className="w-5 h-5 text-blue-400" />
+                <Globe className="w-5 h-5 text-blue-600 dark:text-blue-400" />
                 {t('settings.externalUrl')}
               </h2>
             </CardHeader>
@@ -2681,7 +2681,7 @@ export function SettingsPage() {
           <Card id="card-ftpretry">
             <CardHeader>
               <h2 className="text-lg font-semibold text-white flex items-center gap-2">
-                <RefreshCw className="w-5 h-5 text-blue-400" />
+                <RefreshCw className="w-5 h-5 text-blue-600 dark:text-blue-400" />
                 {t('settings.ftpRetry')}
               </h2>
             </CardHeader>
@@ -2785,7 +2785,7 @@ export function SettingsPage() {
                 {localSettings.ha_enabled && haTestResult && (
                   <div className="flex items-center gap-2">
                     <span className={`w-2.5 h-2.5 rounded-full ${haTestResult.success ? 'bg-green-400' : 'bg-red-400'}`} />
-                    <span className={`text-sm ${haTestResult.success ? 'text-green-400' : 'text-red-400'}`}>
+                    <span className={`text-sm ${haTestResult.success ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'}`}>
                       {haTestResult.success ? t('settings.connected') : t('settings.disconnected')}
                     </span>
                   </div>
@@ -2926,13 +2926,13 @@ export function SettingsPage() {
             <CardHeader>
               <div className="flex items-center justify-between">
                 <h2 className="text-lg font-semibold text-white flex items-center gap-2">
-                  <Wifi className="w-5 h-5 text-blue-400" />
+                  <Wifi className="w-5 h-5 text-blue-600 dark:text-blue-400" />
                   {t('settings.mqttPublishing')}
                 </h2>
                 {mqttStatus?.enabled && (
                   <div className="flex items-center gap-2">
                     <span className={`w-2.5 h-2.5 rounded-full ${mqttStatus.connected ? 'bg-green-400' : 'bg-red-400'}`} />
-                    <span className={`text-sm ${mqttStatus.connected ? 'text-green-400' : 'text-red-400'}`}>
+                    <span className={`text-sm ${mqttStatus.connected ? 'text-green-700 dark:text-green-400' : 'text-red-700 dark:text-red-400'}`}>
                       {mqttStatus.connected ? t('settings.connected') : t('settings.disconnected')}
                     </span>
                   </div>
@@ -3083,7 +3083,7 @@ export function SettingsPage() {
           <Card id="card-prometheus">
             <CardHeader>
               <h2 className="text-lg font-semibold text-white flex items-center gap-2">
-                <TrendingUp className="w-5 h-5 text-orange-400" />
+                <TrendingUp className="w-5 h-5 text-orange-600 dark:text-orange-400" />
                 {t('settings.prometheusMetrics')}
               </h2>
             </CardHeader>
@@ -3129,12 +3129,12 @@ export function SettingsPage() {
                   <div className="pt-2 border-t border-bambu-dark-tertiary">
                     <p className="text-sm text-white mb-2">{t('settings.availableMetrics')}</p>
                     <div className="text-xs text-bambu-gray space-y-1">
-                      <p><code className="text-orange-400">bambuddy_printer_connected</code> - {t('settings.metricsConnectionStatus')}</p>
-                      <p><code className="text-orange-400">bambuddy_printer_state</code> - {t('settings.metricsPrinterState')}</p>
-                      <p><code className="text-orange-400">bambuddy_print_progress</code> - {t('settings.metricsPrintProgress')}</p>
-                      <p><code className="text-orange-400">bambuddy_bed_temp_celsius</code> - {t('settings.metricsBedTemp')}</p>
-                      <p><code className="text-orange-400">bambuddy_nozzle_temp_celsius</code> - {t('settings.metricsNozzleTemp')}</p>
-                      <p><code className="text-orange-400">bambuddy_prints_total</code> - {t('settings.metricsPrintsTotal')}</p>
+                      <p><code className="text-orange-700 dark:text-orange-400">bambuddy_printer_connected</code> - {t('settings.metricsConnectionStatus')}</p>
+                      <p><code className="text-orange-700 dark:text-orange-400">bambuddy_printer_state</code> - {t('settings.metricsPrinterState')}</p>
+                      <p><code className="text-orange-700 dark:text-orange-400">bambuddy_print_progress</code> - {t('settings.metricsPrintProgress')}</p>
+                      <p><code className="text-orange-700 dark:text-orange-400">bambuddy_bed_temp_celsius</code> - {t('settings.metricsBedTemp')}</p>
+                      <p><code className="text-orange-700 dark:text-orange-400">bambuddy_nozzle_temp_celsius</code> - {t('settings.metricsNozzleTemp')}</p>
+                      <p><code className="text-orange-700 dark:text-orange-400">bambuddy_prints_total</code> - {t('settings.metricsPrintsTotal')}</p>
                       <p className="text-bambu-gray/70 italic">{t('settings.metricsMore')}</p>
                     </div>
                   </div>
@@ -3152,9 +3152,9 @@ export function SettingsPage() {
           <div className="bg-bambu-dark-secondary rounded-lg p-6 max-w-md w-full mx-4">
             <div className="flex items-center gap-3 mb-4">
               {haTestResult.success ? (
-                <CheckCircle className="w-8 h-8 text-green-400" />
+                <CheckCircle className="w-8 h-8 text-green-600 dark:text-green-400" />
               ) : (
-                <XCircle className="w-8 h-8 text-red-400" />
+                <XCircle className="w-8 h-8 text-red-600 dark:text-red-400" />
               )}
               <h3 className="text-lg font-medium text-white">
                 {haTestResult.success ? t('settings.connectionSuccessful') : t('settings.connectionFailed')}
@@ -3219,7 +3219,7 @@ export function SettingsPage() {
                     {bulkPlugActionMutation.isPending ? (
                       <Loader2 className="w-4 h-4 animate-spin" />
                     ) : (
-                      <PowerOff className="w-4 h-4 text-red-400" />
+                      <PowerOff className="w-4 h-4 text-red-600 dark:text-red-400" />
                     )}
                     {t('settings.allOff')}
                   </Button>
@@ -3243,7 +3243,7 @@ export function SettingsPage() {
             <Card className="mb-6">
               <CardHeader>
                 <h3 className="text-base font-semibold text-white flex items-center gap-2">
-                  <Zap className="w-4 h-4 text-yellow-400" />
+                  <Zap className="w-4 h-4 text-yellow-600 dark:text-yellow-400" />
                   {t('settings.energySummary')}
                   {energyLoading && (
                     <Loader2 className="w-4 h-4 animate-spin text-bambu-gray ml-2" />
@@ -3510,7 +3510,7 @@ export function SettingsPage() {
                       {t('settings.testPassedCount', { count: testAllResult.success })}
                     </span>
                     {testAllResult.failed > 0 && (
-                      <span className="flex items-center gap-1 text-red-400">
+                      <span className="flex items-center gap-1 text-red-700 dark:text-red-400">
                         <XCircle className="w-4 h-4" />
                         {t('settings.testFailedCount', { count: testAllResult.failed })}
                       </span>
@@ -3519,7 +3519,7 @@ export function SettingsPage() {
                   {testAllResult.results.filter(r => !r.success).length > 0 && (
                     <div className="space-y-1 mt-2 pt-2 border-t border-bambu-dark-tertiary">
                       {testAllResult.results.filter(r => !r.success).map((result) => (
-                        <div key={result.provider_id} className="text-xs text-red-400">
+                        <div key={result.provider_id} className="text-xs text-red-700 dark:text-red-400">
                           <span className="font-medium">{result.provider_name}:</span> {result.message}
                         </div>
                       ))}
@@ -3970,38 +3970,38 @@ export function SettingsPage() {
                         <div className="flex items-center gap-2">
                           <div className="flex gap-1 text-xs flex-wrap justify-end">
                             {key.can_read_status && (
-                              <span className="px-1.5 py-0.5 bg-blue-500/20 text-blue-400 rounded">{t('settings.read')}</span>
+                              <span className="px-1.5 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 rounded">{t('settings.read')}</span>
                             )}
                             {key.can_queue && (
-                              <span className="px-1.5 py-0.5 bg-green-500/20 text-green-400 rounded">{t('queue.title')}</span>
+                              <span className="px-1.5 py-0.5 bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 rounded">{t('queue.title')}</span>
                             )}
                             {key.can_control_printer && (
-                              <span className="px-1.5 py-0.5 bg-orange-500/20 text-orange-400 rounded">{t('settings.control')}</span>
+                              <span className="px-1.5 py-0.5 bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 rounded">{t('settings.control')}</span>
                             )}
                             {key.can_manage_library && (
-                              <span className="px-1.5 py-0.5 bg-cyan-500/20 text-cyan-400 rounded">{t('settings.libraryBadge')}</span>
+                              <span className="px-1.5 py-0.5 bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-400 rounded">{t('settings.libraryBadge')}</span>
                             )}
                             {key.can_manage_inventory && (
-                              <span className="px-1.5 py-0.5 bg-pink-500/20 text-pink-400 rounded">{t('settings.inventoryBadge')}</span>
+                              <span className="px-1.5 py-0.5 bg-pink-100 dark:bg-pink-500/20 text-pink-700 dark:text-pink-400 rounded">{t('settings.inventoryBadge')}</span>
                             )}
                             {key.can_manage_maintenance && (
-                              <span className="px-1.5 py-0.5 bg-teal-500/20 text-teal-400 rounded">{t('settings.maintenanceBadge')}</span>
+                              <span className="px-1.5 py-0.5 bg-teal-100 dark:bg-teal-500/20 text-teal-700 dark:text-teal-400 rounded">{t('settings.maintenanceBadge')}</span>
                             )}
                             {key.can_manage_archives && (
-                              <span className="px-1.5 py-0.5 bg-indigo-500/20 text-indigo-400 rounded">{t('settings.archivesBadge')}</span>
+                              <span className="px-1.5 py-0.5 bg-indigo-100 dark:bg-indigo-500/20 text-indigo-700 dark:text-indigo-400 rounded">{t('settings.archivesBadge')}</span>
                             )}
                             {key.can_manage_projects && (
-                              <span className="px-1.5 py-0.5 bg-lime-500/20 text-lime-400 rounded">{t('settings.projectsBadge')}</span>
+                              <span className="px-1.5 py-0.5 bg-lime-100 dark:bg-lime-500/20 text-lime-700 dark:text-lime-400 rounded">{t('settings.projectsBadge')}</span>
                             )}
                             {key.can_access_cloud && (
-                              <span className="px-1.5 py-0.5 bg-purple-500/20 text-purple-400 rounded">{t('settings.cloudBadge', 'Cloud')}</span>
+                              <span className="px-1.5 py-0.5 bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 rounded">{t('settings.cloudBadge', 'Cloud')}</span>
                             )}
                             {key.can_update_energy_cost && (
-                              <span className="px-1.5 py-0.5 bg-amber-500/20 text-amber-400 rounded">{t('settings.energyCostBadge')}</span>
+                              <span className="px-1.5 py-0.5 bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 rounded">{t('settings.energyCostBadge')}</span>
                             )}
                             {key.user_id === null && (
                               <span
-                                className="px-1.5 py-0.5 bg-yellow-500/20 text-yellow-400 rounded"
+                                className="px-1.5 py-0.5 bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 rounded"
                                 title={t('settings.legacyKeyTooltip', 'Created before per-user ownership; recreate to use cloud access')}
                               >
                                 {t('settings.legacyKey', 'Legacy')}
@@ -4013,7 +4013,7 @@ export function SettingsPage() {
                             size="sm"
                             onClick={() => setShowDeleteAPIKeyConfirm(key.id)}
                           >
-                            <Trash2 className="w-4 h-4 text-red-400" />
+                            <Trash2 className="w-4 h-4 text-red-600 dark:text-red-400" />
                           </Button>
                         </div>
                       </div>
@@ -4048,32 +4048,32 @@ export function SettingsPage() {
                 </p>
                 <div className="space-y-2 font-mono text-xs">
                   <div className="p-2 bg-bambu-dark rounded">
-                    <span className="text-blue-400">GET</span>{' '}
+                    <span className="text-blue-700 dark:text-blue-400">GET</span>{' '}
                     <span className="text-white">/api/v1/webhook/status</span>
                     <span className="text-bambu-gray"> - {t('settings.webhook.getAllStatus')}</span>
                   </div>
                   <div className="p-2 bg-bambu-dark rounded">
-                    <span className="text-blue-400">GET</span>{' '}
+                    <span className="text-blue-700 dark:text-blue-400">GET</span>{' '}
                     <span className="text-white">/api/v1/webhook/status/:id</span>
                     <span className="text-bambu-gray"> - {t('settings.webhook.getSpecificStatus')}</span>
                   </div>
                   <div className="p-2 bg-bambu-dark rounded">
-                    <span className="text-green-400">POST</span>{' '}
+                    <span className="text-green-700 dark:text-green-400">POST</span>{' '}
                     <span className="text-white">/api/v1/webhook/queue</span>
                     <span className="text-bambu-gray"> - {t('settings.webhook.addToQueue')}</span>
                   </div>
                   <div className="p-2 bg-bambu-dark rounded">
-                    <span className="text-orange-400">POST</span>{' '}
+                    <span className="text-orange-700 dark:text-orange-400">POST</span>{' '}
                     <span className="text-white">/api/v1/webhook/printer/:id/pause</span>
                     <span className="text-bambu-gray"> - {t('settings.webhook.pausePrint')}</span>
                   </div>
                   <div className="p-2 bg-bambu-dark rounded">
-                    <span className="text-orange-400">POST</span>{' '}
+                    <span className="text-orange-700 dark:text-orange-400">POST</span>{' '}
                     <span className="text-white">/api/v1/webhook/printer/:id/resume</span>
                     <span className="text-bambu-gray"> - {t('settings.webhook.resumePrint')}</span>
                   </div>
                   <div className="p-2 bg-bambu-dark rounded">
-                    <span className="text-red-400">POST</span>{' '}
+                    <span className="text-red-700 dark:text-red-400">POST</span>{' '}
                     <span className="text-white">/api/v1/webhook/printer/:id/stop</span>
                     <span className="text-bambu-gray"> - {t('settings.webhook.stopPrint')}</span>
                   </div>
@@ -4376,7 +4376,7 @@ export function SettingsPage() {
           <Card id="card-preheat">
             <CardHeader>
               <h3 className="text-base font-semibold text-white flex items-center gap-2">
-                <Flame className="w-4 h-4 text-amber-400" />
+                <Flame className="w-4 h-4 text-amber-600 dark:text-amber-400" />
                 {t('settings.preheatTitle', 'Preheat & Heat Soak')}
               </h3>
             </CardHeader>
@@ -4659,7 +4659,7 @@ export function SettingsPage() {
                 {(localSettings.preferred_slicer ?? 'bambu_studio') === 'orcaslicer' && (
                   <div
                     role="alert"
-                    className="text-xs text-amber-200 bg-amber-900/20 border border-amber-700/40 rounded p-2 mt-2"
+                    className="text-xs text-amber-800 dark:text-amber-200 bg-amber-50 dark:bg-amber-900/20 border border-amber-300 dark:border-amber-700/40 rounded p-2 mt-2"
                   >
                     {t(
                       'settings.orcaslicerKnownIssuesWarning',
@@ -4766,7 +4766,7 @@ export function SettingsPage() {
           <Card>
             <CardHeader>
               <h3 className="text-base font-semibold text-white flex items-center gap-2" id="card-drying">
-                <Flame className="w-4 h-4 text-amber-400" />
+                <Flame className="w-4 h-4 text-amber-600 dark:text-amber-400" />
                 {t('settings.queueDrying')}
               </h3>
             </CardHeader>
@@ -5138,7 +5138,7 @@ export function SettingsPage() {
                 {/* Humidity Thresholds */}
                 <div className="space-y-3">
                   <div className="flex items-center gap-2 text-white">
-                    <Droplets className="w-4 h-4 text-blue-400" />
+                    <Droplets className="w-4 h-4 text-blue-600 dark:text-blue-400" />
                     <span className="font-medium">{t('settings.humidity')}</span>
                   </div>
                   <div className="grid grid-cols-2 gap-3">
@@ -5178,7 +5178,7 @@ export function SettingsPage() {
                   <p className="text-xs text-bambu-gray">
                     {t('settings.aboveFairBad')}
                   </p>
-                  <p className="text-xs text-amber-400/70">
+                  <p className="text-xs text-amber-700/80 dark:text-amber-400/70">
                     {t('settings.fairAlsoDryingThreshold')}
                   </p>
                 </div>
@@ -5186,7 +5186,7 @@ export function SettingsPage() {
                 {/* Temperature Thresholds */}
                 <div className="space-y-3 pt-2 border-t border-bambu-dark-tertiary">
                   <div className="flex items-center gap-2 text-white">
-                    <Thermometer className="w-4 h-4 text-orange-400" />
+                    <Thermometer className="w-4 h-4 text-orange-600 dark:text-orange-400" />
                     <span className="font-medium">{t('settings.temperature')}</span>
                   </div>
                   <div className="grid grid-cols-2 gap-3">
@@ -5233,7 +5233,7 @@ export function SettingsPage() {
                 {/* History Retention */}
                 <div className="space-y-3 pt-4 border-t border-bambu-dark-tertiary">
                   <div className="flex items-center gap-2 text-white">
-                    <Database className="w-4 h-4 text-purple-400" />
+                    <Database className="w-4 h-4 text-purple-600 dark:text-purple-400" />
                     <span className="font-medium">{t('settings.historyRetention')}</span>
                   </div>
                   <div>
@@ -5535,7 +5535,7 @@ export function SettingsPage() {
                 <div className="flex items-center gap-3">
                   <div className={`w-10 h-10 rounded-full flex items-center justify-center ${authEnabled ? 'bg-green-500/20' : 'bg-gray-500/20'}`}>
                     {authEnabled ? (
-                      <Lock className="w-5 h-5 text-green-400" />
+                      <Lock className="w-5 h-5 text-green-600 dark:text-green-400" />
                     ) : (
                       <Unlock className="w-5 h-5 text-gray-400" />
                     )}
@@ -5570,7 +5570,7 @@ export function SettingsPage() {
               <CardContent className="py-4">
                 <div className="flex items-start gap-3">
                   <div className="w-10 h-10 rounded-full flex items-center justify-center bg-blue-500/20 flex-shrink-0">
-                    <Mail className="w-5 h-5 text-blue-400" />
+                    <Mail className="w-5 h-5 text-blue-600 dark:text-blue-400" />
                   </div>
                   <div>
                     <h3 className="text-white font-medium">{t('settings.email.advancedAuthEnabled')}</h3>
@@ -5642,9 +5642,9 @@ export function SettingsPage() {
                       </div>
                     </div>
                     {(localSettings?.session_max_hours ?? 24) > 24 && (
-                      <div className="flex items-start gap-2 p-3 rounded-lg bg-yellow-500/10 border border-yellow-500/30">
-                        <AlertTriangle className="w-4 h-4 text-yellow-400 flex-shrink-0 mt-0.5" />
-                        <p className="text-xs text-yellow-200">
+                      <div className="flex items-start gap-2 p-3 rounded-lg bg-yellow-50 dark:bg-yellow-500/10 border border-yellow-300 dark:border-yellow-500/30">
+                        <AlertTriangle className="w-4 h-4 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5" />
+                        <p className="text-xs text-yellow-800 dark:text-yellow-200">
                           {t('settings.sessionPolicy.warning')}
                         </p>
                       </div>
@@ -5675,7 +5675,7 @@ export function SettingsPage() {
                           <p className="text-white font-medium text-lg">{user.username}</p>
                           <div className="flex flex-wrap gap-1 mt-2">
                             {user.is_admin && (
-                              <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-purple-500/20 text-purple-300">
+                              <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300">
                                 {t('settings.admin')}
                               </span>
                             )}
@@ -5684,11 +5684,11 @@ export function SettingsPage() {
                                 key={group.id}
                                 className={`px-2 py-0.5 rounded-full text-xs font-medium ${
                                   group.name === 'Administrators'
-                                    ? 'bg-purple-500/20 text-purple-300'
+                                    ? 'bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300'
                                     : group.name === 'Operators'
-                                    ? 'bg-blue-500/20 text-blue-300'
+                                    ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300'
                                     : group.name === 'Viewers'
-                                    ? 'bg-green-500/20 text-green-300'
+                                    ? 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-300'
                                     : 'bg-gray-500/20 text-gray-300'
                                 }`}
                               >
@@ -5739,12 +5739,12 @@ export function SettingsPage() {
                               <p className="text-white font-medium truncate">{userItem.username}</p>
                               <div className="flex flex-wrap gap-1 mt-1">
                                 {userItem.auth_source === 'ldap' && (
-                                  <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-cyan-500/20 text-cyan-300">
+                                  <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-cyan-100 dark:bg-cyan-500/20 text-cyan-700 dark:text-cyan-300">
                                     LDAP
                                   </span>
                                 )}
                                 {userItem.is_admin && (
-                                  <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-purple-500/20 text-purple-300">
+                                  <span className="px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300">
                                     {t('settings.admin')}
                                   </span>
                                 )}
@@ -5753,11 +5753,11 @@ export function SettingsPage() {
                                     key={group.id}
                                     className={`px-2 py-0.5 rounded-full text-xs font-medium ${
                                       group.name === 'Administrators'
-                                        ? 'bg-purple-500/20 text-purple-300'
+                                        ? 'bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-300'
                                         : group.name === 'Operators'
-                                        ? 'bg-blue-500/20 text-blue-300'
+                                        ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300'
                                         : group.name === 'Viewers'
-                                        ? 'bg-green-500/20 text-green-300'
+                                        ? 'bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-300'
                                         : 'bg-gray-500/20 text-gray-300'
                                     }`}
                                   >
@@ -5822,17 +5822,17 @@ export function SettingsPage() {
                                 <Shield
                                   className={`w-4 h-4 ${
                                     group.name === 'Administrators'
-                                      ? 'text-purple-400'
+                                      ? 'text-purple-600 dark:text-purple-400'
                                       : group.name === 'Operators'
-                                      ? 'text-blue-400'
+                                      ? 'text-blue-600 dark:text-blue-400'
                                       : group.name === 'Viewers'
-                                      ? 'text-green-400'
+                                      ? 'text-green-600 dark:text-green-400'
                                       : 'text-bambu-gray'
                                   }`}
                                 />
                                 <span className="text-white font-medium">{group.name}</span>
                                 {group.is_system && (
-                                  <span className="px-2 py-0.5 rounded text-xs bg-yellow-500/20 text-yellow-400">
+                                  <span className="px-2 py-0.5 rounded text-xs bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400">
                                     {t('settings.system')}
                                   </span>
                                 )}
@@ -6084,7 +6084,7 @@ export function SettingsPage() {
                     minLength={6}
                   />
                   {userFormData.confirmPassword && userFormData.password !== userFormData.confirmPassword && (
-                    <p className="text-red-400 text-xs mt-1">{t('settings.passwordsDoNotMatch')}</p>
+                    <p className="text-red-700 dark:text-red-400 text-xs mt-1">{t('settings.passwordsDoNotMatch')}</p>
                   )}
                 </div>
                 <div>
@@ -6103,7 +6103,7 @@ export function SettingsPage() {
                         />
                         <span className="text-sm text-white">{group.name}</span>
                         {group.is_system && (
-                          <span className="text-xs text-yellow-400">{t('settings.systemBadge')}</span>
+                          <span className="text-xs text-yellow-700 dark:text-yellow-400">{t('settings.systemBadge')}</span>
                         )}
                       </label>
                     ))}
@@ -6207,7 +6207,7 @@ export function SettingsPage() {
                 {/* Username Field */}
                 <div>
                   <label className="block text-sm font-medium text-white mb-2">
-                    {t('settings.username')} {advancedAuthStatus?.advanced_auth_enabled && <span className="text-red-400">*</span>}
+                    {t('settings.username')} {advancedAuthStatus?.advanced_auth_enabled && <span className="text-red-700 dark:text-red-400">*</span>}
                   </label>
                   <input
                     type="text"
@@ -6222,7 +6222,7 @@ export function SettingsPage() {
                 {/* Email Field */}
                 <div>
                   <label className="block text-sm font-medium text-white mb-2">
-                    {t('users.form.email') || 'Email'} {advancedAuthStatus?.advanced_auth_enabled ? <span className="text-red-400">*</span> : <span className="text-bambu-gray font-normal">({t('users.form.optional') || 'optional'})</span>}
+                    {t('users.form.email') || 'Email'} {advancedAuthStatus?.advanced_auth_enabled ? <span className="text-red-700 dark:text-red-400">*</span> : <span className="text-bambu-gray font-normal">({t('users.form.optional') || 'optional'})</span>}
                   </label>
                   <input
                     type="email"
@@ -6269,7 +6269,7 @@ export function SettingsPage() {
                           minLength={6}
                         />
                         {userFormData.confirmPassword && userFormData.password !== userFormData.confirmPassword && (
-                          <p className="text-red-400 text-xs mt-1">{t('settings.passwordsDoNotMatch')}</p>
+                          <p className="text-red-700 dark:text-red-400 text-xs mt-1">{t('settings.passwordsDoNotMatch')}</p>
                         )}
                       </div>
                     )}
@@ -6321,7 +6321,7 @@ export function SettingsPage() {
                         />
                         <span className="text-sm text-white">{group.name}</span>
                         {group.is_system && (
-                          <span className="text-xs text-yellow-400">({t('users.system') || 'System'})</span>
+                          <span className="text-xs text-yellow-700 dark:text-yellow-400">({t('users.system') || 'System'})</span>
                         )}
                       </label>
                     ))}
@@ -6380,7 +6380,7 @@ export function SettingsPage() {
             onClick={(e: React.MouseEvent) => e.stopPropagation()}
           >
             <CardHeader>
-              <div className="flex items-center gap-2 text-red-400">
+              <div className="flex items-center gap-2 text-red-700 dark:text-red-400">
                 <Trash2 className="w-5 h-5" />
                 <h3 className="text-lg font-semibold">{t('settings.deleteUserTitle')}</h3>
               </div>
@@ -6489,9 +6489,9 @@ export function SettingsPage() {
 
       {activeTab === 'backup' && (
         <div id="card-backup">
-          <div className="mb-4 p-3 bg-amber-500/10 border border-amber-500/30 rounded-lg flex items-start gap-2">
-            <Shield className="text-amber-400 flex-shrink-0 mt-0.5" size={16} />
-            <p className="text-sm text-amber-400">{t('backup.includesEncryptionKey')}</p>
+          <div className="mb-4 p-3 bg-amber-50 dark:bg-amber-500/10 border border-amber-300 dark:border-amber-500/30 rounded-lg flex items-start gap-2">
+            <Shield className="text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" size={16} />
+            <p className="text-sm text-amber-700 dark:text-amber-400">{t('backup.includesEncryptionKey')}</p>
           </div>
           <GitHubBackupSettings />
         </div>
@@ -6599,7 +6599,7 @@ export function SettingsPage() {
                     minLength={6}
                   />
                   {changePasswordData.confirmPassword && changePasswordData.newPassword !== changePasswordData.confirmPassword && (
-                    <p className="text-red-400 text-xs mt-1">{t('settings.passwordsDoNotMatch')}</p>
+                    <p className="text-red-700 dark:text-red-400 text-xs mt-1">{t('settings.passwordsDoNotMatch')}</p>
                   )}
                 </div>
               </div>

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio