/* ============================================================
   波特云 · 登录页
   整页一个背景主图 + 右侧悬浮登录卡(账号密码 / 短信验证码 Tab,
   下方常驻微信扫码)。全屏、自适应。

   素材全部来自本目录 images/:
     login-bg.jpg   整页背景(纯蓝色渐变 + 水波纹,无插画)
     login-ct.png   左栏插画(透明抠图,波特云立体标,无背景)
     user.svg       账号类输入框图标(#999999,20×20)
     password.svg   密码输入框图标(#999999,20×20)
     qr.svg         二维码占位(点阵画的,扫不出东西 —— 见下方说明)

   二维码为什么是占位的:原型没有后端,真二维码也换不来登录态。
   生成脚本沿用 assets/js/ui/login.js 里 qrPoints 的路子(三个定位角 +
   校正图形 + 定时图形 + 固定种子伪随机点),不引二维码库,双击 file:// 就能开。
   接后端时把 .qr__img 的 src 换成接口返回的二维码图片即可。

   配色取自平台变量 assets/css/tokens.css,不另造色。
   ============================================================ */

:root {
  /* --- 品牌 --- */
  --brand:      #1a6fd4;   /* Tab 选中、注册按钮文字、扫码文案。白底 4.92:1 */
  --brand-lite: #1f8ce6;   /* 主按钮渐变起 */
  --brand-deep: #1466d6;   /* 主按钮渐变尾 */
  --brand-ring: rgba(26, 111, 212, .22);

  /* --- 墨(对比度按白底核算)--- */
  --ink:    #1b2a3a;   /* 输入值  14.59:1 */
  --ink-2:  #5b6b7c;   /* 忘记密码  5.47:1 */
  --ink-3:  #8b97a6;   /* 2.97:1 —— 只许发丝线与装饰,不用于文字 */
  --ph-ink: #65717e;   /* 占位符  4.85:1 */
  --dim-ink:#6b7683;   /* 分割线文字  4.62:1 */
  --icon:   #7b8794;   /* 功能图标(眼睛)  3.69:1 —— 非文字,过 3:1 */

  /* --- 面 --- */
  --card:  #ffffff;
  --sunk:  #fafbfd;    /* 输入框底 */
  --rule:  #e6ebf2;    /* 发丝线 */
  --line:  #e3e9f1;    /* 输入框描边 */

  --crit: #d03b3b;
  --crit-ring: rgba(208, 59, 59, .20);

  --foot-ink: #666666;   /* 页脚版权与备案 —— 按设计指定值 */

  /* 卡面投影:按设计指定 #49AFF8 / 20%。
     两层几何保持原样(外层扩散 + 贴边收口),只换颜色。
     底色是浅蓝,蓝投影会偏"光晕"而不是"压暗"。 */
  --shadow-card: 0 24px 60px -24px rgba(73, 175, 248, .20),
                 0 2px 8px rgba(73, 175, 248, .20);
  --shadow-field: inset 0 1px 2px rgba(16, 50, 92, .04);

  --ease: cubic-bezier(.2, .7, .3, 1);
}

/* ---------- 基础 ---------- */

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

html, body { height: 100%; }

