/* =============================================================================
 * PIE CLICKER 2 -- components.css
 * The pie itself, cards, upgrade grid, tooltip, achievements, stats, settings,
 * store/production/reality lists, toasts, modals and the ascension zone.
 * ========================================================================== */

/* =============================== THE PIE ================================= */

.pie-header { text-align: center; flex: 0 0 auto; }

.big-counter {
  font-family: var(--font-num);
  font-size: clamp(30px, 4.6vw, 56px);
  font-weight: 750; letter-spacing: -.02em;
  color: var(--gold-soft);
  text-shadow: 0 0 34px rgba(240,178,63,.30), 0 2px 0 rgba(0,0,0,.35);
  line-height: 1.05;
  transition: transform var(--t-fast) var(--ease);
  will-change: transform;
}
.big-counter-label {
  font-size: 12px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--muted); font-weight: 700; margin-top: 2px;
}

/* Pies on the left, Reality Shards immediately to their right. The gap is the
   only separator -- a divider here reads as a second panel at small sizes. */
.counter-row {
  display: flex; align-items: flex-start; justify-content: center;
  gap: clamp(14px, 3.2vw, 34px);
}
.counter-block { min-width: 0; }
.shard-counter {
  font-size: clamp(20px, 3vw, 36px);
  color: var(--reality);
  text-shadow: 0 0 30px rgba(169,139,255,.32), 0 2px 0 rgba(0,0,0,.35);
}
.shard-label { color: var(--reality-2); opacity: .95; }

.temp-readout { margin-top: 10px; display: inline-flex; flex-direction: column; align-items: center; gap: 5px; }
.temp-value {
  font-family: var(--font-num); font-size: 19px; font-weight: 700;
  color: var(--gold); transition: color var(--t-med) var(--ease);
}
.temp-bar {
  position: relative;
  width: min(280px, 46vw); height: 7px;
  border-radius: 999px; overflow: hidden;
  background: linear-gradient(90deg, #2b4a63, #33507a 18%, #4a4130 42%, #6b3a1e 68%, #7a2417);
  border: 1px solid var(--line);
}
.temp-fill {
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 2px; margin-left: -1px;
  background: #fff;
  box-shadow: 0 0 9px 2px rgba(255,255,255,.8);
  border-radius: 2px;
  transition: left var(--t-slow) var(--ease);
}
/* left/width are set by ui.js so the band tracks the real optimal range. */
.temp-optimal-band {
  position: absolute; top: 0; bottom: 0;
  left: 37.5%; width: 3%;
  background: rgba(124,196,111,.55);
  box-shadow: inset 0 0 0 1px rgba(124,196,111,.8);
  pointer-events: none;
}
.temp-status { font-size: 11.5px; color: var(--muted); font-weight: 600; letter-spacing: .03em; }
.temp-status.is-cold     { color: var(--cold); }
.temp-status.is-cool     { color: #8fb8cf; }
.temp-status.is-optimal  { color: var(--good); }
.temp-status.is-hot      { color: var(--hot); }
.temp-status.is-overheat { color: #ff5c5c; }

/* Particles and floating numbers are absolutely positioned inside the stage
   and routinely fly outside it. Without a clip here they enlarge #pie-area's
   scrollable overflow, so every critical click made the centre column
   scrollable and flashed a scrollbar. `clip` (not `hidden`) keeps the box
   unscrollable, and the clip margin lets the effects spill visually anyway. */
.pie-stage {
  /* One source of truth for the pie's size: the click ring is sized from it
     too, so the burst always reads as coming off the pie and can never grow
     larger than the stage that clips it. */
  --pie-size: min(46vh, 36vw, 380px);
  position: relative; flex: 1 1 auto;
  display: flex; align-items: center; justify-content: center;
  width: 100%; min-height: 220px;
  margin: 6px 0;
  overflow: clip;
  overflow-clip-margin: 48px;
}

.pie-glow {
  position: absolute; width: min(56vh, 44vw, 460px); aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(240,178,63,.20), rgba(240,178,63,0) 66%);
  pointer-events: none;
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.pie-shadow {
  position: absolute; bottom: 6%;
  width: min(40vh, 32vw, 330px); height: 26px;
  border-radius: 50%;
  background: radial-gradient(ellipse, rgba(0,0,0,.55), transparent 70%);
  filter: blur(5px);
  pointer-events: none;
}

.pie {
  position: relative;
  width: var(--pie-size); aspect-ratio: 1;
  border-radius: 50%;
  transform-origin: 50% 56%;
  will-change: transform;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  user-select: none;
  transition: filter var(--t-fast) var(--ease);
  /* Lives here rather than on .pie-crust: the crust spins, this must not. */
  box-shadow: 0 10px 24px -6px rgba(0,0,0,.6);
}
.pie:hover { filter: brightness(1.05); }
.pie:active { filter: brightness(.97); }

/* Dish beneath the crust gives the pie real depth. */
.pie-dish {
  position: absolute; inset: 3% 1% -2%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 34%, #7a6050, #433327 58%, #241a14 88%, #180f0b);
  box-shadow:
    0 18px 34px -10px rgba(0,0,0,.85),
    inset 0 -9px 16px rgba(0,0,0,.55),
    inset 0 3px 6px rgba(255,215,175,.10);
}

/* Everything baked into the pie lives in here and turns as one piece. Keep it
   free of directional light: a highlight that rotates reads as the sun going
   round the pie rather than the pie going round under the sun. */
.pie-body {
  position: absolute; inset: 0;
  border-radius: 50%;
}

/* Outer crust ring. Radially symmetric on purpose -- browning ramps outward,
   which looks the same at every angle. The light comes from .pie-shine. */
.pie-crust {
  position: absolute; inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 50%, #f2c78d, #e0aa6a 42%, #c0863f 66%, #8f5f2b 84%, #5f3c18 96%, #452a11);
  /* A ring, not a direction -- identical at every angle, so it survives the spin. */
  box-shadow: inset 0 0 22px rgba(84,46,14,.42);
}
/* Crimped edge bumps generated by ui.js. Size and browning vary per bump; the
   highlight does not -- one light source, so every bump catches it top-left. */
.crust-bump {
  position: absolute; top: 50%; left: 50%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 36% 28%, #fbd5a0 4%, #e8b878 34%, #c48f4e 62%, #96632e 84%, #68431c);
  box-shadow:
    inset 0 -3px 5px rgba(104,62,22,.45),
    inset 0 2px 4px rgba(255,238,200,.38);
  pointer-events: none;
}
/* Painted over the bumps (they are its children): the outer edge of a crust
   always catches the most oven, so the crimp browns as it turns away. */
.pie-crust::after {
  content: ''; position: absolute; inset: 0;
  border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle,
    rgba(96,54,18,.10) 62%, rgba(112,64,22,.34) 82%, rgba(74,40,12,.60) 95%, rgba(52,27,8,.72) 100%);
}

/* Filling well */
.pie-filling {
  position: absolute; inset: 12.5%;
  border-radius: 50%;
  overflow: hidden;
  background:
    /* Centred, not lit from 40%/30%: this turns with .pie-body, and an off-centre
       highlight here is the one thing that made the spin read as the light
       swinging round the pie. The top-lighting comes from .pie-shine instead. */
    radial-gradient(circle at 50% 50%, #e05f3f, #cd4430 22%, #b13323 46%, #8d241a 70%, #661610 88%, #440f0b);
  /* Inside .pie-body, so this turns with the pie: symmetric only. A directional
     inset shadow here sweeps round the filling once a minute. */
  box-shadow:
    inset 0 0 20px rgba(0,0,0,.45),
    0 0 0 3px rgba(126,78,32,.6);
}
/* Directional shade plus the glossy bubbles of a filling that has just come
   out of the oven. Sits under the lattice, so the strips read as laid on top. */
.pie-filling-shade {
  position: absolute; inset: 0; border-radius: 50%;
  background:
    radial-gradient(circle at 31% 61%, rgba(255,196,152,.46) 0 3.4%, transparent 3.9%),
    radial-gradient(circle at 63% 27%, rgba(255,212,170,.42) 0 2.5%, transparent 3%),
    radial-gradient(circle at 46% 45%, rgba(255,182,142,.36) 0 1.8%, transparent 2.3%),
    radial-gradient(circle at 73% 57%, rgba(255,204,160,.34) 0 2.8%, transparent 3.3%),
    radial-gradient(circle at 22% 36%, rgba(255,190,148,.32) 0 2.0%, transparent 2.5%),
    radial-gradient(circle at 40% 79%, rgba(255,186,142,.30) 0 2.3%, transparent 2.8%),
    radial-gradient(circle at 80% 40%, rgba(255,198,154,.26) 0 1.7%, transparent 2.2%),
    radial-gradient(circle at 55% 74%, rgba(112,20,14,.48) 0 3.6%, transparent 4.1%),
    radial-gradient(circle at 37% 20%, rgba(118,24,16,.40) 0 2.6%, transparent 3.1%),
    radial-gradient(circle at 66% 68%, rgba(104,18,12,.34) 0 3.0%, transparent 3.5%);
}
/* Lattice strips generated by ui.js */
.pie-lattice { position: absolute; inset: 0; }
/* Each direction is a rotated container (see ui.js buildPieArt) so the strips
   stay evenly spaced whatever the angle. The container is oversized because
   rotation pushes its corners outside the filling, which clips it. */
.lattice-set {
  position: absolute; left: -30%; top: -30%; width: 160%; height: 160%;
  transform-origin: 50% 50%;
}
/* `top` is set per strip by ui.js; the negative margin centres it on that line.
   Set B additionally carries a mask that cuts it away at the crossings it
   passes under -- that mask is the whole weave. */
/* height / margin-top are written by ui.js so they track THICK. */
.lattice-strip {
  position: absolute; left: 0; width: 100%; height: 6.9%;
  top: 50%; margin-top: -3.45%;
  border-radius: 3px;
  background:
    linear-gradient(180deg,
      #a06c33 0%, #e8bd82 7%, #ffe0b0 20%, #edbf85 44%,
      #cf9a56 70%, #a56f36 90%, #7d5124 100%);
  box-shadow:
    0 2px 5px rgba(52,28,8,.55),
    inset 0 1px 1px rgba(255,244,215,.6),
    inset 0 -1px 2px rgba(96,58,22,.45);
}
/* The two directions are baked a shade apart -- the same dough, but one set
   sat a little higher in the oven. */
.lattice-strip.b {
  background:
    linear-gradient(180deg,
      #96632e 0%, #dfb27a 7%, #fbd8a6 20%, #e4b57c 44%,
      #c5904f 70%, #9a6631 90%, #734a21 100%);
}
/* Baked browning over the lattice: everything darkens toward the crust, the
   way the outer edge of a real pie catches more heat than its middle. */
.pie-bake {
  position: absolute; inset: 0; border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle at 50% 50%,
    transparent 44%, rgba(104,58,20,.22) 70%, rgba(66,34,10,.48) 88%, rgba(46,22,6,.64) 100%);
}

/* Raised inner lip where the lattice ends tuck under the crust. */
.pie-rim {
  position: absolute; inset: 12.2%;
  border-radius: 50%;
  pointer-events: none;
  /* Keep these blurs tight. At 17px the top shadow reached a quarter of the way
     across the filling and desaturated the red into a brown haze that read as
     fog on glass -- the rim is a contact shadow, not a vignette. .pie-bake
     already handles the broad browning toward the edge. */
  box-shadow:
    inset 0 0 5px rgba(58,30,10,.6),
    inset 0 3px 6px rgba(44,22,6,.45),
    inset 0 -2px 5px rgba(44,22,6,.28);
}

/* The crust's share of the fixed light, masked to the ring. It is much stronger
   than anything the filling can take -- a broad top-light laid over the dark
   filling as well reads as fog on glass rather than as a lit dome. */
.pie-form {
  position: absolute; inset: 0;
  border-radius: 50%; pointer-events: none;
  background:
    linear-gradient(180deg, rgba(255,235,200,.42) 0%, rgba(255,235,200,.15) 22%, transparent 48%),
    linear-gradient(0deg, rgba(36,18,4,.58) 0%, rgba(36,18,4,.27) 20%, transparent 46%);
  /* The filling is inset 12.5%, i.e. 75% of the pie's radius. Start the cut
     outside that: feathering across the boundary instead spills the strong
     top-light onto the filling's outer ring, which is the fog it exists to
     avoid. The rim's contact shadow covers the join. */
  -webkit-mask-image: radial-gradient(circle, transparent 76%, #000 83%);
  mask-image: radial-gradient(circle, transparent 76%, #000 83%);
}

/* One specular pass over the whole pie, crust included, so the crust and the
   filling agree about where the light is. */
.pie-shine {
  position: absolute; inset: 0; border-radius: 50%;
  pointer-events: none;
  background:
    /* a tight specular, not a veil -- over the dark filling a broad one fogs */
    radial-gradient(ellipse 22% 15% at 32% 17%, rgba(255,246,226,.26), transparent 74%),
    /* the filling's own gradient is centred now, so this is what lights it */
    linear-gradient(180deg, rgba(255,233,197,.20) 0%, rgba(255,233,197,.07) 26%, transparent 52%),
    linear-gradient(0deg, rgba(38,19,4,.34) 0%, rgba(38,19,4,.14) 24%, transparent 50%),
    /* the dome falls away at its edge whichever way the pie is facing */
    radial-gradient(circle at 50% 50%, transparent 58%, rgba(40,20,4,.28) 88%, rgba(30,14,2,.42) 100%),
    /* warm bounce off the dish along the lower rim */
    radial-gradient(ellipse 66% 30% at 50% 98%, rgba(255,192,118,.24), transparent 74%);
}

.pie-steam { position: absolute; left: 0; right: 0; top: -14%; height: 34%; pointer-events: none; }
.steam-puff {
  position: absolute; bottom: 0;
  width: 13px; height: 13px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,240,220,.55), rgba(255,240,220,0) 70%);
  filter: blur(1.5px);
}

/* --------------------------------------------------------- centre extras -- */
.pie-substats {
  flex: 0 0 auto;
  display: flex; gap: 10px; flex-wrap: wrap; justify-content: center;
  margin-top: 4px;
}
.substat {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 7px 16px;
  background: rgba(255,236,205,.04);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  min-width: 108px;
}
.s-label { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--faint); font-weight: 700; }
.s-value { font-family: var(--font-num); font-size: 15px; font-weight: 650; color: var(--gold-soft); }

/* ------------------------------------------------------------- ascension -- */
.ascend-zone { flex: 0 0 auto; margin-top: 12px; width: min(520px, 100%); text-align: center; }
.ascend-bar {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: rgba(169,139,255,.14);
  border: 1px solid rgba(169,139,255,.28);
}
.ascend-fill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--reality-2), var(--reality), #d9c6ff);
  box-shadow: 0 0 14px rgba(169,139,255,.6);
  transition: width var(--t-slow) var(--ease);
}
.ascend-caption {
  margin-top: 5px; font-size: 11.5px; color: var(--muted); font-weight: 600; letter-spacing: .04em;
}
.btn-ascend {
  margin-top: 11px;
  display: inline-flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 11px 34px;
  border-radius: var(--radius);
  background: linear-gradient(135deg, var(--reality-2), #8b5cf6 55%, #c4b0ff);
  color: #fff;
  box-shadow: 0 8px 26px -8px rgba(139,92,246,.9), inset 0 1px 0 rgba(255,255,255,.35);
  transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), filter var(--t-fast) var(--ease);
}
.btn-ascend:hover { transform: scaleY(1.05); filter: brightness(1.08); box-shadow: 0 14px 34px -10px rgba(139,92,246,1); }
.btn-ascend:active { transform: translateY(0) scale(.985); }
.asc-title { font-weight: 800; letter-spacing: .18em; font-size: 15px; }
.asc-sub { font-size: 11.5px; opacity: .92; font-family: var(--font-num); }

/* ============================== UPGRADE ROW ============================== */

.upgrade-section {
  flex: 0 0 auto;
  padding: 10px 12px 11px;
  border-bottom: 1px solid var(--line);
  background: rgba(0,0,0,.14);
}
.upgrade-head { display: flex; align-items: center; gap: 7px; margin-bottom: 8px; }
.upgrade-title { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); font-weight: 800; }
.upgrade-collapse {
  display: flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 0; margin: 0;
  cursor: pointer; color: inherit;
}
.upgrade-collapse:hover .upgrade-title { color: var(--text-dim); }
.uc-chev {
  font-size: 10px; line-height: 1; color: var(--faint);
  transition: transform var(--t-fast) var(--ease);
}
.upgrade-section.collapsed .uc-chev { transform: rotate(-90deg); }
.upgrade-section.collapsed .upgrade-body { display: none; }
.upgrade-section.collapsed .upgrade-pager { display: none; }
/* .upgrade-row carries negative margins so its padding can bleed to the
 * section edges. Without a block formatting context here, that -6px bottom
 * margin collapses out through the body whenever the row is tall enough to
 * fill it, making the section 6px shorter with a full page than with a
 * part-full one -- and auto-buy crosses that boundary constantly. flow-root
 * contains the margin, so the reserved height is the height you actually get. */
