/* ui — the design system, shared by every page of this project.
 *
 * WHY THIS IS A FILE AND NOT A <style> BLOCK
 *
 * It used to live inline at the top of zombie-shooter.html, back when that was
 * the only page. It isn't any more: the Studio, the body catalogs and the enemy
 * catalog are their own HTML entry points now (studio.html, bodies.html,
 * enemies.html), and all four need the same tokens. Inline meant either four
 * copies that drift or three pages that guess at the palette.
 *
 * WHAT BELONGS HERE
 *
 * The palette, the light-theme override js/theme.js flips, the two typefaces,
 * and the handful of primitives every screen composes (.mono, .chip, .btn,
 * .field, .card and friends). Nothing that knows about a particular screen —
 * the HUD, the lobby, the shop and the pause menu stay in the game's own
 * <style>, and each tool page injects its own from its module.
 *
 * WHAT IS DELIBERATELY NOT HERE
 *
 * The page background. The game paints black behind its canvas; the tool pages
 * want --bg-deep, which is not the same colour and follows the theme. Each page
 * sets its own on <body>.
 *
 * CACHING: this is code, not an asset — it changes with the HTML and must
 * expire with it. deploy.sh puts css/ under the same no-store Nginx rule as
 * shared/ and js/ for exactly that reason.
 */
/* ---------- design tokens ----------
   Every colour the UI uses, named for what it means rather than what it is.
   They are all colours the game already had — the redesign renamed and
   systematised them, it did not invent any. Two rules make the set work:
   one accent per meaning (amber = act/authoring, green = online/owned/safe,
   red = health/death), and selection is always accent border + tinted
   background + accent text, never a colour swap alone.

   Anything reading a raw hex instead of a var here is a place the palette
   cannot be retuned from one spot — prefer the var. */
:root {
  /* surfaces, dark to light */
  --bg-deep:    #05080f;   /* page and overlay base */
  --bg-panel:   #0a0f18;   /* panel surfaces */
  --bg-panel-2: #0d1220;   /* inputs, tiles, list rows */
  --bg-bar:     #070b13;   /* toolbars and status bars */
  --bg-view:    #0a0d14;   /* behind the canvas / viewport */
  /* borders, dim to bright */
  --bd:         #141c2e;   /* panel dividers */
  --bd-2:       #1f2a44;   /* control borders, dim */
  --bd-3:       #2a3550;   /* control borders, normal */
  --bd-4:       #232d47;   /* card borders */
  --bd-dash:    #3a466a;   /* drop targets, and the outlined-hover border */
  /* text, brightest to faintest */
  --tx:         #ffffff;
  --tx-2:       #cdd6ee;
  --tx-3:       #8b93a7;
  --tx-3b:      #9aa3b5;   /* descriptions */
  --tx-4:       #6a7288;   /* labels */
  --tx-5:       #5d677e;   /* metadata */
  --tx-6:       #3f4859;   /* faintest */
  /* amber — act, authoring, ammo */
  --am:         #fbbf24;
  --am-ink:     #1a1408;   /* text on amber */
  --am-bg:      #171208;   /* selected amber surface */
  --am-bd:      #4a3a10;   /* selected amber border */
  --am-sel:     rgba(251,191,36,.07);   /* amber-washed drop/selection surface */
  --am-glow:    rgba(251,191,36,.18);   /* amber hover bloom */
  /* green — online, success, owned, safe */
  --gr:         #86efac;
  --gr-ink:     #06140a;
  --gr-bg:      #0b1a12;
  --gr-bd:      #1f5133;
  /* red — health, death, destructive */
  --rd:         #f87171;
  --rd-ink:     #1a0808;
  --rd-deep:    #dc2626;
  --rd-mid:     #ef4444;
  --rd-dark:    #7f1d1d;
  --rd-bd:      #4a2020;   /* destructive control border */
  /* blue — stamina; link — the two authoring links */
  --bl:         #38bdf8;
  --lk:         #7dd3fc;
  --lk-h:       #a5e4ff;
  /* type: display for everything, mono for labels/metadata/key hints */
  --f-disp: 'Barlow Condensed', 'Segoe UI Semibold', 'Arial Narrow', system-ui, sans-serif;
  --f-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
  /* the two transition speeds the whole UI shares */
  --t-fast: 120ms ease-out;   /* hover and selection */
  --t-slow: 180ms ease-out;   /* panels and overlays opening */
  /* surfaces that float over a 3D viewport, and the viewport's own furniture.
     Vars rather than literals so the light theme below can swap them. */
  --chip-bg:    rgba(10,15,24,.85);     /* chips floating over the stage */
  --vgrid:      rgba(255,255,255,.03);  /* viewport grid lines */
  --th-ph:      #111827;   /* thumbnail placeholder */
  --th-ph-2:    #0b1220;
}
/* ---------- light theme ----------
   One override block, from the prop-catalog handoff. Applied by setting
   data-theme="light" on <html>, which js/theme.js does for every authoring
   screen off one stored preference (localStorage.bzs_props_theme). The tool
   pages also set it from an inline <head> script before first paint, so a
   light-mode author never sees a frame of the dark palette on the way in.
   The game does not opt in — it is a night-time shooter and its HUD is drawn
   against that; see the long note in js/theme.js. */
