/* Sudoku board + controls for play.html. */

/* Vertical only: the `padding` shorthand here was resetting .wrap's own
   horizontal padding to 0, which put the board flush against both edges of a
   phone. Invisible on desktop, where max-width centres the board anyway. */
.play-wrap { padding-top: 28px; padding-bottom: 48px; }
.play-layout {
  display: grid; gap: 28px;
  grid-template-columns: minmax(0, 1fr) 300px;
  align-items: start;
}
@media (max-width: 900px) { .play-layout { grid-template-columns: minmax(0, 1fr); } }


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

.board-shell { max-width: 560px; }
.board {
  display: grid; grid-template: repeat(9, 1fr) / repeat(9, 1fr);
  aspect-ratio: 1; width: 100%;
  background: var(--line); gap: 1px;
  border: 2px solid var(--line-strong); border-radius: 6px; overflow: hidden;
  touch-action: manipulation; user-select: none;
}
.cell {
  background: var(--bg-raised); position: relative; cursor: pointer;
  display: grid; place-items: center; border: 0; padding: 0; font: inherit;
  color: var(--accent); font-size: clamp(18px, 4.6vw, 30px); font-weight: 500;
  font-variant-numeric: tabular-nums;
}
/* 3x3 box separators, drawn as inset shadows so they survive the 1px gap grid */
.cell[data-c="2"], .cell[data-c="5"] { box-shadow: inset -2px 0 0 -1px var(--line-strong); }
.cell[data-r="2"], .cell[data-r="5"] { box-shadow: inset 0 -2px 0 -1px var(--line-strong); }
.cell[data-c="2"][data-r="2"], .cell[data-c="2"][data-r="5"],
.cell[data-c="5"][data-r="2"], .cell[data-c="5"][data-r="5"] {
  box-shadow: inset -2px 0 0 -1px var(--line-strong), inset 0 -2px 0 -1px var(--line-strong);
}
.cell.given { color: var(--ink); font-weight: 600; }
.cell.peer { background: var(--bg-sunken); }
.cell.same { background: var(--accent-soft); }
.cell.sel { background: color-mix(in srgb, var(--accent) 26%, var(--bg-raised)); }
.cell.bad { color: var(--warn); }
.cell.bad::after {
  content: ""; position: absolute; inset: 0;
  background: color-mix(in srgb, var(--warn) 15%, transparent);
}
.cell:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 2; }

.notes {
  position: absolute; inset: 8%; display: grid;
  grid-template: repeat(3, 1fr) / repeat(3, 1fr);
  font-size: clamp(7px, 1.5vw, 10px); color: var(--ink-faint); font-weight: 500;
  line-height: 1; place-items: center; pointer-events: none;
}

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

/* One row: 1-9 plus Erase. Two rows split a keypad that reads better whole,
   and the row is short enough to stay comfortable even on a phone. */
.pad {
  display: grid; grid-template-columns: repeat(10, minmax(0, 1fr));
  gap: 6px; margin-top: 16px; max-width: 100%;
}
.pad button {
  aspect-ratio: 1 / 1.06; border: 1px solid var(--line); background: var(--bg-raised);
  color: var(--ink); border-radius: 9px; font: inherit; font-size: 15px; cursor: pointer;
  font-variant-numeric: tabular-nums; line-height: 1.1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.pad button:hover { border-color: var(--line-strong); }
.pad button:disabled { opacity: .3; cursor: default; }
.pad button.wide { grid-column: span 1; font-size: 17px; }
.pad .count { display: block; font-size: 8.5px; color: var(--ink-faint); margin-top: 1px; }

/* ---- side panel ---- */

.panel {
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px; margin-bottom: 14px;
}
.panel h3 { font-size: 14px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint); margin: 0 0 12px; font-weight: 600; }
.stat-row { display: flex; justify-content: space-between; gap: 12px; padding: 5px 0; font-size: 14px; }
.stat-row dt { color: var(--ink-soft); margin: 0; }
.stat-row dd { color: var(--ink); margin: 0; font-weight: 550; font-variant-numeric: tabular-nums; }
dl { margin: 0; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  font-size: 12px; padding: 4px 9px; border-radius: 999px;
  background: var(--bg-sunken); color: var(--ink-soft); border: 1px solid var(--line);
}
.chip.top { background: var(--accent-soft); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 34%, transparent); font-weight: 560; }

