<script setup>
/*
 * MelissaBusca
 * --------------------------------------------------
 * Busca rápida glass-style. Adaptação do GlobalSearch da topbar
 * (`src/components/search/GlobalSearch.vue`) pro layout Melissa.
 *
 * Diferenças vs. GlobalSearch:
 *  - Não chama Supabase — recebe pacientes/eventos via prop (preview)
 *  - Visual glass (white-on-glass) ao invés de surface-card
 *  - Sem loading state (busca client-side, instantâneo)
 *  - Emite ações pro parent decidir o que fazer
 *
 * Quando promover pra produção: trocar a busca por chamada à RPC
 * `search_global` + manter a mesma estrutura de panel/items.
 */
import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
import { supabase } from '@/lib/supabase/client';
import { useTenantStore } from '@/stores/tenantStore';
import { useRecentPatients } from '@/composables/useRecentPatients';

const props = defineProps({
    pacientes: { type: Array, default: () => [] },
    eventos: { type: Array, default: () => [] },
    atalhos: {
        type: Array,
        default: () => [
            { id: 'agenda', label: 'Agenda', icon: 'pi pi-calendar', sublabel: 'Sessões e compromissos', keywords: ['agenda', 'calendario', 'sessoes', 'hoje'] },
            { id: 'pacientes', label: 'Pacientes', icon: 'pi pi-users', sublabel: 'Cadastro e prontuários', keywords: ['pacientes', 'lista', 'cadastro'] },
            { id: 'conversas', label: 'WhatsApp', icon: 'pi pi-whatsapp', sublabel: 'Conversas em andamento', keywords: ['whatsapp', 'conversas', 'mensagens', 'chat'] },
            { id: 'financeiro', label: 'Financeiro', icon: 'pi pi-wallet', sublabel: 'Recebíveis e lançamentos', keywords: ['financeiro', 'pagamentos', 'cobrancas', 'dinheiro'] },
            { id: 'configuracoes', label: 'Configurações', icon: 'pi pi-cog', sublabel: 'Preferências e equipe', keywords: ['configuracoes', 'ajustes', 'preferencias', 'settings'] }
        ]
    }
});

const emit = defineEmits(['acao', 'paciente', 'evento', 'documento', 'intake', 'goto-date']);

const tenantStore = useTenantStore();

const rootEl = ref(null);
const inputEl = ref(null);
const query = ref('');
const showPanel = ref(false);
const activeIndex = ref(-1);

// RPC search_global results — preenchidos por debounce conforme o usuário digita.
// Cliente-side (props.pacientes / props.eventos) continua sendo fallback rápido
// pra digitação curta (1 char) e como complemento aos primeiros resultados.
const rpcResults = ref({ patients: [], appointments: [], documents: [], services: [], intakes: [] });
const searching = ref(false);
let debounceT = null;
let searchSeq = 0;

// Recently viewed (localStorage) — só aparece quando o input está vazio
const { items: recentPatients, hasItems: hasRecentPatients } = useRecentPatients();
const showRecent = computed(() => !query.value.trim() && hasRecentPatients.value);
const recentItems = computed(() => showRecent.value ? (recentPatients.value || []).slice(0, 5) : []);

function normalize(s) {
    return String(s || '')
        .normalize('NFD')
        .replace(/[̀-ͯ]/g, '')
        .toLowerCase()
        .trim();
}

// Parser de data — portado de MelissaAgendaSearchPopover.
// Aceita: "hoje", "amanha"/"amanhã", "ontem", "DD/MM", "DD/MM/YYYY"
// (separadores /, - ou .). Retorna Date|null. Acao "Ir para esta data"
// so se torna visivel quando ha match (vide dateMatch computed).
function parseSearchAsDate(str) {
    const t = String(str || '').trim().toLowerCase();
    if (!t) return null;
    if (t === 'hoje') { const d = new Date(); d.setHours(0, 0, 0, 0); return d; }
    if (t === 'amanha' || t === 'amanhã') {
        const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() + 1); return d;
    }
    if (t === 'ontem') {
        const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); return d;
    }
    const m = t.match(/^(\d{1,2})[/\-.](\d{1,2})(?:[/\-.](\d{2,4}))?$/);
    if (m) {
        const day = parseInt(m[1], 10);
        const month = parseInt(m[2], 10);
        let year = parseInt(m[3] || '', 10);
        if (!year || Number.isNaN(year)) year = new Date().getFullYear();
        if (year < 100) year += 2000;
        if (day < 1 || day > 31 || month < 1 || month > 12) return null;
        const d = new Date(year, month - 1, day);
        if (Number.isNaN(d.getTime())) return null;
        return d;
    }
    return null;
}

