/* Base layout, HUD chrome and the menu — house tokens follow Tank Arena's
   style.css shape (a --panel/--edge/--ui set every screen reuses) but in
   Perennial's own palette: living green over dusk, not military amber. */
:root {
  --leaf: #5fbf6a;
  --bark: #a9784f;
  --sky: #6fb7d9;
  --ink: #070b09;
  --panel: rgba(9, 16, 12, .82);
  --edge: rgba(95, 191, 106, .35);
  --ui: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--ink);
  color: #eaf3ec;
  font-family: var(--ui);
  -webkit-font-smoothing: antialiased;
}

#view { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

kbd {
  display: inline-block;
  min-width: 1.5em;
  padding: .15em .4em;
  margin: 0 .12em;
  border: 1px solid rgba(255, 255, 255, .28);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: rgba(255, 255, 255, .07);
  font: inherit;
  font-size: .82em;
  text-align: center;
}

/* ========================= HUD ========================= */
#hud { position: fixed; inset: 0; pointer-events: none; user-select: none; }
#hud[hidden] { display: none; }

#crosshair {
  position: absolute; left: 50%; top: 50%; width: 20px; height: 20px;
  margin: -10px 0 0 -10px;
}
#crosshair i {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .85);
  box-shadow: 0 0 4px rgba(0, 0, 0, .8);
}
#crosshair::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 3px; height: 3px;
  margin: -1.5px 0 0 -1.5px; border-radius: 50%; background: #fff;
}
#crosshair.reject i { animation: reject .3s ease-out; }
@keyframes reject {
  0% { border-color: #ff5a4a; transform: scale(1.4); }
  100% { border-color: rgba(255, 255, 255, .85); transform: scale(1); }
}

#readouts {
  position: absolute; top: calc(10px + env(safe-area-inset-top, 0px));
  left: 50%; transform: translateX(-50%);
  display: flex; gap: 14px; padding: 6px 16px;
  background: var(--panel); border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 8px; backdrop-filter: blur(8px);
  font-size: 12px; letter-spacing: .04em; opacity: .9;
}
#pingReadout { opacity: .6; }

#debug {
  position: absolute; top: calc(48px + env(safe-area-inset-top, 0px));
  left: 10px; margin: 0; padding: 8px 10px;
  background: var(--panel); border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 6px; font-size: 11px; line-height: 1.5; white-space: pre;
  opacity: .92;
}
#debug[hidden] { display: none; }

#hotbarWrap {
  position: absolute; left: 0; right: 0; bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  display: flex; justify-content: center; pointer-events: none;
}
#hotbar {
  display: flex; gap: 5px; max-width: min(94vw, 620px); overflow-x: auto;
  padding: 6px; background: var(--panel); border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 10px; backdrop-filter: blur(8px); pointer-events: auto;
  scrollbar-width: thin;
}
.hbslot {
  flex: none; width: 52px; height: 52px; position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding: 3px 2px; border-radius: 6px; cursor: pointer;
  border: 1.5px solid rgba(255, 255, 255, .16);
  background: rgba(0, 0, 0, .3);
  font: inherit; color: #eaf3ec;
}
/* #hotbar's 9 slots at 52px + 5px gaps + 12px padding need 520px of width;
   min(94vw, 620px) caps at ~367px on a 390px-wide phone, silently scrolling
   slots 8-9 out of view with no visible affordance (mobile WebKit/Blink hide
   scrollbars until an active scroll gesture) — a real player never
   discovers the last two hotbar slots exist. Shrinking the slot below this
   breakpoint keeps all 9 visible without scrolling: 9*35 + 8*4 + 12 = 359px,
   under 94vw of even a 380px-wide phone. */