:root[data-theme="light"] {
  --bg-deep:    #e6e7ea;
  --bg-panel:   #f5f5f7;
  --bg-panel-2: #ffffff;
  --bg-bar:     #ececed;
  --bg-view:    #d9dade;
  --bd:         #d6d7dc;
  --bd-2:       #c6c8cf;
  --bd-3:       #b3b6c0;
  --bd-4:       #dcdde2;
  --bd-dash:    #9aa0ae;
  --tx:         #15171c;
  --tx-2:       #2b2f39;
  --tx-3:       #565c6b;
  --tx-3b:      #454b59;
  --tx-4:       #6b7280;
  --tx-5:       #828896;
  --tx-6:       #a0a5b1;
  --am:         #c2740a;
  --am-ink:     #ffffff;
  --am-bg:      #f8ead2;
  --am-bd:      #e4bd85;
  --am-sel:     rgba(194,116,10,.10);
  --am-glow:    rgba(194,116,10,.22);
  --gr:         #15803d;
  --gr-bg:      #e8f5ec;
  --gr-bd:      #b6dcc4;
  --lk:         #1d6fa5;
  --lk-h:       #12547e;
  --chip-bg:    rgba(255,255,255,.88);
  --vgrid:      rgba(0,0,0,.05);
  --th-ph:      #e3e4e9;
  --th-ph-2:    #eceef2;
}
/* The only thing in the UI that animates continuously: the green server /
   network status dot. Everything else moves only in response to a person. */
@keyframes pulseG { 0%, 100% { opacity: .35 } 50% { opacity: .9 } }

/* ---------- shared primitives ----------
   The handoff's recurring controls, defined once. Screens compose these
   rather than restating the same border/radius/tracking triplet, which is
   what kept the old UI's chips subtly disagreeing with each other. */

/* Mono label: uppercase, tracked, small. The default for any label,
   metadata, key hint, status line or numeric id in the design. */
.mono {
  font-family: var(--f-mono); font-weight: 500; font-size: 11px;
  letter-spacing: 1.5px; text-transform: uppercase;
}
.mono.xs { font-size: 9px; letter-spacing: 1.2px; }
.mono.sm { font-size: 10px; }
.mono.lg { font-size: 12px; letter-spacing: 2px; }

/* Chip / pill: a bordered nowrap scrap of status or a small action. Every
   one is flex-shrink:0 so a crowded toolbar scrolls rather than squashing. */
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px; border: 1px solid var(--bd-2); border-radius: 7px;
  background: var(--bg-panel-2); color: var(--tx-3);
  white-space: nowrap; flex-shrink: 0;
  font-family: var(--f-mono); font-weight: 500; font-size: 10px;
  letter-spacing: 1.5px; text-transform: uppercase;
}
.chip.pill { border-radius: 999px; }
.chip.on  { border-color: var(--am); background: var(--am-bg); color: var(--am); }
.chip.ok  { border-color: var(--gr-bd); background: var(--gr-bg); color: var(--gr); }
.chip.off { color: var(--tx-5); }
button.chip, a.chip { cursor: pointer; transition: border-color var(--t-fast), color var(--t-fast); }
button.chip:hover, a.chip:hover { border-color: var(--bd-dash); color: var(--tx-2); }

/* Buttons. Amber and green never change colour on hover — they bloom, and
   press pushes them down 1px. Outlined controls brighten border and text.
   Stated once here because the design applies it to every button it has. */
