/* ============================================================================
 * v4 微拟物控件语言（skeuomorphic controls）—— 设计系统的灵魂
 *
 *   物理模型：光从正上方来。每个可交互控件都是一枚「真实的键」——
 *     ① 凸面     竖向微渐变（顶亮→底沉），面是鼓起来的
 *     ② 顶部反光 inset 高光线（键面上缘接住光）
 *     ③ 贴地投影 两层落影（近影锐、远影柔），键浮在纸面上
 *     ④ 反光光晕 外圈 0 0 0 Npx 高光环（键周围一圈反光），hover 时变亮变宽
 *     ⑤ 按压内陷 :active 渐变翻转 + inset 阴影——按下去真的「凹」
 *
 *   铁律：
 *     · 按钮一律【圆角矩形】（sm/md=8px · lg=12px），禁胶囊(999)——胶囊只留给非交互徽章
 *     · 光影只从本文件的质感类取（zzm-btn / zzm-card / zzm-input），禁止散写 boxShadow——
 *       微拟物的一体感来自全站共用同一套光照模型，各写各的光源方向必然穿帮
 *     · backdrop-filter 仍然全域禁用（性能）；渐变/阴影仅经本文件的类生效
 *
 *   变体：默认纸键 / --primary 墨键 / --accent 朱键 / --ghost 幽灵(hover 才成键) / --ondark 暗面键
 *   尺寸：--sm h28 / 默认 h36 / --lg h44；--icon 方形；Shadcn/Radix 确认窗亦在此复用纸面/朱砂/键感
 * [PROTOCOL]: 变更时更新此头部，然后检查 CLAUDE.md
 * ========================================================================== */

/* ── 基键（纸面键）── */
.zzm-v4 .zzm-btn {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 36px;
  padding: 0 16px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .2px;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  border-radius: 8px;                                   /* 圆角矩形——按钮禁胶囊 */
  border: 1px solid rgba(0, 0, 0, .14);
  color: #3F3F3B;
  background: linear-gradient(180deg, #FFFFFF 0%, #F2F2EF 100%);
  box-shadow:
    0 0 0 3px rgba(255, 255, 255, .55),                 /* ④ 反光光晕环 */
    0 1px 2px rgba(0, 0, 0, .09),                       /* ③ 近影 */
    0 2px 6px rgba(0, 0, 0, .06),                       /* ③ 远影 */
    inset 0 1px 0 rgba(255, 255, 255, .92),             /* ② 顶部反光 */
    inset 0 -1px 0 rgba(0, 0, 0, .05);                  /* ① 底缘收沉 */
  transition: box-shadow .16s ease, transform .16s ease, background .16s ease,
    border-color .16s ease, filter .16s ease, opacity .16s ease;
}
.zzm-v4 .zzm-btn:hover {
  transform: translateY(-1px);
  border-color: rgba(0, 0, 0, .18);
  box-shadow:
    0 0 0 4px rgba(255, 255, 255, .8),
    0 2px 4px rgba(0, 0, 0, .10),
    0 4px 12px rgba(0, 0, 0, .09),
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 -1px 0 rgba(0, 0, 0, .05);
}
.zzm-v4 .zzm-btn:active {
  transform: translateY(0);
  background: linear-gradient(180deg, #ECECE9 0%, #F4F4F1 100%);   /* ⑤ 凹面翻转 */
  box-shadow:
    0 0 0 3px rgba(255, 255, 255, .45),
    0 1px 0 rgba(255, 255, 255, .65),
    inset 0 2px 4px rgba(0, 0, 0, .13),
    inset 0 1px 2px rgba(0, 0, 0, .09);
}
.zzm-v4 .zzm-btn:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 3px rgba(166, 64, 47, .20),                   /* 键盘焦点＝朱色光晕 */
    0 1px 2px rgba(0, 0, 0, .09),
    0 2px 6px rgba(0, 0, 0, .06),
    inset 0 1px 0 rgba(255, 255, 255, .92);
}
/* ── 禁用（非等待）：灰面配灰字——任何变体禁用后都读得清。
      不再用 opacity 淡化整键：变体白字 × 半透明 × 灰面 ＝ 白字隐形事故（后台登录「验证中」曾不可读） ── */
.zzm-v4 .zzm-btn:disabled {
  cursor: not-allowed;
  transform: none;
}
.zzm-v4 .zzm-btn:disabled:not(.zzm-btn--busy) {
  color: #A2A29C;
  background: #F2F2EF;
  border-color: rgba(0, 0, 0, .08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7), 0 1px 2px rgba(0, 0, 0, .04);
}
.zzm-v4 .zzm-btn--ondark:disabled:not(.zzm-btn--busy) {
  color: rgba(255, 255, 255, .45);
  background: rgba(255, 255, 255, .08);
  border-color: rgba(255, 255, 255, .16);
  box-shadow: none;
}

/* ── Saving / 等待键（--busy）＝设计系统原始按钮本体，只叠加三样，不改基座（v21.2.0 老大定版）：
      ① 一道反光扫过——与档位胶囊同一条 zzmPillShine 关键帧（::after 覆盖整键面、快扫一次后长歇＝
         「时不时闪一下」，非呼吸光晕）；② 不可点击——pointer-events:none（Btn 组件 disabled 亦已禁）；
      ③ 饱和度略低——filter:saturate(.72)（比普通键偏低，朱键最明显、墨键近灰变化细微）。
      变体色相/渐变/边框/五层光影一概不动（墨键仍墨、朱键仍朱）；::before 旋转环保持不变。
      overflow:hidden 只裁剪反光覆盖层，不裁外圈光影（box-shadow/focus 环不受 overflow 裁剪）。 ── */
.zzm-v4 .zzm-btn--busy {
  position: relative;
  overflow: hidden;
  pointer-events: none;
  opacity: .92;
  filter: saturate(.72);
  transform: none;
}
.zzm-v4 .zzm-btn--busy::before {
  content: "";
  position: relative;
  z-index: 1;                                            /* 旋转环压在反光层之上 */
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: .7;
  animation: zzmBtnSpin .7s linear infinite;
}
/* 反光层：斜向半透明白，从 -180% 扫到 180%（zzmPillShine），一道光从键面掠过 */
.zzm-v4 .zzm-btn--busy::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  transform: translateX(-180%);
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, .45) 50%, transparent 60%);
  animation: zzmPillShine 4.4s ease-in-out infinite;
}

