@charset "utf-8";
/* ==========================================================================
   立非智码（Lifre SmartCode）官网 · 共享样式
   设计令牌依据：《02-契约规范与合规/设计系统与多端UI规范.md》§3
   --------------------------------------------------------------------------
   配色定档「墨蓝印红」：2026-08-29 李总拍板。
   主色 = 墨蓝 #16324F；官方 logo 红 #d40000 降级为点睛色 --td-accent，
   仅用于主 CTA 按钮、必填校验与关键告警，全站红色面积控制在 5% 以内。
   --------------------------------------------------------------------------
   为什么红色不做主色（2026-08-29 李总提问「大面积红会不会不适」的答复）：
   1) 长波长的红在视觉上会前冲，大面积铺底会挤压内容、造成压迫感与疲劳；
   2) 对比度硬伤：红底 #d40000 配深字仅 3.80:1，未过 WCAG 2.1 AA（4.5:1），
      红底只能配白字（5.53:1 才达标），可用场景被大幅压缩；
   3) 红色在中文语境强绑定「错误/禁用/危险」，与 --td-error #d54941 语义打架；
   4) 墨蓝 #16324F 配白字 13.10:1（AAA），既能承载大面积实底，也让红色
      在按钮上真正跳出来 —— 这才是「画龙点睛」该有的效果。
   变更史：#0052D9（TDesign 占位）→ #d40000（取 logo 红）→ #16324F（墨蓝定稿）
   ========================================================================== */

:root {
  /* 色彩 —— 主色：墨蓝（品牌基调，承载导航/标题/图标/行动区实底） */
  --td-brand-color: #16324F;
  --td-brand-color-hover: #0e2135;
  --td-brand-color-active: #0a1826;
  --td-brand-color-light: #eef2f7;

  /* 色彩 —— 点睛色：官方 logo 红，只给主 CTA 与关键校验，禁止铺底 */
  --td-accent: #d40000;
  --td-accent-hover: #b00000;
  --td-accent-active: #8a0000;
  --td-accent-light: #fdeded;

  --td-success: #00a870;
  --td-warning: #ed7b2f;
  --td-error: #d54941;

  /* 色彩 —— 文字三阶 */
  --td-text-primary: #1d2129;
  --td-text-secondary: #4e5969;
  --td-text-placeholder: #a9aeb8;
  --td-text-anti: #ffffff;

  /* 色彩 —— 背景与描边 */
  --td-bg-page: #ffffff;
  --td-bg-container: #f5f7fa;
  --td-bg-container-hover: #eef0f3;
  --td-component-stroke: #e5e6eb;
  --td-component-border: #dcdcdc;

  /* 字体（规范 §3.2：系统字体栈，中文优先 PingFang / 微软雅黑） */
  --td-font-family: -apple-system, BlinkMacSystemFont, "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial,
    sans-serif;
  --td-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* 字号阶梯（规范 §3.2：12/14/16/20/24/32） */
  --td-font-size-s: 12px;
  --td-font-size-base: 14px;
  --td-font-size-m: 16px;
  --td-font-size-l: 20px;
  --td-font-size-xl: 24px;
  --td-font-size-xxl: 32px;

  /* 间距（规范 §3.3：4 倍数栅格） */
  --td-space-1: 4px;
  --td-space-2: 8px;
  --td-space-3: 12px;
  --td-space-4: 16px;
  --td-space-5: 24px;
  --td-space-6: 32px;
  --td-space-7: 48px;
  --td-space-8: 64px;

  /* 圆角（规范 §3.3：sm 3 / md 6 / lg 9 / round 999） */
  --td-radius-sm: 3px;
  --td-radius-md: 6px;
  --td-radius-lg: 9px;
  --td-radius-round: 999px;

  /* 阴影三档 */
  --td-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.05);
  --td-shadow-2: 0 4px 12px rgba(0, 0, 0, 0.08);
  --td-shadow-3: 0 8px 24px rgba(0, 0, 0, 0.12);

  /* 布局 */
  --td-container-width: 1160px;
  --td-header-height: 60px;
}

/* --------------------------------------------------------------- 基础重置 */
*,
*::before,
*::after {
  box-sizing: border-box;
}

[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--td-font-family);
  font-size: var(--td-font-size-m);
  line-height: 1.7;
  color: var(--td-text-primary);
  background: var(--td-bg-page);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4,
p,
ul,
ol,
figure,
blockquote {
  margin: 0;
}

ul,
ol {
  padding: 0;
  list-style: none;
}

a {
  color: var(--td-brand-color);
  text-decoration: none;
}

a:hover {
  color: var(--td-brand-color-hover);
}

img,
svg {
  max-width: 100%;
  display: block;
}

button,
input,
select,
textarea {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--td-brand-color);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------- 布局容器 */
.container {
  width: 100%;
  max-width: var(--td-container-width);
  margin: 0 auto;
  padding: 0 var(--td-space-5);
}

.section {
  padding: var(--td-space-8) 0;
}

.section--tint {
  background: var(--td-bg-container);
}

.section--border {
  border-top: 1px solid var(--td-component-stroke);
}

.section-head {
  max-width: 720px;
  margin-bottom: var(--td-space-7);
}

.section-head h2 {
  font-size: var(--td-font-size-xl);
  line-height: 1.4;
  margin-bottom: var(--td-space-3);
}

.section-head p {
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-m);
}

