/* ============================================================
   Glass 模板 · iOS 26 液态玻璃风格
   契约:与 default 模板同一套 CSS 变量名 + app.js 输出的类名
   主题:[data-theme="light" | "dark" | "wallpaper"](真实环境挂在 <html>,预览环境挂在手机框上)
   ============================================================ */

/* ---------- 变量:与后台注入契约一致 ---------- */
:root, [data-theme] {
    /* 后台可注入的契约变量(注入块在本文件之后,同名会覆盖这里) */
    --brand-primary: #0a84ff;
    --bubble-self: var(--brand-primary);
    /* 质感关键:灰底 + 白气泡,气泡靠投影从背景"浮起来"(default 模板的立体感来源) */
    --bubble-other: #ffffff;
    --bubble-self-text: #ffffff;
    --bubble-other-text: #0b0b0d;
    --bubble-radius: 20px;
    --bg-chat: #f2f2f7;
    --bg-bottom: #f2f2f7;
    --header-bg: #ffffff;
    --header-text: #1c1c1e;
    --accent-green: var(--brand-primary);
    --avatar-radius: 50%;

    /* 气泡光影配方:外层浮起投影 + 顶部受光内高光 + 发丝描边(各主题覆盖)。
       注意:含 color-mix 的增强版在文件末尾的 @supports 块里定义——
       color-mix 写进自定义属性后 var() 兜底救不了(IACVT),旧内核会把
       气泡背景整个打成透明,必须用 @supports 隔离 */
    --bubble-other-fx:
        0 2px 8px rgba(24, 28, 45, 0.08),
        0 1px 2px rgba(24, 28, 45, 0.05),
        inset 0 1px 0 rgba(255, 255, 255, 0.9),
        inset 0 0 0 1px rgba(24, 28, 45, 0.035);
    --bubble-self-fx:
        inset 0 1px 0 rgba(255, 255, 255, 0.38),
        0 2px 8px rgba(24, 28, 45, 0.14),
        0 1px 2px rgba(24, 28, 45, 0.06);

    /* glass 模板内部变量 */
    --text-dim: rgba(60, 60, 67, 0.6);
    --divider-ink: rgba(60, 60, 67, 0.5);
    --tint-strength: 62%;
    --shine-edge: rgba(0, 0, 0, 0.07);
    --shine-hi: rgba(255, 255, 255, 1);
    --shine-hi2: rgba(255, 255, 255, 0.8);
    --shine-glow: rgba(255, 255, 255, 0.5);
    --shine-dark: rgba(0, 0, 0, 0.12);
    --glass-drop: rgba(24, 26, 48, 0.1);
    --glass-drop2: rgba(24, 26, 48, 0.06);
    --btn-bg: rgba(120, 120, 128, 0.12);
    --btn-bg-hover: rgba(120, 120, 128, 0.22);
    --caret: var(--brand-primary);
    --focus-ring: rgba(10, 132, 255, 0.75);
    --emoji-panel-bg: rgba(255, 255, 255, 0.9);
    --modal-bg: rgba(0, 0, 0, 0.72);
    --glass-text-shadow: none;
    --status-green: #30d158;
    --typing-dot: rgba(120, 120, 128, 0.6);
}

[data-theme="dark"] {
    --bubble-other: #2a2a30;
    --bubble-other-text: rgba(255, 255, 255, 0.96);
    --bg-chat: #000000;
    --bg-bottom: #000000;
    --header-bg: #1c1c20;
    --header-text: rgba(255, 255, 255, 0.96);

    /* 深色质感:顶部一线受光 + 沉底黑影,气泡从纯黑上浮起(color-mix 版在末尾 @supports) */
    --bubble-other-fx:
        inset 0 1px 0 rgba(255, 255, 255, 0.07),
        inset 0 0 0 1px rgba(255, 255, 255, 0.045),
        0 2px 10px rgba(0, 0, 0, 0.45);
    --bubble-self-fx:
        inset 0 1px 0 rgba(255, 255, 255, 0.28),
        0 2px 10px rgba(0, 0, 0, 0.5);

    --text-dim: rgba(235, 235, 245, 0.6);
    --divider-ink: rgba(235, 235, 245, 0.5);
    --tint-strength: 45%;
    --shine-edge: rgba(255, 255, 255, 0.12);
    --shine-hi: rgba(255, 255, 255, 0.55);
    --shine-hi2: rgba(255, 255, 255, 0.3);
    --shine-glow: rgba(255, 255, 255, 0.13);
    --shine-dark: rgba(0, 0, 0, 0.5);
    --glass-drop: rgba(0, 0, 0, 0.5);
    --glass-drop2: rgba(0, 0, 0, 0.3);
    --btn-bg: rgba(120, 120, 128, 0.24);
    --btn-bg-hover: rgba(120, 120, 128, 0.38);
    --caret: #ffffff;
    --focus-ring: rgba(255, 255, 255, 0.8);
    --emoji-panel-bg: rgba(28, 28, 32, 0.92);
}

