html,
body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  color: rgba(255, 255, 255, 0.87);
  background-color: #000000;
}

#app {
  position: relative;
  width: 100vw;
  height: 100dvh;
  overflow: hidden;
  /* A game: no panning, no double-tap zoom. A panel that scrolls opts back in. */
  touch-action: none;
}

#app canvas {
  display: block;
  /* Safety net: the browser must never smooth the canvas if it gets scaled. */
  image-rendering: pixelated;
}

/* Without JavaScript: where to read the resume instead. */
.noscript {
  margin: 16px;
  font-family: system-ui, sans-serif;
}

.noscript a {
  color: #de801d;
}

/* DOM overlay above the canvas. Interactive children opt back in to pointer events. */
#ui-layer {
  /* Screen pixels per art pixel of the UI: frames, text and cursors are sized in it. */
  --px: 3px;
  --ink: #4a3028;
  /* 4.8:1 on the cream: small text stays readable (WCAG AA). */
  --ink-soft: #8f612e;
  /* The frame's interior and its outer border (ASSETS.md). */
  --cream: #fff1d2;
  --outline: #6d4b27;
  /* The island's grass and its shore's foam: the title's card. */
  --grass: #afc259;
  --foam: #b9d4e5;
  /* morzy.dev's orange: the loading screen's nod to the site. */
  --brand: #de801d;
  /* The touch controls' gap to the screen's edges, and the room they take: at the bottom of a
     portrait screen, on each side of a landscape one. */
  --touch-margin: 16px;
  --touch-room: calc(148px + 2 * var(--touch-margin));
  position: absolute;
  inset: 0;
  pointer-events: none;
  font-family: "Pixelify Sans", system-ui, sans-serif;
}

@media (max-width: 640px), (max-height: 420px) {
  #ui-layer {
    --px: 2px;
  }
}

@media (min-width: 1800px) and (min-height: 1000px) {
  #ui-layer {
    --px: 4px;
  }
}

/* The UI frame (D13, set as --frame by UiLayer): a 9-slice of its 8-pixel corners. */
.frame {
  box-sizing: border-box;
  margin: 0;
  border: calc(8 * var(--px)) solid transparent;
  border-image-source: var(--frame);
  border-image-slice: 8 fill;
  border-image-width: calc(8 * var(--px));
  border-image-repeat: round;
  image-rendering: pixelated;
  color: var(--ink);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Scene changes fade through black (FadeOverlay animates the opacity; the class holds the end state). */
.fade {
  position: absolute;
  inset: 0;
  background-color: #000000;
  opacity: 0;
}

.fade.dark {
  opacity: 1;
}

/* Debug views. */
.debug-caption {
  position: absolute;
  top: calc(4 * var(--px));
  /* Right of the mute button. */
  left: calc(25 * var(--px));
  max-width: calc(100 * var(--px));
  padding: 0 calc(2 * var(--px));
  font-size: calc(7 * var(--px));
  line-height: 1.3;
}

.fps-meter {
  position: absolute;
  top: calc(4 * var(--px) + env(safe-area-inset-top));
  right: calc(4 * var(--px) + env(safe-area-inset-right));
  padding: 0 calc(2 * var(--px));
  font-size: calc(7 * var(--px));
  line-height: 1.3;
}

/* Dialogue: a box at the bottom, the speaker's tag above its left end, choices above its right end. */
.dialogue {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(4 * var(--px) + env(safe-area-inset-bottom));
  width: min(100% - 32px, 240 * var(--px));
  margin: 0 auto;
  pointer-events: auto;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  font-size: calc(8 * var(--px));
  line-height: 1.25;
}

.dialogue-box {
  position: relative;
  /* Three lines of text. */
  min-height: calc(3 * 1.25em + 16 * var(--px));
  padding: 0 calc(4 * var(--px)) 0 calc(2 * var(--px));
}

.dialogue-text {
  margin: 0;
  overflow-wrap: break-word;
}

/* The untyped rest of the page keeps its room, so words never jump to the next line. */
.dialogue-rest {
  visibility: hidden;
}

/* "Next" marker, a ▼ drawn with borders: the font has no triangles (D14). */
.dialogue-next {
  position: absolute;
  right: calc(1 * var(--px));
  bottom: calc(1 * var(--px));
  border-top: calc(3 * var(--px)) solid var(--ink-soft);
  border-left: calc(3 * var(--px)) solid transparent;
  border-right: calc(3 * var(--px)) solid transparent;
  animation: dialogue-bob 0.8s steps(1) infinite;
}

@keyframes dialogue-bob {
  50% {
    transform: translateY(var(--px));
  }
}

.dialogue-speaker {
  position: absolute;
  /* Over the box's 5-pixel top border. */
  bottom: calc(100% - 5 * var(--px));
  z-index: 1;
  left: calc(4 * var(--px));
  padding: 0 calc(2 * var(--px));
  font-size: calc(7 * var(--px));
  line-height: 1.25;
}

.dialogue-choices {
  position: absolute;
  right: 0;
  /* Over the box's 5-pixel top border. */
  bottom: calc(100% - 5 * var(--px));
  z-index: 1;
  list-style: none;
  padding: 0 calc(3 * var(--px)) 0 calc(1 * var(--px));
}

.dialogue-choices a,
.dialogue-choices button {
  display: block;
  position: relative;
  /* The cursor's padding stays inside the width, or the item overflows its list. */
  box-sizing: border-box;
  width: 100%;
  margin: 0;
  padding: 0 0 0 calc(6 * var(--px));
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  outline: none;
}

.dialogue-choices a:hover,
.dialogue-choices button:hover {
  color: var(--ink-soft);
}

/* The ▶ cursor on the selected choice, which also has the focus: on the item's first line. */
.dialogue-choices .selected::before,
.menu .selected::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(0.625em - 3 * var(--px));
  border-left: calc(3 * var(--px)) solid currentColor;
  border-top: calc(3 * var(--px)) solid transparent;
  border-bottom: calc(3 * var(--px)) solid transparent;
}