function fmtHora(h) {
    const horas = Math.floor(h);
    const mins = Math.round((h - horas) * 60);
    return `${String(horas).padStart(2, '0')}:${String(mins).padStart(2, '0')}`;
}

// Match de data — se a query parseia como data, a primeira "linha" do
// painel vira um card destacado "Ir para [data]" (igual ao popover da
// agenda). Click/Enter dispara emit('goto-date', date) e o MelissaLayout
// abre a agenda + navega o calendario.
const dateMatch = computed(() => parseSearchAsDate(query.value));

function fmtDataLonga(d) {
    if (!(d instanceof Date) || Number.isNaN(d.getTime())) return '';
    // "Sábado, 20/06/2026" — primeira letra maiuscula no weekday
    const s = d.toLocaleDateString('pt-BR', {
        weekday: 'long',
        day: '2-digit',
        month: '2-digit',
        year: 'numeric'
    });
    return s.charAt(0).toUpperCase() + s.slice(1);
}

const filteredAtalhos = computed(() => {
    const q = normalize(query.value);
    if (!q) return props.atalhos.slice(0, 4); // 4 defaults quando vazio
    return props.atalhos.filter((a) => {
        const hay = normalize(a.label + ' ' + (a.keywords || []).join(' '));
        return hay.includes(q);
    }).slice(0, 5);
});

// Pacientes — combina RPC (autoritativo, todos os pacientes) com props (preview de hoje).
// RPC tem prioridade; props complementa quando RPC ainda não trouxe nada.
//
// Shape do RPC search_global (patients): { id, label, sublabel, avatar_url, deeplink, score }
// label = nome_completo; sublabel = email_principal ou telefone.
const filteredPacientes = computed(() => {
    const q = normalize(query.value);
    if (q.length < 2) return [];

    const rpc = rpcResults.value.patients || [];
    if (rpc.length) {
        return rpc.slice(0, 5).map(p => ({
            id: p.id,
            nome: p.label || '(sem nome)',
            sub: p.sublabel || '',
            avatar_url: p.avatar_url || null
        }));
    }
    // Fallback client-side (props.pacientes vem do MelissaLayout — shape diferente)
    return props.pacientes
        .filter((p) => normalize(p.nome).includes(q))
        .slice(0, 5)
        .map(p => ({ id: p.id, nome: p.nome, sub: '', avatar_url: null }));
});

const filteredEventos = computed(() => {
    const q = normalize(query.value);
    if (q.length < 2) return [];
    return props.eventos
        .filter((e) => {
            const hay = normalize(
                (e.label || '') + ' ' + (e.pacienteNome || '') + ' ' + (e.descricao || '')
            );
            return hay.includes(q);
        })
        .slice(0, 5);
});

// Resultados exclusivos da RPC (não há fallback client-side)
const rpcAppointments = computed(() => rpcResults.value.appointments || []);
const rpcDocuments   = computed(() => rpcResults.value.documents || []);
const rpcIntakes     = computed(() => rpcResults.value.intakes || []);

const flatList = computed(() => {
    const out = [];
    // "Ir para [data]" sempre no topo quando query parseia como data —
    // acao predominante (Enter direto seleciona ela).
    if (dateMatch.value) out.push({ group: 'goto-date', item: dateMatch.value, idx: 0 });
    recentItems.value.forEach((p, i) => out.push({ group: 'recent', item: p, idx: i }));
    filteredAtalhos.value.forEach((a, i) => out.push({ group: 'atalhos', item: a, idx: i }));
    filteredPacientes.value.forEach((p, i) => out.push({ group: 'pacientes', item: p, idx: i }));
    filteredEventos.value.forEach((e, i) => out.push({ group: 'eventos', item: e, idx: i }));
    rpcAppointments.value.forEach((a, i) => out.push({ group: 'rpc-appointments', item: a, idx: i }));
    rpcDocuments.value.forEach((d, i) => out.push({ group: 'rpc-documents', item: d, idx: i }));
    rpcIntakes.value.forEach((r, i) => out.push({ group: 'rpc-intakes', item: r, idx: i }));
    return out;
});