.section-eyebrow {
  display: inline-block;
  font-size: var(--td-font-size-s);
  letter-spacing: 0.08em;
  color: var(--td-brand-color);
  margin-bottom: var(--td-space-2);
}

/* ------------------------------------------------------------------ 跳转链 */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--td-brand-color);
  color: var(--td-text-anti);
  padding: var(--td-space-2) var(--td-space-4);
  border-radius: 0 0 var(--td-radius-md) 0;
}

.skip-link:focus {
  left: 0;
}

/* -------------------------------------------------------------------- 头部 */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--td-component-stroke);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: var(--td-space-4);
  min-height: var(--td-header-height);
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: var(--td-space-2);
  color: var(--td-text-primary);
  flex-shrink: 0;
}

.logo:hover {
  color: var(--td-text-primary);
}

.logo-mark {
  /* 官方 logo.svg（240×240 原图，等比缩放到 28×28）。
     两条硬约束，改动前请务必理解：
     1) 中间图案是「真镂空」——SVG 内的反向子路径在 nonzero 填充规则下形成孔洞，
        并不存在白色图形，透出的是下层背景色。因此这里绝不能垫 background-color，
        否则镂空被填成红色，图案直接消失。
     2) 不加 border-radius、不做任何形变：logo 为标准方形构图，
        圆角会裁掉红色底的四角，属于对品牌素材的擅自修改。
     允许的操作仅有一项：等比改尺寸（同时调 width/height）。 */
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  background: url("logo.svg") center / contain no-repeat;
}

.logo-text {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  font-weight: 600;
  font-size: var(--td-font-size-m);
}

.logo-text em {
  font-style: normal;
  font-size: var(--td-font-size-s);
  font-weight: 400;
  color: var(--td-text-placeholder);
  letter-spacing: 0.04em;
}

.site-nav {
  margin-left: auto;
}

.site-nav ul {
  display: flex;
  align-items: center;
  gap: var(--td-space-2);
}

.site-nav a {
  display: block;
  padding: var(--td-space-2) var(--td-space-3);
  border-radius: var(--td-radius-md);
  font-size: var(--td-font-size-base);
  color: var(--td-text-secondary);
}

.site-nav a:hover {
  color: var(--td-brand-color);
  background: var(--td-bg-container);
}

.site-nav a[aria-current="page"] {
  color: var(--td-brand-color);
  font-weight: 600;
  background: var(--td-brand-color-light);
}

.header-cta {
  flex-shrink: 0;
}

.nav-toggle {
  display: none;
  margin-left: auto;
  width: 40px;
  height: 40px;
  border: 1px solid var(--td-component-border);
  border-radius: var(--td-radius-md);
  background: var(--td-bg-page);
  cursor: pointer;
  padding: 0;
  place-items: center;
}

.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 18px;
  height: 2px;
  background: var(--td-text-primary);
  border-radius: 2px;
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.nav-toggle-bars {
  position: relative;
  margin: 0 auto;
}

.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: "";
  position: absolute;
  left: 0;
}

.nav-toggle-bars::before {
  top: -6px;
}

