<template>
  <AppPage>
    <section class="client-overview">
      <div class="client-overview__title">
        <h1>客户端</h1>
        <p>管理配置、二维码和启停状态。</p>
      </div>
      <div class="client-overview__stats">
        <span>总数 {{ listData.total }}</span>
        <span>已启用 {{ enabledCount }}</span>
        <span>离线通知 {{ offlineMonitorCount }}</span>
      </div>
    </section>

    <n-card class="client-filter-card form-surface" :bordered="false">
      <div class="client-filter-card__head">
        <h3>筛选客户端</h3>
        <div class="client-filter-card__actions">
          <n-button secondary type="primary" @click="refreshList">刷新</n-button>
          <n-button type="primary" @click="addClient">添加客户端</n-button>
        </div>
      </div>

      <QueryBar @search="search">
        <n-form ref="listQueryRef" label-placement="top" :model="searchParam" class="client-filter-form">
          <n-form-item size="small" label="名称" path="name">
            <n-input v-model:value="searchParam.name" size="small" placeholder="按名称搜索" />
          </n-form-item>
          <n-form-item label="邮箱" path="email">
            <n-input v-model:value="searchParam.email" size="small" placeholder="按邮箱搜索" />
          </n-form-item>
          <n-form-item label="IP" path="ipAllocation">
            <n-input v-model:value="searchParam.ipAllocation" size="small" placeholder="按 IP 搜索" />
          </n-form-item>
          <n-form-item label="状态" path="enabled">
            <n-select
              v-model:value="searchParam.enabled"
              size="small"
              placeholder="请选择状态"
              clearable
              :options="selOptions"
            />
          </n-form-item>
        </n-form>
      </QueryBar>
    </n-card>

    <section class="client-grid">
      <n-card
        v-for="row in listData.data"
        :key="row.id"
        class="client-card"
        :hoverable="true"
        :bordered="false"
      >
        <template #header>
          <div class="client-card__title">
            <n-popover trigger="hover">
              <template #trigger>
                <strong>{{ ellipsis(row.name) }}</strong>
              </template>
              <span>{{ row.name }}</span>
            </n-popover>
            <n-tag size="small" :bordered="false" :type="row.enabled === 1 ? 'success' : 'error'">
              {{ row.enabled === 1 ? '启用' : '禁用' }}
            </n-tag>
          </div>
        </template>
        <template #header-extra>
          <div class="client-card__actions">
            <n-button size="small" secondary type="primary" @click="openEditModal(row)">详情</n-button>
            <n-button size="small" color="#0f766e" @click="openQrCode(row.id,row.name)">二维码</n-button>
            <n-dropdown
              trigger="click"
              :options="dropMenuOpts"
              :show-arrow="true"
              @select="moreSelectHandle"
            >
              <n-button size="small" type="primary" @click="saveRows(row)">更多</n-button>
            </n-dropdown>
          </div>
        </template>

        <div class="client-card__body">
          <div class="info-row">
            <span class="info-row__label">邮箱</span>
            <span class="info-row__value">{{ !row.email ? '--' : row.email }}</span>
          </div>
          <div class="info-row">
            <span class="info-row__label">创建人</span>
            <span class="info-row__value">{{ row.createUser }}</span>
          </div>
          <div class="info-row">
            <span class="info-row__label">离线通知</span>
            <n-tag size="small" :bordered="false" :type="row.offlineMonitoring === 1 ? 'success' : 'warning'">
              {{ row.offlineMonitoring === 1 ? '启用' : '禁用' }}
            </n-tag>
          </div>
          <div class="info-row info-row--stacked">
            <span class="info-row__label">客户端 IP</span>
            <div class="client-card__ip-list">
              <n-tag v-for="cip in row.ipAllocation" :key="cip" size="small" type="info" round>
                {{ cip }}
              </n-tag>
            </div>
          </div>
          <div class="client-card__meta">
            <span>创建于 {{ row.createdAt }}</span>
            <span>更新于 {{ row.updatedAt }}</span>
          </div>
        </div>
      </n-card>

      <n-empty
        v-if="!listData.data.length"
        class="client-empty"
        description="当前没有匹配的客户端"
      />
    </section>

    <div class="client-pagination">
      <n-card v-if="listData.total > 8" class="client-pagination__card" :bordered="false">
        <n-pagination
          v-model:page="searchParam.current"
          :item-count="listData.total"
          :default-page-size="8"
          @update-page="pageChange"
        />
      </n-card>
    </div>
  </AppPage>

  <n-modal
    class="client-qr-modal"
    v-model:show="showQrCode"
    preset="card"
    :title="qrCodeData.title"
    header-style="text-align: center"
    content-style="text-align: center"
  >
    <n-image
      :src="qrCodeData.data"
      preview-disabled
      alt="请使用手机Wireguard软件扫码"
    />
  </n-modal>

  <n-modal
    class="client-form-modal"
    v-model:show="editModalShow"
    preset="card"
    :title="editModalTitle"
    style="width: min(760px, calc(100vw - 48px))"
    header-style="text-align: center"
  >
    <n-form
      ref="editModalFormRef"
      class="client-form"
      :rules="editModalFormRules"
      :model="editModalForm"
      label-placement="top"
      require-mark-placement="right"
    >
      <n-collapse class="client-form__collapse" :default-expanded-names="['basic']">
        <n-collapse-item title="基础信息" name="basic">
          <div class="client-form__section">
            <n-form-item label="名称" path="name">
              <n-input v-model:value="editModalForm.name" />
            </n-form-item>
            <n-form-item label="邮箱" path="email">
              <n-input v-model:value="editModalForm.email" />
            </n-form-item>
            <n-form-item class="client-form__full" label="IP" path="ipAllocation" :rule="{
              required: true,
              type: 'array',
              message: 'IP不能为空',
              trigger: ['blur', 'change']
            }">
              <n-select
                v-model:value="editModalForm.ipAllocation"
                filterable
                multiple
                tag
                placeholder="输入，按回车确认"
                :show-arrow="false"
                :show="false"
              />
            </n-form-item>
            <n-form-item label="服务端DNS" path="useServerDns">
              <n-radio-group class="client-form__radio" :value="editModalForm.useServerDns">
                <n-radio :value="1" :checked="editModalForm.useServerDns === 1" @change="editModalForm.useServerDns = 1">是</n-radio>
                <n-radio :value="0" :checked="editModalForm.useServerDns === 0" @change="editModalForm.useServerDns = 0">否</n-radio>
              </n-radio-group>
            </n-form-item>
            <n-form-item label="状态" path="editModalForm.enabled">
              <n-radio-group class="client-form__radio" :value="editModalForm.enabled">
                <n-radio :value="1" :checked="editModalForm.enabled === 1" @change="editModalForm.enabled = 1">启用</n-radio>
                <n-radio :value="0" :checked="editModalForm.enabled === 0" @change="editModalForm.enabled = 0">禁用</n-radio>
              </n-radio-group>
            </n-form-item>
            <n-form-item label="离线通知" path="offlineMonitoring">
              <n-radio-group class="client-form__radio" :value="editModalForm.offlineMonitoring">
                <n-radio :value="1" :checked="editModalForm.offlineMonitoring === 1" @change="editModalForm.offlineMonitoring = 1">启用</n-radio>
                <n-radio :value="0" :checked="editModalForm.offlineMonitoring === 0" @change="editModalForm.offlineMonitoring = 0">禁用</n-radio>
              </n-radio-group>
            </n-form-item>
          </div>
        </n-collapse-item>
        <n-collapse-item title="网络范围" name="network">
          <div class="client-form__section">
            <n-form-item class="client-form__full" label="可访问IP" path="allowedIps">
              <n-select
                v-model:value="editModalForm.allowedIps"
                filterable
                multiple
                tag
                placeholder="输入，按回车确认"
                :show-arrow="false"
                :show="false"
              />
            </n-form-item>
            <n-form-item class="client-form__full" label="可访问IP（扩展）" path="extraAllowedIps">
              <n-select
                v-model:value="editModalForm.extraAllowedIps"
                filterable
                multiple
                tag
                placeholder="输入，按回车确认"
                :show-arrow="false"
                :show="false"
              />
            </n-form-item>
          </div>
        </n-collapse-item>
        <n-collapse-item title="密钥与时间" name="meta">
          <div class="client-form__section">
            <n-form-item class="client-form__full" label="公钥" path="keys.publicKey">
              <n-input disabled v-model:value="editModalForm.keys.publicKey" />
            </n-form-item>
            <n-form-item class="client-form__full" label="私钥" path="keys.privateKey">
              <n-input disabled v-model:value="editModalForm.keys.privateKey" />
            </n-form-item>
            <n-form-item class="client-form__full" label="共享密钥" path="keys.presharedKey">
              <n-input disabled v-model:value="editModalForm.keys.presharedKey" />
            </n-form-item>
            <n-form-item class="timeItem client-form__full" label="时间">
              <n-space vertical>
                <span>创建时间: {{ editModalForm.createdAt }}</span>
                <span>更新时间: {{ editModalForm.updatedAt }}</span>
              </n-space>
            </n-form-item>
          </div>
        </n-collapse-item>
      </n-collapse>
      <n-form-item class="client-form__full client-form__footer">
        <n-button type="primary" @click="updateClient()">保存客户端</n-button>
      </n-form-item>
    </n-form>
  </n-modal>

  <n-modal
    class="client-form-modal"
    v-model:show="addModalShow"
    preset="card"
    title="添加"
    style="width: min(760px, calc(100vw - 48px))"
    header-style="text-align: center"
  >
    <n-form
      ref="addModalFormRef"
      class="client-form"
      :rules="addModalFormRules"
      :model="addModalForm"
      label-placement="top"
      require-mark-placement="right"
    >
      <n-collapse class="client-form__collapse" :default-expanded-names="['basic']">
        <n-collapse-item title="基础信息" name="basic">
          <div class="client-form__section">
            <n-form-item label="名称" path="name">
              <n-input v-model:value="addModalForm.name" />
            </n-form-item>
            <n-form-item label="邮箱" path="email">
              <n-input v-model:value="addModalForm.email" />
            </n-form-item>
            <n-form-item class="client-form__full" label="IP" path="ipAllocation" :rule="{
              required: true,
              type: 'array',
              message: 'IP不能为空',
              trigger: ['blur', 'change']
            }">
              <n-select
                v-model:value="addModalForm.ipAllocation"
                filterable
                multiple
                tag
                placeholder="输入，按回车确认"
                :show-arrow="false"
                :show="false"
              />
            </n-form-item>
            <n-form-item label="服务端DNS" path="useServerDns">
              <n-radio-group class="client-form__radio" :value="addModalForm.useServerDns">
                <n-radio :value="1" :checked="addModalForm.useServerDns === 1" @change="addModalForm.useServerDns = 1">是</n-radio>
                <n-radio :value="0" :checked="addModalForm.useServerDns === 0" @change="addModalForm.useServerDns = 0">否</n-radio>
              </n-radio-group>
            </n-form-item>
            <n-form-item label="状态" path="editModalForm.enabled">
              <n-radio-group class="client-form__radio" :value="addModalForm.enabled">
                <n-radio :value="1" :checked="addModalForm.enabled === 1" @change="addModalForm.enabled = 1">启用</n-radio>
                <n-radio :value="0" :checked="addModalForm.enabled === 0" @change="addModalForm.enabled = 0">禁用</n-radio>
              </n-radio-group>
            </n-form-item>
            <n-form-item label="离线通知" path="offlineMonitoring">
              <n-radio-group class="client-form__radio" :value="addModalForm.offlineMonitoring">
                <n-radio :value="1" :checked="addModalForm.offlineMonitoring === 1" @change="addModalForm.offlineMonitoring = 1">启用</n-radio>
                <n-radio :value="0" :checked="addModalForm.offlineMonitoring === 0" @change="addModalForm.offlineMonitoring = 0">禁用</n-radio>
              </n-radio-group>
            </n-form-item>
          </div>
        </n-collapse-item>
        <n-collapse-item title="网络范围" name="network">
          <div class="client-form__section">
            <n-form-item class="client-form__full" label="可访问IP" path="allowedIps">
              <n-select
                v-model:value="addModalForm.allowedIps"
                filterable
                multiple
                tag
                placeholder="输入，按回车确认"
                :show-arrow="false"
                :show="false"
              />
            </n-form-item>
            <n-form-item class="client-form__full" label="可访问IP（扩展）" path="extraAllowedIps">
              <n-select
                v-model:value="addModalForm.extraAllowedIps"
                filterable
                multiple
                tag
                placeholder="输入，按回车确认"
                :show-arrow="false"
                :show="false"
              />
            </n-form-item>
          </div>
        </n-collapse-item>
        <n-collapse-item title="密钥" name="keys">
          <div class="client-form__section">
            <n-form-item class="client-form__full client-form__tools">
              <n-button size="small" secondary type="primary" @click="generateKeys">重新生成密钥对</n-button>
            </n-form-item>
            <n-form-item class="client-form__full" label="公钥" path="keys.publicKey">
              <n-input v-model:value="addModalForm.keys.publicKey" />
            </n-form-item>
            <n-form-item class="client-form__full" label="私钥" path="keys.privateKey">
              <n-input v-model:value="addModalForm.keys.privateKey" />
            </n-form-item>
            <n-form-item class="client-form__full" label="共享密钥" path="keys.presharedKey">
              <n-input v-model:value="addModalForm.keys.presharedKey" />
            </n-form-item>
          </div>
        </n-collapse-item>
      </n-collapse>
      <n-form-item class="client-form__full client-form__footer">
        <n-button type="primary" @click="confirmAddClient()">添加客户端</n-button>
      </n-form-item>
    </n-form>
  </n-modal>