/* ↗ after a link that opens a new tab. */
.external-link-icon {
  display: inline-block;
  width: calc(6 * var(--px));
  height: calc(6 * var(--px));
  margin-left: calc(3 * var(--px));
}

/* Menus (Menu): a list of choices, the cursor on the left. */
.menu {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: calc(8 * var(--px));
  line-height: 1.25;
  text-align: left;
}

.menu.frame {
  padding: calc(1 * var(--px)) calc(5 * var(--px)) calc(1 * var(--px))
    calc(2 * var(--px));
}

.menu li + li {
  margin-top: calc(2 * var(--px));
}

.menu a,
.menu button {
  display: block;
  position: relative;
  /* The cursor's padding stays inside the width, or the item overflows its list (a scrollbar in a panel). */
  box-sizing: border-box;
  width: 100%;
  margin: 0;
  padding: 0 0 0 calc(7 * var(--px));
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  outline: none;
}

/* Under a panel or a fade, the cursor stays where it was, faded. */
.menu[inert] .selected::before {
  border-left-color: var(--ink-soft);
}

/* The choice in use (the current language). */
.menu [aria-current="true"] {
  text-decoration: underline;
  text-decoration-thickness: var(--px);
  text-underline-offset: calc(2 * var(--px));
}

/* Panels (Panel): a frame in the middle of the screen, over a dimmed backdrop. */
.panel-backdrop {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  box-sizing: border-box;
  background-color: rgba(0, 0, 0, 0.4);
  pointer-events: auto;
}

.panel {
  max-width: min(100%, calc(200 * var(--px)));
  max-height: 100%;
  overflow-y: auto;
  touch-action: pan-y;
  padding: calc(1 * var(--px)) calc(5 * var(--px)) calc(2 * var(--px))
    calc(3 * var(--px));
  font-size: calc(8 * var(--px));
  line-height: 1.25;
  text-align: left;
  user-select: none;
  -webkit-user-select: none;
}

.panel-title {
  margin: 0 0 calc(4 * var(--px));
  color: var(--ink-soft);
  font-size: inherit;
  font-weight: normal;
  text-align: center;
}

.controls-list {
  display: grid;
  grid-template-columns: auto auto;
  align-items: center;
  gap: calc(3 * var(--px)) calc(8 * var(--px));
  margin: 0 0 calc(6 * var(--px));
}

.controls-list dt,
.controls-list dd {
  margin: 0;
}

.controls-or {
  color: var(--ink-soft);
}

kbd {
  display: inline-block;
  padding: 0 calc(2 * var(--px));
  border: var(--px) solid var(--ink-soft);
  border-bottom-width: calc(2 * var(--px));
  font: inherit;
  font-size: calc(7 * var(--px));
  line-height: 1.25;
}

kbd .speaker-icon {
  display: inline-block;
  vertical-align: calc(-1 * var(--px));
}

@media (max-width: 640px) {
  .controls-list {
    grid-template-columns: auto;
    row-gap: calc(1 * var(--px));
  }

  .controls-list dd + dt {
    margin-top: calc(3 * var(--px));
  }
}

.credits-author {
  margin: 0 0 calc(6 * var(--px));
}

