<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/views/pages/account/ProfilePage.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<script setup>
import { useConfirm } from 'primevue/useconfirm';
import { useToast } from 'primevue/usetoast';
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';

import { useLayout as _useLayout } from '@/layout/composables/layout';
import { applyThemeEngine } from '@/theme/theme.options';
const { setVariant } = _useLayout();

import Checkbox from 'primevue/checkbox';
import InputMask from 'primevue/inputmask';
import Select from 'primevue/select';
import Textarea from 'primevue/textarea';

import { useLayout } from '@/layout/composables/layout';
import { supabase } from '@/lib/supabase/client';

const router = useRouter();
const toast = useToast();
const confirm = useConfirm();

const mounted = ref(false);

/** trava para não marcar dirty durante o load */
const silentApplying = ref(true);

/** Storage bucket do avatar */
const AVATAR_BUCKET = 'avatars';

/* ----------------------------
   Estado geral
----------------------------- */
const saving = ref(false);
const dirty = ref(false);

const fieldErrors = reactive({
    full_name: '',
    nickname: '',
    phone: ''
});

function clearErr(field) {
    fieldErrors[field] = '';
}

function validateRequired() {
    const nameParts = form.full_name?.trim().split(/\s+/).filter(Boolean) || [];
    fieldErrors.full_name = nameParts.length === 0 ? 'Nome completo é obrigatório.' : nameParts.length < 2 ? 'Informe seu nome e sobrenome.' : '';
    fieldErrors.nickname = form.nickname?.trim() ? '' : 'Nome de exibição é obrigatório.';
    const digits = form.phone?.replace(/[^0-9]/g, '') || '';
    fieldErrors.phone = digits.length >= 10 ? '' : 'WhatsApp é obrigatório.';
    return !fieldErrors.full_name && !fieldErrors.nickname && !fieldErrors.phone;
}

const openPassword = ref(false);
const sendingPassword = ref(false);
const passwordSent = ref(false);

const userEmail = ref('');
const userId = ref('');

const fileInput = ref(null);

const ui = reactive({
    avatarPreview: '',
    avatarFile: null,
    avatarFilePreviewUrl: ''
});

// Perfil
const form = reactive({
    full_name: '',
    nickname: '',
    work_description: '',
    work_description_other: '',
    avatar_url: '',
    bio: '',
    phone: '',

    site_url: '',
    social_instagram: '',
    social_youtube: '',
    social_facebook: '',
    social_x: '',

    language: 'pt-BR',
    timezone: 'America/Sao_Paulo',

    notify_system_email: true,
    notify_reminders: true,
    notify_news: false
});

const customSocials = ref([]);

function addCustomSocial() {
    customSocials.value.push({ name: '', url: '' });
    markDirty();
}

function removeCustomSocial(idx) {
    customSocials.value.splice(idx, 1);
    markDirty();
}

const workDescriptionOptions = [
    { label: 'Psicólogo(a) Clínico(a)', value: 'psicologo_clinico' },
    { label: 'Psicanalista', value: 'psicanalista' },
    { label: 'Psiquiatra', value: 'psiquiatra' },
    { label: 'Psicoterapeuta', value: 'psicoterapeuta' },
    { label: 'Neuropsicólogo(a)', value: 'neuropsicologo' },
    { label: 'Psicólogo(a) Organizacional', value: 'psicologo_organizacional' },
    { label: 'Psicólogo(a) Escolar / Educacional', value: 'psicologo_escolar' },
    { label: 'Psicólogo(a) Hospitalar', value: 'psicologo_hospitalar' },
    { label: 'Psicólogo(a) Jurídico(a)', value: 'psicologo_juridico' },
    { label: 'Coach / Mentor(a)', value: 'coach_mentor' },
    { label: 'Terapeuta Holístico(a)', value: 'terapeuta_holistico' },
    { label: 'Outro', value: 'outro' }
];

const sections = [
    { id: 'conta', label: 'Conta', icon: 'pi pi-user' },
    { id: 'redes-sociais', label: 'Sites e Redes', icon: 'pi pi-share-alt' },
    { id: 'avatar', label: 'Avatar', icon: 'pi pi-image' },
    { id: 'layout', label: 'Aparência', icon: 'pi pi-palette' },
    { id: 'preferencias', label: 'Preferências', icon: 'pi pi-sliders-h' },
    { id: 'layout-variant', label: 'Layout', icon: 'pi pi-th-large' },
    { id: 'seguranca', label: 'Segurança', icon: 'pi pi-shield' }
];

const activeSection = ref('conta');

const initials = computed(() => {
    const name = form.full_name || userEmail.value || '';
    const parts = String(name).trim().split(/\s+/).filter(Boolean);
    const a = parts[0]?.[0] || 'U';
    const b = parts.length > 1 ? parts[parts.length - 1][0] : '';
    return (a + b).toUpperCase();
});

function markDirty() {
    dirty.value = true;
}

/* ----------------------------
   Gamificação / Progresso
----------------------------- */
const profileFields = computed(() => [
    { key: 'full_name', filled: !!form.full_name?.trim(), icon: 'pi pi-user', text: 'Preencha seu nome completo' },
    { key: 'nickname', filled: !!form.nickname?.trim(), icon: 'pi pi-comment', text: 'Escolha um nome de exibição' },
    { key: 'work_description', filled: !!form.work_description?.trim(), icon: 'pi pi-briefcase', text: 'Descreva seu trabalho' },
    { key: 'avatar', filled: !!(form.avatar_url?.trim() || ui.avatarFile), icon: 'pi pi-image', text: 'Adicione uma foto' },
    { key: 'bio', filled: !!form.bio?.trim(), icon: 'pi pi-pencil', text: 'Complete sua bio' },
    { key: 'phone', filled: !!form.phone?.trim()?.replace(/[^0-9]/g, ''), icon: 'pi pi-whatsapp', text: 'Informe seu WhatsApp' },
    { key: 'social', filled: !!(form.social_instagram || form.social_x || form.site_url || form.social_youtube || form.social_facebook || customSocials.value.length), icon: 'pi pi-share-alt', text: 'Adicione uma rede social' }
]);

const profileProgress = computed(() => {
    const filled = profileFields.value.filter((f) => f.filled).length;
    return Math.round((filled / profileFields.value.length) * 100);
});

const progressSuggestions = computed(() => profileFields.value.filter((f) => !f.filled));

const progressColor = computed(() => {
    if (profileProgress.value >= 80) return '#10b981';
    if (profileProgress.value >= 50) return '#f59e0b';
    return '#ef4444';
});

const gameLevels = [
    { min: 0, max: 14, label: 'Iniciante', icon: '🌱', color: '#94a3b8' },
    { min: 15, max: 28, label: 'Aprendiz', icon: '🌿', color: '#60a5fa' },
    { min: 29, max: 42, label: 'Praticante', icon: '⚡', color: '#f59e0b' },
    { min: 43, max: 57, label: 'Avançado', icon: '🔥', color: '#f97316' },
    { min: 58, max: 71, label: 'Expert', icon: '💎', color: '#a78bfa' },
    { min: 72, max: 85, label: 'Mestre', icon: '🏆', color: '#10b981' },
    { min: 86, max: 100, label: 'Lendário', icon: '🌟', color: '#eab308' }
];

const currentLevel = computed(() => gameLevels.find((l) => profileProgress.value >= l.min && profileProgress.value <= l.max) || gameLevels[0]);
const nextLevel = computed(() => {
    const i = gameLevels.indexOf(currentLevel.value);
    return i < gameLevels.length - 1 ? gameLevels[i + 1] : null;
});
const xpToNext = computed(() => (nextLevel.value ? nextLevel.value.min - profileProgress.value : 0));

const badges = computed(() => [
    { key: 'name', earned: !!form.full_name?.trim(), icon: '👤', label: 'Identificado' },
    { key: 'nick', earned: !!form.nickname?.trim(), icon: '✏️', label: 'Apelido' },
    { key: 'work', earned: !!form.work_description?.trim(), icon: '💼', label: 'Profissional' },
    { key: 'photo', earned: !!(form.avatar_url?.trim() || ui.avatarFile), icon: '📷', label: 'Fotogênico' },
    { key: 'bio', earned: !!form.bio?.trim(), icon: '📝', label: 'Eloquente' },
    { key: 'phone', earned: !!form.phone?.trim()?.replace(/[^0-9]/g, ''), icon: '📱', label: 'Conectado' },
    { key: 'social', earned: !!(form.social_instagram || form.social_x || form.site_url || form.social_youtube || form.social_facebook || customSocials.value.length), icon: '🌐', label: 'Social' }
]);

