html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: #0f1a10;
  font-family: 'Segoe UI', system-ui, sans-serif;
  color: #f3ecd8;
}

.gathering-page {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.gathering-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  background: #1c2b1a;
  border-bottom: 2px solid #4a6b3a;
  flex-shrink: 0;
  gap: 12px;
  flex-wrap: wrap;
}

.gathering-topbar h1 {
  font-size: 16px;
  margin: 0;
  color: #f3d98b;
  letter-spacing: 0.03em;
}

.gathering-topbar .subtitle {
  font-size: 11px;
  color: #b7c9ab;
  margin-left: 8px;
}

.resource-bar {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.resource-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  background: #26381f;
  border: 1px solid #4a6b3a;
  border-radius: 999px;
  padding: 4px 10px;
  font-size: 12px;
}

.resource-pill .amt {
  font-weight: 700;
  color: #f3d98b;
}

/* Mobile Funnel Fixes + Playtest UX Round — Item 6: replaces the old
   one-pill-per-resource flat row (still used for the "No resources
   harvested yet" empty state via .resource-pill above) with a compact
   row of small labeled group boxes — the whole point being ONE row that
   never grows past a handful of boxes regardless of how many individual
   resources exist behind them. */
.resource-bar-groups {
  display: flex;
  gap: 6px;
}

.resource-group-box {
  min-width: 34px;
  height: 30px;
  padding: 0 8px;
  border-radius: 8px;
  background: #26381f;
  border: 1px solid #4a6b3a;
  color: #f3d98b;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  touch-action: manipulation;
}
.resource-group-box:hover { background: #33482a; border-color: #caa54d; }
.resource-group-box.active {
  background: #caa54d;
  border-color: #f3d98b;
  color: #1c1c1c;
}

.resource-group-panel {
  position: fixed;
  z-index: 45;
  min-width: 200px;
  max-width: min(80vw, 280px);
  max-height: 60vh;
  overflow-y: auto;
  background: rgba(24, 20, 12, 0.96);
  border: 1px solid #caa54d;
  border-radius: 12px;
  padding: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  box-sizing: border-box;
}

.resource-group-panel-title {
  font-size: 11px;
  font-weight: 700;
  color: #caa54d;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(74, 107, 58, 0.5);
}

.resource-group-panel-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.resource-group-panel-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 0;
}

.resource-group-panel-icon {
  width: 20px;
  height: 20px;
  object-fit: contain;
  flex-shrink: 0;
}

.resource-group-panel-icon-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #4a6b3a;
  flex-shrink: 0;
  margin: 0 6px;
}

.resource-group-panel-name {
  flex: 1;
  font-size: 12px;
  color: #f3ecd8;
}

.resource-group-panel-amt {
  font-size: 12px;
  font-weight: 700;
  color: #f3d98b;
}

.gathering-stage {
  position: relative;
  flex: 1;
  overflow: hidden;
  background: #16241a; /* fallback only — the backdrop itself is canvas-drawn so it pans/zooms with the grid */
}

.gathering-stage canvas {
  position: absolute;
  inset: 0;
  cursor: grab;
  /* Mobile Round 2: without this, the browser's own gesture recognizer is
     free to decide a one-finger drag is a page scroll and cancel the
     pointer-event sequence mid-gesture — the actual cause of pan "working
     for a fraction of a second, then stopping." Also stops the browser from
     fighting the new pinch-to-zoom handling in main.js with its own
     gesture. */
  touch-action: none;
}
.gathering-stage canvas.panning { cursor: grabbing; }

/* Floating overlay layer for DOM-based UI cards positioned over the canvas */
.gathering-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.gathering-overlay > * { pointer-events: auto; }

