/* done_seat.css v0.2 — DONE Web Seat · 자리·크기·모양은 엔진 고정, 색·글꼴은 Host 가 --ds-* 로 준다
 * 엔진은 색 기본값을 정의하지 않는다 — 아래 var(…, 중립값) 은 Host 가 안 줬을 때 쓰는 회색뿐(HOLD-22 ㈀) */
:root { --ds-h: 74px; --ds-safe: 98px; }
html.done-seat-on body { padding-bottom: var(--ds-safe); }        /* footer 가림 0(98/76) */
.done-seat { position: fixed; left: 0; right: 0; bottom: 0; z-index: 900;
  font-family: var(--ds-font, inherit); color: var(--ds-fg, #eeeeee); background: var(--ds-bg, #151515);
  border-top: 1px solid var(--ds-line, #3a3a3a); }
.ds-bar { display: flex; align-items: center; gap: 18px; height: calc(var(--ds-h) - 1px);   /* 위 테두리 1px 을 높이 안에(209: 53/75) */
  padding: 0 clamp(12px, 3vw, 48px); box-sizing: border-box; }
.ds-dot { width: 34px; height: 34px; flex: none; border-radius: 50%; border: 2px solid var(--ds-accent, #bbbbbb);
  display: flex; align-items: center; justify-content: center; }
.ds-dot i { width: 16px; height: 16px; border-radius: 50%; background: var(--ds-accent-fg, #ffffff); display: block; }
.ds-id { display: flex; flex-direction: column; line-height: 1.25; flex: none; }
.ds-id b { font-weight: 500; font-size: 17px; letter-spacing: .5px; }
.ds-id small { font-size: 11px; color: var(--ds-mute, #9a9a9a); letter-spacing: 1px; text-transform: uppercase; }
.ds-sep { width: 1px; height: 60%; background: var(--ds-line, #3a3a3a); flex: none; }
.ds-line { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.35; }
.ds-say { font-size: 17px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.ds-sub { font-size: 13px; color: var(--ds-mute, #9a9a9a); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-acts { display: flex; gap: 10px; flex-wrap: nowrap; }
.ds-act { font: inherit; font-size: 14px; color: var(--ds-fg, #eeeeee); background: transparent; text-decoration: none;
  border: 1px solid var(--ds-line, #3a3a3a); border-radius: 22px; padding: 8px 18px; white-space: nowrap; cursor: pointer; }
.ds-act:hover, .ds-act:focus-visible { border-color: var(--ds-accent, #bbbbbb); outline: none; }
.ds-primary { border-color: var(--ds-accent, #bbbbbb); background: var(--ds-accent-bg, #2a2a2a); color: var(--ds-accent-fg, #ffffff); }
.ds-tg { flex: none; width: 36px; height: 36px; border: 0; background: transparent; color: var(--ds-fg, #eeeeee); cursor: pointer; font-size: 18px; }
.ds-tg::before { content: '\2303'; }                       /* ⌃ */
.ds-open .ds-tg::before { content: '\2304'; }              /* ⌄ */
.ds-tg:focus-visible { outline: 2px solid var(--ds-accent, #bbbbbb); border-radius: 6px; }

/* 얇은 판: 화면 높이 < 900 · 폰 */
.ds-compact .ds-bar { gap: 12px; }
.ds-compact .ds-dot { width: 26px; height: 26px; }
.ds-compact .ds-dot i { width: 12px; height: 12px; }
.ds-compact .ds-id b { font-size: 15px; }
.ds-compact .ds-say { font-size: 15px; }
.ds-compact .ds-sub { display: none; }
.ds-compact .ds-act { padding: 5px 14px; font-size: 13px; }
.ds-phone .ds-sep, .ds-phone .ds-acts-bar { display: none; }
.ds-phone .ds-id small { display: none; }

/* 펼침: 아래에서 위로 · 60vh·520 상한 · 폰 72vh · 입력칸 맨 아래 */
.ds-panel { display: flex; flex-direction: column; max-height: min(520px, 60vh);
  border-bottom: 1px solid var(--ds-line, #3a3a3a); padding: 14px clamp(12px, 3vw, 48px) 12px; box-sizing: border-box; }
.ds-panel[hidden] { display: none; }
.ds-phone .ds-panel { max-height: 72vh; }
.ds-msgs { flex: 1; overflow-y: auto; min-height: 60px; font-size: 14px; line-height: 1.6; }
.ds-msgs p { margin: 0 0 8px; max-width: 70ch; }
.ds-m-d { color: var(--ds-fg, #eeeeee); }
.ds-m-u { color: var(--ds-accent-fg, #ffffff); text-align: right; margin-left: auto !important; }
.ds-acts-all { flex-wrap: wrap; margin: 10px 0; }
.ds-compose { display: flex; gap: 8px; }
.ds-compose[hidden] { display: none; }
.ds-compose input { flex: 1; min-width: 0; font: inherit; font-size: 15px; color: var(--ds-fg, #eeeeee); background: transparent;
  border: 1px solid var(--ds-line, #3a3a3a); border-radius: 10px; padding: 10px 12px; }
.ds-compose input:focus { outline: none; border-color: var(--ds-accent, #bbbbbb); }
.ds-compose button { font: inherit; font-size: 14px; border: 1px solid var(--ds-accent, #bbbbbb); background: var(--ds-accent-bg, #2a2a2a);
  color: var(--ds-accent-fg, #ffffff); border-radius: 10px; padding: 0 16px; cursor: pointer; }

/* ⭐TX-INFRA-201(승인 0025) — 입력창 바로 아래 개인정보 안내 한 줄. flex 형제(ds-compose 뒤)라
   ds-msgs(flex:1) 쪽이 줄어 공간을 내주고, 입력창·전송 단추는 밀려나지 않는다(Ryan 0007 §6). */
.ds-privacy-note { margin: 6px 0 0; font-size: 12px; line-height: 1.55; color: var(--ds-mute, #9a9a9a); flex-shrink: 0; }
.ds-privacy-note a { color: inherit; text-decoration: underline; }

/* ⭐TX-ACROPOLIS-1333 F3(TX-1398 리베이스) — 펼친 패널 맨 아래 작은 글씨(기억 지우기).
   바 단계엔 안 보인다(ds-panel 안이라 panel[hidden] 과 함께 접힘 · 새 분기 0). */
.ds-panel-foot { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--ds-line, #3a3a3a); }
.ds-panel-foot:empty { margin: 0; padding: 0; border: none; }
.ds-forget-link { font: inherit; font-size: 12px; color: var(--ds-mute, #9a9a9a); background: transparent;
  border: none; padding: 0; cursor: pointer; text-decoration: underline; }
.ds-forget-link:hover, .ds-forget-link:focus-visible { color: var(--ds-fg, #eeeeee); }
.ds-forget-confirm p { font-size: 12px; color: var(--ds-mute, #9a9a9a); margin: 0 0 6px; }
.ds-forget-confirm { display: flex; flex-direction: column; }
.ds-forget-yes, .ds-forget-no { font: inherit; font-size: 12px; border: 1px solid var(--ds-line, #3a3a3a); background: transparent;
  color: var(--ds-fg, #eeeeee); border-radius: 8px; padding: 4px 12px; cursor: pointer; margin-right: 8px; display: inline-block; width: fit-content; }
.ds-forget-yes { border-color: var(--ds-accent, #bbbbbb); }
.ds-forget-done { font-size: 12px; color: var(--ds-mute, #9a9a9a); margin: 0; }

/* 맥동 두 상태 — 번쩍임 금지 · 빠르기는 시안에서 의장이 고른다(기본 1.2s / .5s) */
.ds-fade { animation: dsfade .3s ease-out; }
@keyframes dsfade { from { opacity: .2 } to { opacity: 1 } }
@keyframes dsbeat { 0%,100% { transform: scale(1); opacity: 1 } 50% { transform: scale(1.3); opacity: .55 } }
@media (prefers-reduced-motion: no-preference) {
  .done-seat[data-state="waiting"] .ds-dot i { animation: dsbeat var(--ds-wait, 1.2s) ease-in-out infinite; }
  .done-seat[data-state="thinking"] .ds-dot i { animation: dsbeat var(--ds-think, .5s) ease-in-out infinite; }
}
@media print { .done-seat { display: none; } html.done-seat-on body { padding-bottom: 0; } }

/* ⭐TX-ACROPOLIS-1329 H3 + TX-ACROPOLIS-1332 P1⑶(TX-1398 리베이스) — 폰 바('hidden' 단계)
   환대 닫기 단추. 꼴은 Ryan REV-07(REV-RYAN-20261011-DOOR-GREET-SCREEN-07)로 확정됐다. 기존 규칙 0 변경(추가뿐). */
.ds-welcome-bar-close {
  position: absolute; right: 44px; top: 50%; transform: translateY(-50%);
  width: 28px; height: 28px; line-height: 26px; text-align: center;
  border: none; border-radius: 50%; background: rgba(0,0,0,.18); color: inherit;
  font-size: 16px; cursor: pointer; z-index: 2;
}
.ds-welcome-bar-close:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* ===================================================================
   TX-RSI-217/218(Ryan 48) 재생성 — 문자열-인식 토크나이저로 다시 추출.
   TX-RSI-212 의 정규식 추출기가 ensureSymbolCSS() 머리 주석 속 인용구
   '상태별 표정이 무한반복 blink/breathe 에 가려 안 보이는' 를 문자열로 오인해
   앞에 끼워 넣었던 손상을 고쳤다(extraction_proof.json 로 오염 0 증명).
   =================================================================== */

/* ===== marker: TX-RSI-214 B — done_seat.css 가 실제로 로드됐는지 엔진이
   런타임에 재는 자리(getComputedStyle 로 읽는다, CSP 와 무관) ===== */
.done-seat{--ds-css-loaded:1}

/* ===== symbol — 출처: Ryan Canon v1.1 원문(sha cc052f97d42e, 바이트 그대로) +
   TX-RSI-150(크기 34/26px) + TX-RSI-204(symState 고침은 JS 쪽, CSS 영향 0) +
   TX-RSI-209(error 상태점 r:9px 가시성 덧칠). 원래 done_seat.js::ensureSymbolCSS()
   안에 있었다(블레이드92 기준 482~497행). ===== */
/* ITGI DONE Visual Canon v1.1
   Shared visual asset for every ITGI project that mounts DONE.
   Project code may control only: data-state, placement, size, visibility.
   Do not redraw per project.
*/

/* ⭐TX-RSI-226 — v1.3(Ryan-60) 로 전환. Canon 루트가 자기 class="done-visual-canon" ·
   id="done-visual-canon" 를 직접 갖고 있어(v1.1/1.2 의 "done-symbol"/엔진이 더하는 id="ds-dot"
   방식과 다름) 엔진 쪽 selector 베이스를 Ryan 이 준 그 이름으로 맞춘다 — Canon 파일 바이트는
   완전히 그대로(review §1 역산 검증). 엔진은 바 아이콘 공용 치수(.ds-dot 10~33행)를 계속 쓰기
   위해 class 토큰 "ds-dot" 하나만 "추가"로 더 건다(engine_build §1 참조, 이것도 Canon 파일이
   아니라 메모리 상 삽입 문자열에서만 일어나는 엔진측 처리). 상태별 class 도 v1.3 에서
   done-expr-*→done-state-* 로 바뀌었다(실측, Ryan-60 문서엔 이 이름변경이 적혀 있지 않음 —
   review §2 에 관찰로 적어 둔다). */
.done-visual-canon{
  width:1em;
  height:1em;
  display:inline-block;
  overflow:visible;
  vertical-align:middle;
}

.done-visual-canon .done-outer-ring{
  transform-box:fill-box;
  transform-origin:center;
}

.done-visual-canon .done-face-disc,
.done-visual-canon .done-expression{
  transform-box:fill-box;
  transform-origin:center;
}

/* done-face-body 래퍼 — 미세 호흡은 이 한 자리로만(겹호흡 방지, TX-RSI-221 과 같은 방침). */
.done-visual-canon .done-face-body{
  transform-box:fill-box;
  transform-origin:center;
}

/* ⭐TX-RSI-226 — 시선 이동 v1.3 contract(Ryan-60). ⛔중대 발견(조건부가동⑥, review 참조):
   원래 여기 있던 `.done-visual-canon[data-gaze="right"] .done-gaze{transform:translate(4.8,0)}`
   류 규칙은 **단위 없는 숫자가 CSS translate() 의 <length> 로 무효**라 파서가 선언 자체를
   버린다(CSSOM 에서 style.transform 이 빈 문자열로 실측 확인) — **v1.2(지금 운영, TX-1449
   반영본)도 같은 결함으로 실제 이동이 0 이었다.** 고침: CSS 규칙을 버리고 done_seat.js 의
   `applyGazeTransform()` 이 SVG transform **속성**(setAttribute)으로 직접 건다 — 속성형
   transform 은 SVG 사용자좌표(Ryan 의 "u")를 그대로 받아 유효하고, fill-box 기준박스 계산도
   필요 없다(순수 translate 라 origin 영향도 없음). 여기 남는 것은 transition 뿐 — 속성으로
   건 transform 도 computed "transform" 값에 그대로 올라와 전환이 걸린다(실측 확인). return
   easing 은 Ryan 권고범위(0.25~0.40s) 안의 고정값 .30s. */
.done-visual-canon .done-gaze,
.done-visual-canon .done-face-follow{
  transition:transform .30s ease;
}

.done-visual-canon .done-expression,
.done-visual-canon .done-thought-dots{
  display:none;
}

.done-visual-canon[data-state="idle"] .done-state-idle,
.done-visual-canon[data-state="greeting"] .done-state-greeting,
.done-visual-canon[data-state="listening"] .done-state-listening,
.done-visual-canon[data-state="thinking"] .done-state-thinking,
.done-visual-canon[data-state="responding"] .done-state-responding,
.done-visual-canon[data-state="complete"] .done-state-complete,
.done-visual-canon[data-state="attention"] .done-state-attention,
.done-visual-canon[data-state="error"] .done-state-error{
  display:block;
}

.done-visual-canon[data-state="thinking"] .done-thought-dots{
  display:block;
}

/* ⭐TX-RSI-226 — v1.3 의 error-dot 은 더 이상 done-state-error 안에 중첩되지 않고(실측,
   Ryan-60 미기재) 루트 바로 아래 형제 요소라 자기 display 를 직접 상태로 가려야 한다(안 가리면
   항상 보임 — 구조상 필요한 최소 추가, 크기·색은 Ryan 값 그대로 0 변경). */
.done-visual-canon .done-error-dot{ display:none; }
.done-visual-canon[data-state="error"] .done-error-dot{ display:block; }

/* Base living motion: outer ring stays fixed — done-face-body 한 자리에만(겹호흡 방지). */
.done-visual-canon .done-face-body{
  animation:done-breathe-v11 4.2s ease-in-out infinite;
}

.done-visual-canon[data-state="idle"] .done-eye,
.done-visual-canon[data-state="responding"] .done-eye{
  transform-box:fill-box;
  transform-origin:center;
  animation:done-blink-v11 5.4s ease-in-out infinite;
}

/* One-time greeting when greeting state is entered. */
.done-visual-canon[data-state="greeting"] .done-state-greeting{
  animation:done-greeting-v11 900ms ease-out 1;
}

/* Listening: alert but not exaggerated. */
.done-visual-canon[data-state="listening"] .done-state-listening{
  animation:done-listen-v11 1.8s ease-in-out infinite;
}

/* ⭐TX-RSI-226 — Thinking: v1.3 에 .done-pupil 요소가 없다(실측 — 눈이 원형→타원 눈으로 바뀌며
   동공을 뺐다, Ryan-60 미기재 관찰). 눈-드리프트 애니메이션은 대상이 없어 자연히 무동작(제거
   아니라 "더 걸 자리가 없음" — review §2 에 기록). 세 점은 이제 개별 class 가 없어(실측) 순서
   기반(nth-child)으로만 지연을 건다. */
.done-visual-canon[data-state="thinking"] .done-thought-dots circle{
  transform-box:fill-box;
  transform-origin:center;
  animation:done-think-dot-v11 1.5s ease-in-out infinite;
}
.done-visual-canon[data-state="thinking"] .done-thought-dots circle:nth-child(2){animation-delay:150ms}
.done-visual-canon[data-state="thinking"] .done-thought-dots circle:nth-child(3){animation-delay:300ms}

/* Responding: small mouth movement only. ⭐TX-RSI-226 — v1.3 class 이름 done-mouth-talk→
   done-mouth-speaking(실측, Ryan-60 미기재). */
.done-visual-canon[data-state="responding"] .done-mouth-speaking{
  transform-box:fill-box;
  transform-origin:center;
  animation:done-speak-v11 680ms ease-in-out infinite;
}

/* Complete: smile lands once, then remains calm. */
.done-visual-canon[data-state="complete"] .done-state-complete{
  animation:done-complete-v11 1s ease-out 1;
}

/* Attention: subtle apologetic dip. */
.done-visual-canon[data-state="attention"] .done-state-attention{
  animation:done-attention-v11 1.4s ease-in-out infinite;
}

/* Error: expression stays restrained; only orange error dot carries color. ⭐TX-RSI-226 —
   v1.3 class 이름 done-status-dot→done-error-dot(실측, Ryan-60 미기재). 크기·색은 Ryan 값
   그대로(TX-RSI-209 때처럼 다시 키우는 보정은 이번엔 안 함 — 이 TX 범위는 시선이고, 작아
   보이면 그건 Ryan 판정 청구 자리). */
.done-visual-canon[data-state="error"] .done-error-dot{
  transform-box:fill-box;
  transform-origin:center;
  animation:done-error-dot-v11 1.2s ease-in-out infinite;
}

@keyframes done-breathe-v11{
  0%,100%{transform:scale(1)}
  50%{transform:scale(1.015)}
}

@keyframes done-blink-v11{
  0%,46%,50%,100%{transform:scaleY(1)}
  48%{transform:scaleY(.16)}
}

@keyframes done-greeting-v11{
  0%{transform:scale(.97) rotate(-1deg)}
  55%{transform:scale(1.02) rotate(1deg)}
  100%{transform:scale(1) rotate(0)}
}

@keyframes done-listen-v11{
  0%,100%{transform:scale(1)}
  50%{transform:scale(1.018)}
}

@keyframes done-think-look-v11{
  0%,100%{transform:translate(0,0)}
  50%{transform:translate(1.4px,-1.1px)}
}

@keyframes done-think-dot-v11{
  0%,100%{opacity:.28;transform:scale(.84)}
  50%{opacity:1;transform:scale(1)}
}

@keyframes done-speak-v11{
  0%,100%{transform:scaleY(.76) scaleX(.94)}
  50%{transform:scaleY(1.12) scaleX(1.04)}
}

@keyframes done-complete-v11{
  0%{transform:scale(.98)}
  55%{transform:scale(1.02)}
  100%{transform:scale(1)}
}

@keyframes done-attention-v11{
  0%,100%{transform:translateY(0)}
  50%{transform:translateY(1px)}
}

@keyframes done-error-dot-v11{
  0%,100%{transform:scale(1);opacity:.82}
  50%{transform:scale(1.12);opacity:1}
}

/* Static fallback for users who request reduced motion. */
@media (prefers-reduced-motion:reduce){
  .done-visual-canon *,
  .done-visual-canon{
    animation:none!important;
    transition:none!important;
  }
}
/* ⭐TX-RSI-226 — id/class 를 v1.3 이름으로 맞춤(#ds-dot→#done-visual-canon · .done-symbol→
   .done-visual-canon, TX-RSI-150 치수규칙). TX-RSI-209 의 .done-status-dot r:9px 보정줄은 그
   class 가 v1.3 에 없어 뺐다 — v1.3 네이티브 error-dot(r=4.2, #ff8a3d)을 그대로 쓴다(이번 TX
   범위는 시선이라 별도 확대 보정은 안 함, 작아 보이면 Ryan 판정 청구 자리로 review 에 적음). */
#done-visual-canon.done-visual-canon{width:34px;height:34px}.ds-compact #done-visual-canon.done-visual-canon{width:26px;height:26px}.ds-entry-emph{transition:box-shadow .4s ease}.ds-entry-emph.ds-entry-emph-on{box-shadow:0 0 0 2px var(--ds-accent,#bbbbbb)}

/* ===== welcome — 출처: done_seat.js::ensureWelcomeCSS()(블레이드92 기준
   508~536행). TX-RSI-1301~1304 환대(welcome) 기능의 자리·크기 CSS. ===== */
.ds-welcome-mode .ds-panel{position:fixed;right:28px;left:auto;top:auto;bottom:calc(var(--ds-h) + 16px);width:380px;max-width:calc(100vw - 32px);max-height:min(430px,calc(100dvh - 160px));border:1px solid var(--line, var(--ds-line,#3a3a3a));border-radius:var(--radius,4px);background:var(--bg, var(--ds-bg,#151515));box-shadow:0 8px 28px rgba(0,0,0,.35);z-index:901;}.done-seat.ds-phone.ds-welcome-mode .ds-panel{right:16px;left:16px;width:auto;bottom:calc(var(--ds-h) + 12px);}.ds-welcome-mode .ds-tg{min-width:44px;min-height:44px;}.ds-welcome-in{animation:dswelcomein 160ms ease-out both;}@keyframes dswelcomein{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion: reduce){.ds-welcome-in{animation:none}}.ds-welcome-btns{display:flex;flex-direction:column;gap:8px;margin:10px 0 4px;}.ds-welcome-btn{min-height:44px;width:100%;text-align:left;}.ds-welcome-card{position:fixed;right:16px;left:16px;bottom:calc(var(--ds-h) + 12px);z-index:901;border:1px solid var(--line, var(--ds-line,#3a3a3a));border-radius:var(--radius,4px);background:var(--bg, var(--ds-bg,#151515));color:var(--fg, var(--ds-fg,#eeeeee));box-shadow:0 8px 28px rgba(0,0,0,.35);padding:12px;box-sizing:border-box;}.ds-welcome-card .ds-welcome-card-line{font-size:15px;line-height:1.4;margin:0 0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.ds-welcome-card .ds-welcome-btns{margin:0;}.ds-welcome-dock{position:fixed;right:16px;left:16px;bottom:calc(var(--ds-h) + 12px);height:44px;z-index:901;display:flex;align-items:center;padding:0 14px;box-sizing:border-box;cursor:pointer;border:1px solid var(--line, var(--ds-line,#3a3a3a));border-radius:var(--radius,4px);background:var(--bg, var(--ds-bg,#151515));color:var(--fg, var(--ds-fg,#eeeeee));box-shadow:0 8px 28px rgba(0,0,0,.35);font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
