/* Singlish base styles — extracted verbatim from the single-file build (src/pop.html @ 3f1ad12). */

/* A night-mode music app on purpose: one dark look, lit by the current song's cover art. */
:root{
  color-scheme:dark;
  --bg:#0B0A14; --glass:rgba(255,255,255,.055); --glass-2:rgba(255,255,255,.1); --glass-3:rgba(255,255,255,.16);
  --stroke:rgba(255,255,255,.09); --stroke-2:rgba(255,255,255,.18);
  --ink:#F7F5FF; --soft:#D4D0EC; --muted:#928EB3; --dim:#5D5A7C;
  --hot:#FF4D8D; --coral:#FF7A59; --amber:#FFB547; --hl:#FFE14A; --hl-ink:#1D1426; --right-green:#4ADE80;
  --grad:linear-gradient(95deg,var(--hot),var(--coral) 55%,var(--amber));
  --f-display:"Bricolage Grotesque","Avenir Next","PingFang SC",system-ui,sans-serif;
  --f-body:"Figtree",-apple-system,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  --f-ipa:"Gentium Book Plus","Charis SIL","Lucida Sans Unicode","Segoe UI",serif;
  --art:none;
}
*{box-sizing:border-box}
[hidden]{display:none!important}
/* body grows with the content so sticky header + search stay pinned however far the page scrolls (phones pin the body separately) */
html{height:100%}
body{min-height:100%}
body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 var(--f-body);-webkit-font-smoothing:antialiased}
button{font:inherit;color:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}
a{color:var(--amber)}
:focus-visible{outline:2px solid var(--hot);outline-offset:2px}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}

