/* ── Snap ───────────────────────────────────────────────────────────────────
   A grid you draw a single path across. The play chrome (.q-chrome / .q-stage /
   .q-foot) is the shared shell from queens.css; below is Snap's own — the paper
   grid, the drawn path band (an SVG stroke), and the numbered nodes. The board
   is a fixed px square set by the JS; --sn-cell (its cell size) drives the node
   and number sizing. Everything is theme-aware via tokens.

   Layers, bottom to top: the paper grid (board background), the path stroke
   (an SVG, pointer-transparent), then the interactive cells with their nodes —
   so the band paints over the grid lines but the numbers stay on top. */

.snap-play { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.snap-play .q-stage { padding: var(--space-5); display: grid; place-items: center; }
.sn-hold { display: inline-block; }

/* The board: a lattice of dots at the cell corners rather than ruled lines, so
   the grid states the geometry without competing with the cord for attention.
   These are Snap's OWN tokens — it used to read Nonogram's --no-* here, which
   meant restyling either game silently restyled the other. */
.sn-board {
  position: relative;
  border-radius: 14px;
  border: var(--sn-edge-w) solid var(--sn-frame);
  background-color: var(--sn-paper);
  background-image: radial-gradient(var(--sn-grid) 1.6px, transparent 1.7px);
  background-size: var(--sn-cell) var(--sn-cell);
  background-position: calc(var(--sn-cell) * -0.5) calc(var(--sn-cell) * -0.5);
  overflow: hidden;
  touch-action: none; user-select: none; -webkit-user-select: none;
}

/* ── the cord ───────────────────────────────────────────────────────────────
   Two strokes over one `d`: the band, then a narrow highlight down its middle.
   That highlight is the whole trick — it gives the corner an inside edge to
   resolve against, so the path reads as a round cord lying on the board rather
   than a flat band painted on it. */
.sn-path { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; }
.sn-line {
  stroke: var(--sn-path); stroke-width: 0.58;
  stroke-linecap: round; stroke-linejoin: round;
  transition: stroke 200ms var(--ease);
}
.sn-spine {
  stroke: var(--sn-spine); stroke-width: 0.16;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── the pinned prefix ──────────────────────────────────────────────────────
   What a hint fixed. The cord KEEPS its colour here too (see below) — a pinned
   run is marked by rivets punched along it in the board's own paper, the way a
   cord is tacked down rather than repainted. Deliberately flat: no animation,
   because this is a permanent state of the board, not an event. */
.sn-lock {
  stroke: var(--sn-paper); stroke-width: 0.13;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 0.001 0.26;
  opacity: 0.85;
}
/* a pinned checkpoint restates the plate's own ring, or this equally-specific
   rule would eat it — same trick the start's halo plays */
.sn-cell.sn-locked .sn-node { box-shadow: inset 0 0 0 2px var(--sn-node), 0 0 0 2px var(--accent); }

/* ── solved ─────────────────────────────────────────────────────────────────
   The cord KEEPS its colour. This used to be `stroke: var(--accent)`, which
   threw the palette away at the one moment the player is looking hardest — the
   finished route went amber no matter what colour it had been drawn in.

   The celebration is a surge instead: a bright dash running the route end to
   end, twice, the way a line lights up when the circuit closes. `pathLength=1`
   normalises the path so the dash maths is in fractions of the route and needs
   no measuring, whatever the board size or shape. */
.sn-surge {
  stroke: var(--sn-spine); stroke-width: 0.34;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 0.14 1; stroke-dashoffset: 0.14;
  opacity: 0;
}
.sn-board.sn-solved .sn-surge { animation: sn-surge 1100ms var(--ease) 2; }
@keyframes sn-surge {
  from { stroke-dashoffset: 0.14; opacity: 0.95; }
  to   { stroke-dashoffset: -1;   opacity: 0.95; }
}

/* the head: a chevron at the tip, pointing the way you last went. The tip used
   to be marked only by `cursor: grab` — a mouse affordance in a game played by
   dragging a finger. Hidden once solved: the route has no tip any more. */
.sn-head { fill: none; stroke: var(--sn-paper); stroke-width: 0.10;
  stroke-linecap: round; stroke-linejoin: round; }
.sn-board.sn-solved .sn-head { display: none; }

/* the interactive cells + their number nodes, on top */
.sn-cells { position: absolute; inset: 0; display: grid; z-index: 2; }
.sn-cell { border: 0; background: transparent; padding: 0; margin: 0; display: grid; place-items: center; cursor: pointer; position: relative; }
.sn-cell.tip { cursor: grab; }

/* An interchange plate: the only non-round mark on a board of round joins, so a
   checkpoint never reads as just another blob on the line. It fills with the
   board's own paper — that is what keeps the numeral legible where the cord
   runs beneath it, rather than relying on the numeral out-contrasting the band.
   The colours are Snap's; this used to be a hard var(--text)/var(--bg) disc,
   which meant a checkpoint could never theme away from body text. */
.sn-node {
  width: calc(var(--sn-cell) * 0.62); height: calc(var(--sn-cell) * 0.62);
  border-radius: 26%;
  background: var(--sn-paper); color: var(--sn-node);
  box-shadow: inset 0 0 0 2px var(--sn-node);
  display: grid; place-items: center;
  font-family: var(--font-mono); font-weight: 700; font-size: calc(var(--sn-cell) * 0.34);
  position: relative; z-index: 3;
}
/* the start keeps its accent halo — and has to restate the plate's own ring, or
   this equally-specific rule would silently eat it on the "1" */
.sn-node.first { box-shadow: inset 0 0 0 2px var(--sn-node), 0 0 0 2px var(--accent); }

/* ── footer: the arrow pad + the nudge message (tap a path cell to cut) ────── */
.snap-foot { justify-content: center; gap: var(--space-4); flex-wrap: wrap; }
.sn-msg { font-size: var(--text-sm); color: var(--danger-text); min-width: 0; }

/* ── level-card thumbnail: the numbered nodes (+ the path once solved) ─────── */
.sn-mini { position: relative; width: 100%; margin: 0 auto; aspect-ratio: var(--c) / var(--r); }
.sn-mini svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.sn-mini svg path.p { fill: none; stroke: var(--sn-path); stroke-width: 0.34; stroke-linecap: round; stroke-linejoin: round; opacity: 0.92; }
.sn-mini svg circle { fill: var(--sn-paper); stroke: var(--sn-node); stroke-width: 0.07; }
.sn-mini svg text { font-size: 0.5px; text-anchor: middle; dominant-baseline: central; fill: var(--sn-node); font-weight: 700; }
.sn-mini-g { position: absolute; inset: 0; display: grid; gap: 0; }
.sn-mini-g i { border: 0.5px solid var(--sn-grid); }

@media (prefers-reduced-motion: reduce) {
  .sn-line { transition: none; }
  /* the surge is a celebration, not information — drop it entirely rather than
     leaving a bright dash parked on the route */
  .sn-board.sn-solved .sn-surge { animation: none; opacity: 0; }
}

/* the arrow pad: one back-chevron icon, rotated per direction */
/* The arrow D-pad rides the undo/redo slot (.q-ur): a triangle-over-line
   layout — up on top, left · down · right beneath — so it reads like every
   game pad ever. DOM order (stage · pad · foot) places it above the bottom
   bar in portrait and left of the right rail in landscape; display:grid
   overrides the shared landscape flex-direction, so the pad keeps its shape. */
.q-ur.sn-pad {
  display: grid;
  grid-template-columns: repeat(3, var(--control, 44px));
  gap: var(--space-2);
  justify-content: flex-end;
  align-content: center;
}
.sn-pad .sn-up    { grid-column: 2; grid-row: 1; }
.sn-pad .sn-left  { grid-column: 1; grid-row: 2; }
.sn-pad .sn-down  { grid-column: 2; grid-row: 2; }
.sn-pad .sn-right { grid-column: 3; grid-row: 2; }
/* the d-pad is a MOVEMENT tool, not the undo/redo cluster it replaces — solid
   surface + accent ink so it can't be mistaken for a broken undo pair */
.sn-pad .icon-btn { border: var(--hairline) solid var(--line-2); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--accent); }
.sn-pad .icon-btn:disabled { color: var(--mute); opacity: 0.55; }
.sn-pad .sn-up svg { transform: rotate(90deg); }
.sn-pad .sn-down svg { transform: rotate(-90deg); }
.sn-pad .sn-right svg { transform: rotate(180deg); }

/* the bite: the head recoils, the bitten body cell flashes — you can't eat yourself */
/* the head lives in the path SVG, whose user units are CELLS (viewBox 0 0 C R
   stretched over the board) — so the shake distances are fractions of a cell,
   not screen pixels */
.sn-biting .sn-head { animation: sn-bite-shake 0.3s var(--ease); }
@keyframes sn-bite-shake {
  0%, 100% { transform: none; }
  25% { transform: translate(-0.07px, 0); }
  55% { transform: translate(0.07px, 0); }
  80% { transform: translate(-0.035px, 0); }
}
.sn-cell.sn-bit { animation: sn-bit-flash 0.4s var(--ease); }
@keyframes sn-bit-flash {
  0% { box-shadow: inset 0 0 0 3px var(--red, #c0392b); }
  100% { box-shadow: inset 0 0 0 0 transparent; }
}
