/* Self-hosted (license in fonts/OFL.txt), so the game's first frame never waits on a third-party server. */
@font-face {
  font-family: "Press Start 2P";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/press-start-2p-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* The text version's reading font: pixel letters drawn for running text (license in fonts/DotGothic16-OFL.txt). */
@font-face {
  font-family: "DotGothic16";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/dotgothic16-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --bg: #0b0b10;
  --bezel: #17171f;
  --bezel-edge: #2a2a36;
  --text: #e8e8f0;
  --muted: #8a8aa0;
  --key: #23232e;
  --key-edge: #3a3a4a;
  --accent: #e45c10;
  --gold: #f8b800;
  --link: #a4e4fc;
  /* The game's palette, for the text version. */
  --sky: #5c94fc;
  --peach: #fcbcb0;
  --brick: #c84c0c;
  --brick-dark: #881400;
  --paper: #fcfcfc;
  --detail: #bcbcbc;
  --green: #80d010;
  --boss: #fc7460;
  /* The dialog box's dotted divider, at 2x. */
  --dots: repeating-linear-gradient(90deg, #7c7c7c 0 2px, transparent 2px 4px);
  --font: "Press Start 2P", ui-monospace, monospace;
  --font-text: "DotGothic16", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

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

/* Hidden stays hidden, whatever display a class gives. */
[hidden] {
  display: none !important;
}

html,
body {
  height: 100%;
  margin: 0;
}

html {
  /* Quick taps are game input (jumps, dialog pages), so a double tap must never zoom the page. */
  touch-action: manipulation;
}

body {
  display: grid;
  place-items: center;
  overflow: hidden;
  background: radial-gradient(ellipse at 50% 30%, #1b1b28 0%, var(--bg) 70%);
  color: var(--text);
  font-family: var(--font);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

.stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 16px;
}

/* ── Title bar: the page's heading, and the way to the text version ── */

.bar {
  display: flex;
  align-items: baseline;
  gap: 18px;
  /* As wide as the stage without widening it, and one line tall: main.js reserves its height for the canvas. */
  width: 0;
  min-width: 100%;
  font-size: 8px;
  line-height: 1.5;
  white-space: nowrap;
}

/* Mixed case: the pixel font's capital É looks like a small é. */
.bar__title {
  flex: 1;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--muted);
  font: inherit;
}

.bar__game {
  color: var(--gold);
}

.bar__links {
  display: flex;
  gap: 18px;
}

.bar__link {
  color: var(--muted);
  text-decoration: none;
  text-transform: uppercase;
}

.bar__link--text {
  color: var(--link);
}

/* A button that looks like the links beside it. */
.bar__fullscreen {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
}

/* A taller target for thumbs; main.js measures the bar, so the canvas still fits. */
@media (pointer: coarse) {
  .bar__link {
    padding-block: 8px;
  }

  /* Touch screens go full screen as a run starts. */
  .bar__fullscreen {
    display: none;
  }
}

.bar__link:hover,
.bar__link:focus-visible {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.bar__link:focus-visible,
.cv a:focus-visible,
.cv button:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 3px;
}

/* ── Screen with bezel & faint scanlines ───────────────────────── */

.screen {
  position: relative;
  padding: 6px;
  border-radius: 10px;
  background: var(--bezel);
  box-shadow:
    0 0 0 1px var(--bezel-edge),
    0 24px 60px rgba(0, 0, 0, 0.7);
}

.screen::after {
  content: "";
  position: absolute;
  inset: 6px;
  pointer-events: none;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.08) 0 1px, transparent 1px 3px);
}

canvas {
  display: block;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  background: #000;
}

/* ── Keyboard legend ───────────────────────────────────────────── */

.legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--muted);
  font-size: 9px;
  line-height: 1;
}

/* Short windows give all their height to the game. */
@media (max-height: 420px) {
  .bar,
  .legend {
    display: none;
  }
}

.legend li {
  display: flex;
  align-items: center;
  gap: 4px;
}

kbd {
  padding: 4px 5px 3px;
  border: 1px solid var(--key-edge);
  border-bottom-width: 3px;
  border-radius: 4px;
  background: var(--key);
  color: var(--text);
  font-family: var(--font);
  font-size: 8px;
}

/* ── Touch controls (phones & tablets only) ───────────────────── */

.touch {
  display: none;
}

