:root {
  /* One interface step. Every fixed size below is a whole number of these, so
     on a screen tall enough (--ui-scale 2 and up, set from JS) the whole frame
     doubles by whole pixels and stays on the 8px grid the type is drawn on.
     Media query breakpoints stay in plain CSS px: the scale only ever rises
     past 1 on viewports far larger than any breakpoint in this stylesheet */
  --ui-scale: 1;
  --u: calc(1px * var(--ui-scale));

  /* Colors - Base */
  --color-background: #121212;

  /* Colors - The evening sky, as the stylesheet paints it under the canvas
     until the first frame has painted the real one over it */
  --color-sky-top: #1A2E68;
  --color-sky-bottom: #FD9463;

  /* Colors - Desert HUD */
  --color-hud-text: #4a3a2e;
  --color-hud-muted: rgba(74, 58, 46, 0.18);
  --color-material: #e8823c;
  --color-material-lit: #f8bb82;
  --color-material-deep: #ae5523;
  --color-material-ink: #5e2a12;
  --color-material-medium: #d97a2b;

  /* Colors - The plate the readout is set on: riveted steel off the bridge,
     rusted maroon and lit rust red, lettered pale and framed in ink */
  --color-hud-plate: #3a2129;
  --color-hud-plate-lit: #ae4d32;
  --color-hud-plate-shade: #20121b;
  --color-hud-rivet: #e07a48;
  --color-hud-trough: #1a0e18;
  --color-hud-drop: rgba(10, 12, 40, 0.45);
  --color-hud-ink: #0a0510;
  --color-hud-type: #f4e8de;

  /* Colors - The material as the readout shows it: a block of the pads'
     asphalt, and the neon it glows with in the air, going amber and then red
     as it runs low */
  --color-hud-chip: #33313e;
  --color-hud-chip-lit: #9c9aae;
  --color-neon: #6ff6ff;
  --color-neon-glow: rgba(111, 246, 255, 0.5);
  --color-neon-medium: #ffc857;
  --color-neon-low: #ff5a7a;

  /* Colors - The paper the sound menu is drawn on */
  --color-panel: #F7EFE3;
  --color-panel-edge: rgba(74, 58, 46, 0.18);
  --color-hud-caption: rgba(74, 58, 46, 0.75);

  /* Colors - Game over overlay */
  --color-overlay-scrim: rgba(20, 22, 52, 0.58); /* Dims the scene to dusk without hiding it */
  --color-overlay-shade: #1a1c3a;
  --color-overlay-glow: rgba(255, 168, 92, 0.45); /* The warmth the title throws round itself */
  --color-overlay-text: #f7efe3;
  --color-overlay-muted: rgba(247, 239, 227, 0.72);

  /* Spacing */
  --spacing-xs: calc(5 * var(--u));
  --spacing-sm: calc(10 * var(--u));
  --spacing-md: calc(15 * var(--u));
  --spacing-lg: calc(20 * var(--u));
  --spacing-xl: calc(30 * var(--u));


  /* Fonts: one pixel face, so the type matches the art. It is drawn on an 8px
     grid, so every size is a whole multiple of 8 and the glyphs stay crisp */
  --font-family: "Press Start 2P", "Courier New", monospace;
  --font-size-xs: calc(8 * var(--u));
  --font-size-sm: calc(16 * var(--u));
  --font-size-md: calc(16 * var(--u));
  --font-size-lg: calc(24 * var(--u));

  /* Animations */
  --animation-speed-fast: 0.2s;
  --animation-speed-medium: 0.3s;

  /* Sizing */
  --material-meter-height: calc(8 * var(--u));
  --settings-button-size: calc(40 * var(--u));
  /* How tall the instructions strip stands. It is measured once laid out and
     written back here by the code, since how many rows the steps wrap into is
     the window's to decide; what is set here is only what the first frame draws
     with, before that measure lands */
  --instructions-height: calc(132 * var(--u));
  /* What the strip covers, which is its height while it stands there and
     nothing once it has slid away */
  --instructions-clearance: var(--instructions-height);
}