@media (max-width: 480px) {
  #hotbar { gap: 4px; }
  .hbslot { width: 35px; height: 35px; }
  .hbslot em { font-size: 7px; }
  .hbslot span { font-size: 6px; }
}
.hbslot i {
  position: absolute; inset: 4px 4px 16px 4px; border-radius: 3px;
  /* Mandatory fix: a real thumbnail of the block's own top texture
     (hud.js's thumbnailDataURL call), not a hashed-color swatch — crisp
     pixel-art scaling, no smoothing, matching the 16px-tile look. */
  background-color: #223;
  background-image: var(--swatch-img, none);
  background-size: cover;
  image-rendering: pixelated;
}
.hbslot em {
  position: absolute; top: 2px; left: 4px; font-style: normal; font-size: 9px; opacity: .65;
}
.hbslot span {
  position: relative; font-size: 7px; letter-spacing: .02em; line-height: 1.1;
  text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%; opacity: .85;
}
.hbslot.sel { border-color: var(--leaf); box-shadow: 0 0 10px rgba(95, 191, 106, .4); }
.hbslot .icon {
  position: absolute; inset: 4px 4px 12px 4px; border-radius: 3px;
  background-color: #223; background-image: var(--swatch-img, none);
  background-size: cover; image-rendering: pixelated;
}
.hbslot .icon.empty { background-color: rgba(255, 255, 255, .04); background-image: none; }
.hbslot em.qty {
  position: absolute; right: 3px; bottom: 12px; font-style: normal; font-size: 10px;
  font-weight: 700; text-shadow: 0 1px 2px #000; padding: 0 2px;
}
.hbslot em.num {
  position: absolute; top: 2px; left: 4px; font-style: normal; font-size: 9px; opacity: .65;
}
.hbslot b.dur {
  position: absolute; left: 5px; right: 5px; bottom: 4px; height: 3px;
  background: rgba(0, 0, 0, .5); border-radius: 2px; overflow: hidden; display: block;
}
.hbslot b.dur i { display: block; height: 100%; }

/* 92px, not 76px: the hotbar's top edge sits at a fixed 80px (14px offset +
   52px slot + 12px padding + 2px border) and #hotbarWrap comes later in
   index.html with no z-index on either, so at 76px the label's own box
   (76..89px) was painted over and "Empty Hand" was clipped across its lower
   third in every single world screenshot. 12px of gap above the hotbar. */
#toolLabel {
  position: absolute; left: 50%; bottom: calc(92px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%); font-size: 11px; letter-spacing: .06em; opacity: .75;
  text-shadow: 0 1px 3px #000; pointer-events: none; white-space: nowrap;
}

/* ===================== break-progress ring ===================== */
#breakRing {
  position: absolute; left: 50%; top: 50%; width: 34px; height: 34px;
  margin: -17px 0 0 -17px; border-radius: 50%;
  background: conic-gradient(#eafce0 calc(var(--frac, 0) * 360deg), rgba(255, 255, 255, .18) 0);
  -webkit-mask: radial-gradient(circle, transparent 11px, #000 12px);
  mask: radial-gradient(circle, transparent 11px, #000 12px);
}
#breakRing[hidden] { display: none; }

/* ===================== pickup flashes ===================== */
/* ...and the toast rail moves up with it. The whole bottom stack is ONE
   ladder, every rung measured from the viewport bottom and every one of them
   clearing the rung below: hotbar 14..80, tool label 92..105, chat bar
   112..145 (chat.js), pickups 152 up, chat rail 156 up (chat.js), claim
   banner 176 (claims.js). */
#pickups {
  position: absolute; left: 50%; bottom: calc(152px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%); display: flex; flex-direction: column-reverse; gap: 3px;
  align-items: center; pointer-events: none;
}
.pickup {
  display: flex; align-items: center; gap: 6px; padding: 3px 8px;
  background: rgba(9, 16, 12, .78); border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 20px; font-size: 11px; opacity: 0; transform: translateY(4px);
  transition: opacity .25s, transform .25s;
}
.pickup.go { opacity: 1; transform: translateY(0); }
.pickup i {
  width: 16px; height: 16px; border-radius: 3px; background-size: cover;
  image-rendering: pixelated; flex: none;
}
/* Refusal/confirmation toasts share the pickup rail so there is exactly one
   place to look for "what just happened". */
.pickup.notice { padding: 4px 11px; max-width: min(74vw, 340px); text-align: center; }
.pickup.notice.warn { border-color: rgba(226, 120, 96, .55); color: #f0c5b5; }
.pickup.notice.good { border-color: rgba(126, 200, 122, .55); color: #cfeec3; }

/* ===================== Loupe gene panel ===================== */
#loupe {
  position: absolute; right: calc(14px + env(safe-area-inset-right, 0px)); top: 96px;
  width: 200px; padding: 10px 12px; background: var(--panel); border: 1px solid var(--edge);
  border-radius: 10px; backdrop-filter: blur(8px); pointer-events: none;
}
#loupe[hidden] { display: none; }
#loupe h4 { margin: 0 0 8px; font-size: 11px; letter-spacing: .06em; opacity: .85; }
.gbar { display: grid; grid-template-columns: 58px 1fr 26px; align-items: center; gap: 6px; margin: 4px 0; font-size: 10px; }
.gbar span { opacity: .7; text-transform: capitalize; }
.gbar b { display: block; height: 5px; background: rgba(255, 255, 255, .12); border-radius: 3px; overflow: hidden; }
.gbar b i { display: block; height: 100%; background: var(--leaf); }
.gbar em { font-style: normal; opacity: .7; text-align: right; }

#graftHint {
  position: absolute; left: 50%; bottom: calc(180px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%); padding: 6px 12px; background: var(--panel);
  border: 1px solid var(--edge); border-radius: 8px; font-size: 11px; pointer-events: none;
}
#graftHint[hidden] { display: none; }

/* ========================= INVENTORY / CRAFTING ========================= */
#invScreen {
  position: fixed; inset: 0; z-index: 30; display: grid; place-items: center;
  background: rgba(4, 8, 5, .6); padding: 20px;
}
#invScreen[hidden] { display: none; }
.invPanel {
  width: min(760px, 100%); max-height: min(88vh, 700px); display: flex; flex-direction: column;
  background: rgba(9, 16, 12, .95); border: 1px solid var(--edge); border-radius: 14px;
  box-shadow: 0 30px 90px rgba(0, 0, 0, .65); overflow: hidden;
}
.invHead { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid rgba(255, 255, 255, .08); }
.invHead h2 { margin: 0; font-size: 15px; letter-spacing: .08em; }
.invHead button {
  width: 30px; height: 30px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, .2);
  background: rgba(255, 255, 255, .06); color: #eaf3ec; font-size: 16px; cursor: pointer;
}
.invBody { display: flex; gap: 16px; padding: 16px 18px; overflow: auto; }
.invLeft { flex: 1 1 320px; min-width: 260px; }
.invRight { flex: 1 1 320px; min-width: 260px; border-left: 1px solid rgba(255, 255, 255, .08); padding-left: 16px; }

