/*
 * 로그인 — 사용자/관리자 두 진입 화면이 함께 쓰는 셸.
 *
 * 마크업은 views/loginScene.js 한 곳에서 만든다. 두 화면이 같은 구조를 쓰므로
 * 여기 규칙도 한 벌이면 된다.
 *
 * 앱과 같은 계측기(instrument) 언어.
 *
 * 예전에는 이 화면만 구리·청록 SCADA 팔레트를 따로 들고 있었다. 스코프가 잘 잡혀
 * 있어 사고는 안 났지만, 로그인과 본 앱이 서로 다른 제품처럼 보였다.
 * 이제 --login-* 는 값을 직접 들지 않고 tokens.css 의 semantic 토큰을 가리킨다.
 * 스코프(이 이름들이 화면 밖으로 새지 않는 것)는 그대로 두면서 팔레트만 합친 것이다.
 *
 * 그래서 .theme-light 블록이 통째로 필요 없어졌다 — 참조하는 토큰이 이미 테마별로
 * 값이 갈리기 때문이다. 유지보수 지점이 두 곳에서 한 곳(tokens.css)으로 줄었다.
 *
 * 남긴 것: 레이아웃, mono 규칙, 캔버스 네트워크(login-network.js).
 * 걷어낸 것: 오로라·스캔광 등 데이터 위 대비만 깎던 장식 층.
 */

.login-page {
  /* --- 표면 · 글자 : 전역 토큰을 그대로 쓴다 --- */
  --login-bg: var(--surface-base);
  --login-panel: var(--surface-raised);
  --login-line: var(--graticule);
  --login-text: var(--ink);
  --login-dim: var(--ink-dim);
  --login-faint: var(--ink-faint);
  --login-card-shadow: var(--shadow-md);

  /* --- 액센트 : 시안 시그널 하나 + 상태 4색 ---
     구리/청록 두 액센트를 쓰면 "색은 상태에만" 규칙이 깨진다. */
  --login-copper: var(--signal);
  --login-cyan: var(--signal);
  --login-red: var(--state-alert-ink);
  /* mark 는 도트·채움용(채도 유지), ink 는 글자용(대비 확보) — tokens.css 의 구분을 그대로 따른다.
     하나로 합치면 라이트에서 초록 글자가 흰 면 위에 1.9:1 로 떨어진다. */
  --login-ok: var(--state-good-mark);
  --login-ok-ink: var(--state-good-ink);
  --login-ok-line: var(--state-good-ink);
  --login-ok-glow: var(--state-good-soft);
  --login-cyan-ring: var(--signal-soft);

  --login-btn-bg: var(--btn-primary-bg);
  --login-btn-ink: var(--btn-primary-ink);

  /* --- 배경 : 눈금 격자만 남긴다 --- */
  --login-grid: var(--graticule-faint);
  --login-stage-bg: transparent;
  --login-panel-veil: transparent;
  --login-sweep: none;
  --login-aurora-1: none;
  --login-aurora-2: none;
  --login-aurora-3: none;
  --login-aurora-opacity: 0;
  --login-aurora3-lo: 0;
  --login-aurora3-hi: 0;

  /* 캔버스가 읽어 가는 값(login-network.js). CSS 변수를 캔버스가 직접 못 쓰므로
     스크립트가 이 요소의 computed style 에서 꺼낸다. */
  --login-link: var(--graticule-strong);
  --login-link-max: 0.24;
  --login-node-glow: 8;

  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  overflow: hidden;
  background: var(--login-bg);
  color: var(--login-text);
  color-scheme: dark;
}

/* 스펙은 Space Grotesk / Inter / JetBrains Mono 를 쓰지만, 이 프로젝트는 이미
   Noto Sans KR + IBM Plex Mono 로 통일돼 있다. 한 화면 때문에 웹폰트 세 벌을 더
   받는 건 값이 크고 그동안의 통일도 깨진다 — 계기판 느낌은 '수치·태그는 mono'
   라는 규칙이 만드는 것이라 그 규칙만 가져왔다. */
/* mono 는 라틴·숫자에만 건다. 한글을 mono 로 두면 자족이 무너지고, 넓은 자간까지
   겹치면 '정 상', '전 력 · 공 기 질' 처럼 글자가 흩어져 읽기 어려워진다. */
.login-page .brand-mark,
.login-page .brand-sub,
.login-page .gauge-tag,
.login-page .gauge-value,
.login-page .gauge-unit,
.login-page .stage-foot,
.login-page .login-eyebrow,
.login-page .divider-label {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ============================================================
 * 배경 3겹 — 캔버스 / 오로라 / 그리드·스캔광
 * ============================================================ */
#bgCanvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  display: block;
}

