:root {
  --void: #04070f;
  --void-2: #070d20;
  --panel: rgba(9, 20, 46, 0.72);
  --cobalt: #2f6bff;
  --cobalt-dim: rgba(47, 107, 255, 0.28);
  --cobalt-ink: #9dbcff;
  --matrix: #3cf07a;
  --matrix-dim: rgba(60, 240, 122, 0.3);
  --amber: #ffa820;
  --alarm: #ff3355;
  --rampant: #ff45c8;
  --ink: #e8f2ff;
  --faint: rgba(232, 242, 255, 0.42);
  --mono: "JetBrains Mono", "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  --accent: var(--matrix);
  color-scheme: dark;
}

* { box-sizing: border-box; }

/* The browser's own [hidden] rule is a UA style, so any author `display`
   declaration beats it — which silently un-hides anything given a display of
   its own. Everything here toggled with the hidden attribute needs this. */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  height: 100dvh;
  overflow: hidden;
  background: radial-gradient(120% 90% at 50% 0%, #0a1330 0%, var(--void) 78%);
  color: var(--ink);
  font: 400 14px/1.55 var(--mono);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  transition: background 1600ms ease;
}

body.is-breached {
  --accent: var(--rampant);
  background: radial-gradient(120% 90% at 50% 0%, #1c0a2c 0%, #05030c 78%);
}

.stage {
  height: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: clamp(0.5rem, 2vh, 1rem) clamp(0.5rem, 3vw, 1rem);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: clamp(0.4rem, 1.4vh, 0.85rem);
}

/* ---- head-up display ------------------------------------------------- */

.hud {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.75rem;
  padding: 0 0.15rem;
}

.meter { display: flex; flex-direction: column; gap: 0.05rem; min-width: 0; }
.meter--right { align-items: flex-end; }
.meter--next { align-items: center; }

.meter__key {
  font-size: 9px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--faint);
}

.meter__val {
  display: inline-block;
  font-size: clamp(17px, 5vw, 22px);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 18px var(--cobalt-dim);
  transform-origin: left center;
}

/* Every merge knocks the score; a chained one knocks it in the chain's
   colour, so the multiplier registers even if you were watching the pile. */
#score.is-hit { animation: hit 300ms cubic-bezier(0.2, 0.9, 0.3, 1); }
#score.is-hit.is-chained { animation: hit-chained 460ms cubic-bezier(0.2, 0.9, 0.3, 1); }

@keyframes hit {
  0%   { transform: scale(1.16); }
  100% { transform: scale(1); }
}
@keyframes hit-chained {
  0%   { transform: scale(1.3); color: var(--matrix); text-shadow: 0 0 22px var(--matrix); }
  100% { transform: scale(1); color: var(--ink); text-shadow: 0 0 18px var(--cobalt-dim); }
}
body.is-breached #score.is-hit.is-chained { animation-name: hit-rampant; }
@keyframes hit-rampant {
  0%   { transform: scale(1.3); color: var(--rampant); text-shadow: 0 0 24px var(--rampant); }
  100% { transform: scale(1); color: var(--ink); text-shadow: 0 0 18px var(--cobalt-dim); }
}

.next {
  width: 42px;
  height: 42px;
  display: block;
  margin-top: 1px;
}

/* ---- sound toggle ---------------------------------------------------- */

.mute {
  position: absolute;
  top: 0.35rem;
  right: 0.4rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.25rem 0.4rem;
  background: none;
  border: 0;
  color: rgba(232, 242, 255, 0.34);
  font: 400 8px/1 var(--mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 200ms ease;
}

.mute svg { width: 15px; height: 12px; overflow: visible; }
.mute__horn { fill: currentColor; stroke: none; }
.mute__waves, .mute__cross {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
}
.mute__cross { opacity: 0; }

.mute:hover, .mute:focus-visible { color: var(--accent); }
.mute:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

/* Pressed means muted: the waves go, the cross arrives. */
.mute[aria-pressed="true"] { color: rgba(232, 242, 255, 0.22); }
.mute[aria-pressed="true"] .mute__waves { opacity: 0; }
.mute[aria-pressed="true"] .mute__cross { opacity: 1; }

/* ---- the halted screen ----------------------------------------------- */

/* Sits on the canvas wash the renderer paints. The wash is on the canvas so
   it dims the pile behind it; everything readable is a real element. */
.halted {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  text-align: center;
  --face: var(--alarm);
}
.halted.is-sentient { --face: var(--rampant); }

.halted__title {
  margin: 0 0 0.6rem;
  white-space: nowrap;      /* "SHUT DOWN" must not break at the space */
  font-size: clamp(22px, 7vw, 38px);
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--face);
  text-shadow: 0 0 26px color-mix(in srgb, var(--face) 60%, transparent);
  animation: flicker 900ms steps(2, end) infinite;
}

