/* ============================================================
   敲敲英语 / 敲敲计量 · 手机与微信内置浏览器适配
   ------------------------------------------------------------
   这一层只加规则、不改 styles.css，加载顺序排在它后面。
   针对的三类环境：
     · 微信 iOS（WKWebView）—— 软键盘不改 innerHeight，只改 visualViewport；
       聚焦离屏 input 会把页面顶歪；:hover 会粘在最后点过的元素上。
     · 微信安卓（X5 内核）—— 软键盘会压缩视口；没有 speechSynthesis；
       输入法默认中文，且 keydown 只给 keyCode 229。
     · 刘海屏 / 灵动岛 —— 页面已经 viewport-fit=cover，必须自己补 safe-area。
   ============================================================ */

/* ---------- 全局：文字缩放、点击高亮、橡皮筋 ---------- */
html{
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
}
body{
  -webkit-tap-highlight-color:transparent;
  overscroll-behavior:none;
}
button,a,.pill-btn,.ghost-btn,.gchip,.course-item,.qopt,.big-btn,
.wc-th,.subj,.drill-btn,.profile-chip,.theme-btn,.goal,.modal-x,.nav-btn,.seg button{
  touch-action:manipulation;
  -webkit-touch-callout:none;
}
/* 打字区长按会弹出「拷贝 / 翻译」，把整句答案递到嘴边；场景卡长按会弹「保存图片」 */
.typing,.word,.ch,.chunks,.zh,.scene,.kb{
  -webkit-touch-callout:none;
  -webkit-user-select:none;user-select:none;
}

/* ---------- 视口高度 ----------
   100vh 在手机上量的是「地址栏收起后」的高度，页面一上来就比屏幕高一截，
   底部的设置栏被顶出屏幕。dvh 能解决地址栏，但解决不了软键盘：
   iOS 弹键盘时 innerHeight 纹丝不动，只有 visualViewport 会变。
   所以 JS 量到值以后给 <html> 加 .vv，用 --app-h 接管。 */
@supports (height:100dvh){
  .app{height:100dvh}
}
html.vv .app{height:var(--app-h)}
/* 浮层是 position:fixed + inset:0，量的是布局视口 —— 软键盘弹起来时
   它照样铺满整屏，下半截藏在键盘后面。跟着 --app-h 收一下。 */
html.vv .modal,
html.vv .cmdk{height:var(--app-h)}

/* ---------- 安全区（刘海 / 底部横条） ---------- */
@supports (padding:env(safe-area-inset-bottom)){
  .topbar{
    padding-left:calc(26px + env(safe-area-inset-left));
    padding-right:calc(26px + env(safe-area-inset-right));
  }
  .group-bar{
    padding-left:calc(26px + env(safe-area-inset-left));
    padding-right:calc(26px + env(safe-area-inset-right));
  }
  .stage{padding-bottom:calc(26px + env(safe-area-inset-bottom))}
  .q-stage{padding-bottom:calc(40px + env(safe-area-inset-bottom))}
  .sidebar{
    padding-top:calc(18px + env(safe-area-inset-top));
    padding-bottom:calc(18px + env(safe-area-inset-bottom));
    padding-left:calc(14px + env(safe-area-inset-left));
  }
  #toasts{bottom:calc(18px + env(safe-area-inset-bottom))}
  .modal{
    padding-top:calc(26px + env(safe-area-inset-top));
    padding-bottom:calc(26px + env(safe-area-inset-bottom));
  }
  .cmdk{padding-bottom:calc(20px + env(safe-area-inset-bottom))}
  @media (max-width:820px){
    .topbar{
      padding-left:calc(14px + env(safe-area-inset-left));
      padding-right:calc(14px + env(safe-area-inset-right));
    }
    .group-bar{
      padding-left:calc(14px + env(safe-area-inset-left));
      padding-right:calc(14px + env(safe-area-inset-right));
    }
    .stage{padding-bottom:calc(18px + env(safe-area-inset-bottom))}
    #toasts{bottom:calc(10px + env(safe-area-inset-bottom))}
  }
  @media (max-width:560px){
    .topbar{
      padding-left:calc(12px + env(safe-area-inset-left));
      padding-right:calc(12px + env(safe-area-inset-right));
    }
    .stage{padding-bottom:calc(14px + env(safe-area-inset-bottom))}
  }
}

/* ---------- 弹窗：360px 屏上会横向溢出 ----------
   .modal 是 grid + place-items:center，隐式列的最小尺寸取自内容的 min-content。
   档案面板里的打卡热力图 min-content 有 383px，直接把卡片撑到 433px、
   顶出 360px 的屏幕，右边整列数字看不见也滚不到。
   把列钉成 minmax(0,1fr)，再给卡片和滚动区解开 min-width/min-height:auto。 */