const hasAnyResult = computed(() => flatList.value.length > 0);

function findFlatIndex(group, idx) {
    return flatList.value.findIndex((x) => x.group === group && x.idx === idx);
}

function selectEntry(entry) {
    if (entry.group === 'goto-date') emit('goto-date', entry.item);
    else if (entry.group === 'atalhos') emit('acao', entry.item.id);
    else if (entry.group === 'pacientes') emit('paciente', entry.item);
    else if (entry.group === 'recent') emit('paciente', { id: entry.item.id, nome: entry.item.nome, ...entry.item.extras });
    else if (entry.group === 'eventos') emit('evento', entry.item);
    else if (entry.group === 'rpc-appointments') {
        // Sessão da RPC: deeplink pra agenda com evento focado
        emit('evento', { id: entry.item.id, deeplink: entry.item.deeplink });
    } else if (entry.group === 'rpc-documents') {
        // Documento da RPC: extrai patient_id da deeplink se possível
        const dl = entry.item.deeplink || '';
        const m = dl.match(/patients\/([0-9a-f-]+)/i);
        emit('documento', { id: entry.item.id, patient_id: m?.[1] || null, label: entry.item.label });
    } else if (entry.group === 'rpc-intakes') {
        emit('intake', entry.item);
    }
    closePanel();
}

function closePanel() {
    showPanel.value = false;
    query.value = '';
    activeIndex.value = -1;
}

function openDialog() {
    showPanel.value = true;
    // Foca input do Dialog após ele montar
    nextTick(() => inputEl.value?.focus());
}

function onKeydown(e) {
    if (e.key === 'ArrowDown') {
        e.preventDefault();
        activeIndex.value = Math.min(activeIndex.value + 1, flatList.value.length - 1);
    } else if (e.key === 'ArrowUp') {
        e.preventDefault();
        activeIndex.value = Math.max(activeIndex.value - 1, 0);
    } else if (e.key === 'Enter') {
        // Enter sem selecao explicita: pega o primeiro item do flatList
        // (UX spotlight padrao — usuario digita "hoje" + Enter deve ir
        // direto pra hoje sem precisar ArrowDown).
        if (activeIndex.value >= 0) {
            e.preventDefault();
            selectEntry(flatList.value[activeIndex.value]);
        } else if (flatList.value.length > 0) {
            e.preventDefault();
            selectEntry(flatList.value[0]);
        }
    }
    // Escape é tratado pelo Dialog (dismissableMask + closable)
}

function onGlobalKeydown(e) {
    // Ctrl+K / ⌘+K → abre dialog
    if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {
        e.preventDefault();
        openDialog();
    }
}

// ── RPC search_global debounced ───────────────────────────────────────────
// Mesmo padrão do GlobalSearch.vue: query >= 2 chars dispara em 200ms,
// controla ordem via searchSeq pra ignorar respostas obsoletas.
function resetRpcResults() {
    rpcResults.value = { patients: [], appointments: [], documents: [], services: [], intakes: [] };
}

watch(query, (v) => {
    if (debounceT) clearTimeout(debounceT);
    const q = String(v || '').trim();
    if (q.length < 2) {
        resetRpcResults();
        searching.value = false;
        return;
    }
    // Query parseou como data: pula RPC (nao faz sentido buscar paciente
    // chamado "20/06"). Card "Ir para data" cobre o caso sozinho.
    if (dateMatch.value) {
        ++searchSeq; // invalida requests em flight
        resetRpcResults();
        searching.value = false;
        return;
    }
    searching.value = true;
    const mySeq = ++searchSeq;
    debounceT = setTimeout(async () => {
        try {
            const { data, error } = await supabase.rpc('search_global', { p_tenant_id: tenantStore.activeTenantId, p_q: q, p_limit: 6 });
            if (mySeq !== searchSeq) return;
            if (error) {
                console.error('[MelissaBusca search_global]', error);
                resetRpcResults();
            } else {
                rpcResults.value = {
                    patients:     Array.isArray(data?.patients)     ? data.patients     : [],
                    appointments: Array.isArray(data?.appointments) ? data.appointments : [],
                    documents:    Array.isArray(data?.documents)    ? data.documents    : [],
                    services:     Array.isArray(data?.services)     ? data.services     : [],
                    intakes:      Array.isArray(data?.intakes)      ? data.intakes      : []
                };
            }
        } catch (e) {
            if (mySeq !== searchSeq) return;
            console.error('[MelissaBusca search_global exception]', e);
            resetRpcResults();
        } finally {
            if (mySeq === searchSeq) searching.value = false;
        }
    }, 200);
});

