:root {
  --bg: #070a16;
  --glass: rgba(14, 18, 38, 0.72);
  --glass-2: rgba(255, 255, 255, 0.06);
  --line: rgba(255, 255, 255, 0.12);
  --text: #eef1ff;
  --muted: #9aa3c7;
  --accent: #7cc4ff;
  --accent-2: #ffb86b;
  --radius: 18px;
  --gap: max(12px, env(safe-area-inset-left));
  --font: 'Fredoka', ui-rounded, 'SF Pro Rounded', system-ui, -apple-system, sans-serif;
}

* { box-sizing: border-box; }
/* The page does not scroll and does not zoom. It is fixed to the viewport so iOS cannot drag it,
   `touch-action: manipulation` drops the double-tap zoom, and `-webkit-text-size-adjust` stops
   Safari resizing the text on a rotate. viewport.js blocks the pinch, which no CSS reaches. */
html, body {
  position: fixed; inset: 0; height: 100%; width: 100%; margin: 0;
  overflow: hidden; overscroll-behavior: none;
  touch-action: manipulation;
  -webkit-text-size-adjust: 100%;
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}
#c {
  position: fixed; inset: 0; width: 100%; height: 100%; display: block;
  touch-action: none; outline: none;
}

/* ---------- sidebar
   One column: header (brand, music, collapse), body (create, this world, your worlds), footer (settings, help).
   The body is the only scroll region. */
#panel {
  position: fixed; top: max(12px, env(safe-area-inset-top)); left: var(--gap); bottom: max(12px, env(safe-area-inset-bottom));
  width: min(320px, calc(100vw - 24px));
  background: var(--glass);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
  z-index: 5;
  display: flex; flex-direction: column;
}
#panel.collapsed { bottom: auto; width: fit-content; max-width: min(440px, calc(100vw - 24px)); }
#panel.collapsed .body, #panel.collapsed footer { display: none; }

#panel header {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 12px 10px 16px; cursor: pointer; user-select: none; -webkit-user-select: none;
}
#panel h1 { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: 0.3px; white-space: nowrap; }
#panel h1 .logo { color: var(--accent-2); margin-right: 2px; }
.hworld {
  display: none; flex: 1; min-width: 0; color: var(--muted); font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hworld::before { content: '· '; }
#panel.collapsed .hworld { display: block; }
.hbtns { display: flex; gap: 6px; margin-left: auto; }
#toggle, #mute, .probe-icon {
  background: var(--glass-2); border: 1px solid var(--line); color: var(--text);
  width: 34px; height: 34px; border-radius: 10px; cursor: pointer; font-size: 16px;
}
#mute[aria-pressed="true"] { color: var(--muted); }
/* The probe in the header. It says the same thing as the text button in the card, and it stays
   in reach while the sidebar is folded away. */
.probe-icon { line-height: 1; }
.probe-icon[hidden] { display: none; }
.probe-icon:hover { border-color: var(--accent); }
.probe-icon[aria-pressed="true"] { border-color: var(--accent); background: rgba(124, 196, 255, 0.2); }

#panel .body { flex: 1; min-height: 0; overflow: auto; padding: 0 14px; overscroll-behavior: contain; }
.sec { padding: 4px 0 14px; }
.sec + .sec { border-top: 1px solid var(--line); padding-top: 12px; }
.sechead { display: flex; align-items: center; justify-content: space-between; margin: 0 2px 8px; }
#panel h2 {
  margin: 0; font-size: 12px; font-weight: 600; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--muted);
}

#panel footer { border-top: 1px solid var(--line); padding: 10px 14px max(10px, env(safe-area-inset-bottom)); }
.music { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 13px; }
.music input { flex: 1; min-width: 0; accent-color: var(--accent); cursor: pointer; }
.music input:disabled { opacity: 0.4; cursor: default; }
.help { margin: 8px 0 0; color: var(--muted); font-size: 11px; line-height: 1.4; opacity: 0.8; }
/* The about link. It is quiet on purpose: small, muted, and under the help line. */
.about-link {
  display: block; margin: 6px 0 0; padding: 0; background: none; border: 0;
  color: var(--muted); font: inherit; font-size: 11px; opacity: 0.6; cursor: pointer;
}
.about-link:hover, .about-link:focus-visible { opacity: 1; color: var(--accent); }