.nav-toggle-bars::after {
  top: 6px;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bars {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before {
  transform: translateY(6px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after {
  transform: translateY(-6px) rotate(-45deg);
}

/* -------------------------------------------------------------------- 按钮 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--td-space-2);
  padding: 0 var(--td-space-5);
  height: 40px;
  border-radius: var(--td-radius-md);
  border: 1px solid transparent;
  font-size: var(--td-font-size-base);
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.15s ease, border-color 0.15s ease,
    color 0.15s ease;
}

.btn:hover {
  text-decoration: none;
}

/* 主 CTA 走点睛红：墨蓝底上的红按钮是整页视觉落点，红色面积因此可控在 5% 内 */
.btn-primary {
  background: var(--td-accent);
  color: var(--td-text-anti);
}

.btn-primary:hover {
  background: var(--td-accent-hover);
  color: var(--td-text-anti);
}

.btn-outline {
  background: var(--td-bg-page);
  border-color: var(--td-component-border);
  color: var(--td-text-primary);
}

.btn-outline:hover {
  border-color: var(--td-brand-color);
  color: var(--td-brand-color);
}

.btn-lg {
  height: 48px;
  padding: 0 var(--td-space-6);
  font-size: var(--td-font-size-m);
}

.btn-block {
  width: 100%;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--td-space-3);
}

/* -------------------------------------------------------------- 首屏 Hero */
/* 2026-08-29 李总选定「方案 B · 左文右图」：
   原 hero 是纯文字单栏，右侧 456px（占 container 39%）完全空白，且无任何图形元素。
   改造为两栏：左文案 + 右「一物一码链路」SVG 示意。
   图形不是装饰 —— 它把「一枚码 → 验真 / 溯源 / 渠道」这条业务主线在几秒内讲清楚。 */
.hero {
  padding: var(--td-space-8) 0 var(--td-space-8);
  border-bottom: 1px solid var(--td-component-stroke);
  background: radial-gradient(760px 400px at 72% 10%, rgba(22, 50, 79, 0.09),
                              transparent 62%),
              linear-gradient(180deg, var(--td-brand-color-light) 0%, #ffffff 100%);
}

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 430px;
  gap: var(--td-space-7);
  align-items: center;
}

.hero h1 {
  font-size: var(--td-font-size-xxl);
  line-height: 1.35;
  margin-bottom: var(--td-space-4);
}

.hero-lead {
  font-size: var(--td-font-size-m);
  color: var(--td-text-secondary);
  max-width: 680px;
  margin-bottom: var(--td-space-6);
}

.hero-visual {
  width: 100%;
  height: auto;
  max-width: 430px;
  justify-self: end;
}

/* ---- 首屏编排：h1 不参与（保 LCP），其下元素依次上浮 ----
   位移用 translate 而非 transform —— 按钮自带 hover 抬升（transform: translateY），
   若编排也占用 transform，两者会同属性打架，hover 失效（这个坑在 .feature-row 上踩过一次）。 */
.js-rise {
  animation: rise 0.62s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

[data-rise="1"] { animation-delay: 0.10s; }
[data-rise="2"] { animation-delay: 0.18s; }
[data-rise="3"] { animation-delay: 0.26s; }

@keyframes rise {
  from { opacity: 0; translate: 0 16px; }
  to   { opacity: 1; translate: 0 0; }
}

/* ---- SVG 链路动画 ----
   默认态必须是「完整可见」：线条 dashoffset 为 0、节点 opacity 1。
   只有 JS 加上 .is-running 后才播放 —— 无 JS 时图形静态完整，不会白屏。
   动画不设 fill-mode，播完自然回到默认态，无残留。 */
.hero-visual .link-line {
  stroke: var(--td-brand-color);
  stroke-width: 2;
  fill: none;
  stroke-linecap: round;
  stroke-dasharray: 300;
  stroke-dashoffset: 0;
  opacity: 0.45;
}

.hero-visual .node {
  transform-box: fill-box;
  transform-origin: center;
}

.hero-visual .qr {
  transform-box: fill-box;
  transform-origin: center;
}

.hero-visual.is-running .qr {
  animation: hv-pop 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

.hero-visual.is-running .link-line {
  animation: hv-draw 0.9s cubic-bezier(0.4, 0, 0.2, 1) both;
}

.hero-visual.is-running .link-line.l2 { animation-delay: 0.22s; }
.hero-visual.is-running .link-line.l3 { animation-delay: 0.44s; }

.hero-visual.is-running .node {
  animation: hv-pop 0.45s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.hero-visual.is-running .node.n1 { animation-delay: 0.70s; }
.hero-visual.is-running .node.n2 { animation-delay: 0.88s; }
.hero-visual.is-running .node.n3 { animation-delay: 1.06s; }

/* 循环扫描线：纯装饰，无 JS 时不可见也不影响二维码本体 */
.hero-visual .scan { opacity: 0; }
.hero-visual.is-running .scan {
  animation: hv-scan 2.4s ease-in-out 1.3s infinite;
}

@keyframes hv-draw {
  from { stroke-dashoffset: 300; opacity: 0.12; }
  to   { stroke-dashoffset: 0;   opacity: 0.45; }
}

@keyframes hv-pop {
  from { opacity: 0; transform: scale(0.82); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes hv-scan {
  0%   { opacity: 0; transform: translateY(0); }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(46px); }
}

.hero-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--td-space-2);
  margin-bottom: var(--td-space-6);
}

.tag {
  display: inline-block;
  padding: 2px var(--td-space-3);
  font-size: var(--td-font-size-s);
  color: var(--td-brand-color);
  background: var(--td-bg-page);
  border: 1px solid #cddcf7;
  border-radius: var(--td-radius-round);
}

/* ------------------------------------------------------------------ 面包屑 */
/* 2026-08-29：面包屑由 <main> 直下独占一行，移入 .page-head 内与 h1 同属一个块。
   原先它是「main > .container > nav」+ 「.page-head」两个相邻容器，
   中间隔着各自的盒模型留白，视觉上像一条孤立的横线浮在页头之外。
   移入后改用 margin 控制与标题的间距，不再靠自身 padding 撑高度。 */
.breadcrumb {
  margin: 0 0 var(--td-space-3);
  font-size: var(--td-font-size-s);
  color: var(--td-text-placeholder);
}

.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--td-space-2);
}

.breadcrumb li + li::before {
  content: "/";
  margin-right: var(--td-space-2);
  color: var(--td-component-stroke);
}

/* 上内边距由 space-7(48) 降到 space-5(24)：
   面包屑移入后已占一行（36px），若仍保留 48px 顶部留白，
   h1 会被推到距页头顶端 100px 处，头部显得空旷且与下方内容脱节。
   24 + 36(面包屑) + 12(面包屑下边距) = 72px，与页头体量匹配。
   注：本站 .page-head 仅出现在 6 个内页，且这 6 页现均含面包屑，故无需 :has() 分支。 */
.page-head {
  padding: var(--td-space-5) 0 var(--td-space-6);
  border-bottom: 1px solid var(--td-component-stroke);
  background: var(--td-bg-container);
}

.page-head h1 {
  font-size: var(--td-font-size-xxl);
  line-height: 1.35;
  margin-bottom: var(--td-space-3);
}

.page-head p {
  color: var(--td-text-secondary);
  max-width: 720px;
}

/* -------------------------------------------------------------------- 栅格 */
.grid {
  display: grid;
  gap: var(--td-space-5);
}

.grid-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.grid-3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.grid-4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* -------------------------------------------------------------------- 卡片 */
.card {
  background: var(--td-bg-page);
  border: 1px solid var(--td-component-stroke);
  border-radius: var(--td-radius-lg);
  padding: var(--td-space-5);
  box-shadow: var(--td-shadow-1);
}

.card h3 {
  font-size: var(--td-font-size-m);
  margin-bottom: var(--td-space-3);
}

.card p {
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-base);
}

.card-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--td-radius-md);
  background: var(--td-brand-color-light);
  color: var(--td-brand-color);
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: var(--td-font-size-base);
  margin-bottom: var(--td-space-4);
}

