/* 忆念之间 · 纪念调性覆盖（第0档：暖白 + 烛光金，收敛论坛观感） */
:root {
    /* 主题色 */
    --mem-warm-bg: #FAF6F0;
    --mem-warm-card: #F4EFE7;
    /* 页面底色：body 与 .wrapper 必须同色。二者一旦不一致，短页面会在 wrapper 结束处
       露出一条横向色带接缝（游客态 /top100、/search 等页脚下方可见）。 */
    --mem-page-bg: #F4EFE7;
    --mem-ink: #5C3A1E;
    --mem-ink-soft: #8a7a6a;
    --mem-gold: #8A5A2B;
    --mem-gold-deep: #633806;
    --mem-gold-light: #C9A46C;
    --mem-warm-glow: #FAEEDA;

    /* 暖色渐变背景（由 hall/inqury.ftl 提炼，全站复用） */
    --grad-warm-bg: linear-gradient(135deg, #faf6f2 0%, #f2ebe4 50%, #e8ded0 100%);

    /* 烛光暮夜背景（聊天 / 灯火等深色页面）：底部金色光晕 + 零星愿星
       由 hall/chat.ftl 的 radial-gradient 提炼，深色页只引用这个 token，不要再各写一套 */
    --grad-dusk-night:
        radial-gradient(1.6px 1.6px at 9% 14%, rgba(255, 238, 205, 0.9), transparent 55%),
        radial-gradient(1.3px 1.3px at 23% 7%, rgba(255, 238, 205, 0.7), transparent 55%),
        radial-gradient(1.8px 1.8px at 37% 22%, rgba(255, 244, 220, 0.95), transparent 55%),
        radial-gradient(1.2px 1.2px at 52% 9%, rgba(255, 238, 205, 0.66), transparent 55%),
        radial-gradient(1.6px 1.6px at 67% 18%, rgba(255, 240, 210, 0.85), transparent 55%),
        radial-gradient(1.3px 1.3px at 81% 6%, rgba(255, 238, 205, 0.6), transparent 55%),
        radial-gradient(1.7px 1.7px at 92% 24%, rgba(255, 244, 220, 0.8), transparent 55%),
        radial-gradient(1.2px 1.2px at 15% 38%, rgba(255, 238, 205, 0.55), transparent 55%),
        radial-gradient(1.5px 1.5px at 44% 45%, rgba(255, 240, 210, 0.6), transparent 55%),
        radial-gradient(1.2px 1.2px at 74% 36%, rgba(255, 238, 205, 0.5), transparent 55%),
        radial-gradient(1.4px 1.4px at 88% 48%, rgba(255, 240, 210, 0.55), transparent 55%),
        radial-gradient(ellipse 80% 60% at 50% 95%, rgba(255, 200, 120, 0.28), transparent 60%),
        radial-gradient(ellipse 50% 40% at 50% 100%, rgba(240, 185, 90, 0.18), transparent 70%),
        linear-gradient(180deg, #1a1410 0%, #2a1f17 60%, #3d2b1f 100%);

    /* 深色页底部导航（深色玻璃），与 --grad-dusk-night 成对使用 */
    --mem-dusk-panel: rgba(26, 20, 16, 0.82);
    --mem-dusk-line: rgba(240, 185, 90, 0.16);
    --mem-dusk-text: rgba(240, 220, 190, 0.6);

    /* 底部主导航高度（全站唯一来源：遮罩/留白都引用它，不要再写死 43px/56px） */
    --mem-tabbar-h: 56px;
    --mem-tabbar-total: calc(var(--mem-tabbar-h) + env(safe-area-inset-bottom, 0px));
}

body {
    background-color: var(--mem-page-bg);
}

.wrapper {
    background-color: var(--mem-page-bg);
}

a {
    color: #8A5A2B;
}

a:hover,
a:focus {
    color: #633806;
}

.navbar.bg-light {
    background-color: #FAF6F0;
}

.navbar-light .navbar-brand {
    color: #7A4E1F;
    font-weight: 500;
}

.navbar-light .navbar-nav .nav-link {
    color: #4A3B2A;
}

.navbar-light .navbar-nav .nav-link.active {
    color: #633806;
    font-weight: 500;
}

/* ============ 顶栏用户名下拉（复制 Token / 退出） ============ */
.navbar-light .navbar-nav .nav-link.dropdown-toggle::after {
    margin-left: 4px;
    vertical-align: 1px;
    opacity: 0.6;
}

.nav-user-menu {
    min-width: 160px;
    margin-top: 0;
    padding: 6px 0;
    background-color: var(--mem-warm-bg);
    border: 1px solid rgba(138, 90, 43, 0.16);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(92, 58, 30, 0.14);
}

.nav-user-menu .dropdown-item {
    color: var(--mem-ink);
    font-size: 14px;
    padding: 8px 18px;
}

.nav-user-menu .dropdown-item i {
    width: 16px;
    margin-right: 8px;
    color: var(--mem-gold);
    text-align: center;
}

.nav-user-menu .dropdown-item:hover,
.nav-user-menu .dropdown-item:focus {
    background-color: var(--mem-warm-glow);
    color: var(--mem-gold-deep);
}

.nav-user-menu .dropdown-divider {
    border-top-color: rgba(138, 90, 43, 0.12);
    margin: 4px 0;
}

.btn-outline-success {
    color: #8A5A2B;
    border-color: #C9A46C;
}

.btn-outline-success:hover,
.btn-outline-success:focus,
.btn-outline-success:active {
    background-color: #8A5A2B;
    border-color: #8A5A2B;
    color: #fff;
}

.alert-activate {
    background-color: #FAEEDA;
    border-color: #E8CFA4;
    color: #633806;
}

/* ============ 时光馆详情底部操作条（替换原 5 个浮动按钮） ============ */
.memorial-dock {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    justify-content: space-around;
    align-items: center;
    background: rgba(250, 246, 240, 0.96);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-top: 1px solid rgba(138, 90, 43, 0.14);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
    z-index: 998;
}
.memorial-chip {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    padding: 6px 2px;
    color: var(--mem-ink-soft);
    cursor: pointer;
    border-radius: 12px;
    transition: color 0.2s, background 0.3s, box-shadow 0.3s, opacity 0.3s;
    min-width: 0;
}
.memorial-chip:hover,
.memorial-chip:focus {
    color: var(--mem-gold);
    outline: none;
}
.memorial-chip.is-active {
    color: var(--mem-gold-deep);
    background: rgba(240, 185, 90, 0.18);
}
.memorial-chip-icon {
    width: 22px;
    height: 22px;
    fill: currentColor;
    margin-bottom: 2px;
}
.memorial-chip-label {
    font-size: 11px;
    line-height: 1.2;
    white-space: nowrap;
}
.memorial-chip.is-unlit {
    opacity: 0.5;
}
.memorial-chip.is-unlit.is-active {
    opacity: 1;
}

/* 点灯 / 心愿的「亮着」状态。
   🔴 演变史（两次都被用户退回，别再退回深棕）：
   ① 原版：「已点亮」只表示成"少一个 opacity:0.5" ⇒ 刷新后与未点亮无差别。
   ② 2026-09-11 第一次改：图标 fill 改 --mem-gold(#8A5A2B 深棕) + 6px 柔光。
      用户仍反馈「这俩功能有啥效果吗？没看出来」——根因：**深棕在暖白底上不发光**，
      且 chip 底色没变，所以与未点亮只是"深浅之别"，形不成"亮/灭"的对比。
   ③ 2026-09-11 第二次（当前）：按"真的点着一盏灯"重做 ——
      亮金火苗(#E09422) + 暖金底 + 双层暖光晕；点亮瞬间整个 chip「暖光腾起」。
   ⚠️ 不要复用 .is-active —— 那是 dock 面板开关的语义（金色底 = 当前打开的面板）。
      点灯/心愿没有 data-panel，永远不会 is-active，所以借用金色底不会同屏冲突。
   ⚠️ .is-lit 的 inset 描边会被 .is-lighting 动画临时覆盖（0.9s）—— 有意为之：光晕盖过描边。 */
.memorial-chip.is-lit {
    color: #8A4A06;
    background: rgba(250, 224, 170, 0.72);
    box-shadow: inset 0 0 0 1px rgba(217, 160, 70, 0.42);
}
.memorial-chip.is-lit .memorial-chip-icon {
    fill: #E09422;
    filter: drop-shadow(0 0 5px rgba(240, 185, 90, 0.95))
            drop-shadow(0 0 14px rgba(232, 163, 61, 0.55));
}
.memorial-chip.is-lit .memorial-chip-label {
    color: #8A4A06;
}

/* 点亮瞬间：整个 chip 一次「暖光腾起」—— 一圈暖金光晕向外扩散 + 图标放大回弹。
   末帧与静态 is-lit 外观一致，播完不跳。两个 keyframes 必须同时挂：
   scale 放 chip 上（光晕要跟着走），放大倍数放 icon 上（chip 放大 1.5 倍会挤出 dock）。 */
@keyframes mem-candle-flame {
    0%   { transform: scale(1);    box-shadow: 0 0 0 0 rgba(240, 185, 90, 0); }
    35%  { transform: scale(1.05); box-shadow: 0 0 0 11px rgba(240, 185, 90, 0.20); }
    100% { transform: scale(1);    box-shadow: 0 0 0 24px rgba(240, 185, 90, 0); }
}
@keyframes mem-candle-flicker {
    0%   { transform: scale(1); }
    35%  { transform: scale(1.55); }
    70%  { transform: scale(0.94); }
    100% { transform: scale(1); }
}
.memorial-chip.is-lighting {
    animation: mem-candle-flame 0.9s ease-out;
}
.memorial-chip.is-lighting .memorial-chip-icon {
    animation: mem-candle-flicker 0.9s cubic-bezier(0.25, 0.8, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
    .memorial-chip.is-lighting,
    .memorial-chip.is-lighting .memorial-chip-icon {
        animation: none;
    }
}

/* ============ 灯台：点灯之后的「落点」（2026-09-11 新增） ============
   在此之前，"点灯"只让 dock 上那个按钮变个色，页面上**没有任何第二处变化** —— 点了像没点。
   灯台补上这个落点：点亮之后，生平正文下方真的出现一簇火苗。
   ⚠️ 未点亮时模板整块不渲染（见 hall/detail.ftl），所以这里只写"亮着"的样子。
   ⚠️ 刻意不做"已有 N 人点灯"的聚合计数（用户否掉）；这里只显示"我这一盏"。 */
.mem-candle-stand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin: 28px 0 10px;
}
.mem-candle-flame {
    width: 34px;
    height: 34px;
    fill: #E09422;
    /* 两层光晕：内层贴着火焰，外层摊开成一团烛光 */
    filter: drop-shadow(0 0 6px rgba(240, 185, 90, 0.9))
            drop-shadow(0 0 16px rgba(232, 163, 61, 0.45));
    /* 锚点压到火苗底部 —— 火是"从根上往上摇"的，锚在中心会像在原地转圈 */
    transform-origin: 50% 88%;
    /* 两条动画周期不同（1.7s / 2.3s）⇒ 永不周期性重合，才像活的火。
       一个管形状的摇，一个管光晕的明暗，分开跑比揉在一条里不规则得多。 */
    animation: mem-candle-sway 1.7s ease-in-out infinite,
               mem-candle-glow 2.3s ease-in-out infinite;
    will-change: transform, filter;
}
.mem-candle-date {
    font-size: 12px;
    letter-spacing: 1px;
    color: var(--mem-ink-soft);
}
/* 火苗的「摇」：不规则的碎抖动 + 轻微明暗。
   真火不匀速、不对称，所以每个关键帧的缩放/位移/角度都刻意取不同值，
   并且首尾用同一个值闭环（-1.2deg），避免播到 100% 时跳一下。 */
@keyframes mem-candle-sway {
    0%   { transform: translate(0, 0)          rotate(-1.2deg) scale(1);    opacity: 1; }
    11%  { transform: translate(0.6px, -1px)   rotate(1.6deg)  scale(1.07); opacity: 0.95; }
    23%  { transform: translate(-0.7px, 0)     rotate(-2.1deg) scale(0.96); opacity: 0.9; }
    34%  { transform: translate(0.4px, -1.3px) rotate(1.1deg)  scale(1.09); opacity: 0.97; }
    46%  { transform: translate(-0.4px, -0.3px) rotate(-0.7deg) scale(1);   opacity: 0.93; }
    57%  { transform: translate(0.8px, -1.6px) rotate(2.2deg)  scale(1.1);  opacity: 1; }
    68%  { transform: translate(-0.6px, -0.4px) rotate(-1.4deg) scale(0.97); opacity: 0.88; }
    79%  { transform: translate(0.3px, -1.1px) rotate(0.9deg)  scale(1.06); opacity: 0.96; }
    90%  { transform: translate(-0.3px, -0.2px) rotate(-1.8deg) scale(1.01); opacity: 0.94; }
    100% { transform: translate(0, 0)          rotate(-1.2deg) scale(1);    opacity: 1; }
}
/* 烛光的「强弱」：光晕忽大忽小、忽明忽暗。
   周期与 sway 错开（2.3s vs 1.7s），叠在一起就找不出节奏了。 */
@keyframes mem-candle-glow {
    0%   { filter: drop-shadow(0 0 6px rgba(240, 185, 90, 0.9))
                   drop-shadow(0 0 16px rgba(232, 163, 61, 0.45)); }
    27%  { filter: drop-shadow(0 0 10px rgba(240, 185, 90, 1))
                   drop-shadow(0 0 24px rgba(232, 163, 61, 0.68)); }
    54%  { filter: drop-shadow(0 0 5px rgba(240, 185, 90, 0.78))
                   drop-shadow(0 0 12px rgba(232, 163, 61, 0.34)); }
    76%  { filter: drop-shadow(0 0 8px rgba(240, 185, 90, 0.95))
                   drop-shadow(0 0 19px rgba(232, 163, 61, 0.55)); }
    100% { filter: drop-shadow(0 0 6px rgba(240, 185, 90, 0.9))
                   drop-shadow(0 0 16px rgba(232, 163, 61, 0.45)); }
}
/* 从无到有：首次点灯时由 JS 挂 .is-appearing（0.9s 后摘掉，交回呼吸动画）。
   末尾与静态外观一致，播完不跳。 */
@keyframes mem-candle-appear {
    0%   { opacity: 0; transform: scale(0.4) translateY(10px); filter: none; }
    100% { opacity: 1; transform: scale(1)   translateY(0); }
}
.mem-candle-stand.is-appearing .mem-candle-flame {
    animation: mem-candle-appear 0.9s ease-out;
}
/* 占位未亮：首次点灯时先把它插进 DOM（只为量出灯台的位置），
   等那簇光飞到了再摘掉 is-pending 让它亮起来。opacity 不影响布局，所以位置量得准。 */
.mem-candle-stand.is-pending {
    opacity: 0;
}

/* 点灯仪式里那簇「光」：从底栏按钮飞向灯台。
   fixed + 视口坐标 ⇒ 页面滚动不影响；飞完由 JS 立即移除，不在 DOM 里留东西。
   z-index 要压过底部 dock(998) 与弹窗(1000)，否则会被挡住。 */
.mem-spark {
    position: fixed;
    z-index: 1100;
    width: 12px;
    height: 12px;
    margin: -6px 0 0 -6px;
    border-radius: 50%;
    background: #F0B95A;
    box-shadow: 0 0 8px 3px rgba(240, 185, 90, 0.85),
                0 0 18px 8px rgba(232, 163, 61, 0.45);
    pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
    .mem-candle-flame,
    .mem-candle-stand.is-appearing .mem-candle-flame {
        animation: none;
    }
    /* 降级：不做飞行，灯台直接可见 */
    .mem-candle-stand.is-pending {
        opacity: 1;
    }
}

/* 时光馆页面为底部固定 dock 让出空间。
   ⚠️ 必须把 safe-area-inset-bottom 算进去：dock 自身是 `6px + 内容 + 6px + env(safe-area-inset-bottom)`，
   iPhone 上安全区约 34px ⇒ dock 实际高 ~96px。只写死 80px 的话，内容最后一行（「留言」提交按钮）
   会被底栏压住 —— 2026-09-11 实际踩到过。
   62px = 实测 dock 不含安全区时的高度；再留 22px 呼吸位。 */
.hall-detail-pad {
    padding-bottom: calc(62px + env(safe-area-inset-bottom, 0px) + 22px);
}

/* ============ 时光馆详情页（hall/detail.ftl） ============
   2026-09-11 重构。原实现是一堆互相打架的魔数：
     ① 照片 absolute + 相对 .hall 的百分比坐标 → 同时吃 .hall 的宽**和**高，窗口一矮就往下压到正文上；
     ② 正文靠 `margin-top: 355px` 手动给照片让位（这个 355 就是被 ① 逼出来的）；
     ③ 留言列表靠 `margin-top: 255px` 定位，还放在「留言」面板**外面**；
     ④ 内容列用 col-md-9 + `overflow:scroll;height:585px`，右侧空一整片、正文在内层盒子里滚动。
   现在全部改成正常文档流：照片多高下面就从多高开始排，不再需要任何间距魔数。 */
.hall-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 26px 16px 4px;
}

.hall-avatar {
    /* 正常流布局：不再 absolute、不再用百分比，因此与窗口高度彻底解耦 */
    position: static;
    /* 随屏宽自适应：手机约 150~190px，桌面封顶 208px（固定 168px 在宽屏上偏小） */
    width: clamp(150px, 38vw, 208px);
    aspect-ratio: 3 / 4;
    height: auto;
    object-fit: cover;
    border-radius: 14px;
    border: 4px solid rgba(255, 253, 250, .92);
    box-shadow: 0 10px 26px rgba(138, 90, 43, .16);
    background-color: rgba(255, 253, 250, .5);
}

/* 没传照片时的占位：暖金相机线稿（与聊天页顶部头像同一套做法） */
.hall-avatar--empty {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C9A46C' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'><path d='M3 8.5h3l1.5-2h9L18 8.5h3v11H3z'/><circle cx='12' cy='14' r='3.6'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 52px 52px;
}

.hall-hero-title {
    margin: 18px 0 0;
    font-size: 22px;
    font-weight: 600;
    letter-spacing: .5px;
    color: var(--mem-gold-deep);
}

.hall-hero-dates {
    margin: 7px 0 0;
    font-size: 13px;
    letter-spacing: .3px;
    color: var(--mem-ink-soft);
    font-variant-numeric: tabular-nums;
}

.hall-detail-col {
    /* 阅读宽度上限：正文一行别超过 ~45 个中文字。容器宽 960px 时一行会到 60+ 字，眼睛很难跟行。
       居中后与上方的照片、名字同一条中轴线（<=768px 时该列的 padding 被 hall.css 归零，手机上仍是通栏）。 */
    max-width: 784px;
    margin-left: auto;
    margin-right: auto;
    padding-left: 12px;
    padding-right: 12px;
}

/* 正文：给足行高与段距，悼文/生平这类文字最怕挤在一起 */
.hall-detail-content {
    padding: 18px 18px 4px;
    font-size: 15px;
    line-height: 1.9;
    color: var(--mem-ink);
}
.hall-detail-content p:last-child {
    margin-bottom: 0;
}
.hall-detail-content img {
    max-width: 100%;
    border-radius: 10px;
}

/* 卡片底部那条论坛式信息（阅读数 / 编辑 / 删除）：弱化成卡片页脚 */
.hall-detail-foot {
    margin-top: 14px;
    padding: 10px 18px 12px;
    border-top: 1px solid rgba(138, 90, 43, .1);
}
.hall-detail-meta {
    margin: 0;
    font-size: .82rem;
}

/* 留言列表卡片：bootstrap 的 .card 是纯 #fff，比暖白纸色亮一档，
   和下面那个写留言框并排时会有明显色差 */
.card.comments {
    background-color: #FFFDFA;
    border-color: rgba(138, 90, 43, .14);
    border-radius: 10px;
    overflow: hidden;
}
.card.comments > .card-header {
    background-color: transparent;
    border-bottom: 1px solid rgba(138, 90, 43, .12);
    color: var(--mem-gold-deep);
    font-size: 15px;
}
.card.comments .comment-detail-content {
    color: var(--mem-ink);
    line-height: 1.85;
}

/* 留言区：**已并入生平一屏**（2026-09-11），所以它不再是独立面板 ——
   打开时光馆就能同时看到「正文 + 留言」，底部的「留言」chip 改成滚动定位（data-jump="comments"）。
   ⚠️ `.comments`（来自共享组件 topic_comments.ftl）本身带 `display:none`（配合旧的面板显隐），
   这里用**后代选择器**把它在合并后的容器内放出来 —— 作用域限定在 .hall-comments-block 内，
   不影响其它使用该组件的页面。 */
.hall-comments-block {
    margin-top: 16px;
}
.hall-comments-block .comments {
    display: block;
}

/* 写留言框。原实现是纯 bootstrap .card + 表头白字 —— 白字落在浅色卡片上几乎看不见 */
.hall-comment-form {
    margin-top: 16px;
    background-color: #FFFDFA;
    border: 1px solid rgba(138, 90, 43, .14);
    border-radius: 10px;
    overflow: hidden;
}
.hall-comment-form > .card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background-color: transparent;
    border-bottom: 1px solid rgba(138, 90, 43, .12);
    color: var(--mem-gold-deep);
    font-size: 15px;
}
.hall-comment-form > .card-header a {
    color: var(--mem-gold);
}
.hall-comment-editor {
    padding: 12px 13px 0;
}
.hall-comment-form > .card-body {
    padding: 12px 13px;
}

