/* ══════════════════════════════════════════════════════════════
   components.css — 공용 컴포넌트

   페이지 CSS에서 이 컴포넌트들을 재정의하지 않는다.
   변형이 필요하면 여기에 수식어 클래스를 추가한다.

   짝이 되는 Jinja 매크로: templates/_components.html
   규격: docs/UI_STANDARDS.md 3장
   ══════════════════════════════════════════════════════════════ */

/* ══ 레이아웃 컨테이너 ═════════════════════════════════════════ */
.page-container,
.main-wrapper,
.dashboard-wrapper {
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: var(--sp-6) var(--sp-4);
}

.section { margin-bottom: var(--sp-8); }
.section-title {
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  margin-bottom: var(--sp-3);
  padding-bottom: var(--sp-1);
  border-bottom: 2px solid var(--border);
}

/* ══ 페이지 헤더 ═══════════════════════════════════════════════
   값은 관행을 따른다. 제목과 보조 설명은 한 덩어리이므로 8px,
   헤더와 본문 사이는 24px 다.
     Bootstrap 5  $headings-margin-bottom: $spacer * .5 = 8px
     Material 3   관련 요소 사이 8dp, 구역 사이 16~24dp
     GOV.UK       제목 아래 30px, 문단 아래 20px
   근거 없이 이 값을 키우지 않는다. 붙어 보인다면 대개 간격이 아니라
   대비 문제다 — DESIGN_GUIDE.md 4.1.2 를 먼저 본다. */
.page-header {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-6);
}

/* 목록만 있는 화면(허브 4종)의 변형.
   본문이 카드 격자뿐이라 헤더가 첫 그룹에 딸려 보이기 쉽다. 한 단계 더 벌려
   헤더를 독립된 구역으로 읽히게 한다. 세로가 아까운 모바일은 32px 에서 멈춘다. */
.page-header--index { gap: var(--sp-3); margin-bottom: var(--sp-8); }
@media (min-width: 1024px) {
  .page-header--index { margin-bottom: var(--sp-12); }
}
.page-header-main {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.page-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-2xl);
  font-weight: var(--fw-black);
  color: var(--text-primary);
  letter-spacing: -0.02em;
  line-height: var(--lh-tight);
}
.page-desc {
  font-size: var(--fs-base);
  color: var(--text-muted);
  /* 한 줄 길이 제한. 폭이 남아도 줄을 바꾸는 것은 의도다 — 줄이 길면 눈이
     다음 줄 첫머리를 놓친다. WCAG 1.4.8 은 한 줄 최대치를 라틴 80자,
     CJK 40자로 잡는다. 한글은 글자 하나가 곧 1em 이므로 40em = 40자다.

     단위가 ch 가 아닌 이유: ch 는 숫자 "0" 의 폭이라 라틴 기준이다.
     이 화면에서 재보니 1ch = 7.80px, 한글 한 글자 = 12.89px 였고,
     그래서 62ch(=483px)가 한글로는 37자에서 끊겼다. 기준에 가깝긴 했으나
     우연이었고 글꼴이 바뀌면 함께 흔들린다. */
  max-width: 40em;
}
/* 모바일에서는 액션이 제목 아래 한 줄로 내려가 가로 스크롤된다 */
.page-actions {
  display: flex;
  gap: var(--sp-2);
  overflow-x: auto;
  padding-bottom: 2px;
}
@media (min-width: 640px) {
  .page-header-main { flex-wrap: nowrap; align-items: center; }
  .page-actions { margin-left: auto; overflow: visible; }
}

/* ══ 카드 ══════════════════════════════════════════════════════ */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  padding: var(--sp-4);
  width: 100%;
  max-width: 560px;
  margin: var(--sp-6) auto;
}
.page-container > .card { margin-top: 0; }

.panel {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-4);
}
@media (min-width: 640px) {
  .card, .panel { padding: var(--sp-5); }
}

/* ══ 배지 ══════════════════════════════════════════════════════
   구 dash-badge / status-badge / q-status 를 모두 흡수한다.
   색만으로 상태를 전달하지 않는다 — 항상 텍스트를 포함한다. */
