/* =========================================================
   2SHIN 앱 셸 (App Shell) — 2026-08-08 신규
   Capacitor 하이브리드 앱(안드로이드/iOS)에서 "웹사이트를 웹뷰에 띄운 것"이 아니라
   네이티브 앱처럼 보이고 만져지게 만드는 층.

   왜 별도 파일인가:
   2shin.css는 863줄 한 덩어리라 여기에 앱 규칙을 섞으면 되돌리기가 어렵다.
   이 파일은 **2shin.css 다음에** 로드되어 필요한 것만 덮어쓴다. 통째로 빼면 원래 사이트로 돌아간다.

   적용 범위 3단계:
   1) 전역     — 브라우저·앱 공통(터치 하이라이트, iOS 입력 확대 차단 등). 데스크톱에 무해한 것만.
   2) .is-app  — 웹뷰/홈화면 실행일 때만. 2shin.js가 <html>에 붙인다.
   3) 컴포넌트 — 앱형 UI 부품(페이지헤더/리스트행/바텀시트/세그먼트/FAB/스켈레톤).
      화면 개편 때 하나씩 갈아끼우려고 미리 정의해 둔다.
   ========================================================= */

:root {
  /* ── 간격 스케일 ──────────────────────────────────────────
     기존 CSS는 여백이 전부 리터럴 px이라 "앱에서만 조금 촘촘하게" 같은 조정을
     일괄로 할 수 없었다. 4px 배수 스케일을 도입해 새 규칙부터 여기에 맞춘다. */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 20px;  --sp-6: 24px;  --sp-8: 32px;  --sp-10: 40px;

  /* ── 타이포 스케일 ────────────────────────────────────────
     웹보다 한 단계씩 크다. 앱은 팔 길이에서 한 손으로 보는 화면이라
     "정보를 많이" 보다 "한눈에 읽힘"이 먼저다. 단계 수도 줄여 위계를 뚜렷하게 했다. */
  --fs-xs: 12px;   --fs-sm: 13.5px; --fs-base: 16px;
  --fs-md: 18px;   --fs-lg: 22px;   --fs-xl: 28px;

  /* ── 안전영역 ─────────────────────────────────────────────
     ⚠ 이 값들은 <meta viewport>에 viewport-fit=cover가 있어야만 0이 아닌 값이 온다.
       2026-08-08 이전엔 그게 없어서, 탭바에 써둔 env(safe-area-inset-bottom)이
       조용히 전부 0으로 계산되고 있었다(CSS는 멀쩡한데 홈바에 가려지던 원인). */
  --sa-top: env(safe-area-inset-top, 0px);
  --sa-bottom: env(safe-area-inset-bottom, 0px);

  /* 하단 탭바 실제 점유 높이 — 본문 하단 여백·떠 있는 요소들이 공통으로 참조한다 */
  --tabbar-h: calc(60px + var(--sa-bottom));
  --header-h: 68px;
}

/* =========================================================
   1) 전역 — 브라우저에서도 켠다 (데스크톱에 부작용 없는 것만)
   ========================================================= */

/* 탭할 때 안드로이드 크롬이 씌우는 회색 사각형. 웹에선 익숙하지만 앱에선 즉시 "웹뷰구나" 티가 난다. */
* { -webkit-tap-highlight-color: transparent; }

body {
  /* 스크롤이 끝에 닿았을 때 페이지 전체가 딸려 움직이는 고무줄 효과 차단.
     none이 아니라 contain인 이유: none은 모달 안쪽 스크롤까지 막아버리는 브라우저가 있다. */
  overscroll-behavior-y: contain;
  /* ⚠ -webkit-touch-callout:none 은 쓰지 않는다. 길게 눌러 나오는 '복사' 메뉴까지 막혀
     공고번호를 복사할 수 없게 된다(2026-08-09 실사용에서 확인). 링크 미리보기 팝업이
     조금 뜨는 것보다 복사가 되는 쪽이 훨씬 중요하다. */
}
input, textarea, select, [contenteditable] {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
}

/* iOS는 폰트가 16px 미만인 입력에 포커스가 가면 **화면을 강제로 확대한다**.
   확대된 뒤엔 자동으로 원복되지 않아 레이아웃이 깨진 것처럼 보인다.
   maximum-scale로 막는 방법은 확대 자체를 봉인해 접근성을 해치므로, 폰트를 키워 해결한다. */
@media (max-width: 1024px) {
  .form-control, input[type="text"], input[type="password"], input[type="email"],
  input[type="tel"], input[type="number"], input[type="search"], input[type="date"],
  textarea, select { font-size: 16px; }
}

/* 상단 안전영역 — 노치/다이나믹아일랜드 아래로 헤더가 파고들지 않게.
   sticky 헤더라 padding으로 밀면 스크롤 시 상태바 뒤가 비어 보이지 않고 자연스럽게 이어진다. */
.nav { padding-top: var(--sa-top); }

/* 터치 타깃 44px — 애플/구글 양쪽 가이드라인의 최소치.
   기존 값들이 7~9px 패딩이라 손가락으로는 자주 빗나갔다. */
@media (max-width: 1024px) {
  .btn { min-height: 44px; }
  .btn-sm { min-height: 38px; padding: 9px 14px; }
  .pill-tabs a { min-height: 40px; display: inline-flex; align-items: center; }
  .mobile-nav-group a, .nav-drop-panel a { min-height: 44px; display: flex; align-items: center; }
}

/* =========================================================
   2) .is-app — 웹뷰/홈화면 실행 전용
   ========================================================= */

/* 앱에선 화면 폭과 무관하게 하단 탭이 항상 있어야 한다.
   2shin.css의 탭바는 @media(max-width:1024px)에 갇혀 있어 태블릿·가로모드에서 사라진다. */
html.is-app .tabbar { display: flex; }
html.is-app body { padding-bottom: calc(var(--tabbar-h) + var(--sp-5)); }

/* 앱에는 브라우저 주소창이 없으므로, 웹사이트용 부속을 걷어낸다.
   ⚠ 푸터를 통째로 숨기면 안 된다 — 사업자 표기(상호·대표·주소·연락처·사업자번호)는
   전자상거래법 제10조상 앱 화면에서도 보여야 하고, PG 심사도 모바일로 확인한다(2026-08-16).
   링크 그리드와 SEO 링크만 숨기고 면책문구+사업자정보(.footer-bottom)는 남긴다. */
html.is-app .footer-grid { display: none; }              /* 메뉴 링크는 '내 정보'의 둘러보기가 대신한다 */
html.is-app .footer-bottom .footer-links { display: none; }  /* 지역/업종 SEO 링크는 웹 전용 */
html.is-app .footer { margin-top: var(--sp-5); padding: 20px 0 16px; }
html.is-app .footer-bottom { border-top: 0; padding-top: 0; }

/* 사이트 상단바(브랜드+메뉴+햄버거) 통째로 교체.
   아래에 탭바가 있는데 위에도 메뉴가 있으면 길이 두 갈래가 되어 웹사이트로 읽힌다.
   앱은 "지금 어느 화면인가"만 위에 쓴다. */
html.is-app .nav { display: none; }
html.is-app .appbar { display: flex; }

/* 앱바가 화면 이름을 이미 달고 있으므로, 본문 맨 위의 같은 제목은 지운다.
   제목이 두 번 나오는 건 웹사이트에서 흔하지만 앱에선 바로 어색하게 읽힌다.
   ⚠ 줄 전체를 display:none 하면 안 된다 — 이 줄의 우측 액션(필터·저장 버튼)까지 같이 사라진다.
     h1만 지우고, 액션이 없으면(=.act를 아예 렌더링하지 않으면) 줄이 저절로 접히게 둔다. */
html.is-app .app-head.page-title { min-height: 0; margin-bottom: 0; }
html.is-app .app-head.page-title > h1 { display: none; }
html.is-app .app-head.page-title > .act { margin: 0 0 var(--sp-3) auto; }

