/* ==========================================================
   notes.css — Notes 基础样式
   ------------------------------------------------------------

   加载序: CSS 第 31 / 37 (index.html <head> 第 31 个 <link>; 后加载的覆盖先加载的)
   ★ 全站 37 个 CSS 的完整加载序 + 职责表见 index.html 头注释「📂 文件结构速查」
     (单一事实源 —— 旧版 19 个文件各抄一份清单, 且停在 25/26/28/31 四个旧版本;
      加一个 CSS 要改 19 处, 编号还是"分组号"而非真实加载位, 现已收敛)
   [Backlog #156 · 2026-10-03] 新建, 跟 life-reading.css (§1-§6 基础)
   同结构 + PDF 模态内置 (复用 portfolio-preview 米白容器):

   §1 课程笔记模态 (米白浅色, Backlog #99 Modal 浅色主题色板)
       #notes-modal.collage-modal-overlay 米白半透 + blur
       .notes-inner 米白卡纸 + 八角切角 16px + 双层硬投影
       .notes-header 顶色高光线 (var(--theme-color))
       .notes-body 滚动区
       .notes-close 米白胶囊 + hover 深 teal 反色

   §2 筛选栏 + 计数条
       .notes-chip 米白胶囊 + hover 深 teal + is-active 选中态全色 [Backlog #181]
       .notes-chip-sep / .notes-chip-dim 分隔
       [Backlog #221] 两级化: .notes-filter-row 行容器
              + .notes-chip--group 父级(实底/加粗) / .notes-chip--sub 子级(缩小一号/弱描边/缩进)
       [Backlog #196] 筛选栏改**左右两栏** (左学科 / 右时间), 抄 photography 的
              .photo-filter-bar / .photo-filter-col 布局机制。实测筛选栏高度
              299 → 110px, 首屏可视区 (798px) 里的占比从 37% 降到 14%。

   §3 笔记网格
       .notes-grid 2 列 (≥1025px), 1 列 (≤1024px)
       [Backlog #196] 宽屏加密见 notes-responsive.css §7.5 (≥1800 五列 / ≥2400 六列)

   §4 单张笔记卡
       .notes-item 米白实色 + border-left 3px 强调 (整卡可点)
       .notes-item-thumb 首页预览框 (object-fit: contain, 完整第一页)
       .notes-item-thumb::after 水印 (content: attr(data-watermark))  [Backlog #174]
       .notes-item-pinned-badge 置顶 📌 徽章  [Backlog #174]
       .notes-item-thumb 首页预览框 (object-fit: contain, 完整第一页)
       .notes-item-thumb-img / -cap (总页数角标, [Backlog #180] 原为 P.1) / -missing 降级占位
       .notes-item-title Cinzel serif 深墨
       .notes-item-en 英文小字深 teal
       .notes-item-meta 学期 · 分类 · 大小
       .notes-item-note 古铜色 ★ 标注
       .notes-pdf-large > 50MB 红字警示

   §4.5 置顶区 (Backlog #174, 照搬 Photography 的 photoPinnedSection)
       .notes-section / .notes-section-label 分区标题
       .notes-section--pinned 置顶区 (古铜色标题线)

   §5 主题色 (黄/古铜 #d4a55a 跟 canvas home 菱形 Backlog #71 同色系)

   §6 PDF 模态 (Backlog #156 新增, 复用 portfolio-preview 浅米白容器)
       .notes-pdf-modal 米白半透 backdrop + blur
       .notes-pdf-container #f7f1e1 米白 + 双层硬投影 + 八角切角
       .notes-pdf-header top 高光线 (主题色)
       .notes-pdf-close 米白胶囊 + hover 深 teal
       .notes-pdf-stage 图片舞台 (flex:1 滚动区) + .notes-pdf-pages/-page
       .notes-pdf-toolbar 页码 / 翻页 / 页码跳转 / 缩放  [Backlog #170; #217 加 .notes-pdf-jump*]
       .notes-pdf-watermark 满屏半透明水印 (个人标识 + 学期 + 课程名; **#217 删掉了 ID 段**)  [Backlog #174: 30px/700/0.15, 原 14px/0.06 隐形]
       .notes-pdf-notice 底部警示条 (防下载)

   响应式 + 覆盖节 §7+ 在 notes-responsive.css。
   ========================================================== */

/* §1 Notes 主模态容器 */
#notes-modal.collage-modal-overlay {
    background: rgba(247, 241, 225, 0.55);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

/* [Backlog #156-fix] pointer-events: auto !important — 必须显式打开交互。
   根因: #content-wrapper { pointer-events: none } (portfolio-layout.css:60) 是
   **可继承** 属性, 本模态写在 #content-wrapper 内部 (index.html L1996), 沿父链
   一路继承到整个子树。症状极具迷谋性: 模态"完全能看见", 但关闭键 / 筛选 chip /
   卡片 / 按钮 **一个都点不动**; 只有 ESC 还能用 —— ESC 监听挂在 document 上,
   不依赖命中测试。
   同坑同解 (站内已有 4 处先例): portfolio-preview.css:108 · life-photography-lightbox.css:87
   · portfolio-card-entry.css:104 · life-modal.css:342 (.collage-modal-body)。
   pointer-events 可继承 → 只需在遮罩根打开一次, 后代自动恢复;
   .notes-pdf-watermark / .notes-pdf-notice 自身显式声明了 none, 保持不挡 PDF 区。 */
#notes-modal {
    pointer-events: auto !important;
}

/* [Backlog #179] position: relative —— 让 .notes-close 相对**卡纸**定位。
   根因: .notes-close 是 position:absolute (top/right 14px), 但定位祖先链上
   .notes-inner 自己没有定位上下文 → 回退到 #notes-modal.collage-modal-overlay
   (position:fixed, inset:0, 100vw/100vh, life-modal.css:173) → 按钮落到
   **视口**右上角而不是米白卡纸内。卡纸垂直居中 (inner y=139 ~ 681), 按钮在
   y=14 ~ 46, 整块悬在卡纸顶边之上 → 被下面这条 clip-path 八角切角**整个裁掉**,
   视觉消失 + 命中测试也一起失效 (elementFromPoint 落到 overlay 而非按钮),
   于是右上角既看不见也点不动, 只剩 ESC 能关。
   为什么之前一直没被发现: 规则本身写得完全正确, DOM 里按钮也在, 静态断言
   「.notes-close 存在」「CSS 规则存在」全过 —— 只有量 rect / 打点才暴露。
   同款八角切角容器 .notes-pdf-container 本来就有 position:relative
   (本文件 §7), 这里只是漏写, 不是设计意图。 */
#notes-modal .notes-inner {
    background: #f7f1e1;
    border: 1px solid rgba(0, 80, 100, 0.4);
    box-shadow:
        2px 3px 0px rgba(10, 31, 36, 0.55),
        0 4px 12px rgba(10, 31, 36, 0.4),
        inset 0 1px 0 rgba(255, 255, 255, 0.5);
    width: min(95vw, 1400px);
    max-height: 90vh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    position: relative;
    clip-path: polygon(
        16px 0%, calc(100% - 16px) 0%,
        100% 16px, 100% calc(100% - 16px),
        calc(100% - 16px) 100%, 16px 100%,
        0% calc(100% - 16px), 0% 16px
    );
}

#notes-modal .notes-header {
    padding: 22px 38px 18px;
    border-bottom: 1px solid rgba(0, 80, 100, 0.2);
    box-shadow: inset 0 1px 0 0 rgba(212, 165, 90, 0.4);
    position: relative;
}

#notes-modal .notes-title {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 1.3rem;
    color: rgba(10, 31, 36, 0.92);
    font-weight: 500;
    letter-spacing: 0.08em;
    margin: 0;
}

#notes-modal .notes-close {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 32px;
    height: 32px;
    border: 1px solid rgba(0, 80, 100, 0.35);
    background: rgba(255, 252, 240, 0.92);
    color: rgba(10, 31, 36, 0.7);
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s ease, color 0.2s ease;
    font-family: inherit;
    /* [Backlog #179] z-index: 10 —— .notes-header 自己也是 position:relative,
       且 DOM 上排在 .notes-close **之后** (index.html:2020 close → :2021 header)。
       同为定位元素且 z-index 都是 auto 时按 DOM 顺序绘制 → 后画的头部整个盖住按钮。
       头部背景透明, 所以**看得见却点不动**: 命中测试落到 .notes-header, 点击被吃掉,
       看起来像「按钮还是没反应」。照抄同族 .notes-pdf-close 的 z-index:10 (§7)。 */
    z-index: 10;
}