/* ---------- create */
#seed-form { display: flex; gap: 6px; }
#seed {
  flex: 1; min-width: 0;
  background: rgba(0, 0, 0, 0.35); border: 1px solid var(--line); color: var(--text);
  border-radius: 12px; padding: 10px 12px; font: inherit; font-size: 16px;
}
#seed:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(124, 196, 255, 0.2); }
button.go {
  background: linear-gradient(135deg, #7cc4ff, #6a8bff); color: #08122a; border: 0;
  border-radius: 12px; padding: 0 14px; font: inherit; font-weight: 600; cursor: pointer;
}
button.go:hover { filter: brightness(1.08); }
#dice {
  background: var(--glass-2); border: 1px solid var(--line); border-radius: 12px;
  width: 40px; cursor: pointer; font-size: 18px; padding: 0;
}
.sub { margin: 8px 2px 0; color: var(--muted); font-size: 13px; }

/* ---------- this world */
#info .iname { font-size: 20px; font-weight: 600; }
#info .itype { color: var(--accent); font-size: 12px; margin-bottom: 8px; letter-spacing: 0.4px; }
#info dl { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; margin: 0; font-size: 12px; }
#info dt { color: var(--muted); }
#info dd { margin: 0; }
#info .chips { display: flex; flex-wrap: wrap; gap: 4px; }
.chip {
  background: var(--glass-2); border: 1px solid var(--line); color: var(--text);
  border-radius: 999px; padding: 2px 8px; font: inherit; font-size: 11px; cursor: pointer; white-space: nowrap;
}
.chip:hover { border-color: var(--accent); color: var(--accent); }

