/* D·IARY —— 门（登录页）
   ===========================================================================
   六扇门全是 CSS 画的，一份结构两种尺寸：贴纸墙上的小图 .sm、放大当主角的 .lg。
   里面所有零件都用**百分比**定位 —— 换尺寸只改外框那一个宽高，里头一个数都不用动。

   颜色走每扇门自己的一组令牌（--dw 门扇 / --trim 门套 / --iron 铁 / --brass 铜
   / --leaf 叶 / --stone 石），登录卡片也吃同一组，所以卡片和门天然是一套的。

   加第七扇门：doors.js 的 DOORS + 这儿一段 [data-door="…"] + server.py 的 DOOR_KEYS。
   =========================================================================== */

/* ── 门：公共骨架 ───────────────────────────────────────────────────── */
.door {
  position: relative; flex: none;
  --dw: #8FB0B4; --dw2: #7A9BA0; --trim: #E9DFCC; --iron: var(--line-2);
  --brass: #E3B65A; --leaf: #8FB27A; --stone: #EFE7D8; --glow: #FFE6B8;
  --edge: var(--line-2);                 /* 描边：马克笔黑。门是画出来的，全靠这道线 */
  --cta: var(--dw);                      /* 卡片和按钮的主色。门扇本身太浅的（花房门）单独指定 */
  width: 158px; height: 214px;
}
.door.lg { width: 250px; height: 338px; }
/* 只给定位，**不给 display** —— 写了 display:block 的话，
   这条 (0,1,1) 会压过 .dw-lamp / .dw-rail / .dw-plant 那些 (0,1,0) 的 display:none，
   结果每扇门都挂上了壁灯和栏杆（第一版就是这么六扇门长一个样的）。 */
.door > span { position: absolute; }

/* 台阶：门底下垫一块，门才像立在地上而不是飘着 */
.dw-step {
  left: 4%; right: 4%; bottom: 0; height: 5.5%;
  background: var(--stone);
  border-radius: 3px 3px 2px 2px;
  box-shadow: inset 0 0 0 var(--mk) var(--edge);
}