.badge {
  display: inline-block;
  padding: 2px 10px;
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  line-height: 1.6;
}
.badge--running { background: var(--ok-bg);     color: var(--ok); }
.badge--idle    { background: var(--idle-bg);   color: var(--idle); }
.badge--warn    { background: var(--warn-bg);   color: var(--warn); }
.badge--error   { background: var(--danger-bg); color: var(--danger); }
.badge--info    { background: var(--info-bg);   color: var(--info); }

/* ══ 로또 공 ═══════════════════════════════════════════════════
   lotto_ball 매크로와 짝이다. 동행복권 공식 배색은 테마와 무관하게 고정이다. */
.lotto-ball {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--r-full);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  color: var(--lotto-ball-ink-light);
  flex-shrink: 0;
}
.ball-y { background: var(--lotto-ball-1); color: var(--lotto-ball-ink-dark); }  /* 1–10 */
.ball-b { background: var(--lotto-ball-2); }                                     /* 11–20 */
.ball-r { background: var(--lotto-ball-3); }                                     /* 21–30 */
.ball-g { background: var(--lotto-ball-4); }                                     /* 31–40 */
.ball-p { background: var(--lotto-ball-5); color: var(--lotto-ball-ink-dark); }  /* 41–45 */
.lotto-ball--bonus { box-shadow: 0 0 0 2px var(--bg-surface), 0 0 0 4px var(--text-secondary); }

/* ══ 버튼 ══════════════════════════════════════════════════════ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 12px var(--sp-4);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  text-decoration: none;
  cursor: pointer;
  min-height: 44px;
  white-space: nowrap;
  transition: background var(--motion-fast) var(--ease),
              border-color var(--motion-fast) var(--ease);
}
@media (min-width: 1024px) {
  .btn { min-height: 40px; padding: 9px var(--sp-4); }
}

.btn--primary   { background: var(--accent); color: var(--text-on-accent); }
.btn--primary:not(:disabled):hover { background: var(--accent-hover); }
.btn--secondary { background: var(--bg-surface); color: var(--text-secondary); border-color: var(--border-strong); }
.btn--secondary:not(:disabled):hover { background: var(--bg-surface-alt); }
.btn--danger    { background: var(--danger); color: var(--text-on-accent); }
.btn--ghost     { background: transparent; color: var(--accent); }
.btn--ghost:not(:disabled):hover { background: var(--accent-soft); }
.btn:disabled   { background: var(--bg-surface-alt); color: var(--text-muted); cursor: not-allowed; border-color: transparent; }

.btn--sm { min-height: 32px; padding: 4px var(--sp-3); font-size: var(--fs-xs); }

.btn-row { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); }
.btn-row > button, .btn-row > .btn { flex: 1; }

/* ══ 폼 필드 ═══════════════════════════════════════════════════ */
.field { margin-bottom: var(--sp-4); overflow: hidden; }
.field-label {
  display: block;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  margin-bottom: var(--sp-1);
}
.field-required { color: var(--danger); margin-left: 2px; }
.field-hint {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin-top: var(--sp-1);
}
.field-error {
  font-size: var(--fs-xs);
  color: var(--danger);
  margin-top: var(--sp-1);
}
/* 체크박스·라디오 — checkbox() 매크로와 cgv/weather/복권의 라디오가 함께 쓴다.
   crawl.css 에만 있어서 그 파일을 싣지 않는 페이지에서는 라벨이 세로로 쌓였다. */
.check-label {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  cursor: pointer;
  font-size: var(--fs-base);
  color: var(--text-primary);
  margin-bottom: 0;
}
.check-label input[type="checkbox"],
.check-label input[type="radio"] { margin-top: 3px; flex-shrink: 0; }
.check-field { margin-bottom: var(--sp-4); }

