<script setup lang="ts">
import { ElMessage, ElMessageBox } from "element-plus";
import { computed, onMounted, reactive, ref } from "vue";

import { api } from "../services/api";
import type { EntitlementPlan, SsoAuditItem, SsoClientItem, SsoIdentityItem } from "../types/api";
import AdminPagination from "./AdminPagination.vue";

const loading = ref(false);
const savingUrl = ref(false);
const clients = ref<SsoClientItem[]>([]);
const entitlementPlans = ref<EntitlementPlan[]>([]);
const userClientUrl = ref("");
const activeTab = ref("applications");
const clientDialogOpen = ref(false);
const editingClientId = ref<number | null>(null);
const secretDialogOpen = ref(false);
const revealedSecret = ref("");
const revealedAppId = ref("");

const identityItems = ref<SsoIdentityItem[]>([]);
const identityTotal = ref(0);
const identityPage = ref(1);
const identityPageSize = ref(10);
const identityKeyword = ref("");
const identityClientId = ref<number | undefined>();

const auditItems = ref<SsoAuditItem[]>([]);
const auditTotal = ref(0);
const auditPage = ref(1);
const auditPageSize = ref(10);
const auditClientId = ref<number | undefined>();
const auditStatus = ref("");

const clientForm = reactive({
  appId: "",
  name: "",
  redirectUrisText: "",
  allowAutoRegister: false,
  defaultEntitlementPlanId: undefined as number | undefined,
  status: 1,
});

const dialogTitle = computed(() => editingClientId.value ? "编辑接入应用" : "新增接入应用");

onMounted(loadOverview);

async function loadOverview() {
  loading.value = true;
  try {
    const [config, clientList, plans] = await Promise.all([
      api.ssoConfig(),
      api.ssoClients(),
      api.entitlementPlans(false),
    ]);
    userClientUrl.value = config.userClientUrl;
    clients.value = clientList;
    entitlementPlans.value = plans;
  } catch (error) {
    showError(error, "应用接入配置加载失败");
  } finally {
    loading.value = false;
  }
}

async function savePublicUrl() {
  savingUrl.value = true;
  try {
    const result = await api.saveSsoConfig(userClientUrl.value.trim());
    userClientUrl.value = result.userClientUrl;
    ElMessage.success("用户端公网地址已保存");
  } catch (error) {
    showError(error, "用户端公网地址保存失败");
  } finally {
    savingUrl.value = false;
  }
}

function openCreateDialog() {
  editingClientId.value = null;
  Object.assign(clientForm, {
    appId: "",
    name: "",
    redirectUrisText: "",
    allowAutoRegister: false,
    defaultEntitlementPlanId: undefined,
    status: 1,
  });
  clientDialogOpen.value = true;
}

function openEditDialog(client: SsoClientItem) {
  editingClientId.value = client.id;
  Object.assign(clientForm, {
    appId: client.appId,
    name: client.name,
    redirectUrisText: client.redirectUris.join("\n"),
    allowAutoRegister: client.allowAutoRegister,
    defaultEntitlementPlanId: client.defaultEntitlementPlanId ?? undefined,
    status: client.status,
  });
  clientDialogOpen.value = true;
}

async function saveClient() {
  const appId = clientForm.appId.trim();
  const name = clientForm.name.trim();
  if (!appId || !name) {
    ElMessage.warning("请填写应用ID和应用名称");
    return;
  }
  if (clientForm.allowAutoRegister && !clientForm.defaultEntitlementPlanId) {
    ElMessage.warning("允许自动注册时请选择默认权益版本");
    return;
  }
  const redirectUris = clientForm.redirectUrisText
    .split(/\r?\n/)
    .map((item) => item.trim())
    .filter(Boolean);
  try {
    if (editingClientId.value) {
      await api.updateSsoClient(editingClientId.value, {
        name,
        redirectUris,
        allowAutoRegister: clientForm.allowAutoRegister,
        defaultEntitlementPlanId: clientForm.defaultEntitlementPlanId ?? null,
        status: clientForm.status,
      });
      ElMessage.success("接入应用已更新");
    } else {
      const result = await api.createSsoClient({
        appId,
        name,
        redirectUris,
        allowAutoRegister: clientForm.allowAutoRegister,
        defaultEntitlementPlanId: clientForm.defaultEntitlementPlanId ?? null,
        status: clientForm.status,
      });
      revealedSecret.value = result.clientSecret || "";
      revealedAppId.value = result.appId;
      secretDialogOpen.value = true;
    }
    clientDialogOpen.value = false;
    await loadOverview();
  } catch (error) {
    showError(error, "接入应用保存失败");
  }
}

