Layout 100%, Notificações, SetupWizard

This commit is contained in:
Leonardo
2026-03-17 21:08:14 -03:00
parent 84d65e49c0
commit 66f67cd40f
77 changed files with 35823 additions and 15023 deletions

View File

@@ -17,7 +17,7 @@ const hasLinkPersonalizado = computed(() => entitlements.can('agendador.link_per
// ── Estado ─────────────────────────────────────────────────────
const loading = ref(true)
const ownerId = ref(null)
const expandedCard = ref(null)
const expandedCard = ref(new Set())
const savingCard = ref(null)
// ── Upload de imagens ────────────────────────────────────────────
@@ -62,8 +62,8 @@ async function onFileSelected (event, field) {
// ── Expand / Collapse all ────────────────────────────────────────
const CARDS = ['identidade', 'perfil', 'fluxo', 'pagamento', 'triagem', 'textos']
function expandAll () { expandedCard.value = CARDS[0] } // abre o primeiro como ponto de entrada
function collapseAll () { expandedCard.value = null }
function expandAll () { expandedCard.value = new Set(CARDS) }
function collapseAll () { expandedCard.value = new Set() }
// ── Defaults ───────────────────────────────────────────────────
const DEFAULT_CFG = {
@@ -405,7 +405,7 @@ async function saveCard (cardKey) {
)
toast.add({ severity: 'success', summary: 'Salvo', life: 2500 })
expandedCard.value = null
expandedCard.value = new Set()
} catch (e) {
toast.add({ severity: 'error', summary: 'Erro ao salvar', detail: e.message, life: 4000 })
} finally {
@@ -474,7 +474,10 @@ function buildPayload (cardKey) {
}
function toggleCard (key) {
expandedCard.value = expandedCard.value === key ? null : key
const s = new Set(expandedCard.value)
if (s.has(key)) s.delete(key)
else s.add(key)
expandedCard.value = s
}
onMounted(load)
@@ -490,43 +493,27 @@ onMounted(load)
<template v-else>
<!-- HEADER SECUNDÁRIO -->
<div class="flex items-center justify-between gap-3 px-1">
<div>
<div class="text-base font-semibold">Configurações do Agendador</div>
<div class="text-xs text-surface-400 mt-0.5">Personalize a aparência, fluxo e comportamento do seu agendador público.</div>
<!-- Subheader -->
<div class="cfg-subheader">
<div class="cfg-subheader__icon"><i class="pi pi-calendar-clock" /></div>
<div class="min-w-0">
<div class="cfg-subheader__title">Agendador Online</div>
<div class="cfg-subheader__sub">Personalize a aparência, fluxo e comportamento do seu agendador público</div>
</div>
<div class="flex items-center gap-2 shrink-0">
<Button
size="small"
icon="pi pi-arrows-v"
label="Expandir tudo"
severity="secondary"
outlined
class="rounded-full"
@click="expandAll"
/>
<Button
size="small"
icon="pi pi-minus"
label="Contrair"
severity="secondary"
outlined
class="rounded-full"
@click="collapseAll"
/>
<div class="cfg-subheader__actions">
<Button size="small" icon="pi pi-arrows-v" label="Expandir" severity="secondary" outlined class="rounded-full" @click="expandAll" />
<Button size="small" icon="pi pi-minus" label="Contrair" severity="secondary" outlined class="rounded-full" @click="collapseAll" />
</div>
</div>
<!-- CARD: STATUS / ATIVAR -->
<Card>
<template #content>
<div class="agd-card">
<div class="flex flex-col gap-4">
<!-- Cabeçalho PRO -->
<div class="flex items-start justify-between gap-4">
<div class="flex items-center gap-3">
<div class="grid place-items-center w-11 h-11 rounded-2xl shrink-0"
<div class="grid place-items-center w-11 h-11 rounded-[6px] shrink-0"
:class="cfg.ativo ? 'bg-green-100 dark:bg-green-900/30 text-green-600' : 'bg-surface-100 text-surface-400'">
<i class="pi pi-calendar-clock text-xl" />
</div>
@@ -586,9 +573,9 @@ onMounted(load)
</div>
<!-- Link personalizado bloqueado -->
<div v-if="!hasLinkPersonalizado" class="mt-3 flex items-center gap-3 p-3 rounded-xl border border-dashed
<div v-if="!hasLinkPersonalizado" class="mt-3 flex items-center gap-3 p-3 rounded-[6px] border border-dashed
border-surface-300 dark:border-surface-600 bg-surface-50 dark:bg-surface-800/50">
<div class="grid place-items-center w-9 h-9 rounded-xl bg-amber-100 dark:bg-amber-900/30 text-amber-500 shrink-0">
<div class="grid place-items-center w-9 h-9 rounded-[6px] bg-amber-100 dark:bg-amber-900/30 text-amber-500 shrink-0">
<i class="pi pi-lock text-base" />
</div>
<div class="flex-1 min-w-0">
@@ -617,34 +604,27 @@ onMounted(load)
Você controla quem pode agendar e quais horários ficam disponíveis.
</div>
</div>
</template>
</Card>
</div>
<!-- CARD: IDENTIDADE VISUAL -->
<Card class="overflow-hidden">
<template #content>
<!-- Cabeçalho do card -->
<button
type="button"
class="w-full flex items-center justify-between gap-3 text-left"
@click="toggleCard('identidade')"
>
<div class="flex items-center gap-3">
<div class="grid place-items-center w-9 h-9 rounded-xl bg-purple-100 dark:bg-purple-900/30 text-purple-600 shrink-0">
<i class="pi pi-palette" />
</div>
<div>
<div class="font-semibold leading-none">Identidade Visual</div>
<div v-if="expandedCard !== 'identidade'" class="text-xs text-surface-400 mt-1">{{ resumoIdentidade }}</div>
</div>
</div>
<i class="pi transition-transform duration-200 text-surface-400 shrink-0"
:class="expandedCard === 'identidade' ? 'pi-angle-up' : 'pi-angle-down'" />
</button>
<div class="agd-accordion" :class="{ 'agd-accordion--open': expandedCard.has('identidade') }">
<button
type="button"
class="agd-accordion__header"
@click="toggleCard('identidade')"
>
<div class="agd-accordion__icon bg-purple-100 dark:bg-purple-900/30 text-purple-600">
<i class="pi pi-palette" />
</div>
<div class="min-w-0 flex-1 text-left">
<div class="agd-accordion__title">Identidade Visual</div>
<div v-if="!expandedCard.has('identidade')" class="agd-accordion__summary">{{ resumoIdentidade }}</div>
</div>
<i class="pi agd-accordion__chevron"
:class="expandedCard.has('identidade') ? 'pi-chevron-up' : 'pi-chevron-down'" />
</button>
<!-- Conteúdo expandido -->
<template v-if="expandedCard === 'identidade'">
<Divider />
<div v-if="expandedCard.has('identidade')" class="agd-accordion__body">
<div class="flex flex-col gap-5">
<!-- Nome de exibição (aqui pois é parte da identidade) -->
@@ -660,7 +640,7 @@ onMounted(load)
<div class="flex items-center gap-3">
<ColorPicker v-model="cfg.cor_primaria" format="hex" />
<InputText v-model="cfg.cor_primaria" placeholder="#4b6bff" class="w-32 font-mono" maxlength="7" />
<div class="w-10 h-10 rounded-xl border border-surface-200 shrink-0"
<div class="w-10 h-10 rounded-[6px] border border-surface-200 shrink-0"
:style="{ background: cfg.cor_primaria }" />
</div>
<div class="text-xs text-surface-400 mt-1">Botões e destaques do agendador.</div>
@@ -708,7 +688,7 @@ onMounted(load)
@change="e => onFileSelected(e, 'header')" />
</div>
<InputText v-model="cfg.imagem_header_url" placeholder="ou cole uma URL pública..." class="w-full text-xs" />
<div v-if="cfg.imagem_header_url" class="rounded-xl overflow-hidden h-20 w-full">
<div v-if="cfg.imagem_header_url" class="rounded-[6px] overflow-hidden h-20 w-full">
<img :src="cfg.imagem_header_url" alt="Header" class="w-full h-full object-cover" />
</div>
</div>
@@ -728,7 +708,7 @@ onMounted(load)
@change="e => onFileSelected(e, 'fundo')" />
</div>
<InputText v-model="cfg.imagem_fundo_url" placeholder="ou cole uma URL pública..." class="w-full text-xs" />
<div v-if="cfg.imagem_fundo_url" class="rounded-xl overflow-hidden h-28 w-full">
<div v-if="cfg.imagem_fundo_url" class="rounded-[6px] overflow-hidden h-28 w-full">
<img :src="cfg.imagem_fundo_url" alt="Fundo" class="w-full h-full object-cover" />
</div>
</div>
@@ -744,33 +724,28 @@ onMounted(load)
/>
</div>
</div>
</template>
</template>
</Card>
</div>
</div>
<!-- CARD: PERFIL PÚBLICO -->
<Card>
<template #content>
<button
type="button"
class="w-full flex items-center justify-between gap-3 text-left"
@click="toggleCard('perfil')"
>
<div class="flex items-center gap-3">
<div class="grid place-items-center w-9 h-9 rounded-xl bg-blue-100 dark:bg-blue-900/30 text-blue-600 shrink-0">
<i class="pi pi-map-marker" />
</div>
<div>
<div class="font-semibold leading-none">Perfil Público</div>
<div v-if="expandedCard !== 'perfil'" class="text-xs text-surface-400 mt-1">{{ resumoPerfil }}</div>
</div>
</div>
<i class="pi transition-transform duration-200 text-surface-400 shrink-0"
:class="expandedCard === 'perfil' ? 'pi-angle-up' : 'pi-angle-down'" />
</button>
<div class="agd-accordion" :class="{ 'agd-accordion--open': expandedCard.has('perfil') }">
<button
type="button"
class="agd-accordion__header"
@click="toggleCard('perfil')"
>
<div class="agd-accordion__icon bg-blue-100 dark:bg-blue-900/30 text-blue-600">
<i class="pi pi-map-marker" />
</div>
<div class="min-w-0 flex-1 text-left">
<div class="agd-accordion__title">Perfil Público</div>
<div v-if="!expandedCard.has('perfil')" class="agd-accordion__summary">{{ resumoPerfil }}</div>
</div>
<i class="pi agd-accordion__chevron"
:class="expandedCard.has('perfil') ? 'pi-chevron-up' : 'pi-chevron-down'" />
</button>
<template v-if="expandedCard === 'perfil'">
<Divider />
<div v-if="expandedCard.has('perfil')" class="agd-accordion__body">
<div class="flex flex-col gap-5">
<!-- Endereço -->
@@ -780,7 +755,7 @@ onMounted(load)
</div>
<!-- Botão Como Chegar -->
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-xl">
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-[6px]">
<div>
<div class="font-medium text-sm">Botão "Como chegar"</div>
<div class="text-xs text-surface-400 mt-0.5">Exibe um botão que abre o mapa para o paciente.</div>
@@ -804,33 +779,28 @@ onMounted(load)
/>
</div>
</div>
</template>
</template>
</Card>
</div>
</div>
<!-- CARD: FLUXO DE AGENDAMENTO -->
<Card>
<template #content>
<button
type="button"
class="w-full flex items-center justify-between gap-3 text-left"
@click="toggleCard('fluxo')"
>
<div class="flex items-center gap-3">
<div class="grid place-items-center w-9 h-9 rounded-xl bg-cyan-100 dark:bg-cyan-900/30 text-cyan-600 shrink-0">
<i class="pi pi-sitemap" />
</div>
<div>
<div class="font-semibold leading-none">Fluxo de Agendamento</div>
<div v-if="expandedCard !== 'fluxo'" class="text-xs text-surface-400 mt-1">{{ resumoFluxo }}</div>
</div>
</div>
<i class="pi transition-transform duration-200 text-surface-400 shrink-0"
:class="expandedCard === 'fluxo' ? 'pi-angle-up' : 'pi-angle-down'" />
</button>
<div class="agd-accordion" :class="{ 'agd-accordion--open': expandedCard.has('fluxo') }">
<button
type="button"
class="agd-accordion__header"
@click="toggleCard('fluxo')"
>
<div class="agd-accordion__icon bg-cyan-100 dark:bg-cyan-900/30 text-cyan-600">
<i class="pi pi-sitemap" />
</div>
<div class="min-w-0 flex-1 text-left">
<div class="agd-accordion__title">Fluxo de Agendamento</div>
<div v-if="!expandedCard.has('fluxo')" class="agd-accordion__summary">{{ resumoFluxo }}</div>
</div>
<i class="pi agd-accordion__chevron"
:class="expandedCard.has('fluxo') ? 'pi-chevron-up' : 'pi-chevron-down'" />
</button>
<template v-if="expandedCard === 'fluxo'">
<Divider />
<div v-if="expandedCard.has('fluxo')" class="agd-accordion__body">
<div class="flex flex-col gap-5">
<!-- Modo de aprovação -->
@@ -840,7 +810,7 @@ onMounted(load)
<div
v-for="opt in modoOptions"
:key="opt.value"
class="flex items-center gap-3 p-3 rounded-xl border cursor-pointer transition"
class="flex items-center gap-3 p-3 rounded-[6px] border cursor-pointer transition"
:class="cfg.modo_aprovacao === opt.value
? 'border-primary bg-primary/5 dark:bg-primary/10'
: 'border-surface-200 dark:border-surface-700 hover:border-surface-300'"
@@ -957,33 +927,28 @@ onMounted(load)
/>
</div>
</div>
</template>
</template>
</Card>
</div>
</div>
<!-- CARD: PAGAMENTO -->
<Card>
<template #content>
<button
type="button"
class="w-full flex items-center justify-between gap-3 text-left"
@click="toggleCard('pagamento')"
>
<div class="flex items-center gap-3">
<div class="grid place-items-center w-9 h-9 rounded-xl bg-green-100 dark:bg-green-900/30 text-green-600 shrink-0">
<i class="pi pi-credit-card" />
</div>
<div>
<div class="font-semibold leading-none">Pagamento</div>
<div v-if="expandedCard !== 'pagamento'" class="text-xs text-surface-400 mt-1">{{ resumoPagamento }}</div>
</div>
</div>
<i class="pi transition-transform duration-200 text-surface-400 shrink-0"
:class="expandedCard === 'pagamento' ? 'pi-angle-up' : 'pi-angle-down'" />
</button>
<div class="agd-accordion" :class="{ 'agd-accordion--open': expandedCard.has('pagamento') }">
<button
type="button"
class="agd-accordion__header"
@click="toggleCard('pagamento')"
>
<div class="agd-accordion__icon bg-green-100 dark:bg-green-900/30 text-green-600">
<i class="pi pi-credit-card" />
</div>
<div class="min-w-0 flex-1 text-left">
<div class="agd-accordion__title">Pagamento</div>
<div v-if="!expandedCard.has('pagamento')" class="agd-accordion__summary">{{ resumoPagamento }}</div>
</div>
<i class="pi agd-accordion__chevron"
:class="expandedCard.has('pagamento') ? 'pi-chevron-up' : 'pi-chevron-down'" />
</button>
<template v-if="expandedCard === 'pagamento'">
<Divider />
<div v-if="expandedCard.has('pagamento')" class="agd-accordion__body">
<div class="flex flex-col gap-5">
<!-- Modo de pagamento -->
@@ -994,13 +959,13 @@ onMounted(load)
v-for="modo in modosPagamento"
:key="modo.value"
type="button"
class="flex items-center gap-3 p-3 rounded-xl border text-left transition"
class="flex items-center gap-3 p-3 rounded-[6px] border text-left transition"
:class="cfg.pagamento_modo === modo.value
? 'border-primary bg-primary/5 ring-1 ring-primary/30'
: 'border-surface-border bg-surface-50 dark:bg-surface-800 hover:bg-surface-100 dark:hover:bg-surface-700'"
@click="cfg.pagamento_modo = modo.value"
>
<div class="grid place-items-center w-9 h-9 rounded-lg shrink-0"
<div class="grid place-items-center w-9 h-9 rounded-[6px] shrink-0"
:class="cfg.pagamento_modo === modo.value ? 'bg-primary/15 text-primary' : 'bg-surface-200 dark:bg-surface-700 text-surface-400'">
<i :class="['pi', modo.icon]" />
</div>
@@ -1023,7 +988,7 @@ onMounted(load)
<RouterLink to="/configuracoes/pagamento" class="underline">Configurações Pagamento</RouterLink>.
</p>
<div v-if="!algumMetodoConfigurado" class="rounded-xl border border-orange-200 bg-orange-50 dark:bg-orange-900/20 p-3 text-sm text-orange-700 dark:text-orange-300">
<div v-if="!algumMetodoConfigurado" class="rounded-[6px] border border-orange-200 bg-orange-50 dark:bg-orange-900/20 p-3 text-sm text-orange-700 dark:text-orange-300">
<i class="pi pi-exclamation-triangle mr-1" />
Nenhuma forma de pagamento configurada ainda.
<RouterLink to="/configuracoes/pagamento" class="underline font-medium ml-1">Configurar agora</RouterLink>
@@ -1033,7 +998,7 @@ onMounted(load)
<label
v-for="m in metodosDisponiveis"
:key="m.key"
class="flex items-center gap-3 p-3 rounded-xl border cursor-pointer transition select-none"
class="flex items-center gap-3 p-3 rounded-[6px] border cursor-pointer transition select-none"
:class="[
!m.ativo ? 'opacity-40 cursor-not-allowed border-surface-border bg-surface-50 dark:bg-surface-800' :
isMetodoVisivel(m.key) ? 'border-primary bg-primary/5 ring-1 ring-primary/20' : 'border-surface-border bg-surface-50 dark:bg-surface-800 hover:bg-surface-100 dark:hover:bg-surface-700'
@@ -1125,39 +1090,34 @@ onMounted(load)
/>
</div>
</div>
</template>
</template>
</Card>
</div>
</div>
<!-- CARD: TRIAGEM & CONFORMIDADE -->
<Card>
<template #content>
<button
type="button"
class="w-full flex items-center justify-between gap-3 text-left"
@click="toggleCard('triagem')"
>
<div class="flex items-center gap-3">
<div class="grid place-items-center w-9 h-9 rounded-xl bg-orange-100 dark:bg-orange-900/30 text-orange-600 shrink-0">
<i class="pi pi-shield" />
</div>
<div>
<div class="font-semibold leading-none">Triagem & Conformidade</div>
<div v-if="expandedCard !== 'triagem'" class="text-xs text-surface-400 mt-1">{{ resumoTriagem }}</div>
</div>
</div>
<i class="pi transition-transform duration-200 text-surface-400 shrink-0"
:class="expandedCard === 'triagem' ? 'pi-angle-up' : 'pi-angle-down'" />
</button>
<div class="agd-accordion" :class="{ 'agd-accordion--open': expandedCard.has('triagem') }">
<button
type="button"
class="agd-accordion__header"
@click="toggleCard('triagem')"
>
<div class="agd-accordion__icon bg-orange-100 dark:bg-orange-900/30 text-orange-600">
<i class="pi pi-shield" />
</div>
<div class="min-w-0 flex-1 text-left">
<div class="agd-accordion__title">Triagem & Conformidade</div>
<div v-if="!expandedCard.has('triagem')" class="agd-accordion__summary">{{ resumoTriagem }}</div>
</div>
<i class="pi agd-accordion__chevron"
:class="expandedCard.has('triagem') ? 'pi-chevron-up' : 'pi-chevron-down'" />
</button>
<template v-if="expandedCard === 'triagem'">
<Divider />
<div v-if="expandedCard.has('triagem')" class="agd-accordion__body">
<div class="flex flex-col gap-4">
<div class="text-sm font-semibold text-surface-600">Campos extras no formulário</div>
<!-- Triagem: motivo -->
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-xl">
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-[6px]">
<div>
<div class="font-medium text-sm">Motivo da consulta</div>
<div class="text-xs text-surface-400 mt-0.5">Campo de texto livre opcional para o paciente informar o motivo.</div>
@@ -1166,7 +1126,7 @@ onMounted(load)
</div>
<!-- Triagem: como conheceu -->
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-xl">
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-[6px]">
<div>
<div class="font-medium text-sm">Como nos conheceu?</div>
<div class="text-xs text-surface-400 mt-0.5">Pergunta de origem (indicação, redes sociais, busca).</div>
@@ -1179,7 +1139,7 @@ onMounted(load)
<div class="text-sm font-semibold text-surface-600">Segurança & LGPD</div>
<!-- Verificação de email -->
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-xl">
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-[6px]">
<div>
<div class="font-medium text-sm">Verificação de e-mail</div>
<div class="text-xs text-surface-400 mt-0.5">
@@ -1190,7 +1150,7 @@ onMounted(load)
</div>
<!-- Aceite LGPD -->
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-xl">
<div class="flex items-center justify-between p-3 bg-surface-50 dark:bg-surface-800 rounded-[6px]">
<div>
<div class="font-medium text-sm">Aceite obrigatório de termos (LGPD)</div>
<div class="text-xs text-surface-400 mt-0.5">
@@ -1209,33 +1169,28 @@ onMounted(load)
/>
</div>
</div>
</template>
</template>
</Card>
</div>
</div>
<!-- CARD: TEXTOS DA JORNADA -->
<Card>
<template #content>
<button
type="button"
class="w-full flex items-center justify-between gap-3 text-left"
@click="toggleCard('textos')"
>
<div class="flex items-center gap-3">
<div class="grid place-items-center w-9 h-9 rounded-xl bg-pink-100 dark:bg-pink-900/30 text-pink-600 shrink-0">
<i class="pi pi-file-edit" />
</div>
<div>
<div class="font-semibold leading-none">Textos da Jornada</div>
<div v-if="expandedCard !== 'textos'" class="text-xs text-surface-400 mt-1">{{ resumoTextos }}</div>
</div>
</div>
<i class="pi transition-transform duration-200 text-surface-400 shrink-0"
:class="expandedCard === 'textos' ? 'pi-angle-up' : 'pi-angle-down'" />
</button>
<div class="agd-accordion" :class="{ 'agd-accordion--open': expandedCard.has('textos') }">
<button
type="button"
class="agd-accordion__header"
@click="toggleCard('textos')"
>
<div class="agd-accordion__icon bg-pink-100 dark:bg-pink-900/30 text-pink-600">
<i class="pi pi-file-edit" />
</div>
<div class="min-w-0 flex-1 text-left">
<div class="agd-accordion__title">Textos da Jornada</div>
<div v-if="!expandedCard.has('textos')" class="agd-accordion__summary">{{ resumoTextos }}</div>
</div>
<i class="pi agd-accordion__chevron"
:class="expandedCard.has('textos') ? 'pi-chevron-up' : 'pi-chevron-down'" />
</button>
<template v-if="expandedCard === 'textos'">
<Divider />
<div v-if="expandedCard.has('textos')" class="agd-accordion__body">
<div class="flex flex-col gap-5">
<!-- Mensagem de boas-vindas -->
@@ -1289,28 +1244,119 @@ onMounted(load)
/>
</div>
</div>
</template>
</template>
</Card>
</div>
</div>
</template>
</div>
</template>
<style scoped>
/* ── Upload zone ──────────────────────────────────── */
.agd-upload-zone {
display: flex;
align-items: center;
gap: 0.625rem;
padding: 0.75rem 1rem;
border: 1.5px dashed var(--surface-border);
border-radius: 0.875rem;
border-radius: 6px;
cursor: pointer;
transition: border-color 0.15s, background 0.15s;
background: var(--surface-ground);
}
.agd-upload-zone:hover {
border-color: var(--p-primary-500, #6366f1);
background: color-mix(in srgb, var(--p-primary-500, #6366f1) 5%, transparent);
border-color: var(--primary-color, #6366f1);
background: color-mix(in srgb, var(--primary-color, #6366f1) 5%, transparent);
}
</style>
/* ── Subheader degradê ────────────────────────────── */
.cfg-subheader {
display: flex; align-items: center; gap: 0.65rem;
padding: 0.875rem 1rem; border-radius: 6px;
border: 1px solid color-mix(in srgb, var(--primary-color, #6366f1) 30%, transparent);
background: linear-gradient(135deg,
color-mix(in srgb, var(--primary-color, #6366f1) 12%, var(--surface-card)) 0%,
color-mix(in srgb, var(--primary-color, #6366f1) 4%, var(--surface-card)) 60%,
var(--surface-card) 100%);
position: relative; overflow: hidden;
}
.cfg-subheader::before {
content: ''; position: absolute;
top: -20px; right: -20px;
width: 80px; height: 80px; border-radius: 50%;
background: color-mix(in srgb, var(--primary-color, #6366f1) 15%, transparent);
filter: blur(20px); pointer-events: none;
}
.cfg-subheader__icon {
display: grid; place-items: center;
width: 2rem; height: 2rem; border-radius: 6px; flex-shrink: 0;
background: color-mix(in srgb, var(--primary-color, #6366f1) 20%, transparent);
color: var(--primary-color, #6366f1); font-size: 0.85rem;
}
.cfg-subheader__title { font-size: 0.95rem; font-weight: 700; letter-spacing: -0.01em; color: var(--primary-color, #6366f1); }
.cfg-subheader__sub { font-size: 0.75rem; color: var(--text-color-secondary); opacity: 0.85; }
.cfg-subheader__actions { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; flex-shrink: 0; position: relative; z-index: 1; }
/* ── Card status (sem accordion) ─────────────────── */
.agd-card {
border: 1px solid var(--surface-border);
border-radius: 6px;
background: var(--surface-card);
padding: 1rem;
}
/* ── Accordion cards ──────────────────────────────── */
.agd-accordion {
border: 1px solid var(--surface-border);
border-radius: 6px;
background: var(--surface-card);
overflow: hidden;
transition: border-color 0.15s;
}
.agd-accordion--open {
border-color: color-mix(in srgb, var(--primary-color, #6366f1) 35%, transparent);
}
.agd-accordion__header {
display: flex; align-items: center; gap: 0.75rem;
width: 100%; padding: 0.875rem 1rem;
background: transparent; border: none; cursor: pointer;
transition: background 0.12s;
text-align: left;
}
.agd-accordion__header:hover { background: var(--surface-hover); }
.agd-accordion--open .agd-accordion__header {
background: color-mix(in srgb, var(--primary-color, #6366f1) 4%, var(--surface-card));
border-bottom: 1px solid var(--surface-border);
}
.agd-accordion__icon {
display: grid; place-items: center;
width: 2rem; height: 2rem; border-radius: 6px; flex-shrink: 0;
}
.agd-accordion__title {
font-size: 0.88rem; font-weight: 700;
color: var(--text-color);
}
.agd-accordion--open .agd-accordion__title {
color: var(--primary-color, #6366f1);
}
.agd-accordion__summary {
font-size: 0.72rem; color: var(--text-color-secondary);
opacity: 0.75; margin-top: 1px;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.agd-accordion__chevron {
font-size: 0.7rem; color: var(--text-color-secondary);
opacity: 0.5; flex-shrink: 0;
transition: transform 0.2s;
}
.agd-accordion--open .agd-accordion__chevron {
color: var(--primary-color, #6366f1); opacity: 0.8;
}
.agd-accordion__body {
padding: 1rem;
display: flex; flex-direction: column; gap: 1.25rem;
}
</style>