/* ============================================================
   join.css — D7 login page styles
   ============================================================ */

/* ── Full-page centering ── */
html, body {
  height: 100%;
}

.join-wrap {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px 20px;
  background: var(--primary-deep);
}

/* ── Card ── */
.join-card {
  background: var(--card);
  border-radius: 22px;
  box-shadow: 0 12px 40px rgba(0,0,0,0.25);
  padding: 26px 20px;   /* UIV-09：画板 26 / 20（原 28 22 26） */
  width: 100%;
  max-width: 400px;
}

/* ── Brand ── */
.join-brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin-bottom: 26px;
}
.join-leaf {
  width: 56px; height: 56px; border-radius: 18px;
  background: var(--primary-light); color: var(--primary-deep);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 14px;
}

.join-logo {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 800;
  color: #fff;
  letter-spacing: -0.3px;
}

.join-school {
  font-size: 13px;
  font-weight: 500;
  color: #A9C4AC;
  margin-top: 4px;
}

/* ── Steps ── */
.join-step {
  display: none;
}

.join-step.active {
  display: block;
}

/* ── Typography ── */
.join-title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  text-align: center;
  margin-bottom: 6px;
}

.join-hint {
  font-size: 13px;
  color: var(--text-secondary);
  text-align: center;
  margin-bottom: 20px;
}

/* ── Inputs ── */
.join-input {
  width: 100%;
  padding: 13px 14px;
  border: 1.5px solid var(--border);
  border-radius: 12px;
  font-size: 16px;
  color: var(--text);
  background: #fff;
  outline: none;
  margin-bottom: 12px;
  transition: border-color 0.15s;
  -webkit-appearance: none;
}

.join-input:focus {
  border-color: var(--primary);
}

/* UIV-09 C-ph：原来写死 #B0B8C1，压白 2.01 不过线；画板没画这一屏，按全站次级字（5.17） */
.join-input::placeholder {
  color: var(--text-secondary);
}

/* ── OTP row ── */
.otp-row {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-bottom: 20px;
}

.otp-box {
  width: 44px;
  height: 52px;
  border: 1.5px solid var(--border);
  border-radius: 12px;
  font-size: 20px;   /* UIV-09：画板 20（原 22） */
  font-weight: 700;
  text-align: center;
  color: var(--text);
  background: #fff;
  outline: none;
  transition: border-color 0.15s;
  -webkit-appearance: none;
}

.otp-box:focus {
  border-color: var(--accent);
  border-width: 2px;
  background: #fff;
}
.otp-box:not(:placeholder-shown) {
  border-color: var(--primary);
  background: #F6F9F4;
}

@media (max-width: 360px) {
  /* 原来是 38×46：**宽掉到 44 以下，而这是她必须点六次的东西**。
     360 的可用宽度 = 360 - 2×20（页面内边距）= 320；6×44 + 5×4 = 284，放得下。
     所以不是「小屏放不下」，是间隔可以再紧一点。 */
  .otp-box { width: 44px; height: 46px; font-size: 20px; }
  .otp-row { gap: 4px; }
}

/* ── Primary button ── */
.join-btn {
  width: 100%;
  padding: 15px;
  background: var(--primary);
  color: #fff;
  border: none;
  /* 主行动的圆角走 token（T103 / UX-006 ②）。**这不是审美选择，是让它只有一个来源** ——
     改之前全站主按钮 4 种圆角，而四种不是四个人各写各的，是没有一处可引用的必然结果。 */
  border-radius: var(--radius-btn);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  margin-bottom: 16px;
  transition: background 0.15s, opacity 0.15s;
  -webkit-appearance: none;
}

