/*
 * hufu-theme/design-lab —— 前台与编辑器共用的样式。
 *
 * 本仓库的几个老坑，改这个文件之前先看一遍：
 *
 * 1. 改完必须抬 block.json 的 version。`style: file:./style.css` 的 ?ver 取的是
 *    block.json 里的 version，旁边放一个 style.asset.php 会被静默忽略
 *    （script 的 index.asset.php 才管用）。
 *
 * 2. 本主题沿用 Twenty Twenty-Five，没有全局的 box-sizing: border-box。
 *    这里凡是同时有 width 和 padding/border 的地方都得自己写。
 *
 * 3. 注释里不要出现星号加斜杠那个组合，它会把注释提前结束，
 *    然后解析器会把下一条规则整条吞掉，而且哪儿都不报错。
 *
 * 4. 所有视觉和尺寸规则挂 .design-lab，不挂 .wp-block-hufu-theme-design-lab。
 *    编辑器里 useBlockProps() 的包装元素和 render.php 的输出会同时带上后者，
 *    把 min-height/background 写在那儿会生效两次（画布里黑带高度翻倍）。
 *
 * 5. 尺寸一律用 stage 的容器查询单位（cqw/cqh），别用 vw/vh —— 常态只有 62vh 高，
 *    用视口单位这套构图在横带里会散架。换算关系来自原型：原型 stage 就是 100vh，
 *    所以它那些百分比数字原样搬过来即可。
 */

/* ── 外壳 ───────────────────────────────────────────────────────────────── */