/* minmax(0,1fr), not a bare 1fr: a <button> grid item's default min-width
   (its own content/padding) otherwise wins over the track size on a narrow
   viewport, and the row overflows its own panel instead of shrinking —
   the classic CSS-grid-with-buttons pitfall, caught by the touch-mode shot. */
.islots { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 4px; }
.islot {
  aspect-ratio: 1; position: relative; border-radius: 5px; cursor: pointer;
  border: 1.5px solid rgba(255, 255, 255, .14); background: rgba(0, 0, 0, .3);
  padding: 0; min-width: 0;
}
.islot.hb { border-color: rgba(95, 191, 106, .35); }
.islot.picked { border-color: var(--leaf); box-shadow: 0 0 8px rgba(95, 191, 106, .4); }
.islot .icon { position: absolute; inset: 3px; border-radius: 3px; background-color: #223; background-image: var(--swatch-img, none); background-size: cover; image-rendering: pixelated; }
.islot .icon.empty { background-color: rgba(255, 255, 255, .04); background-image: none; }
.islot em.qty { position: absolute; right: 2px; bottom: 1px; font-style: normal; font-size: 9px; text-shadow: 0 1px 2px #000; }

.invDetail { margin: 10px 0; font-size: 11.5px; opacity: .85; min-height: 2.4em; }
#repairBtn {
  margin-bottom: 10px; padding: 7px 14px; font: inherit; color: #10150f; cursor: pointer;
  background: var(--leaf); border: 0; border-radius: 6px;
}

.craft3x3wrap { margin-top: 12px; }
.craft3x3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; width: 150px; }
.craft3x3.match { outline: 2px solid var(--leaf); border-radius: 6px; }
.ccell {
  aspect-ratio: 1; border-radius: 5px; border: 1.5px dashed rgba(255, 255, 255, .2);
  background-color: rgba(0, 0, 0, .25); background-image: var(--swatch-img, none);
  background-size: cover; cursor: pointer;
}
.ccell.filled { border-style: solid; }
.craft3x3row { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
#craftHint { font-size: 11px; opacity: .85; flex: 1; }
#craftBtn {
  padding: 7px 16px; font: inherit; color: #10150f; cursor: pointer;
  background: var(--leaf); border: 0; border-radius: 6px;
}
html.touch .craft3x3wrap { display: none; }