[data-theme="wallpaper"] {
    /* 真机:壁纸上的接收气泡是半透明玻璃 + 白字(见 Apple 官方截图),不是实心白底 */
    --bubble-other: rgba(255, 255, 255, 0.22);
    --bubble-other-text: #ffffff;
    --bg-chat: transparent;
    --bg-bottom: transparent;
    --header-bg: #ffffff;
    --header-text: rgba(255, 255, 255, 0.96);

    --text-dim: rgba(255, 255, 255, 0.65);
    --divider-ink: rgba(255, 255, 255, 0.85);
    --tint-strength: 16%;
    --shine-edge: rgba(255, 255, 255, 0.13);
    --shine-hi: rgba(255, 255, 255, 0.85);
    --shine-hi2: rgba(255, 255, 255, 0.5);
    --shine-glow: rgba(255, 255, 255, 0.28);
    --shine-dark: rgba(0, 0, 0, 0.22);
    --glass-drop: rgba(8, 10, 40, 0.32);
    --glass-drop2: rgba(8, 10, 40, 0.18);
    --btn-bg: rgba(255, 255, 255, 0.16);
    --btn-bg-hover: rgba(255, 255, 255, 0.28);
    --caret: #ffffff;
    --focus-ring: rgba(255, 255, 255, 0.8);
    --glass-text-shadow: 0 1px 3px rgba(20, 20, 60, 0.25);
    /* 玻璃气泡上的"正在输入"点用白色系 */
    --typing-dot: rgba(255, 255, 255, 0.75);

    /* 壁纸质感:玻璃气泡的边缘高光 + 彩色投影(color-mix 版在末尾 @supports) */
    --bubble-other-fx:
        inset 0 1px 0 rgba(255, 255, 255, 0.35),
        inset 0 0 0 1px rgba(255, 255, 255, 0.16),
        0 4px 14px rgba(8, 10, 40, 0.2);
    --bubble-self-fx:
        inset 0 1px 0 rgba(255, 255, 255, 0.4),
        0 6px 18px rgba(10, 100, 255, 0.35);
}

/* color-mix 增强层:只在支持的内核(iOS 16.2+ / Chrome 111+)启用品牌色派生的
   渐变与彩影;旧内核停留在上面的 rgba 兜底版,气泡永远有底色 */
@supports (background: color-mix(in srgb, red, #fff)) {
    :root, [data-theme] {
        /* 蓝气泡顶部受光渐变;78% 处收敛回纯色,保证底部小尾巴颜色严格一致 */
        --bubble-self-grad: linear-gradient(180deg, color-mix(in srgb, var(--bubble-self) 84%, #ffffff), var(--bubble-self) 78%);
        --bubble-self-fx:
            inset 0 1px 0 rgba(255, 255, 255, 0.38),
            0 2px 8px color-mix(in srgb, var(--bubble-self) 32%, transparent),
            0 1px 2px rgba(24, 28, 45, 0.06);
    }
    [data-theme="dark"] {
        --bubble-self-fx:
            inset 0 1px 0 rgba(255, 255, 255, 0.28),
            0 2px 10px color-mix(in srgb, var(--bubble-self) 35%, transparent);
    }
    [data-theme="wallpaper"] {
        --bubble-self-fx:
            inset 0 1px 0 rgba(255, 255, 255, 0.4),
            0 6px 18px color-mix(in srgb, var(--bubble-self) 40%, transparent);
    }
}

/* ---------- 基础 ---------- */
* {
    margin: 0; padding: 0; box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none; /* 禁全局长按菜单(图片长按不弹"存储图像") */
}
/* 气泡文字显式可选,方便访客长按复制(与 default 模板同契约) */
.bubble {
    -webkit-user-select: text;
    user-select: text;
    -webkit-touch-callout: default;
}
html, body { height: 100%; }

body {
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", "Helvetica Neue", "Microsoft YaHei", sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    background: var(--bg-chat);
}

/* 淡品牌蓝渐变底(light):纯色灰底让毛玻璃无物可折射,给一层从顶到底淡出的品牌蓝,
   顶栏/输入区的backdrop-filter立刻有内容可糊;透明度压到2-6%,不影响读消息。
   color-mix版放@supports隔离(同文件既有惯例),旧内核回退到固定淡蓝。 */
html[data-theme="light"] #app {
    background: linear-gradient(180deg, rgba(10,132,255,0.05) 0%, rgba(10,132,255,0.02) 36%, var(--bg-chat) 78%);
}
@supports (background: color-mix(in srgb, red, blue)) {
    html[data-theme="light"] #app {
        background: linear-gradient(180deg,
            color-mix(in srgb, var(--brand-primary) 6%, var(--bg-chat)) 0%,
            color-mix(in srgb, var(--brand-primary) 3%, var(--bg-chat)) 36%,
            var(--bg-chat) 78%);
    }
}

#app {
    position: relative;
    /* --app-height 由 shared/js/app.js 用 visualViewport 维护:iOS 键盘是覆盖式,
       不消费它的话底部输入栏会被键盘挡住;无 app.js 时(本地预览)回退 100% */
    height: var(--app-height, 100%);
    overflow: hidden;
    background: var(--bg-chat);
    color: var(--header-text);
}

