<template>
  <el-dialog
    :visible.sync="visibleProxy"
    :show-close="false"
    width="90%"
    :close-on-click-modal="false"
    custom-class="booking-calendar-dialog"
    append-to-body
  >
    <div class="dialog-inner">
      <div class="dialog-header">
        <div class="dialog-title">预约日历</div>
        <span class="dialog-close" @click="visibleProxy = false"><i class="el-icon-close"></i></span>
      </div>

      <div class="dialog-search">
        <el-form @submit.native.prevent :inline="true" size="small">
          <el-form-item label="预约状态">
            <el-select v-model="query.status" placeholder="预约状态" clearable style="width:160px">
              <el-option label="已预约" value="booked" />
              <el-option label="服务中" value="serving" />
              <el-option label="已完成" value="converted" />
              <el-option label="已取消" value="cancelled" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="search">查询</el-button>
            <el-button @click="reset">重置</el-button>
          </el-form-item>
        </el-form>
      </div>

      <div class="dialog-content" v-loading="loading">
        <FullCalendar
          ref="fullCalendar"
          class="store-calendar"
          defaultView="dayGridMonth"
          :header="calendarHeader"
          :plugins="calendarPlugins"
          :weekends="true"
          :events="calendarEvents"
          locale="zh-cn"
          :buttonText="buttonText"
          :height="calendarHeight"
          :eventLimit="true"
          allDayText="全天"
          :editable="false"
          :dayRender="onDayRender"
          @datesRender="datesRender"
          @dateClick="handleDateClick"
          @eventClick="handleEventClick"
        />
      </div>
    </div>

    <booking-consume-dialog
      :visible.sync="consumeVisible"
      :prefill="consumePrefill"
      @saved="handleConsumeSaved"
    />
    <booking-consume-detail-dialog
      :visible.sync="detailVisible"
      :booking="selectedBooking"
      @cancel="handleDetailCancel"
      @edit="handleDetailEdit"
      @start="handleDetailStart"
      @convert="handleDetailConvert"
    />
  </el-dialog>
</template>

<script>
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'
import BookingConsumeDialog from '@/components/booking-consume-dialog.vue'
import BookingConsumeDetailDialog from '@/components/booking-consume-detail-dialog.vue'

const STORAGE_KEY = 'store_pc_pre_consume_bookings'

