<template>
    <div class="dp-page">
      
        <section class="dp-glass dp-toolbar">
            <div class="dp-toolbar-row">
                <span class="dp-field-label">
                    <el-icon><Calendar /></el-icon>
                    预约日期
                </span>
                <el-date-picker
                    v-model="dateRange"
                    type="daterange"
                    range-separator="—"
                    start-placeholder="开始"
                    end-placeholder="结束"
                    value-format="YYYY-MM-DD"
                    unlink-panels
                    class="dp-field-date"
                    @change="() => loadAppointments()"
                />
                <span class="dp-field-label">
                    <el-icon><Filter /></el-icon>
                    状态
                </span>
                <el-select
                    v-model="filters.status"
                    placeholder="全部"
                    clearable
                    class="dp-field-select"
                    @change="() => loadAppointments()"
                >
                    <el-option label="全部状态" value="" />
                    <el-option label="已预约（待就诊）" value="1" />
                    <el-option label="已完成" value="3" />
                    <el-option label="已过号" value="4" />
                </el-select>
                <span class="dp-field-label">
                    <el-icon><Search /></el-icon>
                    患者
                </span>
                <el-input
                    v-model="filters.patient_name"
                    placeholder="姓名"
                    clearable
                    class="dp-field-search"
                    @keyup.enter="() => loadAppointments()"
                />
                <div class="dp-toolbar-actions">
                    <el-button type="primary" :loading="loading" :icon="Search" @click="() => loadAppointments()">
                        查询
                    </el-button>
                    <el-button :icon="RefreshRight" @click="resetFilters">重置</el-button>
                </div>
            </div>
        </section>

        <section v-if="doctors.length" class="dp-glass dp-doc-section">
            <div class="dp-section-head">
                <el-icon class="dp-section-icon"><User /></el-icon>
                <span class="dp-section-title">选择医生</span>
                <span class="dp-section-hint">切换后自动加载该医生挂号</span>
            </div>
            <el-radio-group
                v-model="selectedDoctorId"
                class="dp-doc-pills"
                @change="() => loadAppointments()"
            >
                <el-radio-button
                    v-for="d in doctors"
                    :key="d.id"
                    :label="Number(d.id)"
                    class="dp-doc-pill"
                >
                    {{ d.name || d.account || '—' }}
                </el-radio-button>
            </el-radio-group>
        </section>

        <section class="dp-glass dp-table-wrap" v-loading="loading">
            <div class="dp-table-head">
                <div class="dp-table-head-left">
                    <span class="dp-table-title">患者列表</span>
                    <span v-if="dateRange?.length === 2" class="dp-table-range">{{ dateRange[0] }} ~ {{ dateRange[1] }}</span>
                </div>
                <div class="dp-table-badges">
                    <span v-if="currentAccountLabel" class="dp-chip dp-chip--account">当前账号 {{ currentAccountLabel }}</span>
                    <span v-if="currentDoctorName" class="dp-chip dp-chip--doc">{{ currentDoctorName }}</span>
                    <span v-if="selectedDoctorId !== undefined && !loading" class="dp-chip dp-chip--count">{{ displayRows.length }} 人</span>
                    <span v-if="hiddenCompletedCount > 0" class="dp-chip dp-chip--muted">已隐藏已完成 {{ hiddenCompletedCount }}</span>
                </div>
            </div>
            <el-empty v-if="!doctors.length" description="暂无医生数据" />
            <el-empty v-else-if="selectedDoctorId === undefined" description="请选择医生" />
            <el-table
                v-else
                :data="displayRows"
                class="dp-table"
                size="default"
                :empty-text="tableEmptyText"
            >
                <el-table-column label="患者" min-width="200" fixed="left">
                    <template #default="{ row }">
                        <div class="dp-cell-user" :class="{ 'is-my-patients': isMyAssistantPatient(row) }">
                            <template v-if="isMyAssistantPatient(row)">
                                <div class="dp-my-patients-caption">我的患者</div>
                                <div class="dp-my-patients-eta">{{ assistantVisitEtaText(row) }}</div>
                            </template>
                            <div class="dp-cell-user-body">
                                <div class="dp-avatar">{{ patientInitial(row.patient_name) }}</div>
                                <div class="dp-user-meta">
                                    <span class="dp-user-name">{{ row.patient_name || '—' }}</span>
                                    <span class="dp-user-phone">{{ row.patient_phone || '—' }}</span>
                                </div>
                            </div>
                        </div>
                    </template>
                </el-table-column>
                <el-table-column label="预约时间" width="170">
                    <template #default="{ row }">
                        <span class="dp-time">{{ formatApptTime(row) }}</span>
                    </template>
                </el-table-column>
                <el-table-column label="挂号" width="104" align="center">
                    <template #default="{ row }">
                        <el-tag :type="appointmentTagType(row.status)" effect="light" round size="small">
                            {{ row.status_desc }}
                        </el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="面诊进度" min-width="360">
                    <template #default="{ row }">
                        <div class="dp-steps">
                            <template v-for="(s, i) in buildSteps(row)" :key="i">
                                <div
                                    class="dp-step"
                                    :class="{ 'is-done': s.done, 'is-current': s.current && !s.done }"
                                >
                                    <div class="dp-step-dot">{{ i + 1 }}</div>
                                    <div class="dp-step-text">
                                        <span class="dp-step-name">{{ s.label }}</span>
                                        <span v-if="s.hint" class="dp-step-hint">{{ s.hint }}</span>
                                    </div>
                                </div>
                                <div v-if="i < 3" class="dp-step-line" :class="{ 'is-done': s.done }" />
                            </template>
                        </div>
                        <el-progress :percentage="progressPercent(row)" :stroke-width="8" class="dp-progress" />
                    </template>
                </el-table-column>
                <el-table-column label="处方" width="92" align="center">
                    <template #default="{ row }">
                        <el-tag v-if="row.has_prescription" type="success" effect="dark" round size="small">已开</el-tag>
                        <span v-else class="dp-muted">未开</span>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="96" fixed="right" align="center">
                    <template #default="{ row }">
                        <el-button
                            v-if="row.diagnosis_id"
                            type="primary"
                            size="small"
                            round
                            plain
                            @click="goDiagnosis(row.diagnosis_id)"
                        >
                            诊单
                        </el-button>
                        <span v-else class="dp-muted">—</span>
                    </template>
                </el-table-column>
            </el-table>
        </section>
    </div>
