/* ============================================================
   Ecosystem Puzzle
   A meadow read from above: paper-pale ground, soft green ink,
   and one warm accent that only the animals are allowed to use.
   ============================================================ */

:root {
  --ink: #3c4a36;
  --ink-soft: #6d7a66;
  --ink-faint: #9aa593;

  --paper: #f7f9f0;
  --card: #ffffff;
  --ground: #e9f0dc;
  --ground-deep: #dde8cc;
  --line: #d3e0be;

  --green: #5a9e4b;
  --green-bright: #7ec05c;
  --green-deep: #41773a;
  --warm: #e08a4a;
  --bone: #cfc8b3;

  --radius: 14px;
  --radius-sm: 10px;
  --shadow: 0 1px 2px rgba(60, 74, 54, .08), 0 6px 18px rgba(60, 74, 54, .07);

  --font: "Hiragino Sans", "Noto Sans JP", -apple-system, BlinkMacSystemFont,
    "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 16px 8px;
  font-family: var(--font);
  color: var(--ink);
  background:
    radial-gradient(1200px 400px at 50% -80px, #eef6e2 0%, rgba(238, 246, 226, 0) 70%),
    var(--paper);
  -webkit-text-size-adjust: 100%;
}

body.is-modal { overflow: hidden; }

.sprite-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.wrap {
  max-width: 480px;
  margin: 0 auto;
  padding-block: 20px 8px;
}

/* ---------- Title ---------- */

.topbar { text-align: center; margin-bottom: 18px; }

.title {
  position: relative;
  display: inline-block;
  margin: 0;
  padding-bottom: 12px;
  font-size: clamp(1.55rem, 7vw, 2.1rem);
  line-height: 1.05;
  letter-spacing: -.015em;
  font-weight: 700;
}

.title-word { color: var(--ink); }

/* the second word is lifted a touch and a sprout pushes up between the
   two, so the name itself looks like something growing out of a field */
.title-word--2 {
  position: relative;
  margin-left: .34em;
  color: var(--green);
}

.title-sprout {
  position: absolute;
  left: -.58em;
  bottom: -.02em;   /* its stem has to reach the field line, or it reads
                       as a stray mark rather than something growing */
  width: .7em;
  height: .92em;
  overflow: visible;
}

.title-field {
  position: absolute;
  left: -4%;
  right: -4%;
  bottom: 0;
  width: 108%;
  height: 12px;
}

.tagline {
  margin: 8px 0 0;
  color: var(--ink-soft);
  font-size: .92rem;
}

/* ---------- Scores ---------- */

.scorebar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 12px;
}

.score {
  flex: 1;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 9px 14px;
  box-shadow: var(--shadow);
}

.score-label {
  display: block;
  font-size: .7rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.score-value {
  display: block;
  font-size: 1.5rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.score--best .score-value { color: var(--ink-soft); }

/* ---------- The rung ----------
   One accent per level, walking the same path the meadow does: bare
   ground, then green, then green with some age on it, and the warm
   accent — the one otherwise reserved for animals — at the top, where
   almost nobody is. The bar behind the words is the difficulty curve;
   it fills in a couple of turns on Lv 1 and barely moves on Lv 6. */
.level {
  flex: 1 0 100%;
  --rung: var(--ink-faint);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 8px 14px 10px;
  box-shadow: var(--shadow);
}

.level[data-level="2"] { --rung: var(--green-bright); }
.level[data-level="3"] { --rung: var(--green); }
.level[data-level="4"] { --rung: #4a8c3e; }
.level[data-level="5"] { --rung: #35702f; }
.level[data-level="6"] { --rung: var(--warm); }

.level-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
  margin-bottom: 7px;
}

.level-num {
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #fff;
  background: var(--rung);
  border-radius: 999px;
  padding: 2px 8px;
  white-space: nowrap;
}

.level-name {
  font-size: .95rem;
  font-weight: 600;
  color: var(--rung);
}

/* Pushed to the far end so the eye reads name first, cost second. */
.level-next {
  margin-left: auto;
  font-size: .72rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.level-track {
  display: block;
  height: 7px;
  border-radius: 999px;
  background: var(--ground-deep);
  overflow: hidden;
}

.level-fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--rung) 0%, var(--rung) 65%, #fff8 100%);
  transition: width .45s cubic-bezier(.2, .8, .3, 1);
}

@media (prefers-reduced-motion: reduce) {
  .level-fill { transition: none; }
}

/* ---------- Hand ---------- */

.handbar {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: 10px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 14px;
  box-shadow: var(--shadow);
  margin-bottom: 14px;
}

.hand-slot { text-align: center; }

.hand-tiles {
  display: flex;
  gap: 6px;
  justify-content: center;
}

/* .tile is declared further down with the same specificity, so this has
   to out-rank it rather than merely follow it.

   Big, because this is the one thing you have to read before every tap:
   at the old 38px a sprout and a patch of grass were the same green
   smudge, and telling them apart is the whole decision. The pale fill
   under the art is the same one a taken square gets, so a tile in hand
   already looks like a tile on the board. */
.tile.hand-tile {
  width: 52px;
  height: 52px;
  border-width: 2px;
  background: rgba(255, 255, 255, .72);
}

/* An empty slot has to read as a slot, not as a gap in the layout, or
   the hand looks like it shrank rather than emptied. */
.hand-tile.is-empty {
  background: transparent;
  border-style: dashed;
  border-color: var(--line);
  opacity: .75;
}

.refill {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 5px;
}

.refill-track {
  /* a span, so it has to be told to be a box: on narrow screens .refill
     stops being a flex container and an inline track collapses to
     nothing — which took the whole meter off the phone layout, the one
     place it is most needed. */
  display: block;
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: var(--ground);
  overflow: hidden;
}

.refill-fill {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 2px;
  background: var(--green);
  transition: width .18s linear;
}

.refill-word {
  font-size: .6rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
}

.pause-note {
  grid-column: 1 / -1;
  margin: 0;
  font-size: .78rem;
  color: var(--ink-soft);
  font-style: italic;
}

/* The board reads as out of reach while the hand is empty, so a tap that
   cannot do anything looks like it cannot rather than like a bug. */
.board--spent { opacity: .82; }

/* ...and if the tap happens anyway, the hand answers for the board. An
   empty hand is the only refusal in the game that looks exactly like a
   dead button: the square was empty, the tap was legal, and nothing
   moved. So the hand flinches and the meter lights up, which puts your
   eyes on the thing that is actually running out. */
@keyframes hand-nudge {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-5px); }
  45% { transform: translateX(4px); }
  70% { transform: translateX(-2px); }
}

.hand-slot--nudge .hand-tiles { animation: hand-nudge .38s ease; }

.hand-slot--nudge .hand-tile.is-empty {
  border-color: var(--green);
  opacity: 1;
}

.hand-slot--nudge .refill-track { box-shadow: 0 0 0 2px rgba(90, 158, 75, .35); }
.hand-slot--nudge .refill-fill { background: var(--green-bright); }
.hand-slot--nudge .refill-word { color: var(--green); }

.btn--speed[aria-pressed="true"] {
  border-color: var(--green);
  color: var(--ink);
}

.hand-label {
  display: block;
  font-size: .64rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 2px;
}

.tile {
  display: block;
  width: 46px;
  height: 46px;
  border-radius: var(--radius-sm);
  background: var(--ground);
  border: 1px solid var(--line);
}

/* Still quieter than the hand — it is not yours yet — but no longer so
   faint that you cannot tell which tile is coming. */
.tile--next {
  width: 42px;
  height: 42px;
  opacity: .88;
  margin-top: 6px;
}

.tile-art { display: block; width: 100%; height: 100%; }

/* the standing instruction: what the board is one step away from */
.goal {
  grid-column: 3;
  align-self: center;
  margin: 0;
  padding-left: 2px;
  font-size: .88rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--green);
}

/* and under it, what just happened */
.ticker {
  grid-column: 1 / -1;
  margin: 0;
  padding-top: 2px;
  min-height: 2.4em;
  font-size: .82rem;
  line-height: 1.35;
  color: var(--ink-faint);
}

/* ---------- Season ---------- */

.season {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 4px 10px;
  margin-bottom: 10px;
  padding: 9px 14px 12px;
  border: 1px solid var(--season-line, var(--line));
  border-radius: var(--radius);
  background: var(--season-bg, #fff);
  overflow: hidden;
  transition: background .4s ease, border-color .4s ease;
}

.season-name {
  font-size: .95rem;
  font-weight: 700;
  color: var(--season-ink, var(--green));
}

.season-note {
  font-size: .76rem;
  line-height: 1.3;
  color: var(--ink-soft);
}

.season-mult {
  font-size: 1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--season-ink, var(--green));
}

.season-mult { white-space: nowrap; justify-self: end; }
.season-next {
  grid-column: 1 / -1;
  font-size: .72rem;
  line-height: 1.4;
  color: var(--season-ink, var(--green));
  font-variant-numeric: tabular-nums;
}

/* how far through this difficulty stage the run is */
.season-track {
  grid-column: 1 / -1;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: rgba(90, 110, 80, .1);
}

.season-fill {
  display: block;
  height: 100%;
  background: var(--season-ink, var(--green));
  opacity: .55;
  transition: width .25s ease;
}

/* Each season repaints the strip, so the run visibly moves through the
   year rather than just getting harder for no stated reason. */