/* ---------- your worlds */
#worlds { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; }
#worlds .empty { grid-column: 1 / -1; color: var(--muted); font-size: 13px; margin: 4px 2px; }
.world {
  position: relative; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: var(--glass-2); border: 1px solid var(--line); color: var(--text);
  border-radius: 14px; padding: 8px 6px 7px; cursor: pointer; font: inherit;
  transition: transform 0.15s ease, border-color 0.15s ease;
}
.world:hover { transform: translateY(-2px); border-color: rgba(255, 255, 255, 0.3); }
.world.active { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(124, 196, 255, 0.25); }
.world img { width: 56px; height: 56px; border-radius: 50%; background: #0b1024; object-fit: cover; }
.world .wname { font-size: 12px; font-weight: 600; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.world .wtype { font-size: 10px; color: var(--muted); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.world .del {
  position: absolute; top: 4px; right: 6px; font-style: normal; color: var(--muted);
  width: 18px; height: 18px; line-height: 18px; text-align: center; border-radius: 50%; font-size: 14px;
  opacity: 0; transition: opacity 0.15s;
}
.world:hover .del, .world:focus .del { opacity: 1; }
.world .del:hover { background: rgba(255, 90, 90, 0.35); color: #fff; }
@media (pointer: coarse) { .world .del { opacity: 0.7; } }

button.ghost {
  background: transparent; border: 1px solid var(--line); color: var(--muted);
  border-radius: 10px; padding: 5px 10px; font: inherit; font-size: 12px; cursor: pointer;
}
button.ghost:hover { color: var(--text); border-color: rgba(255, 255, 255, 0.3); }

/* ---------- the probe button and the dive overlay */
button.probe {
  display: block; width: 100%; margin-top: 10px; padding: 9px 12px;
  background: var(--glass-2); border: 1px solid var(--line); color: var(--text);
  border-radius: 12px; font: inherit; font-size: 13px; cursor: pointer;
}
button.probe:hover { border-color: var(--accent); color: var(--accent); }
button.probe[hidden] { display: none; }

/* The dive fades the screen to the atmosphere colour. The app sets the colour and the opacity.
   The label reports what the worker builds while the probe falls. */
#dive { position: fixed; inset: 0; z-index: 9; opacity: 0; pointer-events: none; display: grid; place-items: end center; }
#dive-label {
  margin: 0 0 12vh; padding: 6px 14px; border-radius: 12px;
  background: rgba(7, 10, 22, 0.28); color: #fff; font-size: 13px; letter-spacing: 0.02em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
#dive-label:empty { display: none; }

/* The aim message. It tells the reader to choose the ground the probe lands on. It floats over
   the scene and it takes no pointer event, because the reader taps the planet under it. */
#aim {
  position: fixed; top: 18px; left: 50%; transform: translateX(-50%); z-index: 9;
  margin: 0; padding: 7px 16px; border-radius: 12px;
  background: rgba(7, 10, 22, 0.55); border: 1px solid var(--line); color: #fff;
  font-size: 13px; letter-spacing: 0.02em; pointer-events: none;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
#aim[hidden] { display: none; }

/* ---------- the floating probe button
   It shows at the two ends of the zoom, where the zoom has nothing left to give and the reader
   who keeps pulling is asking to travel. It sits low and half lit, so it offers the journey
   without covering the world. visibility carries the fade out and takes the button out of the
   tab order with it. */
.floatbtn {
  position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%) translateY(6px); z-index: 9;
  margin: 0; padding: 10px 20px; border-radius: 999px; cursor: pointer;
  background: rgba(7, 10, 22, 0.5); border: 1px solid var(--line); color: #fff;
  font: inherit; font-size: 13px; letter-spacing: 0.02em;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
  opacity: 0; visibility: hidden;
  transition: opacity 0.28s, visibility 0.28s, transform 0.28s, background 0.15s;
}
.floatbtn.show { opacity: 0.72; visibility: visible; transform: translateX(-50%) translateY(0); }
.floatbtn.show:hover, .floatbtn.show:focus-visible { opacity: 1; background: rgba(7, 10, 22, 0.75); }
@media (prefers-reduced-motion: reduce) { .floatbtn { transition: opacity 0.28s, visibility 0.28s; } }

/* ---------- overlay */
#overlay {
  position: fixed; inset: 0; z-index: 10; display: grid; place-items: center;
  background: rgba(7, 10, 22, 0.55); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  opacity: 0; pointer-events: none; transition: opacity 0.25s;
}
#overlay.show { opacity: 1; pointer-events: auto; }
#overlay .box {
  width: 260px; text-align: center; padding: 22px 20px; border-radius: 20px;
  background: var(--glass); border: 1px solid var(--line); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
#overlay .orb {
  width: 54px; height: 54px; margin: 0 auto 14px; border-radius: 50%;
  background: conic-gradient(from 0deg, #7cc4ff, #6fbf5a, #ffb86b, #b783d0, #7cc4ff);
  animation: spin 1.6s linear infinite;
  box-shadow: 0 0 30px rgba(124, 196, 255, 0.45), inset -10px -8px 20px rgba(0, 0, 0, 0.45);
}
@keyframes spin { to { transform: rotate(360deg); } }
#overlay-label { font-size: 15px; margin-bottom: 12px; }
#overlay .track { height: 6px; border-radius: 6px; background: rgba(255, 255, 255, 0.1); overflow: hidden; }
#overlay-bar { height: 100%; width: 0; background: linear-gradient(90deg, #7cc4ff, #ffb86b); transition: width 0.2s; }

/* ---------- small screens: the sidebar docks at the bottom as a sheet */
@media (max-width: 600px) {
  /* The sidebar docks at the bottom here, where the floating buttons live. The buttons ride
     above the sheet instead of covering it, folded or open. app.js writes --panel-h. */
  .floatbtn { bottom: calc(var(--panel-h, 0px) + 12px); }
  #panel {
    top: auto; left: 0; right: 0; bottom: 0; width: 100%;
    max-height: 72vh; border-radius: var(--radius) var(--radius) 0 0; border-bottom: 0;
  }
  #panel.collapsed { bottom: 0; width: 100%; max-width: none; }
  #panel header { padding: 10px 12px 8px 16px; }
  #panel h1 { font-size: 18px; }
  #worlds { grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); }
  .world img { width: 44px; height: 44px; }
  #info dl { grid-template-columns: auto 1fr auto 1fr; }
  .help { display: none; }
}
@media (max-height: 460px) {
  #info dl { display: none; }
  .help { display: none; }
}

/* ---------- creature inspector */
#creature {
  position: fixed; inset: 0; z-index: 8; display: grid; place-items: center; padding: 12px;
  background: rgba(7, 10, 22, 0.45); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  opacity: 0; transition: opacity 0.25s;
}
#creature.show { opacity: 1; }
#creature[hidden] { display: none; }
.ccard {
  position: relative; display: grid; grid-template-columns: 320px 1fr; gap: 18px;
  width: min(760px, 100%); max-height: calc(100vh - 24px); overflow: auto;
  background: var(--glass); border: 1px solid var(--line); border-radius: 22px; padding: 18px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
}
.cclose {
  position: absolute; top: 10px; right: 10px; width: 32px; height: 32px; border-radius: 10px;
  background: var(--glass-2); border: 1px solid var(--line); color: var(--text); font-size: 18px; cursor: pointer; z-index: 1;
}
.cview { position: relative; width: 320px; height: 320px; border-radius: 16px; overflow: hidden;
  background: radial-gradient(circle at 50% 40%, rgba(255, 255, 255, 0.08), rgba(0, 0, 0, 0.35)); }
