/* 말랩스 앱 공통 부품 v2
   ═══════════════════════════════════════════════════════════════
   `v1.css` 는 **값**을 맞췄다(색·글꼴·인터랙션·돌아가기 알약). 그것만으로는
   화면이 정갈해지지 않았다 — 값이 같아도 **모양**이 화면마다 달랐기 때문이다.

   실측이 그렇게 말한다(2026-09-13):
     시딩   페이지 평균  92줄 · 공용 부품  4개   ← 조립한다
     adref  페이지 평균 444줄 · 공용 부품 20개   ← 화면마다 다시 그린다
     허브   페이지 평균 235줄 · 공용 부품  0개   ← 전부 다시 그린다

   그래서 이 파일은 **모양**을 맞춘다. 카드 머리·표·빈 상태·요약 띠가
   어느 앱에서든 같은 것이 되도록.

   ── 기준을 어디서 가져왔나 ────────────────────────────────────
   대표가 데모 일곱 곳에서 둘을 골랐고(2026-09-13), 그 둘의 실제 소스를 받아
   수치를 나란히 놓고 섞었다. 추측한 값이 없다.

     shadcn 공식 blocks       (레지스트리 new-york-v4 원본)
     Material Dashboard Shadcn (GitHub, MIT)

     항목            shadcn   Material   우리      왜
     ─────────────────────────────────────────────────────────
     카드 모서리      12       12         12       둘이 같다
     카드 여백        24       24         24       둘이 같다
     카드 내부 간격   24       —          24       shadcn. 우리에겐 없던 규칙이다
     카드 그림자      있음     없음       없음     대표가 「깔끔」으로 고른 쪽
     버튼 높이        36       40         36       shadcn. 조밀한 쪽
     버튼 입체        없음     있음       있음     대표가 「입체감」으로 고른 쪽
     표 셀            8        16         12/16    둘 사이. 손익표는 오래 본다
     빈 상태          4단      없음       4단      shadcn. 우리는 글자 한 줄뿐이었다

   한 줄로 줄이면 — **면은 평평하게, 누르는 것만 입체로.**

   ⛔ **아이콘은 이모지를 계속 쓴다**(2026-09-13 대표 결정). lucide 로 바꾸는
      안이 있었지만 ⚠·⛔ 는 슬랙·문서에서도 쓰는 우리 말버릇이라 그대로 둔다.

   ── 쓰는 법 ──────────────────────────────────────────────────
     <link rel="stylesheet" href="https://app.marlabs.co.kr/ui/v2.css">
   그리고 앱은 `src/components/ui/` 의 얇은 부품 파일을 복사해 쓴다. 값은
   **여기 한 곳**에서 나오므로, 나중에 톤을 바꿔도 이 파일만 고치면 된다.

   ⛔ **판본을 올릴 때는 v3.css 를 새로 만든다.** 이 파일을 덮으면 한 앱을
      고치려다 전 앱이 같이 바뀌고, 그때는 되돌릴 자리가 없다.

   ⛔ **클래스 이름을 지우거나 바꾸지 않는다.** 2026-09-13 에 이 파일의 초안이
      `.v2-*` 를 쓰고 있었는데 정본을 만들면서 `.m2-*` 로 통째로 갈아엎었다.
      그 순간 `.v2-*` 를 쓰던 화면이 **아무 스타일도 없는 상태**가 되어 대표에게
      그대로 보였다. 서빙되는 파일 쪽에서는 **누가 쓰고 있는지 알 수 없다** —
      값은 바꿔도 되지만 이름은 남긴다.

   ⛔ **고치면 부르는 쪽의 `?v=` 를 같이 올린다.** 서빙 헤더가
      `max-age=300, stale-while-revalidate=86400` 이라, 옛 파일을 받아둔
      브라우저는 **최대 하루** 그걸 계속 쓴다. 같은 날 이것 때문에 멀쩡한
      화면까지 깨져 보였다. 지금 판: **v=27**

   ⛔ **이 파일은 `@layer` 밖이다 — Tailwind 유틸리티로 못 덮는다.**
      Tailwind 유틸리티는 `@layer utilities` 안에 있고, CSS 규칙상 **레이어 밖이
      레이어 안을 항상 이긴다**(구체성과 무관하다). 그래서

          <div className="m2-surface p-6">      ← p-6 은 안 먹는다. 여백은 24px
          <span className="m2-badge text-[11px]"> ← 11px 아니라 규격 글자크기
          <p className="m2-band__value mt-auto">  ← margin 을 규격이 다시 적는다

      **빌드도 통과하고 클래스도 남아 있는데 아무 일도 안 일어난다.** 2026-09-22
      goal100 에서 `Card` 가 언제나 `--flush`(padding:0) 라 화면 34곳의
      `p-3`·`p-5`·`p-6` 이 한 곳도 안 먹었고, 글자가 카드 테두리에 붙어 있었다.
      사람이 두 번 고치고 두 번 다 「여전해」였다.

      고치는 법 — 유틸리티를 지우고 **규격 부품의 변형**을 쓰거나, 규격을 고친다.
      그래도 덮어야 하면 **감싼 칸(`<div>`)에 준다** — 규격 클래스가 없는 칸이라 먹는다.
      점검기 `/root/bin/ui-audit.py` 가 「안 먹는 유틸리티」로 매일 센다. */

/* ─── 치수 ─────────────────────────────────────────────
   `@theme` 로 넣은 Tailwind 토큰(marlabs-hub#278)과 **같은 값**이다.
   Tailwind 를 안 쓰는 앱도 같은 치수를 갖게 하려고 여기 한 번 더 적는다. */
:root {
  --m2-radius: 0.75rem; /* 12px — 카드·패널·버튼·입력칸 */
  --m2-radius-sm: 0.375rem; /* 6px — 작은 칩·배지 */

  --m2-pad: 1.5rem; /* 24px — 카드 안 여백 (shadcn·Material 일치) */
  --m2-gap: 1.5rem; /* 24px — 카드 **안쪽** 덩어리 사이. shadcn gap-6 */
  --m2-gap-sm: 0.75rem; /* 12px — 버튼끼리, 칩끼리 */

  --m2-cell-y: 0.75rem; /* 12px — 표 셀 위아래 */
  --m2-cell-x: 1rem; /* 16px — 표 셀 좌우 */

  --m2-h: 2.25rem; /* 36px — 버튼·입력칸 높이 (shadcn h-9) */
  --m2-text: 0.875rem; /* 14px */
  --m2-text-sm: 0.8125rem; /* 13px */
}

/* ─── 층 ──────────────────────────────────────────────
   ⛔ **면에는 그림자를 주지 않는다.** 층은 테두리 1px 하나로 낸다.
      대표 규칙(「층은 그림자·테두리 하나만」)이자 Material 카드의 실제 모습이다.
      그림자를 쓰는 것은 **누를 수 있는 것 하나뿐**이다. */

/* ─── 카드 ─────────────────────────────────────────────
   내부는 세로 flex + gap 24 로 리듬을 고정한다. 지금까지는 자식마다
   `mb-2`·`mb-5`·`mt-0.5` 를 따로 붙여서 카드마다 간격이 달랐다. */
.m2-card {
  display: flex;
  flex-direction: column;
  gap: var(--m2-gap);
  padding: var(--m2-pad);
  border: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  border-radius: var(--m2-radius);
  background: var(--m-surface, #fff);
  box-shadow: none;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
/* ─── 면만 필요할 때 ───────────────────────────────────────
   `.m2-card` 는 **자식 사이를 24px 로 벌린다.** 그게 목적인 자리(제목·본문·
   단추가 층층이 쌓이는 카드)에는 맞지만, **촘촘한 숫자 더미**에는 안 맞는다.

   ⛔ goal100 의 지표 타일이 그랬다(2026-09-14). 「전체 ROAS」 밑에 숫자, 그
      밑에 설명을 `mt-0.5`(2px)·`mt-1`(4px)로 **일부러 붙여** 놨는데, 카드로
      감싸니 24px 씩 벌어져 한 덩어리로 안 읽히게 됐다.
      → 소스를 읽고 잡았다. 그 앱은 로컬 실행이 안 돼서 화면으로는 못 봤다.

   그래서 **면만** 주는 것을 따로 둔다. 자식이 자기 간격을 직접 정하는 자리에 쓴다.
   판단 한 줄: **간격을 카드가 정하면 `.m2-card`, 자식이 정하면 `.m2-surface`.** */
.m2-surface {
  padding: var(--m2-pad);
  border: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  border-radius: var(--m2-radius);
  background: var(--m-surface, #fff);
  box-shadow: none;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
[data-theme="dark"] .m2-surface {
  border-color: var(--m-border, oklch(37.2% 0.044 257.287));
  background: var(--m-surface, oklch(20.8% 0.042 265.755));
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}

/* 표를 통째로 담는 카드는 안쪽 여백이 없어야 한다 — 셀이 이미 갖고 있다 */
.m2-card--flush {
  padding: 0;
  gap: 0;
  overflow: hidden;
}
.m2-card__title {
  font-size: var(--m2-text);
  font-weight: 600;
  margin: 0;
}
.m2-card__sub {
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  margin: 0.25rem 0 0;
}
/* 제목+부제는 한 덩어리다 — 사이는 4px, 다음 덩어리와는 24px */
.m2-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--m2-gap-sm);
  flex-wrap: wrap;
}

/* 큰 상자(화면 안의 구역)의 제목. 위계를 셋으로 둔다:
     20px 페이지 제목 · 16px 구역 제목 · 14px 카드 제목 */
.m2-card__title--lg {
  font-size: 1rem;
}

/* 표를 담는 구역 — 머리는 여백을 갖고 본문만 가장자리까지 간다.
   `--flush`(여백을 통째로 없앰)와 다르다. 제목이 있는 상자에 쓴다. */
.m2-card--flushbody {
  overflow: hidden;
}
.m2-card--flushbody > :last-child {
  margin-inline: calc(var(--m2-pad) * -1);
  margin-bottom: calc(var(--m2-pad) * -1);
}

/* ─── 페이지 머리 ───────────────────────────────────────
   허브 35화면이 저마다 다르게 그리고 있었다. 하나로 둔다. */
.m2-pagehead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--m2-gap-sm);
  flex-wrap: wrap;
  margin-bottom: var(--m2-gap);
}
.m2-pagehead h1 {
  font-size: 1.25rem; /* 20px */
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}
.m2-pagehead p {
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  margin: 0.25rem 0 0;
}
.m2-pagehead__actions {
  display: flex;
  gap: var(--m2-gap-sm);
  flex-wrap: wrap;
}