async function toggleClient(client: SsoClientItem) {
  const targetStatus = client.status;
  try {
    await api.updateSsoClient(client.id, {
      name: client.name,
      redirectUris: client.redirectUris,
      allowAutoRegister: client.allowAutoRegister,
      defaultEntitlementPlanId: client.defaultEntitlementPlanId ?? null,
      status: targetStatus,
    });
    ElMessage.success(targetStatus === 1 ? "应用已启用" : "应用已停用");
  } catch (error) {
    client.status = targetStatus === 1 ? 0 : 1;
    showError(error, "应用状态更新失败");
  }
}

async function rotateSecret(client: SsoClientItem) {
  try {
    await ElMessageBox.confirm(
      `更新后，${client.name} 使用的旧密钥会立即失效。确定继续吗？`,
      "更新应用密钥",
      { type: "warning", confirmButtonText: "确认更新", cancelButtonText: "取消" },
    );
    const result = await api.rotateSsoClientSecret(client.id);
    revealedSecret.value = result.clientSecret;
    revealedAppId.value = client.appId;
    secretDialogOpen.value = true;
  } catch (error) {
    if (error === "cancel" || error === "close") return;
    showError(error, "应用密钥更新失败");
  }
}

async function copySecret() {
  await navigator.clipboard.writeText(revealedSecret.value);
  ElMessage.success("应用密钥已复制");
}

async function switchTab(tabName: string | number) {
  activeTab.value = String(tabName);
  if (activeTab.value === "identities") await loadIdentities();
  if (activeTab.value === "audits") await loadAudits();
}

async function loadIdentities() {
  loading.value = true;
  try {
    const page = await api.ssoIdentities({
      clientId: identityClientId.value,
      keyword: identityKeyword.value.trim(),
      page: identityPage.value,
      pageSize: identityPageSize.value,
    });
    identityItems.value = page.items;
    identityTotal.value = page.total;
  } catch (error) {
    showError(error, "账号绑定加载失败");
  } finally {
    loading.value = false;
  }
}

async function searchIdentities() {
  identityPage.value = 1;
  await loadIdentities();
}

async function changeIdentityPage(page: number, pageSize: number) {
  identityPage.value = page;
  identityPageSize.value = pageSize;
  await loadIdentities();
}

async function unlinkIdentity(item: SsoIdentityItem) {
  try {
    await ElMessageBox.confirm(
      `解除后，${item.userName} 下次从 ${item.clientName} 进入时需要重新核对手机号。`,
      "解除账号绑定",
      { type: "warning", confirmButtonText: "解除绑定", cancelButtonText: "取消" },
    );
    await api.unlinkSsoIdentity(item.id);
    ElMessage.success("账号绑定已解除");
    await Promise.all([loadIdentities(), loadOverview()]);
  } catch (error) {
    if (error === "cancel" || error === "close") return;
    showError(error, "解除账号绑定失败");
  }
}

async function loadAudits() {
  loading.value = true;
  try {
    const page = await api.ssoAudits({
      clientId: auditClientId.value,
      auditStatus: auditStatus.value,
      page: auditPage.value,
      pageSize: auditPageSize.value,
    });
    auditItems.value = page.items;
    auditTotal.value = page.total;
  } catch (error) {
    showError(error, "登录审计加载失败");
  } finally {
    loading.value = false;
  }
}

async function searchAudits() {
  auditPage.value = 1;
  await loadAudits();
}

async function changeAuditPage(page: number, pageSize: number) {
  auditPage.value = page;
  auditPageSize.value = pageSize;
  await loadAudits();
}

function formatTime(value?: string | null) {
  if (!value) return "-";
  return new Date(value).toLocaleString("zh-CN", { hour12: false });
}

function maskPhone(phone: string) {
  return phone.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2");
}

function showError(error: unknown, fallback: string) {
  ElMessage.error(error instanceof Error ? error.message : fallback);
}
</script>

