/* Shared chrome for every page in the game: menu, cutscenes, levels. */
:root {
  --ink:    #cfdad8;
  --dim:    #63797a;
  --rust:   #d0682c;
  --amber:  #e8a13a;
  --panel:  rgba(6, 11, 13, 0.78);
  --line:   rgba(110, 150, 150, 0.20);
  --bg:     #05080a;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; height: 100%; overflow: hidden;
  background: var(--bg);
  color: var(--ink);
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  -webkit-font-smoothing: antialiased;
  /* Touch: the page is a game, not a document. Without these a drag to look
   * scrolls the page instead, a two-finger pinch zooms the browser rather
   * than the camera, and a long press on a button starts a text selection
   * with a magnifier over it.
   *
   * `touch-action: manipulation` is the one that stops DOUBLE-TAP ZOOM, and
   * it has to be here rather than on the canvas — the canvas already says
   * `none`, so the taps that were zooming were the ones landing on the UI:
   * a HUD panel, and above all a puzzle's own buttons, where two quick
   * presses of the same key is normal play. On iPad that zoom then STAYS,
   * and because it moves the visual viewport it takes any screen-corner
   * chrome off the edge of the screen with it — which is how a keypad
   * became a puzzle with no way out.
   *
   * It is the FIRST of three layers and on an iPad it is not enough on its
   * own: Safari also smart-zooms off a trackpad double-tap and off a pinch,
   * neither of which is a touch-action concern. The other two — the tap
   * guard and the undo — are inline in `partials/head.html`, so they cover
   * the menu and the cutscenes as well. */
  touch-action: manipulation;
  overscroll-behavior: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

canvas { display: block; touch-action: none; }
a { color: inherit; }

/* ---------- shared HUD ---------- */
.hud {
  position: fixed; z-index: 10;
  background: var(--panel);
  border: 1px solid var(--line);
  backdrop-filter: blur(8px);
  padding: 10px 12px;
  font-size: 11px;
  line-height: 1.55;
  letter-spacing: 0.02em;
  user-select: none;
  pointer-events: none;
}
.hud b { color: var(--rust); font-weight: 600; }
.hud .k { color: var(--dim); }
.hud hr { border: 0; border-top: 1px solid var(--line); margin: 7px 0; }

#keys  { top: 150px; left: 14px; }
#stats { top: 14px; right: 14px; text-align: right; min-width: 128px; }

/* ---------- scrap counter ---------- */
#food {
  position: fixed; top: 14px; left: 14px; z-index: 12;
  background: var(--panel);
  border: 1px solid var(--line); border-left: 2px solid var(--rust);
  backdrop-filter: blur(8px);
  padding: 11px 16px 10px;
  user-select: none; pointer-events: none;
  min-width: 150px;
}
#food .row { display: flex; align-items: baseline; gap: 7px; }
#food .n {
  font-size: 32px; line-height: 1; font-weight: 600; color: var(--amber);
  text-shadow: 0 0 16px rgba(232, 161, 58, .45);
  transition: transform .13s cubic-bezier(.3, 1.6, .5, 1);
  transform-origin: left bottom;
}
#food .of  { font-size: 13px; color: var(--dim); }
#food .lbl { margin-top: 6px; font-size: 9px; letter-spacing: .24em; color: var(--dim); }
#food.pulse .n { transform: scale(1.3); }
#food .bar { margin-top: 8px; height: 2px; background: rgba(180, 220, 218, .10); }
#food .bar i {
  display: block; height: 100%; width: 0;
  background: var(--rust); box-shadow: 0 0 8px var(--rust);
  transition: width .35s ease;
}
#food .lvl {
  margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--line);
  font-size: 9px; letter-spacing: .2em; color: var(--dim);
}
/* The standing objective, once eating everything has unlocked the way out. */
#food .goal {
  display: none; margin-top: 6px;
  font-size: 9px; letter-spacing: .2em; color: var(--amber);
  text-shadow: 0 0 14px rgba(232, 161, 58, .4);
}
#food .goal.on { display: block; }
/* A chapter with nothing to eat is pure traversal — the counter is just noise. */
#food.nofood .row,
#food.nofood .lbl,
#food.nofood .bar { display: none; }
#food.nofood .lvl { margin-top: 0; padding-top: 0; border-top: 0; }