#notes-modal .notes-close:hover {
    background: rgba(0, 80, 100, 0.85);
    color: #fff;
}

#notes-modal .notes-body {
    padding: 24px 38px 60px;
    overflow-y: auto;
    flex: 1;
    position: relative;
}

/* §2 筛选栏
   [Backlog #221 · 2026-10-06] 容器由「单行 flex-wrap 自然换行」改为「纵向多行」。
   旧版 21 个 chip 全挤在一个 flex 容器里, 靠换行区分, **没有行语义**;
   两级化之后子级必须能 (a) 缩进表达从属 (b) 在两组子级之间插分隔线,
   这两件事都要求真行容器, 否则只能靠 margin 猜。 */
#notes-modal .notes-filter-bar {
    /* [Backlog #196] column → row: 左右两栏并排 (学科 | 时间)。
       照抄 life-photography.css:59 的 flex-direction: row。 */
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 18px;
    padding: 12px 0;
    border-bottom: 1px solid rgba(0, 80, 100, 0.2);
    margin-bottom: 18px;
}

/* [Backlog #196] 两栏子容器 —— 照抄 life-photography.css:82-88
   .photo-filter-col 的四条声明。min-width:0 必抄: 缺了它,
   flex 子项的 min-width 默认是 auto, chip 容器不肯收缩就会把栏撑宽
   —— photography 自己也是这么写的, 不是可选项。 */
#notes-modal .notes-filter-col {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1 1 0;
    min-width: 0;
}
/* 学科栏略宽 (3 个父级 / 6 个子级) vs 时间栏 (2 父级 / 9 子级)。
   实测 1920 下两栏内容宽度: 学科 615px / 时间 613px, 基本持平 ——
   按内容给 1.15:1 而不是照抄 photography 的 1.6:1 (那边地点栏有 3 个维度)。 */
/* [Backlog #210 · 2026-10-12] 两栏**非对称**: 左窄(学科 3 父级 + 6 子级)
   右宽(时间 2 父级 + 9 子级 + 6 年份) —— 用户原话「左边内容少, 右边内容多」。
   抄 Photography #91 的做法(它把内容多的地点栏设 1.6), 但**比例不是照抄**:
   那边是 1.6 : 1, 这边学科子级只有 6 颗且折叠后右侧只剩 6 颗, 给到 1.35 就够 ——
   比例由实测行数决定, 不由别处的数字决定。 */
#notes-modal .notes-filter-col--cat {
    flex: 1 1 0;
}
#notes-modal .notes-filter-col--term {
    flex: 1.35 1 0;
}

/* [Backlog #221] 行容器 —— 每一行自己负责换行。
   width:100% 是关键: 父级是 column 布局, 不占满宽度的话每行会按内容宽度收缩,
   换行点与设计意图不符。 */
#notes-modal .notes-filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    flex: 1;        /* [Backlog #196] 占满所属栏宽 (抄 photo-filter-chips:118) */
    min-width: 0;
}

/* 子级行: 缩进 + 收紧行距, 视觉上从属于上一行的父级。
   负 margin 把 4 行压到 3 行的观感高度, 免得筛选栏占掉过多竖向空间。 */
#notes-modal .notes-filter-row--sub {
    padding-left: 14px;
    gap: 4px;
    margin: -2px 0 2px;
}

/* [Backlog #206 · 2026-10-12] hidden 覆盖 —— **这两条是必需项, 不是加固**。
   .notes-chip 是 display:inline-flex / .notes-filter-row 是 display:flex,
   作者样式里的 display **盖得住** UA 的 [hidden]{display:none} (UA 规则特异度最低)。
   本轮用 hidden 属性实现「空子目录自动隐藏」, 少了这两条 = 芯片照样占位、
   照样可点, 而**控制台零报错、断言若只查 hidden 属性也照样全绿**。
   已实测: 带 display 声明的 [hidden] 按钮仍返回 54×29 的可见矩形。
   ⚠ **三个选择器缺一不可**: 第一版只写了 .notes-chip 与 .notes-filter-row,
     漏了 .notes-chip-sep —— 它也是 display:inline-block, 于是选「经济学」后
     子级行里留下一排孤零零的竖线 (| | | | 大五 交换期间 | | |)。
     **这个洞 shim 查不出来**(shim 没有 CSS, 隐藏就是隐藏), 只有截图能看见。
     凡是「设了 hidden 就当它不存在」的类, 都要在这里列一遍。
   同款写法本文件下方 .notes-section[hidden] 早已有先例 (防 grid 规则覆盖),
   两处是同一个坑的两个落点, 改其中一处记得看另一处。 */
#notes-modal .notes-chip[hidden],
#notes-modal .notes-chip-sep[hidden],
#notes-modal .notes-filter-row[hidden] {
    display: none;
}

/* 年份行: 时间栏的第三行。与上方「学期」块之间用一条极淡的横线分开 ——
   不分开的话, 「按年份」会读起来像是学期子级的续行 (它前面已经有一行缩进的
   子级了, 再跟一行同级的东西, 层级关系会被误读)。 */
/* [Backlog #253] 维度行: 左栏的「按维度」与右栏的「按年份」同形态 ——
   都是**独立的扁平维度行**, 上面一条极淡横线把它们与上一行分开
   (不分开会读成上一行的续行, 层级关系被误读)。 */
#notes-modal .notes-filter-row--year,
#notes-modal .notes-filter-row--dim {
    gap: 6px;
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid rgba(0, 80, 100, 0.12);
}

#notes-modal .notes-chip {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border: 1px solid rgba(0, 80, 100, 0.3);
    background: rgba(255, 252, 240, 0.85);
    color: rgba(10, 31, 36, 0.85);
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 12px;
    letter-spacing: 0.05em;
    cursor: pointer;
    transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
    border-radius: 2px;
}

#notes-modal .notes-chip:hover {
    background: rgba(0, 80, 100, 0.85);
    color: #fff;
    border-color: rgba(0, 80, 100, 0.85);
}

/* [Backlog #181] 选中态 —— 照搬同族 is-active 范式 (life-reading.css:129
   .reading-chip.is-active / life-photography.css:157 .photo-chip.is-active)。
   这里原来叫 .notes-chip--all, 但那个 class 是**身份**不是**状态**: 它在
   makeChip() 里静态加给「全部」芯片, 于是产生两个方向的错 ——
     (a) 选中任何学科/学期时**没有任何芯片高亮** (用户报的就是这个);
     (b) 「全部」永远保持满色, 与真实筛选状态**脱钩** —— 选完「建筑史」后,
         看上去仍像「全部」被选中。
   声明值一字未改: 选中态沿用它原本的深青底白字, 不发明新配色。
   .notes-chip--all 退化为**纯身份标记** (对齐 Reading 的 .reading-chip.is-all),
   不再有任何视觉规则 —— 与同族一致: 「全部」芯片只在它真的是当前筛选时才满色。 */
#notes-modal .notes-chip.is-active {
    background: rgba(0, 80, 100, 0.85);
    color: #fff;
    border-color: rgba(0, 80, 100, 0.85);
}

#notes-modal .notes-chip-sep {
    display: inline-block;
    width: 1px;
    height: 14px;
    background: rgba(0, 80, 100, 0.3);
    margin: 0 6px;
}

#notes-modal .notes-chip-dim {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 11px;
    color: rgba(0, 80, 100, 0.55);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/* [Backlog #221] 父级 / 子级 chip 的视觉分级。
   分级**只靠尺寸与描边深浅**, 不另配色 —— 本站 6 条纸雕铁律里「纯色无
   multi-stop 渐变」「不新增色板」都还在, 靠"大小 + 透明度"表达层级更稳。

   ⚠ 特异度陷阱: .notes-chip.is-active 是 3 个 class, .notes-chip--sub 只有 2 个,
     所以**子级选中态仍然是深青底白字**, 不会被下面的弱化样式盖掉。
     同理 :hover (多一个伪类) 依然压过 is-active, 与既有 .notes-chip:hover 一致。 */
#notes-modal .notes-chip--group {
    background: rgba(247, 241, 225, 0.95);
    border-color: rgba(0, 80, 100, 0.45);
    font-weight: 600;
}

#notes-modal .notes-chip--sub {
    padding: 3px 9px;
    font-size: 11px;
    border-color: rgba(0, 80, 100, 0.2);
    background: rgba(255, 252, 240, 0.6);
    color: rgba(10, 31, 36, 0.7);
}