.design-lab {
	/* 主题没有全局 border-box，自己写。 */
	box-sizing: border-box;
	position: relative;
	overflow: hidden;

	/*
	 * 底色和文字色都不写死，只继承 —— 默认落到主题的 base(#FFFFFF) 与
	 * contrast(#111111)，也就是白底黑字。要改就在右侧栏「颜色」面板里选，
	 * 区块声明了 supports.color 的 background / text。
	 */

	/* 常态：一条横带，基本上占满一屏。
	   62svh 在 900px 高的屏上只有 558px，图标和名字都被压得偏小；
	   72svh（648px）仍嫌矮，所以这一版直接抬到 90svh —— 1440×900 下 810px，
	   图标随 cqh 一起长到 92px。上限 1000px 只是防超长屏变成一堵墙。
	   下限 360px 是绝对值：视口比它还矮时不能比视口本身更高。
	   用 svh 不用 vh：移动端地址栏收起时 vh 会跳一下，横带跟着抽动。 */
	min-height: clamp(360px, 90svh, 1000px);

	/* EXPLORE 按钮的安全带高度。见 .design-lab__stage 的注释。 */
	--lab-strip: 88px;

	/*
	 * 行的节拍：必须和列的节拍（--left 的 10.3% 舞台宽）在**像素**上相等，
	 * 上下左右四张图标的圆心才构成正方形。列节拍是宽度的 10.3%，行节拍若也
	 * 写成高度百分比，同一份数字在 1440×900（stage 722）只有 130px，比列距
	 * 148px 小一截 —— 这就是「像长方形」的来路。
	 *
	 * 所以这里用 cqw（舞台宽）而不是 cqh：10.3cqw 恒等于列距。
	 * 23cqh 是矮屏上的拟合上限 —— 再大第二排就会顶到 55% 的横分割线和
	 * FABRIC 标签。1440×900 下 min(148.3, 166) = 148，正好是正方形；
	 * 1280×720 这类矮屏退到 128.8（列距 131.8，误差 2%）。
	 *
	 * max(…, 8cqw + 22px) 是窄屏（701~900px 宽）的防重叠项：卡片宽是 8cqw，
	 * 名字那一行的字号有 10px 下限，不再随宽度缩小，于是卡片总高（≈ 8cqw+18）
	 * 会超过 10.3cqw 的节拍，上下两排叠进去几像素。22px 是 18px + 呼吸量。
	 */
	--lab-row-pitch: min(
		max(10.3cqw, calc(8cqw + 22px)),
		23cqh
	);

	/*
	 * 锚点跳转（页眉菜单里的 #design-lab）的落点偏移 —— 刻意保持 0，别改。
	 *
	 * 管理栏看起来会挡住落点：它 position:fixed 盖在顶上 32px，锚点元素滚到
	 * 视口顶端 y=0 就被压住。但 WordPress 为管理栏输出的那条
	 * `html{margin-top:32px}` 已经把整页内容下移了同样的距离，落点自然就在
	 * 管理栏下沿。这里再加 32px 是重复计算，实测会多出一条 32px 的白缝：
	 *
	 *     scroll-margin-top: 0   → section 顶端落在 y=32（正是管理栏下沿）✓
	 *     scroll-margin-top: 32  → section 顶端落在 y=64（多 32px 白边）✗
	 *
	 * 所以除非哪天主题把管理栏那条 bump 去掉了（add_theme_support('admin-bar')
	 * 换掉默认回调），否则不要在这里补偏移。横版页眉不是 sticky，滚走了不占位，
	 * 也不需要为它留位置。
	 */
	scroll-margin-top: 0;

	/*
	 * ── 前景的三档不透明度：全部由 currentColor 派生 ──────────────────────
	 *
	 * 这是「白底也能用」的关键。原先各处写的是 rgba(255,255,255,.x)，底色一改成
	 * 白的，文字变黑了、分割线/轨道圈/胶囊底/描边却还是白的，会一起隐形。
	 * 改成从 currentColor 派生之后，换文字色它们就跟着走。
	 *
	 * 用 color-mix 不是随手挑的：theme.json 的 accent-6 本来就是
	 * `color-mix(in srgb, currentColor 20%, transparent)`，本主题早就以它为基线，
	 * 所以这里不必再写一层 rgba 降级。
	 */
	--lab-veil: color-mix(in srgb, currentColor 10%, transparent);
	--lab-hair: color-mix(in srgb, currentColor 20%, transparent);
	--lab-mute: color-mix(in srgb, currentColor 45%, transparent);

	/*
	 * 反色态（选中的模式键、悬停的 ✕ 与 CTA）的文字色 —— 也就是「挖出来」的那块底色。
	 *
	 * CSS 读不到元素的 background-color，「把祖先的底色当值用」这件事在纯 CSS 里没有解
	 * （试过 currentColor 存进自定义属性、@property 注册，都不行，见下面
	 * .design-lab__knockout）。所以真正的值由 view.js 的 syncBackdrop() 量出来，
	 * 以**内联** --lab-bg 写在 section 上，压过这里这条。
	 *
	 * 这里这条是脚本没跑起来时的兜底（view.js 没加载、或在它之前就报错）：主题 base 是白，
	 * 默认配色下正好对。深底白字那种配色就指望不上了 —— 那正是「选中键白底白字」的来路：
	 * 底板吃的是墨色(白)，文字又是这个写死的白。脚本一跑，文字就跟上真实底色。
	 */
	--lab-bg: var(--wp--preset--color--base, #fff);
}

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

/* 满屏态：矩形由 JS 逐帧写内联 top/left/width/height。
   这里只管「已经是 fixed 了」之后的层叠与外观。 */
.design-lab.is-lab-fixed {
	position: fixed;
	z-index: 9000;

	/* 兜底。真正干活的是 JS 里的 section.style.margin = '0'：本主题开了
	   useRootPaddingAwareAlignments，`.has-global-padding > .alignfull` 会给
	   左右各 -50px 的 margin（root padding = spacing|50 = clamp(30px,5vw,50px)）。
	   切到 fixed 之后那些 margin 依然生效，left:0 + width:1440 会落到 x=-50。
	   下面这条和 WP 那条同为 (0,2,0)，纯看源码顺序，所以不敢只靠它 ——
	   但留一条总比没有强，顺序万一变了还能兜住。 */
	margin: 0 !important;

	border-radius: 0;
}

/* 只有展开动画进行中才给内联尺寸挂过渡。收起时也走同一条路径。 */
.design-lab.is-lab-animating {
	transition:
		top 0.9s cubic-bezier(0.65, 0, 0.35, 1),
		left 0.9s cubic-bezier(0.65, 0, 0.35, 1),
		width 0.9s cubic-bezier(0.65, 0, 0.35, 1),
		height 0.9s cubic-bezier(0.65, 0, 0.35, 1);
}

.design-lab.is-lab-open {
	--lab-strip: 0px;
}

/*
 * 满屏（宽屏轨道版）时这一整块是画布，不是可滚的文档：竖划手势收下来转轨道，
 * 不让浏览器拿去滚页面、触发下拉刷新或者边缘回弹。view.js 里只认单指竖向拖动，
 * 所以横划和双指缩放照旧交给浏览器 —— 这也是这里写 pan-x pinch-zoom 而不是
 * none 的原因：none 会把双指缩放一起关掉，那是实打实的可访问性损失。
 *
 * 700px 以下挡在断点外，但理由和以前不同了：窄屏满屏**也有**轨道（两圈迷你环，
 * 见下面 @media max-width:700px），拦它的不是「没有轨道」，而是关闭态那一屏是
 * 可滚网格 —— 竖划在任何时候都得留给滚动。窄屏转环继续由 view.js 的
 * isMobile() 拦着（spinCards），两个地方都不能松。
 *
 * ⚠️ 下限是 701 不是 700。这里和窄屏那块曾经一头写 min-width:700、一头写
 *    max-width:700，于是**正好 700px 宽时两边同时命中**：touch-action 被这条
 *    拿回 pan-x pinch-zoom，而 view.js 的 MOBILE_QUERY 认为这是手机形态 ——
 *    CSS 和 JS 在同一宽度上各说各话。主题那条 781(max)/782(min) 的不重不漏
 *    在这里同样适用，两个 701 都要保持。
 */
@media ( min-width: 701px ) {
	.design-lab.is-lab-open {
		touch-action: pan-x pinch-zoom;
	}
}

/* ── 舞台 ───────────────────────────────────────────────────────────────── */

.design-lab__stage {
	position: absolute;
	inset: 0;

	/*
	 * 底部留出一条安全带给 EXPLORE 按钮。
	 *
	 * 不留的话：按钮 bottom:22px、高 44px，在 1440×900 会压到最下一排 fabric
	 * 图标约 12px。把 stage 的底边抬到按钮上方，两者就永远不相撞。
	 * 满屏时按钮本来就淡出了，--lab-strip 归零。
	 */
	bottom: var(--lab-strip);

	/* 常态高度由外壳的 min-height 定，stage 铺满；容器查询让 cq 单位有参照。 */
	container-type: size;
	container-name: lab;

	overflow: hidden;
}

/* ── 十字分割线 ─────────────────────────────────────────────────────────── */

/* 数字照搬原型（DesignLab.html:38-52），只把 vh/vw 换成 cqh/cqw。 */

.design-lab__rule {
	position: absolute;
	background: var(--lab-hair);
	z-index: 10;
	pointer-events: none;

	transition:
		transform 1.2s cubic-bezier(0.7, 0, 0.3, 1),
		opacity 0.5s;
}

.design-lab__rule--v {
	width: 1.5px;
	height: 42cqh;
	left: 50%;
	top: 8%;
	transform-origin: top;
}

.design-lab__rule--h {
	width: 85cqw;
	height: 1.5px;

	/* 原型是 50%。行距按平方节拍拉开后，第二排的卡片下沿最高到 54%
	   （15% 起点 + 23% 行距上限 + 16% 卡片高），50% 会从名字中间穿过去；
	   55% 是能同时让开卡片和 FABRIC 标签（56%）的位置。 */
	top: 55%;
	left: 7.5%;
	transform-origin: left;
}

/* 满屏后十字线缩没。 */
.design-lab.is-lab-open .design-lab__rule--v {
	transform: scaleY(0);
}

.design-lab.is-lab-open .design-lab__rule--h {
	transform: scaleX(0);
}

/* ── 分类标签 ───────────────────────────────────────────────────────────── */

.design-lab__label {
	position: absolute;
	z-index: 5;

	/* 位置是 render.php 算好的百分比数字（--left / --top 为无单位数）。 */
	left: calc(var(--left) * 1%);
	top: calc(var(--top) * 1%);

	/* 跟着 stage 缩：横带里小、满屏里大。这一版整体上调了一档。 */
	font-size: clamp(11px, 1.2cqh, 16px);
	letter-spacing: 1px;
	font-weight: 500;
	line-height: 1;
	white-space: nowrap;

	transition: opacity 0.5s ease;
}

.design-lab.is-lab-open .design-lab__label {
	opacity: 0;
}

/* ── 卡片层 ─────────────────────────────────────────────────────────────── */

.design-lab__cards {
	position: absolute;
	inset: 0;
	z-index: 20;
}

.design-lab__card {
	position: absolute;

	/* 坐标由 render.php 算好（原型里是 10 + (i%4)*10.3 这类取模取整，
	   CSS 没有 floor/mod，所以放在 PHP 里算）。
	   --top 是纯百分比的老算法（cq 单位不认时的兜底，行距按高度缩放）；
	   有 cq 支持时走第二条：横坐标交给百分比，纵向第几行交给 --row × 行节拍，
	   行节拍与列距等值，四邻才排成正方形。分类标签没有 --top-origin/--row，
	   两个 fallback 让它们继续用 --top。 */
	left: calc(var(--left) * 1%);
	top: calc(var(--top) * 1%);
	top: calc(
		var(--top-origin, var(--top)) * 1% + var(--row, 0) * var(--lab-row-pitch)
	);

	/*
	 * 宽度：先给纯 px 兜底，再让容器查询覆盖。
	 *
	 * 为什么必须有兜底：卡片是绝对定位，width 一旦失效成 auto 就会收缩到 0，
	 * 整个构图当场消失。老浏览器不认 cq 单位时，第二条声明整条作废，
	 * 第一条就顶上了。
	 *
	 * 数字怎么来的：1440×900 的满屏 stage（868 高）里 min(112, 115.2, 111.1)
	 * = 111.1px；常态横带（90svh，stage 722 高）里 min(112, 115.2, 92.4)
	 * = 92.4px，是 62svh 那一版（56.4px）的 1.64 倍。满屏时宽度其实由
	 * view.js 的 layout() 写内联值，这条只管收起态。
	 */
	width: 112px;
	width: min(112px, 8cqw, 12.8cqh);

	aspect-ratio: 1 / 1;

	display: flex;
	flex-direction: column;
	align-items: center;

	/* 轨道段飞行用这个（写在卡片上，视差写在内层 wrapper 上，两个 transform 分开）。 */
	transition:
		transform 1.6s cubic-bezier(0.22, 1, 0.36, 1),
		opacity 0.8s ease,
		width 1.6s cubic-bezier(0.22, 1, 0.36, 1),
		left 1.6s cubic-bezier(0.22, 1, 0.36, 1),
		top 1.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.design-lab__wrapper {
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 100%;
	will-change: transform;
}

/*
 * 手势转动轨道期间（view.js 在滚轮/滑动时挂上 is-lab-spinning，手停 180ms 后摘掉）。
 *
 * 卡片平时挂着上面那条 1.6s 的 transform 补间 —— 换模式时从旧轨道飞到新轨道
 * 要的就是它。但转动是逐帧写 transform 的，留着那条补间，每一帧的新角度都会被
 * 1.6s 的缓动拖住，转起来黏在手指后面，这就是「不跟手」。所以手势期间只留
 * 透明度那条（换模式时压暗/点亮还要渐变），把 transform 从补间里摘出去。
 *
 * 摘掉的是 transform 而不是 duration：把时长改小会让「跟手」变成另一种抖动，
 * 而且换模式的飞行也会一起变快。
 */
.design-lab.is-lab-spinning .design-lab__card {
	transition: opacity 0.8s ease;
	will-change: transform;
}

.design-lab__zoom {
	width: 100%;
	aspect-ratio: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;

	transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

.design-lab__card img {
	width: 100%;
	/*
	 * 高度由 1:1 的 aspect-ratio 定，不写 height:100%。
	 * height:100% 在这个 flex 图框里会落到「按固有比例算」，竖图（sign 293×320）
	 * 于是给自己算出 101px 高，再把图框一起撑到 101px —— 横图的固有高度只有
	 * 78px，所以这个问题一直只出现在 sign 身上。aspect-ratio 把方框钉死，
	 * 横竖图都停在 92×92，再由 object-fit: contain 自己留白。
	 */
	aspect-ratio: 1 / 1;
	object-fit: contain;
	display: block;
	transform-origin: center;
}

/*
 * 这两张图在画布里的图形本身偏小，原型单独放大 1.25 倍找齐
 * （DesignLab.html:327-329 的 adjust-scale）。镜像时只等比缩放没裁边，
 * 所以这套补偿继续成立。
 */
.design-lab__card.is-scale-up img {
	transform: scale(1.25);
}

/*
 * 反向补偿：清单里只有 sign 是竖图（293×320），其余都是 320×2xx 的横幅。
 * contain 让横图按宽度吃满、竖图按高度吃满，所以即便图框已经修回 1:1，
 * sign 的图形高度仍是 92px，比同排最高的 skin / speak（88px）还高一截。
 * 再缩 5% 落到 87px，和邻居齐平。
 */
.design-lab__card.is-scale-down img {
	transform: scale(0.95);
}

/*
 * 原型的标签是死的 font-size:10px + margin-top:10px，不随 stage 缩放。
 * 实测横带里行距只有 90~100px，字号一旦跟不上卡片就会直接重叠。把字号和
 * 上边距都纳入 cq 缩放后，横带里大约 12.3px、满屏里 12.5px，比原型
 * （10px）明显大一档。
 *
 * 上限 12.5px 是量出来的：最长的一行 digitizationsimulation 在 9.75px 时
 * 宽 111px，按比例放到 12.5px 约 142px，列距 148px 还放得下；再大就会和
 * 右边 WEIGHT 的字挨上。
 *
 * 前缀那条纯 px 是兜底：cq 单位不认时整条 clamp 作废，得有个能落地的值。
 */
.design-lab__name {
	margin-top: 10px;
	margin-top: clamp(4px, min(0.8cqw, 1.1cqh), 10px);
	font-size: 12.5px;
	font-size: clamp(10px, min(0.86cqw, 1.7cqh), 12.5px);
	line-height: 1.2;
	text-transform: uppercase;
	text-align: center;
	white-space: nowrap;

	/* 不再写死白色：继承 .design-lab 的 currentColor，换配色跟着走。 */
	color: inherit;

	transition: opacity 0.5s;
}

/*
 * 键盘焦点环自己画。
 *
 * WP 的全局样式里有一条 `:where(.wp-site-blocks :focus){outline-style:solid;
 * outline-width:2px}` —— 它连鼠标点出来的焦点（:focus）也描边，于是点一张图标会
 * 在放大后的图标外面套一个黑色方框，看着像漏了一条边框。`:where()` 的特异性是 0，
 * 自己写一条就压得过：:focus 关掉，:focus-visible 画一条细的 —— 键盘用户照样看得见，
 * 鼠标点击不再有框。
 */
.design-lab .design-lab__card:focus {
	outline: none;
}

.design-lab .design-lab__card:focus-visible {
	outline: 1px solid color-mix(in srgb, currentColor 35%, transparent);
	outline-offset: 6px;
}

/* 悬停：卡片浮到最上、图标放大、名字无论在哪一圈都亮起来。 */
.design-lab__card:hover {
	z-index: 100;
}

.design-lab__card:hover .design-lab__zoom {
	transform: scale(1.4);
}

.design-lab__card:hover .design-lab__name {
	opacity: 1;
}

/* 轨道三层：越外圈越淡，名字在外圈基本隐掉。 */
.design-lab__card.is-layer-1 {
	opacity: 1;
}

.design-lab__card.is-layer-2 {
	opacity: 0.5;
}

.design-lab__card.is-layer-3 {
	opacity: 0.15;
}

.design-lab__card.is-layer-2 .design-lab__name {
	opacity: 0.6;
}

.design-lab__card.is-layer-3 .design-lab__name {
	opacity: 0;
}

/* 收起的一瞬间要让卡片立刻回网格，不能等 1.6s 的飞行 —— 否则盒子已经缩回
   470px 了，图标还在半路上，会看到 216px 的巨图塞在小 stage 里。 */
.design-lab.is-lab-closing .design-lab__card,
.design-lab.is-lab-closing .design-lab__wrapper {
	transition: none;
}

/* ── 轨道参考圈 ─────────────────────────────────────────────────────────── */

.design-lab__guide {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);

	border: 1px solid var(--lab-veil);
	border-radius: 50%;
	pointer-events: none;
	opacity: 0;

	/* 直径由 JS 按 baseSize 写。 */
	transition: opacity 1s ease;
}

.design-lab.is-lab-open .design-lab__guide {
	opacity: 1;
}

/* ── 底部按钮组（EXPLORE + 圆形次按钮）──────────────────────────────── */

/*
 * 三列网格：两侧各一条 minmax(0,1fr)，中间 auto 放 EXPLORE。1fr 让左右两边
 * 恒等宽，主按钮的中心就永远压在这块的垂直中线上，跟右边圆钮展开成多宽无关
 * —— 圆钮在第三条轨道里，轨道最小 0，它变宽只会溢出轨道，不会把轨道撑大、
 * 也就不会把主按钮挤得往左挪。
 *
 * 不能改成「整组 flex 居中」：那样内容一宽，translateX(-50%) 就让主按钮每帧
 * 往左飘几像素。也不能把圆钮绝对定位在 left:100% 上：绝对定位盒的宽度是
 * shrink-to-fit，而 left 已把可用宽度吃掉，算出来是负数（实测圆钮只长到
 * 56px，文字格被压成 0），grid 的 0fr → 1fr 展开就失效了。
 *
 * 盒子铺满整行只为给两条 1fr 提供参照，本身不吃点击 —— 不然底部这条
 * 44px 高的横带会把「点空白处收起」的点击全拦下来。
 */
.design-lab__actions {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 22px;
	z-index: 30;

	display: grid;
	grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
	align-items: center;
	pointer-events: none;

	transition: opacity 0.5s ease, visibility 0.5s ease;
}

.design-lab__actions > * {
	pointer-events: auto;
}

/* ── EXPLORE 按钮 ───────────────────────────────────────────────────── */

.design-lab__start {
	grid-column: 2;

	/*
	 * 高度改成定值 44px，不再靠 font-size 加内边距碰运气 —— 正文继承下来的
	 * 行高一旦变（18px 字号 × 1.7），10px 的上下内边距仍会把胶囊顶到 53px，
	 * 和右侧 40px 的圆钮一胖一瘦。定高之后字体怎么变都不影响这两颗的高度。
	 */
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 44px;
	padding: 0 64px;
	border-radius: 100px;
	border: 1px solid var(--lab-hair);

	background: var(--lab-veil);
	-webkit-backdrop-filter: blur(15px);
	backdrop-filter: blur(15px);
	color: inherit;

	font: inherit;
	font-weight: 800;
	letter-spacing: 1px;
	cursor: pointer;
	white-space: nowrap;

	/*
	 * 常态不给投影，悬停才给一点（见下面的 :hover）。
	 *
	 * 原来这里是一条 0 8px 32px 的大影子。问题是按钮离这块的底边只有 22px，
	 * 影子往下能铺开 40px —— 越出底边的那截被 .design-lab 的 overflow:hidden
	 * 齐齐切断，断口正好压在这块的边界上，等于用一圈影子把 section 的边框
	 * 「描」了出来。悬停给 2px/8px 就够把胶囊从底色上托起来，又铺不到边界。
	 *
	 * 投影刻意不跟 currentColor 走：它的职责是「比底色更暗」，不是「文字色」。
	 * 跟了的话，深底白字时会变成一圈白色光晕。保持深色：默认白底上是一层正常
	 * 投影，深色底上几乎看不见，两种情况都不突兀。
	 */
	transition: opacity 0.5s ease, visibility 0.5s ease, background 0.3s, transform 0.3s,
		box-shadow 0.3s;
}

.design-lab__start:hover {
	background: var(--lab-hair);
	transform: scale(1.05);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.design-lab__start:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 3px;
}

/*
 * 透明还不够：visibility 才能把它从 Tab 顺序里摘掉。
 * 满屏时按钮在 stage 之外、盒子又被撑到视口大小，它其实还在原地，
 * 只是看不见 —— 不摘掉的话键盘用户会 Tab 到一个隐形的按钮。
 *
 * 隐藏挂在外层盒子上，两颗一起退场：只藏子元素的话，外层这颗空盒子
 * 仍然盖在 stage 底部中央，会拦掉那儿本该落到「空白处」的点击。
 */
.design-lab.is-lab-open .design-lab__actions {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
}

/* ── EXPLORE 右侧的圆形次按钮 ─────────────────────────────────────────── */

/*
 * 常态是一颗 44px 的圆点（42px 图标格 + 左右各 1px 边框），紧贴在 EXPLORE
 * 右侧 10px 处，两者构成一组主/次按钮 —— 高度和 EXPLORE 的 44px 对齐，
 * 并排时不至于一颗高一颗矮。
 *
 * 待在网格第三列、左边缘对齐轨道起点，所以展开时左边缘钉死、往右长：
 * 主按钮不动，圆钮自己变宽。宽度由文字决定，文案改成多长都能装下，
 * 不用在 CSS 里猜。
 *
 * 宽度动画交给 .design-lab__corner-label 的 grid 0fr → 1fr：
 * 用 max-width 做的话，目标值一旦远大于文字实际宽度，未等动画走完就已经
 * 弹到满宽（实测 0.55s 的曲线在 30ms 内就到位），看着是「跳」不是「展开」。
 * grid 轨道从 0 增长到内容宽度，宽度才真的一帧一帧跟得上。
 */
.design-lab__corner {
	grid-column: 3;
	justify-self: start;
	margin-left: 10px;

	display: flex;
	align-items: center;
	gap: 0;
	height: 44px;

	/*
	 * 左侧内边距从 0 长到 16px，和展开同步。不补的话文字从胶囊左缘第 1px
	 * 起排，正好压在 20px 的圆角上，S 被切掉一角；而常驻的内边距又会让圆心
	 * 这颗 40px 的圆点变成 56px。所以它只能跟着展开一起长。
	 */
	padding-left: 0;

	position: relative;
	/* 自成一个层叠上下文：下面的玻璃层用 z-index:-1 退到文案之后，不会跑出
	   这颗按钮去盖住外面的东西。 */
	isolation: isolate;

	border-radius: 100px;
	border: 1px solid var(--lab-hair);

	color: inherit;
	text-decoration: none;
	overflow: hidden;
	cursor: pointer;

	transition:
		gap 0.55s cubic-bezier(0.16, 1, 0.3, 1),
		padding-left 0.55s cubic-bezier(0.16, 1, 0.3, 1),
		opacity 0.5s ease,
		visibility 0.5s ease;
}

/*
 * 毛玻璃底 + 一个真的洞。
 *
 * 底色和背景模糊都挪到 ::before 上：遮罩只能作用在它自己那一层，留在元素
 * 身上就挖不动 —— 元素自己的 background 画在 border-box 里，mask 会连边框
 * 一起裁掉，等于把整颗按钮挖没。
 *
 * 洞的位置以**右缘**为基准：图标格永远钉在右端，展开时只有文字往左长，
 * 圆心不动，所以一个静态的 calc() 就能跟住两种状态。圆心距外缘 22px
 * （1px 边框 + 42px 图标格的一半）；::before 的盒子右边贴着边框内侧，
 * 所以是 21px。半径 9px，和下面 ::after 的 18px 洞沿对齐，8.5 → 9
 * 留半像素做抗锯齿。
 */
.design-lab__corner::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;

	background: var(--lab-veil);
	-webkit-backdrop-filter: blur(15px);
	backdrop-filter: blur(15px);

	-webkit-mask-image: radial-gradient(circle at calc(100% - 21px) 50%, transparent 0 8.5px, #000 9px);
	mask-image: radial-gradient(circle at calc(100% - 21px) 50%, transparent 0 8.5px, #000 9px);

	transition: background 0.3s ease;
}

/*
 * 洞沿：和按钮边框同一条 --lab-hair，正好压在遮罩挖开的那圈边界上 ——
 * 一半在玻璃上、一半悬在页面那一层，看起来才像钻出来的孔，而不是
 * 玻璃上贴了张浅色圆片。
 */
.design-lab__corner::after {
	content: "";
	position: absolute;
	top: 50%;
	right: 12px;
	width: 18px;
	height: 18px;
	transform: translateY(-50%);
	border-radius: 50%;
	border: 1px solid var(--lab-hair);
	pointer-events: none;
}

.design-lab__corner-label {
	display: grid;
	grid-template-columns: 0fr;
	min-width: 0;

	transition: grid-template-columns 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}

.design-lab__corner-text {
	overflow: hidden;
	white-space: nowrap;
	min-width: 0;

	font-size: 11px;
	font-weight: 700;
	letter-spacing: 1px;
	line-height: 1;

	opacity: 0;
	transition: opacity 0.35s ease;
}

/* 空盒子，只负责把右端那 42px 占住 —— 洞本身由 CSS 画（见上面的 ::before/::after）。 */
.design-lab__corner-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 42px;
	height: 42px;
	flex: none;
}

/*
 * 展开只在真有指针悬停的设备上生效。触屏上 :hover 会「粘住」，
 * 展开后的胶囊会一直挂在 EXPLORE 右边、把构图撑歪，所以窄屏只保留圆点。
 *
 * 悬停底色与 EXPLORE 用同一个 --lab-hair，不再反色：两颗按钮是一组，
 * 一颗变灰、另一颗翻成墨底白字的话，看着像两套控件。
 */
@media (hover: hover) {

	.design-lab__corner:hover::before {
		background: var(--lab-hair);
	}
}

/*
 * 展开另外要求 min-width: 601px。圆钮待的第三列宽度是「半屏减掉主按钮的一半」，
 * 窗口窄到 545px 以下时这一列装不下展开后的 150px，shrink-to-fit 会把文字格
 * 压窄、文案被截掉一截。低于这个宽度就当它是一颗纯圆钮。
 */
@media (hover: hover) and (min-width: 601px) {

	.design-lab__corner:hover {
		gap: 16px;
		padding-left: 16px;
	}

	.design-lab__corner:hover .design-lab__corner-label {
		grid-template-columns: 1fr;
	}

	.design-lab__corner:hover .design-lab__corner-text {
		opacity: 1;
	}
}

/* 键盘用户也应该看得到文案：聚焦时与悬停同样展开、同样换底色。 */
.design-lab__corner:focus-visible::before {
	background: var(--lab-hair);
}

.design-lab__corner:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 3px;
}

@media (min-width: 601px) {

	.design-lab__corner:focus-visible {
		gap: 16px;
		padding-left: 16px;
	}

	.design-lab__corner:focus-visible .design-lab__corner-label {
		grid-template-columns: 1fr;
	}

	.design-lab__corner:focus-visible .design-lab__corner-text {
		opacity: 1;
	}
}

/* 满屏后的退场由外层 .design-lab__actions 统一处理，见上面 EXPLORE 那段。 */

/* ── 底部导航栏 ─────────────────────────────────────────────────────────── */

.design-lab__nav {
	position: absolute;
	left: 50%;
	bottom: 0;
	transform: translate(-50%, calc(100% + 24px));

	display: flex;
	align-items: center;
	gap: 15px;
	z-index: 40;

	/* 关闭态除了移出可视区，还要 visibility:hidden + inert —— 它被
	   overflow:hidden 裁掉了但仍在 Tab 顺序里，会让焦点跳到看不见的按钮上。 */
	visibility: hidden;
	transition:
		bottom 0.8s cubic-bezier(0.16, 1, 0.3, 1),
		transform 0.8s cubic-bezier(0.16, 1, 0.3, 1),
		visibility 0.8s;
}

.design-lab.is-lab-open .design-lab__nav {
	bottom: 40px;
	transform: translate(-50%, 0);
	visibility: visible;
}

.design-lab__cta {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 44px;
	padding: 0 25px;
	border-radius: 100px;

	background: var(--lab-veil);
	-webkit-backdrop-filter: blur(15px);
	backdrop-filter: blur(15px);
	border: 1px solid var(--lab-hair);

	color: inherit;
	text-decoration: none;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 1px;
	white-space: nowrap;
	cursor: pointer;
	transition: 0.3s;
}

/*
 * 这颗胶囊只在「链接地址」填了的时候才存在（见 render.php），所以这里按真链接写，
 * 不再需要 [href] 这种「只认能点的那颗」的限定 —— 以前没填地址会退化出一颗
 * 不可点的假按钮，那套区分已经跟着一起删了。
 *
 * 悬停反色：底板吃 currentColor。这里**不能**再写 color: var(--lab-bg) ——
 * 见 .design-lab__knockout 那段。基态的 color: inherit 已经让它拿到墨色。
 */
.design-lab__cta:hover {
	background: currentColor;
}

.design-lab__modes {
	display: flex;
	padding: 6px;
	border-radius: 100px;

	background: color-mix(in srgb, currentColor 5%, transparent);
	-webkit-backdrop-filter: blur(15px);
	backdrop-filter: blur(15px);
	border: 1px solid var(--lab-veil);
}

.design-lab__mode {
	background: none;
	border: none;
	border-radius: 100px;
	padding: 10px 24px;

	color: var(--lab-mute);
	font: inherit;
	font-size: 11px;
	font-weight: 700;
	cursor: pointer;
	white-space: nowrap;
	transition: 0.4s;
}

/* 选中态：先 color: inherit 把上面那条 --lab-mute 压回去，currentColor 才是实心墨色。
   顺序有意义：两条声明同属一个规则，currentColor 看到的是本元素最终的 color。 */
.design-lab__mode.is-active {
	color: inherit;
	background: currentColor;
}

.design-lab__mode:focus-visible,
.design-lab__cta:focus-visible,
.design-lab__close:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 2px;
}