onMounted(() => {
    window.addEventListener('keydown', onGlobalKeydown);
});
onBeforeUnmount(() => {
    window.removeEventListener('keydown', onGlobalKeydown);
    if (debounceT) clearTimeout(debounceT);
});

// Exposto pro MelissaLayout — a lupa unica na .melissa-tray chama
// melissaBuscaRef.openDialog() direto, e o provide('openMelissaBusca')
// reusa o mesmo metodo pra qualquer descendente que queira abrir o
// spotlight programaticamente. closeDialog alias do closePanel.
defineExpose({ openDialog, closeDialog: closePanel });
</script>

<template>
    <div ref="rootEl" class="mb-search">
        <!-- Trigger: aparência de input, mas é botão (abre Dialog) -->
        <button type="button" class="mb-field" @click="openDialog" :aria-label="'Buscar (Ctrl+K)'">
            <i class="pi pi-search mb-field__icon" />
            <span class="mb-field__placeholder">Buscar paciente, agenda, atalho…</span>
            <span class="mb-field__kbd" aria-hidden="true">Ctrl K</span>
        </button>

        <!-- Dialog Spotlight: input grande no topo + resultados em coluna -->
        <Dialog
            v-model:visible="showPanel"
            modal
            :draggable="false"
            :closable="false"
            :dismissableMask="true"
            :showHeader="false"
            class="mb-dialog"
            :style="{ width: '640px', maxWidth: '94vw' }"
            pt:mask:class="mb-dialog__mask"
            pt:content:class="mb-dialog__content"
            @hide="closePanel"
        >
            <!-- Field do Dialog (input real, autofocus) -->
            <div class="mb-dialog__field">
                <i class="pi pi-search mb-dialog__field-icon" />
                <input
                    ref="inputEl"
                    v-model="query"
                    type="text"
                    placeholder="Buscar paciente, agenda, atalho…"
                    class="mb-dialog__input"
                    @keydown="onKeydown"
                    autocomplete="off"
                    spellcheck="false"
                />
                <span class="mb-dialog__esc" aria-hidden="true">Esc</span>
            </div>

            <!-- Painel de resultados (scroll interno) -->
            <div class="mb-panel" role="listbox">
                <div
                    v-if="query.trim().length >= 2 && !hasAnyResult"
                    class="mb-empty"
                >
                    Nada encontrado pra "<span class="text-white/80">{{ query.trim() }}</span>"
                </div>

                <!-- "Ir para [data]" — quando query parseia como data
                     (hoje/amanha/ontem/DD/MM/YYYY). Predominante: vai pra
                     primeira linha do flatList e Enter direto seleciona. -->
                <div v-if="dateMatch" class="mb-group">
                    <button
                        class="mb-item mb-item--gotodate"
                        :class="{ 'is-active': findFlatIndex('goto-date', 0) === activeIndex }"
                        @click="selectEntry({ group: 'goto-date', item: dateMatch })"
                        @mouseenter="activeIndex = findFlatIndex('goto-date', 0)"
                    >
                        <span class="mb-item__icon mb-item__icon--gotodate"><i class="pi pi-calendar" /></span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">Ir para {{ fmtDataLonga(dateMatch) }}</span>
                            <span class="mb-item__sub">Pular para essa data no calendário</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>

                <!-- Acessados recentemente (só quando query vazia) -->
                <div v-if="showRecent" class="mb-group">
                    <div class="mb-group__title">Acessados recentemente</div>
                    <button
                        v-for="(p, i) in recentItems"
                        :key="'mr-' + p.id"
                        class="mb-item"
                        :class="{ 'is-active': findFlatIndex('recent', i) === activeIndex }"
                        @click="selectEntry({ group: 'recent', item: p })"
                        @mouseenter="activeIndex = findFlatIndex('recent', i)"
                    >
                        <span class="mb-item__icon"><i class="pi pi-history" /></span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">{{ p.nome }}</span>
                            <span class="mb-item__sub">{{ p.extras?.telefone || p.extras?.email || 'Abrir prontuário' }}</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>

                <!-- Atalhos -->
                <div v-if="filteredAtalhos.length" class="mb-group">
                    <div class="mb-group__title">{{ query.trim() ? 'Ações' : 'Atalhos' }}</div>
                    <button
                        v-for="(a, i) in filteredAtalhos"
                        :key="'a-' + a.id"
                        class="mb-item"
                        :class="{ 'is-active': findFlatIndex('atalhos', i) === activeIndex }"
                        @click="selectEntry({ group: 'atalhos', item: a })"
                        @mouseenter="activeIndex = findFlatIndex('atalhos', i)"
                    >
                        <span class="mb-item__icon"><i :class="a.icon" /></span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">{{ a.label }}</span>
                            <span v-if="a.sublabel" class="mb-item__sub">{{ a.sublabel }}</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>

                <!-- Pacientes -->
                <div v-if="filteredPacientes.length" class="mb-group">
                    <div class="mb-group__title">Pacientes</div>
                    <button
                        v-for="(p, i) in filteredPacientes"
                        :key="'p-' + p.id"
                        class="mb-item"
                        :class="{ 'is-active': findFlatIndex('pacientes', i) === activeIndex }"
                        @click="selectEntry({ group: 'pacientes', item: p })"
                        @mouseenter="activeIndex = findFlatIndex('pacientes', i)"
                    >
                        <span class="mb-item__icon mb-item__icon--patient"><i class="pi pi-user" /></span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">{{ p.nome }}</span>
                            <span class="mb-item__sub">{{ p.sub || 'Abrir prontuário' }}</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>

                <!-- Eventos -->
                <div v-if="filteredEventos.length" class="mb-group">
                    <div class="mb-group__title">Agenda de hoje</div>
                    <button
                        v-for="(e, i) in filteredEventos"
                        :key="'e-' + e.id"
                        class="mb-item"
                        :class="{ 'is-active': findFlatIndex('eventos', i) === activeIndex }"
                        @click="selectEntry({ group: 'eventos', item: e })"
                        @mouseenter="activeIndex = findFlatIndex('eventos', i)"
                    >
                        <span
                            class="mb-item__icon"
                            :style="{ backgroundColor: `${e.color}33`, color: e.color }"
                        >
                            <i class="pi pi-clock" />
                        </span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">{{ e.label }}</span>
                            <span class="mb-item__sub">{{ fmtHora(e.startH) }} – {{ fmtHora(e.endH) }}</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>

                <!-- RPC: Sessões/agendamentos (qualquer data)
                     RPC retorna { id, label, sublabel, deeplink }. Sublabel ja vem
                     com "Paciente · dd/mm/yyyy HH:MM". Cor do icone = cor de sessao
                     (indigo-500, igual ao pickColor() padrao). -->
                <div v-if="rpcAppointments.length" class="mb-group">
                    <div class="mb-group__title">Sessões</div>
                    <button
                        v-for="(e, i) in rpcAppointments"
                        :key="'rpc-a-' + e.id"
                        class="mb-item"
                        :class="{ 'is-active': findFlatIndex('rpc-appointments', i) === activeIndex }"
                        @click="selectEntry({ group: 'rpc-appointments', item: e })"
                        @mouseenter="activeIndex = findFlatIndex('rpc-appointments', i)"
                    >
                        <span class="mb-item__icon mb-item__icon--sessao"><i class="pi pi-calendar" /></span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">{{ e.label || 'Sessão' }}</span>
                            <span class="mb-item__sub">{{ e.sublabel || 'Sem detalhes' }}</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>

                <!-- RPC: Documentos -->
                <div v-if="rpcDocuments.length" class="mb-group">
                    <div class="mb-group__title">Documentos</div>
                    <button
                        v-for="(d, i) in rpcDocuments"
                        :key="'rpc-d-' + d.id"
                        class="mb-item"
                        :class="{ 'is-active': findFlatIndex('rpc-documents', i) === activeIndex }"
                        @click="selectEntry({ group: 'rpc-documents', item: d })"
                        @mouseenter="activeIndex = findFlatIndex('rpc-documents', i)"
                    >
                        <span class="mb-item__icon mb-item__icon--doc"><i class="pi pi-file" /></span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">{{ d.label || 'Documento' }}</span>
                            <span class="mb-item__sub">{{ d.sublabel || '' }}</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>

                <!-- RPC: Cadastros recebidos (intakes) -->
                <div v-if="rpcIntakes.length" class="mb-group">
                    <div class="mb-group__title">Cadastros recebidos</div>
                    <button
                        v-for="(r, i) in rpcIntakes"
                        :key="'rpc-i-' + r.id"
                        class="mb-item"
                        :class="{ 'is-active': findFlatIndex('rpc-intakes', i) === activeIndex }"
                        @click="selectEntry({ group: 'rpc-intakes', item: r })"
                        @mouseenter="activeIndex = findFlatIndex('rpc-intakes', i)"
                    >
                        <span class="mb-item__icon mb-item__icon--intake"><i class="pi pi-inbox" /></span>
                        <span class="mb-item__main">
                            <span class="mb-item__label">{{ r.label || 'Cadastro' }}</span>
                            <span class="mb-item__sub">{{ r.sublabel || '' }}</span>
                        </span>
                        <i class="mb-item__go pi pi-arrow-right" />
                    </button>
                </div>
            </div>
        </Dialog>
    </div>
