/* S-Cube 컨트롤 — 스타일. 외부 폰트·CDN 없음(오프라인 동작). */
:root {
  /* ★페이지는 흰 바탕, **계기·조작부는 어둡거나 색을 쓴다** (2026-08-07 사용자 결정).
   * 처음 밝은 테마로 바꿨을 때 전부 흰색이라 어디가 조작부인지 눈에 안 잡혔다.
   * ⟹ 문서(카드·글)는 밝게, **그래프·게이지·로그·버튼은 어둡게** 갈랐다.
   *   그래프가 어두운 건 취향이 아니라 실용이다 — 밝은 선 3가닥이 검은 바탕에서
   *   가장 잘 갈라진다(계측기가 다 그렇게 생긴 이유). */
  --bg: #ffffff;
  --panel: #ffffff;
  --panel2: #eef2f7;      /* 카드 머리 */
  --line: #d5dbe1;
  --tx: #1c2126;
  --dim: #5f6b76;
  --accent: #0a68d4;
  --ok: #12803a;
  --warn: #8a5d00;
  --bad: #c62a35;

  /* ── 어두운 구역 (그래프·게이지·로그·매트릭스) ─────────────────────── */
  --dark:      #131a23;   /* 계기 바탕 */
  --dark2:     #1d2733;   /* 그 위의 트랙·비활성 */
  --chart:     #131a23;
  --chart-grid:#232f3d;   /* 눈금선 */
  --chart-axis:#3a4a5c;   /* 0 기준선 */
  --chart-tx:  #8fa0b3;   /* 그래프 위 글자 */
  --tilt-ring: #4a5f78;   /* 기울기 원판의 안내 원·십자 — 그래프 눈금보다 진하게.
                             ⚠️여기는 "읽는 눈금"이 아니라 **기울기를 가늠하는 자**라
                             보이지 않으면 원판이 그냥 검은 동그라미가 된다(사용자 신고) */
  /* 그래프 선 — 어두운 바탕이라 **밝고 선명한** 색을 쓴다 */
  --gx: #ff7b72;
  --gy: #7ee787;
  --gz: #79c0ff;

  /* ── 버튼 ─────────────────────────────────────────────────────────── */
  --btn:       #2f3a47;   /* 흰 페이지 위에서 "누를 것"으로 바로 읽힌다 */
  --btn-hover: #3d4b5a;
  --btn-tx:    #eef2f7;

  --panel-dark: #10151b;  /* 매트릭스 패널(장치 흉내) 전용 */
  --dot-off: #2a323c;     /* 〃 꺼진 점 — 어두운 패널 위라 밝은 회색을 쓰면 반대로 보인다 */
  /* 어두운 트랙 위의 **채움색**은 밝은 쪽을 쓴다 — 흰 바탕용 --accent/--ok 를 그대로 쓰면
   * 어두운 트랙과 대비가 안 서서 얼마나 찼는지 안 보인다. */
  --fill:     #4aa3ff;
  --fill-ok:  #3fb950;
  --fill-bad: #f85149;
  --r: 10px;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--tx);
  font: var(--fs-tx)/1.5 "Malgun Gothic", "맑은 고딕", system-ui, sans-serif;
}
button, input, select { font: inherit; color: inherit; }

/* ── 상단 바 ─────────────────────────────────────────────────────────── */
/* ★머리줄은 **언제나 한 줄**이다 (2026-08-20 대표 신고 —
 *   「소개 자료·수업 준비·수업 현황에 로보초등학교가 아랫쪽에 보인다」).
 *   원인은 flex-wrap 이었다. 창이 1400px 언저리보다 좁으면 학교·학년·반 표시가
 *   둘째 줄로 넘어가, 탭 아래에 학교 이름만 덩그러니 남았다 — 본문의 일부처럼 보인다.
 *   ⟹ 줄바꿈을 막고, 자리가 모자라면 **탭이 옆으로 밀려 넘어간다**(아래 .mtabs).
 *     그래도 모자라면 학교 표시를 접는다 — 셋 중 가장 덜 급한 것이다
 *     (수업 코드는 「수업 QR」 단추가, 학교·반은 수업 현황이 그대로 보여 준다). */
