/* ==========================================================================
   次元小窝 · 样式表
   设计方向：水色 · 余白（日系极简）。全站三条原则：用线不用阴影 / 主色只表达"可交互·被选中" / 标题压小、字距拉开。
   目录：§0 设计令牌  §1 基础重置  §2 页面骨架  §3 左侧栏  §4 顶栏  §5 头图卡  §6 筛选栏  §7 作品区  §8 入场动效  §9 响应式  §10 果冻交互
   ⚠️ 全站零渐变。"氛围"靠点阵图案 + 角落同心圆涟漪（见 §1 body::before / §5 .des::after）。
   ========================================================================== */


/* ============================ §0 设计令牌 ============================
   颜色 / 圆角 / 间距 / 动效都写成 CSS 变量放在 :root：换主题色只改这一处。 */
:root{
	/* ---------- 颜色 · 静空蓝阶（还是二次元那支蓝，只是把亮度压回来） ----------
	   色相锁在 206°（正天蓝，不偏青也不偏紫），饱和度 60~72%，最亮档从 97% 起步、
	   最深档压到 28%。整体比上一版暗一档，是"晴天抬头那种蓝"，不是"手机屏幕发光那种蓝"。
	   ⚠️ 上一版主色 #38bdf8 亮度 74%、饱和 92%：大面积铺在近白的页面上等于一块光源，
	      盯久了眼酸；而且它压白字只有 2.14:1 —— 那几个"主按钮"上的字其实一直是糊的。
	   ⚠️ 这一版只做两件事：把最亮档压下去（不许再当大面积底色用），
	      把最深档加深（白字才立得住）。彩度不再往上顶，观感从"霓虹"回到"晴空"。
	   ⚠️ 三条硬规则，以后改色别破：
	      ① 白字只能压 --blue-600(5.67:1) / --blue-700(8.51:1)；
	      ② --blue-400(2.68:1) 上必须配深墨字，且只用在小面积（图标、开关、徽章）；
	      ③ --blue-500(4.11:1) 不承载 14px 以下的白字，只做描边、图标、大色块。 */
	--blue-50:   #f2f8fe;   /* 最浅：输入框底、悬停底 */
	--blue-100:  #e3f0fb;   /* 选中底、浅色区块 */
	--blue-200:  #c4def5;   /* 淡蓝描边 */
	--blue-300:  #96c4e9;   /* 装饰线、进度槽（配深墨字 8.73:1） */
	--blue-400:  #61a4db;   /* 图标高亮、开关打开态（配深墨字 6.02:1） */
	--blue-500:  #2f82c4;   /* 强调、选中描边 */
	--blue-600:  #1d6ba6;   /* 主按钮底（白字 5.67:1）、主色文字 */
	--blue-700:  #14507c;   /* 深蓝：悬停、焦点环、文字链接（白字 8.51:1） */

	/* ---------- 颜色 · 墨色（不用纯黑，带一点蓝的灰压浅蓝上不发脏） ----------
	   ⚠️ 四档按"投影到纸底上的实测对比度"排的，别随手调浅：
	      15.1 / 9.6 / 6.2 / 3.8:1。上一版 --ink-400 只有 3.6:1、--ink-500 6.0:1，
	      时间戳和辅助说明在浅蓝底上已经开始"发灰"，这一版全部往上提了一档。 */
	--ink-900: #16222e;     /* 标题（纸底 15.1:1） */
	--ink-700: #2f4356;     /* 正文（9.6:1，长文就用它） */
	--ink-500: #4c5f72;     /* 次要文字（6.2:1，稳过 AA） */
	--ink-400: #6e8194;     /* 占位符、空状态（3.8:1，只放非关键信息） */

	/* ---------- 颜色 · 线 ---------- */
	--line:      #d8e4f0;   /* 主要发丝线 */
	--line-soft: #e7eff7;   /* 更弱的分隔线 */
	--line-blue: #bcd4ea;   /* 浅蓝区域里的线 */

	/* ---------- 颜色 · 面 ----------
	   ⚠️ --paper 从 #eef6fc（饱和度 60%）退到 #f4f8fc（55% / 亮度 97%）：
	      底色是"大面积"，它的彩度每高一点，全站的眼疲劳就多一点。
	      底色淡了，白卡片和底色那点差就交给 --line 的线来兜 —— 本项目本来就是"用线不用阴影"。 */
	--surface: #ffffff;
	--paper:   #f4f8fc;

	/* ---------- 语义色（全站唯一允许出现的第二个色相） ---------- */
	--alert:      #c9304d;
	--alert-soft: #fdeef2;
	--alert-line: #f6d3dc;
	--dot:        #ff6b8a;

	/* ---------- 圆角：五档就够，别再造新数值 ----------
	   ⚠️ 比上一版整体调大：Q 弹造型靠"圆"，小圆角会显得硬。
	   --r-full 给 chip / 头像 / 胶囊按钮 —— 写 999px 而不是 50%，
	   因为 50% 遇到非正方形（长条按钮）会变成椭圆。 */
	--r-xs: 6px;       /* 小徽章 */
	--r-sm: 10px;      /* 按钮、chip、输入框 */
	--r-md: 14px;
	--r-lg: 20px;      /* 卡片 */
	--r-full: 999px;   /* 胶囊、圆形图标按钮 */

	/* ---------- 间距梯度 ---------- */
	--sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px;
	--sp-4: 18px; --sp-5: 26px; --sp-6: 40px;

	/* 内容区左右留白。⚠️ .con 的 padding 和 .topbar 的 margin 必须用同一个变量 */
	--gutter: 34px;

	/* ---------- 阴影：三级体系（静置 / 浮起 / 悬浮层），颜色带蓝不带黑 ----------
	   ⚠️ Y 偏移按 2 / 8 / 24 拉开档差。只改模糊值不动偏移，三档看起来一样高。 */
	--sh-1: 0 2px 8px -2px rgba(29, 107, 166, 0.16), 0 1px 2px rgba(22, 34, 46, 0.05);
	--sh-2: 0 10px 24px -12px rgba(29, 107, 166, 0.40), 0 2px 6px -2px rgba(22, 34, 46, 0.08);
	--sh-3: 0 24px 48px -20px rgba(29, 107, 166, 0.46), 0 8px 20px -10px rgba(22, 34, 46, 0.10);

	/* ---------- 动效 ----------
	   ⚠️ --ease 是"出场缓动"，本身不过冲，拿它做按压不会颤。
	   Q 弹感必须显式用 --ease-q：控制点 y > 1 才会冲过终点再弹回来。 */
	--ease: cubic-bezier(0.16, 1, 0.3, 1);            /* 出场：纯减速，无过冲 */
	--ease-q: cubic-bezier(0.34, 1.56, 0.64, 1);      /* 果冻：小元素回弹 */
	--ease-q-soft: cubic-bezier(0.22, 1.30, 0.36, 1); /* 果冻·弱：大面板回弹，幅度小免得晕 */
	--dur-fast: 160ms;   /* 悬停 */
	--dur-press: 110ms;  /* 按压下压。⚠️ 要快，慢了像卡顿不像果冻 */
	--dur: 320ms;        /* 面板、展开 */
	--dur-slow: 480ms;   /* 入场 */

	/* ---------- 字体 ---------- */
	/* 中文正文优先本机黑体 */
	--font-body: "PingFang SC", "HarmonyOS Sans SC", "Microsoft YaHei UI",
		"Microsoft YaHei", "Hiragino Sans", "Noto Sans SC", system-ui, sans-serif;
	/* 展示字体：Jost 只有拉丁字形，汉字会自动落到 --font-body */
	--font-display: "Jost", var(--font-body);

	/* ---------- 字号：六档，别再写裸 px ----------
	   ⚠️ 原来全站散着 15 种字号（10/11/11.5/12/12.5/13/13.5/14/16/17/18/19/21/22），
	      其中 11.5 和 12、13 和 13.5 肉眼几乎分不出，改起来却每处都要重新想一遍。
	      收敛成六档后，改全站字号只动这里。
	   ⚠️ 用 px 不用 rem：本项目没有"跟着系统字号缩放"的需求，px 对稿更直接。 */
	--fs-xs:   12px;   /* 徽章、计数、时间戳 */
	--fs-sm:   13px;   /* 标签、辅助说明 */
	--fs-base: 14px;   /* 次要正文 */
	--fs-md:   15px;   /* 正文主轴（body 基准） */
	--fs-lg:   17px;   /* 区块标题（评论 / 同分区推荐） */
	--fs-xl:   20px;   /* 小节大标题、统计数字 */
	--fs-2xl:  24px;   /* 页面主标题 */

	/* ---------- 头像三档：按"信息层级"分，不是按页面分 ----------
	   ⚠️ 原来是 34 / 38 / 32 三个没有规律的数，现在按大小顺序排好：
	      评论最次要 → 顶栏居中 → 详情页作者最大。 */
	--av-sm: 32px;     /* 评论 @ 详情页 */
	--av-md: 36px;     /* 顶栏 */
	--av-lg: 40px;     /* 详情页作者 */
}