#notes-modal .notes-chip--sub:hover {
    background: rgba(0, 80, 100, 0.85);
    color: #fff;
    border-color: rgba(0, 80, 100, 0.85);
}

/* [Backlog #210] "更多 +N" 折叠按钮 —— 抄 life-photography.css:176 的四条声明
   (虚线描边 + 弱化 + 斜体), **只抄机制不抄配色**: 那边 hover 用摄影的蓝
   #4a5d8f, 这边换成 Notes 的深青 #005064 族。
   虚线是刻意的: 它要让"这不是一个筛选值"一眼可辨。 */
#notes-modal .notes-chip--more {
    border-style: dashed;
    opacity: 0.75;
    font-style: italic;
    letter-spacing: 0.05em;
}
#notes-modal .notes-chip--more:hover {
    border-style: solid;
    opacity: 1;
    background: rgba(0, 80, 100, 0.08);
    border-color: rgba(0, 80, 100, 0.35);
    color: rgba(10, 31, 36, 0.95);
}

#notes-modal .notes-count {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 12px;
    color: rgba(0, 80, 100, 0.7);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin-bottom: 14px;
}

/* §3 课程网格 */
/* [Backlog #267 · 2026-10-23] **每行更多卡**: 改用 auto-fill + 窄轨道。
   旧值是 `repeat(2, 1fr)`(卡 422px), 宽屏阶梯在 notes-responsive.css 里
   按断点写死 3/4/5/6 列 —— 那些数**会随模态宽度变**, 且没法自适应。
   ⇒ 轨道宽 minmax(190px, 240px): 1400px 的模态里自动排 6 列(约 210~240px/张),
     密度翻倍; 轨道再窄就压不住中文标题了, 再宽就不像「笔记」了(竖版)。
   justify-content: center —— 轨道不满一行时居中, 不留半截空档。 */
#notes-modal .notes-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 240px));
    justify-content: center;
    gap: 14px;
}

/* §4 课程卡
   [Backlog #254 · 2026-10-22] 改成**家族卡的八角样式** —— 与 .project-card (portfolio-entry.css)
   和 .seaweed-frame--paper (seaweed-frame.css) **逐值一致**:
     clip-path 八角 12px / box-shadow 3px 4px 0 + 0 6px 14px + inset 0 1px 0
     / ::before 顶部 3.5px 主题色纸带 / ::after 1px 切面细线 (clip-path: inherit)
   ⚠ 原来的 `border` + `border-left 3px 古铜竖条` **都去掉**: 八角切角会把竖条两头斜切掉
   (看着是断的), 而家族卡一律 border:none + ::after 的 1px 细线描边;
   强调色改由家族同款的**顶部纸带**承担(同色 古铜 #b87333)。
   ⚠ overflow:hidden 是必须的: 八角之外的角要靠它切掉(家族卡同样带这一条)。 */
#notes-modal .notes-item {
    background: #f7f1e1;
    border: none;
    border-radius: 0;
    padding: 14px 16px;
    position: relative;
    overflow: hidden;
    cursor: pointer;
    /* 双层硬投影 + 顶部卡纸高光 (与 .project-card 逐值一致) */
    box-shadow:
        3px 4px 0px rgba(0, 3, 10, 0.18),
        0 6px 14px rgba(0, 3, 10, 0.10),
        inset 0 1px 0 rgba(255, 255, 255, 0.6);
    /* 八边形刻刀切角: 12px 斜切 */
    clip-path: polygon(
        12px 0%,
        calc(100% - 12px) 0%,
        100% 12px,
        100% calc(100% - 12px),
        calc(100% - 12px) 100%,
        12px 100%,
        0% calc(100% - 12px),
        0% 12px
    );
    transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1), box-shadow 0.3s ease;
}

/* hover: 抬升 -5px + 投影加深 (家族同款)
   ⚠ 这是**家族基线层**的值, 逐字等于 portfolio-entry.css:208 `.project-card:hover`
   与 seaweed-frame.css:202 `.seaweed-frame--paper:hover`。
   ⚠⚠ 别拿「作品集网格里渲染出来的那张卡」当参照 —— 那一层的 hover 被两条
   后加的 !important 规则改了 (见 §254 记录):
     · portfolio-grid.css:264 `.project-card.clustered-card:hover` → transform 变
       `rotate(0) translate(0,-6px) scale(1.05)` (比本条多一个放大)
     · portfolio-entry.css:222+ `.project-card:has(.tag-*):hover` → box-shadow 变
       深色双层 `0 8px 16px rgba(0,0,0,.8) / 0 30px 60px rgba(0,3,5,.95)`
   那两条是**作品集网格专属的强调手法**(旋转归零 + tag 强调色), 不是家族卡身份,
   套到 Notes 网格上会让整排卡抖动, 且深色投影与米白纸面打架。 */
#notes-modal .notes-item:hover {
    transform: translateY(-5px);
    box-shadow:
        5px 7px 0px rgba(0, 3, 10, 0.22),
        0 12px 24px rgba(0, 3, 10, 0.15),
        inset 0 1px 0 rgba(255, 255, 255, 0.8);
}

/* [Backlog #254] 按下态 (家族同款): 物理按下 —— 缩到 0.96 + 下沉 2px + 投影收成软影 + 压暗。
   家族来源两处, 声明值逐字相同:
     · portfolio-preview.css:151 `.project-card:active`
     · seaweed-frame.css:212  `.seaweed-frame--paper:active`
   ⚠ 必须排在 `:hover` **之后**: 两者特异度都是 (1,2,0), 同特异度时后写者胜 ——
   按住鼠标时 :hover 和 :active 同时命中, 靠源码顺序让 :active 赢。 */
#notes-modal .notes-item:active {
    transform: scale(0.96) translateY(2px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
    filter: brightness(0.8);
}

/* ---- 维度配色 (Backlog #267 · 2026-10-23) ----
   6 个维度各一个色, **全部取自站内既有色**(全站 CSS 出现 ≥3 次), 不新增色板:
     建筑史 #4a5d8f 靛蓝(摄影主题色) / 理论 #1f7a6a 青绿(配速色阶)
     技术 #b87333 古铜(本模块原色, 不变) / 实务 #b31515 砖红(全站强调色)
     阅读笔记 #6b4d8a 紫 / 设计 #5e6a1c 橄榄
   色相间隔 30~99°, 六色在米白纸带上两两可辨; 每个都是**深一档**的印刷色,
   压在 #f7f1e1 米白纸上仍然够暗(不像浅金 #d4a55a 那样 ΔL≈0 看不见)。
   ⚠ 卡体底色**不动**(仍是 #f7f1e1): 铁律 1「Opaque over transparent」
     要求每个面都是 100% 不透明的卡纸 —— 用 rgba 做色晕会把卡变半透明。
     ⇒ 类型色落在**顶部纸带**(家族机制) + **缩略图框的 1px 描边**(第二线索)。
   芯片(筛选栏「按维度」那一行)用同一个色 ⇒ 颜色↔类型自解释。
   ⚠ 筛选芯片本来就带 data-dim="dim" + data-val=<维度key>(notes-filter.js:379),
     所以芯片这边**一行 JS 都不用改**。 */
#notes-modal .notes-item[data-dim="history"]   { --notes-band: #4a5d8f; }
#notes-modal .notes-item[data-dim="theory"]    { --notes-band: #1f7a6a; }
#notes-modal .notes-item[data-dim="technique"] { --notes-band: #b87333; }
#notes-modal .notes-item[data-dim="practice"]  { --notes-band: #b31515; }
#notes-modal .notes-item[data-dim="reading"]   { --notes-band: #6b4d8a; }
#notes-modal .notes-item[data-dim="design"]    { --notes-band: #5e6a1c; }

#notes-modal .notes-item[data-dim] .notes-item-thumb {
    border-color: var(--notes-band, rgba(10, 31, 36, 0.22));
}