</template>

<script setup>
import api from '@/views/client/api'
import { debounce, ellipsis } from '@/utils'
import clientApi from '@/views/client/api'
import QueryBar from '@/components/query-bar/QueryBar.vue'
import event from '@/utils/event/event'

const { $bus } = event()

const selOptions = [
  {
    label: '启用',
    value: 1,
  },
  {
    label: '禁用',
    value: 0
  }
]

const listQueryRef = ref()

const listData = reactive({
  data: [],
  total: 0,
  totalPage: 0,
})

const enabledCount = computed(() => listData.data.filter((item) => item.enabled === 1).length)
const offlineMonitorCount = computed(
  () => listData.data.filter((item) => item.offlineMonitoring === 1).length
)

const showQrCode = ref(false)
const editModalShow = ref(false)
const addModalShow = ref(false)
const editModalTitle = ref('')

const qrCodeData = {
  title: '',
  data: '',
}

const getMoreRowData = ref({
  id: '',
  name: ''
})

const editModalFormRef = ref()
const addModalFormRef = ref()

const editModalFormRules = {
  name: [
    { required: true, message: '名称不能为空', trigger: 'blur' }
  ],
  keys: {
    privateKey: [
      { required: true, message: '密钥不能为空', trigger: 'blur' }
    ],
    publicKey: [
      { required: true, message: '公钥不能为空', trigger: 'blur' }
    ],
    presharedKey: [
      { required: true, message: '共享密钥不能为空', trigger: 'blur' }
    ],
  },
  enabled: [
    { required: true, message: '状态不能为空', trigger: 'change' }
  ]
}