.design-lab__close {
	width: 44px;
	height: 44px;
	flex: none;
	border-radius: 50%;

	background: var(--lab-veil);
	-webkit-backdrop-filter: blur(15px);
	backdrop-filter: blur(15px);
	border: 1px solid var(--lab-hair);

	color: inherit;
	font: inherit;
	font-size: 18px;
	line-height: 1;
	cursor: pointer;
	transition: 0.3s;
}

.design-lab__close:hover {
	background: currentColor;
}

/*
 * ── 反色态的文字挖空 ──────────────────────────────────────────────────────
 *
 * 选中键、悬停的胶囊、悬停的 ✕ 都是「底板 = 这一节的墨色，文字 = 这一节的底色」。
 * 底板用 background: currentColor 拿墨色，但 currentColor 指的是**元素自己**的
 * color —— 一旦在同一个元素上再写 color: var(--lab-bg)，currentColor 当场变成
 * 那块底色，结果就是白底白字，文字整个消失。
 *
 * 试过但**没用**的两条路，别再走：
 *   1. 把墨色存进自定义属性（--lab-ink: currentColor）—— 自定义属性是文本替换，
 *      currentColor 依旧在使用它的那个元素上求值，等于没换。
 *   2. @property 注册成 <color> 想把它「钉」在声明处 —— 实测 Chrome 155 里注册过的
 *      属性写 currentColor 照样在使用处求值。注册表本身是好的，救不了这一条。
 *
 * 所以反色拆成两层：控件自己 color: inherit（回到祖先的墨色，currentColor 因此拿得到
 * 墨色），文字另交给一个后代 span 承接底色。render.php 会给这几处文案套上
 * .design-lab__knockout —— 不在反色态时它不被任何规则命中，完全透明。
 */
