/* 현장에서 폰으로 쓰는 화면.
   손가락으로 누르는 것을 전제로 단추와 입력칸을 크게 잡았다.
   글자 16px 미만이면 iOS 가 입력할 때 화면을 확대해 버린다 — 그래서 16px 아래로 내리지 않는다. */

:root {
  color-scheme: light dark;
  --ink: #16202c;
  --muted: #64748b;
  --line: #dbe3ec;
  --paper: #f4f6f9;
  --card: #ffffff;
  --accent: #1f6feb;
  --ok: #157a4b;
  --info: #2a5f9e;
  --warn: #a76a00;
  --bad: #c0392b;
}
@media (prefers-color-scheme: dark) {
  :root {
    --ink: #e8eef6; --muted: #94a3b8; --line: #2a3644;
    --paper: #0e141c; --card: #161f2a; --accent: #4d9bff;
  }
}

* { box-sizing: border-box; }
/* hidden 은 브라우저 기본 규칙(display:none)으로 동작하는데, 그 힘이 약해서
   .viewer{display:flex} 같은 우리 규칙 하나에 밀린다. 그러면 숨기라고 해도
   그대로 떠 있는다 — 실제로 미리보기 창이 늘 떠 있는 사고가 났다.
   숨김은 어떤 규칙보다 세야 한다. */
[hidden] { display: none !important; }

body {
  margin: 0; background: var(--paper); color: var(--ink);
  font: 16px/1.55 Pretendard, "Malgun Gothic", -apple-system, system-ui, sans-serif;
  padding-bottom: env(safe-area-inset-bottom);
}

.top {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: calc(10px + env(safe-area-inset-top)) 16px 10px;
  background: var(--card); border-bottom: 1px solid var(--line);
}
.kicker { margin: 0; font-size: 10px; letter-spacing: .16em; color: var(--muted); }
h1 { margin: 0; font-size: 19px; letter-spacing: -.02em; }
h2 { margin: 0; font-size: 15px; }

/* 주소 뒤에 ?diag 를 붙였을 때만 나오는 진단표. 폰에서 그대로 찍어 보낼 수 있게
   글자를 작고 촘촘하게, 줄바꿈은 그대로 둔다. */
.diag {
  margin: 0; padding: 12px; overflow-x: auto;
  background: var(--ink); color: #d7e3f4; border-radius: 10px;
  font: 11.5px/1.7 ui-monospace, "Consolas", monospace; white-space: pre-wrap; word-break: break-all;
}

/* 서버에 닿지 않을 때. 눈에 띄어야 한다 — 이걸 못 보면 사진을 다 넣고 나서
   저장이 안 되는 것을 알게 된다. */
.offline-bar {
  max-width: 720px; margin: 12px auto 0; padding: 12px 14px;
  background: #fdecea; border: 1px solid var(--bad); border-radius: 12px;
  color: #8e2b1f; font-size: 14px; line-height: 1.55;
}

/* 홈 화면에 넣으라는 안내. 설치할 수 있을 때만 뜨고, 한 번 닫으면 다시 안 뜬다. */
.install-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  max-width: 720px; margin: 12px auto 0; padding: 12px 14px;
  background: var(--card); border: 1px solid var(--accent); border-radius: 12px;
  font-size: 14px; line-height: 1.5;
}
.install-actions { display: flex; gap: 8px; flex: none; }
.install-actions button { padding: 9px 14px; font-size: 14px; }

/* 아이폰에서 홈 화면 앱으로 열면 시스템이 왼쪽 위에 ··· 단추를 그린다.
   그 자리를 비워두지 않으면 제목과 겹친다. 지울 수는 없어서 자리를 내준다. */
@supports (-webkit-touch-callout: none) {
  @media (display-mode: standalone) {
    .top { padding-top: calc(10px + env(safe-area-inset-top) + 20px); }
  }
}

main { max-width: 720px; margin: 0 auto; padding: 14px 14px 60px; display: grid; gap: 16px; }
/* **격자 칸은 제 속내용보다 좁아지지 않는다.** 그것이 기본값(min-width:auto)이다.
   그래서 안쪽에 안 줄어드는 것이 하나라도 있으면 — 이를테면 현장명이 긴 채로
   [말로 채우기] 단추가 함께 떠 있는 제목 줄 — 그 폭만큼 **화면 전체가 넓어진다.**
   폰에서는 화면이 옆으로 밀리고, 브라우저가 줄여 보여주려 해서 확대된 것처럼 보인다.
   실제로 그 일이 났다: 화면 360인데 문서가 416이 되었다.
   칸이 줄어들 수 있게 풀어 준다. 줄어든 자리는 안쪽에서 말줄임(…)으로 처리된다. */
main > * { min-width: 0; }
.card { padding: 14px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; }
.section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.count { display: inline-block; min-width: 22px; padding: 1px 7px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 12px; text-align: center; }

/* 격자 칸은 기본값이 "안의 것보다 작아지지 않기" 라서, 안의 입력칸이 넓으면
   칸이 밀려 틀 밖으로 나간다. 줄어들 수 있게 열어 준다. */
