/* 터치 키보드·자체 입력란 스타일 — docs/KEYBOARD.md §7~§9.  style 속성 없이 클래스·데이터 속성·CSS 변수만 쓴다(CSP).
   모든 색·크기는 --kb-* 토큰. 어두운 화면: prefers-color-scheme + [data-theme]. 고대비: .kb-hc */

.kb-host, .kbf {
  /* 라이트 */
  --kb-accent: #1d5fd1;
  --kb-accent-ink: #ffffff;
  --kb-accent-soft: #e3edfd;
  --kb-sheet: #e8ecf2;
  --kb-sheet-edge: rgba(15, 23, 42, .10);
  --kb-key: #ffffff;
  --kb-key-ink: #0f172a;
  --kb-key-edge: rgba(15, 23, 42, .08);
  --kb-key-shadow: rgba(15, 23, 42, .16);
  --kb-key-down: #cfd8e6;
  --kb-fn: #cbd3df;
  --kb-fn-ink: #1e293b;
  --kb-cons: #f4f7fb;
  --kb-vowel: #d9e8ff;
  --kb-chip: #ffffff;
  --kb-mute: #5b6677;
  --kb-field: #ffffff;
  --kb-field-edge: #c3ccd9;
  --kb-field-ink: #0f172a;
  --kb-pre-bg: rgba(29, 95, 209, .12);
  --kb-danger: #c62828;
  --kb-ring: #1d5fd1;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .kb-host, :root:not([data-theme="light"]) .kbf {
    --kb-accent: #6aa4ff; --kb-accent-ink: #08111f; --kb-accent-soft: #1b2b49;
    --kb-sheet: #10151d; --kb-sheet-edge: rgba(255, 255, 255, .08);
    --kb-key: #232c3a; --kb-key-ink: #f1f5f9; --kb-key-edge: rgba(255, 255, 255, .06); --kb-key-shadow: rgba(0, 0, 0, .55);
    --kb-key-down: #3a465a; --kb-fn: #353f50; --kb-fn-ink: #e2e8f0; --kb-cons: #1d2531; --kb-vowel: #263a5c;
    --kb-chip: #232c3a; --kb-mute: #9aa6b8;
    --kb-field: #171d27; --kb-field-edge: #3a4558; --kb-field-ink: #f1f5f9; --kb-pre-bg: rgba(106, 164, 255, .20);
    --kb-danger: #ff8a80; --kb-ring: #6aa4ff;
  }
}
:root[data-theme="dark"] .kb-host, :root[data-theme="dark"] .kbf {
  --kb-accent: #6aa4ff; --kb-accent-ink: #08111f; --kb-accent-soft: #1b2b49;
  --kb-sheet: #10151d; --kb-sheet-edge: rgba(255, 255, 255, .08);
  --kb-key: #232c3a; --kb-key-ink: #f1f5f9; --kb-key-edge: rgba(255, 255, 255, .06); --kb-key-shadow: rgba(0, 0, 0, .55);
  --kb-key-down: #3a465a; --kb-fn: #353f50; --kb-fn-ink: #e2e8f0; --kb-cons: #1d2531; --kb-vowel: #263a5c;
  --kb-chip: #232c3a; --kb-mute: #9aa6b8;
  --kb-field: #171d27; --kb-field-edge: #3a4558; --kb-field-ink: #f1f5f9; --kb-pre-bg: rgba(106, 164, 255, .20);
  --kb-danger: #ff8a80; --kb-ring: #6aa4ff;
}

/* ---------- 자리·크기 ---------- */
.kb-host { width: 100%; display: flex; justify-content: center; z-index: 50; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; touch-action: manipulation; --kb-maxw: 100%; }
.kb-host.kb-dock { position: fixed; left: 0; right: 0; bottom: 0; }
.kb-hand-left, .kb-hand-right { --kb-maxw: 85%; }
@media (orientation: landscape) {
  .kb-host { --kb-maxw: calc(1280px * var(--ui)); }
  .kb-hand-left, .kb-hand-right { --kb-maxw: calc(960px * var(--ui)); }
}
.kb-hand-left { justify-content: flex-start; }
.kb-hand-right { justify-content: flex-end; }
.kb-wrap { width: min(100%, var(--kb-maxw)); container-type: inline-size; }