/* ---------- 彩色壁纸(glass.js 在 wallpaper 主题下注入) ---------- */
.lg-wallpaper {
    position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 0;
    background: linear-gradient(160deg, #2e3f9e 0%, #4b3fb8 30%, #7a3fb0 55%, #b8408f 78%, #d4645a 100%);
    overflow: hidden;
    pointer-events: none;
}
.lg-blob {
    position: absolute; border-radius: 50%;
    filter: blur(64px); opacity: 0.8; will-change: transform;
}
.lg-blob-1 { width: 56vmax; height: 56vmax; top: -16%; left: -14%;
    background: radial-gradient(circle at 35% 35%, #8b7bff, transparent 62%);
    animation: lgDrift1 28s ease-in-out infinite alternate; }
.lg-blob-2 { width: 48vmax; height: 48vmax; bottom: -18%; right: -12%;
    background: radial-gradient(circle at 55% 45%, #ff6aa9, transparent 60%);
    animation: lgDrift2 34s ease-in-out infinite alternate; }
.lg-blob-3 { width: 40vmax; height: 40vmax; top: 30%; left: 44%;
    background: radial-gradient(circle at 50% 50%, #35c8ff, transparent 58%);
    animation: lgDrift3 23s ease-in-out infinite alternate; }
@keyframes lgDrift1 { to { transform: translate(13vw, 9vh) scale(1.12); } }
@keyframes lgDrift2 { to { transform: translate(-11vw, -7vh) scale(0.92); } }
@keyframes lgDrift3 { to { transform: translate(-9vw, 11vh) scale(1.18) rotate(18deg); } }
.lg-ring {
    position: absolute; border-radius: 50%;
    border: 1.5px solid rgba(255, 255, 255, 0.26);
}
.lg-ring-1 { width: 52vmin; height: 52vmin; top: 8%; left: -8%; }
.lg-ring-2 { width: 66vmin; height: 66vmin; bottom: -6%; right: -10%; border-color: rgba(255, 255, 255, 0.18); }

/* ---------- 液态玻璃材质 ----------
   作用在各个"悬浮小件"上(真机形态:分散的独立玻璃件,不是通栏大板):
   元素自身 backdrop-filter 负责模糊(或被 glass.js 升级成折射),
   ::before 是着色层,::after 是镜面高光。 */
.composer-plus, .input-dock, .quick-msg-btn {
    position: relative;
    isolation: isolate;
    box-shadow: 0 10px 26px var(--glass-drop), 0 2px 6px var(--glass-drop2);
    backdrop-filter: blur(16px) saturate(180%);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
}
.composer-plus::before, .input-dock::before, .quick-msg-btn::before {
    content: "";
    position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -1;
    border-radius: inherit;
    pointer-events: none;
    /* 第一行是旧内核兜底(实心底,牺牲通透保可读),支持 color-mix 的内核走第二行 */
    background: var(--bg-bottom);
    background: color-mix(in srgb, var(--bg-bottom) var(--tint-strength), transparent);
}
.composer-plus::after, .input-dock::after, .quick-msg-btn::after {
    content: "";
    position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1;
    border-radius: inherit;
    pointer-events: none;
    box-shadow:
        inset 0 0 0 1px var(--shine-edge),
        inset 1.8px 3px 0 -1.5px var(--shine-hi),
        inset -2px -2px 0 -1.5px var(--shine-hi2),
        inset 0 10px 28px -10px var(--shine-glow),
        inset 0 -7px 14px -9px var(--shine-dark);
}

/* ---------- 顶栏:通栏玻璃条(骨架同 default 模板,材质为玻璃) ---------- */
.header {
    position: absolute;
    top: 0; left: 0; right: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: calc(9px + env(safe-area-inset-top)) 16px 9px;
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
    color: var(--header-text);
    isolation: isolate;
    backdrop-filter: blur(16px) saturate(180%);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
    box-shadow: 0 8px 24px var(--glass-drop2);
}
.header::before {
    content: "";
    position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -1;
    pointer-events: none;
    /* 旧内核兜底:实心顶栏 */
    background: var(--header-bg);
    background: color-mix(in srgb, var(--header-bg) var(--tint-strength), transparent);
}
.header::after {
    content: "";
    position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1;
    pointer-events: none;
    box-shadow:
        inset 0 1px 0 var(--shine-hi2),
        inset 0 -1px 0 var(--shine-edge);
}
.header-id {
    display: flex; align-items: center; gap: 10px;
    min-width: 0;
}
.header-logo {
    width: 36px; height: 36px;
    border-radius: var(--avatar-radius);
    object-fit: cover;
    flex-shrink: 0;
    box-shadow: inset 0 1px 1px rgba(255,255,255,0.4), 0 2px 8px rgba(20, 40, 120, 0.22);
}
.header-meta { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.header-title {
    font-size: 16px; font-weight: 600;
    letter-spacing: 0.2px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    text-shadow: var(--glass-text-shadow);
}
/* 连接状态:标题下方的小字(骨架同 default)。app.js 会把 connected/disconnected
   类打在 #statusDot 上,文本写进 #status,两个必须是独立元素 */
.header-status {
    display: flex; align-items: center; gap: 5px;
    min-width: 0;
}
#statusDot {
    width: 6px; height: 6px; border-radius: 50%;
    background: #a0a3ad;
    flex-shrink: 0;
    transition: background 0.3s;
}
#statusDot.connected {
    background: var(--status-green);
    box-shadow: 0 0 6px var(--status-green);
}
#statusDot.disconnected { background: #ff453a; }
#status {
    font-size: 11.5px;
    color: var(--text-dim);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* app.js 断线时注入的重连按钮 ↻(内联 span):字号只有 11.5px,
   用负外边距把命中区扩到手指能点中的大小 */
#status span[onclick] {
    display: inline-block;
    padding: 14px;
    margin: -14px;
}

/* ---------- 消息流 ---------- */
.chat-stream {
    position: absolute; top: 0; right: 0; bottom: 0; left: 0;
    z-index: 5;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* contain:滚到边界不把滚动链传给文档(安卓下拉刷新/iOS 整页回弹) */
    overscroll-behavior: contain;
    padding: calc(72px + env(safe-area-inset-top)) 14px calc(158px + env(safe-area-inset-bottom));
    /* 横屏刘海机:左右让出安全区 */
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
    display: flex; flex-direction: column;
    scrollbar-width: none;
}
.chat-stream::-webkit-scrollbar { display: none; }
/* emoji 面板(覆盖层)打开时给消息区让位,由 glass.js 切换该类 */
#app.lg-emoji-open .chat-stream { padding-bottom: calc(430px + env(safe-area-inset-bottom)); }

.welcome-text {
    align-self: center;
    max-width: 86%;
    text-align: center;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--divider-ink);
    margin: 2px 0 14px;
}

/* glass.js 注入的时间戳 / 已送达 */
.lg-time-stamp {
    align-self: center;
    font-size: 11px; font-weight: 500;
    color: var(--divider-ink);
    margin: 10px 0 12px;
    /* iOS风 pill 衬底 */
    background: rgba(120, 120, 128, 0.12);
    border-radius: 999px;
    padding: 3px 10px;
}

/* "正在输入"三点跳动气泡(glass.js 把 typingIndicator 文本升级为视觉三点) */
.lg-dots {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 1px;
}
.lg-dots i {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--typing-dot);
    animation: lg-dot-bounce 1.1s infinite ease-in-out;
}
.lg-dots i:nth-child(2) { animation-delay: 0.15s; }
.lg-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes lg-dot-bounce {
    0%, 60%, 100% { transform: translateY(0); opacity: .45; }
    30% { transform: translateY(-4px); opacity: 1; }
}
.lg-receipt {
    align-self: flex-end;
    font-size: 11px; font-weight: 500;
    color: var(--divider-ink);
    margin: -9px 6px 12px 0;
}