const addModalFormRules = {
  name: [
    { required: true, message: '名称不能为空', trigger: 'blur' }
  ],
  keys: {
    privateKey: [
      { required: true, message: '密钥不能为空', trigger: 'blur' }
    ],
    publicKey: [
      { required: true, message: '公钥不能为空', trigger: 'blur' }
    ],
    presharedKey: [
      { required: true, message: '共享密钥不能为空', trigger: 'blur' }
    ],
  },
  enabled: [
    { required: true, message: '状态不能为空', trigger: 'change' }
  ]
}

const editModalForm = ref({
  id: '',
  name: '',
  email: '',
  ipAllocation: [],
  allowedIps: [],
  extraAllowedIps: [],
  useServerDns: 0,
  keys: {
    privateKey: '',
    publicKey: '',
    presharedKey: ''
  },
  enabled: 1,
  offlineMonitoring: 1,
  createdAt: '',
  updatedAt: ''
})

const addModalForm = ref({
  id: '',
  name: '',
  email: '',
  ipAllocation: [],
  allowedIps: [],
  extraAllowedIps: [],
  useServerDns: 0,
  keys: {
    privateKey: '',
    publicKey: '',
    presharedKey: ''
  },
  enabled: 1,
  offlineMonitoring: 1
})

const dropMenuOpts = [
  {
    key: 'download',
    label: '下载',
  },
  {
    key: 'mail',
    label: '邮件',
  },
  {
    key: 'delete',
    label: '删除',
  }
]

