/* ===========================================================================
   BitSoul3D — Build & Terraform tools
   ---------------------------------------------------------------------------
   Owns: the chrome of the Build and Terraform windows — the undo/redo bar, the
   shape and brush pickers, the sliders, the reset guard, and the touch commit
   pad the phone build path needs.

   Visual language is the one already shipped in ui-map.css: the warm gilded
   bezel and the rarity ramp, reused rather than reinvented, so a creative tool
   looks like it belongs to the same product as the map and the collection
   frames. Tokens are inherited from ui-map.css (--bs-brass, --bs-r-*), which
   loads first; the handful defined here are the ones only these tools need.

   Everything is drawn with gradients and box-shadow. These panels open on top
   of a live 3D world on a project already over its triangle budget on
   handhelds, so no bitmaps, no extra fetches, no filters that force a layer.
   =========================================================================== */

:root {
  /* Brush identities — the SAME four colours TERRA_TINT uses in app.js, so the
     chip in the panel and the ring on the ground are never two different
     greens. If one moves, move both. */
  --bs-t-raise: #8effa0;
  --bs-t-lower: #ff9d6f;
  --bs-t-smooth: #6fe0ff;
  --bs-t-flat: #ffd24f;

  --bs-build-ink: #dfe7f5;
  --bs-build-dim: #93a3bd;
  --bs-build-well: rgba(6, 10, 20, 0.55);
}

/* ---------------------------------------------------------------------------
   Undo / redo bar
   ---------------------------------------------------------------------------
   Sits at the very top of both tool panels. Creative tools without a visible
   way back teach people not to experiment, so this is the first thing in the
   window rather than a shortcut you have to know about. */
.bs-tool-bar {
  display: flex;
  gap: 6px;
  margin: 0 0 9px;
  padding: 0 0 9px;
  border-bottom: 1px solid rgba(200, 162, 78, 0.22);
}

.bs-hist {
  flex: 1;
  min-height: 32px;
  padding: 6px 8px;
  font: 600 12px/1 inherit;
  letter-spacing: 0.02em;
  color: var(--bs-build-ink);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0) 62%),
    var(--bs-build-well);
  border: 1px solid rgba(200, 162, 78, 0.42);
  border-radius: 7px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 1px 2px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, transform 0.06s;
}

