/* ============================================================
   Climate Strike — arcade layer on top of the school shell
   ============================================================ */

/* The site injects a bottom dock below 1020px and reserves body padding for a
   masthead it never renders here. A full-screen game owns the viewport. */
@media (max-width: 1020px) {
  body { padding-top: 0 !important; padding-bottom: 0 !important; }
  #mobileBar.mobile-bar,
  .mobile-pop,
  .mobile-pop-backdrop { display: none !important; }
}

.mj-stage.cs-stage {
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: transparent;
  display: block;
  overflow: hidden;
  position: relative;
}
.mj-stage.cs-stage > * { max-width: none; margin: 0; width: 100%; }

/* ---------------- topbar toggles ---------------- */
/* Sound is a plain note with a ruled line struck through it, not an emoji:
   a colour emoji in a monochrome brass bar reads as a foreign object. */
#btnMute { position: relative; font-size: 16px; line-height: 1; }
#btnMute.is-off { color: #8fa39b; }
#btnMute.is-off::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 21px; height: 1.7px;
  border-radius: 2px;
  background: currentColor;
  transform: translate(-50%, -50%) rotate(-42deg);
}
#btnPause { font-size: 11px; letter-spacing: -1px; }
#btnPause.is-on { color: #ffd166; border-color: rgba(255, 209, 102, .62); }

/* a paused frame keeps the field visible: the player should recognise exactly
   where they stopped, not stare at a blank panel */
.cs-overlay.is-paused { backdrop-filter: blur(2px) brightness(.72); }

.cs-world {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #08130f;
  touch-action: none;
}

