补充斗鱼粉丝日报本地预览脚本并压缩版面
1. 为本地测试脚本增加粉丝日报 HTML 预览输出,统一映射新版模板需要的数据结构\n2. 内置稳定的预览文案拼装逻辑,方便不依赖LLM也能本地验收页面效果\n3. 压缩粉丝日报模板的卡片间距、字号、行高和高度,让同样的信息更紧凑简约地展示
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
@@ -27,6 +28,25 @@ def _load_helper():
|
||||
return module.DouyuDanmuSummaryHelper
|
||||
|
||||
|
||||
def _load_report_template_module():
|
||||
"""
|
||||
单独按文件路径加载模板模块。
|
||||
这样本地预览不需要完整初始化插件,也不依赖 Redis 或其他运行时对象。
|
||||
"""
|
||||
current_dir = Path(__file__).resolve().parent
|
||||
project_root = current_dir.parent.parent
|
||||
project_root_str = str(project_root)
|
||||
# 把项目根目录补进 sys.path,保证 report_template.py 内部引用 utils 等项目模块时可正常导入。
|
||||
if project_root_str not in sys.path:
|
||||
sys.path.insert(0, project_root_str)
|
||||
module_path = current_dir / "report_template.py"
|
||||
spec = importlib.util.spec_from_file_location("douyu_report_template_local", module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
assert spec.loader is not None
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def _build_session(room_id: str, anchor_day: str, messages: List[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
ordered = sorted(messages, key=lambda item: item.get("timestamp") or datetime.min)
|
||||
if not ordered:
|
||||
@@ -51,6 +71,181 @@ def _build_session(room_id: str, anchor_day: str, messages: List[Dict[str, Any]]
|
||||
}
|
||||
|
||||
|
||||
def _build_preview_template_payload(local_result: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
将本地测试结果转成粉丝日报模板真正需要的结构。
|
||||
这样预览链路和正式模板共用同一套字段命名,后续查问题更直观。
|
||||
"""
|
||||
session_meta = local_result.get("session_meta", {}) or {}
|
||||
local_stats_preview = local_result.get("local_stats_preview", {}) or {}
|
||||
topic_clusters = local_result.get("topic_evidence_clusters", []) or []
|
||||
hero_mentions = local_result.get("hero_mentions", []) or []
|
||||
content_cues = local_result.get("content_cues", []) or []
|
||||
timeline_digest = local_result.get("timeline_digest", []) or []
|
||||
representative_messages = local_result.get("representative_messages", []) or []
|
||||
|
||||
return {
|
||||
"report_meta": {
|
||||
"room_id": str(session_meta.get("room_id") or "").strip(),
|
||||
"anchor_day": str(session_meta.get("anchor_day") or "").strip(),
|
||||
"nickname": str(session_meta.get("nickname") or "").strip(),
|
||||
"room_name": str(session_meta.get("room_name") or "").strip(),
|
||||
"session_count": 1,
|
||||
"message_count": int(session_meta.get("message_count", 0) or 0),
|
||||
"unique_user_count": int(session_meta.get("unique_user_count", 0) or 0),
|
||||
},
|
||||
"local_stats": {
|
||||
"message_count": int(session_meta.get("message_count", 0) or 0),
|
||||
"unique_user_count": int(session_meta.get("unique_user_count", 0) or 0),
|
||||
"top_emotion_bursts": [
|
||||
{
|
||||
"text": str(item.get("text") or "").strip(),
|
||||
"count": int(item.get("count", 0) or 0),
|
||||
}
|
||||
for item in content_cues
|
||||
if str(item.get("kind") or "").strip() == "emotion"
|
||||
][:8],
|
||||
"top_repeated_messages": [
|
||||
{
|
||||
"text": str(item.get("text") or "").strip(),
|
||||
"count": int(item.get("count", 0) or 0),
|
||||
"user_count": int(item.get("user_count", 0) or 0),
|
||||
}
|
||||
for item in local_stats_preview.get("top_repeated_messages", [])[:8]
|
||||
],
|
||||
"peak_windows": [
|
||||
{
|
||||
"start_time": str(item.get("start_time") or "").strip(),
|
||||
"message_count": int(item.get("message_count", 0) or 0),
|
||||
"user_count": int(item.get("user_count", 0) or 0),
|
||||
}
|
||||
for item in local_stats_preview.get("peak_buckets", [])[:6]
|
||||
],
|
||||
},
|
||||
"topic_evidence_clusters": [
|
||||
{
|
||||
"label": str(item.get("label") or "").strip(),
|
||||
"count": int(item.get("match_count", item.get("count", 0)) or 0),
|
||||
"user_count": int(item.get("user_count", 0) or 0),
|
||||
"time_range": (
|
||||
f"{str(item.get('first_hm') or '').strip()}-{str(item.get('last_hm') or '').strip()}"
|
||||
).strip("-"),
|
||||
"keywords": item.get("keywords", []) or [],
|
||||
"samples": item.get("samples", []) or [],
|
||||
}
|
||||
for item in topic_clusters[:6]
|
||||
],
|
||||
"compact_scene_material": {
|
||||
"semantic_fact_hints": {
|
||||
"hero_mentions": hero_mentions[:6],
|
||||
},
|
||||
"content_cues": content_cues[:18],
|
||||
"timeline_digest": timeline_digest[:20],
|
||||
},
|
||||
"representative_messages": representative_messages[:12],
|
||||
"repeated_messages": [
|
||||
{
|
||||
"text": str(item.get("text") or "").strip(),
|
||||
"count": int(item.get("count", 0) or 0),
|
||||
"user_count": int(item.get("user_count", 0) or 0),
|
||||
}
|
||||
for item in local_stats_preview.get("top_repeated_messages", [])[:12]
|
||||
],
|
||||
"burst_terms": [
|
||||
{
|
||||
"text": str(item.get("text") or "").strip(),
|
||||
"count": int(item.get("count", 0) or 0),
|
||||
}
|
||||
for item in local_stats_preview.get("top_burst_terms", [])[:12]
|
||||
],
|
||||
"peak_buckets": local_stats_preview.get("peak_buckets", [])[:6],
|
||||
"top_terms": [
|
||||
{"term": str(keyword).strip(), "count": 0}
|
||||
for item in topic_clusters[:4]
|
||||
for keyword in (item.get("keywords", []) or [])[:2]
|
||||
if str(keyword).strip()
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _build_preview_report_text(payload: Dict[str, Any]) -> str:
|
||||
"""
|
||||
为本地模板预览提供一份稳定的示例文本。
|
||||
这里不依赖真实 LLM,只用已经提纯好的结果拼装固定结构,
|
||||
方便我们快速检查模板是否把关键信息展示完整。
|
||||
"""
|
||||
meta = payload.get("report_meta", {}) or {}
|
||||
topic_clusters = payload.get("topic_evidence_clusters", []) or []
|
||||
hero_mentions = (
|
||||
payload.get("compact_scene_material", {})
|
||||
.get("semantic_fact_hints", {})
|
||||
.get("hero_mentions", [])
|
||||
or []
|
||||
)
|
||||
repeated_messages = payload.get("repeated_messages", []) or []
|
||||
burst_terms = payload.get("burst_terms", []) or []
|
||||
peak_buckets = payload.get("peak_buckets", []) or []
|
||||
representative_messages = payload.get("representative_messages", []) or []
|
||||
anchor_day = str(meta.get("anchor_day") or "").strip()
|
||||
|
||||
lines = [
|
||||
f"{anchor_day} 这场直播的弹幕不只是热闹,核心信息也很密:赛事、位置、英雄、团播人物和摄像头梗都有人追着聊。",
|
||||
"【今日重点信息】",
|
||||
]
|
||||
for item in topic_clusters[:5]:
|
||||
label = str(item.get("label") or "").strip()
|
||||
time_range = str(item.get("time_range") or "").strip()
|
||||
count = int(item.get("count", 0) or 0)
|
||||
samples = item.get("samples", []) or []
|
||||
sample_text = str(samples[0].get("content") or "").strip()[:42] if samples else ""
|
||||
if label and sample_text:
|
||||
lines.append(f"- {label}从 {time_range or '全场'} 一直有人聊,相关弹幕约 {count} 条,代表说法是「{sample_text}」。")
|
||||
|
||||
lines.append("【核心讨论话题】")
|
||||
for item in topic_clusters[:4]:
|
||||
label = str(item.get("label") or "").strip()
|
||||
keywords = [str(keyword).strip() for keyword in (item.get("keywords", []) or [])[:5] if str(keyword).strip()]
|
||||
if label and keywords:
|
||||
lines.append(f"- 大家围着 {label} 打转,关键词主要是 {'、'.join(keywords)}。")
|
||||
|
||||
lines.append("【英雄与对局焦点】")
|
||||
for item in hero_mentions[:4]:
|
||||
hero_name = str(item.get("hero") or "").strip()
|
||||
mention_count = int(item.get("mention_count", 0) or 0)
|
||||
samples = item.get("samples", []) or []
|
||||
sample_text = str(samples[0].get("content") or "").strip()[:36] if samples else ""
|
||||
if hero_name and sample_text:
|
||||
lines.append(f"- {hero_name}被点名 {mention_count} 次,弹幕现场直接聊到「{sample_text}」。")
|
||||
|
||||
lines.append("【今日笑点】")
|
||||
if peak_buckets:
|
||||
top_bucket = peak_buckets[0]
|
||||
lines.append(
|
||||
f"- {str(top_bucket.get('start_time') or '')[-8:-3]} 前后是最热窗口,弹幕量直接冲到 {int(top_bucket.get('message_count', 0) or 0)} 条。"
|
||||
)
|
||||
if repeated_messages:
|
||||
item = repeated_messages[0]
|
||||
lines.append(f"- 复读冠军是「{str(item.get('text') or '').strip()[:24]}」,一天被刷了 {int(item.get('count', 0) or 0)} 次。")
|
||||
if burst_terms:
|
||||
item = burst_terms[0]
|
||||
lines.append(f"- 情绪词「{str(item.get('text') or '').strip()}」集中爆了 {int(item.get('count', 0) or 0)} 次。")
|
||||
|
||||
lines.append("【弹幕名场面】")
|
||||
for item in representative_messages[:5]:
|
||||
nickname = str(item.get("nickname") or "").strip() or "观众"
|
||||
content = str(item.get("content") or "").strip()
|
||||
if content:
|
||||
lines.append(f"- {nickname}:{content[:44]}")
|
||||
|
||||
lines.append("【梗王榜】")
|
||||
for item in repeated_messages[:3]:
|
||||
lines.append(f"- {str(item.get('text') or '').strip()[:28]}|复读 {int(item.get('count', 0) or 0)} 次")
|
||||
|
||||
lines.append("【收尾播报】")
|
||||
lines.append("- 本地预览版已经把有效信息和乐子一起塞进同一张图里了。")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def run_local_test(file_path: str) -> str:
|
||||
helper = _load_helper()
|
||||
resolved_path = str(Path(file_path).resolve())
|
||||
@@ -85,11 +280,36 @@ def run_local_test(file_path: str) -> str:
|
||||
return str(output_path)
|
||||
|
||||
|
||||
def render_fans_preview_from_file(file_path: str) -> str:
|
||||
"""
|
||||
读取本地弹幕文件并直接产出新版粉丝日报 HTML 预览。
|
||||
这样我们每次调整提纯逻辑或模板后,都能用同一条命令快速验收最终展示效果。
|
||||
"""
|
||||
local_result_path = Path(run_local_test(file_path))
|
||||
local_result = json.loads(local_result_path.read_text(encoding="utf-8"))
|
||||
payload = _build_preview_template_payload(local_result)
|
||||
report_text = _build_preview_report_text(payload)
|
||||
report_template = _load_report_template_module()
|
||||
html_content = report_template.render_fans_daily_report_html(
|
||||
payload=payload,
|
||||
fans_report_text=report_text,
|
||||
)
|
||||
|
||||
output_dir = Path(os.getcwd()) / "temp" / "douyu_materials"
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
file_name = Path(file_path).stem
|
||||
output_path = output_dir / f"{file_name}_fans_template_preview.html"
|
||||
output_path.write_text(html_content, encoding="utf-8")
|
||||
return str(output_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sample_files = [
|
||||
r"plugins\douyu\danmu_test\52876_20260428.txt",
|
||||
r"plugins\douyu\danmu_test\52876_20260429.txt",
|
||||
]
|
||||
for sample in sample_files:
|
||||
path = run_local_test(sample)
|
||||
print(path)
|
||||
result_path = run_local_test(sample)
|
||||
preview_path = render_fans_preview_from_file(sample)
|
||||
print(result_path)
|
||||
print(preview_path)
|
||||
|
||||
@@ -105,12 +105,12 @@
|
||||
.fans-metric-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
margin-top: 16px;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.fans-metric-card {
|
||||
padding: 18px 18px 16px;
|
||||
border-radius: 20px;
|
||||
padding: 14px 15px 12px;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,.96), rgba(255,245,239,.92));
|
||||
border: 1px solid rgba(219,95,65,.12);
|
||||
}
|
||||
@@ -120,48 +120,48 @@
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.fans-metric-value {
|
||||
font-size: 28px;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
font-weight: 900;
|
||||
color: #cf593e;
|
||||
word-break: break-all;
|
||||
}
|
||||
.fans-metric-hint {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
font-size: 11px;
|
||||
color: #8f7368;
|
||||
line-height: 1.5;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.section {
|
||||
margin-top: 18px;
|
||||
padding: 22px;
|
||||
border-radius: 26px;
|
||||
margin-top: 14px;
|
||||
padding: 16px 18px;
|
||||
border-radius: 20px;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,.96), rgba(255,249,244,.94));
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
.section-summary-list {
|
||||
margin: 0 0 14px;
|
||||
padding-left: 22px;
|
||||
margin: 0 0 10px;
|
||||
padding-left: 18px;
|
||||
}
|
||||
.section-summary-list li {
|
||||
margin: 8px 0;
|
||||
margin: 5px 0;
|
||||
color: #5a3e37;
|
||||
font-size: 15px;
|
||||
line-height: 1.76;
|
||||
font-size: 14px;
|
||||
line-height: 1.58;
|
||||
font-weight: 600;
|
||||
}
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 24px;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 21px;
|
||||
font-weight: 900;
|
||||
color: #5b2d23;
|
||||
}
|
||||
.section-title .icon {
|
||||
width: 14px;
|
||||
height: 28px;
|
||||
width: 12px;
|
||||
height: 22px;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(180deg, var(--accent), var(--accent-2));
|
||||
box-shadow: 0 6px 14px rgba(219,95,65,.2);
|
||||
@@ -169,108 +169,108 @@
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
gap: 10px;
|
||||
}
|
||||
.fans-info-card {
|
||||
padding: 16px 16px 15px;
|
||||
border-radius: 18px;
|
||||
padding: 12px 13px;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,.98), rgba(255,245,240,.94));
|
||||
border: 1px solid rgba(219,95,65,.12);
|
||||
min-height: 112px;
|
||||
min-height: 84px;
|
||||
}
|
||||
.fans-info-text {
|
||||
font-size: 15px;
|
||||
line-height: 1.76;
|
||||
font-size: 14px;
|
||||
line-height: 1.58;
|
||||
color: #523935;
|
||||
font-weight: 600;
|
||||
}
|
||||
.topic-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
gap: 10px;
|
||||
}
|
||||
.topic-cluster-card {
|
||||
padding: 18px 18px 14px;
|
||||
border-radius: 20px;
|
||||
padding: 13px 14px 11px;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,.98), rgba(255,244,237,.94));
|
||||
border: 1px solid rgba(219,95,65,.12);
|
||||
}
|
||||
.topic-cluster-title {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: 900;
|
||||
color: #6d2f22;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.topic-cluster-meta {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
color: #8d6c61;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
.topic-cluster-list {
|
||||
margin: 0;
|
||||
padding-left: 18px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.topic-cluster-list li {
|
||||
margin: 8px 0;
|
||||
font-size: 14px;
|
||||
line-height: 1.66;
|
||||
margin: 5px 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.52;
|
||||
color: #4d3832;
|
||||
}
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
gap: 10px;
|
||||
}
|
||||
.hero-mention-card {
|
||||
padding: 16px;
|
||||
border-radius: 18px;
|
||||
padding: 12px 13px;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(135deg, rgba(255,255,255,.98), rgba(255,241,232,.94));
|
||||
border: 1px solid rgba(243,164,71,.22);
|
||||
}
|
||||
.hero-mention-name {
|
||||
font-size: 17px;
|
||||
font-size: 15px;
|
||||
line-height: 1.4;
|
||||
font-weight: 900;
|
||||
color: #6b311f;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.hero-mention-meta {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
color: #8c6d61;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.hero-mention-sample {
|
||||
font-size: 14px;
|
||||
line-height: 1.65;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: #533833;
|
||||
}
|
||||
.timeline-layout {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
|
||||
gap: 14px;
|
||||
gap: 10px;
|
||||
}
|
||||
.hot-window-stack,
|
||||
.repeat-chip-wrap,
|
||||
.meme-rank-stack {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
}
|
||||
.fans-hot-window-card,
|
||||
.repeat-digest-panel,
|
||||
.rank-panel {
|
||||
padding: 14px 16px;
|
||||
border-radius: 18px;
|
||||
padding: 11px 12px;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,.98), rgba(255,245,239,.94));
|
||||
border: 1px solid rgba(219,95,65,.12);
|
||||
}
|
||||
.fans-hot-window-time {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: 900;
|
||||
color: #c84f3f;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.fans-hot-window-meta {
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
color: #5c433b;
|
||||
}
|
||||
.repeat-chip-wrap {
|
||||
@@ -280,9 +280,9 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 14px;
|
||||
gap: 8px;
|
||||
padding: 9px 11px;
|
||||
border-radius: 12px;
|
||||
background: rgba(255,255,255,.9);
|
||||
border: 1px solid rgba(219,95,65,.1);
|
||||
}
|
||||
@@ -290,35 +290,35 @@
|
||||
background: rgba(255,247,236,.94);
|
||||
}
|
||||
.repeat-chip-text {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: #4d3932;
|
||||
font-weight: 700;
|
||||
}
|
||||
.repeat-chip-count {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
color: #a05441;
|
||||
font-weight: 800;
|
||||
}
|
||||
.two-col {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.08fr) minmax(280px, .92fr);
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
}
|
||||
.funny-list {
|
||||
margin: 0;
|
||||
padding-left: 22px;
|
||||
padding-left: 18px;
|
||||
}
|
||||
.funny-list li {
|
||||
margin: 10px 0;
|
||||
margin: 6px 0;
|
||||
color: #533835;
|
||||
font-size: 15px;
|
||||
line-height: 1.76;
|
||||
font-size: 14px;
|
||||
line-height: 1.58;
|
||||
}
|
||||
.meme-rank-card {
|
||||
padding: 14px 16px;
|
||||
border-radius: 16px;
|
||||
padding: 11px 12px;
|
||||
border-radius: 13px;
|
||||
background: linear-gradient(135deg, rgba(255,255,255,.98), rgba(255,240,232,.95));
|
||||
border: 1px solid rgba(242,95,92,.18);
|
||||
}
|
||||
@@ -327,35 +327,35 @@
|
||||
font-size: 12px;
|
||||
letter-spacing: .08em;
|
||||
font-weight: 900;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.meme-rank-text {
|
||||
color: #4b2e2b;
|
||||
font-size: 15px;
|
||||
line-height: 1.66;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
font-weight: 700;
|
||||
}
|
||||
.scene-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
gap: 10px;
|
||||
}
|
||||
.fans-scene-card {
|
||||
padding: 16px 16px 15px;
|
||||
border-radius: 18px;
|
||||
padding: 12px 13px;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,.98), rgba(255,245,240,.95));
|
||||
border: 1px solid rgba(255,138,61,.16);
|
||||
min-height: 102px;
|
||||
min-height: 78px;
|
||||
}
|
||||
.fans-scene-quote {
|
||||
color: #5b3c37;
|
||||
font-size: 15px;
|
||||
line-height: 1.75;
|
||||
font-size: 13px;
|
||||
line-height: 1.54;
|
||||
}
|
||||
.closing-box {
|
||||
margin-top: 16px;
|
||||
padding: 20px 22px;
|
||||
border-radius: 24px;
|
||||
margin-top: 14px;
|
||||
padding: 15px 17px;
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(135deg, rgba(255,126,103,.1), rgba(243,164,71,.14));
|
||||
border: 1px solid rgba(255,126,103,.16);
|
||||
}
|
||||
@@ -364,16 +364,16 @@
|
||||
font-size: 13px;
|
||||
letter-spacing: .08em;
|
||||
font-weight: 900;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.closing-text {
|
||||
color: #613b34;
|
||||
font-size: 18px;
|
||||
line-height: 1.8;
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
font-weight: 700;
|
||||
}
|
||||
.footer-note {
|
||||
margin-top: 18px;
|
||||
margin-top: 14px;
|
||||
text-align: right;
|
||||
color: #8f736c;
|
||||
font-size: 12px;
|
||||
|
||||
Reference in New Issue
Block a user