/* ---------- 앱바 ---------- */
.appbar {
  display: none;   /* 브라우저에선 사이트 상단바가 그대로 쓰인다 */
  position: sticky; top: 0; z-index: 50;
  align-items: center; gap: var(--sp-2);
  height: 52px; padding: var(--sa-top) var(--sp-4) 0;
  box-sizing: content-box;
  background: var(--y-nav-bg-solid);
  -webkit-backdrop-filter: saturate(180%) blur(12px); backdrop-filter: saturate(180%) blur(12px);
  /* 본문과 경계가 없으면 제목 줄이 허공에 뜬 것처럼 허전하다.
     스크롤이 내려갔을 때만 선이 생기게 하면(아래 .is-scrolled) 평소엔 깔끔하고
     내용이 밀려 올라갈 때는 경계가 잡힌다. */
  border-bottom: 1px solid transparent;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.appbar.is-scrolled {
  border-bottom-color: var(--y-line);
  box-shadow: 0 6px 18px rgba(11,14,20,.05);
}
.ab-title {
  flex: 1 1 auto; min-width: 0; font-size: var(--fs-md); font-weight: 800; letter-spacing: -.03em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 탭 뿌리 화면(뒤로가기가 없는 곳)에서는 제목 왼쪽이 비어 허전하다 — 브랜드 마크로 채운다. */
.ab-mark {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 9px;
  background: var(--y-brand); color: #fff;
  display: grid; place-items: center;
  font-size: 11.5px; font-weight: 800; letter-spacing: -.05em;
}
.ab-back, .ab-act {
  flex: 0 0 auto; width: 38px; height: 38px; border: 0; background: transparent; padding: 0;
  display: flex; align-items: center; justify-content: center; color: var(--y-ink);
  border-radius: 12px; cursor: pointer; position: relative;
}
.ab-back { margin-left: -9px; }
.ab-act { margin-right: -9px; }
.ab-back svg, .ab-act svg { width: 22px; height: 22px; }
.ab-back:active, .ab-act:active { background: var(--y-brand-tint); }
/* 읽지 않은 알림은 개수가 아니라 점 하나로. 앱바에 숫자까지 넣으면 다시 정보가 붐빈다. */
.ab-act .dot {
  position: absolute; top: 6px; right: 6px; width: 7px; height: 7px; border-radius: 999px;
  background: var(--y-danger); box-shadow: 0 0 0 2px var(--y-nav-bg-solid);
}

/* ⚠ 예전엔 `html.is-app body { user-select: none }`으로 본문 선택을 통째로 막았다.
   "앱은 문서가 아니라 화면"이라는 이유였는데, 그 결과 **공고번호·기관명·금액을 복사할 수 없었다.**
   공고번호를 복사해 나라장터에 붙여넣는 건 입찰 실무의 기본 동작이다 — 막을 이유가 없다.
   지금은 선택을 허용하고, **눌러서 넘어가는 조작 요소**에서만 끈다(스크롤 중 글자가 잡히는 것 방지). */
html.is-app .tabbar, html.is-app .appbar, html.is-app .btn,
html.is-app .tile, html.is-app .cnav, html.is-app .quick,
html.is-app .seg, html.is-app .chips, html.is-app .ps-foot,
html.is-app .chev, html.is-app .menu-row .mi, html.is-app .tl-go {
  -webkit-user-select: none; user-select: none;
}

/* 가로 스크롤은 앱에서 특히 사고로 읽힌다 — 손가락이 살짝 비스듬하면 화면이 옆으로 밀린다.

   ⚠ 이걸 예전엔 `html.is-app body { overflow-x: hidden }`으로 걸었다. 그게
   **하단 탭바가 사라지는 버그의 원인**이었다. body에 overflow를 주면 WebKit에서
   body가 스크롤 컨테이너가 되고, 그 안의 `position: fixed`가 뷰포트가 아니라
   **문서 전체를 기준으로 붙는다.** 그래서 탭바가 화면 맨 아래가 아니라
   '문서 맨 아래'(수천 px 아래)로 내려가 안 보이고 누를 수도 없었다.
   증상이 긴 페이지(알림함·외자통계·투찰성향)에서만 두드러졌던 것도 이 때문이다 —
   앱바는 문서 맨 위라 제자리처럼 보여서 이상을 못 느꼈다.

   `clip`은 `hidden`과 달리 **스크롤 컨테이너를 만들지 않는다.** 잘라내기만 한다.
   대상도 body가 아니라 html이어야 한다. */
html.is-app { overflow-x: clip; }

/* =========================================================
   3) 앱형 컴포넌트
   화면을 하나씩 개편하며 갖다 쓰는 부품들. 아직 쓰이지 않아도 여기 모아둔다.
   ========================================================= */

/* ---------- 밀도 ----------
   "앱 같지 않다"의 정체는 배치보다 밀도였다. 웹은 한 화면에 최대한 담는 게 미덕이지만
   앱은 반대다 — 한 화면에 한 가지. 아래 세 가지로 밀도를 낮춘다.
     1) 테두리 제거: 카드마다 두른 1px 선이 화면을 격자로 쪼개 문서처럼 보이게 한다.
        카드는 바탕색 차이만으로 뜨게 하고, 구분은 여백이 한다.
     2) 여백 확대: 카드 안팎을 넉넉히.
     3) 모서리 확대: 12/16px은 웹의 값이다. 앱은 18~20px에서 부드럽게 읽힌다.
   ------------------------------------------------------------- */
@media (max-width: 1024px) {
  .card {
    border: 0;
    border-radius: 18px;
    padding: var(--sp-5);
    box-shadow: none;
  }
  /* 섹션 사이는 선이 아니라 공간으로 나눈다 */
  .container > section + section { margin-top: var(--sp-8); }
}

/* ---------- 페이지 헤더 (제목 + 뒤로가기 + 우측 액션) ---------- */
.app-head {
  display: flex; align-items: center; gap: var(--sp-2);
  min-height: 44px; margin: 0 0 var(--sp-4);
}
/* 화면 중간의 섹션 제목. 인라인 style="margin-top:22px"를 곳곳에 박는 대신 이 클래스를 쓴다. */
.app-head.sec { margin-top: var(--sp-6); }
/* 앞에 내용이 있는 app-head는 자동으로 위 여백을 갖는다(관리자 화면처럼 섹션이 여럿일 때) */
.table-wrap + .app-head, .card + .app-head, .list + .app-head, .empty + .app-head,
.metric-strip + .app-head, .tile-card + .app-head { margin-top: var(--sp-6); }
.app-head .back {
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; margin-left: -10px; border-radius: 12px;
  color: var(--y-ink); flex: 0 0 auto;
}
.app-head .back:hover, .app-head .back:active { background: var(--y-brand-tint); text-decoration: none; }
.app-head .back svg { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.app-head h1 { font-size: var(--fs-lg); margin: 0; flex: 1 1 auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.app-head .act { flex: 0 0 auto; display: flex; gap: var(--sp-2); }

/* ---------- 리스트 행 — 모바일에서 표를 대체하는 기본 단위 ----------
   규칙: **두 줄까지**. 제목 한 줄(최대 2행) + 보조정보 한 줄.
   보조정보에 기관·금액·계약방법·마감을 다 넣으면 줄이 접히면서 행마다 높이가 달라지고,
   그 들쭉날쭉함이 "앱이 아니라 표를 카드로 바꾼 것"처럼 보이게 한다.
   금액은 오른쪽에 큰 숫자로 따로 세운다 — 목록에서 눈이 가장 먼저 가는 값이다. */
.list { display: flex; flex-direction: column; }
.list-row {
  display: flex; align-items: center; gap: var(--sp-3);
  /* 한 화면에 한 건이라도 더 — 목록은 스크롤 길이가 곧 피로다 */
  padding: var(--sp-3) var(--sp-1); min-height: 58px;
  border-bottom: 1px solid var(--y-line); color: var(--y-ink);
}
.list-row:last-child { border-bottom: none; }
.list-row:active { background: var(--y-brand-tint); }
.list-row:hover { text-decoration: none; }
.list-row .body { flex: 1 1 auto; min-width: 0; }
.list-row .ttl {
  font-weight: 700; font-size: var(--fs-base); line-height: 1.38; letter-spacing: -.02em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  word-break: keep-all;  /* 한글은 단어 중간에서 끊으면 읽기 어렵다 */
}
.list-row .sub {
  margin-top: 4px; font-size: var(--fs-sm); color: var(--y-muted);
  display: flex; align-items: center; gap: var(--sp-2);
  /* 한 줄 고정 — 넘치면 접지 말고 자른다 */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.list-row .sub > * { flex: 0 0 auto; }
.list-row .sub .org { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }
.list-row .chev { flex: 0 0 auto; color: var(--y-muted2); }
.list-row .chev svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* 오른쪽 금액 열 */
.list-row .tail { flex: 0 0 auto; text-align: right; }
.list-row .tail .amt {
  font-size: var(--fs-base); font-weight: 800; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.list-row .tail .cd { margin-top: 2px; font-size: var(--fs-xs); font-weight: 700; color: var(--y-on-danger); white-space: nowrap; }
.list-row .tail .cd.far { color: var(--y-muted); font-weight: 600; }

/* ---------- 바텀시트 — 앱에서 필터/선택은 새 페이지가 아니라 아래에서 올라온다 ---------- */
.sheet-backdrop {
  position: fixed; inset: 0; z-index: 150; background: rgba(11,14,20,.42);
  opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
.sheet-backdrop.open { opacity: 1; pointer-events: auto; }

/* ⚠ 안전한 퇴화(safe degradation).
   시트를 띄우는 것은 app.js다. 그래서 기본 상태를 "화면 밖"으로 두면,
   JS가 로드 실패하거나 그 위에서 예외가 나는 순간 시트 안의 폼에 **아예 도달할 수 없다**
   (관리자 등록 폼 5개가 여기 들어 있다 — 예전엔 JS 없이도 보이던 것들이다).
   그래서 감추는 규칙은 <html>에 sheets-ready가 붙었을 때만 적용한다.
   JS가 죽으면 시트는 그냥 본문에 펼쳐진 카드로 남는다 — 보기엔 투박해도 쓸 수는 있다. */
.sheet {
  background: var(--y-card); border-radius: 20px;
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
  margin-top: var(--sp-4);
}
html.sheets-ready .sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 151;
  margin-top: 0; border-radius: 20px 20px 0 0;
  border-top: 1px solid var(--y-line);
  max-height: 86vh; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--sp-2) var(--sp-5) calc(var(--sp-6) + var(--sa-bottom));
  transform: translateY(100%); transition: transform .26s cubic-bezier(.32,.72,0,1);
}
html.sheets-ready .sheet.open { transform: translateY(0); }
/* 손잡이 — "아래로 끌어 닫을 수 있다"는 신호. 실제 드래그는 app.js가 처리한다.
   JS가 없으면 시트가 아니라 그냥 카드이므로 손잡이도 띄우지 않는다. */
html.sheets-ready .sheet::before {
  content: ""; display: block; width: 38px; height: 4px; margin: var(--sp-2) auto var(--sp-4);
  border-radius: 999px; background: var(--y-line-strong);
}
.sheet h3 { font-size: var(--fs-md); margin: 0 0 var(--sp-4); }
/* JS가 없으면 여는 버튼도 의미가 없다 — 시트가 이미 보이므로 감춘다 */
html:not(.sheets-ready) [data-sheet-open],
html:not(.sheets-ready) [data-sheet-close] { display: none; }

/* ---------- 세그먼트 컨트롤 — 2~4개 중 하나 고르기 ---------- */
.seg {
  display: flex; gap: 2px; padding: 3px; border-radius: 12px;
  background: var(--y-bg); border: 1px solid var(--y-line);
}
.seg a, .seg button {
  flex: 1 1 0; min-width: 0; min-height: 38px; border: 0; background: transparent;
  display: flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: var(--fs-sm); font-weight: 700; color: var(--y-muted);
  border-radius: 9px; cursor: pointer;
}
.seg a.active, .seg button.active {
  background: var(--y-card); color: var(--y-brand); box-shadow: var(--y-shadow-sm);
  text-decoration: none;
}

/* ---------- 칩 — 가로 스크롤 필터 ---------- */
.chips {
  display: flex; gap: var(--sp-2); overflow-x: auto; padding-bottom: var(--sp-1);
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.chips::-webkit-scrollbar { display: none; }
.chip {
  flex: 0 0 auto; min-height: 36px; display: inline-flex; align-items: center;
  padding: 0 var(--sp-4); border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--y-line); background: var(--y-card);
  font-size: var(--fs-sm); font-weight: 700; color: var(--y-muted);
}
.chip.active { background: var(--y-brand); border-color: var(--y-brand); color: #fff; }
.chip:hover { text-decoration: none; }

/* ---------- FAB — 화면당 핵심 행동 하나 ---------- */
.fab {
  position: fixed; right: var(--sp-4); z-index: 80;
  bottom: calc(var(--tabbar-h) + var(--sp-4));
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 52px; padding: 0 var(--sp-5); border-radius: 999px;
  background: var(--y-brand); color: #fff; font-weight: 800; font-size: var(--fs-base);
  box-shadow: 0 6px 20px rgba(37,99,255,.34);
}
.fab:hover, .fab:active { text-decoration: none; color: #fff; }

/* ---------- 스켈레톤 — 빈 화면 대신 뼈대를 보여준다 ---------- */
.sk { background: var(--y-line); border-radius: 8px; animation: sk-pulse 1.4s ease-in-out infinite; }
.sk-line { height: 13px; margin-bottom: var(--sp-2); }
@keyframes sk-pulse { 0%,100% { opacity: .55; } 50% { opacity: .95; } }

/* ---------- 빈 상태 ---------- */
.empty { text-align: center; padding: var(--sp-10) var(--sp-5); color: var(--y-muted); }
/* 이모지 대신 선 아이콘이 들어간다 — 원 안에 담아 다른 화면의 아이콘과 같은 언어를 쓰게 한다. */
.empty .ico {
  width: 62px; height: 62px; margin: 0 auto var(--sp-4); border-radius: 999px;
  background: var(--y-bg); color: var(--y-muted2);
  display: flex; align-items: center; justify-content: center;
}
.empty .ico .ico-svg { width: 28px; height: 28px; }
.empty .msg { font-size: var(--fs-base); font-weight: 700; color: var(--y-ink); margin-bottom: var(--sp-2); }
.empty .hint { font-size: var(--fs-sm); }

/* ---------- 인트로(스플래시) ----------
   앱을 켜면 서버에서 첫 화면을 받아오는 동안 흰 화면이 잠깐 뜬다. 그 사이가
   "느리다 / 멈췄다"로 읽히는 구간이라, 브랜드 화면으로 덮는다.
   네이티브 스플래시(Capacitor SplashScreen)는 앱 실행 순간만 담당하고
   웹뷰가 서버를 기다리는 구간은 못 덮는다 — 그 틈을 이게 메운다.

   세션당 한 번만 뜬다. 화면을 옮길 때마다 로고가 번쩍이면 그게 더 거슬린다. */
/* 기본은 숨김. <head>가 intro-pending을 찍었을 때만 뜬다 — 즉 앱에서, 세션 첫 화면에서만. */
.intro { display: none; }
html.intro-pending .intro {
  position: fixed; inset: 0; z-index: 400;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-4);
  background: var(--y-brand); color: #fff;
  transition: opacity .38s ease, visibility .38s ease;
}
html.intro-pending .intro.done { opacity: 0; visibility: hidden; pointer-events: none; }
.intro-mark {
  width: 76px; height: 76px; border-radius: 26px;
  background: rgba(255,255,255,.16); backdrop-filter: blur(4px);
  display: grid; place-items: center;
  font-size: 27px; font-weight: 800; letter-spacing: -.05em;
  animation: intro-pop .5s cubic-bezier(.2,.9,.3,1.4) both;
}
.intro-name { font-size: var(--fs-md); font-weight: 700; letter-spacing: -.03em; opacity: .92;
  animation: intro-fade .5s .12s ease both; }
.intro-dots { display: flex; gap: 6px; margin-top: var(--sp-2); }
.intro-dots i {
  width: 6px; height: 6px; border-radius: 999px; background: rgba(255,255,255,.55);
  animation: intro-blink 1s infinite ease-in-out;
}
.intro-dots i:nth-child(2) { animation-delay: .15s; }
.intro-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes intro-pop { from { transform: scale(.7); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes intro-fade { from { opacity: 0; transform: translateY(6px); } to { opacity: .92; transform: none; } }
@keyframes intro-blink { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .intro-mark, .intro-name, .intro-dots i { animation: none; }
}

/* ---------- 페이지 전환 진행바 ----------
   서버 렌더링이라 링크를 누르면 다음 화면이 그려질 때까지 아무 반응이 없다.
   앱에선 이 무반응 구간이 "멈췄나?"로 읽히므로 상단에 진행바를 띄운다. */
.navprog {
  position: fixed; top: 0; left: 0; height: 2.5px; width: 0; z-index: 300;
  background: var(--y-brand); opacity: 0; transition: width .2s ease, opacity .2s ease;
}
.navprog.on { opacity: 1; }

/* ---------- 관심공고 카드 ---------- */
.watch-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.watch-card { background: var(--y-card); border-radius: 18px; padding: var(--sp-5); }
/* 중지된 조건은 살아있는 것과 한눈에 구분돼야 한다 — 목록에 섞여 있으면 알림이 왜 안 오는지 모른다 */
.watch-card.off { opacity: .62; }
.wc-head { display: flex; align-items: center; gap: var(--sp-2); }
.wc-name { font-weight: 800; font-size: var(--fs-md); letter-spacing: -.02em; word-break: keep-all; }
.wc-head .badge { margin-left: auto; flex: 0 0 auto; }
.wc-cond { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2); margin-top: var(--sp-2); }
.wc-cond .cond {
  font-size: var(--fs-xs); font-weight: 600; color: var(--y-muted);
  background: var(--y-bg); border: 1px solid var(--y-line);
  padding: 2px 9px; border-radius: 999px;
}
.wc-cond .cond.kw { color: var(--y-brand); background: var(--y-brand-tint); border-color: var(--y-brand-tint2); }
.wc-act {
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--y-line);
}
.wc-act form { display: inline; }
.btn-sm.danger { color: var(--y-danger); }

/* ---------- 설정형 메뉴 목록 (내 정보 탭) ---------- */
.menu-title {
  font-size: var(--fs-sm); font-weight: 700; color: var(--y-muted2);
  margin: var(--sp-6) 0 var(--sp-2) var(--sp-4); letter-spacing: -.01em;
}
.menu-group {
  background: var(--y-card); border-radius: 18px; overflow: hidden;
}
.menu-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5); min-height: 56px;
  color: var(--y-ink);
}
/* 구분선은 아이콘 열을 비켜 시작한다 — 왼쪽 끝까지 그으면 목록이 표처럼 보인다 */
.menu-row + .menu-row { box-shadow: inset 0 1px 0 var(--y-line); }
.menu-row:hover, .menu-row:active { text-decoration: none; background: var(--y-brand-tint); }
.menu-row .mi { flex: 0 0 auto; width: 26px; font-size: 19px; line-height: 1; text-align: center; }
.menu-row .mt { flex: 1 1 auto; min-width: 0; font-size: var(--fs-base); font-weight: 600; letter-spacing: -.02em; }
.menu-row .chev { flex: 0 0 auto; color: var(--y-muted2); font-size: 20px; line-height: 1; }
.menu-row .theme-toggle { margin-left: auto; }
/* 설명줄. 회원 화면에서는 쓰지 않는다(R4) — 이름이 이미 말해주기 때문.
   비회원 랜딩에서는 다르다: 아직 이 서비스를 모르는 사람이라 한 줄이 필요하다. */
.menu-row .mt em {
  display: block; font-style: normal; font-weight: 500;
  font-size: var(--fs-sm); color: var(--y-muted); margin-top: 1px;
}
.menu-row .price-tag {
  flex: 0 0 auto; font-size: var(--fs-base); font-weight: 800; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; color: var(--y-ink);
}
.menu-row .price-tag small { font-size: var(--fs-xs); font-weight: 600; color: var(--y-muted); }

/* ---------- 하단 홍보 시트 ----------
   아래에서 주욱 올라와 화면 아래 1/3쯤을 덮는다. 얇은 띠는 눈에 안 들어와 홍보가 되지 않았다.
   덮는 만큼 닫을 길을 분명히 준다 — 오늘 하루 보지 않기 / 닫기 / 바깥 누르기. */
.promo-back {
  position: fixed; inset: 0; z-index: 150; background: rgba(11,14,20,.34);
  opacity: 0; transition: opacity .3s ease;
}
.promo-back.on { opacity: 1; }
/* 시트 하단 여백에 탭바 높이를 더해, 시트가 떠도 탭 이동은 막히지 않게 한다 */
.promo-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 151;
  background: var(--y-card); border-radius: 24px 24px 0 0;
  /* 탭바 높이를 더해 시트가 떠 있어도 탭 이동이 막히지 않게 한다 — 예전엔 z-index 151로
     탭바(90)를 통째로 덮어, 앱을 켜고 1.5초 뒤부터 화면 이동이 봉쇄됐다. */
  padding: var(--sp-2) var(--sp-5) calc(var(--sp-4) + var(--tabbar-h));
  box-shadow: 0 -10px 40px rgba(11,14,20,.22);
  transform: translateY(100%);
  transition: transform .42s cubic-bezier(.32,.72,0,1);
}
.promo-sheet.up { transform: translateY(0); }
.ps-grip {
  width: 38px; height: 4px; margin: var(--sp-2) auto var(--sp-4);
  border-radius: 999px; background: var(--y-line-strong);
}
.ps-tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px 5px 9px; border-radius: 999px;
  background: var(--y-brand-tint); color: var(--y-brand);
  font-size: var(--fs-xs); font-weight: 800; letter-spacing: -.02em;
}
.ps-tag .ico-svg { width: 15px; height: 15px; }
.ps-title {
  margin-top: var(--sp-3); font-size: var(--fs-xl); font-weight: 800;
  letter-spacing: -.035em; line-height: 1.28; word-break: keep-all;
  transition: opacity .2s ease;
}
.ps-title .hl { color: var(--y-brand); font-variant-numeric: tabular-nums; }
.ps-sub { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--y-muted); transition: opacity .2s ease; }
.promo-sheet.swap .ps-title, .promo-sheet.swap .ps-sub { opacity: .25; }

.ps-rates {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2) var(--sp-4);
  margin: var(--sp-4) 0 var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--y-line);
}
.ps-rate { display: flex; align-items: baseline; gap: var(--sp-2); min-width: 0; }
.ps-rate .n {
  flex: 1 1 auto; min-width: 0; font-size: var(--fs-sm); color: var(--y-muted); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ps-rate .v {
  flex: 0 0 auto; font-size: var(--fs-base); font-weight: 800; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}

.ps-foot { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }
.ps-foot button {
  flex: 1 1 0; min-height: 44px; border: 0; background: transparent;
  font-family: inherit; font-size: var(--fs-sm); font-weight: 600; color: var(--y-muted);
  cursor: pointer; border-radius: 12px;
}
.ps-foot button:active { background: var(--y-bg); }
.ps-foot button + button { color: var(--y-ink); font-weight: 700; }

@media (min-width: 1025px) {
  html:not(.is-app) .promo-sheet { left: auto; right: var(--sp-6); max-width: 420px; border-radius: 24px; bottom: var(--sp-6); }
  html:not(.is-app) .promo-back { background: rgba(11,14,20,.18); }
}
@media (prefers-reduced-motion: reduce) {
  .promo-sheet, .promo-back { transition: none; }
}

/* ---------- 관리자 진입 ----------
   앱에선 사이트 상단바(햄버거)가 사라져 관리자 메뉴에 닿을 길이 없다. '더보기' 맨 위에 둔다. */
.admin-entry {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-5); padding: var(--sp-4) var(--sp-5);
  background: var(--y-solid-dark); color: #fff; border-radius: 18px;
}
.admin-entry:hover, .admin-entry:active { text-decoration: none; color: #fff; }
.ae-ico {
  flex: 0 0 auto; width: 42px; height: 42px; border-radius: 999px;
  background: rgba(255,255,255,.14); display: flex; align-items: center; justify-content: center;
}
.ae-ico .ico-svg { width: 22px; height: 22px; }
.ae-txt { flex: 1 1 auto; min-width: 0; }
.ae-txt .t { display: block; font-size: var(--fs-base); font-weight: 800; letter-spacing: -.02em; }
.ae-txt .s { display: block; font-size: var(--fs-xs); opacity: .68; margin-top: 1px; }
.admin-entry .chev { flex: 0 0 auto; color: rgba(255,255,255,.5); font-size: 20px; line-height: 1; }

/* ---------- 어디서든 알림받기 ----------
   보고 있는 조건을 그 자리에서 담는다. 화면마다 버튼을 심지 않고 레이아웃에 하나만 둔다. */
.quick-watch { position: fixed; right: var(--sp-4); bottom: calc(var(--tabbar-h) + var(--sp-4)); z-index: 82; }
.quick-watch button, a.quick-watch > span {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 46px; padding: 0 var(--sp-5); border: 0; border-radius: 999px;
  background: var(--y-solid-dark); color: #fff; font-family: inherit;
  font-size: var(--fs-sm); font-weight: 800; letter-spacing: -.02em; cursor: pointer;
  box-shadow: 0 6px 20px rgba(11,14,20,.28);
}
.quick-watch button:active, a.quick-watch:active > span { transform: translateY(1px); }
a.quick-watch { text-decoration: none; }
a.quick-watch:hover { text-decoration: none; }
.quick-watch svg { width: 18px; height: 18px; }
/* 등록 완료 상태 — 눌러도 색이 그대로라 등록됐는지 몰랐다는 지적(2026-09-08)에 대한 답.
   채운 종(fill) + 강조색으로 "이미 켜져 있다"가 한눈에 보이게. */
a.quick-watch.is-active > span { background: var(--y-brand); }
/* 주행동(액션바)이 있으면 감추지 말고 **그 위로 올린다** — 감추면 그 화면에서
   알림등록을 아예 못 하게 된다(예측 화면이 그랬다). 겹치는 것만 피하면 된다. */
/* 떠 있는 버튼(알림받기·+만들기)은 본문 마지막 요소를 덮는다 — 공고 목록의 '다음 페이지'를
   누르려다 알림이 등록되고, 관심공고 마지막 카드의 버튼 줄이 잘렸다.
   app.js가 붙이는 .has-floating으로 그 화면만 아래 여백을 더 준다(:has() 미지원 웹뷰 대비). */
html.is-app body.has-floating,
body.has-floating { padding-bottom: calc(var(--tabbar-h) + 88px); }
/* FAB이 있는 화면(관심공고)은 그 화면 자체가 등록 화면이라 중복이다 */
body:has(.fab) .quick-watch { display: none; }

.quick-watch-toast {
  position: fixed; left: var(--sp-4); right: var(--sp-4); z-index: 200;
  bottom: calc(var(--tabbar-h) + 76px);
  background: var(--y-solid-dark); color: #fff; border-radius: 14px;
  padding: var(--sp-3) var(--sp-4); font-size: var(--fs-sm); font-weight: 600; text-align: center;
  box-shadow: 0 8px 24px rgba(11,14,20,.3);
  animation: qw-toast 4s ease forwards;
}
@keyframes qw-toast {
  0% { opacity: 0; transform: translateY(10px); }
  8%, 80% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(6px); visibility: hidden; }
}