/* ---------- toast ---------- */
#toast {
  position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%);
  z-index: 30; background: var(--panel); border: 1px solid var(--line);
  border-left: 2px solid var(--amber);
  padding: 9px 16px; font-size: 11px; letter-spacing: .04em;
  opacity: 0; transition: opacity .3s ease; pointer-events: none;
  white-space: nowrap;
}
#toast.on { opacity: 1; }

/* ---------- interact prompt ----------
 * Sits above the toast rather than on top of it: a toast is a sentence you
 * read once, this is a label that stays up for as long as you stand there,
 * and the two collide constantly at the mouth of a locked door. */
#prompt {
  position: fixed; bottom: 72px; left: 50%; transform: translateX(-50%);
  z-index: 29; background: var(--panel); border: 1px solid var(--line);
  padding: 7px 14px; font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--dim);
  opacity: 0; transition: opacity .18s ease; pointer-events: none;
  white-space: nowrap;
}
#prompt.on { opacity: 1; }
#prompt b {
  color: var(--amber); font-weight: 600; margin-right: 8px;
  border: 1px solid var(--line); padding: 1px 6px;
}

/* ---------- panel-puzzle overlay ----------
 * The host the engine hands a puzzle. It is `display: none` rather than
 * transparent when shut, because a full-screen layer with pointer events
 * left on eats every click on the canvas underneath it — which reads as
 * the camera drag dying for no reason. */
#panel {
  position: fixed; inset: 0; z-index: 40;
  display: none; place-items: center;
  background: radial-gradient(ellipse at center, rgba(4,7,9,.55), rgba(4,7,9,.9));
  backdrop-filter: blur(3px);
}
#panel.on { display: grid; }

/* Everything below is the chrome a panel puzzle gets for free. A kind that
 * wants a different look styles its own node; these are the defaults so a
 * new kind is not also a CSS project. */
.pz {
  position: relative;                      /* the ✕ hangs off this corner */
  background: var(--panel); border: 1px solid var(--line);
  padding: 20px 22px 18px; min-width: 240px;
  box-shadow: 0 24px 70px rgba(0,0,0,.6);
}
.pz-title {
  font-size: 10px; letter-spacing: .26em; color: var(--dim);
  text-align: center; margin-bottom: 14px; text-transform: uppercase;
  padding: 0 22px;                         /* room for the ✕ over a long title */
}
.pz-screen {
  border: 1px solid var(--line); background: rgba(0,0,0,.45);
  color: var(--amber); font-size: 20px; letter-spacing: .42em;
  text-align: center; padding: 11px 0 10px; margin-bottom: 4px;
  min-height: 44px; text-indent: .42em;   /* the last letter-space, re-centred */
}
.pz-screen.bad  { color: var(--rust); border-color: rgba(208,104,44,.5); }
.pz-screen.good { color: #7fd6a0; border-color: rgba(127,214,160,.5); }
/* A shake says "wrong" before the colour does, and survives being read by
 * someone who cannot tell the two states apart by hue. */
.pz-screen.bad { animation: pz-shake .3s ease; }
@keyframes pz-shake {
  0%,100% { transform: translateX(0); }
  25%     { transform: translateX(-5px); }
  75%     { transform: translateX(5px); }
}
.pz-keys {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin-top: 12px;
}
.pz-keys button {
  font: inherit; font-size: 15px; color: var(--ink);
  background: rgba(255,255,255,.03); border: 1px solid var(--line);
  padding: 12px 0; cursor: pointer; transition: background .12s ease;
}
.pz-keys button:hover  { background: rgba(255,255,255,.09); }
.pz-keys button:active { background: rgba(232,161,58,.18); }
.pz-hint {
  margin-top: 13px; font-size: 10px; letter-spacing: .06em;
  color: var(--dim); text-align: center;
}

/* THE COLOUR PAD. The screen is a row of slots rather than a line of text,
 * so it needs its own layout — the digit screen's letter-spacing and text
 * indent are there to centre a string and both fight a flex row. */
.pz-screen.pz-swatches {
  display: flex; gap: 9px; justify-content: center; align-items: center;
  letter-spacing: 0; text-indent: 0;
}
.pz-sw {
  width: 26px; height: 26px; border: 1px solid var(--line);
  background: rgba(255,255,255,.03);
}
.pz-sw.on { border-color: rgba(255,255,255,.28); }
.pz-keys.pz-paint { grid-template-columns: repeat(4, 1fr); }
/* The swatch and the NAME, stacked. Hue alone is not a readable puzzle. */
.pz-keys.pz-paint button {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dim); padding: 9px 0 8px;
}
.pz-chip { width: 26px; height: 26px; border: 1px solid rgba(255,255,255,.22); }