.btn {
  border: 0; border-radius: 10px; cursor: pointer;
  font-family: var(--f-disp); font-weight: 700; font-size: 20px;
  letter-spacing: 3px; text-transform: uppercase; padding: 16px;
  transition: box-shadow var(--t-fast), transform var(--t-fast),
              border-color var(--t-fast), color var(--t-fast);
}
.btn:active { transform: translateY(1px); }
.btn.amber { background: var(--am);  color: var(--am-ink); }
.btn.green { background: var(--gr);  color: var(--gr-ink); }
.btn.red   { background: var(--rd);  color: var(--rd-ink); }
.btn.amber:hover { box-shadow: 0 0 40px rgba(251,191,36,.18); }
.btn.green:hover { box-shadow: 0 0 40px rgba(134,239,172,.18); }
.btn.red:hover   { box-shadow: 0 0 40px rgba(248,113,113,.18); }
.btn.out {
  background: transparent; color: var(--tx-2);
  border: 1px solid var(--bd-3); font-weight: 600; font-size: 17px;
  letter-spacing: 2px; padding: 15px;
}
.btn.out:hover { border-color: var(--bd-dash); color: var(--tx); }
.btn.sm { font-size: 15px; font-weight: 600; letter-spacing: 2px; padding: 9px 14px; border-radius: 8px; }
.btn.danger { border-color: var(--rd-bd); color: var(--rd); }
.btn.danger:hover { border-color: var(--rd); }
.btn:disabled { opacity: .4; cursor: default; transform: none; box-shadow: none; }

/* Text input / select row: the same shell whether it holds a value or opens
   a list. Amber border marks the one field a screen wants you in. */
.fld {
  background: var(--bg-panel-2); border: 1px solid var(--bd-3);
  border-radius: 10px; color: var(--tx); padding: 15px 18px; outline: none;
  font-family: var(--f-disp); font-weight: 600; font-size: 20px;
  line-height: 1.2; letter-spacing: 1px;
  transition: border-color var(--t-fast);
}
.fld:focus { border-color: var(--am); }
.fld.hot { border-color: var(--am); color: var(--am); }

/* Label + control column. Layout gaps are always gap, never sibling margins. */
.field { display: flex; flex-direction: column; gap: 7px; }
.field > label {
  font-family: var(--f-mono); font-weight: 500; font-size: 11px;
  letter-spacing: 2px; text-transform: uppercase; color: var(--tx-4);
}

/* Segmented control: the editor's tool/snap groups and the catalog's tabs. */
.seg {
  display: inline-flex; padding: 3px; gap: 2px; background: var(--bg-panel-2);
  border: 1px solid var(--bd-2); border-radius: 8px; flex-shrink: 0;
}
.seg > button {
  background: transparent; border: 0; border-radius: 6px; cursor: pointer;
  padding: 6px 11px; color: var(--tx-3); white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--f-mono); font-weight: 500; font-size: 10px;
  letter-spacing: 1.5px; text-transform: uppercase;
  transition: background var(--t-fast), color var(--t-fast);
}
.seg > button:hover { color: var(--tx-2); }
.seg > button.on { background: var(--am); color: var(--am-ink); }
.seg > button.on.neutral { background: var(--bd-2); color: var(--tx); }
.seg > button:disabled { color: var(--tx-6); cursor: default; }
.seg svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.6; }

/* Toggle: 38x21 pill, 15x15 knob, 3px inset. On = accent fill + dark knob. */
.tog {
  width: 38px; height: 21px; border-radius: 999px; border: 0; padding: 0;
  background: var(--bd-2); position: relative; cursor: pointer; flex-shrink: 0;
  transition: background var(--t-fast);
}
.tog::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 15px; height: 15px; border-radius: 50%; background: var(--tx-5);
  transition: transform var(--t-fast), background var(--t-fast);
}
.tog.on { background: var(--gr); }
.tog.on::after { transform: translateX(17px); background: var(--gr-ink); }
.tog.amber.on { background: var(--am); }
.tog.amber.on::after { background: var(--am-ink); }
/* A toggle row: label on the left, the pill on the right. */
.togrow {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-family: var(--f-disp); font-weight: 600; font-size: 16px; color: var(--tx-2);
}

/* Bars. 3-10px tall, radius 2-5, faint white track, accent fill. Set the
   fill's width; --v is there so a caller can drive it from one property. */