.card--flat {
  box-shadow: none;
}

/* --------------------------------------------------------------- 能力清单 */
.checklist li {
  position: relative;
  padding-left: var(--td-space-5);
  margin-bottom: var(--td-space-2);
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-base);
}

.checklist li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 10px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--td-brand-color);
}

.checklist li:last-child {
  margin-bottom: 0;
}

/* ------------------------------------------------------------ 产品能力条目 */
/* 2026-08-29：左右内边距 0 → 24px（李总反馈「article 内空在悬停时与边框 0 边距」）。
   这个 article 有 hover 态（抬升 + 阴影 + 品牌色描边），阴影勾勒出的矩形边界
   原本紧贴文字起点（实测 contentLeftGap = 0），边界一出现就显得内容顶在框上。
   加内边距后，内容与悬停边界之间留出 24px 呼吸位。

   分割线同步改为伪元素：若继续用 border-top，线会随内边距缩进 24px，
   与上下其它块（.section-head、.notice）的通栏线对不齐，出现内凹错位。
   伪元素 absolute 撑满 border-box，线仍通栏，内容向内缩进，两者各司其职。 */
.feature-row {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--td-space-7);
  align-items: start;
  padding: var(--td-space-7) var(--td-space-5);
}

.feature-row::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--td-component-stroke);
}

.feature-row:first-of-type::before {
  display: none;
}

/* 顶线替代原先 border-color 的悬停反馈（线改用伪元素后，border-color 已无处作用）。 */
.feature-row:hover::before {
  background: var(--td-brand-color-light);
}

.feature-row h2 {
  font-size: var(--td-font-size-xl);
  line-height: 1.4;
  margin-bottom: var(--td-space-3);
}

/* 2026-08-29 移除：序号前缀（01 / 品类 01）经李总确认属冗余装饰，全站删除。
   序号对读者没有信息增量 —— 内容本身就是并列的，编号反而暗示了并不存在的先后次序。 */

.feature-row p {
  color: var(--td-text-secondary);
  margin-bottom: var(--td-space-4);
}

.feature-side {
  background: var(--td-bg-container);
  border: 1px solid var(--td-component-stroke);
  border-radius: var(--td-radius-lg);
  padding: var(--td-space-5);
}

.feature-side h3 {
  font-size: var(--td-font-size-base);
  margin-bottom: var(--td-space-3);
}

.feature-side .checklist li {
  font-size: var(--td-font-size-base);
}

/* -------------------------------------------------------------------- 表格 */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--td-component-stroke);
  border-radius: var(--td-radius-lg);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--td-font-size-base);
  min-width: 560px;
}

caption {
  text-align: left;
  padding: var(--td-space-4) var(--td-space-5);
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-s);
  border-bottom: 1px solid var(--td-component-stroke);
}

th,
td {
  text-align: left;
  padding: var(--td-space-3) var(--td-space-5);
  border-bottom: 1px solid var(--td-component-stroke);
  vertical-align: top;
}

thead th {
  background: var(--td-bg-container);
  font-weight: 600;
  color: var(--td-text-primary);
  white-space: nowrap;
}

tbody tr:last-child td {
  border-bottom: none;
}

tbody td {
  color: var(--td-text-secondary);
}

/* -------------------------------------------------------------- 部署形态卡 */
.deploy-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--td-space-5);
}

.deploy-card {
  border: 1px solid var(--td-component-stroke);
  border-radius: var(--td-radius-lg);
  padding: var(--td-space-6);
  background: var(--td-bg-page);
}

.deploy-card h3 {
  font-size: var(--td-font-size-l);
  margin-bottom: var(--td-space-2);
}

.deploy-card .deploy-sub {
  font-size: var(--td-font-size-base);
  color: var(--td-text-placeholder);
  margin-bottom: var(--td-space-4);
}

/* ------------------------------------------------------------------ 定价卡 */
.price-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--td-space-5);
  align-items: stretch;
}

.price-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--td-component-stroke);
  border-radius: var(--td-radius-lg);
  background: var(--td-bg-page);
  padding: var(--td-space-6);
  box-shadow: var(--td-shadow-1);
}

.price-card--featured {
  border-color: var(--td-brand-color);
  box-shadow: var(--td-shadow-2);
}

.price-badge {
  align-self: flex-start;
  font-size: var(--td-font-size-s);
  color: var(--td-brand-color);
  background: var(--td-brand-color-light);
  border-radius: var(--td-radius-round);
  padding: 2px var(--td-space-3);
  margin-bottom: var(--td-space-3);
}

.price-card h3 {
  font-size: var(--td-font-size-l);
  margin-bottom: var(--td-space-1);
}

.price-card .price-en {
  font-size: var(--td-font-size-s);
  color: var(--td-text-placeholder);
  letter-spacing: 0.04em;
  margin-bottom: var(--td-space-4);
}

.price-amount {
  font-size: var(--td-font-size-xxl);
  font-weight: 600;
  line-height: 1.2;
}

.price-amount small {
  font-size: var(--td-font-size-base);
  font-weight: 400;
  color: var(--td-text-secondary);
}

.price-note {
  font-size: var(--td-font-size-s);
  color: var(--td-text-secondary);
  margin-top: var(--td-space-2);
}