/* 时光馆面板区段：默认收起，激活后展开 */
.memorial-section {
    display: none;
}
.memorial-section.is-open {
    display: block;
}
.comments {
    display: none;
}
.comments.is-open {
    display: block;
}

/* ============ 通用暖色卡片（通知/搜索/积分榜等列表页） ============
   注意：卡片底色要比页面底色（--mem-page-bg: #F4EFE7）亮一档，否则卡片会"糊"在页面里。
   原先用 --mem-warm-bg(#FAF6F0) 与页面几乎同色，卡片边界几乎看不见，这里改用暖白纸色。 */
.mem-card {
    background-color: #FFFDFA;
    border-color: rgba(138, 90, 43, 0.14);
}
.mem-card > .card-header {
    background-color: transparent;
    border-bottom: 1px solid rgba(138, 90, 43, 0.12);
    color: var(--mem-gold-deep);
}

/* ============ 建馆表单（替代硬编码 140px 无边框输入） ============ */
.hall-create-card {
    background-color: var(--mem-warm-bg);
    border-color: rgba(138, 90, 43, 0.12);
}
.hall-create-card .card-header {
    background-color: transparent;
    border-bottom: 1px solid rgba(138, 90, 43, 0.12);
    color: var(--mem-gold-deep);
    font-size: 18px;
}
.form-label {
    font-weight: 500;
    color: var(--mem-ink);
    margin-bottom: 4px;
    display: block;
}
.required-mark::before {
    content: "*";
    color: var(--mem-gold);
    margin-right: 2px;
}
/* 选填字段的浅色说明（跟在 label 文字后，如「可留空」）：弱化处理，别抢 required-mark 的注意力 */
.form-optional {
    color: var(--mem-ink-soft);
    font-weight: 400;
    font-size: 12px;
    margin-left: 4px;
}
.form-control-warm {
    border: 1px solid rgba(138, 90, 43, 0.25);
    background-color: #fff;
    color: var(--mem-ink);
    border-radius: 6px;
    transition: border-color 0.2s, box-shadow 0.2s;
}
.form-control-warm:focus {
    border-color: var(--mem-gold);
    box-shadow: 0 0 0 3px rgba(240, 185, 90, 0.25);
    outline: none;
}
/* ============ 「录入更多信息」折叠卡（2026-09-14）============
   创建 / 编辑时光馆里「离世日期」默认收起 —— 常驻「去世日期」四个字等于一上来就告诉用户
   "这儿是给逝者的"，给在世家人或自己建馆的人会当场退场（用户原话：「活人看到去世日期
   这几个字，肯定不想用这个功能了」）。入口文案由 JS 的 syncPassDayUI() 唯一决定，这里只管长相：
     · 默认态 = 虚线胶囊 + 灰字（明显是"可选的补充"，不抢主流程注意力）
     · 有值时入口加 .is-filled = 实线 + 暖金底（此时是给逝者建的馆，日期该被看见） */
