ソースを参照

Merge branch 'master' into mock

gdias 1 ヶ月 前
コミット
7681fd533c

+ 33 - 0
.claude/settings.json

@@ -0,0 +1,33 @@
+{
+  "permissions": {
+    "allow": [
+      "Bash(curl -s http://localhost:5173)",
+      "Bash(cd /mnt/c/Users/gabri/.claude/projects/--wsl-localhost-Ubuntu-home-gabrielrd-workspace2-nettown-front && pwd)",
+      "Read(//mnt/c/Users/gabri/.claude/projects/**)",
+      "Bash(find /home -name \"nettown_front\" -type d 2>/dev/null | head -5)",
+      "Read(///wsl.localhost/Ubuntu//**)",
+      "Read(//home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/**)",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/**)",
+      "Read(//home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/**)",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/**)",
+      "Read(//home/gabrielrd/workspace2/nettown_front/src/lib/core/models/**)",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/lib/core/models/**)",
+      "Bash(mkdir -p /home/gabrielrd/workspace2/nettown_front/src/routes/\\\\\\(app\\\\\\)/dashboard/executive /home/gabrielrd/workspace2/nettown_front/src/routes/\\\\\\(app\\\\\\)/dashboard/agents /home/gabrielrd/workspace2/nettown_front/src/routes/\\\\\\(app\\\\\\)/dashboard/sla)",
+      "Bash(ls //wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/)",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/**)",
+      "Bash(New-Item -ItemType Directory -Force \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/executive\")",
+      "Bash(Out-Null)",
+      "Bash(New-Item -ItemType Directory -Force \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/agents\")",
+      "Bash(New-Item -ItemType Directory -Force \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/sla\")",
+      "Bash(Write-Output \"Directories created\")",
+      "Bash(ls \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front/src/routes/\\(app\\)/dashboard/\")",
+      "Bash(cd \"//wsl.localhost/Ubuntu/home/gabrielrd/workspace2/nettown_front\" && npm run build 2>&1 | tail -30)",
+      "Read(///wsl.localhost/Ubuntu/home/gabrielrd/workspace2/**)",
+      "PowerShell($env:WSLENV = \"\"; wsl -e bash -c \"cd /home/gabrielrd/workspace2/nettown_front && npm run build 2>&1 | tail -35\")",
+      "PowerShell(wsl -e bash -c \"cd /home/gabrielrd/workspace2/nettown_front && npx svelte-check --tsconfig ./tsconfig.json 2>&1 | tail -20\")"
+    ],
+    "additionalDirectories": [
+      "\\home\\gabrielrd\\workspace2\\nettown_front\\src\\routes\\(app)\\dashboard"
+    ]
+  }
+}

+ 7 - 0
.claude/settings.local.json

@@ -0,0 +1,7 @@
+{
+  "permissions": {
+    "allow": [
+      "Bash(npm run *)"
+    ]
+  }
+}

+ 3 - 0
.gitignore

@@ -21,3 +21,6 @@ Thumbs.db
 # Vite
 vite.config.js.timestamp-*
 vite.config.ts.timestamp-*
+.windsurfrules
+.cursor
+claude.md

+ 29 - 31
src/lib/features/sentiment/domain/sentiment-dashboard.service.js

@@ -2,36 +2,31 @@ import { sentimentDashboardMockSource } from '../data/sentiment-dashboard.mock.j
 import { AlertTriangle, CheckCircle, MessageSquare, TrendingUp } from 'lucide-svelte';
 
 const summaryCardsConfig = [
-	{ 
-		key: 'atRiskClients', 
-		label: 'Clientes em risco',
-		icon: AlertTriangle,
-		color: 'text-red-600 dark:text-red-400',
-		bg: 'bg-red-50 dark:bg-red-400/10'
-	},
-	{ 
-		key: 'opportunities', 
-		label: 'Oportunidades',
-		icon: CheckCircle,
-		color: 'text-emerald-600 dark:text-emerald-400',
-		bg: 'bg-emerald-50 dark:bg-emerald-400/10'
-	},
-	{ 
-		key: 'recentInteractions', 
-		label: 'Interacoes recentes',
-		icon: MessageSquare,
-		color: 'text-sky-600 dark:text-sky-400',
-		bg: 'bg-sky-50 dark:bg-sky-400/10'
-	},
-	{ 
-		key: 'netTrend', 
-		label: 'Tendencia liquida',
-		icon: TrendingUp,
-		color: 'text-indigo-600 dark:text-indigo-400',
-		bg: 'bg-indigo-50 dark:bg-indigo-400/10'
-	}
+	{ key: 'atRiskClients', label: 'Clientes em risco', icon: AlertTriangle, color: 'text-red-600 dark:text-red-400', bg: 'bg-red-50 dark:bg-red-400/10' },
+	{ key: 'opportunities', label: 'Oportunidades', icon: CheckCircle, color: 'text-emerald-600 dark:text-emerald-400', bg: 'bg-emerald-50 dark:bg-emerald-400/10' },
+	{ key: 'recentInteractions', label: 'Interacoes recentes', icon: MessageSquare, color: 'text-sky-600 dark:text-sky-400', bg: 'bg-sky-50 dark:bg-sky-400/10' },
+	{ key: 'netTrend', label: 'Tendencia liquida', icon: TrendingUp, color: 'text-indigo-600 dark:text-indigo-400', bg: 'bg-indigo-50 dark:bg-indigo-400/10' }
 ];
 
+function buildTimelineViews(baseWeekTimeline) {
+	const week = baseWeekTimeline;
+	const day = Array.from({ length: 7 }, (_, idx) => ({
+		period: `Dia ${idx + 1}`,
+		gains: Math.round(28 + idx * 3 + (idx % 2 === 0 ? 4 : 0)),
+		losses: Math.round(12 + idx + (idx % 2 === 0 ? -1 : 1))
+	}));
+	const month = [
+		{ period: 'Jan', gains: 180, losses: 75 },
+		{ period: 'Fev', gains: 195, losses: 70 },
+		{ period: 'Mar', gains: 210, losses: 82 },
+		{ period: 'Abr', gains: 225, losses: 79 },
+		{ period: 'Mai', gains: 238, losses: 84 },
+		{ period: 'Jun', gains: 252, losses: 88 }
+	];
+
+	return { day, week, month };
+}
+
 const priorityLabel = {
 	high: 'Alta prioridade',
 	medium: 'Media prioridade',
@@ -39,10 +34,12 @@ const priorityLabel = {
 };
 
 export function getSentimentDashboardViewModel() {
+	const timelineViews = buildTimelineViews(sentimentDashboardMockSource.timeline);
 	return {
 		summaryCards: mapSummaryCards(sentimentDashboardMockSource.summary),
 		alerts: mapAlerts(sentimentDashboardMockSource.alerts),
-		timeline: sentimentDashboardMockSource.timeline,
+		timeline: timelineViews.week,
+		timelineViews,
 		aspects: mapAspects(sentimentDashboardMockSource.aspects)
 	};
 }
@@ -122,8 +119,9 @@ export function getAlertInsight(alertId, viewModel) {
 	};
 }
 
-export function getTimelineInsight(period, viewModel) {
-	const timelinePoint = viewModel.timeline.find((item) => item.period === period);
+export function getTimelineInsight(period, viewModel, timeframe = 'week') {
+	const timelineCollection = viewModel.timelineViews?.[timeframe] ?? viewModel.timeline ?? [];
+	const timelinePoint = timelineCollection.find((item) => item.period === period);
 	if (!timelinePoint) return createFallbackInsight();
 
 	const balance = timelinePoint.gains - timelinePoint.losses;

+ 39 - 12
src/lib/features/sentiment/ui/GainLossChart.svelte

@@ -1,5 +1,18 @@
 <script>
-	let { data = [], onPointSelect = () => {}, selectedPeriod = null } = $props();
+	const defaultTimeframeOptions = [
+		{ id: 'day', label: 'Diário' },
+		{ id: 'week', label: 'Semanal' },
+		{ id: 'month', label: 'Mensal' }
+	];
+
+	let {
+		data = [],
+		onPointSelect = () => {},
+		selectedPeriod = null,
+		timeframeOptions = defaultTimeframeOptions,
+		selectedTimeframe = 'week',
+		onTimeframeChange = () => {}
+	} = $props();
 
 	const chartWidth = 760;
 	const chartHeight = 320;
@@ -25,18 +38,32 @@
 </script>
 
 <section class="h-[460px] flex flex-col rounded-xl border border-slate-200 dark:border-slate-800 bg-white dark:bg-[#1e293b] p-5 shadow-sm transition-colors duration-200">
-	<div class="mb-6 flex items-center justify-between border-b border-slate-100 dark:border-slate-800/50 pb-3 shrink-0">
-		<h2 class="text-sm font-bold tracking-wider text-slate-500 dark:text-slate-400 uppercase">
-			Opinião do Público
-		</h2>
-		<div class="flex items-center gap-4 text-xs font-bold">
-			<span class="flex items-center gap-1.5 text-emerald-600 dark:text-emerald-400">
-				<i class="h-2.5 w-2.5 rounded-full bg-emerald-500"></i>Positivo
-			</span>
-			<span class="flex items-center gap-1.5 text-red-600 dark:text-red-400">
-				<i class="h-2.5 w-2.5 rounded-full bg-red-500"></i>Negativo
-			</span>
+	<div class="mb-6 flex flex-wrap items-center justify-between gap-4 border-b border-slate-100 dark:border-slate-800/50 pb-3 shrink-0">
+		<div>
+			<h2 class="text-sm font-bold tracking-wider text-slate-500 dark:text-slate-400 uppercase">
+				Opinião do Público
+			</h2>
+			<div class="flex items-center gap-4 text-xs font-bold mt-2">
+				<span class="flex items-center gap-1.5 text-emerald-600 dark:text-emerald-400">
+					<i class="h-2.5 w-2.5 rounded-full bg-emerald-500"></i>Positivo
+				</span>
+				<span class="flex items-center gap-1.5 text-red-600 dark:text-red-400">
+					<i class="h-2.5 w-2.5 rounded-full bg-red-500"></i>Negativo
+				</span>
+			</div>
 		</div>
+		<label class="flex items-center gap-2 text-xs font-semibold text-slate-500 dark:text-slate-400">
+			<span>Período</span>
+			<select
+				class="rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-sm font-medium text-slate-700 shadow-sm transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-600 dark:bg-[#0f172a] dark:text-slate-200"
+				value={selectedTimeframe}
+				onchange={(event) => onTimeframeChange(event.currentTarget.value)}
+			>
+				{#each timeframeOptions as option}
+					<option value={option.id}>{option.label}</option>
+				{/each}
+			</select>
+		</label>
 	</div>
 
 	<div class="flex-1 w-full flex items-center justify-center pt-2">

+ 319 - 242
src/routes/(app)/+layout.svelte

@@ -1,246 +1,323 @@
 <script>
-    import { page } from '$app/stores';
-    import { LayoutDashboard, MessageSquare, BarChart2, Settings, LogOut, Bell, Search, Menu, X, TrendingUp, ChevronLeft, ChevronRight, Moon, Sun, UserRound, User, Key, CreditCard, HelpCircle } from 'lucide-svelte';
-    import { goto } from '$app/navigation';
-    import logoWhite from '$lib/assets/images/nettown_white_logo.svg';
-    import logoBlack from '$lib/assets/images/nettown_black_logo.svg.svg';
-    import { theme, toggleTheme } from '$lib/core/stores/theme';
-    import { onMount } from 'svelte';
-
-    let { children } = $props();
-    let isMobileMenuOpen = $state(false);
-    let isSidebarCollapsed = $state(false);
-    let currentTheme = $state('light');
-    let isUserMenuOpen = $state(false);
-
-    onMount(() => {
-        theme.subscribe(val => {
-            currentTheme = val;
-        });
-    });
-
-    const navItems = [
-        { name: 'Visão Geral', href: '/dashboard', icon: LayoutDashboard },
-        { name: 'Interações', href: '/dashboard/interactions', icon: MessageSquare },
-        { name: 'Análise de Sentimento', href: '/dashboard/analytics', icon: BarChart2 },
-        { name: 'Personas', href: '/dashboard/personas', icon: UserRound },
-        { name: 'Evolução', href: '/dashboard/evolucao', icon: TrendingUp },
-        { name: 'Configurações', href: '/dashboard/settings', icon: Settings },
-    ];
-
-    function handleLogout() {
-        goto('/');
-    }
-
-    function toggleMobileMenu() {
-        isMobileMenuOpen = !isMobileMenuOpen;
-    }
-
-    function toggleSidebar() {
-        isSidebarCollapsed = !isSidebarCollapsed;
-    }
-
-    function toggleUserMenu() {
-        isUserMenuOpen = !isUserMenuOpen;
-    }
-
-    function handleUserAction(action) {
-        isUserMenuOpen = false;
-        switch(action) {
-            case 'profile':
-                // TODO: Navigate to profile page
-                console.log('Navigate to profile');
-                break;
-            case 'password':
-                // TODO: Open password change modal
-                console.log('Open password change modal');
-                break;
-            case 'billing':
-                // TODO: Navigate to billing page
-                console.log('Navigate to billing');
-                break;
-            case 'help':
-                // TODO: Open help modal
-                console.log('Open help modal');
-                break;
-            case 'logout':
-                handleLogout();
-                break;
-        }
-    }
+	import { page } from '$app/state';
+	import {
+		LayoutDashboard,
+		MessageSquare,
+		BarChart2,
+		Settings,
+		LogOut,
+		Bell,
+		Search,
+		Menu,
+		X,
+		TrendingUp,
+		ChevronLeft,
+		ChevronRight,
+		Moon,
+		Sun,
+		UserRound,
+		User,
+		CreditCard,
+		HelpCircle,
+		PieChart,
+		Users,
+		ShieldCheck
+	} from 'lucide-svelte';
+	import { goto } from '$app/navigation';
+	import logoWhite from '$lib/assets/images/nettown_white_logo.svg';
+	import logoBlack from '$lib/assets/images/nettown_black_logo.svg.svg';
+	import { theme, toggleTheme } from '$lib/core/stores/theme';
+	import { onMount } from 'svelte';
+
+	let { children } = $props();
+	let isMobileMenuOpen = $state(false);
+	let isSidebarCollapsed = $state(false);
+	let currentTheme = $state('light');
+	let isUserMenuOpen = $state(false);
+
+	onMount(() => {
+		theme.subscribe((val) => {
+			currentTheme = val;
+		});
+	});
+
+	const navItems = [
+		{ name: 'Visão Geral', href: '/dashboard', icon: LayoutDashboard },
+		{ name: 'Interações', href: '/dashboard/interactions', icon: MessageSquare },
+		{ name: 'Análise de Sentimento', href: '/dashboard/analytics', icon: BarChart2 },
+		{ name: 'Personas', href: '/dashboard/personas', icon: UserRound },
+		{ name: 'Evolução', href: '/dashboard/evolucao', icon: TrendingUp },
+		{ name: 'Configurações', href: '/dashboard/settings', icon: Settings },
+		{ name: 'Dashboard Executivo', href: '/dashboard/executive', icon: PieChart },
+		{ name: 'Agentes', href: '/dashboard/agents', icon: Users },
+		{ name: 'Config. SLA', href: '/dashboard/sla', icon: ShieldCheck }
+	];
+
+	function handleLogout() {
+		goto('/');
+	}
+
+	function toggleMobileMenu() {
+		isMobileMenuOpen = !isMobileMenuOpen;
+	}
+
+	function toggleSidebar() {
+		isSidebarCollapsed = !isSidebarCollapsed;
+	}
+
+	function isNavItemActive(href) {
+		const currentPath = page.url.pathname;
+		if (href === '/dashboard') {
+			return currentPath === '/dashboard';
+		}
+		return currentPath === href || currentPath.startsWith(`${href}/`);
+	}
+
+	function toggleUserMenu() {
+		isUserMenuOpen = !isUserMenuOpen;
+	}
+
+	function closeUserMenu() {
+		isUserMenuOpen = false;
+	}
 </script>
 
-<div class="h-screen w-screen bg-slate-50 dark:bg-[#0f172a] text-slate-900 dark:text-slate-300 font-sans flex overflow-hidden transition-colors duration-200">
-    <!-- Mobile Sidebar Overlay -->
-    {#if isMobileMenuOpen}
-        <div class="fixed inset-0 bg-slate-950/80 z-40 lg:hidden" onclick={toggleMobileMenu} onkeydown={(e) => e.key === 'Escape' && toggleMobileMenu()} tabindex="0" role="button" aria-label="Fechar menu"></div>
-    {/if}
-
-    <!-- User Menu Overlay -->
-    {#if isUserMenuOpen}
-        <div class="fixed inset-0 z-40" onclick={() => isUserMenuOpen = false} onkeydown={(e) => e.key === 'Escape' && (isUserMenuOpen = false)} tabindex="0" role="button" aria-label="Fechar menu"></div>
-    {/if}
-
-    <!-- Sidebar -->
-    <aside class="fixed lg:static inset-y-0 left-0 z-50 h-full bg-white dark:bg-[#1e293b] border-r border-slate-200 dark:border-slate-800 flex flex-col transition-all duration-300 ease-in-out {isSidebarCollapsed ? 'w-20' : 'w-64'} {isMobileMenuOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'} shrink-0 shadow-sm dark:shadow-none">
-        <div class="h-16 flex items-center justify-between px-4 border-b border-slate-200 dark:border-slate-800 shrink-0">
-            <div class="flex items-center gap-2 text-indigo-600 dark:text-indigo-400 overflow-hidden">
-                <div class="h-6 flex items-center shrink-0 {isSidebarCollapsed ? 'w-8 justify-center' : 'w-auto'}">
-                    {#if isSidebarCollapsed}
-                        <TrendingUp size={24} strokeWidth={2.5} class="text-indigo-600 dark:text-indigo-500" />
-                    {:else}
-                        <img src={currentTheme === 'dark' ? logoWhite : logoBlack} alt="NetTown Analytics" class="h-full w-auto" />
-                    {/if}
-                </div>
-            </div>
-            
-            <button class="hidden lg:flex items-center justify-center p-1.5 text-slate-400 hover:text-slate-700 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors shrink-0" onclick={toggleSidebar}>
-                {#if isSidebarCollapsed}
-                    <ChevronRight size={18} />
-                {:else}
-                    <ChevronLeft size={18} />
-                {/if}
-            </button>
-
-            <button class="lg:hidden text-slate-400 hover:text-slate-700 dark:hover:text-white p-1 shrink-0" onclick={toggleMobileMenu}>
-                <X size={20} />
-            </button>
-        </div>
-
-        <div class="flex-1 py-6 flex flex-col gap-2 overflow-y-auto overflow-x-hidden {isSidebarCollapsed ? 'px-2' : 'px-4'}">
-            <div class="text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2 px-2 whitespace-nowrap {isSidebarCollapsed ? 'text-center text-[10px]' : ''}">
-                {isSidebarCollapsed ? 'Menu' : 'Menu Principal'}
-            </div>
-            {#each navItems as item}
-                {@const Icon = item.icon}
-                <a 
-                    href={item.href} 
-                    title={isSidebarCollapsed ? item.name : ''}
-                    class="flex items-center gap-3 py-2.5 rounded-lg transition-colors {$page.url.pathname === item.href || $page.url.pathname.startsWith(item.href + '/') ? 'bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-400 font-medium' : 'text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 hover:text-slate-900 dark:hover:text-slate-200'} {isSidebarCollapsed ? 'justify-center px-0' : 'px-3'}"
-                    onclick={() => isMobileMenuOpen = false}
-                >
-                    <Icon size={isSidebarCollapsed ? 22 : 18} strokeWidth={$page.url.pathname === item.href ? 2.5 : 2} class="shrink-0" />
-                    {#if !isSidebarCollapsed}
-                        <span class="truncate">{item.name}</span>
-                    {/if}
-                </a>
-            {/each}
-        </div>
-
-        <div class="p-4 border-t border-slate-200 dark:border-slate-800 shrink-0">
-            <button 
-                onclick={handleLogout} 
-                title={isSidebarCollapsed ? 'Sair' : ''}
-                class="w-full flex items-center gap-3 py-2.5 rounded-lg text-slate-600 dark:text-slate-400 hover:bg-red-50 dark:hover:bg-slate-800 hover:text-red-600 dark:hover:text-red-400 transition-colors {isSidebarCollapsed ? 'justify-center px-0' : 'px-3'}"
-            >
-                <LogOut size={18} class="shrink-0" />
-                {#if !isSidebarCollapsed}
-                    <span>Sair</span>
-                {/if}
-            </button>
-        </div>
-    </aside>
-
-    <!-- Main Wrapper -->
-    <div class="flex-1 flex flex-col min-w-0 h-full overflow-hidden relative">
-        <!-- Top Header -->
-        <header class="h-16 flex items-center justify-between px-4 lg:px-8 bg-white/95 dark:bg-[#1e293b]/95 backdrop-blur-sm border-b border-slate-200 dark:border-slate-800 shrink-0 w-full z-30 transition-colors duration-200">
-            <div class="flex items-center gap-4">
-                <button class="lg:hidden text-slate-400 hover:text-slate-700 dark:hover:text-white" onclick={toggleMobileMenu}>
-                    <Menu size={24} />
-                </button>
-                <div class="hidden sm:flex items-center relative">
-                    <Search size={18} class="absolute left-3 text-slate-400 dark:text-slate-500" />
-                    <input 
-                        type="text" 
-                        placeholder="Buscar cliente, número..." 
-                        class="w-64 pl-10 pr-4 py-1.5 bg-slate-100 dark:bg-slate-900 border border-transparent dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-500 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:bg-white transition-all"
-                    />
-                </div>
-            </div>
-
-            <div class="flex items-center gap-4">
-                <!-- Theme Toggle -->
-                <button 
-                    onclick={toggleTheme} 
-                    class="relative p-2 text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 rounded-lg hover:bg-indigo-50 dark:hover:bg-slate-800 transition-colors"
-                    title={currentTheme === 'dark' ? 'Mudar para modo claro' : 'Mudar para modo escuro'}
-                >
-                    {#if currentTheme === 'dark'}
-                        <Sun size={20} />
-                    {:else}
-                        <Moon size={20} />
-                    {/if}
-                </button>
-            
-                <button class="relative p-2 text-slate-400 hover:text-slate-700 dark:hover:text-white rounded-full hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors">
-                    <Bell size={20} />
-                    <span class="absolute top-1.5 right-1.5 w-2 h-2 rounded-full bg-red-500 border-2 border-white dark:border-[#1e293b]"></span>
-                </button>
-                <div class="h-8 w-px bg-slate-200 dark:bg-slate-700 mx-1"></div>
-                <div class="flex items-center gap-3 relative">
-                    <div class="text-right hidden sm:block">
-                        <div class="text-sm font-medium text-slate-900 dark:text-white">Admin</div>
-                        <div class="text-xs text-slate-500">Gestor de Vendas</div>
-                    </div>
-                    <div class="relative">
-                        <button 
-                            onclick={toggleUserMenu}
-                            class="w-9 h-9 rounded-full bg-indigo-600 flex items-center justify-center text-white font-bold text-sm shadow-sm shadow-indigo-900/20 hover:bg-indigo-700 transition-colors"
-                            title="Menu do usuário"
-                        >
-                            AD
-                        </button>
-                        
-                        <!-- User Dropdown Menu -->
-                        {#if isUserMenuOpen}
-                            <div class="absolute right-0 mt-2 w-56 bg-white dark:bg-[#1e293b] rounded-lg border border-slate-200 dark:border-slate-800 shadow-lg py-1 z-50">
-                                <div class="px-4 py-3 border-b border-slate-200 dark:border-slate-800">
-                                    <p class="text-sm font-medium text-slate-900 dark:text-white">Admin</p>
-                                    <p class="text-xs text-slate-500 dark:text-slate-400">admin@nettown.com</p>
-                                </div>
-                                
-                                <button 
-                                    onclick={() => handleUserAction('profile')}
-                                    class="w-full flex items-center gap-3 px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
-                                >
-                                    <User size={16} />
-                                    Meu Perfil
-                                </button>
-                                
-                                <button 
-                                    onclick={() => handleUserAction('password')}
-                                    class="w-full flex items-center gap-3 px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
-                                >
-                                    <Key size={16} />
-                                    Alterar Senha
-                                </button>
-                                
-                                <button 
-                                    onclick={() => handleUserAction('billing')}
-                                    class="w-full flex items-center gap-3 px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
-                                >
-                                    <CreditCard size={16} />
-                                    Assinatura
-                                </button>
-                                
-                                <button 
-                                    onclick={() => handleUserAction('help')}
-                                    class="w-full flex items-center gap-3 px-4 py-2 text-sm text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
-                                >
-                                    <HelpCircle size={16} />
-                                    Ajuda
-                                </button>
-                            </div>
-                        {/if}
-                    </div>
-                </div>
-            </div>
-        </header>
-
-        <!-- Page Content Scrollable Area -->
-        <main class="flex-1 overflow-y-auto overflow-x-hidden p-4 lg:p-8 relative">
-            {@render children()}
-        </main>
-    </div>
+<div
+	class="flex h-screen w-screen overflow-hidden bg-slate-50 font-sans text-slate-900 transition-colors duration-200 dark:bg-[#0f172a] dark:text-slate-300"
+>
+	<!-- Mobile Sidebar Overlay -->
+	{#if isMobileMenuOpen}
+		<div
+			class="fixed inset-0 z-40 bg-slate-950/80 lg:hidden"
+			onclick={toggleMobileMenu}
+			onkeydown={(e) => e.key === 'Escape' && toggleMobileMenu()}
+			tabindex="0"
+			role="button"
+			aria-label="Fechar menu"
+		></div>
+	{/if}
+
+	<!-- User Menu Overlay -->
+	{#if isUserMenuOpen}
+		<div
+			class="fixed inset-0 z-40"
+			onclick={() => (isUserMenuOpen = false)}
+			onkeydown={(e) => e.key === 'Escape' && (isUserMenuOpen = false)}
+			tabindex="0"
+			role="button"
+			aria-label="Fechar menu"
+		></div>
+	{/if}
+
+	<!-- Sidebar -->
+	<aside
+		class="fixed inset-y-0 left-0 z-50 flex h-full flex-col border-r border-slate-200 bg-white transition-all duration-300 ease-in-out lg:static dark:border-slate-800 dark:bg-[#1e293b] {isSidebarCollapsed
+			? 'w-20'
+			: 'w-64'} {isMobileMenuOpen
+			? 'translate-x-0'
+			: '-translate-x-full lg:translate-x-0'} shrink-0 shadow-sm dark:shadow-none"
+	>
+		<div
+			class="flex h-16 shrink-0 items-center justify-between border-b border-slate-200 px-4 dark:border-slate-800"
+		>
+			<div class="flex items-center gap-2 overflow-hidden text-indigo-600 dark:text-indigo-400">
+				<div
+					class="flex h-6 shrink-0 items-center {isSidebarCollapsed
+						? 'w-8 justify-center'
+						: 'w-auto'}"
+				>
+					{#if isSidebarCollapsed}
+						<TrendingUp size={24} strokeWidth={2.5} class="text-indigo-600 dark:text-indigo-500" />
+					{:else}
+						<img
+							src={currentTheme === 'dark' ? logoWhite : logoBlack}
+							alt="NetTown Analytics"
+							class="h-full w-auto"
+						/>
+					{/if}
+				</div>
+			</div>
+
+			<button
+				class="hidden shrink-0 items-center justify-center rounded-lg p-1.5 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 lg:flex dark:hover:bg-slate-800 dark:hover:text-white"
+				onclick={toggleSidebar}
+			>
+				{#if isSidebarCollapsed}
+					<ChevronRight size={18} />
+				{:else}
+					<ChevronLeft size={18} />
+				{/if}
+			</button>
+
+			<button
+				class="shrink-0 p-1 text-slate-400 hover:text-slate-700 lg:hidden dark:hover:text-white"
+				onclick={toggleMobileMenu}
+			>
+				<X size={20} />
+			</button>
+		</div>
+
+		<div
+			class="flex flex-1 flex-col gap-2 overflow-x-hidden overflow-y-auto py-6 {isSidebarCollapsed
+				? 'px-2'
+				: 'px-4'}"
+		>
+			<div
+				class="mb-2 px-2 text-xs font-semibold tracking-wider whitespace-nowrap text-slate-500 uppercase {isSidebarCollapsed
+					? 'text-center text-[10px]'
+					: ''}"
+			>
+				{isSidebarCollapsed ? 'Menu' : 'Menu Principal'}
+			</div>
+			{#each navItems as item}
+				{@const Icon = item.icon}
+				{@const isActive = isNavItemActive(item.href)}
+				<a
+					href={item.href}
+					title={isSidebarCollapsed ? item.name : ''}
+					class="flex items-center gap-3 rounded-lg py-2.5 transition-colors {isActive
+						? 'bg-indigo-50 font-medium text-indigo-700 dark:bg-indigo-500/10 dark:text-indigo-400'
+						: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-200'} {isSidebarCollapsed
+						? 'justify-center px-0'
+						: 'px-3'}"
+					onclick={() => (isMobileMenuOpen = false)}
+				>
+					<Icon
+						size={isSidebarCollapsed ? 22 : 18}
+						strokeWidth={isActive ? 2.5 : 2}
+						class="shrink-0"
+					/>
+					{#if !isSidebarCollapsed}
+						<span class="truncate">{item.name}</span>
+					{/if}
+				</a>
+			{/each}
+		</div>
+
+		<div class="shrink-0 border-t border-slate-200 p-4 dark:border-slate-800">
+			<button
+				onclick={handleLogout}
+				title={isSidebarCollapsed ? 'Sair' : ''}
+				class="flex w-full items-center gap-3 rounded-lg py-2.5 text-slate-600 transition-colors hover:bg-red-50 hover:text-red-600 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-red-400 {isSidebarCollapsed
+					? 'justify-center px-0'
+					: 'px-3'}"
+			>
+				<LogOut size={18} class="shrink-0" />
+				{#if !isSidebarCollapsed}
+					<span>Sair</span>
+				{/if}
+			</button>
+		</div>
+	</aside>
+
+	<!-- Main Wrapper -->
+	<div class="relative flex h-full min-w-0 flex-1 flex-col overflow-hidden">
+		<!-- Top Header -->
+		<header
+			class="flex h-16 w-full shrink-0 items-center justify-between border-b border-slate-200 bg-white/95 px-4 backdrop-blur-sm transition-colors duration-200 lg:px-8 dark:border-slate-800 dark:bg-[#1e293b]/95 {isUserMenuOpen
+				? 'relative z-50'
+				: 'z-30'}"
+		>
+			<div class="flex items-center gap-4">
+				<button
+					class="text-slate-400 hover:text-slate-700 lg:hidden dark:hover:text-white"
+					onclick={toggleMobileMenu}
+				>
+					<Menu size={24} />
+				</button>
+				<div class="relative hidden items-center sm:flex">
+					<Search size={18} class="absolute left-3 text-slate-400 dark:text-slate-500" />
+					<input
+						type="text"
+						placeholder="Buscar cliente, número..."
+						class="w-64 rounded-lg border border-transparent bg-slate-100 py-1.5 pr-4 pl-10 text-sm text-slate-900 placeholder-slate-500 transition-all focus:border-indigo-500 focus:bg-white focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+					/>
+				</div>
+			</div>
+
+			<div class="flex items-center gap-4">
+				<!-- Theme Toggle -->
+				<button
+					onclick={toggleTheme}
+					class="relative rounded-lg p-2 text-slate-400 transition-colors hover:bg-indigo-50 hover:text-indigo-600 dark:hover:bg-slate-800 dark:hover:text-indigo-400"
+					title={currentTheme === 'dark' ? 'Mudar para modo claro' : 'Mudar para modo escuro'}
+				>
+					{#if currentTheme === 'dark'}
+						<Sun size={20} />
+					{:else}
+						<Moon size={20} />
+					{/if}
+				</button>
+
+				<button
+					class="relative rounded-full p-2 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 dark:hover:bg-slate-800 dark:hover:text-white"
+				>
+					<Bell size={20} />
+					<span
+						class="absolute top-1.5 right-1.5 h-2 w-2 rounded-full border-2 border-white bg-red-500 dark:border-[#1e293b]"
+					></span>
+				</button>
+				<div class="mx-1 h-8 w-px bg-slate-200 dark:bg-slate-700"></div>
+				<div class="relative flex items-center gap-3">
+					<div class="hidden text-right sm:block">
+						<div class="text-sm font-medium text-slate-900 dark:text-white">Admin</div>
+						<div class="text-xs text-slate-500">Gestor de Vendas</div>
+					</div>
+					<div class="relative">
+						<button
+							onclick={toggleUserMenu}
+							class="flex h-9 w-9 items-center justify-center rounded-full bg-indigo-600 text-sm font-bold text-white shadow-sm shadow-indigo-900/20 transition-colors hover:bg-indigo-700"
+							title="Menu do usuário"
+						>
+							AD
+						</button>
+
+						<!-- User Dropdown Menu -->
+						{#if isUserMenuOpen}
+							<div
+								class="absolute right-0 z-50 mt-2 w-56 rounded-lg border border-slate-200 bg-white py-1 shadow-lg dark:border-slate-800 dark:bg-[#1e293b]"
+							>
+								<div class="border-b border-slate-200 px-4 py-3 dark:border-slate-800">
+									<p class="text-sm font-medium text-slate-900 dark:text-white">Admin</p>
+									<p class="text-xs text-slate-500 dark:text-slate-400">admin@nettown.com</p>
+								</div>
+
+								<a
+									href="/dashboard/profile"
+									onclick={closeUserMenu}
+									class="flex w-full items-center gap-3 px-4 py-2 text-sm text-slate-700 transition-colors hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800"
+								>
+									<User size={16} />
+									Meu Perfil
+								</a>
+
+								<a
+									href="/dashboard/subscription"
+									onclick={closeUserMenu}
+									class="flex w-full items-center gap-3 px-4 py-2 text-sm text-slate-700 transition-colors hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800"
+								>
+									<CreditCard size={16} />
+									Assinatura
+								</a>
+
+								<a
+									href="/dashboard/help"
+									onclick={closeUserMenu}
+									class="flex w-full items-center gap-3 px-4 py-2 text-sm text-slate-700 transition-colors hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800"
+								>
+									<HelpCircle size={16} />
+									Ajuda
+								</a>
+							</div>
+						{/if}
+					</div>
+				</div>
+			</div>
+		</header>
+
+		<!-- Page Content Scrollable Area -->
+		<main class="relative flex-1 overflow-x-hidden overflow-y-auto p-4 lg:p-8">
+			{@render children()}
+		</main>
+	</div>
 </div>

+ 246 - 66
src/routes/(app)/dashboard/+page.svelte

@@ -10,7 +10,7 @@
 	} from 'lucide-svelte';
 	import { Chart, Svg, Axis, Bar, Line, Spline, Highlight, Group } from 'layerchart';
 	import { scaleTime, scaleLinear, scaleBand } from 'd3-scale';
-	import { format } from 'date-fns';
+	import { format, addDays } from 'date-fns';
 	import { ptBR } from 'date-fns/locale';
 	import { goto } from '$app/navigation';
 
@@ -37,6 +37,47 @@
 
 	let selectedAspectDrilldown = $state(null);
 
+	const periodOptions = [
+		{ id: 'today', label: 'Hoje (24h)', multiplier: 0.9 },
+		{ id: 'yesterday', label: 'Ontem', multiplier: 0.7 },
+		{ id: 'week', label: 'Últimos 7 dias', multiplier: 1.45 }
+	];
+
+	const unitOptions = [
+		{ id: 'all', label: 'Todas as unidades', multiplier: 1 },
+		{ id: 'flagship', label: 'Loja Flagship', multiplier: 1.35 },
+		{ id: 'franquias', label: 'Franquias', multiplier: 0.75 },
+		{ id: 'pop-up', label: 'Pop-up Stores', multiplier: 1.1 },
+		{ id: 'digital', label: 'Operação Digital', multiplier: 1.6 }
+	];
+
+	const areaOptions = [
+		{ id: 'all', label: 'Todas as áreas', multiplier: 1 },
+		{ id: 'atendimento', label: 'Atendimento', multiplier: 1.25 },
+		{ id: 'produto', label: 'Produto', multiplier: 0.8 },
+		{ id: 'logistica', label: 'Logística & Entrega', multiplier: 1.3 },
+		{ id: 'marketing', label: 'Marketing & Campanhas', multiplier: 1.4 }
+	];
+
+	const sentimentFilterOptions = [
+		{ id: 'all', label: 'Todos', multiplier: 1, weights: { positive: 1, neutral: 1, negative: 1 } },
+		{ id: 'positive', label: 'Positivo', multiplier: 1.35, weights: { positive: 1.5, neutral: 0.7, negative: 0.4 } },
+		{ id: 'neutral', label: 'Neutro', multiplier: 0.95, weights: { positive: 0.8, neutral: 1.3, negative: 0.8 } },
+		{ id: 'negative', label: 'Negativo', multiplier: 0.6, weights: { positive: 0.4, neutral: 0.7, negative: 1.7 } }
+	];
+
+	const volumeViewOptions = [
+		{ id: 'hour', label: 'Por Hora', format: 'HH:mm' },
+		{ id: 'day', label: 'Por Dia', format: 'dd/MM' }
+	];
+
+	let selectedPeriod = $state(periodOptions[0].id);
+	let selectedUnit = $state(unitOptions[0].id);
+	let selectedArea = $state(areaOptions[0].id);
+	let selectedSentimentFilter = $state(sentimentFilterOptions[0].id);
+	let volumeView = $state(volumeViewOptions[0].id);
+	let queueTab = $state('all');
+
 	function openAspectDrilldown(aspect, tone) {
 		selectedAspectDrilldown = { aspect, tone };
 	}
@@ -67,62 +108,191 @@
 			: 'Distribuição de Aspectos'
 	);
 
-	// Map KPIs to UI format
-	const kpis = [
+	const selectedFilterContext = $derived({
+		period: periodOptions.find((opt) => opt.id === selectedPeriod) ?? periodOptions[0],
+		unit: unitOptions.find((opt) => opt.id === selectedUnit) ?? unitOptions[0],
+		area: areaOptions.find((opt) => opt.id === selectedArea) ?? areaOptions[0],
+		sentiment: sentimentFilterOptions.find((opt) => opt.id === selectedSentimentFilter) ?? sentimentFilterOptions[0]
+	});
+
+	const combinedMultiplier = $derived(
+		selectedFilterContext.period.multiplier *
+		selectedFilterContext.unit.multiplier *
+		selectedFilterContext.area.multiplier
+	);
+
+	const sentimentWeights = $derived(selectedFilterContext.sentiment.weights);
+
+	const kpiDefinitions = [
 		{
 			title: 'Usuários Cadastrados',
-			value: mockKpis.newPeople.new,
-			// subvalue: `${mockKpis.newPeople.recurring} entrada / 0 saída`,
 			icon: Users,
 			color: 'text-emerald-600 dark:text-emerald-400',
 			bg: 'bg-emerald-50 dark:bg-emerald-400/10',
-			border: 'border-emerald-200 dark:border-emerald-400/20'
+			border: 'border-emerald-200 dark:border-emerald-400/20',
+			compute: ({ multiplier }) => Math.max(5, Math.round(mockKpis.newPeople.new * multiplier)),
+			format: (value) => value.toLocaleString('pt-BR')
 		},
 		{
 			title: 'Atendentes Ativos',
-			value: mockKpis.activeService.value,
-			// subvalue: 'Com conversas no período',
 			icon: UserRoundCog,
 			color: 'text-purple-600 dark:text-purple-400',
 			bg: 'bg-purple-50 dark:bg-purple-400/10',
-			border: 'border-purple-200 dark:border-purple-400/20'
+			border: 'border-purple-200 dark:border-purple-400/20',
+			compute: ({ multiplier }) => Math.max(1, Math.round(mockKpis.activeService.value * (0.6 + multiplier / 1.5))),
+			format: (value) => value.toLocaleString('pt-BR')
 		},
 		{
 			title: 'Total de conversas',
-			value: mockKpis.whatsappMessages.current,
-			// subvalue: `${mockKpis.whatsappMessages.total} total geral`,
 			icon: MessageSquare,
 			color: 'text-sky-600 dark:text-sky-400',
 			bg: 'bg-sky-50 dark:bg-sky-400/10',
-			border: 'border-sky-200 dark:border-sky-400/20'
+			border: 'border-sky-200 dark:border-sky-400/20',
+			compute: ({ multiplier }) => Math.max(0, Math.round(mockKpis.whatsappMessages.current * (multiplier * 0.9 + selectedFilterContext.sentiment.multiplier))),
+			format: (value) => value.toLocaleString('pt-BR')
 		},
 		{
 			title: 'Sentimento Geral',
-			value: getSentimentLabel(mockKpis.generalSentiment.value),
-			// subvalue: `Score ${mockKpis.generalSentiment.value.toFixed(1).replace('.', ',')}`,
 			icon: ThumbsUp,
 			color: 'text-amber-600 dark:text-amber-400',
 			bg: 'bg-amber-50 dark:bg-amber-400/10',
-			border: 'border-amber-200 dark:border-amber-400/20'
+			border: 'border-amber-200 dark:border-amber-400/20',
+			compute: ({ sentimentBias, multiplier }) => {
+				const base = mockKpis.generalSentiment.value * sentimentBias + (multiplier - 1) * 0.4;
+				const adjusted = Math.max(-1, Math.min(1, base));
+				return adjusted;
+			},
+			format: (value) => getSentimentLabel(value)
 		},
 		{
 			title: 'Usuários Não Cadastrados',
-			value: mockKpis.crmLines.total,
-			// subvalue: 'Base sem cadastro no CRM',
 			icon: UserX,
 			color: 'text-indigo-600 dark:text-indigo-400',
 			bg: 'bg-indigo-50 dark:bg-indigo-400/10',
-			border: 'border-indigo-200 dark:border-indigo-400/20'
+			border: 'border-indigo-200 dark:border-indigo-400/20',
+			compute: ({ multiplier }) => Math.max(1000, Math.round(mockKpis.crmLines.total * (1 + (1 - multiplier) / 2))),
+			format: (value) => value.toLocaleString('pt-BR')
 		}
 	];
 
-	// Data-driven Radar Chart logic
+	const kpis = $derived(
+		kpiDefinitions.map((kpi) => ({
+			...kpi,
+			value: kpi.format(
+				kpi.compute({
+					multiplier: combinedMultiplier,
+					sentimentBias: selectedFilterContext.sentiment.multiplier
+				})
+			)
+		}))
+	);
+
+	const aspectsData = $derived(
+		mockAspectsData.map((aspect) => ({
+			...aspect,
+			positive: Math.round(aspect.positive * sentimentWeights.positive * combinedMultiplier),
+			neutral: Math.round(aspect.neutral * sentimentWeights.neutral * combinedMultiplier * 0.95),
+			negative: Math.round(aspect.negative * sentimentWeights.negative * combinedMultiplier)
+		}))
+	);
+
+	const baseDailyVolume = (() => {
+		const grouped = new Map();
+		for (const record of mockVolumeData) {
+			const key = `${record.date.getFullYear()}-${record.date.getMonth()}-${record.date.getDate()}`;
+			if (!grouped.has(key)) {
+				grouped.set(key, { date: new Date(record.date.getFullYear(), record.date.getMonth(), record.date.getDate()), whatsapp: 0 });
+			}
+			grouped.get(key).whatsapp += record.whatsapp;
+		}
+
+		let series = Array.from(grouped.values()).sort((a, b) => a.date - b.date);
+
+		if (series.length <= 1) {
+			const seedDate = series[0]?.date ?? new Date();
+			const seedValue = series[0]?.whatsapp ?? 120;
+			series = Array.from({ length: 5 }, (_, idx) => {
+				const offset = 4 - idx;
+				return {
+					date: addDays(seedDate, -offset),
+					whatsapp: Math.max(5, Math.round(seedValue * (0.5 + idx * 0.2)))
+				};
+			});
+		}
+
+		return series;
+	})();
+
+	const selectedVolumeOption = $derived(volumeViewOptions.find((opt) => opt.id === volumeView) ?? volumeViewOptions[0]);
+
+	const volumeData = $derived.by(() => {
+		const base = volumeView === 'day' ? baseDailyVolume : mockVolumeData;
+		return base.map((entry, idx) => ({
+			date: entry.date,
+			whatsapp: Math.max(0, Math.round(entry.whatsapp * (combinedMultiplier + idx * 0.02)))
+		}));
+	});
+
+	const maxVolume = $derived(Math.max(60, ...volumeData.map((item) => item.whatsapp)));
+
+	const filteredQueueItems = $derived.by(() => {
+		const periodMult = selectedFilterContext.period.multiplier;
+		const sentimentMult = selectedFilterContext.sentiment.multiplier;
+		const areaMult = selectedFilterContext.area.multiplier;
+
+		return mockPriorityQueue.map((item) => {
+			const weight = periodMult * sentimentMult * areaMult;
+			return {
+				...item,
+				impact: Math.round(item.impact * weight),
+				chance: Math.min(100, Math.max(10, Math.round(item.chance * sentimentMult))),
+				isSellerFault: item.status.toLowerCase().includes('vendedora'),
+				isClientFault: !item.status.toLowerCase().includes('vendedora')
+			};
+		});
+	});
+
+	const queueItems = $derived.by(() => {
+		if (queueTab === 'seller') return filteredQueueItems.filter(i => i.isSellerFault);
+		if (queueTab === 'client') return filteredQueueItems.filter(i => i.isClientFault);
+		return filteredQueueItems;
+	});
+
+	const queueCounts = $derived({
+		all: filteredQueueItems.length,
+		seller: filteredQueueItems.filter(i => i.isSellerFault).length,
+		client: filteredQueueItems.filter(i => i.isClientFault).length
+	});
+
+	const totalPotential = $derived(
+		filteredQueueItems.reduce((sum, item) => sum + item.impact, 0)
+	);
+
 	const radarRadius = 80;
 	const radarCenter = 100;
-	const angleStep = (Math.PI * 2) / mockRadarData.length;
+
+	const radarData = $derived.by(() => {
+		const periodBias = selectedFilterContext.period.multiplier;
+		const unitBias = selectedFilterContext.unit.multiplier;
+		const areaBias = selectedFilterContext.area.multiplier;
+		const sentimentBias = selectedFilterContext.sentiment.multiplier;
+		return mockRadarData.map((metric, idx) => {
+			const wave = Math.sin((idx + 1) * periodBias) * 8;
+			const adjusted = Math.max(
+				5,
+				Math.min(
+					100,
+					Math.round(metric.value * sentimentBias * (0.7 + unitBias / 3 + areaBias / 4) + wave)
+				)
+			);
+			return { ...metric, value: adjusted };
+		});
+	});
+
+	const angleStep = $derived((Math.PI * 2) / radarData.length);
 
 	const radarPoints = $derived(
-		mockRadarData.map((d, i) => {
+		radarData.map((d, i) => {
 			const angle = i * angleStep - Math.PI / 2;
 			const r = (d.value / 100) * radarRadius;
 			return {
@@ -139,15 +309,17 @@
 
 	const radarPath = $derived(radarPoints.map((p) => `${p.x},${p.y}`).join(' '));
 
-	const gridLevels = [0.2, 0.4, 0.6, 0.8, 1].map((level) => {
-		return mockRadarData
-			.map((_, i) => {
-				const angle = i * angleStep - Math.PI / 2;
-				const r = level * radarRadius;
-				return `${radarCenter + r * Math.cos(angle)},${radarCenter + r * Math.sin(angle)}`;
-			})
-			.join(' ');
-	});
+	const gridLevels = $derived(
+		[0.2, 0.4, 0.6, 0.8, 1].map((level) => {
+			return radarData
+				.map((_, i) => {
+					const angle = i * angleStep - Math.PI / 2;
+					const r = level * radarRadius;
+					return `${radarCenter + r * Math.cos(angle)},${radarCenter + r * Math.sin(angle)}`;
+				})
+				.join(' ');
+		})
+	);
 </script>
 
 <svelte:head>
@@ -163,37 +335,44 @@
 			<span class="font-medium text-slate-600 dark:text-slate-400">Período:</span>
 			<select
 				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+				bind:value={selectedPeriod}
 			>
-				<option>Hoje (24h)</option>
-				<option>Ontem</option>
-				<option>Últimos 7 dias</option>
+				{#each periodOptions as option}
+					<option value={option.id}>{option.label}</option>
+				{/each}
 			</select>
 		</div>
 		<div class="flex items-center gap-2">
 			<span class="font-medium text-slate-600 dark:text-slate-400">Unidade:</span>
 			<select
 				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+				bind:value={selectedUnit}
 			>
-				<option>Sem segmento</option>
+				{#each unitOptions as option}
+					<option value={option.id}>{option.label}</option>
+				{/each}
 			</select>
 		</div>
 		<div class="flex items-center gap-2">
 			<span class="font-medium text-slate-600 dark:text-slate-400">Área:</span>
 			<select
 				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+				bind:value={selectedArea}
 			>
-				<option>Sem segmento de setor</option>
+				{#each areaOptions as option}
+					<option value={option.id}>{option.label}</option>
+				{/each}
 			</select>
 		</div>
 		<div class="flex items-center gap-2">
 			<span class="font-medium text-slate-600 dark:text-slate-400">Sentimento:</span>
 			<select
 				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+				bind:value={selectedSentimentFilter}
 			>
-				<option>Todos</option>
-				<option>Positivo</option>
-				<option>Neutro</option>
-				<option>Negativo</option>
+				{#each sentimentFilterOptions as option}
+					<option value={option.id}>{option.label}</option>
+				{/each}
 			</select>
 		</div>
 	</div>
@@ -211,14 +390,9 @@
 					>
 						<Icon size={20} strokeWidth={2.5} />
 					</div>
-					<div>
-						<div
-							class="mb-1 text-xs font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
-						>
-							{kpi.title}
-						</div>
-						<div class="mb-0.5 text-2xl font-bold text-slate-900 dark:text-white">{kpi.value}</div>
-						<div class="text-xs text-slate-500">{kpi.subvalue}</div>
+					<div class="space-y-1">
+						<div class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">{kpi.title}</div>
+						<div class="text-2xl font-bold text-slate-900 dark:text-white">{kpi.value}</div>
 					</div>
 				</div>
 			</div>
@@ -243,11 +417,11 @@
 				<div class="flex gap-2">
 					<span
 						class="rounded-md border border-red-200 bg-red-50 px-2.5 py-1 text-xs font-medium text-red-600 dark:border-red-500/20 dark:bg-red-500/10 dark:text-red-400"
-						>22 fora da janela</span
+						>{queueCounts.all} fora da janela</span
 					>
 					<span
 						class="rounded-md border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-medium text-amber-700 dark:border-amber-500/20 dark:bg-amber-500/10 dark:text-amber-400"
-						>Potencial: R$ 81.004</span
+						>Potencial: R$ {totalPotential.toLocaleString('pt-BR')}</span
 					>
 				</div>
 			</div>
@@ -256,21 +430,24 @@
 				class="flex gap-2 border-b border-slate-200 bg-slate-50/50 p-4 dark:border-slate-800 dark:bg-slate-900"
 			>
 				<button
-					class="rounded-lg border border-slate-300 bg-white px-4 py-1.5 text-sm font-medium text-slate-900 shadow-sm dark:border-slate-700 dark:bg-[#1e293b] dark:text-white dark:shadow-none"
-					>Todas (22)</button
-				>
+					type="button"
+					onclick={() => queueTab = 'all'}
+					class="rounded-lg px-4 py-1.5 text-sm font-medium transition-colors {queueTab === 'all' ? 'border border-slate-300 bg-white text-slate-900 shadow-sm dark:border-slate-700 dark:bg-[#1e293b] dark:text-white' : 'border border-transparent bg-transparent text-slate-600 hover:border-slate-300 hover:text-slate-900 dark:text-slate-400 dark:hover:border-slate-700 dark:hover:text-white'}"
+				>Todas ({queueCounts.all})</button>
 				<button
-					class="rounded-lg border border-transparent bg-transparent px-4 py-1.5 text-sm font-medium text-slate-600 transition-colors hover:border-slate-300 hover:text-slate-900 dark:text-slate-400 dark:hover:border-slate-700 dark:hover:text-white"
-					>Pela vendedora (13)</button
-				>
+					type="button"
+					onclick={() => queueTab = 'seller'}
+					class="rounded-lg px-4 py-1.5 text-sm font-medium transition-colors {queueTab === 'seller' ? 'border border-slate-300 bg-white text-slate-900 shadow-sm dark:border-slate-700 dark:bg-[#1e293b] dark:text-white' : 'border border-transparent bg-transparent text-slate-600 hover:border-slate-300 hover:text-slate-900 dark:text-slate-400 dark:hover:border-slate-700 dark:hover:text-white'}"
+				>Pela vendedora ({queueCounts.seller})</button>
 				<button
-					class="rounded-lg border border-transparent bg-transparent px-4 py-1.5 text-sm font-medium text-slate-600 transition-colors hover:border-slate-300 hover:text-slate-900 dark:text-slate-400 dark:hover:border-slate-700 dark:hover:text-white"
-					>Pelo cliente (9)</button
-				>
+					type="button"
+					onclick={() => queueTab = 'client'}
+					class="rounded-lg px-4 py-1.5 text-sm font-medium transition-colors {queueTab === 'client' ? 'border border-slate-300 bg-white text-slate-900 shadow-sm dark:border-slate-700 dark:bg-[#1e293b] dark:text-white' : 'border border-transparent bg-transparent text-slate-600 hover:border-slate-300 hover:text-slate-900 dark:text-slate-400 dark:hover:border-slate-700 dark:hover:text-white'}"
+				>Pelo cliente ({queueCounts.client})</button>
 			</div>
 
 			<div class="flex-1 space-y-4 overflow-y-auto p-4">
-				{#each mockPriorityQueue as item}
+				{#each queueItems as item (item.id)}
 					<div
 						class="group relative overflow-hidden rounded-lg border border-red-200 bg-white p-4 shadow-sm transition-colors hover:border-red-300 dark:border-red-500/30 dark:bg-slate-900 dark:shadow-none dark:hover:border-red-500/60"
 					>
@@ -449,17 +626,20 @@
 				<h2 class="text-base font-bold text-slate-900 dark:text-white">Volume por Canal</h2>
 				<select
 					class="rounded-lg border border-slate-300 bg-slate-50 px-2 py-1 text-xs text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+					bind:value={volumeView}
 				>
-					<option>Por Hora</option>
+					{#each volumeViewOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 
 			<div class="h-full w-full flex-1">
 				<Chart
-					data={mockVolumeData}
-					x="date"
-					y="whatsapp"
-					yDomain={[0, 250]}
+					data={volumeData}
+					x={d => d.date}
+					y={d => d.whatsapp}
+					yDomain={[0, maxVolume]}
 					padding={{ top: 10, right: 10, bottom: 20, left: 30 }}
 				>
 					<Svg>
@@ -470,7 +650,7 @@
 						/>
 						<Axis
 							placement="bottom"
-							format={(d) => format(d, 'HH:mm')}
+							format={(d) => format(d, selectedVolumeOption.format)}
 							class="fill-slate-500 text-xs dark:fill-slate-400"
 						/>
 						<Spline stroke="#38bdf8" strokeWidth={2} />
@@ -508,7 +688,7 @@
 			<div class="custom-scrollbar relative h-full w-full flex-1 overflow-y-auto pr-2">
 				{#if !selectedAspectDrilldown}
 					<div class="space-y-4">
-						{#each mockAspectsData as aspect}
+						{#each aspectsData as aspect}
 							<div>
 								<div class="mb-1 flex justify-between text-xs text-slate-600 dark:text-slate-300">
 									<span class="font-medium">{aspect.aspect}</span>

+ 750 - 0
src/routes/(app)/dashboard/agents/+page.svelte

@@ -0,0 +1,750 @@
+<script>
+	import {
+		Users,
+		UserPlus,
+		Search,
+		CheckCircle,
+		XCircle,
+		Clock,
+		Edit,
+		Power,
+		X,
+		ShieldCheck,
+		MessageSquare
+	} from 'lucide-svelte';
+	import { onMount } from 'svelte';
+
+	let isLoading = $state(true);
+	onMount(() => {
+		setTimeout(() => {
+			isLoading = false;
+		}, 700);
+	});
+
+	// ── Mock agents ───────────────────────────────────────────────────────────
+	let agents = $state([
+		{
+			id: 1,
+			name: 'Maria Santos',
+			initials: 'MS',
+			department: 'SAC',
+			channels: ['whatsapp'],
+			status: 'Ativo',
+			availableForEscalation: true,
+			todayAttendances: 24,
+			avgResponseTime: '3m 12s',
+			responseTimeTrend: 'down',
+			slaPct: 94
+		},
+		{
+			id: 2,
+			name: 'Lívia Ferreira',
+			initials: 'LF',
+			department: 'Vendas',
+			channels: ['whatsapp', 'instagram'],
+			status: 'Em Atendimento',
+			availableForEscalation: false,
+			todayAttendances: 18,
+			avgResponseTime: '5m 44s',
+			responseTimeTrend: 'up',
+			slaPct: 88
+		},
+		{
+			id: 3,
+			name: 'Julia Costa',
+			initials: 'JC',
+			department: 'Suporte',
+			channels: ['whatsapp'],
+			status: 'Ativo',
+			availableForEscalation: true,
+			todayAttendances: 31,
+			avgResponseTime: '2m 08s',
+			responseTimeTrend: 'down',
+			slaPct: 97
+		},
+		{
+			id: 4,
+			name: 'Fernanda Lima',
+			initials: 'FL',
+			department: 'SAC',
+			channels: ['instagram'],
+			status: 'Inativo',
+			availableForEscalation: false,
+			todayAttendances: 0,
+			avgResponseTime: '—',
+			responseTimeTrend: 'stable',
+			slaPct: 0
+		},
+		{
+			id: 5,
+			name: 'Roberto Souza',
+			initials: 'RS',
+			department: 'Vendas',
+			channels: ['whatsapp', 'instagram'],
+			status: 'Em Atendimento',
+			availableForEscalation: true,
+			todayAttendances: 12,
+			avgResponseTime: '8m 30s',
+			responseTimeTrend: 'up',
+			slaPct: 72
+		},
+		{
+			id: 6,
+			name: 'Amanda Rocha',
+			initials: 'AR',
+			department: 'Suporte',
+			channels: ['whatsapp'],
+			status: 'Ativo',
+			availableForEscalation: true,
+			todayAttendances: 29,
+			avgResponseTime: '4m 15s',
+			responseTimeTrend: 'down',
+			slaPct: 91
+		},
+		{
+			id: 7,
+			name: 'Carlos Mendes',
+			initials: 'CM',
+			department: 'SAC',
+			channels: ['whatsapp', 'instagram'],
+			status: 'Ativo',
+			availableForEscalation: false,
+			todayAttendances: 20,
+			avgResponseTime: '6m 00s',
+			responseTimeTrend: 'stable',
+			slaPct: 83
+		},
+		{
+			id: 8,
+			name: 'Patrícia Nunes',
+			initials: 'PN',
+			department: 'Vendas',
+			channels: ['whatsapp'],
+			status: 'Disponível',
+			availableForEscalation: true,
+			todayAttendances: 8,
+			avgResponseTime: '3m 50s',
+			responseTimeTrend: 'down',
+			slaPct: 96
+		}
+	]);
+
+	// ── Filters ───────────────────────────────────────────────────────────────
+	let searchTerm = $state('');
+	let filterDept = $state('Todos');
+	let filterChannel = $state('Todos');
+	let filterStatus = $state('Todos');
+
+	const filteredAgents = $derived(
+		agents.filter((a) => {
+			if (searchTerm && !a.name.toLowerCase().includes(searchTerm.toLowerCase())) return false;
+			if (filterDept !== 'Todos' && a.department !== filterDept) return false;
+			if (filterChannel === 'WhatsApp' && !a.channels.includes('whatsapp')) return false;
+			if (filterChannel === 'Instagram' && !a.channels.includes('instagram')) return false;
+			if (filterStatus === 'Disponível para Escalonamento' && !a.availableForEscalation)
+				return false;
+			if (
+				filterStatus !== 'Todos' &&
+				filterStatus !== 'Disponível para Escalonamento' &&
+				a.status !== filterStatus
+			)
+				return false;
+			return true;
+		})
+	);
+
+	// ── Stats ─────────────────────────────────────────────────────────────────
+	const stats = $derived({
+		total: agents.length,
+		active: agents.filter((a) => a.status === 'Ativo' || a.status === 'Em Atendimento' || a.status === 'Disponível').length,
+		inAttendance: agents.filter((a) => a.status === 'Em Atendimento').length,
+		availableForEscalation: agents.filter((a) => a.availableForEscalation).length
+	});
+
+	// ── Actions ───────────────────────────────────────────────────────────────
+	function toggleEscalation(id) {
+		const agent = agents.find((a) => a.id === id);
+		if (agent) agent.availableForEscalation = !agent.availableForEscalation;
+	}
+
+	function toggleAgentActive(id) {
+		const agent = agents.find((a) => a.id === id);
+		if (agent) agent.status = agent.status === 'Inativo' ? 'Ativo' : 'Inativo';
+	}
+
+	// ── New Agent Modal ───────────────────────────────────────────────────────
+	let showModal = $state(false);
+	let editingId = $state(null);
+
+	const emptyForm = () => ({
+		name: '',
+		email: '',
+		department: 'SAC',
+		channels: [],
+		status: 'Ativo',
+		availableForEscalation: true
+	});
+
+	let form = $state(emptyForm());
+
+	function openNewAgent() {
+		form = emptyForm();
+		editingId = null;
+		showModal = true;
+	}
+
+	function openEditAgent(agent) {
+		form = {
+			name: agent.name,
+			email: agent.email ?? '',
+			department: agent.department,
+			channels: [...agent.channels],
+			status: agent.status,
+			availableForEscalation: agent.availableForEscalation
+		};
+		editingId = agent.id;
+		showModal = true;
+	}
+
+	function toggleChannel(ch) {
+		if (form.channels.includes(ch)) {
+			form.channels = form.channels.filter((c) => c !== ch);
+		} else {
+			form.channels = [...form.channels, ch];
+		}
+	}
+
+	function saveAgent() {
+		if (!form.name.trim()) return;
+		if (editingId !== null) {
+			const agent = agents.find((a) => a.id === editingId);
+			if (agent) {
+				agent.name = form.name;
+				agent.initials = form.name
+					.split(' ')
+					.slice(0, 2)
+					.map((n) => n[0])
+					.join('')
+					.toUpperCase();
+				agent.department = form.department;
+				agent.channels = [...form.channels];
+				agent.status = form.status;
+				agent.availableForEscalation = form.availableForEscalation;
+			}
+		} else {
+			const id = Math.max(0, ...agents.map((a) => a.id)) + 1;
+			agents = [
+				...agents,
+				{
+					id,
+					name: form.name,
+					initials: form.name
+						.split(' ')
+						.slice(0, 2)
+						.map((n) => n[0])
+						.join('')
+						.toUpperCase(),
+					department: form.department,
+					channels: [...form.channels],
+					status: form.status,
+					availableForEscalation: form.availableForEscalation,
+					todayAttendances: 0,
+					avgResponseTime: '—',
+					responseTimeTrend: 'stable',
+					slaPct: 100
+				}
+			];
+		}
+		showModal = false;
+	}
+
+	// ── Helpers ───────────────────────────────────────────────────────────────
+	function statusConfig(status) {
+		const map = {
+			Ativo: { dot: 'bg-emerald-500', text: 'text-emerald-700 dark:text-emerald-400' },
+			'Em Atendimento': { dot: 'bg-sky-500', text: 'text-sky-700 dark:text-sky-400' },
+			Inativo: { dot: 'bg-slate-400', text: 'text-slate-500 dark:text-slate-400' },
+			Disponível: { dot: 'bg-indigo-500', text: 'text-indigo-700 dark:text-indigo-400' }
+		};
+		return map[status] ?? map['Inativo'];
+	}
+
+	function deptBadgeClass(dept) {
+		const map = {
+			SAC: 'bg-sky-50 text-sky-700 border-sky-200 dark:bg-sky-400/10 dark:text-sky-400 dark:border-sky-400/20',
+			Vendas:
+				'bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-400/10 dark:text-emerald-400 dark:border-emerald-400/20',
+			Suporte:
+				'bg-purple-50 text-purple-700 border-purple-200 dark:bg-purple-400/10 dark:text-purple-400 dark:border-purple-400/20'
+		};
+		return (
+			map[dept] ??
+			'bg-slate-50 text-slate-700 border-slate-200 dark:bg-slate-700 dark:text-slate-300 dark:border-slate-600'
+		);
+	}
+
+	function trendArrow(trend) {
+		if (trend === 'down') return { arrow: '↓', cls: 'text-emerald-600 dark:text-emerald-400' };
+		if (trend === 'up') return { arrow: '↑', cls: 'text-red-600 dark:text-red-400' };
+		return { arrow: '→', cls: 'text-slate-400' };
+	}
+
+	function slaBarClass(pct) {
+		if (pct >= 90) return 'bg-emerald-500';
+		if (pct >= 70) return 'bg-amber-500';
+		return 'bg-red-500';
+	}
+</script>
+
+<svelte:head>
+	<title>Agentes - Nettown Analytics</title>
+</svelte:head>
+
+<!-- New Agent Modal -->
+{#if showModal}
+	<div
+		class="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/80 p-4"
+		onclick={(e) => e.target === e.currentTarget && (showModal = false)}
+		onkeydown={(e) => e.key === 'Escape' && (showModal = false)}
+		role="dialog"
+		aria-modal="true"
+		tabindex="-1"
+	>
+		<div
+			class="w-full max-w-lg rounded-xl border border-slate-200 bg-white shadow-2xl dark:border-slate-700 dark:bg-[#1e293b]"
+		>
+			<div
+				class="flex items-center justify-between border-b border-slate-200 p-5 dark:border-slate-700"
+			>
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">
+					{editingId !== null ? 'Editar Agente' : 'Cadastrar Novo Agente'}
+				</h2>
+				<button
+					onclick={() => (showModal = false)}
+					class="rounded-lg p-1.5 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 dark:hover:bg-slate-800 dark:hover:text-white"
+				>
+					<X size={18} />
+				</button>
+			</div>
+
+			<div class="space-y-4 p-5">
+				<!-- Nome -->
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+						Nome completo
+					</label>
+					<input
+						type="text"
+						bind:value={form.name}
+						placeholder="Ex: Carolina Ribeiro"
+						class="w-full rounded-lg border border-slate-300 bg-slate-50 px-3 py-2 text-sm text-slate-900 placeholder-slate-400 transition-colors focus:border-indigo-500 focus:bg-white focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:placeholder-slate-500 dark:focus:bg-slate-900"
+					/>
+				</div>
+
+				<!-- E-mail -->
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+						E-mail
+					</label>
+					<input
+						type="email"
+						bind:value={form.email}
+						placeholder="agente@empresa.com.br"
+						class="w-full rounded-lg border border-slate-300 bg-slate-50 px-3 py-2 text-sm text-slate-900 placeholder-slate-400 transition-colors focus:border-indigo-500 focus:bg-white focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:placeholder-slate-500 dark:focus:bg-slate-900"
+					/>
+				</div>
+
+				<!-- Departamento -->
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+						Departamento
+					</label>
+					<select
+						bind:value={form.department}
+						class="w-full rounded-lg border border-slate-300 bg-slate-50 px-3 py-2 text-sm text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+					>
+						<option>SAC</option>
+						<option>Vendas</option>
+						<option>Suporte</option>
+					</select>
+				</div>
+
+				<!-- Canal -->
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+						Canal (multi-seleção)
+					</label>
+					<div class="flex gap-2">
+						{#each ['whatsapp', 'instagram'] as ch}
+							<button
+								type="button"
+								onclick={() => toggleChannel(ch)}
+								class="rounded-lg border px-4 py-2 text-sm font-medium transition-colors {form.channels.includes(ch)
+									? 'border-indigo-600 bg-indigo-600 text-white dark:border-indigo-500 dark:bg-indigo-500'
+									: 'border-slate-300 bg-white text-slate-700 hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300 dark:hover:bg-slate-800'}"
+							>
+								{ch === 'whatsapp' ? 'WhatsApp' : 'Instagram'}
+							</button>
+						{/each}
+					</div>
+				</div>
+
+				<!-- Status -->
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+						Status inicial
+					</label>
+					<select
+						bind:value={form.status}
+						class="w-full rounded-lg border border-slate-300 bg-slate-50 px-3 py-2 text-sm text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+					>
+						<option>Ativo</option>
+						<option>Inativo</option>
+						<option>Disponível</option>
+					</select>
+				</div>
+
+				<!-- Disponível para escalonamento -->
+				<div class="flex items-center justify-between">
+					<div>
+						<div class="text-sm font-medium text-slate-900 dark:text-white">
+							Disponível para escalonamento
+						</div>
+						<div class="text-xs text-slate-500 dark:text-slate-400">
+							Permite receber conversas escaladas de outros agentes
+						</div>
+					</div>
+					<button
+						type="button"
+						onclick={() => (form.availableForEscalation = !form.availableForEscalation)}
+						class="relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 focus:outline-none {form.availableForEscalation
+							? 'bg-indigo-600 dark:bg-indigo-500'
+							: 'bg-slate-200 dark:bg-slate-700'}"
+					>
+						<span
+							class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow transition duration-200 {form.availableForEscalation
+								? 'translate-x-5'
+								: 'translate-x-0'}"
+						></span>
+					</button>
+				</div>
+			</div>
+
+			<div
+				class="flex justify-end gap-3 border-t border-slate-200 p-5 dark:border-slate-700"
+			>
+				<button
+					onclick={() => (showModal = false)}
+					class="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700"
+				>
+					Cancelar
+				</button>
+				<button
+					onclick={saveAgent}
+					disabled={!form.name.trim()}
+					class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-indigo-500 dark:hover:bg-indigo-600"
+				>
+					Salvar
+				</button>
+			</div>
+		</div>
+	</div>
+{/if}
+
+<div class="mx-auto max-w-[1600px] space-y-6">
+	<!-- Page header -->
+	<div
+		class="flex flex-wrap items-center justify-between gap-4 rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
+		<div class="flex items-center gap-3">
+			<div
+				class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-indigo-500/20 text-indigo-500"
+			>
+				<Users size={20} strokeWidth={2.5} />
+			</div>
+			<div>
+				<h1 class="text-xl font-bold text-slate-900 dark:text-white">Gestão de Agentes</h1>
+				<p class="text-sm text-slate-500 dark:text-slate-400">
+					Gerencie a equipe de atendimento e configure escalonamentos
+				</p>
+			</div>
+		</div>
+		<button
+			onclick={openNewAgent}
+			class="flex items-center gap-2 rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition-all hover:-translate-y-0.5 hover:bg-indigo-700 hover:shadow-md dark:bg-indigo-500 dark:hover:bg-indigo-600"
+		>
+			<UserPlus size={16} strokeWidth={2.5} />
+			+ Cadastrar Agente
+		</button>
+	</div>
+
+	<!-- Stats row -->
+	{#if isLoading}
+		<div class="grid grid-cols-2 gap-4 xl:grid-cols-4">
+			{#each [1, 2, 3, 4] as _}
+				<div
+					class="h-20 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
+				></div>
+			{/each}
+		</div>
+	{:else}
+		<div class="grid grid-cols-2 gap-4 xl:grid-cols-4">
+			{#each [
+				{ label: 'Total de Agentes', value: stats.total, color: 'text-slate-900 dark:text-white', icon: Users, bg: 'bg-slate-100 dark:bg-slate-800', iconCls: 'text-slate-600 dark:text-slate-400' },
+				{ label: 'Ativos agora', value: stats.active, color: 'text-emerald-600 dark:text-emerald-400', icon: CheckCircle, bg: 'bg-emerald-50 dark:bg-emerald-400/10', iconCls: 'text-emerald-600 dark:text-emerald-400' },
+				{ label: 'Em atendimento', value: stats.inAttendance, color: 'text-sky-600 dark:text-sky-400', icon: MessageSquare, bg: 'bg-sky-50 dark:bg-sky-400/10', iconCls: 'text-sky-600 dark:text-sky-400' },
+				{ label: 'Disp. para escalonamento', value: stats.availableForEscalation, color: 'text-indigo-600 dark:text-indigo-400', icon: ShieldCheck, bg: 'bg-indigo-50 dark:bg-indigo-400/10', iconCls: 'text-indigo-600 dark:text-indigo-400' }
+			] as stat}
+				{@const Icon = stat.icon}
+				<div
+					class="flex items-center gap-3 rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition-colors dark:border-slate-800 dark:bg-[#1e293b]"
+				>
+					<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg {stat.bg} {stat.iconCls}">
+						<Icon size={18} strokeWidth={2.5} />
+					</div>
+					<div>
+						<div class="text-2xl font-bold {stat.color}">{stat.value}</div>
+						<div class="text-xs text-slate-500 dark:text-slate-400">{stat.label}</div>
+					</div>
+				</div>
+			{/each}
+		</div>
+	{/if}
+
+	<!-- Filter bar -->
+	<div
+		class="flex flex-wrap items-center gap-3 rounded-xl border border-slate-200 bg-white p-4 text-sm shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
+		<div class="relative flex-1 min-w-48">
+			<Search size={16} class="absolute top-1/2 left-3 -translate-y-1/2 text-slate-400" />
+			<input
+				type="text"
+				placeholder="Buscar por nome..."
+				bind:value={searchTerm}
+				class="w-full rounded-lg border border-slate-300 bg-slate-50 py-1.5 pr-3 pl-9 text-slate-900 placeholder-slate-400 focus:border-indigo-500 focus:bg-white focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:placeholder-slate-500"
+			/>
+		</div>
+
+		<div class="flex items-center gap-2">
+			<span class="text-xs font-medium text-slate-500 dark:text-slate-400">Departamento:</span>
+			<select
+				bind:value={filterDept}
+				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+			>
+				{#each ['Todos', 'SAC', 'Vendas', 'Suporte'] as opt}
+					<option>{opt}</option>
+				{/each}
+			</select>
+		</div>
+
+		<div class="flex items-center gap-2">
+			<span class="text-xs font-medium text-slate-500 dark:text-slate-400">Canal:</span>
+			<select
+				bind:value={filterChannel}
+				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+			>
+				{#each ['Todos', 'WhatsApp', 'Instagram'] as opt}
+					<option>{opt}</option>
+				{/each}
+			</select>
+		</div>
+
+		<div class="flex items-center gap-2">
+			<span class="text-xs font-medium text-slate-500 dark:text-slate-400">Status:</span>
+			<select
+				bind:value={filterStatus}
+				class="rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200"
+			>
+				{#each ['Todos', 'Ativo', 'Inativo', 'Em Atendimento', 'Disponível para Escalonamento'] as opt}
+					<option>{opt}</option>
+				{/each}
+			</select>
+		</div>
+	</div>
+
+	<!-- Agents table -->
+	<div
+		class="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
+		{#if isLoading}
+			<div class="space-y-3 p-4">
+				{#each [1, 2, 3, 4, 5] as _}
+					<div
+						class="h-14 animate-pulse rounded-lg bg-slate-100 dark:bg-slate-800"
+					></div>
+				{/each}
+			</div>
+		{:else}
+			<div class="overflow-x-auto">
+				<table class="w-full min-w-[960px] text-sm">
+					<thead>
+						<tr class="border-b border-slate-200 bg-slate-50 dark:border-slate-800 dark:bg-slate-900/50">
+							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Agente</th>
+							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Depto</th>
+							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Canal</th>
+							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Status</th>
+							<th class="px-4 py-3 text-center text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Escalonamento</th>
+							<th class="px-4 py-3 text-center text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Hoje</th>
+							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">T. Médio Resp.</th>
+							<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">SLA Cumprido</th>
+							<th class="px-4 py-3 text-center text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Ações</th>
+						</tr>
+					</thead>
+					<tbody class="divide-y divide-slate-100 dark:divide-slate-800">
+						{#if filteredAgents.length === 0}
+							<tr>
+								<td colspan="9" class="py-16 text-center">
+									<div class="flex flex-col items-center gap-3">
+										<div class="flex h-12 w-12 items-center justify-center rounded-full bg-slate-100 dark:bg-slate-800">
+											<Users size={20} class="text-slate-400" />
+										</div>
+										<div class="text-sm font-medium text-slate-500 dark:text-slate-400">Nenhum agente encontrado</div>
+										<div class="text-xs text-slate-400 dark:text-slate-500">Tente ajustar os filtros acima</div>
+									</div>
+								</td>
+							</tr>
+						{:else}
+							{#each filteredAgents as agent (agent.id)}
+								{@const sc = statusConfig(agent.status)}
+								{@const trend = trendArrow(agent.responseTimeTrend)}
+								<tr
+									class="transition-colors hover:bg-slate-50 dark:hover:bg-slate-800/40 {agent.status === 'Inativo'
+										? 'opacity-60'
+										: ''}"
+								>
+									<!-- Nome -->
+									<td class="px-4 py-3">
+										<div class="flex items-center gap-3">
+											<div
+												class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-indigo-100 text-xs font-bold text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-300"
+											>
+												{agent.initials}
+											</div>
+											<span class="font-medium text-slate-900 dark:text-white">{agent.name}</span>
+										</div>
+									</td>
+
+									<!-- Departamento -->
+									<td class="px-4 py-3">
+										<span
+											class="rounded-md border px-2 py-0.5 text-xs font-semibold {deptBadgeClass(agent.department)}"
+										>
+											{agent.department}
+										</span>
+									</td>
+
+									<!-- Canal -->
+									<td class="px-4 py-3">
+										<div class="flex flex-wrap gap-1">
+											{#if agent.channels.includes('whatsapp')}
+												<span
+													class="rounded-md border border-emerald-200 bg-emerald-50 px-1.5 py-0.5 text-[10px] font-bold text-emerald-700 dark:border-emerald-400/20 dark:bg-emerald-400/10 dark:text-emerald-400"
+													>WA</span
+												>
+											{/if}
+											{#if agent.channels.includes('instagram')}
+												<span
+													class="rounded-md border border-purple-200 bg-purple-50 px-1.5 py-0.5 text-[10px] font-bold text-purple-700 dark:border-purple-400/20 dark:bg-purple-400/10 dark:text-purple-400"
+													>IG</span
+												>
+											{/if}
+										</div>
+									</td>
+
+									<!-- Status -->
+									<td class="px-4 py-3">
+										<div class="flex items-center gap-2">
+											<span
+												class="inline-block h-2 w-2 shrink-0 rounded-full {sc.dot}"
+											></span>
+											<span class="text-xs font-medium {sc.text}">{agent.status}</span>
+										</div>
+									</td>
+
+									<!-- Escalonamento toggle -->
+									<td class="px-4 py-3 text-center">
+										<button
+											type="button"
+											onclick={() => toggleEscalation(agent.id)}
+											class="relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 focus:outline-none {agent.availableForEscalation
+												? 'bg-indigo-600 dark:bg-indigo-500'
+												: 'bg-slate-200 dark:bg-slate-700'}"
+											title={agent.availableForEscalation
+												? 'Disponível para escalonamento'
+												: 'Indisponível para escalonamento'}
+										>
+											<span
+												class="pointer-events-none inline-block h-4 w-4 transform rounded-full bg-white shadow transition duration-200 {agent.availableForEscalation
+													? 'translate-x-4'
+													: 'translate-x-0'}"
+											></span>
+										</button>
+									</td>
+
+									<!-- Atendimentos hoje -->
+									<td class="px-4 py-3 text-center">
+										<span class="font-semibold text-slate-900 dark:text-white"
+											>{agent.todayAttendances}</span
+										>
+									</td>
+
+									<!-- Tempo médio -->
+									<td class="px-4 py-3">
+										<div class="flex items-center gap-1.5">
+											<Clock size={13} class="shrink-0 text-slate-400" />
+											<span class="text-slate-700 dark:text-slate-300">{agent.avgResponseTime}</span>
+											<span class="text-xs font-semibold {trend.cls}">{trend.arrow}</span>
+										</div>
+									</td>
+
+									<!-- SLA progress -->
+									<td class="px-4 py-3">
+										<div class="flex items-center gap-2">
+											<div class="h-2 w-20 overflow-hidden rounded-full bg-slate-100 dark:bg-slate-800">
+												<div
+													class="h-full rounded-full {slaBarClass(agent.slaPct)}"
+													style="width: {agent.slaPct}%"
+												></div>
+											</div>
+											<span
+												class="text-xs font-semibold {agent.slaPct >= 90
+													? 'text-emerald-600 dark:text-emerald-400'
+													: agent.slaPct >= 70
+													? 'text-amber-600 dark:text-amber-400'
+													: 'text-red-600 dark:text-red-400'}"
+											>
+												{agent.slaPct}%
+											</span>
+										</div>
+									</td>
+
+									<!-- Ações -->
+									<td class="px-4 py-3">
+										<div class="flex items-center justify-center gap-2">
+											<button
+												onclick={() => openEditAgent(agent)}
+												class="rounded-md p-1.5 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 dark:hover:bg-slate-800 dark:hover:text-slate-200"
+												title="Editar agente"
+											>
+												<Edit size={15} />
+											</button>
+											<button
+												onclick={() => toggleAgentActive(agent.id)}
+												class="rounded-md p-1.5 transition-colors {agent.status === 'Inativo'
+													? 'text-emerald-500 hover:bg-emerald-50 hover:text-emerald-700 dark:hover:bg-emerald-400/10'
+													: 'text-slate-400 hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-400/10 dark:hover:text-red-400'}"
+												title={agent.status === 'Inativo' ? 'Reativar agente' : 'Desativar agente'}
+											>
+												<Power size={15} />
+											</button>
+										</div>
+									</td>
+								</tr>
+							{/each}
+						{/if}
+					</tbody>
+				</table>
+			</div>
+		{/if}
+	</div>
+</div>

+ 146 - 0
src/routes/(app)/dashboard/ajuda/+page.svelte

@@ -0,0 +1,146 @@
+<script>
+	import { HelpCircle, MessageCircle, Mail, Book, Globe, FileText, MoreHorizontal, ChevronDown } from 'lucide-svelte';
+	let expandedFaq = null;
+
+	const supportChannels = [
+		{
+			title: 'Central de Ajuda',
+			description: 'Acesse nossa base de conhecimento com artigos e tutoriais',
+			icon: Book,
+			action: 'Acessar',
+			link: '#'
+		},
+		{
+			title: 'E-mail de Suporte',
+			description: 'Envie suas dúvidas para nossa equipe de suporte',
+			icon: Mail,
+			action: 'Enviar',
+			link: 'mailto:support@nettown.com'
+		},
+		{
+			title: 'Chat ao Vivo',
+			description: 'Converse com nossa equipe em tempo real',
+			icon: MessageCircle,
+			action: 'Iniciar Chat',
+			link: '#'
+		},
+		{
+			title: 'Documentação',
+			description: 'Leia a documentação técnica e guias de integração',
+			icon: FileText,
+			action: 'Ler Docs',
+			link: '#'
+		}
+	];
+
+	const faqs = [
+		{
+			question: 'Como funciona a análise de sentimento?',
+			answer: 'Nossa análise de sentimento utiliza inteligência artificial para avaliar o tom e a emoção em conversas. O sistema analisa mensagens de texto e categoriza o sentimento em positivo, negativo ou neutro.'
+		},
+		{
+			question: 'Quais plataformas são suportadas?',
+			answer: 'Atualmente suportamos integração com WhatsApp Business. Estamos trabalhando em suporte para outras plataformas como Messenger, Telegram e SMS.'
+		},
+		{
+			question: 'Como faço para integrar minha conta do WhatsApp?',
+			answer: 'Você pode integrar sua conta do WhatsApp Business através das configurações de integrações. Será necessário ter um número de telefone comercial e acesso à sua conta do Meta Business.'
+		},
+		{
+			question: 'Posso exportar meus dados?',
+			answer: 'Sim! Você pode exportar seus dados em formato CSV ou Excel a qualquer momento. Esta opção está disponível nas configurações de conta.'
+		},
+		{
+			question: 'Qual é o tempo de resposta do suporte?',
+			answer: 'Nosso tempo médio de resposta é de 24 horas para suporte por email. Se você tem um plano Profissional ou Empresa, oferecemos suporte prioritário com tempo de resposta de até 4 horas.'
+		},
+		{
+			question: 'Como posso cancelar minha assinatura?',
+			answer: 'Você pode cancelar sua assinatura a qualquer momento através da seção de Assinatura em seu perfil. Seu acesso será mantido até o final do ciclo de faturamento atual.'
+		}
+	];
+
+	function toggleFaq(index) {
+		expandedFaq = expandedFaq === index ? null : index;
+	}
+</script>
+
+<div class="mx-auto max-w-4xl space-y-6">
+	<!-- Header -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="flex items-center gap-3">
+			<div class="h-8 w-8 shrink-0 rounded-lg bg-indigo-500/20 text-indigo-500 flex items-center justify-center">
+				<HelpCircle size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Ajuda e Suporte</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Encontre respostas para suas dúvidas e entre em contato com nosso suporte
+		</p>
+	</div>
+
+	<!-- Support Channels -->
+	<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
+		{#each supportChannels as channel}
+			{@const Icon = channel.icon}
+			<a
+				href={channel.link}
+				class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-all duration-200 dark:border-slate-800 dark:bg-[#161f30] hover:border-indigo-400 dark:hover:border-indigo-500 hover:shadow-md"
+			>
+				<div class="flex items-start justify-between mb-3">
+					<div class="h-10 w-10 rounded-lg bg-indigo-500/10 text-indigo-600 flex items-center justify-center dark:bg-indigo-900/30 dark:text-indigo-400">
+						<Icon size={20} strokeWidth={2} />
+					</div>
+					<button class="p-1 text-slate-400 hover:text-slate-600 dark:hover:text-slate-300">
+						<MoreHorizontal size={16} />
+					</button>
+				</div>
+				<h3 class="font-semibold text-slate-900 dark:text-white mb-1">{channel.title}</h3>
+				<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">{channel.description}</p>
+				<button class="text-sm font-medium text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300">
+					{channel.action} →
+				</button>
+			</a>
+		{/each}
+	</div>
+
+	<!-- FAQ Section -->
+	<div class="space-y-4">
+		<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Perguntas Frequentes</h2>
+
+		<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30] divide-y divide-slate-200 dark:divide-slate-800">
+			{#each faqs as faq, index}
+				<div class="p-5 hover:bg-slate-50 transition-colors duration-150 dark:hover:bg-slate-800/50">
+					<button
+						onclick={() => toggleFaq(index)}
+						class="w-full flex items-center justify-between"
+					>
+						<h3 class="text-sm font-medium text-slate-900 dark:text-white text-left">{faq.question}</h3>
+						<ChevronDown
+							size={18}
+							class="text-slate-400 shrink-0 transition-transform duration-200 {expandedFaq === index ? 'rotate-180' : ''}"
+						/>
+					</button>
+
+					{#if expandedFaq === index}
+						<p class="mt-3 text-sm text-slate-600 dark:text-slate-400 text-left">
+							{faq.answer}
+						</p>
+					{/if}
+				</div>
+			{/each}
+		</div>
+	</div>
+
+	<!-- Contact Info -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<h2 class="text-lg font-semibold text-slate-900 dark:text-white mb-4">Não encontrou o que procura?</h2>
+		<p class="text-slate-600 dark:text-slate-400 mb-4">
+			Entre em contato com nossa equipe de suporte através de qualquer um dos canais acima. Estamos aqui para ajudá-lo!
+		</p>
+		<div class="space-y-2 text-sm text-slate-600 dark:text-slate-400">
+			<p><strong class="text-slate-900 dark:text-white">E-mail:</strong> support@nettown.com</p>
+			<p><strong class="text-slate-900 dark:text-white">Horário de atendimento:</strong> Segunda à Sexta, 9:00 às 18:00</p>
+		</div>
+	</div>
+</div>

+ 18 - 2
src/routes/(app)/dashboard/analytics/+page.svelte

@@ -13,6 +13,11 @@
 	import { onMount } from 'svelte';
 
 	const dashboardData = getSentimentDashboardViewModel();
+	const timeframeOptions = [
+		{ id: 'day', label: 'Últimos 7 dias' },
+		{ id: 'week', label: 'Últimas 6 semanas' },
+		{ id: 'month', label: 'Últimos 6 meses' }
+	];
 	const defaultInsight = {
 		title: 'Painel de decisao',
 		context: 'Clique em um card, alerta ou ponto do grafico para entender o que esta acontecendo e qual acao executar.',
@@ -26,7 +31,9 @@
 	let selectedCardId = $state(null);
 	let selectedAlertId = $state(null);
 	let selectedPeriod = $state(null);
+	let selectedTimeframe = $state('week');
 	let selectedInsight = $state(defaultInsight);
+	const timelineData = $derived(dashboardData.timelineViews?.[selectedTimeframe] ?? dashboardData.timeline);
 
 	// Read initial state from URL query parameters
 	let panelAspectId = $state($page.url.searchParams.get('aspect') ?? null);
@@ -61,7 +68,13 @@
 		selectedCardId = null;
 		selectedAlertId = null;
 		selectedPeriod = point.period;
-		selectedInsight = getTimelineInsight(point.period, dashboardData);
+		selectedInsight = getTimelineInsight(point.period, dashboardData, selectedTimeframe);
+	}
+
+	function handleTimeframeChange(value) {
+		selectedTimeframe = value;
+		selectedPeriod = null;
+		selectedInsight = defaultInsight;
 	}
 </script>
 
@@ -86,9 +99,12 @@
 		</div>
 		<div class="2xl:col-span-4 flex flex-col">
 			<GainLossChart
-				data={dashboardData.timeline}
+				data={timelineData}
 				onPointSelect={handleTimelinePointSelect}
 				selectedPeriod={selectedPeriod}
+				timeframeOptions={timeframeOptions}
+				selectedTimeframe={selectedTimeframe}
+				onTimeframeChange={handleTimeframeChange}
 			/>
 		</div>
 		<div class="2xl:col-span-2 flex flex-col">

+ 164 - 0
src/routes/(app)/dashboard/assinatura/+page.svelte

@@ -0,0 +1,164 @@
+<script>
+	import { CreditCard, Calendar, AlertCircle, Check } from 'lucide-svelte';
+
+	let currentPlan = {
+		name: 'Profissional',
+		price: 299,
+		billingCycle: 'mensal',
+		status: 'ativo',
+		nextBillingDate: '15/06/2026'
+	};
+
+	const plans = [
+		{
+			name: 'Starter',
+			price: 99,
+			description: 'Perfeito para começar',
+			features: [
+				'Até 5 clientes',
+				'Análise básica de sentimento',
+				'Relatórios mensais',
+				'Suporte por email'
+			],
+			popular: false
+		},
+		{
+			name: 'Profissional',
+			price: 299,
+			description: 'Mais recursos e análises',
+			features: [
+				'Até 50 clientes',
+				'Análise avançada de sentimento',
+				'Relatórios em tempo real',
+				'API access',
+				'Suporte prioritário',
+				'Integrações WhatsApp'
+			],
+			popular: true
+		},
+		{
+			name: 'Empresa',
+			price: 999,
+			description: 'Recursos completos',
+			features: [
+				'Clientes ilimitados',
+				'Análise completa de IA',
+				'Dashboards personalizados',
+				'API completa',
+				'Suporte 24/7',
+				'Todas as integrações',
+				'Usuários ilimitados'
+			],
+			popular: false
+		}
+	];
+
+	function handleUpgrade(plan) {
+		console.log(`Upgrading to ${plan.name} plan`);
+	}
+
+	function handleCancelSubscription() {
+		if (confirm('Tem certeza que deseja cancelar sua assinatura?')) {
+			console.log('Cancelando assinatura...');
+		}
+	}
+</script>
+
+<div class="mx-auto max-w-4xl space-y-6">
+	<!-- Header -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="flex items-center gap-3">
+			<div class="h-8 w-8 shrink-0 rounded-lg bg-indigo-500/20 text-indigo-500 flex items-center justify-center">
+				<CreditCard size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Assinatura</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Gerencie seu plano, faturamento e métodos de pagamento
+		</p>
+	</div>
+
+	<!-- Current Plan -->
+	<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="border-b border-slate-200 p-5 dark:border-slate-800">
+			<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Seu Plano Atual</h2>
+		</div>
+
+		<div class="p-5 md:p-6">
+			<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
+				<div>
+					<p class="text-sm text-slate-600 dark:text-slate-400 mb-1">Plano</p>
+					<p class="text-2xl font-bold text-slate-900 dark:text-white">{currentPlan.name}</p>
+				</div>
+				<div>
+					<p class="text-sm text-slate-600 dark:text-slate-400 mb-1">Preço</p>
+					<p class="text-2xl font-bold text-slate-900 dark:text-white">R$ {currentPlan.price}</p>
+					<p class="text-xs text-slate-500 dark:text-slate-400">por mês</p>
+				</div>
+				<div>
+					<p class="text-sm text-slate-600 dark:text-slate-400 mb-1">Próxima cobrança</p>
+					<div class="flex items-center gap-2">
+						<Calendar size={18} class="text-indigo-600 dark:text-indigo-400" />
+						<span class="text-lg font-semibold text-slate-900 dark:text-white">{currentPlan.nextBillingDate}</span>
+					</div>
+				</div>
+			</div>
+
+			<div class="flex flex-col md:flex-row gap-3 pt-4 border-t border-slate-200 dark:border-slate-800">
+				<button class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150">
+					Atualizar Método de Pagamento
+				</button>
+				<button
+					onclick={handleCancelSubscription}
+					class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg border border-red-300 text-red-600 hover:bg-red-50 transition-colors duration-150 dark:border-red-800 dark:text-red-400 dark:hover:bg-slate-800"
+				>
+					Cancelar Assinatura
+				</button>
+			</div>
+		</div>
+	</div>
+
+	<!-- Available Plans -->
+	<div class="space-y-4">
+		<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Outros Planos Disponíveis</h2>
+
+		<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
+			{#each plans as plan}
+				<div class="rounded-xl border {plan.popular ? 'border-indigo-500 ring-2 ring-indigo-100 dark:ring-indigo-900/30' : 'border-slate-200 dark:border-slate-800'} bg-white shadow-sm transition-colors duration-200 dark:bg-[#161f30] overflow-hidden">
+					{#if plan.popular}
+						<div class="bg-indigo-600 px-4 py-2 text-center">
+							<span class="text-xs font-semibold text-white uppercase tracking-wider">Mais Popular</span>
+						</div>
+					{/if}
+
+					<div class="p-5 md:p-6">
+						<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-2">{plan.name}</h3>
+						<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">{plan.description}</p>
+
+						<div class="mb-6">
+							<span class="text-3xl font-bold text-slate-900 dark:text-white">R$ {plan.price}</span>
+							<span class="text-sm text-slate-600 dark:text-slate-400">/mês</span>
+						</div>
+
+						<button
+							onclick={() => handleUpgrade(plan)}
+							disabled={plan.name === currentPlan.name}
+							class="w-full px-4 py-2 text-sm font-medium rounded-lg transition-colors duration-150 {plan.popular ? 'bg-indigo-600 text-white hover:bg-indigo-700' : 'bg-slate-100 text-slate-900 hover:bg-slate-200 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700'} {plan.name === currentPlan.name ? 'opacity-50 cursor-not-allowed' : ''}"
+						>
+							{plan.name === currentPlan.name ? 'Plano Atual' : 'Escolher Plano'}
+						</button>
+
+						<div class="mt-6 space-y-3 pt-6 border-t border-slate-200 dark:border-slate-800">
+							{#each plan.features as feature}
+								<div class="flex items-center gap-3">
+									<Check size={16} class="text-green-600 dark:text-green-400 shrink-0" />
+									<span class="text-sm text-slate-700 dark:text-slate-300">{feature}</span>
+								</div>
+							{/each}
+						</div>
+					</div>
+				</div>
+			{/each}
+		</div>
+	</div>
+</div>

+ 231 - 35
src/routes/(app)/dashboard/evolucao/+page.svelte

@@ -1,19 +1,185 @@
 <script>
 	import { TrendingUp, Shield, DollarSign, CheckCircle, Heart, Activity } from 'lucide-svelte';
-	import { Chart, Svg, Axis, Line, Spline, Highlight } from 'layerchart';
+	import { Chart, Svg, Axis, Spline, Highlight } from 'layerchart';
 	import { format } from 'date-fns';
-	import { ptBR } from 'date-fns/locale';
 	import { mockEvolucaoSentimentosData, mockMonitoramentoPlaybooksData } from '$lib/core/models/mock-data.js';
 
-	// Mock Data for KPIs
-	const mockEvolucaoKpis = {
-		churnEvitado: '--',
-		roiUpsell: '--',
-		scoreMedio: '--',
-		taxaEvolucao: '--',
-		conversaoEmocao: '--'
+	const periodOptions = [
+		{ id: 'week', label: 'Últimos 7 dias', multiplier: 1, sentimentBoost: 0 },
+		{ id: 'month', label: 'Últimos 30 dias', multiplier: 1.25, sentimentBoost: 0.05 },
+		{ id: 'quarter', label: 'Último trimestre', multiplier: 1.5, sentimentBoost: 0.08 }
+	];
+
+	const unitOptions = [
+		{ id: 'all', label: 'Sem segmento', multiplier: 1 },
+		{ id: 'flagship', label: 'Loja Flagship', multiplier: 1.2 },
+		{ id: 'digital', label: 'Digital', multiplier: 1.1 },
+		{ id: 'atacado', label: 'Atacado', multiplier: 0.85 }
+	];
+
+	const areaOptions = [
+		{ id: 'any', label: 'Sem segmento de setor', multiplier: 1 },
+		{ id: 'atendimento', label: 'Atendimento', multiplier: 1.15 },
+		{ id: 'produto', label: 'Produto', multiplier: 1.05 },
+		{ id: 'logistica', label: 'Logística', multiplier: 0.95 }
+	];
+
+	const lineOptions = [
+		{ id: 'all', label: 'Todas', multiplier: 1 },
+		{ id: 'luxo', label: 'Linha Luxo', multiplier: 1.3 },
+		{ id: 'casual', label: 'Linha Casual', multiplier: 1.1 },
+		{ id: 'basicos', label: 'Linha Básicos', multiplier: 0.9 }
+	];
+
+	const sentimentOptions = [
+		{
+			id: 'all',
+			label: 'Todos',
+			bias: { churn: 1, roi: 1, satisfaction: 1, trend: 1, conversion: 1, sentimentShift: 1, detection: 1, conversionRate: 1 }
+		},
+		{
+			id: 'positive',
+			label: 'Positivo',
+			bias: { churn: 0.85, roi: 1.15, satisfaction: 1.1, trend: 1.2, conversion: 1.2, sentimentShift: 1.15, detection: 1.05, conversionRate: 1.1 }
+		},
+		{
+			id: 'neutral',
+			label: 'Neutro',
+			bias: { churn: 1, roi: 1, satisfaction: 1, trend: 1, conversion: 1, sentimentShift: 1, detection: 1, conversionRate: 1 }
+		},
+		{
+			id: 'negative',
+			label: 'Negativo',
+			bias: { churn: 1.2, roi: 0.85, satisfaction: 0.9, trend: 0.75, conversion: 0.8, sentimentShift: 0.8, detection: 0.9, conversionRate: 0.75 }
+		}
+	];
+
+	const sourceOptions = [
+		{ id: 'all', label: 'Todas', multiplier: 1 },
+		{ id: 'whatsapp', label: 'WhatsApp', multiplier: 1.1 },
+		{ id: 'crm', label: 'CRM', multiplier: 1.05 },
+		{ id: 'email', label: 'E-mail', multiplier: 0.95 }
+	];
+
+	let selectedPeriod = $state(periodOptions[0].id);
+	let selectedUnit = $state(unitOptions[0].id);
+	let selectedArea = $state(areaOptions[0].id);
+	let selectedLine = $state(lineOptions[0].id);
+	let selectedSentiment = $state(sentimentOptions[0].id);
+	let selectedSource = $state(sourceOptions[0].id);
+
+	const filterContext = $derived({
+		period: periodOptions.find((opt) => opt.id === selectedPeriod) ?? periodOptions[0],
+		unit: unitOptions.find((opt) => opt.id === selectedUnit) ?? unitOptions[0],
+		area: areaOptions.find((opt) => opt.id === selectedArea) ?? areaOptions[0],
+		line: lineOptions.find((opt) => opt.id === selectedLine) ?? lineOptions[0],
+		sentiment: sentimentOptions.find((opt) => opt.id === selectedSentiment) ?? sentimentOptions[0],
+		source: sourceOptions.find((opt) => opt.id === selectedSource) ?? sourceOptions[0]
+	});
+
+	const combinedMultiplier = $derived(
+		(filterContext.period?.multiplier ?? 1) *
+			(filterContext.unit?.multiplier ?? 1) *
+			(filterContext.area?.multiplier ?? 1) *
+			(filterContext.line?.multiplier ?? 1) *
+			(filterContext.source?.multiplier ?? 1)
+	);
+
+	const baseKpis = {
+		churnEvitado: 85000,
+		roiUpsell: 3.1,
+		scoreMedio: 74,
+		taxaEvolucao: 21,
+		conversaoEmocao: 47
 	};
 
+	const kpis = $derived.by(() => {
+		const bias = filterContext.sentiment?.bias ?? sentimentOptions[0].bias;
+		const multiplier = Number.isFinite(combinedMultiplier) ? combinedMultiplier : 1;
+		const churnEvitado = Math.round(baseKpis.churnEvitado * multiplier * bias.churn);
+		const roiUpsell = Number((baseKpis.roiUpsell * bias.roi).toFixed(1));
+		const scoreMedio = clamp(
+			Math.round(baseKpis.scoreMedio * bias.satisfaction + (multiplier - 1) * 18),
+			0,
+			100
+		);
+		const taxaEvolucao = Number((baseKpis.taxaEvolucao * multiplier * bias.trend).toFixed(1));
+		const conversaoEmocao = clamp(
+			Math.round(baseKpis.conversaoEmocao * bias.conversion + (multiplier - 1) * 10),
+			0,
+			100
+		);
+		return { churnEvitado, roiUpsell, scoreMedio, taxaEvolucao, conversaoEmocao };
+	});
+
+	function clamp(value, min, max) {
+		return Math.min(max, Math.max(min, value));
+	}
+
+	function formatCurrency(value) {
+		const safeValue = Number.isFinite(value) ? value : 0;
+		return safeValue.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
+	}
+
+	function formatPercent(value) {
+		return `${Number.isFinite(value) ? value.toFixed(1) : '0.0'}%`;
+	}
+
+	function formatNumber(value) {
+		return Number.isFinite(value) ? value.toLocaleString('pt-BR') : '0';
+	}
+
+	function formatRatio(value) {
+		return Number.isFinite(value) ? value.toFixed(1) : '0.0';
+	}
+
+	let evolucaoChartData = $state([...mockEvolucaoSentimentosData]);
+	let playbooksChartData = $state([...mockMonitoramentoPlaybooksData]);
+	let playbooksTotals = $state(
+		[...mockMonitoramentoPlaybooksData].reduce(
+			(acc, point) => {
+				acc.novos += point.novos;
+				acc.convertidos += point.convertidos;
+				return acc;
+			},
+			{ novos: 0, convertidos: 0 }
+		)
+	);
+	let playbooksMaxY = $state(60);
+
+	$effect(() => {
+		const bias = filterContext.sentiment.bias;
+		const adjustedData = mockEvolucaoSentimentosData.map((point) => {
+			const adjusted = clamp(
+				point.value * bias.sentimentShift + (combinedMultiplier - 1) * 0.12 + filterContext.period.sentimentBoost,
+				-1,
+				1
+			);
+			return { ...point, value: Number(adjusted.toFixed(2)) };
+		});
+		evolucaoChartData = adjustedData;
+	});
+
+	$effect(() => {
+		const bias = filterContext.sentiment.bias;
+		const adjustedPlaybooks = mockMonitoramentoPlaybooksData.map((point) => {
+			const novos = Math.max(0, Math.round(point.novos * combinedMultiplier * bias.detection));
+			const convertidos = Math.max(0, Math.round(point.convertidos * combinedMultiplier * bias.conversionRate));
+			return { ...point, novos, convertidos };
+		});
+		playbooksChartData = adjustedPlaybooks;
+		playbooksTotals = adjustedPlaybooks.reduce(
+			(acc, point) => {
+				acc.novos += point.novos;
+				acc.convertidos += point.convertidos;
+				return acc;
+			},
+			{ novos: 0, convertidos: 0 }
+		);
+		const datasetMax = adjustedPlaybooks.reduce((max, point) => Math.max(max, point.novos, point.convertidos), 0);
+		playbooksMaxY = Math.max(10, Math.ceil(datasetMax / 10) * 10 + 10);
+	});
+
 	function formatSentimentAxis(val) {
 		if (val === 1) return 'Pos.';
 		if (val === 0) return 'Neutro';
@@ -40,38 +206,68 @@
 		<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4 w-full text-sm mb-12">
 			<div class="flex flex-col gap-1.5">
 				<span class="text-xs font-semibold text-slate-500 dark:text-slate-400">Período</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Últimos 7 dias</option>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedPeriod}
+				>
+					{#each periodOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex flex-col gap-1.5">
 				<span class="text-xs font-semibold text-slate-500 dark:text-slate-400">Unidade</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Sem segmento</option>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedUnit}
+				>
+					{#each unitOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex flex-col gap-1.5">
 				<span class="text-xs font-semibold text-slate-500 dark:text-slate-400">Área</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Sem segmento de setor</option>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedArea}
+				>
+					{#each areaOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex flex-col gap-1.5">
 				<span class="text-xs font-semibold text-slate-500 dark:text-slate-400">Linha</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Todas</option>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedLine}
+				>
+					{#each lineOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex flex-col gap-1.5">
 				<span class="text-xs font-semibold text-slate-500 dark:text-slate-400">Sentimento</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Todos</option>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedSentiment}
+				>
+					{#each sentimentOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex flex-col gap-1.5">
 				<span class="text-xs font-semibold text-slate-500 dark:text-slate-400">Fonte</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Todas</option>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedSource}
+				>
+					{#each sourceOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 		</div>
@@ -80,27 +276,27 @@
 		<div class="grid grid-cols-2 md:grid-cols-5 gap-6 w-full pb-4">
 			<div class="flex flex-col items-center justify-center text-center">
 				<Shield size={24} class="text-red-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockEvolucaoKpis.churnEvitado}</div>
+				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{formatCurrency(kpis.churnEvitado)}</div>
 				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Churn Evitado (Valor)</div>
 			</div>
 			<div class="flex flex-col items-center justify-center text-center">
 				<DollarSign size={24} class="text-emerald-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockEvolucaoKpis.roiUpsell}</div>
+				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{formatRatio(kpis.roiUpsell)}x</div>
 				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">ROI de Upsell</div>
 			</div>
 			<div class="flex flex-col items-center justify-center text-center">
 				<CheckCircle size={24} class="text-amber-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockEvolucaoKpis.scoreMedio}</div>
+				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{kpis.scoreMedio}</div>
 				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Score Médio Geral</div>
 			</div>
 			<div class="flex flex-col items-center justify-center text-center">
 				<TrendingUp size={24} class="text-blue-400 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockEvolucaoKpis.taxaEvolucao}</div>
+				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{formatPercent(kpis.taxaEvolucao)}</div>
 				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Taxa de Evolução</div>
 			</div>
 			<div class="flex flex-col items-center justify-center text-center">
 				<Heart size={24} class="text-pink-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockEvolucaoKpis.conversaoEmocao}</div>
+				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{formatPercent(kpis.conversaoEmocao)}</div>
 				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Conversão de Emoção</div>
 			</div>
 		</div>
@@ -113,9 +309,9 @@
 			<h2 class="text-base font-bold text-slate-900 dark:text-white mb-4">Evolução dos Sentimentos Geral</h2>
 			<div class="h-full w-full flex-1">
 				<Chart
-					data={mockEvolucaoSentimentosData}
-					x={d => d.date}
-					y={d => d.value}
+					data={evolucaoChartData}
+					x={(d) => d.date}
+					y={(d) => d.value}
 					yDomain={[-1, 1]}
 					padding={{ top: 10, right: 10, bottom: 20, left: 40 }}
 				>
@@ -159,9 +355,9 @@
 					<div class="flex flex-col items-end">
 						<span class="text-[10px] font-bold text-slate-500 uppercase tracking-wider">Total do Período</span>
 						<div class="flex gap-1 text-sm font-bold">
-							<span class="text-indigo-400">148</span>
+							<span class="text-indigo-400">{formatNumber(playbooksTotals.novos)}</span>
 							<span class="text-slate-500">/</span>
-							<span class="text-emerald-400">5</span>
+							<span class="text-emerald-400">{formatNumber(playbooksTotals.convertidos)}</span>
 						</div>
 					</div>
 					<div class="flex items-center gap-4 text-xs font-medium text-slate-400">
@@ -179,9 +375,9 @@
 			
 			<div class="h-full w-full flex-1">
 				<Chart
-					data={mockMonitoramentoPlaybooksData}
-					x={d => d.date}
-					yDomain={[0, 60]}
+					data={playbooksChartData}
+					x={(d) => d.date}
+					yDomain={[0, playbooksMaxY]}
 					padding={{ top: 10, right: 10, bottom: 20, left: 30 }}
 				>
 					<Svg>
@@ -189,7 +385,7 @@
 							placement="left"
 							grid={{ class: 'stroke-slate-200 dark:stroke-slate-700', strokeDasharray: '2 2' }}
 							class="fill-slate-500 text-xs dark:fill-slate-400"
-							ticks={[0, 10, 20, 30, 40, 50, 60]}
+							ticks={[0, playbooksMaxY * 0.25, playbooksMaxY * 0.5, playbooksMaxY * 0.75, playbooksMaxY]}
 						/>
 						<Axis
 							placement="bottom"

+ 557 - 0
src/routes/(app)/dashboard/executive/+page.svelte

@@ -0,0 +1,557 @@
+<script>
+	import {
+		TrendingUp,
+		AlertTriangle,
+		DollarSign,
+		Users,
+		ShieldCheck,
+		Activity,
+		MessageSquare,
+		UserRound,
+		Settings,
+		BarChart2,
+		BookOpen
+	} from 'lucide-svelte';
+	import { onMount } from 'svelte';
+
+	let isLoading = $state(true);
+	onMount(() => {
+		setTimeout(() => {
+			isLoading = false;
+		}, 700);
+	});
+
+	// ── Section 1: Top KPIs ──────────────────────────────────────────────────
+	const topKpis = [
+		{
+			title: 'Venda Atual',
+			value: 'R$ 879',
+			trendLabel: '↑ +12% vs ontem',
+			trendColor: 'text-emerald-600 dark:text-emerald-400',
+			icon: DollarSign,
+			danger: false,
+			color: 'text-emerald-600 dark:text-emerald-400',
+			bg: 'bg-emerald-50 dark:bg-emerald-400/10',
+			border: 'border-emerald-200 dark:border-emerald-400/20'
+		},
+		{
+			title: 'Ticket Médio',
+			value: 'R$ 655,00',
+			trendLabel: '→ estável',
+			trendColor: 'text-slate-500 dark:text-slate-400',
+			icon: BarChart2,
+			danger: false,
+			color: 'text-sky-600 dark:text-sky-400',
+			bg: 'bg-sky-50 dark:bg-sky-400/10',
+			border: 'border-sky-200 dark:border-sky-400/20'
+		},
+		{
+			title: 'Lifetime em Risco',
+			value: 'R$ 8.639',
+			trendLabel: '↑ +5% esta semana',
+			trendColor: 'text-red-600 dark:text-red-400',
+			icon: AlertTriangle,
+			danger: true,
+			color: 'text-red-600 dark:text-red-400',
+			bg: 'bg-red-50 dark:bg-red-400/10',
+			border: 'border-red-200 dark:border-red-400/20'
+		},
+		{
+			title: 'Clientes em Risco Crítico',
+			value: '34',
+			trendLabel: '↑ +3 desde ontem',
+			trendColor: 'text-red-600 dark:text-red-400',
+			icon: Users,
+			danger: true,
+			color: 'text-red-600 dark:text-red-400',
+			bg: 'bg-red-50 dark:bg-red-400/10',
+			border: 'border-red-200 dark:border-red-400/20'
+		}
+	];
+
+	// ── Section 2: Churn donut ───────────────────────────────────────────────
+	const churnData = [
+		{ label: 'Baixo', value: 45, color: '#10b981' },
+		{ label: 'Moderado', value: 30, color: '#f59e0b' },
+		{ label: 'Alto', value: 15, color: '#f97316' },
+		{ label: 'Crítico', value: 10, color: '#ef4444' }
+	];
+
+	function buildDonut(data, cx, cy, r, ri) {
+		const total = data.reduce((s, d) => s + d.value, 0);
+		let a = -Math.PI / 2;
+		return data.map((d) => {
+			const sweep = (d.value / total) * 2 * Math.PI;
+			const a1 = a;
+			const a2 = a + sweep;
+			a = a2;
+			const x1 = cx + r * Math.cos(a1),
+				y1 = cy + r * Math.sin(a1);
+			const x2 = cx + r * Math.cos(a2),
+				y2 = cy + r * Math.sin(a2);
+			const ix1 = cx + ri * Math.cos(a2),
+				iy1 = cy + ri * Math.sin(a2);
+			const ix2 = cx + ri * Math.cos(a1),
+				iy2 = cy + ri * Math.sin(a1);
+			const lg = sweep > Math.PI ? 1 : 0;
+			return {
+				...d,
+				pct: Math.round((d.value / total) * 100),
+				path: `M${x1},${y1} A${r},${r},0,${lg},1,${x2},${y2} L${ix1},${iy1} A${ri},${ri},0,${lg},0,${ix2},${iy2} Z`
+			};
+		});
+	}
+
+	const donutPaths = buildDonut(churnData, 60, 60, 50, 28);
+
+	// ── Section 2: LTV em Risco ──────────────────────────────────────────────
+	const ltvTotal = 285000;
+	const ltvAtRisk = 34556;
+	const ltvRiskPct = Math.round((ltvAtRisk / ltvTotal) * 100);
+
+	// ── Section 2: SLA ──────────────────────────────────────────────────────
+	const slaWithinPct = 78;
+	const slaBreachPct = 22;
+
+	// ── Section 3: Sentiment ─────────────────────────────────────────────────
+	const emotionData = [
+		{ label: 'Alegria', value: 38, color: '#10b981', count: 1524 },
+		{ label: 'Confiança', value: 22, color: '#6366f1', count: 882 },
+		{ label: 'Medo', value: 12, color: '#f97316', count: 481 },
+		{ label: 'Raiva', value: 5, color: '#ef4444', count: 201 },
+		{ label: 'Surpresa', value: 15, color: '#f59e0b', count: 602 },
+		{ label: 'Tristeza', value: 8, color: '#64748b', count: 321 }
+	];
+
+	const avgSentimentScore = 0.28;
+	const scorePosition = ((avgSentimentScore + 1) / 2) * 100;
+	let hoveredEmotion = $state(null);
+
+	// ── Section 4: Quick access ──────────────────────────────────────────────
+	const quickAccessItems = [
+		{
+			label: 'Conversas',
+			href: '/dashboard/interactions',
+			icon: MessageSquare,
+			metric: '418 hoje',
+			trend: '↑',
+			trendColor: 'text-emerald-600 dark:text-emerald-400',
+			color: 'text-sky-600 dark:text-sky-400',
+			bg: 'bg-sky-50 dark:bg-sky-400/10',
+			border: 'border-sky-200 dark:border-sky-400/20'
+		},
+		{
+			label: 'Personas',
+			href: '/dashboard/personas',
+			icon: UserRound,
+			metric: '5 ativas',
+			trend: '→',
+			trendColor: 'text-slate-500 dark:text-slate-400',
+			color: 'text-purple-600 dark:text-purple-400',
+			bg: 'bg-purple-50 dark:bg-purple-400/10',
+			border: 'border-purple-200 dark:border-purple-400/20'
+		},
+		{
+			label: 'Agentes',
+			href: '/dashboard/agents',
+			icon: Users,
+			metric: '12 ativos',
+			trend: '↑',
+			trendColor: 'text-emerald-600 dark:text-emerald-400',
+			color: 'text-emerald-600 dark:text-emerald-400',
+			bg: 'bg-emerald-50 dark:bg-emerald-400/10',
+			border: 'border-emerald-200 dark:border-emerald-400/20'
+		},
+		{
+			label: 'Playbooks',
+			href: '/dashboard/evolucao',
+			icon: BookOpen,
+			metric: '3 ativos',
+			trend: '→',
+			trendColor: 'text-slate-500 dark:text-slate-400',
+			color: 'text-amber-600 dark:text-amber-400',
+			bg: 'bg-amber-50 dark:bg-amber-400/10',
+			border: 'border-amber-200 dark:border-amber-400/20'
+		},
+		{
+			label: 'Configurações',
+			href: '/dashboard/settings',
+			icon: Settings,
+			metric: '2 pendentes',
+			trend: '↓',
+			trendColor: 'text-amber-600 dark:text-amber-400',
+			color: 'text-slate-600 dark:text-slate-400',
+			bg: 'bg-slate-100 dark:bg-slate-700/50',
+			border: 'border-slate-200 dark:border-slate-700'
+		},
+		{
+			label: 'Evolução',
+			href: '/dashboard/evolucao',
+			icon: TrendingUp,
+			metric: '+12% vs ontem',
+			trend: '↑',
+			trendColor: 'text-emerald-600 dark:text-emerald-400',
+			color: 'text-indigo-600 dark:text-indigo-400',
+			bg: 'bg-indigo-50 dark:bg-indigo-400/10',
+			border: 'border-indigo-200 dark:border-indigo-400/20'
+		}
+	];
+</script>
+
+<svelte:head>
+	<title>Executive Dashboard - Nettown Analytics</title>
+</svelte:head>
+
+<div class="mx-auto max-w-[1600px] space-y-6">
+	<!-- Page header -->
+	<div
+		class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
+		<div class="flex items-center gap-3">
+			<div
+				class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-indigo-500/20 text-indigo-500"
+			>
+				<Activity size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Executive Dashboard</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Visão executiva do desempenho comercial e saúde da base de clientes — atualizado agora há
+			pouco
+		</p>
+	</div>
+
+	<!-- Section 1: KPI Bar -->
+	{#if isLoading}
+		<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
+			{#each [1, 2, 3, 4] as _}
+				<div
+					class="h-28 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
+				></div>
+			{/each}
+		</div>
+	{:else}
+		<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
+			{#each topKpis as kpi}
+				{@const Icon = kpi.icon}
+				<div
+					class="rounded-xl border bg-white p-5 shadow-sm transition-colors duration-200 dark:bg-[#1e293b] {kpi.border}"
+				>
+					<div class="flex items-start gap-4">
+						<div
+							class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg {kpi.bg} {kpi.color}"
+						>
+							<Icon size={20} strokeWidth={2.5} />
+						</div>
+						<div class="min-w-0 flex-1 space-y-1">
+							<div class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
+								{kpi.title}
+							</div>
+							<div
+								class="text-2xl font-bold {kpi.danger
+									? kpi.color
+									: 'text-slate-900 dark:text-white'}"
+							>
+								{kpi.value}
+							</div>
+							<div class="text-xs font-medium {kpi.trendColor}">{kpi.trendLabel}</div>
+						</div>
+					</div>
+				</div>
+			{/each}
+		</div>
+	{/if}
+
+	<!-- Section 2: Risk Overview -->
+	{#if isLoading}
+		<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
+			{#each [1, 2, 3] as _}
+				<div
+					class="h-64 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
+				></div>
+			{/each}
+		</div>
+	{:else}
+		<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
+			<!-- Churn Donut -->
+			<div
+				class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+			>
+				<div class="mb-4 flex items-center gap-2">
+					<div
+						class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-400"
+					>
+						<Activity size={18} strokeWidth={2} />
+					</div>
+					<h2 class="text-base font-bold text-slate-900 dark:text-white">
+						Índice de Churn Relacional
+					</h2>
+				</div>
+				<div class="flex items-center gap-6">
+					<svg viewBox="0 0 120 120" class="h-36 w-36 shrink-0">
+						{#each donutPaths as seg}
+							<path d={seg.path} fill={seg.color} class="transition-opacity hover:opacity-80">
+								<title>{seg.label}: {seg.pct}%</title>
+							</path>
+						{/each}
+						<text
+							x="60"
+							y="55"
+							text-anchor="middle"
+							dominant-baseline="middle"
+							class="fill-slate-900 dark:fill-white"
+							font-size="11"
+							font-weight="bold"
+						>Churn</text>
+						<text
+							x="60"
+							y="67"
+							text-anchor="middle"
+							dominant-baseline="middle"
+							class="fill-slate-500 dark:fill-slate-400"
+							font-size="8"
+						>Relacional</text>
+					</svg>
+					<div class="flex-1 space-y-2.5">
+						{#each donutPaths as seg}
+							<div class="flex items-center gap-2 text-xs">
+								<span
+									class="inline-block h-2.5 w-2.5 shrink-0 rounded-full"
+									style="background-color: {seg.color}"
+								></span>
+								<span class="text-slate-700 dark:text-slate-300">{seg.label}</span>
+								<span class="ml-auto font-bold text-slate-900 dark:text-white">{seg.pct}%</span>
+							</div>
+						{/each}
+					</div>
+				</div>
+			</div>
+
+			<!-- LTV em Risco -->
+			<div
+				class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+			>
+				<div class="mb-4 flex items-center gap-2">
+					<div
+						class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-red-50 text-red-600 dark:bg-red-400/10 dark:text-red-400"
+					>
+						<AlertTriangle size={18} strokeWidth={2} />
+					</div>
+					<h2 class="text-base font-bold text-slate-900 dark:text-white">LTV em Risco</h2>
+				</div>
+				<div class="space-y-4">
+					<div>
+						<div class="text-2xl font-bold text-red-600 dark:text-red-400">
+							R$ {ltvAtRisk.toLocaleString('pt-BR')}
+						</div>
+						<div class="text-xs text-slate-500 dark:text-slate-400">
+							de R$ {ltvTotal.toLocaleString('pt-BR')} em LTV total
+						</div>
+					</div>
+					<div>
+						<div class="mb-1.5 flex items-center justify-between text-xs">
+							<span class="text-slate-600 dark:text-slate-300">{ltvRiskPct}% da base em risco</span>
+							<span class="font-semibold text-red-600 dark:text-red-400">↑ aumentando</span>
+						</div>
+						<div class="h-3 w-full overflow-hidden rounded-full bg-slate-100 dark:bg-slate-800">
+							<div
+								class="h-full rounded-full bg-red-500 transition-all"
+								style="width: {ltvRiskPct}%"
+							></div>
+						</div>
+					</div>
+					<div
+						class="rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-400/20 dark:bg-amber-400/10"
+					>
+						<div class="text-xs font-medium text-amber-700 dark:text-amber-400">
+							34 clientes críticos · Ticket médio R$ 1.016
+						</div>
+					</div>
+					<div class="text-xs text-slate-500 dark:text-slate-400">
+						↑ +3 clientes entraram em risco crítico desde ontem
+					</div>
+				</div>
+			</div>
+
+			<!-- SLA Status -->
+			<div
+				class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+			>
+				<div class="mb-4 flex items-center gap-2">
+					<div
+						class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-emerald-50 text-emerald-600 dark:bg-emerald-400/10 dark:text-emerald-400"
+					>
+						<ShieldCheck size={18} strokeWidth={2} />
+					</div>
+					<h2 class="text-base font-bold text-slate-900 dark:text-white">SLA Status</h2>
+				</div>
+				<div class="space-y-4">
+					<div class="flex items-end gap-6">
+						<div>
+							<div class="text-3xl font-bold text-emerald-600 dark:text-emerald-400">
+								{slaWithinPct}%
+							</div>
+							<div class="text-xs text-slate-500 dark:text-slate-400">dentro do SLA</div>
+						</div>
+						<div>
+							<div class="text-2xl font-bold text-red-600 dark:text-red-400">{slaBreachPct}%</div>
+							<div class="text-xs text-slate-500 dark:text-slate-400">estourado</div>
+						</div>
+					</div>
+					<div class="h-3 w-full overflow-hidden rounded-full bg-red-100 dark:bg-red-400/20">
+						<div
+							class="h-full rounded-full bg-emerald-500 transition-all"
+							style="width: {slaWithinPct}%"
+						></div>
+					</div>
+					<div class="grid grid-cols-3 gap-2 text-center">
+						<div class="rounded-lg bg-emerald-50 p-2.5 dark:bg-emerald-400/10">
+							<div class="text-xs font-bold text-emerald-700 dark:text-emerald-400">SAC</div>
+							<div class="text-sm font-semibold text-slate-900 dark:text-white">72%</div>
+						</div>
+						<div class="rounded-lg bg-amber-50 p-2.5 dark:bg-amber-400/10">
+							<div class="text-xs font-bold text-amber-700 dark:text-amber-400">Vendas</div>
+							<div class="text-sm font-semibold text-slate-900 dark:text-white">85%</div>
+						</div>
+						<div class="rounded-lg bg-emerald-50 p-2.5 dark:bg-emerald-400/10">
+							<div class="text-xs font-bold text-emerald-700 dark:text-emerald-400">Suporte</div>
+							<div class="text-sm font-semibold text-slate-900 dark:text-white">91%</div>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	{/if}
+
+	<!-- Section 3: Sentiment Summary -->
+	{#if isLoading}
+		<div
+			class="h-56 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
+		></div>
+	{:else}
+		<div
+			class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<div class="mb-5 flex items-center gap-2">
+				<div
+					class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-indigo-50 text-indigo-600 dark:bg-indigo-400/10 dark:text-indigo-400"
+				>
+					<Activity size={18} strokeWidth={2} />
+				</div>
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">Emoção Geral da Base</h2>
+			</div>
+
+			<!-- Stacked bar with hover tooltip -->
+			<div class="relative mb-2 pt-10">
+				{#if hoveredEmotion}
+					<div
+						class="pointer-events-none absolute top-0 left-0 right-0 flex justify-center"
+					>
+						<div
+							class="rounded-lg border border-slate-200 bg-white px-3 py-2 shadow-lg dark:border-slate-700 dark:bg-[#0f172a]"
+						>
+							<span class="text-sm font-semibold text-slate-900 dark:text-white"
+								>{hoveredEmotion.label}</span
+							>
+							<span class="ml-2 text-xs text-slate-500 dark:text-slate-400">
+								{hoveredEmotion.count.toLocaleString('pt-BR')} interações · {hoveredEmotion.value}%
+							</span>
+						</div>
+					</div>
+				{/if}
+				<div class="flex h-10 w-full overflow-hidden rounded-lg">
+					{#each emotionData as emotion}
+						<button
+							type="button"
+							class="relative h-full cursor-default transition-opacity hover:opacity-85"
+							style="width: {emotion.value}%; background-color: {emotion.color}"
+							onmouseenter={() => (hoveredEmotion = emotion)}
+							onmouseleave={() => (hoveredEmotion = null)}
+							aria-label="{emotion.label}: {emotion.value}%"
+						>
+							{#if emotion.value >= 10}
+								<span
+									class="absolute inset-0 flex items-center justify-center text-xs font-bold text-white drop-shadow-sm"
+									>{emotion.value}%</span
+								>
+							{/if}
+						</button>
+					{/each}
+				</div>
+			</div>
+
+			<!-- Legend -->
+			<div class="mb-6 mt-3 flex flex-wrap gap-4">
+				{#each emotionData as emotion}
+					<div class="flex items-center gap-1.5 text-xs">
+						<span
+							class="inline-block h-2.5 w-2.5 shrink-0 rounded-full"
+							style="background-color: {emotion.color}"
+						></span>
+						<span class="text-slate-700 dark:text-slate-300"
+							>{emotion.label} <span class="font-semibold">{emotion.value}%</span></span
+						>
+					</div>
+				{/each}
+			</div>
+
+			<!-- Sentiment score scale -->
+			<div class="space-y-2">
+				<div class="flex items-center justify-between text-xs">
+					<span class="font-medium text-slate-600 dark:text-slate-400">Score médio de sentimento</span>
+					<span class="font-bold text-emerald-600 dark:text-emerald-400">
+						+{avgSentimentScore} — Positivo ↑
+					</span>
+				</div>
+				<div
+					class="relative h-4 w-full overflow-visible rounded-full"
+					style="background: linear-gradient(to right, #ef4444 0%, #f59e0b 35%, #10b981 100%)"
+				>
+					<div
+						class="absolute top-1/2 h-5 w-5 -translate-y-1/2 -translate-x-1/2 rounded-full border-2 border-white bg-white shadow-md dark:border-slate-900 dark:bg-slate-900"
+						style="left: {scorePosition}%"
+					>
+						<div
+							class="absolute inset-0.5 rounded-full"
+							style="background-color: #10b981"
+						></div>
+					</div>
+				</div>
+				<div class="flex justify-between text-[10px] text-slate-500 dark:text-slate-400">
+					<span>−1 Muito Negativo</span>
+					<span>0 Neutro</span>
+					<span>+1 Muito Positivo</span>
+				</div>
+			</div>
+		</div>
+	{/if}
+
+	<!-- Section 4: Quick Access -->
+	{#if !isLoading}
+		<div
+			class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<h2 class="mb-4 text-base font-bold text-slate-900 dark:text-white">Acesso Rápido</h2>
+			<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-6">
+				{#each quickAccessItems as item}
+					{@const Icon = item.icon}
+					<a
+						href={item.href}
+						class="group flex flex-col items-center gap-3 rounded-xl border p-4 text-center transition-all hover:border-indigo-200 hover:shadow-sm dark:hover:border-indigo-500/30 {item.border}"
+					>
+						<div
+							class="flex h-12 w-12 items-center justify-center rounded-xl {item.bg} {item.color} transition-transform duration-150 group-hover:scale-105"
+						>
+							<Icon size={22} strokeWidth={2} />
+						</div>
+						<div>
+							<div class="text-sm font-semibold text-slate-900 dark:text-white">{item.label}</div>
+							<div class="mt-0.5 text-xs text-slate-500 dark:text-slate-400">{item.metric}</div>
+							<div class="mt-0.5 text-xs font-medium {item.trendColor}">{item.trend}</div>
+						</div>
+					</a>
+				{/each}
+			</div>
+		</div>
+	{/if}
+</div>

+ 146 - 0
src/routes/(app)/dashboard/help/+page.svelte

@@ -0,0 +1,146 @@
+<script>
+	import { HelpCircle, MessageCircle, Mail, Book, Globe, FileText, MoreHorizontal, ChevronDown } from 'lucide-svelte';
+	let expandedFaq = null;
+
+	const supportChannels = [
+		{
+			title: 'Central de Ajuda',
+			description: 'Acesse nossa base de conhecimento com artigos e tutoriais',
+			icon: Book,
+			action: 'Acessar',
+			link: '#'
+		},
+		{
+			title: 'E-mail de Suporte',
+			description: 'Envie suas dúvidas para nossa equipe de suporte',
+			icon: Mail,
+			action: 'Enviar',
+			link: 'mailto:support@nettown.com'
+		},
+		{
+			title: 'Chat ao Vivo',
+			description: 'Converse com nossa equipe em tempo real',
+			icon: MessageCircle,
+			action: 'Iniciar Chat',
+			link: '#'
+		},
+		{
+			title: 'Documentação',
+			description: 'Leia a documentação técnica e guias de integração',
+			icon: FileText,
+			action: 'Ler Docs',
+			link: '#'
+		}
+	];
+
+	const faqs = [
+		{
+			question: 'Como funciona a análise de sentimento?',
+			answer: 'Nossa análise de sentimento utiliza inteligência artificial para avaliar o tom e a emoção em conversas. O sistema analisa mensagens de texto e categoriza o sentimento em positivo, negativo ou neutro.'
+		},
+		{
+			question: 'Quais plataformas são suportadas?',
+			answer: 'Atualmente suportamos integração com WhatsApp Business. Estamos trabalhando em suporte para outras plataformas como Messenger, Telegram e SMS.'
+		},
+		{
+			question: 'Como faço para integrar minha conta do WhatsApp?',
+			answer: 'Você pode integrar sua conta do WhatsApp Business através das configurações de integrações. Será necessário ter um número de telefone comercial e acesso à sua conta do Meta Business.'
+		},
+		{
+			question: 'Posso exportar meus dados?',
+			answer: 'Sim! Você pode exportar seus dados em formato CSV ou Excel a qualquer momento. Esta opção está disponível nas configurações de conta.'
+		},
+		{
+			question: 'Qual é o tempo de resposta do suporte?',
+			answer: 'Nosso tempo médio de resposta é de 24 horas para suporte por email. Se você tem um plano Profissional ou Empresa, oferecemos suporte prioritário com tempo de resposta de até 4 horas.'
+		},
+		{
+			question: 'Como posso cancelar minha assinatura?',
+			answer: 'Você pode cancelar sua assinatura a qualquer momento através da seção de Assinatura em seu perfil. Seu acesso será mantido até o final do ciclo de faturamento atual.'
+		}
+	];
+
+	function toggleFaq(index) {
+		expandedFaq = expandedFaq === index ? null : index;
+	}
+</script>
+
+<div class="mx-auto max-w-4xl space-y-6">
+	<!-- Header -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="flex items-center gap-3">
+			<div class="h-8 w-8 shrink-0 rounded-lg bg-indigo-500/20 text-indigo-500 flex items-center justify-center">
+				<HelpCircle size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Ajuda e Suporte</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Encontre respostas para suas dúvidas e entre em contato com nosso suporte
+		</p>
+	</div>
+
+	<!-- Support Channels -->
+	<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
+		{#each supportChannels as channel}
+			{@const Icon = channel.icon}
+			<a
+				href={channel.link}
+				class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-all duration-200 dark:border-slate-800 dark:bg-[#161f30] hover:border-indigo-400 dark:hover:border-indigo-500 hover:shadow-md"
+			>
+				<div class="flex items-start justify-between mb-3">
+					<div class="h-10 w-10 rounded-lg bg-indigo-500/10 text-indigo-600 flex items-center justify-center dark:bg-indigo-900/30 dark:text-indigo-400">
+						<Icon size={20} strokeWidth={2} />
+					</div>
+					<button class="p-1 text-slate-400 hover:text-slate-600 dark:hover:text-slate-300">
+						<MoreHorizontal size={16} />
+					</button>
+				</div>
+				<h3 class="font-semibold text-slate-900 dark:text-white mb-1">{channel.title}</h3>
+				<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">{channel.description}</p>
+				<button class="text-sm font-medium text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300">
+					{channel.action} →
+				</button>
+			</a>
+		{/each}
+	</div>
+
+	<!-- FAQ Section -->
+	<div class="space-y-4">
+		<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Perguntas Frequentes</h2>
+
+		<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30] divide-y divide-slate-200 dark:divide-slate-800">
+			{#each faqs as faq, index}
+				<div class="p-5 hover:bg-slate-50 transition-colors duration-150 dark:hover:bg-slate-800/50">
+					<button
+						onclick={() => toggleFaq(index)}
+						class="w-full flex items-center justify-between"
+					>
+						<h3 class="text-sm font-medium text-slate-900 dark:text-white text-left">{faq.question}</h3>
+						<ChevronDown
+							size={18}
+							class="text-slate-400 shrink-0 transition-transform duration-200 {expandedFaq === index ? 'rotate-180' : ''}"
+						/>
+					</button>
+
+					{#if expandedFaq === index}
+						<p class="mt-3 text-sm text-slate-600 dark:text-slate-400 text-left">
+							{faq.answer}
+						</p>
+					{/if}
+				</div>
+			{/each}
+		</div>
+	</div>
+
+	<!-- Contact Info -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<h2 class="text-lg font-semibold text-slate-900 dark:text-white mb-4">Não encontrou o que procura?</h2>
+		<p class="text-slate-600 dark:text-slate-400 mb-4">
+			Entre em contato com nossa equipe de suporte através de qualquer um dos canais acima. Estamos aqui para ajudá-lo!
+		</p>
+		<div class="space-y-2 text-sm text-slate-600 dark:text-slate-400">
+			<p><strong class="text-slate-900 dark:text-white">E-mail:</strong> support@nettown.com</p>
+			<p><strong class="text-slate-900 dark:text-white">Horário de atendimento:</strong> Segunda à Sexta, 9:00 às 18:00</p>
+		</div>
+	</div>
+</div>

+ 509 - 294
src/routes/(app)/dashboard/interactions/+page.svelte

@@ -1,303 +1,518 @@
 <script>
-    import { Search, Download, Filter, Eye, X, MessageCircle } from 'lucide-svelte';
-    import { mockInteractions, mockChatLog } from '$lib/core/models/mock-data.js';
-
-    let searchQuery = $state('');
-    let selectedInteraction = $state(null);
-    let isChatModalOpen = $state(false);
-
-    // Filters state
-    let activeFilter = $state('all'); // all, my_clients, new, unfinished
-
-    const filteredInteractions = $derived(
-        mockInteractions.filter(interaction => {
-            if (searchQuery && !interaction.client.includes(searchQuery)) return false;
-            return true;
-        })
-    );
-
-    function getSentimentColor(sentiment) {
-        switch (sentiment) {
-            case 'CONTENTAMENTO': return 'text-emerald-600 bg-emerald-50 border-emerald-200 dark:text-emerald-400 dark:bg-emerald-400/10 dark:border-emerald-400/20';
-            case 'FRUSTRAÇÃO': return 'text-red-600 bg-red-50 border-red-200 dark:text-red-400 dark:bg-red-400/10 dark:border-red-400/20';
-            case 'NEUTRO': return 'text-slate-600 bg-slate-100 border-slate-200 dark:text-slate-400 dark:bg-slate-400/10 dark:border-slate-400/20';
-            default: return 'text-slate-600 bg-slate-100 border-slate-200 dark:text-slate-400 dark:bg-slate-800 dark:border-slate-700';
-        }
-    }
-
-    function openChat(interaction) {
-        selectedInteraction = interaction;
-        isChatModalOpen = true;
-    }
-
-    function closeChat() {
-        isChatModalOpen = false;
-        setTimeout(() => {
-            selectedInteraction = null;
-        }, 300);
-    }
+	import { Search, Download, Eye, X, MessageCircle } from 'lucide-svelte';
+	import { mockInteractions } from '$lib/core/models/mock-data.js';
+
+	let searchQuery = $state('');
+	let selectedInteraction = $state(null);
+	let isChatModalOpen = $state(false);
+
+	// Filters state
+	let activeFilter = $state('all'); // all, my_clients, new, unfinished
+
+	const conversationTemplates = [
+		[
+			{
+				isAgent: false,
+				text: 'Oi, queria saber se esse look chega na loja física ou é só on-line?'
+			},
+			{
+				isAgent: true,
+				text: 'Oi {client}! Aqui é {agent}. Posso te mandar combinações com o que chegou hoje?'
+			},
+			{
+				isAgent: false,
+				text: 'Quero sim! Tive dúvida porque o tecido parece quente, o que você acha?'
+			},
+			{
+				isAgent: true,
+				text: 'Ele é leve, perfeito para eventos. Posso reservar dois tamanhos pra você testar?'
+			}
+		],
+		[
+			{
+				isAgent: false,
+				text: 'Boa tarde! O prazo de entrega está mantido? Preciso para um evento.'
+			},
+			{
+				isAgent: true,
+				text: 'Está sim! Consigo acompanhar junto com a logística e te aviso qualquer mudança.'
+			},
+			{
+				isAgent: false,
+				text: 'Perfeito, fiquei tranquila. Pode confirmar se a cor é igual da foto?'
+			},
+			{
+				isAgent: true,
+				text: 'É idêntica! Vou te mandar mais fotos com detalhes da costura.'
+			}
+		],
+		[
+			{
+				isAgent: false,
+				text: 'Oi, recebi o link mas não consegui finalizar o pagamento.'
+			},
+			{
+				isAgent: true,
+				text: 'Sem problemas, {client}. Gereiem um novo link com cashback extra, vale tentar novamente?'
+			},
+			{
+				isAgent: false,
+				text: 'Agora foi! Consegue separar junto com uma calça flare 38?'
+			},
+			{
+				isAgent: true,
+				text: 'Já separei e mando atualizações de retirada. Obrigada por confiar!'
+			}
+		]
+	];
+
+	function applyFilter(interaction) {
+		const normalizedQuery = searchQuery.trim();
+		if (normalizedQuery && !interaction.client.includes(normalizedQuery)) return false;
+
+		if (activeFilter === 'my_clients') {
+			return interaction.agent !== '-';
+		}
+
+		if (activeFilter === 'new') {
+			return interaction.sentiment === 'CONTENTAMENTO' || interaction.score > 0.4;
+		}
+
+		if (activeFilter === 'unfinished') {
+			return interaction.sentiment === 'FRUSTRAÇÃO' || interaction.score < 0;
+		}
+
+		return true;
+	}
+
+	const filteredInteractions = $derived(mockInteractions.filter(applyFilter));
+
+	function buildConversation(interaction, idx) {
+		const template = conversationTemplates[idx % conversationTemplates.length];
+		const agentName = interaction.agent === '-' ? 'Time Nettown' : interaction.agent;
+		return template.map((message, msgIdx) => ({
+			...message,
+			id: `${interaction.client}-${msgIdx}`,
+			text: message.text
+				.replace('{client}', interaction.client.slice(-4))
+				.replace('{agent}', agentName),
+			time: interaction.datetime.split(',')[1]?.trim() ?? '00:00'
+		}));
+	}
+
+	const conversationThreads = $derived(
+		filteredInteractions.map((interaction, idx) => ({
+			...interaction,
+			thread: buildConversation(interaction, idx)
+		}))
+	);
+
+	function getSentimentColor(sentiment) {
+		switch (sentiment) {
+			case 'CONTENTAMENTO':
+				return 'text-emerald-600 bg-emerald-50 border-emerald-200 dark:text-emerald-400 dark:bg-emerald-400/10 dark:border-emerald-400/20';
+			case 'FRUSTRAÇÃO':
+				return 'text-red-600 bg-red-50 border-red-200 dark:text-red-400 dark:bg-red-400/10 dark:border-red-400/20';
+			case 'NEUTRO':
+				return 'text-slate-600 bg-slate-100 border-slate-200 dark:text-slate-400 dark:bg-slate-400/10 dark:border-slate-400/20';
+			default:
+				return 'text-slate-600 bg-slate-100 border-slate-200 dark:text-slate-400 dark:bg-slate-800 dark:border-slate-700';
+		}
+	}
+
+	function openChat(interaction) {
+		selectedInteraction = interaction;
+		isChatModalOpen = true;
+	}
+
+	function closeChat() {
+		isChatModalOpen = false;
+		setTimeout(() => {
+			selectedInteraction = null;
+		}, 300);
+	}
 </script>
 
 <svelte:head>
-    <title>Interações Analisadas - Nettown Analytics</title>
+	<title>Interações Analisadas - Nettown Analytics</title>
 </svelte:head>
 
-<div class="space-y-6 max-w-[1600px] mx-auto transition-colors duration-200">
-    <!-- Header/Filters -->
-    <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-8">
-        <h1 class="text-2xl font-bold text-slate-900 dark:text-white transition-colors">Últimas Interações Analisadas</h1>
-        
-        <div class="flex flex-wrap items-center gap-3">
-            <button 
-                class="px-4 py-2 rounded-lg text-sm font-medium transition-colors border {activeFilter === 'my_clients' ? 'bg-indigo-50 dark:bg-indigo-500/20 text-indigo-700 dark:text-indigo-400 border-indigo-200 dark:border-indigo-500/30 shadow-inner' : 'bg-white dark:bg-[#1e293b] text-slate-700 dark:text-slate-300 border-slate-200 dark:border-slate-700 hover:border-slate-300 dark:hover:border-slate-500 shadow-sm dark:shadow-none'}"
-                onclick={() => activeFilter = activeFilter === 'my_clients' ? 'all' : 'my_clients'}
-            >
-                Meus Clientes
-            </button>
-            <button 
-                class="px-4 py-2 rounded-lg text-sm font-medium transition-colors border {activeFilter === 'new' ? 'bg-emerald-50 dark:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400 border-emerald-200 dark:border-emerald-500/30 shadow-inner' : 'bg-white dark:bg-[#1e293b] text-slate-700 dark:text-slate-300 border-slate-200 dark:border-slate-700 hover:border-slate-300 dark:hover:border-slate-500 shadow-sm dark:shadow-none'}"
-                onclick={() => activeFilter = activeFilter === 'new' ? 'all' : 'new'}
-            >
-                Relatório Pessoas Novas
-            </button>
-            <button 
-                class="px-4 py-2 rounded-lg text-sm font-medium transition-colors border {activeFilter === 'unfinished' ? 'bg-amber-50 dark:bg-amber-500/20 text-amber-700 dark:text-amber-400 border-amber-200 dark:border-amber-500/30 shadow-inner' : 'bg-white dark:bg-[#1e293b] text-slate-700 dark:text-slate-300 border-slate-200 dark:border-slate-700 hover:border-slate-300 dark:hover:border-slate-500 shadow-sm dark:shadow-none'}"
-                onclick={() => activeFilter = activeFilter === 'unfinished' ? 'all' : 'unfinished'}
-            >
-                Conversas Inacabadas
-            </button>
-            
-            <button class="flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-600 dark:hover:bg-indigo-500 text-white transition-colors shadow-sm dark:shadow-none ml-auto sm:ml-0">
+<div class="mx-auto max-w-[1600px] space-y-6 transition-colors duration-200">
+	<!-- Header/Filters -->
+	<div class="mb-8 flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center">
+		<h1 class="text-2xl font-bold text-slate-900 transition-colors dark:text-white">
+			Últimas Interações Analisadas
+		</h1>
+
+		<div class="flex flex-wrap items-center gap-3">
+			<button
+				class="rounded-lg border px-4 py-2 text-sm font-medium transition-colors {activeFilter ===
+				'my_clients'
+					? 'border-indigo-200 bg-indigo-50 text-indigo-700 shadow-inner dark:border-indigo-500/30 dark:bg-indigo-500/20 dark:text-indigo-400'
+					: 'border-slate-200 bg-white text-slate-700 shadow-sm hover:border-slate-300 dark:border-slate-700 dark:bg-[#1e293b] dark:text-slate-300 dark:shadow-none dark:hover:border-slate-500'}"
+				onclick={() => (activeFilter = activeFilter === 'my_clients' ? 'all' : 'my_clients')}
+			>
+				Meus Clientes
+			</button>
+			<button
+				class="rounded-lg border px-4 py-2 text-sm font-medium transition-colors {activeFilter ===
+				'new'
+					? 'border-emerald-200 bg-emerald-50 text-emerald-700 shadow-inner dark:border-emerald-500/30 dark:bg-emerald-500/20 dark:text-emerald-400'
+					: 'border-slate-200 bg-white text-slate-700 shadow-sm hover:border-slate-300 dark:border-slate-700 dark:bg-[#1e293b] dark:text-slate-300 dark:shadow-none dark:hover:border-slate-500'}"
+				onclick={() => (activeFilter = activeFilter === 'new' ? 'all' : 'new')}
+			>
+				Relatório Pessoas Novas
+			</button>
+			<button
+				class="rounded-lg border px-4 py-2 text-sm font-medium transition-colors {activeFilter ===
+				'unfinished'
+					? 'border-amber-200 bg-amber-50 text-amber-700 shadow-inner dark:border-amber-500/30 dark:bg-amber-500/20 dark:text-amber-400'
+					: 'border-slate-200 bg-white text-slate-700 shadow-sm hover:border-slate-300 dark:border-slate-700 dark:bg-[#1e293b] dark:text-slate-300 dark:shadow-none dark:hover:border-slate-500'}"
+				onclick={() => (activeFilter = activeFilter === 'unfinished' ? 'all' : 'unfinished')}
+			>
+				Conversas Inacabadas
+			</button>
+
+			<!-- <button class="flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-600 dark:hover:bg-indigo-500 text-white transition-colors shadow-sm dark:shadow-none ml-auto sm:ml-0">
                 <Download size={16} />
                 Download
-            </button>
-        </div>
-    </div>
-
-    <!-- Table Container -->
-    <div class="bg-white dark:bg-[#1e293b] rounded-xl border border-slate-200 dark:border-slate-800 shadow-sm overflow-hidden flex flex-col transition-colors duration-200">
-        <!-- Table Toolbar -->
-        <div class="p-4 border-b border-slate-200 dark:border-slate-800 flex justify-between items-center bg-slate-50 dark:bg-[#1e293b] transition-colors duration-200">
-            <div class="relative">
-                <Search size={16} class="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 dark:text-slate-500" />
-                <input 
-                    type="text" 
-                    bind:value={searchQuery}
-                    placeholder="Buscar cliente..." 
-                    class="w-64 pl-9 pr-4 py-2 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all shadow-sm dark:shadow-none"
-                />
-            </div>
-            <div class="text-sm text-slate-500 dark:text-slate-400 font-medium">
-                Exibindo 0 - {filteredInteractions.length} (Página 1)
-            </div>
-        </div>
-
-        <!-- Table -->
-        <div class="overflow-x-auto custom-scrollbar">
-            <table class="w-full text-left border-collapse">
-                <thead>
-                    <tr class="bg-slate-100/50 dark:bg-slate-900/50 text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wider border-b border-slate-200 dark:border-slate-800 transition-colors duration-200">
-                        <th class="p-4">Cliente</th>
-                        <th class="p-4">Agente</th>
-                        <th class="p-4">Sentimento Geral</th>
-                        <th class="p-4">Score</th>
-                        <th class="p-4">Aspectos Detectados</th>
-                        <th class="p-4">Subaspectos Detectados</th>
-                        <th class="p-4">Data e Hora</th>
-                        <th class="p-4 text-right">Análise Avançada</th>
-                    </tr>
-                </thead>
-                <tbody class="divide-y divide-slate-100 dark:divide-slate-800/50 transition-colors duration-200">
-                    {#each filteredInteractions as item}
-                        <tr class="hover:bg-slate-50 dark:hover:bg-slate-800/30 transition-colors group">
-                            <td class="p-4">
-                                <span class="font-bold text-slate-900 dark:text-white">{item.client}</span>
-                            </td>
-                            <td class="p-4 text-slate-600 dark:text-slate-300 font-medium">{item.agent}</td>
-                            <td class="p-4">
-                                <span class="px-2.5 py-1 rounded-md text-xs font-bold border {getSentimentColor(item.sentiment)} transition-colors duration-200">
-                                    {item.sentiment}
-                                </span>
-                            </td>
-                            <td class="p-4 text-slate-700 dark:text-slate-300 font-bold">{item.score}</td>
-                            <td class="p-4 text-slate-600 dark:text-slate-300 font-medium">{item.aspect}</td>
-                            <td class="p-4 text-slate-500 dark:text-slate-400">{item.subaspect}</td>
-                            <td class="p-4 text-slate-500 dark:text-slate-400 text-sm font-medium">{item.datetime}</td>
-                            <td class="p-4 text-right">
-                                <button 
-                                    onclick={() => openChat(item)}
-                                    class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-indigo-50 hover:bg-indigo-100 dark:bg-indigo-500/10 dark:hover:bg-indigo-500/20 text-indigo-600 dark:text-indigo-400 border border-indigo-200 dark:border-indigo-500/20 rounded-md text-sm font-semibold transition-colors shadow-sm dark:shadow-none"
-                                >
-                                    <Eye size={14} />
-                                    Ver Chat
-                                </button>
-                            </td>
-                        </tr>
-                    {/each}
-                    
-                    {#if filteredInteractions.length === 0}
-                        <tr>
-                            <td colspan="8" class="p-8 text-center text-slate-500 font-medium">
-                                Nenhuma interação encontrada.
-                            </td>
-                        </tr>
-                    {/if}
-                </tbody>
-            </table>
-        </div>
-        
-        <!-- Pagination -->
-        <div class="p-4 border-t border-slate-200 dark:border-slate-800 bg-slate-50 dark:bg-[#1e293b] flex items-center justify-center gap-4 transition-colors duration-200">
-            <button class="text-sm font-medium text-slate-400 dark:text-slate-500 hover:text-slate-600 dark:hover:text-slate-300 disabled:opacity-50" disabled>Anterior</button>
-            <span class="text-sm font-bold text-slate-900 dark:text-white">Página 1</span>
-            <button class="text-sm font-medium text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300">Próxima</button>
-        </div>
-    </div>
-</div>
+            </button> -->
+		</div>
+	</div>
+
+	<!-- Table Container -->
+	<div
+		class="flex flex-col overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
+		<div
+			class="flex flex-col gap-3 border-b border-slate-200 bg-slate-50 p-4 sm:flex-row sm:items-center sm:justify-between dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<div class="relative">
+				<Search
+					size={16}
+					class="absolute top-1/2 left-3 -translate-y-1/2 text-slate-400 dark:text-slate-500"
+				/>
+				<input
+					type="text"
+					bind:value={searchQuery}
+					placeholder="Buscar cliente..."
+					class="w-64 rounded-lg border border-slate-300 bg-white py-2 pr-4 pl-9 text-sm text-slate-900 placeholder-slate-400 shadow-sm transition-all focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:placeholder-slate-500 dark:shadow-none"
+				/>
+			</div>
+			<div class="text-sm font-medium text-slate-500 dark:text-slate-400">
+				Exibindo {conversationThreads.length} conversas
+			</div>
+		</div>
+
+		<div class="custom-scrollbar overflow-x-auto">
+			<table class="w-full border-collapse text-left">
+				<thead>
+					<tr
+						class="border-b border-slate-200 bg-slate-100/50 text-xs font-semibold tracking-wider text-slate-500 uppercase transition-colors duration-200 dark:border-slate-800 dark:bg-slate-900/50 dark:text-slate-400"
+					>
+						<th class="p-4">Cliente</th>
+						<th class="p-4">Agente</th>
+						<th class="p-4">Sentimento Geral</th>
+						<th class="p-4">Score</th>
+						<th class="p-4">Aspectos Detectados</th>
+						<th class="p-4">Subaspectos Detectados</th>
+						<th class="p-4">Data e Hora</th>
+						<th class="p-4 text-right">Análise Avançada</th>
+					</tr>
+				</thead>
+				<tbody
+					class="divide-y divide-slate-100 transition-colors duration-200 dark:divide-slate-800/50"
+				>
+					{#each conversationThreads as item}
+						<tr class="group transition-colors hover:bg-slate-50 dark:hover:bg-slate-800/30">
+							<td class="p-4">
+								<span class="font-bold text-slate-900 dark:text-white">{item.client}</span>
+							</td>
+							<td class="p-4 font-medium text-slate-600 dark:text-slate-300"
+								>{item.agent === '-' ? 'Time Nettown' : item.agent}</td
+							>
+							<td class="p-4">
+								<span
+									class="rounded-md border px-2.5 py-1 text-xs font-bold {getSentimentColor(
+										item.sentiment
+									)} transition-colors duration-200"
+								>
+									{item.sentiment}
+								</span>
+							</td>
+							<td class="p-4 font-bold text-slate-700 dark:text-slate-300">{item.score}</td>
+							<td class="p-4 font-medium text-slate-600 dark:text-slate-300">{item.aspect}</td>
+							<td class="p-4 text-slate-500 dark:text-slate-400">{item.subaspect}</td>
+							<td class="p-4 text-sm font-medium text-slate-500 dark:text-slate-400"
+								>{item.datetime}</td
+							>
+							<td class="p-4 text-right">
+								<button
+									onclick={() => openChat(item)}
+									class="inline-flex items-center gap-1.5 rounded-md border border-indigo-200 bg-indigo-50 px-3 py-1.5 text-sm font-semibold text-indigo-600 shadow-sm transition-colors hover:bg-indigo-100 dark:border-indigo-500/20 dark:bg-indigo-500/10 dark:text-indigo-400 dark:shadow-none dark:hover:bg-indigo-500/20"
+								>
+									<Eye size={14} />
+									Ver Chat
+								</button>
+							</td>
+						</tr>
+					{/each}
+
+					{#if conversationThreads.length === 0}
+						<tr>
+							<td colspan="8" class="p-8 text-center font-medium text-slate-500">
+								Nenhuma interação encontrada.
+							</td>
+						</tr>
+					{/if}
+				</tbody>
+			</table>
+		</div>
+
+		<div
+			class="flex items-center justify-center gap-4 border-t border-slate-200 bg-slate-50 p-4 transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<button
+				class="text-sm font-medium text-slate-400 hover:text-slate-600 disabled:opacity-50 dark:text-slate-500 dark:hover:text-slate-300"
+				disabled>Anterior</button
+			>
+			<span class="text-sm font-bold text-slate-900 dark:text-white">Página 1</span>
+			<button
+				class="text-sm font-medium text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300"
+				>Próxima</button
+			>
+		</div>
+	</div>
+
+	<!-- Chat Modal -->
+	{#if isChatModalOpen}
+		<div
+			class="fixed inset-0 z-[100] flex items-center justify-center p-4 transition-colors duration-200 sm:p-6"
+			role="dialog"
+			aria-modal="true"
+		>
+			<!-- Backdrop -->
+			<div
+				class="absolute inset-0 bg-slate-900/60 backdrop-blur-sm transition-opacity dark:bg-slate-950/80"
+				onclick={closeChat}
+				onkeydown={(e) => e.key === 'Escape' && closeChat()}
+				tabindex="0"
+				role="button"
+				aria-label="Close modal"
+			></div>
+
+			<!-- Modal Content -->
+			<div
+				class="animate-in fade-in zoom-in-95 relative flex max-h-[90vh] w-full max-w-6xl flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-2xl duration-200 md:flex-row dark:border-slate-800 dark:bg-[#0f172a]"
+			>
+				<!-- Chat Area -->
+				<div
+					class="flex min-h-[50vh] flex-1 flex-col border-r border-slate-200 bg-slate-50 transition-colors duration-200 md:min-h-[600px] dark:border-slate-800 dark:bg-[#0b1120]"
+				>
+					<!-- Chat Header -->
+					<div
+						class="flex h-16 items-center justify-between border-b border-slate-200 bg-white px-6 transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+					>
+						<div class="flex items-center gap-3">
+							<div
+								class="flex h-10 w-10 items-center justify-center rounded-full bg-slate-100 text-slate-500 dark:bg-slate-800 dark:text-slate-400"
+							>
+								<MessageCircle size={20} />
+							</div>
+							<div>
+								<div class="font-bold text-slate-900 dark:text-white">
+									{selectedInteraction?.client}
+								</div>
+								<div class="text-xs font-medium text-slate-500 dark:text-slate-400">WhatsApp</div>
+							</div>
+						</div>
+						<button
+							onclick={closeChat}
+							class="rounded-lg p-2 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 md:hidden dark:hover:bg-slate-800 dark:hover:text-white"
+						>
+							<X size={20} />
+						</button>
+					</div>
+
+					<!-- Chat Messages -->
+					<div class="custom-scrollbar flex-1 space-y-6 overflow-y-auto p-6">
+						<div class="flex justify-center">
+							<span
+								class="rounded-full border border-slate-200 bg-white px-3 py-1 text-xs font-bold text-slate-500 shadow-sm dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:shadow-none"
+							>
+								ONTEM
+							</span>
+						</div>
 
-<!-- Chat Modal -->
-{#if isChatModalOpen}
-    <div class="fixed inset-0 z-[100] flex items-center justify-center p-4 sm:p-6 transition-colors duration-200" role="dialog" aria-modal="true">
-        <!-- Backdrop -->
-        <div 
-            class="absolute inset-0 bg-slate-900/60 dark:bg-slate-950/80 backdrop-blur-sm transition-opacity" 
-            onclick={closeChat}
-            onkeydown={(e) => e.key === 'Escape' && closeChat()}
-            tabindex="0"
-            role="button"
-            aria-label="Close modal"
-        ></div>
-        
-        <!-- Modal Content -->
-        <div class="relative bg-white dark:bg-[#0f172a] rounded-2xl border border-slate-200 dark:border-slate-800 shadow-2xl w-full max-w-6xl max-h-[90vh] flex flex-col md:flex-row overflow-hidden animate-in fade-in zoom-in-95 duration-200">
-            
-            <!-- Chat Area -->
-            <div class="flex-1 flex flex-col border-r border-slate-200 dark:border-slate-800 bg-slate-50 dark:bg-[#0b1120] min-h-[50vh] md:min-h-[600px] transition-colors duration-200">
-                <!-- Chat Header -->
-                <div class="h-16 px-6 border-b border-slate-200 dark:border-slate-800 flex items-center justify-between bg-white dark:bg-[#1e293b] transition-colors duration-200">
-                    <div class="flex items-center gap-3">
-                        <div class="w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-800 flex items-center justify-center text-slate-500 dark:text-slate-400">
-                            <MessageCircle size={20} />
-                        </div>
-                        <div>
-                            <div class="font-bold text-slate-900 dark:text-white">{selectedInteraction?.client}</div>
-                            <div class="text-xs font-medium text-slate-500 dark:text-slate-400">WhatsApp</div>
-                        </div>
-                    </div>
-                    <button 
-                        onclick={closeChat}
-                        class="md:hidden p-2 text-slate-400 hover:text-slate-700 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
-                    >
-                        <X size={20} />
-                    </button>
-                </div>
-                
-                <!-- Chat Messages -->
-                <div class="flex-1 overflow-y-auto p-6 space-y-6 custom-scrollbar">
-                    <div class="flex justify-center">
-                        <span class="px-3 py-1 rounded-full bg-white dark:bg-slate-800 text-xs font-bold text-slate-500 dark:text-slate-400 border border-slate-200 dark:border-slate-700 shadow-sm dark:shadow-none">
-                            ONTEM
-                        </span>
-                    </div>
-                    
-                    {#each mockChatLog as msg}
-                        <div class="flex flex-col {msg.isAgent ? 'items-end' : 'items-start'}">
-                            <div class="max-w-[80%] {msg.isAgent ? 'bg-indigo-600 text-white rounded-2xl rounded-tr-sm shadow-md shadow-indigo-600/20' : 'bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-200 border border-slate-200 dark:border-transparent rounded-2xl rounded-tl-sm shadow-sm'} p-3.5">
-                                {#if msg.isAgent}
-                                    <div class="text-[10px] font-bold text-indigo-200 mb-1">Ativadora</div>
-                                {/if}
-                                <p class="text-sm leading-relaxed whitespace-pre-wrap">{msg.text}</p>
-                                <div class="text-[10px] text-right mt-1.5 {msg.isAgent ? 'opacity-70' : 'text-slate-400 font-medium'}">{msg.time}</div>
-                            </div>
-                        </div>
-                    {/each}
-                </div>
-            </div>
-            
-            <!-- Analysis Area -->
-            <div class="w-full md:w-[400px] flex flex-col bg-white dark:bg-[#1e293b] shrink-0 transition-colors duration-200">
-                <div class="h-16 px-6 border-b border-slate-200 dark:border-slate-800 flex items-center justify-between">
-                    <h2 class="font-bold text-slate-900 dark:text-white text-lg">Relatório</h2>
-                    <button 
-                        onclick={closeChat}
-                        class="hidden md:flex px-3 py-1.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-md text-sm font-bold transition-colors"
-                    >
-                        Fechar
-                    </button>
-                </div>
-                
-                <div class="flex-1 overflow-y-auto p-6 space-y-8 custom-scrollbar">
-                    <!-- Mini chart placeholder -->
-                    <div class="h-32 bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 relative p-4 flex items-end overflow-hidden shadow-inner">
-                        <!-- Decorative chart lines matching the UI -->
-                        <svg class="absolute inset-0 w-full h-full" preserveAspectRatio="none">
-                            <path d="M0,20 L40,100 L200,100 L300,100 L350,60" fill="none" stroke="#38bdf8" stroke-width="2" vector-effect="non-scaling-stroke" />
-                            <path d="M0,60 L40,100 L200,100 L300,100 L350,40" fill="none" stroke="#10b981" stroke-width="2" vector-effect="non-scaling-stroke" />
-                            <!-- Dots -->
-                            <circle cx="0" cy="20" r="3" fill="#38bdf8" />
-                            <circle cx="40" cy="100" r="3" fill="#38bdf8" />
-                            <circle cx="120" cy="100" r="3" fill="#38bdf8" />
-                            <circle cx="200" cy="100" r="3" fill="#38bdf8" />
-                            <circle cx="300" cy="100" r="3" fill="#38bdf8" />
-                            <circle cx="350" cy="60" r="3" fill="#38bdf8" />
-                        </svg>
-                        <div class="w-full flex justify-between text-[10px] font-medium text-slate-400 dark:text-slate-500 absolute bottom-2 left-0 px-4">
-                            <span>22:58</span>
-                            <span>23:00</span>
-                            <span>23:02</span>
-                            <span>23:04</span>
-                            <span>23:06</span>
-                        </div>
-                    </div>
-                    
-                    <div class="grid grid-cols-2 gap-y-6 gap-x-4">
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">MÉDIA RESPOSTA</div>
-                            <div class="text-lg font-extrabold text-slate-900 dark:text-white">04:03</div>
-                        </div>
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">DURAÇÃO TOTAL</div>
-                            <div class="text-lg font-extrabold text-slate-900 dark:text-white">08:28</div>
-                        </div>
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">MÉDIA AGENTE</div>
-                            <div class="text-lg font-extrabold text-slate-900 dark:text-white">00:00</div>
-                        </div>
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">MÉDIA CLIENTE</div>
-                            <div class="text-lg font-extrabold text-slate-900 dark:text-white">08:05</div>
-                        </div>
-                    </div>
-                    
-                    <div class="space-y-4">
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">ASPECTO PRINCIPAL</div>
-                            <div class="text-base font-semibold text-indigo-600 dark:text-indigo-400">{selectedInteraction?.aspect || 'Atendimento'}</div>
-                        </div>
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">SUBASPECTO</div>
-                            <div class="text-base font-semibold text-slate-700 dark:text-slate-200">{selectedInteraction?.subaspect || 'Informativo'}</div>
-                        </div>
-                    </div>
-                    
-                    <div class="grid grid-cols-2 gap-4 pt-4 border-t border-slate-200 dark:border-slate-800">
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">ÚLTIMA MENSAGEM</div>
-                            <div class="text-sm font-semibold text-slate-900 dark:text-white">Cliente</div>
-                        </div>
-                        <div>
-                            <div class="text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-1">CONSECUTIVAS</div>
-                            <div class="text-sm font-semibold text-slate-900 dark:text-white">Não</div>
-                        </div>
-                    </div>
-                    
-                    <div class="text-center pt-4">
-                        <button class="text-sm font-bold text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors">
-                            Detalhes Extraídos
-                        </button>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-{/if}
+						{#each selectedInteraction?.thread ?? [] as msg}
+							<div class="flex flex-col {msg.isAgent ? 'items-end' : 'items-start'}">
+								<div
+									class="max-w-[80%] {msg.isAgent
+										? 'rounded-2xl rounded-tr-sm bg-indigo-600 text-white shadow-md shadow-indigo-600/20'
+										: 'rounded-2xl rounded-tl-sm border border-slate-200 bg-white text-slate-700 shadow-sm dark:border-transparent dark:bg-slate-800 dark:text-slate-200'} p-3.5"
+								>
+									{#if msg.isAgent}
+										<div class="mb-1 text-[10px] font-bold text-indigo-200">Ativadora</div>
+									{/if}
+									<p class="text-sm leading-relaxed whitespace-pre-wrap">{msg.text}</p>
+									<div
+										class="mt-1.5 text-right text-[10px] {msg.isAgent
+											? 'opacity-70'
+											: 'font-medium text-slate-400'}"
+									>
+										{msg.time}
+									</div>
+								</div>
+							</div>
+						{/each}
+					</div>
+				</div>
+
+				<!-- Analysis Area -->
+				<div
+					class="flex w-full shrink-0 flex-col bg-white transition-colors duration-200 md:w-[400px] dark:bg-[#1e293b]"
+				>
+					<div
+						class="flex h-16 items-center justify-between border-b border-slate-200 px-6 dark:border-slate-800"
+					>
+						<h2 class="text-lg font-bold text-slate-900 dark:text-white">Relatório</h2>
+						<button
+							onclick={closeChat}
+							class="hidden rounded-md bg-slate-100 px-3 py-1.5 text-sm font-bold text-slate-700 transition-colors hover:bg-slate-200 md:flex dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-700"
+						>
+							Fechar
+						</button>
+					</div>
+
+					<div class="custom-scrollbar flex-1 space-y-8 overflow-y-auto p-6">
+						<!-- Mini chart placeholder -->
+						<div
+							class="relative flex h-32 items-end overflow-hidden rounded-lg border border-slate-200 bg-slate-50 p-4 shadow-inner dark:border-slate-800 dark:bg-slate-900"
+						>
+							<!-- Decorative chart lines matching the UI -->
+							<svg class="absolute inset-0 h-full w-full" preserveAspectRatio="none">
+								<path
+									d="M0,20 L40,100 L200,100 L300,100 L350,60"
+									fill="none"
+									stroke="#38bdf8"
+									stroke-width="2"
+									vector-effect="non-scaling-stroke"
+								/>
+								<path
+									d="M0,60 L40,100 L200,100 L300,100 L350,40"
+									fill="none"
+									stroke="#10b981"
+									stroke-width="2"
+									vector-effect="non-scaling-stroke"
+								/>
+								<!-- Dots -->
+								<circle cx="0" cy="20" r="3" fill="#38bdf8" />
+								<circle cx="40" cy="100" r="3" fill="#38bdf8" />
+								<circle cx="120" cy="100" r="3" fill="#38bdf8" />
+								<circle cx="200" cy="100" r="3" fill="#38bdf8" />
+								<circle cx="300" cy="100" r="3" fill="#38bdf8" />
+								<circle cx="350" cy="60" r="3" fill="#38bdf8" />
+							</svg>
+							<div
+								class="absolute bottom-2 left-0 flex w-full justify-between px-4 text-[10px] font-medium text-slate-400 dark:text-slate-500"
+							>
+								<span>22:58</span>
+								<span>23:00</span>
+								<span>23:02</span>
+								<span>23:04</span>
+								<span>23:06</span>
+							</div>
+						</div>
+
+						<div class="grid grid-cols-2 gap-x-4 gap-y-6">
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									MÉDIA RESPOSTA
+								</div>
+								<div class="text-lg font-extrabold text-slate-900 dark:text-white">04:03</div>
+							</div>
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									DURAÇÃO TOTAL
+								</div>
+								<div class="text-lg font-extrabold text-slate-900 dark:text-white">08:28</div>
+							</div>
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									MÉDIA AGENTE
+								</div>
+								<div class="text-lg font-extrabold text-slate-900 dark:text-white">00:00</div>
+							</div>
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									MÉDIA CLIENTE
+								</div>
+								<div class="text-lg font-extrabold text-slate-900 dark:text-white">08:05</div>
+							</div>
+						</div>
+
+						<div class="space-y-4">
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									ASPECTO PRINCIPAL
+								</div>
+								<div class="text-base font-semibold text-indigo-600 dark:text-indigo-400">
+									{selectedInteraction?.aspect || 'Atendimento'}
+								</div>
+							</div>
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									SUBASPECTO
+								</div>
+								<div class="text-base font-semibold text-slate-700 dark:text-slate-200">
+									{selectedInteraction?.subaspect || 'Informativo'}
+								</div>
+							</div>
+						</div>
+
+						<div
+							class="grid grid-cols-2 gap-4 border-t border-slate-200 pt-4 dark:border-slate-800"
+						>
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									ÚLTIMA MENSAGEM
+								</div>
+								<div class="text-sm font-semibold text-slate-900 dark:text-white">Cliente</div>
+							</div>
+							<div>
+								<div
+									class="mb-1 text-xs font-bold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+								>
+									CONSECUTIVAS
+								</div>
+								<div class="text-sm font-semibold text-slate-900 dark:text-white">Não</div>
+							</div>
+						</div>
+
+						<div class="pt-4 text-center">
+							<button
+								class="text-sm font-bold text-indigo-600 transition-colors hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300"
+							>
+								Detalhes Extraídos
+							</button>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	{/if}
+</div>

+ 190 - 0
src/routes/(app)/dashboard/perfil/+page.svelte

@@ -0,0 +1,190 @@
+<script>
+	import { User, Mail, Phone, MapPin, Building, Key, ChevronRight } from 'lucide-svelte';
+	import { goto } from '$app/navigation';
+	let isEditingPassword = false;
+	let passwordForm = {
+		currentPassword: '',
+		newPassword: '',
+		confirmPassword: ''
+	};
+
+	function handleChangePassword() {
+		isEditingPassword = true;
+	}
+
+	function handleSavePassword() {
+		if (passwordForm.newPassword !== passwordForm.confirmPassword) {
+			alert('As senhas não conferem');
+			return;
+		}
+		console.log('Alterando senha...');
+		isEditingPassword = false;
+		passwordForm = { currentPassword: '', newPassword: '', confirmPassword: '' };
+	}
+
+	function handleCancel() {
+		isEditingPassword = false;
+		passwordForm = { currentPassword: '', newPassword: '', confirmPassword: '' };
+	}
+</script>
+
+<div class="mx-auto max-w-3xl space-y-6">
+	<!-- Header -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="flex items-center gap-3">
+			<div class="h-8 w-8 shrink-0 rounded-lg bg-indigo-500/20 text-indigo-500 flex items-center justify-center">
+				<User size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Meu Perfil</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Gerencie suas informações de perfil e preferências de segurança
+		</p>
+	</div>
+
+	<!-- Profile Information -->
+	<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="border-b border-slate-200 p-5 dark:border-slate-800">
+			<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Informações Pessoais</h2>
+		</div>
+
+		<div class="p-5 space-y-4">
+			<!-- Name -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					Nome
+				</label>
+				<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200 dark:border-slate-700">
+					<User size={18} class="text-slate-400 shrink-0" />
+					<span class="text-slate-900 dark:text-slate-200">Admin</span>
+				</div>
+			</div>
+
+			<!-- Email -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					E-mail
+				</label>
+				<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200 dark:border-slate-700">
+					<Mail size={18} class="text-slate-400 shrink-0" />
+					<span class="text-slate-900 dark:text-slate-200">admin@nettown.com</span>
+				</div>
+			</div>
+
+			<!-- Phone -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					Telefone
+				</label>
+				<input
+					type="tel"
+					placeholder="(11) 99999-9999"
+					class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+				/>
+			</div>
+
+			<!-- Company -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					Empresa
+				</label>
+				<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200 dark:border-slate-700">
+					<Building size={18} class="text-slate-400 shrink-0" />
+					<span class="text-slate-900 dark:text-slate-200">NetTown Analytics</span>
+				</div>
+			</div>
+
+			<!-- Save Button -->
+			<div class="flex gap-3 pt-4">
+				<button class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150">
+					Salvar Alterações
+				</button>
+			</div>
+		</div>
+	</div>
+
+	<!-- Security Section -->
+	<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="border-b border-slate-200 p-5 dark:border-slate-800">
+			<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Segurança</h2>
+		</div>
+
+		{#if !isEditingPassword}
+			<div class="divide-y divide-slate-200 dark:divide-slate-800">
+				<div class="p-5 hover:bg-slate-50 transition-colors duration-150 dark:hover:bg-slate-800/50">
+					<div class="flex items-center justify-between">
+						<div class="flex items-center gap-3">
+							<div class="h-10 w-10 rounded-lg bg-slate-100 text-slate-600 flex items-center justify-center dark:bg-slate-800 dark:text-slate-400">
+								<Key size={18} />
+							</div>
+							<div>
+								<h3 class="text-sm font-medium text-slate-900 dark:text-white">Alterar Senha</h3>
+								<p class="mt-0.5 text-xs text-slate-600 dark:text-slate-400">Atualize sua senha com regularidade</p>
+							</div>
+						</div>
+						<button
+							onclick={handleChangePassword}
+							class="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150"
+						>
+							Alterar
+							<ChevronRight size={14} />
+						</button>
+					</div>
+				</div>
+			</div>
+		{:else}
+			<div class="p-5 space-y-4">
+				<div>
+					<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+						Senha Atual
+					</label>
+					<input
+						type="password"
+						placeholder="Insira sua senha atual"
+						bind:value={passwordForm.currentPassword}
+						class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+					/>
+				</div>
+
+				<div>
+					<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+						Nova Senha
+					</label>
+					<input
+						type="password"
+						placeholder="Insira sua nova senha"
+						bind:value={passwordForm.newPassword}
+						class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+					/>
+				</div>
+
+				<div>
+					<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+						Confirmar Nova Senha
+					</label>
+					<input
+						type="password"
+						placeholder="Confirme sua nova senha"
+						bind:value={passwordForm.confirmPassword}
+						class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+					/>
+				</div>
+
+				<div class="flex gap-3 pt-4">
+					<button
+						onclick={handleSavePassword}
+						class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150"
+					>
+						Salvar Senha
+					</button>
+					<button
+						onclick={handleCancel}
+						class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-slate-200 text-slate-900 hover:bg-slate-300 transition-colors duration-150 dark:bg-slate-700 dark:text-slate-200 dark:hover:bg-slate-600"
+					>
+						Cancelar
+					</button>
+				</div>
+			</div>
+		{/if}
+	</div>
+</div>

+ 287 - 64
src/routes/(app)/dashboard/personas/+page.svelte

@@ -1,8 +1,136 @@
 <script>
-	import { Users, AlertTriangle, DollarSign, Compass, UserRound, TrendingUp, HeartHandshake } from 'lucide-svelte';
+	import {
+		Users,
+		AlertTriangle,
+		DollarSign,
+		Compass,
+		UserRound,
+		TrendingUp,
+		HeartHandshake
+	} from 'lucide-svelte';
 	import { mockPersonasKpis, mockPersonas } from '$lib/core/models/mock-data.js';
 
-	let selectedPersona = $state(null);
+	let selectedPersona = $state(mockPersonas[0] ?? null);
+
+	const periodOptions = [
+		{ id: 'week', label: 'Últimos 7 dias', multiplier: 1 },
+		{ id: 'month', label: 'Últimos 30 dias', multiplier: 1.25 },
+		{ id: 'quarter', label: 'Último trimestre', multiplier: 1.6 }
+	];
+
+	const unitOptions = [
+		{ id: 'all', label: 'Todas unidades', multiplier: 1 },
+		{ id: 'flagship', label: 'Loja Flagship', multiplier: 1.4 },
+		{ id: 'digital', label: 'Digital', multiplier: 1.2 },
+		{ id: 'franquias', label: 'Franquias', multiplier: 0.85 }
+	];
+
+	const areaOptions = [
+		{ id: 'any', label: 'Sem segmento de setor', multiplier: 1 },
+		{ id: 'atendimento', label: 'Atendimento', multiplier: 1.15 },
+		{ id: 'produto', label: 'Produto', multiplier: 1.05 },
+		{ id: 'logistica', label: 'Logística', multiplier: 0.9 }
+	];
+
+	const sentimentOptions = [
+		{ id: 'all', label: 'Todos', bias: { churn: 1, volume: 1, potential: 0 } },
+		{ id: 'positive', label: 'Positivo', bias: { churn: 0.85, volume: 1.25, potential: 0.4 } },
+		{ id: 'neutral', label: 'Neutro', bias: { churn: 1, volume: 1, potential: 0 } },
+		{ id: 'negative', label: 'Negativo', bias: { churn: 1.25, volume: 0.85, potential: -0.5 } }
+	];
+
+	let selectedPeriod = $state(periodOptions[0].id);
+	let selectedUnit = $state(unitOptions[0].id);
+	let selectedArea = $state(areaOptions[0].id);
+	let selectedSentiment = $state(sentimentOptions[0].id);
+
+	const baseKpis = {
+		active: Number(mockPersonasKpis.ativas) || 5,
+		churn: parseFloat(String(mockPersonasKpis.riscoChurn).replace(',', '.')) || 60.1,
+		loss:
+			Number(
+				String(mockPersonasKpis.perdaMensalEst)
+					.replace(/[^0-9,.-]/g, '')
+					.replace(',', '.')
+			) || 7521.27,
+		potentialScore: mockPersonasKpis.potencialExpansao === 'Neutro' ? 0 : 0.2
+	};
+
+	const baseStats = {
+		identified: 28,
+		messages: 1840,
+		aspects: 18,
+		subaspects: 56
+	};
+
+	const periodSelection = $derived.by(
+		() => periodOptions.find((opt) => opt.id === selectedPeriod) ?? periodOptions[0]
+	);
+	const unitSelection = $derived.by(
+		() => unitOptions.find((opt) => opt.id === selectedUnit) ?? unitOptions[0]
+	);
+	const areaSelection = $derived.by(
+		() => areaOptions.find((opt) => opt.id === selectedArea) ?? areaOptions[0]
+	);
+	const sentimentSelection = $derived.by(
+		() => sentimentOptions.find((opt) => opt.id === selectedSentiment) ?? sentimentOptions[0]
+	);
+
+	const combinedMultiplier = $derived.by(() => {
+		const periodMultiplier = periodSelection?.multiplier ?? 1;
+		const unitMultiplier = unitSelection?.multiplier ?? 1;
+		const areaMultiplier = areaSelection?.multiplier ?? 1;
+		return periodMultiplier * unitMultiplier * areaMultiplier;
+	});
+
+	const kpis = $derived.by(() => {
+		const sentimentBias = sentimentSelection?.bias ?? sentimentOptions[0].bias;
+		const multiplier = Number.isFinite(combinedMultiplier) ? combinedMultiplier : 1;
+		const active = Math.max(1, Math.round(baseKpis.active * multiplier * sentimentBias.volume));
+		const churn = Math.min(
+			100,
+			Math.max(5, Number((baseKpis.churn * sentimentBias.churn).toFixed(1)))
+		);
+		const loss = Math.max(500, baseKpis.loss * multiplier * sentimentBias.churn * 0.9);
+		const potentialScore = Math.max(
+			-1,
+			Math.min(1.5, baseKpis.potentialScore + sentimentBias.potential)
+		);
+		const potentialLabel =
+			potentialScore >= 0.8
+				? 'Muito alto'
+				: potentialScore >= 0.3
+					? 'Alto'
+					: potentialScore >= -0.2
+						? 'Neutro'
+						: 'Baixo';
+		return {
+			active,
+			churn,
+			loss,
+			potentialLabel,
+			potentialScore
+		};
+	});
+
+	const personaStats = $derived.by(() => {
+		const multiplier = Number.isFinite(combinedMultiplier) ? combinedMultiplier : 1;
+		return {
+			identified: Math.round(baseStats.identified * multiplier),
+			messages: Math.round(baseStats.messages * multiplier * 1.1),
+			aspects: Math.round(baseStats.aspects * (0.9 + multiplier / 4)),
+			subaspects: Math.round(baseStats.subaspects * (0.85 + multiplier / 5))
+		};
+	});
+
+	function formatCurrency(value) {
+		const safeValue = Number.isFinite(value) ? value : 0;
+		return safeValue.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
+	}
+
+	function formatNumber(value) {
+		return Number.isFinite(value) ? value.toLocaleString('pt-BR') : '0';
+	}
 
 	function openPersonaDetails(persona) {
 		selectedPersona = persona;
@@ -19,112 +147,179 @@
 
 <div class="mx-auto max-w-[1600px] space-y-6">
 	<!-- Top Section: Header, Filters, KPIs -->
-	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-8 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
-		<div class="flex items-center gap-3 mb-8">
-			<div class="h-8 w-8 shrink-0 rounded-lg bg-amber-500/20 text-amber-500 flex items-center justify-center">
+	<div
+		class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 md:p-8 dark:border-slate-800 dark:bg-[#161f30]"
+	>
+		<div class="mb-8 flex items-center gap-3">
+			<div
+				class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-amber-500/20 text-amber-500"
+			>
 				<Compass size={20} strokeWidth={2.5} />
 			</div>
-			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Expansão: Laboratório de Personas</h1>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">
+				Expansão: Laboratório de Personas
+			</h1>
 		</div>
 
-		<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 w-full text-sm mb-12">
+		<div class="mb-12 grid w-full grid-cols-1 gap-6 text-sm md:grid-cols-2 lg:grid-cols-4">
 			<div class="flex items-center justify-center gap-2">
-				<span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Período:</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Últimos 7 dias</option>
+				<span class="whitespace-nowrap text-slate-500 dark:text-slate-400">Período:</span>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedPeriod}
+				>
+					{#each periodOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex items-center justify-center gap-2">
-				<span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Unidade:</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Sem segmento</option>
+				<span class="whitespace-nowrap text-slate-500 dark:text-slate-400">Unidade:</span>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedUnit}
+				>
+					{#each unitOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex items-center justify-center gap-2">
-				<span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Área:</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Sem segmento de setor</option>
+				<span class="whitespace-nowrap text-slate-500 dark:text-slate-400">Área:</span>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedArea}
+				>
+					{#each areaOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 			<div class="flex items-center justify-center gap-2">
-				<span class="text-slate-500 dark:text-slate-400 whitespace-nowrap">Sentimento:</span>
-				<select class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200">
-					<option>Todos</option>
+				<span class="whitespace-nowrap text-slate-500 dark:text-slate-400">Sentimento:</span>
+				<select
+					class="rounded-md border border-slate-200 bg-white px-3 py-1.5 text-slate-900 focus:border-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-[#0f172a] dark:text-slate-200"
+					bind:value={selectedSentiment}
+				>
+					{#each sentimentOptions as option}
+						<option value={option.id}>{option.label}</option>
+					{/each}
 				</select>
 			</div>
 		</div>
 
 		<!-- KPIs -->
-		<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 w-full pb-4">
+		<div class="grid w-full grid-cols-1 gap-6 pb-4 md:grid-cols-2 lg:grid-cols-4">
 			<div class="flex flex-col items-center justify-center text-center">
-				<UserRound size={24} class="text-amber-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.ativas}</div>
-				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Personas Ativas</div>
+				<UserRound size={24} class="mx-auto mb-3 text-amber-500" />
+				<div class="mb-1 text-3xl font-bold text-slate-900 dark:text-white">{kpis.active}</div>
+				<div
+					class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+				>
+					Personas Ativas
+				</div>
 			</div>
 			<div class="flex flex-col items-center justify-center text-center">
-				<AlertTriangle size={24} class="text-red-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.riscoChurn}</div>
-				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Risco de Churn</div>
+				<AlertTriangle size={24} class="mx-auto mb-3 text-red-500" />
+				<div class="mb-1 text-3xl font-bold text-slate-900 dark:text-white">{kpis.churn}</div>
+				<div
+					class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+				>
+					Risco de Churn
+				</div>
 			</div>
 			<div class="flex flex-col items-center justify-center text-center">
-				<DollarSign size={24} class="text-red-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.perdaMensalEst}</div>
-				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Perda Mensal Est.</div>
+				<DollarSign size={24} class="mx-auto mb-3 text-red-500" />
+				<div class="mb-1 text-3xl font-bold text-slate-900 dark:text-white">
+					{formatCurrency(kpis.loss)}
+				</div>
+				<div
+					class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+				>
+					Perda Mensal Est.
+				</div>
 			</div>
 			<div class="flex flex-col items-center justify-center text-center">
-				<DollarSign size={24} class="text-amber-500 mb-3 mx-auto" />
-				<div class="text-3xl font-bold text-slate-900 dark:text-white mb-1">{mockPersonasKpis.potencialExpansao}</div>
-				<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400">Potencial de Expansão</div>
+				<DollarSign size={24} class="mx-auto mb-3 text-amber-500" />
+				<div class="mb-1 text-3xl font-bold text-slate-900 dark:text-white">
+					{kpis.potentialLabel}
+				</div>
+				<div
+					class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+				>
+					Potencial de Expansão
+				</div>
 			</div>
 		</div>
 	</div>
 
 	<!-- Personas Grid & Details -->
-	<div class="grid grid-cols-1 xl:grid-cols-3 gap-6">
-		<div class="xl:col-span-2 rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
-			
-			<div class="flex flex-wrap items-center justify-between gap-4 mb-8">
+	<div class="grid grid-cols-1 gap-6 xl:grid-cols-3">
+		<div
+			class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 md:p-6 xl:col-span-2 dark:border-slate-800 dark:bg-[#161f30]"
+		>
+			<div class="mb-8 flex flex-wrap items-center justify-between gap-4">
 				<div class="flex items-center gap-3">
 					<div class="flex items-center justify-center text-slate-700 dark:text-slate-300">
 						<UserRound size={20} />
 					</div>
 					<h2 class="text-lg font-bold text-slate-900 dark:text-white">Minhas Personas</h2>
-					<span class="text-sm text-slate-500 dark:text-slate-400">Conheça sua base de forma humana</span>
+					<span class="text-sm text-slate-500 dark:text-slate-400"
+						>Conheça sua base de forma humana</span
+					>
 				</div>
-				<button class="rounded-lg bg-indigo-600 px-5 py-2 text-sm font-semibold text-white transition-colors hover:bg-indigo-700 shadow-sm whitespace-nowrap">
+				<!-- <button class="rounded-lg bg-indigo-600 px-5 py-2 text-sm font-semibold text-white transition-colors hover:bg-indigo-700 shadow-sm whitespace-nowrap">
 					Meus Clientes
-				</button>
+				</button> -->
 			</div>
 
 			<!-- Header Stats -->
-			<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8 pb-8 border-b border-slate-100 dark:border-slate-800/60">
+			<div
+				class="mb-8 grid grid-cols-2 gap-4 border-b border-slate-100 pb-8 md:grid-cols-4 dark:border-slate-800/60"
+			>
 				<div class="flex flex-col items-start text-left">
-					<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
+					<div
+						class="mb-2 text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+					>
 						Personas Identificadas
 					</div>
-					<div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
+					<div class="text-3xl font-bold text-slate-900 dark:text-white">
+						{personaStats.identified}
+					</div>
 				</div>
 				<div class="flex flex-col items-start text-left">
-					<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
+					<div
+						class="mb-2 text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+					>
 						Volume Total de Mensagens Analisadas
 					</div>
-					<div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
+					<div class="text-3xl font-bold text-slate-900 dark:text-white">
+						{formatNumber(personaStats.messages)}
+					</div>
 				</div>
 				<div class="flex flex-col items-start text-left">
-					<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
+					<div
+						class="mb-2 text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+					>
 						Aspectos Únicos
 					</div>
-					<div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
+					<div class="text-3xl font-bold text-slate-900 dark:text-white">
+						{formatNumber(personaStats.aspects)}
+					</div>
 				</div>
 				<div class="flex flex-col items-start text-left">
-					<div class="text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400 mb-2">
+					<div
+						class="mb-2 text-[11px] font-semibold tracking-wider text-slate-500 uppercase dark:text-slate-400"
+					>
 						Subaspectos Únicos
 					</div>
-					<div class="text-3xl font-bold text-slate-900 dark:text-white">0</div>
+					<div class="text-3xl font-bold text-slate-900 dark:text-white">
+						{formatNumber(personaStats.subaspects)}
+					</div>
 				</div>
 			</div>
 
-			<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
+			<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
 				{#each mockPersonas as persona}
 					<button
 						type="button"
@@ -135,40 +330,64 @@
 								: 'border-slate-200 bg-white hover:border-slate-300 dark:border-slate-700/60 dark:bg-[#1e293b]/40 dark:hover:border-slate-600 dark:hover:bg-[#1e293b]/60'
 						}`}
 					>
-						<span class="inline-block rounded-full bg-indigo-100 px-4 py-1 text-[10px] font-bold text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-400 mb-6 tracking-wider">
+						<span
+							class="mb-6 inline-block rounded-full bg-indigo-100 px-4 py-1 text-[10px] font-bold tracking-wider text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-400"
+						>
 							{persona.tipo}
 						</span>
-						<UserRound size={36} strokeWidth={1.5} class="text-slate-400 dark:text-slate-500 mb-4 mx-auto" />
-						<h3 class="text-sm font-bold text-slate-900 dark:text-white mb-2 leading-snug text-center">{persona.nome}</h3>
-						<p class="text-xs text-slate-500 dark:text-slate-400 leading-relaxed font-medium text-center">{persona.descricao}</p>
+						<UserRound
+							size={36}
+							strokeWidth={1.5}
+							class="mx-auto mb-4 text-slate-400 dark:text-slate-500"
+						/>
+						<h3
+							class="mb-2 text-center text-sm leading-snug font-bold text-slate-900 dark:text-white"
+						>
+							{persona.nome}
+						</h3>
+						<p
+							class="text-center text-xs leading-relaxed font-medium text-slate-500 dark:text-slate-400"
+						>
+							{persona.descricao}
+						</p>
 					</button>
 				{/each}
 			</div>
 		</div>
 
 		<!-- Next Best Action Panel -->
-		<div class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b] flex flex-col h-[600px]">
+		<div
+			class="flex h-[600px] flex-col rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
 			<div class="mb-4">
 				<h2 class="text-lg font-bold text-slate-900 dark:text-white">Next Best Action</h2>
-				<p class="text-sm text-slate-500 dark:text-slate-400">Recomendações estratégicas por persona</p>
+				<p class="text-sm text-slate-500 dark:text-slate-400">
+					Recomendações estratégicas por persona
+				</p>
 			</div>
-			
-			<div class="flex-1 overflow-y-auto custom-scrollbar pr-2">
+
+			<div class="custom-scrollbar flex-1 overflow-y-auto pr-2">
 				{#if selectedPersona}
 					<div class="space-y-6">
 						<div>
-							<div class="flex items-center gap-2 mb-2">
+							<div class="mb-2 flex items-center gap-2">
 								<UserRound size={18} class="text-indigo-500" />
 								<h3 class="font-bold text-slate-900 dark:text-white">{selectedPersona.nome}</h3>
 							</div>
-							<p class="text-sm text-slate-600 dark:text-slate-300 bg-slate-50 dark:bg-slate-800 p-3 rounded-lg border border-slate-100 dark:border-slate-700">
+							<p
+								class="rounded-lg border border-slate-100 bg-slate-50 p-3 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300"
+							>
 								{selectedPersona.detalhes}
 							</p>
 						</div>
 
 						<div class="space-y-4">
-							<div class="rounded-lg border border-emerald-200 bg-emerald-50 p-4 dark:border-emerald-500/20 dark:bg-emerald-500/5">
-								<h4 class="font-bold text-emerald-800 dark:text-emerald-400 mb-2 flex items-center gap-2">
+							<div
+								class="rounded-lg border border-emerald-200 bg-emerald-50 p-4 dark:border-emerald-500/20 dark:bg-emerald-500/5"
+							>
+								<h4
+									class="mb-2 flex items-center gap-2 font-bold text-emerald-800 dark:text-emerald-400"
+								>
 									<TrendingUp size={16} />
 									Expansão
 								</h4>
@@ -177,8 +396,10 @@
 								</p>
 							</div>
 
-							<div class="rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-500/20 dark:bg-red-500/5">
-								<h4 class="font-bold text-red-800 dark:text-red-400 mb-2 flex items-center gap-2">
+							<div
+								class="rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-500/20 dark:bg-red-500/5"
+							>
+								<h4 class="mb-2 flex items-center gap-2 font-bold text-red-800 dark:text-red-400">
 									<HeartHandshake size={16} />
 									Engajamento (Salvar Churn)
 								</h4>
@@ -189,7 +410,9 @@
 						</div>
 					</div>
 				{:else}
-					<div class="flex h-full flex-col items-center justify-center text-center text-slate-500 dark:text-slate-400">
+					<div
+						class="flex h-full flex-col items-center justify-center text-center text-slate-500 dark:text-slate-400"
+					>
 						<UserRound size={48} class="mb-4 opacity-20" />
 						<p>Selecione uma persona ao lado para ver o Next Best Action.</p>
 					</div>

+ 190 - 0
src/routes/(app)/dashboard/profile/+page.svelte

@@ -0,0 +1,190 @@
+<script>
+	import { User, Mail, Phone, MapPin, Building, Key, ChevronRight } from 'lucide-svelte';
+	import { goto } from '$app/navigation';
+	let isEditingPassword = false;
+	let passwordForm = {
+		currentPassword: '',
+		newPassword: '',
+		confirmPassword: ''
+	};
+
+	function handleChangePassword() {
+		isEditingPassword = true;
+	}
+
+	function handleSavePassword() {
+		if (passwordForm.newPassword !== passwordForm.confirmPassword) {
+			alert('As senhas não conferem');
+			return;
+		}
+		console.log('Alterando senha...');
+		isEditingPassword = false;
+		passwordForm = { currentPassword: '', newPassword: '', confirmPassword: '' };
+	}
+
+	function handleCancel() {
+		isEditingPassword = false;
+		passwordForm = { currentPassword: '', newPassword: '', confirmPassword: '' };
+	}
+</script>
+
+<div class="mx-auto max-w-3xl space-y-6">
+	<!-- Header -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="flex items-center gap-3">
+			<div class="h-8 w-8 shrink-0 rounded-lg bg-indigo-500/20 text-indigo-500 flex items-center justify-center">
+				<User size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Meu Perfil</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Gerencie suas informações de perfil e preferências de segurança
+		</p>
+	</div>
+
+	<!-- Profile Information -->
+	<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="border-b border-slate-200 p-5 dark:border-slate-800">
+			<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Informações Pessoais</h2>
+		</div>
+
+		<div class="p-5 space-y-4">
+			<!-- Name -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					Nome
+				</label>
+				<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200 dark:border-slate-700">
+					<User size={18} class="text-slate-400 shrink-0" />
+					<span class="text-slate-900 dark:text-slate-200">Admin</span>
+				</div>
+			</div>
+
+			<!-- Email -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					E-mail
+				</label>
+				<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200 dark:border-slate-700">
+					<Mail size={18} class="text-slate-400 shrink-0" />
+					<span class="text-slate-900 dark:text-slate-200">admin@nettown.com</span>
+				</div>
+			</div>
+
+			<!-- Phone -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					Telefone
+				</label>
+				<input
+					type="tel"
+					placeholder="(11) 99999-9999"
+					class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+				/>
+			</div>
+
+			<!-- Company -->
+			<div>
+				<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+					Empresa
+				</label>
+				<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200 dark:border-slate-700">
+					<Building size={18} class="text-slate-400 shrink-0" />
+					<span class="text-slate-900 dark:text-slate-200">NetTown Analytics</span>
+				</div>
+			</div>
+
+			<!-- Save Button -->
+			<div class="flex gap-3 pt-4">
+				<button class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150">
+					Salvar Alterações
+				</button>
+			</div>
+		</div>
+	</div>
+
+	<!-- Security Section -->
+	<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="border-b border-slate-200 p-5 dark:border-slate-800">
+			<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Segurança</h2>
+		</div>
+
+		{#if !isEditingPassword}
+			<div class="divide-y divide-slate-200 dark:divide-slate-800">
+				<div class="p-5 hover:bg-slate-50 transition-colors duration-150 dark:hover:bg-slate-800/50">
+					<div class="flex items-center justify-between">
+						<div class="flex items-center gap-3">
+							<div class="h-10 w-10 rounded-lg bg-slate-100 text-slate-600 flex items-center justify-center dark:bg-slate-800 dark:text-slate-400">
+								<Key size={18} />
+							</div>
+							<div>
+								<h3 class="text-sm font-medium text-slate-900 dark:text-white">Alterar Senha</h3>
+								<p class="mt-0.5 text-xs text-slate-600 dark:text-slate-400">Atualize sua senha com regularidade</p>
+							</div>
+						</div>
+						<button
+							onclick={handleChangePassword}
+							class="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150"
+						>
+							Alterar
+							<ChevronRight size={14} />
+						</button>
+					</div>
+				</div>
+			</div>
+		{:else}
+			<div class="p-5 space-y-4">
+				<div>
+					<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+						Senha Atual
+					</label>
+					<input
+						type="password"
+						placeholder="Insira sua senha atual"
+						bind:value={passwordForm.currentPassword}
+						class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+					/>
+				</div>
+
+				<div>
+					<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+						Nova Senha
+					</label>
+					<input
+						type="password"
+						placeholder="Insira sua nova senha"
+						bind:value={passwordForm.newPassword}
+						class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+					/>
+				</div>
+
+				<div>
+					<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
+						Confirmar Nova Senha
+					</label>
+					<input
+						type="password"
+						placeholder="Confirme sua nova senha"
+						bind:value={passwordForm.confirmPassword}
+						class="w-full px-4 py-2.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-sm text-slate-900 dark:text-slate-200 placeholder-slate-400 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors"
+					/>
+				</div>
+
+				<div class="flex gap-3 pt-4">
+					<button
+						onclick={handleSavePassword}
+						class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150"
+					>
+						Salvar Senha
+					</button>
+					<button
+						onclick={handleCancel}
+						class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-slate-200 text-slate-900 hover:bg-slate-300 transition-colors duration-150 dark:bg-slate-700 dark:text-slate-200 dark:hover:bg-slate-600"
+					>
+						Cancelar
+					</button>
+				</div>
+			</div>
+		{/if}
+	</div>
+</div>

+ 1 - 55
src/routes/(app)/dashboard/settings/+page.svelte

@@ -1,5 +1,5 @@
 <script>
-	import { Settings, Phone, Users, Bell, Shield, Database, Globe, Palette, HelpCircle } from 'lucide-svelte';
+	import { Settings, Phone, Bell, HelpCircle } from 'lucide-svelte';
 	import { goto } from '$app/navigation';
 
 	// Settings sections
@@ -41,60 +41,6 @@
 				}
 			]
 		},
-		{
-			title: 'Segurança',
-			icon: Shield,
-			items: [
-				{
-					title: 'Autenticação de Dois Fatores',
-					description: 'Proteja sua conta com autenticação adicional',
-					status: 'disabled',
-					action: 'ativar'
-				},
-				{
-					title: 'Permissões de Acesso',
-					description: 'Gerencie quem pode acessar o painel',
-					status: 'configured',
-					action: 'gerenciar'
-				}
-			]
-		},
-		{
-			title: 'Dados',
-			icon: Database,
-			items: [
-				{
-					title: 'Exportar Dados',
-					description: 'Exporte seus dados em formato CSV ou Excel',
-					status: 'available',
-					action: 'exportar'
-				},
-				{
-					title: 'Backup Automático',
-					description: 'Configure backups automáticos dos seus dados',
-					status: 'enabled',
-					action: 'gerenciar'
-				}
-			]
-		},
-		{
-			title: 'Personalização',
-			icon: Palette,
-			items: [
-				{
-					title: 'Tema',
-					description: 'Escolha entre modo claro ou escuro',
-					status: 'dark',
-					action: 'mudar'
-				},
-				{
-					title: 'Idioma',
-					description: 'Selecione o idioma da interface',
-					status: 'pt-BR',
-					action: 'mudar'
-				}
-			]
-		},
 		{
 			title: 'Suporte',
 			icon: HelpCircle,

+ 489 - 0
src/routes/(app)/dashboard/sla/+page.svelte

@@ -0,0 +1,489 @@
+<script>
+	import {
+		ShieldCheck,
+		Clock,
+		CheckCircle,
+		AlertTriangle,
+		XCircle,
+		Plus,
+		X
+	} from 'lucide-svelte';
+	import { onMount } from 'svelte';
+
+	let isLoading = $state(true);
+	onMount(() => {
+		setTimeout(() => {
+			isLoading = false;
+		}, 600);
+	});
+
+	// ── Department configs ────────────────────────────────────────────────────
+	let departments = $state([
+		{
+			id: 'sac',
+			name: 'SAC',
+			firstResponseH: 1,
+			firstResponseM: 30,
+			resolutionH: 24,
+			alertPct: 80,
+			liveStatus: 'breach',
+			liveDetail: '14h estourado',
+			lastUpdated: 'há 8 minutos'
+		},
+		{
+			id: 'vendas',
+			name: 'Vendas',
+			firstResponseH: 0,
+			firstResponseM: 45,
+			resolutionH: 8,
+			alertPct: 80,
+			liveStatus: 'warning',
+			liveDetail: 'próximo de estourar (18% restante)',
+			lastUpdated: 'há 3 minutos'
+		},
+		{
+			id: 'suporte',
+			name: 'Suporte',
+			firstResponseH: 2,
+			firstResponseM: 0,
+			resolutionH: 48,
+			alertPct: 80,
+			liveStatus: 'ok',
+			liveDetail: 'dentro do SLA',
+			lastUpdated: 'há 1 minuto'
+		}
+	]);
+
+	let savedDeptIds = $state([]);
+
+	function saveDepartment(deptId, deptName) {
+		savedDeptIds = [...savedDeptIds, deptId];
+		setTimeout(() => {
+			savedDeptIds = savedDeptIds.filter((id) => id !== deptId);
+		}, 3000);
+	}
+
+	// ── Add department modal ──────────────────────────────────────────────────
+	let showAddModal = $state(false);
+	let newDept = $state({ name: '', firstResponseH: 1, firstResponseM: 0, resolutionH: 24, alertPct: 80 });
+
+	function addDepartment() {
+		if (!newDept.name.trim()) return;
+		departments = [
+			...departments,
+			{
+				id: newDept.name.toLowerCase().replace(/\s+/g, '-'),
+				name: newDept.name,
+				firstResponseH: newDept.firstResponseH,
+				firstResponseM: newDept.firstResponseM,
+				resolutionH: newDept.resolutionH,
+				alertPct: newDept.alertPct,
+				liveStatus: 'ok',
+				liveDetail: 'dentro do SLA',
+				lastUpdated: 'agora'
+			}
+		];
+		newDept = { name: '', firstResponseH: 1, firstResponseM: 0, resolutionH: 24, alertPct: 80 };
+		showAddModal = false;
+	}
+
+	// ── Live status helpers ───────────────────────────────────────────────────
+	function statusBadge(status) {
+		const map = {
+			ok: {
+				label: 'OK',
+				cls: 'bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-400/10 dark:text-emerald-400 dark:border-emerald-400/20'
+			},
+			warning: {
+				label: 'ALERTA',
+				cls: 'bg-amber-50 text-amber-700 border-amber-200 dark:bg-amber-400/10 dark:text-amber-400 dark:border-amber-400/20'
+			},
+			breach: {
+				label: 'CRÍTICO',
+				cls: 'bg-red-50 text-red-700 border-red-200 dark:bg-red-400/10 dark:text-red-400 dark:border-red-400/20'
+			}
+		};
+		return map[status] ?? map['ok'];
+	}
+
+	function statusIndicatorCls(status) {
+		if (status === 'ok') return 'bg-emerald-500';
+		if (status === 'warning') return 'bg-amber-500';
+		return 'bg-red-500';
+	}
+
+	function statusCardBorder(status) {
+		if (status === 'ok') return 'border-emerald-200 dark:border-emerald-400/20';
+		if (status === 'warning') return 'border-amber-200 dark:border-amber-400/20';
+		return 'border-red-200 dark:border-red-400/20';
+	}
+
+	function statusIcon(status) {
+		if (status === 'ok') return CheckCircle;
+		if (status === 'warning') return AlertTriangle;
+		return XCircle;
+	}
+
+	function statusIconCls(status) {
+		if (status === 'ok') return 'text-emerald-600 dark:text-emerald-400';
+		if (status === 'warning') return 'text-amber-600 dark:text-amber-400';
+		return 'text-red-600 dark:text-red-400';
+	}
+
+	const inputCls =
+		'rounded-lg border border-slate-300 bg-slate-50 px-3 py-1.5 text-sm text-slate-900 transition-colors focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 focus:outline-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 w-full';
+</script>
+
+<svelte:head>
+	<title>Configuração de SLA - Nettown Analytics</title>
+</svelte:head>
+
+<!-- Add Department Modal -->
+{#if showAddModal}
+	<div
+		class="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/80 p-4"
+		onclick={(e) => e.target === e.currentTarget && (showAddModal = false)}
+		onkeydown={(e) => e.key === 'Escape' && (showAddModal = false)}
+		role="dialog"
+		aria-modal="true"
+		tabindex="-1"
+	>
+		<div
+			class="w-full max-w-md rounded-xl border border-slate-200 bg-white shadow-2xl dark:border-slate-700 dark:bg-[#1e293b]"
+		>
+			<div
+				class="flex items-center justify-between border-b border-slate-200 p-5 dark:border-slate-700"
+			>
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">Adicionar Departamento</h2>
+				<button
+					onclick={() => (showAddModal = false)}
+					class="rounded-lg p-1.5 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 dark:hover:bg-slate-800 dark:hover:text-white"
+				>
+					<X size={18} />
+				</button>
+			</div>
+			<div class="space-y-4 p-5">
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Nome do departamento</label>
+					<input type="text" bind:value={newDept.name} placeholder="Ex: Financeiro" class={inputCls} />
+				</div>
+				<div class="grid grid-cols-2 gap-4">
+					<div>
+						<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Primeira resposta (h)</label>
+						<input type="number" min="0" max="72" bind:value={newDept.firstResponseH} class={inputCls} />
+					</div>
+					<div>
+						<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Primeira resposta (min)</label>
+						<input type="number" min="0" max="59" bind:value={newDept.firstResponseM} class={inputCls} />
+					</div>
+				</div>
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Tempo máx. de resolução (h)</label>
+					<input type="number" min="1" max="720" bind:value={newDept.resolutionH} class={inputCls} />
+				</div>
+				<div>
+					<label class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">Alerta de estouro em (% do tempo)</label>
+					<input type="number" min="1" max="99" bind:value={newDept.alertPct} class={inputCls} />
+				</div>
+			</div>
+			<div class="flex justify-end gap-3 border-t border-slate-200 p-5 dark:border-slate-700">
+				<button
+					onclick={() => (showAddModal = false)}
+					class="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700"
+				>
+					Cancelar
+				</button>
+				<button
+					onclick={addDepartment}
+					disabled={!newDept.name.trim()}
+					class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-indigo-700 disabled:opacity-50 dark:bg-indigo-500 dark:hover:bg-indigo-600"
+				>
+					Adicionar
+				</button>
+			</div>
+		</div>
+	</div>
+{/if}
+
+<div class="mx-auto max-w-[1600px] space-y-6">
+	<!-- Page header -->
+	<div
+		class="rounded-xl border border-slate-200 bg-white p-5 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+	>
+		<div class="flex items-center gap-3">
+			<div
+				class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-indigo-500/20 text-indigo-500"
+			>
+				<ShieldCheck size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Configuração de SLA</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Defina os tempos de atendimento por departamento. O sistema alertará automaticamente quando os
+			limites estiverem próximos de estourar.
+		</p>
+	</div>
+
+	<!-- Department cards -->
+	{#if isLoading}
+		<div class="space-y-4">
+			{#each [1, 2, 3] as _}
+				<div
+					class="h-56 animate-pulse rounded-xl border border-slate-200 bg-slate-100 dark:border-slate-800 dark:bg-slate-800"
+				></div>
+			{/each}
+		</div>
+	{:else}
+		<div class="space-y-4">
+			{#each departments as dept, i}
+				{@const badge = statusBadge(dept.liveStatus)}
+				{@const StatusIcon = statusIcon(dept.liveStatus)}
+				<div
+					class="overflow-hidden rounded-xl border bg-white shadow-sm transition-colors duration-200 dark:bg-[#1e293b] {statusCardBorder(dept.liveStatus)}"
+				>
+					<!-- Card header -->
+					<div
+						class="flex items-center justify-between border-b border-slate-200 bg-slate-50 px-5 py-4 dark:border-slate-800 dark:bg-slate-900/30"
+					>
+						<div class="flex items-center gap-3">
+							<div class="h-3 w-3 shrink-0 rounded-full {statusIndicatorCls(dept.liveStatus)}"></div>
+							<h2 class="text-base font-bold text-slate-900 dark:text-white">{dept.name}</h2>
+							<span class="rounded-md border px-2 py-0.5 text-xs font-bold {badge.cls}"
+								>{badge.label}</span
+							>
+						</div>
+						<div class="flex items-center gap-2 text-xs text-slate-500 dark:text-slate-400">
+							<StatusIcon size={14} class={statusIconCls(dept.liveStatus)} />
+							<span>{dept.liveDetail}</span>
+						</div>
+					</div>
+
+					<!-- Form fields -->
+					<div class="grid grid-cols-1 gap-6 p-5 sm:grid-cols-2 xl:grid-cols-4">
+						<!-- Primeira resposta horas -->
+						<div>
+							<label
+								class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+							>
+								Primeira resposta — horas
+							</label>
+							<div class="flex items-center gap-2">
+								<input
+									type="number"
+									min="0"
+									max="72"
+									bind:value={departments[i].firstResponseH}
+									class={inputCls}
+								/>
+								<span class="shrink-0 text-xs text-slate-500 dark:text-slate-400">h</span>
+							</div>
+						</div>
+
+						<!-- Primeira resposta minutos -->
+						<div>
+							<label
+								class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+							>
+								Primeira resposta — minutos
+							</label>
+							<div class="flex items-center gap-2">
+								<input
+									type="number"
+									min="0"
+									max="59"
+									bind:value={departments[i].firstResponseM}
+									class={inputCls}
+								/>
+								<span class="shrink-0 text-xs text-slate-500 dark:text-slate-400">min</span>
+							</div>
+						</div>
+
+						<!-- Tempo máx. de resolução -->
+						<div>
+							<label
+								class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+							>
+								Tempo máx. de resolução
+							</label>
+							<div class="flex items-center gap-2">
+								<input
+									type="number"
+									min="1"
+									max="720"
+									bind:value={departments[i].resolutionH}
+									class={inputCls}
+								/>
+								<span class="shrink-0 text-xs text-slate-500 dark:text-slate-400">horas</span>
+							</div>
+						</div>
+
+						<!-- Alerta de estouro -->
+						<div>
+							<label
+								class="mb-1.5 block text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+							>
+								Alertar quando atingir
+							</label>
+							<div class="flex items-center gap-2">
+								<input
+									type="number"
+									min="1"
+									max="99"
+									bind:value={departments[i].alertPct}
+									class={inputCls}
+								/>
+								<span class="shrink-0 text-xs text-slate-500 dark:text-slate-400">% do tempo</span>
+							</div>
+						</div>
+					</div>
+
+					<!-- Summary + save -->
+					<div
+						class="flex flex-wrap items-center justify-between gap-4 border-t border-slate-100 px-5 py-4 dark:border-slate-800"
+					>
+						<div class="flex flex-wrap gap-4 text-xs text-slate-500 dark:text-slate-400">
+							<span>
+								Primeira resposta:
+								<strong class="text-slate-900 dark:text-slate-200">
+									{dept.firstResponseH > 0 ? `${dept.firstResponseH}h ` : ''}{dept.firstResponseM > 0
+										? `${dept.firstResponseM}min`
+										: dept.firstResponseH === 0
+										? '0min'
+										: ''}
+								</strong>
+							</span>
+							<span>
+								Resolução: <strong class="text-slate-900 dark:text-slate-200">{dept.resolutionH}h</strong>
+							</span>
+							<span>
+								Alerta em: <strong class="text-slate-900 dark:text-slate-200">{dept.alertPct}%</strong>
+							</span>
+						</div>
+
+						<div class="flex items-center gap-3">
+							{#if savedDeptIds.includes(dept.id)}
+								<span class="flex items-center gap-1.5 text-sm font-medium text-emerald-600 dark:text-emerald-400">
+									<CheckCircle size={16} />
+									SLA do {dept.name} atualizado
+								</span>
+							{/if}
+							<button
+								onclick={() => saveDepartment(dept.id, dept.name)}
+								class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition-all hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600"
+							>
+								Salvar
+							</button>
+						</div>
+					</div>
+				</div>
+			{/each}
+		</div>
+	{/if}
+
+	<!-- Add Department button -->
+	{#if !isLoading}
+		<div class="flex justify-center">
+			<button
+				onclick={() => (showAddModal = true)}
+				class="flex items-center gap-2 rounded-lg border border-dashed border-slate-300 bg-white px-6 py-3 text-sm font-medium text-slate-600 shadow-sm transition-all hover:border-indigo-400 hover:text-indigo-600 dark:border-slate-700 dark:bg-[#1e293b] dark:text-slate-400 dark:hover:border-indigo-500 dark:hover:text-indigo-400"
+			>
+				<Plus size={16} strokeWidth={2.5} />
+				+ Adicionar Departamento
+			</button>
+		</div>
+	{/if}
+
+	<!-- Live SLA Status panel -->
+	{#if !isLoading}
+		<div
+			class="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#1e293b]"
+		>
+			<div
+				class="flex items-center gap-3 border-b border-slate-200 bg-slate-50 px-5 py-4 dark:border-slate-800 dark:bg-slate-900/30"
+			>
+				<div
+					class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-400"
+				>
+					<Clock size={18} strokeWidth={2} />
+				</div>
+				<h2 class="text-base font-bold text-slate-900 dark:text-white">
+					Status de SLA em Tempo Real
+				</h2>
+			</div>
+
+			<div class="overflow-x-auto">
+				<table class="w-full text-sm">
+					<thead>
+						<tr
+							class="border-b border-slate-100 bg-slate-50/50 dark:border-slate-800 dark:bg-slate-900/20"
+						>
+							<th
+								class="px-5 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+								>Departamento</th
+							>
+							<th
+								class="px-5 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+								>Status atual</th
+							>
+							<th
+								class="px-5 py-3 text-center text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+								>Situação</th
+							>
+							<th
+								class="px-5 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+								>Primeira resposta máx.</th
+							>
+							<th
+								class="px-5 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+								>Resolução máx.</th
+							>
+							<th
+								class="px-5 py-3 text-right text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400"
+								>Atualizado</th
+							>
+						</tr>
+					</thead>
+					<tbody class="divide-y divide-slate-100 dark:divide-slate-800">
+						{#each departments as dept}
+							{@const badge = statusBadge(dept.liveStatus)}
+							{@const StatusIcon = statusIcon(dept.liveStatus)}
+							<tr class="transition-colors hover:bg-slate-50 dark:hover:bg-slate-800/40">
+								<td class="px-5 py-4">
+									<div class="flex items-center gap-2">
+										<div
+											class="h-2.5 w-2.5 shrink-0 rounded-full {statusIndicatorCls(dept.liveStatus)}"
+										></div>
+										<span class="font-semibold text-slate-900 dark:text-white">{dept.name}</span>
+									</div>
+								</td>
+								<td class="px-5 py-4">
+									<div class="flex items-center gap-2 text-sm">
+										<StatusIcon size={15} class={statusIconCls(dept.liveStatus)} />
+										<span class="text-slate-700 dark:text-slate-300">{dept.liveDetail}</span>
+									</div>
+								</td>
+								<td class="px-5 py-4 text-center">
+									<span class="rounded-md border px-2.5 py-1 text-xs font-bold {badge.cls}"
+										>{badge.label}</span
+									>
+								</td>
+								<td class="px-5 py-4 text-slate-700 dark:text-slate-300">
+									{dept.firstResponseH > 0 ? `${dept.firstResponseH}h` : ''}{dept.firstResponseM > 0
+										? ` ${dept.firstResponseM}min`
+										: ''}
+									{dept.firstResponseH === 0 && dept.firstResponseM === 0 ? '—' : ''}
+								</td>
+								<td class="px-5 py-4 text-slate-700 dark:text-slate-300">
+									{dept.resolutionH}h
+								</td>
+								<td class="px-5 py-4 text-right text-xs text-slate-400 dark:text-slate-500">
+									{dept.lastUpdated}
+								</td>
+							</tr>
+						{/each}
+					</tbody>
+				</table>
+			</div>
+		</div>
+	{/if}
+</div>

+ 164 - 0
src/routes/(app)/dashboard/subscription/+page.svelte

@@ -0,0 +1,164 @@
+<script>
+	import { CreditCard, Calendar, AlertCircle, Check } from 'lucide-svelte';
+
+	let currentPlan = {
+		name: 'Profissional',
+		price: 299,
+		billingCycle: 'mensal',
+		status: 'ativo',
+		nextBillingDate: '15/06/2026'
+	};
+
+	const plans = [
+		{
+			name: 'Starter',
+			price: 99,
+			description: 'Perfeito para começar',
+			features: [
+				'Até 5 clientes',
+				'Análise básica de sentimento',
+				'Relatórios mensais',
+				'Suporte por email'
+			],
+			popular: false
+		},
+		{
+			name: 'Profissional',
+			price: 299,
+			description: 'Mais recursos e análises',
+			features: [
+				'Até 50 clientes',
+				'Análise avançada de sentimento',
+				'Relatórios em tempo real',
+				'API access',
+				'Suporte prioritário',
+				'Integrações WhatsApp'
+			],
+			popular: true
+		},
+		{
+			name: 'Empresa',
+			price: 999,
+			description: 'Recursos completos',
+			features: [
+				'Clientes ilimitados',
+				'Análise completa de IA',
+				'Dashboards personalizados',
+				'API completa',
+				'Suporte 24/7',
+				'Todas as integrações',
+				'Usuários ilimitados'
+			],
+			popular: false
+		}
+	];
+
+	function handleUpgrade(plan) {
+		console.log(`Upgrading to ${plan.name} plan`);
+	}
+
+	function handleCancelSubscription() {
+		if (confirm('Tem certeza que deseja cancelar sua assinatura?')) {
+			console.log('Cancelando assinatura...');
+		}
+	}
+</script>
+
+<div class="mx-auto max-w-4xl space-y-6">
+	<!-- Header -->
+	<div class="rounded-xl border border-slate-200 bg-white p-5 md:p-6 shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="flex items-center gap-3">
+			<div class="h-8 w-8 shrink-0 rounded-lg bg-indigo-500/20 text-indigo-500 flex items-center justify-center">
+				<CreditCard size={20} strokeWidth={2.5} />
+			</div>
+			<h1 class="text-xl font-bold text-slate-900 dark:text-white">Assinatura</h1>
+		</div>
+		<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">
+			Gerencie seu plano, faturamento e métodos de pagamento
+		</p>
+	</div>
+
+	<!-- Current Plan -->
+	<div class="rounded-xl border border-slate-200 bg-white shadow-sm transition-colors duration-200 dark:border-slate-800 dark:bg-[#161f30]">
+		<div class="border-b border-slate-200 p-5 dark:border-slate-800">
+			<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Seu Plano Atual</h2>
+		</div>
+
+		<div class="p-5 md:p-6">
+			<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
+				<div>
+					<p class="text-sm text-slate-600 dark:text-slate-400 mb-1">Plano</p>
+					<p class="text-2xl font-bold text-slate-900 dark:text-white">{currentPlan.name}</p>
+				</div>
+				<div>
+					<p class="text-sm text-slate-600 dark:text-slate-400 mb-1">Preço</p>
+					<p class="text-2xl font-bold text-slate-900 dark:text-white">R$ {currentPlan.price}</p>
+					<p class="text-xs text-slate-500 dark:text-slate-400">por mês</p>
+				</div>
+				<div>
+					<p class="text-sm text-slate-600 dark:text-slate-400 mb-1">Próxima cobrança</p>
+					<div class="flex items-center gap-2">
+						<Calendar size={18} class="text-indigo-600 dark:text-indigo-400" />
+						<span class="text-lg font-semibold text-slate-900 dark:text-white">{currentPlan.nextBillingDate}</span>
+					</div>
+				</div>
+			</div>
+
+			<div class="flex flex-col md:flex-row gap-3 pt-4 border-t border-slate-200 dark:border-slate-800">
+				<button class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-150">
+					Atualizar Método de Pagamento
+				</button>
+				<button
+					onclick={handleCancelSubscription}
+					class="inline-flex items-center px-4 py-2 text-sm font-medium rounded-lg border border-red-300 text-red-600 hover:bg-red-50 transition-colors duration-150 dark:border-red-800 dark:text-red-400 dark:hover:bg-slate-800"
+				>
+					Cancelar Assinatura
+				</button>
+			</div>
+		</div>
+	</div>
+
+	<!-- Available Plans -->
+	<div class="space-y-4">
+		<h2 class="text-lg font-semibold text-slate-900 dark:text-white">Outros Planos Disponíveis</h2>
+
+		<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
+			{#each plans as plan}
+				<div class="rounded-xl border {plan.popular ? 'border-indigo-500 ring-2 ring-indigo-100 dark:ring-indigo-900/30' : 'border-slate-200 dark:border-slate-800'} bg-white shadow-sm transition-colors duration-200 dark:bg-[#161f30] overflow-hidden">
+					{#if plan.popular}
+						<div class="bg-indigo-600 px-4 py-2 text-center">
+							<span class="text-xs font-semibold text-white uppercase tracking-wider">Mais Popular</span>
+						</div>
+					{/if}
+
+					<div class="p-5 md:p-6">
+						<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-2">{plan.name}</h3>
+						<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">{plan.description}</p>
+
+						<div class="mb-6">
+							<span class="text-3xl font-bold text-slate-900 dark:text-white">R$ {plan.price}</span>
+							<span class="text-sm text-slate-600 dark:text-slate-400">/mês</span>
+						</div>
+
+						<button
+							onclick={() => handleUpgrade(plan)}
+							disabled={plan.name === currentPlan.name}
+							class="w-full px-4 py-2 text-sm font-medium rounded-lg transition-colors duration-150 {plan.popular ? 'bg-indigo-600 text-white hover:bg-indigo-700' : 'bg-slate-100 text-slate-900 hover:bg-slate-200 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700'} {plan.name === currentPlan.name ? 'opacity-50 cursor-not-allowed' : ''}"
+						>
+							{plan.name === currentPlan.name ? 'Plano Atual' : 'Escolher Plano'}
+						</button>
+
+						<div class="mt-6 space-y-3 pt-6 border-t border-slate-200 dark:border-slate-800">
+							{#each plan.features as feature}
+								<div class="flex items-center gap-3">
+									<Check size={16} class="text-green-600 dark:text-green-400 shrink-0" />
+									<span class="text-sm text-slate-700 dark:text-slate-300">{feature}</span>
+								</div>
+							{/each}
+						</div>
+					</div>
+				</div>
+			{/each}
+		</div>
+	</div>
+</div>