/* ==========================================================================
   로그인 화면 전용 스타일

   원칙 — 색을 직접 쓰지 않고 테마 토큰(css/themes.css)만 참조한다.
   그래야 대시보드에서 고른 테마(signature/slate/harbor/terra/editorial)가
   로그인 화면에도 그대로 적용된다. 특히 우측 패널은 `--brand-gradient` 하나로
   테마 5종을 모두 따라간다.
   ========================================================================== */

.login-body {
    background-color: var(--theme-body-bg);
}

/* Inspinia 의 .auth-box 는 높이를 주지 않는다 → 화면 중앙에 오도록 직접 지정 */
.login-body .auth-box {
    min-height: 100vh;
    padding: 24px 0;
}

.login-card {
    border: 1px solid var(--theme-border-color);
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.1);
}

/* 로고 — 상단바용 .oe-logo 크기 규칙은 .app-topbar/.sidenav-menu 스코프라
   여기서는 적용되지 않는다. 로그인 화면 크기로 따로 정한다. */
.login-logo {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
/* ⚠ 심볼과 글자 비율은 상단바·사이드바 락업(css/dashboard.css 의 .oe-logo-txt)과 맞춘다.
     기준: 글자 잉크 높이 ÷ 심볼 높이 ≒ 0.57.
     로그인 화면은 히어로라 전체를 키우되 **비율은 같게** 둔다
     (예전 값 30px 심볼 + 1.35rem 글자는 한글로 바꾸면서 0.67 이 되어 글자가 더 커 보였다). */
.login-logo .oe-logo-sym {
    height: 32px;
    width: auto;
}
.login-logo .oe-logo-txt {
    font-size: 1.2rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--brand-blue-ui);
}

.login-eye {
    border-color: var(--bs-border-color);
}

/* 자격 저장 옵션 3종 — 좁은 폭에서는 줄바꿈되도록 wrap */
.login-remember {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    margin-top: 4px;
}
.login-remember .form-check {
    margin-bottom: 0;
}
.login-remember .form-check-label {
    font-size: 0.8125rem;
}

/* 비밀번호 저장 경고 — 실제 위험을 알리는 문구이므로 danger 색을 쓴다 */
.login-warn {
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--bs-danger-text-emphasis, #b02a37);
    background-color: var(--bs-danger-bg-subtle);
    border: 1px solid var(--bs-danger-border-subtle);
    border-radius: 8px;
    padding: 8px 10px;
}

/* 비밀번호 보관하지 않는다는 안내 — 경고가 아니라 정보라서 은은하게 */
.login-note {
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--bs-secondary-color);
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--theme-border-color);
    border-radius: 8px;
    padding: 10px 12px;
}

/* ------------------------------------------------------------ 우측 패널 */

.login-side {
    background: var(--brand-gradient);
    color: #fff;
    /* 카드 우측 모서리를 따라가게 — 카드에 overflow:hidden 이 있어 넘침은 잘린다 */
    min-height: 460px;
}

/* 워드마크 원본이 어두운 색이라 그라디언트 위에서는 흰색으로 바꿔 쓴다 */
.login-side-wordmark {
    height: 18px;
    width: auto;
    filter: brightness(0) invert(1);
    opacity: 0.9;
}

.login-side-title {
    font-weight: 700;
    line-height: 1.35;
    color: #fff;
}

.login-side-desc {
    font-size: 0.875rem;
    line-height: 1.7;
    color: rgba(255, 255, 255, 0.85);
    max-width: 32ch;
}

.login-side-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.login-side-list li {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8125rem;
    color: rgba(255, 255, 255, 0.92);
}
.login-side-list i {
    font-size: 1rem;
    color: rgba(255, 255, 255, 0.75);
}

.login-side-foot {
    font-size: 0.6875rem;
    color: rgba(255, 255, 255, 0.7);
}

