:root {
  --bg: #f4f6f9;
  --fg: #2c3542;
  --muted: #7b8698;
  --line: #cdd5e0;
  --cell-bg: #ffffff;
  --block: #8b95a6;
  --block-peer: #78849a;
  --block-sel: #5f6d87;
  --clue-bg: #55637a;
  --clue-fg: #f2f5f9;
  --clue-done: #6f9e63;
  --sel: #d9e4f2;
  --peer: #e3ecf6;
  --wrong: #c1503f;
  --key-bg: #dfe5ee;
  --btn-bg: #55637a;
  --btn-fg: #f2f5f9;
  --sheet-bg: #ffffff;
  --hint-ring: #c9962f;
  /* 판이 쓸 수 있는 폭을 칸 크기 계산에서 다시 세야 해서 둘 다 변수로 둔다.
     한쪽에만 적어 두면 같은 수식을 두 곳에 쓰게 되고, 한쪽만 고치면 어긋난다. */
  --pad-x: clamp(10px, 4vmin, 28px);
  --app-max: 440px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #171b21;
    --fg: #dfe5ee;
    --muted: #8892a3;
    --line: #333c49;
    --cell-bg: #212832;
    --block: #6a7488;
    --block-peer: #7c8aa4;
    --block-sel: #93a1bd;
    --clue-bg: #39424f;
    --clue-fg: #dfe5ee;
    --clue-done: #5e8a54;
    --sel: #38465c;
    --peer: #2e3a4a;
    --wrong: #e0705c;
    --key-bg: #333c49;
    --btn-bg: #4a5568;
    --sheet-bg: #212832;
    --hint-ring: #d8a13a;
  }
}

* { box-sizing: border-box; }
html, body { margin: 0; min-height: 100%; }

body {
  background: var(--bg);
  color: var(--fg);
  font-family: "Pretendard", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  display: flex;
  justify-content: center;
  padding: clamp(10px, 3vmin, 24px) var(--pad-x);
}

.app {
  width: min(100%, var(--app-max));
  display: flex;
  flex-direction: column;
  gap: clamp(8px, 2vmin, 14px);
}

/* 게임마다 헤더가 제각각이면 게임을 옮겨 다닐 때 목록으로 돌아가는 길을 매번
   다시 찾게 된다. 네 게임 모두 목록은 왼쪽 위, 이름은 가운데로 맞춘다.
   양옆을 1fr로 묶으면 좌우 내용의 폭이 달라도 이름이 화면 한가운데에 온다. */
.title-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
}

.title-row h1 { text-align: center; }
.title-row .head-nav { justify-self: start; }
.head-nav { display: flex; align-items: center; gap: 14px; }
.title-row .head-actions { justify-self: end; }

h1 {
  margin: 0;
  font-size: clamp(24px, 6vmin, 34px);
  font-weight: 800;
  letter-spacing: -0.02em;
}

.head-actions { display: flex; align-items: baseline; gap: 14px; }

.toggle {
  border: 0; background: none; padding: 0;
  color: inherit; font-family: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer; opacity: 0.6;
}
.toggle:hover { opacity: 1; }

.back {
  color: inherit; opacity: 0.6; text-decoration: none;
  font-size: 14px; font-weight: 600;
}
.back:hover { opacity: 1; }

.picker-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.picker { display: flex; gap: 4px; }

.pick {
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: inherit;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 4px 10px;
  cursor: pointer;
}

.pick[aria-pressed="true"] {
  background: var(--btn-bg);
  border-color: var(--btn-bg);
  color: var(--btn-fg);
}

.toggle.sound { font-size: 12px; }

/* 취소선은 소리 토글에만 준다. 도움말 토글의 꺼짐은 "안 열림"이라 뜻이 다르다. */
.toggle.sound[aria-pressed="false"] { opacity: 0.38; text-decoration: line-through; }

/* 크기를 고르지 않게 됐으므로 지금 몇 칸짜리인지는 화면이 말해 줘야 한다.
   판을 세어 보게 하지 않으려는 것이라, 난이도 옆에 조용히 붙인다. */
