/* jira-bridge — Utility & component classes
   Faithful port of the design-handoff console CSS.
   This IS the brand's component layer (framework-free): :root tokens + utility classes.
   All values copied verbatim from design_handoff/index.html. */

/* ---------- base ---------- */
body.jb, body.jb *, body.jb *::before, body.jb *::after { box-sizing:border-box; }
body.jb {
  background:var(--bg); color:var(--text); font-family:var(--font);
  font-size:var(--fs-body); line-height:1.5; -webkit-font-smoothing:antialiased;
  transition:background .15s, color .15s; margin:0;
}
.jb a { color:var(--accent); text-decoration:none; }
.jb a:hover { color:var(--accent-hover); text-decoration:underline; }
.jb h1,.jb h2,.jb h3 { margin:0; letter-spacing:-.01em; }
.jb button { font-family:var(--font); }

/* ---------- layout ---------- */
.wrap { max-width:var(--maxw); margin:0 auto; }
/* padding 이 없어서 호출부가 매번 인라인으로 채웠다 — card 41개 중 37개가 style= 를 달고
   패딩 값이 9종으로 갈렸다. --sp-6/--sp-9 주석이 이미 "card padding (compact/roomy)" 라고
   선언해 두었는데 정작 .card 가 쓰지 않고 있었다. 기본을 여기로 되돌린다.
   기존 인라인은 특이도상 그대로 이기므로 이 변경만으로는 화면이 바뀌지 않는다. */
.card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg); box-shadow:var(--shadow);
  padding:var(--sp-6); }
/* ⚠ **자식이** 스스로 패딩을 갖는 카드에만 쓴다 (.state 를 감싼 카드, 표 full-bleed 등).
   같은 요소에 패딩 클래스가 함께 붙은 경우(.auth-card ·.twofa-grid)에 쓰면 안 된다 —
   .card.is-flush (0,2,0) 가 .auth-card (0,1,0) 를 이겨 **패딩이 통째로 사라진다**.
   2026-08-28 실제로 로그인·2FA 화면이 이렇게 깨져 배포됐다. 그 둘은 클래스 자체가
   더 뒤에 선언돼 .card 기본값을 정상적으로 덮으므로 is-flush 가 애초에 필요 없다. */
.card.is-flush { padding:0; }
.card.is-roomy { padding:var(--sp-9); }
.muted { color:var(--text-2); }
.row { display:flex; align-items:center; }
.between { justify-content:space-between; }
.gap8 { gap:8px; } .gap10 { gap:10px; }

/* ---------- form ---------- */
.label { display:block; font-size:var(--fs-label); font-weight:600; color:var(--text-2); margin-bottom:6px; }
.input { width:100%; padding:9px 11px; border:1px solid var(--border-strong); border-radius:var(--radius);
  background:var(--surface-2); color:var(--text); font-size:var(--fs-body); font-family:inherit; }
.input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.input.mono { font-family:var(--mono); }
/* .input 과 같은 규격 — 한 줄에 섞일 때(필터 바 등) 높이·톤이 어긋나지 않게 */
.select { padding:9px 11px; border:1px solid var(--border-strong); border-radius:var(--radius);
  background:var(--surface-2); color:var(--text); font-size:var(--fs-body); font-family:inherit; cursor:pointer; }

/* ---------- button ---------- */
.btn { padding:8px 14px; border-radius:var(--radius); font-size:var(--fs-table); font-weight:600; cursor:pointer;
  font-family:inherit; border:1px solid transparent; white-space:nowrap; }
.btn-primary { background:var(--accent); color:var(--on-accent); }
.btn-primary:hover { background:var(--accent-hover); }
/* 앵커 버튼: .jb a (0,1,1) 가 .btn-* (0,1,0) 색을 이겨 primary 글자가 배경색과 같아지던 것 */
.jb a.btn { text-decoration:none; }
.jb a.btn:hover { text-decoration:none; }
.jb a.btn-primary, .jb a.btn-primary:hover { color:var(--on-accent); }
/* secondary 도 같은 함정에 있었다 — .jb a (0,1,1) 가 .btn-secondary (0,1,0) 를 이겨
   앵커 버튼만 글자가 액센트색으로 나왔다. 같은 클래스가 <button> 이냐 <a> 냐에 따라 다르게
   보였고, 필터 pill 에서는 활성/비활성이 배경으로만 구분돼 활성 표시가 약했다.
   41행 primary 처방과 동형. 대비 16.34:1(라이트)/14.19:1(다크). */