.upgrade-body { display: flow-root; }

/* One page: the pager holds its space but takes no clicks, so the header
 * height cannot change as auto-buy crosses the page boundary. See the
 * reservation note in ui.js. */
.upgrade-pager.no-pages { visibility: hidden; }

.upgrade-count {
  font-family: var(--font-num); font-size: 10.5px; font-weight: 700;
  color: var(--text-dim); background: var(--panel-2);
  border: 1px solid var(--line-soft);
  padding: 1px 7px; border-radius: 999px;
  white-space: nowrap;
}
/* An unbought Reality upgrade is waiting at the far end of the pager. */
.upgrade-count.has-reality {
  color: var(--reality); border-color: rgba(169,139,255,.45);
}
.upgrade-pager { display: flex; align-items: center; gap: 3px; margin-left: auto; }
.upg-page-btn {
  width: 20px; height: 20px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; line-height: 1; font-weight: 800;
  color: var(--text-dim); background: var(--panel-2);
  border: 1px solid var(--line-soft); border-radius: 6px;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease);
}
.upg-page-btn:hover:not(:disabled) { color: var(--gold); border-color: rgba(240,178,63,.45); }
.upg-page-btn:disabled { opacity: .3; cursor: default; }
.upg-page-label {
  font-family: var(--font-num); font-size: 10px; font-weight: 700;
  color: var(--faint); min-width: 26px; text-align: center;
}
/* The scroll box clips at its *padding* edge, and .upg paints outside its own
   border box when hovered (a 3px lift plus a 20px glow). The padding here is
   what gives that room; the negative margin puts the row back where it was. */
.upgrade-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
  gap: 6px;
  max-height: 204px; overflow-y: auto; overflow-x: hidden;
  padding: 8px 9px;
  margin: -8px -9px -6px;
  scrollbar-gutter: stable;
}
.upgrade-empty { font-size: 11.5px; color: var(--faint); font-style: italic; padding: 6px 2px 0; }

.upg {
  position: relative;
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  font-size: 19px; line-height: 1;
  overflow: hidden;
  border-radius: 9px;
  background: var(--panel-2);
  border: 1px solid var(--line-soft);
  filter: grayscale(.72) brightness(.62);
  transition: transform var(--t-fast) var(--ease), filter var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
  will-change: transform;
}
.upg.affordable {
  filter: none;
  background: linear-gradient(160deg, var(--panel-3), var(--panel-2));
  border-color: rgba(240,178,63,.42);
  box-shadow: 0 0 0 1px rgba(240,178,63,.12), 0 4px 12px -4px rgba(240,178,63,.35);
}
.upg.affordable::after {
  content: ''; position: absolute; inset: -1px; border-radius: 9px;
  background: linear-gradient(160deg, rgba(255,255,255,.12), transparent 55%);
  pointer-events: none;
}
body:not(.no-hover-anim) .upg:hover { transform: scale(1.09); z-index: 2; }
body:not(.no-hover-anim) .upg.affordable:hover { box-shadow: 0 8px 20px -6px rgba(240,178,63,.6); }
.upg:active { transform: scale(.94); }
.upg-glyph { pointer-events: none; }
/* Roman tier marker for the per-tower upgrade families. */
.upg-tier {
  position: absolute; right: 1px; bottom: 0;
  font-size: 8px; font-weight: 800; letter-spacing: -.02em;
  font-family: var(--font-num);
  color: var(--gold-soft);
  text-shadow: 0 1px 2px #000, 0 0 3px #000;
  pointer-events: none;
}
.upg:not(.affordable) .upg-tier { color: var(--muted); }

/* Reality upgrades sit at the back of the same row, told apart by colour:
   purplish grey while unaffordable, properly purple once you can buy one. */
