/* 组件库 · vx.css —— 四个组件共用的样式与色值入口
 *
 * 引入：<link rel="stylesheet" href="组件库/vx.css">（或整段内联进单文件 deck）
 * 换品牌色：不改本文件，在宿主页面里把 --vx-* 映射到自己的 token，例如
 *   :root{ --vx-brand: var(--w6a-brand); --vx-ink: var(--w6a-ink-900); }
 * 🔴 本文件是整套组件里唯一允许出现裸色值的地方；art/charts/mol3d 三个 JS 只读 var(--vx-*)。
 */
:root{
  --vx-brand:#1F5FA8;        /* 主色：强调节点、数据条、高亮点 */
  --vx-brand-soft:#E3ECF7;   /* 主色浅底 */
  --vx-accent:#C6613F;       /* 第二强调：只给"这一个"用，一张图最多一处 */
  --vx-ink:#1C2430;          /* 正文字 */
  --vx-muted:#5B6675;        /* 次级字、坐标轴字 */
  --vx-line:#C9D1DB;         /* 线、网格、边框 */
  --vx-paper:#FFFFFF;        /* 卡片底 */
  --vx-panel:#F5F7FA;        /* 图底 */
  --vx-warn:#9A3B12;         /* 口径待补等警示；对白底 6.98:1、对 panel 6.50:1 */
  --vx-ok:#1B7A48;           /* 达标、在研、通过等正向状态；对白底 5.35:1、对 panel 4.99:1（正文级 ≥4.5） */
  --vx-atom-c:#3E4A56; --vx-atom-o:#C6613F; --vx-atom-n:#2F74B5;
  --vx-atom-h:#E8ECEF; --vx-atom-s:#B08A1E; --vx-atom-x:#6E7B75; --vx-bond:#8794A1;
  /* 色盲友好分类色：Okabe & Ito 2008 色板，RGB 按 jfly.uni-koeln.de/color 图 16 逐值核对；
     多系列图（donut 的 data-palette="cat"、echarts-vx-theme.js）按 1,2,3,5,6,7,4,8 取色，黄色挪后：它不宜做细线与小字 */
  --vx-cat-1:#E69F00; --vx-cat-2:#56B4E9; --vx-cat-3:#009E73; --vx-cat-4:#F0E442;
  --vx-cat-5:#0072B2; --vx-cat-6:#D55E00; --vx-cat-7:#CC79A7; --vx-cat-8:#000000;
  --vx-ss-h:#1F5FA8;         /* protein3d：螺旋 */
  --vx-ss-e:#C6613F;         /* protein3d：折叠片 */
  --vx-ss-c:#9AA5B1;         /* protein3d：无规卷曲 */
  --vx-css-charts:16b;       /* 标记本文件已含 charts.js V16 样式，charts.js 见到它就不再运行时注入 */
  --vx-font:"PingFang SC","Hiragino Sans GB","Noto Sans CJK SC","Microsoft YaHei",system-ui,sans-serif;
}

/* 暗色（选用，不跟随系统自动切换，免得把浅底宿主页的字改成浅色）：宿主在 <html data-theme="dark"> 或容器加 .vx-dark 时启用。
   对比度（对 paper #161B22 ／ panel #0F1318）：ink 14.7／15.8，muted 7.7／8.3，brand 7.0／7.5，accent 6.7／7.2，ok 7.8／8.4，warn 8.3／8.9 : 1 */
:root[data-theme="dark"],.vx-dark{
  --vx-brand:#6FA8E8; --vx-brand-soft:#1C2D44; --vx-accent:#E58A66; --vx-ink:#E8EDF3; --vx-muted:#A3AEBB;
  --vx-line:#3A4452; --vx-paper:#161B22; --vx-panel:#0F1318; --vx-warn:#F0A07A; --vx-ok:#4CC38A;
  --vx-cat-8:#E8EDF3;        /* Okabe–Ito 的黑色在暗底看不见，暗色里换成浅色 */
}