.modal{grid-template-columns:minmax(0,1fr)}
.modal-card{max-width:100%;min-width:0}
.modal-body{
  min-width:0;min-height:0;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
}
@supports (max-height:88dvh){
  .modal-card{max-height:88dvh}
  .cmdk-card{max-height:74dvh}
}
.heat{max-width:100%;-webkit-overflow-scrolling:touch}
.weak-cols>div:last-child{-webkit-overflow-scrolling:touch}
.vzg-wrap,.q-stage,.course-nav,.group-bar,.cmdk-list{-webkit-overflow-scrolling:touch}
.course-nav,.cmdk-list,.q-stage{overscroll-behavior:contain}

/* 窄屏上身份头竖过来，不然头像 + 名字 + 连击卡挤成三条断行 */
@media (max-width:560px){
  .pf-head{flex-wrap:wrap;gap:11px;padding:12px}
  .pf-streak{margin-left:auto}
  .pf-uid{font-size:10px}
  .modal{padding:14px}
  .modal-x{top:-11px;right:-11px;width:32px;height:32px}
  .modal-title{font-size:21px;padding:13px 16px 11px}
  .modal-body{padding:15px 15px 20px}
}

/* 首次到访卡：主按钮原来排在滚动区最底下，手机上第一屏只看得到四段介绍，
   没有滚动条提示，用户不知道下面还有「开始练」。把它钉在卡片底部。 */
@media (max-width:820px){
  #welcomeModal .modal-body{padding-bottom:0}
  #welcomeModal .big-btn{
    position:sticky;bottom:0;z-index:2;width:100%;
    margin:10px 0 0;padding:14px 18px;
    /* 第二层阴影是一圈奶油色实心边，把从按钮背后滚过去的介绍卡挡干净 */
    box-shadow:var(--sh-sm),0 0 0 15px var(--cream);
  }
  #welcomeModal .wc-theme{margin-bottom:12px}
}

/* ---------- 触屏：:hover 会粘住 ----------
   触屏没有「移开」这个动作，点过的按钮会一直保持 hover 的抬起态，
   看上去像被选中了。统一还原成静止态，按下的反馈交给 :active。
   带状态类（.on / .active）的规则权重更高，不受影响；这里只补几处
   权重刚好打平、需要显式写回来的。 */
@media (hover:none){
  .course-item:hover{transform:none;box-shadow:none}
  .course-item.active:hover{transform:translate(-2px,-2px);box-shadow:var(--sh-sm)}

  .ghost-btn:hover,.pill-btn:hover{
    transform:none;box-shadow:var(--sh-xs);background:var(--white);color:var(--ink)
  }
  .ghost-btn.primary:hover{background:var(--accent);color:var(--white);box-shadow:var(--sh-sm)}
  .pill-btn.danger:hover{background:var(--bad);color:var(--white)}

  .gchip:hover{transform:none;box-shadow:none}
  .gchip.on:hover{transform:translate(-1px,-1px);box-shadow:var(--sh-sm)}

  .qopt:hover:not(.locked){transform:none;box-shadow:var(--sh-xs);background:var(--cream)}

  .big-btn:hover{transform:none;box-shadow:var(--sh-sm)}
  .wc-th:hover{transform:none;box-shadow:var(--sh-xs)}
  .subj:hover{transform:none;box-shadow:var(--sh-xs)}
  .goal:hover{transform:none;box-shadow:var(--sh-xs)}
  .side-toggle:hover{transform:none;box-shadow:var(--sh-xs);background:var(--white);color:var(--ink)}
  .theme-btn:hover{transform:none;box-shadow:var(--sh-xs);background:var(--white);color:var(--ink)}
  .modal-x:hover{transform:none;background:var(--white);color:var(--ink)}
  .pf-av:hover{transform:rotate(-4deg);background:var(--tint)}
  .pf-name b:hover{background:transparent}
  .rv-head button:hover{transform:none;background:var(--white);color:var(--ink)}

  .profile-chip:hover{transform:none;box-shadow:var(--sh-xs);background:var(--soft)}
  .drill-btn:hover{transform:none;box-shadow:var(--sh-xs);background:var(--white)}
  .drill-btn:hover .dr-tx b{color:var(--ink)}
  .drill-btn:hover .dr-tx i{color:var(--ink2)}
}

/* ---------- 触屏：点得着的尺寸 ----------
   560px 断点把 pill 按钮压到 11px / 5px padding，实际高度 26px 左右，
   拇指点十次错三次。拉到 38px —— 苹果的 44pt 建议在这种密集工具条上
   会把设置栏撑成三行，38px 是能稳定点中又不占屏的折中。 */
