<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/views/pages/clinic/ClinicDashboard.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import { useRouter } from 'vue-router';
import { useLayout } from '@/layout/composables/layout';
import Menu from 'primevue/menu';
import { supabase } from '@/lib/supabase/client';
import { tenantDb } from '@/lib/supabase/tenantClient';
import { useTenantStore } from '@/stores/tenantStore';
import { useClinicKPIs } from '@/composables/useClinicKPIs';
import FirstResponseCard from '@/components/dashboard/FirstResponseCard.vue';

// Fase 3a — KPIs financeiros/operacionais da clínica
const kpis = useClinicKPIs();
const brl = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });
function fmtBRL(v) { return brl.format(Number(v) || 0); }
const revenueMax = computed(() => {
    const arr = kpis.revenueSeries.value || [];
    return arr.reduce((m, r) => Math.max(m, r.received || 0), 0) || 1;
});

const dashHeroSentinelRef = ref(null);
const heroStuck = ref(false);
let _heroObserver = null;

const agora = ref(new Date());
const asideOpen = ref(false);

const { effectiveVariant, layoutState, layoutConfig, isMobile, railPanelPushesLayout } = useLayout();
const isMobileLayout = computed(() => isMobile.value);
const asideLeft = computed(() => {
    if (isMobileLayout.value) return undefined;
    if (effectiveVariant.value !== 'rail') {
        const isStaticActive = layoutConfig.menuMode === 'static' && !layoutState.staticMenuInactive;
        return isStaticActive ? '20rem' : '0';
    }
    return railPanelPushesLayout.value ? 'calc(60px + 260px)' : '60px';
});

let timer = null;
onBeforeUnmount(() => {
    clearInterval(timer);
    _heroObserver?.disconnect();
});

const horaAtual = computed(() => {
    const h = agora.value.getHours().toString().padStart(2, '0');
    const m = agora.value.getMinutes().toString().padStart(2, '0');
    return `${h}:${m}`;
});

const saudacao = computed(() => {
    const h = agora.value.getHours();
    if (h < 12) return 'Bom dia';
    if (h < 18) return 'Boa tarde';
    return 'Boa noite';
});

const tenantStore = useTenantStore();
const router = useRouter();

// ── Mini calendário: menu de contexto ────────────────────────
const calDayMenuRef = ref(null);
const calDayMenuItems = computed(() => [
    {
        label: 'Opções do dia',
        items: [
            {
                label: 'Ver dia na agenda da clínica',
                icon: 'pi pi-calendar',
                command: () => verDiaNaAgenda()
            }
        ]
    }
]);

function onCalDayClick(event, day) {
    selectedDay.value = day;
    calDayMenuRef.value?.toggle(event);
}

function verDiaNaAgenda() {
    const d = String(selectedDay.value).padStart(2, '0');
    const m = String(mesAtual + 1).padStart(2, '0');
    router.push(`/admin/agenda/clinica?date=${anoAtual}-${m}-${d}`);
}

// ── Menu de contexto: Eventos do dia ─────────────────────────
const evMenuRef = ref(null);
const _evAtivo = ref(null);

const evMenuItems = computed(() => [
    {
        label: 'Opções',
        items: [
            {
                label: 'Ver na agenda da clínica',
                icon: 'pi pi-calendar',
                command: () => {
                    if (!_evAtivo.value?.inicioISO) return;
                    const d = new Date(_evAtivo.value.inicioISO);
                    const ds = d.toISOString().slice(0, 10);
                    router.push(`/admin/agenda/clinica?date=${ds}`);
                }
            }
        ]
    }
]);

function openEvMenu(event, ev) {
    _evAtivo.value = ev;
    evMenuRef.value?.toggle(event);
}

// ── Dados ─────────────────────────────────────────────────────
const loading = ref(true);
const eventosDoMes = ref([]);
const _solicitacoesBruto = ref([]);
const _cadastrosBruto = ref([]);
const _terapeutasBruto = ref([]);

const diasSemana = ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'];
const hoje = agora.value.getDate();
const mesAtual = agora.value.getMonth();
const anoAtual = agora.value.getFullYear();
const selectedDay = ref(hoje);

const eventMap = computed(() => {
    const map = {};
    for (const ev of eventosDoMes.value) {
        if (!ev.inicio_em) continue;
        const d = new Date(ev.inicio_em);
        if (d.getMonth() !== mesAtual || d.getFullYear() !== anoAtual) continue;
        const day = d.getDate();
        if (!map[day]) map[day] = { count: 0, hasEvent: true };
        map[day].count++;
    }
    for (const day in map) {
        const c = map[day].count;
        map[day].urgency = c >= 8 ? 'urg-alta' : c >= 4 ? 'urg-media' : 'urg-baixa';
    }
    return map;
});

const calCells = computed(() => {
    const primeiroDia = new Date(anoAtual, mesAtual, 1).getDay();
    const totalDias = new Date(anoAtual, mesAtual + 1, 0).getDate();
    const cells = [];
    for (let i = 0; i < primeiroDia; i++) cells.push({ key: 'e' + i, day: null, isOther: true, isToday: false, hasEvent: false, count: 0, urgency: '' });
    for (let d = 1; d <= totalDias; d++) {
        const ev = eventMap.value[d] || {};
        cells.push({ key: 'd' + d, day: d, isToday: d === hoje, isOther: false, hasEvent: !!ev.hasEvent, count: ev.count || 0, urgency: ev.urgency || '' });
    }
    return cells;
});

const labelDiaSelecionado = computed(() => {
    if (selectedDay.value === hoje) return 'Hoje';
    if (selectedDay.value === hoje + 1) return 'Amanhã';
    return `Dia ${selectedDay.value}/${String(mesAtual + 1).padStart(2, '0')}`;
});

const STATUS_ICON = {
    realizado: 'pi pi-check-circle',
    faltou: 'pi pi-times-circle',
    cancelado: 'pi pi-times-circle',
    remarcar: 'pi pi-undo',
    agendado: 'pi pi-clock'
};

function buildEventoItem(ev) {
    const inicio = new Date(ev.inicio_em);
    const fim = ev.fim_em ? new Date(ev.fim_em) : null;
    const durMin = fim ? Math.round((fim - inicio) / 60000) : 50;
    const h = inicio.getHours().toString().padStart(2, '0');
    const m = inicio.getMinutes().toString().padStart(2, '0');
    return {
        id: ev.id,
        hora: `${h}:${m}`,
        dur: `${durMin}min`,
        nome: ev.patients?.nome_completo || ev.titulo || ev.titulo_custom || '—',
        terapeutaNome: _terapeutasBruto.value.find(t => t.user_id === ev.owner_id)?.full_name || '—',
        modalidade: ev.modalidade || 'Presencial',
        recorrente: !!ev.recurrence_id,
        status: ev.status || 'agendado',
        statusIcon: STATUS_ICON[ev.status] || 'pi pi-clock',
        tipo: ev.tipo || 'sessao',
        inicioISO: ev.inicio_em || null
    };
}

const eventosDoDia = computed(() =>
    eventosDoMes.value
        .filter((ev) => {
            if (!ev.inicio_em) return false;
            const d = new Date(ev.inicio_em);
            return d.getDate() === selectedDay.value && d.getMonth() === mesAtual && d.getFullYear() === anoAtual;
        })
        .sort((a, b) => new Date(a.inicio_em) - new Date(b.inicio_em))
        .map(buildEventoItem)
);