.bar { position: relative; overflow: hidden; background: rgba(255,255,255,.12); border-radius: 3px; height: 4px; }
.bar > i { position: absolute; left: 0; top: 0; bottom: 0; width: var(--v, 0%); border-radius: 3px; background: var(--am); display: block; }
.bar.green > i { background: var(--gr); }
.bar.red > i   { background: var(--rd); }
.bar.blue > i  { background: var(--bl); }

/* A slider drawn as one of those bars with a 14px knob on it. The real
   <input type=range> sits on top at zero opacity so the control stays a
   keyboard-operable range input and not a div that looks like one. */
.slider { position: relative; height: 16px; display: flex; align-items: center; }
.slider > .bar { flex: 1; }
.slider > .knob {
  position: absolute; width: 14px; height: 14px; border-radius: 50%;
  background: var(--am); left: var(--v, 0%); transform: translateX(-50%);
  pointer-events: none;
}
.slider.green > .knob { background: var(--gr); }
.slider > input[type=range] {
  position: absolute; inset: 0; width: 100%; margin: 0;
  opacity: 0; cursor: pointer;
}

/* A 1px vertical hairline between toolbar groups. */
.vr { width: 1px; height: 22px; background: var(--bd); flex-shrink: 0; }

/* Number over label, the design's one way of showing a quantity: the value
   large in Barlow Condensed, its name small in mono underneath or beside. */
.stat { display: flex; flex-direction: column; gap: 4px; }
.stat > b { font-family: var(--f-disp); font-weight: 700; font-size: 38px; line-height: 1; color: var(--tx); }
.stat > span {
  font-family: var(--f-mono); font-weight: 500; font-size: 10px;
  letter-spacing: 2px; text-transform: uppercase; color: var(--tx-5);
}
.stat.amber > b { color: var(--am); }
.stat.green > b { color: var(--gr); }
.stat.red > b   { color: var(--rd); }

/* Card: the shell every panel and dialog section shares. */
.card {
  background: var(--bg-panel); border: 1px solid var(--bd-4);
  border-radius: 14px; padding: 24px 26px;
}

/* ---------- the authoring toolbar button ----------

   The small tracked-mono button every authoring surface puts in its header bar
   and its action rows. It was written out four times — `.stuBtn` (js/studio.js),
   `.bdBtn` (js/bodies.js), `.enBtn` (js/enemy-catalog.js) and `.galHead button`
   (js/gallery.js) — with the same six declarations in each, which is how
   `.bdBtn.go` came to be amber while the same "go" action was green on the other
   two. Retuning the shape now happens here, once.

   `.toolBtn` is the name to reach for in new code. The four legacy names ride
   the same selectors rather than being renamed at ~70 call sites: this is a
   cleanup, and a typo in one of those would silently unstyle a button that
   nothing tests. All four pages load this file, the game page included.

   Two deltas are deliberate and stay with their page: `.galHead button` keeps
   its roomier padding and wider tracking (it sits under a 22px display heading,
   not in a dense toolbar), and `.on` means different things in two places —
   pale-green "this mode is active" in the Studio, amber "this tab is selected"
   in the enemy catalog. That disagreement is real and is a UI question, not a
   CSS one, so it is left visible rather than silently resolved here. */