.jb a.btn-secondary, .jb a.btn-secondary:hover { color:var(--text); }
.btn-secondary { background:var(--surface); color:var(--text); border-color:var(--border-strong); }
.btn-secondary:hover { background:var(--surface-2); }
.btn-danger { background:transparent; color:var(--danger-fg); border-color:var(--danger); }
.btn-danger:hover { background:var(--danger-soft); }
.btn-block { width:100%; display:block; }
.btn:disabled { opacity:.55; cursor:not-allowed; }
.link-btn { background:none; border:none; color:var(--accent); font-weight:600; font-size:var(--fs-label); cursor:pointer; font-family:inherit; padding:0; }

/* ---------- badge / tag / chip ---------- */
/* white-space:nowrap 필수 — 좁은 칸에서 "해결" 이 "해/결" 로 쪼개져 알약 모양이 깨진다 */
.badge { display:inline-flex; align-items:center; gap:5px; padding:2px 9px; border-radius:999px; font-size:var(--fs-micro); font-weight:600; white-space:nowrap; }
/* 배지 셀 — 셀 폭이 배지보다 좁아도 배지를 두 줄로 꺾지 않는다 (영문 상태 "IN PROGRESS" 사례) */
td.badge-wrap { white-space:nowrap; }
.badge .dot { width:6px; height:6px; border-radius:50%; }
.badge.ok    { background:var(--ok-soft); color:var(--ok-fg); }    .badge.ok .dot{background:var(--ok);}
.badge.info  { background:var(--info-soft); color:var(--info-fg); } .badge.info .dot{background:var(--info);}
.badge.warn  { background:var(--warn-soft); color:var(--warn-fg); } .badge.warn .dot{background:var(--warn);}
.badge.muted { background:var(--muted-soft); color:var(--muted-fg); } .badge.muted .dot{background:var(--muted);}
.badge.accent{ background:var(--accent-soft); color:var(--accent); } .badge.accent .dot{background:var(--accent);}
/* DS-3: 실패 전용. 이 변형이 없어서 전송 실패를 warn(주황)으로 표시해 보류와 구분되지 않았다. */
.badge.danger{ background:var(--danger-soft); color:var(--danger-fg); } .badge.danger .dot{background:var(--danger);}
.tag-soon { font-size:var(--fs-micro); font-weight:600; padding:1px 6px; border-radius:4px; background:var(--muted-soft); color:var(--muted-fg); }
.chip { display:inline-block; padding:2px 8px; border-radius:5px; background:var(--surface-3); font-size:var(--fs-caption); color:var(--text-2); font-family:var(--mono); }

/* ---------- banner ---------- */
.banner { display:flex; align-items:center; gap:10px; border-radius:var(--radius); padding:11px 14px; font-size:var(--fs-table); }
.banner.warn { background:var(--warn-soft); border:1px solid var(--warn); color:var(--warn-fg); }
.banner.info { background:var(--info-soft); border:1px solid var(--info); color:var(--info-fg); align-items:flex-start; gap:8px; }
.banner.danger { background:var(--danger-soft); border:1px solid var(--danger); color:var(--danger-fg); align-items:flex-start; gap:8px; }
.banner.ok { background:var(--ok-soft); border:1px solid var(--ok); color:var(--ok-fg); align-items:flex-start; gap:8px; }
.banner svg { flex-shrink:0; }

/* ---------- table ---------- */
.table { width:100%; border-collapse:collapse; font-size:var(--fs-table); }
.table thead tr { background:var(--surface-3); text-align:left; color:var(--text-2); }
.table th { padding:9px 16px; font-weight:600; }
.table td { padding:11px 16px; }
.table tbody tr { border-top:1px solid var(--border); }
/* 세로 구분선 변형 — 숫자 컬럼이 많은 표(공수 보고서 등)에서 열 경계를 잡아준다 */
.table.vlines th, .table.vlines td { border-right:1px solid var(--border); }
.table.vlines th:last-child, .table.vlines td:last-child { border-right:none; }
.code-cell { color:var(--text-3); font-family:var(--mono); }
.table .checkcol { width:20px; }
.table input[type=checkbox] { width:14px; height:14px; accent-color:var(--accent); cursor:pointer; vertical-align:middle; }

/* ---------- 브랜드 / 사용자 / 아이콘 버튼 ----------
   DS-5(#35): 구 상단 네비 레이어(.header/.header-in/.brand/.nav/.nav-link/.header-right)는
   사이드바 앱셸(console-v2) 전환으로 사용처가 0곳이라 제거했다.
   아래는 사이드바 푸터·앱바가 실제로 쓰는 것들만 남긴 것. */
.brand-name { font-size:var(--fs-card-title); font-weight:700; white-space:nowrap; }
.icon-btn { width:32px; height:32px; border-radius:var(--radius); border:1px solid var(--border); background:var(--surface-2); color:var(--text-2); cursor:pointer; font-size:var(--fs-card-title); }
.user-meta { text-align:right; line-height:1.25; }
.user-name { font-size:var(--fs-table); font-weight:600; }
.user-role { font-size:var(--fs-micro); color:var(--text-3); }

