/* ── Design tokens ─────────────────────────────────────────────────────────
   One place to tune the whole UI. Overlays/panels/buttons below consume these
   via the shared .overlay / .panel / .btn classes, so surfaces stay consistent
   and a look change is a one-line edit here. */
:root {
  color-scheme: dark; /* our UI is dark; stops the browser from auto-inverting colors */

  --panel-bg: rgba(15, 20, 32, .72);
  --panel-border: 1px solid rgba(255, 255, 255, .12);
  --panel-radius: 16px;
  --panel-shadow: 0 24px 60px rgba(0, 0, 0, .5);
  --panel-max-h: 92dvh; /* every overlay card fits the viewport by default; override per-panel */

  --overlay-dim: radial-gradient(ellipse at center, rgba(20, 30, 48, .55), rgba(10, 14, 24, .85));
  --overlay-blur: blur(3px);

  --accent: #4caf50;
  --accent-bright: #8be07a;
  --accent-bright-rgb: 139, 224, 122; /* #8be07a as rgb, for rgba() alpha variants */
  --accent-ink: #0c1a0c;    /* text on an accent-filled button */
  --accent-tint: #eafbe4;   /* light-green text on active/selected items */
  --text: #e6edf6;
  --text-dim: #c7d0de;
  --fire: #ff9a2b;          /* furnace burn gauge / flame */
  --fire-rgb: 255, 154, 43; /* …as rgb, for rgba() alpha variants (cf. --accent-bright-rgb) */
}

/* ── Overlay + panel primitives ────────────────────────────────────────────
   .overlay = the full-screen dim+blur scrim that centres a panel. Each modal
   keeps its own id only for z-index and show/hide. .panel = the card. */
.overlay {
  position: fixed; inset: 0;
  align-items: center; justify-content: center;
  background: var(--overlay-dim);
  -webkit-backdrop-filter: var(--overlay-blur); backdrop-filter: var(--overlay-blur);
  /* No double-tap-to-zoom anywhere in an overlay. The viewport meta already says
     user-scalable=no, but iOS has ignored that since iOS 10, so a double-tap-and-drag over panel
     text zoomed the whole page — easy to trigger now that tapping is how you move items.
     `manipulation` kills the double-tap gesture while leaving panning and pinch alone, so the
     panels that scroll internally still do. Set on the kit's shared class, not per panel, since
     every overlay has the same problem. */
  touch-action: manipulation;
}
.panel {
  position: relative;
  background: var(--panel-bg);
  border: var(--panel-border);
  border-radius: var(--panel-radius);
  box-shadow: var(--panel-shadow);
  /* Fit the viewport and scroll inside the card instead of clipping off the top/bottom
     (landscape phones are short). This is THE shared fix — new panels get it for free.
     "Framed" panels (inventory, game menu, containers) scroll an inner region instead, so
     their card never actually scrolls and the header/✕ stay pinned; here it's a harmless
     fallback. Override the cap per-panel with --panel-max-h. */
  max-height: var(--panel-max-h); /* always defined at :root */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

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

html, body {
  width: 100%;
  height: 100dvh;
  overflow: hidden;
  background: #0b1018;
  font-family: "Segoe UI", Roboto, system-ui, sans-serif;
  color: #fff;
  /* Never let the browser inflate our text. Mobile engines "boost" font sizes when a container's
     layout changes — scrolling a panel was enough to trigger it, and the tell was that text
     OUTSIDE the scrolling area grew too, which pinch-zoom would never do. It's a text-autosizing
     heuristic meant for desktop-width pages, and this is a game UI sized to the viewport, so it's
     never wanted. Same family of problem as the Chrome force-dark gotcha: an engine feature
     helpfully rewriting a UI that didn't ask for it. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* No text selection / iOS long-press magnifier-callout on the game UI. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  overscroll-behavior: none;
}

#game { display: block; width: 100dvw; height: 100dvh; touch-action: none; }

/* Underwater tint — a translucent blue wash over the whole view while submerged */
#underwater {
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s ease;
  background:
    radial-gradient(ellipse at center, rgba(30,90,150,0.18), rgba(12,45,95,0.42)),
    rgba(28,86,150,0.32);
}
#underwater.active { opacity: 1; }

/* Hurt vignette — a red edge-flash pulsed on the whole view when a hostile mob hits you */
#hurt {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(ellipse at center, rgba(150,0,0,0) 42%, rgba(150,0,0,0.6) 100%);
}
#hurt.flash { animation: hurt-flash .45s ease-out; }
@keyframes hurt-flash { from { opacity: .9; } to { opacity: 0; } }

/* Crosshair */
/* The finger ring for touch's block-aim mode. Purely a "your touch landed here" cue — it tracks
   the finger, so it has to be cheap to move: transform only, no layout. */
#touchRing {
  /* Sized to a thumb tip — it stands in for the crosshair, so it should read as "here's where
     you're pointing" at a glance without hunting for it. The centring margin is DERIVED from the
     size so the two can't drift apart when this gets tuned again. */
  --ring: 88px;
  position: fixed; top: 0; left: 0;
  width: var(--ring); height: var(--ring);
  margin: calc(var(--ring) / -2) 0 0 calc(var(--ring) / -2);
  border: 2px solid rgba(255, 255, 255, .85);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .45), inset 0 0 0 1px rgba(0, 0, 0, .35);
  pointer-events: none;
  opacity: 0;
  z-index: 4;
  transition: opacity .12s ease;
}
#touchRing.active { opacity: .9; }
/* While actually breaking, the ring fills in — the same "something is happening here" the crack
   overlay gives on desktop, at the point you're actually looking. */
#touchRing.breaking { border-color: var(--accent-bright); background: rgba(var(--accent-bright-rgb), .18); }

#crosshair {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 22px; height: 22px;
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s;
  mix-blend-mode: difference;
}
#crosshair.active { opacity: .85; }
#crosshair span {
  position: absolute;
  background: #fff;
}
#crosshair span:nth-child(1) { top: 50%; left: 0; width: 100%; height: 2px; transform: translateY(-50%); }
#crosshair span:nth-child(2) { left: 50%; top: 0; height: 100%; width: 2px; transform: translateX(-50%); }

/* HUD / hotbar */
#hud {
  position: fixed;
  left: 0; right: 0; bottom: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s;
}
#hud.active { opacity: 1; }

