/* /play: the playable board. Mobile-first: the board takes whatever space
   is left after a compact status bar and a thumb-reachable control deck,
   and the cell size is computed to fit rather than scrolled to. */

/* A fixed height, not a minimum: the stage measures itself to size the board,
   so if the body could grow with its content that measurement would just
   report the oversized board back and the big levels would never shrink. */
.play-body {
  height: 100vh;
  height: 100svh;
  display: flex;
  flex-direction: column;
  overflow: hidden;              /* the board fits; the page never scrolls */
  overscroll-behavior: none;     /* no rubber-banding while swiping moves */
}

/* ---- status bar ---- */
.play-bar {
  display: flex; align-items: center; gap: 16px;
  padding: 10px max(14px, env(safe-area-inset-left)) 10px
               max(14px, env(safe-area-inset-right));
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono); font-size: 13px;
  flex: 0 0 auto;
}
/* Nothing in the bar may wrap. These are labels, not prose: given less room
   than they want they each break onto a second line, and the bar grows from
   one row to three, taking the height out of the board. */
.play-bar > * { white-space: nowrap; }
.play-bar .home {
  display: inline-flex; gap: 6px;
  color: var(--ink-dim); text-decoration: none; font-weight: 600;
}
.play-bar .home:hover { color: var(--ink); }
.play-bar .lvl { color: var(--ink); font-weight: 600; }
.play-bar .stats { margin-left: auto; display: flex; gap: 14px; color: var(--ink-dim); }
.play-bar .stats b {
  color: var(--ink); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.play-bar .done { color: var(--accent); }

/* ---- board area ---- */
.play-stage {
  flex: 1 1 auto;
  display: grid; place-items: center;
  padding: 12px;
  min-height: 0;                 /* let the grid child actually shrink */
  position: relative;
  touch-action: none;            /* swipes are moves, not scrolls */
}
/* No slab behind the grid: these levels are ragged, and a filled bounding
   box would draw a rectangle around shapes that are not rectangles. */
.play-stage .board { background: none; box-shadow: none; }

/* ---- win overlay ---- */
.win {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background: rgba(36, 31, 25, .82);
  padding: 20px;
}
.win[hidden] { display: none; }
.win-card {
  background: var(--void-lift); border: 1px solid var(--rule);
  padding: 28px 30px; max-width: 380px; text-align: center;
}
.win-card h2 { font-size: 22px; margin-bottom: 8px; }
.win-card p { color: var(--ink-dim); font-size: 15px; margin-bottom: 20px; }
.win-card .row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* ---- controls ---- */
/* Mobile stacks: actions on top, d-pad centred beneath them where the
   thumb actually rests. Wide screens put the two side by side instead. */
.play-deck {
  flex: 0 0 auto;
  border-top: 1px solid var(--rule);
  padding: 12px max(14px, env(safe-area-inset-left))
           max(12px, env(safe-area-inset-bottom))
           max(14px, env(safe-area-inset-right));
  display: flex; flex-direction: column-reverse; align-items: center; gap: 12px;
}

button {
  font: 600 13px/1 var(--mono);
  color: var(--ink); background: var(--void-lift);
  border: 1px solid var(--rule);
  padding: 11px 14px; cursor: pointer;
  min-height: 44px;              /* touch target floor */
  transition: background .12s ease, border-color .12s ease;
}
button:hover:not(:disabled) { background: #362f26; border-color: #4c4438; }
button:active:not(:disabled) { background: #221d17; }
button:disabled { opacity: .4; cursor: default; }
button:focus-visible { outline: 2px solid var(--player); outline-offset: 2px; }
button.primary { background: var(--accent); color: #241f19; border-color: var(--accent); }
button.primary:hover:not(:disabled) { background: #dcb057; border-color: #dcb057; }

.deck-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* D-pad: three-column grid so up/down sit above and below the left/right
   pair, which is what a thumb expects. */
.dpad {
  display: grid;
  grid-template-columns: repeat(3, 52px);
  grid-template-rows: repeat(2, 44px);
  gap: 6px;
}
.dpad button { padding: 0; min-height: 0; display: grid; place-items: center; font-size: 16px; }
.dpad .up    { grid-area: 1 / 2; }
.dpad .left  { grid-area: 2 / 1; }
.dpad .down  { grid-area: 2 / 2; }
.dpad .right { grid-area: 2 / 3; }

/* ---- level picker ---- */
.picker { position: absolute; inset: 0; background: var(--void); padding: 20px; overflow-y: auto; }
.picker[hidden] { display: none; }
.picker h2 { font-size: 20px; margin-bottom: 4px; }
.picker .hint { color: var(--ink-dim); font-size: 14px; margin-bottom: 18px; }
.picker-grid {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(58px, 1fr));
  max-width: 620px;
}
.picker-grid button {
  aspect-ratio: 1; min-height: 0; padding: 0;
  display: grid; place-items: center; font-size: 14px;
}
.picker-grid button.solved {
  color: var(--accent); border-color: #5a4a2a; background: #2f2819;
}
.picker-grid button.current { border-color: var(--accent); }

/* Phones: the bar keeps every number and drops only the words that the
   surrounding context already supplies. The wordmark becomes its back
   arrow, and "Level" goes, because "1 / 52" next to moves and pushes is not
   ambiguous. Both stay in the accessibility tree, so the link is still
   named "latent-sokoban" and the counter is still read as a level. */
@media (max-width: 719px) {
  .play-bar { gap: 12px; }
  .play-bar .stats { gap: 12px; }
  .play-bar .home-name,
  .play-bar .lvl-word {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
  /* The arrow is the whole tap target once the name is gone, so it gets a
     real one. The negative margin lets that padding overlap the bar's own
     rather than add to it, so the target grows and the bar does not. */
  .play-bar .home {
    padding: 11px 14px; margin: -11px -14px; min-width: 44px;
    font-size: 15px;
  }
}

@media (min-width: 720px) {
  .play-bar { font-size: 14px; padding-inline: 24px; }
  .play-deck {
    padding-inline: 24px;
    flex-direction: row; justify-content: space-between;
  }
  .dpad { grid-template-columns: repeat(3, 48px); grid-template-rows: repeat(2, 42px); }
}
/* Declared before the media query that flips it on. An equal-specificity
   rule placed after would win and silently hide the hint everywhere. */
.keyhint { display: none; color: var(--ink-dim); font-family: var(--mono); font-size: 12px; }

/* Pointer-precise devices get the keyboard as the primary control, so the
   d-pad stands down to a hint rather than occupying the deck. */
@media (min-width: 900px) and (pointer: fine) {
  .dpad { display: none; }
  .keyhint { display: block; }
}
.keyhint kbd {
  font: inherit; background: var(--void-lift); border: 1px solid var(--rule);
  padding: 2px 5px; margin: 0 1px;
}

@media (prefers-reduced-motion: reduce) {
  button { transition: none; }
}
