:root { color-scheme: dark; }
* { box-sizing: border-box; }
html, body {
  margin: 0; height: 100%;
  background: #05060a;
  color: #cfe9ff;
  font: 14px/1.4 ui-monospace, "SF Mono", Menlo, monospace;
  overflow: hidden;
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
  /* no double-tap-to-zoom anywhere in the game */
  touch-action: manipulation;
}
#wrap {
  height: 100dvh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .5rem;
  /* The pause & wave chips (see #topbar) float over the top corners of the
     board, so we no longer reserve a band for them - the board reclaims that
     height. Safe-area insets still keep clear of notches / home indicators. */
  padding: calc(env(safe-area-inset-top, 0px) + .6rem) .6rem
           calc(env(safe-area-inset-bottom, 0px) + .6rem);
}

/* ── In-game top bar (pause + wave counter) ─────────────────────────────────
   Fixed to the top edge, pinned to the corners, floating *over* the top of the
   board so it costs no vertical space. pointer-events pass through the bar
   itself so the board stays clickable right up to the very top. */
#topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  /* respect the notch / rounded corners so the pause & wave chips stay clear */
  padding: calc(env(safe-area-inset-top, 0px) + .7rem)
           calc(env(safe-area-inset-right, 0px) + .9rem) .7rem
           calc(env(safe-area-inset-left, 0px) + .9rem);
  pointer-events: none;
}
#topbar > * { pointer-events: auto; }
/* Pause & wave chips share the same translucent, blurred backdrop as the #msg
   toast - see the shared look at the bottom of this file. */
#pause {
  padding: .5rem; line-height: 0;
  background: #08142699; border: 1px solid #142744; border-radius: 10px;
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
#pause svg { width: 1.15rem; height: 1.15rem; fill: currentColor; display: block; }
#topbar .wavestat {
  text-align: right; background: #08142699; border: 1px solid #142744;
  border-radius: 10px; padding: .35rem .65rem;
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}

/* ── Menu / Guide / About overlays ──────────────────────────────────────────
   Full-screen glass panels layered above the game board. */