/* ======================= §1 基础重置与排版 ======================= */

*, *::before, *::after{
	box-sizing: border-box;
}

body{
	margin: 0;
	font-family: var(--font-body);
	font-size: var(--fs-md);
	line-height: 1.8;          /* 中文正文行高 ≥1.7 才不挤；日系喜欢更松，给到 1.8 */
	letter-spacing: 0.02em;    /* 汉字之间松一点点，是"清新"最省力的来源 */
	color: var(--ink-700);
	background-color: var(--paper);
	-webkit-font-smoothing: antialiased;
}

/* 氛围层 ①：点阵网格。⚠️ 刻意不用 radial-gradient 光晕 —— 渐变的"雾感"和
   "简洁清晰"是冲突的；规则点阵像绘图纸，边界明确、观感更干净。 */
body::before{
	content: "";
	position: fixed;
	inset: 0;
	z-index: 0;
	pointer-events: none;      /* 装饰层绝不能挡住点击 */
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26'%3E%3Ccircle cx='2' cy='2' r='1.15' fill='%234f93bd' fill-opacity='.16'/%3E%3C/svg%3E");
	background-size: 26px 26px;
}

/* 氛围层 ②：3.5% 纸纹噪点，加一点颗粒有质感。别超过 0.05 */
/* ⚠️ feTurbulence 不是渐变，保留 */
body::after{
	content: "";
	position: fixed;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: 0.035;
	mix-blend-mode: multiply;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* 键盘焦点：全站统一焦点环（--blue-700）。焦点环必须看得见 */
:focus-visible{
	outline: 2px solid var(--blue-700);
	outline-offset: 2px;
	border-radius: var(--r-xs);
}


/* ========================== §2 页面骨架 ========================== */

/* 把整页内容抬到氛围层之上 */
#big-conain{
	position: relative;
	z-index: 1;
	display: flex;
	min-height: 100vh;
	width: 100%;
	background-color: transparent;   /* 底色交给 body 的氛围层 */
}

/* 内容列 */
.con{
	flex: 1;
	min-width: 0;        /* ⚠️ 不加，长内容会顶破整行 */
	display: flex;
	flex-direction: column;
	/* 区块间距：头图卡 / 筛选栏 / 作品区 三段之间。
	   ⚠️ 从 26 提到 30 —— 26px 时三段几乎连成一片，"层次"全靠边框撑着；
	      拉开之后每一段自己成一"块"，眼睛才分得清先后。 */
	gap: 30px;
	padding: 0 var(--gutter) var(--sp-6);
}


/* =========================== §3 左侧栏 =========================== */

.left-sidebar{
	width: 236px;

	/* ↓ 四条"保命设置"，缺一不可 */
	flex-shrink: 0;         /* 内容区再宽也不许把侧栏压扁 */
	box-sizing: border-box; /* 让 padding 算进 236px 之内，否则实际会变宽 */
	position: sticky;       /* 右侧滚动时钉在视口顶部 */
	top: 0;
	height: 100vh;          /* ⚠️ 钉住时必须有高度，否则只有内容高，一滚就跟着跑 */
	overflow-y: auto;
	/* ⚠️ 下面这行别删！自定义滚动条是"占宽度"的（见本段下面的 6px 规则），
	   滚动条一开一关，导航项宽度就在 199↔193 之间跳 6px，看着像整条侧栏在抖。
	   stable = 永远预留那 6px，宽度从此与滚动条开关无关。 */
	scrollbar-gutter: stable;

	display: flex;
	flex-direction: column;
	gap: var(--sp-4);
	padding: var(--sp-5) var(--sp-4);

	/* ⚠️ 实底，不要毛玻璃。backdrop-filter 是这块最大的性能窟窿：
	   侧栏 100vh 高、还要跟着滚动重算模糊，低端机掉帧明显。 */
	background-color: var(--surface);
	border-right: 1px solid var(--line);   /* 一根发丝线分界，不用阴影 */
}

/* 侧栏滚动条：做细，用主色浅档 */
.left-sidebar::-webkit-scrollbar{ width: 6px; }
.left-sidebar::-webkit-scrollbar-track{ background: transparent; }
.left-sidebar::-webkit-scrollbar-thumb{ background: var(--blue-200); border-radius: var(--r-full); }
.left-sidebar::-webkit-scrollbar-thumb:hover{ background: var(--blue-300); }

/* ---------- 3.1 品牌区 ---------- */
.sb-brand{
	display: flex;
	flex-direction: column;
	gap: 6px;
	padding: 0 var(--sp-1);
}

/* 清掉 h1 默认外边距；line-height:0 去掉图片底部空隙 */
.sb-brand-mark{ margin: 0; line-height: 0; }

.sb-logo-img{ display: block; width: 78%; height: auto; }

.sb-sub{
	margin: 0;
	font-size: var(--fs-xs);
	line-height: 1.6;
	letter-spacing: 0.04em;
	color: var(--ink-500);
}