.info-card, .node-card {
  background: rgba(24, 20, 12, 0.94);
  border: 1px solid #caa54d;
  border-radius: 8px;
  /* Post-Deploy Bug Fixes + UX Pass — UX 1: all these desktop-tier values
     (width/padding/font-size, and every other size figure in this rule's
     descendants below) are scaled to 75% of what they were, to stop popup
     cards from cluttering the map. Every property touched here is FULLY
     overridden by the @media (max-width: 640px) block further down, so
     mobile inherits none of this — verified property-by-property, not
     assumed. Only .close's top/right POSITION (not touched by that mobile
     block) is deliberately left alone, so mobile's close-button placement
     stays pixel-identical too. */
  padding: 15px 18px;
  width: clamp(180px, 68vw, 240px);
  box-sizing: border-box;
  font-size: 18px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
}
/* Post-Deploy Bug Fixes + UX Pass Round 3 — Item 8: .gathering-stage (the
   canvas's parent) has overflow:hidden, which clips ANY descendant
   positioned outside the stage's own box — no z-index can rescue an
   element from being clipped by an ancestor's overflow:hidden, only
   escaping that ancestor can. .node-card stays exactly as before
   (position:absolute inside .gathering-overlay) — this fix is scoped to
   the hover .info-card specifically, per the handoff's own report target.
   showHoverCard (main.js) now appends .info-card straight to document.body
   ("portal" style) instead of .gathering-overlay, so position:fixed here
   places it relative to the real viewport, immune to the stage's clipping
   and safely above every other layer at this z-index. positionCardAt/
   clampCardToViewport (main.js) both account for the coordinate-space
   change via their new opts.portal path. */
.info-card {
  position: fixed;
  z-index: 120;
}
/* Round 9 — Requirement D: NOT a regression — the Round 3 fix above only
   ever targeted .info-card (the hover tooltip), by its own explicit scope
   ("scoped to the hover .info-card specifically, per the handoff's own
   report target"). .node-card (the tap-to-open popup — output selector,
   Coconut Tree panel, etc.) was deliberately left untouched at the time and
   has carried z-index:20 ever since, comfortably lower than the HUD's own
   layers (.resource-group-panel: 45, .badge-toast: 41, .player-badge: 40) —
   confirmed by reading every z-index in this file, not guessed. Whenever a
   node-card visually overlaps one of those, the HUD element wins and the
   popup renders underneath it — confirmed live (Coconut Tree output panel
   under the Materials panel). Raised above all of them; still position:
   absolute inside .gathering-overlay (not portaled to body like .info-card
   — that also fixes an unrelated clipping issue .node-card doesn't
   currently have reported against it, so out of scope here per this
   round's own "flag divergences, don't over-fix" standing rule). */
.node-card {
  position: absolute;
  z-index: 50;
}
/* UX 4: fixed center-middle position for the interactive structure card
   (showStructureCard, main.js) — overrides whatever positionCardAt would
   have set, so this one card always lands in the same predictable spot
   instead of near the click. */
.card-centered {
  left: 50% !important;
  top: 50% !important;
  transform: translate(-50%, -50%) !important;
}

/* Post-Deploy Bug Fixes + UX Pass Round 3 — Item 7: width before height.
   .node-card's normal 240px cap (see the base .info-card, .node-card rule
   above) is fine for a single stacked column of 1-3 options, but the
   6-option Produce tab's 2-column .option-grid squeezes each column to
   ~100px there — nowhere near enough for "34 Ash → 17 Sodium
   Hydroxide" on one line. .structure-card (showStructureCard's own class,
   alongside .node-card) gets a wider cap instead of letting text wrap
   across many lines. Deliberately scoped to ONLY .structure-card — plain
   .node-card (tree cards) and .info-card (hover cards) are completely
   unaffected, on both this tier and the mobile override below. */
.node-card.structure-card {
  width: clamp(240px, 85vw, 460px);
}

/* .card-above / .card-below are added in main.js's positionCardAt() as
   semantic markers only (checked by some tests) — the actual transform is
   set inline per-card there too, since it also depends on left/right
   placement (Round 8 item 3: the card displaces away from the hovered
   node's own sprite/tile bounds on BOTH axes, not just centered above/below
   it, so a plain top/bottom-only CSS rule can no longer express it alone). */

.info-card .title, .node-card .title {
  font-weight: 700;
  color: #f3d98b;
  margin-bottom: 6px;
  font-size: 20px;
}