/* 다크 모드 — 카드 그림자를 낮추고 테두리로 경계를 만든다 */
[data-bs-theme='dark'] .login-card {
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

/* ==========================================================================
   로그인 우측 패널 연출 — 살아 움직이는 미니 대시보드  [LOGIN-STAGE-V1]

   구도: KPI 3개(위) · 막대차트(좌하) · 스파크라인(우하) 이 차례로 나타나며
        숫자가 오르고 막대가 자라고 선이 그려진다.
        "이 앱이 무엇을 보여주는가" 가 글이 아니라 움직임으로 읽히게 한다.

   왜 이렇게 만들었나 (AnywhereMD 로그인 연출에서 정리된 규칙을 그대로 따른다)
     · **12초 한 바퀴 · 4장면.** 로그인하는 몇 초 사이에도 최소 한 장면은 보인다.
     · **외부 의존 0** — 이미지·CDN 없이 도형과 키프레임만(사내망에서 끊기지 않게).
     · **transform / opacity 만** 움직인다. width·height·top 을 애니메이션하면
       매 프레임 레이아웃을 다시 계산해 저사양 노트북에서 눈에 보이게 끊긴다.
       막대는 `scaleY`, 숫자는 숫자 띠를 `translateY` 로 굴린다.
       (스파크라인의 `stroke-dashoffset` 은 레이아웃이 아니라 페인트라 예외로 둔다)
     · 무대는 **고정 크기(300×176)** 다. 이 패널은 유동폭(col-lg-6)이라 % 좌표를 쓰면
       창 폭이 바뀔 때 배치가 어긋난다. 무대만 고정하고 정렬한다.

   ⚠ 타이밍 규칙: 큰 타이밍은 **키프레임 %** 로 만들고, `animation-delay` 는
     **항목 사이 시차(0.0x초)만** 담당한다. 둘을 겹쳐 쓰면 12초 주기를 벗어나
     화면이 내내 비어 있게 된다.
   ⚠ 색을 직접 쓰지 않는 원칙의 예외 구역이다 — 배경이 `--brand-gradient` 라
     그 위에서는 흰색 알파만 쓴다(테마 5종 어디서든 대비가 유지된다).
   ========================================================================== */

.lg-stage {
    position: relative;
    width: 300px;
    height: 176px;
    margin: 0 0 18px;
}

/* 공통 카드 — 유리판 느낌. 나타날 때만 움직이고 그 뒤에는 고정된다. */
.lg-card {
    position: absolute;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.14);
    border: 1px solid rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(2px);
    opacity: 0;
    transform: translateY(10px);
    animation: lgIn 12s ease-out infinite;
}
@keyframes lgIn {
    0% {
        opacity: 0;
        transform: translateY(10px);
    }
    /* 8% ≒ 1초 — 세 카드가 0.0x초 시차로 올라온다 */
    8%,
    92% {
        opacity: 1;
        transform: translateY(0);
    }
    100% {
        opacity: 0;
        transform: translateY(10px);
    }
}

/* ------------------------------------------------------- KPI 3칸 (위) */
.lg-card-kpi {
    left: 0;
    top: 0;
    width: 300px;
    height: 62px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    align-items: center;
    padding: 0 4px;
}
.lg-kpi {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 0 8px;
    border-left: 1px solid rgba(255, 255, 255, 0.16);
}
.lg-kpi:first-child {
    border-left: 0;
}
.lg-kpi-lb {
    font-size: 0.625rem;
    color: rgba(255, 255, 255, 0.72);
    white-space: nowrap;
}

/* 숫자 띠 — 세 값을 세로로 쌓아 두고 한 칸씩 굴려 "값이 오르는" 것처럼 보이게 한다.

   ⚠⚠ 구조를 지킬 것 — **창(.lg-roll)과 띠(.lg-roll-s)를 분리한다.**
     애니메이션을 창에 걸면 숫자가 굴러가는 대신 **창이 통째로 위로 밀려 올라간다**
     (숫자가 라벨보다 위로 튀어나오고 첫 값에 멈춘다 — 실제로 그렇게 만들었다가 지적받았다).
     움직이는 것은 항상 **안쪽 띠**다.

   ⚠ 칸 높이(--lg-cell)와 translateY 값이 **정확히 같아야** 숫자가 반쯤 걸리지 않는다.
     그리고 **정수 px** 로 둔다 — 1.05rem(=16.8px) 처럼 소수가 되면 창 높이와 이동량의
     반올림이 어긋나 옆 숫자가 한 줄 비쳐 보인다. */
.lg-roll {
    --lg-cell: 18px;
    display: block;
    height: var(--lg-cell);
    overflow: hidden;
    font-size: 0.9375rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: #fff;
}
.lg-roll-s {
    display: block;
}
.lg-roll b {
    display: block;
    height: var(--lg-cell);
    line-height: var(--lg-cell);
    font-weight: 700;
}
.lg-roll-s {
    animation: lgRoll 12s steps(1, end) infinite;
}
.lg-roll-b {
    animation-delay: 0.08s;
}
.lg-roll-c {
    animation-delay: 0.16s;
}
@keyframes lgRoll {
    0%,
    10% {
        transform: translateY(0);
    }
    18% {
        transform: translateY(calc(var(--lg-cell) * -1));
    }
    26%,
    92% {
        transform: translateY(calc(var(--lg-cell) * -2));
    }
    100% {
        transform: translateY(calc(var(--lg-cell) * -2));
    }
}
/* 납기 지연만 경고색 — 숫자가 줄어드는 것이 좋은 신호라는 것도 색으로 읽힌다 */
.lg-kpi-warn .lg-roll {
    color: #ffd7d7;
}

