/* 앱 셸 — 상단바 + 좌측 사이드바 + 본문 (D-115 · 그룹 사이드바 개편 v2.0 §1).
   색·타이포는 기존 토스톤 토큰(tokens.css) 그대로. 치수만 시안 v2.0으로 맞췄다:
     사이드바 확장 248 / 접힘 68 · 탑바 62(일터) · 행 40/radius 10 · 아이콘 18/stroke 1.7 ·
     라벨 14/600 · 그룹 캡션 11/600 +0.04em

   ⚠ 40여 개 템플릿이 layout.html 하나를 공유한다. 여기 클래스명을 바꾸면 전 페이지가 영향받는다. */

/* ── 일터 셸의 상단바 높이 (v2.0 §1 ⑥) ────────────────────────────
   🔴 **body에 건다.** 예전에 `.shell-client .topbar { --topbar-h: 48px }`처럼 상단바에만 걸었다가
      사이드바 top·스크림 inset·본문 padding-top이 그 값을 못 봐서 셋이 어긋난 적이 있다.
      body에 걸면 .topbar·.sidebar·.shell·.main이 **모두 같은 조상**에서 상속받는다.
   ⚠ 의뢰인(마케팅) 지면은 68px 그대로다 — home.css의 배너 여백이 "68 + 24 + 60 = 152"로
     맞춰져 있어(그 파일 주석) 여기서 낮추면 홈 위쪽 리듬이 통째로 어긋난다. */
body.shell-pro { --topbar-h: 62px; }

/* ── 상단바 ─────────────────────────────────────────── */
/* 좌 / 가운데(브랜드) / 우 3구역. 브랜드를 정확히 가운데 세우려면 좌우가 같은 폭을
   차지해야 한다 — flex + margin:auto로 맞추면 좌우 내용 폭 차이만큼 어긋난다.
   grid 1fr auto 1fr이면 내용과 무관하게 늘 중앙이다.
   🔴 가운데 칸(.top-c)은 **비어도 남긴다**(관리자 셸에는 심볼이 없다). 없애면 우측 구역이
      2번 칸으로 올라와 오른쪽 정렬이 통째로 무너진다. */
.topbar {
  position: fixed; inset: 0 0 auto 0; height: var(--topbar-h); z-index: 30;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: var(--s-lg); padding: 0 var(--s-xl);
  background: var(--bg, var(--background)); border-bottom: 1px solid var(--divider);
}
.top-l { display: flex; align-items: center; justify-content: flex-start; gap: 10px; min-width: 0; }
.top-c { display: flex; align-items: center; justify-content: center; min-width: 0; }
.top-r { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }

/* 브랜드 — **심볼만** 가운데 (D-138b → D-167에서 워드마크 제거).
   ⚠ 심볼 자체가 '로세' 두 글자라, 글자 수가 줄어든 만큼 **크기를 키워야** 획이 읽힌다.
     더 줄이면 '로세'의 계단 획이 뭉쳐서 무슨 글자인지 안 보인다. */
.topbar .brand {
  display: inline-flex; align-items: center;
  white-space: nowrap; color: var(--text-primary);
}
/* ── 락업 렌더 — **캔버스가 아니라 잉크를 기준으로 재운다** (D-259) ──────────────
   🔴 예전엔 `.brand-mark { height: 26px }`였다. 그런데 락업 PNG는 **여백이 절반**이다:
      `logo-kr-light@4x.png`는 580×256 캔버스인데 잉크는 **425×129**(세로의 50.4%)뿐이고,
      여백도 비대칭이다(좌 100 · 우 55 · 상 51 · 하 76 — 직접 재서 확인).
      그래서 26px을 주면 **화면에 보이는 로고는 13.1px**이 됐다 — 브랜드 가이드가 요구하는
      **최소 24px의 55%**다. 「로고 영역이 안 보인다」는 지적의 진짜 원인이 이것이었다.

   그래서 창(.brand)에 잉크만 보이게 잘라 넣는다. 계산 근거(잉크 높이 H 기준):
     · 이미지 높이 = H ÷ (129/256)        = H × 1.9845
     · 이미지 너비 = 이미지높이 × (580/256) = H × 4.4961
     · 창 너비    = 이미지너비 × (425/580) = H × 3.2946
     · 왼쪽 밀기  = 이미지너비 × (100/580) = H × 0.7752
     · 위로 밀기  = 이미지높이 × (51/256)  = H × 0.3953
   ⚠ **자산이 바뀌면 이 다섯 숫자를 다시 재라.** 파일이 바뀌었는지는
     `python3 -c "from PIL import Image; im=Image.open('...').convert('RGBA'); print(im.size, im.split()[3].getbbox())"`
     로 확인한다. 숫자만 고치면 나머지는 따라온다.
   ⚠ 비대칭 여백을 창으로 잘라 내므로 **광학 중심이 저절로 맞는다** — 예전엔 로고가
     칩 안에서 왼쪽·위로 치우쳐 보였다. */