body {
  margin: 0;
  /* 系统中文黑体栈,不引外链 —— 双击 file:// 就能开 */
  font-family: "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB",
               "Source Han Sans SC", "Noto Sans CJK SC", system-ui, sans-serif;
  color: var(--ink);
  background: #dbebfd;              /* 主图加载前的兜底底色,取自主图右侧留白 */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* 只给读屏用,视觉上不占位 */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- 全屏舞台 ---------- */

.stage {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;               /* 移动端地址栏收起时不跳高 */
  display: flex;
  flex-direction: column;
  /* 背景是纯渐变 + 水波纹,没有主体,居中裁切即可 */
  background: #dbebfd url("images/login-bg.jpg") center / cover no-repeat;
}

/* 主区:吃掉页脚以上的全部高度。
   左插画 + 右登录卡,整行居中 —— 超宽屏下两栏才不会被拉到屏幕两端、中间空一大片。 */
.stage__main {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(24px, 4vw, 72px);
  /* 竖向留白压到 4vh:1366×768 这一档才放得下(实测过,见交接说明) */
  padding: clamp(20px, 4vh, 48px) clamp(20px, 5vw, 80px);
}

/* 左栏插画:可缩不可涨,上限 640 */
.hero {
  position: relative;               /* 波浪条是定位元素,静态的插画会被它盖住 */
  z-index: 1;
  flex: 0 1 640px;
  min-width: 0;
  display: flex;
  flex-direction: column;           /* 插画在上、宣传语在下 */
  align-items: center;
  justify-content: center;
  animation: rise-in .5s var(--ease) both;
}

.hero__art {
  display: block;
  width: 100%;
  height: auto;
}

/* 宣传语:紧跟在插画下面,宽度跟插画一致,所以和插画同比例缩放。
   放在图外而不是叠在图上 —— 底座轮廓最低点已经到 y=646(图高 690),图内挤不下 */
.hero__slogan {
  display: block;
  width: 100%;
  height: auto;
  /* 累计上移 70px(-90 回退 20)。这个落点上文字顶仍在底座轮廓线上方一点,
     但压得比 -90 时浅,见交接说明里量出来的重叠量 */
  margin-top: -70px;
}

/* SVG 里的文字不继承页面的 font-family,必须显式写一遍。
   字号 36 是 viewBox 单位:插画按 640px 渲染时约 21.9px。
   颜色走 <linearGradient>(写在 HTML 的 <defs> 里,用 fill 属性引用),这里只管字体。
   投影已按要求去掉。 */
.hero__slogan-text {
  font-family: "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB",
               "Source Han Sans SC", "Noto Sans CJK SC", system-ui, sans-serif;
  font-size: 36px;
  font-weight: 700;
  letter-spacing: 1px;
}

/* 轻蒙层:把主图往后退一档,衬托卡面 */
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg,
              rgba(226, 238, 253, 0) 45%,
              rgba(226, 238, 253, .55) 100%);
}

/* ---------- 登录卡 ---------- */

.login {
  position: relative;
  z-index: 1;
  flex: none;
  width: min(430px, 100%);
  padding: 26px 40px 22px;          /* 比原来各收 2px,抵掉提示占位增高的一部分 */
  border-radius: 16px;
  background: var(--card);
  box-shadow: var(--shadow-card);
  animation: rise-in .5s var(--ease) both;
}

/* 全页唯一一处入场动效:插画和登录卡一起浮上来,只演一次 */
@keyframes rise-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Tab ---------- */

.tabs {
  display: flex;
  border-bottom: 1px solid var(--rule);
}

.tab {
  position: relative;
  flex: 1 1 0;
  padding: 0 0 14px;
  border: 0;
  border-radius: 4px;
  background: none;
  font: inherit;
  font-size: 16px;
  color: var(--ink-2);
  cursor: pointer;
  transition: color .18s var(--ease);
}

.tab:hover { color: var(--brand); }

.tab[aria-selected="true"] {
  color: var(--brand);
  font-weight: 600;
}

/* 压在容器那根 1px 线上 */
.tab[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 3px;
  border-radius: 2px 2px 0 0;
  background: var(--brand);
}

.tab:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* ---------- 表单与面板 ---------- */

.login__form { margin-top: 20px; }

.panel[hidden] { display: none; }

/* ---------- 输入框 ---------- */

/* 字段间距 = 占位槽(4+14.4) + 这里 6px ≈ 24.4px。
   之前是 0(总间距只有 16.4px),提示词一出来贴着上下两个输入框,太挤。 */
.field + .field { margin-top: 6px; }

.field__box {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 48px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--sunk);
  box-shadow: var(--shadow-field);
  transition: border-color .18s var(--ease),
              box-shadow   .18s var(--ease),
              background-color .18s var(--ease);
}

.field__box:hover { border-color: #c3d2e6; }

.field__box:focus-within {
  border-color: var(--brand);
  background: #fff;
  box-shadow: 0 0 0 3px var(--brand-ring);
}

.field__icon {
  flex: none;
  display: block;
  width: 20px;
  height: 20px;
}

.field__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
}

.field__input::placeholder { color: var(--ph-ink); }

/* 隐藏 Edge/IE 自带的密码显示按钮,避免与自定义眼睛图标重复出现 */
input[type="password"]::-ms-reveal { display: none; }

/* 覆盖浏览器自动填充的浅蓝色背景,保持与普通输入框一致 */
.field__input:-webkit-autofill,
.field__input:-webkit-autofill:hover,
.field__input:-webkit-autofill:focus,
.field__input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--ink);
  caret-color: var(--ink);
  transition: background-color 600000s 0s, color 600000s 0s;
}