@media (pointer: coarse) {
  .legend {
    display: none;
  }

  .touch {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: min(100vw - 32px, 520px);
    padding-bottom: env(safe-area-inset-bottom);
  }
}

/* ── Text version: the résumé as HTML (#resume), over the game while open ── */

/*
 * It reads like the game's résumé cards, made for reading: the cards' black boxes and white frames,
 * their colors (gold headings, grey details, green status), the game's font for headings and
 * labels, and DotGothic16, a pixel font drawn for running text, for everything else. Pixel fonts
 * stay sharpest at whole multiples of their grid (8px for Press Start 2P, 16px for DotGothic16),
 * and the art is drawn at whole multiples of a game pixel (--px).
 */
.cv {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 20;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: auto;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-text);
  font-size: 16px;
  line-height: 24px;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

.is-reading .cv {
  display: block;
}

@media (prefers-reduced-motion: no-preference) {
  .cv {
    scroll-behavior: smooth;
  }
}

/* It takes focus when it opens, so screen readers start there; the ring would only frame the whole page. */
.cv:focus {
  outline: none;
}

/* Read by screen readers and kept in copied text, but not shown. */
.cv__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.cv__bar {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  padding: max(12px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) 12px
    max(16px, env(safe-area-inset-left));
  border-bottom: 2px solid #000000;
  background: rgba(11, 11, 16, 0.94);
  font-family: var(--font);
  font-size: 8px;
  line-height: 1.5;
  text-transform: uppercase;
}

.cv__back,
.cv__action {
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  text-transform: inherit;
  text-decoration: none;
  cursor: pointer;
}

.cv__back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--gold);
}

/* A pixel-sharp arrow that doesn't depend on the font having one. */
.cv__back::before {
  content: "";
  border-block: 5px solid transparent;
  border-inline-end: 6px solid currentColor;
}

.cv__actions {
  display: flex;
  gap: 20px;
}

.cv__back:hover,
.cv__action:hover,
.cv__back:focus-visible,
.cv__action:focus-visible {
  color: var(--text);
}

/* Taller targets for thumbs. */
@media (pointer: coarse) {
  .cv__back,
  .cv__action {
    padding-block: 10px;
  }
}

/* ── Opening scene: the title plate over the start of World 1-1 ── */

.cv__scene {
  --px: 2px;
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: calc(16 * var(--px)) max(16px, env(safe-area-inset-right)) calc(36 * var(--px))
    max(16px, env(safe-area-inset-left));
  background:
    url("../assets/resume/ground.svg") left bottom / calc(16 * var(--px)) repeat-x,
    var(--sky);
}

@media (min-width: 720px) {
  .cv__scene {
    --px: 3px;
  }
}

.cv__scene > img {
  position: absolute;
}

.cv__cloud {
  top: calc(10 * var(--px));
  right: 6%;
  width: calc(48 * var(--px));
  height: calc(24 * var(--px));
}

.cv__hill {
  bottom: calc(16 * var(--px));
  left: 3%;
  width: calc(80 * var(--px));
  height: calc(35 * var(--px));
}

.cv__hero {
  bottom: calc(16 * var(--px));
  left: calc(3% + 58 * var(--px));
  width: calc(16 * var(--px));
  height: calc(16 * var(--px));
}

/* The game's riveted title plate: a black outline, light top and left edges, dark bottom and right. */
.cv__plate {
  --rivet: linear-gradient(var(--peach) 0 0);
  --rivet-size: calc(2 * var(--px)) calc(2 * var(--px));
  position: relative;
  z-index: 1;
  width: min(100%, calc(208 * var(--px)));
  padding: calc(12 * var(--px)) calc(10 * var(--px)) calc(11 * var(--px));
  border: var(--px) solid #000000;
  background:
    var(--rivet) left calc(4 * var(--px)) top calc(4 * var(--px)) / var(--rivet-size) no-repeat,
    var(--rivet) right calc(4 * var(--px)) top calc(4 * var(--px)) / var(--rivet-size) no-repeat,
    var(--rivet) left calc(4 * var(--px)) bottom calc(4 * var(--px)) / var(--rivet-size) no-repeat,
    var(--rivet) right calc(4 * var(--px)) bottom calc(4 * var(--px)) / var(--rivet-size) no-repeat,
    var(--brick);
  box-shadow:
    inset var(--px) var(--px) 0 var(--peach),
    inset calc(-1 * var(--px)) calc(-1 * var(--px)) 0 var(--brick-dark);
  font-family: var(--font);
  text-align: center;
  text-transform: uppercase;
}