/* ─── 요약 띠 ───────────────────────────────────────────
   숫자 몇 개를 나란히 보여주는 자리.

   ⛔ **색면을 깔지 않는다** (2026-09-14 대표: *"이런건 너무 투박하게 안이쁜데?
      레퍼런스 2개를 잘 합친거맞아? 깔끔한 느낌이 없잖아"* — goal100 오가닉 띠).

      그 전 판은 연한 강조색으로 **면 전체를 칠하고 라벨까지 강조색**으로 뒀다.
      레퍼런스 둘 다 그렇게 안 한다:
        shadcn *Section Cards*  흰 면 + 테두리 · 라벨은 흐린 회색 · 숫자만 크게
        Material 대시보드        흰 카드 + **작은 색 아이콘 한 점**
      둘 다 강조는 **한 점**이지 면이 아니다. 대표가 준 카드뉴스도 그랬다 —
      큰 검정 덩어리에 오렌지가 한 점.

   ⛔ **숫자 크기를 칸마다 다르게 두지 않는다.** goal100 은 첫 칸만 `text-5xl`,
      나머지는 `text-3xl` 이라 밑줄이 안 맞아 들쭉날쭉해 보였다. 여기서 한 벌로
      고정한다 — 더 강조하고 싶은 칸은 `--lead` 를 준다(크기가 아니라 색이다).

   칸 사이 실선은 `gap:1px` + 바깥 배경으로 낸다. 줄바꿈이 일어나도 격자가
   그대로 유지된다(테두리를 칸에 직접 주면 두 줄째 첫 칸에 선이 남는다). */
/* ⚠️ 칸 사이 선을 `gap:1px` + 바깥 배경으로 내면, 줄바꿈이 일어나 **마지막 줄에
   빈 칸이 남을 때 그 자리가 구분선 색(회색)으로 보인다.** 폰 폭에서 5칸이 2열로
   접히자 실제로 그랬다(2026-09-14 실측). 칸마다 `box-shadow` 로 테두리를 그리면
   빈 자리는 그냥 비어 있고, 이웃한 선은 같은 색이라 1px 로 겹쳐 보인다. */
.m2-band {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 0;
  padding: 0;
  border: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  border-radius: var(--m2-radius);
  background: var(--m-surface, #fff);
  overflow: hidden;
}
.m2-band > * {
  /* 좌우는 **표 셀과 같은 16px.** 다르게 두면 띠 밑에 표가 오는 화면에서
     왼쪽 글자 줄이 어긋나 보인다(2026-09-14 전수 점검). */
  padding: 1rem var(--m2-cell-x);
  background: var(--m-surface, #fff);
  box-shadow: 0 0 0 0.5px var(--m-border, oklch(92.9% 0.013 255.508));
}
/* 숫자 칸은 **한 줄**이다. 「14,917,954원」이 두 줄로 꺾이면 카드 높이가 제각각이 되어
   줄이 어긋난다(2026-09-16 대표: "숫자가 한번에 안들어가", 주간회의·매출·오가닉).
   칸 폭에 맞춰 글자를 줄인다 — 값을 직접 담은 칸이 컨테이너다(cqi). 폭이 넉넉하면 24px. */
:where(:has(> .m2-band__value)) {
  container-type: inline-size;
  min-width: 0;
}
.m2-band__label {
  font-size: var(--m2-text-sm);
  font-weight: 500;
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  margin: 0;
}
.m2-band__value {
  font-size: clamp(1rem, 11cqi, 1.5rem);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
  margin: 0.25rem 0 0;
  white-space: nowrap;
}
/* 그 줄에서 제일 중요한 숫자 하나. 크기가 아니라 **색**으로 든다 — 크기를
   키우면 밑줄이 어긋나고, 그게 「투박하다」의 정체였다. */
.m2-band__value--lead {
  color: var(--m-accent-text-on-bg, oklch(45.7% 0.24 277.023));
}
/* 숫자 뒤에 붙는 단위(건·원·%). 숫자보다 작고 흐리다 */
.m2-band__unit {
  font-size: var(--m2-text);
  font-weight: 500;
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  margin-left: 0.25rem;
}

/* ─── 표 ───────────────────────────────────────────────
   shadcn 8px 과 Material 16px 사이. 손익·정산은 오래 들여다보는 표라
   위아래는 여유를 주고(12), 좌우는 읽는 폭을 지킨다(16). */
.m2-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--m2-text);
}
/* ⛔ **셀은 줄바꿈하지 않는다.** 폰 폭(390px)에서 표를 렌더하면 열이 눌리면서
   셀 안 글자가 **세로로 쪼개진다** — 「8월 / 10 / 일」, 「공 / 용」(2026-09-14 실측).
   대표가 같은 병을 단추에서 먼저 짚었다: *"버튼 세로로 되는것도 문제고,
   모바일버전에서 봤을때 배율맞게 최적화되어야된다는것도 잊으면 안돼"*

   표는 좁아지는 게 아니라 **넘쳐서 옆으로 스크롤**되는 것이 맞다. 그래서
   `.m2-scroll` 로 감싼다(아래). 긴 문장을 담는 열만 `wrap` 으로 푼다. */
.m2-table th,
.m2-table td {
  padding: var(--m2-cell-y) var(--m2-cell-x);
  text-align: left;
  vertical-align: middle;
  white-space: nowrap;
}
/* 긴 글이 들어가는 열에만 준다 — 메모·설명처럼 접혀도 되는 것 */
.m2-table .wrap {
  white-space: normal;
}

/* ⛔ **폰에서 페이지가 통째로 가로로 넘치는 진짜 원인** (2026-09-14 실측)

   `body` 를 flex 컨테이너로 쓰는 앱이 여럿이다(허브 `flex min-h-full flex-col`,
   비품 `flex min-h-dvh flex-col md:flex-row`). flex 자식은 `min-width: auto` 라
   **자기 min-content 보다 작아지지 않는다.** 안에 넓은 표가 하나 있으면
   `<main>` 이 표의 min-content 만큼(측정값 746px) 부풀고, 화면이 390px 이면
   페이지 전체가 옆으로 스크롤된다 — 표만이 아니라 제목·칩 줄까지 잘려 보인다.

   `overflow-x:auto` 감싸개를 제대로 씌워도 소용없다. 넘치는 것은 감싸개가
   아니라 **그 조상**이다.

   `:where()` 로 무게 0 에 둔다 — 앱이 자기 규칙으로 언제든 덮을 수 있다. */
/* 글꼴은 여기서 한 번만 정한다. `:where()` 라 무게가 0 이고, 앱이 자기
   규칙으로 언제든 덮을 수 있다 — 덮을 일이 없어야 맞지만 막지는 않는다. */
:where(body) {
  font-family: var(--m-font-sans);
}

/* ⛔ **부품은 테두리를 높이 안에 넣는다.** 안 그러면 같은 클래스인데 태그마다
   높이가 달라진다 — `<button class="m2-btn--sm">` 은 32px, `<a>` 는 34px 로
   나왔다(2026-09-16 실측). 나란히 놓이는 자리가 많아 2px 이 그대로 보인다.
   브라우저 기본값이 `<button>` 만 border-box 라서 생기는 차이다. */
.m2-btn,
.m2-back,
.m2-field,
.m2-chip,
.m2-nav > *,
.m2-seg > *,
.m2-tabs > * {
  box-sizing: border-box;
}

:where(body) > * {
  min-width: 0;
  /* ⚠️ `min-width:0` 만으로는 **안 된다**(실측). 세로 flex 의 자식은 `stretch`
     로 늘어나는데, 넓은 표가 있으면 Chrome 이 min-content 폭(746px)을 그대로
     쓴다. 폭 자체를 화면으로 묶어야 한다. */
  max-width: 100%;
}

/* 표를 감싸는 자리. 지금까지 앱마다 `<div className="overflow-x-auto">` 를 손으로
   적었고, 빠뜨린 화면은 폰에서 표가 통째로 잘렸다. 이름을 줘서 안 빠지게 한다. */