header {
  position: sticky; top: 0; z-index: 20; box-shadow: 0 1px 3px rgba(0,0,0,.05);
  display: flex; align-items: center; gap: 12px; flex-wrap: nowrap;
  padding: 10px var(--pad-x); background: var(--panel); border-bottom: 1px solid var(--line);
}
header > strong { white-space: nowrap; }
h1 { font-size: var(--fs-h2); margin: 0 8px 0 0; letter-spacing: .5px; }
h1 small { color: var(--dim); font-weight: normal; font-size: var(--fs-tx); }
.dot { width: 10px; height: 10px; border-radius: 50%; background: var(--bad); display: inline-block; }
.dot.on { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.dot.busy { background: var(--warn); }
#devName { font-family: var(--font-ui); color: var(--accent); }
.spacer { flex: 1; }

button {
  background: var(--btn); color: var(--btn-tx);
  border: 1px solid transparent; border-radius: 8px;
  padding: 7px 12px; cursor: pointer; transition: .12s;
}
button:hover:not(:disabled) { background: var(--btn-hover); }
button:disabled { opacity: .4; cursor: not-allowed; }
button.primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: bold; }
button.primary:hover:not(:disabled) { background: var(--acc-ink); }
button.on { background: var(--ok); border-color: var(--ok); color: #fff; }
input[type=number], input[type=text], select {
  background: #fff; color: var(--tx); border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; width: 92px;
}

/* ── 레이아웃 ────────────────────────────────────────────────────────── */
main { display: grid; grid-template-columns: 1fr 400px; gap: 14px; padding: 14px; align-items: start; }
@media (max-width: 1100px) { main { grid-template-columns: 1fr; } }
.col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.card > h2 {
  margin: 0; padding: 9px 13px; font-size: var(--fs-tx); letter-spacing: .3px;
  background: var(--panel2); border-bottom: 1px solid var(--line); color: var(--tx); font-weight: 600;
  display: flex; align-items: center; gap: 8px;
}
.card > h2 .badge { margin-left: auto; font-size: var(--fs-mini); }
/* ★카드 제목 옆의 명령 번호 — "값"으로 오해되던 것을 눌러 놓는다(2026-08-07 사용자 신고:
 * "그룹 번호 0x23" 을 그룹 값 0x23 으로 읽었다). 작고 흐리게, "명령" 이라고 붙여서. */
.cmdid {
  font-weight: normal; font-size: var(--fs-mini); color: var(--dim);
  background: var(--line); border: 1px solid var(--line); border-radius: 4px;
  padding: 1px 6px; letter-spacing: 0;
}
.card .body { padding: 13px; }

/* ── 상태 타일 ───────────────────────────────────────────────────────── */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); gap: 9px; }
.tile { background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: 9px 11px; }
.tile .v { color: var(--accent); }
.tile .k { font-size: var(--fs-mini); color: var(--dim); }
.tile .v { font-size: var(--fs-h1); font-family: var(--font-ui); line-height: 1.25; }
.tile .u { font-size: var(--fs-mini); color: var(--dim); }
.tile.good .v { color: var(--ok); }
.tile.warn .v { color: var(--dim); }
.tile.bad .v { color: var(--tx); }

/* 배터리 — 스펙 §2.2.1: 1% 단위지만 오차 ±10~15%라 "구간으로 뭉개서" 보인다 */
.batt { display: flex; gap: 3px; margin-top: 5px; }
.batt i { flex: 1; height: 7px; background: var(--dark2); border-radius: 2px; }
.batt i.f { background: var(--fill-ok); }
.batt i.f.low { background: var(--fill-bad); }

/* ── 그래프 ──────────────────────────────────────────────────────────── */
canvas { display: block; width: 100%; background: var(--chart); border-radius: 8px; }
.legend { display: flex; gap: 14px; font-size: var(--fs-mini); color: var(--dim); margin-top: 7px; }
.legend b { font-weight: normal; }
.legend .x { color: var(--gx); } .legend .y { color: var(--gy); } .legend .z { color: var(--gz); }

/* ── 바 게이지 ───────────────────────────────────────────────────────── */
.gauge { margin-bottom: 11px; }
.gauge .lab { display: flex; font-size: var(--fs-tx); color: var(--dim); margin-bottom: 4px; }
.gauge .lab b { margin-left: auto; font-family: var(--font-ui); color: var(--tx); font-weight: normal; }
.bar { height: 9px; background: var(--dark2); border-radius: 5px; overflow: hidden; }
.bar > span { display: block; height: 100%; background: var(--fill); width: 0; transition: width .1s linear; }

/* ── 버튼 이벤트 램프 ────────────────────────────────────────────────── */
.btnstate { display: flex; align-items: center; gap: 12px; }
.lamp { width: 46px; height: 46px; border-radius: 50%; background: var(--dark); border: 2px solid var(--dark2); transition: .08s; }
.lamp.on { background: var(--fill); border-color: var(--fill); box-shadow: 0 0 18px var(--fill); }