.cv .cv__plate h2 {
  margin: 0;
  color: var(--peach);
  font-size: 24px;
  line-height: 1.4;
}

.cv__name {
  display: block;
  text-shadow: 3px 3px 0 #000000;
}

/* Each line's shadow is one of its font pixels deep. */
.cv__headline {
  display: block;
  margin-top: calc(5 * var(--px));
  color: var(--paper);
  font-size: 10px;
  line-height: 1.8;
  text-shadow: 1px 1px 0 #000000;
  text-wrap: balance;
}

.cv .cv__eyebrow {
  margin: calc(5 * var(--px)) 0 0;
  color: var(--gold);
  font-size: 8px;
  line-height: 1.5;
  text-shadow: 1px 1px 0 #000000;
}

@media (min-width: 720px) {
  .cv .cv__plate h2 {
    font-size: 32px;
  }

  .cv__name {
    text-shadow: 4px 4px 0 #000000;
  }

  .cv__headline {
    font-size: 12px;
    text-shadow: 2px 2px 0 #000000;
  }
}

/* ── Reading column ── */

.cv__body {
  max-width: 46rem;
  margin: 0 auto;
  padding: 32px max(16px, env(safe-area-inset-right)) 48px max(16px, env(safe-area-inset-left));
}

.cv p,
.cv ul,
.cv dl {
  margin: 0 0 16px;
}

.cv a {
  color: var(--link);
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.cv a:hover {
  color: var(--paper);
}

.cv .cv__lede {
  color: var(--paper);
}

.cv__note {
  padding: 12px 14px;
  border: 2px dashed var(--gold);
}

/* Like the HUD: labels in the game's font over the values. */
.cv__facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px;
  margin-top: 24px;
  border: 2px solid var(--bezel-edge);
  background: var(--bezel-edge);
}

.cv__facts div {
  padding: 12px 14px 14px;
  background: #000000;
}

.cv__facts dt {
  margin-bottom: 8px;
  color: var(--detail);
  font-family: var(--font);
  font-size: 8px;
  line-height: 1.5;
  text-transform: uppercase;
}

.cv__facts dd {
  margin: 0;
  color: var(--paper);
}

/* Keycap buttons, like the touch controls; the main one is the orange A button. */
.cv ul.cv__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 24px;
  padding: 0;
  list-style: none;
}

.cv a.cv__button {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  min-height: 48px;
  padding: 10px 16px 8px;
  border: 2px solid var(--key-edge);
  border-bottom-width: 5px;
  background: var(--key);
  color: var(--paper);
  font-family: var(--font);
  font-size: 10px;
  line-height: 1.5;
  text-decoration: none;
  text-transform: uppercase;
}

.cv a.cv__button--a {
  border-color: #b84a0c;
  background: var(--accent);
}

.cv a.cv__button:hover {
  filter: brightness(1.2);
}

.cv a.cv__button:active {
  border-bottom-width: 2px;
  transform: translateY(3px);
}

/* Level select: a numbered chip per chapter. */
.cv__toc ol {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cv__toc a {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  padding: 4px 12px 4px 4px;
  border: 2px solid var(--key-edge);
  border-bottom-width: 4px;
  background: var(--key);
  color: var(--text);
  text-decoration: none;
}

.cv__toc span {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  background: var(--gold);
  color: #000000;
  font-family: var(--font);
  font-size: 8px;
}

.cv .cv__toc .cv__toc-a {
  padding-left: 12px;
  border-color: #b84a0c;
  background: var(--accent);
  color: var(--paper);
}

.cv__toc a:hover {
  border-color: var(--muted);
  color: var(--paper);
}

/* ── Chapters: the game's dialog box, black with a white line two game pixels in ── */

.cv__chapter {
  margin-top: 32px;
  padding: 24px 28px 28px;
  background: #000000;
  box-shadow:
    inset 0 0 0 4px #000000,
    inset 0 0 0 6px var(--paper);
  /* Links straight to a chapter land it below the sticky bar. */
  scroll-margin-top: 64px;
}

@media (max-width: 560px) {
  .cv__chapter {
    padding: 20px 18px 22px;
  }
}

/* The card's title row: its icon and name over a dotted line. */
.cv__head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 20px;
  padding-bottom: 18px;
  background: var(--dots) left bottom / 100% 2px no-repeat;
}