</template>

<script setup lang="ts" name="doctorProgress">
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import dayjs from 'dayjs'
import { Calendar, Filter, List, QuestionFilled, RefreshRight, Search, User } from '@element-plus/icons-vue'
import { appointmentLists, doctorLists } from '@/api/doctor'
import useUserStore from '@/stores/modules/user'

const router = useRouter()
const userStore = useUserStore()
const loading = ref(false)
const doctors = ref<any[]>([])
/** 当前选中医师（与排班页「选择医生」一致的横向单选） */
const selectedDoctorId = ref<number | undefined>(undefined)
const tableRows = ref<any[]>([])

const todayStr = () => dayjs().format('YYYY-MM-DD')
const dateRange = ref<[string, string]>([todayStr(), todayStr()])

const filters = reactive({
    status: '' as string,
    patient_name: ''
})

const currentDoctorName = computed(() => {
    const id = selectedDoctorId.value
    if (id === undefined) return ''
    const d = doctors.value.find((x) => Number(x.id) === id)
    return d ? String(d.name || d.account || '') : ''
})

const currentAdminId = computed(() => {
    const id = userStore.userInfo?.id
    return id != null && id !== '' ? Number(id) : NaN
})

const currentAccountLabel = computed(() => {
    const u = userStore.userInfo || {}
    return String(u.name || u.account || '').trim()
})

/** 诊单上的医助与当前登录账号一致时显示「我的患者」（医助视角） */
function isMyAssistantPatient(row: any) {
    const me = currentAdminId.value
    if (Number.isNaN(me)) return false
    const aid = row?.assistant_id
    if (aid == null || aid === '') return false
    return Number(aid) === me
}

/** 粗估每位待就诊患者占用时长（分钟），用于候诊顺序预估 */
const AVG_MINUTES_PER_VISIT = 15

/** 触发接诊预估文案随时间刷新（与列表静默刷新互补） */
const etaClock = ref(0)
let etaTickTimer: ReturnType<typeof setInterval> | null = null

function apptTimeSortKey(row: any) {
    const d = String(row.appointment_date || '')
    let t = row.appointment_time || ''
    if (typeof t === 'string' && t.length > 5) {
        t = t.slice(0, 5)
    }
    return `${d} ${t}`.trim()
}

