/* Path: T2Editor/css/t2-visual-system.css */
/* ═══════════════════════════════════════════════════════════════════════════
 * T2Editor Visual System — Precision Rail (rev 2026-08-09)
 *
 * 레이어 3/3. 코어·관리자·모듈·플러그인 표면의 최종 외형.
 * 로드 순서: t2-foundation.css → core/dark → 모듈 → 플러그인 → 이 파일.
 *
 * 이전 개정 대비 변경
 *  - 전체를 @layer t2.product 로 감싸 !important 559개를 0개로 줄였다.
 *    레이어 순서가 특이도를 이기므로 덧칠이 필요하지 않다.
 *  - 대상 셀렉터의 :where() 를 제거했다. v11 은 앵커와 대상을 모두
 *    :where() 로 싸서 특이도가 0,0,0 이었고 클래스 하나에도 패배했다.
 *  - 상태의 주 단서는 하단 rail 이다. 세로 rail 은 관리자 설정 표면
 *    (내비 현재 위치, 목록 현재 항목)에만 쓴다. 한 요소에 상하단 rail 과
 *    좌우측 rail 을 겹치지 않고, 에디터 셸·모달·플러그인에는 쓰지 않는다.
 *  - 하단 상태 바를 원본 감성으로 복원했다. 실제 클래스는 .t2-editor-status
 *    이며 이 개정의 초안이 .t2-editor-statusbar 로 잘못 지정해 구세대 스타일로
 *    렌더되고 있었다.
 *  - 사용자 콘텐츠(css/content.css)는 건드리지 않는다. authored content.
 * ═══════════════════════════════════════════════════════════════════════════ */

@layer t2.product {

/* ═══ 1. 타이포그래피 ═══════════════════════════════════════════════════ */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], [data-t2-modal-companion], .t2-plugin-surface-modal,
  .t2-color-picker-container, .t2-dropdown-layer, .t2-font-size-list,
  .t2-privacy-surface, .t2-nsfw-dialog, .t2-safeai-legal-modal,
  .admin-wrap, .auth-screen, .key-screen, .login-screen) {
  font-family: var(--t2-font-ui);
  font-size: 14px;
  line-height: 1.55;
  letter-spacing: var(--t2-track-body);
  color: var(--t2-ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* 아이콘 폰트가 없을 때 ligature 텍스트가 레이아웃을 밀지 않게 한다 */
:where(.material-icons, .material-icons-outlined, .mi) {
  font-weight: normal; font-style: normal; line-height: 1;
  letter-spacing: normal; text-transform: none; white-space: nowrap;
  overflow: hidden; max-width: 1.25em; flex: 0 0 auto;
  font-feature-settings: "liga";
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
.material-icons, .mi { font-family: "Material Icons"; }
.material-icons-outlined { font-family: "Material Icons Outlined"; }

/* DSc 계보 표식 — 제품색과 역할이 겹치지 않는다 (law 705 §7-9).
   .t2-logo 계열은 §5b 의 lockup 정의에서 단독으로 다룬다. 여기서 중복
   정의하면 gap 이 두 칸을 벌려 일체감을 깨뜨린다. */
.t2-dsc-service-brand, [data-t2-brand="dsc"] {
  color: var(--t2-dsc); font-weight: 700;
  background: transparent; border: 0; padding: 0;
}
.t2-product-brand { color: currentColor; font-weight: 600; letter-spacing: var(--t2-track-title); }
.t2-version-line { font-family: var(--t2-font-mono); font-size: 11px; color: var(--t2-ink-faint); font-variant-numeric: tabular-nums; }


/* ═══ 2. 상호작용 기준선 · 포커스 ═══════════════════════════════════════ */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], [data-t2-modal-companion], .t2-plugin-surface-modal,
  .t2-color-picker-container, .t2-dropdown-layer, .t2-font-size-list,
  .t2-privacy-surface, .t2-nsfw-dialog, .t2-safeai-legal-modal,
  .admin-wrap, .auth-screen, .key-screen, .login-screen)
  :is(button, input, textarea, select, a[href], summary,
      [role="button"], [role="option"], [role="tab"], [tabindex]) {
  font: inherit;
  letter-spacing: inherit;
  -webkit-tap-highlight-color: transparent;
}

/* Focus = 1px outline @2px offset. 두께·레이아웃 불변 (law 707 H) */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], [data-t2-modal-companion], .t2-plugin-surface-modal,
  .t2-color-picker-container, .t2-dropdown-layer, .t2-font-size-list,
  .t2-privacy-surface, .t2-nsfw-dialog, .t2-safeai-legal-modal,
  .admin-wrap, .auth-screen, .key-screen, .login-screen)
  :is(button, input, textarea, select, a[href], summary,
      [role="button"], [role="option"], [role="tab"], [tabindex]):focus {
  outline: none;
}
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], [data-t2-modal-companion], .t2-plugin-surface-modal,
  .t2-color-picker-container, .t2-dropdown-layer, .t2-font-size-list,
  .t2-privacy-surface, .t2-nsfw-dialog, .t2-safeai-legal-modal,
  .admin-wrap, .auth-screen, .key-screen, .login-screen)
  :is(button, input, textarea, select, a[href], summary,
      [role="button"], [role="option"], [role="tab"], [tabindex]):focus-visible {
  outline: 1px solid var(--t2-product);
  outline-offset: 2px;
  border-radius: inherit;
}

/* 마우스·터치 누름은 키보드 포커스를 흉내내지 않는다 */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .admin-wrap) button:active:not(:disabled) { opacity: .78; }


/* ═══ 3. 폼 컨트롤 ══════════════════════════════════════════════════════
   컨트롤은 칠해진 상자여서 컨트롤인 게 아니다. hit area + 상태 (law 707 G).
   ⚠ 대상 셀렉터를 :where() 로 싸지 않는다 — v11 의 0,0,0 특이도 버그. */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], [data-t2-modal-companion], .t2-plugin-surface-modal,
  .t2-dropdown-layer, .t2-privacy-surface, .t2-nsfw-dialog,
  .admin-wrap, .auth-screen, .key-screen, .login-screen)
  :is(input:not([type]), input[type="text"], input[type="search"], input[type="email"],
      input[type="url"], input[type="tel"], input[type="number"], input[type="password"],
      input[type="date"], input[type="time"], input[type="datetime-local"],
      textarea, select) {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  min-height: 38px;
  padding: var(--t2-s2) 0;
  color: var(--t2-ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--t2-line-strong);
  border-radius: var(--t2-radius-field) var(--t2-radius-field) 0 0;
  box-shadow: none;
  font-size: 15px;
  transition: border-color var(--t2-motion-fast);
}
/* [iOS] coarse 환경 입력 텍스트는 16px 이상 — 자동 확대 방지 */
@media (pointer: coarse) {
  :where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
    [data-t2-plugin-surface], .admin-wrap, .auth-screen, .key-screen, .login-screen)
    :is(input, textarea, select) { font-size: 16px; min-height: 44px; }
}

:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .t2-privacy-surface, .admin-wrap)
  :is(input, textarea, select):hover:not(:disabled) { border-bottom-color: var(--t2-ink-faint); }

/* 포커스 시 두께가 아니라 색만 승격한다 */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .t2-privacy-surface, .admin-wrap)
  :is(input, textarea, select):focus-visible {
  outline: none;
  border-bottom-color: var(--t2-product);
  box-shadow: 0 1px 0 0 var(--t2-product);
}
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .admin-wrap)
  :is(input, textarea, select):disabled {
  color: var(--t2-ink-faint);
  border-bottom-color: var(--t2-line);
  cursor: not-allowed;
}
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .admin-wrap)
  :is(input, textarea)::placeholder { color: var(--t2-ink-faint); }
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .admin-wrap)
  :is(input[aria-invalid="true"], input.is-invalid, .form-control.is-invalid) {
  border-bottom-color: var(--t2-danger);
}
:where(.t2-editor-container, .t2-modal-overlay, .admin-wrap) textarea {
  min-height: 76px; resize: vertical; line-height: 1.6;
}

/* select 화살표는 구조다. 별도 라운드 컨트롤을 만들지 않는다. */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .admin-wrap) select:not([multiple]):not([size]) {
  padding-inline-end: 22px;
  cursor: pointer;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 10px) 50%, calc(100% - 5px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* checkbox / radio — 제품색 accent 만, glow 없음 */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .t2-privacy-surface, .admin-wrap)
  :is(input[type="checkbox"], input[type="radio"]) {
  accent-color: var(--t2-product);
  width: 15px; height: 15px;
  margin: 0;
  flex: 0 0 auto;
}
:where(.t2-editor-container, .admin-wrap) input[type="range"] { accent-color: var(--t2-product); }

/* 라벨 · 힌트 */
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) .form-label {
  font-size: 12px; font-weight: 500; color: var(--t2-ink-muted);
}
:where(.admin-wrap, .t2-modal-overlay) :is(.form-hint, .empty-hint) {
  font-size: 11.5px; color: var(--t2-ink-faint); line-height: 1.6;
}
:where(.admin-wrap, .t2-modal-overlay) .form-group { display: grid; gap: var(--t2-s1); margin-bottom: var(--t2-s4); }
:where(.admin-wrap) .form-row { display: grid; gap: var(--t2-s4); }
@media (min-width: 720px) { :where(.admin-wrap) .form-row { grid-template-columns: 1fr 1fr; } }


/* ═══ 4. 버튼 — 결정적 실행만 rail 을 얻는다 (law 705 §6) ═══════════════ */
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], [data-t2-modal-companion], .t2-plugin-surface-modal,
  .t2-privacy-surface, .t2-nsfw-dialog) button,
:where(.admin-wrap, .auth-screen, .key-screen, .login-screen) :is(.btn, .btn-sm, .btn-icon) {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--t2-s1);
  min-height: 36px;
  padding: var(--t2-s2) var(--t2-s3);
  border: 0;
  border-radius: var(--t2-radius-control);
  background: transparent;
  color: var(--t2-ink-muted);
  font-size: 13px;
  font-weight: 500;
  box-shadow: none;
  cursor: pointer;
  transition: color var(--t2-motion-fast), background-color var(--t2-motion-fast);
}
:where(.t2-editor-container, .t2-modal-overlay, .t2-plugin-modal-overlay,
  [data-t2-plugin-surface], .t2-plugin-surface-modal, .t2-privacy-surface) button:hover:not(:disabled),
:where(.admin-wrap, .auth-screen, .key-screen, .login-screen) .btn:hover:not(:disabled) {
  color: var(--t2-ink);
  background: var(--t2-product-wash);
}
:where(.t2-editor-container, .t2-modal-overlay, [data-t2-plugin-surface]) button:disabled,
:where(.admin-wrap) .btn:disabled {
  color: var(--t2-ink-faint); cursor: not-allowed; background: transparent;
}

/* 주요 실행 — 라벨 밑 하단 rail. 채움·굵은 테두리를 쓰지 않는다. */
:where(.admin-wrap, .auth-screen, .key-screen, .login-screen) :is(.btn-primary, .btn[data-primary="true"]),
:where(.t2-modal-overlay, .t2-plugin-modal-overlay, [data-t2-modal-companion],
  .t2-plugin-surface-modal, [data-t2-plugin-surface])
  :is(.t2-btn-primary, .t2-btn[data-action="insert"], .t2-btn[data-action="upload"],
      .t2-btn[data-action="apply"], .t2-btn[data-action="save"], .t2-btn[data-action="confirm"]) {
  color: var(--t2-product-ink);
  background: transparent;
  border: 0;
  font-weight: 600;
}
:where(.admin-wrap, .auth-screen, .key-screen, .login-screen) :is(.btn-primary, .btn[data-primary="true"])::after,
:where(.t2-modal-overlay, .t2-plugin-modal-overlay, [data-t2-modal-companion],
  .t2-plugin-surface-modal, [data-t2-plugin-surface])
  :is(.t2-btn-primary, .t2-btn[data-action="insert"], .t2-btn[data-action="upload"],
      .t2-btn[data-action="apply"], .t2-btn[data-action="save"], .t2-btn[data-action="confirm"])::after {
  content: "";
  position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); bottom: 0;
  height: var(--t2-rail-w);
  background: var(--t2-product);
}
:where(.admin-wrap) .btn-primary:hover:not(:disabled) { background: var(--t2-product-wash); color: var(--t2-product-ink); }
:where(.admin-wrap) .btn-primary:disabled::after { background: var(--t2-line-strong); }