.price-specs {
  margin: var(--td-space-5) 0;
  border-top: 1px solid var(--td-component-stroke);
  padding-top: var(--td-space-4);
}

.price-specs li {
  display: flex;
  justify-content: space-between;
  gap: var(--td-space-3);
  padding: var(--td-space-2) 0;
  font-size: var(--td-font-size-base);
  color: var(--td-text-secondary);
}

.price-specs li span:last-child {
  color: var(--td-text-primary);
  font-weight: 500;
  text-align: right;
}

.price-action {
  margin-top: auto;
}

/* ------------------------------------------------------------------ 提示条 */
.notice {
  border: 1px solid var(--td-component-stroke);
  border-left: 3px solid var(--td-brand-color);
  background: var(--td-bg-container);
  border-radius: var(--td-radius-md);
  padding: var(--td-space-4) var(--td-space-5);
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-base);
}

.notice strong {
  color: var(--td-text-primary);
}

/* -------------------------------------------------------------- 待补充占位 */
.placeholder {
  border: 1px dashed var(--td-component-border);
  border-radius: var(--td-radius-lg);
  background: var(--td-bg-container);
  padding: var(--td-space-6);
  text-align: center;
  color: var(--td-text-secondary);
}

.placeholder-tag {
  display: inline-block;
  font-size: var(--td-font-size-s);
  color: var(--td-warning);
  border: 1px solid var(--td-warning);
  border-radius: var(--td-radius-round);
  /* 竖向 2px 与官网 .tag 对齐（组件级紧凑排版，不是栅格间距，不套间距阶梯） */
  padding: 2px var(--td-space-3);
  margin-bottom: var(--td-space-3);
}

.placeholder h3 {
  font-size: var(--td-font-size-l);
  color: var(--td-text-primary);
  margin-bottom: var(--td-space-3);
}

.placeholder p {
  font-size: var(--td-font-size-base);
  max-width: 560px;
  margin: 0 auto;
}

/* -------------------------------------------------------------------- 表单 */
.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--td-space-4);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--td-space-2);
}

.field--full {
  grid-column: 1 / -1;
}

.field label {
  font-size: var(--td-font-size-base);
  font-weight: 500;
}

.field label .req {
  color: var(--td-error);
  margin-left: 2px;
}

.field input,
.field select,
.field textarea {
  height: 40px;
  padding: 0 var(--td-space-3);
  border: 1px solid var(--td-component-border);
  border-radius: var(--td-radius-md);
  background: var(--td-bg-page);
  transition: border-color 0.15s ease;
}

.field textarea {
  height: auto;
  min-height: 120px;
  padding: var(--td-space-3);
  resize: vertical;
  line-height: 1.6;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--td-brand-color);
  outline: none;
}

.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"],
.field select[aria-invalid="true"] {
  border-color: var(--td-error);
}

.field-error {
  font-size: var(--td-font-size-s);
  color: var(--td-error);
  min-height: 18px;
}

.form-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--td-space-4);
  margin-top: var(--td-space-4);
}

.form-hint {
  font-size: var(--td-font-size-s);
  color: var(--td-text-placeholder);
}

.form-result {
  margin-top: var(--td-space-5);
  border: 1px solid var(--td-component-stroke);
  border-radius: var(--td-radius-md);
  padding: var(--td-space-4);
  background: var(--td-bg-container);
}

.form-result[hidden] {
  display: none;
}

.form-result h3 {
  font-size: var(--td-font-size-base);
  margin-bottom: var(--td-space-2);
}

.form-result textarea {
  width: 100%;
  min-height: 180px;
  padding: var(--td-space-3);
  border: 1px solid var(--td-component-border);
  border-radius: var(--td-radius-md);
  background: var(--td-bg-page);
  font-family: var(--td-font-mono);
  font-size: var(--td-font-size-s);
  line-height: 1.6;
}

.form-status {
  font-size: var(--td-font-size-base);
  padding: var(--td-space-3) var(--td-space-4);
  border-radius: var(--td-radius-md);
  margin-top: var(--td-space-4);
}

.form-status[data-state="ok"] {
  color: var(--td-success);
  background: #e8f8f2;
}

.form-status[data-state="error"] {
  color: var(--td-error);
  background: #fdeeee;
}

/* ------------------------------------------------------------------ 联系卡 */
.contact-grid {
  display: grid;
  grid-template-columns: 340px minmax(0, 1fr);
  gap: var(--td-space-7);
  align-items: start;
}

.contact-list li {
  padding: var(--td-space-3) 0;
  border-bottom: 1px solid var(--td-component-stroke);
  font-size: var(--td-font-size-base);
}

.contact-list li:last-child {
  border-bottom: none;
}

.contact-list .label {
  display: block;
  font-size: var(--td-font-size-s);
  color: var(--td-text-placeholder);
  margin-bottom: 2px;
}

.contact-list .value {
  color: var(--td-text-secondary);
}

.contact-list .value.is-pending {
  color: var(--td-text-placeholder);
}

/* ---------------------------------------------------------------- 前置知识 */
.definition-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--td-space-4) var(--td-space-6);
}

.definition-list div {
  border-left: 2px solid var(--td-component-stroke);
  padding-left: var(--td-space-4);
}

.definition-list dt {
  font-weight: 600;
  font-size: var(--td-font-size-base);
  margin-bottom: 2px;
}

.definition-list dd {
  margin: 0;
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-base);
}