/* ★★`hidden` 은 **어떤 display 규칙보다 세야 한다** (2026-08-10 실기 신고로 발견).
 * 브라우저 기본 `[hidden]{display:none}` 은 **클래스 규칙보다 약하다** ⟹ 아래 `.row{display:flex}`
 * 가 이겨서 `el.hidden = true` 가 **아무 일도 하지 않았다** — 보정이 끝나도 "잡는 중…" 문장이
 * 그대로 남던 원인이다. 같은 이유로 `analogRow` 도 I2C 센서가 잡혔을 때 안 숨겨지고 있었다.
 * ⟹ 개별 선택자(`.modal[hidden]`)로 한 줄씩 막지 말고 **여기서 한 번에** 못박는다. */
[hidden] { display: none !important; }

/* ── 제어 패널 ───────────────────────────────────────────────────────── */
.row { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-bottom: 9px; }
.row:last-child { margin-bottom: 0; }
.row > .lbl { width: 78px; font-size: var(--fs-tx); color: var(--dim); flex-shrink: 0; }
.hint { font-size: var(--fs-mini); color: var(--dim); margin: 7px 0 0; line-height: 1.5; }
.hint.warn { color: var(--dim); }

.badge { padding: 2px 8px; border-radius: 999px; font-size: var(--fs-mini); border: 1px solid var(--line); color: var(--dim); }
.badge.ok { color: var(--ok); border-color: var(--ok); }
.badge.warn { color: var(--dim); border-color: var(--warn); }
.badge.bad { color: var(--tx); border-color: var(--bad); }

/* ── 로그 ────────────────────────────────────────────────────────────── */
/* ★2026-08-20 — 어두운 판을 걷어냈다. 본문 글자색은 진한 회색·연한 회색 둘뿐이고,
   급한 줄은 색이 아니라 **굵기**로 가른다(색약 학생·교사도 같이 읽는다). */
#log { height: 210px; overflow-y: auto; font-family: var(--font-ui); font-size: var(--fs-tx); padding: 9px 12px;
  background: var(--subtle); color: var(--dim); border: 1px solid var(--line); border-radius: var(--r);
  font-variant-numeric: tabular-nums; }
#log div { padding: 1px 0; border-bottom: 1px solid var(--line); white-space: pre-wrap; word-break: break-all; }
#log .t  { color: var(--dim); }
#log .tx { color: var(--dim); }
#log .rx { color: var(--ok); }
#log .er { color: var(--tx); font-weight: 700; }
#log .wr { color: var(--tx); }

.notice {
  margin: 14px; padding: 12px 14px; border-radius: var(--r);
  background: var(--subtle); border: 1px solid var(--line); color: var(--tx); font-size: var(--fs-tx); line-height: 1.6;
}
.notice b { color: var(--tx); }
.notice code { background: var(--panel2); padding: 1px 5px; border-radius: 4px; }

/* ── 모달 (도트매트릭스 그림판) ─────────────────────────────────────────── */
.modal {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center;
}
.modal[hidden] { display: none; }
.modal-box {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
  max-width: 760px; width: calc(100% - 32px); max-height: calc(100vh - 32px); overflow: auto;
  box-shadow: 0 18px 60px rgba(0,0,0,.22);
}
.modal-box > h2 {
  margin: 0; padding: 11px 14px; font-size: var(--fs-tx); background: var(--panel2); color: var(--tx);
  border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 9px;
}
.modal-box > h2 small { color: var(--dim); font-weight: normal; }
.modal-box .x {
  margin-left: auto; padding: 2px 9px; font-size: var(--fs-tx); line-height: 1.4;
}
.modal-body { padding: 14px; display: flex; gap: 16px; flex-wrap: wrap; }
#mtxCanvas {
  width: 360px; height: 360px; flex-shrink: 0; cursor: crosshair;
  background: var(--panel-dark); border-radius: 8px; touch-action: none;
}
.mtx-side { flex: 1; min-width: 230px; }