function parseApptSlot(row: any) {
    const d = row.appointment_date
    if (!d) return null
    let t = row.appointment_time || '00:00'
    if (typeof t === 'string' && t.length > 5) {
        t = t.slice(0, 5)
    }
    const parsed = dayjs(`${d} ${t}`)
    return parsed.isValid() ? parsed : null
}

function formatWaitMinutes(totalMin: number) {
    const m = Math.max(0, Math.round(totalMin))
    if (m === 0) return '不到 1 分钟'
    if (m < 60) return `${m} 分钟`
    const h = Math.floor(m / 60)
    const mm = m % 60
    if (mm === 0) return `${h} 小时`
    return `${h} 小时${mm} 分钟`
}

/**
 * 医助「我的患者」接诊预估：医生在挂号上点「完成」即面诊结束（status=3）。
 * 待就诊：按当日同医生、待就诊列表的排序位次粗估；若预约时段未到会合并提示。
 */
function assistantVisitEtaText(row: any) {
    void etaClock.value
    if (!isMyAssistantPatient(row)) return ''
    const st = Number(row.status)
    if (st === 3) {
        return '面诊已完成（医生已点完成）'
    }
    if (st === 4) {
        return '已过号，无法按序预估'
    }
    if (st !== 1) {
        return ''
    }

    const now = dayjs()
    const slot = parseApptSlot(row)
    const slotAfterNow = slot ? slot.isAfter(now) : false
    const untilSlotMin = slotAfterNow && slot ? Math.max(0, slot.diff(now, 'minute')) : 0

    const pendingSameDay = tableRows.value
        .filter((r) => r.appointment_date === row.appointment_date && Number(r.status) === 1)
        .slice()
        .sort((a, b) => {
            const c = apptTimeSortKey(a).localeCompare(apptTimeSortKey(b))
            if (c !== 0) return c
            return Number(a.id) - Number(b.id)
        })

    const idx = pendingSameDay.findIndex((r) => Number(r.id) === Number(row.id))
    const ahead = idx >= 0 ? idx : 0
    const queueMin = ahead * AVG_MINUTES_PER_VISIT

    const parts: string[] = []
    if (slotAfterNow) {
        parts.push(`距预约时段还有约 ${formatWaitMinutes(untilSlotMin)}`)
    }
    if (ahead === 0) {
        parts.push(slotAfterNow ? '到号后可优先安排面诊' : '已到号，可尽快面诊')
    } else {
        parts.push(`前面约 ${ahead} 人，按序粗估约 ${formatWaitMinutes(queueMin)}`)
    }
    return parts.join('；')
}

/** 未指定具体状态时视为「全部」，此时隐藏挂号「已完成」 */
function isBroadStatusFilter() {
    const s = filters.status as string | undefined | null
    return s === '' || s === undefined || s === null
}

/** 「全部状态」时默认不展示挂号已完成，便于看板聚焦进行中 */
const hiddenCompletedCount = computed(() => {
    if (!isBroadStatusFilter()) return 0
    return tableRows.value.filter((r) => Number(r.status) === 3).length
})

const displayRows = computed(() => {
    if (!isBroadStatusFilter()) {
        return tableRows.value
    }
    return tableRows.value.filter((r) => Number(r.status) !== 3)
})

const tableEmptyText = computed(() => {
    if (hiddenCompletedCount.value > 0 && displayRows.value.length === 0) {
        return `本时段有 ${hiddenCompletedCount.value} 条「已完成」已隐藏，可在状态中选择「已完成」查看`
    }
    return '该时段内暂无挂号'
})

function patientInitial(name: unknown) {
    const s = String(name || '?').trim()
    return s ? s[0] : '?'
}

function formatApptTime(row: any) {
    const d = row.appointment_date || ''
    let t = row.appointment_time || ''
    if (typeof t === 'string' && t.length > 5) {
        t = t.slice(0, 5)
    }
    return d ? `${d} ${t}`.trim() : '—'
}

function appointmentTagType(status: number) {
    if (status === 3) return 'success'
    if (status === 4) return 'warning'
    if (status === 2) return 'info'
    return 'primary'
}

