/* RAPID guided — 제품 본체(styles.css)와 같은 시각 언어를 쓴다.
   이 화면은 원래 어두운 GitHub 팔레트 복제였고, 그래서 같은 제품인데 다른
   물건처럼 보였다. 색은 새로 만들지 않고 본체 토큰을 가져온다.

   2026-09 승인된 A안 리프트 — Pretendard + JetBrains Mono.
   본문/UI는 Pretendard Variable(셀프호스팅), 숫자/경로/코드는 JetBrains Mono.
   세리프 제목 폰트는 폐지하고 모든 제목을 Pretendard 700 으로 통일했다.
   위에 얹는 체계는 하나뿐이다: 근거 강도.
     측정        -> --measured
     가정/미검증  -> --assumed
     미측정/차단  -> --absent
   이 셋은 화면 어디서든 각각 한 가지만 뜻한다. 그 외의 색은 쓰지 않는다. */
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap");
@font-face {
  font-family: "Pretendard Variable";
  src: url("./PretendardVariable.woff2") format("woff2-variations");
  font-weight: 45 920; font-style: normal; font-display: swap;
}

:root {
  --canvas: oklch(98.5% 0.002 247.839);
  --panel: #ffffff;
  --muted: oklch(96.8% 0.007 247.896);
  --ink: oklch(12.9% 0.042 264.695);
  --body: oklch(27.9% 0.041 260.031);
  --quiet: oklch(55.4% 0.046 257.417);
  --rule: rgba(24, 41, 46, 0.12);
  --action: oklch(51.1% 0.096 186.391);
  --action-hover: oklch(43.7% 0.078 188.216);
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;

  /* 근거 강도. 본체가 이미 쓰는 값이라 배지의 뜻이 화면 사이에서 갈리지 않는다.
     본체 값(amber 3.06:1, coral 3.46:1)은 흰 배경의 작은 글자에서 AA 4.5 를
     넘지 못한다. 그래서 테두리·배경용과 글자용을 나눈다 - 색상은 같고 명도만
     내렸다. 계산해서 확인한 값이다. */
  --measured: oklch(50.8% 0.118 165.612);      /* 5.14 : 1 */
  --assumed: oklch(66.6% 0.179 58.318);        /* 테두리 전용 */
  --absent: #c96d57;                           /* 테두리 전용 */
  --measured-ink: var(--measured);
  --assumed-ink: oklch(56.5% 0.179 58.318);    /* 4.59 : 1 */
  --absent-ink: oklch(57% 0.12 28);            /* 4.53 : 1 */
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--body);
  font: 400 13.5px/1.6 "Pretendard Variable", Pretendard, system-ui, sans-serif;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
}

/* 숫자는 자릿수를 맞춰 비교한다. CI 와 비용을 눈으로 대조하는 화면이다. */
.chip, .meta, output, pre, .apath, .unit, input[type=number] {
  font-variant-numeric: tabular-nums;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 22px; background: var(--panel); border-bottom: 1px solid var(--rule);
}
.brand b { font-weight: 700; font-size: 17px; color: var(--ink); }
.brand span { color: var(--quiet); font-size: 13px; margin-left: 10px; }
.badges { display: flex; gap: 8px; align-items: center; }
.badge {
  font-size: 12px; padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--rule); color: var(--quiet);
}
.badge.link { color: var(--action); text-decoration: none; border-color: color-mix(in oklch, var(--action) 35%, transparent); }
.badge.link:hover { background: color-mix(in oklch, var(--action) 8%, transparent); }

.layout {
  display: grid; grid-template-columns: 264px 6px minmax(0, 1fr) 6px 340px;
  height: calc(100vh - 57px);
}
.side { padding: 20px 16px; overflow-y: auto; background: var(--muted); border-right: 1px solid var(--rule); }
.side.right { border-right: 0; border-left: 1px solid var(--rule); }
.center { padding: 20px 26px 64px; overflow-y: auto; }

