/*
 * slime 웹 렌더러 기본 스타일.
 *
 * 렌더러가 클래스 이름만 내보내고 스타일을 주지 않으면, 계획이 정한 등급이
 * 소비자마다 다르게 해석되거나 아예 무시된다 — `data-target="large"`는
 * 이 파일 없이는 아무 효과가 없다. 계약이 약속한 것을 실제로 지키는 파일이다.
 *
 * 세 층으로 나뉜다.
 *   1. 표면 특성은 여기서 **스스로 파악**한다 — 터치 여부, 화면 폭, 다크 모드,
 *      대비 선호. 사용자가 이미 자기 기기에 정해 둔 것이므로 slime의 자동 변경이
 *      아니고, 따라서 설명을 붙이지 않는다.
 *   2. 상황 추정은 **계획이 정한다** — data-target, data-density.
 *   3. 사용자 설정은 둘 다 이긴다 — Hub의 userSettings로 올라간다.
 *
 * 소비자는 이 파일을 그대로 쓰거나, 토큰(--slime-*)만 덮어써 자기 색을 입힌다.
 */

:root {
  /* 색 — 대비를 맞춰 고른 값이다. 덮어쓸 때도 4.5:1을 지킬 것 */
  --slime-fg: #1c1e21;
  --slime-fg-muted: #5b6472;
  --slime-bg: #ffffff;
  --slime-surface: #fafbfc;
  --slime-border: #e2e5ea;
  --slime-accent: #1f6091;        /* 흰 글씨와 6.1:1 */
  --slime-accent-border: #17496e;
  --slime-danger: #a3392f;        /* 흰 글씨와 6.6:1 */
  --slime-danger-border: #7d2c24;
  --slime-on-accent: #ffffff;     /* 버튼 글자 — 배경 토큰과 짝을 이룬다 */
  --slime-disabled-bg: #6b7480;   /* 비활성도 읽혀야 한다 — 규격 예외지만 사용자는 아니다 */
  --slime-disabled-border: #565e68;
  --slime-disabled-fg: #ffffff;
  --slime-notice-bg: #eef1f5;
  --slime-warn-bg: #fdecec;
  --slime-warn-fg: #8a2f28;

  /* 조작 목표 — 계획의 등급이 실제 치수로 바뀌는 자리 */
  --slime-target-standard: 44px;  /* Apple HIG 44pt · WCAG 2.5.5 44px */
  --slime-target-large: 56px;
  --slime-target-gap: 8px;

  /* 글자 — rem이라 사용자가 키운 기본 글꼴이 그대로 반영된다 */
  --slime-text: 0.95rem;
  --slime-text-small: 0.8rem;

  /*
   * 형태와 움직임 — slime의 시각 언어.
   *
   * 계획이 바뀌면 화면은 다시 그려지는 것이 아니라 **흘러 옮겨간다**. 움직임은
   * 장식이 아니라 설명의 연장이다: explanation이 말로 하는 것("걷는 중으로 보여
   * 버튼을 키웠습니다")을 움직임이 눈으로 보여준다 — 커진 버튼이 *어디서* 커졌는지.
   *
   * 그래서 규칙도 설명과 같다. 사실(경고·출처·차단 사유)을 지연시키거나 가리는
   * 움직임은 없고, prefers-reduced-motion이면 전부 멈춘다 — 그것은 표면 특성이라
   * 사용자가 이미 자기 기기에 정해 둔 것이다.
   */
  --slime-radius: 14px;
  --slime-radius-small: 9px;
  --slime-shadow: 0 1px 2px rgba(15, 23, 32, 0.05), 0 5px 18px rgba(15, 23, 32, 0.06);
  --slime-shadow-raised: 0 2px 4px rgba(15, 23, 32, 0.08), 0 10px 28px rgba(15, 23, 32, 0.11);
  --slime-motion-fast: 140ms;
  --slime-motion: 260ms;
  --slime-motion-slow: 420ms;
  --slime-ease: cubic-bezier(0.22, 1, 0.36, 1);          /* 빠르게 떠나 부드럽게 도착 */
  --slime-ease-spring: cubic-bezier(0.34, 1.35, 0.64, 1); /* 미세한 살아 있음 — 과장 금지 */
}