.recipes { display: flex; flex-direction: column; gap: 8px; max-height: 560px; overflow-y: auto; }
.recipe { padding: 8px 10px; border: 1px solid rgba(255, 255, 255, .1); border-radius: 8px; background: rgba(0, 0, 0, .2); }
.recipe.ok { border-color: rgba(95, 191, 106, .4); }
.rname { font-size: 12px; font-weight: 600; margin-bottom: 4px; }
.rio { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.rin, .rout { display: inline-flex; align-items: center; gap: 3px; font-size: 10px; padding: 1px 4px; border-radius: 4px; background: rgba(255, 255, 255, .06); }
.rin.short { color: #ff8a72; }
.rin i, .rout i { width: 14px; height: 14px; background-size: cover; image-rendering: pixelated; border-radius: 2px; }
.arrow { opacity: .5; margin: 0 2px; }
.rtag { margin-top: 4px; font-size: 10px; color: #e0b96a; }
.rcraft {
  margin-top: 6px; padding: 5px 12px; font: inherit; font-size: 11px; color: #10150f; cursor: pointer;
  background: var(--leaf); border: 0; border-radius: 6px;
}
.rcraft:disabled { background: rgba(255, 255, 255, .18); color: rgba(255, 255, 255, .5); cursor: not-allowed; }

#away {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  min-width: 300px; max-width: 90vw; padding: 18px 20px;
  background: var(--panel); border: 1px solid var(--edge); border-radius: 12px;
  backdrop-filter: blur(12px); pointer-events: auto;
}
/* Above the chat bar (z-index 41, chat.js) and the claim banner (35). Both
   are painted from <body>, later in the document than #hud, so without a
   z-index of its own this panel — which is a summary the player is meant to
   read and dismiss — was drawn UNDERNEATH the typing line the moment chat
   became reachable on touch, with its own Close button half-covered. */
#away { z-index: 45; }
#away[hidden] { display: none; }
#away h3 { margin: 0 0 8px; font-size: 13px; letter-spacing: .12em; opacity: .8; }
#away p { margin: 4px 0; font-size: 12.5px; opacity: .85; }
#away button {
  margin-top: 10px; padding: 8px 14px; font: inherit; color: #10150f; cursor: pointer;
  background: var(--leaf); border: 0; border-radius: 6px;
}

/* ========================= MENU ========================= */
#menu {
  position: fixed; inset: 0; display: grid; place-items: center; padding: 20px;
  background: radial-gradient(ellipse at 50% 30%, #142418 0%, #070b09 70%);
  z-index: 20; overflow: auto;
}
#menu.hide { opacity: 0; pointer-events: none; transition: opacity .45s; }

.panel {
  width: min(440px, 100%); padding: 30px 34px 26px;
  background: rgba(9, 16, 12, .9); border: 1px solid var(--edge);
  border-radius: 14px; box-shadow: 0 30px 90px rgba(0, 0, 0, .65);
}
.panel h1 { margin: 0; font-size: clamp(24px, 5vw, 34px); letter-spacing: .12em; }
.panel h1 span { color: var(--leaf); }
.tag { margin: 8px 0 22px; font-size: 12px; opacity: .65; letter-spacing: .02em; }

.field { display: block; margin-bottom: 16px; }
.field span { display: block; font-size: 10px; letter-spacing: .22em; opacity: .55; margin-bottom: 6px; }
.field input {
  width: 100%; padding: 11px 13px; font: inherit; font-size: 15px; color: #fff;
  background: rgba(0, 0, 0, .45); border: 1px solid rgba(255, 255, 255, .15);
  border-radius: 7px; outline: none;
}
.field input:focus { border-color: var(--leaf); box-shadow: 0 0 0 3px rgba(95, 191, 106, .16); }

#playBtn {
  width: 100%; margin-top: 4px; padding: 15px; font: inherit; font-size: 15px; font-weight: 700;
  letter-spacing: .18em; color: #0b150d; cursor: pointer;
  background: linear-gradient(180deg, #86e28f, var(--leaf));
  border: 0; border-radius: 8px; transition: transform .1s, filter .2s;
}
#playBtn:hover { filter: brightness(1.1); }
#playBtn:active { transform: translateY(1px); }
#playBtn:disabled { filter: grayscale(.75) brightness(.7); cursor: wait; }

#connState { min-height: 18px; margin-top: 9px; font-size: 12px; text-align: center; opacity: .75; }
#connState.err { color: #ff8a72; opacity: 1; }

.controls { display: grid; grid-template-columns: 1fr 1fr; gap: 7px 16px; margin: 20px 0 4px; font-size: 11px; }
.controls div { display: flex; align-items: center; gap: 5px; }
.controls em { opacity: .6; font-style: normal; }
.controls b { font-size: 10px; letter-spacing: .08em; padding: .25em .45em; border: 1px solid rgba(255, 255, 255, .28); border-radius: 4px; }
.controls.touchctl { display: none; }
html.touch .controls.keyctl { display: none; }
html.touch .controls.touchctl { display: grid; }

#loader {
  position: fixed; inset: 0; display: grid; place-items: center; gap: 16px; align-content: center;
  background: var(--ink); z-index: 40; font-size: 12px; letter-spacing: .2em; opacity: .9;
}
#loader.gone { display: none; }
.spin { width: 34px; height: 34px; border: 3px solid rgba(255, 255, 255, .14); border-top-color: var(--leaf); border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

@media (max-width: 520px) {
  .panel { padding: 20px 18px 16px; }
  .controls { grid-template-columns: 1fr; gap: 5px; }
}