.panel .note { font-size: 13px; color: var(--ink-faint); margin: 12px 0 0; line-height: 1.5; }

/* ---- win banner ---- */

.banner {
  background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 16px;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.banner strong { color: var(--ink); }
.banner .t { color: var(--ink-soft); font-size: 14px; }
.banner[hidden] { display: none; }

/* Technique chips link to their guide page when one exists. */
a.chip { text-decoration: none; }
a.chip:hover { border-color: var(--accent); color: var(--accent); }

/* Hint highlighting. The pattern cells get the amber the guides use for
   "cells that establish the pattern"; the target gets the teal conclusion. */
.cell.hint-cell { background: color-mix(in srgb, var(--brand-amber) 26%, var(--bg-raised)); }
.cell.hint-target { background: color-mix(in srgb, var(--accent) 34%, var(--bg-raised)); }

.hint-note {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 14px; padding: 12px 14px; font-size: 14px;
  background: var(--accent-soft); color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
  border-radius: var(--radius);
}
.hint-note[hidden] { display: none; }
.hint-note strong { font-weight: 620; }
.hint-note span { color: var(--ink-soft); }
.hint-note a { margin-left: auto; white-space: nowrap; }
.hint-note button {
  background: none; border: 0; color: var(--ink-faint);
  cursor: pointer; font: inherit; padding: 0 2px;
}
.hint-note button:hover { color: var(--ink); }

/* ---- shaded-grid board (Hitori, Nurikabe, Battleship) ---- */

.sboard {
  display: grid;
  grid-template-columns: repeat(var(--n, 7), 1fr);
  aspect-ratio: 1; width: 100%; max-width: 520px;
  background: var(--line); gap: 1px;
  border: 2px solid var(--line-strong); border-radius: 6px; overflow: hidden;
  touch-action: manipulation; user-select: none;
}
.scell {
  background: var(--bg-raised); border: 0; padding: 0; margin: 0;
  display: grid; place-items: center; cursor: pointer; position: relative;
  font: inherit; font-weight: 560; color: var(--ink);
  font-size: clamp(14px, 3.4vw, 22px); font-variant-numeric: tabular-nums;
}
/* Unmarked cells read as undecided; painting commits them.

   These need their own tokens rather than --line-strong, which is near-black
   in light mode but light grey in dark mode. Using it made "sea" render
   LIGHTER than "land" in dark mode — backwards for a game whose sea is the
   wall. `off` is always the heavier state, `on` always the lighter one. */
/* Default shaded-grid states. Hitori and Nurikabe override these below —
   see the per-game blocks, which follow the app's own board rendering. */
.scell.on { background: var(--state-on); }
.scell.off { background: var(--state-off); color: var(--state-off-ink); }
.scell.clue { font-weight: 700; }
body[data-game="nurikabe"] .scell.clue::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  height: 74%; aspect-ratio: 1; transform: translate(-50%, -50%);
  border: 2px solid var(--accent); border-radius: 50%;
}
.scell.hint-cell { box-shadow: inset 0 0 0 2px var(--brand-amber); }
.scell.hint-target { box-shadow: inset 0 0 0 3px var(--accent); }
.scell:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 2; }

/* Tentative "maybe" marks — a corner flag, never a fill, so they can never be
   confused with a committed cell. */
.scell.note-on::before, .scell.note-off::before {
  content: ""; position: absolute; top: 3px; right: 3px;
  width: 8px; height: 8px; border-radius: 2px;
}
.scell.note-on::before { background: color-mix(in srgb, var(--accent) 70%, transparent); }
.scell.note-off::before { background: color-mix(in srgb, var(--brand-indigo) 70%, transparent); }