/* The way out of a panel that is not Esc. A phone has no Esc, and a puzzle
 * you cannot walk away from is a chapter that ends there.
 *
 * It sits on the CARD, not in the screen's corner, and that is the fix for a
 * real report rather than a preference. Screen-corner chrome is `position:
 * fixed`, which is laid out against the LAYOUT viewport — so an iPad that has
 * been double-tap-zoomed (see `touch-action` above) scrolls the visual
 * viewport over the middle of the board and the only way out is somewhere off
 * the edge of the glass. Anchored to the card it is wherever the puzzle is,
 * at any zoom, and it is also simply where anyone looks for it. */
.pz-close {
  position: absolute; top: 0; right: 0; z-index: 41;
  width: 38px; height: 38px; padding: 0;
  display: grid; place-items: center;
  font: inherit; font-size: 14px; line-height: 1;
  color: var(--dim); background: none; border: 0; cursor: pointer;
}
.pz-close:hover  { color: var(--rust); }
.pz-close:active { color: var(--amber); }

/* A step-back button inside a puzzle that needs one. Shift-click turns a
 * disc the other way and there is no shift on a phone; forward-only still
 * reaches every glyph (the steps are coprime) but at up to eleven taps a
 * ring, which is a puzzle turned into a clicking exercise. */
.pz-toggle {
  display: block; margin: 10px auto 0;
  font: inherit; font-size: 10px; letter-spacing: .12em;
  color: var(--dim); background: rgba(255,255,255,.03);
  border: 1px solid var(--line); padding: 9px 14px; cursor: pointer;
}
.pz-toggle.on { color: var(--amber); border-color: rgba(232,161,58,.5); }

/* A board taller than a phone in landscape has to be reachable rather than
 * centred off the top of the screen — `safe` centre stops the overflow
 * going where nothing can scroll to it. */
@media (max-height: 620px), (max-width: 460px) {
  #panel { overflow: auto; padding: 10px; align-items: safe center; }
  .pz { padding: 16px 16px 14px; min-width: 0; }
  .pz-discs { width: min(300px, 78vw, 56vh); }
  .pz-cell  { width: 40px; height: 40px; }
}

/* ---- pipes ----
 * One SVG per cell, not one per board: a tile has to turn, and rotating
 * its own element is the cheapest honest way to show that. Everything is
 * drawn in a 100-unit box centred on 50,50 so the rotation has nothing to
 * correct for. */
.pz-grid { display: grid; gap: 3px; }
.pz-cell {
  width: 46px; height: 46px; padding: 0; cursor: pointer;
  background: rgba(255,255,255,.02); border: 1px solid var(--line);
  transition: transform .13s ease, background .12s ease;
}
.pz-cell.blank { background: none; border-color: transparent; cursor: default; }
.pz-cell.fixed { cursor: default; background: rgba(255,255,255,.05); }
.pz-cell:not(.blank):not(.fixed):hover { background: rgba(255,255,255,.09); }
.pz-cell.lit { background: rgba(232,161,58,.10); }
.pz-cell .pipe { display: block; width: 100%; height: 100%; }