.cv__icon {
  flex: none;
  width: 32px;
  height: 32px;
}

.cv .cv__checkpoint {
  margin: 0 0 8px;
  color: var(--detail);
  font-family: var(--font);
  font-size: 8px;
  line-height: 1.5;
  text-transform: uppercase;
}

.cv h2 {
  margin: 0;
  color: var(--gold);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  text-transform: uppercase;
}

.cv h3 {
  margin: 24px 0 8px;
  color: var(--gold);
  font-family: var(--font);
  font-size: 12px;
  font-weight: 400;
  line-height: 20px;
  text-transform: uppercase;
}

.cv__role h3 {
  margin: 0 0 4px;
}

/* Who it was for, under the role, in the reading font. */
.cv__org {
  display: block;
  margin-top: 4px;
  color: var(--paper);
  font-family: var(--font-text);
  font-size: 16px;
  line-height: 24px;
  text-transform: none;
}

.cv__role + .cv__role {
  margin-top: 24px;
  padding-top: 24px;
  background: var(--dots) left top / 100% 2px no-repeat;
}

.cv__role > :last-child {
  margin-bottom: 0;
}

.cv__role-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px 16px;
  margin-bottom: 4px;
}

.cv .cv__meta {
  margin-bottom: 12px;
  color: var(--detail);
}

/* Status lines from the cards, as tags. */
.cv .cv__status {
  flex: none;
  margin: 0;
  padding: 6px 8px 5px;
  border: 2px solid currentColor;
  color: var(--green);
  font-family: var(--font);
  font-size: 8px;
  line-height: 1;
  text-transform: uppercase;
}

.cv__status--live::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 6px;
  background: currentColor;
  animation: cv-blink 1.07s step-end infinite;
}

.cv .cv__status--boss {
  color: var(--boss);
}

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

/* Lists bullet with the coin the cards use. */
.cv ul.cv__list {
  padding: 0;
  list-style: none;
}

.cv__list li {
  position: relative;
  margin-bottom: 8px;
  padding-left: 24px;
}

.cv__list li::before {
  content: "";
  position: absolute;
  top: 4px;
  left: 0;
  width: 12px;
  height: 16px;
  background: url("../assets/resume/bullet.svg") 0 0 / 100% 100%;
}

@media (min-width: 561px) {
  .cv__list--split {
    columns: 2;
    column-gap: 32px;
  }

  .cv__list--split li {
    break-inside: avoid;
  }
}

.cv__more {
  margin-top: 4px;
}

.cv .cv__trophies-title {
  margin: 32px 0 6px;
  padding-top: 24px;
  background: var(--dots) left top / 100% 2px no-repeat;
}

.cv .cv__trophies-title + h3 {
  margin-top: 0;
  margin-bottom: 16px;
}

.cv ul.cv__trophies {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12.5rem, 1fr));
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cv__trophies li {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 14px 16px 16px;
  border: 2px solid var(--bezel-edge);
  background: var(--bezel);
}

.cv__trophies p {
  margin: 0;
}

.cv .cv__trophies .cv__meta {
  margin: 0;
}

.cv .cv__date {
  color: var(--detail);
  font-family: var(--font);
  font-size: 8px;
  line-height: 1.5;
  text-transform: uppercase;
}

.cv .cv__cert {
  color: var(--paper);
}

.cv__trophies a {
  margin-top: auto;
}

/* Inventory: each skill in its own slot. */
.cv__skills h3:first-child {
  margin-top: 0;
}

.cv ul.cv__items {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0;
  list-style: none;
}

.cv__items li {
  padding: 4px 10px 2px;
  border: 2px solid var(--key-edge);
  border-bottom-width: 4px;
  background: var(--key);
  color: var(--paper);
}

.cv .cv__aside {
  margin: 8px 0 0;
  color: var(--detail);
}

/* The contact card: one big button per way to reach Ralph. */
.cv ul.cv__contact {
  display: grid;
  gap: 12px;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}

.cv .cv__contact a.cv__button {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  font-family: var(--font-text);
  font-size: 16px;
  line-height: 24px;
  text-transform: none;
  overflow-wrap: anywhere;
}

.cv__contact .cv__button span {
  flex: none;
  min-width: 80px;
  font-family: var(--font);
  font-size: 8px;
  text-transform: uppercase;
}

/* ── About the game, questions, footer ── */