/* 파괴적 실행 — 의미색 rail. 제품색을 대용하지 않는다 (law 705 §11). */
:where(.admin-wrap, .auth-screen) :is(.btn-danger, .btn[data-danger="true"]),
:where(.t2-modal-overlay, .t2-plugin-modal-overlay, [data-t2-plugin-surface])
  :is(.t2-btn-danger, .t2-btn[data-action="delete"], .t2-btn[data-action="remove"]) {
  color: var(--t2-danger); background: transparent; border: 0; font-weight: 600;
}
:where(.admin-wrap, .auth-screen) :is(.btn-danger, .btn[data-danger="true"])::after,
:where(.t2-modal-overlay, .t2-plugin-modal-overlay, [data-t2-plugin-surface])
  :is(.t2-btn-danger, .t2-btn[data-action="delete"], .t2-btn[data-action="remove"])::after {
  content: "";
  position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); bottom: 0;
  height: var(--t2-rail-w);
  background: var(--t2-danger);
}
:where(.admin-wrap) .btn-danger:hover:not(:disabled) { background: var(--t2-danger-soft); }

/* 보조 · 아이콘 전용 */
:where(.admin-wrap) .btn-outline { border: 0; background: transparent; color: var(--t2-ink-muted); }
:where(.admin-wrap) .btn-icon {
  width: var(--t2-face); height: var(--t2-face); min-height: var(--t2-face); padding: 0;
}
:where(.admin-wrap) .btn-sm { min-height: 30px; padding: var(--t2-s1) var(--t2-s2); font-size: 12.5px; }


/* ═══ 5. 에디터 셸 ══════════════════════════════════════════════════════ */
.t2-editor-container {
  margin: var(--t2-s4) auto;
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-structural);
  background: var(--t2-surface);
  color: var(--t2-ink);
  box-shadow: none;
  overflow: clip;
  min-width: 0;
  max-width: 100%;
}
.t2-editor-container :where(*, *::before, *::after) { min-width: 0; }

/* ═══ toolbar = 하나의 instrument rail (law 704 §16) ═══════════════════════
   배치 모드는 관리자가 고른다. data-t2-toolbar-mode 하나가 모드의 유일한 훅이며
   JS 는 측정이 필요한 값(--t2-toolbar-btn, --t2-toolbar-columns)만 넘긴다.

     comfortable  버튼 크기 고정 · 높이가 늘어난다(줄바꿈).
                  도구를 숨기지도 줄이지도 않으므로 일반 목적 기본값이다.
     compact      높이 고정 · 버튼 크기가 반응한다. 가운데 정렬.
                  세로 여백과 버튼 사이 간격은 고정하고 가로 바깥 여백만 흡수한다.
     rail         한 줄 고정 크기. 툴바가 자기 가로 넘침을 소유한다(해설 706).
     grouped      한 줄 고정 크기. 넘치는 도구는 그룹 버튼으로 접힌다.

   네 모드 모두 공통으로 지키는 것(해설 708 C-1):
   위·아래 여백이 같고, 좌·우 여백이 같고, 버튼 사이 간격은 사다리에서 온다. */
.t2-toolbar {
  --t2-toolbar-btn: var(--t2-hit);
  --t2-toolbar-pad: var(--t2-inset-control);
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--t2-gap-tight);
  padding: var(--t2-toolbar-pad)
           max(var(--t2-toolbar-pad), env(safe-area-inset-left))
           var(--t2-toolbar-pad)
           max(var(--t2-toolbar-pad), env(safe-area-inset-right));
  min-height: calc(var(--t2-hit) + (var(--t2-inset-control) * 2));
  background: var(--t2-workspace);
  border: 0;
  border-bottom: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-structural);
  box-shadow: none;
  overflow-x: auto;
  overflow-y: visible;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.t2-toolbar::-webkit-scrollbar { height: 0; }

/* comfortable — 줄바꿈. 높이만 변하고 버튼과 간격은 변하지 않는다.
   row-gap 은 column-gap 과 같은 값이라 격자가 정사각 리듬을 유지한다. */
.t2-toolbar[data-t2-toolbar-mode="comfortable"] {
  flex-wrap: wrap;
  row-gap: var(--t2-gap-tight);
  overflow-x: hidden;
}

/* compact — 높이 고정, 버튼 크기 반응, 가운데 정렬.
   버튼 크기는 JS 가 측정해 --t2-toolbar-btn 으로 넘긴다. */
.t2-toolbar[data-t2-toolbar-mode="compact"] {
  flex-wrap: nowrap;
  justify-content: center;
  height: calc(var(--t2-hit) + (var(--t2-inset-control) * 2));
  min-height: calc(var(--t2-hit) + (var(--t2-inset-control) * 2));
  overflow-x: hidden;
}
.t2-toolbar[data-t2-toolbar-mode="compact"] :is(.t2-btn, .t2-toolbar-group-btn) {
  width: var(--t2-toolbar-btn);
  min-width: var(--t2-toolbar-btn);
  height: var(--t2-toolbar-btn);
  min-height: var(--t2-toolbar-btn);
}

/* rail — 한 줄. 넘침은 툴바가 소유하고 문서 루트로 새지 않는다(해설 706). */
.t2-toolbar[data-t2-toolbar-mode="rail"] {
  flex-wrap: nowrap;
  overflow-x: auto;
  scroll-snap-type: x proximity;
}
.t2-toolbar[data-t2-toolbar-mode="rail"] .t2-toolbar-group { scroll-snap-align: start; }

/* grouped — 한 줄. 넘치는 도구는 JS 가 그룹 버튼으로 접는다. */
.t2-toolbar[data-t2-toolbar-mode="grouped"] {
  flex-wrap: nowrap;
  overflow-x: hidden;
}

/* 서브툴바 — 그룹 버튼이 여는 임시 레이어. 예전에는 toolbar.js 가 레이어 밖
   <style> 로 주입했다. 소유권을 여기로 옮긴다. */
.t2-subtoolbar-container {
  position: relative; width: 100%;
  overflow: hidden;
  max-height: 0; opacity: 0;
  background: var(--t2-workspace);
  border-bottom: 1px solid var(--t2-line);
  transition: max-height var(--t2-motion), opacity var(--t2-motion-fast);
}
.t2-subtoolbar-container.active {
  max-height: calc(var(--t2-hit) + (var(--t2-inset-control) * 2));
  opacity: 1;
}
.t2-subtoolbar {
  display: flex; align-items: center;
  gap: var(--t2-gap-tight);
  padding: var(--t2-inset-control) calc(var(--t2-hit) + var(--t2-inset-control))
           var(--t2-inset-control) var(--t2-inset-control);
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.t2-subtoolbar::-webkit-scrollbar { display: none; }
.t2-subtoolbar .t2-btn { flex-shrink: 0; }
.t2-subtoolbar-close {
  position: absolute; top: 50%; right: var(--t2-inset-control);
  transform: translateY(-50%);
  width: var(--t2-face); height: var(--t2-face);
  display: flex; align-items: center; justify-content: center;
  border: 0; background: transparent;
  color: var(--t2-ink-muted);
  border-radius: var(--t2-radius-control);
  cursor: pointer; z-index: 10;
}
.t2-subtoolbar-close:hover { color: var(--t2-ink); background: var(--t2-tool-tile-hover); }
.t2-subtoolbar-close .material-icons { font-size: 18px; }

/* 기능군은 spacing 과 divider 로 읽힌다. 타일 사이는 사다리 최소값(4px)으로
   벌려 인접 타일이 서로 붙어 한 덩어리로 읽히지 않게 한다. */
.t2-toolbar .t2-toolbar-group { display: flex; align-items: center; gap: var(--t2-gap-tight); flex: 0 0 auto; }
.t2-toolbar .t2-toolbar-divider,
.t2-toolbar .t2-divider {
  flex: 0 0 auto; width: 1px; height: 18px;
  background: var(--t2-line);
  margin-inline: var(--t2-s2);
  border: 0;
}

/* 도구는 44px 정사각 타일이다. 시각면과 접근성 44px 터치 타깃을 하나로 합쳐,
   예전처럼 ::before 로 히트 영역을 시각면 밖으로 늘리지 않는다. 휴식 상태에서도
   중성 그레이 면(--t2-tool-tile)을 깔아 "만질 수 있는 타일"로 읽히게 한다.
   면 명도는 재료일 뿐 상태 단서가 아니다 — 활성 여부는 아래 하단 rail 이 알린다. */
.t2-toolbar .t2-btn,
.t2-toolbar .t2-toolbar-group-btn {
  position: relative;
  width: var(--t2-hit);
  min-width: var(--t2-hit);
  height: var(--t2-hit);
  min-height: var(--t2-hit);
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--t2-ink-muted);
  background: var(--t2-tool-tile);
  border: 0;
  border-radius: var(--t2-radius-tile);
  box-shadow: none;
  flex: 0 0 auto;
  transition: color var(--t2-motion-fast), background-color var(--t2-motion-fast);
}
.t2-toolbar .t2-btn:hover:not(:disabled),
.t2-toolbar .t2-toolbar-group-btn:hover:not(:disabled) {
  color: var(--t2-ink);
  background: var(--t2-tool-tile-hover);
}
/* active — 주 단서 하단 rail, 보조 단서 ink·weight. 타일 명도는 한 단계 또렷해질
   뿐 채움색으로 활성을 대신하지 않는다. */
.t2-toolbar .t2-btn.active,
.t2-toolbar .t2-toolbar-group-btn.active,
.t2-toolbar .t2-btn[aria-pressed="true"] {
  color: var(--t2-product-ink);
  background: var(--t2-tool-tile-active);
  font-weight: 600;
}
.t2-toolbar .t2-btn.active::after,
.t2-toolbar .t2-toolbar-group-btn.active::after,
.t2-toolbar .t2-btn[aria-pressed="true"]::after {
  content: "";
  position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); bottom: 0;
  height: var(--t2-rail-w);
  background: var(--t2-product);
  /* rail 은 가운데에서 양끝으로 살짝 넘어갔다 돌아오며 펴진다. */
  animation: t2-rail-in var(--t2-motion-spring) both;
}
@keyframes t2-rail-in { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* 그룹으로 접힌 버튼은 자리를 차지하지 않는다. 위 .t2-toolbar .t2-btn 규칙이
   display 를 선언하므로, 같은 레이어에서 그보다 뒤에 오면서 더 구체적이어야
   이긴다. 예전 런타임 CSS 는 !important 로 이겼고, 그 파일을 걷어내면서 잠시
   숨김이 풀려 접힌 버튼이 그대로 폭을 먹고 툴바가 넘쳤다. */
.t2-toolbar .t2-btn.t2-hidden,
.t2-subtoolbar .t2-btn.t2-hidden { display: none; }

/* ── 성격 부여 ────────────────────────────────────────────────────────
   형상은 sharp 그대로 두고 거동만 바꾼다. 도구는 눌리면 살짝 움츠러들고,
   가리키면 아이콘이 1px 올라온다. 색·radius·테두리는 전혀 건드리지 않으므로
   법의 형상 규칙과 충돌하지 않는다. */
.t2-toolbar .t2-btn :is(svg, .material-icons, .material-icons-outlined),
.t2-toolbar .t2-toolbar-group-btn :is(svg, .material-icons, .material-icons-outlined) {
  transition: transform var(--t2-motion-spring);
}
.t2-toolbar .t2-btn:hover:not(:disabled) :is(svg, .material-icons, .material-icons-outlined),
.t2-toolbar .t2-toolbar-group-btn:hover:not(:disabled) :is(svg, .material-icons, .material-icons-outlined) {
  transform: translateY(-1px);
}
.t2-toolbar .t2-btn { transition: color var(--t2-motion-fast), background-color var(--t2-motion-fast),
                                  transform var(--t2-motion-spring); }
.t2-toolbar .t2-btn:active:not(:disabled),
.t2-toolbar .t2-toolbar-group-btn:active:not(:disabled) { transform: scale(.92); opacity: 1; }

/* 콘텐츠 블록 코너 tick 도 같은 거동으로 등장한다 */
.t2-editor .t2-content-block[data-t2-selected="true"]::before,
.t2-editor .t2-content-block[data-t2-selected="true"]::after {
  animation: t2-tick-in var(--t2-motion-spring) both;
}
@keyframes t2-tick-in { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: scale(1); } }

/* 비활성 도구는 타일 면을 걷어 눌리지 않는 자리로 읽히게 한다. */
.t2-toolbar .t2-btn:disabled { opacity: 1; color: var(--t2-ink-faint); background: transparent; }
/* 플러그인 준비 상태 — disabled 처럼 보이지 않게 약하게만 (기존 계약 유지) */
.t2-toolbar .t2-btn[data-plugin-state="pending"]:not(:disabled),
.t2-toolbar .t2-btn[data-plugin-state="loading"]:not(:disabled) { opacity: .55; }
.t2-toolbar .t2-btn[data-plugin-state="loading"]:not(:disabled) { cursor: progress; }
.t2-toolbar .t2-btn[data-plugin-state="failed"]:not(:disabled) { color: var(--t2-danger); }

.t2-btn-loading-overlay { background: transparent; }
.t2-btn-loading-spinner {
  width: 14px; height: 14px;
  border: 1px solid var(--t2-line-strong);
  border-top-color: var(--t2-product);
  border-radius: 50%;
}