.message {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    margin-bottom: 12px;
    animation: lgMsgIn 0.45s cubic-bezier(0.2, 0.9, 0.3, 1.08) both;
}
.message.self { justify-content: flex-end; }
.message.cont-next { margin-bottom: 2px; }

.message .avatar {
    width: 28px; height: 28px;
    border-radius: var(--avatar-radius);
    object-fit: cover;
    flex-shrink: 0;
    background: var(--btn-bg);
    box-shadow: 0 1px 3px rgba(24, 28, 45, 0.18), inset 0 0 0 1px rgba(24, 28, 45, 0.04);
    transition: opacity 0.15s;
}
/* 同组只在最后一条显示头像,其余占位隐藏,保证气泡左缘对齐 */
.message.other.cont-next .avatar { opacity: 0; }
/* 没有头像元素的 other 行(如 app.js 的"正在输入"指示器)补一个头像位,
   否则气泡会比同组的靠左错一格 */
.message.other:not(:has(.avatar)) { padding-left: 36px; }

@keyframes lgMsgIn {
    from { opacity: 0; transform: translateY(14px) scale(0.96); }
    to   { opacity: 1; transform: none; }
}

/* ---------- 气泡(iMessage 形态) ---------- */
.bubble {
    position: relative;
    max-width: 72%;
    padding: 10px 15px;
    /* 真机是 17px(SF Pro 正文档位),中文同档更舒展 */
    font-size: 17px; line-height: 1.33;
    border-radius: var(--bubble-radius);
    word-break: break-word;
    white-space: pre-wrap;
}
/* 纯表情消息:真机不带气泡,直接大号裸排 */
.bubble.emoji-only {
    background: none !important;
    padding: 0 2px;
    font-size: 42px; line-height: 1.15;
    box-shadow: none;
}
.bubble.emoji-only::before, .bubble.emoji-only::after { display: none; }
.message.other .bubble {
    background: var(--bubble-other);
    color: var(--bubble-other-text);
    box-shadow: var(--bubble-other-fx);
}
.message.self .bubble {
    background: var(--bubble-self-grad, var(--bubble-self));
    color: var(--bubble-self-text);
    box-shadow: var(--bubble-self-fx);
}
/* 壁纸主题接收气泡:玻璃材质需要 backdrop 模糊(真机同款)。
   注意这是逐气泡的 backdrop 层、随消息数线性增长的开销——
   壁纸主题是展示型档位,保真优先;黑白主题无此路径 */