.design-lab__mode.is-active .design-lab__knockout,
.design-lab__cta:hover .design-lab__knockout,
.design-lab__close:hover .design-lab__knockout {
	color: var(--lab-bg);
}

/* ── 页面滚动锁 ─────────────────────────────────────────────────────────── */

/* html 和 body 都加：iOS Safari 只锁 html 并不可靠。
   本块用 JS 里的计数守住，同页两个实例不会互相锁死。 */
html.hufu-lab-open,
body.hufu-lab-open {
	overflow: hidden;
}

/* ── 展开态：让别的 section 和页眉让路 ──────────────────────────────────── */

/*
 * 展开时逐层向上，给每一层的兄弟节点加这个类 —— 只动兄弟、不动祖先。
 * 祖先一旦有了 opacity 或 transform 就会造出层叠上下文，把 position:fixed
 * 的 section 关进去，展开动画当场变成「在页面里撑大」而不是盖满视口。
 */
.hufu-lab-dimmed {
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.55s ease;
}

/* ── 聚焦：点一张图标，它飞出圆环 ───────────────────────────────────────── */

/*
 * 满屏里每张图标都是按钮（view.js 展开时补上 role/tabindex、收起时摘掉 ——
 * 常态横带里点了没有反应，不留 Tab 停靠点）。手型光标只在真的能点的地方给。
 */