/* ------------------------------------------------------------------ 行动区 */
.cta-band {
  background: var(--td-brand-color);
  color: var(--td-text-anti);
  border-radius: var(--td-radius-lg);
  padding: var(--td-space-7);
  text-align: center;
}

.cta-band h2 {
  font-size: var(--td-font-size-xl);
  margin-bottom: var(--td-space-3);
}

.cta-band p {
  color: rgba(255, 255, 255, 0.85);
  max-width: 620px;
  margin: 0 auto var(--td-space-5);
}

.cta-band .btn-primary {
  background: var(--td-bg-page);
  color: var(--td-brand-color);
}

.cta-band .btn-primary:hover {
  background: var(--td-bg-container);
  color: var(--td-brand-color-active);
}

.cta-band .btn-outline {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.6);
  color: var(--td-text-anti);
}

.cta-band .btn-outline:hover {
  border-color: #ffffff;
  color: var(--td-text-anti);
}

/* -------------------------------------------------------------------- 页脚 */
.site-footer {
  margin-top: var(--td-space-8);
  border-top: 1px solid var(--td-component-stroke);
  background: var(--td-bg-container);
  padding: var(--td-space-7) 0 var(--td-space-5);
  font-size: var(--td-font-size-base);
}

.footer-grid {
  display: grid;
  /* 2026-08-29 轻量化：4 列 → 3 列（品牌 / 产品 / 系统入口+联系我们）。
     原第 4 列「联系我们」里塞了 6 项信息 + 一块二维码，是整页视觉最重的一块；
     二维码移到更宽的品牌列后横排放得下，联系方式也从 6 项减到 3 项。 */
  grid-template-columns: 1.5fr 1fr 1.15fr;
  gap: var(--td-space-6);
}

.footer-col h2 {
  font-size: var(--td-font-size-s);
  font-weight: 600;
  /* 原用 --td-text-placeholder #a9aeb8，在页脚浅底 #f5f7fa 上仅 2.07:1，
     远低于 WCAG 2.1 AA 的 4.5:1 —— 备案号、联系方式这类必须让用户看清的
     内容不能这么浅。改用次级文字色后为 6.62:1。2026-08-29 随墨蓝改版修正。 */
  color: var(--td-text-secondary);
  letter-spacing: 0.06em;
  margin-bottom: var(--td-space-3);
}

.footer-col li {
  margin-bottom: var(--td-space-2);
}

.footer-col a {
  color: var(--td-text-secondary);
}

.footer-col a:hover {
  color: var(--td-brand-color);
}

.footer-about p {
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-base);
  margin-top: var(--td-space-3);
  max-width: 320px;
}

/* 系统入口：域名作为副标题跟在链接文字后面，不再另起一行 ——
   原为 display:block 独占一行，5 个入口就是 10 行，是页脚偏高的主因之一。 */
.footer-entries a {
  display: inline-block;
}

.footer-entries em {
  color: var(--td-text-placeholder);
  font-size: var(--td-font-size-s);
  font-style: normal;
  margin-left: 6px;
}

/* 同一列内的第二个小标题，拉开与上一组的距离，避免两组项目糊在一起 */
.footer-col .footer-sub {
  margin-top: var(--td-space-5);
}

/* 地址：纯文本、无链接行为，用最弱的层级，不与电话/邮箱抢注意力 */
.footer-addr {
  color: var(--td-text-placeholder);
  font-size: var(--td-font-size-s);
  line-height: 1.7;
}

.footer-bottom {
  margin-top: var(--td-space-6);
  padding-top: var(--td-space-4);
  border-top: 1px solid var(--td-component-stroke);
  display: flex;
  flex-wrap: wrap;
  gap: var(--td-space-3) var(--td-space-5);
  align-items: center;
  /* 同 .footer-col h2：占位灰 2.07:1 不达标，备案信息改次级文字色 6.62:1 */
  color: var(--td-text-secondary);
  font-size: var(--td-font-size-s);
  line-height: 1.9;
}

.footer-bottom .spacer {
  margin-left: auto;
}

/* 备案信息分隔竖线：备案号与主体名同排展示时用，避免挤成一坨。
   用 opacity 而非固定灰值，深浅主题下都能保持"弱化但不消失"。 */
.footer-bottom .spacer-sep {
  margin: 0 var(--td-space-2);
  opacity: 0.45;
}

/* 公安备案图标必须回到行内。
   文件顶部的 img 复位规则是 `img, svg { max-width:100%; display:block }`，
   display:block 会让这枚 16px 图标独占一行，备案号被挤到下一行、分隔竖线也跟着错位，
   footer-bottom 因此从 40px 涨到 79px（2026-08-29 实测）。
   vertical-align: -3px 是把图标基线往下压，与 12px 汉字视觉居中对齐。 */
.footer-bottom img {
  display: inline;
  height: 16px;
  vertical-align: -3px;
  margin: 0 var(--td-space-1);
}

/* 页脚微信客服二维码。
   素材缺失或加载失败时，img 的 onerror 会向上隐藏整个 .footer-wx，
   不留破图、不占位，页面其余部分不受影响。 */
.footer-wx {
  margin-top: var(--td-space-5);
  /* 2026-08-29：改为横排。此前放在第 4 列（1fr，约 260px 宽）只能纵向堆叠，
     二维码 + 3 行文字把这一列撑得最高；移到品牌列（1.5fr）后横向放得下，
     文字也从 3 行压到 2 行。 */
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--td-space-4);
}

