<script setup>
/*
 * MelissaEventoPanel — Painel de detalhes do evento selecionado.
 * --------------------------------------------------
 * Substitui o panel inline que vivia em MelissaLayout (era prone a crash
 * por referenciar campos inexistentes no normalize: .valor, .participantes,
 * .supervisorNome, .local).
 *
 * Renderiza apenas campos REAIS do useMelissaEventos.normalizeEvent:
 *   tipo, status, modalidade, descricao, pacienteNome, patient_id,
 *   color, label, startH, endH, inicio_em, fim_em
 *
 * Actions emitidas (parent decide o que fazer):
 *   - close
 *   - concluir / faltou / cancelar (mudança de status)
 *   - remarcar / edit (abre dialog de edição — TODO no parent)
 *   - abrir-prontuario / whatsapp / historico (paciente actions)
 */
import { computed } from 'vue';

const props = defineProps({
    evento: { type: Object, required: true },
    busy: { type: Boolean, default: false } // bloqueia botões enquanto UPDATE roda
});

const emit = defineEmits([
    'close',
    'agendar',
    'concluir',
    'faltou',
    'cancelar',
    'remarcar',
    'revogar-antecipacao',
    'edit-sessao',     // botão dedicado ao lado das horas → AgendaEventDialog
    'edit-paciente',   // botão "Editar" do grupo Outras opções → PatientCadastroDialog
    'abrir-prontuario',
    'whatsapp',
    'historico',
    'delete-sessao',     // botão "Excluir sessão" — só pra sessões avulsas (sem recorrência)
    'delete-series',     // botão "Excluir série inteira" — hard delete da regra + materializadas + records pendentes
    'ver-lancamentos',   // botão "Lançamentos" — abre dialog com financial_records vinculados
    'antecipar-pagamento', // botão "Antecipar pagamento" — paciente quer pagar antes da sessão (pacote saldo)
    'trocar-metodo-antecipacao', // botão "Trocar método" — UPDATE no record paid sem cancel+criar novo (evita lixo cancelled)
    'gerar-cobranca',    // botão inline "Gerar fatura" ao lado de "A cobrar R$ X" — atalho sem precisar abrir dialog
    'usar-sessao',       // botão "Usar" no card de pacote saldo — materializa+realizada+gera cobrança individual
    'revogar-sessao'     // botão "Revogar" — desfaz Usar (cancela record + decrementa saldo). Bloqueado se já pago
]);

// Regra atualizada (2026-05-14): botão Excluir aparece SEMPRE pra sessão.
// Handler no parent verifica:
//   - virtual sem materialização → cria recurrence_exception cancel_session
//   - real sem records pagos → DELETE (cobranças pendentes vão junto)
//   - real com record PAGO → bloqueia (estorno pelo Financeiro primeiro)
const canDelete = computed(() => {
    const e = ev.value;
    if (!e) return false;
    // Pra MVP: oculta só em compromisso não-sessão sem id real.
    return true;
});

// Mostra "Excluir série inteira" apenas pra eventos que pertencem a
// uma regra de recorrência (materializados OU ocorrências virtuais).
const isPartOfSeries = computed(() => {
    const e = ev.value;
    if (!e) return false;
    return !!(e.recurrence_id || e.serie_id);
});

// Label "Pacote · X sessões" / "Série semanal" pro popover quando o
// evento pertence a uma recorrência. Lê do _raw que carrega os campos
// da regra (max_occurrences, frequency_type quando expandido).
const seriesLabel = computed(() => {
    if (!isPartOfSeries.value) return null;
    const raw = ev.value._raw || {};
    const total = raw.max_occurrences || raw.qtd_sessoes || raw.series_total || null;
    const idx = raw.occurrence_index || raw.serie_index || null;
    if (total && idx) return `Sessão ${idx} de ${total}`;
    if (total) return `Pacote · ${total} sessões`;
    return 'Série recorrente';
});

// Info de contrato (saldo/upfront) — vem injetada pelo bulk-load via
// _ruleContractMap. Mostra linha no popover indicando o tipo de pacote
// e progresso (usadas/total). Pra saldo é especialmente importante —
// sem essa linha o user não sabe o que está acontecendo (nenhuma
// cobrança no /financeiro até realizar).
const contractInfo = computed(() => {
    const c = ev.value.contract;
    if (!c) return null;
    const total = c.totalSessions || 0;
    const used = c.sessionsUsed || 0;
    const remaining = Math.max(0, total - used);
    const perSession = total > 0 ? (c.packagePrice || 0) / total : 0;
    return {
        style: c.style || 'upfront',
        total,
        used,
        remaining,
        packagePrice: c.packagePrice || 0,
        perSession,
        label: c.style === 'saldo'
            ? `Pacote saldo · ${used}/${total} usadas`
            : `Pacote · ${used}/${total} realizadas`
    };
});