/* ---- circuit ---- */
.pz-board { display: block; max-width: 100%; height: auto; }
.pz-junction {
  fill: rgba(255,255,255,.05); stroke: var(--line); stroke-width: 1.5;
  cursor: pointer; transition: fill .12s ease;
}
.pz-junction:hover { fill: rgba(255,255,255,.14); }
.pz-junction.on { fill: rgba(232,161,58,.20); stroke: var(--amber); }

/* ---- discs ----
 * A ring's hit area is a fat transparent stroke with `pointer-events:
 * stroke` — an annulus you can click without building an annulus path. It
 * sits over the letters, so the whole band is grabbable rather than only
 * the gaps between them. */
.pz-discs { width: 300px; }
.pz-disc-bed  { fill: rgba(255,255,255,.02); stroke: var(--line); stroke-width: 1; }
.pz-disc-ring { fill: none; stroke: var(--line); stroke-width: 1; }
.pz-disc-hit  { fill: none; stroke: transparent; pointer-events: stroke; cursor: grab; }
.pz-disc-hit:hover { stroke: rgba(255,255,255,.05); }
.pz-glyph {
  fill: var(--dim); font-family: inherit; font-weight: 500;
  user-select: none; pointer-events: none;
}
.pz-glyph.lit { fill: var(--amber); }
.pz-disc-mark { fill: var(--amber); }
.pz-disc-read {
  fill: var(--ink); letter-spacing: .22em; text-indent: .22em;
  font-family: inherit; pointer-events: none; user-select: none;
}
.pz-disc-read.good { fill: #7fd6a0; }

/* Every board goes quiet once it is solved — there is nothing left to
 * click, and leaving the hover states live invites you to keep poking a
 * puzzle that is already finished. */
.pz-body.solved .pz-cell,
.pz-body.solved .pz-junction,
.pz-body.solved .pz-disc-hit { cursor: default; pointer-events: none; }

/* ---------- level-clear banner ---------- */
#win {
  position: fixed; inset: 0; z-index: 20;
  display: grid; place-items: center;
  opacity: 0; transition: opacity .9s ease; pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(5,8,10,.35), rgba(5,8,10,.9));
}
#win.on { opacity: 1; }
#win b {
  display: block; font-size: 21px; letter-spacing: .32em; font-weight: 600;
  color: var(--amber); text-shadow: 0 0 34px rgba(232, 161, 58, .5);
  text-align: center;
}
#win small {
  display: block; margin-top: 12px; font-size: 10px;
  letter-spacing: .2em; color: var(--dim); text-align: center;
}

/* ---------- boot / fade ---------- */
#boot {
  position: fixed; inset: 0; z-index: 50;
  display: grid; place-items: center;
  background: var(--bg);
  transition: opacity .6s ease;
  font-size: 11px; letter-spacing: .28em; color: var(--dim);
}
#boot.gone { opacity: 0; pointer-events: none; }

/* Covers the screen when leaving for the next page, so transitions aren't a flash. */
#fade {
  position: fixed; inset: 0; z-index: 60; background: var(--bg);
  opacity: 0; pointer-events: none; transition: opacity .7s ease;
}
#fade.on { opacity: 1; }

/* A single frame of colour over the whole screen — `flash()` in engine.js.
 *
 * It sits UNDER #fade (z 59 against 60) on purpose: a scare ends by going to
 * black and navigating, and a flash that painted over the fade would strobe on
 * the way out. It goes on in one frame and fades out over its own duration,
 * which is the whole of the effect — a flash that eases IN is a light coming
 * up, not a bang. Both are driven from JS, so the timing lives with the thing
 * that fired it rather than in here. */
