/* CHO-2048 interface styles.
 *
 * Mobile first: the defaults target phones in portrait, wide screens only add incremental relaxations. Two hard requirements
 * live here rather than in someone's memory: 1) the board area is never covered by any overlay, so no scrim or blur effect over
 * the board exists here; 2) settings is a separate page shown exclusively against the game view, never stacked on the board.
 * The page itself does not scroll; scrolling happens only inside the settings page and dialogs, avoiding address-bar jitter on phones.
 */

:root {
  --bg: #f5f5f7;
  --bg-elevated: #ffffff;
  --bg-inset: #e6e6eb;
  --text: #1d1d1f;
  --text-dim: #6e6e73;
  --line: rgba(0, 0, 0, 0.1);
  --accent: #0a84ff;
  --accent-soft: rgba(10, 132, 255, 0.12);
  --success: #248a3d;
  --warn: #b25000;
  --danger: #d70015;
  --shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
  --shadow-soft: 0 2px 10px rgba(0, 0, 0, 0.07);
  --radius-lg: 18px;
  --radius-md: 13px;
  --radius-sm: 9px;
  --tile-radius: 11px;
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;
  --mono: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  --tile-transition: 110ms;
  --tap: 44px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f0f11;
    --bg-elevated: #1c1c1e;
    --bg-inset: #2c2c2e;
    --text: #f5f5f7;
    --text-dim: #98989d;
    --line: rgba(255, 255, 255, 0.14);
    --accent-soft: rgba(10, 132, 255, 0.22);
    --shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
    --shadow-soft: 0 2px 12px rgba(0, 0, 0, 0.36);
  }
}

* {
  box-sizing: border-box;
}

/* Views are mutually exclusive via the hidden attribute; no later display rule may override it,
   otherwise the hidden view keeps participating in layout — the root of board-covered-by-overlay bugs. */