/* Edge-clue gutter (Battleship). The first row and column hold the counts. */
.sboard.has-gutter { background: transparent; gap: 2px; border: 0; }
.sboard.has-gutter .scell { border: 1px solid var(--line); }
.sclue {
  background: none; border: 0; padding: 0; cursor: pointer;
  display: grid; place-items: center; font: inherit; font-weight: 700;
  font-size: clamp(12px, 2.6vw, 17px); color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.sclue.met { color: var(--accent); }
.sclue.struck { color: var(--ink-faint); text-decoration: line-through; }
.sclue:hover { color: var(--ink); }

/* Battleship draws its two states as objects rather than tints: a ship is a
   solid rounded block, water is a dot on an empty cell. Shared JS, per-game
   presentation — the difference belongs in CSS, not in another code branch. */
body[data-game="battleship"] .scell.on { background: var(--bg-raised); }
body[data-game="battleship"] .scell.on::after {
  content: ""; position: absolute; inset: 12%;
  background: var(--accent); border-radius: 26%;
}
body[data-game="battleship"] .scell.off { background: var(--bg-raised); }
body[data-game="battleship"] .scell.off::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 17%; height: 17%; margin: -8.5% 0 0 -8.5%;
  background: var(--ink-faint); border-radius: 50%; opacity: .8;
}
/* A given is fixed by the puzzle — ring the cell so it reads as not-yours. */
body[data-game="battleship"] .scell.clue { box-shadow: inset 0 0 0 2px var(--ink-faint); }
body[data-game="battleship"] .scell.clue::before { content: none; }

/* ---- Latin-square board (Skyscrapers, Skyscrapers Plus) ----
   Clues sit on all four sides, so the grid is (n+2) wide with the outer ring
   holding them. Cells are plain — no boxes, unlike Sudoku. */

.lboard {
  display: grid; grid-template-columns: repeat(var(--n, 7), 1fr);
  aspect-ratio: 1; width: 100%; max-width: 520px;
  gap: 2px; touch-action: manipulation; user-select: none;
}
.lcell {
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: 3px; padding: 0; cursor: pointer; position: relative;
  display: grid; place-items: center; font: inherit;
  color: var(--accent); font-weight: 560;
  font-size: clamp(15px, 3.6vw, 26px); font-variant-numeric: tabular-nums;
}
.lcell.given { color: var(--ink); font-weight: 700; }
.lcell.peer { background: var(--bg-sunken); }
.lcell.same { background: var(--accent-soft); }
.lcell.sel { background: color-mix(in srgb, var(--accent) 26%, var(--bg-raised)); }
.lcell.bad { color: var(--warn); background: color-mix(in srgb, var(--warn) 16%, var(--bg-raised)); }
.lcell.hint-cell { box-shadow: inset 0 0 0 2px var(--brand-amber); }
.lcell.hint-target { box-shadow: inset 0 0 0 3px var(--accent); }
.lcell:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 2; }

/* Candidates are a flat list rather than a positional 3x3: these boards run
   4-6 wide, so there is no fixed slot per digit the way Sudoku has. */
.lnotes {
  font-size: clamp(7px, 1.5vw, 10px); color: var(--ink-faint);
  font-weight: 500; line-height: 1.15; letter-spacing: .04em;
  padding: 0 2px; text-align: center; word-break: break-all;
}
.lclue {
  display: grid; place-items: center; color: var(--ink-soft);
  font-weight: 700; font-size: clamp(11px, 2.4vw, 16px);
  font-variant-numeric: tabular-nums;
}

/* The pad sizes to the board: 4-6 digits plus Erase, not a fixed 5 columns. */
.pad.latin { grid-template-columns: repeat(var(--pad, 6), minmax(0, 1fr)); }

/* ---- Kakuro board ----
   Ragged: most cells are block or clue. Clue cells carry a diagonal with the
   across sum above it and the down sum below. */

.kboard {
  display: grid; grid-template-columns: repeat(var(--w, 9), 1fr);
  width: 100%; max-width: 540px; gap: 1.5px;
  background: var(--kakuro-grid); border: 2px solid var(--kakuro-grid);
  border-radius: 6px; overflow: hidden;
  touch-action: manipulation; user-select: none;
}
.kcell {
  position: relative; display: grid; place-items: center;
  font: inherit; font-variant-numeric: tabular-nums;
  aspect-ratio: 1; border: 0; padding: 0; margin: 0;
}
.kcell.block, .kcell.clue { background: var(--kakuro-block); }

/* The clue glyph fills its cell; the SVG viewBox keeps the diagonal and both
   sums exactly placed at any board size. */