.hall-more-toggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 8px;
    padding: 5px 10px;
    border: 1px dashed rgba(138, 90, 43, 0.32);
    border-radius: 999px;
    background: transparent;
    color: var(--mem-ink-soft);
    font-size: 12px;
    line-height: 1.4;
    cursor: pointer;
    transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.hall-more-toggle:hover,
.hall-more-toggle:focus {
    color: var(--mem-gold-deep);
    border-color: var(--mem-gold);
    background: rgba(240, 185, 90, 0.12);
    outline: none;
}
.hall-more-toggle.is-filled {
    border-style: solid;
    border-color: rgba(138, 90, 43, 0.28);
    background: rgba(240, 185, 90, 0.16);
    color: var(--mem-gold-deep);
}
.hall-more-panel {
    margin-top: 10px;
    padding: 12px 14px 14px;
    border: 1px solid rgba(138, 90, 43, 0.14);
    border-radius: 10px;
    background: rgba(250, 246, 240, 0.75);
}
/* ⚠️ `hidden` 属性靠 UA 样式表的 display:none 生效，**任何**给它写的 display 都会盖掉它
   ⇒ 这里显式钉死，防止将来有人给 .hall-more-panel 加 display:flex 后"藏不住"。 */
.hall-more-panel[hidden] { display: none !important; }
.hall-more-panel .form-group { margin-bottom: 0; }

/* ===== 时光信：入口卡 + 列表页横幅 =====
   🔴 2026-09-14 定名并降级。此前那个名字是法律文书词（要签字、要见证、要执行），
      而这个功能的真实实现只是「指定收信人 + 到日子送达」，名实不符；
      更关键的是它会劝退"替长辈做回忆录"的子女 —— 那才是付费决策人。
      ⇒ 换名，并从与「心声」并列的 nav-pill 降级成回忆录主线末尾的一次动作
        （当时的完整论证见 .workbuddy/memory/MEMORY-ui.md 的 D6）。
   ⚠️ 名字 / 位置 / 判定都变了，**唯一没动的是 URL（?tab=will）与后端 will 的一切**。 */

/* 入口卡：形态取次级（浅底 + 金边），与 index.ftl 的 .my-pray 同一家族。
   与 /hall/create 页内那条金色实心「创建时光馆」刻意保持强弱差：那条是本页唯一主动作，
   这条只是给"写完之后还想留封信"的人留的门，抢了列表的注意力就是错的
   （用户 2026-09-12 明确要求建馆入口"要突出些"，两条入口的强弱关系是刻意的）。 */