body {
  margin: 0;
  overflow: hidden;
  font-family: var(--font-family);
  /* The face carries no bold, so synthetic weights would only smear the pixels */
  font-weight: 400;
  line-height: 1.6;
  touch-action: none;
  background-color: var(--color-background);
  user-select: none;
}

#gameCanvas {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  touch-action: none;

  /* The window, stated here as well as written back by the code once it has
     measured. A canvas given no size stands 300 by 150, and the sky below is
     painted on the element itself, so without this the first paint is a small
     pale rectangle in the corner until the script has loaded and sized it. What
     the code writes is these same two lengths in pixels, so nothing moves when
     that lands */
  width: 100%;
  height: 100%;

  /* The evening sky, roughed in on the element itself so the window is not
     blank before the first frame has painted the real one over it */
  background: linear-gradient(var(--color-sky-top) 55%, var(--color-sky-bottom));

  /* Pixel-art pointer, a true mirror of itself about the tip-to-tail axis: two
     arms of equal length leave the tip at right angles, thick enough to read as
     a pointer, and a short stem runs out along the diagonal between them. It
     wears the runner's green, a hue found nowhere else in the evening, inside a
     dark line of its own, so it holds over the navy, the coral and the gold
     alike. Inline SVG, so it needs no asset file and stays crisp on any display */
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22'%3E%3Cg fill='%23252E1A'%3E%3Crect x='0' y='0' width='20' height='4'/%3E%3Crect x='0' y='2' width='20' height='4'/%3E%3Crect x='0' y='4' width='20' height='4'/%3E%3Crect x='0' y='6' width='12' height='4'/%3E%3Crect x='0' y='8' width='14' height='4'/%3E%3Crect x='0' y='10' width='8' height='4'/%3E%3Crect x='8' y='10' width='8' height='4'/%3E%3Crect x='0' y='12' width='8' height='4'/%3E%3Crect x='10' y='12' width='8' height='4'/%3E%3Crect x='0' y='14' width='8' height='4'/%3E%3Crect x='12' y='14' width='8' height='4'/%3E%3Crect x='0' y='16' width='8' height='4'/%3E%3Crect x='14' y='16' width='8' height='4'/%3E%3Crect x='16' y='18' width='4' height='4'/%3E%3C/g%3E%3Cg fill='%238FAD62'%3E%3Crect x='1' y='1' width='18' height='2'/%3E%3Crect x='1' y='3' width='18' height='2'/%3E%3Crect x='1' y='5' width='18' height='2'/%3E%3Crect x='1' y='7' width='10' height='2'/%3E%3Crect x='1' y='9' width='12' height='2'/%3E%3Crect x='1' y='11' width='6' height='2'/%3E%3Crect x='9' y='11' width='6' height='2'/%3E%3Crect x='1' y='13' width='6' height='2'/%3E%3Crect x='11' y='13' width='6' height='2'/%3E%3Crect x='1' y='15' width='6' height='2'/%3E%3Crect x='13' y='15' width='6' height='2'/%3E%3Crect x='1' y='17' width='6' height='2'/%3E%3Crect x='15' y='17' width='6' height='2'/%3E%3Crect x='17' y='19' width='2' height='2'/%3E%3C/g%3E%3Cg fill='%23AECB7F'%3E%3Crect x='1' y='1' width='2' height='2'/%3E%3Crect x='3' y='1' width='2' height='2'/%3E%3Crect x='5' y='1' width='2' height='2'/%3E%3Crect x='7' y='1' width='2' height='2'/%3E%3Crect x='9' y='1' width='2' height='2'/%3E%3Crect x='11' y='1' width='2' height='2'/%3E%3Crect x='13' y='1' width='2' height='2'/%3E%3Crect x='15' y='1' width='2' height='2'/%3E%3Crect x='17' y='1' width='2' height='2'/%3E%3Crect x='1' y='3' width='2' height='2'/%3E%3Crect x='1' y='5' width='2' height='2'/%3E%3Crect x='1' y='7' width='2' height='2'/%3E%3Crect x='1' y='9' width='2' height='2'/%3E%3Crect x='1' y='11' width='2' height='2'/%3E%3Crect x='1' y='13' width='2' height='2'/%3E%3Crect x='1' y='15' width='2' height='2'/%3E%3Crect x='1' y='17' width='2' height='2'/%3E%3C/g%3E%3Cg fill='%23FDF3E6'%3E%3Crect x='3' y='1' width='2' height='2'/%3E%3Crect x='1' y='3' width='2' height='2'/%3E%3C/g%3E%3Cg fill='%236E8B48'%3E%3Crect x='9' y='7' width='2' height='2'/%3E%3Crect x='11' y='9' width='2' height='2'/%3E%3Crect x='13' y='11' width='2' height='2'/%3E%3Crect x='15' y='13' width='2' height='2'/%3E%3Crect x='17' y='15' width='2' height='2'/%3E%3Crect x='19' y='17' width='2' height='2'/%3E%3Crect x='17' y='19' width='2' height='2'/%3E%3C/g%3E%3C/svg%3E") 1 1, auto;
}
#ui {
  position: absolute;
  /* Held clear of a phone's notch in landscape */
  top: calc(var(--spacing-lg) + env(safe-area-inset-top, 0px));
  left: calc(var(--spacing-lg) + env(safe-area-inset-left, 0px));
  color: var(--color-hud-type);
  font-family: var(--font-family);
  pointer-events: none;
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);

  /* A riveted plate of the bridge's steel: rusted maroon, lit rust red along
     its top and its left edge and in its own shade along the other two, a
     rivet in each corner, framed in ink and standing off the scene on a hard
     shadow */
  padding: calc(14 * var(--u)) calc(18 * var(--u)) calc(16 * var(--u));
  --rivet: linear-gradient(var(--color-hud-rivet), var(--color-hud-rivet));
  --rivet-size: calc(4 * var(--u)) calc(4 * var(--u));
  --rivet-inset: calc(6 * var(--u));
  background:
    var(--rivet) left var(--rivet-inset) top var(--rivet-inset) / var(--rivet-size) no-repeat,
    var(--rivet) right var(--rivet-inset) top var(--rivet-inset) / var(--rivet-size) no-repeat,
    var(--rivet) left var(--rivet-inset) bottom var(--rivet-inset) / var(--rivet-size) no-repeat,
    var(--rivet) right var(--rivet-inset) bottom var(--rivet-inset) / var(--rivet-size) no-repeat,
    var(--color-hud-plate);
  box-shadow:
    inset calc(2 * var(--u)) calc(2 * var(--u)) 0 var(--color-hud-plate-lit),
    inset calc(-2 * var(--u)) calc(-2 * var(--u)) 0 var(--color-hud-plate-shade),
    0 0 0 calc(3 * var(--u)) var(--color-hud-ink),
    calc(3 * var(--u)) calc(3 * var(--u)) 0 calc(3 * var(--u)) var(--color-hud-drop);
}