.brand-mark {
  --brand-ink: 24px;                       /* 가이드 최소치. 더 줄이지 마라. */
  display: block; flex: 0 0 auto; position: relative; overflow: hidden;
  height: var(--brand-ink);
  width: calc(var(--brand-ink) * 3.2946);
}
.brand-mark img {
  position: absolute; display: block; max-width: none;
  height: calc(var(--brand-ink) * 1.9845); width: auto;
  left: calc(var(--brand-ink) * -0.7752);
  top: calc(var(--brand-ink) * -0.3953);
}
/* 62px 일터 바에서도 잉크는 24px 그대로다 — 최소치라 줄일 여지가 없다. 대신 칩 여백을 조인다. */
.shell-pro .topbar .brand { padding: 6px 16px; }

/* 관리자 표식 (v2.0 §1 ⑥) — 워드마크 #191F28 + ADMIN 배지.
   ⚠ 색은 tokens.css의 --text-primary(#191F28) 그대로다. 새 색을 만들지 마라. */
.brand-admin { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.brand-admin-word {
  font-size: 16px; font-weight: 700; letter-spacing: var(--ls-lg); color: var(--text-primary);
}
.badge-admin {
  font-size: 10px; font-weight: 700; letter-spacing: .06em; line-height: 1;
  padding: 4px 6px; border-radius: 6px;
  background: var(--text-primary); color: #fff;
}

/* 상단바 검색 320px (v2.0 §1 ⑥) — 배경 #F2F4F6(=--surface-alt).
   ⚠ 갈 곳이 있는 셸에만 그린다(layout.html 주석) — 여기 스타일이 있다고 아무 데나 붙이지 마라. */
.top-search {
  display: flex; align-items: center; gap: 8px;
  width: 320px; max-width: 38vw; height: 36px; padding: 0 12px;
  border-radius: 10px; background: var(--surface-alt);
}
.top-search .ts-ic {
  width: 16px; height: 16px; flex: 0 0 16px;
  stroke: var(--text-tertiary); fill: none; stroke-width: 1.8; stroke-linecap: round;
}
.top-search input {
  flex: 1; min-width: 0; height: 100%;
  border: 0; background: transparent; outline: none;
  font-family: inherit; font-size: 14px; color: var(--text-primary);
}
.top-search input::placeholder { color: var(--text-disabled); }

/* 상단바 버튼은 검색칸과 같은 결로 맞춘다 — 기본 .btn(48px)은 너무 크다. */
.topbar .btn { height: 36px; padding: 0 16px; font-size: 14px; }
.icon-btn {
  width: 38px; height: 38px; border-radius: var(--r-md);
  display: inline-flex; align-items: center; justify-content: center; color: var(--text-secondary);
}
.icon-btn:hover { background: var(--surface-alt); }

/* 안읽음 점 — **서버가 알려줄 때만** 그려진다(layout.html 주석의 판단).
   테두리를 상단바 배경색으로 둘러 종 획 위에 얹혀도 점으로 읽히게 한다. */
.top-bell { position: relative; }
.top-dot {
  position: absolute; top: 7px; right: 8px;
  width: 7px; height: 7px; border-radius: var(--r-full);
  background: var(--error); box-shadow: 0 0 0 2px var(--bg, var(--background));
}

/* ── 브랜드 락업 자리 (D-262, 사용자 지시로 테두리 제거) ──────────────────────
   D-258에서 «눌러지는 자리»가 안 보인다는 지적이 있었다. 회색 면 알약(D-259 이전) → 선만(D-259)
   → **아무 장식도 없음**(지금)으로 왔다.

   🔴 되짚어 둘 것: 그때 지적의 **진짜 원인은 대비가 아니라 크기**였다. 락업 PNG의 잉크가
      캔버스의 50.4%뿐이라 `height:26px`이 실제로는 13.1px로 그려지고 있었다(가이드 최소치
      24px의 55%). 그걸 잡은 것은 아래 `--brand-ink` 창(crop-window)이지 면도 선도 아니다.
      그래서 선을 걷어도 그 결함은 돌아오지 않는다 — **--brand-ink를 24px 밑으로 내리면
      돌아온다.** 로고가 다시 안 보인다는 말이 나오면 테두리가 아니라 그 값을 먼저 재라.

   ⚠ 로고 자체는 손대지 않는다(브랜드 가이드: 색 변형·회전·그림자 금지). 바뀌는 것은
     그 뒤에 깔리는 **우리 UI**뿐이다.
   ⚠ padding은 남긴다. hover 면과 focus 링이 락업에 달라붙지 않게 하는 자리다.
     테두리를 지웠다고 padding까지 지우면 키보드 링이 글자를 물고 그려진다. */
.topbar .brand {
  padding: 8px 18px; border-radius: var(--r-full);
  background: transparent;                 /* 상단바 흰색이 그대로 비친다 */
  transition: background .15s ease;
}
.topbar .brand:hover { background: var(--grey50); }
.topbar .brand:active { background: var(--surface-alt); }
.topbar .brand:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* 아바타 — 사진이 있으면 사진, 없으면 이름 첫 글자(layout.html 주석 참고). */
.top-avatar {
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: var(--r-full);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--primary-light); color: var(--primary-pressed);
  font-size: 14px; font-weight: 700;
  overflow: hidden; cursor: pointer; list-style: none;
}
.top-avatar::-webkit-details-marker { display: none; }  /* summary 기본 삼각형 */
.top-avatar:hover { background: #DCEBFF; }
.top-avatar-img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── 계정 메뉴 (D-258) ────────────────────────────────────────────
   🔴 <details>로 짓는다 — JS 없이도 여닫힌다. shell.js는 «바깥 클릭·Esc로 닫기»만 얹는다. */
.acct { position: relative; }
.acct-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
  min-width: 208px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-float);
}
.acct-head {
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 10px 10px; margin-bottom: 4px; border-bottom: 1px solid var(--divider);
}
.acct-name { font-size: 14px; font-weight: 700; color: var(--text-primary); }
/* 이메일은 길다 — 메뉴 폭을 늘리지 말고 줄인다. */
.acct-mail {
  font-size: 12px; color: var(--text-tertiary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 196px;
}
.acct-item {
  display: block; width: 100%; text-align: left;
  padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-secondary);
  font-family: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
}
.acct-item:hover { background: var(--surface-alt); color: var(--text-primary); }
.acct-item:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
/* 로그아웃은 되돌릴 수 없는 조작이라 한 칸 띄우고 톤을 낮춘다(빨강까지는 가지 않는다 —
   위험한 삭제가 아니라 «나가기»다). */