/* --- 좌측 탭 -------------------------------------------------------------- */
/* 좌 레일은 264px 에서 시작하고 스플리터로 바뀐다. 한국어 탭 일곱 개의 자연
   폭 합계는 약 360px 이라 그 폭에 한 줄로 담기지 않는다. 예전에는 flex-wrap
   으로 흘려보내서 둘째 줄에 "에이전트" 하나만 남았고, 활성 탭에만 알약 배경을
   달아 나머지 여섯 개가 탭으로 읽히지 않았다. 그래서 두 가지를 고쳤다.
     1. 표시는 우측 탭(.tabs)과 같은 밑줄로 통일한다. 한 화면에서 탭을 가리키는
        방법은 하나면 된다.
     2. 배치는 균등 격자로 깔아 어느 줄이든 레일 폭을 꽉 채우게 한다.
   열 수는 레일 폭에 따라 3 / 4 / 7 로만 바뀐다. 그 사이 값을 허용하면 5+2,
   6+1 처럼 아귀가 맞지 않는 줄이 다시 생긴다. 임계값은 셀 하나가 가장 긴
   라벨("실행 목록" 47px)을 여유 있게 담는 50px 를 기준으로 잡았다. */
.side:not(.right) { container-type: inline-size; }
.sidetabs {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0 2px;
  border-bottom: 1px solid var(--rule); margin-bottom: 12px;
}
.sidetab {
  font: 600 11px "Pretendard Variable", Pretendard, system-ui, sans-serif;
  padding: 6px 2px; margin-bottom: -1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: pointer; color: var(--quiet); background: transparent;
  border: 0; border-bottom: 2px solid transparent; border-radius: 0;
}
.sidetab:hover { color: var(--ink); }
.sidetab.active { color: var(--ink); border-bottom-color: var(--action); }
/* 전역 초점 링은 테두리 바깥 2px 에 네모로 그려진다. 알약 탭에서는 자연스러웠지만
   밑줄 탭에서는 글자를 감싸는 네모가 되어 밑줄과 따로 논다. 네모를 걷고 탭이
   원래 쓰는 언어 - 배경과 밑줄 - 로 초점을 표시한다. 초점 표시를 없애는 것이
   아니다. 키보드로 탭을 옮기는 사람에게는 이 표시가 유일한 단서이므로, 활성
   탭의 2px 밑줄보다 굵은 3px 로 그려 활성 상태와도 구분되게 한다. */