</template>

<style scoped>
.mb-search {
    position: relative;
    width: 100%;
    max-width: 560px;
    margin-left: auto;
    margin-right: auto;
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}

/* ─── Trigger no dock (visual de input, mas é botão que abre Dialog) ─── */
.mb-field {
    position: relative;
    display: flex;
    align-items: center;
    width: 100%;
    background: var(--m-bg-soft);
    backdrop-filter: blur(20px) saturate(140%);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    border: 1px solid var(--m-border-strong);
    border-radius: 12px;
    padding: 0 14px;
    height: 44px;
    cursor: pointer;
    text-align: left;
    transition: background-color 160ms ease, border-color 160ms ease;
}
.mb-field:hover {
    background: var(--m-bg-soft-hover);
}
.mb-field__icon {
    color: var(--m-text-muted);
    font-size: 0.95rem;
    margin-right: 10px;
    flex-shrink: 0;
}
.mb-field__placeholder {
    flex: 1;
    color: var(--m-text-muted);
    font-size: 0.9rem;
    font-family: inherit;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mb-field__kbd {
    color: var(--m-text-muted);
    font-size: 0.62rem;
    font-weight: 500;
    padding: 2px 7px;
    border-radius: 4px;
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border-strong);
    margin-left: 8px;
    flex-shrink: 0;
    letter-spacing: 0.05em;
}

