/* The game's shared look — begun as the ADR-APP-006 Phase C prototype sheet,
   moved to ui/ and rethemed to the website's palette by ADR-WEB-002 D2: the
   game now sits inside a site page, so its colors are the site's (soft cream
   paper, indigo brand, deep ink blue in the dark theme — the values in the
   site's _sass/minima.scss). The font stack leads with DM Sans, the site's
   body face; pages that load it from Google Fonts get the match, pages opened
   off disk fall back to the system face. */

:root {
  --bg: #f2f0ea;
  --surface: #fdfcf8;
  --ink: #2c2a26;
  --muted: #6b6b78;
  --line: #d3cfc3;
  --black-cell: #1c2130;
  --filled: #dde4f4;
  --filled-ink: #2b3f6e;
  --preview: #c2cde8;
  --accent: #3b5998;
  --bad: #c0392b;
  --good: #1f8b4c;
}

/* The dark palette applies twice: when the system asks for dark and the
   player hasn't overridden it, and when the shell's theme setting says dark
   outright (data-theme is set on <html> by the settings screen and by each
   page's head snippet). The two blocks below must stay identical — CSS has no
   way to name one block from two conditions without a preprocessor, and this
   game builds nothing. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #151925;
    --surface: #1c2130;
    --ink: #eae7df;
    --muted: #9aa0b2;
    --line: #3a4156;
    --black-cell: #0b0d15;
    --filled: #2b3f6e;
    --filled-ink: #dbe4f8;
    --preview: #3c5185;
    --accent: #4b6cb7;
    --bad: #ef7d70;
    --good: #58c98a;
  }
}

:root[data-theme="dark"] {
  --bg: #151925;
  --surface: #1c2130;
  --ink: #eae7df;
  --muted: #9aa0b2;
  --line: #3a4156;
  --black-cell: #0b0d15;
  --filled: #2b3f6e;
  --filled-ink: #dbe4f8;
  --preview: #3c5185;
  --accent: #4b6cb7;
  --bad: #ef7d70;
  --good: #58c98a;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0.6rem 0.6rem calc(0.6rem + env(safe-area-inset-bottom));
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.45 "DM Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-height: 100vh;
  min-height: 100dvh;
}

/* --- top bar ------------------------------------------------------------ */

.bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.bar select,
.bar button {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  min-height: 2.2rem;
}

/* `width: 0` is what actually lets a <select> shrink — flex-basis alone leaves
   it sized to its longest option, which pushed Reset onto a second row. */
.bar select { flex: 1 1 auto; width: 0; min-width: 5rem; }

.bar button:active { background: var(--preview); }

.progress {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.85rem;
  margin-left: auto;
}

.blurb {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  min-height: 1.3em;
}

/* --- board -------------------------------------------------------------- */

main {
  display: flex;
  justify-content: center;
  flex: 1 1 auto;
  align-items: center;
}

.board {
  display: grid;
  gap: 2px;
  padding: 2px;
  background: var(--line);
  border-radius: 0.4rem;
  /* Fit the width, never taller than the space left over for everything else
     on the screen, and never so stretched that a 4-cell tutorial board fills a
     phone. The middle term was a flat 62vh until the shape picker arrived and
     added a row: a fraction of the viewport is the wrong way to say "what is
     left", because the chrome above and below the board is a fixed height, not
     a share of one. Measured at 390 px wide: the bar, message, picker, pad and
     onward strip come to 313 px, so 20rem is that with a little to spare. On a
     390x667 phone the old rule overflowed the screen by 17 px and the page
     scrolled; this one shrinks the board instead and it fits. Taller screens
     are unaffected — the width still binds there. `dvh` second, so browsers
     that have it use the honest height and the rest keep `vh`. */
  width: min(100%, calc(100vh - 20rem), calc(var(--cols) * 4rem));
  width: min(100%, calc(100dvh - 20rem), calc(var(--cols) * 4rem));
  aspect-ratio: 1;
  touch-action: manipulation;
}

