/* ============================================================
   dh-core.css · 核心样式（手写源，**不需要编译**）
   ------------------------------------------------------------
   ★ 本文件是「手写产物」：直接编辑、直接提交，永不经过 Tailwind 编译。
     它从 src/input.css 拆分而来 —— 原先两者混在一个文件里，导致改任何
     一处前端样式都要重跑整条 Tailwind 构建链（连后台那 60+ KB 原子类
     一起重扫）。拆分后前端加样式零编译。

   ★ 与 assets/app.css 的分工：
       app.css      Tailwind 产物（preflight + 原子类），改后台 UI 时才重建
       dh-core.css  令牌默认值 / .prose-dh / .dh-* 组件 / 关键帧，随时改

   ★ 加载顺序：app.css 在前、本文件在后
     （见 themes/default/layout.php 的两行 <link>）。
     本文件规则位于「无层」，优先级**高于** app.css 里 @layer 内的原子类 ——
     这正是组件样式能盖住原子类的原因，⚠️ 勿把内容包进 @layer。

   ★ 改完只需 clear_cache()（页缓存），**不需要**重建 app.css，也不需要 Node。
     唯一例外：想用产物里尚未生成的新 Tailwind 原子类 —— 那仍要走构建链。
   ============================================================ */


/* ============================================================
   设计令牌（--dh-*）· 默认值
   ------------------------------------------------------------
   ★ 生效层级（后者覆盖前者）：
     ① 本文件 :root 默认值
     ② 主题 theme.json 的 tokens.default（引擎注入 :root{--dh-*}，位置在 </head> 前）
     ③ 站点覆写 settings.site_theme_tokens（同上，优先于 ②）
   ★ 规则：**核心 CSS 与组件一律引用 var(--dh-*)，不写死品牌色** —— 否则换主题
     只换了令牌、样式却没跟着变（这是最难发现的「假换肤」）。
   ========================================================== */
:root {
  --dh-primary:        #2563eb;   /* 主色 */
  --dh-primary-dark:   #1d4ed8;   /* 主色·深（hover） */
  --dh-primary-light:  #60a5fa;   /* 主色·浅（深底上的高亮） */
  --dh-primary-soft:   #eff6ff;   /* 主色·极浅底（角标 / 占位） */
  --dh-accent:         #f97316;   /* 强调色 */
  --dh-surface:        #ffffff;   /* 卡片 / 面板底色 */
  --dh-border:         #e2e8f0;   /* 边框 */
  --dh-text-muted:     #64748b;   /* 次要文字 */
  --dh-radius:         12px;      /* 圆角 */
  --dh-container-max:  1200px;    /* 内容宽度 */
}

/* 站点级字体（下方 body 规则把主题令牌接到实际排版上） */
body {
  font-family: var(--dh-font-sans, var(--font-sans));
}

/* ============================================================
   富文本内容区样式（prose-dh）
   替代 @tailwindcss/typography 插件，避免额外依赖
   ========================================================== */
.prose-dh {
  font-size: 15px;
  line-height: 1.8;
  color: #334155;
}
.prose-dh > *:first-child { margin-top: 0; }
.prose-dh > *:last-child { margin-bottom: 0; }