/* 自动填充时用内阴影覆盖浏览器默认底色,与输入框容器同色 */
.field__input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px var(--sunk) inset;
}
.field__box:focus-within .field__input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px #fff inset;
}

/* 密码框右侧:眼睛 + 忘记密码 */
.icon-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--icon);
  cursor: pointer;
  transition: color .15s var(--ease);
}

.icon-btn:hover { color: var(--ink-2); }

.icon-btn:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* 密码隐藏时补一道斜杠(表示不可见);密码可见时只画眼睛 */
.icon-btn .eye-slash { display: block; }
.icon-btn.is-on .eye-slash { display: none; }

.field__link {
  flex: none;
  border-radius: 4px;
  font-size: 14px;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
  transition: color .15s var(--ease);
}

.field__link:hover { color: var(--brand); }

.field__link:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* 短信面板右侧的获取验证码 */
.code-btn {
  flex: none;
  padding: 0 0 0 12px;
  border: 0;
  border-left: 1px solid var(--rule);
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--brand);
  white-space: nowrap;
  cursor: pointer;
  transition: color .15s var(--ease);
}

.code-btn:hover:not(:disabled) { color: var(--brand-deep); }

.code-btn:disabled {
  color: var(--ink-3);
  cursor: default;
}

.code-btn:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* 校验失败:颜色只是第二通道,文字才是主通道 */
/* 校验提示:常驻占位 —— 不管有没有报错都占住一行,提示出现时登录框不跳高。
   槽高 = 4px + 12×1.2 ≈ 18.4px;它和 .field + .field 的 6px 合起来构成字段间距。
   上面留 4px 是为了提示词别贴着输入框下边。 */
.field__err {
  margin: 4px 0 0 2px;
  font-size: 12px;
  line-height: 1.2;
  color: var(--crit);
}

/* 覆盖 UA 的 [hidden]{display:none}:仍然占位,但不显示、也不进无障碍树,
   所以没报错时读屏不会念这些文案 */
.field__err[hidden] {
  display: block;
  visibility: hidden;
}

.field.is-invalid .field__box {
  border-color: var(--crit);
  background: #fff;
}

.field.is-invalid .field__box:focus-within {
  box-shadow: 0 0 0 3px var(--crit-ring);
}

/* ---------- 按钮 ---------- */

.btn {
  display: block;
  width: 100%;
  height: 50px;
  border-radius: 8px;
  font: inherit;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 1px;
  cursor: pointer;
  transition: filter .18s var(--ease),
              background-color .18s var(--ease),
              border-color .18s var(--ease),
              box-shadow .18s var(--ease),
              transform .14s var(--ease);
}

.btn--primary {
  /* 从 22 收到 18,补掉字段间距拉大带来的增高 */
  margin-top: 18px;
  border: 0;
  background: linear-gradient(135deg, var(--brand-lite) 0%, var(--brand-deep) 100%);
  color: #fff;
  box-shadow: 0 8px 20px -8px rgba(20, 102, 214, .55);
}

.btn--primary:hover {
  filter: brightness(1.06);
  box-shadow: 0 10px 24px -8px rgba(20, 102, 214, .62);
}

.btn--ghost {
  margin-top: 14px;
  border: 1px solid #dbe4f6;
  background: #eef2fb;
  color: var(--brand-deep);
}

.btn--ghost:hover {
  border-color: #cbdcf5;
  background: #e5ecf9;
}

.btn:active { transform: translateY(1px); }

.btn:focus-visible {
  outline: 2px solid var(--brand-deep);
  outline-offset: 2px;
}

/* ---------- 其他登录方式 ---------- */

.divider {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 18px 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--dim-ink);
}

.divider::before,
.divider::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--rule);
}

/* ---------- 微信扫码 ---------- */

.qr {
  margin-top: 17px;
  text-align: center;
}

.qr__box {
  display: inline-flex;
  padding: 10px;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: #fff;
}

.qr__img {
  display: block;
  width: 144px;
  height: 144px;
}

.qr__cap {
  margin: 14px 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--brand);
}

/* ---------- 整页页脚:版权 + 备案 ---------- */