.sidetab:focus-visible {
  outline: none; color: var(--ink);
  background: color-mix(in oklch, var(--action) 12%, transparent);
  box-shadow: inset 0 -3px 0 var(--action);
  border-radius: 4px 4px 0 0;
}
/* 컨테이너 질의의 기준은 .side 의 콘텐츠 폭(레일 폭에서 좌우 여백 32px 을 뺀 값)이다. */
@container (max-width: 205px) { .sidetabs { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* 한 줄에 다 들어가는 폭부터는 격자를 걷는다. 일곱 칸을 균등 분할하면 "모델"
   같은 두 글자 탭까지 넓은 칸을 차지해 글자 사이가 허해진다. 이때는 글자 폭
   그대로 왼쪽에 모으는 편이 낫다 - 줄바꿈 걱정이 없어야 쓸 수 있는 배치다. */
@container (min-width: 356px) {
  .sidetabs { display: flex; flex-wrap: nowrap; gap: 2px; }
  .sidetab { padding: 6px 8px; }
}

/* 모델 탭. 좌 레일 안에서 섹션 사이만 숨을 쉬게 한다. */
.modelstab { padding-top: 4px; display: grid; gap: 6px; }
.modelstab h3 { margin-top: 8px; }
/* 네 좌측 탭(모델/연결/스킬/에이전트)의 카드는 제목과 본문을 세로로 쌓는다.
   .skill 의 전역 flex row 규칙과 섞이면 좁은 레일에서 본문이 제목 옆으로 짜여
   글자가 겹친다 - councilbox/literaturebox 와 같은 이유, 같은 처방. */
.modelstab .skill { display: block; padding: 9px 11px; }

/* 화면이 좁아지면 레일을 접어 세로로 쌓는다. */
@media (max-width: 1100px) {
  .layout { grid-template-columns: 1fr !important; height: auto; }
  .side, .side.right { border: 0; border-bottom: 1px solid var(--rule); }
  .splitter { display: none; }
  /* 손가락으로 누르는 화면에서는 11px 글자에 6px 여백이 너무 얕다. */
  .sidetab { min-height: 34px; }
}

h2 {
  font-weight: 700; font-size: 15px; letter-spacing: -0.01em;
  color: var(--ink); margin: 0 0 6px; display: flex; align-items: baseline; gap: 10px;
  text-wrap: balance;
}
/* 번호를 붙이는 이유는 장식이 아니라 순서가 실제로 강제되기 때문이다.
   생성 전에 검토할 수 없고 검토 전에 승인할 수 없다. */
.stepno {
  flex: 0 0 auto; width: 21px; height: 21px; border-radius: 999px;
  display: inline-grid; place-items: center; align-self: center;
  font-size: 12px; font-weight: 600;
  color: var(--quiet); background: var(--muted); border: 1px solid var(--rule);
}
h3 { margin: 14px 0 6px; font-size: 12px; font-weight: 650; color: var(--ink); }
.meta { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--quiet); }

/* 한 번에 한 단계만 보여준다. 네 단계를 세로로 이어붙이면 아래로 계속 읽어야
   하고, 지금 어디쯤인지도 알기 어렵다. */
.stepnav { display: flex; gap: 6px; margin-bottom: 22px; flex-wrap: wrap; }
.stepbtn {
  display: flex; align-items: center; gap: 8px; padding: 8px 14px 8px 10px;
  font: inherit; font-size: 13px; cursor: pointer; color: var(--quiet);
  background: transparent; border: 1px solid transparent; border-radius: 8px;
}
.stepbtn:hover { color: var(--ink); background: var(--muted); }
.stepbtn.is-active {
  color: var(--ink); font-weight: 600; background: var(--panel);
  border-color: var(--rule); box-shadow: 0 1px 0 var(--action) inset;
}
.stepbtn.is-active .stepno { color: #fff; background: var(--action); border-color: var(--action); }
.stepmeta { font-size: 11.5px; font-weight: 400; color: var(--quiet); }

.steps { list-style: none; margin: 0; padding: 0; max-width: 68ch; }
.step { min-height: 220px; }
.block { margin-bottom: 24px; }
.note { color: var(--quiet); font-size: 13px; margin: 0 0 12px; max-width: 62ch; }
.note.detail { margin-top: 10px; }
.tag { font-size: 11px; color: var(--quiet); }
.unit { color: var(--quiet); font-weight: 400; }

label { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 9px 0; font-size: 13px; }
.fields { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--rule); }
input[type=number], input[type=text], select {
  padding: 5px 8px; background: var(--panel); color: var(--ink);
  border: 1px solid var(--rule); border-radius: 8px; font: inherit;
}
input[type=number] { width: 92px; }
input[type=range] { width: 108px; accent-color: var(--action); }
output { width: 36px; text-align: right; color: var(--quiet); font-size: 12px; }

/* 숫자·경로·코드는 모노로 읽는다. 텍스트 칩(검증됨 등)은 Pretendard 를 유지한다 -
   .chip 은 숫자 칩(비용 시간, 파일 크기)과 텍스트 칩이 같이 쓰는 클래스라 여기에
   넣지 않는다. 모노는 값이 모이는 자리(costvalue)에만 명시한다. */
pre, .apath, .unit, output, input[type=number], .costvalue {
  font-family: var(--mono);
  font-size: 0.95em;
}

:where(button, select, input, a):focus-visible {
  outline: 2px solid var(--action); outline-offset: 2px;
}
button { touch-action: manipulation; }

.primary {
  padding: 8px 16px; font: inherit; font-weight: 600; cursor: pointer;
  color: #fff; background: var(--action); border: 1px solid transparent; border-radius: 8px;
}
.primary:hover:not(:disabled) { background: var(--action-hover); }
.primary:disabled { opacity: .45; cursor: not-allowed; }
.ghost {
  padding: 5px 11px; font: inherit; font-size: 12px; cursor: pointer;
  color: var(--body); background: var(--panel); border: 1px solid var(--rule); border-radius: 8px;
}
.ghost:hover:not(:disabled) { border-color: var(--action); color: var(--action); }
.ghost:disabled { opacity: .5; cursor: not-allowed; }
.cardlink { margin-left: auto; background: none; border: 0; padding: 2px 4px;
  color: var(--action); font: 600 11px "Pretendard Variable", Pretendard, system-ui, sans-serif;
  cursor: pointer; }
.cardlink:hover { text-decoration: underline; }

/* --- 목적 카드 ------------------------------------------------------------
   상태 배지는 여기 한 번만 붙는다. 예전에는 카드, 안내문, 단계 목록, 경고까지
   네 곳에서 같은 사실을 말했다. */
.cards { display: grid; gap: 6px; }
.card {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 11px; font: inherit; font-size: 13px; cursor: pointer;
  color: var(--body); background: var(--panel);
  border: 1px solid var(--rule); border-left: 3px solid var(--rule); border-radius: 8px;
}
.card:hover { border-color: color-mix(in oklch, var(--action) 40%, var(--rule)); }
.card.is-active {
  border-color: var(--action); border-left-color: var(--action);
  background: color-mix(in oklch, var(--action) 6%, var(--panel));
  color: var(--ink); font-weight: 500;
}
/* 사이드 탭 카드 머리. 이름 왼쪽, 상태 칩 오른쪽 — 인라인 흐름에 맡기지 않는다.
   flex:1 1 auto 는 블록 부모에선 죽은 값이지만, 목적 카드(plan.js)의 .card 처럼
   flex 부모에서는 cardmarks 를 오른쪽 끝으로 밀어 내는 살아있는 규칙이다. */
.cardtitle { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; flex: 1 1 auto; min-width: 0; }
.cardtitle .name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 모델 탭의 단계 칩 줄. 긴 칩은 줄을 바꾸되 단어 중간에 끊기지 않게 한다. */
.stagesline { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.stagesline .chip { font-size: 10px; padding: 1px 7px; }
.cardmarks { flex: 0 0 auto; }

/* 근거 강도. 세 값만 쓰고, 각각 한 가지만 뜻한다. */
.mark { font-size: 11px; padding: 1px 7px; border-radius: 999px; border: 1px solid; white-space: nowrap; }
.mark-ok   { color: var(--measured-ink); border-color: color-mix(in oklch, var(--measured) 40%, transparent); }
.mark-warn { color: var(--assumed-ink); border-color: color-mix(in oklch, var(--assumed) 45%, transparent); }
.mark-bad  { color: var(--absent-ink); border-color: color-mix(in oklch, var(--absent) 45%, transparent); }

/* --- 경로(단계) ---------------------------------------------------------- */
.stages { display: grid; gap: 2px; }
.stage {
  display: flex; align-items: center; gap: 9px; padding: 7px 0; font-size: 13px;
  border-bottom: 1px solid var(--rule);
}
.stage:last-child { border-bottom: 0; }
.stage > span:nth-child(2) { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--measured); flex: 0 0 auto; }
.dot.off { background: var(--rule); }
.chip { flex: 0 0 auto; font-size: 10.5px; padding: 2px 8px; color: var(--quiet); }
.stage .chip ~ .chip { margin-left: 8px; }
/* 프로젝트 라운드의 run_id 칩은 버튼이다 - 눌러서 그 실행을 연다. 칩 모양을
   유지하되 누를 수 있음을 말한다. span 칩은 비대칭 표시라 그대로 둔다. */
button.chip {
  cursor: pointer; background: transparent; border: 1px solid transparent;
  font-family: inherit; font-weight: inherit;
}
button.chip:hover { border-color: var(--action); color: var(--action); }
.warnchip { color: var(--assumed-ink); border: 1px solid color-mix(in oklch, var(--assumed) 45%, transparent); border-radius: 999px; padding: 0 7px; white-space: nowrap; }
/* 상단바 실행 상태 칩. 색은 근거 체계를 따른다 - 완료는 측정(measured),
   실패는 차단(absent), 폴링 중단은 미검증(assumed)이다. */
.okchip { color: var(--measured-ink); border: 1px solid color-mix(in oklch, var(--measured) 40%, transparent); border-radius: 999px; padding: 0 7px; white-space: nowrap; }
.badchip { color: var(--absent-ink); border: 1px solid color-mix(in oklch, var(--absent) 45%, transparent); border-radius: 999px; padding: 0 7px; white-space: nowrap; }

/* --- 검토 ---------------------------------------------------------------- */
.status { margin-left: 10px; font-size: 12px; color: var(--quiet); }
.status.bad { color: var(--absent-ink); }
.callout, .warn {
  margin: 10px 0; padding: 9px 12px; font-size: 13px; border-radius: 8px;
  border: 1px solid color-mix(in oklch, var(--assumed) 40%, transparent);
  background: color-mix(in oklch, var(--assumed) 8%, var(--panel));
  color: var(--ink);
}
.callout.coral {
  border-color: color-mix(in oklch, var(--absent) 40%, transparent);
  background: color-mix(in oklch, var(--absent) 8%, var(--panel));
}
.explain { margin: 12px 0; padding: 12px 14px; background: var(--muted); border-radius: 8px; }
.explainhead { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.genbadge { font-size: 11px; color: var(--quiet); }
#explainText { margin: 0; max-width: 62ch; }
.q { margin: 8px 0; padding: 8px 10px; font-size: 13px; background: var(--panel); border: 1px solid var(--rule); border-radius: 8px; }
.qfield { font-weight: 600; margin-right: 6px; }
.qwhy { display: block; margin-top: 4px; font-size: 11.5px; color: var(--quiet); }

.decision { margin: 10px 0; padding: 12px 14px; background: var(--panel); border: 1px solid var(--rule); border-radius: 8px; }
.decision.locked { background: var(--muted); }
.decision .row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.decision .name { font-weight: 600; color: var(--ink); }
.rationale { margin: 8px 0 0; font-size: 13px; color: var(--body); max-width: 62ch; }
.badge.lock, .badge.edited { font-size: 11px; padding: 2px 8px; }
.badge.lock { color: var(--quiet); }
.badge.edited { color: var(--action); border-color: color-mix(in oklch, var(--action) 40%, transparent); }

/* 근거는 결정 안에서 한 번만 보여준다. 예전에는 우측 패널이 같은 목록을
   통째로 다시 그렸다. */
.evidence { margin-top: 10px; }
.evidence summary { cursor: pointer; font-size: 12.5px; color: var(--quiet); }
.evidence summary:hover { color: var(--action); }
.ev { margin: 8px 0; padding: 8px 10px; font-size: 12.5px; background: var(--muted); border-radius: 8px; }
.kind { display: inline-block; margin-right: 7px; padding: 1px 7px; font-size: 11px; border-radius: 999px; border: 1px solid; }
.kind-internal_measurement { color: var(--measured-ink); border-color: color-mix(in oklch, var(--measured) 40%, transparent); }
.kind-literature { color: var(--action); border-color: color-mix(in oklch, var(--action) 40%, transparent); }
.kind-assumption { color: var(--assumed-ink); border-color: color-mix(in oklch, var(--assumed) 45%, transparent); }
.src { display: block; margin-top: 4px; font-size: 11px; color: var(--quiet); word-break: break-all; }

.empty { color: var(--quiet); font-size: 13px; padding: 10px 0; }
pre {
  margin: 10px 0 0; padding: 11px 13px; max-height: 320px; overflow: auto;
  font-size: 11.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-all;
  background: var(--muted); border: 1px solid var(--rule); border-radius: 8px; color: var(--body);
}

/* --- 우측: 실행 / 결과 / 연결 -------------------------------------------- */
.monitorhead { display: flex; gap: 6px; margin-bottom: 10px; }
.monitorhead select { flex: 1; min-width: 0; }
.skill { display: flex; align-items: center; gap: 9px; margin: 6px 0; padding: 9px 11px; font-size: 13px; }
.skill > span:nth-child(2) { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conns { margin-bottom: 10px; }

/* Ditto 의 kv 행 — 라벨은 잔잔히, 값은 모노로. 사이드 탭 카드의 상세에 쓴다. */
.kv { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; font-size: 11.5px; margin: 4px 0 0; }
.kv dt { color: var(--quiet); }
.kv dd { margin: 0; font-family: var(--mono); font-size: 11px; overflow-wrap: anywhere; }
.sdot { width: 7px; height: 7px; border-radius: 999px; display: inline-block; background: var(--quiet); }
.sdot-ok { background: var(--measured); }
.sdot-warn { background: var(--assumed-ink); }
.sdot-bad { background: var(--absent-ink); }

.artifact {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  padding: 6px 9px; margin: 3px 0; font: inherit; font-size: 12px; cursor: pointer;
  color: var(--body); background: var(--panel); border: 1px solid var(--rule); border-radius: 8px;
}
.artifact:hover { border-color: var(--action); color: var(--action); }
/* 긴 경로는 끝이 중요하다. 뒤를 자르면 파일명이 사라진다. */
.apath { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; direction: rtl; text-align: left; }
.preview { margin-top: 12px; }
.previewhead { font-size: 11.5px; color: var(--quiet); margin-bottom: 7px; word-break: break-all; }
.viewer3d { position: relative; width: 100%; height: 300px; border: 1px solid var(--rule); border-radius: 8px; overflow: hidden; }
.artifacttext { max-height: 300px; }

.hidden { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* --- 우측 탭 -------------------------------------------------------------- */
.tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--rule); }
.tab {
  padding: 7px 12px; margin-bottom: -1px; font: inherit; font-size: 13px; cursor: pointer;
  color: var(--quiet); background: transparent; border: 0; border-bottom: 2px solid transparent;
}
.tab:hover { color: var(--ink); }
.tab.is-active { color: var(--ink); font-weight: 600; border-bottom-color: var(--action); }

/* 산출물은 폴더로 묶는다. msa/ 와 tiers/ 아래 파일이 뒤섞이면 찾을 수가 없다. */
.afolder {
  margin: 12px 0 4px; font-size: 11.5px; font-weight: 600; color: var(--quiet);
}
.afolder:first-child { margin-top: 0; }

/* --- 로그인 게이트 --------------------------------------------------------
   워크스페이스를 덮는 대신 아예 대신 선다. 로그인 전에 반쯤 보이는 화면은
   무엇이 고장난 것인지 무엇이 잠긴 것인지 구별되지 않는다. */
.gate {
  position: fixed; inset: 0; z-index: 20; display: grid; place-items: center;
  padding: 24px; background: var(--canvas);
}
.gatecard {
  width: min(380px, 100%); padding: 34px 32px 28px;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 14px;
  box-shadow: 0 1px 2px rgba(24, 41, 46, .04), 0 12px 32px -12px rgba(24, 41, 46, .16);
}
.gatecard h1 {
  margin: 0; font-weight: 700;
  font-size: 30px; letter-spacing: -.01em; color: var(--ink);
}
.gatecard .lede { margin: 8px 0 24px; color: var(--quiet); font-size: 13.5px; text-wrap: pretty; }
.gatecard label { display: block; margin: 0 0 14px; font-size: 13px; color: var(--body); }
.gatecard input {
  display: block; width: 100%; margin-top: 6px; padding: 9px 11px;
  background: var(--canvas); border: 1px solid var(--rule); border-radius: 8px; font: inherit;
}
.gatecard input:focus { background: var(--panel); }
.gatecard .primary { width: 100%; margin-top: 6px; padding: 10px; }
.gateerror { min-height: 18px; margin: 12px 0 0; font-size: 12.5px; color: var(--absent-ink); }

/* --- 타겟 입력 ------------------------------------------------------------ */
.field { display: block; margin: 0 0 14px; font-size: 13px; color: var(--body); }
textarea {
  display: block; width: 100%; margin-top: 6px; padding: 10px 12px; resize: vertical;
  font: 400 12.5px/1.6 var(--mono);
  color: var(--ink); background: var(--canvas);
  border: 1px solid var(--rule); border-radius: 8px;
}
textarea:focus { background: var(--panel); }
.actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* --- 3D 결과를 화면의 초점으로 -------------------------------------------
   밝은 UI 안에서 어두운 뷰포트 하나만 대비를 갖는다. 화려함을 여기 한 곳에
   몰아주고 나머지는 조용히 둔다. */
.viewer3d {
  height: 320px; background: oklch(21% 0.02 250);
  border: 0; border-radius: 8px;
  box-shadow: 0 1px 2px rgba(24, 41, 46, .06), 0 18px 40px -20px rgba(24, 41, 46, .35);
}
.previewhead { font-family: var(--mono); }

/* 상단 바를 조금 더 단단하게 */
.topbar { position: sticky; top: 0; z-index: 5; }
.brand b { letter-spacing: -.01em; }
#whoami { border: 0; color: var(--body); }
button.badge.link { cursor: pointer; background: transparent; font: inherit; font-size: 12px; }

/* --- 분할선 --------------------------------------------------------------
   3D 결과를 볼 때와 계획을 읽을 때 필요한 폭이 다르다. 고정 폭이면 둘 중
   하나는 늘 좁다. */
.splitter {
  position: relative; cursor: col-resize; background: var(--rule);
  transition: background .12s ease;
}
.splitter::after {
  content: ""; position: absolute; inset: 0 -4px;   /* 잡기 쉬운 히트 영역 */
}
.splitter:hover { background: var(--action); }
/* 초점 링을 지우지 않는다. 키보드로 폭을 조절하려면 어디에 있는지 보여야 한다. */
.splitter:focus-visible { background: var(--action); outline: 2px solid var(--action); outline-offset: 1px; }
body.dragging { cursor: col-resize; user-select: none; }
body.dragging iframe, body.dragging canvas { pointer-events: none; }

/* --- 단계 행: 이름 · 모델 · 상태 · 비용 ---------------------------------- */
.sname { flex: 0 0 auto; color: var(--ink); }
.smodel { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
          color: var(--quiet); font-size: 12.5px; }

/* 좌측 설명은 접어 둔다. 펼치기 전에는 두 줄까지만 보인다. */
.side .note > span { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
                     overflow: hidden; }
.side .rationale { white-space: pre-wrap; font-size: 12.5px; }

/* --- 비용 구성 -----------------------------------------------------------
   화면의 일은 "이만큼 쓸 값어치가 있는가" 를 판단하게 하는 것이다. 비용이
   어디로 가는지가 표의 마지막 열이 아니라 형태로 보여야 한다.
   측정하지 않은 구간은 빗금이다 - 0 폭이면 공짜로 보이고, 임의 폭을 주면
   없는 측정을 지어내는 것이 된다. */
.costwrap { margin: 4px 0 22px; }
.costbar { display: flex; gap: 3px; height: 62px; }
.costpart {
  flex: 1 1 0; min-width: 62px; display: flex; flex-direction: column; justify-content: flex-end;
  gap: 2px; padding: 8px 10px; border-radius: 8px; overflow: hidden;
  background: color-mix(in oklch, var(--action) 12%, var(--panel));
  border: 1px solid color-mix(in oklch, var(--action) 22%, transparent);
}
.costpart.is-unknown {
  border-style: dashed; border-color: var(--rule); background: repeating-linear-gradient(
    -45deg, var(--muted) 0 6px, var(--panel) 6px 12px);
}
.costlabel { font-size: 11px; color: var(--quiet); white-space: nowrap;
             overflow: hidden; text-overflow: ellipsis; }
.costvalue { font-size: 13px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.costpart.is-unknown .costvalue { color: var(--quiet); font-weight: 500; }
.costnote { margin: 8px 0 0; font-size: 12px; color: var(--quiet); }

/* --- 구조를 화면 가득 -----------------------------------------------------
   이 화면에서 가장 볼 만한 것이 340px 레일에 갇혀 있을 이유가 없다. 접힘을
   읽으려면 크기가 필요하다. */
.stage-overlay {
  position: fixed; inset: 0; z-index: 30; display: flex; flex-direction: column;
  background: color-mix(in oklch, var(--canvas) 92%, transparent);
  backdrop-filter: blur(6px);
}
.stagehead {
  display: flex; align-items: center; gap: 12px; padding: 14px 20px;
  border-bottom: 1px solid var(--rule); background: var(--panel);
}
.stagetitle {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--mono); font-size: 12.5px; color: var(--quiet);
}
.stagebody { flex: 1; min-height: 0; padding: 20px; }
.viewer3d-lg { height: 100%; border-radius: 8px; }
.previewhead { display: flex; align-items: center; gap: 10px; }
.previewhead > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* --- 타겟 파일 ----------------------------------------------------------- */
.fieldhead { display: flex; align-items: center; gap: 10px; margin-bottom: 2px; }
.fieldhead label { flex: 1; margin: 0; }
.field > .note { margin: 6px 0 0; }

/* --- 계획 대화 -----------------------------------------------------------
   LLM 은 제안만 한다. 적용은 승인 단계를 지나가고 거기서 고정 필드가 거부된다.
   그래서 제안과 거부를 시각적으로 갈라 둔다 - 제안된 것과 반영될 수 있는 것이
   같아 보이면 안 된다. */
.discuss { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--rule); }
.discusshead { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; }
.discusshead h3 { flex: 1; margin: 0; }
.llmsetup { flex: 0 0 auto; }
.llmsetup summary { font-size: 12px; }
.llmsetup label { display: block; margin: 8px 0; font-size: 12.5px; }
.llmsetup input, .llmsetup select { width: 100%; margin-top: 4px; }

.chatlog { max-height: 300px; overflow-y: auto; padding: 4px 0; }
.msg { margin: 10px 0; }
.msg .who { font-size: 11px; font-weight: 600; color: var(--quiet); }
.msg p { margin: 3px 0 0; font-size: 13.5px; white-space: pre-wrap; max-width: 62ch; }
.msg-user p { color: var(--ink); }
.msg .src { margin-top: 3px; }

.proposals { margin: 10px 0; display: grid; gap: 6px; }
.councilbox { display: grid; gap: 8px; margin-top: 6px; }
.councilbox .skill { display: block; padding: 9px 11px; }
.proposal {
  display: flex; align-items: center; gap: 10px; padding: 8px 11px; font-size: 13px;
  background: color-mix(in oklch, var(--action) 6%, var(--panel));
  border: 1px solid color-mix(in oklch, var(--action) 25%, transparent); border-radius: 8px;
}
.proposal .name { font-weight: 600; color: var(--ink); }
.proposal .chip { margin-left: 0; }
.proposal .ghost { margin-left: auto; }
/* 거부된 제안은 적용 버튼이 없다. 회색으로 두면 누를 수 있는 것처럼 보인다. */
.proposal.is-rejected {
  background: var(--muted);
  border-color: color-mix(in oklch, var(--absent) 35%, transparent);
}
.proposal.is-rejected .src { margin-left: auto; margin-top: 0; color: var(--absent-ink); }

.chatform { display: flex; gap: 8px; margin-top: 10px; }
.chatform input { flex: 1; min-width: 0; padding: 8px 11px; }

/* Evidence 탭 참조 검색. 실행과 무관한 참조 결과라 런 전환에 지워지지 않는다. */
.literatureform { display: flex; gap: 8px; margin: 8px 0; }
.literatureform select { flex: 0 0 auto; padding: 8px 8px; }
.literatureform input { flex: 1; min-width: 0; padding: 8px 11px; }
.literaturebox { display: grid; gap: 8px; }
.literaturebox .skill { display: block; padding: 9px 11px; }
.lit-title { color: var(--ink); }

/* --- B안 단일화면 ------------------------------------------------------- */
.plan-section { padding: 14px 16px 20px; border-bottom: 1px solid var(--rule); }
.plan-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.runheader { display: flex; gap: 8px; align-items: center; flex: 1; }
.runlist { display: flex; flex-direction: column; gap: 4px; max-height: 46vh; overflow: auto; }
.runlist .run-item { display: flex; flex-direction: column; gap: 2px; text-align: left;
  background: transparent; border: 1px solid var(--rule); border-radius: 8px;
  padding: 6px 8px; color: inherit; cursor: pointer; }
.runlist .run-item.is-active { border-color: var(--action); }
.run-item .rid { font-weight: 600; font-size: 12px; }
.run-item .rmeta { color: var(--quiet); font-size: 11px; display: flex; gap: 6px; align-items: center; }
.oplinks { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.oplinks a { color: var(--action); font-size: 12px; text-decoration: none; }
.newrun { width: 100%; margin-bottom: 8px; }
.progressbar { height: 6px; border-radius: 6px; background: var(--rule); overflow: hidden; }
.progressbar i { display: block; height: 100%; width: 0; background: var(--action); transition: width .4s; }
.report { border: 1px solid var(--rule); border-radius: 8px; padding: 8px; max-height: 300px; overflow: auto; }
.funnelbox .funnel { display: flex; align-items: flex-end; gap: 6px; height: 90px; margin: 8px 0; }
.funnelbox .funnel i { flex: 1; background: linear-gradient(180deg, var(--action), var(--action-hover)); border-radius: 3px 3px 0 0; }
.hitlist table, .funnelbox table { width: 100%; font-size: 11px; border-collapse: collapse; }
.hitlist th, .hitlist td, .funnelbox th, .funnelbox td { border-bottom: 1px solid var(--rule); padding: 3px 4px; text-align: left; }
.residuestrip { display: flex; flex-direction: column; gap: 4px; }
.residuestrip .resrow { display: flex; flex-wrap: wrap; gap: 1px; align-items: center; }
.residuestrip button { min-width: 18px; font-size: 9px; padding: 1px 2px; border: 1px solid var(--rule);
  background: transparent; color: inherit; cursor: pointer; border-radius: 3px; }
.residuestrip button.is-sel { outline: 2px solid var(--action); }
.residuesel .chip { margin: 2px 2px 0 0; }
/* Evidence 탭: 잔기별 보존도 스트립. 막대 높이가 보존도고, 낮은 위치는 absent 색. */
.conservstrip { display: flex; align-items: flex-end; gap: 1px; height: 44px; padding: 2px 0; }
.conservstrip i { flex: 1 1 0; min-width: 1px; background: var(--measured); opacity: 0.85; border-radius: 1px; }
.conservstrip i.low { background: var(--absent); opacity: 1; }
.evlows { margin: 4px 0 0; }
.evlows .chip { margin: 2px 6px 0 0; }
.evmeta { display: flex; flex-wrap: wrap; gap: 4px 8px; margin: 0 0 8px; }
.evmeta .chip { margin: 0; }
.evidencelinks { display: flex; flex-direction: column; }
.actions .danger { color: var(--absent-ink); border-color: color-mix(in oklch, var(--absent) 45%, transparent); }