.modal-box.wide { max-width: 980px; }
.mtx-frames {
  display: flex; gap: 6px; overflow-x: auto; padding: 10px 14px 14px;
  border-top: 1px solid var(--line); background: var(--panel2);
}
.mtx-fr {
  flex: 0 0 auto; text-align: center; cursor: pointer;
  border: 1px solid var(--line); border-radius: 6px; padding: 3px 3px 0; background: var(--panel-dark);
}
.mtx-fr:hover { border-color: var(--gz); }
.mtx-fr.on { border-color: var(--fill); box-shadow: 0 0 0 2px rgba(74,163,255,.35); }
.mtx-fr canvas { width: 48px; height: 48px; display: block; border-radius: 3px; }
.mtx-fr span { display: block; font-size: var(--fs-mini); color: var(--chart-tx); line-height: 1.6; }
.glyph-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: 8px; padding: 14px; max-height: 62vh; overflow-y: auto;
}
button.glyph { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 6px 3px; }
button.glyph canvas { width: 40px; height: 40px; border-radius: 3px; }
button.glyph span { font-size: var(--fs-mini); color: var(--btn-tx); }

.mtx-fr.off { opacity: .32; }          /* 재생 길이 밖 — 왜 안 나오는지 보이게 */
button.glyph small { font-size: var(--fs-mini); color: var(--dim); line-height: 1.3; }

/* ══════════════════════════════════════════════════════════════════════
 * 멀티 큐브 껍데기 (app_multi) — 위 3칸 요약, 아래 상세
 * 색 변수는 위 :root 를 그대로 쓴다. 여기서 새로 만들지 않는다.
 * ══════════════════════════════════════════════════════════════════════ */
header .tag {
  background: var(--panel2); border: 1px solid var(--line); border-radius: 999px;
  padding: 2px 10px; font-size: var(--fs-tx); color: var(--dim);
}
header .sp, .detail-head .sp { flex: 1; }
.inline { display: inline-flex; align-items: center; gap: 6px; color: var(--dim); font-size: var(--fs-tx); }

/* ── 슬롯 3칸 ─────────────────────────────────────────────────────────── */
.slots {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
  padding: 12px 0;
}
.slot {
  border: 1px solid var(--line); border-radius: var(--r); background: var(--panel);
  padding: 12px 14px; display: flex; flex-direction: column; gap: 8px;
  cursor: pointer; transition: border-color .15s, box-shadow .15s;
  border-top: 1px solid var(--line);
}
/* 큐브 1·2·3 = 빨강·초록·파랑. 실물 LED 와 같은 값이다(큐브_색규약_LED).
   ★위 띠만 3px 이다 — 회색 테두리가 아니라 「어느 큐브인가」를 알리는 표시라
     얇으면 멀리서 안 짚인다 (2026-08-20). 색이 없을 때는 다른 선과 같은 1px. */
.slot.c1 { border-top: 3px solid var(--cube1); }
.slot.c2 { border-top: 3px solid var(--cube2); }
.slot.c3 { border-top: 3px solid var(--cube3); }
.slot.empty { background: var(--subtle); cursor: default; }
/* 붙고 나면 그 자리 단추는 회색으로 가라앉는다 — 지우지 않는다 (2026-08-20) */
.acts button.done {
  background: var(--line); border-color: var(--line); color: var(--dim);
  cursor: default; font-weight: 600;
}
.acts button.done:hover { background: var(--line); }
.slot.sel { box-shadow: 0 0 0 1px var(--accent) inset; }
.slot-head { display: flex; align-items: center; gap: 8px; }
.chip {
  width: 22px; height: 22px; border-radius: 50%; color: #fff; font-size: var(--fs-tx); font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.chip.c1 { background: var(--cube1); } .chip.c2 { background: var(--cube2); } .chip.c3 { background: var(--cube3); }
.chip.c0 { background: var(--dim); }
.slot-name { font-weight: 700; font-size: var(--fs-tx); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slot-sub { color: var(--dim); font-size: var(--fs-tx); }
.slot-row { display: flex; align-items: center; gap: 10px; }
.slot canvas { width: 76px; height: 76px; flex: 0 0 auto; background: var(--dark); border-radius: 50%; }
.slot .mini { display: grid; grid-template-columns: auto 1fr; gap: 2px 8px; font-size: var(--fs-tx); }
.slot .mini span { color: var(--dim); }
.slot .mini b { font-family: var(--font-ui); font-weight: 400; }
.slot .acts { display: flex; gap: 6px; margin-top: auto; }
.slot .acts button { flex: 1; }

/* 배터리 5칸 */
.bt5 { display: inline-flex; gap: 2px; align-items: center; }
.bt5 i { width: 8px; height: 12px; background: var(--dark2); border-radius: 2px; display: block; }
.bt5 i.on { background: var(--fill-ok); }
.bt5 i.low { background: var(--fill-bad); }

/* ── 전체 동시 명령 바 ────────────────────────────────────────────────── */
.bcast {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 12px; padding: 10px 14px;
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r);
}
.bcast-title { font-weight: 700; font-size: var(--fs-tx); }
.bcast-n { color: var(--dim); font-size: var(--fs-tx); }
.bcast .sep { width: 1px; height: 20px; background: var(--line); }
.bcast.off { opacity: .5; pointer-events: none; }

/* ── 상세 ────────────────────────────────────────────────────────────── */
.detail { margin: 0 16px 16px; }
.detail-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding-bottom: 10px; border-bottom: 1px solid var(--line); margin-bottom: 12px;
}
.tabs { display: flex; gap: 4px; }
.tabs button {
  background: transparent; color: var(--dim); border: 1px solid transparent;
  border-radius: 8px 8px 0 0; padding: 7px 14px;
}
.tabs button.on { background: var(--panel2); color: var(--tx); border-color: var(--line); font-weight: 700; }
.pane { display: none; }
.pane.on { display: block; }
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 12px; }
.grid2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (max-width: 1100px) {
  .slots { grid-template-columns: 1fr; }
  .grid3, .grid2 { grid-template-columns: 1fr; }
}
.card canvas#tilt { display: block; margin: 0 auto; }
.card canvas#chGyro, .card canvas#chAcc { width: 100%; height: 180px; display: block; background: var(--chart); border-radius: 8px; }
.kv { width: 100%; font-size: var(--fs-tx); }
.kv td { padding: 3px 0; }
.kv td:first-child { color: var(--dim); width: 70px; }
.kv td:last-child { font-family: var(--font-ui); }