.field-row { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.field-row > .field { flex: 1; min-width: 160px; }
@media (max-width: 639px) {
  .field-row { flex-direction: column; gap: 0; }
  .field-row > .field { min-width: 0; width: 100%; }
}

/* ══ 데이터 목록 — A안의 핵심 ═══════════════════════════════════
   같은 데이터를 모바일에서는 카드, 데스크톱에서는 표로 렌더링한다.
   모바일에서 정보를 숨기지 않는다. 배치만 바꾼다. */
.datalist-cards { display: flex; flex-direction: column; gap: var(--sp-2); }
.datalist-table-wrap { display: none; }

.dl-card {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-1) var(--sp-3);
  align-items: start;
  min-height: 56px;
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.dl-card-title {
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  color: var(--text-primary);
  min-width: 0;
  overflow-wrap: anywhere;
}
.dl-card-badge { grid-column: 2; grid-row: 1; justify-self: end; }
.dl-card-meta {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.dl-card-meta > span:not(:last-child)::after {
  content: "·";
  margin-left: var(--sp-2);
  color: var(--border-strong);
}
.dl-card-actions {
  grid-column: 1 / -1;
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-1);
}
.dl-card-actions > * { flex: 1; }

.dl-empty {
  padding: var(--sp-8) var(--sp-4);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--fs-base);
  background: var(--bg-surface);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
}
.dl-empty-action { margin-top: var(--sp-3); }

@media (min-width: 1024px) {
  .datalist-cards { display: none; }
  .datalist-table-wrap {
    display: block;
    overflow-x: auto;
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--bg-surface);
  }
  .dl-table { font-size: var(--fs-sm); }
  .dl-table th {
    background: var(--bg-surface-alt);
    color: var(--text-secondary);
    font-weight: var(--fw-medium);
    font-size: var(--fs-xs);
    letter-spacing: 0.06em;
    padding: var(--sp-2) var(--sp-4);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
  }
  .dl-table td {
    padding: var(--sp-2) var(--sp-4);
    height: 44px;
    border-bottom: 1px solid var(--border-light);
    color: var(--text-secondary);
    vertical-align: middle;
  }
  .dl-table tbody tr:last-child td { border-bottom: none; }
  .dl-table tbody tr:hover { background: var(--bg-surface-alt); }
  .dl-table td.dl-col-title {
    color: var(--text-primary);
    font-weight: var(--fw-medium);
  }
  /* 정렬 가능한 헤더 — 데스크톱에만 있는 입력을 놀리지 않는다 */
  .dl-table th.is-sortable { cursor: pointer; user-select: none; }
  .dl-table th.is-sortable:hover { color: var(--text-primary); }
  .dl-table th.is-sortable::after { content: " ↕"; opacity: 0.35; }
  .dl-table th[aria-sort="ascending"]::after  { content: " ↑"; opacity: 1; color: var(--accent); }
  .dl-table th[aria-sort="descending"]::after { content: " ↓"; opacity: 1; color: var(--accent); }
}

/* ══ 지표 타일 ═════════════════════════════════════════════════ */
.tile-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
}
@media (min-width: 640px) { .tile-grid { grid-template-columns: repeat(4, 1fr); gap: var(--sp-3); } }

.tile {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-3);
  text-align: center;
}
.tile-value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-2xl);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  color: var(--text-primary);
}
@media (min-width: 640px) { .tile-value { font-size: var(--fs-3xl); } }
.tile-unit { font-size: 0.6em; font-weight: var(--fw-normal); }
.tile-label { font-size: var(--fs-xs); color: var(--text-muted); }
.tile--ok     .tile-value { color: var(--ok); }
.tile--warn   .tile-value { color: var(--warn); }
.tile--danger .tile-value { color: var(--danger); }
.tile--zero   .tile-value { color: var(--text-muted); }

/* ══ 진행률 ════════════════════════════════════════════════════ */
.progress {
  height: 6px;
  border-radius: var(--r-full);
  background: var(--bg-surface-alt);
  overflow: hidden;
}
.progress-fill {
  display: block;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--accent);
  transition: width var(--motion-base) var(--ease);
}
.progress--warn .progress-fill   { background: var(--warn); }
.progress--danger .progress-fill { background: var(--danger); }
.progress-label {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin-bottom: var(--sp-1);
}