[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

button {
  font-family: inherit;
  font-size: 14px;
  color: var(--text);
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0 12px;
  min-height: var(--tap);
  min-width: var(--tap);
  cursor: pointer;
  touch-action: manipulation;
  transition: background 120ms ease, transform 120ms ease;
}

button:hover:not(:disabled) {
  background: var(--bg-inset);
}

button:active:not(:disabled) {
  transform: scale(0.97);
}

button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

button.primary {
  background: var(--accent);
  border-color: transparent;
  color: #fff;
}

button.primary:hover:not(:disabled) {
  background: #0071e3;
}

button.danger {
  color: var(--danger);
  border-color: rgba(215, 0, 21, 0.4);
}

input,
select,
textarea {
  font-family: inherit;
  font-size: 15px;
  color: var(--text);
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  min-height: var(--tap);
  width: 100%;
}

input.mono,
textarea.mono {
  font-family: var(--mono);
}

/* ---------- Shell and views ---------- */

.app {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding:
    max(8px, env(safe-area-inset-top))
    max(10px, env(safe-area-inset-right))
    max(8px, env(safe-area-inset-bottom))
    max(10px, env(safe-area-inset-left));
}

.view {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.view-play {
  /* A grid rather than a single-column flow: landscape phones can put the board on the left and the info
     plus controls on the right, so the board gets the full height instead of being squeezed flat between
     two stacked blocks of UI. Tracks are written as minmax(0, 1fr): the default auto minimum gets pushed
     open by long non-wrapping text in the info area, the whole grid then exceeds the container width, and the right side of the board gets clipped off. */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "hud"
    "stage"
    "toolbar";
  gap: 8px;
  /* Game view: the page never scrolls; swipes are interpreted as direction input only over the board. */
  overflow: hidden;
}

/* Constrained to the track: no item's intrinsic width is allowed to stretch the track open. */
.view-play > * {
  min-width: 0;
}

.view-play .hud {
  grid-area: hud;
}

.view-play .stage {
  grid-area: stage;
}

.view-play .toolbar {
  grid-area: toolbar;
}

.view-settings {
  /* Settings view: a separate page that scrolls on its own, never sharing the screen with the board. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  gap: 12px;
  padding-bottom: 12px;
  /* On wide screens the content is pulled back to a readable width: when table columns stretch across the whole row, the excessive line length makes rows hard to compare. */
  align-items: center;
}

.view-settings > * {
  width: 100%;
  max-width: 1180px;
}

.view-home {
  /* The menu is a page of choices rather than the board, so it scrolls on its own the way the
     settings page does, and never shares the screen with either of them. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  gap: 14px;
  padding-bottom: 14px;
  align-items: center;
}
.view-home > * {
  width: 100%;
  max-width: 720px;
}

/* ---------- Top info area ---------- */

.hud {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.hud-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.hud-title {
  font-size: 16px;
  font-weight: 650;
  letter-spacing: 0.2px;
  line-height: 1.25;
  min-width: 0;
  flex: 1 1 auto;
}

.hud-title small {
  display: block;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-dim);
  letter-spacing: 0.3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hud-head .settings-entry {
  flex: 0 0 auto;
}

.hud-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
}

.hud-actions {
  display: flex;
  gap: 6px;
  flex: 0 0 auto;
}

/* Both entries in the head are the same control; the settings one keeps its own hook so the
   check scripts can find it by name. */
.hud-button {
  font-size: 13px;
  padding: 0 10px;
}

.stat {
  flex: 1 1 auto;
  min-width: 76px;
  padding: 5px 9px;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
}

.stat .label {
  display: block;
  font-size: 10px;
  color: var(--text-dim);
  letter-spacing: 0.5px;
}

.stat .value {
  display: block;
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hash-row {
  /* Config ID segments vary in length, so wrapping is allowed on narrow screens to keep the "character count" label from being squeezed out. */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 6px 10px;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}

.hash-row .hash {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hash-row .tag {
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
}

.hash-row button {
  min-height: var(--tap);
  font-size: 12px;
  padding: 0 10px;
}

/* ---------- Board ---------- */

.stage {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.board-shell {
  /* Touch gestures belong to the board alone: the browser no longer reads vertical swipes as page scrolling,
     and long-press text selection or native dragging is disallowed, otherwise quick flicks get taken over by the system. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  position: relative;
  min-width: 0;
  max-width: 100%;
  padding: 12px;
  background: var(--bg-inset);
  border-radius: var(--radius-lg);
}

.board {
  position: relative;
  display: grid;
  gap: var(--gap, 10px);
  --cell: 64px;
  --gap: 10px;
}

.cell {
  width: var(--cell);
  height: var(--cell);
  border-radius: var(--tile-radius);
  background: rgba(120, 120, 128, 0.14);
}

.tile {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--cell);
  height: var(--cell);
  border-radius: var(--tile-radius);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-weight: 650;
  letter-spacing: -0.2px;
  color: #fff;
  background: #8e8e93;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  transition: transform var(--tile-transition) cubic-bezier(0.22, 0.61, 0.36, 1),
    background-color 160ms ease, box-shadow 160ms ease, opacity 160ms ease;
  will-change: transform;
  overflow: hidden;
}

.tile.enter {
  animation: tile-enter 180ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.tile.leave {
  opacity: 0;
  transform: scale(0.86);
  pointer-events: none;
}

.tile.flash {
  animation: tile-flash 260ms ease;
}

.tile .formula {
  font-size: calc(var(--cell) * 0.26);
  line-height: 1.05;
}

.tile .formula.small {
  font-size: calc(var(--cell) * 0.19);
}

.tile .formula.tiny {
  font-size: calc(var(--cell) * 0.15);
}

/* Tile second line: steps remaining for unstable states. Stable states leave this line empty, so only the layout is handled here. */
.tile .meta {
  font-size: calc(var(--cell) * 0.17);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  opacity: 0.92;
  font-weight: 600;
  white-space: nowrap;
}

.tile.target {
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.75), 0 2px 12px rgba(36, 138, 61, 0.45);
}

.tile.target.glow {
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.85), 0 3px 18px rgba(36, 138, 61, 0.65);
}

.tile.offratio {
  background-image: repeating-linear-gradient(
    135deg,
    rgba(0, 0, 0, 0.16) 0 6px,
    rgba(0, 0, 0, 0) 6px 12px
  );
}

.tile.experimental {
  outline: 1px dashed rgba(255, 255, 255, 0.65);
  outline-offset: -4px;
}

/* Loading and startup-failure notice. It takes part in normal layout and does not cover the board; it is removed once the app has started successfully. */
.boot-note {
  flex: 0 0 auto;
  margin: 0;
  max-width: 30em;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-dim);
  text-align: center;
  word-break: break-word;
}

.boot-note.failed {
  padding: 10px 13px;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-left: 4px solid var(--danger);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  color: var(--text);
}

@keyframes tile-enter {
  from {
    opacity: 0;
    transform: scale(0.6) translate(var(--x), var(--y));
  }
}

@keyframes tile-flash {
  0% {
    filter: brightness(1);
  }
  40% {
    filter: brightness(1.5);
  }
  100% {
    filter: brightness(1);
  }
}

/* ---------- Toolbar (game actions only) ---------- */

.toolbar {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding-top: 2px;
}

.toolbar .spacer {
  flex: 1 1 auto;
}

.toolbar button {
  flex: 1 1 0;
}

.toolbar button.primary {
  flex: 1.4 1 0;
}

/* ---------- Settings page ---------- */

.settings-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  position: sticky;
  top: 0;
  z-index: 5;
  padding: 4px 0 8px;
  background: var(--bg);
}

.settings-head button {
  flex: 0 0 auto;
}

.settings-head .title {
  min-width: 0;
  flex: 1 1 auto;
}

.settings-head .title h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 650;
}

.settings-head .title p {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--text-dim);
}

.settings-list {
  display: grid;
  gap: 10px;
  grid-template-columns: 1fr;
}

.settings-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  text-align: left;
  padding: 13px 14px;
  min-height: var(--tap);
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
}