/* 게이지 */
.gg { display: grid; grid-template-columns: 54px 1fr 70px; gap: 8px; align-items: center; margin-bottom: 6px; }
.gg .lbl { color: var(--dim); font-size: var(--fs-tx); width: auto; }
.gg i { display: block; height: 14px; background: var(--dark2); border-radius: 4px; overflow: hidden; }
.gg i b { display: block; height: 100%; width: 0; background: var(--fill); transition: width .1s linear; }
.gg em { font-style: normal; font-family: var(--font-ui); font-size: var(--fs-tx); text-align: right; }

/* 버튼 램프 */
.lamp2 { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: var(--fs-tx); }
.lamp2 i { width: 14px; height: 14px; border-radius: 50%; background: var(--dark2); display: block; }
.lamp2 i.on { background: var(--fill-ok); box-shadow: 0 0 8px var(--fill-ok); }
.lamp2 b { margin-left: auto; font-family: var(--font-ui); }
.swatch { width: 22px; height: 22px; border-radius: 5px; border: 1px solid var(--line); display: inline-block; }

.bdg {
  font-size: var(--fs-mini); font-weight: 400; padding: 2px 8px; border-radius: 999px;
  background: var(--panel2); border: 1px solid var(--line); color: var(--dim);
}
.bdg.act { background: var(--acc-soft); border-color: transparent; color: var(--accent); }
button.danger { background: var(--bad); }
button.q { min-width: 56px; }
.foot { color: var(--dim); font-size: var(--fs-tx); padding: 0 16px 24px; }
#log .ok { color: var(--ok); }
.pickhint {
  margin: -4px 0 12px; padding: 8px 12px; font-size: var(--fs-tx); color: var(--dim);
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r);
}
.pickhint b { color: var(--tx); }

/* ── 모니터: 큐브 3열 ────────────────────────────────────────────────── */
.mongrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
@media (max-width: 1100px) { .mongrid { grid-template-columns: 1fr; } }
.moncard {
  border: 1px solid var(--line); border-radius: var(--r); background: var(--panel);
  padding: 12px 14px; border-top: 1px solid var(--line);
}
.moncard.c1 { border-top: 3px solid var(--cube1); }
.moncard.c2 { border-top: 3px solid var(--cube2); }
.moncard.c3 { border-top: 3px solid var(--cube3); }
.moncard.off { opacity: .5; }
.monhead { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.monhead b { font-size: var(--fs-tx); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.monhead .bdg { margin-left: auto; flex: 0 0 auto; }
.moncard canvas.tiltc { display: block; margin: 0 auto 6px; border-radius: 50%; background: var(--dark); }
.moncard canvas.chart { width: 100%; height: 130px; display: block; background: var(--chart); border-radius: 8px; }
.moncard h4 {
  font-size: var(--fs-tx); color: var(--dim); font-weight: 700;
  margin: 12px 0 5px; display: flex; gap: 6px; align-items: baseline;
}
.moncard h4 small { font-weight: 400; }
.moncard .num { font-family: var(--font-ui); font-size: var(--fs-mini); color: var(--dim); margin: 3px 0 0; }