/* One line of the readout, e.g. SCORE: 001245 */
.stat {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  font-size: calc(16 * var(--u));
  letter-spacing: var(--u);
  text-transform: uppercase;
  line-height: 1.1;
}

/* The score sits above the rest of the readout */
.stat-primary {
  font-size: calc(24 * var(--u));
  letter-spacing: calc(2 * var(--u));
  margin-bottom: calc(6 * var(--u));
}

#score,
#materialValue {
  font-variant-numeric: tabular-nums;
}

/* Small block of material, matching the ones falling from the sky. It caps the
   right end of the readout, level with the score above and the meter below */
.material-chip {
  margin-left: auto;
  width: calc(12 * var(--u));
  height: calc(12 * var(--u));
  background: var(--color-hud-chip);
  /* Cut like the blocks: asphalt worn pale along its top over the neon along
     its foot, in an ink line of its own and glowing the way they do */
  box-shadow:
    inset 0 calc(2 * var(--u)) 0 var(--color-hud-chip-lit),
    inset 0 calc(-4 * var(--u)) 0 var(--color-neon),
    0 0 0 calc(2 * var(--u)) var(--color-hud-ink),
    0 0 calc(8 * var(--u)) calc(2 * var(--u)) var(--color-neon-glow);
}

/* Runs the full width of the readout, which the score line above sets */
/* A trough set into the plate, framed in ink, that the material fills */
#materialMeter {
  height: var(--material-meter-height);
  background: var(--color-hud-trough);
  overflow: hidden;
  margin-top: calc(6 * var(--u));
  margin-bottom: calc(2 * var(--u));
  box-shadow: 0 0 0 calc(2 * var(--u)) var(--color-hud-ink);
}