/* Survival vitals: hearts (health) above the hotbar, air bubbles above hearts. */
#vitals { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.vit-hearts, .vit-hunger, .vit-bubbles, .vit-armor { display: flex; gap: 2px; }
/* A pip = a dark bg icon with a coloured fg clipped over it (full/half/empty). */
.vit-pip { position: relative; width: 18px; height: 18px; filter: drop-shadow(0 1px 1px rgba(0,0,0,.6)); }
.vit-pip > svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; } /* bg, full-size */
.vit-pip-clip { position: absolute; inset: 0; overflow: hidden; }
.vit-pip-clip svg { position: absolute; top: 0; left: 0; width: 18px; height: 18px; display: block; } /* fg, fixed */
.vit-heart-bg { fill: #40161a; } .vit-heart-fg { fill: #ff4444; }
.vit-food-bg { fill: #2e1e10; } .vit-food-fg { fill: #c9803e; }
.vit-armorpip-bg { fill: #232833; } .vit-armorpip-fg { fill: #cdd6e6; } /* steel armor bar */
.vit-bubble {
  width: 12px; height: 12px; border-radius: 50%;
  background: rgba(0,0,0,.3); border: 1px solid rgba(0,0,0,.4);
}
.vit-bubble.full {
  background: radial-gradient(circle at 35% 30%, #cdeeff, #4aa3e0); border-color: rgba(255,255,255,.4);
}
/* On touch, the hotbar is tappable (above the look pad) to select slots. */
body.is-touch #hud { z-index: 6; }
body.is-touch #hotbar { pointer-events: auto; touch-action: none; }

#hotbar {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: rgba(0,0,0,.35);
  border: 2px solid rgba(0,0,0,.5);
  border-radius: 6px;
}

/* Death screen (survival): a red scrim over the world. */
#death { display: none; z-index: 24; background: radial-gradient(ellipse at center, rgba(96,22,22,.55), rgba(18,6,6,.9)); }
#death.active { display: flex; }
.death-panel { text-align: center; padding: 34px 48px; }
.death-title { font-size: 34px; letter-spacing: 2px; color: #ff6b6b; margin: 0 0 20px; }
.slot {
  position: relative;
  width: 52px; height: 52px;
  background: rgba(255,255,255,.08);
  border: 2px solid rgba(255,255,255,.15);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.slot.selected {
  border-color: #fff;
  box-shadow: 0 0 0 2px rgba(255,255,255,.4);
  transform: scale(1.06);
}
.slot canvas { width: 38px; height: 38px; image-rendering: pixelated; border-radius: 2px; }
.slot .num {
  position: absolute;
  top: 1px; left: 4px;
  font-size: 11px;
  opacity: .6;
  text-shadow: 1px 1px 0 #000;
}
.slot .label {
  position: absolute;
  bottom: -20px; left: 50%;
  transform: translateX(-50%);
  font-size: 11px;
  white-space: nowrap;
  text-shadow: 1px 1px 0 #000;
  opacity: 0;
  transition: opacity .2s;
}
.slot.selected .label { opacity: 1; }
/* survival stack count (bottom-right) and empty (depleted) state */
.slot .count {
  position: absolute;
  bottom: 1px; right: 3px;
  font-size: 12px; font-weight: 700;
  text-shadow: 1px 1px 0 #000, -1px 0 0 #000;
}
.slot.empty canvas { opacity: .28; }
.slot.empty .count { opacity: .6; }
/* Main inventory grid: real slots you can drag between (empty ones are drop targets). */
/* The main inventory is 27 slots = THREE ROWS OF NINE, mirroring the hotbar below it — nine is
   the load-bearing number, since the hotbar is bound to keys 1-9. auto-fill packed whatever the
   width allowed, which came out 12 + 12 + 3 and read as an accident rather than a grid.
   Narrow screens keep auto-fill: nine 56px cells need ~590px including the panel's padding, and
   forcing them on a phone would overflow the card. */
#invItems { display: grid; grid-template-columns: repeat(auto-fill, 56px); gap: 4px; justify-content: center; }
@media (min-width: 620px) { #invItems { grid-template-columns: repeat(9, 56px); } }
#invItems .slot { cursor: pointer; }
/* Dragging a slot must not scroll the panel under your finger, and the drop target is resolved
   by coordinates — so the children mustn't swallow the hit test either. Scoped to the DRAGGABLE
   slots: the armor cells are plain click targets and must stay scrollable. */
/* Slots inside the PANEL must let a finger scroll past them. `touch-action: none` here was for
   the old drag-to-move, which no longer exists — and it meant a scroll that happened to start on
   a slot was swallowed, so the inventory wouldn't scroll and the gesture went somewhere worse.
   pan-y scrolls the list while still suppressing the double-tap/pinch that zoomed the page.
   The HUD hotbar keeps `none`: it isn't in a scroller, and a drag from it should never pan. */
#invItems .slot, #invHotbar .slot { touch-action: pan-y; }
#hotbar .slot { touch-action: none; }
#invItems .slot > *, #hotbar .slot > *, #invHotbar .slot > * { pointer-events: none; }
/* (.slot.dragging and the old .slot.splitting outline went with the drag model — the carry
   styling lives with the tap interaction further down.) */

/* Armor row in the inventory footer: 4 equipped slots (click a worn piece to take it off). */
.inv-armor { display: flex; gap: 6px; margin-bottom: 10px; }
/* Armor screen: left-align the Available grid so it lines up with the Worn slots above
   (the shared .inv-grid centres its row), and give the "Available" heading room to breathe. */
.inv-armor-slots .inv-grid { justify-content: start; }
.inv-armor-slots .inv-sub { margin-top: 20px; }
.inv-armor-slots .inv-sub:first-child { margin-top: 0; }
.armor-slot { width: 46px; height: 46px; }
.armor-slot:not(.empty) { cursor: pointer; border-color: rgba(var(--accent-bright-rgb), .5); }
.armor-slot .label { font-size: 10px; opacity: .5; letter-spacing: .5px; }
/* Tool durability bar — shown only on a worn tool; fill colour goes green→red as it wears.
   Applies to every surface an item can sit in (hotbar, inventory grid, armour row, and the
   container panels' own cells), so wear is visible wherever the item is. */
.fn-slot { position: relative; }
.slot .dura, .fn-slot .dura { position: absolute; left: 4px; right: 4px; bottom: 3px; height: 3px; background: rgba(0,0,0,.6); border-radius: 2px; overflow: hidden; }
.slot .dura i, .fn-slot .dura i { display: block; height: 100%; }

/* Inventory */
#inventory { display: none; z-index: 12; }
#inventory.active { display: flex; }

/* Profile creator: name on top; a category rail, 3D preview, and the active category's
   controls below — all rendered from the avatar-config registry. */
#profile { display: none; z-index: 16; }
#profile.active { display: flex; }
.profile-panel { width: 680px; max-width: 94vw; padding: 22px 26px 24px; } /* fit+scroll from .panel */
.pf-name-row { margin-top: 4px; text-align: left; }
.pf-name-row input {
  width: 100%; padding: 10px 12px; font-size: 15px; color: #eaf1f8;
  background: rgba(0,0,0,.3); border: 1px solid rgba(255,255,255,.18); border-radius: 8px;
}
.pf-name-row input:focus { outline: none; border-color: rgba(var(--accent-bright-rgb), .6); }
.profile-body { display: flex; gap: 18px; margin-top: 10px; text-align: left; align-items: flex-start; }
/* Category rail (left). */
.pf-rail { flex: 0 0 108px; display: flex; flex-direction: column; gap: 4px; }
.pf-rail-btn {
  padding: 9px 12px; text-align: left; font-size: 14px; font-weight: 600; color: var(--text-dim);
  background: transparent; border: none; border-radius: 8px; cursor: pointer;
}
.pf-rail-btn:hover { background: rgba(255,255,255,.06); }
.pf-rail-btn.active { background: rgba(var(--accent-bright-rgb), .16); color: var(--accent-tint); }
/* Preview column (middle): the 3D canvas + action buttons. */
.pf-preview-col { flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; align-items: center; }
.profile-preview {
  width: 220px; height: 300px; border: 1px solid rgba(255,255,255,.1); border-radius: 12px;
  background: radial-gradient(ellipse at 50% 38%, rgba(64,78,104,.4), rgba(6,9,16,.55));
  cursor: grab; touch-action: none; /* drag to rotate; don't scroll the page on touch */
}
.profile-preview.grabbing { cursor: grabbing; }
.pf-actions { display: flex; gap: 8px; }
.pf-actions .btn { margin-top: 0; font-size: 12px; padding: 7px 12px; }
/* Controls for the active category (right). */
.pf-controls { flex: 1; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.pf-controls .set-row label { font-size: 13px; }
.pf-seg { display: flex; gap: 6px; flex-wrap: wrap; }
.pf-seg.pf-grid { display: grid; }          /* even columns → uniform width, rows fill */
.pf-seg.pf-center { justify-content: center; } /* fallback for counts that can't fill */
.pf-seg-btn {
  flex: 0 1 auto; padding: 8px 12px; font-size: 13px; font-weight: 600; color: var(--text-dim);
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.12);
  border-radius: 8px; cursor: pointer;
}
.pf-seg-btn:hover { background: rgba(255,255,255,.1); }
.pf-seg-btn.active { background: rgba(var(--accent-bright-rgb), .18); border-color: rgba(var(--accent-bright-rgb), .5); color: var(--accent-tint); }
/* Colour control: a labelled row with the swatch on the right. */
.pf-color-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 14px; color: var(--text); padding: 7px 12px;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.1); border-radius: 8px;
}
.pf-color-row input[type="color"] {
  width: 46px; height: 28px; padding: 0; border: none; border-radius: 5px; background: none; cursor: pointer;
}
/* One consistent focus treatment — no stray click-ring, a clear keyboard ring. */
.pf-rail-btn:focus, .pf-seg-btn:focus { outline: none; }
.pf-rail-btn:focus-visible, .pf-seg-btn:focus-visible {
  outline: 2px solid rgba(var(--accent-bright-rgb), .6); outline-offset: 1px;
}
/* Portrait (rare — the app is landscape-locked): stack so the wide 3-column row doesn't
   overflow the width. In landscape the default row layout is shorter and uses the space. */
@media (orientation: portrait) {
  .profile-body { flex-direction: column; align-items: stretch; }
  .pf-rail { flex-direction: row; flex-wrap: wrap; flex-basis: auto; }
  .pf-preview-col { align-self: center; }
}
/* Short landscape (phones): shrink the tall preview + tighten so the row fits without scroll. */
@media (max-height: 520px) {
  .profile-panel { padding: 14px 22px 16px; }
  .profile-body { gap: 12px; margin-top: 8px; }
  .profile-preview { width: 150px; height: 205px; }
}

/* Unified game/settings modal — tabs down the left, one page on the right. */
#gameMenu { display: none; z-index: 22; }
#gameMenu.active { display: flex; }
.gm-panel {
  display: flex; gap: 0;
  width: 660px; max-width: 94vw; height: 520px; max-height: 90dvh;
  overflow: hidden; /* framed: fixed-height card clips; .gm-content scrolls (keeps tabs pinned) */
}
.gm-tabs {
  display: flex; flex-direction: column; gap: 4px; padding: 22px 14px;
  background: rgba(0,0,0,.22); border-right: 1px solid rgba(255,255,255,.08); flex: 0 0 170px;
}
.gm-tab {
  padding: 12px 16px; text-align: left; font-size: 15px; font-weight: 600;
  color: #c7d0de; background: transparent; border: none; border-radius: 8px; cursor: pointer;
}
.gm-tab:hover { background: rgba(255,255,255,.06); }
.gm-tab.active { background: rgba(140,224,122,.16); color: #eafbe4; }
.gm-tab[hidden] { display: none; }
/* padding-top clears the ✕, which floats over the panel's top-right corner (.inv-x, absolute to
   the .panel). The other framed panels get away with 32px because their first row is a
   left-aligned <h2> that the button sits beside — these pages open with FULL-WIDTH controls
   (Resume, the option buttons), so anything less runs underneath it. ✕ is top:14px + 38px tall,
   so 60 leaves it clear with a little air. */
.gm-content { flex: 1; padding: 60px 34px 26px; overflow-y: auto; text-align: left; }
/* Center the capped-width page in the content area so leftover space is balanced, not a
   lopsided gap on the right (esp. on touch, where the panel is much wider than the page). */
.gm-page { display: flex; flex-direction: column; gap: 16px; max-width: 420px; margin-inline: auto; }
.gm-page[hidden] { display: none; }
.gm-opts { display: flex; flex-direction: column; gap: 8px; }
/* Settings controls (used inside the Video/Controls pages). */
.set-row { display: flex; flex-direction: column; gap: 6px; }
.set-row label { font-size: 14px; color: #e6edf6; }
.set-val { float: right; opacity: .7; font-variant-numeric: tabular-nums; }
.set-hint { font-size: 11.5px; opacity: .5; margin: 2px 0 0; }
.set-row input[type="range"] { width: 100%; accent-color: #4caf50; }
.set-toggle { flex-direction: row; align-items: center; justify-content: space-between; }
.set-toggle input { width: 18px; height: 18px; accent-color: #4caf50; }
/* Key bindings table (Controls page) — a table now so it can become editable later. */
.kb-title { margin-top: 8px; font-size: 12px; letter-spacing: .5px; text-transform: uppercase; opacity: .5; }
.keybinds { width: 100%; border-collapse: collapse; }
.keybinds td { padding: 6px 0; border-bottom: 1px solid rgba(255,255,255,.07); vertical-align: middle; }
.kb-action { font-size: 13.5px; color: #dbe3ee; }
.kb-keys { text-align: right; }
.keybinds kbd {
  display: inline-block; margin-left: 3px; padding: 2px 7px; font: inherit; font-size: 11.5px;
  color: #e8eef7; background: rgba(255,255,255,.09); border: 1px solid rgba(255,255,255,.18);
  border-bottom-width: 2px; border-radius: 5px;
}
body.is-touch .gm-panel { width: 92vw; height: auto; max-height: 88dvh; }
body.is-touch .gm-tabs { flex-basis: 108px; padding: 12px 8px; }
.inv-panel { /* framed: .panel caps the card; .inv-body scrolls so header + hotbar stay pinned */
  width: min(880px, 94vw);
  display: flex;
  flex-direction: column;
  padding: 24px 28px 20px;
}
/* In CREATIVE the card takes a fixed height, so filtering the palette doesn't resize it.
   Without this the card sizes to its content, and typing in the search box made it shrink a row
   at a time under the cursor — the controls moving while you use them. Survival is left to size
   itself, since it has no palette and a fixed height would just be dead space. */
body.creative .inv-panel { height: min(660px, 88dvh); }
/* Header stays put, the item grid scrolls, the hotbar footer is always visible —
   so the slot you're assigning to is on screen while you browse items. */
.inv-head { flex: 0 0 auto; padding-right: 44px; } /* clear the absolute ✕ */
.inv-body { flex: 1 1 auto; overflow-y: auto; min-height: 0; }
/* Tabbed inventory: a vertical tab rail (like Settings/Profile) + a scrolling page area, so
   the tabs stay pinned and only the active page scrolls. */
.inv-body.inv-tabbed { display: flex; gap: 16px; overflow: hidden; }
.inv-tabs { display: flex; flex-direction: column; gap: 4px; flex: 0 0 auto; }
.inv-tab {
  padding: 10px 16px; text-align: left; font-size: 14px; font-weight: 600;
  color: #c7d0de; background: transparent; border: none; border-radius: 8px; cursor: pointer;
}
.inv-tab:hover { background: rgba(255,255,255,.06); }
.inv-tab.active { background: rgba(var(--accent-bright-rgb), .16); color: var(--accent-tint); }
.inv-pages { flex: 1 1 auto; overflow-y: auto; min-height: 0; }
.inv-page[hidden] { display: none; }
body.is-touch .inv-pages { -webkit-overflow-scrolling: touch; }
/* Armor screen: the 3D avatar preview beside the worn-armor slots. */
.inv-armor-screen { display: flex; gap: 18px; align-items: flex-start; }
.inv-armor-preview {
  flex: 0 0 auto; width: 200px; height: 300px; border-radius: 12px; touch-action: none; cursor: grab;
  background: radial-gradient(ellipse at 50% 38%, rgba(64,78,104,.4), rgba(6,9,16,.55));
  border: 1px solid rgba(255,255,255,.1);
}
.inv-armor-preview.grabbing { cursor: grabbing; }
.inv-armor-slots { flex: 1; min-width: 0; }
@media (max-width: 560px) { .inv-armor-screen { flex-direction: column; align-items: center; } }
.inv-foot {
  flex: 0 0 auto;
  border-top: 1px solid rgba(255,255,255,.12);
  margin-top: 12px;
}
.inv-foot .inv-sub { margin: 10px 0 8px; }
/* Two columns side by side (Your items + palette | Crafting) — only in creative,
   where the palette fills a column. Survival is lighter, so a single column.
   Also stacks to one column when narrow. */
.inv-cols { display: flex; gap: 22px; align-items: flex-start; }
.inv-col { flex: 1; min-width: 0; }
body:not(.creative) .inv-cols { display: block; }
@media (max-width: 560px) { .inv-cols { display: block; } }
/* Always-visible close in the panel's top-right corner (panel no longer scrolls;
   its body does), so you never have to scroll to close it. */
.inv-x {
  position: absolute;
  top: 14px; right: 16px;
  width: 38px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; line-height: 1; color: #fff;
  /* The chip tint over a second layer of the panel colour. It floats above an inner scroll
     region in every framed panel, so a single translucent layer let scrolled text read straight
     through it — doubling the panel tint keeps it a solid-looking button without hard-coding a
     colour outside the tokens. */
  background: linear-gradient(rgba(255,255,255,.08), rgba(255,255,255,.08)), var(--panel-bg);
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 10px;
  cursor: pointer;
  z-index: 3;
}
.inv-x:hover { background: linear-gradient(rgba(255,255,255,.18), rgba(255,255,255,.18)), var(--panel-bg); }
.inv-panel h2 { font-size: 22px; letter-spacing: 2px; }
/* Headings and hints are chrome, not content: a finger dragged across them should do nothing at
   all rather than start a selection or a gesture. */
/* Headings and hints are chrome, not content: no selection. They still allow pan-y, because they
   sit inside the scrolling region and `none` would swallow a scroll that began on the text —
   which is the same mistake the slots had. */
.inv-head, .inv-sub, .inv-hint { touch-action: pan-y; -webkit-user-select: none; user-select: none; }
.inv-hint { margin: 6px 0 16px; font-size: 12px; line-height: 1.5; opacity: .6; }
.inv-hint b { color: #b6f0a8; }
.inv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, 64px);
  align-content: start;   /* few results stay top-aligned rather than stretching down the page */
  gap: 8px;
  justify-content: center;
}
.inv-item { touch-action: pan-y;
  width: 64px; height: 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  background: rgba(255,255,255,.06);
  border: 2px solid rgba(255,255,255,.12);
  border-radius: 6px;
  cursor: pointer;
  transition: background .12s, border-color .12s, transform .08s;
}
.inv-item:hover { background: rgba(255,255,255,.16); border-color: rgba(255,255,255,.4); transform: translateY(-2px); }
.inv-item canvas { width: 34px; height: 34px; image-rendering: pixelated; border-radius: 2px; }
.inv-name {
  font-size: 9px; opacity: .65; line-height: 1;
  max-width: 60px; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.inv-sub { margin: 22px 0 8px; font-size: 12px; letter-spacing: 2px; text-transform: uppercase; opacity: .55; }
.inv-faint { text-transform: none; letter-spacing: 0; opacity: .7; font-size: 11px; }
/* item count badge on inventory cells */
.inv-item .inv-count {
  position: absolute; right: 2px; bottom: 1px;
  font-size: 11px; font-weight: 700;
  text-shadow: 1px 1px 0 #000, -1px 0 0 #000;
}
.inv-item { position: relative; }
/* crafting recipe rows */
.inv-recipes { display: flex; flex-direction: column; gap: 6px; }
.inv-recipe {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.1);
  border-radius: 8px;
  opacity: .45;
}
.inv-recipe.craftable { opacity: 1; cursor: pointer; border-color: rgba(182,240,168,.4); }
.inv-recipe.craftable:hover { background: rgba(182,240,168,.14); }
.inv-recipe canvas { width: 30px; height: 30px; image-rendering: pixelated; }
.inv-recipe .r-out { font-size: 13px; font-weight: 600; min-width: 130px; }
.inv-recipe .r-in { font-size: 11px; opacity: .75; }
.inv-hotbar { display: flex; gap: 4px; justify-content: center; }
.inv-hotbar .slot { cursor: pointer; }
.inv-hotbar .slot .label { display: none; }

/* Worlds panel — same overlay/panel look as the inventory. */
/* (#worlds / .worlds-panel removed — dead since the world list moved into #menu's
   screens; the .world-* rows below are still live inside that screen.) */
/* The only scroll region on the world-select screen: fills the space between the pinned
   title and footer (flex: 1 + the min-height:0 ancestor chain) and scrolls internally.
   Worlds tile into as many columns as fit (2 on a landscape phone, 1 when narrow). */
.world-list {
  flex: 1 1 auto; overflow-y: auto; min-height: 48px; margin-bottom: 14px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 8px; align-content: start;
}
.world-row {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 12px; /* grid `gap` spaces the tiles now, so no per-row margin */
  background: rgba(255,255,255,.16);
  border: 1px solid rgba(255,255,255,.3);
  border-radius: 10px;
  transition: border-color .15s, background .15s;
}
.world-row:hover { background: rgba(140,224,122,.18); border-color: rgba(140,224,122,.6); }
.world-row.current { border-color: rgba(182,240,168,.5); background: rgba(182,240,168,.12); }
.world-info { flex: 1; min-width: 0; }
.world-name { font-size: 15px; display: flex; align-items: center; gap: 8px; }
.world-badge {
  font-size: 10px; text-transform: uppercase; letter-spacing: 1px;
  padding: 2px 6px; border-radius: 6px; color: #cdeec0;
  background: rgba(182,240,168,.18); border: 1px solid rgba(182,240,168,.35);
}
.world-meta { font-size: 12px; opacity: .55; margin-top: 2px; }
.world-load, .world-del { flex: 0 0 auto; padding: 8px 14px; font-size: 13px; }
.world-del { color: #f0b0a8; border-color: rgba(240,140,120,.35); }
/* Create is collapsed to a single button by default (keeps the list roomy on
   short screens); tapping it reveals the name/seed inputs. */
.world-create { flex: 0 0 auto; border-top: 1px solid rgba(255,255,255,.1); padding-top: 12px; }
#worldNewToggle { width: 100%; }
.world-create-form { display: none; }
.world-create.open #worldNewToggle { display: none; }
.world-create.open .world-create-form { display: block; }
.world-create-row { display: flex; gap: 8px; }
.world-create-row button { flex: 1; }
.w-input {
  width: 100%; margin-bottom: 8px; padding: 10px 12px;
  font-size: 14px; color: #fff; font-family: inherit;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.16); border-radius: 8px;
  outline: none;
  user-select: text; -webkit-user-select: text; /* body disables selection */
}
.w-input:focus { border-color: rgba(182,240,168,.5); }

/* Debug */
#debug {
  position: fixed;
  top: max(8px, env(safe-area-inset-top, 0px));
  left: max(8px, env(safe-area-inset-left, 0px));
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  text-shadow: 1px 1px 0 #000;
  pointer-events: none;
  white-space: pre;
  opacity: 0;
}
#debug.active { opacity: .85; }

/* Profiler overlay (top-right, toggle with P) */
#profiler {
  position: fixed;
  top: max(8px, env(safe-area-inset-top, 0px));
  right: max(8px, env(safe-area-inset-right, 0px));
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 12px;
  line-height: 1.45;
  text-shadow: 1px 1px 0 #000;
  pointer-events: none;
  white-space: pre;
  opacity: 0;
  z-index: 6;
}
#profiler.active { opacity: .9; }

/* Touch controls */
#touch { position: fixed; inset: 0; z-index: 4; display: none; }
#touch.active { display: block; }
#touch > * { pointer-events: auto; touch-action: none; }
#lookpad { position: absolute; inset: 0; }
#joystick {
  position: absolute;
  left: max(24px, env(safe-area-inset-left, 0px));
  bottom: max(24px, env(safe-area-inset-bottom, 0px));
  width: 124px; height: 124px; border-radius: 50%;
  background: rgba(255,255,255,.07); border: 2px solid rgba(255,255,255,.18);
}
#joyKnob {
  position: absolute; left: 50%; top: 50%;
  width: 52px; height: 52px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: rgba(255,255,255,.28); border: 2px solid rgba(255,255,255,.4);
}
/* Small utility cluster, top-right, out of the look area. */
#touchTop {
  position: absolute; display: flex; gap: 10px;
  top: max(12px, env(safe-area-inset-top, 0px));
  right: max(12px, env(safe-area-inset-right, 0px));
}
/* Jump (+ fly-down) on the right edge, vertically centred so the lower-right
   corner stays free for the look thumb. */
#touchRight {
  position: absolute; top: 50%; transform: translateY(-50%);
  right: max(16px, env(safe-area-inset-right, 0px));
  display: flex; align-items: center; gap: 12px;
}
#touchRight .tcol { display: flex; flex-direction: column; gap: 12px; }
.tbtn {
  width: 64px; height: 64px; border-radius: 50%;
  background: rgba(0,0,0,.38); border: 2px solid rgba(255,255,255,.22);
  color: #fff; font-size: 24px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  -webkit-user-select: none; user-select: none;
}
.tbtn:active { background: rgba(255,255,255,.22); transform: scale(.94); }
.tbtn.active { background: rgba(182,240,168,.28); border-color: rgba(182,240,168,.6); }
#touchTop .tbtn { width: 48px; height: 48px; font-size: 19px; }
#invClose { display: block; margin: 20px auto 0; }

/* Touch-friendly inventory (esp. short landscape phones): use the screen, scroll
   with momentum, and give recipes/close a bigger tap target. */
body.is-touch .inv-panel {
  width: 86vw;
  padding: 12px 16px 14px;
}
body.is-touch .inv-body { -webkit-overflow-scrolling: touch; }
body.is-touch .inv-panel h2 { font-size: 18px; }
body.is-touch .inv-hint { margin: 4px 0 10px; }
body.is-touch .inv-sub { margin: 14px 0 6px; }
body.is-touch .inv-recipe { padding: 11px 12px; }
body.is-touch .inv-item { width: 60px; height: 60px; }
body.is-touch #invClose { padding: 14px 32px; font-size: 16px; }

/* Menu */
#menu { display: flex; z-index: 10; transition: opacity .25s; }
#menu.hidden { opacity: 0; pointer-events: none; }
/* Live panorama backdrop: reveal the world around the menu card with a soft vignette (for
   contrast) instead of the flat overlay dim, and drop the blur so the moving world stays crisp.
   The .panel card keeps its own solid background, so the title/buttons stay fully legible.
   Override the tokens .overlay already consumes rather than the properties (UI-kit convention). */
body.menu-live #menu {
  --overlay-dim: radial-gradient(ellipse 120% 100% at 50% 42%, rgba(6, 10, 18, .28), rgba(6, 10, 18, .66));
  --overlay-blur: none;
}

/* Light "enter play" prompt over the rendered world (vs the heavy pause menu). */
#playPrompt {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 9;
  background: rgba(8, 12, 20, .5);
  backdrop-filter: blur(2px);
}
#playPrompt.active { display: flex; }
.play-prompt-inner {
  padding: 12px 26px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .5px;
  color: #eaf1f8;
  background: rgba(12, 18, 28, .62);
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 999px;
  box-shadow: 0 8px 26px rgba(0,0,0,.4);
}

/* #menu is now only the pre-game picker (the in-game menu is #gameMenu). */
/* Flex column so a screen's scroll region (the world list) can fill the space between
   the pinned title and footer and scroll on its own, instead of the whole dialog scrolling. */
#menuModeSelect { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* The pre-game menu is a stack of screens; one shows at a time. [hidden] on the
   others; :not([hidden]) so an ID/class display rule can't override the hidden attr. */
.menu-screen:not([hidden]) {
  display: flex; flex-direction: column; gap: 10px; margin: 24px auto 0;
  width: 300px; max-width: 82vw;
}
/* World select alone grows to fill the panel (flex:1 + the min-height:0 chain) so its list
   is the scroll region; the other screens stay content-sized (no stretch). It's also wider
   for the 2-column grid — inherited max-width:82vw caps it on narrow viewports. */
.menu-screen[data-screen="worldSelect"]:not([hidden]) {
  width: 560px; flex: 1 1 auto; min-height: 0;
}
/* Main screen: demote the utilities (Studio/Settings/Profile) into one compact row
   beneath the two hero buttons — keeps the column short enough to fit a landscape phone
   and gives Play/Multiplayer the visual weight. Buttons stay ≥44px tall for touch. */
.menu-secondary { display: flex; gap: 8px; }
.menu-secondary .btn { flex: 1; margin-top: 0; padding: 12px 8px; min-height: 44px; }
/* Rows and form fields read left-aligned; buttons stay centered (panel default). */
.menu-screen .world-info, .menu-screen .ws-field { text-align: left; }
.menu-screen[disabled] { opacity: .4; cursor: not-allowed; }
/* A world row in the select screen: name/meta on the left, Play + Edit on the right. */
.world-play, .world-edit { flex: 0 0 auto; font-size: 13px; border-radius: 8px; }
.world-play {
  height: 38px; padding: 0 18px; font-weight: 700; color: #0c1a0c;
  background: linear-gradient(180deg, #8be07a, #4caf50); border: none; cursor: pointer;
}
.world-play:hover { filter: brightness(1.06); }
/* ⚙ icon button: a fixed square so the glyph sits dead-centre (its font metrics
   otherwise ride high) and matches the Play button's height. */
/* Styled on its own (not .secondary) so no generic button rule can override its
   padding/size. Fixed square + centred inline SVG. */
.world-edit {
  display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: 38px; height: 38px; padding: 0;
  color: #cdd6e6; cursor: pointer;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 9px;
  transition: background .15s, border-color .15s;
}
.world-edit:hover { background: rgba(255,255,255,.16); border-color: rgba(255,255,255,.3); }
.world-edit svg { display: block; } /* symmetric viewBox → centres exactly */
.ws-field { display: flex; flex-direction: column; gap: 4px; }
.ws-field label { font-size: 12px; letter-spacing: .5px; opacity: .6; text-transform: uppercase; }
.ws-field input {
  padding: 10px 12px; font-size: 15px; color: #eaf1f8;
  background: rgba(0,0,0,.3); border: 1px solid rgba(255,255,255,.18); border-radius: 8px;
}
.ws-field input:focus { outline: none; border-color: rgba(139,224,122,.6); }
.ws-readonly { padding: 8px 0 2px; font-size: 15px; opacity: .7; }
.ws-note { font-size: 11.5px; line-height: 1.5; opacity: .55; margin: -2px 0 2px; }
.ws-note code { background: rgba(255,255,255,.1); padding: 1px 5px; border-radius: 4px; font-size: 11px; }
/* ── Buttons ─────────────────────────────────────────────────────────────────
   .btn base (small) + size/variant modifiers, all single-class — so the old
   `button.secondary` (0,1,1) vs `.mode-btn` (0,1,0) specificity trap is gone. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box;
  padding: 9px 22px; font-size: 13px; font-weight: 600;
  border: 1px solid transparent; border-radius: 9px; cursor: pointer;
  transition: background .15s, transform .1s, box-shadow .2s;
}
.btn[disabled] { opacity: .4; cursor: not-allowed; }
.btn-lg { padding: 14px 40px; font-size: 18px; font-weight: 700; letter-spacing: 1px; border-radius: 10px; }
.btn-primary {
  color: var(--accent-ink);
  background: linear-gradient(180deg, var(--accent-bright), var(--accent));
  box-shadow: 0 8px 24px rgba(76,175,80,.35);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 12px 30px rgba(76,175,80,.5); }
.btn-primary:active { transform: translateY(0); }
.btn-secondary {
  margin-top: 10px; color: #d8def0;
  background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.18);
}
.btn-secondary:hover { background: rgba(255,255,255,.16); }
.btn-danger { color: #f0b0a8; border-color: rgba(240,140,120,.35); }
.mode-back { margin-top: 6px; align-self: center; }
.mp-connect { display: flex; gap: 8px; }
#mpAddress {
  flex: 1;
  padding: 11px 12px;
  font-size: 15px;
  color: #eaf1f8;
  background: rgba(0,0,0,.3);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: 8px;
  min-width: 0;
}
#mpAddress:focus { outline: none; border-color: rgba(139,224,122,.6); }
.mp-hint { font-size: 12px; opacity: .6; margin: 2px 0 0; min-height: 1em; }
.mp-hint.warn { color: #f2b56b; opacity: .95; }

/* Picker-only extras on top of the shared .panel card. */
.menu-panel {
  text-align: center;
  padding: 40px 56px;
  /* Flex column so a screen's inner scroll region (the world list) can bound to the space
     between the pinned title and footer — the flex:1/min-height:0 chain on #menuModeSelect
     -> .menu-screen -> .world-list is inert unless THIS is the flex root. (fit+scroll from .panel) */
  display: flex; flex-direction: column; min-height: 0;
  --panel-max-h: 96dvh; /* a touch more room for the picker than the shared default */
}
/* Touch: the desktop key hints don't apply and make the panel too tall to fit a
   landscape phone — hide them. */
body.is-touch .controls { display: none; }
/* Short (landscape phone) viewports: tighten the menu so it fits without scrolling. */
@media (max-height: 520px) {
  .menu-panel { padding: 20px 40px; }
  .menu-panel h1 { font-size: 34px; letter-spacing: 4px; }
  .subtitle { font-size: 11px; }
  .menu-screen:not([hidden]) { margin-top: 14px; gap: 8px; }
}
/* Very short (small landscape phone): squeeze harder before the scroll fallback kicks in. */
@media (max-height: 400px) {
  .menu-panel { padding: 14px 36px; }
  .menu-panel h1 { font-size: 28px; }
  .menu-screen:not([hidden]) { margin-top: 10px; }
}
/* Narrow (portrait phone) viewports: shrink the title so "NOVA" isn't clipped. */
@media (max-width: 430px) {
  .menu-panel { padding: 26px 20px; }
  .menu-panel h1 { font-size: 28px; letter-spacing: 2px; }
  .subtitle { font-size: 11px; letter-spacing: 2px; }
}
.menu-panel h1 {
  font-size: 56px;
  letter-spacing: 8px;
  font-weight: 800;
  background: linear-gradient(180deg, #b6f0a8, #4caf50 60%, #2e7d32);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 2px 16px rgba(76,175,80,.25);
}
.subtitle {
  margin-top: 4px;
  font-size: 14px;
  letter-spacing: 4px;
  text-transform: uppercase;
  opacity: .6;
}
/* (The Resume button reuses id="playBtn" but is styled entirely by .btn classes — no
   #playBtn ID rule, so a picker viewport media query can't leak into the modal.) */

.controls {
  list-style: none;
  margin-top: 18px;
  font-size: 13px;
  line-height: 1.9;
  opacity: .8;
}
.controls b { color: #b6f0a8; }

/* Menu options / settings (the touch-reachable equivalents of the shortcuts) */
.menu-opts { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 14px; }
.menu-opts .btn-secondary { margin-top: 0; }
.menu-adv { margin-top: 12px; font-size: 12px; }
.menu-adv summary { cursor: pointer; opacity: .55; letter-spacing: 1px; margin-bottom: 8px; }
.btn-secondary.on { background: rgba(182,240,168,.22); border-color: rgba(182,240,168,.6); color: #eafbe4; }

/* Transient toast (e.g. "Saved") */
#toast {
  position: fixed;
  top: 14px; left: 50%;
  transform: translateX(-50%) translateY(-8px);
  padding: 7px 16px;
  background: rgba(15, 20, 32, .8);
  border: 1px solid rgba(255,255,255,.15);
  border-radius: 8px;
  font-size: 13px;
  letter-spacing: .5px;
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s, transform .2s;
  z-index: 15;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Uncaught errors (see the inline handler in index.html). Its own element, not #toast: an error
   PERSISTS until reload — one you scrolled past is one you can't report — and the normal toast
   queue must keep working underneath it. Bottom-anchored to stay clear of the hotbar and the
   top-centre toast. Wrapped, because a file:line makes for a long line on a phone. */
#errbar {
  position: fixed;
  bottom: 10px; left: 50%;
  transform: translateX(-50%) translateY(8px);
  max-width: min(92vw, 560px);
  padding: 7px 14px;
  background: rgba(48, 14, 14, .93);
  border: 1px solid rgba(240,140,120,.45);
  border-radius: 8px;
  color: #f0b0a8;
  font-size: 12px;
  line-height: 1.35;
  white-space: normal;
  text-align: left;
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s, transform .2s;
  z-index: 16;              /* above #toast (15) — an error outranks a notice */
}
#errbar.show { opacity: 1; transform: translateX(-50%) translateY(0); }

.saveinfo {
  margin-top: 16px;
  font-size: 12px;
  opacity: .55;
}
.buildinfo {
  margin-top: 14px;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 11px;
  opacity: .4;
}
/* (button.secondary retired — replaced by .btn / .btn-secondary above.) */

/* "Rotate to landscape" — Terra Nova is landscape-only (like Minecraft), on every
   surface, not just gameplay. Manifest orientation locks the installed PWA; this
   covers the browser tab + iOS (which ignore manifest orientation). z-index 30 is
   the top of the stack, so it blankets menus, inventory, studio — everything. */
#rotate {
  position: fixed; inset: 0; z-index: 30;
  display: none;
  flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; text-align: center; padding: 24px;
  background: rgba(10, 14, 24, .94);
}
@media (orientation: portrait) and (pointer: coarse) {
  #rotate { display: flex; }
}
.rotate-icon { font-size: 64px; animation: rotateHint 1.8s ease-in-out infinite; }
@keyframes rotateHint { 0%, 38% { transform: rotate(0); } 60%, 100% { transform: rotate(90deg); } }
#rotate p { font-size: 18px; letter-spacing: 1px; opacity: .85; }

#loading {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  background: #0b1018;
  font-size: 20px;
  letter-spacing: 2px;
  z-index: 20;
}
#loading.active { display: flex; }

/* ---- Chest (block-entity UI): a grid of storage slots ---- */
#chest { display: none; z-index: 12; }
#chest.active { display: flex; }
#hopper { display: none; z-index: 12; }
#hopper.active { display: flex; }
/* Studio — the authoring hub (its own top-level surface, not part of Settings). */
#studio { display: none; z-index: 20; }
#studio.active { display: flex; }
.studio-panel { width: min(560px, 94vw); padding: 20px 22px; }
/* The intro line sits at the ✕'s height, so clear it (the <h2> already does via .inv-head). */
.studio-panel > .set-hint, .sl-panel > .set-hint { padding-right: 44px; }
.studio-tools { display: flex; flex-direction: column; gap: 8px; margin: 14px 0 16px; }
.studio-tool { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; text-align: left;
  padding: 12px 14px; border-radius: var(--panel-radius); border: var(--panel-border);
  background: rgba(255, 255, 255, .04); color: inherit; width: 100%; cursor: pointer; }
button.studio-tool:hover { border-color: rgba(var(--accent-bright-rgb), .5); background: rgba(var(--accent-bright-rgb), .1); }
.studio-tool.is-soon { opacity: .45; cursor: default; }
.studio-tool-title { font-weight: 600; font-size: 15px; }
.studio-tool-desc { font-size: 12px; opacity: .7; }

/* Sound Lab / Music — tools inside Studio; sit above it. */
#soundlab, #musiclab { display: none; z-index: 26; }
#soundlab.active, #musiclab.active { display: flex; }
.ml-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 6px; }
.ml-row .btn { text-align: center; min-width: 0; } /* uniform, column-aligned playback buttons */
.ml-action { flex: 0 0 auto; padding: 5px 11px; font-size: 12px; font-weight: 600; }
/* Music tool — library rail + tabbed editor (like the Sound Lab) */
.sl-panel.ml-panel { width: min(680px, 94vw); } /* beat .sl-panel's width, which is defined later */
.ml-rule { border: 0; border-top: 1px solid rgba(255, 255, 255, .1); margin: 12px 0; } /* separates the tool's logical zones */
.ml-body { display: flex; gap: 14px; align-items: flex-start; }
.ml-rail { flex: 0 0 148px; display: flex; flex-direction: column; gap: 5px; }
.ml-moodlist { display: flex; flex-direction: column; gap: 3px; }
.ml-moodlist .btn { text-align: left; width: 100%; margin-top: 0; } /* kill .btn-secondary's 10px top margin so Auto sits flush with the editor */
.ml-divider { height: 1px; background: rgba(255, 255, 255, .12); margin: 5px 2px; }
.ml-new { text-align: center; margin-top: 3px; }
.ml-edit { flex: 1; min-width: 0; align-self: flex-start; border: var(--panel-border); border-radius: var(--panel-radius); padding: 9px 12px 12px; background: rgba(255, 255, 255, .03); }
.ml-edit-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.ml-edit-title { font-weight: 600; font-size: 14px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ml-edit-acts { display: flex; gap: 6px; flex: 0 0 auto; }
.ml-tabs { display: flex; gap: 2px; border-bottom: 1px solid rgba(255, 255, 255, .1); margin-bottom: 10px; }
.ml-tab { background: transparent; border: none; padding: 6px 10px; font: 600 12px/1 system-ui, sans-serif; color: var(--text-dim); cursor: pointer; border-bottom: 2px solid transparent; }
.ml-tab:hover { color: var(--accent-tint); }
.ml-tab.active { color: var(--accent-tint); border-bottom-color: rgba(var(--accent-bright-rgb), .6); }
.ml-tabbody { display: flex; flex-direction: column; gap: 10px; }
.ml-voices { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
@media (max-width: 520px) { /* stack the rail above the editor on narrow screens */
  .ml-body { flex-direction: column; }
  .ml-rail { flex: none; }
  .ml-moodlist { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
  .ml-moodlist .btn { text-align: center; }
}
.sl-panel { width: min(600px, 94vw); padding: 20px 22px; } /* fit+scroll from .panel */
.sl-body { display: flex; gap: 14px; margin-top: 8px; }
.sl-materials { display: flex; flex-direction: column; gap: 4px; flex: 0 0 132px; }
.sl-mat { text-align: left; }
.sl-mat.selected { background: rgba(var(--accent-bright-rgb), .16); border-color: rgba(var(--accent-bright-rgb), .5); color: var(--accent-tint); }
.sl-editor { flex: 1; min-width: 0; }
.sl-select { width: 100%; }
.sl-preview { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-top: 12px; }
.sl-footer { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 14px; }
/* Mood editor fields (Identity tab) */
.me-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.me-label { font: 600 11px/1 system-ui, sans-serif; letter-spacing: .03em; text-transform: uppercase; color: var(--text-dim); opacity: .8; }
.me-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.me-feel { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.ml-text { width: 100%; padding: 7px 10px; border-radius: 8px; border: var(--panel-border); background: rgba(0, 0, 0, .25); color: var(--text); font: inherit; }
.ml-text:focus { outline: none; border-color: rgba(var(--accent-bright-rgb), .6); }
.me-scale { display: grid; grid-template-columns: repeat(12, 1fr); gap: 3px; }
.me-deg { min-width: 0; padding: 6px 0; font-size: 12px; }
.me-deg.on { background: rgba(var(--accent-bright-rgb), .16); border-color: rgba(var(--accent-bright-rgb), .5); color: var(--accent-tint); }
.me-deg.root { opacity: .7; cursor: default; }
/* Grouped voice controls (Instruments tab): small cluster subheaders */
.ml-group { margin: 8px 2px 2px; font: 600 11px/1 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: var(--text-dim); opacity: .75; }
.ml-group:first-child { margin-top: 2px; }
.chest-grid {
  display: grid;
  grid-template-columns: repeat(9, 52px); /* 9 across = 3 rows of 27 */
  gap: 6px;
  justify-content: center;
  padding: 14px 2px 4px;
}
.chest-grid .fn-slot { width: 52px; height: 52px; }
.chest-grid .fn-slot canvas { width: 34px; height: 34px; }

/* ---- Furnace (block-entity UI): two input slots, burn + cook progress, an output ---- */
#furnace { display: none; z-index: 12; }
#furnace.active { display: flex; }
.container-panel { /* framed: the card never scrolls (overflow:hidden beats .panel's auto), so
                      the header + ✕ stay pinned; the "your items" grid below is the scroll region */
  width: min(720px, 94vw);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 22px 26px 20px;
}
/* The your-items list (furnace #fnItems, chest #chestItems, hopper #hopperItems — all .inv-grid)
   fills the leftover space and scrolls, so the machine/storage + header stay put and the card
   itself doesn't grow past the viewport. (In the main inventory .inv-grid lives in .inv-body, unaffected.) */
.container-panel .inv-grid { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* The loadable-item grid scrolls once it passes ~3 rows, so the panel can't grow tall. */
#fnItems { max-height: 224px; overflow-y: auto; padding: 2px; }
.fn-machine {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 18px 8px 4px;
}
.fn-col { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.fn-slot {
  position: relative;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .18);
  cursor: pointer;
}
.fn-slot:hover { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .38); }
.fn-slot.empty { cursor: default; }
.fn-slot.empty:hover { background: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .18); }
.fn-slot canvas { width: 40px; height: 40px; image-rendering: pixelated; border-radius: 2px; }
.fn-slot .count {
  position: absolute;
  right: 4px;
  bottom: 2px;
  font: 600 12px/1 system-ui, sans-serif;
  color: var(--text);
  text-shadow: 0 1px 2px #000;
}
.fn-out { border-color: rgba(var(--accent-bright-rgb), .5); }

/* Burn gauge (vertical, fills downward as fuel is spent) + cook gauge (horizontal). */
.fn-burn, .fn-cook {
  background: rgba(255, 255, 255, .08);
  border-radius: 4px;
  overflow: hidden;
}
.fn-burn { width: 12px; height: 26px; display: flex; align-items: flex-end; }
.fn-burn > i { display: block; width: 100%; height: 0; background: var(--fire); }
.fn-cook { width: 96px; height: 12px; }
.fn-cook > i { display: block; width: 0; height: 100%; background: var(--accent-bright); }

.fn-title { margin: 14px 2px 6px; font: 600 13px/1 system-ui, sans-serif; color: var(--text-dim); }

/* ---- Creative palette: search + category chips ----
   The palette passed 150 blocks, where a flat grid stops being findable. Controls sit above the
   grid and OUTSIDE it, so they stay put while the grid scrolls. Colours come from the same tokens
   as everything else; the chips are .btn-shaped but smaller than .btn, hence their own class
   rather than an override that would fight .btn's specificity. */
.pal-controls { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 10px; }
.pal-search {
  width: 100%; box-sizing: border-box;
  padding: 8px 10px; font-size: 14px; font-family: inherit;
  color: #e6edf6; background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.16); border-radius: 8px;
}
.pal-search::placeholder { color: rgba(230,237,246,.45); }
.pal-search:focus { outline: none; border-color: rgba(140,224,122,.55); background: rgba(255,255,255,.1); }
.pal-cats { display: flex; flex-wrap: wrap; gap: 6px; }
.pal-cat {
  padding: 5px 11px; font-size: 13px; font-weight: 600; font-family: inherit;
  color: #c7d0de; background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.12); border-radius: 999px; cursor: pointer;
}
.pal-cat:hover { background: rgba(255,255,255,.12); }
.pal-cat.active { background: rgba(140,224,122,.18); border-color: rgba(140,224,122,.45); color: #eafbe4; }

/* A stack picked up for moving. Lit the whole time it's in hand, because with tap-to-move there's
   nothing under the cursor to show what you're carrying — the slot IS the feedback. */
.slot.carrying {
  border-color: var(--accent-bright);
  box-shadow: 0 0 0 2px rgba(var(--accent-bright-rgb), .45);
}
.slot.carrying canvas { opacity: .55; }        /* it's "lifted out" of the slot */
.slot.splitting { border-color: var(--fire); box-shadow: 0 0 0 2px rgba(var(--fire-rgb), .5); }
