/* ============================================================
   CryptoSprouts — Cozy Garden UI
   ============================================================ */

:root {
  color-scheme: light;

  /* Surfaces */
  --cream: #fbf3e0;
  --cream-2: #fff8ea;
  --panel: #fffaf0;
  --panel-2: #fff3da;

  /* Brand */
  --green: #5ba845;
  --green-d: #3f8a32;
  --green-l: #7bc466;
  --brown: #8b5a2b;
  --brown-d: #69401e;
  --gold: #f2b544;
  --gold-d: #d9962a;
  --coral: #e8794b;
  --water: #41b0d8;
  --water-d: #2f93ba;
  --purple: #9a6dd7;

  /* Text */
  --ink: #3a4530;
  --ink-soft: #5d5a44;
  --muted: #978d72;

  /* Lines & depth */
  --line: rgba(110, 84, 46, 0.16);
  --line-2: rgba(110, 84, 46, 0.28);
  --shadow-sm: 0 2px 6px rgba(96, 70, 38, 0.12);
  --shadow: 0 8px 22px rgba(96, 70, 38, 0.16);
  --shadow-lg: 0 16px 40px rgba(96, 70, 38, 0.22);

  --radius: 18px;
  --radius-sm: 13px;
  --radius-xs: 9px;

  --font-ui: "Nunito", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: "Fredoka", var(--font-ui);

  --hud-h: 58px;
  /* Live height of the v2 floating HUD, measured by updateHudMetrics() in JS
     (includes the safe-area inset). The fixed stack below the HUD — buff band,
     farm title, farm column — anchors to this so nothing is covered when the
     HUD wraps to more rows or the medallion size changes. Fallback ≈ a 2-row
     HUD with the 65px medallion, used only for the first paint before JS runs. */
  --hud-bottom: calc(115px + env(safe-area-inset-top));
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-ui);
  font-weight: 600;
  -webkit-font-smoothing: antialiased;
  background:
    radial-gradient(1200px 480px at 50% -120px, #cdeeff 0%, rgba(205, 238, 255, 0) 70%),
    linear-gradient(180deg, #dff3c6 0%, #f4ecd6 220px, #f4ecd6 100%);
  background-attachment: fixed;
}

body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -1;
  background-image: radial-gradient(rgba(120, 95, 55, 0.05) 1.5px, transparent 1.5px);
  background-size: 22px 22px;
}

h1, h2, h3, p { margin: 0; }

.muted { color: var(--muted); font-weight: 700; font-size: 12.5px; }

/* Pixel-art inline icons */
.ico-img {
  width: 1.25em; height: 1.25em;
  display: inline-block;
  vertical-align: -0.28em;
  background: center / contain no-repeat;
  image-rendering: pixelated;
}
.ico-sprout { background-image: url("assets/token-sprout.png?v=3"); }
.ico-coin { background-image: url("assets/coin.png?v=3"); }
/* Painted fertilizer sack (not pixel art) — smooth scaling, no pixelation. */
.ico-fert { background-image: url("assets/fertilizer.png?v=3"); image-rendering: auto; }
.ico-water { background-image: url("assets/watering-can.png?v=2"); }
/* Painted (not pixel-art) booster medallion — smooth scaling, no pixelation. */
.ico-booster-breeding {
  background-image: url("assets/booster-breeding.png?v=2");
  image-rendering: auto;
}
.ico-flower {
  background-image: url("assets/flower-scent.png?v=2");
  image-rendering: auto;
}
.ico-scarecrow { background-image: url("assets/scarecrow.png?v=4"); }

#app {
  width: min(1160px, 100%);
  margin: 0 auto;
  padding: 0 16px calc(96px + env(safe-area-inset-bottom)) ;
}

/* ---------------- HUD ---------------- */
.hud {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 12px;
  height: var(--hud-h);
  margin: 0 -16px 0;
  padding: 0 16px;
  background: rgba(255, 250, 240, 0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}

.brand { display: flex; align-items: center; gap: 8px; }
.brand-logo {
  height: 42px;
  width: auto;
  display: block;
  filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.18));
}

.hud-actions { display: flex; align-items: center; gap: 8px; }