/* Neon, lit white along its top and shaded along its foot, whatever colour it
   is reading in */
#materialLevel {
  height: 100%;
  width: 100%;
  background: var(--color-neon);
  box-shadow:
    inset 0 calc(2 * var(--u)) 0 rgba(255, 255, 255, 0.5),
    inset 0 calc(-2 * var(--u)) 0 rgba(10, 20, 50, 0.35);
  transition: width var(--animation-speed-medium), background-color var(--animation-speed-medium);
}

/* Down to the last of the material, the whole meter blinks */
#materialMeter.is-critical {
  animation: blink 0.6s infinite;
}

/* The bottom right corner: the credit stands there, and the frame counter
   takes its place while it is asked for */
.corner {
  position: absolute;
  /* Clears the instructions strip, and the bar a phone draws at the foot of
     its screen once the strip has gone */
  bottom: calc(var(--instructions-clearance) + var(--spacing-lg) + env(safe-area-inset-bottom, 0px));
  right: calc(var(--spacing-lg) + env(safe-area-inset-right, 0px));
  /* Paper type on a hard dark offset, the shadow the pixel lettering wears
     elsewhere: it is the deck it stands over, so it reads light on dark, and
     the offset keeps it legible however busy the steel behind it is */
  color: var(--color-panel);
  text-shadow: calc(2 * var(--u)) calc(2 * var(--u)) 0 var(--color-overlay-shade);
  opacity: 0.85;
  font-family: var(--font-family);
  z-index: 100;
  text-align: right;
}

/* Neither has any place under a card, which carries the credit at its own foot */
body:has(.overlay.is-visible) .corner {
  display: none;
}

.credit {
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: var(--u);
}

.fps-container {
  display: none;
}

.fps-container.is-visible {
  display: block;
}

.fps-label {
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: var(--u);
  margin-bottom: var(--spacing-xs);
}

#fpsCounter {
  font-size: calc(24 * var(--u));
  letter-spacing: calc(2 * var(--u));
  font-variant-numeric: tabular-nums;
}
.button {
  padding: calc(16 * var(--u)) calc(32 * var(--u));
  margin: 0;
  background: var(--color-material);
  border: none;
  color: var(--color-overlay-text);
  font-family: var(--font-family);
  font-size: var(--font-size-md);
  letter-spacing: calc(2 * var(--u));
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
  /* Cut like a block of the material: lit along its top and left, shaded along
     the other two, in an ink line of its own, and stood off the card on a hard
     shadow with no blur, so it keeps the edges of the pixel art */
  --bevel:
    inset 0 calc(3 * var(--u)) 0 var(--color-material-lit),
    inset calc(3 * var(--u)) 0 0 rgba(255, 220, 180, 0.35),
    inset 0 calc(-3 * var(--u)) 0 var(--color-material-deep),
    inset calc(-3 * var(--u)) 0 0 rgba(94, 42, 18, 0.35),
    0 0 0 calc(3 * var(--u)) var(--color-material-ink);
  box-shadow: var(--bevel), calc(6 * var(--u)) calc(6 * var(--u)) 0 calc(1 * var(--u)) var(--color-overlay-shade);
  text-shadow: calc(2 * var(--u)) calc(2 * var(--u)) 0 var(--color-material-ink);
}