.upg.reality {
  background: linear-gradient(160deg, #2a2434, #221e2b);
  border-color: rgba(169,139,255,.26);
  filter: grayscale(.55) brightness(.7);
}
.upg.reality .upg-tier { color: rgba(169,139,255,.55); }
.upg.reality.affordable {
  filter: none;
  background: linear-gradient(160deg, #3b2f5e, #2c2545);
  border-color: rgba(169,139,255,.6);
  box-shadow: 0 0 0 1px rgba(169,139,255,.18), 0 4px 12px -4px rgba(169,139,255,.5);
}
.upg.reality.affordable::after {
  background: linear-gradient(160deg, rgba(214,198,255,.16), transparent 55%);
}
body:not(.no-hover-anim) .upg.reality.affordable:hover {
  box-shadow: 0 8px 20px -6px rgba(169,139,255,.7);
}

/* ================================ TOOLTIP ================================ */

.tooltip {
  position: fixed; z-index: 200;
  width: 296px; max-width: calc(100vw - 24px);
  padding: 13px 14px;
  background: linear-gradient(170deg, #2c251c, #1c1712);
  border: 1px solid rgba(240,178,63,.26);
  border-radius: 12px;
  box-shadow: var(--shadow-3), 0 0 0 1px rgba(0,0,0,.4);
  pointer-events: none;
  opacity: 0; transform: translateY(6px) scale(.98);
  transition: opacity var(--t-med) var(--ease), transform var(--t-med) var(--ease);
}
.tooltip.show { opacity: 1; transform: none; }
.tt-title {
  font-size: 13px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--gold-soft); margin-bottom: 5px;
}
.tooltip.reality .tt-title { color: var(--reality); }
.tooltip.reality { border-color: rgba(169,139,255,.35); }
.tt-desc { font-size: 12.5px; color: var(--text-dim); font-style: italic; line-height: 1.45; margin-bottom: 9px; }
.tt-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 5px 0; border-top: 1px solid var(--line-soft);
  font-size: 12px;
}
.tt-key { color: var(--faint); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; font-size: 10px; }
.tt-val { font-family: var(--font-num); font-weight: 650; color: var(--text); text-align: right; }
.tt-val.effect { color: var(--good); }
.tt-val.cost { color: var(--gold); }
.tt-val.cost.cant { color: #ff7a6b; }
.tt-note { margin-top: 8px; font-size: 11px; color: var(--faint); }
.tt-cat { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--faint); font-weight: 700; margin-bottom: 3px; }

/* ================================ CARDS ================================== */

.card {
  position: relative;
  background: linear-gradient(165deg, var(--panel-2), var(--panel));
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  margin-bottom: 8px;
  overflow: hidden;
  transition: border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}

/* -------------------------------------------------------------- store ---- */
.buy-amounts { display: flex; align-items: center; gap: 5px; margin-bottom: 10px; }
.buy-label { font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); font-weight: 800; margin-right: 3px; }
.buy-amt {
  padding: 4px 11px; border-radius: 7px;
  font-size: 12px; font-weight: 700;
  background: var(--panel-2); border: 1px solid var(--line-soft); color: var(--muted);
  transition: all var(--t-fast) var(--ease);
}
.buy-amt:hover { color: var(--text); border-color: var(--line); }
.buy-amt.active { background: var(--gold-deep); border-color: var(--gold); color: #fff; }

.store-item {
  display: grid;
  grid-template-columns: 46px minmax(0,1fr) auto;
  gap: 11px; align-items: center;
  padding: 10px 11px;
  cursor: pointer;
  width: 100%; text-align: left;
}
.store-item:disabled { cursor: default; }
.store-item.affordable { border-color: rgba(240,178,63,.34); }
.store-item.affordable:hover { transform: scaleY(1.035); box-shadow: var(--shadow-2); border-color: rgba(240,178,63,.6); }
.store-item.locked-cost { opacity: .58; }
.si-icon {
  width: 46px; height: 46px; border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  font-size: 24px;
  background: radial-gradient(circle at 34% 28%, var(--panel-3), #191410);
  border: 1px solid var(--line-soft);
  flex: 0 0 auto;
  transition: transform var(--t-fast) var(--ease);
}
.store-item.affordable:hover .si-icon { transform: scale(1.07) rotate(-3deg); }
.si-body { min-width: 0; }
.si-name { font-size: 13.5px; font-weight: 700; color: var(--text); }
.si-desc { font-size: 11px; color: var(--faint); margin-top: 1px; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.si-prod { font-size: 11px; color: var(--good); font-family: var(--font-num); margin-top: 3px; font-weight: 650; }
.si-right { text-align: right; flex: 0 0 auto; }
.si-cost { font-family: var(--font-num); font-size: 13px; font-weight: 700; color: var(--gold); white-space: nowrap; }
.store-item:not(.affordable) .si-cost { color: #b0705f; }
.si-owned { font-family: var(--font-num); font-size: 11px; color: var(--muted); margin-top: 2px; }
.locked-tower {
  display: flex; align-items: center; gap: 10px;
  padding: 12px; color: var(--faint); font-size: 12px; font-style: italic;
  border-style: dashed;
}
.locked-tower .lock-icon { font-size: 18px; filter: grayscale(1); opacity: .6; }

/* --------------------------------------------------------- production ---- */
.prod-summary {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  margin-bottom: 11px;
}
.ps-cell {
  padding: 9px 11px; border-radius: var(--radius-sm);
  background: rgba(255,236,205,.04); border: 1px solid var(--line-soft);
}
.ps-label { font-size: 10px; letter-spacing: .09em; text-transform: uppercase; color: var(--faint); font-weight: 800; }
.ps-value { font-family: var(--font-num); font-size: 15px; font-weight: 700; color: var(--gold-soft); margin-top: 1px; }

.prod-item { padding: 11px; }
.pi-head { display: grid; grid-template-columns: 40px minmax(0,1fr) auto; gap: 10px; align-items: center; }
.pi-icon {
  width: 40px; height: 40px; border-radius: 10px; font-size: 21px;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 28%, var(--panel-3), #191410);
  border: 1px solid var(--line-soft);
}
.pi-name { font-size: 13px; font-weight: 700; }
.pi-meta { font-size: 11px; color: var(--muted); font-family: var(--font-num); margin-top: 1px; }
.pi-out { text-align: right; }
.pi-out-val { font-family: var(--font-num); font-size: 13.5px; font-weight: 700; color: var(--good); white-space: nowrap; }
.pi-out-share { font-size: 10.5px; color: var(--faint); font-family: var(--font-num); }

.pi-levelbar {
  position: relative; height: 5px; border-radius: 999px; margin: 9px 0 7px;
  background: rgba(255,236,205,.07); overflow: hidden;
}
.pi-levelfill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold));
  transition: width var(--t-med) var(--ease);
}
.pi-levelbar.ready .pi-levelfill { background: linear-gradient(90deg, var(--reality-2), var(--reality)); }

.pi-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.btn {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 7px 8px; border-radius: 9px;
  background: var(--panel-3); border: 1px solid var(--line-soft);
  transition: all var(--t-fast) var(--ease);
}
.btn:hover:not(:disabled) { border-color: rgba(240,178,63,.45); background: #3b3125; transform: scaleY(1.03); }
.btn:active:not(:disabled) { transform: translateY(0) scale(.98); }
.btn:disabled { opacity: .42; cursor: default; }
.btn-label { font-size: 11.5px; font-weight: 750; letter-spacing: .04em; }
.btn-cost { font-family: var(--font-num); font-size: 10.5px; color: var(--gold); }
.btn.can .btn-cost { color: var(--gold-soft); }
.btn:not(.can) .btn-cost { color: #b0705f; }
.btn-transcend { border-color: rgba(169,139,255,.3); }
.btn-transcend.can {
  background: linear-gradient(135deg, rgba(111,78,224,.4), rgba(169,139,255,.22));
  border-color: rgba(169,139,255,.65);
}
.btn-transcend.can .btn-cost { color: #d6c7ff; }
.btn-transcend .btn-label { color: var(--reality); }

.pi-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.tag {
  font-size: 10px; font-weight: 700; letter-spacing: .04em;
  padding: 2px 7px; border-radius: 999px;
  background: rgba(240,178,63,.12); color: var(--gold-soft);
  border: 1px solid rgba(240,178,63,.22);
}
.tag.transcend { background: rgba(169,139,255,.14); color: #cbb8ff; border-color: rgba(169,139,255,.3); }
.tag.special { background: rgba(124,196,111,.12); color: #a9dfa0; border-color: rgba(124,196,111,.25); }

.empty-note {
  padding: 26px 16px; text-align: center; color: var(--faint);
  font-size: 12.5px; font-style: italic; line-height: 1.6;
}

/* ============================= AUTOMATIONS =============================== */
/* Shard-bought, so the whole tab reads in the Reality purple rather than the
   gold used by everything paid for with Pies. */

.auto-head {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  margin-bottom: 11px;
}
.auto-head .ps-value { color: var(--reality); }

.auto-card { padding: 11px; opacity: .72; }
.auto-card.owned { opacity: 1; }
.auto-card.running { border-color: rgba(169,139,255,.4); }

.au-head { display: grid; grid-template-columns: 40px minmax(0,1fr) auto; gap: 10px; align-items: center; }
.au-icon {
  width: 40px; height: 40px; border-radius: 10px; font-size: 21px;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 28%, var(--panel-3), #191410);
  border: 1px solid var(--line-soft);
}
.auto-card.running .au-icon {
  border-color: rgba(169,139,255,.45);
  box-shadow: 0 0 14px -4px rgba(169,139,255,.7);
}
.au-mid { min-width: 0; }
.au-name { font-size: 13px; font-weight: 700; }
.au-desc { font-size: 11px; color: var(--muted); margin-top: 2px; line-height: 1.45; }
.au-switch { flex: 0 0 auto; align-self: center; }
.au-switch.on { background: var(--reality-2); border-color: var(--reality); }
.au-switch:disabled { opacity: .35; cursor: default; }

/* The level and its state pill are one unbreakable group; the rate takes the
   rest of the line and drops to a line of its own when it will not fit. The
   panel is only ~340px wide and the long labels ("Level 46 / 46 · LEGION"
   against "purchase rate · 10x/s · 32 towers at once") do not share one. */
.au-status {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
  margin-top: 9px; font-family: var(--font-num); font-size: 11px;
}
.au-level { color: var(--text-dim); font-weight: 700; white-space: nowrap; }
.au-rate {
  color: var(--reality); text-align: right; margin-left: auto;
  min-width: 0; flex: 0 1 auto;
}
.auto-card:not(.running) .au-rate { color: var(--faint); }

/* --- what the module is doing right now --------------------------------- */
.au-state {
  display: inline-block; flex: 0 0 auto;
  font-size: 9px; letter-spacing: .1em; text-transform: uppercase;
  font-weight: 800; padding: 2px 6px; border-radius: 999px;
  border: 1px solid var(--line-soft); color: var(--faint);
  white-space: nowrap; cursor: default;
}
/* `display` above outranks the UA rule for [hidden], so restate it. */
.au-state[hidden] { display: none; }
.au-state.working {
  color: var(--good); border-color: rgba(124,196,111,.45);
  background: rgba(124,196,111,.1);
}
.au-state.idle {
  color: var(--gold); border-color: rgba(240,178,63,.45);
  background: rgba(240,178,63,.1);
}
.au-state.suppressed {
  color: var(--hot); border-color: rgba(255,127,69,.45);
  background: rgba(255,127,69,.1);
}

.au-levelbar {
  position: relative; height: 5px; border-radius: 999px; margin: 6px 0 9px;
  background: rgba(255,236,205,.07); overflow: hidden;
}
.au-levelfill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--reality-2), var(--reality));
  transition: width var(--t-med) var(--ease);
}

.au-modes { display: flex; align-items: center; gap: 5px; margin-bottom: 9px; }
.au-modes-label {
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--faint); font-weight: 800; margin-right: 2px;
}
.au-modes .buy-amt { flex: 1 1 0; padding: 4px 6px; }
.au-modes .buy-amt.active {
  background: var(--reality-2); border-color: var(--reality); color: #fff;
}

.au-buy { width: 100%; border-color: rgba(169,139,255,.28); }
.au-buy .btn-label { color: var(--reality); }
.au-buy.can {
  background: linear-gradient(135deg, rgba(111,78,224,.4), rgba(169,139,255,.22));
  border-color: rgba(169,139,255,.65);
}
.au-buy.can .btn-cost { color: #d6c7ff; }
.au-buy:not(.can) .btn-cost { color: #8b7ba8; }

.au-note {
  margin-top: 8px; font-size: 10.5px; line-height: 1.5;
  color: var(--faint);
}

/* --- Overdrive / Legion level styling ----------------------------------- */
.auto-card.overdriven { border-color: rgba(169,139,255,.55); }
.auto-card.overdriven .au-level { color: var(--reality); }
.auto-card.overdriven .au-levelfill {
  background: linear-gradient(90deg, var(--reality), #e0d4ff);
}
.auto-card.legion { border-color: rgba(240,178,63,.55); }
.auto-card.legion .au-level { color: var(--gold); }
.auto-card.legion .au-levelfill {
  background: linear-gradient(90deg, var(--reality), var(--gold), #ffe7b0);
}
/* Singularity is the track above Legion, so it wins both of the rules above.
   It is the only card border that is not a flat colour -- the last track a
   module can be on should not look like one more shade of gold. */
.auto-card.singular { border-color: rgba(103,174,224,.6); }
.auto-card.singular .au-level { color: var(--cold); }
.auto-card.singular .au-levelfill {
  background: linear-gradient(90deg, var(--gold), var(--cold), #dff1ff);
}
.auto-card.singular .au-icon {
  border-color: rgba(103,174,224,.5);
}
.auto-card.singular.running .au-icon {
  box-shadow: 0 0 16px -4px rgba(103,174,224,.85);
}

/* Cascade is the track above Singularity and the last one there is, so it wins
   every rule above it. It reads hot where Singularity reads cold: the pair of
   modules that carry it are the ones burning the bank. */
.auto-card.cascade { border-color: rgba(255,127,69,.6); }
.auto-card.cascade .au-level { color: var(--hot); }
.auto-card.cascade .au-levelfill {
  background: linear-gradient(90deg, var(--cold), var(--hot), var(--gold-soft));
}
.auto-card.cascade .au-icon {
  border-color: rgba(255,127,69,.55);
}
.auto-card.cascade.running .au-icon {
  box-shadow: 0 0 18px -4px rgba(255,127,69,.9);
}

/* ============================== ACHIEVEMENTS ============================= */

.ach-summary {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px;
  margin-bottom: 11px;
}
.as-cell {
  padding: 8px 10px; border-radius: var(--radius-sm);
  background: rgba(255,236,205,.04); border: 1px solid var(--line-soft);
}
.as-label { font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--faint); font-weight: 800; }
.as-value { font-family: var(--font-num); font-size: 14px; font-weight: 700; margin-top: 1px; }
.as-value.prod { color: var(--good); }
.as-value.click { color: var(--gold-soft); }

.ach-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(52px, 1fr)); gap: 6px; }
.ach {
  position: relative; aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  font-size: 21px; border-radius: 11px;
  background: var(--panel-2); border: 1px solid var(--line-soft);
  filter: grayscale(1) brightness(.42); opacity: .75;
  transition: transform var(--t-fast) var(--ease), filter var(--t-fast) var(--ease),
              opacity var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  cursor: help;
}
.ach.unlocked {
  filter: none; opacity: 1;
  background: linear-gradient(160deg, #3a2f20, #241d16);
  border-color: rgba(240,178,63,.4);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 3px 10px -4px rgba(240,178,63,.4);
}
.ach:hover { transform: scale(1.1); z-index: 2; }

/* Every hover transform in the game pivots on the bottom edge -- see HOVER
 * LIFT at the foot of this file. This is the rule that stops the hover
 * flicker; dropping any selector from it brings the flicker back for that
 * control. It is deliberately scoped to :hover, so it cannot reach the
 * centre-authored keyframes (upgPop, upgIn, achShine) on the same tiles. */
.btn:hover, .btn-ascend:hover, .btn-primary:hover, .store-item:hover,
.seed-item:hover, .plot:hover, .upg:hover, .ach:hover {
  transform-origin: bottom center;
}
.ach.hidden-ach { font-size: 17px; color: var(--faint); }

/* --- secrets ------------------------------------------------------------
   Its own block below the main grid rather than tiles mixed into it: an
   unfound secret must leave no gap, no placeholder and no count to infer
   from, so there is simply nothing here until one is found. */
.secret-block {
  margin-top: 16px; padding-top: 13px;
  border-top: 1px dashed var(--line-soft);
}
.secret-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 2px; }
.secret-title {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--reality); font-weight: 800;
}
.secret-count {
  font-family: var(--font-num); font-size: 11px; font-weight: 700;
  color: var(--faint);
}
.secret-note { font-size: 10.5px; color: var(--faint); margin-bottom: 9px; }
.ach.secret-ach {
  background: linear-gradient(160deg, #2e2740, #1d1a28);
  border-color: rgba(169,139,255,.42);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 3px 10px -4px rgba(169,139,255,.45);
}
.ach.secret-ach.unlocked::after { background: var(--reality); box-shadow: 0 0 6px var(--reality); }
.ach.unlocked::after {
  content: ''; position: absolute; right: 3px; bottom: 3px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--good); box-shadow: 0 0 6px var(--good);
}

/* ================================= STATS ================================= */

.stat-group { margin-bottom: 14px; }
.stat-group-title {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold); font-weight: 800;
  padding-bottom: 5px; margin-bottom: 6px;
  border-bottom: 1px solid var(--line-soft);
}
.stat-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 3.5px 2px; font-size: 12px;
}
.stat-row + .stat-row { border-top: 1px solid rgba(255,224,178,.035); }
.stat-key { color: var(--muted); }
.stat-val { font-family: var(--font-num); font-weight: 650; color: var(--text); text-align: right; }
.stat-val.good { color: var(--good); }
.stat-val.gold { color: var(--gold-soft); }
.stat-val.reality { color: var(--reality); }

/* =============================== SETTINGS ================================ */

.set-group { margin-bottom: 15px; }
.set-group-title {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold); font-weight: 800;
  padding-bottom: 5px; margin-bottom: 7px;
  border-bottom: 1px solid var(--line-soft);
}
.set-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 6px 2px; font-size: 12.5px;
}
.set-label { color: var(--text-dim); }
.set-hint { font-size: 10.5px; color: var(--faint); margin-top: 1px; }
/* A read-only right-hand value, where a toggle or segment would otherwise sit. */
.set-value {
  font-family: var(--font-num); font-size: 12px; font-weight: 700;
  color: var(--muted); white-space: nowrap;
}