/* ─── Dialog Spotlight (PrimeVue Dialog customizado) ─── */
:global(.mb-dialog__mask) {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    background: rgba(0, 0, 0, 0.55) !important;
}
:global(.mb-dialog) {
    border-radius: 14px !important;
    overflow: hidden;
    /* Posiciona mais alto que o centro (estilo Spotlight) */
    margin-top: 10vh !important;
    align-self: flex-start;
}
:global(.mb-dialog .mb-dialog__content) {
    padding: 0 !important;
    background: var(--surface-card) !important;
    border-radius: 14px !important;
    overflow: hidden;
    max-height: 70vh;
    display: flex;
    flex-direction: column;
}

.mb-dialog__field {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--surface-border);
    background: var(--surface-card);
    flex-shrink: 0;
}
.mb-dialog__field-icon {
    color: var(--text-color-secondary);
    font-size: 1.05rem;
    flex-shrink: 0;
}
.mb-dialog__input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: var(--text-color);
    font-size: 1.05rem;
    font-family: inherit;
    min-width: 0;
}
.mb-dialog__input::placeholder {
    color: var(--text-color-secondary);
    opacity: 0.7;
}
.mb-dialog__esc {
    color: var(--text-color-secondary);
    font-size: 0.65rem;
    font-weight: 500;
    padding: 2px 8px;
    border-radius: 4px;
    background: var(--surface-ground);
    border: 1px solid var(--surface-border);
    flex-shrink: 0;
    letter-spacing: 0.05em;
    opacity: 0.8;
}