.page-foot {
  position: relative;                  /* 压在蒙层之上 */
  z-index: 1;
  padding: 0 20px calc(18px + env(safe-area-inset-bottom, 0px));
  font-size: 12px;
  line-height: 1.6;
  color: var(--foot-ink);
  /* #666 对浅蓝底 5.12:1,已过 4.5:1;白描边只用来压住底图的水波纹 */
  text-shadow: 0 1px 2px rgba(255, 255, 255, .65);
}

/* 每行两段,窄屏时各自换行仍居中 */
.page-foot__line {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px 28px;
}

.page-foot__line + .page-foot__line { margin-top: 4px; }

/* ---------- 页面底部波浪条 ---------- */

.page-wave {
  position: absolute;               /* 不占布局高度,所以不会顶出滚动条 */
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;                       /* 版权文字、登录卡都是 z-index:1,压在它上面 */
  height: 214.5px;                 /* = bg-footer.png 原始高度的一半,整图等比缩到 50% */
  overflow: hidden;                 /* 轨道 4 份共 10432px,不裁会撑出横向滚动条 */
  opacity: .3;
  pointer-events: none;
}

.page-wave__track {
  display: flex;
  height: 100%;
  /* 必须按内容撑开。块级默认宽度 = 容器宽,那样 translateX 的百分比会按容器算,
     平移量就对不上一对图的宽度,循环处会跳。 */
  width: max-content;
  /* 4 份 = 2 对,一对是整个循环单元,所以平移 50%(= 2 份)正好接上。
     改份数必须同步改这个百分比:平移量 = 2 / 份数 */
  animation: wave-scroll 80s linear infinite;
}

.page-wave__img {
  flex: none;
  display: block;
  height: 100%;
  width: auto;                      /* 高度撑满 429px,宽度按原比例 = 2608px,不缩放 */
}

/* 镜像那一半。接缝处波形和明暗都连续,所以看不出接头 */
.page-wave__img--flip { transform: scaleX(-1); }

@keyframes wave-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ---------- 宣传语的可读下限 ----------
   标语和插画同比例缩放,所以只在插画够宽时才显示。1150px 视口时插画约 560px 宽、
   标语约 19px,刚好跨过 WCAG「大字」门槛(粗体 14pt = 18.66px);
   再窄就掉成普通字号,而渐变亮端只有 3.3:1,达不到普通字号要的 4.5:1,所以收掉。 */

@media (max-width: 1150px) {
  .hero__slogan { display: none; }
}

/* ---------- 窄屏:卡居中,主图退为底纹 ---------- */

@media (max-width: 900px) {
  /* 窄屏放不下两栏:收起插画,只留居中的登录卡 —— 主图本身已经够看 */
  .hero { display: none; }

  .stage__main {
    justify-content: center;
    padding: 32px 20px;
  }

  /* 竖屏下主图被裁到中间,蒙层改垂直方向压暗 */
  .stage::before {
    background: linear-gradient(180deg,
                rgba(226, 238, 253, .40) 0%,
                rgba(226, 238, 253, .68) 100%);
  }

  /* 聚焦不触发 iOS 自动放大 */
  .field__input { font-size: 16px; }
}

@media (max-width: 520px) {
  .login { padding: 28px 22px 24px; }
  .tab { font-size: 15px; }
  .btn { font-size: 16px; }
  .qr__img { width: 132px; height: 132px; }
}

/* ---------- 矮视口:整卡收一档,保住"一屏放得下" ----------
   1366×768 在 4vh 留白下刚好等于视口高、零余量,字体渲染差 1px 就会出滚动条,
   所以 780 及以下整体换成紧凑排版;1280×720 / 1024×700 也靠这一档兜住。 */

@media (max-height: 780px) {
  .login { padding: 20px 40px 16px; }
  .login__form { margin-top: 20px; }
  .divider { margin-top: 14px; }
  .qr { margin-top: 14px; }
  .qr__img { width: 112px; height: 112px; }
}

/* 更矮(横屏手机等):卡顶到上边,放不下就让它纵向滚 */
@media (max-height: 620px) {
  .stage__main {
    align-items: flex-start;
    padding-top: 24px;
    padding-bottom: 24px;
  }
}

/* ---------- 减少动效 ---------- */

@media (prefers-reduced-motion: reduce) {
  .login,
  .hero,
  .page-wave__track { animation: none; }
  .tab,
  .field__box,
  .icon-btn,
  .field__link,
  .code-btn,
  .btn { transition: none; }
  .btn:active { transform: none; }
}
