/* Words of Hanoi. A self-contained sheet for /hanoi and /hanoi/about.
 *
 * The system in one paragraph: two faces (Newsreader for words, IBM Plex
 * Mono for letters, numbers and labels), a 4 px spacing grid, one hairline
 * weight for all structure, cool graphite neutrals, and a single verdigris
 * accent that appears only when something is live: the tube you have picked
 * up, the tube you may drop on, a tube that has become a word. Every state
 * also changes shape or weight, so the board reads without colour.
 *
 * Geometry is soft: the tube is a filled capsule, round at both ends; the
 * tile is a filled rounded square whose radius is a third of its side;
 * buttons, chips, the sheet and the strips share one generous radius.
 * Nothing is squared off, nothing is bubbly, nothing is outlined that can
 * be a quiet filled shape instead.
 */

/* Faces. Subset to Latin, served from the site's own assets. The fallback
   faces carry metric overrides so the swap does not move the layout. */
@font-face {
  font-family: 'Newsreader';
  src: url('/assets/fonts/newsreader-text.woff2') format('woff2');
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/assets/fonts/newsreader-text-italic.woff2') format('woff2');
  font-style: italic;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: 'Newsreader Display';
  src: url('/assets/fonts/newsreader-display.woff2') format('woff2');
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: 'Plex Mono';
  src: url('/assets/fonts/plex-mono-regular.woff2') format('woff2');
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: 'Plex Mono';
  src: url('/assets/fonts/plex-mono-medium.woff2') format('woff2');
  font-style: normal;
  font-weight: 500;
  font-display: swap;
}

/* Metric-matched fallbacks: Georgia sized to Newsreader's lowercase, and a
   generic monospace sized to Plex Mono's 600-unit advance. */
@font-face {
  font-family: 'Newsreader Fallback';
  src: local('Georgia'), local('Times New Roman');
  size-adjust: 97.3%;
  ascent-override: 75.5%;
  descent-override: 27.2%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Newsreader Display Fallback';
  src: local('Georgia'), local('Times New Roman');
  size-adjust: 100.9%;
  ascent-override: 72.9%;
  descent-override: 26.3%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Plex Mono Fallback';
  src: local('Menlo'), local('Consolas'), local('Courier New');
  size-adjust: 100%;
  ascent-override: 102.5%;
  descent-override: 27.5%;
  line-gap-override: 0%;
}

/* Tokens. Light first, then the two ways of asking for dark. */
:root {
  color-scheme: light;
  --bg: #f4f5f7;
  --surface: #fbfbfc;
  --tube: #e9ebef;
  --tile: #d6dae1;
  --ink: #17191e;
  --ink-2: #4b505c;
  --ink-3: #606673;
  --hair: #d9dce2;
  --hair-2: #a5abb7;
  --accent: #14776a;
  --accent-ink: #0f5f55;
  --accent-wash: #e4f1ee;
  --shadow: rgb(23 25 30 / 14%);
  --scrim: rgb(23 25 30 / 28%);

  --serif: 'Newsreader', 'Newsreader Fallback', Georgia, 'Times New Roman', serif;
  --display: 'Newsreader Display', 'Newsreader Display Fallback', Georgia, 'Times New Roman', serif;
  --mono: 'Plex Mono', 'Plex Mono Fallback', Menlo, Consolas, 'Courier New', monospace;

  /* Type scale, 1.2 ratio on 16. */
  --t-1: 0.6875rem; /* 11 */
  --t0: 0.8125rem; /* 13 */
  --t1: 1rem; /* 16 */
  --t2: 1.1875rem; /* 19 */
  --t3: 1.4375rem; /* 23 */
  --t4: 1.75rem; /* 28 */
  --t5: 2.125rem; /* 34 */
  --t6: 2.625rem; /* 42 */

  /* Spacing, 4 px grid. */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;
  --s8: 64px;

  --hairline: 1px;
  --radius: 12px; /* buttons, strips, inputs, code */
  --radius-chip: 999px; /* word chips, keys, the picked-up outline */
  --radius-sheet: 20px; /* the stats sheet's leading corners */
  --glow: 0 0 0 4px var(--accent-wash);
  --ease: cubic-bezier(0.33, 1, 0.68, 1); /* ease-out cubic: a settle, not a snap */
  --ease-soft: cubic-bezier(0.45, 0, 0.2, 1); /* symmetric, for lifts that return */
  --quick: 220ms;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    color-scheme: dark;
    --bg: #111318;
    --surface: #171a20;
    --tube: #1a1e25;
    --tile: #2e343e;
    --ink: #e9ebef;
    --ink-2: #aab0bc;
    --ink-3: #8a919e;
    --hair: #2b3039;
    --hair-2: #4d5461;
    --accent: #6fcfbd;
    --accent-ink: #8ddccd;
    --accent-wash: #16302c;
    --shadow: rgb(0 0 0 / 45%);
    --scrim: rgb(0 0 0 / 55%);
  }
}