/* 1-a. 터치 표면은 손가락이 목표다 — 마우스보다 큰 기본값에서 시작한다 */
@media (pointer: coarse) {
  :root {
    --slime-target-standard: 48px;
    --slime-target-large: 60px;
    --slime-target-gap: 12px;
  }
}

/* 1-b. 움직임을 줄여 달라는 것도 사용자가 이미 정해 둔 것이다 — 전부 멈춘다.
       렌더러 코드도 같은 질의를 보고 계획 사이 형태 전환을 생략한다. */
@media (prefers-reduced-motion: reduce) {
  .ui-plan *, .ui-plan, .semantic-action, .explain-undo-chip, .compose-area textarea {
    animation: none !important;
    transition: none !important;
  }
  ::view-transition-group(*),
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none !important; }
}

/* 1-c. 다크 모드는 사용자가 이미 정해 둔 것이다 — 묻지 않고 따른다 */
@media (prefers-color-scheme: dark) {
  :root {
    --slime-fg: #e8eaed;
    --slime-fg-muted: #aab2bd;
    --slime-bg: #16181b;
    --slime-surface: #1e2126;
    --slime-border: #333941;
    --slime-accent: #6fb2e8;        /* 어두운 배경에서는 밝은 쪽이 대비를 만든다 */
    --slime-accent-border: #8cc4f0;
    --slime-danger: #f08a80;
    --slime-danger-border: #f5a89f;
    --slime-on-accent: #12161a;
    --slime-disabled-bg: #3a4048;
    --slime-disabled-border: #4a515a;
    --slime-disabled-fg: #cfd5dc;
    --slime-notice-bg: #23272d;
    --slime-warn-bg: #3a2320;
    --slime-warn-fg: #f2b3ac;
    /* 어두운 바탕에서 그림자는 안 보인다 — 깊이는 더 짙은 그림자보다 면 대비로 만든다 */
    --slime-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 6px 20px rgba(0, 0, 0, 0.30);
    --slime-shadow-raised: 0 2px 4px rgba(0, 0, 0, 0.45), 0 12px 32px rgba(0, 0, 0, 0.40);
  }
}

/* 1-d. 대비를 더 원하는 사용자에게는 더 준다 */
@media (prefers-contrast: more) {
  :root {
    --slime-fg-muted: var(--slime-fg);
    --slime-border: currentColor;
    --slime-accent: #0f4a75;
    --slime-danger: #7d2c24;
  }
}

/*
 * 계획 사이 형태 전환(View Transitions). 렌더러가 컴포넌트마다
 * view-transition-name을 붙이므로, 같은 컴포넌트는 계획이 바뀔 때
 * 옛 자리에서 새 자리로 **흘러간다** — 사라졌다 다시 나타나지 않는다.
 */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: var(--slime-motion); }
::view-transition-group(*) {
  animation-duration: var(--slime-motion-slow);
  animation-timing-function: var(--slime-ease);
}

/* 첫 도착만 미끄러져 들어온다. 이후의 변화는 형태 전환이 맡는다 —
   재렌더마다 입장을 반복하면 살아 있는 게 아니라 부산스러운 것이다. */