.kb {
  --kb-key-px: calc(96px * var(--ui)); --kb-cols: 10; --kb-scale: 1; --kb-fs: 1;
  --kb-gap: max(8px * var(--ui), calc(var(--kb-unit) * .1));
  --kb-fit: calc((100vw - 48px * var(--ui)) / (1.1 * var(--kb-cols) - .1));   /* 좁은 화면(폰)에서는 한 줄이 화면 폭에 딱 맞게 */
  --kb-unit: clamp(min(88px * var(--ui), var(--kb-fit)), min(calc(var(--kb-key-px) * var(--kb-scale)), var(--kb-fit)), 400px * var(--ui));
  --kb-h: max(46px, calc(var(--kb-unit) * 1.08));
  --kb-font: calc(var(--kb-unit) * .42 * var(--kb-fs));
  box-sizing: border-box; width: 100%; padding: calc(12px * var(--ui)) calc(24px * var(--ui)) calc(28px * var(--ui)); background: var(--kb-sheet);
  border-radius: calc(28px * var(--ui)) calc(28px * var(--ui)) 0 0; box-shadow: 0 -1px 0 var(--kb-sheet-edge), 0 calc(-18px * var(--ui)) calc(40px * var(--ui)) rgba(15, 23, 42, .14);
  font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", system-ui, sans-serif;
  animation: kb-up 180ms cubic-bezier(.2, .8, .2, 1) both;
}
@supports (width: 1cqw) {
  .kb { --kb-fit: calc((100cqw - 48px * var(--ui)) / (1.1 * var(--kb-cols) - .1)); }
}
@keyframes kb-up { from { transform: translateY(calc(24px * var(--ui))); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes kb-pop { from { transform: scale(.4); opacity: .5; } to { transform: scale(1); opacity: 0; } }
@keyframes kbf-shake { 0%, 100% { transform: none; } 20% { transform: translateX(calc(-8px * var(--ui))); } 40% { transform: translateX(calc(8px * var(--ui))); } 60% { transform: translateX(calc(-5px * var(--ui))); } 80% { transform: translateX(calc(5px * var(--ui))); } }
@keyframes kbf-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

.kb-k88 { --kb-key-px: calc(88px * var(--ui)); }
.kb-k92 { --kb-key-px: calc(92px * var(--ui)); }
.kb-k96 { --kb-key-px: calc(96px * var(--ui)); }
.kb-k100 { --kb-key-px: calc(100px * var(--ui)); }
.kb-k104 { --kb-key-px: calc(104px * var(--ui)); }
.kb-k108 { --kb-key-px: calc(108px * var(--ui)); }
.kb-k112 { --kb-key-px: calc(112px * var(--ui)); }
.kb-k116 { --kb-key-px: calc(116px * var(--ui)); }
.kb-k120 { --kb-key-px: calc(120px * var(--ui)); }
.kb-k124 { --kb-key-px: calc(124px * var(--ui)); }
.kb-k128 { --kb-key-px: calc(128px * var(--ui)); }
.kb-k132 { --kb-key-px: calc(132px * var(--ui)); }
.kb-k136 { --kb-key-px: calc(136px * var(--ui)); }
.kb-cols-3 { --kb-cols: 3; }
.kb-cols-4 { --kb-cols: 4; }
.kb-cols-5 { --kb-cols: 5; }
.kb-cols-6 { --kb-cols: 6; }
.kb-cols-7 { --kb-cols: 7; }
.kb-cols-8 { --kb-cols: 8; }
.kb-cols-9 { --kb-cols: 9; }
.kb-cols-10 { --kb-cols: 10; }
.kb-cols-11 { --kb-cols: 11; }
.kb-cols-12 { --kb-cols: 12; }
.kb-scale-1 { --kb-scale: 1; } .kb-scale-1_25 { --kb-scale: 1.25; } .kb-scale-1_5 { --kb-scale: 1.5; }
.kb-lt { --kb-fs: 1.35; }
/* 키 글자 배율(kb.label_scale): 5% 단위. 큰 글씨 클래스(.kb-lt = 1.35배)와 곱한다 */
.kb-ls-80 { --kb-fs: 0.8; } .kb-lt.kb-ls-80 { --kb-fs: 1.08; }
.kb-ls-85 { --kb-fs: 0.85; } .kb-lt.kb-ls-85 { --kb-fs: 1.1475; }
.kb-ls-90 { --kb-fs: 0.9; } .kb-lt.kb-ls-90 { --kb-fs: 1.215; }
.kb-ls-95 { --kb-fs: 0.95; } .kb-lt.kb-ls-95 { --kb-fs: 1.2825; }
.kb-ls-105 { --kb-fs: 1.05; } .kb-lt.kb-ls-105 { --kb-fs: 1.4175; }
.kb-ls-110 { --kb-fs: 1.1; } .kb-lt.kb-ls-110 { --kb-fs: 1.485; }
.kb-ls-115 { --kb-fs: 1.15; } .kb-lt.kb-ls-115 { --kb-fs: 1.5525; }
.kb-ls-120 { --kb-fs: 1.2; } .kb-lt.kb-ls-120 { --kb-fs: 1.62; }
.kb-ls-125 { --kb-fs: 1.25; } .kb-lt.kb-ls-125 { --kb-fs: 1.6875; }
.kb-ls-130 { --kb-fs: 1.3; } .kb-lt.kb-ls-130 { --kb-fs: 1.755; }
.kb-ls-135 { --kb-fs: 1.35; } .kb-lt.kb-ls-135 { --kb-fs: 1.8225; }
.kb-ls-140 { --kb-fs: 1.4; } .kb-lt.kb-ls-140 { --kb-fs: 1.89; }
.kb-ls-145 { --kb-fs: 1.45; } .kb-lt.kb-ls-145 { --kb-fs: 1.9575; }
.kb-ls-150 { --kb-fs: 1.5; } .kb-lt.kb-ls-150 { --kb-fs: 2.025; }
.kb-ls-155 { --kb-fs: 1.55; } .kb-lt.kb-ls-155 { --kb-fs: 2.0925; }
.kb-ls-160 { --kb-fs: 1.6; } .kb-lt.kb-ls-160 { --kb-fs: 2.16; }

/* ---------- 줄과 키 ---------- */
/* 키 너비 배수 */
.kb-w-0_5 { --w: 0.5; }
.kb-w-1 { --w: 1; }
.kb-w-1_5 { --w: 1.5; }
.kb-w-2 { --w: 2; }
.kb-w-2_5 { --w: 2.5; }
.kb-w-3 { --w: 3; }
.kb-w-3_5 { --w: 3.5; }
.kb-w-4 { --w: 4; }
.kb-w-4_5 { --w: 4.5; }
.kb-w-5 { --w: 5; }
.kb-w-5_5 { --w: 5.5; }
.kb-w-6 { --w: 6; }


.kb-body { display: flex; flex-direction: column; gap: var(--kb-gap); align-items: center; }
.kb-row { display: flex; gap: var(--kb-gap); justify-content: center; }
.kb-key {
  position: relative; box-sizing: border-box; flex: none; display: flex; align-items: center; justify-content: center;
  width: calc(var(--kb-unit) * var(--w, 1) + var(--kb-gap) * (var(--w, 1) - 1)); height: var(--kb-h); min-height: calc(88px * var(--ui)); padding: 0; margin: 0;
  border: 0; border-radius: calc(16px * var(--ui)); background: var(--kb-key); color: var(--kb-key-ink);
  box-shadow: 0 2px 0 var(--kb-key-shadow), 0 0 0 1px var(--kb-key-edge);
  font: inherit; font-weight: 600; font-size: max(14px, var(--kb-font)); line-height: 1; letter-spacing: -.01em; cursor: pointer;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation; outline: none; overflow: visible;
  transition: transform 120ms cubic-bezier(.3, 1.6, .5, 1), background-color 120ms;
}
.kb-gapk { background: transparent; box-shadow: none; pointer-events: none; visibility: hidden; }
.kb-key.kb-down { transform: scale(.94); background: var(--kb-key-down); transition-duration: 60ms; transition-timing-function: ease-out; }
.kb-lab { pointer-events: none; }
.kb-sub { position: absolute; top: calc(8px * var(--ui)); right: calc(12px * var(--ui)); font-size: max(14px, calc(var(--kb-font) * .5)); font-weight: 600; color: var(--kb-mute); pointer-events: none; }

.kb-t-backspace, .kb-t-shift, .kb-t-mode, .kb-t-left, .kb-t-right, .kb-t-space, .kb-t-clear { background: var(--kb-fn); color: var(--kb-fn-ink); }
.kb-t-backspace, .kb-t-shift, .kb-t-left, .kb-t-right { font-size: max(14px, calc(var(--kb-font) * .9)); }
.kb-t-mode, .kb-t-space, .kb-t-clear, .kb-t-enter { font-size: max(14px, calc(var(--kb-font) * .62)); }
.kb-t-space { background: var(--kb-key); color: var(--kb-mute); font-weight: 500; }
.kb-t-enter { background: var(--kb-accent); color: var(--kb-accent-ink); box-shadow: 0 2px 0 rgba(0, 0, 0, .22); }
.kb-t-enter.kb-down { background: var(--kb-accent); filter: brightness(.86); }
.kb-t-backspace.kb-down, .kb-t-shift.kb-down, .kb-t-mode.kb-down, .kb-t-left.kb-down, .kb-t-right.kb-down, .kb-t-clear.kb-down { background: var(--kb-key-down); }
.kb-t-shift.kb-on { background: var(--kb-accent); color: var(--kb-accent-ink); }
.kb-t-shift { flex-direction: column; gap: calc(4px * var(--ui)); }
.kb-cap { font-size: max(14px, calc(var(--kb-font) * .4)); font-weight: 600; min-height: 1em; }
.kb-t-shift[data-state="lock"] .kb-lab { text-decoration: underline; text-decoration-thickness: calc(4px * var(--ui)); text-underline-offset: calc(6px * var(--ui)); }

/* 쉬운 한글: 자음·모음 구분 (색 + 모음 키 아래 두꺼운 줄) */
.kb-tone .kb-cons { background: var(--kb-cons); }
.kb-tone .kb-vowel { background: var(--kb-vowel); border-bottom: calc(5px * var(--ui)) solid var(--kb-accent); }
.kb-tone .kb-key.kb-down { background: var(--kb-key-down); }

/* 말풍선 (누른 글자를 키 위에 크게) */
.kb-bub {
  position: absolute; left: 50%; bottom: calc(100% + 6px * var(--ui)); min-width: 1.5em; padding: .15em .35em; box-sizing: border-box; text-align: center;
  transform: translateX(-50%) scale(.8); transform-origin: 50% 100%; opacity: 0; pointer-events: none; z-index: 5;
  background: var(--kb-key); color: var(--kb-key-ink); border-radius: calc(14px * var(--ui)); font-size: calc(var(--kb-font) * 1.5);
  box-shadow: 0 calc(6px * var(--ui)) calc(22px * var(--ui)) rgba(15, 23, 42, .28), 0 0 0 1px var(--kb-key-edge); transition: opacity 80ms, transform 80ms;
}
.kb-bubble .kb-key.kb-down .kb-bub { opacity: 1; transform: translateX(-50%) scale(1); }

/* 터치 리플 (손가락 위치 9×5 칸) */
.kb-rip { position: absolute; left: 50%; top: 50%; width: 140%; padding-top: 140%; margin: 0; border-radius: 50%; pointer-events: none; background: var(--kb-accent); opacity: 0; animation: kb-pop 220ms ease-out both; z-index: 1; }
.kb-key { overflow: hidden; }
.kb-bubble .kb-key { overflow: visible; }
.kb-rip[data-x="0"] { left: 5.5%; } .kb-rip[data-x="1"] { left: 16.5%; } .kb-rip[data-x="2"] { left: 27.5%; } .kb-rip[data-x="3"] { left: 38.5%; }
.kb-rip[data-x="4"] { left: 50%; } .kb-rip[data-x="5"] { left: 61.5%; } .kb-rip[data-x="6"] { left: 72.5%; } .kb-rip[data-x="7"] { left: 83.5%; } .kb-rip[data-x="8"] { left: 94.5%; }
.kb-rip[data-y="0"] { top: 10%; } .kb-rip[data-y="1"] { top: 30%; } .kb-rip[data-y="2"] { top: 50%; } .kb-rip[data-y="3"] { top: 70%; } .kb-rip[data-y="4"] { top: 90%; }
.kb-rip { translate: -50% -50%; width: 120%; padding-top: 0; aspect-ratio: 1; }
.kb-ring::after { content: "한 번 더 → 쌍자음"; position: absolute; left: 50%; top: calc(-34px * var(--ui)); transform: translateX(-50%); padding: calc(4px * var(--ui)) calc(10px * var(--ui)); border-radius: calc(999px * var(--ui)); background: var(--kb-accent); color: var(--kb-accent-ink); font-size: max(14px, calc(18px * var(--ui-text))); font-weight: 600; white-space: nowrap; z-index: 6; }
.kb-ring { box-shadow: 0 0 0 calc(4px * var(--ui)) var(--kb-accent), 0 2px 0 var(--kb-key-shadow); }

/* ---------- 윗줄(도움말·쉬운 한글 전환·접기) ---------- */
.kb-bar { display: flex; align-items: center; gap: calc(12px * var(--ui)); min-height: calc(48px * var(--ui)); margin-bottom: calc(8px * var(--ui)); }
.kb-bar-empty { display: none; }
.kb-hints { font-size: max(14px, calc(22px * var(--ui-text))); font-weight: 600; color: var(--kb-mute); white-space: pre; }
.kb-grow { flex: 1; }
.kb-chip { box-sizing: border-box; min-height: max(44px, calc(48px * var(--ui))); padding: 0 calc(22px * var(--ui)); border: 0; border-radius: calc(999px * var(--ui)); background: var(--kb-chip); color: var(--kb-key-ink); font: inherit; font-size: max(14px, calc(22px * var(--ui-text))); font-weight: 600; box-shadow: 0 0 0 1px var(--kb-key-edge); }
.kb-chip.kb-down { background: var(--kb-key-down); }

/* ---------- 전화번호 큰 숫자 패드 ---------- */
.kb-kind-phone { --kb-scale: 1; --kb-gap: calc(16px * var(--ui)); --kb-unit: calc(160px * var(--ui)); --kb-h: calc(120px * var(--ui)); --kb-font: calc(64px * var(--ui) * var(--kb-fs)); }
.kb-kind-phone .kb-key { min-height: calc(120px * var(--ui)); }
.kb-kind-phone .kb-t-clear, .kb-kind-phone .kb-t-backspace { font-size: calc(var(--kb-font) * .5); }
.kb-kind-phone .kb-t-enter { font-size: calc(var(--kb-font) * .62); }
.kb-pad { display: flex; flex-direction: column; gap: var(--kb-gap); align-items: center; }
.kb-msg { min-height: calc(30px * var(--ui)); margin-bottom: calc(6px * var(--ui)); text-align: center; font-size: max(14px, calc(24px * var(--ui-text))); font-weight: 600; color: var(--kb-mute); }
.kb-t-enter.kb-disabled { background: var(--kb-fn); color: var(--kb-mute); box-shadow: none; }

/* ---------- 낮은 위치(휠체어) ---------- */
.kb-low { padding-bottom: calc(12px * var(--ui)); --kb-gap: max(8px * var(--ui), calc(var(--kb-unit) * .08)); }
.kb-low .kb-bar { margin-bottom: calc(4px * var(--ui)); }

/* ---------- 고대비 ---------- */
.kb-hc { background: #000; box-shadow: 0 -2px 0 #fff; }
.kb-hc .kb-key, .kb-hc .kb-chip { background: #000; color: #fff; box-shadow: none; border: calc(3px * var(--ui)) solid #fff; }
.kb-hc .kb-t-enter { background: #fff; color: #000; }
.kb-hc .kb-t-shift.kb-on { background: #fff; color: #000; }
.kb-hc .kb-key.kb-down, .kb-hc .kb-chip.kb-down { background: #ffd400; color: #000; border-color: #ffd400; filter: none; }
.kb-hc .kb-vowel { border-bottom-width: calc(9px * var(--ui)); }
.kb-hc .kb-sub, .kb-hc .kb-hints, .kb-hc .kb-msg, .kb-hc .kb-cap { color: #fff; }
.kb-hc .kb-bub { background: #ffd400; color: #000; box-shadow: none; }
.kb-hc .kb-t-enter.kb-disabled { background: #000; color: #bbb; border-style: dashed; }
.kb-hc .kb-ring { box-shadow: 0 0 0 calc(4px * var(--ui)) #ffd400; }
.kb-hc .kb-rip { background: #ffd400; }

/* ---------- 자체 입력란 ---------- */
.kbf {
  position: relative; box-sizing: border-box; min-height: calc(96px * var(--ui)); padding: calc(24px * var(--ui)) calc(28px * var(--ui)); display: flex; align-items: center;
  background: var(--kb-field); color: var(--kb-field-ink); border: 2px solid var(--kb-field-edge); border-radius: calc(20px * var(--ui));
  font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", system-ui, sans-serif;
  font-size: max(14px, calc(40px * var(--ui-text))); font-weight: 500; line-height: 1.3; cursor: text; outline: none;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; touch-action: manipulation;
  transition: border-color 140ms, box-shadow 140ms;
}
.kbf[data-kind="phone"] { font-size: max(14px, calc(56px * var(--ui-text))); font-weight: 600; letter-spacing: .02em; font-variant-numeric: tabular-nums; }
.kbf[data-kind="multiline"] { min-height: calc(240px * var(--ui)); align-items: flex-start; }
.kbf-line { display: inline; white-space: pre-wrap; overflow-wrap: anywhere; }
.kbf[data-kind="multiline"] .kbf-line { white-space: pre-wrap; }
.kbf[data-kind]:not([data-kind="multiline"]) .kbf-line { white-space: nowrap; overflow: hidden; text-overflow: clip; max-width: 100%; }
.kbf-ph { position: absolute; left: calc(28px * var(--ui)); right: calc(28px * var(--ui)); color: var(--kb-mute); opacity: .8; pointer-events: none; font-weight: 400; overflow: hidden; white-space: nowrap; }
.kbf[data-empty="false"] .kbf-ph { display: none; }
.kbf[data-empty="true"][data-active="true"] .kbf-ph { opacity: .55; }
.kbf-active { border-color: var(--kb-ring); box-shadow: 0 0 0 calc(5px * var(--ui)) color-mix(in srgb, var(--kb-ring) 28%, transparent); }
.kbf-pre { background: var(--kb-pre-bg); border-bottom: 2px solid var(--kb-accent); border-radius: calc(4px * var(--ui)) calc(4px * var(--ui)) 0 0; }
.kbf-caret { display: inline-block; width: calc(3px * var(--ui)); height: 1.15em; margin: 0 1px; vertical-align: text-bottom; background: var(--kb-accent); border-radius: 2px; animation: kbf-blink 1.06s steps(1) infinite; }
.kbf-nl { color: var(--kb-mute); }
.kbf-dim .kbf-line { filter: blur(calc(8px * var(--ui))); }
.kbf[data-masked="true"] .kbf-line { letter-spacing: .06em; }
.kbf-shake { animation: kbf-shake 360ms ease; border-color: var(--kb-danger); }
.kb-lt-field.kbf { font-size: max(14px, calc(52px * var(--ui-text))); }
.kbf.kbf-hc { background: #000; color: #fff; border-color: #fff; border-width: calc(3px * var(--ui)); }
.kbf.kbf-hc.kbf-active { border-color: #ffd400; box-shadow: none; }
.kbf.kbf-hc .kbf-caret { background: #ffd400; }
.kbf.kbf-hc .kbf-pre { background: transparent; border-bottom: calc(4px * var(--ui)) solid #ffd400; }

@media (prefers-reduced-motion: reduce) {
  .kb { animation: none; }
  .kb-rip { display: none; }
  .kb-key, .kb-bub { transition: background-color 60ms; }
  .kb-key.kb-down { transform: none; }
  .kbf-shake { animation: none; }
  .kbf-caret { animation: none; }
}