.bs-hist:hover:not([disabled]) {
  border-color: var(--bs-braise, #f3dfa6);
  background:
    linear-gradient(180deg, rgba(243, 223, 166, 0.2), rgba(200, 162, 78, 0.08)),
    var(--bs-build-well);
}

.bs-hist:active:not([disabled]) { transform: translateY(1px); }

/* Disabled is the normal state of Undo at the start of a session, so it has to
   read as "nothing yet" rather than as a broken control. */
.bs-hist[disabled] {
  opacity: 0.34;
  cursor: default;
  color: var(--bs-build-dim);
}

.bs-hist:focus-visible {
  outline: 2px solid var(--bs-land-accent, #5b8cff);
  outline-offset: 1px;
}

/* ---------------------------------------------------------------------------
   Shape & brush pickers
   ---------------------------------------------------------------------------
   A row of words told you a block was called "Torus" and nothing about what
   would land on your lawn. Each chip now carries the block's own silhouette,
   drawn in CSS, so the choice is made by sight. */
.bs-shapes .chip,
.bs-brushes .chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 7px 2px 6px;
  line-height: 1;
}

.bs-shapes .chip b,
.bs-brushes .chip b {
  font: 600 10px/1 inherit;
  letter-spacing: 0.03em;
  color: var(--bs-build-dim);
}

.bs-shapes .chip.active b,
.bs-brushes .chip.active b { color: var(--bs-build-ink); }

/* --- block silhouettes --- */
.bs-sh {
  display: block;
  width: 17px;
  height: 17px;
  background: linear-gradient(160deg, #e8edf6 0%, #b9c4d8 46%, #7d8aa3 100%);
  box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.28);
}

.sh-box { border-radius: 2px; }
.sh-sphere { border-radius: 50%; }
.sh-cyl { border-radius: 42% / 18%; }
.sh-cone {
  background: none;
  width: 0;
  height: 0;
  border-left: 8.5px solid transparent;
  border-right: 8.5px solid transparent;
  border-bottom: 16px solid #c2ccdd;
  box-shadow: none;
}
.sh-torus {
  border-radius: 50%;
  box-shadow: none;
  background: radial-gradient(circle at 50% 42%,
    rgba(0, 0, 0, 0) 0 33%, #d3dbea 35%, #93a0b8 100%);
}

/* --- brush directions --- */
/* Each brush shows what it does to the ground: a mound, a dip, a soft hump, a
   level bar. Tinted with the same colour the cursor takes in the world. */
.bs-br {
  display: block;
  width: 18px;
  height: 12px;
  position: relative;
}

.bs-br::after {
  content: "";
  position: absolute;
  inset: auto 0 1px;
  height: 10px;
}

.br-raise::after {
  background: var(--bs-t-raise);
  clip-path: polygon(0 100%, 50% 0, 100% 100%);
}
.br-lower::after {
  background: var(--bs-t-lower);
  clip-path: polygon(0 0, 50% 100%, 100% 0);
}
.br-smooth::after {
  background: var(--bs-t-smooth);
  clip-path: polygon(0 100%, 12% 62%, 30% 26%, 50% 14%, 70% 26%, 88% 62%, 100% 100%);
}
.br-flat::after {
  background: var(--bs-t-flat);
  height: 4px;
  inset: auto 0 4px;
  border-radius: 1px;
}

/* Selected brush lights its own colour rather than the generic chip highlight,
   so the panel and the ground agree at a glance. */
.bs-brushes .chip.active { border-color: rgba(243, 223, 166, 0.75); }
.bs-brushes .chip[data-terra="raise"].active { box-shadow: 0 0 10px -3px var(--bs-t-raise); }
.bs-brushes .chip[data-terra="lower"].active { box-shadow: 0 0 10px -3px var(--bs-t-lower); }
.bs-brushes .chip[data-terra="smooth"].active { box-shadow: 0 0 10px -3px var(--bs-t-smooth); }
.bs-brushes .chip[data-terra="flatten"].active { box-shadow: 0 0 10px -3px var(--bs-t-flat); }

/* ---------------------------------------------------------------------------
   Sliders
   ---------------------------------------------------------------------------
   These were raw <input type="range"> — the most generic surface in the
   product, and on a tool where the value IS the craft. Restyled as a gilded
   channel with a brass thumb and a filled track, driven by the --fill custom
   property app.js sets on input so the bar shows how far along the value is.

   The markup is untouched: still one range input per control, so this survives
   any future rework of the panels around it. */
.bs-slider {
  display: flex;
  align-items: center;
  gap: 9px;
  font: 600 11px/1 inherit;
  letter-spacing: 0.03em;
  color: var(--bs-build-dim);
  margin: 7px 0;
}

.bs-slider input[type="range"] {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 18px;
  background: none;
  cursor: pointer;
  margin: 0;
}

/* The channel: a sunk well with the brass bezel's inner shadow, filled to the
   thumb with the same braise ramp the map's active buttons use. */
.bs-slider input[type="range"]::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: 5px;
  border: 1px solid rgba(200, 162, 78, 0.4);
  background:
    linear-gradient(90deg,
      var(--bs-brass, #c8a24e) 0 var(--fill, 40%),
      rgba(8, 12, 22, 0.75) var(--fill, 40%) 100%);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.6);
}

.bs-slider input[type="range"]::-moz-range-track {
  height: 8px;
  border-radius: 5px;
  border: 1px solid rgba(200, 162, 78, 0.4);
  background:
    linear-gradient(90deg,
      var(--bs-brass, #c8a24e) 0 var(--fill, 40%),
      rgba(8, 12, 22, 0.75) var(--fill, 40%) 100%);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.6);
}

.bs-slider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px;
  border-radius: 50%;
  border: 1px solid var(--bs-brass-dk, #6d5324);
  background: radial-gradient(circle at 50% 34%,
    var(--bs-braise, #f3dfa6), var(--bs-brass, #c8a24e) 62%, var(--bs-brass-dk, #6d5324));
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 0 8px -2px var(--bs-braise, #f3dfa6);
}

.bs-slider input[type="range"]::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid var(--bs-brass-dk, #6d5324);
  background: radial-gradient(circle at 50% 34%,
    var(--bs-braise, #f3dfa6), var(--bs-brass, #c8a24e) 62%, var(--bs-brass-dk, #6d5324));
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 0 8px -2px var(--bs-braise, #f3dfa6);
}

.bs-slider input[type="range"]:focus-visible::-webkit-slider-thumb {
  outline: 2px solid var(--bs-land-accent, #5b8cff);
  outline-offset: 1px;
}

/* ---------------------------------------------------------------------------
   Reset guard
   ---------------------------------------------------------------------------
   Reset Land wipes an entire Homeland. It used to look like every other chip
   in the panel; the first click now arms it and it says so in red until it
   disarms itself. */
.bs-danger {
  width: 100%;
  margin-top: 8px;
  background: rgba(255, 90, 90, 0.16);
  border-color: rgba(255, 120, 120, 0.5);
  color: #ffd9d9;
}

.bs-danger.armed {
  background: rgba(255, 70, 70, 0.4);
  border-color: #ff8a8a;
  color: #fff;
  animation: bs-danger-pulse 0.9s ease-in-out infinite;
}

@keyframes bs-danger-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 90, 90, 0.5); }
  50% { box-shadow: 0 0 14px 2px rgba(255, 90, 90, 0.5); }
}

@media (prefers-reduced-motion: reduce) {
  .bs-danger.armed { animation: none; box-shadow: 0 0 14px 2px rgba(255, 90, 90, 0.5); }
}

/* ---------------------------------------------------------------------------
   Touch build pad
   ---------------------------------------------------------------------------
   On a handheld the canvas touch handlers own drag-to-look, so there is no
   free tap to place a block or bite the ground with — building was simply not
   reachable. Aiming with a finger you cannot see under is also the wrong
   design even where a tap IS free: the finger covers the target.

   So touch aims with a fixed reticle and commits with a button, the way every
   console builder does it. This pad is that button, plus undo, and it only
   exists while a tool is open on a handheld. */
/* --bs-dock-h is the measured height of the phone tool dock, written by
   bsMeasureDock() in app.js. The dock wraps to two rows on a narrow screen, so
   a hard-coded offset put this pad straight through the Build and Land buttons.
   Everything in the touch stack sits off the measured value instead. */
#bsBuildPad {
  display: none;
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--bs-dock-h, 64px) + 10px);
  z-index: 45;
  gap: 10px;
  align-items: center;
  pointer-events: auto;
}

#bsBuildPad.on { display: flex; }

#bsBuildPad button {
  min-width: 58px;
  min-height: 58px;
  padding: 0 12px;
  border-radius: 50%;
  font: 700 11px/1.15 inherit;
  color: var(--bs-build-ink);
  background:
    radial-gradient(circle at 50% 30%, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0) 62%),
    rgba(10, 16, 30, 0.82);
  border: 1px solid rgba(200, 162, 78, 0.55);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* The commit key is the big one and it wears the brass, because it is the
   button the whole touch build flow is built around. */
#bsBuildPad #bsPadDo {
  min-width: 78px;
  min-height: 78px;
  font-size: 12px;
  border-color: var(--bs-braise, #f3dfa6);
  background:
    radial-gradient(circle at 50% 28%, rgba(243, 223, 166, 0.34), rgba(200, 162, 78, 0.1) 66%),
    rgba(10, 16, 30, 0.86);
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.6), 0 0 18px -6px var(--bs-braise, #f3dfa6);
}

#bsBuildPad #bsPadDo:active {
  background:
    radial-gradient(circle at 50% 28%, rgba(243, 223, 166, 0.6), rgba(200, 162, 78, 0.24) 66%),
    rgba(10, 16, 30, 0.9);
}