/* subtoolbar — 컨테이너·레이아웃은 위 §toolbar 블록이 소유한다.
   여기는 그 안의 도구 외형만 정한다. */
.t2-subtoolbar .t2-btn {
  position: relative;
  width: auto; min-width: 0; height: 34px; min-height: 34px;
  padding: 0 var(--t2-s3);
  border: 0; border-radius: var(--t2-radius-tile);
  background: var(--t2-tool-tile); color: var(--t2-ink-muted); font-size: 12.5px;
  transition: color var(--t2-motion-fast), background-color var(--t2-motion-fast);
}
.t2-subtoolbar .t2-btn:hover:not(:disabled) { color: var(--t2-ink); background: var(--t2-tool-tile-hover); }
.t2-subtoolbar .t2-btn.active { color: var(--t2-product-ink); font-weight: 600; background: var(--t2-tool-tile-active); }
.t2-subtoolbar .t2-btn.active::after {
  content: ""; position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); bottom: -2px;
  height: var(--t2-rail-w); background: var(--t2-product);
}

/* canvas — 인셋 20px. 자식 블록은 14px 로 한 단계 작다. */
.t2-editor {
  padding: var(--t2-s5);
  background: var(--t2-surface);
  color: var(--t2-ink);
  border-radius: var(--t2-radius-structural);
  border: 0;
  outline: none;
  font-size: 16px;
  line-height: 1.7;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--t2-line-strong) transparent;
}
.t2-editor ::selection { background: var(--t2-product-select); text-shadow: none; }
.t2-editor > p[data-t2-boundary] { min-height: 1.5em; cursor: text; }

/* ═══ 5b. 하단 상태 바 — T2Editor 고유 감성 ═══════════════════════════
   ⚠ 실제 클래스는 .t2-editor-status 다 (.t2-editor-statusbar 아님).
   이 셸은 원본의 얼굴이다. 로고 lockup · 자동 저장 토글 · 글자 수 ·
   테마/번역 스위치를 원형 유틸리티로 유지한다. */
.t2-editor-status {
  display: flex;
  align-items: center;
  gap: var(--t2-s3);
  padding: var(--t2-s2) var(--t2-s3);
  min-height: 46px;
  border-top: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-structural);
  background: var(--t2-workspace);
  font-family: var(--t2-font-ui);
  font-size: 13px;
  color: var(--t2-ink-muted);
}
.t2-status-left { display: flex; align-items: center; gap: var(--t2-s2); min-width: 0; }

/* ── 로고 lockup — 고정 브랜드 자산 ──────────────────────────────────
   ⚠ 이것은 일반 표면이 아니다. radius·색·구조를 표면 토큰으로 정규화하지
     않는다. 이 개정의 초안이 radius 일괄 치환에 이 요소를 휩쓸어 넣어 일체감을
     깨뜨렸다.

   정의: 실선 테두리를 두른 조금 둥근 직사각형 하나. 그 안에서
     T2      #ff6600 면에 흰 글자. 두 값 모두 테마와 무관하게 고정이다.
     Editor  면은 투명이고 글자만 테마를 따른다 — 라이트에서 진회색~검정,
             다크에서 밝은 회색~흰색.
   테두리와 radius 는 lockup 전체에만 걸고 각 칸에 걸지 않는다. 칸에 걸면
   두 조각으로 읽힌다. 두 칸의 경계는 색이 바뀌는 것으로 충분하다.

   비율이 불변이고 글꼴이 거기에 맞춘다. 반대가 아니다. 높이 H 하나로 다섯 개가
   전부 결정된다.
     ① lockup   세로 5 : 가로 12                     -> 폭 = H / 5 * 12
     ② 두 칸    T2 : Editor = 1 : 2.25               -> 칸폭 = 안쪽폭 / 3.25, * 2.25
     ③ 상하 여백 글자 위아래 여백 = H / 4.5           -> 글꼴 크기가 여기서 나온다
     ④ 좌우 여백 = 상하 여백 / 1.75
     ⑤ 그 좌우 여백이 두 칸에서 같은 크기
   ③ 이 글꼴 크기를 정한다. 안쪽 높이에서 위아래 여백을 빼면 남는 것이 글자 크기다.

       F = H - 2 x (H / 26) - 2 x (H / 4.5) = H x .478632

   그러면 ④⑤ 는 글자 폭까지 못박는다. 가운데 정렬에서 좌우 여백은
   (칸폭 - 글자폭) / 2 이므로, 여백이 정해졌다는 것은 글자 폭이 정해졌다는 뜻이다.

       그려야 할 T2 폭     = 칸폭 - 2 x 여백 = H x .460825
       그려야 할 Editor 폭 = 칸폭 - 2 x 여백 = H x 1.354316

   이 글꼴·굵기가 F 로 그리는 자연 폭은 T2 가 H x .566747, Editor 가 H x 1.358359 다.
   Editor 는 맞지만 T2 는 23% 넓다 — 두 글자짜리 낱말에 칸의 1/3.25 밖에 없으니
   당연하다. 여기서 비율을 물릴 수는 없으므로 글꼴이 칸에 맞춘다. 아래 fit 계수는
   그 맞춤량이고, 자연 폭 나누기 그려야 할 폭이다. 글꼴이나 굵기를 바꾸면 자연 폭이
   달라지므로 계수를 다시 풀어야 하며, ①~⑤ 쪽을 손대서는 안 된다.
   letter-spacing 으로 줄이는 길은 막혀 있다 — 필요한 양(-.10em)에서 T 가로획이
   2 위로 올라탄다. 자간이 아니라 자폭을 줄여야 한다.

   테두리를 border 가 아니라 inset box-shadow 로 그리고 그 자리를 padding 으로
   비워 두는 이유: Chromium 은 border-width 를 정수 px 로 내림한다. 높이에 비례하는
   테두리(H/26, 기준 크기에서 1px)를 border 로 주면 40px 에서 1.54px 가 1px 로
   깎여 안쪽 상자가 비례에서 벗어나고, 그 순간 ⑤ 가 0.8px 어긋난다. padding 과
   box-shadow 는 소수를 그대로 쓰므로 어떤 높이에서도 도형이 닮은꼴로 유지된다.

   칸에 padding 을 주지 않는 이유는 또 다르다 — 여백은 칸폭과 가운데 정렬이 만들고,
   padding 을 더하면 여백이 두 번 들어가 좌우가 다시 어긋난다.

   글꼴은 끝이 곧게 뻗은 그로테스크 산세리프로 고정한다. 주변 문맥의 본문 글꼴이
   세리프면 로고까지 세리프로 그려지기 때문에 상속에 맡기지 않는다.
   크기를 바꿔야 하면 --t2-logo-height 하나만 바꾼다 — 폭·여백·글자 크기가 함께
   따라온다. */
.t2-logo {
  --t2-logo-height: 26px;
  --t2-logo-line: calc(var(--t2-logo-height) / 26);
  --t2-logo-text: calc(var(--t2-logo-height) * .478632);
  --t2-logo-fit-prefix: .81311;
  --t2-logo-fit-suffix: .99702;
  display: inline-flex;
  align-items: stretch;
  /* 테두리는 비율 안쪽에 들어간다. content-box 로 두면 테두리가 밖으로 붙어
     실제로 그려지는 상자가 12:5 가 아니게 된다. */
  box-sizing: border-box;
  height: var(--t2-logo-height);
  width: calc(var(--t2-logo-height) / 5 * 12);
  aspect-ratio: 12 / 5;
  padding: var(--t2-logo-line);
  box-shadow: inset 0 0 0 var(--t2-logo-line) var(--t2-line);
  border-radius: var(--t2-radius-brand);
  /* T2 면은 칸이 아니라 lockup 이 깐다. 칸에 깔면 글꼴을 칸에 맞추는 scaleX 가
     면까지 같이 줄여 ② 가 무너진다. content-box 기준이라 100% / 3.25 는 T2 칸폭과
     정확히 같다. */
  background: linear-gradient(90deg, #ff6600 0 calc(100% / 3.25), transparent 0);
  background-origin: content-box;
  background-clip: content-box;
  overflow: hidden;
  text-decoration: none;
  flex: 0 0 auto;
  font-family: "IBM Plex Sans", "Helvetica Neue", Arial, "Noto Sans KR", system-ui, sans-serif;
  line-height: 1;
  white-space: nowrap;
  transition: transform var(--t2-motion-spring), box-shadow var(--t2-motion-fast);
}
.t2-logo-prefix,
.t2-logo-suffix {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  min-width: 0;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  font-size: var(--t2-logo-text);
}
.t2-logo-prefix {
  flex: 0 0 calc(100% / 3.25);
  color: #fff;
  font-weight: 700;
  letter-spacing: normal;
  transform: scaleX(var(--t2-logo-fit-prefix));
}
.t2-logo-suffix {
  flex: 0 0 calc(100% * 2.25 / 3.25);
  color: var(--t2-ink);
  font-weight: 700;
  letter-spacing: normal;
  transform: scaleX(var(--t2-logo-fit-suffix));
}
.t2-logo { gap: 0; }
a:hover > .t2-logo, .t2-logo:hover {
  box-shadow: inset 0 0 0 var(--t2-logo-line) var(--t2-line-strong);
  transform: translateY(-1px);
}

/* 자동 저장 토글 — 진짜 원형 컨트롤 예외. 썸에 스프링 거동을 준다. */
.t2-autosave-toggle {
  display: flex; align-items: center; gap: var(--t2-s2);
  margin-left: 0;
  min-height: var(--t2-orb);
  height: auto;
  cursor: pointer;
  -webkit-user-select: none; user-select: none;
}
.t2-switch { position: relative; display: inline-block; width: 38px; height: 22px; flex: 0 0 auto; }
.t2-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.t2-slider {
  position: absolute; inset: 0;
  background: var(--t2-line-strong);
  border-radius: 999px;
  box-shadow: none;
  cursor: pointer;
  transition: background-color var(--t2-motion);
}
.t2-slider::before {
  content: ""; position: absolute;
  width: 18px; height: 18px; left: 2px; bottom: 2px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(16,20,26,.28);
  transition: transform var(--t2-motion-spring);
}
.t2-autosave-toggle input:checked + .t2-slider { background: var(--t2-product); }
.t2-autosave-toggle input:checked + .t2-slider::before { transform: translateX(16px); }
.t2-autosave-toggle input:focus-visible + .t2-slider {
  outline: 1px solid var(--t2-product); outline-offset: 2px;
}
.t2-autosave-text { font-size: 12.5px; color: var(--t2-ink-muted); line-height: 1.4; cursor: pointer; }

/* 글자 수 — 수치는 mono, tabular. 값이 바뀌어도 폭이 흔들리지 않는다. */
.t2-char-count {
  font-family: var(--t2-font-mono);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--t2-ink-faint);
  letter-spacing: 0;
}
.t2-char-count-value { color: var(--t2-ink-muted); font-weight: 500; }

/* 환경 스위치 묶음 */
.t2-dark-mode-toggle { display: flex; align-items: center; gap: var(--t2-s1); margin-left: auto; padding-left: 0; }
.t2-translate-toggle { position: relative; display: flex; align-items: center; padding-left: 0; }

/* 원형 유틸리티 — 문서 도구가 아니라 환경 스위치다. 형상으로 역할을 가른다.
   원형은 이 용도에만 허용한다 (law 704 §3 의 기능적 예외). */
.t2-editor-status .t2-dark-mode-btn,
.t2-editor-status .t2-translate-btn,
.t2-editor-status .t2-toolbar-toggle-btn {
  position: relative;
  width: var(--t2-orb); height: var(--t2-orb);
  min-height: var(--t2-orb); min-width: var(--t2-orb);
  padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--t2-line);
  border-radius: 50%;
  background: var(--t2-surface);
  color: var(--t2-product-ink);
  box-shadow: none;
  flex: 0 0 auto;
  transition: color var(--t2-motion-fast), border-color var(--t2-motion-fast),
              background-color var(--t2-motion-fast), transform var(--t2-motion-spring);
}
/* 44px 터치 타깃은 원형 밖으로 확장한다 */
.t2-editor-status .t2-dark-mode-btn::before,
.t2-editor-status .t2-translate-btn::before,
.t2-editor-status .t2-toolbar-toggle-btn::before {
  content: ""; position: absolute;
  inset: calc((var(--t2-orb) - var(--t2-hit)) / 2);
}
.t2-editor-status .t2-dark-mode-btn:hover,
.t2-editor-status .t2-translate-btn:hover,
.t2-editor-status .t2-toolbar-toggle-btn:hover {
  border-color: var(--t2-product);
  background: var(--t2-product-wash);
  transform: translateY(-1px);
}
.t2-editor-status .t2-dark-mode-btn:active,
.t2-editor-status .t2-translate-btn:active,
.t2-editor-status .t2-toolbar-toggle-btn:active { transform: translateY(0) scale(.94); opacity: 1; }
.t2-editor-status .t2-translate-btn.t2-active {
  border-color: var(--t2-product);
  background: var(--t2-product-wash);
  color: var(--t2-product-ink);
}
.t2-editor-status :is(.t2-dark-mode-btn, .t2-translate-btn, .t2-toolbar-toggle-btn) .material-icons,
.t2-editor-status :is(.t2-dark-mode-btn, .t2-translate-btn, .t2-toolbar-toggle-btn) .material-icons-outlined {
  font-size: 17px;
}
.t2-toolbar-toggle-btn .material-icons { transition: transform var(--t2-motion-spring); }