.join-btn:hover { background: #22371F; }
.join-btn:active { background: #1a2b18; }
.join-btn:disabled,
.join-btn.loading {
  opacity: 0.55;
  cursor: not-allowed;
}

/* ── Alt actions ── */
.join-alt {
  /* 两颗文字按钮撑到 44 之后，居中的行内布局会让它们的命中区互相贴着 ——
     **并排的小目标点错的代价是跳去另一件事**（Resend 变成 Change number）。
     用 flex 摆正，中间留出间隔。 */
  display: flex; align-items: center; justify-content: center; gap: 2px;
  font-size: 14px;
  color: var(--text-secondary);
}

.join-link {
  color: var(--primary);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--link-underline);
  font-weight: 600;
}
/* 实测命中区 16.3px。**它是这一屏上唯一一条「先不登录也能看看」的出路**，
   而 16px 高的目标在手机上基本按不中。字号与颜色不动。 */
.join-wrap > .join-guest-link {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 12px;
  margin-top: 10px; font-size: 13px; font-weight: 600; color: #A9C4AC; text-decoration: none;
}
.join-wrap > .join-guest-link:hover { color: #fff; }
/* t-271 / S-029 §2：回岔口那一句借「Browse as guest →」那一身（13 / 600 / 44 / padding 0 12），只换两格 ——
   display flex 独立成行（并排会让两个小目标的命中区贴在一起）、字色 --on-dark-soft（压 --primary-deep 9.87；访客链接留 --on-dark-muted 6.06，
   一眼分得出主路与出口）。/teacher 那一条同一身，色值随浅底取 --primary（teacher.css .teacher-cross）。 */
.join-wrap > .join-cross { display: flex; margin-top: 14px; color: var(--on-dark-soft); }

.join-link:hover { text-decoration: underline; }

.join-link-btn {
  /* 实测命中区 16px（Resend · Change number · Use a different address ·
     None of these for now）。**同一屏里的勾选框已经用 <label> 包出了 306×80** ——
     这一屏不是不知道规矩，是漏了「文字按钮」这一类（UX-007 的原话）。
     字号与下划线不动，变的只有接得住手指的那一块。 */
  /* 命中区 44 撑出来、再用负外边距收回版面（T066 的写法）—— 看得见的间距回到画板那一行，
     手指接得住的那一块不变（t-234 F1c）。 */
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 10px; margin: -13px 0;
  background: none;
  border: none;
  color: var(--primary);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  /* UIV-09：下划线常驻（画板 CJoin）—— 原来只在 :hover 出，触屏上摸不到 hover，看不出它能点。
     简写要写在前面：`text-decoration` 会把颜色一起重置。 */
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--link-underline);
}

/* 二孩家庭：多出来的那个输入框由 join.js 复制第一个而来 */
.join-add-child {
  display: block;
  margin: -4px 0 14px;
  font-size: 13px;
}

/* ── Error ── */
.join-error {
  /* t-234 F1c（design 22:04Z 改判 S-003 §12 的后半句）：**空着的槽不占高度**。
     画板上六格 → Verify 是 22，线上被这个空槽和页面级的那个撑到 40。
     报错出现时按钮往下让，是她刚点完那一下的回应（CLS 也把用户操作后的位移排除在外），不是意外位移。 */
  margin-top: 8px;
  min-height: 20px;
  font-size: 13px;
  color: var(--danger);
  text-align: center;
}
/* S-003 §12 / T178 K4′：贴着按钮的报错槽，**有字时**离按钮上沿留 8px、行高 1.4 ——
   两行以上（格式错 2 行 · 被拦 4 行 · 太频繁 3 行）以前底边直接压在按钮顶上。
   `:not(:empty)`：没有报错时零像素变化（按钮位置、槽高 20 都不动）。
   验码那一步的槽是同一种东西，同一条规则。 */
#join-error-phone:not(:empty),
#join-error-otp:not(:empty) { margin-bottom: 8px; line-height: 1.4; }
.join-error:empty { min-height: 0; margin-top: 0; }
/* UIV-09 · 输入验证码这一屏照画板的间距写法：标题、说明都不带下外边距，
   标题 → 说明 6 是说明的上外边距，说明 → 六格 22 是那一行的上外边距（改前 6 / 20，净差 2px）。
   只限这一屏：别的四步画板没画，.join-title / .join-hint 在那几屏照旧。 */
#step-otp .join-title { margin-bottom: 0; }
#step-otp .join-hint { margin: 6px 0 0; }
#step-otp .otp-row { margin: 22px 0; }   /* 画板上下都是 22（原来这一行的下边距是 20） */

/* ── 短信同意 ──────────────────────────────────────────────────────────────
   运营商要求在收号码的那一刻把「会收到什么、多频繁、谁付费、怎么退出」说清楚。
   排版上刻意压得比正文小一号但**不灰到看不清** —— 这是一份她要同意的东西，
   不是页脚免责声明。 */
.join-consent {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 4px 0 10px; cursor: pointer;
  font-size: 13px; line-height: 1.55; color: #3F4A3C; text-align: left;
}
.join-consent input {
  flex-shrink: 0; width: 18px; height: 18px; margin: 1px 0 0; cursor: pointer;
  accent-color: #2C4428;
}
.join-consent-fine {
  margin: 0 0 16px; text-align: left;
  font-size: 11.5px; line-height: 1.6; color: #6B7568;
}
.join-consent-fine p { margin: 0 0 5px; }
.join-consent-fine p:last-child { margin-bottom: 0; }
.join-consent-fine a { color: #2C4428; text-underline-offset: 2px; }
/* 那两条（Terms · Privacy）**不是句子里的链接** —— 它们自己占一行、用「·」隔开，
   也就是两颗并排的导航目标，实测 14.3px。**并排的小目标是两头错**：点得不准，
   而且点错的那一次会跳到另一份文件去。撑到 44 并把它们隔开。
   （句子里的行内链接不适用这条，见 tests/test_frontend_touch_targets.py 末条。） */
.join-consent-fine p:has(> a:only-of-type) a,
.join-legal-links a {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 10px;
}
.join-legal-links { display: flex; align-items: center; justify-content: flex-start; gap: 2px; }
/* 禁用不等于读不清。默认的白字压在浅灰上几乎看不见 —— 而这颗按钮上写的正是
   「同意」那句话，运营商审核员和家长都得读得到它。 */
.join-btn:disabled {
  background: #E4E8E2; color: #5A6457; cursor: not-allowed;
}
.join-btn:disabled:hover { background: #E4E8E2; }

/* ── 两个同意程序（PD-0016）：验证码自成一段，校方通知是可选的第二段 ── */
.join-program {
  margin: -8px 0 14px; text-align: center;
  font-size: 12px; line-height: 1.5; color: #6B7568;
}
.join-program[hidden] { display: none; }
.join-notices {
  margin-top: 22px; padding-top: 16px; border-top: 1px solid #E4E8E2;
}
.join-notices-title {
  font-size: 12px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
  color: #6B7568; margin-bottom: 8px; text-align: left;
}

/* 总闸开着时的说明（T043）：中性提示，不是报错。红色会让家长以为坏了去报修。 */
.join-muted {
  margin-top: 14px; padding: 12px 14px;
  background: #F6F9F4; border: 1px solid #E3E9DF; border-left: 3px solid #2C4428;
  border-radius: 10px; text-align: left;
  font-size: 13px; line-height: 1.55; color: #3F4A3C;
}
.join-muted[hidden] { display: none; }
.join-muted strong { display: block; margin-bottom: 2px; color: #2C4428; }

/* T079：号码不在名册上。**和上面那块共用一套外观是有意的** —— 两者是同一类东西：
   系统没坏，只是这条路此刻走不通，而她需要知道下一步。红色留给「真的出错了」。 */
.join-notice {
  margin-top: 14px; padding: 12px 14px;
  background: #F6F9F4; border: 1px solid #E3E9DF; border-left: 3px solid #2C4428;
  border-radius: 10px; text-align: left;
  font-size: 13px; line-height: 1.55; color: #3F4A3C;
}
.join-notice[hidden] { display: none; }
.join-notice strong { display: block; margin-bottom: 4px; color: #2C4428; }
.join-notice span { display: block; margin-top: 6px; }

/* ── 第一次登录选渠道（T070 / PD-0038）─────────────────────────────────
   「都不要」和「选了什么」在视觉上是平等的两个答案 —— 把它做成一条不起眼的
   小字链接，就等于用版面替她回答。所以它是 .join-alt 里的按钮，不是脚注。 */
.join-ch {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 0; border-bottom: 1px solid var(--border, #E5E7EB);
  cursor: pointer; text-align: left;
}
/* `.join-ch` 是 display:flex —— **hidden 属性拦不住 flex**，不写这一行
   「学校没配 Telegram 就整格不显示」根本不生效，而它不会报错。 */
.join-ch[hidden] { display: none; }
.join-ch input[type="checkbox"] { margin-top: 3px; width: 18px; height: 18px; flex-shrink: 0; }
.join-ch .join-ch-name { display: block; font-size: 15px; font-weight: 600; }
.join-ch .join-ch-desc { display: block; font-size: 12px; color: var(--text-secondary, #67705F); line-height: 1.45; margin-top: 2px; }
.join-ch input:disabled ~ span .join-ch-name { opacity: 0.55; }

/* 同意确认层（T067）。它挡在视线里，而且必须能退回去 —— 关掉 / 取消 = 什么都不写。 */
.join-modal {
  position: fixed; inset: 0; z-index: 1200; display: flex;
  align-items: center; justify-content: center; padding: 20px;
  background: rgba(0,0,0,0.45);
}
.join-modal[hidden] { display: none; }
.join-modal-card {
  background: #fff; border-radius: 16px; padding: 20px;
  width: 100%; max-width: 380px; max-height: 88vh; overflow-y: auto; text-align: left;
}
.join-modal-card h3 { font-size: 17px; font-weight: 700; margin-bottom: 10px; }
.join-modal-list { margin: 0 0 12px; padding-left: 18px; font-size: 14px; line-height: 1.6; }
.join-modal-note { font-size: 12px; color: var(--text-secondary, #67705F); line-height: 1.5; margin-bottom: 8px; }

.join-guest-link[hidden] { display: none; }

/* ── T071：落地那一刻的介绍 ──
   她是被一条短信带进来的，手指已经在往输入框去了。所以上面这一段
   **只回答「这是哪儿 / 你为什么在这儿」**，字号克制、行数固定；
   「能干什么」那一段放在按钮下面，愿意看的人往下就看得到。
   两段都在 `#step-phone` 里面 —— 验完码它们自己退场。 */
.join-intro {
  margin-bottom: 18px;
  padding-bottom: 16px;
  border-bottom: 1px solid #E4E8E2;
  text-align: center;
}
.join-intro-title {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
  margin: 0 0 8px;
}
.join-intro-lead {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 0;
}

.join-intro-more {
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid #E4E8E2;
  text-align: left;
}
.join-intro-more-title {
  font-size: 12px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
  color: #6B7568; margin-bottom: 8px;
}
.join-intro-list {
  margin: 0; padding-left: 18px;
  font-size: 13px; line-height: 1.5; color: var(--text-secondary);
}
.join-intro-list li { margin-bottom: 5px; }
.join-intro-list li:last-child { margin-bottom: 0; }

/* ⑤ 单独一块：它是她「为什么值得注册」的那句话，不该混在清单里读过去 */
.join-intro-choose {
  margin: 12px 0 0;
  padding: 10px 12px;
  background: #F6F9F4;
  border: 1px solid #E3E9DF;
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}

/* 矮屏（iPhone SE 一类 667px）上，品牌区和介绍各让出一点，
   **好让手机号输入框仍然不用滚动就能看见** —— 那是这一屏的成败判据。 */
@media (max-height: 700px) {
  .join-brand { margin-bottom: 16px; }
  .join-leaf { width: 44px; height: 44px; border-radius: 14px; margin-bottom: 10px; }
  .join-intro { margin-bottom: 14px; padding-bottom: 12px; }
  .join-intro-title { font-size: 17px; }
}

/* ── T083 ②：名册上已有的邮箱 ── */
.join-ch-sub {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 2px 0 10px 28px;      /* 28px = 勾选框宽度 + gap，和上面那行对齐 */
  font-size: 13px;
}
.join-ch-sub[hidden] { display: none; }
.join-ch-known-addr { color: var(--text, #2A2F27); font-weight: 600; word-break: break-all; }

/* ── T083 ①：还差一步的那一屏 ──
   这张「图」用的是首页真实的那个图标和设置页真实的词条 —— 另画一套迟早对不上，
   而对不上的指路比不指路更糟。 */
.join-map {
  margin: 18px 0 0; padding-left: 20px; text-align: left;
  font-size: 13px; line-height: 1.5; color: var(--text-secondary, #67705F);
}
.join-map > li { margin-bottom: 14px; }
.join-map > li:last-child { margin-bottom: 0; }
.join-map-step { display: block; }
.join-map-shot { display: block; margin-top: 8px; }
.join-map-bar {
  display: flex; align-items: center; justify-content: space-between;
  background: #2C4428; color: #fff; border-radius: 10px; padding: 10px 12px;
}
.join-map-bar-title { font-weight: 800; font-size: 14px; }
.join-map-bar-icon {
  display: inline-flex; padding: 4px; border-radius: 8px;
  background: rgba(255,255,255,0.18); outline: 2px solid #F2B705; outline-offset: 2px;
}
.join-map-card {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: #F6F9F4; border: 1px solid #E3E9DF; border-radius: 10px; padding: 10px 12px;
}
.join-map-card-title { font-weight: 700; color: #2C4428; }
.join-map-card-btn {
  background: #2C4428; color: #fff; border-radius: 8px;
  padding: 6px 10px; font-size: 12px; font-weight: 600;
  outline: 2px solid #F2B705; outline-offset: 2px;
}

/* T127 · S-003 §11：她被运营商拦下时那一屏的**呈现**（动作一个没改）。 */

/* ② 号码上方那一行身份 —— 她自己的号码与学校号常常同区号，
   光一串数字分不出这是「谁」。 */
.join-blocked-who {
  margin: 14px 0 -4px; font-size: 12px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-secondary);
}

/* ③ 「Text me my code」在这一状态下降为次级：她此刻按它没用（还没发 START），
   屏幕的视觉重心不该压在一个会失败的动作上。**可点性一点没变。** */
.join-btn.is-secondary {
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
}

/* ── T149 / PD-0066 v2：三档 × 三渠道 ──────────────────────────────────
   每档一个 fieldset、legend 是档名 —— 屏幕阅读器先听到档名再听到渠道。
   三格**横排**而不是九行竖列：九行会把 Save 推到两屏之外，而她是在注册途中。 */
.join-lv {
  border: none; margin: 0 0 18px; padding: 0;
}
.join-lv-name {
  padding: 0; font-size: 15px; font-weight: 700; color: var(--text);
}
.join-lv-desc {
  margin: 2px 0 8px; font-size: 13px; line-height: 1.45; color: var(--text-secondary);
}
.join-chips { display: flex; gap: 8px; flex-wrap: wrap; }
/* 闸 1：命中区 ≥44。chip 是复选，整块可点。 */
.join-chip {
  flex: 1 1 auto; min-height: 44px; display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; border: 1.5px solid var(--border); border-radius: 999px;
  background: var(--card); font-size: 13px; font-weight: 600; color: var(--text);
  cursor: pointer;
}
/* --focus-ring 是一个 box-shadow 值（shared.css:57），不是 outline 值 ——
   写成 outline 那一行整条无效，而**无效的焦点环和没有焦点环长得一模一样**。 */
.join-chip:focus-within { box-shadow: var(--focus-ring); }
/* J1：九个勾选框此前没设 accent-color —— 勾上是**浏览器默认的蓝**，
   而这一屏别处（同意那颗）是绿的。同一屏两种强调色，其中一种还不是这个产品的。
   用 token，不写死：这一屏隔壁那颗至今写着 `#2C4428`，**和 --primary(#2E5937)
   并不是同一个值** —— 那正是写死值会悄悄分家的样子（不在本单范围，已报）。 */
.join-chip input { margin: 0; accent-color: var(--primary); }
.join-chip[hidden] { display: none; }
/* 灰态：**不是只调淡颜色** —— 那句为什么由 aria-describedby 指着（见 #ch-sms-locked）。
   闸 8：灰态文字仍要 ≥3.0，所以用 --text-secondary 不用更浅的。 */
.join-chip.is-locked {
  background: var(--bg); color: var(--text-secondary); cursor: not-allowed;
}
.join-chip.is-locked input { cursor: not-allowed; }
/* J2 / S-007 §1③：**禁用的是那个控件，不是那句告诉她怎么解开的话。**
   这一格里唯一要读的就是它 —— 它跟着变灰，等于把出路一起灭掉。
   `--text`（13.90，改前 --text-secondary 5.17），**400 不加粗**：
   它要**可读**，不是要**最重**。 */
.join-ch-locked {
  margin: -8px 0 16px; font-size: 12.5px; line-height: 1.45;
  color: var(--text); font-weight: 400;
}
/* PD-0069：她自己的同意还在 —— 与上面那句同一个排法、同一个可读度 */
.join-ch-kept {
  margin: -8px 0 16px; font-size: 12.5px; line-height: 1.45;
  color: var(--text); font-weight: 400;
}
/* 确认层里唯一会关掉东西的那一句：加粗，不换色 —— 它是要她读到，不是报错 */
.join-modal-sms-off { font-weight: 700; color: var(--text); }
.join-ch-tg {
  margin: 0 0 14px; font-size: 12.5px; line-height: 1.45; color: var(--text-secondary);
}