#scare {
  position: fixed; inset: 0; z-index: 59;
  opacity: 0; pointer-events: none;
  background: #fff;
}

/* ---------- menus / cutscenes (shared page furniture) ---------- */
/* `safe center` and the scroll are one fix: a grid centred on a box smaller
 * than its content overflows BOTH ways, so the top of the list goes off the
 * screen and no amount of scrolling reaches it. `safe` pins it to the start
 * once it no longer fits. */
.page {
  position: fixed; inset: 0; z-index: 5;
  display: grid; place-items: safe center;
  padding: 32px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}
.stack { width: min(560px, 100%); }

.title {
  font-size: clamp(30px, 7vw, 58px);
  letter-spacing: .2em; font-weight: 600; line-height: 1.05;
  color: var(--ink);
  text-shadow: 0 0 50px rgba(208, 104, 44, .3);
}
.title em {
  display: block; font-style: normal;
  color: var(--rust); font-size: .42em; letter-spacing: .42em;
  margin-top: 14px;
}
.rule { height: 1px; background: var(--line); margin: 26px 0; }

.menu { display: grid; gap: 2px; }
.menu button {
  appearance: none; text-align: left; cursor: pointer;
  background: transparent; color: var(--ink);
  border: 1px solid transparent; border-left: 2px solid transparent;
  padding: 12px 16px; font: inherit; font-size: 13px; letter-spacing: .16em;
  transition: background .16s ease, border-color .16s ease, padding .16s ease, color .16s ease;
}
.menu button:hover:not(:disabled),
.menu button:focus-visible:not(:disabled) {
  outline: none;
  background: var(--panel);
  border-color: var(--line); border-left-color: var(--rust);
  padding-left: 22px;
}
.menu button:disabled { color: #35474a; cursor: not-allowed; }
.menu button small {
  display: block; margin-top: 5px;
  font-size: 9px; letter-spacing: .2em; color: var(--dim);
}
.menu button:disabled small { color: #2b393b; }

.foot {
  margin-top: 28px; font-size: 9.5px; letter-spacing: .2em; color: var(--dim);
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  align-items: center;
}
/* Reads as the line of text it replaced; it is a button so a thumb can
   reach the thing the M key does. */
.foot-btn {
  font: inherit; letter-spacing: inherit; color: inherit;
  background: none; border: 0; padding: 6px 2px; cursor: pointer;
}
.foot-btn:hover { color: var(--ink); }

/* ---------- cutscene ---------- */
.beat {
  position: fixed; inset: 0; z-index: 6;
  display: grid; place-items: center; padding: 40px;
  opacity: 0; transition: opacity 1.1s ease;
  pointer-events: none;
}
.beat.on { opacity: 1; }
.beat p {
  max-width: 620px; margin: 0;
  font-size: clamp(15px, 2.4vw, 20px); line-height: 1.85;
  letter-spacing: .06em; text-align: center; color: var(--ink);
  text-shadow: 0 2px 30px rgba(0, 0, 0, .9);
}
.beat p em {
  font-style: normal; color: var(--amber);
}
/* The ending plays its text over a live 3D room, so it needs more than the
 * beats' own text-shadow: a hard vignette to close the corners and a flat
 * scrim across the middle. Authored strong on purpose — the scene behind is
 * lit a stop or two hot to survive it. */
#dim {
  position: fixed; inset: 0; z-index: 2; pointer-events: none;
  background:
    radial-gradient(ellipse 78% 68% at 50% 52%,
      rgba(2, 5, 8, 0) 0%, rgba(2, 5, 8, .34) 46%,
      rgba(2, 5, 8, .82) 78%, rgba(2, 5, 8, .97) 100%),
    linear-gradient(rgba(3, 6, 9, .28), rgba(3, 6, 9, .28));
}

/* The BEGIN gate — only built when the browser refused the soundtrack, so most
   of the time this is never on screen. Over everything (beats are z 6, the
   ending's scrim z 2) and under #fade, so a page transition still covers it. */
.gate {
  z-index: 20;
  background: rgba(2, 5, 8, .82);
  place-items: center;
}
.gate-stack { width: auto; text-align: center; }
.gate .menu button {
  text-align: center;
  border-color: var(--line); border-left-color: var(--rust);
  background: var(--panel);
  padding: 16px 42px;
}
.gate .menu button:hover, .gate .menu button:focus-visible { padding-left: 42px; }

.skip {
  position: fixed; bottom: 22px; right: 24px; z-index: 12;
  font-size: 9.5px; letter-spacing: .22em; color: var(--dim);
  user-select: none;
}
.skip b { color: var(--rust); }

/* ---------- credits ---------- */
.credits { text-align: center; }
.credits h2 {
  margin: 0 0 6px; font-size: 12px; letter-spacing: .34em;
  color: var(--rust); font-weight: 600;
}
.credits .grid {
  display: grid; gap: 26px; margin: 34px 0;
}
.credits .row .r {
  font-size: 9px; letter-spacing: .28em; color: var(--dim); margin-bottom: 7px;
}
.credits .row .v { font-size: 14px; letter-spacing: .1em; }

/* ---------- touch controls ----------
 * Only ever on a device that reported a coarse pointer — `touch.js` adds
 * `.touch` to the body and builds `#touch` itself, so on a desktop none of
 * this matches anything.
 *
 * The layer is `pointer-events: none` and only the stick zone and the
 * buttons turn them back on. That is what leaves the rest of the screen as
 * the look drag: the canvas underneath simply never sees the touches that
 * land on a control, and the engine needs no zone maths at all. */
.touch #keys { display: none; }        /* a keyboard legend with no keyboard */

/* `#stats` is fps, m/s and the y height — an authoring readout, and there is
 * no reason for a player to be shown one. It was hidden inside the
 * `max-height: 460px` short-landscape query, which is a LANDSCAPE PHONE and
 * nothing else: on an iPad, at 1024 of height, the debug panel shipped in the
 * top-right corner of the game. Found in the App Store screenshots, which is
 * a late place to find it. Hidden on every touch device now. */
.touch #stats { display: none; }

/* `touch-action: none` on every control, not just the canvas. Without it
 * the browser reads the first few pixels of a thumb drag as the start of a
 * scroll, takes the gesture over and fires `pointercancel` — so the stick
 * lights up, dies half a step later and the dog drifts to a halt. It is the
 * same rule the canvas needs, and it has to be said on each element that
 * takes touches of its own. */
#touch { position: fixed; inset: 0; z-index: 20; pointer-events: none; touch-action: none; }
#touch.off { display: none; }

/* the floating stick — the bottom-left quarter, invisible until touched */
#tstick {
  position: fixed; left: 0; bottom: 0; width: 46%; height: 58%;
  pointer-events: auto; touch-action: none;
}
#tstick .ring, #tstick .knob {
  position: fixed; left: 0; top: 0; border-radius: 50%;
  opacity: 0; transition: opacity .16s ease;
}
#tstick.on .ring, #tstick.on .knob { opacity: 1; }
#tstick .ring {
  width: 116px; height: 116px; margin: -58px 0 0 -58px;
  border: 1px solid var(--line); background: rgba(6, 11, 13, .34);
}
#tstick .knob {
  width: 46px; height: 46px; margin: -23px 0 0 -23px;
  border: 1px solid rgba(232, 161, 58, .55); background: rgba(232, 161, 58, .16);
  backdrop-filter: blur(3px);
}