/* ══ 빈 상태 ═══════════════════════════════════════════════════ */
.empty-msg {
  color: var(--text-muted);
  font-size: var(--fs-base);
  text-align: center;
  padding: var(--sp-6) 0;
}

/* ══ 로그 박스 ═════════════════════════════════════════════════ */
.logbox {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-primary);
  line-height: var(--lh-base);
  max-height: 260px;
  overflow-y: auto;
}
@media (max-width: 480px) { .logbox { max-height: 200px; } }
.log-progress::before { content: "⏳ "; }
.log-done::before     { content: "✅ "; }
.log-done             { color: var(--ok); }
.log-error::before    { content: "❌ "; }
.log-error            { color: var(--danger); }
.log-queued::before   { content: "🕐 "; }
.log-queued           { color: var(--warn); }
.log-info::before     { content: "🔍 "; }
.log-end              { color: var(--text-muted); font-style: italic; }

/* ══ 토스트 ════════════════════════════════════════════════════
   구 cgv.html 인라인 구현(z-index:9999)을 대체한다. */
.toast-stack {
  position: fixed;
  left: var(--sp-4);
  right: var(--sp-4);
  bottom: calc(var(--tabbar-h) + var(--sp-4) + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  pointer-events: none;
}
@media (min-width: 1024px) {
  .toast-stack {
    left: auto;
    right: var(--sp-6);
    bottom: auto;
    top: var(--sp-6);
    width: 360px;
    max-width: calc(100vw - var(--sp-12));
  }
}
.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--bg-surface);
  box-shadow: var(--shadow-overlay);
  font-size: var(--fs-base);
  color: var(--text-primary);
  pointer-events: auto;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--motion-base) var(--ease),
              transform var(--motion-base) var(--ease);
}
.toast.is-shown { opacity: 1; transform: none; }
.toast--ok    { border-left: 3px solid var(--ok); }
.toast--warn  { border-left: 3px solid var(--warn); }
.toast--error { border-left: 3px solid var(--danger); }
.toast--info  { border-left: 3px solid var(--info); }
.toast-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: var(--fs-md);
  line-height: 1;
  padding: 0 var(--sp-1);
  min-height: 0;
  cursor: pointer;
}

/* ══ 확인 대화상자 ═════════════════════════════════════════════ */
.dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--overlay-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
}
.dialog {
  background: var(--bg-surface);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-overlay);
  padding: var(--sp-5);
  width: 100%;
  max-width: 400px;
  z-index: var(--z-modal);
}
.dialog-title {
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  margin-bottom: var(--sp-2);
}
/* 폼이 들어가는 모달 — 확인 대화상자보다 넓고, 넘치면 안에서 스크롤한다 */
.dialog--wide { max-width: 520px; max-height: 85vh; overflow-y: auto; }
.dialog-body { color: var(--text-secondary); margin-bottom: var(--sp-5); }
.dialog-actions { display: flex; gap: var(--sp-2); }
.dialog-actions > .btn { flex: 1; }

/* ══ 요일 · 날짜 다중 선택 ══════════════════════════════════════ */
.day-picker { border: none; }
.day-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--sp-1);
  margin-bottom: var(--sp-2);
}
@media (min-width: 640px) {
  .day-grid--month { grid-template-columns: repeat(14, 1fr); }
}
.day-chip {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  cursor: pointer;
  margin-bottom: 0;
  transition: background var(--motion-fast) var(--ease),
              border-color var(--motion-fast) var(--ease);
}
.day-chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.day-chip:hover { border-color: var(--accent); }
.day-chip:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.day-chip:has(input:checked) {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: var(--fw-bold);
}

textarea { resize: vertical; min-height: 80px; }

/* ══ 도구 페이지 공통 표 셀 ═════════════════════════════════════ */
.tool-table-wrap { display: block; overflow-x: auto; }
.tool-cell-text { max-width: 300px; overflow-wrap: anywhere; }
.tool-cell-url  { overflow-wrap: anywhere; }
.tool-cell-sm   { font-size: var(--fs-xs); }
.tool-thumb     { max-width: 60px; max-height: 40px; object-fit: cover; border-radius: var(--r-sm); }
.tool-ac-field  { position: relative; }