#notes-modal .notes-chip[data-dim="dim"][data-val="history"] { --notes-band: #4a5d8f; }
#notes-modal .notes-chip[data-dim="dim"][data-val="theory"] { --notes-band: #1f7a6a; }
#notes-modal .notes-chip[data-dim="dim"][data-val="technique"] { --notes-band: #b87333; }
#notes-modal .notes-chip[data-dim="dim"][data-val="practice"] { --notes-band: #b31515; }
#notes-modal .notes-chip[data-dim="dim"][data-val="reading"] { --notes-band: #6b4d8a; }
#notes-modal .notes-chip[data-dim="dim"][data-val="design"] { --notes-band: #5e6a1c; }
#notes-modal .notes-chip[data-dim="dim"] {
    border-color: var(--notes-band, rgba(0, 80, 100, 0.3));
}
/* ::before —— 顶部 3.5px 主题色纸带 (家族同款, 颜色取本模块的古铜 #b87333) */
#notes-modal .notes-item::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(180deg,
        var(--notes-band, #b87333) 0px,
        var(--notes-band, #b87333) 3.5px,
        transparent 3.5px,
        transparent 100%
    );
    /* 纸带跟着八角走: 顶边两角斜切, 不越出卡面 */
    clip-path: polygon(
        0 12px,
        12px 0,
        calc(100% - 12px) 0,
        100% 12px
    );
    z-index: 3;
}

/* ⚠ [Backlog #254] 家族副本 seaweed-frame.css:353 有一条「≤480px 关掉 3.5px 纸带」的规则,
   Notes **刻意不抄**: 家族那儿的纸带只是装饰(卡纸受光边),
   而 Notes 的纸带**兼作强调色** —— 它顶替了原先的 `border-left 3px 古铜竖条`
   (八角切角会把竖条两头斜切断, 已在卡体注释里说明), 小屏关掉就等于把强调色整个丢了。
   ⇒ 纸带保留到所有断点。 */

/* ::after —— 切面细线 (clip-path: inherit 跟着八角走; hover 加深, 与家族同款) */
#notes-modal .notes-item::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: transparent;
    border: 1px solid rgba(0, 3, 10, 0.12);
    clip-path: inherit;
    z-index: 2;
}
#notes-modal .notes-item:hover::after {
    border-color: rgba(0, 3, 10, 0.22);
}

/* §4.1 首页预览框 — PyMuPDF 离线预渲染 JPEG。
   object-fit: contain 保留整页比例, 纸白底衬托"装裱在卡纸上"的实物感。 */
/* [Backlog #267 · 2026-10-23] **缩略图改竖版**。
   旧值 `height: 200px` 是**横框**, 而笔记原页是竖的(595/846 = 0.703) ⇒
   object-fit: contain 把整页塞进横框, 页面实际只渲染成 141×200,
   **两边各留一大片空白**(实测)。改成按原页比例的竖框后:
     ① 页面铺满框宽(约 210×298), 预览比原来**大 1.5 倍**;
     ② 卡片自然变高变窄(竖版), 不用再靠压扁缩略图换列数;
     ③ 旧阶梯里「越宽屏把缩略图缩到 135px」的补偿**全部作废**。
   ⚠ aspect-ratio 必须配 height:auto —— 写了 height 的话比例会被忽略。 */
#notes-modal .notes-item-thumb {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 595 / 846;
    height: auto;
    margin: 0 0 10px 0;
    background: #fbf8f5;
    border: 1px solid rgba(10, 31, 36, 0.22);
    box-shadow: 1px 1px 0 rgba(10, 31, 36, 0.12);
    overflow: hidden;
}

#notes-modal .notes-item-thumb-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center top;
    background: #fbf8f5;
}

#notes-modal .notes-item-thumb-cap {
    position: absolute;
    right: 0;
    bottom: 0;
    padding: 2px 7px;
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 9px;
    letter-spacing: 0.14em;
    color: rgba(255, 252, 240, 0.95);
    background: rgba(10, 31, 36, 0.72);
}

#notes-modal .notes-item-thumb--missing {
    display: flex;
    align-items: center;
    justify-content: center;
}

#notes-modal .notes-item-thumb-ph {
    font-size: 11px;
    letter-spacing: 0.08em;
    color: rgba(10, 31, 36, 0.45);
}

#notes-modal .notes-item-title {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 15px;
    font-weight: 600;
    color: rgba(10, 31, 36, 0.95);
    margin: 0 0 4px 0;
    letter-spacing: 0.02em;
}

#notes-modal .notes-item-en {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 11px;
    color: rgba(0, 80, 100, 0.7);
    margin: 0 0 8px 0;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

#notes-modal .notes-item-meta {
    font-size: 11px;
    color: rgba(10, 31, 36, 0.6);
    letter-spacing: 0.03em;
    margin: 0 0 8px 0;
    line-height: 1.5;
}

#notes-modal .notes-pdf-large {
    color: #b31515;
    font-weight: 600;
}

#notes-modal .notes-item-note {
    font-size: 12px;
    color: #b87333;
    font-style: italic;
    margin: 6px 0 10px 0;
    padding-left: 10px;
    border-left: 1px dashed rgba(184, 115, 51, 0.4);
}

/* ==========================================================
   §4.5 卡片水印 + 置顶 (Backlog #174)
   ------------------------------------------------------------
   水印照搬 Portfolio 建筑作品卡的范式 (portfolio-entry.css §「编号水印」):
       .project-card::before { content: attr(data-watermark); }
   文案由 JS 写进 data-watermark (DATA.watermarkText), 与笔记浏览器
   那层水印**同源** —— 一处改两处变。

   ⚠ 与 Portfolio 的一处**刻意差异**: Portfolio 的 ::before 用 z-index:1
     压在内容之上, 靠 10% 不透明度"若隐若现"; 但 Portfolio 水印只有 2 个字符
     (C1 / P1), 而这里是一整行 45 字的标识文本, 且 Notes 卡的卡面被标题/英文名/
     元数据塞满 —— 压在卡上会直接毁可读性 (实测元数据行被糊掉)。
     → 水印改挂在 **.notes-item-thumb::after** 上, 即印在「文档首页图像」上:
       水印本来就该印在纸上, 不该印在 UI 文字上; 那片区域也足够大, 看得清。
   ========================================================== */
#notes-modal .notes-item-thumb::after {
    content: attr(data-watermark);
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 18px;
    text-align: center;
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.4;
    letter-spacing: 0.02em;
    word-break: break-word;
    /* ⚠ 不用 var(--theme-color): 那是浅金 #d4a55a, 压在米白 #f7f1e1 上
       对比度≈0, 30% 也看不见。Portfolio 的 --theme-color 是深青/橄榄/灰,
       10% 就够 —— 直接照抄色值是照抄了一个不成立的假设。
       改用文件里已有的古铜 #b87333 (同 .notes-item-note / 置顶标题同色系)。 */
    color: #b87333;
    opacity: 0.30;            /* 实测合成后与米白底 ΔL=0.14, 肉眼可辨又不抢焦点 */
    pointer-events: none;
    user-select: none;
    -webkit-user-select: none;
    z-index: 1;               /* 盖在 img 之上 */
}
/* 页数角标要压在水印之上, 否则被糊掉 */
#notes-modal .notes-item-thumb-cap {
    z-index: 2;
}

/* ---- 置顶区 ---- */
#notes-modal .notes-section {
    margin-bottom: 20px;
}
#notes-modal .notes-section[hidden] {
    display: none;          /* hidden 属性默认 display:none, 显式写死防被 grid 规则覆盖 */
}
#notes-modal .notes-section-label {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 12px;
    color: rgba(0, 80, 100, 0.75);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin-bottom: 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid rgba(0, 80, 100, 0.2);
}
#notes-modal .notes-section--pinned .notes-section-label {
    color: #b87333;         /* 古铜色, 跟 §5 主题色同族, 与普通区区分 */
    border-bottom-color: rgba(184, 115, 51, 0.35);
}

/* ---- 置顶徽章 (照搬 Photography .photo-card__pinned-badge) ---- */
#notes-modal .notes-item-pinned-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 2;              /* 高于水印(0) 与缩略图(auto), 压在卡片右上角 */
    font-size: 14px;
    line-height: 1;
    pointer-events: none;    /* ⚠ 必须 none, 否则会吃掉整卡的点击 */
    filter: drop-shadow(0 1px 1px rgba(10, 31, 36, 0.25));
}
#notes-modal .notes-item--pinned {
    border-left-color: #b87333;   /* 置顶卡左侧强调条换成古铜色 */
    background: #f9f4e7;
}