/* ---------- 3.2 上传主按钮 ---------- */
/* 全站唯一的"实心色块"，视觉重心就在这儿 */
.sb-upload{
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	width: 100%;
	height: 38px;
	border: 0;
	border-radius: var(--r-sm);
	cursor: pointer;
	font-family: inherit;   /* ⚠️ 按钮不继承字体，不写会变宋体 */
	font-size: var(--fs-base);
	font-weight: 600;
	letter-spacing: 0.08em;
	/* ⚠️ 深底必须配白字。原来蓝色阶太浅才用深色字，现在底压到 --blue-600，
	   深字压上去反而糊成一团（对比度掉到 3:1 以下） */
	color: #fff;
	background-color: var(--blue-600);
	box-shadow: var(--sh-2);
	/* 别写 transition: all（会带上布局属性，莫名抖动）*/
	transition: background-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.sb-upload svg{ width: 16px; height: 16px; }

.sb-upload:hover{ background-color: var(--blue-700); transform: translateY(-1px); }
.sb-upload:active{ transform: translateY(0) scale(0.99); }

/* ---------- 3.3 导航 ---------- */
.sb-nav{
	display: flex;
	flex-direction: column;
	min-height: 0;   /* 允许被压缩，否则内容顶出侧栏 */
}

.sb-group{
	list-style: none;   /* 去掉默认小圆点 */
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	/* 2px 时每项几乎黏在一起，一长串看下来没有"项"的感觉；4px 才分得开 */
	gap: 4px;
}

/* 分组小标题：小、浅、字距大，比分割线透气 */
.sb-group-title{
	/* 上方 24px 是"组与组"的分界，比下面 8px 大得多 —— 靠这个差值读出分组 */
	margin: 24px 0 8px;
	padding-left: 12px;
	font-size: var(--fs-xs);
	font-weight: 500;
	/* ⚠️ 0.18em 是照拉丁字母的小标题调的，套到中文上"画廊分区"四个字会被拉散，
	   读起来像间距出错的正文。0.08em 只够让字口气，不多不少。 */
	letter-spacing: 0.08em;
	/* 比导航文字浅一档：分组标题是"标签"，不是可点的项，靠轻来分层 */
	color: var(--ink-400);
}

/* 单个导航项 */
.sb-item{
	position: relative;   /* 给选中态竖条做定位基准 */
	display: flex;
	align-items: center;
	gap: 10px;
	/* ⚠️ 34 → 38：14px 的中文塞在 34px 行里，上下总共只剩 10px 呼吸，
	   十几项连排会读成"一坨"。38px 是"手指点得准、眼睛也分得开"的平衡点 */
	height: 38px;
	padding: 0 12px;
	border-radius: var(--r-sm);
	font-size: var(--fs-base);
	color: var(--ink-700);
	text-decoration: none;   /* 去掉 <a> 默认下划线 */
	transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.sb-item svg{
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	opacity: 0.72;   /* 图标比文字浅，突出文字 */
	transition: opacity var(--dur-fast) var(--ease);
}

.sb-item:hover{
	background-color: var(--blue-50);
	color: var(--ink-900);
}
.sb-item:hover svg{ opacity: 1; }

/* 选中态：淡蓝底 + 深字 + 左侧 2px 竖条（::before 画）*/
.sb-item.is-active{
	/* ⚠️ 选中文字用品牌蓝而不是墨色：墨色读起来只是"加粗了"，
	   换成蓝色才和左边那条竖条是同一个颜色，读成一个整体的"当前项" */
	color: var(--blue-700);
	font-weight: 600;
	background-color: var(--blue-100);
}
.sb-item.is-active svg{ opacity: 1; }
.sb-item.is-active::before{
	content: "";
	position: absolute;
	left: 0;
	top: 50%;
	transform: translateY(-50%);   /* 垂直居中，比硬算 top 值稳 */
	width: 2px;
	height: 16px;
	border-radius: 0 2px 2px 0;
	background-color: var(--blue-700);
}

/* 未读小红点：margin-left:auto 推到行末。红色是"有未读"的通用约定 */
.sb-dot{
	margin-left: auto;
	width: 6px;
	height: 6px;
	flex-shrink: 0;
	border-radius: 50%;
	background: var(--dot);
	box-shadow: 0 0 0 3px rgba(255, 107, 138, 0.14);
}

/* ---------- 3.4 热门标签胶囊 ---------- */
.sb-tags{
	display: flex;
	flex-wrap: wrap;   /* 放不下换行，别撑破 236px */
	gap: 6px;
	padding: 0 var(--sp-1);
}

.sb-tag{
	/* ⚠️ 也改成全胶囊（原来 --r-xs 6px）。侧栏这块、筛选栏那块、图片角标那块
	   是全站仅有的三处"标签"，形状必须是一套 —— 同一屏里三种圆角会显得没做完。 */
	padding: 4px 11px;
	border-radius: var(--r-full);
	font-size: var(--fs-xs);
	color: var(--ink-500);
	background: transparent;
	border: 1px solid var(--line);
	cursor: pointer;
	transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease);
}
.sb-tag:hover{
	color: var(--ink-900);
	background: var(--blue-50);
	border-color: var(--blue-200);
}


/* ============================ §4 顶栏 ============================ */

.topbar{
	position: sticky;
	top: 0;
	z-index: 10;

	/* 顶栏"通栏"：宽度要配 calc(100% + 2×--gutter)，只写 100% 右边界会缩进去。⚠️ --gutter 必须和 .con 的 padding 同源 */
	width: calc(100% + var(--gutter) * 2);
	margin: 0 calc(var(--gutter) * -1);
	height: 58px;
	/* 通栏了要补回 --gutter 内边距，内容才和卡片对齐 */
	padding: 0 var(--gutter);

	display: flex;
	align-items: center;
	gap: var(--sp-3);

	/* ⚠️ 实底顶栏。原来这里是 backdrop-filter: blur(14px) —— 它看起来"高级"，
	   但每次滚动都要把顶栏底下那一整条重新采样做模糊，是最费的写法之一。
	   换成实底后滚动是纯合成，帧率稳得多，字也更清楚。 */
	background-color: var(--surface);
	border-bottom: 1px solid var(--line);
}

/* 所有按钮共用"去默认样式"。⚠️ 必须放在所有 .tb-* 组件样式最前面 —— 里面有 background: transparent，排到后面会把组件背景清透明（搜索按钮曾因此"消失"）*/
.tb-icon,
.tb-go,
.tb-btn,
.tb-avatar{
	font-family: inherit;
	cursor: pointer;
	border: 0;
	background: transparent;
}

/* ---------- 4.1 搜索 ---------- */
.tb-search{
	flex: 1;              /* 吃掉剩余宽度 */
	max-width: 420px;     /* 别在宽屏拉成一条长虫 */
	min-width: 0;         /* ⚠️ 不写，输入框变长会顶破顶栏 */
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	height: 36px;
	padding: 0 4px 0 12px;   /* 右边留 4px：里面塞着 28px 搜索按钮 */
	border-radius: var(--r-sm);
	background-color: var(--blue-50);
	border: 1px solid var(--blue-200);
	color: var(--ink-400);
	transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
		box-shadow var(--dur-fast) var(--ease);
}
.tb-search svg{ width: 15px; height: 15px; flex-shrink: 0; }

/* :focus-within：input 聚焦时整个框一起高亮 */
.tb-search:focus-within{
	background-color: var(--surface);
	border-color: var(--blue-600);
	box-shadow: 0 0 0 3px rgba(29, 107, 166, 0.22);
	color: var(--ink-700);
}

.tb-input{
	flex: 1;
	min-width: 0;
	border: 0;
	background: transparent;
	outline: none;        /* 用外层 focus-within 代替 */
	font-family: inherit;
	font-size: var(--fs-base);
	letter-spacing: inherit;
	color: var(--ink-900);
}
.tb-input::placeholder{ color: var(--ink-400); }

/* 搜索按钮长在框里，高度矮一圈
   ⚠️ 用"淡蓝底 + 深蓝字"而不是实心主色：一屏的主色额度留给右侧「上传作品」，
      搜索提交是高频小动作，抢了主色反而让页面到处都在喊"点我"。 */
.tb-go{
	flex-shrink: 0;
	height: 28px;
	padding: 0 14px;
	border-radius: var(--r-xs);
	font-size: var(--fs-sm);
	font-weight: 600;
	letter-spacing: 0.06em;
	color: var(--blue-700);
	background-color: var(--blue-100);
	transition: background-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.tb-go:hover{ background-color: var(--blue-200); }
.tb-go:active{ transform: scale(0.97); }

/* ---------- 4.2 右侧操作区 ---------- */
.tb-actions{
	margin-left: auto;    /* 推到最右边 */
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	position: relative;   /* 给头像的下拉菜单当定位参照 */
}

/* 图标按钮（暗色模式） */
.tb-icon{
	width: 34px;
	height: 34px;
	display: grid;
	place-items: center;
	border-radius: var(--r-sm);
	color: var(--ink-500);
	transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.tb-icon svg{ width: 18px; height: 18px; }
.tb-icon:hover{ background-color: var(--blue-50); color: var(--ink-900); }

/* ---------- 4.3 登录 / 注册 ----------
   形状全写在 .tb-btn 里，只用底色和边框分主次。
   ⚠️ 这俩已从 <button> 换成 <a href>，两个副作用要手动清：<a> 默认有下划线（text-decoration: none）；行内元素写 height 不生效（用 display: inline-flex 解决） */
.tb-btn{
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 34px;
	padding: 0 16px;
	border-radius: var(--r-sm);
	font-size: var(--fs-base);
	font-weight: 500;
	letter-spacing: 0.06em;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
		color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

/* 次要动作：描边按钮。⚠️ 这 1px 边框不能省 —— 少了会比"注册"矮 2px、窄 2px */
.tb-btn--ghost{
	color: var(--ink-700);
	background-color: var(--surface);
	border: 1px solid var(--blue-200);
}
.tb-btn--ghost:hover{
	color: var(--ink-900);
	background-color: var(--blue-50);
	border-color: var(--blue-400);
}

/* 主要动作：实心按钮。边框写 transparent 而非 0，尺寸才分毫不差 */
.tb-btn--primary{
	color: #fff;
	font-weight: 600;
	background-color: var(--blue-600);
	border: 1px solid transparent;
}
.tb-btn--primary:hover{ background-color: var(--blue-700); transform: translateY(-1px); }
.tb-btn--primary:active{ transform: translateY(0) scale(0.99); }

/* 头像：overflow:hidden 防图片溢出圆形 */
.tb-avatar{
	width: var(--av-md);
	height: var(--av-md);
	display: grid;
	place-items: center;
	border-radius: 50%;
	color: var(--ink-500);
	background-color: var(--blue-50);
	border: 1px solid var(--line);
	overflow: hidden;
	padding: 0;
	transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.tb-avatar svg{ width: 18px; height: 18px; }
.tb-avatar img{
	width: 100%;
	height: 100%;
	object-fit: cover;   /* 非正方形时裁切而非压扁 */
	display: block;
}
.tb-avatar:hover{ border-color: var(--blue-400); color: var(--ink-900); }


/* ---------- 4.4 登录态 ----------
   由 js/auth.js 给 .tb-actions 加上 .is-logged-in 来切换两种状态。
   ⚠️ 默认按"未登录"渲染：大多数访客没登录；
      而且 JS 万一没跑起来，也不会在顶栏露出一个点不动的头像。 */
.tb-avatar{
	display: none;              /* ⚠️ 写在上面基础样式之后，靠顺序盖掉它的 display:grid */
	font-size: var(--fs-md);            /* 没传头像时显示昵称首字母 */
	font-weight: 500;
	color: var(--ink-700);
}
.tb-actions.is-logged-in .tb-avatar{ display: grid; }   /* 已登录：头像出现 */
.tb-actions.is-logged-in .tb-btn{ display: none; }      /* 已登录：收起登录 / 注册 */

/* 退出登录：和头像并排的文字按钮。
   ⚠️ 不能复用 .tb-btn —— 上面那条 `.tb-actions.is-logged-in .tb-btn{display:none}`
      会把它一起藏掉，登录后反而看不见。所以另起一个类，单独给显示规则 */
.tb-out{
	display: none;              /* 默认藏，登录后才露出 */
	align-items: center;
	height: 34px;
	padding: 0 12px;
	border: 1px solid var(--line);
	border-radius: var(--r-full);
	background-color: var(--surface);
	color: var(--ink-500);
	font-family: inherit;
	font-size: var(--fs-sm);
	white-space: nowrap;
	cursor: pointer;
	transition:
		background-color var(--dur-fast) var(--ease),
		color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease);
}
.tb-actions.is-logged-in .tb-out{ display: inline-flex; }

/* 唯一允许用语义红的地方 —— 退出是破坏性动作 */
.tb-out:hover{
	border-color: var(--alert-line);
	background-color: var(--alert-soft);
	color: var(--alert);
}


/* =========================== §5 头图卡 .des =========================== */

.des{
	position: relative;
	overflow: hidden;        /* 圆角不被内部元素顶破；也顺便裁掉角落涟漪的溢出面 */
	width: 100%;
	/* 上下 32 比左右 30 略大：横长条的卡片，光加左右会显得"扁"，加高才立得住 */
	padding: 32px 30px;
	border-radius: var(--r-lg);
	border: 1px solid var(--line-blue);

	/* ⚠️ 原来是「radial 柔光 + linear 斜向渐变」。现在改成纯色底 + 角落同心圆涟漪：
	   零渐变，但比一整块死平色多一层结构。
	   涟漪 = 全站统一的角落动机（login.css 的 .brand 右下角用的是同一个）。 */
	background-color: var(--blue-100);
	box-shadow: var(--sh-1);

	display: flex;
	align-items: center;
	flex-wrap: wrap;         /* 变窄时右侧统计换行 */
	gap: var(--sp-4) var(--sp-5);
}

/* 右上角涟漪：3 条同心弧，圆心贴在角上 → 只露出 1/4，像水波从角落荡开 */
.des::after{
	content: "";
	position: absolute;
	top: 0;
	right: 0;
	width: 260px;
	height: 260px;
	pointer-events: none;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260' viewBox='0 0 260 260'%3E%3Cg fill='none' stroke='%239ecfe8' stroke-width='1.5' stroke-opacity='.6'%3E%3Ccircle cx='260' cy='0' r='56'/%3E%3Ccircle cx='260' cy='0' r='98'/%3E%3Ccircle cx='260' cy='0' r='140'/%3E%3C/g%3E%3C/svg%3E");
	background-size: contain;
	background-repeat: no-repeat;
}

/* 内容全部压在涟漪之上 */
.des > *{ position: relative; z-index: 1; }

/* 文字区：flex:1 吃掉剩余宽度 */
.des-main{
	flex: 1;
	min-width: 0;
}

/* 眉标：微型拉丁字 + 拖尾发丝线（日式「見出し」手法）*/
.des-eyebrow{
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0 0 var(--sp-2);
	font-family: var(--font-display);
	font-size: var(--fs-xs);
	font-weight: 500;
	letter-spacing: 0.24em;
	color: var(--ink-500);
}
.des-eyebrow::after{
	content: "";
	width: 46px;
	height: 1px;
	flex-shrink: 0;
	background-color: var(--line-blue);
}

.des-title{
	margin: 0;
	font-size: var(--fs-2xl);
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: 0.06em;   /* 标题拉开字距 */
	color: var(--ink-900);
}

.des-sub{
	margin: 8px 0 0;
	font-size: var(--fs-base);
	line-height: 1.7;
	color: var(--ink-500);
}

/* ---------- 5.1 右侧统计 ---------- */
.des-stats{
	display: flex;
	flex-shrink: 0;
	margin-left: auto;   /* 贴到最右 */
}

.des-stat{
	display: flex;
	flex-direction: column;
	align-items: flex-end;   /* 数字右对齐 */
	padding: 0 var(--sp-5);
}
/* 相邻两项之间画一条发丝线 */
.des-stat + .des-stat{ border-left: 1px solid var(--line-blue); }

.des-stat b{
	font-family: var(--font-display);   /* 数字交给拉丁展示字 */
	font-size: var(--fs-2xl);
	font-weight: 500;
	line-height: 1.2;
	color: var(--ink-900);
	font-variant-numeric: tabular-nums;  /* 等宽数字，变化时不抖 */
}

.des-stat span{
	font-size: var(--fs-xs);
	letter-spacing: 0.1em;
	color: var(--ink-500);
}


/* ====================== §6 筛选栏 .filter / .fl-* ======================
   ① 排序 / 是否 AI 用「藏起来的 radio + label + :checked」，选中态纯 CSS 画，零 JS。
   ② 控件必须待同一个 <form> 里 ——「清空」靠 form.reset()，表单外的它管不到（踩过）。
   ⚠️ 高度写死 30~34px，一行里 input 和 button 的中线才对齐。
   ======================================================================== */
.filter{
	width: 100%;
	display: flex;
	flex-direction: column;
	gap: var(--sp-4);
	padding: var(--sp-4) var(--sp-5);
	border-radius: var(--r-lg);
	background-color: var(--surface);
	border: 1px solid var(--line);
	box-shadow: var(--sh-1);
}

/* 整块筛选区现在只有一个 <form> 子元素，.filter 的 gap 就没对象可撑了，
   所以把同样的「纵向排列 + 行间距」挪到 form 上。
   ⚠️ 少了这段，合并后两行会贴在一起（.fl-row + .fl-row 只剩 padding-top）。 */
.filter > form{
	display: flex;
	flex-direction: column;
	gap: var(--sp-4);
}

/* 一行：右侧分组靠 margin-left:auto 顶到最右；变窄时换行而非压扁 */
.fl-row{
	display: flex;
	align-items: center;
	gap: var(--sp-4);
	flex-wrap: wrap;
}
/* 第二行分隔：一条浅色发丝线 */
.fl-row + .fl-row{
	padding-top: var(--sp-4);
	border-top: 1px solid var(--line-soft);
}

/* ---------- 6.1 关键词输入 ---------- */
.fl-search{
	flex: 1;
	min-width: 180px;
	max-width: 300px;
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	height: 34px;
	padding: 0 12px;
	border-radius: var(--r-sm);
	background-color: var(--blue-50);
	border: 1px solid var(--blue-200);
	color: var(--ink-400);
	transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
		box-shadow var(--dur-fast) var(--ease);
}
.fl-search svg{ width: 15px; height: 15px; flex-shrink: 0; }
.fl-search:focus-within{
	background-color: var(--surface);
	border-color: var(--blue-600);
	box-shadow: 0 0 0 3px rgba(29, 107, 166, 0.22);
	color: var(--ink-700);
}

/* 输入框本体：框交给外层容器画，自己只留文字 */
.fl-input{
	flex: 1;
	min-width: 0;
	height: 32px;
	border: 0;
	background: transparent;
	outline: none;
	font-family: inherit;
	font-size: var(--fs-base);
	letter-spacing: inherit;
	color: var(--ink-900);
}
.fl-input::placeholder{ color: var(--ink-400); }

/* 标签输入框"自带边框"，把边框加回来。⚠️ 必须写在 .fl-input 后面（特异性一样，后写的赢）*/
.fl-input--tag{
	flex: 0 1 260px;         /* 不伸长、可收缩，基准 260px */
	height: 32px;
	padding: 0 12px;
	border-radius: var(--r-sm);
	background-color: var(--blue-50);
	border: 1px solid var(--blue-200);
	transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease),
		background-color var(--dur-fast) var(--ease);
}
.fl-input--tag:focus{
	background-color: var(--surface);
	border-color: var(--blue-600);
	box-shadow: 0 0 0 3px rgba(29, 107, 166, 0.22);
}

/* ---------- 6.2 分组标题 ---------- */
/* 第一行右边整块（排序 + 是否 AI）：margin-left:auto 顶到最右，flex-wrap 内部可换行，「整块」一起掉行不留断层。⚠️ 绝不能漏写 display:flex —— 漏了里面两组会上下堆叠、贴在一起（踩过）*/
.fl-right{
	margin-left: auto;
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	/* 列距 26px 区分两组（不画竖线，换行时线会孤零零挂着）；行距 14px 留呼吸 */
	column-gap: var(--sp-5);
	row-gap: 14px;
}

.fl-group{
	display: flex;
	/* ⚠️ 必须 flex-start 不能 center：窄屏胶囊折两行时，center 会让标签掉到两行中间（实测差 19px）。配下面那行撑高就稳在第一行 */
	align-items: flex-start;
	gap: 10px;
}

/* 撑到 30px（=第一行胶囊高），标签文字才和胶囊垂直居中对齐。⚠️ 用 .fl-group > .fl-label 收窄范围，别影响第二行的标签 */
.fl-group > .fl-label{ line-height: 30px; }

.fl-label{
	flex-shrink: 0;
	font-size: var(--fs-xs);
	font-weight: 500;
	letter-spacing: 0.14em;
	color: var(--ink-500);
}

/* ---------- 6.3 胶囊选项（排序 / 是否 AI / 热门标签共用一套外观） ---------- */
.fl-chips,
.fl-hot{
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;   /* 行距 8，和下面热区对得上 */
}

.fl-chip{
	position: relative;   /* 隐藏 input 和热区 ::after 靠它定位 */
	display: inline-flex;
	cursor: pointer;      /* label 默认文字光标，改成手型 */
}

/* 藏掉 input：不用 display:none（会丢键盘焦点），透明 + 绝对定位既看不见又能被 Tab / :checked 感知 */
.fl-chip-input{
	position: absolute;
	opacity: 0;
	pointer-events: none;
}

/* 露在外面的样子：胶囊（全圆角）。
   ⚠️ 由 --r-sm(10px) 改成 --r-full：10px 落在 30px 高的块上，四角还是"方的"，
      和侧栏 / 图片角标那两处标签对不上（那两处也是标签，形状得是一套）。
   ⚠️ padding 同步从 12px 提到 14px：胶囊两端的圆弧会"吃掉"视觉宽度，
      不加回来文字会显得顶在圆角上、比原来的方角版还挤。 */
.fl-chip span{
	display: inline-flex;
	align-items: center;
	height: 30px;
	padding: 0 14px;
	border-radius: var(--r-full);
	font-size: var(--fs-sm);
	letter-spacing: 0.04em;
	color: var(--ink-700);
	background-color: var(--surface);
	border: 1px solid var(--line);
	transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}

.fl-chip:hover span{
	color: var(--ink-900);
	background-color: var(--blue-50);
	border-color: var(--blue-200);
}

/* 选中态：淡蓝底 + 描边 + 加粗。⚠️ 描边用 --blue-600 不用主色 --blue-400（主色对白只有 1.7:1，选中状态白底上要 ≥3:1）*/
.fl-chip-input:checked + span{
	color: var(--blue-700);
	font-weight: 600;
	background-color: var(--blue-100);
	border-color: var(--blue-500);
}

/* Tab 过来时给个焦点环 */
.fl-chip-input:focus-visible + span{
	box-shadow: 0 0 0 3px rgba(29, 107, 166, 0.4);
}

/* ---------- 6.4 「展开更多 / 收起」——纯 CSS 折叠，零 JS ----------
   原理：藏起来的 checkbox #fl-more 当开关，勾上后靠 ~ 影响后面的标签。
   ⚠️ 前提：① input 和 .fl-chip--extra 必须在同一父元素下且 input 在前（不能跨一层 div）；② 用 ~ 而非 +，因为标签之间还夹着其它元素 */

/* 折叠：多出来的标签默认不占位置 */
.fl-chip--extra{ display: none; }
/* 展开：开关被勾上，后面的 extra 标签全部长出来 */
.fl-more-input:checked ~ .fl-chip--extra{ display: inline-flex; }

/* 开关本体：同 chip 的 input 一样藏起来（保留键盘焦点）*/
.fl-more-input{
	position: absolute;
	opacity: 0;
	pointer-events: none;
}

/* 展开按钮做成"文字 + 箭头"而非胶囊，在一堆胶囊里最像"操作" */
.fl-more{
	display: inline-flex;
	align-items: center;
	gap: 4px;
	height: 30px;
	padding: 0 8px;
	border-radius: var(--r-sm);
	cursor: pointer;
	font-size: var(--fs-sm);
	letter-spacing: 0.04em;
	color: var(--ink-500);
	transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.fl-more:hover{ color: var(--ink-900); background-color: var(--blue-50); }
.fl-more svg{
	width: 12px;
	height: 12px;
	transition: transform var(--dur) var(--ease);   /* 箭头翻转也走过渡 */
}

/* 展开后：箭头翻上去 + 文字换"收起"。两段文字都写在 HTML 里，靠 :checked 决定谁露面，省掉 JS 改文字 */
.fl-more-input:checked ~ .fl-more svg{ transform: rotate(180deg); }
.fl-more-less{ display: none; }
.fl-more-input:checked ~ .fl-more .fl-more-more{ display: none; }
.fl-more-input:checked ~ .fl-more .fl-more-less{ display: inline; }

/* Tab 选中时焦点环画在看得见的按钮上 */
.fl-more-input:focus-visible ~ .fl-more{
	outline: 2px solid var(--blue-700);
	outline-offset: 2px;
}

/* ---------- 6.5 扩大点击热区 ----------
   胶囊只有 30px 高、手指偏小，用透明 ::after 把热区撑到 40px（只往上下撑）*/
.fl-chip::after{
	content: "";
	position: absolute;
	inset: -5px 0;
}

/* ---------- 6.6 行末按钮组（清空 + 保存） ---------- */
/* margin-left:auto 写这层，两按钮一起顶到最右 */
.fl-actions{
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	flex-shrink: 0;
}

/* 按钮共用形状，主次靠底色和边框区分 */
.fl-btn{
	flex-shrink: 0;
	height: 32px;
	padding: 0 16px;
	border: 0;
	border-radius: var(--r-sm);
	cursor: pointer;
	font-family: inherit;
	font-size: var(--fs-sm);
	font-weight: 600;
	letter-spacing: 0.08em;
	color: #fff;
	background-color: var(--blue-600);
	box-shadow: var(--sh-2);
	transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
		color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.fl-btn:hover{ background-color: var(--blue-700); transform: translateY(-1px); }
.fl-btn:active{ transform: translateY(0) scale(0.99); }

/* 次要动作（清空）：描边按钮。⚠️ 边框写 1px solid 而非 0 —— 少了会比"保存"矮 2px、窄 2px（老坑）*/
.fl-btn--ghost{
	color: var(--ink-500);
	background-color: var(--surface);
	border: 1px solid var(--blue-200);
	box-shadow: none;
}
.fl-btn--ghost:hover{
	color: var(--ink-900);
	background-color: var(--blue-50);
	border-color: var(--blue-400);
}


/* ========================= §8 入场动效 =========================
   侧栏 → 顶栏 → 头图 → 筛选栏 → 作品区，每组间隔 60~70ms，整体不到半秒。
   ⚠️ 包在 prefers-reduced-motion 里：开了「减弱动态效果」的用户直接看终态。 */
@media (prefers-reduced-motion: no-preference){
	/* ⚠️ 填的是 backwards，**不是 both**。这不是抠字眼，是个真踩过的坑：
	   both = backwards + forwards，而 forwards 会在动画结束后把 to 帧
	   （transform: none）一直钉在元素上。CSS 动画在层叠里的优先级高于普通声明，
	   于是 §10 那句 `.sb-upload:active{ transform: scale(0.94) }` 永远赢不了 ——
	   按钮按下去一点反应都没有（实测 transform 恒为 matrix(1,0,0,1,0,0)）。
	   backwards 照样能在 delay 期间先藏好，动画一结束就交还控制权，视觉完全一样。 */
	.sb-brand,
	.sb-upload,
	.sb-nav,
	.topbar,
	.des,
	.filter,
	.show{
		animation: wb-rise var(--dur-slow) var(--ease) backwards;
	}
	.sb-brand{ animation-delay: 30ms; }
	.sb-upload{ animation-delay: 90ms; }
	.sb-nav{ animation-delay: 150ms; }
	.topbar{ animation-delay: 60ms; }
	.des{ animation-delay: 130ms; }
	.filter{ animation-delay: 200ms; }
	.show{ animation-delay: 270ms; }
}

@keyframes wb-rise{
	from{ opacity: 0; transform: translateY(10px); }
	to{ opacity: 1; transform: none; }
}


/* ========================= §9 响应式 =========================
   三档：1280 / 1024 / 760（外加 420 微调）。
   ⚠️ 760 以下侧栏的处理（抽屉）不在这里，在文件最后的 §10。 */

@media (max-width: 1280px){
	:root{ --gutter: 26px; }
	.left-sidebar{ width: 212px; }
}

@media (max-width: 1024px){
	:root{ --gutter: 20px; }
	.left-sidebar{ width: 190px; }
	/* 头图卡：统计别挤在右边，换行放到下面 */
	.des-stats{ margin-left: 0; flex-wrap: wrap; gap: var(--sp-3); }
	.des-stat{ padding: 0 var(--sp-4) 0 0; }
	.des-stat + .des-stat{ padding-left: var(--sp-4); }
	.fl-search{ max-width: none; }
}

@media (max-width: 760px){
	:root{ --gutter: 14px; }

	/* 侧栏：改走 §10 的「抽屉」方案。⚠️ 原来收成 60px 图标栏已废弃 —— 再瘦也一直占 60px，手机宽度不够会让内容疯狂换行；抽屉关着时不占位 */

	/* 内容区 */
	.con{ gap: var(--sp-4); }
	.des{ padding: var(--sp-4); }
	.des-title{ font-size: var(--fs-xl); }
	.des-stat{ padding: 0 var(--sp-3) 0 0; }
	.des-stat + .des-stat{ padding-left: var(--sp-3); }
	.filter{ padding: var(--sp-3) var(--sp-4); }
	.fl-input--tag{ flex: 1 1 100%; }           /* 手输框独占一行 */
	.fl-actions{ margin-left: 0; width: 100%; justify-content: flex-end; }
}

@media (max-width: 420px){
	:root{ --gutter: 12px; }
	.des-stat b{ font-size: var(--fs-xl); }
	.fl-chip span{ padding: 0 10px; }
}


/* ================== §10 移动端抽屉（侧栏收走 → 点按钮弹出） ==================
   桌面侧栏常驻；手机上整条平移出屏幕左边，点顶栏汉堡按钮再推回来。
   开关是「藏起来的 checkbox」.sb-toggle，汉堡 / 关闭 / 遮罩全是它的 <label> —— 零 JS。
   ⚠️ DOM 顺序硬要求：.sb-toggle 必须在 .left-sidebar 和 .sb-mask 前面（~ 只认后面的兄弟）。 */


/* ---------- 10.1 开关本身 ---------- */

/* ⚠️ 用 position + opacity 藏，不用 display:none：后者会让键盘也 tab 不到 */
.sb-toggle{
	position: absolute;
	top: 0;
	left: 0;
	width: 0;
	height: 0;
	opacity: 0;
	pointer-events: none;
}

/* 键盘兜底：Tab 到这个隐形 checkbox 时，焦点环画在汉堡按钮上，否则焦点会"凭空消失" */
.sb-toggle:focus-visible ~ .con .tb-burger{
	outline: 2px solid var(--blue-700);
	outline-offset: 2px;
}


/* ---------- 10.2 遮罩 ---------- */

/* 桌面端 display:none 不渲染。⚠️ 手机拉开抽屉后把窗口拉宽，也不会残留灰罩子（:checked 规则只在 760 以下生效）*/
.sb-mask{ display: none; }


/* ---------- 10.3 汉堡按钮 & 关闭按钮 ---------- */

/* 桌面端两个都藏（侧栏一直在）。放一起是因为除位置外长得一样 */
.tb-burger,
.sb-close{
	display: none;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	cursor: pointer;
	color: var(--ink-700);
	background-color: var(--blue-50);
	border: 1px solid var(--blue-200);
	border-radius: var(--r-sm);
	transition: background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.tb-burger svg,
.sb-close svg{ width: 19px; height: 19px; }

.tb-burger:hover,
.sb-close:hover{
	color: var(--ink-900);
	background-color: var(--blue-100);
	border-color: var(--blue-300);
}


/* ---------- 10.3.1 抽屉里的登录 / 注册 ---------- */

/* 桌面端不显示（顶栏已有登录/注册）*/
.sb-auth{ display: none; }

.sb-auth-btn{
	flex: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	font-family: inherit;      /* ⚠️ 按钮不继承字体，不写会变宋体 */
	font-size: var(--fs-base);
	letter-spacing: 0.08em;
	color: var(--ink-700);
	background-color: var(--surface);
	border: 1px solid var(--blue-200);
	border-radius: var(--r-sm);
	transition: background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.sb-auth-btn:hover{
	color: var(--ink-900);
	background-color: var(--blue-50);
	border-color: var(--blue-300);
}

/* 「注册」比「登录」重一点（浅蓝底 + 深字 + 加粗）。⚠️ 不做实心主色 —— 抽屉里已有「上传作品」实心块，再来一个视觉重心会散 */
.sb-auth-btn--reg{
	color: var(--ink-900);
	font-weight: 600;
	background-color: var(--blue-100);
}
.sb-auth-btn--reg:hover{ background-color: var(--blue-200); }


/* ---------- 10.4 手机档：把抽屉拉开 ---------- */

@media (max-width: 760px){

	/* 汉堡按钮现身。40×40，明显大于桌面 34px，手指才不易点空 */
	.tb-burger{ display: flex; width: 40px; height: 40px; }


	/* ---------- 10.4.1 触控目标地板 ----------
   桌面 34/38px 是按鼠标定的，手机上抬一档。⚠️ 只抬最需要点准的几个，别把所有 chip / 输入框都抬到 44px（会挤掉首屏）*/
	.tb-icon,
	.tb-avatar{ width: 40px; height: 40px; }
	.tb-btn{ height: 40px; }

	/* 搜索框抬到 44px，里面 <input> 吃满高度，否则点到框内空白处唤不出键盘 */
	.tb-search{ height: 44px; }
	.tb-input{ height: 100%; }
	.tb-go{ height: 32px; }

	.fl-input{ height: 40px; }
	.sb-upload{ height: 44px; }
	.sb-item{ height: 40px; }

	/* ⚠️ iOS Safari：输入框 font-size < 16px 时一聚焦就放大整页，手机档一律顶到 16px */
	.tb-input,
	.fl-input{ font-size: 16px; }

	/* 侧栏 → 固定定位的抽屉，默认整条推到屏幕外 */
	.left-sidebar{
		position: fixed;          /* 脱离文档流 = 关着时不占位 */
		top: 0;
		bottom: 0;
		left: 0;
		z-index: 50;              /* 要压在顶栏(10) 和遮罩(40) 上面 */
		width: min(82vw, 276px);  /* 右边留余量，暗示后面还有内容 */
		height: auto;             /* 覆盖桌面的 height:100vh + sticky */

		transform: translateX(-100%);
		/* 只过渡 transform 和 box-shadow，别写 all */
		transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);

		/* 抽屉自己滚到底时，别把后面的整页也带着一起滚 */
		overscroll-behavior: contain;
	}

	/* 拉开：平移回原位 + 投影子 */
	.sb-toggle:checked ~ .left-sidebar{
		transform: none;
		box-shadow: 0 24px 64px -24px rgba(22, 34, 46, 0.5),
			0 0 0 1px var(--line-blue);
	}

	/* 遮罩现身 */
	.sb-mask{
		display: block;
		position: fixed;
		inset: 0;
		z-index: 40;              /* 低于侧栏(50)、高于顶栏(10) */
		/* ⚠️ 这里原来是 backdrop-filter: blur(2px) —— 一块盖满全屏的固定层做模糊，
		   是全站最贵的一处，手机上拉开抽屉能明确看到掉帧。
		   去掉后把底色从 0.34 提到 0.44 补回分量：遮罩本来就该"压住"后面，不需要真去糊它。 */
		background-color: rgba(22, 34, 46, 0.44);
		opacity: 0;
		pointer-events: none;     /* 收着时不能挡住点击 */
		transition: opacity var(--dur) var(--ease);
	}
	.sb-toggle:checked ~ .sb-mask{ opacity: 1; pointer-events: auto; }

	/* 关闭按钮：贴品牌区右上角（label，点一下取消勾选）*/
	.sb-close{
		display: flex;
		position: absolute;
		top: var(--sp-3);
		right: var(--sp-3);
		width: 40px;
		height: 40px;
		background-color: transparent;
		border-color: transparent;
	}
	.sb-close:hover{ background-color: var(--blue-100); border-color: transparent; }

	/* 抽屉开着时锁住背景滚动。⚠️ :has() 支持较新，老浏览器整条忽略 —— 后果仅是背景还能滚，开合不受影响，可当渐进增强 */
	body:has(.sb-toggle:checked){ overflow: hidden; }
}


/* ---------- 10.5 窄手机档：把搜索框单独放一行 ----------
   顶栏挤了 7 个控件，实测 390px 时输入框只剩 4px，没法打字。
   解法：让顶栏允许换行 —— 第一行 菜单 + 靠右操作按钮，第二行 占满整行的搜索框。
   ⚠️ 顶栏高度要从 58px 改成 auto，否则第二行会被裁掉 */
@media (max-width: 560px){

	.topbar{
		height: auto;
		flex-wrap: wrap;
		padding-top: var(--sp-2);
		padding-bottom: var(--sp-2);
		row-gap: var(--sp-2);
	}

	/* order 决定换行后的先后 */
	.tb-burger{ order: 1; }
	.tb-actions{ order: 2; }
	/* flex-basis:100% = 独占一整行，自动被挤到下一行 */
	.tb-search{ order: 3; flex: 1 1 100%; max-width: none; }

	/* ---------- 登录 / 注册从顶栏挪进抽屉 ----------
   原因：① 顶栏控件太多抢地方；② 实心蓝「注册」太扎眼。挪进抽屉后第一行只剩菜单 + 暗色 + 头像 */
	.tb-btn{ display: none; }
	.sb-auth{ display: flex; gap: var(--sp-2); }
	.sb-auth-btn{ height: 40px; }   /* 同抽屉其它可点元素的触控高度 */

	/* ---------- 头图卡：手机上改成上下排 ----------
   原来「左文右统计」并排，但 .des-stats 是 flex-shrink:0，窄屏被挤的全是文字区（实测 390px 时只剩 74px）。
   ⚠️ 横向 flex 改 column 后 align-items 必须一起改成 stretch，否则子项缩成内容宽、右边留白 */
	.des{
		flex-direction: column;
		align-items: stretch;
	}
	.des-main{ flex: none; }        /* 不再和统计抢宽度 */
	.des-stats{ margin-left: 0; }   /* 取消"贴到最右"，改回从左排 */
}


/* ==================== §10 果冻交互（全站统一按压回弹） ====================
   动机：所有"能按的东西"按下去像果冻一样缩一下、松手弹回来。
   ⚠️ 两条规则必须成对，少一条就没有 Q 弹感：
     · 基础态：transform 的 transition 用 --ease-q（带过冲）→ 松手才"弹"回来；
     · :active：把 transition 改写成 --dur-press + --ease（不过冲）→ 按下才跟手。
       如果 :active 也用过冲曲线，手指还没松就已经先冲过头再缩回来，手感是飘的。
   ⚠️ 别给大面积元素（.des / .item-show / .up-drop）加 scale —— 大块缩放看着像页面在抖。
   ⚠️ 本节的规则放在文件最后，靠"同优先级后者覆盖"接管前面散落的 :active，别往上搬。 */

.sb-upload, .sb-item, .sb-tag,
.tb-icon, .tb-go, .tb-btn, .tb-avatar, .tb-menu-item,
.fl-chip, .fl-more, .fl-btn,
.tb-burger, .sb-close, .sb-auth-btn{
	transition:
		background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease),
		color var(--dur-fast) var(--ease),
		box-shadow var(--dur-fast) var(--ease),
		transform var(--dur) var(--ease-q);
}

.sb-upload:active, .sb-item:active, .sb-tag:active,
.tb-icon:active, .tb-go:active, .tb-btn:active, .tb-avatar:active, .tb-menu-item:active,
.fl-chip:active, .fl-more:active, .fl-btn:active,
.tb-burger:active, .sb-close:active, .sb-auth-btn:active{
	transform: translateY(0) scale(0.94);
	transition:
		background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease),
		color var(--dur-fast) var(--ease),
		box-shadow var(--dur-fast) var(--ease),
		transform var(--dur-press) var(--ease);
}

/* 通栏宽行（侧栏项、下拉菜单项）：整体缩 0.94 会看出"忽宽忽窄"，幅度收小 */
.sb-item:active, .tb-menu-item:active{ transform: translateY(0) scale(0.975); }

/* 圆形小图标：面积小，缩狠一点才有回弹的"啪" */
.tb-icon:active, .tb-avatar:active,
.tb-burger:active, .sb-close:active{ transform: translateY(0) scale(0.90); }


/* ============ §11 无障碍：减弱动态效果 / 触摸目标 ============ */

/* ⚠️ 系统开了「减弱动态效果」（前庭失调、晕动症用户）时，位移/缩放/淡入全部关掉。
   用 1ms 而不是 0s：0s 会让依赖 transitionend 的代码收不到事件。
   本节规则带 !important，是覆盖第三方/内联过渡的标准做法，别去掉。 */
@media (prefers-reduced-motion: reduce){
	*, *::before, *::after{
		animation-duration: 1ms !important;
		animation-delay: 0ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 1ms !important;
		transition-delay: 0ms !important;
	}
	/* 按压回弹也一并撤掉，否则"按下去跳一下"本身就是位移 */
	.sb-upload:active, .sb-item:active, .sb-tag:active,
	.tb-icon:active, .tb-go:active, .tb-btn:active, .tb-avatar:active, .tb-menu-item:active,
	.fl-chip:active, .fl-more:active, .fl-btn:active,
	.tb-burger:active, .sb-close:active, .sb-auth-btn:active{ transform: none !important; }
}

/* ⚠️ 桌面鼠标不需要 44px（那是手指的尺寸），只在触摸设备上撑开热区。
   用伪元素外扩而不是改 width/height —— 视觉尺寸一个像素都不动，
   只把"能点到的范围"放大。注意伪元素必须挂在有定位的父级下，所以要补 position:relative。 */
@media (pointer: coarse){
	.tb-icon, .tb-avatar, .tb-burger, .sb-close{ position: relative; }
	.tb-icon::after, .tb-avatar::after,
	.tb-burger::after, .sb-close::after{
		content: "";
		position: absolute;
		top: 50%;
		left: 50%;
		/* max() 保证只放大不缩小：本来就 ≥44px 的元素保持原样 */
		width: max(100%, 44px);
		height: max(100%, 44px);
		transform: translate(-50%, -50%);
	}
}