.cell {
  background: var(--surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(0.6rem, calc(38 / var(--cols) * 1vmin), 2rem);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  user-select: none;
  cursor: pointer;
  border: 0;
  padding: 0;
  border-radius: 2px;
  /* The anchor the corner marks are positioned against. */
  position: relative;
}

/* --- pencil marks — ADR-APP-011 D3 --------------------------------------
   A cell's maybes: up to four small digits along its top-left, muted, at
   roughly a third of the number the cell would hold. They sit in one row in
   ascending order (the engine keeps the list sorted), so the same set of
   maybes always looks the same and re-reading your own workings is free.
   `em` sizes them against the cell's own clamped type size, so they shrink
   with the board; the `max()` floor is what stops four of them turning into
   an unreadable smudge on a 10x10 board on a phone, the smallest cell the
   game ships and the one the four-mark cap exists for. */
.marks {
  position: absolute;
  top: 1px;
  left: 2px;
  right: 2px;
  display: flex;
  gap: 0.16em;
  line-height: 1;
  font-size: max(0.36em, 6px);
  font-weight: 600;
  color: var(--muted);
  pointer-events: none;
}

.cell.black {
  background: var(--black-cell);
  cursor: default;
}

.cell.filled {
  background: var(--filled);
  color: var(--filled-ink);
}

.cell.preview { background: var(--preview); }

/* A pencil preview must not look like a placement preview, or the player finds
   out which one they were making only after the tap. Same cells, different
   promise: an outline where a placement fills. */
.board.pencil .cell.preview {
  background: var(--surface);
  outline: 2px dashed var(--accent);
  outline-offset: -2px;
}

.cell.hinted { outline: 2px solid var(--good); outline-offset: -2px; }

/* Tier-1 hints mark entries that cannot lead to the solution — the outline is
   the "bad" color where .hinted (a lead worth following) uses the good one.
   Here rather than per page because the shared board view renders it. */
.cell.wrong { outline: 2px solid var(--bad); outline-offset: -2px; }

.board.shake { animation: shake 0.25s; }

@keyframes shake {
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}

.board.solved { box-shadow: 0 0 0 3px var(--good); }

/* The solved celebration — ADR-APP-009 D3.

   A wave of highlight sweeps the board along its diagonals and settles back
   into the plain solved state: each cell lifts, flashes the "good" colour and
   returns, delayed by its own place in the wave. `--wave` is row + col, set on
   the cell when the board is built (../ui/board-view.js); the stylesheet
   cannot count cells for itself, and that is the whole of the JavaScript in
   this animation — no library, no build step, per ADR-APP-008 D3.

   The class goes on only for the placement that *completes* the board, never
   for a solved board restored or revisited, so the moment stays earned. */
.board.celebrate .cell:not(.black) {
  animation: solved-wave 0.6s ease-out;
  animation-delay: calc(var(--wave, 0) * 45ms);
}

@keyframes solved-wave {
  40% {
    transform: scale(1.12);
    background: var(--good);
    color: var(--surface);
  }
}

/* Reduced motion gets the instant highlight the game had before: the solved
   outline appears, nothing moves. The shell also declines to add the class at
   all in this case — this rule is the belt to that braces, and covers a player
   who changes the setting mid-animation. */
@media (prefers-reduced-motion: reduce) {
  .board.celebrate .cell:not(.black) { animation: none; }
  .board.shake { animation: none; }
}

/* --- message ------------------------------------------------------------ */

.message {
  min-height: 1.4em;
  text-align: center;
  font-size: 0.9rem;
  font-weight: 600;
}

.message.bad { color: var(--bad); }
.message.good { color: var(--good); }

/* --- the shape picker — ADR-APP-011 D4 ----------------------------------
   Four buttons saying how much of the chosen number a tap writes, each a
   picture of it rather than a word (the prompt asked for graphics), then the
   pencil switch. The strip sits directly above the number pad, one row on a
   phone; the board view builds it, so every page that draws a board has it. */

.picker {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.35rem;
}

.picker button {
  font: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  min-width: 2.6rem;
  min-height: 2.6rem;
  padding: 0 0.4rem;
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
}

.picker svg {
  width: 1.3rem;
  height: 1.3rem;
  display: block;
}

.picker .shape[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* The pencil answers a different question from the four shapes — "is this
   real?", not "how much?" — so D4 makes it a switch rather than a fifth
   choice. It is pill-shaped, captioned, set apart by a margin, and never wears
   the accent colour that means "this is the shape you picked". */
.picker .pencil {
  margin-left: 0.5rem;
  border-radius: 1.3rem;
  padding: 0 0.7rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
}

.picker .pencil[aria-pressed="true"] {
  background: var(--filled);
  border-color: var(--filled-ink);
  color: var(--filled-ink);
}

/* --- number pad --------------------------------------------------------- */

.pad {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem;
}

.pad button {
  font: inherit;
  font-weight: 700;
  font-size: 1.1rem;
  min-width: 2.6rem;
  min-height: 2.6rem;
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
}

.pad button[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.pad button:disabled {
  opacity: 0.35;
  cursor: default;
}

/* --- the way on ---------------------------------------------------------- */

/* The strip under the pad: the tutorial's next-step button, the shell's
   next-puzzle link. Shared because both pages build the same strip. */
.onward {
  display: flex;
  justify-content: center;
  min-height: 2.6rem;
}

.onward a,
.onward button {
  font: inherit;
  font-weight: 700;
  padding: 0.5rem 1.2rem;
  border: 1px solid var(--accent);
  border-radius: 0.5rem;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  text-decoration: none;
}

.onward .back {
  background: none;
  border-color: var(--line);
  color: var(--muted);
  font-weight: 400;
  margin-right: 0.5rem;
}

/* --- help --------------------------------------------------------------- */

.how {
  font-size: 0.85rem;
  color: var(--muted);
}

.how summary { cursor: pointer; }

.how p { margin: 0.5rem 0 0; }