.m2-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.m2-table thead th {
  font-weight: 500;
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  border-bottom: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  white-space: nowrap;
}
.m2-table tbody tr {
  border-bottom: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
}
.m2-table tbody tr:last-child {
  border-bottom: 0;
}
/* 숫자 칸은 자릿수가 맞아야 읽힌다 */
.m2-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ─── 빈 상태 ───────────────────────────────────────────
   지금까지 우리는 글자 한 줄이 전부였다("아직 없습니다"). shadcn 은 넷을
   둔다 — 아이콘칸 · 제목 · 설명 · 다음에 할 일. 마지막이 특히 중요하다:
   빈 화면에서 **무엇을 하면 되는지**를 그 자리에서 알려준다. */
.m2-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--m2-gap-sm);
  padding: 2.5rem 1.5rem;
  border: 1px dashed var(--m-border-strong, oklch(86.9% 0.022 252.894));
  border-radius: var(--m2-radius);
  text-align: center;
}
/* ⚠️ 빈 상태는 **바탕이 비어 있다**(점선 테두리뿐). 아이콘칸을 페이지 바탕과
   비슷한 색으로 두면 통째로 안 보인다 — 실측으로 그랬다. 카드면 + 테두리로
   또렷하게 둔다. */
.m2-empty__icon {
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: var(--m2-radius-sm);
  background: var(--m-surface, #fff);
  border: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  font-size: 1.25rem;
  line-height: 1;
}
/* ⛔ **색을 반드시 정한다.** 빈 상태는 카드 밖에 놓이는 일이 많아서, 색을 안
   주면 그 화면의 글자색을 물려받는다 — 어두운 화면에서 제목이 통째로 안 보였다
   (2026-09-13 실측). 토큰에서 가져오면 밝기를 따라간다. */
.m2-empty__title {
  font-size: var(--m2-text);
  font-weight: 600;
  margin: 0;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
.m2-empty__desc {
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  margin: 0;
  max-width: 44ch;
}

/* ─── 버튼 ─────────────────────────────────────────────
   높이는 shadcn(36), 입체는 Material. 위 1px 흰선 + 아래 2px 검은선이
   「눌러도 될 것 같은」 느낌의 전부다.
   ⛔ Material 에는 실제 눌림(`:active`)이 없다 — 그건 우리 것이고 남긴다. */
.m2-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  height: var(--m2-h);
  padding: 0 1rem;
  font: inherit;
  font-size: var(--m2-text);
  font-weight: 500;
  border-radius: var(--m2-radius-sm);
  cursor: pointer;
  white-space: nowrap;
  color: var(--m-accent-text, #fff);
  border: 1px solid var(--m-accent-edge, oklch(45.7% 0.24 277.023));
  /* ⚠️ 면은 `--m-accent-solid` 다. 표시용(`--m-accent`)은 더 밝아서 글자를
     얹으면 안 읽힌다. 없는 판에서는 `--m-accent` 로 물러난다.

     ⛔ **이 규칙을 파일 뒤쪽에서 다시 쓰지 말 것.** 한 번 그렇게 했다가
        `.m2-btn--quiet`(아래)보다 뒤에 와서 **보조 버튼이 전부 오렌지로
        채워졌다**(2026-09-14, 리뷰업로더에서 눈으로 발견). 선택자 무게가
        같으면 나중에 적힌 쪽이 이긴다. 값은 토큰으로 바꾸고 규칙은 여기 하나만 둔다. */
  background-image: linear-gradient(
    to bottom,
    var(--m-accent-hi, oklch(58.5% 0.233 277.117)),
    var(--m-accent-solid, var(--m-accent, oklch(51.1% 0.262 276.966)))
  );
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.25),
    inset 0 -2px 0 rgb(0 0 0 / 0.35),
    0 1px 2px rgb(15 23 42 / 0.12);
  transition: box-shadow 200ms ease-in;
}
.m2-btn:hover:not(:disabled) {
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.25),
    inset 0 -2px 0 rgb(0 0 0 / 0.35),
    0 3px 8px rgb(15 23 42 / 0.2);
}
.m2-btn:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: inset 0 2px 3px rgb(0 0 0 / 0.3);
}
/* 못 누름 — `opacity` 만 낮추면 **흐린 오렌지가 여전히 화면에서 제일 눈에 띈다.**
   채움을 걷어내고 회색으로 둔다. 「지금은 못 누른다」가 형태로 보여야 한다. */
.m2-btn:disabled {
  background-image: none;
  background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
  border-color: var(--m-border, oklch(92.9% 0.013 255.508));
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  opacity: 1;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}
/* 보조 — 여기까지 입체를 주면 화면에 볼록한 것이 너무 많아진다 */
.m2-btn--quiet {
  background-image: none;
  background: transparent;
  box-shadow: none;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
  border-color: var(--m-border-strong, oklch(86.9% 0.022 252.894));
}
.m2-btn--quiet:hover:not(:disabled) {
  box-shadow: none;
  border-color: var(--m-accent, oklch(51.1% 0.262 276.966));
  opacity: 0.75;
}
.m2-btn--quiet:active:not(:disabled) {
  box-shadow: none;
}
/* 위험 — **채우지 않는다.** 주 동작이 오렌지 채움이라, 위험을 빨강으로 채우면
   색조가 10° 밖에 안 벌어져 나란히 뒀을 때 같은 단추로 보인다(실측 대비 1.01:1).
   형태로 가른다: 주 동작만 채움, 위험은 붉은 테두리 + 붉은 글자.
   부수 효과로 **실수로 삭제를 누를 확률도 준다** — 눈이 채운 쪽으로 먼저 간다. */