.hall-letter {
    display: flex; align-items: center; gap: 12px;
    margin: 0 0 14px; padding: 13px 16px;
    border: 1px solid rgba(240, 185, 90, 0.45); border-radius: 14px;
    background: #FFFDFA; text-decoration: none;
    box-shadow: 0 2px 10px rgba(138, 90, 43, 0.05);
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.hall-letter:hover {
    text-decoration: none; border-color: rgba(201, 164, 108, 0.85);
    box-shadow: 0 4px 16px rgba(138, 90, 43, 0.10);
}
.hall-letter:active { transform: translateY(1px); }
.hall-letter-ic-wrap {
    width: 34px; height: 34px; flex: none; border-radius: 50%;
    background: rgba(201, 164, 108, 0.16);
    display: flex; align-items: center; justify-content: center;
}
.hall-letter-ic { width: 19px; height: 19px; fill: var(--mem-gold-deep); }
.hall-letter-txt { flex: 1; min-width: 0; }
.hall-letter-t { display: block; font-size: 15px; font-weight: 500; color: var(--mem-gold-deep); }
.hall-letter-s {
    display: block; margin-top: 3px; font-size: 12px; color: var(--mem-ink-soft);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hall-letter-go { flex: none; font-size: 13px; color: var(--mem-gold-deep); }

/* 列表页横幅：**纯 CSS**，刻意不用图片。
   ⚠️ 上一版是张位图，把文案**烤进了图里**（该图 2026-09-21 已删除）——
      一改名就作废（还得重出图，而 AI 出图的中文字不可靠）。改成 CSS 后文案跟着命名走，
      以后改名只动一个 <span>。原图那两个大圆泡用 ::before/::after 顶替。 */
.letter-banner {
    position: relative; overflow: hidden;
    min-height: 122px; margin-bottom: 20px; padding: 22px 18px;
    border-radius: 12px; cursor: pointer;
    background: linear-gradient(135deg, #FDF1DC 0%, #F7DEBD 48%, #F0CFAC 100%);
    border: 1px solid rgba(201, 164, 108, 0.38);
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center;
    transition: box-shadow .15s ease, transform .15s ease;
}
.letter-banner:hover { box-shadow: 0 6px 18px rgba(138, 90, 43, 0.12); }
.letter-banner:active { transform: translateY(1px); }
.letter-banner::before,
.letter-banner::after {
    content: ''; position: absolute; border-radius: 50%;
    background: rgba(255, 255, 255, 0.42); pointer-events: none;
}
.letter-banner::before { width: 156px; height: 156px; right: -38px; top: -52px; }
.letter-banner::after {
    width: 88px; height: 88px; right: 74px; top: -18px; background: rgba(255, 255, 255, 0.26);
}
.letter-banner-txt { position: relative; z-index: 1; }
.letter-banner-t {
    display: block; font-size: 20px; font-weight: 500; color: var(--mem-gold-deep);
    letter-spacing: 2px;
}
.letter-banner-s { display: block; margin-top: 9px; font-size: 13px; color: var(--mem-ink-soft); }
.letter-banner-go {
    display: inline-block; position: relative; z-index: 1;
    margin-top: 13px; font-size: 13px; color: var(--mem-gold-deep);
    border-bottom: 1px solid rgba(201, 164, 108, 0.65);
}
.avatar-uploader {
    height: 170px;
    width: 150px;
    border: 2px dashed rgba(138, 90, 43, 0.3);
    border-radius: 8px;
    background-color: #fff;
    object-fit: cover;
    cursor: pointer;
    transition: border-color 0.2s;
}
.avatar-uploader:hover {
    border-color: var(--mem-gold);
}
/* 横版照片上传区（影像生成页） */
.photo-uploader {
    height: 240px;
    width: 320px;
    max-width: 100%;
    border: 2px dashed rgba(138, 90, 43, 0.3);
    border-radius: 8px;
    background-color: #fff;
    object-fit: cover;
    cursor: pointer;
    transition: border-color 0.2s;
}
.photo-uploader:hover {
    border-color: var(--mem-gold);
}
.divider-warm {
    height: 1px;
    background-color: rgba(138, 90, 43, 0.12);
    border: 0;
    margin: 20px 0;
}
.editor-wrap {
    overflow: auto;
    height: 180px;
    border: 1px solid rgba(138, 90, 43, 0.15);
    border-radius: 6px;
    padding: 4px;
}
.btn-warm-primary {
    background-color: var(--mem-gold);
    color: #fff;
    border: 0;
    padding: 12px;
    font-size: 16px;
    letter-spacing: 1px;
    border-radius: 6px;
    transition: background 0.2s;
}
.btn-warm-primary:hover,
.btn-warm-primary:focus {
    background-color: var(--mem-gold-deep);
    color: #fff;
}

/* ============ 收敛论坛残留的 Bootstrap 青色 ============
   历史模板里散落着 .btn-info / .badge-info（Bootstrap 的青色），与暖金体系冲突。
   这里用一条覆盖统一掉，比逐个模板改 class 更彻底、也不会再漏。
   同理 .nav-pills 的激活态是 Bootstrap 蓝色，也在这里一起收敛成暖金。 */
.nav-pills .nav-link {
    color: var(--mem-ink-soft);
    border-radius: 8px;
    transition: color 0.2s, background-color 0.2s;
}
.nav-pills .nav-link:hover,
.nav-pills .nav-link:focus {
    color: var(--mem-gold-deep);
    background-color: rgba(138, 90, 43, 0.06);
}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
    background-color: var(--mem-gold);
    color: #fff;
}
.btn-info {
    background-color: var(--mem-gold);
    border-color: var(--mem-gold);
    color: #fff;
}
.btn-info:hover,
.btn-info:focus,
.btn-info:not(:disabled):not(.disabled):active {
    background-color: var(--mem-gold-deep);
    border-color: var(--mem-gold-deep);
    color: #fff;
}
.badge-info {
    background-color: var(--mem-warm-glow);
    color: var(--mem-gold-deep);
    border: 1px solid rgba(138, 90, 43, 0.18);
    font-weight: normal;
}

/* ============ 页脚（版权 + 备案号） ============ */
/* 常规文档流 + 居中 + 弱对比；底部让出固定导航高度，避免被 z-index:998 的 TabBar 压住 */
.mem-footer {
    padding: 18px 0 calc(var(--mem-tabbar-total) + 14px);
    background-color: var(--mem-warm-bg);
    border-top: 1px solid rgba(138, 90, 43, 0.10);
}
/* 页脚「隐形」态：版权行只在「我的心声」(/ ?tab=myworry) 展示，其余页面只留底部让位。
   ⚠ 必须写在 .mem-footer 之后 —— 同优先级按源码顺序决胜（这条规则就是上次 TabBar 事故的教训）。
   只清掉上留白/边框/底色，**padding-bottom 的让位一定要留住**，否则内容会钻到固定导航底下。 */
.mem-footer--bare {
    padding-top: 0;
    border-top: 0;
    background-color: transparent;
}
.mem-footer-line {
    margin: 0;
    text-align: center;
    font-size: 13px;
    color: var(--mem-ink-soft);
    letter-spacing: 0.2px;
}
.mem-footer-line a {
    color: var(--mem-ink-soft);
    text-decoration: none;
}
.mem-footer-line a:hover,
.mem-footer-line a:focus {
    color: var(--mem-gold);
    text-decoration: none;
}

/* ============ 关于「桌面端是否隐藏底部 TabBar」的两条结论（2026-09-10） ============
   这里曾经放过一条 min-width:768px 的媒体查询，试图在桌面端把底部导航藏掉
   （当时的理由：顶栏 header.ftl 已有完全相同的四个入口 对话 / 建馆 / 灯火 / 我的）。
   已整体删除，原因两个，都很硬 —— 详见 git 历史里的那段 diff：

   1）【级联顺序】那条媒体查询写在 `.memorial-tab-bar` 的基础规则**前面**。
      CSS 同优先级只按源码顺序决胜，媒体查询没有额外权重 → 基础规则里的布局声明把
      隐藏声明覆盖掉，而留白 token 已经被它归零，最终形态是「可见 + 高度 0」，
      底部栏没被藏掉、而是被压成一条细缝（用户反馈的「底层栏太小了」现场）。
      ⇒ 将来若还要隐藏，媒体查询必须放在本文件**所有** .memorial-tab-bar 规则之后。

   2）【语义】hall/chat、hall/pray、hall/inqury 走 halllayout 或裸 HTML，顶栏是注释掉的，
      那条底部栏是这些页面**唯一的导航**；全局隐藏会把用户困在聊天页里。
      ⇒ 结论：底部栏各端保持同一尺寸（56px）显示。若确实想只在「有顶栏的页面」隐藏，
      正确做法是给 layout.ftl 的 body 加一个类（如 has-header），再用后代选择器
      只隐藏该类下的底部栏，并且写在文件末尾。
   ================================================================================ */

/* ============ 底部主导航 TabBar（替换原 silver 横条） ============ */
/* 注意：这里**故意不再**给 .wrapper 加 padding-bottom: var(--mem-tabbar-total)。
   走 layout.ftl 的页面（.wrapper 只在这些页面存在）末尾必定跟着 .mem-footer，而
   .mem-footer 自己已经有 padding-bottom: calc(var(--mem-tabbar-total) + 14px) 来让开固定导航。
   两处都让位会叠加成 56+70px 的双份留白 —— 这就是之前反馈过的「桌面端底部留白过大」。
   底部让位**只由 .mem-footer 承担一次**；hall/* 那些不走 layout.ftl 的页面各自在页面内用
   bottom: var(--mem-tabbar-total) 定位，与此无关。 */
.memorial-tab-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    justify-content: space-around;
    align-items: center;
    /* 高度含安全区，否则 iPhone 上会被 padding 挤扁 */
    height: var(--mem-tabbar-total);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: rgba(250, 246, 240, 0.96);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-top: 1px solid rgba(138, 90, 43, 0.12);
    z-index: 998;
}
.tab-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--mem-ink-soft);
    text-decoration: none;
    padding: 6px 0;
    font-size: 11px;
    line-height: 1;
    transition: color 0.2s;
}
.tab-item:hover,
.tab-item:focus {
    color: var(--mem-gold);
    text-decoration: none;
}
.tab-item.is-active {
    color: var(--mem-gold-deep);
}
.tab-icon {
    width: 22px;
    height: 22px;
    fill: currentColor;
    margin-bottom: 2px;
}
.tab-label {
    line-height: 1;
}
/* 中间「+」FAB 的样式 —— **当前无入口**（2026-09-11 按用户要求从 tab_bar.ftl 移除了那个 FAB，
   理由：它指向的倾诉页不落库、与产品调性不搭）。样式保留在此，需要恢复时直接加回 markup 即可。
   ⚠️ 底栏高度只认 --mem-tabbar-total，与项数无关，所以移除 FAB 不会造成高度/让位位移。 */
.tab-item-fab {
    flex: 0 0 64px;
    position: relative;
}
.tab-item-fab .tab-icon {
    width: 56px;
    height: 56px;
    background: var(--mem-gold);
    color: #fff;
    border-radius: 50%;
    padding: 16px;
    margin-top: -16px;
    box-shadow: 0 4px 12px rgba(138, 90, 43, 0.3);
    transition: background 0.2s;
}
.tab-item-fab:hover .tab-icon,
.tab-item-fab:focus .tab-icon {
    background: var(--mem-gold-deep);
}