const searchParam = reactive({
  name: '',
  email: '',
  ipAllocation: '',
  enabled: undefined,
  current: 1,
  size: 8,
})

function getClientList() {
  api.clientList(searchParam).then((res) => {
    if (res.data.code === 200) {
      listData.data = res.data.data.records
      listData.total = res.data.data.total
      listData.totalPage = res.data.data.totalPage
    }
  })
}

function openQrCode(clientID, title) {
  api.downloadClient('QRCODE', clientID).then((res) => {
    if (res.data.code === 200) {
      qrCodeData.data = res.data.data.qrCode
      qrCodeData.title = title
      showQrCode.value = true
    }
  })
}

function moreSelectHandle(key) {
  switch (key) {
    case 'download':
      api.downloadClient('FILE', getMoreRowData.value.id).then((response) => {
        if (response && response.status === 200) {
          const blob = new Blob([response.data], {
            type: 'text/plain'
          })
          const link = document.createElement('a')
          link.download = getMoreRowData.value.name + '.conf'
          link.style.display = 'none'
          link.href = URL.createObjectURL(blob)
          document.body.appendChild(link)
          link.click()
          URL.revokeObjectURL(link.href)
          document.body.removeChild(link)
        }
      })
      break
    case 'mail':
      api.downloadClient('EMAIL', getMoreRowData.value.id).then((response) => {
        if (response.data.code === 200) {
          $message.success('发送邮件成功,请注意查收!')
        }
      })
      break
    case 'delete':
      $dialog.confirm({
        type: 'warning',
        title: '删除',
        content: `是否删除客户端：【${getMoreRowData.value.name}】？`,
        async confirm() {
          api.deleteClient(getMoreRowData.value.id).then((res) => {
            if (res.data.code === 200) {
              $message.success('操作成功!')
              getClientList()
            }
          })
        },
      })
      break
  }
}