/* 门套 + 两扇门扇 */
.dw-frame {
  left: 21%; right: 21%; top: 17%; bottom: 5.5%;
  background: var(--trim);
  border-radius: 4px 4px 0 0;
  box-shadow: inset 0 0 0 var(--mk) var(--edge);
  padding: 5%;
  perspective: 620px;                    /* 开门要有点透视，不然像两块板平移 */
}
.dw-glow {                               /* 门里透出来的暖光，开门才亮 */
  position: absolute; inset: 5%;
  background: radial-gradient(130% 92% at 50% 108%,
    var(--glow) 0%, #D9A868 34%, #8A5F38 68%, #3E2A1B 100%);
  opacity: 0; transition: opacity .5s var(--ease, ease);
}
/* 门刚开：屋里还是暗的（只有一点暖），光照进去之后才亮透 */
.door.open .dw-glow { opacity: .45; transition: opacity .35s var(--ease, ease) .3s; }
.gate.lit .door.open .dw-glow { opacity: 1; }
/* 照进去的那一束光：从门槛起、往屋里越铺越远（梯形，近宽远窄），.dw-beam 在 doors.js 里挂在门框内。
   由近及远是 scaleY 从 0 到 1、原点在门槛；亮度是奶黄，和墙一个颜色——光是从外面照进去的。 */
.dw-beam {
  position: absolute; inset: 5%;
  background: linear-gradient(0deg, rgba(255, 243, 184, .96) 0%, rgba(255, 243, 184, .62) 48%, rgba(255, 243, 184, 0) 100%);
  clip-path: polygon(-12% 100%, 112% 100%, 64% 0, 36% 0);
  opacity: 0; transform: scaleY(0); transform-origin: 50% 100%;
  pointer-events: none;
}
.door.open .dw-beam { opacity: 1; transform: none;
  transition: transform .58s cubic-bezier(.2, .7, .3, 1) .06s, opacity .2s .06s; }

.lf {
  position: absolute; top: 5%; bottom: 5%; width: 45%;
  background: var(--dw);
  box-shadow: inset 0 0 0 var(--mk) var(--edge);
  transition: transform .62s cubic-bezier(.3, .8, .3, 1);
  transform-style: preserve-3d; backface-visibility: hidden;
}
.lf.l { left: 5%;  transform-origin: left center;  border-radius: 3px 1px 1px 3px; }
.lf.r { right: 5%; transform-origin: right center; border-radius: 1px 3px 3px 1px; }
/* 开门：**不摆动**（用户 2026-09-06："不用有门移动的感觉，就是开门"）——
   门扇一下子就折到里面贴着墙（84°，还剩一条边看得见），没有过渡；情绪全交给那一束光。 */
.door.open .lf { transition: none; }
.door.open .lf.l { transform: rotateY(84deg); }
.door.open .lf.r { transform: rotateY(-84deg); }

.lf i {                                  /* 门扇上半截：玻璃 / 镶板 */
  position: absolute; left: 14%; right: 14%; top: 8%; height: 42%;
  border-radius: 2px;
  background: color-mix(in srgb, var(--dw) 62%, #F6EFE0);
  box-shadow: inset 0 0 0 var(--mk-thin) var(--edge);
}
.lf u {                                  /* 下半截：一块实心镶板 */
  position: absolute; left: 14%; right: 14%; bottom: 8%; height: 32%;
  border-radius: 2px; text-decoration: none;
  background: var(--dw2);
  box-shadow: inset 0 0 0 var(--mk-thin) var(--edge);
}
.dw-knob {
  left: 50%; top: 55%; width: 5%; height: 5%; margin-left: -2.5%;
  border-radius: 50%; background: var(--brass);
  box-shadow: 0 0 0 var(--mk-thin) var(--edge);
  transition: opacity .3s;
}
.door.open .dw-knob { opacity: 0; }

/* 顶上那一件：拱 / 雨棚 / 铁艺雨搭 / 门楣，按门的种类各画各的 */
.dw-top { left: 12%; right: 12%; top: 4%; height: 15%; }
.dw-top i { position: absolute; display: block; }

/* 壁灯 / 挂灯 */
.dw-lamp {
  top: 22%; width: 8%; height: 11%;
  background: var(--iron);
  clip-path: polygon(50% 0, 100% 62%, 78% 100%, 22% 100%, 0 62%);
  display: none;
}
.dw-lamp::after {                        /* 灯芯：一点暖黄 */
  content: ""; position: absolute; left: 24%; right: 24%; top: 46%; bottom: 16%;
  border-radius: 1px; background: #F3C969;   /* 亮着的灯芯：平涂，不发光晕 */
}
.dw-lamp.l { left: 6%; }
.dw-lamp.r { right: 6%; }

/* 小栏杆：一排竖铁条 + 上下两道横的 */
.dw-rail {
  left: 6%; right: 6%; bottom: 5.5%; height: 11%; display: none;
  background:
    repeating-linear-gradient(90deg, var(--iron) 0 1.5px, transparent 1.5px 9px),
    linear-gradient(180deg, transparent 0 8%, var(--iron) 8% 14%, transparent 14% 86%,
                    var(--iron) 86% 100%);
}

/* 花草：一个盆 + 三片叶。叶子按 nth-child 各歪各的，别长成一模一样的三根 */
.dw-plant { bottom: 5.5%; width: 13%; height: 22%; display: none; }
.dw-plant.l { left: 3%; }
.dw-plant.r { right: 3%; }
.dw-plant::after {                       /* 盆 */
  content: ""; position: absolute; left: 12%; right: 12%; bottom: 0; height: 42%;
  background: #D9A578;
  clip-path: polygon(6% 0, 94% 0, 82% 100%, 18% 100%);
  border-radius: 2px 2px 1px 1px;
  box-shadow: inset 0 0 0 var(--mk-thin) var(--edge);
}
.dw-plant i {
  position: absolute; left: 50%; bottom: 36%; width: 34%; height: 46%;
  margin-left: -17%; border-radius: 60% 60% 40% 40%;
  background: var(--leaf); transform-origin: 50% 100%;
  box-shadow: inset 0 0 0 var(--mk-thin) var(--edge);
}
.dw-plant i:nth-child(1) { transform: rotate(-26deg) scaleY(.86); }
.dw-plant i:nth-child(2) { transform: rotate(2deg); }
.dw-plant i:nth-child(3) { transform: rotate(25deg) scaleY(.8); }

/* 门口那张小圆桌（只有咖啡馆门摆） */
.dw-table { left: 2%; bottom: 5.5%; width: 20%; height: 16%; display: none; }
.dw-table::before {                      /* 桌面 + 桌腿 */
  content: ""; position: absolute; left: 0; right: 0; top: 34%; height: 9%;
  border-radius: 3px; background: var(--iron);
  box-shadow: 0 3px 0 -1px var(--iron) inset;
}
.dw-table::after {
  content: ""; position: absolute; left: 46%; top: 43%; width: 8%; bottom: 0;
  background: var(--iron);
}
.dw-table i {                            /* 一把小椅子 */
  position: absolute; right: -18%; bottom: 0; width: 42%; height: 76%;
  border: 2px solid var(--iron); border-right: 0; border-bottom: 0;
  border-radius: 6px 0 0 0;
}

/* 门牌 */
.dw-name {
  left: 8%; right: 8%; bottom: -22px; text-align: center;
  font-size: var(--fs-xs); color: var(--ink-2);
  letter-spacing: var(--ls-label); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.door.lg .dw-name { bottom: -26px; font-size: var(--fs-sm); color: var(--ink); }

/* ══ 一扇一扇来 ═══════════════════════════════════════════════════════ */

/* ① 玻璃花房门：细白框 + 一格一格的玻璃 + 黄铜把手 + 上面一道气窗。
   （原来这儿是「拱顶铁花」，石头拱压得太重，换掉了；老账号存的 'arch' 在
   doors.js / server.py 里都认作这扇。） */
[data-door="glass"] { --dw: #F4EFE6; --dw2: #E7DFD1; --trim: #FBF8F2; --stone: #E9E2D5;
  --brass: #E3B65A; --leaf: #8FB27A;
  --cta: #A8763A; }                              /* 门扇是近白的，卡片跟黄铜走 */
.door[data-door="glass"] .dw-frame {
  left: 22%; right: 22%; top: 20%;
  background: var(--trim);
  box-shadow: inset 0 0 0 var(--mk) var(--edge);
}
/* 门扇＝一整片玻璃格：竖三格、横五格，格线就是门本身的框 */
.door[data-door="glass"] .lf {
  background:
    #D6E4E2;
  box-shadow: inset 0 0 0 2.5px var(--dw), 0 0 0 var(--mk) var(--edge);
}
.door[data-door="glass"] .lf i {                      /* 横向格线：四道 */
  left: 0; right: 0; top: 0; bottom: 0; height: auto; border-radius: 0;
  background:
    linear-gradient(180deg, transparent 0 19%, var(--dw) 19% 21.5%, transparent 21.5% 39%,
      var(--dw) 39% 41.5%, transparent 41.5% 59%, var(--dw) 59% 61.5%,
      transparent 61.5% 79%, var(--dw) 79% 81.5%, transparent 81.5%);
  box-shadow: none;
}
.door[data-door="glass"] .lf u {                      /* 竖向格线：中间一道 */
  left: 0; right: 0; top: 0; bottom: 0; height: auto; border-radius: 0;
  background: linear-gradient(90deg, transparent 0 48%, var(--dw) 48% 52%, transparent 52%);
  box-shadow: none;
}
.door[data-door="glass"] .dw-knob {                   /* 黄铜长把手 */
  left: 47%; top: 52%; width: 3%; height: 13%; margin-left: 0;
  border-radius: 2px; background: var(--brass);
  box-shadow: 0 0 0 var(--mk-thin) var(--edge);
}
.door[data-door="glass"] .dw-top {                    /* 气窗：门上一条横玻璃 */
  left: 22%; right: 22%; top: 10%; height: 10%;
  background: #D6E4E2;
  box-shadow: inset 0 0 0 2.5px var(--trim), 0 0 0 var(--mk) var(--edge);
}
.door[data-door="glass"] .dw-top i.a {                /* 气窗上的格线 */
  left: 0; right: 0; top: 0; bottom: 0;
  background: linear-gradient(90deg, transparent 0 32%, var(--trim) 32% 35%,
    transparent 35% 65%, var(--trim) 65% 68%, transparent 68%);
}
.door[data-door="glass"] .dw-top i.b {                /* 门楣：一道浅檐 */
  left: -6%; right: -6%; top: -9px; height: 8px; border-radius: 2px;
  background: var(--trim); box-shadow: 0 0 0 var(--mk) var(--edge);
}
.door[data-door="glass"] .dw-plant { display: block; width: 12%; height: 24%; }
.door[data-door="glass"] .dw-plant.l { left: 4%; }
.door[data-door="glass"] .dw-plant.r { right: 4%; }

/* ② 街角咖啡馆：条纹雨棚 + 木门 + 门口一张小桌 */
[data-door="cafe"] { --dw: #B07B4F; --dw2: #96663F; --trim: #F1E7D4; --stone: #E3D8C2;
  --leaf: #6E8C56; }
.door[data-door="cafe"] .dw-frame { left: 26%; right: 12%; top: 24%; }
.door[data-door="cafe"] .dw-top {                     /* 雨棚：斜着的一片条纹 */
  left: 4%; right: 4%; top: 8%; height: 16%;
  background: repeating-linear-gradient(90deg,
    #F2E6D2 0 11px, #C2703F 11px 22px);
  border-radius: 4px 4px 2px 2px;
  box-shadow:;
  clip-path: polygon(4% 0, 96% 0, 100% 100%, 0 100%);
}
.door[data-door="cafe"] .dw-top i.a {                 /* 棚下的波浪边 */
  left: 0; right: 0; bottom: -5px; height: 6px;
  background: radial-gradient(circle at 5px 0, #C2703F 4.5px, transparent 5px) 0 0/11px 6px;
}
.door[data-door="cafe"] .dw-top i.b {                 /* 棚顶的铁艺花 */
  left: 34%; right: 34%; top: -22%; height: 24%;
  border: 2px solid var(--iron); border-bottom: 0;
  border-radius: 50% 50% 0 0; opacity: .8;
}
.door[data-door="cafe"] .dw-table { display: block; left: 3%; bottom: 5.5%; width: 24%; height: 22%; }
.door[data-door="cafe"] .dw-table::before {           /* 桌面：一小张圆桌 */
  left: 26%; right: 8%; top: 30%; height: 12%;
  border-radius: 50%; background: var(--iron); box-shadow: none;
}
.door[data-door="cafe"] .dw-table::after {            /* 桌腿 + 底盘 */
  left: 46%; top: 38%; width: 6%; bottom: 8%;
  background: var(--iron);
  box-shadow: -8px 0 0 -2px var(--iron), 8px 0 0 -2px var(--iron);
}
.door[data-door="cafe"] .dw-table i {                 /* 椅子：靠背 + 座 */
  left: 2%; right: auto; bottom: 6%; width: 30%; height: 62%;
  border: 2px solid var(--iron); border-right: 0; border-bottom: 0;
  border-radius: 7px 0 0 0;
}
.door[data-door="cafe"] .dw-plant.r { display: block; right: 1%; width: 11%; height: 17%; }

/* ③ 藤蔓木门：暖木门 + 一盏挂灯 + 两盆绿的 + 垂下来的藤 */
[data-door="vine"] { --dw: #B5793F; --dw2: #9A6234; --trim: #EAD9BC; --stone: #E0D3B8;
  --leaf: #6E8C56; }
.door[data-door="vine"] .dw-top {                     /* 门楣上爬的藤：大小不一才像叶子 */
  left: 6%; right: 6%; top: 4%; height: 16%;
  background:
    radial-gradient(circle at 7px 6px, #6E8C56 6px, transparent 7px) 0 0/26px 15px,
    radial-gradient(circle at 18px 12px, #85A268 5px, transparent 6px) 3px 2px/23px 18px,
    radial-gradient(circle at 12px 3px, #5E7B49 4px, transparent 5px) 9px 0/17px 14px;
}
.door[data-door="vine"] .dw-top i.a {                 /* 门楣板 */
  left: 0; right: 0; bottom: -4px; height: 7px; border-radius: 2px;
  background: color-mix(in srgb, var(--dw) 70%, #000);
}
.door[data-door="vine"] .dw-lamp.l {
  display: block; left: 2%; top: 26%; width: 10%; height: 13%;
}
.door[data-door="vine"] .dw-frame::before,            /* 顺着门套垂下来的两绺藤 */
.door[data-door="vine"] .dw-frame::after {
  content: ""; position: absolute; top: -6%; width: 11px; height: 46%;
  background: radial-gradient(circle at 5px 6px, #6E8C56 4.5px, transparent 5.5px) 0 0/11px 13px;
}
.door[data-door="vine"] .dw-frame::before { left: -13px; }
.door[data-door="vine"] .dw-frame::after { right: -13px; height: 34%; }
.door[data-door="vine"] .dw-lamp.l::before {          /* 挂灯的弯钩 */
  content: ""; position: absolute; left: 40%; top: -70%; width: 2px; height: 74%;
  background: var(--iron);
}
.door[data-door="vine"] .dw-plant { display: block; }

/* ④ 百叶小屋：奶油百叶窗扇 + 窗台一箱花 */
[data-door="shutter"] { --dw: #F0E4CE; --dw2: #E2D2B6; --trim: #C9A87C; --stone: #DCCBAA;
  --brass: #B08444; --leaf: #6E8C56; }
.door[data-door="shutter"] .lf {                      /* 门扇整片都是百叶 */
  background:
    repeating-linear-gradient(180deg,
      color-mix(in srgb, var(--dw) 84%, #000) 0 1.5px, var(--dw) 1.5px 6px);
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--trim) 80%, #000);
}
.door[data-door="shutter"] .lf i, .door[data-door="shutter"] .lf u { display: none; }
.door[data-door="shutter"] .dw-top {                  /* 窗楣 */
  left: 14%; right: 14%; top: 9%; height: 8%;
  background: var(--trim); border-radius: 3px 3px 0 0;
  box-shadow:;
}
.door[data-door="shutter"] .dw-top i.a {
  left: -6%; right: -6%; top: 62%; height: 38%;
  background: color-mix(in srgb, var(--trim) 78%, #000); border-radius: 2px;
}
.door[data-door="shutter"] .dw-rail {                 /* 花箱 */
  display: block; left: 16%; right: 16%; bottom: 5.5%; height: 13%;
  background: #C9915F; box-shadow: inset 0 0 0 var(--mk-thin) var(--edge);
  border-radius: 2px 2px 3px 3px;
}
.door[data-door="shutter"] .dw-rail::after {          /* 箱里的花：三色小点 */
  content: ""; position: absolute; left: 4%; right: 4%; top: -46%; height: 62%;
  background:
    radial-gradient(circle at 5px 8px, #C97C86 4px, transparent 5px) 0 0/17px 14px,
    radial-gradient(circle at 13px 4px, #E4C15E 3px, transparent 4px) 0 0/21px 15px,
    radial-gradient(circle at 8px 12px, #6E8C56 5px, transparent 6px) 0 0/15px 16px;
}

/* ⑤ 老书店：石门套 + 深木双开门 + 两株修剪过的树 */
[data-door="book"] { --dw: #6E4630; --dw2: #5A3826; --trim: #EFE7D8; --stone: #E4DAC6;
  --brass: #C9973F; --leaf: #7E9A63; }
.door[data-door="book"] .dw-frame { top: 19%; box-shadow: inset 0 0 0 var(--mk) var(--edge); }
.door[data-door="book"] .dw-top {                     /* 门楣：石头檐 + 一块招牌 */
  left: 14%; right: 14%; top: 7%; height: 13%;
  background: var(--stone); border-radius: 3px 3px 0 0;
  box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--stone) 70%, #000);
}
.door[data-door="book"] .dw-top i.a {
  left: -8%; right: -8%; top: -6px; height: 8px; border-radius: 3px;
  background: color-mix(in srgb, var(--stone) 88%, #000);
}
.door[data-door="book"] .dw-top i.b {                 /* 招牌上的一行小字（只画个意思）*/
  left: 22%; right: 22%; top: 46%; height: 3px; border-radius: 2px;
  background: color-mix(in srgb, var(--dw) 70%, transparent);
  box-shadow: 0 6px 0 -1px color-mix(in srgb, var(--dw) 45%, transparent);
}
.door[data-door="book"] .dw-plant { display: block; width: 15%; height: 30%; }
.door[data-door="book"] .dw-plant i:nth-child(1),
.door[data-door="book"] .dw-plant i:nth-child(3) { display: none; }
.door[data-door="book"] .dw-plant i:nth-child(2) {    /* 修剪成球的小树：球 + 一小截树干 */
  width: 86%; height: 54%; margin-left: -43%; bottom: 40%;
  border-radius: 50%; transform: none;
  box-shadow: 0 0 0 var(--mk) var(--edge);
}
.door[data-door="book"] .dw-plant::before {
  content: ""; position: absolute; left: 46%; bottom: 34%; width: 8%; height: 14%;
  background: #8B5E39;
}

/* ⑥ 薄荷小门：薄荷绿门扇 + 黑铁雨搭 + 小栏杆 */
[data-door="mint"] { --dw: #9CBFAE; --dw2: #85A996; --trim: #EFE9DC; --stone: #E2DAC8;
  --brass: #D3A24A; }
.door[data-door="mint"] .dw-top {                     /* 铁艺雨搭：贴着门顶的一道半圆铁架 */
  left: 12%; right: 12%; top: 6%; height: 15%;
  border: 2px solid var(--iron); border-bottom: 0;
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  background: color-mix(in srgb, var(--iron) 8%, transparent);
}
.door[data-door="mint"] .dw-top i.a {                 /* 顶上的小尖 + 两端落到墙上的支架 */
  left: 50%; top: -14%; width: 2px; height: 26%; margin-left: -1px; background: var(--iron);
  box-shadow: none;
}
.door[data-door="mint"] .dw-top::before, .door[data-door="mint"] .dw-top::after {
  content: ""; position: absolute; bottom: -10px; width: 2px; height: 12px; background: var(--iron);
}
.door[data-door="mint"] .dw-top::before { left: -1px; }
.door[data-door="mint"] .dw-top::after { right: -1px; }
.door[data-door="mint"] .dw-top i.b {                 /* 挂在雨搭下的小牌 */
  left: 40%; right: 40%; bottom: -34%; height: 26%;
  background: var(--brass); border-radius: 2px;
  box-shadow: 0 0 0 var(--mk) var(--edge);
}
.door[data-door="mint"] .lf i { border-radius: 44% 44% 2px 2px; height: 40%; }
.door[data-door="mint"] .dw-rail { display: block; }

/* ══ 登录页（门口）═════════════════════════════════════════════════════
   这一屏是"还没进屋"的时刻，所以它有自己的一层暖底，
   不跟着风格包的 --bg 走 —— 进了屋才是各人的风格。 */
.gate {
  --gate-bg: var(--butter); --gate-ink: var(--ink);
  position: relative;
  min-height: 100dvh;
  /* place-items 只管"在自己那一格里居中"，格子本身还贴在左边；
     要让整块内容居中得再加 place-content（门原来偏左 80px 就是漏了这一条）。 */
  display: grid; place-items: center; place-content: center;
  padding: 26px 16px calc(26px + env(safe-area-inset-bottom));
  /* 上面是奶黄的墙，下面 30% 是画出来的地砖（细线格子），门就立在砖上 */
  background:
    linear-gradient(var(--gate-bg) 0 70%, transparent 70%),
    linear-gradient(90deg, color-mix(in srgb, var(--line-2) 55%, transparent) 0 1px, transparent 1px),
    linear-gradient(0deg, color-mix(in srgb, var(--line-2) 55%, transparent) 0 1px, transparent 1px),
    var(--bg);
  /* 固定大小的方砖重复铺设，避免长渐变在平板栅格化时出现漏线、大小砖混排。 */
  background-size: 100% 100%, 64px 64px, 64px 64px;
  background-repeat: no-repeat, repeat, repeat;
  color: var(--gate-ink);
  overflow: hidden;
}
/* 招牌和那句小字压在顶上，不参与居中，免得把门顶偏 */
.gate .g-brand, .gate > .g-sub, .gate > .g-swap { position: absolute; left: 50%; transform: translateX(-50%); }
.gate .g-brand { top: 30px; }
.gate > .g-sub { top: 76px; margin: 0; }
.gate > .g-swap { bottom: calc(30px + env(safe-area-inset-bottom)); }
/* 贴纸墙底下那句脚注**跟着内容走**，不许跟顶上那句抢同一个位置。
   （上面那条 `.gate > .g-sub` 是绝对定位钉在 76px 的，两句都吃它就叠成一团。） */
.gate > .g-note {
  position: static; transform: none; opacity: .6;
  margin: 18px auto calc(40px + env(safe-area-inset-bottom));
  max-width: min(760px, 100%);
}

.gate .g-brand { display: flex; align-items: center; gap: 10px; }
/* 这条本来是给那枚方图标的（26 见方）。字标不是方的，得单给一条，
   不然会被压成正方形。 */
.gate .g-brand svg { width: 26px; height: 26px; }
.gate .g-brand .wm { width: auto; height: 44px; }
.gate .g-brand h1 { display: flex; }
.gate .g-brand h1 {
  margin: 0; font-family: var(--f-title); font-weight: var(--w-title);
  font-size: var(--fs-xl); letter-spacing: .06em;
}
.gate .g-sub { margin: 0; font-size: var(--fs-sm); opacity: .78; text-align: center; }

/* 贴纸墙：一格一扇门。白边 + 软影 = 贴纸的样子 */
.doorwall {
  display: grid; gap: 14px; width: min(760px, 100%);
  grid-template-columns: repeat(3, 1fr);
}
/* 贴纸墙这一屏内容高，别居中——顶着上面排，能滚 */
.gate:has(.doorwall) { display: block; padding-top: 118px; overflow: auto; }
.gate:has(.doorwall) .doorwall { margin: 0 auto; }
.dtile {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px 10px 30px; cursor: pointer;
  background: var(--surface); border: 0; border-radius: 18px;
  box-shadow: 0 8px 18px -12px rgba(27, 27, 27, .35);
  transition: transform .22s var(--ease), box-shadow .22s var(--ease);
}
.dtile:hover, .dtile:focus-visible {
  transform: translateY(-4px) rotate(-.5deg);
  box-shadow: 0 16px 26px -14px rgba(27, 27, 27, .4);
  outline: none;
}
.dtile:focus-visible { outline: 2px solid var(--gate-ink); outline-offset: 3px; }
.dtile .d-t { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.dtile .d-d { font-size: var(--fs-xs); color: var(--muted); text-align: center; line-height: 1.5; }

/* 挑中之后：门放大，卡片从门里升起来 */
/* 往下让一截（82px，手机上约 1.2cm —— 屏幕 CSS 像素约 53px/cm）。顶上压着招牌和「点一下敲门」那句，门贴太近就挤；
   开门动画又要把整块放大 3.4 倍，起点偏上的话门的上半截先撞出屏幕。

   **必须用 transform 不能用 margin**：`.gate` 是 place-content:center 居中的，
   加 margin 只会让内容变高、然后被重新居中拉回去大半 —— 给了 64px 实际只挪了 17px。
   transform 不参与布局，给多少就是多少。 */
.gate .g-hero { display: flex; flex-direction: column; align-items: center; gap: 28px;
  transform: translateY(82px); }
.gatecard {
  width: min(340px, 92vw); padding: 22px 20px 18px;
  background: var(--surface); border-radius: 22px;
  box-shadow: 0 22px 34px -18px rgba(27, 27, 27, .45);
  display: flex; flex-direction: column; gap: 10px;
  animation: gaterise .42s cubic-bezier(.2, .8, .3, 1);
}
@keyframes gaterise { from { opacity: 0; transform: translateY(16px) } to { opacity: 1; transform: none } }
.gatecard h2 {
  margin: 0; font-size: var(--fs-lg); font-family: var(--f-title);
  font-weight: var(--w-title); color: var(--ink);
}
.gatecard .g-tip { margin: -6px 0 2px; font-size: var(--fs-xs); color: var(--muted); line-height: 1.6; }
.gatecard .fld { display: flex; flex-direction: column; gap: 5px; }
.gatecard .fld > span { font-size: var(--fs-xs); color: var(--muted); }
.gatecard .inp {
  width: 100%; min-height: var(--tap, 44px); padding: 10px 12px;
  border: 2px solid var(--line); border-radius: 14px;
  background: var(--surface); color: var(--ink);
  /* **16px 不能再小**：iOS Safari 在字号 < 16px 的输入框上一聚焦就放大整个页面，
     而且不缩回来 —— 敲个口令，界面就一直大着进了屋。 */
  font-size: 16px;
}
.gatecard .inp:focus { outline: none; border-color: var(--ink); }
.gatecard .g-go {
  min-height: var(--tap, 44px); border: 0; border-radius: 999px; cursor: pointer;
  background: var(--ink); color: var(--butter); font-size: var(--fs-md); font-weight: 600;
}
@media (hover: hover) { .gatecard .g-go:hover { background: var(--ink-2); } }
.gatecard .g-go[disabled] { opacity: .55; cursor: default; }
.gatecard .g-err { font-size: var(--fs-xs); color: var(--danger); min-height: 1.2em; }
.gatecard .g-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.gatecard .g-link {
  background: none; border: 0; padding: 4px 2px; cursor: pointer;
  font-size: var(--fs-xs); color: var(--muted); text-decoration: underline;
  text-underline-offset: 3px;
}
.gatecard .g-link:hover { color: var(--ink); }

@media (max-width: 620px) {
  .doorwall { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .dtile { padding: 12px 6px 26px; border-radius: 13px; }
  .door { width: 128px; height: 174px; }
  .door.lg { width: 200px; height: 270px; }
  .gate { gap: 14px; padding-top: 34px; }   /* 老 flex 布局留下的 justify-content 去掉了：现在靠 place-content 居中 */
  .gate .g-hero { gap: 20px; }
}
@media (max-height: 680px) {
  .gate .g-hero { gap: 14px; transform: translateY(30px); }   /* 矮屏余量少，让一半 */
  .door.lg { width: 168px; height: 228px; }
}
@media (prefers-reduced-motion: reduce) {
  .lf, .dw-glow, .gatecard, .dtile { transition: none !important; animation: none !important; }
}

/* 挑中之后先开一条缝（还没对口令），对上了才整个打开 */
.door.ajar .lf.l { transform: rotateY(20deg); }
.door.ajar .lf.r { transform: rotateY(-20deg); }
.door.ajar .dw-glow { opacity: .88; }
.door.ajar .dw-knob { opacity: .5; }

/* 进屋：画面**不往门里推**了（原来整屏放大 3.4 倍撞进去，用户不要"门移动的感觉"）。
   门留在弹框时放大的那个位置上、只把虚化去掉，光在门框里铺开；
   然后光漫出门口——整屏被奶黄的光盖住（.gate::after 淡入），下一帧就是屋里（桌面）。 */
.gate.opening .g-hero .door {
  filter: none; transform: scale(var(--askscale, 2.1));
  transition: filter .3s var(--ease, ease);
}
.gate.opening .g-hero .dw-name { opacity: 0; }
.gate.opening .g-knock { pointer-events: none; }
.gate::after {
  content: ""; position: fixed; inset: 0; z-index: 5; pointer-events: none;
  background: var(--butter); opacity: 0;
}
.gate.lit::after { opacity: 1; transition: opacity .42s ease-in; }
.gate.opening .gatecard { animation: gatefade .3s ease forwards; }
@keyframes gatefade { to { opacity: 0; transform: translateY(10px) } }
@media (prefers-reduced-motion: reduce) {
  .gate.opening .gatecard, .gate.opening .g-hero .door { animation: none !important; transition: none !important; }
  .dw-beam { transition: none !important; }
}

/* ══ 敲门 ═══════════════════════════════════════════════════════════════
   一开始只有一扇门，摆正中。点它＝敲门（有声），敲过才弹框。 */
.g-knock {
  position: absolute; inset: 0;
  border: 0; padding: 0; background: transparent; cursor: pointer;
  border-radius: 14px;
}
.g-knock:focus-visible { outline: 2px solid var(--gate-ink); outline-offset: 6px; }
.gate .g-hero { position: relative; display: grid; place-items: center; }

/* 敲门：门框跟着声音里的三个「咚」各震一下（0 / 190 / 380ms，动画 .6s 里的 0% / 32% / 63%）。
   是"被敲"不是"在晃"：每下只往里 2px 又回来，中间是静止的。 */
.door.knocking { animation: knock .6s linear; }
@keyframes knock {
  0%, 20%, 32%, 52%, 63%, 83%, 100% { transform: translateX(0) }
  4%  { transform: translateX(-2px) }  12% { transform: translateX(1px) }
  36% { transform: translateX(-2px) }  44% { transform: translateX(1px) }
  67% { transform: translateX(-2px) }  75% { transform: translateX(1px) }
}

/* 弹框的时候门**虚化退到后面**：焦点在框上，门还在，只是不抢戏。
   注意是**放大**不是缩小——框有 340px 宽，门要是缩着就整个被盖住，
   "虚化在框后面"就成了"门没了"（第一版就是这样）。 */
.gate.asking .g-hero .door {
  filter: blur(5px) saturate(.94) brightness(1.04);
  transform: scale(var(--askscale, 2.1));
  transition: filter .45s var(--ease, ease), transform .45s var(--ease, ease);
}
/* 手机上卡片几乎占满屏，门要**放到比卡片还大**才露得出来——
   放小了就是"门没了"。放大之后门成了一层虚化的背景，卡片浮在上面。 */
@media (max-width: 620px) { .gate { --askscale: 3.1; } }
.gate.asking .g-hero .dw-name { opacity: 0; }
.gate.asking .g-knock { pointer-events: none; }
.gate .g-hero .door { transition: filter .45s var(--ease, ease), transform .45s var(--ease, ease); }

/* 框压在门上（门在正中，框也在正中） */
.gate.asking .gatecard {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  animation: cardin .38s cubic-bezier(.2, .8, .3, 1) both;
  z-index: 2;
}
@keyframes cardin {
  from { opacity: 0; transform: translate(-50%, calc(-50% + 14px)) scale(.98) }
}
.gatecard.gone {
  opacity: 0; pointer-events: none;
  transform: translate(-50%, calc(-50% + 10px));
  transition: opacity .28s, transform .28s;
}
@media (prefers-reduced-motion: reduce) {
  .door.knocking { animation: none }
  .gate.asking .gatecard { animation: none }
}

/* 门口那几枚键（换一扇门 / 登录卡里的次要键）：石色药丸，不描边 */
.gate .g-swap, .gate .g-swap .btn, .gate button.btn {
  border: 0; border-radius: 999px; background: var(--p-stone); color: var(--ink);
  padding: 10px 18px; min-height: var(--tap, 44px); font-weight: 500; cursor: pointer;
}

/* 进门前也能选语言、开启声音；表单高度受可用屏幕约束。 */
.g-cardtop { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.g-language {
  max-width: 145px; min-height: 40px; padding: 7px 9px; border-radius: 20px;
  border: 1px solid var(--line); background: transparent; color: var(--ink-2);
  font: 13px var(--f-ui); cursor: pointer;
}
.g-soundnote { display: flex; gap: 10px; align-items: center; padding: 12px 0; border-top: 1px solid var(--line); }
.g-soundnote p { flex: 1; margin: 0; color: var(--muted); font-size: 12px; line-height: 1.6; }
.g-sound { flex: none; max-width: 45%; min-height: 40px; padding: 8px 12px; border: 0; border-radius: 20px;
  font: inherit; font-size: 12px; background: var(--p-butter); color: var(--ink); cursor: pointer; }
.g-sound[aria-pressed="true"] { background: var(--p-sage); }
.gate.asking .gatecard { max-height: calc(100dvh - 32px); overflow-y: auto; overscroll-behavior: contain; }
.g-language:focus-visible, .g-sound:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* Keep the registration entry before fields, visible even on short screens. */
.g-auth-modes { display:grid; grid-template-columns:1fr 1.35fr; gap:8px; margin:2px 0 8px; }
.g-auth-mode { min-height:48px; padding:10px 8px; border:2px solid var(--ink); border-radius:14px; background:var(--surface); color:var(--ink); font:inherit; font-weight:700; cursor:pointer; line-height:1.3; }
.g-auth-mode.active { background:var(--ink); color:var(--surface); }
.g-auth-mode:focus-visible { outline:3px solid var(--ink); outline-offset:3px; }

/* A painted entrance belonging to the same paper-and-wood room as the studio. */
.gate{
 --gate-bg:#f0e5d2;--gate-ink:#514633;
 background:#f0e5d2 url('/img/studio/paper-v2.webp') center/600px auto repeat;
 isolation:isolate;
}
.gate::before{
 content:"";position:absolute;left:-5%;right:-5%;top:70%;bottom:-8%;z-index:-1;pointer-events:none;
 background:repeating-linear-gradient(90deg,transparent 0 calc(20% - 2px),#76533545 calc(20% - 2px) 20%),url('/img/studio/wood-v3.webp') center/520px auto;
 border-top:7px solid #ad875c;box-shadow:0 -3px 0 #dac5a6, inset 0 14px 20px -12px #6d482f8c;
 transform:perspective(700px) rotateX(15deg);transform-origin:50% 0;
}
.gate .g-brand{top:clamp(28px,7dvh,65px);}
.gate>.g-sub{top:clamp(85px,15dvh,126px);color:#77654f;}
.gate .g-hero{position:absolute;bottom:30%;left:50%;transform:translateX(-50%);gap:0;}
.gate .g-hero .door.lg{width:clamp(250px,34vw,370px);height:clamp(338px,46vw,500px);}
.gate .door{
 --edge:#70573580;--iron:#615d4e;--mk:1px;--mk-thin:.7px;
 filter:drop-shadow(2px 5px 3px #63462c26);
}
.gate .dw-frame{border-radius:5% 4% 1% 2%;box-shadow:inset 2px 1px 1px #fff6,inset -3px -1px 2px #65482f65,2px 3px 3px #5e442f30;}
.gate .lf{border-radius:3% 2% 1% 2%;box-shadow:inset 2px 0 2px #fff5,inset -2px 0 3px #38291860;}
.gate .lf::after,.gate .dw-step::after,.gate .dw-top::after{
 content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
 background:url('/img/studio/paper-v2.webp') center/180px auto;mix-blend-mode:multiply;opacity:.5;
}
.gate .lf::before{content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;
 background:url('/img/studio/wood-v3.webp') center/220px 100%;mix-blend-mode:soft-light;opacity:.55;}
.gate .lf i,.gate .lf u{box-shadow:inset 1px 2px 2px #503a3240,0 1px 1px #fff6;border-radius:6% 3% 4% 2%;}
.gate .door[data-door=glass] .lf i,.gate .door[data-door=glass] .lf u{box-shadow:none;border-radius:0;}
.gate .door[data-door=glass] .lf{background:linear-gradient(125deg,#f1f1d780,#819a8c45),#cedbd0;}
.gate .door[data-door=glass] .lf::before{opacity:.08;}
.gate .dw-plant i{box-shadow:inset 3px 1px 4px #ecedaf50,inset -3px -2px 4px #35492d45;border-radius:57% 43% 46% 54%;}
.gate .dw-plant::after{background:linear-gradient(90deg,#ad714e,#d5a16e 35%,#b88053);box-shadow:inset 0 3px 0 #edc99b80;}
.gate .dw-step{background:#c6ad86 url('/img/studio/paper-v2.webp') center/180px auto;background-blend-mode:multiply;box-shadow:0 5px 5px #5f48333d,inset 0 2px 0 #f4e2ba;}
.gate .dw-name{color:#5f503c!important;letter-spacing:.08em;}
.gate .dtile{background:#faf4e5b5 url('/img/studio/paper-v2.webp') center/400px auto;border:1px solid #d6c5a7;border-radius:7px 13px 8px 11px;box-shadow:1px 5px 9px #70543720;}
.gate .g-swap,.gate button.btn{background:#faf5e6e8;border:1px solid #d6c5a7;box-shadow:0 3px 5px #785d3420;}
.gate.asking .g-hero .door{transform:scale(1.06);filter:blur(4px) saturate(.8);}
.gate.opening .g-hero .door{transform:scale(1.06);filter:none;}
.gate .dw-glow{background:linear-gradient(#ffe7b526,#ffe7b535),url('/img/studio/room-v1.jpg') center/cover;border-radius:3px;}
.gate .dw-beam{background:linear-gradient(0deg,#ffecc699,transparent);}
.gate .door.open .lf{transition:transform .62s cubic-bezier(.22,.6,.35,1);}
.gate .door.open .lf.l{transform:rotateY(82deg);}
.gate .door.open .lf.r{transform:rotateY(-82deg);}
.gate .dw-knob{display:none;}
.gate .lf>u::after{content:"";position:absolute;top:-20%;width:5px;height:14px;border-radius:40%;background:linear-gradient(90deg,#8e6936,#dfbd74,#9d7841);box-shadow:1px 2px 2px #3c2d2440;}
.gate .lf.l>u::after{right:-9%;}.gate .lf.r>u::after{left:-9%;}
.gate .door[data-door=glass] .lf>u::after{top:52%;}
.gate::after{background:#f2e8d7 url('/img/studio/paper-v2.webp') center/600px auto;}
.gate.opening .g-hero::after{content:"";position:absolute;top:96%;left:10%;width:80%;height:28%;background:linear-gradient(#ffedc985,transparent);clip-path:polygon(20% 0,80% 0,100% 100%,0 100%);pointer-events:none;animation:threshold-light .7s ease both;}
@keyframes threshold-light{from{opacity:0;transform:scaleY(.2);transform-origin:top}to{opacity:1;transform:scaleY(1);transform-origin:top}}
@media(max-height:700px){.gate .g-hero .door.lg{width:210px;height:284px;}.gate .g-brand{top:20px;}.gate>.g-sub{top:76px;}}
@media(prefers-reduced-motion:reduce){.gate .door.open .lf,.gate::after{transition:none!important;}.gate.opening .g-hero::after{animation:none!important;}}

/* Keep the entrance within the available viewport, including tablet Safari. */
.gate{height:100dvh;min-height:0;box-sizing:border-box}
.gate::before{z-index:0;transform:none}
.gate .g-brand,.gate>.g-sub,.gate>.g-swap{z-index:2}
.gate .g-hero{z-index:1}
.gate .g-hero .door.lg{height:min(500px,calc(70dvh - 135px));width:min(370px,calc((70dvh - 135px)*.74))}
.gate.asking .gatecard{position:fixed;z-index:4;top:50dvh;max-height:calc(100dvh - 32px - env(safe-area-inset-top) - env(safe-area-inset-bottom));box-sizing:border-box;overflow-y:auto}
.gate>.doorwall,.gate>.g-note{position:relative;z-index:1}