export default {
  name: 'BookingCalendarDialog',
  components: { FullCalendar, BookingConsumeDialog, BookingConsumeDetailDialog },
  props: { visible: { type: Boolean, default: false } },
  data() {
    return {
      loading: false,
      query: { status: undefined },
      calendarPlugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
      calendarEvents: [],
      calendarHeader: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay' },
      buttonText: { today: '今日', month: '月', week: '周', day: '日' },
      startTime: null,
      endTime: null,
      calendarHeight: 600,
      consumeVisible: false,
      consumePrefill: {},
      detailVisible: false,
      selectedBooking: null,
      bookingList: [],
      bookingByDate: {}
    }
  },
  computed: {
    visibleProxy: {
      get() { return this.visible },
      set(v) { this.$emit('update:visible', v) }
    }
  },
  watch: {
    visible(v) {
      if (v) {
        this.setCurrentMonthRange()
        this.refreshBookingDataSync()
        this._installBookingItemClickGuard()
        this.$nextTick(() => {
          this.calcHeight()
          this.initData()
        })
        this._clearFirstOpenTimers()
        const delays = [150, 300, 500, 800]
        delays.forEach((ms, i) => {
          const t = setTimeout(() => {
            if (!this.visibleProxy) return
            this.refreshBookingDataSync()
            this.patchAllCells()
          }, ms)
          if (!this._firstOpenPatchTimers) this._firstOpenPatchTimers = []
          this._firstOpenPatchTimers.push(t)
        })
      } else {
        this._clearFirstOpenTimers()
        this._removeBookingItemClickGuard()
      }
    }
  },
  mounted() {
    window.addEventListener('resize', this.calcHeight)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.calcHeight)
    this._clearFirstOpenTimers()
    this._removeBookingItemClickGuard()
  },
  methods: {
    readStorage() {
      try {
        const raw = localStorage.getItem(STORAGE_KEY)
        if (!raw) return []
        const arr = JSON.parse(raw)
        return Array.isArray(arr) ? arr : []
      } catch (e) {
        return []
      }
    },
    writeStorage(list) {
      try {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(list || []))
      } catch (e) {}
    },
    buildDemoDataForCalendar(visibleMonthDate) {
      // 必须按“当前日历可见月份”生成示例，不能用 activeStart（月视图可能是上月末尾）
      // 优先用传入的可见月基准日，否则 api.getDate()，再否则 startTime/endTime 中点
      let base = visibleMonthDate instanceof Date ? visibleMonthDate : null
      if (!base) {
        const api = this.$refs.fullCalendar && this.$refs.fullCalendar.getApi && this.$refs.fullCalendar.getApi()
        base = api && api.getDate ? api.getDate() : null
      }
      if (!base) {
        const s = this.startTime instanceof Date ? this.startTime.getTime() : null
        const e = this.endTime instanceof Date ? this.endTime.getTime() : null
        base = (s && e) ? new Date((s + e) / 2) : new Date()
      }
      const y = base.getFullYear()
      const m = base.getMonth() + 1
      const mm = String(m).padStart(2, '0')
      const d8 = `${y}-${mm}-08`
      const d9 = `${y}-${mm}-09`
      const mk = (id, date, startTime, endTime, memberName, roomName, status, therapistIds, items) => ({
        id,
        memberId: 'cust_demo',
        memberName,
        date,
        startTime,
        endTime,
        roomId: 'R001',
        roomName,
        therapistIds,
        therapistNames: [],
        status,
        colorKey: 'blue',
        remark: '',
        items: items || [],
        itemLabels: (items || []).map(x => `${x.label}×${x.count || 1}`)
      })
      return [
        mk(
          `PCB_DEMO_${d8}_01`,
          d8,
          '09:00',
          '10:30',
          '林小纤',
          '1号房',
          'booked',
          ['E001', 'E002'],
          [
            { projectId: 'item001', label: '面部深层护理（次卡）', count: 1, workers: [{ workerId: 'E001' }] },
            { projectId: 'item003', label: '眼周护理套餐', count: 1, workers: [{ workerId: 'E002' }] }
          ]
        ),
        mk(
          `PCB_DEMO_${d8}_02`,
          d8,
          '14:00',
          '15:30',
          '王丽',
          'VIP房',
          'serving',
          ['E001'],
          [{ projectId: 'item002', label: '肩颈调理（疗程）', count: 2, workers: [{ workerId: 'E001' }] }]
        ),
        mk(
          `PCB_DEMO_${d9}_01`,
          d9,
          '11:00',
          '12:00',
          '张敏',
          '2号房',
          'converted',
          ['E004'],
          [{ projectId: 'item001', label: '面部深层护理（次卡）', count: 1, workers: [{ workerId: 'E004' }] }]
        )
      ]
    },
    esc(s) {
      return String(s == null ? '' : s)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
    },
    formatDate(d) {
      const dt = d instanceof Date ? d : new Date(d)
      const y = dt.getFullYear()
      const m = String(dt.getMonth() + 1).padStart(2, '0')
      const day = String(dt.getDate()).padStart(2, '0')
      return `${y}-${m}-${day}`
    },
    statusText(status) {
      if (status === 'booked') return '已预约'
      if (status === 'serving') return '服务中'
      if (status === 'converted') return '已完成'
      if (status === 'cancelled') return '已取消'
      return '无'
    },
    statusColor(status) {
      if (status === 'booked') return '#409EFF'
      if (status === 'serving') return '#67C23A'
      if (status === 'converted') return '#909399'
      if (status === 'cancelled') return '#F56C6C'
      return '#909399'
    },
    calcHeight() {
      this.$nextTick(() => {
        const el = this.$el && this.$el.querySelector('.dialog-content')
        if (el) {
          this.calendarHeight = Math.max(el.clientHeight - 20, 500)
        }
      })
    },
    onDayRender(info) {
      const dateStr = this.formatDate(info.date)
      const frame = info.el && (info.el.querySelector('.fc-daygrid-day-frame') || info.el.querySelector('.fc-daygrid-day-events') || info.el)
      if (!frame) return
      let mount = frame.querySelector('.pc-booking-mount')
      if (!mount) {
        mount = document.createElement('div')
        mount.className = 'pc-booking-mount'
        frame.appendChild(mount)
      }
      mount.innerHTML = this.renderDayCell(dateStr)
    },
    datesRender(info) {
      const view = info.view
      this.startTime = view.activeStart
      this.endTime = view.activeEnd
      this.refreshBookingDataSync()
      this.initData()
    },
    getCalendarRoot() {
      // append-to-body 时日历在 document.body，优先从 document 查找
      const fromDoc = document.querySelector('.booking-calendar-dialog .store-calendar')
      return fromDoc || (this.$el && this.$el.querySelector('.store-calendar')) || null
    },
    getVisibleMonthDate() {
      if (this.startTime && this.endTime) {
        const mid = (this.startTime.getTime() + this.endTime.getTime()) / 2
        return new Date(mid)
      }
      return new Date()
    },
    refreshBookingDataSync() {
      const visibleMonth = this.getVisibleMonthDate()
      let list = this.readStorage()
      if (!list || list.length === 0) {
        list = this.buildDemoDataForCalendar(visibleMonth)
        this.writeStorage(list)
      }
      if (this.query.status) list = list.filter(r => r && r.status === this.query.status)
      if (this.startTime && this.endTime) {
        const start = this.startTime.getTime()
        const end = this.endTime.getTime()
        list = list.filter(r => {
          const d = r && r.date ? new Date(r.date) : null
          if (!d || Number.isNaN(d.getTime())) return false
          const t = d.getTime()
          return t >= start && t < end
        })
        if (list.length === 0) {
          const existing = this.readStorage()
          const demo = this.buildDemoDataForCalendar(visibleMonth)
          const y = visibleMonth.getFullYear()
          const m = visibleMonth.getMonth()
          const monthStart = new Date(y, m, 1).getTime()
          const monthEnd = new Date(y, m + 1, 0, 23, 59, 59, 999).getTime()
          const outside = (existing || []).filter(r => {
            const t = r && r.date ? new Date(r.date).getTime() : NaN
            return Number.isNaN(t) || t < monthStart || t > monthEnd
          })
          this.writeStorage([...outside, ...demo])
          list = demo
          if (this.query.status) list = list.filter(r => r && r.status === this.query.status)
        }
      }
      this.bookingList = list
      const map = {}
      list.forEach(r => {
        const key = r && r.date ? r.date : ''
        if (!key) return
        if (!map[key]) map[key] = []
        map[key].push(r)
      })
      Object.keys(map).forEach(k => {
        map[k] = map[k].slice().sort((a, b) => {
          const at = (a && a.startTime) || ''
          const bt = (b && b.startTime) || ''
          return String(at).localeCompare(String(bt))
        })
      })
      this.bookingByDate = map
      this.calendarEvents = list.map(item => {
        const dateStr = item.date || this.formatDate(new Date())
        const start = item.startTime ? `${dateStr}T${item.startTime}:00` : `${dateStr}T00:00:00`
        const end = item.endTime ? `${dateStr}T${item.endTime}:00` : start
        return {
          id: item.id,
          title: '',
          start,
          end,
          color: 'transparent',
          textColor: 'transparent',
          classNames: ['pc-booking-hidden-event'],
          editable: false,
          allDay: false
        }
      })
    },
    _clearFirstOpenTimers() {
      if (this._firstOpenPatchTimers && this._firstOpenPatchTimers.length) {
        this._firstOpenPatchTimers.forEach(t => clearTimeout(t))
        this._firstOpenPatchTimers = []
      }
    },
    setCurrentMonthRange() {
      const now = new Date()
      const y = now.getFullYear()
      const m = now.getMonth()
      this.startTime = new Date(y, m, 1, 0, 0, 0, 0)
      this.endTime = new Date(y, m + 1, 0, 23, 59, 59, 999)
    },
    initData() {
      this.loading = true
      const run = () => {
        this.refreshBookingDataSync()
        this.loading = false
        this.$nextTick(() => {
          this.installDayCellRenderer()
          this.patchAllCells()
          const api = this.$refs.fullCalendar && this.$refs.fullCalendar.getApi && this.$refs.fullCalendar.getApi()
          api && api.rerenderDates && api.rerenderDates()
          this.$nextTick(() => { this.patchAllCells() })
          setTimeout(() => { this.patchAllCells() }, 150)
        })
      }
      // append-to-body 时 FullCalendar DOM 稍晚就绪，用 250ms 保证 getCalendarRoot/patchAllCells 能拿到日格
      const delay = this.startTime && this.endTime ? 250 : 400
      setTimeout(run, delay)
    },
    _installBookingItemClickGuard() {
      this._removeBookingItemClickGuard()
      if (this._pcBookingGuardInstalled) return
      const handler = (e) => {
        if (!this.visibleProxy) return
        const target = e.target
        if (!target || typeof target.closest !== 'function') return
        const itemEl = target.closest('.pc-booking-item')
        if (!itemEl) return
        const dialog = target.closest('.booking-calendar-dialog')
        if (!dialog) return
        e.preventDefault()
        e.stopPropagation()
        const id = itemEl.getAttribute('data-id')
        const rec = (this.bookingList || []).find(x => x && x.id === id)
        if (rec) {
          this.selectedBooking = { ...rec }
          this.detailVisible = true
        }
      }
      document.addEventListener('click', handler, true)
      this._pcBookingGuardHandler = handler
      this._pcBookingGuardTarget = document
      this._pcBookingGuardInstalled = true
    },
    _removeBookingItemClickGuard() {
      if (this._pcBookingGuardTarget && this._pcBookingGuardHandler) {
        this._pcBookingGuardTarget.removeEventListener('click', this._pcBookingGuardHandler, true)
        this._pcBookingGuardTarget = null
        this._pcBookingGuardHandler = null
      }
      this._pcBookingGuardInstalled = false
    },
    installDayCellRenderer() {
      const root = this.getCalendarRoot()
      if (!root) return
      if (this._pcBookingDelegationInstalled) return
      this._pcBookingDelegationInstalled = true

      // 监听 FullCalendar 月视图切换导致的 DOM 变动，及时重绘日格摘要
      this._pcBookingMutation && this._pcBookingMutation.disconnect && this._pcBookingMutation.disconnect()
      this._pcBookingMutation = new MutationObserver(() => {
        this.patchAllCells()
      })
      this._pcBookingMutation.observe(root, { childList: true, subtree: true })
    },
    renderDayCell(dateStr) {
      const list = (this.bookingByDate && this.bookingByDate[dateStr]) ? this.bookingByDate[dateStr] : []
      const total = list.length
      if (!total) return ''

      const maxShow = 2
      const showList = list.slice(0, maxShow)
      const rest = total - showList.length
      const itemsHtml = showList.map(r => {
        const time = `${this.esc(r.startTime || '')}-${this.esc(r.endTime || '')}`.replace(/^-|-$/g, '')
        const member = this.esc(r.memberName || '无')
        const room = this.esc(r.roomName || '无')
        const stText = this.esc(this.statusText(r.status))
        const stColor = this.statusColor(r.status)
        const brief = [time, member, room, stText].filter(Boolean).join(' ')
        return `<div class="pc-booking-item" data-id="${this.esc(r.id)}">
          <span class="pc-booking-dot" style="background:${stColor}"></span>
          <span class="pc-booking-brief" title="${brief}">${brief}</span>
        </div>`
      }).join('')

      const moreHtml = rest > 0 ? `<div class="pc-booking-more">+${rest}</div>` : ''
      return `<div class="pc-booking-wrap">
        <div class="pc-booking-badge">${total}</div>
        <div class="pc-booking-list">${itemsHtml}${moreHtml}</div>
      </div>`
    },
    patchAllCells() {
      const root = this.getCalendarRoot()
      if (!root) return
      const cells = root.querySelectorAll('.fc-daygrid-day')
      cells.forEach(cell => {
        const dateStr = cell.getAttribute('data-date')
        if (!dateStr) return
        let mount = cell.querySelector('.pc-booking-mount')
        if (!mount) {
          // 不能挂在 day-top（高度小/可能 overflow），挂到 day-frame/事件容器里更稳定
          const top = cell.querySelector('.fc-daygrid-day-frame') ||
            cell.querySelector('.fc-daygrid-day-events') ||
            cell
          mount = document.createElement('div')
          mount.className = 'pc-booking-mount'
          top.appendChild(mount)
        }
        mount.innerHTML = this.renderDayCell(dateStr)
      })
    },
    handleDateClick(arg) {
      // 若点击的是预约条目，不打开新建预约，由 capture 层只打开详情
      if (arg && arg.jsEvent && arg.jsEvent.target && arg.jsEvent.target.closest && arg.jsEvent.target.closest('.pc-booking-item')) {
        return
      }
      // 点击空白日期格：打开新建预约，预填点击的日期
      const dateStr = arg && arg.date ? this.formatDate(arg.date) : this.formatDate(new Date())
      this.consumePrefill = { date: dateStr }
      this.consumeVisible = true
    },
    handleEventClick(arg) {
      // 点击日历上已有预约事件（透明占位）：打开预约详情
      const id = arg && arg.event ? arg.event.id : ''
      if (!id) return
      const rec = (this.bookingList || []).find(x => x && x.id === id)
      if (!rec) return
      this.selectedBooking = { ...rec }
      this.detailVisible = true
    },
    handleConsumeSaved() {
      this.consumeVisible = false
      this.initData()
    },
    handleDetailCancel(b) {
      if (!b) return
      this.$confirm(`确定取消「${b.memberName || '该会员'}」在 ${b.date} ${b.startTime || ''}-${b.endTime || ''} 的预约吗？`, '取消预约确认', {
        confirmButtonText: '确定',
        cancelButtonText: '再想想',
        type: 'warning'
      }).then(() => {
        this.updateBookingInStorage(b.id, { ...b, status: 'cancelled' })
        this.detailVisible = false
        this.selectedBooking = null
        this.initData()
        this.$message.success('已取消预约')
      }).catch(() => {})
    },
    handleDetailEdit(b) {
      if (!b) return
      this.consumePrefill = { ...b }
      this.detailVisible = false
      this.$nextTick(() => {
        this.consumeVisible = true
      })
    },
    handleDetailStart(b) {
      if (!b) return
      this.updateBookingInStorage(b.id, { ...b, status: 'serving' })
      this.selectedBooking = { ...this.selectedBooking, status: 'serving' }
      this.initData()
      this.$message.success('已开始服务')
    },
    handleDetailConvert(b) {
      if (!b) return
      this.updateBookingInStorage(b.id, { ...b, status: 'converted' })
      this.detailVisible = false
      this.selectedBooking = null
      this.initData()
      this.$message.success('已转消耗开单')
    },
    updateBookingInStorage(id, updated) {
      const list = this.readStorage()
      const idx = list.findIndex(x => x && x.id === id)
      if (idx >= 0) {
        list[idx] = { ...list[idx], ...updated }
        this.writeStorage(list)
      }
    },
    search() { this.initData() },
    reset() { this.query.status = undefined; this.initData() }
  }
}
</script>