@media ( min-width: 701px ) {
	.design-lab.is-lab-open .design-lab__card {
		cursor: pointer;
	}
}

/* 参考圈放大并淡掉：既是「圆环撑开、让出中间」的那一步，也是长大的余韵。
   不淡到 0 —— 留一层很淡的圈，画面才还读得出这是个系统。 */
.design-lab.is-lab-focused .design-lab__guide {
	transform: translate(-50%, -50%) scale(1.45);
	opacity: 0.25;
	transition: transform 1.2s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.9s ease;
}

/* 其余卡片往外让开（半径由 JS 乘 FOCUS_PUSH）+ 淡成底影。
   同样不淡到 0：留一点点，读起来是「环退到远处了」而不是「东西全没了」。

   pointer-events:none 不只是「别点底影」：信息面板横在正中，底下正压着退开的
   那几张卡片，不摘掉指针事件的话，点面板上的说明文字会命中它们背后的图标 ——
   而 JS 那边「点别处 = 返回」靠的正是这一下能落到 stage 上。

   0.07 是试出来的：再高（0.12）它们会飘在说明文字背后，正文读起来发毛；
   再低就彻底看不见了，而「环还在、只是退远了」这个意思要靠它们兜着。
   不叠 blur()：那要给 31 张图每帧重算一遍模糊，为这点观感不值得。 */