[data-theme="wallpaper"] .message.other .bubble,
[data-theme="wallpaper"] .message.other .voice-msg {
    backdrop-filter: blur(18px) saturate(160%);
    -webkit-backdrop-filter: blur(18px) saturate(160%);
}

/* 连续消息:发送方一侧相邻圆角收小 */
.message.other .bubble.cont-top { border-top-left-radius: 6px; }
.message.other .bubble.cont-bottom { border-bottom-left-radius: 6px; }
.message.self .bubble.cont-top { border-top-right-radius: 6px; }
.message.self .bubble.cont-bottom { border-bottom-right-radius: 6px; }

/* 小尾巴:两层伪元素,一层同色块 + 一层背景色遮罩裁出弯钩。
   壁纸主题背景非纯色会穿帮,自动隐藏。 */
.bubble.tail::before, .bubble.tail::after {
    content: "";
    position: absolute;
    bottom: -1px;
    height: 16px;
}
.message.self .bubble.tail::before {
    right: -6px;
    border-right: 16px solid var(--bubble-self);
    border-bottom-left-radius: 13px 11px;
}
.message.self .bubble.tail::after {
    right: 0;
    width: 10px;
    background: var(--bg-chat);
    border-bottom-left-radius: 8px;
    transform: translateX(10px);
}
.message.other .bubble.tail::before {
    left: -6px;
    border-left: 16px solid var(--bubble-other);
    border-bottom-right-radius: 13px 11px;
}
.message.other .bubble.tail::after {
    left: 0;
    width: 10px;
    background: var(--bg-chat);
    border-bottom-right-radius: 8px;
    transform: translateX(-10px);
}
[data-theme="wallpaper"] .bubble.tail::before,
[data-theme="wallpaper"] .bubble.tail::after { display: none; }
/* 圆角调小时尾巴形状不成立,glass.js 检测到 --bubble-radius < 12px 会挂上这个类 */
.lg-no-tail .bubble.tail::before,
.lg-no-tail .bubble.tail::after { display: none; }

/* 气泡内链接 */
.bubble a, .msg-link {
    color: var(--brand-primary);
    text-decoration: underline;
    word-break: break-all;
}
.message.self .bubble a, .message.self .bubble .msg-link {
    color: var(--bubble-self-text);
}

/* 引用/回复预览(子元素由 app.js renderReplyPreview 动态注入,类名契约见 app.js:1338-1407) */
.reply-preview {
    border-left: 3px solid rgba(127, 127, 127, 0.45);
    border-left: 3px solid color-mix(in srgb, currentColor 40%, transparent);
    padding: 2px 8px;
    margin-bottom: 6px;
    font-size: 12.5px;
    opacity: 0.75;
    border-radius: 4px;
}
.reply-preview-header { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; }
.reply-preview-name { font-weight: 600; font-size: 12px; }
.reply-preview-tag { font-size: 10.5px; opacity: 0.65; }
.reply-preview-content {
    font-size: 12.5px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
/* 引用媒体缩略图:同 default,宽度撑满引用条、固定 140 高 cover 裁切 */
.reply-preview-img {
    display: block;
    width: 100%;
    height: 140px;
    object-fit: cover;
    border-radius: 8px;
    margin-top: 4px;
    background: rgba(127, 127, 127, 0.15);
}
.reply-video-thumb {
    position: relative;
    width: 100%; height: 140px;
    border-radius: 8px;
    overflow: hidden;
    margin-top: 4px;
}
.reply-video-thumb img { width: 100%; height: 100%; object-fit: cover; }
.reply-video-play {
    position: absolute; top: 0; right: 0; bottom: 0; left: 0;
    display: flex; align-items: center; justify-content: center;
}
.reply-video-play::after {
    content: "";
    border-left: 12px solid rgba(255, 255, 255, 0.92);
    border-top: 7px solid transparent;
    border-bottom: 7px solid transparent;
    margin-left: 2px;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.4));
}
/* 兜底:气泡内任何动态注入的图片都不许撑破气泡 */
.bubble img { max-width: 100%; }