/* ---------- 목록 읽음 표시(콘텐츠) ----------
   읽은 글은 지우지 않고 힘만 뺀다. 사라지면 "방금 뭘 봤지?"가 된다.
   기본(안읽음)이 굵게이므로 목록에서 새 글이 저절로 눈에 띈다. */
.list-row[data-read-key] .ttl { font-weight: 700; }
.list-row[data-read-key].is-read .ttl { font-weight: 500; color: var(--y-ink); }
.list-row[data-read-key].is-read .sub { color: var(--y-muted2); }
.list-row[data-read-key].is-read .chev { opacity: .5; }

/* ---------- 알림함 읽음/안읽음 ----------
   안읽음은 진하게 + 왼쪽 점, 읽은 것은 흐리게. 눌러야 읽음이 된다. */
.alert-list { display: flex; flex-direction: column; }
.alert-form { display: block; }
.alert-row {
  width: 100%; border: 0; background: transparent; font-family: inherit; text-align: left;
  cursor: pointer; color: var(--y-ink);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-1); min-height: 58px;
  border-bottom: 1px solid var(--y-line);
}
.alert-row:last-child { border-bottom: 0; }
.alert-row:active { background: var(--y-brand-tint); }
.alert-row .body { flex: 1 1 auto; min-width: 0; display: block; }
.alert-row .ttl {
  display: block; font-size: var(--fs-base); line-height: 1.38; letter-spacing: -.02em;
  word-break: keep-all;
}
.alert-row .sub {
  display: flex; align-items: center; gap: var(--sp-2); margin-top: 4px;
  font-size: var(--fs-sm); color: var(--y-muted);
  white-space: nowrap; overflow: hidden;
}
.alert-row .sub .org { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }
.alert-row .sub .tag {
  flex: 0 0 auto; background: var(--y-bg); padding: 1px 8px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 600;
}
.al-ico {
  flex: 0 0 auto; position: relative;
  width: 38px; height: 38px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
}
.al-ico .ico-svg { width: 19px; height: 19px; }
.alert-row .chev { flex: 0 0 auto; color: var(--y-muted2); }
.alert-row .chev svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* 안읽음 */
/* 굵기 하나만으로는 목록에서 잘 안 잡힌다 — 안 읽은 줄에 강조색 세로바를 하나 더 준다.
   :active의 틴트 배경과 겹치지 않게, 배경이 아니라 왼쪽 선으로 표시한다. */