:root[data-theme='dark'] {
  color-scheme: dark;
  --bg: #111318;
  --surface: #171a20;
  --tube: #1a1e25;
  --tile: #2e343e;
  --ink: #e9ebef;
  --ink-2: #aab0bc;
  --ink-3: #8a919e;
  --hair: #2b3039;
  --hair-2: #4d5461;
  --accent: #6fcfbd;
  --accent-ink: #8ddccd;
  --accent-wash: #16302c;
  --shadow: rgb(0 0 0 / 45%);
  --scrim: rgb(0 0 0 / 55%);
}

/* Base. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-padding-top: 72px;
}

body {
  min-width: 320px;
  min-height: 100svh;
  margin: 0;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  overflow-x: clip;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--t1);
  line-height: 1.5;
  font-kerning: normal;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a {
  color: inherit;
  text-decoration-thickness: var(--hairline);
  text-underline-offset: 0.18em;
  text-decoration-color: var(--hair-2);
}

a:hover {
  text-decoration-color: currentColor;
}

button,
a {
  -webkit-tap-highlight-color: transparent;
}

button {
  margin: 0;
  color: inherit;
  font: inherit;
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

h1,
h2,
h3,
p {
  overflow-wrap: break-word;
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 400;
}

[hidden] {
  display: none !important;
}

code,
pre {
  font-family: var(--mono);
}

/* The label style: mono, small, tracked, upper. Used for every caption. */
.label {
  font-family: var(--mono);
  font-size: var(--t-1);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.skip-link {
  position: fixed;
  top: var(--s2);
  left: var(--s2);
  z-index: 100;
  padding: var(--s2) var(--s3);
  background: var(--ink);
  color: var(--bg);
  font-family: var(--mono);
  font-size: var(--t0);
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

/* Header: one hairline, the mark, three quiet controls. */
.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  width: min(100% - var(--s8), 1120px);
  min-height: 56px;
  margin: 0 auto;
  border-bottom: var(--hairline) solid var(--hair);
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--t0);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-decoration: none;
}

.wordmark-mark {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}

.wordmark-mark circle:last-child {
  fill: currentColor;
  stroke: none;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--s1);
}

.nav-button {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--s3);
  border: 0;
  background: transparent;
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: var(--t0);
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
}

.nav-button:hover,
.nav-button[aria-expanded='true'] {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: var(--hairline);
  text-underline-offset: 0.3em;
}

.theme-toggle {
  display: inline-grid;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  place-items: center;
}

.theme-toggle:hover {
  color: var(--ink);
}

.theme-toggle svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}

/* Main column. On a wide screen the words sit left and the board right,
   both hung from the same top line. */
.hanoi-main {
  display: grid;
  width: min(100% - var(--s8), 1120px);
  margin: 0 auto;
  padding: var(--s7) 0 var(--s8);
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    'intro'
    'help'
    'shell'
    'note';
}

.hanoi-intro { grid-area: intro; }
.hanoi-help { grid-area: help; }
.hanoi-shell { grid-area: shell; }
.noscript-note { grid-area: note; }

@media (min-width: 900px) {
  .hanoi-main {
    column-gap: var(--s8);
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    grid-template-areas:
      'intro shell'
      'help shell'
      'note note';
    align-items: start;
  }

  .hanoi-main > .hanoi-shell {
    margin-top: var(--s2);
  }

  .hanoi-help {
    max-width: 480px;
  }
}

/* Intro: the title, one line of copy, and the edition stamp on a hairline. */
.hanoi-intro {
  display: grid;
  gap: var(--s3);
  max-width: 560px;
}