const ev = computed(() => props.evento || {});

const tipoLabel = computed(() => {
    const t = String(ev.value.tipo || '').toLowerCase();
    if (t === 'sessao') return 'Sessão';
    if (t === 'supervisao' || t === 'supervisão') return 'Supervisão';
    if (t === 'reuniao' || t === 'reunião') return 'Reunião';
    if (t === 'bloqueio') return 'Bloqueio';
    return t || 'Evento';
});

const statusLabel = computed(() => {
    const s = String(ev.value.status || '').toLowerCase();
    if (!s || s === 'agendado') return 'Agendado';
    if (s === 'realizado' || s === 'realizada') return 'Realizada';
    if (s === 'faltou') return 'Faltou';
    if (s === 'cancelado' || s === 'cancelada') return 'Cancelada';
    if (s === 'remarcar') return 'A remarcar';
    return ev.value.status;
});

const statusSlug = computed(() => {
    const s = String(ev.value.status || '').toLowerCase();
    if (s === 'realizada') return 'realizado';
    if (s === 'cancelada') return 'cancelado';
    return s || 'agendado';
});

// Sessão com paciente vinculado mostra o grupo de actions de paciente
const isSessaoComPaciente = computed(
    () => ev.value.tipo === 'sessao' && (ev.value.patient_id || ev.value.pacienteNome)
);

// Sessão "encerrada" — não rolou (cancelada ou paciente faltou).
// Bloqueia: editar sessão (dados não cabem mais) + transições de status
// pra realizado/faltou/cancelar (não faz sentido marcar um cancelado como
// "faltou"). Mantém SÓ "Agendada" funcional como caminho de recuperação
// caso tenha sido marcado por engano.
const isSessaoEncerrada = computed(() => statusSlug.value === 'cancelado' || statusSlug.value === 'faltou');

// "Antecipação ativa": sessão ainda agendada (não rolou) com cobrança paga.
// O paid não veio de Realizada — veio de "Antecipar pagamento" que adianta
// o pagamento. Nesse estado, o botão "Antecipar pagamento" vira "Revogar
// pagamento" pra desfazer caso o user tenha errado. Após Realizada, o paid
// vira pagamento normal da sessão (estorno via /financeiro).
const isAntecipacaoAtiva = computed(() => statusSlug.value === 'agendado' && ev.value.paymentState === 'paid');

// Estado de pagamento — vem anotado pelo useMelissaAgenda via bulk-query
// em financial_records. 'paid' | 'pending' | 'none'. Renderiza linha
// curta abaixo do horário pra sessão com paciente (espelha os 3 canais
// visuais da agenda). Ocorrências virtuais (sem id real) sempre 'none'
// — não polui séries com pacote upfront.
const showPaymentRow = computed(() => {
    if (!isSessaoComPaciente.value) return false;
    // Virtuais sem estado herdado de contrato ficam limpas (paymentState='none').
    // Quando herdam 'paid' ou 'pending' de pacote upfront via propagação no
    // bulk-load, exibem normalmente. Pacote saldo continua limpo (siblings
    // ficam 'none' propositadamente — modelo Cliniko).
    if (ev.value.is_occurrence && (!ev.value.paymentState || ev.value.paymentState === 'none')) return false;
    return !!ev.value.paymentState;
});
const paymentVariant = computed(() => {
    const s = ev.value.paymentState;
    if (s === 'paid') return 'paid';
    if (s === 'pending') return 'pending';
    return 'none';
});
const paymentIcon = computed(() => {
    return paymentVariant.value === 'paid' ? 'pi pi-check-circle' : 'pi pi-dollar';
});
const paymentLabel = computed(() => {
    const state = ev.value.paymentState;
    // Pra estados 'paid' e 'pending' usar o VALOR REAL do record (paymentAmount).
    // Necessário pra cobrir caso de multa: original cancelled R$ 200 + multa
    // pending R$ 30 → state='pending' mas paymentAmount=30 (não R$ 200 do ev.price).
    // Em pacote upfront paid, é o package_price total. Só cai no fallback de
    // ev.price/insurance_value quando state='none' (sem record ativo).
    const valor = (state === 'paid' || state === 'pending') && ev.value.paymentAmount != null
        ? ev.value.paymentAmount
        : (ev.value.price ?? ev.value.insurance_value);
    const valorFmt = (valor != null && !Number.isNaN(Number(valor)))
        ? Number(valor).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })
        : null;
    if (state === 'paid') {
        return valorFmt ? `Pago · ${valorFmt}` : 'Pago';
    }
    if (state === 'pending') {
        return valorFmt ? `A receber ${valorFmt} (cobrança pendente)` : 'Cobrança pendente';
    }
    // 'none' — sessão sem cobrança ativa
    // Quando status='cancelado'/'faltou' + sem record ativo, deixa claro
    // que não há cobrança em aberto (em vez de "A cobrar R$ X" enganoso).
    const slug = String(ev.value.status || '').toLowerCase();
    if (slug === 'cancelado' || slug === 'cancelada') return 'Sessão cancelada · sem cobrança ativa';
    if (slug === 'faltou') return 'Sessão não realizada · sem cobrança ativa';
    // Pacote tied → não cabe "A cobrar R$ X" solto porque o billing é via
    // pacote (saldo: aguarda Usar; upfront: já está coberto pelo contrato).
    // Contract row já mostra o status do pacote.
    const cInfo = ev.value.contract;
    if (cInfo?.style === 'saldo') return 'Aguardando uso do pacote';
    if (cInfo?.style === 'upfront') return 'Coberta pelo pacote (upfront)';
    return valorFmt ? `A cobrar ${valorFmt}` : 'Cobrança ainda não gerada';
});