.cview canvas { width: 100%; height: 100%; display: block; }
/* The card holds one canvas per subject and shows one of them. `display: block` above outranks the
   display the browser gives [hidden], so the rule has to be written here. */
.cview canvas[hidden] { display: none; }
.cname { font-size: 22px; font-weight: 600; margin-top: 4px; }
.clatin { color: var(--accent); font-style: italic; font-size: 13px; margin-bottom: 10px; }
.ctags { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; margin: 0 0 10px; font-size: 12px; }
.ctags dt { color: var(--muted); }
.ctags dd { margin: 0; }
.cstory { font-size: 14px; line-height: 1.45; margin: 0 0 12px; color: #dfe4ff; }
.cnav { display: flex; gap: 8px; }
.cnav .ghost { padding: 7px 12px; font-size: 13px; }
@media (max-width: 720px) {
  .ccard { grid-template-columns: 1fr; gap: 12px; padding: 14px; }
  .cview { width: 100%; height: min(60vw, 300px); }
  .cname { font-size: 19px; }
  .cstory { font-size: 13px; }
}

/* ---------- about
   A native <dialog>. The browser gives the focus trap, the Escape key, and the top layer. */
#about {
  width: min(420px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); padding: 0;
  background: transparent; border: 0; color: var(--text); overflow: visible;
}
#about::backdrop { background: rgba(7, 10, 22, 0.55); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
#about[open] { animation: about-in 0.28s ease-out; }
@keyframes about-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } }
.about-card {
  position: relative; margin: 0; padding: 28px 26px 22px; text-align: center;
  max-height: calc(100dvh - 32px); overflow: auto;
  background: var(--glass); border: 1px solid var(--line); border-radius: 22px;
  backdrop-filter: blur(18px) saturate(1.4); -webkit-backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
}
.about-orb {
  width: 58px; height: 58px; margin: 0 auto 14px; border-radius: 50%;
  background: conic-gradient(from 0deg, #7cc4ff, #6fbf5a, #ffb86b, #b783d0, #7cc4ff);
  box-shadow: 0 0 34px rgba(124, 196, 255, 0.4), inset -10px -8px 20px rgba(0, 0, 0, 0.45);
  animation: spin 24s linear infinite;
}
@media (prefers-reduced-motion: reduce) { #about[open], .about-orb { animation: none; } }
#about h2 { margin: 0; font-size: 24px; font-weight: 600; letter-spacing: 0.3px; }
.about-card .about-kicker {
  margin: 4px 0 18px; color: var(--accent-2);
  font-size: 11px; letter-spacing: 1.4px; text-transform: uppercase;
}
.about-card p { margin: 0 0 12px; color: #dfe4ff; font-size: 14px; line-height: 1.55; }
.about-links {
  display: flex; justify-content: center; gap: 8px; flex-wrap: wrap;
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line);
}
.about-links a {
  color: var(--text); text-decoration: none; font-size: 13px;
  padding: 7px 14px; border-radius: 999px; border: 1px solid var(--line); background: var(--glass-2);
  transition: border-color 0.15s, color 0.15s;
}
.about-links a:hover, .about-links a:focus-visible { border-color: var(--accent); color: var(--accent); }

/* ---------- the probe overlay, issue 31
   The instrument of the probe over the ground: the air, the height, the hour of the star, and the
   uplink that says why the probe stops where it does. It takes no pointer event, because every
   gesture on the screen belongs to the ground under it.

   The frame starts right of the sidebar. --panel-w is the width the sidebar holds, and app.js
   writes it beside --panel-h; on a phone the sidebar docks at the bottom instead, so there the
   frame keeps the full width and lifts its foot over the sheet. */
#probe-hud {
  position: fixed; inset: 0; z-index: 4; pointer-events: none;
  --hud-in: 22px;
  --hud-left: calc(var(--gap) + var(--panel-w, 320px) + var(--hud-in));
  --hud-top: var(--hud-in);
  --hud-bottom: var(--hud-in);
  font-size: 11px; letter-spacing: 0.12em;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
}
#probe-hud[hidden] { display: none; }
#probe-noise { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* The two washes that hold the readings against a bright sky. They belong to the screen and not to
   the frame: a wash that starts where the frame starts leaves a band of clear sky over it and shows
   its own three straight edges, which reads as a panel laid on the picture. These run from the top
   and the bottom edges of the screen, the whole width, and every stop is a step smaller than the one
   over it, so the dark comes on the way it does on a lens and no edge of it can be found. */
#probe-hud::before, #probe-hud::after {
  content: ''; position: absolute; left: 0; right: 0; pointer-events: none;
  /* under the noise and under every reading: the wash carries the readings, it never covers one */
  z-index: -1;
}
#probe-hud::before {
  top: 0; height: calc(var(--hud-top) + 104px);
  background: linear-gradient(180deg,
    rgba(7, 10, 22, 0.5) 0%, rgba(7, 10, 22, 0.42) 22%, rgba(7, 10, 22, 0.28) 45%,
    rgba(7, 10, 22, 0.13) 68%, rgba(7, 10, 22, 0.04) 86%, rgba(7, 10, 22, 0) 100%);
}
#probe-hud::after {
  bottom: 0; height: calc(var(--hud-bottom) + 118px);
  background: linear-gradient(0deg,
    rgba(7, 10, 22, 0.42) 0%, rgba(7, 10, 22, 0.34) 22%, rgba(7, 10, 22, 0.22) 45%,
    rgba(7, 10, 22, 0.1) 68%, rgba(7, 10, 22, 0.03) 86%, rgba(7, 10, 22, 0) 100%);
}