/* Panel agora vive DENTRO do Dialog (não mais absolute). Scroll interno
   resolve o bug de overflow — o conteúdo nunca passa do bottom porque
   o Dialog tem max-height e o panel é flex:1. */
.mb-panel {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 6px;
    background: var(--surface-card);
    scrollbar-width: thin;
    scrollbar-color: var(--surface-border) transparent;
    min-height: 0; /* permite shrink no flex */
}
.mb-panel::-webkit-scrollbar { width: 6px; }
.mb-panel::-webkit-scrollbar-thumb {
    background: var(--surface-border);
    border-radius: 3px;
}

.mb-empty {
    padding: 18px 14px;
    text-align: center;
    color: var(--text-color-secondary);
    font-size: 0.85rem;
}

.mb-group + .mb-group {
    margin-top: 4px;
    padding-top: 4px;
    border-top: 1px solid var(--surface-border);
}
.mb-group__title {
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--text-color-secondary);
    font-size: 0.62rem;
    font-weight: 700;
    padding: 8px 10px 4px;
    opacity: 0.75;
}

.mb-item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    background: transparent;
    border: none;
    border-radius: 8px;
    color: var(--text-color);
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    transition: background-color 100ms ease;
}
.mb-item:hover,
.mb-item.is-active {
    background: color-mix(in srgb, var(--p-primary-color) 8%, transparent);
}
.mb-item__icon {
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    background: var(--surface-ground);
    border-radius: 7px;
    color: var(--text-color-secondary);
    flex-shrink: 0;
    font-size: 0.9rem;
}
/* Cores por tipo — semântica fixa (não depende do tema, é categoria). */
.mb-item__icon--patient {
    background: rgba(244, 114, 182, 0.18);
    color: #ec4899;
}
.mb-item__icon--sessao {
    background: rgba(99, 102, 241, 0.20);
    color: #6366f1;
}
.mb-item__icon--doc {
    background: rgba(14, 165, 233, 0.18);
    color: #0ea5e9;
}
.mb-item__icon--intake {
    background: rgba(251, 146, 60, 0.18);
    color: #f97316;
}
/* Dark mode: clareia as cores semânticas pra manter contraste */
:root.app-dark .mb-item__icon--patient { color: #f9a8d4; }
:root.app-dark .mb-item__icon--sessao { color: #a5b4fc; }
:root.app-dark .mb-item__icon--doc { color: #7dd3fc; }
:root.app-dark .mb-item__icon--intake { color: #fdba74; }

/* "Ir para [data]" — card azul predominante, mesmo padrao visual do
   popover da agenda (MelissaAgendaSearchPopover). Cores diretas (sem
   var/color-mix) pra garantir contraste em ambos os modos. */
.mb-item--gotodate {
    background: rgba(59, 130, 246, 0.16);
    border: 1.5px solid rgba(59, 130, 246, 0.55);
}
.mb-item--gotodate:hover,
.mb-item--gotodate.is-active {
    background: rgba(59, 130, 246, 0.26);
    border-color: rgba(59, 130, 246, 0.75);
}
.mb-item__icon--gotodate {
    background: #3b82f6;
    color: white;
}
.mb-item--gotodate .mb-item__label { color: #2563eb; font-weight: 600; }
:root.app-dark .mb-item--gotodate .mb-item__label { color: #93c5fd; }
:root.app-dark .mb-item--gotodate .mb-item__sub { color: rgba(147, 197, 253, 0.7); }

.mb-item__main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.mb-item__label {
    font-size: 0.88rem;
    font-weight: 500;
    color: var(--text-color);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mb-item__sub {
    font-size: 0.74rem;
    color: var(--text-color-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mb-item__go {
    color: var(--text-color-secondary);
    opacity: 0.5;
    font-size: 0.75rem;
    flex-shrink: 0;
}

</style>