function fmtHora(decimal) {
    if (decimal === null || decimal === undefined || Number.isNaN(decimal)) return '—';
    const h = Math.floor(decimal);
    const m = Math.round((decimal - h) * 60);
    return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
}

function duracaoMin() {
    const s = ev.value.startH;
    const e = ev.value.endH;
    if (typeof s !== 'number' || typeof e !== 'number') return null;
    return Math.max(0, Math.round((e - s) * 60));
}

function modalidadeIcon(mod) {
    const m = String(mod || '').toLowerCase();
    if (m === 'online') return 'pi pi-video';
    return 'pi pi-map-marker';
}
</script>

<template>
    <div class="evento-layer" @click.self="emit('close')">
        <div class="evento-panel">
            <!-- Header -->
            <div class="evento-head">
                <div class="evento-head__main">
                    <div class="evento-pill" :style="{ backgroundColor: ev.color }" />
                    <div class="min-w-0">
                        <div class="evento-tipo">
                            {{ tipoLabel }}
                            <span v-if="seriesLabel" class="evento-tipo__series">· {{ seriesLabel }}</span>
                        </div>
                        <div class="evento-titulo">
                            {{ isSessaoComPaciente ? ev.pacienteNome : (ev.label || ev.titulo || '—') }}
                        </div>
                    </div>
                </div>
                <button
                    class="glass-btn evento-close"
                    v-tooltip.left="'Fechar (Esc)'"
                    @click="emit('close')"
                >
                    <i class="pi pi-times" />
                </button>
            </div>

            <!-- Conteúdo (só campos reais) -->
            <div class="evento-content">
                <div class="evento-row">
                    <i class="pi pi-clock" />
                    <span>
                        {{ fmtHora(ev.startH) }} – {{ fmtHora(ev.endH) }}
                        <span v-if="duracaoMin() !== null" class="evento-row__sub">· {{ duracaoMin() }}min</span>
                    </span>
                    <div class="evento-row__edit-stack">
                        <button
                            v-if="!isSessaoEncerrada"
                            type="button"
                            class="evento-row__edit evento-row__edit--primary"
                            :disabled="busy"
                            v-tooltip.top="'Editar sessão (data, hora, recorrência…)'"
                            @click="emit('edit-sessao')"
                        >
                            <i class="pi pi-pencil" />
                            <span>Editar sessão</span>
                        </button>
                        <button
                            v-if="canDelete"
                            type="button"
                            class="evento-row__edit evento-row__edit--danger"
                            :disabled="busy"
                            v-tooltip.top="'Excluir esta sessão (permanente)'"
                            @click="emit('delete-sessao')"
                        >
                            <i class="pi pi-trash" />
                            <span>Excluir sessão</span>
                        </button>
                        <button
                            v-if="isPartOfSeries"
                            type="button"
                            class="evento-row__edit evento-row__edit--danger"
                            :disabled="busy"
                            v-tooltip.top="'Excluir a série inteira (todas as sessões da recorrência)'"
                            @click="emit('delete-series')"
                        >
                            <i class="pi pi-history" />
                            <span>Excluir série</span>
                        </button>
                    </div>
                </div>

                <div v-if="showPaymentRow" class="evento-row evento-row--pay" :class="`evento-row--pay-${paymentVariant}`">
                    <i :class="paymentIcon" />
                    <span>{{ paymentLabel }}</span>
                    <!-- Atalho "Gerar fatura" — só pra sessão materializada
                         com paymentState='none' (cobrança ainda não gerada).
                         Pago/pendente já existe um record; nesses casos não
                         cabe gerar de novo. -->
                    <!-- "Gerar fatura" só faz sentido pra sessão SEM contrato
                         de pacote OU sem saldo ativo. Em sessão de saldo o
                         fluxo correto é "Usar" (que orquestra cobrança +
                         sessions_used) — gerar fatura solta aqui criaria
                         cobrança duplicada e dessincronizaria o saldo. -->
                    <button
                        v-if="paymentVariant === 'none' && !ev.is_occurrence && !contractInfo && statusSlug !== 'cancelado' && statusSlug !== 'faltou'"
                        type="button"
                        class="evento-row__pay-action"
                        :disabled="busy"
                        v-tooltip.top="'Gerar fatura agora'"
                        @click="emit('gerar-cobranca')"
                    >
                        <i class="pi pi-plus" />
                        <span>Gerar fatura</span>
                    </button>
                </div>

                <!-- Linha de info do contrato (saldo/upfront) — quando a
                     sessão pertence a uma série com billing_contract ativo.
                     Pra saldo é a única forma do user entender que tem um
                     pacote sem cobrança no /financeiro até realizar.
                     Botão "Usar" só pra saldo com saldo disponível —
                     materializa+realizada+gera cobrança em 1 click. -->
                <div v-if="contractInfo" class="evento-row evento-row--contract" :class="`evento-row--contract-${contractInfo.style}`">
                    <i class="pi pi-box" />
                    <span>{{ contractInfo.label }}</span>
                    <!-- Revogar: aparece quando sessão já foi "usada" (record
                         pending vinculado). Bloqueia pra paid (precisa estorno
                         formal pelo Financeiro). -->
                    <button
                        v-if="contractInfo.style === 'saldo' && !ev.is_occurrence && ev.paymentState === 'pending'"
                        type="button"
                        class="evento-row__pay-action evento-row__pay-action--revogar"
                        :disabled="busy"
                        v-tooltip.top="'Desfaz o uso (cancela cobrança e devolve 1 ao saldo)'"
                        @click="emit('revogar-sessao')"
                    >
                        <i class="pi pi-undo" />
                        <span>Revogar</span>
                    </button>
                    <!-- Usar: aparece quando há saldo + sessão ainda não usada
                         (virtual OU materializada sem cobrança ativa). -->
                    <button
                        v-else-if="contractInfo.style === 'saldo' && contractInfo.remaining > 0 && (ev.is_occurrence || ev.paymentState === 'none')"
                        type="button"
                        class="evento-row__pay-action evento-row__pay-action--contract"
                        :disabled="busy"
                        v-tooltip.top="'Marca sessão como realizada e gera cobrança (1 do saldo)'"
                        @click="emit('usar-sessao')"
                    >
                        <i class="pi pi-check" />
                        <span>Usar</span>
                    </button>
                </div>

                <div v-if="ev.modalidade" class="evento-row">
                    <i :class="modalidadeIcon(ev.modalidade)" />
                    <span class="capitalize">{{ ev.modalidade }}</span>
                </div>

                <div class="evento-row">
                    <i class="pi pi-info-circle" />
                    <span class="evento-status" :class="`is-${statusSlug}`">{{ statusLabel }}</span>
                </div>

                <div v-if="ev.descricao" class="evento-desc">
                    {{ ev.descricao }}
                </div>
            </div>

            <!-- Action bar — agrupada por contexto.
                 Cada botão tem ícone + label textual empilhados pra reduzir
                 ambiguidade (tooltip sozinho não é descobrível em touch). -->
            <footer class="evento-actions">
                <!-- Grupo Status — sempre visível pra sessão (permite trocar
                     de status mesmo após marcar realizado/faltou/cancelado).
                     Status atual fica destacado via .is-current. -->
                <section v-if="isSessaoComPaciente" class="evento-actions__section">
                    <div class="evento-actions__label">Marcar sessão como:</div>
                    <div class="evento-actions__group">
                        <button
                            class="evento-act evento-act--info"
                            :class="{ 'is-current': statusSlug === 'agendado' || statusSlug === '' }"
                            :disabled="busy"
                            @click="emit('agendar')"
                        >
                            <i class="pi pi-calendar" />
                            <span class="evento-act__label">Agendada</span>
                        </button>
                        <button
                            class="evento-act evento-act--ok"
                            :class="{ 'is-current': statusSlug === 'realizado' }"
                            :disabled="busy || isSessaoEncerrada"
                            v-tooltip.top="isSessaoEncerrada ? 'Sessão encerrada — use Agendada pra reativar antes' : null"
                            @click="emit('concluir')"
                        >
                            <i class="pi pi-check-circle" />
                            <span class="evento-act__label">Realizada</span>
                        </button>
                        <button
                            class="evento-act evento-act--warn"
                            :class="{ 'is-current': statusSlug === 'faltou' }"
                            :disabled="busy || isSessaoEncerrada"
                            v-tooltip.top="isSessaoEncerrada ? 'Sessão encerrada — use Agendada pra reativar antes' : null"
                            @click="emit('faltou')"
                        >
                            <i class="pi pi-user-minus" />
                            <span class="evento-act__label">Falta</span>
                        </button>
                        <button
                            class="evento-act"
                            :class="{ 'is-current': statusSlug === 'remarcar' || statusSlug === 'remarcado' }"
                            :disabled="busy || isSessaoEncerrada"
                            v-tooltip.top="isSessaoEncerrada ? 'Sessão encerrada — use Agendada pra reativar antes' : null"
                            @click="emit('remarcar')"
                        >
                            <i class="pi pi-calendar-clock" />
                            <span class="evento-act__label">Reagendar</span>
                        </button>
                        <button
                            class="evento-act evento-act--danger"
                            :class="{ 'is-current': statusSlug === 'cancelado' }"
                            :disabled="busy || isSessaoEncerrada"
                            v-tooltip.top="isSessaoEncerrada ? 'Sessão encerrada — use Agendada pra reativar antes' : null"
                            @click="emit('cancelar')"
                        >
                            <i class="pi pi-ban" />
                            <span class="evento-act__label">Cancelar</span>
                        </button>
                    </div>
                </section>

                <!-- Grupo Outras opções — só pra sessão com paciente.
                     "Editar" abre o cadastro do paciente (não a sessão);
                     pra editar a sessão, usar o botão ao lado das horas. -->
                <section v-if="isSessaoComPaciente" class="evento-actions__section">
                    <div class="evento-actions__label">Outras opções:</div>
                    <div class="evento-actions__group">
                        <button
                            class="evento-act"
                            :disabled="busy"
                            @click="emit('abrir-prontuario')"
                        >
                            <i class="pi pi-file" />
                            <span class="evento-act__label">Prontuário</span>
                        </button>
                        <button
                            class="evento-act"
                            :disabled="busy"
                            @click="emit('historico')"
                        >
                            <i class="pi pi-history" />
                            <span class="evento-act__label">Sessões</span>
                        </button>
                        <button
                            class="evento-act"
                            :disabled="busy"
                            @click="emit('whatsapp')"
                        >
                            <i class="pi pi-whatsapp" />
                            <span class="evento-act__label">Conversar</span>
                        </button>
                        <button
                            class="evento-act"
                            :disabled="busy"
                            v-tooltip.top="'Editar cadastro do paciente'"
                            @click="emit('edit-paciente')"
                        >
                            <i class="pi pi-user-edit" />
                            <span class="evento-act__label">Editar</span>
                        </button>
                    </div>
                </section>

                <!-- Grupo Financeiro — abre dialog com todos os lançamentos
                     vinculados a esta sessão (cobrança original + multas/taxas)
                     + antecipar pagamento (paciente paga antes da sessão).
                     Adicionado 2026-05-14. Só pra sessão com paciente. -->
                <section v-if="isSessaoComPaciente" class="evento-actions__section">
                    <div class="evento-actions__label">Financeiro:</div>
                    <div class="evento-actions__group">
                        <button
                            class="evento-act"
                            :disabled="busy"
                            v-tooltip.top="'Ver lançamentos vinculados a esta sessão'"
                            @click="emit('ver-lancamentos')"
                        >
                            <i class="pi pi-list" />
                            <span class="evento-act__label">Lançamentos</span>
                        </button>
                        <button
                            v-if="!isAntecipacaoAtiva"
                            class="evento-act"
                            :disabled="busy"
                            v-tooltip.top="'Paciente quer pagar antes da sessão (pacote saldo)'"
                            @click="emit('antecipar-pagamento')"
                        >
                            <i class="pi pi-money-bill" />
                            <span class="evento-act__label">Antecipar pagamento</span>
                        </button>
                        <template v-else>
                            <button
                                class="evento-act"
                                :disabled="busy"
                                v-tooltip.top="'Atualizar a forma de pagamento sem cancelar o registro (não gera lixo no histórico)'"
                                @click="emit('trocar-metodo-antecipacao')"
                            >
                                <i class="pi pi-sync" />
                                <span class="evento-act__label">Trocar método</span>
                            </button>
                            <button
                                class="evento-act evento-act--danger"
                                :disabled="busy"
                                v-tooltip.top="'Desfazer o pagamento antecipado — cancela o lançamento'"
                                @click="emit('revogar-antecipacao')"
                            >
                                <i class="pi pi-times-circle" />
                                <span class="evento-act__label">Revogar pagamento</span>
                            </button>
                        </template>
                    </div>
                </section>

                <!-- Grupo Geral (não-sessão: bloqueio/compromisso/etc).
                     Aqui "Editar" abre o evento em si (não tem paciente). -->
                <section v-else class="evento-actions__section">
                    <div class="evento-actions__group">
                        <button
                            class="evento-act"
                            :disabled="busy"
                            @click="emit('edit-sessao')"
                        >
                            <i class="pi pi-pencil" />
                            <span class="evento-act__label">Editar</span>
                        </button>
                    </div>
                </section>
            </footer>
        </div>
    </div>
