feat: 发布三笙AI情报局独立版公司研发基线
同步家纺情报 v2 数据、59 个严格权威源、趋势图库、移动端交互、Google/Yandex 翻译门控及静态 SEO/GEO 构建。 补充面向 C# 研发的 README,明确当前无 LLM、多模态与生图模型,记录翻译请求参数、缓存与失败策略、数据处理边界、前端职责和无 GitHub Pages 部署流程。 新增按日期倒序维护的 CHANGELOG,记录影响、验证与代码/数据/dist 回滚方法。 验证:11 个 Python 契约测试、13 个 Node 前端测试通过;静态构建生成 1096 个 Sitemap URL。
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
|||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.pytest_cache/
|
||||||
|
node_modules/
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
dist/
|
||||||
|
runtime/snapshots/
|
||||||
|
runtime/update-*/
|
||||||
|
runtime/test-dist/
|
||||||
|
runtime/.dist-next/
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# 更新日志
|
||||||
|
|
||||||
|
本文件按日期倒序记录独立版的代码、数据、交互和部署变化。每次提交必须先更新本文件,确保公司研发人员可以判断影响范围并使用 `git revert <commit>` 回滚。
|
||||||
|
|
||||||
|
## 2026-08-14 - 公司 Git 首次发布基线
|
||||||
|
|
||||||
|
### 新增
|
||||||
|
|
||||||
|
- 补齐三笙AI情报局独立版的公司研发交接说明,明确当前没有 LLM、多模态理解、生图模型、提示词模板和用户内容模型审核。
|
||||||
|
- 记录 Google 公共文本翻译请求的固定参数、唯一变量、缓存命中、单次调用上限和失败保留策略。
|
||||||
|
- 记录中国大陆使用 Yandex、海外使用 Google、未知地区按语种/时区回退,以及特殊阻断域名的网页翻译门控。
|
||||||
|
- 增加本更新日志并定义每次提交的日期、影响、验证和回滚要求。
|
||||||
|
- 增加本地东观体粗体字库,只在品牌 Banner 和谨慎选择的内容标题使用;正文继续使用系统中文字体栈。
|
||||||
|
|
||||||
|
### 数据与业务逻辑
|
||||||
|
|
||||||
|
- 数据结构保持 v2,当前严格权威源为 59/59;基准日为 2026-08-14。
|
||||||
|
- 今日必看改为从日历、展会、政策、活动和趋势中混合智能排序,不再遗漏趋势雷达的可行动内容。
|
||||||
|
- 日历按规范化节日名、日期和地区聚合,修复圣母无染原罪节、圣斯蒂芬节和跨年夜等重复;当地称呼折叠为英文名和国家数摘要。
|
||||||
|
- 删除前台不可靠的“家纺成熟度”“新兴参考”标签,仅保留内部排序价值。
|
||||||
|
- 修正 Intertextile 上海家纺展官方报名入口、雨果跨境活动详情链接和中国贸促会中文活动页的翻译判断。
|
||||||
|
- 对 V&A 泛化标题进行藏品编号化处理,避免 `Hanging`、`Pattern` 等条目在界面上看似重复;清理错误中文标题和问号乱码。
|
||||||
|
- 明确趋势图库条目按稳定 ID、来源 URL 和藏品信息去重,保留真正不同的原图。
|
||||||
|
|
||||||
|
### UI 与移动端
|
||||||
|
|
||||||
|
- 独立站内容宽度、卡片密度、筛选区和标题字体策略与主站家纺情报保持一致,避免桌面端无边界全宽展示。
|
||||||
|
- 权威源数量等更新细节默认折叠为一行更新时间,减少老板用户不关心的首屏信息。
|
||||||
|
- 跨境活动焦点筛选改为同一行,地区、平台和参与方式在空间足够时保持三列,窄屏自动换行。
|
||||||
|
- 活动倒计时使用日历式月份、日期和剩余天数样式。
|
||||||
|
- 灵感图库支持原图浮层、三笙 Logo 旋转加载动画、关闭和下载图片;加载失败时保留明确状态。
|
||||||
|
- 优化分享、明暗主题按钮、外链顺序、移动端触控尺寸和标题字体范围。
|
||||||
|
|
||||||
|
### SEO/GEO 与部署
|
||||||
|
|
||||||
|
- 生成栏目页、年份日历页和每条情报详情页,并输出 canonical、hreflang、Open Graph、JSON-LD、Sitemap、robots.txt 和 `llms.txt`。
|
||||||
|
- 统一“三笙AI情报局 / 三笙AI”品牌实体和家纺AI、家纺情报、跨境家纺平台等主题词边界。
|
||||||
|
- 构建只公开 `textile-intelligence.json` 与 `textile-trends.json`;翻译缓存、源状态、运行快照和日志不进入 `dist/`。
|
||||||
|
- 明确无需 GitHub Pages:Gitea Runner、Windows 计划任务或公司 CI 构建后,把 `dist/` 原子发布到 IIS/Nginx/对象存储即可。
|
||||||
|
|
||||||
|
### 验证
|
||||||
|
|
||||||
|
- `python -m unittest discover -s tests -p 'test_*.py'`
|
||||||
|
- `node tests\test_frontend.mjs`
|
||||||
|
- `python scripts\build_site.py --site-url http://127.0.0.1:8765`
|
||||||
|
- 发布前再次核对 59/59 严格源、两份公开 JSON、Sitemap、`llms.txt` 和移动端页面。
|
||||||
|
|
||||||
|
### 回滚说明
|
||||||
|
|
||||||
|
- 代码回滚:在公司仓库执行 `git revert <本次提交哈希>`,再重新构建并发布 `dist/`。
|
||||||
|
- 数据回滚:代码与 `data/*.json` 必须回到同一提交,避免旧渲染器读取新字段;运行环境也可从 `runtime/snapshots/` 恢复上一份成功 JSON。
|
||||||
|
- 站点回滚:保留上一版完整 `dist/` 目录或发布槽,健康检查失败时整体切回,禁止逐文件覆盖。
|
||||||
|
|
||||||
|
## 来源项目历史
|
||||||
|
|
||||||
|
### 2026-08-13 - 完善翻译与趋势体验
|
||||||
|
|
||||||
|
- 来源主项目提交:`e4e0b798`。
|
||||||
|
- 增强 IP 区域判断、翻译入口、趋势展示和前端数据契约测试。
|
||||||
|
- 该提交属于源项目历史,不是公司仓库可直接回滚的提交;公司仓库以 2026-08-14 基线为起点。
|
||||||
|
|
||||||
|
### 2026-08-13 - 拆分独立站
|
||||||
|
|
||||||
|
- 来源主项目提交:`e66a468c`。
|
||||||
|
- 从 AI-News-Radar 主线拆出静态前端、家纺数据、采集脚本、SEO 构建、Windows 启动/计划任务和交接文档。
|
||||||
|
- 该提交属于源项目历史,不是公司仓库可直接回滚的提交。
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
# 三笙AI情报局独立版
|
||||||
|
|
||||||
|
三笙AI情报局是面向家纺、服装和跨境电商经营者的静态情报站参考实现。本仓库从 `AI-News-Radar` 主项目中独立出来,供公司 C# 后端研发、前端研发、测试和运维人员理解现有业务,再重构为长期稳定版本。
|
||||||
|
|
||||||
|
> 先明确边界:仓库名称中包含“AI”,但当前版本 **没有调用任何 LLM、多模态理解模型或生图模型**。没有 Qwen、Gemini、OpenAI 等模型请求,没有提示词模板,也没有“先让文本模型理解用户输入,再调用生图模型”的两阶段链路。现有智能能力来自一手信源抓取、规则解析、结构化计算、去重排序、公共机器翻译和静态 SEO/GEO 生成。
|
||||||
|
|
||||||
|
## 当前基线
|
||||||
|
|
||||||
|
当前提交数据以 `data/*.json` 为准,业务基准日为 **2026-08-14**:
|
||||||
|
|
||||||
|
| 指标 | 当前值 |
|
||||||
|
|---|---:|
|
||||||
|
| 严格权威源 | 59/59 |
|
||||||
|
| 日历原始事件 / 聚合机会 | 1270 / 673 |
|
||||||
|
| 今日必看 | 23 |
|
||||||
|
| 展会 | 79 |
|
||||||
|
| 政策与召回 | 48 |
|
||||||
|
| 标准事实 | 4 |
|
||||||
|
| 跨境平台 | 28 |
|
||||||
|
| 跨境活动 | 48 |
|
||||||
|
| 趋势与灵感内容 | 206 |
|
||||||
|
|
||||||
|
这些数字是可回归的仓库快照,不是写死在页面里的宣传数字。每次数据更新后,应以 `textile-intelligence.json.summary`、`source_target/source_success` 和 `textile-trends.json.total_items` 重新核对。
|
||||||
|
|
||||||
|
## 五分钟理解系统
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A[政府/平台/展会/博物馆等公开来源] --> B[Python 定时抓取]
|
||||||
|
B --> C[证据词、状态码、语种和结构校验]
|
||||||
|
C --> D[规则解析、规范化、聚合、去重和排序]
|
||||||
|
D --> E[命中缓存或调用 Google 公共翻译接口]
|
||||||
|
E --> F[生成两份公开 JSON]
|
||||||
|
F --> G[生成首页、详情页、栏目页、Sitemap、JSON-LD、llms.txt]
|
||||||
|
G --> H[原子替换 dist]
|
||||||
|
H --> I[IIS/Nginx/对象存储/CDN 只提供静态文件]
|
||||||
|
```
|
||||||
|
|
||||||
|
生产访问端不需要 Python、Node、数据库、模型服务或 GitHub Pages。Python 只运行在更新节点;最终仅发布 `dist/`。
|
||||||
|
|
||||||
|
## 核心功能
|
||||||
|
|
||||||
|
| 功能 | 用户看到的结果 | 当前实现 |
|
||||||
|
|---|---|---|
|
||||||
|
| 今日必看 | 混合展示备货、展会、政策、活动和趋势任务 | 规则评分、截止日期、经营相关度和风险排序 |
|
||||||
|
| 备货日历 | 节日、国家、备货窗口、产品建议、平台动作 | 多来源日历规范化后按日期、名称和地区聚合 |
|
||||||
|
| 展会通 | 展期、城市、主办方、官方报名和译文入口 | 固定官方源与动态目录合并,优先保留官方报名页 |
|
||||||
|
| 政策预警 | 关税、召回、标签、知识产权和平台规则 | 权威来源证据校验,事实与经营建议分区 |
|
||||||
|
| 跨境活动 | 线上/线下活动、倒计时、报名入口和筛选 | 官方活动优先,行业媒体只承担发现作用 |
|
||||||
|
| 平台渠道 | 市场、品类、卖家准入和官方入驻入口 | 静态核验目录与信源状态组合 |
|
||||||
|
| 趋势雷达 | 趋势文章、灵感图库、时装趋势和原图查看 | RSS/HTML/博物馆公开 API,URL 与标题规则去重 |
|
||||||
|
| SEO/GEO | 可直接索引的中文正文和稳定实体页面 | 静态 HTML、canonical、JSON-LD、Sitemap、robots、llms.txt |
|
||||||
|
|
||||||
|
## AI、模型与渠道清单
|
||||||
|
|
||||||
|
### 当前没有的模型链路
|
||||||
|
|
||||||
|
| 能力 | 当前状态 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| LLM 文本理解 | 未接入 | 不调用 Qwen、Gemini、OpenAI 或其他大语言模型 |
|
||||||
|
| 多模态图片理解 | 未接入 | 不把用户图片或源站图片发送给视觉模型 |
|
||||||
|
| 文生图/图生图 | 未接入 | 灵感图库图片来自公开博物馆或来源站;活动无图时使用 CSS 文字海报 |
|
||||||
|
| 提示词拼接 | 不存在 | 没有 system/user prompt、提示词变量或模型输出 JSON |
|
||||||
|
| 用户内容实时模型审核 | 不存在 | 当前站点没有用户投稿、聊天或生图输入 |
|
||||||
|
|
||||||
|
因此,C# 重构时不要创建“模型编排服务”、提示词数据库或生图任务队列来复刻当前功能。以后若产品明确加入模型能力,应作为独立版本设计,不能把未来方案写成当前依赖。
|
||||||
|
|
||||||
|
### 当前唯一的机器翻译请求
|
||||||
|
|
||||||
|
构建节点会对部分外文标题和摘要执行一次普通 HTTP 翻译请求。它不是 LLM,也不是生图模型:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET https://translate.googleapis.com/translate_a/single
|
||||||
|
client=gtx
|
||||||
|
sl=auto
|
||||||
|
tl=zh-CN
|
||||||
|
dt=t
|
||||||
|
q={规范化后的原文标题或摘要}
|
||||||
|
```
|
||||||
|
|
||||||
|
变量只有 `q`;`sl` 固定为自动识别,`tl` 固定为简体中文。返回数组中每个翻译片段的首字段会按顺序拼接为中文。调用前先以完整原文字符串查询 `data/textile-zh-cache.json`,命中则不请求;未命中才请求,并限制每次任务的新翻译数量:
|
||||||
|
|
||||||
|
| 内容 | 单次最多新增翻译 |
|
||||||
|
|---|---:|
|
||||||
|
| 趋势标题与摘要 | 250 |
|
||||||
|
| 日历标题 | 260 |
|
||||||
|
| 展会标题与摘要 | 200 |
|
||||||
|
| 政策标题/摘要 | 72 |
|
||||||
|
| 活动标题 | 72 |
|
||||||
|
|
||||||
|
请求失败时保留缓存中的上一版中文或官方原文,不会把线上字段清空。该 `client=gtx` 公共端点没有项目 API Key 和商业 SLA;稳定版若要求服务等级、配额和合规审计,应由公司统一替换为正式采购的翻译服务,但必须保持“缓存优先、失败保留上一版、官方原文可访问”的语义。
|
||||||
|
|
||||||
|
### 网页译文入口
|
||||||
|
|
||||||
|
网页翻译按钮只生成跳转 URL,不抓取也不保存整页译文:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Google: https://translate.google.com/translate?sl=auto&tl=zh-CN&u={URL 编码后的官网地址}
|
||||||
|
Yandex: https://translate.yandex.com/translate?url={URL 编码后的官网地址}&lang={源语种}-zh
|
||||||
|
```
|
||||||
|
|
||||||
|
处理规则:
|
||||||
|
|
||||||
|
- 简体中文正文、`.cn` 域名、`bizevent.ccpit.org` 等已知中文页面不显示译文按钮。
|
||||||
|
- 中国大陆 IP 默认使用 Yandex;明确的非中国 IP 默认使用 Google,并以另一渠道为备用。
|
||||||
|
- IP 依次通过 Cloudflare trace、`country.is`、`ipwho.is` 判断;全部失败后再参考浏览器语种和时区。
|
||||||
|
- `cpsc.gov`、`zatca.gov.sa` 等已验证不支持 Google 网页代理的域名只提供 Yandex。
|
||||||
|
- `abai.kgd.gov.kz` 已验证两边都不可用,只保留本站中文摘要和官方原文。
|
||||||
|
- 官方来源/报名按钮始终优先于译文按钮;报名、付款、验证码和资料提交必须回官方域名。
|
||||||
|
|
||||||
|
## 数据请求与处理流程
|
||||||
|
|
||||||
|
### 1. 输入
|
||||||
|
|
||||||
|
系统输入不是用户提示词,而是以下公开数据:
|
||||||
|
|
||||||
|
- 政府、海关、监管机构和标准组织的 HTML、JSON、RSS。
|
||||||
|
- 平台、展会和主办方官网的页面与公开接口。
|
||||||
|
- Met、V&A 等博物馆的公开藏品信息和图片地址。
|
||||||
|
- 已人工登记的信源元数据:ID、栏目、地区、URL、证据词、中文说明和经营动作。
|
||||||
|
|
||||||
|
### 2. 抓取前处理
|
||||||
|
|
||||||
|
- 固定浏览器 User-Agent、语言头、连接/读取超时和有限重试。
|
||||||
|
- 规范化 URL、文本空白、日期、地区、平台和节日名称。
|
||||||
|
- 对已知证书兼容问题只在指定域名使用兼容适配器,禁止全局关闭 TLS 校验。
|
||||||
|
- 动态 API Key 只从目标官网公开前端配置中提取并立即用于同站请求,不在仓库保存密钥。
|
||||||
|
|
||||||
|
### 3. 抓取后校验
|
||||||
|
|
||||||
|
- 同时检查 HTTP 状态、内容类型、最终 URL、正文长度和登记的证据词;HTTP 200 不等于成功。
|
||||||
|
- 为响应正文计算内容指纹,记录 `verified_at`、`content_hash` 和变更状态。
|
||||||
|
- 严格源任一失败时,`--strict` 更新直接退出,正式 JSON 和 `dist/` 不被半成品覆盖。
|
||||||
|
- 活动发现源必须回到主办方或平台官方报名页;行业媒体页不能冒充官方来源。
|
||||||
|
|
||||||
|
### 4. 结构化、去重和排序
|
||||||
|
|
||||||
|
- 日历:规范化节日名、日期和地区后聚合;当地名称折叠为辅助信息。
|
||||||
|
- 展会:规范化展名、开始日和城市;官方固定源覆盖动态目录的弱字段。
|
||||||
|
- 活动:以真实报名 URL、标题、日期和地区去重;中文站不生成翻译入口。
|
||||||
|
- 趋势:先按 URL 去重,再按稳定 ID、标题和来源处理;V&A 泛化标题会加入藏品编号,避免多个 `Hanging/Pattern` 被误认为相同内容。
|
||||||
|
- 今日必看:从各栏目混合选取可行动事项,按截止日期、经营相关性、影响和风险排序。
|
||||||
|
|
||||||
|
### 5. 发布
|
||||||
|
|
||||||
|
`scripts/update_all.py` 在 `runtime/update-*` 临时目录完成抓取、翻译、JSON 校验和站点预构建。只有全部成功后才替换正式数据,并把旧四份 JSON 压缩到 `runtime/snapshots/`。快照最多 14 份、总计不超过 120 MiB。
|
||||||
|
|
||||||
|
`scripts/build_site.py` 仅把以下运行数据复制到公开目录:
|
||||||
|
|
||||||
|
- `dist/data/textile-intelligence.json`
|
||||||
|
- `dist/data/textile-trends.json`
|
||||||
|
|
||||||
|
翻译缓存、源状态、日志和快照不会进入 `dist/`。
|
||||||
|
|
||||||
|
## 审核、预处理和后处理边界
|
||||||
|
|
||||||
|
当前没有用户生成内容,所以没有实时内容安全审核接口。现有“审核”是数据质量审核,不是模型审核:
|
||||||
|
|
||||||
|
- 信源必须预登记并通过证据词和权威层级验证。
|
||||||
|
- 页面语种、日期、URL、地区和栏目在进入正式 JSON 前规范化。
|
||||||
|
- 付费墙、失效站点、二次转载和无来源图片按规则排除。
|
||||||
|
- 机器翻译、官方事实和本站经营建议分别标注,不能混写成官方结论。
|
||||||
|
- 前端不自行补造事实;缺字段时隐藏对应控件,不显示伪数据或占位按钮。
|
||||||
|
|
||||||
|
未来若加入搜索框自由文本、用户评论、文件上传或模型生图,才需要在 API 边界增加长度、格式、恶意 URL、版权、隐私和内容安全审核。该能力不属于当前版本。
|
||||||
|
|
||||||
|
## 前端必须保留的职责
|
||||||
|
|
||||||
|
即使后端改写为 C#,以下工作仍必须由前端完成:
|
||||||
|
|
||||||
|
- 七个业务入口、趋势子分类、搜索和地区/平台/参与方式筛选。
|
||||||
|
- IP 结果返回后选择 Google/Yandex 译文按钮;检测完成前不展示错误渠道。
|
||||||
|
- 官方来源和官方报名链接在译文入口左侧,所有外链新窗口打开并隔离 opener。
|
||||||
|
- 日历倒计时、活动状态、移动端单列布局和触控尺寸。
|
||||||
|
- 灵感图库原图浮层、三笙 Logo 加载动画、关闭/下载/键盘操作。
|
||||||
|
- 主题切换、分享、折叠的更新时间与源状态详情。
|
||||||
|
- 只消费公开 JSON;不得请求 `textile-zh-cache.json` 或源状态文件。
|
||||||
|
|
||||||
|
事实聚合、内容指纹、去重、业务评分和翻译缓存应留在更新服务或后端,不能散落到 UI 组件里。
|
||||||
|
|
||||||
|
## 目录与入口
|
||||||
|
|
||||||
|
```text
|
||||||
|
public/ 独立 HTML、CSS、ES Modules、本地字体、Logo 和平台图标
|
||||||
|
data/ 正式 JSON、源状态与中文翻译缓存
|
||||||
|
scripts/ 抓取、翻译、聚合、去重、SEO 和原子发布
|
||||||
|
docs/ 数据契约、信源、流水线、C# 交接、SEO/GEO 和运维说明
|
||||||
|
runtime/ 计划任务、临时目录和本地快照;不参与公开发布
|
||||||
|
dist/ 可直接部署的静态产物;构建生成,不提交版本库
|
||||||
|
tests/ Python 数据契约测试与 Node 前端契约测试
|
||||||
|
```
|
||||||
|
|
||||||
|
主要入口:
|
||||||
|
|
||||||
|
| 文件 | 职责 |
|
||||||
|
|---|---|
|
||||||
|
| `scripts/update_all.py` | 完整更新事务和原子发布入口 |
|
||||||
|
| `scripts/update_textile_intelligence.py` | 日历、展会、政策、平台、活动、今日必看主聚合 |
|
||||||
|
| `scripts/update_textile_trends.py` | 趋势文章、图库和时装趋势抓取 |
|
||||||
|
| `scripts/intelligence_sources.py` | 严格权威源注册表 |
|
||||||
|
| `scripts/intelligence_web_translation.py` | 页面语种和 Google/Yandex 链接策略 |
|
||||||
|
| `scripts/build_site.py` | 复制公开资产和数据、调用 SEO 构建、替换 `dist/` |
|
||||||
|
| `scripts/build_seo.py` | 栏目页、详情页、年份页和结构化数据 |
|
||||||
|
| `public/assets/js/render-intelligence-core.js` | 情报站核心 UI、筛选和翻译按钮 |
|
||||||
|
|
||||||
|
## 本地运行
|
||||||
|
|
||||||
|
Windows 11 可直接双击:
|
||||||
|
|
||||||
|
1. `start.bat`:缺少 `dist/` 时先构建,再自动寻找从 `8765` 开始的空闲端口。
|
||||||
|
2. `update.bat`:首次创建 `.venv`,从清华 PyPI 镜像安装依赖,严格更新并构建。
|
||||||
|
3. `install-schedule.bat`:安装每天 09:30 的 Windows 计划任务。
|
||||||
|
|
||||||
|
命令行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m venv .venv
|
||||||
|
.\.venv\Scripts\python.exe -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
|
||||||
|
.\.venv\Scripts\python.exe scripts\update_all.py
|
||||||
|
.\.venv\Scripts\python.exe scripts\serve.py
|
||||||
|
```
|
||||||
|
|
||||||
|
只基于仓库快照构建,不联网更新数据:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:SANSHENG_SITE_URL='https://intel.example.com'
|
||||||
|
.\.venv\Scripts\python.exe scripts\build_site.py --site-url $env:SANSHENG_SITE_URL
|
||||||
|
```
|
||||||
|
|
||||||
|
## C# 稳定版重构建议
|
||||||
|
|
||||||
|
最低风险的迁移顺序:
|
||||||
|
|
||||||
|
1. 冻结 `docs/DATA-CONTRACT.md` 描述的 JSON v2,C# 先读取当前两份公开 JSON。
|
||||||
|
2. 用 Worker Service 或独立计划任务承载采集,禁止在 ASP.NET Web 请求中同步抓取 59 个源。
|
||||||
|
3. 使用 `HttpClient`、`System.Text.Json` 和正式 HTML 解析器逐个迁移稳定源;每迁移一个源,与 Python 对同一 URL 双跑比对。
|
||||||
|
4. 将 `Source`、`FetchRun`、`IntelligenceItem`、`ItemSource`、`UserPreference`、`UserTask` 分表保存;自动事实与人工结论分离。
|
||||||
|
5. API 稳定后再迁移前端;服务端渲染静态正文,客户端仅增强筛选、收藏、任务和翻译渠道选择。
|
||||||
|
6. 最后切换正式域名 canonical,并为旧 URL 建立 301 映射。
|
||||||
|
|
||||||
|
C# 实现必须保留以下语义:稳定 ID、UTC `generated_at`、业务 `as_of_date`、内容指纹、源证据、严格失败不发布、缓存翻译失败不清空、官方事实/机器翻译/经营分析分区、原子发布和可回滚快照。
|
||||||
|
|
||||||
|
不要一次性重写全部抓取器,也不要先引入 LLM。先让 C# 后端稳定消费现有 JSON,再按源逐步替换,最容易定位数据差异和回滚。
|
||||||
|
|
||||||
|
## 不依赖 GitHub Pages 的自动部署
|
||||||
|
|
||||||
|
公司 Gitea 没有 Pages 不影响部署。推荐由 Gitea Runner、Windows 计划任务或公司 CI 执行:
|
||||||
|
|
||||||
|
```text
|
||||||
|
检出仓库
|
||||||
|
-> 创建 Python 虚拟环境并安装 requirements.txt
|
||||||
|
-> 运行 Python 与 Node 契约测试
|
||||||
|
-> 设置唯一 SANSHENG_SITE_URL
|
||||||
|
-> 运行 update_all.py(需要联网更新)或 build_site.py(只发布已提交快照)
|
||||||
|
-> 把 dist/ 作为构建制品
|
||||||
|
-> 同步到 IIS/Nginx 新版本目录
|
||||||
|
-> 健康检查通过后切换目录/发布槽
|
||||||
|
```
|
||||||
|
|
||||||
|
Web 节点只接收 `dist/`。不要把仓库、`.venv`、`data/textile-zh-cache.json`、`data/textile-intelligence-source-status.json`、`runtime/` 或抓取日志放进网站目录。IIS/Nginx 必须优先返回真实静态文件,不能让 `/data/*.json` 被 SPA fallback 替换成首页 HTML。
|
||||||
|
|
||||||
|
仓库没有预置绑定具体服务器账号的 Gitea workflow,因为 Runner 标签、发布协议、IIS 路径和密钥名尚未确定。确定这些公司环境参数后,只需把上面的命令接入现有流水线,不需要 Pages。
|
||||||
|
|
||||||
|
## SEO/GEO 基线
|
||||||
|
|
||||||
|
- 品牌实体统一为“三笙AI情报局”,简称“三笙AI”;“家纺AI”是能力词,不替代品牌。
|
||||||
|
- 核心主题覆盖家纺AI、三笙AI、家纺情报、跨境家纺平台、家纺跨境平台。
|
||||||
|
- `SANSHENG_SITE_URL` 是 canonical、Open Graph、Sitemap 和 `llms.txt` 的唯一域名来源。
|
||||||
|
- 独立版不覆盖 `https://www.sanshengai.net/` 根目录,未确定正式域名前不要修改线上 canonical。
|
||||||
|
- 每条静态详情包含可直接索引的中文正文,不要求搜索引擎执行 JavaScript。
|
||||||
|
- 页面区分官方事实、机器翻译和本站经营建议,结构化数据不把分析冒充官方原文。
|
||||||
|
|
||||||
|
## 测试与发布门槛
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m unittest discover -s tests -p 'test_*.py'
|
||||||
|
node tests\test_frontend.mjs
|
||||||
|
python scripts\build_site.py --site-url http://127.0.0.1:8765
|
||||||
|
```
|
||||||
|
|
||||||
|
发布前至少确认:
|
||||||
|
|
||||||
|
- Python 与 Node 契约测试全部通过。
|
||||||
|
- `source_target == source_success`,核心栏目非空。
|
||||||
|
- `dist/index.html`、`robots.txt`、`sitemap.xml`、`llms.txt` 和两份公开 JSON 存在。
|
||||||
|
- 桌面、390px 和 375px 移动端无横向溢出,七个入口可发现。
|
||||||
|
- 中文站不出现译文按钮,已知 Google/Yandex 阻断域名选择正确。
|
||||||
|
- 随机抽查 canonical、JSON-LD、官方链接、报名链接、日期和图库原图。
|
||||||
|
|
||||||
|
## 提交与更新日志规范
|
||||||
|
|
||||||
|
每次影响代码、数据结构、业务规则、信源、部署或 UI 的提交,都必须先在 [CHANGELOG.md](CHANGELOG.md) 顶部增加日期条目,至少写明:
|
||||||
|
|
||||||
|
- 改了什么、为什么改、影响哪些目录或数据字段。
|
||||||
|
- 修复了什么可观察问题,是否有兼容性变化。
|
||||||
|
- 实际运行过的测试和构建命令。
|
||||||
|
- 回滚该提交后需要同步回滚的数据、缓存或静态目录。
|
||||||
|
|
||||||
|
提交信息正文应与日志条目一致,禁止只写“update”“fix”或“优化”。普通回滚使用 `git revert <commit>`,不要重写共享分支历史。
|
||||||
|
|
||||||
|
## 进一步文档
|
||||||
|
|
||||||
|
- [更新日志](CHANGELOG.md)
|
||||||
|
- [信源手册](docs/SOURCES.md)
|
||||||
|
- [数据契约](docs/DATA-CONTRACT.md)
|
||||||
|
- [更新流水线](docs/PIPELINE.md)
|
||||||
|
- [C# 后端与前端交接](docs/CSHARP-NODE-HANDOFF.md)
|
||||||
|
- [SEO/GEO 规范](docs/SEO-GEO.md)
|
||||||
|
- [运维手册](docs/OPERATIONS.md)
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
|||||||
|
# C# 后端与 Node 前端交接
|
||||||
|
|
||||||
|
本仓库是可运行参考实现,不要求研发团队继续使用 Python 前端,也不要求用 C# 重写爬虫。推荐拆分边界如下。
|
||||||
|
|
||||||
|
## C# 后端
|
||||||
|
|
||||||
|
适合负责:用户、企业、角色权限、订阅市场、任务分派、提醒、收藏、人工复核、审计日志和 API。不要把抓取器放进 Web 请求生命周期;通过计划任务或消息队列运行采集作业。
|
||||||
|
|
||||||
|
建议最小实体:
|
||||||
|
|
||||||
|
- `Source`:来源、层级、语言、证据词、抓取策略、启停状态。
|
||||||
|
- `FetchRun`:开始/结束、HTTP 状态、内容指纹、证据、错误。
|
||||||
|
- `IntelligenceItem`:稳定 ID、栏目、事实字段、分析字段、适用地区、来源版本。
|
||||||
|
- `ItemSource`:一条聚合情报与多个来源的多对多关系。
|
||||||
|
- `UserPreference`:企业关注的国家、平台、品类和角色。
|
||||||
|
- `UserTask`:负责人、截止日、提醒、已处理/不相关状态。
|
||||||
|
|
||||||
|
数据库推荐 PostgreSQL;本地单机试运行可用 SQLite。正文去重建立 `normalized_title + start_date + region` 唯一候选键,内容指纹建立普通索引,外部 URL 使用规范化哈希索引。原始 HTML 只在需要审计时对象存储短期保留,不塞入主表。
|
||||||
|
|
||||||
|
API 可直接映射现有 JSON:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /api/intelligence/summary
|
||||||
|
GET /api/intelligence/items?section=&market=&platform=&from=&to=&cursor=
|
||||||
|
GET /api/intelligence/items/{id}
|
||||||
|
GET /api/platforms
|
||||||
|
GET /api/sources/{id}/runs
|
||||||
|
POST /api/tasks
|
||||||
|
PATCH /api/tasks/{id}
|
||||||
|
```
|
||||||
|
|
||||||
|
服务端必须再次校验翻译链接和外链协议,仅允许 `http/https`。用户偏好、任务和人工结论与自动抓取事实分表,避免下一轮增量更新覆盖人工数据。
|
||||||
|
|
||||||
|
## Node 前端
|
||||||
|
|
||||||
|
可以迁移到 Next.js 或 React,但不必重写信息架构。保留七个业务入口和趋势四个子类,默认趋势页进入灵感图库。推荐:
|
||||||
|
|
||||||
|
- TypeScript 定义与 `docs/DATA-CONTRACT.md` 一致的模型。
|
||||||
|
- TanStack Query 或框架原生数据缓存处理分页;Zustand 只存筛选、主题和用户偏好,不存整库情报。
|
||||||
|
- 服务端渲染栏目和详情,客户端只增强筛选、收藏、任务和翻译门控。
|
||||||
|
- 图片使用源站或授权地址时保留来源;没有图时继续使用 HTML 文字海报,不生成无来源的假图片。
|
||||||
|
- 触控目标至少 44px,业务正文至少 16px,移动端七分类首屏可发现。
|
||||||
|
|
||||||
|
## 迁移顺序
|
||||||
|
|
||||||
|
1. 先冻结 JSON v2 契约,将当前两份发布 JSON 导入新 API。
|
||||||
|
2. Node 前端改为读 API,逐页对比旧静态站;此时抓取仍由 Python 定时任务运行。
|
||||||
|
3. C# 增加用户偏好、任务和权限,不改自动事实字段。
|
||||||
|
4. 如确有团队维护收益,再逐个把稳定解析器迁移到 .NET;每迁移一个源,用相同 URL、证据词和快照做双跑比对。
|
||||||
|
5. 最后将 SEO canonical 切向新域名,并保留旧 URL 的 301 映射。
|
||||||
|
|
||||||
|
不要一开始重写 57 个源。先把现有采集器当独立批处理服务,C# 和 Node 围绕稳定 JSON 契约开发,风险和交付周期最低。
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# 数据契约
|
||||||
|
|
||||||
|
## 发布文件
|
||||||
|
|
||||||
|
- `data/textile-intelligence.json`:情报主数据,前端和 SEO 的唯一事实快照。
|
||||||
|
- `data/textile-trends.json`:趋势博客、灵感图库和时装趋势。
|
||||||
|
- `data/textile-intelligence-source-status.json`:生成期源状态,不复制到公开 `dist/data`。
|
||||||
|
- `data/textile-zh-cache.json`:翻译缓存,不复制到公开站点。
|
||||||
|
|
||||||
|
主数据顶层字段:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `version` | number | 数据结构版本 |
|
||||||
|
| `generated_at` | ISO 8601 | 生成时间,UTC |
|
||||||
|
| `as_of_date` | YYYY-MM-DD | 业务判断基准日 |
|
||||||
|
| `source_target/source_success` | number | 严格源目标与成功数 |
|
||||||
|
| `summary` | object | 各栏目数量、去重数、市场数 |
|
||||||
|
| `today` | array | 已排序的今日经营动作 |
|
||||||
|
| `calendar/calendar_insights` | array | 原始日期层与跨源聚合机会层 |
|
||||||
|
| `exhibitions` | array | 展会和报名信息 |
|
||||||
|
| `policies` | array | 政策、召回、平台规则与知识产权 |
|
||||||
|
| `standards` | array | 标准、认证、色彩和材料事实 |
|
||||||
|
| `platforms` | array | 平台目录与中国卖家准入边界 |
|
||||||
|
| `activities` | array | 跨境活动与报名入口 |
|
||||||
|
| `sources` | array | 已通过源的公开核验信息 |
|
||||||
|
|
||||||
|
## 公共字段
|
||||||
|
|
||||||
|
所有可展示条目至少包含稳定 `id`、`title`、`summary`、`source`、`source_url/url`、`verified_at`、`confidence`。外文条目可包含 `title_original`、`summary_original`、`translation_url` 和 `translation_fallback_url`。
|
||||||
|
|
||||||
|
日历聚合条目必须满足:
|
||||||
|
|
||||||
|
- `start_date`、`affected_countries`、`country_details.local_name`
|
||||||
|
- `stocking_start`、`stocking_end`、`planning_stage`
|
||||||
|
- `product_suggestions`、`platforms`、`platform_actions`
|
||||||
|
- `official_sources` 与事实/经营分析边界
|
||||||
|
|
||||||
|
进入“精准机会”的条目必须同时有目标国家、平台、产品、备货窗口,且窗口未在 `as_of_date` 前结束。不满足者只能进入全部节点或观察层。
|
||||||
|
|
||||||
|
展会条目要区分 `registration_url`、`visitor_url`、官网和机器翻译链接。正式报名、付款和验证码不得指向翻译代理。
|
||||||
|
|
||||||
|
平台条目必须包含 `homepage_url`、`official_url`、`seller_url`、`markets`、`access_level`、`access_label`、`cross_border` 和本地 SVG `logo`。不确定的中国主体准入不能标为无条件开放。
|
||||||
|
|
||||||
|
## 兼容策略
|
||||||
|
|
||||||
|
- 新增可选字段不提升 `version`;删除、改名或改变语义必须提升版本。
|
||||||
|
- 消费端忽略未知字段,不依赖数组索引。
|
||||||
|
- C# 反序列化建议启用大小写不敏感和未知字段忽略。
|
||||||
|
- Node/TypeScript 进入数据库前应以 JSON Schema 或 Zod 校验同一契约;不要在 UI 组件内修补脏数据。
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# 运维手册
|
||||||
|
|
||||||
|
## 环境
|
||||||
|
|
||||||
|
- Windows 11、Linux 或 macOS
|
||||||
|
- Python 3.11+
|
||||||
|
- 可访问目标官方站点的网络
|
||||||
|
- Node 仅用于运行前端契约测试,不是生产运行依赖
|
||||||
|
|
||||||
|
## 日常命令
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# 更新并构建
|
||||||
|
.\.venv\Scripts\python.exe scripts\update_all.py
|
||||||
|
|
||||||
|
# 固定日期回归,不用于生产快照
|
||||||
|
.\.venv\Scripts\python.exe scripts\update_all.py --now 2026-08-12
|
||||||
|
|
||||||
|
# 仅重新构建
|
||||||
|
.\.venv\Scripts\python.exe scripts\build_site.py --site-url https://intel.example.com
|
||||||
|
|
||||||
|
# 本地访问
|
||||||
|
.\.venv\Scripts\python.exe scripts\serve.py --port 8765
|
||||||
|
```
|
||||||
|
|
||||||
|
## 部署
|
||||||
|
|
||||||
|
`dist/` 是完整静态目录,可交给 IIS、Nginx、对象存储或任何 CDN。运行服务器不需要 Python;Python 只在更新节点运行。IIS 必须将实际静态文件优先于 SPA fallback,否则 `/data/*.json` 会错误返回首页 HTML。
|
||||||
|
|
||||||
|
更新节点和 Web 节点分离时,将成功构建的 `dist/` 整目录同步到新版本目录,再通过目录链接或发布槽切换;不要边复制边对外提供半成品。
|
||||||
|
|
||||||
|
## 监控
|
||||||
|
|
||||||
|
至少监控:
|
||||||
|
|
||||||
|
- 进程退出码和最后成功时间。
|
||||||
|
- `source_target == source_success`。
|
||||||
|
- 核心栏目数量突降超过 30%。
|
||||||
|
- `textile-intelligence-source-status.json` 的失败源、HTTP 状态、证据词缺失和内容指纹变化。
|
||||||
|
- `dist/sitemap.xml`、`dist/llms.txt` 和两份公开 JSON 可访问且 Content-Type 正确。
|
||||||
|
|
||||||
|
## 故障处理
|
||||||
|
|
||||||
|
- 单个官方源失败:先核验 URL、重定向、证书和正文证据;不要直接删证据词或关闭 TLS 验证。
|
||||||
|
- 参考趋势源 403:允许跳过,不影响严格发布;长期失效再从趋势配置删除。
|
||||||
|
- 翻译代理不可用:保留本站中文摘要和官方原文,不阻断发布。
|
||||||
|
- 构建失败:正式 `data/` 与 `dist/` 保持上一版;修复后重跑。
|
||||||
|
- 数据误判:先修共享规范化或分类函数并加最小回归测试,再重新生成,避免只在前端隐藏。
|
||||||
|
|
||||||
|
## 备份和清理
|
||||||
|
|
||||||
|
`runtime/snapshots/` 自动保存旧 JSON 的 gzip 快照,限制为 14 份和 120 MiB。源码库不提交 `dist/`、`.venv/`、临时更新目录和快照。若迁移到数据库,备份策略由数据库负责,仍应保留每日成功 JSON 作为可重放交换快照。
|
||||||
|
|
||||||
|
## 发布清单
|
||||||
|
|
||||||
|
1. Python 与 Node 测试全绿。
|
||||||
|
2. 严格源全部通过,活动源全部通过。
|
||||||
|
3. `SANSHENG_SITE_URL` 是正式唯一域名。
|
||||||
|
4. 桌面、390px 与 375px 检查七入口、日历、展会、平台、活动和趋势图库。
|
||||||
|
5. 抽查外文、简中、`.cn`、繁中页面的翻译按钮门控。
|
||||||
|
6. 抽查 10 条详情页的 canonical、JSON-LD、官方链接和日期。
|
||||||
|
7. 发布后请求 `/data/textile-intelligence.json`,确认不是 SPA HTML。
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# 更新流水线
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A[官方与参考源] --> B[并发抓取和证据词校验]
|
||||||
|
B --> C[结构化解析与语种识别]
|
||||||
|
C --> D[中文缓存和翻译链接]
|
||||||
|
D --> E[规范化、聚合、排序和去重]
|
||||||
|
E --> F[临时 JSON 校验]
|
||||||
|
F --> G[静态 SEO / GEO 构建]
|
||||||
|
G --> H[原子替换 data 与 dist]
|
||||||
|
H --> I[本地 HTTP 服务或任意静态服务器]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 抓取
|
||||||
|
|
||||||
|
`update_textile_trends.py` 先更新趋势数据,`update_textile_intelligence.py --strict` 再校验权威源并构造全部业务栏目。HTTP 使用超时、有限重试、固定浏览器 UA、内容类型检查和正文证据词,不把“HTTP 200”直接当成功。
|
||||||
|
|
||||||
|
BSMI 官方站证书缺少现代 OpenSSL 严格模式要求的 Subject Key Identifier。`LegacyCertificateAdapter` 只挂载到该域名,并同时作用于代理连接;仍保留 CA 链和主机名验证,禁止全局 `verify=False`。
|
||||||
|
|
||||||
|
## 翻译
|
||||||
|
|
||||||
|
先识别域名、页面语言和正文字符。简体中文或 `.cn` 不创建翻译入口;繁体中文保留原文并提供简体辅助。Google 和 Yandex 只生成访问 URL,不抓取或存储整页翻译。标题和摘要的中文结果进入 `textile-zh-cache.json`,当前使用规范化后的完整原文字符串作为缓存键;内容指纹另用于判断源站是否变化。
|
||||||
|
|
||||||
|
## 排序与去重
|
||||||
|
|
||||||
|
- 日历:规范化节名、日期、适用区域后聚合多个官方来源;同一聚合条目并列展示证据。
|
||||||
|
- 展会:规范化展名、开始日和城市,动态目录与固定官方源相遇时保留官方字段。
|
||||||
|
- 政策:按风险、发布时间、生效时间和适用市场排序;召回与经营政策分类型展示。
|
||||||
|
- 今日必看:只选择可行动的备货、临近展会、重大政策和趋势任务,已过备货窗降级为营销或履约状态。
|
||||||
|
- 趋势:URL、规范化标题和内容指纹去重,优先有图片和较新发布时间的条目。
|
||||||
|
|
||||||
|
## 增量与容量
|
||||||
|
|
||||||
|
`update_all.py` 在 `runtime/update-*` 临时目录完成全部流程。新旧文件 SHA-256 相同则不写正式数据;有变化时先把旧四份 JSON 压缩为单个快照,再使用 `os.replace` 原子更新。快照最多 14 份、总计不超过 120 MiB。
|
||||||
|
|
||||||
|
公开 `dist/data` 只包含两份运行 JSON,不发布源状态和翻译缓存。静态详情页由数据重建,不进入源码版本管理。若以后迁移数据库,建议保留当前 JSON 作为版本化交换契约,而不是让爬虫直接写业务表。
|
||||||
|
|
||||||
|
## 失败语义
|
||||||
|
|
||||||
|
以下任一情况退出非零且不发布:严格源失败、活动源失败、核心栏目为空、JSON 无法解析、SEO 构建失败、目标目录替换失败。日志允许趋势参考源 403 后跳过,因为它们不计入严格权威源;该降级会保留在趋势错误字段中。
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# 三笙AI情报局 SEO/GEO 规范
|
||||||
|
|
||||||
|
## 实体与域名
|
||||||
|
|
||||||
|
- 品牌实体统一写作“**三笙AI情报局**”,简称“三笙AI”;“家纺AI”是产品能力词,不替代品牌名。
|
||||||
|
- 正式域名只由 `SANSHENG_SITE_URL` 注入,例如 `https://intel.example.com`。独立站不占用 `https://www.sanshengai.net/` 根目录,也不复制主站 canonical。
|
||||||
|
- 页面路径固定为 `/textile/`、`/textile/calendar/`、`/textile/intelligence/<section>/<id>/`;末尾保留 `/`,所有 canonical、Open Graph、JSON-LD、Sitemap 使用同一规范 URL。
|
||||||
|
|
||||||
|
## 关键词与页面意图
|
||||||
|
|
||||||
|
核心词:`家纺AI`、`三笙AI`、`家纺情报`、`跨境家纺平台`、`家纺跨境平台`。任务词:家纺备货日历、家纺展会、家纺政策、家纺平台渠道、家纺趋势。
|
||||||
|
|
||||||
|
每个栏目只服务一个问题:备货日历回答“何时备货与下一步动作”,展会回答“是否值得参加与官方报名”,政策回答“发生了什么与不处理的后果”,平台回答“适合谁与官方入驻入口”,趋势回答“如何转化为产品和打样任务”。标题、首段、H2 和 JSON-LD 只围绕该问题组织,不堆叠同义词。
|
||||||
|
|
||||||
|
## GEO(生成式搜索)
|
||||||
|
|
||||||
|
- 每个集合页和详情页首屏输出一段 `data-answer-first="true"` 的“快速答案/先看结论”,答案先给结论,再给证据与动作。
|
||||||
|
- 官方事实、机器翻译、本站经营分析必须分区;机器翻译只作阅读辅助,不改变原文事实,不替代报名、付款、合规提交。
|
||||||
|
- 详情页 JSON-LD 使用 `Event` 或 `Article`,包含 `inLanguage=zh-CN`、`dateModified`、`publisher`、`keywords`、`isAccessibleForFree`;集合页使用 `CollectionPage` + `ItemList`。
|
||||||
|
- `llms.txt` 说明实体定义、栏目意图、事实与分析边界和稳定入口,便于问答系统引用;它不是隐藏关键词页。
|
||||||
|
|
||||||
|
## 抓取与更新
|
||||||
|
|
||||||
|
- 只有内容指纹变化才重新生成机器翻译和详情页;外部翻译失败时保留上一版中文内容。
|
||||||
|
- Sitemap 只列公开 HTML 入口、详情页和年份页;不列抓取日志、翻译缓存、状态 JSON 或内部分析文件。
|
||||||
|
- 当前只有 `zh-CN` 正文,使用 `hreflang="zh-CN"` 与 `x-default` 指向同一 canonical;未来增加人工校验的原生语言页面后,才建立互指 hreflang。
|
||||||
|
- robots.txt 允许公开静态页面,禁止把内部状态文件当成索引入口。
|
||||||
|
|
||||||
|
## 无 GitHub/Pages 部署
|
||||||
|
|
||||||
|
更新节点运行 `python scripts/update_all.py`,再运行 `python scripts/build_site.py --site-url "$SANSHENG_SITE_URL"`,最终只发布 `dist/`。Gitea Actions、Windows 计划任务或公司 CI 均可执行这两个命令,然后用制品上传、IIS/Nginx 目录同步、对象存储或 CDN 发布 `dist/`;访问端不需要 Python、Node、数据库或大模型,也不依赖 GitHub Pages。
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# 信源与 Demo 差集
|
||||||
|
|
||||||
|
## 可信层级
|
||||||
|
|
||||||
|
| 层级 | 用途 | 可生成的结论 |
|
||||||
|
|---|---|---|
|
||||||
|
| L1 政府、国际组织、标准机构 | 日期、法规、关税、召回、标准 | 可作为事实层,必须保留原文和核验时间 |
|
||||||
|
| L2 平台、展会和主办方官方 | 入驻、报名、活动、类目、官方新闻 | 可生成平台或参展动作 |
|
||||||
|
| L3 行业媒体、博物馆、品牌公开页 | 趋势、设计灵感、活动发现 | 只能标为观察或参考,不得冒充法规 |
|
||||||
|
| L4 商业数据摘要 | 公开样本和搜索信号 | 不计入权威源成功数,不依赖付费详情 |
|
||||||
|
|
||||||
|
## 当前严格源
|
||||||
|
|
||||||
|
当前注册表位于 `scripts/intelligence_sources.py`,共 59 个严格校验源。核心覆盖:
|
||||||
|
|
||||||
|
- 日历:Nager.Date、GOV.UK、美国 OPM、日本内阁府、香港政府、AlAdhan、NRF、阿里巴巴 11.11 官方活动、NFL、LA28。
|
||||||
|
- 展会:Messe Frankfurt 系列、Première Vision、Texworld、Maison&Objet、High Point、Las Vegas Market、Milano Unica、CIFF、DOMOTEX、INDEX、UFI、Texpertise、CCBEC、HKTDC Home InStyle。
|
||||||
|
- 政策与合规:USTR、CBP、FTC、CPSC、欧盟税务与海关、ECHA、欧盟纺织战略、英国关税、商务部、香港工贸署、Singapore Customs、ASEAN、EEC、哈萨克斯坦、UAE FTA、ZATCA、台湾 BSMI、沙特 SASO、WIPO、EUIPO。
|
||||||
|
- 平台规则:Amazon、eBay、Walmart、TikTok Shop、Mercado Libre。
|
||||||
|
- 标准与趋势事实:Pantone、Textile Exchange、OEKO-TEX、AATCC。
|
||||||
|
|
||||||
|
平台目录另有 28 项,经官方类目、官网与卖家入口核验,已包含 Amazon、eBay、Walmart、Etsy、TikTok Shop、Temu、Shopee、Lazada、Ozon、Wildberries、Mercado Libre、Noon、Wayfair、Rakuten、Coupang、Allegro、OTTO、Cdiscount、bol、Kaufland、Shopify、Alibaba.com、1688、SHEIN 等。
|
||||||
|
|
||||||
|
## 本轮从 Demo 吸收
|
||||||
|
|
||||||
|
Demo 约有 207 个基础域名,与现有注册表的原始差集约 157 个。域名数量不能等同于可信源数量,因为大量条目只是区域商城、旧入口、转载、咨询商、零售货架或付费报告。
|
||||||
|
|
||||||
|
本轮实际新增四个一手源:
|
||||||
|
|
||||||
|
1. 台湾 BSMI 纺织品检验专区:补齐台湾寝具、毛巾、服装的检验与标示。
|
||||||
|
2. 沙特 SASO 纺织产品技术法规:替代 Demo 中咨询公司的二手法规解释。
|
||||||
|
3. CCBEC 深圳跨境电商展:覆盖家居日用、平台、物流、POD 和服务商对接。
|
||||||
|
4. HKTDC Home InStyle:实体展期经官方 Fair at a Glance 核验为 2027-04-27 至 2027-04-30。
|
||||||
|
|
||||||
|
## 用户点名页面的处理结论
|
||||||
|
|
||||||
|
- `tid.gov.hk/en/tradecircular/2026/ci5442026.html`:已作为香港工贸署官方政策源接入。
|
||||||
|
- `asinsight.com/report/US/cooling-duvet-cover`:已作为公开商业趋势参考接入,不计入权威政策源。
|
||||||
|
- `gdtextiles.cn/nd.jsp?groupId=36&id=1966`:不接入。页面转载中国棉花网且 HTTPS 使用自签名证书;同一政策事实已由 USTR、CBP 等一手来源覆盖。
|
||||||
|
- `bhg.com/best-duvet-inserts-6822459`:不接入自动抓取。当前返回 HTTP 402,并属于消费者测评;只有公开访问与自动使用条件明确时才可作为选品参考,不能作为政策或市场事实。
|
||||||
|
|
||||||
|
## 发现源与排除项
|
||||||
|
|
||||||
|
- 雨果跨境用于发现活动,日期、费用、报名状态必须回平台或主办方官方页复核。
|
||||||
|
- ASInsight 只保留无需登录的公开摘要,标为商业数据参考,不计入权威成功数。
|
||||||
|
- Dezeen、Design Milk、Fibre2Fashion、博物馆图库用于趋势和灵感,不生成政策结论。
|
||||||
|
- 本地零售货架适合后续抽样研究尺寸、材质、色彩和价格带,不做高频库存或价格抓取。
|
||||||
|
- 永久排除 POP 趋势网、91 家纺付费快照、已关闭的 Catch、旧 vente-privee 域名、SEO 转载和只有咨询商解释的法规。
|
||||||
|
- 咨询站只用于发现线索,必须回 FTC、CPSC、欧盟、SASO、海关等官方源。
|
||||||
|
|
||||||
|
新增源必须提供:唯一 ID、栏目、地区、官方 URL、正文证据词、权威说明、中文标题和业务动作。抓取成功只代表页面可访问且证据存在,不代表其中每段内容自动成为经营建议。
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001 >nul
|
||||||
|
setlocal
|
||||||
|
cd /d "%~dp0"
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File "runtime\install_schedule.ps1"
|
||||||
|
if errorlevel 1 pause
|
||||||
|
exit /b %errorlevel%
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
|
--bg: #f5f8fb;
|
||||||
|
--bg-secondary: #edf4f7;
|
||||||
|
--panel: rgba(255, 255, 255, 0.9);
|
||||||
|
--panel-solid: #fff;
|
||||||
|
--card-bg: #fff;
|
||||||
|
--ink: #10233c;
|
||||||
|
--ink-secondary: #334b63;
|
||||||
|
--muted: #64778b;
|
||||||
|
--subtle: #91a1b1;
|
||||||
|
--line: #dbe6ec;
|
||||||
|
--line-strong: #bdd0db;
|
||||||
|
--trans-bg: rgba(15, 69, 91, 0.055);
|
||||||
|
--trans-border: rgba(15, 69, 91, 0.12);
|
||||||
|
--accent: #0051d6;
|
||||||
|
--accent-blue: #0051d6;
|
||||||
|
--accent-orange: #007f73;
|
||||||
|
--accent-orange-bg: rgba(0, 127, 115, 0.08);
|
||||||
|
--accent-orange-border: rgba(0, 127, 115, 0.28);
|
||||||
|
--radius: 8px;
|
||||||
|
--radius-sm: 6px;
|
||||||
|
--radius-lg: 8px;
|
||||||
|
--shadow-sm: 0 1px 3px rgba(16, 35, 60, 0.06);
|
||||||
|
--shadow-md: 0 8px 24px rgba(16, 35, 60, 0.08);
|
||||||
|
--font-dongguan-light: "STDongGuanTi Light", "Noto Serif SC", "Songti SC", "SimSun", serif;
|
||||||
|
--font-dongguan-regular: "STDongGuanTi", "Noto Serif SC", "Songti SC", "SimSun", serif;
|
||||||
|
--font-dongguan-bold: "STDongGuanTi Bld", "STDongGuanTi", "Noto Serif SC", "Songti SC", "SimSun", serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
color-scheme: dark;
|
||||||
|
--bg: #091119;
|
||||||
|
--bg-secondary: #0d1822;
|
||||||
|
--panel: rgba(15, 27, 38, 0.94);
|
||||||
|
--panel-solid: #101d28;
|
||||||
|
--card-bg: #12212d;
|
||||||
|
--ink: #f3f8fb;
|
||||||
|
--ink-secondary: #cad7df;
|
||||||
|
--muted: #98a9b7;
|
||||||
|
--subtle: #6f8393;
|
||||||
|
--line: rgba(220, 237, 245, 0.12);
|
||||||
|
--line-strong: rgba(220, 237, 245, 0.2);
|
||||||
|
--trans-bg: rgba(255, 255, 255, 0.05);
|
||||||
|
--trans-border: rgba(255, 255, 255, 0.1);
|
||||||
|
--accent-blue: #75a7ff;
|
||||||
|
--accent-orange: #45d1b5;
|
||||||
|
--accent-orange-bg: rgba(69, 209, 181, 0.12);
|
||||||
|
--accent-orange-border: rgba(69, 209, 181, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *::before, *::after { box-sizing: border-box; }
|
||||||
|
html { min-width: 320px; scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
|
||||||
|
body { margin: 0; min-height: 100vh; background: linear-gradient(135deg, color-mix(in srgb, var(--accent-blue) 6%, var(--bg)), color-mix(in srgb, #12a889 7%, var(--bg))); color: var(--ink); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", sans-serif; font-size: 16px; line-height: 1.6; }
|
||||||
|
button, input, select { font: inherit; }
|
||||||
|
button, a { -webkit-tap-highlight-color: transparent; }
|
||||||
|
a { color: inherit; }
|
||||||
|
.skip-link { position: fixed; top: 8px; left: 8px; z-index: 100; padding: 10px 14px; background: var(--ink); color: var(--panel-solid); transform: translateY(-150%); }
|
||||||
|
.skip-link:focus { transform: none; }
|
||||||
|
.site-header { position: sticky; top: 0; z-index: 30; display: flex; align-items: center; justify-content: space-between; min-height: 76px; padding: 10px clamp(16px, 4vw, 48px); border-bottom: 1px solid var(--line); background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(18px); }
|
||||||
|
.brand { display: flex; align-items: center; gap: 12px; color: var(--ink); text-decoration: none; }
|
||||||
|
.brand img { width: 52px; height: 52px; object-fit: contain; }
|
||||||
|
.brand span { display: grid; }
|
||||||
|
.brand strong { font-family: inherit; font-size: 22px; font-weight: 700; line-height: 1.2; }
|
||||||
|
.brand small { color: var(--muted); font-size: 13px; }
|
||||||
|
.site-tools { display: flex; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: 8px; background: color-mix(in srgb, var(--panel-solid) 90%, transparent); box-shadow: var(--shadow-sm); }
|
||||||
|
.icon-button { position: relative; display: grid; width: 44px; height: 44px; padding: 0; place-items: center; border: 0; border-radius: 5px; background: transparent; color: var(--ink-secondary); cursor: pointer; transition: color 160ms ease, background 160ms ease, transform 160ms ease; }
|
||||||
|
.icon-button:hover { background: var(--trans-bg); color: var(--accent-blue); }
|
||||||
|
.icon-button:active { transform: scale(0.94); }
|
||||||
|
.icon-button:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: 2px; }
|
||||||
|
.tool-icon { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
||||||
|
.theme-icon-sun { display: none; }
|
||||||
|
html[data-theme="dark"] .theme-icon-moon { display: none; }
|
||||||
|
html[data-theme="dark"] .theme-icon-sun { display: block; }
|
||||||
|
.site-shell { width: min(1760px, calc(100% - 48px)); margin: 0 auto; padding: 28px 0 64px; }
|
||||||
|
.page-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 36px; margin-bottom: 16px; padding: 12px 0 16px; border-bottom: 1px solid var(--line); }
|
||||||
|
.page-heading h1 { margin: 0; font-family: inherit; font-size: clamp(30px, 3vw, 40px); font-weight: 700; line-height: 1.15; letter-spacing: 0; }
|
||||||
|
.page-heading > p { max-width: 760px; margin: 0; color: var(--ink-secondary); font-size: 17px; }
|
||||||
|
.toast { position: fixed; right: 18px; bottom: 18px; z-index: 80; max-width: min(360px, calc(100vw - 36px)); padding: 12px 16px; border: 1px solid var(--line); border-radius: 6px; background: var(--ink); color: var(--panel-solid); opacity: 0; transform: translateY(12px); pointer-events: none; transition: 180ms ease; }
|
||||||
|
.toast.visible { opacity: 1; transform: none; }
|
||||||
|
.intelligence-list-grid { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; width: 100%; }
|
||||||
|
.intelligence-tags { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 12px; }
|
||||||
|
.calendar-local-names { margin: 12px 0; padding: 10px 12px; border-left: 3px solid var(--accent-blue); background: var(--trans-bg); }
|
||||||
|
.calendar-local-names p { margin: 3px 0; color: var(--ink-secondary); font-size: 15px; }
|
||||||
|
|
||||||
|
@media (max-width: 1080px) {
|
||||||
|
.intelligence-list-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
.page-heading { align-items: flex-start; flex-direction: column; gap: 10px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.site-header { min-height: 68px; padding: 8px 12px; }
|
||||||
|
.brand img { width: 44px; height: 44px; }
|
||||||
|
.brand strong { font-size: 19px; }
|
||||||
|
.brand small { display: none; }
|
||||||
|
.site-tools { flex: 0 0 auto; }
|
||||||
|
.site-shell { width: calc(100% - 24px); padding-top: 12px; }
|
||||||
|
.page-heading { margin-bottom: 10px; padding: 12px 0; }
|
||||||
|
.page-heading h1 { font-size: 30px; }
|
||||||
|
.page-heading > p { font-size: 16px; }
|
||||||
|
.intelligence-list-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
*, *::before, *::after { scroll-behavior: auto !important; transition: none !important; animation: none !important; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,983 @@
|
|||||||
|
/* 家纺跨境情报:面向经营者的高可读决策工作台。 */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--intel-brand-blue: #0051d6;
|
||||||
|
--intel-brand-green: #12eea8;
|
||||||
|
--intel-brand-yellow: #fcbb00;
|
||||||
|
--intel-brand-orange: #f99c00;
|
||||||
|
--intel-radius: 6px;
|
||||||
|
--intel-brand-gradient: linear-gradient(120deg, var(--intel-brand-blue), #0879d9 48%, var(--intel-brand-green));
|
||||||
|
--intel-dopamine-gradient: linear-gradient(112deg, #075ee8 0%, #6c4cff 33%, #e947a7 67%, #ff9d2e 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shell.is-textile, .site-shell.textile-wrap { width: min(82vw, 1680px); max-width: none; }
|
||||||
|
.textile-wrap { width: 100%; max-width: none; margin: 1.5rem auto 0; }
|
||||||
|
.textile-wrap *, .textile-wrap *::before, .textile-wrap *::after { border-radius: var(--intel-radius); }
|
||||||
|
.intelligence-panel { --intel-soft: color-mix(in srgb, var(--intel-brand-blue) 7%, var(--panel-solid)); }
|
||||||
|
.intelligence-metrics { margin-bottom: 12px; border-bottom: 1px solid var(--line); }
|
||||||
|
.intelligence-utility-row { display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-height: 42px; padding: 0 4px; color: var(--muted); cursor: pointer; list-style: none; user-select: none; }
|
||||||
|
.intelligence-utility-row::-webkit-details-marker { display: none; }
|
||||||
|
.intelligence-utility-row:hover { color: var(--ink); }
|
||||||
|
.intelligence-utility-row:focus-visible { outline: 2px solid var(--intel-brand-blue); outline-offset: 2px; }
|
||||||
|
.metrics-chevron { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform 160ms ease; }
|
||||||
|
.intelligence-metrics[open] .metrics-chevron { transform: rotate(180deg); }
|
||||||
|
.intelligence-metrics[open] .intelligence-stats { margin-bottom: 12px; }
|
||||||
|
|
||||||
|
.textile-view-switch {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 3px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
padding: 3px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--panel-solid);
|
||||||
|
}
|
||||||
|
|
||||||
|
.textile-view-btn {
|
||||||
|
min-height: 36px;
|
||||||
|
padding: 0 14px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textile-view-btn:hover { color: var(--ink); background: var(--trans-bg); }
|
||||||
|
.textile-view-btn.active { color: #fff; background: var(--intel-brand-gradient); }
|
||||||
|
|
||||||
|
.intelligence-panel { animation: fadeInUp 0.32s ease; }
|
||||||
|
|
||||||
|
.intelligence-overview {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
padding-bottom: 18px;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-overview-copy { max-width: 760px; }
|
||||||
|
.intelligence-kicker { margin: 0 0 6px; color: var(--intel-brand-blue); font-size: 12px; font-weight: 800; }
|
||||||
|
.intelligence-overview h3 { margin: 0; color: var(--ink); font-size: 26px; letter-spacing: 0; }
|
||||||
|
.intelligence-overview p:last-child { margin: 8px 0 0; color: var(--muted); font-size: 14px; }
|
||||||
|
.intelligence-overview-actions { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
|
||||||
|
#intelligenceUpdatedAt { color: var(--muted); font-size: 12px; }
|
||||||
|
|
||||||
|
.intelligence-share-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0 14px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
font-weight: 800;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-share-btn:hover { border-color: var(--intel-brand-blue); color: var(--intel-brand-blue); }
|
||||||
|
|
||||||
|
.intelligence-stats {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
border-left: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-stat {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-right: 1px solid var(--line);
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
background: var(--card-trans-bg);
|
||||||
|
}
|
||||||
|
.intelligence-stat strong { font-variant-numeric: tabular-nums; }
|
||||||
|
|
||||||
|
.intelligence-stat span { display: block; color: var(--muted); font-size: 11px; }
|
||||||
|
.intelligence-stat strong { display: block; margin-top: 4px; color: var(--ink); font-size: 22px; line-height: 1.1; }
|
||||||
|
|
||||||
|
.intelligence-toolbar {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 210px;
|
||||||
|
gap: 10px;
|
||||||
|
margin: 16px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-toolbar input,
|
||||||
|
.intelligence-toolbar select {
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--panel-solid);
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-toolbar input:focus,
|
||||||
|
.intelligence-toolbar select:focus { outline: 3px solid color-mix(in srgb, var(--intel-brand-green) 35%, transparent); border-color: var(--intel-brand-blue); }
|
||||||
|
|
||||||
|
.intelligence-tabs {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0 0 12px;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.intelligence-tabs::-webkit-scrollbar,
|
||||||
|
.calendar-month-rail::-webkit-scrollbar,
|
||||||
|
.policy-scope-switch::-webkit-scrollbar { display: none; }
|
||||||
|
|
||||||
|
.intelligence-tab {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
min-height: 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
justify-content: space-between;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--card-trans-bg);
|
||||||
|
color: var(--ink-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-tab:hover { border-color: color-mix(in srgb, var(--intel-brand-blue) 42%, var(--line)); color: var(--ink); background: var(--intel-soft); }
|
||||||
|
.intelligence-tab.active { color: #fff; border-color: var(--intel-brand-blue); background: var(--intel-brand-blue); box-shadow: 0 7px 18px rgba(0, 81, 214, .2); }
|
||||||
|
.intelligence-tab-count { min-width: 26px; padding: 2px 7px; background: color-mix(in srgb, var(--intel-brand-blue) 9%, var(--panel-solid)); color: var(--intel-brand-blue); font-size: 11px; text-align: center; }
|
||||||
|
.intelligence-tab.active .intelligence-tab-count { background: rgba(255, 255, 255, .18); color: #fff; }
|
||||||
|
|
||||||
|
.intelligence-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-list.is-today { display: block; column-count: 3; column-gap: 16px; }
|
||||||
|
.intelligence-list.is-today > * { display: inline-block; width: 100%; margin: 0 0 16px; break-inside: avoid; vertical-align: top; }
|
||||||
|
.intelligence-list.is-today > .today-briefing { display: flex; column-span: all; }
|
||||||
|
|
||||||
|
.intelligence-card {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 7px;
|
||||||
|
background: var(--card-trans-bg);
|
||||||
|
transition: border-color 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-card:hover { border-color: color-mix(in srgb, var(--intel-brand-blue) 55%, var(--line)); transform: translateY(-2px); }
|
||||||
|
|
||||||
|
.intelligence-card-visual {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(140deg, color-mix(in srgb, var(--poster-accent) 22%, var(--poster-paper)), var(--poster-ink));
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-card-image { display: block; width: 100%; height: 100%; object-fit: cover; }
|
||||||
|
.intelligence-card-visual:not(.is-poster) .intelligence-poster-copy { background: linear-gradient(180deg, transparent 20%, rgba(0, 0, 0, 0.86)); }
|
||||||
|
|
||||||
|
.intelligence-poster-copy {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 18px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-card-visual.is-poster .intelligence-poster-copy { justify-content: space-between; color: var(--poster-paper); }
|
||||||
|
.intelligence-poster-eyebrow, .intelligence-poster-region { font-size: 11px; font-weight: 800; }
|
||||||
|
.intelligence-poster-title { display: -webkit-box; overflow: hidden; font-size: 19px; line-height: 1.25; -webkit-box-orient: vertical; -webkit-line-clamp: 3; }
|
||||||
|
|
||||||
|
.intelligence-card-body { display: grid; align-content: start; padding: 15px; }
|
||||||
|
.intelligence-card-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-height: 22px; }
|
||||||
|
.intelligence-badge { padding: 2px 7px; border-radius: 4px; background: var(--trans-bg); color: var(--muted); font-size: 10px; font-weight: 800; }
|
||||||
|
.badge-calendar { color: #20b486; background: rgba(32, 180, 134, 0.13); }
|
||||||
|
.badge-exhibitions { color: #5b8def; background: rgba(91, 141, 239, 0.13); }
|
||||||
|
.badge-policies, .risk-高 { color: #ff6b6b; background: rgba(255, 107, 107, 0.13); }
|
||||||
|
.badge-standards { color: #d46aa0; background: rgba(212, 106, 160, 0.13); }
|
||||||
|
.impact-高 { color: #f0aa3c; background: rgba(240, 170, 60, 0.13); }
|
||||||
|
.intelligence-card-date { margin-left: auto; color: var(--muted); font-size: 10px; }
|
||||||
|
.intelligence-card-title { margin: 10px 0 7px; color: var(--ink); font-size: 17px; line-height: 1.4; letter-spacing: 0; }
|
||||||
|
.intelligence-card-original { margin: -2px 0 8px; color: var(--muted); font-size: 11px; line-height: 1.45; }
|
||||||
|
.intelligence-card-summary { display: -webkit-box; overflow: hidden; margin: 0; color: var(--ink-secondary); font-size: 13px; line-height: 1.65; -webkit-box-orient: vertical; -webkit-line-clamp: 4; }
|
||||||
|
.intelligence-card-action { margin-top: 12px; padding: 10px 11px; border-left: 3px solid #147566; background: var(--trans-bg); }
|
||||||
|
.intelligence-card-action-label { color: #147566; font-size: 10px; font-weight: 800; }
|
||||||
|
.intelligence-card-action p { margin: 4px 0 0; color: var(--ink-secondary); font-size: 12px; line-height: 1.55; }
|
||||||
|
.intelligence-card-relevance { display: grid; gap: 5px; margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--line); color: var(--ink-secondary); font-size: 11px; line-height: 1.5; }
|
||||||
|
.today-briefing { position: relative; grid-column: 1 / -1; display: flex; align-items: baseline; justify-content: space-between; gap: 16px; overflow: hidden; padding: 18px 20px; border: 0; background: var(--intel-dopamine-gradient); box-shadow: 0 12px 32px rgba(50, 72, 180, .18); isolation: isolate; }
|
||||||
|
.today-briefing::before { position: absolute; inset: 0; z-index: -1; background: linear-gradient(90deg, rgba(4, 13, 31, .2), transparent 48%, rgba(255, 255, 255, .14)); content: ""; }
|
||||||
|
.today-briefing strong { color: #fff; font-size: 18px; text-shadow: 0 1px 2px rgba(0, 0, 0, .24); }
|
||||||
|
.today-briefing span { max-width: 58%; color: rgba(255, 255, 255, .92); font-size: 14px; line-height: 1.5; text-align: right; }
|
||||||
|
.intelligence-card-footer { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 10px 14px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
|
||||||
|
.intelligence-card-footer-actions, .calendar-event-actions, .policy-card-actions, .standard-card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
|
||||||
|
.intelligence-card-proof { min-width: 0; }
|
||||||
|
.intelligence-card-proof strong, .intelligence-card-proof span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.intelligence-card-proof strong { color: var(--ink); font-size: 11px; }
|
||||||
|
.intelligence-card-proof span { margin-top: 2px; color: var(--muted); font-size: 9px; }
|
||||||
|
.intelligence-source-link { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; min-height: 40px; padding: 0 12px; border: 1px solid var(--line); background: var(--panel-solid); color: var(--intel-brand-blue); font-size: 11px; font-weight: 800; text-decoration: none; }
|
||||||
|
.intelligence-source-link:hover, .intelligence-source-link:focus-visible { border-color: var(--intel-brand-blue); background: var(--intel-soft); text-decoration: none; }
|
||||||
|
.intelligence-item-share { display: inline-grid; width: 44px; min-width: 44px; height: 44px; padding: 0; place-items: center; border: 1px solid var(--line); background: var(--panel-solid); color: var(--ink-secondary); cursor: pointer; }
|
||||||
|
.intelligence-item-share svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
||||||
|
.intelligence-item-share:hover, .intelligence-item-share:focus-visible { border-color: var(--intel-brand-blue); background: var(--intel-soft); color: var(--intel-brand-blue); }
|
||||||
|
.intelligence-load-more { grid-column: 1 / -1; min-height: 44px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel-solid); color: var(--ink); cursor: pointer; }
|
||||||
|
.intelligence-load-more:hover { border-color: var(--intel-brand-blue); color: var(--intel-brand-blue); }
|
||||||
|
.intelligence-empty { grid-column: 1 / -1; padding: 48px 20px; border: 1px dashed var(--line); color: var(--muted); text-align: center; }
|
||||||
|
|
||||||
|
.intelligence-skeleton { display: grid; align-content: end; gap: 12px; min-height: 270px; padding: 22px; border: 1px solid var(--line); background: linear-gradient(145deg, color-mix(in srgb, var(--panel-solid) 93%, var(--intel-brand-blue)), var(--panel-solid)); }
|
||||||
|
.intelligence-skeleton-line { display: block; width: 100%; height: 14px; overflow: hidden; background: color-mix(in srgb, var(--muted) 16%, transparent); }
|
||||||
|
.intelligence-skeleton-line::after { display: block; width: 48%; height: 100%; background: linear-gradient(90deg, transparent, color-mix(in srgb, #fff 62%, transparent), transparent); animation: intelligence-shimmer 1.35s ease-in-out infinite; content: ""; transform: translateX(-120%); }
|
||||||
|
.intelligence-skeleton-line.is-short { width: 34%; height: 12px; }
|
||||||
|
.intelligence-skeleton-line.is-title { width: 76%; height: 28px; }
|
||||||
|
.intelligence-list > :not(.today-briefing) { animation: intelligence-content-in .24s ease both; }
|
||||||
|
|
||||||
|
@keyframes intelligence-shimmer { to { transform: translateX(280%); } }
|
||||||
|
@keyframes intelligence-content-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
|
||||||
|
|
||||||
|
/* 备货日历:按市场文化和备货阶段组织,不复用资讯海报卡。 */
|
||||||
|
.intelligence-list.is-calendar,
|
||||||
|
.intelligence-list.is-exhibitions,
|
||||||
|
.intelligence-list.is-policies,
|
||||||
|
.intelligence-list.is-standards { display: block; }
|
||||||
|
|
||||||
|
.calendar-planner {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 24px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: linear-gradient(120deg, color-mix(in srgb, var(--intel-brand-blue) 8%, var(--panel-solid)), color-mix(in srgb, var(--intel-brand-green) 10%, var(--panel-solid)));
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-planner-copy { max-width: 720px; }
|
||||||
|
.calendar-planner-eyebrow { margin: 0 0 7px; color: var(--intel-brand-blue); font-size: 11px; font-weight: 800; text-transform: uppercase; }
|
||||||
|
.calendar-planner h3 { margin: 0; color: var(--ink); font-size: 26px; letter-spacing: 0; }
|
||||||
|
.calendar-planner-copy > p:last-child { margin: 8px 0 0; color: var(--ink-secondary); font-size: 13px; line-height: 1.6; }
|
||||||
|
.calendar-year-switch, .policy-scope-switch { display: inline-flex; gap: 3px; padding: 3px; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.calendar-year-btn, .policy-scope-btn { min-height: 34px; padding: 0 12px; border: 0; background: transparent; color: var(--muted); font-size: 12px; font-weight: 800; cursor: pointer; }
|
||||||
|
.calendar-year-btn:hover, .policy-scope-btn:hover { color: var(--ink); }
|
||||||
|
.calendar-year-btn.active { background: var(--intel-brand-gradient); color: #fff; }
|
||||||
|
|
||||||
|
.calendar-decision-toolbar {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: var(--panel-solid);
|
||||||
|
}
|
||||||
|
.calendar-filter-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
|
||||||
|
.calendar-mode-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding-top: 2px; border-top: 1px solid var(--line); }
|
||||||
|
.calendar-mode-row .calendar-year-switch { margin-left: auto; }
|
||||||
|
.calendar-platform-filter-hint { grid-column: 1 / -1; margin: 0; padding-top: 2px; color: var(--muted); font-size: 13px; line-height: 1.55; }
|
||||||
|
.calendar-scope-switch { display: inline-flex; align-items: center; gap: 3px; padding: 3px; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.calendar-scope-btn { min-height: 38px; padding: 0 13px; border: 0; background: transparent; color: var(--muted); font-size: 12px; font-weight: 800; cursor: pointer; }
|
||||||
|
.calendar-scope-btn.active { background: var(--intel-brand-gradient); color: #fff; }
|
||||||
|
.calendar-filter-field { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 9px; min-width: 0; color: var(--muted); font-size: 11px; font-weight: 700; }
|
||||||
|
.calendar-filter-select { width: 100%; min-height: 38px; padding: 0 34px 0 10px; border: 1px solid var(--line); background: var(--panel-solid); color: var(--ink); font: inherit; cursor: pointer; }
|
||||||
|
|
||||||
|
.calendar-month-rail {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 10px 0 14px;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-month-btn { display: grid; flex: 0 0 auto; min-width: 82px; min-height: 52px; padding: 7px 12px; border: 1px solid transparent; place-content: center; background: transparent; color: var(--muted); font-size: 12px; font-weight: 700; cursor: pointer; }
|
||||||
|
.calendar-month-btn strong { color: inherit; font-size: 16px; }
|
||||||
|
.calendar-month-count { color: var(--muted); font-size: 12px; font-weight: 700; }
|
||||||
|
.calendar-month-btn:hover { color: var(--ink); background: var(--trans-bg); }
|
||||||
|
.calendar-month-btn.active { border-color: color-mix(in srgb, var(--intel-brand-blue) 45%, var(--line)); background: var(--intel-soft); color: var(--intel-brand-blue); }
|
||||||
|
.calendar-month-grid-wrap { margin: 16px 0; overflow: hidden; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.calendar-month-grid-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--line); }
|
||||||
|
.calendar-month-grid-heading h3 { margin: 0; color: var(--ink); font-size: 22px; }
|
||||||
|
.calendar-month-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
|
||||||
|
.calendar-weekday { padding: 9px; border-bottom: 1px solid var(--line); background: var(--intel-soft); color: var(--ink-secondary); font-size: 13px; font-weight: 800; text-align: center; }
|
||||||
|
.calendar-day { min-width: 0; min-height: 104px; padding: 8px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--card-trans-bg); }
|
||||||
|
.calendar-day:nth-child(7n) { border-right: 0; }
|
||||||
|
.calendar-day.is-empty { background: var(--trans-bg); }
|
||||||
|
.calendar-day-number { display: block; margin-bottom: 6px; color: var(--muted); font-size: 13px; font-weight: 800; }
|
||||||
|
.calendar-day-event { display: block; margin-top: 5px; padding: 5px 7px; border-left: 3px solid var(--intel-brand-blue); background: color-mix(in srgb, var(--intel-brand-blue) 8%, var(--panel-solid)); color: var(--ink); font-size: 12px; font-weight: 700; line-height: 1.35; text-decoration: none; }
|
||||||
|
.calendar-day-event.is-high { border-left-color: var(--intel-brand-green); }
|
||||||
|
.calendar-month-section { margin-top: 24px; }
|
||||||
|
.calendar-month-heading { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
|
||||||
|
.calendar-month-heading h3 { margin: 0; color: var(--ink); font-size: 22px; }
|
||||||
|
.calendar-month-heading span { color: var(--muted); font-size: 11px; }
|
||||||
|
.calendar-event-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
||||||
|
.calendar-event-grid.is-insights { grid-template-columns: 1fr; }
|
||||||
|
|
||||||
|
.calendar-event-card {
|
||||||
|
--culture-accent: #0051d6;
|
||||||
|
--culture-ink: #102a43;
|
||||||
|
--culture-paper: #eef7ff;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 126px minmax(0, 1fr);
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: var(--card-trans-bg);
|
||||||
|
transition: border-color 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-event-card:hover { border-color: var(--culture-accent); transform: translateY(-2px); }
|
||||||
|
.calendar-opportunity-card { grid-template-columns: 128px minmax(0, 1fr); }
|
||||||
|
.calendar-opportunity-card[data-relevance="low"] { opacity: 0.86; }
|
||||||
|
.calendar-event-card[data-culture="china"] { --culture-accent: #0051d6; --culture-ink: #102a43; --culture-paper: #eef7ff; }
|
||||||
|
.calendar-event-card[data-culture="japan"] { --culture-accent: #4776d0; --culture-ink: #172b4d; --culture-paper: #f2f6ff; }
|
||||||
|
.calendar-event-card[data-culture="korea"] { --culture-accent: #315d9c; --culture-ink: #151b25; --culture-paper: #f1f6fb; }
|
||||||
|
.calendar-event-card[data-culture="north-america"] { --culture-accent: #1677a6; --culture-ink: #12334a; --culture-paper: #edf8fc; }
|
||||||
|
.calendar-event-card[data-culture="british-isles"] { --culture-accent: #365b9d; --culture-ink: #153561; --culture-paper: #f1f5fb; }
|
||||||
|
.calendar-event-card[data-culture="central-europe"] { --culture-accent: #2f6b63; --culture-ink: #182722; --culture-paper: #edf8f5; }
|
||||||
|
.calendar-event-card[data-culture="southern-europe"] { --culture-accent: #4a78a8; --culture-ink: #18384f; --culture-paper: #f1f7fb; }
|
||||||
|
.calendar-event-card[data-culture="nordic"] { --culture-accent: #3d7f91; --culture-ink: #183d49; --culture-paper: #eef7f8; }
|
||||||
|
.calendar-event-card[data-culture="oceania"] { --culture-accent: #168b83; --culture-ink: #164f4a; --culture-paper: #edf9f7; }
|
||||||
|
.calendar-event-card[data-culture="southeast-asia"] { --culture-accent: #0f8f78; --culture-ink: #105d5b; --culture-paper: #ecfaf6; }
|
||||||
|
.calendar-event-card[data-culture="latin-america"] { --culture-accent: #5568c9; --culture-ink: #273266; --culture-paper: #f1f2ff; }
|
||||||
|
.calendar-event-card[data-culture="southern-africa"] { --culture-accent: #3f7c69; --culture-ink: #123d32; --culture-paper: #eff8f3; }
|
||||||
|
.calendar-event-card[data-culture="turkiye"] { --culture-accent: #3e7194; --culture-ink: #17384a; --culture-paper: #eef6fa; }
|
||||||
|
.calendar-event-card[data-culture="islamic"] { --culture-accent: #16836f; --culture-ink: #0e534a; --culture-paper: #edf9f5; }
|
||||||
|
.calendar-event-card[data-culture="sport"] { --culture-accent: #1976a8; --culture-ink: #17324d; --culture-paper: #eef7fb; }
|
||||||
|
.calendar-event-card[data-culture="retail"] { --culture-accent: #0051d6; --culture-ink: #102a43; --culture-paper: #eef7ff; }
|
||||||
|
|
||||||
|
.calendar-date-block {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 17px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--culture-paper);
|
||||||
|
color: var(--culture-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-date-block::after {
|
||||||
|
position: absolute;
|
||||||
|
right: -20px;
|
||||||
|
bottom: -16px;
|
||||||
|
width: 96px;
|
||||||
|
height: 96px;
|
||||||
|
border: 12px double color-mix(in srgb, var(--culture-accent) 58%, transparent);
|
||||||
|
content: "";
|
||||||
|
transform: rotate(32deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-event-card[data-culture="islamic"] .calendar-date-block::after { border-style: solid double; transform: rotate(45deg); }
|
||||||
|
.calendar-event-card[data-culture="nordic"] .calendar-date-block::after { width: 116px; height: 18px; border-width: 5px 0; transform: rotate(-45deg); }
|
||||||
|
.calendar-event-card[data-culture="retail"] .calendar-date-block::after { width: 130px; height: 36px; border-width: 8px 0; transform: rotate(-24deg); }
|
||||||
|
.calendar-date-year, .calendar-date-month, .calendar-date-weekday, .calendar-culture-label { position: relative; z-index: 1; font-size: 10px; font-weight: 800; }
|
||||||
|
.calendar-date-month { margin-top: 14px; color: var(--culture-accent); font-size: 13px; }
|
||||||
|
.calendar-date-day { position: relative; z-index: 1; margin-top: 2px; font-size: 42px; line-height: 1; }
|
||||||
|
.calendar-date-weekday { margin-top: 4px; }
|
||||||
|
.calendar-culture-label { margin-top: auto; padding-top: 30px; line-height: 1.35; }
|
||||||
|
.calendar-event-content { min-width: 0; padding: 17px; }
|
||||||
|
.calendar-opportunity-card .calendar-event-content { padding: 21px 22px; }
|
||||||
|
.calendar-event-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
|
||||||
|
.calendar-stage {
|
||||||
|
border: 1px solid color-mix(in srgb, var(--culture-accent) 34%, var(--line));
|
||||||
|
background: color-mix(in srgb, var(--culture-accent) 18%, var(--panel-solid));
|
||||||
|
color: color-mix(in srgb, var(--culture-accent) 44%, var(--ink));
|
||||||
|
}
|
||||||
|
.calendar-event-region { margin-left: auto; color: var(--muted); font-size: 10px; }
|
||||||
|
.calendar-event-title { margin: 10px 0 4px; color: var(--ink); font-size: 18px; line-height: 1.35; }
|
||||||
|
.calendar-opportunity-card .calendar-event-title { font-size: 23px; line-height: 1.3; text-wrap: pretty; }
|
||||||
|
.calendar-event-original { margin: 0 0 7px; color: var(--muted); font-size: 10px; line-height: 1.4; }
|
||||||
|
.calendar-event-context { margin: 0; color: var(--ink-secondary); font-size: 12px; }
|
||||||
|
.calendar-decision.is-high {
|
||||||
|
border: 1px solid color-mix(in srgb, var(--intel-brand-green) 34%, var(--line));
|
||||||
|
background: color-mix(in srgb, var(--intel-brand-green) 18%, var(--panel-solid));
|
||||||
|
color: color-mix(in srgb, var(--intel-brand-green) 38%, var(--ink));
|
||||||
|
}
|
||||||
|
.calendar-decision.is-medium {
|
||||||
|
border: 1px solid color-mix(in srgb, var(--intel-brand-blue) 30%, var(--line));
|
||||||
|
background: color-mix(in srgb, var(--intel-brand-blue) 14%, var(--panel-solid));
|
||||||
|
color: color-mix(in srgb, var(--intel-brand-blue) 42%, var(--ink));
|
||||||
|
}
|
||||||
|
.calendar-decision.is-low { border: 1px solid var(--line); color: var(--muted); background: var(--trans-bg); }
|
||||||
|
.calendar-section-label { display: block; color: var(--culture-accent); font-size: 10px; font-weight: 900; }
|
||||||
|
.calendar-explanation { margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--line); }
|
||||||
|
.calendar-explanation p { margin: 5px 0 0; color: var(--ink-secondary); font-size: 13px; line-height: 1.7; text-wrap: pretty; }
|
||||||
|
.calendar-fact-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; margin-top: 14px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
|
||||||
|
.calendar-fact { min-width: 0; padding: 11px 12px 11px 0; }
|
||||||
|
.calendar-fact + .calendar-fact { padding-left: 12px; border-left: 1px solid var(--line); }
|
||||||
|
.calendar-fact span, .calendar-fact strong { display: block; }
|
||||||
|
.calendar-fact span { color: var(--muted); font-size: 9px; }
|
||||||
|
.calendar-fact strong { margin-top: 4px; color: var(--ink); font-size: 11px; line-height: 1.5; }
|
||||||
|
.calendar-business-panel { margin-top: 14px; }
|
||||||
|
.calendar-consumption-scenes { margin: 5px 0 0; color: var(--ink-secondary); font-size: 12px; }
|
||||||
|
.calendar-guidance-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--line); }
|
||||||
|
.calendar-guidance p { margin: 5px 0 0; color: var(--ink-secondary); font-size: 11px; line-height: 1.6; }
|
||||||
|
.calendar-guidance.is-caution .calendar-section-label { color: var(--muted); }
|
||||||
|
.calendar-platform-panel { margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--line); }
|
||||||
|
.calendar-platform-action { display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 10px; padding: 9px 0; }
|
||||||
|
.calendar-platform-action + .calendar-platform-action { border-top: 1px dashed var(--line); }
|
||||||
|
.calendar-platform-action strong { color: var(--ink); font-size: 11px; }
|
||||||
|
.calendar-platform-action p { margin: 0; color: var(--ink-secondary); font-size: 11px; line-height: 1.55; }
|
||||||
|
.calendar-action-box { margin-top: 14px; padding: 12px 13px; background: color-mix(in srgb, var(--culture-accent) 8%, var(--trans-bg)); }
|
||||||
|
.calendar-action-box .calendar-stock-window-title { padding-bottom: 9px; border-bottom: 1px solid var(--line); }
|
||||||
|
.calendar-next-action { margin-top: 9px; }
|
||||||
|
.calendar-next-action p { margin: 4px 0 0; color: var(--ink); font-size: 12px; line-height: 1.6; }
|
||||||
|
.calendar-stock-window { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
|
||||||
|
.calendar-stock-window-title { display: flex; justify-content: space-between; gap: 10px; color: var(--muted); font-size: 10px; }
|
||||||
|
.calendar-stock-window-title strong { color: var(--ink); font-weight: 700; }
|
||||||
|
.calendar-stock-track { height: 4px; margin-top: 7px; overflow: hidden; background: var(--trans-bg); }
|
||||||
|
.calendar-stock-progress { display: block; width: 68%; height: 100%; background: var(--culture-accent); }
|
||||||
|
.calendar-product-tags, .exhibition-focus-tags, .policy-affected-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }
|
||||||
|
.intelligence-tag { padding: 3px 7px; border: 1px solid var(--line); color: var(--ink-secondary); font-size: 10px; }
|
||||||
|
.intelligence-tag.is-platform { border-color: rgba(91, 141, 239, 0.45); color: #77a3ff; }
|
||||||
|
.calendar-event-footer { display: grid; grid-template-columns: minmax(0, 1fr) minmax(320px, auto); align-items: center; gap: 10px 16px; margin-top: 13px; padding-top: 12px; border-top: 1px solid var(--line); }
|
||||||
|
.calendar-event-source { min-width: 0; }
|
||||||
|
.calendar-event-source strong, .calendar-event-source span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.calendar-event-source strong { color: var(--ink); font-size: 10px; }
|
||||||
|
.calendar-event-source span { color: var(--muted); font-size: 9px; }
|
||||||
|
.calendar-opportunity-card .calendar-event-actions { flex-wrap: wrap; justify-content: flex-end; }
|
||||||
|
.calendar-event-actions { justify-content: flex-end; }
|
||||||
|
.calendar-event-actions > * { white-space: nowrap; }
|
||||||
|
.calendar-download { min-width: 156px; min-height: 30px; padding: 0 12px; border: 1px solid var(--line); white-space: nowrap; }
|
||||||
|
|
||||||
|
/* 展会通:报名、观展、翻译和行程准备闭环。 */
|
||||||
|
.scene-summary { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 15px 17px; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.scene-summary strong { color: var(--ink); font-size: 14px; }
|
||||||
|
.scene-summary span { color: var(--muted); font-size: 11px; text-align: right; }
|
||||||
|
.exhibition-grid, .policy-grid, .standards-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; gap: 14px; margin-top: 14px; }
|
||||||
|
.exhibition-card, .policy-card, .standard-card { min-width: 0; overflow: hidden; border: 1px solid var(--line); background: var(--card-trans-bg); }
|
||||||
|
.exhibition-card { display: grid; grid-template-columns: minmax(165px, 36%) minmax(0, 1fr); align-self: start; }
|
||||||
|
.exhibition-card-visual { min-height: 220px; aspect-ratio: auto; }
|
||||||
|
.exhibition-card-body { min-width: 0; padding: 17px; }
|
||||||
|
.exhibition-card-meta { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||||
|
.exhibition-relevance { color: #d9c77c; background: rgba(217, 199, 124, 0.12); }
|
||||||
|
.exhibition-card-title { margin: 11px 0 6px; color: var(--ink); font-size: 18px; line-height: 1.35; }
|
||||||
|
.exhibition-card-original { display: -webkit-box; overflow: hidden; margin: -1px 0 7px; color: var(--muted); font-size: 10px; line-height: 1.45; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
|
||||||
|
.exhibition-card-venue { margin: 0; color: var(--muted); font-size: 11px; line-height: 1.5; }
|
||||||
|
.exhibition-checklist { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 12px; margin: 13px 0 0; padding: 11px 11px 11px 28px; border-left: 3px solid #5b8def; background: var(--trans-bg); color: var(--ink-secondary); font-size: 11px; line-height: 1.5; }
|
||||||
|
.exhibition-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin-top: 13px; }
|
||||||
|
.exhibition-action { display: inline-flex; align-items: center; min-height: 32px; padding: 0 9px; border: 1px solid var(--line); color: var(--ink-secondary); font-size: 10px; font-weight: 800; text-decoration: none; }
|
||||||
|
.exhibition-action:hover { border-color: #5b8def; color: #8db0ff; }
|
||||||
|
.exhibition-action.primary { border-color: #5b8def; background: #5b8def; color: #0d1422; }
|
||||||
|
.exhibition-action.translate { border-color: #20b486; color: #36c99a; }
|
||||||
|
.exhibition-recommendation { margin-top: 13px; padding: 11px 12px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
|
||||||
|
.exhibition-recommendation strong { color: #7fb0ff; font-size: 12px; }
|
||||||
|
.exhibition-recommendation p { margin: 4px 0 0; color: var(--ink-secondary); font-size: 11px; line-height: 1.6; }
|
||||||
|
.exhibition-proof { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px; margin-top: 13px; padding-top: 10px; border-top: 1px solid var(--line); }
|
||||||
|
.exhibition-proof strong, .exhibition-proof span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.exhibition-proof strong { color: var(--ink); font-size: 10px; }
|
||||||
|
.exhibition-proof span { color: var(--muted); font-size: 9px; }
|
||||||
|
|
||||||
|
/* 政策预警:地区、平台、知识产权与产品安全分流。 */
|
||||||
|
.policy-scope-switch { max-width: 100%; overflow-x: auto; margin-bottom: 10px; border-color: var(--line); background: var(--panel-solid); -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
.policy-scope-btn { flex: 0 0 auto; min-height: 44px; padding: 0 14px; color: var(--muted); font-size: 15px; }
|
||||||
|
.policy-scope-btn.active { background: #147566; color: #fff; }
|
||||||
|
.policy-summary { border-left: 3px solid #147566; }
|
||||||
|
.policy-card { padding: 17px; }
|
||||||
|
.policy-card-header, .policy-card-footer { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
|
||||||
|
.policy-card-meta { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||||
|
.policy-changed { color: #f0aa3c; background: rgba(240, 170, 60, 0.13); }
|
||||||
|
.policy-card-date { flex: 0 0 auto; color: var(--muted); font-size: 9px; }
|
||||||
|
.policy-card-title { margin: 11px 0 6px; color: var(--ink); font-size: 17px; line-height: 1.4; }
|
||||||
|
.policy-card-original { display: -webkit-box; overflow: hidden; margin: 0 0 8px; color: var(--muted); font-size: 10px; line-height: 1.45; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
|
||||||
|
.policy-card-summary { display: -webkit-box; overflow: hidden; margin: 0; color: var(--ink-secondary); font-size: 12px; line-height: 1.6; -webkit-box-orient: vertical; -webkit-line-clamp: 4; }
|
||||||
|
.policy-action { margin-top: 12px; padding: 10px 11px; border-left: 3px solid #147566; background: var(--trans-bg); }
|
||||||
|
.policy-change-summary, .policy-consequence, .policy-action { margin-top: 12px; padding: 10px 11px; background: var(--trans-bg); }
|
||||||
|
.policy-change-summary { border-left: 3px solid #e2b765; }
|
||||||
|
.policy-consequence { border-left: 3px solid #ef8b75; }
|
||||||
|
.policy-change-summary span, .policy-consequence span, .policy-action span { color: #ff7777; font-size: 10px; font-weight: 800; }
|
||||||
|
.policy-change-summary span { color: #e2b765; }
|
||||||
|
.policy-change-summary p, .policy-consequence p, .policy-action p { margin: 4px 0 0; color: var(--ink-secondary); font-size: 11px; line-height: 1.55; }
|
||||||
|
.policy-translate { border-color: #20b486; color: #36c99a; }
|
||||||
|
.policy-card-footer { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; margin-top: 13px; padding-top: 10px; border-top: 1px solid var(--line); }
|
||||||
|
.policy-card-actions { justify-content: flex-end; }
|
||||||
|
.policy-proof { min-width: 0; }
|
||||||
|
.policy-proof strong, .policy-proof span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.policy-proof strong { color: var(--ink); font-size: 10px; }
|
||||||
|
.policy-proof span { color: var(--muted); font-size: 9px; }
|
||||||
|
|
||||||
|
/* 趋势雷达:权威结论与产品应用并排。 */
|
||||||
|
.standards-summary { border-left: 3px solid #d46aa0; }
|
||||||
|
.standard-card { display: grid; grid-template-columns: minmax(180px, 38%) minmax(0, 1fr); }
|
||||||
|
.standard-card .intelligence-card-visual { min-height: 100%; aspect-ratio: auto; }
|
||||||
|
.standard-card-body { padding: 17px; }
|
||||||
|
.standard-card-badges { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||||
|
.standard-card-body h3 { margin: 11px 0 7px; color: var(--ink); font-size: 18px; line-height: 1.4; }
|
||||||
|
.standard-card-body > p { margin: 0; color: var(--ink-secondary); font-size: 12px; line-height: 1.6; }
|
||||||
|
.standard-application { margin-top: 13px; padding: 10px 11px; border-left: 3px solid #d46aa0; background: var(--trans-bg); }
|
||||||
|
.standard-application span { color: #e782b7; font-size: 10px; font-weight: 800; }
|
||||||
|
.standard-application p { margin: 4px 0 0; color: var(--ink-secondary); font-size: 11px; line-height: 1.55; }
|
||||||
|
.standard-decision-note { display: block; margin-top: 9px; color: #e7c16f; font-size: 10px; line-height: 1.5; }
|
||||||
|
.standard-swatches { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; margin-top: 13px; }
|
||||||
|
.standard-swatch { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 2px 8px; align-items: center; min-width: 0; padding: 7px; border: 1px solid var(--line); }
|
||||||
|
.standard-swatch-color { grid-row: 1 / 3; width: 24px; height: 24px; background: var(--swatch-color); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.16); }
|
||||||
|
.standard-swatch strong, .standard-swatch small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.standard-swatch strong { color: var(--ink); font-size: 10px; }
|
||||||
|
.standard-swatch small { color: var(--muted); font-size: 9px; }
|
||||||
|
.standard-task-list { margin: 12px 0 0; padding: 10px 10px 10px 27px; background: var(--trans-bg); color: var(--ink-secondary); font-size: 10px; line-height: 1.55; }
|
||||||
|
.standard-download { border-color: #d46aa0; color: #e782b7; }
|
||||||
|
.standard-card-actions { justify-content: flex-end; margin-top: 13px; }
|
||||||
|
|
||||||
|
@media (max-width: 1080px) {
|
||||||
|
.intelligence-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
.intelligence-list.is-today { column-count: 2; }
|
||||||
|
.intelligence-tabs { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
||||||
|
.intelligence-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||||
|
.calendar-event-grid, .exhibition-grid, .policy-grid, .standards-grid { grid-template-columns: 1fr; }
|
||||||
|
.calendar-filter-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 680px) {
|
||||||
|
.shell.is-textile { width: 100%; }
|
||||||
|
.site-shell.textile-wrap { width: calc(100% - 24px); }
|
||||||
|
.textile-wrap { width: 100%; margin-left: 0; transform: none; }
|
||||||
|
.intelligence-panel { display: flex; flex-direction: column; }
|
||||||
|
.intelligence-overview { order: 1; }
|
||||||
|
.intelligence-tabs { order: 2; }
|
||||||
|
.intelligence-toolbar { order: 3; }
|
||||||
|
.intelligence-stats { order: 4; }
|
||||||
|
.intelligence-list { order: 5; }
|
||||||
|
.intelligence-overview { align-items: flex-start; flex-direction: column; }
|
||||||
|
.intelligence-overview h3 { font-size: 22px; }
|
||||||
|
.intelligence-overview-actions { width: 100%; justify-content: space-between; }
|
||||||
|
.intelligence-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
.intelligence-toolbar { grid-template-columns: 1fr; }
|
||||||
|
.intelligence-list { grid-template-columns: 1fr; }
|
||||||
|
.intelligence-list.is-today { column-count: 1; }
|
||||||
|
.today-briefing { align-items: flex-start; flex-direction: column; gap: 5px; }
|
||||||
|
.today-briefing span { max-width: none; text-align: left; }
|
||||||
|
.intelligence-card-visual { aspect-ratio: 16 / 8.8; }
|
||||||
|
.intelligence-poster-title { font-size: 18px; }
|
||||||
|
.calendar-planner, .scene-summary { align-items: flex-start; flex-direction: column; }
|
||||||
|
.calendar-year-switch { width: 100%; }
|
||||||
|
.calendar-year-btn { flex: 1; }
|
||||||
|
.calendar-event-card { grid-template-columns: 94px minmax(0, 1fr); }
|
||||||
|
.calendar-filter-row { grid-template-columns: 1fr; }
|
||||||
|
.calendar-mode-row { display: grid; grid-template-columns: 1fr; }
|
||||||
|
.calendar-mode-row .calendar-year-switch { width: 100%; margin-left: 0; }
|
||||||
|
.calendar-scope-switch { width: 100%; }
|
||||||
|
.calendar-scope-btn { flex: 1; min-height: 44px; }
|
||||||
|
.calendar-filter-field { grid-template-columns: 1fr; gap: 5px; }
|
||||||
|
.calendar-filter-select { min-height: 44px; }
|
||||||
|
.calendar-date-block { padding: 13px 11px; }
|
||||||
|
.calendar-date-day { font-size: 34px; }
|
||||||
|
.calendar-event-content { padding: 14px; }
|
||||||
|
.calendar-opportunity-card .calendar-event-content { padding: 16px; }
|
||||||
|
.calendar-opportunity-card .calendar-event-title { font-size: 20px; }
|
||||||
|
.calendar-fact-grid, .calendar-guidance-grid { grid-template-columns: 1fr; }
|
||||||
|
.calendar-platform-action { grid-template-columns: 1fr; gap: 4px; }
|
||||||
|
.calendar-fact { padding: 10px 0; }
|
||||||
|
.calendar-fact + .calendar-fact { padding-left: 0; border-top: 1px solid var(--line); border-left: 0; }
|
||||||
|
.calendar-stock-window-title { align-items: flex-start; flex-direction: column; gap: 2px; }
|
||||||
|
.calendar-event-footer, .policy-card-footer, .intelligence-card-footer { grid-template-columns: 1fr; align-items: start; }
|
||||||
|
.calendar-event-actions, .policy-card-actions { width: 100%; justify-content: flex-start; }
|
||||||
|
.calendar-event-actions a, .calendar-event-actions button, .policy-card-actions a, .policy-card-actions button { min-height: 44px; }
|
||||||
|
.exhibition-card, .standard-card { grid-template-columns: 1fr; }
|
||||||
|
.exhibition-card-visual, .standard-card .intelligence-card-visual { min-height: 180px; aspect-ratio: 16 / 8.5; }
|
||||||
|
.exhibition-checklist { grid-template-columns: 1fr; }
|
||||||
|
.exhibition-actions .exhibition-action, .exhibition-actions .intelligence-item-share { min-height: 44px; padding: 0 10px; }
|
||||||
|
.scene-summary span { text-align: left; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.intelligence-panel, .intelligence-card, .intelligence-skeleton-line::after, .intelligence-list > * { animation: none; transition: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 40—50 岁经营者高可读模式:业务信息不使用小灰字。 */
|
||||||
|
.textile-head { align-items: flex-start; }
|
||||||
|
.textile-head-title { display: block; min-width: 0; }
|
||||||
|
.textile-head h2 { font-size: 28px; line-height: 1.25; text-wrap: balance; }
|
||||||
|
.textile-head-title p { max-width: 760px; margin: 8px 0 0; color: var(--ink-secondary); font-size: 16px; line-height: 1.7; }
|
||||||
|
.intelligence-panel { font-size: 16px; }
|
||||||
|
.intelligence-panel button, .intelligence-panel a, .intelligence-panel input, .intelligence-panel select { touch-action: manipulation; -webkit-tap-highlight-color: rgba(91, 141, 239, 0.2); }
|
||||||
|
.intelligence-overview p:last-child { color: var(--ink-secondary); font-size: 16px; line-height: 1.65; }
|
||||||
|
.intelligence-overview-actions { align-items: center; }
|
||||||
|
.intelligence-overview-actions > span { color: var(--ink-secondary); font-size: 13px; }
|
||||||
|
.intelligence-share-btn { display: inline-grid; width: 44px; min-width: 44px; height: 44px; padding: 0; place-items: center; border: 1px solid var(--line); background: transparent; color: var(--muted); font-size: 20px; }
|
||||||
|
.intelligence-share-btn:hover, .intelligence-share-btn:focus-visible { border-color: var(--ink-secondary); background: var(--trans-bg); color: var(--ink); }
|
||||||
|
.intelligence-search-field { display: grid; gap: 6px; min-width: 0; color: var(--ink-secondary); font-size: 14px; font-weight: 700; }
|
||||||
|
.intelligence-toolbar input, .intelligence-toolbar select { min-height: 48px; font-size: 16px; }
|
||||||
|
.intelligence-tab { min-height: 48px; font-size: 16px; }
|
||||||
|
.intelligence-tab-count, .intelligence-badge { font-size: 13px; }
|
||||||
|
.intelligence-card-title, .exhibition-card-title, .policy-card-title, .standard-card-body h3 { font-size: 20px; }
|
||||||
|
.intelligence-card-summary, .intelligence-card-relevance, .intelligence-card-action p,
|
||||||
|
.calendar-explanation p, .calendar-consumption-scenes, .calendar-guidance p,
|
||||||
|
.calendar-platform-action p, .calendar-next-action p, .exhibition-recommendation p,
|
||||||
|
.exhibition-checklist, .policy-card-summary, .policy-change-summary p,
|
||||||
|
.policy-consequence p, .policy-action p, .standard-card-body > p,
|
||||||
|
.standard-application p, .standard-task-list { font-size: 16px; line-height: 1.65; }
|
||||||
|
.calendar-section-label, .policy-change-summary span, .policy-consequence span,
|
||||||
|
.policy-action span, .standard-application span { font-size: 14px; }
|
||||||
|
.calendar-event-region, .calendar-event-original, .exhibition-card-original,
|
||||||
|
.exhibition-card-venue, .policy-card-date, .policy-card-original,
|
||||||
|
.intelligence-card-proof span, .calendar-event-source span, .exhibition-proof span,
|
||||||
|
.policy-proof span, .standard-decision-note { font-size: 13px; line-height: 1.55; }
|
||||||
|
.calendar-fact span, .calendar-event-source strong, .exhibition-proof strong,
|
||||||
|
.policy-proof strong, .standard-swatch small { font-size: 13px; }
|
||||||
|
.calendar-fact strong, .calendar-platform-action strong, .intelligence-tag,
|
||||||
|
.standard-swatch strong { font-size: 15px; }
|
||||||
|
.calendar-stock-window-title { font-size: 15px; }
|
||||||
|
.calendar-date-year, .calendar-date-weekday, .calendar-culture-label { font-size: 13px; }
|
||||||
|
.calendar-date-month { font-size: 16px; }
|
||||||
|
.calendar-event-actions a, .calendar-event-actions button, .policy-card-actions a,
|
||||||
|
.policy-card-actions button, .standard-card-actions a, .standard-card-actions button,
|
||||||
|
.intelligence-card-footer-actions a, .intelligence-card-footer-actions button,
|
||||||
|
.exhibition-action, .intelligence-source-link, .intelligence-item-share,
|
||||||
|
.standard-download { min-height: 44px; padding: 0 14px; font-size: 15px; font-weight: 800; }
|
||||||
|
.intelligence-item-share.is-tertiary { width: 44px; padding: 0; border-color: var(--line); background: var(--panel-solid); color: var(--muted); }
|
||||||
|
.policy-translate.is-fallback, .exhibition-action.is-fallback { border-style: dashed; }
|
||||||
|
.calendar-local-names { margin-top: 12px; border-left: 4px solid var(--culture-accent); background: color-mix(in srgb, var(--culture-accent) 7%, var(--trans-bg)); }
|
||||||
|
.calendar-local-names-summary { display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; gap: 8px; align-items: center; min-height: 48px; padding: 0 14px; cursor: pointer; list-style: none; }
|
||||||
|
.calendar-local-names-summary::-webkit-details-marker { display: none; }
|
||||||
|
.calendar-local-names-summary::before { content: "›"; color: var(--culture-accent); font-size: 22px; line-height: 1; transition: transform .16s ease; }
|
||||||
|
.calendar-local-names[open] .calendar-local-names-summary::before { transform: rotate(90deg); }
|
||||||
|
.calendar-local-names-summary:focus-visible { outline: 2px solid var(--culture-accent); outline-offset: -2px; }
|
||||||
|
.calendar-local-summary-name { min-width: 0; overflow: hidden; color: var(--ink); font-size: 15px; font-weight: 800; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.calendar-local-summary-count { color: var(--ink-secondary); font-size: 13px; white-space: nowrap; }
|
||||||
|
.calendar-local-names:not([open]) .calendar-local-name-list { display: none; }
|
||||||
|
.calendar-local-name-list { display: grid; gap: 9px; margin: 0; padding: 12px 14px 14px 40px; border-top: 1px solid color-mix(in srgb, var(--culture-accent) 20%, transparent); }
|
||||||
|
.calendar-local-name-row { display: grid; grid-template-columns: minmax(190px, 240px) minmax(0, 1fr); gap: 2px 12px; align-items: baseline; }
|
||||||
|
.calendar-local-name-row strong { color: var(--ink); font-size: 15px; }
|
||||||
|
.calendar-local-name { min-width: 0; color: var(--culture-accent); font-size: 18px; font-weight: 800; overflow-wrap: anywhere; }
|
||||||
|
.calendar-local-name-row small { grid-column: 2; color: var(--ink-secondary); font-size: 13px; line-height: 1.5; }
|
||||||
|
.calendar-date-variants { margin-top: 12px; padding: 12px 14px; border-left: 4px solid var(--culture-accent); background: color-mix(in srgb, var(--culture-accent) 5%, var(--card-trans-bg)); }
|
||||||
|
.calendar-date-variant-note { margin: 8px 0 10px; color: var(--ink-secondary); font-size: 15px; line-height: 1.7; }
|
||||||
|
.calendar-date-variant-list { display: grid; gap: 7px; }
|
||||||
|
.calendar-date-variant-row { display: grid; grid-template-columns: 90px 150px minmax(0, 1fr); gap: 10px; align-items: baseline; }
|
||||||
|
.calendar-date-variant-row strong { color: var(--ink); font-size: 16px; }
|
||||||
|
.calendar-date-variant-row span { color: var(--culture-accent); font-size: 15px; font-weight: 800; }
|
||||||
|
.calendar-date-variant-row small { color: var(--ink-secondary); font-size: 13px; }
|
||||||
|
|
||||||
|
.trend-search-hub { padding: 18px; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.trend-subtabs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin-bottom: 16px; padding: 10px; border: 1px solid var(--line-strong); background: var(--panel-solid); box-shadow: 0 8px 24px rgba(18, 39, 55, .08); }
|
||||||
|
.trend-subtab { display: flex; align-items: center; justify-content: space-between; min-height: 54px; padding: 0 15px; border: 1px solid var(--line); border-radius: 6px; background: var(--card-trans-bg); color: var(--ink-secondary); font-weight: 800; cursor: pointer; transition: border-color .18s ease, background-color .18s ease, color .18s ease, transform .18s ease; }
|
||||||
|
.trend-subtab strong { font-size: 16px; }
|
||||||
|
.trend-subtab span { font-size: 12px; }
|
||||||
|
.trend-subtab:hover { border-color: #218879; color: var(--ink); transform: translateY(-1px); }
|
||||||
|
.trend-subtab.active { border-color: #147566; background: #147566; color: #fff; box-shadow: 0 6px 16px rgba(20, 117, 102, .24); }
|
||||||
|
.trend-search-heading, .trend-news-summary { display: flex; justify-content: space-between; gap: 16px; align-items: baseline; }
|
||||||
|
.trend-search-heading strong { color: var(--ink); font-size: 20px; }
|
||||||
|
.trend-search-heading span { color: var(--ink-secondary); font-size: 14px; }
|
||||||
|
.trend-search-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 16px; }
|
||||||
|
.trend-search-card { min-width: 0; padding: 16px; border: 1px solid var(--line); background: var(--card-trans-bg); }
|
||||||
|
.trend-search-kicker { color: #d46aa0; font-size: 13px; font-weight: 800; }
|
||||||
|
.trend-search-card h3 { margin: 7px 0 4px; color: var(--ink); font-size: 18px; }
|
||||||
|
.trend-search-card p { min-height: 48px; margin: 0; color: var(--ink-secondary); font-size: 15px; line-height: 1.6; overflow-wrap: anywhere; }
|
||||||
|
.trend-search-keyword { display: block; margin-top: 8px; color: var(--muted); font: 13px/1.55 Inter, "Noto Sans SC", sans-serif; overflow-wrap: anywhere; }
|
||||||
|
.trend-search-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px; margin-top: 14px; }
|
||||||
|
.trend-news-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
|
||||||
|
.trend-search-button, .trend-news-button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 0 13px; border: 1px solid var(--line); color: var(--ink); font-size: 14px; font-weight: 800; text-decoration: none; }
|
||||||
|
.trend-search-button { min-width: 0; padding: 0 8px; white-space: nowrap; }
|
||||||
|
.trend-search-logo { display: block; flex: 0 0 22px; width: 22px; height: 22px; padding: 3px; border-radius: 4px; background: #fff; object-fit: contain; }
|
||||||
|
.trend-search-button.is-pinterest { border-color: #d63d45; color: #ec5961; }
|
||||||
|
.trend-search-button.is-bing { border-color: #3989bf; color: #5aa8db; }
|
||||||
|
.trend-search-button.is-google { border-color: #46a868; color: #64c784; }
|
||||||
|
.requires-cross-border-network { gap: 7px; }
|
||||||
|
.external-network-badge { display: inline-flex; align-items: center; min-height: 22px; padding: 0 6px; border: 1px solid #c8942f; border-radius: 4px; color: #a66e08; font-size: 12px; font-weight: 800; white-space: nowrap; }
|
||||||
|
.trend-news-summary { margin-top: 16px; }
|
||||||
|
.trend-news-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin-top: 14px; }
|
||||||
|
.trend-news-grid.is-gallery { display: block; column-count: 3; column-gap: 14px; }
|
||||||
|
.trend-news-grid.is-gallery .trend-news-card { display: inline-block; width: 100%; margin: 0 0 14px; break-inside: avoid; content-visibility: visible; }
|
||||||
|
.trend-news-grid.is-gallery .trend-news-visual { display: block; min-height: 0; aspect-ratio: auto; padding: 0; }
|
||||||
|
.trend-news-grid.is-gallery .trend-news-visual img { display: block; width: 100%; height: auto; object-fit: contain; }
|
||||||
|
.trend-gallery-zoom { display: block; width: 100%; padding: 0; border: 0; background: transparent; cursor: zoom-in; }
|
||||||
|
.trend-gallery-zoom img { pointer-events: none; }
|
||||||
|
.lightbox-overlay { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; overflow: hidden; padding: 18px; background: rgba(3, 9, 15, .88); backdrop-filter: blur(16px); opacity: 0; visibility: hidden; transition: opacity 180ms ease, visibility 180ms ease; }
|
||||||
|
.lightbox-overlay.active { opacity: 1; visibility: visible; }
|
||||||
|
.lightbox-content-wrapper { position: relative; display: grid; grid-template-rows: minmax(0, 1fr) auto; gap: 12px; width: min(1180px, 96vw); height: calc(100vh - 36px); height: calc(100dvh - 36px); max-height: 880px; }
|
||||||
|
.lightbox-stage { position: relative; min-height: 0; overflow: hidden; border: 1px solid rgba(255,255,255,.14); border-radius: 8px; background: #070b10; box-shadow: 0 20px 70px rgba(0,0,0,.46); }
|
||||||
|
.lightbox-preview, .lightbox-img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: contain; }
|
||||||
|
.lightbox-preview { opacity: .34; filter: blur(16px) saturate(.82); transform: scale(1.035); transition: opacity 220ms ease, filter 220ms ease; }
|
||||||
|
.lightbox-img { opacity: 0; transition: opacity 220ms ease; }
|
||||||
|
.lightbox-overlay.is-loaded .lightbox-img { opacity: 1; }
|
||||||
|
.lightbox-overlay.is-loaded .lightbox-preview { opacity: 0; }
|
||||||
|
.lightbox-overlay.is-error .lightbox-preview { opacity: 1; filter: none; transform: none; }
|
||||||
|
.lightbox-loader { position: absolute; top: 50%; left: 50%; z-index: 2; display: grid; min-width: 190px; padding: 20px 24px 18px; place-items: center; gap: 13px; border: 1px solid rgba(255,255,255,.2); border-radius: 8px; background: rgba(8,17,24,.72); color: #fff; box-shadow: 0 16px 44px rgba(0,0,0,.38); backdrop-filter: blur(16px); transform: translate(-50%, -50%); transition: opacity 180ms ease, visibility 180ms ease, transform 180ms ease; }
|
||||||
|
.lightbox-overlay.is-loaded .lightbox-loader { opacity: 0; visibility: hidden; transform: translate(-50%, -46%); }
|
||||||
|
.lightbox-loader-logo-wrap { position: relative; display: grid; width: 58px; height: 58px; place-items: center; }
|
||||||
|
.lightbox-loader-logo-wrap::before { position: absolute; inset: -9px; border: 2px solid rgba(18,238,168,.24); border-top-color: #12eea8; border-right-color: #0051d6; border-radius: 50%; content: ""; animation: lightbox-logo-spin 1.25s linear infinite; }
|
||||||
|
.lightbox-loader-logo { display: block; width: 52px; height: 52px; object-fit: contain; }
|
||||||
|
.lightbox-loader-status { font-size: 13px; font-weight: 700; }
|
||||||
|
.lightbox-retry { min-height: 34px; padding: 0 14px; border: 1px solid rgba(255,255,255,.34); border-radius: 6px; background: rgba(255,255,255,.12); color: #fff; cursor: pointer; }
|
||||||
|
.lightbox-footer { display: flex; justify-content: center; }
|
||||||
|
.lightbox-download { display: inline-flex; min-height: 42px; padding: 0 17px; align-items: center; justify-content: center; gap: 8px; border: 1px solid rgba(18,238,168,.34); border-radius: 7px; background: rgba(255,255,255,.1); color: #fff; font-size: 13px; font-weight: 800; text-decoration: none; backdrop-filter: blur(12px); transition: background 160ms ease, border-color 160ms ease, transform 160ms ease; }
|
||||||
|
.lightbox-download > span:first-child { font-size: 19px; line-height: 1; }
|
||||||
|
.lightbox-download:hover, .lightbox-download:focus-visible { border-color: #12eea8; background: rgba(18,238,168,.14); transform: translateY(-1px); }
|
||||||
|
.lightbox-download.is-downloading { cursor: wait; opacity: .72; transform: none; }
|
||||||
|
.lightbox-close { position: absolute; top: 12px; right: 12px; z-index: 4; display: grid; width: 42px; height: 42px; padding: 0; place-items: center; border: 1px solid rgba(255,255,255,.3); border-radius: 6px; background: rgba(3,9,15,.58); color: #fff; font-size: 26px; cursor: pointer; backdrop-filter: blur(10px); }
|
||||||
|
@keyframes lightbox-logo-spin { to { transform: rotate(360deg); } }
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
/* 加载态必须保留进度信号;只关闭非必要的过渡动画。 */
|
||||||
|
.lightbox-loader-logo-wrap::before { animation: lightbox-logo-spin 1.8s linear infinite !important; }
|
||||||
|
.lightbox-preview, .lightbox-img, .lightbox-loader, .lightbox-download { transition: none; }
|
||||||
|
}
|
||||||
|
.trend-news-card { min-width: 0; overflow: hidden; border: 1px solid var(--line); background: var(--card-trans-bg); content-visibility: auto; contain-intrinsic-size: 460px; }
|
||||||
|
.trend-news-visual { display: grid; min-height: 190px; aspect-ratio: 16 / 10; padding: 18px; place-content: end start; background: var(--trans-bg); }
|
||||||
|
.trend-news-visual img { width: 100%; height: 100%; object-fit: cover; }
|
||||||
|
.trend-news-visual > span { color: var(--muted); font-size: 14px; }
|
||||||
|
.trend-news-visual > strong { margin-top: 6px; color: var(--ink); font-size: 20px; }
|
||||||
|
.trend-news-body { padding: 16px; }
|
||||||
|
.trend-news-source { margin-left: 8px; color: var(--ink-secondary); font-size: 13px; }
|
||||||
|
.trend-news-body h3 { margin: 12px 0 7px; color: var(--ink); font-size: 20px; line-height: 1.45; text-wrap: pretty; }
|
||||||
|
.trend-news-original, .trend-news-copy { display: -webkit-box; overflow: hidden; margin: 0 0 8px; color: var(--ink-secondary); font-size: 14px; line-height: 1.55; -webkit-box-orient: vertical; -webkit-line-clamp: 3; }
|
||||||
|
.trend-news-copy { font-size: 16px; -webkit-line-clamp: 4; }
|
||||||
|
.trend-news-button.primary { border-color: #5b8def; background: #5b8def; color: #07111e; }
|
||||||
|
.trend-news-button.translate { border-color: #20b486; color: #36c99a; }
|
||||||
|
.standard-swatches { grid-template-columns: 1fr; }
|
||||||
|
.standard-swatch { grid-template-columns: 72px minmax(0, 1fr); padding: 12px; }
|
||||||
|
.standard-swatch-color { width: 72px; height: 72px; }
|
||||||
|
|
||||||
|
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible {
|
||||||
|
outline: 3px solid color-mix(in srgb, #5b8def 80%, white);
|
||||||
|
outline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1080px) {
|
||||||
|
.trend-search-grid, .trend-news-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
.trend-news-grid.is-gallery { column-count: 2; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 680px) {
|
||||||
|
.textile-head h2 { font-size: 24px; }
|
||||||
|
.textile-head-title p { display: none; }
|
||||||
|
.intelligence-overview h3 { font-size: 24px; }
|
||||||
|
.intelligence-overview { margin-bottom: 10px; padding-bottom: 10px; }
|
||||||
|
.intelligence-overview .intelligence-kicker,
|
||||||
|
.intelligence-overview-copy > p:last-child { display: none; }
|
||||||
|
.intelligence-overview-actions { align-items: center; }
|
||||||
|
.intelligence-tabs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; overflow: visible; padding-bottom: 14px; }
|
||||||
|
.intelligence-tab:last-child:nth-child(odd) { grid-column: 1 / -1; }
|
||||||
|
.intelligence-tab { justify-content: space-between; min-width: 0; min-height: 52px; padding: 0 12px; white-space: normal; text-align: left; }
|
||||||
|
.intelligence-tab-count { flex: 0 0 auto; }
|
||||||
|
.calendar-event-card { grid-template-columns: 84px minmax(0, 1fr); }
|
||||||
|
.calendar-local-name-row { grid-template-columns: 1fr; }
|
||||||
|
.calendar-local-name-row small { grid-column: 1; }
|
||||||
|
.trend-search-heading, .trend-news-summary { align-items: flex-start; flex-direction: column; gap: 5px; }
|
||||||
|
.trend-search-grid, .trend-news-grid { grid-template-columns: 1fr; }
|
||||||
|
.trend-news-grid.is-gallery { column-count: 1; }
|
||||||
|
.trend-subtabs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
.calendar-month-grid-wrap { overflow: hidden; }
|
||||||
|
.calendar-day { min-height: 82px; padding: 6px; }
|
||||||
|
.calendar-day-event { display: -webkit-box; overflow: hidden; padding: 4px; font-size: 10px; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
|
||||||
|
.trend-search-button, .trend-news-button { min-height: 48px; }
|
||||||
|
.trend-search-button { padding: 0 6px; font-size: 13px; }
|
||||||
|
.trend-news-visual { min-height: 210px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 编辑型中文标题字体:国内优先东观体,海外回退 Google Noto Serif SC,再回退系统字体。 */
|
||||||
|
:root {
|
||||||
|
--textile-editorial-font: var(--font-dongguan-regular);
|
||||||
|
--textile-editorial-font-bold: var(--font-dongguan-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.textile-head h2, .intelligence-overview h3, .calendar-planner h3,
|
||||||
|
.calendar-event-title, .calendar-local-name, .platform-card h3,
|
||||||
|
.trend-news-body h3, .standard-card-body h3, .policy-card-title,
|
||||||
|
.exhibition-card-title, .intelligence-poster-title {
|
||||||
|
font-family: var(--textile-editorial-font-bold);
|
||||||
|
font-synthesis: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intelligence-list.is-platforms { display: block; }
|
||||||
|
.intelligence-list.is-activities { display: block; }
|
||||||
|
|
||||||
|
/* 跨境活动:行业媒体负责发现,官方平台、政府和国际组织负责证据。 */
|
||||||
|
.activity-filter-toolbar { display: grid; grid-template-columns: 1fr; gap: 10px; margin-bottom: 14px; padding: 14px; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.activity-focus-switch { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
|
||||||
|
.activity-filter-fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
|
||||||
|
.activity-focus-btn { min-height: 40px; padding: 0 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--card-trans-bg); color: var(--ink-secondary); font-size: 14px; font-weight: 800; cursor: pointer; }
|
||||||
|
.activity-focus-btn.active { border-color: #197b65; background: #197b65; color: #fff; }
|
||||||
|
.activity-filter-field { display: grid; gap: 6px; min-width: 0; color: var(--ink-secondary); font-size: 14px; font-weight: 800; }
|
||||||
|
.activity-filter-control { min-width: 0; min-height: 48px; padding: 0 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel-solid); color: var(--ink); font-size: 16px; }
|
||||||
|
.activity-summary-bar { border-left: 3px solid #197b65; }
|
||||||
|
.activity-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; gap: 14px; margin-top: 14px; }
|
||||||
|
.activity-card { min-width: 0; overflow: hidden; border: 1px solid var(--line); border-radius: 7px; background: var(--card-trans-bg); content-visibility: auto; contain-intrinsic-size: 640px; }
|
||||||
|
.activity-card-visual { position: relative; display: grid; width: 100%; min-height: 220px; aspect-ratio: 16 / 9; place-items: center; overflow: hidden; background: var(--intel-brand-gradient); }
|
||||||
|
.activity-generated-poster { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-between; padding: 20px; color: #fff; background: linear-gradient(145deg, rgba(0,81,214,.88), rgba(18,238,168,.66)); }
|
||||||
|
.activity-generated-poster strong { max-width: 82%; font-family: var(--textile-editorial-font-bold); font-size: 23px; font-weight: 400; line-height: 1.35; text-wrap: pretty; font-synthesis: none; }
|
||||||
|
.activity-generated-poster small, .activity-poster-source { font-size: 13px; font-weight: 800; }
|
||||||
|
.activity-card-image { position: relative; z-index: 1; width: 100%; height: 100%; object-fit: cover; }
|
||||||
|
.activity-date-block { position: absolute; right: 12px; bottom: 12px; z-index: 2; display: grid; grid-template-areas: "month month" "day countdown"; grid-template-columns: 46px minmax(54px, 1fr); min-width: 108px; overflow: hidden; border: 1px solid rgba(255,255,255,.58); border-radius: 6px; background: rgba(7, 24, 33, .94); color: #fff; box-shadow: 0 12px 28px rgba(0, 0, 0, .28); backdrop-filter: blur(12px); }
|
||||||
|
.activity-date-month { position: relative; grid-area: month; padding: 7px 9px 6px; border-bottom: 1px solid rgba(7,24,33,.12); background: #f3fbff; color: #075e72; font-size: 13px; font-weight: 800; line-height: 1.1; text-align: center; }
|
||||||
|
.activity-date-month::before, .activity-date-month::after { position: absolute; top: -2px; width: 4px; height: 8px; border-radius: 0 0 2px 2px; background: #19a884; content: ""; }
|
||||||
|
.activity-date-month::before { left: 18px; }
|
||||||
|
.activity-date-month::after { right: 18px; }
|
||||||
|
.activity-date-day { grid-area: day; padding: 9px 5px 10px; font-size: 31px; font-weight: 800; line-height: 1; text-align: center; }
|
||||||
|
.activity-date-countdown { grid-area: countdown; align-self: stretch; display: grid; margin: 7px 7px 7px 0; padding: 0 6px; place-items: center; border: 1px solid rgba(255,255,255,.12); border-radius: 4px; background: rgba(255,255,255,.08); color: rgba(255,255,255,.9); font-size: 12px; font-weight: 700; line-height: 1.2; text-align: center; }
|
||||||
|
.activity-card-body { padding: 17px; }
|
||||||
|
.activity-card-meta, .activity-platforms, .activity-actions { display: flex; flex-wrap: wrap; gap: 7px; }
|
||||||
|
.activity-card-meta span, .activity-platforms span { padding: 4px 8px; border: 1px solid var(--line); border-radius: 999px; color: var(--ink-secondary); font-size: 13px; }
|
||||||
|
.activity-source-level.is-official { border-color: #197b65; color: #2fb48f; }
|
||||||
|
.activity-card-body h3 { margin: 11px 0 6px; color: var(--ink); font-family: var(--textile-editorial-font-bold); font-size: 20px; font-weight: 400; line-height: 1.4; text-wrap: pretty; font-synthesis: none; }
|
||||||
|
.activity-title-original, .activity-location, .activity-proof { margin: 0 0 8px; color: var(--muted); font-size: 13px; line-height: 1.55; }
|
||||||
|
.activity-platforms { margin: 9px 0; }
|
||||||
|
.activity-summary, .activity-next-action { margin: 9px 0 0; color: var(--ink-secondary); font-size: 16px; line-height: 1.65; }
|
||||||
|
.activity-next-action { padding: 11px 12px; border-left: 4px solid #d49b34; background: var(--trans-bg); color: var(--ink); }
|
||||||
|
.activity-actions { margin-top: 15px; }
|
||||||
|
.activity-action { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; padding: 0 13px; border: 1px solid var(--line); color: var(--ink); font-size: 15px; font-weight: 800; text-decoration: none; }
|
||||||
|
.activity-action.primary { border-color: #197b65; background: #197b65; color: #fff; }
|
||||||
|
.activity-action.translate { border-color: #3f81c8; color: #61a3e8; }
|
||||||
|
.activity-action.is-fallback { border-color: #3577cf; color: #5b9ce9; }
|
||||||
|
.activity-proof { margin-top: 13px; }
|
||||||
|
|
||||||
|
@media (max-width: 1080px) {
|
||||||
|
.activity-filter-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||||
|
.activity-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 680px) {
|
||||||
|
.activity-filter-toolbar, .activity-grid { grid-template-columns: 1fr; }
|
||||||
|
.activity-filter-toolbar { padding: 12px; }
|
||||||
|
.activity-focus-switch { grid-template-columns: 1fr 1fr; }
|
||||||
|
.activity-focus-btn { min-height: 48px; }
|
||||||
|
.activity-filter-fields { grid-template-columns: 1fr; }
|
||||||
|
.activity-card-visual { min-height: 190px; }
|
||||||
|
.activity-action { flex: 1 1 150px; min-height: 48px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 中年经营者模式:所有筛选、统计与月份切换保持可读且可触控。 */
|
||||||
|
.intelligence-stat span,
|
||||||
|
.calendar-planner-eyebrow,
|
||||||
|
.calendar-filter-field,
|
||||||
|
.calendar-month-heading span,
|
||||||
|
.calendar-event-source span,
|
||||||
|
.calendar-highlight-button span { font-size: 13px; }
|
||||||
|
.calendar-year-btn, .calendar-scope-btn, .calendar-month-btn { min-height: 44px; font-size: 15px; }
|
||||||
|
.calendar-filter-field > span { font-size: 14px; }
|
||||||
|
|
||||||
|
.calendar-date-block::before {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image: radial-gradient(circle at 20% 25%, color-mix(in srgb, var(--culture-accent) 25%, transparent) 0 2px, transparent 2.5px);
|
||||||
|
background-size: 17px 17px;
|
||||||
|
content: "";
|
||||||
|
opacity: 0.56;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-event-card[data-event-type="christmas"] .calendar-date-block::before { background-image: repeating-linear-gradient(45deg, transparent 0 11px, color-mix(in srgb, var(--culture-accent) 22%, transparent) 11px 13px); }
|
||||||
|
.calendar-event-card[data-event-type="lunar-new-year"] .calendar-date-block::before { background-image: radial-gradient(circle, color-mix(in srgb, var(--culture-accent) 30%, transparent) 0 3px, transparent 3.5px); background-size: 24px 24px; }
|
||||||
|
.calendar-event-card[data-event-type="islamic"] .calendar-date-block::before { background-image: repeating-radial-gradient(circle at 0 0, transparent 0 10px, color-mix(in srgb, var(--culture-accent) 24%, transparent) 11px 12px); }
|
||||||
|
.calendar-event-card[data-event-type="sport"] .calendar-date-block::before { background-image: repeating-linear-gradient(120deg, transparent 0 14px, color-mix(in srgb, var(--culture-accent) 22%, transparent) 14px 17px); }
|
||||||
|
.calendar-event-card[data-event-type="retail"] .calendar-date-block::before { background-image: repeating-linear-gradient(135deg, transparent 0 18px, color-mix(in srgb, var(--culture-accent) 22%, transparent) 18px 21px); }
|
||||||
|
|
||||||
|
.calendar-country-name { display: inline-flex; align-items: center; gap: 7px; }
|
||||||
|
.calendar-country-flag { font-family: "Apple Color Emoji", "Segoe UI Emoji", sans-serif; font-size: 20px; line-height: 1; }
|
||||||
|
.calendar-platform-identity { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
|
||||||
|
.calendar-platform-logo { display: block; width: 24px; height: 24px; padding: 3px; border: 1px solid var(--line); background: #fff; object-fit: contain; }
|
||||||
|
|
||||||
|
.calendar-highlight-rail { margin: 0 0 16px; padding: 14px; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.calendar-highlight-rail > strong { display: block; color: var(--ink); font-family: inherit; font-size: 18px; font-weight: 800; }
|
||||||
|
.calendar-highlight-links { display: flex; gap: 8px; overflow-x: auto; margin-top: 10px; padding-bottom: 3px; }
|
||||||
|
.calendar-highlight-button { display: grid; flex: 0 0 176px; gap: 3px; min-height: 70px; padding: 10px 12px; border: 1px solid var(--line); background: var(--card-trans-bg); color: var(--ink); text-align: left; cursor: pointer; }
|
||||||
|
.calendar-highlight-button:hover, .calendar-highlight-button:focus-visible { border-color: var(--intel-brand-blue); background: color-mix(in srgb, var(--intel-brand-blue) 7%, var(--card-trans-bg)); }
|
||||||
|
.calendar-highlight-button span { color: var(--intel-brand-blue); font-size: 13px; font-weight: 800; }
|
||||||
|
.calendar-highlight-button b { font-size: 15px; line-height: 1.35; }
|
||||||
|
|
||||||
|
.platform-summary { border-left: 3px solid #1e9a76; }
|
||||||
|
.platform-filter-toolbar { display: grid; grid-template-columns: repeat(3, minmax(140px, 0.8fr)) minmax(220px, 1.4fr); gap: 10px; margin-bottom: 14px; padding: 14px; border: 1px solid var(--line); background: var(--panel-solid); }
|
||||||
|
.platform-filter-field { display: grid; gap: 6px; min-width: 0; color: var(--ink-secondary); font-size: 14px; font-weight: 800; }
|
||||||
|
.platform-filter-control { min-width: 0; min-height: 48px; padding: 0 12px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel-solid); color: var(--ink); font-size: 16px; }
|
||||||
|
.platform-filter-control:focus-visible { border-color: #1e9a76; outline-color: #1e9a76; }
|
||||||
|
.platform-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; gap: 14px; margin-top: 14px; }
|
||||||
|
.platform-card { min-width: 0; padding: 18px; border: 1px solid var(--line); background: var(--card-trans-bg); }
|
||||||
|
.platform-card-header { display: grid; grid-template-columns: 78px minmax(0, 1fr); gap: 12px; align-items: center; }
|
||||||
|
.platform-logo-box { display: grid; width: 78px; height: 58px; padding: 8px; place-items: center; border: 1px solid var(--line); background: #fff; }
|
||||||
|
.platform-logo { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
|
||||||
|
.platform-title { min-width: 0; }
|
||||||
|
.platform-title > span { color: var(--ink-secondary); font-size: 13px; }
|
||||||
|
.platform-card h3 { margin: 3px 0 0; color: var(--ink); font-size: 20px; line-height: 1.3; text-wrap: pretty; }
|
||||||
|
.platform-access { grid-column: 1 / -1; justify-self: start; white-space: nowrap; }
|
||||||
|
.platform-access.is-a { color: #148764; background: rgba(20, 135, 100, 0.13); }
|
||||||
|
.platform-access.is-b { color: #315d9c; background: rgba(49, 93, 156, 0.13); }
|
||||||
|
.platform-markets { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 15px; }
|
||||||
|
.platform-category, .platform-access-note, .platform-fit { margin-top: 12px; padding: 11px 12px; background: var(--trans-bg); }
|
||||||
|
.platform-category { border-left: 4px solid #1e9a76; }
|
||||||
|
.platform-access-note { border-left: 4px solid var(--intel-brand-blue); }
|
||||||
|
.platform-category strong, .platform-access-note strong, .platform-fit strong { color: var(--ink); font-size: 14px; }
|
||||||
|
.platform-category p, .platform-access-note p, .platform-fit p { margin: 5px 0 0; color: var(--ink-secondary); font-size: 16px; line-height: 1.65; }
|
||||||
|
.platform-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 15px; }
|
||||||
|
.platform-action-group { display: inline-flex; align-items: stretch; gap: 0; }
|
||||||
|
.platform-action-group > .platform-action { border-radius: 0; }
|
||||||
|
.platform-action-group > .platform-action:first-child { border-radius: 5px 0 0 5px; }
|
||||||
|
.platform-action-group > .platform-action:last-child { border-radius: 0 5px 5px 0; }
|
||||||
|
.platform-action-group > .platform-action + .platform-action { margin-left: -1px; }
|
||||||
|
.translation-action-group .platform-action.translate { border-color: #2fb48f; color: #2fb48f; background: color-mix(in srgb, #2fb48f 9%, var(--panel-solid)); }
|
||||||
|
.platform-action { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; padding: 0 13px; border: 1px solid var(--line); color: var(--ink); font-size: 15px; font-weight: 800; text-decoration: none; }
|
||||||
|
.platform-action.primary { border-color: #1e9a76; background: #1e9a76; color: #fff; }
|
||||||
|
.platform-action.language { border-color: color-mix(in srgb, var(--intel-brand-blue) 52%, var(--line)); color: var(--intel-brand-blue); }
|
||||||
|
.platform-action:hover { border-color: #1e9a76; }
|
||||||
|
.platform-proof { margin: 13px 0 0; color: var(--muted); font-size: 13px; line-height: 1.5; }
|
||||||
|
|
||||||
|
@media (max-width: 1080px) {
|
||||||
|
.platform-filter-toolbar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
.platform-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 680px) {
|
||||||
|
.platform-filter-toolbar { grid-template-columns: 1fr; padding: 12px; }
|
||||||
|
.platform-grid { grid-template-columns: 1fr; }
|
||||||
|
.platform-card-header { grid-template-columns: 70px minmax(0, 1fr); }
|
||||||
|
.platform-access { grid-column: 1 / -1; justify-self: start; }
|
||||||
|
.platform-action-group { flex: 1 1 100%; }
|
||||||
|
.platform-action-group .platform-action { flex: 1 1 auto; min-height: 48px; }
|
||||||
|
.platform-action.language { flex: 1 1 100%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
.calendar-event-card:hover .calendar-date-block::after { animation: calendar-pattern-drift 5s ease-in-out infinite alternate; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes calendar-pattern-drift {
|
||||||
|
to { translate: -10px 8px; rotate: 9deg; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 情报工作台统一视觉覆盖:小圆角、品牌蓝绿、亮暗主题一致。 */
|
||||||
|
.textile-wrap .intelligence-card,
|
||||||
|
.textile-wrap .calendar-event-card,
|
||||||
|
.textile-wrap .exhibition-card,
|
||||||
|
.textile-wrap .policy-card,
|
||||||
|
.textile-wrap .standard-card,
|
||||||
|
.textile-wrap .platform-card,
|
||||||
|
.textile-wrap .activity-card,
|
||||||
|
.textile-wrap .scene-summary,
|
||||||
|
.textile-wrap .calendar-planner,
|
||||||
|
.textile-wrap .calendar-decision-toolbar,
|
||||||
|
.textile-wrap .calendar-highlight-rail,
|
||||||
|
.textile-wrap .calendar-month-grid-wrap,
|
||||||
|
.textile-wrap .trend-search-hub,
|
||||||
|
.textile-wrap .trend-subtabs,
|
||||||
|
.textile-wrap .platform-filter-toolbar,
|
||||||
|
.textile-wrap .activity-filter-toolbar { border-radius: var(--intel-radius); }
|
||||||
|
|
||||||
|
.textile-wrap .intelligence-tab.active,
|
||||||
|
.textile-wrap .intelligence-load-more,
|
||||||
|
.textile-wrap .platform-action.primary,
|
||||||
|
.textile-wrap .activity-action.primary,
|
||||||
|
.textile-wrap .trend-news-button.primary { border-color: var(--intel-brand-blue); }
|
||||||
|
|
||||||
|
.textile-wrap .platform-action.primary,
|
||||||
|
.textile-wrap .activity-action.primary,
|
||||||
|
.textile-wrap .trend-news-button.primary { background: var(--intel-brand-blue); color: #fff; }
|
||||||
|
|
||||||
|
html[data-theme="dark"] .calendar-planner {
|
||||||
|
background: linear-gradient(120deg, color-mix(in srgb, var(--intel-brand-blue) 25%, var(--panel-solid)), color-mix(in srgb, var(--intel-brand-green) 12%, var(--panel-solid)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1360px) {
|
||||||
|
.platform-grid { grid-template-columns: repeat(3, minmax(380px, 1fr)); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
:root {
|
||||||
|
color-scheme: dark;
|
||||||
|
--bg: #090909;
|
||||||
|
--panel: #141414;
|
||||||
|
--line: #303030;
|
||||||
|
--text: #f5f5f2;
|
||||||
|
--muted: #a8a8a2;
|
||||||
|
--accent: #ff6b35;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
|
html { background: var(--bg); }
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
font-family: Inter, "Noto Sans SC", "Microsoft YaHei", sans-serif;
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
a { color: inherit; }
|
||||||
|
|
||||||
|
.seo-topbar {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
min-height: 64px;
|
||||||
|
padding: 0 5vw;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
background: rgba(9, 9, 9, 0.94);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.seo-brand { color: var(--text); font-size: 18px; font-weight: 800; text-decoration: none; }
|
||||||
|
.seo-brand::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 9px; background: var(--accent); }
|
||||||
|
.seo-topbar nav { display: flex; gap: 18px; }
|
||||||
|
.seo-topbar nav a { color: var(--muted); font-size: 14px; text-decoration: none; }
|
||||||
|
.seo-topbar nav a:hover { color: var(--text); }
|
||||||
|
|
||||||
|
.seo-shell { width: min(1180px, 90vw); margin: 0 auto; padding: 56px 0 88px; }
|
||||||
|
.seo-hero { max-width: 780px; margin-bottom: 42px; }
|
||||||
|
.seo-eyebrow { margin: 0 0 10px; color: var(--accent); font-size: 13px; font-weight: 800; }
|
||||||
|
.seo-hero h1, .seo-detail h1 { margin: 0; font-size: clamp(34px, 6vw, 72px); line-height: 1.05; letter-spacing: 0; }
|
||||||
|
.seo-hero > p:last-child, .seo-lead { color: var(--muted); font-size: 18px; }
|
||||||
|
.seo-original { margin: 10px 0 16px; color: var(--muted); font-size: 13px; line-height: 1.5; }
|
||||||
|
|
||||||
|
.seo-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
|
||||||
|
.seo-card { min-width: 0; padding: 22px; border: 1px solid var(--line); border-top: 3px solid var(--card-accent); background: var(--panel); }
|
||||||
|
.seo-card.is-calendar { display: flex; flex-direction: column; box-shadow: inset 4px 0 0 color-mix(in srgb, var(--card-accent) 64%, transparent); }
|
||||||
|
.seo-card-meta { margin: 0 0 12px; color: var(--muted); font-size: 12px; }
|
||||||
|
.seo-card h2 { margin: 0 0 12px; font-size: 20px; line-height: 1.35; }
|
||||||
|
.seo-card h2 a { text-decoration: none; }
|
||||||
|
.seo-card h2 a:hover { color: var(--card-accent); }
|
||||||
|
.seo-card > p:not(.seo-card-meta) { color: var(--muted); font-size: 14px; }
|
||||||
|
.seo-proof { display: block; margin-top: auto; padding-top: 14px; color: var(--card-accent); font-size: 12px; font-weight: 700; }
|
||||||
|
.seo-window { margin: 12px 0 0; padding: 9px 10px; border-left: 3px solid var(--card-accent); background: #1b1b1b; color: var(--text) !important; font-size: 12px !important; }
|
||||||
|
.seo-decision { margin: 12px 0 0; color: var(--card-accent) !important; font-size: 13px !important; font-weight: 800; }
|
||||||
|
.seo-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 11px 0; }
|
||||||
|
.seo-tags span { padding: 3px 7px; border: 1px solid var(--line); color: var(--muted); font-size: 11px; }
|
||||||
|
|
||||||
|
.seo-section-links { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
|
||||||
|
.seo-section-links a { display: flex; justify-content: space-between; padding: 24px; border: 1px solid var(--line); background: var(--panel); text-decoration: none; }
|
||||||
|
.seo-section-links a:hover { border-color: var(--accent); }
|
||||||
|
.seo-section-links span { color: var(--muted); }
|
||||||
|
|
||||||
|
.seo-detail { max-width: 860px; margin: 0 auto; }
|
||||||
|
.seo-breadcrumb { display: flex; gap: 8px; margin-bottom: 28px; color: var(--muted); font-size: 13px; }
|
||||||
|
.seo-breadcrumb a { text-decoration: none; }
|
||||||
|
.seo-detail-image, .seo-poster { width: 100%; aspect-ratio: 16 / 9; margin: 30px 0; border: 1px solid var(--line); }
|
||||||
|
.seo-detail-image { display: block; object-fit: cover; }
|
||||||
|
.seo-poster { display: flex; flex-direction: column; justify-content: space-between; padding: clamp(24px, 6vw, 62px); background: linear-gradient(145deg, color-mix(in srgb, var(--poster-accent) 34%, #111), #090909 68%); }
|
||||||
|
.seo-poster span, .seo-poster small { color: var(--muted); font-weight: 700; }
|
||||||
|
.seo-poster strong { max-width: 720px; font-size: clamp(28px, 5vw, 58px); line-height: 1.15; }
|
||||||
|
.seo-facts { display: grid; grid-template-columns: repeat(2, 1fr); border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
|
||||||
|
.seo-facts div { padding: 18px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
|
||||||
|
.seo-facts dt { color: var(--muted); font-size: 12px; }
|
||||||
|
.seo-facts dd { margin: 4px 0 0; font-weight: 700; }
|
||||||
|
.seo-action { margin: 30px 0; padding: 24px; border-left: 4px solid var(--accent); background: var(--panel); }
|
||||||
|
.seo-action h2 { margin-top: 0; }
|
||||||
|
.seo-source-link { display: inline-flex; padding: 12px 18px; background: var(--accent); color: #111; font-weight: 800; text-decoration: none; }
|
||||||
|
.seo-context { margin: 30px 0; padding: 22px; border: 1px solid var(--line); background: var(--panel); }
|
||||||
|
.seo-context h2 { margin: 0 0 12px; font-size: 20px; }
|
||||||
|
.seo-context p { color: var(--muted); }
|
||||||
|
.seo-context-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 18px; }
|
||||||
|
.seo-context-grid > div { min-width: 0; padding: 14px; border: 1px solid var(--line); background: #101010; }
|
||||||
|
.seo-context-grid strong { font-size: 13px; }
|
||||||
|
.seo-caution { padding: 10px 12px; border-left: 3px solid #ef8b75; background: #1a1210; }
|
||||||
|
.seo-proof-layer { border-left: 4px solid #67cbb7; }
|
||||||
|
.seo-context ol { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px 22px; padding-left: 22px; color: var(--muted); }
|
||||||
|
.seo-link-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
|
||||||
|
.seo-link-row a { display: inline-flex; min-height: 44px; align-items: center; padding: 8px 11px; border: 1px solid var(--line); color: var(--text); font-size: 12px; font-weight: 700; text-decoration: none; }
|
||||||
|
.seo-link-row a:hover { border-color: var(--accent); color: var(--accent); }
|
||||||
|
.seo-year-nav { display: flex; gap: 6px; margin: -18px 0 28px; }
|
||||||
|
.seo-year-nav a { min-width: 74px; padding: 8px 12px; border: 1px solid var(--line); color: var(--muted); font-weight: 800; text-align: center; text-decoration: none; }
|
||||||
|
.seo-year-nav a:hover { border-color: var(--accent); color: var(--text); }
|
||||||
|
.seo-footer { padding: 28px 5vw; border-top: 1px solid var(--line); color: var(--muted); font-size: 12px; text-align: center; }
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.seo-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||||
|
.seo-topbar { align-items: flex-start; flex-direction: column; padding-top: 16px; padding-bottom: 16px; }
|
||||||
|
.seo-topbar nav { width: 100%; overflow-x: auto; }
|
||||||
|
.seo-topbar nav a { flex: 0 0 auto; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 620px) {
|
||||||
|
.seo-shell { width: min(92vw, 540px); padding-top: 38px; }
|
||||||
|
.seo-grid, .seo-section-links, .seo-facts { grid-template-columns: 1fr; }
|
||||||
|
.seo-hero h1, .seo-detail h1 { font-size: 36px; line-height: 1.12; }
|
||||||
|
.seo-lead, .seo-hero > p:last-child { font-size: 16px; }
|
||||||
|
.seo-original { margin-top: 12px; }
|
||||||
|
.seo-card { padding: 18px; }
|
||||||
|
.seo-context ol, .seo-context-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user