/* ---------- 图片 / 视频 / 语音 / 链接消息 ---------- */
/* 媒体统一卡片:全部 180×120 + cover 裁切(业主定的规则,保证消息流里每张一样大) */
.msg-img {
    width: 180px; height: 120px;
    object-fit: cover;
    border-radius: 14px;
    display: block;
    cursor: pointer;
    background: var(--bubble-other);
    box-shadow: 0 4px 14px var(--glass-drop2), inset 0 0 0 1px rgba(127,127,127,0.12);
}
.img-placeholder {
    width: 180px; height: 120px;
    border-radius: 14px;
    background: var(--bubble-other);
    color: var(--text-dim);
    display: flex; align-items: center; justify-content: center;
    box-shadow: var(--bubble-other-fx);
}
.img-placeholder svg { width: 34px; height: 34px; }

.video-msg {
    position: relative;
    width: 180px; height: 120px;
    border-radius: 14px;
    overflow: hidden;
    cursor: pointer;
    background: #17181c;
    box-shadow: 0 4px 14px var(--glass-drop2);
}
/* app.js 原位播放的 video 元素同样锁定卡片尺寸 */
.video-msg-player, .inplace-video {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover;
    display: block;
    border-radius: 14px;
}
.video-cover { width: 100%; height: 100%; object-fit: cover; }
.video-cover-placeholder {
    width: 100%; height: 100%;
    background: linear-gradient(150deg, #2a2c33, #17181c);
}
.play-icon {
    position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 44px; height: 44px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.5), inset 0 0 0 1px rgba(255,255,255,0.2);
}
.play-icon::after {
    content: "";
    position: absolute; top: 50%; left: 55%;
    transform: translate(-50%, -50%);
    border-left: 14px solid #fff;
    border-top: 9px solid transparent;
    border-bottom: 9px solid transparent;
}
.video-duration {
    position: absolute; right: 8px; bottom: 6px;
    font-size: 11px; color: #fff;
    background: rgba(0, 0, 0, 0.45);
    padding: 2px 7px; border-radius: 100px;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.video-msg.loading .play-icon { opacity: 0.4; }

.voice-msg {
    display: flex; align-items: center; gap: 8px;
    min-width: 120px;
    padding: 10px 14px;
    border-radius: var(--bubble-radius);
    background: var(--bubble-other);
    color: var(--bubble-other-text);
    box-shadow: var(--bubble-other-fx);
    cursor: pointer;
}
.message.self .voice-msg {
    background: var(--bubble-self-grad, var(--bubble-self));
    color: var(--bubble-self-text);
    box-shadow: var(--bubble-self-fx);
}
.voice-icon { display: flex; }
.voice-icon svg { width: 18px; height: 18px; }
.voice-waveform { display: flex; align-items: center; gap: 2.5px; }
.voice-bar {
    width: 3px; border-radius: 2px;
    background: currentColor;
}
.voice-bar.inactive { opacity: 0.35; }
.voice-duration { font-size: 12.5px; opacity: 0.8; }
.voice-msg.playing .voice-icon { animation: lgVoicePulse 1s ease-in-out infinite; }
@keyframes lgVoicePulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

.link-msg { cursor: pointer; }
.link-title { font-weight: 600; }
.link-desc { font-size: 13px; opacity: 0.75; margin-top: 3px; }

/* ---------- 底部悬浮区 ---------- */
.bottom-dock {
    position: absolute;
    left: 10px; right: 10px;
    left: max(10px, env(safe-area-inset-left));
    right: max(10px, env(safe-area-inset-right));
    bottom: calc(12px + env(safe-area-inset-bottom));
    z-index: 20;
    display: flex; flex-direction: column;
    gap: 10px;
}
.keyboard-open .bottom-dock { bottom: 8px; }

.quick-msg-bar {
    display: flex; gap: 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain; /* 横滑到头不触发浏览器侧滑返回 */
    scrollbar-width: none;
    padding: 2px;
}
.quick-msg-bar::-webkit-scrollbar { display: none; }
.quick-msg-bar:empty { display: none; }

.quick-msg-btn {
    flex-shrink: 0;
    border: none;
    border-radius: 100px;
    background: transparent;
    color: var(--header-text);
    font-size: 13px; font-family: inherit;
    padding: 9px 17px;
    cursor: pointer;
    /* 注意别用过冲型贝塞尔(y>1),回弹会先放大再落回,视觉上像气泡胀了一下 */
    transition: transform 0.15s ease-out, opacity 0.2s;
    touch-action: manipulation;
    text-shadow: var(--glass-text-shadow);
}
.quick-msg-btn:active { transform: scale(0.92); }
.quick-msg-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.quick-msg-btn.sending { opacity: 0.5; pointer-events: none; }
/* 触屏设备:快捷按钮不上 backdrop(与 glass.js 不给它们上折射的意图一致,
   否则每个小按钮都是独立 backdrop 层,滚动时逐帧重采样) */
@media (pointer: coarse) {
    .quick-msg-btn {
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }
}
.quick-msg-btn.hide { animation: lgQuickHide 0.25s ease forwards; }
@keyframes lgQuickHide {
    /* 只动 opacity/transform;width 从 auto 到 0 无法插值,会中途跳变 */
    to { opacity: 0; transform: scale(0.85); }
}

/* 真机形态:"+" 是独立的圆形玻璃钮,输入药丸单独一条 */
.composer-row {
    display: flex; align-items: center; gap: 8px;
}
.composer-plus {
    width: 44px; height: 44px;
    flex-shrink: 0;
    border: none; border-radius: 50%;
    background: transparent;
    color: var(--header-text);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: transform 0.15s ease-out;
    touch-action: manipulation;
}
.composer-plus:active { transform: scale(0.9); }
.composer-plus:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.composer-plus svg { width: 22px; height: 22px; position: relative; z-index: 2; }

.input-dock {
    flex: 1; min-width: 0;
    display: flex; align-items: center; gap: 2px;
    min-height: 44px;
    border-radius: 22px;
    padding: 4px 5px 4px 16px;
}
.emoji-btn {
    position: relative; z-index: 2;
    /* 44px 命中区(iOS HIG),视觉图标仍是 21px;它紧邻输入框,太小会误触弹键盘。
       负上下外边距抵消高度,不把 44px 高的输入药丸撑胖 */
    width: 44px; height: 44px;
    margin-top: -6px; margin-bottom: -6px;
    flex-shrink: 0;
    border: none; border-radius: 50%;
    background: transparent;
    color: var(--text-dim);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: color 0.2s, transform 0.15s;
    touch-action: manipulation;
}
.emoji-btn:hover { color: var(--header-text); }
.emoji-btn:active { transform: scale(0.9); }
.emoji-btn:focus-visible,
.composer-plus:focus-visible,
.send-pill:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.emoji-btn svg { width: 21px; height: 21px; }
.emoji-btn.active { color: var(--header-text); }

.text-input {
    position: relative; z-index: 2;
    flex: 1; min-width: 0;
    border: none; outline: none; background: transparent;
    color: var(--header-text);
    caret-color: var(--caret);
    /* 16px:小于这个值 iOS Safari 聚焦时会自动缩放页面 */
    font-size: 16px; font-family: inherit;
    padding: 8px 4px;
}
.text-input::placeholder { color: var(--text-dim); }

.send-pill {
    position: relative; z-index: 2;
    width: 34px; height: 34px;
    flex-shrink: 0;
    border: none;
    border-radius: 17px;
    margin-left: 2px;
    background: var(--accent-green);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    box-shadow: inset 0 1.5px 0 rgba(255,255,255,0.45), inset 0 0 0 1px rgba(255,255,255,0.15), 0 4px 14px rgba(24, 28, 45, 0.28);
    box-shadow: inset 0 1.5px 0 rgba(255,255,255,0.45), inset 0 0 0 1px rgba(255,255,255,0.15), 0 4px 14px color-mix(in srgb, var(--accent-green) 45%, transparent);
    transition: transform 0.15s ease-out, opacity 0.15s, width 0.18s ease-out, margin 0.18s ease-out, filter 0.2s;
    touch-action: manipulation;
}
/* 真机行为:没有文字时发送按钮不存在,输入后才弹出(纯 CSS,依赖 :has) */
.input-dock:has(.text-input:placeholder-shown) .send-pill {
    width: 0; margin-left: 0; padding: 0;
    opacity: 0;
    transform: scale(0.4);
    pointer-events: none;
}
.send-pill { overflow: hidden; }
.send-pill::after {
    content: "";
    flex-shrink: 0;
    width: 18px; height: 18px;
    background: #fff;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7'/%3E%3C/svg%3E") center / contain no-repeat;
}
.send-pill:hover { filter: brightness(1.1); }
.send-pill:active { transform: scale(0.88); }
.send-pill.disabled { opacity: 0.45; pointer-events: none; }

/* ---------- 发送失败标记(app.js send-failed) ---------- */
.message.send-failed .bubble { opacity: 0.6; }
.message .send-failed-mark {
    font-size: 11px; color: #ff453a;
}

/* ---------- toast ---------- */
.toast {
    position: fixed;
    top: calc(70px + env(safe-area-inset-top));
    left: 50%;
    transform: translateX(-50%);
    z-index: 1001; /* 要压过 modal/loading 浮层(1000),否则弹窗期间的报错提示被盖住 */
    font-size: 13.5px;
    color: var(--header-text);
    padding: 10px 20px;
    border-radius: 100px;
    background: var(--header-bg);
    background: color-mix(in srgb, var(--header-bg) 70%, transparent);
    backdrop-filter: blur(16px) saturate(180%);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
    box-shadow: 0 8px 24px var(--glass-drop), inset 0 1px 0 var(--shine-hi2), inset 0 0 0 1px var(--shine-edge);
    animation: lgToastIn 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.1);
}
.toast.warning { color: #b25000; }
.toast.error { color: #ff453a; }
@keyframes lgToastIn {
    from { opacity: 0; transform: translateX(-50%) translateY(-10px) scale(0.94); }
    to   { opacity: 1; transform: translateX(-50%); }
}
/* app.js 淡出时引用的是这个名字(toast.style.animation='toastOut ...'),必须提供 */
@keyframes toastOut {
    from { opacity: 1; transform: translateX(-50%); }
    to   { opacity: 0; transform: translateX(-50%) translateY(-10px) scale(0.94); }
}

/* ---------- 弹窗(app.js 动态创建:#image-modal / #video-modal / 加载浮层) ---------- */
.image-modal, .video-modal {
    position: fixed; top: 0; right: 0; bottom: 0; left: 0;
    z-index: 1000;
    background: var(--modal-bg);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    display: flex; align-items: center; justify-content: center;
    overscroll-behavior: contain; /* iOS 上拖弹窗背景不回弹整个文档 */
}
.image-modal img { max-width: 100%; max-height: 80vh; border-radius: 14px; }
.video-modal video { max-width: 100%; max-height: 80vh; }

/* app.js 动态创建的图片预览弹窗:#image-modal > .image-wrapper > img + .close-btn */
.image-modal .image-wrapper {
    position: relative;
    max-width: 92%; max-height: 88%;
    display: flex; align-items: center; justify-content: center;
}
.image-modal .close-btn, .video-modal .close-btn {
    /* 放图片内部右上角:竖长图时按钮不会被顶进刘海/状态栏,且命中区加大 */
    position: absolute; top: 8px; right: 8px;
    width: 40px; height: 40px; line-height: 40px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.18);
    color: #fff; font-size: 22px; line-height: 36px; text-align: center;
    cursor: pointer;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.35);
}