/* mix-blend-mode: screen 을 뺐다. 어두운 배경 위에서는 일반 합성과 눈에 띄는 차이가
   없는데, 매 프레임 배경을 다시 섞느라 이 화면에서 가장 비싼 층이었다(측정: 이 세
   요소만 꺼도 프레임이 111ms → 41ms). blur 도 90px 에서 줄여 같은 인상을 유지한다. */
.aurora {
  position: absolute;
  border-radius: 50%;
  filter: blur(64px);
  z-index: 0;
  pointer-events: none;
  opacity: var(--login-aurora-opacity);
  will-change: transform;
  contain: paint;
}

.aurora-1 {
  width: 560px; height: 560px; top: -160px; left: -120px;
  background: var(--login-aurora-1);
  animation: login-drift-1 16s ease-in-out infinite;
}
.aurora-2 {
  width: 620px; height: 620px; bottom: -220px; right: -160px;
  background: var(--login-aurora-2);
  animation: login-drift-2 19s ease-in-out infinite;
}
.aurora-3 {
  width: 420px; height: 420px; top: 35%; left: 38%;
  background: var(--login-aurora-3);
  animation: login-drift-3 22s ease-in-out infinite;
}

@keyframes login-drift-1 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(90px, 60px) scale(1.15); }
}
@keyframes login-drift-2 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-80px, -70px) scale(1.2); }
}
@keyframes login-drift-3 {
  0%, 100% { transform: translate(-30px, -20px) scale(0.9); opacity: var(--login-aurora3-lo); }
  50% { transform: translate(40px, 30px) scale(1.25); opacity: var(--login-aurora3-hi); }
}

/* 격자 텍스처 + 서로 다른 각도로 지나는 스캔광 두 줄 */
.login-page::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--login-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--login-grid) 1px, transparent 1px);
  background-size: 42px 42px;
  pointer-events: none;
  z-index: 0;
}

.login-page::after {
  content: '';
  position: absolute;
  inset: -20%;
  background: var(--login-sweep);
  background-size: 220% 220%, 260% 260%;
  /* background-position 을 움직이면 화면 전체가 매 프레임 다시 그려진다. transform 은
     합성만 하면 되므로 같은 연출을 훨씬 싸게 만든다(측정: 41ms 절감). */
  animation: login-sweep 9s linear infinite;
  pointer-events: none;
  z-index: 0;
  will-change: transform;
}

@keyframes login-sweep {
  from { transform: translate3d(-6%, -6%, 0); }
  to { transform: translate3d(6%, 6%, 0); }
}

/* ============================================================
 * 왼쪽 — 계기판 스테이지
 * ============================================================ */
.login-stage {
  position: relative;
  z-index: 2;
  flex: 1.15;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--sp-8);
  padding: 48px 56px;
  border-right: 1px solid var(--login-line);
  background: var(--login-stage-bg);
}

.brand { display: flex; align-items: center; gap: var(--sp-3); }

.brand-mark {
  width: 34px; height: 34px;
  flex: none;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--login-copper);
  border-radius: var(--r-md);
  color: var(--login-copper);
}

.brand-mark svg { width: 19px; height: 19px; }

.brand-text { font-size: var(--fs-14); font-weight: var(--fw-semibold); letter-spacing: 0.08em; }
.brand-sub { margin-top: 1px; font-size: var(--fs-11); color: var(--login-dim); letter-spacing: 0.06em; }

.stage-headline { margin-top: 36px; }

.stage-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-11);
  color: var(--login-cyan);
  letter-spacing: 0.04em;
}

.pulse-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--login-ok);
  animation: login-pulse 2s infinite;
}

@keyframes login-pulse {
  0% { box-shadow: 0 0 0 0 var(--login-ok-glow); }
  70% { box-shadow: 0 0 0 6px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.stage-title {
  margin-top: var(--sp-3);
  /* 460px 이면 32px 한글 14자(관리자 헤드라인)가 한 줄에 안 들어가 줄이 접혔다.
     스테이지는 이보다 넓으므로(1440 기준 약 700px) 상자를 늘려 <br> 위치대로 끊는다. */
  max-width: 560px;
  font-size: var(--fs-32);
  font-weight: var(--fw-semibold);
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: var(--login-text);
  /* 한글은 기본값(break-word 성격)이면 단어 한가운데서 잘린다 — '관리하 / 고'.
     keep-all 이면 어절(공백) 단위로만 끊긴다. */
  word-break: keep-all;
}
.stage-title span { color: var(--login-dim); font-weight: var(--fw-regular); }

/* ---- 게이지 클러스터 ---- */
.cluster {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-4);
  margin-top: 38px;
}

.gauge-card {
  position: relative;
  overflow: hidden;
  padding: var(--sp-4) var(--sp-4) var(--sp-4);
  border: 1px solid var(--login-line);
  border-radius: var(--card-radius);
  background: var(--login-panel);
  box-shadow: var(--login-card-shadow);
}

/* 카드 상단의 얇은 색띠가 이 카드가 무엇을 재는지 알려 준다. */
.gauge-card::after {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--gauge-accent, var(--login-copper));
  opacity: 0.7;
}