/* 번역 메뉴 */
.t2-translate-menu {
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-overlay);
  box-shadow: var(--t2-shadow-overlay);
  padding: var(--t2-s1) 0;
  min-width: 168px;
}
.t2-translate-menu-title {
  padding: var(--t2-s2) var(--t2-s3) var(--t2-s1);
  border-bottom: 1px solid var(--t2-line);
  font-family: var(--t2-font-mono);
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--t2-track-label); text-transform: uppercase;
  color: var(--t2-ink-faint);
}
.t2-translate-menu-list { margin: 0; padding: var(--t2-s1) 0 0; list-style: none; }
.t2-translate-menu-item { position: relative; }
.t2-translate-menu-item.t2-active {
  color: var(--t2-product-ink); font-weight: 600; background: transparent;
}
.t2-translate-menu-item.t2-active::after {
  content: ""; position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); bottom: 0;
  height: var(--t2-rail-w); background: var(--t2-product);
}

/* 버전 · 메타 링크 — 하단 바 아래의 부차 정보.
   예전에는 position:absolute 로 셸 밖에 떠 있었다. 컨테이너에 position 이 없어
   컨테이닝 블록이 페이지였고, 그래서 자기 자리를 예약하지 않은 채 에디터
   아래 콘텐츠 위에 얹혀 있었다(해설 708 F-2). 흐름으로 되돌리고, 하단 바와의
   분리는 형제 간격으로 명시한다(708 D). */
.t2-editor-meta-links {
  display: flex; align-items: center; justify-content: flex-end;
  gap: var(--t2-gap-related);
  padding: var(--t2-gap-related) var(--t2-inset-section);
  font-family: var(--t2-font-mono);
  font-size: 11px;
  color: var(--t2-ink-faint);
}
.t2-version-info { display: inline-flex; align-items: center; gap: var(--t2-s1); cursor: pointer; }
.t2-version-info:hover { color: var(--t2-product-ink); }
.t2-version-info .material-icons-outlined { font-size: 14px; }
.t2-admin-link { color: var(--t2-ink-faint); text-decoration: none; }
.t2-admin-link:hover { color: var(--t2-product-ink); }

/* 리사이즈 핸들 — 기능적 signature */
.t2-resize-handle {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--t2-line);
  height: 12px;
  cursor: ns-resize;
  display: grid;
  place-items: center;
}
.t2-resize-handle::after {
  content: ""; width: 28px; height: 2px;
  background: var(--t2-line-strong);
}
.t2-resize-handle:hover::after { background: var(--t2-product); }


/* ═══ 6. 콘텐츠 블록 · 미디어 조작 ══════════════════════════════════════
   선택 상태의 주 단서는 1px 제품색 hairline + tone. 보조는 코너 tick. */
.t2-editor .t2-content-block { position: relative; margin-block: var(--t2-s4); }

/* ── 밖 배치 자리 예약 ────────────────────────────────────────────────────
   슬롯 배치가 'outside' 면 컨트롤 섬은 블록 경계 밖 --t2-block-slot-offset 지점에
   섬 높이만큼 떠 있다. 그 자리를 블록 여백으로 확보하지 않으면 섬이 이웃
   문단 글자와 옆 블록의 섬 위에 겹친다(기본 margin 16px < 필요 46px).

   배치를 inside 로 바꿔 회피하지 않는다. inside 는 콘텐츠 픽셀을 덮으므로
   발행 결과 예견 가능성을 해치고, 그건 블록에 배경을 칠하는 것과 같은 손실이다.

   섬 높이는 아래 __group 규칙(min-height + padding + border)이 정하므로 여기가
   그 값의 소유자다. 예약 규칙도 같은 레이어에 둔다 — 모듈 레이어에 두면
   레이어 순서상 이 파일의 margin-block 에 무조건 진다.

   data-t2-content-block-outside 는 모듈이 실제 슬롯 배치를 보고 부여한다.
   :has() 에 의존하지 않고, 밖 슬롯이 없는 블록은 여백이 늘지 않는다. */
.t2-editor {
  --t2-block-island-h: 36px;  /* __group: min-height 30 + padding 2×2 + border 1×2 */
  --t2-block-island-reserve: calc(var(--t2-block-slot-offset, 6px) + var(--t2-block-island-h) + var(--t2-s1));
}
.t2-editor .t2-content-block[data-t2-content-block-outside~="top"] {
  margin-top: var(--t2-block-island-reserve);
}
.t2-editor .t2-content-block[data-t2-content-block-outside~="bottom"] {
  margin-bottom: var(--t2-block-island-reserve);
}
/* 블록이 맞붙으면 두 섬이 같은 띠를 나눠 쓰게 되어 서로 겹친다. 인접 형제
   margin 은 상쇄되므로 그때만 두 배로 벌려 두 섬이 각자의 띠를 갖게 한다. */
.t2-editor .t2-content-block[data-t2-content-block-outside~="bottom"]
  + .t2-content-block[data-t2-content-block-outside~="top"] {
  margin-top: calc(2 * var(--t2-block-island-reserve));
}

/* ── 콘텐츠 블록은 콘텐츠다 ────────────────────────────────────────────
   ⚠ 배경색을 넣지 않는다. 블록에 면을 칠하면 사용자가 최종 발행 결과를
     예견할 수 없다. 편집 화면과 발행 결과가 달라지는 순간 WYSIWYG 계약이
     깨지고, 그건 미학 문제가 아니라 UX 손실이다.
   초판이 --outlined 에 workspace 면을, 선택 상태에 product-wash 면을
   넣었다. 둘 다 제거했다.

   선택·포커스 표시는 콘텐츠 픽셀을 건드리지 않는 수단만 쓴다:
     outline      박스 밖에 그려지고 레이아웃에 영향이 없다
     코너 tick    블록 경계 밖 모서리
   테두리 두께나 배경으로 상태를 말하지 않는다. */
.t2-editor .t2-content-block,
.t2-editor .t2-content-block.t2-content-block--outlined {
  background: transparent;
}
.t2-editor .t2-content-block.t2-content-block--outlined {
  padding: 0;
  border: 0;
  border-radius: 0;
}
.t2-editor .t2-content-block:focus-within,
.t2-editor .t2-content-block[data-t2-selected="true"] {
  background: transparent;
  border-color: transparent;
  outline: 1px solid var(--t2-product);
  outline-offset: 2px;
}
.t2-editor .t2-content-block[data-t2-selected="true"]::before,
.t2-editor .t2-content-block[data-t2-selected="true"]::after {
  content: ""; position: absolute;
  width: var(--t2-tick); height: var(--t2-tick);
  border-color: var(--t2-product); border-style: solid; pointer-events: none;
  animation: t2-tick-in var(--t2-motion-spring) both;
}
.t2-editor .t2-content-block[data-t2-selected="true"]::before { top: -3px; left: -3px; border-width: 2px 0 0 2px; }
.t2-editor .t2-content-block[data-t2-selected="true"]::after { bottom: -3px; right: -3px; border-width: 0 2px 2px 0; }

/* --bare / --outlined 는 둘 다 면을 갖지 않는다. 위 규칙이 --outlined 를
   0 으로 되돌리므로 --bare 는 같은 값을 명시만 한다 (모듈 레이어에 남아 있던
   중복 선언을 여기로 합쳤다). */
.t2-editor .t2-content-block.t2-content-block--bare { padding: 0; border: 0; background: transparent; }

/* ── 컨테이너 표시 계약 ───────────────────────────────────────────────────
   플러그인이 자기 블록 경계를 보일지 선언하고, 관리자의 "컨테이너 항상 표시"가
   그것을 덮는다. 모듈이 결과를 data-t2-content-block-container 하나로 정규화하므로
   CSS 는 선언 출처를 몰라도 된다.
   경계는 1px hairline 하나뿐이다 — 면을 칠하면 편집 화면과 발행 결과가 달라진다. */
.t2-editor .t2-content-block[data-t2-content-block-container="visible"] {
  padding: var(--t2-inset-control);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-edge);
  background: transparent;
}
.t2-editor .t2-content-block[data-t2-content-block-container="hidden"] {
  padding: 0;
  border: 0;
  background: transparent;
}

/* 기능 그룹 = 유일하게 면을 갖는 요소. 인셋 리듬: 캔버스 > 블록 > 그룹 > 컨트롤
   순으로 한 단계씩 작아진다. 그룹은 사다리의 최하단이므로 --t2-s1 의 절반인
   2px 을 쓴다. 이 값의 소유자는 이 규칙 하나다. */
.t2-editor .t2-content-block__group {
  display: inline-flex; align-items: center; gap: 2px;
  min-height: 30px;
  padding: 2px;
  color: var(--t2-ink-muted);
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-control);
  box-shadow: var(--t2-shadow-overlay);
}
/* 파괴적 그룹 — 의미색 ink + 의미색 hairline. 면은 칠하지 않는다 (law 707 D:
   보조 단서는 ink 승격 + weight 하나까지). */
.t2-editor .t2-content-block__group[data-t2-content-block-group="destructive"] {
  color: var(--t2-danger);
  border-color: color-mix(in srgb, var(--t2-danger) 34%, var(--t2-line));
}
.t2-editor .t2-content-block__group-label {
  padding-inline: var(--t2-s1) 2px;
  font-family: var(--t2-font-mono);
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--t2-track-label);
  text-transform: uppercase;
  color: var(--t2-ink-faint);
  white-space: nowrap;
}
.t2-editor .t2-content-block__control--button {
  position: relative;
  width: 26px; height: 26px; padding: 0;
  border: 0; background: transparent;
  color: inherit;
  border-radius: var(--t2-radius-control);
}
/* 시각면 26px, 히트 영역 44px. 부모 높이를 늘리지 않는다 (law 704 §5). */
.t2-editor .t2-content-block__control--button::before { content: ""; position: absolute; inset: -9px; }
.t2-editor .t2-content-block__control--button:hover { color: var(--t2-product-ink); background: var(--t2-product-wash); }
.t2-editor .t2-content-block__group[data-t2-content-block-group="destructive"] .t2-content-block__control--button:hover {
  color: var(--t2-danger); background: var(--t2-danger-soft);
}
.t2-editor .t2-content-block__control--button:active { background: var(--t2-product-tone); }
.t2-editor .t2-content-block__control--button:focus-visible { outline: 1px solid var(--t2-product); outline-offset: 1px; }
.t2-editor .t2-content-block__control--button .material-icons { font-size: 18px; }
@media (hover: none), (pointer: coarse), (max-width: 640px) {
  /* [iOS⚠️] Keep touch controls at or above the 44×44px target size.
     coarse 포인터에서는 히트 영역 확장 대신 시각면 자체를 키운다.
     섬이 커지면 밖 배치 예약도 같이 커져야 한다. */
  .t2-editor { --t2-block-island-h: 54px; }
  .t2-editor .t2-content-block__group { min-height: 48px; }
  .t2-editor .t2-content-block__control--button { width: 44px; height: 44px; }
  .t2-editor .t2-content-block__control--button::before { inset: 0; }
  .t2-editor .t2-content-block__control--button .material-icons { font-size: 20px; }
}

/* ⚠ 슬롯은 레일이다 — 절대 칠하지 않는다.
   t2-media-controls / t2-move-controls / t2-block-controls / t2-table-controls 는
   두 가지 역할로 쓰인다:
     (구) 레거시 플러그인이 직접 만든 "컨트롤 섬" 컨테이너      → 칠한다
     (신) content-block 모듈이 슬롯 요소에 부여하는 위치 레일    → 칠하지 않는다
   슬롯을 칠하면 자동 숨김이 깨진다. 숨김은 자식 __group 의 opacity/visibility 로
   동작하므로, 슬롯에 면·테두리·그림자가 있으면 아이콘만 사라지고 배경 상자가
   그대로 남는다. (증상: "삭제·이동 버튼이 숨겨졌는데 배경만 떠 있다")
   그래서 신 역할일 때는 페인트에서 제외하고, 면은 __group 만 갖는다. */