.button:hover {
  background: var(--color-material-medium);
}

.button:active {
  /* Pressed down into its own shadow */
  transform: translate(calc(3 * var(--u)), calc(3 * var(--u)));
  box-shadow: var(--bevel), calc(3 * var(--u)) calc(3 * var(--u)) 0 calc(1 * var(--u)) var(--color-overlay-shade);
}

/* The quieter of two buttons standing together: the same block drawn as an
   outline rather than filled, so the one that starts the next run reads first */
.button-secondary {
  background: transparent;
  box-shadow: inset 0 0 0 calc(3 * var(--u)) var(--color-overlay-text), calc(5 * var(--u)) calc(5 * var(--u)) 0 var(--color-overlay-shade);
}

.button-secondary:hover {
  background: var(--color-overlay-shade);
}

.button-secondary:active {
  box-shadow: inset 0 0 0 calc(3 * var(--u)) var(--color-overlay-text), calc(2 * var(--u)) calc(2 * var(--u)) 0 var(--color-overlay-shade);
}
/* The speaker in the top right corner, across from the readout, and the sound
   menu it opens under itself. Both are drawn from the same flat blocks as the
   HUD: no rounding, no blur, and every size a whole number of interface pixels */
#settings {
  position: absolute;
  /* Held clear of a phone's notch in landscape, like the readout across from it */
  top: calc(var(--spacing-lg) + env(safe-area-inset-top, 0px));
  right: calc(var(--spacing-lg) + env(safe-area-inset-right, 0px));
  /* Over the title and game over sheets, so the sound is always to hand */
  z-index: 300;
}

#settingsButton {
  width: var(--settings-button-size);
  height: var(--settings-button-size);
  /* The three a bare <button> comes with, which the speaker wears none of */
  padding: 0;
  background: transparent;
  border: none;
  color: var(--color-hud-text);
  cursor: pointer;
  display: flex;
  /* Offset with no blur, the same shadow the pixel type wears. It is what keeps
     the dark speaker readable over the dimmed sheets it sits above */
  filter: drop-shadow(calc(2 * var(--u)) calc(2 * var(--u)) 0 var(--color-panel));
  align-items: center;
  justify-content: center;
  opacity: 0.7;
  transition: opacity var(--animation-speed-fast) ease, transform var(--animation-speed-fast) ease;
}

#settingsButton:hover {
  opacity: 1;
  transform: scale(1.1);
}

#settingsButton:active {
  transform: scale(0.95);
}

/* Drawn on a 16 pixel grid and only ever scaled by whole multiples of it, so
   the speaker stays as hard-edged as the sprites */
.settings-icon {
  width: calc(32 * var(--u));
  height: calc(32 * var(--u));
  fill: currentColor;
  shape-rendering: crispEdges;
}

/* The waves stand for sound coming out; the cross takes their place once both
   channels are down to nothing */
#settingsButton.is-muted .settings-icon-waves,
#settingsButton:not(.is-muted) .settings-icon-mute {
  display: none;
}

/* A paper panel, stood on its own hard shadow */
.settings-panel {
  position: absolute;
  top: calc(100% + var(--spacing-sm));
  right: 0;
  display: none;
  flex-direction: column;
  gap: var(--spacing-sm);
  box-sizing: border-box;
  width: calc(240 * var(--u));
  padding: var(--spacing-md);
  background: var(--color-panel);
  border: calc(3 * var(--u)) solid var(--color-panel-edge);
  box-shadow: calc(5 * var(--u)) calc(5 * var(--u)) 0 var(--color-overlay-shade);
  color: var(--color-hud-text);
  font-family: var(--font-family);
}

.settings-panel.is-visible {
  display: flex;
}

.settings-title {
  margin: 0 0 var(--spacing-xs) 0;
  font-size: var(--font-size-xs);
  letter-spacing: calc(2 * var(--u));
  text-transform: uppercase;
  color: var(--color-material);
}

/* Name on the left, figure on the right, bar underneath the pair */
.settings-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--spacing-xs);
  align-items: center;
  cursor: pointer;
}