<template>
  <section v-loading="loading" class="sso-page">
    <div class="page-head inline">
      <div>
        <h2>应用接入</h2>
        <p>让已在其他可信应用登录的学员免验证码进入千问千答，并独立管理密钥、账号绑定和登录审计。</p>
      </div>
      <el-button type="primary" @click="openCreateDialog">新增接入应用</el-button>
    </div>

    <section class="sso-public-url">
      <div>
        <strong>用户端公网地址</strong>
        <p>服务端会使用这个地址生成免登录入口，例如 https://qa.example.com。</p>
      </div>
      <el-input v-model="userClientUrl" placeholder="https://qa.example.com" clearable />
      <el-button :loading="savingUrl" @click="savePublicUrl">保存地址</el-button>
    </section>

    <el-tabs class="sso-tabs" :model-value="activeTab" @tab-change="switchTab">
      <el-tab-pane label="接入应用" name="applications">
        <div class="sso-table-shell">
          <el-table :data="clients" stripe empty-text="还没有接入应用" table-layout="fixed" style="width: 100%">
            <el-table-column label="应用" min-width="170">
              <template #default="{ row }">
                <div class="sso-app-cell">
                  <strong>{{ row.name }}</strong>
                  <span>{{ row.appId }}</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="账号策略" min-width="170">
              <template #default="{ row }">
                <div class="sso-policy-cell">
                  <span v-if="row.allowAutoRegister">自动注册 · {{ row.defaultEntitlementPlanName || "未配置权益" }}</span>
                  <span v-else>仅已有学员</span>
                  <small>已绑定 {{ row.identityCount }} 人</small>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="回跳地址" min-width="170" show-overflow-tooltip>
              <template #default="{ row }">{{ row.redirectUris.join("、") || "未配置" }}</template>
            </el-table-column>
            <el-table-column label="运行状态" width="148">
              <template #default="{ row }">
                <div class="sso-status-cell">
                  <div><el-switch v-model="row.status" :active-value="1" :inactive-value="0" @change="toggleClient(row)" /><span>{{ row.status === 1 ? "已启用" : "已停用" }}</span></div>
                  <small>最近使用：{{ formatTime(row.lastUsedAt) }}</small>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="150" align="right">
              <template #default="{ row }">
                <div class="sso-row-actions">
                  <el-button size="small" @click="openEditDialog(row)">编辑</el-button>
                  <el-button size="small" @click="rotateSecret(row)">更新密钥</el-button>
                </div>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <div class="sso-app-cards">
          <el-empty v-if="!clients.length" description="还没有接入应用" :image-size="72" />
          <article v-for="client in clients" v-else :key="client.id" class="sso-app-card">
            <div class="sso-app-card-head">
              <div class="sso-app-cell"><strong>{{ client.name }}</strong><span>{{ client.appId }}</span></div>
              <div class="sso-card-status"><el-switch v-model="client.status" :active-value="1" :inactive-value="0" @change="toggleClient(client)" /><span>{{ client.status === 1 ? "已启用" : "已停用" }}</span></div>
            </div>
            <dl>
              <div><dt>账号策略</dt><dd>{{ client.allowAutoRegister ? `自动注册 · ${client.defaultEntitlementPlanName || "未配置权益"}` : "仅已有学员" }}（已绑定 {{ client.identityCount }} 人）</dd></div>
              <div><dt>回跳地址</dt><dd>{{ client.redirectUris.join("、") || "未配置" }}</dd></div>
              <div><dt>最近使用</dt><dd>{{ formatTime(client.lastUsedAt) }}</dd></div>
            </dl>
            <div class="sso-card-actions"><el-button size="small" @click="openEditDialog(client)">编辑</el-button><el-button size="small" @click="rotateSecret(client)">更新密钥</el-button></div>
          </article>
        </div>
      </el-tab-pane>

      <el-tab-pane label="账号绑定" name="identities">
        <div class="sso-filters">
          <el-select v-model="identityClientId" clearable placeholder="全部应用">
            <el-option v-for="client in clients" :key="client.id" :label="client.name" :value="client.id" />
          </el-select>
          <el-input v-model="identityKeyword" clearable placeholder="搜索姓名、手机号或外部用户ID" @keyup.enter="searchIdentities" />
          <el-button type="primary" @click="searchIdentities">查询</el-button>
        </div>
        <el-table :data="identityItems" stripe empty-text="暂无账号绑定">
          <el-table-column prop="clientName" label="来源应用" min-width="150" />
          <el-table-column prop="userName" label="学员" min-width="120" />
          <el-table-column label="手机号" width="140">
            <template #default="{ row }">{{ maskPhone(row.phone) }}</template>
          </el-table-column>
          <el-table-column prop="externalUserId" label="外部用户ID" min-width="190" />
          <el-table-column label="最近免登录" width="180">
            <template #default="{ row }">{{ formatTime(row.lastLoginAt) }}</template>
          </el-table-column>
          <el-table-column label="操作" width="120" align="center">
            <template #default="{ row }"><el-button size="small" type="danger" plain @click="unlinkIdentity(row)">解除绑定</el-button></template>
          </el-table-column>
        </el-table>
        <AdminPagination :page="identityPage" :page-size="identityPageSize" :total="identityTotal" @change="changeIdentityPage" />
      </el-tab-pane>

      <el-tab-pane label="登录审计" name="audits">
        <div class="sso-filters">
          <el-select v-model="auditClientId" clearable placeholder="全部应用">
            <el-option v-for="client in clients" :key="client.id" :label="client.name" :value="client.id" />
          </el-select>
          <el-select v-model="auditStatus" clearable placeholder="全部状态">
            <el-option label="成功" value="SUCCESS" />
            <el-option label="失败" value="FAILED" />
          </el-select>
          <el-button type="primary" @click="searchAudits">查询</el-button>
        </div>
        <el-table :data="auditItems" stripe empty-text="暂无登录审计">
          <el-table-column prop="clientName" label="来源应用" min-width="150" />
          <el-table-column prop="externalUserId" label="外部用户ID" min-width="190" />
          <el-table-column label="环节" width="110">
            <template #default="{ row }">{{ row.action === "ticket" ? "申请授权码" : "兑换登录态" }}</template>
          </el-table-column>
          <el-table-column label="状态" width="100" align="center">
            <template #default="{ row }"><el-tag :type="row.status === 'SUCCESS' ? 'success' : 'danger'">{{ row.status === "SUCCESS" ? "成功" : "失败" }}</el-tag></template>
          </el-table-column>
          <el-table-column prop="errorMessage" label="失败原因" min-width="220" show-overflow-tooltip />
          <el-table-column prop="ip" label="请求IP" width="140" />
          <el-table-column label="时间" width="180"><template #default="{ row }">{{ formatTime(row.createdAt) }}</template></el-table-column>
        </el-table>
        <AdminPagination :page="auditPage" :page-size="auditPageSize" :total="auditTotal" @change="changeAuditPage" />
      </el-tab-pane>
    </el-tabs>

    <el-dialog v-model="clientDialogOpen" class="sso-client-dialog" :title="dialogTitle" width="min(720px, calc(100vw - 32px))" destroy-on-close align-center>
      <el-form class="sso-client-form" label-position="top">
        <section class="sso-form-section">
          <div class="sso-section-heading">
            <strong>基本信息</strong>
            <span>用于识别接入方，应用 ID 创建后不可修改。</span>
          </div>
          <div class="sso-form-grid">
            <el-form-item label="应用名称"><el-input v-model="clientForm.name" placeholder="例如：学员服务 App" /></el-form-item>
            <el-form-item label="应用 ID"><el-input v-model="clientForm.appId" :disabled="Boolean(editingClientId)" placeholder="例如：student-app" /></el-form-item>
          </div>
        </section>
        <section class="sso-form-section">
          <div class="sso-section-heading">
            <strong>登录后回跳</strong>
            <span>每行一个完整 HTTPS 地址，不需要回跳时可以留空。</span>
          </div>
          <el-form-item class="sso-redirect-field" label="允许回跳地址">
            <el-input v-model="clientForm.redirectUrisText" type="textarea" :rows="3" placeholder="https://student.example.com/home" />
          </el-form-item>
        </section>
        <section class="sso-form-section">
          <div class="sso-section-heading">
            <strong>访问与账号策略</strong>
            <span>控制应用是否可用，以及首次进入时如何处理新学员。</span>
          </div>
          <div class="sso-setting-list">
            <div class="sso-setting-row">
              <div><strong>启用应用</strong><span>停用后，该应用将无法继续申请或使用免登录。</span></div>
              <el-switch v-model="clientForm.status" :active-value="1" :inactive-value="0" />
            </div>
            <div class="sso-setting-row">
              <div><strong>自动注册新学员</strong><span>传入已验证手机号和姓名时，可自动创建账号并分配权益。</span></div>
              <el-switch v-model="clientForm.allowAutoRegister" />
            </div>
            <div v-if="clientForm.allowAutoRegister" class="sso-entitlement-setting">
              <el-form-item label="新学员默认权益">
                <el-select v-model="clientForm.defaultEntitlementPlanId" placeholder="请选择权益版本" style="width: 100%">
                  <el-option v-for="plan in entitlementPlans" :key="plan.id" :label="plan.name" :value="plan.id" />
                </el-select>
              </el-form-item>
            </div>
          </div>
        </section>
      </el-form>
      <template #footer>
        <el-button @click="clientDialogOpen = false">取消</el-button>
        <el-button type="primary" @click="saveClient">保存</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="secretDialogOpen" title="请立即保存应用密钥" width="620px" :close-on-click-modal="false">
      <el-alert title="密钥只在本次显示，关闭后无法再次查看。请保存到接入应用的服务端密钥管理中，不要放入前端代码。" type="warning" :closable="false" show-icon />
      <div class="sso-secret-block">
        <label>应用ID</label><code>{{ revealedAppId }}</code>
        <label>应用密钥</label><code>{{ revealedSecret }}</code>
      </div>
      <template #footer>
        <el-button @click="copySecret">复制密钥</el-button>
        <el-button type="primary" @click="secretDialogOpen = false">我已保存</el-button>
      </template>
    </el-dialog>
  </section>