.cv__extra {
  margin-top: 56px;
  padding-top: 32px;
  border-top: 2px dashed var(--bezel-edge);
}

.cv .cv__extra h2 {
  margin-bottom: 20px;
  color: var(--text);
  font-size: 12px;
}

.cv .cv__extra h3 {
  margin: 24px 0 8px;
  color: var(--paper);
  font-family: var(--font-text);
  font-size: 16px;
  line-height: 24px;
  text-transform: none;
}

.cv__extra p {
  color: var(--detail);
}

.cv__table {
  overflow-x: auto;
  margin-bottom: 16px;
}

.cv table {
  width: 100%;
  border-collapse: collapse;
}

.cv th,
.cv td {
  padding: 8px 10px;
  border-bottom: 2px solid var(--bezel-edge);
  text-align: left;
  vertical-align: top;
}

.cv thead th {
  color: var(--muted);
  font-family: var(--font);
  font-size: 8px;
  font-weight: 400;
  text-transform: uppercase;
}

.cv tbody th {
  color: var(--paper);
  font-weight: 400;
}

.cv td {
  color: var(--detail);
}

.cv__footer {
  margin-top: 56px;
  padding-top: 24px;
  border-top: 2px dashed var(--bezel-edge);
}

.cv .cv__footer p {
  margin-bottom: 8px;
  color: var(--muted);
}

/* The page ends on the ground, like the level. */
.cv__ground {
  height: calc(32px + env(safe-area-inset-bottom));
  background: url("../assets/resume/ground.svg") left top / 32px;
}

@media (prefers-reduced-motion: reduce) {
  .cv__status--live::before {
    animation: none;
  }
}

/*
 * Upright phones can't play, so the page becomes the résumé to read, under a prompt to turn the
 * phone sideways for the game. (Game.js pauses a run when the phone turns upright.)
 */
.rotate {
  display: none;
}

@media (pointer: coarse) and (orientation: portrait) and (max-width: 600px) {
  html,
  body {
    height: auto;
  }

  /* As a plain block, so the stage spans the page (place-items would shrink it to fit). */
  body {
    display: block;
    place-items: normal;
    overflow: visible;
  }

  .stage {
    padding: max(16px, env(safe-area-inset-top)) 16px 0;
  }

  .stage > :not(.bar),
  .bar__link--text {
    display: none;
  }

  .bar {
    white-space: normal;
  }

  .rotate {
    display: flex;
    align-items: center;
    gap: 20px;
    margin: 20px 16px 0;
    padding: 16px 18px;
    border: 2px dashed var(--bezel-edge);
    border-radius: 10px;
    color: var(--text);
    font-size: 10px;
    line-height: 1.7;
  }

  .rotate p {
    margin: 0;
  }

  .rotate span {
    color: var(--muted);
    font-size: 8px;
  }

  .rotate__phone {
    flex: none;
    width: 24px;
    height: 40px;
    border: 3px solid var(--text);
    border-radius: 5px;
    animation: rotate-hint 2.4s ease-in-out infinite;
  }

  .cv {
    display: block;
    position: static;
    overflow: visible;
    background: none;
  }

  .cv__bar {
    display: none;
  }
}

@keyframes rotate-hint {
  0%, 25% { transform: rotate(0deg); }
  50%, 75% { transform: rotate(-90deg); }
  100% { transform: rotate(0deg); }
}

@media (prefers-reduced-motion: reduce) {
  .rotate__phone {
    animation: none;
    transform: rotate(-90deg);
  }
}

.touch__btn {
  display: grid;
  place-items: center;
  border: 1px solid var(--key-edge);
  border-bottom-width: 4px;
  border-radius: 10px;
  background: var(--key);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  touch-action: none;
}

.touch__btn.is-pressed {
  border-bottom-width: 1px;
  transform: translateY(3px);
  filter: brightness(1.3);
}

.touch__dpad {
  display: grid;
  grid-template-areas:
    ". up ."
    "left . right"
    ". down .";
  /* One pad: the thumb rolls between arrows and onto diagonals, corners included (see TouchControls). */
  touch-action: none;
  grid-template-columns: repeat(3, 44px);
  grid-template-rows: repeat(3, 44px);
  gap: 4px;
}

.touch__btn--up { grid-area: up; }
.touch__btn--left { grid-area: left; }
.touch__btn--right { grid-area: right; }
.touch__btn--down { grid-area: down; }