/* ── 通用容器 ── */
.vx-art,.vx-chart,.vx-mol{font-family:var(--vx-font);color:var(--vx-ink);margin:0}
.vx-art svg,.vx-chart svg{display:block;width:100%;height:auto;overflow:visible}
.vx-cap,.vx-src{font-size:14px;line-height:1.5;color:var(--vx-muted);margin-top:8px}
.vx-src.vx-missing{color:var(--vx-warn);font-weight:600}

/* ── art.js ── */
.vx-art .vx-node rect{fill:var(--vx-paper);stroke:var(--vx-line);stroke-width:2}
.vx-art .vx-hot rect{fill:var(--vx-brand-soft);stroke:var(--vx-brand);stroke-width:3}
.vx-art .vx-t{font-size:26px;font-weight:600;fill:var(--vx-ink)}
.vx-art .vx-sub{font-size:20px;fill:var(--vx-muted)}
.vx-art .vx-edge{fill:none;stroke:var(--vx-brand);stroke-width:3;stroke-dasharray:1;stroke-dashoffset:1}
.vx-art .vx-tip{fill:var(--vx-brand)}
.vx-art .vx-packet{fill:var(--vx-accent);opacity:0}
.vx-art .vx-layer{fill:var(--vx-brand-soft);stroke:var(--vx-brand);stroke-width:2}
.vx-art .vx-node{opacity:0;transform:translateY(14px);transform-box:fill-box;
  transition:opacity .5s ease calc(var(--vx-i,0)*.14s),transform .5s ease calc(var(--vx-i,0)*.14s)}
.vx-art .vx-edge{transition:stroke-dashoffset .6s ease calc(.25s + var(--vx-i,0)*.14s)}
.vx-art.vx-in .vx-node{opacity:1;transform:none}
.vx-art.vx-in .vx-edge{stroke-dashoffset:0}
.vx-art.vx-in .vx-packet{opacity:1;transition:opacity .3s ease 1s}

/* ── charts.js ── */
.vx-chart .vx-axis{stroke:var(--vx-line);stroke-width:1.5;fill:none}
.vx-chart .vx-grid{stroke:var(--vx-line);stroke-width:1;stroke-dasharray:4 6;fill:none}
.vx-chart .vx-lab{fill:var(--vx-ink)}
.vx-chart .vx-num{fill:var(--vx-ink);font-weight:700}
.vx-chart .vx-tick{fill:var(--vx-tick,var(--vx-muted))}
.vx-chart .vx-bar{fill:var(--vx-line)}
.vx-chart .vx-bar.vx-hi{fill:var(--vx-brand)}
.vx-chart .vx-bar{transform:scaleX(0);transform-box:fill-box;transform-origin:left center;
  transition:transform .8s cubic-bezier(.2,.7,.2,1) calc(var(--vx-i,0)*.09s)}
.vx-chart.vx-in .vx-bar{transform:none}
.vx-chart .vx-lineplot{fill:none;stroke:var(--vx-brand);stroke-width:4;stroke-dasharray:1;stroke-dashoffset:1;
  transition:stroke-dashoffset 1.2s ease}
.vx-chart.vx-in .vx-lineplot{stroke-dashoffset:0}
.vx-chart .vx-dot{fill:var(--vx-paper);stroke:var(--vx-brand);stroke-width:3}
.vx-chart .vx-seg{fill:none;transition:stroke-dasharray .9s ease}
.vx-chart .vx-num,.vx-chart .vx-dot{opacity:0;transition:opacity .4s ease .7s}
.vx-chart.vx-in .vx-num,.vx-chart.vx-in .vx-dot{opacity:1}

/* ── mol3d.js ── */
.vx-mol canvas{display:block;width:100%;aspect-ratio:16/9;touch-action:none;cursor:grab;
  background:var(--vx-panel);border-radius:14px}
.vx-mol canvas:active{cursor:grabbing}