@keyframes slime-in {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
.ui-plan section { animation: slime-in var(--slime-motion) var(--slime-ease) backwards; }
.ui-plan section:nth-child(2) { animation-delay: 45ms; }
.ui-plan section:nth-child(3) { animation-delay: 90ms; }
.ui-plan section:nth-child(4) { animation-delay: 135ms; }
.ui-plan section:nth-child(n+5) { animation-delay: 180ms; }
.slime-settled .ui-plan section { animation: none; }

.ui-plan section {
  border: 1px solid var(--slime-border);
  border-radius: var(--slime-radius);
  padding: 12px 14px;
  margin: 0 0 10px;
  background: var(--slime-bg);
  color: var(--slime-fg);
  box-shadow: var(--slime-shadow);
}
.ui-plan h3 { margin: 0 0 4px; font-size: var(--slime-text); }
.content-line { margin: 2px 0; font-size: var(--slime-text); }
.density-note { margin: 0; font-size: var(--slime-text-small); color: var(--slime-fg-muted); }
.pattern-list { background: var(--slime-surface); }
.pattern-detail { border-left: 4px solid var(--slime-accent); }
.pattern-glancecapsule { background: var(--slime-surface); }

/* 2. 계획이 정한 목표 크기가 실제 치수가 되는 자리.
      크기 전환에 시간을 준다 — 걷기 시작해 버튼이 커지는 순간, 커지는 것이
      보여야 explanation의 문장과 화면이 같은 말을 한다. */
.semantic-action {
  margin: 4px var(--slime-target-gap) 4px 0;
  min-height: var(--slime-target-standard);
  padding: 8px 20px;
  border-radius: var(--slime-radius-small);
  border: 1px solid var(--slime-accent-border);
  background: var(--slime-accent);
  color: var(--slime-on-accent);
  font-size: var(--slime-text);
  cursor: pointer;
  box-shadow: var(--slime-shadow);
  transition:
    min-height var(--slime-motion) var(--slime-ease),
    padding var(--slime-motion) var(--slime-ease),
    transform var(--slime-motion-fast) var(--slime-ease-spring),
    box-shadow var(--slime-motion-fast) var(--slime-ease),
    background-color var(--slime-motion-fast) var(--slime-ease);
}
.semantic-action[data-target="large"] {
  min-height: var(--slime-target-large);
  padding: 12px 24px;
}
.semantic-action:hover:not([disabled]) {
  transform: translateY(-1px);
  box-shadow: var(--slime-shadow-raised);
}
.semantic-action:active:not([disabled]) { transform: scale(0.97); }
.semantic-action[disabled] {
  background: var(--slime-disabled-bg);
  border-color: var(--slime-disabled-border);
  color: var(--slime-disabled-fg);
  cursor: not-allowed;
}
.semantic-action[data-risk="high"] {
  background: var(--slime-danger);
  border-color: var(--slime-danger-border);
}

.modality-notice, .sensing-disclosure, .confidence-badge {
  display: inline-block; margin: 0 0 10px; padding: 4px 10px;
  font-size: var(--slime-text-small); border-radius: 999px;
  background: var(--slime-notice-bg); border: 1px solid var(--slime-border);
  color: var(--slime-fg-muted);
}
/* 무엇이라 말하면 되는지. 버튼 바로 아래 붙어야 어느 행동의 낱말인지 보인다. */
.voice-hint {
  margin: 2px 0 10px; font-size: var(--slime-text-small);
  color: var(--slime-fg-muted);
}
.handoff-notice, .blocked-notice, .observe-notice {
  margin: 0 0 10px; padding: 8px 12px; font-size: var(--slime-text-small);
  color: var(--slime-fg-muted); background: var(--slime-notice-bg);
  border: 1px dashed var(--slime-border); border-radius: 8px;
}
.observe-notice { display: flex; gap: 10px; align-items: center; }
.observe-notice .takeover {
  min-height: var(--slime-target-standard); padding: 6px 14px; border-radius: 6px;
  border: 1px solid var(--slime-accent-border); background: var(--slime-bg);
  color: var(--slime-accent); font-size: var(--slime-text-small); cursor: pointer;
}
/*
 * 출처·등급·부담 파티. 이 줄을 끄는 토큰은 두지 않는다 — 계약이 요구하는 사실을
 * 숨기는 손잡이를 만들지 않기 위해서다. 색은 다른 보조 문구와 같게 두되, 등급은
 * 배경을 줘서 본문과 섞이지 않게 한다.
 */
.agent-trust { margin: 0 0 6px; font-size: var(--slime-text-small); color: var(--slime-fg-muted); }
.agent-tier {
  padding: 1px 8px; border-radius: 999px; background: var(--slime-surface);
  border: 1px solid var(--slime-border); color: var(--slime-fg);
}
/* 공인은 색으로도 구분한다 — 값은 계약의 말이고 이 선택자는 표현일 뿐이다.
   말(공인/등록)은 여전히 계획이 실어 온 것을 그대로 쓴다 (V-4). */
.agent-tier[data-tier="certified"] {
  border-color: color-mix(in srgb, var(--slime-accent) 45%, var(--slime-border));
  background: color-mix(in srgb, var(--slime-accent) 8%, var(--slime-bg));
  color: var(--slime-accent);
}
.tier-evaluated { color: var(--slime-fg-muted); }
.bearing-party { color: var(--slime-fg-muted); }

.progressive-reveal {
  border: 1px solid var(--slime-border); border-radius: 8px; padding: 8px 12px;
  margin: 0 0 10px; background: var(--slime-surface); font-size: var(--slime-text);
}
.progressive-reveal summary {
  cursor: pointer; color: var(--slime-accent); font-size: var(--slime-text-small);
  min-height: var(--slime-target-standard); display: flex; align-items: center;
}
.reveal-line { margin: 6px 0 0; }

/* 가림은 서리 낀 유리처럼 — 내용이 기기에 없다는 사실은 그대로이고(계약이 막는다),
   "여기 무언가 있는데 지금은 가려져 있다"는 상태가 형태로도 읽히게 한다. */
.pattern-privacyveil {
  border-left: 4px solid var(--slime-fg-muted);
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--slime-fg-muted) 7%, var(--slime-bg)),
    var(--slime-bg) 65%
  );
}
.veil-note { margin: 0 0 6px; font-size: var(--slime-text-small); color: var(--slime-fg-muted); }
.veil-mask {
  margin: 0; font-size: 1.2rem; letter-spacing: 4px;
  color: transparent;
  text-shadow: 0 0 7px var(--slime-fg-muted); /* 초점이 맞지 않는 점들 — 서리다 */
}
@media (prefers-contrast: more) {
  .veil-mask { color: var(--slime-fg-muted); text-shadow: none; }
}