.season[data-season="0"] { --season-bg: #f2f9ea; --season-line: #cfe4bb; --season-ink: #5a9e4b; }
.season[data-season="1"] { --season-bg: #f6fbe6; --season-line: #d9e6ae; --season-ink: #7a9b32; }
.season[data-season="2"] { --season-bg: #fdf4e6; --season-line: #ecd3ac; --season-ink: #c47f34; }
.season[data-season="3"] { --season-bg: #eef2f6; --season-line: #ccd7e0; --season-ink: #5b7890; }

/* ---------- Board ---------- */

.board-frame { position: relative; }

.board {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 7px;
  padding: 9px;
  background: linear-gradient(160deg, var(--ground) 0%, var(--ground-deep) 100%);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7), var(--shadow);
}

.cell {
  position: relative;
  aspect-ratio: 1 / 1;
  min-width: 0;
  padding: 0;
  border: 1px solid rgba(120, 150, 100, .18);
  border-radius: 11px;
  background: rgba(255, 255, 255, .42);
  font: inherit;
  cursor: pointer;
  transition: background .12s ease, transform .12s ease;
  -webkit-tap-highlight-color: transparent;
}

.cell:not(:disabled):hover { background: rgba(255, 255, 255, .8); }
.cell:not(:disabled):active { transform: scale(.95); }

.cell:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 2px;
}

.cell--taken {
  background: rgba(255, 255, 255, .72);
  cursor: default;
}

.cell--bones,
.cell--scrub,
.cell--stone {
  background: rgba(206, 198, 178, .38);
  border-color: rgba(150, 142, 120, .3);
}

/* anything alive carries a meter, so it sits high in the square */
.cell .tile-art {
  position: absolute;
  inset: 2% 4% 16%;
  width: 92%;
  height: 82%;
}

/* dead ground has no clock, so it gets the whole square */
.cell--bones .tile-art,
.cell--scrub .tile-art,
.cell--stone .tile-art { inset: 7%; width: 86%; height: 86%; }

/* The one tile that does not fit in a square. It is four squares of the
   twenty-five, so it does not need decoration to be noticed — it needs a
   rim and a shadow that say it is standing ON the meadow rather than in
   it, and art with room to breathe now that the square is that big. */
.cell--big {
  border-color: rgba(120, 150, 100, .38);
  box-shadow: 0 4px 14px rgba(60, 80, 45, .22), inset 0 1px 0 rgba(255, 255, 255, .8);
  z-index: 1;
}

.cell--big .tile-art { inset: 4% 6% 14%; width: 88%; height: 82%; }

/* a tile in its last turns loses a little colour */
.cell--fading .tile-art { opacity: .72; }

/* raised by a merge, and therefore the only thing an elephant will eat.
   A small notch in the top-left corner rather than a word: it has to be
   readable on twenty-five tiles at once without competing with the
   hunger meter, and it only appears at all from the tiger onward. */
.cell--raised::before {
  content: "";
  position: absolute;
  top: 4px;
  left: 4px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #6b4a86;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .75);
  pointer-events: none;
  z-index: 2;
}

/* within reach of a hungry mouth next turn: a dashed warm ring, so the
   shape of an animal's reach is something you can see and build around */
.cell--inreach {
  border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--warm);
  background: rgba(224, 138, 74, .12);
}

.cell--inreach::after {
  content: "";
  position: absolute;
  inset: 3px;
  border: 1.5px dashed rgba(224, 138, 74, .55);
  border-radius: 8px;
  pointer-events: none;
}

/* ---------- Hunger meter ---------- */

.meter {
  position: absolute;
  left: 16%;
  right: 16%;
  bottom: 7%;
  height: 5px;
  border-radius: 3px;
  background: rgba(90, 110, 80, .18);
  overflow: hidden;
}

.meter-fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--green-bright);
  transition: width .18s ease;
}

