diff --git a/release/SpineThumbnailGenerateServer站点/app.js b/release/SpineThumbnailGenerateServer站点/app.js new file mode 100644 index 0000000..25ee276 --- /dev/null +++ b/release/SpineThumbnailGenerateServer站点/app.js @@ -0,0 +1,66 @@ +(function () { + 'use strict'; + + var root = document.documentElement; + var themeToggle = document.getElementById('themeToggle'); + + if (themeToggle) { + themeToggle.addEventListener('click', function () { + var next = root.dataset.theme === 'dark' ? 'light' : 'dark'; + root.dataset.theme = next; + try { localStorage.setItem('stg-site-theme', next); } catch (error) {} + }); + } + + var revealEls = Array.prototype.slice.call(document.querySelectorAll('.reveal')); + var revealTick = 0; + + function revealInViewport() { + var viewportHeight = window.innerHeight || document.documentElement.clientHeight; + revealEls.forEach(function (el) { + if (el.classList.contains('visible')) return; + var rect = el.getBoundingClientRect(); + if (rect.top < viewportHeight * 0.94 && rect.bottom > 0) el.classList.add('visible'); + }); + } + + function scheduleReveal() { + if (revealTick) return; + revealTick = window.requestAnimationFrame(function () { + revealTick = 0; + revealInViewport(); + }); + } + + revealInViewport(); + window.addEventListener('scroll', scheduleReveal, { passive: true }); + window.addEventListener('resize', scheduleReveal); + setTimeout(function () { + revealEls.forEach(function (el) { el.classList.add('visible'); }); + }, 2000); + + var lightbox = document.getElementById('lightbox'); + var lightboxImg = lightbox ? lightbox.querySelector('img') : null; + + function closeLightbox() { + if (!lightbox || lightbox.hidden) return; + lightbox.hidden = true; + lightboxImg.removeAttribute('src'); + document.body.style.overflow = ''; + } + + if (lightbox) { + document.querySelectorAll('img.zoomable').forEach(function (img) { + img.addEventListener('click', function () { + lightboxImg.src = img.currentSrc || img.src; + lightboxImg.alt = img.alt || ''; + lightbox.hidden = false; + document.body.style.overflow = 'hidden'; + }); + }); + lightbox.addEventListener('click', closeLightbox); + window.addEventListener('keydown', function (event) { + if (event.key === 'Escape') closeLightbox(); + }); + } +})(); diff --git a/release/SpineThumbnailGenerateServer站点/assets/logo.png b/release/SpineThumbnailGenerateServer站点/assets/logo.png new file mode 100644 index 0000000..4ef2ca1 Binary files /dev/null and b/release/SpineThumbnailGenerateServer站点/assets/logo.png differ diff --git a/release/SpineThumbnailGenerateServer站点/assets/promo-banner.jpg b/release/SpineThumbnailGenerateServer站点/assets/promo-banner.jpg new file mode 100644 index 0000000..a1d71b6 Binary files /dev/null and b/release/SpineThumbnailGenerateServer站点/assets/promo-banner.jpg differ diff --git a/release/SpineThumbnailGenerateServer站点/assets/ui-main.jpg b/release/SpineThumbnailGenerateServer站点/assets/ui-main.jpg new file mode 100644 index 0000000..8ea405b Binary files /dev/null and b/release/SpineThumbnailGenerateServer站点/assets/ui-main.jpg differ diff --git a/release/SpineThumbnailGenerateServer站点/assets/ui-window.png b/release/SpineThumbnailGenerateServer站点/assets/ui-window.png new file mode 100644 index 0000000..040951f Binary files /dev/null and b/release/SpineThumbnailGenerateServer站点/assets/ui-window.png differ diff --git a/release/SpineThumbnailGenerateServer站点/index.html b/release/SpineThumbnailGenerateServer站点/index.html new file mode 100644 index 0000000..35fbc0a --- /dev/null +++ b/release/SpineThumbnailGenerateServer站点/index.html @@ -0,0 +1,384 @@ + + + + + +SpineThumbnails — Eagle 插件 · Spine 导出资源缩略图自动生成 + + + + + + + + + + + + + +
+
+ + SpineThumbnails 图标 + SpineThumbnails + v1.0.0 + + +
+ + 获取插件 +
+
+
+ +
+
+ +
+
+ Eagle 插件 · 自动资源配对 +

导入完成,
缩略图自动就位

+

+ SpineThumbnails 识别 Eagle 中导入的 Spine 骨骼、Atlas 与贴图, + 自动跨 item 文件夹完成配对,再按你的设置生成静态 PNG 或动态 WebP 缩略图。 + 从版本识别到渲染、写入、进度反馈,一次完成。 +

+ +
    +
  • 9Spine 版本
    3.4 – 4.3
  • +
  • 2缩略图模式
    静态 / 动态
  • +
  • 8界面语言
    简繁英日韩俄西德
  • +
+
+
+
+ SpineThumbnails 插件主界面:自动生成开关、生成方式、策略、状态、统计与分类日志 +
SpineThumbnails 1.0.0 · 插件主界面
+
+
+ + 首次使用默认关闭自动生成,只有主动开启后才会处理新导入的素材。 +
+
+
+
+
    +
  • json
  • +
  • skel
  • +
  • skel.bytes
  • +
  • atlas
  • +
  • atlas.txt
  • +
  • png / jpg / webp · 用于 atlas 贴图配对
  • +
+
+
+ +
+
+
+ SAFE BY DEFAULT +

默认关闭,只处理新导入

+

缩略图会写入 Eagle 素材卡片,因此在首次使用时需要明确打开自动生成开关。

+
+
    +
  • + 01 + 不扫描历史素材 +

    插件从启用后的新导入批次开始监听,不会回头批量修改已有素材。

    +
  • +
  • + 02 + 不覆盖自定义缩略图 +

    检测到素材已有自定义缩略图时直接跳过,并把结果记录在分类日志中。

    +
  • +
  • + 03 + 配置独立保存 +

    设置写入 Eagle 用户数据目录,不修改素材 metadata.json、标签或注释。

    +
  • +
+
+
+ +
+
+
+ FEATURES +