</template>

<style scoped>
.sso-page {
  container-type: inline-size;
  display: grid;
  gap: 20px;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
}

.sso-public-url {
  display: grid;
  grid-template-columns: minmax(230px, 1fr) minmax(280px, 1.2fr) auto;
  gap: 18px;
  align-items: center;
  min-width: 0;
  padding: 20px 22px;
  border: 1px solid #dce8e4;
  border-radius: 16px;
  background: #fff;
}

.sso-public-url > *,
.sso-tabs,
.sso-table-shell {
  min-width: 0;
}

.sso-public-url p {
  margin: 6px 0 0;
  color: #71817d;
  font-size: 13px;
}

:deep(.sso-tabs .el-tabs__content),
:deep(.sso-tabs .el-tab-pane) {
  width: 100%;
  min-width: 0;
  max-width: 100%;
}

.sso-table-shell {
  width: 100%;
  max-width: 100%;
  overflow: hidden;
  border: 1px solid #e1eae7;
  border-radius: 14px;
  background: #fff;
}

.sso-app-cell,
.sso-policy-cell,
.sso-status-cell {
  display: grid;
  gap: 5px;
  min-width: 0;
}

.sso-app-cell strong,
.sso-policy-cell span {
  overflow: hidden;
  color: #253b35;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sso-app-cell span,
.sso-policy-cell small,
.sso-status-cell small {
  overflow: hidden;
  color: #80908b;
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sso-status-cell > div,
.sso-card-status {
  display: flex;
  gap: 8px;
  align-items: center;
  color: #4f625c;
  font-size: 13px;
}

.sso-row-actions,
.sso-card-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  white-space: nowrap;
}

.sso-row-actions :deep(.el-button + .el-button),
.sso-card-actions :deep(.el-button + .el-button) {
  margin-left: 0;
}

.sso-app-cards {
  display: none;
}

.sso-filters {
  display: flex;
  gap: 12px;
  margin-bottom: 16px;
}

.sso-filters .el-select {
  width: 190px;
}

.sso-filters .el-input {
  max-width: 360px;
}

.sso-client-form {
  display: grid;
  gap: 16px;
}

.sso-form-section {
  min-width: 0;
  padding: 18px 20px;
  border: 1px solid #e0e9e6;
  border-radius: 14px;
  background: #fbfcfc;
}

.sso-section-heading {
  display: grid;
  gap: 4px;
  margin-bottom: 16px;
}

.sso-section-heading strong {
  color: #203a33;
  font-size: 15px;
}

.sso-section-heading span {
  color: #7a8b86;
  font-size: 13px;
  line-height: 1.55;
}

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

.sso-client-form :deep(.el-form-item) {
  min-width: 0;
  margin-bottom: 0;
}

.sso-client-form :deep(.el-form-item__label) {
  height: auto;
  padding-bottom: 7px;
  color: #465a54;
  font-weight: 600;
  line-height: 1.4;
}

.sso-client-form :deep(.el-input__wrapper) {
  min-height: 42px;
}

.sso-redirect-field :deep(.el-textarea__inner) {
  min-height: 82px !important;
  padding: 11px 13px;
  line-height: 1.55;
}

.sso-setting-list {
  overflow: hidden;
  border: 1px solid #e0e9e6;
  border-radius: 12px;
  background: #fff;
}

.sso-setting-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 24px;
  align-items: center;
  min-height: 72px;
  padding: 14px 16px;
}