/* ── charts.js V2：scatter / heat / kpi ── */
.vx-chart .vx-pt{fill:var(--vx-brand);fill-opacity:.55;stroke:var(--vx-brand);stroke-width:1.5;opacity:0;
  transition:opacity .4s ease calc(var(--vx-i,0)*.025s)}
.vx-chart .vx-pt.vx-hi{fill:var(--vx-accent);stroke:var(--vx-accent);fill-opacity:1}
.vx-chart.vx-in .vx-pt{opacity:1}
.vx-chart .vx-diag{stroke:var(--vx-muted);stroke-width:1.5;stroke-dasharray:8 6;fill:none}
.vx-chart .vx-stat{fill:var(--vx-brand)}
.vx-chart .vx-cell{fill:var(--vx-brand);opacity:0;transition:opacity .35s ease calc(var(--vx-i,0)*.03s)}
.vx-chart .vx-stop{stop-color:var(--vx-brand)}
.vx-chart.vx-in .vx-cell{opacity:1}
.vx-chart .vx-cellnum{fill:var(--vx-ink)}
.vx-chart .vx-cellnum.vx-inv{fill:var(--vx-paper)}
.vx-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:16px}
.vx-kpi{background:var(--vx-panel);border-radius:14px;padding:18px 20px;opacity:0;transform:translateY(12px);
  transition:opacity .5s ease calc(var(--vx-i,0)*.12s),transform .5s ease calc(var(--vx-i,0)*.12s)}
.vx-kpi.vx-hi{background:var(--vx-brand-soft);box-shadow:inset 0 0 0 2px var(--vx-brand)}
.vx-chart.vx-in .vx-kpi{opacity:1;transform:none}
.vx-kpi-n{font-size:clamp(34px,4.2vw,56px);font-weight:800;line-height:1.05;color:var(--vx-brand);font-variant-numeric:tabular-nums}
.vx-kpi-u{font-size:18px;font-weight:600;color:var(--vx-muted);margin-left:4px}
.vx-kpi-l{font-size:16px;color:var(--vx-ink);margin-top:6px}

/* ── art.js V2：timeline / layers ── */
.vx-art .vx-mark{fill:var(--vx-paper);stroke:var(--vx-brand);stroke-width:3}
.vx-art .vx-hot .vx-mark{fill:var(--vx-brand)}
.vx-art .vx-stem{stroke:var(--vx-line);stroke-width:2;fill:none}

/* ── graph.js ── */
.vx-graph{font-family:var(--vx-font);color:var(--vx-ink);margin:0}
.vx-graph svg{display:block;width:100%;height:auto;touch-action:none}
.vx-graph .vx-link{stroke:var(--vx-line);stroke-width:2;stroke-dasharray:1;stroke-dashoffset:1;
  transition:stroke-dashoffset .6s ease calc(.3s + var(--vx-i,0)*.03s)}
.vx-graph.vx-in .vx-link{stroke-dashoffset:0}
.vx-graph .vx-gn{cursor:grab}
.vx-graph .vx-gnode{opacity:0;transform:scale(.3);transform-box:fill-box;transform-origin:center;
  transition:opacity .45s ease calc(var(--vx-i,0)*.04s),transform .45s cubic-bezier(.3,1.5,.5,1) calc(var(--vx-i,0)*.04s)}
.vx-graph.vx-in .vx-gnode{opacity:1;transform:none}
.vx-graph .vx-gnode circle{fill:var(--vx-paper);stroke-width:3}
.vx-graph .vx-g0 circle{stroke:var(--vx-brand)} .vx-graph .vx-g1 circle{stroke:var(--vx-accent)}
.vx-graph .vx-g2 circle{stroke:var(--vx-muted)} .vx-graph .vx-g3 circle{stroke:var(--vx-ink)}
.vx-graph .vx-hot circle{fill:var(--vx-brand);stroke:var(--vx-brand)}
.vx-graph text{font-size:17px;fill:var(--vx-ink);pointer-events:none}
.vx-graph .vx-gstat{font-size:16px;font-weight:700;fill:var(--vx-brand)}