/* 입력 아래 붙는 예시·힌트 상자 — 파일 다운로드·스크래핑·주식 분석이 함께 쓴다 */
.tool-hint-box {
  margin-top: var(--sp-4);
  background: var(--bg-surface);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
}
.tool-hint-title {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin: 0 0 var(--sp-2);
  font-weight: var(--fw-medium);
}
.tool-hint-tags { display: flex; flex-wrap: wrap; gap: var(--sp-1); }

.tool-error {
  background: var(--danger-bg);
  color: var(--danger);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  font-size: var(--fs-base);
}
.tool-desc { color: var(--text-muted); font-size: var(--fs-base); margin-bottom: var(--sp-4); }

/* datalist 슬롯 영역 */
.dl-card-body { grid-column: 1 / -1; }
.dl-row-actions { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
.dl-row-actions form { display: inline; }
@media (min-width: 1024px) {
  .dl-detail-row td { background: var(--bg-surface-alt); padding-top: 0; }
}
.is-disabled { opacity: 0.55; }

/* ══ 접기·펼치기 ════════════════════════════════════════════════
   datalist 의 detail 슬롯에서 쓴다. 다운로드 스케줄·CGV·사이트 감시가
   crawl.css 의 .cr-details 를 참조하면서 그 파일은 싣지 않아 세 페이지 중
   둘이 스타일 없이 렌더링되고 있었다. 두 곳 이상이 쓰므로 여기로 올린다. */
.details {
  grid-column: 1 / -1;
  margin-top: var(--sp-2);
}
.details summary {
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--accent);
  padding: var(--sp-1) 0;
  list-style: none;
}
.details summary::-webkit-details-marker { display: none; }
.details summary::before { content: "▸ "; }
.details[open] > summary::before { content: "▾ "; }
.details summary:hover { text-decoration: underline; }

/* ══ 화면 내 탭 ═════════════════════════════════════════════════
   앱 셸의 탭(하단·사이드바)과는 다른 층위다. 한 페이지 안에서
   보기를 전환할 때 쓴다. 이전에는 6개 페이지가 각자 구현했다.

   링크형(<a>)과 패널형(<button>)이 같은 모양을 쓴다. 짝이 되는
   매크로는 tabs() / tab_panel(), 동작은 maru.js가 담당한다.

   아래 경계선을 컨테이너의 inset 그림자로 그리는 이유:
   이전에는 컨테이너에 border-bottom을 주고 탭에 margin-bottom:-1px 로
   겹쳤는데, overflow-x:auto 는 overflow-y 를 auto 로 만들기 때문에
   그 1px 이 세로 넘침이 되어 탭 줄에 스크롤바가 생겼다. */
.tabs {
  display: flex;
  gap: var(--sp-1);
  margin-bottom: var(--sp-6);
  box-shadow: inset 0 -1px 0 var(--border);
  overflow-x: auto;
  overflow-y: hidden;
  /* 탭은 좌우로 밀어서 본다. 막대는 감춘다 — 자리를 차지해 탭이 잘린다. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-base);
  color: var(--text-muted);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  min-height: 44px;            /* 터치 대상 최소 크기 */
}
@media (min-width: 1024px) {
  .tab { min-height: 40px; }
}
.tab:hover { color: var(--text-primary); }
.tab:focus-visible { outline-offset: -3px; }
.tab.is-active {
  color: var(--accent);
  font-weight: var(--fw-bold);
  border-bottom-color: var(--accent);
}

/* .tab-panel 에는 display 규칙을 두지 않는다. 패널의 가시성은 hidden 속성
   하나로만 다루고(UI_STANDARDS 4.2), 클래스는 maru.js가 패널을 찾는 표시로만 쓴다. */