.meter-fill.is-mid { background: #e8c057; }
.meter-fill.is-low { background: #dd6a52; }

/* ---------- Turn feedback ---------- */

@keyframes grew {
  0% { transform: scale(.6); }
  60% { transform: scale(1.12); }
  100% { transform: scale(1); }
}
@keyframes eaten {
  0% { background: rgba(224, 138, 74, .5); }
  100% { background: rgba(255, 255, 255, .42); }
}
@keyframes died {
  0%, 40% { background: rgba(196, 150, 84, .38); }
  100% { background: rgba(206, 198, 178, .38); }
}

.cell--grew { animation: grew .28s ease-out; }
.cell--eaten { animation: eaten .5s ease-out; }
.cell--died { animation: died .6s ease-out; }

@media (prefers-reduced-motion: reduce) {
  .cell--grew, .cell--eaten, .cell--died { animation: none; }
  .cell:not(:disabled):active { transform: none; }
  /* the colour half of the nudge still lands, so the message is not lost
     with the movement */
  .hand-slot--nudge .hand-tiles { animation: none; }
}

/* ---------- Game over ---------- */

/* both overlays set `display`, which outranks the browser's own rule for
   [hidden] — without this they are never actually hidden */
.modal[hidden],
.gameover[hidden] { display: none; }

.start-screen[hidden] { display: none; }

/* A painted meadow the player looks at once before the first tap: sky,
   a mountain with low hills in front, five animals out of the chain, and
   the wordmark above them. The board waits behind it, already dealt. */

.start-screen {
  position: fixed;
  z-index: 20;
  inset: 0;
  display: grid;
  place-items: center;
  background: linear-gradient(#e8f4fb 0%, #f2f9e8 38%, #e7f2d3 100%);
}

/* the poster keeps a phone-shaped column on a wide screen; the sky
   behind it is the same gradient, so the edges do not show */
.start-stage {
  position: relative;
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  width: min(100%, 560px);
  height: 100%;
  overflow: hidden;
  padding:
    calc(env(safe-area-inset-top, 0px) + 16px) 20px
    calc(env(safe-area-inset-bottom, 0px) + 22px);
}

/* ---- the scene ---- */

.start-scene { position: absolute; inset: 0; pointer-events: none; }

.start-sun {
  position: absolute;
  top: 8%;
  right: 12%;
  width: 74px;
  height: 74px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff6d8 0%, #ffe9a8 55%, rgba(255, 233, 168, 0) 72%);
}

.start-cloud {
  position: absolute;
  height: 20px;
  border-radius: 999px;
  background: #fff;
  opacity: .75;
  box-shadow: 22px 6px 0 -3px #fff, -20px 5px 0 -4px #fff;
}

.start-cloud--1 { top: 11%; left: 8%; width: 66px; animation: start-drift 34s linear infinite; }

/* the meadow is the grid row between the title and PLAY; it reaches out
   over the stage padding so the grass meets both window edges */
.start-meadow {
  position: relative;
  margin: 8px -20px 10px;
  container-type: size;
  pointer-events: none;
}

/* stretched to the row, never cropped: the paths reach past the box,
   and the animals use the same percentages, so they move with the hills */
.start-hills { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.start-mountain { fill: #a6e86d; }
.start-knolls { fill: #7fd04b; stroke: rgba(255, 255, 255, .35); stroke-width: 4px; vector-effect: non-scaling-stroke; }

/* --x / --y are the spot on the hill line under the animal's feet; the
   size follows the row's height so a short screen gets a smaller herd */
.start-critter {
  position: absolute;
  left: var(--x);
  bottom: var(--y);
  width: auto;
  height: min(var(--start-size), var(--start-max));
  translate: -50% 0;
  transform-origin: 50% 100%;
  filter: drop-shadow(0 4px 0 rgba(40, 90, 30, .18));
  animation: start-breathe 3.6s ease-in-out infinite;
  animation-delay: var(--start-delay, 0s);
}

.start-critter--elephant { --start-size: 30cqh; --start-max: 120px; }
.start-critter--zebra { --start-size: 34cqh; --start-max: 110px; }
.start-critter--lion { --start-size: 26cqh; --start-max: 90px; }
.start-critter--fox { --start-size: 17cqh; --start-max: 54px; }
.start-critter--rabbit { --start-size: 18cqh; --start-max: 56px; }

/* ---- top line ---- */

.start-topline {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.start-kicker {
  margin: 0;
  color: var(--green);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}

.start-best {
  margin: 0;
  padding: 7px 13px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .82);
  border: 1px solid var(--line);
  box-shadow: 0 2px 0 rgba(60, 74, 54, .08);
  color: var(--ink-soft);
  font-size: .74rem;
  font-weight: 700;
}

.start-best span { color: var(--ink); font-size: .92rem; }

/* ---- the wordmark ---- */

.start-hero {
  position: relative;
  display: grid;
  place-content: center;
  justify-items: center;
  text-align: center;
}

.start-logo {
  position: relative;
  margin: 0;
  color: #fffdf4;
  font-size: clamp(3rem, 20vw, 4.6rem);
  letter-spacing: -.045em;
  line-height: .86;
  -webkit-text-stroke: 5px var(--green-deep);
  paint-order: stroke fill;
  text-shadow: 0 7px 0 rgba(65, 119, 58, .32), 0 16px 26px rgba(60, 74, 54, .2);
  transform: rotate(-2.2deg);
  animation: start-rise .8s cubic-bezier(.2, .9, .25, 1) both;
}

.start-logo span { display: block; }
.start-logo-2 { margin-top: .02em; font-size: .82em; }

.start-sprout {
  width: .42em;
  height: .52em;
  margin-right: .02em;
  vertical-align: -.04em;
  transform-origin: 50% 100%;
  animation: start-sway 5s ease-in-out infinite;
}

.start-tagline {
  margin: 16px 0 0;
  padding: 7px 15px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .72);
  color: var(--ink-soft);
  font-size: .86rem;
  font-weight: 600;
  animation: start-rise .8s .12s cubic-bezier(.2, .9, .25, 1) both;
}

/* ---- controls ---- */

.start-controls {
  position: relative;
  display: grid;
  gap: 12px;
  justify-items: center;
  animation: start-rise .8s .2s cubic-bezier(.2, .9, .25, 1) both;
}

.start-play {
  width: min(100%, 330px);
  min-height: 62px;
  border: 0;
  border-radius: 18px;
  color: #fff;
  font-family: inherit;
  font-size: 1.22rem;
  font-weight: 800;
  letter-spacing: .06em;
  cursor: pointer;
  background: linear-gradient(var(--green-bright), var(--green));
  box-shadow: 0 6px 0 var(--green-deep), 0 14px 24px rgba(65, 119, 58, .3);
  transition: transform .12s, box-shadow .12s;
}

.start-play:active {
  transform: translateY(5px);
  box-shadow: 0 1px 0 var(--green-deep), 0 6px 12px rgba(65, 119, 58, .26);
}

.start-play:focus-visible { outline: 3px solid var(--warm); outline-offset: 3px; }

.start-minor { display: flex; gap: 10px; }

.start-icon {
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  border-radius: 15px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .85);
  color: var(--ink-soft);
  font-family: inherit;
  font-size: 1.05rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 3px 0 rgba(60, 74, 54, .1);
}

.start-icon:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(60, 74, 54, .1); }
.start-icon:focus-visible { outline: 3px solid var(--green); outline-offset: 2px; }

.start-foot { margin: 2px 0 0; color: var(--ink-soft); font-size: .7rem; }

/* breathing, not hopping: the feet stay on the grass */
@keyframes start-breathe {
  0%, 100% { transform: scale(1, 1); }
  50% { transform: scale(1.012, 1.035); }
}

@keyframes start-drift {
  from { transform: translateX(-12vw); }
  to { transform: translateX(112vw); }
}

@keyframes start-sway {
  0%, 100% { transform: rotate(-5deg); }
  50% { transform: rotate(5deg); }
}

@keyframes start-rise {
  from { opacity: 0; transform: translateY(16px) rotate(-2.2deg); }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .start-cloud, .start-critter, .start-sprout,
  .start-logo, .start-tagline, .start-controls { animation: none; }
}

/* ---------- Ready?? / Go!! ---------- */

/* A soft haze rather than a curtain: the player should already see the
   board they are about to play. The overlay keeps its pointer events so
   an eager tap during the beat does not land on a cell. */

.countdown[hidden] { display: none; }

.countdown {
  position: fixed;
  z-index: 25;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(247, 249, 240, .42);
}

/* the white ring is built from shadows rather than -webkit-text-stroke,
   which would eat into the letters instead of sitting behind them */
.countdown-word {
  position: relative;
  margin: 0;
  font-size: clamp(2.7rem, 15vw, 4.8rem);
  font-weight: 900;
  letter-spacing: .03em;
  color: var(--green-bright);
  animation: countdown-boing .5s cubic-bezier(.2, .9, .25, 1) both;
  text-shadow:
    -4px -4px 0 #fff, 0 -4px 0 #fff, 4px -4px 0 #fff,
    -4px 0 0 #fff, 4px 0 0 #fff,
    -4px 4px 0 #fff, 0 4px 0 #fff, 4px 4px 0 #fff,
    0 7px 0 var(--green-deep),
    0 14px 20px rgba(60, 74, 54, .25);
}

.countdown-word--go {
  color: var(--warm);
  animation: countdown-bang .55s cubic-bezier(.2, .9, .25, 1) both;
  text-shadow:
    -4px -4px 0 #fff, 0 -4px 0 #fff, 4px -4px 0 #fff,
    -4px 0 0 #fff, 4px 0 0 #fff,
    -4px 4px 0 #fff, 0 4px 0 #fff, 4px 4px 0 #fff,
    0 7px 0 #b3612c,
    0 14px 22px rgba(60, 74, 54, .28);
}

/* the "kira" on Go: one ring thrown outwards from behind the word */
.countdown-word--go::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 46px;
  height: 46px;
  margin: -23px 0 0 -23px;
  border: 7px solid rgba(224, 138, 74, .55);
  border-radius: 50%;
  animation: countdown-ring .6s ease-out both;
}

/* Game Over drops in, lands, then wilts like a thirsty sprout, in time
   with the sagging horn */
.countdown-word--over {
  color: #8a9aa6;
  white-space: nowrap;
  transform-origin: 50% 100%;
  animation: countdown-wilt 2.4s ease-out both;
  text-shadow:
    -4px -4px 0 #fff, 0 -4px 0 #fff, 4px -4px 0 #fff,
    -4px 0 0 #fff, 4px 0 0 #fff,
    -4px 4px 0 #fff, 0 4px 0 #fff, 4px 4px 0 #fff,
    0 7px 0 #56656f,
    0 14px 22px rgba(40, 50, 60, .3);
}

@keyframes countdown-wilt {
  0% { opacity: 0; transform: translateY(-60px) scale(1.1); }
  14% { opacity: 1; transform: translateY(0) scale(1.06, .9); }
  22% { transform: translateY(0) scale(1); }
  /* one sag per "wah" */
  34% { transform: translateY(3px) rotate(-2deg) scale(1, .97); }
  46% { transform: translateY(6px) rotate(2deg) scale(1, .94); }
  58% { transform: translateY(9px) rotate(-3deg) scale(1, .91); }
  /* and the long droop */
  86% { transform: translateY(18px) rotate(5deg) scale(1.04, .82); opacity: 1; }
  100% { transform: translateY(20px) rotate(6deg) scale(1.04, .8); opacity: .9; }
}

@keyframes countdown-boing {
  0% { opacity: 0; transform: scale(.4) rotate(-9deg); }
  45% { opacity: 1; transform: scale(1.18) rotate(4deg); }
  66% { transform: scale(.93) rotate(-3deg); }
  84% { transform: scale(1.05) rotate(1.5deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}

@keyframes countdown-bang {
  0% { opacity: 0; transform: scale(.5) rotate(4deg); }
  38% { opacity: 1; transform: scale(1.34) rotate(-4deg); }
  60% { transform: scale(1.04) rotate(1deg); }
  100% { opacity: 1; transform: scale(1.14) rotate(0); }
}

@keyframes countdown-ring {
  from { transform: scale(.4); opacity: .85; }
  to { transform: scale(7); opacity: 0; }
}

/* the words still have to be readable when the bounce is switched off */
@media (prefers-reduced-motion: reduce) {
  .countdown-word, .countdown-word--go, .countdown-word--over { animation: none; }
  .countdown-word--go::before { display: none; }
}

.gameover {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 14px;
  border-radius: 18px;
  background: rgba(247, 249, 240, .88);
  backdrop-filter: blur(2px);
}

.gameover-card {
  width: 100%;
  max-width: 300px;
  text-align: center;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px 18px;
  box-shadow: var(--shadow);
}

.gameover-card h2 { margin: 0 0 6px; font-size: 1.15rem; }

.go-score {
  margin: 0 0 10px;
  color: var(--ink-soft);
  font-size: .85rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.go-level {
  margin: 0 0 12px;
  font-size: .95rem;
  font-weight: 600;
  color: var(--green);
}

.go-score strong {
  display: block;
  font-size: 2rem;
  color: var(--ink);
  letter-spacing: normal;
  font-variant-numeric: tabular-nums;
}

.go-note {
  margin: 0 0 16px;
  font-size: .86rem;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* ---------- Buttons ---------- */

.controls {
  display: flex;
  gap: 10px;
  margin: 14px 0 20px;
}

.btn {
  flex: 1;
  padding: 11px 14px;
  font: inherit;
  font-weight: 600;
  font-size: .92rem;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}

.btn:hover { background: #f2f7e9; }
.btn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

.btn--primary {
  width: 100%;
  color: #fff;
  background: var(--green);
  border-color: var(--green);
}
.btn--primary:hover { background: #4f8e42; }

.btn--armed {
  color: var(--warm);
  border-color: var(--warm);
  background: #fdf4ec;
}

/* ---------- Food chain reference ---------- */

.chain {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 10px 14px;
  box-shadow: var(--shadow);
}

.chain-head {
  margin: 0 0 10px;
  text-align: center;
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 600;
}

.chain-row {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  /* five rungs is one more than the row was built for, so let it wrap
     rather than squeeze the tiles on a narrow phone */
  flex-wrap: wrap;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.chain-step {
  flex: 0 1 auto;
  min-width: 0;
  text-align: center;
}

.tile--mini {
  width: 38px;
  height: 38px;
  margin: 0 auto 4px;
}

.chain-name {
  display: block;
  font-size: .72rem;
  font-weight: 600;
}

.chain-eats {
  display: block;
  font-size: .62rem;
  color: var(--ink-faint);
  line-height: 1.25;
}

.chain-note {
  margin: 10px 0 0;
  text-align: center;
  font-size: .66rem;
  line-height: 1.45;
  color: var(--ink-faint);
}

.chain-arrow {
  align-self: center;
  padding: 0 2px 14px;
  font-size: .7rem;
  font-weight: 700;
  color: var(--ink-faint);
}

/* ---------- How to play ---------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: end center;
  padding: 0;
  background: rgba(45, 56, 40, .42);
}

.modal-card {
  position: relative;
  width: 100%;
  max-width: 480px;
  max-height: 92vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--card);
  border-radius: 20px 20px 0 0;
  padding: 22px 18px 24px;
}

.modal-card h2 { margin: 0 0 4px; font-size: 1.2rem; }

.modal-close {
  position: absolute;
  top: 10px;
  right: 12px;
  width: 34px;
  height: 34px;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--ink-soft);
  background: none;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}
.modal-close:hover { background: #f1f5e9; }

.guide {
  margin: 14px 0 18px;
  padding: 0;
  list-style: none;
}

.guide-step {
  padding: 14px 0;
  border-top: 1px solid #eef2e6;
}
.guide-step:first-child { border-top: 0; padding-top: 0; }

.guide-step h3 {
  margin: 0 0 8px;
  font-size: .95rem;
  color: var(--green);
}

.guide-step p {
  margin: 8px 0 0;
  font-size: .87rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

.guide-art {
  display: block;
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
  height: auto;
}

.ga-grid rect {
  fill: #eef4e4;
  stroke: var(--line);
  stroke-width: 1.2;
}
.ga-grid rect.ga-empty { fill: #f7faf1; stroke-dasharray: 3 3; }
.ga-grid rect.ga-dead { fill: #eae5d6; stroke: #d6cfba; }

.ga-arrow { stroke: #c3d6ac; stroke-width: 2.4; stroke-linecap: round; fill: none; }
.ga-head { fill: #c3d6ac; }
.ga-tap { fill: rgba(90, 158, 75, .3); }
.ga-ring { fill: none; stroke: var(--green); stroke-width: 1.6; stroke-dasharray: 4 4; }
.ga-spark { fill: var(--green-bright); }

.ga-pts {
  fill: var(--warm);
  font-family: var(--font);
  font-size: 12px;
  font-weight: 700;
  text-anchor: middle;
}

.ga-cap {
  fill: var(--ink-faint);
  font-family: var(--font);
  font-size: 10px;
  text-anchor: middle;
}

.ga-meter-bg { fill: rgba(90, 110, 80, .18); }
.ga-meter-mid { fill: #e8c057; }
.ga-meter-low { fill: #dd6a52; }

.ga-season rect { stroke-width: 1.2; }

.ga-seasonname text {
  font-family: var(--font);
  font-size: 9px;
  font-weight: 700;
  text-anchor: middle;
}

.ga-seasonmult text {
  font-family: var(--font);
  font-size: 11px;
  font-weight: 700;
  text-anchor: middle;
}

.ga-stones circle { fill: #b9b7ad; }

.modal-done { margin-top: 4px; }

/* ---------- Footer ---------- */

.app-footer {
  margin-top: 18px;
  text-align: center;
  font-size: .76rem;
  color: var(--ink-faint);
}
.app-footer p { margin: 0; }

/* ---------- Narrow screens ---------- */

@media (max-width: 380px) {
  .board { gap: 5px; padding: 7px; }
  .tile { width: 40px; height: 40px; }
  .tile--next { width: 36px; height: 36px; }
  /* three hand slots plus the next tile is the widest row on the page.
     It used to be the hand that gave way, down to 32px — but a phone is
     where this game is actually played, so the sentence beside it moves
     to its own line instead and the tiles stay readable. The word stays
     — it is the half of the meter that can actually be read aloud —
     and the meter drops under it. */
  .tile.hand-tile { width: 46px; height: 46px; }
  .hand-tiles { gap: 5px; }
  .goal { grid-column: 1 / -1; padding-left: 0; }
  .refill { display: block; }
  .refill-track { width: 100%; }
  .refill-word { white-space: normal; font-size: .56rem; }
  .tile--mini { width: 32px; height: 32px; }
  .chain-eats { display: none; }
  .chain-arrow { padding-bottom: 8px; }
  /* the name and the multiplier are the part that matters; the sentence
     wraps to two lines down here and is spelled out in the guide anyway */
  .season-note { display: none; }
  .season { grid-template-columns: auto 1fr; }
}

/* ---------- Wide screens ---------- */

@media (min-width: 700px) {
  .modal { place-items: center; padding: 24px; }
  .modal-card { border-radius: 20px; max-height: 86vh; }
}

/* ---------- The effects layer ---------- */
/* Decoration only. It sits over the board, never takes a tap, and holds
   nothing the game reads back. The pops leave from the square that
   earned them, so the number and the move are one event. */

.fx {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  border-radius: 18px;
  z-index: 3;
}

.pop {
  position: absolute;
  transform: translate(-50%, -50%);
  font-size: .95rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--green);
  /* A pop spends its first third of a second directly over the animal
     that earned it, so the halo has to be thick enough to read against
     fur rather than merely against the ground. */
  text-shadow:
    0 0 3px #fff, 0 0 3px #fff, 0 0 3px #fff,
    0 0 10px rgba(255, 255, 255, .95), 0 1px 0 rgba(255, 255, 255, .9);
  white-space: nowrap;
  animation: pop-rise 1.05s cubic-bezier(.2, .8, .3, 1) forwards;
}

/* Bigger prey, bigger number, louder pop — the sizes are the score
   ladder, so a wolf's meal never reads like a sprout's. */
.pop--rabbit { font-size: 1.05rem; }
.pop--fox { font-size: 1.2rem; color: var(--warm); }
.pop--wolf { font-size: 1.35rem; color: #8b5cf6; }

@keyframes pop-rise {
  0% { opacity: 0; transform: translate(-50%, -30%) scale(.7); }
  18% { opacity: 1; transform: translate(-50%, -55%) scale(1.15); }
  32% { transform: translate(-50%, -58%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -155%) scale(1); }
}

/* A chain used to land all at once: the result appeared, one number flew
   up, and a badge said how many rungs had happened somewhere. These two
   shapes are the chain told one rung at a time, timed to the pops the
   synth was already playing. Durations come from script.js so the
   milliseconds live in one place. */

/* The tile that is gone, going. It travels from its own square into the
   square that kept the result and shrinks as it is swallowed, so a merge
   has a direction instead of merely a before and an after. Partly
   transparent from the first frame: it is a memory of a tile, and a solid
   one reads as a second animal that was somehow there all along. */
.ghost {
  position: absolute;
  transform: translate(-50%, -50%);
  opacity: 0;
  animation: ghost-suck 300ms cubic-bezier(.35, 0, .65, 1) forwards;
}

@keyframes ghost-suck {
  0% { opacity: .62; transform: translate(-50%, -50%) scale(1); }
  65% { opacity: .46; }
  100% {
    opacity: 0;
    transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px))) scale(.42);
  }
}

/* The landing. Drawn at the size of the square that kept the result, so
   the elephant's ring is twice the size of the rabbit's and nothing has
   to say so. */
.ring {
  position: absolute;
  transform: translate(-50%, -50%);
  border: 3px solid var(--warm);
  border-radius: 14px;
  animation: ring-out 500ms cubic-bezier(.2, .8, .3, 1) forwards;
}

@keyframes ring-out {
  0% { opacity: .9; transform: translate(-50%, -50%) scale(.52); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.22); }
}

.fx-chain {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--warm);
  color: #fff;
  font-size: .8rem;
  font-weight: 800;
  letter-spacing: .04em;
  box-shadow: 0 4px 14px rgba(224, 138, 74, .45);
  animation: chain-in 1.15s ease forwards;
}

@keyframes chain-in {
  0% { opacity: 0; transform: translateX(-50%) scale(.6); }
  15% { opacity: 1; transform: translateX(-50%) scale(1.1); }
  28% { transform: translateX(-50%) scale(1); }
  75% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) translateY(-10px) scale(1); }
}

/* The first rabbit, the first fox, the first wolf. Once per run each —
   a fuss that happens every time stops being a fuss. */
.first {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(82%, 260px);
  display: grid;
  justify-items: center;
  gap: 4px;
  padding: 16px 16px 14px;
  text-align: center;
  background: rgba(255, 255, 255, .96);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 10px 30px rgba(60, 74, 54, .22);
  animation: first-in 1.85s cubic-bezier(.2, .8, .3, 1) forwards;
}

.first-art {
  width: 54px;
  height: 54px;
  animation: first-art-in 1.85s cubic-bezier(.2, .8, .3, 1) forwards;
}

.first strong { font-size: 1.05rem; }
.first span { font-size: .8rem; color: var(--ink-soft); line-height: 1.35; }

.first--fox { border-color: var(--warm); }
.first--wolf { border-color: #8b5cf6; }

@keyframes first-in {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(.75); }
  10% { opacity: 1; transform: translate(-50%, -50%) scale(1.04); }
  18% { transform: translate(-50%, -50%) scale(1); }
  82% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -62%) scale(.96); }
}