@media (pointer:coarse){
  .pill-btn,.ghost-btn,.gchip,.big-btn,.nav-btn,.theme-btn,.side-toggle{
    min-height:38px;
  }
  .nav-btn,.theme-btn{min-width:38px}
  .seg button{min-height:34px}
  .settings-row,.hint-row{gap:8px}
  .modal-x{width:40px;height:40px}
  .wc-th{min-width:56px}
  .qopt{padding:13px 14px}
  .ol{width:28px;height:28px}
}

/* 指法键盘在 900px 以下是 display:none 的，按钮留着只会点了没反应 */
@media (max-width:900px){
  #kbdBtn{display:none}
}

/* ---------- 软键盘顶起来以后 ----------
   键盘一弹，可用高度只剩一半。场景卡 + 小节条 + 设置栏全留着的话，
   中文提示和打字区会被挤到键盘底下 —— 正在敲的那一行看不见。
   保留「中文 → 拆解 → 打字区」这条主链，其余先收起来。 */
html.kb-open .deco,
html.kb-open .scene,
html.kb-open .group-bar,
html.kb-open .settings-row,
html.kb-open .progress-bar,
html.kb-open .tap-hint{display:none !important}
html.kb-open .stage{
  justify-content:flex-start;gap:8px;padding-top:10px;padding-bottom:10px;
}
html.kb-open .topbar{height:48px}
html.kb-open .zh{font-size:19px}
/* 新概念跟打页上面还压着「第几句 / 第几课」和一整行中译。键盘一弹，
   这两样加起来能占掉小半屏 —— 句号收掉，中译降一档，位置全让给英文。 */
html.kb-open .tp-head{display:none}
html.kb-open .tp-zh{font-size:17px;line-height:1.4}
html.kb-open .word .letters{font-size:26px}
/* 键盘弹起来以后可用高度只剩一半，打字区的上限得跟着实测视口走：
   这时候 vh / dvh 量的还是整屏，按它算会有一半藏在键盘后面。 */
html.kb-open .typing{min-height:0;padding:12px;max-height:calc(var(--app-h,60vh) * .46)}
html.kb-open .miss-hint{top:-9px;padding:5px 9px;font-size:10.5px}
html.kb-open .hint-row{margin-bottom:2px}

/* ---------- 「点这里调出键盘」 ----------
   电脑上直接敲就行，手机上必须先聚焦一个 input 才会弹键盘 ——
   而承接输入的 #catcher 是隐形的，屏幕上没有任何东西告诉用户该点哪。 */
/* 一行搞定：手机上每多占 30px 高，底下的设置栏就少露一排 */
.tap-hint{
  display:none;align-items:center;justify-content:center;gap:7px;flex-wrap:wrap;
  width:min(440px,100%);padding:9px 14px;cursor:pointer;line-height:1.25;
  font-family:var(--body);font-size:12.5px;font-weight:800;color:var(--on-accent);
  background:var(--soft);border:2.5px solid var(--ink);border-radius:11px;
  box-shadow:var(--sh-xs);animation:tapPulse 1.6s ease-in-out 3;
}
.tap-hint i{
  font-style:normal;font-size:10px;font-weight:700;opacity:.7;
}
html.touch .tap-hint.show{display:flex}
@keyframes tapPulse{
  0%,100%{transform:translateY(0)}
  50%{transform:translateY(-3px)}
}
@media (prefers-reduced-motion:reduce){
  .tap-hint{animation:none}
}

/* 手机上把 #catcher 挪进舞台里（mobile.js 做的），iOS 聚焦时会把它滚进视野，
   在屏幕外的话整页会横向弹一下。宽高留 1px、字号 16px 免得 iOS 自动放大。 */
html.touch #catcher{
  position:absolute;left:50%;top:60%;width:1px;height:1px;
  opacity:0;border:0;padding:0;margin:0;font-size:16px;
  color:transparent;background:transparent;caret-color:transparent;
  pointer-events:none;z-index:-1;
}

/* iOS 上任何 <16px 的输入框聚焦都会强制放大页面，再也缩不回去 */
@media (pointer:coarse){
  #cmdkInput{font-size:16px}
  input,textarea,select{font-size:16px}
}

/* ---------- 朗读不可用（微信安卓 X5 没有 speechSynthesis） ---------- */
html.no-tts #speakBtn,
html.no-tts #dictationBtn,
html.no-tts #spellBtn,
html.no-tts #speakMode{
  opacity:.42;
}
html.no-tts #speakBtn::after,
html.no-tts #dictationBtn::after{
  content:'✕';margin-left:5px;font-weight:900;
}

/* ---------- 命令面板 ---------- */
@media (max-width:560px){
  .cmdk{padding:4vh 10px 10px}
  .cmdk-foot{display:none}
  .cmd-row{padding:11px 10px}
}

/* ---------- 提示条 ---------- */
@media (max-width:820px){
  .toast{min-width:0}
}