/* §4.6 跳转落点脉冲高亮 (Backlog #176 · 2026-10-04)
   ------------------------------------------------------------
   由 life-resume-jump.js 的 highlightNoteCard() 挂上, 1.8s 后移除。
   目的: 跨模态跳过来之后用户要能一眼看到落在哪张卡 —— 补上 X1 §交互架构
   里「简历卡 → 协议层 → 筛选 → 目标卡高亮」这条链的最后一环。

   ⚠ 刻意**不用** animation-fill-mode 永久停驻, 也不用 animationend 回调移除
     class (合成器出帧才推进动画时间线, 本项目 rAF 长期被节流 #165, 回调可能不跑 →
     class 永久残留)。移除逻辑在 JS 里用 setTimeout + token 校验兜底。

   ⚠⚠ **测这条规则时有两个陷阱, 都踩过 (别重蹈)**:
     ① `box-shadow` 读到的古铜其实是 **@keyframes 0% 帧** (`0 0 0 0 rgba(184,115,51,.75)`),
        不是这条静态声明 —— 动画在首帧就覆盖了它。真正生效的静态值是
        `0 0 0 3px rgba(184,115,51,.45)`。
     ② `border-color` **生效但同 tick 测不到终值**: `.notes-item` 上有
        `transition: … border-color 0.2s ease`, class 挂上后浏览器在插值起点,
        `getComputedStyle` 读到的仍是旧值 `rgba(0,80,100,.3)`。要读终值得等 0.2s
        过渡走完 (而本环境 rAF/合成器被节流, 后台 tab 走不完)。
        → 故主视觉信号**必须**由不参与 transition 的 animation 承担, border 只当保险。

   用古铜 #b87333 而不是主题浅金 #d4a55a: 浅金压米白对比度≈0 (#174 实测 ΔL≈0.02),
   高亮必须在米白底上真的看得见。古铜环 ΔL 远高于可辨阈值。 */
#notes-modal .notes-item--jump-target {
    animation: notes-jump-pulse 1.8s ease-out;
    /* [Backlog #254] 原来的 `border-color: #b87333` 保险项**失效了** —— 卡体改成家族样式后
       border 是 none, 没有可变的边色。强调改由 ::after 的 1px 细线承担(那才是卡的可见边)。 */
    box-shadow: 0 0 0 3px rgba(184, 115, 51, 0.45), 0 8px 20px rgba(10, 31, 36, 0.18);
}
/* ⚠ 这里必须比 `#notes-modal .notes-item:hover::after` (1,3,0) 更具体, 否则
   鼠标悬停时边色被 hover 规则盖掉(同特异度时**后写者胜**, 而 hover 规则在前面)。
   写成 `.notes-item.notes-item--jump-target` → (1,3,0) 且位置更靠后 → 赢。 */
#notes-modal .notes-item.notes-item--jump-target::after {
    border-color: #b87333;            /* 保险项: 过渡走完后到位, 不承担主视觉 */
}
@keyframes notes-jump-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(184, 115, 51, 0.75), 0 8px 20px rgba(10, 31, 36, 0.18); }
    35%  { box-shadow: 0 0 0 8px rgba(184, 115, 51, 0.28), 0 8px 20px rgba(10, 31, 36, 0.18); }
    70%  { box-shadow: 0 0 0 3px rgba(184, 115, 51, 0.45), 0 8px 20px rgba(10, 31, 36, 0.18); }
    100% { box-shadow: 0 0 0 0 rgba(184, 115, 51, 0), 0 8px 20px rgba(10, 31, 36, 0.18); }
}
@media (prefers-reduced-motion: reduce) {
    #notes-modal .notes-item--jump-target {
        animation: none;   /* 保留静态 ring, 靠 border-color + box-shadow 表明落点 */
    }
    /* [Backlog #254] 家族同款: 降级动效时取消 hover 抬升
       (seaweed-frame.css:367 `.seaweed-frame--paper:hover` → 只留 rotate)。
       Notes 卡没有 rotate, 故直接 none。 */
    #notes-modal .notes-item:hover {
        transform: none;
    }
}

/* §5 主题色 */
#notes-modal {
    --theme-color: #d4a55a;

    /* [Backlog #215 · 2026-10-06] 统一 Notes 字体基线。
       实测 (getComputedStyle) 本模块有直接文本的元素分两类:
         ① 9 个显式声明 → 全部 'Cinzel', 'Playfair Display', sans-serif
         ② 4 个**一条 CSS 规则都没有**, 纯继承 → 全部解析成裸 "Times New Roman":
            .notes-close / .notes-item-meta / .notes-pdf-large / .notes-item-note
       Times 泄漏在本项目是已知铁律违反 (Resume 侧 Backlog #123 修过同款),
       在这里只需给根元素一条基线, 4 个继承者一并归位 —— 比逐个补规则更少改动,
       也不会漏掉以后新增的未声明元素。
       满屏水印 (.notes-pdf-watermark) 本轮另行去掉栈里多出的 monospace,
       使两处水印与其余内容完全同栈。 */
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
}

/* §7 PDF 模态 (复用 portfolio-preview 浅米白容器范式) */
.notes-pdf-modal.collage-modal-overlay {
    background: rgba(247, 241, 225, 0.55);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 11000000;
}

.notes-pdf-modal .notes-pdf-container {
    background: #f7f1e1;
    border: 1px solid rgba(0, 80, 100, 0.4);
    box-shadow:
        0 8px 20px rgba(10, 31, 36, 0.18),
        0 40px 80px rgba(10, 31, 36, 0.12),
        inset 0 1px 0 rgba(255, 255, 255, 0.5);
    width: min(95vw, 1200px);
    height: min(95vh, 900px);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    position: relative;
    clip-path: polygon(
        16px 0%, calc(100% - 16px) 0%,
        100% 16px, 100% calc(100% - 16px),
        calc(100% - 16px) 100%, 16px 100%,
        0% calc(100% - 16px), 0% 16px
    );
}