.alert-row.unread { position: relative; padding-left: calc(var(--sp-1) + 10px); }
.alert-row.unread::before {
  content: ""; position: absolute; left: 0; top: 12px; bottom: 12px;
  width: 3px; border-radius: 999px; background: var(--y-brand);
}
.alert-row.unread .ttl { font-weight: 800; }
.alert-row.unread .al-ico { background: var(--y-brand-tint); color: var(--y-brand); }
.alert-row.unread .al-ico::after {
  content: ""; position: absolute; top: 1px; right: 1px;
  width: 8px; height: 8px; border-radius: 999px; background: var(--y-danger);
  box-shadow: 0 0 0 2px var(--y-bg);
}
/* 읽음 — 지우지 않고 힘만 뺀다. 사라지면 "방금 뭘 눌렀지?"가 된다. */
.alert-row.read .ttl { font-weight: 500; color: var(--y-ink); }
.alert-row.read .al-ico { background: var(--y-bg); color: var(--y-muted2); }
.alert-row.read .sub { color: var(--y-muted2); }

/* ---------- 앱바 인사말 ----------
   왼쪽은 브랜드, 오른쪽은 사람(인사말)과 종. 예전엔 인사말이 제목 자리를 차지해
   브랜드가 통째로 사라졌다. */
.ab-hello {
  flex: 0 1 auto; min-width: 0; margin-left: auto;
  font-size: var(--fs-xs); font-weight: 700; color: var(--y-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---------- 홈 큰 글씨(오늘 할 일) ----------
   인사가 아니라 오늘 처리할 일이 본문 첫 줄이어야 한다. 누르면 그 공고들로 간다. */
.today-line { color: var(--y-ink); }
.tl-txt {
  display: block; font-size: var(--fs-xl); font-weight: 800;
  letter-spacing: -.035em; line-height: 1.3; word-break: keep-all;
}
/* 숫자 자체가 링크다 — 화살표를 따로 두지 않고 밑줄로 "누를 수 있다"를 말한다.
   문장 전체를 링크로 만들면 글자를 복사하려다 화면이 넘어간다. */
.tl-num {
  color: var(--y-brand); text-decoration: none;
  border-bottom: 3px solid var(--y-brand-tint2); padding-bottom: 1px;
}
.tl-num:hover, .tl-num:active { text-decoration: none; border-bottom-color: var(--y-brand); }

/* ---------- 신규 수집 표시 ----------
   "새 공고"는 공고일이 아니라 **우리가 방금 받아온 것**을 뜻한다(Notice.CreatedAt).
   숨쉬듯 옅어졌다 진해지며, 목록을 훑을 때 새 줄이 눈에 걸리게 한다. */
.new-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 999px;
  background: #22C55E; margin-right: 6px; vertical-align: 1px;
  animation: newDot 2.2s ease-in-out infinite;
}
@keyframes newDot {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(34,197,94,.45); }
  50%      { opacity: .35; box-shadow: 0 0 0 5px rgba(34,197,94,0); }
}
@media (prefers-reduced-motion: reduce) { .new-dot { animation: none; } }

/* 본문에 들어오는 미디어는 반드시 화면 안에 가둔다.
   관리자가 뉴스·가이드·약관 본문에 넣은 이미지/표는 폭을 알 수 없는데,
   루트에 overflow-x: clip이 걸려 있어 넘치면 **잘린 채 밀어서 볼 수조차 없다.** */
img, video, iframe { max-width: 100%; }
img, video { height: auto; }
/* 운영자가 쓴 본문(뉴스·가이드·자료실 = .card, 약관 = .policy-doc) 안의 표·코드는
   잘라내지 말고 그 안에서 가로로 밀리게 한다. 관리자 표(.admin-main)는 이미 .table-wrap이 담당. */
.card table:not(.tbl), .policy-doc table { display: block; overflow-x: auto; max-width: 100%; }
.card pre, .policy-doc pre { overflow-x: auto; }

/* 스위치 항목의 보조설명 — 무엇을 켜고 끄는지 한 줄로 */
.sw-sub { display: block; margin-top: 2px; font-size: var(--fs-xs); color: var(--y-muted); font-weight: 500; word-break: keep-all; }

/* 이모지 자리를 대신하는 인라인 아이콘 — 글줄 안에 섞여도 baseline이 맞아야 한다.
   (예전엔 ⚠·ⓘ·📂 같은 이모지라 기기마다 그림이 달라 SVG 세트와 따로 놀았다) */
