/* reader.css — 阅读视图（复用主体卡片列表区，段落排版与编辑器镜像一致） */

.reader-loading,
.reader-error {
  text-align: center;
  color: #94a3b8;
  font-size: 0.7rem;
  padding: 2rem 0;
}

/* ---------- 标题区 ---------- */
.reader-head {
  text-align: center;
  padding-top: 0; /* ④ 顶部留白统一由 .card-overlay 的 1.2rem 承担（与左/右一致） */
  margin-bottom: 1.2rem; /* 与编辑视图一致：更贴近正文 */
}
.reader-title {
  font-size: 1.5rem; /* 老内核兑底（rem 值，微信字体已由 JS 层锁定；保证标题恒大于正文 1.125rem） */
  font-size: clamp(1.32rem, 4.08vw, 1.8rem); /* 原 clamp(1.65rem,5.1vw,2.25rem) 缩小 20% */
  font-weight: 700;
  color: var(--dark, #0f172a);
  line-height: 1.4;
  margin: 0 0 0.6rem;
}
.reader-meta {
  font-size: 0.845rem; /* 原 0.65rem，副标题行整体放大 30% */
  color: #94a3b8;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.reader-meta-sep {
  color: #cbd5e1;
}

/* 置顶（蓝）/ 加密（深绿）状态徽标，横排在日期左边；字号与 meta 行（时间/日期/阅读）一致 */
.reader-flag {
  display: inline-flex;
  align-items: center;
  gap: 0.1rem;
  line-height: 1; /* 继承 meta 行字号 0.845rem，与时间/日期/阅读量同一基线 */
}
.reader-flag .icon {
  display: block; /* 消除 svg 行内基线占位，保证与文本上下中心对齐 */
  flex-shrink: 0;
  width: 0.7rem;
  height: 0.7rem;
}
.reader-flag span {
  display: inline-flex;
  align-items: center;
  line-height: 1;
}
.reader-flag.pin {
  color: #2563eb;
}
.reader-flag.secret {
  color: #15803d;
}

/* 背景音乐开关：裸 icon（无背景无包边），播放态变蓝；图标比 meta 文字略大（1.05rem）易于辨认点击热区 */
.reader-music-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  border: none;
  background: transparent;
  border-radius: 0;
  width: 1.4rem; /* 点击热区略大于图标 */
  height: 1.4rem;
  padding: 0;
  font-size: 1.05rem;
  color: #94a3b8;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
  transition: opacity 0.15s;
}
.reader-music-btn .icon {
  width: 1.05rem;
  height: 1.05rem;
}
.reader-music-btn:hover {
  opacity: 0.75;
}
.reader-music-btn.playing {
  color: #2563eb;
  background: transparent;
  border-color: transparent;
}

/* ---------- 段落流 ---------- */
.reader-body {
  display: flex;
  flex-direction: column;
  gap: 0.45rem; /* 段落间距：0.9→0.45（缩 1/2） */
}
.para-text {
  font-size: 1.125rem; /* 原 0.75rem 放大 50% */
  line-height: 1.45; /* 行间距：1.9 → (1.9-1)/2+1=1.45（缩 1/2 的“行距部分”） */
  color: #334155;
  /* 缩进由文本自身空格驱动（pre-wrap 保留段首空格）：不再 text-indent:2em 强制空两格 */
  white-space: pre-wrap;
  margin: 0;
}
.para-image {
  max-width: 100%;
  border-radius: 0.4rem;
  display: block;
  margin: 0 auto; /* 外边距/居中由外层 .img-rot 负责（旋转换盒，见下） */
}
/* ---------- ① 宽图点击旋转（阅读页 .para-image / 编辑页 img.media-view 共用） ----------
   旋转 = 换布局盒 + 按比例放大：盒宽 = 容器可用宽（= 未旋转时的渲染宽，即“顶满”）、
   盒高 = 可用宽 × 原图 iw/ih（高度变成宽度 → 下方内容被向下挤开）。只转不放大会毫无放大效果。
   纯 transform 不产生布局高度，故用 --rot-w/--rot-h/--rot-iw 三个变量由 image-rotate.js 写入。
   **两个状态都写显式 px + 图片绝对居中**，因此盒子能对 width/height 做过渡 →
   旋转/还原时下方文字跟着下落/回升（而不是瞬间跳位）。
   量好之前（.sized 未加）仍走自然尺寸，图片未加载完不会出现塔盒。 */