.compose-area textarea {
  width: 100%; box-sizing: border-box; font: inherit; font-size: var(--slime-text);
  padding: 10px; border: 1px solid var(--slime-border);
  border-radius: var(--slime-radius-small);
  background: var(--slime-bg); color: var(--slime-fg); resize: vertical;
  transition:
    border-color var(--slime-motion-fast) var(--slime-ease),
    box-shadow var(--slime-motion-fast) var(--slime-ease);
}
.compose-area textarea:focus {
  outline: none;
  border-color: var(--slime-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--slime-accent) 18%, transparent);
}
.compose-area textarea[disabled] { background: var(--slime-surface); color: var(--slime-fg-muted); }
.draft-note { margin: 6px 0 0; font-size: var(--slime-text-small); color: var(--slime-fg-muted); }

.explain-undo-chip {
  display: inline-flex; gap: 10px; align-items: center; margin-top: 10px;
  background: var(--slime-notice-bg); border: 1px solid var(--slime-border);
  border-radius: 999px; padding: 4px 14px; font-size: var(--slime-text-small);
  color: var(--slime-fg);
}
.explain-undo-chip .undo {
  border: none; background: none; color: var(--slime-accent); cursor: pointer;
  font-size: var(--slime-text-small); text-decoration: underline;
  min-height: var(--slime-target-standard);
}
.explain-undo-chip .undo[disabled] { color: var(--slime-fg-muted); cursor: not-allowed; }