.footer-wx img {
  /* 源图仅 150x150。两条硬经验：
     1) 屏幕物理像素数决定扫码成败 —— DPR 1 的普通显示器上，CSS 尺寸即物理像素，
        低于 ~150px 时手机扫屏幕会因细节不足而失败（李总 02:28 实测反馈扫不出）。
     2) image-rendering: pixelated 让浏览器用最近邻缩放，二维码模块边界保持锐利；
        默认的双线性/Lanczos 插值会把黑白边界糊成灰边，显著降低识别率。 */
  width: 140px;
  height: 140px;
  flex-shrink: 0;
  /* 有意不套用间距/圆角阶梯：border-box 下 padding 计入 140px 盒子，
     增大 padding 会压缩二维码内容区，直接抬高扫码失败率；140px 与 pixelated
     是 02:28 实测调出来的临界组合。可扫性优先于栅格对齐，勿改。 */
  padding: 6px;
  border-radius: 10px;
  border: 1px solid var(--td-component-stroke);
  background: #fff;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

.footer-wx span {
  color: var(--td-text-placeholder);
  font-size: var(--td-font-size-s);
  line-height: 1.6;
}

.footer-col a,
.footer-bottom a {
  transition: color 0.18s ease;
}

/* -------------------------------------------------------------- 错误页样式 */
.error-page {
  padding: var(--td-space-8) 0;
  text-align: center;
}

.error-code {
  font-size: 64px;
  font-weight: 700;
  color: var(--td-brand-color);
  line-height: 1;
  margin-bottom: var(--td-space-4);
}

/* ------------------------------------------------------------------ 工具类 */
.text-secondary {
  color: var(--td-text-secondary);
}

.text-small {
  font-size: var(--td-font-size-s);
}

.mt-4 {
  margin-top: var(--td-space-4);
}

.mt-5 {
  margin-top: var(--td-space-5);
}

.mt-6 {
  margin-top: var(--td-space-6);
}

/* ------------------------------------------------------------------ 响应式 */
@media (max-width: 1024px) {
  /* 1024 及以下 container 已铺满视口，24px 侧边距即"屏幕边缘到文字"的全部距离。
     在 product / solutions 的两列 feature-row 下更明显：左列正文紧贴屏幕左缘，
     右侧卡片也只剩 24px。统一提到 32px，全站一致，不破坏对齐。
     480 以下仍由后面的断点降到 16px —— 小屏横向空间更宝贵，16px 是移动端常规值。 */
  .container {
    padding: 0 var(--td-space-6);
  }

  /* 右列收窄：1024 下若仍占 430px，左列正文只剩约 480px，h1 会被挤成多行。 */
  .hero-grid {
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: var(--td-space-6);
  }

  .hero-visual {
    max-width: 340px;
  }

  .grid-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .price-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--td-space-4);
  }

  .price-card {
    padding: var(--td-space-5);
  }

  .contact-grid {
    grid-template-columns: 280px minmax(0, 1fr);
    gap: var(--td-space-5);
  }

  .footer-grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--td-space-5);
  }

  /* 品牌列跨满行：3 列降为 2 列时，若品牌只占 1 列会被挤窄，
     二维码（固定 140px）与文字就要换行堆叠，正好回到要消除的问题。 */
  .footer-about {
    grid-column: 1 / -1;
  }
}