.design-lab.is-lab-focused .design-lab__card {
	opacity: 0.07;
	pointer-events: none;
}

/* 拎出来的那张照旧可点：再点一下就是放回去。 */
.design-lab.is-lab-focused .design-lab__card.is-focused {
	opacity: 1;
	pointer-events: auto;
	z-index: 200;
}

/* 聚焦的那张，名字交给信息面板用正常字号去说，卡片自带的 10px 小标签收起来。
   图标也不再悬停放大 —— 它已经是画面里最大的东西了。 */
.design-lab.is-lab-focused .design-lab__card.is-focused .design-lab__name {
	opacity: 0;
}

.design-lab.is-lab-focused .design-lab__card.is-focused .design-lab__zoom {
	transform: none;
}

/*
 * 信息面板。
 *
 * 位置不是随手定的：聚焦的图标停在「中心上方 FOCUS_RISE」处，而它的高度正好是
 * FOCUS_RISE 的两倍（view.js 里 0.32 / 2 = 0.16），所以图标下沿恰好压在正中线上，
 * 面板从 top:50% 往下排就不会和它打架。
 *
 * pointer-events:none 是必须的：面板横在画面正中，挡住的话「点空白处返回」就点不穿。
 * visibility:hidden 负责在非聚焦态把它从无障碍树和 Tab 顺序里摘掉。
 */
.design-lab__info {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translateX(-50%);
	z-index: 250;

	width: min(46ch, 80%);
	margin-top: clamp(14px, 3cqh, 34px);

	text-align: center;
	pointer-events: none;

	opacity: 0;
	visibility: hidden;
	transition: opacity 0.6s ease 0.2s, visibility 0.6s;
}

.design-lab.is-lab-focused .design-lab__info {
	opacity: 1;
	visibility: visible;
}

/* 这块里没有全局的 margin 归零（主题只给了 box-sizing），自己来。 */
.design-lab__info-cat,
.design-lab__info-name,
.design-lab__info-desc,
.design-lab__info-hint {
	display: block;
	margin: 0;
}

.design-lab__info-cat {
	font-size: clamp(9px, min(1.1cqh, 0.9cqw), 12px);
	font-weight: 700;
	letter-spacing: 2.5px;
	text-transform: uppercase;
	opacity: 0.45;
}

.design-lab__info-name {
	margin-top: clamp(6px, 1.2cqh, 14px);
	font-size: clamp(19px, min(3.4cqh, 2.6cqw), 40px);
	font-weight: 800;
	line-height: 1.05;
	letter-spacing: 0.5px;
	text-transform: uppercase;
	overflow-wrap: anywhere; /* 免得 digitizationsimulation 这种长词顶破面板 */
}