/* ══ 칩 ═════════════════════════════════════════════════════════
   짧은 라벨. 누를 수 있으면 .chip--action. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 3px var(--sp-2);
  border-radius: var(--r-full);
  background: var(--bg-surface-alt);
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  white-space: nowrap;
}
.chip--action { cursor: pointer; border: 1px solid var(--border); text-decoration: none; }
.chip--action:hover { border-color: var(--accent); color: var(--accent); }
.chip--info { background: var(--info-bg); color: var(--info); }
.chip--ok   { background: var(--ok-bg);   color: var(--ok); }
.chip--warn { background: var(--warn-bg); color: var(--warn); }

/* ══ 플래시 메시지 ══════════════════════════════════════════════ */
.flash-messages { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.flash-msg {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  font-size: var(--fs-base);
  border: 1px solid transparent;
}
.flash-msg.flash-error   { background: var(--danger-bg); color: var(--danger); border-color: var(--danger); }
.flash-msg.flash-success { background: var(--ok-bg);     color: var(--ok);     border-color: var(--ok); }
.flash-msg.flash-warning { background: var(--warn-bg);   color: var(--warn);   border-color: var(--warn); }

/* ══ 카드 격자 ══════════════════════════════════════════════════ */
/* ── 카드 (트럼프) ─────────────────────────────────────────────
   7포커·블랙잭이 같이 쓴다. 앱은 무슨 카드인지 모르므로 **상태만** 그린다.

     --back  뒷면 (안 보이게 받은 카드)
     --open  앞면이지만 무엇인지는 모름 (보이게 받은 카드)
     --face  값을 알려 준 카드 (블랙잭 딜러 업카드)
     --ask   눌러서 알려 달라는 자리
     --laid  눕힌 카드 (블랙잭 더블)

   유니코드 카드 문자는 기기마다 모양이 다르고 안 나오는 데도 있다.
   칩을 이모지 대신 CSS 원으로 그린 것과 같은 이유로 여기서도 CSS로 그린다. */

.pcards-row {
  display: flex;
  align-items: center;
  padding-left: var(--sp-1);
}

.pcard {
  width: 26px;
  height: 36px;
  flex: none;
  margin-left: -8px;              /* 실제 테이블처럼 겹쳐 쥔다 */
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--bg-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  line-height: 1;
}
.pcard:first-child { margin-left: 0; }

.pcard--back {
  background-color: var(--accent-soft);
  background-image: repeating-linear-gradient(
    45deg, transparent 0 3px, var(--bg-surface) 3px 6px);
  color: transparent;
}

.pcard--open { background: var(--bg-surface); }
.pcard--face { background: var(--bg-surface); color: var(--text-primary); }

.pcard--ask {
  border-style: dashed;
  color: var(--text-muted);
  cursor: pointer;
}

.pcard--laid { transform: rotate(90deg); margin-left: 2px; }

/* 끝난 손·빠진 사람의 카드는 흐리게 */
.pcards-row--dim { opacity: 0.45; }

/* 좁은 칸용 — 7포커는 좌석이 한 줄에 네댓 칸이라 기본 크기로는 이름을 밀어낸다 */
.pcards-row--sm .pcard {
  width: 16px;
  height: 22px;
  margin-left: -6px;
  font-size: var(--fs-xs);
}

/* 더 좁은 칸용 — 7포커가 치는 중일 때의 좌석(58px)에 7장이 들어가야 한다.
   7 × (11 - 4) + 4 = 53px */
.pcards-row--xs .pcard {
  width: 11px;
  height: 16px;
  margin-left: -4px;
  font-size: var(--fs-xs);
}


/* ── 차례 줄 ───────────────────────────────────────────────────
   「나 → 민지 → 영수」처럼 사람 순서를 늘어놓는다. 7포커의 걸기 순서와
   두 게임의 카드 나눠주는 순서가 같이 쓴다. 첫 사람만 강조한다. */

.order-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1) var(--sp-2);
  margin-top: var(--sp-2);
}

.order-name { font-size: var(--fs-md); color: var(--text-secondary); }
.order-name.is-first { color: var(--accent); font-weight: var(--fw-bold); }
.order-sep { color: var(--text-muted); font-size: var(--fs-sm); }


.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-3);
}
@media (min-width: 640px)  { .card-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1440px) { .card-grid { grid-template-columns: repeat(3, 1fr); } }