/* The bracket. It is a thin line with two corners, so the frame reads as an instrument and the
   world keeps the middle of the screen. */
.hud-frame {
  position: absolute; top: var(--hud-top); right: var(--hud-in);
  bottom: var(--hud-bottom); left: var(--hud-left);
  border: 1px solid rgba(124, 196, 255, 0.18); border-radius: 6px;
}
.hud-frame::before, .hud-frame::after {
  content: ''; position: absolute; width: 26px; height: 26px;
  border: 2px solid var(--accent); opacity: 0.7;
}
.hud-frame::before { top: -1px; left: -1px; border-right: 0; border-bottom: 0; }
.hud-frame::after { right: -1px; bottom: -1px; border-left: 0; border-top: 0; }

/* The overlay stands over a lit sky as often as over a dark one, so the labels carry their own
   contrast: a lighter grey than the sidebar uses, and a shadow under every line. */
#probe-hud .k {
  display: block; color: rgba(226, 232, 255, 0.72); font-size: 9px;
  letter-spacing: 0.2em; text-transform: uppercase;
}
#probe-hud b {
  font-weight: 500; font-size: 15px; letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}

/* the strip along the top of the frame: the air, the hour, and the link */
.hud-bar {
  position: absolute; top: calc(var(--hud-top) + 10px); left: calc(var(--hud-left) + 16px);
  right: calc(var(--hud-in) + 16px); display: flex; gap: 26px; align-items: flex-start;
}
.hud-bar .hud-right { margin-left: auto; text-align: right; }