.notes-pdf-modal .notes-pdf-header {
    padding: 14px 24px;
    background: rgba(212, 165, 90, 0.06);
    border-bottom: 2px solid var(--theme-color, #d4a55a);
    box-shadow: inset 0 1px 0 rgba(212, 165, 90, 0.3);
    flex-shrink: 0;
    position: relative;
}

.notes-pdf-modal .notes-pdf-title {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 1rem;
    color: rgba(10, 31, 36, 0.92);
    font-weight: 600;
    margin: 0;
    padding-right: 50px;
    letter-spacing: 0.04em;
}

.notes-pdf-modal .notes-pdf-subtitle {
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: rgba(0, 80, 100, 0.7);
    margin: 4px 0 0 0;
    font-weight: 400;
}

.notes-pdf-modal .notes-pdf-close {
    position: absolute;
    top: 14px;
    right: 18px;
    width: 28px;
    height: 28px;
    border: 1px solid rgba(0, 80, 100, 0.35);
    background: rgba(255, 252, 240, 0.92);
    color: rgba(10, 31, 36, 0.7);
    cursor: pointer;
    font-size: 18px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s ease, color 0.2s ease;
    font-family: inherit;
    z-index: 10;
}

.notes-pdf-modal .notes-pdf-close:hover {
    background: rgba(0, 80, 100, 0.85);
    color: #fff;
}

/* [Backlog #170] 图片舞台 —— 取代 <iframe> 嵌 PDF。
   整条防下载逻辑的落点: DOM 里只有 <img>, 浏览器拿不到任何 PDF 文件。
   容器 .notes-pdf-container 是 flex column + overflow: hidden, 这里吃掉剩余高度。 */
.notes-pdf-modal .notes-pdf-stage {
    flex: 1;
    min-height: 0;              /* flex 子项默认 min-height:auto, 不写会被内容顶开 */
    overflow: auto;
    /* ⚠ position:relative 不是装饰 —— syncVisiblePages() 与 scrollToPage()
       都用 img.offsetTop 作为"该页在滚动内容里的纵向位置", 只有舞台自己是
       定位祖先时这个值才不含 header 高度、不受外层定位上下文干扰。 */
    position: relative;
    /* 底色比容器略深, 衬托白纸边缘 */
    background: #efe8d6;
    /* ⚠ 故意用 display:block + 子元素 margin:auto 居中, 而不是
       justify-content:center —— flex 容器 + overflow 时居中会裁掉左侧且滚不回去 */
    display: block;
    padding: 12px;
    /* ⚠ 刻意**不**用 scroll-behavior: smooth
       ① 平滑滚动依赖动画帧, 在 rAF 被节流的环境里会永远走不完 (Backlog #165 起的老问题),
          实测导致 scrollToPage() 设了 scrollTop 也不动;
       ② 点「上一页/下一页」要的是立刻到位, 页码指示才追得准。 */
    user-select: none;
    -webkit-user-drag: none;
}

/* 宽度由 JS applyZoom() 按「舞台可用宽 × 缩放比」写入 */
.notes-pdf-modal .notes-pdf-pages {
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex-shrink: 0;
}

.notes-pdf-modal .notes-pdf-page {
    display: block;
    width: 100%;
    height: auto;
    /* [Backlog #170] 懒加载的命门: 未加载的 <img> 也必须有真实高度。
       没有 src 的 img 高度为 0, N 张会叠在同一位置 -> IntersectionObserver
       判定它们"全部相交" -> 反而一次性全量加载。
       实测 1,599 页宽高比 0.6627~0.7257 / 中位 0.7038 / 0 张横向,
       故占位取 595/846 (=0.7033)。`auto` 前缀是关键: 图片加载后
       自动切回该页真实比例, 占位值只负责"还没加载时"的布局。 */
    aspect-ratio: auto 595 / 846;
    background: #fff;
    box-shadow: 0 2px 8px rgba(10, 31, 36, 0.16);
    user-select: none;
    -webkit-user-drag: none;
    -webkit-touch-callout: none;
}

/* 数据层缺 pages 字段时的明确提示 (不留空白) */
.notes-pdf-modal .notes-pdf-missing {
    padding: 60px 20px;
    text-align: center;
    color: rgba(10, 31, 36, 0.6);
    font-size: 0.9rem;
    line-height: 2;
}
.notes-pdf-modal .notes-pdf-missing small {
    color: rgba(10, 31, 36, 0.42);
    font-size: 0.75rem;
}

/* 工具栏: 页码 + 翻页 + 缩放。
   z-index 7 > 水印层 5 —— 水印是 inset:0 的绝对定位, 不加会盖在工具栏上。 */
.notes-pdf-modal .notes-pdf-toolbar {
    position: relative;
    z-index: 7;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 8px;
    padding: 8px 24px 10px;
    background: rgba(212, 165, 90, 0.06);
    border-top: 1px solid rgba(0, 80, 100, 0.18);
}

.notes-pdf-modal .notes-pdf-nav {
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border: 1px solid rgba(0, 80, 100, 0.35);
    background: rgba(255, 252, 240, 0.92);
    color: rgba(10, 31, 36, 0.75);
    cursor: pointer;
    font-size: 15px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s ease, color 0.2s ease;
}
.notes-pdf-modal .notes-pdf-nav:hover:not(:disabled) {
    background: rgba(0, 80, 100, 0.85);
    color: #fff;
}
.notes-pdf-modal .notes-pdf-nav:disabled {
    opacity: 0.3;
    cursor: default;
}
.notes-pdf-modal .notes-pdf-nav--zoom {
    width: 26px;
    height: 26px;
    font-size: 14px;
}

.notes-pdf-modal .notes-pdf-indicator {
    min-width: 92px;
    text-align: center;
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    color: rgba(0, 80, 100, 0.85);
    user-select: none;
}

.notes-pdf-modal .notes-pdf-zoomval {
    min-width: 54px;
    height: 26px;
    border: 1px solid rgba(0, 80, 100, 0.25);
    background: transparent;
    color: rgba(10, 31, 36, 0.7);
    font-family: 'Cinzel', 'Playfair Display', monospace, sans-serif;
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    cursor: pointer;
}
.notes-pdf-modal .notes-pdf-zoomval:hover {
    border-color: rgba(0, 80, 100, 0.6);
    color: rgba(0, 80, 100, 0.95);
}

/* [Backlog #217 · 2026-10-06] 页码跳转组 —— 参照建筑作品集模态的 .pdf-jump-input /
   .pdf-jump-btn 几何, 颜色沿用本工具栏既有的「深青描边 + 透明底」语汇
   (与 .notes-pdf-zoomval 同款, 不引入第二套控件皮肤)。
   分隔: 左侧一段留白把它与「翻页组」分开, 右侧同理与「缩放组」分开 —— 语义上
   它属于翻页而不是缩放, 挤在一起会让人误以为是缩放的一部分。 */
.notes-pdf-modal .notes-pdf-jump {
    display: flex;
    align-items: center;
    gap: 4px;
    margin: 0 10px;
}
.notes-pdf-modal .notes-pdf-jump-input {
    width: 54px;
    height: 26px;
    box-sizing: border-box;
    padding: 0 8px;
    border: 1px solid rgba(0, 80, 100, 0.25);
    background: transparent;
    color: rgba(10, 31, 36, 0.85);
    font-family: 'Cinzel', 'Playfair Display', monospace, sans-serif;
    font-size: 0.68rem;
    text-align: center;
    outline: none;
}
.notes-pdf-modal .notes-pdf-jump-input::placeholder {
    color: rgba(10, 31, 36, 0.4);
}
.notes-pdf-modal .notes-pdf-jump-input:focus {
    border-color: rgba(0, 80, 100, 0.7);
}
.notes-pdf-modal .notes-pdf-jump-go {
    height: 26px;
    padding: 0 10px;
    border: 1px solid rgba(0, 80, 100, 0.25);
    background: transparent;
    color: rgba(10, 31, 36, 0.7);
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 0.66rem;
    letter-spacing: 0.08em;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.2s, color 0.2s;
}
.notes-pdf-modal .notes-pdf-jump-go:hover {
    border-color: rgba(0, 80, 100, 0.6);
    color: rgba(0, 80, 100, 0.95);
}

.notes-pdf-modal .notes-pdf-watermark {
    position: absolute;
    inset: 0;
    z-index: 5;
    pointer-events: none;
    user-select: none;
    /* [Backlog #174] 原来是 14px / 400 / rgba(...,0.06) —— 6% 压在明亮扫描页上
       等于隐形, 用户报"笔记看不见水印"。文字格式一字未改, 只把呈现提到看得见:
       字号 ×2.1、700 加粗、不透明度 0.06 → 0.15。 */
    color: rgba(10, 31, 36, 0.15);
    font-family: 'Cinzel', 'Playfair Display', sans-serif;

    font-size: 30px;
    font-weight: 700;
    line-height: 80px;
    letter-spacing: 0.04em;
    transform: rotate(-22deg);
    transform-origin: center center;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    word-break: break-all;
    overflow: hidden;
    padding: 0 40px;
}

.notes-pdf-modal .notes-pdf-notice {
    position: absolute;
    /* [Backlog #170] 底部新增了工具栏 (约 44px), 警示条上移让开, 否则叠在按钮上 */
    bottom: 56px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 6;
    pointer-events: none;
    font-family: 'Cinzel', 'Playfair Display', sans-serif;
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: rgba(10, 31, 36, 0.7);
    background: rgba(247, 241, 225, 0.85);
    border: 1px solid rgba(0, 80, 100, 0.35);
    padding: 6px 18px;
    box-shadow:
        0 1px 0 rgba(10, 31, 36, 0.15),
        inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

/* §8 空态 */
#notes-modal .notes-empty {
    grid-column: 1 / -1;
    text-align: center;
    padding: 60px 20px;
    color: rgba(10, 31, 36, 0.5);
    font-style: italic;
    font-size: 13px;
}

/* §8.5 [Backlog #170] 窄屏: 工具栏按钮换行, 页面图占满宽度 */
@media (max-width: 768px) {
    .notes-pdf-modal .notes-pdf-toolbar {
        padding: 6px 12px 8px;
        gap: 6px;
    }
    .notes-pdf-modal .notes-pdf-indicator {
        min-width: 76px;
        font-size: 0.66rem;
    }
    .notes-pdf-modal .notes-pdf-notice {
        bottom: 78px;
        font-size: 10px;
        padding: 5px 12px;
    }
}

/* §9 [Backlog #170] 整节移除 —— 记一笔, 免得后人重蹈
   #169 当时写下的 .notes-pdf-iframe::part(download) { display:none }:
     ① #169 实测 Chrome 内置 PDF viewer **不暴露** shadow part, 那是死代码;
     ② #170 起根本没有 <iframe> 了 —— 页面是逐页 <img>, **连下载按钮都不存在**,
        更没有可另存的对象。这条路到此为止, 不必再试 PDF.js
        (file:// 需 Range, Backlog #95 已否决)。 */

/* §10 Notes 大卡 (.notes-module-card) — 与作品卡同构的竖版
   [Backlog #183 · 2026-10-05] 用户原话 "notes的卡片样式参考作品集其它卡片的样式",
   拍板「改成竖版与作品卡同构」+「改成中性米白, 与作品卡完全一致」。
   本节每个值都是从**真实 .project-card 实测**抄来的, 不是按公式推的。基准卡 P1 实测:
     rect 200×180 / flex-direction column / padding 12px 10px / min-height 180px /
     border 0 / border-radius 0 / overflow hidden / cursor pointer / user-select none /
     clip-path polygon(12px …) 八角 / box-shadow 硬边 3px 4px rgba(0,3,10,.18)
       + 0 6px 14px rgba(0,3,10,.10) + inset 0 1px 0 rgba(255,255,255,.6) /
     transition transform .3s cubic-bezier(.25,.46,.45,.94) + box-shadow .3s /
     ::before 编号水印 (clamp(5rem,8.5vw,12rem) / 900 / opacity .10 / z-index 1) /
     ::after 顶部描边 1px rgba(0,3,10,.12) + clip-path inherit + z-index 2 /
     hover translateY(-5px) + 5px 7px 0 rgba(0,3,10,.22) …, ::after 描边转 .22 /
     meta 三行: tag 9px Cinzel uppercase 600 / title 13px display 600 #333 line-clamp 2 /
       date 9px Cinzel #6a7378 nowrap
     logo-wrapper: flex 1 1 0 / min-height 0 / max-height 180px / margin-bottom 5px
     meta 区: flex 0 0 auto + min-height 60px + z-index 5 (flex-shrink:0 保证日期不被裁)

   ⚠ **三个值必须按「运行时实测」抄, 不能按源文件声明抄** ——
   遍历 document.styleSheets 逐条溯源 (Backlog #183 实测) 发现:
     ① transition 源声明在 portfolio-entry.css:127 是 cubic-bezier(.25, 1, .5, 1),
        但**胜出者是 portfolio-preview.css** 的 .project-card [important] ——
        0.3s cubic-bezier(.25, .46, .45, .94) (即 ease), 因为 portfolio-preview 排在其后。
        本节抄的是**实测胜出值**。
     ② 卡宽 200px **不是** portfolio-grid.css 的 150px —— 那是 .clustered-card 基础值,
        被 portfolio-grid-responsive.css 的 @media (max-width: 1279px) 覆盖成 200px
        (实测 rect 200×180)。宽屏 ≥1280 时簇内卡才回到 150px。
     ③ min-height 同样有多档响应式覆盖 (165 / 180 / 200 / 210 / 220 / 230 / 240px)。
   **本节宽度取 200px 并固定**: 那是作品卡在 ≤1279 主流档的实测宽度;
   作品卡宽度之所以响应式, 是因为它被塞进簇的 grid cell, 而 Notes 卡是独立单卡、
   不受簇约束, 跟随断点会在宽屏缩到 150px 显得孤零。**这是唯一一处刻意的偏离。**

   ⚠⚠ **class 刻意不叫 project-card** —— 本节最要紧的一条。
   有四个 JS 系统对**所有** `.project-card` 生效, 给 Notes 卡套上这个 class 会被误接管:
     ① portfolio-grid.js:63  bindProjectCards() —— click 按 X1/PDF 分发, 会把点击抢去
        走 X1 模态或新标签页, **Notes 模态就开不出来了**;
     ② portfolio-grid.js:227 clusterSingleGrid() —— 按 watermark 首字符 (X/P/M/S/C/O) 聚类,
        会把 "NT" 当成一个不存在的分类参与摆位;
     ③ main.js:462 —— 鼠标倾斜视差;
     ④ card-draw-animation.js —— 抽卡翻牌动画 (依赖 .project-card 的 clip-path)。
   所以保留独立 class, 只把**视觉值**对齐过去。将来作品卡改了, 这里必须跟着改。
   ⚠ 上一版 (§10 旧) 的 .notes-module-watermark 是一条**死规则** —— DOM 里从来没有
   <span class="notes-module-watermark">, 改用 ::before + attr(data-watermark) 后
   机制与作品卡完全一致, 该规则随之删除。 */
/* ==========================================================
   [Backlog #204 · 2026-10-12] Notes 衬底拆成「盒子 + 托盘」两层, 与上面两段对齐。

   用户原话:「notes的卡片底下的衬底的margin也和上面建筑作品集和ai lab的margin对齐」

   问题的准确形态 (实测 12 档): **右缘在每一档都完全对齐(差 0)**, 左缘差全部来自**宽度**
     建筑网格 / AI Lab pair : max-width 1080(≤1279 760 / ≤899 100%), 托盘 1068
     .notes-module         : max-width 320                          ← 右侧一条窄带
     1440 视口左缘差 760px; 1024 档 440px。

   为什么会错位: §184.1 当初写的是「`.portfolio-grid--ai` 用 `max-width: 320px`,
   复刻同值, 紧邻两块面板**等宽**」—— 这条在 #200 之后**失效了**: #200 把 AI Lab 从
   320px 的两块小面板改成了**铺满 1080 整条带**。前提没了, 复刻值就变成了错值。
   与 §200.4 记的「断点是手抄的, 对方改了不会跟着动」同源。

   为什么必须拆成两层: `.notes-module` 原本**一个元素身兼两职** ——
   既是对齐用的盒子(该 1080), 又是有底色描边的托盘(该 1068 = 1080 − 2×6)。
   #200 之前两者都是 320, 身兼两职没问题; 现在两者不再相等, 必须分开。
   拆法照既有的 `.ai-lab-pair`(盒子) > `.portfolio-theme-cluster`(托盘), 不发明新范式。
   ========================================================== */
.notes-module {
    /* 盒子层 —— 逐条抄 life-ai-modal.css 的 .ai-lab-pair (同源 .portfolio-grid--architecture):
       display/grid-template 这几条是**给内层托盘**用的, 盒子自己不需要, 故不复抄。 */
    margin: 30px 0 0 auto;                 /* 与 .ai-lab-pair 同: 上 30px + 右对齐 */
    width: 100%;
    max-width: 1080px;                     /* 抄 .ai-lab-pair 基础档 */
    box-sizing: border-box;
    /* 14px 上下 / 6px 左右 —— 与 .ai-lab-pair / .portfolio-grid 同值,
       正是这 6px 让内层托盘落在 826..1894 而不是 820..1900 */
    padding: 14px var(--space-3);
}

/* 托盘层 —— 逐值抄 .portfolio-theme-cluster (portfolio-grid.css:68-93) */
.notes-module-tray {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    justify-items: center;
    align-items: center;
    /* cluster 的 padding: 22px 上（留给 label） / 14px 左右 / 26px 下（呼吸） */
    padding: 22px 14px 26px;
    min-height: 420px;                    /* 与 cluster 同高 */
    background: rgba(252, 245, 230, 0.45);
    border: 1px solid rgba(210, 190, 155, 0.4);
    border-radius: 6px;
}

/* [Backlog #204] max-width 阶梯 —— 逐档抄 life-ai-modal.css 的 .ai-lab-pair
   (建筑网格那侧同理, 见 portfolio-grid-responsive.css:62 / :132)。
   ⚠ 手抄的: 建筑那边改断点, 这里不会自动跟(同 §200.4 记的债)。 */
@media (max-width: 1279px) {
    .notes-module {
        max-width: 760px;
    }
}
@media (max-width: 899px) {
    .notes-module {
        max-width: 100%;
    }
}
/* 衬底右下角小标签 —— 逐值抄 .portfolio-theme-cluster::before
   (portfolio-grid.css:179-192)。cluster 那边用 content: attr(data-cluster-label)
   由 JS 按 data-cluster 映射出 "Perception" / "Monument" …; Notes 是静态块,
   直接写字面量, 不必为此加 data 属性。 */
.notes-module-tray::before {
    content: 'Learning Notes';
    position: absolute;
    bottom: 4px;
    right: 8px;
    font-family: var(--font-serif);
    font-size: var(--type-micro-sm);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: #333333;
    font-weight: 600;
    pointer-events: none;
    z-index: 0;
}
.notes-module-card {
    position: relative;
    display: flex;
    /* 竖版: logo 区在上, meta 三行在下 (与 .project-card 逐项同构) */
    flex-direction: column;
    /* [Backlog #184] 100% → 200px: 父级 .notes-module 从「卡本身」变成了「衬底」
       (320px 上限 - 2×14px padding = 292px 内容盒), 若还写 width:100% 卡会被拉成
       292px 宽, 与旁边 200px 的作品卡**不同构**。宽度基准仍是 #183 实测的 200×180。 */
    width: 200px;
    padding: var(--space-4) var(--space-5);   /* 12px 10px, 同作品卡 */
    min-height: 180px;
    /* 中性米白 = 作品卡基础底色 #f5f5f7 (#183 用户拍板, 放弃 #182 的 #fbf8f5 金调) */
    background: #f5f5f7;
    border: none;
    border-radius: 0;
    text-decoration: none;
    /* 主题色只喂给水印 (::before); 中性卡取作品卡 Other 档的灰 */
    --theme-color: #6a7378;
    /* 八边形刻刀切角: 12px (作品卡的值; §10 旧版横条是 8px) */
    clip-path: polygon(
        12px 0%,
        calc(100% - 12px) 0%,
        100% 12px,
        100% calc(100% - 12px),
        calc(100% - 12px) 100%,
        12px 100%,
        0% calc(100% - 12px),
        0% 12px
    );
    /* 浅色卡纸: 硬边切角投影 + 顶部高光 (与 .project-card 逐值相同) */
    box-shadow:
        3px 4px 0px rgba(0, 3, 10, 0.18),
        0 6px 14px rgba(0, 3, 10, 0.10),
        inset 0 1px 0 rgba(255, 255, 255, 0.6);
    cursor: pointer;
    /* ⚠⚠ [Backlog #183] 这两行是「能不能点」的全部要害, 别删。
       #content-wrapper (portfolio-layout.css:60) 声明了 pointer-events: none ——
       而 pointer-events 是**可继承属性**, 整棵子树默认 none, **每个可交互元素必须
       自己声明 auto 才能参与 hit-test**。缺了它, 浏览器 hit-test 直接跳过本卡,
       事件落到 body 上 —— 实测 elementsFromPoint 栈 [0] 是 <body>, 卡根本不在栈里。
       跟 .portfolio-entry-card (portfolio-card-entry.css:115-120) / .project-card
       (portfolio-entry.css:266) 是同一条铁律, 本项目里已经因此踩坑多次。
       z-index: 130 同理 —— .seaweed-label-layer (z=20) 虽然 pointer-events:none,
       但它的子元素 .seaweed-label 是 position:absolute + pointer-events:auto + opacity:0
       (**不可见照样参与命中测试**), 卡片必须浮在它之上才点得动。 */
    pointer-events: auto;
    position: relative;
    z-index: 130;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    overflow: hidden;
    transform: translateZ(0);
    will-change: transform;
    transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.3s ease;
}
/* 编号水印: 机制与 .project-card::before 完全相同, 只 content 取 data-watermark="NT" */
.notes-module-card::before {
    content: attr(data-watermark);
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-family: var(--font-serif);
    font-size: clamp(5rem, 8.5vw, 12rem);
    font-weight: 900;
    line-height: 0.85;
    color: var(--theme-color);
    opacity: 0.10;
    pointer-events: none;
    user-select: none;
    z-index: 1;
    letter-spacing: -0.06em;
    text-transform: uppercase;
}
/* 顶部描边: clip-path: inherit 跟着卡一起切角 (与作品卡同款) */
.notes-module-card::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: transparent;
    border: 1px solid rgba(0, 3, 10, 0.12);
    clip-path: inherit;
    z-index: 2;
}
.notes-module-card:hover,
.notes-module-card:focus-visible {
    transform: translateY(-5px);
    box-shadow:
        5px 7px 0px rgba(0, 3, 10, 0.22),
        0 12px 24px rgba(0, 3, 10, 0.15),
        inset 0 1px 0 rgba(255, 255, 255, 0.8);
}
.notes-module-card:hover::after,
.notes-module-card:focus-visible::after {
    border-color: rgba(0, 3, 10, 0.22);
}
/* logo 区: 对应 .project-logo-wrapper (flex 撑高 + max-height 防撑爆) */
/* [Backlog #295 · 2026-10-26] 📓 emoji → 自绘 SVG(螺旋本 + 铅笔)。
   尺寸沿用 emoji 原来的字号(--icon-logo-placeholder = 2.8rem), 视觉重量不变。
   ⚠ color 给成卡片主题灰 #6a7378 —— SVG 的描边都走 currentColor。 */