#bsBuildPad button[disabled] { opacity: 0.35; }

/* ---------------------------------------------------------------------------
   Handheld layout
   ---------------------------------------------------------------------------
   A tool window is a floating draggable panel on desktop. On a phone there is
   no room to float anything, and dragging a window with the same finger that
   flies the camera is not a real interaction — so the panels dock to the
   bottom as a sheet, above the touch pad, and scroll internally.

   Height is capped in dynamic viewport units so a landscape phone (812x375)
   does not end up with a panel taller than the screen. */
html.bs-phone #win-build,
html.bs-phone #win-terraform,
html.bs-tablet #win-build,
html.bs-tablet #win-terraform {
  left: 8px !important;
  right: 8px !important;
  top: auto !important;
  /* Above the commit pad, which is itself above the measured dock. */
  bottom: calc(var(--bs-dock-h, 64px) + 98px) !important;
  width: auto !important;
  max-height: min(38dvh, 300px);
  margin-left: 0 !important;
  /* The shared touch rules centre a floating window with translate(-50%,-50%).
     Docking to the bottom edge means anchoring to it, so the centring transform
     has to go or the panel sits half off the left of the screen — measured at
     x = -171 on a 375-wide phone before this line. */
  transform: none !important;
  display: flex;
  flex-direction: column;
  z-index: 46;
}