.resources {
  display: flex;
  gap: 8px;
  margin-left: auto;
  overflow-x: auto;
  scrollbar-width: none;
}
.resources::-webkit-scrollbar { display: none; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px 6px 9px;
  background: linear-gradient(180deg, var(--cream-2), #ffeec8);
  border: 1px solid var(--line-2);
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
  white-space: nowrap;
}
.chip-ico { font-size: 15px; }
.chip .ico-img.chip-ico { width: 18px; height: 18px; vertical-align: -4px; }
.chip strong { font-family: var(--font-display); font-weight: 600; font-size: 15px; color: var(--ink); }
.chip-tag { font-size: 10px; font-weight: 800; color: var(--muted); letter-spacing: 0.5px; }
.chip-muted { background: linear-gradient(180deg, #fdeede, #f8dcc4); }

/* ---------------- Buttons ---------------- */
.btn {
  appearance: none;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 13.5px;
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: 9px 16px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  line-height: 1;
  transition: transform 0.08s ease, box-shadow 0.15s ease, filter 0.15s ease;
  box-shadow: 0 3px 0 var(--btn-shade, rgba(0,0,0,0.18)), 0 6px 14px rgba(96,70,38,0.18);
}
.btn:hover { transform: translateY(-1px); filter: brightness(1.04); }
.btn:active { transform: translateY(3px); box-shadow: 0 0 0 var(--btn-shade, rgba(0,0,0,0.18)), 0 3px 8px rgba(96,70,38,0.18); }
.btn:disabled { cursor: not-allowed; filter: grayscale(0.5) brightness(0.98); opacity: 0.55; transform: none; box-shadow: var(--shadow-sm); }

.btn-primary { background: linear-gradient(180deg, var(--green-l), var(--green-d)); --btn-shade: #2f6e26; }
.btn-gold { background: linear-gradient(180deg, #ffce63, var(--gold-d)); color: #5a3d0a; --btn-shade: #b67c1f; }
.btn-water { background: linear-gradient(180deg, #62c7e6, var(--water-d)); --btn-shade: #237a9d; }
.btn-coral { background: linear-gradient(180deg, #f59169, #d4612f); --btn-shade: #ad4d24; }
.btn-warn { background: linear-gradient(180deg, #f5a34a, #d97d1c); color: #fff; --btn-shade: #a85e0f; }
.btn-danger { background: linear-gradient(180deg, #ef5a5a, #c62f2f); color: #fff; --btn-shade: #8f1f1f; }
.btn-ghost {
  background: var(--cream-2);
  color: var(--ink);
  --btn-shade: rgba(110,84,46,0.22);
  box-shadow: 0 2px 0 var(--btn-shade), 0 4px 10px rgba(96,70,38,0.12);
}
.btn-sm { padding: 7px 12px; font-size: 12px; }
.btn-block { width: 100%; margin-top: 10px; }

/* ---------------- Hero ---------------- */
.hero {
  position: relative;
  margin: 10px 0;
  height: 115px;
  border-radius: var(--radius);
  overflow: hidden;
  background: url("assets/scene.png?v=4") center 38% / cover no-repeat;
  box-shadow: var(--shadow), inset 0 -30px 40px -20px rgba(20,40,15,0.55);
  border: 3px solid #fff;
  outline: 1px solid var(--line-2);
  display: grid;
  place-items: center;
}
.hero-logo {
  position: relative;
  z-index: 2;
  height: 84px;
  width: auto;
  max-width: 88%;
  object-fit: contain;
  margin-top: -4px;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.4));
  animation: pop-in 0.45s ease both;
}
.hero-cap {
  position: absolute;
  left: 20px;
  bottom: 12px;
  right: 20px;
  text-align: center;
  color: #fff;
  text-shadow: 0 2px 8px rgba(0,0,0,0.65);
}
/* The half-height hero has no room for the caption without crowding the logo. */
.hero-cap p { display: none; }

.hero-bugs { position: absolute; inset: 0; pointer-events: none; }
.bug {
  position: absolute;
  background-repeat: no-repeat;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,0.3));
}
/* Animated insects. Each background is a horizontal sprite strip; background-size
   is N×(element width) so stepping background-position-x by one element-width
   advances exactly one frame. Two animations run together: the *-flap one cycles
   the wing frames (steps), and flit-* drifts the insect across the hero. */
.bug.bee      { width: 40px; height: 40px; background-image: url("assets/bee-fly.png?v=2");              background-size: 160px 128px; background-position-y: center; }
.bug.bfly-mon { width: 32px; height: 28px; background-image: url("assets/butterfly-monarch.png?v=4"); background-size: 352px 28px; }
@keyframes bee-flap      { from { background-position-x: 0; } to { background-position-x: -160px; } }
@keyframes bfly-mon-flap { from { background-position-x: 0; } to { background-position-x: -352px; } }
.bug.b1  { top: 20px; left: 7%;  animation: bee-flap      0.32s steps(4)  infinite, flit-a 7s ease-in-out infinite; }
.bug.bm1 { top: 28px; left: 83%; animation: bfly-mon-flap 0.85s steps(11) infinite, flit-c 6s ease-in-out infinite 1s; }

/* ---------------- Cards & layout ---------------- */
.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.layout {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(330px, 0.82fr);
  gap: 16px;
  align-items: start;
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 4px 2px 12px;
}
.section-head.sm { margin: 16px 2px 10px; }
.section-head h2 { font-family: var(--font-display); font-weight: 700; font-size: 20px; color: var(--ink); }
.section-head h3 { font-family: var(--font-display); font-weight: 600; font-size: 16px; color: var(--ink); }

.pill {
  font-size: 11px; font-weight: 800; padding: 4px 10px; border-radius: 999px;
  letter-spacing: 0.3px;
}
.pill-soft { background: #eef6e2; color: var(--green-d); }
.pill-warn { background: #fef3e2; color: #a85e0f; }
.pill-legacy { background: #edeae2; color: var(--muted); }

/* ---------------- Daily banner ---------------- */
.daily {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 14px 16px;
  margin-bottom: 16px;
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
}

/* ---------------- Live event banner ---------------- */
.event-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  margin-bottom: 16px;
  background: linear-gradient(110deg, #6d3fb0, #b0427a, #e08a3d);
  color: #fff;
  border: none;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15);
}
/* display:flex above would defeat the hidden attribute: with no live event the
   empty banner painted as a phantom bar over the farm title (and swallowed the
   taps meant for the ‹ › farm buttons). */
.event-banner[hidden] { display: none; }
.event-banner .event-emoji { font-size: 1.6rem; line-height: 1; }
.event-banner .event-body { flex: 1; display: flex; flex-direction: column; line-height: 1.25; }
.event-banner .event-body strong { font-size: 0.98rem; }
.event-banner .event-body span { font-size: 0.8rem; opacity: 0.9; }
.event-banner .event-timer {
  font-weight: 800; font-size: 0.85rem; white-space: nowrap;
  background: rgba(0, 0, 0, 0.25); padding: 4px 10px; border-radius: 999px;
}

/* ---------------- Tip of the Day ---------------- */
.tip {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 12px 14px;
  margin-bottom: 16px;
  background: linear-gradient(180deg, #fffdf4, #fff6da);
  border-color: var(--line-2);
}
.tip[hidden] { display: none; }  /* display:grid would defeat the hidden attribute */
.tip-icon {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: 12px;
  font-size: 18px;
  background: linear-gradient(180deg, #fff0cf, #ffd98f);
  border: 1px solid var(--line-2);
  box-shadow: var(--shadow-sm);
}
.tip-body { min-width: 0; }
.tip-head { font-size: 9px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--gold-d); }
.tip-text { margin: 2px 0 0; font-size: 12.5px; font-weight: 600; line-height: 1.4; color: var(--ink); }
.tip-next {
  flex-shrink: 0;
  width: 30px; height: 30px;
  border-radius: 10px;
  border: 1px solid var(--line-2);
  background: var(--panel);
  color: var(--muted);
  font-size: 15px;
  cursor: pointer;
  transition: transform 0.2s ease, color 0.2s ease;
}
.tip-next:hover { color: var(--green-d); }
.tip-next:active { transform: rotate(180deg); }

/* Lunar Vault transparency banner (NFTs tab). */
.vault-banner {
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 14px;
  background: linear-gradient(180deg, #2a2350, #1c1838);
  border: 1px solid #4b3f87;
  color: #efeaff;
}
.vault-head { font-weight: 700; display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.vault-reset { margin-left: auto; font-size: 10px; font-weight: 600; opacity: 0.6; }
.vault-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(72px, 1fr)); gap: 8px; text-align: center; }
.vault-grid div { background: rgba(255, 255, 255, 0.06); border-radius: 10px; padding: 8px 4px; }
.vault-grid strong { display: block; font-size: 15px; }
.vault-grid span { font-size: 11px; opacity: 0.7; }
.vault-unit { font-size: 9px; font-weight: 600; opacity: 0.6; letter-spacing: 0.02em; }
.vault-total { margin-top: 8px; font-size: 12px; opacity: 0.8; text-align: center; }
.vault-total strong { font-weight: 700; }
.vault-note { margin-top: 10px; font-size: 11px; opacity: 0.65; line-height: 1.35; }
.vault-perks { margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255, 255, 255, 0.12); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.vault-perks strong { font-size: 12px; color: #ffd86b; width: 100%; }
.perk-chip { font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 999px; background: rgba(255, 216, 107, 0.16); color: #ffe9a8; }
.vault-supply { margin-top: 10px; }
.vault-supply-track { height: 6px; border-radius: 999px; background: rgba(255, 255, 255, 0.12); overflow: hidden; margin-bottom: 5px; }
.vault-supply-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, #c49fff, #e8b8ff); transition: width 0.4s; }
/* Farmer Mastery sheet: gold XP fill on the shared supply-bar track, and the
   not-yet-earned titles in the ladder sit dimmed until their level is hit. */
.vault-supply-fill.mastery-fill { background: linear-gradient(90deg, #ffe19a, var(--gold)); }
.mastery-locked { opacity: 0.45; }
/* Badge rank art (assets/badges/): inline chip size in list rows / next-badge
   note, hero size in the Mastery sheet header. Vertical-align keeps the chip
   sitting on the text baseline next to names and pills. */
.mastery-badge-sm { width: auto; height: 20px; vertical-align: -4px; }
.mastery-badge-lg { width: auto; height: 64px; flex: 0 0 auto; filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.35)); }
.mastery-head { display: flex; align-items: center; gap: 12px; }
/* LV 100 prestige (goldenFrame perk): the medallion ring glows gold and the
   player's name renders in gold on the leaderboard and clan roster. */
body.v2 .lvl-medal.mastery-gold {
  background: conic-gradient(#ffe9b0 calc(var(--xp, 0) * 1%), rgba(255, 214, 120, 0.45) 0);
  box-shadow: 0 0 12px rgba(255, 209, 102, 0.75);
}
body.v2 .lvl-medal.mastery-gold .core { border-color: var(--gold); }
.mastery-gold-name {
  background: linear-gradient(180deg, #fff3c4, var(--gold));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 4px rgba(255, 209, 102, 0.35));
}
/* Frosted-glass Mastery board: translucent so the farm shows through, but a
   high-opacity cream layer + heavy blur keeps the dark ink text crisp (the
   whole point — see-through, never washed out). Scoped to the mastery sheet so
   other sheets keep their solid panel. */
.modal.sheet.mastery-sheet {
  background: rgba(255, 250, 240, 0.72);
  backdrop-filter: blur(22px) saturate(1.25);
  -webkit-backdrop-filter: blur(22px) saturate(1.25);
  border: 1px solid rgba(255, 255, 255, 0.55);
  box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255, 255, 255, 0.55);
}
/* Ladder rows sit on the glass as lightly-tinted panes rather than solid cards,
   so the transparency reads through the list too — still dark text on a light
   pane, so every row stays readable. */
.mastery-sheet .list .row {
  background: rgba(255, 255, 255, 0.42);
  border-color: rgba(110, 84, 46, 0.22);
}
.mastery-sheet .list .row.mastery-locked { background: rgba(255, 255, 255, 0.24); }
/* The header stat tiles and XP track are dark-on-light chips on the glass;
   nudge their fills up in opacity so the numbers keep contrast. */
.mastery-sheet .vault-grid div { background: rgba(255, 255, 255, 0.5); }
.mastery-sheet .vault-supply-track { background: rgba(58, 69, 48, 0.16); }
/* The "Paragon N" sub-label on the light glass tile — keep it readable, not
   washed out. */
.mastery-sheet .vault-grid span { opacity: 0.9; color: var(--ink); }
/* Paragon ★ + number: a deep, saturated blue so it stays legible on the light
   frosted tile (the old pale-blue gradient washed out against the cream). */
.mastery-paragon {
  background: linear-gradient(180deg, #2b7de0, #0e46a6);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 1px 1px rgba(10, 38, 96, 0.4));
  font-weight: 800;
}
.vault-supply-label { font-size: 11px; opacity: 0.75; text-align: center; }
.vault-supply-label strong { color: #e8b8ff; }
.vault-pace { margin-top: 8px; font-size: 11px; opacity: 0.75; text-align: center; }
.vault-pace strong { color: #ffd86b; }
.vault-feed { margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255, 255, 255, 0.12); }
.vault-feed-head { font-size: 11px; font-weight: 700; opacity: 0.55; letter-spacing: 0.5px; text-transform: uppercase; margin-bottom: 6px; }
.vault-feed-item { display: flex; align-items: baseline; gap: 6px; font-size: 11px; padding: 3px 0; opacity: 0.85; }
.vault-feed-item:not(:last-child) { border-bottom: 1px solid rgba(255, 255, 255, 0.06); }
.vault-feed-name { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vault-feed-slice { font-weight: 700; color: #c9f0a8; white-space: nowrap; }
.vault-feed-time { font-size: 10px; opacity: 0.5; white-space: nowrap; }

/* In-game Growth Stake / Greenhouse panel. The hero art already carries the
   "GREENHOUSE" sign + tagline, so no HTML title overlay is drawn on it. */
/* Dark-green backdrop for the whole Greenhouse tab, tying it to the art. */
#tab-stake { background: linear-gradient(180deg, #133021 0%, #0c1d13 55%, #09150d 100%); }
.greenhouse-hero { border-radius: 14px; overflow: hidden; margin-bottom: 10px; line-height: 0; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35); }
.greenhouse-hero img { width: 100%; height: auto; display: block; }
.stake-agg { background: linear-gradient(180deg, rgba(120, 200, 120, 0.16), rgba(120, 200, 120, 0.06)); border: 1px solid rgba(140, 220, 140, 0.3); border-radius: 10px; padding: 8px 10px; margin-bottom: 8px; font-size: 12px; font-weight: 600; color: #d3f0c9; }
.stake-note { padding: 10px 12px; font-size: 12px; background: rgba(255, 255, 255, 0.05); border-radius: 10px; }
.stake-durs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-bottom: 8px; }
.stake-dur { appearance: none; cursor: pointer; border: 1px solid rgba(140, 220, 140, 0.28); background: rgba(120, 200, 120, 0.06); border-radius: 10px; padding: 8px 4px; display: grid; gap: 2px; justify-items: center; color: var(--ink-soft); font-family: var(--font-ui); transition: background 0.15s, border-color 0.15s; }
.stake-dur.sel { background: rgba(64, 132, 58, 0.85); border-color: rgba(150, 230, 150, 0.9); box-shadow: 0 0 0 1px rgba(150, 230, 150, 0.5) inset; }
.stake-dur-days { font-weight: 800; font-size: 13px; }
.stake-dur-sub { font-size: 10px; opacity: 0.75; }
.stake-dur.sel .stake-dur-days { color: #fff; }
.stake-dur.sel .stake-dur-sub { color: #eafbe6; opacity: 0.95; }
.stake-amount-row { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.stake-amount-row input { flex: 1; }
.stake-preview { font-size: 12px; line-height: 1.45; margin: 0 0 8px; min-height: 1em; }
.stake-preview b { color: #c9f0a8; }

/* Rows inside the dark clan/referral banner keep their cream background, so
   their text must stay dark — otherwise names inherit the banner's light
   lavender (#efeaff) and become unreadable on cream (clan members, board). */
.vault-banner .row { color: var(--ink); }
.vault-banner .row-title span.name { color: var(--ink); }
/* Section headings sit directly on the dark banner, so flip them to light. */
.vault-banner .section-head h3 { color: #efeaff; }
.vault-banner .section-head .muted { color: #c9c2e6; }

/* Clan Wars champion prize (Rank tab, inside the clan card). A warm gold banner
   so an active winning-clan boost reads as a reward against the purple shell. */
.clan-war-prize {
  border-radius: 12px;
  padding: 10px 12px;
  margin: 12px 0;
  background: linear-gradient(180deg, #4a3410, #2e2208);
  border: 1px solid #b8862b;
  color: #ffe9a8;
}
.clan-war-prize .vault-head { color: #ffd86b; margin-bottom: 6px; }
.clan-war-prize .vault-note { color: #f2dca0; opacity: 0.85; margin-top: 0; }
/* Clan Wars loyalty pot: a lighter gold chip (it's an accruing pot, not a claimed
   reward), sitting between the intro and the league boards. */
.clan-pot-note {
  margin: 10px 0;
  padding: 9px 12px;
  border-radius: 10px;
  background: rgba(255, 216, 107, 0.12);
  border: 1px solid rgba(216, 169, 58, 0.5);
  color: #ffe9a8;
  font-size: 12.5px;
  line-height: 1.4;
}
.clan-pot-note strong { font-size: 14px; color: #ffd86b; }
.clan-pot-note span { opacity: 0.8; font-size: 11.5px; }

/* Clan Wars weekly missions: a stack of goal cards, each with a progress bar. */
.clan-missions { display: flex; flex-direction: column; gap: 8px; margin: 8px 0 4px; }
.mission {
  padding: 9px 11px;
  border-radius: 10px;
  background: rgba(20, 30, 46, 0.55);
  border: 1px solid rgba(150, 190, 255, 0.22);
}
.mission-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.mission-label { font-weight: 700; font-size: 12.5px; color: #eaf1ff; }
.mission-count { font-weight: 800; font-size: 11.5px; color: #c3d3e6; white-space: nowrap; }
.mission-bar { height: 7px; border-radius: 999px; background: rgba(255, 255, 255, 0.12); overflow: hidden; }
.mission-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, #5ba845, #8bd15a); transition: width 0.4s; }
.mission-reward { margin-top: 5px; font-size: 10.5px; font-weight: 800; color: #ffd86b; letter-spacing: 0.02em; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.mission-mvp { color: #b7e6a0; font-weight: 800; white-space: nowrap; }
.mission.done { border-color: #8bd15a; background: rgba(58, 88, 40, 0.5); }
.mission.done .mission-count { color: #b7e6a0; }
.mission.done .mission-fill { background: linear-gradient(90deg, #8bd15a, #b7e6a0); }

/* Clan Wars "what you're playing for" panel: always-visible rewards explainer so
   players see the prize before they've won anything. */
.clan-rewards {
  margin: 8px 0;
  padding: 11px 13px;
  border-radius: 12px;
  background: rgba(20, 30, 46, 0.55);
  border: 1px solid rgba(150, 190, 255, 0.28);
}
.reward-head { font-weight: 800; font-size: 13.5px; color: #ffd86b; margin-bottom: 4px; }
.reward-sub { font-size: 11.5px; color: #c3d3e6; line-height: 1.4; margin-bottom: 8px; }
.reward-sub b { color: #eaf1ff; }
.reward-tier { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 0; border-top: 1px solid rgba(255, 255, 255, 0.08); }
.reward-rank { font-weight: 800; font-size: 12.5px; color: #eaf1ff; white-space: nowrap; }
.reward-val { font-weight: 700; font-size: 11.5px; color: #b7e6a0; text-align: right; }
.reward-extra { margin-top: 8px; font-size: 11.5px; color: #cdd8ea; line-height: 1.4; }
.reward-extra b { color: #ffe9a8; }
/* The viewer's own clan, highlighted in either league board. Mirrors .row.selected:
   a light gold wash (keeps the dark row text readable) plus a gold ring. */
.vault-banner .row.clan-war-mine {
  background: #fdf3d6;
  border-color: #d8a93a;
  box-shadow: 0 0 0 2px rgba(216, 169, 58, 0.3);
}

/* Referral invite card (Rank tab). Reuses the vault-banner shell. */
.referral-banner { background: linear-gradient(180deg, #2a3d2a, #1c2e1c); border-color: #4b8a4f; }
.referral-link-row { display: flex; gap: 8px; margin-top: 10px; }
.referral-link-row input {
  flex: 1; min-width: 0; padding: 9px 10px; font-size: 12px; font-weight: 700;
  border: 1px solid rgba(255, 255, 255, 0.25); border-radius: 10px;
  background: rgba(255, 255, 255, 0.08); color: #efeaff;
}
.referral-link-row .btn { flex: none; }
/* Referral ladder: escalating invite bonuses, one row per rung. Reached rungs
   dim + strike-through-ish (ticked ✅); the next target stays bright. */
.referral-ladder { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 5px; }
.referral-ladder li {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 6px 10px; font-size: 12px; border-radius: 9px;
  background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.12);
}
.referral-ladder li strong { color: #b7f7c2; white-space: nowrap; }
.referral-ladder li.referral-rung-done { opacity: 0.55; }
.referral-ladder li.referral-rung-done strong { color: #8fd39c; }
/* Crown reward: the unique, permanent Red Panda Farmer — the headline prize of
   the invite panel. Gold-bordered so it reads apart from the SPROUT rungs. */
.referral-crown {
  display: flex; gap: 12px; align-items: center;
  margin: 10px 0 2px; padding: 11px 12px; border-radius: 12px;
  background: linear-gradient(135deg, rgba(255,196,84,0.16), rgba(255,140,60,0.10));
  border: 1px solid rgba(255,196,84,0.55);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.04);
}
.referral-crown.won { border-color: rgba(120,231,150,0.7); background: linear-gradient(135deg, rgba(120,231,150,0.16), rgba(60,160,90,0.10)); }
.referral-crown-badge { flex: none; line-height: 0; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.35)); }
/* .farmer-ico uses percentage background-size, so a larger box shows the same
   front-pose frame bigger — the real Red Panda sprite instead of an emoji. */
.referral-crown-badge .redpanda-ico { width: 50px; height: 54px; }
/* Small inline sprite marking the Red Panda rung in the SPROUT ladder. */
.referral-ladder .rung-ico { display: inline-block; width: 19px; height: 21px; vertical-align: -6px; margin-left: 3px; }
/* A rung that ALSO grants a Red Panda: gold-tinted, with a clear "+ Red Panda"
   badge so the crown reward is signalled right on its target. */
.referral-ladder li.referral-rung-crown {
  background: linear-gradient(135deg, rgba(255,196,84,0.16), rgba(255,140,60,0.09));
  border-color: rgba(255,196,84,0.55);
}
.referral-ladder li.referral-rung-crown strong {
  display: inline-flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 6px; white-space: normal;
}
.rung-crown-badge {
  display: inline-flex; align-items: center; gap: 2px;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.2px; color: #2a1c07;
  background: linear-gradient(180deg, #ffd477, #ffb43c);
  padding: 1px 8px 1px 3px; border-radius: 999px; white-space: nowrap;
}
.rung-crown-badge .rung-ico { width: 18px; height: 20px; vertical-align: middle; margin-left: 0; }
.referral-crown-body { min-width: 0; }
.referral-crown-title { font-weight: 800; font-size: 14px; color: #ffe9c2; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.referral-crown-tag {
  font-size: 9.5px; font-weight: 800; letter-spacing: 0.5px; color: #2a1c07;
  background: linear-gradient(180deg, #ffd477, #ffb43c); padding: 2px 6px; border-radius: 999px;
}
.referral-crown-sub { font-size: 12px; color: #f2e6cf; margin-top: 3px; line-height: 1.35; }
.referral-crown-note { font-size: 11px; color: #ffd9a0; margin-top: 5px; line-height: 1.35; font-weight: 600; }
/* Community missions card (Rank tab): a warm-green banner (community/growth),
   one row per social task with an emoji, its label + reward, and a CTA/claim. */
.missions-card { background: linear-gradient(180deg, #263a2b, #1a2c20); border-color: #4f8a63; }
.mission-list { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
/* Collapsed "Completed" missions: keep the panel compact but reachable. */
.missions-done { margin-top: 10px; border-top: 1px solid rgba(255, 255, 255, 0.12); padding-top: 4px; }
.missions-done > summary {
  cursor: pointer; list-style: none; user-select: none; -webkit-user-select: none;
  font-size: 12px; color: #cfe6d5; padding: 6px 2px;
}
.missions-done > summary::-webkit-details-marker { display: none; }
.missions-done > summary::before {
  content: '▸'; display: inline-block; margin-right: 6px; transition: transform 0.15s ease;
}
.missions-done[open] > summary::before { transform: rotate(90deg); }
.missions-done .mission-list { margin-top: 4px; opacity: 0.9; }
/* Leaderboard search box (light rank tab). */
.rank-search {
  width: 100%; box-sizing: border-box; margin: 8px 0; padding: 10px 12px;
  border-radius: 10px; border: 1px solid var(--line-2); background: #fff;
  color: var(--ink); font-size: 14px; -webkit-appearance: none;
}
.rank-search:focus { outline: none; border-color: var(--green); }
#rank-more-btn { margin-top: 8px; }
.mission-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.mission-row.done { opacity: 0.62; }
.mission-emoji { font-size: 20px; line-height: 1; width: 24px; text-align: center; flex: none; }
.mission-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mission-body strong { font-size: 12.5px; font-weight: 700; color: #eef7ee; line-height: 1.25; }
.mission-reward { font-size: 11px; font-weight: 700; color: #ffe08a; }
.mission-btn { flex: none; white-space: nowrap; }
.mission-btn.mission-done { background: rgba(255, 255, 255, 0.12); color: #cfe6d3; }
/* Social tab: official channels & socials — one tappable row per link, same
   visual language as the mission rows but the whole row is the button. */
.social-card { background: linear-gradient(180deg, #263a2b, #1a2c20); border-color: #4f8a63; }
.social-list { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.social-link {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 11px 12px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.social-link:active { transform: scale(0.985); background: rgba(255, 255, 255, 0.1); }
.social-emoji { font-size: 20px; line-height: 1; width: 24px; text-align: center; flex: none; }
.social-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.social-body strong { font-size: 12.5px; font-weight: 700; color: #eef7ee; line-height: 1.25; }
.social-body span { font-size: 11px; color: #cfe6d3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.social-go { flex: none; font-size: 14px; font-weight: 800; color: #ffe08a; }
/* Login "grow the community" popup: same dark-green branding as the Rank card so
   the shared mission rows (light text) render correctly, with a discreet skip.
   Uses .modal.mission-popup so it beats the base .modal (light) panel, which is
   defined later in this file with equal single-class specificity. */
.modal.mission-popup {
  background: linear-gradient(180deg, #263a2b, #1a2c20);
  border: 1px solid #4f8a63;
  color: #eef7ee;
}
.modal.mission-popup h3 { color: #eef7ee; }
.mission-popup-sub { font-size: 12.5px; line-height: 1.4; color: #cfe6d3; margin-bottom: 12px; }
.mission-popup-sub b { color: #ffe08a; }
.mission-popup .mission-list { max-height: 52vh; overflow-y: auto; }
.mission-popup-done { text-align: center; padding: 18px 8px; font-size: 14px; color: #cfe6d3; }
.mission-skip {
  display: block; margin: 14px auto 0; padding: 6px 10px;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 600;
  color: rgba(238, 247, 238, 0.5);
  text-decoration: underline; text-underline-offset: 2px;
}
.mission-skip:hover { color: rgba(238, 247, 238, 0.85); }
/* Invite Festival start-screen popup: image-led splash for the invite campaign,
   dark-green branding like the missions popup so the skip/subtext read right. */
.modal.invite-popup {
  background: linear-gradient(180deg, #263a2b, #1a2c20);
  border: 1px solid #4f8a63; color: #eef7ee;
  text-align: center; padding: 0 16px 16px;
}
.invite-popup-art {
  display: block; width: calc(100% + 32px); margin: 0 -16px 12px;
  border-radius: 14px 14px 0 0; aspect-ratio: 1 / 1; object-fit: cover;
}
.modal.invite-popup h3 { color: #eef7ee; margin-top: 2px; }
.invite-popup-sub { font-size: 13px; line-height: 1.45; color: #cfe6d3; margin: 6px 4px 14px; }
.invite-popup-sub b { color: #ffe08a; }
/* Missions campaign riding below the invite section in the same login popup. */
.invite-missions { text-align: left; margin-top: 14px; padding-top: 12px; border-top: 1px solid rgba(255, 255, 255, 0.14); }
.invite-missions-head { font-size: 12.5px; font-weight: 800; color: #eef7ee; margin: 0 2px 8px; line-height: 1.35; }
.invite-missions-head .muted { font-weight: 600; color: #cfe6d3; }
.invite-missions-head b { color: #ffe08a; }
.invite-missions .mission-list { max-height: 34vh; overflow-y: auto; }
/* Android internal-test join popup: same dark-green branding as the invite
   splash, with a Play Store link, an email field and the pay CTA. */
.modal.android-test-popup {
  background: linear-gradient(180deg, #263a2b, #1a2c20);
  border: 1px solid #4f8a63; color: #eef7ee;
  text-align: center; padding: 20px 16px 16px;
}
.modal.android-test-popup h3 { color: #eef7ee; margin-top: 2px; }
.android-test-sub { font-size: 13px; line-height: 1.45; color: #cfe6d3; margin: 6px 4px 14px; }
.android-test-sub b { color: #ffe08a; }
.android-test-link {
  display: block; margin: 0 0 14px; padding: 10px 12px;
  background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 10px; color: #bfe3c9; font-size: 12.5px; font-weight: 700;
  text-decoration: none; word-break: break-word;
}
.android-test-link:hover { background: rgba(255, 255, 255, 0.14); color: #eef7ee; }
.android-test-note {
  font-size: 12px; line-height: 1.4; color: #ffe08a;
  text-align: center; margin: 0 4px 14px;
}
.android-test-slots {
  font-size: 12px; line-height: 1.4; color: #cfe6d3;
  text-align: center; margin: -6px 4px 12px;
}
.android-test-slots b { color: #eef7ee; }
.android-test-already { color: #9fc7ab; font-size: 11.5px; }
.android-test-label {
  display: block; text-align: left; font-size: 12px; font-weight: 800;
  color: #cfe6d3; margin: 0 2px 6px;
}
.modal.android-test-popup input {
  margin-bottom: 14px; background: rgba(255, 255, 255, 0.96); color: #14251a;
}
.streak-badge {
  display: grid;
  place-items: center;
  width: 58px; height: 58px;
  border-radius: 16px;
  background: linear-gradient(180deg, #fff0cf, #ffd98f);
  border: 1px solid var(--line-2);
  box-shadow: var(--shadow-sm);
  text-align: center;
  line-height: 1;
}
.streak-badge .flame { font-size: 18px; }
.streak-badge b { font-family: var(--font-display); font-weight: 700; font-size: 20px; color: var(--gold-d); }
.streak-badge small { font-size: 9px; font-weight: 800; color: var(--muted); text-transform: uppercase; }

.quests { display: grid; gap: 8px; }
.quest { display: grid; gap: 4px; }
.quest .q-top { display: flex; justify-content: space-between; font-size: 12px; font-weight: 800; }
.quest.done .q-top { color: var(--green-d); }
.q-bar { height: 9px; border-radius: 999px; background: #ece1c4; overflow: hidden; }
.q-bar i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--green-l), var(--green)); transition: width 0.4s ease; }

/* ---------------- Plots ---------------- */
.plots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
  gap: 14px;
}

.plot {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: linear-gradient(180deg, #bfe6ff 0%, #d8f0ff 44%, #cdeebf 44%, #cdeebf 100%);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  animation: pop-in 0.35s ease both;
}
.plot:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.plot.ready { box-shadow: var(--shadow-lg), 0 0 0 3px rgba(242,181,68,0.55); }

.plot-body {
  position: relative;
  display: grid;
  place-items: end center;
  min-height: 186px;
  padding-bottom: 4px;
  /* The crop sprites carry their own soil mound, so the plot just provides a
     soft grassy bed for them to sit on — no second, clashing soil texture. */
  background: radial-gradient(125% 58% at 50% 100%,
    #a7d56b 0%, #a7d56b 40%, rgba(167, 213, 107, 0) 72%) bottom / 100% 64px no-repeat;
}

.farm-actions { display: flex; gap: 8px; margin-bottom: 10px; }
.farm-actions .btn { flex: 1; }

/* Buy-farm bar (Phase 2). The ‹ Farm X/N › nav moved to the farm-title strip
   at the top; this row only ever holds the Buy-farm button now, centered. */
.farm-switcher { margin-bottom: 10px; }
.farm-switcher[hidden] { display: none; }
.farm-switch-row {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 6px 10px; border-radius: var(--radius-sm);
  background: var(--panel-2, rgba(255, 255, 255, 0.5)); border: 1px solid var(--line-2);
}
.farm-switch-row .farm-buy { white-space: nowrap; }

/* ---------------- Farm scene (single illustrated field, 4x3 plot grid) ---- */
.farm-scene {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  /* Field-green fallback shown only if a scene layer is ever missing; in normal
     use the .farm-layer card(s) cover the whole square so this never shows. */
  background: #8fc96b;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  border: 3px solid #fff;
  outline: 1px solid var(--line-2);
  container-type: inline-size;
  animation: pop-in 0.35s ease both;
  /* Let the page scroll vertically, but reserve horizontal drags for the
     farm-switch swipe gesture (see initFarmSwipe) so the webview doesn't
     hijack them as navigation. */
  touch-action: pan-y;
}

/* "How to play" button — a HUD action button (.btn-info sizing) that opens the
   getting-started guide. While unseen it pulses a soft gold ring to draw a new
   player's eye; the ring is a box-shadow (no transform/size change) so it never
   nudges the header layout. Rendered above its neighbours so the glow shows. */
.help-btn { position: relative; z-index: 1; }
.help-btn.blink { animation: help-glow 1.2s ease-in-out infinite; }
@keyframes help-glow {
  0%, 100% { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 0 0 0 rgba(245, 197, 66, 0.75); }
  50%      { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 0 0 6px rgba(245, 197, 66, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .help-btn.blink { animation: none; }
}

/* The full farm "card": background + plots + every sprite in one absolutely
   positioned layer that slides on a farm switch. Two exist briefly during a
   slide — the outgoing snapshot (a clone) and the incoming live layer — so the
   whole square (background included) leaves one edge as the next enters the
   other. Per-farm scenery can later be driven by adding a scene class here. */
.farm-layer {
  position: absolute; inset: 0;
  background: url("assets/farm-scene.png?v=9") center / cover no-repeat;
  will-change: transform;
}
/* Time-of-day + weather skins. JS (applyFarmAmbience) toggles these classes on
   #plots by the clock; the background lives on the layer(s) inside, so the live
   layer and any in-flight clone show the same sky. */
#plots.farm-dusk  .farm-layer { background-image: url("assets/farm-scene-sunset.png?v=2"); }
#plots.farm-night .farm-layer { background-image: url("assets/farm-scene-night.png?v=2"); }

/* Rainy day: its own overcast scene, with rain-drop sprites animated on top.
   The dusk hours (sunrise/sunset) reuse this same scene on a rainy day, and
   rainy night reuses the same rain-drop overlay over a dedicated night-rain
   scene, so the storm keeps falling from dawn to dark on a rainy day. */
#plots.farm-rain .farm-layer { background-image: url("assets/farm-scene-rain.png?v=2"); }
#plots.farm-rain-night .farm-layer { background-image: url("assets/farm-scene-rain-night.png?v=5"); }
/* The rain-drop overlay lives on the FIELD layer (.farm-layer), whose ::after
   renders reliably. It must NOT live on #plots::after: that container carries
   `overflow:hidden` + `container-type:inline-size` + a persisting pop-in
   `transform` (fill `both`), a combination that stops the animated pseudo from
   painting in the Telegram/WebKit webview — the storm silently disappears.
   z-index 10 keeps it ABOVE every decoration (decor-front z9), plant row (top
   cells z7) and the farmer (z8), so the storm falls in FRONT of everything on
   the field — yet below the decor editor UI (toolbar/dock at z 20+). */
#plots.farm-rain .farm-layer::after,
#plots.farm-rain-night .farm-layer::after {
  content: "";
  position: absolute;
  inset: -20%;
  z-index: 10;
  pointer-events: none;
  background-image:
    url("assets/rain-drops-1.png?v=2"),
    url("assets/rain-drops-2.png?v=2");
  background-size: 50% 50%, 50% 50%;
  background-repeat: repeat;
  background-position: 0 0, 25% 50%;
  transform: rotate(10deg);
  opacity: 0.85;
  animation: farm-rain-drop-fall 1.2s linear infinite;
  will-change: background-position;
}
@keyframes farm-rain-drop-fall {
  from { background-position: 0 0,    25% 50%; }
  to   { background-position: 0 100%, 25% 150%; }
}
@media (prefers-reduced-motion: reduce) {
  #plots.farm-rain .farm-layer::after,
  #plots.farm-rain-night .farm-layer::after { animation: none; }
}
/* Plot cells live in their own layer so the wandering butterfly overlay (a
   sibling) survives each renderPlots() innerHTML swap without losing its
   JS-held node. */
#plot-cells { position: absolute; inset: 0; }

/* Wandering butterfly. It flies in from a random side, perches on one of the
   planted plots for a beat, then flutters off again — all driven from JS (see
   the Butterfly controller). The background is an 11-frame wing-flap strip
   stepped via background-position-x; sized in cqw so it scales with the board.
   Anchored at its bottom-centre (translateY -100%) so a perch point sits on the
   plant it lands on. */
.bfly2 {
  position: absolute;
  width: 6.5cqw; height: 5.69cqw;          /* one frame = 64 x 56 px */
  background: url("assets/butterfly-monarch.png?v=4") 0 0 no-repeat;
  background-size: 71.5cqw 5.69cqw;          /* 11 frames x 6.5cqw */
  image-rendering: pixelated;
  pointer-events: none;
  z-index: 5;
  opacity: 0;
  transition: opacity 0.4s ease;
  transform: translate(-50%, -100%);
  filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, 0.3));
  will-change: transform, left, top;
}
@keyframes bfly2-flap { from { background-position-x: 0; } to { background-position-x: -71.5cqw; } }

/* Per-farm scarecrow guard. Shown only while the farm in view is protected
   (toggled from JS). Fixed on the right-hand grass strip between the plots and
   the fence, level with the central plot row. Anchored at its bottom centre;
   pointer-events:none so taps pass through to the plots beneath it. Sized in cqw
   so it scales with the board. A single still pose — it just stands guard; the
   only motion is the pop-in when it first appears. */
.scarecrow2 {
  position: absolute;
  left: 81%; top: calc(48% - 1cm);
  width: 14.375cqw;
  aspect-ratio: 238 / 294;
  background: url("assets/scarecrow.png?v=4") center / contain no-repeat;
  image-rendering: pixelated;
  pointer-events: none;
  z-index: 3;
  transform: translate(-50%, -100%);
  filter: drop-shadow(2px 4px 3px rgba(0, 0, 0, 0.32));
  /* Own pop-in that keeps the translate(-50%,-100%) foot-anchor in every
     keyframe: the shared pop-in ends on `transform: scale(1)`, which (with
     fill `both`) wipes the anchor and drops the sprite down-right off its
     left/top spot. Must preserve the translate here. */
  animation: scarecrow-pop 0.4s ease both;
}
@keyframes scarecrow-pop {
  0%   { opacity: 0; transform: translate(-50%, -100%) scale(0.94); }
  100% { opacity: 1; transform: translate(-50%, -100%) scale(1); }
}
.scarecrow2[hidden] { display: none; }

/* ---- Paragon cosmetics ---------------------------------------------------- */
/* Rainbow Butterflies: ambient drifters (not tied to Flower Scent). Reuse the
   butterfly sprite + wing-flap, add a looping flight path and a hue-rotate that
   cycles the whole rainbow. Two instances (.a/.b) with offset paths/speeds so
   the farm always has a couple fluttering about. Pure CSS — just toggled on. */
.rbfly2 {
  position: absolute;
  width: 6.5cqw; height: 5.69cqw;
  background: url("assets/butterfly-monarch.png?v=4") 0 0 no-repeat;
  background-size: 71.5cqw 5.69cqw;
  image-rendering: pixelated;
  pointer-events: none;
  z-index: 5;
  transform: translate(-50%, -100%);
  filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, 0.3)) saturate(1.6) hue-rotate(0deg);
  animation: bfly2-flap 0.45s steps(11) infinite, rbfly-hue 4s linear infinite, rbfly-path-a 15s ease-in-out infinite;
  will-change: transform, left, top;
}
.rbfly2[hidden] { display: none; }
.rbfly2.b {
  animation: bfly2-flap 0.5s steps(11) infinite, rbfly-hue 5.5s linear infinite reverse, rbfly-path-b 19s ease-in-out infinite;
}
@keyframes rbfly-hue {
  to { filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, 0.3)) saturate(1.6) hue-rotate(360deg); }
}
@keyframes rbfly-path-a {
  0%   { left: -8%;  top: 30%; transform: translate(-50%, -100%) scaleX(1) rotate(-6deg); }
  25%  { left: 34%;  top: 19%; transform: translate(-50%, -100%) scaleX(1) rotate(5deg); }
  50%  { left: 72%;  top: 33%; transform: translate(-50%, -100%) scaleX(1) rotate(-5deg); }
  75%  { left: 44%;  top: 47%; transform: translate(-50%, -100%) scaleX(-1) rotate(6deg); }
  100% { left: -8%;  top: 30%; transform: translate(-50%, -100%) scaleX(-1) rotate(-6deg); }
}
@keyframes rbfly-path-b {
  0%   { left: 108%; top: 44%; transform: translate(-50%, -100%) scaleX(-1) rotate(6deg); }
  30%  { left: 60%;  top: 24%; transform: translate(-50%, -100%) scaleX(-1) rotate(-5deg); }
  55%  { left: 28%;  top: 40%; transform: translate(-50%, -100%) scaleX(-1) rotate(5deg); }
  80%  { left: 66%;  top: 50%; transform: translate(-50%, -100%) scaleX(1) rotate(-6deg); }
  100% { left: 108%; top: 44%; transform: translate(-50%, -100%) scaleX(1) rotate(6deg); }
}

/* Paragon scarecrow skin: reskins the crow scarecrow in place — same spot and
   size (positioned by updateParagonCosmetics off the same plot anchor), no idle
   movement. The skin's art is set inline (background-image) per equipped skin.
   Skins are now tight-cropped (figure fills the frame) at a common HEIGHT, so
   the box is sized by height to match the default scarecrow (14.375cqw × 294/238
   ≈ 17.76cqw tall) and made a touch wider than the widest skin (panda, ar 0.84)
   — with `contain` every skin renders at that height, at its natural width,
   instead of shrinking inside a padded canvas. */
.pscarecrow2 {
  position: absolute;
  width: 15.3cqw;
  height: 17.76cqw;
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: contain;
  image-rendering: pixelated;
  pointer-events: none;
  z-index: 3;
  transform: translate(-50%, -100%);
  animation: scarecrow-pop 0.4s ease both, pscare-aura 2.6s ease-in-out infinite;
}
.pscarecrow2[hidden] { display: none; }
/* Prestige aura: a soft gold glow that gently pulses around the equipped skin,
   marking it as a Paragon cosmetic. Rides the drop-shadow so no extra element
   is needed; keeps the base ground shadow in every keyframe. */
@keyframes pscare-aura {
  0%, 100% { filter: drop-shadow(2px 4px 3px rgba(0, 0, 0, 0.32)) drop-shadow(0 0 3px rgba(255, 221, 128, 0.45)); }
  50%      { filter: drop-shadow(2px 4px 3px rgba(0, 0, 0, 0.32)) drop-shadow(0 0 12px rgba(255, 210, 90, 0.85)); }
}
@media (prefers-reduced-motion: reduce) {
  .pscarecrow2 { animation: scarecrow-pop 0.4s ease both; filter: drop-shadow(2px 4px 3px rgba(0, 0, 0, 0.32)) drop-shadow(0 0 6px rgba(255, 216, 110, 0.6)); }
}

/* ---- Farm decorations (DEV placement kit) --------------------------------- */
/* Two full-scene layers holding placed props. Behind the farmer (z2) and in
   front of it (z9), so a prop can tuck behind or overlap the character. The
   front layer must stay ABOVE the farmer (z8) — see the farmer z-index rule by
   the plot-cell layers — so the "bring in front of the farmer" toggle works.
   Panels themselves ignore taps; individual props opt back in while editing. */
.decor-layer { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.decor-layer-front { z-index: 9; }
/* A placed prop. Anchored at its bottom-centre on (x,y)% of the scene, so it
   sits on the ground where it was dropped; scale/rotation/flip come from JS via
   the transform. Sized by width in cqw so every prop scales with the board. */
.decor2 {
  position: absolute;
  width: 26cqw; height: auto;
  transform-origin: bottom center;
  image-rendering: auto;
  pointer-events: none;
  user-select: none; -webkit-user-drag: none;
  filter: drop-shadow(2px 4px 4px rgba(0, 0, 0, 0.35));
  /* No permanent will-change here: a farm can hold many placed props, and a
     standing `will-change: transform` promotes EACH one to its own GPU
     compositing layer for the whole session. On memory-constrained mobile
     webviews (Telegram) those layers exhaust the compositor — props and the
     editor bars blank out (go "transparent"), then the surface is lost (black
     screen) and the app freezes. The hint is added transiently to the single
     prop being dragged instead (see .decor2.dragging below). */
}
/* The default crow scarecrow (bought with the functional Scarecrow) renders at
   the exact size of the old fixed scarecrow (the retired .scarecrow2 was
   14.375cqw wide) instead of the standard 26cqw prop width. */
.decor2[src*="scarecrow_basic"] { width: 14.375cqw; }
/* While the editor is on, props become tappable/draggable and the selected one
   shows a dashed ring so its bounds and orientation are visible. */
body.decor-editing .decor2 { pointer-events: auto; cursor: grab; }
/* Promote ONLY the prop being dragged, and only for the duration of the drag
   (the `.dragging` class is added on pointerdown and removed on pointerup), so
   at most one decoration ever holds a compositing layer at a time. */
body.decor-editing .decor2.dragging { cursor: grabbing; will-change: transform, left, top; }
.decor2.selected { outline: 2px dashed var(--gold, #e0a53a); outline-offset: 2px; }
/* A locked prop is fixed: a small padlock badge marks it and it can't be dragged
   (JS blocks the drag; it stays selectable so it can be unlocked). */
body.decor-editing .decor2.locked { cursor: default; }
body.decor-editing .decor2.locked.selected { outline-style: solid; outline-color: #7fd18a; }

/* ---- Immersive edit mode ---- */
/* Turning the editor on hides the whole game HUD (header, cards, tabs, shop,
   bottom nav — all inside #app) and the two body-level farm bars, leaving just
   the full-screen farm backdrop (#plots) plus the editor's own dock/toolbar. */
body.decor-editing #app { display: none !important; }
body.decor-editing #farm-actions,
body.decor-editing #farm-switcher,
body.decor-editing #farm-buffs,
body.decor-editing #decor-fab,
body.decor-editing #farm-title { display: none !important; }
/* Lift the transform toolbar above the dock while both are on screen. */
body.decor-editing .decor-toolbar { bottom: 96px; }

/* Peek mode: hide the big bottom dock palette so most of the farm image is
   visible, but KEEP editing live — props stay selectable/draggable and the
   floating command panel (toolbar) still works, so you can arrange the farm
   with a clear view. A single floating button (below) brings the dock back. */
body.decor-peek #decor-dock { display: none !important; }
/* With the dock gone, drop the toolbar back down to the bottom edge. */
body.decor-peek .decor-toolbar { bottom: calc(14px + env(safe-area-inset-bottom)); }
.decor-peek-restore {
  position: fixed; z-index: 62;
  right: 12px; bottom: calc(14px + env(safe-area-inset-bottom));
  padding: 10px 14px; border: 1px solid rgba(224, 165, 58, 0.6);
  border-radius: 999px; cursor: pointer;
  font-size: 14px; font-weight: 700; color: #fff8e8;
  background: rgba(16, 12, 8, 0.86); backdrop-filter: blur(4px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}

/* The dock: a bottom bar with a scrollable palette of every available prop and
   the Lock button that fixes the arrangement and brings the HUD back. */
.decor-dock {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 21;
  /* Column: prop tray on top, control buttons on their own row below, so the
     buttons never squeeze the decoration thumbnails. */
  display: flex; flex-direction: column; align-items: stretch; gap: 8px;
  padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
  background: linear-gradient(to top, rgba(16, 12, 8, 0.96), rgba(16, 12, 8, 0.8));
  border-top: 1px solid rgba(224, 165, 58, 0.4);
}
.decor-dock[hidden] { display: none; }
.decor-dock-hint { display: none; }
.decor-dock-tray {
  flex: 0 0 auto; display: flex; gap: 7px; overflow-x: auto; padding: 2px; scrollbar-width: none;
}
.decor-dock-actions {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 8px; flex-wrap: wrap;
}

/* Visitor mode: a shared decorated farm opened via a "share my farm" link. Hide
   the whole game HUD, leaving only the farm stage + the visit banner/CTA. */
body.visiting header.hud,
body.visiting .hero,
body.visiting .tabs,
body.visiting .bottom-nav,
body.visiting #decor-fab,
body.visiting .farm-cards-toggle,
body.visiting #event-banner,
body.visiting #daily,
body.visiting #tip,
body.visiting .col-farm > .section-head,
body.visiting #farm-actions,
body.visiting #farm-switcher,
body.visiting #farm-buffs,
body.visiting #farm-title { display: none !important; }
body.visiting .cell { pointer-events: none; }
/* In-app visits render the visited farm's OWN crops (in #plot-cells) and its
   assigned farmer sprite, so keep the field visible — just make everything
   read-only: no planting a cell, no tapping the farmer to open its config. */
body.visiting #plot-cells,
body.visiting #farm-slider > i { pointer-events: none !important; }
.visit-banner {
  position: fixed; left: 0; right: 0; top: 0; z-index: 60;
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: calc(14px + env(safe-area-inset-top)) 14px 18px;
  background: linear-gradient(to bottom, rgba(16, 12, 8, 0.92), rgba(16, 12, 8, 0));
  pointer-events: none;
}
.visit-title {
  font-family: 'Fredoka', sans-serif; font-weight: 600; font-size: 20px;
  color: #fff; text-shadow: 0 2px 6px rgba(0, 0, 0, 0.7);
}
.visit-title b { color: var(--gold); }
.visit-play { pointer-events: auto; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4); }
/* ❤️ "leave a like" button for in-app visits. Anchored at the bottom-center as a
   floating FAB — NOT in the top banner, which the Telegram Mini App's native
   header can cover, hiding it entirely on some devices. */
.visit-heart {
  position: fixed; left: 50%; bottom: calc(24px + env(safe-area-inset-bottom));
  transform: translateX(-50%); z-index: 70;
  pointer-events: auto; cursor: pointer;
  display: inline-flex; align-items: center; gap: 9px;
  padding: 13px 24px; border: 0; border-radius: 999px;
  font-family: 'Fredoka', sans-serif; font-weight: 600; font-size: 17px; color: #fff;
  background: rgba(224, 46, 78, 0.96); box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
  transition: transform 0.12s ease, background 0.15s ease;
}
.visit-heart .vh-ico { font-size: 19px; line-height: 1; filter: saturate(1.1); }
.visit-heart .visit-heart-n {
  background: rgba(255, 255, 255, 0.24); border-radius: 999px;
  padding: 1px 10px; font-size: 15px; min-width: 22px; text-align: center;
}
.visit-heart:active { transform: translateX(-50%) scale(0.95); }
.visit-heart.hearted { background: rgba(190, 30, 62, 0.96); animation: heart-pop-fab 0.42s ease; }
@keyframes heart-pop-fab {
  0% { transform: translateX(-50%) scale(1); }
  40% { transform: translateX(-50%) scale(1.16); }
  100% { transform: translateX(-50%) scale(1); }
}
/* Kept for the hearts popup emoji (bottom-anchored FAB uses heart-pop-fab). */
@keyframes heart-pop {
  0% { transform: scale(1); } 40% { transform: scale(1.28); } 100% { transform: scale(1); }
}
/* Heart "mostrador": how many ❤️s the farm being decorated has received. Shown
   only in decoration mode, as a fixed pill anchored above the dock — clear of
   the dock at the bottom and of the top of the screen (which the Telegram Mini
   App's native header can cover). */
.heart-meter {
  position: fixed; z-index: 43;
  left: 50%; transform: translateX(-50%);
  bottom: calc(170px + env(safe-area-inset-bottom));
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 15px; border-radius: 999px;
  background: rgba(16, 12, 8, 0.82); backdrop-filter: blur(4px);
  border: 1px solid rgba(224, 165, 58, 0.4);
  color: #fff; font-family: 'Fredoka', sans-serif; font-weight: 600; font-size: 14px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4); pointer-events: none;
}
.heart-meter[hidden] { display: none; }
.heart-meter .hm-ico { font-size: 16px; line-height: 1; }
.heart-meter .hm-n { font-size: 17px; }
.heart-meter .hm-lbl { opacity: 0.82; font-weight: 500; font-size: 12px; }
/* "Someone liked your farm" popup. */
.hearts-popup { text-align: center; }
.hearts-pop-emoji { font-size: 46px; line-height: 1; margin-bottom: 6px; animation: heart-pop 0.5s ease; }
.hearts-pop-sub { margin: 4px 0 12px; opacity: 0.9; }
.hearts-pop-sub b { color: var(--gold); }
.hearts-pop-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.hearts-pop-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border-radius: 10px; background: rgba(255, 255, 255, 0.06);
}
.hearts-pop-row .hp-farm { font-weight: 600; }
.hearts-pop-row .hp-n { opacity: 0.9; }
/* Privacy toggle row in the profile/name sheet. */
.visit-privacy-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 12px; padding: 10px 12px; border-radius: 10px;
  background: rgba(120, 95, 55, 0.08); font-size: 14px; cursor: pointer;
}
.visit-privacy-row input { width: 20px; height: 20px; accent-color: var(--green); flex: 0 0 auto; }
/* Leaderboard "visit farm" button sits inline before the score. */
.rank-visit { flex: 0 0 auto; }
.decor-dock-tray::-webkit-scrollbar { display: none; }
.decor-dock-item {
  flex: 0 0 auto; width: 62px; height: 62px; padding: 4px;
  background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 11px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.decor-dock-item img { max-width: 100%; max-height: 100%; object-fit: contain; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.4)); }
.decor-dock-item.arming { border-color: var(--gold); box-shadow: 0 0 0 2px rgba(224, 165, 58, 0.55); }
.decor-dock-item:active { transform: scale(0.95); }
.decor-lock-done { flex: 0 0 auto; white-space: nowrap; }
/* Floating "Decorar" entry button on the farm HUD (only meaningful in dev). */
.decor-enter-btn { position: absolute; z-index: 8; }

/* "Tap the farm to place it" banner shown during placement mode. */
.decor-banner {
  position: absolute; left: 50%; top: 10px; transform: translateX(-50%);
  z-index: 20; max-width: 92%;
  background: rgba(20, 16, 10, 0.86); color: #ffe9b8;
  border: 1px solid rgba(224, 165, 58, 0.5); border-radius: 999px;
  padding: 7px 14px; font-size: 12px; font-weight: 700; text-align: center;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35); animation: pop-in 0.25s ease both;
}
.decor-banner[hidden] { display: none; }

/* Floating control bar for the selected prop: sits along the bottom of the
   scene. Wraps on narrow screens so every control stays reachable. */
.decor-toolbar {
  position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%);
  z-index: 20; display: flex; flex-wrap: wrap; justify-content: center; gap: 5px;
  padding: 7px 9px; max-width: 94%;
  background: rgba(20, 16, 10, 0.9); border: 1px solid rgba(224, 165, 58, 0.4);
  border-radius: 14px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
  animation: pop-in 0.2s ease both;
}
.decor-toolbar[hidden] { display: none; }
.decor-toolbar.dragging { cursor: grabbing; box-shadow: 0 10px 26px rgba(0, 0, 0, 0.55); }
/* Grip handle: the one spot that drags the whole panel. touch-action:none so a
   touch-drag moves the panel instead of scrolling the webview. */
.decor-toolbar .decor-tool-drag {
  align-self: center; touch-action: none; cursor: grab;
  color: #ffe9b8; font-size: 16px; line-height: 1;
  padding: 0 6px; user-select: none; -webkit-user-select: none;
}
.decor-toolbar.dragging .decor-tool-drag { cursor: grabbing; }
.decor-toolbar button {
  min-width: 34px; height: 34px; padding: 0 8px;
  border: 1px solid rgba(255, 255, 255, 0.16); border-radius: 9px;
  background: rgba(255, 255, 255, 0.08); color: #fff;
  font-size: 15px; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.decor-toolbar button:active { transform: scale(0.94); }
.decor-toolbar button.decor-danger { background: rgba(200, 60, 60, 0.28); border-color: rgba(255, 120, 120, 0.4); }
.decor-toolbar button.decor-done { background: rgba(90, 180, 100, 0.32); border-color: rgba(150, 230, 160, 0.5); }
.decor-toolbar .decor-tool-label { color: #ffe9b8; font-size: 11px; align-self: center; padding: 0 4px; font-weight: 700; }
/* Directional nudge cluster: kept together and tinted so it reads as one
   move control next to the transform buttons. */
.decor-toolbar .decor-tool-move { display: inline-flex; gap: 3px; padding: 3px; border-radius: 11px; background: rgba(224, 165, 58, 0.12); }
.decor-toolbar .decor-tool-move button { min-width: 30px; padding: 0 5px; background: rgba(224, 165, 58, 0.2); border-color: rgba(224, 165, 58, 0.4); font-size: 12px; }

/* Decoration shop (dev): kit sections, each a grid of prop thumbnails; tapping
   one arms placement. */
#decor-shop { display: block; }
.decor-kit-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: 8px; }
.decor-kit-head {
  display: flex; align-items: center; gap: 6px;
  margin: 14px 0 8px; font-size: 13px; font-weight: 800; color: var(--ink);
}
.decor-kit-head:first-of-type { margin-top: 2px; }
.decor-kit-head .muted { font-weight: 700; font-size: 11px; }
.decor-card {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 8px 6px; background: rgba(255, 250, 240, 0.72);
  backdrop-filter: blur(7px) saturate(1.1); -webkit-backdrop-filter: blur(7px) saturate(1.1);
  border: 1px solid rgba(110, 84, 46, 0.22); border-radius: var(--radius-sm);
  text-align: center; cursor: pointer;
}
.decor-card img { width: auto; height: 66px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.25)); }
.decor-card .decor-card-name { font-size: 11px; font-weight: 800; color: var(--ink); line-height: 1.15; }
.decor-card.arming { border-color: var(--gold); box-shadow: 0 0 0 2px rgba(224, 165, 58, 0.4); }
/* Unowned props read as locked until bought: dimmed art, buy button below. */
.decor-card.locked img { opacity: 0.62; filter: grayscale(0.35) drop-shadow(0 2px 3px rgba(0, 0, 0, 0.25)); }
.decor-card .btn { width: 100%; margin-top: 2px; }
.decor-editing-note { margin: 2px 0 8px; font-size: 12px; }
.decor-dock-empty { padding: 8px 10px; font-size: 12px; align-self: center; }

/* Paragon Shop balance header */
/* Balance sits directly on the dark shop panel, so its text is light (like the
   section headers), not the dark ink used inside the light tiles. */
.paragon-balance { font-size: 13px; font-weight: 800; color: #ffe9b0; padding: 2px 2px 8px; }
.paragon-balance .muted { font-weight: 600; font-size: 11.5px; color: #e6d8bb; }
/* Pointer from the Paragon shop to where scarecrow skins now live. */
.paragon-scare-note { margin-top: 12px; font-size: 12px; line-height: 1.4; }
.paragon-sub { margin-top: 12px; }

/* Player-icon avatars: a round-tile grid; single-select (the equipped one gets
   a gold ring), locked ones dimmed until bought. */
.paragon-avatars {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.pavatar {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 8px 6px;
  background: var(--cream-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  text-align: center;
}
.pavatar img {
  width: 100%; max-width: 88px; aspect-ratio: 1; border-radius: 50%;
  object-fit: cover; image-rendering: auto;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.pavatar.locked img { filter: grayscale(0.35) brightness(0.96); opacity: 0.9; }
.pavatar.equipped { border-color: var(--gold); box-shadow: 0 0 0 2px rgba(224, 165, 58, 0.35); }
.pavatar-name { font-size: 11px; font-weight: 800; color: var(--ink); line-height: 1.15; }
.pavatar .btn { width: 100%; padding: 5px 4px; }

/* Scarecrow skins: same single-select tile grid as avatars, but the art is a
   tall standing scarecrow (not a round icon) shown whole on a grass-tinted tile. */
.paragon-scarecrows {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.pscare {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 8px 6px;
  background: var(--cream-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  text-align: center;
}
.pscare img {
  width: auto; height: 84px; object-fit: contain;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.25));
}
.pscare.locked img { filter: grayscale(0.4) brightness(0.96); opacity: 0.9; }
.pscare.equipped { border-color: var(--gold); box-shadow: 0 0 0 2px rgba(224, 165, 58, 0.35); }
.pscare .btn { width: 100%; padding: 5px 4px; }
/* Equipped skin shows two actions stacked: edit-farms + hide. */
.pscare-actions { display: flex; flex-direction: column; gap: 4px; width: 100%; }
.pscare-actions .btn { width: 100%; }

/* Translucent Paragon Shop items: the tiles (cosmetic rows, avatar + scarecrow
   cards) are frosted glass so the dark shop panel reads softly through them —
   but the cream layer stays opaque enough (0.72) that the dark ink text on top
   keeps contrast. (0.4 was too sheer over the dark panel and the text vanished.)
   Equipped tiles keep their gold ring. */
#paragon-shop .row,
#paragon-shop .pavatar,
#paragon-shop .pscare {
  background: rgba(255, 250, 240, 0.72);
  backdrop-filter: blur(7px) saturate(1.1);
  -webkit-backdrop-filter: blur(7px) saturate(1.1);
  border-color: rgba(110, 84, 46, 0.22);
}
#paragon-shop .row.mastery-locked,
#paragon-shop .pavatar.locked,
#paragon-shop .pscare.locked { background: rgba(255, 250, 240, 0.52); }

/* The equipped avatar as the medallion core (top-left HUD), replacing the 🐼.
   It fills the round core; the avatar's own frame shows, so the core drops its
   green disc + border while the gold XP ring around the medallion stays. */
.medal-avatar { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
body.v2 .lvl-medal .core.has-avatar { background: none; border: 0; }

/* Raiding crow. Flown onto a plot a crow has just eaten by the CrowRaid
   controller; the background is an 8-frame flapping strip stepped via
   background-position-x, anchored at its bottom-centre so it lands on the plant. */
.crow2 {
  position: absolute;
  width: 9cqw; height: 9cqw;
  background: url("assets/crow-fly.png?v=4") 0 0 no-repeat;
  background-size: 72cqw 9cqw;             /* 8 frames × 9cqw */
  image-rendering: pixelated;
  pointer-events: none;
  z-index: 7;
  opacity: 0;
  display: none;
  transition: opacity 0.3s ease;
  transform: translate(-50%, -90%);
  filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, 0.4));
  will-change: transform, left, top, background-position;
}
@keyframes crow2-flap { from { background-position-x: 0; } to { background-position-x: -72cqw; } }
/* While settled on a raided plot the crow shows a single grounded/pecking pose
   instead of the flight strip. */
.crow2.pecking {
  background-image: url("assets/crow-peck.png?v=4");
  background-size: contain;
  animation: none;
}

/* The plant a crow is devouring: the server already cleared the plot, so the
   raid controller re-draws the eaten crop here (positioned like its plot cell)
   for the crow to land on, then fades it out — shrinking toward the stem base —
   the moment it's pecked away. Sits just under the crow overlay. */
.crow-victim {
  z-index: 4;
  pointer-events: none;
  transform-origin: 50% 90%;
  transition: opacity 0.45s ease, transform 0.45s ease;
}
.crow-victim.eaten { opacity: 0; transform: scale(0.45); }

/* Panda Farmer: walks around the assigned farm plot-by-plot, planting, watering
   and harvesting autonomously. Sprite sheet (overalls gardener art): 1408×768px,
   8 cols × 4 rows, uniform cell 176×192px → element 12cqw × 15cqw.
   Background-size: 96cqw × 60cqw (8×12 by 4×15).
   Row layout (0-based, y = -row×15cqw, x = -col×12cqw):
     0 WALK-side 8f (flip scaleX for left; reused as trot)
     1 front stand/WALK-down 5f (cols 0-4) · WATER-can 2f (cols 5-6) · smile (col 7, unused)
     2 WALK-up/back 4f (cols 0-3) · PLANT/shovel dig 3f (cols 4-6) · side stand (col 7, unused)
     3 seedling hold 3f (cols 1-3, unused) · celebrate 4f (cols 4-7, unused)
   Sideways walk flips via scaleX; vertical movement uses rows 1/2. */
.panda2 {
  position: absolute;
  width: 12cqw; height: 15cqw;
  background: url("assets/panda-farmer.png?v=14") 0 0 no-repeat;
  background-size: 96cqw 60cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.panda2[hidden] { display: none; }
/* Row 1, col 0 – idle, a single held frame. Cols 0-1 alternate poses that are
   drawn slightly offset from each other, so cycling them made the panda jitter
   sideways; he simply stands still instead. */
@keyframes panda2-idle {
  from { background-position: 0 -15cqw; }
  to   { background-position: 0 -15cqw; }
}
/* Row 0 – walk sideways, 8 frames (flip scaleX for left) */
@keyframes panda2-walk {
  from { background-position: 0 0; }
  to   { background-position: -96cqw 0; }
}
/* Row 0 – trot/run, 8 frames (reuse walk-side row) */
@keyframes panda2-trot {
  from { background-position: 0 0; }
  to   { background-position: -96cqw 0; }
}
/* Row 1, cols 0-4 – walk down (front), 5 frames */
@keyframes panda2-walk-down {
  from { background-position: 0 -15cqw; }
  to   { background-position: -60cqw -15cqw; }
}
/* Row 2, cols 0-3 – walk up (back-view), 4 frames */
@keyframes panda2-walk-up {
  from { background-position: 0 -30cqw; }
  to   { background-position: -48cqw -30cqw; }
}
/* Row 2, cols 4-6 – plant/harvest, 3 frames (shovel dig) */
@keyframes panda2-plant {
  from { background-position: -48cqw -30cqw; }
  to   { background-position: -84cqw -30cqw; }
}
/* Row 1, cols 5-6 – water, 2 frames (watering can) */
@keyframes panda2-water {
  from { background-position: -60cqw -15cqw; }
  to   { background-position: -84cqw -15cqw; }
}
/* Personality flourishes live on a second sheet (panda-personality.png, same
   8×4 geometry). The .perso class swaps the background to it while an idle
   flourish plays, then the controller drops it back to the chore sheet.
     Row 0 – celebration · Row 1 – dance · Row 3 – silly faces
   Column 0 of each row carries a baked-in text label, so every flourish starts
   at column 1. */
.panda2.perso {
  background-image: url("assets/panda-personality.png?v=1");
}
/* Row 0, cols 1-4 – arms-up cheer with confetti, 4 frames. */
@keyframes panda2-celebrate {
  from { background-position: -12cqw 0; }
  to   { background-position: -60cqw 0; }
}
/* Row 1, cols 1-4 – little dance ending on a hat lift, 4 frames. */
@keyframes panda2-dance {
  from { background-position: -12cqw -15cqw; }
  to   { background-position: -60cqw -15cqw; }
}
/* Row 3, cols 1-4 – pull a few silly faces, 4 frames. */
@keyframes panda2-faces {
  from { background-position: -12cqw -45cqw; }
  to   { background-position: -60cqw -45cqw; }
}

/* Shark Farmer sprite (1408×768 source → 8 cols × 4 rows, frame 176×192px).
   Displayed at 12cqw × 15cqw, background-size: 96cqw × 60cqw (8×12 by 4×15).
   Real row layout (0-based, y = -row×15cqw, x = -col×12cqw):
     0 WALK-side, 8f (flip scaleX for left; reused as trot)
     1 WALK-down/front 6f (cols 0-5) · WATER 2f (cols 6-7)
     2 WALK-up/back 4f (cols 0-3) · PLANT/dig 4f (cols 4-7)
     3 IDLE 4f (cols 0-3) · map/wave emotes (cols 4-7, unused)
   Dev-mode-only — never rendered in production. */
.shark2 {
  position: absolute;
  width: 12cqw; height: 15cqw;
  background: url("assets/shark-farmer.png?v=2") 0 0 no-repeat;
  background-size: 96cqw 60cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.shark2[hidden] { display: none; }
/* Row 3 – idle: gentle 2-frame breathing (cols 0-1). */
@keyframes shark2-idle {
  from { background-position: 0 -45cqw; }
  to   { background-position: -24cqw -45cqw; }
}
/* Row 0 – walk sideways, 8 frames (flip scaleX for left). */
@keyframes shark2-walk {
  from { background-position: 0 0; }
  to   { background-position: -96cqw 0; }
}
/* Trot reuses the row-0 side walk (no dedicated run row), 8 frames. */
@keyframes shark2-trot {
  from { background-position: 0 0; }
  to   { background-position: -96cqw 0; }
}
/* Row 1 – walk down/front, 6 frames (cols 0-5; cols 6-7 are watering). */
@keyframes shark2-walk-down {
  from { background-position: 0 -15cqw; }
  to   { background-position: -72cqw -15cqw; }
}
/* Row 2 – walk up/back, 4 frames (cols 0-3; cols 4-7 are digging). */
@keyframes shark2-walk-up {
  from { background-position: 0 -30cqw; }
  to   { background-position: -48cqw -30cqw; }
}
/* Row 2 – plant/dig, 4 frames (cols 4-7). */
@keyframes shark2-plant {
  from { background-position: -48cqw -30cqw; }
  to   { background-position: -96cqw -30cqw; }
}
/* Row 1 – water, 2 frames (cols 6-7). */
@keyframes shark2-water {
  from { background-position: -72cqw -15cqw; }
  to   { background-position: -96cqw -15cqw; }
}

/* Fox Farmer sprite (1408×768 source → 8 cols × 4 rows, frame 176×192px).
   Displayed at 12cqw × 15cqw, background-size: 96cqw × 60cqw (8×12 by 4×15).
   Row layout (0-based, y = -row×15cqw, x = -col×12cqw):
     0 WALK-side, 8f (flip scaleX for left; reused as trot)
     1 WALK-down/front 6f (cols 0-5) · WATER 2f (cols 6-7)
     2 WALK-up/back 4f (cols 0-3) · PLANT/dig 4f (cols 4-7)
     3 IDLE 2f (cols 0-1) */
.fox2 {
  position: absolute;
  width: 12cqw; height: 15cqw;
  background: url("assets/fox-farmer.png?v=10") 0 0 no-repeat;
  background-size: 96cqw 60cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  /* The +10% size is baked into the sprite frames themselves (fox-farmer.png),
     so every animation state is the same size — no runtime scale to drift
     between idle and walk/plant/water. */
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.fox2[hidden] { display: none; }
/* Farming sheet (fox-farmer.png, 8 cols × 4 rows):
     Row 0 – front idle/walk (c0-6) + wave (c7)   · Row 1 – front (c0-4) + watering can (c5-6) + laugh (c7)
     Row 2 – back walk-up (c0-3) + shovel dig (c4-7)
     Row 3 – front idle (c0-3) + harvest holding the seed map (c4-5) + celebrate (c6-7)
   This sheet is front-facing (no side profile), so horizontal movement uses the
   front row 0. Cols 5-7 of the walk rows carry expression frames, so the walk
   loops cols 0-6 only. */
/* Row 1, cols 0-1 – neutral front pose used as idle, 2 frames. */
@keyframes fox2-idle {
  from { background-position: 0       -15cqw; }
  to   { background-position: -24cqw  -15cqw; }
}
/* Row 0, cols 0-6 – walk (front), 7 frames (scaleX mirrors for left). */
@keyframes fox2-walk {
  from { background-position: 0       0; }
  to   { background-position: -84cqw  0; }
}
/* Trot reuses the row-0 walk, 7 frames. */
@keyframes fox2-trot {
  from { background-position: 0       0; }
  to   { background-position: -84cqw  0; }
}
/* No separate front/side walk — down movement reuses the row-0 walk, 7 frames. */
@keyframes fox2-walk-down {
  from { background-position: 0       0; }
  to   { background-position: -84cqw  0; }
}
/* Row 2, cols 0-3 – walk up / away (back view), 4 frames. */
@keyframes fox2-walk-up {
  from { background-position: 0       -30cqw; }
  to   { background-position: -48cqw  -30cqw; }
}
/* Row 2, cols 4-7 – dig with the shovel as the plant action, 4 frames. */
@keyframes fox2-plant {
  from { background-position: -48cqw  -30cqw; }
  to   { background-position: -96cqw  -30cqw; }
}
/* Row 1, cols 5-6 – tip the watering can as the water action, 2 frames. */
@keyframes fox2-water {
  from { background-position: -60cqw  -15cqw; }
  to   { background-position: -84cqw  -15cqw; }
}
/* Idle flourishes (played occasionally between chores, then back to the still
   idle frame). Row 3 c6-7 – cheer with an arm up; Row 3 c4-5 – show the seed map. */
@keyframes fox2-celebrate {
  from { background-position: -72cqw  -45cqw; }
  to   { background-position: -96cqw  -45cqw; }
}
@keyframes fox2-show {
  from { background-position: -48cqw  -45cqw; }
  to   { background-position: -72cqw  -45cqw; }
}

/* Panda Farmer LE sprite (limited edition, Brazil-kit football art) — 8×4 /
   176×192 sheet, same geometry as the standard farmers.
   Row layout (0-based, y = -row×15cqw, x = -col×12cqw):
     0 side stand (c0) · front stand (c1) · BACK views 2f (c2-3) · ball kicks (c4-7)
     1 side walk (c0) · front-with-ball 3f (c1-3) · KICK series 3f (c4-6) · seat trick (c7)
     2 standing juggles 8f (WATER borrows c4-5)
     3 dribble run 4f (c0-3, the WALK cycle) · stand/kicks (c4-7) */
.pandale2 {
  position: absolute;
  width: 12cqw; height: 15cqw;
  background: url("assets/panda-farmer-le.png?v=6") 0 0 no-repeat;
  background-size: 96cqw 60cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.pandale2[hidden] { display: none; }
/* Freestyle (embaixadinha) sheet: panda-juggle.png, 8 cols × 5 rows
   (176×192px each, same cell geometry as the main sheet):
     Row 0 – lateral keepie-uppies · Row 1 – chest kill ("matando no peito")
     Row 2 – run-up + jump header  · Row 3 – celebration
     Row 4 – front-facing keepie-uppies (the original juggle strip: the ball
             travels a vertical line through the body centre and balances on
             the head)
   The animations hand-pick cells instead of walking each row: a few source
   frames read as handling the ball (paw touching it) or carry white impact
   puffs between panda and ball, so those cells are skipped entirely and the
   keyframes jump between the clean football poses. Everything runs with
   `step-end` and non-uniform stops so the ball obeys real timing: fast while
   travelling, hanging at the apex, quick at each contact. The .juggle class
   is toggled by PandaleFarmer whenever a freestyle animation plays. */
.pandale2.juggle {
  background-image: url("assets/panda-juggle.png?v=13");
  background-size: 96cqw 75cqw; /* 8 cols × 12cqw, 5 rows × 15cqw */
}
/* Keepie-uppie loop (row 0, cells 0/3/4/5/3/7 — knee-and-foot touches only):
   knee flicks it up, ball rises past the head, hangs at the apex, falls back
   and the other knee catches it. Runs with step-end (set from JS), so each
   stop below holds until the next one. */
@keyframes pandale2-idle {
  0%   { background-position: 0      0; }  /* knee kick */
  15%  { background-position: -36cqw 0; }  /* rising past the head */
  31%  { background-position: -48cqw 0; }  /* apex above the head */
  52%  { background-position: -60cqw 0; }  /* hangs, tips over */
  66%  { background-position: -36cqw 0; }  /* falling back down */
  82%, 100% { background-position: -84cqw 0; } /* other knee takes it */
}
/* Chest kill (row 1, cells 0/1/4/5/6/7): ball flies in fast, meets the chest
   (contact implied between the arrival and the pop-up), hangs above the head,
   then drops and dies at the feet. Cells 2-3 (white impact puffs, ball at paw
   height) are skipped. */
@keyframes pandale2-chest {
  0%   { background-position: 0      -15cqw; }
  13%  { background-position: -12cqw -15cqw; }
  30%  { background-position: -48cqw -15cqw; }
  54%  { background-position: -60cqw -15cqw; }
  66%  { background-position: -72cqw -15cqw; }
  80%, 100% { background-position: -84cqw -15cqw; }
}
/* Juggle sheet row 2 – run-up + jump header. Even run strides (f0–f1),
   explosive takeoff (f2), slower rise to the ball (f3), snap head contact
   (f4), ball sails off while he falls (f5), landing crouch absorbs (f6),
   stand back up (f7). */
@keyframes pandale2-header {
  0%   { background-position: 0      -30cqw; }
  12%  { background-position: -12cqw -30cqw; }
  24%  { background-position: -24cqw -30cqw; }
  33%  { background-position: -36cqw -30cqw; }
  47%  { background-position: -48cqw -30cqw; }
  56%  { background-position: -60cqw -30cqw; }
  70%  { background-position: -72cqw -30cqw; }
  84%, 100% { background-position: -84cqw -30cqw; }
}
/* Celebration (row 3, cells 3-7): winks at the ball by his feet, arms go up,
   a little hop, lands and finishes with his foot on the ball. Cells 0-1 are
   skipped — they hold the ball in a paw, which reads as a handball. The ball
   stays on the ground through the hop (composited into cells 4-6 at build
   time). */
@keyframes pandale2-celebrate {
  0%   { background-position: -36cqw -45cqw; }
  22%  { background-position: -48cqw -45cqw; }
  44%  { background-position: -60cqw -45cqw; }
  66%  { background-position: -72cqw -45cqw; }
  84%, 100% { background-position: -84cqw -45cqw; }
}
/* Front keepie-uppies (row 4, all 8 frames): ground → knee flick → face →
   balances on the head for two beats → drops past the face → belly → ground.
   Uniform frames (steps(8) from JS), torso-aligned so nothing drifts. */
@keyframes pandale2-idle-front {
  from { background-position: 0      -60cqw; }
  to   { background-position: -96cqw -60cqw; }
}
/* Main sheet – standing idle, Row 1 cols 2-3 (front hold → front stand).
   Alternates with the keepie-uppie idle so it doesn't get repetitive. */
@keyframes pandale2-stand {
  from { background-position: -24cqw -15cqw; }
  to   { background-position: -48cqw -15cqw; }
}
/* Farming sheet layout (panda-farmer-le.png, 8 cols × 4 rows):
     Row 0 – walk side (8f)      · Row 1 – walk down/front (c0-5) + water (c6-7)
     Row 2 – walk up/back (c0-3) + dig/plant (c4-7)
     Row 3 – idle front (c0) + harvest holding the seedling (c1-3) + wave (c4-7)
   The football freestyle (embaixadinha) idle keeps running off the separate
   panda-juggle.png sheet via the .juggle class; only these main-sheet chores
   use this sheet. */
/* Row 0, all 8 cols – walk sideways (flip scaleX for left). */
@keyframes pandale2-walk {
  from { background-position: 0      0; }
  to   { background-position: -96cqw 0; }
}
/* Trot reuses the row-0 walk cycle, 8 frames, driven faster from JS. */
@keyframes pandale2-trot {
  from { background-position: 0      0; }
  to   { background-position: -96cqw 0; }
}
/* Row 1, cols 0-5 – walk down / toward the viewer, 6 frames. */
@keyframes pandale2-walk-down {
  from { background-position: 0      -15cqw; }
  to   { background-position: -72cqw -15cqw; }
}
/* Row 2, cols 0-3 – walk up / away (hat brim toward camera), 4 frames. */
@keyframes pandale2-walk-up {
  from { background-position: 0      -30cqw; }
  to   { background-position: -48cqw -30cqw; }
}
/* Row 2, cols 4-7 – dig with the shovel as the plant action, 4 frames. */
@keyframes pandale2-plant {
  from { background-position: -48cqw -30cqw; }
  to   { background-position: -96cqw -30cqw; }
}
/* Row 1, cols 6-7 – tip the watering can as the water action, 2 frames. */
@keyframes pandale2-water {
  from { background-position: -72cqw -15cqw; }
  to   { background-position: -96cqw -15cqw; }
}
/* Row 3, cols 1-3 – lift and cradle the harvested seedling, 3 frames. */
@keyframes pandale2-harvest {
  from { background-position: -12cqw -45cqw; }
  to   { background-position: -48cqw -45cqw; }
}

/* Porcupine Farmer sprite (1408×768 source → 8 cols × 4 rows, frame 176×192px).
   Same layout as the fox/shark; dev-mode-only. */
.porcupine2 {
  position: absolute;
  width: 12cqw; height: 15cqw;
  background: url("assets/porcupine-farmer.png?v=3") 0 0 no-repeat;
  background-size: 96cqw 60cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.porcupine2[hidden] { display: none; }
/* Farming sheet (porcupine-farmer.png, 8 cols × 4 rows):
     Row 0 – side walk (c0-6) + celebrate (c7)   · Row 1 – front (c0-4) + watering can (c5-6) + laugh (c7)
     Row 2 – back walk-up (c0-3) + shovel dig (c4-7)
     Row 3 – front idle (c0-3) + harvest holding the seed map (c4-5) + celebrate (c6-7)
   No front walk, so down movement reuses the side walk. */
/* Row 1, cols 0-1 – neutral front pose used as idle, 2 frames. */
@keyframes porcupine2-idle {
  from { background-position: 0       -15cqw; }
  to   { background-position: -24cqw  -15cqw; }
}
/* Row 0, cols 0-6 – walk sideways, 7 frames (flip scaleX for left). */
@keyframes porcupine2-walk {
  from { background-position: 0       0; }
  to   { background-position: -84cqw  0; }
}
/* Trot reuses the row-0 side walk, 7 frames. */
@keyframes porcupine2-trot {
  from { background-position: 0       0; }
  to   { background-position: -84cqw  0; }
}
/* No front walk — down movement reuses the row-0 side walk, 7 frames. */
@keyframes porcupine2-walk-down {
  from { background-position: 0       0; }
  to   { background-position: -84cqw  0; }
}
/* Row 2, cols 0-3 – walk up / away (back view), 4 frames. */
@keyframes porcupine2-walk-up {
  from { background-position: 0       -30cqw; }
  to   { background-position: -48cqw  -30cqw; }
}
/* Row 2, cols 4-7 – dig with the shovel as the plant action, 4 frames. */
@keyframes porcupine2-plant {
  from { background-position: -48cqw  -30cqw; }
  to   { background-position: -96cqw  -30cqw; }
}
/* Row 1, cols 5-6 – tip the watering can as the water action, 2 frames. */
@keyframes porcupine2-water {
  from { background-position: -60cqw  -15cqw; }
  to   { background-position: -84cqw  -15cqw; }
}
/* Idle flourishes: Row 3 c6-7 – cheer with an arm up; Row 3 c4-5 – show the seed map. */
@keyframes porcupine2-celebrate {
  from { background-position: -72cqw  -45cqw; }
  to   { background-position: -96cqw  -45cqw; }
}
@keyframes porcupine2-show {
  from { background-position: -48cqw  -45cqw; }
  to   { background-position: -72cqw  -45cqw; }
}

/* Alligator Farmer sprite (1408×768 source → 8 cols × 4 rows, frame 176×192px).
   Same layout as the fox/porcupine; dev-mode-only. */
.alligator2 {
  position: absolute;
  width: 12cqw; height: 15cqw;
  background: url("assets/alligator-farmer.png?v=5") 0 0 no-repeat;
  background-size: 96cqw 60cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  /* 10% larger than the base art; scaled around the foot anchor (50% 85%,
     matching the translate) so the feet stay planted. The JS movement
     transform mirrors this scale — keep them in sync. */
  transform-origin: 50% 85%;
  transform: translate(-50%, -85%) scale(1.1);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.alligator2[hidden] { display: none; }
/* Farming sheet (alligator-farmer.png, 8 cols × 4 rows):
     Row 0 – side walk (c0-7, 8f)                 · Row 1 – front idle (c0-3) + watering can (c4-7)
     Row 2 – back walk-up (c0-3) + shovel dig (c4-7)
     Row 3 – front idle (c0-3) + holding the sprout (c4-5) + celebrate wink (c6-7)
   No front walk, so down movement reuses the side walk. The water action tips
   the watering can (c4-7) as the gator pours over the plot. */
/* Row 1, cols 0-1 – neutral front pose used as idle, 2 frames. */
@keyframes alligator2-idle {
  from { background-position: 0       -15cqw; }
  to   { background-position: -24cqw  -15cqw; }
}
/* Row 0, cols 0-7 – walk sideways, 8 frames (flip scaleX for left). */
@keyframes alligator2-walk {
  from { background-position: 0       0; }
  to   { background-position: -96cqw  0; }
}
/* Trot reuses the row-0 side walk, 8 frames. */
@keyframes alligator2-trot {
  from { background-position: 0       0; }
  to   { background-position: -96cqw  0; }
}
/* No front walk — down movement reuses the row-0 side walk, 8 frames. */
@keyframes alligator2-walk-down {
  from { background-position: 0       0; }
  to   { background-position: -96cqw  0; }
}
/* Row 2, cols 0-3 – walk up / away (back view), 4 frames. */
@keyframes alligator2-walk-up {
  from { background-position: 0       -30cqw; }
  to   { background-position: -48cqw  -30cqw; }
}
/* Row 2, cols 4-7 – dig with the shovel as the plant action, 4 frames. */
@keyframes alligator2-plant {
  from { background-position: -48cqw  -30cqw; }
  to   { background-position: -96cqw  -30cqw; }
}
/* Row 1, cols 4-7 – tip the watering can as the water action, 4 frames. */
@keyframes alligator2-water {
  from { background-position: -48cqw  -15cqw; }
  to   { background-position: -96cqw  -15cqw; }
}
/* Idle flourishes: Row 3 c6-7 – cheer with an arm up; Row 3 c4-5 – show the seed map. */
@keyframes alligator2-celebrate {
  from { background-position: -72cqw  -45cqw; }
  to   { background-position: -96cqw  -45cqw; }
}
@keyframes alligator2-show {
  from { background-position: -48cqw  -45cqw; }
  to   { background-position: -72cqw  -45cqw; }
}

/* Bat Farmer sprite (1408×768 source → 8 cols × 4 rows, frame 176×192px).
   Same layout as the fox/alligator; dev-mode-only. The bat art is drawn ~17%
   larger inside its cells than the other farmers, so the whole sprite (and its
   keyframe offsets) is rendered at 0.85× to match their on-screen size. */
.bat2 {
  position: absolute;
  width: 10.2cqw; height: 12.75cqw;
  background: url("assets/bat-farmer.png?v=4") 0 0 no-repeat;
  background-size: 81.6cqw 51cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  /* 10% larger than the base art; scaled around the foot anchor (50% 85%,
     matching the translate) so the feet stay planted on the plot. The JS
     movement transform mirrors this scale — keep them in sync. */
  transform-origin: 50% 85%;
  transform: translate(-50%, -85%) scale(1.1);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.bat2[hidden] { display: none; }
/* Sheet layout (bat-farmer.png, 8 cols × 4 rows):
     Row 0 – front idle / expressions (8f)   · Row 1 – walk sideways (8f)
     Row 2 – dig/shovel (c0-3) + watering can (c4-7)
     Row 3 – front celebrate/laugh (8f, currently unused)
   This sheet has no dedicated front/back walk, so vertical movement reuses the
   side walk. */
/* Row 0, cols 0-1 – calm closed-mouth front pose used as idle. */
@keyframes bat2-idle {
  from { background-position: 0 0; }
  to   { background-position: -20.4cqw 0; }
}
/* Row 1 – walk sideways, 8 frames (flip scaleX for left). */
@keyframes bat2-walk {
  from { background-position: 0       -12.75cqw; }
  to   { background-position: -81.6cqw -12.75cqw; }
}
/* Trot reuses the row-1 side walk, 8 frames. */
@keyframes bat2-trot {
  from { background-position: 0       -12.75cqw; }
  to   { background-position: -81.6cqw -12.75cqw; }
}
/* No front/back walk on this sheet — down/up movement reuses the side walk. */
@keyframes bat2-walk-down {
  from { background-position: 0       -12.75cqw; }
  to   { background-position: -81.6cqw -12.75cqw; }
}
@keyframes bat2-walk-up {
  from { background-position: 0       -12.75cqw; }
  to   { background-position: -81.6cqw -12.75cqw; }
}
/* Row 2, cols 0-3 – dig with the shovel as the plant action, 4 frames. */
@keyframes bat2-plant {
  from { background-position: 0       -25.5cqw; }
  to   { background-position: -40.8cqw -25.5cqw; }
}
/* Row 2, cols 4-7 – tip the watering can as the water action, 4 frames. */
@keyframes bat2-water {
  from { background-position: -40.8cqw -25.5cqw; }
  to   { background-position: -81.6cqw -25.5cqw; }
}
/* Idle flourishes: Row 3 c0-3 – happy wing-flap cheer; Row 0 c4-7 – wink/wave expressions. */
@keyframes bat2-celebrate {
  from { background-position: 0        -38.25cqw; }
  to   { background-position: -40.8cqw -38.25cqw; }
}
@keyframes bat2-wink {
  from { background-position: -40.8cqw 0; }
  to   { background-position: -81.6cqw 0; }
}

/* Sheep Farmer sprite (1408×768 source → 8 cols × 4 rows, frame 176×192px).
   Same layout as the bat; dev-mode-only. The sheep art is drawn larger inside
   its cells than the standard farmers, so the whole sprite (and its keyframe
   offsets) is rendered at 0.86× to keep its on-screen size in proportion. */
.sheep2 {
  position: absolute;
  width: 10.32cqw; height: 12.9cqw;
  background: url("assets/sheep-farmer.png?v=2") 0 0 no-repeat;
  background-size: 82.56cqw 51.6cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.sheep2[hidden] { display: none; }
/* Row 0 – idle, 2 frames (cols 0-1) — calm closed-mouth front pose. Row 3 is the
   mouth-open laugh, so idle borrows the neutral row-0 frames instead. */
@keyframes sheep2-idle {
  from { background-position: 0 0; }
  to   { background-position: -20.64cqw 0; }
}
/* Row 0 – walk sideways, 8 frames (flip scaleX for left) */
@keyframes sheep2-walk {
  from { background-position: 0 0; }
  to   { background-position: -82.56cqw 0; }
}
/* Trot reuses the row-0 side walk, 8 frames. */
@keyframes sheep2-trot {
  from { background-position: 0 0; }
  to   { background-position: -82.56cqw 0; }
}
/* Row 1 – walk down/front, 6 frames (cols 0-5) */
@keyframes sheep2-walk-down {
  from { background-position: 0 -12.9cqw; }
  to   { background-position: -61.92cqw -12.9cqw; }
}
/* Row 2 – walk up/back, 4 frames (cols 0-3) */
@keyframes sheep2-walk-up {
  from { background-position: 0 -25.8cqw; }
  to   { background-position: -41.28cqw -25.8cqw; }
}
/* Row 2 – plant/dig, 4 frames (cols 4-7) */
@keyframes sheep2-plant {
  from { background-position: -41.28cqw -25.8cqw; }
  to   { background-position: -82.56cqw -25.8cqw; }
}
/* Row 1 – water, 2 frames (cols 6-7) */
@keyframes sheep2-water {
  from { background-position: -61.92cqw -12.9cqw; }
  to   { background-position: -82.56cqw -12.9cqw; }
}

/* Mantis Farmer sprite (1408×768 source → 8 cols × 4 rows, frame 176×192px).
   Row layout matches the bat/sheep: row 0 is the neutral front pose (idle borrows
   its first frames), row 3 is the mouth-open laugh. The mantis art is drawn larger
   inside its cells than the standard farmers, so the whole sprite (and its keyframe
   offsets) is rendered at 0.85× to keep its on-screen size in proportion.
   Dev-mode-only. */
.mantis2 {
  position: absolute;
  width: 10.2cqw; height: 12.75cqw;
  background: url("assets/mantis-farmer.png?v=2") 0 0 no-repeat;
  background-size: 81.6cqw 51cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.mantis2[hidden] { display: none; }
/* Row 0 – idle, 2 frames (cols 0-1) — calm front pose. */
@keyframes mantis2-idle {
  from { background-position: 0 0; }
  to   { background-position: -20.4cqw 0; }
}
/* Row 0 – walk sideways, 8 frames (flip scaleX for left) */
@keyframes mantis2-walk {
  from { background-position: 0 0; }
  to   { background-position: -81.6cqw 0; }
}
/* Trot reuses the row-0 side walk, 8 frames. */
@keyframes mantis2-trot {
  from { background-position: 0 0; }
  to   { background-position: -81.6cqw 0; }
}
/* Row 1 – walk down/front, 6 frames (cols 0-5) */
@keyframes mantis2-walk-down {
  from { background-position: 0 -12.75cqw; }
  to   { background-position: -61.2cqw -12.75cqw; }
}
/* Row 2 – walk up/back, 4 frames (cols 0-3) */
@keyframes mantis2-walk-up {
  from { background-position: 0 -25.5cqw; }
  to   { background-position: -40.8cqw -25.5cqw; }
}
/* Row 2 – plant/dig, 4 frames (cols 4-7) */
@keyframes mantis2-plant {
  from { background-position: -40.8cqw -25.5cqw; }
  to   { background-position: -81.6cqw -25.5cqw; }
}
/* Row 1 – water, 2 frames (cols 6-7) */
@keyframes mantis2-water {
  from { background-position: -61.2cqw -12.75cqw; }
  to   { background-position: -81.6cqw -12.75cqw; }
}

/* Red Panda Farmer — invite-campaign reward. 8×4 sheet, same geometry as the
   panda (cells 176×192): 12cqw × 15cqw, background-size 96cqw 60cqw. Frame
   layout matches the fox/mantis: walk-side 8f (row 0), walk-down 6f + water 2f
   (row 1), walk-up 4f + plant 4f (row 2), idle 2f (row 3, front pose). */
.redpanda2 {
  position: absolute;
  width: 12cqw; height: 15cqw;
  background: url("assets/redpanda-farmer.png?v=2") 0 0 no-repeat;
  background-size: 96cqw 60cqw;
  image-rendering: pixelated;
  pointer-events: auto;
  cursor: pointer;
  z-index: 4;
  opacity: 0;
  display: none;
  transition: opacity 0.45s ease;
  transform: translate(-50%, -85%);
  filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.35));
  will-change: transform, left, top;
}
.redpanda2[hidden] { display: none; }
/* Row 3 – idle, front pose. Col 0 is the empty-handed stand; col 1 has the
   panda holding a sprout (an action pose), so idle rests only on col 0 — an
   idle should show no action. Held static regardless of the steps() count. */
@keyframes redpanda2-idle {
  from { background-position: 0 -45cqw; }
  to   { background-position: 0 -45cqw; }
}
/* Row 0 – walk sideways, 8 frames (flip scaleX for left) */
@keyframes redpanda2-walk {
  from { background-position: 0 0; }
  to   { background-position: -96cqw 0; }
}
/* Trot reuses the row-0 side walk, 8 frames. */
@keyframes redpanda2-trot {
  from { background-position: 0 0; }
  to   { background-position: -96cqw 0; }
}
/* Row 1 – walk down/front, 6 frames (cols 0-5) */
@keyframes redpanda2-walk-down {
  from { background-position: 0 -15cqw; }
  to   { background-position: -72cqw -15cqw; }
}
/* Row 2 – walk up/back, 4 frames (cols 0-3) */
@keyframes redpanda2-walk-up {
  from { background-position: 0 -30cqw; }
  to   { background-position: -48cqw -30cqw; }
}
/* Row 2 – plant/dig, 4 frames (cols 4-7) */
@keyframes redpanda2-plant {
  from { background-position: -48cqw -30cqw; }
  to   { background-position: -96cqw -30cqw; }
}
/* Row 1 – water, 2 frames (cols 6-7) */
@keyframes redpanda2-water {
  from { background-position: -72cqw -15cqw; }
  to   { background-position: -96cqw -15cqw; }
}

/* Active-buff indicator floating over the farm scene (top-left). */
.farm-buffs {
  position: absolute; top: 8px; left: 8px; z-index: 6;
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  pointer-events: none;
}
/* The chips live in their own wrapping row so the breakdown panel can stack
   beneath them. */
.buff-strip {
  display: flex; flex-wrap: wrap; gap: 6px;
  max-width: min(90vw, 360px);
}
.buff-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px 4px 5px; border-radius: 999px;
  background: rgba(38, 26, 12, 0.72); color: #fff7e0;
  font-family: var(--font-display); font-weight: 700; font-size: 12px;
  line-height: 1; white-space: nowrap;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(2px);
  border: 1px solid rgba(255, 214, 121, 0.5);
}
.buff-chip .ico-flower { width: 18px; height: 18px; }
.buff-chip .buff-sep { opacity: 0.5; }
.buff-chip .buff-landings { color: #ffd679; }
/* Panda LE holder-perk chip opens with an emoji, not an icon image, so it
   takes symmetric padding. */
.buff-chip.pandale { padding: 4px 9px; }
/* Greenhouse stake chip: emoji-led like the LE chip, with a green accent. */
.buff-chip.greenhouse { padding: 4px 9px; border-color: rgba(140, 220, 140, 0.6); }
.buff-chip.greenhouse .buff-landings { color: #b8f0a0; }
/* Shrine total-boost chip: moonlit lavender accent. */
.buff-chip.shrine { padding: 4px 9px; border-color: rgba(200, 160, 255, 0.6); }
.buff-chip.shrine .buff-landings { color: #e0c8ff; }
/* Multi-farm daily-cap chip: earthy amber accent (cap scaling, not a boost). */
.buff-chip.farms { padding: 4px 9px; border-color: rgba(230, 180, 110, 0.6); }
.buff-chip.farms .buff-landings { color: #ffcf8a; }
/* Clan Wars prize chip: a martial crimson accent, distinct from the golden dish
   and amber farm chips. */
.buff-chip.clan { padding: 4px 9px; border-color: rgba(240, 130, 130, 0.6); }
.buff-chip.clan .buff-landings { color: #ff9d9d; }
/* Kitchen dish amplifier chip (2× Growth Stake / 2× Shrine): a distinct golden
   accent so the doubling effect reads as its own bonus, not a plain dish buff. */
.buff-chip.amplify { padding: 4px 9px; border-color: rgba(255, 205, 120, 0.75); background: rgba(58, 40, 12, 0.78); }
.buff-chip.amplify .buff-landings { color: #ffe08a; }

/* ---- Total-production summary chip + tap-to-expand breakdown ---------------
   Once the bar is busy (4+ buffs) the production chips fold into this single
   pill; tapping it reveals the full breakdown panel below. Only these two are
   interactive — the rest of the bar stays click-through over the farm art. */
.buff-chip.buff-total {
  pointer-events: auto; cursor: pointer;
  padding: 4px 8px 4px 9px;
  border: 1px solid rgba(255, 224, 150, 0.85);
  background: linear-gradient(135deg, rgba(74, 52, 16, 0.92), rgba(52, 34, 10, 0.92));
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45), inset 0 0 0 1px rgba(255, 224, 150, 0.12);
  transition: transform 0.12s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
.buff-chip.buff-total:active { transform: scale(0.96); }
.buff-chip.buff-total .buff-landings { color: #ffe4a0; }
.buff-chip.buff-total.open {
  border-color: rgba(255, 236, 180, 1);
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.5), 0 0 0 2px rgba(255, 224, 150, 0.28);
}
.buff-chip.buff-total .buff-caret {
  font-size: 9px; opacity: 0.75; margin-left: 1px;
  transition: transform 0.25s ease;
}
.buff-chip.buff-total.open .buff-caret { transform: rotate(180deg); }

.buff-breakdown {
  pointer-events: auto;
  position: fixed; top: 44px; left: 8px; z-index: 60;
  width: min(86vw, 288px);
  border-radius: 14px;
  background: rgba(30, 20, 9, 0.92);
  border: 1px solid rgba(255, 214, 121, 0.4);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  color: #fff7e0;
  /* Collapsed by default; the .open class animates it into view. A freshly
     re-rendered node created already-open skips the transition (no class flip),
     so the live 1s countdown refresh never re-triggers the animation. */
  max-height: 0; opacity: 0; overflow: hidden;
  transform: translateY(-6px);
  transition: max-height 0.3s ease, opacity 0.2s ease, transform 0.3s ease;
}
.buff-breakdown.open {
  max-height: 60vh; opacity: 1; overflow-y: auto;
  transform: none;
}
/* The panel is mounted on <body>; the farm is the only screen with no
   `screen-*` class, so hide it on every other tab (it must not float over the
   shop/kitchen/etc.). */
body[class*="screen-"] #buff-breakdown-portal { display: none !important; }
.buff-breakdown .bd-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 11px 13px 9px;
  font-family: var(--font-display); font-weight: 700; font-size: 12px;
  letter-spacing: 0.02em;
  border-bottom: 1px solid rgba(255, 214, 121, 0.16);
}
.buff-breakdown .bd-head strong { font-size: 16px; color: #ffe4a0; }
.buff-breakdown .bd-list { padding: 5px 7px; display: flex; flex-direction: column; }
.buff-breakdown .bd-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 6px; border-radius: 9px;
  font-size: 12px; line-height: 1;
}
.buff-breakdown .bd-row + .bd-row { margin-top: 1px; }
.buff-breakdown .bd-row:hover { background: rgba(255, 214, 121, 0.07); }
.buff-breakdown .bd-ico { width: 18px; text-align: center; flex: none; }
.buff-breakdown .bd-label {
  flex: 1 1 auto; min-width: 0; font-weight: 600; color: #f3e6c8;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.buff-breakdown .bd-time {
  flex: none; font-size: 10px; font-weight: 700;
  color: #d8c39a; opacity: 0.85; font-variant-numeric: tabular-nums;
}
.buff-breakdown .bd-pct {
  flex: none; font-family: var(--font-display); font-weight: 700;
  color: #ffd679; font-variant-numeric: tabular-nums;
}
.buff-breakdown .bd-sub {
  padding: 8px 13px 3px;
  font-size: 10px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  color: #cbb894; opacity: 0.85;
  border-top: 1px solid rgba(255, 214, 121, 0.14);
  margin-top: 3px;
}

.cell {
  position: absolute;
  margin: 0; padding: 0; border: 0; background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* Per-row depth vs. the BACK decoration layer (decor-back z2): the near (bottom)
   row's plants tuck BEHIND a back-decoration while the far (top/mid) rows sit in
   FRONT of it. The farmer (z8) and the FRONT decoration layer (decor-front z9)
   both render above every plant row, so the character is never hidden behind a
   crop. Raise/lower the whole cell as a unit so its crop (z1) and status tags
   (z2) keep their normal internal order. data-row is set per plot in renderPlots(). */
.cell[data-row="top"]    { z-index: 7; }
.cell[data-row="mid"]    { z-index: 3; }
.cell[data-row="bottom"] { z-index: 1; }
/* The farmer character always walks IN FRONT of the plants: z8 sits above every
   plot-cell row (top is z7). A decoration can still tuck behind it (decor-back
   z2) or overlap it (decor-front z9), and the rain overlay (z10) still falls
   over everything. New farmers copy this list — keep it in sync with the sprite
   classes above. */
.panda2, .shark2, .fox2, .porcupine2, .alligator2,
.bat2, .sheep2, .mantis2, .redpanda2, .pandale2 { z-index: 8; }
.cell.empty:active, .cell.planted:active { filter: brightness(1.08); }

/* dashed hint ring on an empty, plantable plot */
.cell.empty::after {
  content: "";
  position: absolute; left: 50%; bottom: 16%; transform: translateX(-50%);
  width: 52%; aspect-ratio: 1; border-radius: 50%;
  border: 2px dashed rgba(255, 255, 255, 0.85);
  opacity: 0; transition: opacity 0.15s ease;
}
.cell.empty:hover::after, .cell.empty:focus-visible::after { opacity: 0.85; }

.cell.locked { cursor: default; }
.cell.locked::after {
  content: "🔒";
  position: absolute; left: 50%; bottom: 28%; transform: translateX(-50%);
  font-size: max(11px, 3.6cqw); opacity: 0.8;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}

/* The next buyable plot: tappable, with a coin-priced badge instead of a lock. */
.cell.locked.unlockable { cursor: pointer; }
.cell.locked.unlockable::after { content: none; }
.cell-unlock {
  position: absolute; left: 50%; bottom: 20%; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 8px; border-radius: 999px; white-space: nowrap;
  background: rgba(38, 26, 12, 0.78); color: #fff7e0;
  font-family: var(--font-display); font-weight: 700; font-size: max(10px, 3.2cqw);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  transition: transform 0.15s ease;
}
.cell.unlockable:hover .cell-unlock, .cell.unlockable:focus-visible .cell-unlock { transform: translateX(-50%) scale(1.06); }
.cell-unlock-plus { color: #aee37d; font-weight: 800; }
.cell-unlock-cost { display: inline-flex; align-items: center; gap: 3px; }

/* A butterfly-blessed plant (Flower Scent): a soft pulsing glow behind the crop
   marking the 5× NFT drop chance, centred on the tilled square. */
.cell-glow {
  position: absolute; left: 50%; top: 54%; transform: translate(-50%, -50%);
  width: 60%; aspect-ratio: 1; border-radius: 50%;
  pointer-events: none; z-index: 0;
  background: radial-gradient(circle, rgba(255, 214, 121, 0.85) 0%, rgba(247, 160, 224, 0.5) 42%, rgba(247, 160, 224, 0) 70%);
  animation: cell-glow-pulse 1.8s ease-in-out infinite;
}
@keyframes cell-glow-pulse {
  0%, 100% { opacity: 0.55; transform: translate(-50%, -50%) scale(0.92); }
  50%      { opacity: 1;    transform: translate(-50%, -50%) scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
  .cell-glow { animation: none; opacity: 0.7; }
}

.cell-crop-wrap {
  /* Anchor on the plot centre: top:50% + translateY(-82%) puts the point 82%
     down the sprite (the stem base, where the plant meets its soil mound) on
     the centre of the tilled square, so the plant grows from the plot centre. */
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -82%);
  pointer-events: none;
  z-index: 1;
}
.cell-crop-wrap .crop-sprite {
  /* Sprites carry their own soil mound, so size them so the mound covers the
     tilled plot square (mound base ~= plot width) and the plant rises above. */
  --cell: 14cqw;
  display: block;
  transform-origin: 50% 100%;
  filter: drop-shadow(1px 3px 3px rgba(0, 0, 0, 0.28));
}
/* No sway: the sprite includes its soil tile, which shouldn't rock. */
.cell.planted.ready .cell-crop-wrap .crop-sprite { animation: glow 1.4s ease-in-out infinite; }
/* Crops keep full brightness in the night scenes on purpose: dimming them
   (brightness/saturate on the wrap) made the plants read as muddy blobs on
   desktop, and legibility beats scene-matching here. */

.cell-ready {
  position: absolute; top: -4%; left: 50%; transform: translateX(-50%);
  font-size: max(11px, 3.2cqw); pointer-events: none;
  animation: bob 1s ease-in-out infinite;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
}
.cell-tags {
  position: absolute; top: 4%; right: 6%;
  display: flex; gap: 2px; pointer-events: none;
  /* Above .cell-crop-wrap (z-index 1) so the watered/fertilized/blessed
     markers stay visible instead of being hidden behind a tall plant sprite. */
  z-index: 2;
}
.cell-tags i {
  font-style: normal; font-size: max(9px, 2.6cqw);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.45));
}

/* PIX payment QR + copy field (also used by the USDC address field) */
.pix-qr { display: block; width: 200px; height: 200px; margin: 10px auto; image-rendering: pixelated; border-radius: 8px; }
#pix-copy, #crypto-addr { width: 100%; margin-top: 8px; font-size: 12px; padding: 8px; border-radius: 8px; border: 1px solid var(--line, #d9d2c4); background: #fff; }

/* Cell action sheet (reuses the modal root) */
.modal.sheet .sheet-list { display: flex; flex-direction: column; gap: 8px; margin: 6px 0 4px; }
/* A seed row in the plant sheet: "Plant" fills the row, "Plant all" sits beside it. */
.seed-plant-row { display: flex; gap: 6px; align-items: stretch; }
.seed-plant-row .sheet-plant { flex: 1; }
.seed-plant-row .sheet-plant-all { white-space: nowrap; flex: 0 0 auto; }
.seed-plant-row .sheet-plant .muted { color: rgba(255,255,255,0.8); font-size: 13px; }
.modal.sheet .crop-sprite.sheet-ico {
  --cell: 26px; width: 26px; height: 26px; vertical-align: -8px; margin-right: 4px;
}
/* Panda Farmer seed-choice rows — compact so all 5 seeds fit without scrolling */
.seed-choice-row {
  display: flex; align-items: center; gap: 7px;
  padding: 3px 9px; cursor: pointer;
  border-radius: var(--radius-sm); border: 1px solid var(--line-2);
  background: var(--panel-2, rgba(255,255,255,0.45));
  transition: background 0.15s;
}
.seed-choice-row:hover, .seed-choice-row.selected { background: rgba(91,168,69,0.12); border-color: var(--green); }
.seed-choice-row input[type=checkbox] { flex: 0 0 auto; width: 16px; height: 16px; accent-color: var(--green); cursor: pointer; }
.seed-choice-row .seed-label { font-size: 13px; font-weight: 600; color: var(--ink); }
/* "2× harvest" badge next to a farmer's specialization crop in the config sheet. */
.seed-buff-badge {
  display: inline-block; margin-left: 8px; padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 800; white-space: nowrap;
  color: #6b3fa0; background: rgba(185,139,255,0.22); border: 1px solid rgba(185,139,255,0.55);
}
/* Shrink the seed icon too (mini-seed sizes its sprite via --cell). */
.seed-choice-row .mini-seed { --cell: 26px; width: 26px; height: 26px; }
.seed-choice-row .seed-lunar, .seed-choice-row .seed-bag { width: 26px; height: 26px; }
/* Tighter row spacing in the farmer config seed list. */
#modal-root .modal.sheet .sheet-list { gap: 5px; }
/* Auto-action toggles in the Panda Farmer modal */
.panda-toggles { display: flex; flex-direction: column; gap: 8px; margin: 12px 0 0; }
.panda-toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 10px 12px; cursor: pointer; font: inherit; text-align: left;
  border-radius: var(--radius-sm); border: 1px solid var(--line-2);
  background: var(--cream-2); color: var(--ink); transition: all 0.15s;
}
.panda-toggle .pt-label { font-size: 13px; font-weight: 700; }
.panda-toggle .pt-state {
  flex: 0 0 auto; font-size: 12px; font-weight: 800; letter-spacing: 0.5px;
  padding: 3px 10px; border-radius: 999px; background: #e3ddcd; color: var(--ink-soft);
}
.panda-toggle.on { border-color: var(--green); background: rgba(91,168,69,0.12); }
.panda-toggle.on .pt-state { background: var(--green-d); color: #fff; }

.crop-sprite {
  display: inline-block;
  image-rendering: pixelated;
  background-image: url("assets/crops.png?v=11");
  background-repeat: no-repeat;
  width: var(--cell);
  height: var(--cell);
  background-size: calc(var(--cell) * 4) calc(var(--cell) * 4);
  background-position: calc(var(--col, 0) * var(--cell) * -1) calc(var(--row, 0) * var(--cell) * -1);
}
.crop-sprite.sprout { --col: 0; }
.crop-sprite.grow { --col: 1; }
.crop-sprite.almost { --col: 2; }
.crop-sprite.ready { --col: 3; }
.crop-sprite.tomato { --row: 0; }
.crop-sprite.lettuce { --row: 1; }
.crop-sprite.corn { --row: 2; }
.crop-sprite.pumpkin { --row: 3; }
/* Lunar Bloom grows from its own 4-frame strip (not part of crops.png).
   Override to a 4-wide / 1-tall sheet; the stage classes still drive --col. */
.crop-sprite.lunar {
  background-image: url("assets/lunar.png?v=4");
  background-size: calc(var(--cell) * 4) var(--cell);
  --row: 0;
}
/* Profession crops — each its own 4-frame strip (painted art, not pixel). The
   Alchemist's moonpetal reuses the Lunar Bloom strip (it IS a moonbloom). */
.crop-sprite.flower, .crop-sprite.carrot, .crop-sprite.herb, .crop-sprite.moonpetal {
  background-size: calc(var(--cell) * 4) var(--cell);
  image-rendering: auto;
  --row: 0;
}
.crop-sprite.flower   { background-image: url("assets/flower.png?v=2"); }
.crop-sprite.carrot   { background-image: url("assets/carrot.png?v=2"); }
.crop-sprite.herb     { background-image: url("assets/herb.png?v=2"); }
.crop-sprite.moonpetal { background-image: url("assets/lunar.png?v=4"); }

.plot .crop-sprite {
  --cell: 152px;
  position: relative;
  z-index: 2;
  transform-origin: 50% 100%;
  animation: sway 2.4s ease-in-out infinite;
  filter: drop-shadow(3px 6px 4px rgba(0,0,0,0.22));
}
.plot.ready .crop-sprite { animation: sway 2.4s ease-in-out infinite, glow 1.1s ease-in-out infinite; }

.empty-plot {
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  gap: 6px;
  margin-bottom: 18px;
  text-align: center;
}
.empty-plot .dig {
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center; font-size: 22px;
  background: rgba(255,255,255,0.7);
  border: 1px dashed var(--line-2);
}
.empty-plot span { font-size: 11px; font-weight: 800; color: var(--brown-d); text-transform: uppercase; letter-spacing: 0.5px; }

.plot-tags {
  position: absolute; z-index: 3; top: 8px; left: 8px;
  display: flex; gap: 5px;
}
.tag {
  display: grid; place-items: center;
  width: 27px; height: 27px; font-size: 14px;
  border-radius: 9px;
  background: rgba(255,255,255,0.92);
  border: 1px solid var(--line-2);
  box-shadow: var(--shadow-sm);
}

.ready-flag {
  position: absolute; z-index: 3; top: 9px; right: 9px;
  font-family: var(--font-display); font-weight: 600; font-size: 11px;
  padding: 4px 9px; border-radius: 999px; color: #5a3d0a;
  background: linear-gradient(180deg, #ffd86b, var(--gold-d));
  box-shadow: var(--shadow-sm);
  animation: bob 1s ease-in-out infinite;
}

.plot-footer {
  position: relative;
  z-index: 3;
  display: grid;
  gap: 9px;
  padding: 11px 12px 12px;
  background: var(--panel);
  border-top: 1px solid var(--line);
}
.plot-name { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.plot-name strong { font-family: var(--font-display); font-weight: 600; font-size: 15px; }
.plot-name .timer { font-size: 11.5px; font-weight: 800; color: var(--muted); }

.bar {
  height: 10px; border-radius: 999px;
  background: #e8dcbf; overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.12);
}
.bar i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--green-l), var(--green)); transition: width 0.5s ease; }

.plot-actions { display: flex; flex-wrap: wrap; gap: 7px; }
.plot-actions .btn { flex: 1 1 auto; }
.plot-actions.single .btn { flex: 1 1 100%; }

/* ---------------- Side panel ---------------- */
.col-panel { padding: 0; overflow: hidden; align-self: start; }

.tabs {
  display: grid;
  /* Auto-fit one column per (visible) tab so adding/removing tabs — including the
     DEV-only Greenhouse — never wraps to a second row. */
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 4px;
  padding: 8px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--line);
}
.tab {
  appearance: none;
  border: none;
  background: transparent;
  border-radius: var(--radius-xs);
  padding: 8px 2px 6px;
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: 10.5px;
  color: var(--ink-soft);
  cursor: pointer;
  display: grid;
  justify-items: center;
  gap: 3px;
  min-width: 0; /* let the label truncate instead of forcing the track wider */
  transition: background 0.15s ease, color 0.15s ease, transform 0.1s ease;
}
.tab span { font-size: 11px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tab:hover { background: rgba(255,255,255,0.6); }
.tab.active { background: #fff; color: var(--green-d); box-shadow: var(--shadow-sm); }

.tab-panel { display: none; padding: 14px; animation: fade 0.25s ease; }

/* Sub-tabs inside a panel (NFTs / Marketplace: Plant vs Ingredients). A pill
   segmented control that filters the list below without leaving the tab. */
.subtabs {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: 6px; margin-bottom: 12px;
  background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px;
}
.subtab {
  appearance: none; border: none; background: transparent; cursor: pointer;
  border-radius: 999px; padding: 7px 5px;
  font-family: var(--font-ui); font-weight: 800; font-size: 11px; letter-spacing: -0.2px;
  color: var(--ink-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: background 0.15s ease, color 0.15s ease;
}
.subtab:hover { background: rgba(255,255,255,0.5); }
.subtab.active { background: #fff; color: var(--green-d); box-shadow: var(--shadow-sm); }
/* On the translucent NFT/market art panels the segmented control reads as glass. */
body.v2.screen-nfts .subtabs, body.v2.screen-market .subtabs {
  background: rgba(14, 22, 32, 0.5); border-color: rgba(150, 200, 255, 0.28);
}
body.v2.screen-nfts .subtab, body.v2.screen-market .subtab { color: #cdd9e8; }
body.v2.screen-nfts .subtab.active, body.v2.screen-market .subtab.active { color: var(--green-d); background: #eef4ff; }
.tab-panel.active { display: block; }
/* .tab / .nav-item set an explicit display, which beats the UA [hidden] rule —
   so a hidden tab/nav entry (e.g. the DEV-only Greenhouse) needs this override. */
.tab[hidden], .nav-item[hidden] { display: none !important; }

.list { display: grid; gap: 9px; }

.row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 10px 11px;
  background: var(--cream-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.1s ease;
}
.row:hover { transform: translateY(-1px); border-color: var(--line-2); }
.row.selected { border-color: var(--green); background: #eefbe2; box-shadow: 0 0 0 2px rgba(91,168,69,0.25); }
/* The player's own row in the individual leaderboard. */
.row.rank-mine { border-color: var(--green); background: #eefbe2; box-shadow: 0 0 0 2px rgba(91,168,69,0.25); }

.row-main { min-width: 0; }
.row-title { display: flex; align-items: center; gap: 9px; font-family: var(--font-display); font-weight: 600; font-size: 14.5px; margin-bottom: 2px; }
.row-title span.name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-meta { font-size: 11.5px; font-weight: 700; color: var(--muted); line-height: 1.35; }

/* Lunar Bloom hold-gate: per-mutant checklist on the locked seed card. */
.mutant-reqs { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.mutant-req {
  font-size: 10.5px; font-weight: 800; line-height: 1;
  padding: 3px 6px; border-radius: 999px; white-space: nowrap;
}
.mutant-req.have { background: rgba(91, 168, 69, 0.16); color: var(--green-d); }
.mutant-req.missing { background: rgba(0, 0, 0, 0.06); color: var(--muted); }
.row-side { display: grid; gap: 6px; justify-items: end; }
.price { font-family: var(--font-display); font-weight: 600; font-size: 13px; color: var(--brown-d); }

/* Bulk-list toolbar + selection (NFTs tab). */
.bulk-bar { margin: 0 0 8px; }
.bulk-bar-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Farm Kitchen: the recipe card's action strip (cook / truffle / eat / NFT). */
.kitchen-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
/* The recipe ingredient line wraps its per-veggie chips instead of one long
   run-on, so the small illustrations line up next to their counts. */
.kitchen-needs { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }
.kitchen-needs .need { display: inline-flex; align-items: center; gap: 3px; }
/* Always-visible "what it costs to craft this Ingredient NFT" line: 10 units of
   the ingredient + 1 Moonbloom Essence, with live have/need counts. */
.kitchen-recipe-note { margin-top: 6px; font-size: 0.82rem; opacity: 0.9; }
.kitchen-recipe-note .ok { color: #6fe08a; opacity: 1; }
.kitchen-recipe-note .muted { color: #ff9a9a; opacity: 0.9; }
/* "❔ Help" chip in the Pantry section head — pinned to the far right, next to
   the "made by professions" pill. Opens the Ingredient NFT how-to popup. */
.section-head .help-btn { margin-left: auto; flex: 0 0 auto; }
/* Numbered how-to popup for the Ingredient NFT life cycle. */
.help-sheet { text-align: left; }
.help-steps { margin: 10px 0 16px; padding-left: 20px; display: flex; flex-direction: column; gap: 10px; }
.help-steps li { line-height: 1.4; font-size: 0.9rem; }
.help-sheet .help-section { margin: 14px 0 2px; font-size: 1rem; font-weight: 800; }
.help-sheet .help-section:first-of-type { margin-top: 8px; }
/* Tab strip at the top of the help popup (How to play / Tokenomics). */
.help-tabs { display: flex; gap: 6px; margin-bottom: 4px; }
.help-tab {
  flex: 1; padding: 8px 10px; border-radius: 10px 10px 0 0;
  border: 1px solid var(--line-2); border-bottom: none;
  background: var(--cream-2, rgba(255, 255, 255, 0.5));
  font: inherit; font-weight: 700; font-size: 0.9rem; color: inherit;
  cursor: pointer; opacity: 0.6;
}
.help-tab.active { opacity: 1; background: var(--gold); color: #4a3208; }
.help-tabpane[hidden] { display: none; }
.help-tabpane { border-top: 2px solid var(--gold); padding-top: 8px; }
/* Original (pre-discount) material count, struck through when a specialization
   tool is active and the reduced amount is shown right after it. */
.cost-was { opacity: 0.5; margin-right: 2px; text-decoration: line-through; }

/* Painted veggie & truffle illustrations (not pixel art — smooth scaling). */
.veg-ico {
  display: inline-block;
  width: 34px; height: 34px;
  background: center / contain no-repeat;
  vertical-align: middle;
}
.veg-ico.sm { width: 18px; height: 18px; }
.veg-ico.thumb { width: 42px; height: 42px; }
.veg-ico.tomato  { background-image: url("assets/veggie-tomato.png?v=1"); }
.veg-ico.corn    { background-image: url("assets/veggie-corn.png?v=1"); }
.veg-ico.lettuce { background-image: url("assets/veggie-lettuce.png?v=1"); }
.veg-ico.pumpkin { background-image: url("assets/veggie-pumpkin.png?v=1"); }
.veg-ico.truffle { background-image: url("assets/ingredient-truffle.png?v=1"); }
.veg-ico.honey   { background-image: url("assets/ingredient-honey.png?v=1"); }
.veg-ico.spices  { background-image: url("assets/ingredient-spices.png?v=1"); }
.veg-ico.essence { background-image: url("assets/ingredient-essence.png?v=1"); }
.veg-ico.floweritem { background-image: url("assets/flower-item.png?v=1"); }
.veg-ico.carrot  { background-image: url("assets/ingredient-carrot.png?v=1"); }
.veg-ico.herb    { background-image: url("assets/ingredient-herb.png?v=1"); }
.veg-ico.moonpetal { background-image: url("assets/ingredient-moonpetal.png?v=1"); }

/* Painted dish icons (cooked dishes). */
.dish-ico {
  display: inline-block; width: 42px; height: 42px;
  background: center / contain no-repeat; vertical-align: middle;
}
.dish-ico.farmers_salad { background-image: url("assets/dish-farmers_salad.png?v=1"); }
.dish-ico.harvest_stew  { background-image: url("assets/dish-harvest_stew.png?v=1"); }
.dish-ico.lucky_pie     { background-image: url("assets/dish-lucky_pie.png?v=1"); }
.dish-ico.clan_banquet  { background-image: url("assets/dish-clan_banquet.png?v=1"); }

/* Painted specialization badges (assets/spec-<id>.png) — the profession picker
   icons: circular emblems, transparent, one uniform size. */
.spec-ico {
  display: inline-block; flex: 0 0 auto;
  width: 46px; height: 46px;
  background: center / contain no-repeat;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.4));
}
.spec-ico.beekeeper      { background-image: url("assets/spec-beekeeper.png?v=1"); }
.spec-ico.truffle_hunter { background-image: url("assets/spec-truffle_hunter.png?v=1"); }
.spec-ico.herbalist      { background-image: url("assets/spec-herbalist.png?v=1"); }
.spec-ico.alchemist      { background-image: url("assets/spec-alchemist.png?v=1"); }
/* Small inline variant for the collapsed Specializations header pill. */
.spec-ico.sheet-ico { width: 22px; height: 22px; vertical-align: -6px; filter: none; margin-right: 2px; }

/* Beekeeper Apiary panel. */
.apiary-hero {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 10px;
  min-height: 72px; margin-bottom: 8px; padding: 6px 12px; border-radius: 14px;
  background: linear-gradient(180deg, rgba(60,42,16,0.15), rgba(60,42,16,0.55));
  box-shadow: inset 0 -2px 10px rgba(0,0,0,0.25);
}
.ws-share-spec { flex: 0 0 auto; }
.apiary-title { font-family: 'Fredoka', sans-serif; font-weight: 700; font-size: 22px; color: #fff; text-shadow: 0 2px 6px rgba(0,0,0,0.6); }

/* Workshop 3-level evolution bar (DEV). Sits under the hero, on the same dark
   glass as the other Workshop cards. */
.ws-progress {
  margin-bottom: 10px; padding: 10px 12px; border-radius: 12px;
  background: rgba(30,22,10,0.66);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  color: #f3ead4;
}
.ws-prog-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.ws-prog-title { font-family: 'Fredoka', sans-serif; font-weight: 600; font-size: 15px; }
.ws-prog-title b { color: var(--gold); }
.ws-prog-xp { font-size: 12px; }
.ws-prog-track { display: flex; gap: 5px; }
.ws-prog-seg {
  flex: 1 1 0; height: 12px; border-radius: 6px; overflow: hidden;
  background: rgba(255,255,255,0.14);
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.35);
}
.ws-prog-seg > span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, #f5c542, #ffe38a);
  border-radius: 6px; transition: width 0.4s ease;
}
.ws-prog-seg.done > span { background: linear-gradient(90deg, #8ad06a, #b6e79a); }
.ws-prog-note { margin-top: 7px; font-size: 11px; line-height: 1.4; }
.ws-prog-unlocks { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; }
.ws-unlock-chip {
  font-size: 11px; padding: 3px 8px; border-radius: 999px;
  background: rgba(255,255,255,0.10); color: #e9dcc0;
  border: 1px solid rgba(255,255,255,0.12);
}
.ws-unlock-chip.on {
  background: rgba(138,208,106,0.22); color: #dff5cf;
  border-color: rgba(138,208,106,0.5);
}
.apiary-foot {
  margin-top: 10px; font-size: 12px; line-height: 1.4;
  color: #f3ead4; background: rgba(30,22,10,0.66);
  padding: 8px 10px; border-radius: 10px;
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
/* Cook premium toggles (Truffle / Essence) — tick either or both before cooking. */
.kitchen-toggles { display: flex; flex-wrap: wrap; gap: 10px; margin: 4px 0 2px; }
.cook-toggle { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; cursor: pointer; }
.cook-toggle.muted { opacity: 0.5; cursor: not-allowed; }
.cook-toggle input { accent-color: #e0a83a; }

/* Workshop preview: the "confirm to unlock" gate shown while exploring a
   profession you haven't committed to. Sits above the (locked) tools. */
.ws-preview-bar {
  border: 1px solid rgba(240,196,72,0.55);
  background: linear-gradient(180deg, rgba(60,48,16,0.72), rgba(40,30,10,0.82));
}
.ws-preview-bar .kitchen-actions { margin-top: 8px; }
/* The player's current profession in the picker list. */
.prof-row.prof-current { outline: 1px solid rgba(240,196,72,0.5); border-radius: 12px; }

/* Collapsible Specializations card (top of the Kitchen). The header is a full-
   width toggle; the body only renders when expanded. */
.spec-card.collapsed { padding-bottom: 0; }
.spec-head {
  appearance: none; border: none; background: transparent; cursor: pointer;
  width: 100%; display: flex; align-items: center; gap: 8px;
  padding: 2px 0; text-align: left; color: inherit;
}
.spec-title { font-family: 'Fredoka', sans-serif; font-weight: 700; font-size: 15px; }
.spec-head .pill { margin-left: 2px; }
.spec-chevron { margin-left: auto; font-size: 13px; opacity: 0.8; }
/* Highlighted "+" on the minimized card so players notice it can be opened. */
.spec-plus {
  margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: linear-gradient(180deg, #ffd24d, #f0a815);
  color: #3a2a08; font-weight: 800; font-size: 18px; line-height: 1;
  box-shadow: 0 0 0 0 rgba(240,196,72,0.55);
  animation: spec-plus-pulse 1.6s ease-in-out infinite;
}
@keyframes spec-plus-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(240,196,72,0.55); transform: scale(1); }
  50%      { box-shadow: 0 0 0 7px rgba(240,196,72,0); transform: scale(1.1); }
}
@media (prefers-reduced-motion: reduce) { .spec-plus { animation: none; } }
.spec-body { margin-top: 10px; }

/* On the pale icon-chip (pantry/bag rows) the illustration fills the chip. */
.icon-chip .veg-ico { width: 30px; height: 30px; }

.bulk-bar-spacer { flex: 1 1 auto; }
.bulk-check { min-width: 40px; font-size: 15px; line-height: 1; }
.nft-row.bulk-eligible { cursor: pointer; }
.nft-row.bulk-locked { opacity: 0.55; }

/* Big collections freeze the NFTs (and Marketplace) tab on open. The whole list
   is built up front — even while the panel is hidden — so the moment it flips to
   visible the browser lays out and paints every row and decodes every large card
   PNG at once. On a phone with a few hundred NFTs that's a multi-second main-
   thread stall ("game freezes when I open the NFT tab"). content-visibility lets
   the browser skip rendering rows that aren't on screen, so the work scales with
   the viewport instead of the collection size; contain-intrinsic-size supplies a
   placeholder height (~one row) so the scrollbar and the poll's scroll-restore
   stay accurate for the rows that haven't been rendered yet. */
#nft-list > .row,
#market-list > .row {
  content-visibility: auto;
  contain-intrinsic-size: auto 72px;
}

/* Bulk-buy quantity stepper (shop rows + cash-booster modal). */
.qty-stepper {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  background: #fff;
  overflow: hidden;
}
.qty-stepper button {
  width: 30px;
  height: 30px;
  border: 0;
  background: var(--panel-2);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}
.qty-stepper button:active { background: var(--gold); }
.qty-stepper .qty-val {
  width: 44px;
  min-width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: #fff;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  -moz-appearance: textfield;
  appearance: textfield;
}
.qty-stepper .qty-val:focus {
  outline: none;
  background: var(--panel-2);
}
.qty-stepper .qty-val::-webkit-outer-spin-button,
.qty-stepper .qty-val::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.qty-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 6px 0 2px;
  font-weight: 700;
  color: var(--ink-soft);
}

.thumb {
  flex: 0 0 auto;
  border-radius: var(--radius-xs);
  border: 1px solid var(--line-2);
  /* background-color (not the `background` shorthand) so it tints behind the
     thumbnail without wiping the crop sprite's background-image. */
  background-color: #f3ead0;
  box-shadow: var(--shadow-sm);
}
.mini-seed { --cell: 34px; width: 34px; height: 34px; }
/* Lunar Bloom seed-pouch icon (hides the Moonbloom NFT until harvest). */
.seed-lunar {
  display: inline-block;
  width: 34px; height: 34px;
  background: center / contain no-repeat url("assets/seed-lunar.png?v=2");
  image-rendering: pixelated;
}
.seed-lunar.sheet-ico { width: 26px; height: 26px; vertical-align: -8px; margin-right: 4px; }
.seed-lunar.locked {
  display: grid; place-items: center; font-size: 16px;
  filter: grayscale(0.7) brightness(0.65);
}
/* The Alchemist's "Enhanced Lunar Seed" — its own painted icon (not pixel art). */
.seed-enhanced-lunar {
  display: inline-block;
  width: 34px; height: 34px;
  background: center / contain no-repeat url("assets/enhanced-lunar-seed.png?v=1");
}
.seed-enhanced-lunar.mini { width: 22px; height: 22px; vertical-align: -5px; }
.seed-enhanced-lunar.sheet-ico { width: 26px; height: 26px; vertical-align: -8px; margin-right: 4px; }
.seed-enhanced-lunar.mini-seed { width: 34px; height: 34px; }
.icon-chip {
  width: 34px; height: 34px; display: grid; place-items: center; font-size: 18px;
  background: linear-gradient(180deg, #eaf7d8, #d6efb6);
}
/* Painted seed-pouch thumbnails (assets/seedbag-<id>.png). Transparent, no
   frame, one uniform size across the shop, bag and pickers. */
.seed-bag {
  display: inline-block; flex: 0 0 auto;
  width: 46px; height: 46px;
  background: center / contain no-repeat;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,0.35));
}
.seed-bag.tomato    { background-image: url("assets/seedbag-tomato.png?v=1"); }
.seed-bag.lettuce   { background-image: url("assets/seedbag-lettuce.png?v=1"); }
.seed-bag.corn      { background-image: url("assets/seedbag-corn.png?v=1"); }
.seed-bag.pumpkin   { background-image: url("assets/seedbag-pumpkin.png?v=1"); }
.seed-bag.flower    { background-image: url("assets/seedbag-flower.png?v=1"); }
.seed-bag.carrot    { background-image: url("assets/seedbag-carrot.png?v=1"); }
.seed-bag.herb      { background-image: url("assets/seedbag-herb.png?v=1"); }
.seed-bag.moonpetal { background-image: url("assets/seedbag-moonpetal.png?v=1"); }
.seed-bag.sheet-ico { width: 30px; height: 30px; vertical-align: -9px; margin-right: 5px; filter: none; }
/* Front-facing farmer portraits used as the shop thumbnails: the idle frame
   cropped from the 8×4 sprite sheet (176×192 cells, ~0.917 aspect kept so the
   crop isn't squished). Idle sits on row 3 — col 0 for shark/fox/porcupine/
   alligator/bat, col 4 for the panda sheet. */
.farmer-ico {
  width: 31px; height: 34px;
  background-repeat: no-repeat;
  background-size: 800% 400%;
  image-rendering: pixelated;
}
.panda-ico     { background-image: url("assets/panda-farmer.png?v=14");     background-position: 0% 33.333%; }
.shark-ico     { background-image: url("assets/shark-farmer.png?v=2");     background-position: 0% 100%; }
.fox-ico       { background-image: url("assets/fox-farmer.png?v=10");       background-position: 0% 100%; }
.porcupine-ico { background-image: url("assets/porcupine-farmer.png?v=2"); background-position: 0% 100%; }
.alligator-ico { background-image: url("assets/alligator-farmer.png?v=5"); background-position: 0% 100%; }
/* Row-0 col-0 (closed-mouth front pose) and rendered smaller — the bat art is
   drawn larger than the other farmers, so it would otherwise loom in the chip. */
.bat-ico       { background-image: url("assets/bat-farmer.png?v=4");       background-position: 0% 0%; width: 26px; height: 29px; }
/* Row-0 col-0 (closed-mouth front pose) and rendered smaller — like the bat, the
   sheep art is drawn larger than the standard farmers, so it shrinks in the chip. */
.sheep-ico     { background-image: url("assets/sheep-farmer.png?v=2");     background-position: 0% 0%; width: 27px; height: 29px; }
/* Row-0 col-0 (front pose) and rendered smaller — like the bat/sheep, the mantis
   art is drawn larger than the standard farmers, so it shrinks in the chip. */
.mantis-ico    { background-image: url("assets/mantis-farmer.png?v=2");    background-position: 0% 0%; width: 27px; height: 29px; }
/* Red Panda chip — Row 1 col 0 (front stand) of the 8×4 sheet. */
.redpanda-ico  { background-image: url("assets/redpanda-farmer.png?v=2");  background-position: 0% 33.333%; }
/* Panda Farmer LE chip — Row 1 col 3 (front stand) of the LE sheet. */
.pandale-ico   { background-image: url("assets/panda-farmer-le.png?v=5");   background-position: 42.857% 33.333%; }

/* Grouped farmer shop card: top line = selectable icon strip (left) + buy/activate
   button (right); the selected farmer's name + blurb sit on the line below. */
.farmer-shop-row { display: block; }
.farmer-nft-note { color: #d4af37; margin-top: 3px; }
.farmer-buff-note { color: #b98bff; margin-top: 3px; font-weight: 600; }
.farmer-shop-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
}
.farmer-shop-head .row-side { flex: 0 0 auto; }
.farmer-picks { display: flex; flex-wrap: wrap; gap: 6px; align-content: center; }
.farmer-pick {
  display: grid; place-items: center;
  width: 38px; height: 38px; padding: 0;
  border: 1px solid var(--line-2); border-radius: var(--radius-xs);
  background: linear-gradient(180deg, #eaf7d8, #d6efb6);
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
.farmer-pick:hover { transform: translateY(-1px); border-color: var(--green); }
.farmer-pick.selected { border-color: var(--green); box-shadow: 0 0 0 2px rgba(91, 168, 69, 0.3); }
/* The painted booster medallion fills the chip rather than sitting small in it. */
.icon-chip .ico-booster-breeding { width: 32px; height: 32px; vertical-align: middle; }
.icon-chip .ico-flower { width: 32px; height: 32px; vertical-align: middle; }
.icon-chip .ico-scarecrow { width: 30px; height: 30px; vertical-align: middle; }

/* ── Uniform, frameless item thumbnails (bag & shop item rows) ──────────────
   Every item icon inside a .row-title renders at one size (46px) with no frame:
   transparent painted art with a soft drop-shadow, matching the seed pouches.
   This strips the old pale "moldura" — the .thumb border and the .icon-chip
   gradient box — so boosters, ingredients, the scarecrow and perishable veggies
   all line up like the seeds. Inline icons elsewhere (kitchen needs, pickers)
   keep their own sizes because they're not in a .row-title. */
.row-title .thumb,
.row-title .icon-chip {
  width: 46px; height: 46px;
  border: 0; border-radius: 0;
  box-shadow: none;
  display: grid; place-items: center;
  font-size: 30px; /* emoji fallbacks (🧂 / 🍽️ / 🌱) scale up too */
}
/* Drop only the frame tint from a .thumb icon — never its own background-image
   (the perishable veggie rows put .thumb straight on the painted .veg-ico). */
.row-title .thumb { background-color: transparent; }
/* .icon-chip is always a wrapper, so wiping its gradient box is safe. */
.row-title .icon-chip { background: none; }
.row-title .seed-bag,
.row-title .veg-ico,
.row-title .dish-ico,
.row-title .seed-lunar,
.row-title .seed-enhanced-lunar,
.row-title .mini-seed { width: 46px; height: 46px; }
.row-title .mini-seed { --cell: 46px; }
/* Painted icons that used to sit small inside the chip now fill the slot.
   Den treasures (img.den-ico) default to 26px inside a chip; in a bag/shop row
   they scale up to match the other item art so they don't look tiny. */
.row-title .icon-chip .ico-img,
.row-title .icon-chip .veg-ico,
.row-title .icon-chip img.den-ico { width: 40px; height: 40px; }
/* Den treasures fill the full 46px slot (like the seed bags) so their detailed
   art reads clearly and sits proportional to the other bag items. */
.row-title .icon-chip img.den-ico { width: 46px; height: 46px; }
/* Consistent soft depth cue across all painted item art (seed-bag already has
   its own; this covers the rest). */
.row-title .veg-ico,
.row-title .dish-ico,
.row-title .icon-chip .ico-img,
.row-title .icon-chip img.den-ico { filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35)); }
.nft-art {
  width: 50px; height: 50px;
  /* painted illustrations (not pixel art) — smooth scaling, no pixelation */
  background: #241a3a center / contain no-repeat;
}
.nft-art.tomato.rare { background-image: url("assets/nft-tomato-rare.png?v=2"); }
.nft-art.tomato.epic { background-image: url("assets/nft-tomato-epic.png?v=2"); }
.nft-art.tomato.mythic { background-image: url("assets/nft-tomato-mythic.png?v=2"); }
.nft-art.lettuce.rare { background-image: url("assets/nft-lettuce-rare.png?v=2"); }
.nft-art.lettuce.epic { background-image: url("assets/nft-lettuce-epic.png?v=2"); }
.nft-art.lettuce.mythic { background-image: url("assets/nft-lettuce-mythic.png?v=2"); }
.nft-art.corn.rare { background-image: url("assets/nft-corn-rare.png?v=2"); }
.nft-art.corn.epic { background-image: url("assets/nft-corn-epic.png?v=2"); }
.nft-art.corn.mythic { background-image: url("assets/nft-corn-mythic.png?v=2"); }
.nft-art.pumpkin.rare { background-image: url("assets/nft-pumpkin-rare.png?v=2"); }
.nft-art.pumpkin.epic { background-image: url("assets/nft-pumpkin-epic.png?v=2"); }
.nft-art.pumpkin.mythic { background-image: url("assets/nft-pumpkin-mythic.png?v=2"); }
.mutant-art {
  width: 50px; height: 50px;
  /* painted illustrations (not pixel art) — smooth scaling, no pixelation */
  background: #1d1536 center / contain no-repeat;
  animation: glow 1.6s ease-in-out infinite;
}
.mutant-art.golden_corn { background-image: url("assets/mutant-1.png?v=4"); }
.mutant-art.lunar_pumpkin { background-image: url("assets/mutant-2.png?v=4"); }
.mutant-art.tomettuce { background-image: url("assets/mutant-3.png?v=4"); }
.mutant-art.cornpkin { background-image: url("assets/mutant-4.png?v=4"); }
/* Moonbloom (legendary) */
.mutant-art.moonbloom { background-image: url("assets/moonbloom.png?v=2"); }
.mutant-art.moonbloom.sm { width: 34px; height: 34px; border-radius: var(--radius-xs); }
.mutant-art.moonbloom.locked {
  background: #2a2540; background-image: none;
  display: grid; place-items: center; font-size: 18px;
}

.rarity {
  display: inline-block; font-size: 10px; font-weight: 800; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; letter-spacing: 0.4px;
}
.rarity.common { background: #ece3cf; color: #7a6f53; }
.rarity.uncommon { background: #d9eecb; color: #4f7d38; }
.rarity.rare { background: #cfe6fb; color: #2f6ca3; }
.rarity.epic { background: #e7d6fb; color: #6d3fb0; }
.rarity.mythic { background: linear-gradient(90deg, #ffe0a3, #f5b0e0); color: #8a3d7a; }
.rarity.mutant { background: linear-gradient(90deg, #c6f6d5, #9ae6e0); color: #1f6b5c; box-shadow: 0 0 0 1px rgba(34, 160, 130, 0.3); }
.rarity.legendary { background: linear-gradient(90deg, #c8b6ff, #ffd98e, #a0e9ff); color: #4b2e83; box-shadow: 0 0 0 1px rgba(120, 80, 200, 0.3); }

.empty-state { text-align: center; color: var(--muted); font-weight: 700; font-size: 13px; padding: 22px 10px; }
.empty-state .ico { font-size: 30px; display: block; margin-bottom: 6px; opacity: 0.8; }

/* ---------------- Bottom nav (mobile) ---------------- */
.bottom-nav { display: none; }

/* ---------------- Modal ---------------- */
#modal-root {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  padding: 20px;
  background: rgba(40, 30, 15, 0.5);
  backdrop-filter: blur(3px);
  animation: fade 0.2s ease;
}
#modal-root[hidden] { display: none; }
.modal {
  width: min(380px, 100%);
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: var(--panel);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 20px;
  animation: pop-in 0.25s ease;
}
.modal h3 { font-family: var(--font-display); font-weight: 700; font-size: 19px; margin-bottom: 6px; }
.modal p { font-size: 13px; color: var(--ink-soft); font-weight: 700; margin-bottom: 14px; }
.modal input {
  width: 100%; padding: 12px 14px; font-family: var(--font-ui); font-weight: 800; font-size: 15px;
  border: 1px solid var(--line-2); border-radius: var(--radius-sm); background: #fff; color: var(--ink);
  margin-bottom: 14px;
}
.modal input:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px rgba(91,168,69,0.2); }
/* Wallet-login gate nickname field: grouped with the "Connect Wallet" button
   below it (own margins keep it clear of the Telegram button above). */
.walletgate-nick { margin-top: 14px; margin-bottom: 8px; text-align: center; }

/* "Your rank" card: the player's display name + an Edit button, so wallet-login
   players (who start as "Player") can pick an identity shown in ranks/clans. */
.rank-name-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 10px; }
.rank-name { font-weight: 800; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-name-row .btn { flex: none; }

/* Always-visible identity button in the top HUD (👤): opens the rename modal on
   tap. Kept icon-only and the same footprint as the sound/info buttons so it
   never widens the crowded HUD into an extra wrapped row (which would overlap
   the boost-chip band below it). The name itself is shown inside the modal. */
.modal-actions { display: flex; gap: 10px; }
.modal-actions .btn { flex: 1; }

/* Share picker: one brag + a 2×2 grid of networks (Telegram / WhatsApp / X /
   Copy). Every shareable moment routes through this so the channel list and
   look stay in one place. */
.modal-share .share-brag {
  margin: 2px 0 12px; font-size: .9rem; color: var(--muted);
}
.share-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 10px;
}
.btn-share {
  color: #fff; border: 0; font-weight: 700;
}
.btn-share.tg   { background: #229ED9; }
.btn-share.wa   { background: #25D366; }
.btn-share.x    { background: #111; }
.btn-share.copy { background: #6b7280; }
.btn-share.photo { background: #7c3aed; margin-bottom: 10px; }

/* "Share my farm" photo: a HUD-free snapshot of the field, rendered client-side
   (see captureFarmPhotoBlob). Shown above the channel grid; the preview frame
   holds a 1:1 slot so the sheet doesn't jump when the image arrives. */
.share-photo { margin: 2px 0 12px; }
.share-photo-frame {
  position: relative; width: 100%; aspect-ratio: 1 / 1;
  border-radius: var(--radius); overflow: hidden;
  background: rgba(0, 0, 0, 0.06); border: 1px solid var(--line-2);
  display: flex; align-items: center; justify-content: center;
}
.share-photo-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.share-photo-spin { font-size: 2rem; animation: spin-slow 1.4s linear infinite; }
.share-photo[data-state="error"] .share-photo-frame { display: none; }
.share-photo-note {
  margin: 8px 0 0; font-size: .82rem; color: var(--muted); text-align: center;
}
@keyframes spin-slow { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .share-photo-spin { animation: none; }
}

/* NFT artwork lightbox: tap the list thumbnail to view it full size. */
.nft-art-trigger {
  /* inline-flex so the sprite span stays a flex item and keeps its 50px box —
     plain inline spans ignore width/height and would collapse to nothing. */
  display: inline-flex; flex: 0 0 auto;
  padding: 0; border: 0; background: none; cursor: zoom-in; line-height: 0;
  border-radius: var(--radius-xs);
}
.nft-art-trigger:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(91,168,69,0.35); }
/* List icon as a mini collectible card. */
.nft-thumb-card {
  width: 50px; height: 50px; object-fit: cover; display: block;
  border-radius: var(--radius-xs);
}
.modal-art {
  width: auto; max-width: min(380px, 92vw); padding: 16px;
  display: grid; justify-items: center; gap: 8px; position: relative;
  text-align: center;
}
.modal-art h3 { margin: 4px 0 0; }
.art-meta { font-size: 13px; color: var(--ink-soft); font-weight: 700; }
.art-close {
  position: absolute; top: 10px; right: 10px; z-index: 1;
  width: 32px; height: 32px; border-radius: 999px; border: 0; cursor: pointer;
  background: var(--panel); box-shadow: var(--shadow-sm); color: var(--ink);
  font-size: 15px; line-height: 1;
}
.nft-art.art-lg, .mutant-art.art-lg {
  width: min(256px, 64vw); height: min(256px, 64vw);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
/* Full collectible card (square artwork with name + rarity baked in). */
.nft-card-img {
  width: min(340px, 84vw); height: auto; display: block;
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}

/* ---------------- Toast ---------------- */
#toast {
  position: fixed; left: 50%; bottom: calc(20px + env(safe-area-inset-bottom));
  transform: translateX(-50%) translateY(8px);
  z-index: 90;
  /* Purely informational: it sits above the bottom nav, so it must never
     swallow taps meant for the buttons beneath it (it lingers ~3s after every
     action, which otherwise dead-zones the center nav buttons mid-session). */
  pointer-events: none;
  display: flex; align-items: center; gap: 9px;
  width: min(440px, calc(100vw - 28px));
  padding: 12px 16px;
  background: #36431f;
  color: #fff7e6;
  font-weight: 800; font-size: 13.5px;
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
#toast.error { background: #7d3326; }
#toast .t-ico { font-size: 17px; }
/* Persistent toast: stays until its X is tapped, so it must accept taps
   (the default toast is deliberately tap-through). Leave room for the X. */
#toast.persistent { pointer-events: auto; padding-right: 12px; }
#toast .t-close {
  flex: 0 0 auto; margin-left: auto;
  width: 26px; height: 26px; padding: 0;
  display: grid; place-items: center;
  border: none; border-radius: 8px;
  background: rgba(255, 255, 255, 0.14); color: inherit;
  font-size: 14px; font-weight: 800; line-height: 1; cursor: pointer;
}
#toast .t-close:hover { background: rgba(255, 255, 255, 0.24); }

/* ---------------- Animations ---------------- */
@keyframes sway { 0%,100% { transform: rotate(-1.2deg); } 50% { transform: rotate(1.2deg) translateY(-2px); } }
@keyframes glow { 0%,100% { filter: drop-shadow(3px 6px 4px rgba(0,0,0,0.22)) brightness(1); } 50% { filter: drop-shadow(3px 6px 4px rgba(0,0,0,0.22)) brightness(1.28) saturate(1.15); } }
@keyframes bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@keyframes pop-in { 0% { opacity: 0; transform: scale(0.94) translateY(6px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes flit-a { 0%,100% { transform: translate(0,0); } 50% { transform: translate(40px,-16px); } }
@keyframes flit-b { 0%,100% { transform: translate(0,0); } 50% { transform: translate(-52px,12px); } }
@keyframes flit-c { 0%,100% { transform: translate(0,0); } 50% { transform: translate(-44px,14px); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001s !important; animation-iteration-count: 1 !important; }
}

/* ---------------- Responsive ---------------- */
@media (max-width: 880px) {
  #app { padding: 0 12px calc(86px + env(safe-area-inset-bottom)); }
  /* Two-row HUD: brand + actions on top, resource chips on their own full
     line below, so nothing truncates or needs sideways scrolling. */
  .hud {
    margin: 0 -12px;
    flex-wrap: wrap;
    height: auto;
    row-gap: 8px;
    padding-top: 8px;
    padding-bottom: 8px;
  }
  .brand { order: 1; }
  .hud-actions { order: 2; margin-left: auto; gap: 5px; }
  /* Tighten the top action buttons on phones so the row (brand + buttons +
     wallet) fits without truncating. */
  .hud-actions .btn-info { padding: 5px 7px; font-size: 13px; }
  .lang-flag { padding: 3px 5px; font-size: 13px; }
  .hud-actions .btn-wallet { padding: 6px 9px; font-size: 12px; }
  .hud-actions .wallet-text { font-size: 12px; }
  .resources {
    order: 3;
    flex-basis: 100%;
    margin-left: 0;
    justify-content: space-between;
    gap: 6px;
  }
  .brand-logo { height: 34px; }
  .layout { grid-template-columns: 1fr; }
  .hero { height: 95px; }
  .hero-logo { height: 70px; }

  /* Screen switching driven by bottom nav */
  .col-panel { display: none; }
  body.screen-shop .col-farm,
  body.screen-kitchen .col-farm,
  body.screen-apiary .col-farm,
  body.screen-inventory .col-farm,
  body.screen-nfts .col-farm,
  body.screen-shrine .col-farm,
  body.screen-den .col-farm,
  body.screen-vault .col-farm,
  body.screen-stake .col-farm,
  body.screen-market .col-farm,
  body.screen-rank .col-farm,
  body.screen-clan .col-farm,
  body.screen-social .col-farm { display: none; }
  body.screen-shop .col-panel,
  body.screen-kitchen .col-panel,
  body.screen-apiary .col-panel,
  body.screen-inventory .col-panel,
  body.screen-nfts .col-panel,
  body.screen-shrine .col-panel,
  body.screen-den .col-panel,
  body.screen-vault .col-panel,
  body.screen-stake .col-panel,
  body.screen-market .col-panel,
  body.screen-rank .col-panel,
  body.screen-clan .col-panel,
  body.screen-social .col-panel { display: block; }

  /* On phones the bottom nav is the section switcher, so the in-panel tab bar is
     redundant — hide it to cut clutter. */
  .tabs { display: none; }

  .bottom-nav {
    /* A single horizontally-scrollable row of every section: items keep a
       comfortable width and the bar scrolls sideways when they don't all fit,
       instead of shrinking or wrapping. */
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    /* Reserve horizontal finger drags for sliding the bar, and keep an edge
       overscroll from triggering the browser's back/forward navigation. */
    touch-action: pan-x;
    overscroll-behavior-x: contain;
    scrollbar-width: none; /* Firefox */
    scroll-behavior: smooth;
    gap: 2px;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 50;
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
    background: rgba(255, 250, 240, 0.94);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--line);
    box-shadow: 0 -6px 18px rgba(96,70,38,0.12);
  }
  .bottom-nav::-webkit-scrollbar { display: none; } /* Chrome/Safari */
  .nav-item {
    /* Grow to fill the bar when the items fit; hold this width and let the bar
       scroll when they don't. */
    flex: 1 0 auto;
    min-width: 62px;
    appearance: none; border: none; background: transparent; cursor: pointer;
    display: grid; justify-items: center; gap: 2px;
    font-family: var(--font-ui); font-weight: 800; font-size: 20px; /* the emoji icon */
    color: var(--muted);
    padding: 5px 0;
    border-radius: 10px;
  }
  /* The label under the icon: small, and truncates rather than colliding. */
  .nav-item span { font-size: 9.5px; line-height: 1.1; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .nav-item.active { color: var(--green-d); background: rgba(91,168,69,0.12); }

  .plots { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
  .plot .crop-sprite { --cell: 128px; }
  .daily { grid-template-columns: auto 1fr; }
  .daily .btn { grid-column: 1 / -1; }
}

@media (max-width: 380px) {
  .chip-tag { display: none; }
  .plots { grid-template-columns: 1fr 1fr; }
  /* Very narrow: drop the wallet button's text label (keep the 👛 icon) so the
     top action row can never truncate. */
  .hud-actions .wallet-text { display: none; }
  .hud-actions { gap: 4px; }
}

/* ---------------- Tokenomics page ---------------- */
.btn-info { padding: 6px 9px; font-size: 14px; }
/* Language switch: the two flags sit side by side; the active language is lit
   and the other is dimmed to grayscale. Compact so the HUD action row doesn't
   overflow the wallet button on narrow screens. */
.lang-switch { display: inline-flex; align-items: center; gap: 2px; padding: 2px; border-radius: 10px; background: var(--cream-2); box-shadow: 0 2px 0 rgba(110,84,46,0.22), 0 4px 10px rgba(96,70,38,0.12); }
.lang-switch[hidden] { display: none; }
.lang-flag { appearance: none; border: none; background: transparent; cursor: pointer; font-size: 15px; line-height: 1; padding: 4px 6px; border-radius: 8px; opacity: 0.35; filter: grayscale(1); transition: opacity .15s, filter .15s, background .15s, box-shadow .15s; }
.lang-flag:hover { opacity: 0.7; filter: grayscale(0.3); }
.lang-flag.active { opacity: 1; filter: none; background: rgba(91,168,69,0.18); box-shadow: 0 0 0 2px rgba(91,168,69,0.55), 0 0 8px rgba(91,168,69,0.45); cursor: default; }

#app.info-wrap { padding: 0 16px calc(40px + env(safe-area-inset-bottom)); }
.info-page { max-width: 640px; margin: 20px auto 0; display: grid; gap: 14px; }
.info-card { padding: 18px 20px; }
.info-card-muted { background: var(--panel-2); }
.info-title { font-family: var(--font-display); font-size: 24px; font-weight: 700; color: var(--ink); margin-bottom: 8px; }
.info-lead { font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); }
.info-note { font-size: 12.5px; line-height: 1.55; margin-top: 10px; }

.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.info-tile { background: var(--cream-2); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px 14px; }
.info-tile-h { font-family: var(--font-display); font-weight: 600; font-size: 14px; color: var(--ink); margin-bottom: 6px; }
.info-tile-p { font-size: 12px; line-height: 1.5; }

.info-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.info-list li {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 12px;
  background: var(--cream-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13px;
}
.info-list li strong { font-family: var(--font-display); color: var(--green-d); }

@media (max-width: 880px) {
  .info-page { margin: 12px auto 0; }
  .info-grid { grid-template-columns: 1fr; }
}

/* ---------------- Raffle card (Shop tab) ---------------- */
.raffle-card {
  border-radius: 14px;
  padding: 13px 14px 14px;
  margin-bottom: 14px;
  background: linear-gradient(160deg, #3a1a5e, #1e1035);
  border: 1px solid #7b4fd8;
  color: #f0eaff;
}
.raffle-card:empty { display: none; }
.raffle-head {
  display: flex; align-items: center; gap: 8px;
  font-weight: 800; font-size: 14px; margin-bottom: 10px;
}
.raffle-head .raffle-badge {
  margin-left: auto; font-size: 10px; font-weight: 700;
  background: rgba(255,255,255,0.12); border-radius: 999px;
  padding: 2px 8px; letter-spacing: 0.03em;
}
.raffle-pot-row {
  display: flex; align-items: baseline; gap: 6px; margin-bottom: 8px;
}
.raffle-pot-label { font-size: 11px; opacity: 0.6; }
.raffle-pot-value { font-size: 22px; font-weight: 800; color: #ffd86b; line-height: 1; }
.raffle-pot-unit { font-size: 11px; font-weight: 700; opacity: 0.6; margin-left: 1px; }
.raffle-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  margin-bottom: 10px;
}
.raffle-stat {
  background: rgba(255,255,255,0.07); border-radius: 9px;
  padding: 7px 6px; text-align: center;
}
.raffle-stat strong { display: block; font-size: 14px; font-weight: 800; }
.raffle-stat span { font-size: 10px; opacity: 0.6; }
.raffle-split {
  display: flex; gap: 4px; margin-bottom: 10px;
}
.raffle-split-item {
  flex: 1; border-radius: 8px; padding: 5px 4px; text-align: center;
  font-size: 10px; font-weight: 700;
}
.raffle-split-winner { background: rgba(255,216,107,0.15); color: #ffd86b; }
.raffle-split-burn { background: rgba(255,100,80,0.15); color: #ff9080; }
.raffle-split-vault { background: rgba(140,100,255,0.15); color: #c9a8ff; }
.raffle-actions {
  display: flex; gap: 8px; margin-top: 4px;
}
.raffle-actions .btn { flex: 1; }
.raffle-qty {
  display: flex; align-items: center; gap: 6px; background: rgba(255,255,255,0.08);
  border-radius: 9px; padding: 0 10px;
}
.raffle-qty button {
  background: none; border: none; color: #f0eaff; font-size: 18px;
  font-weight: 700; padding: 6px 2px; cursor: pointer; line-height: 1;
}
.raffle-qty span { min-width: 28px; text-align: center; font-weight: 800; font-size: 14px; }
.raffle-my-tickets {
  margin-top: 8px; font-size: 11px; opacity: 0.75; text-align: center;
}
.raffle-my-tickets strong { color: #a8d4ff; font-weight: 800; }
.raffle-history {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid rgba(255,255,255,0.1);
}
.raffle-history-head {
  font-size: 10px; font-weight: 700; opacity: 0.5;
  letter-spacing: 0.05em; text-transform: uppercase; margin-bottom: 6px;
}
.raffle-history-row {
  display: flex; align-items: baseline; gap: 6px;
  font-size: 11px; padding: 3px 0; opacity: 0.85;
}
.raffle-history-row:not(:last-child) { border-bottom: 1px solid rgba(255,255,255,0.06); }
.raffle-history-winner { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.raffle-history-prize { font-weight: 700; color: #ffd86b; white-space: nowrap; }
.raffle-history-time { font-size: 10px; opacity: 0.5; white-space: nowrap; }

/* ---------------- Moonbloom Shrine ---------------- */
#shrine-panel { display: flex; flex-direction: column; gap: 10px; container-type: inline-size; }
.shrine-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.shrine-sub { font-size: 11px; }
.shrine-note { font-size: 11px; margin: 0; }
.shrine-warn {
  font-size: 11.5px; font-weight: 700; margin: 0;
  color: #8a5a00; background: #fff2cc; border: 1px solid var(--gold);
  padding: 6px 10px; border-radius: 10px;
}
.pill-gold { background: linear-gradient(180deg, var(--gold), var(--gold-d)); color: #4a3208; font-weight: 800; border: none; }
.shrine-stage {
  position: relative; width: 100%; aspect-ratio: 1 / 1;
  background: url('assets/moonbloom-shrine.jpg?v=3') center/cover no-repeat;
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm);
}
.shrine-slot {
  position: absolute; transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center;
  margin: 0; padding: 0; border: none; background: transparent;
  border-radius: 8px; cursor: pointer;
}
.shrine-slot[disabled] { cursor: default; }
.shrine-slot.empty { transition: background 0.12s ease; }
.shrine-slot.empty:hover { background: rgba(154, 109, 215, 0.30); }
.shrine-slot.filled:hover { background: rgba(0, 0, 0, 0.20); }
.shrine-slot .nft-thumb-card,
.shrine-slot .nft-art,
.shrine-slot .mutant-art { width: 100%; height: 100%; object-fit: contain; }
.shrine-plus { font-size: 5cqw; color: rgba(255, 255, 255, 0.6); font-weight: 700; line-height: 1; }
.shrine-lock { font-size: 4cqw; opacity: 0.7; }
/* Offering altar — sits over the circular dais at the base of the shrine art. */
.shrine-slot.altar {
  background: radial-gradient(closest-side, rgba(255, 190, 80, 0.22), transparent 75%);
  transition: background 0.12s ease;
}
.shrine-slot.altar:hover { background: radial-gradient(closest-side, rgba(255, 190, 80, 0.45), transparent 75%); }
.shrine-cost {
  display: inline-flex; align-items: center; gap: 2px;
  font-size: 2.7cqw; font-weight: 800; color: #4a3208; line-height: 1;
  background: linear-gradient(180deg, var(--gold), var(--gold-d));
  padding: 3px 6px; border-radius: 999px; white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

/* Multi-select shrine offering picker: a leading check glyph and a highlighted
   "picked" state so several NFTs can be queued for one burn, plus the footer
   bar tallying the combined blessing above the confirm button. */
.shrine-offer-check { width: 1.1em; text-align: center; opacity: 0.75; }
.shrine-offer-pick.picked {
  outline: 2px solid var(--gold, #f5c542);
  background: rgba(245, 197, 66, 0.16);
}
.shrine-offer-pick.picked .shrine-offer-check { opacity: 1; color: var(--gold, #f5c542); }
/* Toolbar above the offering list: Select all + running tally + the burn
   (Offer) button, so both live actions sit at the top of the picker. */
.shrine-offer-bar {
  display: flex; align-items: center; gap: 8px;
  margin: 4px 0 8px; padding-bottom: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.shrine-offer-bar .shrine-offer-total { margin-left: 2px; }
.shrine-offer-bar .shrine-offer-go { margin-left: auto; }

/* ============================================================
   V2 GAME-FEEL SKIN — the shipped layout for everyone
   Applied unconditionally by app.js (`body.v2`); see applyV2Mode().
   Turns the page layout into a game: full-screen portrait stage,
   floating HUD, wooden dock in the sky (per player decision the nav
   must never cover the farm), panels as drop-down sheets, juice.
   Design source: docs/GAME_UX_PROPOSALS.md + public/v2-preview.html.
   Every weather/time skin has its own portrait artwork (player-provided),
   each with its own plot-centre table in app.js (PLOT_CENTERS_V2).
   ============================================================ */

body.v2 {
  overflow: hidden;
  height: 100vh;   /* fallback for webviews without dvh */
  height: 100dvh;
  /* Extends the scene's own sky/grass on ultra-wide screens. */
  background: linear-gradient(180deg, #0172e7 0%, #4d9bee 40%, #7fbf5a 78%, #5e9c41 100%);
  /* One portrait canvas ratio shared by every skin (852×1842). */
  --scene-ar: 0.4625;
  /* How much wider than a pure contain-fit each desktop phone is drawn. A phone
     frames the game to its SCREEN (wider than the portrait canvas), so the art
     zooms in and the sky crops off the top. On desktop we push this further so
     the two phones fill the wide window instead of leaving big empty margins
     and everything reading tiny. The farm plots (y 56–70%) and shrine slots
     (y 46–85%) sit low in their bottom-anchored scenes, so they stay on screen
     up to ~1.7×; 1.5 keeps a safe margin while filling the space. */
  --phone-zoom: 1.5;
  /* The play-frame: a phone-shaped column that every fixed layer (stage, HUD,
     dock, panels, cards) is centred inside.
     Portrait (phones): COVER — fill the viewport width and let the taller
     portrait art crop off-screen, so the game is edge-to-edge and immersive
     exactly as before. The landscape override below swaps this to CONTAIN. */
  --stage-w: max(100vw, calc(100vh * var(--scene-ar)));    /* fallback */
  --stage-w: max(100vw, calc(100dvh * var(--scene-ar)));
}
/* Landscape / desktop: a wide window can't be covered by a portrait canvas
   without the art overflowing off the top and the whole UI stretching to the
   edges (the "no format, unplayable on desktop" report). Switch the frame to
   CONTAIN — derive its width from the height so the game is a centred,
   phone-shaped column that always fits, with the sky/grass gradient as wings. */
@media (orientation: landscape) {
  body.v2 { --stage-w: min(100vw, calc(100vh * var(--scene-ar) * var(--phone-zoom))); }
  body.v2 { --stage-w: min(100vw, calc(100dvh * var(--scene-ar) * var(--phone-zoom))); }
}
body.v2 #app { width: 100%; max-width: none; padding: 0; }
body.v2 .hero { display: none; }
body.v2 .layout { display: block; }

/* ---------------- The stage ---------------- */
body.v2 .farm-scene {
  position: fixed; bottom: 0;
  /* Centre with margins, NOT transform: the base .farm-scene pop-in animation
     (fill mode `both`) would permanently override a transform set here. */
  left: 0; right: 0; margin: 0 auto;
  transform: none; animation: none;
  /* The stage IS the play-frame: fill the frame width (portrait phone → full
     viewport width; landscape/desktop → height-derived), never overflowing. */
  width: var(--stage-w);
  aspect-ratio: var(--scene-ar);
  border: 0; outline: none; border-radius: 0;
  box-shadow: none; background: transparent;
  z-index: 0;
}
/* Every time-of-day/weather skin has its own portrait artwork, each with its
   own canvas proportions — the stage reads them from --scene-ar so the cover
   maths and the per-skin plot tables (PLOT_CENTERS_V2 in app.js) line up.
   Keep the selectors compound (body.v2 + skin) so they outrank the
   square-scene skin rules above. */
body.v2 .farm-layer,
body.v2 #plots.farm-dusk .farm-layer,
body.v2 #plots.farm-night .farm-layer,
body.v2 #plots.farm-rain .farm-layer,
body.v2 #plots.farm-rain-night .farm-layer {
  background-image: url("assets/farm-scene-portrait.png?v=2");
  image-rendering: pixelated;
}
body.v2 #plots.farm-dusk .farm-layer { background-image: url("assets/farm-scene-portrait-sunset.png?v=2"); }
body.v2 #plots.farm-night .farm-layer { background-image: url("assets/farm-scene-portrait-night.png?v=2"); }
body.v2 #plots.farm-rain .farm-layer { background-image: url("assets/farm-scene-portrait-rain.png?v=2"); }
body.v2 #plots.farm-rain-night .farm-layer { background-image: url("assets/farm-scene-portrait-rain-night.png?v=2"); }
/* "Open" (fence-less) scene set: a per-farm alternative backdrop with no baked
   fence, toggled from the decoration editor (see farmSceneOpen in app.js). One
   fence-less artwork per skin; the plot grids line up with the same
   PLOT_CENTERS_V2 tables. The compound selectors (extra .farm-open class)
   outrank the fenced skin rules above. */
body.v2 #plots.farm-open .farm-layer                 { background-image: url("assets/farm-scene-portrait-open.png?v=1"); }
body.v2 #plots.farm-open.farm-dusk .farm-layer       { background-image: url("assets/farm-scene-portrait-open-sunset.png?v=1"); }
body.v2 #plots.farm-open.farm-night .farm-layer      { background-image: url("assets/farm-scene-portrait-open-night.png?v=1"); }
body.v2 #plots.farm-open.farm-rain .farm-layer       { background-image: url("assets/farm-scene-portrait-open-rain.png?v=1"); }
body.v2 #plots.farm-open.farm-rain-night .farm-layer { background-image: url("assets/farm-scene-portrait-open-rain-night.png?v=1"); }
/* Themed Workshop scenarios (each a Workshop LV 3 unlock, toggled per farm in
   the decoration editor via data-farm-scene). Most replace every time/weather
   skin — applyFarmAmbience clears those classes when such a scenario is on, so a
   single rule is all that's needed; the attribute selector outranks the base
   portrait rule. The crops reuse the DEFAULT plot grid (PLOT_CENTERS_V2.day);
   the artwork is authored so its drawn dirt plots already line up with those
   default cells, so each scene just fills the field 1:1 (base center/cover).
   Time-aware scenes (see TIME_AWARE_SCENES in app.js) are the exception: they
   ship day/dusk/night artwork and keep the farm-dusk/farm-night class, so their
   backdrop follows the clock like the base field (but never the rain overlay).
   The compound `[data-farm-scene][.farm-dusk|.farm-night]` selectors outrank the
   scene's own base rule below. */
body.v2 #plots[data-farm-scene="castle"] .farm-layer    { background-image: url("assets/farm-scene-portrait-castle.png?v=4"); }
body.v2 #plots[data-farm-scene="herbalist"] .farm-layer { background-image: url("assets/farm-scene-portrait-herbalist.png?v=9"); }
body.v2 #plots[data-farm-scene="herbalist"].farm-dusk  .farm-layer { background-image: url("assets/farm-scene-portrait-herbalist-dusk.png?v=3"); }
body.v2 #plots[data-farm-scene="herbalist"].farm-night .farm-layer { background-image: url("assets/farm-scene-portrait-herbalist-night.png?v=3"); }
body.v2 #plots[data-farm-scene="beekeeper"] .farm-layer { background-image: url("assets/farm-scene-portrait-beekeeper.png?v=9"); }
body.v2 #plots[data-farm-scene="beekeeper"].farm-dusk  .farm-layer { background-image: url("assets/farm-scene-portrait-beekeeper-dusk.png?v=3"); }
body.v2 #plots[data-farm-scene="beekeeper"].farm-night .farm-layer { background-image: url("assets/farm-scene-portrait-beekeeper-night.png?v=3"); }
body.v2 #plots[data-farm-scene="truffle"] .farm-layer   { background-image: url("assets/farm-scene-portrait-truffle.png?v=6"); }
body.v2 #plots[data-farm-scene="truffle"].farm-dusk  .farm-layer { background-image: url("assets/farm-scene-portrait-truffle-dusk.png?v=1"); }
body.v2 #plots[data-farm-scene="truffle"].farm-night .farm-layer { background-image: url("assets/farm-scene-portrait-truffle-night.png?v=1"); }
/* Dirt-plot overlay. The beekeeper and truffle artwork (every clock skin) and
   the herbalist dusk/night artwork ship without baked plots, so instead of
   compositing dirt into each backdrop, mount the tilled 12-plot grid as one
   shared transparent
   layer on top of the field. It's authored on the 0.4625 stage canvas at the
   PLOT_CENTERS_V2.day cells and stretched to fill the layer (background-size
   100% 100%), so it lines up with the crop cells on every skin. The pseudo-
   element paints above the backdrop but below #plot-cells (later in the tree),
   so crops and farmers still sit on top of the soil. Dusk/night reuse the same
   day-lit dirt, colour-graded via filter to match the scene light. Herbalist
   day is untouched — its backdrop already has the plots baked in. */
body.v2 #plots[data-farm-scene="beekeeper"] .farm-layer::before,
body.v2 #plots[data-farm-scene="truffle"] .farm-layer::before,
body.v2 #plots[data-farm-scene="herbalist"].farm-dusk  .farm-layer::before,
body.v2 #plots[data-farm-scene="herbalist"].farm-night .farm-layer::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url("assets/plots-overlay.png?v=1") 0 0 / 100% 100% no-repeat;
  image-rendering: pixelated;
  pointer-events: none;
}
body.v2 #plots[data-farm-scene="beekeeper"].farm-dusk  .farm-layer::before,
body.v2 #plots[data-farm-scene="herbalist"].farm-dusk  .farm-layer::before,
body.v2 #plots[data-farm-scene="truffle"].farm-dusk    .farm-layer::before {
  filter: brightness(0.9) sepia(0.32) saturate(1.25) hue-rotate(-8deg);
}
body.v2 #plots[data-farm-scene="beekeeper"].farm-night .farm-layer::before,
body.v2 #plots[data-farm-scene="herbalist"].farm-night .farm-layer::before,
body.v2 #plots[data-farm-scene="truffle"].farm-night   .farm-layer::before {
  filter: brightness(0.6) saturate(0.72) hue-rotate(6deg) brightness(0.92);
}
/* The empty-plot hint ring: cells are much shorter in the portrait field. */
body.v2 .cell.empty::after { width: 44%; bottom: 6%; }
body.v2 .cell.locked::after { bottom: 18%; }
/* Field furniture drawn for the square scene, reseated for the portrait one
   (beside rows 2–3, on the grass strip between the plots and the fence). */
body.v2 .scarecrow2 { left: 83.5%; top: 63%; }
/* Active-boost chips: a stat row right under the SPROUT/coins/score chips,
   instead of floating over the field. */
body.v2 .farm-buffs {
  position: fixed; z-index: 22;
  top: calc(var(--hud-bottom) + 2px);
  left: 0; right: 0; margin: 0 auto;
  width: min(430px, calc(var(--stage-w) - 20px));
  display: flex; flex-wrap: nowrap; gap: 6px;
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;
  pointer-events: auto;
  padding: 0 2px 2px;
}
body.v2 .farm-buffs::-webkit-scrollbar { display: none; }

/* Large farm-number title over the field — a persistent scene title so it's
   always clear which farm is on screen. Sits just under the boost-chip row,
   centred over the sky. Same layer band as the chips (below the z-40 panels, so
   an open menu covers it); click-through so it never blocks the field. */
body.v2 .farm-title {
  position: fixed; z-index: 21;
  top: calc(var(--hud-bottom) + 46px);
  left: 0; right: 0; margin: 0 auto;
  display: flex; justify-content: center; align-items: center; gap: 8px;
  pointer-events: none;
}
body.v2 .farm-title[hidden] { display: none; }
/* ‹ › farm-switch buttons flanking the badge. The row itself stays
   click-through (pointer-events:none) so it never steals taps from the field —
   only the buttons catch input. */
body.v2 .farm-title .ft-nav {
  pointer-events: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; margin: 0; padding: 0 0 2px;
  border-radius: 10px; cursor: pointer;
  background: rgba(20, 14, 6, 0.55);
  border: 1.5px solid rgba(255, 220, 160, 0.45);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
  color: #ffd679; font-family: var(--font-display);
  font-weight: 700; font-size: 20px; line-height: 1;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
  transition: transform 0.1s ease, background 0.12s ease;
}
body.v2 .farm-title .ft-nav:active { transform: scale(0.92); background: rgba(50, 36, 16, 0.65); }
body.v2 .farm-title .ft-nav[disabled] { opacity: 0.35; cursor: default; }
body.v2 .farm-title .farm-title-badge {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 4px 14px; border-radius: 11px;
  background: rgba(20, 14, 6, 0.55);
  border: 1.5px solid rgba(255, 220, 160, 0.45);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
body.v2 .farm-title .ft-label {
  font-family: var(--font-display); font-weight: 700; font-size: 17px;
  color: #fff6df; letter-spacing: 0.5px;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.6), 0 0 2px rgba(0, 0, 0, 0.8);
}
body.v2 .farm-title .ft-num {
  font-family: var(--font-display); font-weight: 700; font-size: 17px;
  color: #ffd679; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
}
body.v2 .farm-title .ft-of {
  font-family: var(--font-display); font-weight: 600; font-size: 11px; color: #e7d3ad;
}

/* ---------------- Floating HUD ---------------- */
body.v2 .hud {
  position: fixed; top: 0; left: 0; right: 0; z-index: 45;
  /* Centre the chips/actions over the play-frame instead of flinging them to
     the far corners of a wide desktop window. */
  margin: 0 auto; width: 100%; max-width: var(--stage-w);
  height: auto;
  padding: calc(8px + env(safe-area-inset-top)) 12px 6px;
  background: transparent;
  border-bottom: 0; box-shadow: none; backdrop-filter: none;
  pointer-events: none;
  flex-wrap: wrap; row-gap: 8px;
}
body.v2 .hud > * { pointer-events: auto; }
body.v2 .brand { display: none; }
body.v2 .chip {
  background: rgba(15, 25, 10, 0.66);
  border-color: rgba(255, 255, 255, 0.16);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.35), 0 1px 0 rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(3px);
}
body.v2 .chip strong { color: #ffe9b0; }
body.v2 .chip-tag { color: #cbb591; }
body.v2 .hud .btn-ghost {
  background: rgba(15, 25, 10, 0.6);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(3px);
}

/* Level medallion (hidden outside V2 via [hidden] set from JS). */
.lvl-medal[hidden] { display: none !important; }
/* Medallion sized so the player-icon core reads clearly (~25% larger than the
   original 52px). The v2 HUD is a transparent, auto-height floating bar, so the
   bigger badge just takes a little more room top-left — no layout reflow. */
body.v2 .lvl-medal {
  position: relative; flex: 0 0 auto;
  width: 65px; height: 65px; border-radius: 50%;
  border: 0; padding: 0; cursor: pointer;
  display: grid; place-items: center;
  background: conic-gradient(var(--gold) calc(var(--xp, 0) * 1%), rgba(255, 255, 255, 0.22) 0);
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.35));
}
body.v2 .lvl-medal .core {
  width: 53px; height: 53px; border-radius: 50%;
  background: linear-gradient(180deg, #486b2f, #2c4519);
  border: 2px solid rgba(255, 255, 255, 0.3);
  display: grid; place-items: center; font-size: 25px;
}
body.v2 .lvl-medal .lvl-tag {
  position: absolute; bottom: -7px; left: 50%; transform: translateX(-50%);
  font-family: var(--font-display); font-weight: 700; font-size: 11px; color: #2c1f08;
  background: linear-gradient(180deg, #ffe19a, var(--gold));
  padding: 1px 9px; border-radius: 999px; white-space: nowrap;
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

/* Flying coin (harvest -> HUD). Fixed so it survives the field re-render. */
.v2-coin-fly {
  position: fixed; z-index: 60; pointer-events: none;
  width: 26px; height: 26px;
  background: url("assets/coin.png?v=3") center / contain no-repeat;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.4));
}
/* Harvest SPROUT drop: the same fly-to-HUD juice as coins, but the 🌱 token
   streams up to the SPROUT chip. Count scales with the drop (see v2FlySprouts). */
.v2-sprout-fly {
  position: fixed; z-index: 60; pointer-events: none;
  width: 24px; height: 24px;
  background: url("assets/token-sprout.png?v=3") center / contain no-repeat;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.4));
}
/* The SPROUT chip gives a little bounce when a sprout drop lands on it. */
@keyframes v2-chip-pop {
  0% { transform: scale(1); }
  40% { transform: scale(1.18); }
  100% { transform: scale(1); }
}
.v2-chip-pop { animation: v2-chip-pop 360ms cubic-bezier(0.34, 1.56, 0.64, 1); }

/* ---------------- Wooden dock, docked at the bottom ---------------- */
/* The dock rides the bottom of the screen (like the production nav) so tab
   panels get the full height above it — no more squeezed sheets or the dead
   band the sky-dock left under short menus. */
body.v2 .tabs { display: none; }
body.v2 .bottom-nav {
  display: flex;
  position: fixed; left: 0; right: 0; top: auto;
  bottom: calc(8px + env(safe-area-inset-bottom));
  margin: 0 auto;
  width: min(430px, calc(var(--stage-w) - 20px));
  background: linear-gradient(180deg, #52381f, #3a2a18);
  border: 1px solid rgba(255, 220, 160, 0.3);
  border-top: 1px solid rgba(255, 220, 160, 0.3);
  border-radius: 18px;
  padding: 7px 6px 8px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.14);
  overflow-x: auto; overflow-y: visible;
  scrollbar-width: none;
  gap: 2px;
  z-index: 44;
}
body.v2 .nav-item {
  position: relative;
  flex: 1 0 auto; min-width: 56px;
  appearance: none; border: none; background: transparent; cursor: pointer;
  display: grid; justify-items: center; gap: 2px;
  font-family: var(--font-ui); font-weight: 800; font-size: 20px;
  color: #cbb591;
  padding: 4px 0 3px;
  border-radius: 10px;
  opacity: 0.78; filter: saturate(0.75);
}
body.v2 .nav-item span {
  font-size: 8.5px; line-height: 1.1; letter-spacing: 0.05em; text-transform: uppercase;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
body.v2 .nav-item.active {
  color: #ffe9b0; opacity: 1; filter: none;
  background: rgba(255, 220, 160, 0.14);
}
body.v2 .nav-item[data-badge]:not([data-badge=""])::after {
  content: attr(data-badge);
  position: absolute; top: -3px; right: 3px;
  min-width: 16px; height: 16px; border-radius: 999px; padding: 0 4px;
  background: linear-gradient(180deg, #ff8a6a, #e04f2e);
  color: #fff; font-size: 9.5px; font-weight: 800; line-height: 16px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}

/* ---------------- Panels are full-screen overlays over the stage --------- */
/* Player decision: every tab artwork is the FULL-SCREEN backdrop of its tab,
   never a banner inside a sheet. The panel covers the viewport (content slides
   up from the bottom), sits under the HUD/dock, and each tab swaps the
   backdrop below. Content scrolls over the art. */
body.v2 .col-panel {
  display: block;
  /* Centred over the play-frame (not the whole viewport) so the portrait tab
     artwork and its content stay a phone-shaped column on desktop. */
  position: fixed; top: 0; bottom: 0; left: 0; right: 0; z-index: 40;
  /* The base .col-panel sets align-self:start, which makes an inset-stretched
     fixed box collapse to its content height — pin the height explicitly. */
  height: 100%; align-self: stretch;
  width: 100%; max-width: var(--stage-w); max-height: none; margin: 0 auto;
  overflow-y: auto; overscroll-behavior: contain;
  background: linear-gradient(180deg, #241a10, #38281a);
  image-rendering: pixelated;
  border: 0; border-radius: 0; box-shadow: none;
  /* Top padding clears the floating HUD; bottom padding clears the docked nav
     so the last row of a list is never hidden behind it. */
  padding: calc(104px + env(safe-area-inset-top)) 10px calc(84px + env(safe-area-inset-bottom));
  transform: translateY(102%);
  transition: transform 0.34s cubic-bezier(0.22, 1.1, 0.36, 1);
}
/* Backdrops por aba: a arte inteira cobre a tela, SEM véu escuro — as artes
   entram cheias. A legibilidade do conteúdo vem dos próprios cartões (madeira
   escura) e da sombra de texto nos títulos. */
body.v2.screen-market .col-panel {
  background: #241a10 url("assets/marketplace-portrait.png?v=2") center / cover no-repeat;
}
body.v2.screen-nfts .col-panel {
  background: #101a24 url("assets/nft-lab-portrait.png?v=1") center / cover no-repeat;
}
body.v2.screen-stake .col-panel {
  background: #09150d url("assets/greenhouse-portrait.png?v=1") center / cover no-repeat;
}
body.v2.screen-rank .col-panel {
  background: #14202e url("assets/rank-portrait.png?v=2") center / cover no-repeat;
}
/* Clan Wars: its own screen, backed by the old leaderboard-castle art (the rank
   screen now uses the new podium art above). */
body.v2.screen-clan .col-panel {
  background: #14202e url("assets/clanwar-portrait.png?v=1") center / cover no-repeat;
}
/* Social: the community-village art, with the link card as translucent green
   glass (below) so the waterfall scene shows through behind it. The art is
   anchored to the very top so it fills the whole background from the top edge
   (behind the floating HUD), and the card starts lower so the scene's
   CryptoSprouts logo + COMMUNITY sign stay fully visible above the links. */
body.v2.screen-social .col-panel {
  background: #1a3a20 url("assets/community-portrait.jpg?v=4") center top / cover no-repeat;
  padding-top: calc(300px + env(safe-area-inset-top));
}
/* Shrine: SÓ a imagem de fundo funcional (o palco interativo com os slots).
   Sem uma cópia decorativa em `cover` no painel — ela reaparecia embaixo do
   palco rolado e criava a imagem fantasma atrás das notas. Fundo chapado. */
body.v2.screen-shrine .col-panel {
  background: linear-gradient(180deg, #1a1030, #140b20);
}
/* Adventurer's Den (DEV): the den art, darkened with a purple veil so the light
   panel text stays readable over the busy illustration. */
body.v2.screen-den .col-panel {
  background:
    linear-gradient(180deg, rgba(20, 12, 30, 0.74), rgba(20, 12, 30, 0.86)),
    #1c1330 url("assets/den-portrait.jpg?v=2") center top / cover no-repeat;
}
body.v2.screen-shop .col-panel {
  background: #241a10 url("assets/shop-portrait.png?v=1") center / cover no-repeat;
}
body.v2.screen-kitchen .col-panel {
  background: #241a10 url("assets/kitchen-portrait.png?v=1") center / cover no-repeat;
}
body.v2.screen-apiary .col-panel {
  background: #24361a url("assets/apiary-portrait.png?v=2") center / cover no-repeat;
}
body.v2.screen-apiary.prof-truffle_hunter .col-panel {
  background: #2a2013 url("assets/pigpen-portrait.png?v=2") center / cover no-repeat;
}
body.v2.screen-apiary.prof-herbalist .col-panel {
  background: #1c2a12 url("assets/herbgarden-portrait.png?v=2") center / cover no-repeat;
}
body.v2.screen-apiary.prof-alchemist .col-panel {
  background: #1a1226 url("assets/lab-portrait.png?v=2") center / cover no-repeat;
}
body.v2.screen-inventory .col-panel {
  background: #17100a url("assets/bag-portrait.png?v=2") center / cover no-repeat;
}
body.v2.screen-vault .col-panel {
  background: #16122a url("assets/lunar-vault-portrait.png?v=1") center / cover no-repeat;
}
/* Lunar Vault: translucent panels so the vault-door art shows through. */
body.v2.screen-vault .col-panel .vault-banner {
  background: rgba(22, 16, 44, 0.60);
  border-color: rgba(180, 150, 245, 0.34);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}
body.v2.screen-shop .col-panel,
body.v2.screen-kitchen .col-panel,
body.v2.screen-apiary .col-panel,
body.v2.screen-inventory .col-panel,
body.v2.screen-nfts .col-panel,
body.v2.screen-shrine .col-panel,
body.v2.screen-den .col-panel,
body.v2.screen-vault .col-panel,
body.v2.screen-stake .col-panel,
body.v2.screen-market .col-panel,
body.v2.screen-rank .col-panel,
body.v2.screen-clan .col-panel,
body.v2.screen-social .col-panel { transform: none; }

/* Professions Workshop: cartões translúcidos para a arte do fundo (apiário /
   pig pen / herb garden / lab) aparecer atrás — vidro escuro + texto claro. */
body.v2.screen-apiary .col-panel .row {
  background: rgba(16, 20, 12, 0.56);
  border-color: rgba(240, 222, 170, 0.30);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.34);
}
body.v2.screen-apiary .col-panel .row .row-title span.name,
body.v2.screen-apiary .col-panel .section-head h3 { color: #f6eed8; }
body.v2.screen-apiary .col-panel .row .row-meta,
body.v2.screen-apiary .col-panel .row .need { color: #e2d7bd; }

/* Kitchen: cartões translúcidos para a arte da cozinha aparecer atrás. Same
   dark-glass treatment as the Workshop/Lab (rows + the Specializations banner). */
body.v2.screen-kitchen .col-panel .row,
body.v2.screen-kitchen .col-panel .vault-banner {
  background: rgba(20, 16, 10, 0.56);
  border-color: rgba(240, 222, 170, 0.30);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.34);
}
body.v2.screen-kitchen .col-panel .row .row-title span.name,
body.v2.screen-kitchen .col-panel .vault-banner .section-head h3,
body.v2.screen-kitchen .col-panel > .section-head h3 { color: #f6eed8; }
body.v2.screen-kitchen .col-panel .row .row-meta,
body.v2.screen-kitchen .col-panel .row .need,
body.v2.screen-kitchen .col-panel .row .kitchen-recipe-note,
body.v2.screen-kitchen .col-panel .vault-banner p.muted { color: #e2d7bd; }
/* Keep the "have/need" counters readable on the dark-glass kitchen rows: the
   red "still missing" state would otherwise inherit the light body color. */
body.v2.screen-kitchen .col-panel .row .kitchen-recipe-note .muted { color: #ff9a9a; }
body.v2.screen-kitchen .col-panel .row .kitchen-recipe-note .ok { color: #6fe08a; }
/* Enhance-Food toggle labels ("Truffle (n)", "Essence (n)") and any bare "muted"
   sub-text in a recipe row inherit the app's dark ink/muted, which is invisible
   on the dark-glass kitchen rows. Lift them to the same warm cream as the rest of
   the row. The recipe-note .muted/.ok keep their red/green via the more specific
   rules above. */
body.v2.screen-kitchen .col-panel .row .cook-toggle,
body.v2.screen-kitchen .col-panel .row .muted { color: #e2d7bd; }

/* NFT Lab: cartões translúcidos para a arte do laboratório aparecer atrás
   (o conteúdo continua legível — vidro escuro + texto claro). */
body.v2.screen-nfts .col-panel .row {
  background: rgba(14, 22, 32, 0.60);
  border-color: rgba(150, 200, 255, 0.28);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.32);
}
body.v2.screen-nfts .col-panel .row .row-title span.name { color: #eef4ff; }
body.v2.screen-nfts .col-panel .row .row-meta { color: #c3d3e6; }
body.v2.screen-nfts .col-panel .row.selected {
  border-color: #8bd15a;
  background: rgba(58, 88, 40, 0.62);
  box-shadow: 0 0 0 2px rgba(139, 209, 90, 0.4);
}
body.v2.screen-nfts .col-panel .empty-state { color: #dfeaf6; }

/* Greenhouse: vidraria translúcida, mas LEGÍVEL — as cartas ficam mais opacas
   e todo texto solto sobre a arte clara ganha um chip escuro + sombra. */
body.v2.screen-stake .col-panel .row {
  background: rgba(8, 22, 13, 0.78);
  border-color: rgba(150, 220, 160, 0.32);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
}
body.v2.screen-stake .col-panel .row .name { color: #f1fdec; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); }
body.v2.screen-stake .col-panel .row .row-meta { color: #cdeccf; }
/* Loose lines that sit straight on the bright artwork (intro, active-boost
   banner, stake note/preview) get their own dark chip so they stay readable. */
body.v2.screen-stake #stake-panel > p.muted,
body.v2.screen-stake .col-panel .stake-agg,
body.v2.screen-stake .col-panel .stake-note,
body.v2.screen-stake .col-panel .stake-preview {
  background: rgba(8, 20, 12, 0.70);
  border-radius: 10px;
  padding: 8px 11px;
  color: #eafbe6;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
body.v2.screen-stake .col-panel .stake-agg { border-color: rgba(150, 230, 150, 0.4); }

/* Rank & Clans: castle artwork backdrop with the same translucent glass on the
   leaderboard rows and the clan/referral banners. */
body.v2.screen-rank .col-panel .row,
body.v2.screen-rank .col-panel .vault-banner {
  /* Higher opacity than the other tabs: the new podium art is bright, so a
     lighter glass would wash the light row text out over the sky. */
  background: rgba(14, 24, 38, 0.74);
  border-color: rgba(150, 190, 255, 0.30);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
}
body.v2.screen-rank .col-panel .row .name,
body.v2.screen-rank .col-panel .row .row-title span.name,
body.v2.screen-rank .col-panel .vault-banner { color: #eaf1ff; }
body.v2.screen-rank .col-panel .row .row-meta { color: #c3d3e6; }
body.v2.screen-rank .col-panel .empty-state { color: #dfeaf6; }

/* Clan Wars: same translucent glass over the podium art — the clan card, both
   league boards and the member rows read as dark glass with light text, matching
   every other v2 tab. */
body.v2.screen-clan .col-panel .row,
body.v2.screen-clan .col-panel .vault-banner {
  background: rgba(14, 24, 38, 0.62);
  border-color: rgba(150, 190, 255, 0.30);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.34);
}
body.v2.screen-clan .col-panel .row .name,
body.v2.screen-clan .col-panel .row .row-title span.name,
body.v2.screen-clan .col-panel .vault-banner { color: #eaf1ff; }
body.v2.screen-clan .col-panel .row .row-meta { color: #c3d3e6; }
body.v2.screen-clan .col-panel .empty-state { color: #dfeaf6; }
/* Social: green glass over the bright community-village art — same treatment as
   the other v2 tabs, tinted to keep the card's community branding. */
body.v2.screen-social .col-panel .social-card {
  background: rgba(12, 26, 16, 0.68);
  border-color: rgba(160, 230, 170, 0.32);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
}

/* The champion-prize banner keeps its solid warm gold (it's a reward, not glass),
   just tightened for the darker backdrop. Higher specificity than the glass rule
   above so it isn't flattened to translucent blue. */
body.v2.screen-clan .col-panel .clan-war-prize {
  background: linear-gradient(180deg, #4a3410, #2e2208);
  border-color: #b8862b;
}
/* The viewer's own clan, highlighted in either league — a warm gold glass (keeps
   the light row text readable) + gold ring, instead of the light wash used off-v2. */
body.v2.screen-clan .col-panel .row.clan-war-mine {
  background: rgba(74, 52, 16, 0.66);
  border-color: #d8a93a;
  box-shadow: 0 0 0 2px rgba(216, 169, 58, 0.4), 0 4px 14px rgba(0, 0, 0, 0.34);
}

/* Marketplace: cartões translúcidos para a arte das barracas aparecer atrás
   (vidro escuro e quente + texto claro, casando com a cena). */
body.v2.screen-market .col-panel .row {
  background: rgba(24, 16, 8, 0.60);
  border-color: rgba(255, 220, 160, 0.28);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.34);
}
body.v2.screen-market .col-panel .row .name,
body.v2.screen-market .col-panel .row .row-title span.name { color: #fbf0d8; }
body.v2.screen-market .col-panel .row .row-meta { color: #e3d3ac; }
body.v2.screen-market .col-panel .empty-state { color: #f0e2c4; }

/* Shop & Bag: mesma vidraria quente do marketplace — as artes das prateleiras
   (shop) e do porão (bag) aparecem atrás dos cartões translúcidos. */
body.v2.screen-shop .col-panel .row,
body.v2.screen-inventory .col-panel .row {
  background: rgba(24, 16, 8, 0.60);
  border-color: rgba(255, 220, 160, 0.28);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.34);
}
body.v2.screen-shop .col-panel .row .name,
body.v2.screen-shop .col-panel .row .row-title span.name,
body.v2.screen-inventory .col-panel .row .name,
body.v2.screen-inventory .col-panel .row .row-title span.name { color: #fbf0d8; }
body.v2.screen-shop .col-panel .row .row-meta,
body.v2.screen-inventory .col-panel .row .row-meta { color: #e3d3ac; }
/* Prices keep the light-theme dark brown by default, which vanishes on the
   dark-glass cards — lift them to warm gold on every glass screen. */
body.v2.screen-market .col-panel .row .price,
body.v2.screen-shop .col-panel .row .price,
body.v2.screen-inventory .col-panel .row .price { color: #ffd679; }
body.v2.screen-shop .col-panel .empty-state,
body.v2.screen-inventory .col-panel .empty-state { color: #f0e2c4; }

/* O palco do Shrine é interativo (slots sobre a arte). Ele preenche a tela
   inteira como a cena da fazenda: a largura é dirigida para que a altura da
   arte sempre cubra a viewport, ancorada embaixo e centralizada (as bordas
   laterais recortam, o santuário fica central). Os slots são % deste elemento,
   então continuam alinhados à arte em qualquer tamanho. Fica no z-index 0 do
   painel (col-panel z-40), logo abaixo do HUD (z-45) e do dock (z-44), como as
   fazendas — arte imersiva por baixo da moldura fixa. */
body.v2 #shrine-panel .shrine-stage {
  position: fixed; left: 50%; bottom: 0; transform: translateX(-50%);
  /* Ride the shared play-frame exactly like the farm stage: COVER on a portrait
     phone, CONTAIN in landscape. Reading --stage-w (not a hardcoded max()) is
     what makes the landscape override actually take — a duplicate width rule
     here would win on source order and the shrine would overflow off the top,
     leaving its upper slots unreachable. The art's own 852/1846 ratio drives the
     height via aspect-ratio below; the ~0.2% gap vs the frame ratio is
     imperceptible and the slots are % of this box, so they stay on the art. */
  width: var(--stage-w);
  margin: 0; border-radius: 0; box-shadow: none;
  z-index: 0;
}
/* Shrine V2: o texto e o mostruário de bônus flutuam sobre o céu pintado acima
   do santuário — o palco é a base e o overlay é click-through (não bloqueia os
   slots), com um véu que some de cima para baixo para o texto ficar legível. */
body.v2 #shrine-panel { position: relative; display: block; }
body.v2 #shrine-panel .shrine-sky {
  position: absolute; top: 0; left: 0; right: 0; z-index: 3;
  display: flex; flex-direction: column; gap: 8px;
  padding: 4px 10px 22px;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(12, 7, 24, 0.82) 0%, rgba(12, 7, 24, 0.55) 45%, rgba(12, 7, 24, 0) 100%);
}
body.v2 #shrine-panel .shrine-sky .pill { pointer-events: auto; }
body.v2 #shrine-panel .shrine-sky .shrine-sub {
  color: #d6c9f5; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}
body.v2 #shrine-panel .shrine-sky .shrine-note {
  color: #eae3f7; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.92);
}
body.v2 #shrine-panel .shrine-sky .shrine-warn {
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}
/* Minimizar/expandir as notas do shrine. Os mostradores de bônus (pills) ficam
   sempre visíveis; isto só dobra os parágrafos de explicação, e a escolha é
   lembrada. Fica no canto superior-direito sobre o céu (o pai é click-through,
   então o botão reativa o próprio ponteiro); a fileira de pills reserva espaço
   para nenhuma pill correr por baixo dele. */
body.v2 #shrine-panel .shrine-sky .shrine-head { padding-right: 38px; }
body.v2 #shrine-panel .shrine-notes-toggle {
  position: absolute; top: 6px; right: 8px;
  width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; font-weight: 800; line-height: 1;
  color: #f0e6ff; pointer-events: auto; cursor: pointer;
  background: rgba(30, 18, 52, 0.75);
  border: 1px solid rgba(214, 201, 245, 0.45);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.42);
}
body.v2 #shrine-panel .shrine-sky.notes-collapsed .shrine-notes-body { display: none; }
/* Greenhouse: a arte é o fundo do painel — o hero interno sai de cena. */
body.v2 .greenhouse-hero { display: none; }
body.v2 #tab-stake { background: transparent; }
/* Cream headings sit straight on the artwork now (no veil), so a soft dark
   halo keeps them readable over bright sky. */
body.v2 .col-panel .section-head h2,
body.v2 .col-panel .section-head h3 {
  color: #ffe9b0;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 0 10px rgba(0, 0, 0, 0.55);
}
body.v2 .col-panel .section-head .muted,
body.v2 .col-panel > .tab-panel > .muted {
  color: #f0e2c4;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
}
body.v2 .empty-state { color: #cbb591; }

/* The farm column stays on stage behind an open sheet (the mobile rules hide
   it per-screen; in V2 the field must always be visible). */
body.v2 .col-farm { display: block !important; }

/* ---------------- Farm-screen furniture ---------------- */
/* Event banner / daily / tip live in a slim scrollable column in the sky.
   With the dock now at the bottom, this starts right under the HUD and gets
   more headroom, so the streak/quest card is no longer clipped mid-row.
   The column itself is click-through (pointer-events:none) so its empty area
   never steals taps from the plots below — only the cards catch input. */
body.v2 .col-farm {
  position: fixed; z-index: 20;
  left: 0; right: 0; margin: 0 auto;
  /* Below the HUD + boost-chip row AND the farm-title strip (the title's ‹ ›
     farm-switch buttons live at 148px; cards starting there would cover them —
     the old layout only worked because the phantom event-banner bar happened
     to push the first card down by the same amount). */
  top: calc(var(--hud-bottom) + 90px);
  width: min(430px, calc(var(--stage-w) - 20px));
  max-height: 40vh;   /* fallback for webviews without dvh */
  max-height: 40dvh;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none;
  pointer-events: none;
  padding-right: 42px;   /* right lane reserved for the collapse handle */
}
body.v2 .col-farm > .section-head { display: none; }

/* Collapse handle: clears the event/streak/tip cards off the field. Lives in
   the reserved right lane of the sky column so it never covers card content.
   z-21 keeps it above the column but below open menu panels (z-40), so it only
   shows on the farm screen. */
.farm-cards-toggle { display: none; }
body.v2 .farm-cards-toggle {
  display: grid; place-items: center;
  position: fixed; z-index: 21;
  top: calc(var(--hud-bottom) + 46px);
  right: max(10px, calc(50% - 215px + 4px));
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid rgba(255, 220, 160, 0.35);
  background: rgba(20, 14, 6, 0.72);
  color: #ffe9b0; font-size: 16px; font-weight: 800; line-height: 1;
  backdrop-filter: blur(4px);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
  cursor: pointer;
}
body.v2 .farm-cards-toggle::before { content: "\2013"; }        /* – minimize */
body.v2.cards-hidden .farm-cards-toggle::before { content: "\002B"; }  /* + restore */
body.v2.cards-hidden .col-farm { display: none !important; }

/* Decoration-editor shortcut: mirrors .farm-cards-toggle but on the LEFT, one
   band under the buff strip (which sits at --hud-bottom + 2px). Opens the
   immersive decoration editor. Hidden by default; app.js unhides it only when
   the server enables decorations, and body.decor-editing hides it (with the
   rest of the HUD) once the editor is open. */
.decor-fab { display: none; }
body.v2 .decor-fab {
  display: grid; place-items: center;
  position: fixed; z-index: 21;
  top: calc(var(--hud-bottom) + 46px);
  left: max(10px, calc(50% - 215px + 4px));
  width: 34px; height: 34px; border-radius: 50%;
  padding: 0;
  border: 1px solid rgba(255, 220, 160, 0.35);
  background: rgba(20, 14, 6, 0.72);
  color: #ffe9b0; font-size: 17px; line-height: 1;
  backdrop-filter: blur(4px);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
  cursor: pointer;
}
body.v2 .decor-fab[hidden] { display: none; }
body.v2 .decor-fab:active { transform: scale(0.94); }
body.v2 .daily, body.v2 .tip, body.v2 .event-banner {
  /* Above the stage: #plots is a positioned CHILD of .col-farm (z 0), so its
     static siblings would otherwise paint underneath the full-screen scene. */
  position: relative; z-index: 2;
  pointer-events: auto;   /* re-enable input on the cards (column is click-through) */
  background: rgba(20, 14, 6, 0.72);
  border: 1px solid rgba(255, 220, 160, 0.25);
  color: #f5ead2;
  backdrop-filter: blur(4px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
  margin-bottom: 8px;
}
body.v2 .tip-text { color: #f5ead2; }
body.v2 .tip-head { color: #ffd679; }
body.v2 .tip-icon { background: rgba(255, 220, 160, 0.15); border-color: rgba(255, 220, 160, 0.3); }
body.v2 .tip-next { background: rgba(255, 220, 160, 0.12); color: #f5ead2; border-color: rgba(255, 220, 160, 0.3); }
body.v2 .daily .muted { color: #cbb591; }
body.v2 .quest .q-top { color: #f5ead2; }
body.v2 .q-bar { background: rgba(255, 255, 255, 0.14); }
body.v2 .streak-badge { background: rgba(255, 220, 160, 0.14); border-color: rgba(255, 220, 160, 0.3); }
body.v2 .streak-badge small { color: #cbb591; }

/* Bulk actions float over the dirt path, lifted to clear the docked nav.
   Stays at z-20 (below the z-40 panels) so it hides under an open menu.
   Both bars are reparented to <body> by applyV2Mode — they are NOT part of
   the collapsible cards column, so minimizing the cards keeps them on stage.
   The strips are click-through; only the buttons/pill row catch taps. */
body.v2 .farm-actions {
  position: fixed; z-index: 20;
  left: 0; right: 0; margin: 0 auto;
  /* Lifted well clear of the docked nav so the bar reads as its own strip. */
  bottom: calc(104px + env(safe-area-inset-bottom));
  width: min(430px, calc(var(--stage-w) - 20px));
  pointer-events: none;
}
body.v2 .farm-actions .btn { pointer-events: auto; }
/* Buy-farm bar docks right under the farm-title strip up top. While it's up,
   the cards column starts a step lower (body.buy-farm-visible, set by
   renderFarmSwitcher) so the first card never hides the button. */
body.v2 .farm-switcher {
  position: fixed; z-index: 21;
  left: 0; right: 0; margin: 0 auto;
  top: calc(var(--hud-bottom) + 92px);
  width: min(430px, calc(var(--stage-w) - 20px));
  display: flex; justify-content: center;
  pointer-events: none;
}
body.v2 .farm-switcher .farm-switch-row { pointer-events: auto; }
body.v2.buy-farm-visible .col-farm { top: calc(var(--hud-bottom) + 142px); }
body.v2 .farm-switch-row {
  background: rgba(20, 14, 6, 0.72);
  border-color: rgba(255, 220, 160, 0.3);
  backdrop-filter: blur(4px);
  padding: 3px 6px;
}
/* Slim the Buy-farm button so it matches the smaller Farm X/N strip above it. */
body.v2 .farm-switch-row .farm-buy { padding: 5px 12px; font-size: 11px; }

/* Toast clears the docked nav and the floating bulk-action bar. */
body.v2 #toast { bottom: calc(164px + env(safe-area-inset-bottom)); }

/* ---------------- V2: Moonbloom Shrine portrait stage ---------------- */
/* The portrait shrine art replaces the square one; slot coordinates come from
   SHRINE_SLOT_POS_V2 in app.js. Two skins — day (default) and night (added by
   renderShrine after dark) — each with its own frame layout. */
body.v2 .shrine-stage {
  aspect-ratio: 852 / 1846;   /* full art, uncropped */
  background-image: url("assets/moonbloom-shrine-portrait-day.png?v=1");
  image-rendering: pixelated;
}
body.v2 .shrine-stage.shrine-night {
  background-image: url("assets/moonbloom-shrine-portrait-night.png?v=1");
}

/* ---------------- Desktop: two phones side by side ----------------
   A wide landscape window has room for two portrait "phones": the FARM on the
   left (always live) and the MENU on the right — its tab artworks and lists
   permanently open as a second phone, instead of sliding up over the field.
   Below this width we keep the single centred frame; portrait phones are
   untouched. Every layer is already sized to --stage-w and centred on the
   viewport, so this only (a) makes --stage-w one phone wide and (b) slides the
   farm group into the left phone and the menu group into the right.
   NOTE: this block lives at the END of the V2 section on purpose — its
   left/right overrides share specificity with the base rules above, so it must
   come later in source order to win. */
@media (orientation: landscape) and (min-width: 820px) {
  body.v2 {
    --phone-gap: 24px;
    /* Each phone is half the width (minus the gap), but sized to a real phone's
       screen ratio (--phone-zoom) rather than the raw canvas, so the farm/shrine
       sky crops off the top and the tab backdrops crop like on a phone. Capped
       at half the width so the pair always fits side by side. */
    --phone-w: min(calc(50vw - var(--phone-gap)), calc(100vh * var(--scene-ar) * var(--phone-zoom)));
    --phone-w: min(calc(50vw - var(--phone-gap)), calc(100dvh * var(--scene-ar) * var(--phone-zoom)));
    --stage-w: var(--phone-w);
  }

  /* Farm group → left phone. Each element keeps its own width and centres
     inside the left column box via margin:auto. */
  body.v2 .hud,
  body.v2 .farm-scene,
  body.v2 .col-farm,
  body.v2 .farm-buffs,
  body.v2 .farm-title,
  body.v2 .farm-actions,
  body.v2 .farm-switcher {
    left: calc(50vw - var(--phone-w) - var(--phone-gap) / 2);
    right: calc(50vw + var(--phone-gap) / 2);
    margin: 0 auto;
  }

  /* Menu group → right phone, permanently open (never slides away). */
  body.v2 .col-panel {
    left: calc(50vw + var(--phone-gap) / 2);
    right: calc(50vw - var(--phone-gap) / 2 - var(--phone-w));
    width: auto; max-width: none; margin: 0;
    transform: none !important;
  }
  /* The section dock rides the bottom of the menu phone so every tab is
     reachable there; the farm has its own phone, so its Farm entry is dropped. */
  body.v2 .bottom-nav {
    left: calc(50vw + var(--phone-gap) / 2);
    right: calc(50vw - var(--phone-gap) / 2 - var(--phone-w));
    margin: 0 auto;
  }
  body.v2 .bottom-nav .nav-item[data-screen="farm"] { display: none; }

  /* The Shrine's interactive stage is fixed to the viewport centre by default;
     re-centre it on the right (menu) phone so its slots land on its own art. */
  body.v2 #shrine-panel .shrine-stage {
    left: calc(50vw + var(--phone-gap) / 2 + var(--phone-w) / 2);
  }
}

/* The desktop zoom crops only the top sky of the bottom-anchored farm, so its
   decorative path/foreground would eat ~45% of the phone below the plots — a big
   empty band under the field with nothing in it. Drop the farm scene so that
   dead foreground crops off the bottom and the whole fenced field sits lower and
   centred, close to a phone's framing. Landscape-only (portrait phones already
   frame right) and farm-only (the shrine and menu tabs use their own bottoms).
   Placed after the base .farm-scene rule so this bottom wins the cascade. */
@media (orientation: landscape) {
  body.v2 .farm-scene { bottom: -15vh; }   /* fallback for webviews without dvh */
  body.v2 .farm-scene { bottom: -15dvh; }
}



/* ---- Adventurer's Den (DEV) ---------------------------------------------- */
.den-hero {
  background: linear-gradient(135deg, #3a2c5a, #241a3a);
  border: 1px solid rgba(178, 148, 255, 0.35);
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 12px;
  color: #f3ecff;
}
.den-hero-title { font-family: 'Fredoka', sans-serif; font-weight: 700; font-size: 1.15rem; }
.den-hero-sub { font-size: 0.82rem; opacity: 0.85; margin-top: 4px; }
.den-list { display: flex; flex-direction: column; gap: 8px; }
.den-empty { padding: 8px 4px; font-size: 0.85rem; }
.den-row, .den-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.den-row-ico, .den-item-ico { font-size: 1.5rem; flex: 0 0 auto; }
/* Den rows use the Shop's farmer sprite miniature. The sprite <i> is inline by
   default, so give it a block context (and center it) for its fixed width/height
   to apply — matching the Shop's .farmer-pick chip. */
.den-row-ico { display: inline-grid; place-items: center; min-width: 34px; }
.den-row-ico .farmer-ico { display: block; }
.den-row-body, .den-item-body { flex: 1 1 auto; min-width: 0; }
.den-row-name, .den-item-name { font-weight: 700; }
.den-hearts { font-size: 0.72rem; letter-spacing: 1px; margin-left: 4px; white-space: nowrap; vertical-align: middle; }
.den-item-blurb { font-size: 0.8rem; opacity: 0.82; margin-top: 2px; }
.den-item.locked { opacity: 0.55; }
.den-item.owned { border-color: rgba(120, 220, 140, 0.5); background: rgba(90, 200, 120, 0.10); }
.den-exp-ready { color: #7ee0a0; font-size: 0.82rem; }
.den-exp-timer { color: #cbb8ff; font-size: 0.82rem; }
.den-dev { margin-top: 12px; }

/* The Den panel sits on a dark portrait (body.v2.screen-den .col-panel), but the
   row/treasure text inherits the app's dark --ink green — invisible against it.
   Lift the names, blurbs and muted sub-labels off the background so the
   translucent rows stay legible. Section headings are already handled by the
   shared body.v2 .col-panel .section-head rule. */
body.v2.screen-den .col-panel .den-row-name,
body.v2.screen-den .col-panel .den-item-name {
  color: #f3ecff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
body.v2.screen-den .col-panel .den-item-blurb { color: #ded4f5; opacity: 1; }
body.v2.screen-den .col-panel .den-empty,
body.v2.screen-den .col-panel .den-row .muted { color: #cabfe6; }

/* ---- Adventurer's Den equipment (DEV) ------------------------------------ */
.den-farms { display: flex; flex-direction: column; gap: 10px; }
.den-farm {
  padding: 10px 12px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.den-farm-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.den-slots { display: flex; gap: 8px; margin-bottom: 8px; }
.den-slot {
  width: 40px; height: 40px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.15rem; position: relative;
  border: 1px dashed rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.03); color: inherit;
}
.den-slot.filled { border-style: solid; border-color: rgba(178, 148, 255, 0.55); background: rgba(120, 90, 200, 0.18); cursor: pointer; }
.den-slot.empty { opacity: 0.4; }
.den-slot-x { position: absolute; top: -6px; right: -6px; font-size: 0.7rem; background: #b24a4a; color: #fff; border-radius: 50%; width: 15px; height: 15px; line-height: 15px; text-align: center; }
.den-equip-choices { display: flex; flex-wrap: wrap; gap: 6px; }
.den-hint { font-size: 0.78rem; }

/* ---- Den equipment slots inside the farmer config modal (DEV) ------------ */
.farmer-gear {
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: 12px;
  background: rgba(120, 90, 200, 0.10);
  border: 1px solid rgba(178, 148, 255, 0.30);
}
.farmer-gear-head { font-weight: 700; margin-bottom: 8px; display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap; }
.farmer-gear .den-slots { display: flex; gap: 8px; margin-bottom: 8px; }
.farmer-gear .den-equip-choices { display: flex; flex-wrap: wrap; gap: 6px; }
.den-item-where { font-size: 0.76rem; opacity: 0.9; margin-top: 3px; color: #cbb8ff; }

/* ---- Den item icons (real art, replacing the emoji) ---------------------- */
img.den-ico { object-fit: contain; vertical-align: middle; display: inline-block; width: 1.5em; height: 1.5em; }
.den-item-ico { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; }
.den-item-ico img.den-ico { width: 46px; height: 46px; }
.den-slot img.den-ico { width: 30px; height: 30px; }
.icon-chip img.den-ico { width: 26px; height: 26px; }
.den-equip-choices img.den-ico { width: 20px; height: 20px; margin-right: 2px; }

/* ============================================================================
   Den return battle (DEV) — the claim's raven-ambush cutscene.
   Played by DenBattle in app.js over the whole game (see /den/claim).
   All classes/keyframes are dbt- prefixed; sprite frames are driven by ONE
   var-parametrized keyframe (dbt-sprite): the JS sets --r/--c0/--c1 + steps().
   Actor cells: --aw/--ah display size, --cols/--rows the sheet grid.
   ========================================================================== */
.dbt-stage {
  position: fixed; inset: 0; z-index: 200; overflow: hidden;
  --dbt-bw: clamp(64px, 14vmin, 130px);
  background: #101c12 center bottom / cover no-repeat;
  font-family: inherit; user-select: none; -webkit-user-select: none;
  /* iOS: sem o flash cinza nativo sobre o inimigo tocado (tap highlight é
     herdado), sem callout de long-press (golpe de segurar) e sem zoom de
     duplo-toque no meio da chuva de taps. */
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  touch-action: manipulation;
}
.dbt-stage .dbt-actor { touch-action: manipulation; }
.dbt-stage::after { /* vinheta */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 45%, transparent 55%, rgba(8, 18, 10, 0.5) 100%);
}
/* Profundidade: placeActor() (app.js) seta z-index inline por ator a partir do
   bottom — mais baixo na tela = mais perto da câmera = na frente (faixa
   ~330–605). As camadas fixas abaixo (sombra 5 · FX 700+ · HUD 900+ · fade
   1000+) cercam essa faixa. */
.dbt-actor {
  position: absolute; display: block; width: var(--aw); height: var(--ah);
  transform: translateX(-50%) scaleX(1); z-index: 450; pointer-events: none;
}
.dbt-actor .dbt-bob { display: block; width: 100%; height: 100%; }
.dbt-actor .dbt-abody {
  display: block; width: 100%; height: 100%;
  background: transparent 0 0 no-repeat;
  background-size: calc(var(--aw) * var(--cols)) calc(var(--ah) * var(--rows));
  image-rendering: pixelated;
  filter: drop-shadow(2px 4px 3px rgba(0, 0, 0, 0.4));
  transform-origin: 50% 92%;
}
@keyframes dbt-sprite {
  from { background-position: calc(var(--aw) * -1 * var(--c0)) calc(var(--ah) * -1 * var(--r)); }
  to   { background-position: calc(var(--aw) * -1 * var(--c1)) calc(var(--ah) * -1 * var(--r)); }
}
.dbt-actor.dbt-float .dbt-bob { animation: dbt-bob 1.5s ease-in-out infinite; }
@keyframes dbt-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6%); }
}
@keyframes dbt-flash { /* levar dano */
  0%   { filter: brightness(3.5) saturate(0.2) drop-shadow(2px 4px 3px rgba(0,0,0,0.4)); }
  100% { filter: brightness(1) drop-shadow(2px 4px 3px rgba(0,0,0,0.4)); }
}
@keyframes dbt-die { /* corvo tomba para trás (pivô nos pés) */
  0%   { transform: rotate(0deg) translateY(0); filter: brightness(1.5) drop-shadow(2px 4px 3px rgba(0,0,0,0.4)); }
  55%  { transform: rotate(74deg) translateY(4%); }
  100% { transform: rotate(88deg) translateY(16%); filter: brightness(1.5) saturate(0.3); }
}
@keyframes dbt-wobble { /* farmer tonto na derrota */
  0%, 100% { transform: rotate(0deg); }
  25%      { transform: rotate(-10deg); }
  75%      { transform: rotate(10deg); }
}
.dbt-actor.dbt-defeated { transition: opacity 0.5s ease-in 0.15s; opacity: 0; }
.dbt-shadow {
  position: absolute; z-index: 5; pointer-events: none;
  width: calc(var(--dbt-bw) * 0.62); height: calc(var(--dbt-bw) * 0.16);
  background: radial-gradient(50% 50% at 50% 50%, rgba(0, 0, 0, 0.35), transparent 70%);
  transform: translateX(-50%); border-radius: 50%;
  transition: opacity 0.4s;
}
.dbt-hp {
  position: absolute; left: 50%; bottom: 100%; transform: translateX(-50%);
  display: flex; gap: 4px; font-size: calc(var(--dbt-bw) * 0.28);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); z-index: 8;
}
.dbt-hp span.off { filter: grayscale(1) brightness(0.5); transform: scale(0.8); }
.dbt-hp span { transition: filter 0.2s, transform 0.2s; }
.dbt-fx { position: absolute; z-index: 800; pointer-events: none; transform: translate(-50%, -50%); }
.dbt-pow {
  font-weight: 800; font-size: clamp(20px, 4.5vmin, 42px);
  color: #ffd23e; -webkit-text-stroke: 2px #7a2c0c;
  animation: dbt-pow 0.55s cubic-bezier(0.2, 1.6, 0.4, 1) forwards;
}
.dbt-pow.bad { color: #ff6257; -webkit-text-stroke: 2px #ffffff; }
@keyframes dbt-pow {
  0%   { transform: translate(-50%, -50%) scale(0.2) rotate(-14deg); opacity: 0; }
  35%  { transform: translate(-50%, -50%) scale(1.25) rotate(6deg); opacity: 1; }
  100% { transform: translate(-50%, -90%) scale(1) rotate(0deg); opacity: 0; }
}
.dbt-alert {
  font-weight: 800; font-size: clamp(22px, 5vmin, 46px);
  color: #ff5252; -webkit-text-stroke: 2px #fff;
  animation: dbt-alert 0.7s cubic-bezier(0.2, 1.8, 0.4, 1) forwards;
}
@keyframes dbt-alert {
  0%   { transform: translate(-50%, -20%) scale(0); opacity: 0; }
  40%  { transform: translate(-50%, -60%) scale(1.3); opacity: 1; }
  100% { transform: translate(-50%, -70%) scale(1); opacity: 0; }
}
.dbt-spark {
  position: absolute; z-index: 800; pointer-events: none;
  font-size: clamp(12px, 2.6vmin, 24px);
  animation: dbt-spark 0.85s ease-out forwards;
}
@keyframes dbt-spark {
  from { transform: translate(-50%, -50%) scale(0.4) rotate(0deg); opacity: 1; }
  to   { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(1.15) rotate(var(--rot, 0deg)); opacity: 0; }
}
.dbt-chip {
  position: absolute; left: 50%; top: max(12px, env(safe-area-inset-top)); transform: translateX(-50%);
  z-index: 900; font-weight: 700; font-size: 12px; color: rgba(255, 247, 224, 0.9);
  background: rgba(20, 32, 20, 0.6); padding: 5px 12px; border-radius: 999px;
  white-space: nowrap; max-width: 94%; overflow: hidden; text-overflow: ellipsis;
}
.dbt-skip {
  position: absolute; left: 50%; bottom: max(10px, env(safe-area-inset-bottom)); transform: translateX(-50%);
  z-index: 1001; font-weight: 700; font-size: 11px; color: rgba(255, 247, 224, 0.7);
  background: rgba(20, 32, 20, 0.55); padding: 6px 12px; border-radius: 999px; white-space: nowrap;
  pointer-events: auto; cursor: pointer;
}
/* Golpe ativo (Enxame Mortal): o inimigo tocável pulsa dourado, a dica
   flutua, e o enxame renderiza acima de todos os atores. */
.dbt-actor.dbt-swarm { z-index: 700; }
.dbt-actor.dbt-tappable { cursor: pointer; }
.dbt-actor.dbt-tappable .dbt-bob { animation: dbt-tap-pulse 1.1s ease-in-out infinite; }
@keyframes dbt-tap-pulse {
  0%, 100% { filter: none; }
  50%      { filter: drop-shadow(0 0 10px rgba(255, 210, 62, 0.95)) drop-shadow(0 0 22px rgba(255, 210, 62, 0.5)); }
}
.dbt-hint {
  /* Mid-screen, in the player's line of sight, but above the play area: the
     tallest counter stack (⚡/✊ chip over a back-row elite's crown+hearts)
     tops out around 53% from the bottom, and at 36% the pill sat right on it. */
  position: absolute; left: 50%; bottom: 54%; transform: translateX(-50%);
  z-index: 900; font-weight: 800; font-size: clamp(13px, 3vmin, 20px);
  color: #ffe19a; background: rgba(20, 32, 20, 0.72);
  border: 1.5px solid rgba(242, 181, 68, 0.8);
  padding: 8px 16px; border-radius: 999px; white-space: nowrap; max-width: 94%;
  overflow: hidden; text-overflow: ellipsis; pointer-events: none;
  animation: dbt-hint-bob 1.4s ease-in-out infinite;
}
.dbt-hint[hidden] { display: none; }
/* Contador de quota "⚡ x/N" acima dos corações do inimigo. */
.dbt-quota {
  position: absolute; transform: translateX(-50%); z-index: 800; white-space: nowrap;
  font-weight: 800; font-size: calc(var(--dbt-bw) * 0.22);
  color: #ffd23e; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.65);
}
.dbt-quota.fail { color: #ff6257; animation: dbt-quota-fail 0.4s ease-out 2; }
@keyframes dbt-quota-fail {
  0%, 100% { transform: translateX(-50%) scale(1); }
  50%      { transform: translateX(-50%) scale(1.25); }
}
/* Inimigo elite: aura arcana permanente + coroa nos corações. */
.dbt-actor.dbt-elite .dbt-abody {
  filter: drop-shadow(0 0 8px rgba(168, 85, 247, 0.9)) drop-shadow(0 0 20px rgba(168, 85, 247, 0.45)) drop-shadow(2px 4px 3px rgba(0, 0, 0, 0.4));
}
.dbt-crown { margin-right: 0.2em; }
@keyframes dbt-hint-bob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(-6px); }
}
.dbt-banner {
  position: absolute; left: 50%; top: 32%; transform: translate(-50%, -50%) scale(0);
  z-index: 900; text-align: center; width: 94%;
  font-weight: 800; font-size: clamp(30px, 7vmin, 64px);
  color: #ffd23e; -webkit-text-stroke: 2.5px #7a2c0c;
  text-shadow: 0 6px 18px rgba(0, 0, 0, 0.55);
}
.dbt-banner.lose { color: #ff6257; -webkit-text-stroke: 2.5px #4a0e0e; }
.dbt-banner.show { animation: dbt-banner-pop 0.8s cubic-bezier(0.2, 1.7, 0.4, 1) forwards; }
@keyframes dbt-banner-pop {
  from { transform: translate(-50%, -50%) scale(0) rotate(-8deg); }
  to   { transform: translate(-50%, -50%) scale(1) rotate(0deg); }
}
.dbt-banner small {
  display: block; font-size: 0.36em; color: #fff7e0;
  -webkit-text-stroke: 0; margin-top: 0.4em; font-weight: 800;
}
.dbt-loot {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(0);
  z-index: 900; text-align: center;
  background: rgba(22, 34, 20, 0.88); border: 2px solid #f2b544; border-radius: 18px;
  padding: 12px 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}
.dbt-loot.show { animation: dbt-banner-pop 0.7s cubic-bezier(0.2, 1.7, 0.4, 1) 0.3s forwards; }
.dbt-loot .dbt-loot-title {
  margin: 0 0 6px; font-weight: 800; font-size: clamp(13px, 3vmin, 22px);
  color: #ffe19a; letter-spacing: 0.06em; text-transform: uppercase;
}
.dbt-loot .dbt-loot-item {
  display: inline-flex; align-items: center; gap: 0.35em;
  font-weight: 800; font-size: clamp(15px, 3.4vmin, 26px); color: #fff7e0;
  background: rgba(255, 247, 224, 0.12); border-radius: 999px; padding: 0.25em 0.75em;
}
.dbt-loot img.den-ico { width: 1.3em; height: 1.3em; }
.dbt-fade { position: absolute; inset: 0; background: #101c12; z-index: 1000; opacity: 1; transition: opacity 0.7s; pointer-events: none; }
.dbt-fade.out { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .dbt-actor .dbt-abody, .dbt-actor .dbt-bob { animation: none !important; }
}