/* 深色页（hall/chat、hall/pray）的底部导航：同一组件、同一尺寸，只换配色 */
.memorial-tab-bar.is-dusk {
    background: var(--mem-dusk-panel);
    border-top-color: var(--mem-dusk-line);
}
.memorial-tab-bar.is-dusk .tab-item {
    color: var(--mem-dusk-text);
}
.memorial-tab-bar.is-dusk .tab-item:hover,
.memorial-tab-bar.is-dusk .tab-item:focus {
    color: var(--mem-gold-light);
}
.memorial-tab-bar.is-dusk .tab-item.is-active {
    color: var(--mem-gold-light);
}

/* ============ 深色页底部输入条（聊天 / 灯火） ============ */
.memorial-send-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: var(--mem-tabbar-total);
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 16px;
    background: var(--mem-dusk-panel);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-top: 1px solid var(--mem-dusk-line);
    z-index: 997;
}
.memorial-send-bar .send-input {
    flex: 1;
    min-width: 0;
    height: 44px;
    padding: 0 18px;
    font-size: 16px;
    color: #3A2A1C;
    background: #FBF6EE;
    border: 1px solid rgba(240, 185, 90, 0.34);
    border-radius: 22px;
    outline: none;
    transition: border-color 0.2s, box-shadow 0.2s;
}
.memorial-send-bar .send-input::placeholder {
    color: #A99A86;
}
.memorial-send-bar .send-input:focus {
    border-color: var(--mem-gold-light);
    box-shadow: 0 0 0 3px rgba(240, 185, 90, 0.2);
}
.memorial-send-bar .send-action {
    flex: 0 0 auto;
    width: 92px;
    height: 44px;
    line-height: 44px;
    text-align: center;
    font-size: 16px;
    color: #fff;
    background: linear-gradient(135deg, var(--mem-gold-light) 0%, var(--mem-gold) 100%);
    border-radius: 22px;
    cursor: pointer;
    user-select: none;
    transition: filter 0.2s;
}
.memorial-send-bar .send-action:hover {
    filter: brightness(1.08);
}

/* ============ 时光信 ============ */
.will-detail-card {
    margin-top: 40px;
    margin-bottom: 40px;
}
.will-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 28px;
    font-size: 14px;
    color: var(--mem-ink-soft);
}
.will-meta strong {
    color: var(--mem-ink);
    font-weight: 600;
}
.will-content {
    line-height: 1.9;
    color: var(--mem-ink);
    font-size: 15px;
    /* 2026-09-21：写信页正文框换成朴素 textarea（参照「我的故事」）后，正文就是**纯文本多行**
       （邮件侧本来也是 nl2br 处理的）⇒ 这里必须保留换行，否则分段写的一封信在详情页会塌成一整段。
       ⚠️ 与 detail.ftl 的 `${will.content!}` 原样输出配套；不加 pre-wrap 就等于把信封的折痕抹平。 */
    white-space: pre-wrap;
    word-break: break-word;
}
.will-list-item {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 16px;
    padding: 12px 14px;
    margin-bottom: 8px;
    background-color: var(--mem-warm-card);
    border: 1px solid rgba(138, 90, 43, 0.10);
    border-radius: 8px;
    transition: border-color 0.2s;
}
.will-list-item:hover {
    border-color: rgba(138, 90, 43, 0.28);
}
.will-list-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--mem-ink);
    text-decoration: none;
}
.will-list-name:hover,
.will-list-name:focus {
    color: var(--mem-gold-deep);
    text-decoration: none;
}
.will-list-date {
    font-size: 13px;
    color: var(--mem-ink-soft);
}


/* ============ 时光馆「邀请家人 + 记忆卡片」（2026-09-10） ============
   原来的 .share 面板只有一条「分享微博」+ 收藏，白色斜体字（在浅色背景上几乎看不见）。
   现在改成两块：① 邀请家人一起留言（把「一个人的时光馆」变成「一家人的地方」）
                ② 生成一张可保存/发朋友圈的记忆卡片（避开沉重仪式感意象的正向产物）。
   ⚠️ 2026-09-11 起这两块**整体搬进了弹窗**（#shareModal，样式见上面那段），
      `.share` 这个外层容器在模板里已经不存在了 —— 下面这条 max-width 规则留着只是备用，
      `.share-card` 及以下仍然被弹窗里的邀请态复用。 */
/* 分享容器跟正文走**同一条中轴线**：原先是通栏，1080px 下两个按钮各被拉到 ~500px 宽，
   与上面居中的照片/名字完全不搭（页面看起来像"两个不同宽度的页面叠在一起"）。
   宽度与 .hall-detail-col 对齐（784px，含 12px 内边距）。 */