/* the altitude ladder, on the inside of the right edge */
.hud-ladder {
  position: absolute; right: calc(var(--hud-in) + 18px); bottom: calc(var(--hud-bottom) + 90px);
  width: 92px; height: 190px; text-align: right;
}
.hud-ladder .rung {
  position: absolute; right: 0; width: 14px; height: 1px; background: rgba(255, 255, 255, 0.22);
}
.hud-ladder .rung:nth-child(1) { top: 0; width: 22px; }
.hud-ladder .rung:nth-child(2) { top: 25%; }
.hud-ladder .rung:nth-child(3) { top: 50%; width: 22px; }
.hud-ladder .rung:nth-child(4) { top: 75%; }
.hud-ladder .rung:nth-child(5) { top: 100%; width: 22px; }
.hud-ladder b {
  position: absolute; right: 28px; bottom: 0; transform: translateY(50%);
  color: var(--accent); text-shadow: 0 0 10px rgba(124, 196, 255, 0.45);
  transition: bottom 0.12s linear;
}
.hud-ladder .k { position: absolute; right: 0; bottom: -18px; }

/* the uplink block, inside the bottom left corner of the frame, clear of the floating buttons */
.hud-link {
  position: absolute; left: calc(var(--hud-left) + 16px); bottom: calc(var(--hud-bottom) + 14px);
}
.hud-bars { display: flex; gap: 4px; align-items: flex-end; height: 19px; margin-bottom: 6px; }
.hud-bars i { display: block; width: 6px; border-radius: 1px; background: rgba(255, 255, 255, 0.16); }
.hud-bars i.lit { background: var(--accent); }
.hud-bars i.lit.hot { background: #ff7a6b; }
#hud-link.weak { color: #ff7a6b; }

/* the one line the reader gets when the relay runs out. It says what the world does, not what the
   reader did wrong. */
.hud-warn {
  position: absolute; left: 50%; bottom: calc(var(--hud-bottom) + 84px); transform: translateX(-50%);
  margin: 0; padding: 7px 16px; white-space: nowrap;
  border: 1px solid #ff7a6b; border-radius: 999px; background: rgba(7, 10, 22, 0.55);
  color: #ff7a6b; font-size: 11px; letter-spacing: 0.1em;
  opacity: 0; transition: opacity 0.3s;
}
.hud-warn.show { opacity: 1; }

/* A folded sidebar on a wide screen is a strip along the top, and it holds nothing under it. The
   frame then takes the whole width and starts under the strip, so the reader keeps the view.
   app.js writes the class on the root element beside the two panel variables. */
@media (min-width: 601px) {
  :root.panel-folded #probe-hud {
    --hud-left: var(--gap);
    --hud-top: calc(var(--gap) + var(--panel-h, 56px) + 14px);
  }
}
@media (max-width: 600px) {
  /* the sidebar docks at the bottom here, so the frame takes the full width and stands over it */
  #probe-hud {
    --hud-in: 12px;
    --hud-left: var(--hud-in);
    --hud-bottom: calc(var(--panel-h, 0px) + 12px);
  }
  .hud-ladder { height: 150px; bottom: calc(var(--hud-bottom) + 74px); }
  .hud-warn { white-space: normal; text-align: center; max-width: calc(100vw - 48px); }
}
@media (prefers-reduced-motion: reduce) {
  .hud-ladder b, .hud-warn { transition: none; }
}