.acct-out { margin-top: 4px; border-top: 1px solid var(--divider); border-radius: 0 0 var(--r-sm) var(--r-sm); }

/* 사이드바 프로필 사진 — 상단바와 같은 값을 그린다. */
.sp-av { overflow: hidden; }
.sp-av-img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── 사이드바 모드 전환 (D-138c) ─────────────────────────────
   상단바에서 내려온 세그먼트 컨트롤. 메뉴 머리에 있어야 "이걸 누르면 아래 목록이 바뀐다"가
   위치로 읽힌다. 사이드바 폭을 꽉 채워 두 칸으로 나눈다. */
.side-mode {
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px;
  padding: 3px; margin-bottom: 8px;
  background: var(--surface-alt); border: 1px solid var(--border);
  border-radius: var(--r-full);
}
.side-mode-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 32px; border: 0; border-radius: var(--r-full);
  background: transparent; color: var(--text-tertiary);
  font-size: 13px; font-weight: 600; white-space: nowrap; cursor: pointer;
}
.side-mode-btn svg {
  width: 16px; height: 16px; flex: 0 0 16px;
  stroke: currentColor; fill: none; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.side-mode-btn:hover { color: var(--text-secondary); }
/* 선택된 쪽은 메인 컬러 알약 — 흰 알약은 회색 트랙 위에서 대비가 약해
   "지금 어느 모드인지"가 한눈에 안 읽혔다(D-123 당시 사용자 피드백). */
.side-mode-btn.on { background: var(--primary); color: #fff; }
.side-mode-btn.on:hover { color: #fff; }

/* 접힌 레일(68px)에는 두 칸이 안 들어간다. **지금이 아닌 쪽**만 아이콘으로 남겨
   누르면 바로 그 모드로 넘어가게 한다 — 접어 둔 사람도 모드를 바꿀 수 있어야 한다. */
html.rail .side-mode {
  grid-template-columns: 1fr; background: none; border: 0; padding: 0; margin-bottom: 10px;
}
html.rail .side-mode-btn.on { display: none; }
html.rail .side-mode-btn {
  width: 40px; height: 40px; margin: 0 auto;
  border: 1px solid var(--border); background: var(--surface);
}
html.rail .side-mode-btn svg { width: 18px; height: 18px; flex: 0 0 18px; }

/* ── 셸 ─────────────────────────────────────────────── */
.shell { display: flex; padding-top: var(--topbar-h); min-height: 100vh; }

/* 🔴 사이드바는 **세 층**이다: 스크롤 되는 메뉴(.side-scroll) + 바닥에 고정된 프로필 카드
      (.side-profile). 그래서 스크롤을 사이드바가 아니라 안쪽 칸이 가진다 — 예전처럼
      .sidebar에 overflow-y를 두면 메뉴가 길 때 프로필 카드가 같이 밀려 올라가 바닥에서 사라진다. */
.sidebar {
  position: fixed; top: var(--topbar-h); bottom: 0; left: 0; z-index: 20;
  width: var(--sidebar-w); overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--bg, var(--background)); border-right: 1px solid var(--divider);
  transition: width .18s ease;
}
.side-scroll {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; padding: 8px 10px;
}

/* ── 그룹 (v2.0 §1 ①) ────────────────────────────────
   평평한 목록을 이름 붙은 묶음으로. 캡션은 11/600 +0.04em — 읽으라고 두는 글자가 아니라
   **어디쯤인지 알려주는 표식**이라 본문보다 확실히 작고 흐리다. */
.nav-group { display: flex; flex-direction: column; }
.nav-group + .nav-group { margin-top: 8px; }
.nav-cap {
  margin: 0 0 4px; padding: 0 12px;
  font-size: 11px; font-weight: 600; line-height: 1; letter-spacing: .04em;
  color: var(--text-disabled);
}

/* 🔴 높이 36은 취향이 아니라 **계산 결과**다. 세무사 메뉴는 17줄이라 40px이면
      1440×900(가장 흔한 노트북)에서 109px이 넘쳐 마지막 줄이 반쯤 잘린 채 멈춘다.
      36 + 아래의 여백 축소로 900에 정확히 들어간다. 줄 수를 늘리려면 여기부터 다시 재라. */
.nav-item {
  display: flex; align-items: center; gap: 10px;
  height: 36px; padding: 0 12px; border-radius: 10px;
  font-weight: 600; font-size: 14px; color: var(--text-secondary); white-space: nowrap;
}
.nav-item:hover { background: var(--surface-alt); }
.nav-item.active { background: var(--primary-light); color: var(--primary); }
.nav-item svg {
  flex: 0 0 18px; width: 18px; height: 18px;
  stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
.nav-sep { height: 1px; background: var(--divider); margin: 6px 8px; }
.nav-foot { margin-top: auto; }
.nav-logout { width: 100%; text-align: left; }

/* ── 하단 고정 프로필 카드 (v2.0 §1 ⑤) ────────────────
   스크롤 밖이라 어느 화면에서도 같은 자리에 있다 — 구독 상태를 "찾아서" 보는 게 아니라
   "지나가다" 보게 하려는 자리다. */
.side-profile {
  position: relative; flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-top: 1px solid var(--divider);
  background: var(--bg, var(--background));
}
/* 메뉴가 넘칠 때 마지막 줄이 **반쯤 잘린 채** 멈추면 고장으로 읽힌다. 스크롤 칸 바닥에
   배경색으로 사라지는 20px 그라데이션을 덮어 "아래 더 있다"로 읽히게 한다.
   내용이 짧아 넘치지 않으면 배경 위에 배경이라 눈에 띄지 않는다 — 알아서 숨는다. */
.side-profile::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 100%; height: 20px;
  pointer-events: none;
  background: linear-gradient(to top, var(--bg, var(--background)), transparent);
}
.side-profile:hover { background: var(--surface-alt); }
.sp-av {
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: var(--r-full);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--primary-light); color: var(--primary-pressed);
  font-size: 14px; font-weight: 700;
}
.sp-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sp-name {
  font-size: 13px; font-weight: 700; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sp-sub {
  font-size: 12px; color: var(--text-tertiary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── 접힘(레일 68px) — 라벨만 감추고 아이콘은 남긴다 ────────────
   아이콘 상자 40px + 좌우 14px = 68px. 라벨은 shell.js가 title(툴팁)로 옮겨 준다
   (사이드바가 overflow:hidden이라 CSS 말풍선은 잘린다 — 그래서 네이티브 툴팁을 쓴다). */
html.rail .sidebar { width: var(--rail-w); }
html.rail .side-scroll { padding: 8px 14px; }
html.rail .nav-item { width: 40px; padding: 0; gap: 0; justify-content: center; }
html.rail .nlabel { display: none; }
html.rail .nav-cap { display: none; }
/* 캡션이 사라져도 묶음은 남아야 한다 — 이름표 대신 선으로 가른다. */
html.rail .nav-group + .nav-group {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--divider);
}
html.rail .nav-sep { margin: 10px 4px; }
html.rail .side-profile { justify-content: center; padding: 10px 0; }
html.rail .sp-txt { display: none; }
html.rail .main { margin-left: var(--rail-w); }

/* 접힌 레일의 메뉴 이름 말풍선 (D-281).
   🔴 **body에 붙는다.** 사이드바 안에 두면 `.sidebar { overflow:hidden }`이 오른쪽으로 나가는
      말풍선을 잘라 버린다 — 예전에 네이티브 `title`을 쓸 수밖에 없었던 이유가 그것이다.
      `position: fixed` + JS가 계산한 좌표라 클리핑을 통째로 벗어난다.
   ⚠ `pointer-events: none` — 말풍선이 커서를 가로채면 그 위에서 mouseleave가 나 깜빡인다.
   ⚠ z-index는 사이드바(20)보다 위여야 한다. 아래면 사이드바 뒤로 숨는다.
   ⚠ 위치는 JS가 아이콘 **세로 가운데**를 주므로 여기서 translateY(-50%)로 맞춘다. */
.rail-tip {
  position: fixed; z-index: 60; pointer-events: none;
  transform: translateY(-50%);
  padding: 6px 10px; border-radius: var(--r-sm, 6px);
  background: var(--text-primary); color: #fff;
  font-size: 12px; font-weight: 600; line-height: 1.3; white-space: nowrap;
  box-shadow: 0 4px 14px rgba(17, 31, 40, .18);
  opacity: 0; visibility: hidden;
  transition: opacity .12s ease;
}
.rail-tip.on { opacity: 1; visibility: visible; }
/* 화살표 — 어느 아이콘을 가리키는지 분명히 한다. */
.rail-tip::before {
  content: ''; position: absolute; right: 100%; top: 50%;
  transform: translateY(-50%);
  border: 5px solid transparent; border-right-color: var(--text-primary);
}
@media (prefers-reduced-motion: reduce) { .rail-tip { transition: none; } }

/* 본문은 남은 자리를 **전부** 쓴다(D-154). 예전엔 `max-width: 사이드바 + 1240`으로 묶어
   넓은 화면에서 오른쪽이 통째로 비었다. 좌우 여백만 화면 폭에 따라 준다. */
.main {
  flex: 1; margin-left: var(--sidebar-w); min-width: 0;
  padding: 24px var(--shell-pad) 64px; transition: margin-left .18s ease;
  /* 🔴 **푸터를 아래에 붙이기 위한 세로 격자**(D-241). `.shell`이 이미 `min-height:100vh`라
        `.main`은 화면 끝까지 늘어나 있었는데, 그 안의 푸터는 일반 흐름 블록이라 **본문 바로 뒤**에
        섰다. 그래서 내용이 짧으면 푸터가 화면 한가운데 뜨고 그 아래가 죽은 여백이 됐다.
     ⚠ 푸터에 `margin-top:auto`를 주지 않는다. 그러면 내용이 길 때 auto가 0으로 줄어 본문과
       구분선이 붙는다. 대신 **본문 칸을 늘려**(아래 `> :first-child`) 밀어내고, 푸터의
       56px 간격은 내용 길이와 무관하게 그대로 남긴다. */
  display: flex; flex-direction: column;
}
/* 일터 지면의 회색 판(v2.0 §1 ⑦)은 D-420에서 은퇴 — 전 메뉴가 캘린더(D-416)처럼
   흰 바탕이다. 카드 경계는 카드 자신의 테두리·그림자가 만든다. */

/* 본문 조각(`layout:fragment="content"`의 div)이 남는 세로를 가져간다.
   ⚠ `flex: 1 0 auto` — 세 번째 값이 `auto`여야 내용이 화면보다 길 때 줄어들지 않는다.
   🔴 **`:first-child`로 잡으면 안 된다**(D-525, 실측 사고). 플래시(page-flash)가 뜨면 그것이
      첫 자식이 되어 **늘어나는 것이 본문이 아니라 플래시**가 된다 — 결제 직후 화면에서
      한 줄짜리 안내가 **660px 빈 회색 상자**로 떴다. 플래시가 있는 **모든 지면**이 같았다.
   🔴 푸터는 언제나 마지막이므로 «푸터 **바로 앞**»을 잡는다 — 플래시가 있든 없든 본문이 걸린다. */
.main > :nth-last-child(2) { flex: 1 0 auto; min-width: 0; }
/* ⚠ 플래시는 제 높이만 쓴다 — 위 규칙이 어떤 이유로 플래시를 잡아도 늘어나지 않게 못 박는다. */
.main > .page-flash { flex: 0 0 auto; }

/* ── 셸 안의 푸터 «말»(D-710, 시안 B 확정) — 본문 흐름 끝에 붙는다(위 격자가 늘 화면 아래로 민다).
   브랜드 블록 = 락업(잉크 32px · 위 .brand-mark 창 패턴 재사용) + 태그라인 + 질문 한 줄
   (낱말 단위로 어긋나게 떠오름 → 3초 머묾 → 조용히 사라짐 · 4문장 순환 16s) + 고정 답줄.
   락업·심볼은 움직이지 않는다(브랜드 README). 움직이는 속성은 transform·opacity뿐(design.md §7).
   배경은 흰색이다 — 13px 회색 글자(--text-tertiary)가 --grey50 위에서는 4.42:1로 하한(4.5)에
   못 미친다(실측). 반응형은 @container(푸터 폭 기준) — 960px 위에서 «브랜드 | 링크» 두 단.
   🔴 푸터 자신이 컨테이너(테두리·위 여백)이고 안쪽 .sf-in이 격자다 — 컨테이너 쿼리는 컨테이너
      자신에게는 적용되지 않으므로 격자 규칙은 안쪽 상자에 둔다(푸터에 두면 두 단이 «암묵 열»로
      생겨 열 간격·행 정의가 사라진다 — 시안 단계에서 실제로 그렇게 깨졌다).
   바닥 줄은 subgrid로 같은 두 열을 이어받아 약관 링크가 링크 열의 왼쪽 끝선에 선다(미지원
   브라우저에서는 「셈톡」 아래 약관이 쌓일 뿐 내용·접근성은 그대로). */
.shell-footer {
  --sf-gap: 64px;              /* 두 단 사이 */
  --sf-q-size: 26px;           /* 데스크톱 질문 글줄 — 사다리 실측(24/26/28)으로 고른 값 · notes.md */
  container-type: inline-size;
  margin-top: 56px; padding-top: 32px;
  border-top: 1px solid var(--border);
  color: var(--text-tertiary); font-size: 13px;
  flex: 0 0 auto;
}
.shell-footer .sf-in { display: grid; grid-template-columns: minmax(0, 1fr); align-items: start; }

/* ── 브랜드 블록: 락업 → 태그라인 → 질문 글줄 → 답줄 ───────────────────────────────── */
.shell-footer .sf-brand { min-width: 0; }
.shell-footer .brand-mark { --brand-ink: 32px; }
.shell-footer .sf-tag {
  margin: 14px 0 0; font-size: 16px; font-weight: 500; line-height: 1.4;
  letter-spacing: var(--ls-lg); color: var(--text-primary);
}

/* 질문 글줄 — 네 문장은 절대배치로 같은 자리에 겹치고 가장 긴 문장(프리랜서…)을 visibility:hidden
   으로 한 벌 더(.sf-ghost) 흐름에 두어 높이를 잡는다 → 문장이 바뀌어도 레이아웃 점프 0.
   낱말은 inline-block이라 낱말 안에서 줄이 갈리지 않는다. 유령도 같은 낱말 구조·keep-all이라
   접히는 자리가 실제 문장과 같다. */
.shell-footer .sf-talk { position: relative; margin-top: 24px; }
.shell-footer .sf-q {
  margin: 0; min-width: 0; word-break: keep-all; overflow-wrap: normal;
  font-size: 20px; font-weight: 500; line-height: 1.4;
  letter-spacing: var(--ls-xl); color: var(--text-primary);
}
.shell-footer .sf-q:not(.sf-ghost) { position: absolute; inset: 0; }
.shell-footer .sf-ghost { visibility: hidden; }

/* 낱말 모션 — 기본 상태는 «아직 안 나온 낱말»(투명·8px 아래).
   지연 = 문장 위상(--t: 0/4/8/12s) + 낱말 차례(--w: 0~4) × 60ms. 유령의 낱말은 움직이지 않는다. */
.shell-footer .sf-q span {
  display: inline-block; opacity: 0; transform: translateY(8px);
  animation: sf-word 16s ease-out infinite;
  animation-delay: calc(var(--t, 0s) + var(--w, 0) * 60ms);
}
.shell-footer .sf-ghost span { animation: none; }
.shell-footer .sf-q2 { --t: 4s; }
.shell-footer .sf-q3 { --t: 8s; }
.shell-footer .sf-q4 { --t: 12s; }
.shell-footer .sf-q span:nth-child(2) { --w: 1; }
.shell-footer .sf-q span:nth-child(3) { --w: 2; }
.shell-footer .sf-q span:nth-child(4) { --w: 3; }
.shell-footer .sf-q span:nth-child(5) { --w: 4; }
/* 16s = 100% (1% = 0.16s). 0~0.55s 떠오름(ease-out) · 3.5s까지 머묾(첫 낱말 기준 2.95s) ·
   3.5~3.76s 사라짐(opacity만 · ease-in-out) · 나머지는 투명 대기. 다섯째 낱말(+0.24s)도 4.0s에
   다 사라져 다음 문장(4.0s)과 겹치지 않는다. 마지막 키프레임 = 첫 키프레임 → 루프 이음새 없음. */
@keyframes sf-word {
  0%      { opacity: 0; transform: translateY(8px); animation-timing-function: ease-out; }
  3.4375% { opacity: 1; transform: translateY(0);   animation-timing-function: linear; }
  21.875% { opacity: 1; transform: translateY(0);   animation-timing-function: ease-in-out; }
  23.5%   { opacity: 0; transform: translateY(0); }
  23.6%   { opacity: 0; transform: translateY(8px); }
  100%    { opacity: 0; transform: translateY(8px); }
}
.shell-footer .sf-ans { margin: 8px 0 0; font-size: 15px; line-height: 1.4; color: var(--text-tertiary); }

/* ── 링크 3열 — 열 머리 13px/500 · 링크 14px/400. 모바일 히트 44px(11+22+11) ──────────── */
.shell-footer .sf-nav { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 16px; margin-top: 32px; }
.shell-footer .sf-cap { margin: 0 0 4px; font-size: 13px; font-weight: 500; line-height: 20px; color: var(--text-tertiary); }
.shell-footer .sf-col ul { list-style: none; margin: 0; padding: 0; }
.shell-footer .sf-col a {
  display: inline-block; padding: 11px 0; font-size: 14px; font-weight: 400; line-height: 22px;
  color: var(--text-secondary); text-decoration: none;
}
/* 세무사 한 줄 — 마지막 링크의 아래 패딩(11)과 합쳐 글자 사이 37px */
.shell-footer .sf-pro { margin: 26px 0 0; font-size: 14px; line-height: 22px; color: var(--text-tertiary); }
.shell-footer .sf-pro a {
  display: inline-block; padding: 11px 0; margin: -11px 0; color: var(--text-secondary);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--grey300);
}

/* ── 바닥 줄 — 「셈톡」 글자 + 약관 3링크(필수). 위 칸과는 더 옅은 --divider 헤어라인 ──────── */
.shell-footer .sf-bottom {
  display: flex; align-items: center; justify-content: space-between; gap: 0 16px; flex-wrap: wrap;
  margin-top: 24px; padding-top: 6px; border-top: 1px solid var(--divider);
}
.shell-footer .sf-name { font-size: 13px; font-weight: 500; line-height: 20px; color: var(--text-tertiary); }
.shell-footer .sf-legal { display: flex; flex-wrap: wrap; column-gap: 20px; list-style: none; margin: 0; padding: 0; }
.shell-footer .sf-legal a { display: inline-block; padding: 12px 0; font-size: 13px; line-height: 20px; color: var(--text-secondary); text-decoration: none; }

/* ── 링크 상태 — hover는 잉크 진해짐 + 밑줄 · 키보드 포커스는 브랜드 파랑 링 ─────────────── */
.shell-footer a { transition: color .15s ease; }
.shell-footer a:hover { color: var(--text-primary); text-decoration: underline; text-underline-offset: 3px; }
.shell-footer a:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 4px; }

/* ── 넓은 푸터(컨테이너 ≥ 600) — 글줄 24px · 링크 열 고정 폭 · 데스크톱 히트(32px) ────────── */
@container (min-width: 600px) {
  .shell-footer .sf-in { padding-top: 8px; }   /* 푸터 32 + 8 = 테두리 아래 40px */
  .shell-footer .sf-tag { font-size: 17px; }
  .shell-footer .sf-talk { margin-top: 28px; }
  .shell-footer .sf-q { font-size: 24px; line-height: 1.35; letter-spacing: var(--ls-2xl); }
  /* 열 피치 152(112 + 40) 둘 · 셋째 열은 제 폭 — 두 단일 때 오른쪽 끝선이 본문 끝선과 맞는다 */
  .shell-footer .sf-nav { grid-template-columns: 112px 112px auto; column-gap: 40px; margin-top: 36px; }
  .shell-footer .sf-col a { padding: 5px 0; }
  .shell-footer .sf-legal a { padding: 6px 0; }
  .shell-footer .sf-pro a { padding: 5px 0; margin: -5px 0; }
  .shell-footer .sf-pro { margin-top: 23px; }   /* 링크 패딩 5 + 23 = 글자 사이 28px */
  .shell-footer .sf-bottom { margin-top: 32px; }
}

/* ── 두 단(컨테이너 ≥ 960 · 데스크톱 셸 1161) — 브랜드 | 링크 3열 + 세무사 한 줄.
   바닥 줄은 subgrid로 같은 두 열(같은 열 사이 간격)을 이어받는다 → 약관 링크 = 링크 열 왼쪽 끝선. */
@container (min-width: 960px) {
  .shell-footer .sf-in {
    grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto 1fr auto;
    column-gap: var(--sf-gap);
  }
  .shell-footer .sf-brand { grid-column: 1; grid-row: 1 / span 2; }
  .shell-footer .sf-nav { grid-column: 2; grid-row: 1; margin-top: 0; }
  .shell-footer .sf-pro { grid-column: 2; grid-row: 2; align-self: end; margin-top: 20px; }
  .shell-footer .sf-q { font-size: var(--sf-q-size); }
  .shell-footer .sf-bottom {
    grid-column: 1 / 3; grid-row: 3;
    display: grid; grid-template-columns: subgrid; column-gap: var(--sf-gap); align-items: center;
    margin-top: 36px;
  }
  .shell-footer .sf-name { grid-column: 1; }
  .shell-footer .sf-legal { grid-column: 2; justify-self: start; }
}

/* ── 앱 임베드 — 셸이 접혀 좌우 패딩이 0이다. 큰 글줄·락업은 접고 링크 열과 바닥 줄만 남긴다. */
.app-embed .shell-footer { margin-inline: 0; padding-inline: 16px; }
.app-embed .shell-footer .sf-in { grid-template-columns: minmax(0, 1fr); column-gap: 0; }
.app-embed .shell-footer .sf-brand { display: none; }
.app-embed .shell-footer .sf-nav,
.app-embed .shell-footer .sf-pro { grid-column: 1; grid-row: auto; }
.app-embed .shell-footer .sf-nav { margin-top: 0; }
.app-embed .shell-footer .sf-bottom { grid-column: 1; grid-row: auto; display: flex; }

/* ── 모션 줄임 — 첫 문장만 정지 표시 · 나머지는 숨김(유령이 높이를 지킨다) ───────────────── */
@media (prefers-reduced-motion: reduce) {
  .shell-footer .sf-q span { animation: none; }
  .shell-footer .sf-q1 span { opacity: 1; transform: none; }
  .shell-footer .sf-q2, .shell-footer .sf-q3, .shell-footer .sf-q4 { visibility: hidden; }
  .shell-footer a { transition: none; }
}

/* ── 드로어 모드 ────────────────────────────────────────────────
   사이드바를 화면 밖에 두고 햄버거로 밀어 넣는다. 이제 **좁은 화면(≤768px)에서만** 켜진다.

   🔴 **의뢰인모드도 데스크톱에서는 상시 노출이다**(D-281, 사용자 지시). 예전에는
      「의뢰인모드 — 폭과 무관하게 항상 드로어」였다. 그래서 같은 서비스인데 세무사는 메뉴가
      늘 보이고 의뢰인은 매번 햄버거를 눌러야 했다 — **모드가 다르다고 조작법까지 달라졌다.**
   ⇒ 골격은 하나다. 데스크톱이면 상시 노출 + 레일 접기, 좁으면 드로어. 모드는 관여하지 않는다.
   ⚠ 아래 규칙을 다시 `.shell-client`로 좁히지 마라 — 좁히는 순간 의뢰인만 레일을 잃고,
     그러면 hover 툴팁(shell.js)도 함께 죽는다(툴팁은 «라벨이 실제로 숨겨졌을 때»만 붙는다).
   ⚠ 좁은 화면용 드로어 규칙은 아래 `@media (max-width: 768px)` 블록에 **일반형으로 이미 있다**.
     여기서 의뢰인 전용 사본을 지운 것이지 드로어를 없앤 게 아니다. */
.hamburger { display: inline-flex; }
.drawer-scrim { display: none; }

/* ── 모바일(≤768px): 모드와 무관하게 드로어 ───────────── */
@media (max-width: 768px) {
  /* 좁은 화면 상단바 — 참고 지면(nol.yanolja.com)도 모바일에서는 윗줄이 56px다.
     ⚠ :root와 body 양쪽에 적는다 — 위에서 body.shell-pro에 62px를 걸었으므로 :root만
       고치면 일터 셸이 그 62px를 계속 본다(가까운 조상이 이긴다). */
  :root { --topbar-h: 56px; }
  body.shell-pro { --topbar-h: 56px; }
  /* 🔴 여기서 `.brand-mark { height }`를 덮지 마라 — 그 값은 **창 높이 = 로고 잉크 높이**다
     (shell.css 위쪽 --brand-ink 주석). 심볼만 쓰던 시절의 `height: 34px`가 여기 남아 있어서
     좁은 화면에서만 잉크가 24 → 34px로 커져 있었다(실측으로 발견). 잉크는 어느 폭에서도
     가이드 최소 24px 그대로 두고, 좁은 화면에서 조일 것은 **칩 여백**뿐이다(위 .topbar .brand). */
  /* 좁은 화면에는 검색칸이 들어갈 자리가 없다 — 브랜드·햄버거가 먼저다. */
  .top-search { display: none; }
  .sidebar {
    width: var(--sidebar-w) !important;
    transform: translateX(-100%); transition: transform .2s ease;
  }
  html.drawer-open .sidebar { transform: none; box-shadow: 0 8px 40px rgba(17, 31, 40, .18); }
  html.drawer-open .drawer-scrim {
    display: block; position: fixed; inset: var(--topbar-h) 0 0 0; z-index: 15;
    background: rgba(0, 0, 0, .35);
  }
  /* 모바일에선 접기 개념이 없다 — 라벨·캡션을 항상 보이게 되돌린다. */
  html.rail .nlabel { display: inline; }
  html.rail .nav-cap { display: block; }
  html.rail .nav-item { width: auto; padding: 0 12px; gap: 10px; justify-content: flex-start; }
  html.rail .side-scroll { padding: 8px 10px; }
  /* 56px 바 — 잉크 24px + 위아래 여백 4px = 32px. 링(offset 2 + 굵기 2)까지 들어간다.
     ⚠ 잉크를 24px 밑으로 내리지 마라(가이드 최소치). 줄일 것은 칩 여백뿐이다. */
  .topbar .brand { padding: 4px 14px; }
  html.rail .nav-group + .nav-group { margin-top: 14px; padding-top: 0; border-top: 0; }
  html.rail .side-profile { justify-content: flex-start; padding: 10px 12px; }
  html.rail .sp-txt { display: flex; }
  html.rail .side-mode { grid-template-columns: 1fr 1fr; }
  html.rail .side-mode-btn { width: auto; height: 32px; margin: 0; border: 0; background: transparent; }
  html.rail .side-mode-btn.on { display: inline-flex; background: var(--primary); }
  .main { margin-left: 0 !important; padding: 16px 16px 48px; }
  /* 좁은 화면에서는 브랜드가 가운데, 햄버거가 왼쪽 — 좌측 구역은 폭만 잡는다. */
  .topbar { padding: 0 var(--s-md); gap: var(--s-sm); }
}

/* 로그인 유도 — 메뉴 안에서 다른 항목과 구분되어야 눈에 걸린다. */
.nav-cta { color: var(--primary); font-weight: 700; }
.nav-cta:hover { background: var(--primary-light); }

/* ── 의뢰인 상단바 (D-138a → 높이는 D-166에서 되돌림) ────────────────────
   ⚠ 예전엔 `.shell-client { --topbar-h: 48px }`로 **의뢰인 바만 얇게** 했다. "글자 하나와
     버튼 하나뿐이라 같은 높이면 흰 띠만 두껍게 남는다"가 이유였는데, 사용자 지시로
     **68px**(참고 지면 nol.yanolja.com 윗줄 실측)로 되돌렸다.
   ⚠ 높이를 다시 덮지 마라. --topbar-h는 사이드바 top·스크림 inset·본문 padding-top이
     모두 따라오는 값이라, 상단바에만 걸면 그 셋이 어긋난다(위 body.shell-pro 주석 참조).
   아래 항목들(패딩·아이콘)은 의뢰인 바를 **가볍게** 유지하려는 것이라 남긴다. */
.shell-client .topbar { padding: 0 var(--s-lg); }
.shell-client .icon-btn { width: 34px; height: 34px; }
.shell-client .icon-btn svg { width: 20px; height: 20px; }
/* ⚠ 의뢰인 바에서 심볼을 줄이지 않는다(D-167) — 워드마크가 없어 심볼이 유일한 표식이라
   작게 만들면 브랜드가 안 읽힌다. */

/* ══ 앱 인앱 웹뷰 임베드 (D-692) ═══════════════════════════════════════════════
   앱은 화면이 없는 기능을 웹뷰로 연다(D-252 ②, 지금 14곳). 그때 웹이 자기 상단바를 들고
   들어와 **앱 앱바 아래에 상단바가 두 겹**이 됐다 — 「맞춤 세무사」에서 사용자가 봤다.

   🔴 내비게이션은 **앱이 갖는다**(앱바·서랍·하단 탭). 그러니 여기서는 셸을 접고 본문만 준다.
   ⚠ `display:none`으로 접는다 — 폭만 0으로 만들면 상단바 높이(--topbar-h)만큼 빈 띠가 남는다.
   ⚠ 판정은 서버 한 곳(GlobalModelAdvice.appEmbed)이고 여기서는 **그리기만** 한다.
      질의문자열을 CSS가 다시 읽지 마라. */
.app-embed .topbar,
.app-embed .sidebar { display: none; }
.app-embed .shell { padding-top: 0; }
.app-embed .main { padding-left: 0; padding-right: 0; }
/* 본문 자체의 좌우 여백은 지면들이 각자 갖고 있다 — 여기서 --shell-pad를 0으로 만들면
   글이 화면 가장자리에 붙는다. 셸이 주던 여백만 걷는다. */