</template>

<style scoped>
/* Camada full-screen com backdrop blur — mantém pattern .evento-layer
   que vivia inline no MelissaLayout (assim o lift transition no parent
   continua funcionando sem alteração). */
.evento-layer {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: grid;
    place-items: center;
    /* Blur XS — bem leve. O resumo continua legível atrás, só ganha
       um leve "tilt-shift" pra direcionar o olhar pro panel. */
    background: rgba(0, 0, 0, 0.32);
    backdrop-filter: blur(4px) saturate(110%);
    -webkit-backdrop-filter: blur(4px) saturate(110%);
    padding: 20px;
}

.evento-panel {
    width: 100%;
    max-width: 480px;
    background: var(--m-bg-medium, rgba(20, 20, 20, 0.85));
    backdrop-filter: blur(28px) saturate(170%);
    -webkit-backdrop-filter: blur(28px) saturate(170%);
    border: 1px solid var(--m-border, rgba(255, 255, 255, 0.12));
    border-radius: 18px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
    color: var(--m-text);
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    padding: 22px 22px 18px;
    display: flex;
    flex-direction: column;
    gap: 18px;
}

/* ─── Header ────────────────────────────────────── */
.evento-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}
.evento-head__main {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
.evento-pill {
    width: 4px;
    height: 38px;
    border-radius: 2px;
    flex-shrink: 0;
}
.evento-tipo {
    color: var(--m-text-muted);
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    font-weight: 600;
}
.evento-tipo__series {
    color: var(--p-primary-color);
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
    margin-left: 4px;
}
.evento-titulo {
    color: var(--m-text);
    font-size: 1.1rem;
    font-weight: 500;
    margin-top: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 340px;
}
.evento-close {
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    flex-shrink: 0;
    background: var(--m-bg-soft, rgba(255, 255, 255, 0.08));
    border: 1px solid var(--m-border, rgba(255, 255, 255, 0.12));
    color: var(--m-text);
    border-radius: 10px;
    cursor: pointer;
    transition: background-color 140ms ease;
    font-size: 0.85rem;
}
.evento-close:hover { background: var(--m-bg-soft-hover, rgba(255, 255, 255, 0.16)); }

/* ─── Conteúdo ──────────────────────────────────── */
.evento-content {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.evento-row {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--m-text);
    font-size: 0.88rem;
}
.evento-row > i {
    color: var(--m-text-muted);
    font-size: 0.95rem;
    width: 18px;
    text-align: center;
}
.evento-row__sub {
    color: var(--m-text-muted);
    margin-left: 4px;
    font-size: 0.82rem;
}

/* Linha de cobrança — espelha os 3 canais visuais da agenda:
   - paid: verde (estado-alvo, sessão quitada)
   - pending: amber (cobrança gerada mas não paga)
   - none: amber leve (sem cobrança gerada ainda) */
.evento-row--pay {
    font-weight: 500;
}
.evento-row--pay-paid {
    color: #047857; /* emerald-700 */
}
.evento-row--pay-paid > i {
    color: #10b981; /* emerald-500 */
}
html.app-dark .evento-row--pay-paid {
    color: #34d399; /* emerald-400 */
}
html.app-dark .evento-row--pay-paid > i {
    color: #34d399;
}
.evento-row--pay-pending,
.evento-row--pay-none {
    color: #b45309;
}
.evento-row--pay-pending > i,
.evento-row--pay-none > i {
    color: #f59e0b;
}
html.app-dark .evento-row--pay-pending,
html.app-dark .evento-row--pay-none {
    color: #fbbf24;
}
html.app-dark .evento-row--pay-pending > i,
html.app-dark .evento-row--pay-none > i {
    color: #fbbf24;
}
/* Atalho "Gerar fatura" — pill amber pequeno ao lado de "A cobrar R$ X".
   Aparece só pra paymentVariant='none' (sem cobrança ainda). Click emite
   'gerar-cobranca' pro parent que chama gerarCobrancaManual sem abrir
   o AgendaEventDialog. */
.evento-row__pay-action {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px;
    border-radius: 999px;
    background: color-mix(in srgb, #f59e0b 16%, transparent);
    border: 1px solid color-mix(in srgb, #f59e0b 40%, transparent);
    color: #b45309;
    font-size: 0.74rem;
    font-weight: 600;
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color 120ms ease, border-color 120ms ease;
}
.evento-row__pay-action:hover:not(:disabled) {
    background: color-mix(in srgb, #f59e0b 26%, transparent);
    border-color: color-mix(in srgb, #f59e0b 60%, transparent);
}
.evento-row__pay-action:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.evento-row__pay-action > i {
    font-size: 0.72rem;
}
html.app-dark .evento-row__pay-action {
    color: #fbbf24;
    background: color-mix(in srgb, #fbbf24 14%, transparent);
    border-color: color-mix(in srgb, #fbbf24 30%, transparent);
}

/* Linha de contrato — exibe "Pacote saldo · N/M usadas" ou "Pacote · N/M
   realizadas". Saldo em violeta (modelo Cliniko), upfront em verde
   (já cobrado). Acompanha as cores do info card do AgendaEventDialog. */
.evento-row--contract {
    font-weight: 500;
}
.evento-row--contract-saldo {
    color: rgb(124, 58, 237); /* violet-600 */
}
.evento-row--contract-saldo > i {
    color: rgb(124, 58, 237);
}
.evento-row--contract-upfront {
    color: rgb(5, 150, 105); /* emerald-600 */
}
.evento-row--contract-upfront > i {
    color: rgb(5, 150, 105);
}
html.app-dark .evento-row--contract-saldo {
    color: #a78bfa; /* violet-400 */
}
html.app-dark .evento-row--contract-saldo > i {
    color: #a78bfa;
}
html.app-dark .evento-row--contract-upfront {
    color: #34d399; /* emerald-400 */
}
html.app-dark .evento-row--contract-upfront > i {
    color: #34d399;
}
/* Override do pay-action quando dentro da linha de contrato — usa
   violeta (saldo) pra combinar com a linha. */
.evento-row__pay-action--contract {
    color: rgb(124, 58, 237) !important;
    background: color-mix(in srgb, rgb(124, 58, 237) 12%, transparent) !important;
    border-color: color-mix(in srgb, rgb(124, 58, 237) 36%, transparent) !important;
}
.evento-row__pay-action--contract:hover:not(:disabled) {
    background: color-mix(in srgb, rgb(124, 58, 237) 22%, transparent) !important;
    border-color: color-mix(in srgb, rgb(124, 58, 237) 56%, transparent) !important;
}
html.app-dark .evento-row__pay-action--contract {
    color: #a78bfa !important;
    background: color-mix(in srgb, #a78bfa 14%, transparent) !important;
    border-color: color-mix(in srgb, #a78bfa 30%, transparent) !important;
}
/* Revogar — vermelho/amber pra sinalizar ação destrutiva. */
.evento-row__pay-action--revogar {
    color: rgb(220, 38, 38) !important; /* red-600 */
    background: color-mix(in srgb, rgb(220, 38, 38) 10%, transparent) !important;
    border-color: color-mix(in srgb, rgb(220, 38, 38) 32%, transparent) !important;
}
.evento-row__pay-action--revogar:hover:not(:disabled) {
    background: color-mix(in srgb, rgb(220, 38, 38) 18%, transparent) !important;
    border-color: color-mix(in srgb, rgb(220, 38, 38) 50%, transparent) !important;
}
html.app-dark .evento-row__pay-action--revogar {
    color: #f87171 !important; /* red-400 */
    background: color-mix(in srgb, #f87171 14%, transparent) !important;
    border-color: color-mix(in srgb, #f87171 30%, transparent) !important;
}

/* Stack de botões "Editar sessão" + "Excluir sessão" (Fase 5, 2026-05-14).
   Empilhados verticalmente à direita da linha das horas. */
.evento-row__edit-stack {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
    align-items: stretch;
    flex-shrink: 0;
}
.evento-row__edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 4px 10px;
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    border-radius: 100px;
    color: var(--m-text-muted);
    font-size: 0.7rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: background-color 140ms ease, color 140ms ease, border-color 140ms ease;
}
.evento-row__edit:hover:not(:disabled) {
    background: var(--m-bg-soft-hover);
    color: var(--m-text);
    border-color: var(--m-accent, var(--primary-color, #7c6af7));
}
.evento-row__edit:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.evento-row__edit i { font-size: 0.65rem; }
/* Variant primary (Editar sessão — ação principal). */
.evento-row__edit--primary {
    background: var(--primary-color, #7c6af7);
    border-color: var(--primary-color, #7c6af7);
    color: var(--primary-color-text, #fff);
}
.evento-row__edit--primary:hover:not(:disabled) {
    background: color-mix(in srgb, var(--primary-color, #7c6af7) 88%, black);
    border-color: color-mix(in srgb, var(--primary-color, #7c6af7) 88%, black);
    color: var(--primary-color-text, #fff);
}
/* Variant danger (Excluir sessão — destrutivo, outlined). */
.evento-row__edit--danger {
    background: transparent;
    border-color: color-mix(in srgb, var(--red-500, #ef4444) 50%, var(--m-border));
    color: var(--red-400, #f87171);
}
.evento-row__edit--danger:hover:not(:disabled) {
    background: color-mix(in srgb, var(--red-500, #ef4444) 12%, transparent);
    border-color: var(--red-500, #ef4444);
    color: var(--red-300, #fca5a5);
}
.evento-status {
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    border: 1px solid var(--m-border);
    background: var(--m-bg-soft);
}
.evento-status.is-realizado {
    color: rgb(16, 185, 129);
    border-color: rgba(16, 185, 129, 0.35);
    background: rgba(16, 185, 129, 0.12);
}
.evento-status.is-faltou {
    color: rgb(239, 68, 68);
    border-color: rgba(239, 68, 68, 0.35);
    background: rgba(239, 68, 68, 0.12);
}
.evento-status.is-cancelado {
    color: rgb(148, 163, 184);
    border-color: rgba(148, 163, 184, 0.35);
    background: rgba(148, 163, 184, 0.12);
}
.evento-status.is-remarcar {
    color: rgb(245, 158, 11);
    border-color: rgba(245, 158, 11, 0.35);
    background: rgba(245, 158, 11, 0.12);
}
.evento-desc {
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    border-radius: 10px;
    padding: 10px 12px;
    color: var(--m-text);
    font-size: 0.85rem;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 140px;
    overflow-y: auto;
}

/* ─── Action bar ────────────────────────────────── */
.evento-actions {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-top: 14px;
    border-top: 1px solid var(--m-border);
}
.evento-actions__section {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.evento-actions__label {
    font-size: 0.7rem;
    color: var(--m-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
    padding-left: 2px;
}
.evento-actions__group {
    display: flex;
    gap: 4px;
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    border-radius: 12px;
    padding: 4px;
}
.evento-act {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 8px 4px;
    background: transparent;
    border: none;
    color: var(--m-text);
    border-radius: 9px;
    cursor: pointer;
    font-size: 1rem;
    font-family: inherit;
    transition: background-color 140ms ease, color 140ms ease, transform 140ms ease;
}
.evento-act__label {
    font-size: 0.7rem;
    line-height: 1.1;
    font-weight: 500;
    letter-spacing: 0.01em;
    white-space: nowrap;
}
.evento-act:hover:not(:disabled) {
    background: var(--m-bg-soft-hover);
    transform: translateY(-1px);
}
.evento-act:focus-visible {
    outline: 2px solid var(--m-accent);
    outline-offset: 2px;
}
.evento-act:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}
.evento-act--info:hover:not(:disabled) {
    color: rgb(56, 189, 248);
    background: rgba(56, 189, 248, 0.10);
}
.evento-act--ok:hover:not(:disabled) {
    color: rgb(16, 185, 129);
    background: rgba(16, 185, 129, 0.15);
}
.evento-act--warn:hover:not(:disabled) {
    color: rgb(245, 158, 11);
    background: rgba(245, 158, 11, 0.15);
}
.evento-act--danger:hover:not(:disabled) {
    color: rgb(239, 68, 68);
    background: rgba(239, 68, 68, 0.15);
}

/* Estado .is-current — sinaliza o status atual da sessão dentro do
   grupo de actions. Permite que o usuário troque o status mesmo após
   marcar realizado/faltou/cancelado, vendo qual está ativo. */
.evento-act.is-current {
    background: rgba(255, 255, 255, 0.12);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
}
.evento-act--info.is-current {
    color: rgb(56, 189, 248);
    background: rgba(56, 189, 248, 0.18);
    box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.55);
}
.evento-act--ok.is-current {
    color: rgb(16, 185, 129);
    background: rgba(16, 185, 129, 0.18);
    box-shadow: inset 0 0 0 1px rgba(16, 185, 129, 0.55);
}
.evento-act--warn.is-current {
    color: rgb(245, 158, 11);
    background: rgba(245, 158, 11, 0.18);
    box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.55);
}
.evento-act--danger.is-current {
    color: rgb(239, 68, 68);
    background: rgba(239, 68, 68, 0.18);
    box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.55);
}

/* Light mode — overlay ainda mais discreto */
html:not(.app-dark) .evento-layer {
    background: rgba(15, 23, 42, 0.18);
}
</style>