.img-rot {
  display: block;
  max-width: 100%;
  margin: 0.3rem auto;
}
.img-rot.sized {
  position: relative;
  max-width: none; /* 尺寸已由变量精确给出，不再被夹取 */
  width: var(--rot-w);
  height: var(--rot-h);
  transition: width 0.25s ease, height 0.25s ease;
}
.img-rot.sized > img {
  position: absolute;
  top: 50%;
  left: 50%;
  display: block;
  width: var(--rot-iw);
  height: auto;
  max-width: none;
  border-radius: 0.4rem;
  transform: translate(-50%, -50%) rotate(0deg);
  /* 宽度也一起过渡：旋转态图片的 CSS 宽 = 盒高，同步插值才是“边转边放大”，
     而不是宽度瞬跳（瞬跳会让过渡中间出现更大的横向裁切） */
  transition: transform 0.25s ease, width 0.25s ease;
}
.img-rot.sized.rotated > img {
  transform: translate(-50%, -50%) rotate(90deg);
}
.para-audio,
.para-video {
  text-align: center;
}
.para-audio audio {
  width: min(21rem, 100%);
}
.para-video video {
  max-width: 100%;
  border-radius: 0.4rem;
}
.para-missing {
  font-size: 0.65rem;
  color: #cbd5e1;
}

/* 链接组：一行 1~3 个链接，靠左排列 */
.para-link-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: flex-start;
  margin: 0.2rem 0;
}
.para-link-group.mode-1 {
  width: 50%;
  margin: 0.2rem auto;
}
.para-link-group.mode-2 {
  width: calc(200% / 3);
  margin: 0.2rem auto;
}
.para-link-group.mode-3 {
  width: 90%;
  margin: 0.2rem auto;
}
.para-link-card {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border: 1px solid #e2e8f0;
  background: #fff;
  border-radius: 0.4rem;
  padding: 0.9rem; /* 上下=左右，内边距四边一致 */
  text-decoration: none;
  color: #2563eb;
  font-size: 0.7rem;
  transition: border-color 0.15s;
}
.para-link-card:hover {
  border-color: #93c5fd;
  background: #f8fafc;
}
.para-link-icon {
  width: 1rem;
  height: 1rem;
  object-fit: contain;
}
.para-link-icon-fallback {
  font-size: 0.8rem;
}

/* 文件卡片（下载项） */
.para-file-card {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  align-self: center;
  margin: 0.2rem auto;
  border: 1px solid #e2e8f0;
  background: #f8fafc;
  border-radius: 0.4rem;
  padding: 0.6rem 1rem;
  text-decoration: none;
  color: #334155;
  font-size: 0.7rem;
  font-weight: 500;
  transition: border-color 0.15s;
}
.para-file-card:hover {
  border-color: #93c5fd;
}