/* ambient cover-art glow behind everything */
.ambient{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.ambient i{position:absolute;inset:-15%;background:center/cover no-repeat;filter:blur(90px) saturate(1.7);opacity:0;transition:opacity 1.2s ease;transform:scale(1.1)}
.ambient i.show{opacity:.5}
.ambient::after{content:"";position:absolute;inset:0;background:radial-gradient(120% 90% at 70% 0%,transparent,var(--bg) 75%)}
.top,.app{position:relative;z-index:1}

/* ---------- header ---------- */
.top{position:sticky;top:env(safe-area-inset-top,0px);z-index:20;display:flex;align-items:center;gap:18px;padding:14px 28px;
  background:color-mix(in srgb,var(--bg) 62%,transparent);backdrop-filter:blur(18px) saturate(1.4);-webkit-backdrop-filter:blur(18px) saturate(1.4);border-bottom:1px solid var(--stroke)}
.logo{display:flex;align-items:center;gap:10px;min-width:0}
.logo h1{margin:0;font:800 24px/1 var(--f-display);letter-spacing:-.03em;white-space:nowrap}
.logo h1 span{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.eq{display:inline-flex;align-items:flex-end;gap:3px;height:20px}
.eq i{width:4px;height:6px;border-radius:2px;background:var(--grad);transition:height .3s}
.eq i:nth-child(1){height:8px}.eq i:nth-child(2){height:16px}.eq i:nth-child(3){height:11px}.eq i:nth-child(4){height:20px}   /* a still logo when nothing plays */
body.is-playing .eq i{animation:eq .8s ease-in-out infinite alternate}
.eq i:nth-child(2){animation-delay:-.2s!important}.eq i:nth-child(3){animation-delay:-.45s!important}.eq i:nth-child(4){animation-delay:-.1s!important}
@keyframes eq{0%{height:4px}100%{height:20px}}
.tagline{margin:0;color:var(--muted);font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.top .grow{flex:1}
.prog{display:flex;align-items:center;gap:10px;font-size:13px;color:var(--muted);white-space:nowrap;font-variant-numeric:tabular-nums}
.prog b{color:var(--ink);font-weight:700}
.prog-bar{width:120px;height:6px;border-radius:99px;background:var(--glass-2);overflow:hidden}
.prog-bar i{display:block;height:100%;width:0;background:var(--grad);border-radius:inherit;transition:width .6s cubic-bezier(.3,.7,.3,1)}

/* ---------- layout ---------- */
.app{display:grid;grid-template-columns:minmax(0,1fr) minmax(400px,470px);gap:32px;padding:24px 28px 40px;align-items:start;max-width:1480px;margin:0 auto}
.browser{min-width:0}
.filters{display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin-bottom:14px;
  /* stays in view while the cards scroll: pinned right under the sticky header (53px) */
  position:sticky;top:calc(env(safe-area-inset-top,0px) + 53px);z-index:15;margin-inline:-10px;padding:12px 10px;
  background:color-mix(in srgb,var(--bg) 86%,transparent);backdrop-filter:blur(16px) saturate(1.3);-webkit-backdrop-filter:blur(16px) saturate(1.3);border-radius:0 0 18px 18px}
.search{flex:1 1 240px;position:relative;min-width:0}
.search svg{position:absolute;left:14px;top:50%;translate:0 -50%;color:var(--muted)}
.search input{width:100%;height:42px;border:1px solid var(--stroke);background:var(--glass);color:var(--ink);border-radius:999px;padding:0 16px 0 40px;font:inherit;font-size:14px}
.search input::placeholder{color:var(--muted)}
.search input:focus{outline:none;border-color:var(--stroke-2);background:var(--glass-2)}
.chips{display:flex;gap:6px;flex-wrap:wrap}
.chips button{height:34px;border:1px solid var(--stroke);background:transparent;border-radius:999px;padding:0 14px;font-size:13px;font-weight:600;color:var(--soft)}
.chips button:hover{background:var(--glass)}
.chips button[aria-pressed="true"]{background:var(--hot);color:#fff;border-color:var(--hot)}
.count{font-size:12px;color:var(--muted);margin:0 0 14px;letter-spacing:.08em;text-transform:uppercase}
/* B1（2026-09-30 工单 AC3）：会话内点队列外词时词表里的明确提示（js/app.js showPickHint 懒创建/自动移除） */
.pick-hint{font-size:13px;font-weight:700;color:var(--amber);margin:0 0 12px;letter-spacing:0}
/* 游客 20 词限制提示（docs/guest-mode.md §2，2026-09-29 增补）：仅游客态露出（body.guest 由 js/app.js 开关） */
.guest-note{display:none;margin:-8px 0 14px}
body.guest .guest-note{display:block}
/* qa_journey_vision_1002 工单 U（F9）：最小列 186→168——1280 视口词表列 3→4 列
   （722px 列宽 ÷ 168+14 = 4.04），消掉大宽度下的成片空置；移动断点有自己的列规则，不受影响 */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(168px,1fr));gap:14px;align-content:start}

/* card = record sleeve with the song's disc peeking out */
.card{--r:18px;position:relative;overflow:hidden;text-align:left;border:1px solid var(--stroke);background:var(--glass);border-radius:var(--r);padding:16px 16px 14px;display:flex;flex-direction:column;gap:3px;min-height:150px;
  transition:transform .2s cubic-bezier(.3,.7,.3,1),background .2s,border-color .2s}
.card:hover{transform:translateY(-3px) rotate(-.4deg);background:var(--glass-2);border-color:var(--stroke-2)}
.card .disc{position:absolute;top:-18px;right:-18px;width:78px;height:78px;border-radius:50%;overflow:hidden;
  background:#111;box-shadow:0 0 0 5px rgba(0,0,0,.55),0 6px 18px rgba(0,0,0,.5);transition:transform .35s cubic-bezier(.3,.7,.3,1)}
.card .disc img{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(1.15)}
.card .disc::after{content:"";position:absolute;inset:0;border-radius:50%;background:radial-gradient(circle,var(--bg) 0 5px,rgba(0,0,0,.35) 6px 11px,transparent 12px),repeating-radial-gradient(circle,rgba(0,0,0,.14) 0 1px,transparent 1px 4px)}
.card:hover .disc{transform:translate(-6px,6px) rotate(40deg)}
.card.playing .disc{animation:spin 3.2s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.card .no{font-size:11px;font-weight:700;color:var(--dim);letter-spacing:.08em;font-variant-numeric:tabular-nums}
.card .w{margin-top:10px;font:700 24px/1.05 var(--f-display);letter-spacing:-.025em;overflow-wrap:anywhere;padding-right:30px}
.card .ph{font:14px/1.3 var(--f-ipa);color:var(--muted)}
.card .mn{font-size:13px;color:var(--soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card .sg{margin-top:auto;padding-top:10px;font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card .sg b{color:var(--soft);font-weight:600}
.card.done .no::after{content:"  ✓ 已学";color:var(--amber);letter-spacing:.04em}
.card.on{border-color:transparent;background:linear-gradient(var(--bg),var(--bg)) padding-box,var(--grad) border-box;border:1.5px solid transparent}
.card.on .w{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.card .w.long{font-size:clamp(16px,4.6vw,21px);letter-spacing:-.035em;overflow-wrap:normal}
.empty{color:var(--muted);padding:40px 0;text-align:center;grid-column:1/-1}

/* ---------- now playing ---------- */
.aside{position:sticky;top:calc(env(safe-area-inset-top,0px) + 86px);display:flex;flex-direction:column;gap:12px;
  height:calc(100dvh - env(safe-area-inset-top,0px) - 86px - 16px);min-height:520px}
/* 合并播放卡（用户反馈：deck+ctl 两卡合一、压高度还歌词）：上 .deck-main 行 + 发丝线 + .ctl 控制行。
   高度取舍：信息列（徽章+歌名两行+歌手+链接 ≈124px）+ 控制行（56px）+ padding/gap（36px）的内容下限
   ≈216px——工单给的 17dvh/176 会把链接/徽章削顶（.deck overflow:hidden），故定 22dvh、196-216（下限兜矮窗）；
   仍比原 deck(140-210)+ctl(72)+gap(12) 合计 224-294 矮 28-78px，差额全数落进 #deskStage（flex:1）歌词 */
.aside > .deck{flex:none;aspect-ratio:auto;height:clamp(196px,22dvh,216px)}
#deskStage{flex:1;min-height:0;display:flex}
#deskStage .stage{flex:1;min-height:0;overflow:hidden}
#deskStage .lyrics{flex:1;height:auto;min-height:110px}
.aside > .hint{flex:none}
.deck{position:relative;overflow:hidden;border-radius:26px;max-width:100%;display:flex;flex-direction:column;gap:10px;padding:14px 16px 12px;background:#15121F;box-shadow:0 20px 60px rgba(0,0,0,.55),0 0 0 1px var(--stroke)}
.deck-bg{position:absolute;inset:-20%;background:center/cover no-repeat;filter:blur(40px) saturate(1.6) brightness(.7);transition:background-image .6s}
.deck-bg::after{content:"";position:absolute;inset:0;background:linear-gradient(100deg,rgba(11,10,20,.25),rgba(11,10,20,.8) 70%)}
.deck-main{position:relative;z-index:1;flex:1;min-height:0;display:flex;align-items:center;gap:16px}
/* the cover itself is the CD: same disc treatment as the cards, spinning while a clip plays.
   旋转挂在 img 上而非 .deck-cd——盘面已收编为播放/暂停/重播钮（.cd-ctl），钮不能跟着转；
   ::after 纹理（径向渐变）旋转对称，挪轴后视觉不变 */
.deck-cd{position:relative;flex:none;height:100%;aspect-ratio:1;z-index:1;border-radius:50%;overflow:hidden;background:#111;
  box-shadow:0 0 0 6px rgba(0,0,0,.55),0 14px 40px rgba(0,0,0,.6)}
.deck-cd img{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(1.15);animation:spin 5s linear infinite;animation-play-state:paused}
body.is-playing .deck-cd img{animation-play-state:running}
.deck-cd::after{content:"";position:absolute;inset:0;border-radius:50%;background:radial-gradient(circle,#15121F 0 6%,rgba(0,0,0,.35) 6.5% 13%,transparent 13.5%),repeating-radial-gradient(circle,rgba(0,0,0,.14) 0 1px,transparent 1px 4px)}
.cd-ctl{position:absolute;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;border:0;padding:0;border-radius:50%;background:transparent;color:#fff;cursor:pointer;-webkit-tap-highlight-color:transparent}
.cd-ctl svg{filter:drop-shadow(0 1px 8px rgba(0,0,0,.65))}
.cd-ctl:hover{background:rgba(8,6,16,.32);backdrop-filter:blur(1.5px);-webkit-backdrop-filter:blur(1.5px)}
.cd-ctl:focus-visible{outline:2px solid var(--hot);outline-offset:3px}
.deck-info{position:relative;z-index:1;min-width:0;display:flex;flex-direction:column;gap:4px;align-self:flex-end}
.deck-info b{font:800 19px/1.1 var(--f-display);letter-spacing:-.02em;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.deck-info > span{font-size:13px;color:var(--soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.deck-info a{margin-top:4px;font-size:12px;font-weight:700;color:var(--ink);text-decoration:none;opacity:.8;white-space:nowrap}
.deck-info a:hover{opacity:1;text-decoration:underline}
.clip{align-self:flex-start;margin-bottom:4px;background:rgba(11,10,20,.6);backdrop-filter:blur(8px);color:#fff;font-size:12px;font-weight:700;border-radius:999px;padding:3px 10px;font-variant-numeric:tabular-nums;display:flex;gap:6px;align-items:center}
.clip::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--hot);box-shadow:0 0 10px var(--hot)}
/* F5（qa_journey_vision_1002 工单 M）：渐变发丝线语义独占给会话进度（#learnProg）——片段播放进度
   只在播放中露出，且降为中性白色刻度（#time 同语义层），非播放态不占视觉 */
.deck-prog{position:absolute;left:0;right:0;bottom:0;height:4px;background:rgba(255,255,255,.1);z-index:2;opacity:0;transition:opacity .25s}
.deck-prog i{display:block;height:100%;width:0;background:rgba(255,255,255,.5)}
body.is-playing .deck-prog{opacity:1}
.stage{position:relative;background:var(--glass);border:1px solid var(--stroke);border-radius:26px;padding:18px 22px 16px;display:flex;flex-direction:column;gap:10px;min-width:0;
  backdrop-filter:blur(24px) saturate(1.3);-webkit-backdrop-filter:blur(24px) saturate(1.3)}
.st-top{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.pill{font-size:11.5px;font-weight:700;letter-spacing:.04em;border-radius:999px;padding:3px 10px;background:var(--glass-2);color:var(--soft)}
.pill.band{background:var(--grad);color:#1A0C14}
.st-top .no{margin-left:auto;font-size:12px;font-weight:700;color:var(--dim);font-variant-numeric:tabular-nums}
.st-word{margin:2px 0 0;font:800 clamp(36px,3.6vw,50px)/.95 var(--f-display);letter-spacing:-.045em;overflow-wrap:anywhere}
/* qa_journey_vision_1002 工单 V（F16）：音标 pill 与释义拆行（原 align-items:center 同行挤压），
   层级与学习卡同构；试听/学习共用同一模板，卡片增高由歌词区 flex 吸收，无布局跳动 */
.st-row{display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.st-ipa{display:inline-flex;gap:8px;align-items:center;border:1px solid var(--stroke-2);background:transparent;border-radius:999px;padding:4px 12px 4px 10px;font:16px/1.4 var(--f-ipa);color:var(--soft);transition:background .2s,color .2s}
.st-ipa:hover{background:var(--ink);color:var(--bg)}
.st-mean{margin:0;font-size:17px;font-weight:700}
.st-en{margin:-4px 0 0;color:var(--muted);font-size:14px}
/* 词面信息区容器（stage 的主子元素层）：桌面只承接原 .stage 的 gap:10 节奏，布局语义不变；
   移动端（phone 断点）升格为溢出阀门——歌词改固定带后，超长词面在卡内自滚，
   不再把歌词顶出卡底被 carousel 硬裁剪（拉伸 flex 项的内溢出不进 slide 滚动区） */
.st-body{display:flex;flex-direction:column;gap:10px;min-width:0}

.lyrics{position:relative;height:190px;overflow:hidden;scroll-behavior:smooth;margin:4px -4px 0;padding:0 4px;user-select:none;-webkit-user-select:none;-webkit-mask-image:linear-gradient(transparent,#000 22%,#000 78%,transparent);mask-image:linear-gradient(transparent,#000 22%,#000 78%,transparent)}   /* F2: 程序赋 scrollTop 时平滑跟随 */
.lyrics-in{padding:6px 0;transition:transform .55s cubic-bezier(.3,.7,.3,1)}
.stage.live .lyrics-in{padding:70px 0}
/* lines wrap at 100%/1.06 so the current line, scaled by 1.06 from the left, still fits the box */
.ln{cursor:pointer;max-width:calc(100% / 1.06);margin:0;padding:13px 0;font:700 20px/1.35 var(--f-display);letter-spacing:-.01em;color:var(--soft);isolation:isolate;transform-origin:left center;transition:transform .4s cubic-bezier(.3,.7,.3,1),opacity .4s,color .4s}
.stage.live .ln{color:var(--dim)}
@media (hover:hover){ .ln:hover{color:var(--ink)} .stage.live .ln:not(.cur):hover{color:var(--soft)} }
.stage.live .ln.cur{color:var(--ink);transform:scale(1.06)}
.stage.live .ln.past{color:var(--muted);opacity:.6}
.lw{--p:0}
.stage.live .ln.cur .lw:not(.tw):not(.xw){background:var(--grad) 0 0/calc(var(--p)*100%) 100% no-repeat,linear-gradient(var(--ink),var(--ink));-webkit-background-clip:text;background-clip:text;color:transparent}
.tw{position:relative;white-space:nowrap;cursor:help;color:var(--hl-ink)!important;padding:0 .12em;margin:0 -.04em}
.tw::before{content:"";position:absolute;inset:.1em -.02em .02em;background:var(--hl);border-radius:.28em .18em .32em .2em;transform:skew(-7deg) rotate(-1.2deg);z-index:-1;box-shadow:0 0 22px rgba(255,225,74,.35)}
.stage.live .ln.cur .tw.hit::before{animation:pop .45s cubic-bezier(.3,1.6,.5,1)}
@keyframes pop{0%{transform:skew(-7deg) rotate(-1.2deg) scale(1)}45%{transform:skew(-7deg) rotate(-3deg) scale(1.18)}100%{transform:skew(-7deg) rotate(-1.2deg) scale(1)}}
.lyr-msg{color:var(--muted);font-size:13px;padding:10px 0}
/* U8（2026-09-30）：歌词加载失败后的「重试」钮——胶囊玻璃按钮族（同 .browser-head button），
   只出现在歌词区失败态，点击重走 fillLyrics（js/lyrics.js） */
.lyr-retry{display:inline-block;margin:4px 0 12px;min-height:36px;padding:8px 20px;border:1px solid var(--stroke-2);
  border-radius:999px;background:var(--glass-2);color:var(--ink);font-size:13px;font-weight:700;transition:background .15s}
.lyr-retry:hover{background:var(--glass-3)}

.st-note{margin:0;font-size:13px;color:var(--soft)}
.st-tip{font-size:13.5px;color:var(--soft);border:1px dashed var(--stroke-2);border-radius:14px;padding:9px 12px}
.st-tip b{font-size:11px;font-weight:800;letter-spacing:.1em;color:var(--amber);margin-right:8px}

/* ---------- controls ---------- */
/* 控制行不再独立成胶囊（并入播放卡）：玻璃底/描边/圆角/模糊全撤，发丝线上边线当分隔，
   左右收 2px 让线贴近内容、宽随卡身 */
.ctl{display:flex;align-items:center;gap:4px;position:relative;z-index:1;padding:10px 2px 0;border-top:1px solid var(--stroke-2)}
.ctl button{border:0;background:transparent;border-radius:999px;height:40px;min-width:40px;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0 10px;color:var(--soft);font-size:13px;font-weight:700;transition:background .15s,color .15s}
.ctl button:hover{background:var(--glass-2);color:var(--ink)}
.ctl .play{background:var(--grad);color:#1A0C14;width:46px;height:46px;box-shadow:0 8px 26px rgba(255,77,141,.45)}
.ctl .play:hover{background:var(--grad);color:#1A0C14;transform:scale(1.05)}
/* ---------- W4（2026-09-30 工单）：首播在途反馈——点播到出声之间加载态脉冲（playing 事件到达即收，
   reduced-motion 下自动关闭）；is-playing 到来时 is-loading 已被清除，两态不并存 ---------- */
body.is-loading .ctl .play svg{animation:pulse .9s ease-in-out infinite alternate}
body.is-loading .eq i{animation:eq .8s ease-in-out infinite alternate}
@keyframes pulse{from{opacity:.35}to{opacity:1}}
.ctl .tog[aria-pressed="true"],.ctl .tog[aria-pressed="true"]:hover{color:var(--hot);background:rgba(255,77,141,.16);box-shadow:inset 0 0 0 1px rgba(255,77,141,.35)}
.ctl .time{margin-left:auto;font-size:12px;font-weight:600;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
/* 会话态（学习/复习）传输行整排退役：播放/暂停/重播收进黑胶盘（.cd-ctl 三态），
   上一词/下一词由会话键行与滑卡/键盘承担，随机/循环/计时属自由浏览语境——功能全局不丢 */
body.stw-learn .ctl,body.stw-review .ctl,body.stw-study .ctl{display:none}
/* 桌面会话 deck 压实（2026-10-05 用户定调：传输行退役后组件还照旧高、四行字回潮）：
   把 2026-10-04 移动端二轮减行的排版（PR #14「四行字太多」——片段徽章去、收成
   标题/歌手+跳转两行、链接缩短）延伸到桌面会话态；卡高 auto 随两行内容走，
   盘 96px 保住点按面（原 196-216 高卡连 ctl 一起算 ~80px 还给词卡/歌词）。
   只圈 min-width:900px——移动断点已有同款值，避免盖掉移动端 56px 盘 */
@media (min-width:900px){
  body:is(.stw-learn,.stw-review,.stw-study) .aside > .deck{height:auto;padding:10px 14px 8px;gap:8px;border-radius:22px}
  body:is(.stw-learn,.stw-review,.stw-study) .deck-cd{height:96px}
  body:is(.stw-learn,.stw-review,.stw-study) .aside > .deck .clip{display:none}
  body:is(.stw-learn,.stw-review,.stw-study) .deck-info{align-self:center;flex:1;min-width:0;flex-flow:row wrap;align-items:baseline;gap:2px 10px}
  body:is(.stw-learn,.stw-review,.stw-study) .deck-info b{flex:1 1 100%;-webkit-line-clamp:1}
  body:is(.stw-learn,.stw-review,.stw-study) .deck-info a{margin-left:auto;margin-top:0}
  body:is(.stw-learn,.stw-review,.stw-study) .deck-info a .long{display:none}
}
.hint{font-size:12px;color:var(--muted);margin:0;padding:0 8px}
.hint kbd{font:600 11px var(--f-body);border:1px solid var(--stroke-2);border-bottom-width:2px;border-radius:5px;padding:0 5px;color:var(--soft)}
.foot{grid-column:1;font-size:12px;color:var(--dim);border-top:1px solid var(--stroke);padding-top:16px;max-width:80ch}
.carousel{display:none}
/* W4（2026-09-30 工单）：轮播 [×] 回首页钮——桌面本就没有轮播，基础态一律不渲染（移动断点内的
   :not([hidden]) 规则才把它放出来；双保险：js 也按 isMobile() 门控） */
.carousel-x{display:none}
/* F13（2026-09-29）：桌面端词表也露出「词表 + 关闭」头——关闭钮是词库可见的回首页出口
   （此前只在 ≤899px 显示，桌面用户进词库后只能靠隐藏的 logo 交互逃离）。关闭经 #closeList
   派 stw:list-close → js/home.js open() 回首页；移动端吸顶样式仍在下方媒体查询里，不回归 */
.browser-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
.browser-head h2{margin:0;font:800 26px var(--f-display);letter-spacing:-.03em}
.browser-head button{border:1px solid var(--stroke-2);background:var(--glass);border-radius:999px;padding:7px 15px;font-weight:700;font-size:13px}

/* ---------- phone ---------- */
@media (max-width:899px){
  html{height:100%;overflow:hidden;overscroll-behavior:none}
  body{overflow:hidden;display:flex;flex-direction:column;height:100%;position:fixed;inset:0;overscroll-behavior:none}
  .top{padding:6px 16px;gap:10px;flex:none}
  .logo h1{font-size:21px}
  .tagline,.prog-bar{display:none}
  .top .logo{flex:none}
  /* ---------- W2（2026-09-30 工单）：移动端头部重排，消掉中间的 ~130px 空白 ----------
     手机上的标准分布是「品牌靠左、操作靠右」，把撑开的 .grow 提前（order 只在 flex 布局里重排
     视觉顺序，DOM/读屏顺序不动），空隙落在品牌与操作簇之间。桌面 ≥900px 无此规则，头部保持
     原序（tagline 还在，重排会乱）。完整版 pill 已于 2026-09-30 移除，序号跳过 2 不重排。 */
  .top .grow{order:1}
  .top .prog{order:3}
  .top .btn-auth{order:4}
  /* z-index:auto so the fixed word-list panel (z 40) can sit above the header (z 20) */
  .app{display:flex;flex-direction:column;padding:0;flex:1;min-height:0;min-width:0;gap:0;width:100%;max-width:100vw;z-index:auto}
  .aside{position:static;display:contents}
  #deskStage,.hint,.foot{display:none}
  /* 词为中心（与桌面同序）：轮播（词卡+歌词）在上，合并播放卡（信息+控制行）流内沉底 */
  .carousel{order:1}
  /* 控制行已并卡（无悬浮控制条）：底部让位从 100px 收成 14px+安全区，高度 auto 内容自适应。
     2026-10-04 歌词固定带工单：会话内歌词要与词面同屏，deck 再压一轮——padding/gap/CD 全收，
     歌名移动端单行截断。2026-10-11 用户反馈：词卡（歌词区）与播放卡贴死，顶边距留隙（与底边距同拍 10px） */
  .aside > .deck{order:3;flex:none;align-self:stretch;width:auto;margin:10px 16px calc(10px + env(safe-area-inset-bottom,0px));border-radius:22px;height:auto;padding:10px 14px 8px;gap:8px}
  /* 高 auto 下 .deck-cd 的 height:100% 失去参照（塌陷/被原尺寸撑爆），给固定大小，宽由 aspect-ratio:1 推出 */
  .deck-cd{height:56px}
  /* 二轮减行（2026-10-04 用户定调：四行字太多）：片段徽章移动端去掉；信息列收成
     标题 / 歌手+跳转 两行——标题独占一行，Apple Music 跳转挪到歌手行另一端（卡片右缘）。
     flex:1 让信息列撑到卡右缘，margin-left:auto 才是真右对齐，不是内容宽的伪右 */
  .aside > .deck .clip{display:none}
  .deck-info a .long{display:none}
  .deck-info{align-self:center;flex:1;min-width:0;flex-flow:row wrap;align-items:baseline;gap:2px 10px}
  .deck-info b{flex:1 1 100%;-webkit-line-clamp:1}
  .deck-info a{margin-left:auto;margin-top:0}
  .aside > .deck .ctl{padding-top:4px}
  /* 词表面板（2026-09-30 用户定调：标题区完全固定不动）——面板改 flex 列不滚动，
     标题/筛选/统计静置，唯一滚动区是 .grid（占位推卡式布局，弃 sticky 吸附方案） */
  .browser{position:fixed;inset:0;z-index:40;background:var(--bg);display:none;flex-direction:column;overflow:hidden;padding:calc(env(safe-area-inset-top,0px) + 14px) 16px 0}
  .browser.open{display:flex}
  .browser .filters{position:static;margin-inline:-16px;padding:10px 16px;border-radius:0}
  .browser-head{display:flex;align-items:center;justify-content:space-between;margin:0 -16px 12px;padding:0 16px}
  .grid{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;margin:0 -16px;padding:2px 16px calc(env(safe-area-inset-bottom,0px) + 24px);grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;scrollbar-width:none}
  .browser .grid::-webkit-scrollbar{display:none}
  .card .w{font-size:21px}
  /* padding-bottom 不再给固定播放器让位（deck 已进文档流垫在下面）——这 ~84px 还给词卡（用户 2026-09-28：卡片撑大） */
  .carousel{display:flex;flex:1;min-height:0;width:100%;min-width:0;max-width:100vw;overflow-x:auto;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;scrollbar-width:none}
  .carousel::-webkit-scrollbar{display:none}
  .slide{flex:0 0 100%;scroll-snap-align:center;scroll-snap-stop:always;padding:6px 16px 0;display:flex;overflow:hidden}
  .slide .stage{flex:1;padding:10px 18px 8px;gap:7px;min-height:100%;border-radius:24px}
  /* ---------- 歌词固定带（2026-10-04 工单：会话内歌词被挤到卡底外硬裁剪且不可滚） ----------
     旧模型 .slide{overflow-y:auto} 依赖卡高超窗滚动让出歌词——实测拉伸 flex 项（.stage）的内部
     溢出不进 slide 的 scrollHeight，超出的歌词直接被 carousel 裁掉（390×668 实测歌词 100% 不可见）。
     新模型：歌词 flex:1 + min-height 随视口浮动（22dvh，140–200 兜底）永远在折叠线上方；
     词面信息收进 .st-body 作溢出阀门，超高时卡内自滚，次要信息（例句/搭配/形态注）让位。
     卡内滚动条全隐，手势与轮播横滑按轴向天然分流 */
  .slide .st-body{flex:0 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;gap:6px;scrollbar-width:none}
  .slide .st-body::-webkit-scrollbar{display:none}
  .slide .st-word{font-size:36px}
  /* 音标 pill 与释义并排（F16 拆行是桌面层级方案；移动会话竖向预算紧张，行内同权更省 34px） */
  .slide .st-row{flex-direction:row;flex-wrap:wrap;align-items:center;gap:4px 12px}
  .slide .st-tip{padding:6px 10px}
  .slide .lyrics{flex:1 1 0;height:auto;min-height:clamp(140px,21dvh,200px)}
  .stage.live .lyrics-in{padding:40px 0}
  .ln{font-size:19px}
  /* .ctl 已随播放卡流内（合并卡）：原 position:fixed 底部悬浮规则整段拆除，尺寸/玻璃底直接吃桌面值 */
  /* ---------- W4（2026-09-30 工单）：移动端会话内关键触控目标命中区 ≥44×44 ----------
     仅移动断点生效。控制行按钮因用户「合卡压高度」定调 44→40（随桌面值，.play 46 由更具体规则压住），
     其余项维持 44 不回退 */
  .ctl button{height:40px;min-width:40px}
  /* 词表[关闭]（#closeList）：padding 撑出的 ~34px 高 → 命中区 44（AC7 审计项，本单内修） */
  .browser-head button{min-height:44px}
  /* 朗读钮（.st-ipa，词卡内会话控件）：32.4 → 44（AC7 全量审计发现的同族遗漏，本单内修） */
  .st-ipa{min-height:44px}
  /* 词表面板搜索框（#q）42 → 44、词典筛选 chips 34 → 44（与 AC7 点名的 .plan-chip 同族，本单内修） */
  .search input{height:44px}
  .chips button{height:44px}
  /* ---------- 移动端轮播回首页钮（index.html #carouselClose，W4 2026-09-30 工单引入） ----------
     位置：手机端 body flex 列内的流内成员（order:-2，与会话条 .learn-row 同槽位同占位方式）——
     可见时把轮播卡片自然下推，不遮任何内容；hidden 仍是唯一真值源（js/wiring.js syncCarouselClose）。
     2026-09-30 用户四次定调（iteration_3 后）：与会话条完全同格式——全宽玻璃横条、18px 圆角、
     「← 词库」左对齐（会话条是「← 学习 x/y」）；圆形款/小浮芯片均作废。
     图标仍为 Phosphor arrow-left 内联 SVG（index.html） */
  .carousel-x:not([hidden]){order:-2;flex:none;align-self:stretch;display:flex;align-items:center;gap:8px;justify-content:flex-start;
    height:52px;margin:10px 16px 0;padding:0 14px;border:1px solid var(--stroke);background:var(--glass);color:var(--soft);border-radius:18px;
    transition:background .15s,color .15s;-webkit-tap-highlight-color:transparent}
  .carousel-x-label{font-size:13px;font-weight:700;letter-spacing:.02em}
  .carousel-x:not([hidden]):hover{background:var(--glass-2);color:var(--ink)}
}
@media (max-width:420px){ .ctl .time{display:none} }
/* iOS zooms the page when focusing a field whose text is under 16px; 16px keeps the layout still (pinch-zoom stays allowed) */
@media (max-width:899px), (pointer:coarse){ input, select, textarea{font-size:16px!important} }
/* 会话模式桌面同手机（用户 2026-09-30 定调）：学习/复习中不显示词表列，播放列收成居中焦点列；
   会话条（learn-row）提到列顶。1003 工单 W19：review-ops 的 order:-2 覆盖已删——桌面 DOM 序
   （deskStage → reviewOps → deck）+ order:auto 本身就是移动端真相（进度行顶/词卡/键行），
   旧覆盖曾让键行排在其操作的进度之前（b47 跨端心智翻转）。回退预案：若 learn-ctrl 或桌面截图
   出现密度/滚动级联（1002 搬布局引爆教训），回退本项转 BK-2 桌面专项 */
@media (min-width:900px){
  body.stw-learn .app,body.stw-review .app,body.stw-study .app{grid-template-columns:minmax(0,470px);justify-content:center}
  body.stw-learn .browser,body.stw-review .browser,body.stw-study .browser{display:none}
  .aside > .learn-row{order:-2}
}
@media (min-width:900px) and (max-height:800px){ .aside > .hint{display:none} }
@media (prefers-reduced-motion:reduce){ *,*::before{animation:none!important;transition:none!important} }
/* ---------- extra IELTS words in the lyrics ---------- */
:root{--xw:var(--hot);--xw-edge:rgba(255,77,141,.5);--xw-ink:#FF7AA8}
/* same highlighter shape and pop as the main word, in the site's pink-red (start of the player gradient), white text */
.xw{position:relative;white-space:nowrap;cursor:help;padding:0 .12em;margin:0 -.04em;color:#FFFFFF!important}
.xw::before{content:"";position:absolute;inset:.1em -.02em .02em;background:var(--xw);border-radius:.28em .18em .32em .2em;transform:skew(-7deg) rotate(-1.2deg);z-index:-1}
.stage.live .ln.cur .xw.hit::before{animation:pop .45s cubic-bezier(.3,1.6,.5,1)}
/* label sits in the gap above the word's line (lines are spaced to make room); lives inside the scrolling lyrics */
.lyrics-in{position:relative}
.gloss{position:absolute;z-index:2;display:inline-flex;gap:5px;align-items:baseline;white-space:nowrap;pointer-events:none;
  height:20px;padding:0 9px;border-radius:7px;background:rgba(22,19,34,.88);border:1px solid var(--xw-edge);font-size:13px;line-height:18px;color:var(--soft);
  opacity:0;transform:translate(-50%,2px);transition:opacity .2s,transform .2s}
.gloss.on{opacity:1;transform:translate(-50%,0)}
.gloss b{font:700 13.5px/18px var(--f-display);color:var(--xw-ink)}
.gloss.main{border-color:rgba(255,225,74,.5)}
.gloss.main b{color:var(--hl)}
.gloss i{font:13px/18px var(--f-ipa);font-style:normal;color:var(--muted)}
.lyrics{isolation:isolate}
/* 完整版「想要」计数器 + 一次性问卷的样式已于 2026-09-30 随功能移除（头部完整版 pill 一并退役） */
/* ---------- word bank ---------- */
.card{content-visibility:auto;contain-intrinsic-size:auto 150px}
/* 换歌只换歌词（2026-10-04 用户定调）：卡底与词面静止，歌词盒随手势渐出、新内容渐入；
   原 swapUp/swapDown 整卡动画（translateY 34% + 渐隐，连底色带词面一起动）随 switchClip 改造移除 */
.lyrics{transition:opacity .18s ease}
.lyrics.lyr-swap{opacity:0}
.lyrics.lyr-in{animation:lyrIn .32s ease-out}
@keyframes lyrIn{from{opacity:0}to{opacity:1}}
/* 词面入场（2026-10-04 用户定调）：换词推进/收卡回词面/胶囊关闭时词面上滑渐入，
   明确「已是下一个单词」；reduced-motion 由全局关断覆盖 */
.stage.enter-word{animation:wordIn .38s cubic-bezier(.2,.8,.2,1)}
@keyframes wordIn{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}
/* songs of this word: a vertical column of dots on the card's right edge (like story pagination) */
.clip-dots{position:absolute;right:7px;top:50%;transform:translateY(-50%);z-index:4;display:flex;flex-direction:column;align-items:center;gap:6px}
.clip-dot{width:6px;height:6px;padding:0;border:0;border-radius:3px;background:rgba(255,255,255,.28);transition:height .3s cubic-bezier(.3,.7,.3,1),background .3s}
.clip-dot.on{height:20px;background:var(--grad)}
.clip-dot::after{content:"";position:absolute;inset:-6px -10px}   /* bigger tap target */
.clip-dot{position:relative}
@media (hover:hover){ .clip-dot:not(.on):hover{background:rgba(255,255,255,.55)} }
/* the part of the card that moves when changing song */
.stage .swipe-body{will-change:transform,opacity}
.loading{color:var(--muted);padding:40px 0;text-align:center;grid-column:1/-1}
/* ---------- share ---------- */
.st-share{border:1px solid var(--stroke-2);background:transparent;color:var(--soft);border-radius:50%;width:32px;height:32px;padding:0;display:inline-flex;align-items:center;justify-content:center;transition:background .15s,color .15s}
.st-share:hover{background:var(--ink);color:var(--bg)}
.st-fav{font-size:15px;line-height:1}
.st-fav[aria-pressed="true"]{color:var(--amber);border-color:var(--amber)}
.st-fav[aria-pressed="true"]:hover{background:transparent;color:var(--amber)}
.card.fav .no::before{content:"★ ";color:var(--amber)}
.st-top .no{margin-left:auto}
/* ---------- W4（2026-09-30 工单）：移动端词卡 ☆ 收藏 / 分享命中区 44×44（视觉圆径仍 32） ----------
   必须在上面 .st-share / .st-fav 基类之后：同特异性下源序靠后者胜，放前面会被基类压掉。
   命中区 = 按钮本体 44×44（getBoundingClientRect 达标、elementFromPoint 真可点），视觉圆走 ::before；
   两钮相邻 gap 6 → 中心距 = 22+6+22 = 50 ≥ 44，命中区边界间距 6px 不重叠。仅移动断点，桌面零变化 */
@media (max-width:899px){
  .st-share{position:relative;width:44px;height:44px;border:0;background:transparent}
  .st-share::before{content:"";position:absolute;left:50%;top:50%;width:32px;height:32px;transform:translate(-50%,-50%);border:1px solid var(--stroke-2);border-radius:50%;background:transparent;transition:background .15s}
  .st-share:hover{background:transparent;color:var(--bg)}
  .st-share:hover::before{background:var(--ink)}
  .st-fav[aria-pressed="true"]::before{border-color:var(--amber)}
  .st-fav[aria-pressed="true"]:hover{color:var(--amber)}
  .st-fav[aria-pressed="true"]:hover::before{background:transparent}
}
.sheet{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;padding:calc(env(safe-area-inset-top,0px) + 16px) 16px calc(env(safe-area-inset-bottom,0px) + 16px);background:rgba(6,5,12,.72);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
.sheet-card{display:flex;flex-direction:column;align-items:center;gap:14px;max-width:min(440px,100%);max-height:100%}
.sheet-card img{display:block;max-width:100%;max-height:calc(100dvh - 190px);border-radius:18px;background:#15121F;
  /* the poster is dark on a dark backdrop: a light hairline and soft halo keep its edge readable */
  box-shadow:0 0 0 1px rgba(255,255,255,.22),0 0 0 6px rgba(255,255,255,.04),0 24px 70px rgba(0,0,0,.7)}
.sheet-card .busy{color:var(--soft);font-size:14px;padding:40px}
.sheet-actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.sheet-actions button{height:44px;border-radius:999px;padding:0 18px;font-weight:700;font-size:14px;border:1px solid var(--stroke-2);background:var(--glass-2);color:var(--ink)}
.sheet-actions .primary{border:0;background:var(--grad);color:#1A0C14}
.sheet-hint{margin:0;color:var(--muted);font-size:12px;text-align:center}
.sheet-hint:empty{display:none}
.sheet-hint{line-height:1.7}
.sheet-hint.strong{font-size:15px;font-weight:700;color:var(--ink)}
.sheet-hint small{font-size:12px;font-weight:500;color:var(--muted)}
@media (max-width: 400px){ .prog-word{display:none} }