.design-lab__info-desc {
	margin-top: clamp(8px, 1.6cqh, 18px);
	font-size: clamp(12px, min(1.75cqh, 1.1cqw), 16px);
	line-height: 1.75;
	opacity: 0.6;
}

/* 上面那条把 display 写成了 block，作者样式压得过 UA 的 [hidden]{display:none}，
   所以要自己补一条 —— 没填说明的图标不该留一行空白。 */
.design-lab__info-desc[hidden] {
	display: none;
}

.design-lab__info-hint {
	margin-top: clamp(12px, 2.4cqh, 26px);
	font-size: clamp(9px, min(1.1cqh, 0.85cqw), 11px);
	letter-spacing: 1.5px;
	text-transform: uppercase;
	opacity: 0.32;
}

/* ── 窄屏：另一种形态（两圈迷你轨道 + 底部抽屉）──────────────────────────── */

/*
 * 700px 是「触屏 / 平板」的分界，不是主题那条 781px 的「内容栏宽」分界。
 * 故意不统一：iPad 竖屏正好 768px，落在 700~781 之间，而半径流体化之后
 * 那里恰好是好看的，跟着 781 走会白白把 iPad 竖屏推进手机形态、丢掉圆环。
 * view.js 里的 MOBILE_QUERY 是同一个数字，两边要一起改。
 *
 * 这里不是「降级」——是同一套东西的两种画法：
 *
 *   关闭态：31 张图标的流式网格（横带比桌面矮，靠内容撑高）
 *   满屏态：两圈迷你轨道，**只画当前分类**（8 或 15 张），点图标从底部升起信息
 *
 * 圈数、半径、卡尺寸在 view.js 的 layout() 里算（那儿有为什么是 0.20/0.42
 * 这组数的推导），这里只负责摆位方式和底栏形态。
 */