.settings-card .name {
  font-size: 15px;
  font-weight: 650;
}

.settings-card .summary {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.5;
  white-space: normal;
}

/* Home: the mode blocks explain a way to play, the level cards state what the level asks for and
   what has already been achieved on it. */
.page-head {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.page-head h1 {
  font-size: 20px;
  font-weight: 680;
  letter-spacing: 0.2px;
}
.page-head p {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.5;
}
.mode-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 13px 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
}
.mode-card .name,
.level-card .name {
  font-size: 15px;
  font-weight: 650;
}
.mode-card .summary,
.level-card .summary {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.5;
  white-space: normal;
}
.level-list {
  display: grid;
  gap: 10px;
  grid-template-columns: 1fr;
}
.level-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  text-align: left;
  padding: 13px 14px;
  min-height: var(--tap);
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
}
.level-card:hover {
  border-color: var(--accent);
}
.level-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}
.level-head .tag {
  margin-left: auto;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  background: var(--bg-inset);
  color: var(--text-dim);
}
.level-head .tag.best {
  background: var(--accent-soft);
  color: var(--accent);
}
.level-stats {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.stat-line {
  font-size: 12px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.stat-line.current {
  color: var(--success);
}
.hint-inline {
  font-size: 12px;
  color: var(--text-dim);
  align-self: center;
}

.section-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.section-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 4px;
}

.section-actions button {
  flex: 1 1 auto;
}

/* ---------- Mini lessons ---------- */

/* Lesson card: this is what pops up on double-tap inside a tile, and the mini-lessons section in settings is the same content. */
.lesson-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.lesson {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 12px 13px;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
}

.lesson-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.lesson-head .formula {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--text-dim);
}

.lesson-head .lesson-name {
  font-size: 15px;
  font-weight: 650;
}

.lesson-summary {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
}

.lesson-detail {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-dim);
}

.lesson-tips {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-dim);
}

.lesson-lines {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 8px;
}

.lesson-lines .label {
  font-size: 12px;
  color: var(--text-dim);
}

.lesson-lines .line {
  font-size: 12px;
  padding: 3px 8px;
  background: var(--bg-inset);
  border-radius: var(--radius-sm);
}

.dialog .lesson {
  /* The overlay already has a border and background, so the lesson card does not stack another layer. */
  padding: 0;
  border: none;
  background: transparent;
  box-shadow: none;
}

/* ---------- Notification stack ---------- */

.toast-stack {
  position: fixed;
  right: max(10px, env(safe-area-inset-right));
  /* Lifted above the bottom action bar: when a notification covers buttons like "New game", the player thinks the interface is broken. */
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + 56px);
  left: max(10px, env(safe-area-inset-left));
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 60;
  pointer-events: none;
}

.toast {
  position: relative;
  margin-left: auto;
  width: min(360px, 100%);
  padding: 10px calc(var(--tap) + 8px) 12px 12px;
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  overflow: hidden;
  animation: toast-in 180ms cubic-bezier(0.22, 0.61, 0.36, 1);
  /* The notification itself takes no pointer events: it may hover above the board, and swipes must
     still pass through to the board. Only the close button is clickable. */
  pointer-events: none;
}

.toast .title {
  font-size: 13px;
  font-weight: 620;
}

.toast .detail {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 2px;
  word-break: break-word;
}

.toast .bar {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  width: 100%;
  transform-origin: left center;
  animation: toast-bar linear forwards;
}

.toast .close {
  position: absolute;
  top: 0;
  right: 0;
  width: var(--tap);
  height: var(--tap);
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0;
  line-height: 1;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-size: 15px;
  pointer-events: auto;
}