/* ---------------- the region, slowly drifting ---------------- */
.cs-bg {
  position: absolute;
  left: 0;
  right: 0;
  height: 100%;
  /* only ever seen if the scene fails to parse — the generated art covers it */
  background: linear-gradient(180deg,
    var(--sky-deep, #070f0d) 0%,
    var(--sky-top, #0d1a17) 62%,
    var(--sky-top, #0d1a17) 100%);
  top: 0;
  will-change: transform;
}
.cs-bg svg { width: 100%; height: 100%; display: block; filter: brightness(.9) saturate(1.06) contrast(1.03); }
.cs-bg.b { display: none; }

/* the two painted states cross-fade on --r, which lives on .cs-world */
.cs-bg .sc-bad { opacity: 1; }
.cs-bg .sc-good { opacity: var(--r, 0); transition: opacity .5s cubic-bezier(.2,.7,.3,1); }

.cs-tint {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(115% 62% at 50% -6%, rgba(0,0,0,0), rgba(3,12,10,.16) 82%),
    radial-gradient(82% 38% at 50% 112%, rgba(3,12,10,.34), transparent 76%);
}

.cs-layer { position: absolute; inset: 0; pointer-events: none; }
#targets { z-index: 3; }
#bullets { z-index: 4; }
#fx { z-index: 6; }

/* ---------------- the craft ---------------- */
/* the hull's shadow on the ice: it lengthens and fades as the craft climbs */
.cs-shadow {
  position: absolute;
  left: 0; top: 0;
  width: 110px;
  height: 26px;
  margin: -13px 0 0 -55px;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%, rgba(2,10,8,.62), rgba(2,10,8,.24) 52%, rgba(2,10,8,0) 74%);
  filter: blur(3px);
  opacity: 0;
  z-index: 3;
  pointer-events: none;
  will-change: transform, opacity;
}
.cs-craft {
  position: absolute;
  left: 0; top: 0;
  width: 135px;
  height: 104px;
  margin: -52px 0 0 -68px;
  z-index: 5;
  will-change: transform;
  filter: drop-shadow(0 12px 22px rgba(0,0,0,.5));
}
.cs-craft .cs-art { display: none; width: 100%; height: 100%; }
.cs-craft[data-craft="ship"] .cs-art-ship { display: block; }
.cs-craft[data-craft="boat"] .cs-art-boat { display: block; }

/* ---------------- livery ---------------- */
/* The craft is repainted per region, so you can tell at a glance where you
   are flying: ice blue over the poles, dust gold over the Sahel, soot orange
   over the burn scars. Only the coloured parts are variables — the ivory
   fuselage, the glass and the near-black outline stay put, so every livery
   keeps the same readable silhouette. */
.cs-craft {
  --c-wing-a: #4fd39a;
  --c-wing-b: #17553f;
  --c-dark: #123a2c;
  --c-edge: #8fd3b8;
  --c-glow: #a9f0cd;
}
.cs-craft[data-paint="ice"]       { --c-wing-a:#7fd8f0; --c-wing-b:#1a4a63; --c-dark:#123a4a; --c-edge:#9fd8f0; --c-glow:#d8f2ff; }
.cs-craft[data-paint="melt"]      { --c-wing-a:#6fd8c0; --c-wing-b:#134a40; --c-dark:#0f3a34; --c-edge:#8fe0d0; --c-glow:#cdf6ee; }
.cs-craft[data-paint="floe"]      { --c-wing-a:#7fd0e8; --c-wing-b:#14404f; --c-dark:#0f3544; --c-edge:#8fd8f0; --c-glow:#c8f0ff; }
.cs-craft[data-paint="dust"]      { --c-wing-a:#e0c078; --c-wing-b:#5a4418; --c-dark:#4a3a1c; --c-edge:#f0d090; --c-glow:#f6e2b0; }
.cs-craft[data-paint="burn"]      { --c-wing-a:#f0a070; --c-wing-b:#5e2414; --c-dark:#4a1e14; --c-edge:#ffb890; --c-glow:#ffd0a8; }
.cs-craft[data-paint="peat"]      { --c-wing-a:#e8b070; --c-wing-b:#4f3115; --c-dark:#43240f; --c-edge:#f0c088; --c-glow:#ffd9a8; }
.cs-craft[data-paint="gyre"]      { --c-wing-a:#86c8d8; --c-wing-b:#164a5c; --c-dark:#123a4a; --c-edge:#98d8e8; --c-glow:#c8ecf6; }
.cs-craft[data-paint="oil"]       { --c-wing-a:#8090d8; --c-wing-b:#1e2a4a; --c-dark:#1a2440; --c-edge:#98a8f0; --c-glow:#c0caf6; }
.cs-craft[data-paint="delta"]     { --c-wing-a:#b8c878; --c-wing-b:#33451e; --c-dark:#26351c; --c-edge:#c8d890; --c-glow:#e2f0b8; }
.cs-craft[data-paint="coral"]     { --c-wing-a:#f090a8; --c-wing-b:#4e2632; --c-dark:#40202c; --c-edge:#ffa8bc; --c-glow:#ffd0dc; }
.cs-craft[data-paint="orbit"]     { --c-wing-a:#b8a0e8; --c-wing-b:#33254e; --c-dark:#2c2340; --c-edge:#c8b4f0; --c-glow:#e0d4ff; }
.cs-craft[data-paint="jet"]       { --c-wing-a:#90b8f0; --c-wing-b:#1e3860; --c-dark:#1c3050; --c-edge:#a8c8f6; --c-glow:#d0e2ff; }
.cs-craft[data-paint="storm"]     { --c-wing-a:#78d0c0; --c-wing-b:#14403c; --c-dark:#16323c; --c-edge:#8fe0d2; --c-glow:#c0f0e8; }
.cs-craft[data-paint="threshold"] { --c-wing-a:#ffd166; --c-wing-b:#5c3f10; --c-dark:#4a3410; --c-edge:#ffdf90; --c-glow:#fff0c0; }

/* aircraft grade — the higher the combo, the hotter the craft reads */
.cs-craft[data-tier="1"] .cs-art { filter: drop-shadow(0 0 7px rgba(127,240,255,.45)); }
.cs-craft[data-tier="2"] .cs-art { filter: drop-shadow(0 0 12px rgba(127,240,255,.7)); }
.cs-craft[data-tier="3"] .cs-art { filter: drop-shadow(0 0 18px rgba(127,240,255,.92)) saturate(1.12); }
.cs-craft[data-tier="1"] .cs-art-ship circle[fill="#ffd166"],
.cs-craft[data-tier="2"] .cs-art-ship circle[fill="#ffd166"],
.cs-craft[data-tier="3"] .cs-art-ship circle[fill="#ffd166"] { fill:#5ff0ff; }

.cs-exhaust {
  position: absolute;
  left: 50%;
  top: 78%;
  width: 16px;
  height: 34px;
  margin-left: -8px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 20%, #eafff5, #3fbf86 45%, rgba(63,191,134,0) 72%);
  filter: blur(2px);
  opacity: .85;
  animation: csExhaust .18s steps(2) infinite alternate;
}
.cs-craft[data-craft="ship"] .cs-exhaust { scale: 1 var(--thrust, 1); transform-origin: 50% 0; }
.cs-craft[data-craft="boat"] .cs-exhaust {
  width: 62px; height: 16px; top: 86%; margin-left: -31px;
  background: radial-gradient(circle at 50% 50%, rgba(207,236,226,.9), rgba(143,211,184,0) 70%);
  animation: csWake .9s ease-in-out infinite;
}
@keyframes csExhaust { from { transform: scaleY(1); opacity: .8; } to { transform: scaleY(1.35); opacity: 1; } }
@keyframes csWake { 50% { transform: scaleX(1.25); opacity: .55; } }

.cs-craft.is-hit .cs-art { animation: csHit .32s ease; }
@keyframes csHit {
  20% { transform: translateX(-5px); filter: brightness(2) saturate(.3); }
  60% { transform: translateX(4px); }
}

/* ---------------- targets ---------------- */
/* a nudge, not a seizure: the world moves about a third as far as it used to,
   and for a shorter beat. Reads as impact; stops being a reason to look away. */
.cs-world.shake { animation: csShake .2s cubic-bezier(.36,.07,.19,.97); }
@keyframes csShake {
  15%, 85% { transform: translate3d(calc(var(--shake, 1) * -1px), calc(var(--shake, 1) * .3px), 0); }
  35%, 65% { transform: translate3d(calc(var(--shake, 1) * 1.5px), 0, 0); }
  50% { transform: translate3d(calc(var(--shake, 1) * -1.5px), calc(var(--shake, 1) * -.4px), 0); }
}
.cs-target {
  position: absolute;
  left: 0; top: 0;
  width: 72px;
  height: 72px;
  margin: -36px 0 0 -36px;
  will-change: transform;
  pointer-events: none;
}

/* --- the two behaviours, read before the kill, not after -------------------
   A diver carries an amber chevron under it and flares the moment it commits;
   a splitter wears an inner dashed ring, so "this one becomes two" is visible
   while it is still falling. Both are cues on the silhouette, not on the ring:
   the ring already means weakness and must not be asked to mean two things. */
.cs-target.is-diver::after {
  content: '';
  position: absolute;
  left: 50%; bottom: -3px;
  width: 0; height: 0;
  transform: translateX(-50%);
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 9px solid #ffb457;
  filter: drop-shadow(0 0 5px rgba(255, 180, 87, .85));
  opacity: .92;
}
.cs-target.is-diver.is-homing::after {
  animation: csDiverLock .42s ease-in-out infinite;
}
@keyframes csDiverLock {
  50% { opacity: .35; bottom: 1px; }
}
/* `::after`, not `::before`: the bloom's SVG is opaque, so anything painted
   before it is hidden behind the artwork. The splitter wears a SECOND ring just
   outside the weakness ring, turning the other way — two rings, two blooms. It
   does not touch the weakness colour, which must keep meaning exactly one
   thing. */
.cs-target.is-splitter::after {
  content: '';
  position: absolute;
  inset: -5%;
  border-radius: 50%;
  border: 1.5px dashed rgba(255, 255, 255, .55);
  pointer-events: none;
  animation: csSplitSpin 22s linear infinite reverse;
}
@keyframes csSplitSpin {
  to { transform: rotate(360deg); }
}
.cs-target.is-mini svg {
  filter: drop-shadow(0 3px 7px rgba(0, 0, 0, .4)) saturate(.9);
  opacity: .96;
}
.cs-target svg {
  width: 100%; height: 100%; display: block;
  transform: scale(calc(.86 + .14 * var(--hp, 1)));
  transition: transform .12s ease, filter .12s ease;
  filter: drop-shadow(0 4px 10px rgba(0,0,0,.45));
}
.cs-target .cs-ring {
  fill: none;
  stroke-width: 2.4;
  stroke-dasharray: 5 8;
  stroke-linecap: round;
  opacity: .95;
  transform-box: fill-box;
  transform-origin: center;
  animation: csRingSpin 13s linear infinite;
}
@keyframes csRingSpin { to { transform: rotate(360deg); } }
/* A hit used to flare the old smudge; with hard shapes a brightness pop reads
   cleaner and never fights the size scale. */
.cs-target.is-hit svg { animation: csFlash .18s ease; }
/* half a beat of warning on the shooter before its round leaves */
.cs-target.is-firing svg { animation: csFiring .3s ease; }
@keyframes csFiring {
  40% { filter: brightness(2.4) drop-shadow(0 0 10px rgba(255,130,80,.95)); }
}
@keyframes csFlash {
  50% { filter: brightness(2.6) saturate(1.5) drop-shadow(0 0 12px rgba(255,255,255,.7)); }
}
/* --- the golden bloom -------------------------------------------------------
   One bloom in eighteen surfaces as gold. It must read as a gift from across
   the field, so it glows warm and wears its own pulsing halo. ::before, not
   ::after: the chevron (diver) and the second ring (splitter) already own
   ::after, and a bloom can be both a splitter and golden. */
.cs-target.is-gold svg {
  filter: drop-shadow(0 0 9px rgba(255,209,102,.95)) drop-shadow(0 0 22px rgba(255,156,74,.5)) brightness(1.1) saturate(1.12);
}
.cs-target.is-gold::before {
  content: '';
  position: absolute;
  inset: -14%;
  border-radius: 50%;
  border: 2px solid rgba(255, 209, 102, .8);
  pointer-events: none;
  animation: csGoldHalo 1.1s ease-in-out infinite;
}
@keyframes csGoldHalo {
  0%, 100% { transform: scale(.8); opacity: .35; }
  50%      { transform: scale(1.12); opacity: 1; }
}
/* `scale`, not `transform`: the game writes translate3d() every frame, and a
   transform animation would yank the dying bloom back to the origin. */
.cs-target.is-dead { animation: csPop .28s ease forwards; }
@keyframes csPop {
  to { scale: 1.45; opacity: 0; }
}

/* ---------------- bullets: the real tiles ---------------- */
/* Smaller and slower than the first pass. At 34x46 and 1080px/s four barrels
   of QUINT filled the screen with tumbling faces faster than the eye could
   read a single one, which is exactly what "dizzying" meant. */
.cs-shot {
  position: absolute;
  left: 0; top: 0;
  width: 14px;
  height: 19px;
  margin: -9.5px 0 0 -7px;
  will-change: transform;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,.4)) brightness(.9) saturate(.92);
}
.cs-shot .tl,
.cs-shot .cs-face {
  width: 100% !important;
  height: 100% !important;
  border-radius: 3px;
}
/* a short tracer behind the tile so a volley reads as speed, not as confetti */
.cs-shot::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 90%;
  width: 2px;
  height: 11px;
  margin-left: -1px;
  border-radius: 2px;
  background: linear-gradient(180deg, rgba(185,255,224,.55), rgba(143,211,184,0));
  pointer-events: none;
}
.cs-shot.big { width: 17px; height: 23px; margin: -11.5px 0 0 -8.5px; }
.cs-shot.tier3 { box-shadow: 0 0 8px rgba(143,211,184,.75); border-radius: 5px; }
.cs-shot.tier4 { box-shadow: 0 0 12px rgba(255,209,102,.85); border-radius: 5px; }
.cs-shot.tier5 { box-shadow: 0 0 17px rgba(255,140,90,.95), 0 0 5px #fff; border-radius: 5px; }

/* wing tiles: smaller and colder than the hull's, so a busy screen still reads
   "mine, mine, mine, escort, mine" instead of one uniform ribbon */
.cs-shot.wing-shot {
  width: 11px;
  height: 15px;
  margin: -7.5px 0 0 -5.5px;
  filter: drop-shadow(0 0 5px rgba(255,209,102,.55)) brightness(.94) saturate(.9);
}
.cs-shot.wing-shot::after {
  height: 9px;
  background: linear-gradient(180deg, rgba(255,209,102,.5), rgba(255,209,102,0));
}

/* ---------------- escort drones ---------------- */
.cs-wing {
  position: absolute;
  left: 0; top: 0;
  width: 38px;
  height: 30px;
  margin: -15px 0 0 -19px;
  will-change: transform;
  filter: drop-shadow(0 4px 8px rgba(0,0,0,.45)) drop-shadow(0 0 8px rgba(63,191,140,.35));
  animation: csWingIn .3s cubic-bezier(.2,1.4,.4,1);
}
.cs-wing svg { width: 100%; height: 100%; display: block; }
/* the water escort: a patrol boat on station, with a light wake behind it */
.cs-wing.is-boat {
  width: 42px;
  height: 35px;
  margin: -17px 0 0 -21px;
  filter: drop-shadow(0 3px 6px rgba(0,0,0,.45)) drop-shadow(0 0 9px rgba(120,232,197,.4));
}
.cs-wing.is-boat::after {
  content: '';
  position: absolute;
  left: 50%; top: 88%;
  width: 16px; height: 26px;
  margin-left: -8px;
  border-radius: 50%;
  background: linear-gradient(to bottom, rgba(223,248,239,.5), rgba(223,248,239,0));
  filter: blur(3px);
  animation: csWake .9s ease-in-out infinite;
}
@keyframes csWake {
  50% { opacity: .45; scale: 1.18 .88; }
}
.cs-wing.is-leaving { animation: csWingOut .26s ease forwards; }

/* the moment a drone plucks a bullet out of the air */
.cs-wing.is-cover { filter: drop-shadow(0 0 10px rgba(185,255,220,.95)); }
.cs-wing.is-cover svg { animation: csWingCover .22s ease; }
@keyframes csWingCover { 50% { filter: brightness(2.2); } }
/* The last run. The drone has stopped patrolling and is burning its own fuel
   into a dive, so it gets a hot outline and a flame off the tail — the eye
   should follow it all the way into the hull it is about to hit. */
.cs-wing.is-dashing {
  z-index: 4;
  scale: 1.1;
  filter: drop-shadow(0 0 13px rgba(255,196,110,.9)) drop-shadow(0 0 26px rgba(255,132,52,.55));
}
.cs-wing.is-dashing::before {
  content: '';
  position: absolute;
  left: 50%; top: -14%;
  width: 13px; height: 36px;
  margin-left: -6.5px;
  border-radius: 50%;
  background: linear-gradient(to top, rgba(255,226,160,.95), rgba(255,124,52,.6) 45%, rgba(255,124,52,0));
  filter: blur(2.5px);
  animation: csDiveFlame .15s steps(2, end) infinite;
}
@keyframes csDiveFlame {
  50% { opacity: .55; scale: .82 1.3; }
}
@keyframes csWingIn {
  from { scale: .2; opacity: 0; }
  to { scale: 1; opacity: 1; }
}
@keyframes csWingOut {
  to { scale: .3; opacity: 0; translate: 0 -18px; }
}

/* the badge on the water: gold diamond, unmistakable next to a white die */
.cs-missile {
  position: absolute;
  left: 0; top: 0;
  width: 24px;
  height: 45px;
  margin: -22px 0 0 -12px;
  will-change: transform;
  pointer-events: none;
  filter: drop-shadow(0 0 9px rgba(255,180,92,.6)) drop-shadow(0 3px 6px rgba(0,0,0,.5));
}
.cs-missile svg { width: 100%; height: 100%; display: block; }
/* a trail that hangs off the tail and turns with the dart */
.cs-missile::before {
  content: '';
  position: absolute;
  left: 50%; top: 78%;
  width: 11px; height: 30px;
  margin-left: -5.5px;
  border-radius: 50%;
  background: linear-gradient(to bottom, rgba(255,203,122,.55), rgba(255,120,60,0));
  filter: blur(3px);
}
.cs-ms-flame {
  transform-box: fill-box;
  transform-origin: top center;
  animation: csFlame .14s steps(2) infinite;
}
@keyframes csFlame {
  50% { transform: scaleY(.6); opacity: .72; }
}

/* the boat escort's flare: a magnesium light with a halo and a falling trail.
   Over dark water this is the brightest thing on the board, which is exactly
   what a "they fire light" escort should look like. */
.cs-flare {
  position: absolute;
  left: 0; top: 0;
  width: 26px;
  height: 42px;
  margin: -10px 0 0 -13px;
  will-change: transform;
  pointer-events: none;
  filter: drop-shadow(0 0 12px rgba(255,207,107,.85)) drop-shadow(0 0 26px rgba(255,156,74,.45));
}
.cs-flare svg { width: 100%; height: 100%; display: block; }
.cs-flare-halo {
  transform-box: fill-box;
  transform-origin: center;
  animation: csFlarePulse .5s ease-in-out infinite;
}
@keyframes csFlarePulse {
  0%, 100% { opacity: .3; transform: scale(.86); }
  50% { opacity: .62; transform: scale(1.16); }
}

.cs-escort-drop {
  position: absolute;
  left: 0; top: 0;
  width: 40px;
  height: 40px;
  margin: -20px 0 0 -20px;
  z-index: 4;
  will-change: transform;
  filter: drop-shadow(0 0 10px rgba(255,209,102,.6));
  animation: csBadgePulse 1.8s ease-in-out infinite;
}
.cs-escort-drop svg { width: 100%; height: 100%; display: block; }
@keyframes csBadgePulse {
  0%, 100% { filter: drop-shadow(0 0 8px rgba(255,209,102,.45)); }
  50% { filter: drop-shadow(0 0 16px rgba(255,209,102,.9)); }
}

/* aircraft grade badge, sits under the escort timer */
.cs-crafttier {
  position: absolute;
  left: calc(16px + env(safe-area-inset-left));
  top: 116px;
  z-index: 9;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 3px 8px; border-radius: 9px;
  background: rgba(8,30,24,.62); border: 1px solid rgba(127,240,255,.4);
  pointer-events: none;
}
.cs-crafttier b { font-size: 13px; color: #7ef0ff; font-variant-numeric: tabular-nums; letter-spacing: .5px; }
.cs-crafttier span { font-size: 9px; letter-spacing: 1.5px; color: rgba(127,240,255,.72); }

/* hull / lives badge, directly under the grade badge so both read at a glance */
.cs-lives {
  position: absolute;
  left: calc(16px + env(safe-area-inset-left));
  top: 158px;
  z-index: 9;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 3px 8px; border-radius: 9px;
  background: rgba(38,12,8,.66); border: 1px solid rgba(255,138,106,.5);
  pointer-events: none;
}
.cs-lives b { font-size: 14px; color: #ff8a6a; letter-spacing: 2px; line-height: 1; }
.cs-lives b.is-low { color: #ff5d4a; animation: csLivesWarn .7s ease-in-out infinite; }
@keyframes csLivesWarn {
  50% { opacity: .35; text-shadow: 0 0 10px rgba(255,93,74,.9); }
}
.cs-lives span { font-size: 9px; letter-spacing: 1.5px; color: rgba(255,156,130,.8); }

/* the blink that buys you time to get clear after a lost life */
.cs-craft.is-invuln { animation: csInvuln .18s steps(2, end) infinite; }
@keyframes csInvuln {
  50% { opacity: .3; filter: brightness(1.6) drop-shadow(0 0 8px rgba(159,232,255,.8)); }
}

/* escort timer, mirrored against the combo pill on the other side */
.cs-wingtag {
  position: absolute;
  left: calc(16px + env(safe-area-inset-left));
  top: 74px;
  z-index: 9;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 11px 8px;
  border-radius: 11px;
  background: linear-gradient(135deg, rgba(18,44,36,.94), rgba(8,22,18,.9));
  border: 1px solid rgba(255,209,102,.34);
  box-shadow: 0 8px 24px rgba(0,0,0,.42);
  color: #ffe9b3;
  font: 800 8.5px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .16em;
  pointer-events: none;
}
.cs-wingtag b { font-size: 13px; letter-spacing: 0; color: #ffd166; font-variant-numeric: tabular-nums; }
.cs-wingtag-track {
  position: absolute;
  left: 10px; right: 10px; bottom: 3px;
  height: 2px;
  border-radius: 2px;
  background: rgba(255,209,102,.18);
  overflow: hidden;
}
.cs-wingtag-track i {
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #ffd166, #fff3c4);
  transition: width .12s linear;
}

/* muzzle flash */
.cs-muzzle {
  position: absolute;
  width: 22px; height: 22px;
  margin: -11px 0 0 -11px;
  border-radius: 50%;
  background: radial-gradient(circle, #eafff5, rgba(143,211,184,0) 68%);
  animation: csMuzzle .18s ease-out forwards;
  pointer-events: none;
}
@keyframes csMuzzle { to { transform: scale(2.4); opacity: 0; } }

/* ---------------- particles ---------------- */
.cs-p {
  position: absolute;
  left: 0; top: 0;
  border-radius: 2px;
  will-change: transform, opacity;
  pointer-events: none;
}
.cs-p.shard { border-radius: 1px; }
.cs-p.clean {
  border-radius: 50%;
  background: radial-gradient(circle, rgba(185,255,224,.95), rgba(63,191,134,0) 70%);
}
.cs-puff {
  position: absolute;
  left: 0; top: 0;
  width: 24px; height: 24px;
  margin: -12px 0 0 -12px;
  border-radius: 50%;
  border: 2px solid rgba(185,255,224,.9);
  animation: csPuff .5s cubic-bezier(.2,.8,.3,1) forwards;
  pointer-events: none;
}
@keyframes csPuff { from { transform: scale(.3); opacity: .9; } to { transform: scale(3.6); opacity: 0; } }

.cs-pop {
  position: absolute;
  left: 0; top: 0;
  transform: translate(-50%, -50%);
  font: 800 15px/1 ui-monospace, Menlo, monospace;
  color: #eafff5;
  text-shadow: 0 2px 8px rgba(0,0,0,.7);
  animation: csPop2 .7s ease-out forwards;
  pointer-events: none;
  white-space: nowrap;
}
@keyframes csPop2 {
  from { transform: translate(-50%, -50%) scale(.7); opacity: 0; }
  25% { transform: translate(-50%, -60%) scale(1.15); opacity: 1; }
  to { transform: translate(-50%, -140%) scale(1); opacity: 0; }
}

/* ---------------- HUD ---------------- */
.cs-hud {
  position: absolute;
  left: 0; right: 0; top: 0;
  z-index: 8;
  display: flex;
  align-items: flex-start;
  gap: 18px;
  padding: 12px 16px calc(12px + env(safe-area-inset-top));
  pointer-events: none;
  color: #eef5f1;
  text-shadow: 0 2px 10px rgba(0,0,0,.6);
}
/* Blooms enter from above, so for the first second they sit right on top of the
   index bar and the numbers. A wash of shade keeps the two readable without
   moving the playfield. */
.cs-hud::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 126px;
  background: linear-gradient(180deg, rgba(3,12,10,.78), rgba(3,12,10,.32) 55%, rgba(3,12,10,0));
  pointer-events: none;
  z-index: -1;
}
.cs-index { flex: 1 1 auto; max-width: 420px; }
.cs-index-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font: 700 9.5px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .16em;
  color: rgba(238,245,241,.72);
  margin-bottom: 5px;
}
.cs-index-top b {
  font: 700 18px/1 ui-monospace, Menlo, monospace;
  letter-spacing: 0;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.cs-index-bar {
  position: relative;
  height: 11px;
  border-radius: 99px;
  background: rgba(6,20,17,.7);
  overflow: hidden;
  box-shadow: inset 0 1px 3px rgba(0,0,0,.6), 0 1px 0 rgba(255,255,255,.12);
}
.cs-index-bar::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, #2f8f6f 0%, #6cbf62 38%, #e0b83c 68%, #d97941 84%, #c0392b 100%);
  opacity: .95;
}
.cs-index-bar i {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: calc(100% - var(--pct, 0%));
  background: #0b1d18;
  transition: width .18s linear;
}
.cs-index-bar.is-critical i { animation: csPulse .6s ease-in-out infinite; }
@keyframes csPulse { 50% { opacity: .5; } }

.cs-score, .cs-cleared {
  flex: 0 0 auto;
  text-align: right;
  font: 700 9px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .14em;
  color: rgba(238,245,241,.6);
}
.cs-score b, .cs-cleared b {
  display: block;
  margin-top: 3px;
  font-size: 15px;
  letter-spacing: 0;
  color: #fff;
  font-variant-numeric: tabular-nums;
}

/* ---------------- chain banner ---------------- */
.cs-chain {
  position: absolute;
  left: 50%;
  top: 26%;
  transform: translateX(-50%);
  z-index: 9;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 99px;
  background: rgba(9,26,22,.72);
  border: 1px solid rgba(143,211,184,.5);
  box-shadow: 0 8px 26px rgba(0,0,0,.4), 0 0 22px rgba(143,211,184,.25);
  color: #eafff5;
  font: 800 11px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .18em;
  animation: csChainPop .28s cubic-bezier(.2,1.5,.4,1);
}
.cs-chain b { font-size: 19px; color: #b9ffdc; letter-spacing: 0; }
.cs-chain span { opacity: .8; }
@keyframes csChainPop { from { transform: translateX(-50%) scale(.6); opacity: 0; } }

/* ---------------- combo multiplier ----------------
   The score used to be a flat 100 + hp*20 per kill, so a clean run and a
   messy one ended on the same number. This is the meter that makes a run
   worth protecting. */
.cs-combo {
  position: absolute;
  right: calc(16px + env(safe-area-inset-right));
  top: 104px;
  z-index: 9;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 13px 7px 11px;
  border-radius: 12px;
  background: linear-gradient(135deg, rgba(18,44,36,.94), rgba(8,22,18,.9));
  border: 1px solid rgba(185,255,224,.26);
  box-shadow: 0 8px 24px rgba(0,0,0,.42);
  color: #eafff5;
  font: 800 8.5px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .18em;
  pointer-events: none;
}
.cs-combo b {
  font-size: 22px;
  letter-spacing: 0;
  color: #b9ffdc;
  font-variant-numeric: tabular-nums;
}
.cs-combo div { display: grid; gap: 4px; }
.cs-combo i {
  font-style: normal;
  font-size: 11px;
  letter-spacing: 0;
  color: rgba(238,245,241,.72);
  font-variant-numeric: tabular-nums;
}
/* multi-kill banner: two or more blooms inside a second and the field says so */
.cs-mkill {
  position: absolute;
  left: 50%;
  top: 30%;
  z-index: 9;
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  gap: 3px;
  pointer-events: none;
  text-align: center;
}
.cs-mkill b {
  font-size: 34px;
  line-height: 1;
  letter-spacing: .1em;
  color: #ffe3a0;
  text-shadow: 0 0 18px rgba(255, 176, 70, .7), 0 4px 16px rgba(0, 0, 0, .7);
  animation: csMKill .62s cubic-bezier(.14,1.5,.36,1) forwards;
}
.cs-mkill span {
  font-size: 10px;
  letter-spacing: .16em;
  color: rgba(255, 227, 160, .82);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .8);
}
/* Full opacity by 12%: a multi-kill banner is restarted by every kill in the
   cluster, so a slow fade-in would keep it invisible for the whole chain. */
@keyframes csMKill {
  0%   { opacity: .35; scale: .62; }
  12%  { opacity: 1; scale: 1.18; }
  26%  { scale: 1; }
  74%  { opacity: 1; scale: 1; }
  100% { opacity: 0; scale: 1.03; }
}

.cs-combo.is-hot {
  border-color: rgba(255,215,106,.6);
  box-shadow: 0 8px 24px rgba(0,0,0,.42), 0 0 22px rgba(255,215,106,.38);
}
.cs-combo.is-hot b { color: #ffd76a; }
.cs-combo.bump { animation: csComboBump .2s cubic-bezier(.2,1.6,.4,1); }
@keyframes csComboBump { from { transform: scale(1.14); } }

/* ---------------- boss health ---------------- */
.cs-bossbar {
  position: absolute;
  left: 50%;
  top: 76px;
  transform: translateX(-50%);
  z-index: 9;
  width: min(520px, 74%);
  pointer-events: none;
  animation: csBossIn .42s cubic-bezier(.2,.9,.3,1);
}
@keyframes csBossIn { from { opacity: 0; transform: translate(-50%, -10px); } }
.cs-boss-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 5px;
  font: 700 8.5px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .2em;
  color: rgba(238,245,241,.76);
  text-shadow: 0 2px 8px rgba(0,0,0,.85);
}
.cs-boss-head em { font-style: normal; letter-spacing: .14em; filter: brightness(2.1) saturate(1.3); }
.cs-boss-track {
  height: 9px;
  border-radius: 99px;
  background: rgba(4,12,10,.86);
  border: 1px solid rgba(255,255,255,.18);
  overflow: hidden;
  box-shadow: inset 0 1px 3px rgba(0,0,0,.7);
}
.cs-boss-track i {
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #7a2c22, #c0453a 40%, #e0a03c 76%, #ffe08a);
  transition: width .18s ease;
}

/* ---------------- level-8 boss body ---------------- */
.cs-boss {
  position: absolute;
  left: 0; top: 0;
  width: 200px;
  height: 200px;
  margin: -100px 0 0 -100px;
  will-change: transform;
  pointer-events: none;
  filter: drop-shadow(0 18px 44px rgba(0,0,0,.62));
}
.cs-boss svg { width: 100%; height: 100%; display: block; overflow: visible; }
.cs-boss .cs-boss-ring {
  stroke: var(--weak, #2e6fb0);
  transform-box: fill-box;
  transform-origin: center;
  animation: csRingSpin var(--spin, 9s) linear infinite;
  filter: drop-shadow(0 0 7px var(--weak, #2e6fb0));
  transition: stroke .3s ease;
}
.cs-boss .cs-boss-ring2 {
  stroke: rgba(255,255,255,.34);
  transform-box: fill-box;
  transform-origin: center;
  animation: csRingSpin calc(var(--spin, 9s) * 1.7) linear infinite reverse;
}
.cs-boss .cs-boss-core {
  transform-box: fill-box;
  transform-origin: center;
  animation: csBossCore 2.6s ease-in-out infinite;
}
@keyframes csBossCore {
  0%, 100% { opacity: .45; scale: .9; }
  50%      { opacity: .95; scale: 1.18; }
}
.cs-boss .cs-boss-spikes {
  transform-box: fill-box;
  transform-origin: center;
  animation: csRingSpin 34s linear infinite reverse;
}
.cs-boss .cs-boss-eye {
  fill: var(--weak, #ffe08a);
  animation: csBossEye 1.5s ease-in-out infinite;
  filter: drop-shadow(0 0 8px var(--weak, #ffe08a));
  transition: fill .3s ease;
}
@keyframes csBossEye { 50% { opacity: .38; } }
.cs-boss.is-hit svg { animation: csBossHit .13s ease; }
@keyframes csBossHit { 50% { filter: brightness(2.4) saturate(1.7); } }
.cs-boss.is-dead { animation: csBossDie 1.5s ease forwards; }
@keyframes csBossDie { to { opacity: 0; scale: 1.45; } }

/* the hull has to look like it is *running*: exhaust climbing off the funnels
   and four propellers turning, or the tanker reads as a static sticker */
.cs-boss .cs-smoke circle {
  fill: rgba(14,17,15,.9);
  transform-box: fill-box;
  transform-origin: center;
  animation: csSmoke 2.4s ease-out infinite;
}
@keyframes csSmoke {
  0%   { opacity: 0; transform: translate(0, 10px) scale(.42); }
  14%  { opacity: .92; }
  100% { opacity: 0; transform: translate(10px, -26px) scale(2); }
}
.cs-boss .cs-prop {
  transform-box: fill-box;
  transform-origin: center;
  animation: csProp .42s linear infinite;
}
@keyframes csProp { to { transform: rotate(360deg); } }

/* ---------------- incoming pollution ---------------- */
.cs-threat {
  position: absolute;
  left: 0; top: 0;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  background: radial-gradient(circle at 36% 30%, #ffe6a3, #c98b3a 42%, #6b3d16 78%, #2a1608);
  box-shadow: 0 0 16px rgba(255,170,90,.6), 0 0 4px rgba(255,230,160,.9);
  will-change: transform;
  pointer-events: none;
}
.cs-threat::after {
  content: '';
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  border: 1px solid rgba(255,190,120,.34);
}
.cs-threat.boss {
  background: radial-gradient(circle at 36% 30%, #fff3c4, #d05a3a 40%, #6b1d16 76%, #2a0a08);
  box-shadow: 0 0 22px rgba(255,110,80,.65), 0 0 6px rgba(255,210,170,.95);
}
.cs-threat.oil {
  background: radial-gradient(circle at 36% 30%, #9fd8ff, #33475a 46%, #101a20);
  box-shadow: 0 0 16px rgba(110,170,220,.55);
}
.cs-threat.methane {
  background: radial-gradient(circle at 36% 30%, #fff6d2, #c9a44e 46%, #5d4720);
}

/* A round fired by something on screen arrives as that thing in miniature —
   the silhouette is the tell, the red rim is the "this one is hostile" flag. */
.cs-threat.is-clone {
  width: 30px;
  height: 30px;
  margin: -15px 0 0 -15px;
  background: radial-gradient(circle at 50% 46%,
    rgba(255,140,96,.34), rgba(255,72,44,.14) 60%, rgba(120,20,10,0) 78%);
  box-shadow: 0 0 14px rgba(255,110,70,.55), 0 0 3px rgba(255,214,178,.9);
}
.cs-threat.is-clone::after { display: none; }
.cs-threat.is-clone svg {
  width: 100%; height: 100%; display: block;
  filter: drop-shadow(0 0 4px rgba(255,120,80,.8));
}
.cs-threat.is-clone::before {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 1.5px solid rgba(255,124,88,.55);
  animation: csThreatRing .9s ease-out infinite;
}
@keyframes csThreatRing {
  from { transform: scale(.8); opacity: .85; }
  to { transform: scale(1.3); opacity: 0; }
}

/* ---------------- suit selector ---------------- */
.cs-suits {
  position: absolute;
  left: 50%;
  bottom: calc(10px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  gap: 8px;
  padding: 7px 9px;
  border-radius: 16px;
  background: rgba(6,20,17,.62);
  border: 1px solid rgba(255,255,255,.13);
  backdrop-filter: blur(10px);
  box-shadow: 0 10px 30px rgba(0,0,0,.42);
}
.cs-suit {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-rows: auto auto;
  justify-content: center;
  align-items: center;
  column-gap: 4px;
  row-gap: 3px;
  width: 56px;
  padding: 5px 2px 4px;
  border-radius: 11px;
  border: 1px solid transparent;
  background: transparent;
  color: rgba(238,245,241,.62);
  font: 700 8px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .12em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .15s, color .15s, border-color .15s, transform .12s, opacity .15s;
}
.cs-tag { grid-column: 1; grid-row: 1; }
.cs-n { grid-column: 2; grid-row: 1; }
.cs-suit > span { grid-column: 1 / -1; grid-row: 2; }
.cs-suit:hover { color: #fff; border-color: rgba(255,255,255,.2); }
.cs-suit:active { transform: scale(.95); }
.cs-suit.on {
  background: linear-gradient(180deg, rgba(63,191,134,.35), rgba(31,107,82,.45));
  border-color: rgba(143,211,184,.7);
  color: #fff;
  box-shadow: 0 0 16px rgba(63,191,134,.35);
}
/* The suit selector shows a plain colour swatch and a live count. No tile faces
   up here on purpose: mahjong tiles belong in the game world — flying out of the
   gun, tumbling back down to be picked up — not in a HUD icon. */
.cs-tag {
  --sc: #2e6fb0;
  position: relative;
  display: block;
  width: 21px;
  height: 25px;
  border-radius: 4px;
  border: 1px solid var(--sc);
  background-color: rgba(9, 24, 20, .85);
  background-repeat: no-repeat;
  box-shadow: inset 0 0 9px rgba(255, 255, 255, .07);
}
.cs-tag[data-k="bam"] { --sc: #2f8f6f; }
.cs-tag[data-k="crak"] { --sc: #c0453a; }
.cs-tag[data-k="wind"] { --sc: #c8a23c; }

/* dots: one pip over two */
.cs-tag[data-k="dot"] {
  background-image:
    radial-gradient(circle, var(--sc) 2.6px, transparent 3.1px),
    radial-gradient(circle, var(--sc) 2.6px, transparent 3.1px),
    radial-gradient(circle, var(--sc) 2.6px, transparent 3.1px);
  background-size: 7px 7px, 7px 7px, 7px 7px;
  background-position: center 5px, 5px 16px, 13px 16px;
}
/* bams: three bamboo staves */
.cs-tag[data-k="bam"] {
  background-image: repeating-linear-gradient(90deg,
    transparent 0 3px, var(--sc) 3px 5px, transparent 5px 8px);
  background-size: 100% 15px;
  background-position: center 5px;
}
/* craks: a single brushed chevron */
.cs-tag[data-k="crak"] {
  background-image:
    linear-gradient(120deg, transparent 44%, var(--sc) 44% 56%, transparent 56%),
    linear-gradient(60deg, transparent 44%, var(--sc) 44% 56%, transparent 56%);
  background-size: 100% 100%, 100% 100%;
}
/* winds: an arrowhead, the one suit that points somewhere */
.cs-tag[data-k="wind"] {
  background-image:
    linear-gradient(135deg, transparent 46%, var(--sc) 46% 54%, transparent 54%),
    linear-gradient(45deg, transparent 46%, var(--sc) 46% 54%, transparent 54%),
    linear-gradient(180deg, var(--sc) 1.6px, transparent 1.6px);
  background-size: 11px 11px, 11px 11px, 1.6px 9px;
  background-position: 4px 6px, 13px 6px, 50% 15px;
}

.cs-n {
  font: 700 11px/1 ui-monospace, Menlo, monospace;
  letter-spacing: 0;
  color: rgba(185, 255, 224, .72);
  font-variant-numeric: tabular-nums;
}
.cs-suit.on .cs-n { color: #b9ffdc; }
.cs-suit.is-low .cs-n { color: #ffb08a; }
.cs-suit.is-out { opacity: .42; }
.cs-suit.is-out .cs-n { color: #ff7a5c; }

/* ---------------- pulse: the one button the player owns ---------------- */
.cs-pulse-btn {
  position: absolute;
  right: calc(14px + env(safe-area-inset-right));
  bottom: calc(14px + env(safe-area-inset-bottom));
  z-index: 11;
  width: 66px;
  height: 66px;
  padding: 3px;
  border: 0;
  border-radius: 50%;
  background: conic-gradient(from -90deg, #ffd76a calc(var(--q, 0) * 1%), rgba(255,255,255,.1) 0);
  cursor: pointer;
  opacity: .6;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s, box-shadow .25s, opacity .25s;
}
.cs-pulse-btn > span {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 2px;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 28%, #13352a, #051310);
  border: 1px solid rgba(255,255,255,.14);
  color: rgba(255,224,138,.55);
  font: 800 8.5px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .12em;
}
.cs-pulse-btn b { font-size: 8.5px; letter-spacing: .12em; }
.cs-pulse-btn i { font-size: 6px; font-style: normal; opacity: .5; letter-spacing: .06em; }
.cs-pulse-btn.is-charging { opacity: .9; }
.cs-pulse-btn.is-ready {
  opacity: 1;
  box-shadow: 0 0 0 2px rgba(255,215,106,.5), 0 0 26px rgba(255,215,106,.6);
  animation: csReady 1.4s ease-in-out infinite;
}
.cs-pulse-btn.is-ready > span { color: #ffe08a; border-color: rgba(255,215,106,.55); }
.cs-pulse-btn:active { transform: scale(.94); }
@keyframes csReady {
  50% { box-shadow: 0 0 0 3px rgba(255,215,106,.75), 0 0 42px rgba(255,215,106,.85); }
}

.cs-pulse {
  position: absolute;
  left: 0; top: 0;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  border: 2.5px solid rgba(255,224,138,.72);
  box-shadow: 0 0 18px rgba(255,224,138,.4);
  pointer-events: none;
  animation: csPulseWave .62s cubic-bezier(.15,.8,.3,1) forwards;
}
@keyframes csPulseWave {
  from { transform: scale(.12); opacity: 1; }
  to   { transform: scale(var(--pr, 20)); opacity: 0; }
}

/* ---- pickups: tiles and dice that fall back into the water ---- */
.cs-pick, .cs-dice {
  position: absolute;
  left: 0; top: 0;
  z-index: 4;
  will-change: transform;
}
.cs-pick { width: 21px; height: 28px; margin: -14px 0 0 -10.5px; }
.cs-pick .tl, .cs-pick svg {
  width: 100% !important; height: 100% !important; display: block;
  border-radius: 4px;
  box-shadow: 0 0 0 1px rgba(185,255,224,.45), 0 5px 12px rgba(0,0,0,.5),
              0 0 16px rgba(143,211,184,.45);
}
.cs-pick.is-locked .tl, .cs-pick.is-locked svg { box-shadow: 0 0 0 2px #b9ffdc, 0 0 24px rgba(185,255,224,.9); }

.cs-dice {
  width: 34px; height: 34px; margin: -17px 0 0 -17px;
  border-radius: 8px;
  background: linear-gradient(155deg, #fdfbf3, #d8d2c4);
  border: 1px solid rgba(60,50,30,.5);
  box-shadow: 0 0 0 2px rgba(224,184,60,.55), 0 6px 16px rgba(0,0,0,.5),
              0 0 24px rgba(224,184,60,.6);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  justify-items: center;
  align-items: center;
  padding: 4px;
}
.cs-dice i { width: 6px; height: 6px; border-radius: 50%; background: #24201a; }
/* The pill uses the standalone rotate/scale properties, never transform — the
   game writes translate3d() into node.style transform every frame, and an
   animation on transform would outrank that and pin the die at the origin. */
.cs-dice { animation: csDiceGlow 1.6s ease-in-out infinite; }
.cs-dice.is-rolling {
  animation: csDiceGlow 1.6s ease-in-out infinite, csDiceRoll .45s linear infinite;
}
@keyframes csDiceRoll {
  0%   { rotate: -7deg;  scale: 1; }
  50%  { rotate: 7deg;   scale: 1.09; }
  100% { rotate: -7deg;  scale: 1; }
}
@keyframes csDiceGlow {
  0%, 100% {
    box-shadow: 0 0 0 2px rgba(224,184,60,.5), 0 6px 16px rgba(0,0,0,.5),
                0 0 18px rgba(224,184,60,.4);
  }
  50% {
    box-shadow: 0 0 0 2px rgba(224,184,60,.8), 0 6px 16px rgba(0,0,0,.5),
                0 0 34px rgba(224,184,60,.85);
  }
}

/* a pickup that is being pulled in */
.cs-pick.is-magnet, .cs-dice.is-magnet { transition: none; }

/* ---- buff tells ---- */
.cs-world.is-double .cs-craft { filter: drop-shadow(0 0 16px rgba(255, 150, 90, .8)); }
/* overdrive: the hull and its tiles run hot for as long as the chain holds */
.cs-world.is-frenzy .cs-craft { filter: drop-shadow(0 0 20px rgba(255, 199, 92, .72)) saturate(1.1); }
.cs-world.is-frenzy .cs-shot { filter: drop-shadow(0 0 6px rgba(255, 209, 102, .9)) brightness(1.08); }
.cs-world.is-frenzy .cs-exhaust { background: radial-gradient(circle at 50% 20%, #fff4d6, #ffb648 45%, rgba(255, 140, 60, 0) 74%); }

/* the burst ring under a dying bloom */
.cs-kring {
  position: absolute;
  border: 1.5px solid rgba(185, 255, 220, .8);
  border-radius: 50%;
  pointer-events: none;
  animation: csKRing .34s cubic-bezier(.2,.9,.3,1) forwards;
}
@keyframes csKRing {
  from { scale: .4; opacity: .8; }
  to   { scale: 1.25; opacity: 0; }
}
.cs-world.is-shield .cs-craft::after {
  content: '';
  position: absolute;
  inset: -13px -11px -7px;
  border-radius: 50% / 46%;
  border: 2px solid rgba(143, 211, 232, .8);
  box-shadow: 0 0 24px rgba(143, 211, 232, .55), inset 0 0 20px rgba(143, 211, 232, .22);
  pointer-events: none;
  animation: csShieldPulse 1.5s ease-in-out infinite;
}
@keyframes csShieldPulse {
  0%, 100% { opacity: .55; transform: scale(.975); }
  50%      { opacity: 1;   transform: scale(1.03); }
}

/* ---------------- toast / overlay ---------------- */
.cs-toast {
  position: absolute;
  left: 50%;
  top: 12%;
  transform: translateX(-50%);
  z-index: 20;
  padding: 9px 16px;
  border-radius: 9px;
  background: rgba(9,26,22,.9);
  border: 1px solid rgba(255,255,255,.14);
  color: #eef5f1;
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  max-width: 80%;
  box-shadow: 0 10px 26px rgba(0,0,0,.4);
  animation: csToast .25s ease;
}
@keyframes csToast { from { opacity: 0; transform: translate(-50%, -8px); } }
/* the boss owns the top of the screen — its callout has to live down here */
.cs-toast.is-low {
  top: auto;
  bottom: calc(74px + env(safe-area-inset-bottom));
  animation: csToastLow .25s ease;
}
@keyframes csToastLow { from { opacity: 0; transform: translate(-50%, 8px); } }

.cs-overlay {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(4,14,11,.7);
  backdrop-filter: blur(7px);
  animation: csFade .22s ease;
}
@keyframes csFade { from { opacity: 0; } }

.cs-modal {
  width: min(560px, 94vw);
  max-height: 88%;
  overflow-y: auto;
  border-radius: 18px;
  background: linear-gradient(180deg, #fffdf8, #f2ecdf);
  border: 1px solid rgba(27,42,34,.16);
  box-shadow: 0 30px 80px rgba(0,0,0,.5);
  padding: 24px 24px 20px;
  text-align: center;
  animation: csModal .3s cubic-bezier(.2,1.3,.4,1);
}
@keyframes csModal { from { transform: translateY(14px) scale(.97); opacity: 0; } }
/* The map is the one dialog that has to show fourteen tiles plus a way out.
   At 560px the grid folded into four rows and pushed "Close" below the fold;
   six columns fit it on three and leave the exit visible without scrolling. */
.cs-modal.is-wide { width: min(760px, 94vw); }

.cs-modal .cs-eyebrow {
  font: 700 9.5px/1 ui-monospace, Menlo, monospace;
  letter-spacing: .2em;
  color: #b08d57;
  margin-bottom: 9px;
}
.cs-modal h2 {
  margin: 0 0 6px;
  font: 600 25px/1.15 Georgia, serif;
  color: #16352a;
}
.cs-modal .cs-sub { margin: 0 0 14px; font-size: 12.5px; line-height: 1.55; color: #6f7d74; }
.cs-stars { font-size: 25px; letter-spacing: 6px; color: #d9cfae; margin-bottom: 12px; }
.cs-stars .on { color: #e0b83c; text-shadow: 0 3px 10px rgba(224,184,60,.45); }
.cs-sci {
  text-align: left;
  font-size: 12px;
  line-height: 1.62;
  color: #4f5d55;
  background: rgba(47,143,111,.07);
  border-left: 3px solid #2f8f6f;
  border-radius: 0 10px 10px 0;
  padding: 11px 13px;
  margin: 0 0 16px;
}
.cs-sci b { color: #1f6b52; }
.cs-modal-actions { display: flex; gap: 9px; justify-content: center; flex-wrap: wrap; }
.cs-modal-actions .mj-btn { padding: 10px 18px; font-size: 12.5px; font-weight: 700; color: #1c2b22; }
.cs-modal-actions .primary {
  background: linear-gradient(180deg, #2f8f6f, #1f6b52);
  color: #fff !important;
  border-color: #17553f;
}

.cs-levelgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: 8px;
  margin: 4px 0 14px;
  text-align: left;
}
.cs-lvbtn {
  border-radius: 10px;
  border: 1px solid rgba(27,42,34,.14);
  background: #fffdf8;
  padding: 8px 10px;
  cursor: pointer;
  font: inherit;
  color: #1c2b22;
  transition: transform .15s, box-shadow .15s;
}
.cs-lvbtn:hover { transform: translateY(-2px); box-shadow: 0 8px 18px rgba(20,45,33,.12); }
.cs-lvbtn b { display: block; font-size: 12px; }
.cs-lvbtn small { display: block; font-size: 9.5px; color: #8b978f; margin-top: 2px; }
.cs-lvbtn.locked { opacity: .4; cursor: not-allowed; }
.cs-lvbtn.now { border-color: #2f8f6f; box-shadow: 0 0 0 2px rgba(47,143,111,.25); }

/* the one door out of the campaign: the only tile in the list that is not a
   region, so it is styled as a band rather than a fourteenth button */
.cs-endlessbtn {
  display: block;
  width: 100%;
  margin: 10px 0 0;
  padding: 11px 14px;
  text-align: left;
  border-radius: 12px;
  cursor: pointer;
  font: inherit;
  color: #eafff5;
  border: 1px solid rgba(255, 209, 102, .38);
  background: linear-gradient(135deg, #14402f, #0a2318 62%, #123a2a);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
  transition: transform .15s, box-shadow .15s, border-color .15s;
}
.cs-endlessbtn:hover {
  transform: translateY(-2px);
  border-color: rgba(255, 209, 102, .8);
  box-shadow: 0 10px 22px rgba(6, 28, 20, .35), inset 0 1px 0 rgba(255, 255, 255, .14);
}
.cs-endlessbtn b { display: block; font-size: 12.5px; letter-spacing: .06em; color: #ffd166; }
.cs-endlessbtn small { display: block; margin-top: 3px; font-size: 10px; line-height: 1.45; color: #a9c6b8; }

/* ---------------- responsive ---------------- */
@media (max-width: 900px) {
  .cs-topbar-extra { display: none !important; }
  .cs-chapter { display: none; }
  .cs-hud { gap: 10px; padding: 9px 11px calc(9px + env(safe-area-inset-top)); }
  .cs-index { max-width: none; }
  .cs-index-top { font-size: 8.5px; letter-spacing: .1em; }
  .cs-index-top b { font-size: 15px; }
  .cs-score b, .cs-cleared b { font-size: 13px; }
  .cs-craft { width: 90px; height: 69px; margin: -34px 0 0 -45px; }
  .cs-suits { gap: 5px; padding: 5px 6px; bottom: calc(6px + env(safe-area-inset-bottom)); }
  .cs-suit { width: 52px; }
  .cs-tag { width: 18px; height: 22px; }
}

@media (max-width: 560px) {
  /* two extra topbar buttons (pause, sound) cost the title its last letters on
     a 390px screen. Tighten the bar rather than clip the name. */
  .mj-topbar .mj-tools { gap: 4px; }
  .mj-topbar .mj-iconbtn { width: 31px; height: 31px; font-size: 13px; }
  .mj-topbar .mj-btn { padding-left: 8px; padding-right: 8px; font-size: 11px; }
  .mj-topbar .mj-title { font-size: 15px; letter-spacing: 0; }
  .cs-score, .cs-cleared { display: none; }  .cs-craft { width: 79px; height: 61px; margin: -30px 0 0 -40px; }
  .cs-suit { width: 50px; font-size: 7px; }
  .cs-tag { width: 16px; height: 20px; }
  .cs-n { font-size: 10px; }
  .cs-chain { top: 21%; }
  /* the combo pill lives where the small screen has room: under the index bar,
     right-aligned, and short enough not to eat the playfield */
  .cs-combo {
    top: 76px;
    right: calc(9px + env(safe-area-inset-right));
    padding: 5px 9px 5px 8px;
    gap: 7px;
  }
  .cs-combo b { font-size: 17px; }
  .cs-combo i { font-size: 9.5px; }
  .cs-bossbar { top: 62px; width: 84%; }
  .cs-boss-head { font-size: 7.5px; letter-spacing: .14em; }
  .cs-threat { width: 22px; height: 22px; margin: -11px 0 0 -11px; }
  .cs-threat.is-clone { width: 26px; height: 26px; margin: -13px 0 0 -13px; }
  /* the field is a fifth as wide, so the litter has to shrink with it */
  .cs-pick { width: 18px; height: 24px; margin: -12px 0 0 -9px; }
  .cs-shot { width: 11px; height: 15px; margin: -7.5px 0 0 -5.5px; }
  .cs-shot.big { width: 13px; height: 18px; margin: -9px 0 0 -6.5px; }
  .cs-shot::after { height: 8px; }
  .cs-shot.wing-shot { width: 9px; height: 12px; margin: -6px 0 0 -4.5px; }
  .cs-wing { width: 30px; height: 24px; margin: -12px 0 0 -15px; }
  .cs-wing.is-boat { width: 33px; height: 27px; margin: -13px 0 0 -16.5px; }
  .cs-missile { width: 19px; height: 36px; margin: -18px 0 0 -9.5px; }
  .cs-flare { width: 21px; height: 34px; margin: -8px 0 0 -10.5px; }
  .cs-escort-drop { width: 34px; height: 34px; margin: -17px 0 0 -17px; }
  .cs-wingtag {
    left: calc(9px + env(safe-area-inset-left));
    top: 64px;
    gap: 6px;
    padding: 5px 8px 7px;
    font-size: 7.5px;
  }
  .cs-wingtag b { font-size: 11px; }
  .cs-dice { width: 26px; height: 26px; margin: -13px 0 0 -13px; }
  .cs-dice i { width: 4px; height: 4px; }
  .cs-pulse-btn {
    width: 54px; height: 54px;
    right: calc(9px + env(safe-area-inset-right));
    bottom: calc(9px + env(safe-area-inset-bottom));
  }
  .cs-pulse-btn b { font-size: 7.5px; }
  .cs-pulse-btn i { display: none; }
  /* fourteen regions in two columns would run off a phone screen */
  .cs-levelgrid { grid-template-columns: repeat(3, 1fr); gap: 6px; }
  .cs-lvbtn { padding: 7px 6px; }
  .cs-lvbtn b { font-size: 10px; line-height: 1.2; }
  .cs-lvbtn small { font-size: 8px; letter-spacing: 0; }
  .cs-lvbtn .st { font-size: 8.5px; }
  .cs-modal { padding: 18px 16px 16px; max-height: 92%; }
}

@media (max-width: 380px) {
  /* at 360px the shell's global menu button is the only thing that can give the
     title its last four letters back, and the game already carries its own
     Levels and Help entries */
  .mj-topbar [data-act="menu"] { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .cs-target .cs-ring, .cs-exhaust, .cs-pulse-btn.is-ready,
  .cs-boss .cs-boss-ring, .cs-boss .cs-boss-ring2, .cs-boss .cs-boss-core,
  .cs-target.is-splitter::after, .cs-target.is-diver.is-homing::after { animation: none; }
}

/* =====================================================================
   The planet you are holding — a live globe in the HUD that mirrors the
   greenhouse index. --health (1 thriving → 0 tipping) and --smog (0 clean
   → 1 smoggy) are written every frame from G.index; the colour stops are
   interpolated in JS so the world visibly warms or heals as you play.
   ===================================================================== */
.cs-earth {
  --health: 1;            /* 1 = thriving, 0 = tipping point */
  --smog: 0;              /* 0 = clear air, 1 = smoggy */
  --ice: 1;               /* polar cap scale */
  --c-ocean: #1f8fb8; --c-ocean-lo: #1c5e7a; --c-ocean-hi: #78d2ff; --c-land: #6cbf62;
  position: absolute; top: 10px; right: 12px; z-index: 9;
  width: 66px; height: 66px; border-radius: 50%;
  pointer-events: none;
  filter: drop-shadow(0 5px 12px rgba(0,0,0,.55));
}
.cs-earth-atmo {
  position: absolute; inset: -8px; border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(150,225,255,0) 56%, rgba(150,225,255,.4) 72%, rgba(150,225,255,0) 100%);
  opacity: calc(.35 + var(--health) * .55);
  transition: opacity .5s ease, background .6s ease;
}
.cs-earth-body {
  position: absolute; inset: 0; border-radius: 50%; overflow: hidden;
  background: radial-gradient(circle at 50% 46%, var(--c-ocean-hi), var(--c-ocean) 60%, var(--c-ocean-lo) 100%);
  box-shadow: inset -8px -10px 18px rgba(0,0,0,.5), inset 5px 6px 14px rgba(255,255,255,.14), 0 0 0 2px rgba(255,255,255,.10);
  transition: background .6s ease, box-shadow .5s ease;
}
.cs-earth-land {
  position: absolute; border-radius: 46% 54% 60% 40% / 52% 44% 56% 48%;
  background: var(--c-land);
  opacity: calc(.5 + var(--health) * .5);
  filter: drop-shadow(0 1px 1px rgba(0,0,0,.25));
  transition: background .6s ease, opacity .5s ease;
}
.cs-l1 { width: 27px; height: 21px; left: 11px; top: 29px; }
.cs-l2 { width: 18px; height: 15px; left: 39px; top: 17px; }
.cs-l3 { width: 23px; height: 17px; left: 29px; top: 44px; }
.cs-earth-ice {
  position: absolute; left: 13%; right: 13%; height: 30%;
  background: linear-gradient(180deg, #f4fbff, #d3eaf6);
  border-radius: 50%;
  transform: scaleY(var(--ice, 1));
  transform-origin: center;
  opacity: calc(.45 + var(--health) * .55);
  transition: transform .6s cubic-bezier(.2,1.4,.4,1), opacity .5s ease;
}
.cs-ice-n { top: -10%; }
.cs-ice-s { bottom: -10%; transform: scaleY(calc(var(--ice, 1) * -1)); }
.cs-earth-smog {
  position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, rgba(120,70,40,0) 38%, rgba(110,60,30,.6) 100%);
  mix-blend-mode: multiply;
  opacity: var(--smog);
  transition: opacity .6s ease;
}
.cs-earth-ring { position: absolute; inset: -11px; border-radius: 50%; border: 2px solid rgba(124,242,176,0); opacity: 0; }
.cs-earth-crack {
  position: absolute; inset: 0; border-radius: 50%;
  background:
    linear-gradient(122deg, transparent 47%, rgba(18,9,4,.6) 48%, transparent 49%),
    linear-gradient(34deg, transparent 51%, rgba(18,9,4,.5) 52%, transparent 53%),
    linear-gradient(200deg, transparent 60%, rgba(18,9,4,.45) 61%, transparent 62%);
  opacity: 0; transition: opacity .5s ease;
}

/* success: the world breathes back — a green shockwave, atmosphere flares,
   ice caps pop, smog clears */
.cs-earth.is-healing .cs-earth-ring { animation: csEarthHeal 1.15s cubic-bezier(.2,1,.3,1) forwards; }
.cs-earth.is-healing .cs-earth-atmo { animation: csEarthGlow .9s ease; }
.cs-earth.is-healing .cs-earth-ice { animation: csEarthIcePop .8s cubic-bezier(.2,1.6,.4,1); }
@keyframes csEarthHeal {
  0%   { opacity: .95; transform: scale(.65); border-color: rgba(124,242,176,.95); }
  70%  { opacity: .45; }
  100% { opacity: 0; transform: scale(1.8); border-color: rgba(124,242,176,0); }
}
@keyframes csEarthGlow { 0% { opacity: 1; } 100% { opacity: calc(.35 + var(--health) * .55); } }
@keyframes csEarthIcePop { 0%,100% { transform: scaleY(var(--ice,1)); } 40% { transform: scaleY(calc(var(--ice,1) * 1.18)); } }

/* failure: the world tips — red atmosphere, smog surges, a hairline crack,
   a short shudder. The stage desaturates behind the result card. */
.cs-earth.is-dying .cs-earth-crack { opacity: .9; }
.cs-earth.is-dying .cs-earth-atmo {
  background: radial-gradient(circle at 50% 50%, rgba(255,90,60,0) 56%, rgba(255,90,60,.55) 74%, rgba(255,90,60,0) 100%);
  animation: csEarthGlowRed 1.5s ease;
}
.cs-earth.is-dying { animation: csEarthShake .5s ease 2; }
@keyframes csEarthGlowRed { 0% { opacity: 1; } 100% { opacity: .55; } }
@keyframes csEarthShake {
  0%,100% { transform: translate(0,0); } 25% { transform: translate(-2px,1px); }
  50% { transform: translate(2px,-1px); } 75% { transform: translate(-1px,-1px); }
}
.cs-stage.is-dying { filter: saturate(.5) brightness(.88); transition: filter .6s ease; }
.cs-stage.is-dying .cs-earth { filter: drop-shadow(0 5px 12px rgba(0,0,0,.55)) saturate(.7); }

/* full-screen win flash */
.cs-flash {
  position: absolute; inset: 0; z-index: 11; pointer-events: none; opacity: 0;
  background: radial-gradient(circle at 50% 56%, rgba(186,255,222,.92), rgba(120,230,180,.42) 58%, rgba(120,230,180,0) 100%);
}
.cs-flash.go { animation: csFlash .5s ease-out; }
@keyframes csFlash { 0% { opacity: .9; } 100% { opacity: 0; } }
/* the same full-screen hit, in red, for losing a life */
.cs-flash.hurt {
  background: radial-gradient(circle at 50% 56%, rgba(255,120,96,.6), rgba(255,70,50,.34) 55%, rgba(180,40,20,0) 100%);
}
.cs-flash.hurt.go { animation: csHurtFlash .4s ease-out; }
@keyframes csHurtFlash { 0% { opacity: .95; } 100% { opacity: 0; } }
