Files
agenciapsilmno/src/features/agenda/components/AdicionarCompromissoPage.vue

1004 lines
30 KiB
Vue

<template>
<div class="p-4 md:p-6">
<!-- Header -->
<div class="mb-4 flex items-center justify-between">
<div class="min-w-0">
<h1 class="text-xl md:text-2xl font-semibold text-[var(--text-color)] leading-tight">
Adicionar Atividade
</h1>
<p class="text-sm text-[var(--text-color-secondary)]">
Cadastre um compromisso e visualize como ele ficará na agenda.
</p>
</div>
<Button
icon="pi pi-times"
severity="secondary"
text
rounded
aria-label="Fechar"
@click="onClose"
/>
</div>
<!-- Main surface -->
<div class="activity-shell">
<!-- LEFT -->
<div class="left-pane">
<Card class="h-full">
<template #content>
<!-- Tabs fake (somente Atividade, como no layout) -->
<div class="fake-tabs">
<div class="fake-tab is-active">Atividade</div>
</div>
<div class="mt-4">
<div class="field">
<label class="field-label">Título:</label>
<!-- Tipo de atividade -->
<div class="activity-types">
<div
v-for="t in activityTypes"
:key="t.value"
class="activity-type"
:class="{ 'is-selected': form.type === t.value }"
@click="form.type = t.value"
role="button"
tabindex="0"
>
<RadioButton
:inputId="`type-${t.value}`"
name="activityType"
:value="t.value"
v-model="form.type"
/>
<label :for="`type-${t.value}`" class="activity-type__label">
<span class="dot" :style="{ background: t.dot }" />
<span class="name">{{ t.label }}</span>
</label>
</div>
</div>
<!-- Título custom -->
<div class="mt-3">
<FloatLabel>
<InputText
id="customTitle"
v-model="form.customTitle"
class="w-full"
autocomplete="off"
/>
<label for="customTitle">Informe o título se necessário</label>
</FloatLabel>
<small class="hint">
Se vazio, usaremos o título do tipo selecionado.
</small>
</div>
</div>
<Divider />
<!-- Paciente -->
<div class="field">
<div class="flex items-center justify-between gap-3">
<label class="field-label m-0">Paciente:</label>
<Button
icon="pi pi-plus"
label="Adicionar paciente"
severity="secondary"
text
@click="onAddPatient"
/>
</div>
<div class="patient-row mt-2">
<Avatar
:image="selectedPatient?.avatar"
shape="circle"
class="patient-avatar"
/>
<div class="min-w-0">
<div class="flex items-center gap-2 min-w-0">
<div class="patient-name truncate">
{{ selectedPatient?.name || 'Selecione um paciente' }}
</div>
<Tag
v-if="selectedPatient?.recorrente"
value="RECORRENTE"
severity="danger"
class="patient-tag"
/>
</div>
<div class="patient-meta">
<span class="pi pi-phone" />
<span>{{ selectedPatient?.phone || '—' }}</span>
<span class="sep"></span>
<span class="pi pi-envelope" />
<span class="truncate">{{ selectedPatient?.email || '—' }}</span>
</div>
<div class="patient-meta">
<span class="pi pi-map-marker" />
<span class="truncate">{{ selectedPatient?.address || '—' }}</span>
</div>
</div>
<div class="min-w-[240px] hidden md:block">
<!-- Select (PrimeVue v4) -->
<FloatLabel>
<Select
inputId="patientSelect"
v-model="form.patientId"
:options="patients"
optionLabel="name"
optionValue="id"
filter
class="w-full"
/>
<label for="patientSelect">Selecionar paciente</label>
</FloatLabel>
</div>
</div>
<!-- Select mobile -->
<div class="mt-3 md:hidden">
<FloatLabel>
<Select
inputId="patientSelectMobile"
v-model="form.patientId"
:options="patients"
optionLabel="name"
optionValue="id"
filter
class="w-full"
/>
<label for="patientSelectMobile">Selecionar paciente</label>
</FloatLabel>
</div>
</div>
<Divider />
<!-- Data e horário -->
<div class="field">
<div class="field-label">Data e Horário <span class="muted">(Fuso: Brasil - São Paulo, +3H)</span></div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-3 mt-2">
<FloatLabel>
<Calendar
inputId="date"
v-model="form.date"
dateFormat="dd/mm/yy"
showIcon
class="w-full"
/>
<label for="date">Data</label>
</FloatLabel>
<FloatLabel>
<Select
inputId="startTime"
v-model="form.startTime"
:options="timeOptions"
class="w-full"
/>
<label for="startTime">Início</label>
</FloatLabel>
<FloatLabel>
<InputText
inputId="endTime"
:value="computedEndTime"
class="w-full"
disabled
/>
<label for="endTime">Fim</label>
</FloatLabel>
</div>
<div class="mt-3">
<div class="field-label">Selecione o horário:</div>
<div class="slots-block mt-2">
<div class="slots-row">
<div class="slot-group-title">MANHÃ</div>
<div class="slot-chips">
<Button
v-for="s in slotGroups.manha"
:key="`m-${s}`"
:label="s"
size="small"
:severity="slotSeverity(s)"
:outlined="!isSelectedSlot(s)"
class="slot-chip"
@click="selectSlot(s)"
/>
</div>
</div>
<div class="slots-row">
<div class="slot-group-title">
TARDE <span class="muted">(intervalo: 12:00 - 13:00)</span>
</div>
<div class="slot-chips">
<Button
v-for="s in slotGroups.tarde"
:key="`t-${s}`"
:label="s"
size="small"
:severity="slotSeverity(s)"
:outlined="!isSelectedSlot(s)"
class="slot-chip"
@click="selectSlot(s)"
/>
</div>
</div>
<div class="slots-row">
<div class="slot-group-title">NOITE</div>
<div class="slot-chips">
<Button
v-for="s in slotGroups.noite"
:key="`n-${s}`"
:label="s"
size="small"
:severity="slotSeverity(s)"
:outlined="!isSelectedSlot(s)"
class="slot-chip"
@click="selectSlot(s)"
/>
</div>
</div>
<div class="legend mt-2">
<span class="legend-item">
<span class="legend-dot is-blocked" /> Slot bloqueado paciente
</span>
<span class="legend-item">
<span class="legend-dot is-free" /> Disponível
</span>
<span class="legend-item">
<span class="legend-dot is-selected" /> Selecionado
</span>
</div>
</div>
</div>
</div>
<Divider />
<!-- Observações -->
<div class="field">
<FloatLabel>
<InputText
id="notes"
v-model="form.notes"
class="w-full"
autocomplete="off"
/>
<label for="notes">Observações (opcional)</label>
</FloatLabel>
</div>
</div>
</template>
</Card>
</div>
<!-- RIGHT -->
<div class="right-pane">
<Card class="h-full">
<template #content>
<div class="preview-top">
<div class="flex items-center gap-2">
<Tag value="Hoje" severity="secondary" />
<div class="preview-date">
{{ previewDateLabel }}
</div>
</div>
<div class="preview-badge">PRÉ-VISUALIZAÇÃO</div>
</div>
<Divider class="my-3" />
<!-- Timeline -->
<div class="timeline">
<div class="timeline-left">
<div
v-for="h in timelineHours"
:key="`h-${h}`"
class="hour"
>
<div class="hour-label">{{ pad2(h) }}00</div>
<div class="half-label">30</div>
</div>
</div>
<div class="timeline-grid">
<div
v-for="h in timelineHours"
:key="`g-${h}`"
class="grid-hour"
>
<div class="grid-line" />
<div class="grid-half" />
</div>
<!-- evento preview -->
<div
class="event-chip"
:style="eventStyle"
>
<div class="event-title">{{ computedTitle }}</div>
<div class="event-sub">{{ selectedPatient?.name || '—' }}</div>
</div>
<!-- marcador de agora (estático, estética) -->
<div class="now-marker" :style="{ top: nowMarkerTop + 'px' }">
<div class="now-pill">10:06</div>
<div class="now-line" />
</div>
</div>
</div>
<!-- conflito -->
<div v-if="hasConflict" class="conflict mt-3">
<i class="pi pi-exclamation-triangle" />
<div class="conflict-text">
<b>Conflito detectado:</b> possui um evento neste horário!
</div>
</div>
<Divider class="my-4" />
<!-- Repetição -->
<div class="section">
<div class="section-title">Repetição:</div>
<div class="repeat-row mt-2">
<div class="repeat-options">
<div
v-for="r in repeatOptions"
:key="r.value"
class="repeat-pill"
:class="{ 'is-on': form.repeat === r.value }"
@click="form.repeat = r.value"
role="button"
tabindex="0"
>
<RadioButton
:inputId="`rep-${r.value}`"
name="repeat"
:value="r.value"
v-model="form.repeat"
/>
<label :for="`rep-${r.value}`">{{ r.label }}</label>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mt-3">
<div>
<FloatLabel>
<Select
inputId="repeatUntil"
v-model="form.repeatUntil"
:options="repeatUntilOptions"
class="w-full"
:disabled="form.repeat === 'none'"
/>
<label for="repeatUntil">Termine em</label>
</FloatLabel>
</div>
<div>
<FloatLabel>
<InputText
id="repeatCount"
v-model="form.repeatCount"
class="w-full"
:disabled="form.repeat === 'none'"
/>
<label for="repeatCount">Data específica</label>
</FloatLabel>
</div>
</div>
</div>
<Divider class="my-4" />
<!-- Lembrete -->
<div class="section">
<div class="section-title">Lembrete:</div>
<div class="mt-2">
<FloatLabel>
<Select
inputId="reminder"
v-model="form.reminder"
:options="reminderOptions"
class="w-full"
/>
<label for="reminder">Quando avisar</label>
</FloatLabel>
</div>
</div>
<!-- Atenção recorrente -->
<div v-if="selectedPatient?.recorrente" class="attention mt-4">
<div class="attention-title">Atenção :</div>
<ul class="attention-list">
<li>Este é um paciente recorrente, com horários pré-estabelecidos na sua agenda.</li>
<li>Se continuar o sistema adicionará uma sessão extra.</li>
<li class="linklike" @click="onManageRecurring">Se deseja alterar os horários pré-estabelecidos, clique aqui</li>
</ul>
</div>
<!-- Footer buttons -->
<div class="footer-actions mt-5">
<Button
label="Cancelar"
severity="secondary"
outlined
class="w-full md:w-auto"
@click="onClose"
/>
<Button
label="Salvar"
class="w-full md:w-auto"
@click="onSave"
/>
</div>
</template>
</Card>
</div>
</div>
</div>
</template>
<script setup>
import { computed, reactive } from 'vue'
// PrimeVue
import Card from 'primevue/card'
import Button from 'primevue/button'
import Divider from 'primevue/divider'
import FloatLabel from 'primevue/floatlabel'
import InputText from 'primevue/inputtext'
import Calendar from 'primevue/calendar'
import RadioButton from 'primevue/radiobutton'
import Tag from 'primevue/tag'
import Avatar from 'primevue/avatar'
import Select from 'primevue/select'
// ---------------------------------------------------------------------
// Mock de dados (substitua por Supabase depois)
// ---------------------------------------------------------------------
const patients = [
{
id: 'p1',
name: 'Leonardo Nohama',
recorrente: true,
phone: '(16) 98828-8038',
email: 'leonardo@gmail.com',
address: 'Rua Dr. X, 123, Centro, Campinas, SP — 13010-001',
avatar: 'https://i.pravatar.cc/80?img=12'
},
{
id: 'p2',
name: 'Mariana S.',
recorrente: false,
phone: '(11) 99999-0000',
email: 'mariana@email.com',
address: 'São Carlos, SP',
avatar: 'https://i.pravatar.cc/80?img=47'
},
{
id: 'p3',
name: 'Rafael A.',
recorrente: false,
phone: '(19) 98888-1212',
email: 'rafa@exemplo.com',
address: 'Araraquara, SP',
avatar: 'https://i.pravatar.cc/80?img=33'
}
]
// ---------------------------------------------------------------------
// Form state
// ---------------------------------------------------------------------
const form = reactive({
type: 'atendimento',
customTitle: '',
patientId: 'p1',
date: new Date(),
startTime: '09:00',
durationMin: 60,
notes: '',
repeat: 'none', // none | daily | weekly | biweekly | monthly
repeatUntil: 'never',
repeatCount: 'Após 10 ocorrências',
reminder: '4h'
})
// ---------------------------------------------------------------------
// UI options
// ---------------------------------------------------------------------
const activityTypes = [
{ value: 'atendimento', label: 'Atendimento', dot: 'rgba(59,130,246,.85)' },
{ value: 'supervisao', label: 'Supervisão', dot: 'rgba(99,102,241,.85)' },
{ value: 'analise', label: 'Análise pessoal', dot: 'rgba(245,158,11,.85)' },
{ value: 'estudo', label: 'Estudo', dot: 'rgba(16,185,129,.85)' }
]
const timeOptions = [
'07:00','07:30','08:00','08:30','09:00','09:30','10:00','10:30','11:00','11:30',
'12:00','12:30','13:00','13:30','14:00','14:30','15:00','15:30','16:00','16:30',
'17:00','17:30','18:00','18:30','19:00','19:30','20:00','20:30','21:00','21:30','22:00'
]
const repeatOptions = [
{ value: 'none', label: 'Não repete' },
{ value: 'daily', label: 'Diário' },
{ value: 'weekly', label: 'Semanal' },
{ value: 'biweekly', label: 'Quinzenal' },
{ value: 'monthly', label: 'Mensal' }
]
const repeatUntilOptions = ['Nunca', 'Data específica', 'Após X ocorrências'].map((v) => ({
label: v,
value: v === 'Nunca' ? 'never' : v === 'Data específica' ? 'date' : 'count'
}))
const reminderOptions = [
{ label: 'Sem lembrete', value: 'none' },
{ label: '10 minutos antes', value: '10m' },
{ label: '30 minutos antes', value: '30m' },
{ label: '1 hora antes', value: '1h' },
{ label: '4 horas antes', value: '4h' },
{ label: '1 dia antes', value: '1d' }
]
// Slots (exemplo)
const slotGroups = {
manha: ['08:00','09:00','10:00','11:00'],
tarde: ['13:00','15:00','16:00','17:00'],
noite: ['18:00','19:00','20:00','21:00','22:00']
}
// Slots bloqueados “pelo paciente” (mock)
const blockedSlots = new Set(['16:00', '21:00', '09:00']) // exemplo
const timelineStart = 7
const timelineEnd = 12 // só pra caber bonito; você pode aumentar conforme sua agenda
const timelineHours = Array.from({ length: timelineEnd - timelineStart }, (_, i) => timelineStart + i)
// ---------------------------------------------------------------------
// Computeds
// ---------------------------------------------------------------------
const selectedPatient = computed(() => patients.find(p => p.id === form.patientId) || null)
const computedTitle = computed(() => {
const typed = (form.customTitle || '').trim()
if (typed) return typed
const found = activityTypes.find(t => t.value === form.type)
return found?.label || 'Atividade'
})
const computedEndTime = computed(() => addMinutesToTime(form.startTime, form.durationMin))
// conflito mock: se startTime estiver em “09:00” dispara
const hasConflict = computed(() => form.startTime === '09:00')
// label de data no topo
const previewDateLabel = computed(() => {
const d = form.date instanceof Date ? form.date : new Date()
const day = d.getDate()
const month = d.toLocaleDateString('pt-BR', { month: 'long' })
const weekday = d.toLocaleDateString('pt-BR', { weekday: 'long' })
return `${day} ${month}, ${weekday}`
})
// ---------------------------------------------------------------------
// Preview positioning (timeline)
// ---------------------------------------------------------------------
const pxPerHour = 84 // ajuste fino do grid
const nowMarkerTop = 3.1 * pxPerHour // só estético (aprox 10:06 dentro do bloco)
const eventStyle = computed(() => {
// converte startTime para offset
const [hh, mm] = form.startTime.split(':').map(Number)
const startFloat = hh + (mm / 60)
const top = (startFloat - timelineStart) * pxPerHour
const height = (form.durationMin / 60) * pxPerHour
return {
top: `${Math.max(6, top)}px`,
height: `${Math.max(38, height)}px`
}
})
// ---------------------------------------------------------------------
// Slot selection helpers
// ---------------------------------------------------------------------
function isSelectedSlot(t) {
return form.startTime === t
}
function selectSlot(t) {
form.startTime = t
}
function slotSeverity(t) {
if (isSelectedSlot(t)) return 'primary'
if (blockedSlots.has(t)) return 'danger'
return 'secondary'
}
// ---------------------------------------------------------------------
// Actions (plugue no seu router/toast depois)
// ---------------------------------------------------------------------
function onClose() {
// ex: router.back()
console.log('close')
}
function onSave() {
// ex: salvar no Supabase
console.log('save', JSON.parse(JSON.stringify(form)))
}
function onAddPatient() {
console.log('add patient')
}
function onManageRecurring() {
console.log('manage recurring')
}
// ---------------------------------------------------------------------
// Utils
// ---------------------------------------------------------------------
function pad2(n) {
return String(n).padStart(2, '0')
}
function addMinutesToTime(hhmm, minutesToAdd) {
const [h, m] = hhmm.split(':').map(Number)
const total = (h * 60 + m + minutesToAdd) % (24 * 60)
const nh = Math.floor(total / 60)
const nm = total % 60
return `${pad2(nh)}:${pad2(nm)}`
}
</script>
<style scoped>
.activity-shell{
display:grid;
grid-template-columns: 1.08fr .92fr;
gap: 1rem;
}
@media (max-width: 1024px){
.activity-shell{ grid-template-columns: 1fr; }
}
.fake-tabs{
border-bottom: 1px solid var(--surface-border);
display:flex;
gap:.5rem;
}
.fake-tab{
padding:.65rem 1rem;
border: 1px solid var(--surface-border);
border-bottom: none;
border-top-left-radius: .8rem;
border-top-right-radius: .8rem;
background: color-mix(in srgb, var(--surface-card), transparent 18%);
color: var(--text-color-secondary);
font-weight: 600;
}
.fake-tab.is-active{
background: var(--surface-card);
color: var(--text-color);
box-shadow: 0 10px 30px rgba(0,0,0,.04);
}
.field{ margin-top: 1rem; }
.field-label{
font-weight: 700;
color: var(--text-color);
}
.field-label .muted{
font-weight: 600;
color: var(--text-color-secondary);
margin-left: .35rem;
}
.hint{
display:block;
margin-top:.35rem;
color: var(--text-color-secondary);
}
.activity-types{
margin-top: .6rem;
display:flex;
flex-direction:column;
gap:.55rem;
}
.activity-type{
display:flex;
align-items:center;
gap:.7rem;
padding:.65rem .75rem;
border-radius: 1rem;
border: 1px solid var(--surface-border);
background: color-mix(in srgb, var(--surface-card), transparent 22%);
cursor:pointer;
}
.activity-type.is-selected{
border-color: color-mix(in srgb, var(--primary-color), var(--surface-border) 55%);
background: color-mix(in srgb, var(--primary-color), transparent 92%);
}
.activity-type__label{
display:flex;
align-items:center;
gap:.55rem;
cursor:pointer;
}
.dot{
width:10px;height:10px;border-radius:999px;
box-shadow: 0 0 0 4px color-mix(in srgb, currentColor, transparent 85%);
}
.name{ font-weight: 650; color: var(--text-color); }
.patient-row{
display:flex;
gap:.75rem;
align-items:flex-start;
border: 1px solid var(--surface-border);
border-radius: 1.25rem;
padding: .85rem;
background: color-mix(in srgb, var(--surface-card), transparent 18%);
}
.patient-avatar{
width: 40px;
height: 40px;
}
.patient-name{
font-weight: 800;
}
.patient-tag{ height: 22px; }
.patient-meta{
margin-top:.25rem;
display:flex;
align-items:center;
gap:.45rem;
color: var(--text-color-secondary);
font-size: .9rem;
}
.patient-meta .sep{
opacity:.7;
margin: 0 .25rem;
}
.slots-block{
border: 1px solid var(--surface-border);
border-radius: 1.25rem;
padding: .85rem;
background: color-mix(in srgb, var(--surface-card), transparent 18%);
}
.slots-row{
display:flex;
flex-direction:column;
gap:.5rem;
margin-bottom:.85rem;
}
.slot-group-title{
font-weight: 800;
color: var(--text-color);
}
.slot-group-title .muted{
font-weight: 650;
color: var(--text-color-secondary);
margin-left:.35rem;
}
.slot-chips{
display:flex;
flex-wrap:wrap;
gap:.5rem;
}
.slot-chip{
border-radius: 999px;
}
.legend{
display:flex;
flex-wrap:wrap;
gap:.9rem;
color: var(--text-color-secondary);
font-size: .85rem;
}
.legend-item{
display:flex;
align-items:center;
gap:.4rem;
}
.legend-dot{
width:10px;height:10px;border-radius:999px;
border: 1px solid var(--surface-border);
}
.legend-dot.is-blocked{ background: color-mix(in srgb, var(--red-500), transparent 10%); }
.legend-dot.is-free{ background: color-mix(in srgb, var(--surface-500), transparent 55%); }
.legend-dot.is-selected{ background: color-mix(in srgb, var(--primary-color), transparent 10%); }
.preview-top{
display:flex;
justify-content:space-between;
align-items:center;
gap:1rem;
}
.preview-date{
font-weight: 900;
font-size: 1.05rem;
color: var(--text-color);
}
.preview-badge{
font-weight: 900;
font-size: .8rem;
letter-spacing:.06em;
color: color-mix(in srgb, var(--red-500), var(--text-color) 15%);
}
.timeline{
display:grid;
grid-template-columns: 68px 1fr;
gap:.75rem;
align-items:start;
}
.timeline-left .hour{
height: calc(84px);
position:relative;
padding-right:.4rem;
}
.hour-label{
font-weight: 900;
color: var(--text-color);
font-size: .9rem;
}
.half-label{
position:absolute;
top: 41px;
font-size: .8rem;
color: var(--text-color-secondary);
}
.timeline-grid{
position:relative;
border-radius: 1.25rem;
border: 1px solid var(--surface-border);
overflow:hidden;
background: color-mix(in srgb, var(--surface-card), transparent 12%);
}
.grid-hour{
height: 84px;
position:relative;
}
.grid-line{
position:absolute;
left:0; right:0; top:0;
height:1px;
background: color-mix(in srgb, var(--surface-border), transparent 5%);
}
.grid-half{
position:absolute;
left:0; right:0; top:42px;
height:1px;
background: color-mix(in srgb, var(--surface-border), transparent 35%);
}
.event-chip{
position:absolute;
left: 14px;
right: 18%;
border-radius: 12px;
padding: .7rem .85rem;
background: color-mix(in srgb, var(--primary-color), transparent 10%);
color: var(--primary-color-text);
box-shadow: 0 18px 40px rgba(0,0,0,.10);
}
.event-title{
font-weight: 900;
}
.event-sub{
opacity: .92;
font-weight: 650;
font-size: .9rem;
margin-top:.15rem;
}
.now-marker{
position:absolute;
left: 0;
right: 0;
pointer-events:none;
}
.now-pill{
position:absolute;
left: -56px;
top: -10px;
background: #111;
color:#fff;
font-weight: 900;
font-size: .75rem;
padding:.2rem .4rem;
border-radius: .45rem;
}
.now-line{
position:absolute;
left:0; right:0;
top:0;
height:2px;
background: color-mix(in srgb, var(--surface-900), transparent 15%);
opacity:.45;
}
.conflict{
display:flex;
align-items:flex-start;
gap:.6rem;
padding:.75rem .9rem;
border-radius: 1rem;
border: 1px solid color-mix(in srgb, var(--orange-500), var(--surface-border) 45%);
background: color-mix(in srgb, var(--orange-100), transparent 30%);
color: color-mix(in srgb, var(--orange-900), var(--text-color) 20%);
}
.conflict i{ margin-top:.1rem; }
.conflict-text{ line-height:1.2rem; }
.section-title{
font-weight: 900;
color: var(--text-color);
}
.repeat-options{
display:flex;
flex-wrap:wrap;
gap:.6rem;
}
.repeat-pill{
display:flex;
align-items:center;
gap:.55rem;
padding:.55rem .75rem;
border-radius: 999px;
border: 1px solid var(--surface-border);
background: color-mix(in srgb, var(--surface-card), transparent 18%);
cursor:pointer;
}
.repeat-pill.is-on{
border-color: color-mix(in srgb, var(--primary-color), var(--surface-border) 55%);
background: color-mix(in srgb, var(--primary-color), transparent 92%);
}
.attention{
border-radius: 1.25rem;
border: 1px solid color-mix(in srgb, var(--red-500), var(--surface-border) 45%);
background: color-mix(in srgb, var(--red-50), transparent 18%);
padding: 1rem 1rem .9rem;
}
.attention-title{
font-weight: 950;
color: color-mix(in srgb, var(--red-700), var(--text-color) 15%);
margin-bottom:.45rem;
}
.attention-list{
margin: 0;
padding-left: 1.1rem;
color: color-mix(in srgb, var(--red-900), var(--text-color) 25%);
}
.attention-list li{ margin:.35rem 0; }
.linklike{
cursor:pointer;
text-decoration: underline;
font-weight: 800;
}
.footer-actions{
display:flex;
justify-content:flex-end;
gap:.75rem;
flex-wrap:wrap;
}
</style>