.m2-btn--danger {
  background-image: none;
  background: var(--m-surface, #fff);
  border-color: var(--m-bad-line, oklch(80% 0.1 27.5));
  box-shadow: none;
  color: var(--m-bad, oklch(50.5% 0.213 27.518));
}
.m2-btn--danger:hover:not(:disabled) {
  background: var(--m-bad-bg, oklch(96% 0.02 27.5));
  border-color: var(--m-bad, oklch(50.5% 0.213 27.518));
  box-shadow: none;
  opacity: 1;
}
/* ── 줄마다 있는 「저장」 ────────────────────────────────────
   위 규칙(**반복되는 줄에는 강조를 쓰지 않는다**)에는 곧바로 따라오는 물음이
   있다 — *그럼 줄마다 하나씩 있는 저장 단추는 어떻게 하나?*

   회색으로 두면 고르개들 사이에 묻혀 안 보이고(실제로 그랬다), 주 단추로 두면
   목록에 오렌지가 여덟 개 생겨 규칙을 스스로 어긴다.

   답: **평소엔 조용, 그 줄을 건드리는 동안만 주 단추.** 사용자가 실제로 고치고
   있는 줄은 언제나 하나뿐이므로, 화면에 강조는 늘 0개 아니면 1개다.
   자바스크립트 없이 `:focus-within` 하나로 된다. */
.m2-btn--armed {
  background-image: none;
  background: transparent;
  box-shadow: none;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
  border-color: var(--m-border-strong, oklch(86.9% 0.022 252.894));
}
:where(form, [data-arm]):focus-within .m2-btn--armed {
  color: var(--m-accent-text, #fff);
  border-color: var(--m-accent-edge, oklch(45.7% 0.24 277.023));
  background-image: linear-gradient(
    to bottom,
    var(--m-accent-hi, oklch(58.5% 0.233 277.117)),
    var(--m-accent-solid, var(--m-accent, oklch(51.1% 0.262 276.966)))
  );
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.25),
    inset 0 -2px 0 rgb(0 0 0 / 0.35),
    0 1px 2px rgb(15 23 42 / 0.12);
}

.m2-btn--sm {
  height: 2rem; /* 32px — shadcn h-8 */
  padding: 0 0.75rem;
  font-size: var(--m2-text-sm);
}

/* ─── 입력칸 ───────────────────────────────────────────── */
.m2-field {
  height: var(--m2-h);
  width: 100%;
  padding: 0 0.75rem;
  font: inherit;
  font-size: var(--m2-text);
  border-radius: var(--m2-radius-sm);
  border: 1px solid var(--m-border-strong, oklch(86.9% 0.022 252.894));
  background: var(--m-surface, #fff);
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
.m2-field:focus-visible {
  outline: 2px solid var(--m-accent, oklch(51.1% 0.262 276.966));
  outline-offset: 2px;
}
/* 줄 안에 끼워 넣는 입력칸(필터의 고르개 같은 것). `.m2-field` 는 width:100%
   라 그대로 쓰면 한 줄을 다 먹는다 — 폭만 내용에 맞춘다.
   ⚠️ Tailwind 의 `w-auto` 로는 안 된다. 이 파일은 레이어 밖이라 유틸리티를 이긴다. */
.m2-field--inline {
  width: auto;
  /* ⛔ 상한이 없으면 <select> 가 **가장 긴 항목 이름만큼** 늘어난다 — goal100
     오가닉에서 「제품: 전체」 고르개가 옆 「브랜드」의 세 배로 벌어졌다
     (2026-09-16 대표 사진). 넘치는 글자는 말줄임으로 자른다. */
  max-width: 16rem;
  text-overflow: ellipsis;
}

/* 여러 줄 입력. `.m2-field` 는 높이가 36px 로 고정이라 `<textarea>` 에 그대로
   쓰면 한 줄로 눌린다 — 높이만 풀고 나머지(테두리·모서리·색)는 그대로 쓴다. */
.m2-field--area {
  height: auto;
  min-height: calc(var(--m2-h) * 2);
  padding: 0.5rem 0.75rem;
  line-height: 1.5;
}
.m2-label {
  display: block;
  font-size: var(--m2-text-sm);
  font-weight: 500;
  margin-bottom: 0.375rem;
}
.m2-help {
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  margin: 0.375rem 0 0;
}

/* ═══ 강조를 쓰는 법 — 규칙 하나 ═══════════════════════════
   **반복되는 줄에는 강조를 쓰지 않는다.**

   2026-09-14 대표(goal100 `/gf/settings` 오가닉 계정 캡처): *"이런것 보면 눈에
   하나도 안띄지?"* 계정 8개가 전부 담당자 미지정이라 「담당자를 정해야 …」가
   **오렌지로 여덟 번** 찍혔다. 여덟 번 반복된 강조는 강조가 아니라 배경이다.
   게다가 그 문장은 바로 위 고르개가 이미 「담당자 미지정」이라고 말하고 있었다.

   목록·표처럼 같은 줄이 N 번 반복되는 자리는 이렇게 나눈다:

     줄 안(N번)   전부 중립. 상태는 `.m2-badge--quiet` 같은 무채색으로만
     머리(1번)    **여기에만** 강조. 「담당자 미지정 8」처럼 **개수로** 말한다

   할 일은 화면에 한 번만 적힌다. 그래야 그 한 곳이 눈에 띈다.
   ═══════════════════════════════════════════════════════ */

/* ─── 세로 메뉴 ─────────────────────────────────────────
   2026-09-14 대표(`/admin` 캡처): *"여기 메뉴도 uiux 통일해줘야되는거 알지?"*

   원인은 그 화면이 아니라 **규격에 세로 메뉴가 없던 것**이다. `.m2-tabs`·`.m2-seg`
   는 가로용이라, 세로 메뉴는 다섯 곳이 각각 손으로 그리고 있었다:
     허브 `/admin` · 비품 Sidebar · goal100 GfSidebar · 시딩 Sidebar · adref
   셋은 서로 베낀 사본이라 거의 같았고(그래서 여기 치수는 그 셋에서 가져왔다),
   허브와 adref 만 따로 놀았다.

   ⚠️ **손가락 크기**를 규격이 정한다. 마우스에서는 36px 로 조밀하게, 손가락
   (`pointer: coarse`)에서는 44px 로 벌린다 — 앱마다 `py-1.5` / `py-2.5` 를
   손으로 갈라 쓰다 폰에서 눌리는 칸 높이가 제각각이었다. */
.m2-nav {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
/* 폰에서는 왼쪽에 둘 자리가 없다. 눕히고 옆으로 밀어 보게 한다.
   ⚠️ 앱이 Tailwind `max-sm:flex-row` 로 못 뒤집는다 — 이 파일은 레이어 밖이라
      유틸리티를 이긴다(2026-09-14 `/admin` 에서 실측). 그래서 변형을 여기 둔다. */
.m2-nav--responsive {
  gap: 0.25rem;
}
@media (max-width: 639px) {
  .m2-nav--responsive {
    flex-direction: row;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 0.25rem;
  }
  .m2-nav--responsive > * {
    flex-shrink: 0;
  }
}

.m2-nav > * {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  box-sizing: border-box;
  width: 100%;
  min-height: var(--m2-h);
  padding: 0.375rem 0.625rem;
  border: 0;
  border-radius: var(--m2-radius-sm);
  background: transparent;
  box-shadow: none;
  /* 항목이 <button> 인 앱(리오더 탭·시딩 상품)에서 브라우저 기본 단추 글꼴·가운데
     정렬이 새어 들어와 글자가 한가운데로 몰렸다(2026-09-16 실측). 링크와 같게 되돌린다. */
  font: inherit;
  font-size: var(--m2-text);
  text-align: left;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
  text-decoration: none;
  cursor: pointer;
}
@media (pointer: coarse) {
  .m2-nav > * {
    min-height: 2.75rem; /* 44px — 손가락으로 누르는 최소 크기 */
  }
}
.m2-nav > *:hover {
  background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
}
/* 고른 표시는 다른 부품과 **같은 선택자 넷**을 받는다 */
.m2-nav > [aria-current="page"],
.m2-nav > [aria-selected="true"],
.m2-nav > [aria-pressed="true"],
.m2-nav > [data-on="true"] {
  background: var(--m-accent-bg, oklch(96.2% 0.018 272.314));
  color: var(--m-accent-text-on-bg, oklch(45.7% 0.24 277.023));
  font-weight: 500;
}
/* 아이콘 칸 — 글자 시작점이 항목마다 어긋나지 않게 폭을 고정한다 */
.m2-nav__icon {
  display: flex;
  width: 1.25rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.m2-nav__label {
  flex: 1;
  min-width: 0;
}
/* 항목 오른쪽 개수·꼬리표 */
.m2-nav__n {
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
}
/* 메뉴 안 구역 제목 */
/* ⛔ 묶음 제목이 **항목보다 흐리면 안 된다.** 흐린 회색 보통 굵기로 뒀더니
   위아래 구분이 사라져 메뉴가 그냥 긴 목록으로 보였다(2026-09-16 대표:
   *"상위메뉴와 하위메뉴의 구분감이 전혀없는데"*).

   기준 앱(시딩)은 **주황 막대 + 굵은 진한 글자**다. 거기에 맞춘다 —
   막대는 글자가 아니라 그림이라 글꼴이 바뀌어도 자리가 안 흔들린다. */
.m2-nav__group {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 1.25rem 0 0.25rem;
  padding: 0 0.5rem;
  font-size: var(--m2-text-sm);
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
.m2-nav__group::before {
  content: "";
  width: 0.25rem;
  height: 0.875rem;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--m-accent, oklch(51.1% 0.262 276.966));
}
/* 맨 위 묶음 제목만 위 여백 0. ⛔ 그냥 `:first-child` 로 두면 앱이 묶음을 <div> 로
   한 겹 감쌀 때 **모든** 제목이 첫째 자식이 되어 위 항목에 붙는다(CRM·골포커싱·
   adref 실측, 2026-09-16 대표: "좌측 메뉴 간격… CRM은 엉망"). 몸통 기준으로 센다. */
.m2-side__body > .m2-nav__group:first-child,
.m2-side__body > :first-child > .m2-nav__group:first-child {
  margin-top: 0;
}

/* ─── 전체 너비 토글 ─────────────────────────────────────
   대표(2026-09-16): "전체너비 버튼만 나오고 기능은 구현안된것도 있네".
   앱마다 Tailwind 로 스위치를 그렸는데 Tailwind 없는 앱(CRM·리오더)에서는
   클래스가 아무것도 안 해 **글자만 남은 단추**가 됐다. 여기서 그린다 —
   마크업은 `PageWidth` 템플릿 하나, 모양은 이 파일 하나.

     <div class="m2-widthbar">
       <button type="button" role="switch" aria-checked="true" class="m2-switch">
         <span class="m2-switch__label">↔ 전체 너비</span>
         <span class="m2-switch__track"><span class="m2-switch__knob"></span></span>
       </button>
     </div> */
/* 본문 폭. 켜면 사이드바 뺀 자리를 다 쓰고, 끄면 72rem(6xl) 가운데.
   ⛔ Tailwind `max-w-6xl` 로 두면 Tailwind 없는 앱에서 **단추만 있고 폭은 안 바뀐다**. */
.m2-width {
  max-width: none;
}
.m2-width--center {
  max-width: 72rem;
  margin-left: auto;
  margin-right: auto;
}
.m2-widthbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem; /* 왼쪽에 「log」(v2.js) 가 앉는다 */
  margin-bottom: 0.25rem;
}
.m2-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 2rem;
  padding: 0 0.5rem;
  border: 0;
  border-radius: var(--m2-radius-sm);
  background: transparent;
  box-shadow: none;
  font: inherit;
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  cursor: pointer;
}
.m2-switch:hover {
  background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
}
.m2-switch__track {
  position: relative;
  display: inline-block;
  width: 2rem;
  height: 1rem;
  flex: none;
  border-radius: 999px;
  background: var(--m-border-strong, oklch(86.9% 0.022 252.894));
  transition: background-color 0.15s;
}
.m2-switch__knob {
  position: absolute;
  top: 0.125rem;
  left: 0.125rem;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.25);
  transition: transform 0.15s;
}
.m2-switch[aria-checked="true"] .m2-switch__track {
  background: var(--m-accent-solid, oklch(51.1% 0.262 276.966));
}
.m2-switch[aria-checked="true"] .m2-switch__knob {
  transform: translateX(1rem);
}

/* ─── 왼쪽 메뉴 골격 ─────────────────────────────────────
   대표(2026-09-16): *"좌측 메뉴 템플릿도 다 가지각색이거든? 이걸 통일할거야."*

   전수(2026-09-16): 사이드바가 있는 앱 9곳이 **전부 달랐다** — 폭 220·224·240,
   묶음 제목 넷, 항목 다섯, 폰에서 안 접히는 곳 하나. 규격에 골격이 없어서
   앱마다 그렸다. 기준 앱(시딩)을 그대로 옮겨 적는다.

   앱은 이 마크업만 쓴다(값·색·폭·폰 동작은 전부 여기가 정한다):

     <div class="m2-shell">
       <aside class="m2-side" data-open="false">
         <div class="m2-side__brand">
           <span class="m2-side__icon">N</span>
           <span class="m2-side__name">협찬·시딩 관리<small>인플루언서 협찬</small></span>
           <button class="m2-side__toggle" aria-expanded="false">메뉴</button>
         </div>
         <div class="m2-side__body">
           <nav class="m2-nav">…</nav>
           <p class="m2-nav__group">상품 관리</p>
           <nav class="m2-nav">…</nav>
           <div class="m2-side__foot">
             <a class="m2-back" href="…">시작화면</a>
             <p class="m2-side__who">이름<small>역할</small></p>
           </div>
         </div>
       </aside>
       <main class="m2-main">…</main>
     </div>

   폰(767px 이하)에서는 접혀서 이름 줄만 남고 「메뉴」로 연다. 앱은 `data-open`
   만 바꾼다 — 화면을 옮기면 false 로 되돌리는 것도 앱 몫이다(안 닫으면 새 화면
   위에 덮인다). */
.m2-shell {
  display: flex;
  min-height: 100dvh;
  align-items: stretch;
}
.m2-main {
  flex: 1;
  min-width: 0;
  padding: 1.25rem 1rem;
}
@media (min-width: 768px) {
  .m2-main {
    padding: 1.5rem;
  }
}
.m2-side {
  box-sizing: border-box;
  width: 15rem; /* 240px — 기준 앱 값 */
  flex: none;
  display: flex;
  flex-direction: column;
  background: var(--m-surface, #fff);
  border-right: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  /* PC 에서는 화면에 붙박이다. 페이지 길이만큼 늘어나게 두면 맨 아래
     「시작화면」 단추가 표 끝까지 밀려 **긴 화면에서는 안 보인다**
     (adref 롱런 소재 실측, 2026-09-16). 메뉴는 스크롤해도 늘 같은 자리. */
  position: sticky;
  top: 0;
  height: 100dvh;
  align-self: flex-start;
}
.m2-side__brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 1rem;
  border-bottom: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
}
.m2-side__icon {
  display: flex;
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border-radius: var(--m2-radius-sm);
  background: var(--m-accent-solid, var(--m-accent, oklch(51.1% 0.262 276.966)));
  color: var(--m-accent-text, #fff);
  font-size: var(--m2-text-sm);
  font-weight: 700;
  line-height: 1;
}
.m2-side__name {
  flex: 1;
  min-width: 0;
  font-size: var(--m2-text);
  font-weight: 600;
  line-height: 1.2;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.m2-side__name small {
  display: block;
  font-size: 0.625rem; /* 10px */
  font-weight: 400;
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  margin-top: 0.125rem;
}
.m2-side__toggle {
  display: none; /* 폰에서만 */
}
.m2-side__body {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  overflow-y: auto;
  padding: 0.75rem;
}
/* 묶음 제목은 위 항목과 **띄운다**(1.25rem). 붙이면 어느 묶음 것인지 안 읽힌다. */
.m2-side__body > .m2-nav__group + .m2-nav {
  margin-top: 0.125rem;
}
.m2-side__foot {
  margin-top: auto;
  padding-top: 0.75rem;
  border-top: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
}
.m2-side__foot .m2-back {
  width: 100%;
  justify-content: center;
}
.m2-side__who {
  margin: 0.75rem 0 0;
  padding: 0 0.5rem;
  font-size: var(--m2-text);
  font-weight: 500;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
.m2-side__who small {
  display: block;
  font-size: var(--m2-text-sm);
  font-weight: 400;
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
}
/* ─── 사이드바 접기 (PC) ─────────────────────────────────────
   대표(2026-09-16): *"이 메뉴바는 축소시킬 수 있는 버튼을 놓으면 좋겠어. 노션에서
   사이드바 닫기처럼"*. 단추와 상태는 `/ui/v2.js` 가 붙인다(앱은 마크업을 안 고친다):
     .m2-side__brand 안에 <button class="m2-side__collapse"> · 접히면 .m2-side[data-collapsed="true"]
   접힌 폭 3.75rem — 아이콘만 남고 이름·묶음 제목·꼬리표·누구인지는 숨는다.
   아이콘이 없는 항목은 JS 가 첫 글자로 만든다(.m2-nav__icon--auto). */
.m2-side__collapse {
  display: none;
}
@media (min-width: 768px) {
  .m2-side {
    transition: width 0.15s ease;
  }
  .m2-side__collapse {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    flex: none;
    padding: 0;
    border: 0;
    border-radius: var(--m2-radius-sm);
    background: transparent;
    color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
    cursor: pointer;
  }
  .m2-side__collapse:hover {
    background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
    color: var(--m-text, oklch(20.8% 0.042 265.755));
  }
  .m2-side__collapse::before {
    content: "";
    width: 1rem;
    height: 1rem;
    background: currentColor;
    mask: var(--m2-panel-icon) center / contain no-repeat;
    -webkit-mask: var(--m2-panel-icon) center / contain no-repeat;
  }
  .m2-side[data-collapsed="true"] {
    width: 3.75rem;
  }
  .m2-side[data-collapsed="true"] .m2-side__brand {
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.75rem 0.5rem;
  }
  .m2-side[data-collapsed="true"] .m2-side__name,
  .m2-side[data-collapsed="true"] .m2-nav__group,
  .m2-side[data-collapsed="true"] .m2-nav__label,
  .m2-side[data-collapsed="true"] .m2-nav__n,
  .m2-side[data-collapsed="true"] .m2-side__who,
  .m2-side[data-collapsed="true"] .m2-side__foot .m2-btn {
    display: none;
  }
  .m2-side[data-collapsed="true"] .m2-side__body {
    padding: 0.5rem;
    overflow-x: hidden;
  }
  .m2-side[data-collapsed="true"] .m2-nav > * {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
  }
  /* 묶음 제목 대신 얇은 선으로 묶음을 가른다 */
  .m2-side[data-collapsed="true"] .m2-nav__group + .m2-nav {
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  }
  .m2-side[data-collapsed="true"] .m2-side__foot .m2-back {
    padding: 0;
    gap: 0;
    font-size: 0; /* 글자는 감추고 화살표만 */
  }
}
/* 아이콘이 없는 항목에 JS 가 만든 첫 글자 아이콘 */
.m2-nav__icon--auto {
  font-size: 0.6875rem;
  font-weight: 700;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 0.25rem;
  background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
}
.m2-side:not([data-collapsed="true"]) .m2-nav__icon--auto {
  display: none; /* 펼쳐 있을 때는 글자만 — 원래 모양 그대로 */
}

/* 폰 — 접어 둔다. 시딩·골포커싱·CRM·리오더가 이미 이렇게 동작한다. */
@media (max-width: 767px) {
  .m2-shell {
    flex-direction: column;
  }
  .m2-side {
    width: auto;
    height: auto;
    align-self: stretch;
    position: sticky;
    top: 0;
    z-index: 30;
    border-right: 0;
    border-bottom: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  }
  .m2-side__brand {
    padding: 0.625rem 0.875rem;
    border-bottom: 0;
  }
  .m2-side__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 2rem;
    padding: 0 0.75rem;
    font: inherit;
    font-size: var(--m2-text-sm);
    font-weight: 500;
    border-radius: var(--m2-radius-sm);
    border: 1px solid var(--m-border-strong, oklch(86.9% 0.022 252.894));
    background: var(--m-surface, #fff);
    color: var(--m-text, oklch(20.8% 0.042 265.755));
    cursor: pointer;
  }
  .m2-side__body {
    display: none;
  }
  .m2-side[data-open="true"] .m2-side__body {
    display: flex;
    max-height: 70dvh;
    border-top: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
  }
}
[data-theme="dark"] .m2-side,
[data-theme="dark"] .m2-side__brand,
[data-theme="dark"] .m2-side__foot {
  border-color: var(--m-border, oklch(37.2% 0.044 257.287));
}

/* ─── 배지 ─────────────────────────────────────────────
   작은 것에는 작은 모서리. 6px 이다 — 18px 짜리에 12px 을 주면 알약이 된다. */
.m2-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border-radius: var(--m2-radius-sm);
  border: 1px solid transparent;
  font-size: var(--m2-text-sm);
  font-weight: 500;
  white-space: nowrap;
}
.m2-badge--accent {
  background: var(--m-accent, oklch(51.1% 0.262 276.966));
  color: var(--m-accent-text, #fff);
}
.m2-badge--quiet {
  background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
  border-color: var(--m-border, oklch(92.9% 0.013 255.508));
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
}
.m2-badge--warn {
  background: var(--m-warn-bg, oklch(98.7% 0.022 95.277));
  border-color: var(--m-warn-line, oklch(82.8% 0.189 84.429));
  color: var(--m-warn-text, oklch(41.4% 0.112 45.904));
}
.m2-badge--ok {
  background: var(--m-ok-bg, oklch(97.9% 0.021 166.113));
  border-color: var(--m-ok-line, oklch(84.5% 0.143 164.978));
  color: var(--m-ok-text, oklch(43.2% 0.095 166.913));
}
/* 작은 꼬리표. 배지가 옆 본문(14px)과 거의 같은 13px 이라 「또 하나의 글자」로
   읽혔다 — 크기 한 단계를 규격이 갖는다(2026-09-22 대표 결정, 세 안을 렌더해 비교).
   ⚠️ 글자만 줄이면 알약이 헐렁해진다. 좌우·위아래 여백도 한 단계 조인다.
   ⛔ 화면에서 `text-[11px]` 로 적지 않는다 — 규격이 이겨서 안 먹는다(#443·#444). */
.m2-badge--sm {
  padding: 0.0625rem 0.375rem;
  font-size: 0.6875rem; /* 11px */
}

/* 잘못된 것·실패한 것. 기준 앱(시딩)을 규격에 맞추다 **없어서** 찾았다 —
   「무산」·「실패」 꼬리표를 담을 자리가 규격에 없었다(2026-09-16). */
.m2-badge--bad {
  background: var(--m-bad-bg, oklch(96% 0.02 27.5));
  border-color: var(--m-bad-line, oklch(80% 0.1 27.5));
  color: var(--m-bad, oklch(50.5% 0.213 27.518));
}

/* ─── 어두운 화면 ───────────────────────────────────────
   ⚠️ 반드시 위 규칙들 **아래**에 둔다. 우선순위가 같아서 나중에 적힌 쪽이
      이긴다 — 위에 두면 조용히 안 먹는다(시딩이 그렇게 배포된 적이 있다). */
[data-theme="dark"] .m2-card,
[data-theme="dark"] .m2-table thead th,
[data-theme="dark"] .m2-table tbody tr {
  border-color: var(--m-border, oklch(37.2% 0.044 257.287));
}
[data-theme="dark"] .m2-card {
  background: var(--m-surface, oklch(20.8% 0.042 265.755));
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}
[data-theme="dark"] .m2-band {
  border-color: var(--m-border, oklch(37.2% 0.044 257.287));
  background: var(--m-surface, oklch(20.8% 0.042 265.755));
}
[data-theme="dark"] .m2-band > * {
  background: var(--m-surface, oklch(20.8% 0.042 265.755));
  box-shadow: 0 0 0 0.5px var(--m-border, oklch(37.2% 0.044 257.287));
}
[data-theme="dark"] .m2-band__value {
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}
[data-theme="dark"] .m2-band__value--lead {
  color: var(--m-accent-text-on-bg, oklch(78.5% 0.115 274.713));
}
[data-theme="dark"] .m2-empty {
  border-color: var(--m-border-strong, oklch(44.6% 0.043 257.281));
}
[data-theme="dark"] .m2-empty__title {
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}
[data-theme="dark"] .m2-empty__icon {
  background: var(--m-surface, oklch(20.8% 0.042 265.755));
  border-color: var(--m-border, oklch(37.2% 0.044 257.287));
}
[data-theme="dark"] .m2-badge--quiet {
  background: var(--m-surface-2, oklch(27.9% 0.041 260.031));
}
[data-theme="dark"] .m2-field {
  border-color: var(--m-border-strong, oklch(44.6% 0.043 257.281));
  background: var(--m-surface-2, oklch(27.9% 0.041 260.031));
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}
[data-theme="dark"] .m2-nav > * {
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}
[data-theme="dark"] .m2-nav > *:hover {
  background: var(--m-surface-2, oklch(27.9% 0.041 260.031));
}
[data-theme="dark"] .m2-nav > [aria-current="page"],
[data-theme="dark"] .m2-nav > [aria-selected="true"],
[data-theme="dark"] .m2-nav > [aria-pressed="true"],
[data-theme="dark"] .m2-nav > [data-on="true"] {
  background: var(--m-accent-bg, oklch(25.7% 0.09 281.288));
  color: var(--m-accent-text-on-bg, oklch(78.5% 0.115 274.713));
}
[data-theme="dark"] .m2-btn--armed,
[data-theme="dark"] .m2-btn--quiet {
  color: var(--m-text, oklch(96.8% 0.007 247.896));
  border-color: var(--m-border-strong, oklch(44.6% 0.043 257.281));
}

/* '동작 줄이기'를 켠 사람에게는 움직임을 뺀다(v1 과 같은 이유). */
@media (prefers-reduced-motion: reduce) {
  .m2-btn {
    transition: none;
  }
  .m2-btn:active:not(:disabled) {
    transform: none;
  }
}

/* ═══════════════════════════════════════════════════════════════
   블랙 앤 오렌지 — 회사 컨셉 색 (2026-09-14 대표 요청)

   대표가 준 카드뉴스 두 장에서 **픽셀을 직접 뽑았다.** 눈대중한 값이 없다.
     밝은 판  바탕 #F7F3EC · 글자 #1A1612 · 오렌지 #E8430D · 보조 #6B6258
     어두운 판 바탕 #0A0A0A · 글자 #F5F1EA · 오렌지 #FF5722 · 보조 #9A9289

   ── ⚠️ 오렌지가 둘인 이유 ──────────────────────────────────
   밝은 바탕에서 `#E8430D` 위에 흰 글자는 **4.01** 이다. 본문 기준이 4.5 라
   미달이고, 버튼 글자가 안 읽힌다. 어두운 판은 문제가 없다 — 대표가 준
   이미지가 오렌지 면에 **검은 글자**를 얹어 6.26 을 만들고 있다.

   그래서 자리를 갈랐다:
     --m-accent       표시용. 테두리·아이콘·큰 글자   (이미지 그대로)
     --m-accent-solid 면용. 글자를 얹는 자리(버튼)     (밝은 판만 조금 진하게)
                      밝은 판 #C93A0B 위 흰 글자 5.13 ✅
                      어두운 판 #FF5722 위 검은 글자 6.26 ✅

   ⛔ **이 블록을 지우거나 값을 흩뜨리지 말 것.** 색을 또 바꿀 일이 생기면
      여기 열 줄만 고친다 — 2026-09-14 에 앱 여섯 곳의 클래스를 일일이
      바꾸느라(`bg-slate-900` → `bg-indigo-600`, 58+29곳) 같은 일을 두 번 했다.
      그 반복을 없애려고 토큰으로 뺀 것이다.
   ── ⛔ 기본값이다. 표시를 붙여야 나오는 게 아니다 (2026-09-14 고침) ──
      처음엔 `[data-brand="orange"]` 안에만 뒀다. 그런데 **그 표시를 붙인 앱이
      CRM 하나뿐**이었다 — 허브·adref·리뷰업로더·비품 앱은 `.m2-*` 부품이
      전부 **옛 인디고**로 나오고 있었다(2026-09-14 비품 앱 로컬 렌더로 확인:
      화면은 오렌지인데 「복사」 단추만 파랬다. Tailwind 램프는 갈아끼웠지만
      부품 CSS 는 이 파일에서 값을 받아 가기 때문이다).

      「앱을 새로 붙여도 자동으로 기준 테마」가 되려면 **아무것도 안 붙인 앱이
      오렌지여야** 한다. 그래서 `:root` 로 옮긴다. `[data-brand="orange"]` 는
      이미 붙인 앱(CRM)이 깨지지 않게 그대로 둔다 — 같은 값이다.
   ═══════════════════════════════════════════════════════════ */
:root,
[data-brand="orange"] {
  /* ── 검정을 쓴다 (2026-09-14 대표) ──────────────────────────
     *"블랙오렌지 테마니까 검은색도 적절하게 잘써줘. 너무 오렌지랑 베이지만
     쓰니까 맛이 안살고 눈에도 잘 안띄는거같아"* — 라이트 모드 얘기다.

     맞다. 크림 바탕 + 회색 글자 + 오렌지만 쓰면 **전부 중간 톤**이라 눈이
     걸릴 데가 없다. 대표가 준 이미지에는 **큰 검정 덩어리**(굵은 제목)가
     있고 오렌지는 거기 한 점이다.

     그래서 「먹」을 따로 둔다 — 고른 것·중요한 단추처럼 **무게가 필요한
     자리**를 검정으로 채운다. 오렌지는 강조 한 점으로 아껴 쓴다. */
  --m-ink: #14110e;
  --m-ink-text: #fffdf9;

  /* 「밖으로 나가는 링크」 전용 회색. 보조 글자(`--m-text-muted`, 5.40)보다
     한 칸 진하다 — 앱 밖으로 데려가는 글자는 **7.5:1** 을 지킨다는 사내
     규약이 있다(허브 #246, CRM 이 그 이유를 자기 파일에 적어 뒀다).
     ⚠️ 이 값이 없으면 CRM 이 옛 차가운 회색으로 폴백해 혼자 파랗게 남는다. */
  --m-quiet: #4f473f;

  /* ── 글꼴 (2026-09-16) ──────────────────────────────────────
     ⛔ 규격이 글꼴을 **안 정하고 있었다.** 그래서 앱마다 제각각이었다 —
        댓글 스튜디오만 `Apple SD Gothic Neo`·`Malgun Gothic` 이라 혼자 다른
        글씨였다(2026-09-16 대표: *"폰트도 그렇고 아예 기준문서랑 템플릿이
        안맞는 느낌이야. 색감만 맞췄고"*).
     웹폰트를 새로 받지 않는다 — Pretendard 가 깔린 기기는 그것을, 아니면
     각 OS 의 기본 글꼴을 쓴다. 느려지지 않으면서 대부분 같은 글씨가 된다. */
  --m-font-sans:
    "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont,
    system-ui, "Segoe UI", "Apple SD Gothic Neo", "Malgun Gothic", roboto,
    "Helvetica Neue", sans-serif;
  --m-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* 왼쪽 꺾쇠. 글자가 아니라 그림이라 글꼴이 바뀌어도 모양이 안 변한다. */
  --m2-chevron-left: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M10 3 5 8l5 5'/></svg>");
  --m2-panel-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='1.75' y='2.75' width='12.5' height='10.5' rx='2'/><path d='M6 2.75v10.5'/></svg>");

  --m-bg: #f7f3ec;
  --m-surface: #fffdf9;
  --m-surface-2: #f0ebe1;
  --m-text: #1a1612;
  --m-text-muted: #6b6258;
  --m-border: #e2dbcd;
  --m-border-strong: #d8d0c0;

  /* 표시용 — 테두리·아이콘·띠·큰 글자. 대표가 준 이미지 값 그대로 (밝은 오렌지) */
  --m-accent: #e8430d;

  /* 버튼·칩 면 — **흰 글자**다 (2026-09-14 대표: "오렌지 버튼에는 흰색 글씨가
     낫지않을까 싶어. 인디고도 그랬고").

     ⚠️ 그런데 밝은 브랜드 오렌지(#FF5722) 위에 흰 글자는 **3.16** 이라 안 읽힌다.
        그래서 **면만** 조금 진하게 한다. 표시용 오렌지는 위 그대로 밝다 —
        띠·테두리·아이콘은 눈에 띄어야 하고 글자를 얹지 않으니 문제가 없다.

     ⚠️ 그라데이션은 **윗쪽이 가장 밝다.** 거기가 대비의 기준이다:
          윗 #d53d0c 위 흰 글자 4.66 ✅ · 아래 #c23809 위 5.44 ✅
        (비교: 옛 인디고 버튼은 6.46)

     ⛔ 밝기와 무관하게 **같은 값**을 쓴다. 오렌지 단추는 어느 판에서든 같은
        단추여야 한다 — 판마다 다르면 「눌러도 되는 것」의 모양을 두 번 배운다. */
  --m-accent-hi: #d53d0c;
  --m-accent-solid: #c23809;
  --m-accent-edge: #a32f09;
  --m-accent-text: #ffffff;

  /* ── 그래프 계열 색 (2026-09-16) ─────────────────────────────
     선이 여럿인 그래프는 색도 여럿이어야 한다. 그렇다고 앱이 각자 고르면
     같은 화면을 옮겨 다닐 때 「매출」이 앱마다 다른 색이 된다 — 허브는
     인디고·로즈·에메랄드·앰버·스카이, goal100 은 보라 하나였다.

     첫째는 **브랜드 오렌지**다. 한 줄짜리 그래프는 늘 이 색이 된다.
     나머지는 오렌지와 색조가 충분히 떨어지면서 크림·검정 양쪽에서 읽히는 값. */
  --m-series-1: #e8430d;
  --m-series-2: #2f7d8f;
  --m-series-3: #7a5209;
  --m-series-4: #6b4c9a;
  --m-series-5: #14663f;
  --m-series-6: #a51f18;

  --m-accent-bg: #fdeee7;
  --m-accent-line: #f2c2ae;
  --m-accent-text-on-bg: #9c2d09;

  /* ── 상태색 — 2026-09-14 에 **처음** 정한다 ─────────────────
     그 전까지 `--m-bad`·`--m-warn-*`·`--m-ok-*` 는 **어디에도 정의되지 않았고**
     규칙마다 적힌 폴백(옛 인디고판 값)만 쓰이고 있었다. 그래서 위험 단추가
     옛 빨강(#c62f21)으로 떨어졌는데, 주 동작 오렌지(#c23809)와
     **색조 차이 10° · 밝기 대비 1.01:1** 이라 나란히 두면 같은 단추로 보였다
     (2026-09-14 부품 전수 렌더로 확인 — 「삭제」와 「주 동작」이 구분 불가).

     오렌지가 브랜드색인 이상 **빨강으로는 위험을 못 가른다.** 색이 아니라
     **형태**로 가른다 — 주 동작만 채우고 위험은 테두리형이다.
     그래서 여기 빨강은 채움색이 아니라 **글자·테두리색**이다. */
  /* ⚠️ **위험 바탕은 강조 바탕과 색조를 벌려야 한다.** 처음엔 #fdecea 로 뒀는데
     강조 바탕(#fdeee7)과 **색조 차이가 13°** 뿐이라, adref 의 「수집이 멈춘 것
     같습니다」 경고 상자가 **경고가 아니라 강조로 읽혔다**(2026-09-14 렌더로 확인).
     브랜드가 주황-빨강이라, 위험은 **분홍 쪽으로** 확실히 민다(325° 차이). */
  --m-bad: #a51f18; /* 카드면 위 7.36 · 아래 분홍 바탕 위 6.48 ✅ */
  --m-bad-bg: #fdeaef;
  --m-bad-line: #eeaab6;

  --m-warn-bg: #fdf4e3;
  --m-warn-line: #e8c98a;
  --m-warn-text: #7a5209; /* 오렌지와 안 헷갈리게 노랑 쪽으로 */

  --m-ok-bg: #e9f6ef;
  --m-ok-line: #a9d8bf;
  --m-ok-text: #16643f;
}
[data-theme="dark"],
[data-theme="dark"] [data-brand="orange"],
[data-brand="orange"][data-theme="dark"] {
  /* 어두운 판에서 「먹」은 뒤집힌다 — 검정 바탕에 검정을 얹을 수는 없다.
     하는 일(무게를 준다)은 같고 색만 반대다. */
  --m-ink: #f5f1ea;
  --m-ink-text: #0a0a0a;
  --m-quiet: #a8a198;

  --m-bg: #0a0a0a;
  --m-surface: #0e0c0a;
  --m-surface-2: #171310;
  --m-text: #f5f1ea;
  --m-text-muted: #9a9289;
  --m-border: #2a261f;
  /* ⚠️ 입력칸·보조단추·점선 테두리가 이 값을 쓴다. #3a352c 는 페이지 바탕
     (#0a0a0a) 대비 **1.63:1** 이라 어두운 판에서 **입력칸이 안 보였다**
     (2026-09-14 전수 렌더로 확인. 경계는 3:1 이 기준 — WCAG 1.4.11).
     #6b6355 는 3.34:1 이다. */
  --m-border-strong: #6b6355;

  /* 표시용은 어두운 바탕에서 더 밝게 — 검은 바탕 위 6.26 */
  --m-accent: #ff5722;
  /* 면은 밝은 판과 **같은 값**이다(위 설명 참조). 검은 바탕과도 4.94 로 갈린다. */
  --m-accent-hi: #d53d0c;
  --m-accent-solid: #c23809;
  --m-accent-edge: #a32f09;
  --m-accent-text: #ffffff;

  --m-accent-bg: #180e0b;
  --m-accent-line: #4a2416;
  --m-accent-text-on-bg: #ff5722;

  --m-bad: #ff8a7d;
  --m-bad-bg: #2a100c;
  --m-bad-line: #5c2620;

  --m-warn-bg: #241a08;
  --m-warn-line: #5c4517;
  --m-warn-text: #f0c063;

  --m-ok-bg: #0c1f16;
  --m-ok-line: #1f4d36;
  --m-ok-text: #6fd0a1;
}

/* 규격 색으로 칠하는 바탕. 미리보기·새 앱이 페이지 전체를 토큰에 맡길 때 쓴다. */
.m2-page {
  background: var(--m-bg, oklch(96.8% 0.007 247.896));
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}

/* ═══════════════════════════════════════════════════════════════
   고르는 것들 — 칩 · 분할 · 탭 (2026-09-14)

   대표: *"이런걸 보면 통일감이 안느껴져"* — adref 와 리뷰업로더를 나란히 놓고.

   색을 같게 해도 통일이 안 됐던 이유는 **같은 일을 하는 부품의 모양이 앱마다
   달랐기** 때문이다. 세어보니 「고르기」 하나에 네 가지 모양이 있었다:

     adref        알약 칩(필터 15~25개) · 알약 탭(정렬) · 분할 컨트롤(이미지/영상)
     리뷰업로더    큰 카드 + 체크 동그라미 · 분할 컨트롤(엑셀/직접입력)
     허브 키워드   밑줄 탭(화면 이동)

   ⚠️ **하나로 합치면 안 된다.** 하는 일이 다르기 때문이다. 셋으로 나눈다:

     .m2-tabs   **화면을 옮긴다** — 주소가 바뀐다. 밑줄로 지금 위치를 표시
     .m2-seg    **값을 고른다(2~4개)** — 한 자리에서 바뀐다. 분할 컨트롤
     .m2-chip   **값을 고른다(많다)** — 필터처럼 개수를 모를 때. 알약

   판단 기준 한 줄: **주소가 바뀌면 탭, 개수가 적으면 분할, 많으면 칩.**
   ═══════════════════════════════════════════════════════════ */

/* ─── 나가는 문 ───────────────────────────────────────────
   앱에서 시작 화면으로 돌아가는 단추.

   ⛔ **이름은 「시작화면」 하나다**(2026-09-16 대표 지시). 그전에는 네 가지가
      살아 있었다 — 「도구 모음」·「말랩스도구」·「말랩스 시작 화면」·「말랩스 허브」.
      한 앱 안에 세 가지가 같이 있는 곳도 있었다(골포커싱·adref·비품).
      *"어디서는 '도구모음'으로 나오고 어디서는 '말랩스 허브'로 나오고
      대체 왜이러는거냐고"*

   ⛔ **화살표를 글자로 찍지 않는다.** 유니코드 `←` 는 글꼴마다 굵기와 높이가
      달라 옆 글자와 안 맞는다. 여기서 그려 주므로 앱은 이름만 적는다:

        <a class="m2-back" href="https://app.marlabs.co.kr">시작화면</a>

   모양은 조용한 단추(`.m2-btn--quiet.m2-btn--sm`)와 같은 값이다. */
.m2-back {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  height: 2rem;
  padding: 0 0.75rem;
  font: inherit;
  font-size: var(--m2-text-sm);
  font-weight: 500;
  border-radius: var(--m2-radius-sm);
  border: 1px solid var(--m-border-strong, oklch(86.9% 0.022 252.894));
  background: var(--m-surface, #fff);
  /* 앱 밖으로 데려가는 글자는 7.5:1 을 지킨다는 사내 규약이 있다 */
  color: var(--m-quiet, oklch(44.6% 0.043 257.281));
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.m2-back::before {
  content: "";
  width: 0.875rem;
  height: 0.875rem;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: var(--m2-chevron-left) center / contain no-repeat;
  mask: var(--m2-chevron-left) center / contain no-repeat;
}
.m2-back:hover {
  background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
.m2-back:active {
  transform: translateY(1px);
}
@media (prefers-reduced-motion: reduce) {
  .m2-back:active {
    transform: none;
  }
}

/* ─── 화면 이동 탭 ───────────────────────────────────────── */
.m2-tabs {
  display: flex;
  gap: 0.125rem;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
}
.m2-tabs::-webkit-scrollbar {
  display: none;
}
.m2-tabs > * {
  flex-shrink: 0;
  padding: 0.625rem 0.875rem;
  font-size: var(--m2-text);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  text-decoration: none;
  background: none;
  border-top: 0;
  border-inline: 0;
  cursor: pointer;
  font-family: inherit;
}
.m2-tabs > [aria-current="page"],
.m2-tabs > [aria-selected="true"],
.m2-tabs > [aria-pressed="true"],
.m2-tabs > [data-on="true"] {
  color: var(--m-accent, oklch(51.1% 0.262 276.966));
  border-bottom-color: var(--m-accent, oklch(51.1% 0.262 276.966));
  font-weight: 500;
}

/* ─── 분할 컨트롤 (2~4개 중 하나) ─────────────────────────
   눌러야 할 것들이 **한 덩어리로 붙어 있어야** 「이 중에 하나」로 읽힌다.
   떨어뜨려 놓으면 각각이 별개 단추로 보인다. */
.m2-seg {
  display: inline-flex;
  gap: 0.125rem;
  padding: 0.1875rem;
  border-radius: 999px;
  background: var(--m-surface-2, oklch(96.8% 0.007 247.896));
  border: 1px solid var(--m-border, oklch(92.9% 0.013 255.508));
}
.m2-seg > * {
  padding: 0.3125rem 0.875rem;
  border-radius: 999px;
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  white-space: nowrap;
  text-decoration: none;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
  transition:
    background 160ms,
    color 160ms;
}
/* ⚠️ 이 자리는 **링크로 만드는 일이 많다**(주소에 값이 실린다). 링크에는
   `aria-pressed` 를 쓰지 않는다 — 누름 상태가 아니라 「지금 이 값」이므로
   `aria-current="page"` 가 맞다. 셋 다 받아 준다. */
/* 고른 것은 **먹으로 채운다.** 흰 알약으로 두면 회색 트랙 위에서 거의 안
   보인다 — 「고른 것」은 한눈에 들어와야 한다. */
.m2-seg > [aria-selected="true"],
.m2-seg > [aria-pressed="true"],
.m2-seg > [aria-current="page"],
.m2-seg > [data-on="true"] {
  background: var(--m-ink, var(--m-surface, #fff));
  color: var(--m-ink-text, var(--m-text, oklch(20.8% 0.042 265.755)));
  font-weight: 600;
}

/* ─── 필터 칩 (개수가 많다) ───────────────────────────────
   ⚠️ 켜진 것은 **면을 채운다.** 테두리만 바꾸면 열댓 개가 늘어섰을 때
      무엇이 켜졌는지 한눈에 안 들어온다(adref 실측: 한 화면에 15~25개). */
.m2-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  font-size: var(--m2-text-sm);
  border: 1px solid var(--m-border-strong, oklch(86.9% 0.022 252.894));
  background: transparent;
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  font-family: inherit;
  transition:
    border-color 160ms,
    background 160ms,
    color 160ms;
}
.m2-chip:hover {
  border-color: var(--m-accent, oklch(51.1% 0.262 276.966));
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
.m2-chip[aria-pressed="true"],
.m2-chip[aria-current="page"],
.m2-chip[data-on="true"] {
  background: var(
    --m-accent-solid,
    var(--m-accent, oklch(51.1% 0.262 276.966))
  );
  border-color: var(
    --m-accent-edge,
    var(--m-accent, oklch(45.7% 0.24 277.023))
  );
  color: var(--m-accent-text, #fff);
  font-weight: 500;
}
/* 칩 옆의 개수 — 켜졌을 때도 읽혀야 한다 */
.m2-chip__n {
  opacity: 0.65;
  font-variant-numeric: tabular-nums;
}

/* ─── 큰 선택 카드 (둘 중 하나를 고르는데 설명이 필요할 때) ──
   리뷰업로더의 「리뷰에이드 / 알파리뷰」 같은 자리. 분할 컨트롤로 하기엔
   설명이 붙고, 칩으로 하기엔 무게가 다르다. */
.m2-choice {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: var(--m2-pad);
  border-radius: var(--m2-radius);
  border: 1px solid var(--m-border-strong, oklch(86.9% 0.022 252.894));
  background: var(--m-surface, #fff);
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  transition:
    border-color 160ms,
    background 160ms;
}
.m2-choice:hover {
  border-color: var(--m-accent, oklch(51.1% 0.262 276.966));
}
/* ⛔ 고른 표시는 **넷이 같은 선택자를 받는다.** 전에는 여기만 `aria-pressed`
   하나였고, `data-on="true"` 로 적은 화면은 **아무 표시도 안 나면서 오류도
   안 났다**(2026-09-14 전수 점검에서 발견). 규격이 부품마다 다르면 앱이 어긋난다.
   ⚠️ 골라진 표시는 **안쪽 그림자**로 굵힌다 — `border-width` 를 키우면 그 칸만
      1px 씩 움직여서 옆 칸과 밑줄이 어긋난다. */
.m2-choice[aria-pressed="true"],
.m2-choice[aria-selected="true"],
.m2-choice[aria-current="page"],
.m2-choice[data-on="true"] {
  border-color: var(--m-accent, oklch(51.1% 0.262 276.966));
  background: var(--m-accent-bg, oklch(96.2% 0.018 272.314));
  box-shadow: inset 0 0 0 1px var(--m-accent, oklch(51.1% 0.262 276.966));
}
.m2-choice__title {
  font-size: var(--m2-text);
  font-weight: 600;
  color: var(--m-text, oklch(20.8% 0.042 265.755));
}
.m2-choice__desc {
  font-size: var(--m2-text-sm);
  color: var(--m-text-muted, oklch(55.4% 0.046 257.417));
}

/* 어두운 화면 — ⚠️ 위 규칙들 **아래**에 둔다 */
[data-theme="dark"] .m2-tabs,
[data-theme="dark"] .m2-seg {
  border-color: var(--m-border, oklch(37.2% 0.044 257.287));
}
[data-theme="dark"] .m2-seg {
  background: var(--m-surface-2, oklch(27.9% 0.041 260.031));
}
/* ⚠️ 여기서 색을 다시 정하지 않는다 — `--m-ink` 가 판마다 뒤집히므로 위
   규칙 하나로 둘 다 맞는다. 옛 판(먹 토큰이 없는 인디고)에서는 폴백이
   흰 알약이라 예전 그대로다. */
[data-theme="dark"] .m2-seg > [aria-selected="true"]:not([data-x]),
[data-theme="dark"] .m2-seg > [aria-pressed="true"]:not([data-x]) {
  background: var(--m-ink, var(--m-surface, oklch(20.8% 0.042 265.755)));
  color: var(--m-ink-text, var(--m-text, oklch(96.8% 0.007 247.896)));
}
[data-theme="dark"] .m2-chip {
  border-color: var(--m-border-strong, oklch(44.6% 0.043 257.281));
  color: var(--m-text-muted, oklch(70.4% 0.04 256.788));
}
[data-theme="dark"] .m2-chip:hover {
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}
[data-theme="dark"] .m2-choice {
  border-color: var(--m-border-strong, oklch(44.6% 0.043 257.281));
  background: var(--m-surface, oklch(20.8% 0.042 265.755));
}
[data-theme="dark"] .m2-choice__title {
  color: var(--m-text, oklch(96.8% 0.007 247.896));
}
[data-theme="dark"] .m2-choice[aria-pressed="true"],
[data-theme="dark"] .m2-choice[aria-selected="true"],
[data-theme="dark"] .m2-choice[aria-current="page"],
[data-theme="dark"] .m2-choice[data-on="true"] {
  background: var(--m-accent-bg, oklch(25.7% 0.09 281.288));
}

/* ─── 먹 단추 ───────────────────────────────────────────
   오렌지는 강조 **한 점**이라 화면에 여러 개 두면 힘이 빠진다. 무게는
   필요한데 주 동작이 아닌 자리는 먹으로 채운다.
   ⛔ 한 화면에 오렌지 단추와 먹 단추를 **둘 다 여러 개** 두지 않는다 —
      그러면 무엇이 주 동작인지 다시 알 수 없어진다. */
.m2-btn--ink {
  background-image: none;
  background: var(--m-ink, oklch(20.8% 0.042 265.755));
  border-color: var(--m-ink, oklch(20.8% 0.042 265.755));
  color: var(--m-ink-text, #fff);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.15),
    inset 0 -2px 0 rgb(0 0 0 / 0.3),
    0 1px 2px rgb(15 23 42 / 0.12);
}