.notes-module-logo-svg {
    width: auto;
    /* [Backlog #295] 5.25rem = 84px, 与 AI 卡的 .ai-work-cover-svg 同尺寸(兄弟卡等重) */
    height: 5.25rem;
    max-width: 100%;
    max-height: 100%;
    display: block;
    color: #6a7378;
}

.notes-module-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 5px;
    overflow: hidden;
    position: relative;
    flex: 1 1 0;
    min-height: 0;
    max-height: 180px;
    z-index: 2;
    font-size: var(--icon-logo-placeholder);   /* 2.8rem, 同空 logo 占位符 */
    line-height: 1;
}
/* meta 区: 对应 .project-meta —— flex-shrink: 0 是关键, 卡片高度不够时
   底下三行**永远不收缩**, 日期不会被裁掉。 */
.notes-module-meta {
    text-align: left;
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    position: relative;
    z-index: 5;                 /* 高于水印 z=1 */
    min-height: 60px;           /* tag(12) + title(16) + date(12) + margin 兜底 */
    flex-shrink: 0;
    overflow: visible;
}
.notes-module-tag {
    font-size: var(--type-micro-sm);   /* 0.5625rem = 9px */
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    color: #6a7378;                   /* 灰, 与中性米白卡同族 (tag-other 同值) */
    position: relative;
    z-index: 3;
}
.notes-module-title {
    font-size: var(--type-body-sm);    /* 0.8125rem = 13px */
    color: #333333;                    /* 浅色背景配深灰, 同作品卡 */
    margin: 3px 0 0 0;
    font-weight: 600;
    letter-spacing: 0.03em;
    font-family: var(--font-display);
    position: relative;
    z-index: 3;
    overflow-wrap: anywhere;
    word-break: normal;
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;            /* 最多 2 行 */
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
/* [Backlog #296 · 2026-10-26] ⚠ 这条规则**现在没有消费者** ——
   卡上的统计行(40 Courses · 8 Categories · 1933 Pages)已按用户要求整行删除。
   按「功能移除选「只清数据、机制留着」」: 规则**保留** —— 将来想恢复统计行,
   只要把 <span class="notes-module-date"> 加回 index.html, 样式与布局都还在。
   ⚠ 代价: 这条路径现在**零测试覆盖**(DOM 里没有这个 class)。 */
/* [Backlog #296 · 2026-10-26] ⚠ 这条规则**现在没有消费者** ——
   卡上的统计行(40 Courses · 8 Categories · 1933 Pages)已按用户要求整行删除。
   按「功能移除选「只清数据、机制留着」」: 规则**保留** —— 将来想恢复统计行,
   只要把 <span class="notes-module-date"> 加回 index.html, 样式与布局都还在。
   ⚠ 代价: 这条路径现在**零测试覆盖**(DOM 里没有这个 class)。 */
.notes-module-date {
    display: block;
    font-size: var(--type-micro-sm);   /* 9px */
    color: #6a7378;                    /* 同作品卡日期灰 */
    letter-spacing: 0.5px;
    margin-top: 3px;
    font-family: 'Cinzel', serif;
    white-space: nowrap;               /* 永不换行, 永远单行完整 */
    overflow: visible;
}

/* [Backlog #204 续] 补 `.notes-module-tray` 的 ≤1279 / ≤767 档声明。
   专项回归第一次跑就报了 16 条: ≤1279 档建筑簇降到
     padding `var(--space-8) 14px var(--space-9)` (= 20 14 24) / min-height 400
   而托盘还停在基础档的 22 14 26 / 420 —— 与 §223.10 修 `.ai-work-module` 时是**同一个坑**
   (只对齐了盒子层的宽度, 忘了托盘自己的降档声明)。

   抄 portfolio-grid-responsive.css 的两处, 逐条记出处:
     :88-91   (@media ≤1279) min-height 0 + padding var(--space-8) 14px var(--space-9)
     :115-117 (@media ≤1279, 更靠后) min-height 400  ← 后者赢, 故实际是 400
     :145-147 (@media ≤767)  min-height 0
   实测 600/390 档 cluster 的 min-height 确实是 0, 与 :145-147 吻合。 */
@media (max-width: 1279px) {
    .notes-module-tray {
        min-height: 400px;                              /* portfolio-grid-responsive.css:115-117 */
        padding: var(--space-8) 14px var(--space-9);    /* :90 */
    }
}
@media (max-width: 767px) {
    .notes-module-tray {
        min-height: 0;                                  /* :146 */
    }
}