.settings-name,
.settings-value {
  font-size: var(--font-size-xs);
  letter-spacing: var(--u);
  text-transform: uppercase;
  line-height: 1;
}

.settings-value {
  color: var(--color-hud-caption);
  font-variant-numeric: tabular-nums;
}

/* The bar is the track itself: filled up to the setting in material orange, and
   dim beyond it, the same two colours the material meter reads in */
.settings-slider {
  grid-column: 1 / -1;
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: calc(10 * var(--u));
  margin: calc(2 * var(--u)) 0 0 0;
  background: linear-gradient(
    to right,
    var(--color-material) 0 var(--fill, 0%),
    var(--color-hud-muted) var(--fill, 0%) 100%
  );
  cursor: pointer;
}

.settings-slider:focus-visible {
  outline: calc(2 * var(--u)) solid var(--color-material);
  outline-offset: calc(2 * var(--u));
}

/* A square knob standing on the bar, in the dark of the sprite outlines */
.settings-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: calc(8 * var(--u));
  height: calc(18 * var(--u));
  border: none;
  border-radius: 0;
  background: var(--color-overlay-shade);
}

.settings-slider::-moz-range-thumb {
  width: calc(8 * var(--u));
  height: calc(18 * var(--u));
  border: none;
  border-radius: 0;
  background: var(--color-overlay-shade);
}

.settings-slider::-moz-range-track {
  background: transparent;
}
/* Both sheets - the title card and the game over card - are the same frame: a
   dimmed sheet over the scene, with no panel of its own */
.overlay {
  position: fixed;
  /* Stops above the instructions strip, so the name and the loop stay readable */
  inset: 0 0 var(--instructions-clearance) 0;
  z-index: 200;

  /* Laid out as a flex column, so visibility is a class rather than a display toggle */
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-xl);

  background: var(--color-overlay-scrim);
  color: var(--color-overlay-text);
  font-family: var(--font-family);
  text-align: center;
  /* The card gives way as the strip slides in under it, at the same pace */
  transition: bottom var(--animation-speed-medium) ease;
}

.overlay.is-visible {
  display: flex;
}

/* The line of story under the title on the card */
.overlay-story {
  margin: 0;
  font-size: var(--font-size-sm);
  line-height: 2;
  letter-spacing: var(--u);
  color: var(--color-overlay-muted);
}

.overlay-title {
  margin: 0;
  /* Stepped rather than fluid, so the letters only ever scale by whole pixels */
  font-size: calc(32 * var(--u));
  letter-spacing: calc(4 * var(--u));
  text-transform: uppercase;
  color: var(--color-material);
  /* Offset with no blur, so the letters keep the hard edges of the pixel art,
     and a glow behind that, the name lit the way the material is */
  text-shadow:
    0 calc(-2 * var(--u)) 0 var(--color-material-lit),
    calc(5 * var(--u)) calc(5 * var(--u)) 0 var(--color-overlay-shade),
    0 0 calc(24 * var(--u)) var(--color-overlay-glow);
}

/* The one figure the run leaves behind, centred under the title */
.overlay-stat {
  display: flex;
  gap: var(--spacing-md);
  margin: 0;
  font-size: var(--font-size-md);
  letter-spacing: var(--u);
  text-transform: uppercase;
}

.overlay-label {
  color: var(--color-overlay-muted);
}

.overlay-value {
  font-variant-numeric: tabular-nums;
}

/* The two ways on from the game over card: run it again, or read the loop again */
.overlay-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-lg);
}

/* Who made it, at the foot of both cards: what it was built with, and under
   that the name, which leads to the author. Pinned to the foot rather than
   stacked with the rest, so the card stays centred on what it has to say */
.overlay-credit {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--spacing-lg) + env(safe-area-inset-bottom, 0px));
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-sm);
  font-size: var(--font-size-xs);
  letter-spacing: var(--u);
  text-transform: uppercase;
  color: var(--color-overlay-muted);
  /* The same hard offset the credit wears in the corner during a run */
  text-shadow: calc(2 * var(--u)) calc(2 * var(--u)) 0 var(--color-overlay-shade);
}