/* ----------------------------
   Cores e preset
----------------------------- */
const primaryColors = [
    { name: 'noir', palette: { 500: 'currentColor' } },
    { name: 'emerald', palette: { 500: '#10b981' } },
    { name: 'green', palette: { 500: '#22c55e' } },
    { name: 'lime', palette: { 500: '#84cc16' } },
    { name: 'orange', palette: { 500: '#f97316' } },
    { name: 'amber', palette: { 500: '#f59e0b' } },
    { name: 'yellow', palette: { 500: '#eab308' } },
    { name: 'teal', palette: { 500: '#14b8a6' } },
    { name: 'cyan', palette: { 500: '#06b6d4' } },
    { name: 'sky', palette: { 500: '#0ea5e9' } },
    { name: 'blue', palette: { 500: '#3b82f6' } },
    { name: 'indigo', palette: { 500: '#6366f1' } },
    { name: 'violet', palette: { 500: '#8b5cf6' } },
    { name: 'purple', palette: { 500: '#a855f7' } },
    { name: 'fuchsia', palette: { 500: '#d946ef' } },
    { name: 'pink', palette: { 500: '#ec4899' } },
    { name: 'rose', palette: { 500: '#f43f5e' } }
];

const surfaces = [
    { name: 'slate', palette: { 500: '#64748b' } },
    { name: 'gray', palette: { 500: '#6b7280' } },
    { name: 'zinc', palette: { 500: '#71717a' } },
    { name: 'neutral', palette: { 500: '#737373' } },
    { name: 'stone', palette: { 500: '#78716c' } }
];

const presetOptions = ['Aura', 'Lara', 'Nora'];

/* ----------------------------
   Navegação (sidebar)
----------------------------- */
// ── Hero menu (mobile < 1200px) ──────────────────────────
const heroMenuRef = ref(null);
const heroEl = ref(null);
const heroSentinelRef = ref(null);
const heroStuck = ref(false);

const heroMenuItems = computed(() => [
    { label: 'Voltar', icon: 'pi pi-arrow-left', command: () => router.back() },
    { label: 'Salvar alterações', icon: 'pi pi-check', command: () => saveAll(), disabled: !dirty.value },
    { separator: true },
    {
        label: 'Menu desta sessão',
        items: sections.map((s) => ({ label: s.label, icon: s.icon, command: () => scrollTo(s.id) }))
    }
]);

let disconnectStickyObserver = null;