// ── Terapeutas com sessões hoje ───────────────────────────────
const terapeutas = computed(() => {
    const eventosHoje = eventosDoMes.value.filter((ev) => {
        if (!ev.inicio_em) return false;
        const d = new Date(ev.inicio_em);
        return d.getDate() === hoje && d.getMonth() === mesAtual && d.getFullYear() === anoAtual && ev.tipo !== 'bloqueio';
    });

    const map = {};
    for (const ev of eventosHoje) {
        const uid = ev.owner_id || '?';
        if (!map[uid]) {
            const membro = _terapeutasBruto.value.find((t) => t.user_id === uid);
            map[uid] = {
                id: uid,
                nome: membro?.full_name || 'Terapeuta',
                sessoesHoje: 0,
                realizadas: 0
            };
        }
        map[uid].sessoesHoje++;
        if (ev.status === 'realizado') map[uid].realizadas++;
    }
    return Object.values(map).sort((a, b) => b.sessoesHoje - a.sessoesHoje).slice(0, 8);
});

// ── Derivados — single pass ────────────────────────────────────
const _statsDoMes = computed(() => {
    const now = agora.value;
    const semIni = new Date(now);
    semIni.setDate(now.getDate() - now.getDay());
    semIni.setHours(0, 0, 0, 0);
    const semFim = new Date(semIni);
    semFim.setDate(semIni.getDate() + 6);
    semFim.setHours(23, 59, 59, 999);

    let hojeCnt = 0, semanaCnt = 0, realizadosCnt = 0, encerradosCnt = 0;
    const hojeLista = [], timelineLista = [];
    const diasSemanaMap = [[], [], [], [], [], [], []];
    const terapeutasAtivosHoje = new Set();

    for (const ev of eventosDoMes.value) {
        if (!ev.inicio_em) continue;
        const d = new Date(ev.inicio_em);
        const dDay = d.getDate(), dMon = d.getMonth(), dYear = d.getFullYear();
        const isHoje = dDay === hoje && dMon === mesAtual && dYear === anoAtual;

        if (isHoje) {
            hojeCnt++;
            hojeLista.push(ev);
            timelineLista.push(ev);
            if (ev.owner_id && ev.tipo !== 'bloqueio') terapeutasAtivosHoje.add(ev.owner_id);
        }
        if (d >= semIni && d <= semFim) {
            semanaCnt++;
            diasSemanaMap[d.getDay()].push(ev);
        }
        if (d < now && ['realizado', 'faltou', 'cancelado'].includes(ev.status)) {
            encerradosCnt++;
            if (ev.status === 'realizado') realizadosCnt++;
        }
    }

    const taxaPresenca = encerradosCnt > 0 ? Math.round((realizadosCnt / encerradosCnt) * 100) : null;
    return { hojeCnt, semanaCnt, taxaPresenca, hojeLista, timelineLista, diasSemanaMap, terapeutasAtivosHoje };
});

const taxaPresenca = computed(() => _statsDoMes.value.taxaPresenca);

const quickStats = computed(() => {
    const pendentes = _solicitacoesBruto.value.length + _cadastrosBruto.value.length;
    const terapAtivos = _statsDoMes.value.terapeutasAtivosHoje.size || _terapeutasBruto.value.length;
    const pct = taxaPresenca.value;
    return [
        { value: String(_statsDoMes.value.hojeCnt), label: 'Sessões Hoje', cls: '' },
        { value: String(terapAtivos), label: 'Terapeutas', cls: '' },
        { value: String(pendentes), label: 'Pendentes', cls: pendentes > 0 ? 'qs-urgente' : '' },
        { value: pct !== null ? `${pct}%` : '—', label: 'Presença', cls: pct !== null && pct >= 85 ? 'qs-ok' : '' }
    ];
});

const resumoHoje = computed(() => {
    const sessoes = _statsDoMes.value.hojeLista.filter((ev) => ev.tipo !== 'bloqueio').length;
    const sols = _solicitacoesBruto.value.length;
    const terapAtivos = _statsDoMes.value.terapeutasAtivosHoje.size;
    const parts = [];
    if (sessoes === 1) parts.push('1 sessão na clínica hoje');
    else if (sessoes > 1) parts.push(`${sessoes} sessões na clínica hoje`);
    else parts.push('Nenhuma sessão hoje');
    if (terapAtivos > 0) parts.push(`${terapAtivos} terapeuta${terapAtivos > 1 ? 's' : ''} ativ${terapAtivos > 1 ? 'os' : 'o'}`);
    if (sols > 0) parts.push(`${sols} solicitaç${sols === 1 ? 'ão' : 'ões'} pendente${sols > 1 ? 's' : ''}`);
    return parts.join(' · ');
});

// ── Solicitações ──────────────────────────────────────────────
function initials(nome) {
    const parts = (nome || '').trim().split(/\s+/);
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}

const solicitacoes = computed(() =>
    _solicitacoesBruto.value.map((s) => {
        const nome = `${s.paciente_nome || ''} ${s.paciente_sobrenome || ''}`.trim() || '—';
        const dia = s.data_solicitada ? new Date(s.data_solicitada + 'T00:00:00').toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' }) : '—';
        const hora = s.hora_solicitada ? String(s.hora_solicitada).slice(0, 5) : '';
        const tipo = s.tipo === 'primeira' ? 'Primeira consulta' : s.tipo === 'retorno' ? 'Retorno' : s.tipo || '—';
        const modal = s.modalidade === 'online' ? 'Online' : s.modalidade === 'presencial' ? 'Presencial' : s.modalidade || '—';
        return { id: s.id, nome, initials: initials(nome), detalhe: `${tipo} · ${modal} · ${dia}${hora ? ' ' + hora : ''}` };
    })
);
const solicitacoesPendentes = computed(() => solicitacoes.value.length);

const cadastros = computed(() =>
    _cadastrosBruto.value.map((c) => {
        const nome = c.nome_completo || '—';
        const criado = c.created_at ? new Date(c.created_at).toLocaleDateString('pt-BR') : '—';
        return { id: c.id, nome, initials: initials(nome), detalhe: `Via portal · ${criado}` };
    })
);
const cadastrosPendentes = computed(() => cadastros.value.length);