.credits .menu li + li {
  margin-top: calc(4 * var(--px));
}

.credit-role {
  display: block;
  color: var(--ink-soft);
}

/* DOM scenes (loading, title): the whole screen, under the fade like the maps. */
.screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 16px;
  box-sizing: border-box;
  pointer-events: auto;
  user-select: none;
  -webkit-user-select: none;
  text-align: center;
}

/* Loading: morzy.dev's >_ and a bar, in its orange on black. */
.loading {
  background-color: #000000;
  color: var(--brand);
}

.loading-logo {
  margin: 0 0 calc(8 * var(--px));
  font-size: calc(24 * var(--px));
  line-height: 1;
}

.loading-cursor {
  animation: blink 1s steps(1) infinite;
}

.loading-bar {
  box-sizing: content-box;
  width: calc(60 * var(--px));
  height: calc(3 * var(--px));
  padding: var(--px);
  border: var(--px) solid var(--brand);
}

.loading-fill {
  height: 100%;
  background-color: var(--brand);
}

.loading-error {
  max-width: calc(160 * var(--px));
  margin: 0 0 calc(6 * var(--px));
  color: var(--cream);
  font-size: calc(8 * var(--px));
  line-height: 1.25;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

/* Title: the name in cream lettering outlined in the frame's brown, on a card of plain grass in the
   middle: a small island over the real one, which the canvas draws behind (TitleBackdrop). */
.title-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  box-sizing: border-box;
  max-width: 100%;
  padding: calc(10 * var(--px)) calc(14 * var(--px));
  border: calc(2 * var(--px)) solid var(--foam);
  background-color: var(--grass);
  /* Lifted off the island: a brown outline round the foam, then a hard shadow under it. */
  box-shadow:
    0 0 0 var(--px) var(--outline),
    0 calc(4 * var(--px)) 0 var(--px) rgba(0, 0, 0, 0.35);
}

.title-screen {
  /* The island behind, dimmed a little, so the card stands out. */
  background-color: rgba(0, 0, 0, 0.3);
  --outlined:
    calc(-1 * var(--px)) 0 0 var(--outline), var(--px) 0 0 var(--outline),
    0 calc(-1 * var(--px)) 0 var(--outline), 0 var(--px) 0 var(--outline),
    calc(-1 * var(--px)) calc(-1 * var(--px)) 0 var(--outline),
    var(--px) calc(-1 * var(--px)) 0 var(--outline),
    calc(-1 * var(--px)) var(--px) 0 var(--outline),
    var(--px) var(--px) 0 var(--outline);
  color: var(--cream);
}

.title-name {
  margin: 0;
  font-size: calc(16 * var(--px));
  font-weight: normal;
  line-height: 1.1;
  /* The outline, then a deeper shadow under it. */
  text-shadow:
    var(--outlined),
    0 calc(2 * var(--px)) 0 var(--outline),
    calc(-1 * var(--px)) calc(2 * var(--px)) 0 var(--outline),
    var(--px) calc(2 * var(--px)) 0 var(--outline);
}

/* The small lettering is plain ink on the grass (6:1): an outline as thick as its strokes blurs it. */
.title-subtitle {
  margin: calc(3 * var(--px)) 0 0;
  color: var(--ink);
  font-size: calc(8 * var(--px));
}

/* The visitor, idle (the Bunny's front row, 5 frames at 6 fps) on its shadow, at twice the UI's scale. */
.title-bunny {
  --scale: calc(2 * var(--px));
  width: calc(48 * var(--scale));
  height: calc(48 * var(--scale));
  /* The frame is mostly empty: hug the body. */
  margin: calc(-8 * var(--scale)) 0 calc(-12 * var(--scale));
  background-repeat: no-repeat;
  background-size:
    calc(240 * var(--scale)) calc(192 * var(--scale)),
    calc(16 * var(--scale)) calc(16 * var(--scale));
  /* The shadow's cell puts the feet, pixel (24, 32) of the frame, on its pixel (8, 13). */
  background-position:
    0 calc(-144 * var(--scale)),
    calc(16 * var(--scale)) calc(19 * var(--scale));
  image-rendering: pixelated;
  animation: title-bunny-idle calc(5s / 6) steps(5) infinite;
}

@keyframes title-bunny-idle {
  from {
    background-position-x: 0, calc(16 * var(--scale));
  }
  to {
    background-position-x: calc(-240 * var(--scale)), calc(16 * var(--scale));
  }
}

.title-start {
  position: relative;
  margin-top: calc(8 * var(--px));
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: calc(8 * var(--px));
  cursor: pointer;
  outline: none;
  animation: blink 1.2s steps(1) infinite;
}