/* the verbs
 *
 * The cluster is held a good way IN from the corner — 66/70 rather than the
 * 16/20 it shipped with. Hard against the edge of the glass it is a thumb
 * reaching past the bezel for the one button it presses most, and on an iPad
 * held in two hands the bottom-right corner is where the hand already is. */
#tbtns {
  position: fixed;
  right: max(66px, calc(env(safe-area-inset-right) + 50px));
  bottom: max(70px, calc(env(safe-area-inset-bottom) + 50px));
  width: 190px; height: 200px; pointer-events: none;
}
.tb {
  position: absolute; pointer-events: auto; touch-action: none;
  display: grid; place-items: center; border-radius: 50%;
  font: inherit; font-size: 11px; letter-spacing: .14em; color: var(--ink);
  background: var(--panel); border: 1px solid var(--line);
  backdrop-filter: blur(8px);
  transition: background .1s ease, border-color .1s ease, color .1s ease;
}
.tb.hit { background: rgba(232, 161, 58, .22); border-color: var(--amber); color: var(--amber); }
.tb.jump { right: 0;    bottom: 0;    width: 96px; height: 96px; }
.tb.bark { right: 94px; bottom: 44px; width: 76px; height: 76px; font-size: 10px; }
.tb.use  { right: 10px; bottom: 106px; width: 80px; height: 80px; display: none; color: var(--amber); border-color: rgba(232,161,58,.45); }
.tb.use.on { display: grid; }
/* RUN is the only LATCHING button out here — it is a gear, not a verb, so it
 * stays lit while it is on rather than flashing on the press. */