/* ── 墨键（主操作·深墨）── */
.zzm-v4 .zzm-btn--primary {
  color: #FFFFFF;
  border-color: rgba(0, 0, 0, .85);
  background: linear-gradient(180deg, #3A3A36 0%, #1D1D1B 58%, #141412 100%);
  box-shadow:
    0 0 0 3px rgba(22, 22, 22, .06),
    0 1px 2px rgba(0, 0, 0, .18),
    0 3px 10px rgba(22, 22, 22, .24),
    inset 0 1px 0 rgba(255, 255, 255, .20),
    inset 0 -1px 0 rgba(0, 0, 0, .38);
}
.zzm-v4 .zzm-btn--primary:hover {
  filter: brightness(1.12);
  border-color: rgba(0, 0, 0, .85);
  box-shadow:
    0 0 0 4px rgba(22, 22, 22, .09),
    0 2px 4px rgba(0, 0, 0, .20),
    0 5px 14px rgba(22, 22, 22, .28),
    inset 0 1px 0 rgba(255, 255, 255, .24),
    inset 0 -1px 0 rgba(0, 0, 0, .38);
}
.zzm-v4 .zzm-btn--primary:active {
  filter: none;
  background: linear-gradient(180deg, #101010 0%, #22221F 100%);
  box-shadow:
    0 0 0 3px rgba(22, 22, 22, .06),
    inset 0 2px 5px rgba(0, 0, 0, .55),
    inset 0 1px 2px rgba(0, 0, 0, .4);
}

/* ── 朱键（品牌强调·会员/播放/危险动作）── */
.zzm-v4 .zzm-btn--accent {
  color: #FFFFFF;
  border-color: rgba(122, 42, 29, .9);
  background: linear-gradient(180deg, #C25743 0%, #A6402F 56%, #99392A 100%);
  box-shadow:
    0 0 0 3px rgba(166, 64, 47, .10),                   /* 朱色反光光晕 */
    0 1px 2px rgba(0, 0, 0, .14),
    0 3px 10px rgba(166, 64, 47, .28),
    inset 0 1px 0 rgba(255, 255, 255, .32),
    inset 0 -1px 0 rgba(0, 0, 0, .20);
}
.zzm-v4 .zzm-btn--accent:hover {
  filter: brightness(1.06);
  border-color: rgba(122, 42, 29, .9);
  box-shadow:
    0 0 0 4px rgba(166, 64, 47, .16),
    0 2px 4px rgba(0, 0, 0, .16),
    0 5px 14px rgba(166, 64, 47, .34),
    inset 0 1px 0 rgba(255, 255, 255, .36),
    inset 0 -1px 0 rgba(0, 0, 0, .20);
}
.zzm-v4 .zzm-btn--accent:active {
  filter: none;
  background: linear-gradient(180deg, #8E3425 0%, #A03D2C 100%);
  box-shadow:
    0 0 0 3px rgba(166, 64, 47, .10),
    inset 0 2px 5px rgba(0, 0, 0, .34),
    inset 0 1px 2px rgba(0, 0, 0, .24);
}

/* ── 幽灵键（工具条/次级导航）：静默是文字，hover 才「长成键」── */
.zzm-v4 .zzm-btn--ghost {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
  color: #4A4A46;
}
.zzm-v4 .zzm-btn--ghost:hover {
  transform: translateY(-1px);
  border-color: rgba(0, 0, 0, .14);
  background: linear-gradient(180deg, #FFFFFF 0%, #F2F2EF 100%);
  box-shadow:
    0 0 0 3px rgba(255, 255, 255, .55),
    0 1px 2px rgba(0, 0, 0, .09),
    0 2px 6px rgba(0, 0, 0, .06),
    inset 0 1px 0 rgba(255, 255, 255, .92);
}
.zzm-v4 .zzm-btn--ghost:active {
  transform: translateY(0);
  border-color: rgba(0, 0, 0, .14);
  background: linear-gradient(180deg, #ECECE9 0%, #F4F4F1 100%);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .12);
}

/* ── 暗面键（深色面上的键：付款页/播放器锁罩/海报态）── */
.zzm-v4 .zzm-btn--ondark {
  color: #FFFFFF;
  border-color: rgba(255, 255, 255, .28);
  background: linear-gradient(180deg, rgba(255, 255, 255, .16) 0%, rgba(255, 255, 255, .06) 100%);
  box-shadow:
    0 0 0 3px rgba(255, 255, 255, .05),
    0 2px 8px rgba(0, 0, 0, .4),
    inset 0 1px 0 rgba(255, 255, 255, .28),
    inset 0 -1px 0 rgba(0, 0, 0, .3);
}
.zzm-v4 .zzm-btn--ondark:hover {
  border-color: rgba(255, 255, 255, .4);
  background: linear-gradient(180deg, rgba(255, 255, 255, .22) 0%, rgba(255, 255, 255, .10) 100%);
  box-shadow:
    0 0 0 4px rgba(255, 255, 255, .08),
    0 3px 10px rgba(0, 0, 0, .45),
    inset 0 1px 0 rgba(255, 255, 255, .34),
    inset 0 -1px 0 rgba(0, 0, 0, .3);
}
.zzm-v4 .zzm-btn--ondark:active {
  background: linear-gradient(180deg, rgba(0, 0, 0, .28) 0%, rgba(255, 255, 255, .04) 100%);
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, .5);
}

/* ── 视频启动键：唯一允许为圆形的交互键 ───────────────────────────────
   圆形不是装饰例外，而是「点按即开始播放」这个媒体语义的通用符号；导学封面与
   所有课时海报必须共用这一原件，避免同一动作在不同页面长成不同按钮。
   其余文字按钮仍遵循 8/12 圆角矩形，禁止借此扩散成胶囊。 ── */
.zzm-v4 .zzm-video-play {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  padding: 0;
  border: 1px solid rgba(0, 0, 0, .16);
  border-radius: 50%;
  cursor: pointer;
  color: #1D1D1B;
  background: linear-gradient(180deg, #FFFFFF 0%, #F2F2EF 100%);
  box-shadow:
    0 0 0 4px rgba(255, 255, 255, .24),
    0 2px 4px rgba(0, 0, 0, .16),
    0 6px 16px rgba(0, 0, 0, .22),
    inset 0 1px 0 rgba(255, 255, 255, .96),
    inset 0 -1px 0 rgba(0, 0, 0, .08);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.zzm-v4 .zzm-video-play--center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.zzm-v4 .zzm-video-play:hover {
  border-color: rgba(0, 0, 0, .3);
  box-shadow:
    0 0 0 5px rgba(255, 255, 255, .3),
    0 3px 6px rgba(0, 0, 0, .18),
    0 9px 22px rgba(0, 0, 0, .28),
    inset 0 1px 0 rgba(255, 255, 255, .98),
    inset 0 -1px 0 rgba(0, 0, 0, .08);
}
.zzm-v4 .zzm-video-play--center:hover { transform: translate(-50%, -50%) scale(1.06); }
.zzm-v4 .zzm-video-play:active {
  transform: scale(.98);
  background: linear-gradient(180deg, #E9E9E6 0%, #F4F4F1 100%);
  box-shadow:
    0 0 0 4px rgba(255, 255, 255, .24),
    inset 0 2px 5px rgba(0, 0, 0, .16),
    inset 0 1px 2px rgba(0, 0, 0, .10);
}
.zzm-v4 .zzm-video-play--center:active { transform: translate(-50%, -50%) scale(.98); }
.zzm-v4 .zzm-video-play:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 4px rgba(166, 64, 47, .28),
    0 2px 4px rgba(0, 0, 0, .16),
    0 6px 16px rgba(0, 0, 0, .22),
    inset 0 1px 0 rgba(255, 255, 255, .96);
}
.zzm-v4 .zzm-video-play__icon {
  width: 24px;
  height: 24px;
  margin-left: 4px;
  fill: currentColor;
}

/* ── 尺寸（高度落 4pt 网格：28/36/44）── */
.zzm-v4 .zzm-btn--sm { height: 28px; padding: 0 12px; font-size: 12px; gap: 4px; }
.zzm-v4 .zzm-btn--lg { height: 44px; padding: 0 24px; font-size: 14px; border-radius: 12px; gap: 8px; }
.zzm-v4 .zzm-btn--icon { width: 36px; padding: 0; }
.zzm-v4 .zzm-btn--icon.zzm-btn--sm { width: 28px; }
.zzm-v4 .zzm-btn--icon.zzm-btn--lg { width: 44px; }
.zzm-v4 .zzm-btn--block { width: 100%; }

/* ── 主题化确认窗（Shadcn/Radix Dialog）──────────────────────────────────
   浏览器原生 confirm 没有产品的层级、语言和键感；所有后台确认统一经过
   DialogProvider(appearance="v4")。Portal 仍挂在 .zzm-v4 内，故此处可复用
   同一纸面、朱砂、凸键和内凹输入槽，而不是另造一套浮窗皮肤。
   遮罩只降亮度，不模糊：背景仍可辨认当前操作上下文。 ── */
.zzm-v4 .zzm-dialog-overlay {
  background: rgba(22, 22, 22, .46);
}
.zzm-v4 .zzm-dialog-panel {
  width: min(calc(100% - 32px), 440px);
  max-width: 440px;
  gap: 16px;
  padding: 24px;
  border: 1px solid rgba(0, 0, 0, .14);
  border-radius: 16px;
  background: #FFFFFF;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .10),
    0 18px 48px rgba(0, 0, 0, .22),
    inset 0 1px 0 rgba(255, 255, 255, .92);
}
.zzm-v4 .zzm-dialog-title {
  color: #1D1D1B;
  font-size: 17px;
  font-weight: 700;
  line-height: 24px;
}
.zzm-v4 .zzm-dialog-description {
  color: #6E6E68;
  font-size: 13px;
  line-height: 20px;
}
.zzm-v4 input.zzm-dialog-input {
  width: 100%;
}
.zzm-v4 .zzm-dialog-actions {
  margin-top: 4px;
  gap: 8px;
}

/* ── 可点卡链（zzm-cardlink）：给「裸缩略图+文字」的课节/历史/收藏卡穿上白卡承托，
      悬停＝高亮描边 + 上浮 + 柔影——与综合首页课程卡(zzm-hovercard)同一手感,全站卡片一个词汇。
      内容内嵌圆角取 12(卡 16 内嵌 12,圆角梯嵌套律) ── */
.zzm-v4 .zzm-cardlink {
  background: #FFFFFF;
  border: 1px solid rgba(0, 0, 0, .09);
  border-radius: 16px;
  padding: 12px;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.zzm-v4 .zzm-cardlink:hover {
  transform: translateY(-3px);
  border-color: rgba(0, 0, 0, .3);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .09), 0 1px 2px rgba(0, 0, 0, .04);
}

/* ── 已完成课节卡（--done）：容器级完成态——整卡纸面朱染 + 朱描边，一眼可辨，
      取代右上角 18px ✓ 小圆徽（用户不必费力找小标识）。色值＝朱色低透明派生：
      底 .04（比目录当前行 .06 低一档，大面积 tint 更淡）/ 边 .35（zzm-vdrag hover 同系数）。
      必须走类而非 inline borderColor——inline 会永久压过 :hover 的描边高亮（specificity） ── */
.zzm-v4 .zzm-cardlink--done {
  background: rgba(166, 64, 47, .04);
  border-color: rgba(166, 64, 47, .35);
}
.zzm-v4 .zzm-cardlink--done:hover {
  border-color: rgba(166, 64, 47, .55);
}

/* ── 微拟物卡片：白面浮在纸上（1px 细线仍在，光影让层级立起来）── */
.zzm-v4 .zzm-card {
  background: #FFFFFF;
  border: 1px solid rgba(0, 0, 0, .09);
  border-radius: 16px;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .04),
    0 6px 18px rgba(0, 0, 0, .05),
    inset 0 1px 0 rgba(255, 255, 255, .85);
}

/* ── 输入内凹（既有 .zzm-input 全站自动升级：键是凸的，输入槽是凹的）── */
.zzm-v4 input.zzm-input,
.zzm-v4 textarea.zzm-input {
  background: #FDFDFC;
  box-shadow:
    inset 0 1.5px 3px rgba(0, 0, 0, .06),
    inset 0 1px 1px rgba(0, 0, 0, .04);
}
.zzm-v4 input.zzm-input:focus,
.zzm-v4 textarea.zzm-input:focus {
  box-shadow:
    inset 0 1.5px 3px rgba(0, 0, 0, .06),
    0 0 0 3px rgba(22, 22, 22, .07);                    /* 聚焦光晕 */
}
.zzm-v4 input.zzm-input-accent:focus {
  box-shadow:
    inset 0 1.5px 3px rgba(0, 0, 0, .06),
    0 0 0 3px rgba(166, 64, 47, .14);
}

/* ── 档位胶囊闪光（.zzm-pill-shine）：一道反光时不时从名牌上扫过（与 saving 键 --busy 同一条
      zzmPillShine 关键帧）。胶囊几何/配色由 JSX inline 出（TierPill 读 lib/courseTiers）；本类只负责
      裁剪 + 反光 ::after。错峰靠调用方经 CSS 变量 --zzm-shine-delay 逐卡设不同延时，避免齐刷。 ── */
.zzm-v4 .zzm-pill-shine {
  position: relative;
  overflow: hidden;
}
.zzm-v4 .zzm-pill-shine::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  transform: translateX(-180%);
  background: linear-gradient(105deg, transparent 34%, rgba(255, 255, 255, .85) 50%, transparent 66%);
  animation: zzmPillShine 4.6s ease-in-out infinite;
  animation-delay: var(--zzm-shine-delay, 0s);
}