/** 面诊进度四步：挂号有效 → 诊单已确认 → 已完诊 → 已开方（开方=今日已创建处方，见 prescription_today_only） */
function buildSteps(row: any) {
    const cancelled = Number(row.status) === 2
    const regOk = !cancelled && [1, 3, 4].includes(Number(row.status))
    const confirmed = !!row.diagnosis_confirmed
    const visitDone = Number(row.status) === 3
    const rx = !!row.has_prescription

    const steps = [
        {
            label: '挂号',
            done: regOk,
            current: regOk && !confirmed && Number(row.status) === 1,
            hint: cancelled ? '已取消' : Number(row.status) === 4 ? '已过号' : ''
        },
        {
            label: '确认诊单',
            done: confirmed,
            current: regOk && !confirmed,
            hint: ''
        },
        {
            label: '就诊中',
            done: visitDone,
            current: regOk && confirmed && !visitDone && Number(row.status) === 1,
            hint: Number(row.status) === 1 && confirmed ? '待完诊' : ''
        },
        {
            label: '开方',
            done: rx,
            current: visitDone && !rx,
            hint: ''
        }
    ]
    return steps
}

function progressPercent(row: any) {
    const steps = buildSteps(row)
    const n = steps.filter((s) => s.done).length
    return Math.round((n / 4) * 100)
}

/** 单次请求最大条数（避免 page_type=0 一次拉全表导致服务端 500/超时） */
const APPOINT_PAGE_SIZE = 2000
/** 自动刷新间隔（毫秒） */
const AUTO_REFRESH_MS = 15_000

let autoRefreshTimer: ReturnType<typeof setInterval> | null = null

async function loadDoctors() {
    const res = await doctorLists({
        role_id: 1,
        page_type: 0,
        page_no: 1,
        /** 仅登录即可拉取，不依赖菜单权限（与接口 progress_board 约定一致） */
        progress_board: 1
    })
    doctors.value = res?.lists || []
    if (!doctors.value.length) {
        selectedDoctorId.value = undefined
        tableRows.value = []
        return
    }
    const valid = doctors.value.some((d) => Number(d.id) === selectedDoctorId.value)
    if (selectedDoctorId.value === undefined || !valid) {
        selectedDoctorId.value = Number(doctors.value[0].id)
    }
}

async function loadAppointments(opts?: { silent?: boolean }) {
    if (selectedDoctorId.value === undefined) {
        tableRows.value = []
        return
    }
    const silent = opts?.silent === true
    if (!silent) {
        loading.value = true
    }
    try {
        const params: Record<string, any> = {
            doctor_id: selectedDoctorId.value,
            page_type: 1,
            page_no: 1,
            page_size: APPOINT_PAGE_SIZE,
            /** 开方状态仅认「今日创建」的处方，避免历史处方误判进度 */
            prescription_today_only: 1,
            /** 本页不展示已取消挂号（status=2） */
            exclude_cancelled: 1,
            /** 不按医生/医助角色收窄数据；与接口免菜单权限约定一致 */
            progress_board: 1
        }
        if (dateRange.value?.length === 2) {
            params.start_date = dateRange.value[0]
            params.end_date = dateRange.value[1]
        }
        if (filters.status !== '') {
            params.status = filters.status
        }
        if (filters.patient_name?.trim()) {
            params.patient_name = filters.patient_name.trim()
        }
        const res = await appointmentLists(params)
        let list = res?.lists || []
        const total = Number(res?.count ?? list.length)
        if (total > list.length && list.length >= APPOINT_PAGE_SIZE) {
            const extra: any[] = []
            const pages = Math.min(Math.ceil(total / APPOINT_PAGE_SIZE), 20)
            for (let p = 2; p <= pages; p++) {
                const r = await appointmentLists({ ...params, page_no: p })
                const chunk = r?.lists || []
                if (!chunk.length) break
                extra.push(...chunk)
            }
            list = [...list, ...extra]
        }
        tableRows.value = [...list].sort((a, b) => {
            const da = `${a.appointment_date || ''} ${a.appointment_time || ''}`
            const db = `${b.appointment_date || ''} ${b.appointment_time || ''}`
            return da.localeCompare(db)
        })
    } catch (e) {
        console.error(e)
        if (!silent) {
            tableRows.value = []
        }
    } finally {
        if (!silent) {
            loading.value = false
        }
    }
}

function runAutoRefresh() {
    if (typeof document !== 'undefined' && document.hidden) {
        return
    }
    void loadAppointments({ silent: true }).catch(() => {})
}

function resetFilters() {
    filters.status = ''
    filters.patient_name = ''
    dateRange.value = [todayStr(), todayStr()]
    loadAppointments()
}