.hi { display: inline-flex; vertical-align: -3px; margin-right: 4px; }
.hi svg { width: 16px; height: 16px; }
.app-head h1 .hi svg { width: 19px; height: 19px; }
.st-ok, .st-bad { display: inline-flex; vertical-align: -3px; }
.st-ok svg { width: 17px; height: 17px; color: var(--y-on-ok); }
.st-bad svg { width: 17px; height: 17px; color: var(--y-on-danger); }
.nav-icon-btn svg { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.empty .ico svg { width: 30px; height: 30px; }

/* 신규 공고 요약 줄 — 점이 왜 초록인지 말해준다 */
.fresh-note {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: 0 0 var(--sp-3); padding: var(--sp-3) var(--sp-4);
  background: rgba(34,197,94,.10); border-radius: 12px;
  font-size: var(--fs-sm); color: var(--y-ink); word-break: keep-all;
}
.fresh-note b { font-weight: 800; }
.fresh-note .new-dot { margin-right: 0; }

/* ---------- 소식 티커 ----------
   마감임박과 하단 탭바 사이가 비어 화면이 멈춰 보였다. 한 줄만 쓰면서
   제목이 위로 밀려 올라가게 해 "돌아가고 있다"를 보여준다. */
.ticker {
  display: flex; align-items: center; gap: var(--sp-3);
  /* 홈의 마지막 요소다 — 아래 여백이 없으면 탭바에 잘려 보인다 */
  margin-top: var(--sp-5); margin-bottom: var(--sp-4); padding: var(--sp-3) var(--sp-4);
  background: var(--y-card); border-radius: 16px; color: var(--y-ink);
}
.ticker:hover, .ticker:active { text-decoration: none; }
.tk-tag {
  flex: 0 0 auto; font-size: var(--fs-xs); font-weight: 800; letter-spacing: -.02em;
  padding: 3px 9px; border-radius: 999px; background: var(--y-brand-tint); color: var(--y-brand);
}
.tk-view {
  position: relative; flex: 1 1 auto; min-width: 0; height: 20px; overflow: hidden;
}
.tk-item {
  position: absolute; inset: 0; display: flex; align-items: center;
  font-size: var(--fs-sm); font-weight: 600; color: var(--y-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* 기본 위치는 아래. .on이면 제자리, .out이면 위로 빠져나간다. */
  transform: translateY(100%); opacity: 0;
  transition: transform .45s cubic-bezier(.32,.72,0,1), opacity .3s ease;
}
.tk-item {
  color: inherit; text-decoration: none;
  /* 보이지 않는 항목이 손가락을 가로채면 엉뚱한 기사로 간다 — .on일 때만 눌린다 */
  pointer-events: none;
}
.tk-item.on { transform: translateY(0); opacity: 1; pointer-events: auto; }
.tk-item.is-read { font-weight: 500; color: var(--y-muted); }
.tk-item.out { transform: translateY(-100%); opacity: 0; }
.tk-go {
  flex: 0 0 auto; color: var(--y-muted2); font-size: 18px; line-height: 1;
  text-decoration: none; padding: 4px 2px 4px 6px;
}
.tk-go:hover, .tk-go:active { text-decoration: none; color: var(--y-brand); }
@media (prefers-reduced-motion: reduce) {
  .tk-item { transition: none; }
}

/* ---------- 열람 성향 막대 ---------- */
.tend-row { display: flex; align-items: center; gap: var(--sp-3); }
.tend-row + .tend-row { margin-top: var(--sp-3); }
.tend-row .tl {
  flex: 0 0 96px; font-size: var(--fs-sm); font-weight: 700; letter-spacing: -.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tend-row .tb { flex: 1 1 auto; height: 9px; border-radius: 999px; background: var(--y-bg); overflow: hidden; }
.tend-row .tb span { display: block; height: 100%; border-radius: 999px; }
.tend-row .tv {
  flex: 0 0 auto; min-width: 26px; text-align: right;
  font-size: var(--fs-sm); font-weight: 800; font-variant-numeric: tabular-nums; color: var(--y-muted);
}

/* ---------- 예측 후 관심 담기 ---------- */
.watch-cta {
  margin-top: var(--sp-3); background: var(--y-card); border-radius: 18px; padding: var(--sp-4) var(--sp-5);
}
.wc-line {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-sm); color: var(--y-muted); line-height: 1.5;
}
.wc-line strong { color: var(--y-ink); }
.wc-ico {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 999px;
  background: var(--y-tint-ok); color: var(--y-on-ok);
  display: flex; align-items: center; justify-content: center;
}
.wc-ico .ico-svg { width: 18px; height: 18px; }
.watch-cta form { margin-top: var(--sp-3); }
.wc-done {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--y-line);
  font-size: var(--fs-sm); color: var(--y-on-ok);
}
.wc-done .ico-svg { width: 17px; height: 17px; flex: 0 0 auto; }
.wc-done strong { color: var(--y-ink); }

/* ---------- 관리자 대시보드 히어로 ---------- */
.admin-hero {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-3);
  background: var(--y-brand); color: #fff; border-radius: 18px;
  box-shadow: 0 6px 20px rgba(37,99,255,.24);
}
.admin-hero:hover, .admin-hero:active { text-decoration: none; color: #fff; }
.ah-ico {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 999px;
  background: rgba(255,255,255,.18); display: flex; align-items: center; justify-content: center;
}
.ah-ico .ico-svg { width: 21px; height: 21px; }
.ah-txt { flex: 1 1 auto; min-width: 0; }
.ah-txt .t { display: block; font-size: var(--fs-md); font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.ah-txt .s { display: block; font-size: var(--fs-xs); opacity: .82; margin-top: 2px; }
.admin-hero .chev { flex: 0 0 auto; color: rgba(255,255,255,.6); font-size: 20px; line-height: 1; }

/* ---------- AI 학습 강조 배지 ---------- */
.ai-tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px 5px 9px; border-radius: 999px;
  background: var(--y-brand-tint); color: var(--y-brand);
  font-size: var(--fs-xs); font-weight: 800; letter-spacing: -.02em;
}
.ai-tag .ico-svg { width: 15px; height: 15px; }

/* ---------- 공고 상세 ---------- */
.nd-head { padding: var(--sp-5); }
.nd-badges { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.nd-title {
  font-size: var(--fs-lg); font-weight: 800; letter-spacing: -.03em; line-height: 1.34;
  margin: 0; word-break: keep-all;
}
.nd-org { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--y-muted); font-weight: 600; }
.nd-figures {
  display: flex; margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--y-line);
}
.nd-figures > div { flex: 1 1 0; min-width: 0; text-align: center; }
.nd-figures > div + div { border-left: 1px solid var(--y-line); }
.nd-figures .k { font-size: var(--fs-xs); color: var(--y-muted); font-weight: 600; }
.nd-figures .v {
  margin-top: 2px; font-size: var(--fs-md); font-weight: 800; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; word-break: keep-all;
}
.nd-figures .v.hot { color: var(--y-on-danger); }
.nd-figures .v.off { color: var(--y-muted); }

/* 사실 목록 — 라벨/값 두 칸. 값이 길면(참가지역 등) 아래로 흐르게 wide를 준다. */
.nd-facts { padding: var(--sp-1) 0; }
.nd-fact {
  display: flex; align-items: flex-start; gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5); font-size: var(--fs-sm);
}
.nd-fact + .nd-fact { box-shadow: inset 0 1px 0 var(--y-line); }
.nd-fact .k { flex: 0 0 92px; color: var(--y-muted); font-weight: 600; }
.nd-fact .v { flex: 1 1 auto; min-width: 0; font-weight: 700; text-align: right; word-break: break-word; }
.nd-fact .v.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--fs-xs); }
.nd-fact.wide { flex-direction: column; gap: var(--sp-1); }
.nd-fact.wide .v { text-align: left; font-weight: 600; line-height: 1.55; }

/* ---------- 업종별 적중률 막대 ---------- */
.rate-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.rate-row { display: flex; align-items: center; gap: var(--sp-3); }
.rate-row .rl {
  flex: 0 0 84px; font-size: var(--fs-sm); font-weight: 700; letter-spacing: -.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rate-row .rb { flex: 1 1 auto; height: 8px; border-radius: 999px; background: var(--y-bg); overflow: hidden; }
.rate-row .rb span { display: block; height: 100%; border-radius: 999px; background: var(--y-brand); }
.rate-row .rv {
  flex: 0 0 auto; min-width: 48px; text-align: right;
  font-size: var(--fs-sm); font-weight: 800; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; color: var(--y-brand);
}

/* ---------- 비회원 랜딩 ---------- */
.lead-sub { margin: 0; font-size: var(--fs-base); color: var(--y-muted); line-height: 1.55; word-break: keep-all; }
.cta-row { margin-top: var(--sp-5); }
.cta-note { margin-top: var(--sp-2); text-align: center; font-size: var(--fs-sm); color: var(--y-muted); }

/* 약관류 — 그룹 밖 작은 글씨. 평소 볼 일이 없는 것에 메뉴 칸을 내주지 않는다. */
.legal-row {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2) var(--sp-4);
  margin: var(--sp-6) 0 var(--sp-4); font-size: var(--fs-xs);
}
.legal-row a { color: var(--y-muted2); }

/* ⚠ 어두운 면 위에 흰 글씨를 얹는 부품은 --y-ink를 배경으로 쓰면 안 된다.
   --y-ink는 **본문 글자색**이라 다크모드에서 #E8ECF3(거의 흰색)으로 바뀐다
   → 흰 배경에 흰 글씨가 되어 관리자 진입 카드·알림받기 버튼·토스트가 통째로 사라진다.
   배경 목적의 짙은 면은 테마와 무관하게 항상 어두워야 하므로 별도 변수로 고정한다. */
:root { --y-solid-dark: #0B0E14; }
:root[data-theme="dark"] { --y-solid-dark: #202733; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --y-solid-dark: #202733; }
}

/* ---------- 프로필 카드 ---------- */
.profile-card { background: var(--y-card); border-radius: 20px; padding: var(--sp-5); }
.pc-top { display: flex; align-items: center; gap: var(--sp-3); }
.pc-avatar {
  flex: 0 0 auto; width: 48px; height: 48px; border-radius: 999px;
  background: var(--y-brand); color: #fff; font-weight: 800; font-size: 20px;
  display: flex; align-items: center; justify-content: center;
}
.pc-name { min-width: 0; }
.pc-name .n { font-size: var(--fs-lg); font-weight: 800; letter-spacing: -.03em; }
.pc-name .t { display: flex; align-items: center; gap: 6px; margin-top: 2px; font-size: var(--fs-xs); }
.pc-tier {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  background: var(--y-brand-tint); color: var(--y-brand); font-weight: 800; letter-spacing: -.02em;
}
.profile-card.pro .pc-tier { background: rgba(11,14,20,.06); color: var(--y-ink); }

/* 오른쪽 빈 자리 = 잔여 게이지. 원형이라 "얼마나 찼나"가 숫자보다 먼저 읽힌다.
   --p는 **쓴 비율**이다(0%면 아직 안 씀). */
.pc-gauge {
  flex: 0 0 auto; margin-left: auto; width: 62px; height: 62px; border-radius: 999px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: conic-gradient(var(--y-line) 0 var(--p), var(--y-brand) var(--p) 100%);
  position: relative;
}
.pc-gauge::after {
  content: ""; position: absolute; inset: 5px; border-radius: 999px; background: var(--y-card);
}
.pc-gauge .g-num { position: relative; z-index: 1; font-size: 19px; font-weight: 800; letter-spacing: -.04em; line-height: 1; }
.pc-gauge .g-cap { position: relative; z-index: 1; margin-top: 2px; font-size: 10px; color: var(--y-muted); font-weight: 700; }

.pc-badge {
  flex: 0 0 auto; margin-left: auto; display: inline-flex; align-items: center; gap: 5px;
  padding: 7px 12px; border-radius: 999px; background: var(--y-brand); color: #fff;
  font-size: var(--fs-xs); font-weight: 800;
}
.pc-badge svg { width: 15px; height: 15px; }

/* 업그레이드 유도 — 값을 먼저 말하고 버튼은 뒤에 둔다.
   "업그레이드하세요"만 있으면 광고고, 뭐가 달라지는지 적으면 안내다. */
.pc-up {
  display: flex; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-4); padding-top: var(--sp-4);
  border-top: 1px solid var(--y-line); text-decoration: none; color: inherit;
}
.pc-up .up-txt { min-width: 0; display: block; }
.pc-up .up-txt .t { display: block; font-size: var(--fs-sm); font-weight: 700; letter-spacing: -.02em; word-break: keep-all; }
.pc-up .up-txt .t b { color: var(--y-brand); font-weight: 800; }
.pc-up .up-txt .s { display: block; margin-top: 3px; font-size: var(--fs-xs); color: var(--y-muted); word-break: keep-all; }
.pc-up .up-cta {
  flex: 0 0 auto; margin-left: auto; padding: 9px 14px; border-radius: 999px;
  background: var(--y-brand); color: #fff; font-size: var(--fs-xs); font-weight: 800; white-space: nowrap;
}
.pc-up:active .up-cta { transform: translateY(1px); }
.pc-up.plain .up-txt .t b { color: var(--y-ink); }

/* ---------- 예측 결과 카드 ----------
   테두리 2px 대신 강조색 틴트로 채운다. 앱에서 "중요한 것"은 선이 아니라 면으로 말한다. */
.result-card {
  background: var(--y-brand-tint); border-radius: 20px; padding: var(--sp-5);
}
.rc-top { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--y-muted); }
.rc-top .badge { margin-left: auto; }
.rc-figure {
  margin-top: var(--sp-1); font-size: 34px; font-weight: 900;
  color: var(--y-brand); letter-spacing: -.045em; line-height: 1.15;
  font-variant-numeric: tabular-nums;
  /* 금액이 길어 좁은 화면에서 넘칠 수 있다 — 잘리는 대신 줄어들게 */
  overflow-wrap: anywhere;
}
.rc-rate { color: var(--y-muted); font-size: var(--fs-sm); }
.rc-rate strong { color: var(--y-ink); }
.result-card .disclaimer { margin-top: var(--sp-3); }
/* 예측 전 자리표시 — 같은 자리, 같은 크기, 색만 빠진 상태 */
.result-card.empty-state { background: var(--y-bg); }
.result-card.empty-state .rc-figure { color: var(--y-muted2); }