.sso-setting-row + .sso-setting-row,
.sso-entitlement-setting {
  border-top: 1px solid #e7eeec;
}

.sso-setting-row > div {
  display: grid;
  gap: 5px;
  min-width: 0;
}

.sso-setting-row strong {
  color: #324942;
  font-size: 14px;
}

.sso-setting-row span {
  color: #7a8b86;
  font-size: 13px;
  line-height: 1.5;
}

.sso-entitlement-setting {
  padding: 14px 16px 16px;
  background: #f5faf8;
}

:deep(.sso-client-dialog) {
  max-height: calc(100vh - 32px);
  overflow: hidden;
  border-radius: 18px;
}

:deep(.sso-client-dialog .el-dialog__header) {
  margin-right: 0;
  padding: 22px 26px 17px;
  border-bottom: 1px solid #e7eeec;
}

:deep(.sso-client-dialog .el-dialog__title) {
  color: #1f3932;
  font-size: 21px;
  font-weight: 700;
}

:deep(.sso-client-dialog .el-dialog__body) {
  max-height: calc(100vh - 178px);
  overflow-y: auto;
  padding: 20px 26px;
}

:deep(.sso-client-dialog .el-dialog__footer) {
  padding: 16px 26px 20px;
  border-top: 1px solid #e7eeec;
}