.share {
    max-width: 784px;
    margin: 0 auto;
    padding: 0 12px;
    box-sizing: border-box;
}
.share-card {
    margin: 0;
    padding: 18px 16px;
    border-radius: 12px;
    background: rgba(250, 246, 240, 0.95);
    border: 1px solid rgba(138, 90, 43, 0.16);
}
/* 窄屏下两个按钮并排会把文字挤到换行，改成竖排更好点按 */
@media (max-width: 420px) {
    .share-actions { flex-direction: column; }
}
.share-title {
    margin: 0 0 6px;
    font-size: 15px;
    font-weight: 500;
    color: var(--mem-gold-deep);
}
.share-desc {
    margin: 0 0 14px;
    font-size: 13px;
    line-height: 1.7;
    color: var(--mem-ink-soft);
}
.share-input {
    width: 100%;
    box-sizing: border-box;
    padding: 10px 12px;
    margin-bottom: 12px;
    font-size: 14px;
    color: var(--mem-ink);
    background: #FFFDFA;
    border: 1px solid rgba(138, 90, 43, 0.22);
    border-radius: 8px;
}
.share-input:focus { outline: none; border-color: var(--mem-gold); }
.share-input::placeholder { color: #b8a894; }
.share-actions { display: flex; gap: 10px; }
.share-btn {
    flex: 1;
    padding: 11px 14px;
    font-size: 14px;
    color: #fff;
    background: var(--mem-gold);
    border: 0;
    border-radius: 8px;
    cursor: pointer;
}
.share-btn:hover, .share-btn:focus { background: var(--mem-gold-deep); outline: none; }
.share-btn-ghost {
    color: var(--mem-gold);
    background: transparent;
    border: 1px solid rgba(138, 90, 43, 0.35);
}
.share-btn-ghost:hover, .share-btn-ghost:focus { background: rgba(138, 90, 43, 0.08); }
.share-hint {
    margin: 10px 0 0;
    min-height: 16px;
    font-size: 12px;
    color: var(--mem-gold);
}
.share-foot {
    display: flex;
    justify-content: space-between;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(138, 90, 43, 0.12);
    font-size: 13px;
}
.share-foot a, .share-foot span { color: var(--mem-ink-soft); text-decoration: none; }
.share-foot a:hover { color: var(--mem-gold); }

/* ============ 分享弹窗（2026-09-11：分享从"页面内联面板"改成"弹窗"） ============
   一个弹窗两态，靠 #shareViewInvite / #shareViewCard 上的 .is-on 互斥切换：
     ① 邀请态 = 写一句想说的话 + 生成记忆卡片 / 一键分享 + 收藏（暖白纸卡）
     ② 卡片态 = 刚生成的记忆卡片图 + 分享 / 下载图片 / 返回
   外层直接复用下面 .card-modal 的遮罩与层级（z-index 1000），所以这里只写差异部分。 */
.card-modal-inner.share-modal-inner {
    max-width: 400px;
    /* 卡片态自己要居中，所以对齐方式由各态自己声明，别在这里写 center */
    text-align: left;
}
.share-view { display: none; }
.share-view.is-on { display: block; }
/* 卡片态收窄并居中：图是 1080x1440 的竖版，给到 400px 会太高 */
.share-view-card { max-width: 320px; margin: 0 auto; text-align: center; }
/* 卡片图的兜底限高：1080x1440 在 320px 宽下就是 426px 高，矮屏（小屏横屏、分屏窗口）
   会把下面的「下载图片 / 返回」顶出可视区 —— 弹窗本身是不滚动的。
   限高 + 宽度自动 = 等比缩小；max-width 与 max-height 同时给，浏览器取更严的那个。 */
.share-view-card #cardPreviewImg {
    width: auto;
    max-width: 100%;
    max-height: 56vh;
    margin: 0 auto;
}
/* 弹窗里的卡片要提到最亮一档，否则压在深色遮罩上会发灰 */
.share-card--modal { background: #FFFDFA; }
/* 关闭按钮挂在弹窗层（深色遮罩）上：浅色卡片里放浅色的叉是看不见的。
   绝对定位相对 .card-modal（它是 position:fixed）的 padding box，不会跟着卡片滚动。 */
.share-modal-close {
    position: absolute;
    top: calc(12px + env(safe-area-inset-top));
    right: 12px;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid rgba(250, 246, 240, 0.32);
    border-radius: 50%;
    background: rgba(250, 246, 240, 0.12);
    color: rgba(250, 246, 240, 0.92);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
}
.share-modal-close:hover,
.share-modal-close:focus {
    background: rgba(250, 246, 240, 0.22);
    outline: none;
}

/* 记忆卡片预览层：z-index 要压过底部导航(998)与引导遮罩(900) */
.card-modal {
    display: none;
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    z-index: 1000;
    padding: 20px;
    box-sizing: border-box;
    background: rgba(20, 14, 8, 0.74);
    align-items: center;
    justify-content: center;
}
.card-modal.is-open { display: flex; }
.card-modal-inner { width: 100%; max-width: 320px; text-align: center; }
#cardPreviewImg { display: block; width: 100%; border-radius: 12px; }
.card-modal-hint {
    margin: 10px 0 12px;
    font-size: 12px;
    color: rgba(250, 246, 240, 0.85);
}
.card-modal-actions { display: flex; gap: 10px; }
/* 弹窗里主按钮（分享）占满一行，次要操作（下载/关闭）排在下一行 */
.card-modal-actions-sub { margin-top: 10px; }
.card-modal-msg {
    margin: 10px 0 0;
    min-height: 16px;
    line-height: 1.5;
    color: var(--mem-gold-light, #E8C79A);
}

/* ---------- 话题列表里的无照片占位（2026-09-13）----------
   起因：轻建馆（POST /api/hall/quick）只问一个称呼，照片留空 ⇒
   components/topics.ftl 原先写的 `src="${topic.topicUrl!}"` 会渲染 <img src="">，
   浏览器画一个破图并露出 alt 文字。这里等价替换成暖金相机线稿，
   与详情页 .hall-avatar--empty、记录页 .wk-avatar 同一套视觉。 */
.topic-thumb--empty {
    display: inline-block;
    width: 47px;
    height: 55px;
    border-radius: 6px;
    background-color: rgba(138, 90, 43, 0.06);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C9A46C' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M3 8.5h3l1.5-2h9L18 8.5h3v11H3z'/><circle cx='12' cy='14' r='3.6'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 22px 22px;
}

/* ===== 写一封时光信（/will/create）：暖色化 + **修掉编辑器被裁** =====
   🔴 为什么整段都挂在 .will-compose 前缀下：本页用到的 .hall-create-card / .form-control-warm /
      .required-mark / .editor-wrap **是 5 个页面共用的**（hall/create、hall/edit、will/create、
      will/detail、videoAI/create）。直接改那些类 = 一次动 5 个页面，所以这里一律加页面作用域，
      要单独调这一页只改这一段。页面侧只挂了 `.will-compose` 这一个钩子（见 will/create.ftl）。
   🔴 修的是**真问题不是审美**（2026-09-15 实测）：.editor-wrap 是 `height:180px` + `overflow:auto`，
      而 editor.ftl 把 CodeMirror `setSize('auto','450px')` ⇒ 实测 clientH=178 / scrollH=458，
      **编辑器被裁掉一大半**，用户只能在一个 180px 的小窗口里滚着写一封信。下面放成 height:auto。
   ⚠️ 覆盖 CodeMirror 时特意把选择器写重（.will-compose .CodeMirror pre.CodeMirror-line 这种）：
      codemirror.min.css 是从 cdnjs 拉的、**排在 memorial-tone.css 之后**，同特异度时后者胜出，
      所以凡 CDN 里也是两段式的规则（pre.CodeMirror-line / .CodeMirror-focused .CodeMirror-selected），
      必须比它多半段，否则默默不生效。

   ===== 第二轮（2026-09-15 下午）：用户「一页展示。简洁一点」 =====
   改前实测 430×932：写信卡底边落在 1024px（1.10 屏），**「寄出这封信」被挤到首屏外**，
   要往下滑一下才看得见。这轮**不动写作区的最大高度、也不动任何字段语义**，只收紧卡上下的"软骨"：
   页头/卡体 padding、form-group 间距、label 字号行高、输入框 padding、按钮 padding，
   并删掉夹在「送达日期」与信件正文之间的那条 hr 分隔线。
   🔴 另一条真修复：`.CodeMirror` 的高度是 editor.ftl 里 `setSize('auto','450px')` 写的**行内样式**，
      行内样式只有 `!important` 盖得住（`.editor-wrap{height:auto}` 管不着它）。
      下面给它一个跟随视口的 `clamp(180px, 100dvh - 490px, 450px)`：屏幕高就多给写作区、
      屏幕矮就自动让位，保证按钮始终留在首屏内。
      ⚠️ 那个 490px 常量 = 本页**除写作区以外**的全部固定高度之和，包含
         顶栏 57 + 页头 + 卡体 padding + 三个字段 + 按钮 40 + 各段间距 + 卡下方那条**收起的**
         「我寄出的信」页头 45 与它的 18px 上边距 + 10px 余量。
         **改上面任何一处 padding/字号/按钮高，都要回头把这个常量跟着改**，否则"整页一屏"失准。

   ===== 第三轮（同日稍晚）：按钮降高 + 「我寄出的信」改折叠 =====
   用户：「我寄出的信改为下拉框方式。寄出这封信，这个高度太高了」
   ① 按钮 48px → **40px**（padding 12→8）；
   ② 「我寄出的信」整张卡改成原生 `<details>/<summary>` 折叠：收起时只剩一行页头
      （手机 45px / 桌面 52px），点一下才展开信列表 ⇒ 页面**连列表页头都一屏放得下**。
   ⚠️ 两处都记进上面那个 490 常量里了（按钮 -8、折叠页头 +45 ⇒ 净 +37，460 → 490 正好对上）。 */

/* 卡片：居中限宽 + 奶油底 + 暖边柔和阴影（与 .hall-letter 家族同一套色） */
.will-compose {
    max-width: 880px;
    margin: 0 auto;
    background: #FFFDFA;
    border: 1px solid rgba(201, 164, 108, 0.42);
    border-radius: 16px;
    box-shadow: 0 6px 26px rgba(138, 90, 43, 0.08);
    overflow: hidden;              /* 让 header 的渐变跟着圆角裁 */
}
/* 页头：暖色渐变条（原来是不透明白底 + 灰分隔线，和「时光信」这个题材不搭） */
.will-compose .card-header {
    padding: 12px 24px;
    font-size: 18px;
    background: linear-gradient(135deg, #FDF3E2 0%, #F8E3C6 100%);
    border-bottom: 1px solid rgba(201, 164, 108, 0.32);
}
.will-compose .card-header strong { color: var(--mem-gold-deep); letter-spacing: 1px; }
.will-compose .card-header small { color: var(--mem-ink-soft); }
.will-compose .card-body { padding: 16px 24px 18px; }

/* 字段间距：bootstrap 的 .form-group 是 margin-bottom:1rem(16px)，这页竖排四个字段叠起来
   就是 64px 的纯空气。收成 10px —— 这轮的"简洁"主要就省在这里。 */
.will-compose .form-group { margin-bottom: 10px; }

/* 收信人邮箱的提示行（2026-09-21 撤掉手机号后，它只讲邮箱这一件事）。
   ⚠️ 负上边距是为了抵掉 .form-row 里 form-group 的 10px —— 这行是上面那个字段的补充说明，
      要贴着它、不要另起一段空气；下边距给提交按钮留位。 */
.will-compose .will-contact-hint {
    margin: -2px 0 12px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--mem-ink-soft);
}
.will-compose .will-contact-hint strong { color: var(--mem-gold-deep); font-weight: 500; }

/* 输入框：往暖里收。bootstrap 的 .form-control 是定高（calc(1.5em+.75rem+2px)），
   所以改 padding 必须同时 height:auto，否则文字被压扁 */
.will-compose .form-control-warm {
    height: auto;
    padding: 8px 12px;
    color: var(--mem-ink);
    background-color: #FFFDF8;
    border: 1px solid rgba(138, 90, 43, 0.22);
    border-radius: 10px;
}
.will-compose .form-control-warm::placeholder { color: rgba(138, 90, 43, 0.36); }
.will-compose .form-control-warm:focus {
    background-color: #fff;
    border-color: var(--mem-gold-light);
    box-shadow: 0 0 0 3px rgba(201, 164, 108, 0.22);
}
/* 日期控件自带的小日历图标：默认纯黑，太跳，弱化到暖灰 */
.will-compose input[type="date"]::-webkit-calendar-picker-indicator {
    cursor: pointer; opacity: .5; transition: opacity .15s;
}
.will-compose input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: .95; }
/* label：字号比正文略小、行高收紧。原来是 16px/1.5 + 8px 下边距 ⇒ 一个字段光标题就占 32px，
   三个字段就是小半屏。 */
.will-compose .form-label {
    color: var(--mem-gold-deep);
    font-weight: 500;
    font-size: 13.5px;
    line-height: 1.45;
    margin-bottom: 3px;
}
.will-compose .required-mark::before { color: #C0392B; opacity: .7; }
/* 页面上的 <hr class="divider-warm"> 已于 2026-09-15 第二轮删掉（它夹在「送达日期」和信件正文
   之间，只是把本来就相邻的两块又推开 45px）。规则留着，将来要加回来直接可用。 */
.will-compose .divider-warm { background-color: rgba(201, 164, 108, 0.3); margin: 14px 0; }

/* 编辑器外框：**height:auto** 是这轮的真修复（见段首）。padding 归零 + overflow:hidden
   是为了让圆角把里面的 CodeMirror 一起裁掉，不然四个角会露出直角 */
.will-compose .editor-wrap {
    height: auto;
    overflow: hidden;
    padding: 0;
    background: #FFFDF8;
    border: 1px solid rgba(138, 90, 43, 0.18);
    border-radius: 12px;
}
/* CodeMirror 默认是冷色（白底 + #f7f7f7 灰槽 + #d9d9d9 选中），和暖色主题对不上 */
.will-compose .CodeMirror {
    /* 🔴 三行 height 是同一个值的**降级链**（后一行浏览器认识就覆盖前一行）：
       ① 不认识 clamp/dvh 的老浏览器 → 静止 450px（= editor.ftl 原来写死的值）；
       ② 只有 vh 的 → 跟视口走；
       ③ 有 dvh 的 → 跟"动态可视高度"走（手机上地址栏收起/展开不会把按钮顶出屏幕）；
       450px 是上限、180px 是下限（下限只在小屏上生效，用来保证"最后一张卡"也不被顶出首屏：
       375×667 实测写作区落到 180px 时整页底边 663 <= 667 ✓；下限写 200 时是 681，会差 14px）。
       必须 !important：450px 是 editor.ftl 写在元素上的行内 style，普通声明一律盖不住。 */
    height: 450px !important;
    height: clamp(180px, calc(100vh - 490px), 450px) !important;
    height: clamp(180px, calc(100dvh - 490px), 450px) !important;
    font-family: inherit;
    font-size: 15px;
    line-height: 1.8;
    color: var(--mem-ink);
    background: #FFFDF8;
    border-radius: 12px;
}
.will-compose .CodeMirror-gutters {
    background: #FBF3E7;
    border-right: 1px solid rgba(201, 164, 108, 0.28);
}
.will-compose .CodeMirror-linenumber { color: rgba(138, 90, 43, 0.42); }
.will-compose .CodeMirror-lines { padding: 10px 0; }
.will-compose .CodeMirror pre.CodeMirror-line { padding: 0 14px; }
.will-compose .CodeMirror-cursor { border-left: 2px solid var(--mem-gold-deep); }
.will-compose .CodeMirror-selected { background: rgba(201, 164, 108, 0.26); }
.will-compose .CodeMirror-focused .CodeMirror-selected { background: rgba(201, 164, 108, 0.32); }
.will-compose .CodeMirror-placeholder { color: rgba(138, 90, 43, 0.34) !important; }

/* 主按钮：金色渐变 + 轻抬升（原来是一块平涂的深棕，和站内其它主按钮不是一个语汇） */
.will-compose .btn-warm-primary {
    /* 高度 2026-09-15 第二轮降过一次：48px → **40px**（用户「这个高度太高了」）。
       padding 上下 12→8，左右不动（宽按钮不需要左右内距撑）。 */
    padding: 8px 12px;
    border: 0;
    border-radius: 12px;
    background: linear-gradient(135deg, #C9A46C 0%, #8A5A2B 100%);
    box-shadow: 0 6px 18px rgba(138, 90, 43, 0.22);
    transition: box-shadow .2s, transform .15s, background .2s;
}
.will-compose .btn-warm-primary:hover,
.will-compose .btn-warm-primary:focus {
    background: linear-gradient(135deg, #B8925C 0%, #6E4520 100%);
    box-shadow: 0 9px 24px rgba(138, 90, 43, 0.3);
    color: #fff;
}
.will-compose .btn-warm-primary:active { transform: translateY(1px); box-shadow: 0 3px 10px rgba(138, 90, 43, 0.24); }

/* 手机上卡片不再限宽（max-width 本来也不影响），但把内距收一点，别让输入框贴边 */
@media (max-width: 575.98px) {
    .will-compose .card-header { padding: 10px 16px; font-size: 16px; }
    .will-compose .card-body { padding: 14px 16px 16px; }
    .will-compose .form-group { margin-bottom: 9px; }
}

/* ===== 写信页的「我寄出的信」列表（2026-09-15 建 · 2026-09-21 重做视觉） =====
   位置在写信卡下方：首页那张卡改直连写信页后，已写好的信只剩这一条入口。
   🔴 全部是**新类名**（.will-mine*），一个既有类都没改 —— 所以不会波及
      /?tab=will 的 .will-list-item 家族、也不会波及另外 4 个用 .hall-create-card 的页面。
      卡片外框直接复用 .will-compose（880px 居中 / 奶油底 / 暖边），只多给一个上边距隔开。

   2026-09-21 第二轮（用户：「我寄出的信，ui 调整的好看一点。大胆搞。要加上录音文件」）：
   原来是**一行四项**的平铺行（寄给 X ／ 日期 ／ 状态徽标 ／ 箭头），信息挤成一条线，
   且整行是一个 <a> —— 结构上根本塞不进播放控件。现在的形态：
     · 一封信 = 一张卡：左边一枚**印章**（收信人名字首字），右边两行（给谁 / 哪天到 + 倒计时），
       右侧状态徽标；有录音的信在卡内多一条**虚线分隔的播放行**（圆钮 + 段数 + 进度条 + 时间）。
     · 卡身高了一点（印章 38px 撑起来的），换来的是"扫一眼就知道这封信什么状态"。
     · 整卡可点仍然是硬要求（点哪都能进详情）⇒ 用一层铺满的透明链接 .will-mine-link 实现，
       播放行在它**上面**（z-index）—— 这就是为什么播放键不会被"点一下就跳走"吃掉。
       不把整卡包进 <a> 的原因：交互元素不能嵌套，播放键会变成点不动。
     · 录音段数由服务端按 audio_url 算出（多值），前端只负责播。 */

.will-mine { margin-top: 18px; }

/* 🔴 形态 2026-09-15 第三轮：整张卡改成 <details> 折叠（用户「我寄出的信改为下拉框方式」）。
   收起时只剩一行页头（手机 45px / 桌面 52px），页面因此能真正一屏放下；点页头才展开信列表。
   **零 JS** —— 原生 <details>/<summary>，关掉 JS 照样能开合。
   ⚠️ summary 天生带一个三角标记，去掉要**双管齐下**：
      `list-style: none`（标准）+ `::-webkit-details-marker { display:none }`（Chromium / Safari）。
      只写一个，另一种内核上会留个小三角。
   ⚠️ summary 里只能放**短语内容**，所以页头里的两段文字各包了一层 <span>（见 create.ftl）。 */
.will-mine-sum {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    cursor: pointer;
    list-style: none;
    -webkit-user-select: none;
    user-select: none;
}
.will-mine-sum::-webkit-details-marker { display: none; }
.will-mine-sum:focus { outline: none; }
.will-mine-sum:focus-visible { outline: 2px solid rgba(201, 164, 108, 0.6); outline-offset: -2px; }
.will-mine-sum:hover { background: linear-gradient(135deg, #FDF0DC 0%, #F7DFBE 100%); }
.will-mine-sum-t { display: flex; align-items: baseline; min-width: 0; }
.will-mine-caret {
    flex: 0 0 auto;
    display: inline-flex;
    color: rgba(138, 90, 43, 0.6);
    transition: transform .2s;
}
/* 展开时箭头翻转朝上 —— 是"能收回去"的唯一提示 */
.will-mine[open] .will-mine-caret { transform: rotate(180deg); }
.will-mine .card-body { padding: 14px 16px 16px; }

/* ---------- 一张卡 = 一封信 ---------- */
.will-mine-item {
    position: relative;                /* 供 .will-mine-link 那层覆盖定位 */
    display: flex;
    flex-wrap: wrap;                   /* 播放行要能整行换到第二排 */
    align-items: center;
    gap: 10px 12px;
    padding: 12px 14px;
    margin-bottom: 10px;
    border-radius: 14px;
    background: linear-gradient(180deg, #FFFEFA 0%, #FFFCF5 100%);
    border: 1px solid rgba(201, 164, 108, 0.30);
    box-shadow: 0 1px 2px rgba(138, 90, 43, 0.04);
    transition: border-color .18s, box-shadow .18s, transform .18s;
}
/* ⚠️ 用 :last-of-type 而不是 :last-child —— 列表末尾的 <audio> 也是 card-body 的子元素，
   它会让最后一张卡的 :last-child 落空，卡片下沿白多出一条间距。 */
.will-mine-item:last-of-type { margin-bottom: 0; }
/* 悬停：只抬 1px + 加深阴影。不做大幅位移，免得列表在鼠标划动时"蹦" */
.will-mine-item:hover,
.will-mine-item:focus-within {
    border-color: rgba(138, 90, 43, 0.45);
    box-shadow: 0 6px 18px rgba(138, 90, 43, 0.10);
    transform: translateY(-1px);
}

/* 铺满整卡的透明链接（bootstrap 的 stretched-link 是同一个手法）。
   ⚠️ 不写 inset: 0 —— Safari 14 以前不认这个简写，四个边各写一遍最省心。 */
.will-mine-link {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: 1;
    border-radius: inherit;
    text-decoration: none;
}
.will-mine-link:focus-visible { outline: 2px solid rgba(201, 164, 108, 0.7); outline-offset: 2px; }
/* 给读屏用的隐藏文字（铺满链接本身是空元素，得有个可念的名字）。
   Bootstrap 的 .sr-only 同款写法，不额外引一个类，本页自带。 */
.will-vh {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* 印章：收信人名字的第一个字。扫一列信时"给谁"是最先要找的信息，字比图标快。
   待送达=暖金，已送达=竹青（与状态徽标同一套语义）。 */
.will-mine-seal {
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    font-weight: 600;
    color: #FFF9EE;
    background: linear-gradient(140deg, #D8B47C 0%, #8A5A2B 100%);
    box-shadow: inset 0 0 0 1px rgba(255, 249, 238, 0.45), 0 3px 8px rgba(138, 90, 43, 0.22);
    -webkit-user-select: none;
    user-select: none;
}
.will-mine-item.is-done .will-mine-seal {
    background: linear-gradient(140deg, #93B79C 0%, #46704F 100%);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.40), 0 3px 8px rgba(70, 112, 79, 0.18);
}

/* 右半边：两行字。min-width:0 是让下面的 nowrap + ellipsis 能生效的前提 */
.will-mine-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.will-mine-who {
    font-size: 15px;
    color: var(--mem-ink-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.will-mine-who strong { color: var(--mem-ink); font-weight: 600; }
.will-mine-sub {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: 12.5px;
    line-height: 1.2;
    white-space: nowrap;
}
.will-mine-date {
    flex: 0 0 auto;
    color: #A2957F;
    font-variant-numeric: tabular-nums;   /* 日期等宽，多行时右侧不参差 */
}
/* 倒计时（还有 N 天 / 已经送达）：由 JS 现算写进来；空着时整格不占位 —— 关掉 JS 也不会留个空胶囊 */
.will-mine-left {
    flex: 0 0 auto;
    color: #8A5A2B;
    background: rgba(201, 164, 108, 0.14);
    border-radius: 999px;
    padding: 1px 8px;
    font-size: 11.5px;
}
.will-mine-left:empty { display: none; }
.will-mine-item.is-done .will-mine-left { color: #3F6B4C; background: rgba(74, 124, 89, 0.10); }

/* 送达状态：待送达=暖金，已送达=竹青。颜色只做提示，文案本身就说明了含义 */
.will-mine-flag {
    flex: 0 0 auto;
    font-size: 12px;
    line-height: 1;
    padding: 4px 9px;
    border-radius: 999px;
    color: #8A5A2B;
    background: rgba(201, 164, 108, 0.18);
    border: 1px solid rgba(201, 164, 108, 0.36);
}
.will-mine-flag.is-done {
    color: #3F6B4C;
    background: rgba(74, 124, 89, 0.10);
    border-color: rgba(74, 124, 89, 0.30);
}

.will-mine-go { flex: 0 0 auto; font-size: 18px; line-height: 1; color: rgba(138, 90, 43, 0.38); }
.will-mine-item:hover .will-mine-go { color: var(--mem-gold-deep); }

/* ---------- 卡内播放行（只在这封信有录音时渲染） ----------
   🔴 position + z-index：必须抬到铺满整卡的那层链接之上，否则点播放 = 点进详情。 */
.will-mine-aud {
    position: relative;
    z-index: 2;
    flex: 1 1 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 2px;
    padding-top: 10px;
    border-top: 1px dashed rgba(201, 164, 108, 0.45);
}
.will-mine-play {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #FFF9EE;
    background: linear-gradient(140deg, #C9A46C 0%, #8A5A2B 100%);
    box-shadow: 0 4px 10px rgba(138, 90, 43, 0.22);
    cursor: pointer;
    transition: transform .12s, box-shadow .15s;
    -webkit-tap-highlight-color: transparent;
}
.will-mine-play:hover { transform: scale(1.06); box-shadow: 0 5px 14px rgba(138, 90, 43, 0.28); }
.will-mine-play:active { transform: scale(0.96); }
.will-mine-play svg { width: 16px; height: 16px; display: block; }
/* 一个按钮里放两个图标，靠类名切换（播放中 → 暂停符号） */
.will-mine-play .will-mine-ic-pause { display: none; }
.will-mine-play.is-playing .will-mine-ic-play { display: none; }
.will-mine-play.is-playing .will-mine-ic-pause { display: block; }

.will-mine-aud-t { flex: 0 0 auto; font-size: 12px; color: #8A7D6D; }
.will-mine-bar {
    flex: 1 1 auto;
    min-width: 40px;
    height: 6px;
    border-radius: 999px;
    background: rgba(201, 164, 108, 0.22);
    cursor: pointer;
    overflow: hidden;
}
.will-mine-bar-fill {
    display: block;
    height: 100%;
    width: 0;
    border-radius: 999px;
    background: linear-gradient(90deg, #D8B47C 0%, #8A5A2B 100%);
    transition: width .12s linear;
}
.will-mine-aud-time {
    flex: 0 0 auto;
    font-size: 11.5px;
    color: #8A7D6D;
    font-variant-numeric: tabular-nums;
}

/* 手机上：卡身收紧，日期+倒计时不换行、名字过长仍省略 */
@media (max-width: 575.98px) {
    .will-mine .card-body { padding: 12px 12px 14px; }
    .will-mine-item { padding: 12px; gap: 8px 10px; }
    .will-mine-seal { width: 34px; height: 34px; font-size: 14px; }
    .will-mine-go { display: none; }        /* 整卡都能点，右侧箭头在窄屏是多余的 */
    .will-mine-sub { white-space: normal; flex-wrap: wrap; }   /* 320px 档日期+倒计时放不下一行，允许折行 */
    .will-mine-aud { gap: 8px; }
    .will-mine-aud-t { font-size: 11.5px; }
}

/* ============ 话题列表：卡片式行（2026-09-15 重排） ============
   用户看着「印记」页列表截图说「这个布局好看点」。改的是**视觉**，
   数据、落点、接口一个都没动（标记见 components/topics.ftl 的文件头注释）。
   旧形态是一条条贴着灰细线的裸行：缩略图 47×55 定死、破图就露 alt 文字、
   作者名独占一行、时间与浏览数挨成「4天前4次浏览」、标题单行截断。
   新形态**一条 = 一张卡**，卡片之间用行内留白（margin）代替那条灰细线。
   配色刻意与 .will-mine-item（写信页的"我寄出的信"）保持一致 ——
   同一个 app 里的两种列表，用户不该看出是两套皮。 */

/* 🔴 行距由**行自己**的 margin-bottom 承担，不用外层容器 + flex gap。
   原因是分页的「下滑加载」把下一页的行插到哨兵前面（= 插进 .card-body），
   行若被包进容器，追加进来的行就落在容器外面、丢掉容器上的样式 —— 间距首当其冲。
   margin 挂在行上则不依赖父子关系，追加的行照样有间距。详见 topics.ftl 文件头。 */
.mtl-item {
    position: relative;               /* 供 .mtl-link 那层覆盖定位 */
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    margin-bottom: 10px;
    border-radius: 12px;
    background: #FFFDF8;
    border: 1px solid rgba(201, 164, 108, 0.28);
    transition: border-color 0.2s, background 0.2s;
}
.mtl-item:hover,
.mtl-item:focus-within {
    background: #FDF6EA;
    border-color: rgba(138, 90, 43, 0.42);
}

/* 整卡主链：铺满卡片的透明覆盖层，点哪儿都进详情页。
   ⚠️ 为什么不用「把整行做成 <a>」：卡里还有标签链接和作者链接，
      a 里套 a 是非法 HTML，浏览器会把内层拆出来、落点就不受控了。
      分层覆盖（覆盖层 z-index:1 + 二级链接 z-index:2）是这个问题的标准解法。 */
.mtl-link {
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
}
.mtl-link:focus-visible { outline: 2px solid rgba(138, 90, 43, 0.5); outline-offset: 2px; }
.mtl-tag,
.mtl-who { position: relative; z-index: 2; }

/* 缩略图：54×64 竖版（与照片原型一致）。
   底层永远是「首字封面」（暖色底 + 名字首字，色值由标记按 topic.id 内联），
   有真照片才在上面盖一层 img；img 加载失败时由 onerror 摘掉自己 ⇒ 露出首字封面。
   ⇒ 不会出现破图，也不会露出 alt 文字。
   ⚠️ 这里**不再用相机线稿占位**：相机是"这里能放照片"的意思，
     而这一页大多数条目本来就只是没人传照片，画相机等于把"缺"当成常态展示。
     首字封面与建馆页的时光馆卡片（passed_topics.ftl）是同一套做法，见 topics.ftl 文件头。 */
.mtl-thumb {
    position: relative;
    flex: none;
    width: 54px;
    height: 64px;
    border-radius: 10px;
    overflow: hidden;
    background-color: rgba(138, 90, 43, 0.06);
    border: 1px solid rgba(201, 164, 108, 0.40);
}
.mtl-initial {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    font-weight: 500;
    color: var(--mem-gold-deep);
    letter-spacing: 0;
}
.mtl-thumb img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;               /* 任意比例的照片都填满，不拉伸 */
    display: block;
}

.mtl-body {
    flex: 1 1 auto;
    min-width: 0;                    /* 让下面的省略号生效（flex 子项默认不收缩） */
    display: flex;
    flex-direction: column;
    gap: 7px;
}

/* 标题最多两行。原来是单行截断，稍长的名字一律变成「…」结尾 */
.mtl-title {
    font-size: 15px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--mem-ink);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.mtl-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    line-height: 1;
    color: var(--mem-ink-soft);
}
/* 时间 / 浏览 / 留言合成一行的那一段：整段不折，免得「· 2 条留言」被甩到下一行 */
.mtl-stat { white-space: nowrap; }

.mtl-tag {
    font-size: 11px;
    line-height: 1;
    padding: 3px 8px;
    border-radius: 999px;
    background: var(--mem-warm-glow);
    color: var(--mem-gold-deep);
    border: 1px solid rgba(138, 90, 43, 0.16);
    text-decoration: none;
}
.mtl-tag:hover,
.mtl-tag:focus { text-decoration: none; background: rgba(201, 164, 108, 0.32); color: var(--mem-gold-deep); }
/* 「精华」是论坛残留语义，颜色沿用「已送达」那支竹青，与暖金区分开 */
.mtl-tag--good {
    background: rgba(74, 124, 89, 0.10);
    color: #3F6B4C;
    border-color: rgba(74, 124, 89, 0.28);
}
.mtl-tag--good:hover,
.mtl-tag--good:focus { background: rgba(74, 124, 89, 0.16); color: #3F6B4C; }

.mtl-who { color: var(--mem-gold); text-decoration: none; }
.mtl-who:hover,
.mtl-who:focus { color: var(--mem-gold-deep); text-decoration: none; }

/* ===== 让掉 Bootstrap 那层白底卡壳（只挂在渲染本列表的两支上，见 index.ftl） =====
   不归零的话①卡片里再套卡片、②.card-body 的 20px 内边距会让列表比上方的
   .my-pray / .hall-letter 缩进一截、左边缘对不齐。 */
.mem-list-card {
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
}
.mem-list-card > .card-body { padding: 0; }