/* --------------------------------------------------- 막대차트 (좌하) */
.lg-card-bar {
    left: 0;
    top: 72px;
    width: 168px;
    height: 104px;
    padding: 8px 10px 10px;
    animation-delay: 0.1s;
}
.lg-cap {
    display: block;
    font-size: 0.625rem;
    color: rgba(255, 255, 255, 0.72);
    margin-bottom: 6px;
}
.lg-bars {
    display: flex;
    align-items: flex-end;
    gap: 5px;
    height: 62px;
}
.lg-bars > i {
    flex: 1;
    height: 100%;
    border-radius: 2px 2px 0 0;
    background: rgba(255, 255, 255, 0.85);
    /* 바닥을 축으로 자란다 — height 를 건드리지 않는다 */
    transform-origin: bottom;
    transform: scaleY(0);
    animation: lgGrow 12s cubic-bezier(0.22, 1, 0.36, 1) infinite;
    animation-delay: var(--d, 0s);
}
@keyframes lgGrow {
    0%,
    10% {
        transform: scaleY(0);
    }
    /* 각 막대의 최종 높이는 인라인 --h (0~1) 가 정한다 */
    30%,
    92% {
        transform: scaleY(var(--h, 0.6));
    }
    100% {
        transform: scaleY(0);
    }
}

/* ------------------------------------------------- 스파크라인 (우하) */
.lg-card-line {
    left: 176px;
    top: 72px;
    width: 124px;
    height: 104px;
    padding: 8px 10px 10px;
    animation-delay: 0.2s;
}
.lg-spark {
    display: block;
    width: 100%;
    height: 62px;
    overflow: visible;
}
.lg-spark-ln {
    fill: none;
    stroke: #fff;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    /* 선 전체 길이보다 넉넉히 잡아 둔다(좌표를 조금 바꿔도 안 깨진다) */
    stroke-dasharray: 200;
    stroke-dashoffset: 200;
    animation: lgDraw 12s ease-in-out infinite;
}
@keyframes lgDraw {
    0%,
    14% {
        stroke-dashoffset: 200;
    }
    46%,
    92% {
        stroke-dashoffset: 0;
    }
    100% {
        stroke-dashoffset: 200;
    }
}
/* 선 끝에서 반짝 — "지금 들어온 값" */
.lg-dot {
    position: absolute;
    right: 12px;
    top: 26px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.6);
    opacity: 0;
    animation: lgPing 12s ease-out infinite;
}
@keyframes lgPing {
    0%,
    44% {
        opacity: 0;
        transform: scale(0.6);
    }
    50% {
        opacity: 1;
        transform: scale(1);
    }
    62%,
    92% {
        opacity: 0.9;
        transform: scale(1);
    }
    100% {
        opacity: 0;
        transform: scale(0.6);
    }
}

/* ------------------------------------------- 흐르는 점 (데이터 유입) */
.lg-flow {
    position: absolute;
    top: -14px;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.9);
    opacity: 0;
    animation: lgFlow 12s linear infinite;
}
.lg-flow-1 {
    left: 46px;
}
.lg-flow-2 {
    left: 148px;
    animation-delay: 0.5s;
}
.lg-flow-3 {
    left: 244px;
    animation-delay: 1s;
}
@keyframes lgFlow {
    0% {
        opacity: 0;
        transform: translateY(0);
    }
    4% {
        opacity: 0.95;
    }
    /* KPI 카드 상단(높이 14px 위)에서 카드 안으로 빨려 들어간다 */
    10% {
        opacity: 0;
        transform: translateY(26px);
    }
    100% {
        opacity: 0;
        transform: translateY(26px);
    }
}

/* 폼도 한 번 부드럽게 올라온다(반복 없음 — 입력을 방해하지 않게) */
.login-card {
    animation: lgCardIn 0.45s ease-out both;
}
@keyframes lgCardIn {
    from {
        opacity: 0;
        transform: translateY(12px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ⚠ 움직임을 줄여 달라고 설정한 사용자에게는 **완성된 모습으로 고정**한다.
     애니메이션만 끄면 막대 scaleY(0)·선 dashoffset 이 남아 빈 카드가 보인다. */
@media (prefers-reduced-motion: reduce) {
    .lg-card,
    .lg-roll-s,
    .lg-bars > i,
    .lg-spark-ln,
    .lg-dot,
    .lg-flow,
    .login-card {
        animation: none !important;
    }
    .lg-card {
        opacity: 1;
        transform: none;
    }
    .lg-roll-s {
        transform: translateY(calc(var(--lg-cell) * -2));
    }
    .lg-bars > i {
        transform: scaleY(var(--h, 0.6));
    }
    .lg-spark-ln {
        stroke-dashoffset: 0;
    }
    .lg-dot {
        opacity: 0.9;
        transform: scale(1);
    }
    .lg-flow {
        opacity: 0;
    }
}