// ── Timeline ──────────────────────────────────────────────────
const hoursRange = [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
const TL_START = 7, TL_END = 20, TL_SPAN = TL_END - TL_START;

function toPercent(h, m) {
    return ((h + m / 60 - TL_START) / TL_SPAN) * 100;
}

const timelineEvents = computed(() =>
    _statsDoMes.value.timelineLista
        .slice()
        .sort((a, b) => new Date(a.inicio_em) - new Date(b.inicio_em))
        .map((ev) => {
            const item = buildEventoItem(ev);
            const [hh, mm] = item.hora.split(':').map(Number);
            const durMin = parseInt(item.dur) || 50;
            return {
                id: item.id,
                label: item.nome.split(' ')[0],
                tipo: item.tipo,
                status: item.status,
                tooltip: `${item.hora} · ${item.nome} · ${item.terapeutaNome} · ${item.modalidade}`,
                badge: item.modalidade?.toLowerCase() === 'online' ? '📱' : '',
                style: { left: toPercent(hh, mm) + '%', width: Math.max((durMin / 60 / TL_SPAN) * 100, 4) + '%' }
            };
        })
);

const nowCursorLeft = computed(() => {
    const pct = toPercent(agora.value.getHours(), agora.value.getMinutes());
    return Math.min(Math.max(pct, 0), 100) + '%';
});

// ── Radar da semana ───────────────────────────────────────────
const DIAS_PT = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'];

const radarSemana = computed(() => {
    const diasMap = _statsDoMes.value.diasSemanaMap;
    const dow = agora.value.getDay();
    return DIAS_PT.map((dia, i) => {
        const evs = diasMap[i];
        const total = evs.length;
        const presentes = evs.filter((ev) => ev.status === 'realizado').length;
        const faltas = evs.filter((ev) => ev.status === 'faltou').length;
        let status = 'ok';
        if (faltas > 0 && faltas >= presentes) status = 'falta';
        return { dia, total, pct: total === 0 ? 0 : Math.min(Math.round((total / 12) * 100), 100), status, isToday: i === dow };
    });
});

// ── Ocupação dos terapeutas (card) ────────────────────────────
function hashColor(str) {
    const palette = ['#6366f1', '#0ea5e9', '#ec4899', '#f59e0b', '#22c55e', '#8b5cf6', '#ef4444', '#14b8a6'];
    let h = 0;
    for (let i = 0; i < (str || '').length; i++) h = (h * 31 + str.charCodeAt(i)) & 0xffffffff;
    return palette[Math.abs(h) % palette.length];
}

const ocupacaoTerapeutas = computed(() => {
    const maxSessoes = Math.max(...terapeutas.value.map((t) => t.sessoesHoje), 1);
    return terapeutas.value.map((t) => ({
        ...t,
        pct: Math.round((t.sessoesHoje / maxSessoes) * 100),
        color: hashColor(t.id),
        initials: initials(t.nome)
    }));
});

// ── Load ──────────────────────────────────────────────────────
async function load() {
    loading.value = true;
    await tenantStore.ensureLoaded();
    const tid = tenantStore.activeTenantId || tenantStore.tenantId || null;
    if (!tid) {
        loading.value = false;
        return;
    }

    const mesInicio = new Date(anoAtual, mesAtual, 1, 0, 0, 0, 0).toISOString();
    const mesFim = new Date(anoAtual, mesAtual + 1, 0, 23, 59, 59, 999).toISOString();

    try {
        const [eventosRes, membrosRes, solRes, cadRes] = await Promise.all([
            tenantDb().from('agenda_eventos')
                .select('id, inicio_em, fim_em, status, modalidade, tipo, titulo, titulo_custom, patient_id, owner_id, recurrence_id, patients(nome_completo)')
                
                .gte('inicio_em', mesInicio)
                .lte('inicio_em', mesFim)
                .order('inicio_em', { ascending: true }),
            supabase
                .from('v_tenant_members_with_profiles')
                .select('user_id, full_name, role')
                .eq('tenant_id', tid)
                .in('role', ['therapist', 'tenant_admin'])
                .eq('status', 'active'),
            tenantDb().from('agendador_solicitacoes')
                .select('id, paciente_nome, paciente_sobrenome, tipo, modalidade, data_solicitada, hora_solicitada')
                
                .eq('status', 'pendente')
                .order('created_at', { ascending: false })
                .limit(10),
            tenantDb().from('patient_intake_requests')
                .select('id, nome_completo, status, created_at')
                
                .eq('status', 'new')
                .order('created_at', { ascending: false })
                .limit(10)
        ]);

        eventosDoMes.value = eventosRes.data || [];
        _terapeutasBruto.value = membrosRes.data || [];
        _solicitacoesBruto.value = solRes.data || [];
        _cadastrosBruto.value = cadRes.data || [];

        // KPIs financeiros em paralelo (não bloqueante)
        kpis.load();
    } catch (e) {
        console.error('[ClinicDashboard] load:', e);
    } finally {
        loading.value = false;
    }
}

onMounted(async () => {
    timer = setInterval(() => { agora.value = new Date(); }, 60000);
    _heroObserver = new IntersectionObserver(
        ([entry]) => { heroStuck.value = !entry.isIntersecting; },
        { threshold: 0 }
    );
    if (dashHeroSentinelRef.value) _heroObserver.observe(dashHeroSentinelRef.value);
    await load();
});
</script>

<template>
    <div class="flex min-h-[calc(100vh-4.5rem)] bg-[var(--surface-ground,#f5f7fa)]">
        <!-- ═══════════════════════════════════════
         OVERLAY (mobile) + ASIDE
        ══════════════════════════════════════════ -->
        <div v-if="asideOpen" class="fixed inset-0 bg-black/40 backdrop-blur-sm z-[39] xl:hidden" @click="asideOpen = false" />

        <aside
            class="aside-drawer flex flex-col overflow-y-auto shrink-0 bg-[var(--surface-card,#fff)] border-r border-[var(--surface-border,#e2e8f0)]"
            :class="asideOpen ? 'translate-x-0 visible' : 'max-xl:-translate-x-full max-xl:invisible'"
            :style="{ left: asideLeft }"
        >
            <!-- Mini calendário -->
            <div class="p-3.5 pb-2.5 border-b border-[var(--surface-border,#e2e8f0)]">
                <div class="flex items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary,#64748b)] mb-2.5">
                    <i class="pi pi-calendar" />
                    <span>{{ new Date(anoAtual, mesAtual).toLocaleDateString('pt-BR', { month: 'long', year: 'numeric' }) }}</span>
                </div>

                <template v-if="loading">
                    <div class="grid grid-cols-7 mb-0.5">
                        <Skeleton v-for="n in 7" :key="n" height="14px" class="mx-0.5" />
                    </div>
                    <div class="grid grid-cols-7 gap-px mt-1">
                        <Skeleton v-for="n in 35" :key="n" height="22px" class="rounded" />
                    </div>
                </template>

                <template v-else>
                    <div class="grid grid-cols-7 mb-0.5">
                        <span v-for="d in diasSemana" :key="d" class="text-center text-xs font-bold text-[var(--text-color-secondary,#94a3b8)] py-0.5">{{ d }}</span>
                    </div>
                    <div class="grid grid-cols-7 gap-px">
                        <button
                            v-for="cell in calCells"
                            :key="cell.key"
                            class="relative aspect-square flex items-center justify-center text-xs font-medium rounded border-none cursor-pointer transition-colors duration-100"
                            :class="{
                                'bg-[var(--primary-color,#6366f1)] text-white font-bold rounded-md': cell.isToday,
                                'text-[var(--text-color-secondary,#cbd5e1)] cursor-default': cell.isOther,
                                'bg-indigo-500/10 text-[var(--primary-color,#6366f1)] font-bold': cell.day === selectedDay && !cell.isToday,
                                'text-[var(--text-color,#1e293b)] hover:bg-[var(--surface-hover,#f1f5f9)]': !cell.isToday && !cell.isOther
                            }"
                            @click="cell.day && onCalDayClick($event, cell.day)"
                        >
                            <span>{{ cell.day }}</span>
                            <span
                                v-if="cell.count"
                                class="absolute bottom-px right-0.5 w-1 h-1 rounded-full"
                                :class="{
                                    'bg-red-500': cell.urgency === 'urg-alta',
                                    'bg-amber-500': cell.urgency === 'urg-media',
                                    'bg-green-500': cell.urgency === 'urg-baixa'
                                }"
                            />
                        </button>
                    </div>
                </template>
            </div>

            <!-- Eventos do dia (clínica toda) -->
            <div class="p-3.5 pb-2.5 border-b border-[var(--surface-border,#e2e8f0)]">
                <div class="flex items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary,#64748b)] mb-2.5">
                    <i class="pi pi-clock" /><span>{{ labelDiaSelecionado }}</span>
                </div>

                <template v-if="loading">
                    <div class="flex flex-col gap-2">
                        <div v-for="n in 3" :key="n" class="aside-ev aside-ev--skeleton">
                            <div class="flex flex-col gap-1 min-w-[36px] items-end">
                                <Skeleton width="32px" height="10px" />
                                <Skeleton width="24px" height="8px" />
                            </div>
                            <Skeleton shape="square" size="28px" border-radius="4px" />
                            <div class="flex flex-col gap-1.5 flex-1">
                                <Skeleton :width="n === 1 ? '75%' : n === 2 ? '60%' : '70%'" height="10px" />
                                <Skeleton width="40%" height="8px" />
                            </div>
                        </div>
                    </div>
                </template>

                <div v-else class="flex flex-col gap-2 max-h-[260px] overflow-y-auto pr-0.5">
                    <div
                        v-for="ev in eventosDoDia"
                        :key="ev.id"
                        class="aside-ev aside-ev--default"
                        :class="{
                            'aside-ev--reuniao': ev.tipo === 'reuniao',
                            'aside-ev--realizado': ev.status === 'realizado'
                        }"
                        @click="openEvMenu($event, ev)"
                    >
                        <div class="aside-ev__time">
                            <span class="aside-ev__hora">{{ ev.hora }}</span>
                            <span class="aside-ev__dur">{{ ev.dur }}</span>
                        </div>
                        <Avatar :label="initials(ev.nome)" shape="square" size="small" class="shrink-0" />
                        <div class="flex-1 min-w-0">
                            <span class="block text-[0.8125rem] font-semibold truncate text-[var(--text-color)]">{{ ev.nome }}</span>
                            <div class="flex gap-1.5 mt-0.5 items-center">
                                <span class="aside-ev__badge">{{ ev.terapeutaNome.split(' ')[0] }}</span>
                                <i v-if="ev.recorrente" class="pi pi-sync text-[0.6rem] text-[var(--primary-color,#6366f1)]" title="Recorrente" />
                            </div>
                        </div>
                        <i :class="ev.statusIcon" class="text-xs text-[var(--text-color-secondary)] shrink-0" />
                    </div>
                    <div v-if="!eventosDoDia.length" class="flex items-center gap-2 py-3 text-[var(--text-color-secondary)] text-sm"><i class="pi pi-sun" /><span>Sem compromissos</span></div>
                </div>
            </div>

            <!-- Terapeutas com sessões hoje -->
            <div class="p-3.5 pb-2.5">
                <div class="flex items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-[var(--text-color-secondary,#64748b)] mb-2.5">
                    <i class="pi pi-users" /><span>Terapeutas hoje</span>
                    <span class="ml-auto bg-[var(--primary-color,#6366f1)] text-white rounded-full px-1.5 text-xs font-bold">{{ terapeutas.length }}</span>
                </div>

                <template v-if="loading">
                    <div class="flex flex-col gap-2">
                        <div v-for="n in 4" :key="n" class="aside-rec aside-rec--skeleton">
                            <Skeleton shape="square" size="30px" border-radius="4px" />
                            <div class="flex flex-col gap-1.5 flex-1">
                                <Skeleton :width="n % 2 === 0 ? '65%' : '50%'" height="10px" />
                                <Skeleton width="75%" height="8px" />
                            </div>
                            <Skeleton width="28px" height="10px" />
                        </div>
                    </div>
                </template>

                <div v-else class="flex flex-col gap-1.5 max-h-[220px] overflow-y-auto pr-0.5">
                    <div v-for="t in terapeutas" :key="t.id" class="aside-rec">
                        <Avatar :label="initials(t.nome)" shape="square" size="normal" class="shrink-0" :style="{ backgroundColor: hashColor(t.id) + '22', color: hashColor(t.id) }" />
                        <div class="flex-1 min-w-0">
                            <span class="block text-[0.8125rem] font-semibold truncate text-[var(--text-color)]">{{ t.nome.split(' ').slice(0, 2).join(' ') }}</span>
                            <span class="block text-xs text-[var(--text-color-secondary)]">{{ t.sessoesHoje }} sessão{{ t.sessoesHoje !== 1 ? 'ões' : '' }}</span>
                        </div>
                        <div class="aside-rec__prox text-[var(--primary-color,#6366f1)] font-bold">{{ t.sessoesHoje }}</div>
                    </div>
                    <div v-if="!terapeutas.length" class="flex items-center gap-2 py-3 text-[var(--text-color-secondary)] text-sm"><i class="pi pi-info-circle" /><span>Nenhum terapeuta com sessão hoje</span></div>
                </div>
            </div>
        </aside>

        <!-- ═══════════════════════════════════════
         CONTEÚDO PRINCIPAL
        ══════════════════════════════════════════ -->
        <div ref="dashHeroSentinelRef" class="h-px" />

        <main class="flex-1 min-w-0 p-4 xl:p-[1.125rem_1.375rem] flex flex-col gap-4 overflow-y-auto" :style="{ marginLeft: isMobileLayout ? undefined : '272px' }">

            <!-- Hero Header — Skeleton -->
            <section v-if="loading" class="relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 mx-3 md:mx-4 mt-4">
                <div class="flex items-center gap-3">
                    <Skeleton width="40px" height="40px" border-radius="6px" />
                    <div class="flex flex-col gap-1.5 flex-1">
                        <Skeleton width="12rem" height="14px" />
                        <Skeleton width="18rem" height="11px" />
                    </div>
                    <Skeleton width="36px" height="36px" border-radius="999px" />
                    <Skeleton width="36px" height="36px" border-radius="999px" />
                </div>
            </section>

            <!-- Quick stats — Skeleton -->
            <section v-if="loading" class="grid grid-cols-2 md:grid-cols-4 gap-2.5 mx-3 md:mx-4 mb-4">
                <div v-for="n in 4" :key="n" class="flex flex-col gap-1.5 px-4 py-2.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)]">
                    <Skeleton width="2rem" height="20px" />
                    <Skeleton width="4rem" height="10px" />
                </div>
            </section>

            <!-- Hero Header -->
            <section
                v-if="!loading"
                class="sticky mx-3 md:mx-4 mt-4 mb-4 z-20 overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5"
                :style="{ top: 'var(--layout-sticky-top, 56px)' }"
                :class="{ 'rounded-tl-none rounded-tr-none': heroStuck }"
            >
                <div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
                    <div class="absolute rounded-full blur-[70px] w-72 h-72 -top-16 -right-20 bg-indigo-400/10" />
                    <div class="absolute rounded-full blur-[70px] w-80 h-80 top-10 -left-24 bg-emerald-400/10" />
                    <div class="absolute rounded-full blur-[70px] w-72 h-72 -bottom-20 right-24 bg-fuchsia-400/10" />
                </div>
                <div class="relative z-10 flex items-center justify-between gap-3 flex-wrap">
                    <div class="flex items-center gap-3 flex-1 min-w-0">
                        <div class="grid place-items-center w-10 h-10 rounded-md shrink-0 bg-indigo-500/10 text-indigo-600 dark:text-indigo-400">
                            <i class="pi pi-building text-lg" />
                        </div>
                        <div class="min-w-0">
                            <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">{{ saudacao }} <span class="text-[var(--primary-color,#6366f1)]">👋</span></div>
                            <div class="text-[0.78rem] text-[var(--text-color-secondary)] mt-0.5">{{ resumoHoje }}</div>
                        </div>
                    </div>
                    <div class="flex items-center gap-2 shrink-0">
                        <Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Recarregar" @click="load" />
                        <Button icon="pi pi-cog" severity="secondary" outlined class="h-9 w-9 rounded-full" title="Configurações" @click="$router.push('/configuracoes')" />
                    </div>
                </div>
            </section>

            <!-- Quick stats (separados do hero) -->
            <section v-if="!loading" class="grid grid-cols-2 md:grid-cols-4 gap-2.5 mx-3 md:mx-4 mb-4">
                <div
                    v-for="s in quickStats"
                    :key="s.label"
                    class="flex flex-col gap-0.5 px-4 py-3 rounded-md border transition-colors duration-150"
                    :class="{
                        'border-red-500/25 bg-red-500/5': s.cls === 'qs-urgente',
                        'border-green-500/25 bg-green-500/5': s.cls === 'qs-ok',
                        'border-[var(--surface-border)] bg-[var(--surface-card)]': !s.cls
                    }"
                >
                    <div
                        class="text-[1.35rem] font-bold leading-none"
                        :class="{
                            'text-red-500': s.cls === 'qs-urgente',
                            'text-green-500': s.cls === 'qs-ok',
                            'text-[var(--text-color)]': !s.cls
                        }"
                    >
                        {{ s.value }}
                    </div>
                    <div class="text-[0.7rem] text-[var(--text-color-secondary)] opacity-75 truncate">{{ s.label }}</div>
                </div>
            </section>

            <!-- ═══════════════════════════════════════
                 KPIs financeiros/operacionais (Fase 3a)
                ══════════════════════════════════════════ -->
            <section v-if="!loading" class="flex flex-col gap-3">
                <!-- Cards KPI -->
                <div class="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-6 gap-2.5">
                    <div class="flex flex-col gap-0.5 px-4 py-3 rounded-md border border-emerald-500/25 bg-emerald-500/5">
                        <div class="text-[0.7rem] text-[var(--text-color-secondary)] uppercase tracking-wide">Recebido no mês</div>
                        <div class="text-[1.25rem] font-bold text-emerald-600 leading-tight">{{ fmtBRL(kpis.mrrCurrentCents.value) }}</div>
                        <div class="text-[0.68rem] text-[var(--text-color-secondary)] opacity-75">
                            Ticket médio: {{ fmtBRL(kpis.avgTicket.value) }}
                        </div>
                    </div>

                    <div
                        class="flex flex-col gap-0.5 px-4 py-3 rounded-md border"
                        :class="kpis.overdueCount.value > 0 ? 'border-red-500/25 bg-red-500/5' : 'border-[var(--surface-border)] bg-[var(--surface-ground)]'"
                    >
                        <div class="text-[0.7rem] text-[var(--text-color-secondary)] uppercase tracking-wide">Inadimplência</div>
                        <div class="text-[1.25rem] font-bold leading-tight" :class="kpis.overdueCount.value > 0 ? 'text-red-500' : 'text-[var(--text-color)]'">
                            {{ fmtBRL(kpis.overdueCents.value) }}
                        </div>
                        <div class="text-[0.68rem] text-[var(--text-color-secondary)] opacity-75">
                            {{ kpis.overdueCount.value }} recebível(is) em atraso
                        </div>
                    </div>

                    <div class="flex flex-col gap-0.5 px-4 py-3 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)]">
                        <div class="text-[0.7rem] text-[var(--text-color-secondary)] uppercase tracking-wide">A receber</div>
                        <div class="text-[1.25rem] font-bold text-[var(--text-color)] leading-tight">{{ fmtBRL(kpis.pendingCents.value) }}</div>
                        <div class="text-[0.68rem] text-[var(--text-color-secondary)] opacity-75">Pendentes no mês</div>
                    </div>

                    <div class="flex flex-col gap-0.5 px-4 py-3 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)]">
                        <div class="text-[0.7rem] text-[var(--text-color-secondary)] uppercase tracking-wide">Pacientes</div>
                        <div class="text-[1.25rem] font-bold text-[var(--text-color)] leading-tight">
                            {{ kpis.activePatients.value }}
                            <span class="text-[0.75rem] text-[var(--text-color-secondary)] font-normal">/ {{ kpis.totalPatients.value }}</span>
                        </div>
                        <div class="text-[0.68rem] text-[var(--text-color-secondary)] opacity-75">Ativos · {{ kpis.inactivePatients.value }} inativos</div>
                    </div>

                    <div class="flex flex-col gap-0.5 px-4 py-3 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)]">
                        <div class="text-[0.7rem] text-[var(--text-color-secondary)] uppercase tracking-wide">Sessões no mês</div>
                        <div class="text-[1.25rem] font-bold text-[var(--text-color)] leading-tight">{{ kpis.sessionsDone.value }}</div>
                        <div class="text-[0.68rem] text-[var(--text-color-secondary)] opacity-75">
                            de {{ kpis.sessionsScheduled.value }} agendadas
                        </div>
                    </div>

                    <div
                        class="flex flex-col gap-0.5 px-4 py-3 rounded-md border"
                        :class="(kpis.noShowRate.value ?? 0) > 15 ? 'border-amber-500/25 bg-amber-500/5' : 'border-[var(--surface-border)] bg-[var(--surface-ground)]'"
                    >
                        <div class="text-[0.7rem] text-[var(--text-color-secondary)] uppercase tracking-wide">Taxa de falta</div>
                        <div class="text-[1.25rem] font-bold leading-tight" :class="(kpis.noShowRate.value ?? 0) > 15 ? 'text-amber-600' : 'text-[var(--text-color)]'">
                            {{ kpis.noShowRate.value !== null ? kpis.noShowRate.value + '%' : '—' }}
                        </div>
                        <div class="text-[0.68rem] text-[var(--text-color-secondary)] opacity-75">
                            {{ kpis.sessionsNoShow.value }} faltas · {{ kpis.sessionsCancelled.value }} cancel.
                        </div>
                    </div>
                </div>

                <!-- Grid: gráfico 6 meses + top pacientes -->
                <div class="grid grid-cols-1 xl:grid-cols-[1fr_320px] gap-3">
                    <!-- Gráfico de receita (barras SVG simples) -->
                    <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-4">
                        <div class="flex items-center justify-between mb-3">
                            <div class="text-sm font-semibold text-[var(--text-color)]">Receita recebida · últimos 6 meses</div>
                            <i class="pi pi-chart-bar text-[var(--text-color-secondary)]" />
                        </div>
                        <div v-if="!kpis.revenueSeries.value.length" class="text-xs text-[var(--text-color-secondary)] py-6 text-center">
                            Sem dados no período.
                        </div>
                        <div v-else class="flex items-end gap-2 h-40">
                            <div
                                v-for="(m, i) in kpis.revenueSeries.value"
                                :key="i"
                                class="flex-1 flex flex-col items-center gap-1 min-w-0"
                            >
                                <div class="text-[0.65rem] text-[var(--text-color-secondary)] truncate w-full text-center">
                                    {{ fmtBRL(m.received) }}
                                </div>
                                <div
                                    class="w-full bg-emerald-500/70 rounded-t-md transition-all duration-300 min-h-[2px]"
                                    :style="{ height: `${Math.max(2, (m.received / revenueMax) * 130)}px` }"
                                />
                                <div class="text-[0.68rem] text-[var(--text-color-secondary)] uppercase">{{ m.label }}</div>
                            </div>
                        </div>
                    </div>

                    <!-- Top 5 pacientes -->
                    <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-4">
                        <div class="flex items-center justify-between mb-3">
                            <div class="text-sm font-semibold text-[var(--text-color)]">Top pacientes · 6 meses</div>
                            <i class="pi pi-users text-[var(--text-color-secondary)]" />
                        </div>
                        <div v-if="!kpis.topPatients.value.length" class="text-xs text-[var(--text-color-secondary)] py-6 text-center">
                            Sem dados.
                        </div>
                        <ol v-else class="flex flex-col gap-1.5">
                            <li
                                v-for="(p, i) in kpis.topPatients.value"
                                :key="p.patient_id"
                                class="flex items-center justify-between gap-2 text-xs"
                            >
                                <div class="flex items-center gap-2 min-w-0 flex-1">
                                    <span class="w-5 h-5 rounded-full bg-[var(--surface-ground)] grid place-items-center text-[0.65rem] font-bold shrink-0">{{ i + 1 }}</span>
                                    <span class="truncate text-[var(--text-color)]">{{ p.nome_completo }}</span>
                                </div>
                                <span class="font-semibold text-emerald-600 shrink-0">{{ fmtBRL(p.total) }}</span>
                            </li>
                        </ol>
                    </div>
                </div>
            </section>

            <!-- Toggle aside — só mobile -->
            <button
                class="xl:hidden flex w-full items-center justify-between gap-3 px-4 py-3 bg-[var(--surface-card,#fff)] border-b border-[var(--surface-border,#e2e8f0)] text-sm font-semibold text-[var(--text-color)] cursor-pointer sticky top-0 z-30"
                @click="asideOpen = !asideOpen"
            >
                <div class="flex items-center gap-2 min-w-0">
                    <i class="pi pi-calendar-clock text-[var(--primary-color,#6366f1)]" />
                    <span class="truncate">Agenda · {{ labelDiaSelecionado }}</span>
                    <span v-if="eventosDoDia.length" class="inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-xs font-bold shrink-0">{{ eventosDoDia.length }}</span>
                </div>
                <i class="pi transition-transform duration-200" :class="asideOpen ? 'pi-chevron-up' : 'pi-chevron-down'" />
            </button>

            <!-- Linha do tempo — Skeleton -->
            <section v-if="loading" class="bg-[var(--surface-card)] rounded-md border border-[var(--surface-border)] p-2.5">
                <div class="flex items-center justify-between mb-2.5">
                    <Skeleton width="12rem" height="12px" />
                    <Skeleton width="6rem" height="12px" />
                </div>
                <Skeleton width="100%" height="40px" border-radius="6px" class="mt-2.5" />
            </section>

            <!-- Linha do tempo -->
            <section v-if="!loading" class="bg-[var(--surface-card,#fff)] rounded-md border border-[var(--surface-border,#e2e8f0)] p-2.5 shadow-[0_0_0_3px_color-mix(in_srgb,var(--primary-color)_7%,transparent)]">
                <div class="flex items-center justify-between mb-2.5">
                    <div class="flex items-center gap-2.5">
                        <div class="grid place-items-center w-10 h-10 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
                            <i class="pi pi-chart-bar text-lg" />
                        </div>
                        <div class="flex flex-col leading-tight">
                            <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Linha do tempo — Hoje</div>
                            <div class="text-xs font-semibold text-[var(--text-color-secondary)] flex items-center gap-1.5">
                                <span class="pulse-dot w-[15px] h-[5px] rounded-full bg-red-500"></span>
                                Agora: {{ horaAtual }}
                            </div>
                        </div>
                    </div>
                    <Button icon="pi pi-calendar" severity="secondary" outlined class="rounded-full" title="Agenda da Clínica" label="Agenda" @click="$router.push('/admin/agenda/clinica')" />
                </div>
                <div class="mt-2.5 relative">
                    <div class="flex justify-between mb-1">
                        <div v-for="h in hoursRange" :key="h" class="flex-1 text-left">
                            <span class="text-[0.80rem] text-[var(--text-color-secondary)] font-semibold">{{ h }}h</span>
                        </div>
                    </div>
                    <div class="relative h-10 bg-[var(--surface-ground,#f8fafc)] rounded-md overflow-visible">
                        <div
                            v-for="ev in timelineEvents"
                            :key="ev.id"
                            class="absolute top-[3px] h-[34px] rounded flex items-center px-1.5 overflow-hidden cursor-default min-w-[32px] hover:brightness-110 transition-[filter] duration-150 z-10"
                            :style="ev.style"
                            :class="{
                                'bg-sky-400': ev.tipo === 'reuniao',
                                'bg-green-500': ev.status === 'realizado',
                                'bg-[var(--primary-color,#6366f1)]': ev.tipo !== 'reuniao' && ev.status !== 'realizado'
                            }"
                            :title="ev.tooltip"
                        >
                            <span class="text-[0.58rem] font-bold text-white truncate">{{ ev.label }}</span>
                            <span v-if="ev.badge" class="text-xs ml-auto">{{ ev.badge }}</span>
                        </div>
                        <div class="absolute top-0 h-full flex flex-col items-center pointer-events-none z-20" :style="{ left: nowCursorLeft }">
                            <div class="w-0.5 h-full bg-red-500 opacity-80" />
                            <div class="absolute -top-0.5 w-[7px] h-[7px] rounded-full bg-red-500" />
                        </div>
                    </div>
                </div>
            </section>

            <!-- Cards de notificação -->
            <section class="grid grid-cols-1 lg:grid-cols-2 gap-3.5">
                <!-- Skeleton -->
                <template v-if="loading">
                    <div v-for="n in 4" :key="n" class="flex flex-col bg-[var(--surface-card,#fff)] rounded-md border border-[var(--surface-border,#e2e8f0)]">
                        <div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2 border-b border-[var(--surface-border,#f1f5f9)] bg-[var(--surface-ground,#f8fafc)]">
                            <Skeleton width="32px" height="32px" border-radius="6px" />
                            <div class="flex flex-col gap-1.5 flex-1">
                                <Skeleton :width="n % 2 === 0 ? '9rem' : '7rem'" height="12px" />
                                <Skeleton :width="n % 3 === 0 ? '13rem' : '10rem'" height="10px" />
                            </div>
                        </div>
                        <div class="flex-1 flex flex-col gap-2 px-3.5 py-3 min-h-[72px]">
                            <div v-for="i in 2" :key="i" class="flex items-center gap-2">
                                <Skeleton shape="circle" size="26px" />
                                <div class="flex flex-col gap-1 flex-1">
                                    <Skeleton :width="i === 1 ? '65%' : '50%'" height="10px" />
                                    <Skeleton width="75%" height="9px" />
                                </div>
                            </div>
                        </div>
                        <div class="px-3.5 py-2 border-t border-[var(--surface-border,#f1f5f9)]">
                            <Skeleton width="5rem" height="10px" />
                        </div>
                    </div>
                    <div class="lg:col-span-2">
                        <AppLoadingPhrases action="Carregando o painel da clínica..." containerClass="py-8" />
                    </div>
                </template>

                <!-- Agendamentos Recebidos -->
                <div v-if="!loading" class="dash-card rounded-md">
                    <div class="dash-card__head gap-2.5 p-2.5">
                        <div class="grid place-items-center w-10 h-10 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
                            <i class="pi pi-inbox text-lg" />
                        </div>
                        <div>
                            <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Agendamentos Recebidos</div>
                            <div class="dash-card__sub">Solicitações vindas do agendador online</div>
                        </div>
                        <span
                            v-if="solicitacoesPendentes > 0"
                            class="dash-card__badge"
                            style="background: color-mix(in srgb, #ef4444 10%, transparent); color: #ef4444; border: 1px solid color-mix(in srgb, #ef4444 30%, transparent)"
                        >{{ solicitacoesPendentes }}</span>
                    </div>
                    <div class="dash-card__body">
                        <div v-for="sol in solicitacoes" :key="sol.id" class="dash-item bg-[color-mix(in_srgb,var(--surface-ground)_50%,transparent)] p-2 gap-2 rounded-md">
                            <Avatar :label="sol.initials" shape="square" size="normal" />
                            <div class="min-w-0 flex-1">
                                <div class="dash-item__name">{{ sol.nome }}</div>
                                <div class="dash-item__sub">{{ sol.detalhe }}</div>
                            </div>
                            <button
                                class="w-8 h-8 rounded-full border border-[var(--surface-border)] bg-[var(--surface-ground)] text-[var(--text-color-secondary)] flex items-center justify-center transition-all hover:bg-[var(--primary-color)] hover:text-white hover:border-[var(--primary-color)]"
                                @click="$router.push('/admin/agendamentos-recebidos')"
                            >
                                <i class="pi pi-arrow-right text-xs" />
                            </button>
                        </div>
                        <div v-if="!solicitacoes.length" class="dash-empty"><i class="pi pi-check-circle" /> Nenhuma solicitação pendente</div>
                    </div>
                    <div class="dash-card__foot" @click="$router.push('/admin/agendamentos-recebidos')">Ver todas →</div>
                </div>

                <!-- Analytics: tempo de 1ª resposta WhatsApp -->
                <FirstResponseCard v-if="!loading" />

                <!-- Cadastros externos -->
                <div v-if="!loading" class="dash-card">
                    <div class="dash-card__head gap-2.5 p-2.5">
                        <div class="grid place-items-center w-10 h-10 rounded-md shrink-0" style="background: color-mix(in srgb, #0ea5e9 15%, transparent); color: #0ea5e9">
                            <i class="pi pi-user-plus text-lg" />
                        </div>
                        <div>
                            <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Cadastros Externos</div>
                            <div class="dash-card__sub">Pacientes que preencheram seus próprios dados</div>
                        </div>
                        <span
                            v-if="cadastrosPendentes > 0"
                            class="dash-card__badge"
                            style="background: color-mix(in srgb, #0ea5e9 10%, transparent); color: #0ea5e9; border: 1px solid color-mix(in srgb, #0ea5e9 30%, transparent)"
                        >{{ cadastrosPendentes }}</span>
                    </div>
                    <div class="dash-card__body">
                        <div v-for="c in cadastros" :key="c.id" class="dash-item bg-[color-mix(in_srgb,var(--surface-ground)_50%,transparent)] p-2 gap-2 rounded-md">
                            <Avatar :label="c.initials" shape="square" size="normal" />
                            <div class="min-w-0 flex-1">
                                <div class="dash-item__name">{{ c.nome }}</div>
                                <div class="dash-item__sub">{{ c.detalhe }}</div>
                            </div>
                            <button
                                class="w-8 h-8 rounded-full border border-[var(--surface-border)] bg-[var(--surface-ground)] text-[var(--text-color-secondary)] flex items-center justify-center transition-all hover:bg-[var(--primary-color)] hover:text-white hover:border-[var(--primary-color)]"
                                @click="$router.push('/admin/pacientes/cadastro/recebidos')"
                            >
                                <i class="pi pi-arrow-right text-xs" />
                            </button>
                        </div>
                        <div v-if="!cadastros.length" class="dash-empty"><i class="pi pi-check-circle" /> Nenhum cadastro pendente</div>
                    </div>
                    <div class="dash-card__foot" @click="$router.push('/admin/pacientes/cadastro/recebidos')">Gerenciar triagem →</div>
                </div>

                <!-- Ocupação dos terapeutas -->
                <div v-if="!loading" class="dash-card">
                    <div class="dash-card__head gap-2.5 p-2.5">
                        <div class="grid place-items-center w-10 h-10 rounded-md shrink-0" style="background: color-mix(in srgb, #8b5cf6 15%, transparent); color: #8b5cf6">
                            <i class="pi pi-users text-lg" />
                        </div>
                        <div>
                            <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Ocupação dos Terapeutas</div>
                            <div class="dash-card__sub">Sessões este mês por profissional</div>
                        </div>
                        <span class="dash-card__badge" style="background: color-mix(in srgb, #8b5cf6 10%, transparent); color: #8b5cf6; border: 1px solid color-mix(in srgb, #8b5cf6 30%, transparent)">
                            {{ ocupacaoTerapeutas.length }}
                        </span>
                    </div>
                    <div class="dash-card__body" style="min-height: auto">
                        <div v-if="ocupacaoTerapeutas.length" class="flex flex-col gap-2.5 py-1">
                            <div v-for="t in ocupacaoTerapeutas" :key="t.id" class="flex items-center gap-2.5">
                                <Avatar
                                    :label="t.initials"
                                    shape="square"
                                    size="small"
                                    class="shrink-0"
                                    :style="{ backgroundColor: t.color + '22', color: t.color }"
                                />
                                <div class="flex-1 min-w-0">
                                    <div class="text-xs font-semibold text-[var(--text-color)] truncate mb-1">{{ t.nome.split(' ').slice(0, 2).join(' ') }}</div>
                                    <div class="h-1.5 rounded-full bg-[var(--surface-border)] overflow-hidden">
                                        <div class="h-full rounded-full transition-all duration-500" :style="{ width: t.pct + '%', backgroundColor: t.color }" />
                                    </div>
                                </div>
                                <span class="text-xs font-bold text-[var(--text-color-secondary)] shrink-0 min-w-[2rem] text-right">{{ t.sessoesHoje }}</span>
                            </div>
                        </div>
                        <div v-else class="dash-empty"><i class="pi pi-info-circle" /> Nenhum terapeuta com sessão hoje</div>
                    </div>
                    <div class="dash-card__foot" @click="$router.push('/admin/clinic/professionals')">Ver profissionais →</div>
                </div>

                <!-- Radar da semana -->
                <div v-if="!loading" class="dash-card">
                    <div class="dash-card__head gap-2.5 p-2.5">
                        <div class="grid place-items-center w-10 h-10 rounded-md shrink-0" style="background: color-mix(in srgb, #6366f1 15%, transparent); color: #6366f1">
                            <i class="pi pi-chart-pie text-lg" />
                        </div>
                        <div>
                            <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Radar da Semana</div>
                            <div class="dash-card__sub">Sessões e faltas da clínica</div>
                        </div>
                    </div>
                    <div class="dash-card__body" style="min-height: auto">
                        <div class="flex gap-1.5 items-end h-[88px] mt-6">
                            <div v-for="d in radarSemana" :key="d.dia" class="flex-1 flex flex-col items-center gap-1">
                                <div class="flex-1 w-full flex items-end">
                                    <div class="w-full h-[68px] bg-[var(--surface-ground)] rounded overflow-hidden flex items-end">
                                        <div
                                            class="w-full rounded transition-all duration-500 ease-in-out"
                                            :style="{ height: d.pct + '%' }"
                                            :class="{
                                                'bg-gradient-to-t from-indigo-500 to-indigo-400': d.status === 'ok',
                                                'bg-gradient-to-t from-red-500 to-red-300': d.status === 'falta'
                                            }"
                                        />
                                    </div>
                                </div>
                                <span class="text-sm font-semibold" :class="d.isToday ? 'text-[var(--primary-color)] font-extrabold' : 'text-[var(--text-color-secondary)]'">{{ d.dia }}</span>
                                <span class="text-xs text-[var(--text-color-secondary)]">{{ d.total }}</span>
                            </div>
                        </div>
                        <div class="flex gap-3 mt-2 flex-wrap">
                            <span class="flex items-center gap-1.5 text-sm text-[var(--text-color-secondary)] font-semibold"><span class="w-4 h-2.5 rounded-sm bg-gradient-to-r from-indigo-500 to-indigo-400 shrink-0" />Sessões</span>
                            <span class="flex items-center gap-1.5 text-sm text-[var(--text-color-secondary)] font-semibold"><span class="w-4 h-2.5 rounded-sm bg-gradient-to-r from-red-500 to-red-300 shrink-0" />Faltas</span>
                        </div>
                    </div>
                </div>
            </section>

            <LoadedPhraseBlock v-if="!loading" />
        </main>

        <!-- Menus de contexto -->
        <Menu ref="calDayMenuRef" :model="calDayMenuItems" :popup="true" />
        <Menu ref="evMenuRef" :model="evMenuItems" :popup="true" />
    </div>
</template>

<style scoped>
.aside-drawer {
    position: fixed;
    top: calc(56px + var(--notice-banner-height, 0px));
    left: 0;
    height: calc(100dvh - 56px - var(--notice-banner-height, 0px));
    width: min(300px, 85vw);
    z-index: 40;
    overflow-y: auto;
    transition:
        transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
        visibility 0.25s;
    box-shadow: 4px 0 24px rgba(0, 0, 0, 0.15);
}
@media (min-width: 1280px) {
    .aside-drawer {
        position: fixed;
        top: calc(56px + var(--notice-banner-height, 0px));
        height: calc(100vh - 56px - var(--notice-banner-height, 0px));
        width: 272px;
        transform: none;
        visibility: visible;
        box-shadow: none;
        z-index: auto;
        overflow-y: auto;
    }
}

.pulse-dot {
    animation: pulse-red 1.5s infinite;
}
@keyframes pulse-red {
    0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); }
    50% { box-shadow: 0 0 0 4px rgba(239, 68, 68, 0); }
}