label { display: grid; gap: 5px; font-size: 13px; color: var(--muted); min-width: 0; }
label.block { margin-top: 10px; }
input, textarea, select {
  width: 100%; min-width: 0; box-sizing: border-box;
  padding: 11px 12px; font: inherit; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line); border-radius: 9px;
  /* **16px 아래로 절대 내리지 않는다.**
     아이폰은 그보다 작은 칸을 누르면 글자를 읽히려고 화면을 통째로 확대한다.
     그리고 그 확대는 **저절로 풀리지 않는다** — 그때부터 화면이 웹페이지처럼
     좌우로 밀려다닌다. 자료를 불러온 뒤 칸을 누를 때 그 일이 났다.
     위의 font:inherit 만 두면 감싸고 있는 label(13px)을 물려받아 13px 이 된다.
     그래서 여기서 크기만 따로 못박는다. */
  font-size: 16px;
}
/* 아이폰·아이패드는 날짜칸을 제 마음대로 넓게 그린다. 그러면 틀을 넘어간다. */
input[type="date"] { -webkit-appearance: none; appearance: none; }
input:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
textarea { resize: vertical; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.grid2 > *, .grid3 > * { min-width: 0; }
@media (max-width: 520px) { .grid2, .grid3 { grid-template-columns: 1fr; } }

button, .button {
  padding: 11px 14px; font: inherit; font-weight: 600;
  color: var(--ink); background: var(--card);
  border: 1px solid var(--line); border-radius: 9px; cursor: pointer;
  text-align: center; text-decoration: none; display: inline-block;
}
button:active, .button:active { transform: translateY(1px); }
.primary { background: var(--accent); border-color: var(--accent); color: #fff; padding: 11px 22px; }
.button.strong { border-color: var(--accent); color: var(--accent); }
.button.disabled { opacity: .4; pointer-events: none; }

/* 선으로 그린 기호. 글자 크기와 색을 그대로 따라간다 —
   이모지처럼 기기마다 모양이 달라지거나 혼자 알록달록해지지 않는다. */
.ic {
  width: 1.15em; height: 1.15em; flex: none;
  vertical-align: -.22em; stroke-width: 1.6;
}

.items { display: grid; gap: 12px; }
.item { padding: 12px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; }
.item-head { display: flex; align-items: center; gap: 8px; }
.item-no { flex: none; width: 30px; height: 30px; display: grid; place-items: center; border-radius: 8px; background: var(--paper); font-size: 13px; font-weight: 700; color: var(--muted); }
.item-head .title { flex: 1; font-weight: 600; }
.remove { flex: none; width: 38px; padding: 0; height: 38px; color: var(--muted); }

/* 상태 넷. 현장에서 한 번 눌러 고른다. */
.status-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.status-row label { display: block; }
.status-row input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip {
  display: block; padding: 8px 14px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card);
  font-size: 14px; font-weight: 600; color: var(--muted); cursor: pointer;
}
.status-row input:checked + .chip { color: #fff; }
.status-row input:checked + .chip.tone-ok { background: var(--ok); border-color: var(--ok); }
.status-row input:checked + .chip.tone-info { background: var(--info); border-color: var(--info); }
.status-row input:checked + .chip.tone-warn { background: var(--warn); border-color: var(--warn); }
.status-row input:focus-visible + .chip { outline: 2px solid var(--accent); outline-offset: 2px; }

/* 사진 — 현장에서 가장 많이 쓰는 부분이라 크게 둔다. */
.photo-buttons { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px; }
.add-photo {
  display: block; padding: 14px; text-align: center; cursor: pointer;
  border: 1.5px dashed var(--line); border-radius: 10px;
  color: var(--muted); font-size: 15px; font-weight: 600;
}
.add-photo.shoot { border-style: solid; border-color: var(--accent); color: var(--accent); }
.add-photo:active { background: var(--paper); }

.shots { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 8px; margin-top: 10px; }
.shots:empty { display: none; }
.shot { position: relative; margin: 0; }
.shot img { width: 100%; height: 104px; object-fit: cover; border-radius: 8px; border: 1px solid var(--line); display: block; }
.shot .caption { margin-top: 4px; padding: 7px 8px; font-size: 13px; }
.shot .drop {
  position: absolute; top: 5px; right: 5px; width: 30px; height: 30px; padding: 0;
  border-radius: 50%; border: 0; background: rgba(0,0,0,.6); color: #fff; font-size: 14px;
}

/* 금액 칸. 오른쪽 정렬에 자릿수 고정 글꼴을 쓰면 쉼표가 세로로 줄을 맞춰
   180,000 과 1,800,000 이 한눈에 갈린다. 자리를 잘못 넣었을 때 보이는 게 목적이다. */
.money-input {
  text-align: right; font-variant-numeric: tabular-nums;
  font-size: 18px; font-weight: 600; letter-spacing: .01em;
}
.money-input::placeholder { font-weight: 400; }

/* 계산서 — 넣는 즉시 합계가 보여야 한다. */
.money { margin: 14px 0 0; display: grid; gap: 6px; }
.money > div { display: flex; justify-content: space-between; align-items: baseline; padding: 7px 2px; border-bottom: 1px solid var(--line); }
.money dt { color: var(--muted); font-size: 14px; }
.money dd { margin: 0; font-variant-numeric: tabular-nums; font-weight: 600; }
.money .total { border-bottom: 0; border-top: 2px solid var(--ink); margin-top: 4px; padding-top: 12px; }
.money .total dt { color: var(--ink); font-weight: 700; font-size: 16px; }
.money .total dd { font-size: 22px; font-weight: 800; }

.actions { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
/* 문서마다 [미리보기] [발행] 둘이다. 한 줄에 한 문서씩 놓는다 —
   그래야 어느 문서의 단추인지 헷갈리지 않는다.
   발행 쪽을 조금 넓게 잡는다. 가장 중요하고 되돌릴 수 없는 단추다. */
.actions.three { grid-template-columns: 1fr 1.15fr; }

/* 발행 이력 */
.issues { display: grid; gap: 8px; }
.issue-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  padding: 11px 12px; background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
}
.issue-name { font-weight: 700; font-size: 14.5px; }
.issue-sub { display: block; color: var(--muted); font-size: 12px; margin-top: 2px; }
/* 해시는 위변조 대조용이다. 자릿수 고정 글꼴이라야 눈으로 견줄 수 있다. */
.issue-hash { font: 11px ui-monospace, Consolas, monospace; color: var(--muted); word-break: break-all; }
.issue-row a { flex: none; padding: 8px 12px; font-size: 13px; }

.saved { display: grid; gap: 8px; }
.saved-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; padding: 12px; background: var(--card); border: 1px solid var(--line); border-radius: 10px; }
.saved-row .sub { display: block; color: var(--muted); font-size: 12.5px; }
.saved-links { display: flex; gap: 6px; }
.saved-links a, .saved-links button { padding: 8px 12px; font-size: 13.5px; }

.empty { margin: 0; padding: 18px; text-align: center; color: var(--muted); font-size: 14px; line-height: 1.7; }
.hint { margin: 10px 0 0; color: var(--muted); font-size: 12.5px; line-height: 1.6; }

/* 사진 장수 표시. 셋을 넘으면 어느 것이 문서에 안 나오는지 알린다. */
.photo-note { margin: 8px 0 0; font-size: 12.5px; color: var(--muted); }
.photo-note.warn { color: #a2500e; font-weight: 600; }
/* 자리가 다 찼으면 단추를 흐리게 하고 눌러도 안 열리게 한다. */
.add-photo.off { opacity: .4; pointer-events: none; }

/* ── 현장 모드 ──────────────────────────────────────────────
   현장에서는 이 화면 말고 볼 것이 없다. 검은 바탕에 큰 단추만 둔다.
   단추를 아래에 몰아 둔 것은 한 손으로 잡았을 때 엄지가 닿는 자리라서다. */
.field-go {
  display: block; width: 100%; padding: 16px; text-align: left;
  border: 0; border-radius: 14px; background: var(--accent); color: #fff;
}
.field-go-main { display: flex; align-items: center; gap: 8px; font-size: 18px; font-weight: 800; letter-spacing: -.02em; }
.field-go-sub { display: block; margin-top: 3px; font-size: 13px; opacity: .85; }
.field-go:active { filter: brightness(.92); }

.field-mode {
  position: fixed; inset: 0; z-index: 60; display: flex; flex-direction: column;
  background: #000; color: #fff;
}
.fm-stage { position: relative; flex: 1; min-height: 0; background: #000; }
#fm-video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 찍혔다는 것이 눈에 보여야 한다 — 장갑을 끼면 누른 감이 없다. */
.fm-flash { position: absolute; inset: 0; background: #fff; opacity: 0; pointer-events: none; }
.fm-flash.on { animation: fm-blink .22s ease-out; }
@keyframes fm-blink { from { opacity: .85; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .fm-flash.on { animation: none; } }

.fm-rec {
  position: absolute; top: calc(12px + env(safe-area-inset-top)); left: 50%; transform: translateX(-50%);
  margin: 0; padding: 6px 14px; border-radius: 999px;
  background: rgba(200, 30, 30, .92); font-size: 13px; font-weight: 700;
}
.fm-fallback { flex: 1; display: grid; place-content: center; gap: 14px; padding: 24px; text-align: center; font-size: 15px; line-height: 1.7; }
.fm-fallback .add-photo { color: #fff; border-color: #fff; }

/* 방금 찍은 것 몇 장만. 다 띄우면 40장에서 화면이 느려진다. */
.fm-strip { display: flex; gap: 6px; padding: 8px 10px 0; overflow-x: auto; }
.fm-strip:empty { display: none; }
.fm-strip img { width: 54px; height: 54px; object-fit: cover; border-radius: 6px; flex: none; }

.fm-bar { padding: 10px 14px calc(12px + env(safe-area-inset-bottom)); }
.fm-tally { margin: 0; text-align: center; font-size: 14px; color: #cbd5e1; }
.fm-tally b { color: #fff; font-size: 17px; }
.fm-note { margin: 4px 0 0; height: 18px; text-align: center; font-size: 12.5px; color: #93c5fd; }

.fm-controls { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px; margin-top: 8px; }
.fm-shutter {
  width: 76px; height: 76px; padding: 0; border-radius: 50%;
  background: #fff; border: 5px solid rgba(255, 255, 255, .35); box-shadow: none;
}
.fm-shutter:active { transform: scale(.94); }
.fm-side {
  display: grid; gap: 2px; padding: 12px 8px; border-radius: 12px;
  background: rgba(255, 255, 255, .12); border: 1.5px solid transparent;
  color: #fff; font-size: 14px; font-weight: 700;
}
.fm-side small { font-size: 11px; font-weight: 500; opacity: .7; }
/* 다음 사진부터 새 공정이라는 표시. 눌러 놓고 잊어도 보이게 켜 둔다. */
.fm-side.armed { background: var(--warn); border-color: #fff; }
.fm-side.on { background: #c81e1e; }

/* 말로 남기기. 셔터와 떨어뜨려 크게 둔다 — 잘못 눌리면 안 되는 단추다. */
.fm-memo {
  display: block; width: 100%; margin-top: 12px; padding: 13px;
  border-radius: 12px; border: 1.5px solid rgba(255, 255, 255, .3);
  background: rgba(255, 255, 255, .1); color: #fff; font-size: 15px; font-weight: 700;
}
.fm-memo-top { display: inline-flex; align-items: center; justify-content: center; gap: 7px; }
.fm-memo small { display: block; margin-top: 2px; font-size: 11.5px; font-weight: 500; opacity: .7; }
.fm-memo.on { background: #c81e1e; border-color: #fff; }

/* 받아 적힌 말. 듣는 중에는 흐리게, 다 끝나면 또렷하게. */
.fm-heard {
  margin: 0 0 6px; padding: 9px 12px; border-radius: 10px;
  background: rgba(255, 255, 255, .1); color: #e8eef6;
  font-size: 14px; line-height: 1.5; text-align: center;
}
.fm-heard.live { color: #93c5fd; }

.fm-foot { display: grid; grid-template-columns: 1fr 2fr; gap: 8px; margin-top: 12px; }
.fm-foot button { padding: 14px; font-size: 15px; font-weight: 700; }
.fm-foot button:not(.primary) { background: rgba(255, 255, 255, .12); border-color: transparent; color: #fff; }
.fm-foot .primary:disabled { opacity: .4; }

/* ── 사진 분석 ──────────────────────────────────────────────
   초안이 들어온 항목은 **한눈에 달라 보여야 한다.** 확인을 누르기 전까지는
   아직 사람이 안 본 글이고, 그대로 저장되면 고객이 그 글을 읽는다. */
/* 사진 단추와 같은 크기로 둔다. 장갑 낀 손으로 누르는 자리다. */
.ai-row { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.ai-go {
  flex: 1; min-width: 0; padding: 14px; font-size: 15px; font-weight: 600;
  border: 1.5px solid var(--accent); border-radius: 10px; color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
}
.ai-go:disabled { opacity: .55; }
.ai-left { flex: none; font-size: 12.5px; color: var(--muted); }

.item.ai-pending { border-color: var(--warn); box-shadow: 0 0 0 1px var(--warn) inset; }
.item.ai-pending .title,
.item.ai-pending .condition,
.item.ai-pending .action,
.item.ai-pending .note { background: color-mix(in srgb, var(--warn) 8%, var(--card)); }

/* 확인은 정확성을 지키는 자리다. 눈에 띄고 크게 둔다 —
   작아서 못 보고 지나치면 확인 안 한 글이 그대로 고객에게 간다. */
/* 말로 남긴 것. 숫자가 섞여 있을 수 있어 눈에 띄게 두되, 칸이 아니라 메모로 보이게 한다. */
.heard {
  margin: 10px 0 0; padding: 9px 11px; border-radius: 9px;
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
  font-size: 13px; line-height: 1.55;
}
.heard-label { display: block; font-size: 11.5px; font-weight: 700; color: var(--accent); }
.heard-text { color: var(--ink); }

.ai-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.ai-tag { flex: 1 1 100%; font-size: 13px; font-weight: 700; color: var(--warn); }
.ai-bar.low .ai-tag { color: #b3261e; }
.ai-bar button { flex: 1; min-width: 0; padding: 11px 14px; font-size: 14px; }
.ai-bar .ai-ok { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 700; }
/* 문서에 안 들어갈 사진에 표시를 남긴다 — 지우기 전에 어느 것인지 보이게. */
.shot.over img { opacity: .45; }
.shot.over::after {
  content: '문서 제외'; position: absolute; left: 4px; top: 4px;
  padding: 2px 6px; border-radius: 6px;
  background: #a2500e; color: #fff; font-size: 11px; font-weight: 700;
}

/* 접는 칸.
   <details> 를 쓴다 — 자바스크립트 없이도 접히고, 접힌 안쪽은 폰의
   화면 낭독기와 "페이지에서 찾기" 에서도 건너뛴다. 직접 만들면 그게 안 된다. */
.fold { padding: 0; }
.fold > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px; cursor: pointer; list-style: none; -webkit-tap-highlight-color: transparent;
}
/* 브라우저가 그리는 삼각형을 지운다. 우리 것을 제목 앞에 따로 둔다. */
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::marker { content: ''; }
.fold-title { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 700; }
.fold-title::before {
  content: '▸'; display: inline-block; width: 12px;
  color: var(--muted); font-size: 12px; transition: transform .15s ease;
}
.fold[open] > summary .fold-title::before { transform: rotate(90deg); }
.fold > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 12px; }
.fold-body { padding: 0 14px 14px; }
/* 접었을 때 무엇이 든 칸인지 알려주는 곁말 — 현장명 같은 것. */
.fold-sub { font-weight: 500; font-size: 13.5px; color: var(--muted); }

/* 입력칸 옆에 붙는 단추 (주소 검색). */
.with-button { display: flex; gap: 8px; }
.with-button input { flex: 1; min-width: 0; }
.with-button button { flex: none; padding: 11px 13px; font-size: 14px; }

/* 주소 검색 창은 미리보기 창과 같은 틀을 쓴다. */
.finder-box { flex: 1; overflow: auto; background: #fff; min-height: 0; }
/* 접었을 때 머리 아래가 허전하지 않도록 조금 눌러 준다. */
.fold:not([open]) > summary { padding-bottom: 13px; }

/* 견적 줄 — 현장에서 폰으로 누른다.
   이름은 한 줄을 통째로 쓰고, 숫자는 그 아래 한 줄에 넷으로 나눈다.
   한 줄에 다 밀어 넣으면 칸이 40px 아래로 좁아져 옆 칸을 누르게 된다. */
.qlines { display: grid; gap: 10px; }

/* 계산서는 갈래마다 따로 모은다 — 견적 / 추가 / 반품.
   섞여 있으면 무엇이 원래 견적이고 무엇이 나중에 붙은 것인지 짚어 봐야 한다. */
#i-lines { display: grid; gap: 16px; }
.qgroup-title {
  margin: 0 0 8px; padding-left: 9px; border-left: 3px solid var(--line);
  font-size: 13px; font-weight: 700; color: var(--muted);
}
.qgroup[data-kind="quote"] .qgroup-title { border-color: #7ea0d6; color: #3c5a8a; }
.qgroup[data-kind="extra"] .qgroup-title { border-color: #e6c79a; color: #8a5210; }
.qgroup[data-kind="return"] .qgroup-title { border-color: #e8b3ab; color: #a3271b; }
.qline { padding: 10px; background: var(--card); border: 1px solid var(--line); border-radius: 10px; }
.qline-top { display: flex; align-items: center; gap: 8px; }
/* 계산서에서 견적분과 추가분을 갈라 보여준다. 어느 줄이 시공 중에 붙었는지
   한눈에 보여야 고객에게 설명할 수 있다. */
/* 직접 넣은 줄에서는 이 표시가 곧 단추다 — 눌러서 추가 ↔ 반품 을 바꾼다. */
.q-tag {
  flex: none; padding: 5px 9px; border: 1px solid transparent; border-radius: 7px;
  font: inherit; font-size: 11.5px; font-weight: 700; cursor: pointer;
}
.q-tag:disabled { cursor: default; }
.q-tag:not(:disabled) { border-style: dashed; }
.q-tag:not(:disabled):active { transform: translateY(1px); }
.q-tag.q { background: #eef2f8; color: #3c5a8a; }
.q-tag.x { background: #fdf0e2; color: #9a5a10; border-color: #e6c79a; }
.q-tag.r { background: #fdecea; color: #a3271b; border-color: #e8b3ab; }
/* 반품은 빼는 줄이다. 금액이 마이너스로 나오므로 색으로도 표시한다. */
.qline.back { border-color: #f0c8c2; background: #fffaf9; }
.qline.back .q-amount { color: #a3271b; }

/* 기수령액 — 체크해야 금액칸이 열린다. 실수로 빼는 일을 막으려는 것이다. */
.paid-head { margin: 16px 0 8px; }
.paid-head h2 { font-size: 14px; color: var(--muted); }
.paid-box { display: grid; gap: 8px; }
.paid-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; align-items: center; }
.paid-row .money-input { text-align: right; }
.paid-row input:disabled { background: var(--paper); color: var(--muted); }

/* 견적과 청구가 얼마나 벌어졌는지. 저장하고 PDF 를 열어봐야 알면 늦다. */
.diff-line { margin: 10px 0 0; padding: 9px 11px; border-radius: 9px; background: var(--paper);
  color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.diff-line.up { color: #a2500e; background: #fdf3e7; }
.diff-line.down { color: var(--ok); background: #eaf6ef; }
.stale { margin: 10px 0 0; padding: 9px 11px; border-radius: 9px;
  background: #fdf3e7; color: #a2500e; font-size: 13px; }

/* 드롭다운과 글자칸은 같은 자리를 번갈아 쓴다. 폭이 달라 보이면 화면이 튄다. */
.qline-top .q-name, .qline-top .q-pick { flex: 1; min-width: 0; font-weight: 600; }
.qline-top .q-pick { text-overflow: ellipsis; }
.qline-top .drop {
  flex: none; width: 34px; padding: 0; height: 34px; line-height: 1;
  color: var(--muted); background: transparent; border-color: transparent;
}
.qline-top .drop:hover { color: var(--bad); }

/* 수량·단위·단가는 좁게, 금액은 넓게. 금액이 결과라 가장 잘 보여야 한다. */
.qline-num { display: grid; grid-template-columns: 1fr .7fr 1.3fr 1.4fr; gap: 8px; margin-top: 8px; align-items: end; }
.qline-num label { display: grid; gap: 4px; font-size: 12px; color: var(--muted); }
.qline-num input { text-align: right; font-variant-numeric: tabular-nums; }
.qline-num .q-unit { text-align: center; }
.q-sum { display: grid; gap: 4px; padding-bottom: 9px; text-align: right; font-size: 12px; color: var(--muted); }
.q-sum b { font-size: 16px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }

/* 아주 좁은 폰에서는 넷이 한 줄에 들어가지 않는다. 둘씩 접는다. */
@media (max-width: 380px) {
  .qline-num { grid-template-columns: 1fr 1fr; }
  .q-sum { text-align: left; padding-bottom: 0; }
}

/* 관리자 — 단가표 */
.cat-tools { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.cat-tools .add-photo { margin: 0; }
.catalog { display: grid; gap: 8px; margin-top: 12px; }
.cat-row { display: grid; grid-template-columns: 1fr .55fr .9fr 34px; gap: 8px; align-items: center; }
.cat-row .c-unit { text-align: center; }
.cat-row .c-price { text-align: right; font-variant-numeric: tabular-nums; }
.cat-row .drop {
  width: 34px; height: 34px; padding: 0; line-height: 1;
  color: var(--muted); background: transparent; border-color: transparent;
}
.cat-row .drop:hover { color: var(--bad); }
@media (max-width: 460px) {
  /* 이름이 짧으면 무엇의 단가인지 알 수 없다. 좁아지면 이름에 한 줄을 준다. */
  .cat-row { grid-template-columns: 1fr .9fr 34px; }
  .cat-row .c-name { grid-column: 1 / -1; }
}

/* 관리자 — 로고 */
.logo-row { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.logo-preview {
  flex: none; width: 96px; height: 96px; display: grid; place-items: center;
  border: 1.5px dashed var(--line); border-radius: 12px;
  color: var(--muted); font-size: 13px;
  /* 보고서 머리말이 파란 바탕이라 그 위에서 어떻게 보이는지 미리 보여준다. */
}
/* 문서에서 로고에 테두리를 두르지 않으므로 미리보기도 두르지 않는다.
   파란 바탕은 남긴다 — 머리말이 파랗다는 것을 보여줘야 하기 때문이다. */
.logo-preview.has { border: 0; background: linear-gradient(112deg, #2f63dc, #1f4bb2); }
.logo-preview img { max-width: 72px; max-height: 72px; object-fit: contain; }
/* 기본 로고는 파일 자체가 흰색·투명이다. 파란 바탕 위에 그대로 얹으면 된다. */
.logo-note { margin: 0; font-size: 13px; font-weight: 600; color: var(--muted); }

/* 체크박스 한 줄. 글자를 눌러도 켜지도록 label 로 감싼다 — 폰에서 네모만
   정확히 누르게 하면 몇 번은 헛손질을 한다. */
.check { display: flex; align-items: center; gap: 10px; cursor: pointer;
  font-size: 15px; color: var(--ink); }
.check input { width: 20px; height: 20px; margin: 0; flex: none; accent-color: var(--accent); }
.logo-actions { flex: 1; min-width: 220px; display: grid; gap: 8px; align-content: start; }
.logo-actions .add-photo { margin: 0; }

/* 미리보기 창. 앱 위에 통째로 덮는다 — 다른 쪽으로 넘어가지 않으므로
   뒤로가기가 앱을 빠져나갈 일이 없다. */
.viewer {
  position: fixed; inset: 0; z-index: 30;
  display: flex; flex-direction: column; background: var(--paper);
}
.viewer-top {
  display: flex; align-items: center; gap: 10px;
  padding: calc(10px + env(safe-area-inset-top)) 14px 10px;
  background: var(--card); border-bottom: 1px solid var(--line);
}
.viewer-top span { flex: 1; font-weight: 700; font-size: 15px; }
.viewer-top button, .viewer-top .button { padding: 9px 13px; font-size: 14px; }
/* 문서를 A4 폭(800px)으로 그려 놓고 통째로 줄여 화면에 맞춘다.
   줄이는 것은 그림이 아니라 화면이므로 글자는 그대로 또렷하다. */
.viewer-stage {
  flex: 1; overflow: hidden; display: flex; justify-content: center;
  background: #fff; padding-bottom: env(safe-area-inset-bottom);
}
.viewer-stage iframe {
  flex: none; width: 800px; border: 0; background: #fff;
  transform-origin: top center;
}
/* 미리보기가 떠 있는 동안 뒤쪽이 따라 스크롤되지 않게 한다. */
body.locked { overflow: hidden; }

/* PDF 를 만든 뒤 무엇을 할지 고르는 자리. 아래에서 올라온다 — 폰에서는 손이
   화면 아래쪽에 있다. */
/* 동의 창은 현장 모드(z-index 60) 위에 떠야 한다.
   아래에 깔리면 묻는 창이 안 보인 채로 녹음이 시작된다 — 실제로 그런 일이 있었다. */
#ai-consent { z-index: 70; }

.sheet {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(10, 16, 24, .45);
}
.sheet-box {
  width: 100%; max-width: 520px;
  padding: 18px 16px calc(18px + env(safe-area-inset-bottom));
  background: var(--card); border-radius: 16px 16px 0 0;
}
.sheet-title { margin: 0; font-size: 17px; font-weight: 700; }
.sheet-name {
  margin: 6px 0 0; color: var(--muted); font-size: 13px;
  word-break: break-all; font-variant-numeric: tabular-nums;
}
/* PDF 로 보낼지 사진으로 보낼지. 보내기 전에 고르게 한다 —
   보내고 나서 "안 열린다" 는 말을 들으면 이미 늦다. */
.sheet-kinds { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
.sheet-kinds button {
  padding: 11px 8px; font-size: 14px; font-weight: 700; line-height: 1.35;
  border: 1.5px solid var(--line); border-radius: 10px; background: var(--card); color: var(--muted);
}
.sheet-kinds button small { display: block; margin-top: 2px; font-size: 11px; font-weight: 500; }
.sheet-kinds button.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--card)); }

.sheet-actions { display: grid; gap: 8px; margin-top: 14px; }
.sheet-actions button { padding: 14px; font-size: 15.5px; }

.toast {
  position: fixed; left: 50%; bottom: calc(16px + env(safe-area-inset-bottom)); transform: translateX(-50%);
  max-width: calc(100% - 28px); margin: 0; padding: 12px 18px; z-index: 20;
  background: var(--ink); color: var(--paper); border-radius: 10px;
  font-size: 14px; box-shadow: 0 8px 24px rgba(0,0,0,.28);
}
.toast.good { background: var(--ok); color: #fff; }
.toast.bad { background: var(--bad); color: #fff; }

/* ── 앱처럼 움직이게 ────────────────────────────────────────
   덮는 창이 **툭 나타나면** 웹페이지로 보인다. 앱은 어디선가 온다 —
   바탕은 스며들고, 상자는 아래에서 올라온다.
   길이는 짧게 잡았다(0.18~0.24초). 길면 현장에서 기다리는 느낌이 든다. */
@keyframes ui-fade { from { opacity: 0; } }
@keyframes ui-rise { from { transform: translateY(14px); opacity: .6; } }
@keyframes ui-lift { from { transform: translateY(100%); } }
@keyframes ui-zoom { from { transform: scale(.98); opacity: 0; } }

.sheet, .dlg { animation: ui-fade .18s ease-out; }
/* 아래에서 올라오는 상자. 끝에서 살짝 무르게 서도록 곡선을 준다. */
.sheet-box, .dlg-box { animation: ui-lift .26s cubic-bezier(.22, .9, .26, 1); }
.viewer { animation: ui-fade .16s ease-out; }
.viewer-stage { animation: ui-zoom .22s cubic-bezier(.22, .9, .26, 1); }
.toast { animation: ui-rise .2s cubic-bezier(.22, .9, .26, 1); }

/* 닫힐 때. 열 때보다 짧게 — 사라지는 것을 기다리게 하면 안 된다. */
.dlg.out { animation: ui-fade .18s ease-in reverse; pointer-events: none; }
.dlg.out .dlg-box { animation: ui-lift .18s ease-in reverse; }

@media (prefers-reduced-motion: reduce) {
  .sheet, .dlg, .sheet-box, .dlg-box, .viewer, .viewer-stage, .toast,
  .dlg.out, .dlg.out .dlg-box { animation: none; }
}

/* ── 묻는 창 ────────────────────────────────────────────────
   window.confirm 을 대신한다. 그 창에는 주소가 찍혀서, 뜨는 순간
   앱이 아니라 웹페이지가 된다(ui.js 참고). */
.dlg {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(10, 16, 24, .5);
  /* 뒤가 살짝 흐려지면 앞의 창이 떠 보인다. 안 되는 기기에서는 그냥 안 흐려질 뿐이다. */
  backdrop-filter: blur(2px);
}
.dlg-box {
  width: 100%; max-width: 460px;
  padding: 20px 18px calc(18px + env(safe-area-inset-bottom));
  background: var(--card); border-radius: 18px 18px 0 0;
  box-shadow: 0 -8px 40px rgba(0, 0, 0, .22);
}
/* 손이 닿는 자리가 아래라 폰에서는 아래에 붙인다.
   화면이 넓으면 가운데로 띄운다 — 넓은 화면 아래쪽 끝은 오히려 멀다. */
@media (min-width: 640px) {
  .dlg { align-items: center; }
  .dlg-box {
    border-radius: 18px; padding: 22px 20px;
    animation: ui-zoom .2s cubic-bezier(.22, .9, .26, 1);
  }
  /* 가운데 뜨는 창은 잡아당길 것이 아니다. 손잡이를 뗀다. */
  .dlg-box::before { display: none; }
  .dlg.out .dlg-box { animation: ui-zoom .16s ease-in reverse; }
}
/* 위쪽의 짧은 손잡이. 잡아당겨 닫는 창이라는 표시다 — 폰에서 아래에서 올라오는
   창에는 거의 다 있어서, 없으면 그것만으로 웹페이지처럼 보인다. */
.dlg-box::before {
  content: ''; display: block; width: 38px; height: 4px;
  margin: -8px auto 16px; border-radius: 2px; background: var(--line);
}
.dlg-box:focus { outline: none; }
.dlg-title { margin: 0; font-size: 17.5px; font-weight: 700; line-height: 1.4; }
.dlg-body {
  margin: 10px 0 0; color: var(--muted); font-size: 14.5px; line-height: 1.6;
}
.dlg-actions { display: grid; gap: 8px; margin-top: 18px; }
.dlg-actions button { padding: 14px; font-size: 15.5px; }
/* 지우는 단추는 빨갛다. 목록의 옅은 빨강과 달리 여기서는 꽉 채운다 —
   이 창은 되돌릴 수 없는 일을 묻는 자리다. */
.dlg-actions .danger { background: var(--bad); border-color: var(--bad); color: #fff; }

/* ── 브라우저 티를 지운다 ────────────────────────────────────
   앱처럼 안 느껴지는 것들은 대개 작은 데서 온다. 누를 때 도는 파란 네모,
   끝까지 당기면 튕기는 화면, 꾹 누르면 뜨는 글자 선택 메뉴 같은 것들이다. */
html {
  /* 화면 끝에서 더 당겨도 튕기지 않는다. 폰 브라우저의 '새로고침 당기기' 도 같이 막힌다 —
     현장에서 사진 목록을 훑다가 새로고침이 걸려 적던 것이 날아가는 일을 막는다. */
  overscroll-behavior-y: none;
}
* {
  /* 안드로이드에서 누를 때 도는 회색 네모를 없앤다. */
  -webkit-tap-highlight-color: transparent;
}
button, .button, summary, label, .top, .item-head, .chip, .tab, .trade, .say, .linky {
  /* 꾹 눌러도 글자가 잡히지 않게 한다. 앱의 단추는 글이 아니라 물건이다.
     **적은 내용(input·textarea)과 문서 글은 건드리지 않는다** — 거기서는 골라
     복사할 수 있어야 한다. */
  user-select: none; -webkit-user-select: none;
  /* 두 번 눌러 확대되는 것을 막는다. 누르고 나서 300ms 기다리던 것도 사라진다. */
  touch-action: manipulation;
}
/* **적는 칸은 되돌려 놓는다.** user-select 는 물려받는 성질이라, 위에서 label 을
   막으면 그 안에 든 입력칸까지 같이 막힌다 — 적어 둔 주소를 골라 복사하지 못하게 된다. */
input, textarea, select, [contenteditable] { user-select: text; -webkit-user-select: text; }
/* 누르는 순간 반응이 있어야 눌린 줄 안다. 현장에서는 화면을 흘깃 보므로
   0.1초라도 눌렸다는 표시가 있어야 두 번 누르지 않는다. */
button:active, .button:active { transform: scale(.985) translateY(1px); }
@media (prefers-reduced-motion: reduce) {
  button:active, .button:active { transform: none; }
}
/* 손으로 누르거나 코드가 손을 얹었을 때 두꺼운 검정 테가 도는 것을 없앤다.
   **자판으로 옮겨 다닐 때는 남긴다** — 그때는 어디에 있는지 보여야 한다. */
button:focus:not(:focus-visible), .button:focus:not(:focus-visible),
summary:focus:not(:focus-visible) { outline: none; }
button:focus-visible, .button:focus-visible, summary:focus-visible,
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* ── 로그인 화면 ────────────────────────────────────────────
   앱 화면과 달리 위쪽 띠가 없다. 여기서 할 일이 하나뿐이라 나눌 것이 없다. */
.auth-page { display: flex; min-height: 100vh; min-height: 100dvh; }
.auth {
  width: 100%; max-width: 420px; margin: auto;
  padding: 28px 16px calc(28px + env(safe-area-inset-bottom));
  display: grid; gap: 16px; align-content: center;
}
.auth-mark { text-align: center; display: grid; gap: 2px; justify-items: center; }
/* logo-mark.png 는 투명 바탕에 검정 그림이다.
   밝은 화면에서는 그대로 두고, 어두운 화면에서만 뒤집어 흰색으로 쓴다. */
.auth-logo { display: block; margin-bottom: 10px; }
@media (prefers-color-scheme: dark) {
  .auth-logo { filter: invert(1); }
}

/* 자동 로그인 같은 켬/끔 칸. 글자까지 눌러도 켜지도록 label 로 감싼다 —
   현장에서 작은 네모만 겨냥해 누르게 두면 몇 번씩 헛누른다. */
.check {
  display: flex; align-items: flex-start; gap: 10px; margin-top: 14px;
  font-size: 14px; color: var(--ink); cursor: pointer;
}
.check input { width: 20px; height: 20px; flex: none; margin: 1px 0 0; accent-color: var(--accent); }
.check small { display: block; font-size: 12.5px; color: var(--muted); font-weight: 400; }
.auth-mark h1 { font-size: 22px; }
.auth-card { display: grid; gap: 0; }
.auth-card h2 { font-size: 17px; }
.auth-lead { margin-top: 6px; }
.auth-go { margin-top: 16px; width: 100%; padding: 14px; font-size: 15.5px; }
/* 아이디·비밀번호가 틀렸다는 말은 칸 바로 아래 있어야 한다.
   위쪽에 띄우면 폰에서 자판에 가려 안 보인다. */
.auth-msg { margin: 10px 0 0; font-size: 14px; line-height: 1.5; }
.auth-msg.bad { color: var(--bad); }
.auth-swap { text-align: center; margin-top: 14px; }
.auth-foot { text-align: center; }
/* 지금 저장된 자료가 어디로 가는지 알리는 자리. */
.auth-note {
  margin: 10px 0 0; padding: 11px 13px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  color: var(--muted); font-size: 13px; line-height: 1.6;
}
/* 글 안에 섞이는 단추. 링크처럼 보이되 단추라서 자판 조작이 그대로 통한다. */
.linky {
  padding: 0; border: 0; background: none; color: var(--accent);
  font: inherit; font-weight: 600; text-decoration: underline; cursor: pointer;
}

/* ── 누가 쓰고 있는지 ───────────────────────────────────────
   현장에서 폰을 돌려 쓰는 일이 있어서, 지금 누구로 들어와 있는지가
   늘 보여야 한다. 남의 이름으로 발행하면 되돌릴 수 없다. */
/* 이름과 작업장을 두 줄로 쌓는다. 옆으로 늘어놓으면 좁은 폰에서 단추를 밀어낸다.
   긴 이름은 잘라서 ... 로 둔다 — 줄어드는 것은 이름이지 단추가 아니다. */
.who {
  display: grid; gap: 0; margin: 0; text-align: right; line-height: 1.25;
  max-width: 40vw; font-size: 12px; color: var(--muted);
}
.who b, .who .ws { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.who b { color: var(--ink); font-weight: 600; font-size: 13px; }
.who .ws { font-size: 11px; }

/* 사람 부르기 — 초대 코드 */
.invite-code {
  display: block; margin: 10px 0 0; padding: 14px;
  background: var(--paper); border: 1px dashed var(--accent); border-radius: 10px;
  font: 700 22px/1.3 ui-monospace, "Consolas", monospace; letter-spacing: .12em;
  text-align: center; color: var(--ink); user-select: all;
}
.people { display: grid; gap: 8px; margin-top: 10px; }
.person, .invite-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 12px; background: var(--paper);
  border: 1px solid var(--line); border-radius: 10px; font-size: 14px;
}
.person .role, .invite-row .state { flex: none; font-size: 12px; color: var(--muted); }
.invite-row code { font: 600 14px/1 ui-monospace, "Consolas", monospace; letter-spacing: .08em; }
.invite-row.used, .invite-row.expired { opacity: .55; }

/* 우리가 하는 일 — 여러 개를 고르는 칸.
   글자까지 눌러도 켜지도록 label 로 감쌌다. 작은 네모만 겨냥하면 헛누른다. */
.trades { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 4px; }
.trade {
  display: flex; align-items: center; gap: 7px;
  padding: 9px 13px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--paper); font-size: 14px; color: var(--ink); cursor: pointer;
}
.trade input { width: 17px; height: 17px; margin: 0; flex: none; accent-color: var(--accent); }
/* 고른 것이 한눈에 보여야 한다. 테두리만으로는 훑을 때 안 잡힌다. */
.trade:has(input:checked) {
  border-color: var(--accent); color: var(--accent); font-weight: 600;
  background: color-mix(in srgb, var(--accent) 8%, var(--paper));
}

/* 카드 안에 작게 접어 두는 것. 위쪽 .fold 는 카드 자체를 접는 큰 틀이라
   여기 쓰면 여백이 어긋난다. */
.mini-fold { margin-top: 12px; }
.mini-fold > summary {
  padding: 10px 0; font-size: 14px; font-weight: 600; color: var(--accent); cursor: pointer;
}
.mini-fold > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* 지우는 단추. 옆 단추들과 같은 크기로 두되 색으로만 구별한다 —
   더 크게 만들면 현장에서 엄지가 먼저 닿는다. 되돌릴 수 없는 일이라 그러면 안 된다. */
.saved-links .danger { color: var(--bad); border-color: transparent; }
.saved-links .danger:hover, .saved-links .danger:focus-visible { border-color: var(--bad); }
/* 발행본이 있는 현장임을 목록에서 미리 알린다. 지우기 전에 보여야 한다. */
.sub .issued { color: var(--warn); font-weight: 600; }

/* ── 개요를 말로 채우기 ────────────────────────────────────
   제목 줄 안에 둔다. 현장에 도착해서 제일 먼저 누를 것이라 위쪽이 맞다. */
.say { flex: none; padding: 7px 12px; font-size: 13.5px; color: var(--accent); border-color: var(--line); white-space: nowrap; }
/* 제목이 단추에 밀려 두 줄로 깨지지 않게 한다. 넘치면 현장명 쪽이 줄어든다 —
   제목은 늘 온전히 보여야 어느 카드인지 안다. */
#fold-site > summary .fold-title { min-width: 0; flex: 1 1 auto; white-space: nowrap; }
#fold-site > summary #site-badge { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 기호는 24px 캔버스에 선 굵기 1.6으로 그려져 있다. 그대로 16px 로 줄이면
   선이 1픽셀 남짓이 되어 받침과 대가 화면에서 사라진다 — 몸통만 남아 "0" 처럼 보인다.
   작게 쓸 때는 선을 굵혀야 같은 무게로 읽힌다. */
.say .ic { width: 17px; height: 17px; stroke-width: 2.2; }
/* 듣는 중에는 눈에 띄어야 한다. 말하는 동안 화면을 안 보기 때문에,
   말을 마치고 봤을 때 아직 듣고 있다는 것이 한눈에 들어와야 한다. */
.say.on { background: var(--accent); border-color: var(--accent); color: #fff; }
@media (prefers-reduced-motion: no-preference) {
  .say.on { animation: say-pulse 1.4s ease-in-out infinite; }
}
@keyframes say-pulse { 50% { opacity: .72; } }

/* 듣는 동안 보여주는 자리.
   현장에서는 폰을 들고 말하느라 화면을 계속 볼 수 없다. 흘깃 봤을 때
   "들어가고 있다" 가 한눈에 들어와야 한다. */
.say-live {
  margin: 0 0 12px; padding: 12px 14px;
  background: color-mix(in srgb, var(--accent) 8%, var(--paper));
  border: 1px solid var(--accent); border-radius: 10px;
}
/* 소리 크기 막대. 말하면 움직이고, 말을 멈추면 줄어든다.
   이게 움직이면 마이크는 살아 있는 것이다 — 아직 글로 안 바뀌었더라도. */
/* 안내 글과 소리 켬/끔 단추를 한 줄에 놓되, 좁으면 단추가 아래로 내려간다. */
.say-top { display: flex; align-items: flex-start; gap: 10px; }
.say-top .say-guide { flex: 1 1 auto; min-width: 0; }
.say-voice { flex: none; font-size: 12.5px; white-space: nowrap; }

/* 무엇을 말해야 하는지. 굵은 줄은 빈 칸 목록, 작은 줄은 예시 한 문장이다. */
.say-guide { margin: 0 0 10px; font-size: 13.5px; line-height: 1.6; color: var(--ink); }
.say-guide small { display: block; margin-top: 4px; color: var(--muted); font-size: 12.5px; }
/* 어떻게 끝나는지. 이걸 모르면 다 말하고도 한없이 기다린다. */
.say-guide .say-how { margin-top: 7px; color: var(--accent); font-weight: 600; }

/* 받아 적히는 글. 말한 것이 제대로 들어갔는지 확인하는 유일한 길이라 크게 둔다.
   글이 실시간으로 늘어나는 것 자체가 "듣고 있다" 는 신호다.
   소리 크기 막대는 없앴다 — 그걸 그리려면 마이크를 하나 더 열어야 하는데,
   받아쓰기도 같은 마이크를 써서 둘이 부딪히면 인식이 나빠진다. */
.say-heard {
  margin: 10px 0 0; padding-left: 17px; position: relative;
  font-size: 15px; line-height: 1.55; color: var(--ink);
  min-height: 1.55em; word-break: keep-all; overflow-wrap: break-word;
}
.say-heard.empty { color: var(--muted); }
/* 왼쪽에서 깜박이는 점. 아직 아무 말도 안 했을 때도 살아 있음을 알린다. */
.say-heard::before {
  content: ''; position: absolute; left: 0; top: .5em;
  width: 9px; height: 9px; border-radius: 50%; background: var(--accent);
}
@media (prefers-reduced-motion: no-preference) {
  .say-heard::before { animation: say-blink 1.2s ease-in-out infinite; }
}
@keyframes say-blink { 50% { opacity: .25; } }
/* 아직 확정되지 않은 추측. 흐리게 보여 준다 — 바뀔 수 있는 글이라서다. */
.say-heard .guess { color: var(--muted); }
.say-state {
  margin: 0 0 12px; padding: 10px 12px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  font-size: 13.5px; line-height: 1.6; color: var(--muted);
}
.say-state.warn { color: var(--warn); border-color: var(--warn); }
.say-state.bad { color: var(--bad); border-color: var(--bad); }

/* 개요를 한 번에 비우는 단추. 아래쪽에 조용히 둔다 —
   자주 쓸 것이 아니고, 위에 두면 저장 단추 옆에서 잘못 눌린다. */
.site-clear {
  margin-top: 14px; padding: 9px 14px; font-size: 13.5px;
  color: var(--muted); border-color: var(--line);
}
.site-clear:hover, .site-clear:focus-visible { color: var(--bad); border-color: var(--bad); }

/* 말로 채워진 칸. 사람이 적은 것과 구별되어야 확인하고 넘어간다. */
.from-voice { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--paper)); }