.overlay-author {
  color: var(--color-overlay-text);
  text-decoration: none;
}

.overlay-author:hover,
.overlay-author:focus-visible {
  text-decoration: underline;
}
/* A strip of the material lying over the foot of the scene: the game's name,
   then the loop in five steps */
#instructions {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /* No height of its own. It stands as tall as the rows its steps wrap into,
     which the width of the window decides, and the code publishes that height
     as --instructions-height for the cards above to stop clear of */
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: var(--spacing-xl);
  padding: var(--spacing-lg) var(--spacing-xl);
  /* Clear of the bar a phone draws across the foot of its screen */
  padding-bottom: calc(var(--spacing-lg) + env(safe-area-inset-bottom, 0px));
  /* Cut like the buttons on the cards above it, from the same orange: an ink
     line along its top, lit under that and shaded along its foot */
  background: var(--color-material);
  border-top: calc(3 * var(--u)) solid var(--color-material-ink);
  box-shadow:
    inset 0 calc(3 * var(--u)) 0 var(--color-material-lit),
    inset 0 calc(-3 * var(--u)) 0 var(--color-material-deep);
  color: var(--color-material-ink);
  font-family: var(--font-family);
  z-index: 150;
  overflow: hidden;
  transition: transform var(--animation-speed-medium) ease;
}

/* The strip lies over the scene rather than beside it, so leaving is a slide off
   the foot of the window: the run behind it neither grows nor shrinks. It keeps
   its own height on the way out — only what it covers goes to nothing */
.instructions-hidden {
  --instructions-clearance: 0px;
}

.instructions-hidden #instructions {
  transform: translateY(100%);
}

/* The name, stacked on two lines so it stands as tall as the pictures */
.instructions-brand {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  padding-right: var(--spacing-xl);
  /* A groove down the orange: in shade on the side turned from the light, lit
     on the side facing it */
  border-right: calc(3 * var(--u)) solid var(--color-material-deep);
  box-shadow: calc(3 * var(--u)) 0 0 var(--color-material-lit);
  align-self: stretch;
  justify-content: center;
}

.instructions-name {
  /* Stepped rather than fluid, so the letters only ever scale by whole pixels */
  font-size: calc(24 * var(--u));
  letter-spacing: calc(3 * var(--u));
  text-transform: uppercase;
  /* Lettered the way the buttons are: pale, on a hard ink offset with no blur */
  color: var(--color-overlay-text);
  text-shadow: calc(3 * var(--u)) calc(3 * var(--u)) 0 var(--color-material-ink);
}

/* The steps run left to right, arrows sitting between them, and fall into a
   second row rather than off the end when the window is too narrow to hold them */
.instructions-steps {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-around;
  gap: var(--spacing-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

.instructions-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-sm);
}

/* The row aligns to its top, so the arrow lines up with the pictures rather than
   with the pictures and their captions together */
.instructions-arrow {
  flex: none;
}

.instructions-art {
  display: block;
  image-rendering: pixelated;
}

.instructions-caption {
  font-size: var(--font-size-xs);
  letter-spacing: var(--u);
  text-transform: uppercase;
  color: var(--color-material-ink);
  /* One line while there is width for one; centred under its picture when the
     narrower layouts let it break */
  text-align: center;
  white-space: nowrap;
}
/* Switches rather than fades, so it reads like a warning lamp and not a glow */
@keyframes blink {
  0%,
  49.9% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0.15;
  }
}
@media (max-width: 768px) {
  :root {
    --settings-button-size: calc(32 * var(--u));
  }

  .stat {
    font-size: calc(8 * var(--u));
    letter-spacing: 0;
  }

  .stat-primary {
    font-size: calc(16 * var(--u));
    letter-spacing: var(--u);
  }

  /* Halved with the button, so the speaker still scales by a whole multiple of
     the grid it is drawn on */
  .settings-icon {
    width: calc(16 * var(--u));
    height: calc(16 * var(--u));
  }

  .settings-panel {
    width: calc(200 * var(--u));
  }

  .overlay-story {
    font-size: var(--font-size-xs);
    line-height: 2.2;
  }

  .overlay-stat {
    font-size: var(--font-size-xs);
    gap: var(--spacing-sm);
  }

  .button {
    padding: calc(12 * var(--u)) calc(26 * var(--u));
    font-size: var(--font-size-sm);
  }
}