.t2-media-controls:not(.t2-content-block__slot),
.t2-move-controls:not(.t2-content-block__slot),
.t2-block-controls:not(.t2-content-block__slot),
.t2-table-controls:not(.t2-content-block__slot) {
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-control);
  box-shadow: var(--t2-shadow-overlay);
  padding: 2px;
  gap: 2px;
}
/* 신 역할(슬롯)일 때는 레일로 되돌린다. 모듈 레이어가 이미 이렇게 선언하지만
   레이어 순서상 product 가 이기므로 여기서 명시적으로 되돌려야 한다. */
.t2-content-block__slot:is(.t2-media-controls, .t2-move-controls, .t2-block-controls, .t2-table-controls) {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  gap: var(--t2-s1);
}
.t2-media-controls button, .t2-block-controls button, .t2-table-controls button {
  width: 26px; height: 26px; min-height: 26px; padding: 0;
  color: var(--t2-ink-muted);
}


/* color-mix 미지원 브라우저 폴백. 구 모듈 파일이 갖고 있던 것을 외형 소유권을
   product 로 옮길 때 빠뜨렸다. 없으면 파괴적 그룹의 테두리가 기본값으로 돌아간다. */
@supports not (color: color-mix(in srgb, black 50%, white)) {
  .t2-editor .t2-content-block__group[data-t2-content-block-group="destructive"] {
    border-color: rgba(180, 35, 45, .35);
  }
}


/* ═══ 7. 오버레이 · 드롭다운 ════════════════════════════════════════════ */
.t2-font-size-list, .t2-dropdown-layer, .t2-color-picker-container, .t2-translate-menu {
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-overlay);
  box-shadow: var(--t2-shadow-overlay);
  padding: var(--t2-s1) 0;
}
/* 목록형 오버레이는 항목이 폭을 꽉 채우므로 가로 인셋이 0 이어야 한다. 색 선택은
   목록이 아니라 격자여서 같은 규칙을 쓰면 좌우 여백만 사라진 비대칭 상자가 된다
   (해설 708 C-1). 오버레이 인셋 한 단계를 대칭으로 준다. */
.t2-color-picker-container { padding: var(--t2-inset-island); }
/* 색 적용은 이 표면의 유일한 실행이다. §4 의 공통 버튼 규칙이 면과 굵기를
   지워 본문 글자와 구분되지 않았다 (해설 709 A-1·A-5). 주요 실행 문법인
   라벨 밑 하단 rail 로 되돌린다. */
.t2-cp-apply {
  position: relative;
  min-height: var(--t2-hit);
  color: var(--t2-product-ink);
  background: transparent;
  border: 0;
  font-weight: 600;
}
.t2-cp-apply::after {
  content: "";
  position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); bottom: var(--t2-inset-chip);
  height: var(--t2-rail-w);
  background: var(--t2-product);
}
.t2-cp-apply:hover { background: var(--t2-product-wash); }
.t2-font-size-option, .t2-translate-menu-item {
  position: relative;
  padding: 7px var(--t2-s3);
  font-size: 13px;
  color: var(--t2-ink);
  background: transparent;
  cursor: pointer;
}
.t2-font-size-option:hover, .t2-translate-menu-item:hover { background: var(--t2-product-wash); }
.t2-dropdown-layer [role="option"] {
  padding: 7px var(--t2-s3); font-size: 13px; color: var(--t2-ink); background: transparent;
}
.t2-dropdown-layer [role="option"]:hover { background: var(--t2-product-wash); }
.t2-dropdown-layer [role="option"][aria-selected="true"] {
  color: var(--t2-product-ink); font-weight: 600; background: var(--t2-product-wash);
}

/* 알림(toast) — 짧게 머무는 오버레이.
   core.css 는 .t2-notification 에 color:#fff 와 그림자만 주고, 면은
   .t2-notification-<type> 이 칠하도록 되어 있었다. 그 네 규칙이 어느 CSS 에도
   없다. 클래스 이름을 js/utils.js 가 런타임에 조립하므로 소스에 리터럴로
   나타나지 않고, 유령 선택자로 오인되기 쉬운 형태다. 결과는 배경 없는 흰 글자가
   툴바 위에 그대로 겹쳐 뜨는 것이었다 — 다크에서도 라이트에서도 읽을 수 없다.
   여기서 면을 정의한다. 의미는 상단 rail + 아이콘 잉크가 전달하고(law 707),
   면 자체는 중립 재료를 쓴다. 의미색으로 전체를 칠하지 않는다. */
.t2-notification {
  position: relative;
  overflow: hidden;
  color: var(--t2-ink);
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-overlay);
  box-shadow: var(--t2-shadow-overlay);
  font-size: 13px;
}
.t2-notification::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset);
  height: var(--t2-rail-w);
  background: var(--t2-ink-faint);
  border-radius: 0 0 var(--t2-radius-edge) var(--t2-radius-edge);
}
.t2-notification-info::before    { background: var(--t2-info); }
.t2-notification-success::before { background: var(--t2-success); }
.t2-notification-warning::before { background: var(--t2-warning); }
.t2-notification-error::before   { background: var(--t2-danger); }
.t2-notification-close {
  color: var(--t2-ink-muted);
  background: transparent;
  border: 0;
  border-radius: var(--t2-radius-control);
}
.t2-notification-close:hover { color: var(--t2-ink); background: var(--t2-product-wash); }

/* 남은 시간 표시줄 — 의미 rail 과 같은 자리를 쓰지 않도록 위쪽일 때는 rail 아래에
   붙는다. transform 으로만 줄어들어 레이아웃을 건드리지 않는다. */
.t2-notification-progress {
  position: absolute;
  left: 0; right: 0;
  height: var(--t2-rail-w);
  background: transparent;
  pointer-events: none;
}
.t2-notification-progress[data-position="top"] { top: var(--t2-rail-w); }
.t2-notification-progress[data-position="bottom"] { bottom: 0; }
.t2-notification-progress-fill {
  height: 100%;
  transform-origin: left center;
  transform: scaleX(1);
  background: var(--t2-ink-faint);
}
.t2-notification-info .t2-notification-progress-fill    { background: var(--t2-info); }
.t2-notification-success .t2-notification-progress-fill { background: var(--t2-success); }
.t2-notification-warning .t2-notification-progress-fill { background: var(--t2-warning); }
.t2-notification-error .t2-notification-progress-fill   { background: var(--t2-danger); }
@media (prefers-reduced-motion: reduce) {
  /* 남은 시간은 정보이므로 없애지 않는다. 연속 애니메이션만 끊는다. */
  .t2-notification-progress-fill { transition: none !important; }
}


/* ═══ 8. 작업 레이어 (modal) ═════════════════════════════════════════════ */
.t2-modal-overlay, .t2-plugin-modal-overlay {
  background: var(--md-overlay);
}
.t2-modal-surface, .t2-plugin-surface-shell, .t2-plugin-surface-dialog,
.t2-nsfw-dialog, .t2-safeai-legal-modal, .plugin-modal, .tp-modal-box,
.icon-picker-modal, .module-picker-modal, .ai-budget-plugin-modal-box {
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-modal);
  box-shadow: var(--t2-shadow-modal);
}
/* 절삭 모서리는 critical surface 전용이다 — 날카로움이 "위험한 작업"이라는
   의미를 가질 때만 쓴다. clip-path 는 border-radius 렌더를 덮으므로 겹칠 수
   없고 겹칠 이유도 없다. 일반 modal 은 둥근 모서리를 쓴다. */
.t2-nsfw-dialog-blocked,
[data-t2-surface="critical"] {
  border-radius: 0;
  clip-path: polygon(var(--t2-chamfer) 0, 100% 0, 100% 100%, 0 100%, 0 var(--t2-chamfer));
}
/* 모달은 이미 작업 경계다. 안에서 header/body/footer 를 박스로 반복 분리하지 않는다. */
.t2-plugin-surface-header, .t2-modal-header, .t2-nsfw-dialog-header, .t2-safeai-legal-header {
  padding: var(--t2-s4) var(--t2-s4) var(--t2-s2) var(--t2-s5);
  background: transparent;
  border: 0;
  display: flex; align-items: center; gap: var(--t2-s2);
}
.t2-plugin-surface-title, .t2-modal-title, .t2-nsfw-dialog-title, .t2-safeai-legal-title {
  font-size: 14px; font-weight: 600; letter-spacing: var(--t2-track-title); margin: 0;
}
.t2-plugin-surface-body, .t2-modal-body, .plugin-modal-body,
.t2-nsfw-dialog-body, .t2-safeai-legal-body {
  padding: 0 var(--t2-s4) var(--t2-s4);
  background: transparent;
  border: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}
.t2-plugin-surface-footer, .t2-modal-footer, .t2-nsfw-dialog-footer, .t2-safeai-legal-footer {
  display: flex; align-items: center; gap: var(--t2-s1);
  padding: var(--t2-s2) var(--t2-s4) var(--t2-s4);
  background: transparent;
  border: 0;
}
.t2-modal-sheet-handle { background: var(--t2-line-strong); border-radius: 999px; }


/* ═══ 9. 의미 상태 — rail + 아이콘. 배경 채움을 키우지 않는다. ══════════ */
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface], .t2-editor-container)
  :is(.alert, .warning-banner, .up-status-banner) {
  position: relative;
  display: flex; gap: var(--t2-s2);
  padding: 10px var(--t2-s3);
  background: var(--t2-workspace);
  border: 0;
  border-radius: var(--t2-radius-structural);
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--t2-ink);
}
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface], .t2-editor-container)
  :is(.alert, .warning-banner, .up-status-banner)::before {
  content: ""; position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); top: 0;
  height: var(--t2-rail-w);
  background: var(--t2-ink-faint);
}
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) .alert-error::before { background: var(--t2-danger); }
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) .alert-warn::before { background: var(--t2-warning); }
:where(.admin-wrap) .warning-banner::before { background: var(--t2-warning); }
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) .alert-success::before { background: var(--t2-success); }
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) .alert-info::before { background: var(--t2-product); }

/* badge / tag / chip — 채움 pill 이 아니라 hairline + ink */
:where(.admin-wrap, [data-t2-plugin-surface])
  :is(.badge, .tag, .ext-chip, .tp-status-badge, .plugin-manifest-badge, .license-badge, .ai-cap-chip) {
  display: inline-flex; align-items: center; gap: var(--t2-s1);
  padding: 2px var(--t2-s2);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-control);
  background: transparent;
  font-family: var(--t2-font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--t2-ink-muted);
}
:where(.admin-wrap) .badge-primary { color: var(--t2-product-ink); border-color: var(--t2-product); }
:where(.admin-wrap) .badge-success { color: var(--t2-success); border-color: var(--t2-success); }
:where(.admin-wrap) .badge-warn    { color: var(--t2-warning); border-color: var(--t2-warning); }
:where(.admin-wrap) .badge-error   { color: var(--t2-danger);  border-color: var(--t2-danger); }
:where(.admin-wrap) .badge-muted   { color: var(--t2-ink-faint); }

/* 상태 dot — 진짜 원형 예외 */
:where(.admin-wrap) :is(.admin-status-dot, .status-dot) {
  width: 5px; height: 5px; border-radius: 50%; background: var(--t2-success); flex: 0 0 auto;
}


/* ═══ 10. 관리자 셸 ═════════════════════════════════════════════════════ */
.admin-wrap, .main-wrap { background: var(--t2-base); color: var(--t2-ink); }

/* 상단 헤더 = topbar(제목·검색·액션) + 그 아래 위치표시 strip 두 줄이 이루는
   하나의 고정 밴드다. 둘 다 스크롤러(.admin-wrap main) 바깥의 flex 자식이라
   화면 최상단에 붙박여 있다. 분리선은 밴드 맨 아래 하나만 두고, 좌우 인셋은
   본문(.content-area)과 같은 --t2-inset-shell 로 맞춰 세 요소의 왼쪽 모서리가
   한 세로줄에 선다. 예전에는 topbar 만 흰 면+하단 경계였고 좌우 인셋도 s4 로
   달라서, 위치표시 strip 이 회색 바탕 위 다른 들여쓰기로 홀로 떠 보였다. */
.topbar {
  display: flex; align-items: center; gap: var(--t2-s3);
  height: 48px;
  padding: 0 var(--t2-inset-shell);
  background: var(--t2-surface);
  border: 0;
  box-shadow: none;
}
.topbar-title { font-size: 13px; font-weight: 600; letter-spacing: var(--t2-track-title); }
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: var(--t2-s1); }

/* 사이드바 열기 버튼은 사이드바가 오버레이로 접히는 폭에서만 존재한다.
   §4 의 관리자 버튼 블록이 display 를 선언하므로 admin-navigation.css 의
   .topbar-menu-btn{display:none} 은 레이어 순서에서 무조건 진다. 실제로
   데스크톱 관리자 상단에 쓸모없는 햄버거 버튼이 늘 떠 있었다.
   존재 조건도 같은 레이어에서 함께 소유한다. 폭 기준은 admin-navigation.css
   의 사이드바 접힘 기준과 같아야 한다. */