<style lang="scss">
@import '~@fullcalendar/core/main.css';
@import '~@fullcalendar/daygrid/main.css';
@import '~@fullcalendar/timegrid/main.css';

.booking-calendar-dialog .store-calendar {
  .fc-toolbar.fc-header-toolbar { padding: 16px 20px; margin-bottom: 0; border-bottom: 2px solid #f1f5f9; background: linear-gradient(135deg, rgba(59,130,246,0.02) 0%, rgba(96,165,250,0.02) 100%); }
  .fc-toolbar-title { font-size: 18px; font-weight: 700; color: #1e293b; }
  .fc-button-primary { background-color: #3b82f6; border-color: #3b82f6; border-radius: 10px; font-size: 13px; font-weight: 500; height: 34px; line-height: 34px; padding: 0 14px; transition: all 0.2s; &:hover { background: #2563eb; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(59,130,246,0.3); } }
  .fc-button-primary:not(:disabled):active, .fc-button-primary:not(:disabled).fc-button-active { background-color: #2563eb; border-color: #2563eb; box-shadow: 0 4px 12px rgba(59,130,246,0.3); }
  .fc-day-today { background: linear-gradient(135deg, rgba(59,130,246,0.05) 0%, rgba(96,165,250,0.05) 100%); .fc-daygrid-day-number { background: linear-gradient(135deg, #3b82f6, #2563eb); color: #fff; border-radius: 6px; box-shadow: 0 2px 8px rgba(59,130,246,0.3); } }
  .fc-event { cursor: pointer; border-radius: 6px; padding: 3px 6px; font-size: 12px; font-weight: 500; border: none; box-shadow: 0 2px 4px rgba(0,0,0,0.1); transition: all 0.2s; &:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); } }
  .fc-day-header { font-size: 14px !important; color: #64748b !important; font-weight: 700 !important; background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%) !important; border-bottom: 2px solid #e2e8f0 !important; padding: 12px 8px !important; }
  .fc-unthemed th, .fc-unthemed td { border-color: #f1f5f9; }
}

.booking-calendar-dialog .store-calendar {
  .pc-booking-hidden-event { display: none !important; }
  .pc-booking-mount {
    position: relative;
    margin: 4px 6px 0 4px;
    pointer-events: auto;
    z-index: 2;
  }
  .pc-booking-wrap { position: relative; }
  .pc-booking-badge {
    position: absolute;
    top: -2px;
    right: 6px;
    min-width: 16px;
    height: 16px;
    line-height: 16px;
    padding: 0 5px;
    border-radius: 999px;
    background: rgba(37, 99, 235, 0.12);
    color: #2563eb;
    font-size: 11px;
    font-weight: 700;
    text-align: center;
  }
  .pc-booking-list { margin-top: 18px; }
  .pc-booking-item {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 2px 0;
    padding: 2px 6px;
    border-radius: 8px;
    background: rgba(241, 245, 249, 0.55);
    cursor: pointer;
    user-select: none;
    transition: background 0.15s;
    &:hover { background: rgba(219, 234, 254, 0.8); }
  }
  .pc-booking-dot { width: 6px; height: 6px; border-radius: 999px; flex-shrink: 0; }
  .pc-booking-brief {
    font-size: 11px;
    color: #334155;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 16px;
    max-width: 140px;
  }
  .pc-booking-more {
    font-size: 11px;
    color: #64748b;
    padding: 0 6px;
    margin-top: 2px;
    white-space: nowrap;
  }
}
</style>

<style lang="scss" scoped>
::v-deep .booking-calendar-dialog { max-width: 1600px; margin-top: 3vh !important; border-radius: 20px; padding: 0; background: radial-gradient(circle at 0 0, rgba(255,255,255,0.96) 0, rgba(248,250,252,0.98) 40%, rgba(241,245,249,0.98) 100%); box-shadow: 0 24px 48px rgba(15,23,42,0.18), 0 0 0 1px rgba(255,255,255,0.9); backdrop-filter: blur(22px); -webkit-backdrop-filter: blur(22px); }
::v-deep .el-dialog__header { display: none; }
::v-deep .el-dialog__body { padding: 0; }
.dialog-inner { display: flex; flex-direction: column; max-height: 92vh; height: 88vh; }
.dialog-header { flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; margin: 18px 22px 0; padding: 10px 14px; border-radius: 14px; background: rgba(219,234,254,0.96); }
.dialog-title { font-size: 17px; font-weight: 600; color: #0f172a; }
.dialog-close { cursor: pointer; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: 999px; color: #64748b; transition: all 0.15s; &:hover { background: rgba(0,0,0,0.06); color: #0f172a; } }
.dialog-search { flex-shrink: 0; padding: 12px 22px 4px; }
.dialog-content { flex: 1; min-height: 0; overflow: hidden; padding: 0 22px 14px; }
::v-deep .booking-calendar-dialog .el-input__inner { border-radius: 999px; height: 32px; line-height: 32px; border-color: #e5e7eb; background-color: #f9fafb; &:focus { border-color: #2563eb; } }
::v-deep .booking-calendar-dialog .el-button--primary { border-radius: 999px; background: #2563eb; border-color: #2563eb; box-shadow: 0 4px 10px rgba(37,99,235,0.35); }
::v-deep .booking-calendar-dialog .el-button--default { border-radius: 999px; }
::v-deep .booking-calendar-dialog .el-form-item { margin-bottom: 8px; }
::v-deep .booking-calendar-dialog .el-form-item__label { white-space: nowrap; }
</style>