.sso-secret-block {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr);
  gap: 12px 16px;
  align-items: start;
  margin-top: 20px;
}

.sso-secret-block label {
  color: #6c7d79;
}

.sso-secret-block code {
  padding: 10px 12px;
  overflow-wrap: anywhere;
  border-radius: 8px;
  background: #f3f7f5;
  color: #173d34;
}

@container (max-width: 940px) {
  .sso-public-url {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .sso-public-url > div {
    grid-column: 1 / -1;
  }

  .sso-table-shell {
    display: none;
  }

  .sso-app-cards {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
  }

  .sso-app-cards > .el-empty {
    grid-column: 1 / -1;
  }

  .sso-app-card {
    display: grid;
    gap: 16px;
    min-width: 0;
    padding: 18px;
    border: 1px solid #dfe9e6;
    border-radius: 14px;
    background: #fff;
  }

  .sso-app-card-head {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    justify-content: space-between;
  }

  .sso-card-status {
    flex: 0 0 auto;
  }

  .sso-app-card dl {
    display: grid;
    gap: 12px;
    margin: 0;
  }

  .sso-app-card dl > div {
    display: grid;
    gap: 4px;
    min-width: 0;
  }

  .sso-app-card dt {
    color: #82918d;
    font-size: 12px;
  }

  .sso-app-card dd {
    margin: 0;
    overflow-wrap: anywhere;
    color: #41554f;
    font-size: 13px;
    line-height: 1.55;
  }
}

@container (max-width: 660px) {
  .sso-app-cards,
  .sso-public-url {
    grid-template-columns: minmax(0, 1fr);
  }

  .sso-public-url > div {
    grid-column: auto;
  }

  .sso-public-url .el-button {
    width: 100%;
  }

  .sso-filters {
    flex-wrap: wrap;
  }

  .sso-filters .el-select,
  .sso-filters .el-input {
    width: 100%;
    max-width: none;
  }
}

@media (max-width: 760px) {
  .sso-form-grid {
    grid-template-columns: 1fr;
  }

  .sso-form-section {
    padding: 16px;
  }

  :deep(.sso-client-dialog .el-dialog__header),
  :deep(.sso-client-dialog .el-dialog__body),
  :deep(.sso-client-dialog .el-dialog__footer) {
    padding-right: 18px;
    padding-left: 18px;
  }
}
</style>
