/* ==========================================================================
   登录页视觉
   --------------------------------------------------------------------------
   前台（/login，飞书扫码）和后台（/admin/login，账号密码）共用这一套：
   同样的背景、文案排版、玻璃卡片，只有卡片内的表单不同。
   抽成独立文件是为了改一次两边同时生效，不必维护两份。
   ========================================================================== */

/* ==================================================================
           登录页
           布局：≥1024px 左右分栏（左文案 / 右卡片），窄屏堆叠居中
           缩放：字号间距全用 rem，跟随 tokens.css 的根字号断点，1K→4K 通吃
           ================================================================== */

        /* ------------------------------------------------------------------
           尺寸系统：单一基准单位 --u 驱动整页
           ------------------------------------------------------------------
           设计稿 1672×941（16:9），卡片宽 535px、右边距 172px、文案左边距 430px。
           把稿中每个尺寸都换算成 u 的倍数，页面上只写倍数，比例就被永久锁死，
           换任何分辨率都不走形。

           u 取 min(vw份额, vh份额)。设计稿与主流屏幕同为 16:9，
           所以在 16:9 上两个份额相等，其他比例下取较小者，保证既不横向溢出也不顶边。

           ⚠ 不要在这里混用 rem 做 clamp 上限：大屏上 rem 上限会先撞顶，
             vw/vh 随即失效，比例崩坏（4K 下卡片宽高比会从 0.81 变成 0.95）。
           ------------------------------------------------------------------ */
        :root {
            /* 背景图。文件缺失时下层渐变兜底，不会白屏 */
            /* 照片用 JPEG：同样画质下体积只有 PNG 的十分之一（1.5MB → 136KB）。
               换图后跑 scripts/optimize_images.py 重新压一遍即可。 */
            --login-bg: url('/static/images/login-bg.jpg');

            --u: min(1.143vw, 2.032vh);

            /* 卡片专用单位。整张卡片（含内部所有元素）按这个比例缩放，
               只调这一个数就能整体放大缩小，内部比例不会走形。 */
            --cu: calc(var(--u) * 0.86);

            --card-w: calc(var(--cu) * 28);     /* 稿中卡片宽 = 28 个单位 */
            --edge-right: calc(var(--u) * 9);   /* 稿中 172px = 10.3% */
            --hero-gap: calc(var(--u) * 7.1);   /* 稿中 135px */
        }

        html, body {
            height: 100%;
        }

        body {
            overflow: hidden;
        }

        .login-page {
            position: relative;
            min-height: 100vh;
            min-height: 100dvh;
            display: flex;
            align-items: center;
            overflow: hidden;
        }

        /* ---------- 背景层 ---------- */
        .login-bg {
            position: absolute;
            inset: 0;
            background-image: var(--login-bg),
                              linear-gradient(115deg,
                                  #DCEBD8 0%,
                                  #EAF3E4 22%,
                                  #F4F7F0 48%,
                                  #FAFBF7 70%,
                                  #F2F5EE 100%);
            background-size: cover;
            background-position: center center;
            background-repeat: no-repeat;
            z-index: 0;
        }

        /* 右侧压一层柔光，保证卡片下方始终有干净的浅色底，
           不管背景图换成什么构图，卡片上的文字都读得清 */
        .login-bg::after {
            content: '';
            position: absolute;
            inset: 0;
            background: linear-gradient(100deg,
                        rgba(255, 255, 255, 0) 30%,
                        rgba(255, 255, 255, 0.30) 58%,
                        rgba(255, 255, 255, 0.55) 100%);
        }

        /* ---------- 内容容器 ---------- */
        /* 内容整体靠右：背景图左侧的绿植和杯子要露出来，
           所以左边距远大于右边距，不是简单的居中。 */
        .login-content {
            position: relative;
            z-index: var(--z-base);
            width: 100%;
            padding: calc(var(--u) * 2) var(--edge-right) calc(var(--u) * 2) calc(var(--u) * 1.5);
            display: flex;
            align-items: center;
            justify-content: flex-end;
            gap: var(--hero-gap);
        }

        /* ---------- 左侧文案 ---------- */
        .login-hero {
            flex: 0 1 auto;
            animation: rise 0.7s var(--ease) both;
        }

        .hero-title {
            margin: 0;
            font-family: var(--font-hand);
            font-size: calc(var(--u) * 3.35);   /* 稿中 67px */
            font-weight: var(--fw-bold);
            line-height: 1.28;
            letter-spacing: 0.04em;
            color: var(--green-700);
            text-shadow: 0 2px 12px rgba(255, 255, 255, 0.7);
            white-space: nowrap;
        }

        /* 标题下的手绘弧线：中间下凹、右端上扬收笔，
           用 SVG 才有手写的那一笔感觉，直线条做不出来 */
        .hero-underline {
            width: calc(var(--u) * 14.5);            /* 稿中 290px */
            height: auto;
            margin: calc(var(--u) * 0.4) 0 calc(var(--u) * 2.6);
            margin-left: calc(var(--u) * 1.75);      /* 起笔从"从"字右侧开始，对齐设计稿 */
            display: block;
            overflow: visible;
        }

        .hero-underline path {
            stroke-dasharray: 320;
            stroke-dashoffset: 320;
            animation: draw-stroke 1.1s 0.35s var(--ease) forwards;
        }

        .hero-tags {
            margin: 0;
            font-size: calc(var(--u) * 1.2);    /* 稿中 24px */
            font-weight: var(--fw-medium);
            letter-spacing: 0.42em;
            margin-right: -0.42em;
            color: var(--green-600);
            text-shadow: 0 1px 8px rgba(255, 255, 255, 0.8);
            white-space: nowrap;
        }

        /* ---------- 右侧玻璃卡片 ---------- */
        /* 卡片内各元素尺寸按设计稿对 560px 卡片宽归一化后换算，
           所以统统用 vw + clamp，缩放时卡片内部比例始终不变。 */
        .login-card {
            flex: 0 0 auto;
            width: var(--card-w);
            /* 二维码是固定 260px 的（尺寸不能再压，否则静区不够扫不出），
               卡片必须宽到装得下它 + 两侧内边距，否则窄屏上会被撑破。
               上限 100% 是给手机的，避免卡片反过来超出屏幕。 */
            min-width: min(340px, 100%);
            padding: calc(var(--cu) * 2.4) calc(var(--cu) * 2.5);   /* 稿中 55/50px，扫码版略收 */
            background: rgba(255, 255, 255, 0.78);
            backdrop-filter: blur(26px) saturate(155%);
            -webkit-backdrop-filter: blur(26px) saturate(155%);
            border: 1px solid rgba(255, 255, 255, 0.9);
            border-radius: calc(var(--cu) * 1.4);                  /* 稿中 28px */
            box-shadow: 0 calc(var(--cu) * 1.2) calc(var(--cu) * 3.5) rgba(31, 39, 44, 0.13),
                        0 2px 8px rgba(31, 39, 44, 0.05);
            text-align: center;
            animation: rise 0.7s 0.12s var(--ease) both;
        }

        .card-logo {
            width: calc(var(--cu) * 4);          /* 稿中 90px，扫码版略收 */
            height: calc(var(--cu) * 4);
            margin: 0 auto calc(var(--cu) * 1);
            object-fit: contain;
        }

        /* logo 图片缺失时的 CSS 占位，避免出现破图裂图标 */
        .card-logo-fallback {
            width: calc(var(--cu) * 4);
            height: calc(var(--cu) * 4);
            margin: 0 auto calc(var(--cu) * 1);
            border-radius: calc(var(--cu) * 0.8);
            background: linear-gradient(140deg, var(--brand-blue-light), var(--brand-blue-dark));
            color: #fff;
            font-size: calc(var(--cu) * 2.2);
            font-weight: var(--fw-bold);
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 8px 20px rgba(22, 119, 224, 0.28);
        }

        .card-title {
            margin: 0 0 calc(var(--cu) * 0.6);
            /* 稿中是 2.1（"OA系统"三个字）；换成"FITORY OA 系统"后长了一倍，
               同样字号会顶满卡片宽度显得笨重，收到 1.75 更透气 */
            font-size: calc(var(--cu) * 1.75);
            font-weight: var(--fw-bold);
            color: var(--text-primary);
            letter-spacing: 0.02em;
            white-space: nowrap;
        }

        .card-subtitle {
            margin: 0 0 calc(var(--cu) * 1.2);
            font-size: calc(var(--cu) * 1);      /* 稿中 20px */
            letter-spacing: 0.35em;
            color: var(--text-muted);
            /* 字间距会在右侧多出一格，负边距让整体保持视觉居中 */
            margin-right: -0.35em;
        }

        /* ---------- 扫码区 ---------- */
        /* 扫码区顶掉设计稿里「两个输入框 + 记住我 + 按钮」的整段（共 15u），
           视觉重量与原稿一致，卡片高度也就不会跑偏 */
        /* 加载中还没有 iframe，给个固定占位，避免卡片高度跳动 */
        .qr-frame:not(.is-ready) {
            width: 180px;
            height: 180px;
        }

        .qr-frame {
            position: relative;
            /* ⚠ 二维码绝对不能缩放。
               它靠黑白格子的像素对齐来识别，尤其三个角的定位图案；
               transform: scale() 会让边缘模糊错位，手机直接扫不出来
               （曾经为了"跨屏观感一致"加过 0.83~1.9 倍缩放，结果扫码全废）。
               所以这里 1:1 贴合 SDK 输出的原生尺寸，宁可大屏上显得小一点。 */
            width: fit-content;
            height: fit-content;
            line-height: 0;
            margin: 0 auto calc(var(--cu) * 0.9);
            padding: calc(var(--cu) * 0.3);
            background: #fff;
            border-radius: calc(var(--cu) * 0.7);
            box-shadow: var(--shadow-sm);
            overflow: hidden;
        }

        .qr-frame iframe {
            display: block;
            border: 0;
        }

        /* 扫码区的加载/失败状态 */
        .qr-state {
            position: absolute;
            inset: 0;
            /* 容器高度改为自适应后，二维码还没出来时得有东西撑住，否则会塌成一条 */
            min-height: calc(var(--cu) * 9);
            line-height: 1.6;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: var(--space-3);
            padding: var(--space-4);
            background: #fff;
            border-radius: var(--radius-lg);
            font-size: 0.85rem;
            color: var(--text-secondary);
            line-height: 1.6;
        }

        .spinner {
            width: 1.75rem;
            height: 1.75rem;
            border: 3px solid var(--green-100);
            border-top-color: var(--primary);
            border-radius: 50%;
            animation: spin 0.8s linear infinite;
        }

        .qr-hint {
            margin: 0 0 calc(var(--cu) * 0.9);
            font-size: calc(var(--cu) * 0.9);
            color: var(--text-secondary);
        }

        .qr-hint strong {
            color: var(--green-600);
            font-weight: var(--fw-semibold);
        }

        /* ---------- 表单（秘钥模式）---------- */
        .field {
            position: relative;
            margin-bottom: calc(var(--cu) * 1);
            text-align: left;
        }

        .field-input {
            width: 100%;
            height: calc(var(--cu) * 3.4);       /* 稿中 68px */
            padding: 0 calc(var(--cu) * 2.6);
            font-size: calc(var(--cu) * 1);
            font-family: inherit;
            color: var(--text-primary);
            background: var(--bg-field);
            border: 1.5px solid transparent;
            border-radius: calc(var(--cu) * 0.7);
            outline: none;
            transition: border-color var(--duration) var(--ease),
                        background var(--duration) var(--ease),
                        box-shadow var(--duration) var(--ease);
        }

        .field-input::placeholder {
            color: var(--text-muted);
        }

        .field-input:focus {
            background: #fff;
            border-color: var(--primary);
            box-shadow: 0 0 0 4px rgba(47, 174, 88, 0.12);
        }

        .field-icon {
            position: absolute;
            top: 50%;
            left: calc(var(--cu) * 1);
            transform: translateY(-50%);
            width: calc(var(--cu) * 1.1);
            height: calc(var(--cu) * 1.1);
            color: var(--text-muted);
            pointer-events: none;
        }

        .field-action {
            position: absolute;
            top: 50%;
            right: calc(var(--cu) * 1);
            transform: translateY(-50%);
            width: calc(var(--cu) * 1.1);
            height: calc(var(--cu) * 1.1);
            color: var(--text-muted);
            cursor: pointer;
            background: none;
            border: 0;
            padding: 0;
            transition: color var(--duration-fast) var(--ease);
        }

        .field-action:hover {
            color: var(--primary);
        }

        .btn-primary {
            width: 100%;
            height: calc(var(--cu) * 3.6);       /* 稿中 72px */
            margin-top: calc(var(--cu) * 0.6);
            font-family: inherit;
            font-size: calc(var(--cu) * 1.1);
            font-weight: var(--fw-semibold);
            letter-spacing: 0.3em;
            color: var(--text-inverse);
            background: var(--primary);
            border: 0;
            border-radius: calc(var(--cu) * 0.7);
            cursor: pointer;
            transition: background var(--duration) var(--ease),
                        transform var(--duration) var(--ease),
                        box-shadow var(--duration) var(--ease);
            /* letter-spacing 让文字整体右偏，补回来 */
            text-indent: 0.3em;
        }

        .btn-primary:hover:not(:disabled) {
            background: var(--primary-hover);
            transform: translateY(-1px);
            box-shadow: var(--shadow-primary);
        }

        .btn-primary:active:not(:disabled) {
            transform: translateY(0);
            background: var(--primary-active);
        }

        .btn-primary:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        /* ---------- 模式切换 ---------- */
        .switch-row {
            margin-top: calc(var(--cu) * 0.7);
            padding-top: calc(var(--cu) * 0.7);
            border-top: 1px solid var(--border-color);
        }

        .link-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: calc(var(--cu) * 0.3);
            font-family: inherit;
            font-size: calc(var(--cu) * 0.85);
            color: var(--text-secondary);
            background: none;
            border: 0;
            padding: calc(var(--cu) * 0.3);
            cursor: pointer;
            text-decoration: none;
            transition: color var(--duration-fast) var(--ease);
        }

        .link-btn:hover {
            color: var(--primary);
        }

        .link-btn svg {
            width: calc(var(--cu) * 0.8);
            height: calc(var(--cu) * 0.8);
        }

        /* 飞书账密登录是正式通道，比下面的秘钥降级通道更醒目 */
        .link-primary {
            display: flex;
            color: var(--primary-active);
            font-weight: var(--fw-medium);
        }

        .link-primary + .link-btn {
            display: flex;
            margin-top: calc(var(--cu) * 0.2);
            font-size: calc(var(--cu) * 0.78);
            color: var(--text-muted);
        }

        /* ---------- 错误提示 ---------- */
        .alert {
            display: flex;
            align-items: flex-start;
            gap: calc(var(--cu) * 0.4);
            margin-bottom: calc(var(--cu) * 1);
            padding: calc(var(--cu) * 0.6) calc(var(--cu) * 0.8);
            font-size: calc(var(--cu) * 0.85);
            line-height: 1.6;
            text-align: left;
            color: #A33;
            background: #FDF0F0;
            border: 1px solid #F5D5D5;
            border-radius: calc(var(--cu) * 0.4);
        }

        .alert svg {
            flex: 0 0 auto;
            width: calc(var(--cu) * 0.95);
            height: calc(var(--cu) * 0.95);
            margin-top: calc(var(--cu) * 0.15);
        }

        /* ---------- 卡片页脚：文字两侧带短横线 ---------- */
        .card-footer {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: calc(var(--cu) * 0.6);
            margin-top: calc(var(--cu) * 0.85);
            font-size: calc(var(--cu) * 0.9);    /* 稿中 18px */
            letter-spacing: 0.12em;
            color: var(--text-muted);
        }

        .card-footer::before,
        .card-footer::after {
            content: '';
            width: calc(var(--cu) * 1.5);
            height: 1px;
            background: var(--border-strong);
        }

        /* ---------- 动效 ---------- */
        @keyframes rise {
            from { opacity: 0; transform: translateY(1.5rem); }
            to   { opacity: 1; transform: translateY(0); }
        }

        @keyframes draw-stroke {
            to { stroke-dashoffset: 0; }
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        /* ==================================================================
           响应式
           ================================================================== */

        /* 平板横屏：文案和卡片开始挤，缩小间距换空间 */
        @media (max-width: 1180px) {
            :root {
                --hero-gap: calc(var(--u) * 3);
                --edge-right: calc(var(--u) * 3);
            }
        }

        /* 竖屏平板 / 手机：改为堆叠。
           此时 min(vw,vh) 算出的 u 太小（375px 屏上不到 5px），
           必须换成按屏宽取份额，否则整张卡片会缩成一团。 */
        @media (max-width: 900px) {
            :root {
                --u: clamp(0.6rem, 3.1vw, 1.15rem);
                --card-w: min(100%, calc(var(--u) * 28));
                --hero-gap: calc(var(--u) * 2.5);
                --edge-right: calc(var(--u) * 1.5);
            }

            body { overflow: auto; }

            /* 页脚是 .login-page 的 flex 子项，不改方向的话它会被排到
               内容区右侧，同时把内容挤窄——卡片变小和页脚跑偏是同一个原因 */
            .login-page {
                flex-direction: column;
                align-items: stretch;
                justify-content: flex-start;
                padding: calc(var(--u) * 2) 0;
            }

            .login-content {
                flex-direction: column;
                justify-content: flex-start;
                align-items: center;
                padding: calc(var(--u) * 1.5) var(--edge-right);
            }

            .login-hero { text-align: center; }

            .hero-title { font-size: calc(var(--u) * 2.8); }

            .hero-underline {
                margin-left: auto;
                margin-right: auto;
            }

            .hero-tags {
                font-size: calc(var(--u) * 1);
                letter-spacing: 0.3em;
                margin-right: -0.3em;
            }

            {#- 这里原来按 --u 覆盖过 .qr-frame 的宽高，会把容器压到 163px、
                把二维码连同静区一起裁掉。二维码尺寸由 SDK 固定，
                容器必须始终贴合它，任何断点都不要再覆盖尺寸。 -#}

            /* 窄屏上背景图右侧留白不一定够，整体加白纱保证可读 */
            .login-bg::after {
                background: rgba(255, 255, 255, 0.42);
            }

        }

        /* 超宽屏（21:9 及更宽）：u 由 vh 决定后，两侧会空出大片，
           把右边距按比例放大，让内容回到视觉重心而不是贴着屏幕边 */
        @media (min-aspect-ratio: 2/1) {
            :root {
                --edge-right: calc(var(--u) * 12);
                --hero-gap: calc(var(--u) * 6);
            }
        }

/* 门户标识。从后台入口进来的登录页要标出来，否则两侧是同一张扫码页，
   点完「管理后台」看着像没反应。与 admin/login.html 里的 .admin-badge 同款。 */
.portal-badge {
    display: inline-block;
    margin-bottom: calc(var(--cu) * 0.7);
    padding: calc(var(--cu) * 0.15) calc(var(--cu) * 0.6);
    font-size: calc(var(--cu) * 0.7);
    font-weight: var(--fw-semibold);
    letter-spacing: 0.1em;
    color: var(--primary-active);
    background: var(--primary-soft);
    border: 1px solid var(--primary-border);
    border-radius: var(--radius-pill);
}