@keyframes first-art-in {
  0% { transform: scale(.4) rotate(-12deg); }
  22% { transform: scale(1.12) rotate(4deg); }
  34% { transform: scale(1) rotate(0); }
}

/* Motion is the whole point of this layer, so when it is unwelcome the
   effects still SAY what happened — they just appear and go. */
@media (prefers-reduced-motion: reduce) {
  .pop, .fx-chain, .first, .first-art {
    animation: none;
    opacity: 1;
  }
  .pop { transform: translate(-50%, -140%); }
  /* The ghost and the ring are nothing but motion, so replayChain does not
     make them at all here. The rungs still arrive one at a time and still
     say what each one paid. */
}

/* A touch-friendly preview: no hover or extra tap is needed. */
.cell--merge-ready { box-shadow: inset 0 0 0 2px #679844; }
.merge-preview { color: #345824; font-size: clamp(9px, 2.5vw, 13px); font-weight: 700; pointer-events: none; }

.first--bear { border-color: #a57550; background: #fff6df; box-shadow: 0 8px 36px #80563d38; }
/* One knob for every idle on the board. Each animal keeps its own
   shape and pace below; this only sets how far they all move. The
   numbers in each @keyframes are the shape at 1; 2.5 is what it takes
   for a 44px tile to read as alive on a phone rather than as a still. */
.cell { --idle: 2.5; }

/* Every animal breathes. This runs on the `scale` property, not
   `transform`, so it stacks on top of each animal's own idle (the
   rabbit's bob, the buffalo's graze) instead of replacing it.
   The shape is a real breath, not a sine wave: the chest fills over
   two fifths of the cycle, holds full for a beat, empties, then rests
   empty -- that rest is what makes it read as an animal and not a
   pulsing icon. A breath widens the ribs a little as well as lifting
   them, so x grows by half of y.
   Rate and depth follow body size: small animals breathe fast and
   shallow, big ones slow and deep. Pivot is each animal's own
   transform-origin, the feet, so the body swells upward from the
   ground. */
.cell { --breath-rate: 3s; --breath-depth: .03; }
.cell--rabbit   { --breath-rate: 1.5s; --breath-depth: .028; }
.cell--fox      { --breath-rate: 2.1s; --breath-depth: .03; }
.cell--deer     { --breath-rate: 1.3s; --breath-depth: .022; }
.cell--zebra    { --breath-rate: 3.2s; --breath-depth: .032; }
.cell--buffalo  { --breath-rate: 3.8s; --breath-depth: .034; }
.cell--wolf     { --breath-rate: .95s; --breath-depth: .03; }
.cell--bear     { --breath-rate: 3.6s; --breath-depth: .04; }
.cell--lion     { --breath-rate: 4.4s; --breath-depth: .045; }
.cell--tiger    { --breath-rate: 4.8s; --breath-depth: .03; }
.cell--elephant { --breath-rate: 5.4s; --breath-depth: .035; }
@keyframes breathe {
  0%, 100% { scale: 1 1; }
  40%, 50% { scale: calc(1 + var(--breath-depth) * .5) calc(1 + var(--breath-depth)); }
  86%      { scale: 1 1; }
}

/* The bear carries her weight from one side to the other.
   Deliberately the opposite of the rabbit: where the rabbit ticks at
   2.6s and never settles, the bear takes 4.2s and is always settled.
   The pivot is at her feet, so the lean reads as a weight shift rather
   than a wobble, and the small rise at the half-beat is the moment the
   weight is on neither side. Under a degree of rotation, because two
   things share this tile and a bigger swing would swim the cub across
   her chest. */
.cell--bear .tile-art {
  transform-origin: center bottom;
  animation: bear-sway 4.2s ease-in-out infinite, breathe var(--breath-rate) ease-in-out infinite;
}
.cell--bear:nth-child(3n+2) .tile-art { animation-delay: -1.4s; }
.cell--bear:nth-child(3n+3) .tile-art { animation-delay: -2.8s; }

@keyframes bear-sway {
  0%, 100% { transform: rotate(calc(-.9deg * var(--idle))); }
  25%, 75% { transform: translateY(calc(-.5px * var(--idle))) rotate(0deg); }
  50%      { transform: rotate(calc(.9deg * var(--idle))); }
}

/* the arrival takes the tile over for its third of a second; the sway
   comes back on the next render */
.cell--bear.cell--grew .tile-art { animation: bear-arrive .35s ease-out; }

@keyframes bear-arrive { 0% { transform: scale(.6); } 65% { transform: scale(1.12); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .cell--bear .tile-art, .cell--bear.cell--grew .tile-art { animation: none; } }

/* The rabbit never quite settles.
   Kept deliberately small and slow: motion on this board already MEANS
   something (a merge, a meal, a death), and those read as big, fast and
   once. A character idle has to stay under that ceiling or it drowns
   out the signals the player actually needs.
   The offsets stop a row of rabbits breathing in unison, which looks
   less alive than one rabbit does. Negative delays start them
   mid-cycle, so nothing waits to begin. */
.cell--rabbit .tile-art {
  transform-origin: center bottom;
  animation: rabbit-idle 2.6s ease-in-out infinite, breathe var(--breath-rate) ease-in-out infinite;
}
.cell--rabbit:nth-child(4n+2) .tile-art { animation-delay: -.6s; }
.cell--rabbit:nth-child(4n+3) .tile-art { animation-delay: -1.3s; }
.cell--rabbit:nth-child(4n+4) .tile-art { animation-delay: -2s; }

@keyframes rabbit-idle {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(calc(-1.6px * var(--idle))); }
}

@media (prefers-reduced-motion: reduce) {
  .cell--rabbit .tile-art { animation: none; }
}

/* The buffalo grazes, and grazing is the slowest thing on this board.
   The rabbit ticks at 2.6s and never settles; the bear takes 4.2s and
   is always settled. The buffalo takes 6.4s, slower than either,
   because the one thing a player should read off this tile is WEIGHT.

   The pivot is at the rump end -- the hind legs, off the left edge --
   so a positive rotation drops the head rather than rocking the body.
   That turns one degree of rotation into a head going down to the
   grass and coming back up, which is the only thing a still painting
   of a buffalo can be doing. Held long at the bottom (the 45-65%
   stretch) because the animal is eating there, not passing through.

   Kept under the bear's swing for the same reason the bear is kept
   under the rabbit's: motion on this board MEANS something, and an
   idle that competes with a merge or a death drowns out the signal. */
.cell--buffalo .tile-art {
  transform-origin: 12% bottom;
  animation: buffalo-graze 6.4s ease-in-out infinite, breathe var(--breath-rate) ease-in-out infinite;
}
.cell--buffalo:nth-child(3n+2) .tile-art { animation-delay: -2.1s; }
.cell--buffalo:nth-child(3n+3) .tile-art { animation-delay: -4.2s; }

@keyframes buffalo-graze {
  0%, 100%  { transform: rotate(0deg); }
  45%, 65%  { transform: translateY(calc(.4px * var(--idle))) rotate(calc(1.1deg * var(--idle))); }
}

/* the arrival owns the tile for a third of a second, then the graze
   picks up again on the next render -- same handover as the bear */
.cell--buffalo.cell--grew .tile-art { animation: buffalo-arrive .35s ease-out; }

@keyframes buffalo-arrive { 0% { transform: scale(.6); } 65% { transform: scale(1.1); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .cell--buffalo .tile-art, .cell--buffalo.cell--grew .tile-art { animation: none; } }

/* The deer is the frightened one, and fright is not a big movement --
   it is a small one that never stops. The painting already says so:
   it is the only animal drawn with shake lines around its legs. The
   idle is there to make those lines true.

   Two animations run at once on SEPARATE properties, `translate` and
   `rotate`, so they compose instead of the second one wiping out the
   first. That buys two rhythms out of one element: a 0.28s shiver that
   never lets up, and one flinch every 5.6s. A single @keyframes cannot
   hold two beats, and the alternative -- forty hand-written stops on
   one `transform` -- is not something anyone should have to read.

   The shiver is the smallest motion on the board: 0.15px against the
   rabbit's 1.6px breath, at a tenth of its period. Small enough that at
   44px it reads as a buzz and not as a slide, which is the difference
   between a nervous animal and a broken one.

   The flinch pivots at the hooves and goes negative, which lifts the
   nose (everything faces right): a head snapping up at a noise, then
   nearly two seconds of settling back down. The scaleY at the top is
   the spine straightening with it. It is the one moment this tile asks
   to be looked at, so it stays under a degree -- the ceiling the bear
   and the buffalo keep to, because motion on this board MEANS something
   and an idle must never compete with a merge or a death.

   `.cell--grew` animates the cell itself, not the art, so a deer that
   has just been merged into keeps shivering through its arrival. That
   is correct for this animal: the deer is the one that does not get a
   confident entrance.

   The offsets stagger the herd -- one deer flinching at a time is an
   animal reacting, five flinching together is a screensaver. Negative
   delays start them mid-cycle so nothing waits to begin. */
.cell--deer .tile-art {
  transform-origin: center bottom;
  animation: deer-shiver .28s linear infinite, deer-flinch 5.6s ease-in-out infinite, breathe var(--breath-rate) ease-in-out infinite;
}
.cell--deer:nth-child(3n+2) .tile-art { animation-delay: -.09s, -1.9s; }
.cell--deer:nth-child(3n+3) .tile-art { animation-delay: -.18s, -3.7s; }

@keyframes deer-shiver {
  0%, 100% { translate: calc(-.15px * var(--idle)) 0; }
  50%      { translate: calc(.15px * var(--idle)) 0; }
}

@keyframes deer-flinch {
  0%, 62% { rotate: 0deg; }
  65%     { rotate: calc(-.75deg * var(--idle)); }
  70%     { rotate: calc(-.6deg * var(--idle)); }
  78%     { rotate: calc(-.45deg * var(--idle)); }
  88%     { rotate: calc(-.2deg * var(--idle)); }
  100%    { rotate: 0deg; }
}

@media (prefers-reduced-motion: reduce) {
  .cell--deer .tile-art { animation: none; }
}

/* The tiger only breathes. Everything else on this board also does
   something -- bobs, grazes, shivers, sways -- and the tiger's whole
   character is that it has no reason to. A slow, steady 4.8s breath
   and nothing else: the animal that is watching you. */
.cell--tiger .tile-art {
  transform-origin: center bottom;
  animation: breathe var(--breath-rate) ease-in-out infinite;
}
.cell--tiger:nth-child(3n+2) .tile-art { animation-delay: -2.4s; }
.cell--tiger:nth-child(3n+3) .tile-art { animation-delay: -4.8s; }


@media (prefers-reduced-motion: reduce) {
  .cell--tiger .tile-art { animation: none; }
}

/* The zebra parks its weight and leaves it there.
   Four animals already move on this board and each of them owns a
   shape: the rabbit ticks, the bear rocks from side to side at 4.2s,
   the buffalo puts its head down, the deer cannot stop shaking. The
   zebra is drawn standing square on all four legs, facing us, and a
   rotation on that pose reads as the bear's rock with stripes on -- so
   there is no rotation in here at all.

   What is left is the thing a standing horse actually does: it takes
   the weight off one side, stands like that for a while, and later
   takes it off the other. So the whole movement is .3px sideways and
   .4% of height, and 4 of the 5.8 seconds are spent holding one end or
   the other. The eye catches the change of posture, never the moving.

   Pivot at the hooves, so the body leans and the feet stay planted. */
.cell--zebra .tile-art {
  transform-origin: center bottom;
  animation: zebra-settle 5.8s ease-in-out infinite, breathe var(--breath-rate) ease-in-out infinite;
}
.cell--zebra:nth-child(3n+2) .tile-art { animation-delay: -1.9s; }
.cell--zebra:nth-child(3n+3) .tile-art { animation-delay: -3.9s; }

@keyframes zebra-settle {
  0%, 34%   { transform: translateX(calc(-.3px * var(--idle))) scaleY(1); }
  50%       { transform: translateX(0) scaleY(calc(1 + .004 * var(--idle))); }
  66%, 100% { transform: translateX(calc(.3px * var(--idle))) scaleY(1); }
}

@media (prefers-reduced-motion: reduce) {
  .cell--zebra .tile-art { animation: none; }
}

/* The lion is mid-yawn in the painting, so it gets the deepest,
   slowest breath of the cats (4.4s, 4.5% of its height): a big chest
   filling and emptying, an animal that has decided you are not worth
   getting up for. */
.cell--lion .tile-art {
  transform-origin: center bottom;
  animation: breathe var(--breath-rate) ease-in-out infinite;
}
.cell--lion:nth-child(3n+2) .tile-art { animation-delay: -2.2s; }
.cell--lion:nth-child(3n+3) .tile-art { animation-delay: -4.4s; }


@media (prefers-reduced-motion: reduce) {
  .cell--lion .tile-art { animation: none; }
}

.first--elephant { border:3px solid #c6983b; background:#fff9df; }

/* Keep the choices and the whole meadow together on a phone. */
.sr-only {
  position: absolute !important; width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: -1px !important; overflow: hidden !important;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0 !important;
}
.wrap { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px 16px; padding-top: 12px; }
.wrap > * { grid-column: 1 / -1; min-width: 0; }
.topbar { grid-column: 1; align-self: center; margin: 0; text-align: left; }
.title { font-size: 1.35rem; padding-bottom: 5px; }
.title-field { height: 6px; }
.tagline { display: none; }
.scorebar { grid-column: 2; flex-wrap: nowrap; gap: 6px; margin: 0; }
.score { padding: 5px 8px; border-radius: 9px; box-shadow: none; }
.score-label { color: #65735e; font-size: 10px; letter-spacing: .04em; }
.score-value { font-size: 1.15rem; }
.scorebar .level { display: none; }
.handbar { grid-template-columns: minmax(0, 3fr) 12px minmax(0, 1fr); gap: 4px; margin: 0; padding: 6px; box-shadow: none; }
.hand-slot { min-width: 0; }
.hand-tiles { display: grid; grid-template-columns: minmax(0, 1fr) 12px minmax(0, 1fr) 12px minmax(0, 1fr); gap: 4px; align-items: center; }
.hand-piece { display: grid; justify-items: center; gap: 2px; padding: 3px 2px; border-radius: 8px; min-width: 0; }
.hand-piece.is-now { background: #e9f4de; }
.hand-step-label { font-size: 10px; line-height: 12px; font-weight: 700; color: #64745b; white-space: nowrap; }
.hand-piece.is-now .hand-step-label { color: #315f24; }
.hand-kind-name { color: #45583b; font-size: 11px; font-weight: 600; line-height: 13px; }
.hand-arrow { text-align: center; color: #748669; font-size: 15px; }
.tile.hand-tile, .tile.tile--next { width: 42px; height: 42px; margin: 0; opacity: 1; background: #f5f8ee; border: 1px solid #d3dfc3; }
.is-now .tile.hand-tile { border: 2px solid #5a8f3f; background: #fff; box-shadow: 0 1px 4px #425b2520; }
.pause-note { font-style: normal; font-weight: 700; text-align: center; padding: 2px; }
.growth-summary { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 5px 12px; border: 1px solid var(--line); border-radius: 12px; background: #fff; }
.growth-pair { display: flex; align-items: center; gap: 12px; }
.growth-kind { display: grid; justify-items: center; gap: 1px; }
.growth-label { display: block; font-size: 10px; line-height: 12px; color: #6a755e; }
.growth-kind strong, .growth-goal strong { font-size: 11px; line-height: 13px; color: #3d5430; }
.tile.growth-tile { width: 36px; height: 32px; background: transparent; border: 0; }
.growth-picture { display: flex; align-items: center; }
.growth-two { font-size: 11px; font-weight: 700; color: #577544; }
.growth-arrow { color: #5c8345; font-size: 20px; }
.growth-goal { display: flex; align-items: center; gap: 4px; padding-left: 10px; border-left: 1px solid #e2e8d7; }
.growth-goal .growth-tile { width: 46px; height: 45px; }
.growth-goal strong { display: block; color: #745727; }
#growthProgress { display: block; font-size: 10px; line-height: 15px; color: #697657; white-space: nowrap; }
.season { display: flex; align-items: center; gap: 7px; min-height: 29px; margin: 0; padding: 5px 9px 7px; border-radius: 8px; }
.season-name { font-size: 11px; white-space: nowrap; }
.season-note { display: none; }
.season-mult { font-size: 10px; margin-left: auto; white-space: nowrap; }
.season-next { font-size: 10px; margin: 0; white-space: nowrap; }
.season-track { height: 3px; }
.move-hint { color: #586b48; font-size: 11px; line-height: 16px; margin: 0; min-height: 16px; text-align: center; }
.board-frame { width: 100%; justify-self: center; }
.board { gap: 5px; padding: 7px; }
/* A finger on the board never scrolls the page. With pan-y, a tap that
   drifted a few pixels scrolled the page (it is a little taller than the
   screen) and on a phone it bounced back, which read as the screen
   shaking on every planting. A drifting tap is still cancelled by the
   10px check in script.js. */
.board-frame { touch-action: none; }
.cell { touch-action: none; -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
.cell:not(:disabled):active { transform: none; }
.cell--merge-ready { background: #f8fbf0; border: 1px dashed #7c9e5d; box-shadow: none; }
.merge-preview { display: flex; position: absolute; inset: 4px 1px; flex-direction: column; align-items: center; justify-content: center; gap: 1px; pointer-events: none; }
.tile.merge-preview-art { width: 58%; height: 58%; border: 0; background: transparent; opacity: .78; }
.cell .merge-preview-art .tile-art { position: static; width: 100%; height: 100%; }
.merge-preview-label { font-size: clamp(8px, 2.3vw, 10px); line-height: 12px; font-weight: 700; color: #4a6c30; white-space: nowrap; }
.merge-preview-count { position: absolute; right: 2px; top: 0; padding: 1px 3px; border-radius: 8px; background: #e4efd8; color: #375527; font-size: 9px; line-height: 12px; font-weight: 700; }
.cell--preview-origin { outline: 3px solid #54923a; outline-offset: -3px; }
.cell--preview-step { box-shadow: inset 0 0 0 2px #ce9940; }
.cell--preview-destination { outline: 3px solid #cc8325; outline-offset: -3px; background: #fff1cd; }
.preview-layer { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.merge-path { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; color: #b46c16; }
.merge-path-line { fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; filter: drop-shadow(0 1px 1px #fff); }
.merge-path-step { fill: #fff9eb; stroke: #b46c16; stroke-width: 2; }
.merge-path text { fill: #fff; font-family: var(--font); font-size: 12px; font-weight: 800; stroke: none; }
.growth-summary.is-complete .growth-two, .growth-summary.is-complete .growth-arrow { display: none; }
.growth-summary.is-complete #growthNextName { color: #59813c; }
.growth-summary [hidden] { display: none; }
.controls { gap: 6px; margin: 0; }
.controls .btn { min-height: 44px; padding: 8px 4px; font-size: 12px; }
.chain { margin-top: 6px; padding: 10px; }
.chain-heading { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.chain-heading .chain-head { font-size: 10px; color: #5b7150; margin: 0; letter-spacing: .03em; text-align: left; }
.chain-heading > span { font-size: 10px; color: #70845f; }
.chain-row { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 9px 2px; }
.chain-step { position: relative; padding: 3px 0; border: 1px solid transparent; border-radius: 8px; }
.chain-step:not(:nth-child(6n))::after { content: '›'; position: absolute; right: -5px; top: 17px; font-size: 14px; color: #90a080; }
.chain-step .tile--mini { width: 36px; height: 36px; background: #f5f7ef; border-color: #e5eadb; }
.chain-step .chain-name { font-size: 9px; }
.chain-step.is-current { border-color: #7daa57; background: #f0f7e8; }
.chain-step.is-next { border-style: dashed; border-color: #b69b50; }
.chain-step.is-reached .chain-name { color: #48712e; }
.chain-note { color: #667758; font-size: 10px; margin-top: 9px; }
.meadow-notes { padding: 2px 4px; }
.meadow-notes .goal { font-size: 12px; line-height: 1.5; padding: 0; }
.meadow-notes .ticker { font-size: 11px; color: #69775c; padding-top: 6px; }
.app-footer { margin-top: 4px; }
@media (max-width: 600px) {
  body { padding: 0 max(10px, env(safe-area-inset-right)) env(safe-area-inset-bottom) max(10px, env(safe-area-inset-left)); }
  .wrap { padding-top: max(6px, env(safe-area-inset-top)); gap: 6px 10px; }
  .title { font-size: 1.12rem; }
  .score { padding: 4px 7px; }
  .score-value { font-size: 1.05rem; }
  .board-frame { width: min(100%, max(266px, calc(100svh - 344px))); }
  .growth-summary { padding: 4px 8px; gap: 4px; }
  .growth-pair { gap: 7px; }
  .growth-goal { padding-left: 5px; gap: 0; }
  .season { gap: 5px; }
  .season-next { font-size: 9px; }
  .first { width: min(82%, 240px); padding: 10px; }
  .first-art { width: 42px; height: 42px; }
  .first span { font-size: 11px; }
}
@media (max-width: 600px) and (max-height: 650px) {
  .wrap { gap: 4px 8px; }
  .handbar { padding: 3px 5px; }
  .hand-piece { padding: 2px 1px; gap: 1px; }
  .tile.hand-tile, .tile.tile--next { width: 36px; height: 36px; }
  .growth-summary { padding-block: 3px; }
  .tile.growth-tile { height: 26px; }
  .growth-goal .growth-tile { height: 36px; width: 39px; }
  .board-frame { width: min(100%, max(266px, calc(100svh - 304px))); }
  .move-hint { font-size: 10px; }
}

/* The fox sniffs: the nose dips and lifts twice, quickly, then the
   animal stands and listens. Pivot at the paws, so it is the head end
   that moves (everything faces right). Faster than the rabbit's breath,
   because a fox is busy, but with a long still stretch so it reads as
   attention rather than fidgeting. */
.cell--fox .tile-art {
  transform-origin: center bottom;
  animation: fox-sniff 3.4s ease-in-out infinite, breathe var(--breath-rate) ease-in-out infinite;
}
.cell--fox:nth-child(3n+2) .tile-art { animation-delay: -1.1s; }
.cell--fox:nth-child(3n+3) .tile-art { animation-delay: -2.3s; }
@keyframes fox-sniff {
  0%, 52%, 100% { transform: rotate(0deg); }
  60%           { transform: rotate(calc(.7deg * var(--idle))); }
  67%           { transform: rotate(calc(-.2deg * var(--idle))); }
  74%           { transform: rotate(calc(.6deg * var(--idle))); }
  84%           { transform: rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) { .cell--fox .tile-art { animation: none; } }

/* The wolf is drawn starving, so its breath is a pant: under a
   second per breath, the fastest on the board. */
.cell--wolf .tile-art {
  transform-origin: center bottom;
  animation: breathe var(--breath-rate) ease-in-out infinite;
}
.cell--wolf:nth-child(3n+2) .tile-art { animation-delay: -.3s; }
.cell--wolf:nth-child(3n+3) .tile-art { animation-delay: -.6s; }
@media (prefers-reduced-motion: reduce) { .cell--wolf .tile-art { animation: none; } }

/* The elephant moves like the biggest thing in the meadow: a slow
   rock from foot to foot over eight seconds, the slowest loop here.
   It covers four squares, so a fraction of a degree is already a lot
   of ground -- half the bear's swing reads as more weight, not less. */
.cell--elephant .tile-art {
  transform-origin: center bottom;
  animation: elephant-sway 8s ease-in-out infinite, breathe var(--breath-rate) ease-in-out infinite;
}
@keyframes elephant-sway {
  0%, 100% { transform: rotate(calc(-.4deg * var(--idle))); }
  50%      { transform: translateY(calc(-.3px * var(--idle))) rotate(calc(.4deg * var(--idle))); }
}
@media (prefers-reduced-motion: reduce) { .cell--elephant .tile-art { animation: none; } }

/* ---------- The elephant celebration (rules 17) ----------
   Shown every time an elephant is born. Full screen, above the board,
   while the meadow's clock waits. Motion stops under reduced motion. */
.celebrate {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; padding: 16px;
  background: radial-gradient(circle at 50% 42%, #fff6cfee 0%, #f3d77fe6 34%, #3c4a36f2 100%);
  overflow: hidden;
  animation: celebrate-in .35s ease-out both;
}
.celebrate-rays {
  position: absolute; left: 50%; top: 42%; width: 220vmax; height: 220vmax;
  margin: -110vmax 0 0 -110vmax; pointer-events: none;
  background: repeating-conic-gradient(from 0deg, #fff3b833 0deg 9deg, transparent 9deg 22.5deg);
  animation: celebrate-spin 24s linear infinite;
}
.celebrate-confetti { position: absolute; inset: 0; pointer-events: none; }
.confetti {
  position: absolute; top: -24px; width: 10px; height: 14px; border-radius: 60% 0 60% 0;
  opacity: 0; animation-name: confetti-fall; animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.confetti--leaf { width: 9px; height: 16px; border-radius: 0 80% 0 80%; }
.confetti--dot { width: 8px; height: 8px; border-radius: 50%; }
.confetti--c0 { background: #f6c945; }
.confetti--c1 { background: #7ec05c; }
.confetti--c2 { background: #f29bb0; }
.confetti--c3 { background: #e08a4a; }
.confetti--c4 { background: #ffffff; }
.celebrate-card {
  position: relative; width: min(100%, 340px);
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 18px 18px 20px; border-radius: 22px; text-align: center;
  background: #fffbea; border: 3px solid #c6983b; color: var(--ink);
  box-shadow: 0 0 0 6px #fff3c466, 0 18px 60px #3c2a0a66;
  animation: celebrate-pop .6s cubic-bezier(.2, 1.6, .4, 1) .1s both;
}
.celebrate-kicker {
  margin: 0; font-size: .78rem; font-weight: 800; letter-spacing: .22em;
  text-transform: uppercase; color: #a87414;
}
.celebrate-art {
  width: 150px; height: 150px; display: block;
  animation: celebrate-stomp 1.1s ease-in-out .5s infinite alternate;
  filter: drop-shadow(0 8px 10px #6b4a1240);
}
.celebrate h2 {
  margin: 0; font-size: clamp(2rem, 11vw, 2.8rem); line-height: 1; letter-spacing: .04em;
  color: #b9781a; text-shadow: 0 2px 0 #fff, 0 4px 0 #e9c46a;
}
.celebrate-sub { margin: 0; font-size: .9rem; color: var(--ink-soft); }
.celebrate-score {
  margin: 6px 0 0; display: flex; align-items: baseline; gap: 8px;
  font-variant-numeric: tabular-nums;
}
.celebrate-score span { font-size: .78rem; font-weight: 700; color: #a87414; text-transform: uppercase; letter-spacing: .12em; }
.celebrate-score strong { font-size: 2rem; color: var(--green-deep); }
.celebrate-score.is-done strong { animation: celebrate-flash .5s ease-out; }
.celebrate-count { margin: 0; font-size: .8rem; color: var(--ink-soft); }
.celebrate-btn { margin-top: 8px; min-height: 44px; min-width: 160px; }
body.is-celebrating { overflow: hidden; }

.gameover--elephant .gameover-card { border: 3px solid #c6983b; background: #fffbea; }
.gameover--elephant #goNote { color: #a87414; font-weight: 700; }

@keyframes celebrate-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes celebrate-spin { to { transform: rotate(360deg); } }
@keyframes celebrate-pop { from { opacity: 0; transform: scale(.4) translateY(30px); } to { opacity: 1; transform: none; } }
@keyframes celebrate-stomp { from { transform: translateY(0) rotate(-1.5deg); } to { transform: translateY(-6px) rotate(1.5deg); } }
@keyframes celebrate-flash { 0% { transform: scale(1.25); } 100% { transform: scale(1); } }
@keyframes confetti-fall {
  0% { opacity: 0; transform: translate(0, 0) rotate(0); }
  8% { opacity: 1; }
  100% { opacity: .9; transform: translate(var(--drift), 108vh) rotate(var(--spin)); }
}
.celebrate--still, .celebrate--still .celebrate-card { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .celebrate, .celebrate-rays, .celebrate-card, .celebrate-art, .celebrate-score.is-done strong { animation: none; }
}

/* Character accents are painted inside the canvas, on top of these
   quiet breathing idles. Keep their signals below merge/meal effects. */
.cell { --idle: 1.3; }
.cell--wolf { --breath-rate: 2.7s; --breath-depth: .025; }
.cell--wolf.cell--fading { --breath-rate: 1.1s; --breath-depth: .035; }
.cell--deer { --breath-rate: 2s; }
.cell--fading { --idle: .65; }
.board--life-paused .cell > .tile-art { animation-play-state: paused; }

/* index.html?watch — a bot replays a recorded run (watch.js). */
.is-watching #board { pointer-events: none; }
.watch-badge {
  position: fixed; right: 12px; bottom: 12px; z-index: 60;
  padding: 8px 14px; border: 0; border-radius: 999px;
  background: #2b2140; color: #fff; font: 700 14px/1 system-ui, sans-serif;
  letter-spacing: .04em; box-shadow: 0 4px 14px rgba(0, 0, 0, .3); cursor: pointer;
}

/* ============================================================
   The Ledger — achievements (concepts/achievements-v1, design B).
   An old naturalist's book on its own paper, so it reads the same in
   every skin. Seals are wax; only the elephant's plate is gilded, and
   only the elephant has a diamond.
   ============================================================ */

.start-ledger { position: relative; }
.start-ledger svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linejoin: round; }
.ledger-dot {
  position: absolute; top: -3px; right: -3px; width: 12px; height: 12px; border-radius: 50%;
  background: #e0573c; box-shadow: 0 0 0 2px #10150e;
}
.ledger-dot[hidden] { display: none; }

.ledger {
  position: fixed; inset: 0; z-index: 45; display: grid; place-items: end center;
  background: rgba(8, 10, 6, .62);
  --lg-ink: #2b2416; --lg-mute: #6d5d3a; --lg-cream: #ece4c8;
  --lg-bronze: #c8834a; --lg-silver: #d4d8de; --lg-gold: #e8c25a;
  --lg-dia: linear-gradient(135deg, #bff6ff 0%, #8fd3ff 25%, #f3b6ff 50%, #fff3b0 75%, #bff6ff 100%);
  --lg-serif: "IM Fell English", Georgia, serif;
  --lg-caps: "IM Fell English SC", "IM Fell English", Georgia, serif;
  --lg-type: "Special Elite", "Courier New", monospace;
}
.ledger[hidden] { display: none; }
.ledger-book {
  position: relative; width: 100%; max-width: 440px; max-height: 92vh; overflow-y: auto; overscroll-behavior: contain;
  padding: 16px 16px 22px; color: var(--lg-ink); font-family: var(--lg-serif);
  border-radius: 8px 18px 0 0;
  background: radial-gradient(120% 80% at 30% 20%, #efe4c4, #d9c99c 70%, #c9b57f);
  box-shadow: inset 6px 0 0 #8a7448, inset 8px 0 10px rgba(0, 0, 0, .25), 0 -8px 30px rgba(0, 0, 0, .5);
}
.ledger-head { display: flex; align-items: baseline; gap: 10px; margin: 0 0 14px 6px; }
.ledger-head h2 { margin: 0; font-family: var(--lg-caps); font-weight: 400; font-size: 1.5rem; letter-spacing: .04em; }
.ledger-count { font-family: var(--lg-type); font-size: .72rem; color: var(--lg-mute); }
.ledger-close {
  margin-left: auto; align-self: center; width: 36px; height: 36px; border: 0; border-radius: 50%;
  background: rgba(60, 48, 24, .12); color: var(--lg-ink); font-size: 1.4rem; line-height: 1; cursor: pointer;
}
.ledger-close:focus-visible { outline: 3px solid #7a2a20; outline-offset: 2px; }

.lg-plate {
  position: relative; margin: 6px 4px 18px; padding: 14px 12px 12px; text-align: center; transform: rotate(-1.2deg);
  background: linear-gradient(#1d1810, #120e08); color: var(--lg-cream); border-radius: 4px;
  box-shadow: 0 0 0 3px #b8913d, 0 0 0 4px #5a4318, 0 0 0 7px var(--lg-gold), 0 6px 16px rgba(0, 0, 0, .45);
}
.lg-plate::before, .lg-plate::after {
  content: ""; position: absolute; top: -10px; width: 46px; height: 18px; background: rgba(240, 232, 200, .65); transform: rotate(-8deg);
}
.lg-plate::before { left: -8px; }
.lg-plate::after { right: -8px; transform: rotate(9deg); }
.lg-plate--diamond { box-shadow: 0 0 0 3px #b8913d, 0 0 0 4px #5a4318, 0 0 0 7px #bff6ff, 0 0 30px rgba(143, 211, 255, .6), 0 6px 16px rgba(0, 0, 0, .45); }
.lg-kicker, .lg-label { font-family: var(--lg-type); font-size: .66rem; letter-spacing: .14em; text-transform: uppercase; }
.lg-kicker { color: var(--lg-gold); }
.lg-label { color: var(--lg-mute); margin: 16px 0 4px; font-weight: 400; }
.lg-plate-name { margin: 2px 0 0; font-family: var(--lg-caps); font-weight: 400; font-size: 1.75rem; letter-spacing: .08em; }
.lg-plate-name em { display: block; font-family: var(--lg-serif); font-size: .9rem; color: #a39c7c; letter-spacing: 0; }
.lg-plate-art { width: 170px; height: 120px; object-fit: contain; margin: 4px 0; filter: sepia(.35) drop-shadow(0 0 12px rgba(232, 194, 90, .35)); }
.lg-tally { margin: 0; font-family: var(--lg-type); font-size: .8rem; color: #a39c7c; }
.lg-tally b { margin-right: 6px; font-family: var(--lg-caps); font-weight: 400; font-size: 1.6rem; color: var(--lg-gold); }
.lg-seals { display: flex; justify-content: center; gap: 12px; margin-top: 10px; }
.lg-seal { width: 54px; text-align: center; font-family: var(--lg-type); font-size: .62rem; color: #a39c7c; }
.lg-seal .lg-wax { margin: 0 auto 4px; }
.lg-dia-word { background: var(--lg-dia); -webkit-background-clip: text; background-clip: text; color: transparent; }
.lg-margin { margin: 10px 0 0; font-family: var(--lg-type); font-size: .68rem; color: #c9b57f; transform: rotate(1deg); }

.lg-wax {
  display: grid; place-items: center; flex: none; width: 46px; height: 46px; font-style: normal;
  font-family: var(--lg-caps); font-size: 1.1rem; color: rgba(0, 0, 0, .45);
  border-radius: 47% 53% 50% 50% / 52% 48% 52% 48%;
  box-shadow: inset 0 -3px 0 rgba(0, 0, 0, .25), inset 0 2px 0 rgba(255, 255, 255, .25);
}
.lg-wax--b { background: radial-gradient(circle at 40% 35%, #e6a06a, var(--lg-bronze) 60%, #7a4a24); }
.lg-wax--s { background: radial-gradient(circle at 40% 35%, #fff, var(--lg-silver) 60%, #8b9097); }
.lg-wax--g { background: radial-gradient(circle at 40% 35%, #fff2b8, var(--lg-gold) 60%, #9a7424); }
.lg-wax--d { background: var(--lg-dia); background-size: 300% 300%; border-radius: 0; clip-path: polygon(50% 0, 100% 40%, 50% 100%, 0 40%); animation: lg-shine 6s linear infinite; }
.lg-wax--off, .lg-wax--part { background: none; box-shadow: inset 0 0 0 1.5px rgba(236, 228, 200, .25); color: rgba(236, 228, 200, .35); }
.lg-wax--part { color: var(--lg-silver); font-family: var(--lg-type); font-size: .62rem; }
.lg-wax--dia { position: relative; border-radius: 0; box-shadow: none; background: #1a1522; clip-path: polygon(50% 0, 100% 40%, 50% 100%, 0 40%); color: #bff6ff; font-size: 1.2rem; }
@keyframes lg-shine { to { background-position: 300% 0; } }

.lg-entry { display: grid; grid-template-columns: 46px 1fr auto; gap: 10px; align-items: center; padding: 8px 2px; border-bottom: 1px dashed rgba(60, 48, 24, .35); }
.lg-entry-art { width: 46px; height: 38px; object-fit: contain; filter: sepia(.6) contrast(1.05); }
.lg-entry-name { font-family: var(--lg-caps); font-size: 1.05rem; }
.lg-entry-sub { font-family: var(--lg-type); font-size: .66rem; color: var(--lg-mute); }
.lg-mini { display: flex; gap: 3px; }
.lg-mini i { width: 15px; height: 15px; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(60, 48, 24, .4); }
.lg-mini .lg-mini--b { background: var(--lg-bronze); box-shadow: none; }
.lg-mini .lg-mini--s { background: var(--lg-silver); box-shadow: none; }
.lg-mini .lg-mini--g { background: var(--lg-gold); box-shadow: none; }

.lg-specimens { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-top: 8px; }
.lg-pin {
  position: relative; height: 52px; display: grid; place-items: center; border-radius: 4px;
  background: rgba(255, 255, 255, .25); box-shadow: inset 0 0 0 1px rgba(60, 48, 24, .2);
}
.lg-pin img { width: 90%; height: 40px; object-fit: contain; filter: sepia(.6); }
.lg-pin::before { content: ""; position: absolute; top: 3px; left: 50%; width: 5px; height: 5px; margin-left: -2px; border-radius: 50%; background: #7a2a20; }
.lg-pin--empty { background: none; box-shadow: inset 0 0 0 1.5px rgba(60, 48, 24, .3); color: rgba(60, 48, 24, .45); font-family: var(--lg-caps); font-size: 1.2rem; }
.lg-pin--empty::before { display: none; }
.lg-stamp {
  display: inline-block; margin-top: 12px; padding: 3px 8px; transform: rotate(-4deg); opacity: .85;
  border: 2px solid #7a2a20; color: #7a2a20; font-family: var(--lg-type); font-size: .7rem; letter-spacing: .1em; text-transform: uppercase;
}
.lg-stamp--todo { border-style: dashed; opacity: .6; }

/* ---------- seal toasts: torn slips of the ledger, top right ---------- */
.seal-toasts {
  position: fixed; top: 66px; right: 10px; z-index: 50; display: flex; flex-direction: column; align-items: flex-end; gap: 8px;
  pointer-events: none;
  --lg-bronze: #c8834a; --lg-silver: #d4d8de; --lg-gold: #e8c25a;
  --lg-dia: linear-gradient(135deg, #bff6ff 0%, #8fd3ff 25%, #f3b6ff 50%, #fff3b0 75%, #bff6ff 100%);
  --lg-caps: "IM Fell English SC", "IM Fell English", Georgia, serif;
}
.seal-toast {
  pointer-events: auto; cursor: pointer; display: flex; align-items: center; gap: 10px; padding: 10px 16px 10px 10px;
  border: 0; color: #2b2416; text-align: left; transform-origin: right top;
  background: radial-gradient(120% 80% at 30% 20%, #efe4c4, #d9c99c);
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .5));
  clip-path: polygon(0 4%, 6% 0, 14% 5%, 24% 1%, 36% 4%, 50% 0, 63% 4%, 76% 1%, 88% 5%, 100% 0, 100% 100%, 90% 96%, 78% 100%, 64% 97%, 50% 100%, 37% 96%, 24% 100%, 12% 96%, 0 100%);
  animation: seal-in .55s ease-out both, seal-out .5s ease-in 4.3s forwards;
}
.seal-toast .lg-wax { width: 36px; height: 36px; font-size: .9rem; }
.seal-toast-words { display: flex; flex-direction: column; }
.seal-toast-kind { font-family: "Special Elite", "Courier New", monospace; font-size: .62rem; letter-spacing: .12em; text-transform: uppercase; color: #7a2a20; }
.seal-toast-name { font-family: "IM Fell English", Georgia, serif; font-size: 1rem; line-height: 1.15; }
.seal-toast--elephant {
  padding-right: 18px; color: #ece4c8; background: linear-gradient(#1d1810, #120e08);
  filter: drop-shadow(0 0 3px #e8c25a) drop-shadow(0 0 14px rgba(232, 194, 90, .6));
  animation: seal-in .55s ease-out both, seal-out .5s ease-in 6.5s forwards;
}
.seal-toast--elephant .seal-toast-kind { color: #e8c25a; }
.seal-toast-art { width: 46px; height: 36px; object-fit: contain; filter: drop-shadow(0 0 6px rgba(232, 194, 90, .7)); }
.seal-flash {
  position: fixed; inset: 0; z-index: 49; pointer-events: none;
  background: radial-gradient(circle at 85% 10%, rgba(232, 194, 90, .45), transparent 60%);
  animation: seal-flash 1.6s ease-out forwards;
}
@keyframes seal-in { from { transform: translateY(-30px) rotate(-6deg); opacity: 0; } to { transform: rotate(-1.5deg); } }
@keyframes seal-out { to { transform: translateX(30%) rotate(-1.5deg); opacity: 0; } }
@keyframes seal-flash { to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .seal-toast, .seal-toast--elephant { animation: seal-out .01s linear 4.3s forwards; transform: rotate(-1.5deg); }
  .lg-wax--d, .seal-flash { animation: none; }
  .seal-flash { display: none; }
}

/* ---------- Growth strip (always on screen) ----------
   Twelve rungs in one row under the hand, so the next animal is never
   behind the menu. Sized off the row width so all twelve fit a 320px
   phone without scrolling sideways. */
.ladder-strip { display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-radius: 999px; background: var(--card, #fff); border: 1px solid var(--line, #e3e7da); }
.ladder-label { flex: none; font-size: 9px; font-weight: 700; line-height: 1.1; width: 34px; color: var(--ink-faint, #6b7a5e); }
.ladder-row { flex: 1; min-width: 0; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 0; margin: 0; padding: 0; list-style: none; }
.ladder-step { position: relative; display: flex; justify-content: center; padding: 1px 0; border-radius: 8px; border: 1px solid transparent; }
.ladder-row .chain-step.ladder-step::after { content: none; }
.ladder-step + .ladder-step::before { content: '›'; position: absolute; left: -3px; top: 50%; transform: translateY(-50%); font-size: 10px; line-height: 1; color: var(--ink-faint, #90a080); pointer-events: none; }
.ladder-step .tile--mini { width: 100%; max-width: 30px; height: auto; aspect-ratio: 1; margin: 0; border-radius: 7px; }
.ladder-step:not(.is-reached):not(.is-next) .tile--mini { opacity: .5; }
.ladder-step.is-current { background: rgba(125, 170, 87, .18); border-color: #7daa57; }
.ladder-step.is-next { border-style: dashed; border-color: #b69b50; }
@media (max-width: 360px) { .ladder-label { display: none; } .ladder-strip { padding: 3px 5px; } }
/* Account/store and the game-over choices share the meadow palette. */
.economy-modal { position:fixed; inset:0; z-index:1000; background:#15241bcc; display:flex; align-items:center; justify-content:center; padding:12px; }
.economy-modal[hidden], #reviveResume[hidden] { display:none; }
.economy-card { background:#fff8e8; color:#243c2e; border:3px solid #668666; border-radius:22px; padding:20px; width:min(100%,480px); max-height:calc(100dvh - 24px); overflow:auto; box-shadow:0 16px 60px #0006; }
.economy-head { display:flex; justify-content:space-between; align-items:center; gap:12px; }
.economy-head h2 { margin:0; font-size:22px; }
.economy-card p { font-size:14px; line-height:1.5; }
.economy-card label { display:block; margin:12px 0 6px; font-size:14px; }
.economy-card input { box-sizing:border-box; display:block; width:100%; padding:10px; min-height:44px; font:inherit; border:1px solid #668666; border-radius:8px; }
.economy-actions, .crystal-products, .revive-options { display:grid; grid-template-columns:1fr; gap:8px; margin:12px 0; }
.crystal-products { grid-template-columns:1fr 1fr; }
.economy-card .btn, .revive-options .btn { min-height:44px; white-space:normal; }
.economy-card .btn { max-width:100%; }
.economy-status { min-height:1.5em; font-size:13px; line-height:1.35; overflow-wrap:anywhere; }
.no-ads-product { padding:12px; border-radius:12px; background:#e8efd8; }
.no-ads-product h3 { margin:0; font-size:17px; }
.checkout-confirm { margin:12px 0; padding:12px; border:2px solid #668666; border-radius:12px; background:#fffdf5; }
.checkout-confirm[hidden] { display:none; }
.checkout-confirm h3 { margin:0 0 6px; font-size:17px; }
.checkout-confirm dl { margin:0; font-size:14px; line-height:1.45; }
.checkout-confirm dl > div { display:grid; grid-template-columns:76px 1fr; gap:8px; padding:5px 0; border-bottom:1px solid #d9e2cc; }
.checkout-confirm dt { font-weight:700; }
.checkout-confirm dd { margin:0; }
.legal-links { font-size:13px; }
.legal-links a { color:inherit; }
.gameover-card { max-height:95%; overflow:auto; }
.gameover-card .go-note { margin:8px 0; }
.record-list { margin-top:16px; font-size:13px; }
#scoreValue, #bestValue, #goScore, #startBest { white-space:nowrap; }
#reviveResume { position:fixed; z-index:80; bottom:max(12px,env(safe-area-inset-bottom)); left:50%; transform:translateX(-50%); width:min(280px,calc(100% - 24px)); min-height:44px; box-shadow:0 4px 20px #0008; }
@media(max-width:360px) { .pop-top .scorebar { flex-wrap:wrap; gap:2px 8px; } #scoreValue { font-size:24px; } }
@media(max-width:360px) { .economy-card { padding:14px; } .economy-head h2 { font-size:19px; } .revive-options { gap:5px; margin:6px 0; } .gameover-card .btn { min-height:38px; padding:8px; } }

/* ---------- revive: one button at a time, the daily dawn chained without No Ads ---------- */
.go-candles, .go-rule, .revive-options [hidden] { display: none !important; }
.skin-eldritch .go-candles:not([hidden]) { display: flex !important; }
.skin-eldritch .go-rule:not([hidden]) { display: flex !important; }
.revive-btn { position: relative; display: flex; align-items: center; gap: 12px; text-align: left; padding: 11px 14px; }
.revive-words { min-width: 0; }
.revive-words strong { display: block; font-weight: 700; }
.revive-words em { display: block; font-style: normal; font-size: 11px; opacity: .75; }
.revive-words em:empty { display: none; }
.revive-ico { width: 24px; height: 24px; flex: none; }
.revive-ico--sun { border-radius: 50%; background: radial-gradient(circle, #f1c66a 0 30%, transparent 31%), repeating-conic-gradient(#f1c66a 0 9deg, transparent 9deg 45deg);
  -webkit-mask: radial-gradient(circle, #000 0 30%, transparent 31% 41%, #000 42%); mask: radial-gradient(circle, #000 0 30%, transparent 31% 41%, #000 42%); }
.revive-ico--gem { background: #c9e88a; clip-path: polygon(50% 0, 92% 38%, 50% 100%, 8% 38%); }
.revive-ico--eye { height: 14px; border-radius: 50%; background: radial-gradient(circle at 50% 50%, #10150e 0 24%, #d8cc86 25% 36%, #f1ead0 37%); box-shadow: 0 0 0 1.5px #0b0e09; }
.revive-btn--locked > .revive-ico, .revive-btn--locked > .revive-words { opacity: .38; filter: grayscale(.7); }
/* two iron chains crossed over the whole button, a padlock where they meet */
.revive-chains { position: absolute; inset: 0; pointer-events: none; }
.revive-chains::before, .revive-chains::after { content: ""; position: absolute; left: -4%; width: 108%; top: 50%; height: 7px; margin-top: -3.5px;
  background: radial-gradient(4.6px 2.8px at 50% 50%, transparent 45%, #8a8676 55% 85%, transparent 95%) 0 0 / 8px 7px repeat-x;
  filter: drop-shadow(0 1px 0 #0b0e09) drop-shadow(0 -1px 0 #0b0e09); transform: rotate(9deg); }
.revive-chains::after { transform: rotate(-9deg); }
.revive-lock { position: absolute; left: 50%; top: 50%; width: 18px; height: 20px; transform: translate(-50%, -45%); }
.revive-btn--locked:not(:disabled):hover .revive-chains { animation: revive-rattle .4s ease-in-out; }
@keyframes revive-rattle { 25% { transform: translateX(-2px) rotate(-.6deg); } 75% { transform: translateX(2px) rotate(.6deg); } }
.revive-hush { margin: -3px 0 2px; font-size: 11px; text-align: center; color: var(--ink-soft); }
.gameover-card .go-again { background: none; box-shadow: none; color: var(--ink-soft); font-style: italic; min-height: 36px; }
@media (prefers-reduced-motion: reduce) { .revive-btn--locked .revive-chains { animation: none !important; } }
#shopBtn[hidden], #startShopBtn[hidden] { display: none !important; }

/* Chains build locally, then finish with one readable praise badge. */
.ring {
  border-width: calc(3px + var(--chain-power, 0) * .35px);
  box-shadow: 0 0 calc(var(--chain-power, 0) * 3px) var(--warm);
}
.fx-chain { z-index: 3; white-space: nowrap; }
.fx-chain[data-tier="1"] { background: #417c58; box-shadow: 0 4px 18px #417c5866; }
.fx-chain[data-tier="2"] { background: #7550a1; box-shadow: 0 4px 22px #9266c577; }
.fx-chain[data-tier="3"] { background: #81551c; box-shadow: 0 4px 26px #e5b85699; }
.fx-chain--praise {
  display: grid;
  justify-items: center;
  gap: 1px;
  padding: 8px 18px 7px;
  border: 1px solid #fff7;
  border-radius: 16px;
  animation: chain-praise 1s ease-out forwards;
}
.fx-chain--praise strong { font-size: clamp(17px, 5vw, 25px); line-height: 1.15; letter-spacing: .035em; }
.fx-chain--praise small { font-size: 10px; letter-spacing: .18em; }
.chain-spark {
  position: absolute;
  width: var(--spark-size);
  height: var(--spark-size);
  border-radius: 50%;
  background: #e5f9c2;
  box-shadow: 0 0 6px #b5ed8c;
  animation: chain-spark-out .7s ease-out forwards;
}
.chain-spark[data-tier="2"] { background: #e9d4ff; box-shadow: 0 0 7px #c396f5; }
.chain-spark[data-tier="3"] { background: #fff0b5; box-shadow: 0 0 8px #ffd66e; }
.chain-edge {
  position: absolute;
  inset: 2px;
  border: 2px solid #e6c577;
  border-radius: inherit;
  box-shadow: inset 0 0 22px #e6c57777;
  animation: chain-edge-out .95s ease-out forwards;
}
@keyframes chain-praise {
  0% { opacity: 0; transform: translateX(-50%) scale(.75); }
  16% { opacity: 1; transform: translateX(-50%) scale(1.08); }
  30%, 76% { opacity: 1; transform: translateX(-50%) scale(1); }
  100% { opacity: 0; transform: translateX(-50%) translateY(-6px) scale(1); }
}
@keyframes chain-spark-out {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(.4); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.2); }
}
@keyframes chain-edge-out { 0% { opacity: 0; } 18% { opacity: .9; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .fx-chain--praise { animation: none; opacity: 1; }
  .chain-spark, .chain-edge { display: none; }
}