.accent-1 { --gauge-accent: var(--chart-cat-1); }
.accent-2 { --gauge-accent: var(--chart-cat-2); }
.accent-3 { --gauge-accent: var(--chart-cat-3); }
.accent-4 { --gauge-accent: var(--chart-cat-4); }

.gauge-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-2); }
.gauge-tag { font-size: var(--fs-11); color: var(--login-dim); letter-spacing: 0.06em; }
.gauge-label { margin-top: var(--sp-1); font-size: var(--fs-12); font-weight: var(--fw-medium); color: var(--login-text); }

.gauge-status {
  flex: none;
  padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--login-ok-line);
  border-radius: var(--card-radius);
  font-size: var(--fs-11);
  line-height: 1.4;
  white-space: nowrap;
  color: var(--login-ok-ink);
}

.gauge-body { display: flex; align-items: flex-end; gap: var(--sp-4); margin-top: var(--sp-4); }
.gauge-ring { width: 58px; height: 58px; flex: none; }
.gauge-ring .ring-track { fill: none; stroke: var(--login-line); stroke-width: 5; }
.gauge-ring .ring-value {
  fill: none;
  stroke: var(--gauge-accent, var(--login-copper));
  stroke-width: 5;
  stroke-linecap: round;
  transition: stroke-dashoffset 800ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* 관리자 로그인은 로그인 전에 보여 줄 계측값이 없다. 링 자리에 기능 아이콘을 넣어
   같은 카드 형태를 유지하되 숫자를 지어내지 않는다. */
.gauge-icon {
  width: 58px;
  height: 58px;
  flex: none;
  display: grid;
  place-items: center;
  border: 1px solid var(--login-line);
  border-radius: var(--card-radius);
  color: var(--gauge-accent, var(--login-cyan));
}
.gauge-icon svg { width: 24px; height: 24px; }
.gauge-body.is-feature { align-items: center; }

.gauge-read { min-width: 0; }
.gauge-value { font-size: var(--fs-20); font-weight: var(--fw-bold); line-height: 1; }
.gauge-unit { margin-left: var(--sp-1); font-size: var(--fs-11); color: var(--login-dim); }
.gauge-sub { margin-top: var(--sp-2); font-size: var(--fs-11); color: var(--login-dim); }

/* 로그인 전에는 실제 계측값을 붙일 수 없다. 숫자가 현장 값으로 읽히지 않도록 밝힌다. */
.cluster-note {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-11);
  color: var(--login-faint);
}

.stage-foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  font-size: var(--fs-11);
  color: var(--login-dim);
}
.stage-divider { flex: 1; height: 1px; margin: 0 var(--sp-4) var(--sp-2); background: var(--login-line); }

/* ============================================================
 * 오른쪽 — 로그인 폼
 * ============================================================ */
.login-panel {
  position: relative;
  z-index: 2;
  flex: 0.85;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-8);
  background: var(--login-panel-veil);
}

.login-box { width: 100%; max-width: 360px; }

/*
 * 테마 전환. 공용 부트 스크립트([data-admin-theme-toggle])에 맡기지 않는다 —
 * 그쪽은 버튼의 textContent 를 라벨로 덮어써서 아이콘이 지워진다. 로그인 화면은
 * 자체 핸들러를 갖는 [data-theme-toggle] 규약을 쓰고(admin 로그인 · gds007 도 동일),
 * 저장 키는 공용과 같은 userTheme 이라 선택이 로그인 이후 화면까지 이어진다.
 */
.theme-switch {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--login-line);
  border-radius: var(--r-md);
  background: var(--login-panel);
  color: var(--login-dim);
  cursor: pointer;
  transition: color 150ms ease, border-color 150ms ease;
}
.theme-switch:hover { color: var(--login-text); border-color: var(--login-dim); }
.theme-switch svg { width: 17px; height: 17px; }

/* 다크에서는 '해'(라이트로 감), 라이트에서는 '달'(다크로 감)을 보인다. */
.theme-switch .icon-moon { display: none; }
.theme-light .theme-switch .icon-sun { display: none; }
.theme-light .theme-switch .icon-moon { display: block; }

.login-eyebrow { font-size: var(--fs-11); color: var(--login-dim); letter-spacing: 0.12em; }
.login-title { margin-top: var(--sp-2); font-size: var(--fs-24); font-weight: var(--fw-semibold); color: var(--login-text); }
.login-desc { margin-top: var(--sp-2); font-size: var(--fs-13); line-height: 1.5; color: var(--login-dim); }