.toolBtn, .stuBtn, .bdBtn, .enBtn, .galHead button {
  font-family: var(--f-mono, monospace); font-size: 10px; letter-spacing: 1.2px;
  text-transform: uppercase; padding: 7px 11px; border-radius: 7px; cursor: pointer;
  background: var(--bg-panel-2, #0d1220); color: var(--tx-3, #8b93a7);
  border: 1px solid var(--bd-2, #1f2a44); text-decoration: none; display: inline-block;
}
.toolBtn:hover:not(:disabled), .stuBtn:hover:not(:disabled), .bdBtn:hover:not(:disabled),
.enBtn:hover:not(:disabled), .galHead button:hover:not(:disabled) {
  border-color: var(--bd-dash, #3a466a); color: var(--tx-2, #cdd6ee);
}
/* Green = go/safe, red = destructive, amber = caution. One accent per meaning. */
.toolBtn.go, .stuBtn.go, .bdBtn.go, .enBtn.go { border-color: var(--gr); color: var(--gr); }
.toolBtn.bad, .stuBtn.bad, .bdBtn.bad, .enBtn.bad { border-color: var(--rd); color: var(--rd); }
.toolBtn.warn, .stuBtn.warn, .bdBtn.warn, .enBtn.warn { border-color: var(--am); color: var(--am); }
.toolBtn:disabled, .stuBtn:disabled, .bdBtn:disabled, .enBtn:disabled { opacity: .42; cursor: default; }
/* An author `display` beats the UA's [hidden] rule, so a footer button with no
   token was shown anyway — greyed out, but there, offering to publish. */
.toolBtn[hidden], .stuBtn[hidden], .bdBtn[hidden], .enBtn[hidden] { display: none; }

/* Keyboard focus has to be VISIBLE on the rows and tiles that are divs wearing
   role="button" — a real <button> gets a ring from the UA, these get nothing, so
   tabbing through the Studio's rig rows or the prop grid moved an invisible
   cursor. :focus-visible rather than :focus, so a mouse click does not leave a
   ring behind it. */
[role="button"]:focus-visible {
  outline: 2px solid var(--am);
  outline-offset: 2px;
}

/* No background here on purpose — see the note at the top of this file. Every
   page sets its own on <body>, because the game wants black behind its canvas
   and the tool pages want the themed surface. */
html, body { margin: 0; height: 100%; overflow: hidden; font-family: var(--f-disp); }

/* ---------------------------------------------------------------------------
   Collision boxes — the per-box list in the Studio's Size and collision section.

   One row per box a prop collides as. The row is the reliable way to pick a box
   out and to set whether its top is a surface feet land on; clicking the box on
   the turntable does the same thing, and this is what makes it discoverable and
   keyboard-reachable.

   The swatch repeats the colour the box is drawn in, so the list and the picture
   are read as one thing rather than as two lists of numbers. Amber for the
   selected row, which is this page's selection colour everywhere else.
   --------------------------------------------------------------------------- */
.stuBoxes { display: flex; flex-direction: column; gap: 3px; margin-top: 6px; }

.stuBox {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 7px; border: 1px solid var(--bd-2); border-radius: 5px;
  background: var(--bg-panel-2); cursor: pointer; font-size: 11px;
  color: var(--tx-2);
}
.stuBox:hover { border-color: var(--bd-3); }
.stuBox.on { border-color: var(--am-bd); background: var(--am-bg); }
/* With the edit panel attached below, the selected row reads as its header. */
.stuBox.on:has(+ .stuBoxEdit) { border-radius: 5px 5px 0 0; }

/* The box's own colour, matching the turntable: green stands, blue does not. */
.stuBox .sw {
  width: 9px; height: 9px; border-radius: 2px; flex: 0 0 auto;
}
.stuBox .n { color: var(--tx-4); min-width: 1em; font-variant-numeric: tabular-nums; }
.stuBox .d { flex: 1 1 auto; font-variant-numeric: tabular-nums; }

/* The standable tick. Its own label so a click on it does not also move the
   selection — see the guard in the Studio's click handler. */
.stuBox .st {
  display: flex; align-items: center; gap: 4px; flex: 0 0 auto;
  color: var(--tx-3b); cursor: pointer; white-space: nowrap;
}
.stuBox .st input { margin: 0; }

/* The selected box's own fields, under its row: position, size, heights, turn,
   and — when its top is standable — the height feet actually land at, which is
   how a curved roof stops floating (top may sit below the apex; a rock's shelf
   has done that since before boxes existed). Inputs live-update the cage; the
   repaint waits for the commit so it cannot replace the field mid-keystroke. */
.stuBoxEdit {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px 6px;
  padding: 6px 7px 7px; margin-top: -2px;
  border: 1px solid var(--am-bd); border-top: none; border-radius: 0 0 5px 5px;
  background: var(--am-bg);
}
.stuBoxEdit label {
  display: flex; flex-direction: column; gap: 2px;
  font-size: 9.5px; color: var(--tx-4); text-transform: uppercase;
  letter-spacing: 0.04em;
}
.stuBoxEdit input {
  width: 100%; box-sizing: border-box; font-size: 11px;
  background: var(--bg-panel-2); color: var(--tx-2);
  border: 1px solid var(--bd-3); border-radius: 4px; padding: 3px 5px;
}

/* Delete this one box. Its own row under the fields rather than a seventh cell
   among them: it is not a value to set, and a destructive control sitting in the
   grid where Width and Depth are is one mis-click from the field beside it. */
.stuBoxEdit .rm { grid-column: 1 / -1; justify-self: start; margin-top: 3px; }
