/* Latchword. Colors: gold marks a right letter; blue (earlier, towards A) and
   orange (later, towards Z) are a pair that stays distinct for the common kinds
   of color blindness, and every mark also has its own arrow position. */
:root {
  --lw-bg: #0f131a;
  --panel: #171d27;
  --panel-2: #1f2733;
  --panel-3: #283243;
  --line: #2f3b4c;
  --text: #eef1f5;
  --muted: #9aa6b5;
  --brass: #efbf55;
  --brass-2: #c68f2a;
  --brass-ink: #251802;
  --early: #5cb8ef;
  --late: #ff8a4c;
  --good: #6ad48a;
  --bad: #ff6a5c;
  /* The safe areas (docs/PLATFORMS.md, "Safe areas"), through variables so a
     test can give an emulated phone a notch's insets: an emulator reports none. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  /* The site header: 48 px, and the status bar's height in the home-screen
     app, where the page draws under it (site.css). */
  --header-h: calc(48px + var(--safe-top));
  /* The smallest text (docs/PLATFORMS.md, "Readable at phone size"): 14 px
     on a desktop, 15 on a tablet and 13 on a phone. */
  --text-min: 14px;
  /* How far controls keep inside the safe areas: 16 px on a touch screen, so
     a thumb on one never starts the system's edge gestures. */
  --edge: 8px;
  color-scheme: dark;
}

@media (pointer: coarse) {
  :root {
    --text-min: 15px;
    --edge: 16px;
  }
}

/* Phones: a touch screen under 600 px on its short side. */
@media (pointer: coarse) and (max-width: 599px), (pointer: coarse) and (max-height: 599px) {
  :root {
    --text-min: 13px;
  }
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  background: var(--lw-bg);
  color: var(--text);
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Ubuntu, sans-serif;
  -webkit-text-size-adjust: 100%;
}

a {
  color: var(--brass);
}