.toast.success {
  border-left: 3px solid var(--success);
}

.toast.info {
  border-left: 3px solid var(--accent);
}

.toast.warn {
  border-left: 3px solid var(--warn);
}

.toast.error {
  border-left: 3px solid var(--danger);
}

.toast.success .bar {
  background: var(--success);
}

.toast.info .bar {
  background: var(--accent);
}

.toast.warn .bar {
  background: var(--warn);
}

.toast.error .bar {
  background: var(--danger);
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
  }
}

@keyframes toast-bar {
  from {
    transform: scaleX(1);
  }
  to {
    transform: scaleX(0);
  }
}

/* ---------- Confirmation and input dialogs ----------
   Only for momentary decisions that must interrupt, such as delete confirmation; settings no longer uses dialogs. */

.dialog-root:empty {
  display: none;
}

.dialog-scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.44);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
  z-index: 90;
}

.dialog {
  width: 100%;
  max-height: 86dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow);
  overflow: hidden;
}

.dialog header {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 14px 10px;
  border-bottom: 1px solid var(--line);
}

.dialog header h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 650;
}

.dialog header p {
  margin: 3px 0 0;
  font-size: 12px;
  color: var(--text-dim);
}

.dialog header .close {
  margin-left: auto;
  min-height: 34px;
  border: none;
  background: transparent;
  font-size: 18px;
  line-height: 1;
  color: var(--text-dim);
}