.prose-dh p { margin: 1em 0; }
.prose-dh h1, .prose-dh h2, .prose-dh h3,
.prose-dh h4, .prose-dh h5, .prose-dh h6 {
  font-weight: 700;
  color: #0f172a;
  line-height: 1.4;
  margin: 1.6em 0 0.7em;
}
.prose-dh h1 { font-size: 1.6em; }
.prose-dh h2 { font-size: 1.35em; padding-bottom: .3em; border-bottom: 1px solid #e2e8f0; }
.prose-dh h3 { font-size: 1.15em; }
.prose-dh h4 { font-size: 1em; }

.prose-dh a { color: var(--dh-primary, #2563eb); text-decoration: underline; text-underline-offset: 2px; }
.prose-dh a:hover { color: var(--dh-primary-dark, #1d4ed8); }

.prose-dh strong { font-weight: 700; color: #0f172a; }

.prose-dh ul, .prose-dh ol { margin: 1em 0; padding-left: 1.6em; }
.prose-dh ul { list-style: disc; }
.prose-dh ol { list-style: decimal; }
.prose-dh li { margin: 0.4em 0; }
.prose-dh li > ul, .prose-dh li > ol { margin: 0.4em 0; }

.prose-dh blockquote {
  margin: 1.4em 0;
  padding: 0.6em 1.2em;
  border-left: 4px solid #93c5fd;
  background: #f8fafc;
  color: #475569;
  border-radius: 0 6px 6px 0;
}

.prose-dh code {
  background: #f1f5f9;
  color: #be123c;
  padding: 0.15em 0.4em;
  border-radius: 4px;
  font-size: 0.88em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.prose-dh pre {
  background: #0f172a;
  color: #e2e8f0;
  padding: 1em 1.2em;
  border-radius: 8px;
  overflow-x: auto;
  margin: 1.4em 0;
  font-size: 0.88em;
  line-height: 1.6;
}
.prose-dh pre code { background: none; color: inherit; padding: 0; }

.prose-dh img {
  max-width: 100%;
  height: auto;
  border-radius: 8px;
  margin: 1.4em auto;
  display: block;
}

/* 富文本视频：本站上传的 mp4（原生 <video>）与第三方平台（白名单 iframe 播放器）
   ⚠️ 编辑器会把 width/height 写成 "auto"（非法值，浏览器按 intrinsic 处理），
      所以必须在这里兜住尺寸，否则 1080p 视频会撑破正文栏。 */
.prose-dh video {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 1.4em auto;
  border-radius: 8px;
  background: #000;
}
.prose-dh iframe {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  margin: 1.4em auto;
  border: 0;
  border-radius: 8px;
  background: #000;
}
/* wangEditor 视频节点的外层 div（序列化后会写进库） */
.prose-dh [data-w-e-type="video"] { margin: 1.4em 0; }
.prose-dh [data-w-e-type="video"] > video,
.prose-dh [data-w-e-type="video"] > iframe { margin: 0 auto; }

.prose-dh hr { margin: 2em 0; border: 0; border-top: 1px solid #e2e8f0; }

.prose-dh table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.4em 0;
  font-size: 0.94em;
}
.prose-dh th, .prose-dh td {
  border: 1px solid #e2e8f0;
  padding: 0.55em 0.8em;
  text-align: left;
}
.prose-dh th { background: #f8fafc; font-weight: 600; color: #0f172a; }
.prose-dh tbody tr:nth-child(even) { background: #fcfdfe; }

/* ------------------------------------------------------------
   .prose-dh-inv — 深色底（栏目 Banner）上的富文本变体
   用途：Banner 副标题下的「简介」（后台栏目 → Banner → 简介，富文本）。
   与 .prose-dh 配合使用；只需覆盖「会变成深字/白底」的那几项。
   ⚠️ 这里显式给 font-size / line-height：.prose-dh 的 15px 是**非分层** CSS，
      优先级高于 Tailwind 工具类，所以尺寸只能在这里定，别在模板上加 text-sm。
   ------------------------------------------------------------ */
.prose-dh-inv {
  font-size: .875rem;                              /* 14px，与副标题一致 */
  line-height: 1.75;
  color: rgb(255 255 255 / .78);
}
.prose-dh-inv h1, .prose-dh-inv h2, .prose-dh-inv h3,
.prose-dh-inv h4, .prose-dh-inv h5, .prose-dh-inv h6 {
  color: #fff;
  margin: 1.1em 0 0.5em;
}
.prose-dh-inv h1 { font-size: 1.3em; }
.prose-dh-inv h2 { font-size: 1.2em; border-bottom-color: rgb(255 255 255 / .2); }
.prose-dh-inv h3 { font-size: 1.1em; }
.prose-dh-inv h4 { font-size: 1em; }
.prose-dh-inv strong { color: #fff; }
.prose-dh-inv a { color: #93c5fd; }                /* blue-300 */
.prose-dh-inv a:hover { color: #bfdbfe; }
.prose-dh-inv blockquote {
  border-left-color: rgb(255 255 255 / .3);
  background: rgb(255 255 255 / .08);
  color: rgb(255 255 255 / .72);
}
.prose-dh-inv code { background: rgb(255 255 255 / .16); color: #fff; }
.prose-dh-inv pre { background: rgb(0 0 0 / .35); color: #e2e8f0; }
.prose-dh-inv pre code { background: none; }
/* Banner 里列表常出现在居中标题下，inside 让圆点跟着文字走，不会甩到很远的一侧 */
.prose-dh-inv ul, .prose-dh-inv ol { list-style-position: inside; }
.prose-dh-inv hr { border-top-color: rgb(255 255 255 / .2); }
.prose-dh-inv th, .prose-dh-inv td { border-color: rgb(255 255 255 / .2); }
.prose-dh-inv th { background: rgb(255 255 255 / .08); color: #fff; }
.prose-dh-inv tbody tr:nth-child(even) { background: rgb(255 255 255 / .04); }

/* ============================================================
   顶部导航配色（partials/nav.php）
   ★ 文字色只有一套（深色底上的白系），底部背景有两态：
     · .nav-bar            近黑实底 —— 全站默认态（含首页滚动后）
     · header[data-overlay] 透明     —— 仅首页首屏叠在 Banner 上
   改配色只改这里，不要回模板里拼 Tailwind 颜色类。
   ========================================================== */
.nav-bar,
header[data-overlay][data-scrolled] {
  background-color: rgb(15 23 42 / .95);            /* slate-900，接近黑 */
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-color: rgb(255 255 255 / .08);
}

.nav-link {
  color: rgb(255 255 255 / .85);
  transition: color .2s ease;
}
.nav-link:hover,
.nav-link.is-active { color: var(--dh-primary-light, #60a5fa); }   /* blue-400：深底上的品牌蓝 */
.nav-brand { color: #fff; }
.nav-menu-btn { color: rgb(255 255 255 / .9); }
.nav-menu-btn:hover { background-color: rgb(255 255 255 / .12); }

/* 透明叠加态：盖在 Banner 上时去掉底色与毛玻璃，只留一条极淡的细边线 */
header[data-overlay] {
  background-color: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-color: rgb(255 255 255 / .07);
}

/* 顶部压暗渐变（scrim）：透明导航叠在深色横幅上时，
   横幅里的亮图/亮色区域会让白色导航文字糊掉 —— 这层把顶部压暗一档。
   z-index 30 < 导航的 40，所以导航文字仍在最上层；pointer-events:none 不吃点击。
   滚动后导航已转实底，本层淡出（相邻兄弟选择器，scrim 紧跟在 header 之后）。 */
.nav-scrim {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 140px;
  z-index: 30;
  pointer-events: none;
  background-image: linear-gradient(to bottom,
      rgb(2 6 23 / .45),
      rgb(2 6 23 / .20) 45%,
      rgb(2 6 23 / 0));
  transition: opacity .3s ease;
}
header[data-overlay][data-scrolled] + .nav-scrim { opacity: 0; }

/* ============================================================
   行数截断工具类
   ========================================================== */
.line-clamp-1, .line-clamp-2, .line-clamp-3 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.line-clamp-1 { -webkit-line-clamp: 1; }
.line-clamp-2 { -webkit-line-clamp: 2; }
.line-clamp-3 { -webkit-line-clamp: 3; }

/* ============================================================
   导航下拉面板（.nav-panel）
   内容多了（子栏目 + 内容）时：高度封顶 + 内部滚动，滚动条收细不抢眼
   ========================================================== */
.nav-panel {
  scroll-behavior: smooth;
  scrollbar-width: thin;                          /* Firefox：细滚动条 */
  scrollbar-color: #cbd5e1 transparent;
  -webkit-overflow-scrolling: touch;              /* iOS 惯性滚动 */
}
.nav-panel::-webkit-scrollbar { width: 6px; height: 6px; }
.nav-panel::-webkit-scrollbar-track { background: transparent; }
.nav-panel::-webkit-scrollbar-thumb {
  background-color: #cbd5e1;
  border-radius: 9999px;
}
.nav-panel::-webkit-scrollbar-thumb:hover { background-color: #94a3b8; }

/* 用户系统设置「减弱动效」时，平滑滚动一并关掉（展开过渡由 motion-reduce:transition-none 处理） */
@media (prefers-reduced-motion: reduce) {
  .nav-panel { scroll-behavior: auto; }
}

/* ============================================================
   Logo 走马灯（blocks/logo-marquee.php）
   列表复制两份并排，平移 -50% 实现无缝循环；减弱动效时停住
   ========================================================== */.marquee-track {
  animation: marquee linear infinite;
  will-change: transform;
}
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; }
}

/* ============================================================
   轮播兜底背景（categorys/page-home.php · blocks/hero-carousel.php）
   某组轮播没配「背景色」时用它顶住，否则深色导航叠上去会糊成一片。
   ★ 颜色出口在此（模板不再写十六进制）；两个令牌可在主题清单里覆写。
   ========================================================== */
[data-slide] {
  background: linear-gradient(135deg, var(--dh-hero-from, #0f172a), var(--dh-hero-to, #1d4ed8));
}

/* ============================================================
   首页 Banner 右侧产品图 · 柔和悬浮（categorys/page-home.php）
   三个层次（全部 transform/opacity，GPU 合成，不触发重排）：
     ① 容器 .dh-banner-fig     首屏入场：淡入 + 上浮 18px（只跑一次）
     ② 图片   .dh-banner-float 持续：缓慢浮动 + 极轻呼吸缩放（7.5s 循环）
     ③ 影子   ::after          地面投影与浮动反相：图升起→影子收窄变淡
   减弱动效时全部停住（与 marquee-track 同一惯例）。
   ========================================================== */
@keyframes dh-banner-in {
  from { opacity: 0; transform: translate3d(0, 18px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
@keyframes dh-banner-float {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(0, -14px, 0) scale(1.015); }
}
@keyframes dh-banner-shadow {
  0%, 100% { transform: translateX(-50%) scaleX(1);   opacity: .45; }
  50%      { transform: translateX(-50%) scaleX(.78); opacity: .22; }
}

.dh-banner-fig {
  position: relative;
  animation: dh-banner-in .9s cubic-bezier(.22, .61, .36, 1) .15s both;
}
/* 地面投影：椭圆柔光，挂容器伪元素不占布局；
   静态 opacity 与 0% 帧一致，避免动画 delay 期间过浓地闪一下 */
.dh-banner-fig::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -16px;
  width: 62%;
  height: 22px;
  background: radial-gradient(50% 50% at 50% 50%, rgb(15 23 42 / .55), transparent 70%);
  transform: translateX(-50%);
  opacity: .45;
  z-index: -1;                          /* 压到图片后面（容器有入场 transform=stacking context） */
  animation: dh-banner-shadow 7.5s ease-in-out 1.05s infinite;
}
.dh-banner-fig img {
  animation: dh-banner-float 7.5s ease-in-out 1.05s infinite;   /* 等入场结束后再浮 */
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .dh-banner-fig,
  .dh-banner-fig::after,
  .dh-banner-fig img { animation: none; }
}

/* ============================================================
   时间轴区块 · 固定高度框内滚动（templates/blocks/timeline.php）
   节点多时默认只占一屏高、框内滚动，省页面纵向空间。
     .dh-tl-box    定位壳（底部渐隐的参照，不参与滚动）
     .dh-tl-scroll 滚动容器：max-height + overflow-y
     .dh-tl-fade   底部渐隐（白→透明），提示「下面还有内容」
   档位：默认 480px / .dh-tl-h-sm 360 / .dh-tl-h-lg 640
   ★ 容器末尾的 padding-bottom 是给渐隐留的：滚到底时最后一行文字
     正好落在渐隐之上，既不被切到、也仍有「到底了」的柔和过渡。
   ============================================================ */
.dh-tl-box {
  position: relative;
}

.dh-tl-scroll {
  max-height: 480px;
  overflow-y: auto;
  overscroll-behavior: contain;      /* 滚到底不带着整页一起滚（正文仍可正常滚） */
  padding-right: 14px;               /* 与滚动条留出距离 */
  padding-bottom: 40px;              /* 末行留白，配合下方渐隐 */
  scrollbar-width: thin;             /* Firefox */
  scrollbar-color: rgb(203 213 225) transparent;
}
.dh-tl-h-sm { max-height: 360px; }
.dh-tl-h-lg { max-height: 640px; }

.dh-tl-scroll::-webkit-scrollbar { width: 8px; }
.dh-tl-scroll::-webkit-scrollbar-track { background: transparent; }
.dh-tl-scroll::-webkit-scrollbar-thumb {
  background: rgb(203 213 225);
  border-radius: 999px;
}
.dh-tl-scroll:hover::-webkit-scrollbar-thumb { background: rgb(148 163 184); }

/* 键盘聚焦（tabindex=0）时的可见焦点环 */
.dh-tl-scroll:focus-visible {
  outline: 2px solid rgb(147 197 253);
  outline-offset: 6px;
  border-radius: 10px;
}

/* 底部渐隐：right 让开滚动条，避免把滚动条末端一起淡化 */
.dh-tl-fade {
  position: absolute;
  left: 0;
  right: 8px;
  bottom: 0;
  height: 32px;
  background: linear-gradient(to bottom, rgb(255 255 255 / 0), #fff 85%);
  pointer-events: none;
}

/* ============================================================
   图文卡片 · 图标底色（templates/blocks/cards.php 的 `icon_bg`）
   白 / 浅色图标（如联系方式那三枚）放在白卡上会**完全看不见**，
   垫一层色块才显形。
     .dh-card-icon-brand  品牌蓝渐变底（白图标首选）
     .dh-card-icon-soft   浅灰底（给深色图标做统一块面）
   ============================================================ */
.dh-card-icon {
  position: relative;                /* 压在大序号之上（与 .dh-card-icon 同级的 h3 同理） */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 5.25rem;
  height: 5.25rem;
  margin: 0 auto 1.25rem;            /* 替代原 img 的 mb-4，保持卡片纵向节奏 */
  border-radius: 1rem;
}
.dh-card-icon img {
  width: 2.5rem;
  height: 2.5rem;
  object-fit: contain;
  transition: transform .6s ease;
}
.dh-card-icon-brand {
  background-image: linear-gradient(135deg, var(--dh-primary, #2563eb), var(--dh-primary-light, #3b82f6));
  box-shadow: 0 12px 22px -12px rgb(37 99 235 / .75);
}
.dh-card-icon-soft { background: #f1f5f9; }
/* 卡片 hover 时图标轻翻转（与原站联系卡一致的「活」感） */
.group:hover .dh-card-icon img { transform: rotateY(360deg); }

/* ============================================================
   地图 / 联系方式区块（templates/blocks/map.php）
     .dh-map-frame   地图 iframe（tx/embed 直出）：去边框 + 圆角 + 底色
     .dh-map-wrap    GL 模式容器：定位上下文 + 圆角 + 底色（加载中不留白）
     .dh-map-canvas  GL 挂载点（铺满容器）
     .dh-map-fill    兜底 iframe（脚本失败注入 / noscript），铺满容器
     ↑ 具体高度由模板写成 style="height:Npx"（区块字段「地图高度（px）」，默认 480）
     .dh-map-icon    联系方式图标色块 —— 白图标靠底色显形，hover 翻转
   ============================================================ */
.dh-map-frame {
  display: block;
  width: 100%;
  height: 480px;
  border: 0;
  border-radius: 1rem;
  background: #e2e8f0;
}
.dh-map-wrap {
  position: relative;
  height: 480px;
  border-radius: 1rem;
  overflow: hidden;
  border: 1px solid #e2e8f0;
  background: #eef2f7;
}
.dh-map-canvas {
  width: 100%;
  height: 100%;
}
.dh-map-fill {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.dh-map-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: .875rem;
  background-image: linear-gradient(135deg, var(--dh-primary, #2563eb), var(--dh-primary-light, #3b82f6));
  box-shadow: 0 12px 22px -12px rgb(37 99 235 / .75);
}
.dh-map-icon img {
  width: 2rem;
  height: 2rem;
  object-fit: contain;
  transition: transform .6s ease;
}
.dh-map-item:hover .dh-map-icon img { transform: rotateY(360deg); }

@media (prefers-reduced-motion: reduce) {
  .group:hover .dh-card-icon img,
  .dh-map-item:hover .dh-map-icon img { transform: none; }
}

/* ============================================================
   组件库基础样式（app/components.php 的 dh_* 输出）
   ------------------------------------------------------------
   ★ 为什么组件只用「语义类名」而不堆 Tailwind 原子类：
     核心 app.css 是 Tailwind CLI 产物，只有被 @source 扫到的**完整字面量**
     类名才有规则。组件是**运行时拼字符串**，拼出来的类名不会被扫到
     → 样式静默丢失。所以组件把样式集中在这里（编译期就存在），
     主题再用 theme.css 覆盖 —— 这也是「AI 生成主题」可靠的前提。
   ★ 颜色/圆角/字体一律走 var(--dh-*)。
   ★ 未分层的普通 CSS 优先级**高于** Tailwind 的 utilities 层，
     所以组件内部状态用 .is-active 之类的类名表达，不依赖原子类切换。
   ========================================================== */

/* ── 容器与区块 ── */
.dh-wrap {
  max-width: var(--dh-container-max, 1200px);
  margin-inline: auto;
  padding-inline: 1rem;
}
.dh-block { padding-block: 3rem; }
.dh-section-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: #0f172a;
  margin: 0 0 .5rem;
}
.dh-section-note {
  font-size: .875rem;
  color: var(--dh-text-muted, #64748b);
  margin: 0 0 1rem;
}

/* ── 网格（移动端单列 → 中屏 cols_md → 大屏 cols）── */
.dh-grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 768px) {
  .dh-grid-1, .dh-grid-md-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
  .dh-grid-2, .dh-grid-md-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dh-grid-3, .dh-grid-md-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dh-grid-4, .dh-grid-md-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .dh-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dh-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ── 卡片 ── */
.dh-card {
  display: flex;
  flex-direction: column;
  background: var(--dh-surface, #fff);
  border: 1px solid var(--dh-border, #e2e8f0);
  border-radius: var(--dh-radius, 12px);
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  transition: box-shadow .25s ease, transform .25s ease, border-color .25s ease;
}
.dh-card:hover {
  box-shadow: 0 14px 30px -16px rgb(15 23 42 / .3);
  transform: translateY(-2px);
  border-color: var(--dh-primary-light, #60a5fa);
}
.dh-card-media {
  display: block;
  position: relative;
  aspect-ratio: var(--dh-ratio, 16 / 10);
  background: var(--dh-primary-soft, #eff6ff);
  overflow: hidden;
}
.dh-card-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .4s ease;
}
.dh-card:hover .dh-card-media img { transform: scale(1.04); }
.dh-card-media .dh-ph {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 2.5rem;
  height: 2.5rem;
  color: #cbd5e1;
}
.dh-card-body {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  flex: 1;
  min-width: 0;
  padding: 1.25rem;
}
.dh-card-title {
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.45;
  color: #0f172a;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.dh-card:hover .dh-card-title { color: var(--dh-primary, #2563eb); }
.dh-card-text {
  font-size: .875rem;
  line-height: 1.65;
  color: var(--dh-text-muted, #64748b);
  flex: 1;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.dh-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-top: .75rem;
  font-size: .75rem;
  color: var(--dh-text-muted, #64748b);
}
.dh-card-cta {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  color: var(--dh-primary, #2563eb);
  white-space: nowrap;
}
.dh-card-cta::after { content: '→'; transition: transform .2s ease; }
.dh-card:hover .dh-card-cta::after { transform: translateX(3px); }

/* 横向行卡（左图右文）：.dh-cards--list 容器 */
.dh-cards { display: flex; flex-direction: column; gap: 1.25rem; }
.dh-card--row { flex-direction: row; }
.dh-card--row .dh-card-media {
  flex: 0 0 40%;
  max-width: 14rem;
  aspect-ratio: var(--dh-ratio, 16 / 10);
}
@media (min-width: 640px) {
  .dh-card--row .dh-card-media { aspect-ratio: auto; align-self: stretch; }
}
.dh-card--row .dh-card-body { justify-content: center; }

/* ── 角标 ── */
.dh-badge {
  align-self: flex-start;
  font-size: .75rem;
  line-height: 1.6;
  padding: 0 .5rem;
  border-radius: 9999px;
  background: #fef2f2;
  color: #dc2626;
}
.dh-badge--type {
  background: var(--dh-primary-soft, #eff6ff);
  color: var(--dh-primary, #2563eb);
}

/* ── 按钮 ── */
.dh-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .625rem 1.25rem;
  font-size: .875rem;
  font-weight: 500;
  line-height: 1.4;
  border: 1px solid transparent;
  border-radius: calc(var(--dh-radius, 12px) * .66);
  cursor: pointer;
  text-decoration: none;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}
.dh-btn--sm { padding: .375rem .875rem; font-size: .8125rem; }
.dh-btn--lg { padding: .875rem 1.75rem; font-size: 1rem; }
.dh-btn--block { width: 100%; }
.dh-btn--primary { background: var(--dh-primary, #2563eb); color: #fff; }
.dh-btn--primary:hover { background: var(--dh-primary-dark, #1d4ed8); color: #fff; }
.dh-btn--ghost {
  background: transparent;
  color: var(--dh-primary, #2563eb);
  border-color: var(--dh-border, #e2e8f0);
}
.dh-btn--ghost:hover { border-color: var(--dh-primary, #2563eb); }
.dh-btn--light { background: #fff; color: #0f172a; }
.dh-btn--light:hover { background: #f1f5f9; }

/* ── 面包屑 ── */
.dh-crumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .375rem;
  font-size: .875rem;
  color: var(--dh-text-muted, #64748b);
  margin-bottom: 1.5rem;
}
.dh-crumb a { color: inherit; text-decoration: none; }
.dh-crumb a:hover { color: var(--dh-primary, #2563eb); }
.dh-crumb-sep { color: #cbd5e1; }

/* ── 分页 ── */
.dh-pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  margin-top: 2.5rem;
}
.dh-pager-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.25rem;
  padding: .375rem .75rem;
  font-size: .875rem;
  color: var(--dh-text-muted, #64748b);
  background: transparent;
  border: 1px solid var(--dh-border, #e2e8f0);
  border-radius: calc(var(--dh-radius, 12px) * .5);
  text-decoration: none;
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.dh-pager-item:hover { border-color: var(--dh-primary-light, #60a5fa); color: var(--dh-primary, #2563eb); }
.dh-pager-item.is-active {
  background: var(--dh-primary, #2563eb);
  border-color: var(--dh-primary, #2563eb);
  color: #fff;
}
.dh-pager-total { margin-left: .5rem; font-size: .75rem; color: var(--dh-text-muted, #64748b); }

/* ── 空态 ── */
.dh-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding: 5rem 1.5rem;
  background: var(--dh-surface, #fff);
  border: 1px solid var(--dh-border, #e2e8f0);
  border-radius: var(--dh-radius, 12px);
  text-align: center;
}
.dh-empty-tip { margin: 0; color: #94a3b8; font-size: .9375rem; }

/* ── 字段行（规格 / 参数）── */
.dh-field-list { display: flex; flex-wrap: wrap; gap: .5rem; }
.dh-field-rows { display: block; }
.dh-field { font-size: .875rem; }
.dh-field--tag {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .25rem .625rem;
  background: #f8fafc;
  border: 1px solid var(--dh-border, #e2e8f0);
  border-radius: calc(var(--dh-radius, 12px) * .5);
  color: #334155;
}
.dh-field--row {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  padding: .625rem 0;
  border-bottom: 1px solid var(--dh-border, #e2e8f0);
}
.dh-field--row .dh-field-label {
  flex: 0 0 6rem;
  color: var(--dh-text-muted, #64748b);
}
.dh-field--plain { color: inherit; }
.dh-field-label { color: var(--dh-text-muted, #64748b); }
.dh-field-link { color: var(--dh-primary, #2563eb); text-decoration: none; }
.dh-field-link:hover { color: var(--dh-primary-dark, #1d4ed8); text-decoration: underline; }

/* ── 多组字段（repeater）── */
.dh-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--dh-border, #e2e8f0);
  border-radius: var(--dh-radius, 12px);
  background: var(--dh-surface, #fff);
}
.dh-table { width: 100%; border-collapse: collapse; font-size: .875rem; }
.dh-table th, .dh-table td {
  padding: .625rem .875rem;
  text-align: left;
  border-bottom: 1px solid var(--dh-border, #e2e8f0);
}
.dh-table th { background: #f8fafc; font-weight: 600; color: #0f172a; white-space: nowrap; }
.dh-table tr:last-child td { border-bottom: 0; }
.dh-repeater { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .75rem; }
.dh-repeater--cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.dh-repeater-item {
  padding: .875rem 1rem;
  background: var(--dh-surface, #fff);
  border: 1px solid var(--dh-border, #e2e8f0);
  border-radius: calc(var(--dh-radius, 12px) * .75);
}
.dh-repeater-row { display: flex; gap: .5rem; font-size: .875rem; }
.dh-repeater-row .dh-field-label { flex: 0 0 5rem; }

/* ── 表单（dh_form）── */
.dh-form-section { margin-top: 1.5rem; }
.dh-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: 1.5rem;
  background: var(--dh-surface, #fff);
  border: 1px solid var(--dh-border, #e2e8f0);
  border-radius: var(--dh-radius, 12px);
}
.dh-label { display: block; font-size: .875rem; font-weight: 500; color: #334155; margin-bottom: .375rem; }
.dh-input {
  width: 100%;
  padding: .625rem .875rem;
  font-size: .875rem;
  color: inherit;
  background: #fff;
  border: 1px solid #cbd5e1;
  border-radius: calc(var(--dh-radius, 12px) * .5);
  outline: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.dh-input:focus {
  border-color: var(--dh-primary, #2563eb);
  box-shadow: 0 0 0 2px var(--dh-primary-soft, #eff6ff);
}
.dh-flash {
  padding: .75rem 1rem;
  font-size: .875rem;
  border-radius: calc(var(--dh-radius, 12px) * .5);
  margin-bottom: 1rem;
}
.dh-flash.is-ok { background: #f0fdf4; color: #15803d; border: 1px solid #bbf7d0; }
.dh-flash.is-err { background: #fef2f2; color: #b91c1c; border: 1px solid #fecaca; }

/* ── 栏目首屏横幅（dh_hero）──
   ★ 用 .is-active 表达当前帧：未分层的本文件优先级高于 Tailwind utilities，
     所以**不能**依赖 app.js 切换 opacity-100/opacity-0 —— 那些原子类会被
     下面的 opacity:0 压掉。app.js 已同步切换 is-active。
   ★ -4rem 上提 = 滑入导航下方（与 partials/page-header.php 的 -mt-16 一致）；
     因此内边距顶部要补回导航高度。 */
.dh-hero {
  position: relative;
  overflow: hidden;
  margin-top: -4rem;
  background: #0f172a;
  color: #fff;
}
.dh-hero-bg {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .7s ease;
  z-index: 0;
}
.dh-hero-bg.is-active { opacity: 1; }
.dh-hero-bg img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .6;
}
.dh-hero-inner {
  position: relative;
  z-index: 2;
  max-width: var(--dh-container-max, 1200px);
  margin-inline: auto;
  padding-inline: 1rem;
  text-align: center;
}
.dh-hero--sm .dh-hero-inner { padding-block: 7.5rem 3.5rem; }   /* 120 / 56 */
.dh-hero--md .dh-hero-inner { padding-block: 9rem 5rem; }       /* 144 / 80 */
.dh-hero--lg .dh-hero-inner { padding-block: 11rem 7rem; }      /* 176 / 112 */
.dh-hero-caption { display: none; }
.dh-hero-caption.is-active { display: block; }
.dh-hero-title {
  font-size: 1.875rem;
  font-weight: 700;
  line-height: 1.25;
  margin: 0 0 1rem;
  max-width: 56rem;
  margin-inline: auto;
}
@media (min-width: 768px) { .dh-hero-title { font-size: 2.25rem; } }
.dh-hero-sub { color: rgb(255 255 255 / .82); margin: 0; max-width: 56rem; margin-inline: auto; }
.dh-hero-intro { margin-top: 1rem; max-width: 56rem; margin-inline: auto; }
.dh-hero-actions { margin-top: 2rem; }
.dh-hero-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 0;
  border-radius: 9999px;
  background: rgb(0 0 0 / .3);
  color: #fff;
  cursor: pointer;
  transition: background-color .2s ease;
}
.dh-hero-nav:hover { background: rgb(0 0 0 / .5); }
.dh-hero-nav svg { width: 1.25rem; height: 1.25rem; }
.dh-hero-prev { left: .5rem; }
.dh-hero-next { right: .5rem; }
@media (min-width: 768px) {
  .dh-hero-prev { left: 1rem; }
  .dh-hero-next { right: 1rem; }
}
.dh-hero-dots {
  position: absolute;
  bottom: 1rem;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
}
.dh-hero-dot {
  width: .625rem;
  height: .625rem;
  padding: 0;
  border: 0;
  border-radius: 9999px;
  background: rgb(255 255 255 / .4);
  cursor: pointer;
  transition: background-color .2s ease;
}
.dh-hero-dot:hover { background: rgb(255 255 255 / .7); }
.dh-hero-dot.is-active { background: #fff; }

@media (prefers-reduced-motion: reduce) {
  .dh-card, .dh-card-media img, .dh-card-cta::after,
  .dh-hero-bg, .dh-hero-nav, .dh-hero-dot { transition: none; }
  .dh-card:hover { transform: none; }
  .dh-card:hover .dh-card-media img { transform: none; }
}