导入之后,剩下交给插件

+

不是只会渲染一张图:资源发现、跨目录配对、版本切换、编码搜索和写入反馈都在同一个后台流程里完成。

+
+
+
+ +

跨文件夹自动配对

+

Eagle 会把每个导入文件拆成独立 item 文件夹。插件按文件名与尾缀规则关联骨骼、atlas 和贴图,即使它们分散在不同目录也能组成一套资源。

+
+
+ +

静态与动态两种输出

+

静态模式固定使用 setup pose 输出 PNG;动态模式读取骨骼中的第一个动画,逐帧渲染后封装为轻量 WebP。

+
+
+ +

体积与速度双策略

+

“最优体积”生成十个候选档位并保留最小结果;“最优速度”先粗估再只渲染最有希望的一两档,适合大批量导入。

+
+
+ +

9 个运行版本

+

从 JSON 版本字段或 SKEL 二进制头部识别 Spine 版本,自动匹配 3.4–4.3 对应的本地运行时。

+
+
+ +

批次串行处理

+

一次只渲染一个素材,避免批量导入时把 Eagle 卡住。后续批次自动排队,进度窗口会同步总数与剩余数量。

+
+
+ +

暂停、继续与取消

+

大批量动态生成时自动显示进度窗口。可暂停当前队列、继续执行,或取消剩余任务并保留已经完成的结果。

+
+
+ +

分类日志

+

成功、失败、警告和错误可分别筛选。每条记录包含素材名、Eagle 文件夹、骨架、atlas 与贴图齐全情况。

+
+
+ +

八种界面语言

+

跟随 Eagle 当前语言显示简体中文、繁体中文、英文、日文、韩文、俄文、西班牙文或德文界面。

+
+
+
+
+ +
+
+
+ WORKFLOW +

从导入到缩略图

+

首次打开自动生成后,后续新导入的 Spine 素材会沿同一条串行流程处理。

+
+
    +
  1. + 01 +

    发现新素材

    +

    监听 Eagle 素材库目录,在导入批次稳定后读取新增 item,历史素材不会进入队列。

    +
  2. +
  3. + 02 +

    配对与检查

    +

    关联骨骼、atlas 和贴图,检查版本、复合后缀、贴图数量以及是否已有自定义缩略图。

    +
  4. +
  5. + 03 +

    渲染缩略图

    +

    加载匹配运行时,按静态或动态模式绘制画布。动态模式继续搜索满足目标体积的编码参数。

    +
  6. +
  7. + 04 +

    写入与反馈

    +

    通过 Eagle 官方接口写入自定义缩略图,并同步更新统计、分类日志与进度窗口。

    +
  8. +
+
+
+ +
+
+
+ OUTPUT +

按素材用途选择输出

+

两种模式共用同一套资源识别与安全检查,只在最终渲染阶段不同。

+
+
+
+ +
+ STATIC +

静帧 · setup pose

+

始终生成一个稳定的 default 姿势,适合需要明确默认形象、动画首帧不适合作为封面的素材。

+
    +
  • 输出格式:PNG
  • +
  • 渲染内容:setup pose
  • +
  • 速度:更快,结果稳定
  • +
+
+
+
+ +
+ ANIMATED +

动态 · 首个动画

+

读取骨骼中的第一个动画,采样帧后封装为动态 WebP,让素材卡片直接呈现动作状态。

+
    +
  • 输出格式:动画 WebP
  • +
  • 渲染内容:第一个动画
  • +
  • 速度:更慢,需搜索编码档位
  • +
+
+
+
+
+
+ +
+
+
+ SUPPORTED +

覆盖 Spine 3.4 – 4.3

+

支持 JSON、SKEL、SKEL.BYTES、ATLAS 与 ATLAS.TXT,使用与皮肤和约束相匹配的本地运行时渲染。

+
+
    +
  • 3.4
  • 3.5
  • 3.6
  • 3.7
  • +
  • 3.8
  • 4.0
  • 4.1
  • 4.2
  • 4.3
  • +
+
+ + + + + + + + + + + + + + + + + + + + + +
版本骨骼输入渲染说明
3.4 / 3.5JSON · SKEL · SKEL.BYTES使用独立版本运行时和匹配的二进制解析分支,保留网格、权重、变形、约束与绘制顺序。
3.6 / 3.7JSON · SKEL · SKEL.BYTES通过官方同版本 SkeletonBinary 兼容层解析,无需额外导入 JSON。
3.8 – 4.3JSON · SKEL · SKEL.BYTES读取数据版本并加载对应运行时;4.x 的物理约束、裁剪和染色能力由运行时处理。
+
+
    +
  • 复合后缀 skel.bytes
  • +
  • 复合后缀 atlas.txt
  • +
  • PMA 贴图
  • +
  • 多皮肤骨骼
  • +
  • 动态 WebP
  • +
  • 进度暂停与取消
  • +
  • 八种界面语言
  • +
+
+
+ +
+
+
+ GET STARTED +

安装后只需打开一次开关

+

插件不会在默认状态下自动写入缩略图。先在控制面板开启“导入时自动生成缩略图”,再导入新的 Spine 资源。

+
+ + + EAGLE PLUGIN COMMUNITY + 在 Eagle 插件社区获取 SpineThumbnails + 搜索“Spine缩略图”,或直接打开 Eagle 插件社区。 + + 前往插件页 → + +
    +
  1. +

    安装并打开插件

    +

    在 Eagle 中安装插件,打开 SpineThumbnails 控制面板。

    +
  2. +
  3. +

    启用自动生成

    +

    打开“导入时自动生成缩略图”,选择动态或静态模式,以及最优体积或最优速度策略。

    +
  4. +
  5. +

    导入整套资源

    +

    把骨骼、atlas 和贴图导入 Eagle。插件会只针对本次新导入的素材自动处理。

    +
  6. +
+ +
+
+ +
+
+
+ FAQ +

常见问题

+
+
+
+ 插件会覆盖我已经设置好的缩略图吗? +

不会。检测到素材已有自定义缩略图时会跳过并记录日志。插件只通过 Eagle 官方接口设置当前新素材的缩略图。