.kglyph { position: absolute; inset: 0; width: 100%; height: 100%; }
.kslash { stroke: var(--kakuro-grid); stroke-width: 2.2; }
.ksum {
  fill: #fff; font-family: ui-sans-serif, system-ui, sans-serif;
  font-weight: 700; font-size: 30px;
}
.kcell.white {
  background: var(--kakuro-white); cursor: pointer;
  color: var(--accent); font-weight: 600;
  font-size: clamp(13px, 2.8vw, 22px);
}
.kcell.white.mate { background: color-mix(in srgb, var(--accent) 13%, var(--kakuro-white)); }
.kcell.white.sel { background: color-mix(in srgb, var(--accent) 32%, var(--kakuro-white)); }
.kcell.white.bad { color: var(--warn); background: color-mix(in srgb, var(--warn) 22%, var(--kakuro-white)); }
.kcell.white.hint-cell { box-shadow: inset 0 0 0 2px var(--brand-amber); }
.kcell.white.hint-target { box-shadow: inset 0 0 0 3px var(--accent); }
.kcell.white:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 2; }

.knotes {
  font-size: clamp(7px, 1.4vw, 10px); color: color-mix(in srgb, var(--ink) 55%, transparent);
  font-weight: 500; letter-spacing: .06em; line-height: 1.1;
  padding: 0 2px; word-break: break-all; text-align: center;
}

/* ---- Bridges board ----
   SVG, not a grid: a bridge is a line between two arbitrary points. */

.bboard { width: 100%; max-width: 520px; }
.bsvg { width: 100%; height: auto; display: block; touch-action: manipulation; }

/* The grid the islands sit on. Thin and quiet: it is there to give the board
   a shape and to show how far apart two islands are, not to be read. */
.bgrid line { stroke: var(--bridges-grid); stroke-width: 1; }
.bframe { fill: none; stroke: var(--bridges-grid); stroke-width: 1.6; }

.bspan line { stroke: var(--ink-soft); stroke-width: 2.4; stroke-linecap: round; }
.bspan.hint line { stroke: var(--accent); stroke-width: 3.4; }

/* Invisible but generous, so a 2px bridge is still comfortably tappable. */
.bhit {
  stroke: transparent; stroke-width: 16; cursor: pointer;
  pointer-events: stroke;
}
.bhit:hover { stroke: color-mix(in srgb, var(--accent) 14%, transparent); }

.bisland circle {
  fill: var(--bg-raised); stroke: var(--ink); stroke-width: 1.8;
}
.bisland text {
  fill: var(--ink); font: 700 15px ui-sans-serif, system-ui, sans-serif;
  text-anchor: middle; pointer-events: none;
}
/* An island whose clue is satisfied stops being something to look at. */
.bisland.met circle { stroke: var(--accent); fill: var(--accent-soft); }
.bisland.met text { fill: var(--accent); }
.bisland.over circle { stroke: var(--warn); fill: color-mix(in srgb, var(--warn) 18%, var(--bg-raised)); }
.bisland.over text { fill: var(--warn); }
.bisland.hint circle { stroke: var(--brand-amber); stroke-width: 3; }

/* ---- Slitherlink board ----
   State lives on the edges between dots, so this is SVG with a hit target per
   edge rather than per cell. */

.slboard { width: 100%; max-width: 520px; }
.slsvg { width: 100%; height: auto; display: block; touch-action: manipulation; }

.slcell { fill: transparent; }
.slcell.met { fill: color-mix(in srgb, var(--accent) 10%, transparent); }
.slcell.hint { fill: color-mix(in srgb, var(--brand-amber) 22%, transparent); }
.slclue {
  fill: var(--ink); font: 600 17px ui-sans-serif, system-ui, sans-serif;
  text-anchor: middle; pointer-events: none;
}
.sldot { fill: var(--ink-faint); pointer-events: none; }

.slline { stroke: var(--ink); stroke-width: 3.4; stroke-linecap: round; }
.slmark { stroke: var(--ink-faint); stroke-width: 1.8; stroke-linecap: round; }
.sledge.hint .slline { stroke: var(--accent); }
.sledge.hint .slmark { stroke: var(--accent); }

/* Invisible but generous — an edge is a hairline, a thumb is not. */
.slhit { stroke: transparent; stroke-width: 18; cursor: pointer; pointer-events: stroke; }
.slhit:hover { stroke: color-mix(in srgb, var(--accent) 16%, transparent); }