.topbar-menu-btn { display: none; }
@media (max-width: 860px) { .topbar-menu-btn { display: inline-flex; } }

.sidebar {
  background: var(--t2-surface);
  border: 0;
  border-right: 1px solid var(--t2-line);
  box-shadow: none;
  padding-block: var(--t2-s2);
  overflow-y: auto;
  overscroll-behavior-y: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--t2-line-strong) transparent;
}
.sidebar-logo { padding: var(--t2-s3) var(--t2-s4); border: 0; }
.sidebar-footer { padding: var(--t2-s3) var(--t2-s4); border-top: 1px solid var(--t2-line); }
.sidebar-overlay { background: var(--md-overlay); }

/* 내비게이션 — 밀도 유지. 현재 위치는 행 tone + ink·weight, 큰 pill 없음. */
.nav-section { margin-block: var(--t2-s1); }
.nav-section-label, .nav-tech-label {
  display: block;
  padding: var(--t2-s3) var(--t2-s4) var(--t2-s1);
  font-family: var(--t2-font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: var(--t2-track-label);
  text-transform: uppercase;
  color: var(--t2-ink-faint);
}
.nav-item {
  display: flex; align-items: center; gap: var(--t2-s2);
  padding: 8px var(--t2-s4);
  min-height: 36px;
  border: 0;
  border-radius: var(--t2-radius-structural);
  background: transparent;
  color: var(--t2-ink-muted);
  font-size: 13px;
  text-decoration: none;
  transition: color var(--t2-motion-fast), background-color var(--t2-motion-fast);
}
.nav-item:hover { color: var(--t2-ink); background: var(--t2-product-wash); }
/* 관리자 설정 표면에 한해 세로 rail 을 쓴다.
   ⚠ 여기서 배경 tone 을 함께 쓰면 단서가 3개가 된다 (rail + tone + weight).
     rail 을 주 단서로 삼았으므로 tone 을 걷어내고 weight 만 보조로 남긴다.
   ⚠ 같은 요소에 하단 rail 을 겹치지 않는다. */
.nav-item.active, .nav-item[aria-current] {
  position: relative;
  color: var(--t2-product-ink);
  font-weight: 600;
  background: transparent;
}
.nav-item.active::after, .nav-item[aria-current]::after {
  content: ""; position: absolute;
  inset-inline-start: 0;
  top: var(--t2-rail-inset); bottom: var(--t2-rail-inset);
  width: var(--t2-rail-w);
  background: var(--t2-product);
  animation: t2-rail-in-y var(--t2-motion-spring) both;
}
@keyframes t2-rail-in-y { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.nav-item.active:hover, .nav-item[aria-current]:hover { background: var(--t2-product-wash); }
.nav-item :is(.material-icons, .material-icons-outlined, .mi) { font-size: 18px; opacity: .9; }
.nav-item .count {
  margin-left: auto;
  font-family: var(--t2-font-mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--t2-ink-faint);
}
.nav-item.active .count { color: var(--t2-product-ink); }
.nav-purpose-items .nav-item { padding-left: calc(var(--t2-s4) + 26px); font-size: 12.5px; }
.nav-purpose-toggle {
  display: flex; align-items: center; width: 100%;
  padding: 8px var(--t2-s4); min-height: 36px;
  background: transparent; border: 0; color: var(--t2-ink-muted); font-size: 13px;
}
.nav-purpose-chevron { margin-left: auto; color: var(--t2-ink-faint); transition: transform var(--t2-motion-spring); }
[aria-expanded="true"] > .nav-purpose-chevron { transform: rotate(90deg); }

.content-area, .admin-flat-page {
  padding: var(--t2-inset-shell);
  background: var(--t2-base);
}

/* ── 스크롤 소유자와 sticky 스택 — 해설 708 G ───────────────────────────
   관리자 셸은 문서가 아니라 flex 셸이다. 스크롤 소유자는 .admin-wrap main 이고
   .topbar 는 그 바깥에 있다. 그래서 스크롤러 안의 sticky 표면이 헤더 높이를
   오프셋으로 쓰면, 이미 화면에 없는 것을 위해 자리를 비워 둔 채 콘텐츠 한가운데
   떠 있게 된다. 실제로 .plugin-section-nav 와 .ai-purpose-nav 가
   top:calc(--header-h + 6px) 로 그렇게 떠 있었다.
   오프셋의 소유자는 높이를 정하는 쪽 하나뿐이다. 스크롤러가 자기 안쪽 기준을
   선언하고, sticky 표면은 그 이름만 읽는다. */
:where(.admin-wrap) main {
  --t2-sticky-top: 0px;
  scroll-padding-top: var(--t2-sticky-top);
}
:where(.admin-wrap) :is(.plugin-section-nav, .ai-purpose-nav, .module-admin-list-pane) {
  top: var(--t2-sticky-top);
}
/* sticky 표면은 아래를 스쳐 지나가는 콘텐츠를 가린다. 반투명하면 두 층이 겹쳐
   읽히므로 불투명해야 한다 (708 F-1). */
:where(.admin-wrap) :is(.plugin-section-nav, .ai-purpose-nav) {
  background: var(--t2-base);
  border: 0;
  border-bottom: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-structural);
  padding: var(--t2-inset-chip) 0;
  margin-block: 0 var(--t2-gap-group);
  box-shadow: none;
}

/* ── 제목의 소속 — 해설 708 C-3·E ───────────────────────────────────────
   제목 위 간격 > 제목 아래 간격. 그래야 제목이 아래 내용에 속해 보인다.
   section 제목과 subsection 제목은 서로 다른 값을 갖는다 (708 E-2). */
.section-header {
  display: flex; align-items: baseline; gap: var(--t2-gap-related);
  margin: 0 0 var(--t2-trail-title);
  padding: 0;
  background: transparent;
  border: 0;
}
.section-header :is(h2, h3) {
  margin: 0; font-size: 13px; font-weight: 600; letter-spacing: var(--t2-track-title);
}
.section-header p { margin: 0; }
/* 구현 용어는 보조 표기다 — 화면 이름을 대체하지 않는다 (해설 709 D-2).
   사이드바의 .nav-tech-label 과 같은 문법을 쓴다. */
.section-tech-label {
  flex: 0 0 auto;
  padding: 2px var(--t2-inset-control);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-control);
  font-family: var(--t2-font-mono);
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--t2-track-label);
  text-transform: uppercase;
  color: var(--t2-ink-faint);
  white-space: nowrap;
}
:where(.admin-wrap) .section-panel > :is(h3, h4, .subsection-title, .form-section-title) {
  margin: var(--t2-lead-subtitle) 0 var(--t2-trail-subtitle);
}
:where(.admin-wrap) .section-panel > :is(h3, h4, .subsection-title, .form-section-title):first-child {
  margin-top: 0;
}
.admin-flat-section, .section-panel {
  background: transparent;
  border: 0;
  padding: 0;
  margin-bottom: var(--t2-gap-section);
}

/* ── 블록 대칭 — 해설 708 C-2 ───────────────────────────────────────────
   면이나 테두리를 가진 블록에서 첫 자식의 위 여백과 마지막 자식의 아래 여백이
   남으면 위아래가 비대칭이 된다. 테두리 있는 사각 블록의 글자 아래 여백만
   유독 넓어 보이던 원인이 이것이다. 여백은 블록의 padding 이 소유하고,
   자식의 바깥 여백은 경계에서 상쇄한다. */
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface])
  :is(.card, .stat-card, .api-card, .env-feature-card, .module-policy-card,
      .plugin-manager-card, .tp-card, .up-release-card, .bp-card, .group-card,
      .alert, .warning-banner, .up-status-banner, .save-bar, .auth-card, .key-card,
      .admin-flat-section, .t2-modal-surface, .plugin-modal, .tp-modal-box,
      .ai-budget-metric, .ai-budget-mode-card, .ai-cap-tier-card, .ai-purpose-section,
      .tp-empty, .env-guide, .env-status-panel, .pkg-sec-report, .system-extension-card, .up-file)
  > :first-child { margin-block-start: 0; }
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface])
  :is(.card, .stat-card, .api-card, .env-feature-card, .module-policy-card,
      .plugin-manager-card, .tp-card, .up-release-card, .bp-card, .group-card,
      .alert, .warning-banner, .up-status-banner, .save-bar, .auth-card, .key-card,
      .admin-flat-section, .t2-modal-surface, .plugin-modal, .tp-modal-box,
      .ai-budget-metric, .ai-budget-mode-card, .ai-cap-tier-card, .ai-purpose-section,
      .tp-empty, .env-guide, .env-status-panel, .pkg-sec-report, .system-extension-card, .up-file)
  > :last-child { margin-block-end: 0; }
/* 컨테이너를 이름으로 열거하는 것만으로는 새로 생기는 표면을 놓친다. 흐름
   요소 쪽에서도 경계 여백을 상쇄해, 어떤 컨테이너 안에 들어가든 위아래가
   대칭이 되게 한다. 안쪽 여백의 소유자는 컨테이너의 padding 하나다. */
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface])
  :is(p, ul, ol, dl, pre, blockquote, table, h1, h2, h3, h4, h5, h6, .form-group, .alert):first-child {
  margin-block-start: 0;
}
:where(.admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface])
  :is(p, ul, ol, dl, pre, blockquote, table, h1, h2, h3, h4, h5, h6, .form-group, .alert):last-child {
  margin-block-end: 0;
}

/* 사다리 밖 값과 의도 없는 비대칭을 이 레이어에서 되돌린다 (708 A·C-1).
   .env-guide 는 margin-top:11px/padding-top:2px, .ai-purpose-section 은
   padding:14px 0 4px 이었다. 둘 다 관리자 CSS 가 자기 값을 발명한 경우다. */
:where(.admin-wrap) .env-guide { margin-top: var(--t2-gap-related); padding-top: var(--t2-gap-related); }
:where(.admin-wrap) .ai-purpose-section { padding-block: var(--t2-inset-section); }
:where(.admin-wrap) :is(.ai-budget-metric, .ai-cap-tier-card, .tp-empty) { padding: var(--t2-inset-island); }
.card, .stat-card, .api-card, .env-feature-card, .module-policy-card,
.plugin-manager-card, .tp-card, .up-release-card, .bp-card, .group-card,
/* 카드 안에 카드를 기본 구분 수단으로 쓰지 않는다 (law 704 §6) */
.card .card, .stat-card .card, .api-card .card, .tp-card .card {
  background: transparent; border: 0; box-shadow: none; padding: 0;
}
.card-header, .api-card-head, .env-feature-head, .up-release-head, .bp-head, .tp-toolbar {
  display: flex; align-items: center; gap: var(--t2-s2);
  padding: 0 0 var(--t2-s3);
  margin: 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--t2-line);
}
.card-title, .card-title-wrap { font-size: 13px; font-weight: 600; letter-spacing: var(--t2-track-title); margin: 0; }
.card-body, .api-card-main, .bp-body { padding: var(--t2-s3) 0 0; background: transparent; border: 0; }
.divider { height: 1px; background: var(--t2-line); border: 0; margin-block: var(--t2-s4); }

/* stat — 숫자가 주인공. 아이콘 컨테이너를 장식으로 쓰지 않는다. */
/* 통계 격자 — 면을 갖지 않는다. admin CSS 는 "격자를 경계색으로 칠하고 셀은
   surface 로 덮어 2px 틈이 hairline 으로 보이게" 하는 기법을 쓰고 있었다.
   이 파일이 .stat-card 의 배경을 transparent 로 평탄화하면서 덮을 셀이 사라져,
   격자 전체가 --md-border 색 판때기로 남고 그 위에 글자가 얹혔다.
   기법의 나머지 절반도 여기서 함께 걷어낸다. 구분은 간격이 담당한다. */
.stat-grid {
  display: grid; gap: var(--t2-s3);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: var(--t2-radius-structural);
  box-shadow: none;
  overflow: visible;
}
.stat-label {
  font-family: var(--t2-font-mono);
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--t2-track-label); text-transform: uppercase;
  color: var(--t2-ink-faint);
}
.stat-value {
  font-size: 26px; font-weight: 600;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  color: var(--t2-ink);
  line-height: 1.15;
}
.stat-icon { background: transparent; border: 0; color: var(--t2-ink-faint); padding: 0; }
/* 칠해진 컨테이너 안의 흰 글리프 — admin CSS 는 색 칩(파랑·틸·보라·주황) 위에
   글리프를 흰색으로 얹는 방식이었다. 이 파일이 칩의 면을 걷어내면서 흰 글리프만
   남아 밝은 배경 위에서 보이지 않게 됐다. 면을 잃은 컨테이너는 글리프도 잉크를
   따라야 한다. 스피너 색은 아래 §업로드의 .spinner 규칙이 소유한다. */
