/* ==========================================================================
   麻进 / Magic Man — 视觉增强补丁  polish.css
   --------------------------------------------------------------------------
   本文件是「增量补丁」：只做增强，不推翻原有设计语言。
   保持：深底、无圆角、无渐变堆砌、编辑式排版、荧光黄绿单点强调。
   加入：颗粒质感、滚动驱动入场、门类层级、焦点与点击目标修复。

   加载方式（放在 style.css 之后）：
     <link rel="stylesheet" href="css/style.css">
     <link rel="stylesheet" href="css/polish.css">
   ========================================================================== */

/* ==========================================================================
   1. 颗粒质感 —— 把「网页黑」变成「展厅的暗」
   --------------------------------------------------------------------------
   原理：canvas 实时生成一张灰度噪点，以 overlay 混合模式低透明度铺满视口。
   收益：① 消除大块纯色的塑料感 ② 让水墨、纸张、火焰的材质延展到界面
   注意：透明度上限建议 0.10，超过就开始显脏。
   ========================================================================== */
:root {
  --grain-opacity: .075;   /* 全局噪点强度，唯一需要调的旋钮 */
  --ease-out-expo: cubic-bezier(.16, 1, .3, 1);
  --ease-soft: cubic-bezier(.22, .61, .36, 1);
}

.grain {
  position: fixed; inset: 0; z-index: 9999;
  pointer-events: none;
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
  background-repeat: repeat;
  background-size: 180px 180px;
  /* 无 canvas 时的兜底：用 CSS 画细密斜纹，同样能打散纯色 */
  background-image:
    repeating-linear-gradient(0deg, rgba(255,255,255,.5) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.5) 0 1px, transparent 1px 2px);
}

/* 顶栏原本是 92% 不透明 + 模糊。让噪点也覆盖它，避免滚动时出现「干净条」 */
.topbar { background: rgba(11, 11, 11, .86); }

@media (prefers-reduced-motion: reduce) {
  .grain { opacity: calc(var(--grain-opacity) * .7); }
}

/* ==========================================================================
   2. 滚动驱动入场 —— 让滚动参与叙事（原来全站 0 个 keyframes）
   --------------------------------------------------------------------------
   两层实现：
   A. 优先用原生 CSS 滚动驱动动画（Chrome 115+/Safari 26+），零 JS、走合成器
   B. 不支持的浏览器由 polish.js 用 IntersectionObserver 加 .is-in 类兜底
   两者互不冲突：原生生效时 .is-in 只是多余的空类。
   ========================================================================== */