html.bs-phone #win-build .win-body,
html.bs-phone #win-terraform .win-body,
html.bs-tablet #win-build .win-body,
html.bs-tablet #win-terraform .win-body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* Touch targets. 32px is fine under a mouse and misses under a thumb. */
html.bs-touch .bs-hist { min-height: 42px; font-size: 13px; }
html.bs-touch .bs-shapes .chip,
html.bs-touch .bs-brushes .chip { min-height: 52px; }
html.bs-touch .bs-slider input[type="range"] { height: 30px; }
html.bs-touch .bs-slider input[type="range"]::-webkit-slider-thumb { width: 24px; height: 24px; margin-top: -9px; }
html.bs-touch .bs-slider input[type="range"]::-moz-range-thumb { width: 24px; height: 24px; }
html.bs-touch .bs-danger { min-height: 44px; }

/* A short landscape phone has no vertical room for the prose. The hints are
   help for a first-time builder, not something to re-read every session.
   Gated on the handheld CLASS rather than `pointer: coarse` — bs-phone already
   establishes that this is a handheld, and double-gating it meant the rule
   silently did nothing wherever the two disagreed. */
/* LANDSCAPE PHONE — the panel moves to the SIDE.
   Stacking bottom-to-top does not survive 375px of height: dock 54, pad 62 and
   a panel that needs ~200 left 26px of visible world, measured, which is not
   enough to aim through. But a landscape phone is 812px WIDE. A 300px side
   sheet leaves ~500px of world at full height — the same panel, a usable view,
   and the aim point moves beside it rather than above it. */
@media (max-height: 460px) {
  html.bs-phone #win-build .hint,
  html.bs-phone #win-terraform .muted.small,
  html.bs-phone #win-build .muted.small { display: none; }
  html.bs-phone #win-build,
  html.bs-phone #win-terraform {
    left: 8px !important;
    right: auto !important;
    top: 8px !important;
    bottom: calc(var(--bs-dock-h, 56px) + 6px) !important;
    width: 300px !important;
    max-height: none;
  }
  /* Out of the world view and clear of the side sheet. */
  #bsBuildPad {
    left: auto;
    right: 12px;
    transform: none;
    bottom: calc(var(--bs-dock-h, 56px) + 6px);
    flex-direction: column-reverse;
  }
  #bsBuildPad button { min-width: 48px; min-height: 48px; }
  #bsBuildPad #bsPadDo { min-width: 62px; min-height: 62px; }
}

/* ---------------------------------------------------------------------------
   Reticle
   ---------------------------------------------------------------------------
   The touch aim point. A world-space ring already marks the target on the
   ground; this is the screen-space anchor that says WHERE the aim is taken
   from, so the two read as one instrument. */
#bsAimDot {
  display: none;
  position: fixed;
  left: 50%;
  /* `top` is set from app.js each frame — it tracks the middle of the world
     area left above the docked panel, not the middle of the screen. */
  top: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  z-index: 44;
  pointer-events: none;
  border-radius: 50%;
  border: 1px solid rgba(243, 223, 166, 0.9);
  box-shadow: 0 0 8px -2px rgba(243, 223, 166, 0.8), inset 0 0 6px -2px rgba(243, 223, 166, 0.6);
}

#bsAimDot::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 3px;
  height: 3px;
  margin: -1.5px 0 0 -1.5px;
  border-radius: 50%;
  background: rgba(243, 223, 166, 0.95);
}

#bsAimDot.on { display: block; }
#bsAimDot.blocked { border-color: rgba(255, 120, 120, 0.9); box-shadow: 0 0 8px -2px rgba(255, 120, 120, 0.8); }
#bsAimDot.blocked::after { background: rgba(255, 140, 140, 0.95); }