function scrollTo(id) {
    activeSection.value = id;
    const el = document.getElementById(id);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

function observeSections() {
    const ids = sections.map((s) => s.id);
    const els = ids.map((id) => document.getElementById(id)).filter(Boolean);

    const io = new IntersectionObserver(
        (entries) => {
            const visible = entries.filter((e) => e.isIntersecting).sort((a, b) => (b.intersectionRatio || 0) - (a.intersectionRatio || 0))[0];
            if (visible?.target?.id) activeSection.value = visible.target.id;
        },
        { root: null, threshold: [0.2, 0.35, 0.5], rootMargin: '-15% 0px -70% 0px' }
    );

    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
}

let disconnectObserver = null;

/* ----------------------------
   Avatar: URL
----------------------------- */
function onAvatarUrlChange() {
    ui.avatarPreview = String(form.avatar_url || '').trim();
    markDirty();
}

function removeAvatar() {
    form.avatar_url = '';
    ui.avatarPreview = '';
    clearAvatarFile();
    markDirty();
}

/* ----------------------------
   Avatar: upload arquivo
----------------------------- */
function clearAvatarFile() {
    ui.avatarFile = null;
    if (ui.avatarFilePreviewUrl) {
        try {
            URL.revokeObjectURL(ui.avatarFilePreviewUrl);
        } catch {}
    }
    ui.avatarFilePreviewUrl = '';
    if (fileInput.value) fileInput.value.value = '';
}

function onAvatarFileSelected(ev) {
    const file = ev?.target?.files?.[0];
    if (!file) return;

    if (!file.type?.startsWith('image/')) {
        toast.add({ severity: 'warn', summary: 'Arquivo inválido', detail: 'Escolha uma imagem (PNG/JPG/WebP).', life: 3500 });
        clearAvatarFile();
        return;
    }

    if (file.size > 5 * 1024 * 1024) {
        toast.add({ severity: 'warn', summary: 'Arquivo grande', detail: 'Máximo recomendado: 5MB.', life: 3500 });
        clearAvatarFile();
        return;
    }

    ui.avatarFile = file;

    if (ui.avatarFilePreviewUrl) {
        try {
            URL.revokeObjectURL(ui.avatarFilePreviewUrl);
        } catch {}
    }
    ui.avatarFilePreviewUrl = URL.createObjectURL(file);
    ui.avatarPreview = ui.avatarFilePreviewUrl;

    markDirty();
}

function applyFilePreviewOnly() {
    if (!ui.avatarFilePreviewUrl) return;
    ui.avatarPreview = ui.avatarFilePreviewUrl;
    markDirty();
}

function extFromMime(mime) {
    if (!mime) return 'png';
    if (mime.includes('jpeg')) return 'jpg';
    if (mime.includes('png')) return 'png';
    if (mime.includes('webp')) return 'webp';
    return 'png';
}

async function uploadAvatarIfNeeded() {
    if (!ui.avatarFile) return null;
    if (!userId.value) throw new Error('Sessão inválida para upload.');

    const file = ui.avatarFile;
    const ext = extFromMime(file.type);
    const path = `${userId.value}/avatar-${Date.now()}.${ext}`;

    const { error: upErr } = await supabase.storage.from(AVATAR_BUCKET).upload(path, file, { upsert: true, contentType: file.type });

    if (upErr) throw upErr;

    const { data } = supabase.storage.from(AVATAR_BUCKET).getPublicUrl(path);
    const url = data?.publicUrl;
    if (!url) throw new Error('Upload ok, mas não consegui obter a URL pública.');

    return url;
}

/* ----------------------------
   Aparência (SEM duplicar engine)
----------------------------- */
const { layoutConfig, layoutState, toggleDarkMode, changeMenuMode } = useLayout();

function isDarkNow() {
    return document.documentElement.classList.contains('app-dark');
}

function setDarkMode(shouldBeDark) {
    if (shouldBeDark !== isDarkNow()) toggleDarkMode();
}

const presetModel = computed({
    get: () => layoutConfig.preset,
    set: (val) => {
        if (!val || val === layoutConfig.preset) return;
        layoutConfig.preset = val;
        applyThemeEngine(layoutConfig);
        if (!silentApplying.value) markDirty();
    }
});

const menuModeOptions = [
    { label: 'Static', value: 'static' },
    { label: 'Overlay', value: 'overlay' }
];

const menuModeModel = computed({
    get: () => layoutConfig.menuMode,
    set: (val) => {
        if (!val || val === layoutConfig.menuMode) return;
        layoutConfig.menuMode = val;
        // Não chama changeMenuMode() no Rail — ela reseta estados do sidebar
        if (layoutConfig.variant !== 'rail') {
            try {
                changeMenuMode?.(val);
            } catch {
                try {
                    changeMenuMode?.({ value: val });
                } catch {}
            }
        }
        if (!silentApplying.value) markDirty();
    }
});

const themeModeOptions = [
    { label: 'Claro', value: 'light' },
    { label: 'Escuro', value: 'dark' }
];

const themeModeModel = computed({
    get: () => (isDarkNow() ? 'dark' : 'light'),
    set: async (val) => {
        if (!val) return;
        setDarkMode(val === 'dark');
        await nextTick();
        if (!silentApplying.value) markDirty();
    }
});

function updateColors(type, item) {
    if (type === 'primary') {
        layoutConfig.primary = item.name;
        applyThemeEngine(layoutConfig);
        if (!silentApplying.value) markDirty();
        return;
    }
    if (type === 'surface') {
        layoutConfig.surface = item.name;
        applyThemeEngine(layoutConfig);
        if (!silentApplying.value) markDirty();
    }
}

/* ----------------------------
   DB: carregar/aplicar settings
----------------------------- */
function safeEq(a, b) {
    return String(a || '').trim() === String(b || '').trim();
}

async function loadUserSettings(uid) {
    const { data: settings, error } = await supabase.from('user_settings').select('theme_mode, preset, primary_color, surface_color, menu_mode, layout_variant').eq('user_id', uid).maybeSingle();

    if (error) {
        const msg = String(error.message || '');
        const tolerant = /does not exist/i.test(msg) || /relation .* does not exist/i.test(msg) || /permission denied/i.test(msg) || /violates row-level security/i.test(msg);
        if (!tolerant) throw error;
        return null;
    }

    if (!settings) return null;

    if (settings.theme_mode) setDarkMode(settings.theme_mode === 'dark');

    if (settings.preset && !safeEq(settings.preset, layoutConfig.preset)) layoutConfig.preset = settings.preset;
    if (settings.primary_color && !safeEq(settings.primary_color, layoutConfig.primary)) layoutConfig.primary = settings.primary_color;
    if (settings.surface_color && !safeEq(settings.surface_color, layoutConfig.surface)) layoutConfig.surface = settings.surface_color;
    if (settings.menu_mode && !safeEq(settings.menu_mode, layoutConfig.menuMode)) {
        layoutConfig.menuMode = settings.menu_mode;
        // Não chama changeMenuMode() — ela reseta staticMenuInactive e outros estados,
        // fazendo a sidebar desaparecer ao entrar na página.
    }

    // Variant NÃO é re-aplicada aqui: bootstrapUserSettings cuida disso no arranque.
    // Re-aplicar no loadUserSettings causava regressão (dado stale do banco sobrescrevia
    // o variant ativo). A UI lê layoutConfig.variant diretamente para exibir a seleção.

    applyThemeEngine(layoutConfig);

    return settings;
}

/* ----------------------------
   Load / Save (perfil)
----------------------------- */
async function ensureProfileExists(uid) {
    const { data: prof, error: selErr } = await supabase.from('profiles').select('id, role').eq('id', uid).maybeSingle();

    if (selErr) throw selErr;
    if (prof?.id) return prof;

    const { data: created, error: insErr } = await supabase.from('profiles').insert({ id: uid, role: 'portal_user' }).select('id, role').single();

    if (insErr) throw insErr;
    return created;
}

async function loadProfile() {
    silentApplying.value = true;

    const { data: u, error: uErr } = await supabase.auth.getUser();
    if (uErr) throw uErr;
    const user = u?.user;
    if (!user) throw new Error('Você precisa estar logado.');

    userId.value = user.id;
    userEmail.value = user.email || '';

    await ensureProfileExists(user.id);

    const meta = user.user_metadata || {};
    form.full_name = meta.full_name || '';
    form.avatar_url = meta.avatar_url || '';
    ui.avatarPreview = form.avatar_url;

    const { data: prof, error: pErr } = await supabase
        .from('profiles')
        .select(
            'full_name, avatar_url, phone, bio, nickname, work_description, work_description_other, site_url, social_instagram, social_youtube, social_facebook, social_x, social_custom, language, timezone, notify_system_email, notify_reminders, notify_news'
        )
        .eq('id', user.id)
        .maybeSingle();

    if (!pErr && prof) {
        form.full_name = prof.full_name ?? form.full_name;
        form.avatar_url = prof.avatar_url ?? form.avatar_url;
        form.phone = prof.phone ?? '';
        form.bio = prof.bio ?? '';
        form.nickname = prof.nickname ?? '';
        form.work_description = prof.work_description ?? '';
        form.work_description_other = prof.work_description_other ?? '';
        form.site_url = prof.site_url ?? '';
        form.social_instagram = prof.social_instagram ?? '';
        form.social_youtube = prof.social_youtube ?? '';
        form.social_facebook = prof.social_facebook ?? '';
        form.social_x = prof.social_x ?? '';

        if (Array.isArray(prof.social_custom)) {
            customSocials.value = prof.social_custom;
        }

        form.language = prof.language ?? form.language;
        form.timezone = prof.timezone ?? form.timezone;

        if (typeof prof.notify_system_email === 'boolean') form.notify_system_email = prof.notify_system_email;
        if (typeof prof.notify_reminders === 'boolean') form.notify_reminders = prof.notify_reminders;
        if (typeof prof.notify_news === 'boolean') form.notify_news = prof.notify_news;

        ui.avatarPreview = form.avatar_url;
    }

    await loadUserSettings(user.id);

    silentApplying.value = false;
    dirty.value = false;
}

async function saveAll() {
    if (!validateRequired()) {
        toast.add({ severity: 'warn', summary: 'Campos obrigatórios', detail: 'Preencha nome completo, nome de exibição e WhatsApp antes de salvar.', life: 4000 });
        // Rola até a seção Conta para o usuário ver os erros
        document.getElementById('conta')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
        return;
    }
    saving.value = true;
    try {
        if (ui.avatarFile) {
            try {
                const uploadedUrl = await uploadAvatarIfNeeded();
                if (uploadedUrl) {
                    form.avatar_url = uploadedUrl;
                    ui.avatarPreview = uploadedUrl;
                }
            } catch (e) {
                toast.add({
                    severity: 'warn',
                    summary: 'Avatar não subiu',
                    detail: `Não consegui enviar o arquivo (bucket "${AVATAR_BUCKET}"). Você pode usar Avatar URL. (${e?.message || 'erro'})`,
                    life: 6500
                });
            }
        }

        const metaPayload = {
            full_name: String(form.full_name || '').trim(),
            avatar_url: String(form.avatar_url || '').trim() || null
        };

        const { error: upErr } = await supabase.auth.updateUser({ data: metaPayload });
        if (upErr) throw upErr;

        await ensureProfileExists(userId.value);

        const profilePayload = {
            full_name: metaPayload.full_name,
            avatar_url: metaPayload.avatar_url,
            phone: String(form.phone || '').trim() || null,
            bio: String(form.bio || '').trim() || null,
            nickname: String(form.nickname || '').trim() || null,
            work_description: String(form.work_description || '').trim() || null,
            work_description_other: form.work_description === 'outro' ? String(form.work_description_other || '').trim() || null : null,
            site_url: String(form.site_url || '').trim() || null,
            social_instagram: String(form.social_instagram || '').trim() || null,
            social_youtube: String(form.social_youtube || '').trim() || null,
            social_facebook: String(form.social_facebook || '').trim() || null,
            social_x: String(form.social_x || '').trim() || null,
            social_custom: customSocials.value.filter((s) => s.name || s.url),

            language: form.language || 'pt-BR',
            timezone: form.timezone || 'America/Sao_Paulo',

            notify_system_email: !!form.notify_system_email,
            notify_reminders: !!form.notify_reminders,
            notify_news: !!form.notify_news
        };

        const { data: updatedProfile, error: pErr2 } = await supabase
            .from('profiles')
            .update(profilePayload)
            .eq('id', userId.value)
            .select(
                'id, role, full_name, avatar_url, phone, bio, nickname, work_description, work_description_other, site_url, social_instagram, social_youtube, social_facebook, social_x, social_custom, language, timezone, notify_system_email, notify_reminders, notify_news, updated_at'
            )
            .single();

        if (pErr2) {
            const msg = String(pErr2.message || '');
            const tolerant = /does not exist/i.test(msg) || /column .* does not exist/i.test(msg) || /relation .* does not exist/i.test(msg) || /permission denied/i.test(msg) || /violates row-level security/i.test(msg);
            if (!tolerant) throw pErr2;
        }

        if (!updatedProfile) {
            throw new Error('Perfil não encontrado para atualização (profiles).');
        }

        const settingsPayload = {
            user_id: userId.value,
            theme_mode: isDarkNow() ? 'dark' : 'light',
            preset: layoutConfig.preset || 'Aura',
            primary_color: layoutConfig.primary || 'noir',
            surface_color: layoutConfig.surface || 'slate',
            menu_mode: layoutConfig.menuMode || 'static',
            layout_variant: layoutConfig.variant || 'rail',
            updated_at: new Date().toISOString()
        };

        const { error: sErr } = await supabase.from('user_settings').upsert(settingsPayload, { onConflict: 'user_id' });

        if (sErr) {
            const msg = String(sErr.message || '');
            const tolerant = /does not exist/i.test(msg) || /relation .* does not exist/i.test(msg) || /permission denied/i.test(msg) || /violates row-level security/i.test(msg);
            if (!tolerant) throw sErr;
        }

        clearAvatarFile();
        dirty.value = false;
        layoutState._variantDirty = false;
        toast.add({ severity: 'success', summary: 'Salvo', detail: 'Seu perfil foi atualizado.', life: 2500 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao salvar', detail: e?.message || 'Não consegui salvar.', life: 6000 });
    } finally {
        saving.value = false;
    }
}

/* ----------------------------
   Segurança: reset + signout
----------------------------- */
async function sendPasswordReset() {
    if (!userEmail.value) return;
    sendingPassword.value = true;
    passwordSent.value = false;
    try {
        const redirectTo = `${window.location.origin}/auth/reset-password`;
        const { error } = await supabase.auth.resetPasswordForEmail(userEmail.value, { redirectTo });
        if (error) throw error;
        passwordSent.value = true;
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao enviar e-mail.', life: 5000 });
    } finally {
        sendingPassword.value = false;
    }
}

function confirmSignOut() {
    confirm.require({
        header: 'Sair',
        message: 'Deseja sair da sua conta neste dispositivo?',
        icon: 'pi pi-exclamation-triangle',
        acceptLabel: 'Sair',
        rejectLabel: 'Cancelar',
        acceptClass: 'p-button-danger',
        accept: async () => {
            try {
                await supabase.auth.signOut();
            } finally {
                router.push('/auth/login');
            }
        }
    });
}

/* ----------------------------
   Lifecycle
----------------------------- */
onMounted(async () => {
    try {
        await loadProfile();
        mounted.value = true;
        disconnectObserver = observeSections();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Não consegui carregar o perfil.', life: 6000 });
    }

    // Sticky detection: sentinel sai da área visível (top 56px = topbar) → hero grudou
    const sentinel = heroSentinelRef.value;
    if (sentinel) {
        const io = new IntersectionObserver(
            ([entry]) => {
                heroStuck.value = !entry.isIntersecting;
            },
            { rootMargin: `${document.querySelector('.l2-main') ? '0px' : '-56px'} 0px 0px 0px` }
        );
        io.observe(sentinel);
        disconnectStickyObserver = () => io.disconnect();
    }
});

onBeforeUnmount(() => {
    try {
        disconnectObserver?.();
    } catch {}
    try {
        disconnectStickyObserver?.();
    } catch {}
    clearAvatarFile();
});
</script>

<template>
    <!-- ── HERO ────────────────────────────────────────────── -->
    <div ref="heroSentinelRef" class="p-2" />
    <div
        ref="heroEl"
        class="sticky mx-3 md:mx-4 mb-4 z-20 overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-2"
        :style="{ top: 'var(--layout-sticky-top, 55px)' }"
        :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-80 h-80 -top-20 -right-16 bg-indigo-500/[0.14]" />
            <div class="absolute rounded-full blur-[70px] w-[22rem] h-[22rem] top-4 -left-20 bg-emerald-400/10" />
            <div class="absolute rounded-full blur-[70px] w-64 h-64 -bottom-12 right-20 bg-fuchsia-500/[0.09]" />
        </div>

        <div class="relative z-10 flex items-center gap-5 flex-wrap">
            <div class="flex items-center gap-4 flex-1 min-w-0">
                <div class="relative shrink-0">
                    <img v-if="ui.avatarPreview" :src="ui.avatarPreview" class="w-16 h-16 rounded-[1.125rem] border-2 border-[var(--surface-border)] block object-cover" alt="avatar" />
                    <div v-else class="w-16 h-16 rounded-[1.125rem] border-2 border-[var(--surface-border)] grid place-items-center bg-[var(--surface-ground)] text-[1.3rem] font-extrabold text-[var(--text-color)]">{{ initials }}</div>
                    <span class="absolute bottom-[-3px] right-[-3px] w-[0.9rem] h-[0.9rem] rounded-full bg-emerald-400 border-[2.5px] border-[var(--surface-card)]" />
                </div>
                <div class="min-w-0">
                    <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] leading-snug truncate">{{ form.full_name || 'Meu Perfil' }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5 truncate">{{ userEmail || 'Gerencie suas informações pessoais e segurança' }}</div>
                </div>
            </div>

            <!-- Desktop (≥1200px) -->
            <div class="hidden xl:flex items-center gap-2 shrink-0">
                <Button label="Voltar" icon="pi pi-arrow-left" severity="secondary" outlined class="rounded-full" @click="router.back()" />
                <Button label="Salvar" icon="pi pi-check" class="rounded-full" :loading="saving" :disabled="!dirty" @click="saveAll" />
            </div>

            <!-- Mobile (<1200px) -->
            <div class="flex xl:hidden items-center gap-2 shrink-0">
                <Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => heroMenuRef.toggle(e)" />
                <Menu ref="heroMenuRef" :model="heroMenuItems" :popup="true" />
            </div>
        </div>
    </div>

    <!-- ── PROGRESSO / GAMIFICAÇÃO ──────────────────────────── -->
    <div class="px-3 md:px-4 mb-4">
        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-4 space-y-4">
            <!-- Nível + barra -->
            <div class="flex items-center gap-4">
                <div class="shrink-0 w-12 h-12 rounded-xl flex items-center justify-center text-2xl border" :style="{ backgroundColor: currentLevel.color + '18', borderColor: currentLevel.color + '40' }" v-tooltip.top="currentLevel.label">
                    {{ currentLevel.icon }}
                </div>

                <div class="flex-1 min-w-0">
                    <div class="flex items-center justify-between mb-1.5">
                        <div class="flex items-center gap-2">
                            <span class="text-[1rem] font-bold text-[var(--text-color)]">{{ currentLevel.label }}</span>
                            <span class="text-xs font-semibold px-2 py-0.5 rounded-full" :style="{ backgroundColor: currentLevel.color + '20', color: currentLevel.color }">Nível {{ gameLevels.indexOf(currentLevel) + 1 }}</span>
                        </div>
                        <span class="text-xs font-bold" :style="{ color: progressColor }">{{ profileProgress }}%</span>
                    </div>

                    <div class="w-full h-2.5 rounded-full bg-[var(--surface-ground)] overflow-hidden">
                        <div class="h-full rounded-full transition-all duration-700 ease-out relative overflow-hidden" :style="{ width: profileProgress + '%', backgroundColor: currentLevel.color }">
                            <div class="absolute inset-0 prof-shimmer" />
                        </div>
                    </div>

                    <p class="text-xs text-[var(--text-color-secondary)] mt-1.5 m-0">
                        <span v-if="nextLevel">
                            <span class="font-medium" :style="{ color: nextLevel.color }">{{ xpToNext }}% até {{ nextLevel.label }} {{ nextLevel.icon }}</span>
                            — preencha mais dados para evoluir
                        </span>
                        <span v-else class="font-semibold" style="color: #10b981">🎉 Perfil 100% completo!</span>
                    </p>
                </div>
            </div>

            <!-- Badges -->
            <div>
                <p class="text-xs font-semibold text-[var(--text-color-secondary)] uppercase tracking-wider mb-2">Conquistas</p>
                <div class="flex gap-2 flex-wrap">
                    <div v-for="badge in badges" :key="badge.key" class="prof-badge" :class="badge.earned ? 'prof-badge--earned' : 'prof-badge--locked'" v-tooltip.top="badge.earned ? badge.label : 'Bloqueado — ' + badge.label">
                        <span class="text-base leading-none">{{ badge.icon }}</span>
                        <span class="text-xs font-medium leading-none">{{ badge.label }}</span>
                    </div>
                </div>
            </div>

            <!-- Dicas do que falta -->
            <div v-if="progressSuggestions.length" class="flex flex-wrap gap-2 pt-1 border-t border-[var(--surface-border)]">
                <span v-for="(tip, i) in progressSuggestions" :key="i" class="inline-flex items-center gap-1.5 text-xs px-2.5 py-1 rounded-full bg-[var(--surface-ground)] text-[var(--text-color-secondary)] border border-[var(--surface-border)]">
                    <i :class="tip.icon" class="text-[0.65rem]" />
                    {{ tip.text }}
                </span>
            </div>
        </div>
    </div>

    <!-- ── GRID ─────────────────────────────────────────────── -->
    <div class="px-3 md:px-4 pb-8 grid grid-cols-12 gap-4 md:gap-5">
        <!-- Sidebar -->
        <div class="col-span-12 lg:col-span-3">
            <div class="sticky rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 flex flex-col gap-3" :style="{ top: 'var(--layout-sticky-top, 140px)' }">
                <!-- Mini user -->
                <div class="flex items-center gap-3 pb-1">
                    <div class="relative shrink-0">
                        <img v-if="ui.avatarPreview" :src="ui.avatarPreview" class="w-10 h-10 rounded-xl border border-[var(--surface-border)] block object-cover" alt="avatar" />
                        <div v-else class="w-10 h-10 rounded-xl border border-[var(--surface-border)] grid place-items-center bg-[var(--surface-ground)] text-[1rem] font-bold text-[var(--text-color)]">{{ initials }}</div>
                        <span class="absolute bottom-[-2px] right-[-2px] w-2.5 h-2.5 rounded-full bg-emerald-400 border-2 border-[var(--surface-card)]" />
                    </div>
                    <div class="min-w-0">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)] truncate">{{ form.full_name || 'Conta' }}</div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)] truncate">{{ userEmail }}</div>
                    </div>
                </div>

                <!-- Nav -->
                <nav class="flex flex-col gap-0.5">
                    <button
                        v-for="s in sections"
                        :key="s.id"
                        class="nav-link flex items-center gap-2.5 px-3 py-2 rounded-xl text-[1rem] font-medium cursor-pointer text-left w-full border border-transparent bg-transparent transition-all"
                        :class="{ 'nav-link--active': activeSection === s.id }"
                        @click="scrollTo(s.id)"
                    >
                        <i :class="[s.icon, 'text-[1rem] opacity-65 shrink-0']" />
                        <span>{{ s.label }}</span>
                    </button>
                </nav>

                <div class="h-px bg-[var(--surface-border)]" />

                <!-- Quick actions -->
                <div class="flex flex-col gap-0.5">
                    <button class="action-btn flex items-center gap-2.5 px-3 py-2 rounded-xl text-[1rem] font-medium border-0 bg-transparent cursor-pointer text-left w-full transition-all" @click="openPasswordDialog">
                        <i class="pi pi-key" /> <span>Trocar senha</span>
                    </button>
                    <button class="action-btn action-btn--danger flex items-center gap-2.5 px-3 py-2 rounded-xl text-[1rem] font-medium border-0 bg-transparent cursor-pointer text-left w-full transition-all" @click="confirmSignOut">
                        <i class="pi pi-sign-out" /> <span>Sair da conta</span>
                    </button>
                </div>
            </div>
        </div>

        <!-- Content -->
        <div class="col-span-12 lg:col-span-9 flex flex-col gap-4 md:gap-5">
            <!-- ── 01 CONTA ───────────────────────────────────── -->
            <div
                id="conta"
                class="pcard relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-6 scroll-mt-20 transition-[border-color] duration-[220ms]"
                style="--c: #60a5fa; --c-dim: rgba(96, 165, 250, 0.08); --c-border: rgba(96, 165, 250, 0.2)"
            >
                <div class="pcard__num absolute top-3.5 right-5 text-[4.5rem] font-black tracking-[-0.06em] leading-none text-[var(--text-color)] opacity-[0.022] pointer-events-none select-none transition-opacity duration-[220ms]">01</div>
                <div class="pcard__shine" />

                <div class="flex items-center gap-2.5 mb-3.5">
                    <div class="w-9 h-9 rounded-[0.625rem] shrink-0 flex items-center justify-center" style="background: var(--c-dim); border: 1px solid var(--c-border); color: var(--c)"><i class="pi pi-user" /></div>
                    <span class="text-[1rem] font-extrabold uppercase tracking-[0.14em] opacity-75" style="color: var(--c)">Conta</span>
                </div>

                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] mb-1">Informações pessoais</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Seu nome, contato e descrição exibidos no app.</div>

                <div class="h-px bg-[var(--surface-border)] my-5" />

                <div class="grid grid-cols-12 gap-4">
                    <!-- Nome completo -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <InputText
                                id="prof_name"
                                v-model="form.full_name"
                                class="w-full"
                                autocomplete="name"
                                :invalid="!!fieldErrors.full_name"
                                @input="
                                    markDirty();
                                    clearErr('full_name');
                                "
                            />
                            <label for="prof_name">Nome completo <span class="text-red-400">*</span></label>
                        </FloatLabel>
                        <Message v-if="fieldErrors.full_name" severity="error" size="small" variant="simple" class="mt-1">{{ fieldErrors.full_name }}</Message>
                        <div v-else class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Aparece no menu, cabeçalhos e registros.</div>
                    </div>

                    <!-- Como a Agência PSI deveria te chamar? -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <InputText
                                id="prof_nickname"
                                v-model="form.nickname"
                                class="w-full"
                                autocomplete="nickname"
                                :invalid="!!fieldErrors.nickname"
                                @input="
                                    markDirty();
                                    clearErr('nickname');
                                "
                            />
                            <label for="prof_nickname">Como a Agência PSI deveria te chamar? <span class="text-red-400">*</span></label>
                        </FloatLabel>
                        <Message v-if="fieldErrors.nickname" severity="error" size="small" variant="simple" class="mt-1">{{ fieldErrors.nickname }}</Message>
                        <div v-else class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Apelido ou nome preferido para comunicação.</div>
                    </div>

                    <!-- O que melhor descreve seu trabalho? -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <Select id="prof_work_desc" v-model="form.work_description" :options="workDescriptionOptions" optionLabel="label" optionValue="value" class="w-full" @change="markDirty" />
                            <label for="prof_work_desc">O que melhor descreve seu trabalho?</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Exibido no seu perfil público.</div>
                    </div>

                    <!-- E-mail -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <InputText id="prof_email" :modelValue="userEmail" class="w-full" disabled />
                            <label for="prof_email">E-mail</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Gerenciado pelo Supabase Auth.</div>
                    </div>

                    <!-- Informe seu trabalho (somente quando 'outro') -->
                    <Transition name="prof-slide">
                        <div v-if="form.work_description === 'outro'" class="col-span-12">
                            <FloatLabel variant="on">
                                <InputText id="prof_work_other" v-model="form.work_description_other" class="w-full" autocomplete="off" @input="markDirty" />
                                <label for="prof_work_other">Informe qual é o seu trabalho</label>
                            </FloatLabel>
                            <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Descreva brevemente sua atuação profissional.</div>
                        </div>
                    </Transition>

                    <!-- Bio -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <Textarea id="prof_bio" v-model="form.bio" class="w-full" rows="5" maxlength="300" @input="markDirty" />
                            <label for="prof_bio">Bio</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)] flex justify-between">
                            <span>Breve descrição sobre você.</span>
                            <span>{{ (form.bio || '').length }}/300</span>
                        </div>
                    </div>

                    <!-- Whatsapp -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <InputMask
                                id="prof_phone"
                                v-model="form.phone"
                                class="w-full"
                                mask="(99) 99999-9999"
                                :autoClear="false"
                                :invalid="!!fieldErrors.phone"
                                @update:modelValue="
                                    markDirty();
                                    clearErr('phone');
                                "
                            />
                            <label for="prof_phone">WhatsApp <span class="text-red-400">*</span></label>
                        </FloatLabel>
                        <Message v-if="fieldErrors.phone" severity="error" size="small" variant="simple" class="mt-1">{{ fieldErrors.phone }}</Message>
                        <div v-else class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)] flex items-center gap-1.5">
                            <i class="pi pi-lock text-[0.7rem] opacity-60" />
                            <span>Usado apenas para notificações importantes.</span>
                        </div>
                    </div>
                </div>
            </div>

            <!-- ── 02 SITES E REDES SOCIAIS ─────────────────────── -->
            <div
                id="redes-sociais"
                class="pcard relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-6 scroll-mt-20 transition-[border-color] duration-[220ms]"
                style="--c: #e879f9; --c-dim: rgba(232, 121, 249, 0.08); --c-border: rgba(232, 121, 249, 0.2)"
            >
                <div class="pcard__num absolute top-3.5 right-5 text-[4.5rem] font-black tracking-[-0.06em] leading-none text-[var(--text-color)] opacity-[0.022] pointer-events-none select-none transition-opacity duration-[220ms]">02</div>
                <div class="pcard__shine" />

                <div class="flex items-center gap-2.5 mb-3.5">
                    <div class="w-9 h-9 rounded-[0.625rem] shrink-0 flex items-center justify-center" style="background: var(--c-dim); border: 1px solid var(--c-border); color: var(--c)"><i class="pi pi-share-alt" /></div>
                    <span class="text-[1rem] font-extrabold uppercase tracking-[0.14em] opacity-75" style="color: var(--c)">Sites e Redes Sociais</span>
                </div>

                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] mb-1">Seus Sites e Redes Sociais</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Links exibidos no seu perfil público.</div>

                <div class="h-px bg-[var(--surface-border)] my-5" />

                <div class="grid grid-cols-12 gap-4">
                    <!-- Site -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <IconField>
                                <InputIcon class="pi pi-globe" />
                                <InputText id="prof_site" v-model="form.site_url" class="w-full" type="url" @input="markDirty" />
                            </IconField>
                            <label for="prof_site">Endereço do site</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Ex: https://seuperfil.com.br</div>
                    </div>

                    <!-- Instagram -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <IconField>
                                <InputIcon class="pi pi-instagram" />
                                <InputText id="prof_instagram" v-model="form.social_instagram" class="w-full" @input="markDirty" />
                            </IconField>
                            <label for="prof_instagram">Instagram</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Ex: @seuperfil</div>
                    </div>

                    <!-- Youtube -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <IconField>
                                <InputIcon class="pi pi-youtube" />
                                <InputText id="prof_youtube" v-model="form.social_youtube" class="w-full" @input="markDirty" />
                            </IconField>
                            <label for="prof_youtube">YouTube</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Ex: @seucanal</div>
                    </div>

                    <!-- Facebook -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <IconField>
                                <InputIcon class="pi pi-facebook" />
                                <InputText id="prof_facebook" v-model="form.social_facebook" class="w-full" @input="markDirty" />
                            </IconField>
                            <label for="prof_facebook">Facebook</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Ex: /suapagina</div>
                    </div>

                    <!-- X -->
                    <div class="col-span-12 md:col-span-6">
                        <FloatLabel variant="on">
                            <IconField>
                                <InputIcon class="pi pi-twitter" />
                                <InputText id="prof_x" v-model="form.social_x" class="w-full" @input="markDirty" />
                            </IconField>
                            <label for="prof_x">X (Twitter)</label>
                        </FloatLabel>
                        <div class="mt-1.5 text-[1rem] text-[var(--text-color-secondary)]">Ex: @seuuser</div>
                    </div>
                </div>

                <!-- Outras redes -->
                <div class="mt-5">
                    <div class="flex items-center justify-between mb-3">
                        <div>
                            <div class="text-[1rem] font-semibold text-[var(--text-color)]">Outras redes ou links</div>
                            <div class="text-[1rem] text-[var(--text-color-secondary)]">Adicione qualquer outra rede social, podcast, link ou perfil.</div>
                        </div>
                        <Button icon="pi pi-plus" label="Adicionar" severity="secondary" size="small" outlined class="rounded-full" @click="addCustomSocial" />
                    </div>

                    <div v-if="customSocials.length" class="flex flex-col gap-3">
                        <div v-for="(item, idx) in customSocials" :key="idx" class="flex items-center gap-2">
                            <FloatLabel variant="on" class="flex-1">
                                <InputText :id="`prof_cs_name_${idx}`" v-model="item.name" class="w-full" @input="markDirty" />
                                <label :for="`prof_cs_name_${idx}`">Nome da rede</label>
                            </FloatLabel>

                            <FloatLabel variant="on" class="flex-[2]">
                                <IconField>
                                    <InputIcon class="pi pi-link" />
                                    <InputText :id="`prof_cs_url_${idx}`" v-model="item.url" class="w-full" @input="markDirty" />
                                </IconField>
                                <label :for="`prof_cs_url_${idx}`">URL / usuário</label>
                            </FloatLabel>

                            <Button icon="pi pi-trash" severity="danger" text rounded size="small" v-tooltip.top="'Remover'" @click="removeCustomSocial(idx)" />
                        </div>
                    </div>

                    <div v-else class="text-[1rem] text-[var(--text-color-secondary)] italic mt-1">Nenhuma rede adicional cadastrada ainda.</div>
                </div>
            </div>

            <!-- ── 03 AVATAR ──────────────────────────────────── -->
            <div
                id="avatar"
                class="pcard relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-6 scroll-mt-20 transition-[border-color] duration-[220ms]"
                style="--c: #4ade80; --c-dim: rgba(74, 222, 128, 0.08); --c-border: rgba(74, 222, 128, 0.2)"
            >
                <div class="pcard__num absolute top-3.5 right-5 text-[4.5rem] font-black tracking-[-0.06em] leading-none text-[var(--text-color)] opacity-[0.022] pointer-events-none select-none transition-opacity duration-[220ms]">03</div>
                <div class="pcard__shine" />

                <div class="flex items-center gap-2.5 mb-3.5">
                    <div class="w-9 h-9 rounded-[0.625rem] shrink-0 flex items-center justify-center" style="background: var(--c-dim); border: 1px solid var(--c-border); color: var(--c)"><i class="pi pi-image" /></div>
                    <span class="text-[1rem] font-extrabold uppercase tracking-[0.14em] opacity-75" style="color: var(--c)">Avatar</span>
                </div>

                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] mb-1">Foto de perfil</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Envie um arquivo ou cole uma URL pública.</div>

                <div class="h-px bg-[var(--surface-border)] my-5" />

                <div class="grid grid-cols-12 gap-4 items-start">
                    <!-- Preview -->
                    <div class="col-span-12 md:col-span-3 flex flex-col items-center gap-3">
                        <div class="w-22 h-22 rounded-[1.375rem] border-2 border-[var(--surface-border)] bg-[var(--surface-ground)] grid place-items-center overflow-hidden" style="width: 5.5rem; height: 5.5rem">
                            <img v-if="ui.avatarPreview" :src="ui.avatarPreview" class="w-full h-full object-cover" alt="preview" />
                            <div v-else class="text-[1.75rem] font-extrabold text-[var(--text-color)]">{{ initials }}</div>
                        </div>
                        <div class="text-center">
                            <div class="text-[1rem] font-medium truncate max-w-[120px]">{{ form.full_name || '—' }}</div>
                            <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Preview</div>
                        </div>
                        <Button label="Remover" icon="pi pi-trash" severity="danger" outlined size="small" :disabled="!form.avatar_url && !ui.avatarFile && !ui.avatarPreview" @click="removeAvatar" />
                    </div>

                    <!-- Upload + URL -->
                    <div class="col-span-12 md:col-span-9 flex flex-col gap-4">
                        <!-- Upload arquivo -->
                        <div class="rounded-md border border-dashed border-[var(--surface-border)] bg-[var(--surface-ground)] p-4 flex flex-col gap-2.5">
                            <div class="flex items-center gap-2 text-[1rem] font-semibold text-[var(--text-color-secondary)]">
                                <i class="pi pi-upload" />
                                <span>Arquivo (PNG · JPG · WebP · máx 5 MB)</span>
                            </div>
                            <div class="flex items-center gap-2 flex-wrap">
                                <input ref="fileInput" type="file" accept="image/*" class="text-[1rem] flex-1 text-[var(--text-color-secondary)]" @change="onAvatarFileSelected" />
                                <Button icon="pi pi-times" severity="secondary" outlined size="small" :disabled="!ui.avatarFile" @click="clearAvatarFile" v-tooltip.top="'Limpar'" />
                            </div>
                            <div class="text-[1rem] text-[var(--text-color-secondary)]">
                                Ao salvar, o arquivo é enviado ao bucket <b>{{ AVATAR_BUCKET }}</b> e a URL é atualizada automaticamente.
                            </div>
                        </div>

                        <!-- URL direta -->
                        <FloatLabel variant="on">
                            <InputText id="prof_avatar_url" v-model="form.avatar_url" class="w-full" @input="onAvatarUrlChange" />
                            <label for="prof_avatar_url">Avatar URL</label>
                        </FloatLabel>
                        <div class="-mt-2 text-[1rem] text-[var(--text-color-secondary)]">Cole uma URL pública de imagem. Se vazio, usamos suas iniciais.</div>
                    </div>
                </div>
            </div>

            <!-- ── 04 APARÊNCIA ───────────────────────────────── -->
            <div
                id="layout"
                class="pcard relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-6 scroll-mt-20 transition-[border-color] duration-[220ms]"
                style="--c: #a78bfa; --c-dim: rgba(167, 139, 250, 0.08); --c-border: rgba(167, 139, 250, 0.2)"
            >
                <div class="pcard__num absolute top-3.5 right-5 text-[4.5rem] font-black tracking-[-0.06em] leading-none text-[var(--text-color)] opacity-[0.022] pointer-events-none select-none transition-opacity duration-[220ms]">04</div>
                <div class="pcard__shine" />

                <div class="flex items-center gap-2.5 mb-3.5">
                    <div class="w-9 h-9 rounded-[0.625rem] shrink-0 flex items-center justify-center" style="background: var(--c-dim); border: 1px solid var(--c-border); color: var(--c)"><i class="pi pi-palette" /></div>
                    <span class="text-[1rem] font-extrabold uppercase tracking-[0.14em] opacity-75" style="color: var(--c)">Aparência</span>
                </div>

                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] mb-1">Tema e visual</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Personalize cores, preset de componentes e modo do menu.</div>

                <div class="h-px bg-[var(--surface-border)] my-5" />

                <div class="grid grid-cols-12 gap-4">
                    <!-- Primary -->
                    <div class="col-span-12 md:col-span-6">
                        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] p-4 h-full">
                            <div class="flex items-start justify-between mb-3.5">
                                <div>
                                    <div class="text-[1rem] font-semibold text-[var(--text-color)]">Cor principal</div>
                                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Tom dominante da interface.</div>
                                </div>
                                <i class="pi pi-palette opacity-40" />
                            </div>
                            <div class="flex gap-1.5 flex-wrap">
                                <button
                                    v-for="pc of primaryColors"
                                    :key="pc.name"
                                    type="button"
                                    :title="pc.name"
                                    class="swatch w-[1.375rem] h-[1.375rem] rounded-full border-2 border-transparent cursor-pointer outline-none outline-offset-2 transition-transform duration-150"
                                    :class="{ 'swatch--active': layoutConfig.primary === pc.name }"
                                    :style="{ backgroundColor: pc.name === 'noir' ? 'var(--text-color)' : pc.palette['500'] }"
                                    @click="updateColors('primary', pc)"
                                />
                            </div>
                        </div>
                    </div>

                    <!-- Surface -->
                    <div class="col-span-12 md:col-span-6">
                        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] p-4 h-full">
                            <div class="flex items-start justify-between mb-3.5">
                                <div>
                                    <div class="text-[1rem] font-semibold text-[var(--text-color)]">Surface</div>
                                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Base de fundo e superfícies.</div>
                                </div>
                                <i class="pi pi-circle-fill opacity-40" />
                            </div>
                            <div class="flex gap-1.5 flex-wrap">
                                <button
                                    v-for="sf of surfaces"
                                    :key="sf.name"
                                    type="button"
                                    :title="sf.name"
                                    class="swatch w-[1.375rem] h-[1.375rem] rounded-full border-2 border-transparent cursor-pointer outline-none outline-offset-2 transition-transform duration-150"
                                    :class="{
                                        'swatch--active': layoutConfig.surface ? layoutConfig.surface === sf.name : isDarkNow() ? sf.name === 'zinc' : sf.name === 'slate'
                                    }"
                                    :style="{ backgroundColor: sf.palette['500'] }"
                                    @click="updateColors('surface', sf)"
                                />
                            </div>
                        </div>
                    </div>

                    <!-- Preset -->
                    <div class="col-span-12 md:col-span-4">
                        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] p-4 h-full">
                            <div class="flex items-start justify-between mb-3.5">
                                <div>
                                    <div class="text-[1rem] font-semibold text-[var(--text-color)]">Preset</div>
                                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Aura · Lara · Nora</div>
                                </div>
                                <i class="pi pi-sparkles opacity-40" />
                            </div>
                            <SelectButton v-model="presetModel" :options="presetOptions" :allowEmpty="false" />
                        </div>
                    </div>

                    <!-- Menu Mode: só relevante no Layout Clássico -->
                    <div v-if="layoutConfig.variant === 'classic'" class="col-span-12 md:col-span-4">
                        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] p-4 h-full">
                            <div class="flex items-start justify-between mb-3.5">
                                <div>
                                    <div class="text-[1rem] font-semibold text-[var(--text-color)]">Menu</div>
                                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Static ou Overlay</div>
                                </div>
                                <i class="pi pi-bars opacity-40" />
                            </div>
                            <SelectButton v-model="menuModeModel" :options="menuModeOptions" :allowEmpty="false" optionLabel="label" optionValue="value" />
                        </div>
                    </div>

                    <!-- Theme Mode -->
                    <div class="col-span-12 md:col-span-4">
                        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] p-4 h-full">
                            <div class="flex items-start justify-between mb-3.5">
                                <div>
                                    <div class="text-[1rem] font-semibold text-[var(--text-color)]">Tema</div>
                                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Claro ou escuro</div>
                                </div>
                                <i class="pi pi-moon opacity-40" />
                            </div>
                            <SelectButton v-model="themeModeModel" :options="themeModeOptions" :allowEmpty="false" optionLabel="label" optionValue="value" />
                        </div>
                    </div>
                </div>
            </div>

            <!-- ── 05 PREFERÊNCIAS ────────────────────────────── -->
            <div
                id="preferencias"
                class="pcard relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-6 scroll-mt-20 transition-[border-color] duration-[220ms]"
                style="--c: #fb923c; --c-dim: rgba(251, 146, 60, 0.08); --c-border: rgba(251, 146, 60, 0.2)"
            >
                <div class="pcard__num absolute top-3.5 right-5 text-[4.5rem] font-black tracking-[-0.06em] leading-none text-[var(--text-color)] opacity-[0.022] pointer-events-none select-none transition-opacity duration-[220ms]">05</div>
                <div class="pcard__shine" />

                <div class="flex items-center gap-2.5 mb-3.5">
                    <div class="w-9 h-9 rounded-[0.625rem] shrink-0 flex items-center justify-center" style="background: var(--c-dim); border: 1px solid var(--c-border); color: var(--c)"><i class="pi pi-sliders-h" /></div>
                    <span class="text-[1rem] font-extrabold uppercase tracking-[0.14em] opacity-75" style="color: var(--c)">Preferências</span>
                </div>

                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] mb-1">Notificações</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Escolha quais comunicações deseja receber.</div>

                <div class="h-px bg-[var(--surface-border)] my-5" />

                <div class="flex flex-col gap-3">
                    <label class="toggle-row flex items-start gap-3.5 px-4 py-3.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] cursor-pointer transition-[border-color,background] duration-150">
                        <Checkbox v-model="form.notify_system_email" binary @change="markDirty" />
                        <div>
                            <div class="text-[1rem] font-semibold text-[var(--text-color)]">E-mails do sistema</div>
                            <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Confirmações, alertas importantes e faturas.</div>
                        </div>
                    </label>

                    <label class="toggle-row flex items-start gap-3.5 px-4 py-3.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] cursor-pointer transition-[border-color,background] duration-150">
                        <Checkbox v-model="form.notify_reminders" binary @change="markDirty" />
                        <div>
                            <div class="text-[1rem] font-semibold text-[var(--text-color)]">Lembretes de sessão</div>
                            <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Notificações antes das consultas agendadas.</div>
                        </div>
                    </label>

                    <label class="toggle-row flex items-start gap-3.5 px-4 py-3.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] cursor-pointer transition-[border-color,background] duration-150">
                        <Checkbox v-model="form.notify_news" binary @change="markDirty" />
                        <div>
                            <div class="text-[1rem] font-semibold text-[var(--text-color)]">Novidades da plataforma</div>
                            <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Updates, novas funcionalidades e comunicados.</div>
                        </div>
                    </label>
                </div>
            </div>

            <!-- ── 06 LAYOUT ─────────────────────────────────── -->
            <div
                id="layout-variant"
                class="pcard relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-6 scroll-mt-20 transition-[border-color] duration-[220ms]"
                style="--c: #22d3ee; --c-dim: rgba(34, 211, 238, 0.08); --c-border: rgba(34, 211, 238, 0.2)"
            >
                <div class="pcard__num absolute top-3.5 right-5 text-[4.5rem] font-black tracking-[-0.06em] leading-none text-[var(--text-color)] opacity-[0.022] pointer-events-none select-none transition-opacity duration-[220ms]">06</div>
                <div class="pcard__shine" />

                <div class="flex items-center gap-2.5 mb-3.5">
                    <div class="w-9 h-9 rounded-[0.625rem] shrink-0 flex items-center justify-center" style="background: var(--c-dim); border: 1px solid var(--c-border); color: var(--c)"><i class="pi pi-th-large" /></div>
                    <span class="text-[1rem] font-extrabold uppercase tracking-[0.14em] opacity-75" style="color: var(--c)">Layout</span>
                </div>

                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] mb-1">Estilo de navegação</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Escolha como a interface principal é organizada.</div>

                <div class="h-px bg-[var(--surface-border)] my-5" />

                <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
                    <!-- Layout 1: Clássico -->
                    <button
                        class="lv-card"
                        :class="{ 'lv-card--active': layoutConfig.variant === 'classic' }"
                        @click="
                            setVariant('classic');
                            markDirty();
                        "
                    >
                        <div class="lv-card__preview lv-card__preview--classic">
                            <div class="lv-p__sidebar" />
                            <div class="lv-p__main">
                                <div class="lv-p__bar" />
                                <div class="lv-p__line" />
                                <div class="lv-p__line lv-p__line--sm" />
                            </div>
                        </div>
                        <div class="lv-card__foot">
                            <div class="lv-card__radio">
                                <div v-if="layoutConfig.variant === 'classic'" class="lv-card__dot" />
                            </div>
                            <div>
                                <div class="lv-card__name">Clássico</div>
                                <div class="lv-card__sub">Sidebar lateral com menu completo</div>
                            </div>
                        </div>
                    </button>

                    <!-- Layout 2: Rail -->
                    <button
                        class="lv-card"
                        :class="{ 'lv-card--active': layoutConfig.variant === 'rail' }"
                        @click="
                            setVariant('rail');
                            markDirty();
                        "
                    >
                        <div class="lv-card__preview lv-card__preview--rail">
                            <div class="lv-p__rail" />
                            <div class="lv-p__panel" />
                            <div class="lv-p__main">
                                <div class="lv-p__bar" />
                                <div class="lv-p__line" />
                                <div class="lv-p__line lv-p__line--sm" />
                            </div>
                        </div>
                        <div class="lv-card__foot">
                            <div class="lv-card__radio">
                                <div v-if="layoutConfig.variant === 'rail'" class="lv-card__dot" />
                            </div>
                            <div>
                                <div class="lv-card__name">Rail</div>
                                <div class="lv-card__sub">Mini rail + painel expansível, full-width</div>
                            </div>
                        </div>
                    </button>
                </div>

                <div class="mt-4 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] px-4 py-3 flex items-start gap-3">
                    <i class="pi pi-info-circle text-[var(--text-color-secondary)] mt-0.5 shrink-0" />
                    <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">
                        O layout Rail exibe ícones no canto esquerdo. Ao clicar em um ícone, o painel lateral expande com os itens de navegação. Disponível apenas no desktop.
                    </div>
                </div>
            </div>

            <!-- ── 07 SEGURANÇA ───────────────────────────────── -->
            <div
                id="seguranca"
                class="pcard relative overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-6 scroll-mt-20 transition-[border-color] duration-[220ms]"
                style="--c: #f87171; --c-dim: rgba(248, 113, 113, 0.08); --c-border: rgba(248, 113, 113, 0.2)"
            >
                <div class="pcard__num absolute top-3.5 right-5 text-[4.5rem] font-black tracking-[-0.06em] leading-none text-[var(--text-color)] opacity-[0.022] pointer-events-none select-none transition-opacity duration-[220ms]">07</div>
                <div class="pcard__shine" />

                <div class="flex items-center gap-2.5 mb-3.5">
                    <div class="w-9 h-9 rounded-[0.625rem] shrink-0 flex items-center justify-center" style="background: var(--c-dim); border: 1px solid var(--c-border); color: var(--c)"><i class="pi pi-shield" /></div>
                    <span class="text-[1rem] font-extrabold uppercase tracking-[0.14em] opacity-75" style="color: var(--c)">Segurança</span>
                </div>

                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)] mb-1">Acesso e senha</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">Mantenha sua conta protegida com uma senha forte.</div>

                <div class="h-px bg-[var(--surface-border)] my-5" />

                <div class="flex flex-col sm:flex-row gap-3">
                    <Button label="Trocar senha de acesso" icon="pi pi-shield" severity="secondary" outlined @click="router.push('/account/security')" />
                </div>
            </div>
        </div>
    </div>

    <div class="px-3 md:px-4 pb-3">
        <LoadedPhraseBlock v-if="mounted" />
    </div>

    <!-- Dialog: Trocar senha -->
    <Dialog v-model:visible="openPassword" modal header="Redefinir senha" :draggable="false" :style="{ width: '28rem', maxWidth: '92vw' }">
        <div class="space-y-4">
            <div class="text-[1rem] text-[var(--text-color-secondary)]">Enviaremos um link de redefinição de senha para o seu e-mail.</div>

            <FloatLabel variant="on">
                <InputText id="dlg_email" :modelValue="userEmail" class="w-full" disabled />
                <label for="dlg_email">E-mail</label>
            </FloatLabel>

            <div v-if="passwordSent" class="rounded-md border border-emerald-500/20 bg-emerald-500/5 px-4 py-3 flex items-center gap-2 text-[1rem] text-emerald-600 dark:text-emerald-400">
                <i class="pi pi-check" />
                Link enviado! Verifique sua caixa de entrada (e pasta de spam).
            </div>
        </div>

        <template #footer>
            <Button label="Fechar" icon="pi pi-times" text @click="openPassword = false" />
            <Button label="Enviar link" icon="pi pi-envelope" :loading="sendingPassword" @click="sendPasswordReset" />
        </template>
    </Dialog>

    <ConfirmDialog />