.confirm-banner, .draft-loss-warning, .plan-rejected {
  background: var(--slime-warn-bg); border: 1px solid var(--slime-danger);
  border-radius: 8px; padding: 10px 12px; margin-bottom: 10px;
  font-size: var(--slime-text); color: var(--slime-warn-fg);
}
.confirm-banner { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.confirm-banner button {
  min-height: var(--slime-target-standard); padding: 6px 14px; border-radius: 6px;
  border: 1px solid var(--slime-danger-border); background: var(--slime-danger);
  color: var(--slime-on-accent); cursor: pointer; font-size: var(--slime-text-small);
}
.confirm-banner .confirm-dismiss { background: var(--slime-bg); color: var(--slime-danger); }
.draft-loss-warning { font-weight: 600; }
.plan-rejected p { margin: 6px 0 0; font-weight: 400; }
.plan-rejected-detail {
  margin-top: 8px; font-size: var(--slime-text-small); color: var(--slime-fg-muted);
}
.plan-rejected-detail summary { cursor: pointer; }
.plan-rejected-detail ul { margin: 6px 0 0; padding-left: 18px; }

.degraded-shell {
  margin: 0 0 10px; padding: 8px 12px; font-size: var(--slime-text-small);
  background: var(--slime-notice-bg); border: 1px dashed var(--slime-border);
  border-radius: 8px; color: var(--slime-fg-muted);
}

/* 키보드 초점은 어디서든 같은 모양으로 보인다. box-shadow는 강제 색상 모드에서
   사라지므로, 거기서는 시스템 outline이 대신 선다. */
.semantic-action:focus-visible,
.explain-undo-chip .undo:focus-visible,
.observe-notice .takeover:focus-visible,
.confirm-banner button:focus-visible,
.progressive-reveal summary:focus-visible {
  outline: 2px solid var(--slime-accent);
  outline-offset: 2px;
}
@media (forced-colors: active) {
  .compose-area textarea:focus { outline: 2px solid; }
}

/*
 * 메뉴 셸 — 연결된 채널. 계획이 아니므로 계획 컴포넌트와 다르게 보인다:
 * 그림자도 카드도 없고, 고른 칸만 밑줄로 선다. 셸이 내용처럼 보이면
 * 사용자는 메뉴를 읽을거리로 오해한다.
 *
 * 목표 크기는 계획이 정한 등급을 따르지 않는다 — 셸은 계약 밖이므로
 * 표준 치수로 고정하고, 표면 특성(터치 여부)만 반영한다.
 */
.menu-shell {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin: 0 0 14px; padding-bottom: 6px;
  border-bottom: 1px solid var(--slime-border);
  overflow-x: auto;
}
.menu-item {
  min-height: var(--slime-target-standard);
  padding: 6px 14px; border: none; background: none; cursor: pointer;
  font: inherit; font-size: var(--slime-text-small); color: var(--slime-fg-muted);
  border-bottom: 2px solid transparent; border-radius: var(--slime-radius-small);
  white-space: nowrap;
  transition:
    color var(--slime-motion-fast) var(--slime-ease),
    border-color var(--slime-motion-fast) var(--slime-ease),
    background-color var(--slime-motion-fast) var(--slime-ease);
}
.menu-item:hover { background: var(--slime-surface); color: var(--slime-fg); }
.menu-item[aria-selected="true"] {
  color: var(--slime-accent); border-bottom-color: var(--slime-accent); font-weight: 600;
}
.menu-item:focus-visible { outline: 2px solid var(--slime-accent); outline-offset: 2px; }

/* 로그인 셸 — 채널이 열리기 전의 화면(`I-1`). 계획이 아니므로 등급 토큰
   (목표 크기·밀도)이 붙지 않는다. 여기서 정할 것은 계획이 없기 때문이다. */
.login-shell {
  max-width: 22rem; margin: 4rem auto; padding: 1.5rem;
  background: var(--slime-bg); border: 1px solid var(--slime-border); border-radius: 10px;
}
.login-title { font-size: 1rem; margin: 0 0 1.25rem; }
.login-label { display: block; font-size: .78rem; margin: .65rem 0 .25rem; color: var(--slime-fg-muted); }
.login-input {
  width: 100%; box-sizing: border-box; padding: .5rem; border-radius: 6px;
  border: 1px solid var(--slime-border); background: var(--slime-surface); color: var(--slime-fg);
}
.login-input:focus-visible { outline: 2px solid var(--slime-accent); outline-offset: 1px; }
.login-submit {
  width: 100%; margin-top: 1rem; padding: .55rem; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--slime-border); background: var(--slime-fg); color: var(--slime-bg); font-weight: 600;
}
.login-submit[disabled] { opacity: .5; cursor: default; }
.login-toggle {
  margin-top: .6rem; padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--slime-fg-muted); font-size: .76rem; text-decoration: underline;
}
/* 색만으로 가르지 않는다 — 셸이 `role="alert"`를 함께 붙인다. */
.login-notice { min-height: 1.2em; margin: .75rem 0 0; font-size: .78rem; color: var(--slime-fg-muted); }
.login-notice-error { color: var(--slime-danger, #b00); }