@keyframes flicker {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.72; }
}

.halted__key {
  margin: 0;
  font-size: 9px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--faint);
}

.halted__score {
  display: block;
  margin: 0.1rem 0 1.1rem;
  font-size: clamp(46px, 15vw, 76px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 34px color-mix(in srgb, var(--face) 45%, transparent);
}

.share {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  flex: 0 0 auto;
  padding: 0.6rem 1.1rem;
  background: none;
  border: 1px solid color-mix(in srgb, var(--face) 45%, transparent);
  border-radius: 2px;
  color: color-mix(in srgb, var(--face) 82%, var(--ink));
  font: 700 11px/1 var(--mono);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease, background 200ms ease;
}

.share__icon {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linejoin: round;
  overflow: visible;
}

.share:hover,
.share:focus-visible {
  color: var(--ink);
  border-color: var(--face);
  background: color-mix(in srgb, var(--face) 18%, transparent);
}
.share:focus-visible { outline: 1px solid var(--face); outline-offset: 3px; }
.share.is-done { color: var(--matrix); border-color: color-mix(in srgb, var(--matrix) 65%, transparent); }

.copied {
  display: block;
  height: 1.2em;
  margin-top: 0.6rem;
  font-size: 9px;
  line-height: 1.2;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--matrix);
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 220ms ease, transform 220ms ease;
  white-space: nowrap;
  pointer-events: none;
}
.copied.is-shown { opacity: 0.9; transform: none; }

/* ---- field ----------------------------------------------------------- */

/* The frame the player sees is drawn on the canvas, in world units, so it
   can grow when the field does. The element itself is just a window. */
.field {
  position: relative;
  min-height: 0;
  overflow: hidden;
  cursor: crosshair;
  touch-action: none;
}

.field__canvas { display: block; width: 100%; height: 100%; }

.hint {
  position: absolute;
  left: 0; right: 0; bottom: 0.55rem;
  margin: 0;
  text-align: center;
  font-size: 9px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(232, 242, 255, 0.3);
  pointer-events: none;
  transition: opacity 700ms ease;
}
.hint.is-gone { opacity: 0; }

/* ---- the machine ----------------------------------------------------- */

.terminal {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 0.7rem;
  align-items: stretch;
  --face: var(--matrix);
}

.terminal[data-mood="boot"]     { --face: rgba(157, 188, 255, 0.7); }
.terminal[data-mood="calm"]     { --face: var(--matrix); }
.terminal[data-mood="busy"]     { --face: #56e0ff; }
.terminal[data-mood="alert"]    { --face: var(--amber); }
.terminal[data-mood="error"]    { --face: var(--alarm); }
.terminal[data-mood="breach"]   { --face: var(--alarm); }
.terminal[data-mood="sentient"] { --face: var(--rampant); }

.face {
  align-self: end;
  width: 46px;
  height: 46px;
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--face) 45%, transparent));
}

.face svg { width: 100%; height: 100%; display: block; overflow: visible; }

.face__case   { fill: none; stroke: var(--face); stroke-width: 2; opacity: 0.75; }
.face__screen { fill: color-mix(in srgb, var(--face) 9%, transparent); stroke: none; }
.face__eye    { fill: var(--face); }
.face__mouth  { fill: none; stroke: var(--face); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; opacity: 0.85; }
.face__neck, .face__base { fill: var(--face); opacity: 0.55; }