.touch__btn--start {
  width: 52px;
  height: 28px;
  border-radius: 14px;
  font-size: 10px;
}

.touch__btn--start.is-idle {
  /* Hidden, not removed: the HUD span is measured from this button's place. */
  visibility: hidden;
}

.touch__btn--round {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  font-size: 16px;
}

.touch__btn--a {
  background: var(--accent);
  border-color: #b84a0c;
}

/* ── Held sideways: the game fills the screen and the controls float over it ── */

@media (pointer: coarse) and (orientation: landscape) {
  /* Playing full screen, no gesture zooms or scrolls the page (or pulls to refresh). */
  html {
    touch-action: none;
  }

  body {
    background: #000;
  }

  .stage {
    padding: 0;
  }

  .bar {
    display: none;
  }

  .screen {
    padding: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .screen::after {
    inset: 0;
  }

  /* Pause top right; D-pad and A in the bottom corners, inside the notch and home-bar margins. */
  .touch {
    --edge: max(16px, env(safe-area-inset-left), env(safe-area-inset-right));
    --top: max(10px, env(safe-area-inset-top));
    --arm: 48px;
    --round: 72px;
    position: fixed;
    inset: 0;
    display: grid;
    grid-template:
      ". start" auto
      ". ." 1fr
      "dpad jump" auto
      / 1fr auto;
    width: auto;
    padding: var(--top) var(--edge) max(16px, env(safe-area-inset-bottom));
    pointer-events: none;
  }

  .touch > * {
    pointer-events: auto;
  }

  /* Centered on the HUD's two rows, 16 game pixels down; a game pixel is 1/240 of the screen's height. */
  .touch__btn--start {
    grid-area: start;
    justify-self: end;
    margin-top: max(0px, calc(100dvh * 16 / 240 - 28px / 2 - var(--top)));
  }

  .touch__dpad {
    grid-area: dpad;
    justify-self: start;
    grid-template-columns: repeat(3, var(--arm));
    grid-template-rows: repeat(3, var(--arm));
    gap: 0;
  }

  .touch__btn--round {
    width: var(--round);
    height: var(--round);
    font-size: calc(var(--round) * 0.25);
  }

  .touch__dpad .touch__btn {
    font-size: calc(var(--arm) * 0.3);
  }

  /* See-through buttons, so the level stays visible underneath. */
  .touch__btn {
    border: 2px solid rgba(255, 255, 255, 0.55);
    background: rgba(255, 255, 255, 0.16);
    color: #ffffff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  }

  .touch__btn.is-pressed {
    border-bottom-width: 2px;
    transform: none;
    filter: none;
    background: rgba(255, 255, 255, 0.4);
  }

  /* A mirrors the D-pad: its center sits as far in from the corner as the D-pad's. */
  .touch__btn--a {
    grid-area: jump;
    align-self: center;
    margin-right: calc((3 * var(--arm) - var(--round)) / 2);
    background: rgba(228, 92, 16, 0.6);
  }

  .touch__btn--a.is-pressed {
    background: rgba(228, 92, 16, 0.8);
  }

  /* The four arms and a hub join into one cross. */
  .touch__dpad::before {
    content: "";
    grid-area: 2 / 2;
    background: rgba(255, 255, 255, 0.16);
  }

  .touch__btn--up {
    border-bottom: 0;
    border-radius: 12px 12px 0 0;
  }

  .touch__btn--down {
    border-top: 0;
    border-radius: 0 0 12px 12px;
  }

  .touch__btn--left {
    border-right: 0;
    border-radius: 12px 0 0 12px;
  }

  .touch__btn--right {
    border-left: 0;
    border-radius: 0 12px 12px 0;
  }
}

/* Tablets: larger controls for the larger screen. */
@media (pointer: coarse) and (orientation: landscape) and (min-height: 500px) {
  .touch {
    --arm: 60px;
    --round: 88px;
  }
}

/* ── Computers, whatever the system or window shape: the game fills the window ── */

@media not all and (pointer: coarse) {
  /* The stage takes the whole window, so the title bar runs along its top and the keys along its bottom. */
  body {
    place-items: stretch;
    background: #000;
  }

  /* Never wider than the window, even while the canvas is still sized for a larger one, so the keys wrap to it before main.js measures them. */
  .stage {
    min-width: 0;
    min-height: 0;
    gap: 10px;
    padding: 0;
  }

  .bar {
    padding: 10px 16px 0;
  }

  .legend {
    padding: 0 16px 10px;
  }

  /* From side to side between them, sized by main.js to the room they leave. */
  .screen {
    margin-block: auto;
    padding: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .screen::after {
    inset: 0;
  }

  /* Full screen (F, or the bar's button), the game covers all of it. */
  :fullscreen .bar,
  :fullscreen .legend {
    display: none;
  }
}

/* ── Loading, no JavaScript, printing ──────────────────────────── */

/* Until main.js has sized the canvas, the game stays hidden, so it appears in place instead of jumping there. */
@media (scripting: enabled) {
  html:not(.is-ready) .screen,
  html:not(.is-ready) .touch,
  html:not(.is-ready) .legend {
    visibility: hidden;
  }
}

/* Without JavaScript there is no game: the page is the text version. */
@media (scripting: none) {
  html,
  body {
    height: auto;
  }

  body {
    display: block;
    place-items: normal;
    overflow: visible;
  }

  .stage > :not(.bar),
  .bar__link--text,
  .cv__bar {
    display: none;
  }

  .cv {
    display: block;
    position: static;
    overflow: visible;
    background: none;
  }
}

/* Printing, or saving as PDF, gives the résumé whatever is on screen: in black on white, without the game's art. */
@media print {
  @page {
    margin: 16mm 14mm;
  }

  html,
  body {
    height: auto;
  }

  body {
    display: block;
    place-items: normal;
    overflow: visible;
    background: #ffffff;
  }

  .stage,
  .rotate,
  .cv__bar,
  .cv__scene > img,
  .cv__eyebrow,
  .cv__game-note,
  .cv__buttons,
  .cv__toc,
  .cv__icon,
  .cv__status,
  .cv__aside,
  .cv__more,
  .cv__extra,
  .cv__ground {
    display: none !important;
  }

  .cv {
    display: block;
    position: static;
    overflow: visible;
    background: none;
    font-size: 10.5pt;
    line-height: 1.45;
  }

  .cv *,
  .cv li::marker {
    color: #000000 !important;
    text-shadow: none !important;
  }

  .cv__scene,
  .cv__plate {
    display: block;
    place-items: normal;
    width: auto;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
    text-align: left;
  }

  .cv .cv__plate h2 {
    font-size: 16pt;
  }

  .cv__headline {
    margin-top: 6pt;
    font-size: 9pt;
  }

  .cv__body {
    max-width: none;
    padding: 0;
  }

  .cv__intro {
    margin-top: 10pt;
  }

  .cv__facts {
    gap: 0;
    border: 0;
    background: none;
  }

  .cv__facts div {
    padding: 4pt 8pt 4pt 0;
    background: none;
  }

  .cv__chapter {
    margin-top: 14pt;
    padding: 10pt 0 0;
    border-top: 1px solid #999999;
    background: none;
    box-shadow: none;
  }

  .cv__head {
    margin-bottom: 8pt;
    padding-bottom: 0;
    background: none;
  }

  .cv h2 {
    font-size: 10pt;
  }

  .cv h3 {
    margin-top: 10pt;
    font-size: 8pt;
    line-height: 1.6;
  }

  .cv__org {
    font-size: 10.5pt;
    line-height: 1.45;
  }

  .cv__role + .cv__role,
  .cv .cv__trophies-title {
    margin-top: 10pt;
    padding-top: 0;
    background: none;
  }

  .cv .cv__meta {
    margin-bottom: 4pt;
  }

  .cv ul.cv__list {
    padding-left: 14pt;
    list-style: square;
  }

  .cv__list li {
    margin-bottom: 2pt;
    padding-left: 0;
  }

  .cv__list li::before {
    content: none;
  }

  .cv__trophies li,
  .cv__items li {
    border: 1px solid #999999;
    background: none;
  }

  .cv__trophies li {
    padding: 6pt 8pt;
  }

  .cv__items li {
    padding: 1pt 5pt;
  }

  .cv .cv__contact a.cv__button {
    min-height: 0;
    padding: 0;
    border: 0;
    background: none;
  }

  .cv h2,
  .cv h3,
  .cv__head,
  .cv__role-head {
    break-after: avoid;
  }

  .cv__role,
  .cv__facts,
  .cv__trophies li,
  .cv__items {
    break-inside: avoid;
  }

  .cv a {
    text-decoration: none;
  }
}