/* ── tools/mol2d.py 产出的二维结构式 ── */
.vx-mol2d{margin:0;font-family:var(--vx-font)}
.vx-mol2d svg{display:block;width:100%;height:auto;max-height:440px}
/* 默认就是终态；只有 art.js 接管（加 vx-armed）后才先藏起、进场再描，没引 art.js 也不会是空图 */
.vx-mol2d .vx-b{fill:none;stroke:var(--vx-ink);stroke-width:2.4;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:0;
  transition:stroke-dashoffset .3s ease calc(var(--vx-i,0)*.06s)}
.vx-mol2d .vx-w{fill:var(--vx-ink)} .vx-mol2d .vx-hash{fill:none;stroke:var(--vx-ink);stroke-width:1.8}
.vx-mol2d .vx-w,.vx-mol2d .vx-hash,.vx-mol2d .vx-a{transition:opacity .3s ease calc(var(--vx-i,0)*.06s)}
.vx-mol2d.vx-armed:not(.vx-in) .vx-b{stroke-dashoffset:1}
.vx-mol2d.vx-armed:not(.vx-in) .vx-w,.vx-mol2d.vx-armed:not(.vx-in) .vx-hash,.vx-mol2d.vx-armed:not(.vx-in) .vx-a{opacity:0}
.vx-mol2d .vx-a{font-size:17px;font-weight:600;fill:var(--vx-atom-x)}
.vx-mol2d .vx-ix,.vx-mol2d .vx-sup{font-size:12px}
.vx-mol2d .vx-el-O{fill:var(--vx-atom-o)} .vx-mol2d .vx-el-N{fill:var(--vx-atom-n)} .vx-mol2d .vx-el-S{fill:var(--vx-atom-s)}

/* ── protein3d.js ── */
.vx-prot{margin:0;font-family:var(--vx-font)}
.vx-prot canvas{display:block;width:100%;aspect-ratio:16/9;touch-action:none;cursor:grab;background:var(--vx-panel);border-radius:14px}
.vx-prot canvas:active{cursor:grabbing}
.vx-prot-bar{display:flex;gap:8px;margin-top:10px}
.vx-prot-bar button{font:600 14px var(--vx-font);color:var(--vx-ink);background:var(--vx-paper);border:1.5px solid var(--vx-line);
  border-radius:999px;padding:6px 16px;cursor:pointer}
.vx-prot-bar button[aria-pressed="true"]{background:var(--vx-brand);border-color:var(--vx-brand);color:var(--vx-paper)}

/* ── 质感背景（整块容器加 class 即可，纯 CSS，不需要 JS） ── */
.vx-bg-dots{background-image:radial-gradient(var(--vx-line) 1.2px,transparent 1.4px);background-size:22px 22px}
.vx-bg-grid{background-image:linear-gradient(var(--vx-line) 1px,transparent 1px),linear-gradient(90deg,var(--vx-line) 1px,transparent 1px);
  background-size:48px 48px;background-position:-1px -1px}
.vx-bg-grain{position:relative;isolation:isolate}
.vx-bg-grain::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:.12;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
.vx-bg-aurora{background-color:var(--vx-panel);
  background-image:radial-gradient(55% 60% at 15% 20%,color-mix(in oklab,var(--vx-brand) 24%,transparent),transparent 70%),
    radial-gradient(45% 55% at 85% 25%,color-mix(in oklab,var(--vx-accent) 18%,transparent),transparent 70%),
    radial-gradient(65% 55% at 50% 105%,color-mix(in oklab,var(--vx-brand) 16%,transparent),transparent 70%);
  background-size:160% 160%;animation:vx-drift 22s ease-in-out infinite alternate}
@keyframes vx-drift{from{background-position:0% 0%}to{background-position:100% 100%}}

/* ── 内联图标（tools/icon_inline.py 产出；描边用 currentColor，随文字色走） ── */
.vx-ico{display:inline-flex;width:1.15em;height:1.15em;vertical-align:-.2em;color:var(--vx-brand)}
.vx-ico svg{width:100%;height:100%;stroke-width:1.75}