.screen {
  position: fixed; inset: 0; z-index: 100;
  /* `safe center` centers the card when it fits, but falls back to top-aligned
     once it's taller than the viewport - otherwise the top scrolls off-screen
     and can't be reached (e.g. the long changelog on a phone). */
  display: flex; align-items: safe center; justify-content: center;
  padding: 1.2rem;
  background: radial-gradient(120% 90% at 50% 0%, #0b1e3aee 0%, #05060af5 70%);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  overflow-y: auto;
}
.screen[hidden] { display: none; }
.menu-card {
  position: relative; z-index: 1; /* float above the background preview */
  width: min(420px, 100%);
  display: flex; flex-direction: column; align-items: center; gap: .8rem;
  text-align: center;
  background: #081426f2; border: 1px solid #1d3a5f; border-radius: 16px;
  padding: 2rem 1.4rem;
  box-shadow: 0 20px 60px #000b, 0 0 26px #1e6fff33;
}
.menu-card.wide { width: min(520px, 100%); }
.menu-title {
  margin: 0; font-size: 1.9rem; color: #fff; letter-spacing: .02em;
  text-shadow: 0 0 18px #46b4ff88;
  display: flex; align-items: center; justify-content: center; gap: .5rem;
}
.brand-icon { display: inline-flex; line-height: 0; }
.brand-icon canvas { display: block; }
.menu-tag { margin: 0; opacity: .55; text-transform: uppercase; letter-spacing: .12em; font-size: .72rem; }
.menu-nav { display: flex; flex-direction: column; gap: .9rem; width: 100%; margin-top: .6rem; }
/* looping mini-battle that plays in the background of the main menu: pinned
   full-width to the bottom, behind the card, fading up into the backdrop */
.menu-preview {
  position: absolute; left: 0; right: 0; bottom: 0;
  width: 100%; height: min(240px, 34vh);
  z-index: 0; opacity: .55; pointer-events: none;
  -webkit-mask-image: linear-gradient(to top, #000 70%, transparent);
          mask-image: linear-gradient(to top, #000 70%, transparent);
}
.menu-btn { width: 100%; padding: .8rem 1rem; font-size: 1rem; }
/* Co-op lobby */
.coop-or { opacity: .4; text-transform: uppercase; letter-spacing: .12em; font-size: .7rem; }
.coop-join { display: flex; gap: .6rem; width: 100%; }
.coop-join .menu-btn { width: auto; flex: 0 0 auto; }
.coop-input {
  flex: 1 1 auto; min-width: 0; padding: .8rem 1rem;
  font: inherit; font-size: 1.3rem; letter-spacing: .35em; text-align: center; text-transform: uppercase;
  color: #eaf2ff; background: #0a1830; border: 1px solid #24406e; border-radius: 8px;
}
.coop-input::placeholder { color: #3a5a8c; opacity: .5; letter-spacing: .35em; }
.coop-input:focus { outline: none; border-color: #46b4ff; box-shadow: 0 0 0 2px #46b4ff33; }
.coop-status { margin: .2rem 0 0; min-height: 1.2em; font-size: .8rem; line-height: 1.4; opacity: .8; }
.coop-status.err { color: #ff7b9c; opacity: 1; }
.coop-status .code { color: #6bff9e; font-size: 1.6rem; letter-spacing: .35em; font-weight: 700; }
/* "Host is choosing a level" waiting screen - three pulsing dots after the tag */
.wait-dots { display: inline-flex; gap: .28em; margin-left: .2em; vertical-align: baseline; }
.wait-dots span {
  width: .34em; height: .34em; border-radius: 50%; background: #46b4ff;
  animation: wait-dot 1.2s ease-in-out infinite;
}
.wait-dots span:nth-child(2) { animation-delay: .2s; }
.wait-dots span:nth-child(3) { animation-delay: .4s; }
@keyframes wait-dot { 0%, 80%, 100% { opacity: .2; } 40% { opacity: 1; } }
/* Guide */
.guide-body { text-align: left; width: 100%; display: flex; flex-direction: column; gap: .7rem; }
.guide-body p { margin: 0; line-height: 1.55; }
.guide-body b { color: #7fdfff; }
.guide-towers { margin: .2rem 0 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: .35rem; }
.guide-towers li { line-height: 1.4; }
/* Level briefing popup - same reading style as the guide */
.popup-body { text-align: left; width: 100%; display: flex; flex-direction: column; gap: .7rem; }
.popup-body p { margin: 0; line-height: 1.55; }
.popup-body b { color: #7fdfff; }
/* About */
.about-credits { display: flex; flex-direction: column; gap: .3rem; margin: .8rem 0; }
.about-role { opacity: .5; text-transform: uppercase; letter-spacing: .1em; font-size: .72rem; }
.about-name { color: #46ffd1; font-size: 1.5rem; text-shadow: 0 0 16px #12ffcf66; }
/* Inline UI icons (js/icons.js) - sit in buttons/headings and take their colour.
   Height tracks the surrounding font; width auto-fits each glyph's aspect. */
.icn { display: inline-flex; line-height: 0; vertical-align: -0.13em; }
.icn svg { height: 1em; width: auto; fill: currentColor; display: block; }
.about-link { color: #7fdfff; font-size: 1.05rem; text-decoration: none; }
.about-link:hover { text-decoration: underline; text-shadow: 0 0 12px #46b4ff88; }
.about-version { color: #7fdfff; font-size: 1.15rem; letter-spacing: .04em; font-variant-numeric: tabular-nums; }
/* Changelog */
.changelog-body { text-align: left; width: 100%; display: flex; flex-direction: column; gap: 1.1rem; }
.cl-entry { display: flex; flex-direction: column; gap: .45rem; padding-bottom: 1rem; border-bottom: 1px solid #1d3a5f66; }
.cl-entry:last-child { border-bottom: 0; padding-bottom: 0; }
.cl-head { display: flex; align-items: baseline; justify-content: space-between; gap: .6rem; }
.cl-version { color: #46ffd1; font-size: 1.1rem; text-shadow: 0 0 14px #12ffcf55; font-variant-numeric: tabular-nums; }
.cl-date { opacity: .45; font-size: .72rem; letter-spacing: .08em; font-variant-numeric: tabular-nums; }
.cl-notes { margin: 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: .35rem; }
.cl-notes li { line-height: 1.45; }

/* ── Game over overlay ──────────────────────────────────────────────────────
   red-tinted, heavier blur over the frozen board - fades in after the core
   finishes wobbling (the overlay is un-hidden by JS at that point) */
.gameover {
  background: radial-gradient(120% 90% at 50% 38%, #4a0a14ee 0%, #12040af7 72%);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  animation: gameover-fade .55s ease both;
}
.gameover .menu-card { animation: gameover-rise .55s ease .08s both; }
@keyframes gameover-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes gameover-rise {
  from { opacity: 0; transform: translateY(10px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
.gameover .menu-card { border-color: #ff466688; box-shadow: 0 20px 60px #000b, 0 0 42px #ff223355; }
.over-title { color: #ff6b6b; text-shadow: 0 0 22px #ff2244aa; }
.over-wave { color: #ff8a8a; text-shadow: 0 0 16px #ff224466; }
#restart {
  width: 100%; background: #2a0d12; color: #ff9e9e; border-color: #7a2b2b;
}
#restart:hover:not(:disabled) { border-color: #ff6b6b; color: #ffc2c2; box-shadow: 0 0 14px #ff334477; }

/* ── Level selector ──────────────────────────────────────────────────────── */
.level-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: .7rem;
  width: 100%; margin: .3rem 0 .4rem;
}
.level-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: .35rem;
  text-align: left; padding: .85rem .9rem; min-height: 92px;
  background: #0a1830; border: 1px solid #1d3a5f; border-radius: 12px;
}
.level-card:hover:not(:disabled) { border-color: #46b4ff; box-shadow: 0 0 14px #1e6fff66; transform: translateY(-1px); }
.level-card.locked { opacity: .5; filter: grayscale(.5); }
.level-card .lc-top { display: flex; align-items: center; gap: .4rem; width: 100%; }
.level-card .lc-name { color: #fff; font-weight: 600; font-size: 1rem; }
.level-card .lc-desc { margin: 0; font-size: .78rem; line-height: 1.35; opacity: .65; }
.level-card .lc-badge { margin-left: auto; font-size: .82rem; }
.level-card .lc-badge.stars { color: #ffd23b; text-shadow: 0 0 10px #ffb43366; letter-spacing: -1px; }
.level-card .lc-badge.endless { color: #46ffd1; font-weight: 700; }
.level-card .lc-lock { margin-left: auto; }
@media (max-width: 480px) { .level-grid { grid-template-columns: 1fr; } }

/* ── Level-clear overlay ─────────────────────────────────────────────────── */
.levelclear {
  background: radial-gradient(120% 90% at 50% 38%, #0a3a2aee 0%, #04120cf7 72%);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  animation: gameover-fade .55s ease both;
}
.levelclear .menu-card { animation: gameover-rise .55s ease .08s both; border-color: #2fbf7a88; box-shadow: 0 20px 60px #000b, 0 0 42px #12ff9955; }
.clear-title { color: #6bff9e; text-shadow: 0 0 22px #12ffcfaa; }
.lc-result { font-size: 2rem; color: #ffd23b; text-shadow: 0 0 20px #ffb43377; letter-spacing: .1em; margin: .3rem 0; }
.lc-actions { display: flex; gap: .5rem; width: 100%; }
.lc-actions button { flex: 1; }

/* ── Co-op end overlay ───────────────────────────────────────────────────────
   Host controls / partner waiting screen shown when a co-op game ends. Reuses
   the solo overlay treatments, themed green (win) or red (lose) by a class. */
.coopend { -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); animation: gameover-fade .55s ease both; }
.coopend .menu-card { animation: gameover-rise .55s ease .08s both; }
.coopend.win  { background: radial-gradient(120% 90% at 50% 38%, #0a3a2aee 0%, #04120cf7 72%); }
.coopend.win  .menu-card { border-color: #2fbf7a88; box-shadow: 0 20px 60px #000b, 0 0 42px #12ff9955; }
.coopend.win  #ceTitle { color: #6bff9e; text-shadow: 0 0 22px #12ffcfaa; }
.coopend.lose { background: radial-gradient(120% 90% at 50% 38%, #4a0a14ee 0%, #12040af7 72%); }
.coopend.lose .menu-card { border-color: #ff466688; box-shadow: 0 20px 60px #000b, 0 0 42px #ff223355; }
.coopend.lose #ceTitle { color: #ff6b6b; text-shadow: 0 0 22px #ff2244aa; }
#ceWait .menu-btn { width: 100%; margin-top: .8rem; }

/* One-shot info note on the main menu (e.g. "co-op session ended") */
.menu-note {
  margin: .1rem 0 .2rem; padding: .5rem .7rem; border-radius: 8px;
  background: #1d3a5f44; border: 1px solid #46b4ff44; color: #bcd7ff;
  font-size: .82rem; line-height: 1.4;
}
.menu-note[hidden] { display: none; }

/* Co-op "connected" indicator - a small pulsing green dot in the top bar */
.conn-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: #35e08a; box-shadow: 0 0 8px #12ff9988;
  align-self: center;
  /* sit just right of the pause button; soak up the free space so the wave chip
     stays pinned to the far right (the top bar is justify-content: space-between) */
  margin-left: .55rem; margin-right: auto;
  animation: conn-pulse 1.8s ease-in-out infinite;
}
.conn-dot[hidden] { display: none; }
@keyframes conn-pulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; box-shadow: 0 0 12px #12ff99cc; } }

#hud {
  flex: none;
  display: flex; gap: 1.25rem; align-items: center; flex-wrap: wrap;
  justify-content: center;
}
#hud .stat b { color: #fff; font-size: 1.1rem; }
#hud .stat span { opacity: .5; text-transform: uppercase; letter-spacing: .08em; font-size: .7rem; }
/* two towers per row - wraps to a tidy 2×2 block as the roster grows */
.shop { display: flex; flex-wrap: wrap; gap: .5rem; width: min(320px, 100%); }
/* touch-action:none so a press-drag off the button builds instead of scrolling */
.shop button {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  touch-action: none; flex: 1 1 calc(50% - .25rem); min-width: 0;
}
/* the tower art that follows the finger while dragging out of the shop */
.drag-ghost {
  position: fixed; z-index: 50; pointer-events: none;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 4px 10px #000a);
}
.shop button canvas { flex: none; }
.shop button .lbl { display: inline-flex; align-items: baseline; gap: .35rem; white-space: nowrap; }
.shop button .pr { opacity: .6; }
.shop button .pr::before { content: "· "; }
button {
  font: inherit; cursor: pointer;
  background: #0c1526; color: #7fdfff;
  border: 1px solid #1d3a5f; border-radius: 8px;
  padding: .6rem .9rem; transition: all .12s;
  -webkit-tap-highlight-color: transparent;
}
button:hover:not(:disabled) { border-color: #46b4ff; box-shadow: 0 0 12px #1e6fff66; }
button:disabled { opacity: .35; cursor: not-allowed; }
button.sel { border-color: #46ffd1; color: #46ffd1; box-shadow: 0 0 14px #12ffcf55; }
button.go { background: #10361f; color: #6bff9e; border-color: #1f7a45; }
#ff { display: inline-flex; align-items: center; gap: .4rem; }
#ff[hidden] { display: none; }
/* custom double-chevron fast-forward icon - inherits the button colour, so it
   turns gold along with the text when fast-forward is engaged */
.ff-ico { width: 1.15em; height: 1em; flex: none; fill: currentColor; display: block; }
#ff.fast { border-color: #ffd36b; color: #ffd36b; box-shadow: 0 0 14px #ffb43355; }
#ff.fast .ff-ico { filter: drop-shadow(0 0 4px #ffb43399); }
/* the board frame: the largest 2:3 box that fits both the width cap and the
   height #board hands it. Carrying the size here (not on the canvas) means the
   frame shrink-wraps the board exactly, so the upgrade panel anchored to it
   always sits on the canvas - even when #board is taller on big screens. */
#frame {
  position: relative;
  aspect-ratio: 2 / 3;
  max-width: min(440px, 96vw);
  max-height: 100%;
}
canvas {
  display: block; width: 100%; height: 100%;
  border: 1px solid #142744; border-radius: 12px;
  box-shadow: 0 0 60px #0a1e4033, inset 0 0 60px #0009;
  touch-action: none;
}
/* Floats over the bottom of the board (anchored to #frame, like #panel) with a
   small blurred pill behind the text so it stays readable over the grid. It
   reserves no layout space, and :empty hides it entirely once flash() clears
   the text - so the board keeps that room the rest of the time. */
#msg {
  position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%);
  z-index: 4; pointer-events: none;
  width: max-content; max-width: 92%; padding: .4rem .75rem;
  text-align: center; color: #ffd36b;
  text-shadow: 0 0 10px #ffb43355;
  background: #08142699; border: 1px solid #ffd36b2e; border-radius: 10px;
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
#msg:empty { display: none; }
kbd { background: #0c1526; border: 1px solid #1d3a5f; border-radius: 4px; padding: 0 .3em; }
/* shrinks (but never grows) to the height left after the message + HUD, and
   centres the frame inside it - this is what stops the board clipping top or
   bottom, while keeping the whole column tidily grouped on tall screens */
#board { position: relative; display: flex; flex: 0 1 auto; min-height: 0; width: 100%; align-items: center; justify-content: center; }
/* upgrade card - floats over the bottom of the board when a tower is picked */
#panel {
  position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%);
  width: min(340px, 94%);
  background: #081426f2; border: 1px solid #46b4ff; border-radius: 12px;
  padding: .6rem .7rem; z-index: 5;
  box-shadow: 0 10px 34px #000b, 0 0 18px #1e6fff44;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
#panel[hidden] { display: none; }
#panel .phead { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; }
#panel .phead span { color: #fff; font-size: 1rem; }
#panel .phead b { color: #ffd36b; font-size: .8rem; letter-spacing: .05em; }
#pstats { opacity: .8; margin: .3rem 0; }
#pnext { color: #6bff9e; min-height: 1.2em; font-size: .82rem; }
#panel .prow { display: flex; gap: .4rem; margin-top: .5rem; }
#panel #upg { flex: 1; padding: .5rem .4rem; white-space: nowrap; }
#panel #sell { padding: .5rem .55rem; border-color: #7a4a1f; color: #ffb43b; white-space: nowrap; }
#panel #sell:hover:not(:disabled) { border-color: #ffb43b; box-shadow: 0 0 12px #ffb43355; }
#panel #pclose { padding: .5rem .7rem; }
/* On phones the three shop buttons won't fit in one row - give the shop the
   full width, let the buttons share it equally, and stack name over price. */
@media (max-width: 520px) {
  #hud { gap: .5rem .75rem; }
  .shop { flex: 1 1 100%; width: auto; gap: .4rem; }
  .shop button { flex: 1 1 calc(50% - .2rem); min-width: 0; justify-content: center; padding: .45rem .3rem; gap: .35rem; }
  .shop button canvas { width: 26px !important; height: 26px !important; }
  .shop button .lbl { flex-direction: column; align-items: flex-start; gap: 0; line-height: 1.15; }
  .shop button .nm { color: #fff; font-size: .82rem; }
  .shop button .pr { font-size: .72rem; }
  .shop button .pr::before { content: ""; }
}