function saveRows(row) {
  getMoreRowData.value = row
}

function openEditModal(row) {
  editModalShow.value = true
  editModalTitle.value = row.name
  editModalForm.value.id = row.id
  editModalForm.value.name = row.name
  editModalForm.value.email = row.email
  editModalForm.value.ipAllocation = row.ipAllocation
  editModalForm.value.allowedIps = row.allowedIps
  editModalForm.value.extraAllowedIps = row.extraAllowedIps
  editModalForm.value.useServerDns = row.useServerDns
  editModalForm.value.keys.privateKey = row.keys.privateKey
  editModalForm.value.keys.publicKey = row.keys.publicKey
  editModalForm.value.keys.presharedKey = row.keys.presharedKey
  editModalForm.value.enabled = row.enabled
  editModalForm.value.offlineMonitoring = row.offlineMonitoring
  editModalForm.value.createdAt = row.createdAt
  editModalForm.value.updatedAt = row.updatedAt
}

async function updateClient() {
  editModalFormRef.value.validate(async (valid) => {
    if (valid) {
      return valid
    }

    const res = await api.saveClient(editModalForm.value)
    if (res.data.code === 200) {
      editModalShow.value = false
      getClientList()
    }
  })
}

async function confirmAddClient() {
  addModalFormRef.value.validate(async (valid) => {
    if (valid) {
      return valid
    }

    const response = await clientApi.saveClient(addModalForm.value)
    if (response.data.code === 200) {
      refreshList()
      addModalShow.value = false
    }
  })
}

const addClient = debounce(() => {
  generateClientIPS()
  addModalForm.value.name = ''
  addModalShow.value = true
}, 300)

async function generateKeys() {
  const res = await clientApi.generateClientKeys()
  if (res.data.code === 200) {
    addModalForm.value.keys.privateKey = res.data.data.privateKey
    addModalForm.value.keys.publicKey = res.data.data.publicKey
    addModalForm.value.keys.presharedKey = res.data.data.presharedKey
  }
}

async function generateClientIPS() {
  const res = await clientApi.generateClientIP()
  if (res.data.code === 200) {
    addModalForm.value.ipAllocation = res.data.data.clientIPS
    addModalForm.value.allowedIps = res.data.data.serverIPS
    await generateKeys()
  }
}

function refreshList() {
  searchParam.name = ''
  searchParam.email = ''
  searchParam.enabled = undefined
  searchParam.ipAllocation = ''
  searchParam.current = 1
  getClientList()
}

function pageChange(page) {
  searchParam.current = page
  getClientList()
}

function search() {
  searchParam.current = 1
  getClientList()
}

const handleRefreshClients = (value) => {
  if (value) {
    getClientList()
  }
}

$bus.on('refreshClients', handleRefreshClients)

onBeforeUnmount(() => {
  $bus.off('refreshClients', handleRefreshClients)
})

getClientList()
</script>

<style scoped lang="scss">
.client-overview {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 2px;
}

.client-overview__title h1,
.client-filter-card__head h3 {
  margin: 0;
  font-size: 18px;
  line-height: 1.4;
}

.client-overview__title p {
  margin: 4px 0 0;
  font-size: 13px;
  color: #64748b;
}

.client-overview__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.client-overview__stats span {
  padding: 6px 10px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 999px;
  font-size: 13px;
  color: #475569;
  background: rgba(255, 255, 255, 0.9);
}