.tb.run  { right: 100px; bottom: 128px; width: 64px; height: 64px; font-size: 10px; }
.tb.run.on { background: rgba(232, 161, 58, .22); border-color: var(--amber); color: var(--amber); }

/* the chapter-level verbs: menu, mute, camera mode */
#tsys {
  position: fixed; right: 14px; top: 104px;
  display: grid; gap: 6px; justify-items: end; pointer-events: none;
}
.tp {
  pointer-events: auto; touch-action: none; font: inherit; font-size: 9.5px; letter-spacing: .18em;
  color: var(--dim); background: var(--panel); border: 1px solid var(--line);
  backdrop-filter: blur(8px); padding: 9px 12px;
}
.tp.hit { color: var(--amber); border-color: rgba(232, 161, 58, .5); }

/* A phone is 390 px wide and both of these are authored `nowrap`, which on a
 * sentence-length hint runs straight off both edges. They sit above the
 * buttons rather than behind them. */
@media (max-width: 560px) {
  #toast, #prompt {
    white-space: normal; text-align: center;
    max-width: calc(100vw - 32px); line-height: 1.5;
  }
}
/* ...and on touch they move to the top of the frame outright. The bottom
 * third of a phone is the controls — a toast down there is either under a
 * thumb or under a button. */
.touch #prompt { top: 168px; bottom: auto; }   /* clear of the scrap panel */
.touch #toast  { top: 220px; bottom: auto; }

/* Landscape on a phone is ~370 px of height with the browser chrome in it —
 * everything has to come in, and the stick zone has to stop covering the
 * whole left side of the picture. */
@media (max-height: 460px) {
  #tstick { height: 74%; width: 40%; }
  /* The 50 px inset above is most of a landscape phone's height, so out here
   * it comes back to something the cluster still fits inside. */
  #tbtns  { width: 160px; height: 168px;
            right: max(30px, calc(env(safe-area-inset-right) + 22px));
            bottom: max(26px, calc(env(safe-area-inset-bottom) + 18px)); }
  .tb.jump { width: 78px; height: 78px; }
  .tb.bark { right: 78px; bottom: 38px; width: 64px; height: 64px; }
  .tb.use  { right: 8px; bottom: 86px; width: 66px; height: 66px; }
  .tb.run  { right: 84px; bottom: 108px; width: 54px; height: 54px; font-size: 9px; }
  #tsys { top: 92px; gap: 5px; }
  .touch #prompt { top: 96px; }
  .touch #toast  { top: 148px; }
}

/* On touch the cutscene hint is also the skip control, so it needs to be a
 * thing you can hit rather than a line of text. */
.skip.tapskip {
  pointer-events: auto; padding: 11px 15px;
  background: var(--panel); border: 1px solid var(--line);
  bottom: max(22px, env(safe-area-inset-bottom));
}