/* The game over title steps up in whole multiples of its 8px grid */
@media (min-width: 700px) {
  .overlay-title {
    font-size: calc(48 * var(--u));
  }
}

@media (min-width: 1100px) {
  .overlay-title {
    font-size: calc(64 * var(--u));
  }
}

/* Under the width that holds the loop in a single line, the arrows go and the
   captions break rather than run on. No step is ever dropped: the strip stands
   only over the cards at either end of a run now, and it is the whole loop that
   is read there */
@media (max-width: 1250px) {
  .instructions-arrow {
    display: none;
  }

  .instructions-step {
    width: calc(112 * var(--u));
  }

  .instructions-caption {
    white-space: normal;
  }
}

@media (max-width: 900px) {
  .instructions-name {
    font-size: calc(16 * var(--u));
    letter-spacing: calc(2 * var(--u));
    text-shadow: calc(2 * var(--u)) calc(2 * var(--u)) 0 var(--color-material-ink);
  }
}

/* A phone reads the loop as a block of steps rather than a line of them: they
   wrap into as many rows as the screen has room for, centred, and the name goes
   — the card standing above the strip already carries it */
@media (max-width: 620px) {
  #instructions {
    gap: var(--spacing-md);
    padding: var(--spacing-md);
    padding-bottom: calc(var(--spacing-md) + env(safe-area-inset-bottom, 0px));
  }

  .instructions-brand {
    display: none;
  }

  .instructions-steps {
    justify-content: center;
    row-gap: var(--spacing-md);
  }

  .instructions-step {
    width: calc(96 * var(--u));
  }
}

/* Two buttons too wide to stand side by side stack instead, and take the width
   of the wider of them rather than breaking into a ragged line */
@media (max-width: 560px) {
  .overlay-actions {
    flex-direction: column;
    align-items: stretch;
    gap: var(--spacing-md);
  }
}

/* A window too short to hold a card over a block of steps — a phone held
   sideways — puts the strip back to a single line of smaller ones and pulls the
   card in tight above it */
@media (max-height: 560px) {
  .overlay {
    gap: var(--spacing-md);
  }

  #instructions {
    padding: var(--spacing-sm) var(--spacing-md);
    padding-bottom: calc(var(--spacing-sm) + env(safe-area-inset-bottom, 0px));
  }

  .instructions-brand {
    display: none;
  }

  .instructions-arrow {
    display: none;
  }

  .instructions-step {
    width: calc(80 * var(--u));
  }

  .instructions-caption {
    white-space: normal;
  }
}

/* A phone held upright can play, but held sideways sees the run coming from
   much further off. Said once, over the top of the scene, until tapped away */
#rotateHint {
  display: none;
}

@media (orientation: portrait) and (max-width: 600px) {
  #rotateHint:not([hidden]) {
    display: block;
    position: fixed;
    top: calc(var(--spacing-lg) + env(safe-area-inset-top, 0px));
    left: 50%;
    transform: translateX(-50%);
    z-index: 250;
    padding: var(--spacing-sm) var(--spacing-md);
    background: var(--color-overlay-shade);
    color: var(--color-overlay-text);
    font-family: var(--font-family);
    font-size: var(--font-size-xs);
    letter-spacing: var(--u);
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
  }
}
/* press-start-2p-latin-400-normal */
@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url(/uptime/game/assets/press-start-2p-latin-400-normal-_wFEWmAB.woff2) format('woff2'), url(/uptime/game/assets/press-start-2p-latin-400-normal-KLytu4cr.woff) format('woff');
}