/* ══════════════════════════════════════════════════════════
   Abyssal — UI shell
   Deep-water glassmorphism. Everything sits above a full
   bleed WebGL canvas, so panels are translucent + blurred.
   ══════════════════════════════════════════════════════════ */

:root{
  --ink:        #eaf4ff;
  --ink-dim:    #9fb6cf;
  --ink-faint:  #6c839c;
  --glass:      rgba(9, 24, 40, .58);
  --glass-hi:   rgba(22, 46, 70, .62);
  --edge:       rgba(150, 205, 255, .16);
  --edge-hi:    rgba(150, 205, 255, .34);
  --teal:       #35e0d0;
  --teal-deep:  #0f8f8a;
  --gold:       #f6c445;
  --gold-deep:  #b8860b;
  --danger:     #ff6b6b;

  --r-common:    #9fb6cf;
  --r-uncommon:  #5fd98a;
  --r-rare:      #4aa8ff;
  --r-epic:      #b06bff;
  --r-legendary: #ffb03a;
  --r-mythic:    #ff5ea8;

  /* Blur radius is the expensive dimension of a shadow: the compositor blends
     the blurred region over whatever is behind it, and here that is a canvas
     redrawing every frame. Measured on a Galaxy A40, the HUD's original
     large-radius shadows cost ~20% of the frame rate on their own. Keep radii
     small and prefer a single layer; a gradient can stand in for inset depth
     at no extra paint cost. */
  --shadow: 0 6px 16px rgba(0,0,0,.45);
  --font: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* instrument-panel HUD chrome (wallet / vitals / quest / dock) — brass
     fittings bolted to the tank rather than glass floating over it. Scoped
     to its own variables so the drawer/modal/journal glass is untouched. */
  --brass:        #c7a05c;
  --brass-hi:     #e9cf9a;
  --brass-deep:   #6f5527;
  --verdigris:    #4b8577;
  --verdigris-hi: #7cb8a8;
  --oxide:        #b85c3e;
  --bone:         #e7ddc6;
  --bone-dim:     #a9b8ab;
  --bone-faint:   #71847a;
  --font-instrument: 'Space Grotesk Var', var(--font);
}

@font-face{
  font-family:'Space Grotesk Var';
  font-style:normal;
  font-weight:300 700;
  font-display:swap;
  src:url('assets/fonts/SpaceGrotesk-Variable.woff2') format('woff2');
}

*{ box-sizing:border-box; -webkit-tap-highlight-color:transparent; }

/* The `hidden` attribute is only honoured by the UA stylesheet's
   [hidden]{display:none}, and *any* author `display` declaration outranks
   it — so `#fatal{display:grid}` and `.modal{display:grid}` below were
   silently cancelling it and leaving those panels permanently on screen.
   Restate it as an author rule so `hidden` actually hides things. */
[hidden]{ display:none !important; }

html,body{
  margin:0; height:100%; overflow:hidden;
  background:#03080f; color:var(--ink);
  font-family:var(--font);
  font-size:14px;
  -webkit-font-smoothing:antialiased;
  user-select:none;
  /* Kills the native double-tap-to-zoom gesture everywhere, not just on
     #gl (which already opts out with touch-action:none for its own custom
     pan/orbit/pinch handling). `manipulation` still allows panning/scroll
     inside the drawer and modal lists — it only drops pinch-zoom and
     double-tap-zoom, both of which just fight our own camera gestures and
     the fixed-viewport HUD in a game that never wants to zoom the page. */
  touch-action:manipulation;
}

#gl{ position:fixed; inset:0; width:100%; height:100%; display:block; touch-action:none; cursor:crosshair; }
#gl.grabbing{ cursor:grabbing; }

.hidden{ display:none !important; }

/* ── focus ────────────────────────────────────────────── */
/* :focus-visible, not :focus — keyboard navigation gets a ring, mouse/touch
   clicks stay quiet. Covers every focusable element by default rather than
   enumerating each custom button class, since the UA default outline is
   barely legible against this dark, blurred glass UI and squares off
   rounded controls. */
:focus-visible{
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}

/* ── boot ─────────────────────────────────────────────── */
#boot{
  position:fixed; inset:0; z-index:200;
  display:grid; place-items:center;
  background:radial-gradient(ellipse at 50% 40%, #0b2740, #03080f 70%);
  transition:opacity .7s ease, visibility .7s;
}
#boot.gone{ opacity:0; visibility:hidden; }
.boot-inner{ text-align:center; }
.boot-logo{
  font-size:clamp(38px,7vw,72px); font-weight:200; letter-spacing:.42em;
  margin-right:-.42em;
  background:linear-gradient(180deg,#dff6ff,#4fbfd6 60%,#1b7089);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.boot-sub{ margin-top:6px; color:var(--ink-faint); letter-spacing:.28em; font-size:11px; text-transform:uppercase; }
.boot-bar{ margin:30px auto 12px; width:min(280px,60vw); height:2px; background:rgba(255,255,255,.09); overflow:hidden; border-radius:2px; }
.boot-bar i{ display:block; height:100%; width:0%; background:linear-gradient(90deg,var(--teal-deep),var(--teal)); transition:width .3s ease; }
.boot-msg{ color:var(--ink-faint); font-size:12px; letter-spacing:.05em; }

#fatal{
  position:fixed; inset:0; z-index:300; display:grid; place-items:center;
  background:#05101c; padding:24px; overflow-y:auto;
}
.fatal-inner{ max-width:600px; }
.fatal-inner h1{ font-weight:300; letter-spacing:.04em; margin:0 0 14px; font-size:26px; }
.fatal-inner p{ color:var(--ink-dim); line-height:1.65; margin:0 0 12px; }
#fatal-msg{
  color:#ffb4b4; font-family:ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size:13px; background:rgba(255,107,107,.09);
  border:1px solid rgba(255,107,107,.28); border-radius:9px; padding:10px 12px;
  word-break:break-word;
}
#fatal-diag{
  margin:14px 0 0; padding:12px; max-height:230px; overflow:auto;
  background:rgba(255,255,255,.045); border:1px solid var(--edge);
  border-radius:10px; font-size:11px; line-height:1.55; color:var(--ink-faint);
  font-family:ui-monospace, "Cascadia Code", Consolas, monospace;
  white-space:pre-wrap; user-select:text;
}
.fatal-actions{ display:flex; gap:8px; margin-top:14px; }