.hanoi-intro h1 {
  font-family: var(--display);
  font-size: clamp(var(--t5), 3.2vw + 1rem, var(--t6));
  line-height: 1.05;
  letter-spacing: -0.012em;
}

.hanoi-lede {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--t2);
  line-height: 1.4;
  text-wrap: pretty;
}

.hanoi-stamp {
  display: block;
  min-height: 1.5em;
  margin: var(--s2) 0 0;
  padding-top: var(--s3);
  border-top: var(--hairline) solid var(--hair);
  font-style: normal;
}

/* How to play. A numbered list with a hairline between rules. */
.hanoi-help {
  max-width: 560px;
  margin-top: var(--s6);
  padding-top: var(--s4);
  border-top: var(--hairline) solid var(--hair-2);
}

.hanoi-help h2 {
  font-family: var(--mono);
  font-size: var(--t0);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.hanoi-help ol {
  margin: var(--s3) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: rule;
}

.hanoi-help li {
  display: grid;
  gap: var(--s4);
  padding: var(--s3) 0;
  border-top: var(--hairline) solid var(--hair);
  color: var(--ink-2);
  font-size: var(--t1);
  grid-template-columns: 2ch 1fr;
  counter-increment: rule;
}

.hanoi-help li::before {
  content: counter(rule, decimal-leading-zero);
  font-family: var(--mono);
  font-size: var(--t-1);
  line-height: 2.1;
  color: var(--ink-3);
}

.hanoi-help kbd {
  padding: 0 0.35em;
  border: var(--hairline) solid var(--hair-2);
  border-radius: 6px;
  font-family: var(--mono);
  font-size: 0.85em;
  color: var(--ink);
}

/* The shell: counters, board, caption, controls, all on one column.

   Sizing is plain pixels. The board is as wide as the column, capped at
   --board-max, and the page measures that width and writes --hanoi-tile and
   --hanoi-gap in px on the board (see sizeBoard in hanoi.js). Nothing here
   leans on viewport units, container units, aspect-ratio, ch, or on a flex
   item stretching inside a <button>: Safari on the founder's device resolved
   those differently from the Playwright WebKit build, and drew the tubes at
   the 46 px floor with tile fills the width of a letter. */
.hanoi-shell {
  --hanoi-tile: 46px;
  --hanoi-gap: 8px;
  --hanoi-height: 4;
  --hanoi-tubes: 5;
  --board-max: 380px;
  width: min(100%, 640px);
  margin: var(--s7) auto 0;
}

.hanoi-counters {
  display: grid;
  width: min(100%, var(--board-max));
  margin: 0 auto;
  padding-bottom: var(--s2);
  border-bottom: var(--hairline) solid var(--hair-2);
  grid-template-columns: 1fr auto 1fr;
  gap: var(--s3);
  align-items: baseline;
}

.hanoi-counters p {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--t0);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

.hanoi-counters p:first-child {
  color: var(--ink);
  font-weight: 500;
}

.hanoi-counters p:last-child {
  text-align: right;
}

.hanoi-counters .game-folio {
  color: var(--ink-3);
  font-size: var(--t-1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The board. Five open tubes on a grid that fills the column, so the tubes
   share the width the text has, and a 44 px tap target still holds at 320.
   Room for the word under each tube is held open from the start, so a win
   never shifts anything. */
.hanoi-board {
  position: relative;
  display: grid;
  width: min(100%, var(--board-max));
  margin: var(--s6) auto 0;
  padding-bottom: 26px;
  grid-template-columns: repeat(var(--hanoi-tubes), var(--hanoi-tile));
  gap: var(--hanoi-gap);
  justify-content: center;
}

/* The tube is a filled capsule, round at both ends: a quiet grey fill with
   a hairline rim one step darker, so it reads as a shape rather than a
   frame. Every state changes the rim or the halo, never only the hue. */
.hanoi-tube {
  --tube-round: calc(var(--hanoi-tile) / 2);
  position: relative;
  display: flex;
  width: var(--hanoi-tile);
  min-width: 0;
  height: calc(var(--hanoi-tile) * var(--hanoi-height) + 30px);
  padding: 0 4px 6px;
  border: var(--hairline) solid var(--hair);
  border-radius: var(--tube-round);
  background: var(--tube);
  touch-action: none;
  cursor: pointer;
  flex-direction: column;
  justify-content: flex-end;
  transition:
    border-color var(--quick) var(--ease),
    box-shadow var(--quick) var(--ease),
    background-color var(--quick) var(--ease);
}

.hanoi-tube:hover:not([disabled]) {
  border-color: var(--hair-2);
}

/* Full but not a word: the rim goes dashed, one step darker. */
.hanoi-tube[data-full='true'] {
  border-color: var(--hair-2);
  border-style: dashed;
}

/* A word: the capsule seals solid, 1.5 px, in the accent, with the wash
   inside and a label beneath on the win. */
.hanoi-tube[data-word='true'] {
  border-color: var(--accent);
  border-style: solid;
  border-width: 1.5px;
  background: var(--accent-wash);
}

/* Selected: the rim goes to ink, a soft ink halo sits round the capsule,
   and the top tile lifts out. */
.hanoi-tube[aria-pressed='true'] {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px var(--bg), 0 0 0 4px var(--ink);
}

/* Droppable: a dashed accent rim, the wash inside and a soft glow around;
   the shape changes, not just the hue. */
.hanoi-tube[data-drop-target='true'] {
  border-style: dashed;
  border-color: var(--accent);
  background: var(--accent-wash);
  box-shadow: var(--glow);
}

/* An invalid drop: a short dotted flash of the rim and a soft sway, set by
   the page for the length of the snap back. */
.hanoi-tube[data-invalid='true'] {
  border-style: dotted;
  border-color: var(--ink);
  animation: hanoi-refuse 320ms var(--ease-soft);
}

@keyframes hanoi-refuse {
  0%, 100% { translate: 0 0; }
  30% { translate: -2px 0; }
  60% { translate: 2px 0; }
}

.hanoi-stack {
  display: flex;
  width: calc(var(--hanoi-tile) - 10px);
  min-height: 0;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: flex-end;
  gap: 4px;
}

.hanoi-tube-number {
  padding: 6px 0 2px;
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: var(--t-1);
  line-height: 1;
  text-align: center;
}

.hanoi-tube[aria-pressed='true'] .hanoi-tube-number {
  color: var(--ink);
  font-weight: 500;
}

/* The tile: a letter in Plex Mono Medium on a filled soft square, the
   corner a third of the side, sitting inside the capsule clear of the rim.
   The rim is the fill's own tone, so the tile reads as one shape. Width and
   height are both explicit: the width is the tube's inside, the height the
   same length in px, so no engine has to infer either from the other. */
.hanoi-tile {
  display: grid;
  width: calc(var(--hanoi-tile) - 10px);
  height: calc(var(--hanoi-tile) - 10px);
  flex: 0 0 auto;
  border: var(--hairline) solid var(--tile);
  border-radius: calc((var(--hanoi-tile) - 10px) / 3);
  background: var(--tile);
  color: var(--ink);
  font-family: var(--mono);
  font-size: clamp(1.375rem, calc(var(--hanoi-tile) * 0.44), 1.75rem);
  font-weight: 500;
  line-height: 1;
  place-items: center;
  user-select: none;
  -webkit-user-select: none;
  transition:
    transform 260ms var(--ease),
    box-shadow 260ms var(--ease),
    border-color var(--quick) var(--ease),
    background-color var(--quick) var(--ease);
}

/* Lifted: the tile eases 8 px up out of the mouth, with one soft shadow to
   say it has left the tube. The lift is a transform, not a translate: the
   drag sets an inline translate and clears it on the drop, and that must
   never ease. */
.hanoi-tile[data-lifted='true'] {
  border-color: var(--ink);
  transform: translateY(-8px);
  box-shadow: 0 8px 16px -8px var(--shadow);
}

.hanoi-tile[data-dragging='true'] {
  border-color: var(--ink);
  box-shadow: 0 14px 28px -10px var(--shadow);
  cursor: grabbing;
}

.hanoi-tube[data-word='true'] .hanoi-tile {
  border-color: var(--accent);
  color: var(--accent-ink);
}

/* The word under a sealed tube, revealed on the win. */
.hanoi-tube-word {
  position: absolute;
  top: 100%;
  right: 0;
  left: 0;
  padding-top: 8px;
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: var(--t-1);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-align: center;
  opacity: 0;
  transition: opacity 240ms var(--ease) 200ms;
}

.hanoi-shell[data-win] .hanoi-tube-word {
  opacity: 1;
}

.hanoi-shell[data-win='quiet'] .hanoi-tube-word {
  transition-delay: 0ms;
}

/* Tiles lift in turn from the left. The delay is set per tile by the page,
   so the wave follows the board rather than the DOM order. The whole moment
   ends inside 1.2 s: 11 x 40 ms of stagger plus one 560 ms lift and settle
   (1000 ms). The lift is quick and the settle slow, so it reads as a breath
   rather than a bounce. */
.hanoi-tile[data-wave='true'] {
  animation: hanoi-wave 560ms var(--ease-soft) var(--hanoi-wave-delay, 0ms) both;
}

@keyframes hanoi-wave {
  0% { transform: translateY(0); }
  35% { transform: translateY(-7px); }
  100% { transform: translateY(0); }
}

/* Captions under the board. */
.hanoi-board-label {
  margin: var(--s2) 0 0;
  text-align: center;
}

.hanoi-announce {
  min-height: 1.5em;
  margin: var(--s1) 0 0;
  color: var(--ink-2);
  font-size: var(--t0);
  text-align: center;
}

/* Controls: three hairline buttons in one row, the width of the board. */
.hanoi-controls {
  display: grid;
  width: min(100%, var(--board-max));
  margin: var(--s4) auto 0;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s2);
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: 44px;
  padding: 0 var(--s3);
  border: var(--hairline) solid var(--hair-2);
  border-radius: var(--radius-chip);
  background: transparent;
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--t0);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--quick) var(--ease), background-color var(--quick) var(--ease), color var(--quick) var(--ease);
}