.login-form { margin-top: var(--sp-8); }
.field { margin-bottom: var(--sp-4); }
.field label { display: block; margin-bottom: var(--sp-2); font-size: var(--fs-12); font-weight: var(--fw-medium); color: var(--login-dim); }

.field-input {
  display: flex;
  align-items: center;
  border: 1px solid var(--login-line);
  border-radius: var(--r-md);
  background: var(--login-panel);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}

.field-input:focus-within {
  border-color: var(--login-cyan);
  box-shadow: 0 0 0 3px var(--login-cyan-ring);
}

.field-input input {
  flex: 1;
  min-width: 0;
  padding: var(--sp-3) var(--sp-4);
  border: none;
  outline: none;
  background: transparent;
  color: var(--login-text);
  font-family: inherit;
  font-size: var(--fs-14);
}
/* 자리표시자는 faint 가 아니라 dim 을 쓴다 — 읽어야 하는 글자다. */
.field-input input::placeholder { color: var(--login-dim); }

/* 실패했을 때만 테두리가 붉어진다. */
.field-input:has(input[aria-invalid="true"]) { border-color: var(--login-red); }

/* 안내가 나타날 때 폼이 아래로 밀리지 않도록 자리를 늘 잡아 둔다. */
.login-error {
  min-height: 18px;
  margin: -4px 0 18px;
  font-size: var(--fs-12);
  line-height: 1.4;
  color: var(--login-red);
}

.btn-submit {
  width: 100%;
  padding: var(--sp-4);
  border: none;
  border-radius: var(--r-md);
  background: var(--login-btn-bg);
  color: var(--login-btn-ink);
  font-family: inherit;
  font-size: var(--fs-14);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: filter 150ms ease, transform 150ms ease;
}
/* 배경을 반드시 다시 정해야 한다. components.css 의 button:hover 가 (0,1,1)로
   .btn-submit(0,1,0)보다 명시도가 높아서, 여기서 안 잡으면 호버 시 배경이
   --surface-hover(라이트에서 거의 흰색)로 바뀌고 흰 글자가 사라진다. */
.btn-submit:hover {
  background: var(--signal-hover);
  color: var(--login-btn-ink);
}
.btn-submit:active { transform: scale(0.985); }

.divider-row { display: flex; align-items: center; gap: var(--sp-3); margin: 26px 0 14px; }
.divider-row .line { flex: 1; height: 1px; background: var(--login-line); }
.divider-label { font-size: var(--fs-11); color: var(--login-dim); letter-spacing: 0.1em; }

/* 스펙의 '자동 로그인'과 '비밀번호 찾기'는 서버에 대응 기능이 없어 넣지 않았다.
   동작하지 않는 컨트롤 대신 실제 절차를 문장으로 안내한다. */
.login-help {
  margin: 0;
  font-size: var(--fs-12);
  line-height: 1.55;
  color: var(--login-dim);
}

.foot-note { margin-top: var(--sp-6); text-align: center; font-size: var(--fs-11); color: var(--login-faint); }
.foot-meta { margin-top: var(--sp-2); text-align: center; font-size: var(--fs-11); color: var(--login-faint); }
.foot-meta code { font-family: var(--font-mono); }

.login-page :focus-visible { outline: 2px solid var(--login-cyan); outline-offset: 2px; }

/* ============================================================
 * 좁은 화면 — 스테이지를 접고 폼만
 * ============================================================ */
@media (max-width: 1080px) {
  .login-stage { display: none; }
  .login-panel { flex: 1; padding: var(--sp-8) var(--sp-6); }
}

/* 제목 크기는 이 셸이 직접 소유한다. 예전에는 좁은 화면에서 user-base.css 의
   `.is-mobile h1`(0,1,1)이 .login-title(0,1,0)을 이겨서 줄여 줬는데, 그 규칙이
   user 레이아웃에만 있어서 관리자·뷰어 로그인은 안 줄어들었다. 같은 셸이 어느
   레이아웃에 얹히든 같게 나와야 한다. */
@media (max-width: 768px) {
  /* .login-page 를 앞에 붙여 (0,2,0)으로 올린다 — 미디어쿼리는 명시도를 더해 주지
     않으므로 이게 없으면 .is-mobile h1(0,1,1)에 진다. */
  .login-page .login-title { font-size: var(--fs-20); }
}

/* ============================================================
 * 움직임 최소화 — 스펙 체크리스트에서 미구현으로 남아 있던 항목.
 * 캔버스는 스크립트가 한 장만 그리고 멈추고, 여기서는 오로라·스캔광·펄스를
 * 정지시킨다. 화면이 비지 않도록 오로라는 남겨 두되 움직이지만 않게 한다.
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .aurora,
  .login-page::after,
  .pulse-dot {
    animation: none;
  }
  .login-page::after { transform: none; }
  .gauge-ring .ring-value { transition: none; }
}