@keyframes riseIn {
  from { opacity: 0; transform: translate3d(0, 26px, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes slideInLeft {
  from { opacity: 0; transform: translate3d(-22px, 0, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes wipeIn {
  /* [WorkBuddy-Intl 2026-10-14 修正] 原版只驱动 clip-path，而 .feature__media
     基础态是 opacity:0 —— 结果动画跑完图仍然不可见（首页百米龙图整张消失）。
     这里把 opacity 一并驱动（0 → 1），与「从左往右展开」的原意一致。
     若要回到交接包原始字节，删掉下面两行里的 opacity 声明即可。 */
  from { opacity: 0; clip-path: inset(0 100% 0 0); }
  to   { opacity: 1; clip-path: inset(0 0 0 0); }
}

/* --- 首屏作品：入场 ---
   关键约束（踩过的坑）：
   1) 每张作品自带 rotate 角度，构成错落的拼贴感 —— 入场动画若写
      transform: none 会把角度全部抹平。
   2) 若用 animation 驱动 transform，其 forwards 填充值的优先级
      高于原站 hover 的 transform: … !important，会把「悬停摆正」
      效果打死。
   因此：动画只驱动 opacity + 独立的 translate 属性，transform 完全
   交还原站 CSS。translate 与 transform 是两个属性，会自然复合。 */
.obj {
  opacity: 0;
  translate: 0 30px;
  animation: objRise .82s var(--ease-out-expo) forwards;
  animation-play-state: paused;
}
@keyframes objRise {
  from { opacity: 0; translate: 0 30px; }
  to   { opacity: 1; translate: 0 0; }
}
.is-hero-ready .obj { animation-play-state: running; }
.obj--a { animation-delay: .04s; }
.obj--b { animation-delay: .12s; }
.obj--c { animation-delay: .16s; }
.obj--d { animation-delay: .22s; }
.obj--e { animation-delay: .28s; }
.obj--f { animation-delay: .34s; }

/* 大标题：从下方压上来，但不要和作品抢戏 */
.hero__name {
  opacity: 0; transform: translate3d(0, 18px, 0);
  animation: riseIn .9s var(--ease-out-expo) .06s forwards;
}

/* --- 门类网格：逐行上浮，制造节奏 ---
   注：入场动画独占 opacity（0→1），因此「降权档」不用 opacity 表达，
   改用字号 + 颜色层级（见下方 .field--minor）。这样两者不打架，
   也避免整体变透明带来的可读性下降。 */
.field {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition:
    opacity .62s var(--ease-out-expo),
    transform .62s var(--ease-out-expo),
    border-color .3s;
}
.field.is-in { opacity: 1; transform: none; }
.field:hover, .field:focus-visible { border-bottom-color: var(--accent); }

/* 同排错开，产生「依次点亮」的感觉（4 列布局下按列错开） */
.field:nth-child(4n+1) { transition-delay: 0ms; }
.field:nth-child(4n+2) { transition-delay: 65ms; }
.field:nth-child(4n+3) { transition-delay: 130ms; }
.field:nth-child(4n+4) { transition-delay: 195ms; }

/* --- 长卷入口 --- */
.feature__label, .feature h2, .feature p, .feature__cta {
  opacity: 0; transform: translate3d(0, 16px, 0);
  transition: opacity .7s var(--ease-out-expo), transform .7s var(--ease-out-expo);
}
.feature.is-in .feature__label { opacity: 1; transform: none; transition-delay: 0ms; }
.feature.is-in h2 { opacity: 1; transform: none; transition-delay: 80ms; }
.feature.is-in p { opacity: 1; transform: none; transition-delay: 150ms; }
.feature.is-in .feature__cta { opacity: 1; transform: none; transition-delay: 220ms; }

/* 长卷配图：从左往右「展开」，呼应「长卷」本身 */
.feature__media {
  opacity: 0;
  animation: wipeIn 1s var(--ease-out-expo) forwards;
  animation-play-state: paused;
}
.feature.is-in .feature__media { animation-play-state: running; }

/* --- 通用工具类：加到任何元素上即可获得入场效果 --- */
.rise { opacity: 0; transform: translate3d(0, 22px, 0); transition: opacity .7s var(--ease-out-expo), transform .7s var(--ease-out-expo); }
.rise.is-in { opacity: 1; transform: none; }
.rise--d1 { transition-delay: 70ms; }
.rise--d2 { transition-delay: 140ms; }
.rise--d3 { transition-delay: 210ms; }

/* --------------------------------------------------------------------------
   原生滚动驱动 —— 支持的浏览器上直接接管，比 JS 更省电
   --------------------------------------------------------------------------
   机制说明（重要）：
   两条路径必须【互斥】，不能叠加，否则同一个元素会被
   transition 和 keyframes 同时控制，出现闪烁或卡在半透明状态。

   做法：在 @supports 块内把 transition 版的状态彻底复位
   （opacity:1 / transform:none / transition:none），
   完全交给 animation-timeline 驱动。
   JS 兜底类 .is-in 此时变成无害的多余类。
   -------------------------------------------------------------------------- */
@supports (animation-timeline: view()) {
  .field, .rise {
    opacity: 1;
    transform: none;
    transition: border-color .3s;
    animation: riseIn both linear;
    animation-timeline: view();
    animation-range: entry 6% cover 32%;
  }
  /* 首屏作品与标题不用滚动时间轴（它们本来就在视口内），
     继续走 JS 的入场时序，避免「一进页面就已经播完」的空洞感 */
}

@media (prefers-reduced-motion: reduce) {
  .obj, .hero__name, .feature__media { animation: none !important; opacity: 1 !important; transform: none !important; }
  .field, .rise, .feature__label, .feature h2, .feature p, .feature__cta {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
}

/* ==========================================================================
   3. 十二门类的层级 —— 最重要的一处结构改进
   --------------------------------------------------------------------------
   问题：70 件的「多元立体书法」和 1 件的「抽象水墨」原来视觉权重完全相同。
   做法：按作品数分三档，让「主业」和「补充」一眼可辨。
         信息层级 = 身份叙事：观众要能立刻读出「他主要做什么」。
   ========================================================================== */

/* 第一档：主业，占满整行，数字放大 */
.field--lead {
  grid-column: 1 / -1;
  grid-template-columns: 40px 1fr auto;
  min-height: auto;
  padding: clamp(18px, 2.4vw, 28px) 0 clamp(20px, 2.6vw, 30px);
  border-bottom: 1px solid var(--line-strong);
  align-items: center;
}
.field--lead b {
  font-family: var(--display-cn);
  font-weight: 900;
  font-size: clamp(26px, 3.4vw, 46px);
  letter-spacing: -.03em;
  line-height: 1.05;
}
.field--lead i { font-size: 12px; align-self: flex-start; padding-top: 8px; }
.field--lead em {
  grid-column: 2 / -1;
  font-size: 11.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  margin-top: 6px;
}
.field--lead .field__n {
  font-family: var(--display);
  font-size: clamp(30px, 4vw, 54px);
  line-height: 1;
  color: var(--fg);
  letter-spacing: -.03em;
  align-self: flex-start;
}
.field--lead:hover .field__n,
.field--lead:focus-visible .field__n { color: var(--accent); }

/* 第二档：主力门类，数字提亮到正文色 */
.field--major .field__n { color: var(--fg-dim); font-size: 13px; }
.field--major b { font-size: clamp(15px, 1.35vw, 17px); }

/* 第三档：边缘门类
   降权不使用 opacity（会与入场动画争抢同一属性、也会降低可读性），
   改用「字号更小 + 颜色退到背景层」来表达层级。 */
.field--minor b { font-size: clamp(13px, 1.15vw, 14.5px); color: var(--fg-faint); font-weight: 400; transition: color .28s; }
.field--minor .field__n { color: var(--fg-faint); font-size: 10.5px; }
.field--minor i { color: var(--fg-faint); }
.field--minor:hover b, .field--minor:focus-visible b { color: var(--fg); }

/* 分档小标题：给三档之间加一道无声的分隔 */
.fields__tier {
  grid-column: 1 / -1;
  font-size: 10px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: clamp(16px, 2.4vw, 26px) 0 clamp(2px, .8vw, 8px);
  display: flex; align-items: center; gap: 12px;
}
.fields__tier::after {
  content: ''; flex: 1; height: 1px; background: var(--line);
}
.fields__tier:first-child { margin-top: 0; }

/* 小屏兜底：
   原站在 ≤620px 用两列，但每格宽度不足以容纳「序号 + 名称 + 数字」三段，
   右侧的数字会被挤出可视区。
   这里改为单列，让每一档在手机上都能完整读出序号、名称与作品数。

   另一个关键点：grid 的 1fr 列默认 min-width:auto，中文长名
   （如「艺术教育与共创」）会把网格撑破，导致右侧数字列被推出容器。
   必须显式允许收缩（min-width:0）+ 允许换行，数字才留得住。 */
@media (max-width: 620px) {
  .fields__grid { grid-template-columns: 1fr; }
  .field { grid-template-columns: 24px minmax(0, 1fr) auto; column-gap: 8px; }
  .field b { overflow-wrap: anywhere; }
  .field--lead { grid-template-columns: 26px minmax(0, 1fr) auto; }
  .field--lead .field__n { font-size: 34px; }
  .field--lead b { font-size: clamp(22px, 7.5vw, 30px); overflow-wrap: anywhere; }
  .fields__tier { margin-top: 14px; }
}

/* 更窄的机型（≤380px）：进一步收紧横向空间 */
@media (max-width: 380px) {
  .field--lead b { font-size: 21px; }
  .field--lead .field__n { font-size: 26px; }
  .field--major b, .field--minor b { font-size: 13px; }
}

/* --------------------------------------------------------------------------
   修复：.fields 的纵向 padding 简写吃掉了 .wrap 的左右留白
   --------------------------------------------------------------------------
   .fields { padding: clamp(...) 0 clamp(...) } 是四值简写，左右被写成 0，
   而它和 .wrap 同时挂在 <section class="fields wrap"> 上，
   谁在样式表里更靠后谁赢 —— 结果是移动端整块门类区贴死屏幕左右边缘，
   数字被顶到最右边，长名称也失去呼吸空间。
   这里把左右留白显式补回来。 */
.fields.wrap { padding-left: var(--pad); padding-right: var(--pad); }

/* ==========================================================================
   4. 焦点可达性 —— 修复键盘不可用
   --------------------------------------------------------------------------
   原站 style.css 已有 :focus-visible，但只在部分元素上有效。
   这里做三件事：① 确保所有交互元素都有可见焦点环 ② 补 --accent 的对比度
                ③ 消除 :focus 与 :focus-visible 的差异，避免鼠标点击后残留焦点环
   ========================================================================== */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

/* 深色图片上的焦点环对比度不足：加一圈暗色底衬 */
.obj:focus-visible,
.tile:focus-visible,
.feature__media:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(11, 11, 11, .85), 0 0 0 8px var(--accent);
}

/* 顶栏导航项：底线本身要变成焦点指示 */
.nav a:focus-visible {
  outline: none;
  border-bottom-color: var(--accent);
  color: var(--fg);
}

/* 鼠标点击不留焦点环，键盘操作必须留 */
:focus:not(:focus-visible) { outline: none; }

/* ==========================================================================
   5. 触摸点击目标 —— 修复移动端过小的可点区域
   --------------------------------------------------------------------------
   实测：底部链接高 14px、「进入长卷」高 18px。触屏及格线是 44×44。
   做法：用伪元素扩展热区，不改变视觉排版（视觉高度不变，可点范围变大）。
   ========================================================================== */
@media (hover: none) and (pointer: coarse) {
  a, button { position: relative; }

  /* 正文内的小链接、页脚链接、返回链接 */
  .footer a, .back, .tile__more, .feature__cta, .detail__cta {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* 门类条目整行可点，高度已足够，但把上下内边距补到 44px */
  .field { min-height: 52px; padding-top: 8px; padding-bottom: 8px; }

  /* 顶栏导航：竖排中文字符宽度天然不足 44px，
     用左右负 margin + padding 撑开热区，视觉位置不变。 */
  .nav a {
    min-height: 44px;
    display: inline-flex; align-items: center;
    padding: 12px 10px;
    margin: 0 -10px;
  }
  .lang { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; }

  /* 品牌标识同样是可点链接，撑到 44px 高 */
  .brand, .topbar__brand { min-height: 44px; display: inline-flex; align-items: center; padding: 12px 8px; margin: 0 -8px; }

  /* 页脚链接：短词条（如「艺术家」）宽度不足 44px，
     用左右内边距撑开热区，负 margin 抵消以保持排版不动。 */
  .footer__in a {
    display: inline-flex; align-items: center;
    min-height: 44px;
    padding: 3px 10px;
    margin: 0 -10px;
  }

  /* 回到顶部 */
  .totop { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; }

  /* 作品索引页：每个门类标题行右侧的「NN 件 →」入口。
     这是作品索引页的主要导航，共 12 个，实测仅 53×20px。
     它带内联 style（color），所以用 padding + 负 margin 撑热区，
     既不吃掉内联样式，也不改变视觉位置。 */
  .fields__head a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    min-width: 44px;
    justify-content: flex-end;
    padding: 12px 10px;
    margin: -12px -10px;
  }

  /* 详情页的分类标签链接（class="tag"，如「多元立体书法」），实测 90×28px。
     同样用 padding + 负 margin 撑开，视觉不变。 */
  .tag, .detail a, .work a, .detail__tags a, .work__tags a, .tags a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 8px 10px;
    margin: -8px -10px;
  }

  /* 品牌标识（Magic Man）：实测 83×19px，class 是 .wordmark。加 padding 撑高，负 margin 抵消 */
  .wordmark,
  .brand,
  .topbar__brand,
  a.brand,
  a[class*="brand"] {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 12px 10px;
    margin: 0 -10px;
  }
}

/* ==========================================================================
   6. 标题层级 —— 补语义 H2（纯视觉辅助，实际标签在 app.js 里改）
   --------------------------------------------------------------------------
   原来首页 H1 之后直接跳到 H3（页脚的「作品」「联络」）。
   为「进入作品世界」和「百米龙图」补上正确的标题级别。
   ========================================================================== */
.fields__head b { font-size: 12px; }          /* 作为 h2 时保持原视觉大小 */
.fields__head h2 { margin: 0; font-weight: 400; font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--accent); }

/* ==========================================================================
   7. 图片自适应 —— 补 srcset 契约
   --------------------------------------------------------------------------
   原站缩略图是 4:3 固定裁切，桌面端放大时会糊。
   这里给所有缩略图容器声明尺寸提示，配合 polish.js 注入的 srcset 生效。
   ========================================================================== */
.tile__media img, .obj img { background: var(--bg-soft); }

/* 高 DPI 屏幕上，缩略图允许轻微锐化以掩盖采样不足 */
@media (min-resolution: 2dppx) {
  .obj img, .tile__media img { image-rendering: -webkit-optimize-contrast; }
}

/* ==========================================================================
   8. 顺带：详情页与分类页的入场（保持全站一致）
   ========================================================================== */
.page__title, .page__sub {
  opacity: 0; transform: translate3d(0, 18px, 0);
  animation: riseIn .8s var(--ease-out-expo) .04s forwards;
}
.page__sub { animation-delay: .12s; }
.page__intro, .page__meta {
  opacity: 0; transform: translate3d(0, 14px, 0);
  animation: riseIn .75s var(--ease-out-expo) .2s forwards;
}
.page__meta { animation-delay: .28s; }

.tile {
  opacity: 0; transform: translate3d(0, 20px, 0);
  transition: opacity .68s var(--ease-out-expo), transform .68s var(--ease-out-expo);
}
.tile.is-in { opacity: 1; transform: none; }
.tile:nth-child(3n+1) { transition-delay: 0ms; }
.tile:nth-child(3n+2) { transition-delay: 80ms; }
.tile:nth-child(3n+3) { transition-delay: 160ms; }

.detail__media, .detail__zh, .detail__en, .detail__text {
  opacity: 0; transform: translate3d(0, 16px, 0);
  animation: riseIn .8s var(--ease-out-expo) forwards;
}
.detail__media { animation-delay: .04s; }
.detail__zh { animation-delay: .14s; }
.detail__en { animation-delay: .2s; }
.detail__text { animation-delay: .26s; }

@media (prefers-reduced-motion: reduce) {
  .page__title, .page__sub, .page__intro, .page__meta,
  .tile, .detail__media, .detail__zh, .detail__en, .detail__text {
    opacity: 1 !important; transform: none !important; animation: none !important; transition: none !important;
  }
}

/* ==========================================================================
   9. 跨页转场 —— 让站内跳转不再硬切
   --------------------------------------------------------------------------
   同源页面之间自动生成过渡，纯 CSS，零 JS。不支持的浏览器静默降级。
   配合 app.js 里给缩略图加 view-transition-name，可实现「缩略图长成大图」。
   ========================================================================== */
@view-transition { navigation: auto; }

/* 转场节奏：出快进慢，符合「离开决断、到达从容」的观感 */
::view-transition-old(root) { animation-duration: .28s; animation-timing-function: ease-in; }
::view-transition-new(root) { animation-duration: .46s; animation-timing-function: var(--ease-out-expo); }

/* 顶栏保持不动，避免整页闪动时的廉价感 */
.topbar { view-transition-name: topbar; }
::view-transition-old(topbar), ::view-transition-new(topbar) { animation: none; }

/* 说明：颗粒层刻意【不】单独命名。
   它是 position:fixed + 固定图案，新旧两页的噪点图案与位置完全一致，
   随 root 一起淡入淡出时反而看不出变化；
   若单独命名成独立快照层，mix-blend-mode 在快照上下文里可能失效，
   反倒会闪一下。这里保持默认行为更稳。 */

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ==========================================================================
   10. 联系页 —— 经纪人微信二维码
   --------------------------------------------------------------------------
   原站联系页留的是「待填入」占位，现由 polish.js 换成真实二维码。
   二维码必须保有浅底（反色就扫不出来），所以这里做成一块白卡：
   在整站深底上，它自然获得「这是一个入口」的视觉重量，不需要额外装饰。
   ========================================================================== */
.qr {
  margin: 2.25rem 0 2.5rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .875rem;
}

.qr img {
  display: block;
  width: 208px;
  height: auto;
  background: #fff;
  /* 深底上压一道极细亮边，避免白卡边缘"糊"进背景 */
  box-shadow: 0 0 0 1px rgba(241, 240, 233, .14);
}

.qr figcaption {
  font-size: .8125rem;
  line-height: 1.5;
  letter-spacing: .02em;
  color: rgba(241, 240, 233, .55);
}

@media (max-width: 620px) {
  .qr { margin: 1.75rem 0 2rem; }
  .qr img { width: 176px; }
}