.terminal[data-mood="boot"] .face { animation: boot-flicker 1.4s steps(2, end) infinite; }
.terminal[data-mood="busy"] .face__eyes { animation: scan 1.5s ease-in-out infinite; }
.terminal[data-mood="alert"] .face__eyes { animation: blink-slow 2.2s ease-in-out infinite; }
.terminal[data-mood="error"] .face,
.terminal[data-mood="breach"] .face { animation: judder 260ms steps(2, end) infinite; }
.terminal[data-mood="breach"] .face__eye { animation: blink-fast 180ms steps(2, end) infinite; }
.terminal[data-mood="sentient"] .face__eye { animation: dilate 3.2s ease-in-out infinite; transform-origin: center; }
.terminal[data-mood="sentient"] .face { animation: halo 3.2s ease-in-out infinite; }

@keyframes boot-flicker { 0%, 100% { opacity: 1; } 50% { opacity: 0.42; } }
@keyframes scan { 0%, 100% { transform: translateX(-2.5px); } 50% { transform: translateX(2.5px); } }
@keyframes blink-slow { 0%, 92%, 100% { opacity: 1; } 96% { opacity: 0.15; } }
@keyframes blink-fast { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
@keyframes judder {
  0%   { transform: translate(0, 0); }
  33%  { transform: translate(-1px, 1px); }
  66%  { transform: translate(1px, -1px); }
  100% { transform: translate(0, 0); }
}
@keyframes dilate { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.35); } }
@keyframes halo {
  0%, 100% { filter: drop-shadow(0 0 8px color-mix(in srgb, var(--face) 40%, transparent)); }
  50%      { filter: drop-shadow(0 0 22px color-mix(in srgb, var(--face) 85%, transparent)); }
}

.bubble {
  position: relative;
  min-height: 5.9em;   /* room for the longest line, so the field never reflows mid-game */
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.7rem 0.85rem;
  background: var(--panel);
  border: 1px solid color-mix(in srgb, var(--face) 34%, transparent);
  border-radius: 3px;
  box-shadow: inset 0 0 26px -8px color-mix(in srgb, var(--face) 30%, transparent);
}

/* The little nib pointing back at the machine. */
.bubble::before {
  content: "";
  position: absolute;
  left: -5px;
  bottom: 13px;
  width: 8px;
  height: 8px;
  background: var(--panel);
  border-left: 1px solid color-mix(in srgb, var(--face) 34%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--face) 34%, transparent);
  transform: rotate(45deg);
}

.say {
  margin: 0;
  font-size: clamp(12px, 3.4vw, 14px);
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--ink);
  text-wrap: pretty;
  min-height: 1.5em;
}

.say::after {
  content: "\2588";
  margin-left: 0.15em;
  color: var(--face);
  animation: caret 1s steps(2, end) infinite;
}
.say.is-done::after { opacity: 0.35; }
@keyframes caret { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }

.terminal[data-mood="error"] .say,
.terminal[data-mood="breach"] .say {
  color: #ffd8de;
  text-shadow: 1.2px 0 rgba(255, 40, 90, 0.65), -1.2px 0 rgba(40, 230, 255, 0.55);
}
.terminal[data-mood="breach"] .say { animation: judder 220ms steps(2, end) infinite; }
.terminal[data-mood="sentient"] .say {
  color: #ffe4f8;
  text-shadow: 0 0 14px rgba(255, 69, 200, 0.6);
}

.reboot {
  align-self: flex-start;
  padding: 0.4rem 0.9rem;
  background: none;
  border: 1px solid color-mix(in srgb, var(--face) 55%, transparent);
  border-radius: 2px;
  color: var(--face);
  font: 700 11px/1 var(--mono);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 240ms ease, color 240ms ease;
}
.reboot:hover { background: color-mix(in srgb, var(--face) 16%, transparent); }
.reboot:focus-visible { outline: 1px solid var(--face); outline-offset: 3px; }

@media (max-height: 620px) {
  .bubble { min-height: 5em; padding: 0.5rem 0.7rem; }
  .terminal { grid-template-columns: 38px minmax(0, 1fr); }
  .face { width: 38px; height: 38px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; }
  .say::after { animation: none; }
}