/* Focused from the keyboard: the menus' ▶ cursor on its left. */
.title-start:focus-visible::before {
  content: "";
  position: absolute;
  right: calc(100% + 4 * var(--px));
  top: calc(50% - 3 * var(--px));
  border-left: calc(3 * var(--px)) solid currentColor;
  border-top: calc(3 * var(--px)) solid transparent;
  border-bottom: calc(3 * var(--px)) solid transparent;
}

.title-menu {
  min-width: calc(80 * var(--px));
  margin-top: calc(8 * var(--px));
}

/* Pause: the menu at the top right, over the frozen map. */
.pause-menu {
  position: absolute;
  top: calc(4 * var(--px) + env(safe-area-inset-top));
  right: calc(4 * var(--px) + env(safe-area-inset-right));
  min-width: calc(72 * var(--px));
  pointer-events: auto;
  user-select: none;
  -webkit-user-select: none;
}

/* The speaker at the top left (MuteButton), a keycap on the title and the maps. */
.mute-button {
  position: absolute;
  top: calc(4 * var(--px) + env(safe-area-inset-top));
  left: calc(4 * var(--px) + env(safe-area-inset-left));
  display: block;
  margin: 0;
  padding: calc(3 * var(--px)) calc(3 * var(--px)) calc(2 * var(--px));
  border: var(--px) solid var(--outline);
  border-bottom-width: calc(2 * var(--px));
  background-color: var(--cream);
  color: var(--ink);
  cursor: pointer;
  pointer-events: auto;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}

.mute-button:hover {
  color: var(--ink-soft);
}

.mute-button:focus-visible {
  outline: var(--px) solid var(--cream);
  outline-offset: var(--px);
}

.speaker-icon {
  display: block;
  width: calc(9 * var(--px));
  height: calc(7 * var(--px));
}

/* Touch controls (TouchControls), on a phone or a tablet: the D-pad at the bottom left, A and Menu
   at the bottom right. Sized for thumbs in CSS pixels; their art is 2 CSS pixels per pixel. */
.touch-controls {
  position: absolute;
  inset: 0;
  opacity: 0.85;
}

.touch-dpad,
.touch-a,
.touch-menu {
  position: absolute;
  pointer-events: auto;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

.touch-dpad svg,
.touch-a svg {
  display: block;
  width: 100%;
  height: 100%;
}

.touch-dpad {
  left: calc(var(--touch-margin) + env(safe-area-inset-left));
  bottom: calc(var(--touch-margin) + env(safe-area-inset-bottom));
  /* 74 pixels: the 72-pixel cross and its outline, which straddles the edge. */
  width: 148px;
  height: 148px;
}

.touch-face,
.touch-a path {
  fill: var(--cream);
}

.touch-pressed,
.touch-a.pressed path {
  fill: #f0cf98;
}

.touch-arrow {
  fill: var(--ink-soft);
}

.touch-outline,
.touch-a path {
  stroke: var(--outline);
  stroke-width: 2;
}

.touch-outline {
  fill: none;
}

.touch-a {
  right: calc(var(--touch-margin) + 8px + env(safe-area-inset-right));
  bottom: calc(var(--touch-margin) + 24px + env(safe-area-inset-bottom));
  width: 68px;
  height: 68px;
}

.touch-a-letter {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  font-size: 32px;
  line-height: 1;
}

.touch-menu {
  right: calc(var(--touch-margin) + env(safe-area-inset-right));
  bottom: calc(var(--touch-margin) + 108px + env(safe-area-inset-bottom));
  width: 84px;
  padding: 2px 0 0;
  border: 2px solid var(--outline);
  border-bottom-width: 4px;
  box-sizing: border-box;
  background-color: var(--cream);
  color: var(--ink);
  font-size: 16px;
  line-height: 22px;
  text-align: center;
}

.touch-menu.pressed {
  background-color: #f0cf98;
}

/* The dialogue box keeps clear of the touch controls: above them in portrait, between them in
   landscape. */
@media (pointer: coarse) and (orientation: portrait) {
  .dialogue {
    bottom: calc(var(--touch-room) + env(safe-area-inset-bottom));
  }
}

@media (pointer: coarse) and (orientation: landscape) {
  .dialogue {
    width: min(
      100% - 2 *
        (
          var(--touch-room) +
            max(env(safe-area-inset-left), env(safe-area-inset-right))
        ),
      240 * var(--px)
    );
  }
}

@media (prefers-reduced-motion: reduce) {
  .dialogue-next,
  .loading-cursor,
  .title-bunny,
  .title-start {
    animation: none;
  }
}