/* Generation runs in a Web Worker, so the board stays interactive while it
   works — this just says "something is happening" for the few hundred
   milliseconds a hard Battleship board takes. */
.board-shell.busy .sboard,
.board-shell.busy .bsvg,
.board-shell.busy .board {
  opacity: .45; transition: opacity .12s var(--ease);
}

/* Daily-mode banner, shown in place of the tier picker. */
.daily-tag {
  font-size: 13.5px; color: var(--ink-soft);
  padding: 6px 12px; border-radius: 999px;
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
}
.daily-tag a { color: var(--accent); text-decoration: none; font-weight: 560; }
.seg button:disabled { opacity: .4; cursor: not-allowed; }
/* `hidden` is only display:none in the UA sheet, so site.css's `.seg
   { display: flex }` wins and a hidden group still paints its pill. Hitori
   hides its tool picker outright (it cycles instead), so say it here. */
.seg[hidden] { display: none; }

/* ============================================================ polish pass
   The boards were flat rectangles while everything around them had gained
   elevation and rounding. Bring them into the same language. */

.board, .sboard, .kboard {
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.lboard, .bboard, .slboard { padding: 4px; }

/* Give the SVG boards a surface to sit on, like the grid boards have. */
.bboard, .slboard {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px;
}

/* Number pad: real buttons, not boxes. */
.pad button {
  border-radius: 12px;
  font-weight: 560;
  box-shadow: var(--shadow);
  transition: transform .16s var(--ease), border-color .16s var(--ease),
              background .16s var(--ease);
}
.pad button:hover:not(:disabled) {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
  background: color-mix(in srgb, var(--accent) 7%, var(--bg-raised));
}
.pad button:active:not(:disabled) { transform: translateY(0); }
.pad .count { letter-spacing: .02em; }

/* Side panels: match the card elevation on the rest of the site. */
.panel {
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.panel h3 { letter-spacing: .08em; font-size: 12.5px; }

/* Technique chips read as pills that invite a click when they link out. */
.chip {
  border-radius: 999px; padding: 5px 11px; font-size: 12.5px;
  transition: border-color .16s var(--ease), color .16s var(--ease),
              background .16s var(--ease), transform .16s var(--ease);
}
a.chip:hover {
  transform: translateY(-1px);
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}

/* The win banner should feel like a reward, not a notice. */
.banner {
  border-radius: var(--radius); padding: 16px 18px;
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--teal) 16%, var(--bg-raised)),
    color-mix(in srgb, var(--indigo) 12%, var(--bg-raised)));
  border-color: color-mix(in srgb, var(--teal) 38%, transparent);
  box-shadow: var(--shadow-lift);
}
.hint-note { border-radius: var(--radius); }

/* ==================================================== per-game board marks
   These follow the app's own rendering (GridWits/Views/*BoardView.swift), not
   a generic fill, because the shape of a mark is part of how each game reads.

   Hitori circles BOTH states — green for kept, red for rejected — and never
   fills the cell, so the number stays readable either way. An unmarked cell
   shows no circle at all: an open choice, not a default. Taps cycle through
   the three, so a player meets all of them without a picker. */

body[data-game="hitori"] .scell.on,
body[data-game="hitori"] .scell.off {
  background: var(--bg-raised); color: var(--ink);
}
body[data-game="hitori"] .scell.on::after,
body[data-game="hitori"] .scell.off::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  height: 78%; aspect-ratio: 1; transform: translate(-50%, -50%);
  border-radius: 50%; border: 2.5px solid currentColor;
  pointer-events: none;
}
body[data-game="hitori"] .scell.on::after  { color: var(--mark-keep); }
body[data-game="hitori"] .scell.off::after { color: var(--mark-drop); }
/* A rejected number is out of the answer — dim it without hiding it. */
body[data-game="hitori"] .scell.off { color: var(--ink-faint); }

/* Nurikabe is asymmetric in the app: land is a ring, sea is a fill. */
body[data-game="nurikabe"] .scell.on { background: var(--bg-raised); }
body[data-game="nurikabe"] .scell.on::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  height: 74%; aspect-ratio: 1; transform: translate(-50%, -50%);
  border-radius: 50%; border: 2.4px solid var(--mark-keep);
  pointer-events: none;
}
body[data-game="nurikabe"] .scell.off {
  background: var(--mark-sea); color: var(--state-off-ink);
}
/* A clue cell is land by definition, so its ring is the land ring. */
body[data-game="nurikabe"] .scell.clue::after {
  border-color: var(--mark-keep); border-width: 2.8px;
}