/* ── 浏览器壳与手机壳：包住 tools/shoot.py 的实拍，截图变成"在用的产品" ── */
.vx-browser{margin:0;border-radius:12px;overflow:hidden;background:var(--vx-paper);border:1px solid var(--vx-line);
  box-shadow:0 10px 32px color-mix(in oklab,var(--vx-ink) 16%,transparent)}
.vx-browser::before{content:attr(data-url);display:block;padding:9px 14px 9px 66px;font:13px/1.4 var(--vx-font);color:var(--vx-muted);
  background:var(--vx-panel) no-repeat 14px 50%/42px 10px;border-bottom:1px solid var(--vx-line);
  background-image:radial-gradient(circle at 5px 5px,var(--vx-cat-6) 4.5px,transparent 5px),
    radial-gradient(circle at 21px 5px,var(--vx-cat-1) 4.5px,transparent 5px),radial-gradient(circle at 37px 5px,var(--vx-cat-3) 4.5px,transparent 5px)}
.vx-browser img,.vx-phone img{display:block;width:100%;height:auto}
.vx-phone{margin:0 auto;max-width:300px;padding:12px;border-radius:40px;background:var(--vx-ink);
  box-shadow:0 12px 36px color-mix(in oklab,var(--vx-ink) 22%,transparent)}
.vx-phone img{border-radius:28px}

/* ── 滚动揭示（浏览器原生滚动驱动动画；不支持的浏览器直接显示，不会藏住内容） ── */
@supports (animation-timeline: view()){
  .vx-reveal{animation:vx-rise linear both;animation-timeline:view();animation-range:entry 0% entry 70%}
}
@keyframes vx-rise{from{opacity:0;transform:translateY(32px) scale(.98)}to{opacity:1;transform:none}}
.vx-balance{text-wrap:balance}

/* ── 幻灯内（deck.css 的 .vx-slide，1920×1080 设计稿）：图注、口径、数字卡的 HTML 字号抬到投影可读 ── */
.vx-slide .vx-cap,.vx-slide .vx-src,.vx-slide .vx-demo{font-size:20px}
.vx-slide .vx-kpi-u{font-size:24px} .vx-slide .vx-kpi-l{font-size:24px}
.vx-slide .vx-kpi-n{font-size:72px}

/* ── charts.js V16：radar / sankey / gauge / waffle / progress / magnitude / scatter 分类与决策边界 / sparkline / demo 标注 ──
   与 charts.js 里 CHARTS_CSS 逐条同值（自测 C2 比对），改一处必须同改另一处 */