/* 잔여 횟수 줄 — 배지로 헤더에 달면 앱바와 겹쳐 붐빈다. 본문 한 줄로 내렸다. */
.quota-line {
  display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-3) 0 var(--sp-4); padding-left: var(--sp-1);
  font-size: var(--fs-sm); color: var(--y-muted); font-weight: 600;
}
.quota-line strong { color: var(--y-ink); }
.quota-line .sep { width: 3px; height: 3px; border-radius: 999px; background: var(--y-line-strong); }
.quota-line a { color: var(--y-muted); }

/* ---------- 지표 3칸 ----------
   화면의 요지가 되는 숫자를 표 위에 가운데 정렬로 세운다. 왼쪽 정렬된 글 사이에
   가운데 정렬된 숫자가 들어가야 화면에 리듬이 생긴다. */
.metric-strip { display: flex; padding: var(--sp-4) var(--sp-2); }
.metric-strip > div { flex: 1 1 0; text-align: center; min-width: 0; }
.metric-strip > div + div { border-left: 1px solid var(--y-line); }
.metric-strip .v {
  font-size: var(--fs-lg); font-weight: 800; letter-spacing: -.035em;
  color: var(--y-brand); font-variant-numeric: tabular-nums; line-height: 1.2;
}
.metric-strip .k { margin-top: 2px; font-size: var(--fs-xs); color: var(--y-muted); font-weight: 600; }

/* ---------- 개찰결과 카드 ---------- */
.res-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.res-card { background: var(--y-card); border-radius: 18px; padding: var(--sp-4) var(--sp-5); }
.rr-top { display: flex; align-items: flex-start; gap: var(--sp-2); }
.rr-top .ttl {
  flex: 1 1 auto; min-width: 0; font-weight: 700; font-size: var(--fs-base);
  line-height: 1.38; letter-spacing: -.02em; word-break: keep-all;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.rr-top .badge { flex: 0 0 auto; }
.rr-sub {
  margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--y-muted);
  display: flex; align-items: center; gap: var(--sp-2);
  white-space: nowrap; overflow: hidden;
}
.rr-sub .org { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }
.rr-sub .tag {
  flex: 0 0 auto; background: var(--y-bg); padding: 1px 8px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 600;
}
.rr-nums {
  display: flex; margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px solid var(--y-line);
}
.rr-nums > div { flex: 1 1 0; text-align: center; min-width: 0; }
.rr-nums .k { font-size: var(--fs-xs); color: var(--y-muted); font-weight: 600; }
.rr-nums .v {
  margin-top: 1px; font-size: var(--fs-base); font-weight: 800;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.rr-nums .v.ok { color: var(--y-on-ok); }
.rr-nums .v.bad { color: var(--y-on-danger); }

/* 필터가 걸려 있음을 알리는 한 줄 */
.filter-note {
  display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-3) 0; padding-left: var(--sp-1);
  font-size: var(--fs-sm); color: var(--y-muted); font-weight: 600;
}
.filter-note a { margin-left: auto; color: var(--y-brand); }

/* 각주 — 법적 고지·표시 한계 같은, 읽히긴 해야 하나 자리를 뺏으면 안 되는 문구 */
.fineprint {
  margin: var(--sp-5) 0 var(--sp-6); font-size: var(--fs-xs);
  color: var(--y-muted2); line-height: 1.6; text-align: center;
}

/* ---------- 검색바 ---------- */
.searchbar { position: relative; display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.searchbar .ico {
  position: absolute; margin-left: 13px; pointer-events: none; color: var(--y-muted2);
  display: flex;
}
.searchbar .ico svg { width: 18px; height: 18px; }
.searchbar .form-control {
  flex: 1 1 auto; min-width: 0; padding-left: 40px; border-radius: 999px; min-height: 46px;
}
/* 검색바 안에서도, 페이지 헤더에서도 쓴다 — 선택자를 .searchbar 아래 가두면
   헤더에 놓았을 때 스타일이 통째로 빠진다(실제로 그랬다). */
.filter-btn {
  flex: 0 0 auto; min-height: 40px; padding: 0 var(--sp-4); border-radius: 999px;
  background: var(--y-card); border: 1px solid var(--y-line); color: var(--y-ink);
  font-family: inherit; font-size: var(--fs-sm); font-weight: 700; cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--sp-1); white-space: nowrap;
}
.filter-btn:hover { background: var(--y-brand-tint); border-color: var(--y-brand-tint2); }
.searchbar .filter-btn { min-height: 46px; }
/* 검색 입력의 브라우저 기본 X 버튼은 위치가 제각각이라 지운다 */
.searchbar input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }

/* ---------- 시트 안 폼 ---------- */
.switch-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  min-height: 48px; font-size: var(--fs-base); font-weight: 600;
  border-top: 1px solid var(--y-line); margin-top: var(--sp-2); padding-top: var(--sp-3);
}
/* 그룹의 첫 줄엔 위 선을 긋지 않는다 — 제목 바로 아래 선이 두 겹으로 보인다 */
.switch-row:first-child,
.app-head + .switch-row,
h3 + .switch-row { border-top: 0; margin-top: 0; padding-top: 0; }
.switch-row input[type="checkbox"] { width: 22px; height: 22px; accent-color: var(--y-brand); }
.sheet-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-5); }
.sheet-actions .btn { flex: 1 1 0; }

/* ---------- 페이지 이동 ---------- */
.pager {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-3);
  margin-top: var(--sp-5); font-size: var(--fs-sm); color: var(--y-muted);
}
.pager span { text-align: center; }

/* 목록 행 안의 배지·태그 */
.list-row .ttl .badge { margin-right: 6px; vertical-align: 1px; }
.list-row .sub .tag {
  color: var(--y-muted); background: var(--y-bg);
  padding: 1px 8px; border-radius: 999px; font-size: var(--fs-xs); font-weight: 600;
}

/* =========================================================
   앱 홈(대시보드) — _HomeDashboard.cshtml 전용
   ========================================================= */