/* ---------- page / tiles ---------- */
.page-head h1 { font-size:var(--fs-page-title); font-weight:700; margin-bottom:3px; }
.page-head p { margin:0 0 22px; color:var(--text-2); }
/* .jb h2 { margin:0 } (0,1,1) 이 .section-title (0,1,0) 을 항상 이겨 상단 여백이 죽어 있었다 — 명시도를 올려 복구 */
.jb .section-title { font-size:var(--fs-card-title); font-weight:700; margin:var(--sp-section) 0 14px; display:flex; align-items:center; gap:8px; }
.head-row { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; }
.grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:16px; }

/* ---------- switch ---------- */
.switch { position:relative; width:34px; height:20px; display:inline-block; flex-shrink:0; }
/* A11Y-2: display:none 은 체크박스를 접근성 트리·탭 순서에서 제거해 키보드로 토글이
   불가능했다(규칙/대상 활성화가 마우스 전용). 시각적으로만 숨기고 포커스는 유지한다. */
.switch input { position:absolute; opacity:0; width:100%; height:100%; margin:0; cursor:pointer; }
.switch input:focus-visible + .track { box-shadow:0 0 0 3px var(--accent-soft); }
.switch .track { position:absolute; inset:0; background:var(--border-strong); border-radius:999px; transition:.15s; cursor:pointer; }
.switch .track:before { content:""; position:absolute; width:16px; height:16px; border-radius:50%; background:#fff; top:2px; left:2px; transition:.15s; box-shadow:0 1px 2px rgba(0,0,0,.25); }
.switch input:checked + .track { background:var(--accent); }
.switch input:checked + .track:before { transform:translateX(14px); }

/* ---------- kv / list / avatar ---------- */
.kv { display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--border); border:1px solid var(--border); border-radius:var(--radius-lg); overflow:hidden; }
.kv .cell { background:var(--surface); padding:12px 16px; }
.kv .k { font-size:var(--fs-micro); color:var(--text-3); margin-bottom:4px; }
.kv .v { font-size:var(--fs-body); font-weight:600; }
.list { border:1px solid var(--border); border-radius:var(--radius-lg); overflow:hidden; background:var(--surface); }
.list-item { padding:12px 16px; border-top:1px solid var(--border); }
.list-item:first-child { border-top:none; }
.avatar { width:26px; height:26px; border-radius:50%; background:var(--accent-soft); color:var(--accent); display:inline-flex; align-items:center; justify-content:center; font-size:var(--fs-micro); font-weight:700; flex-shrink:0; }

/* ---------- rules ---------- */
.rule-row { display:flex; align-items:center; gap:14px; padding:14px 16px; border-top:1px solid var(--border); }
.rule-row:first-child { border-top:none; }
.handle { color:var(--text-3); cursor:grab; font-size:var(--fs-lead); user-select:none; }
.prio { width:24px; height:24px; border-radius:6px; background:var(--surface-3); display:inline-flex; align-items:center; justify-content:center; font-weight:700; font-size:var(--fs-label); color:var(--text-2); flex-shrink:0; }

/* ---------- filter / toolbar ---------- */
.filterbar { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-bottom:16px; }
.filterbar .search { flex:1; min-width:200px; }
.toolbar { display:flex; align-items:center; gap:12px; margin-top:16px; padding:12px 16px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); box-shadow:var(--shadow); }
.tkey { font-family:var(--mono); font-weight:600; color:var(--accent); }
.link-ext { color:var(--text-3); font-weight:600; }
.link-ext:hover { color:var(--accent); text-decoration:none; }

/* ---------- OTP ---------- */
.otp { display:flex; gap:8px; }
.otp input { width:44px; height:52px; text-align:center; font-size:var(--fs-otp); font-weight:600; border:1px solid var(--border-strong); border-radius:var(--radius); background:var(--surface-2); color:var(--text); font-family:var(--mono); }
.otp input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.otp.lg input { width:52px; height:60px; font-size:var(--fs-display); }

/* ---------- 2FA setup (QR + steps) ---------- */
.twofa-grid { display:grid; grid-template-columns:220px 1fr; gap:24px; align-items:start; padding:24px; }
.qr { border:1px solid var(--border); border-radius:var(--radius); overflow:hidden; }
.qr canvas, .qr img { display:block; margin:0 auto; }
@media (max-width:820px) { .twofa-grid { grid-template-columns:1fr; } }

/* ---------- auth ---------- */
.auth { min-height:100vh; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:24px; position:relative; }
.auth-toggle { position:absolute; top:20px; right:24px; }
.auth-brand { display:flex; align-items:center; gap:10px; margin-bottom:22px; }
.auth-brand .brand-name { font-size:var(--fs-section); }
.auth-card { width:100%; max-width:380px; padding:28px; }
.auth-foot { margin-top:20px; color:var(--text-3); font-size:var(--fs-caption); }