@media (max-width: 860px) {
  :root {
    --td-space-7: 32px;
    --td-space-8: 44px;
  }

  /* Hero 改单栏：860 以下两栏会把正文挤成窄条，链路图也失去示意价值。
     图形落到文案下方并居中，可读性与桌面端等价。 */
  .hero-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--td-space-6);
  }

  .hero-visual {
    max-width: 380px;
    justify-self: center;
  }

  .nav-toggle {
    display: grid;
  }

  .header-cta {
    display: none;
  }

  .site-nav {
    order: 3;
    width: 100%;
    margin-left: 0;
    display: none;
    border-top: 1px solid var(--td-component-stroke);
    padding: var(--td-space-2) 0 var(--td-space-3);
  }

  .site-nav.is-open {
    display: block;
  }

  .site-nav ul {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  .site-nav a {
    padding: var(--td-space-3);
    border-radius: var(--td-radius-sm);
  }

  .header-inner {
    flex-wrap: wrap;
    padding-top: var(--td-space-2);
    padding-bottom: var(--td-space-2);
  }

  .grid-2,
  .grid-3,
  .grid-4,
  .deploy-grid,
  .price-grid,
  .definition-list,
  .contact-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .feature-row {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--td-space-4);
    padding: var(--td-space-6) 0;
  }

  .form-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .hero h1,
  .page-head h1 {
    font-size: var(--td-font-size-xl);
  }

  .hero {
    padding-top: var(--td-space-7);
  }

  /* 2026-08-29：窄屏 3 列全塌成 1 列后，页脚实测高达 1003px —— 比 390×844
     的手机视口还高，用户滑到底还得再滑一屏才看到备案号。
     改为「品牌列跨满行 + 两个链接列并排」，高度降到约 730px；
     这与站点 860 断点下 .grid-2/3/4 的处理保持一致。 */
  .footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 480px) {
  .container {
    padding: 0 var(--td-space-4);
  }

  .btn-lg {
    width: 100%;
  }

  .hero-tags {
    gap: var(--td-space-2);
  }

  .cta-band {
    padding: var(--td-space-5) var(--td-space-4);
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  * {
    transition: none !important;
  }

  /* 进场动画的初始态必须显式清掉：transition:none 只挡住过渡过程，
     不会把 opacity:0 改回 1，否则内容会永久不可见 —— 这是无障碍上最严重的失败模式。 */
  .js-reveal,
  .js-reveal.is-visible {
    opacity: 1 !important;
    translate: none !important;
  }

  /* 首屏编排与 Hero 链路动画同理：动画停掉后必须停在「最终可见态」，
     而不是停在 keyframes 的 from（opacity:0 / scale(.82)）。 */
  .js-rise {
    animation: none !important;
    opacity: 1 !important;
    translate: none !important;
  }

  .hero-visual.is-running .link-line,
  .hero-visual.is-running .node,
  .hero-visual.is-running .qr,
  .hero-visual.is-running .scan {
    animation: none !important;
  }

  .hero-visual .link-line {
    stroke-dashoffset: 0 !important;
    opacity: 0.45 !important;
  }

  .hero-visual .node,
  .hero-visual .qr {
    opacity: 1 !important;
    transform: none !important;
  }

  .hero-visual .scan {
    opacity: 0 !important;
  }
}

/* ==========================================================================
   灵动感 · 2026-08-29
   李总反馈：「官网整体专业严谨很好，只是有些死板，不够灵动，也不够现代」。

   诊断：全站 transition 仅 4 处、卡片没有任何 hover 反馈、分区依赖
   section--tint 斑马纹交替。「死板」的直接来源是「没有交互反馈」——
   鼠标划过任何卡片都毫无反应，页面读起来像一张印刷品。

   本次只加「动效层」：不动内容结构、不改 HTML 结构，8 个页面零改动即全站生效。
   所有动效在 prefers-reduced-motion 下自动关闭（见本文件末尾覆盖段）。
   ========================================================================== */

/* ---- 1) 卡片悬停抬升：最直接的「活起来」信号 ---- */
.card,
.card--flat,
.feature-row,
.feature-side {
  transition: transform 0.22s cubic-bezier(0.22, 0.61, 0.36, 1),
              box-shadow 0.22s cubic-bezier(0.22, 0.61, 0.36, 1),
              border-color 0.22s ease;
}

.card:hover,
.card--flat:hover,
.feature-row:hover,
.feature-side:hover {
  transform: translateY(-3px);
  box-shadow: var(--td-shadow-2);
  border-color: var(--td-brand-color-light);
}

/* ---- 2) 按钮：按下有回弹，划过有抬升 ---- */
.btn {
  transition: transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1),
              box-shadow 0.18s ease,
              background-color 0.15s ease,
              border-color 0.15s ease;
}

.btn:hover {
  transform: translateY(-1px);
  box-shadow: var(--td-shadow-2);
}

.btn:active {
  transform: translateY(0);
  box-shadow: var(--td-shadow-1);
}

/* ---- 3) 顶部导航：下划线滑入 + 当前页常驻指示 ---- */
.site-nav a {
  position: relative;
  transition: color 0.18s ease;
}

.site-nav a::after {
  content: "";
  position: absolute;
  left: var(--td-space-3);
  right: var(--td-space-3);
  bottom: 2px;
  height: 2px;
  border-radius: 2px;
  background: var(--td-brand-color);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.24s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.site-nav a:hover::after,
.site-nav a:focus-visible::after,
.site-nav a[aria-current="page"]::after {
  transform: scaleX(1);
}

.site-nav a[aria-current="page"] {
  color: var(--td-brand-color);
  font-weight: 600;
}

/* ---- 4) 外链标记：顶部「工作台」跳 oscm.lifre.cn，需提示离站 ---- */
.nav-external::before {
  content: "\2197";
  display: inline-block;
  margin-right: 4px;
  font-size: 0.85em;
  opacity: 0.55;
}

/* ---- 5) 区块标题：左侧点睛竖线，用品牌红做唯一装饰色 ----
   红只做点睛、面积占比远低于 5%，其余一律墨蓝（见本文件头部配色说明）。 */
.section-head {
  position: relative;
  padding-left: 16px;
}

.section-head::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.28em;
  bottom: 0.28em;
  width: 3px;
  border-radius: 2px;
  background: var(--td-accent);
}

/* ---- 6) 滚动进场 ----
   .js-reveal 由 app.js 添加：没有 JS 时这个 class 根本不存在，
   内容照常显示，不会因为脚本失败而变成一片空白（避免 FOUC 式的白屏风险）。
   首屏（.hero、.page-head）不参与，避免拖累 LCP。 */
/* 位移用独立的 translate 属性，而不是 transform —— 这是个必须避开的坑：
   若写 transform: translateY(14px)，则 .js-reveal.is-visible { transform: none }
   与 .feature-row:hover { transform: translateY(-3px) } 特异性完全相同 (0,2,0)，
   而 .is-visible 定义在后面（本文件更下方），hover 的抬升会被静默吃掉 ——
   product / solutions 的功能块悬停不动，且不留任何报错，很难查。
   translate 与 transform 是两个独立属性，互不参与层叠冲突，可叠加生效。
   不支持 translate 的旧浏览器只会失去进场位移，内容照常显示（opacity 独立控制），
   属优雅降级而非事故。 */
.js-reveal {
  opacity: 0;
  translate: 0 14px;
}

.js-reveal.is-visible {
  opacity: 1;
  translate: 0 0;
  transition: opacity 0.5s ease,
              translate 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---- 7) 入口标签（tag）轻微呼吸感 ---- */
.tag {
  transition: color 0.18s ease, border-color 0.18s ease,
              background-color 0.18s ease;
}
