/* ============================================================
   RTP Stream Analyzer — 主题样式
   浅色现代主题：通过覆写 Bootstrap 5.3 的 CSS 变量全站换肤，
   自定义组件（上传框 / 选项卡 / SIP 阶梯图 / 统计卡）在此定义。
   ============================================================ */

:root {
    /* 主题色板 */
    --brand: #4f46e5;
    --brand-2: #7c3aed;
    --ink: #0f172a;
    --muted: #64748b;
    --line: #e6eaf2;
    --surface: #ffffff;

    /* 覆写 Bootstrap 语义色（text-/bg-/border-* 全站生效）。
       info 保持 Bootstrap 原亮青——代码里 bg-info 一律配深色字 */
    --bs-primary-rgb: 79, 70, 229;      /* indigo */
    --bs-success-rgb: 5, 150, 105;      /* emerald */
    --bs-danger-rgb: 225, 29, 72;       /* rose */
    --bs-warning-rgb: 217, 119, 6;      /* amber */
    --bs-secondary-rgb: 71, 85, 105;    /* slate */
    --bs-light-rgb: 248, 250, 252;
    --bs-dark-rgb: 15, 23, 42;
    --bs-border-color: #e2e8f0;
    --bs-border-radius: .55rem;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
        "Helvetica Neue", Arial, sans-serif;
    color: #1e293b;
    background:
        radial-gradient(1100px 380px at 88% -120px, rgba(99, 102, 241, .10), transparent 60%),
        radial-gradient(900px 340px at 6% -140px, rgba(14, 165, 233, .09), transparent 60%),
        linear-gradient(180deg, #f7f9fc 0%, #f1f4f9 100%);
    background-attachment: fixed;
    min-height: 100vh;
}

/* ====== 页面宽度自适应：替换 Bootstrap 固定档位 container ====== */
.shell {
    width: 100%;
    max-width: min(1920px, 97vw);
    margin-inline: auto;
    padding-inline: clamp(1rem, 2vw, 2.25rem);
}
/* 首页内容流：窄屏占满，宽屏封顶居中，避免上传框过分拉伸 */
.page-main {
    max-width: 1560px;
    margin-inline: auto;
}

/* ====== 导航栏 ====== */
.navbar-app {
    background: linear-gradient(115deg, #0b1220 0%, #1e1b4b 58%, #312e81 100%) !important;
    padding: .6rem 0;
    position: sticky;
    top: 0;
    z-index: 1030;
    box-shadow: 0 10px 30px -18px rgba(2, 6, 23, .8);
}
.navbar-app .shell {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}
.navbar-brand {
    display: flex;
    align-items: center;
    gap: .65rem;
    font-weight: 700;
    letter-spacing: .01em;
}
.navbar-brand i {
    display: inline-grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: 11px;
    background: linear-gradient(135deg, #6366f1, #a855f7);
    box-shadow: 0 6px 16px -6px rgba(129, 140, 248, .7);
    font-size: 1.1rem;
    color: #fff;
}
.navbar-text {
    color: #cbd5e1 !important;
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 999px;
    padding: .32rem .9rem;
    font-size: .82rem;
}

/* ====== 首页标题区 ====== */
.hero { padding: 1.2rem 0 .4rem; }
.hero-title {
    font-size: clamp(1.55rem, 2.4vw, 2.3rem);
    font-weight: 800;
    color: var(--ink);
    letter-spacing: -0.02em;
}
.hero-title i { color: #6366f1; }
.hero-sub {
    color: var(--muted);
    font-size: clamp(.95rem, 1.2vw, 1.08rem);
    margin-top: .55rem;
}

/* ====== 卡片 ====== */
.card {
    border: 1px solid var(--line);
    border-radius: 16px;
    background: var(--surface);
    box-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 12px 32px -20px rgba(15, 23, 42, .12);
    overflow: hidden;
}
.card-body { padding: 1.25rem 1.35rem; }

/* 卡片头：色类只用于着色，统一为浅底深字的柔和风格 + 顶部色条 */
.card-header {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .95rem 1.35rem;
    background: #fff;
    border-bottom: 1px solid var(--line);
}
.card-header h5 {
    display: flex;
    align-items: center;
    gap: .55rem;
    margin: 0;
    font-size: 1.02rem;
    font-weight: 650;
}
.card-header h5 i { font-size: 1.15rem; }
.card-header.bg-primary {
    background: #eef2ff !important;
    color: #4338ca;
    box-shadow: inset 0 3px 0 #6366f1;
    border-bottom-color: #e0e7ff;
}
.card-header.bg-success {
    background: #ecfdf5 !important;
    color: #047857;
    box-shadow: inset 0 3px 0 #10b981;
    border-bottom-color: #d1fae5;
}
.card-header.bg-warning {
    background: #fffbeb !important;
    color: #b45309;
    box-shadow: inset 0 3px 0 #f59e0b;
    border-bottom-color: #fef3c7;
}
.card-header.bg-info {
    background: #f0f9ff !important;
    color: #0369a1;
    box-shadow: inset 0 3px 0 #0ea5e9;
    border-bottom-color: #e0f2fe;
}
.card-header.bg-secondary {
    background: #f8fafc !important;
    color: #475569;
    box-shadow: inset 0 3px 0 #94a3b8;
    border-bottom-color: #e2e8f0;
}
.card-header.bg-purple {
    background: #faf5ff !important;
    color: #7e22ce;
    box-shadow: inset 0 3px 0 #a855f7;
    border-bottom-color: #f3e8ff;
}

/* 报告正文里的小节标题：渐变竖条 + 加重 */
.card-body h6 {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: .95rem;
    font-weight: 700;
    color: #1e293b;
    margin: 1.35rem 0 .65rem;
}
.card-body h6::before {
    content: '';
    flex: 0 0 auto;
    width: 4px;
    height: 16px;
    border-radius: 2px;
    background: linear-gradient(180deg, #6366f1, #a855f7);
}

/* ====== 上传区域 ====== */
.upload-box {
    position: relative;
    border: 1.5px dashed #c3cde0;
    border-radius: 16px;
    padding: 22px 15px;
    text-align: center;
    cursor: pointer;
    background: linear-gradient(180deg, #fbfcfe, #f6f8fc);
    min-height: 150px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transition: border-color .2s ease, background .2s ease,
        transform .2s ease, box-shadow .2s ease;
}
.upload-box:hover {
    border-color: #818cf8;
    background: #f5f7ff;
    transform: translateY(-2px);
    box-shadow: 0 12px 26px -16px rgba(79, 70, 229, .45);
}
.upload-box.has-file {
    border: 1.5px solid #6ee7b7;
    background: linear-gradient(180deg, #f6fffb, #effdf7);
}
.upload-box i {
    width: 54px;
    height: 54px;
    border-radius: 15px;
    background: #eef2ff;
    color: #6366f1;
    font-size: 1.5rem;
    display: grid;
    place-items: center;
    margin-bottom: .35rem;
    transition: background .2s ease, color .2s ease;
}
.upload-box.has-file i {
    background: #d1fae5;
    color: #059669;
}
.upload-label {
    cursor: pointer;
    margin: 0;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}
.upload-label .d-block {
    font-weight: 600;
    color: #334155;
}
.upload-label small { color: #94a3b8; }
.file-input { display: none; }
.file-name {
    font-size: .82rem;
    color: #059669;
    margin-top: 8px;
    word-break: break-all;
    font-weight: 600;
}
.file-name:not(:empty)::before {
    content: '✓ ';
    font-weight: 800;
}

/* ====== 方向 / 通话 选项卡（JS 动态生成） ====== */
.direction-option {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .4rem .6rem;
    padding: .8rem 1rem;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: #fff;
    cursor: pointer;
    font-weight: 500;
    color: #334155;
    transition: border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.direction-option > .badge { margin-left: auto; }
.direction-option:hover {
    border-color: #a5b4fc;
    background: #f8faff;
}
.direction-option.selected {
    border-color: #6366f1;
    background: #eef2ff;
    box-shadow: inset 0 0 0 1px #6366f1;
    font-weight: 600;
    color: #3730a3;
}
.direction-option.selected::after {
    content: '\2713';
    color: #4f46e5;
    font-weight: 800;
}
.direction-option.disabled {
    opacity: .45;
    cursor: not-allowed;
    pointer-events: none;
    background: #f8fafc;
}

/* ====== 媒体类型选项卡：纵向堆叠在"分析范围"列里 ====== */
.media-type-option {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    padding: .7rem .9rem;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: #fff;
    cursor: pointer;
    transition: border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.media-type-option:hover {
    border-color: #a5b4fc;
    background: #f8faff;
}
.media-type-option.selected {
    border-color: #6366f1;
    background: #eef2ff;
    box-shadow: inset 0 0 0 1px #6366f1;
    color: #3730a3;
}
.mt-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-weight: 600;
}
.media-type-option .form-check-input {
    flex-shrink: 0;
    width: 1.05em;
    height: 1.05em;
}
.media-type-option.selected .mt-head::after {
    content: '\2713';
    margin-left: auto;
    color: #4f46e5;
    font-weight: 800;
}

/* ====== 统计卡片（摘要，JS 动态生成） ====== */
.stat-card {
    display: flex;
    align-items: center;
    gap: .85rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: .95rem 1.05rem;
    height: 100%;
    box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
    transition: box-shadow .2s ease, transform .2s ease;
}
.stat-card:hover {
    box-shadow: 0 12px 26px -16px rgba(15, 23, 42, .25);
    transform: translateY(-2px);
}
.stat-icon {
    flex: 0 0 auto;
    width: 46px;
    height: 46px;
    border-radius: 13px;
    display: grid;
    place-items: center;
    font-size: 1.3rem;
}
.stat-title {
    font-size: .78rem;
    font-weight: 600;
    color: var(--muted);
    letter-spacing: .02em;
}
.stat-value {
    font-size: 1.42rem;
    font-weight: 750;
    line-height: 1.25;
    color: var(--ink);
}
.stat-value .stat-unit {
    font-size: .85rem;
    font-weight: 600;
    color: var(--muted);
    margin-left: 2px;
}
.stat-sub { font-size: .74rem; color: #94a3b8; }
.stat-primary .stat-icon { background: #eef2ff; color: #4f46e5; }
.stat-primary .stat-value { color: #4338ca; }
.stat-success .stat-icon { background: #ecfdf5; color: #059669; }
.stat-success .stat-value { color: #047857; }
.stat-danger  .stat-icon { background: #fff1f2; color: #e11d48; }
.stat-danger  .stat-value { color: #be123c; }
.stat-warning .stat-icon { background: #fffbeb; color: #d97706; }
.stat-warning .stat-value { color: #b45309; }

/* ====== 结果页页头 ====== */
.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
    padding-top: .75rem;
}
.page-head h2 {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin: 0;
    font-size: 1.45rem;
    font-weight: 750;
    color: var(--ink);
    letter-spacing: -.01em;
}
.page-head h2 i { color: #0ea5e9; }

/* ====== 按钮 ====== */
.btn { border-radius: 10px; font-weight: 600; }
.btn:active { transform: translateY(1px); }
.btn-primary {
    --bs-btn-bg: #4f46e5;
    --bs-btn-border-color: #4f46e5;
    --bs-btn-hover-bg: #4338ca;
    --bs-btn-hover-border-color: #4338ca;
    --bs-btn-active-bg: #3730a3;
    --bs-btn-active-border-color: #3730a3;
    --bs-btn-disabled-bg: #4f46e5;
    --bs-btn-disabled-border-color: #4f46e5;
    --bs-btn-focus-shadow-rgb: 99, 102, 241;
    box-shadow: 0 8px 18px -8px rgba(79, 70, 229, .55);
}
.btn-warning {
    --bs-btn-color: #422006;
    --bs-btn-hover-color: #422006;
    --bs-btn-active-color: #422006;
    --bs-btn-bg: #fbbf24;
    --bs-btn-border-color: #fbbf24;
    --bs-btn-hover-bg: #f59e0b;
    --bs-btn-hover-border-color: #f59e0b;
    --bs-btn-active-bg: #d97706;
    --bs-btn-active-border-color: #d97706;
    --bs-btn-focus-shadow-rgb: 245, 158, 11;
    box-shadow: 0 8px 18px -8px rgba(245, 158, 11, .55);
}
.btn-outline-primary {
    --bs-btn-color: #4f46e5;
    --bs-btn-border-color: #c7d2fe;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #4f46e5;
    --bs-btn-hover-border-color: #4f46e5;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #4338ca;
    --bs-btn-active-border-color: #4338ca;
    --bs-btn-focus-shadow-rgb: 99, 102, 241;
}
.btn-outline-secondary {
    --bs-btn-color: #475569;
    --bs-btn-border-color: #cbd5e1;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #475569;
    --bs-btn-hover-border-color: #475569;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #334155;
    --bs-btn-active-border-color: #334155;
}

/* ====== 徽章 / 提示框 / 表单 ====== */
.badge {
    border-radius: 999px;
    font-weight: 600;
    padding: .4em .75em;
}
.alert { border-radius: 14px; }
.alert-info    { background: #f0f9ff; border-color: #e0f2fe; color: #0c4a6e; }
.alert-warning { background: #fffbeb; border-color: #fef3c7; color: #92400e; }
.alert-success { background: #ecfdf5; border-color: #d1fae5; color: #065f46; }
.alert-danger  { background: #fff1f2; border-color: #ffe4e6; color: #9f1239; }

.form-check-input:checked {
    background-color: #4f46e5;
    border-color: #4f46e5;
}
.form-check-input:focus,
.form-control:focus,
.form-select:focus {
    border-color: #a5b4fc;
    box-shadow: 0 0 0 .25rem rgba(99, 102, 241, .18);
}
.form-label { color: #334155; }

.list-group { --bs-list-group-border-color: #e9edf5; }
.list-group-item { padding: .65rem .9rem; }

/* ====== 加载动画（注意不要覆盖 sm 尺寸） ====== */
.spinner-border:not(.spinner-border-sm) {
    width: 3rem;
    height: 3rem;
}

/* ====== 结果图表 ====== */
#result-chart, #chart-img {
    max-width: 100%;
    height: auto;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: .75rem;
}

/* ====== 表格 ====== */
.table { --bs-table-border-color: #e9edf5; }
.table > :not(caption) > * > * { padding: .6rem .75rem; }
.table thead th {
    background: #f8fafc;
    color: #64748b;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .03em;
}
.table-sm td, .table-sm th { font-size: .85rem; }

/* 折叠面板 summary：小箭头 + 悬停反馈 */
details > summary {
    cursor: pointer;
    color: var(--muted);
    border-radius: 8px;
    padding: .2rem .45rem;
    transition: background .15s ease, color .15s ease;
}
details > summary::before {
    content: '\25B8';
    display: inline-block;
    margin-right: .35rem;
    transition: transform .15s ease;
}
details[open] > summary::before { transform: rotate(90deg); }
details > summary:hover {
    background: #eef2ff;
    color: #4338ca;
}

/* ====== 报告 issue：可点击展开逐包明细 ====== */
.issue-clickable {
    cursor: pointer;
    user-select: none;
}
.issue-clickable:hover { text-decoration: underline; }
.issue-chevron {
    display: inline-block;
    margin-right: 0.35rem;
    transition: transform 0.15s ease;
    font-size: 0.8em;
}
.issue-chevron.open { transform: rotate(90deg); }
.issue-explain {
    margin-top: 0.4rem;
    font-size: 0.85em;
    color: #64748b;
    line-height: 1.7;
}
.issue-table { font-size: 0.82em; }
.issue-table th { white-space: nowrap; }

/* ====== SIP 信令流程 — 时序阶梯图 ====== */
.sip-flow {
    max-height: 380px;
    overflow-y: auto;
}
.sl-head {
    position: sticky;
    top: 0;
    z-index: 2;
    background: #fff;
    display: flex;
    align-items: flex-end;
    border-bottom: 2px solid #e9edf5;
    padding-bottom: 4px;
    margin-bottom: 4px;
}
.sl-gutter { flex: 0 0 58px; }
.sl-track {
    flex: 1 1 auto;
    position: relative;
    display: grid;
    min-width: 0;
}
.sl-p {
    text-align: center;
    min-width: 0;
    padding: 0 4px;
    overflow: hidden;
}
.sl-name {
    font-weight: 600;
    font-size: 0.78rem;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;   /* 长 SIP 标识（分机/显示名）省略显示，悬停看 title */
}
.sl-ip {
    font-family: SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.66rem;
    color: #94a3b8;
}
.sl-role {
    display: inline-block;
    font-size: 0.66rem;
    line-height: 1.5;
    padding: 0 8px;
    border-radius: 8px;
}
/* RTP 部分：协商编码标签 + 媒体开始/结束标线 */
.sl-codecs {
    position: relative;
    z-index: 1;
    display: flex;
    gap: 6px;
    align-items: center;
    margin: 1px 0 3px 66px;   /* 时间线内、RTP 开始线下方，与标线标签对齐 */
    font-size: 0.7rem;
}
.sl-marker {
    position: relative;
    z-index: 1;
    height: 20px;
    margin: 3px 0;
}
.sl-marker::before {
    content: '';
    position: absolute;
    left: 58px;                 /* 与 .sl-lines 同起点（扣除时间列） */
    right: 0;
    top: 50%;
    border-top: 2px solid;
    opacity: .5;
}
.sl-marker .lb {
    position: absolute;
    left: 66px;
    top: 50%;
    transform: translateY(-50%);
    background: #fff;
    padding: 0 6px;
    font-size: 0.68rem;
    white-space: nowrap;
    border-radius: 4px;
}
.sl-marker.sl-start::before { border-color: #10b981; }
.sl-marker.sl-start .lb { color: #059669; }
.sl-marker.sl-end::before { border-color: #94a3b8; }
.sl-marker.sl-end .lb { color: #64748b; }
.sl-body { position: relative; }
/* 生命线容器：左侧让出与 .sl-t/.sl-gutter 等宽的时间列，
   使生命线的百分比定位与消息箭头所在的 .sl-track 完全同基准 */
.sl-lines {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 58px;
    right: 0;
}
.sl-line {
    position: absolute;
    top: 0;
    bottom: 0;
    border-left: 1px dashed #cbd5e1;
}
.sl-row {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 26px;
}
.sl-row:hover { background: #f5f8ff; }
.sl-t {
    flex: 0 0 58px;
    font-family: SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.66rem;
    color: #94a3b8;
    text-align: right;
    padding-right: 8px;
}
.sl-msg {
    position: absolute;
    top: 0;
    height: 100%;
    display: flex;
    align-items: center;
    color: #212529;
}
.sl-msg .ln {
    flex: 1 1 0;
    min-width: 5px;
    height: 0;
    border-top: 1.6px solid currentColor;
    position: relative;
}
.sl-msg .ln.arr-r::after,
.sl-msg .ln.arr-l::after {
    content: '';
    position: absolute;
    top: -3.6px;
    border: 3px solid transparent;
}
.sl-msg .ln.arr-r::after {
    right: -1px;
    border-left: 6px solid currentColor;
    border-right: 0;
}
.sl-msg .ln.arr-l::after {
    left: -1px;
    border-right: 6px solid currentColor;
    border-left: 0;
}
.sl-msg .lb {
    padding: 0 5px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
    background: #fff;
    line-height: 1.4;
    z-index: 1;
}
.sl-msg.sl-self {
    transform: translateX(-50%);
    justify-content: center;
}
/* SDP 行内编码标签：INVITE=支持、183/200=应答，弱化处理不抢信令方法名 */
.sl-sdp {
    margin-left: 3px;
    padding: 0 4px;
    font-size: 0.64rem;
    font-weight: 400;
    color: #475569;
    background: #f1f5f9;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    white-space: nowrap;
}
/* SDP 完整编码列表行：独立于消息行展示，不受消息框（信令线跨度）宽度限制 */
.sl-sdplist {
    position: relative;
    z-index: 1;
    margin: 0 0 3px 66px;   /* 时间线内，与 .sl-codecs 同缩进 */
    font-size: 0.66rem;
    color: #475569;
    line-height: 1.6;
}
.sl-msg.sip-req  { color: #4f46e5; }
.sl-msg.sip-prov { color: #94a3b8; }
.sl-msg.sip-ok   { color: #059669; }
.sl-msg.sip-err  { color: #e11d48; }

/* ====== 细滚动条 ====== */
.sip-flow::-webkit-scrollbar,
.table-responsive::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}
.sip-flow::-webkit-scrollbar-thumb,
.table-responsive::-webkit-scrollbar-thumb {
    background: #cbd5e1;
    border-radius: 8px;
}
.sip-flow::-webkit-scrollbar-track,
.table-responsive::-webkit-scrollbar-track { background: transparent; }

/* ====== 页脚 ====== */
footer {
    border-top: 1px solid var(--line);
    color: #94a3b8;
    font-size: .85rem;
}

/* ====== 页脚微信联系入口 ====== */
.wechat-contact {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .9rem;
    margin-top: .9rem;
}
/* 图片尚未放置时整个入口隐藏（hidden 属性会被上面的 display:flex 覆盖，需显式还原） */
.wechat-contact[hidden] { display: none; }

.wechat-qr-thumb {
    width: 104px;
    height: 104px;
    padding: 5px;
    object-fit: contain;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: .55rem;
    box-shadow: 0 1px 4px rgba(15, 23, 42, .06);
    cursor: zoom-in;
}

.wechat-contact-text {
    text-align: left;
    font-size: .92rem;
    color: #475569;
}
.wechat-contact-text .bi-wechat { color: #07c160; }

.wechat-qr-large {
    width: min(300px, 72vw);
    height: auto;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: .55rem;
}

/* 右下角常驻微信按钮：任何滚动位置都可见，点击打开二维码弹窗 */
.wechat-fab {
    position: fixed;
    right: 22px;
    bottom: 26px;
    z-index: 1030; /* 高于页面内容，低于弹窗遮罩(1050) */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    width: 58px;
    height: 58px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: linear-gradient(135deg, #07c160, #059f52);
    color: #fff;
    font-size: 12px;
    line-height: 1.15;
    box-shadow: 0 4px 14px rgba(7, 193, 96, .35);
    cursor: pointer;
    transition: transform .15s ease, box-shadow .15s ease;
}
.wechat-fab:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 18px rgba(7, 193, 96, .45);
    color: #fff;
}
.wechat-fab .bi { font-size: 20px; }
.wechat-fab[hidden] { display: none; }

/* ====== 微信放大弹窗（自绘，不依赖 Bootstrap JS）====== */
.wechat-modal {
    position: fixed;
    inset: 0;
    z-index: 1060; /* 高于悬浮按钮(1030) */
    display: flex;
    align-items: center;
    justify-content: center;
    animation: wechat-fade .15s ease-out; /* 只做入场淡入，关闭瞬时完成，不会卡在半开状态 */
}
.wechat-modal[hidden] { display: none; }
.wechat-modal-mask {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, .55);
}
.wechat-modal-card {
    position: relative;
    width: min(400px, 92vw);
    background: #fff;
    border-radius: .7rem;
    box-shadow: 0 12px 48px rgba(15, 23, 42, .3);
    overflow: hidden;
}
.wechat-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: .65rem 1rem;
    border-bottom: 1px solid var(--line);
    font-weight: 600;
    color: #1e293b;
}
.wechat-modal-head .bi { color: #07c160; margin-right: .35rem; }
.wechat-modal-x {
    border: none;
    background: none;
    font-size: 1.5rem;
    line-height: 1;
    color: #94a3b8;
    cursor: pointer;
    padding: 0 .2rem;
}
.wechat-modal-x:hover { color: #475569; }
.wechat-modal-body { padding: 1.1rem; text-align: center; }
.wechat-modal-tip { color: #64748b; font-size: .85rem; margin: .7rem 0 0; }
@keyframes wechat-fade { from { opacity: 0; } to { opacity: 1; } }

/* ====== 响应式 ====== */
@media (max-width: 991.98px) {
    .upload-box {
        min-height: 110px;
        padding: 16px 10px;
    }
    .upload-box i {
        width: 46px;
        height: 46px;
        font-size: 1.3rem;
        border-radius: 12px;
    }
}
@media (max-width: 767.98px) {
    .card-body { padding: 1rem; }
    .card-header { padding: .8rem 1rem; }
    .stat-value { font-size: 1.15rem; }
    .hero-title { font-size: 1.5rem; }
    .display-5 { font-size: 1.8rem; }
}
