diff --git a/Web_Backgrounds/pumpkin-theme.css b/Web_Backgrounds/pumpkin-theme.css index 2f11e7f..3793f9d 100644 --- a/Web_Backgrounds/pumpkin-theme.css +++ b/Web_Backgrounds/pumpkin-theme.css @@ -1,70 +1,71 @@ .dark.theme-pumpkin { - --background: 0 30% 4%; - --foreground: 20 50% 95%; - --card: 0 25% 8%; - --card-foreground: 20 50% 95%; - --popover: 0 25% 8%; - --popover-foreground: 20 50% 95%; - --primary: 10 100% 50%; - --primary-foreground: 0 0% 100%; - --secondary: 30 100% 50%; - --secondary-foreground: 0 0% 0%; - --muted: 0 12% 15%; - --muted-foreground: 20 10% 55%; - --accent: 10 100% 50%; + --background: 30 40% 3%; + --foreground: 30 30% 92%; + --card: 25 30% 7%; + --card-foreground: 30 30% 92%; + --popover: 25 30% 7%; + --popover-foreground: 30 30% 92%; + --primary: 25 95% 50%; + --primary-foreground: 30 20% 5%; + --secondary: 35 100% 45%; + --secondary-foreground: 30 20% 5%; + --muted: 25 15% 12%; + --muted-foreground: 30 12% 60%; + --accent: 15 100% 45%; --accent-foreground: 0 0% 100%; --destructive: 0 70% 50%; - --destructive-foreground: 210 40% 98%; - --border: 10 30% 18%; - --input: 10 30% 18%; - --ring: 10 100% 50%; + --destructive-foreground: 0 0% 100%; + --border: 25 20% 16%; + --input: 25 20% 16%; + --ring: 25 95% 50%; --radius: 0.5rem; - --sidebar: 0 30% 4%; - --sidebar-foreground: 20 50% 95%; - --sidebar-primary: 10 100% 50%; - --sidebar-primary-foreground: 0 0% 100%; - --sidebar-accent: 10 100% 50%; + --sidebar: 25 35% 4%; + --sidebar-foreground: 30 30% 92%; + --sidebar-primary: 25 95% 50%; + --sidebar-primary-foreground: 30 20% 5%; + --sidebar-accent: 15 100% 45%; --sidebar-accent-foreground: 0 0% 100%; - --sidebar-border: 10 30% 15%; - --sidebar-ring: 10 100% 50%; + --sidebar-border: 25 18% 14%; + --sidebar-ring: 25 95% 50%; } .light.theme-pumpkin { - --background: 20 30% 96%; - --foreground: 10 50% 10%; + --background: 30 30% 94%; + --foreground: 25 40% 12%; --card: 0 0% 100%; - --card-foreground: 10 50% 10%; + --card-foreground: 25 40% 12%; --popover: 0 0% 100%; - --popover-foreground: 10 50% 10%; - --primary: 10 90% 45%; + --popover-foreground: 25 40% 12%; + --primary: 25 90% 42%; --primary-foreground: 0 0% 100%; - --secondary: 30 90% 45%; + --secondary: 35 90% 42%; --secondary-foreground: 0 0% 100%; - --muted: 20 15% 88%; - --muted-foreground: 10 10% 45%; - --accent: 10 90% 45%; + --muted: 30 15% 86%; + --muted-foreground: 25 10% 42%; + --accent: 15 90% 42%; --accent-foreground: 0 0% 100%; --destructive: 0 80% 50%; --destructive-foreground: 0 0% 100%; - --border: 20 15% 82%; - --input: 20 15% 82%; - --ring: 10 90% 45%; + --border: 25 15% 80%; + --input: 25 15% 80%; + --ring: 25 90% 42%; --radius: 0.5rem; --sidebar: 0 0% 100%; - --sidebar-foreground: 10 50% 10%; - --sidebar-primary: 10 90% 45%; + --sidebar-foreground: 25 40% 12%; + --sidebar-primary: 25 90% 42%; --sidebar-primary-foreground: 0 0% 100%; - --sidebar-accent: 10 90% 45%; + --sidebar-accent: 15 90% 42%; --sidebar-accent-foreground: 0 0% 100%; - --sidebar-border: 20 15% 82%; - --sidebar-ring: 10 90% 45%; + --sidebar-border: 25 15% 80%; + --sidebar-ring: 25 90% 42%; } +/* Warm ambient glow */ .dark.theme-pumpkin body { background: transparent - radial-gradient(ellipse 120% 60% at 20% 30%, rgba(200, 0, 0, 0.2) 0%, transparent 60%), - radial-gradient(ellipse 80% 50% at 80% 70%, rgba(255, 100, 0, 0.15) 0%, transparent 50%), - radial-gradient(ellipse 60% 40% at 50% 50%, rgba(150, 0, 0, 0.1) 0%, transparent 50%); + radial-gradient(ellipse 100% 55% at 20% 25%, rgba(200, 80, 0, 0.18) 0%, transparent 55%), + radial-gradient(ellipse 80% 45% at 80% 75%, rgba(255, 140, 0, 0.12) 0%, transparent 45%), + radial-gradient(ellipse 60% 35% at 50% 50%, rgba(180, 60, 0, 0.08) 0%, transparent 40%); } .dark.theme-pumpkin body > div { @@ -78,195 +79,209 @@ z-index: -1; pointer-events: none; background: - radial-gradient(ellipse 80% 50% at 15% 20%, rgba(200, 50, 0, 0.04) 0%, transparent 60%), - radial-gradient(ellipse 80% 50% at 85% 80%, rgba(255, 100, 0, 0.03) 0%, transparent 60%); + radial-gradient(ellipse 70% 45% at 15% 20%, rgba(200, 80, 0, 0.05) 0%, transparent 55%), + radial-gradient(ellipse 70% 45% at 85% 80%, rgba(255, 140, 0, 0.04) 0%, transparent 55%); } +/* Pumpkin Spice text glow */ .dark.theme-pumpkin .text-glow { - text-shadow: 0 0 10px hsl(10, 100%, 50%), 0 0 30px hsl(10, 100%, 50%), 0 0 60px rgba(255, 0, 0, 0.5); + text-shadow: 0 0 10px hsl(25, 95%, 50%), 0 0 30px hsla(25, 95%, 50%, 0.6), 0 0 60px rgba(200, 80, 0, 0.3); } .light.theme-pumpkin .text-glow { - text-shadow: 0 0 8px hsl(10, 90%, 45%), 0 0 20px hsl(10, 90%, 45%), 0 0 40px rgba(200, 50, 0, 0.3); + text-shadow: 0 0 8px hsl(25, 90%, 42%), 0 0 20px hsla(25, 90%, 42%, 0.4), 0 0 40px rgba(200, 80, 0, 0.15); } -.dark.theme-pumpkin h1, .dark.theme-pumpkin h2, .dark.theme-pumpkin h3 { - background: linear-gradient(135deg, hsl(10, 100%, 50%), hsl(30, 100%, 50%)); +/* Gradient headings — warm orange to amber */ +.dark.theme-pumpkin h1:not(.text-primary):not(.text-foreground), +.dark.theme-pumpkin h2:not(.text-primary):not(.text-foreground), +.dark.theme-pumpkin h3:not(.text-primary):not(.text-foreground) { + background: linear-gradient(135deg, hsl(25, 95%, 55%), hsl(35, 100%, 50%)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } -.light.theme-pumpkin h1, .light.theme-pumpkin h2, .light.theme-pumpkin h3 { - background: linear-gradient(135deg, hsl(10, 90%, 40%), hsl(30, 90%, 40%)); +.light.theme-pumpkin h1:not(.text-primary):not(.text-foreground), +.light.theme-pumpkin h2:not(.text-primary):not(.text-foreground), +.light.theme-pumpkin h3:not(.text-primary):not(.text-foreground) { + background: linear-gradient(135deg, hsl(25, 90%, 40%), hsl(35, 90%, 40%)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } -.dark.theme-pumpkin a { - color: hsl(10, 100%, 55%); -} - -.light.theme-pumpkin a { - color: hsl(10, 90%, 40%); -} - -.dark.theme-pumpkin a:hover { - color: hsl(30, 100%, 55%); - text-shadow: 0 0 8px rgba(255, 100, 0, 0.4); -} - -.light.theme-pumpkin a:hover { - color: hsl(30, 90%, 45%); -} +/* Links */ +.dark.theme-pumpkin a { color: hsl(25, 95%, 55%); } +.light.theme-pumpkin a { color: hsl(25, 90%, 40%); } +.dark.theme-pumpkin a:hover { color: hsl(35, 100%, 55%); text-shadow: 0 0 8px rgba(255, 140, 0, 0.35); } +.light.theme-pumpkin a:hover { color: hsl(35, 90%, 45%); } +/* Blockquotes */ .dark.theme-pumpkin blockquote { - border-left: 3px solid hsl(10, 100%, 50%); - color: hsl(20, 15%, 70%); + border-left: 3px solid hsl(25, 95%, 50%); + color: hsl(30, 15%, 70%); font-style: italic; } - .light.theme-pumpkin blockquote { - border-left: 3px solid hsl(10, 90%, 45%); - color: hsl(10, 10%, 45%); + border-left: 3px solid hsl(25, 90%, 42%); + color: hsl(25, 10%, 42%); font-style: italic; } +/* Code */ .dark.theme-pumpkin code { - color: hsl(10, 100%, 55%); - background: rgba(200, 0, 0, 0.12); - border: 1px solid rgba(200, 0, 0, 0.15); + color: hsl(25, 95%, 55%); + background: rgba(200, 80, 0, 0.1); + border: 1px solid rgba(200, 80, 0, 0.15); } - .light.theme-pumpkin code { - color: hsl(10, 90%, 40%); - background: rgba(200, 50, 0, 0.05); - border: 1px solid rgba(200, 50, 0, 0.1); + color: hsl(25, 90%, 40%); + background: rgba(200, 80, 0, 0.04); + border: 1px solid rgba(200, 80, 0, 0.1); } +.dark.theme-pumpkin pre { background: rgba(25, 12, 0, 0.9); border: 1px solid rgba(200, 80, 0, 0.1); } +.light.theme-pumpkin pre { background: rgba(200, 80, 0, 0.03); border: 1px solid rgba(200, 80, 0, 0.08); } -.dark.theme-pumpkin pre { - background: rgba(20, 0, 0, 0.9); - border: 1px solid rgba(200, 0, 0, 0.1); -} +/* HR */ +.dark.theme-pumpkin hr { border-color: rgba(200, 80, 0, 0.12); } +.light.theme-pumpkin hr { border-color: rgba(200, 80, 0, 0.08); } -.light.theme-pumpkin pre { - background: rgba(200, 50, 0, 0.03); - border: 1px solid rgba(200, 50, 0, 0.08); -} +/* Tables */ +.dark.theme-pumpkin table th { color: hsl(25, 95%, 55%); } +.light.theme-pumpkin table th { color: hsl(25, 90%, 40%); } +.dark.theme-pumpkin table td { border-color: rgba(200, 80, 0, 0.1); } +.light.theme-pumpkin table td { border-color: rgba(200, 80, 0, 0.08); } -.dark.theme-pumpkin hr { - border-color: rgba(200, 0, 0, 0.15); -} +/* Selection */ +.dark.theme-pumpkin ::selection { background: rgba(200, 80, 0, 0.2); color: hsl(0, 0%, 100%); } +.light.theme-pumpkin ::selection { background: rgba(200, 80, 0, 0.1); color: hsl(0, 0%, 0%); } -.light.theme-pumpkin hr { - border-color: rgba(200, 50, 0, 0.1); -} +/* Placeholders */ +.dark.theme-pumpkin input::placeholder, .dark.theme-pumpkin textarea::placeholder { color: hsl(25, 10%, 40%); } +.light.theme-pumpkin input::placeholder, .light.theme-pumpkin textarea::placeholder { color: hsl(25, 10%, 62%); } -.dark.theme-pumpkin table th { - color: hsl(10, 100%, 55%); -} - -.light.theme-pumpkin table th { - color: hsl(10, 90%, 40%); -} - -.dark.theme-pumpkin table td { - border-color: rgba(200, 0, 0, 0.12); -} - -.light.theme-pumpkin table td { - border-color: rgba(200, 50, 0, 0.1); -} - -.dark.theme-pumpkin ::selection { - background: rgba(200, 0, 0, 0.2); - color: hsl(0, 0%, 100%); -} - -.light.theme-pumpkin ::selection { - background: rgba(200, 50, 0, 0.12); - color: hsl(0, 0%, 0%); -} - -.dark.theme-pumpkin input::placeholder, -.dark.theme-pumpkin textarea::placeholder { - color: hsl(20, 10%, 40%); -} - -.light.theme-pumpkin input::placeholder, -.light.theme-pumpkin textarea::placeholder { - color: hsl(10, 10%, 65%); -} - -.dark.theme-pumpkin .page-header-title { - color: hsl(10, 100%, 55%); -} - -.light.theme-pumpkin .page-header-title { - color: hsl(10, 90%, 40%); -} - -.dark.theme-pumpkin .stat-card-value { - color: hsl(10, 100%, 55%); -} - -.light.theme-pumpkin .stat-card-value { - color: hsl(10, 90%, 40%); -} - -.dark.theme-pumpkin .badge { - color: hsl(10, 100%, 55%); -} - -.light.theme-pumpkin .badge { - color: hsl(10, 90%, 40%); -} +/* Page header / stat card / badge */ +.dark.theme-pumpkin .page-header-title, .dark.theme-pumpkin .stat-card-value, .dark.theme-pumpkin .badge { color: hsl(25, 95%, 55%); } +.light.theme-pumpkin .page-header-title, .light.theme-pumpkin .stat-card-value, .light.theme-pumpkin .badge { color: hsl(25, 90%, 40%); } +/* ============================================================ + Dashboard stat card pipeline bars — Pumpkin Spice palette + ============================================================ */ .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(odd) .group .h-1.w-full { - background: linear-gradient(to right, hsl(10, 100%, 50%), hsl(10, 100%, 65%), hsl(10, 100%, 50%)) !important; + background: linear-gradient(to right, hsl(25, 95%, 50%), hsl(25, 95%, 65%), hsl(25, 95%, 50%)) !important; } .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(even) .group .h-1.w-full { - background: linear-gradient(to right, hsl(30, 100%, 50%), hsl(30, 100%, 65%), hsl(30, 100%, 50%)) !important; + background: linear-gradient(to right, hsl(35, 100%, 45%), hsl(35, 100%, 60%), hsl(35, 100%, 45%)) !important; } .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(odd) .group .rounded-xl.shrink-0 { - background: hsla(10, 100%, 50%, 0.1) !important; + background: hsla(25, 95%, 50%, 0.12) !important; } - .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(even) .group .rounded-xl.shrink-0 { - background: hsla(30, 100%, 50%, 0.1) !important; + background: hsla(35, 100%, 45%, 0.12) !important; } .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(odd) .group .rounded-xl.shrink-0 svg { - color: hsl(10, 100%, 50%) !important; + color: hsl(25, 95%, 50%) !important; } - .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(even) .group .rounded-xl.shrink-0 svg { - color: hsl(30, 100%, 50%) !important; + color: hsl(35, 100%, 45%) !important; } .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(odd) .group .absolute.bottom-0.h-1 { - background: linear-gradient(to right, transparent, hsla(10, 100%, 50%, 0.25), transparent) !important; + background: linear-gradient(to right, transparent, hsla(25, 95%, 50%, 0.25), transparent) !important; } - .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(even) .group .absolute.bottom-0.h-1 { - background: linear-gradient(to right, transparent, hsla(30, 100%, 50%, 0.25), transparent) !important; + background: linear-gradient(to right, transparent, hsla(35, 100%, 45%, 0.25), transparent) !important; } .dark.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 .rounded-full.bg-gradient-to-r { - background: linear-gradient(to right, hsl(10, 100%, 50%), hsl(30, 100%, 50%)) !important; + background: linear-gradient(to right, hsl(25, 95%, 50%), hsl(35, 100%, 45%)) !important; } .light.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(odd) .group .h-1.w-full { - background: linear-gradient(to right, hsl(10, 90%, 45%), hsl(10, 90%, 55%), hsl(10, 90%, 45%)) !important; + background: linear-gradient(to right, hsl(25, 90%, 42%), hsl(25, 90%, 55%), hsl(25, 90%, 42%)) !important; } - .light.theme-pumpkin .sm\:grid-cols-2.lg\:grid-cols-3.gap-4.mt-4 > .relative:nth-child(even) .group .h-1.w-full { - background: linear-gradient(to right, hsl(30, 90%, 45%), hsl(30, 90%, 55%), hsl(30, 90%, 45%)) !important; + background: linear-gradient(to right, hsl(35, 90%, 42%), hsl(35, 90%, 55%), hsl(35, 90%, 42%)) !important; } +/* ============================================================ + Chart color overrides — Pumpkin Spice palette + ============================================================ */ +.dark.theme-pumpkin [class*="recharts-"] text, +.light.theme-pumpkin [class*="recharts-"] text { + fill: hsl(30, 12%, 60%) !important; +} + +/* Donut chart gradient stops */ +.dark.theme-pumpkin .recharts-pie-sector:nth-child(1) path, +.light.theme-pumpkin .recharts-pie-sector:nth-child(1) path { + fill: hsl(25, 95%, 50%) !important; +} +.dark.theme-pumpkin .recharts-pie-sector:nth-child(2) path, +.light.theme-pumpkin .recharts-pie-sector:nth-child(2) path { + fill: hsl(35, 100%, 45%) !important; +} +.dark.theme-pumpkin .recharts-pie-sector:nth-child(3) path, +.light.theme-pumpkin .recharts-pie-sector:nth-child(3) path { + fill: hsl(15, 100%, 42%) !important; +} + +/* Stat card icon colors */ +.dark.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(1) .h-8.w-8, +.light.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(1) .h-8.w-8 { + background: hsla(25, 95%, 50%, 0.12) !important; + color: hsl(25, 95%, 50%) !important; +} +.dark.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(2) .h-8.w-8, +.light.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(2) .h-8.w-8 { + background: hsla(35, 100%, 45%, 0.12) !important; + color: hsl(35, 100%, 45%) !important; +} +.dark.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(3) .h-8.w-8, +.light.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(3) .h-8.w-8 { + background: hsla(15, 100%, 42%, 0.12) !important; + color: hsl(15, 100%, 42%) !important; +} + +/* Stat card value colors */ +.dark.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(1) .text-2xl, +.light.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(1) .text-2xl { + color: hsl(25, 95%, 50%) !important; +} +.dark.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(2) .text-2xl, +.light.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(2) .text-2xl { + color: hsl(35, 100%, 45%) !important; +} +.dark.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(3) .text-2xl, +.light.theme-pumpkin .grid.grid-cols-1.sm\:grid-cols-2.lg\:grid-cols-4.gap-4 > div:nth-child(3) .text-2xl { + color: hsl(15, 100%, 42%) !important; +} + +/* Bar chart bar fills */ +.dark.theme-pumpkin .recharts-bar-rectangle:nth-child(1) rect, +.light.theme-pumpkin .recharts-bar-rectangle:nth-child(1) rect { + fill: hsl(25, 95%, 50%) !important; +} +.dark.theme-pumpkin .recharts-bar-rectangle:nth-child(2) rect, +.light.theme-pumpkin .recharts-bar-rectangle:nth-child(2) rect { + fill: hsl(35, 100%, 45%) !important; +} + +/* ============================================================ + Card gradient accent — subtle pumpkin glow on hover + ============================================================ */ +.dark.theme-pumpkin .rounded-xl.border.border-border { + border-color: hsla(25, 20%, 18%, 0.8) !important; +} +.dark.theme-pumpkin .rounded-xl.border.border-border:hover { + border-color: hsla(25, 95%, 50%, 0.25) !important; +} + +/* Growth word on login page — keep brand blue */ .dark.theme-pumpkin .growth-word, .light.theme-pumpkin .growth-word { -webkit-text-fill-color: #1BB0CE !important; @@ -274,70 +289,88 @@ background: none !important; } -/* ============================================================================ - Client Portal Overrides — Background for portal pages - ============================================================================ */ - -/* Make the outer portal container transparent so body::before background shows */ +/* ============================================================ + Client Portal Overrides + ============================================================ */ .dark.theme-pumpkin .min-h-screen.bg-background { background: transparent !important; } -/* Portal sidebar — dark glass */ .dark.theme-pumpkin aside.bg-card.border-r.border-border { - background: hsl(240, 15%, 3%) !important; - border-right-color: hsl(270, 25%, 10%) !important; + background: hsl(25, 35%, 4%) !important; + border-right-color: hsl(25, 20%, 14%) !important; } -/* Portal sidebar nav items — muted text */ .dark.theme-pumpkin aside .text-muted-foreground { - color: hsl(240, 8%, 50%) !important; + color: hsl(30, 10%, 50%) !important; } .dark.theme-pumpkin aside button:hover { - background: hsla(330, 100%, 50%, 0.08) !important; + background: hsla(25, 95%, 50%, 0.08) !important; color: hsl(0, 0%, 90%) !important; } -/* Portal sidebar active nav item */ .dark.theme-pumpkin aside .bg-primary\/10.text-primary { - background: hsl(330, 100%, 50%) !important; + background: hsl(25, 95%, 50%) !important; color: hsl(0, 0%, 100%) !important; - box-shadow: 0 0 10px rgba(255, 0, 127, 0.3), 0 0 20px rgba(255, 0, 127, 0.1); - border-color: hsl(330, 100%, 50%) !important; + box-shadow: 0 0 10px hsla(25, 95%, 50%, 0.3), 0 0 20px hsla(25, 95%, 50%, 0.1); + border-color: hsl(25, 95%, 50%) !important; } .dark.theme-pumpkin aside .bg-primary\/10.text-primary svg { color: hsl(0, 0%, 100%) !important; } -/* Portal header — dark glass */ .dark.theme-pumpkin header.bg-card\/80 { - background: hsl(240, 15%, 3%) !important; - border-bottom-color: hsl(270, 25%, 10%) !important; + background: hsl(25, 35%, 4%) !important; + border-bottom-color: hsl(25, 20%, 14%) !important; } -/* Portal card backgrounds — semi-transparent glass */ .dark.theme-pumpkin .bg-card { - background: hsla(240, 15%, 7%, 0.65) !important; + background: hsla(25, 30%, 7%, 0.65) !important; backdrop-filter: blur(10px) !important; - border-color: hsla(270, 30%, 20%, 0.35) !important; + border-color: hsla(25, 20%, 16%, 0.35) !important; } -/* Portal borders */ .dark.theme-pumpkin .border-border { - border-color: hsl(270, 25%, 12%) !important; + border-color: hsl(25, 18%, 14%) !important; } -/* Portal input fields */ .dark.theme-pumpkin .bg-muted { - background: hsl(240, 12%, 9%) !important; + background: hsl(25, 15%, 10%) !important; } -/* Portal primary buttons */ .dark.theme-pumpkin .bg-primary { - background: hsl(330, 100%, 50%) !important; - box-shadow: 0 0 10px rgba(255, 0, 127, 0.2); + background: hsl(25, 95%, 50%) !important; + box-shadow: 0 0 10px hsla(25, 95%, 50%, 0.2); } .dark.theme-pumpkin .bg-primary:hover { - background: hsl(330, 100%, 55%) !important; - box-shadow: 0 0 15px rgba(255, 0, 127, 0.4); + background: hsl(25, 95%, 55%) !important; + box-shadow: 0 0 15px hsla(25, 95%, 50%, 0.35); +} + +/* Light mode portal */ +.light.theme-pumpkin .min-h-screen.bg-background { + background: transparent !important; +} + +.light.theme-pumpkin aside.bg-card.border-r.border-border { + background: hsl(0, 0%, 100%) !important; + border-right-color: hsl(25, 15%, 82%) !important; +} + +.light.theme-pumpkin header.bg-card\/80 { + background: hsl(0, 0%, 98%) !important; + border-bottom-color: hsl(25, 15%, 82%) !important; +} + +.light.theme-pumpkin .bg-card { + background: hsla(0, 0%, 100%, 0.65) !important; + backdrop-filter: blur(10px) !important; + border-color: hsla(25, 15%, 80%, 0.5) !important; +} + +.light.theme-pumpkin .bg-primary { + background: hsl(25, 90%, 42%) !important; +} +.light.theme-pumpkin .bg-primary:hover { + background: hsl(25, 90%, 48%) !important; } diff --git a/src/app/(dashboard)/ai-assistant/page.tsx b/src/app/(dashboard)/ai-assistant/page.tsx index e70bc7f..9cbe06c 100644 --- a/src/app/(dashboard)/ai-assistant/page.tsx +++ b/src/app/(dashboard)/ai-assistant/page.tsx @@ -73,9 +73,12 @@ Example format: [{"companyName":"Acme Corp","contactName":"John Smith","email":"john@acme.com","phone":"555-0100","description":"Brief description"}] Use realistic company names, names, and emails for the ${job.industry} industry.` - aiChatRef.current?.addAssistantMessage(`🔍 Finding leads for **${job.job_title}**...`) + + const addMsg = (text: string) => aiChatRef.current?.addAssistantMessage(text) try { + addMsg(`🔍 Step 1/3: Asking AI to generate leads for **${job.job_title}**...`) + const res = await fetch("/api/ai/chat", { method: "POST", headers: { "Content-Type": "application/json" }, @@ -84,11 +87,22 @@ Use realistic company names, names, and emails for the ${job.industry} industry. if (!res.ok) { const data = await res.json().catch(() => ({})) - throw new Error(data.error || `Error ${res.status}`) + const statusInfo = `HTTP ${res.status}: ${data.error || res.statusText}` + addMsg(`❌ Step 1/3 failed — AI chat returned ${statusInfo}. Make sure Ollama is running (port 11434) and the AI service on port 3001 is up.`) + setSearching(false) + return } const data = await res.json() const raw = data.response || "" + if (!raw) { + addMsg("❌ Step 1/3 failed — AI returned an empty response.") + setSearching(false) + return + } + + addMsg(`✅ Step 1/3 complete. Parsing AI response...`) + let leads: any[] try { let text = raw.trim() @@ -97,11 +111,19 @@ Use realistic company names, names, and emails for the ${job.industry} industry. leads = JSON.parse(text) if (!Array.isArray(leads)) leads = [leads] } catch (e) { - aiChatRef.current?.addAssistantMessage(`⚠️ AI response wasn't valid JSON. Showing raw output:\n\n${raw.slice(0, 1500)}`) + addMsg(`⚠️ Step 2/3 failed — AI response wasn't valid JSON. Raw output:\n\n${raw.slice(0, 1500)}`) setSearching(false) return } + if (leads.length === 0) { + addMsg("⚠️ Step 2/3 — AI returned an empty array. No leads to create.") + setSearching(false) + return + } + + addMsg(`✅ Step 2/3 — Parsed **${leads.length}** lead${leads.length > 1 ? "s" : ""} from AI response. Step 3/3: Saving to database...`) + let created = 0 let lastError = "" for (const lead of leads.slice(0, 5)) { @@ -119,18 +141,20 @@ Use realistic company names, names, and emails for the ${job.industry} industry. }), }) if (r.ok) created++ - else { const e = await r.json().catch(() => ({})); lastError = e.error || r.statusText; } - } catch (e) { lastError = "Network error" } + else { const e = await r.json().catch(() => ({})); lastError = `API ${res.status} ${e.error || r.statusText}`; } + } catch (e) { + lastError = `Network error: ${e instanceof Error ? e.message : "Failed to reach server"}` + } } if (created > 0) { - aiChatRef.current?.addAssistantMessage(`✅ Created **${created}** lead${created > 1 ? "s" : ""} for **${job.job_title}**! Go to the Leads tab to see them.`) + addMsg(`✅ Created **${created}** lead${created > 1 ? "s" : ""} for **${job.job_title}**! Go to the **Leads** tab to view and manage them.${lastError ? `\n\n⚠️ ${leads.length - created} lead${leads.length - created > 1 ? "s" : ""} failed: ${lastError}` : ""}`) } else { - aiChatRef.current?.addAssistantMessage(`❌ Failed to create leads. Last error: ${lastError || "Unknown"}. Make sure you're logged in with an account that has permission to create leads.`) + addMsg(`❌ Step 3/3 failed — Could not save any leads.\n\nLast error: ${lastError || "Unknown"}\n\nPossible causes:\n• Your session expired — try logging out and back in\n• You don't have permission to create leads\n• The database connection is down`) } } catch (err) { - const msg = err instanceof Error ? err.message : "Search failed" - aiChatRef.current?.addAssistantMessage(`❌ Error: ${msg}. Make sure Ollama is running with the model loaded.`) + const msg = err instanceof Error ? err.message : "Unknown error" + addMsg(`❌ Unexpected error: ${msg}\n\nThis might be a network issue or the AI service (port 3001) is not responding. Try again.`) } finally { setSearching(false) } diff --git a/src/app/(dashboard)/calendar/page.tsx b/src/app/(dashboard)/calendar/page.tsx index 164f88d..e62560a 100644 --- a/src/app/(dashboard)/calendar/page.tsx +++ b/src/app/(dashboard)/calendar/page.tsx @@ -126,11 +126,11 @@ export default function CalendarPage() { fetch("/api/event-users") .then((r) => r.json()) .then((data) => setUsers(data.users || [])) - .catch(() => {}) + .catch((err) => console.error("Failed to fetch event users:", err)) fetch("/api/leads?limit=200") .then((r) => r.json()) .then((data) => setLeads((Array.isArray(data) ? data : data?.leads || []).map((l: any) => ({ id: l.id, contactName: l.contactName, companyName: l.companyName })))) - .catch(() => {}) + .catch((err) => console.error("Failed to fetch leads:", err)) }, [user, router]) useEffect(() => { @@ -139,13 +139,13 @@ export default function CalendarPage() { }, [fetchMonthEvents]) useEffect(() => { - fetchUpcomingEvents().catch(() => {}) + fetchUpcomingEvents().catch((err) => console.error("Failed to fetch upcoming events:", err)) }, [fetchUpcomingEvents]) useEffect(() => { const interval = setInterval(() => { - fetchMonthEvents().catch(() => {}) - fetchUpcomingEvents().catch(() => {}) + fetchMonthEvents().catch((err) => console.error("Failed to fetch month events:", err)) + fetchUpcomingEvents().catch((err) => console.error("Failed to fetch upcoming events:", err)) }, 15000) return () => clearInterval(interval) }, [fetchMonthEvents, fetchUpcomingEvents]) diff --git a/src/app/(dashboard)/campaigns/[id]/page.tsx b/src/app/(dashboard)/campaigns/[id]/page.tsx index 0ca20a3..d72eaac 100644 --- a/src/app/(dashboard)/campaigns/[id]/page.tsx +++ b/src/app/(dashboard)/campaigns/[id]/page.tsx @@ -39,8 +39,11 @@ export default function CampaignDetailPage({ params }: { params: Promise<{ id: s const searchLeads = async (q: string) => { setLeadSearch(q) if (q.length < 2) { setSearchResults([]); return } - const res = await fetch(`/api/leads?search=${encodeURIComponent(q)}&limit=10`) - if (res.ok) setSearchResults(await res.json()) + try { + const res = await fetch(`/api/leads?search=${encodeURIComponent(q)}&limit=10`) + if (res.ok) setSearchResults(await res.json()) + else console.error("Failed to search leads:", res.status, res.statusText) + } catch (err) { console.error("Failed to search leads:", err) } } const addStep = async () => { @@ -84,12 +87,15 @@ export default function CampaignDetailPage({ params }: { params: Promise<{ id: s } const updateStatus = async (status: string) => { - await fetch(`/api/campaigns/${id}`, { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ status }), - }) - fetchCampaign() + try { + const res = await fetch(`/api/campaigns/${id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ status }), + }) + if (!res.ok) console.error("Failed to update campaign status:", res.status, res.statusText) + fetchCampaign() + } catch (err) { console.error("Failed to update campaign status:", err) } } if (loading) return
+
{totals?.teamUtilization ?? 0}%
@@ -157,7 +148,7 @@ export default function ResourcePlanningPage() { {members.map((m) => { const status = statusLabel(m.utilization) return ( -