.button:hover:not([disabled]) {
  border-color: var(--ink);
}

.button-primary {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg);
}

.button-primary:hover:not([disabled]) {
  background: var(--ink-2);
  border-color: var(--ink-2);
}

.button[disabled] {
  border-color: var(--hair);
  color: var(--ink-3);
  cursor: not-allowed;
}

.hanoi-key,
.hanoi-pill {
  color: var(--ink-3);
  font-size: var(--t-1);
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.hanoi-key {
  padding: 1px 6px;
  border: var(--hairline) solid var(--hair);
  border-radius: var(--radius-chip);
  line-height: 1.2;
}

.button[disabled] .hanoi-key {
  border-color: var(--hair);
}

.hanoi-rule-line {
  margin: var(--s5) 0 0;
  color: var(--ink-3);
  font-size: var(--t0);
  text-align: center;
}

.hanoi-rule-line a {
  color: var(--ink-2);
}

.hanoi-shell[data-game-state='error'] .hanoi-board,
.hanoi-shell[data-game-state='error'] .hanoi-controls {
  display: none;
}

/* The result. A rule, a kicker, the words, the route strip, the actions. */
.hanoi-result {
  width: min(100%, var(--board-max), 520px);
  margin: var(--s7) auto 0;
  padding-top: var(--s4);
  border-top: var(--hairline) solid var(--hair-2);
}

.hanoi-result h2 {
  margin-top: var(--s2);
  font-family: var(--display);
  font-size: var(--t4);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.hanoi-result-copy {
  margin: var(--s2) 0 0;
  color: var(--ink-2);
  font-size: var(--t1);
}

.hanoi-result-words {
  display: flex;
  margin: var(--s4) 0 0;
  padding: 0;
  flex-wrap: wrap;
  gap: var(--s2);
  list-style: none;
}

.hanoi-result-words li {
  padding: var(--s1) var(--s3);
  border: var(--hairline) solid var(--accent);
  border-radius: var(--radius-chip);
  background: var(--accent-wash);
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: var(--t0);
  font-weight: 500;
  letter-spacing: 0.12em;
}

.hanoi-share-strip {
  margin: var(--s5) 0 0;
  padding: var(--s3) var(--s4);
  border: var(--hairline) solid var(--hair-2);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--t0);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.hanoi-share-label {
  margin: var(--s2) 0 0;
}

.hanoi-share-actions {
  display: flex;
  margin-top: var(--s4);
  gap: var(--s2);
  flex-wrap: wrap;
}

.hanoi-share-note {
  min-height: 1.5em;
  margin: var(--s2) 0 0;
  color: var(--ink-2);
  font-size: var(--t0);
}

.hanoi-seed-line {
  margin: var(--s4) 0 0;
  color: var(--ink-3);
  font-size: var(--t0);
}

.hanoi-seed-line code,
.hanoi-prose code {
  padding: 0 0.4em;
  border: var(--hairline) solid var(--hair);
  border-radius: 6px;
  font-size: 0.9em;
  overflow-wrap: anywhere;
}

.hanoi-app-cta {
  display: flex;
  justify-content: space-between;
  gap: var(--s3);
  margin-top: var(--s5);
  padding: var(--s3) 0;
  border-top: var(--hairline) solid var(--hair);
  border-bottom: var(--hairline) solid var(--hair);
  color: var(--ink);
  font-size: var(--t1);
  text-decoration: none;
}

.hanoi-app-cta:hover {
  text-decoration: underline;
}

.hanoi-app-cta .label {
  align-self: center;
  color: var(--ink-3);
}

/* Subscribe, after the solve. */
.hanoi-subscribe {
  margin-top: var(--s5);
}

.hanoi-subscribe h3 {
  font-size: var(--t2);
  line-height: 1.3;
}

.hanoi-subscribe .subscribe-copy {
  margin: var(--s1) 0 0;
  color: var(--ink-2);
  font-size: var(--t1);
}

.subscribe-form {
  margin-top: var(--s3);
}

.subscribe-form > label {
  display: block;
  margin-bottom: var(--s1);
  font-family: var(--mono);
  font-size: var(--t-1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.subscribe-controls {
  display: flex;
  gap: var(--s2);
  flex-wrap: wrap;
}

.subscribe-controls input {
  flex: 1 1 200px;
  min-height: 44px;
  padding: 0 var(--s3);
  border: var(--hairline) solid var(--hair-2);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 16px;
}

.subscribe-controls input:hover,
.subscribe-controls input:focus-visible {
  border-color: var(--ink);
  outline: none;
}

.subscribe-trap {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.subscribe-result {
  min-height: 1.5em;
  margin: var(--s2) 0 0;
  color: var(--ink-2);
  font-size: var(--t0);
}

.subscribe-result[data-state='success'] {
  color: var(--accent-ink);
}

/* Stats: a sheet. From the side on a wide screen, from the bottom on a
   phone. The sheet scrolls inside itself, never the page behind it. */
.hanoi-stats {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  align-items: end;
  justify-items: stretch;
  background: var(--scrim);
}

.hanoi-stats-inner {
  width: 100%;
  max-height: 88svh;
  padding: var(--s4) var(--s4) calc(var(--s5) + env(safe-area-inset-bottom));
  border-top: var(--hairline) solid var(--hair-2);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  background: var(--bg);
  overflow-y: auto;
  overscroll-behavior: contain;
}

@media (min-width: 640px) {
  .hanoi-stats {
    align-items: stretch;
    justify-items: end;
  }

  .hanoi-stats-inner {
    width: min(100%, 400px);
    max-height: none;
    padding: var(--s5) var(--s5) var(--s6);
    border-top: 0;
    border-left: var(--hairline) solid var(--hair-2);
    border-radius: var(--radius-sheet) 0 0 var(--radius-sheet);
  }
}

.hanoi-stats-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  padding-bottom: var(--s3);
  border-bottom: var(--hairline) solid var(--hair-2);
}

.hanoi-stats-head h2 {
  font-family: var(--display);
  font-size: var(--t3);
  line-height: 1.15;
}

.hanoi-stat-grid {
  margin: var(--s2) 0 0;
  padding: 0;
  list-style: none;
}

/* A ledger: the label left, the figure right, a hairline between rows. */
.hanoi-stat-grid li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-direction: row-reverse;
  gap: var(--s3);
  padding: var(--s3) 0;
  border-bottom: var(--hairline) solid var(--hair);
}

.hanoi-stat-number {
  font-family: var(--mono);
  font-size: var(--t3);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.hanoi-stats-subhead {
  margin: var(--s5) 0 var(--s2);
}

.hanoi-bars {
  margin: 0;
  padding: 0;
  list-style: none;
}

.hanoi-bars li {
  display: grid;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) 0;
  grid-template-columns: 3.5rem 1fr 2.5rem;
}

.hanoi-bar-label,
.hanoi-bar-count {
  font-family: var(--mono);
  font-size: var(--t0);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

.hanoi-bar-count {
  text-align: right;
}

.hanoi-bar {
  display: block;
  height: 6px;
  border-radius: 3px;
  background: var(--hair);
}

.hanoi-bar-fill {
  display: block;
  width: 0;
  min-width: 6px;
  height: 100%;
  border-radius: 3px;
  background: var(--ink);
  transition: width 320ms var(--ease);
}

.hanoi-bars li[data-bucket='under'] .hanoi-bar-fill {
  background: var(--accent);
}

.hanoi-countdown {
  margin: var(--s5) 0 0;
  color: var(--ink-2);
  font-size: var(--t0);
}

.hanoi-countdown span {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.hanoi-stats .button {
  margin-top: var(--s3);
}

/* The about page. */
.hanoi-prose {
  max-width: 600px;
  margin-top: var(--s7);
}

.hanoi-prose section {
  padding-top: var(--s5);
  border-top: var(--hairline) solid var(--hair);
}

.hanoi-prose section + section {
  margin-top: var(--s6);
}

.hanoi-prose h2 {
  font-family: var(--mono);
  font-size: var(--t0);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.hanoi-prose p {
  margin: var(--s3) 0 0;
  color: var(--ink);
  font-size: var(--t2);
  line-height: 1.5;
  text-wrap: pretty;
}

.hanoi-code {
  margin: var(--s4) 0 0;
  padding: var(--s3) var(--s4);
  border: var(--hairline) solid var(--hair-2);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--t0);
  line-height: 1.55;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.hanoi-seed[data-state='revealed'] {
  border-top-color: var(--accent);
}

.hanoi-seed .button {
  margin-top: var(--s3);
}

.hanoi-seed .hanoi-stamp {
  margin: var(--s3) 0 0;
  padding: 0;
  border: 0;
}

.noscript-note {
  margin: var(--s6) 0 0;
  color: var(--ink-2);
}

/* Widths. */
@media (max-width: 640px) {
  .site-header,
  .hanoi-main {
    width: calc(100% - var(--s6));
  }

  .hanoi-prose p {
    font-size: 1.0625rem;
  }

  .hanoi-main {
    padding-top: var(--s6);
  }

  .hanoi-shell {
    margin-top: var(--s6);
  }
}

@media (max-width: 460px) {
  .site-header,
  .hanoi-main {
    width: calc(100% - var(--s5));
  }

  .site-nav {
    gap: 0;
  }

  .nav-button {
    padding: 0 var(--s2);
  }

  .hanoi-main {
    padding-top: var(--s4);
  }

  .hanoi-intro {
    gap: var(--s2);
  }

  .hanoi-intro h1 {
    font-size: var(--t5);
  }

  .hanoi-lede {
    font-size: var(--t1);
  }

  .hanoi-stamp {
    margin-top: var(--s1);
    padding-top: var(--s2);
  }

  .hanoi-shell {
    margin-top: var(--s5);
  }

  .hanoi-board {
    margin-top: var(--s4);
  }

  .hanoi-controls {
    margin-top: var(--s3);
  }

  .hanoi-controls {
    gap: 6px;
  }

  .button {
    padding: 0 var(--s2);
    font-size: var(--t-1);
  }

  .hanoi-key {
    display: none;
  }
}

/* Motion. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0ms !important;
    animation-duration: 0ms !important;
  }

  .hanoi-tile {
    transition: none !important;
  }

  .hanoi-tile[data-dragging='true'] {
    rotate: 0deg !important;
  }

  .hanoi-tile[data-wave='true'] {
    animation: none !important;
  }

  .hanoi-tube[data-invalid='true'] {
    animation: none !important;
  }

  .hanoi-tube {
    transition: none !important;
  }

  .hanoi-tube-word {
    transition: none !important;
  }
}

@media (forced-colors: active) {
  .hanoi-tube[aria-pressed='true'],
  .hanoi-tube[data-drop-target='true'] {
    box-shadow: none;
    outline: 3px solid currentColor;
  }

  .hanoi-bar-fill {
    background: CanvasText;
  }
}