.switch {
  position: relative; flex: 0 0 auto;
  width: 40px; height: 22px; border-radius: 999px;
  background: var(--panel-3); border: 1px solid var(--line-soft);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.switch::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--muted);
  transition: transform var(--t-med) var(--ease), background var(--t-fast) var(--ease);
}
.switch.on { background: var(--gold-deep); border-color: var(--gold); }
.switch.on::after { transform: translateX(18px); background: #fff; }

.seg { display: flex; gap: 3px; background: var(--panel); border: 1px solid var(--line-soft); border-radius: 8px; padding: 2px; }
.seg button {
  padding: 3px 10px; border-radius: 6px; font-size: 11.5px; font-weight: 700; color: var(--muted);
  transition: all var(--t-fast) var(--ease);
}
.seg button:hover { color: var(--text); }
.seg button.active { background: var(--gold-deep); color: #fff; }

.set-slider { width: 116px; accent-color: var(--gold); }

.set-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; margin-top: 8px; }
.btn-wide {
  padding: 8px; border-radius: 9px; font-size: 12px; font-weight: 700;
  background: var(--panel-3); border: 1px solid var(--line-soft);
  transition: all var(--t-fast) var(--ease);
}
.btn-wide:hover { border-color: rgba(240,178,63,.5); background: #3b3125; }
.btn-wide.danger { color: #ff8f7a; border-color: rgba(255,110,90,.28); }
.btn-wide.danger:hover { background: rgba(192,57,43,.2); border-color: rgba(255,110,90,.6); }
.set-textarea {
  width: 100%; height: 78px; margin-top: 7px; resize: vertical;
  background: var(--bg-deep); color: var(--text-dim);
  border: 1px solid var(--line-soft); border-radius: 8px;
  padding: 7px; font-family: var(--font-num); font-size: 10.5px;
}

/* ================================ TOASTS ================================= */

/* Anchored to the inner edge of the right sidebar (--rw is 0 when closed) so
   notifications never sit on top of the Store. */
.toasts {
  position: fixed; right: calc(var(--rw, 0px) + 16px); bottom: 16px; z-index: 180;
  transition: right var(--t-slow) var(--ease);
  display: flex; flex-direction: column-reverse; gap: 8px;
  pointer-events: none; max-width: min(340px, calc(100vw - 32px));
}
.toast {
  display: grid; grid-template-columns: 40px minmax(0,1fr); gap: 11px; align-items: center;
  padding: 11px 14px 11px 11px;
  background: linear-gradient(160deg, #33291d, #1d1812);
  border: 1px solid rgba(240,178,63,.35);
  border-radius: 12px;
  box-shadow: var(--shadow-3);
  pointer-events: auto;
}
.toast-icon {
  width: 40px; height: 40px; border-radius: 10px; font-size: 21px;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 28%, #4a3b28, #241c14);
  border: 1px solid rgba(240,178,63,.25);
}
.toast-kind { font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--gold); font-weight: 800; }
.toast-title { font-size: 13px; font-weight: 750; margin-top: 1px; }
.toast-body { font-size: 11.5px; color: var(--text-dim); margin-top: 1px; line-height: 1.4; }
.toast-reward { font-size: 11.5px; font-weight: 750; color: var(--good); margin-top: 3px; font-family: var(--font-num); }
.toast.secret { border-color: rgba(169,139,255,.55); }
.toast.secret .toast-kind { color: var(--reality); }
.toast.reality { border-color: rgba(169,139,255,.45); }
.toast.reality .toast-kind { color: var(--reality); }
.toast.transcend { border-color: rgba(169,139,255,.4); }

/* ================================ MODAL ================================== */

.modal-layer {
  position: fixed; inset: 0; z-index: 190;
  display: flex; align-items: center; justify-content: center;
  background: rgba(6,5,4,.72);
  backdrop-filter: blur(4px);
  padding: 20px;
}
.modal {
  width: min(460px, 100%);
  background: linear-gradient(165deg, #2b241b, #191510);
  border: 1px solid rgba(240,178,63,.28);
  border-radius: 18px;
  box-shadow: var(--shadow-3);
  padding: 24px;
  text-align: center;
}
.modal h2 { font-size: 20px; letter-spacing: .04em; margin-bottom: 6px; }
.modal .m-sub { color: var(--muted); font-size: 12.5px; margin-bottom: 16px; }
.m-figure {
  font-family: var(--font-num); font-size: 30px; font-weight: 800;
  color: var(--gold-soft); text-shadow: 0 0 26px rgba(240,178,63,.35);
}
.m-figure-label { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); font-weight: 800; margin-top: 2px; }
.m-rows { text-align: left; margin: 16px 0; }
.m-actions { display: flex; gap: 9px; justify-content: center; margin-top: 6px; }
.btn-primary {
  padding: 10px 26px; border-radius: 11px; font-weight: 750; font-size: 13px;
  background: linear-gradient(135deg, var(--gold-deep), var(--gold));
  color: #221a0c;
  box-shadow: 0 8px 22px -8px rgba(240,178,63,.8);
  transition: transform var(--t-fast) var(--ease), filter var(--t-fast) var(--ease);
}
.btn-primary:hover { transform: scaleY(1.06); filter: brightness(1.07); }
.btn-primary:active { transform: none; }
.btn-ghost {
  padding: 10px 20px; border-radius: 11px; font-weight: 700; font-size: 13px;
  border: 1px solid var(--line); color: var(--muted);
  transition: all var(--t-fast) var(--ease);
}
.btn-ghost:hover { color: var(--text); border-color: var(--gold); }

/* ============================== FX LAYER ================================= */

.fx-layer { position: absolute; inset: 0; pointer-events: none; overflow: visible; z-index: 5; }
.float-num {
  position: absolute;
  font-family: var(--font-num); font-weight: 800; font-size: 17px;
  color: var(--gold-soft);
  text-shadow: 0 2px 5px rgba(0,0,0,.75);
  pointer-events: none; will-change: transform, opacity;
  white-space: nowrap;
}
.float-num.crit { color: #fff3c4; font-size: 23px; text-shadow: 0 0 14px rgba(255,196,60,.9), 0 2px 5px rgba(0,0,0,.8); }
/* Crystal and Golden Crit add no damage of their own -- they are pure crit
 * chance -- so the floating number is where the player actually sees them. */
.float-num.crit.golden  { color: #fff6d2; font-size: 25px; text-shadow: 0 0 18px rgba(255,206,74,1), 0 0 34px rgba(255,176,32,.65), 0 2px 5px rgba(0,0,0,.8); }
.float-num.crit.crystal { color: #eaf4ff; font-size: 26px; text-shadow: 0 0 18px rgba(150,200,255,1), 0 0 36px rgba(169,139,255,.7), 0 2px 5px rgba(0,0,0,.8); }
.crumb {
  position: absolute; width: 7px; height: 7px; border-radius: 2px;
  background: var(--crust); pointer-events: none; will-change: transform, opacity;
}
.crumb.filling { background: var(--filling); border-radius: 50%; }

/* ======================= SMALL-SCREEN ADJUSTMENTS ======================= */

/* Drawer mode: no sidebar columns, so the pie can take more of the width, and
   toasts must stop blanketing it. */
@media (max-width: 940px) {
  .pie-stage { --pie-size: min(46vh, 62vw, 380px); }
  .toasts { max-width: min(300px, calc(100vw - 24px)); }
  .toast { grid-template-columns: 34px minmax(0,1fr); gap: 9px; padding: 9px 12px 9px 9px; }
  .toast-icon { width: 34px; height: 34px; font-size: 18px; }
  .toast-title { font-size: 12.5px; }
  .toast-body { font-size: 11px; }
}

@media (max-width: 620px) {
  .pie-stage { --pie-size: min(40vh, 74vw, 330px); }
  .big-counter { font-size: clamp(26px, 9vw, 40px); }
  .shard-counter { font-size: clamp(18px, 6vw, 28px); }
  .counter-row { gap: 12px; }
  .big-counter-label { font-size: 10.5px; letter-spacing: .16em; }
  .temp-bar { width: min(240px, 62vw); }
  /* Full-bleed, shorter toasts so two of them cannot bury the pie. */
  .toasts { left: 12px; right: 12px; bottom: 12px; max-width: none; }
  .toast-body { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .pie-substats { gap: 6px; }
  .substat { min-width: 0; flex: 1 1 30%; padding: 6px 8px; }
  .s-value { font-size: 13px; }
  .pie-stage { min-height: 180px; }
}


/* ============================== BONUS PIES =============================== */

/* Spans the whole centre column but never takes a pointer event; only the
   bonus pie itself is clickable, and ui.js places it clear of the pie, so a
   pie click can never be intercepted (invariant 7). */
.bonus-layer {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 20;
  /* Claim bursts spawn in here. `clip` keeps the box unscrollable so those
     particles cannot enlarge #pie-area's scrollable overflow. */
  overflow: clip;
}

.bonus-pie {
  position: absolute;
  width: 74px; height: 74px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: none; background: none; padding: 0;
  cursor: pointer;
  pointer-events: auto;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  will-change: transform, opacity;
}
.bonus-glyph {
  position: relative; z-index: 2;
  font-size: 38px; line-height: 1;
  pointer-events: none;
  filter: drop-shadow(0 3px 6px rgba(0,0,0,.65));
}
.bonus-halo {
  position: absolute; inset: -18%;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(255,214,133,.55), rgba(240,178,63,.18) 48%, transparent 70%);
}
.bonus-pie.diamond .bonus-halo {
  background: radial-gradient(circle, rgba(200,220,255,.6), rgba(169,139,255,.24) 48%, transparent 70%);
}

/* Time-remaining ring. --p is written by ui.js each frame. */
.bonus-ring {
  position: absolute; inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(var(--gold-soft) var(--p, 100%), rgba(255,255,255,.10) 0);
  -webkit-mask: radial-gradient(circle, transparent 60%, #000 62%);
  mask: radial-gradient(circle, transparent 60%, #000 62%);
  opacity: .9;
}
.bonus-pie.diamond .bonus-ring {
  background: conic-gradient(#cfe0ff var(--p, 100%), rgba(255,255,255,.10) 0);
}

/* --- Special Pie Combo -----------------------------------------------------
 * A combo pie is the same pie with the volume turned up: a wider, hotter halo
 * and a bright rim, so it reads as "this one is not on the timer" at a glance.
 */
.bonus-pie.combo .bonus-halo {
  inset: -34%;
  background: radial-gradient(circle, rgba(255,255,255,.75), rgba(255,214,133,.42) 38%, rgba(240,178,63,.18) 60%, transparent 76%);
}
.bonus-pie.combo.diamond .bonus-halo {
  background: radial-gradient(circle, rgba(255,255,255,.8), rgba(200,220,255,.48) 38%, rgba(169,139,255,.2) 60%, transparent 76%);
}
.bonus-pie.combo .bonus-glyph {
  filter: drop-shadow(0 0 10px rgba(255,236,180,.95)) drop-shadow(0 3px 6px rgba(0,0,0,.65));
}
.bonus-pie.combo.diamond .bonus-glyph {
  filter: drop-shadow(0 0 10px rgba(206,228,255,.95)) drop-shadow(0 3px 6px rgba(0,0,0,.65));
}
.bonus-pie.combo .bonus-ring { opacity: 1; }

body:not(.no-hover-anim) .bonus-pie:hover { transform: scale(1.12); }
.bonus-pie:active { transform: scale(.92); }

/* ================================ BUFF BAR ============================== */

.buff-bar {
  flex: 0 0 auto;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 7px;
  margin: 6px 0 2px;
  max-width: 100%;
}
.buff-chip {
  position: relative;
  display: flex; align-items: center; gap: 7px;
  padding: 5px 11px 6px 8px;
  border-radius: 999px;
  background: linear-gradient(160deg, var(--panel-3), var(--panel-2));
  border: 1px solid rgba(240,178,63,.42);
  box-shadow: 0 0 0 1px rgba(240,178,63,.10), 0 4px 14px -6px rgba(240,178,63,.5);
  overflow: hidden;
}
.buff-chip.diamond {
  border-color: rgba(169,139,255,.5);
  box-shadow: 0 0 0 1px rgba(169,139,255,.14), 0 4px 14px -6px rgba(169,139,255,.55);
}
.buff-icon { font-size: 15px; line-height: 1; }
.buff-body { display: flex; align-items: baseline; gap: 7px; }
.buff-name {
  font-size: 11px; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; color: var(--gold-soft);
}
.buff-chip.diamond .buff-name { color: #cfc0ff; }
.buff-time {
  font-family: var(--font-num); font-size: 11px; font-weight: 700;
  color: var(--text-dim);
}
/* Drains left to right as the buff runs out. Width is set from live state. */
.buff-fill {
  position: absolute; left: 0; bottom: 0; height: 2px;
  background: var(--gold);
  transition: width .2s linear;
}
.buff-chip.diamond .buff-fill { background: var(--reality); }

/* ============================== BAKERY FIRE ============================== */
/* Behind everything in the centre column. #pie-area's other children are
   lifted to z-index 1 so this layer can never intercept a pie click
   (invariant 7) and never paints over the pie itself. */

.bakery-fire {
  position: absolute; inset: 0;
  z-index: 0;
  pointer-events: none;
  /* An explicit zero clip margin, not just `overflow: clip`: the tongues are
     wider than their slots and the outermost ones bleed past the column,
     which made #pie-area horizontally scrollable on a phone. Nothing in the
     centre column may add scrollable overflow -- see the same note on
     .pie-stage above. */
  overflow: clip;
  overflow-clip-margin: 0px;
  opacity: 0;
  transition: opacity 1.2s var(--ease);
  /* --fire-h is the flame height as a percentage of the column; --fire-a is
     how strongly the warm wash reads. Both are written from effects.js. */
  --fire-h: 0%;
  --fire-a: 0;
  --flame-core: #ffe9a8;
  --flame-mid:  #ff9a1f;
  --flame-edge: #c0392b;
}
.bakery-fire.lit { opacity: 1; }

/* Every other child of the centre column sits above the fire.
   .bonus-layer is deliberately NOT in this list: it is position:absolute with
   inset:0, and this rule's `position: relative` beat that on specificity,
   collapsing the layer to a zero-height in-flow box at the bottom of the
   column. Its own `overflow: clip` then erased the bonus pie entirely, while
   placeBonus() kept computing coordinates against #pie-area -- so pies spawned
   and expired unseen. The layer is pointer-events:none and placeBonus() treats
   #pie as a hard obstacle, so it never needed the lift to satisfy invariant 7. */
#pie-area > .pie-header,
#pie-area > .buff-bar,
#pie-area > .pie-stage,
#pie-area > .pie-substats,
#pie-area > .recipe-chip,
#pie-area > .ascend-zone { position: relative; z-index: 1; }

/* --- the warm wash ------------------------------------------------------ */
.fire-heat {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: calc(var(--fire-h) + 18%);
  background: linear-gradient(0deg,
    rgba(255,142,44,.42) 0%,
    rgba(240,120,30,.22) 38%,
    rgba(240,178,63,.08) 70%,
    rgba(240,178,63,0) 100%);
  opacity: var(--fire-a);
  filter: blur(14px);
  transition: height .6s var(--ease), opacity .6s var(--ease);
}

/* --- the flame tongues -------------------------------------------------- */
.fire-flames {
  position: absolute; left: 0; right: 0; bottom: 0;
  z-index: 1;
  height: var(--fire-h);
  /* `isolation` keeps the tongues' screen-blending to each other. Without it
     a full-height fire screen-blended against the page and 26 overlapping
     tongues saturated the whole column to white. The row's overall strength
     is then one number per stage, set below. */
  isolation: isolate;
  opacity: .55;
  /* Clip the sides only. The tongues' 3px blur spilled ~9px past the column
     and showed up in #pie-area's scrollWidth; the top stays open because the
     taller tongues deliberately overshoot the row, which is what stops the
     fire reading as a flat-topped comb. */
  clip-path: inset(-200% 0 0 0);
  transition: height .8s var(--ease), opacity 1s var(--ease);
}
.flame {
  position: absolute; bottom: 0;
  /* Width is a fraction of the flame row, never of --fire-h: that value is a
     percentage, and multiplying it inside calc() resolves against the
     containing block's WIDTH, which produced tongues hundreds of pixels wide
     that read as blobs rather than fire. */
  width: calc(4.2% * var(--w, 1));
  height: calc(100% * var(--h, 1));
  transform: translateX(-50%);
  border-radius: 50% 50% 44% 44% / 64% 64% 20% 20%;
  /* Fire is hottest at its base: white at the floor, through amber and
     orange, to a red tip that fades out rather than ending on a hard edge. */
  background: linear-gradient(0deg,
    var(--flame-core) 0%,
    var(--flame-mid) 34%,
    var(--flame-edge) 68%,
    rgba(120,24,12,0) 100%);
  filter: blur(3px);
  opacity: .62;
  mix-blend-mode: screen;
  transform-origin: 50% 100%;
  animation: flameLick var(--fd, 1.4s) ease-in-out infinite alternate;
}
@keyframes flameLick {
  0%   { transform: translateX(-50%) scale(.82, .78) skewX(-5deg); opacity: .40; }
  50%  { transform: translateX(-50%) scale(1.06, 1.08) skewX(4deg); opacity: .70; }
  100% { transform: translateX(-50%) scale(.9, .88) skewX(-2deg); opacity: .52; }
}

/* Colour walks from a dull ember toward white as the stages climb. A tiny
   fire is also a blurrier, fainter one, so the first rungs read as a flicker
   along the floor rather than as small solid shapes. */
.bakery-fire.s0 .fire-flames { opacity: .42; }
.bakery-fire.s1 .fire-flames { opacity: .5; }
.bakery-fire.s0 .flame, .bakery-fire.s1 .flame { filter: blur(4px); }
.bakery-fire.s4, .bakery-fire.s5 { --flame-mid: #ff9e24; --flame-core: #ffd257; }
.bakery-fire.s6, .bakery-fire.s7 { --flame-mid: #ffb43a; --flame-edge: #e0521f; }
.bakery-fire.s8, .bakery-fire.s9 { --flame-mid: #ffc857; --flame-edge: #ff6a1f; --flame-core: #ffe0a0; }
/* A taller fire is a bigger area of screen, so it needs to be fainter to sit
   at the same visual weight -- and the pie has to stay the subject. */
.bakery-fire.s6 .fire-flames, .bakery-fire.s7 .fire-flames { opacity: .46; }
.bakery-fire.s8 .fire-flames { opacity: .4; }
.bakery-fire.s9 .fire-flames { opacity: .34; }
.bakery-fire.sunlit  { --flame-mid: #ffd07a; --flame-edge: #ff8a2f; --flame-core: #ffe6b8; }
.bakery-fire.sunlit .fire-flames { opacity: .26; }

/* --- the star ----------------------------------------------------------- */
/* Centred on the pie, which is the centre of the column. Hidden until 22,000F,
   and at 36,000F it blows out to fill the whole play area. */
.fire-star {
  /* Above the flames: by the time it ignites they are at full height, and
     behind them the star was invisible. */
  position: absolute; top: 54%; left: 50%; z-index: 2;
  /* Larger than the pie (whose --pie-size tops out at 380px) so it reads as a
     sun standing behind it, but small enough to stay clear of the header --
     at 700px it swallowed the temperature readout. */
  width: min(68vh, 54vw, 590px); aspect-ratio: 1;
  transform: translate(-50%, -50%) scale(0);
  border-radius: 50%;
  opacity: 0;
  background:
    radial-gradient(circle at 50% 50%,
      #ffffff 0%, #fff6d0 16%, #ffd257 34%, #ff8c1a 54%,
      rgba(192,57,43,.5) 72%, rgba(192,57,43,0) 92%);
  box-shadow: 0 0 130px 30px rgba(255,170,40,.35);
  transition: transform 2.4s var(--ease), opacity 2.4s var(--ease),
              border-radius 2.4s var(--ease), width 2.4s var(--ease);
  animation: starPulse 4.2s ease-in-out infinite alternate;
}
@keyframes starPulse {
  from { filter: brightness(.94) saturate(1); }
  to   { filter: brightness(1.16) saturate(1.15); }
}
.bakery-fire.sunlit .fire-star {
  opacity: .9;
  transform: translate(-50%, -50%) scale(1);
}
/* Nova: the star stops being an object behind the pie and becomes the
   background of the whole centre column.
   The background lives on .bakery-fire, not on a scaled-up .fire-star. An
   earlier cut grew the star to 260% and the gradient then sized to a
   ~2,500px box, so the visible 1,500px of it was only the washed-out core --
   every authored stop past the second fell off screen. Painting it on the
   full-bleed layer sizes the gradient to exactly what the player sees. */
/* Its own full-bleed child rather than a background on .bakery-fire: that
   container is the fire's clip box, and painting the star's body on it left
   the four corners showing the page's near-black at the one moment the column
   is supposed to BE the star. A dedicated layer also gives the nova something
   to fade in with. */
.fire-nova {
  position: absolute; inset: 0;
  z-index: 0;
  opacity: 0;
  transition: opacity 2.4s var(--ease);
  /* farthest-CORNER, not the default farthest-side: the latter renders as an
     ellipse tangent to the edges and drops the corners entirely. The solid
     colour under the gradient is the belt to that braces. */
  background:
    radial-gradient(circle farthest-corner at 50% 54%,
      #ffffff 0%, #fff0b4 10%, #ffc832 24%, #ff9418 42%,
      #f4661f 62%, #e04a1c 82%, #c9381a 100%)
    #c9381a;
}
.bakery-fire.nova .fire-nova {
  opacity: 1;
  animation: novaChurn 6s ease-in-out infinite alternate;
}
@keyframes novaChurn {
  from { filter: brightness(.97) saturate(1.02); }
  to   { filter: brightness(1.12) saturate(1.18); }
}
/* The disc itself stays a disc, just hotter and a little wider -- it is the
   core of the star the background is now the body of. */
.bakery-fire.nova .fire-star {
  width: min(82vh, 62vw, 700px);
  opacity: 1;
  box-shadow: 0 0 180px 60px rgba(255,208,90,.5);
  background:
    radial-gradient(circle at 50% 50%,
      #ffffff 0%, #fff8dc 22%, #ffd257 46%, rgba(255,160,32,.5) 70%,
      rgba(255,140,26,0) 100%);
}
/* Once the background *is* the star, the tongues would only muddy it. */
.bakery-fire.nova .fire-flames { opacity: .14; }
.bakery-fire.nova .fire-heat { opacity: 0; }

/* Once the star is lit, the column's text is sitting on a bright ground.
   The fire is #pie-area's first child, so every readout is a later sibling. */
.bakery-fire.sunlit ~ .pie-header,
.bakery-fire.sunlit ~ .pie-substats,
.bakery-fire.sunlit ~ .ascend-zone,
.bakery-fire.sunlit ~ .buff-bar {
  text-shadow: 0 1px 2px rgba(20,8,2,.85), 0 0 14px rgba(20,8,2,.7);
}
.bakery-fire.sunlit ~ .pie-substats .substat,
.bakery-fire.sunlit ~ .ascend-zone .ascend-bar {
  background: rgba(24,12,4,.5);
  border-color: rgba(24,12,4,.6);
}

/* --- settings-driven damping -------------------------------------------- */
/* The fire still reads the temperature at every setting -- it is a genuine
   readout of state, not decoration -- but the motion is what gets stilled. */
body.reduced-animations .flame,
body.reduced-motion .flame,
body.reduced-animations .fire-star,
body.reduced-motion .fire-star,
body.reduced-animations .fire-nova,
body.reduced-motion .fire-nova { animation: none !important; }
body.no-particles .flame { opacity: .34; filter: blur(9px); }
@media (prefers-reduced-motion: reduce) {
  .flame, .fire-star, .fire-nova { animation: none !important; }
}

/* ============================== RECIPE CARDS ============================= */

/* The chip sits above the ascend zone and is the only permanent reminder of
   what is different about this run. Hidden outright until cards unlock. */
.recipe-chip {
  display: flex; align-items: center; gap: 9px;
  margin: 0 auto 8px; padding: 7px 11px; max-width: 340px;
  border-radius: var(--radius-sm);
  background: rgba(255,236,205,.04);
  border: 1px solid var(--line-soft);
  cursor: help;
}
.recipe-chip.active { border-color: rgba(169,139,255,.42); background: rgba(169,139,255,.07); }
.rc-icon { font-size: 18px; line-height: 1; }
.rc-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.rc-name {
  font-size: 12px; font-weight: 800; color: var(--gold-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.recipe-chip.active .rc-name { color: var(--reality); }
.rc-sub { font-size: 10px; color: var(--faint); }
.rc-payout {
  font-family: var(--font-num); font-size: 13px; font-weight: 800;
  color: var(--good);
}

/* --- the draft ---------------------------------------------------------- */
.modal.modal-wide {
  /* .modal fixes `width`, so max-width alone cannot widen it. The draft also
     has to survive a short viewport, hence the scroll. */
  width: min(880px, 100%);
  max-height: calc(100vh - 40px);
  overflow-y: auto;
}
.draft-title {
  margin-top: 15px; font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--gold); font-weight: 800;
}
.draft-note { font-size: 11px; color: var(--faint); margin: 3px 0 10px; }
.draft-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(185px, 1fr));
  gap: 9px;
}
.recipe-card {
  display: flex; flex-direction: column; gap: 7px;
  padding: 11px; text-align: left; cursor: pointer;
  border-radius: var(--radius-sm);
  background: var(--panel-2); border: 1px solid var(--line-soft);
  color: inherit; font: inherit;
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
/* Scale about the bottom edge, never translateY -- see invariant 8. A lift
   moves the hit box with the element, so a pointer resting near the card's
   bottom edge flickers in and out of :hover at frame rate. These are wide
   cards, so the growth is vertical only. */
.recipe-card:hover {
  transform-origin: bottom center;
  transform: scaleY(1.02);
  border-color: rgba(240,178,63,.55);
  box-shadow: 0 8px 20px -10px rgba(240,178,63,.5);
}
/* Deeper tiers read as rarer at a glance, before any text is parsed. */
.recipe-card.tier-2 { border-color: rgba(169,139,255,.32); }
.recipe-card.tier-3 {
  border-color: rgba(169,139,255,.55);
  background: linear-gradient(165deg, #2b2440, #1b1826);
}
/* Tier 4 leaves the purple behind entirely: these cards remove whole systems,
   and they should not read as "tier 3 but more". */
.recipe-card.tier-4 {
  border-color: rgba(240,178,63,.6);
  background: linear-gradient(165deg, #3a2b1c, #1e1712);
  box-shadow: inset 0 0 24px -8px rgba(240,178,63,.35);
}
.recipe-card.tier-4 .rcd-name { color: var(--gold); }
.recipe-card.tier-4 .rcd-tier { color: rgba(240,178,63,.75); }
.recipe-card.tier-0 { opacity: .82; }
.rcd-head { display: flex; align-items: center; gap: 8px; }
.rcd-icon { font-size: 20px; line-height: 1; }
.rcd-heading { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.rcd-name { font-size: 13px; font-weight: 800; color: var(--gold-soft); }
.rcd-tier {
  font-size: 9px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--faint); font-weight: 700;
}
.recipe-card.tier-2 .rcd-name, .recipe-card.tier-3 .rcd-name { color: var(--reality); }
.rcd-payout {
  font-family: var(--font-num); font-size: 15px; font-weight: 800; color: var(--good);
}
.rcd-blurb { font-size: 11px; line-height: 1.45; color: var(--faint); font-style: italic; }
.rcd-mods { display: flex; flex-direction: column; gap: 3px; }
.rcd-mod {
  font-size: 11px; line-height: 1.35; padding-left: 11px; position: relative;
}
.rcd-mod::before { content: '+'; position: absolute; left: 0; font-weight: 800; }
.rcd-mod.good { color: var(--good); }
.rcd-mod.bad { color: var(--hot); }
.rcd-mod.bad::before { content: '−'; }
.rcd-mod.neutral { color: var(--faint); }
.rcd-mod.neutral::before { content: '·'; }

/* ------------------------------------------- production collapse heads ---
 * The Towers header mirrors the Upgrades one: the chevron and label are a
 * single button, and the count sits to its right. Collapsing hides the cards
 * with a class rather than [hidden], so the rule below is an ordinary author
 * `display: none` and needs no !important fight with the UA sheet.
 * ------------------------------------------------------------------------ */
.section-head { display: flex; align-items: center; gap: 7px; margin-bottom: 9px; }
.section-collapse {
  display: flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 0; margin: 0;
  cursor: pointer; color: inherit;
}
.section-title {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--faint); font-weight: 800;
}
.section-collapse:hover .section-title { color: var(--text-dim); }
.sc-chev {
  font-size: 10px; line-height: 1; color: var(--faint);
  transition: transform var(--t-fast) var(--ease);
}
.section-count {
  font-family: var(--font-num); font-size: 10.5px; font-weight: 700;
  color: var(--text-dim); background: var(--panel-2);
  border: 1px solid var(--line-soft);
  padding: 1px 7px; border-radius: 999px;
}
.towers-collapsed .sc-chev { transform: rotate(-90deg); }
/* Every tower card goes; the farm block is a sibling in the same list and
   stays, which is what puts the summary and the Farm on one screen. */
.towers-collapsed .prod-item,
.towers-collapsed .prod-list > .empty-note { display: none; }
/* With the towers gone there is nothing to separate the farm from, so it sits
   straight under the Towers header. */
.towers-collapsed .farm-block { margin-top: 0; }

/* ============================================================== the farm ==
 * Two components: the seed shelf in the Store (under the towers, behind a
 * rule) and the farm block at the bottom of the Production list. Both are
 * hidden outright until the Farm is bought, so `[hidden]` in base.css is
 * doing the work -- nothing here may set `display` on either root, or it
 * would beat the user-agent rule and leave the whole thing on screen.
 * ======================================================================== */

/* ---------------------------------------------------------- seed shelf --- */
.shelf-rule {
  border: 0; border-top: 1px solid var(--line);
  margin: 18px 0 12px;
}
.shelf-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 9px;
}
.shelf-title {
  font-size: 12px; font-weight: 800; letter-spacing: .11em;
  text-transform: uppercase; color: var(--reality);
}
.shelf-note { font-size: 10.5px; color: var(--faint); }

.seed-item {
  display: grid; grid-template-columns: 34px minmax(0,1fr) auto;
  gap: 9px; align-items: center; padding: 8px 10px;
  text-align: left; cursor: pointer; width: 100%;
  border-color: rgba(169,139,255,.14);
}
.seed-item.affordable { border-color: rgba(169,139,255,.4); }
.seed-item.affordable:hover {
  transform: scaleY(1.045); box-shadow: var(--shadow-2);
  border-color: rgba(169,139,255,.7);
}
.sd-icon {
  width: 34px; height: 34px; border-radius: 9px; font-size: 18px;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 28%, var(--panel-3), #191410);
  border: 1px solid var(--line-soft);
}
.sd-name { font-size: 13px; font-weight: 700; color: var(--text); }
.sd-grow { font-size: 10.5px; color: var(--faint); font-family: var(--font-num); margin-top: 1px; }
.sd-right { text-align: right; }
.sd-cost {
  font-family: var(--font-num); font-size: 12.5px; font-weight: 700;
  color: var(--reality); white-space: nowrap;
}
.seed-item:not(.affordable) .sd-cost { color: #7a6aa8; }
.sd-held { font-family: var(--font-num); font-size: 10.5px; color: var(--muted); margin-top: 2px; }

/* ---------------------------------------------------------- farm block --- */
.farm-block { margin-top: 14px; }
/* Collapsed: the header and the summary stay, everything below them goes.
   Keeping the summary is the whole point of collapsing -- it mirrors the way
   the tower summary survives collapsing the towers -- so .prod-summary is
   deliberately NOT in this list. renderFarm() keeps writing it. */
.farm-block.collapsed .sc-chev { transform: rotate(-90deg); }
.farm-block.collapsed .farm-grid,
.farm-block.collapsed .farm-breed,
.farm-block.collapsed .breed-msg,
.farm-block.collapsed .farm-inv,
.farm-block.collapsed .farm-codex { display: none; }

/* --- the 4x4 grid --- */
.farm-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px;
  margin-bottom: 11px;
}
.plot {
  position: relative; aspect-ratio: 1 / 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; padding: 0; cursor: pointer;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-soft);
  background: linear-gradient(165deg, #2a2118, #1b1610);
  color: var(--text);
  transition: border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.plot:hover { transform: scale(1.05); border-color: var(--line); }
.plot.is-empty {
  background: repeating-linear-gradient(135deg, #241d16 0 6px, #1e1811 6px 12px);
}
.plot.is-empty::after {
  content: '+'; position: absolute; font-size: 18px; color: var(--faint);
  opacity: 0; transition: opacity var(--t-fast) var(--ease);
}
.plot.is-empty:hover::after { opacity: 1; }

/* The growth ring. `--p` is a 0..1 fraction written by renderFarm; a conic
   gradient is the cheapest way to draw it without a second element per plot. */
.plot-ring {
  position: absolute; inset: 3px; border-radius: inherit;
  pointer-events: none;
  background: conic-gradient(rgba(124,196,111,.34) calc(var(--p, 0) * 360deg),
                             transparent 0);
  -webkit-mask: radial-gradient(circle, transparent 60%, #000 61%);
          mask: radial-gradient(circle, transparent 60%, #000 61%);
}
.plot-icon { font-size: 22px; line-height: 1; z-index: 1; }
.plot-time {
  font-family: var(--font-num); font-size: 9.5px; font-weight: 650;
  color: var(--muted); z-index: 1;
}
.plot.is-ready {
  border-color: rgba(124,196,111,.6);
  box-shadow: 0 0 0 1px rgba(124,196,111,.2), 0 0 16px -4px rgba(124,196,111,.5);
}
.plot.is-ready .plot-icon { animation: plotReady 2.4s ease-in-out infinite; }
.plot.is-hybrid { border-color: rgba(169,139,255,.42); }
.plot.is-hybrid.is-ready {
  border-color: rgba(169,139,255,.75);
  box-shadow: 0 0 0 1px rgba(169,139,255,.25), 0 0 18px -4px rgba(169,139,255,.55);
}
.plot.inert { opacity: .38; cursor: default; }
.plot.inert:hover { transform: none; }
.plot.picked {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgba(240,178,63,.35), 0 0 18px -4px rgba(240,178,63,.55);
}
.plot-pick {
  position: absolute; top: 3px; right: 4px; z-index: 2;
  font-family: var(--font-num); font-size: 10px; font-weight: 800;
  color: #1a1409; background: var(--gold);
  min-width: 15px; height: 15px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
}
.plot-pick:empty { display: none; }

/* --- breeding bar --- */
.farm-breed { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.breed-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 11px 6px 8px; border-radius: 999px; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--line-soft);
  color: var(--muted); font-size: 12px; font-weight: 700;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.breed-toggle:hover { color: var(--text); border-color: var(--line); }
.bt-switch {
  width: 26px; height: 15px; border-radius: 999px; flex: 0 0 auto;
  background: #3a3128; position: relative;
  transition: background var(--t-fast) var(--ease);
}
.bt-switch::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 11px; height: 11px; border-radius: 50%; background: var(--muted);
  transition: transform var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.breed-toggle.on { color: var(--reality); border-color: rgba(169,139,255,.45); }
.breed-toggle.on .bt-switch { background: var(--reality-2); }
.breed-toggle.on .bt-switch::after { transform: translateX(11px); background: #fff; }

.breed-go {
  padding: 6px 13px; border-radius: 999px; font-size: 12px; font-weight: 700;
  background: var(--reality-2); border: 1px solid var(--reality); color: #fff;
  cursor: pointer;
}
.breed-go:disabled { opacity: .4; cursor: default; }
.breed-msg {
  margin-top: 8px; font-size: 11.5px; line-height: 1.45;
  font-style: italic; color: var(--text-dim);
}
.breed-msg.bad { color: #ff9b8a; }
.breed-msg.good { color: var(--good); }

/* --- inventory --- */
.farm-inv { margin-top: 13px; }
.inv-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 7px; }
.inv-title {
  font-size: 10px; letter-spacing: .11em; text-transform: uppercase;
  color: var(--faint); font-weight: 800;
}
.inv-hint { font-size: 10px; color: var(--faint); }
.inv-list { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.inv-item {
  display: grid; grid-template-columns: 22px minmax(0,1fr) auto;
  gap: 7px; align-items: center;
  padding: 6px 8px; border-radius: var(--radius-sm); cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--line-soft);
  color: var(--text); text-align: left;
}
.inv-item:hover { border-color: var(--line); }
.inv-item.selected {
  border-color: var(--gold);
  box-shadow: 0 0 0 1px rgba(240,178,63,.3);
  background: rgba(240,178,63,.09);
}
.inv-icon { font-size: 16px; }
.inv-text { min-width: 0; }
.inv-name {
  display: block; font-size: 11.5px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.inv-sub { display: block; font-size: 9.5px; color: var(--faint); font-family: var(--font-num); }
.inv-count { font-family: var(--font-num); font-size: 11.5px; font-weight: 700; color: var(--gold); }

/* --- codex --- */
.farm-codex { margin-top: 13px; }
.codex-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 7px; }
.codex-title {
  font-size: 10px; letter-spacing: .11em; text-transform: uppercase;
  color: var(--faint); font-weight: 800;
}
.codex-count { font-family: var(--font-num); font-size: 11px; color: var(--reality); font-weight: 700; }
.codex-list { display: flex; flex-wrap: wrap; gap: 5px; }
.codex-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px 3px 6px; border-radius: 999px;
  font-size: 10.5px; font-weight: 650;
  background: rgba(169,139,255,.08); border: 1px solid rgba(169,139,255,.2);
  color: var(--text-dim);
}
.codex-chip.t1 { background: rgba(169,139,255,.12); }
.codex-chip.t2 { background: rgba(169,139,255,.18); border-color: rgba(169,139,255,.35); color: var(--text); }
.codex-chip.t3 {
  background: rgba(169,139,255,.26); border-color: var(--reality); color: #fff;
}
.cc-icon { font-size: 12px; }

@media (max-width: 420px) {
  .inv-list { grid-template-columns: 1fr; }
}

/* ====================================================== HOVER LIFT =======
 * A `:hover` rule that moves an element with translateY() moves its hit box
 * with it. Park the pointer within the lift distance of the bottom edge and
 * the element slides out from under it: :hover drops, the transform reverses,
 * the element returns under the pointer, :hover re-applies. That oscillates at
 * frame rate for as long as the pointer sits there, and it is what made the
 * Upgrade, Transcend, store, seed and farm-plot controls flicker. Measured
 * with a still cursor 0.5px above the bottom edge: 40 enter/leave events in
 * 1.2 seconds.
 *
 * **No :hover rule in this file may use translateY().** translate is
 * origin-independent, so it always moves the bottom edge. The replacement is
 * `transform-origin: bottom center` plus a pure scale(): scaling about the
 * bottom edge only ever grows the box upward and sideways, so a pointer
 * anywhere inside the resting box is still inside the hovered box, at any
 * scale factor. That is a property of the geometry, not a tuned value, so it
 * cannot be broken by resizing a control later.
 *
 * Wide controls scale on Y only. A uniform scale large enough to read as a
 * lift would widen a 362px store card by ~23px; scaleY() gives the same rise
 * with no horizontal growth, and 3-6% of vertical stretch on a ~50px card is
 * not perceptible.
 *
 * > **Trap: a hit-box "skirt" pseudo-element does not work here.** The obvious
 * > alternative -- an `X:hover::before` covering the band the element just
 * > vacated -- was built, measured, and had *no effect at all* on `.btn`,
 * > `.store-item`, `.seed-item` or `.plot`. All four are `<button>` elements,
 * > and Chromium does not hit-test a button's pseudo-elements. The A/B numbers
 * > were identical with the skirt present and absent (Store tower: 12 events
 * > before, 12 after). Do not reintroduce it.
 *
 * The origin is applied on `:hover` only, never on the base rule. `upgPop`,
 * `upgIn` and `achShine` in animations.css are all authored about the centre,
 * and a base-rule origin silently re-pivoted every one of them.
 *
 * `.bonus-pie` already scaled about its centre, which grows in every
 * direction, so it was never affected and is left alone.
 * ======================================================================== */

/* ================================ THE THREE PRODUCTION PANELS ============
 * Reactor, Prism and Constellation, in that order under the Farm. They share
 * one chrome -- a 2x2 .prod-summary, a .section-head that collapses, a body of
 * cards -- so the Production tab reads as one column of sections rather than
 * as a tab plus three visitors.
 *
 * Colour carries the currency, the same convention the rest of the game uses:
 * the Reactor is bought with Pies and is gold, the Constellation is bought
 * with Reality Shards and is purple, and the Prism costs nothing at all so it
 * takes its colour from the channels themselves.
 *
 * Every root is hidden with the `hidden` attribute until its upgrade is
 * bought, so nothing here may set `display` on `.panel-block` -- an author
 * rule beats the user-agent one and would leave a locked panel on screen.
 * ======================================================================== */

.panel-block { margin-top: 16px; }
.towers-collapsed .panel-block { margin-top: 12px; }
/* Collapsed keeps the summary, exactly as the Towers and Farm sections do --
   the counters are the reason to collapse, not part of what is collapsed. */
.panel-block.collapsed .sc-chev { transform: rotate(-90deg); }
.panel-block.collapsed .panel-body { display: none; }

.panel-body { display: flex; flex-direction: column; gap: 7px; }

/* --- the card shared by all three ---------------------------------------- */
.pl-card { padding: 10px 11px; opacity: .78; }
.pl-card.lit { opacity: 1; }
.pl-head { display: grid; grid-template-columns: 36px minmax(0,1fr) auto; gap: 9px; align-items: center; }
.pl-icon {
  width: 36px; height: 36px; border-radius: 10px; font-size: 19px;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 28%, var(--panel-3), #191410);
  border: 1px solid var(--line-soft);
}
.pl-mid { min-width: 0; }
.pl-name { font-size: 12.5px; font-weight: 700; }
.pl-eff { font-size: 10.5px; color: var(--muted); margin-top: 2px; line-height: 1.4; }
.pl-lvl {
  font-family: var(--font-num); font-size: 15px; font-weight: 700;
  color: var(--gold-soft); text-align: right; white-space: nowrap;
}
.pl-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 8px; }
.pl-actions .btn { padding: 6px 7px; }
.pl-actions .btn-cost { font-size: 10px; }

/* --- Reactor -------------------------------------------------------------- */
.rod-card.lit { border-color: rgba(240,178,63,.28); }
.rod-card.lit .pl-icon {
  border-color: rgba(240,178,63,.4);
  box-shadow: 0 0 12px -4px rgba(240,178,63,.65);
}

/* --- Prism ----------------------------------------------------------------
 * The bar is the only place the allocation is visible as a shape rather than
 * as five numbers, so it sits above the cards and uses the same five tones. */
.prism-bar {
  display: flex; height: 8px; border-radius: 999px; overflow: hidden;
  background: rgba(255,236,205,.06); border: 1px solid var(--line-soft);
  margin-bottom: 4px;
}
.prism-seg { width: 0; transition: width var(--t-med) var(--ease); }
.prism-seg.tone-amber     { background: linear-gradient(90deg, var(--gold-deep), var(--gold)); }
.prism-seg.tone-crimson   { background: linear-gradient(90deg, var(--filling-2), var(--filling)); }
.prism-seg.tone-violet    { background: linear-gradient(90deg, var(--reality-2), var(--reality)); }
.prism-seg.tone-azure     { background: linear-gradient(90deg, #2f6f9e, var(--cold)); }
.prism-seg.tone-verdigris { background: linear-gradient(90deg, #3f7a4a, var(--good)); }

.chan-card.tone-amber.lit     { border-color: rgba(240,178,63,.35); }
.chan-card.tone-crimson.lit   { border-color: rgba(192,57,43,.42); }
.chan-card.tone-violet.lit    { border-color: rgba(169,139,255,.4); }
.chan-card.tone-azure.lit     { border-color: rgba(103,174,224,.38); }
.chan-card.tone-verdigris.lit { border-color: rgba(124,196,111,.38); }
.chan-card.tone-amber .pl-lvl     { color: var(--gold-soft); }
.chan-card.tone-crimson .pl-lvl   { color: #f0a294; }
.chan-card.tone-violet .pl-lvl    { color: var(--reality); }
.chan-card.tone-azure .pl-lvl     { color: var(--cold); }
.chan-card.tone-verdigris .pl-lvl { color: var(--good); }

/* Five steppers on one row. Deliberately not the two-column .pl-actions grid:
   moving facets is a dial, and a dial wants small equal presses. */
.pl-actions.steppers { grid-template-columns: repeat(5, 1fr); gap: 4px; }
.btn-step {
  flex-direction: row; justify-content: center;
  padding: 5px 4px; font-family: var(--font-num);
  font-size: 11px; font-weight: 700; color: var(--text-dim);
}
.btn-step:hover:not(:disabled) { color: var(--gold-soft); }
.prism-reset {
  margin-top: 4px; padding: 7px 10px;
  font-size: 11px; font-weight: 700; color: var(--muted);
}
.prism-reset:hover:not(:disabled) { color: var(--text); }

/* --- Constellation --------------------------------------------------------
 * Shard-bought, so purple throughout, matching the Automations tab and the
 * seed shelf. The Axis is the one star that is not a multiplier and it is
 * marked as such rather than left to be found in a tooltip. */
.star-card { border-color: rgba(169,139,255,.14); }
.star-card.lit { border-color: rgba(169,139,255,.36); }
.star-card .pl-lvl { color: var(--reality); }
.star-card.lit .pl-icon {
  border-color: rgba(169,139,255,.45);
  box-shadow: 0 0 14px -4px rgba(169,139,255,.7);
}
.star-card .btn-cost { color: var(--reality); }
.star-card .btn.can .btn-cost { color: #d6c7ff; }
.star-card.axis {
  background: linear-gradient(135deg, rgba(111,78,224,.16), transparent 62%);
  border-color: rgba(169,139,255,.34);
}
.star-card.axis .pl-name { color: var(--reality); }
.star-card.maxed .pl-lvl { color: var(--good); }
.star-card.maxed .btn { opacity: .4; }

.stars-block .ps-value { color: var(--reality); }

/* =========================== THE NOVA LAYER ==============================
   Its own palette -- white-gold rather than the violet Ascension owns -- so
   that at a glance a Nova control is never mistaken for a Reality one. The
   two live side by side in the top bar and in the tooltips. */

:root { --nova: #ffd77a; --nova-2: #ff8a3c; --nova-dim: rgba(255,215,122,.16); }

.tb-novas .tb-value { color: var(--nova); }
.nova-glyph { font-size: .82em; opacity: .9; }

/* ------------------------------------------------- the centre-column bar -- */
.nova-zone { flex: 0 0 auto; margin-top: 10px; width: min(520px, 100%); text-align: center; }
.nova-bar {
  height: 6px; border-radius: 999px; overflow: hidden;
  background: rgba(255,215,122,.12);
  border: 1px solid rgba(255,215,122,.26);
}
.nova-fill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--nova-2), var(--nova), #fff6de);
  box-shadow: 0 0 16px rgba(255,196,92,.7);
  transition: width var(--t-slow) var(--ease);
}
.nova-caption {
  margin-top: 5px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .09em;
  color: rgba(255,215,122,.72);
  font-family: var(--font-num);
}

/* ------------------------------------------------------------- the tab --- */
.nova-head { margin-bottom: 10px; }
.nova-head .ps-value { color: var(--nova); }
.nova-note {
  margin-top: 9px; font-size: 11px; font-style: italic;
  color: var(--faint); line-height: 1.45;
}

/* The wrapper scrolls; the grid inside it is a fixed pixel canvas that the
   two layers (links and nodes) share, so a link can never drift off a node. */
.nova-tree-wrap { overflow-x: auto; overflow-y: hidden; padding-bottom: 6px; }
.nova-grid { position: relative; margin: 0 auto; }

.nova-links { position: absolute; inset: 0; pointer-events: none; }
.nova-link {
  stroke: rgba(255,224,178,.10);
  stroke-width: 2;
  transition: stroke var(--t-med) var(--ease), stroke-width var(--t-med) var(--ease);
}
.nova-link.open { stroke: rgba(255,215,122,.42); stroke-width: 2.5; }
.nova-link.done { stroke: rgba(255,215,122,.85); stroke-width: 3; filter: drop-shadow(0 0 4px rgba(255,196,92,.65)); }

/* ----------------------------------------------------------- the nodes --- */
.nova-node {
  position: absolute;
  /* Must match NOVA_CELL in ui.js -- the link endpoints are computed from it. */
  width: 44px; height: 44px;
  border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--panel-2);
  border: 2px solid var(--line);
  color: var(--muted);
  /* transform-origin + scale only. A :hover that used translateY() would move
     the hit box and make the node flicker at its bottom edge -- invariant 8. */
  transform-origin: center center;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.nn-icon { font-size: 19px; line-height: 1; filter: grayscale(1) opacity(.45); transition: filter var(--t-med) var(--ease); }

.nova-node.locked { opacity: .5; border-style: dashed; cursor: not-allowed; }
.nova-node.can {
  border-color: var(--nova);
  background: linear-gradient(160deg, rgba(255,215,122,.16), rgba(255,138,60,.06));
  box-shadow: 0 0 0 3px rgba(255,215,122,.12), 0 0 18px rgba(255,196,92,.35);
  animation: novaPulse 2.1s var(--ease) infinite;
}
.nova-node.can .nn-icon { filter: none; }
.nova-node.owned { border-color: rgba(255,215,122,.7); background: rgba(255,215,122,.08); }
.nova-node.owned .nn-icon { filter: none; }
.nova-node.maxed {
  border-color: #fff3d2;
  background: linear-gradient(160deg, rgba(255,243,210,.22), rgba(255,138,60,.10));
  box-shadow: 0 0 20px rgba(255,214,120,.55);
  animation: none;
}
body:not(.no-hover-anim) .nova-node:not(:disabled):hover { transform: scale(1.12); }
.nova-node:disabled { cursor: default; }

@keyframes novaPulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(255,215,122,.10), 0 0 14px rgba(255,196,92,.28); }
  50%      { box-shadow: 0 0 0 5px rgba(255,215,122,.20), 0 0 26px rgba(255,196,92,.55); }
}

/* Six pips ride the bottom arc of the circle: "one purchase plus five
   upgrades" has to be readable without opening the tooltip. */
.nn-pips {
  position: absolute; left: 0; right: 0; bottom: -9px;
  display: flex; justify-content: center; gap: 2px;
}
.nn-pip {
  width: 4px; height: 4px; border-radius: 50%;
  background: rgba(255,224,178,.16);
  transition: background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.nn-pip.on { background: var(--nova); box-shadow: 0 0 5px rgba(255,196,92,.9); }

.nn-cost {
  position: absolute; top: -8px; right: -6px;
  min-width: 16px; padding: 1px 4px;
  border-radius: 999px;
  font-family: var(--font-num); font-size: 9.5px; font-weight: 800;
  background: var(--panel-3); border: 1px solid var(--line);
  color: var(--gold-soft);
}
.nova-node.can .nn-cost { background: var(--nova); border-color: var(--nova); color: #241a08; }
.nova-node.maxed .nn-cost { color: var(--nova); font-size: 8px; letter-spacing: .06em; }
.nova-node.locked .nn-cost { background: transparent; border-color: transparent; }

@keyframes novaBought {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.35); box-shadow: 0 0 34px rgba(255,214,120,.9); }
  100% { transform: scale(1); }
}
.nova-node.bought { animation: novaBought .5s var(--ease); }
body.reduced-animations .nova-node.bought,
body.reduced-animations .nova-node.can { animation: none; }