.stat-icon :is(.mi, .material-icons, .material-icons-outlined) { color: inherit; }
.market-hero-icon { color: var(--t2-ink-muted); }
.market-hero-icon :is(.mi, .material-icons, .material-icons-outlined) { color: inherit; }
.dashboard-stat-heading { font-size: 13px; font-weight: 600; letter-spacing: var(--t2-track-title); }

/* 테이블 — hairline 만. 그림자·라운딩 없음. */
:where(.admin-wrap) table { width: 100%; border-collapse: collapse; background: transparent; }
:where(.admin-wrap) :is(th, td) {
  padding: 9px var(--t2-s3);
  border: 0;
  border-bottom: 1px solid var(--t2-line);
  text-align: left;
  vertical-align: top;
  font-size: 13px;
}
:where(.admin-wrap) th {
  font-family: var(--t2-font-mono);
  font-size: 10px; font-weight: 500;
  letter-spacing: var(--t2-track-label); text-transform: uppercase;
  color: var(--t2-ink-faint);
  background: transparent;
}
:where(.admin-wrap) tbody tr:hover { background: var(--t2-product-wash); }

/* 목록 행 */
.plugin-item, .module-list-item, .file-item, .api-list-row, .up-store-row,
.license-row, .cert-row, .official-row, .admin-setting-row, .ai-budget-plugin-row {
  display: flex; align-items: center; gap: var(--t2-s3);
  padding: 10px var(--t2-s3);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-structural);
  box-shadow: none;
}
/* 마지막 행의 hairline 은 목록의 아래 경계가 아니라 "다음 항목이 있다" 는
   신호다. 남겨 두면 카드 안에 끊긴 선이 하나 떠 있는 것으로 읽힌다.
   관리자 CSS 에 :last-child 규칙이 있었지만 이 파일이 같은 요소에
   border-bottom 을 선언하므로 레이어 순서에서 전부 죽어 있었다. */
.plugin-item:last-child, .module-list-item:last-child, .file-item:last-child,
.api-list-row:last-child, .up-store-row:last-child, .license-row:last-child,
.cert-row:last-child, .official-row:last-child, .admin-setting-row:last-child,
.ai-budget-plugin-row:last-child { border-bottom: 0; }
:where(.admin-wrap) tbody tr:last-child :is(th, td) { border-bottom: 0; }

.plugin-item:hover, .module-list-item:hover, .api-list-row:hover { background: var(--t2-product-wash); }
.module-list-item.active, .plugin-item.active {
  position: relative;
  color: var(--t2-product-ink); font-weight: 600; background: transparent;
}
.module-list-item.active::after, .plugin-item.active::after {
  content: ""; position: absolute;
  inset-inline-start: 0; top: var(--t2-rail-inset); bottom: var(--t2-rail-inset);
  width: var(--t2-rail-w); background: var(--t2-product);
}

/* 탭 / 세그먼트 — 하단 rail */
.module-viewport-tabs, .plugin-section-nav, .ai-purpose-nav, .ai-cap-popover-seg, .plugin-sort-group {
  display: flex; align-items: center; gap: var(--t2-s1);
  border-bottom: 1px solid var(--t2-line);
  padding: 0;
  background: transparent;
}
.module-viewport-tab {
  position: relative;
  padding: 8px var(--t2-s3);
  min-height: 34px;
  background: transparent;
  border: 0;
  border-radius: var(--t2-radius-structural);
  color: var(--t2-ink-muted);
  font-size: 12.5px;
}
.module-viewport-tab.active, .module-viewport-tab[aria-selected="true"] {
  color: var(--t2-product-ink); font-weight: 600; background: transparent;
}
.module-viewport-tab.active::after, .module-viewport-tab[aria-selected="true"]::after {
  content: ""; position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); bottom: -1px;
  height: var(--t2-rail-w); background: var(--t2-product);
}

/* 필터 · chip 버튼 */
.module-filter-btn, .icon-category-chip, .ai-budget-period-chip, .btn-chip, .plugin-sort-btn {
  position: relative;
  padding: var(--t2-s1) var(--t2-s2); min-height: 30px;
  background: transparent;
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-control);
  color: var(--t2-ink-muted);
  font-size: 12.5px;
}
.module-filter-btn:hover, .icon-category-chip:hover, .btn-chip:hover {
  border-color: var(--t2-line-strong); color: var(--t2-ink);
}
.module-filter-btn.active, .icon-category-chip.active, .ai-budget-period-chip.active,
.btn-chip.active, .plugin-sort-btn.active {
  color: var(--t2-product-ink); border-color: var(--t2-product); font-weight: 600;
  background: var(--t2-product-wash);
}

/* 검색 */
.admin-search-shell, .admin-search-box, .dev-search-wrap, .module-admin-search,
.module-picker-search, .icon-search, .tag-input-wrap, .ext-add-wrap {
  display: flex; align-items: center; gap: var(--t2-s2);
  padding: 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--t2-line-strong);
  border-radius: 0;
  box-shadow: none;
}
.admin-search-shell:focus-within, .dev-search-wrap:focus-within,
.tag-input-wrap:focus-within, .ext-add-wrap:focus-within {
  border-bottom-color: var(--t2-product);
  box-shadow: 0 1px 0 0 var(--t2-product);
}
.admin-search-kbd, .icon-cmd {
  font-family: var(--t2-font-mono);
  font-size: 10.5px;
  padding: 2px var(--t2-s1);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-control);
  color: var(--t2-ink-faint);
  background: transparent;
}
.admin-search-results, .dev-results, .icon-picker-results, .module-picker-list {
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-overlay);
  box-shadow: var(--t2-shadow-overlay);
  overflow-y: auto;
  overscroll-behavior-y: contain;
}
.admin-search-result, .dev-result, .icon-picker-item {
  position: relative;
  display: flex; align-items: center; gap: var(--t2-s2);
  padding: 8px var(--t2-s3);
  border: 0;
  border-radius: var(--t2-radius-structural);
  background: transparent;
  color: var(--t2-ink);
  font-size: 13px;
}
.admin-search-result:hover, .admin-search-result.active,
.dev-result:hover, .icon-picker-item:hover { background: var(--t2-product-wash); }
.admin-search-result-description { font-size: 11.5px; color: var(--t2-ink-faint); }
.admin-search-target-highlight { background: var(--t2-product-select); }
.admin-search-status { font-family: var(--t2-font-mono); font-size: 11px; color: var(--t2-ink-faint); }

/* 토글 — 진짜 원형 컨트롤 예외 */
.toggle-track, .toggle {
  width: 34px; height: 18px;
  border-radius: 999px;
  background: var(--t2-line-strong);
  border: 0;
  box-shadow: none;
  position: relative;
  flex: 0 0 auto;
  transition: background-color var(--t2-motion);
}
.toggle-thumb {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: #fff;
  border: 0;
  box-shadow: none;
  position: absolute; top: 2px; left: 2px;
  transition: transform var(--t2-motion);
}
.toggle[aria-checked="true"], .toggle.on { background: var(--t2-product); }
.toggle[aria-checked="true"] .toggle-thumb, .toggle.on .toggle-thumb { transform: translateX(16px); }
.toggle-wrap { display: flex; align-items: center; gap: var(--t2-s2); font-size: 13px; color: var(--t2-ink-muted); cursor: pointer; }

/* 슬라이더 — 제품 레이어가 외형을, 관리자 레거시 레이어가 위치 계산을 소유한다. */
.t2-discrete-slider-track {
  height: calc(var(--t2-slider-thumb) + var(--t2-slider-pad) * 2);
  box-sizing: border-box;
  border: 0;
  border-radius: 999px;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--t2-line);
  overflow: visible;
}
.t2-discrete-slider-fill {
  height: var(--t2-slider-rail);
  background: var(--t2-product);
  border-radius: 999px;
}
.t2-discrete-slider-thumb {
  width: var(--t2-slider-thumb);
  height: var(--t2-slider-thumb);
  border-radius: 50%;
  background: #fff;
  border: 0;
  box-shadow: 0 2px 10px rgba(17,24,39,.28);
}
.t2-discrete-slider-point {
  width: var(--t2-slider-dot);
  height: var(--t2-slider-dot);
  border-radius: 50%;
  background: color-mix(in srgb, #fff 62%, transparent);
}
.t2-discrete-slider-point[data-active="false"] { background: var(--t2-ink-muted); opacity: .45; }
.t2-discrete-slider-labels { font-family: var(--t2-font-mono); font-size: 11px; color: var(--t2-ink-muted); }
.t2-discrete-slider[aria-disabled="true"] .t2-discrete-slider-fill { background: var(--t2-ink-muted); }
.t2-discrete-slider[aria-disabled="true"] .t2-discrete-slider-thumb { background: var(--t2-inset); box-shadow: none; }
@media (max-width: 760px) {
  .t2-discrete-slider-labels { font-size: 10px; }
}

/* 진행 · 스피너 */
.t2-nsfw-progress, .t2-nsfw-model-bar {
  height: 2px; background: var(--t2-line); border-radius: 999px; overflow: hidden;
}
.t2-nsfw-progress-fill, .t2-nsfw-model-bar-fill { background: var(--t2-product); }
.t2-upload-progress .t2-progress-bar { height: 2px; background: var(--t2-line); border-radius: 999px; }
.t2-upload-progress .t2-progress-fill { background: var(--t2-product); }
.t2-upload-progress .t2-progress-text { font-family: var(--t2-font-mono); font-size: 11px; color: var(--t2-ink-faint); }
.spinner {
  width: 14px; height: 14px;
  border: 1px solid var(--t2-line-strong);
  border-top-color: var(--t2-product);
  border-radius: 50%;
  box-shadow: none;
}

/* 코드 · 진단 출력 */
:where(.admin-wrap, [data-t2-plugin-surface])
  :is(.dev-code, .api-example, .pkg-sec-code, .up-code-diff, .up-diff-code, .key-code, pre) {
  font-family: var(--t2-font-mono);
  font-size: 12px;
  background: var(--t2-inset);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-control);
  color: var(--t2-ink);
  padding: var(--t2-s3);
}
:where(.admin-wrap) .up-diff-old { color: var(--t2-danger); background: var(--t2-danger-soft); }
:where(.admin-wrap) :is(.dev-key, .dev-stat, .env-check-count) {
  font-family: var(--t2-font-mono); font-variant-numeric: tabular-nums;
}

/* ── 저장 바 — 해설 709 A ──────────────────────────────────────────────
   실행이 초점을 갖는다. 예전에는 save-hint 가 저장 버튼보다 앞에 놓여, 매번
   같은 설명을 지나야 실행에 닿았다. 마크업에서 버튼을 앞으로 옮겼고(읽기
   순서와 시각 위계 일치, 709 A-2), 여기서는 설명을 보조로 낮춘다.

   sticky 로 떠 있으므로 아래 콘텐츠 자리를 확보해야 한다 (708 F-2).
   자리 확보는 아래 .section-panel 규칙이 담당한다. */
.save-bar {
  display: flex; align-items: center; gap: var(--t2-gap-group);
  padding: var(--t2-inset-control) var(--t2-inset-section);
  background: var(--t2-surface);
  border: 0;
  border-top: 1px solid var(--t2-line);
  box-shadow: none;
}
.save-bar .save-hint {
  flex: 1 1 auto; min-width: 0;
  font-size: 12px; font-weight: 400;
  color: var(--t2-ink-muted);
}
.save-bar .save-hint-title { font-weight: 500; color: var(--t2-ink-muted); }
.save-bar :is(.btn, .btn-primary) { flex: 0 0 auto; }

/* 떠 있는 저장 바는 자기 뒤에 오는 콘텐츠를 영구히 덮는다 (708 F-2).
   ai 탭처럼 카드마다 저장 바가 있는 화면에서 실제로 그랬다. 스크롤 끝에서
   제자리로 돌아와 아무것도 가리지 않게 되는 위치 — 패널의 마지막 요소 —
   일 때만 떠 있을 수 있고, 그 밖의 저장 바는 흐름 안에 있는다. */
:where(.admin-wrap) .save-bar { position: static; }
:where(.admin-wrap) .section-panel > .save-bar:last-child {
  position: sticky;
  bottom: var(--t2-inset-control);
}

.admin-save-state { font-family: var(--t2-font-mono); font-size: 11px; color: var(--t2-ink-faint); }

/* ── 정본 위치 표시기 — 해설 709 C-3·C-4 ────────────────────────────────
   맥락 때문에 다른 탭에 나타난 설정이 자신의 원래 자리를 밝히고, 그 표시가
   그대로 이동 수단이 된다. 값은 정본과 같은 것을 읽으므로 여기서 편집하지
   않는다는 사실도 함께 말한다. 위치 표시의 리듬은 708 E 를 따른다. */