button {
  font: inherit;
  color: inherit;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

[hidden] {
  display: none !important;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- page and game area ---------- */

.lw-page {
  display: block;
}

/* The game fills the screen below the site header, and follows the browser's
   bars as they slide in and out (dvh). Nothing in it is selected or opens a
   long-press menu; each screen says how a finger may move it. */
.lw {
  position: relative;
  height: calc(100vh - var(--header-h));
  height: calc(100dvh - var(--header-h));
  min-height: 260px;
  overflow: hidden;
  background:
    radial-gradient(120% 70% at 50% 0%, rgba(239, 191, 85, 0.07), transparent 60%),
    linear-gradient(180deg, #121823, var(--lw-bg));
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.screen {
  position: absolute;
  inset: 0;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 46px;
  padding: 10px 18px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel-2);
  color: var(--text);
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
  transition:
    background 0.15s,
    transform 0.1s,
    border-color 0.15s;
}
/* Hover looks only where there is hover: a tap leaves no stuck highlight. */
@media (hover: hover) {
  .btn:hover {
    background: var(--panel-3);
    border-color: #3d4b5f;
  }
}
.btn:active {
  transform: translateY(1px);
}
.btn:focus-visible,
.toggle:focus-visible,
.bar-btn:focus-visible,
.dial:focus-visible,
.arch-item:focus-visible,
.sheet-close:focus-visible {
  outline: 3px solid var(--early);
  outline-offset: 2px;
}
.btn.primary {
  background: linear-gradient(180deg, #f6cd6c, var(--brass-2));
  border-color: #f6cd6c;
  color: var(--brass-ink);
}
@media (hover: hover) {
  .btn.primary:hover {
    background: linear-gradient(180deg, #ffd97f, #d49a31);
  }
}
.btn.ghost {
  background: transparent;
}
.btn.big {
  min-height: 54px;
  font-size: 18px;
  width: 100%;
}

/* ---------- home ---------- */

/* The menus scroll with a finger where they don't fit, and the page around
   them still zooms. */
.home {
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y pinch-zoom;
}
.home-inner {
  width: min(460px, 100%);
  margin: 0 auto;
  padding: clamp(12px, 3.5dvh, 36px) max(16px, calc(var(--edge) + var(--safe-right))) calc(20px + var(--safe-bottom)) max(16px, calc(var(--edge) + var(--safe-left)));
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 2dvh, 18px);
}
.brand {
  text-align: center;
}
.brand-dial {
  width: clamp(54px, 11dvh, 84px);
  height: auto;
  display: block;
  margin: 0 auto 6px;
  animation: dial-idle 9s ease-in-out infinite;
}
.bd-ring {
  fill: #1b2230;
  stroke: var(--brass);
  stroke-width: 3;
}
.bd-ticks line {
  stroke: #c9b07a;
  stroke-width: 1.4;
  stroke-linecap: round;
}
.bd-knob {
  fill: var(--brass-2);
  stroke: var(--brass);
  stroke-width: 2;
}
.bd-mark {
  fill: var(--brass);
}
@keyframes dial-idle {
  0%,
  100% {
    transform: rotate(0deg);
  }
  30% {
    transform: rotate(-40deg);
  }
  55% {
    transform: rotate(25deg);
  }
  75% {
    transform: rotate(-8deg);
  }
}
.brand h1 {
  margin: 0;
  font-size: clamp(32px, 6.4dvh, 48px);
  font-weight: 900;
  letter-spacing: 0.04em;
  line-height: 1.05;
  background: linear-gradient(180deg, #ffe3a1 10%, var(--brass) 55%, var(--brass-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.brand-sub {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 15px;
}

.daily-card {
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  border: 1px solid #3a4658;
  border-radius: 16px;
  padding: 14px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}
.dc-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.dc-label {
  font-weight: 800;
  color: var(--brass);
  letter-spacing: 0.02em;
}
.dc-date {
  color: var(--muted);
  font-size: max(14px, var(--text-min));
  text-align: right;
}
.dc-theme {
  font-size: 20px;
}
.dc-theme-label {
  font-size: var(--text-min);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  margin-right: 4px;
}
.dc-status {
  color: #cfd6df;
  font-size: 15px;
  min-height: 20px;
}
.countdown {
  color: var(--brass);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.streak-line {
  text-align: center;
  color: #d7dde5;
  font-size: 15px;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px 4px;
}
.streak-line strong {
  color: var(--brass);
  font-size: 18px;
}
.key-icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: var(--brass);
  stroke-width: 2;
  stroke-linecap: round;
  vertical-align: -3px;
}
.home-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.sound-row {
  display: flex;
  justify-content: center;
  gap: 10px;
}
.toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font-weight: 600;
  cursor: pointer;
  min-height: 44px;
}
.toggle-dot {
  width: 28px;
  height: 16px;
  border-radius: 999px;
  background: #3a4556;
  position: relative;
  transition: background 0.15s;
}
.toggle-dot::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #cfd6df;
  transition: transform 0.15s;
}
.toggle[aria-pressed='true'] {
  color: var(--text);
}
.toggle[aria-pressed='true'] .toggle-dot {
  background: var(--brass-2);
}
.toggle[aria-pressed='true'] .toggle-dot::after {
  transform: translateX(12px);
  background: #fff4d8;
}

/* ---------- play screen ---------- */

/* Play takes no pan, pinch zoom or pull-to-refresh from a finger
   (docs/PLATFORMS.md, "No scrolling, zooming or text selection during
   play"): only the board scrolls, when its rows don't fit. main.js stops
   Safari's pinch and the long-press menu. */
.play {
  display: flex;
  flex-direction: column;
  max-width: 620px;
  margin: 0 auto;
  touch-action: none;
  overscroll-behavior: none;
}
.play-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px calc(var(--edge) + var(--safe-right)) 2px calc(var(--edge) + var(--safe-left));
  min-height: 46px;
}
.bar-left {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 6px;
}
.bar-btn {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-height: 44px;
  min-width: 44px;
  padding: 0 8px 0 4px;
  border-radius: 10px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  font-weight: 700;
  font-size: 15px;
  cursor: pointer;
}
@media (hover: hover) {
  .bar-btn:hover {
    background: var(--panel-2);
  }
}

.bar-btn.icon {
  padding: 0;
  justify-content: center;
}
.bar-btn svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.bar-btn svg .dot {
  fill: currentColor;
}
.bar-btn .cross {
  display: none;
}
.bar-btn[aria-pressed='false'] {
  color: var(--muted);
}
.bar-btn[aria-pressed='false'] .cross {
  display: inline;
}
.bar-btn[aria-pressed='false'] .wave {
  display: none;
}
.vault-title {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1.15;
  text-align: center;
}
.vt-name {
  font-size: var(--text-min);
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.vt-theme {
  font-size: 17px;
  font-weight: 800;
  color: var(--brass);
  white-space: normal;
  overflow: visible;
  max-width: 100%;
}
.bar-right {
  display: flex;
  flex: none;
  gap: 2px;
}
/* Touch screens: thumb-sized, 8 px apart (docs/PLATFORMS.md, "Thumb-sized targets"). */
@media (pointer: coarse) {
  .bar-btn {
    min-height: 44px;
    min-width: 44px;
  }
  .bar-right {
    gap: 8px;
  }
}

.picks {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  height: 22px;
  padding: 0 8px;
}
.pick {
  width: 10px;
  height: 22px;
  flex: none;
  overflow: visible;
  transition: opacity 0.3s;
}
.pick .p-handle {
  fill: var(--brass);
}
.pick .p-shaft {
  fill: none;
  stroke: #ffe3a1;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pick.used {
  opacity: 0.55;
}
.pick.used .p-handle {
  fill: #3a4453;
}
.pick.used .p-shaft {
  stroke: #4a5566;
}
.picks-text {
  margin-left: 6px;
  font-size: var(--text-min);
  font-weight: 700;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 48px;
}
.picks.low .pick:not(.used) {
  animation: pick-pulse 1.1s ease-in-out infinite;
}
.picks.low .pick:not(.used) .p-handle {
  fill: var(--bad);
}
.picks.low .pick:not(.used) .p-shaft {
  stroke: #ffb2a3;
}
.picks.low .picks-text {
  color: var(--bad);
}
@keyframes pick-pulse {
  50% {
    transform: scale(1.15);
  }
}

.play-main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* main.js sizes the tiles (--tile) and the dials of the row being typed
   (--dial, at least --dial-min) to the board's space (src/fit.js). */
.board {
  --tile: 52px;
  --dial: 52px;
  --dial-min: 46px;
  --tile-gap: 6px;
  /* 1: a waiting lock shows its blank row (0 on a phone held sideways). */
  --shut-rows: 1;
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: none;
  padding: 4px calc(8px + var(--safe-right)) 6px calc(8px + var(--safe-left));
  display: flex;
  flex-direction: column;
  gap: 8px;
  scrollbar-width: thin;
}
/* Rows that don't fit scroll with a finger, and never carry the page along. */
.board.scrolls {
  touch-action: pan-y;
}
/* Centre the locks when there is room, without clipping them when there isn't. */
.board > :first-child {
  margin-top: auto;
}
.board > :last-child {
  margin-bottom: auto;
}
.side {
  display: flex;
  flex-direction: column;
}

.lock {
  --t: var(--tile);
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(23, 29, 39, 0.85);
  padding: 2px 8px 8px;
  transition:
    border-color 0.3s,
    box-shadow 0.3s,
    opacity 0.3s;
  /* Share spare board height between the three vault panels, without
     shrinking their rows when history needs the board's own scrolling. */
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.lock-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: calc(var(--text-min) * 1.7);
  font-size: var(--text-min);
  color: var(--muted);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  gap: 8px;
  flex: none;
}
.lock-name {
  font-weight: 800;
  color: #c6cfdb;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
}
.lock-len {
  font-weight: 600;
  color: var(--muted);
}
.lock-meta {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lock-ico {
  width: 11px;
  height: 12px;
  position: relative;
  display: inline-block;
}
.lock-ico::before {
  content: '';
  position: absolute;
  left: 1px;
  top: 0;
  width: 5px;
  height: 6px;
  border: 2px solid currentColor;
  border-bottom: 0;
  border-radius: 5px 5px 0 0;
}
.lock-ico::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 11px;
  height: 7px;
  border-radius: 2px;
  background: currentColor;
}
.lock.open .lock-ico::before {
  left: 5px;
  top: -2px;
}
.lock.current {
  border-color: rgba(239, 191, 85, 0.55);
  box-shadow:
    0 0 0 1px rgba(239, 191, 85, 0.18),
    0 8px 26px rgba(0, 0, 0, 0.35);
  background: rgba(27, 34, 46, 0.95);
}
.lock.current .lock-name {
  color: var(--brass);
}
.lock.open {
  background: linear-gradient(180deg, rgba(239, 191, 85, 0.1), rgba(23, 29, 39, 0.85));
  border-color: rgba(239, 191, 85, 0.35);
}
.lock.open .lock-name {
  color: var(--brass);
}
.lock.waiting {
  opacity: 0.55;
}
.lock.failed {
  border-color: rgba(255, 106, 92, 0.4);
}
.lock.failed .lock-meta {
  color: var(--bad);
}

.rows {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--t) * 0.08);
}
.row {
  display: flex;
  gap: var(--tile-gap);
  justify-content: center;
}
/* The dials' touch areas meet: the gap between them is drawn inside each. */
.row.entry {
  gap: 0;
}
.row.past,
.board.done .row {
  --t: calc(var(--tile) * 0.82);
}
.row.answer,
.row.shut {
  --t: calc(var(--tile) * 0.64);
}
.board.done .row.answer {
  --t: calc(var(--tile) * 0.82);
}

.tile {
  --t2: var(--t, 48px);
  position: relative;
  width: var(--t2);
  height: var(--t2);
  display: inline-grid;
  place-items: center;
  border-radius: calc(var(--t2) * 0.18);
  border: 2px solid #3a4658;
  background: #1c2330;
  color: var(--text);
  font-weight: 800;
  /* Half the tile, and never under the smallest text size on small tiles. */
  font-size: max(var(--text-min), calc(var(--t2) * 0.5));
  line-height: 1;
  flex: none;
}
.tile .l {
  position: relative;
  z-index: 1;
}
.tile .mk {
  position: absolute;
  left: 50%;
  width: 0;
  height: 0;
  transform: translateX(-50%);
  display: none;
  --a: calc(var(--t2) * 0.13);
}
.tile.up .up-mk {
  display: block;
  top: calc(var(--t2) * 0.07);
  border-left: var(--a) solid transparent;
  border-right: var(--a) solid transparent;
  border-bottom: calc(var(--a) * 1.15) solid var(--early);
}
.tile.down .down-mk {
  display: block;
  bottom: calc(var(--t2) * 0.07);
  border-left: var(--a) solid transparent;
  border-right: var(--a) solid transparent;
  border-top: calc(var(--a) * 1.15) solid var(--late);
}
.tile.up {
  border-color: var(--early);
  background: linear-gradient(180deg, rgba(92, 184, 239, 0.3), rgba(92, 184, 239, 0.08));
}
.tile.down {
  border-color: var(--late);
  background: linear-gradient(0deg, rgba(255, 138, 76, 0.3), rgba(255, 138, 76, 0.08));
}
.tile.up .l {
  transform: translateY(calc(var(--t2) * 0.06));
}
.tile.down .l {
  transform: translateY(calc(var(--t2) * -0.06));
}
.tile.hit {
  border-color: #ffe08e;
  background: linear-gradient(180deg, #ffd978, var(--brass-2));
  color: var(--brass-ink);
  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.18);
}
.tile.blank {
  background: #161c26;
  border-color: #2a3444;
}
.tile.answer {
  border: 2px dashed var(--brass);
  background: rgba(239, 191, 85, 0.08);
  color: var(--brass);
}
/* A locked letter in the row being typed: drawn as big as the dials beside it. */
.row.entry .tile.fixed {
  --t2: calc(var(--dial) - 4px);
  margin: 2px;
}

/* The row being typed: one dial per letter. The button is the dial's touch
   area, meeting its neighbours' with no gap (a tap between two dials lands on
   the nearer one); the dial is drawn 2 px inside it. At least --dial-min, so
   it is thumb-sized and its range of letters is never under the smallest
   text size. */
.dial {
  position: relative;
  width: var(--dial);
  height: var(--dial);
  padding: 2px;
  border: 0;
  border-radius: calc(var(--dial) * 0.2);
  background: none;
  display: inline-grid;
  cursor: pointer;
  color: var(--text);
  flex: none;
}
.dial-face {
  position: relative;
  display: grid;
  place-items: center;
  border-radius: calc(var(--dial) * 0.18);
  border: 2px solid #4a5a70;
  background: radial-gradient(circle at 50% 38%, #2a3445, #171d28 75%);
  font-weight: 800;
  font-size: calc(var(--dial) * 0.46);
  line-height: 1;
}
.dial .range {
  position: absolute;
  top: calc(var(--dial) * 0.04);
  left: 0;
  right: 0;
  font-size: max(var(--text-min), calc(var(--dial) * 0.2));
  font-weight: 700;
  color: #8fa0b5;
  letter-spacing: 0.02em;
  text-align: center;
  line-height: 1;
  white-space: nowrap;
}
.dial .l {
  transform: translateY(calc(var(--dial) * 0.11));
}
.dial.cursor .dial-face {
  border-color: var(--brass);
  box-shadow:
    0 0 0 3px rgba(239, 191, 85, 0.25),
    0 0 18px rgba(239, 191, 85, 0.25);
}
.dial.cursor .dial-face::after {
  content: '';
  position: absolute;
  bottom: calc(var(--dial) * 0.07);
  left: 30%;
  right: 30%;
  height: 3px;
  border-radius: 2px;
  background: var(--brass);
  animation: caret 1s steps(1) infinite;
}
.dial.cursor.filled .dial-face::after {
  opacity: 0.5;
  animation: none;
}
@keyframes caret {
  50% {
    opacity: 0;
  }
}
.dial.filled .dial-face {
  border-color: #6b7d95;
}
.dial.filled .l {
  animation: type-pop 0.12s ease-out;
}
@keyframes type-pop {
  from {
    transform: translateY(calc(var(--dial) * 0.11)) scale(1.25);
  }
}

/* Reveal: each dial flips to its mark in turn. */
.row.revealing .tile {
  animation: flip 0.34s ease both;
  animation-delay: calc(var(--i, 0) * 0.11s);
}
.row.revealing .tile .mk,
.row.revealing .tile .l {
  animation: mark-in 0.34s ease both;
  animation-delay: calc(var(--i, 0) * 0.11s);
}
@keyframes flip {
  0% {
    transform: rotateX(0deg);
    background: #1c2330;
    border-color: #6b7d95;
    color: var(--text);
  }
  49% {
    background: #1c2330;
    border-color: #6b7d95;
    color: var(--text);
  }
  50% {
    transform: rotateX(90deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}
@keyframes mark-in {
  0%,
  50% {
    opacity: 0;
  }
  51%,
  100% {
    opacity: 1;
  }
}
.row.revealing .tile .l {
  animation-name: none;
}

.lock.just-opened {
  animation: lock-glow 0.9s ease-out;
}
.lock.just-opened .row.answer .tile {
  animation: pop 0.45s cubic-bezier(0.3, 1.6, 0.5, 1) both;
}
.lock.just-opened .row.answer .tile:nth-child(2) {
  animation-delay: 0.04s;
}
.lock.just-opened .row.answer .tile:nth-child(3) {
  animation-delay: 0.08s;
}
.lock.just-opened .row.answer .tile:nth-child(4) {
  animation-delay: 0.12s;
}
.lock.just-opened .row.answer .tile:nth-child(5) {
  animation-delay: 0.16s;
}
.lock.just-opened .row.answer .tile:nth-child(6) {
  animation-delay: 0.2s;
}
@keyframes pop {
  0% {
    transform: scale(0.7);
  }
  100% {
    transform: scale(1);
  }
}
@keyframes lock-glow {
  0% {
    box-shadow: 0 0 0 0 rgba(239, 191, 85, 0.7);
  }
  100% {
    box-shadow: 0 0 0 18px rgba(239, 191, 85, 0);
  }
}
.row.shake {
  animation: shake 0.4s ease;
}
@keyframes shake {
  20% {
    transform: translateX(-7px);
  }
  40% {
    transform: translateX(6px);
  }
  60% {
    transform: translateX(-4px);
  }
  80% {
    transform: translateX(2px);
  }
}

.msg {
  min-height: 24px;
  padding: 2px calc(12px + var(--safe-right)) 2px calc(12px + var(--safe-left));
  text-align: center;
  font-size: max(14px, var(--text-min));
  line-height: 1.35;
  color: #cfd6df;
}
.msg.bad {
  color: #ffb3a8;
}
.msg.good {
  color: var(--brass);
  font-weight: 700;
}
.msg.warn {
  color: #ffc2b5;
  font-weight: 700;
}

/* ---------- keyboard ---------- */

/* The on-screen keys. Each key's touch area meets its neighbours' with no
   gap, as on a phone's own keyboard, so a tap between two keys lands on the
   nearer one; the key is drawn inside it, the gap between drawn keys being its
   transparent border. A key area is at least 46 px tall; on a phone the ten
   keys of a row are as wide as the row allows (DESIGN.md, "Platforms"). */
.keyboard {
  --key-h: clamp(46px, 7.6dvh, 62px);
  --key-gap: 2.5px;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: 2px calc(var(--edge) + var(--safe-right)) calc(var(--edge) + var(--safe-bottom)) calc(var(--edge) + var(--safe-left));
}
.krow {
  display: flex;
  justify-content: center;
}
.krow:nth-child(2)::before,
.krow:nth-child(2)::after {
  content: '';
  flex: 0.5 1 0;
}
.key {
  display: grid;
  place-items: center;
  flex: 1 1 0;
  min-width: 0;
  height: var(--key-h);
  border: var(--key-gap) solid transparent;
  border-radius: 10px;
  background: #2c3647 padding-box;
  color: var(--text);
  font-weight: 700;
  font-size: 18px;
  cursor: pointer;
  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.3);
  padding: 0;
  white-space: nowrap;
  /* Only the pressed colour fades: a key dims or lights at once as the cursor
     moves, as a fade on a dozen keys at every key press made typing cost
     several times more (DESIGN.md, "Platforms"). */
  transition: background-color 0.1s;
}
@media (hover: hover) {
  .key:hover {
    background-color: #36425a;
  }
}
.key:active {
  background-color: #45536b;
  transform: translateY(1px);
}
.key.wide {
  flex: 1.65 1 0;
  font-size: max(14px, var(--text-min));
  background-color: #3a465a;
}
.key svg {
  width: 26px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.key.dim {
  opacity: 0.35;
}
.keyboard.off .key {
  opacity: 0.35;
  pointer-events: none;
}

/* Alphabet order makes a narrow keypad easy to scan without tiny keys.
   Every hit area meets its neighbours and is at least 44 × 44 px. */
.keyboard.compact {
  display: grid;
  grid-template-columns: repeat(6, minmax(44px, 1fr));
  --key-h: clamp(44px, 5dvh, 56px);
}
.keyboard.compact .krow {
  display: contents;
}
.keyboard.compact .krow::before,
.keyboard.compact .krow::after {
  display: none;
}
.keyboard.compact .key {
  order: var(--order);
}
.keyboard.compact .key.wide {
  grid-column: span 2;
}
.keyboard.compact.compact-wide {
  grid-template-columns: repeat(7, minmax(44px, 1fr));
}
.keyboard.compact.compact-wide .key.wide {
  grid-column: span 1;
}
.keyboard.compact .krow:last-child {
  padding: 0;
}
@media (pointer: coarse) and (max-width: 599px), (pointer: coarse) and (max-height: 599px) {
  .keyboard.compact {
    padding-bottom: max(24px, calc(var(--edge) + var(--safe-bottom)));
  }
}

/* ---------- sheets ---------- */

.overlay {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  padding: 14px calc(12px + var(--safe-right)) calc(24px + var(--safe-bottom)) calc(12px + var(--safe-left));
  background: rgba(6, 9, 13, 0.74);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  user-select: text;
  -webkit-user-select: text;
}
.sheet {
  position: relative;
  width: min(460px, 100%);
  margin: auto 0;
  padding: 20px 16px 16px;
  border-radius: 18px;
  border: 1px solid #3a4658;
  background: linear-gradient(180deg, #1d2532, var(--panel));
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
  animation: sheet-in 0.22s ease-out;
}
.sheet:focus {
  outline: none;
}
@keyframes sheet-in {
  from {
    transform: translateY(12px);
    opacity: 0;
  }
}
.sheet h2 {
  margin: 0 40px 8px 0;
  font-size: 24px;
}
.sheet-results h2 {
  margin: 0 0 4px;
  text-align: center;
}
.sheet h3 {
  margin: 16px 0 8px;
  font-size: max(13px, var(--text-min));
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.sheet p {
  margin: 8px 0;
  line-height: 1.45;
}
.sheet-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
}
@media (hover: hover) {
  .sheet-close:hover {
    background: var(--panel-3);
    color: var(--text);
  }
}
.sheet-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}
.sheet-actions .btn {
  flex: 1 1 130px;
}
.sheet-actions .btn.primary {
  flex-basis: 100%;
}

.res-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto 6px;
}
.res-icon svg {
  width: 100%;
  height: 100%;
}
.vi-body {
  fill: #283243;
  stroke: var(--brass);
  stroke-width: 3;
}
.vi-door {
  fill: #3a4658;
  stroke: var(--brass);
  stroke-width: 2;
}
.vi-hole {
  fill: #0b0e13;
  stroke: #ffe08e;
  stroke-width: 2;
}
.vi-dial {
  fill: #1c2330;
  stroke: var(--bad);
  stroke-width: 3;
}
.vi-hand {
  fill: none;
  stroke: var(--bad);
  stroke-width: 3;
  stroke-linecap: round;
}
.res-icon.won {
  animation: pop 0.5s cubic-bezier(0.3, 1.6, 0.5, 1);
}
.res-sub {
  text-align: center;
  color: var(--muted);
  font-size: max(14px, var(--text-min));
  margin: 0 0 8px !important;
}
.res-big {
  text-align: center;
  font-size: 18px;
  color: #d7dde5;
}
.res-big strong {
  font-size: 40px;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
}
.res-locks {
  list-style: none;
  margin: 12px 0 8px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.res-locks li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.res-word {
  display: flex;
  gap: 3px;
}
.rt {
  width: 26px;
  height: 26px;
  display: inline-grid;
  place-items: center;
  border-radius: 6px;
  font-weight: 800;
  font-size: 15px;
}
.rt.hit {
  background: linear-gradient(180deg, #ffd978, var(--brass-2));
  color: var(--brass-ink);
}
.rt.answer {
  border: 2px dashed var(--brass);
  color: var(--brass);
}
.res-picks {
  color: var(--muted);
  font-size: max(14px, var(--text-min));
  white-space: nowrap;
}
.res-locks li.shut .res-picks {
  color: #ffb3a8;
}
.mini {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  margin: 10px 0;
}
.mini-row {
  display: flex;
  gap: 3px;
}
.mini-cell {
  width: 14px;
  height: 14px;
  border-radius: 3px;
  position: relative;
}
.mini-cell.hit {
  background: var(--brass);
}
.mini-cell.up {
  background: rgba(92, 184, 239, 0.25);
  border-top: 4px solid var(--early);
}
.mini-cell.down {
  background: rgba(255, 138, 76, 0.25);
  border-bottom: 4px solid var(--late);
}
.res-streak,
.res-next {
  text-align: center;
  color: #d7dde5;
}
.res-next {
  color: var(--brass);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.res-ach {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
}
.res-ach-label {
  width: 100%;
  text-align: center;
  font-size: var(--text-min);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.chip {
  border: 1px solid rgba(239, 191, 85, 0.55);
  background: rgba(239, 191, 85, 0.1);
  color: var(--brass);
  border-radius: 999px;
  padding: 4px 10px;
  font-size: max(14px, var(--text-min));
  font-weight: 700;
}
/* Each new achievement says what earned it: a tooltip would need a mouse. */
.res-ach-list {
  width: 100%;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.res-ach-list li {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 4px 8px;
  text-align: center;
}
.res-ach-text {
  color: var(--muted);
  font-size: max(14px, var(--text-min));
}
.done-bar {
  padding: 6px calc(var(--edge) + var(--safe-right)) max(10px, calc(var(--edge) + var(--safe-bottom))) calc(var(--edge) + var(--safe-left));
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
}
.done-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.done-actions .btn {
  flex: 1 1 120px;
}
.done-actions .btn.primary {
  flex-basis: 100%;
}
.done-next {
  margin: 10px 0 0;
  text-align: center;
  color: var(--brass);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.share-note {
  text-align: center;
  font-size: max(14px, var(--text-min));
  color: var(--muted);
  min-height: 1em;
}
.share-text {
  width: 100%;
  font:
    max(14px, var(--text-min)) / 1.4 ui-monospace,
    monospace;
  background: #0f131a;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(76px, 1fr));
  gap: 8px;
}
.stat {
  background: var(--panel-2);
  border-radius: 10px;
  padding: 8px 6px;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.stat strong {
  font-size: 22px;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
}
.stat span {
  font-size: var(--text-min);
  color: var(--muted);
}
.stat-note {
  font-size: max(14px, var(--text-min));
  color: var(--muted);
}
.dist {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.dist-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.dist-n {
  width: calc(var(--text-min) * 1.4);
  text-align: right;
  font-size: var(--text-min);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.dist-bar {
  width: var(--w);
  min-width: calc(var(--text-min) * 2.2);
  background: #3a4658;
  border-radius: 4px;
  padding: 1px 6px;
  text-align: right;
  font-size: var(--text-min);
  font-weight: 700;
}
.dist-row.mine .dist-bar {
  background: var(--brass-2);
  color: var(--brass-ink);
}
.ach-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ach-list .ach {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 8px;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--panel-2);
  opacity: 0.6;
}
.ach-list .ach.got {
  opacity: 1;
  border: 1px solid rgba(239, 191, 85, 0.45);
}
.ach-list .ach strong {
  grid-column: 1;
}
.ach-list .ach span:not(.ach-state) {
  grid-column: 1;
  font-size: var(--text-min);
  color: var(--muted);
}
.ach-state {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  font-size: var(--text-min);
  color: var(--muted);
}
.ach-list .ach.got .ach-state {
  color: var(--brass);
  font-weight: 700;
}

.arch-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.arch-item {
  width: 100%;
  display: grid;
  grid-template-columns: 48px 1fr auto;
  align-items: center;
  gap: 8px;
  text-align: left;
  padding: 10px 10px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  cursor: pointer;
}
@media (hover: hover) {
  .arch-item:hover {
    border-color: #4a5a70;
  }
}
.arch-num {
  font-weight: 800;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.arch-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.arch-theme {
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.arch-date {
  font-size: var(--text-min);
  color: var(--muted);
}
.arch-status {
  font-size: var(--text-min);
  color: var(--muted);
  text-align: right;
}
.arch-item.won .arch-status {
  color: var(--brass);
}
.arch-item.lost .arch-status {
  color: #ffb3a8;
}
.arch-item.fresh .arch-status {
  color: var(--early);
}

.help-lead {
  font-size: 16px;
}
.help-row {
  --t: 44px;
  margin: 6px 0 10px;
}
.help-marks {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.help-marks li {
  display: flex;
  align-items: center;
  gap: 10px;
}
.tile.mini-tile {
  --t2: 36px;
}
.help-small {
  font-size: max(14px, var(--text-min));
  color: var(--muted);
}

/* ---------- below the game ---------- */

.ad-slot {
  max-width: 970px;
  margin: 12px auto 0;
}
.about {
  max-width: 760px;
  margin: 0 auto;
  padding: 20px 16px 8px;
  color: #cfd6df;
  line-height: 1.55;
  user-select: text;
  -webkit-user-select: text;
}
.about h2 {
  color: var(--text);
}
.about h3 {
  margin-top: 20px;
  color: var(--text);
}
.credits {
  font-size: 14px;
  color: var(--muted);
}

/* ---------- sizes ---------- */

@media (min-width: 700px) and (min-height: 700px) {
  .play-bar {
    padding-top: 12px;
  }
  .vt-theme {
    font-size: 20px;
  }
  .picks {
    height: 30px;
  }
  .pick {
    height: 26px;
    width: 12px;
  }
  .keyboard {
    --key-h: clamp(52px, 6.4dvh, 64px);
    padding-bottom: calc(16px + var(--safe-bottom));
  }
  .key {
    font-size: 20px;
  }
  .msg {
    font-size: max(15px, var(--text-min));
    min-height: 28px;
  }
}

/* Tablets: room in each dial for its range at 15 px. */
@media (pointer: coarse) and (min-width: 600px) and (min-height: 600px) {
  .board {
    --dial-min: 50px;
  }
}

/* Phones: the screen's corners stay clear, as Android reports no rounded
   corners (docs/PLATFORMS.md, "Safe areas"): the bottom row of keys is 8 px
   narrower, and the buttons after a vault sit 24 px up. */
@media (pointer: coarse) and (max-width: 599px), (pointer: coarse) and (max-height: 599px) {
  .krow:last-child {
    padding: 0 8px;
  }
  .done-bar {
    padding-bottom: max(24px, calc(var(--edge) + var(--safe-bottom)));
  }
}

@media (max-width: 400px) {
  .vt-theme {
    font-size: 15px;
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-height: 1.1;
  }
  .lock-len {
    display: none;
  }
}

/* The theme is the clue: it must remain readable beside the toolbar. */
@media (max-width: 599px) and (orientation: portrait) {
  .play-bar,
  .lw.is-full .play-bar {
    flex-wrap: wrap;
  }
  .play-bar {
    padding-top: 26px;
  }
  .vault-title {
    order: 3;
    flex-basis: 100%;
  }
  .vt-theme {
    white-space: normal;
    overflow: visible;
    display: block;
  }
}

/* The narrowest phones: Enter and Delete take a little more of their row. */
@media (max-width: 360px) {
  .keyboard {
    --key-gap: 2px;
  }
  .key {
    font-size: 16px;
  }
  .key.wide {
    flex-grow: 2;
    font-size: var(--text-min);
  }
  .board {
    --tile-gap: 5px;
  }
  .bar-btn span {
    display: none;
  }
}

/* Held sideways (a phone, a tablet, a desktop window wider than it is tall):
   two columns. The board takes the game's whole height on the left, so it
   is as large as the screen allows; the play bar, the picks, the messages
   and the keys stand on the right, the keys at the bottom (DESIGN.md,
   "Platforms"). */
@media (orientation: landscape) and (max-height: 520px), (orientation: landscape) and (min-width: 900px) {
  .play {
    max-width: 1200px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr);
    grid-template-areas:
      'board bar'
      'board picks'
      'board side';
    column-gap: 8px;
  }
  .play-main {
    display: contents;
  }
  .play-bar {
    grid-area: bar;
    padding-left: 8px;
  }
  .picks {
    grid-area: picks;
  }
  /* At the screen's left and bottom edges: the dials keep 16 px inside the
     safe areas (24 from the side, clear of the corners). */
  .board {
    grid-area: board;
    padding: 8px 4px calc(8px + var(--safe-bottom)) calc(max(8px, var(--edge)) + var(--safe-left));
  }
  .side {
    grid-area: side;
    min-width: 0;
    justify-content: flex-end;
  }
  .keyboard {
    padding-left: 0;
  }
}

/* Phones held sideways: the same two columns at phone scale. A waiting lock
   shows its heading alone (its letters' count is in it), which leaves two
   more rows for the lock being picked; past the smallest tiles the board
   scrolls by itself, keeping the row being typed in view. */
@media (orientation: landscape) and (max-height: 520px) {
  .play {
    max-width: none;
    grid-template-columns: minmax(0, 1fr) minmax(calc(308px + var(--edge) + var(--safe-right)), 1fr);
  }
  .play-bar {
    padding-top: 2px;
    padding-bottom: 0;
    min-height: 44px;
  }
  .picks {
    height: 18px;
  }
  .pick {
    height: 17px;
  }
  .board {
    --shut-rows: 0;
    padding-top: 2px;
    gap: 5px;
  }
  .lock {
    padding-left: 6px;
    padding-right: 6px;
  }
  .row.shut {
    display: none;
  }
  .lock-head {
    height: calc(var(--text-min) * 1.45);
  }
  .keyboard {
    --key-h: clamp(44px, calc((100dvh - var(--header-h) - 120px) / 3), 52px);
  }
  .key {
    font-size: 16px;
  }
  .key.wide {
    flex-grow: 1.8;
    font-size: max(13px, var(--text-min));
  }
  .msg {
    min-height: 20px;
    font-size: var(--text-min);
  }
  .home-inner {
    width: min(760px, 100%);
    display: grid;
    grid-template-columns: 1fr 1.2fr;
    align-items: center;
    column-gap: 20px;
    padding-top: 10px;
  }
  .home-inner .brand {
    grid-row: 1 / span 4;
  }
  .brand h1 {
    font-size: 34px;
  }
}

/* The smallest phones held sideways: Menu shows its arrow alone, so the
   vault's name keeps room beside it in the narrower column. */
@media (orientation: landscape) and (max-height: 520px) and (max-width: 760px) {
  .bar-btn span {
    display: none;
  }
}

/* ---------- full screen (the site's button; docs/PLATFORMS.md, "Full screen") ---------- */

/* main.js marks the root .is-full while it is the fullscreen element. The
   site's "Leave full screen" stays at the top in the middle, at --fs-top (on
   a touch screen 16 px down, as every control keeps from the edges). Held
   sideways it sits in a gutter between the two columns; upright, where the
   play bar is wide enough (a tablet), in the bar's middle, which the vault's
   name stops short of; on a phone held upright, and over the menus and
   sheets, everything starts below it, in a band of its own. */
.lw.is-full {
  --fs-top: max(8px, var(--safe-top));
  --fs-band: calc(var(--fs-top) + 52px);
}
@media (pointer: coarse) {
  .lw.is-full {
    --fs-top: calc(16px + var(--safe-top));
  }
}
/* Phones held sideways: 24 px down clears the screen's corner beside the
   play bar's buttons, unless a notch already keeps them 8 px or more from
   the side. */
@media (pointer: coarse) and (orientation: landscape) and (max-height: 520px) {
  .lw.is-full {
    --fs-top: calc(max(16px, 24px - var(--safe-right)) + var(--safe-top));
  }
}
.lw.is-full > .am-fs-exit {
  top: var(--fs-top);
}
.lw.is-full .home-inner,
.lw.is-full .overlay {
  padding-top: var(--fs-band);
}
.lw.is-full .play-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 60px minmax(0, 1fr);
  min-height: calc(var(--fs-top) + 48px);
  padding-top: var(--fs-top);
  padding-left: calc(var(--edge) + max(var(--safe-left), var(--safe-right)));
  padding-right: calc(var(--edge) + max(var(--safe-left), var(--safe-right)));
}
.lw.is-full .vault-title {
  align-items: flex-start;
  text-align: left;
}
.lw.is-full .bar-right {
  grid-column: 3;
  justify-self: end;
}
/* Phones held upright: no room to spare in the play bar's middle. */
@media (max-width: 599px) and (orientation: portrait) {
  .lw.is-full .play-bar {
    display: flex;
    min-height: 0;
    padding-top: var(--fs-band);
  }
  .lw.is-full .vault-title {
    align-items: center;
    text-align: center;
  }
}
/* Held sideways: the two columns share the width evenly around a gutter
   for the button, and start --fs-top down. */
@media (orientation: landscape) and (max-height: 520px), (orientation: landscape) and (min-width: 900px) {
  .lw.is-full .play {
    max-width: none;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 60px;
    padding-top: var(--fs-top);
  }
  .lw.is-full .play-bar {
    display: flex;
    min-height: 44px;
    padding: 0 calc(var(--edge) + var(--safe-right)) 0 0;
  }
  .lw.is-full .vault-title {
    align-items: center;
    text-align: center;
  }
  .lw.is-full .board {
    padding-top: 0;
  }
}

@media (orientation: landscape) and (max-height: 520px) {
  .lw.is-full .play {
    column-gap: 52px;
  }
  .lw.is-full .board {
    padding-right: 0;
  }
  .play-bar .vault-title {
    position: absolute;
    top: 2px;
    left: calc(var(--edge) + var(--safe-left));
    width: calc((100% - 8px) / 2 - var(--edge) - var(--safe-left) - 8px);
  }
  .lw.is-full .play-bar .vault-title {
    top: var(--fs-top);
    width: calc((100% - 52px) / 2 - var(--edge) - var(--safe-left) - 8px);
  }
  .vt-theme {
    white-space: normal;
    overflow: visible;
    font-size: var(--text-min);
    line-height: 1.2;
  }
  .play .board,
  .lw.is-full .play .board {
    padding-top: 38px;
  }
  .play-bar .bar-left {
    flex: 1;
  }
}

/* Large screens use their space on the page as well as in full screen.
   The locks keep the same rows and proportions; only their scale grows. */
@media (min-width: 1600px) and (min-height: 1600px) {
  :root {
    --text-min: 24px;
  }
  .play {
    max-width: none;
  }
  .keyboard {
    max-width: 1100px;
    --key-h: 96px;
  }
  .key {
    font-size: 30px;
  }
  .vt-theme {
    font-size: 32px;
  }
  .play-bar {
    min-height: 80px;
  }
  .bar-btn {
    font-size: 24px;
  }
}
@media (orientation: portrait) and (min-width: 600px) {
  .play {
    max-width: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Calm decoration; action and result feedback keep their timing. */
  .brand-dial, .picks.low .pick:not(.used), .dial.cursor .dial-face::after, .row.shake, .sheet { animation: none; }
  button, .switch, .switch i { transition: none; }
}