function goDiagnosis(diagnosisId: number) {
    router.push({ path: '/tcm/diagnosis', query: { id: String(diagnosisId) } })
}

onMounted(async () => {
    await loadDoctors()
    await loadAppointments()
    autoRefreshTimer = setInterval(runAutoRefresh, AUTO_REFRESH_MS)
    etaTickTimer = setInterval(() => {
        etaClock.value += 1
    }, 60_000)
})

onUnmounted(() => {
    if (autoRefreshTimer != null) {
        clearInterval(autoRefreshTimer)
        autoRefreshTimer = null
    }
    if (etaTickTimer != null) {
        clearInterval(etaTickTimer)
        etaTickTimer = null
    }
})
</script>

<style scoped lang="scss">
.dp-page {
    padding: 20px 24px 40px;
    min-height: 100%;
    box-sizing: border-box;
    background:
        radial-gradient(ellipse 120% 80% at 8% -15%, rgba(64, 158, 255, 0.12), transparent 52%),
        radial-gradient(ellipse 90% 55% at 96% 8%, rgba(103, 194, 58, 0.08), transparent 48%),
        linear-gradient(180deg, #f8fafc 0%, #eef2f7 45%, #e8edf4 100%);
}

.dp-hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 20px;
    padding: 2px 0;
}

.dp-hero-main {
    display: flex;
    align-items: center;
    gap: 16px;
    min-width: 0;
}

.dp-hero-badge {
    width: 52px;
    height: 52px;
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
    color: #fff;
    box-shadow: 0 8px 28px rgba(64, 158, 255, 0.32);
}

.dp-hero-title {
    margin: 0 0 6px;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--el-text-color-primary);
}

.dp-hero-sub {
    margin: 0;
    font-size: 14px;
    color: var(--el-text-color-secondary);
}

.dp-hero-aside {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}

.dp-pulse {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.75);
    border: 1px solid var(--el-border-color-lighter);
    backdrop-filter: blur(8px);
    font-size: 12px;
    color: var(--el-text-color-secondary);
}

.dp-pulse-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--el-color-success);
    box-shadow: 0 0 0 3px var(--el-color-success-light-8);
    animation: dp-pulse 2.2s ease-in-out infinite;
}

@keyframes dp-pulse {
    0%,
    100% {
        opacity: 1;
        transform: scale(1);
    }
    50% {
        opacity: 0.72;
        transform: scale(0.9);
    }
}

.dp-icon-btn {
    border: 1px solid var(--el-border-color-lighter);
}

.dp-tip-lines {
    max-width: 280px;
    line-height: 1.6;
    font-size: 13px;
}

.dp-glass {
    background: rgba(255, 255, 255, 0.86);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 255, 255, 0.95);
    border-radius: 16px;
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 14px 44px -14px rgba(15, 23, 42, 0.14);
    margin-bottom: 16px;
}

.dp-toolbar {
    padding: 16px 20px;
}

.dp-toolbar-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 16px;
}

.dp-field-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 500;
    color: var(--el-text-color-secondary);
    flex-shrink: 0;
}

.dp-field-date {
    width: 260px;
}

.dp-field-select {
    width: 168px;
}

.dp-field-search {
    width: 140px;
}

.dp-toolbar-actions {
    margin-left: auto;
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.dp-doc-section {
    padding: 14px 18px 18px;
}

.dp-section-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}

.dp-section-icon {
    color: var(--el-color-primary);
}

.dp-section-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--el-text-color-primary);
}

.dp-section-hint {
    font-size: 12px;
    color: var(--el-text-color-placeholder);
}

.dp-doc-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    width: 100%;
}

.dp-doc-pills :deep(.el-radio-button__inner) {
    border-radius: 10px !important;
    border: 1px solid var(--el-border-color-lighter);
    padding: 8px 16px;
    font-weight: 500;
    box-shadow: none;
}

.dp-doc-pills :deep(.el-radio-button.is-active .el-radio-button__inner) {
    background: linear-gradient(135deg, var(--el-color-primary-light-3), var(--el-color-primary)) !important;
    border-color: transparent !important;
    color: #fff !important;
    box-shadow: 0 4px 14px rgba(64, 158, 255, 0.32);
}

.dp-table-wrap {
    padding: 0;
    overflow: hidden;
}

.dp-table-wrap :deep(.el-loading-mask) {
    border-radius: 16px;
}