+
+
+ 为什么历史素材没有自动处理? +

这是默认安全行为。插件只处理启用后新导入的素材,不扫描、不修改历史素材,避免一次开关造成全素材库批量变更。

+
+
+ 资源没有同时导入会怎样? +

配套不全的素材会记为待观察。后续批次补齐 atlas 或贴图后,插件会重新检查并继续处理。

+
+
+ 动态缩略图为什么比静态慢? +

动态模式需要渲染多个动画帧,还要在分辨率、帧率、质量和目标体积之间寻找合适档位。选择“最优速度”会减少实际生成的候选数量。

+
+
+
+
+
+ + + + + + + + diff --git a/release/SpineThumbnailGenerateServer站点/style.css b/release/SpineThumbnailGenerateServer站点/style.css new file mode 100644 index 0000000..0de8fa1 --- /dev/null +++ b/release/SpineThumbnailGenerateServer站点/style.css @@ -0,0 +1,1463 @@ +/* ========================================================================== + SpineThumbnails 插件介绍网站样式 + - 品牌色取自插件图标(红) + ========================================================================== */ + +:root { + --bg: #131317; + --bg-2: #17171c; + --panel: #1c1c22; + --panel-2: #24242c; + --text: #e9e9ee; + --text-dim: #9d9da8; + --border: #2c2c35; + --accent: #f2353b; + --accent-2: #ff6a4d; + --cyan: #4fc1ff; + --card-shadow: 0 18px 40px rgba(0, 0, 0, .38); +} + +html[data-theme="light"] { + --bg: #f4f5f7; + --bg-2: #ebedf0; + --panel: #ffffff; + --panel-2: #f1f2f4; + --text: #1d1d22; + --text-dim: #63636e; + --border: #dcdee3; + --accent: #e01f26; + --accent-2: #ff5a3c; + --cyan: #0078d4; + --card-shadow: 0 16px 34px rgba(20, 20, 30, .10); +} + +* { box-sizing: border-box; } + +html { + scroll-behavior: smooth; + scroll-padding-top: 78px; +} + +body { + margin: 0; + background-color: var(--bg); + background-image: + radial-gradient(900px 520px at 12% 0%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 62%), + radial-gradient(760px 460px at 88% 120px, color-mix(in srgb, var(--cyan) 10%, transparent), transparent 64%); + background-repeat: no-repeat; + color: var(--text); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; + font-size: 15px; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +::selection { background: color-mix(in srgb, var(--accent) 38%, transparent); } + +a { color: inherit; } + +code { + font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace; + font-size: .86em; + background: color-mix(in srgb, var(--panel-2) 82%, transparent); + border: 1px solid var(--border); + border-radius: 6px; + padding: 1px 6px; + white-space: nowrap; +} + +kbd { + font-family: inherit; + font-size: .86em; + font-weight: 700; + background: var(--panel-2); + border: 1px solid var(--border); + border-bottom-width: 2px; + border-radius: 6px; + padding: 1px 7px; +} + +:focus-visible { + outline: 2px solid color-mix(in srgb, var(--cyan) 65%, transparent); + outline-offset: 2px; + border-radius: 6px; +} + +.wrap { + width: 100%; + max-width: 1140px; + margin: 0 auto; + padding: 0 22px; +} + +/* ---------- 顶栏 ---------- */ + +.topbar { + position: sticky; + top: 0; + z-index: 50; + background: color-mix(in srgb, var(--bg) 93%, transparent); + border-bottom: 1px solid var(--border); +} + +.topbar-inner { + display: flex; + align-items: center; + gap: 18px; + min-height: 62px; +} + +.brand { + display: inline-flex; + align-items: center; + gap: 10px; + text-decoration: none; + font-weight: 700; + letter-spacing: -0.01em; +} + +.brand img { border-radius: 8px; display: block; } + +.brand-name { font-size: 16px; } + +.brand-ver { + font-size: 11.5px; + font-weight: 600; + color: var(--text-dim); + border: 1px solid var(--border); + border-radius: 999px; + padding: 1px 9px; +} + +.nav { + margin-left: auto; + display: flex; + gap: 2px; +} + +.nav a { + text-decoration: none; + color: var(--text-dim); + font-size: 13.5px; + padding: 8px 12px; + border-radius: 8px; + transition: color .15s, background .15s; +} + +.nav a:hover { color: var(--text); background: var(--panel); } + +.topbar-actions { display: flex; align-items: center; gap: 10px; } + +.icon-btn { + width: 36px; + height: 36px; + display: grid; + place-items: center; + border-radius: 10px; + border: 1px solid var(--border); + background: var(--panel); + color: var(--text-dim); + cursor: pointer; + transition: color .15s, border-color .15s; +} + +.icon-btn:hover { color: var(--text); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); } + +.icon-btn svg { + width: 18px; + height: 18px; + fill: none; + stroke: currentColor; + stroke-width: 1.7; + stroke-linecap: round; + stroke-linejoin: round; +} + +.icon-sun { display: none; } +.icon-moon { display: block; } +html[data-theme="dark"] .icon-sun { display: block; } +html[data-theme="dark"] .icon-moon { display: none; } + +/* ---------- 按钮 ---------- */ + +.btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 11px 20px; + border-radius: 11px; + font-size: 14px; + font-weight: 600; + text-decoration: none; + border: 1px solid transparent; + cursor: pointer; + transition: transform .16s, box-shadow .16s, border-color .16s, background .16s; + white-space: nowrap; +} + +.btn-primary { + background: linear-gradient(135deg, var(--accent), var(--accent-2)); + color: #fff; + box-shadow: 0 10px 26px color-mix(in srgb, var(--accent) 30%, transparent); +} + +.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 14px 30px color-mix(in srgb, var(--accent) 38%, transparent); } + +.btn-ghost { + background: var(--panel); + border-color: var(--border); + color: var(--text); +} + +.btn-ghost:hover { border-color: color-mix(in srgb, var(--cyan) 45%, var(--border)); transform: translateY(-1px); } + +.btn-sm { padding: 8px 15px; font-size: 13px; border-radius: 9px; } + +.link-arrow { + color: var(--cyan); + text-decoration: none; + font-size: 14px; + font-weight: 600; +} + +.link-arrow:hover { text-decoration: underline; } + +/* ---------- Hero ---------- */ + +.hero { position: relative; padding: 70px 0 26px; overflow: hidden; } + +.hero-glow { + position: absolute; + left: 50%; + top: -140px; + transform: translateX(-50%); + width: min(1500px, 130vw); + height: 620px; + background: + radial-gradient(560px 300px at 26% 34%, color-mix(in srgb, var(--accent) 20%, transparent), transparent 66%), + radial-gradient(520px 300px at 74% 26%, color-mix(in srgb, var(--cyan) 15%, transparent), transparent 68%); + pointer-events: none; +} + +.hero-grid { + position: relative; + display: grid; + grid-template-columns: 1.02fr .98fr; + gap: 48px; + align-items: center; +} + +.pill { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 7px 14px; + border-radius: 999px; + border: 1px solid var(--border); + background: color-mix(in srgb, var(--panel) 72%, transparent); + color: var(--text-dim); + font-size: 12.5px; +} + +.pill .dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: #35d07f; + box-shadow: 0 0 0 0 rgba(53, 208, 127, .5); + animation: pulse 2.4s infinite; +} + +@keyframes pulse { + 0% { box-shadow: 0 0 0 0 rgba(53, 208, 127, .45); } + 70% { box-shadow: 0 0 0 7px rgba(53, 208, 127, 0); } + 100% { box-shadow: 0 0 0 0 rgba(53, 208, 127, 0); } +} + +.hero h1 { + margin: 20px 0 16px; + font-size: clamp(2.1rem, 4.1vw, 3.25rem); + line-height: 1.14; + letter-spacing: -0.022em; + font-weight: 800; +} + +.grad { + background: linear-gradient(115deg, var(--accent), var(--accent-2) 42%, var(--cyan)); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.hero-sub { + margin: 0; + max-width: 560px; + color: var(--text-dim); + font-size: 15.5px; + line-height: 1.8; +} + +.hero-cta { + display: flex; + align-items: center; + gap: 16px; + flex-wrap: wrap; + margin: 28px 0 32px; +} + +.stats { + list-style: none; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 12px; + padding: 0; + margin: 0; +} + +.stats li { + display: flex; + flex-direction: column; + gap: 4px; + padding: 13px 15px; + border: 1px solid var(--border); + border-radius: 13px; + background: color-mix(in srgb, var(--panel) 74%, transparent); +} + +.stats b { + font-size: 21px; + line-height: 1.1; + letter-spacing: -0.02em; + background: linear-gradient(120deg, var(--text), color-mix(in srgb, var(--cyan) 55%, var(--text))); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.stats span { font-size: 11.5px; color: var(--text-dim); line-height: 1.55; } + +.hero-visual { display: flex; flex-direction: column; } + +.badge-chip { + display: flex; + align-items: center; + gap: 10px; + margin-top: 14px; + padding: 11px 14px; + border: 1px dashed var(--border); + border-radius: 12px; + color: var(--text-dim); + font-size: 12.5px; + line-height: 1.6; +} + +.badge-chip img { flex: none; border-radius: 5px; } + +.file-chips { + list-style: none; + display: flex; + flex-wrap: wrap; + gap: 10px; + padding: 0; + margin: 40px 0 0; +} + +.chip { + font-family: ui-monospace, "SFMono-Regular", Consolas, monospace; + font-size: 12px; + padding: 6px 13px; + border-radius: 999px; + border: 1px solid var(--border); + background: var(--panel); + color: var(--text-dim); +} + +.chip-on { + color: var(--cyan); + border-color: color-mix(in srgb, var(--cyan) 38%, var(--border)); + background: color-mix(in srgb, var(--cyan) 9%, var(--panel)); +} + +.chip-off { border-style: dashed; font-family: inherit; } + +/* ---------- 截图 ---------- */ + +.shot { + margin: 0; + border: 1px solid var(--border); + border-radius: 14px; + overflow: hidden; + background: var(--panel); + box-shadow: var(--card-shadow); +} + +.shot img { + display: block; + width: 100%; + height: auto; +} + +.shot .zoomable { cursor: zoom-in; } + +.shot figcaption { + padding: 9px 14px; + font-size: 12px; + color: var(--text-dim); + border-top: 1px solid var(--border); + background: color-mix(in srgb, var(--panel) 90%, transparent); + line-height: 1.6; +} + +.shot-hero { position: relative; } + +/* ---------- 通用区块 ---------- */ + +.section { padding: 86px 0; } + +.section.alt { + background: var(--bg-2); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.section-head { max-width: 740px; margin-bottom: 42px; } + +.kicker { + font-size: 11.5px; + font-weight: 700; + letter-spacing: .2em; + color: var(--accent); +} + +.section h2 { + margin: 10px 0 12px; + font-size: clamp(1.6rem, 3vw, 2.15rem); + letter-spacing: -0.018em; +} + +.section-lead { + margin: 0; + color: var(--text-dim); + font-size: 15px; + line-height: 1.8; +} + +/* ---------- 功能特性 ---------- */ + +.features { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 16px; +} + +.feature-card { + padding: 22px; + border: 1px solid var(--border); + border-radius: 16px; + background: var(--panel); + transition: transform .18s, border-color .18s, box-shadow .18s; +} + +.feature-card:hover { + transform: translateY(-3px); + border-color: color-mix(in srgb, var(--accent) 46%, var(--border)); + box-shadow: var(--card-shadow); +} + +.f-icon { + width: 40px; + height: 40px; + display: grid; + place-items: center; + margin-bottom: 16px; + border-radius: 11px; + border: 1px solid var(--border); + background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 16%, var(--panel)), color-mix(in srgb, var(--cyan) 12%, var(--panel))); + color: var(--accent); +} + +html[data-theme="dark"] .f-icon { color: color-mix(in srgb, var(--accent) 80%, #fff); } + +.f-icon svg { + width: 20px; + height: 20px; + fill: none; + stroke: currentColor; + stroke-width: 1.7; + stroke-linecap: round; + stroke-linejoin: round; +} + +.feature-card h3 { margin: 0 0 9px; font-size: 16px; letter-spacing: -0.01em; } + +.feature-card p { + margin: 0; + color: var(--text-dim); + font-size: 13.8px; + line-height: 1.75; +} + +.chips { + list-style: none; + display: flex; + flex-wrap: wrap; + gap: 10px; + padding: 0; + margin: 26px 0 0; +} + +.chips li { + padding: 7px 14px; + border-radius: 999px; + border: 1px solid var(--border); + background: color-mix(in srgb, var(--panel) 80%, transparent); + color: var(--text-dim); + font-size: 12.5px; +} + +/* ---------- 实际界面 ---------- */ + +.crop-grid { + display: grid; + grid-template-columns: minmax(170px, 215px) 1fr; + gap: 16px; + align-items: start; +} + +.crop.toolbar { grid-column: 1 / -1; } + +.crop.animlist { grid-column: 1; } + +.crop.timeline { grid-column: 2; } + +.crop.animlist img { + display: block; + width: 100%; + max-width: 128px; + margin: 18px auto; + box-shadow: 0 6px 18px rgba(0, 0, 0, .35); + border-radius: 6px; +} + +.crop.toolbar img, .crop.timeline img { border-radius: 6px; } + +.demo-block { margin-top: 58px; } + +.demo-head h3 { margin: 0 0 8px; font-size: 19px; letter-spacing: -0.01em; } + +.demo-head p { margin: 0 0 20px; color: var(--text-dim); font-size: 14.5px; line-height: 1.75; max-width: 780px; } + +/* ---------- 查看器界面复刻(配色与 viewer/spine.html 一致) ---------- */ + +.viewer { + position: relative; + height: 560px; + overflow: hidden; + border: 1px solid var(--v-border); + border-radius: 14px; + background: var(--v-bg); + color: var(--v-text); + font-size: 13px; + box-shadow: var(--card-shadow); + user-select: none; + -webkit-user-select: none; + outline: none; + --v-bg: #1e1e1e; + --v-panel: #252526; + --v-panel-2: #2d2d30; + --v-text: #e6e6e6; + --v-dim: #9d9d9d; + --v-accent: #4fc1ff; + --v-border: #3c3c3c; +} + +html[data-theme="light"] .viewer { + --v-bg: #f3f4f6; + --v-panel: #ffffff; + --v-panel-2: #f0f0f0; + --v-text: #1f1f1f; + --v-dim: #6b6b6b; + --v-accent: #0078d4; + --v-border: #dcdcdc; +} + +.v-toolbar { + position: absolute; + top: 12px; + left: 12px; + right: 12px; + z-index: 10; + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + padding: 8px 12px; + border: 1px solid var(--v-border); + border-radius: 8px; + background: color-mix(in srgb, var(--v-panel) 97%, transparent); + box-shadow: 0 5px 18px rgba(0, 0, 0, .25); +} + +.v-field, .v-check { + display: inline-flex; + align-items: center; + gap: 4px; + color: var(--v-dim); + font-size: 12.5px; + white-space: nowrap; +} + +.v-check { cursor: pointer; } + +.v-field select { + background: var(--v-panel-2); + color: var(--v-text); + border: 1px solid var(--v-border); + border-radius: 4px; + padding: 4px 6px; + font-size: 12.5px; + font-family: inherit; +} + +.v-field input[type="range"] { width: 108px; accent-color: var(--v-accent); } + +.v-btn { + background: var(--v-panel-2); + color: var(--v-text); + border: 1px solid var(--v-border); + border-radius: 4px; + padding: 5px 10px; + font-size: 12.5px; + font-family: inherit; + cursor: pointer; + white-space: nowrap; + transition: background .15s; +} + +.v-btn:hover { background: var(--v-border); } + +.v-btn:disabled { opacity: .45; cursor: default; } + +.v-icon { padding: 5px 9px; } + +.v-spacer { flex: 1; } + +.v-version { color: var(--v-dim); font-size: 12px; white-space: nowrap; } + +.v-anim-panel { + position: absolute; + top: calc(22px + 46px); + left: 12px; + z-index: 9; + display: flex; + flex-direction: column; + width: max-content; + min-width: 128px; + max-width: min(260px, 34vw); + max-height: calc(100% - 46px - 68px - 56px); + overflow: hidden; + border: 1px solid var(--v-border); + border-radius: 7px; + background: color-mix(in srgb, var(--v-panel) 97%, transparent); + box-shadow: 0 5px 18px rgba(0, 0, 0, .28); +} + +.v-anim-title { + padding: 8px 10px; + color: var(--v-dim); + font-size: 12px; + border-bottom: 1px solid var(--v-border); + flex: none; +} + +.v-anim-list { + overflow: auto; + padding: 5px; + scrollbar-width: thin; + scrollbar-color: color-mix(in srgb, var(--v-dim) 58%, transparent) transparent; +} + +.v-anim-list::-webkit-scrollbar { width: 8px; height: 8px; } + +.v-anim-list::-webkit-scrollbar-thumb { + min-height: 28px; + border: 2px solid transparent; + border-radius: 999px; + background: color-mix(in srgb, var(--v-dim) 58%, transparent); + background-clip: padding-box; +} + +.v-anim-item { + display: block; + width: 100%; + min-width: 116px; + max-width: 248px; + padding: 6px 8px; + margin: 0 0 2px; + border: 0; + border-radius: 4px; + background: transparent; + color: var(--v-text); + font-size: 12.5px; + font-family: inherit; + text-align: left; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; +} + +.v-anim-item:hover { background: var(--v-panel-2); } + +.v-anim-item.active { + background: color-mix(in srgb, var(--v-accent) 20%, var(--v-panel)); + color: var(--v-accent); + box-shadow: inset 3px 0 0 var(--v-accent); +} + +.v-stage { position: absolute; inset: 0; overflow: hidden; cursor: grab; } + +.v-stage.dragging { cursor: grabbing; } + +.v-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; } + +.v-status { + position: absolute; + bottom: calc(22px + 68px); + left: 12px; + color: var(--v-dim); + font-size: 12px; + pointer-events: none; + opacity: 0; + transition: opacity .25s; + text-shadow: 0 1px 2px rgba(0, 0, 0, .3); +} + +.v-status.show { opacity: 1; } + +.v-timeline { + position: absolute; + left: 12px; + right: 12px; + bottom: 12px; + z-index: 10; + display: flex; + align-items: center; + gap: 10px; + padding: 6px 12px; + border: 1px solid var(--v-border); + border-radius: 8px; + background: color-mix(in srgb, var(--v-panel) 97%, transparent); + box-shadow: 0 -4px 18px rgba(0, 0, 0, .22); +} + +.v-tl-labels { + display: flex; + flex-direction: column; + justify-content: space-between; + align-self: stretch; + min-width: 136px; + padding: 8px 0 1px; +} + +.v-tl-label { color: var(--v-dim); font-size: 12px; white-space: nowrap; } + +.v-tl-legend { + display: flex; + align-items: center; + gap: 6px; + color: var(--v-dim); + font-size: 11px; + white-space: nowrap; + cursor: help; +} + +.v-tl-legend::before { + content: ""; + width: 10px; + height: 7px; + border-radius: 1px; + background: var(--v-accent); + opacity: .7; +} + +.v-track { position: relative; flex: 1; padding: 20px 0 0; min-width: 0; } + +.v-track input[type="range"] { + -webkit-appearance: none; + appearance: none; + display: block; + width: 100%; + height: 16px; + margin: 0; + background: transparent; + cursor: pointer; +} + +.v-track input[type="range"]::-webkit-slider-runnable-track { + height: 4px; + border-radius: 2px; + background: color-mix(in srgb, var(--v-dim) 38%, transparent); +} + +.v-track input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 14px; + height: 14px; + margin-top: -5px; + border: 0; + border-radius: 50%; + background: var(--v-accent); + box-shadow: 0 0 0 4px color-mix(in srgb, var(--v-accent) 22%, transparent); +} + +.v-track input[type="range"]::-moz-range-track { + height: 4px; + border-radius: 2px; + background: color-mix(in srgb, var(--v-dim) 38%, transparent); +} + +.v-track input[type="range"]::-moz-range-thumb { + width: 14px; + height: 14px; + border: 0; + border-radius: 50%; + background: var(--v-accent); +} + +.v-track input[type="range"]:disabled { opacity: .45; cursor: default; } + +.v-ruler { position: absolute; top: 0; left: 7px; right: 7px; height: 19px; } + +.v-ruler .tick { + position: absolute; + bottom: 0; + width: 1px; + height: 5px; + background: var(--v-border); + transform: translateX(-.5px); +} + +.v-ruler .tick.major { height: 9px; background: var(--v-dim); } + +.v-ruler .tick-label { + position: absolute; + bottom: 8px; + color: var(--v-dim); + font-size: 10px; + font-variant-numeric: tabular-nums; + transform: translateX(-50%); + white-space: nowrap; +} + +.v-ruler .tick-label.first { transform: none; } + +.v-ruler .tick-label.last { transform: translateX(-100%); } + +.v-keys { position: relative; height: 8px; margin-top: 2px; } + +.v-keys span { + position: absolute; + top: 0; + width: 3px; + height: 8px; + background: var(--v-accent); + opacity: .62; + transform: translateX(-1.5px); + cursor: help; + transition: opacity .12s, transform .12s; +} + +.v-keys span:hover { opacity: 1; transform: translateX(-1.5px) scaleY(1.35); } + +.v-readout { + color: var(--v-dim); + font-size: 12px; + min-width: 178px; + font-variant-numeric: tabular-nums; + white-space: nowrap; + text-align: right; +} + +.demo-hint { + margin: 14px 0 0; + text-align: center; + color: var(--text-dim); + font-size: 12.5px; +} + +/* ---------- 支持版本 ---------- */ + +.v-chips { + list-style: none; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + padding: 0; + margin: 0 0 28px; +} + +.v-chips li { + padding: 8px 18px; + border: 1px solid var(--border); + border-radius: 11px; + background: var(--panel); + font-weight: 600; + font-size: 14px; + font-variant-numeric: tabular-nums; +} + +.v-chips li.sep { border: 0; background: none; color: var(--text-dim); padding: 0; font-weight: 400; } + +.v-table-wrap { + overflow-x: auto; + border: 1px solid var(--border); + border-radius: 14px; + background: var(--panel); +} + +.v-table { width: 100%; min-width: 660px; border-collapse: collapse; font-size: 13.5px; } + +.v-table th { + text-align: left; + padding: 13px 18px; + font-size: 11.5px; + font-weight: 600; + letter-spacing: .1em; + color: var(--text-dim); + background: color-mix(in srgb, var(--panel-2) 70%, var(--panel)); + border-bottom: 1px solid var(--border); +} + +.v-table td { + padding: 15px 18px; + border-bottom: 1px solid var(--border); + line-height: 1.7; + vertical-align: top; + color: var(--text); +} + +.v-table tr:last-child td { border-bottom: 0; } + +.v-table td:first-child { white-space: nowrap; } + +.v-note { margin: 14px 0 0; color: var(--text-dim); font-size: 13px; } + +/* ---------- 工作流程 ---------- */ + +.steps { + list-style: none; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 16px; + padding: 0; + margin: 0; +} + +.step { + padding: 22px; + border: 1px solid var(--border); + border-radius: 16px; + background: var(--panel); + position: relative; +} + +.step-num { font-size: 12px; font-weight: 700; letter-spacing: .14em; color: var(--accent); } + +.step h3 { margin: 12px 0 8px; font-size: 15.5px; } + +.step p { margin: 0; color: var(--text-dim); font-size: 13.5px; line-height: 1.75; } + +/* ---------- 安装使用 ---------- */ + +.dl-cta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + flex-wrap: wrap; + padding: 22px 24px; + border: 1px solid var(--border); + border-radius: 16px; + background: var(--panel); + text-decoration: none; + color: var(--text); + transition: transform .18s, border-color .18s, box-shadow .18s; +} + +.dl-cta:hover { + transform: translateY(-3px); + border-color: color-mix(in srgb, var(--cyan) 50%, var(--border)); + box-shadow: var(--card-shadow); +} + +.dl-cta-info { display: flex; flex-direction: column; gap: 7px; min-width: 0; } + +.dl-cta strong { font-size: 16px; letter-spacing: -0.01em; } + +.dl-os { font-size: 12px; font-weight: 700; letter-spacing: .06em; color: var(--cyan); } + +.dl-meta { font-size: 12.5px; color: var(--text-dim); } + +.dl-note { margin: 16px 0 0; color: var(--text-dim); font-size: 12.5px; } + +.install-steps { + list-style: none; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 16px; + padding: 0; + margin: 34px 0 0; +} + +.install-steps li { + padding: 20px; + border: 1px dashed var(--border); + border-radius: 14px; + background: color-mix(in srgb, var(--panel) 72%, transparent); +} + +.install-steps h3 { margin: 0 0 8px; font-size: 14.5px; } + +.install-steps p { margin: 0; color: var(--text-dim); font-size: 13px; line-height: 1.75; } + +.callout { + margin-top: 26px; + padding: 18px 20px; + border: 1px solid color-mix(in srgb, var(--cyan) 32%, var(--border)); + border-radius: 14px; + background: color-mix(in srgb, var(--cyan) 7%, var(--panel)); +} + +.callout strong { display: block; margin-bottom: 6px; font-size: 14px; } + +.callout p { margin: 0; color: var(--text-dim); font-size: 13.5px; line-height: 1.75; } + +/* ---------- 常见问题 ---------- */ + +.faq { display: grid; gap: 12px; max-width: 880px; } + +.faq details { + border: 1px solid var(--border); + border-radius: 14px; + background: var(--panel); + padding: 2px 20px; + transition: border-color .2s; +} + +.faq details[open] { border-color: color-mix(in srgb, var(--accent) 38%, var(--border)); } + +.faq summary { + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; + padding: 16px 0; + font-size: 14.5px; + font-weight: 600; + cursor: pointer; + list-style: none; +} + +.faq summary::-webkit-details-marker { display: none; } + +.faq summary::after { + content: "+"; + font-size: 19px; + font-weight: 400; + color: var(--accent); + transition: transform .2s; + flex: none; +} + +.faq details[open] summary::after { transform: rotate(45deg); } + +.faq details p { margin: 0 0 18px; color: var(--text-dim); font-size: 13.5px; line-height: 1.8; } + +.faq-contact { margin: 20px 0 0; color: var(--text-dim); font-size: 14px; } + +.faq-contact a { + color: var(--cyan); + font-weight: 600; + text-decoration: none; +} + +.faq-contact a:hover { text-decoration: underline; } + +/* ---------- 页脚 ---------- */ + +.footer { + border-top: 1px solid var(--border); + background: var(--bg-2); + padding: 40px 0 46px; +} + +.footer-inner { display: flex; align-items: center; } + +.foot-brand { display: flex; align-items: center; gap: 12px; } + +.foot-brand img { border-radius: 9px; } + +.foot-brand strong { display: block; font-size: 15px; } + +.foot-brand span { color: var(--text-dim); font-size: 12.5px; } + +/* ---------- 图片放大 ---------- */ + +.lightbox { + position: fixed; + inset: 0; + z-index: 100; + display: grid; + place-items: center; + padding: 4vmin; + background: rgba(8, 8, 11, .92); + cursor: zoom-out; + animation: fade .18s ease-out; +} + +.lightbox[hidden] { display: none; } + +.lightbox img { + max-width: 94vw; + max-height: 90vh; + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, .18); + box-shadow: 0 34px 90px rgba(0, 0, 0, .6); +} + +@keyframes fade { from { opacity: 0; } to { opacity: 1; } } + +/* ---------- 滚动出现 ---------- */ + +.reveal { + opacity: 0; + transform: translateY(16px); + transition: opacity .55s ease, transform .55s ease; +} + +.reveal.visible { opacity: 1; transform: none; } + +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + .reveal { opacity: 1; transform: none; transition: none; } + .pill .dot { animation: none; } +} + +/* ---------- 响应式 ---------- */ + +@media (max-width: 1020px) { + .hero-grid { grid-template-columns: 1fr; gap: 36px; } + .crop-grid { grid-template-columns: 1fr; } + .crop.toolbar, .crop.animlist, .crop.timeline { grid-column: 1; } + .crop.animlist img { max-width: 132px; } +} + +@media (max-width: 880px) { + .nav { display: none; } + .topbar-actions { margin-left: auto; } + .section { padding: 64px 0; } + .viewer { height: 540px; } +} + +@media (max-width: 720px) { + .hero { padding-top: 52px; } + .v-toolbar { top: 8px; left: 8px; right: 8px; gap: 8px; padding: 8px 10px; } + .v-anim-panel { + top: 152px; + left: 8px; + max-height: calc(100% - 152px - 96px); + } + .v-timeline { left: 8px; right: 8px; bottom: 8px; gap: 8px; padding: 6px 10px; } + .v-tl-labels { min-width: 104px; } + .v-readout { font-size: 11px; } + .v-version { display: none; } +} + +@media (max-width: 520px) { + .wrap { padding: 0 16px; } + .stats { grid-template-columns: 1fr; gap: 10px; } + .brand-ver { display: none; } + .viewer { height: 520px; } + .v-tl-labels { min-width: 96px; } + .v-tl-legend { font-size: 10px; } + .v-readout { display: none; } +} + +/* ---------- SpineThumbnails 专属区块 ---------- */ + +.safety-band { + padding: 52px 0; + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + background: + linear-gradient(180deg, color-mix(in srgb, var(--panel) 72%, transparent), color-mix(in srgb, var(--bg-2) 94%, transparent)), + var(--bg-2); +} + +.safety-head { + display: grid; + grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); + column-gap: 48px; + align-items: end; + margin-bottom: 24px; +} + +.safety-head .kicker { grid-column: 1; } + +.safety-head h2 { + margin: 8px 0 0; + grid-column: 1; + font-size: clamp(1.45rem, 2.4vw, 1.9rem); + letter-spacing: -.015em; +} + +.safety-head p { + margin: 0 0 4px; + grid-column: 2; + grid-row: 1 / span 2; + color: var(--text-dim); + font-size: 14px; + line-height: 1.8; +} + +.safety-grid { + list-style: none; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + padding: 0; + margin: 0; +} + +.safety-grid li { + position: relative; + padding: 20px 20px 19px 58px; + border: 1px solid var(--border); + border-radius: 14px; + background: color-mix(in srgb, var(--panel) 86%, transparent); +} + +.safety-mark { + position: absolute; + left: 18px; + top: 19px; + display: grid; + place-items: center; + width: 26px; + height: 26px; + border-radius: 8px; + background: color-mix(in srgb, var(--accent) 14%, var(--panel)); + color: var(--accent); + font-size: 10px; + font-weight: 800; + letter-spacing: .08em; +} + +.safety-grid strong { + display: block; + margin-bottom: 6px; + font-size: 14px; +} + +.safety-grid p { + margin: 0; + color: var(--text-dim); + font-size: 12.8px; + line-height: 1.7; +} + +.mode-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 18px; +} + +.mode-card { + overflow: hidden; + border: 1px solid var(--border); + border-radius: 18px; + background: var(--panel); + box-shadow: var(--card-shadow); +} + +.mode-visual { + position: relative; + height: 190px; + overflow: hidden; + border-bottom: 1px solid var(--border); + background: + linear-gradient(130deg, color-mix(in srgb, var(--accent) 15%, var(--panel-2)), transparent 62%), + radial-gradient(240px 180px at 78% 22%, color-mix(in srgb, var(--cyan) 15%, transparent), transparent 70%), + var(--panel-2); +} + +.mode-visual::before { + content: ""; + position: absolute; + inset: 0; + opacity: .32; + background-image: + linear-gradient(color-mix(in srgb, var(--text-dim) 12%, transparent) 1px, transparent 1px), + linear-gradient(90deg, color-mix(in srgb, var(--text-dim) 12%, transparent) 1px, transparent 1px); + background-size: 28px 28px; + mask-image: linear-gradient(to bottom right, #000, transparent 78%); +} + +.pose-ring { + position: absolute; + left: 50%; + top: 50%; + width: 112px; + height: 112px; + border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent); + border-radius: 50%; + transform: translate(-50%, -50%); + box-shadow: 0 0 44px color-mix(in srgb, var(--accent) 18%, transparent); +} + +.pose-bone { + position: absolute; + left: 50%; + top: 50%; + height: 7px; + width: 138px; + border-radius: 999px; + background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent-2) 75%, #fff)); + transform-origin: 12% 50%; + box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 35%, transparent); +} + +.pose-bone::before, +.pose-bone::after { + content: ""; + position: absolute; + top: 50%; + width: 18px; + height: 18px; + border-radius: 50%; + border: 5px solid var(--panel); + background: #fff; + transform: translateY(-50%); + box-shadow: 0 2px 10px rgba(0, 0, 0, .28); +} + +.pose-bone::before { left: -8px; } +.pose-bone::after { right: -8px; } +.pose-bone.b1 { transform: translate(-46px, -48px) rotate(24deg); } +.pose-bone.b2 { transform: translate(-18px, 3px) rotate(-28deg); } +.pose-bone.b3 { transform: translate(-56px, -21px) rotate(67deg); } + +.motion-line { + position: absolute; + left: 18%; + right: 18%; + top: 50%; + height: 2px; + transform: rotate(-9deg); + background: linear-gradient(90deg, transparent, var(--cyan), transparent); + opacity: .7; +} + +.motion-dot { + position: absolute; + width: 58px; + height: 58px; + border-radius: 17px; + border: 1px solid color-mix(in srgb, var(--cyan) 45%, var(--border)); + background: color-mix(in srgb, var(--panel) 86%, transparent); + box-shadow: 0 12px 30px rgba(0, 0, 0, .28); +} + +.motion-dot::after { + content: ""; + position: absolute; + left: 13px; + top: 14px; + width: 28px; + height: 28px; + border-radius: 8px; + background: linear-gradient(135deg, var(--accent), var(--accent-2)); + box-shadow: inset 0 0 0 6px rgba(255, 255, 255, .12); +} + +.motion-dot.d1 { left: 18%; top: 24px; transform: rotate(-14deg) scale(.72); opacity: .45; } +.motion-dot.d2 { left: 42%; top: 64px; transform: rotate(6deg); } +.motion-dot.d3 { right: 18%; top: 34px; transform: rotate(16deg) scale(.78); opacity: .55; } + +.mode-file { + position: absolute; + right: 16px; + bottom: 14px; + padding: 5px 10px; + border: 1px solid color-mix(in srgb, var(--cyan) 42%, var(--border)); + border-radius: 999px; + background: color-mix(in srgb, var(--panel) 86%, transparent); + color: var(--cyan); + font: 700 10.5px/1.4 ui-monospace, "SFMono-Regular", Consolas, monospace; + letter-spacing: .12em; +} + +.mode-copy { padding: 24px; } + +.mode-label { + color: var(--accent); + font-size: 10.5px; + font-weight: 800; + letter-spacing: .18em; +} + +.mode-copy h3 { + margin: 8px 0 10px; + font-size: 19px; + letter-spacing: -.01em; +} + +.mode-copy p { + margin: 0; + color: var(--text-dim); + font-size: 13.7px; + line-height: 1.78; +} + +.mode-copy ul { + list-style: none; + display: flex; + flex-wrap: wrap; + gap: 8px; + padding: 0; + margin: 18px 0 0; +} + +.mode-copy li { + padding: 5px 10px; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--panel-2); + color: var(--text-dim); + font-size: 11.5px; +} + +@media (max-width: 880px) { + .safety-head { + display: block; + } + + .safety-head p { + margin-top: 10px; + max-width: 680px; + } + + .safety-grid, + .mode-grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 520px) { + .safety-band { padding: 42px 0; } + .safety-grid li { padding: 18px 18px 18px 54px; } + .mode-visual { height: 170px; } + .mode-copy { padding: 20px; } +}