.vx-chart .vx-big{font-weight:800}
.vx-chart .vx-rgrid{fill:none;stroke:var(--vx-line);stroke-width:1}
.vx-chart .vx-raxis{stroke:var(--vx-line);stroke-width:1}
.vx-chart .vx-rpoly{stroke-width:2.5;stroke-linejoin:round}
.vx-chart .vx-grow{transform:scale(0);transition:transform .9s cubic-bezier(.2,.7,.2,1)}
.vx-chart.vx-in .vx-grow{transform:none}
.vx-chart .vx-flow{fill:none;stroke-opacity:.34;stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset 1.1s ease calc(var(--vx-i,0)*.07s)}
.vx-chart.vx-in .vx-flow{stroke-dashoffset:0}
.vx-chart .vx-slab{paint-order:stroke;stroke:var(--vx-paper);stroke-width:4px;stroke-linejoin:round}
.vx-chart .vx-gtrack{fill:none;stroke:var(--vx-brand-soft);stroke-linecap:round}
.vx-chart .vx-garc{fill:none;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset 1.2s cubic-bezier(.2,.7,.2,1)}
.vx-chart.vx-in .vx-garc{stroke-dashoffset:0}
.vx-chart .vx-wf{fill:var(--vx-brand-soft);opacity:0;transition:opacity .25s ease calc(var(--vx-i,0)*.012s)}
.vx-chart .vx-wf.vx-on{fill:var(--vx-brand)}
.vx-chart.vx-in .vx-wf{opacity:1}
.vx-chart .vx-track{fill:var(--vx-brand-soft)}
.vx-chart .vx-segnum{fill:var(--vx-paper);font-weight:600;opacity:0;transition:opacity .4s ease .8s}
.vx-chart.vx-in .vx-segnum{opacity:1}
.vx-chart .vx-err{color:var(--vx-warn);font-weight:600;padding:12px 14px;border:1px dashed var(--vx-warn);border-radius:8px}
.vx-chart .vx-bar.vx-mrange{fill:var(--vx-brand);fill-opacity:.35}
.vx-chart .vx-bound{fill:none;stroke:var(--vx-ink);stroke-width:2.5;stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset 1.2s ease .3s}
.vx-chart.vx-in .vx-bound{stroke-dashoffset:0}
.vx-chart .vx-bkey{fill:none;stroke:var(--vx-ink);stroke-width:2.5}
.vx-chart .vx-spark{stroke-width:2.5}
.vx-chart .vx-sdot{fill:var(--vx-brand)}
.vx-demo{display:inline-block;margin:0 0 8px;padding:3px 10px;border-radius:6px;font-size:14px;font-weight:600;color:var(--vx-warn);border:1px solid var(--vx-warn)}
@media (prefers-reduced-motion: reduce){.vx-chart .vx-grow,.vx-chart .vx-flow,.vx-chart .vx-garc,.vx-chart .vx-wf,.vx-chart .vx-segnum,.vx-chart .vx-bound{transition:none!important;opacity:1!important;transform:none!important;stroke-dashoffset:0!important}}
html.vx-static .vx-chart .vx-grow,html.vx-static .vx-chart .vx-flow,html.vx-static .vx-chart .vx-garc,html.vx-static .vx-chart .vx-wf,html.vx-static .vx-chart .vx-segnum,html.vx-static .vx-chart .vx-bound{transition:none!important;opacity:1!important;transform:none!important;stroke-dashoffset:0!important}

/* ── 终态：无动效偏好 / 静帧导出（html.vx-static）一律直接显示终态 ── */
@media (prefers-reduced-motion: reduce){
  .vx-art .vx-node,.vx-art .vx-edge,.vx-chart .vx-bar,.vx-chart .vx-lineplot,.vx-chart .vx-num,.vx-chart .vx-dot,
  .vx-chart .vx-pt,.vx-chart .vx-cell,.vx-kpi,.vx-graph .vx-link,.vx-graph .vx-gnode,
  .vx-mol2d .vx-b,.vx-mol2d .vx-w,.vx-mol2d .vx-hash,.vx-mol2d .vx-a{
    transition:none!important;opacity:1!important;transform:none!important;stroke-dashoffset:0!important}
  .vx-art .vx-packet{display:none}
  .vx-bg-aurora,.vx-reveal{animation:none!important}
}
html.vx-static .vx-art .vx-node,html.vx-static .vx-art .vx-edge,html.vx-static .vx-chart .vx-bar,
html.vx-static .vx-chart .vx-lineplot,html.vx-static .vx-chart .vx-num,html.vx-static .vx-chart .vx-dot,
html.vx-static .vx-chart .vx-pt,html.vx-static .vx-chart .vx-cell,html.vx-static .vx-kpi,
html.vx-static .vx-graph .vx-link,html.vx-static .vx-graph .vx-gnode,html.vx-static .vx-mol2d .vx-b,
html.vx-static .vx-mol2d .vx-w,html.vx-static .vx-mol2d .vx-hash,html.vx-static .vx-mol2d .vx-a{
  transition:none!important;opacity:1!important;transform:none!important;stroke-dashoffset:0!important}
html.vx-static .vx-art .vx-packet{display:none}
html.vx-static .vx-bg-aurora,html.vx-static .vx-reveal{animation:none!important}