.admin-canonical {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: var(--t2-gap-tight);
  margin-top: var(--t2-trail-locator);
  padding: 0;
  font-family: var(--t2-font-mono);
  font-size: 11px;
  color: var(--t2-ink-faint);
  background: transparent;
  border: 0;
  text-align: start;
}
button.admin-canonical.is-link { cursor: pointer; min-height: var(--t2-hit); }
button.admin-canonical.is-link:hover { color: var(--t2-product-ink); }
button.admin-canonical.is-link:focus-visible { outline: 1px solid var(--t2-product); outline-offset: 2px; }
.admin-canonical-crumb[aria-current="true"] { color: var(--t2-ink-muted); font-weight: 500; }
.admin-canonical-sep { color: var(--t2-line-strong); }
.admin-canonical-go { font-size: 14px; }
.admin-canonical-note { color: var(--t2-ink-faint); }

/* ── 위치 표시 — 해설 708 E-1 ──────────────────────────────────────────
   위치 표시는 아래 제목에 속한다. 위 콘텐츠와는 멀고 제목과는 가깝다. */
.admin-context-strip {
  font-family: var(--t2-font-mono);
  font-size: 11px;
  color: var(--t2-ink-faint);
  padding: var(--t2-inset-control) var(--t2-inset-shell) var(--t2-trail-locator);
  background: var(--t2-surface);
  border: 0;
  border-bottom: 1px solid var(--t2-line);
}
.admin-context-path {
  font-family: var(--t2-font-mono);
  color: var(--t2-ink-faint);
}

/* 인증 화면 */
.auth-screen, .key-screen, .login-screen {
  background: var(--t2-base);
  display: grid;
  place-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--t2-s5);
}
.auth-card, .key-card {
  width: min(100%, 380px);
  background: var(--t2-surface);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-island);
  box-shadow: none;
  padding: var(--t2-s6);
}
.auth-title, .key-title { font-size: 16px; font-weight: 600; letter-spacing: var(--t2-track-title); margin: 0 0 var(--t2-s2); }
.auth-desc, .key-desc { font-size: 12.5px; color: var(--t2-ink-muted); line-height: 1.65; }
.auth-logo, .key-icon { color: var(--t2-ink-faint); background: transparent; border: 0; }

/* 토스트 */
.toast-container { display: grid; gap: var(--t2-s2); }
.toast {
  position: relative;
  display: flex; align-items: center; gap: var(--t2-s2);
  padding: 10px var(--t2-s3);
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-overlay);
  box-shadow: var(--t2-shadow-overlay);
  font-size: 12.5px;
  color: var(--t2-ink);
}
.toast::before {
  content: ""; position: absolute;
  left: var(--t2-rail-inset); right: var(--t2-rail-inset); top: 0;
  height: var(--t2-rail-w); background: var(--t2-product);
}
.toast[data-type="error"]::before   { background: var(--t2-danger); }
.toast[data-type="warning"]::before { background: var(--t2-warning); }
.toast[data-type="success"]::before { background: var(--t2-success); }
.toast-close { color: var(--t2-ink-faint); background: transparent; border: 0; }


/* ═══ 11. 플러그인 공통 표면 ═════════════════════════════════════════════
   플러그인은 제2의 시각 체계를 만들지 않는다. 토큰만 별칭한다. */
[data-t2-plugin-surface] { color: var(--t2-ink); font-family: var(--t2-font-ui); }
.t2-plugin-block {
  background: var(--t2-workspace);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-structural);
  box-shadow: none;
}
/* 플러그인 지역 토큰 재정렬 — 경쟁 accent 무력화 */
[data-t2-plugin-surface] {
  --t2-aic-border: var(--t2-line);
  --t2-aic-surface: var(--t2-surface);
  --t2-aic-surface-muted: var(--t2-inset);
  --t2-aic-accent: var(--t2-product);
  --t2-collab-accent: var(--t2-product);
  --t2-collab-border: var(--t2-line);
}
/* 협업 원격 캐럿 — 사용자 색은 기능이므로 유지, 두께만 통일 */
.t2-remote-caret { width: 2px; border-radius: 0; }
.t2-remote-selection { mix-blend-mode: multiply; }
html[data-t2editor-theme="dark"] .t2-remote-selection { mix-blend-mode: screen; }
.t2-search-highlight-active { background: var(--t2-product-select); outline: 1px solid var(--t2-product); }

/* 업로드 표면 */
.t2-upload-container {
  background: var(--t2-workspace);
  border: 1px dashed var(--t2-line-strong);
  border-radius: var(--t2-radius-island);
  color: var(--t2-ink-muted);
  padding: var(--t2-s5);
  text-align: center;
}
.t2-upload-container.drag-over, .t2-upload-container:focus-within {
  border-color: var(--t2-product);
  border-style: solid;
  background: var(--t2-product-wash);
}
.t2-upload-container__hint { font-size: 11.5px; color: var(--t2-ink-faint); }

/* 개인정보 · NSFW — critical surface. 의미가 지배한다. */
.t2-privacy-surface, .t2privacy-dialog {
  background: var(--t2-floating);
  border: 1px solid var(--t2-line);
  border-radius: var(--t2-radius-modal);
  box-shadow: var(--t2-shadow-modal);
}
.t2privacy-backdrop, .t2-nsfw-dialog-overlay, .t2-safeai-legal-overlay { background: var(--md-overlay); }
/* 개인정보 동의 버튼 — 동의/거부는 되돌리기 어려운 결정이므로 두 선택지가
   형태로 구별되어야 한다. §4 의 공통 버튼 규칙이 background 를 transparent,
   color 를 muted 로 잡아 두 버튼이 똑같이 보였다. 표면 토큰으로 되돌린다.
   런타임도 같은 토큰을 인라인으로 굳혀(호스트 CSS 방어) 값이 갈라지지 않는다. */
.t2-privacy-surface .t2privacy-btn {
  background: var(--t2-privacy-surface);
  color: var(--t2-privacy-on-surface);
  border: 1px solid var(--t2-privacy-border);
}
.t2-privacy-surface .t2privacy-btn-primary {
  background: var(--t2-privacy-primary);
  color: var(--t2-privacy-primary-text);
  border-color: transparent;
  font-weight: 600;
}
/* 안내 배너 닫기 버튼 — §4 의 공통 버튼 규칙이 position:relative 와 컨트롤
   radius 를 선언해 모듈의 absolute 배치와 원형을 덮었다. 결과는 배너 오른쪽에
   빈 자리(52px 패딩)만 남고 닫기 버튼이 본문 아래로 흘러내린 상태였다.
   진짜 원형 컨트롤은 law 704 의 radius 예외에 해당한다. */
.t2privacy-notice > button {
  position: absolute;
  top: var(--t2-s2); right: var(--t2-s2);
  width: var(--t2-hit); height: var(--t2-hit);
  padding: 0;
  border: 0;
  border-radius: var(--t2-radius-pill);
  background: transparent;
  color: inherit;
}
.t2-nsfw-dialog-blocked { border-color: var(--t2-danger); }
.t2-nsfw-status-badge-simple, .t2-safeai-legal-chip {
  font-family: var(--t2-font-mono); font-size: 10.5px;
  border: 1px solid var(--t2-line); border-radius: var(--t2-radius-control);
  background: transparent; color: var(--t2-ink-muted); padding: 2px var(--t2-s1);
}
.t2-nsfw-timer-seconds { font-family: var(--t2-font-mono); font-variant-numeric: tabular-nums; }
.t2-nsfw-dialog-separator, .t2-safeai-legal-divider { height: 1px; background: var(--t2-line); border: 0; }
.t2privacy-btn { position: relative; }


/* ═══ 12. 반응형 · 안전 영역 ════════════════════════════════════════════ */
@media (max-width: 767px), (pointer: coarse) {
  .t2-editor-container { margin: var(--t2-s2) auto; }
  .t2-editor { padding: var(--t2-s4); }
  .content-area, .admin-flat-page { padding: var(--t2-s4) var(--t2-s3); }
  .card, .stat-card, .api-card { padding: var(--t2-s3); }

  /* 기능을 숨기지 않고 geometry 만 재구성한다 (law 707 I) */
  .t2-toolbar { flex-wrap: nowrap; }
  .t2-toolbar .t2-btn.active::after { left: 11px; right: 11px; }

  .t2-modal-surface, .t2-plugin-surface-shell {
    max-height: 92vh; max-height: 92dvh;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .sidebar { padding-bottom: env(safe-area-inset-bottom); }
  /* [iOS⚠️] 화면 아래에 머무는 저장 바는 홈 인디케이터 위로 자기 여백을 확보한다.
     아래쪽 sticky 오프셋도 같은 만큼 밀어야 바가 인디케이터에 물리지 않는다. */
  :where(.admin-wrap) .save-bar {
    padding-bottom: max(var(--t2-inset-control), env(safe-area-inset-bottom));
    padding-inline: max(var(--t2-inset-section), env(safe-area-inset-left))
                    max(var(--t2-inset-section), env(safe-area-inset-right));
  }
  :where(.admin-wrap) .section-panel > .save-bar:last-child {
    bottom: max(var(--t2-inset-control), env(safe-area-inset-bottom));
  }
  .topbar { padding-inline: max(var(--t2-s3), env(safe-area-inset-left)) max(var(--t2-s3), env(safe-area-inset-right)); }
  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
  .t2-plugin-surface-footer { flex-wrap: wrap; }
}

/* 관리자 반응형 외형도 제품 레이어가 소유한다. 레거시 레이어의 @media 규칙은
   이 레이어의 기본 선언을 이길 수 없으므로, 실제로 달라져야 하는 값은 여기 둔다. */
@media (min-width: 561px) {
  .module-viewport-tab { min-height: 36px; }
}
@media (max-width: 900px) {
  .sidebar { padding-top: max(0px, env(safe-area-inset-top)); }
  .topbar { padding: 8px max(12px, env(safe-area-inset-right)) 8px max(12px, env(safe-area-inset-left)); }
  .content-area { padding: var(--t2-s5) var(--t2-s4) 72px; }
  .admin-setting-row { gap: var(--t2-s2); }
}
@media (max-width: 860px) {
  .nav-purpose-toggle { min-height: 48px; }
  .admin-context-strip {
    padding-inline: max(12px, env(safe-area-inset-left)) max(12px, env(safe-area-inset-right));
  }
}
@media (max-width: 820px) {
  .plugin-item { gap: var(--t2-s2) var(--t2-s3); }
  .plugin-modal { border-radius: var(--t2-radius-structural); }
  .plugin-modal-body { padding: var(--t2-s4); }
}
@media (max-width: 700px) {
  .content-area { padding: var(--t2-s4) 14px 68px; }
  .section-header { padding-bottom: var(--t2-s3); }
  .card-body { padding: var(--t2-s4); }
  .card-header { padding: 14px var(--t2-s4); }
  .stat-card { padding: 14px; }
  .topbar-title { font-size: 14px; }
  .auth-card, .key-card { padding: var(--t2-s6) var(--t2-s4); }
}
@media (max-width: 720px) {
  .t2-plugin-surface-shell { border-radius: var(--t2-radius-control); }
  .t2-plugin-surface-title { font-size: 16px; }
}
@media (max-width: 680px) {
  .icon-picker-modal { border-radius: var(--t2-radius-structural); }
}
@media (max-width: 640px) {
  .t2privacy-dialog { border-radius: var(--t2-radius-structural); }
}
@media (max-width: 620px) {
  .admin-context-strip { padding-block: var(--t2-s1); }
}
@media (max-width: 600px) {
  .topbar { gap: var(--t2-s2); }
  .up-release-card { padding: var(--t2-s3); }
}
@media (max-width: 560px) {
  .module-viewport-tab { min-width: 44px; min-height: 44px; }
}
@media (max-width: 480px) {
  .plugin-item { padding: var(--t2-s3) var(--t2-s2); }
}
@media (max-width: 420px) {
  .content-area { padding-inline: var(--t2-s3); }
}
@media (max-width: 767px), (pointer: coarse) {
  .t2-editor-container { border-radius: var(--t2-radius-control); }
  .t2-editor-status {
    min-height: 50px;
    padding-right: max(10px, env(safe-area-inset-right));
    padding-left: max(12px, env(safe-area-inset-left));
  }
  .t2-translate-menu-item, .t2-font-size-option { font-size: 16px; }
}

/* 축소된 모션 */
@media (prefers-reduced-motion: reduce) {
  :where(.t2-editor-container, .admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) *,
  :where(.t2-editor-container, .admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) *::before,
  :where(.t2-editor-container, .admin-wrap, .t2-modal-overlay, [data-t2-plugin-surface]) *::after {
    transition-duration: .01ms;
    animation-duration: .01ms;
  }
}

/* 고대비 환경 — 색 외 단서를 유지한다 */
@media (forced-colors: active) {
  .t2-toolbar .t2-btn.active::after,
  .module-viewport-tab.active::after { forced-color-adjust: none; }
  :where(.t2-editor-container, .admin-wrap) :is(button, input, select, textarea):focus-visible {
    outline: 2px solid CanvasText;
  }
}

} /* @layer t2.product */
