/* VANTA BLACK — shared 3D world chrome.

   Only what NEXUS's stylesheet does not already provide. The world HUD reuses
   .hud, .hud-top, .hud-brand, .hud-prompt, .hud-chip, .hud-perf, .joystick,
   .mbtn and .look-area from nexus.css, so this file stays small on purpose. */

/* The world mounts inside the platform's game stage. `isolation` keeps the
   world HUD's z-indexes contained so the platform's pause and results overlays
   (z-index 5 in vanta.css) always win. */
.world-mount { position: absolute; inset: 0; z-index: 1; isolation: isolate; }
.world-mount canvas { display: block; width: 100%; height: 100%; }
.world-mount.finished { pointer-events: none; }

.world-root { position: fixed; inset: 0; overflow: hidden; background: #000; }
.world-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

/* ---------------- loading ---------------- */
.world-loading {
  position: absolute; inset: 0; z-index: 40;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  background: radial-gradient(circle at 50% 40%, #17132a 0%, #060509 70%);
  transition: opacity 0.6s ease;
}
.world-loading.done { opacity: 0; pointer-events: none; }
.world-loading h2 { font-size: 26px; letter-spacing: 0.3em; margin-left: 0.3em; text-align: center; padding: 0 16px; }
.world-loading .wl-status { color: var(--text-dim); font-size: 13.5px; }
.world-loading .wl-bar { width: min(300px, 70vw); height: 4px; border-radius: 2px; background: var(--bg3); overflow: hidden; }
.world-loading .wl-bar i { display: block; height: 100%; width: 0; background: var(--grad); transition: width 0.4s; }
.world-loading .wl-tip { color: var(--text-faint); font-size: 12.5px; margin-top: 12px; font-style: italic; max-width: 34ch; text-align: center; }

/* ---------------- objectives ---------------- */
.w3-tasks {
  position: absolute; left: 16px; top: 84px;
  display: flex; flex-direction: column; gap: 6px;
  width: min(300px, 60vw); max-width: calc(100vw - 32px);
}
.w3-tasks-toggle {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: rgba(8, 7, 12, 0.62); border: 1px solid var(--line);
  border-radius: 9px; padding: 6px 11px; font: inherit; font-size: 12px;
  color: var(--dim, #9a94a8); text-align: left; cursor: pointer;
  letter-spacing: 0.08em; text-transform: uppercase;
  backdrop-filter: blur(6px);
}
.w3-tasks-toggle:hover, .w3-tasks-toggle:focus-visible { border-color: var(--line-strong); color: var(--text); }
.w3-tasks-title { flex: none; }
.w3-tasks-now {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-transform: none; letter-spacing: 0; color: var(--text); font-size: 13px;
}
.w3-tasks-count { flex: none; color: var(--lav); font-variant-numeric: tabular-nums; }
.w3-tasks-chev { flex: none; color: var(--lav); font-size: 10px; }
.w3-tasks[data-collapsed="false"] .w3-tasks-title { flex: 1; }
.w3-tasks.updated .w3-tasks-toggle { border-color: var(--lav); color: var(--text); animation: w3pulse 1s ease-in-out 2; }
.reduced-motion .w3-tasks.updated .w3-tasks-toggle { animation: none; }

.w3-objectives {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-direction: column; gap: 6px;
  opacity: 1; transition: opacity 0.16s ease;
}
.w3-tasks[data-collapsed="true"] .w3-objectives { display: none; opacity: 0; }
.w3-objectives li {
  display: flex; align-items: center; gap: 8px;
  background: rgba(8, 7, 12, 0.62); border: 1px solid var(--line);
  border-radius: 9px; padding: 6px 11px; font-size: 13px;
  backdrop-filter: blur(6px);
}
.w3-objectives li.done { opacity: 0.55; }
.w3-objectives li.done .w3-label { text-decoration: line-through; }
.w3-objectives li.bonus { border-style: dashed; }
.w3-tick { color: var(--lav); font-size: 12px; width: 12px; text-align: center; }
.w3-objectives li.done .w3-tick { color: var(--ok, #7fd8a0); }
.w3-label { flex: 1; color: var(--text); }
.w3-count { color: var(--lav); font-variant-numeric: tabular-nums; font-family: var(--font-display); }

/* ---------------- vitals ---------------- */
.w3-vitals { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.w3-timer {
  font-family: var(--font-display); font-size: 21px; font-variant-numeric: tabular-nums;
  color: var(--text); text-shadow: 0 2px 12px rgba(0, 0, 0, 0.7); letter-spacing: 0.06em;
}
.w3-timer.urgent { color: var(--danger, #d8607b); animation: w3pulse 1s ease-in-out infinite; }
.w3-health {
  width: 168px; height: 7px; border-radius: 4px; overflow: hidden;
  background: rgba(8, 7, 12, 0.75); border: 1px solid var(--line);
}
.w3-health i {
  display: block; height: 100%;
  background: linear-gradient(90deg, #d8607b, #e6cf8f);
  transition: width 0.25s ease;
}

/* ---------------- banner ---------------- */
.w3-banner {
  position: absolute; left: 50%; top: 26%; transform: translate(-50%, -8px);
  padding: 10px 20px; border-radius: 11px; font-size: 15px; text-align: center;
  background: rgba(8, 7, 12, 0.82); border: 1px solid var(--line-strong);
  color: var(--text); opacity: 0; transition: opacity 0.25s ease, transform 0.25s ease;
  max-width: min(440px, 84vw); pointer-events: none;
}
.w3-banner.show { opacity: 1; transform: translate(-50%, 0); }
.w3-banner.k-warn { border-color: var(--gold, #e6cf8f); color: var(--gold, #e6cf8f); }
.w3-banner.k-danger { border-color: var(--danger, #d8607b); color: var(--danger, #d8607b); }
.w3-banner.k-good { border-color: var(--lav); color: var(--lav); }

@keyframes w3pulse { 50% { opacity: 0.55; } }

.reduced-motion .w3-timer.urgent { animation: none; }

@media (max-width: 720px) {
  .w3-tasks { top: 74px; font-size: 12px; width: min(260px, 62vw); }
  /* On a phone the collapsed bar is nearly all there is, so the current task
     gets the room the tally was using. Expanded still shows every count. */
  .w3-tasks[data-collapsed="true"] .w3-tasks-count { display: none; }
  .w3-health { width: 120px; }
}

/* ==========================================================================
   Story-world chrome — inventory, subtitles, dialogue, cutscenes, the VC
   vendor, party status and party decisions.

   Everything here is used by src/world3d/{inventory,cinematics,shop,coop}.js,
   so a world gets it by importing those and never by shipping its own CSS.
   Two rules run through all of it: nothing may sit where the subtitle bar
   sits, and everything stays legible over a black corridor and over a white
   flash, because a horror world is both within the same second.
   ========================================================================== */

/* ---------------- hidden during cinematics ---------------- */
.world-hud.cinematic .w3-tasks,
.world-hud.cinematic .w3-vitals,
.world-hud.cinematic .hud-prompt,
.world-hud.cinematic .hud-top-right,
.world-hud.cinematic .mobile-controls,
.world-hud.cinematic .w3-party { opacity: 0; pointer-events: none; transition: opacity 0.35s ease; }
.world-hud .w3-tasks, .world-hud .w3-vitals, .world-hud .hud-top-right { transition: opacity 0.35s ease; }

/* ---------------- subtitles ---------------- */
.w3-subs {
  position: absolute; left: 50%; bottom: 8.5%; transform: translateX(-50%);
  z-index: 24; max-width: min(760px, 88vw); text-align: center;
  padding: 10px 20px; border-radius: 10px; pointer-events: none;
  background: rgba(4, 4, 7, 0.82); border: 1px solid rgba(255, 255, 255, 0.09);
  font-size: calc(17px * var(--sub-scale, 1)); line-height: 1.45;
  /* The shadow is what keeps a caption readable over a white flash, where a
     translucent panel alone would vanish. */
  text-shadow: 0 1px 3px #000, 0 0 14px rgba(0, 0, 0, 0.9);
}
.w3-subs b { display: block; font-size: 0.72em; letter-spacing: 0.19em; color: var(--lav); margin-bottom: 3px; }
.w3-subs span { color: #f2f0f7; }
.w3-subs.t-warn b { color: var(--gold, #e6cf8f); }
.w3-subs.t-threat b { color: var(--danger, #d8607b); }
.w3-subs.t-threat span { color: #f0d8de; }
.w3-subs.t-far { opacity: 0.78; font-style: italic; }

/* ---------------- dialogue ---------------- */
.w3-dialogue { position: absolute; inset: 0; z-index: 26; display: flex; align-items: flex-end; justify-content: center; }
.w3-dlg-panel {
  width: min(680px, 92vw); margin-bottom: 5vh; padding: 16px 20px 13px;
  background: linear-gradient(180deg, rgba(11, 10, 18, 0.95), rgba(6, 5, 10, 0.97));
  border: 1px solid var(--line-strong); border-radius: 14px;
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.65); cursor: pointer;
}
.w3-dlg-who { display: block; font-size: 12px; letter-spacing: 0.2em; color: var(--lav); margin-bottom: 6px; }
.w3-dlg-text { margin: 0 0 12px; font-size: 16px; line-height: 1.5; color: #eeebf5; min-height: 3em; }
.w3-dlg-choices { display: flex; flex-direction: column; gap: 6px; }
.w3-dlg-choices .btn { justify-content: flex-start; text-align: left; width: 100%; }
.w3-dlg-choices .btn i { font-style: normal; color: var(--lav); margin-right: 9px; opacity: 0.85; }
.w3-dlg-hint { margin: 10px 0 0; font-size: 11.5px; color: var(--text-faint); letter-spacing: 0.05em; }
/* The dialogue panel owns the bottom of the screen while it is open. That is
   enforced in JS (Subtitles.setMuted), not with a sibling selector: the
   subtitle bar is created before the panel, so `~` would never match. */

/* ---------------- cutscenes ---------------- */
.w3-cine { position: absolute; inset: 0; z-index: 22; pointer-events: none; }
.w3-cine-bar { position: absolute; left: 0; right: 0; height: 0; background: #000; transition: height 0.5s ease; }
.w3-cine-bar.top { top: 0; }
.w3-cine-bar.bottom { bottom: 0; }
.w3-cine.letterbox .w3-cine-bar { height: 9vh; }
.w3-cine-skip {
  position: absolute; right: 18px; bottom: calc(9vh + 14px); text-align: right;
  font-size: 11.5px; letter-spacing: 0.14em; color: rgba(240, 238, 247, 0.62);
}
.w3-cine-skip span { display: block; color: var(--lav); font-variant-numeric: tabular-nums; }
.w3-cine-flash { position: absolute; inset: 0; opacity: 0; }
.w3-cine-flash.fx-flash { animation: w3flash 0.5s ease-out; background: #fff; }
.w3-cine-flash.fx-static { animation: w3static 0.7s steps(6) 2; background: rgba(220, 226, 240, 0.5); }
.w3-cine-flash.fx-shake { animation: none; }
.w3-cine.shaking { animation: w3shake 0.5s ease-in-out; }
@keyframes w3flash { 0% { opacity: 0.9; } 100% { opacity: 0; } }
@keyframes w3static { 0%, 100% { opacity: 0; } 20% { opacity: 0.34; } 40% { opacity: 0.06; } 60% { opacity: 0.28; } 80% { opacity: 0.1; } }
@keyframes w3shake { 0%, 100% { transform: translate(0, 0); } 25% { transform: translate(-5px, 3px); } 50% { transform: translate(4px, -3px); } 75% { transform: translate(-3px, -2px); } }
.reduced-motion .w3-cine.shaking { animation: none; }

/* ---------------- inventory ---------------- */
.w3-inv { position: absolute; inset: 0; z-index: 30; background: rgba(3, 3, 6, 0.68); display: flex; align-items: center; justify-content: center; }
.w3-inv-panel {
  width: min(720px, 94vw); max-height: 82vh; overflow: auto;
  background: linear-gradient(180deg, #0f0d1a, #08070d);
  border: 1px solid var(--line-strong); border-radius: 16px; padding: 18px 20px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.7);
}
.w3-inv-panel header { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.w3-inv-panel header > div { flex: 1; }
.w3-inv-panel header b { display: block; letter-spacing: 0.22em; font-size: 13px; }
.w3-inv-panel header span { display: block; color: var(--text-faint); font-size: 11.5px; margin-top: 3px; }
.w3-inv-close, .w3-shop-close {
  background: none; border: 1px solid var(--line); color: var(--text-dim);
  border-radius: 8px; width: 30px; height: 30px; cursor: pointer; font-size: 14px;
}
.w3-inv-close:hover, .w3-shop-close:hover { color: var(--text); border-color: var(--line-strong); }
.w3-inv-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; }
.w3-slot {
  position: relative; aspect-ratio: 1; border-radius: 11px; cursor: pointer;
  background: rgba(255, 255, 255, 0.028); border: 1px solid var(--line);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  padding: 6px; color: var(--text-dim); font: inherit; text-align: center;
}
.w3-slot.empty { cursor: default; opacity: 0.35; }
.w3-slot:not(.empty):hover { border-color: var(--line-strong); background: rgba(255, 255, 255, 0.055); }
.w3-slot.sel { border-color: var(--lav); box-shadow: inset 0 0 0 1px var(--lav); }
.w3-slot.cool { opacity: 0.62; }
.w3-slot-icon { font-size: 24px; color: var(--item, #9fe8f5); line-height: 1; text-shadow: 0 0 16px currentColor; }
.w3-slot-name { font-size: 10.5px; line-height: 1.25; color: var(--text-dim); }
.w3-slot-qty { position: absolute; right: 6px; bottom: 5px; font-size: 11px; color: var(--text); font-variant-numeric: tabular-nums; }
.w3-slot-cool { position: absolute; left: 6px; bottom: 5px; font-size: 10px; font-style: normal; color: var(--gold, #e6cf8f); }
.w3-inv-detail { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 12px; min-height: 96px; }
.w3-inv-detail h4 { margin: 0 0 3px; font-size: 15px; }
.w3-inv-kind { margin: 0 0 7px; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--lav); }
.w3-inv-detail p { margin: 0 0 10px; font-size: 13.5px; color: var(--text-dim); line-height: 1.5; }
.w3-inv-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.w3-inv-empty { color: var(--text-faint); font-style: italic; }

/* ---------------- VC vendor ---------------- */
.w3-shop { position: absolute; inset: 0; z-index: 30; background: rgba(3, 3, 6, 0.7); display: flex; align-items: center; justify-content: center; }
.w3-shop-panel {
  width: min(640px, 94vw); max-height: 84vh; overflow: auto;
  background: linear-gradient(180deg, #120e14, #08060a);
  border: 1px solid var(--line-strong); border-radius: 16px; padding: 18px 20px;
}
.w3-shop-panel header { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.w3-shop-panel header > div:first-child { flex: 1; }
.w3-shop-panel header b { display: block; letter-spacing: 0.2em; font-size: 13px; }
.w3-shop-panel header span { display: block; color: var(--text-faint); font-size: 11.5px; margin-top: 3px; }
.w3-shop-vc { font-family: var(--font-display); font-size: 15px; color: var(--gold, #e6cf8f); white-space: nowrap; }
.w3-shop-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.w3-shop-list li {
  display: flex; align-items: center; gap: 12px; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: 11px; background: rgba(255, 255, 255, 0.024);
}
.w3-shop-list li > div { flex: 1; }
.w3-shop-list b { font-size: 14px; }
.w3-shop-list p { margin: 3px 0 4px; font-size: 12.5px; color: var(--text-dim); line-height: 1.45; }
.w3-shop-eff { font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--lav); }
.w3-shop-status { min-height: 1.3em; margin: 12px 0 0; font-size: 13px; color: var(--text-dim); }
.w3-shop-status.good { color: var(--ok, #7fd8a0); }
.w3-shop-status.warn { color: var(--gold, #e6cf8f); }
.w3-shop-fine { margin: 8px 0 0; font-size: 11px; color: var(--text-faint); line-height: 1.5; }

/* ---------------- party ---------------- */
.w3-party { position: absolute; right: 16px; top: 84px; display: flex; flex-direction: column; gap: 5px; z-index: 12; }
.w3-mate {
  display: flex; align-items: center; gap: 8px; padding: 5px 10px; font-size: 12px;
  background: rgba(8, 7, 12, 0.62); border: 1px solid var(--line); border-radius: 9px;
  backdrop-filter: blur(6px);
}
.w3-mate i { width: 7px; height: 7px; border-radius: 50%; background: var(--ok, #7fd8a0); }
.w3-mate.down i { background: var(--danger, #d8607b); }
.w3-mate.down { border-color: var(--danger, #d8607b); }
.w3-mate b { flex: 1; font-weight: 500; color: var(--text); }
.w3-mate span { color: var(--text-faint); font-variant-numeric: tabular-nums; }

/* ---------------- party decision ---------------- */
.w3-vote { position: absolute; inset: 0; z-index: 28; display: flex; align-items: center; justify-content: center; pointer-events: none; }
.w3-vote-panel {
  pointer-events: auto; width: min(560px, 92vw); padding: 20px 22px;
  background: linear-gradient(180deg, rgba(14, 10, 18, 0.96), rgba(7, 5, 10, 0.98));
  border: 1px solid var(--line-strong); border-radius: 15px; text-align: center;
  box-shadow: 0 26px 70px rgba(0, 0, 0, 0.7);
}
.w3-vote-panel h3 { margin: 0 0 5px; font-size: 17px; letter-spacing: 0.05em; }
.w3-vote-timer { margin: 0 0 15px; font-size: 12px; color: var(--text-faint); letter-spacing: 0.12em; }
.w3-vote-opts { display: flex; flex-direction: column; gap: 8px; }
.w3-vote-opts .btn { justify-content: space-between; width: 100%; text-align: left; }
.w3-vote-opts .btn.mine { border-color: var(--lav); }
.w3-vote-opts .btn em { font-style: normal; color: var(--lav); font-variant-numeric: tabular-nums; }
.w3-vote-note { margin: 13px 0 0; font-size: 11.5px; color: var(--text-faint); line-height: 1.5; }

/* ---------------- NEXUS portal facts ---------------- */
.portal-facts { list-style: none; margin: 12px 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px; }
.portal-facts li { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; border-bottom: 1px solid var(--line); padding-bottom: 4px; }
.portal-facts b { color: var(--text-faint); font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; font-size: 11px; }
.portal-facts span { color: var(--text); text-transform: capitalize; }

@media (max-width: 720px) {
  .w3-party { top: 74px; right: 10px; }
  .w3-subs { font-size: calc(15px * var(--sub-scale, 1)); bottom: 14%; max-width: 92vw; }
  .w3-inv-grid { grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); }
  .portal-facts { grid-template-columns: 1fr; }
}

/* ═══════════════ CHANNEL ZERO — field kit HUD ═══════════════
   World-specific, but it lives here with the rest of the 3D world chrome so
   there is one file to read for "what does a world draw on top of the canvas".
   Everything below is prefixed .cz- and is not referenced by any other world. */

/* ---------------- hotbar ---------------- */
.cz-hotbar {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%);
  display: flex; gap: 8px; padding: 8px; z-index: 6;
  background: rgba(8, 7, 12, 0.66); border: 1px solid var(--line);
  border-radius: var(--r-lg, 16px); backdrop-filter: blur(9px);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
  transition: opacity var(--fast, 140ms) ease;
}
.cz-hotbar.hidden { opacity: 0; pointer-events: none; }
.cz-hotbar .cz-slot {
  position: relative; width: 66px; height: 66px; padding: 0; margin: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  background: rgba(20, 19, 28, 0.82); border: 1px solid var(--line);
  border-radius: var(--r, 10px); color: var(--text-2, #a6a6b4);
  font: inherit; cursor: pointer; overflow: hidden;
  transition: border-color var(--fast, 140ms) ease, transform var(--fast, 140ms) ease, background var(--fast, 140ms) ease;
}
.cz-hotbar .cz-slot.empty { cursor: default; background: rgba(14, 13, 20, 0.5); border-style: dashed; }
.cz-hotbar .cz-slot:hover:not(.empty) { border-color: var(--line-strong, #33333f); transform: translateY(-2px); }
.cz-hotbar .cz-slot:focus-visible { outline: 2px solid var(--ice, #9fe8f5); outline-offset: 2px; }
.cz-hotbar .cz-slot.sel {
  border-color: var(--ice, #9fe8f5); background: rgba(159, 232, 245, 0.1);
  box-shadow: inset 0 0 0 1px rgba(159, 232, 245, 0.28);
}
.cz-hotbar .cz-slot.cool { opacity: 0.55; }
.cz-hotbar .cz-slot > b {
  position: absolute; top: 3px; left: 5px; font-size: 10px; font-weight: 600;
  color: var(--text-3, #6e6e7c); font-variant-numeric: tabular-nums;
}
.cz-hotbar .cz-slot img { width: 30px; height: 30px; object-fit: contain; image-rendering: auto; }
.cz-hotbar .cz-glyph { font-size: 21px; line-height: 1; color: var(--item, #9fe8f5); }
.cz-slot-name {
  max-width: 60px; font-size: 8.5px; letter-spacing: 0.05em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-3, #6e6e7c);
}
.cz-hotbar .cz-slot.sel .cz-slot-name { color: var(--text, #edeae4); }
.cz-qty {
  position: absolute; right: 4px; top: 3px; font-size: 11px; font-style: normal;
  font-weight: 700; color: var(--gold, #efdca3); font-variant-numeric: tabular-nums;
}
.cz-slot-charge {
  position: absolute; left: 6px; right: 6px; bottom: 4px; height: 3px;
  border-radius: 2px; background: rgba(255, 255, 255, 0.12); overflow: hidden;
}
.cz-slot-charge i { display: block; height: 100%; background: var(--gold, #efdca3); transition: width 0.3s linear; }
.cz-slot-cool {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(6, 5, 10, 0.62); font-size: 13px; color: var(--text, #edeae4);
  font-variant-numeric: tabular-nums;
}

/* ---------------- battery ---------------- */
.cz-battery {
  position: absolute; left: 14px; bottom: 16px; z-index: 6;
  display: grid; grid-template-columns: auto auto; grid-template-rows: auto auto;
  gap: 3px 9px; align-items: center; padding: 9px 13px 8px;
  background: rgba(8, 7, 12, 0.66); border: 1px solid var(--line);
  border-radius: var(--r, 10px); backdrop-filter: blur(9px);
}
.cz-batt-icon { display: flex; align-items: center; grid-row: span 2; }
.cz-batt-cell {
  display: block; width: 30px; height: 15px; padding: 2px;
  border: 1.5px solid var(--text-2, #a6a6b4); border-radius: 3px;
}
.cz-batt-cell i { display: block; height: 100%; background: var(--text-2, #a6a6b4); transition: width 0.4s linear; }
.cz-batt-nub { width: 3px; height: 7px; border-radius: 0 2px 2px 0; background: var(--text-2, #a6a6b4); }
.cz-batt-read { display: flex; align-items: baseline; gap: 7px; grid-column: 2; }
.cz-batt-pct {
  font-family: var(--font-display); font-size: 17px; font-variant-numeric: tabular-nums;
  color: var(--text, #edeae4); letter-spacing: 0.03em;
}
.cz-batt-state { font-size: 9.5px; letter-spacing: 0.16em; color: var(--text-3, #6e6e7c); }
.cz-batt-segs { grid-column: 2; display: flex; gap: 2px; }
.cz-batt-segs i { width: 7px; height: 3px; border-radius: 1px; background: rgba(255, 255, 255, 0.1); }
.cz-batt-segs i.on { background: var(--text-2, #a6a6b4); }

.cz-battery.lit .cz-batt-state { color: var(--gold, #efdca3); }
.cz-battery.s-low .cz-batt-cell,
.cz-battery.s-low .cz-batt-nub { border-color: var(--warn, #e9b96b); background-color: var(--warn, #e9b96b); }
.cz-battery.s-low .cz-batt-cell { background: none; }
.cz-battery.s-low .cz-batt-cell i,
.cz-battery.s-low .cz-batt-segs i.on { background: var(--warn, #e9b96b); }
.cz-battery.s-low .cz-batt-state,
.cz-battery.s-low .cz-batt-pct { color: var(--warn, #e9b96b); }
.cz-battery.s-critical { border-color: var(--danger, #f07a7a); }
.cz-battery.s-critical .cz-batt-cell { border-color: var(--danger, #f07a7a); }
.cz-battery.s-critical .cz-batt-nub,
.cz-battery.s-critical .cz-batt-cell i,
.cz-battery.s-critical .cz-batt-segs i.on { background: var(--danger, #f07a7a); }
.cz-battery.s-critical .cz-batt-state,
.cz-battery.s-critical .cz-batt-pct { color: var(--danger, #f07a7a); }
/* A slow 1.4s pulse, well under any photosensitivity threshold, and dropped
   entirely for reduced motion. */
.cz-battery.s-critical.lit { animation: czBatt 1.4s ease-in-out infinite; }
.cz-battery.s-empty { border-color: var(--line); opacity: 0.8; }
.cz-battery.s-empty .cz-batt-pct,
.cz-battery.s-empty .cz-batt-state { color: var(--text-3, #6e6e7c); }
@keyframes czBatt { 0%, 100% { opacity: 1; } 50% { opacity: 0.62; } }
@media (prefers-reduced-motion: reduce) { .cz-battery.s-critical.lit { animation: none; } }

/* ---------------- pickups ---------------- */
.cz-pickups {
  position: absolute; left: 50%; bottom: 104px; transform: translateX(-50%);
  display: flex; flex-direction: column-reverse; align-items: center; gap: 5px;
  z-index: 6; pointer-events: none;
}
.cz-pickup {
  display: flex; align-items: center; gap: 8px; padding: 6px 13px;
  background: rgba(8, 7, 12, 0.8); border: 1px solid var(--line-strong, #33333f);
  border-radius: 999px; font-size: 12.5px; color: var(--text, #edeae4);
  opacity: 0; transform: translateY(8px);
  transition: opacity 0.22s ease, transform 0.22s ease;
  white-space: nowrap;
}
.cz-pickup.in { opacity: 1; transform: none; }
.cz-pickup img { width: 18px; height: 18px; object-fit: contain; }
.cz-pickup-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ice, #9fe8f5); }
.cz-pickup b { color: var(--gold, #efdca3); font-variant-numeric: tabular-nums; }
.cz-pickup.k-good { border-color: rgba(143, 224, 168, 0.4); }
.cz-pickup.k-warn { border-color: rgba(233, 185, 107, 0.5); color: var(--warn, #e9b96b); }

/* ---------------- camera mode chip ---------------- */
.cz-viewchip {
  position: absolute; left: 50%; top: 84px; transform: translateX(-50%);
  padding: 5px 13px; z-index: 6; pointer-events: none;
  background: rgba(8, 7, 12, 0.72); border: 1px solid var(--line);
  border-radius: 999px; font-size: 10px; letter-spacing: 0.2em;
  color: var(--text-2, #a6a6b4); opacity: 0; transition: opacity 0.22s ease;
}
.cz-viewchip.in { opacity: 1; }

/* The hotbar and the battery are gameplay chrome: a cutscene takes them too. */
.world-hud.cinematic ~ .cz-hotbar,
.world-hud.cinematic ~ .cz-battery,
.world-hud.cinematic ~ .cz-pickups { opacity: 0; pointer-events: none; }

@media (max-width: 720px) {
  .cz-hotbar { bottom: 12px; gap: 5px; padding: 5px; }
  .cz-hotbar .cz-slot { width: 50px; height: 50px; }
  .cz-hotbar .cz-slot img { width: 22px; height: 22px; }
  .cz-slot-name { display: none; }
  .cz-battery { left: 8px; bottom: 78px; padding: 6px 10px; }
  .cz-batt-segs { display: none; }
  .cz-pickups { bottom: 74px; }
}

/* Shop rows carry a thumbnail and an "already carried" count — see
   world3d/shop.js. Both are optional: a world that passes no icons renders the
   placeholder glyph and no count, exactly as before. */
.w3-shop-list li { align-items: flex-start; }
.w3-shop-icon {
  flex: 0 0 auto; width: 42px; height: 42px; margin-right: 12px;
  object-fit: contain; border-radius: var(--r-sm, 6px);
  background: rgba(20, 19, 28, 0.7); border: 1px solid var(--line);
}
.w3-shop-icon-none {
  display: grid; place-items: center; font-size: 17px; color: var(--text-3, #6e6e7c);
}
.w3-shop-held {
  display: inline-block; margin-top: 4px; padding: 2px 8px;
  border-radius: 999px; font-size: 10.5px; letter-spacing: 0.08em;
  color: var(--good, #8fe0a8); border: 1px solid rgba(143, 224, 168, 0.35);
}

/* Café Static's drinks list (games/nexus/cafe.js) reuses the shop panel, and
   asks it for one thing it does not otherwise do: a row whose thumbnail is the
   colour of the drink. Eight cups drawn as eight glyphs would be eight
   identical glyphs, and the colour is the fastest read there is for "which one
   is the green one". `--cup` is set per row from the drink's own fill. */
.cafe-shop .w3-shop-panel header b { letter-spacing: 0.1em; }
.cafe-shop .cafe-swatch {
  display: grid; place-items: center; font-size: 26px; line-height: 1;
  color: var(--cup, #9fe8f5);
  text-shadow: 0 0 10px var(--cup, #9fe8f5);
}

/* Quick-slot row in the shared inventory panel. Only rendered when a world
   passes `quickSlots` (see world3d/inventory.js) — Channel Zero's field kit is
   currently the only one that does. */
.w3-quick-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin: 10px 0 4px; padding-top: 10px; border-top: 1px solid var(--line);
}
.w3-quick-row > span {
  font-size: 10px; letter-spacing: 0.16em; color: var(--text-3, #6e6e7c);
  margin-right: 2px; text-transform: uppercase;
}
.w3-quick {
  width: 28px; height: 28px; padding: 0; border-radius: var(--r-sm, 6px);
  background: rgba(20, 19, 28, 0.8); border: 1px solid var(--line);
  color: var(--text-2, #a6a6b4); font: inherit; font-size: 12px;
  font-variant-numeric: tabular-nums; cursor: pointer;
  transition: border-color var(--fast, 140ms) ease, background var(--fast, 140ms) ease;
}
.w3-quick:hover:not(:disabled) { border-color: var(--line-strong, #33333f); color: var(--text, #edeae4); }
.w3-quick:focus-visible { outline: 2px solid var(--ice, #9fe8f5); outline-offset: 2px; }
.w3-quick.on {
  border-color: var(--ice, #9fe8f5); color: var(--ice, #9fe8f5);
  background: rgba(159, 232, 245, 0.12);
}
.w3-quick.clear { margin-left: 2px; color: var(--text-3, #6e6e7c); }
.w3-quick:disabled { opacity: 0.35; cursor: default; }

/* Hotbar drag feedback. */
.cz-hotbar .cz-slot.dragging { opacity: 0.4; }
.cz-hotbar .cz-slot.drop { border-color: var(--ice, #9fe8f5); border-style: solid; }

/* ── CHANNEL ZERO · vault keypad ───────────────────────────────────────────
   Sized so it is usable with a thumb: the smallest key is 56px square, which
   clears the 44px touch-target floor with room for an imprecise press, and the
   grid is capped narrow enough that a phone in portrait does not stretch the
   keys into letterboxes. The display is deliberately the loudest element —
   on a keypad the only thing a player needs to verify is what they have typed. */
.cz-keypad-panel { max-width: 340px; }

.cz-keypad-display {
  display: flex; align-items: baseline; justify-content: center; gap: 2px;
  padding: 14px 10px; margin-bottom: 6px;
  background: #0a0910; border: 1px solid var(--line, #2a2838); border-radius: 8px;
  font-variant-numeric: tabular-nums;
}
.cz-keypad-display b {
  font-size: 34px; line-height: 1; font-weight: 600;
  color: #3b3950;                       /* an empty slot: present, but not lit */
  transition: color 0.12s ease;
}
.cz-keypad-display b.on { color: var(--ice, #9fe8f5); text-shadow: 0 0 14px rgba(159, 232, 245, 0.45); }
.cz-keypad-display i { font-size: 34px; line-height: 1; font-style: normal; color: #3b3950; }
.cz-keypad-display span { margin-left: 8px; font-size: 12px; letter-spacing: 0.16em; color: var(--text-faint); }
.cz-keypad-display.good b.on, .cz-keypad-display.good i { color: var(--ok, #7fd8a0); text-shadow: 0 0 14px rgba(127, 216, 160, 0.45); }
.cz-keypad-display.bad b, .cz-keypad-display.bad i { color: var(--bad, #d8607b); text-shadow: none; }
/* One shake on rejection. Suppressed under reduced motion, where the colour
   change alone still carries the whole message. */
.cz-keypad-display.bad { animation: cz-keypad-shake 0.32s ease; }
@keyframes cz-keypad-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-6px); }
  75% { transform: translateX(6px); }
}
@media (prefers-reduced-motion: reduce) {
  .cz-keypad-display.bad { animation: none; }
}

.cz-keypad-known {
  margin: 0 0 10px; text-align: center;
  font-size: 12px; letter-spacing: 0.18em; color: var(--gold, #e6cf8f);
  min-height: 1.1em;
}

.cz-keypad-keys { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.cz-key {
  min-height: 56px; font-size: 20px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text, #e8e2f0);
  background: #17151f; border: 1px solid var(--line, #2a2838); border-radius: 8px;
  cursor: pointer; transition: background 0.1s ease, border-color 0.1s ease;
}
.cz-key:hover:not(:disabled) { background: #221f2e; border-color: var(--ice, #9fe8f5); }
.cz-key:active:not(:disabled) { background: #2b2739; }
.cz-key:focus-visible { outline: 2px solid var(--ice, #9fe8f5); outline-offset: 2px; }
.cz-key:disabled { opacity: 0.3; cursor: default; }
.cz-key-fn { font-size: 13px; letter-spacing: 0.1em; color: var(--text-dim); }

/* The finale's confirmation step. Deliberately plain and a little stark —
   this is the last thing the player reads before an irreversible choice. */
.cz-vote-warn {
  margin: 0 0 14px; padding: 12px 14px;
  font-size: 13.5px; line-height: 1.55; text-align: left;
  color: var(--text); background: rgba(216, 96, 123, 0.08);
  border: 1px solid rgba(216, 96, 123, 0.35); border-radius: 9px;
}
.w3-vote-opts .btn-danger { border-color: rgba(216, 96, 123, 0.6); }
.w3-vote-opts .btn-danger:hover { background: rgba(216, 96, 123, 0.16); }

/* ── the spec runtime ──────────────────────────────────────────────────────
   Deliberately minimal. This is not the Creator Mode editor: it is the
   smallest surface that lets a creator see WHICH document they are looking at,
   what the runtime thinks of it, and how to get out. Everything a creator
   wrote is inserted as text, never as markup — see src/world3d/spec/session.js. */

.spec-preview-bar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 40;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 8px 14px;
  font-size: 12.5px; line-height: 1.4;
  color: var(--text, #e8e2f0);
  background: linear-gradient(180deg, rgba(13, 11, 24, 0.94), rgba(13, 11, 24, 0.72));
  border-bottom: 1px solid rgba(143, 123, 216, 0.45);
  backdrop-filter: blur(6px);
  pointer-events: auto;
}
.spec-preview-bar .spec-tag {
  padding: 3px 9px; border-radius: 4px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.16em;
  color: #0d0b18; background: var(--violet, #8f7bd8);
}
.spec-preview-bar .spec-title { font-weight: 600; letter-spacing: 0.02em; }
.spec-preview-bar .spec-meta {
  font-variant-numeric: tabular-nums;
  color: var(--text-dim, #9a94ab);
}
.spec-preview-bar .spec-chip {
  padding: 2px 8px; border-radius: 4px;
  color: var(--gold, #e6cf8f);
  border: 1px solid rgba(230, 207, 143, 0.4);
  background: rgba(230, 207, 143, 0.08);
}
.spec-preview-bar .spec-chip-error {
  color: var(--rose, #d8607b);
  border-color: rgba(216, 96, 123, 0.5);
  background: rgba(216, 96, 123, 0.1);
}
.spec-preview-actions { display: flex; gap: 6px; margin-left: auto; flex-wrap: wrap; }
.spec-preview-actions .btn { padding: 4px 10px; font-size: 11.5px; }

/* Loading, failure and completion all share one box. */
.spec-overlay {
  position: absolute; inset: 0; z-index: 45;
  display: grid; place-items: center;
  padding: 24px;
  background: rgba(6, 5, 12, 0.82);
  backdrop-filter: blur(4px);
}
.spec-overlay-box {
  width: min(520px, 100%);
  padding: 26px 28px;
  text-align: center;
  color: var(--text, #e8e2f0);
  background: #12101c;
  border: 1px solid var(--line, #2a2838);
  border-radius: 12px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
}
.spec-overlay-box h2 {
  margin: 0 0 10px;
  font-size: 19px; letter-spacing: 0.06em; text-transform: uppercase;
}
.spec-overlay-box p { margin: 0 0 8px; font-size: 14px; line-height: 1.6; }
.spec-overlay-note { color: var(--text-dim, #9a94ab); font-size: 13px; }
.spec-overlay-error .spec-overlay-box { border-color: rgba(216, 96, 123, 0.45); }
.spec-overlay-detail {
  margin: 12px 0 0; padding: 10px 12px;
  max-height: 160px; overflow: auto;
  text-align: left; white-space: pre-wrap; word-break: break-word;
  font-size: 12px; color: var(--text-dim, #9a94ab);
  background: #0c0a14; border: 1px solid var(--line, #2a2838); border-radius: 8px;
}
.spec-overlay-actions { display: flex; gap: 10px; justify-content: center; margin-top: 18px; flex-wrap: wrap; }

/* An indeterminate bar: the load has no honest percentage to report. */
.spec-overlay-bar {
  height: 3px; margin-top: 16px; border-radius: 2px; overflow: hidden;
  background: rgba(143, 123, 216, 0.18);
}
.spec-overlay-bar::after {
  content: ''; display: block; height: 100%; width: 38%;
  border-radius: 2px; background: var(--violet, #8f7bd8);
  animation: spec-slide 1.1s ease-in-out infinite;
}
@keyframes spec-slide {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(320%); }
}
@media (prefers-reduced-motion: reduce) {
  .spec-overlay-bar::after { animation: none; width: 100%; opacity: 0.5; }
}

.spec-diagnostics {
  position: absolute; top: 52px; right: 14px; z-index: 46;
  width: min(460px, calc(100% - 28px));
  max-height: min(60vh, 520px); overflow: auto;
  padding: 14px 16px;
  color: var(--text, #e8e2f0);
  background: rgba(12, 10, 20, 0.96);
  border: 1px solid var(--line, #2a2838); border-radius: 10px;
}
.spec-diagnostics h3 {
  margin: 0 0 10px; font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-dim, #9a94ab);
}
.spec-diagnostics pre {
  margin: 0 0 12px; padding: 10px 12px;
  font-size: 11.5px; line-height: 1.6; white-space: pre-wrap;
  background: #0c0a14; border: 1px solid var(--line, #2a2838); border-radius: 8px;
}
.spec-diagnostics-log { display: grid; gap: 4px; margin-bottom: 12px; }
.spec-diag { margin: 0; font-size: 11.5px; line-height: 1.5; color: var(--text-dim, #9a94ab); }
.spec-diag-warn { color: var(--gold, #e6cf8f); }
.spec-diag-error { color: var(--rose, #d8607b); }