/* 3D 空间占位卡片 */
.para-space-card {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: 1px dashed #cbd5e1;
  border-radius: 0.5rem;
  background: linear-gradient(135deg, #f8fafc 0%, #eef2ff 100%);
  padding: 1.7rem 1rem;
  color: #64748b;
  font-size: 0.7rem;
}
.para-space-icon {
  font-size: 1.1rem;
}
.para-space-icon .icon {
  width: 1.1rem;
  height: 1.1rem;
}

/* ---------- 轻提示 ---------- */
.reader-toast {
  position: fixed;
  left: 50%;
  bottom: 3.5rem;
  transform: translateX(-50%) translateY(0.6rem);
  background: rgba(15, 23, 42, 0.92);
  color: #fff;
  font-size: 0.65rem;
  padding: 0.45rem 0.9rem;
  border-radius: 0.4rem;
  opacity: 0;
  pointer-events: none;
  transition: all 0.2s;
  z-index: 99999;
}
.reader-toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* 富文本段落内联样式（阅读端渲染保险，与编辑器一致） */
.para-text strong {
  font-weight: 700;
}
.para-text em {
  font-style: italic;
}
.para-text u {
  text-decoration: underline;
}

/* ---------- 内嵌 HTML 应用（沙箱 iframe，编辑页 .app-block 复用同一套外壳） ---------- */
.para-app {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
/* 应用要"原生融进正文"：**不描边、不铺底色、不加圆角、不加内边距** ——
   让应用里的卡片与文字和正文字栏左右齐平，看起来就是文章自己的那一段；
   画上外框则像"贴进文章的一张截图"，还把正文栏切出一块内缩的孤岛。
   （应用自己在嵌入态也不再留白，见 tax-simulator.html 的 html.embedded .app。）
   宽度就是 100%：原来用 content-box + calc(100% - 2px) 是给那 1px 外框让位的，外框没了就不需要。
   不设 overflow 滚动：高度恒等于应用内容高度，整页应用在正文里完整显示（apps.js MAX_REM 亦然）。 */
.app-frame {
  display: block;
  width: 100%;
  /* 必须显式清零边框：iframe 的 UA 默认值是 2px inset（深色立体边），
     原 1px 发丝线删掉后它就会露出来 —— 比原来那圈"勾边"还重；
     而且它还会吃掉内容盒上下各 2px（全局 border-box），应用回报的高度就不够用，
     iframe 内部会挂出滚动条。 */
  border: 0;
}

/* ---------- 出血区（bleed）：让应用里的动效画得出去 ----------
   iframe 是**硬裁剪视口** —— 应用里的点击缩放（峰值时元素比自身大 pop 倍）、
   按住放大的光环、圆点被顶到线条端点时探出的半个圆，只要画到自己的盒子外就一律看不见。
   实测（root 14px、正文栏 57rem）：左侧「个体」轮换按钮峰值越界 0.209rem、右侧折起方框 0.125rem
   —— 这两个今天就是被 iframe 裁掉的；展开后的 BUFF tag 按算式 ≈0.37rem（最坏）、圆点 0.625rem。
   做法：iframe 四周各外扩 --bleed，再用负 margin 把这圈占位**原样收回**，
   同时应用侧把内容内缩同样的量（tax-simulator.html 的 html.bleed .app，同一个 ?bleed=N）——
   于是版面与对齐一格不动，多出来的这一圈纯粹是"画得出去"的余量。
   三条硬约束：
     ① N 必须 ≥ 任何动效的越界量（超过 N 的部分照样被裁，N 不是"无限"）；
     ② N ≤ 文章卡片的横向留白（1.2rem）—— 出血连卡片边框都不该碰到，
        卡片（overflow:hidden）才是最终裁剪边界，这正是需求：只裁在卡片上；
     ③ 这一圈必须**透明**：iframe 画在相邻段落之上，若不透明就会盖住上下两行字
        （应用侧也把 body 背景改成 transparent，见 tax-simulator.html）。
   代价：这一圈属于 iframe 的命中区 —— 落在里面的点击算给应用、不再选中后面的正文。
   N 取 1.2rem（= 文章卡片的横向留白）：既满足 ① 的 3 倍余量，也把 ② 用到满 ——
   应用内容仍然严格等于正文栏，但横向可画空间从"零"变成"卡片整整两条留白"。 */
.app-frame.app-bleed {
  width: calc(100% + 2 * var(--bleed, 0rem));
  margin: calc(-1 * var(--bleed, 0rem));
  background: transparent;
  position: relative;
  z-index: 1; /* 出血部分要压在相邻段落之上：它们都是 z-auto，这一条足够 */
}

/* ---------- 阅读卡：横向留白必须挂在**滚动容器**上，不能挂在卡片上 ----------
   与编辑页同构（editor.css 的 #view-editor.card-overlay { padding: 1.2rem 0 0 } +
   .editor-scroll { padding: 0 1.2rem … }），阅读页此前是反过来的：卡片 padding 1.2rem、
   滚动容器 padding 0 —— 而 `.reader-scroll` 是滚动容器，**它的裁剪盒就是它自己的 border box**，
   卡片 padding 在它外面。于是正文栏左右沿成了一道硬裁剪线：应用那一圈出血余量
   （.app-frame.app-bleed）被它整条裁掉，表现就是"按钮放大时左侧圆角被切平"。
   把留白下移到滚动容器后，滚动容器的 border box 扩到卡片整宽 → 裁剪盒跟着扩，
   应用才真的画得出去，最终裁剪边界落回卡片自己（.card-overlay 的 overflow:hidden）。
   栏宽与位置不变：容器 border box 加宽 2×1.2rem、padding 补回同样的 2×1.2rem。 */
#view-reader.card-overlay {
  padding: 1.2rem 0 0; /* 顶部的 1.2rem 保留（横向交给下面那条），下边距仍交给滚动容器 */
}
#view-reader .reader-scroll {
  padding: 0 1.2rem 3.6rem; /* 底部 3.6rem：给「分享 / 返回」悬浮按钮让位（原在 .reader-scroll 上） */
}