.size {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.timer {
  margin-inline-start: auto;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* 판을 만드는 동안에도 "만드는 중" 가림막이 자리를 차지해야 한다. 크기를
   미리 모르게 되면서 첫 판은 격자가 없는 채로 시작하는데, 가림막은 이 상자에
   맞춰 늘어나므로 상자가 0이면 아무것도 안 보인다. 가장 작은 4×4 판도 이보다
   높아서 실제 판을 밀어내지는 않는다. */
.board-wrap { position: relative; min-height: 180px; }

/* 격자 옆과 아래에 단서 줄이 한 칸씩 더 붙는다. */
.board {
  /* 더블클릭으로 칸을 순환시키므로 그때 글자가 선택되지 않게 막는다. */
  user-select: none;
  /* 화면 폭에 맞춰 줄이는 항이 필요하다. 화면 비율만 보면 7×7(단서 줄까지 여덟
     칸)이 좁은 폰에서 판 폭을 넘어 옆으로 잘린다. --cols는 buildBoard가 넣는다. */
  --cell: min(clamp(34px, 11vmin, 52px),
    calc((min(100vw - 2 * var(--pad-x), var(--app-max)) - (var(--cols) - 1) * 2px) / var(--cols)));
  display: grid;
  gap: 2px;
  width: max-content;
  margin-inline: auto;
}

.cell, .clue, .corner {
  width: var(--cell);
  height: var(--cell);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  font-family: inherit;
  font-weight: 700;
  padding: 0;
  border: 0;
}

.cell {
  position: relative;
  background: var(--cell-bg);
  color: inherit;
  font-size: calc(var(--cell) * 0.5);
  cursor: pointer;
  box-shadow: inset 0 0 0 1px var(--line);
}

.cell.wrong { color: var(--wrong); }
.cell.peer { background: var(--peer); }
.cell.selected { background: var(--sel); box-shadow: inset 0 0 0 2px var(--btn-bg); }

/* 검은 칸 규칙은 강조 규칙보다 뒤에 와야 한다. 앞에 두면 같은 특정도라 순서에
   밀려 강조 배경이 블록을 덮어버리고, 블록을 놓았는지 아닌지 구분이 안 된다.
   강조는 배경을 갈아끼우는 대신 블록 색을 밝기만 달리해서 표시한다. */
.cell.block { background: var(--block); box-shadow: none; }
.cell.block.peer { background: var(--block-peer); }
.cell.block.selected { background: var(--block-sel); box-shadow: inset 0 0 0 2px var(--btn-bg); }
/* 힌트가 짚은 칸. 설명이 사라질 때까지 남긴다 — 한 번에 여러 칸이 좁혀지는
   경우가 있어, 반짝하고 마는 표시로는 어디를 봐야 하는지 놓친다. 검은 칸이나
   선택 표시 위에서도 보이도록 그것들과 같은 구체성으로 둔다. */
.cell.hinted,
.cell.block.hinted,
.cell.selected.hinted {
  animation: flash 900ms ease-out;
  box-shadow: inset 0 0 0 2px var(--hint-ring);
}

@keyframes flash {
  0%, 100% { background: var(--cell-bg); }
  25% { background: #f0c674; }
}

/* 연필 표시는 자리를 고정해야 어떤 숫자가 빠졌는지 눈으로 셀 수 있다. */
.marks {
  position: absolute;
  inset: 2px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  font-size: calc(var(--cell) * 0.24);
  font-weight: 600;
  color: var(--muted);
  line-height: 1;
  pointer-events: none;
}
.marks span { display: flex; align-items: center; justify-content: center; }
/* ■는 같은 크기로 두면 숫자 후보 사이에서 혼자 튄다. */
.marks .mark-block { font-size: 0.72em; }

.clue {
  background: var(--clue-bg);
  color: var(--clue-fg);
  font-size: calc(var(--cell) * 0.42);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.clue:hover { filter: brightness(1.15); }
.clue:active { filter: brightness(0.9); }

/* 그 줄이 규칙과 합을 모두 만족하면 단서를 지운 것으로 표시한다. */
.clue.done { background: var(--clue-done); }
.clue.broken { background: var(--wrong); }

.corner { background: none; }

.veil {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg) 75%, transparent);
  font-weight: 700;
  color: var(--muted);
}
.veil[hidden] { display: none; }

.toast {
  margin: 0;
  min-height: 20px;
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--muted);
}

/* 힌트 설명처럼 남겨 두는 안내는 여러 줄이 되므로, 읽을 것이 있다는 게
   보이도록 상자에 담고 눌러서 닫을 수 있게 한다. */
.toast.persist {
  text-align: left;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--cell-bg);
  color: var(--fg);
  cursor: pointer;
}

/* 앱의 조합 패널처럼, 고른 칸이 속한 줄의 합을 만들 수 있는 숫자 조합을 보여준다.
   이 퍼즐에서 사람이 실제로 손에 쥐고 따지는 정보다. */
.combos {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--cell-bg);
  font-size: 13px;
}
.combos[hidden] { display: none; }

.combo-line { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.combo-head { font-weight: 700; color: var(--muted); flex: none; }
.combo-set {
  display: inline-flex;
  gap: 3px;
  padding: 2px 6px;
  border-radius: 5px;
  background: var(--key-bg);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.combo-none { color: var(--muted); }

.pad { display: flex; flex-direction: column; gap: 8px; }

.digits { display: grid; gap: 5px; }

.digit {
  height: clamp(38px, 7.5vmin, 48px);
  border: 0;
  border-radius: 7px;
  background: var(--key-bg);
  color: inherit;
  font-family: inherit;
  font-size: clamp(16px, 4vmin, 20px);
  font-weight: 700;
  cursor: pointer;
  padding: 0;
}
.digit:active { filter: brightness(0.92); }
.digit.done { opacity: 0.3; }
.digit.block-key { background: var(--block); color: #fff; }

.tools { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; }

.tool {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 7px 0;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: none;
  color: inherit;
  font-family: inherit;
  cursor: pointer;
}
/* 도구 아이콘은 글자가 아니라 도형이다(`shared/icons.js`). 기호 문자로 두었더니
   글꼴마다 크기와 두께가 달랐고, 아예 안 그리는 글꼴도 있었다. */
.tool-icon { display: inline-flex; line-height: 0; }
.tool-icon svg { width: 19px; height: 19px; }
.tool-label { font-size: 11px; font-weight: 600; opacity: 0.8; }
.tool:disabled { opacity: 0.35; cursor: default; }
.tool[aria-pressed="true"] {
  background: var(--btn-bg);
  border-color: var(--btn-bg);
  color: var(--btn-fg);
}

.sheet {
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--sheet-bg);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.sheet[hidden] { display: none; }

.sheet-title { margin: 0; font-size: 19px; font-weight: 800; }
.sheet-note { margin: 0; font-size: 14px; color: var(--muted); }
.sheet-actions { display: flex; gap: 8px; }

.btn {
  flex: 1;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 0;
  border-radius: 8px;
  padding: 11px 16px;
  font-size: 15px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
}

.help-list {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 14px;
  line-height: 1.55;
}

@media (prefers-reduced-motion: reduce) {
  .cell.hinted { animation-duration: 1ms; }
}