.dp-table-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px 12px;
    border-bottom: 1px solid var(--el-border-color-extra-light);
    flex-wrap: wrap;
    gap: 10px;
}

.dp-table-head-left {
    display: flex;
    align-items: baseline;
    gap: 12px;
    flex-wrap: wrap;
}

.dp-table-title {
    font-size: 17px;
    font-weight: 700;
    color: var(--el-text-color-primary);
}

.dp-table-range {
    font-size: 13px;
    color: var(--el-text-color-secondary);
}

.dp-table-badges {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.dp-chip {
    font-size: 12px;
    padding: 4px 10px;
    border-radius: 999px;
    font-weight: 500;
}

.dp-chip--account {
    background: var(--el-fill-color-blank);
    color: var(--el-text-color-regular);
    border: 1px solid var(--el-border-color-lighter);
}

.dp-chip--doc {
    background: var(--el-color-primary-light-9);
    color: var(--el-color-primary);
    border: 1px solid var(--el-color-primary-light-5);
}

.dp-chip--count {
    background: var(--el-fill-color-light);
    color: var(--el-text-color-secondary);
    border: 1px solid var(--el-border-color-lighter);
}

.dp-chip--muted {
    background: transparent;
    color: var(--el-text-color-placeholder);
    border: 1px dashed var(--el-border-color);
    font-weight: 400;
}

.dp-table {
    width: 100%;
    --el-table-border-color: var(--el-border-color-extra-light);
}

.dp-table :deep(.el-table__header th) {
    background: var(--el-fill-color-light) !important;
    font-weight: 600;
    font-size: 13px;
}

.dp-table :deep(.el-table__body tr:hover > td) {
    background: var(--el-fill-color-lighter) !important;
}

.dp-cell-user {
    display: flex;
    align-items: center;
    gap: 12px;
}

.dp-cell-user.is-my-patients {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
}

.dp-my-patients-caption {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--el-color-primary);
    line-height: 1.2;
}

.dp-my-patients-eta {
    font-size: 11px;
    line-height: 1.45;
    color: var(--el-text-color-secondary);
    max-width: 220px;
}

.dp-cell-user-body {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.dp-avatar {
    width: 40px;
    height: 40px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    font-weight: 700;
    color: #fff;
    background: linear-gradient(145deg, #6366f1 0%, #8b5cf6 100%);
    flex-shrink: 0;
}

.dp-user-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.dp-user-name {
    font-weight: 600;
    color: var(--el-text-color-primary);
}

.dp-user-phone {
    font-size: 12px;
    color: var(--el-text-color-secondary);
}

.dp-time {
    font-variant-numeric: tabular-nums;
    font-size: 13px;
    color: var(--el-text-color-regular);
}

.dp-steps {
    display: flex;
    align-items: center;
    gap: 0;
    margin-bottom: 10px;
    max-width: 500px;
}

.dp-step {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 6px;
    padding: 6px 2px;
}

.dp-step-dot {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    color: var(--el-text-color-secondary);
    background: var(--el-fill-color);
    border: 2px solid var(--el-border-color);
}

.dp-step.is-done .dp-step-dot {
    background: var(--el-color-success);
    border-color: var(--el-color-success);
    color: #fff;
}

.dp-step.is-current:not(.is-done) .dp-step-dot {
    border-color: var(--el-color-primary);
    color: var(--el-color-primary);
    background: var(--el-color-primary-light-9);
    box-shadow: 0 0 0 3px var(--el-color-primary-light-8);
}

.dp-step-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.dp-step-name {
    font-size: 12px;
    font-weight: 600;
    color: var(--el-text-color-primary);
}

.dp-step-hint {
    font-size: 11px;
    color: var(--el-text-color-placeholder);
    line-height: 1.3;
}

.dp-step-line {
    flex: 0 0 14px;
    height: 2px;
    background: var(--el-border-color);
    border-radius: 1px;
    align-self: center;
}

.dp-step-line.is-done {
    background: linear-gradient(90deg, var(--el-color-success-light-5), var(--el-color-success));
}

.dp-progress {
    max-width: 420px;

    :deep(.el-progress-bar__outer) {
        border-radius: 999px;
        overflow: hidden;
    }

    :deep(.el-progress__text) {
        font-size: 12px !important;
        min-width: 36px;
    }
}

.dp-muted {
    font-size: 13px;
    color: var(--el-text-color-placeholder);
}
</style>