/* ---------- misc ---------- */
.divider { height:1px; background:var(--border); margin:18px 0; }
.back { background:none; border:none; color:var(--text-2); font-size:var(--fs-table); cursor:pointer; padding:0; font-family:inherit; }
.back:hover { color:var(--text); }
.secret-box { display:flex; align-items:center; gap:8px; background:var(--surface-2); border:1px solid var(--border); border-radius:var(--radius); padding:9px 11px; }
.secret-box code { flex:1; font-family:var(--mono); font-size:var(--fs-body); letter-spacing:.05em; color:var(--text); }
.copy-btn { padding:4px 9px; border-radius:5px; border:1px solid var(--border-strong); background:var(--surface); color:var(--text-2); font-size:var(--fs-micro); font-weight:600; cursor:pointer; font-family:inherit; }

/* ─────────────────────────────────────────────────────────────
   접근성 (#27) — 2026-07-28
   CSS 전체에서 :focus 가 .input/.otp 2곳뿐이라 키보드 사용자가 버튼·링크·셀렉트에서
   자기 위치를 볼 수 없었다. 마우스 클릭 시엔 링이 안 뜨도록 :focus-visible 사용.
   ───────────────────────────────────────────────────────────── */
.jb .btn:focus-visible,
.jb .link-btn:focus-visible,
.jb .pager-btn:focus-visible,
.jb .tab:focus-visible,
.jb .icon-btn:focus-visible,
.jb .copy-btn:focus-visible,
.jb a:focus-visible,
.jb summary:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
  border-radius: 6px;
}
.jb .select:focus,
.jb select:focus,
.jb input[type="checkbox"]:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* A11Y-4: 스킵 링크 — 사이드바 링크 9~12개를 매 페이지 탭으로 통과하지 않도록 */
.skip-link {
  position: absolute; left: 8px; top: -40px; z-index: 100;
  background: var(--accent); color: var(--on-accent);
  padding: 8px 14px; border-radius: 6px; font-size:var(--fs-table); font-weight: 600;
  text-decoration: none; transition: top .12s;
}
.skip-link:focus { top: 8px; }
/* ⚠ .jb a (0,1,1) 가 .skip-link (0,1,0) 의 color 를 이겨 글자색이 배경색과 같아진다(대비 1.0:1).
   화면 밖에 있다가 포커스에만 나타나므로 눈으로도 스크린샷으로도 안 잡힌다 — 실제로 16개
   관리자 페이지의 첫 탭스톱이 '글자 없는 보라색 알약'이었다(2026-08-28 CDP 로 Tab 눌러 확인).
   41행의 .btn-primary 와 같은 처방. 접근성 기능 자체가 안 보이던 것이라 우선순위가 높다. */
.jb a.skip-link, .jb a.skip-link:hover, .jb a.skip-link:focus { color: var(--on-accent); }

/* A11Y-5: 한국어 조판 — 제목 열에 overflow-wrap:anywhere 가 걸려 음절 임의 지점에서
   잘렸다. keep-all 로 단어 단위 줄바꿈. (긴 영문·URL 은 anywhere 로 예외) */
.jb .table.fixed td.ko-text,
.jb .ko-text { word-break: keep-all; overflow-wrap: break-word; }

/* A11Y-6: 모션 최소화 선호 존중.
   ⚠ 종전에는 .001ms 로 **전부** 죽였다. 선호는 존중되지만 상태 변화 피드백까지 사라진다 —
     호버·포커스의 색 전환은 움직임이 아니라 "지금 이걸 가리키고 있다"는 신호이고,
     스피너 정지는 "작동 중"이라는 유일한 표시를 없앤다.
   이 디자인 시스템의 실제 움직임은 셋뿐이다: 스킵링크 top 슬라이드 · 토글 손잡이
   translateX · 스피너 회전. 나머지 transition 은 전부 색이다.
   → 움직임만 끄고, 색 피드백은 남기고, 스피너는 느리게 돌린다. */
@media (prefers-reduced-motion: reduce) {
  .jb *, .jb *::before, .jb *::after {
    /* 화이트리스트: 여기 없는 속성(top·transform 등 위치·크기)은 전환 없이 즉시 바뀐다 */
    transition-property: color, background-color, border-color, box-shadow, opacity !important;
    transition-duration: .12s !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
  /* 스피너는 남긴다 — 정지하면 "작동 중"을 알릴 수단이 사라진다. 대신 느리게.
     .jb .spinner (0,2,0) 가 위 .jb * (0,1,0) 를 이기므로 !important 끼리도 이쪽이 적용된다. */
  .jb .spinner { animation: jb-spin 1.6s linear infinite !important; }
}