.info-card .row, .node-card .row { display: flex; justify-content: space-between; gap: 15px; color: #d8d0ba; }

/* Mobile-Tap Round 5 — Item 2: the live-updating accumulation value gets a
   slightly warmer emphasis than a plain row value, since it's the one field
   that's actually changing while the card is open. */
.node-card .accumulated-value { color: #f3d98b; font-weight: 600; }

/* Cleanup Round — Item 4: the Haven card's single line of flavor text —
   distinct from .row (a label/value pair, flex space-between), which
   doesn't fit a single sentence. */
.node-card .flavor-text {
  display: block;
  opacity: 0.85;
  color: #d8d0ba;
  margin: 4px 0 10px;
  font-size: 15px;
  line-height: 1.4;
}

.node-card button {
  display: block;
  width: 100%;
  text-align: left;
  background: #2c3f24;
  border: 1px solid #4a6b3a;
  color: #f3ecd8;
  border-radius: 6px;
  padding: 9px 12px;
  margin-top: 9px;
  cursor: pointer;
  font-size: 18px;
}
.node-card button:hover { background: #3d5730; border-color: #caa54d; }

/* UX 2: standing rule — no option-card column exceeds 3 rows. Buttons
   wrapped in this container (outputSelectorHtml, structureProduceOptionsHtml)
   flow into a new column every 3 items instead of stacking indefinitely —
   the 6-option structure Produce tab becomes 2 columns x 3 rows; a 1-3
   option tree card still renders as a single column, pixel-equivalent to
   the old stacked layout, since everything fits within the first column's
   3 rows. Generalizes to any future option count with no further changes. */
.option-grid {
  display: grid;
  grid-template-rows: repeat(3, auto);
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 8px;
  margin-top: 9px;
}
.option-grid button {
  margin-top: 0; /* the grid's own gap replaces the individual stacked-button margin */
}

/* Mobile-Tap Round 5 — Item 2: marks whichever output button matches
   node.selectedOutput, so a re-opened/re-rendered card makes it visually
   obvious what's currently producing among the choices, not just via the
   ✓ mark in the button's own text. */
.node-card button.selected {
  background: #3d5730;
  border-color: #caa54d;
}

.node-card button .rate-line {
  display: block;
  font-size: 15px;
  color: #b7c9ab;
  margin-top: 3px;
}

.node-card .close {
  position: absolute;
  top: 8px;
  right: 12px;
  cursor: pointer;
  color: #b7c9ab;
  font-size: 18px;
  background: none;
  border: none;
  width: auto;
  margin: 0;
  padding: 3px 6px;
}

/* Wave 1 Handoff — Item 4: Produce/Upgrade tabs on a structure's card —
   same visual language as .build-menu-tab (build.js's tab bar), as its own
   class rather than reusing that one directly since it lives in a
   .node-card, not the build menu panel. */
.structure-tabs {
  display: flex;
  gap: 5px;
  margin-top: 6px;
}
.structure-tab {
  background: #2c3f24;
  border: 1px solid #4a6b3a;
  color: #d8d0ba;
  border-radius: 8px 8px 0 0;
  padding: 5px 11px;
  font-size: 12px;
  cursor: pointer;
  width: auto;
  margin: 0;
}
.structure-tab:hover { background: #3d5730; }
.structure-tab.active {
  background: #caa54d;
  border-color: #f3d98b;
  color: #1c1c1c;
}

/* Wave 1 Handoff — Item 4: an unaffordable production-tier option — same
   red-tinted convention .build-item.unaffordable already uses for the
   build menu, applied to .node-card's own button styling here instead. */
.node-card button.unaffordable {
  cursor: default;
  border-color: #8a4a4a;
  opacity: 0.75;
}
.node-card button.unaffordable:hover { background: #2c3f24; border-color: #8a4a4a; }
.node-card button.unaffordable .rate-line { color: #e08a8a; }

.harvest-float {
  position: absolute;
  transform: translate(-50%, -50%);
  color: #ffe9a8;
  font-weight: 700;
  font-size: 14px;
  text-shadow: 0 1px 3px rgba(0,0,0,0.8);
  pointer-events: none;
  z-index: 30;
  animation: harvest-drift 3.3s ease-out forwards;
}

@keyframes harvest-drift {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
  8%   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  80%  { opacity: 1; transform: translate(-50%, -150%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -180%) scale(1); }
}

/* Sell-Asset Round 2: was bottom-center, directly behind the (also
   bottom-center) toolbar once that existed. Bottom-left stays clear of the
   toolbar as more buttons are added — a pragmatic corner, not a final
   design; this text is expected to be reworked entirely later. */
.gathering-hint {
  position: absolute;
  bottom: 10px;
  left: 10px;
  font-size: 11px;
  color: #cdd8bd;
  background: rgba(0,0,0,0.4);
  padding: 4px 10px;
  border-radius: 6px;
  z-index: 5;
  max-width: 60vw;
  box-sizing: border-box;
}

/* Sell-Asset Round 2: on a narrow phone viewport, 60vw is wide enough to
   reach under the bottom-center toolbar (measured overlap at 390px: hint
   right edge 264px vs toolbar left edge 140px) — confirmed by an actual
   layout check, not assumed. 640px matches the breakpoint convention used
   elsewhere in this project. This narrower cap only clears TODAY's 2-button
   toolbar with margin; it will need revisiting as more buttons arrive and
   the toolbar widens further (same "reworked later" caveat as the corner
   placement itself). */
@media (max-width: 640px) {
  .gathering-hint {
    max-width: 110px;
    font-size: 10px;
  }
}

/* Round 11 item 2 — dev-only anchor debug overlay indicator (not shipped
   UI, just a "yes this is on" confirmation so it's never mistaken for a
   real bug when toggled on/off during play-testing). */
.debug-anchor-indicator {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 12px;
  font-weight: 600;
  color: #1c1c1c;
  background: #ffe14d;
  padding: 5px 12px;
  border-radius: 6px;
  z-index: 30;
}

/* Move-Asset Round 1 — Feature 1. Bottom-center toolbar, Elvenar-style.
   Deliberately sized to its CONTENT (fit-content via inline-flex, not a
   fixed/full-width box) and positioned only at bottom-center — taps
   anywhere else on the stage still reach the canvas underneath with no
   pointer-events trickery needed, the same way .gathering-hint and
   .debug-anchor-indicator already coexist with the canvas below them.
   Expandable: the 7 future buttons (sell/upgrade/build/research/world map/
   trader/inventory) are just more .toolbar-btn children of this same flex
   row — adding them is a content change, not a layout redesign. */
.gathering-toolbar {
  position: absolute;
  left: 50%;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  display: inline-flex;
  gap: 8px;
  padding: 6px;
  background: rgba(24, 20, 12, 0.9);
  border: 1px solid #4a6b3a;
  border-radius: 16px;
  z-index: 25;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
}

.toolbar-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  /* 44px is the accepted comfortable minimum touch-target size (see the
     mobile info-card sizing rounds' tap-target research) — this container
     is the tap target itself, not just its visible icon. */
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  border-radius: 10px;
  background: #2c3f24;
  border: 1px solid #4a6b3a;
  color: #f3ecd8;
  cursor: pointer;
  touch-action: manipulation;
  padding: 0;
}
.toolbar-btn:hover { background: #3d5730; border-color: #caa54d; }
/* Active/inactive state (move mode on = visibly highlighted). */
.toolbar-btn.active {
  background: #caa54d;
  border-color: #f3d98b;
  color: #1c1c1c;
}

/* Round 7.1 — Item 2: a real link (not a mode toggle) among the toolbar's
   other buttons, so it needs both the anchor-default underline suppressed
   and a visual break from its siblings — a left margin + border reads as
   "separate group" without needing a whole second toolbar. */
.toolbar-btn-home {
  text-decoration: none;
  margin-left: 4px;
  padding-left: 8px;
  border-left: 1px solid rgba(243, 236, 216, 0.25);
  border-radius: 0 10px 10px 0;
}
.toolbar-btn-home:hover { background: #3d5730; border-color: #caa54d; }

/* Floating confirm/cancel pair for a move-destination preview — sized like
   the info-card system's small controls, positioned via that same
   positionCardAt/clampCardToViewport code path (main.js) so it's never
   off-screen, just like info cards. */
.move-confirm-bar {
  position: absolute;
  display: inline-flex;
  gap: 8px;
  padding: 6px;
  background: rgba(24, 20, 12, 0.9);
  border: 1px solid #caa54d;
  border-radius: 14px;
  z-index: 26;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
}
/* The `hidden` attribute and this class both carry equal (0,1,0)
   specificity, and an author rule beats the UA default `[hidden]{display:
   none}` regardless of specificity — so without this explicit override,
   the flex rule above wins and the bar shows even while `hidden`. */
.move-confirm-bar[hidden] {
  display: none;
}
.move-confirm, .move-cancel {
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  border-radius: 10px;
  border: 1px solid #4a6b3a;
  font-size: 20px;
  font-weight: 700;
  cursor: pointer;
  touch-action: manipulation;
  padding: 0;
}
.move-confirm { background: #2f5c2f; color: #d8f5d8; border-color: #4a8a4a; }
.move-confirm:hover { background: #3a713a; }
.move-cancel { background: #5c2f2f; color: #f5d8d8; border-color: #8a4a4a; }
.move-cancel:hover { background: #713a3a; }

/* Sell-Asset Round 2 — red accent throughout, so Sell never reads as
   "the same thing as Move" at a glance: the toolbar button's active state,
   the confirm bar's border, and the toast all share the same red. The
   confirm (✓) / cancel (✗) BUTTONS themselves keep Move's green/red
   colors (universal go/stop meaning) — only the bar chrome around them
   carries the mode's own accent. */
.toolbar-btn-sell.active {
  background: #8a3a3a;
  border-color: #d97a7a;
  color: #fff0f0;
}
.toolbar-btn-sell.active:hover { background: #9c4444; }

.sell-confirm-bar {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 10px;
  background: rgba(24, 20, 12, 0.94);
  border: 1px solid #d97a7a;
  border-radius: 14px;
  z-index: 26;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  max-width: 240px;
}
.sell-confirm-bar[hidden] { display: none; }
.sell-confirm-text {
  font-size: 14px;
  color: #f3ecd8;
  text-align: center;
}
.sell-confirm-buttons {
  display: flex;
  gap: 8px;
}

.sell-toast {
  position: absolute;
  top: 60px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(138, 58, 58, 0.95);
  color: #fff0f0;
  border: 1px solid #d97a7a;
  padding: 8px 16px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  z-index: 27;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  transition: opacity 0.2s ease;
}
.sell-toast[hidden] { display: none; }

/* Build-Menu Round 3 — Feature 2 confirm bar. Gold accent (matches the
   toolbar's existing .toolbar-btn.active gold) so it reads as its own mode,
   distinct from Move's neutral bar and Sell's red one. */
.build-confirm-bar {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 10px;
  background: rgba(24, 20, 12, 0.94);
  border: 1px solid #caa54d;
  border-radius: 14px;
  z-index: 26;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  max-width: 240px;
}
.build-confirm-bar[hidden] { display: none; }
.build-confirm-text {
  font-size: 14px;
  color: #f3ecd8;
  text-align: center;
}
.build-confirm-text:empty { display: none; }
.build-confirm-buttons {
  display: flex;
  gap: 8px;
}

.build-toast {
  position: absolute;
  top: 60px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(138, 108, 58, 0.95);
  color: #fff8ec;
  border: 1px solid #caa54d;
  padding: 8px 16px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  z-index: 27;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  transition: opacity 0.2s ease;
}
.build-toast[hidden] { display: none; }

/* Build-Menu Round 3 — Feature 1. Full-stage dim backdrop; desktop centers
   the panel over the map, mobile (media query below) anchors it as a
   slide-up sheet instead. This overlay intentionally captures ALL pointer
   input across the stage while open (unlike .gathering-hint/.gathering-
   toolbar, which deliberately let clicks pass through to the canvas) —
   "only one mode/panel active at a time" means the canvas underneath must
   not be tappable while the menu is up. */
.build-menu {
  position: absolute;
  inset: 0;
  z-index: 35;
  background: rgba(10, 14, 8, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
}
.build-menu[hidden] { display: none; }

.build-menu-panel {
  width: min(92vw, 520px);
  max-height: 82vh;
  display: flex;
  flex-direction: column;
  background: #1c2b1a;
  border: 1px solid #4a6b3a;
  border-radius: 14px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  overflow: hidden;
}

.build-menu-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 10px 0 14px;
  flex-shrink: 0;
}

/* Tab bar — a scaffold (build.js's BUILD_TABS drives how many render here);
   adding a 4th tab (e.g. Decorations) needs no layout change, just wraps if
   it doesn't fit on one line. */
.build-menu-tabs {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.build-menu-tab {
  background: #2c3f24;
  border: 1px solid #4a6b3a;
  color: #d8d0ba;
  border-radius: 8px 8px 0 0;
  padding: 8px 16px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  min-height: 44px;
}
.build-menu-tab:hover { background: #3d5730; }
.build-menu-tab.active {
  background: #caa54d;
  border-color: #f3d98b;
  color: #1c1c1c;
}

.build-menu-close {
  width: 36px;
  height: 36px;
  min-width: 36px;
  border-radius: 8px;
  background: #2c3f24;
  border: 1px solid #4a6b3a;
  color: #f3ecd8;
  font-size: 18px;
  cursor: pointer;
  flex-shrink: 0;
}
.build-menu-close:hover { background: #3d5730; border-color: #caa54d; }

.build-menu-body {
  padding: 14px;
  overflow-y: auto;
  flex: 1;
}

/* UX 3: 3x3 grid (was 2x3) of large item buttons — caps at 9 items/page,
   see build.js's BUILD_ITEMS_PER_PAGE and main.js's renderBuildMenu.
   Mobile media query below shrinks item sizing but keeps the same 3-across
   layout. */
.build-item-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.build-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  background: #26381f;
  border: 1px solid #4a6b3a;
  border-radius: 10px;
  padding: 12px 10px;
  min-height: 150px;
  color: #f3ecd8;
  cursor: pointer;
  text-align: center;
}
.build-item:hover { background: #33482a; border-color: #caa54d; }

.build-item-art {
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.build-item-art img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.build-item-art-placeholder {
  width: 100%;
  height: 100%;
  border-radius: 8px;
  background: #16241a;
  border: 1px dashed #4a6b3a;
}

.build-item-name {
  font-weight: 700;
  font-size: 14px;
  color: #f3d98b;
}

.build-item-cost {
  font-size: 12px;
  color: #b7c9ab;
}
.build-item-cost .free { color: #9fd39f; }

/* Unaffordable: full art, but the cost line and border are red-tinted — a
   deliberately DIFFERENT visual treatment from coming-soon's flat grayscale
   dimming below, so "you can't afford this yet" never reads the same as
   "this doesn't exist yet." Not clickable (main.js doesn't attach a
   placement handler to this state). */
.build-item.unaffordable {
  cursor: default;
  border-color: #8a4a4a;
}
.build-item.unaffordable:hover { background: #26381f; border-color: #8a4a4a; }
.build-item.unaffordable .build-item-cost {
  color: #e08a8a;
  font-weight: 700;
}

/* Coming soon: grayed out, reduced opacity, not clickable. */
.build-item.coming-soon {
  cursor: default;
  opacity: 0.45;
  filter: grayscale(0.6);
}
.build-item.coming-soon:hover { background: #26381f; border-color: #4a6b3a; }
.build-item-soon-label {
  font-size: 11px;
  font-weight: 700;
  color: #cdd8bd;
  background: rgba(0,0,0,0.35);
  border-radius: 999px;
  padding: 2px 10px;
}

.build-menu-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 8px 14px 12px;
  flex-shrink: 0;
}
.build-menu-pagination[hidden] { display: none; }
.build-page-btn {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  background: #2c3f24;
  border: 1px solid #4a6b3a;
  color: #f3ecd8;
  font-size: 18px;
  cursor: pointer;
}
.build-page-btn:hover { background: #3d5730; border-color: #caa54d; }
.build-page-btn:disabled { opacity: 0.4; cursor: default; }
.build-page-label { font-size: 12px; color: #b7c9ab; }

/* Mobile: slide-up sheet anchored above the toolbar/safe-area, not a
   centered modal — same breakpoint convention as the rest of this file. */
@media (max-width: 640px) {
  .build-menu {
    align-items: flex-end;
  }
  .build-menu-panel {
    width: 100%;
    max-height: 70vh;
    border-radius: 16px 16px 0 0;
    /* Clears the bottom toolbar (which sits at 14px + safe-area) so the
       sheet never overlaps the move/sell/build buttons underneath it. */
    margin-bottom: calc(72px + env(safe-area-inset-bottom, 0px));
  }
  .build-item {
    min-height: 130px;
    padding: 10px 8px;
  }
  .build-item-art {
    width: 56px;
    height: 56px;
  }
  .build-item-name { font-size: 12px; }
  .build-item-cost { font-size: 11px; }
}

/* Mobile Round 3: Round 2 only shrank the outer card WIDTH (via clamp()) —
   font size, padding, and option-row spacing were still desktop values, so
   the card still read as oversized even at its smaller width. 640px matches
   the breakpoint convention already used elsewhere in this project (see
   public/index.html's `@media (max-width: 640px)` rules), not a new one.
   Positioning/clamp logic in main.js is untouched — it measures the real
   rendered box, so it adapts automatically to whatever this resolves to.

   Note on the tap-target trade-off (see Step 0 flag in the report back):
   a literal 50% cut on `.node-card button` — the tappable Coconut Oil /
   Coconuts / Coconut Frond rows — would land total
   row height around 44px, right at the accepted minimum comfortable
   tap-target size (44pt/44px is the long-standing iOS HIG figure; WCAG
   2.2's AA minimum is lower, 24px, but 44px is the safer bar for a
   thumb). That's too tight a margin to bank on across every phone's
   rendering, so those rows only shrink to ~60% rather than 50% (padding
   9px 10px vs 12px 16px, font 14px vs 24px, rate-line 11px vs 20px),
   landing around 50px tall. The decorative elements (card padding, title,
   row gap) take the full 50%+ cut instead, per the doc's explicit
   allowance to trade off that direction rather than silently shrinking
   the tappable rows to match. */
@media (max-width: 640px) {
  .info-card, .node-card {
    width: clamp(180px, 55vw, 240px);
    padding: 10px 12px;
    font-size: 12px;
  }
  .info-card .title, .node-card .title {
    font-size: 15px;
    margin-bottom: 4px;
  }
  .info-card .row, .node-card .row { gap: 10px; }
  .node-card button {
    padding: 9px 10px;
    margin-top: 7px;
    font-size: 14px;
  }
  .node-card button .rate-line {
    font-size: 11px;
    margin-top: 2px;
  }
  .node-card .close {
    font-size: 16px;
    padding: 2px 4px;
  }
  /* Item 7: a two-class selector (.node-card.structure-card) always beats
     a one-class selector (.node-card) regardless of media query order —
     without this override, the desktop-tier 460px cap above would leak
     onto mobile for structure cards specifically. Still wider than a
     plain mobile .node-card (same reason as desktop: the 6-option grid
     genuinely needs more room), just capped for a phone viewport instead
     of a desktop one. */
  .node-card.structure-card {
    width: clamp(180px, 92vw, 320px);
  }
}

/* Cleanup Round — Item 3: moved from fixed-to-viewport (a sibling of
   .gathering-page, reserving 50px of topbar padding to visually clear it —
   see prior comment history) to absolute-within-.gathering-stage, now that
   it's nested inside #overlay (gathering/index.html). safe-area-inset is
   dropped — no longer meaningful once anchored to the stage box instead of
   the viewport edge, and the stage itself already sits below the topbar/
   any notch. Top-left of the MAP now, not the page; the resource bar still
   owns the topbar's own top-right corner. No longer viewport-independent/
   copy-pasteable per Round 6's original goal — that tradeoff is the point:
   this round's brief asks for it to live IN the play field specifically. */
.player-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 40;
  font-family: 'Segoe UI', system-ui, sans-serif;
}

.player-badge-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 5px 12px 5px 8px;
  border-radius: 999px;
  background: rgba(24, 20, 12, 0.72);
  border: 1px solid #4a6b3a;
  color: #f3ecd8;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  max-width: min(70vw, 320px);
  text-align: left;
}
.player-badge-chip:hover { background: #26381f; border-color: #caa54d; }
.player-badge-chip .badge-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #2c3f24;
  flex-shrink: 0;
  font-size: 14px;
}
/* Signed-in state gets a subtle gold ring on the icon — the same "gold =
   this is the active/confirmed mode" language the toolbar's .active state
   and the build-confirm-bar already use elsewhere in this file. */
.player-badge-chip.signed-in .badge-icon {
  background: #3d5730;
  box-shadow: 0 0 0 2px #caa54d;
}
.player-badge-chip .badge-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.player-badge-chip .badge-subtext {
  display: block;
  font-size: 11px;
  font-weight: 400;
  color: #b7c9ab;
}

.player-badge-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  width: min(88vw, 280px);
  background: rgba(24, 20, 12, 0.96);
  border: 1px solid #caa54d;
  border-radius: 12px;
  padding: 16px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  box-sizing: border-box;
}
.player-badge-panel[hidden] { display: none; }

.player-badge-panel .pitch {
  font-size: 13px;
  color: #d8d0ba;
  margin-bottom: 12px;
  line-height: 1.4;
}

.player-badge-panel .google-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 44px;
  padding: 10px 16px;
  border-radius: 8px;
  background: #f3ecd8;
  border: 1px solid #caa54d;
  color: #1c1c1c;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.player-badge-panel .google-btn:hover { background: #fff; }

/* Mobile Funnel Fixes + Playtest UX Round — Item 5: email/password sign-in
   + account creation, matching public/index.html's login-modal shape
   (tab toggle, stacked inputs, error banner, submit) so it reads as the
   same auth flow, just reskinned in this panel's compact fantasy palette. */
.badge-auth-tabs {
  display: flex;
  border: 1px solid #4a6b3a;
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 10px;
}
.badge-auth-tab {
  flex: 1;
  padding: 7px 0;
  font-size: 12px;
  font-weight: 600;
  color: #caa54d;
  background: transparent;
  border: none;
  cursor: pointer;
  margin: 0;
  width: auto;
}
.badge-auth-tab:hover { background: rgba(74, 107, 58, 0.3); }
.badge-auth-tab.active { background: #caa54d; color: #1c1c1c; }

.badge-auth-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  background: #0f1612;
  border: 1px solid #4a6b3a;
  border-radius: 8px;
  color: #f3ecd8;
  font-size: 13px;
  padding: 9px 12px;
  margin-top: 8px;
}
.badge-auth-input:focus { outline: none; border-color: #caa54d; }

.badge-auth-error {
  margin-top: 8px;
  font-size: 11px;
  color: #e08a8a;
  background: rgba(138, 58, 58, 0.15);
  border: 1px solid #8a4a4a;
  border-radius: 8px;
  padding: 6px 10px;
}
.badge-auth-error[hidden] { display: none; }

.badge-auth-submit {
  display: block;
  width: 100%;
  min-height: 40px;
  margin-top: 10px;
  border-radius: 8px;
  background: #caa54d;
  border: 1px solid #f3d98b;
  color: #1c1c1c;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.badge-auth-submit:hover { background: #f3d98b; }

.badge-auth-divider {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0;
  font-size: 10px;
  color: rgba(183, 201, 171, 0.7);
  letter-spacing: 0.08em;
}
.badge-auth-divider::before, .badge-auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: rgba(74, 107, 58, 0.5);
}

/* Signed-in menu — a scaffold: each row is its own block so a future entry
   (Settings, Notifications, Account) is just another .badge-menu-row, not a
   redesign, same discipline the toolbar and build-menu tabs already follow. */
.badge-menu-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 4px;
  border-bottom: 1px solid rgba(74, 107, 58, 0.4);
}
.badge-menu-row:last-child { border-bottom: none; }
.badge-menu-row .label { font-size: 11px; color: #9fae8f; text-transform: uppercase; letter-spacing: 0.04em; }
.badge-menu-row .value { font-size: 14px; color: #f3ecd8; word-break: break-word; }
.badge-menu-row.copyable {
  cursor: pointer;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.badge-menu-row.copyable:hover { background: rgba(74, 107, 58, 0.15); border-radius: 6px; }
.badge-menu-row.copyable .copy-hint { font-size: 11px; color: #9fae8f; flex-shrink: 0; }

.badge-signout-btn {
  display: block;
  width: 100%;
  min-height: 44px;
  margin-top: 10px;
  padding: 10px 16px;
  border-radius: 8px;
  background: #5c2f2f;
  border: 1px solid #8a4a4a;
  color: #f5d8d8;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.badge-signout-btn:hover { background: #713a3a; }

.badge-toast {
  /* Cleanup Round — Item 3: absolute within .gathering-stage now, same
     reasoning as .player-badge above — top offset (badge's own 10px top +
     ~40px chip height + gap) keeps it anchored just under the badge chip. */
  position: absolute;
  top: 58px;
  left: 10px;
  background: rgba(58, 90, 138, 0.95);
  color: #eaf1ff;
  border: 1px solid #7aa8d9;
  padding: 8px 16px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  z-index: 41;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  max-width: min(80vw, 320px);
}
.badge-toast[hidden] { display: none; }

@media (max-width: 640px) {
  .player-badge-chip {
    font-size: 12px;
    padding: 5px 12px 5px 8px;
  }
  .player-badge-chip .badge-subtext { font-size: 10px; }
  .player-badge-panel { width: min(90vw, 260px); padding: 12px; }
}