/* ── generic panel ────────────────────────────────────── */
.panel{
  position:fixed; z-index:20;
  background:var(--glass);
  backdrop-filter:blur(10px) saturate(135%);
  -webkit-backdrop-filter:blur(10px) saturate(135%);
  border:1px solid var(--edge);
  border-radius:14px;
  box-shadow:var(--shadow);
}

button{ font-family:inherit; color:inherit; cursor:pointer; border:none; background:none; }
a.btn{ display:inline-flex; align-items:center; text-decoration:none; color:inherit; cursor:pointer; }

.btn{
  border-radius:10px; padding:9px 16px; font-size:13px; font-weight:600;
  border:1px solid var(--edge-hi);
  background:linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.02));
  transition:transform .1s ease, filter .15s ease, background .15s;
}
.btn:hover{ filter:brightness(1.25); }
.btn:active{ transform:translateY(1px) scale(.985); }
.btn.sm{ padding:6px 11px; font-size:12px; }
.btn.primary{ background:linear-gradient(180deg,#2ec6bd,#12817d); border-color:#38e3d6; color:#012526; }
.btn.gold{ background:linear-gradient(180deg,#f9d264,#c9930f); border-color:#ffdb7a; color:#3a2500; }
.btn.ghost{ background:rgba(255,255,255,.05); }
.btn.danger{ color:var(--danger); border-color:rgba(255,107,107,.4); }
.btn:disabled{ opacity:.4; cursor:not-allowed; filter:grayscale(.6); }

.x{
  position:absolute; top:10px; right:10px; width:28px; height:28px; line-height:1;
  border-radius:8px; font-size:20px; color:var(--ink-dim);
  display:grid; place-items:center;
}
.x:hover{ background:rgba(255,255,255,.09); color:var(--ink); }

/* ── wallet: riveted brass plaque ─────────────────────── */
.wallet{
  position:fixed; z-index:20; top:14px; left:14px; padding:9px 16px;
  display:flex; align-items:center; border-radius:6px;
  border:1px solid var(--brass-deep);
  background:
    radial-gradient(circle at 35% 30%, var(--brass-hi), var(--brass-deep) 70%) 6px 6px/6px 6px no-repeat,
    radial-gradient(circle at 35% 30%, var(--brass-hi), var(--brass-deep) 70%) calc(100% - 6px) 6px/6px 6px no-repeat,
    radial-gradient(circle at 35% 30%, var(--brass-hi), var(--brass-deep) 70%) 6px calc(100% - 6px)/6px 6px no-repeat,
    radial-gradient(circle at 35% 30%, var(--brass-hi), var(--brass-deep) 70%) calc(100% - 6px) calc(100% - 6px)/6px 6px no-repeat,
    /* The dark tail of this gradient stands in for the inset vignette the
       box-shadow below used to draw — same recessed look, no extra paint. */
    linear-gradient(165deg, #1a2f24 0%, #0f1e18 62%, #0a1611 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 4px 10px rgba(0,0,0,.45);
}
.cur{
  display:flex; align-items:center; gap:7px; padding:0 12px;
  font-family:var(--font-instrument); font-variant-numeric:tabular-nums;
  font-weight:600; font-size:16px; color:var(--bone);
  text-shadow:0 -1px 0 rgba(0,0,0,.7), 0 1px 0 rgba(255,255,255,.08);
}
.cur:first-child{ padding-left:2px; }
.cur .ico{ width:16px; height:16px; }
.cur.bump{ animation:bump .42s cubic-bezier(.2,1.7,.4,1); }
@keyframes bump{ 0%{transform:scale(1)} 35%{transform:scale(1.22)} 100%{transform:scale(1)} }
.sep{ width:1px; height:20px; background:rgba(199,160,92,.25); }
.wallet .stat{
  color:var(--bone-dim); font-size:13px; font-variant-numeric:tabular-nums;
  font-family:var(--font-instrument); padding:0 4px 0 12px;
}
.wallet .stat small{ opacity:.65; }

/* ── vitals: pressure-gauge cluster ──────────────────────
   shares the dial-bezel/dial-face/dial-track/dial-fg vocabulary with the
   quest ring below — same brass-ring, dark-face, verdigris-fill language,
   just three of them instead of one. */
.vitals{
  position:fixed; z-index:20; top:14px; right:14px; padding:10px 12px 8px; width:186px;
  border-radius:6px; border:1px solid var(--brass-deep);
  /* Dark tail replaces the inset vignette — see .wallet. */
  background:linear-gradient(165deg, #1a2f24 0%, #0f1e18 62%, #0a1611 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 4px 10px rgba(0,0,0,.45);
}
.dial-cluster{ display:flex; justify-content:space-between; gap:6px; }
.dial{ display:flex; flex-direction:column; align-items:center; gap:4px; }
.dial-bezel{
  --d:44px; width:var(--d); height:var(--d); flex:0 0 auto; box-sizing:border-box;
  border-radius:50%; padding:3px;
  background:conic-gradient(from 220deg, var(--brass-deep), var(--brass-hi) 30%, var(--brass-deep) 60%, var(--brass) 85%, var(--brass-deep));
  box-shadow:0 4px 10px rgba(0,0,0,.5);
}
.dial-face{
  width:100%; height:100%; border-radius:50%; box-sizing:border-box;
  background:radial-gradient(circle at 40% 32%, #14263a, #081019 75%);
  display:flex; align-items:center; justify-content:center;
}
.dial-face svg{ display:block; width:100%; height:100%; }
.dial-track{ fill:none; stroke:rgba(255,255,255,.08); stroke-width:4; }
.dial-fg{
  fill:none; stroke-width:4; stroke-linecap:round; stroke:var(--verdigris-hi);
  transition:stroke-dashoffset .4s ease, stroke .4s;
}
.dial-fg.warn{ stroke:var(--brass); }
.dial-fg.bad{ stroke:var(--oxide); }
.dial-lbl{
  font-family:var(--font-instrument); font-weight:500; font-size:9px; text-transform:uppercase;
  color:var(--brass); letter-spacing:.08em;
}
.vfoot{
  text-align:right; font-size:11px; color:var(--brass); font-variant-numeric:tabular-nums;
  padding-top:6px; font-family:var(--font-instrument);
}
.clockrow{ display:flex; align-items:center; gap:5px; margin-top:5px; }
.clockico{ font-size:11px; flex:0 0 auto; }
.clockrow #hud-time{ flex:1 1 auto; min-width:0; accent-color:var(--teal); }
.clockval{
  flex:0 0 auto; font-size:10px; color:var(--brass); font-variant-numeric:tabular-nums;
  font-family:var(--font-instrument);
}
.clockpause{
  flex:0 0 auto; width:18px; height:18px; padding:0; display:grid; place-items:center;
  background:transparent; border:1px solid var(--brass-deep); border-radius:4px;
  color:var(--brass); font-size:9px; line-height:1; cursor:pointer;
}
.clockpause:hover{ color:var(--bone); border-color:var(--brass-hi); }
.clockpause.active{ color:var(--verdigris-hi); border-color:var(--verdigris-hi); }

/* ── objective card ───────────────────────────────────── */
/* Bottom-centre, directly above the dock it is telling you to press. */
.quest{
  position:fixed; z-index:20; left:50%; transform:translateX(-50%); bottom:104px;
  width:min(450px, calc(100vw - 28px));
  padding:11px 16px; display:flex; align-items:center; gap:13px;
  border-radius:6px; border:1px solid var(--brass-deep);
  background:linear-gradient(160deg, #16211a, #0d1712);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06), 0 4px 10px rgba(0,0,0,.45);
}
.quest::before, .quest::after{
  content:""; position:absolute; top:0; bottom:0; width:12px; border-radius:6px;
  background:linear-gradient(90deg, rgba(199,160,92,.16), transparent);
}
.quest::before{ left:0; }
.quest::after{ right:0; transform:scaleX(-1); }
.quest.hidden{ display:none !important; }

/* the ring reuses .dial-bezel/.dial-face from the vitals cluster —
   .quest-ring only adds the position:relative the step-number overlay needs. */
.quest-ring{ position:relative; }
.quest-step{
  position:absolute; inset:0; display:grid; place-items:center;
  font-family:var(--font-instrument); font-size:13px; font-weight:700;
  color:var(--bone); font-variant-numeric:tabular-nums;
}

.quest-body{ flex:1; min-width:0; }
.quest-eyebrow{
  font-family:var(--font-instrument); font-size:9px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--brass); font-weight:600; display:flex; gap:6px;
}
.quest-eyebrow span{ color:var(--bone-faint); font-weight:500; letter-spacing:.08em; }
.quest h4{ margin:3px 0 2px; font-size:15px; font-weight:600; line-height:1.2; font-family:var(--font-instrument); color:var(--bone); }
.quest p{ margin:0; font-size:11.5px; color:var(--bone-dim); line-height:1.4; font-family:var(--font-instrument); }
.quest-meta{
  flex:0 0 auto; font-size:10.5px; color:var(--bone-faint); font-family:var(--font-instrument);
  font-variant-numeric:tabular-nums; text-align:right; max-width:80px; line-height:1.35;
}
.quest.done{ border-color:var(--verdigris-hi); }
.quest.done .dial-fg{ stroke:var(--verdigris-hi); }
.quest.done .quest-step{ color:var(--verdigris-hi); }

/* ── FTUE pointer ─────────────────────────────────────── */
#ftue-pointer{ position:fixed; z-index:45; pointer-events:none; transform:translate(-50%,-50%); }
.fp-ring{
  position:absolute; left:50%; top:50%; width:62px; height:62px;
  margin:-31px 0 0 -31px; border-radius:50%;
  border:2px solid var(--gold);
  animation:fpPulse 1.5s ease-out infinite;
}
.fp-arrow{
  position:absolute; left:50%; top:26px; transform:translateX(-50%);
  color:var(--gold); font-size:16px; text-shadow:0 2px 8px rgba(0,0,0,.85);
  animation:fpBob 1.1s ease-in-out infinite;
}
@keyframes fpPulse{
  0%{ transform:scale(.6); opacity:.95 }
  70%{ transform:scale(1.18); opacity:0 }
  100%{ opacity:0 }
}
@keyframes fpBob{ 0%,100%{ transform:translate(-50%,0) } 50%{ transform:translate(-50%,5px) } }

/* ── hold-to-grab ring ────────────────────────────────── */
#holdring{ position:fixed; z-index:46; pointer-events:none; width:48px; height:48px; transform:translate(-50%,-50%); }
#holdring svg{ width:48px; height:48px; transform:rotate(-90deg); }
.hr-bg{ fill:rgba(4,14,24,.55); stroke:rgba(255,255,255,.18); stroke-width:3; }
.hr-fg{
  fill:none; stroke:var(--teal); stroke-width:3; stroke-linecap:round;
  stroke-dasharray:125.6; stroke-dashoffset:125.6;
}
.hr-icon{ position:absolute; inset:0; display:grid; place-items:center;
  font-size:17px; color:var(--teal); text-shadow:0 1px 4px #000; }
#holdring.armed .hr-fg{ stroke:var(--gold); }
#holdring.armed .hr-icon{ color:var(--gold); }

@media (max-width:640px){
  .quest{ bottom:92px; padding:9px 11px; gap:9px; }
  .quest-meta{ display:none; }
}

/* ── toasts ───────────────────────────────────────────── */
#toasts{
  position:fixed; z-index:40; left:50%; top:70px; transform:translateX(-50%);
  display:flex; flex-direction:column; align-items:center; gap:7px; pointer-events:none;
}
.toast{
  background:var(--glass-hi); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  border:1px solid var(--edge); border-radius:999px;
  padding:7px 17px; font-size:12.5px; box-shadow:var(--shadow);
  display:flex; align-items:center; gap:9px; white-space:nowrap;
  animation:toastIn .32s cubic-bezier(.2,1.4,.4,1);
}
.toast.out{ animation:toastOut .34s ease forwards; }
.toast b{ font-weight:700; }
.toast .tico{ font-size:15px; }
@keyframes toastIn{ from{ opacity:0; transform:translateY(-14px) scale(.94) } }
@keyframes toastOut{ to{ opacity:0; transform:translateY(-10px) scale(.96) } }

/* ── floating score pops ──────────────────────────────── */
#pops{ position:fixed; inset:0; z-index:35; pointer-events:none; overflow:hidden; }
.pop{
  position:absolute; transform:translate(-50%,-50%);
  font-weight:800; font-size:15px; color:var(--gold);
  text-shadow:0 2px 10px rgba(0,0,0,.85), 0 0 18px rgba(246,196,69,.5);
  animation:popUp 1.15s cubic-bezier(.15,.85,.35,1) forwards;
  white-space:nowrap;
}
.pop.xp{ color:var(--teal); text-shadow:0 2px 10px rgba(0,0,0,.85), 0 0 18px rgba(53,224,208,.45); }
/* Ambient income is continuous and per-creature, not a deliberate reward —
   kept smaller and dimmer than .pop so a busy tank doesn't read as a slot
   machine. Its own keyframes (not a static opacity) since popUp already
   drives opacity for the full animation and would otherwise win. */
.pop.coin{
  font-size:11px; font-weight:700;
  text-shadow:0 1px 6px rgba(0,0,0,.8), 0 0 10px rgba(246,196,69,.35);
  animation-name:popUpDim; animation-duration:.95s;
}
@keyframes popUp{
  0%{ opacity:0; transform:translate(-50%,-40%) scale(.6) }
  18%{ opacity:1; transform:translate(-50%,-58%) scale(1.1) }
  100%{ opacity:0; transform:translate(-50%,-155%) scale(1) }
}
@keyframes popUpDim{
  0%{ opacity:0; transform:translate(-50%,-35%) scale(.6) }
  18%{ opacity:.75; transform:translate(-50%,-50%) scale(1) }
  100%{ opacity:0; transform:translate(-50%,-120%) scale(1) }
}

/* ── creature card ────────────────────────────────────── */
.inspector{
  left:14px; top:70px; width:288px; padding:13px 14px 12px;
  max-height:calc(100vh - 190px); overflow-y:auto;
}
.inspector::-webkit-scrollbar{ width:6px; }
.inspector::-webkit-scrollbar-thumb{ background:rgba(255,255,255,.14); border-radius:3px; }

.insp-head{ display:flex; gap:11px; align-items:center; }
.insp-portrait{
  width:64px; height:46px; flex:0 0 auto; object-fit:contain;
  border-radius:9px; background:radial-gradient(circle at 50% 60%, rgba(255,255,255,.09), rgba(0,0,0,.25));
  border:1px solid rgba(255,255,255,.08);
}
.insp-id{ min-width:0; }
.insp-head h3{ margin:4px 0 1px; font-size:17px; font-weight:650; line-height:1.15; }
.insp-species{ color:var(--ink-faint); font-size:11px; font-style:italic; }
.insp-rar{
  display:inline-block; font-size:9px; letter-spacing:.16em; text-transform:uppercase;
  font-weight:800; padding:2px 7px; border-radius:5px; background:rgba(255,255,255,.08);
}

.insp-locked-hint{
  margin:11px 0 0; padding:8px 10px; border-radius:10px; font-size:11.5px;
  color:var(--ink-faint); line-height:1.45; background:rgba(255,255,255,.045);
  border:1px solid var(--edge);
}

.insp-temper{
  margin:11px 0 0; padding:8px 10px; border-radius:10px;
  background:linear-gradient(180deg, rgba(53,224,208,.11), rgba(53,224,208,.03));
  border:1px solid rgba(53,224,208,.22);
}
.insp-temper .tname{ display:block; font-weight:700; font-size:13px; color:var(--teal); }
.insp-temper .tdesc{ display:block; font-size:11.5px; color:var(--ink-dim); margin-top:2px; line-height:1.45; }

.insp-now{
  margin:9px 0 10px; font-size:12px; color:var(--ink);
  padding:6px 10px; border-radius:8px; background:rgba(255,255,255,.05);
}
.insp-now b{ color:var(--teal); font-weight:650; }

.insp-tabs{ display:flex; gap:3px; margin-bottom:10px; }
.itab{
  flex:1; padding:5px 4px; border-radius:8px; font-size:11px; color:var(--ink-faint);
  transition:color .14s, background .14s, border-color .14s; border:1px solid transparent;
}
.itab:hover{ color:var(--ink); background:rgba(255,255,255,.06); }
.itab.active{ background:rgba(53,224,208,.14); color:var(--teal); font-weight:650; }

.insp-pane{ margin-bottom:11px; }

/* trait rows */
.trait{ margin-bottom:9px; }
.trait-top{ display:flex; justify-content:space-between; font-size:11px; margin-bottom:3px; }
.trait-top .tl{ color:var(--ink-dim); }
.trait-top .tv{ color:var(--ink); font-weight:650; }
.trait-track{
  height:6px; border-radius:3px; background:rgba(255,255,255,.08);
  position:relative; overflow:hidden;
}
.trait-track i{
  position:absolute; inset:0 auto 0 0; border-radius:3px;
  background:linear-gradient(90deg, var(--teal-deep), var(--teal));
}
.trait-track i.hot{ background:linear-gradient(90deg,#c9701a,#f6a545); }
.trait-track i.cool{ background:linear-gradient(90deg,#2a5f8a,#5aa8d8); }
.trait-note{ font-size:10.5px; color:var(--ink-faint); margin-top:2px; font-style:italic; }

.insp-facts{ font-size:11.5px; color:var(--ink-dim); line-height:1.8; }
.insp-facts .k{ color:var(--ink-faint); }
.insp-facts .row{ display:flex; justify-content:space-between; gap:8px; }
.insp-facts .row b{ color:var(--ink); font-weight:600; }

.moments{ font-size:11.5px; color:var(--ink-dim); }
.moment{ display:flex; gap:8px; padding:5px 0; border-bottom:1px solid rgba(255,255,255,.06); }
.moment:last-child{ border-bottom:none; }
.moment .mi{ flex:0 0 auto; font-size:14px; line-height:1.3; }
.moment .mt{ line-height:1.45; }
.moment .mw{ display:block; color:var(--ink-faint); font-size:10px; margin-top:1px; }
.moments .empty{ color:var(--ink-faint); font-style:italic; padding:6px 0; }

.insp-actions{ display:flex; gap:6px; }
.insp-actions .btn{ flex:1; padding:6px 4px; }

/* ── dock: instrument rack ────────────────────────────────
   each tool sits in its own recessed brass socket instead of a rounded
   glass button — "locked"/"active" get a physical read (empty vs. lit
   socket) rather than an opacity change. */
.dock{
  position:fixed; z-index:25; bottom:16px; left:50%; transform:translateX(-50%);
  display:flex; align-items:center; gap:8px; padding:8px 14px;
  background:linear-gradient(180deg, #241a10, #16100a);
  border:1px solid var(--brass-deep); border-radius:14px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.05), 0 4px 10px rgba(0,0,0,.45);
  max-width:calc(100vw - 24px); overflow-x:auto; scrollbar-width:none;
}
.dock::-webkit-scrollbar{ display:none; }
.dock-group{ display:flex; gap:6px; }
.dock-sep{ width:1px; align-self:stretch; background:rgba(199,160,92,.25); margin:2px 3px; }

.dockbtn{
  width:52px; padding:0; border-radius:10px;
  display:flex; flex-direction:column; align-items:center; gap:4px;
  color:var(--bone-faint); font-family:var(--font-instrument); font-size:9.5px; letter-spacing:.03em;
  border:none; background:none; transition:color .15s; position:relative; flex:0 0 auto;
}
.dockbtn svg, .dockbtn .glyph{
  width:34px; height:34px; box-sizing:border-box; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:radial-gradient(circle at 38% 30%, #1a2c3e, #060d13 78%);
  box-shadow:inset 0 2px 5px rgba(0,0,0,.7), inset 0 -1px 0 rgba(255,255,255,.05), 0 0 0 2px var(--brass-deep);
  transition:box-shadow .15s;
}
.dockbtn svg{ padding:7px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; }
.dockbtn .glyph{ font-size:16px; line-height:1; }
.dockbtn:hover{ color:var(--bone); }
.dockbtn:hover svg, .dockbtn:hover .glyph{ box-shadow:inset 0 2px 5px rgba(0,0,0,.7), inset 0 -1px 0 rgba(255,255,255,.05), 0 0 0 2px var(--brass-hi); }
.dockbtn.active{ color:var(--verdigris-hi); }
.dockbtn.active svg, .dockbtn.active .glyph{
  box-shadow:inset 0 2px 5px rgba(0,0,0,.5), inset 0 -1px 0 rgba(255,255,255,.05), 0 0 0 2px var(--verdigris-hi), 0 0 12px rgba(124,184,168,.5);
}
.dockbtn.locked{ opacity:.42; }
.dockbtn .count{
  position:absolute; top:-2px; right:5px; font-size:9.5px; font-weight:800;
  background:rgba(0,0,0,.6); border:1px solid var(--brass-deep); border-radius:6px; padding:1px 4px;
  color:var(--brass-hi); font-variant-numeric:tabular-nums;
}

.hint{
  position:fixed; z-index:20; bottom:88px; left:50%; transform:translateX(-50%);
  font-size:11px; color:var(--ink-faint); letter-spacing:.05em;
  text-shadow:0 1px 6px #000; pointer-events:none; transition:opacity .6s; text-align:center;
}
.hint.fade{ opacity:0; }

/* ── centred UI yields to the drawer ──────────────────
   The shop slides in from the right and would otherwise sit on top of the
   dock and the objective card — exactly the two things you need to read
   while shopping. Everything horizontally centred shifts left by half the
   drawer's width so it stays centred in the space that's left. */
:root{ --drawer-shift: 0px; }

.dock, .quest, #toasts{
  transition:transform .34s cubic-bezier(.3,.9,.3,1);
}
body.shop-open .dock,
body.shop-open .quest,
body.shop-open #toasts{
  transform:translateX(calc(-50% - var(--drawer-shift)));
}

/* ── drawer (shop) ────────────────────────────────────── */
.drawer{
  position:fixed; z-index:60; top:0; right:0; height:100%; width:min(430px,100vw);
  background:rgba(6,18,31,.9); backdrop-filter:blur(14px) saturate(140%);
  -webkit-backdrop-filter:blur(14px) saturate(140%);
  border-left:1px solid var(--edge);
  display:flex; flex-direction:column;
  transform:translateX(100%); transition:transform .34s cubic-bezier(.3,.9,.3,1);
  box-shadow:-20px 0 60px rgba(0,0,0,.5);
}
.drawer.open{ transform:none; }
.drawer-head{ padding:16px 18px 10px; border-bottom:1px solid var(--edge); position:relative; }
.drawer-head h2{ margin:0; font-size:19px; font-weight:600; letter-spacing:.02em; }
.drawer-wallet{ margin-top:3px; font-size:12.5px; color:var(--gold); font-variant-numeric:tabular-nums; }
.drawer-wallet span:last-child{ color:#dbe9ff; }

.tabs{ display:flex; gap:3px; padding:9px 12px; border-bottom:1px solid var(--edge); overflow-x:auto; scrollbar-width:none; }
.tabs::-webkit-scrollbar{ display:none; }
.tab{
  padding:6px 13px; border-radius:9px; font-size:12.5px; color:var(--ink-faint);
  white-space:nowrap; transition:color .14s, background .14s;
}
.tab:hover{ color:var(--ink); background:rgba(255,255,255,.06); }
.tab.active{ background:rgba(53,224,208,.15); color:var(--teal); font-weight:650; }

.drawer-body{ flex:1; overflow-y:auto; padding:12px; }
.drawer-body::-webkit-scrollbar{ width:8px; }
.drawer-body::-webkit-scrollbar-thumb{ background:rgba(255,255,255,.13); border-radius:4px; }

.shop-note{ font-size:11.5px; color:var(--ink-faint); padding:2px 4px 10px; line-height:1.6; }
.shop-group{ font-size:10px; letter-spacing:.18em; text-transform:uppercase; color:var(--ink-faint); margin:14px 4px 8px; }

.card{
  display:flex; gap:12px; align-items:center; padding:11px;
  border:1px solid var(--edge); border-radius:13px; margin-bottom:8px;
  background:linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.012));
  transition:border-color .16s, background .16s; position:relative; overflow:hidden;
}
.card:hover{ border-color:var(--edge-hi); background:rgba(255,255,255,.06); }
.card.owned::after{
  content:"OWNED"; position:absolute; top:9px; right:11px;
  font-size:8.5px; letter-spacing:.14em; color:var(--teal); font-weight:800;
}
.card .thumb{
  width:60px; height:52px; flex:0 0 auto; border-radius:10px;
  background:radial-gradient(circle at 50% 60%, rgba(255,255,255,.08), rgba(0,0,0,.25));
  display:grid; place-items:center; overflow:hidden; border:1px solid rgba(255,255,255,.07);
}
.card .thumb svg{ width:100%; height:100%; }
.card .thumb .glyph{ font-size:27px; }
.card .body{ flex:1; min-width:0; }
.card .title{ display:flex; align-items:baseline; gap:7px; }
.card .title h4{ margin:0; font-size:14px; font-weight:650; }
.card .rar{ font-size:8.5px; letter-spacing:.14em; text-transform:uppercase; font-weight:800; }
.card .desc{ font-size:11.5px; color:var(--ink-dim); line-height:1.5; margin-top:3px; }
.card .tags{ display:flex; gap:5px; flex-wrap:wrap; margin-top:6px; }
.card .tag{
  font-size:9.5px; padding:2px 6px; border-radius:5px;
  background:rgba(255,255,255,.07); color:var(--ink-faint); letter-spacing:.04em;
}
.card .buy{ flex:0 0 auto; display:flex; flex-direction:column; gap:5px; align-items:stretch; }
.price{
  display:flex; align-items:center; justify-content:center; gap:4px;
  font-weight:750; font-size:13px; font-variant-numeric:tabular-nums; white-space:nowrap;
}
.price.coins{ color:var(--gold); }
.price.pearls{ color:#dbe9ff; }

/* locked rank teaser — shows the ladder without making it browsable */
.rank-locked{
  display:flex; align-items:center; gap:10px; margin:14px 4px 8px;
  padding:9px 11px; border-radius:11px;
  border:1px dashed var(--edge); background:rgba(255,255,255,.02);
}
.rl-lock{ font-size:14px; opacity:.55; }
.rl-body{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.rl-body b{ font-size:10px; letter-spacing:.16em; text-transform:uppercase; }
.rl-body em{ font-style:normal; font-size:11px; color:var(--ink-faint); }

/* the one thing the current objective wants you to buy */
.card.focus{
  border-color:var(--gold);
  background:linear-gradient(180deg, rgba(246,196,69,.14), rgba(255,255,255,.02));
  box-shadow:0 0 0 1px rgba(246,196,69,.25), 0 6px 22px rgba(246,196,69,.14);
}
.card.dimmed{ opacity:.34; }
.card.dimmed:hover{ border-color:var(--edge); background:rgba(255,255,255,.02); }
.focus-flag{
  position:absolute; top:9px; right:11px;
  font-size:8.5px; letter-spacing:.14em; font-weight:800; color:var(--gold);
}

/* rarity colour hooks */
.r-common{ color:var(--r-common) } .r-uncommon{ color:var(--r-uncommon) }
.r-rare{ color:var(--r-rare) }     .r-epic{ color:var(--r-epic) }
.r-legendary{ color:var(--r-legendary) } .r-mythic{ color:var(--r-mythic) }
.bg-common{ background:rgba(159,182,207,.16) } .bg-uncommon{ background:rgba(95,217,138,.16) }
.bg-rare{ background:rgba(74,168,255,.16) }    .bg-epic{ background:rgba(176,107,255,.18) }
.bg-legendary{ background:rgba(255,176,58,.18) } .bg-mythic{ background:rgba(255,94,168,.18) }

/* ── modal ────────────────────────────────────────────── */
.modal{
  position:fixed; inset:0; z-index:80; display:grid; place-items:center;
  background:rgba(2,7,13,.72); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  padding:20px; animation:fadeIn .2s ease;
}
@keyframes fadeIn{ from{opacity:0} }

/* ── low quality: no backdrop-filter ─────────────────────
   Measured on a Galaxy A40: opening a .modal (position:fixed; inset:0) or the
   .drawer (~430px, which is the full width on a phone) tanks fps in a way the
   render-scale slider above does nothing for, because it isn't fill rate in
   the 3D scene — it's the compositor reblurring the ENTIRE viewport, every
   single frame, for as long as the panel is open, since backdrop-filter has
   to sample whatever's still animating underneath it (the water, the fish).
   Low quality exists specifically for weak GPUs, so on it these two fall back
   to a solid near-opaque background instead — same information, same layout,
   just not frosted glass.
   The small always-on HUD chrome (.panel, .toast) is deliberately NOT
   included here: it covers a fraction of the screen rather than the whole
   viewport, and with only that on screen the A40 was already vsync-bound at
   low quality — there's no measured fps to buy by touching it, only
   legibility to lose, since --glass/--glass-hi are semi-transparent and lean
   on the blur for contrast against a bright, moving background. */
body[data-quality="low"] .modal,
body[data-quality="low"] .drawer{
  backdrop-filter:none;
  -webkit-backdrop-filter:none;
}
body[data-quality="low"] .modal{ background:rgba(3,9,16,.94); }
body[data-quality="low"] .drawer{ background:rgba(4,12,21,.96); }
.modal-card{
  position:relative; width:min(440px,100%); max-height:86vh; overflow-y:auto;
  background:rgba(9,24,40,.96); border:1px solid var(--edge); border-radius:18px;
  padding:22px; box-shadow:var(--shadow);
  animation:cardIn .3s cubic-bezier(.2,1.3,.4,1);
}
@keyframes cardIn{ from{ opacity:0; transform:translateY(16px) scale(.97) } }
.modal-card h2{ margin:0 0 14px; font-size:20px; font-weight:600; }
.modal-card hr{ border:none; border-top:1px solid var(--edge); margin:14px 0; }
.modal-card input[type=text]{
  width:100%; background:rgba(255,255,255,.07); border:1px solid var(--edge); color:var(--ink);
  border-radius:8px; padding:8px 10px; font-family:inherit; font-size:13px; outline:none; box-sizing:border-box;
}
.modal-card input[type=text]:focus-visible{ outline:2px solid var(--teal); outline-offset:1px; }
.setrow{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:7px 0; font-size:13px; }
.setrow label{ color:var(--ink-dim); }
/* In-page dropdown. A native <select> popup is an OS-level window; on
   Windows it drops the page out of Chromium's fast presentation path and
   every hover repaint then re-blurs the backdrop-filter panels underneath.
   Rendering the list ourselves keeps it all on the compositor's happy path
   — and makes it styleable, which the native popup never was. */
.picker{ position:relative; min-width:130px; }
.picker-btn{
  width:100%; display:flex; align-items:center; justify-content:space-between; gap:8px;
  background:rgba(255,255,255,.07); border:1px solid var(--edge); color:var(--ink);
  border-radius:8px; padding:5px 9px; font-size:12.5px;
}
.picker-btn:hover{ background:rgba(255,255,255,.12); }
.picker-btn i{ font-style:normal; color:var(--ink-faint); font-size:10px; }
.picker-list{
  position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:5;
  background:#0d1f30; border:1px solid var(--edge-hi); border-radius:9px;
  overflow:hidden; box-shadow:0 10px 28px rgba(0,0,0,.55);
}
.picker-list button{
  display:block; width:100%; text-align:left; padding:7px 10px;
  font-size:12.5px; color:var(--ink);
}
.picker-list button:hover{ background:rgba(53,224,208,.16); color:var(--teal); }
.picker-list button.sel{ color:var(--teal); font-weight:650; }

.setrow select, .setrow input[type=text]{
  background:rgba(255,255,255,.07); border:1px solid var(--edge); color:var(--ink);
  border-radius:8px; padding:5px 9px; font-family:inherit; font-size:12.5px; outline:none; min-width:130px;
  /* The popup list is drawn by the OS and does NOT inherit these colours —
     it defaults to a white sheet, which made white option text invisible. */
  color-scheme: dark;
}
.setrow select option{ background:#0d1f30; color:var(--ink); }
.setrow select:focus-visible, .setrow input[type=text]:focus-visible{
  outline: 2px solid var(--teal); outline-offset: 1px;
}
.setrow .val{
  min-width:52px; text-align:right; color:var(--teal);
  font-variant-numeric:tabular-nums; font-size:12px;
}
.setrow .withval{ display:flex; align-items:center; gap:8px; }
.setrow input[type=range]{ width:150px; accent-color:var(--teal); }
.setrow input[type=checkbox]{ width:17px; height:17px; accent-color:var(--teal); cursor:pointer; }
.modal-actions{ display:flex; gap:8px; margin-top:16px; flex-wrap:wrap; }
.modal-actions .btn{ flex:1; min-width:120px; }
.fineprint{ font-size:10.5px; color:var(--ink-faint); line-height:1.6; margin:14px 0 0; }

/* ── crate ────────────────────────────────────────────── */
.crate-desc{ font-size:12.5px; color:var(--ink-dim); line-height:1.6; margin:0 0 12px; }
.crate-odds{ display:flex; flex-wrap:wrap; gap:5px; margin-bottom:14px; }
.odd{ font-size:10px; padding:3px 8px; border-radius:6px; background:rgba(255,255,255,.06); letter-spacing:.05em; }
.crate-stage{
  min-height:150px; border-radius:14px; border:1px dashed var(--edge);
  display:grid; place-items:center; text-align:center; padding:16px;
  background:radial-gradient(ellipse at 50% 60%, rgba(53,224,208,.07), transparent 70%);
}
.crate-stage .reveal{ animation:reveal .7s cubic-bezier(.2,1.5,.4,1); }
@keyframes reveal{ 0%{opacity:0; transform:scale(.4) rotate(-16deg)} 60%{transform:scale(1.14) rotate(4deg)} 100%{opacity:1; transform:none} }
.crate-stage .rname{ font-size:22px; font-weight:700; margin:8px 0 2px; }
.crate-stage .rrar{ font-size:10px; letter-spacing:.22em; text-transform:uppercase; font-weight:800; }
.crate-stage .rsvg{ width:120px; height:80px; }
.crate-stage .idle{ color:var(--ink-faint); font-size:12.5px; }

#fps{
  position:fixed; z-index:90; bottom:6px; left:8px; font-size:11px;
  color:var(--teal); font-variant-numeric:tabular-nums;
  text-shadow:0 1px 4px #000; pointer-events:none;
}

/* ── mobile ───────────────────────────────────────────── */
@media (max-width:640px){
  .vitals{ width:150px; padding:9px 10px 6px; }
  .dial-bezel{ --d:38px; }
  .inspector{ top:auto; bottom:96px; left:8px; width:calc(100vw - 16px); max-width:290px; }
  .dockbtn{ width:48px; }
  .dockbtn svg, .dockbtn .glyph{ width:34px; height:34px; }
  .wallet{ padding:7px 12px; }
}

/* ══════════════════════════════════════════════════════════════════════
   Journal — a book. Sections on the spine, one page at a time.

   The collection views exist to make *absence* legible: an unowned species
   is drawn as a silhouette with its rarity and blurb intact, never as an
   empty slot, so the size of what is left is visible at a glance.
   ══════════════════════════════════════════════════════════════════════ */

#journal .book {
  display: flex; width: min(1020px, 94vw); height: min(680px, 88vh);
  border-radius: 16px; overflow: hidden; position: relative;
  background: linear-gradient(160deg, #16212f, #0e1620);
  border: 1px solid rgba(150, 190, 230, .16);
  box-shadow: 0 30px 90px rgba(0, 0, 0, .55);
}
#journal .x { position: absolute; top: 10px; right: 12px; z-index: 3; }

.book-spine {
  width: 176px; flex: 0 0 176px; display: flex; flex-direction: column;
  padding: 18px 12px 12px; gap: 4px;
  background: linear-gradient(180deg, rgba(28, 44, 62, .95), rgba(16, 26, 38, .95));
  border-right: 1px solid rgba(150, 190, 230, .14);
}
.book-title {
  font-size: 13px; letter-spacing: .16em; text-transform: uppercase;
  color: #7f9dc0; margin: 0 0 12px 6px;
}
.book-tabs { display: flex; flex-direction: column; gap: 2px; }
.btab {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: 9px; cursor: pointer;
  background: transparent; color: #b9cde3; font: inherit; font-size: 14px;
  text-align: left; transition: background .13s, color .13s;
}
.btab i { font-style: normal; font-size: 15px; opacity: .85; }
.btab:hover { background: rgba(120, 170, 220, .10); }
.btab.active { background: rgba(90, 150, 220, .20); color: #eaf3ff; }
.book-foot {
  margin-top: auto; padding: 10px 8px 4px; font-size: 12px; line-height: 1.5;
  color: #6f8aa8; border-top: 1px solid rgba(150, 190, 230, .12);
}

/* Narrower than the 176px spine leaves room for on a phone-width modal. */
@media (max-width:640px){
  .book-spine{ width:120px; flex:0 0 120px; padding:14px 8px 8px; }
  .book-title{ font-size:11px; margin-bottom:8px; }
  .btab{ padding:8px 6px; font-size:12.5px; gap:6px; }
  .book-foot{ font-size:10.5px; padding:8px 6px 2px; }
}

.book-page { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.book-head { padding: 20px 24px 12px; border-bottom: 1px solid rgba(150, 190, 230, .12); }
.book-head h2 { margin: 0; font-size: 21px; letter-spacing: .01em; }
.book-head p { margin: 4px 0 0; font-size: 13px; color: #86a0bd; }
.book-body { flex: 1; overflow-y: auto; padding: 16px 24px 24px; }

/* ── shared entry grid ── */
.jgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 10px; }
.jgroup {
  grid-column: 1 / -1; margin: 14px 0 2px; font-size: 11px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: #7f9dc0;
}
.jgroup:first-child { margin-top: 0; }

.jcard {
  display: flex; gap: 10px; align-items: center; padding: 9px 10px;
  border-radius: 11px; background: rgba(255, 255, 255, .035);
  border: 1px solid rgba(150, 190, 230, .11);
}
.jcard.locked { opacity: .58; }
.jcard .jthumb {
  width: 56px; height: 40px; flex: 0 0 56px; border-radius: 7px;
  background: rgba(0, 0, 0, .22); display: grid; place-items: center; overflow: hidden;
}
.jcard .jthumb img { width: 100%; height: 100%; object-fit: contain; }
/* An undiscovered species shows its outline, not a blank tile. */
.jcard.locked .jthumb img { filter: brightness(0) saturate(0) opacity(.42); }
.jcard .jmeta { min-width: 0; flex: 1; }
.jcard .jname {
  font-size: 14px; font-weight: 600; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.jcard .jsub {
  font-size: 11.5px; color: #86a0bd; margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jcard .jtag { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; }
.jcard .jcount {
  font-size: 12px; color: #9fc7ee; background: rgba(90, 150, 220, .16);
  border-radius: 20px; padding: 2px 8px; flex: 0 0 auto;
}

/* ── residents ── */
.jres { cursor: pointer; transition: background .13s, border-color .13s; }
.jres:hover { background: rgba(120, 170, 220, .11); border-color: rgba(150, 190, 230, .24); }

/* ── goals ── */
.goal { padding: 12px 14px; border-radius: 12px; background: rgba(255, 255, 255, .035);
        border: 1px solid rgba(150, 190, 230, .11); margin-bottom: 9px; }
.goal-top { display: flex; align-items: baseline; gap: 10px; }
.goal-name { font-size: 14.5px; font-weight: 600; flex: 1; }
.goal-tier { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: #7f9dc0; }
.goal-desc { font-size: 12.5px; color: #86a0bd; margin: 3px 0 8px; }
.goal-bar { height: 6px; border-radius: 4px; background: rgba(0, 0, 0, .3); overflow: hidden; }
.goal-bar i { display: block; height: 100%; border-radius: 4px;
              background: linear-gradient(90deg, #3d8fe0, #63c8ff); transition: width .4s; }
.goal-foot { display: flex; justify-content: space-between; margin-top: 6px;
             font-size: 11.5px; color: #7f9dc0; }

/* ── dev/admin panel ─────────────────────────────────── */
.dev-panel {
  top: 14px; right: 14px; width: 300px; max-height: calc(100vh - 28px);
  display: flex; flex-direction: column; padding: 12px;
  transform: translateX(calc(100% + 14px)); opacity: 0;
  transition: transform .18s ease, opacity .18s ease;
  pointer-events: none;
}
.dev-panel.open { transform: none; opacity: 1; pointer-events: auto; }
.dev-head { justify-content: space-between; align-items: center; margin-bottom: 4px; }
.dev-section { margin-top: 10px; }
.dev-label { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: #7f9dc0; margin-bottom: 5px; }
.dev-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.dev-select {
  flex: 1; min-width: 0; font-family: inherit; font-size: 12.5px; color: inherit;
  background: rgba(255, 255, 255, .05); border: 1px solid var(--edge); border-radius: 8px; padding: 6px 8px;
  /* The popup list is drawn by the OS and does NOT inherit these colours —
     it defaults to a white sheet, which made white option text invisible.
     Same fix as .setrow select. */
  color-scheme: dark;
}
.dev-select option { background: #0d1f30; color: var(--ink); }
.dev-hint { font-size: 11px; color: #7f9dc0; }
.dev-close {
  width: 26px; height: 26px; line-height: 1; border-radius: 8px; font-size: 16px;
  color: var(--ink-dim); display: grid; place-items: center; flex-shrink: 0;
}
.dev-close:hover { background: rgba(255, 255, 255, .09); color: var(--ink); }
.dev-list { flex: 1; overflow-y: auto; margin-top: 4px; }
.dev-list-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 4px; border-bottom: 1px solid rgba(150, 190, 230, .1);
}
.dev-list-name { font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dev-list-actions { display: flex; gap: 4px; flex: 0 0 auto; }
.goal.done .goal-bar i { background: linear-gradient(90deg, #35b57a, #6fe0a8); }
.goal.mystery .goal-name { color: #6f8aa8; letter-spacing: .18em; }

.jempty { color: #7f9dc0; font-size: 13.5px; padding: 26px 4px; text-align: center; }

/* ── reduced motion ───────────────────────────────────────
   A "must" in every current UI guideline, and on a weak phone it is a
   performance lever too: every transition here animates a paint property
   (colour, background, box-shadow, width), so honouring the preference also
   removes those repaints. The canvas keeps animating — this is chrome only,
   and the tank *is* the content. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