@media (max-width: 700px) {

	.design-lab {
		/* 窄屏横带矮一点。这里**不再设 --lab-strip** —— 原来的 92px 是死代码：
		   .design-lab.is-lab-open{--lab-strip:0} 权重 (0,2,0) 压过 (0,1,0)，
		   而关闭态 stage 是 inset:auto，两处都用不上它。满屏时轨道避让底栏
		   改由 view.js 的 navStrip() 实测高度（那是布局真正需要的东西）。 */
		min-height: clamp(320px, 72svh, 720px);

		/* 底部抽屉和底栏共用的高度。抽屉靠它坐在底栏上方而不是互相遮。
		   这里的 calc 只是**首帧兜底**：满屏后 view.js 会把 nav 的实测高度
		   内联写回这个变量（窄屏底栏的三颗模式键是自适应的，估算值迟早对不上），
		   轨道避让用的是同一个数 —— 一个让开、一个没让开就是这么来的。
		   76 = 实测的底栏高（三颗键 63 + 下缘抬起的 12）+ 1px 余量，跟原来
		   64 对 63 的余量一致。 */
		--lab-nav-h: calc(76px + env(safe-area-inset-bottom, 0px));
	}

	/* 关闭态：靠内容撑高，不能让 stage 铺满固定高度。
	   必须用 inline-size —— size 会把高度也交给容器查询，而这里高度恰恰
	   要由内容决定，用 size 会把卡片压扁。 */
	.design-lab__stage {
		position: relative;
		inset: auto;
		height: auto;
		container-type: inline-size;
		overflow: visible;
	}

	/* 满屏态：回到 fixed 盒子里的绝对定位，容器查询切回 size（高度由盒子定了），
	   也不再需要滚动 —— 两圈装得下，底栏的高度已经在算半径时让出来了。 */
	.design-lab.is-lab-open .design-lab__stage {
		position: absolute;
		inset: 0;
		container-type: size;
		overflow: hidden;
	}

	/*
	 * 关闭态的网格。底部留白要盖过 EXPLORE 那颗胶囊 —— 它在窄屏压在网格下缘，
	 * 留不够最后一排图标就和按钮叠上：390px 宽实测叠了 6px（按钮上沿比最后一排的
	 * 下沿还高 6px），用户反馈的「EXPLORE 太贴图片」就是这个。
	 *
	 * 102px 拆开是：按钮高 56px（含边框，360px 下 55）+ 它的 bottom 偏移 22px +
	 * 想留的 24px 空隙。按钮的 padding 或 bottom 一动，这里要跟着重量一遍。
	 */
	.design-lab__cards {
		position: static;
		inset: auto;

		display: flex;
		flex-wrap: wrap;
		justify-content: center;
		gap: clamp(8px, 2.5vw, 14px);

		padding: clamp(40px, 12vw, 56px) 16px calc(56px + 22px + 24px);
	}

	/*
	 * 满屏态把摆位权交回给 layout()：left/top/width 都是它写的内联值。
	 * 这里只把关闭态网格用的静态定位解开，**不要**再写 width —— 内联宽度
	 * 压得过这里，写了也只是个看不懂的摆设。
	 */
	.design-lab.is-lab-open .design-lab__cards {
		position: absolute;
		inset: 0;
		display: block;
		padding: 0;
	}

	.design-lab__card {
		position: static;
		flex: 0 0 auto;

		/* 64 → 76px：手机上图标也大了一档。390px 宽时一行从 5 张变 4 张，
		   整节因此更高，正好和「高度高一点」一起生效。 */
		width: 76px;
		height: auto;
		aspect-ratio: auto;
	}

	/*
	 * 满屏态把摆位权交回给 layout()：left/top/width/transform 全是它写的内联值。
	 *
	 * ⚠️ 这里**不能**写 `transform: none !important`。placeCard() 写的是内联
	 *    transform，而 !important 的作者声明压得过内联 —— 加上的话窄屏的环
	 *    整个不转，卡片全叠在圆心。原来那一版有这条，是因为当时跨形态时
	 *    resetCards() 不会被调用、内联几何会残留；现在 onResize 已经会在
	 *    形态切换时清干净（见那边的注释），这条兜底就成了纯粹的破坏。
	 *
	 * width 写回容器查询那套，而不是 auto：绝对定位 + auto 宽会收缩成 0，
	 * 万一哪天 layout() 没跑到就是一片空白。内联值照旧压过它。
	 *
	 * 数字对的是 layout() 的算法：卡片 = baseSize × 0.18（内圈）/ 0.14（外圈），竖屏时
	 * baseSize ≈ 容器宽，所以 15cqw 正好落在两档之间（桌面那条 7cqw 不能照抄 ——
	 * 同样的 7cqw 在 390px 的容器上只有 27px）。30cqh 防极矮横屏把环撑爆。
	 */
	.design-lab.is-lab-open .design-lab__card {
		position: absolute;
		width: min(100px, 15cqw, 30cqh);
		aspect-ratio: 1 / 1;
	}

	.design-lab__zoom {
		aspect-ratio: 1 / 1;
	}

	/* 十字分割线和象限标签是桌面构图的坐标系统，两圈迷你轨道里没有它们的位置。 */
	.design-lab__rule,
	.design-lab__label {
		display: none;
	}

	/* 55~70px 的卡片放不下名字（还有 digitizationsimulation 这种 21 个字的长名）。
	   名字不是不给，是改在底部抽屉里用正常字号说。 */
	.design-lab__name {
		display: none;
	}

	/*
	 * 一次只显示当前分类：未匹配的直接收起来，不是压暗。
	 * 窄屏只有两圈、装不下 31 张，压暗会留下 16 张看不清也点不到的残影。
	 */
	.design-lab__card.is-filtered {
		display: none;
	}

	/*
	 * 聚焦（点开一张）：不做桌面那套「其余淡成 0.07 的底影」—— 窄屏没有飞出去的
	 * 那张大图占住中心，全淡掉就只剩一片空。改成「这张留亮，其余退到 0.25」，
	 * 读起来还是「环退远了」，但手机上一眼能看出还能点别的。
	 *
	 * pointer-events 必须留在 auto：桌面那边摘掉它是因为信息面板横在正中、
	 * 点面板会命中背后的图标；窄屏的面板是底部抽屉，没有这个遮挡问题，
	 * 而「再点另一张就换过去」正是这里该有的手感。
	 */
	.design-lab.is-lab-focused .design-lab__card {
		opacity: 0.25;
		pointer-events: auto;
	}

	.design-lab.is-lab-focused .design-lab__card.is-focused {
		opacity: 1;
	}

	/* 参考圈不放大：两圈本来就贴着屏幕边，放大 1.45 会直接出屏。 */
	.design-lab.is-lab-focused .design-lab__guide {
		transform: translate(-50%, -50%);
		opacity: 0.55;
	}

	/*
	 * 信息面板 → 底部抽屉。
	 *
	 * 桌面那份是绝对定位在 top:50% 的，这里必须整体换掉：窄屏的聚焦图标留在
	 * 自己圈里、占着画面中间，面板再压上去就全糊了。
	 *
	 * 不写底色 —— 这是一张压在环上的纸，填实了背后的图标就没了。对比度靠那圈
	 * 退到 0.25 的图标来给。（--lab-bg 现在由 view.js 实测，够准，但这里要的不是
	 * 「和底色一致」，是「把背后的环让出来」。）
	 *
	 * bottom 用 --lab-nav-h：抽屉坐在底栏之上，两者不互相遮。
	 *
	 * ⚠️ 用 position:absolute 而不是 fixed，虽然满屏时两者看起来一样。
	 *    面板在 DOM 里是 stage 的子元素（render.php 里 .design-lab__info 就写在
	 *    stage 里面），而 stage 挂着 container-type —— 那等价于 contain:layout，
	 *    会把 stage 变成 fixed 后代的包含块。于是 position:fixed 其实按 stage 定位，
	 *    和 absolute 同义，却让人以为它认的是视口。写 absolute 至少是实话：
	 *    它按 stage 定位，而 stage 满屏时正好是 inset:0，就是视口。
	 */
	.design-lab__info {
		position: absolute;
		left: 0;
		right: 0;
		top: auto;
		bottom: var(--lab-nav-h);
		transform: translateY(100%);

		width: auto;
		margin-top: 0;
		padding: 20px clamp(20px, 6vw, 32px);
		max-height: 58dvh;
		overflow-y: auto;

		text-align: left;
		transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.4s ease, visibility 0.5s;
	}

	.design-lab.is-lab-focused .design-lab__info {
		transform: translateY(0);
	}

	/* 底栏 → 吸底满宽。CTA 在窄屏不存在（JS/图案侧就没有输出），所以是
	   三颗模式键 + ✕ 排一行。

	   下缘留 20px：原来跟顶部一样是 8px，三颗键几乎贴在屏幕下沿上，用户反馈
	   「贴底边不好看」。抬高**做进盒子的下内边距**，不是写 bottom: 20px ——
	   view.js 的 navStrip() 量的是 nav.offsetHeight，轨道半径、环心、抽屉高度
	   全按这个数算，做进盒子它们自动跟着走；写 bottom 的话 offsetHeight 不含
	   那段空隙，而且 bottom 上挂着 0.8s 过渡，开合动画途中会量到中间值。
	   safe-area 那一项不能丢：iPhone 上它才是避开 home indicator 的那段。 */
	.design-lab__nav {
		left: 0;
		right: 0;
		bottom: 0;
		width: auto;
		transform: translateY(calc(100% + 24px));
		gap: 10px;
		padding: 8px 12px;
		padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px));
	}

	/* 必须同时压过上面这条和桌面那条 .design-lab.is-lab-open .design-lab__nav
	   （(0,2,0)，在窄屏同样命中），否则展开后底栏还停在 -50% 的位移上。 */
	.design-lab.is-lab-open .design-lab__nav {
		bottom: 0;
		transform: translateY(0);
	}

	.design-lab__cta {
		display: none;
	}

	.design-lab__modes {
		flex: 1 1 auto;
		justify-content: space-between;
		min-width: 0;
	}

	.design-lab__mode {
		padding: 10px 8px;
		font-size: 9px;
		letter-spacing: 0;
		min-width: 0;
		flex: 1 1 0;
	}
}

/* ── 减弱动效 ───────────────────────────────────────────────────────────── */

/* 展开/收起变成瞬时；轨道飞行也直接落位。
   注意这也是 JS 里不能用 transitionend 当状态门的原因之一 ——
   这条规则会让那些事件根本不触发。 */
@media (prefers-reduced-motion: reduce) {

	.design-lab.is-lab-animating {
		transition: none;
	}

	.design-lab__card,
	.design-lab__wrapper,
	.design-lab__zoom,
	.design-lab__rule,
	.design-lab__guide,
	.design-lab__nav,
	.design-lab__actions,
	.design-lab__start,
	.design-lab__corner,
	.design-lab__corner::before,
	.design-lab__corner-label,
	.design-lab__corner-text,
	.design-lab__label,
	.design-lab__info {
		transition-duration: 0.01ms !important;
	}
}

/* ── 编辑器 ─────────────────────────────────────────────────────────────── */

/*
 * 编辑器不加载 viewScript（WP 的契约是 front-end only），所以画布里看到的
 * 永远是这个区块的常态：一条全宽横带 + 底部那颗 EXPLORE 按钮。
 * 那正是需要确认的东西 —— 是不是只有一条（不是两条、高度没翻倍）、
 * 有没有被压到 645px。
 */
.block-editor-block-list__block.is-selected .design-lab,
.block-editor-block-list__block.is-highlighted .design-lab {
	/* 选中时给一点轮廓，不然这条横带在画布里看不出边界。
	   用 currentColor 而不是写死的白：底色现在是可调的，白底上白轮廓等于没有。 */
	outline: 1px solid color-mix(in srgb, currentColor 25%, transparent);
	outline-offset: -1px;
}