.dialog .body {
  padding: 14px;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.dialog footer {
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 12px 14px max(12px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--bg);
}

.dialog footer .spacer {
  display: none;
}

.dialog footer button {
  flex: 1 1 auto;
}

/* ---------- Tables and forms ---------- */

.table-wrap {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}

table.grid {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  line-height: 1.45;
}

table.grid th,
table.grid td {
  padding: 9px 11px;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

/* The header stays one line tall and uses the secondary color, so data rows do not blend into it. */
table.grid th {
  position: sticky;
  top: 0;
  background: var(--bg-inset);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.02em;
  color: var(--text-dim);
  z-index: 1;
}

table.grid tbody tr:last-child td {
  border-bottom: none;
}

/* Zebra striping: columns are very wide on wide screens, so rows need a reference the eye can follow. */
table.grid tbody tr:nth-child(even) td {
  background: var(--bg-inset);
}

/* Numeric columns are right-aligned and use tabular figures, so values with different digit counts line up place by place. */
table.grid th.num,
table.grid td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

table.grid tr.offratio td:nth-child(2) {
  color: var(--warn);
}

table.grid tr.target td:nth-child(2) {
  color: var(--success);
  font-weight: 620;
}

table.grid td.mono,
table.grid td .mono {
  font-family: var(--mono);
}

/* Controls inside the table: the font size follows the table body text, and controls no longer add extra height to the whole row.
   The checkbox is the main source of row height: its default min-height renders it at touch size, and with the line box's
   baseline gap on top, one table row grows to seventy-something pixels. */
table.grid select,
table.grid input:not([type="checkbox"]) {
  min-height: 34px;
  padding: 5px 8px;
  font-size: 13px;
}

/* A select inside the table must keep showing the value it holds. The table is as wide as its
   container and its columns shrink to their minimum content width, and the minimum content width of
   a select is its arrow: without this the status column collapses to about one character and the
   current status becomes invisible until the control is opened. Two extra characters of room are
   what keeps the longest status label readable, and the wrapper scrolls if that does not fit. */
table.grid select {
  width: 100%;
  min-width: 104px;
}

table.grid input[type="checkbox"] {
  width: 18px;
  height: 18px;
  min-width: 18px;
  min-height: 18px;
  flex: 0 0 auto;
}

/* Checkbox labels inside a cell are laid out on one line, leaving no baseline gap in between. */
table.grid td label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

/* On touch devices clickable elements still have to stay 44x44: the label itself fills the touch
   size, the checkbox keeps its small appearance, and the two stack so the total row height is unchanged. */
@media (pointer: coarse) {
  table.grid select,
  table.grid input:not([type="checkbox"]) {
    min-height: 44px;
  }

  table.grid td label {
    min-width: 44px;
    min-height: 44px;
  }
}

.field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.field .label {
  font-size: 12px;
  color: var(--text-dim);
}

.row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.row > * {
  flex: 1 1 150px;
}

.hint {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.55;
  margin: 0;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  background: var(--bg-inset);
  color: var(--text-dim);
}

.chip.ok {
  background: rgba(36, 138, 61, 0.16);
  color: var(--success);
}

.chip.warn {
  background: rgba(178, 80, 0, 0.16);
  color: var(--warn);
}

.chip.error {
  background: rgba(215, 0, 21, 0.16);
  color: var(--danger);
}

.list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.list .item {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.5;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg);
}

.list .item .grow {
  flex: 1 1 140px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.filters {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: flex-end;
}

.filters .field {
  flex: 1 1 160px;
}

textarea.code {
  min-height: 110px;
  font-family: var(--mono);
  font-size: 12px;
  resize: vertical;
}

.checks {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  font-size: 13px;
}

.checks label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.checks input[type="checkbox"] {
  width: 20px;
  min-height: 20px;
  height: 20px;
  flex: 0 0 auto;
}

.preset-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.preset-card {
  min-height: var(--tap);
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--bg);
  cursor: pointer;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 5px;
  align-items: flex-start;
}

.preset-card:hover {
  border-color: var(--accent);
}

.preset-card .name {
  font-size: 14px;
  font-weight: 650;
}

.preset-card .summary {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.5;
  white-space: normal;
}

.preset-card .hash {
  max-width: 100%;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- Narrow-screen details ----------
   On phones iOS auto-zooms the page when inputs are smaller than 16px, so everything here is raised to 16px. */

@media (max-width: 600px) {
  input,
  select,
  textarea {
    font-size: 16px;
  }

  .stage {
    gap: 8px;
  }

  .board-shell {
    padding: 10px;
  }

  /* On phones both text and buttons go up one step: mis-tapping buttons and unreadable tile text on narrow screens are the most direct sources of complaints. */
  .hud-title small {
    font-size: 12px;
  }

  .stat .label {
    font-size: 11px;
  }

  .stat .value {
    font-size: 16px;
  }

  .hash-row .hash {
    font-size: 12px;
  }

  .toolbar {
    gap: 10px;
  }

  .toolbar button {
    font-size: 15px;
  }
}

/* ---------- Wide-screen increments ----------
   Control sizes are tightened only for devices that are "large enough and mouse-driven". Touch devices keep the 44px
   touch height no matter how wide they are, otherwise buttons on tablets or landscape phones become hard to hit. */

@media (min-width: 820px) and (min-height: 601px) and (pointer: fine) {
  :root {
    --tap: 36px;
  }

  html,
  body {
    font-size: 14px;
  }

  .app {
    padding: 18px clamp(18px, 3vw, 48px) 14px;
  }

  .view-play {
    gap: 14px;
  }

  .stage {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 22px;
  }

  .stage .banner {
    width: min(320px, 30vw);
    max-width: none;
    align-self: center;
  }

  .settings-list {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  }

  .settings-head {
    position: static;
  }

  .dialog-scrim {
    align-items: center;
    padding: 24px;
  }

  .dialog {
    width: min(var(--dialog-width, 560px), 100%);
    max-height: 86vh;
    border-radius: var(--radius-lg);
  }

  .dialog footer {
    justify-content: flex-end;
  }

  .dialog footer button {
    flex: 0 0 auto;
    min-width: 96px;
  }

  .preset-grid {
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  }

  .section-actions button {
    flex: 0 0 auto;
  }

  button {
    padding: 0 13px;
  }

  .toolbar button {
    flex: 0 0 auto;
  }
}

/* ---------- Landscape phones ----------
   At around 400 pixels of height, a top-to-bottom layout squeezes the board down to 30 pixels per cell, which is basically unplayable.
   Here it becomes a two-column split: the board takes the full height, while the info and control areas collapse into one column on the right. */

@media (orientation: landscape) and (max-height: 600px) {
  .view-play {
    /* The right column is bounded by both a pixel cap and a ratio: with only the pixel cap, the width
       left for the board on a 568px-wide landscape phone is not enough for cells to reach 44px. */
    grid-template-columns: minmax(0, 1fr) minmax(0, min(300px, 42%));
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "stage hud"
      "stage toolbar";
    gap: 10px;
  }

  .view-play .hud {
    align-self: start;
  }

  .view-play .toolbar {
    align-self: start;
  }

  .hud-stats {
    gap: 5px;
  }

  .stat {
    min-width: 68px;
    padding: 4px 8px;
  }

  .toolbar {
    gap: 6px;
  }

  .hash-row {
    padding: 4px 8px;
  }

  .hash-row .hash {
    font-size: 10px;
  }
}