/* ── Aside: Eventos do dia ───────────────────────── */
.aside-ev {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.625rem;
    border-radius: 8px;
    border-left: 3px solid var(--ev-color, var(--primary-color, #6366f1));
    background: var(--surface-ground, #f8fafc);
    cursor: pointer;
    transition: background 0.12s, box-shadow 0.12s;
}
.aside-ev:hover {
    background: var(--surface-hover, #f1f5f9);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.aside-ev--reuniao   { --ev-color: #38bdf8; }
.aside-ev--realizado { --ev-color: #22c55e; }
.aside-ev--default   { --ev-color: var(--primary-color, #6366f1); }
.aside-ev--skeleton  { cursor: default; pointer-events: none; }

.aside-ev__time {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    min-width: 36px;
    flex-shrink: 0;
    gap: 1px;
}
.aside-ev__hora {
    font-size: 0.78rem;
    font-weight: 800;
    color: var(--text-color);
    letter-spacing: -0.01em;
    line-height: 1;
}
.aside-ev__dur {
    font-size: 0.68rem;
    color: var(--text-color-secondary);
    line-height: 1;
}
.aside-ev__badge {
    font-size: 0.68rem;
    font-weight: 600;
    padding: 1px 6px;
    border-radius: 4px;
    background: var(--surface-border, #e2e8f0);
    color: var(--text-color-secondary);
    line-height: 1.5;
    white-space: nowrap;
}

/* ── Aside: Terapeutas ───────────────────────────── */
.aside-rec {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.45rem 0.5rem;
    border-radius: 8px;
    border: 1px solid transparent;
    cursor: default;
    transition: background 0.12s, border-color 0.12s;
}
.aside-rec:hover {
    background: var(--surface-ground, #f8fafc);
    border-color: var(--surface-border, #e2e8f0);
}
.aside-rec--skeleton { cursor: default; pointer-events: none; }
.aside-rec__prox {
    font-size: 0.72rem;
    white-space: nowrap;
    flex-shrink: 0;
    padding: 2px 7px;
    border-radius: 999px;
    background: color-mix(in srgb, currentColor 10%, transparent);
}

/* ── Cards do dashboard ──────────────────────────── */
.dash-card {
    display: flex;
    flex-direction: column;
    background: var(--surface-card, #fff);
    border: 1px solid var(--surface-border, #e2e8f0);
    border-radius: 8px;
    overflow: hidden;
}
.dash-card__head {
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--surface-border, #f1f5f9);
    background: var(--surface-ground, #f8fafc);
}
.dash-card__sub {
    font-size: 0.75rem;
    color: var(--text-color-secondary);
}
.dash-card__badge {
    margin-left: auto;
    font-size: 0.78rem;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 999px;
    flex-shrink: 0;
}
.dash-card__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.75rem 0.875rem;
    min-height: 72px;
}
.dash-card__foot {
    padding: 0.5rem 0.875rem;
    border-top: 1px solid var(--surface-border, #f1f5f9);
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--primary-color, #6366f1);
    cursor: pointer;
    transition: background 0.12s;
}
.dash-card__foot:hover {
    background: var(--surface-ground, #f8fafc);
}

.dash-item {
    display: flex;
    align-items: center;
}
.dash-item__name {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text-color);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.dash-item__sub {
    font-size: 0.72rem;
    color: var(--text-color-secondary);
}
.dash-item__actions {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    flex-shrink: 0;
}

.dash-empty {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 0;
    color: var(--text-color-secondary);
    font-size: 0.8125rem;
}
</style>