.home-greet { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.home-hello { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.035em; line-height: 1.2; }
.home-bell {
  position: relative; margin-left: auto; flex: 0 0 auto;
  width: 42px; height: 42px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  background: var(--y-card); color: var(--y-ink);
}
.home-bell:hover { text-decoration: none; background: var(--y-brand-tint); }
.home-bell svg { width: 21px; height: 21px; }
/* 숫자 대신 점 — 개수는 알림함에 들어가면 보인다. 홈에서 필요한 건 "새 게 있다"뿐이다. */
.home-bell .dot {
  position: absolute; top: 8px; right: 9px; width: 8px; height: 8px; border-radius: 999px;
  background: var(--y-danger); box-shadow: 0 0 0 2.5px var(--y-card);
}

/* =========================================================
   스타벅스형 부품 (2026-08-08 3차 · 시안 C 채택)
   가져온 것은 **형태**만이다 — 원형 아이콘, 원형 진행링, 색 띠 카드, 두 줄 인사.
   색은 기존 코발트 토큰을 그대로 쓴다(딥그린으로 가면 공공조달에서 신뢰보다
   친환경으로 읽힌다는 판단).

   ⚠ 스타벅스 앱이 가벼워 보이는 큰 이유는 **사진**이다 — 음료 사진이 화면 절반을 채운다.
     공고에는 이미지가 없으므로 그 자리를 그대로 비우면 허전해진다.
     여기서는 사진 자리를 **색 띠 + 남은 시간(D-2 / 6시간)**으로 대체했다.
   ========================================================= */

/* 두 줄 인사 — 두 번째 줄이 "지금 앱을 켠 이유"를 말한다 */
.greet2 { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.035em; line-height: 1.28; }
.greet2 em { font-style: normal; color: var(--y-brand); }

/* 원형 진행링 카드 — 적중률처럼 "얼마나 찼나"인 값에 맞는 표현 */
/* 최근 낙찰 이력 미니표 — .tbl 기본 패딩(14/16px)은 5열 컴팩트표엔 너무 커 모바일에서 넘친다.
   box-sizing:border-box로 지정 폭이 패딩 포함 실제 폭이 되게 해 어떤 폭에서도 넘치지 않게 한다.
   max-width로 넓은 화면에서 낙찰사 칸이 휑하게 늘어나지 않도록 표를 적당한 폭에 묶는다. */
/* table.tbl.mini-tbl — .tbl의 데스크톱 min-width:640px(2shin.css:624, 가로스크롤용)를 덮어야 하므로
   같은 구체성(table.tbl.x)으로 min-width를 0으로 되돌린다. 이게 없으면 표가 640px 밑으로 못 줄어
   좁은 화면에서 오른쪽 열들이 잘린다(2026-08-25 라이브 측정으로 확정). */
table.tbl.mini-tbl { min-width: 0; max-width: 480px; }
.mini-tbl th, .mini-tbl td { padding: 6px 7px !important; white-space: nowrap; box-sizing: border-box; }
.mini-tbl th { text-transform: none; letter-spacing: 0; }
@media (max-width: 420px) {
  .mini-tbl th, .mini-tbl td { padding: 6px 5px !important; font-size: 11.5px; }
}

/* 승산 추정 — 실전 컨텍스트 카드 안. "낙찰가 예측"과 "내 당첨"을 분리해 정직하게. */
.wc-box { border-top: 1px dashed var(--y-line); padding-top: 8px; }
.wc-head { font-size: 13.5px; color: var(--y-ink); }
.wc-head strong { font-size: var(--fs-md); letter-spacing: -.02em; }
.wc-sub { font-size: var(--fs-xs); color: var(--y-muted); font-weight: 500; }
.wc-note { margin-top: 3px; font-size: var(--fs-xs); color: var(--y-muted); word-break: keep-all; line-height: 1.45; }

/* 투찰 브리핑 — 무효 하한선·만점투찰률. 예측가 밑에서 "어떻게 투찰하지"를 한 곳에. */
.brief-card {
  margin-top: var(--sp-3); border-radius: 16px; padding: var(--sp-3) var(--sp-4);
  background: var(--y-brand-tint); border: 1px solid var(--y-line);
}
.brief-title { font-weight: 800; font-size: var(--fs-sm); color: var(--y-brand); letter-spacing: -.03em; margin-bottom: 6px; }
.brief-row { display: flex; align-items: baseline; gap: var(--sp-2); padding: 4px 0; }
.brief-k { flex: 0 0 84px; font-size: var(--fs-sm); color: var(--y-muted); font-weight: 600; }
.brief-v { flex: 1 1 0; min-width: 0; font-size: var(--fs-md); font-weight: 800; letter-spacing: -.02em; color: var(--y-ink); font-variant-numeric: tabular-nums; word-break: keep-all; }
/* 부가설명은 금액 아래 줄로 — 한 줄에 붙이면 좁은 폰에서 잘렸다. */
.brief-sub { display: block; margin-top: 1px; font-size: var(--fs-xs); font-weight: 500; color: var(--y-muted); }
.brief-danger .brief-v { color: #dc2626; }
.brief-warn { margin-top: 6px; font-size: var(--fs-xs); color: #dc2626; font-weight: 700; word-break: keep-all; }
.brief-cta {
  display: block; margin-top: 10px; text-align: center;
  padding: 9px 12px; border-radius: 10px; background: var(--y-brand); color: #fff;
  font-size: 13.5px; font-weight: 700; letter-spacing: -.02em;
}
.brief-cta:hover, .brief-cta:active { text-decoration: none; opacity: .92; }
.brief-note { margin-top: 7px; font-size: var(--fs-xs); color: var(--y-muted); word-break: keep-all; line-height: 1.45; }

/* 신뢰도 등급 카드 — 예측가 바로 아래. 등급색으로 "얼마나 믿어도 되나"가 즉시 읽힌다. */
.conf-card {
  margin-top: var(--sp-3); border-radius: 16px; padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--y-line); border-left-width: 4px;
}
/* 배지와 숫자를 세로로 쌓는다 — 한 줄 space-between은 좁은 폰(375px)에서 ±1% 숫자가 잘렸다. */
.conf-head { display: flex; flex-direction: column; gap: 2px; }
.conf-badge { font-weight: 800; font-size: var(--fs-md); letter-spacing: -.03em; }
.conf-nums { font-size: var(--fs-xs); color: var(--y-muted); font-variant-numeric: tabular-nums; word-break: keep-all; }
.conf-nums strong { color: var(--y-ink); }
.conf-line { margin-top: 4px; font-size: var(--fs-sm); font-weight: 600; color: var(--y-ink); word-break: keep-all; }
.conf-why { margin-top: 3px; font-size: var(--fs-xs); color: var(--y-muted); word-break: keep-all; }
.conf-god   { border-left-color: #16a34a; background: color-mix(in srgb, #16a34a 7%, var(--y-card)); }
.conf-god   .conf-badge { color: #16a34a; }
.conf-sure  { border-left-color: var(--y-brand); background: var(--y-brand-tint); }
.conf-sure  .conf-badge { color: var(--y-brand); }
.conf-range { border-left-color: #d97706; background: color-mix(in srgb, #d97706 7%, var(--y-card)); }
.conf-range .conf-badge { color: #b45309; }
.conf-draw  { border-left-color: #6b7280; background: color-mix(in srgb, #6b7280 7%, var(--y-card)); }
.conf-draw  .conf-badge { color: #4b5563; }

.ring-card {
  display: flex; align-items: center; gap: var(--sp-4);
  background: var(--y-card); border-radius: 24px; padding: var(--sp-5);
  color: var(--y-ink);
}
.ring-card:hover, .ring-card:active { text-decoration: none; }
.ring {
  flex: 0 0 auto; width: 78px; height: 78px; border-radius: 999px;
  display: grid; place-items: center;
}
.ring > span {
  width: 62px; height: 62px; border-radius: 999px; background: var(--y-card);
  display: grid; place-items: center;
  font-size: var(--fs-md); font-weight: 800; letter-spacing: -.035em;
  color: var(--y-brand); font-variant-numeric: tabular-nums;
}
.ring-body { min-width: 0; }
.ring-body .k { font-size: var(--fs-sm); color: var(--y-muted); font-weight: 600; }
.ring-body .v { font-size: var(--fs-md); font-weight: 800; letter-spacing: -.03em; margin-top: 1px; }
.ring-body .go { margin-top: var(--sp-2); font-size: var(--fs-sm); font-weight: 700; color: var(--y-brand); }

/* 정직 포지셔닝 3포인트 — 홈 히어로 아래. "무효표 방지·정직 구분"을 못 박는다. */
.trust-strip { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; }
.trust-item {
  font-size: 13.5px; line-height: 1.5; color: var(--y-ink); word-break: keep-all;
  padding-left: 22px; position: relative;
}
.trust-item::before {
  content: "\2713"; position: absolute; left: 0; top: 0;  /* ✓ — CSS 이스케이프로 인코딩 사고 방지 */
  color: var(--y-brand); font-weight: 900;
}
.ti-k { font-weight: 800; letter-spacing: -.02em; }
.trust-item strong { color: var(--y-brand); font-variant-numeric: tabular-nums; }

/* 경쟁사 비교표로 가는 티저 링크 — 적중률 근거 바로 아래. */
.cmp-teaser {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 12px; padding: 13px 16px; border-radius: 12px;
  border: 1px solid var(--y-line); background: var(--y-card, #fff);
  font-size: 14px; font-weight: 600; color: var(--y-ink); word-break: keep-all;
}
.cmp-teaser strong { color: var(--y-brand); }
.cmp-teaser .chev { color: var(--y-brand); font-weight: 900; font-size: 18px; flex: 0 0 auto; }

/* 원형 바로가기 — 둥근 사각 대신 원. 손가락 목표가 커지고 화면이 부드러워진다. */
.circle-nav { display: flex; justify-content: space-between; gap: var(--sp-1); }
.cnav {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  flex: 1 1 0; min-width: 0; text-align: center;
  font-size: var(--fs-xs); font-weight: 600; color: var(--y-ink); letter-spacing: -.03em;
  word-break: keep-all;
}
.cnav:hover, .cnav:active { text-decoration: none; }
.cnav .ico {
  /* 좁은 화면에서 칸이 늘어도(4→5칸) 넘치지 않도록 아이콘을 살짝 줄인다.
     넓은 화면·4칸에서는 58px 상한이 걸려 기존 모습 그대로다. */
  width: clamp(46px, 14vw, 58px); height: clamp(46px, 14vw, 58px); border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  background: var(--y-brand-tint); color: var(--y-brand);
}
.cnav:active .ico { background: var(--y-brand-tint2); }
.cnav .ico svg { width: 24px; height: 24px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* 색 띠 카드 — 사진이 없는 서비스에서 사진 자리를 대신한다 */
.hcard.banded { width: 208px; padding: 0; overflow: hidden; }
.hcard .band { padding: var(--sp-3) var(--sp-4); background: var(--y-brand); color: #fff; }
.hcard .band.calm { background: #0B1E4A; }
:root[data-theme="dark"] .hcard .band.calm { background: #24334F; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hcard .band.calm { background: #24334F; }
}
.hcard .band .d { font-size: 22px; font-weight: 800; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.hcard .band .o {
  font-size: var(--fs-xs); opacity: .84; font-weight: 600; margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hcard .bd { padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.hcard .bd .ttl {
  font-size: 14.5px; font-weight: 700; line-height: 1.38; letter-spacing: -.02em; word-break: keep-all;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 2.76em;
}
.hcard .bd .amt {
  margin-top: var(--sp-2); font-size: var(--fs-base); font-weight: 800;
  letter-spacing: -.03em; color: var(--y-brand); font-variant-numeric: tabular-nums;
}

/* 타일 아이콘도 원형으로 — 내 정보 격자와 홈의 원형 바로가기가 같은 언어를 쓰게 한다.
   내용물은 이모지가 아니라 선 아이콘(Icons.cs)이다. 이모지는 기기마다 그림이 다르고
   색·굵기를 맞출 수 없어 얇은 선으로 정리된 화면에서 혼자 튄다. */
.tile .ti {
  width: 46px; height: 46px; border-radius: 999px;
  background: var(--y-brand-tint); color: var(--y-brand);
  display: flex; align-items: center; justify-content: center;
}
.tile { gap: var(--sp-2); padding: var(--sp-3) 2px; }

/* 아이콘 기본 크기. currentColor를 따르므로 다크모드·강조색이 자동으로 맞는다. */
.ico-svg { width: 22px; height: 22px; display: block; }
.tile .ti .ico-svg { width: 23px; height: 23px; }
.menu-row .mi { display: flex; align-items: center; justify-content: center; color: var(--y-muted); }
.menu-row .mi .ico-svg { width: 21px; height: 21px; }
.menu-row:hover .mi, .menu-row:active .mi { color: var(--y-brand); }

/* ---------- SEO 랜딩(/L/*) ----------
   검색으로 처음 들어오는 사람이 보는 첫 화면. 데스크톱 히어로를 그대로 쓰면
   폰에서 제목이 화면을 다 먹고 위아래 빈 여백이 한 화면 가까이 생긴다. */
.lp-hero { padding-top: var(--sp-4); }
.lp-title {
  font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.035em;
  line-height: 1.25; word-break: keep-all; margin: var(--sp-2) 0 var(--sp-3);
}
/* 색을 박아두지 않는다 — 예전엔 #4A5560 하드코딩이라 다크모드에서 어두운 배경 위 어두운 회색이었다 */
.lp-intro { color: var(--y-muted); font-size: var(--fs-base); line-height: 1.65; word-break: keep-all; }
.lp-intro p { margin: 0 0 var(--sp-2); }
.lp-hero .btn-row { margin-top: var(--sp-4); }
@media (min-width: 900px) {
  .lp-title { font-size: 34px; }
  .lp-intro { max-width: 640px; }
}

/* 버튼 두 개를 나란히 — 예전엔 .hero-cta 라는 같은 이름을 아래 '주행동 카드'와 나눠 쓰다가,
   나중에 로드되는 이 파일이 이겨서 랜딩 페이지 버튼이 파란 카드 안에 갇혔다. */
.btn-row { display: flex; gap: var(--sp-3); flex-wrap: wrap; }

/* 주행동 카드 — 이 화면에서 하려는 단 하나.
   잔여횟수·적중률을 카드 밖 별도 줄로 두면 그만큼 세로가 늘어난다. 카드 발치에 붙여 한 덩어리로. */
.hero-cta {
  display: block; padding: var(--sp-5); border-radius: 20px;
  background: var(--y-brand); color: #fff;
  box-shadow: 0 8px 24px rgba(37,99,255,.28);
}
.hero-cta:hover, .hero-cta:active { text-decoration: none; color: #fff; }
.hc-row { display: flex; align-items: center; gap: var(--sp-4); }
.hc-txt { flex: 1 1 auto; min-width: 0; }
.hc-k { font-size: var(--fs-sm); opacity: .8; font-weight: 600; }
.hc-t { font-size: var(--fs-lg); font-weight: 800; letter-spacing: -.035em; margin-top: 1px; }
.hc-go {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 999px;
  background: rgba(255,255,255,.18); display: flex; align-items: center; justify-content: center;
}
.hc-go svg { width: 20px; height: 20px; }
.hc-foot {
  display: flex; margin-top: var(--sp-4); padding-top: var(--sp-3);
  border-top: 1px solid rgba(255,255,255,.2);
}
.hc-foot div { flex: 1 1 0; text-align: center; }
.hc-foot div + div { border-left: 1px solid rgba(255,255,255,.2); }
.hc-foot .v { font-size: var(--fs-md); font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.hc-foot .k { font-size: var(--fs-xs); opacity: .78; font-weight: 600; }

/* ---------- 타일 격자 ----------
   세로 목록 20줄을 4열 격자 5줄로 접는다. "스크롤이 길다"의 가장 직접적인 해법이고,
   전부 왼쪽에 붙어 있던 라벨이 가운데로 오면서 화면이 목록이 아니라 화면으로 읽힌다. */
/* ── 큰 타일(3열 카드) ─────────────────────────────────────────
   자주 쓰는 항목은 크게. 4열 46px 아이콘은 정보는 많이 담기지만 손가락으로 누르기엔
   작고 눈에도 안 들어왔다. 3열 카드 + 30px 아이콘으로 키운다.
   대신 **전부 크게 만들지는 않는다** — 24개를 다 이 크기로 하면 스크롤이 다시 길어진다.
   자주 쓰는 그룹만 이걸 쓰고, 나머지는 아래 .row-grid(2열 목록)로 간다. */
/* 카드(네모) 위에 아이콘을 얹으면 아이콘이 카드에 "붙여놓은 것"처럼 따로 논다.
   네모를 없애고 **원만** 남긴다 — 원의 틴트와 아이콘 색이 같은 계열이라 둘이 한 덩어리로 읽힌다.
   홈의 원형 바로가기(.cnav)와 같은 형태여서 두 화면의 언어도 맞는다. */
.tile-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-3) var(--sp-1);
}
.tile-grid .tile {
  background: transparent; border-radius: 14px;
  min-height: auto; padding: var(--sp-2) 2px; gap: var(--sp-2);
  justify-content: flex-start;
  font-size: var(--fs-xs); font-weight: 600;
}
.tile-grid .tile .ti {
  width: 56px; height: 56px; border-radius: 999px;
  background: var(--y-brand-tint); color: var(--y-brand);
}
.tile-grid .tile .ti .ico-svg { width: 26px; height: 26px; }
.tile-grid .tile:active .ti { background: var(--y-brand-tint2); }
.tile-card { background: transparent; border: 0; padding: 0; }

/* ── 2열 목록 ──────────────────────────────────────────────────
   가끔 쓰는 항목. 아이콘은 작게 왼쪽, 이름은 그대로 읽힌다.
   같은 8개를 큰 타일로 두면 3행이 더 생긴다. */
.row-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--sp-2);
  background: var(--y-card); border-radius: 18px; padding: var(--sp-2) var(--sp-3);
}
.row-item {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: 52px; padding: 0 var(--sp-2); color: var(--y-ink);
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: -.02em;
  word-break: keep-all;
}
.row-item:hover, .row-item:active { text-decoration: none; color: var(--y-brand); }
.row-item .ri { flex: 0 0 auto; display: flex; color: var(--y-muted); }
.row-item:hover .ri, .row-item:active .ri { color: var(--y-brand); }
.row-item .ri .ico-svg { width: 20px; height: 20px; }

/* <button>도 타일/행으로 쓴다(테마 토글) — 기본 버튼 스타일을 지운다 */
button.tile, button.row-item {
  border: 0; background: transparent; font-family: inherit; cursor: pointer; text-align: left;
}
button.tile { text-align: center; }
.tile {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: var(--sp-2);
  padding: var(--sp-3) 2px; border-radius: 14px; color: var(--y-ink);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: -.03em; text-align: center;
  line-height: 1.25; word-break: keep-all;
}
.tile:hover, .tile:active { text-decoration: none; background: var(--y-brand-tint); }
.tile .ti { font-size: 23px; line-height: 1; height: 26px; display: flex; align-items: center; }
.tile .tb {
  position: absolute; margin: -4px 0 0 22px;
  background: var(--y-danger); color: #fff; font-size: 9.5px; font-weight: 800;
  line-height: 1; padding: 3px 5px; border-radius: 999px;
}

/* ---------- 가로 카드 레일 ----------
   목록을 세로로 쌓으면 항목 수만큼 화면이 길어진다. 홈처럼 "훑어보는" 자리에선 옆으로 민다. */
.hrail {
  display: flex; gap: var(--sp-3); overflow-x: auto;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* 컨테이너 좌우 패딩 밖까지 흘려보내 카드가 화면 끝에서 잘리는 느낌을 준다(= 더 있다는 신호) */
  margin: 0 -18px; padding: 2px 18px var(--sp-2);
}
.hrail::-webkit-scrollbar { display: none; }
.hcard {
  flex: 0 0 auto; width: 216px; scroll-snap-align: start;
  background: var(--y-card); border-radius: 18px; padding: var(--sp-4);
  color: var(--y-ink); display: flex; flex-direction: column;
}
.hcard:hover, .hcard:active { text-decoration: none; }
.hcard .hd {
  align-self: flex-start; font-size: var(--fs-xs); font-weight: 800; letter-spacing: -.02em;
  padding: 3px 9px; border-radius: 999px;
  background: var(--y-tint-danger); color: var(--y-on-danger);
}
.hcard .hd.far { background: var(--y-bg); color: var(--y-muted); }
.hcard .ht {
  margin-top: var(--sp-3); font-size: var(--fs-base); font-weight: 700; letter-spacing: -.025em;
  line-height: 1.36; word-break: keep-all;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 2.72em;
}
.hcard .hb {
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--y-line);
  display: flex; align-items: baseline; gap: var(--sp-2);
}
.hcard .ho {
  flex: 1 1 auto; min-width: 0; font-size: var(--fs-xs); color: var(--y-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hcard .ha { flex: 0 0 auto; font-size: var(--fs-sm); font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }

/* 빠른 실행 — 4칸 고정. 카드가 아니라 아이콘 버튼이다(테두리 없음). */
.quick-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); }
.quick {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-1);
  font-size: var(--fs-xs); font-weight: 700; color: var(--y-ink); text-align: center;
  letter-spacing: -.03em;
}
.quick:hover, .quick:active { text-decoration: none; }
.quick:active .ico { background: var(--y-brand-tint2); }
.quick .ico {
  width: 50px; height: 50px; border-radius: 17px; display: flex; align-items: center; justify-content: center;
  background: var(--y-brand-tint); color: var(--y-brand);
}
.quick .ico svg { width: 22px; height: 22px; }

/* 섹션 헤더 */
.app-head h1 { font-size: var(--fs-lg); }
.app-head .act a { font-size: var(--fs-sm); font-weight: 700; color: var(--y-muted); }

/* =========================================================
   4) 관리자 화면 보정
   .admin-side가 #201A45 / #cdc9e6 로 하드코딩돼 있어 다크모드에서 홀로 보라색으로 떠 있었고,
   활성 항목이 노랑(--y-yellow)이라 "코발트 단일 강조색" 원칙에서도 벗어나 있었다.
   (--y-yellow는 카카오 브랜드 고정값이라 장식에 쓰면 안 되는 색이다 — 2shin.css:15 주석)
   ========================================================= */
:root { --admin-side-bg: #14171F; --admin-side-fg: #B9C1CE; --admin-side-grp: #6E7986; }
:root[data-theme="dark"] { --admin-side-bg: #10141A; --admin-side-fg: #A8B2C0; }
/* OS 다크는 따라가지 않는다(2shin.css의 다크 테마 주석 참조) — data-theme만 본다. */
.admin-side { background: var(--admin-side-bg); color: var(--admin-side-fg); }
.admin-nav a { color: var(--admin-side-fg); }
.admin-nav a.active { background: var(--y-brand); color: #fff; }
.admin-nav .grp { color: var(--admin-side-grp); }
.admin-side .brand small { color: var(--admin-side-grp); }
/* 관리자 사이드바가 모바일에서 전체화면 오버레이로 뜰 때 상태바에 파고들지 않게 */
@media (max-width: 900px) {
  .admin-side.mobile-open { padding-top: calc(22px + var(--sa-top)); }
}

/* ── 앱에서의 관리자 화면 ──────────────────────────────────────────────
   관리자도 폰 앱에서 다 쓴다(2026-08-08 결정). 공개 화면과 같은 문법으로 맞춘다:
   위는 앱바, 아래는 탭바, 사이드바는 '메뉴' 버튼으로 여는 오버레이.        */
html.is-app .admin-topbar { display: none; }          /* 앱바가 제목을 대신한다 */
html.is-app .admin-shell { grid-template-columns: 1fr; }
html.is-app .admin-side { display: none; }             /* 메뉴 버튼으로만 연다 */
html.is-app .admin-side.mobile-open {
  display: flex; flex-direction: column; position: fixed; inset: 0; z-index: 200;
  overflow-y: auto; padding: calc(22px + var(--sa-top)) 16px calc(34px + var(--sa-bottom));
}
html.is-app .admin-main { padding: var(--sp-4) var(--sp-4) 0; background: var(--y-bg); }
html.is-app .tabbar { display: flex; }
html.is-app body { padding-bottom: calc(var(--tabbar-h) + var(--sp-5)); }

/* 관리자 표는 데이터 밀도가 목적이라 목록으로 바꾸지 않는다(R9 예외).
   대신 앱에서 가로 스크롤이 되는 것을 분명히 보여주고, 손가락으로 밀리게 한다. */
html.is-app .table-wrap {
  -webkit-overflow-scrolling: touch;
  /* 오른쪽에 잘림 그림자 — "옆으로 더 있다"는 신호. 없으면 열이 잘린 걸 사고로 읽는다.
     --edge는 표가 놓인 바탕색이다. 관리자 표는 카드가 아니라 페이지 바탕 위에 놓이므로
     기본값을 --y-bg로 두고, 카드 안에 들어간 표만 --y-card로 바꾼다. */
  --edge: var(--y-bg);
  background:
    linear-gradient(to right, var(--edge) 30%, transparent) left / 24px 100% no-repeat,
    linear-gradient(to left, var(--edge) 30%, transparent) right / 24px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%, rgba(11,14,20,.10), transparent) left / 12px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%, rgba(11,14,20,.10), transparent) right / 12px 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}
html.is-app .card .table-wrap { --edge: var(--y-card); }
/* 관리자 지표는 자릿수가 커서(누적 예측 등) 3등분 칸을 꽉 채운다 — 한 단계 줄인다 */
html.is-app .admin-main .metric-strip .v { font-size: var(--fs-md); }
.fineprint br { line-height: 2; }

/* ---------- 하단 고정 액션바 — 상세화면의 주행동을 엄지 근처에 ----------
   ⚠ 예전엔 액션바가 있으면 탭바를 감췄다(`body.has-actionbar .tabbar { display:none }`).
     그 결과 AI 투찰예측 화면에 들어가면 **다른 화면으로 갈 방법이 사라졌다** — 뒤로가기밖에 없었다.
     둘이 겹치는 게 문제였으니, 감추는 대신 **탭바 위에 얹는다.** */
.actionbar {
  position: fixed; left: 0; right: 0; z-index: 85;
  bottom: 0; padding: var(--sp-3) var(--sp-4) calc(var(--sp-3) + var(--sa-bottom));
  background: var(--y-nav-bg-solid);
  -webkit-backdrop-filter: saturate(180%) blur(12px); backdrop-filter: saturate(180%) blur(12px);
  border-top: 1px solid var(--y-line);
  display: flex; gap: var(--sp-2);
}
.actionbar .btn { flex: 1 1 0; }

/* 액션바 안으로 들어온 알림받기 — 떠 있지 않으니 본문을 가리지 않는다.
   주행동(예측하기)이 폭을 갖고, 알림받기는 아이콘 크기만 차지한다. */
.actionbar .quick-watch.in-bar { position: static; flex: 0 0 auto; z-index: auto; }
.actionbar .quick-watch.in-bar button,
.actionbar a.quick-watch.in-bar > span {
  min-height: 48px; width: 48px; padding: 0; gap: 0; justify-content: center;
  border-radius: 14px; background: var(--y-brand-tint); color: var(--y-brand); box-shadow: none;
}
/* 아이콘만 남기고 글자는 뺀다 — 48px 안에 "알림받기"를 넣으면 읽히지도 눌리지도 않는다.
   무슨 버튼인지는 aria-label이 말한다. */
.actionbar .quick-watch.in-bar button,
.actionbar a.quick-watch.in-bar > span { font-size: 0; }
.actionbar .quick-watch.in-bar svg { width: 22px; height: 22px; }
body.has-actionbar { padding-bottom: 84px; }

/* 탭바가 보이는 상황(모바일 폭 또는 앱)에서는 액션바를 탭바 높이만큼 띄운다. */
@media (max-width: 1024px) {
  .actionbar { bottom: var(--tabbar-h); padding-bottom: var(--sp-3); }
  body.has-actionbar { padding-bottom: calc(var(--tabbar-h) + 76px); }
}
html.is-app .actionbar { bottom: var(--tabbar-h); padding-bottom: var(--sp-3); }
html.is-app body.has-actionbar { padding-bottom: calc(var(--tabbar-h) + 76px); }