</template>

<style scoped>
/* ─── Shimmer na barra de progresso ─────────────────────── */
@keyframes prof-shimmer-anim {
    0% {
        transform: translateX(-100%);
    }
    100% {
        transform: translateX(250%);
    }
}
.prof-shimmer {
    background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.28) 50%, transparent 100%);
    width: 55%;
    animation: prof-shimmer-anim 2.2s ease-in-out infinite;
}

/* ─── Badges de conquista ────────────────────────────────── */
.prof-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.3rem 0.65rem;
    border-radius: 9999px;
    border: 1px solid;
    transition: all 0.18s ease;
    cursor: default;
}
.prof-badge--earned {
    background-color: rgba(16, 185, 129, 0.08);
    border-color: rgba(16, 185, 129, 0.3);
    color: #10b981;
}
.prof-badge--locked {
    background-color: var(--surface-ground);
    border-color: var(--surface-border);
    color: var(--text-color-secondary);
    filter: grayscale(1);
    opacity: 0.45;
}

/* ─── Sidebar nav ───────────────────────────────────────── */
.nav-link {
    color: var(--text-color-secondary);
}
.nav-link:hover,
.nav-link--active {
    color: var(--text-color);
    background: var(--surface-ground);
    border-color: var(--surface-border);
}

/* ─── Sidebar actions ───────────────────────────────────── */
.action-btn {
    color: var(--text-color-secondary);
}
.action-btn:hover {
    color: var(--text-color);
    background: var(--surface-ground);
}
.action-btn--danger:hover {
    color: #f87171;
    background: rgba(248, 113, 113, 0.06);
}