/* Battleship keeps its block-and-water shapes; the ship takes the app's hull
   blue so a fleet reads as a fleet rather than as an accent colour. */
body[data-game="battleship"] .scell.on::after { background: var(--mark-ship); }
body[data-game="battleship"] .scell.off::after {
  width: 34%; height: 12%; margin: -6% 0 0 -17%;
  border-radius: 999px; opacity: .55;
  box-shadow: 0 5px 0 -1px var(--ink-faint);
}

/* -------------------------------------------------- tool picker swatches
   A tool button should show the mark it paints, so the picker is readable
   before you have tried it. */
#tools button { display: inline-flex; align-items: center; gap: 7px; }
#tools button::before {
  content: ""; width: 11px; height: 11px; border-radius: 50%; flex: none;
  border: 2px solid currentColor; opacity: .85;
}
/* No Hitori rules here: it cycles instead of painting, so its picker is
   hidden (see `cycles` in shaded.js) and has no swatches to style. */
body[data-game="nurikabe"] #tools button[data-tool="on"]::before { color: var(--mark-keep); }
body[data-game="nurikabe"] #tools button[data-tool="off"]::before {
  background: var(--mark-sea); border-color: var(--mark-sea); border-radius: 3px;
}
body[data-game="battleship"] #tools button[data-tool="on"]::before {
  background: var(--mark-ship); border-color: var(--mark-ship); border-radius: 3px;
}
body[data-game="battleship"] #tools button[data-tool="off"]::before { color: var(--ink-faint); }
body[data-game="battleship"] #tools button[data-tool^="note-"]::before {
  border-style: dashed; opacity: .7;
}
/* Slitherlink's tools paint lines, not cells. */
body[data-game="slitherlink"] #tools button[data-tool="line"]::before {
  width: 14px; height: 3px; border: 0; border-radius: 2px; background: var(--ink);
}
body[data-game="slitherlink"] #tools button[data-tool="mark"]::before {
  border: 0; width: 12px; height: 12px; color: var(--ink-faint);
  background:
    linear-gradient(45deg, transparent 44%, currentColor 44%, currentColor 56%, transparent 56%),
    linear-gradient(-45deg, transparent 44%, currentColor 44%, currentColor 56%, transparent 56%);
}

/* ================================================== standalone control button
   Undo, Reset, Hint, Smart Hint, Check and New puzzle are independent actions,
   not a choice between options, so each is its own button. A segmented control
   is reserved for the two places that really are single-choice: the difficulty
   picker and the tool picker. */

.ctl {
  border: 1px solid var(--line); background: var(--bg-raised); color: var(--ink);
  font: inherit; font-size: 13.5px; font-weight: 530;
  padding: 8px 14px; border-radius: 10px; cursor: pointer;
  box-shadow: var(--shadow);
  transition: transform .16s var(--ease), border-color .16s var(--ease),
              background .16s var(--ease), color .16s var(--ease);
}
.ctl:hover:not(:disabled) {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  color: var(--accent);
}
.ctl:active:not(:disabled) { transform: translateY(0); }
.ctl:disabled { opacity: .4; cursor: not-allowed; box-shadow: none; }

/* Pencil is a toggle, so it shows its state rather than just reacting. */
.ctl[aria-pressed="true"] {
  background: var(--accent-soft); color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}

/* The toolbar now holds loose buttons, so it needs its own rhythm. */
.board-shell .toolbar { gap: 8px; }

/* ------------------------------------------------------------------ mobile
   A ten-key row on a 375px screen leaves ~27px per key. The digit has to fit;
   the "n left" counter does not, so it goes rather than forcing the row wider
   than the screen. */
@media (max-width: 560px) {
  .pad { gap: 5px; }
  .pad .count { display: none; }
  .pad button { aspect-ratio: 1 / 1.15; font-size: 15px; border-radius: 8px; }
  .pad button.wide { font-size: 16px; }
  .ctl { padding: 8px 11px; font-size: 12.5px; }
  .board-shell .toolbar { gap: 6px; }
  .play-wrap { padding-top: 18px; }
}