/* app.js 动态创建的视频弹窗:#video-modal(顶部返回栏 + 播放区) */
.video-modal { flex-direction: column; justify-content: flex-start; }
.video-modal-header {
    width: 100%;
    padding: calc(12px + env(safe-area-inset-top)) 14px 10px;
}
.video-modal-back {
    display: inline-flex; align-items: center; gap: 6px;
    border: none; border-radius: 100px;
    padding: 8px 18px 8px 14px;
    background: rgba(255, 255, 255, 0.16);
    color: #fff; font-size: 14.5px; font-family: inherit;
    cursor: pointer;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), inset 0 0 0 1px rgba(255,255,255,0.12);
}
.video-modal-back:active { transform: scale(0.95); }
.video-modal-back span { font-size: 17px; line-height: 1; }
.video-modal-content {
    flex: 1; width: 100%;
    min-height: 0;
    display: flex; align-items: center; justify-content: center;
    padding: 0 0 calc(20px + env(safe-area-inset-bottom));
}
.video-modal-content video { max-width: 100%; max-height: 100%; border-radius: 0; }

/* app.js 动态创建的加载浮层(#videoLoading / #imageLoading 用内联样式定位,这里只管内容) */
.loading-progress { color: #fff; font-size: 14px; margin-top: 4px; }

.loading-content {
    display: flex; flex-direction: column; align-items: center; gap: 14px;
    color: #fff;
}
.loading-spinner {
    width: 34px; height: 34px;
    border: 3px solid rgba(255, 255, 255, 0.25);
    border-top-color: #fff;
    border-radius: 50%;
    animation: lgSpin 0.9s linear infinite;
}
@keyframes lgSpin { to { transform: rotate(360deg); } }
.loading-cancel-btn {
    border: none; border-radius: 100px;
    padding: 8px 22px;
    background: rgba(255, 255, 255, 0.18);
    color: #fff; font-size: 14px;
    cursor: pointer;
}

/* ---------- emoji 面板 ---------- */
.emoji-picker-panel {
    /* 定位基准是 .bottom-dock(最近定位祖先):bottom:100% = 永远悬在整个
       输入区上方,不用叠 safe-area(dock 自己已经算过一次,再叠会双计) */
    position: absolute;
    left: 0; right: 0;
    bottom: calc(100% + 8px);
    z-index: 30;
    border-radius: 22px;
    background: var(--emoji-panel-bg);
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    box-shadow: 0 14px 34px var(--glass-drop), inset 0 1px 0 var(--shine-hi2), inset 0 0 0 1px var(--shine-edge);
    max-height: 260px;
    display: none;
    flex-direction: column;
    overflow: hidden;
}
.emoji-picker-panel.open { display: flex; }
.emoji-tabs { display: flex; gap: 4px; padding: 8px 10px 0; }
.emoji-tab {
    border: none; background: transparent;
    color: var(--text-dim);
    font-size: 13px; padding: 6px 12px;
    border-radius: 100px; cursor: pointer;
}
.emoji-tab.active { background: var(--btn-bg); color: var(--header-text); }
.emoji-content { overflow-y: auto; padding: 8px 10px 12px; }
.emoji-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(38px, 1fr)); }
.emoji-item {
    border: none; background: transparent;
    font-size: 24px; padding: 5px;
    border-radius: 8px; cursor: pointer;
}
.emoji-item:active { background: var(--btn-bg); }

/* ---------- 动效偏好 ---------- */
@media (prefers-reduced-motion: reduce) {
    .lg-blob { animation: none; }
    .message { animation: none; }
}