/* ─── Content cards ─────────────────────────────────────── */
.pcard {
    animation: prof-fadeUp 0.4s ease both;
}
.pcard:hover {
    border-color: var(--c-border);
}
.pcard:hover .pcard__shine {
    opacity: 1;
}
.pcard:hover .pcard__num {
    opacity: 0.055;
}

.pcard__shine {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
    background: radial-gradient(ellipse at 20% 0%, color-mix(in srgb, var(--c) 9%, transparent), transparent 52%);
}

/* ─── Swatches ──────────────────────────────────────────── */
.swatch:hover {
    transform: scale(1.2);
}
.swatch--active {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
    transform: scale(1.1);
}

/* ─── Toggle rows ───────────────────────────────────────── */
.toggle-row:hover {
    border-color: color-mix(in srgb, var(--primary-color) 40%, transparent);
    background: color-mix(in srgb, var(--primary-color) 3%, var(--surface-ground));
}

/* ─── Layout variant cards ──────────────────────────────── */
.lv-card {
    position: relative;
    display: flex;
    flex-direction: column;
    border-radius: 0.75rem;
    border: 2px solid var(--surface-border);
    background: var(--surface-ground);
    cursor: pointer;
    text-align: left;
    transition:
        border-color 0.18s,
        box-shadow 0.18s;
    overflow: hidden;
}
.lv-card:hover {
    border-color: color-mix(in srgb, var(--primary-color) 50%, transparent);
}
.lv-card--active {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 12%, transparent);
}
.lv-card--active .lv-card__radio {
    border-color: var(--primary-color);
}
.lv-card__preview {
    height: 90px;
    display: flex;
    background: var(--surface-card);
    border-bottom: 1px solid var(--surface-border);
    overflow: hidden;
    padding: 10px;
}
.lv-card__preview--classic {
    gap: 6px;
}
.lv-card__preview--rail {
    gap: 4px;
}
.lv-p__sidebar {
    width: 38px;
    border-radius: 5px;
    background: var(--surface-border);
    flex-shrink: 0;
}
.lv-p__rail {
    width: 14px;
    border-radius: 4px;
    background: var(--surface-border);
    flex-shrink: 0;
}
.lv-p__panel {
    width: 28px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--surface-border) 60%, transparent);
    flex-shrink: 0;
}
.lv-p__main {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding-top: 2px;
}
.lv-p__bar {
    height: 10px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--primary-color) 25%, transparent);
}
.lv-p__line {
    height: 7px;
    border-radius: 3px;
    background: var(--surface-border);
}
.lv-p__line--sm {
    width: 65%;
}
.lv-card__foot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
}
.lv-card__radio {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid var(--surface-border);
    display: grid;
    place-items: center;
    flex-shrink: 0;
    transition: border-color 0.15s;
}
.lv-card__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--primary-color);
}
.lv-card__name {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-color);
}
.lv-card__sub {
    font-size: 1rem;
    color: var(--text-color-secondary);
    margin-top: 1px;
}

/* ─── Animation ─────────────────────────────────────────── */
@keyframes prof-fadeUp {
    from {
        opacity: 0;
        transform: translateY(14px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ─── Transition "outro" ────────────────────────────────── */
.prof-slide-enter-active,
.prof-slide-leave-active {
    transition:
        opacity 0.2s ease,
        max-height 0.25s ease,
        margin 0.2s ease;
    max-height: 6rem;
    overflow: hidden;
}
.prof-slide-enter-from,
.prof-slide-leave-to {
    opacity: 0;
    max-height: 0;
    margin: 0;
}
</style>