.client-filter-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
}

.client-filter-card__actions {
  display: flex;
  gap: 10px;
}

.client-filter-card,
.client-pagination__card,
.client-card {
  border-radius: 14px;
  background: #ffffff;
}

.form-surface {
  box-shadow: 0 18px 45px rgba(15, 23, 42, 0.06);
}

.client-filter-form {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0 14px;
}

.client-filter-form :deep(.n-form-item-label) {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #64748b;
}

.client-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}

.client-card__title,
.client-card__actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.client-card__title strong {
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 15px;
  color: #0f172a;
}

.client-card__body {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.info-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.info-row--stacked {
  align-items: flex-start;
  flex-direction: column;
}

.info-row__label {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #94a3b8;
}

.info-row__value {
  color: #334155;
  text-align: right;
  word-break: break-all;
}

.client-card__ip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.client-card__meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 12px;
  border-top: 1px solid rgba(148, 163, 184, 0.16);
  font-size: 12px;
  color: #94a3b8;
}

.client-empty {
  grid-column: 1 / -1;
  padding: 48px 0;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.9);
}

.client-pagination {
  display: flex;
  justify-content: center;
}

.client-pagination__card {
  width: 100%;
}

.timeItem {
  .n-form-item-blank {
    display: block;
  }
}

.client-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 18px;
}

.client-form__full {
  grid-column: 1 / -1;
}

.client-form__collapse {
  grid-column: 1 / -1;
}

.client-form__section {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 18px;
  padding-top: 8px;
}

.client-form__radio {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  width: 100%;
  padding: 10px 14px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 12px;
  background: linear-gradient(180deg, #f8fafc 0%, #ffffff 100%);
}

.client-form__tools {
  margin-bottom: 4px;
}

.client-form__action {
  margin-top: 8px;
}

.client-form__action :deep(.n-button) {
  min-width: 148px;
  height: 42px;
  border-radius: 12px;
}

.client-form__footer {
  grid-column: 1 / -1;
  margin-top: 14px;
  margin-bottom: 0;
  padding-top: 16px;
  border-top: 1px solid rgba(148, 163, 184, 0.16);
}

.client-form__footer :deep(.n-form-item-blank) {
  justify-content: flex-start;
}

.client-form__footer :deep(.n-button) {
  min-width: 148px;
  height: 42px;
  border-radius: 12px;
}

.client-form :deep(.n-form-item-label) {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #64748b;
}

.client-form :deep(.n-form-item-blank) {
  align-items: flex-start;
}

.client-form :deep(.n-collapse-item) {
  border-radius: 14px;
  background: #f8fafc;
}

.client-form :deep(.n-collapse-item + .n-collapse-item) {
  margin-top: 12px;
}

.client-form :deep(.n-collapse-item__header) {
  padding: 14px 16px;
  font-weight: 600;
  color: #334155;
}

.client-form :deep(.n-collapse-item__content-wrapper) {
  border-top: 1px solid rgba(148, 163, 184, 0.16);
}

.client-form :deep(.n-collapse-item__content-inner) {
  padding: 0 16px 16px;
}

.client-form :deep(.n-input),
.client-form :deep(.n-base-selection),
.client-form :deep(.n-input-number) {
  width: 100%;
}

.client-form :deep(.n-input .n-input__input-el),
.client-form :deep(.n-base-selection .n-base-selection-label),
.client-form :deep(.n-input-number .n-input__input-el) {
  min-height: 42px;
}

:deep(.client-form-modal) {
  width: auto;
}

:deep(.client-form-modal .n-card) {
  width: min(760px, calc(100vw - 48px));
  border-radius: 20px;
  overflow: hidden;
}

:deep(.client-form-modal .n-card-header) {
  padding: 22px 24px 12px;
}

:deep(.client-form-modal .n-card__content) {
  padding: 12px 24px 24px;
}

:deep(.client-qr-modal) {
  width: auto;
}

:deep(.client-qr-modal .n-card) {
  width: min(300px, calc(100vw - 96px));
  border-radius: 20px;
}

@media (max-width: 960px) {
  .client-overview {
    flex-direction: column;
  }

  .client-filter-form {
    grid-template-columns: 1fr;
  }

  .client-filter-card__head {
    flex-direction: column;
    align-items: flex-start;
  }

  .client-form {
    grid-template-columns: 1fr;
  }

  .client-form__section {
    grid-template-columns: 1fr;
  }
}
</style>
