/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   FONT SIZE RULES: read before adding or changing any text. The menus (RULES & RECORDS, EXPLOITS,
   the STORE, SETTINGS, the info cards) share one scale; use one of these sizes, not a new one.
     17px    a card's title (h2: EXPLOITS, STORE) and an item's name (h3: an exploit, a booster)
     15.5px  a section head (STORE's BOOSTERS, EXPLOITS' TIER 1, SETTINGS' // SOUND); the banners
     14.5px  body text in the cards' pages; the ===== lines (14.5px, line-height 15px, 2px apart)
     13px    notes and descriptions under a head or an option (store notes, tier notes, settings
             notes and sub-heads like THEME)
     12px    buttons (BACK, the settings toggles, BUY)
     11.5px  small tags, and the smallest text there is: EQUIPPED, TAP TO REMOVE, every locked
             item's LV n (tracks, themes, fonts, the side slots), the footer, prices' small print
     10.5px  only the HUD's box labels (SCORE, CHAIN...), which shrink to fit
     9px     only how far those HUD labels may shrink (--label-min); past it, they wrap
   Text with no size of its own in the cards' pages, notes, the tutorial and the game-over box
   takes 1.3x what it inherits (see :where(...) { font-size: 1.3em } further down).
   Sections in a card are parted by ===== lines (.store-rule, or a ::before/::after like it),
   never dashes. Fonts are sized to Courier's metrics (js/fonts.js), so these hold in any font.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
/* FONTS: COURIER (the default) and five unlockable fonts, bundled in assets/fonts/ (SIL OFL) and
   set up by js/fonts.js, which fits each to Courier's line height and capital height so switching
   fonts moves and resizes nothing. [data-font] on <html> picks one; everything reads var(--font). */
/* NO SCROLLBARS anywhere: menus, cards and lists still scroll (touch, wheel, keys), with no bar showing */
* { scrollbar-width: none; }
*::-webkit-scrollbar { display: none; }
/* The smallest a HUD label may shrink to and stay readable (script.js's fitStatValues; past it,
   labels wrap) */
:root { --label-min: 9; }
/* Courier's line height in every font (js/fonts.js sets --line); buttons and fields too (the
   browser's own style gives them "normal", which is the font's) */
html { line-height: var(--line, normal); }
button, input, select, textarea { line-height: inherit; }
:root { --font: 'Courier New', Courier, monospace; }
:root[data-font="share-tech"] { --font: 'Share Tech Mono', 'Courier New', monospace; }
:root[data-font="press-start"] { --font: 'Press Start 2P', 'Courier New', monospace; }
:root[data-font="bitcount"] { --font: 'Bitcount Single', 'Courier New', monospace; }
:root[data-font="bytesized"] { --font: 'Bytesized', 'Courier New', monospace; }
:root[data-font="orbitron"] { --font: 'Orbitron', 'Courier New', monospace; }
/* The font picker shows each name in its own font */
[data-font-preview="courier"] { font-family: 'Courier New', Courier, monospace !important; }
[data-font-preview="share-tech"] { font-family: 'Share Tech Mono', 'Courier New', monospace !important; }
[data-font-preview="press-start"] { font-family: 'Press Start 2P', 'Courier New', monospace !important; }
[data-font-preview="bitcount"] { font-family: 'Bitcount Single', 'Courier New', monospace !important; }
[data-font-preview="bytesized"] { font-family: 'Bytesized', 'Courier New', monospace !important; }
[data-font-preview="orbitron"] { font-family: 'Orbitron', 'Courier New', monospace !important; }

/* [data-theme] also works on any element, so the settings panel's theme swatches preview each theme. */
:root,
[data-theme="terminal"] {
  /* Every color is a role, so a theme ([data-theme] on <html>) only swaps these values.
     *-rgb triplets feed rgba() alphas, and fx.js, viz.js and grid-bg.js read them too. */
  --bg: #050a08;
  --bg-solid: #020403; /* flat match for the gradient's edge; also the meta theme-color */
  --bg-center: #0d1b16;
  --panel: #0b1512;
  --panel-text: #b9f3d3;
  --popup-bg: #06110d;
  --overlay-bg: #0b0b0b;
  --grid-line: #1c3d33;
  --board-bg: #01120a;
  --cell-bg: #06140d;
  --fg: #39ff8f; /* terminal text and bits */
  --fg-rgb: 57, 255, 143;
  --fg-dim: #1f7a52;
  --accent: #ffd166; /* exploits, warnings, cracked layers */
  --accent-rgb: 255, 209, 102;
  --cracked: var(--accent); /* cracked layers; SPECTRUM keeps them still */
  /* The RESOURCES' own colors, the same in every theme (PAPER darker, MONOCHROME in grays); KEYS take the accent */
  --res-bugs: #b5824a; /* roach brown */
  --res-cache: #c8ccd0; /* light gray */
  --res-crypto: #f7931a; /* Bitcoin orange */
  --res-rootkits: #ff3b4e; /* red */
  --res-master: #e8b10e; /* deep gold, with a glow */
  --res-master-glow: rgba(232, 177, 14, 0.7);
  --afford: #3ddc84; /* a price's amount you have enough of (red, --danger, where you're short) */
  /* Icons drawn in CSS (as masks, so they take the text color): no emoji anywhere */
  --icon-lock: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'><rect x='5' y='11' width='14' height='10' rx='2'/><path d='M8 11V7a4 4 0 0 1 8 0v4'/></svg>");
  --icon-play: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 4 L19 12 L7 20 Z' fill='black'/></svg>");
  --inset-bg: rgba(0, 0, 0, 0.35); /* HUD boxes, visualizer */
  --danger: #ff4d5e; /* the trace: overflow and game over */
  --danger-rgb: 255, 77, 94;
  --layer-a: #2a2a2a; /* encryption layer stripes */
  --layer-b: #1a1a1a;
  --layer-border: #777;
  --layer-text: #999;
  --layer-rgb: 175, 175, 175;
  --exploit-bg: #1a1405;
  --alarm-text: #fff4cf;
  --byte-text: #d9ffe9;
  --hot-rgb: 120, 255, 180; /* meltdown glow */
  --burst-hot-rgb: 170, 255, 205;
  --heat-text: #9dffc6;
  --heat-bg: #0c2a1b;
  --heat-peak-border: #d9ffe9;
  --heat-peak-text: #f0fff6;
  --heat-peak-bg: #14482d;
}

/* CIPHER: cyan bits, magenta encryption layers that crack to yellow */
[data-theme="cipher"] {
  --bg: #04080b;
  --bg-solid: #020306;
  --bg-center: #0b1520;
  --panel: #0a121a;
  --panel-text: #bfeef8;
  --popup-bg: #07111a;
  --overlay-bg: #0a0a0d;
  --grid-line: #173946;
  --board-bg: #01101a;
  --cell-bg: #051420;
  --fg: #3fe6ff;
  --fg-rgb: 63, 230, 255;
  --fg-dim: #1e7489;
  --accent: #ffe14d;
  --accent-rgb: 255, 225, 77;
  --danger: #ff5a36;
  --danger-rgb: 255, 90, 54;
  --layer-a: #3a0f38;
  --layer-b: #230a22;
  --layer-border: #ff4fd8;
  --layer-text: #ff8ae6;
  --layer-rgb: 255, 79, 216;
  --exploit-bg: #1a1705;
  --alarm-text: #fff8cc;
  --byte-text: #dcfaff;
  --hot-rgb: 130, 235, 255;
  --burst-hot-rgb: 175, 240, 255;
  --heat-text: #9ff0ff;
  --heat-bg: #0b2530;
  --heat-peak-border: #dcfaff;
  --heat-peak-text: #f0fdff;
  --heat-peak-bg: #124656;
}

/* AMBER CRT: an old amber monitor, gray layers, cyan for cracks and exploits (the amber's opposite) */
[data-theme="amber-crt"] {
  --bg: #0a0703;
  --bg-solid: #040301;
  --bg-center: #1a1206;
  --panel: #140e05;
  --panel-text: #f5deb0;
  --popup-bg: #120c04;
  --overlay-bg: #0d0a05;
  --grid-line: #3d2c10;
  --board-bg: #120b02;
  --cell-bg: #1a1003;
  --fg: #ffc33d; /* (a yellower amber than the old #ffb000) */
  --fg-rgb: 255, 195, 61;
  --fg-dim: #8f6a1c;
  --accent: #4fe3e0; /* (cyan: the amber's opposite, standing apart from it and from the danger red) */
  --accent-rgb: 79, 227, 224;
  --danger: #ff4d3d;
  --danger-rgb: 255, 77, 61;
  --layer-a: #2a2a2a;
  --layer-b: #1a1a1a;
  --layer-border: #777;
  --layer-text: #999;
  --layer-rgb: 175, 175, 175;
  --exploit-bg: #0e1c1c;
  --alarm-text: #ffffff;
  --byte-text: #fff1cc;
  --hot-rgb: 255, 200, 90;
  --burst-hot-rgb: 255, 215, 140;
  --heat-text: #ffd27a;
  --heat-bg: #2e1f05;
  --heat-peak-border: #fff1cc;
  --heat-peak-text: #fffaf0;
  --heat-peak-bg: #5a3a08;
}

/* MONOCHROME: black and white; layers told apart by their stripes and dashed borders */
[data-theme="monochrome"] {
  --afford: #ffffff;
  --res-bugs: #8c8c8c;
  --res-cache: #d6d6d6;
  --res-crypto: #b0b0b0;
  --res-rootkits: #ffffff;
  --res-master: #ffffff;
  --res-master-glow: rgba(255, 255, 255, 0.6);
  --bg: #070707;
  --bg-solid: #030303;
  --bg-center: #151515;
  --panel: #0f0f0f;
  --panel-text: #d0d0d0;
  --popup-bg: #0c0c0c;
  --overlay-bg: #0a0a0a;
  --grid-line: #2e2e2e;
  --board-bg: #080808;
  --cell-bg: #121212;
  --fg: #dcdcdc;
  --fg-rgb: 220, 220, 220;
  --fg-dim: #6e6e6e;
  --accent: #ffffff;
  --accent-rgb: 255, 255, 255;
  --danger: #ffffff;
  --danger-rgb: 255, 255, 255;
  --layer-a: #2c2c2c;
  --layer-b: #0c0c0c;
  --layer-border: #8a8a8a;
  --layer-text: #9a9a9a;
  --layer-rgb: 150, 150, 150;
  --exploit-bg: #262626;
  --alarm-text: #ffffff;
  --byte-text: #ffffff;
  --hot-rgb: 230, 230, 230;
  --burst-hot-rgb: 240, 240, 240;
  --heat-text: #f0f0f0;
  --heat-bg: #262626;
  --heat-peak-border: #ffffff;
  --heat-peak-text: #ffffff;
  --heat-peak-bg: #4a4a4a;
}

/* ANAGLYPH: red/cyan 3D glasses. Off-white bits and titles with a red fringe on the left and a
   cyan one on the right; layers in the red lens, cracks in the cyan one, a bright red trace */
[data-theme="anaglyph"] {
  --bg: #07080a;
  --bg-solid: #030405;
  --bg-center: #101318;
  --panel: #0c0e11;
  --panel-text: #c9d1d8;
  --popup-bg: #0b0d10;
  --overlay-bg: #08090b;
  --grid-line: #262c33;
  --board-bg: #08090c;
  --cell-bg: #121519;
  --fg: #eef3f7;
  --fg-rgb: 238, 243, 247;
  --fg-dim: #76828d;
  --accent: #29dcff;
  --accent-rgb: 41, 220, 255;
  --danger: #ff2e56;
  --danger-rgb: 255, 46, 86;
  --layer-a: #2a0c14;
  --layer-b: #19070c;
  --layer-border: #c23a57;
  --layer-text: #ff7d96;
  --layer-rgb: 194, 58, 87;
  --exploit-bg: #0a1d24;
  --alarm-text: #eaffff;
  --byte-text: #e8fbff;
  --hot-rgb: 255, 110, 140;
  --burst-hot-rgb: 140, 235, 255;
  --heat-text: #ff9db0;
  --heat-bg: #2e0b13;
  --heat-peak-border: #eaffff;
  --heat-peak-text: #ffffff;
  --heat-peak-bg: #104552;
  --ana-l: rgba(255, 40, 80, 0.8);
  --ana-r: rgba(0, 220, 255, 0.8);
}
/* The 3D-glasses fringes: text and edges split into a red left and a cyan right */
[data-theme="anaglyph"] h1,
[data-theme="anaglyph"] h1 span,
[data-theme="anaglyph"] .cell.disc,
[data-theme="anaglyph"] .hud .stat .value,
[data-theme="anaglyph"] #current-piece,
[data-theme="anaglyph"] .bit-sq,
[data-theme="anaglyph"] .cpu-grid i.bit,
[data-theme="anaglyph"] .overlay-box h2 {
  text-shadow: -1.5px 0 var(--ana-l), 1.5px 0 var(--ana-r);
}
[data-theme="anaglyph"] .cell.disc { box-shadow: -1.5px 0 0 var(--ana-l), 1.5px 0 0 var(--ana-r); }
[data-theme="anaglyph"] .cell .glyph { filter: drop-shadow(-1.5px 0 var(--ana-l)) drop-shadow(1.5px 0 var(--ana-r)); }

/* SYNTHWAVE: pink bits, purple layers, orange cracks and a cyan trace */
[data-theme="synthwave"] {
  --bg: #0a0410;
  --bg-solid: #040108;
  --bg-center: #1c0a2c;
  --panel: #140a1f;
  --panel-text: #f3c6ec;
  --popup-bg: #12081c;
  --overlay-bg: #0d0614;
  --grid-line: #3d1a55;
  --board-bg: #0e0418;
  --cell-bg: #170826;
  --fg: #ff5fd2;
  --fg-rgb: 255, 95, 210;
  --fg-dim: #8a2f78;
  --accent: #ffa53a;
  --accent-rgb: 255, 165, 58;
  --danger: #3fe6ff;
  --danger-rgb: 63, 230, 255;
  --layer-a: #2b1650;
  --layer-b: #1a0c33;
  --layer-border: #9d6bff;
  --layer-text: #c0a0ff;
  --layer-rgb: 157, 107, 255;
  --exploit-bg: #221306;
  --alarm-text: #fff0dc;
  --byte-text: #ffe0f6;
  --hot-rgb: 255, 140, 225;
  --burst-hot-rgb: 255, 180, 235;
  --heat-text: #ff9fe4;
  --heat-bg: #3a0f33;
  --heat-peak-border: #ffe0f6;
  --heat-peak-text: #fff5fc;
  --heat-peak-bg: #6a1a5c;
}

/* DOT MATRIX: four shades of olive green, like an old handheld game screen */
[data-theme="dot-matrix"] {
  --bg: #0f1f0f;
  --bg-solid: #081208;
  --bg-center: #1b331a;
  --panel: #132613;
  --panel-text: #b8cf7a;
  --popup-bg: #102210;
  --overlay-bg: #0c180c;
  --grid-line: #2d4f22;
  --board-bg: #0b1a0b;
  --cell-bg: #16301a;
  --fg: #9bbc0f;
  --fg-rgb: 155, 188, 15;
  --fg-dim: #4f7a1f;
  --accent: #e0f0a8;
  --accent-rgb: 224, 240, 168;
  --danger: #ff6b4a;
  --danger-rgb: 255, 107, 74;
  --layer-a: #24421f;
  --layer-b: #162b14;
  --layer-border: #6b8f2a;
  --layer-text: #8bac0f;
  --layer-rgb: 139, 172, 15;
  --exploit-bg: #26301a;
  --alarm-text: #f4ffd0;
  --byte-text: #e8f8c0;
  --hot-rgb: 190, 220, 90;
  --burst-hot-rgb: 210, 235, 140;
  --heat-text: #cfe88a;
  --heat-bg: #2a4a18;
  --heat-peak-border: #f4ffd0;
  --heat-peak-text: #fbffe8;
  --heat-peak-bg: #4d7a1c;
}

/* PAPER: dark ink on pale paper, for bright rooms and outdoors */
[data-theme="paper"] {
  --afford: #1a7f3c;
  --res-bugs: #7a4f22;
  --res-cache: #111111;
  --res-crypto: #c26a00;
  --res-rootkits: #c4142a;
  --res-master: #a67c00;
  --res-master-glow: rgba(166, 124, 0, 0.35);
  --inset-bg: rgba(90, 70, 30, 0.06);
  --bg: #efeadf;
  --bg-solid: #e9e3d6;
  --bg-center: #f7f3ea;
  --panel: #faf7f0;
  --panel-text: #3a3f37;
  --popup-bg: #fbf8f1;
  --overlay-bg: #faf7f0;
  --grid-line: #d3cbb8;
  --board-bg: #ebe5d7;
  --cell-bg: #fffdf7;
  --fg: #1b1d1c; /* near-black ink */
  --fg-rgb: 27, 29, 28;
  --fg-dim: #6a6a68; /* gray */
  --accent: #a35f00;
  --accent-rgb: 163, 95, 0;
  --danger: #c62828;
  --danger-rgb: 198, 40, 40;
  --layer-a: #d6d6d4;
  --layer-b: #c3c3c1;
  --layer-border: #7c7c7a;
  --layer-text: #4a4a48;
  --layer-rgb: 115, 115, 112;
  --exploit-bg: #fbefd6;
  --alarm-text: #6e3f00;
  --byte-text: #111312;
  --hot-rgb: 80, 82, 80;
  --burst-hot-rgb: 40, 42, 40;
  --heat-text: #111312;
  --heat-bg: #dcdcda;
  --heat-peak-border: #111312;
  --heat-peak-text: #000000;
  --heat-peak-bg: #bdbdbb;
}

/* Glows smudge on paper: PAPER's text stays crisp */
[data-theme="paper"] * { text-shadow: none !important; }
/* PAPER: the chosen mode (and daily game / CPU level) is filled in ink; the rest get a firmer outline */
[data-theme="paper"] .modes button { border-color: var(--layer-border); color: var(--panel-text); }
[data-theme="paper"] .modes button.active { background: var(--fg); border: 2px solid var(--fg); color: var(--panel); font-weight: bold; box-shadow: none; }

/* GLYPH: bits drawn as shapes, one corner per point of their number, on blueprint blue */
[data-theme="glyph"] {
  --bg: #06101f;
  --bg-solid: #030a15;
  --bg-center: #0d1f3a;
  --panel: #0a1830;
  --panel-text: #cfe0ff;
  --popup-bg: #081528;
  --overlay-bg: #070f1c;
  --grid-line: #1d3a63;
  --board-bg: #051024;
  --cell-bg: #0a1a33;
  --fg: #d8e8ff;
  --fg-rgb: 216, 232, 255;
  --fg-dim: #5b7cad;
  --accent: #ffc857;
  --accent-rgb: 255, 200, 87;
  --danger: #ff5a5a;
  --danger-rgb: 255, 90, 90;
  --layer-a: #1c2b44;
  --layer-b: #121d30;
  --layer-border: #6f86ab;
  --layer-text: #93a8c9;
  --layer-rgb: 147, 168, 201;
  --exploit-bg: #1f1a0a;
  --alarm-text: #fff6dc;
  --byte-text: #eef5ff;
  --hot-rgb: 170, 205, 255;
  --burst-hot-rgb: 200, 222, 255;
  --heat-text: #bcd6ff;
  --heat-bg: #123058;
  --heat-peak-border: #eef5ff;
  --heat-peak-text: #ffffff;
  --heat-peak-bg: #1e4a86;
}

/* SPECTRUM: every bit cycles through the rainbow on its own; the page drifts slowly behind them */
[data-theme="spectrum"] {
  --bg: #07070a;
  --bg-solid: #030305;
  --bg-center: #15151c;
  --panel: #0e0e14;
  --panel-text: #e6e6f0;
  --popup-bg: #0c0c12;
  --overlay-bg: #0a0a0e;
  --grid-line: #2a2a38;
  --board-bg: #08080c;
  --cell-bg: #101018;
  --fg: #ff4d6d;
  --fg-rgb: 255, 77, 109;
  --fg-dim: #8a3a52;
  --accent: #ffd166;
  --accent-rgb: 255, 209, 102;
  --danger: #ff4d5e;
  --danger-rgb: 255, 77, 94;
  --layer-a: #2a2a2a;
  --layer-b: #1a1a1a;
  --layer-border: #6e6e6e;
  --layer-text: #8e8e8e;
  --layer-rgb: 170, 170, 170;
  --exploit-bg: #1a1405;
  --alarm-text: #fff4cf;
  --byte-text: #ffe0ea;
  --hot-rgb: 255, 150, 180;
  --burst-hot-rgb: 255, 190, 210;
  --heat-text: #ffb0c4;
  --heat-bg: #301018;
  --heat-peak-border: #ffe0ea;
  --heat-peak-text: #fff5f8;
  --heat-peak-bg: #5a1a2c;
  --cracked: #e4e4e4; /* layers stay still: gray, and near-white once cracked */
}

* { box-sizing: border-box; }

/* Buttons use the game's font (the chosen one), not the browser's own button font */
button { font-family: inherit; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: radial-gradient(ellipse at center, var(--bg-center) 0%, var(--bg-solid) 100%);
  /* Android Chrome samples the page's bottom edge for the system nav bar; a gradient reads as white */
  background-color: var(--bg-solid);
  font-family: var(--font);
  color: var(--fg);
}

/* THE GAME: no card around it (the phone's own edges are its frame); everything sits 8px in from the
   screen's edges. (The game in a bordered card, as it was before: commit 318ba34) */
.crt {
  position: relative;
  padding: 8px 8px 32px;
  max-width: 480px;
  width: 100%;
}

header { text-align: center; margin-bottom: 12px; }

h1 {
  margin: 0;
  letter-spacing: 4px;
  font-size: 28px;
  text-shadow: 0 0 8px var(--fg);
}

h1 span { color: var(--accent); text-shadow: 0 0 8px var(--accent); }

.tagline {
  margin: 4px 0 0;
  font-size: 11px;
  color: var(--fg-dim);
  letter-spacing: 2px;
}

.hud {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin: 16px 0;
  flex-wrap: wrap;
}

.stat {
  flex: 1;
  min-width: 72px;
  display: flex;
  flex-direction: column;
  justify-content: space-between; /* the label at the top, the value (or bit) at the bottom */
  text-align: center;
  position: relative;
  isolation: isolate; /* the starlight canvas (.stat-bg) sits under the text */
  background: var(--board-bg);
  border: 1px solid var(--grid-line);
  border-radius: 6px;
  padding: 6px 4px;
}
.stat-bg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; border-radius: 5px; pointer-events: none; }
.cpu-stat { background: var(--inset-bg); }

.stat .label {
  display: block;
  line-height: 1.15;
  font-size: 9px;
  color: var(--fg-dim);
  letter-spacing: 1px;
}
/* The HUD's labels (SCORE ... CURRENT): brighter than the other dim text, to read at a glance */
.hud .stat .label { color: rgba(var(--fg-rgb), 0.85); }

.stat .value {
  display: block;
  line-height: 1;
  white-space: nowrap;
  font-size: 18px;
  font-weight: bold;
  margin-top: 2px;
}

/* CURRENT and NEXT: one unit that wraps together; CURRENT gets the most room */
.hud-bits { display: flex; gap: 8px; flex: 1 1 72px; }
.hud-bits.has-next { flex: 2 1 176px; }
.hud-bits .stat { flex: 1 1 0; min-width: 0; }
.hud-bits .stat-current { flex-grow: 1.4; }

/* Bits in the HUD are square frames, drawn like the board's cells */
.bit-sq {
  position: relative;
  width: 40px;
  height: 40px;
  margin: 4px auto 0;
  border-radius: 3px;
  border: 1px solid var(--fg);
  background: var(--cell-bg);
  color: var(--fg);
  text-shadow: 0 0 6px rgba(var(--fg-rgb), 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font);
  font-weight: bold;
  font-size: 16px;
}
.bit-row { display: flex; justify-content: center; gap: 4px; }
.bit-row .bit-sq { margin: 4px 0 0; } /* NEXT: in full color, as CURRENT */
.stat.keylogger .bit-row .bit-sq { width: 30px; height: 30px; font-size: 13px; }

.board-wrap {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 424px;
  margin: 0 auto;
}

/* The drop buttons sit under the grid by default; the settings panel can move them above it. */
.board-wrap.buttons-top .column-buttons { order: -1; margin: 0 0 4px; }

.column-buttons {
  display: grid;
  grid-template-columns: repeat(var(--cols, 7), 1fr);
  gap: 3px;
  padding: 0 14px; /* (under the columns: the board's side margin, 13px, and its frame's 1px border) */
  margin-top: 4px;
}

.column-buttons button {
  min-width: 0;
  height: 28px;
  background: rgba(var(--fg-rgb), 0.08);
  border: 1px solid var(--fg-dim);
  color: var(--fg);
  font-family: inherit;
  cursor: pointer;
  border-radius: 4px;
  transition: background 0.15s, transform 0.1s;
}

@media (hover: hover) { .column-buttons button:hover:not(:disabled) {
  background: rgba(var(--fg-rgb), 0.25);
  transform: translateY(-2px);
} }

/* PIVOT: the picked column and the two neighbors it can swap with */
.column-buttons button.pivot-from { border-color: var(--accent); color: var(--accent); }
.column-buttons button.pivot-target {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(var(--accent-rgb), 0.15);
  animation: warn-pulse 1s ease-in-out infinite;
}
/* ...and their columns on the grid: the picked one outlined, the two it can swap with glowing and pulsing */
.cell.pivot-col-from { box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.75); }
.cell.pivot-col-target { box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 10px rgba(var(--accent-rgb), 0.45), 0 0 6px rgba(var(--accent-rgb), 0.35); background-color: rgba(var(--accent-rgb), 0.08); animation: warn-pulse 1s ease-in-out infinite; }

.column-buttons button:disabled {
  opacity: 0.25;
  cursor: not-allowed;
}

.board {
  display: grid;
  grid-template-columns: repeat(var(--cols, 7), 1fr);
  gap: 3px;
  position: relative;
  padding: 6px;
}

/* THE CHAIN METER (script.js): a segmented bar up each side of the grid, in the frame's margin;
   lit segment by segment as a chain grows, the whole bar lit and pulsing while an exploit is ready */
/* (the grid gets a wider margin at the sides for it: the bar, then the same 3px gap as between the
   squares; it runs from the top row down to the bottom of row 1, script.js placing it, and the
   ===== line under the board runs on under it) */
#board, #cpu-full { padding-left: 13px; padding-right: 13px; }
/* VS on points: THE SCORE BAR above the grid (script.js), in a taller top margin: the bar, then the
   same 3px gap. Yours fills in your color, the CPU's in its amber; the | marks the middle (or,
   in TUG OF WAR, where the points stand) */
.board-frame.with-vs-bar #board { padding-top: 13px; }
.vs-bar { position: absolute; left: 13px; right: 13px; top: 6px; height: 4px; border-radius: 2px; background: rgba(var(--fg-rgb), 0.12); z-index: 2; pointer-events: none; }
.vs-bar[hidden] { display: none; }
.vs-bar i { position: absolute; top: 0; bottom: 0; transition: width 0.3s, left 0.3s; }
.vs-bar .mine { background: var(--fg); box-shadow: 0 0 6px var(--fg); }
.vs-bar .theirs { background: var(--accent); box-shadow: 0 0 6px var(--accent); }
.vs-bar .mark { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--panel-text, #fff); box-shadow: 0 0 4px rgba(255, 255, 255, 0.7); transition: left 0.3s; }
:is(#board, #cpu-full) :is(.layer-line, .overflow-line) { margin-left: -7px; margin-right: -7px; }
.chain-meter { position: absolute; top: 6px; bottom: 6px; width: 4px; z-index: 2; display: flex; flex-direction: column-reverse; gap: 3px; pointer-events: none; }
.chain-meter.left { left: 6px; }
.chain-meter.right { right: 6px; }
.chain-meter[hidden] { display: none; }
.chain-meter i { position: relative; flex: 1; border-radius: 1px; background: rgba(var(--fg-rgb), 0.12); overflow: hidden; transition: box-shadow var(--fill-ms, 0.25s) linear var(--fill-delay, 0s); }
/* (each segment fills from the bottom by its share of the charge: a draining one shows part lit;
   lighting and going dark ease over 0.25s, HARD's drain steadily) */
.chain-meter i::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: calc(var(--fill, 0) * 100%); background: var(--fg); box-shadow: 0 0 6px var(--fg); transition: height var(--fill-ms, 0.25s) linear var(--fill-delay, 0s); }
.chain-meter i.lit { box-shadow: 0 0 5px rgba(var(--fg-rgb), 0.5); }
.chain-meter i.waiting::before { content: ''; position: absolute; inset: 0; background: var(--accent); box-shadow: 0 0 8px var(--accent); animation: chain-ready 1.1s ease-in-out infinite; }
@keyframes chain-ready { 50% { opacity: 0.35; } } /* (opacity only: the bar clips the glow anyway) */
.board-frame {
  position: relative;
  background: var(--board-bg);
  border: 1px solid var(--grid-line);
  border-radius: 6px;
  overflow: hidden;
}

/* Page-wide particle layer so bursts aren't clipped (board cells, the warning text) */
#board-fx {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 30;
  pointer-events: none;
}

#board-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.cell {
  aspect-ratio: 1;
  min-width: 0;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font);
  font-size: clamp(11px, 3.6vw, 18px);
  font-weight: bold;
  white-space: nowrap;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--grid-line);
  transition: transform 0.12s ease, opacity 0.2s ease;
}

.byte-grid .cell { font-size: clamp(10px, 3.2vw, 17px); }

.cell.disc {
  background: var(--cell-bg);
  border: 1px solid var(--fg);
  color: var(--fg);
  text-shadow: 0 0 6px rgba(var(--fg-rgb), 0.6);
}

.cell.firewall {
  background: repeating-linear-gradient(45deg, var(--layer-a), var(--layer-a) 4px, var(--layer-b) 4px, var(--layer-b) 8px);
  border: 1px dashed var(--layer-border);
  color: var(--layer-text);
}

.cell.firewall.cracked {
  border-color: var(--cracked);
  color: var(--cracked);
}

/* GLYPH: a bit is a shape with one corner per point of its number, plus a small number */
.cell .glyph,
.bit-sq .glyph { display: block; width: 72%; height: 72%; overflow: visible; }
.glyph path,
.glyph polygon { fill: rgba(var(--fg-rgb), 0.14); stroke: currentColor; stroke-width: 7; stroke-linejoin: round; }
.cell.disc.has-glyph { position: relative; }
.glyph-num {
  position: absolute;
  right: 3px;
  bottom: 1px;
  font-size: 9px;
  line-height: 1;
  opacity: 0.7;
}

/* SPECTRUM: each bit cycles hue on its own (random speed, start and direction, set per bit
   by script.js); the rest of the page drifts slowly through the hues together. Gray and
   white (the layers) are untouched by hue-rotate, so they stay still. */
@property --bit-h {
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}
@keyframes bit-hue { from { --bit-h: 0; } to { --bit-h: 360; } }
@keyframes page-hue { from { filter: hue-rotate(0deg); } to { filter: hue-rotate(360deg); } }

[data-theme="spectrum"] .cell.disc {
  color: hsl(var(--bit-h) 100% 64%);
  border-color: hsl(var(--bit-h) 100% 64%);
  text-shadow: 0 0 6px hsl(var(--bit-h) 100% 64% / 0.6);
  animation: bit-hue var(--spin, 6s) linear var(--spin-delay, 0s) infinite var(--spin-dir, normal);
}
/* (the page's drift starts at a random point, not always on the palette's own red: --page-hue-at, a
   random part of its cycle, set before the first paint and again on each switch to SPECTRUM; the
   title screen drifts with the rest) */
[data-theme="spectrum"] .cabinet,
[data-theme="spectrum"] footer,
[data-theme="spectrum"] .start-screen,
[data-theme="spectrum"] .music-player :is(.mp-head, .mp-scroll > :not(.mp-viz)) { animation: page-hue 48s linear var(--page-hue-at, 0s) infinite; }
[data-theme="spectrum"] .cell.pop { animation: pop-out 0.16s ease-out forwards; }

@media (prefers-reduced-motion: reduce) {
  [data-theme="spectrum"] .cell.disc,
  [data-theme="spectrum"] .cabinet,
  [data-theme="spectrum"] footer,
  [data-theme="spectrum"] .start-screen,
  [data-theme="spectrum"] .music-player :is(.mp-head, .mp-scroll > :not(.mp-viz)) { animation: none; }
  /* (held still on a random hue instead, the same one --page-hue-at would start from) */
  [data-theme="spectrum"] :is(.cabinet, footer, .start-screen, .music-player :is(.mp-head, .mp-scroll > :not(.mp-viz))) { filter: hue-rotate(var(--page-hue-deg, 0deg)); }
}

.cell.overflow {
  background: rgba(var(--danger-rgb), 0.04);
  border-color: rgba(var(--danger-rgb), 0.2);
}

.cell.overflow.disc,
.cell.overflow.firewall {
  border-color: var(--danger);
  color: var(--danger);
  text-shadow: 0 0 6px rgba(var(--danger-rgb), 0.6);
}

.overflow-line {
  grid-column: 1 / -1;
  overflow: hidden;
  white-space: nowrap;
  text-align: center;
  font-size: 12px;
  line-height: 12px;
  letter-spacing: 2px;
  color: var(--danger);
  opacity: 0.8;
}

.cell.pop {
  animation: pop-out 0.16s ease-out forwards;
}

@keyframes pop-out {
  0% { opacity: 1; filter: brightness(2.2); }
  100% { opacity: 0; transform: scale(0.9); filter: brightness(1); }
}

.cell.landed {
  animation: land 0.15s ease;
}

@keyframes land {
  0% { transform: translateY(-8px) scale(0.9); }
  100% { transform: translateY(0) scale(1); }
}

.message {
  text-align: center;
  font-size: 14px;
  color: var(--accent);
  margin-top: 10px;
  min-height: 18px;
  text-shadow: 0 0 6px var(--accent);
}

.message.hidden { visibility: hidden; }

.message.warn { animation: warn-pulse 1s ease-in-out infinite; }

/* (opacity only: an animated glow repaints every frame; the element's own glow fades with it) */
@keyframes warn-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

.message.alarm {
  color: var(--alarm-text);
  letter-spacing: 1px;
  text-shadow: 0 0 10px var(--accent), 0 0 22px rgba(var(--accent-rgb), 0.8);
  animation: alarm-in 0.25s ease-out;
}

@keyframes alarm-in { from { opacity: 0.4; } to { opacity: 1; } }

/* Hard: BYTE CLEARED bonus */
.message.byte {
  color: var(--byte-text);
  letter-spacing: 2px;
  text-shadow: 0 0 10px var(--fg), 0 0 22px rgba(var(--fg-rgb), 0.8);
  animation: byte-in 0.35s ease-out;
}

@keyframes byte-in {
  from { opacity: 0.3; transform: scale(1.25); }
  to { opacity: 1; transform: scale(1); }
}

.stat.danger {
  border-color: var(--accent);
  animation: stat-danger 1s ease-in-out infinite;
}

.stat.danger .value { color: var(--accent); }

@keyframes stat-danger {
  0%, 100% { box-shadow: none; }
  50% { box-shadow: 0 0 12px rgba(var(--accent-rgb), 0.55); }
}

.overflow-line.hot { animation: line-hot 0.9s ease-in-out infinite; }
/* The ==== line under the board: full brightness, flashing amber when the next drop brings a layer */
.layer-line { grid-column: 1 / -1; overflow: hidden; white-space: nowrap; text-align: center; font-size: 12px; line-height: 12px; letter-spacing: 2px; color: var(--fg); }
/* ENCRYPT IN's =====: the layer it counts down to, as bright as the line under the board, flashing
   with it when the next drop brings one */
.stat .layer-mark { display: none; font-size: 9px; line-height: 1; letter-spacing: 1px; margin-top: 3px; color: var(--fg); }
#pulse-stat.counts-layers .layer-mark { display: block; }
.hud #pulse-stat > .layer-mark { position: absolute; left: 0; right: 0; top: calc(50% + 11px); margin: 0; }
body.vs-mode .hud #pulse-stat > .layer-mark { top: auto; bottom: 7px; } /* (VS: its number sits lower in the square) */
#pulse-stat.layer-next .layer-mark { color: var(--accent); opacity: 1; text-shadow: 0 0 6px var(--accent); animation: warn-pulse 0.6s ease-in-out infinite; }
.layer-line.next { color: var(--accent); opacity: 1; text-shadow: 0 0 6px var(--accent); animation: warn-pulse 0.6s ease-in-out infinite; }
.cpu-grid i.under-edge { border-bottom: 2px solid rgba(var(--fg-rgb), 0.3); }
.cpu-grid.layer-next i.under-edge { border-bottom-color: var(--accent); animation: warn-pulse 0.6s ease-in-out infinite; }
/* VS: the CPU's score, bright amber */
.cpu-score { color: var(--accent); font-weight: bold; text-shadow: 0 0 6px var(--accent); }

@keyframes line-hot {
  0%, 100% { opacity: 0.6; text-shadow: 0 0 2px rgba(var(--danger-rgb), 0.5); }
  50% { opacity: 1; text-shadow: 0 0 6px var(--danger), 0 0 14px rgba(var(--danger-rgb), 0.9); }
}

/* Game-over meltdown: pieces shake and glow hotter and hotter green before bursting */
.board.meltdown .cell.disc,
.board.meltdown .cell.firewall,
.board.meltdown .cell.hack {
  animation: jitter 0.08s steps(2) infinite, heat 0.9s ease-in forwards;
}

@keyframes jitter {
  0% { transform: translate(-1px, 0.5px); }
  50% { transform: translate(1px, -0.5px); }
  100% { transform: translate(-0.5px, -1px); }
}

@keyframes heat {
  35% {
    border-color: var(--fg);
    color: var(--heat-text);
    background-color: var(--heat-bg);
    box-shadow: 0 0 6px rgba(var(--fg-rgb), 0.5);
  }
  100% {
    border-color: var(--heat-peak-border);
    color: var(--heat-peak-text);
    background-color: var(--heat-peak-bg);
    text-shadow: 0 0 8px var(--fg);
    box-shadow: 0 0 14px rgba(var(--fg-rgb), 0.95), inset 0 0 10px rgba(var(--hot-rgb), 0.6);
  }
}

@media (prefers-reduced-motion: reduce) {
  .board.meltdown .cell.disc,
  .board.meltdown .cell.firewall,
  .board.meltdown .cell.hack { animation: heat 0.9s ease-in forwards; }
}

.controls { text-align: center; margin-top: 14px; }

#restart-btn, #overlay-restart-btn, .overlay-replay-btn {
  background: transparent;
  border: 1px solid var(--fg);
  color: var(--fg);
  font-family: inherit;
  padding: 8px 18px;
  border-radius: 4px;
  cursor: pointer;
  letter-spacing: 1px;
}

.free-exploit-btn {
  margin-left: 8px;
  background: rgba(var(--accent-rgb), 0.08);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: inherit;
  padding: 8px 14px;
  border-radius: 4px;
  cursor: pointer;
  letter-spacing: 1px;
  text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6);
  animation: warn-pulse 1.6s ease-in-out infinite;
}
.free-exploit-btn[hidden] { display: none; }
.free-exploit-btn:disabled { animation: none; opacity: 0.4; cursor: default; }
#vibrate-btn { margin-top: 6px; }
.rec-reset { margin-top: 14px; width: 100%; padding: 6px; background: none; border: 1px solid var(--grid-line); border-radius: 4px; color: var(--fg-dim); font-family: inherit; font-size: 14.5px; letter-spacing: 1px; cursor: pointer; }

.overlay-replay-btn { margin-left: 18px; } /* (as SHARE) */
.overlay-replay-btn[hidden] { display: none; }
@media (hover: hover) { #restart-btn:hover, #overlay-restart-btn:hover, .overlay-replay-btn:hover {
  background: rgba(var(--fg-rgb), 0.15);
} }



.stat .sub {
  display: block;
  margin-top: 2px;
  font-size: 9px;
  color: var(--fg-dim);
  letter-spacing: 1px;
}

.stat .sub span { color: var(--accent); }
/* BEST: its own box, the number in the accent color (not in VS) */
.stat-best .value { color: var(--accent); }
body.vs-mode .stat-best { display: none; }

.stat[hidden] { display: none; }

.bit-sq.hack,
.cell.hack {
  border-color: var(--accent);
  color: var(--accent);
  text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6);
}

.cell.hack { background: var(--exploit-bg); }

.difficulty {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 14px;
}

.level-bar {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 2px 6px;
  background: none;
  border: none;
  color: var(--fg-dim);
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 1px;
}
.level-bar #level-label { color: var(--accent); }
.level-bar .xp { display: block; width: 90px; height: 4px; background: rgba(var(--fg-rgb), 0.12); border-radius: 2px; overflow: hidden; }
.level-bar .xp i { display: block; height: 100%; width: 0; background: var(--fg); transition: width 0.4s ease; }
.level-bar.maxed .xp i { background: var(--accent); }

.rec-level { margin: 0 0 10px; padding: 8px; border: 1px dashed var(--grid-line); border-radius: 4px; }
.rec-level .rec-head { font-size: 15.5px; }
.rec-level { border-color: var(--accent); }
.rec-level .rec-name, .rec-level .rec-state { color: var(--fg); text-shadow: 0 0 6px rgba(var(--fg-rgb), 0.4); }
.rec-level .rec-name em, .rec-level .rec-state em { font-style: normal; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
.rec-rankup { margin-top: 8px; width: 100%; padding: 6px; background: rgba(var(--accent-rgb), 0.1); border: 1px solid var(--accent); border-radius: 4px; color: var(--accent); font-family: inherit; font-size: 14.5px; letter-spacing: 1px; cursor: pointer; }

.modes {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 12px;
}

.modes button {
  background: transparent;
  border: 1px solid var(--fg-dim);
  color: var(--fg-dim);
  font-family: inherit;
  font-size: 11px;
  padding: 4px 9px;
  border-radius: 4px;
  cursor: pointer;
  letter-spacing: 1px;
}
/* Six modes on one row */
/* (the phone layout everywhere) */
.modes button { padding: 4px 6px; letter-spacing: 0.5px; }
@media (max-width: 380px) {
  .modes button { padding: 3px 5px; font-size: 10px; letter-spacing: 0; }
}
@media (hover: hover) { .modes button:hover { color: var(--fg); border-color: var(--fg); } }
.modes button.active { color: var(--fg); border-color: var(--fg); box-shadow: 0 0 8px rgba(var(--fg-rgb), 0.3); }

.mode-info {
  margin: 8px auto 0;
  max-width: 340px;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--fg-dim);
}
.difficulty[hidden] { display: none; }


/* A solved puzzle uses the terminal color instead of the trace red */
.overlay-box.win { border-color: var(--fg); box-shadow: 0 0 30px rgba(var(--fg-rgb), 0.4); }
.overlay-box.win h2,
.overlay-box.win .overlay-sub { color: var(--fg); text-shadow: 0 0 8px var(--fg); }

.overlay-note { font-size: 14.5px; letter-spacing: 1px; color: var(--fg-dim); }
.overlay-share-btn {
  margin-left: 18px; /* (8px and what Courier's space between them used to be) */
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: inherit;
  padding: 8px 18px;
  border-radius: 4px;
  cursor: pointer;
  letter-spacing: 1px;
}
.overlay-share-btn[hidden] { display: none; }
@media (hover: hover) { .overlay-share-btn:hover { background: rgba(var(--accent-rgb), 0.15); } }

.stat.time-low .value { color: var(--danger); text-shadow: 0 0 8px var(--danger); }

.difficulty button {
  background: transparent;
  border: 1px solid var(--fg);
  color: var(--fg);
  font-family: inherit;
  padding: 6px 14px;
  border-radius: 4px;
  cursor: pointer;
  letter-spacing: 1px;
}

@media (hover: hover) { .difficulty button:hover { background: rgba(var(--fg-rgb), 0.15); } }

.difficulty button.active {
  background: var(--fg);
  color: var(--panel);
  font-weight: bold;
  box-shadow: 0 0 10px rgba(var(--fg-rgb), 0.4);
}

.difficulty#daily-kinds { gap: 6px; }
.difficulty#daily-kinds button { padding-left: 10px; padding-right: 10px; }
#vs-layers-btn, #vs-exploits-btn { white-space: nowrap; padding-left: 8px; padding-right: 8px; }
/* VS CPU: the opponent's mini board, the incoming-garbage badge, and a slimmer header */
/* The CPU's board: a small copy of the grid with its numbers */
.cpu-stat { cursor: zoom-in; user-select: none; -webkit-user-select: none; touch-action: none; position: relative; }
/* Before START: the picked bot's play style, a bordered see-through card over its board, the
   text centered both ways (script.js shrinks it to fit) */
.cpu-desc {
  position: absolute; inset: 22px 6px 6px; z-index: 2; margin: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; overflow: hidden;
  padding: 4px; border: 1px solid var(--fg-dim); border-radius: 3px;
  background: color-mix(in srgb, var(--board-bg) 72%, transparent);
  font-size: 10px; line-height: 1.35; letter-spacing: 0.5px; text-align: center; color: var(--fg);
  pointer-events: none;
}
.cpu-desc[hidden] { display: none; }
/* (before START the box is the bot's card alone, no board or score behind it, the same space all round) */
.cpu-stat.pre-start > .label, .cpu-stat.pre-start > .cpu-grid { visibility: hidden; }
.cpu-stat.pre-start .cpu-desc { inset: 6px; }
.cpu-stat.pre-start { cursor: default; }
.cpu-desc b { color: var(--accent); font-weight: normal; letter-spacing: 1px; white-space: nowrap; }
.cpu-stat .sub { font-size: 10px; margin-top: 3px; }
.cpu-stat.low .label { color: var(--danger); }
.cpu-hint { display: block; margin-top: 2px; font-size: 8px; letter-spacing: 1px; color: var(--fg-dim); opacity: 0.7; }
.cpu-grid { display: grid; grid-template-columns: repeat(var(--cpu-cols, 7), 1fr); gap: 2px; width: 100%; max-width: 210px; margin: 4px auto 0; }
.cpu-grid i {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-style: normal;
  font-weight: bold;
  font-size: clamp(8px, 2.6vw, 13px);
  border: 1px solid var(--grid-line);
  border-radius: 2px;
  color: var(--fg);
}
.cpu-grid i.over { border-color: rgba(var(--danger-rgb), 0.45); }
.cpu-grid i.over-edge { border-bottom: 2px solid var(--danger); }
.cpu-grid i.bit { background: rgba(var(--fg-rgb), 0.14); border-color: var(--fg-dim); text-shadow: 0 0 4px rgba(var(--fg-rgb), 0.6); }
/* Layers colored like yours: [=] in the layer gray, [-] (cracked) in the cracked color */
.cpu-grid i.layer { background: repeating-linear-gradient(45deg, var(--layer-a), var(--layer-a) 2px, var(--layer-b) 2px, var(--layer-b) 4px); border: 1px dashed var(--layer-border); color: var(--layer-text); }
.cpu-grid i.layer.cracked { border-color: var(--cracked); color: var(--cracked); }
.cpu-grid i.over.bit, .cpu-grid i.over.layer { border-color: var(--danger); color: var(--danger); }
.cpu-grid i .glyph { width: 78%; height: 78%; }
/* The preview's effects, lighter than your board's: a flash as a bit decrypts, a small drop as one
   lands, a blink as a layer peels */
.cpu-grid i.pop { animation: cpu-pop 0.22s ease-out forwards; }
@keyframes cpu-pop { 0% { filter: brightness(2); } 100% { opacity: 0.1; filter: brightness(1); } }
.cpu-grid i.landed { animation: land 0.15s ease; }
.cpu-grid i.peeled { animation: cpu-peel 0.2s ease-out; }
@keyframes cpu-peel { 0% { filter: brightness(1.9); } 100% { filter: brightness(1); } }
[data-theme="spectrum"] .cpu-grid i.bit {
  color: hsl(var(--bit-h) 100% 64%);
  border-color: hsl(var(--bit-h) 100% 64%);
  background: hsl(var(--bit-h) 100% 64% / 0.14);
  animation: bit-hue var(--spin, 6s) linear var(--spin-delay, 0s) infinite var(--spin-dir, normal);
}
[data-theme="spectrum"] .cpu-grid i.bit.pop { animation: cpu-pop 0.22s ease-out forwards; }
/* Held: the CPU's board full size over yours */
.cpu-full { position: absolute; inset: 0; z-index: 4; background: var(--board-bg); }
.cpu-full[hidden] { display: none; }
.cpu-full::after {
  content: 'CPU BOARD';
  position: absolute;
  top: 4px;
  right: 8px;
  font-size: 10px;
  letter-spacing: 2px;
  color: var(--accent);
}
.vs-quit {
  padding: 8px 18px;
  background: none;
  border: 1px solid var(--danger);
  border-radius: 4px;
  color: var(--danger);
  font-family: inherit; /* same size as RESTART, whose place it takes */
  letter-spacing: 1px;
  cursor: pointer;
}
/* VS layout: your stats and QUIT stacked on the left, the CPU's board on the right */
/* VS: the header as in every game (BYTEFALL, then VS. CPU // the game mode), the target in the
   status line over your stats */
.vs-status { display: none; }
body.vs-mode .vs-status { display: flex; align-items: center; justify-content: center; font-size: 11px; letter-spacing: 1px; text-align: center; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
/* Before the match: pick the CPU level and LAYERS, then START */
.vs-setup {
  position: absolute;
  inset: 0;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 12px 16px;
  text-align: center;
  background: var(--board-bg); /* with the defrag canvas (#vs-setup-bg) over it */
  isolation: isolate;
  animation: byte-in 0.35s ease-out;
}
.vs-setup-bg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
.vs-setup[hidden] { display: none; }
.vs-setup-title { margin: 0; font-size: 16px; letter-spacing: 3px; color: var(--accent); text-shadow: 0 0 8px rgba(var(--accent-rgb), 0.6); }
.vs-setup-note { margin: 0; max-width: 300px; font-size: 11px; line-height: 1.5; color: var(--panel-text); }
.vs-setup .difficulty { flex-wrap: wrap; margin-top: 0; }
.vs-start {
  padding: 10px 34px;
  background: rgba(var(--fg-rgb), 0.12);
  border: 1px solid var(--fg);
  border-radius: 4px;
  color: var(--fg);
  font-family: inherit;
  font-size: 14px;
  letter-spacing: 3px;
  cursor: pointer;
  box-shadow: 0 0 12px rgba(var(--fg-rgb), 0.35);
}
/* Its height (set by script.js) spans where the difficulty row and HUD sit in regular play, so your
   board keeps its regular size and place */
/* VS's top: the info panels, then BOT (the CPU's face) and the CPU's board in boxes the same size */
/* The info: a 2x2 grid of boxes (SCORE, CHAIN / ENCRYPT IN, CURRENT) under the status line */
/* (the squares' columns and rows are exactly their size, so the four sit flush with the strip's
   left edge and their bottoms line up with BOT's and the CPU board's; those two share the rest) */
body.vs-mode .hud { display: grid; grid-template-columns: var(--vs-sq, 60px) var(--vs-sq, 60px) minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: auto var(--vs-sq, 60px) var(--vs-sq, 60px); gap: 6px; align-items: stretch; align-content: end; }
body.vs-mode .hud > * { min-width: 0; min-height: 0; }
body.vs-mode .hud > .vs-status { grid-column: 1 / 3; grid-row: 1; }
body.vs-mode .hud > #score-stat { grid-column: 1; grid-row: 2; }
body.vs-mode .hud > #chain-stat { grid-column: 2; grid-row: 2; }
body.vs-mode .hud > #pulse-stat { grid-column: 1; grid-row: 3; }
body.vs-mode .hud > .hud-bits { grid-column: 2; grid-row: 3; }
/* The four boxes are squares (--vs-sq, set by script.js's layoutVsTop), packed together in the
   middle of their area */
body.vs-mode .hud > :is(#score-stat, #chain-stat, #pulse-stat, .hud-bits) { width: var(--vs-sq, 60px); height: var(--vs-sq, 60px); }
body.vs-mode .hud > :is(#score-stat, #chain-stat) { align-self: end; }
body.vs-mode .hud > :is(#pulse-stat, .hud-bits) { align-self: start; }
body.vs-mode .hud > :is(#score-stat, #pulse-stat) { justify-self: end; }
body.vs-mode .hud > :is(#chain-stat, .hud-bits) { justify-self: start; }
/* In each square the value sits dead center, and the label centered in the space above it */
body.vs-mode .hud > :is(#score-stat, #chain-stat, #pulse-stat) .value,
body.vs-mode .hud-bits:not(.has-next) #current-piece { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); max-width: calc(100% - 6px); }
body.vs-mode .hud > :is(#score-stat, #chain-stat, #pulse-stat) .label,
body.vs-mode .hud-bits:not(.has-next) .stat-current .label { position: absolute; left: 1px; right: 1px; top: 0; letter-spacing: 0 !important; height: calc(50% - 17px); display: flex; align-items: center; justify-content: center; text-align: center; line-height: 1.1 !important; }
body.vs-mode .hud > .cpu-face { grid-column: 3; grid-row: 1 / -1; }
body.vs-mode .hud > .cpu-stat { grid-column: 4; grid-row: 1 / -1; justify-content: flex-start; padding: 4px 6px; }
/* CURRENT's square splits when a KEYLOGGER shows the next bits (VS has no NEXT otherwise) */
body.vs-mode .hud-bits { display: flex; flex-direction: column; gap: 4px; overflow: hidden; }
body.vs-mode .hud-bits .stat { flex: 1 1 0; }
body.vs-mode .hud-bits .bit-row { gap: 2px; justify-content: center; }
body.vs-mode .hud-bits .stat.keylogger .bit-row .bit-sq { width: 16px; height: 16px; font-size: 9px; margin-top: 0; }
/* ENCRYPT IN stays on one line (it shrinks to fit instead: script.js's fitStatValues) */
#pulse-label { white-space: nowrap; }
body.vs-mode .cpu-grid { flex: none; width: 100%; max-width: none; margin: auto 0; }
/* (one box for the 7x7 board and the 8x8 one: the 7x7's shape, the 8x8's smaller squares centered in
   it, so changing the CPU's level never moves or resizes a thing) */
body.vs-mode .cpu-grid { aspect-ratio: 7 / 8; min-height: 0; align-content: center; }
body.vs-mode .cpu-grid { grid-template-columns: repeat(var(--cpu-cols, 7), minmax(0, 1fr)); gap: 1px; }
body.vs-mode .cpu-grid i { aspect-ratio: 1; min-width: 0; overflow: hidden; font-size: clamp(7px, 1.1vh, 11px); line-height: 1; }
body.vs-mode .hud-bits { flex: none; }
/* The info panels: each label centered over its number, in the middle of its box */
body.vs-mode .hud > .stat:not(.cpu-stat):not(.cpu-face),
body.vs-mode .hud-bits .stat { flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 4px 4px; text-align: center; }
body.vs-mode .hud .stat:not(.cpu-stat) .value { margin-top: 0; font-size: 16px; }
body.vs-mode .hud .stat:not(.cpu-stat) .sub { display: none; }
body.vs-mode .hud > .stat:not(.cpu-stat), body.vs-mode .hud-bits .stat { padding-top: 2px; padding-bottom: 2px; }
/* CURRENT in VS: the whole bit in its box, as in the other modes */
body.vs-mode .hud-bits #current-piece { width: 30px; height: 30px; margin: 0; flex: none; font-size: 15px; }
body.vs-mode .hud-bits, body.vs-mode .hud-bits .stat { min-height: 0; }
body.vs-mode .vs-status { font-size: 13px; white-space: nowrap; overflow: hidden; height: 16px; line-height: 16px; } /* (just the game mode, at the notes' size; one fixed height: its text shrinking, if ever it must, never moves the board) */
.incoming {
  position: absolute;
  top: 2px;
  left: 4px;
  z-index: 5;
  padding: 1px 6px;
  border: 1px solid var(--danger);
  border-radius: 3px;
  background: rgba(var(--danger-rgb), 0.15);
  color: var(--danger);
  font-size: 11px;
  letter-spacing: 1px;
  text-shadow: 0 0 6px var(--danger);
  pointer-events: none;
}
.incoming[hidden] { display: none; }
/* ▼ 14 INCOMING, then a small square pip per block, in groups of 8 (up to 32) */
.incoming:not([hidden]) { display: flex; align-items: center; gap: 6px; max-width: calc(100% - 8px); white-space: nowrap; }
.incoming .pips { display: flex; flex-wrap: nowrap; gap: 1px; }
.incoming .pips:empty { display: none; }
.incoming .pips i { width: 3px; height: 3px; flex: none; background: currentColor; box-shadow: 0 0 3px var(--danger); }
.incoming .pips i:nth-child(8n):not(:last-child) { margin-right: 2px; }
body.vs-mode header #mode-info { display: none; }

.new-best {
  color: var(--accent);
  text-shadow: 0 0 8px var(--accent);
  letter-spacing: 2px;
}

.cabinet {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "game";
  width: 100%;
  max-width: 480px;
}

.cabinet .crt { grid-area: game; }

.panel {
  background: var(--panel);
  border: 1px dashed var(--fg-dim);
  border-radius: 6px;
  padding: 14px;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--panel-text);
}

.panel h2 {
  margin: 0 0 8px;
  font-size: 23.5px;
  letter-spacing: 3px;
  color: var(--fg);
  text-shadow: 0 0 8px var(--fg);
}

.panel p { margin: 0 0 10px; }
.panel b { color: var(--accent); }
.panel .keys { color: var(--fg-dim); margin-bottom: 0; }

.hack-item {
  border: 1px dashed var(--grid-line);
  border-radius: 4px;
  padding: 8px 10px;
  margin-top: 10px;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.hack-item h3 {
  margin: 0 0 4px;
  font-size: 17px;
  letter-spacing: 1px;
  color: var(--fg);
}

.hack-item .icon { display: inline-flex; align-items: center; gap: 1px; min-width: 2.6em; margin-right: 4px; color: var(--accent); }
.hack-item .icon .ico-br { color: var(--fg-dim); }
.hack-item h3 { display: flex; align-items: baseline; }
.hack-item .combo {
  margin-left: auto;
  font-size: 14.5px;
  color: var(--fg-dim);
}
.hack-item.held .combo { color: var(--accent); }
.hack-item p { margin: 0; font-size: 14.5px; }

.hack-item.held {
  border: 1px solid var(--accent);
  box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.3);
}

.hack-item.held h3 { color: var(--accent); }

/* Exploit loadout: tap an unlocked card to equip or remove it */
.slot-info { margin: 0 0 8px; font-size: 14.5px; letter-spacing: 1px; color: var(--accent); }
.hack-item.unlocked { cursor: pointer; }
.hack-item.unlocked:not(.equipped) { opacity: 0.7; }
@media (hover: hover) { .hack-item.unlocked:hover { border-color: var(--fg-dim); } }
.hack-item.equipped { border: 1px solid var(--fg); }

.hack-item { position: relative; overflow: hidden; }
/* DEV MODE: three quick taps on an exploit's name make it the next drop (selecting no text, zooming nothing) */
.dev-unlock .hack-item { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; touch-action: manipulation; }
.hack-item.equipped h3::after { content: 'EQUIPPED'; margin-left: 8px; font-size: 11.5px; letter-spacing: 1px; color: var(--fg); order: 3; }
.hack-item .lock-tag { display: block; margin-top: 4px; font-size: 11.5px; letter-spacing: 2px; color: var(--fg-dim); }
.hack-item.locked .lock-tag { color: var(--accent); }

/* LOGIC BOMB and HONEYPOT sit on the board as armed blocks */
.cell.hack.armed { animation: armed-pulse 1s ease-in-out infinite; }
.cell.hack.armed.bomb { font-size: clamp(10px, 3.2vw, 16px); }
@keyframes armed-pulse {
  0%, 100% { box-shadow: 0 0 0 rgba(var(--danger-rgb), 0); }
  50% { box-shadow: 0 0 10px rgba(var(--danger-rgb), 0.7); }
}

/* PACKET SNIFFER: the CURRENT bit can be changed */
.stat.sniffing { border-color: var(--accent); }
.stat.sniffing .label { color: var(--accent); }
.stat.sniffing .bit-sq { cursor: pointer; border-color: var(--accent); }

/* Bonus exploits and tracks without Full Access (preview with ?free) */
.settings button .need { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; font-size: 9px; letter-spacing: 0; color: var(--accent); }
.settings .theme-option { position: relative; min-width: 0; }
/* Every locked item (theme, font, HARD, track, exploit card): its content dims behind a lock
   centered on it */
.settings .theme-option.locked::after,
.difficulty button.locked::after,
.settings #playlist-tracks button.locked::after,
.hack-item.locked::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 16px;
  transform: translate(-50%, -50%);
  background: var(--fg);
  -webkit-mask: var(--icon-lock) center / contain no-repeat;
  mask: var(--icon-lock) center / contain no-repeat;
  pointer-events: none;
}
.settings .theme-option.locked > *:not(.lv-tag),
.hack-item.locked > *:not(.lock-tag) { opacity: 0.3; }
/* (a locked theme's or font's unlock level, in its top-right corner, as the tracks show theirs) */
.settings .theme-option .lv-tag { position: absolute; top: 2px; right: 4px; font-size: 8px; line-height: 1; letter-spacing: 0; color: var(--accent); pointer-events: none; font-family: 'Courier New', monospace; }
.difficulty button.locked { position: relative; color: rgba(var(--fg-rgb), 0.3); }
.settings #playlist-tracks button.locked { position: relative; color: rgba(var(--fg-rgb), 0.3); opacity: 1; }
.hack-item.locked { position: relative; }
.hack-item.unused { opacity: 0.45; }
.settings .theme-option.locked { cursor: help; }

.stat.keylogger { border-color: var(--accent); }
.stat.keylogger .label { color: var(--accent); }


/* Records: the trophy in the CRT's top-left corner, mirroring the settings icon */
.records-btn {
  position: absolute;
  top: 8px;
  left: 8px;
  width: 56px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: none;
  border: none;
  color: var(--fg);
  opacity: 0.35;
  cursor: pointer;
  transition: opacity 0.25s ease, filter 0.25s ease;
}
.records-btn svg { width: 48px; height: 19px; display: block; }
.records-btn[aria-expanded="true"] {
  opacity: 1;
  filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6));
}
/* (hover only with a real pointer: on touch screens it sticks after the tap that closes the panel) */
@media (hover: hover) {
  .records-btn:hover { opacity: 1; filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6)); }
}

.records {
  position: absolute;
  top: 44px;
  left: 12px;
  right: 12px; /* the same inset on both sides of the game panel */
  z-index: 20;
  max-height: calc(100% - 56px); /* stays inside the game panel (it's absolute within .crt) */
  overscroll-behavior: contain;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 10px 12px;
  text-align: left;
  background: var(--popup-bg);
  border: 1px dashed var(--fg-dim);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
}
.records[hidden] { display: none; }
/* EXPLOITS and STORE have buttons of their own (main menu, pause screen): no tabs for them here, and
   opened on their own the card has no tabs at all */
.records .menu-tabs [data-pane="exploits"], .records .menu-tabs [data-pane="store"], .records.solo .menu-tabs { display: none; }

.records-tabs { display: flex; gap: 4px; margin-bottom: 10px; }
.records-tabs button {
  flex: 1;
  padding: 5px 2px;
  background: none;
  border: 1px solid var(--grid-line);
  border-radius: 4px;
  color: var(--fg-dim);
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 1px;
  cursor: pointer;
}
.records-tabs button[aria-selected="true"] { color: var(--fg); border-color: var(--fg); }

/* The MENU's tabs: RULES, EXPLOITS, RECORDS, each with its icon; each tab shows its own card */
.menu-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.menu-tabs button {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 7px 2px 6px;
  background: none;
  border: 1px solid var(--grid-line);
  border-radius: 4px;
  color: var(--fg-dim);
  font-family: inherit;
  font-size: 11px;
  letter-spacing: 1px;
  cursor: pointer;
}
.menu-tabs button svg { width: 18px; height: 18px; display: block; }
@media (hover: hover) { .menu-tabs button:hover { background: rgba(var(--fg-rgb), 0.08); } }
.menu-tabs button[aria-selected="true"] { color: var(--fg); border-color: var(--fg); text-shadow: 0 0 6px rgba(var(--fg-rgb), 0.6); filter: drop-shadow(0 0 3px rgba(var(--fg-rgb), 0.35)); }
.menu-pane[hidden] { display: none; }
.records .panel { padding: 10px; font-size: 14.5px; }
.records .panel h2 { font-size: 17px; }
.records .panel-records { font-size: 15.5px; }
/* RECORDS text: 12px at most, the rest a step down */
.records-body { font-size: 15.5px; }
.rec-group { margin: 10px 0 4px; font-size: 14.5px; letter-spacing: 2px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
/* ======= between achievement sections */
.rec-sep { margin: 12px 0 0; overflow: hidden; white-space: nowrap; font-size: 14.5px; line-height: 15px; letter-spacing: 2px; color: var(--accent); opacity: 0.7; }
.rec-sep + .rec-group { margin-top: 6px; }
.rec-group:first-child { margin-top: 0; }
.rec-summary { margin: 0 0 8px; color: var(--accent); letter-spacing: 1px; }
.rec-list { list-style: none; margin: 0; padding: 0; }
.rec-row { padding: 6px 0; border-bottom: 1px dashed var(--grid-line); }
.rec-head { display: flex; gap: 8px; align-items: baseline; }
.rec-name { color: var(--fg-dim); letter-spacing: 1px; }
.rec-state { margin-left: auto; font-size: 14.5px; color: var(--fg-dim); white-space: nowrap; }
.rec-row.done .rec-name { color: var(--fg); }
.rec-row.done .rec-state { color: var(--accent); }
.rec-check { color: var(--accent); }
.rec-desc { margin: 2px 0 0; font-size: 14.5px; color: var(--panel-text); opacity: 0.8; }
.rec-bar { height: 3px; margin-top: 5px; background: rgba(var(--fg-rgb), 0.12); border-radius: 2px; overflow: hidden; }
.rec-bar i { display: block; height: 100%; background: var(--fg); }
.rec-stats { margin: 0; }
/* each stat joined to its value by a dotted leader: LONGEST CHAIN ........ 6x */
.rec-stats div { display: flex; align-items: baseline; margin-bottom: 5px; }
.rec-stats dt { display: flex; flex: 1; min-width: 0; color: var(--fg-dim); white-space: nowrap; }
.rec-stats dt::after {
  content: ' ................................................................................................';
  flex: 1;
  min-width: 16px;
  overflow: hidden;
  padding: 0 6px 0 4px;
  opacity: 0.6;
}
.rec-stats dd { margin: 0; text-align: right; color: var(--fg); white-space: nowrap; }

/* Shown while the dev page's UNLOCK EVERYTHING switch is on */
.dev-badge {
  /* In the game card, centered between the corner buttons and level with their middles (they're
     30px tall, 10px up: their middles 25px up) */
  position: absolute;
  left: 50%;
  bottom: 25px;
  transform: translate(-50%, 50%);
  z-index: 0; /* (under the wanderers, which come after it) */
  pointer-events: none;
  white-space: nowrap;
  padding: 3px 7px;
  border: 1px dashed var(--accent);
  border-radius: 4px;
  background: var(--popup-bg);
  color: var(--accent);
  font-size: 9px;
  letter-spacing: 1px;
  text-decoration: none;
}
.dev-badge[hidden] { display: none; }

.led-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.settings-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 56px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: none;
  border: none;
  color: var(--fg);
  opacity: 0.35;
  cursor: pointer;
  transition: opacity 0.25s ease, filter 0.25s ease;
}

.settings-btn svg { width: 48px; height: 19px; display: block; }

.settings-btn[aria-expanded="true"] {
  opacity: 1;
  filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6));
}
/* (hover only with a real pointer: on touch screens it sticks after the tap that closes the panel) */
@media (hover: hover) {
  .settings-btn:hover { opacity: 1; filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6)); }
}

.settings {
  position: absolute;
  top: 44px;
  right: 12px;
  z-index: 20;
  width: 240px;
  max-width: calc(100% - 24px);
  max-height: calc(100% - 56px); /* stays inside the game panel (it's absolute within .crt) */
  overscroll-behavior: contain;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 10px 12px;
  text-align: left;
  background: var(--popup-bg);
  border: 1px dashed var(--fg-dim);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
}

.settings[hidden] { display: none; }

.settings-title {
  margin: 0 0 6px;
  font-size: 10px;
  letter-spacing: 2px;
  color: var(--fg-dim);
}

.settings-section {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--grid-line);
}

.settings ol { list-style: none; margin: 0; padding: 0; }

.settings button {
  display: flex;
  width: 100%;
  padding: 6px 8px;
  text-align: left;
  white-space: pre;
  background: none;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--fg);
  font-family: inherit;
  font-size: 12px;
  letter-spacing: 1px;
  cursor: pointer;
}

@media (hover: hover) { .settings button:hover:not(:disabled) { background: rgba(var(--fg-rgb), 0.12); } }
.settings button.active { border-color: var(--fg-dim); }
.settings button.playing { border-color: var(--accent); color: var(--accent); }
.settings button.playing::after {
  content: '';
  width: 9px;
  height: 11px;
  margin: auto 0 auto auto;
  background: currentColor;
  -webkit-mask: var(--icon-play) center / contain no-repeat;
  mask: var(--icon-play) center / contain no-repeat;
}
.settings button:disabled { color: var(--fg-dim); opacity: 0.55; cursor: default; }

.settings-row { display: flex; gap: 6px; margin-bottom: 6px; }


.theme-list { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.settings .theme-option {
  flex-direction: column;
  align-items: stretch;
  text-align: center; /* the name centered across the button, like the fonts */
  gap: 5px;
  padding: 6px 7px;
  font-size: 10px;
  white-space: nowrap;
  color: var(--fg-dim);
  border-color: var(--grid-line);
}
.settings .theme-option.active { color: var(--fg); border-color: var(--fg); }
/* Font picker: each name in its own font, centered both ways (clear of the lock icon) */
.settings .font-list .theme-option { justify-content: center; align-items: center; text-align: center; min-height: 34px; padding-left: 8px; padding-right: 8px; letter-spacing: 0.5px; }
/* Locked font: its name dims behind a lock centered on the button */

/* Each swatch carries its theme's data-theme, so it shows that theme's bit, layer and accent colors */
/* The theme's colors as three short, wide bars under its name */
.swatches { display: flex; gap: 3px; width: 100%; }
.swatches i { display: block; flex: 1; height: 5px; border-radius: 3px; }
.swatches i:nth-child(1) { background: var(--fg); }
.swatches i:nth-child(2) { background: var(--layer-border); }
.swatches i:nth-child(3) { background: var(--accent); }


.settings-row .toggle-btn { justify-content: center; }

.settings .viz-toggle {
  display: block;
  width: 100%;
  height: 26px;
  margin: 0 0 8px;
  padding: 0;
  border: 1px solid var(--grid-line);
  border-radius: 4px;
  background: var(--inset-bg);
  cursor: pointer;
  overflow: hidden;
  white-space: normal; /* .settings button uses pre, which would render the markup's newline above the canvas */
}

@media (hover: hover) { .settings .viz-toggle:hover { border-color: var(--fg-dim); background: var(--inset-bg); } }

.viz-toggle canvas { display: block; width: 100%; height: 100%; }

.settings-options {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--grid-line);
}

.settings .toggle-btn { font-size: 11px; color: var(--fg-dim); border-color: var(--grid-line); }
.settings .toggle-btn.on { color: var(--fg); border-color: var(--fg-dim); }

.settings-note + .toggle-btn { margin-top: 10px; }
.settings-panel > .toggle-btn + .toggle-btn { margin-top: 6px; } /* (two in a row, no note between: VIBRATION, then DROP BY; the same 6px as SOUND / MUSIC to SOUND OUTPUT) */

.settings-note {
  margin: 6px 2px 0;
  font-size: 13px;
  line-height: 1.4;
  color: rgba(var(--fg-rgb), 0.78); /* (brighter than --fg-dim: easy to read) */
}
.settings-first { margin-top: 0; padding-top: 0; border-top: 0; }
.settings-sub { margin-top: 12px; }
.settings .settings-gap { margin-top: 4px; }
.settings-title + .toggle-btn { margin-top: 0; }
/* The app's UNLOCK EVERYTHING padlock, where the DEV link is on the web */
.settings .dev-unlock-btn, .dev-unlock-btn { display: inline-flex; align-items: center; gap: 5px; width: auto; padding: 4px 2px; border: 0; background: none; color: var(--fg); font-family: inherit; font-size: 11px; letter-spacing: 1px; cursor: pointer; }
.dev-link[hidden], .dev-unlock-btn[hidden] { display: none !important; }
.dev-unlock-btn.on { opacity: 1; color: var(--accent); filter: drop-shadow(0 0 4px rgba(var(--accent-rgb), 0.6)); }

/* Under the game card (inside SETTINGS on phones): the text, then the dev link */
footer {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 12px;
  width: 100%;
  max-width: 480px;
  margin-top: 20px;
  text-align: center;
}

.footer-text { grid-column: 1; }

.dev-link {
  grid-column: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 28px;
  color: var(--fg);
  opacity: 0.35;
  transition: opacity 0.25s ease, filter 0.25s ease;
}

.dev-link { width: auto; height: auto; padding: 4px 2px; font-size: 11px; letter-spacing: 1px; white-space: nowrap; text-decoration: none; }

.dev-link:focus-visible { opacity: 1; filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6)); }
@media (hover: hover) { .dev-link:hover { opacity: 1; filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6)); } }


footer p {
  font-size: 10px;
  color: var(--fg-dim);
  letter-spacing: 0.16em;
  margin: 4px auto;
}

/* Build, updated and commit: a line each */
.footer-meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  row-gap: 2px;
}

.meta-item { white-space: nowrap; }
footer span { color: var(--fg); }

.overlay {
  position: fixed;
  z-index: 100;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  display: flex;
  align-items: center;
  justify-content: center;
}

.overlay.hidden { display: none; }

.overlay-box {
  text-align: center;
  border: 2px solid var(--danger);
  padding: 24px 32px;
  border-radius: 8px;
  background: var(--overlay-bg);
  box-shadow: 0 0 30px rgba(var(--danger-rgb), 0.4);
}

.overlay-box h2 {
  color: var(--danger);
  text-shadow: 0 0 8px var(--danger);
  letter-spacing: 2px;
}

.overlay-box h2 { margin-bottom: 4px; }

.overlay-sub {
  margin-top: 0;
  font-size: 15.5px;
  letter-spacing: 2px;
  color: var(--danger);
  opacity: 0.75;
}

/* Tight spacing around the board so the whole game panel fits the window with as big a board
   as possible (script.js's fitBoard sizes the board to what's left). The phone layout, used on
   every screen. */
.crt { padding-top: 8px; padding-bottom: 14px; }
h1 { font-size: 24px; }
header { margin-bottom: 6px; }
.level-bar { margin-top: 3px; }
.modes { margin-top: 6px; }
.mode-info { margin-top: 4px; }
.difficulty { margin-top: 6px; }
.difficulty button { padding-top: 4px; padding-bottom: 4px; }
.hud { margin: 8px 0; }
.stat { padding-top: 4px; padding-bottom: 4px; }
.message { margin-top: 4px; }
.controls { margin-top: 6px; }
.free-exploit-btn { padding-top: 6px; padding-bottom: 6px; }

/* Inline SVG icons (lock, bolt, arrows) sized to the text around them */
.ico { display: inline-block; width: 1em; height: 1em; vertical-align: -0.14em; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.ico.solid { fill: currentColor; stroke: none; }
.free-exploit-btn .ico { margin-right: 6px; }

/* ===== Lower corners =====
   RESTART (QUIT in VS) sits in the game card's lower-left corner during a session; the exploit
   button in the lower-right. */
/* The corner buttons are 60x30 (2:1) with the bit cells' square corners, level with each other
   and 8px in from the screen's edges. The message line sits centered between the column
   buttons and the corner buttons' tops: its 12px top gap matches the room left above them in the
   50px bottom padding (50 - 8 below - 30 tall). */
.crt { padding-bottom: 50px; }
.message-slot { margin-top: 12px; }
.message-slot .message { margin-top: 0; }
.corner-btn {
  position: absolute;
  bottom: 8px;
  width: 60px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--grid-line);
  border-radius: 3px;
  color: var(--fg);
  cursor: pointer;
}
.corner-btn[hidden] { display: none; }
#restart-btn.corner-btn, #vs-quit.corner-btn { padding: 0; letter-spacing: 0; } /* not the old text buttons' padding */
@media (hover: hover) { #restart-btn.corner-btn:hover { background: rgba(var(--fg-rgb), 0.08); } }
/* Nothing to restart yet (before the first drop, or once the run is over): grayed out */
#restart-btn.corner-btn:disabled { color: var(--fg-dim); opacity: 0.4; cursor: default; background: rgba(255, 255, 255, 0.02); }
.corner-btn svg { width: 20px; height: 20px; display: block; }
.restart-icon, .quit-icon { left: 8px; }
/* QUIT: dim like the exploit button beside it; red while pressed and while it waits to confirm */
.quit-icon { color: var(--fg-dim); opacity: 0.6; touch-action: none; }
/* In a match the corner button is PAUSE (two bars); otherwise QUIT */
.quit-icon .pause-glyph, .quit-icon.as-pause .quit-glyph { display: none; }
.quit-icon.as-pause .pause-glyph { display: block; }
/* THE EXPLOIT BUTTON: its own row under the grid (under the drop buttons, a gap between: not one
   of them), a square the size of a grid square with the exploit's symbol in the middle */
.exploit-row { order: 2; display: flex; justify-content: center; margin-top: 12px; }
.board-wrap.buttons-top .exploit-row { order: 1; margin-top: 8px; }
.exploit-icon {
  position: relative; width: var(--cell, 40px); height: var(--cell, 40px); display: flex; align-items: center; justify-content: center;
  padding: 0; background: var(--board-bg); border: 1px solid var(--grid-line); border-radius: 6px; cursor: pointer;
  color: var(--fg-dim); --dim: 0.6; font-family: inherit; -webkit-tap-highlight-color: transparent;
}
/* (in layers, as the grid's own slots: the starlight twinkling, the slot's see-through shading over it,
   then the icon. The icon's dimmed, never see-through; bought, it's as bright as a dropped bit) */
.exploit-icon { isolation: isolate; background: var(--board-bg); }
.exploit-icon > .stat-bg { border-radius: inherit; z-index: -2; }
.exploit-icon::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  background: rgba(var(--fg-rgb), 0.04); box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.55); }
.exploit-icon > :not(.stat-bg) { filter: brightness(var(--dim, 0.6)); }
.exploit-icon.side-slot.owned { text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6); }
.exploit-icon.side-slot.owned .exploit-glyph { filter: drop-shadow(0 0 4px rgba(var(--accent-rgb), 0.55)); }
.exploit-icon.side-slot.armed, .exploit-icon.side-slot.armed:disabled { color: var(--accent); --dim: 1; border-style: solid; border-color: var(--accent); animation: amber-pulse 0.9s ease-in-out infinite; cursor: default; }
.exploit-glyph { display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: bold; line-height: 1; }
.exploit-glyph svg { width: 22px; height: 22px; }
.exploit-count { position: absolute; top: -7px; right: -7px; padding: 0 4px; border-radius: 6px; background: var(--fg); color: var(--panel); font-size: 10px; font-weight: bold; }
.exploit-count[hidden] { display: none; }
/* An exploit to arm: bright green glow, showing that exploit's icon */
.exploit-icon.ready { color: var(--fg); --dim: 1; border-color: var(--fg); box-shadow: 0 0 12px rgba(var(--fg-rgb), 0.7); text-shadow: 0 0 8px rgba(var(--fg-rgb), 0.9); }
/* Armed as the next drop: glowing, pulsing amber */
.exploit-icon.armed { color: var(--accent); --dim: 1; border-color: var(--accent); animation: amber-pulse 0.9s ease-in-out infinite; }
/* THE SIDE SLOTS, either side of the exploit button: a STARTER (an R in its corner) or one bought (a
   tick), ready to arm; or the BLACK MARKET's offer (dashed, its price in KEYS under it; a first
   tap lights it, pulsing, for the second to buy) */
.exploit-row { gap: 10px; }
.exploit-icon.side-slot[hidden] { display: none; }
.exploit-icon.side-slot.closed { visibility: hidden; }
/* (used: the item dimmed in its slot, a tick in the corner, through the next drop; then the shuffle) */
.exploit-icon.side-slot.spent, .exploit-icon.side-slot.spent:disabled { --dim: 0.5; color: var(--fg-dim); border-style: dotted; border-color: rgba(var(--fg-rgb), 0.45); cursor: default; }
.exploit-icon.side-slot.owned { color: var(--accent); --dim: 1; border-color: rgba(var(--accent-rgb), 0.7); }
.exploit-icon.side-slot.owned:disabled { --dim: 0.35; cursor: default; }
.exploit-icon.side-slot.market { --dim: 0.85; border-style: dashed; border-color: rgba(var(--accent-rgb), 0.55); color: var(--fg-dim); }
.exploit-icon.side-slot.market.short { --dim: 0.4; }
.exploit-icon.side-slot.market.confirm { --dim: 1; color: var(--accent); border-style: solid; border-color: var(--accent); animation: amber-pulse 0.9s ease-in-out infinite; }
.exploit-icon.side-slot.turned .exploit-glyph { animation: slot-turn 0.35s steps(3); }
@keyframes slot-turn { 0% { opacity: 0; transform: translateY(6px); } 100% { opacity: 1; transform: none; } }
.slot-price { position: absolute; bottom: -15px; left: 0; right: 0; text-align: center; font-size: 10px; line-height: 1; color: var(--accent); }
.starter-tag { position: absolute; top: 1px; right: 3px; font-size: 8px; line-height: 1; color: var(--accent); }
/* A locked exploit: dimmed under a padlock centered on it, as the menus' locked buttons; its
   UNLOCKS AT LV n bright, pulsing a moment when it's tapped (as the main menu's can't-do line) */
.store-item.starter-item.locked { position: relative; }
.store-item.starter-item.locked > :not(.store-deal),
.store-item.starter-item.locked .store-costs,
.store-item.starter-item.locked .store-btns { opacity: 0.3; }
.store-item.starter-item.locked::after {
  content: ''; position: absolute; top: 50%; left: 50%; width: 14px; height: 16px; transform: translate(-50%, -50%);
  background: var(--fg); -webkit-mask: var(--icon-lock) center / contain no-repeat; mask: var(--icon-lock) center / contain no-repeat; pointer-events: none;
}
.store-item.starter-item.locked .booster-owned { color: var(--accent); }
.booster-owned.pulse { text-shadow: 0 0 6px var(--accent); animation: alarm-in 0.25s ease-out, warn-pulse 1s ease-in-out 0.25s infinite; }
@keyframes amber-pulse {
  0%, 100% { box-shadow: 0 0 4px rgba(var(--accent-rgb), 0.4); }
  50% { box-shadow: 0 0 18px rgba(var(--accent-rgb), 0.95); }
}


/* ===== Phones and the app: no page scroll ===== the footer sits inside SETTINGS (moved there
   by script.js) */
body.cards-in-settings .settings footer { margin-top: 12px; display: block; font-size: 10px; }
/* An amber ===== line between the footer and the settings above it */
body.cards-in-settings .settings footer::before { content: "================================================================================"; display: block; margin-bottom: 10px; overflow: hidden; white-space: nowrap; font-size: 14.5px; line-height: 15px; letter-spacing: 2px; color: var(--accent); opacity: 0.7; }
body.cards-in-settings .settings .dev-link { display: inline-flex; margin-top: 6px; }

/* Shorter HUD: SCORE, CHAIN, ENCRYPT IN, CURRENT and NEXT take less height */
.hud .stat { padding-top: 3px; padding-bottom: 3px; }
.hud .stat .value { font-size: 16px; margin-top: 0; }
.hud .bit-sq { width: 30px; height: 30px; margin-top: 2px; font-size: 15px; }
.stat.keylogger .bit-row .bit-sq { width: 26px; height: 26px; font-size: 12px; }
/* All five boxes share one row, even with NEXT showing (Easy) */
.hud .stat { min-width: 0; padding-left: 2px; padding-right: 2px; }
/* Every box the same width: SCORE, BEST, CHAIN, ENCRYPT IN, CURRENT (and NEXT) */
.hud { flex-wrap: nowrap; gap: 5px; }
.hud > .stat { flex: 1 1 0; }
/* (the pair's basis makes up for what each other box's padding and border add, 6px, plus the 5px
   gap between CURRENT and NEXT, so every box comes out the same width) */
.hud-bits { gap: 5px; flex: 1 1 6px; }
.hud-bits.has-next { flex: 2 1 17px; }
.hud-bits .stat-current { flex-grow: 1; }
.hud .stat .label { font-size: 8px; letter-spacing: 0.5px; }
/* Phones and the app: the game fills the screen's height; its contents center vertically in it */
body.cards-in-settings { padding: 0; height: 100vh; height: 100dvh; height: var(--app-h, 100dvh); min-height: 0; }
/* Tall screens (tablets, fullscreen) let the card grow wider with the height, so the extra
   room goes to a bigger board rather than empty space (phones stay limited by their width) */
body.cards-in-settings .cabinet,
body.cards-in-settings .crt { max-width: max(480px, calc(var(--app-h, 100dvh) * 0.56)); }
body.cards-in-settings .board-wrap { max-width: none; } /* (script.js's fitBoard sizes it to the height) */
body.cards-in-settings .cabinet { height: 100%; grid-template-areas: "game"; grid-template-rows: minmax(0, 1fr); gap: 0; }
body.cards-in-settings .crt { height: 100%; display: flex; flex-direction: column; justify-content: center; }
/* VS places its HUD from the top itself (script.js's layoutVsTop) */
body.cards-in-settings.vs-mode .crt { justify-content: flex-start; }
body.cards-in-settings .crt.measuring { height: auto; align-self: start; } /* script.js's fitBoard measures the contents */
/* The header sits at the top of the card, its title level with PAUSE (as the main menu's is with
   its BACK arrow); the HUD, grid and message follow straight under it. VS too: BYTEFALL, VS. CPU //
   its game mode, then its HUD (script.js's layoutVsTop) */
body.cards-in-settings .crt { justify-content: flex-start; padding-top: 8px; }
body.cards-in-settings header { margin-top: var(--head-nudge, 0px); }
/* (the header's title, subtitle and the HUD's panels 8px apart, all at the top: any height to
   spare goes under the message, at the bottom) */
body.cards-in-settings header { margin-bottom: 0; }
body.cards-in-settings header h1 { line-height: 1; }
body.cards-in-settings header .tagline { margin-top: 8px; line-height: 1; }
body.cards-in-settings .crt > .hud { margin-top: 8px; }
body.cards-in-settings .crt > .message-slot { margin-bottom: auto; }
body.cards-in-settings .crt.measuring::after { display: none; }

/* Every confirm (and QUIT while pressed) (RESTART, QUIT, mode / difficulty / DAILY / VS switches mid-run, DECRYPTOR,
   reset progress) looks the same while it waits for the second press: red border and text on
   a red tint, no glow, whatever state or hover the button is in */
button.danger,
button.danger:hover,
#restart-btn.pressing,
#vs-quit.pressing {
  color: var(--danger) !important;
  border-color: var(--danger) !important;
  background: rgba(var(--danger-rgb), 0.12) !important;
  box-shadow: none !important;
  text-shadow: none !important;
  filter: none !important;
  animation: none !important;
  opacity: 1 !important;
  font-weight: normal !important;
}

/* Any other button while it's held down: a light tint, gone again if the finger or mouse slides
   off (which cancels the press: script.js) */
button.pressing:not(:disabled):not(.danger):not(#restart-btn):not(#vs-quit),
a.pressing { box-shadow: inset 0 0 0 999px rgba(var(--fg-rgb), 0.16); }

/* Picking a theme: every color on the page fades to the new theme (script.js adds .theme-fade for
   --theme-fade: 1s, or 1.25s into or out of the light PAPER so it doesn't flash). A pick mid-fade
   carries on from wherever the colors are. The gradients' colors are registered so they fade too. */
@property --bg-center { syntax: '<color>'; inherits: true; initial-value: #000; }
@property --bg-solid { syntax: '<color>'; inherits: true; initial-value: #000; }
@property --layer-a { syntax: '<color>'; inherits: true; initial-value: #000; }
@property --layer-b { syntax: '<color>'; inherits: true; initial-value: #000; }
html.theme-fade,
html.theme-fade *,
html.theme-fade *::before,
html.theme-fade *::after {
  transition-property: color, background-color, border-color, outline-color, box-shadow, text-shadow, fill, stroke, --bg-center, --bg-solid, --layer-a, --layer-b !important;
  transition-duration: var(--theme-fade, 1s) !important;
  transition-timing-function: ease-in-out !important;
}

/* BOT: the CPU's face in VS, a pixel creature with legs. data-bot picks its body and color
   (BOT, GRIFTER's horns, BUNKER's helmet, GLITCH's slipping slices); data-level its resting face
   (EASY happy, NORMAL confident, HARD angry, INSANE red-eyed with bared teeth); data-mood
   (script.js) what it's doing: idle (bobs and blinks), think (looks around), happy, hit, worried,
   dead (you won), smug (it won) */
.cpu-face { display: none; }
body.vs-mode .cpu-face:not(.mini-bot):not([hidden]) { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 4px; background: var(--inset-bg); }
.cpu-bot { width: 78%; max-height: 80%; overflow: visible; }
.cpu-face { --bot: var(--fg); --bot-rgb: var(--fg-rgb); }
.cpu-face[data-bot="grifter"] { --bot: var(--accent); --bot-rgb: var(--accent-rgb); }
.cpu-face[data-bot="bunker"] { --bot: var(--layer-text); --bot-rgb: var(--layer-rgb); }
.cpu-face[data-bot="glitch"] { --bot: var(--danger); --bot-rgb: var(--danger-rgb); }
.cpu-bot .bot-body { fill: var(--bot); filter: drop-shadow(0 0 1px rgba(var(--bot-rgb), 0.8)); }
.cpu-bot .bot-face { fill: var(--board-bg); }
.cpu-bot .shape, .cpu-bot .eyes, .cpu-bot .mouth, .cpu-bot .sweat, .cpu-bot .teeth { display: none; }
.cpu-face[data-bot="bot"] .shape-bot,
.cpu-face[data-bot="grifter"] .shape-grifter,
.cpu-face[data-bot="bunker"] .shape-bunker,
.cpu-face[data-bot="glitch"] .shape-glitch { display: inline; }
.cpu-bot .sweat { fill: var(--accent); }
.cpu-bot .teeth { fill: var(--bot); }
/* Resting (idle, and thinking): the level's face */
.cpu-face:is([data-mood="idle"], [data-mood="think"]):not([data-variant])[data-level="easy"] :is(.eyes-happy, .mouth-smile),
.cpu-face:is([data-mood="idle"], [data-mood="think"]):not([data-variant])[data-level="normal"] :is(.eyes-open, .mouth-smirk),
.cpu-face:is([data-mood="idle"], [data-mood="think"]):not([data-variant])[data-level="hard"] :is(.eyes-angry, .mouth-frown),
.cpu-face:is([data-mood="idle"], [data-mood="think"]):not([data-variant])[data-level="insane"] :is(.eyes-angry, .mouth-teeth, .teeth) { display: inline; }
.cpu-face[data-level="insane"] .eyes-angry { fill: var(--danger); filter: drop-shadow(0 0 1px var(--danger)); }
.cpu-face[data-level="insane"][data-bot="glitch"] .eyes-angry { fill: var(--alarm-text); filter: drop-shadow(0 0 1px var(--alarm-text)); } /* (red on its red body) */
/* Moments and endings */
.cpu-face[data-mood="happy"] :is(.eyes-happy, .mouth-open),
.cpu-face[data-mood="hit"] :is(.eyes-hit, .mouth-open),
.cpu-face[data-mood="worried"] :is(.eyes-wide, .mouth-flat, .sweat),
.cpu-face[data-mood="dead"] :is(.eyes-x, .mouth-flat),
.cpu-face[data-mood="smug"] :is(.eyes-squint, .mouth-smirk),
.cpu-face[data-mood="annoyed"] :is(.eyes-annoyed, .mouth-under),
.cpu-face[data-mood="devious"] :is(.eyes-devious, .mouth-grin),
.cpu-face[data-mood="scared"] :is(.eyes-wide, .mouth-wavy, .sweat),
.cpu-face[data-mood="tired"] :is(.eyes-tired, .mouth-pant, .sweat),
.cpu-face[data-mood="surprised"] :is(.eyes-wide, .mouth-o),
.cpu-face[data-mood="love"] :is(.eyes-heart, .mouth-smile),
.cpu-face[data-mood="dizzy"] :is(.eyes-x, .mouth-wavy),
.cpu-face[data-mood="laugh"] :is(.eyes-happy, .mouth-grin),
.cpu-face[data-mood="skeptic"] :is(.eyes-brow, .mouth-smirk),
.cpu-face[data-mood="paused"] :is(.eyes-annoyed, .mouth-flat),
.cpu-face[data-mood="angry"] :is(.eyes-angry, .mouth-frown),
.cpu-face[data-mood="snarl"] :is(.eyes-angry, .mouth-teeth, .teeth),
.cpu-face[data-variant="bored"] :is(.eyes-squint, .mouth-flat),
.cpu-face[data-variant="tapping"] :is(.eyes-open, .mouth-under),
.cpu-face[data-variant="scan"] :is(.eyes-open, .mouth-flat),
.cpu-face[data-variant="ponder"] :is(.eyes-open, .mouth-smirk) { display: inline; }
.bot-say { font-size: 9px; letter-spacing: 1px; color: var(--fg-dim); min-height: 1em; white-space: nowrap; }
.cpu-face[data-mood="happy"] .bot-say, .cpu-face[data-mood="smug"] .bot-say { color: var(--bot); }
.cpu-face:is([data-mood="hit"], [data-mood="worried"], [data-mood="dead"]) .bot-say,
.cpu-face[data-level="insane"]:is([data-mood="idle"], [data-mood="think"]) .bot-say { color: var(--danger); }
/* Idle: a bob and a blink; think: eyes darting; happy: hops; hit: shakes; worried: shivers and
   sweats; GLITCH's slices slip about all the time */
.cpu-face[data-mood="idle"] .bot { animation: bot-bob 1.2s steps(2) infinite; }
.cpu-face[data-mood="idle"] .eyes { animation: bot-blink 3.7s steps(1) infinite; transform-origin: 8px 7px; }
/* ...and glances around now and then: to each side and up at an angle */
.cpu-face[data-mood="idle"]:not([data-variant]) .bot-face { animation: bot-glance 9s steps(1) infinite; }
.cpu-face[data-mood="think"]:not([data-variant]) .eyes { animation: bot-look 0.8s steps(1) infinite; }
/* Waiting variants. BORED: half-lidded, now and then a sigh (it sinks a pixel); TAPPING: looking
   up from side to side, a foot tapping */
.cpu-face[data-variant="bored"] .bot { animation: bot-sigh 3.2s steps(1) infinite; }
.cpu-face[data-variant="tapping"] .bot-face { animation: bot-up-glance 2.4s steps(1) infinite; }
.cpu-face[data-variant="tapping"] .eyes { animation: bot-blink 3.7s steps(1) infinite; transform-origin: 8px 7px; }
.cpu-face[data-variant="tapping"] .leg-a { animation: bot-step 0.4s steps(1) infinite; }
/* Planning variants. SCAN: eyes sweeping across the board; PONDER: looking up to the side, a
   hand to its chin */
.cpu-face[data-variant="scan"] .eyes { animation: bot-scan 0.9s steps(1) infinite; }
.cpu-face[data-variant="ponder"] .bot-face { transform: translate(1px, -1px); }
.cpu-face[data-variant="ponder"] .arm-r { transform: translateY(-2px); }
.cpu-face[data-variant="ponder"] .eyes { animation: bot-blink 2.9s steps(1) infinite; transform-origin: 8px 7px; }
/* PAUSED (-_-): mildly annoyed, waiting: a slow tap, a side-eye now and then */
.cpu-face[data-mood="paused"] .leg-b { animation: bot-step 0.8s steps(1) infinite; }
.cpu-face[data-mood="paused"] .bot-face { animation: bot-side-eye 5s steps(1) infinite; }
.cpu-face[data-mood="happy"] .bot { animation: bot-hop 0.3s steps(2) infinite; }
.cpu-face:is([data-mood="happy"], [data-mood="smug"]) .leg-a { animation: bot-step 0.3s steps(1) infinite; }
.cpu-face[data-mood="hit"] .bot { animation: bot-shake 0.12s steps(2) infinite; }
.cpu-face[data-mood="worried"] .bot { animation: bot-shake 0.5s steps(2) infinite; }
.cpu-face[data-mood="worried"] .sweat { animation: bot-sweat 0.9s steps(4) infinite; }
.cpu-face[data-mood="dead"] .bot { transform: translateY(1px); }
/* Switching bots: the old one pixelates out and the new one resolves in, 0.25s each (script.js) */
.cpu-face.pix-out .bot-swap { animation: bot-pix-out 0.25s steps(1) forwards; }
.cpu-face.pix-in .bot-swap { animation: bot-pix-in 0.25s steps(1) forwards; }
@keyframes bot-pix-out {
  0% { filter: url(#bot-pix2); opacity: 1; }
  33% { filter: url(#bot-pix4) blur(0.08px); opacity: 0.9; }
  66% { filter: url(#bot-pix4) blur(0.16px); opacity: 0.6; }
  100% { filter: url(#bot-pix4) blur(0.25px); opacity: 0; }
}
@keyframes bot-pix-in {
  0% { filter: url(#bot-pix4) blur(0.2px); opacity: 0.35; }
  33% { filter: url(#bot-pix4) blur(0.08px); opacity: 0.75; }
  66% { filter: url(#bot-pix2); opacity: 1; }
  100% { filter: none; opacity: 1; }
}
/* Devious (holding an exploit, or EXPLOITS switched on): scheming, its arms rubbing up and down
   in opposite directions */
.cpu-face[data-mood="devious"] .arm-l { animation: bot-arm 0.5s steps(2) infinite; }
.cpu-face[data-mood="devious"] .arm-r { animation: bot-arm 0.5s steps(2) infinite reverse; }
.cpu-face[data-mood="devious"] .bot-say { color: var(--bot); }
@keyframes bot-arm { 0% { transform: translateY(-1px); } 100% { transform: translateY(1px); } }
/* Annoyed (-_-): a slow, flat-footed tap */
.cpu-face[data-mood="annoyed"] .leg-b { animation: bot-step 0.6s steps(1) infinite; }
.cpu-face[data-bot="glitch"] .slice-a { animation: bot-slip 1.7s steps(1) infinite; }
.cpu-face[data-bot="glitch"] .slice-c { animation: bot-slip 1.3s steps(1) infinite reverse; }
@keyframes bot-bob { 0% { transform: translateY(0); } 100% { transform: translateY(-0.5px); } }
@keyframes bot-blink { 0%, 92% { transform: scaleY(1); } 94% { transform: scaleY(0.15); } 97% { transform: scaleY(1); } }
@keyframes bot-look { 0% { transform: translateX(-1px); } 50% { transform: translateX(1px); } }
@keyframes bot-glance {
  0% { transform: translate(0, 0); }
  14% { transform: translate(-1px, 0); }
  22% { transform: translate(0, 0); }
  36% { transform: translate(1px, -1px); }
  43% { transform: translate(0, 0); }
  58% { transform: translate(1px, 0); }
  66% { transform: translate(0, 0); }
  80% { transform: translate(-1px, -1px); }
  87% { transform: translate(0, 0); }
}
@keyframes bot-up-glance { 0% { transform: translate(-1px, -1px); } 50% { transform: translate(1px, -1px); } }
@keyframes bot-scan { 0% { transform: translateX(-1px); } 25% { transform: translateX(0); } 50% { transform: translateX(1px); } 75% { transform: translateX(0); } }
@keyframes bot-sigh { 0% { transform: translateY(0); } 70% { transform: translateY(1px); } 90% { transform: translateY(0); } }
@keyframes bot-side-eye { 0% { transform: translate(0, 0); } 60% { transform: translate(-1px, 0); } 80% { transform: translate(0, 0); } }
@keyframes bot-hop { 0% { transform: translateY(0); } 100% { transform: translateY(-1px); } }
@keyframes bot-step { 0% { transform: translateY(0); } 50% { transform: translateY(-1px); } }
@keyframes bot-shake { 0% { transform: translateX(-0.5px); } 100% { transform: translateX(0.5px); } }
@keyframes bot-sweat { 0% { transform: translateY(0); opacity: 1; } 100% { transform: translateY(3px); opacity: 0; } }
@keyframes bot-slip { 0%, 70% { transform: translateX(0); } 75% { transform: translateX(1px); } 85% { transform: translateX(-1px); } 90% { transform: translateX(0); } }
@media (prefers-reduced-motion: reduce) { .cpu-face .bot, .cpu-face .bot-face, .cpu-face .eyes, .cpu-face .leg, .cpu-face .arm, .cpu-face .sweat, .cpu-face .slice-a, .cpu-face .slice-c { animation: none !important; } }
/* VS: the win / loss banner shows over the boards without darkening them */
body.vs-mode .overlay { background: transparent; }
/* The opponent and level pickers: four buttons a row, on one line */
.vs-setup .difficulty { flex-wrap: nowrap; gap: 4px; }
.vs-setup .difficulty button { padding: 5px 6px; font-size: 11px; letter-spacing: 1px; white-space: nowrap; }
.vs-setup #vs-options-row { gap: 6px; }
/* PAUSE: no cover of its own. The board's defrag keeps running behind; the pieces fade out
   quickly and the pause options fade in over it */
.vs-setup.vs-pause { background: transparent; animation: pause-in 0.18s ease-out; }
.vs-pause.closing { animation: pause-out 0.15s ease-in forwards; }
@keyframes pause-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pause-out { from { opacity: 1; } to { opacity: 0; } }
.board-frame #board { transition: opacity 0.15s ease-out; }
.board-frame.paused #board, .board-frame.paused .incoming, .board-frame.paused .chain-meter { opacity: 0; pointer-events: none; } /* (the EXPLOIT meter goes with the bits) */
/* (paused, or a panel up over the board: the INFECTIONS' displays and pop-ups out of sight with the bits) */
.board-wrap:has(.board-frame.paused) > .inf, .board-wrap:has(.vs-pause:not([hidden])) > .inf { visibility: hidden; }
.vs-pause .pause-row { gap: 8px; }
.vs-pause .pause-row button { font-size: 12px; padding: 6px 14px; min-width: 9ch; }
.vs-setup .difficulty.two-rows { flex-wrap: wrap; justify-content: center; max-width: 100%; }
.vs-setup #vs-options-row button { font-size: 12px; padding: 6px 10px; }
/* The game mode, and its target score or starting points: − TARGET 2,000 + (NO TARGET for CLASSIC, as
   bright as the rest) */
.vs-goal-row { display: flex; align-items: center; gap: 8px; }
.vs-goal-row button {
  width: 26px; height: 24px; padding: 0; font-family: inherit; font-size: 14px; line-height: 1; letter-spacing: 0;
  background: transparent; border: 1px solid var(--fg); border-radius: 4px; color: var(--fg); cursor: pointer;
}
@media (hover: hover) { .vs-goal-row button:hover { background: rgba(var(--fg-rgb), 0.15); } }
.vs-goal { min-width: 13ch; font-size: 12px; letter-spacing: 1px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }

/* VS setup: a notice above the title (a locked bot or level), fading in and pulsing like the
   game's warnings, then bursting into pixels (script.js) */
.vs-setup-msg { margin: 0; min-height: 1.3em; max-width: 100%; white-space: nowrap; overflow: hidden; font-size: 12px; letter-spacing: 1px; color: var(--accent); text-shadow: 0 0 6px var(--accent); visibility: hidden; }
.vs-setup-msg.show { visibility: visible; animation: alarm-in 0.25s ease-out, warn-pulse 1s ease-in-out 0.25s infinite; }

/* Tablets and phones: no double-tap zoom (it threw the layout off on iPad) */
html { touch-action: manipulation; }
.cpu-stat { overflow: hidden; }

/* MUSIC PLAYER: the soundtrack on its own, over the whole page (player.js) */
.music-player {
  position: fixed; inset: 0; z-index: 100; display: flex; justify-content: center;
  overflow-y: auto; overscroll-behavior: contain;
  background: radial-gradient(ellipse at center, var(--bg-center) 0%, var(--bg-solid) 100%);
  animation: pause-in 0.2s ease-out;
}
.music-player[hidden] { display: none; }
body.player-open { overflow: hidden; }
/* (laid exactly over the game (player.js's fitCard), 8px in from the screen's edges like it, the head
   staying put and what's under it scrolling, as the game's own cards do) */
.music-player { overflow: hidden; padding: 0; box-sizing: border-box; }
.mp-inner {
  display: flex; flex-direction: column; align-items: stretch; gap: 12px; overflow: hidden;
  width: 100%; max-width: 480px; height: 100%; box-sizing: border-box;
  padding: 8px 8px 0;
}
/* (its head as the game's cards': BACK top left, the title beside it) */
.mp-head { margin-bottom: 0; flex: none; }
.mp-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 14px; padding-bottom: 20px; }
.mp-title { font-size: 13px; letter-spacing: 2px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
@media (hover: hover) { .mp-close:hover { background: rgba(var(--fg-rgb), 0.12); } }
.mp-viz {
  display: block; width: 100%; height: min(38vh, 300px); padding: 0; cursor: pointer;
  border: 1px solid var(--grid-line); border-radius: 6px; background: var(--inset-bg);
}
.mp-viz { position: relative; overflow: hidden; flex-shrink: 0; } /* (its full height whatever's open under it) */
.mp-viz canvas { display: block; width: 100%; height: 100%; }
/* The style's name, top left; TAP TO SWITCH, top right */
.mp-viz-name, .mp-viz-hint { position: absolute; top: 6px; font-family: inherit; font-size: 10px; letter-spacing: 1px; pointer-events: none; }
.mp-viz-name { left: 8px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
.mp-viz-hint { right: 8px; color: var(--fg-dim); }
/* The styles drawer: an arrow just under the visualizer's lower left, pulling out every style */
.mp-viz-drawer-wrap { position: relative; z-index: 5; margin-top: -15px; display: flex; justify-content: space-between; padding: 0 10px; }
/* FULL SCREEN: the visualizer over everything, edge to edge; its name and the way out show a moment
   after each touch */
.music-player.viz-full .mp-viz { position: fixed; inset: 0; z-index: 210; width: 100vw; height: 100vh; height: 100dvh; border: 0; border-radius: 0; background: var(--bg-solid); }
.music-player.viz-full .mp-viz-hint { display: none; }
.music-player.viz-full .mp-viz-name { top: max(10px, env(safe-area-inset-top)); left: 12px; transition: opacity 0.6s ease; }
.music-player.viz-full.viz-calm .mp-viz-name { opacity: 0; }
/* Play / pause, flashing up in the middle of the full screen visualizer */
.mp-viz-flash {
  position: absolute; left: 50%; top: 50%; width: 76px; height: 76px; margin: -38px 0 0 -38px; display: grid; place-items: center;
  color: var(--fg); background: rgba(0, 0, 0, 0.45); border: 1px solid var(--fg-dim); border-radius: 50%; opacity: 0; pointer-events: none;
}
.mp-viz-flash svg { width: 32px; height: 32px; }
.mp-viz-flash .mp-flash-pause, .mp-viz-flash.paused .mp-flash-play { display: none; }
.mp-viz-flash.paused .mp-flash-pause { display: block; }
.mp-viz-flash.show { animation: mp-flash 0.9s ease-out; }
@keyframes mp-flash { 0% { opacity: 0; transform: scale(0.8); } 15% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(1.15); } }
.mp-viz-exit {
  position: fixed; z-index: 211; top: max(8px, env(safe-area-inset-top)); right: 10px; width: 40px; height: 40px;
  display: grid; place-items: center; padding: 0; cursor: pointer; color: var(--fg); background: rgba(0, 0, 0, 0.45);
  border: 1px solid var(--fg-dim); border-radius: 6px; transition: opacity 0.6s ease;
}
.mp-viz-exit[hidden] { display: none; }
.music-player.viz-calm .mp-viz-exit { opacity: 0; pointer-events: none; }
.mp-drawer-btn {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 8px 4px 6px; cursor: pointer;
  font-family: inherit; font-size: 10px; letter-spacing: 1px; color: var(--fg); background: var(--inset-bg);
  border: 1px solid var(--grid-line); border-top: 0; border-radius: 0 0 5px 5px;
  margin-top: 0; padding-top: 5px; /* (a tab: its sides run up into the visualizer's border) */
}
.mp-drawer-btn svg { transition: transform 0.2s ease; }
.mp-source-btn::before { content: 'SOURCE: '; color: var(--fg-dim); }
.mp-source-btn.other { color: var(--accent); }
.mp-source-btn[hidden] { display: none; } /* (no other source: the Google Play RELEASE app) */
.mp-drawer-btn[aria-expanded="true"] svg { transform: rotate(180deg); }
.mp-viz-drawer {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 6; /* (over the controls below, not pushing them down) */
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; padding: 8px;
  background: var(--bg-solid); border: 1px solid var(--grid-line); border-radius: 6px; box-shadow: 0 10px 24px rgba(0, 0, 0, 0.6);
  animation: mp-drawer-in 0.18s ease-out;
}
.mp-viz-drawer[hidden] { display: none; }
.mp-viz-group { grid-column: 1 / -1; font-size: 9px; letter-spacing: 2px; color: var(--accent); padding: 6px 2px 0; } /* (a group's heading among the styles) */
.mp-viz-group:first-child { padding-top: 0; }
/* (SETTINGS, under the styles: the style showing's own; vizSettingsPanel in viz.js) */
.mp-viz-set { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 6px; margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--grid-line); font-size: 9px; letter-spacing: 1px; color: var(--fg-dim); }
.mp-viz-set[hidden] { display: none; }
.mp-viz-set .viz-set-head { color: var(--accent); letter-spacing: 2px; }
.mp-viz-set .viz-set-row { display: flex; align-items: center; gap: 6px; }
.mp-viz-set .viz-set-name { width: 92px; flex: none; color: var(--fg); }
.mp-viz-set input { width: 68px; font-family: inherit; font-size: 12px; color: var(--fg); background: transparent; border: 1px solid var(--fg-dim); border-radius: 4px; padding: 4px 6px; }
.mp-viz-set .viz-set-live { margin-left: auto; }
.music-player .mp-viz-drawer .viz-set-toggle { padding: 4px 10px; font-size: 10px; }
.music-player .mp-viz-drawer .viz-set-toggle.on { color: var(--accent); border-color: var(--accent); }
.mp-viz-set .viz-set-btns { display: flex; gap: 4px; justify-content: flex-end; }
.music-player .mp-viz-drawer .viz-set-btns button { padding: 4px 7px; }
.mp-viz-drawer button:disabled { opacity: 0.4; cursor: default; }
@keyframes mp-drawer-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.mp-viz-drawer button {
  padding: 6px 4px; cursor: pointer; font-family: inherit; font-size: 9px; letter-spacing: 1px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; color: var(--fg-dim); background: transparent;
  border: 1px solid var(--grid-line); border-radius: 4px;
}
.music-player .mp-viz-drawer button.active { color: var(--accent); border-color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
@media (hover: hover) { .mp-viz-drawer button:hover { color: var(--fg); border-color: var(--fg-dim); } }
.mp-now { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.mp-label { font-size: 10px; letter-spacing: 2px; color: var(--fg-dim); }
/* (GENERATED's SONG CODE: copy the one playing, or enter one) */
.mp-code { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px; min-height: 26px; }
.mp-code-btn { font-family: inherit; font-size: 10px; letter-spacing: 1px; padding: 4px 8px; cursor: pointer; background: transparent; color: var(--fg-dim); border: 1px solid var(--grid-line); border-radius: 4px; }
.mp-code-btn.code { color: var(--accent); border-color: rgba(var(--fg-rgb), 0.35); }
.mp-code-form { display: flex; gap: 6px; }
.mp-code-form[hidden] { display: none; }
.mp-code-form input { width: 120px; font-family: inherit; font-size: 12px; letter-spacing: 1px; text-transform: uppercase; padding: 4px 6px; background: transparent; color: var(--fg); border: 1px solid var(--fg-dim); border-radius: 4px; }
.mp-code-msg { flex-basis: 100%; font-size: 10px; letter-spacing: 1px; color: var(--accent); min-height: 0; }
.mp-code-msg:empty { display: none; }
.mp-track { font-size: 20px; letter-spacing: 2px; color: var(--fg); text-shadow: 0 0 8px rgba(var(--fg-rgb), 0.5); }
.mp-transport { display: flex; justify-content: center; align-items: center; gap: 18px; }
.mp-transport button {
  display: grid; place-items: center; width: 48px; height: 48px; padding: 0; cursor: pointer;
  background: transparent; color: var(--fg); border: 1px solid var(--fg-dim); border-radius: 50%;
}
.mp-transport button svg { width: 20px; height: 20px; }
.mp-transport .mp-play { width: 64px; height: 64px; border-color: var(--fg); box-shadow: 0 0 12px rgba(var(--fg-rgb), 0.35); }
.mp-transport .mp-play svg { width: 26px; height: 26px; }
.mp-play .mp-icon-pause, .mp-play.playing .mp-icon-play { display: none; }
.mp-play.playing .mp-icon-pause { display: block; }
.mp-modes { display: flex; justify-content: center; gap: 6px; }
.mp-modes button, .mp-bg {
  font-family: inherit; font-size: 11px; letter-spacing: 1px; padding: 6px 10px; cursor: pointer;
  background: transparent; color: var(--fg); border: 1px solid var(--fg); border-radius: 4px;
}
.mp-modes button.active { background: var(--fg); color: var(--bg-solid); }
.mp-bg { align-self: center; color: var(--fg-dim); border-color: var(--grid-line); }
.mp-bg.on { color: var(--fg); border-color: var(--fg-dim); }
.mp-tracks { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; }
@media (max-width: 360px) { .mp-tracks { grid-template-columns: 1fr; } }
.mp-tracks button {
  display: flex; align-items: center; gap: 6px; width: 100%; padding: 6px 8px; box-sizing: border-box;
  font-family: inherit; font-size: 11px; letter-spacing: 1px; text-align: left; overflow: hidden;
  background: transparent; color: var(--fg); border: 1px solid var(--grid-line); border-radius: 4px; cursor: pointer;
}
.mp-tracks button.active { border-color: var(--fg); background: rgba(var(--fg-rgb), 0.12); }
.mp-tracks button.playing { box-shadow: 0 0 8px rgba(var(--fg-rgb), 0.35); }
.mp-tracks button:disabled { cursor: default; color: rgba(var(--fg-rgb), 0.3); }
.mp-tracks .mp-n { flex: none; line-height: 1.3; }
.mp-tracks .mp-t { flex: 1; min-width: 0; line-height: 1.3; }
.mp-tracks .mp-v { display: block; }
.mp-tracks .need { margin-left: auto; font-size: 9px; letter-spacing: 0; color: var(--accent); }
.mp-note { margin: 0; font-size: 10px; line-height: 1.5; text-align: center; color: var(--panel-text); opacity: 0.8; }
/* OPEN MUSIC PLAYER: the same gap above the visualizer as between the menu's other buttons */
.settings #open-player-btn { margin-bottom: 6px; }
/* The main HUD (not VS): the four small boxes one size (two equal rows): each its title 4px from its
   top edge, and its height that title, then 8px, its value (16px) and 8px (--hud-val, kept under the
   title, so a value shrunk to fit never changes it); the value itself centered between the box's top
   and bottom edges, across too. CURRENT as tall as the two boxes beside it, its title 4px from its
   top and its bit, its own size, centered in the box the same way (never up under its title, in the
   shorter box over NEXT or TIME). SCORE's story meter, along its foot, takes no room of its own */
body:not(.vs-mode) .hud { grid-template-rows: 1fr 1fr; --hud-val: 32px; }
body:not(.vs-mode) .hud > .stat:not(.cpu-stat):not(.cpu-face),
body:not(.vs-mode) .hud-bits .stat { min-height: 0; padding: 4px 2px var(--hud-val); justify-content: flex-start; }
body:not(.vs-mode) .hud .stat:not(.cpu-stat):not(.cpu-face) > .label {
  position: static; flex: none; height: auto; line-height: 1; margin: 0; text-align: center;
}
body:not(.vs-mode) .hud .stat:not(.cpu-stat):not(.cpu-face) > :is(.value, .bit-sq, .bit-row) {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); margin: 0; max-width: calc(100% - 4px);
}
/* (each value trimmed to its capitals, so its digits center by what shows, not the font's line box;
   --val-foot: how far under the middle the digits end, where the bands under them start) */
body:not(.vs-mode) .hud .stat:not(.cpu-stat):not(.cpu-face) > .value { text-box: trim-both cap alphabetic; }
body:not(.vs-mode) .hud { --val-foot: 5.5px; }
body:not(.vs-mode) .hud-bits .stat-current { padding-bottom: 0; }
/* (CURRENT's bit centered too, but never up under its title: 4px, the title's 10.5px line, 2px clear,
   then half the bit's 42px) */
body:not(.vs-mode) .hud .hud-bits .stat.stat-current:not(.cpu-stat):not(.cpu-face) > .bit-sq { top: max(50%, 37.5px); }
/* (ENCRYPT IN's ===== in the band under its 8, taking no room either) */
body:not(.vs-mode) .hud #pulse-stat > .layer-mark { top: auto; bottom: 0; height: calc(50% - var(--val-foot)); align-items: center; justify-content: center; line-height: 1; font-size: 9px; } /* (centered between the foot of its count and the box's bottom edge) */
body:not(.vs-mode) .hud #pulse-stat.counts-layers > .layer-mark { display: flex; }
/* (its = signs sit high in their line, so the band's top is taken in a little: they center in it by
   what shows) */
body:not(.vs-mode) .hud #pulse-stat > .layer-mark { box-sizing: border-box; padding-top: 1.5px; }
/* (NEXT and TIME's short panel under CURRENT: its words and value trimmed to their capitals, so they
   center in it by what shows, whatever the font's ascent and descent) */
body:not(.vs-mode) .hud-bits :is(#next-stat, #time-stat) > :is(.label, .value) { text-box: trim-both cap alphabetic; }
/* (CLASSIC's cycle icon: it flips to STORY, and back) */
.modes .swap-ico { width: 0.9em; height: 0.9em; margin-left: 0.4em; vertical-align: -0.1em; flex: none; }

/* VS: the drop clock, a bar along the bottom of CURRENT that runs down; red and pulsing for the
   last 2 seconds (the bit then drops by itself) */
.drop-timer { position: absolute; left: 4px; right: 4px; bottom: 3px; height: 3px; border-radius: 2px; background: rgba(var(--fg-rgb), 0.15); overflow: hidden; }
.drop-timer[hidden] { display: none; }
/* INFECTED: the little bot at its laptop, in CURRENT's corner */
.inf-badge { position: absolute; right: 4px; bottom: 7px; display: flex; align-items: flex-end; gap: 2px; pointer-events: auto; font-style: normal; }
.inf-badge[hidden] { display: none; }
.inf-badge svg { width: 24px; height: 12px; display: block; }
.inf-badge b { font-weight: normal; font-size: 8px; line-height: 8px; color: var(--danger); }
.inf-badge .ib-H, .inf-badge .ib-A { fill: var(--fg); }
.inf-badge .ib-E { fill: var(--board-bg); }
.inf-badge .ib-S, .inf-badge .ib-K { fill: var(--fg-dim); }
.inf-badge .ib-R { fill: var(--danger); animation: ib-blink 0.9s steps(1) infinite; }
.inf-badge .ib-a1 { animation: ib-type 0.32s steps(1) infinite; }
.inf-badge .ib-a2 { animation: ib-type 0.32s steps(1) infinite reverse; }
@keyframes ib-blink { 50% { opacity: 0.25; } }
@keyframes ib-type { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .inf-badge .ib-R, .inf-badge .ib-a1, .inf-badge .ib-a2 { animation: none; } .inf-badge .ib-a2 { opacity: 0; } }
.drop-timer::after { content: ''; position: absolute; inset: 0; transform-origin: left; transform: scaleX(var(--left, 1)); background: var(--fg); transition: transform 0.1s linear; }
.drop-timer.low::after { background: var(--danger); animation: warn-pulse 0.5s ease-in-out infinite; }
/* The CPU's attack still charging: hollow pips, and your own charging attack by its score */
.incoming .pips i.charging { background: transparent; box-shadow: inset 0 0 0 1px currentColor; }
.cpu-label .charging, #cpu-label .charging { color: var(--accent); animation: warn-pulse 0.6s ease-in-out infinite; }

/* TUTORIAL: the button beside the RULES title, the banner over the board, and whatever the
   banner is talking about pulsing */
.panel h2.rules-head { display: flex; align-items: center; gap: 12px; }
/* RULES' sections, each under a ===== line, a head as EXPLOITS' tiers have */
.panel-rules .rules-sub { margin: 0 0 4px; font-size: 15.5px; letter-spacing: 2px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
.panel-rules .store-rule + .rules-sub { margin-top: 0; }
.tut-open {
  font-family: inherit; font-size: 11px; letter-spacing: 1px; padding: 4px 10px; cursor: pointer; text-shadow: none;
  background: transparent; color: var(--accent); border: 1px solid var(--accent); border-radius: 4px;
}
.tut-open.danger { color: var(--danger); border-color: var(--danger); }
.tut-banner {
  position: absolute; left: 13px; right: 13px; top: 6px; z-index: 7; max-height: calc(100% - 12px);
  display: flex; flex-direction: column; /* (as wide as the grid: the chain meter shows beside it) */
  color: var(--panel-text); font-size: 12px; line-height: 1.45;
  animation: pause-in 0.2s ease-out;
}
.tut-banner { pointer-events: none; } /* (only its card and buttons take taps, not the gaps) */
.tut-banner > * { pointer-events: auto; }
/* The frame: the heading, BOT and its words (BACK / NEXT sit under it, outside) */
.tut-card {
  flex: 0 1 auto; min-height: 0; overflow-y: auto;
  padding: 8px 10px 10px; border: 1px solid var(--accent); border-radius: 6px;
  background: color-mix(in srgb, var(--panel) 94%, transparent);
  box-shadow: 0 0 14px rgba(var(--accent-rgb), 0.25);
}
.tut-banner[hidden] { display: none; }
.tut-banner.bottom { top: auto; bottom: 30%; max-height: calc(70% - 12px); } /* (long text scrolls in its card, never past the frame's top) */
/* Over an open menu: fixed at the bottom of the screen, above the menus */
.tut-banner.float { position: fixed; top: auto; left: 50%; right: auto; bottom: 16px; width: min(460px, calc(100% - 32px)); transform: translateX(-50%); z-index: 1001; max-height: 45vh; }
/* (a modal over the menus: on top of them, the dim and the pulsing frames, and solid, so nothing of
   the menu under it shows through or draws across it) */
.tut-banner.float .tut-card { background: var(--panel); }
.tut-banner.float.nudge { animation: none; }
/* The tutorial's dim (tutorial.js): the screen a little darker but for what to tap and the
   banner; see-through to taps, fading over 0.25s */
.tut-dim { position: fixed; inset: 0; z-index: 250; background: rgba(0, 0, 0, 0.5); opacity: 0; pointer-events: none; transition: opacity 0.25s ease; }
.tut-dim.on { opacity: 1; }
.tut-banner.float.middle { top: 50%; bottom: auto; transform: translate(-50%, -50%); }
/* (over the main menu: from the top of the EXPLOITS / STORE row, down) */
.tut-banner.float.anchored { top: var(--tut-top); bottom: auto; max-height: calc(100dvh - var(--tut-top) - 16px); }
/* The menu buttons are dim until opened: pulsing in the tutorial, they light up full */
:is(.records-btn, .settings-btn).tut-pulse { opacity: 1; filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6)); }
.tut-banner.nudge { animation: tut-nudge 0.3s ease-out; }
@keyframes tut-nudge { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
.tut-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; font-size: 10px; letter-spacing: 2px; color: var(--accent); }
.tut-exit { font-family: inherit; font-size: 10px; letter-spacing: 1px; padding: 2px 8px; cursor: pointer; background: transparent; color: var(--fg-dim); border: 1px solid var(--grid-line); border-radius: 3px; }
.tut-text { margin: 0; line-height: calc(0.62em + 8px); } /* (8px between one line's letters and the next's) */
/* The points a drop made, line by line: the bits, what each is worth, the multiplier, the result,
   each its own color */
.tut-points { margin: 8px 0 0; font-family: inherit; font-size: 14.5px; line-height: calc(0.62em + 8px); color: var(--fg-dim); letter-spacing: 0; }
.tut-points > div { white-space: nowrap; }
.tut-points .tp-bits { color: var(--fg); }
.tut-points .tp-sum { color: var(--fg-dim); }
.tut-points .tp-x { color: var(--accent); }
.tut-points .tp-eq { color: var(--panel-text); }
.tut-points :is(.tp-bonus, .tp-total) { color: var(--accent); }
.tut-actions { flex: none; display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }
.tut-actions button {
  font-family: inherit; font-size: 12px; letter-spacing: 1px; padding: 5px 14px; cursor: pointer;
  background: var(--fg); color: var(--bg-solid); border: 1px solid var(--fg); border-radius: 4px;
}
.tut-actions button:not(.tut-back) + button { background: var(--panel); color: var(--fg); }
/* BACK: on the left, outlined */
.tut-actions button.tut-back { margin-right: auto; background: var(--panel); color: var(--fg); border-color: var(--fg-dim); }
/* THE FRAMES (tutorial.js's drawFrames): what a step points at gets a pulsing frame, all of them in one
   layer over everything (the dim, every panel and card), so nothing covers one; 4px out from what
   it frames (a roomy one 8px: words or a thin bar never touching it), the narration card's 6px
   corners, as the dim's openings have */
.tut-frames { position: fixed; inset: 0; z-index: 1000; pointer-events: none; }
.tut-frames i { position: absolute; left: 0; top: 0; border-radius: 6px; animation: tut-pulse 0.9s ease-in-out infinite; }
.tut-frames i[hidden] { display: none; }
@keyframes tut-pulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.9), 0 0 6px rgba(var(--accent-rgb), 0.5); }
  50% { box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 1), 0 0 16px rgba(var(--accent-rgb), 0.9); }
}
/* (the line under BYTEFALL framed round its words, not the screen's width) */
#game-mode-label.tut-roomy { width: fit-content; margin-left: auto; margin-right: auto; }
.overflow-line.tut-pulse { animation: warn-pulse 0.9s ease-in-out infinite !important; color: var(--accent); }
/* (the tutorial's drop buttons: full presence, as the rest of the screen, whether or not this card
   takes a drop; a tap it doesn't want gets BOT's -_- instead) */
.column-buttons.tut-full button:disabled { opacity: 1; cursor: default; }

/* START SCREEN: a card filling the screen, the starlight twinkling across it, the title in the
   middle and TAP TO START blinking below. Tapping fades everything to black (.start-black), then
   the black fades away off the game. (Hidden before first paint on a refresh: html.no-start.) */
.start-screen {
  position: fixed; inset: 0; z-index: 200; display: flex; padding: 0;
  background: radial-gradient(ellipse at center, var(--bg-center) 0%, var(--bg-solid) 100%);
  -webkit-tap-highlight-color: transparent; outline: none;
}
html.no-start .start-screen, .start-screen[hidden] { display: none; }
.start-card {
  position: relative; flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  overflow: hidden; isolation: isolate;
  background: var(--board-bg);
}
.start-bg, .arcade-bg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
.start-title { text-align: center; }
.start-title h1 { font-size: clamp(34px, 11vw, 64px); letter-spacing: 0.18em; margin-right: -0.18em; }
.start-tagline { margin: 10px 0 0; font-size: 12px; letter-spacing: 3px; color: var(--fg-dim); }
.start-btn {
  position: absolute; left: 50%; bottom: 22%; transform: translateX(-50%); cursor: pointer;
  padding: 10px 34px; font-family: inherit; font-size: 16px; letter-spacing: 5px;
  /* (a neon sign: the tube's core near white, the theme's color glowing round it, inside and out) */
  background: rgba(var(--fg-rgb), 0.06); color: rgb(var(--burst-hot-rgb)); border: 2px solid var(--fg); border-radius: 6px;
  text-shadow: 0 0 2px rgba(var(--fg-rgb), 0.9), 0 0 8px var(--fg), 0 0 18px rgba(var(--fg-rgb), 0.6);
  box-shadow: 0 0 12px rgba(var(--fg-rgb), 0.45), inset 0 0 10px rgba(var(--fg-rgb), 0.3);
  animation: start-glow 1.6s ease-in-out infinite;
}
/* (unseen till index.html's placeStartBtn has put it under the tagline, so it never shows here first) */
.start-btn:not(.placed) { visibility: hidden; }
.start-btn:focus-visible { background: rgba(var(--fg-rgb), 0.18); outline: none; }
@media (hover: hover) { .start-btn:hover { background: rgba(var(--fg-rgb), 0.18); outline: none; } }
@keyframes start-glow { 0%, 100% { box-shadow: 0 0 8px rgba(var(--fg-rgb), 0.3), inset 0 0 6px rgba(var(--fg-rgb), 0.2); } 50% { box-shadow: 0 0 22px rgba(var(--fg-rgb), 0.65), inset 0 0 12px rgba(var(--fg-rgb), 0.4); } }
/* (after the title's intro: START flickering on like a neon sign, the tube catching, dropping out and
   catching again before it holds, then glowing as ever) */
.start-btn.neon { animation: neon-on 1.4s steps(1, end) both, start-glow 1.6s ease-in-out 1.4s infinite; }
@keyframes neon-on {
  0% { opacity: 0; } 5% { opacity: 0.12; } 10% { opacity: 1; } 13% { opacity: 0.12; } 28% { opacity: 1; } 30% { opacity: 0.12; }
  34% { opacity: 0.9; } 39% { opacity: 0.3; } 44% { opacity: 1; } 47% { opacity: 0.12; } 60% { opacity: 1; } 62% { opacity: 0.5; } 65%, 100% { opacity: 1; }
}
@keyframes start-blink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }
.start-screen.starting .start-btn { animation: start-blink 0.16s steps(1) infinite; }
/* START → the game: the start card's contents fade out, its border staying (laid exactly over the game
   card's: start.js's fitStart), and the game card's contents fade in inside the same border */
.start-card > * { transition: opacity 0.6s ease; }
.start-card.leaving > *, .start-card.entering > * { opacity: 0; transition-duration: 0.6s; }
.start-card.entering > * { transition: none; }
.start-card { transition: background-color 0.6s ease; }
.start-card.leaving { background-color: var(--panel); }
.crt.card-in > :not(.card-lights) { animation: card-in 0.6s ease both; }
@keyframes card-in { from { opacity: 0; } }
.crt.card-out > :not(.card-lights) { opacity: 0; transition: opacity 0.6s ease; }
.start-black { position: fixed; inset: 0; z-index: 210; background: #000; opacity: 0; pointer-events: none; transition: opacity 0.6s ease; }
.start-black.on { opacity: 1; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) { .start-btn, .start-btn.neon { animation: none; } }
/* THE TITLE's INTRO (start.js): the title, its tagline and START unseen from the first paint till it
   plays (and shown anyway after 5s, should it never start). It plays on a copy of the title laid over
   the real one, which never moves; START shows as it flickers on */
.start-card:is(.intro-wait, .intro-run) > .start-title:not(.start-intro) { visibility: hidden; }
.start-card:is(.intro-wait, .intro-run) .start-btn:not(.neon) { visibility: hidden; }
.start-card.intro-wait > .start-title, .start-card.intro-wait .start-btn { animation: intro-failsafe 0s linear 5s forwards; }
@keyframes intro-failsafe { to { visibility: visible; } }
.start-title.start-intro { position: absolute; margin: 0; pointer-events: none; }
.start-intro h1 { white-space: nowrap; } /* (its letters split into boxes of their own mustn't wrap) */
.start-intro h1 .intro-l { display: inline-block; color: inherit; text-shadow: inherit; }
.start-intro h1 .intro-l.scrambled { color: var(--fg-dim); text-shadow: none; }
.start-intro .intro-cursor { color: transparent; background: var(--fg-dim); }
.start-intro .intro-rest { visibility: hidden; }
/* (BIT's ghosts: copies of the title left behind as it falls, and where it lands, fading) */
.start-intro .intro-ghost { position: absolute; margin: 0; opacity: 0; white-space: nowrap; pointer-events: none; filter: blur(0.6px); }
/* (DROP's landing: an amber band out from under the title, bursting into pixels and binary dust) */
.intro-band { position: absolute; height: 8px; border-radius: 2px; background: var(--accent); box-shadow: 0 0 10px var(--accent), 0 0 24px rgba(var(--accent-rgb), 0.7); transform: scaleX(0); }

/* MINI BOTS (minibot.js): the CPU's face, small, anywhere (the tutorial's narrator, the start
   screen's wanderers) */
.cpu-face.mini-bot { display: block; padding: 0; background: none; border: none; }
.mini-bot .cpu-bot { display: block; width: 100%; height: auto; max-height: none; }
/* Talking: the mouth opens and shuts, whatever the mood's own mouth */
.cpu-face.talking .mouth { display: none !important; }
.cpu-face.talking .mouth-open { display: inline !important; animation: bot-talk 0.16s steps(1) infinite; }
@keyframes bot-talk { 0% { opacity: 1; } 50% { opacity: 0; } }
/* The tutorial's narrator: BOT beside what it says */
/* BOT in the corner, its words wrapping around it and on under it (flow-root: the card holds it) */
.tut-body { display: flow-root; }
.tut-bot { float: left; width: 36px; margin: 2px 10px 2px 0; }
.tut-body .tut-text { cursor: pointer; white-space: pre-line; } /* (a step's text can break into lines) */

/* The start screen's wanderers: along the bottom of the card, walking in and out of it */
/* (the whole card: the bots walk along its bottom, and what flies, falls or hangs uses all of it) */
.start-walkers { position: absolute; left: 0; right: 0; top: 0; bottom: 10px; pointer-events: none; }
/* (a wanderer walking in or out past a lane's sides is cut off there, not counted toward the page's
   width: no scroll bar flickering on as it goes; open above and below, for what they say) */
:is(.start-walkers, .game-walkers, .saver-lane) { overflow-x: clip; overflow-y: visible; }
.start-title { position: relative; z-index: 1; } /* (the spider drops behind the title) */
.start-btn { z-index: 2; } /* (START over October's forest too: the trees' own layer, the HOLLOW's, sits under it) */
:is(.start-walkers, .game-walkers) .walker { position: absolute; left: 0; bottom: 0; width: 34px; will-change: transform; }
.walker.walking .bot { animation: bot-hop 0.28s steps(2) infinite; }
.walker.walking .leg-a { animation: bot-step 0.28s steps(1) infinite; }
.walker.walking .leg-b { animation: bot-step 0.28s steps(1) 0.14s infinite; }
.walker-emote {
  position: absolute; left: 50%; bottom: 100%; transform: translate(-50%, 2px); margin-bottom: 2px;
  font-size: 11px; letter-spacing: 0; color: var(--accent); text-shadow: 0 0 6px var(--accent);
  opacity: 0; transition: opacity 0.15s, transform 0.15s; white-space: nowrap;
}
.walker-emote.show { opacity: 1; transform: translate(-50%, 0); }
.tut-text .unsaid { visibility: hidden; }

/* The extra moods. SCARED: trembling fast, sweating; TIRED: heaving, panting, sweating; SURPRISED:
   a jump; LOVE: red heart eyes, beating; DIZZY: swaying; LAUGH: shaking with it */
.cpu-face[data-mood="scared"] .bot { animation: bot-shake 0.08s steps(2) infinite; }
.cpu-face[data-mood="scared"] .sweat { animation: bot-sweat 0.6s steps(4) infinite; }
.cpu-face[data-mood="tired"] .bot { animation: bot-heave 0.7s steps(2) infinite; }
.cpu-face[data-mood="tired"] .sweat { animation: bot-sweat 1.1s steps(4) infinite; }
.cpu-bot .pant-low { animation: bot-talk 0.35s steps(1) infinite; }
.cpu-face[data-mood="surprised"] .bot { animation: bot-hop 0.2s steps(2) 2; }
.cpu-bot .eyes-heart { fill: var(--danger); }
.cpu-face[data-mood="love"] .eyes-heart { animation: bot-beat 0.6s steps(1) infinite; transform-origin: 8px 6px; }
.cpu-face[data-mood="dizzy"] .bot { animation: bot-sway 0.9s steps(4) infinite; transform-origin: 8px 15px; }
.cpu-face[data-mood="laugh"] .bot { animation: bot-hop 0.16s steps(2) infinite; }
@keyframes bot-heave { 0% { transform: translateY(0); } 50% { transform: translateY(1px); } }
@keyframes bot-beat { 0%, 60% { transform: scale(1); } 61%, 100% { transform: scale(1.12); } }
@keyframes bot-sway { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-6deg); } 75% { transform: rotate(6deg); } }
/* Wanderers look where they're going (their eyes and mouth a pixel that way) */
.walker[data-look="right"] .bot-face { animation: none; transform: translateX(1px); }
.walker[data-look="left"] .bot-face { animation: none; transform: translateX(-1px); }
.walker.running .bot { animation: bot-hop 0.14s steps(2) infinite; }
/* HEADPHONES (wanderers.js): standing, eyes closed, nodding on the kicks or tapping a foot on the
   hats; walking, its steps on the beat (two to a beat); --beat and --beat-at set from the music */
.walker.grooving .eyes { display: none !important; }
.walker.grooving .eyes-squint { display: inline !important; }
/* (standing, its own moves come from the drums, wanderers.js: no mood's bounce under them) */
.walker.grooving :is(.bot, .leg-a, .leg-b) { animation: none !important; }
.walker.grooving .bot { transform-box: fill-box; transform-origin: 50% 60%; }
.walker.vibing.walking:not(.running) .bot { animation: bot-hop calc(var(--beat, 0.56s) / 2) steps(2) var(--beat-at, 0s) infinite; }
.walker.vibing.walking:not(.running) .leg-a { animation: bot-step calc(var(--beat, 0.56s) / 2) steps(1) var(--beat-at, 0s) infinite; }
.walker.vibing.walking:not(.running) .leg-b { animation: bot-step calc(var(--beat, 0.56s) / 2) steps(1) calc(var(--beat-at, 0s) + var(--beat, 0.56s) / 4) infinite; }
.walker.running .leg-a { animation: bot-step 0.14s steps(1) infinite; }
.walker.running .leg-b { animation: bot-step 0.14s steps(1) 0.07s infinite; }

/* Wanderers: a hop or two (--hops), popping into view pixelated, and decrypting away */
.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.walker.hopping .bot { animation: walker-hop 0.36s ease-out var(--hops, 1); }
@keyframes walker-hop { 0%, 100% { transform: translateY(0); } 45% { transform: translateY(-3px); } }
.walker.pop-in .bot-swap { animation: walker-pix-in 0.45s steps(1) forwards; }
.walker.pix-out .bot-swap { animation: walker-pix-out 0.45s steps(1) forwards; }
@keyframes walker-pix-in {
  0% { filter: url(#mini-pix4) blur(0.2px); opacity: 0.3; }
  33% { filter: url(#mini-pix4); opacity: 0.75; }
  66% { filter: url(#mini-pix2); opacity: 1; }
  100% { filter: none; opacity: 1; }
}
@keyframes walker-pix-out {
  0% { filter: url(#mini-pix2); opacity: 1; }
  33% { filter: url(#mini-pix4); opacity: 0.85; }
  66% { filter: url(#mini-pix4) blur(0.15px); opacity: 0.5; }
  100% { filter: url(#mini-pix4) blur(0.25px); opacity: 0; }
}
/* (the particles show over the start screen while it's up: a wanderer's decrypt burst) */
.start-screen:not([hidden]) ~ #board-fx { z-index: 205; }

/* Poking a wanderer: it can be tapped; shaking itself off with a puff of dust */
:is(.start-walkers, .game-walkers) .walker { pointer-events: auto; cursor: pointer; touch-action: manipulation; }
.cpu-face.shaking .bot { animation: walker-shake 0.1s steps(2) 7; }
/* The VS CPU's face can be poked too */
#cpu-face { position: relative; cursor: pointer; -webkit-tap-highlight-color: transparent; }
@keyframes walker-shake { 0% { transform: translateX(-1px); } 100% { transform: translateX(1px); } }
.walker-dust {
  position: absolute; left: 50%; top: 55%; width: 4px; height: 4px; background: var(--bot); box-shadow: 0 0 3px var(--bot); pointer-events: none;
  animation: walker-dust 0.6s ease-out forwards;
}
@keyframes walker-dust { 0% { transform: translate(0, 0); opacity: 0.9; } 100% { transform: translate(var(--dx), var(--dy)); opacity: 0; } }
/* WINTER skaters: blades under the feet, a lean into the glide and long pushes off each leg, no
   hop; the powder they kick up lies on the lane and melts away */
.walker.skater .skate-blade { fill: #cfd8e6 !important; }
.walker.skater.walking .bot { animation: none; transform: rotate(7deg); transform-origin: 50% 100%; }
.walker.skater.walking[data-look="left"] .bot { transform: rotate(-7deg); }
.walker.skater.walking .leg-a { animation: skate-push 0.76s ease-in-out infinite; }
.walker.skater.walking .leg-b { animation: skate-push 0.76s ease-in-out -0.38s infinite; }
.walker.skater.walking[data-look="left"] :is(.leg-a, .leg-b) { animation-name: skate-push-left; }
@keyframes skate-push { 0%, 100% { transform: translate(0, 0); } 40% { transform: translate(-2px, -1px); } }
@keyframes skate-push-left { 0%, 100% { transform: translate(0, 0); } 40% { transform: translate(2px, -1px); } }
.skate-powder {
  position: absolute; left: 0; bottom: 0; width: 2px; height: 2px; background: #e8eef7; box-shadow: 0 0 2px rgba(232, 238, 247, 0.7);
  pointer-events: none; animation: skate-melt 3s ease-in forwards;
}
@keyframes skate-melt { 0% { opacity: 0.95; } 60% { opacity: 0.6; } 100% { opacity: 0; } }
[data-theme="paper"] .skate-powder, [data-theme="daylight"] .skate-powder { background: #9fb0c8; box-shadow: none; }
/* (achievement pop-ups show over the start screen too) */
/* The game card's wanderers: along its bottom edge between the corner buttons, coming and going from behind them */
.game-walkers { position: absolute; left: 0; right: 0; bottom: 6px; height: 44px; pointer-events: none; z-index: 0;
  clip-path: inset(-60px 0 -6px 0); } /* (hidden past its sides, where they walk in and out behind the corner buttons; open above, for what they say) */
.corner-btn { z-index: 1; }
/* The drop buttons and the message under the grid: a layer over the wanderers' lane (bats, crows,
   the spider's thread and the rest pass under them) */
.column-buttons, .message-slot { position: relative; z-index: 2; }
/* DROP BY: BOTH (script.js): the grid takes the touch too, and the bit being aimed rides the top
   row over its column, its button lit */
.column-buttons button.aimed { background: rgba(var(--fg-rgb), 0.25); border-color: var(--fg); }
.board.touch-drop { touch-action: none; cursor: pointer; -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none; }
.board .cell.pivot-arrow { color: var(--accent); text-shadow: 0 0 6px var(--accent); }
.board .drag-ghost { position: absolute; margin: 0; pointer-events: none; opacity: 0.9; z-index: 1; }
/* The restart corner button is EXIT (back to the title card) until the first drop */
.restart-icon .exit-glyph, .restart-icon.exit .restart-glyph { display: none; }
.restart-icon.exit .exit-glyph { display: block; }
/* No tap box (highlight, focus ring, text selection) around a poked bot or visitor */
:is(.start-walkers, .game-walkers) :is(.walker, .visitor) { -webkit-tap-highlight-color: transparent; outline: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }

/* Dev: AD BANNER PREVIEW (script.js). The page's height (--app-h) already leaves the strip out; the
   transform makes the body the frame for fixed layers (start screen, overlays, particles), so they
   stay clear of the strip too. */
html.strip-preview body { transform: translate(0, 0); }
html.strip-preview #board-fx { height: 100%; }
html:not(.strip-preview) .strip-preview-bar, .strip-preview-bar[hidden] { display: none; }
.strip-preview-bar {
  position: fixed; top: 100%; left: 0; right: 0; height: var(--strip-h, 50px); z-index: 10000;
  display: flex; align-items: center; justify-content: center;
  background: #8a8a8a; color: #3a3a3a; border-top: 1px solid #b0b0b0;
  font: 11px/1 monospace; letter-spacing: 2px; pointer-events: none;
}
/* At the top (the default): the body moves down under the strip, which hangs just above it */
html.strip-preview.strip-top body { margin-top: var(--strip-h); }
html.strip-top .strip-preview-bar { top: auto; bottom: 100%; border-top: 0; border-bottom: 1px solid #b0b0b0; }

/* Dev: TWINKLE BACKGROUND (grid-bg.js). The starlight twinkling across the whole screen behind the
   game card (and its menus), in place of the plain gradient */
.page-bg { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; display: none; }
html.page-twinkle .page-bg { display: block; }

/* FIXED BUTTONS (script.js's lockButtons): measured in COURIER, then locked to that width in every
   font; their labels stay on one line */
.ref-font, .ref-font * { font-family: 'Courier New', Courier, monospace !important; }
:is(.modes, .difficulty, .records-tabs) button, #vs-layers-btn, #vs-exploits-btn, #vs-start, #pause-resume,
#overlay-restart-btn, #overlay-replay-btn, #overlay-share-btn { white-space: nowrap; }
/* The FONT and THEME notes change with the pick: each keeps room for its longest (3 and 4 lines in
   Courier), so picking one never moves what's below */
#font-note { min-height: 3lh; }
#theme-note { min-height: 4lh; }

/* STORE (store.js): the MENU's fourth tab, cards like the exploits', and RESTORE PURCHASES */
.panel-store .store-preview { font-size: 13px; letter-spacing: 1px; color: var(--accent); }
.store-item {
  border: 1px dashed var(--grid-line); border-radius: 4px; padding: 8px 10px; margin-top: 10px;
  display: flex; flex-direction: column; gap: 6px;
}
.store-item h3 { margin: 0; display: flex; align-items: baseline; font-size: 17px; letter-spacing: 1px; color: var(--fg); }
.store-item p { margin: 0; font-size: 14.5px; }
.store-price { margin-left: auto; font-size: 15.5px; color: var(--accent); }
.store-item .store-upgrade { color: var(--accent); } /* (FULL ACCESS for a REMOVE ADS owner: the upgrade) */
.store-buy, .store-restore {
  font-family: inherit; font-size: 12px; letter-spacing: 2px; padding: 6px 16px; cursor: pointer;
  background: rgba(var(--accent-rgb), 0.08); color: var(--accent); border: 1px solid var(--accent); border-radius: 4px;
}
.store-buy { align-self: flex-end; }
@media (hover: hover) { .store-buy:hover:not(:disabled), .store-restore:hover { background: rgba(var(--accent-rgb), 0.18); } }
.store-item.owned { border-style: solid; border-color: var(--fg-dim); }
.store-item.owned .store-price { color: var(--fg); }
.store-buy:disabled { cursor: default; color: var(--fg); border-color: var(--fg-dim); background: none; }
.store-item.flash { animation: store-flash 1.2s ease-out; }
@keyframes store-flash { 0%, 30% { border-color: var(--accent); box-shadow: 0 0 14px rgba(var(--accent-rgb), 0.5); } 100% { box-shadow: none; } }
/* (room for a message, so RESTORE PURCHASES never moves) */
.store-msg { min-height: 2lh; margin: 10px 0 6px !important; font-size: 14.5px; letter-spacing: 1px; color: var(--accent); text-align: center; }
.store-restore { display: block; width: 100%; color: var(--fg); border-color: var(--fg-dim); background: none; }
.panel-store .store-restore { margin: var(--gap) 0; } /* (the one gap above and below it, as between the cards) */
.panel-store .store-note { margin: 8px 0 0; font-size: 13px; color: var(--fg-dim); }
/* REMOVE ADS: a quiet link at the foot of the menu's other tabs */
.store-shortcut {
  display: flex; align-items: center; justify-content: center; gap: 6px; margin: 10px auto 0; padding: 5px 12px;
  font-family: inherit; font-size: 11px; letter-spacing: 2px; cursor: pointer;
  background: none; color: var(--accent); border: 1px dashed rgba(var(--accent-rgb), 0.6); border-radius: 4px;
}
.store-shortcut svg { width: 15px; height: 15px; }
.store-buy, .store-restore, .store-shortcut, .menu-tabs button { white-space: nowrap; }
@media (hover: hover) { .store-shortcut:hover { background: rgba(var(--accent-rgb), 0.1); } }
.store-shortcut[hidden] { display: none; }

/* START SCREEN credits: the studio at the top, the copyright above the wanderers */
.start-studio {
  position: absolute; top: 28px; left: 0; right: 0; margin: 0; text-align: center;
  font-size: 11px; letter-spacing: 4px; color: var(--fg-dim);
}
.start-studio span { display: block; margin-top: 6px; font-size: 9px; letter-spacing: 3px; opacity: 0.7; }
.start-legal {
  position: absolute; left: 12px; right: 12px; bottom: 64px; text-align: center; pointer-events: none;
  font-size: 9px; letter-spacing: 1px; line-height: 1.6; color: var(--fg-dim); opacity: 0.8;
}
.start-legal p { margin: 0; }

/* A mad wanderer poked (wanderers.js's rabid): a hard head shake, then snapping at you like a
   rabid dog, lunging forward with its jaw chomping open and shut */
:is(.walker, #cpu-face).headshaking .bot { animation: walker-headshake 0.16s steps(2) 4; }
@keyframes walker-headshake { 0% { transform: translateX(-1px); } 100% { transform: translateX(1px); } } /* (whole pixels of its grid, no tilt) */
:is(.walker, #cpu-face).snapping .bot { transform-origin: 50% 80%; animation: walker-lunge 0.2s steps(2) 3; }
@keyframes walker-lunge { 0% { transform: scale(1.22) translateY(1px); } 100% { transform: scale(1); } }
:is(.walker, #cpu-face).snapping .mouth-teeth { transform-box: fill-box; transform-origin: 50% 0; animation: walker-jaw 0.2s steps(2) 3; }
@keyframes walker-jaw { 0% { transform: scaleY(2); } 100% { transform: scaleY(0.5); } }

/* SEASONAL COSTUMES on the wanderers (wanderers.js): drawn over the body, under the face; the
   pumpkin and the ghost recolor the whole bot (its --bot color, glow and all) */
.walker svg { overflow: visible; } /* (the witch's hat and the devil's tail reach past the grid) */
.walker[data-costume="pumpkin"] { --bot: #ff8a1f; --bot-rgb: 255, 138, 31; }
.walker[data-costume="pumpkin"] .c-rib { fill: #c4580a; }
.walker[data-costume="pumpkin"] .c-stem { fill: #3f8f3a; }
.walker[data-costume="pumpkin"] .c-leaf { fill: #6cc24a; }
.walker[data-costume="ghost"] .costume { opacity: 0.8; filter: drop-shadow(0 0 1px rgba(238, 243, 242, 0.6)); } /* (see-through: BOT shows under it) */
.walker[data-costume="ghost"] .c-sheet { fill: #eef3f2; }
[data-theme="paper"] .walker[data-costume="ghost"] .costume { filter: drop-shadow(0 0 0.5px rgba(40, 30, 20, 0.6)); } /* (a white sheet on a light card) */
.walker[data-costume="witch"] .c-hat { fill: #3b2455; }
.walker[data-costume="witch"] .c-band { fill: #ff8a1f; }
.walker[data-costume="witch"] .shape-grifter rect[y="1"] { display: none; } /* (its ear tips, under the hat) */
.walker[data-costume="devil"] .c-horn { fill: #b0142a; filter: drop-shadow(0 0 0.6px rgba(255, 60, 80, 0.7)); }

/* HALLOWEEN snacks (wanderers.js): a gummy drop tossed into the mouth, then a chew */
.walker-candy {
  position: absolute; left: 0; top: 0; width: calc(2 * 34px / 16); height: calc(2 * 34px / 16); pointer-events: none; /* (a 2x2 drop in the bots' pixels) */
  background: var(--c); box-shadow: 0 0 3px var(--c);
}
.cpu-face[data-mood="munch"] :is(.eyes-squint, .mouth-o) { display: inline; }
.cpu-face[data-mood="munch"]:is([data-level="hard"], [data-level="insane"]) .eyes-squint { display: none; }
.cpu-face[data-mood="munch"]:is([data-level="hard"], [data-level="insane"]) .eyes-angry { display: inline; }
.walker.chewing .mouth-o { transform-box: fill-box; transform-origin: 50% 0; animation: walker-chew 0.19s steps(1) 2; }
@keyframes walker-chew { 0% { transform: scaleY(0.5); } 50% { transform: scaleY(1); } }

/* VISITORS (visitors.js): seasonal characters in the wanderers' lane, behind the bots (bats and
   crows over them); they sway and bob in whole pixels of their grid */
:is(.start-walkers, .game-walkers) .visitor { position: absolute; left: 0; bottom: 0; z-index: 0; pointer-events: auto; cursor: pointer; touch-action: manipulation; will-change: transform; }
:is(.start-walkers, .game-walkers) .walker { z-index: 1; }
:is(.start-walkers, .game-walkers) :is(.visitor-bat, .visitor-crow, .visitor-goose, .visitor-duck, .visitor-songbird, .visitor-swallow) { z-index: 2; }
.visitor svg { display: block; overflow: visible; }
.visitor .f-b { display: none; }
.visitor.step .f-a { display: none; }
.visitor.step .f-b { display: inline; }
.visitor-ghost svg { opacity: 0.6; filter: drop-shadow(0 0 2px rgba(242, 246, 255, 0.7)); }
/* (the dark ones get a faint light edge, to show on the dark card) */
:is(.visitor-nosferatu, .visitor-bat, .visitor-crow, .visitor-goose, .visitor-duck, .visitor-songbird, .visitor-swallow) svg { filter: drop-shadow(0 0 1px rgba(220, 225, 240, 0.45)); }
.visitor-drip { position: absolute; top: 40%; width: 2px; height: 3px; background: #6fd3ff; box-shadow: 0 0 2px #6fd3ff; pointer-events: none; animation: visitor-drip 0.65s ease-in forwards; }
@keyframes visitor-drip { to { transform: translate(var(--dx), var(--dy)); opacity: 0; } }
.visitor.v-stomp svg { animation: visitor-stomp 0.14s steps(1) 5 alternate; }
@keyframes visitor-stomp { 0% { translate: 0 calc(-2 * 34px / 16); } 100% { translate: 0 0; } }
.visitor.v-wobble svg, .visitor.v-shake svg { animation: visitor-shake 0.09s steps(1) 8 alternate; }
@keyframes visitor-shake { 0% { translate: calc(-1 * 34px / 16) 0; } 100% { translate: calc(34px / 16) 0; } }
.visitor.v-boo svg { animation: visitor-boo 0.5s steps(3) forwards; }
@keyframes visitor-boo { 0% { scale: 1; } 40% { scale: 1.5; } 100% { scale: 1.2; } }
.visitor.v-fade svg { transition: opacity 0.7s steps(5); opacity: 0; }
.visitor.v-vanish svg { animation: walker-pix-out 0.45s steps(1) forwards; }
/* The VIRUS glitches now and then: a jump sideways, a flash of another color */
.visitor-virus svg { animation: virus-glitch 2.6s steps(1) infinite; }
.visitor-virus.v-vanish svg { animation: walker-pix-out 0.45s steps(1) forwards; }
/* (the BUG and the unmasked TROJAN glitch too; any virus pixelates in) */
:is(.visitor-bug, .visitor-trojan.unmasked) > svg { animation: virus-glitch 2.6s steps(1) infinite; }
.visitor.v-popin > svg { animation: walker-pix-in 0.45s steps(1) forwards; }
.visitor.v-popout > svg, .visitor.v-popout > .adware-text { animation: walker-pix-out 0.45s steps(1) forwards; }
/* The TROJAN: a bot on the outside (walking like one), the horse hidden until it's poked; then the
   disguise peels off and the horse resolves under it */
.visitor-trojan .trojan-look { position: absolute; left: 50%; bottom: 0; width: 34px; translate: -50% 0; }
.visitor-trojan.disguised > svg { visibility: hidden; }
.visitor-trojan.disguised.moving .trojan-look .bot { animation: bot-hop 0.28s steps(2) infinite; }
.visitor-trojan.disguised.moving .trojan-look .leg-a { animation: bot-step 0.28s steps(1) infinite; }
.visitor-trojan.disguised.moving .trojan-look .leg-b { animation: bot-step 0.28s steps(1) 0.14s infinite; }
/* (unmasked: the disguise's pixels peel off from the top, and the horse resolves top first under them) */
.visitor-trojan .trojan-peel { position: absolute; pointer-events: none; }
.visitor-trojan.unmasked.unmasking > svg { animation: trojan-resolve 0.6s steps(6) both; }
@keyframes trojan-resolve { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes virus-glitch { 0%, 86%, 100% { translate: 0 0; filter: none; } 88% { translate: 2px 0; filter: hue-rotate(140deg); } 91% { translate: -2px 0; filter: none; } 94% { translate: 1px 0; filter: hue-rotate(250deg); } }

/* Pushing the scary tree: straining */
.cpu-face[data-mood="strain"] :is(.eyes-squint, .mouth-flat, .sweat) { display: inline; }
/* SCENERY (visitors.js): behind everything in the lane, bots and visitors, but in front of the start
   card's copyright line */
.start-walkers { z-index: 0; }
:is(.start-walkers, .game-walkers) .visitor-scenery { z-index: -1; }
/* NOVEMBER's FOG (visitors.js): coarse-pixel mist behind the trees, the trees dark against it, a
   thinner mist in front of everything; the trees and the wanderer fade in and out of it */
:is(.start-walkers, .game-walkers, .saver-lane) .fog-layer { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; pointer-events: none; }
/* (rising a little over the lane's top, fading out, and down to the card's bottom edge: the lane
   sits 6px above it on the game card, 10px on the start screen; rounded off with the card's corners) */
.game-walkers .fog-layer { top: -28px; height: calc(100% + 34px); clip-path: inset(0 round 0 0 8px 8px); }
.start-walkers .fog-layer { height: calc(100% + 10px); }
.fog-layer.fog-back { z-index: -3; }
/* Under the fog, the twinkling background fades to black (as the fog thickens), from the floor up */
:is(.start-walkers, .game-walkers) .fog-dark { position: absolute; left: 0; right: 0; bottom: 0; top: 0; z-index: -4; pointer-events: none; opacity: 0;
  background: linear-gradient(to top, #000 0%, #000 55%, transparent 100%); }
.game-walkers .fog-dark { top: -28px; bottom: -6px; clip-path: inset(0 round 0 0 8px 8px); }
.start-walkers:not(.saver-lane) .fog-dark { top: auto; height: 50%; bottom: -10px; }
.saver-lane .fog-dark, [data-theme="paper"] .fog-dark, [data-theme="daylight"] .fog-dark { display: none; } /* (the saver's already black; the light themes keep their card) */
.fog-layer.fog-fore { z-index: 3; }
:is(.start-walkers, .game-walkers) .visitor.fog-tree { z-index: -2; pointer-events: none; transition: opacity 3s ease-in; }
.visitor.fog-tree svg { filter: none !important; }
:is(.start-walkers, .game-walkers) .visitor.fog-wraith { z-index: 0; transition: opacity 1.8s ease; }
.visitor.fog-wraith svg { filter: drop-shadow(0 0 3px rgba(220, 235, 255, 0.5)); }
.visitor.fog-wraith .walker-emote { color: #dfe8f2; }
:is(.start-walkers, .game-walkers) .visitor.fog-visitor { transition: opacity 1.8s ease; }
.visitor.fog-wraith.scary svg { filter: drop-shadow(0 0 3px rgba(255, 60, 60, 0.45)); }
.visitor.fog-wraith.scary .walker-emote { color: #ff8a8a; }
.visitor-tree svg { filter: drop-shadow(0 0 1px rgba(220, 225, 240, 0.3)); }
.visitor-tree.v-creak svg { animation: visitor-shake 0.1s steps(1) 6 alternate; }
/* OCTOBER's HAUNTED FOREST (visitors.js): the big trees in front of everything (the fog drifting
   over them), the glowing eyes between the trees */
:is(.start-walkers, .game-walkers) .visitor.fog-tree.fore { z-index: 2; }
.visitor.fog-tree.fore svg { filter: drop-shadow(0 0 1px rgba(150, 162, 178, 0.35)) !important; }
:is(.start-walkers, .game-walkers) .visitor.v-front { z-index: 2; }
:is(.start-walkers, .game-walkers) .visitor.fog-eyes { z-index: -2; transition: opacity 0.8s ease; }
.visitor.fog-eyes svg { filter: drop-shadow(0 0 2px currentColor); }
.visitor.fog-eyes.blink svg { opacity: 0; }
/* A MOON rising behind the trees: the BLOOD FOG's, or the WEREWOLF's full moon; the night falling
   for it (as under the fog) */
:is(.start-walkers, .game-walkers) .moon-sky { position: absolute; left: 0; right: 0; top: 0; bottom: 0; overflow: hidden; z-index: -2; pointer-events: none; transition: opacity 6s ease-in; }
.game-walkers .moon-sky { top: -28px; clip-path: inset(0 round 0 0 8px 8px); }
.moon-sky .moon { position: absolute; transition: bottom 12s cubic-bezier(0.2, 0.6, 0.3, 1); filter: drop-shadow(0 0 6px rgba(255, 244, 205, 0.55)); }
.moon-sky.blood .moon { filter: drop-shadow(0 0 8px rgba(255, 40, 30, 0.7)); }
:is(.start-walkers, .game-walkers) .night-dark { position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -4; pointer-events: none; opacity: 0; transition: opacity 3s ease;
  background: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0.92) 55%, rgba(0, 0, 0, 0) 100%); }
.night-dark.on { opacity: 0.85; }
.game-walkers .night-dark { top: -28px; bottom: -6px; clip-path: inset(0 round 0 0 8px 8px); }
.start-walkers:not(.saver-lane) .night-dark { top: auto; height: 55%; bottom: -10px; }
.saver-lane .night-dark, [data-theme="paper"] .night-dark, [data-theme="daylight"] .night-dark { display: none; }
.visitor.v-howl :is(.f-a, .f-b) { display: none; }
.visitor.v-howl .f-c { display: inline; }
/* LIGHTS OUT: the card dark (flickering off, and back on), nothing but the bots' eyes */
:is(.start-walkers, .game-walkers) .lights-out { position: absolute; left: 0; right: 0; top: 0; bottom: -2px; z-index: 5; background: #000; pointer-events: none; animation: lights-off 0.7s steps(1) both; }
.game-walkers .lights-out { top: -60px; bottom: -6px; clip-path: inset(0 round 0 0 8px 8px); }
.start-walkers:not(.saver-lane) .lights-out { bottom: -10px; }
.lights-out.on { animation: lights-on 0.8s steps(1) forwards; }
@keyframes lights-off { 0% { opacity: 0; } 15% { opacity: 1; } 30% { opacity: 0; } 45% { opacity: 1; } 55% { opacity: 0.3; } 70%, 100% { opacity: 1; } }
@keyframes lights-on { 0% { opacity: 1; } 20% { opacity: 0; } 35% { opacity: 1; } 55% { opacity: 0; } 70% { opacity: 0.8; } 85%, 100% { opacity: 0; } }
:is(.start-walkers, .game-walkers) .dark-eyes { position: absolute; bottom: 19px; width: 34px; height: 5px; z-index: 6; pointer-events: none; transition: opacity 0.3s ease; animation: dark-blink 3.1s steps(1) infinite; }
.dark-eyes i { position: absolute; top: 0; width: 4.25px; height: 4.25px; background: #eaf6ff; box-shadow: 0 0 4px rgba(200, 230, 255, 0.85); }
.dark-eyes.red i { background: #ff2a2a; box-shadow: 0 0 5px rgba(255, 42, 42, 0.9); }
@keyframes dark-blink { 0%, 90% { transform: scaleY(1); } 93% { transform: scaleY(0.1); } 96%, 100% { transform: scaleY(1); } }
/* POSSESSED: red, glowing eyes and a stiff walk (no bounce, slow steps) */
.walker.possessed .cpu-bot .eyes { fill: #ff2a2a !important; filter: drop-shadow(0 0 1px #ff2a2a); }
.walker.possessed.walking .bot { animation: none; }
.walker.possessed.walking :is(.leg-a, .leg-b) { animation-duration: 0.7s; }
.walker.possessed.walking .leg-b { animation-delay: 0.35s; }
/* The spider's silk thread, up out of sight */
.visitor-thread { position: absolute; left: 50%; bottom: 60%; width: 1px; height: var(--thread, 160px); background: rgba(220, 225, 240, 0.45); pointer-events: none; }
.visitor-spider svg { filter: drop-shadow(0 0 1px rgba(220, 225, 240, 0.45)); }
/* WINTER and the holidays: the scenery shakes (v-creak) or its flames flare (v-glow) when poked */
.visitor-scenery.v-creak svg { animation: visitor-shake 0.1s steps(1) 6 alternate; }
.visitor-scenery.v-glow svg { animation: visitor-glow 0.9s steps(3) 1; }
/* The JACK O' LANTERN glows from inside (a warm halo that flickers with its candle); poked, it flares */
.visitor-jacklantern svg { filter: drop-shadow(0 0 3px rgba(255, 160, 40, 0.55)); }
.visitor-jacklantern.step svg { filter: drop-shadow(0 0 2px rgba(255, 160, 40, 0.4)); }
.visitor-jacklantern.v-creak svg { animation: jack-flare 0.9s ease-out 1; }
@keyframes jack-flare { 0% { filter: drop-shadow(0 0 10px rgba(255, 180, 40, 1)) brightness(1.5); } 100% { filter: drop-shadow(0 0 3px rgba(255, 160, 40, 0.55)); } }
@keyframes visitor-glow { 0%, 100% { filter: none; } 50% { filter: brightness(1.5) drop-shadow(0 0 3px #ffd23f); } }
.visitor-evergreen.v-blink .f-a { animation: visitor-blink 0.24s steps(1) 5; }
@keyframes visitor-blink { 50% { opacity: 0; } }
:is(.visitor-menorah, .visitor-kinara, .visitor-sign) svg { filter: drop-shadow(0 0 1.5px rgba(255, 210, 63, 0.5)); }
.visitor-evergreen svg { filter: drop-shadow(0 0 1.5px rgba(255, 190, 110, 0.75)) drop-shadow(0 0 5px rgba(255, 160, 70, 0.35)); } /* (the filament bulbs' warm glow) */
:is(.visitor-penguin, .visitor-reindeer, .visitor-snowman, .visitor-dreidel) svg { filter: drop-shadow(0 0 1px rgba(220, 225, 240, 0.4)); }
.visitor .f-c { display: none; } /* (the penguin on its belly) */
.visitor.v-slide :is(.f-a, .f-b) { display: none; }
.visitor.v-slide .f-c { display: inline; }
.visitor .f-d { display: none; } /* (a crow flying: wings up, f-c; wings down, f-d) */
.visitor.v-fly :is(.f-a, .f-b) { display: none; }
.visitor.v-fly .f-c { display: inline; }
.visitor.v-fly.step .f-c { display: none; }
.visitor.v-fly.step .f-d { display: inline; }
.visitor-reindeer.v-rudolph svg { filter: drop-shadow(0 0 1px rgba(220, 225, 240, 0.4)) drop-shadow(0 0 2px #ff2a2a); }
/* Snow, in pixel flakes; fireworks, a rocket and its sparks (all in the bots' pixels) */
:is(.visitor-flake, .visitor-spark) { position: absolute; left: 0; bottom: 0; width: calc(34px / 16); height: calc(34px / 16); pointer-events: none; z-index: 2; }
.visitor-flake { background: #f2f4f8; opacity: 0.85; }
[data-theme="paper"] .visitor-flake { background: #b8c4d6; }
.visitor-spark { background: var(--c); box-shadow: 0 0 3px var(--c); }
.visitor-spark.rocket { background: #fff6c2; box-shadow: 0 0 2px #ffd23f; }

/* SCREEN SAVER (saver.js): black, but for the wanderers, at a height that moves each minute */
.saver { position: fixed; inset: 0; z-index: 300; background: #000; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.saver.fading { background: transparent; } /* (the blocks do the black while it fades) */
.saver-pixels { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; pointer-events: none; }
.saver:not(.fading) .saver-pixels { display: none; }
.saver[hidden] { display: none; }
.saver .lane-fore .forest-ground { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent); } /* (the floor fading to black just past the scene) */
.saver .lane-fore { clip-path: inset(-400px 0 -28px 0); }
.saver .lane-fore .visitor.fore { -webkit-mask-image: linear-gradient(to top, transparent var(--roots, 0px), #000 calc(var(--roots, 0px) + 28px)); mask-image: linear-gradient(to top, transparent var(--roots, 0px), #000 calc(var(--roots, 0px) + 28px)); }
.saver .saver-lane { top: calc(var(--y, 60%) - 90px); bottom: auto; height: 90px; left: 16px; right: 16px; } /* (its floor at --y; a height for the fog to fill) */

/* A hat (wanderers.js's winter, holiday and party costumes): the antennas and ear tips go under it */
.walker[data-hat] :is(.shape-bot, .shape-grifter, .shape-glitch) rect[y="1"] { display: none; }

/* ===== MAIN MENU (#home, script.js's showHome) =====
   Over the game card between the start screen and a game: the title, the level bar, the six
   modes, and the picked mode's panel (its options, what it is, your best, PLAY). The game under
   it is hidden while it's up; the top icons (RULES & RECORDS, SETTINGS) and the wanderers stay. */
.home[hidden] { display: none; }
.home {
  position: absolute; inset: 0; z-index: 15; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 52px 8px 64px; text-align: center; overflow-y: auto;
}
.home > * { pointer-events: auto; }
.home-head h1 { font-size: 34px; letter-spacing: 6px; }
.home .level-bar { margin-top: 0; }
.home .modes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; width: 100%; margin-top: 0; }
.home .modes button { padding: 10px 4px; font-size: 13px; letter-spacing: 1px; }
.home-panel {
  width: 100%; display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 14px 12px; border: 1px solid var(--grid-line); border-radius: 6px; background: rgba(var(--fg-rgb), 0.03);
  animation: pause-in 0.18s ease-out;
}
.home-mode-name { margin: 0; font-size: 15px; letter-spacing: 3px; color: var(--accent); text-shadow: 0 0 8px rgba(var(--accent-rgb), 0.6); }
.home .mode-info { margin: 0; font-size: 11px; line-height: 1.5; color: var(--panel-text); }
.home .difficulty { margin-top: 0; }
.home-best { margin: 0; font-size: 12px; letter-spacing: 2px; color: var(--fg-dim); }
.home-best b { color: var(--fg); }
.home-best:empty { display: none; }
.home-play { margin-top: 2px; }
/* The game under the menu: hidden (still laid out, so nothing jumps when PLAY shows it) */
body.at-home .crt > :is(header, .hud, .board-wrap, .message-slot, .corner-btn, .dev-badge) { visibility: hidden; }
/* (nothing under a card is drawn: RULES & RECORDS, EXPLOITS, the STORE and SETTINGS cover the main
   menu, the game and the wanderers' lane; the MUSIC PLAYER covers the whole game card) */
body.panel-open .crt > :is(#home, #game-walkers, header, .hud, .board-wrap, .message-slot, .corner-btn, .dev-badge) { visibility: hidden; }
body.player-open :is(.cabinet, body > footer) { visibility: hidden; }
/* (the wanderers held still where they stand while their lane is covered: their steps and blinks too) */
:is(body.panel-open, body.player-open, html.saver-on body) #game-walkers * { animation-play-state: paused !important; }

/* In a game (not the tutorial): the top-left icon is PAUSE (← BACK to the main menu, like the
   cards' BACK, when there's nothing to pause: VS's setup, a finished run), and SETTINGS waits on
   the pause screen */
.records-btn svg { position: absolute; left: 4px; top: 4.5px; }
.records-btn .rb-pause { visibility: hidden; }
.records-btn span.rb-back { display: none; pointer-events: none; }
body.in-game .records-btn .rb-menu { display: none; } /* (gone, not just hidden: PAUSE's words are fitted to what's in the button) */
body.in-game.can-pause .records-btn .rb-pause { visibility: visible; }
/* (a card open over the game, the STORE, RULES & RECORDS, EXPLOITS or SETTINGS: no PAUSE in the corner;
   its own visibility mustn't show it through the hidden button) */
body.panel-open .records-btn .rb-pause { visibility: hidden !important; }
body.in-game:not(.can-pause) .records-btn span.rb-back { display: inline-flex; }
body.in-game:not(.can-pause) .records-btn { opacity: 1; width: auto; height: auto; top: 8px; } /* (the main menu's ← BACK's inset) */
@media (hover: hover) { body.in-game:not(.can-pause) .records-btn:hover .rb-back { background: rgba(var(--fg-rgb), 0.12); } }
body.in-game .settings-btn:not([aria-expanded="true"]) { visibility: hidden; }
/* PAUSE in every mode: RESUME, RESTART (and EXIT in VS), RULES & RECORDS and SETTINGS, MAIN MENU */
.vs-pause .pause-row button { font-size: 11px; padding: 6px 10px; }
.vs-pause :is(#pause-exit, #pause-restart, #pause-menu)[hidden] { display: none; }
.pause-menu {
  padding: 6px 14px; background: transparent; border: 1px solid var(--fg-dim); border-radius: 4px;
  color: var(--fg-dim); font-family: inherit; font-size: 12px; letter-spacing: 2px; cursor: pointer;
}
@media (hover: hover) { .pause-menu:hover { color: var(--fg); border-color: var(--fg); } }
/* The game over box: MAIN MENU under NEW SESSION */
.overlay-menu-btn {
  display: block; margin: 12px auto 0; padding: 6px 14px; background: transparent; border: 1px solid var(--fg-dim);
  border-radius: 4px; color: var(--fg-dim); font-family: inherit; font-size: 11px; letter-spacing: 2px; cursor: pointer;
}
@media (hover: hover) { .overlay-menu-btn:hover { color: var(--fg); border-color: var(--fg); } }
.home #daily-kinds { gap: 5px; }
.home #daily-kinds button { padding-left: 7px; padding-right: 7px; }
/* The main menu's RULES & RECORDS and SETTINGS: buttons, as on the pause screen (the corner
   icons only show there while their panel is open, to close it) */
.home-row { display: flex; justify-content: center; gap: 8px; width: 100%; margin-top: 0; }
.home-row button { flex: 1; font-size: 12px; padding: 8px 6px; }
body.at-home :is(.records-btn, .settings-btn):not([aria-expanded="true"]) { visibility: hidden; }

/* RULES & RECORDS and SETTINGS: each its own card, covering the game card (BACK closes it; the
   corner icons hide while one is open) */
.records, .settings {
  top: 0; left: 0; right: 0; bottom: 0; width: auto; max-width: none; max-height: none;
  padding: 8px 8px 20px; border: none; border-radius: 0; box-shadow: none;
  background: var(--panel);
}
.card-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.card-head span { font-size: 13px; letter-spacing: 2px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
.card-back, :is(.records, .settings) .card-back {
  padding: 6px 12px; background: transparent; border: 1px solid var(--fg); border-radius: 4px;
  color: var(--fg); font-family: inherit; font-size: 12px; letter-spacing: 1px; cursor: pointer;
}
@media (hover: hover) { :is(.records, .settings, .arcade) .card-back:hover { background: rgba(var(--fg-rgb), 0.12); } }
body.panel-open .crt :is(.records-btn, .settings-btn) { visibility: hidden !important; }

/* THE HUD (not VS): BEST over SCORE on the left, CURRENT large in the middle (NEXT, on Easy, a
   short dim panel under it; TIME / BITS LEFT under it in the timed and counted modes), ENCRYPT
   IN over CHAIN on the right */
body:not(.vs-mode) .hud {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) minmax(0, 1fr);
  grid-template-rows: auto auto;
  grid-template-areas: "best cur enc" "score cur chain";
  gap: 6px;
}
body:not(.vs-mode) .hud.no-pulse { grid-template-areas: "best cur chain" "score cur chain"; }
body:not(.vs-mode) .hud > #best-stat { grid-area: best; }
body:not(.vs-mode) .hud > #score-stat { grid-area: score; }
body:not(.vs-mode) .hud > #pulse-stat { grid-area: enc; }
body:not(.vs-mode) .hud > #chain-stat { grid-area: chain; }
body:not(.vs-mode) .hud > .hud-bits { grid-area: cur; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
body:not(.vs-mode) .hud-bits .stat-current { flex: 1 1 auto; }
body:not(.vs-mode) .hud-bits .stat-current .bit-sq { width: 42px; height: 42px; font-size: 20px; margin: auto auto 2px; }
/* NEXT (and BLITZ's TIME): a short, dim panel under CURRENT */
body:not(.vs-mode) .hud-bits :is(#next-stat, #time-stat) { flex: 0 0 28px; height: 28px; min-height: 0; flex-direction: row !important; align-items: center; justify-content: center; gap: 8px; padding: 0 4px; }
body:not(.vs-mode) .hud-bits #time-stat { opacity: 0.7; } /* (NEXT's bits at full brightness, as CURRENT's) */
body:not(.vs-mode) .hud-bits :is(#next-stat, #time-stat) .label { width: auto; margin: 0; }
body:not(.vs-mode) .hud-bits #next-stat .bit-row { margin: 0; }
body:not(.vs-mode) .hud-bits #next-stat .bit-sq { width: 20px; height: 20px; margin: 0; font-size: 10px; }
/* The cards' tops stay put while their pages scroll: BACK and the title (and RULES & RECORDS'
   four tabs, and RECORDS' own tabs just under them) */
.records, .settings { padding-top: 0; }
.records .card-top, .settings .card-head {
  position: sticky; top: 0; z-index: 5; padding-top: 8px; background: var(--panel);
}
.records .card-top { padding-bottom: 2px; }
.settings .card-head { padding-bottom: 10px; margin-bottom: 4px; }
.records .records-tabs { position: sticky; top: var(--card-top-h, 120px); z-index: 4; padding: 6px 0; background: var(--panel); }
/* (BACK as on RULES & RECORDS: not the settings list's full-width button) */
.card-back, :is(.records, .settings) .card-back { display: inline-flex; width: auto; flex: none; white-space: nowrap; text-align: center; }
/* The dividers between the settings' sections: dashed in the accent color, like the ===== over the footer */
.settings-section, .settings-options { border-top-color: rgba(var(--accent-rgb), 0.7); }
/* RULES & RECORDS: the card stays put and each tab's dashed box scrolls inside its border;
   RECORDS' own tabs stick to the box's top */
.records:not([hidden]) { display: flex; flex-direction: column; overflow: hidden; padding-bottom: 14px; }
.records .card-top, .records .store-shortcut { flex: none; }
.records .menu-pane:not([hidden]) { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.records .menu-pane > .panel {
  flex: 1 1 auto; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
}
.records .records-tabs { top: -14px; }
/* Section titles in the accent color, like the cards' titles (// SETTINGS) and the RECORDS categories */
.panel h2, .settings-title { color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
/* The main menu's TUTORIAL: as wide as one of the buttons above it, centered */
.home-row-single button { flex: 0 0 calc((100% - 8px) / 2); }
/* UPDATE (the Google Play release, js/app-update.js): beside TUTORIAL, in the accent; ready to
   install, RESTART TO UPDATE pulses */
#home-update[hidden] { display: none; }
#home-update { color: var(--accent); border-color: var(--accent); }
#home-update:disabled { opacity: 0.7; cursor: default; }
#home-update.ready { animation: warn-pulse 1.2s ease-in-out infinite; }
/* EQUIPPED and OWNED in the accent color */
.hack-item.equipped h3::after { color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
.store-item.owned .store-price, .store-item.owned .store-buy { color: var(--accent); }
/* REDUCED EFFECTS (SETTINGS → EFFECTS): no glows (repainted with every change) */
.low-fx *, .low-fx *::before, .low-fx *::after { text-shadow: none !important; box-shadow: none !important; }
/* (the HUD centered over the grid card, its width set by fitBoard) */
.crt > .hud { align-self: center; max-width: 100%; margin-left: auto; margin-right: auto; }
/* NEXT (Easy): one row in its short panel, the label beside the bit (not over it, as the taller
   boxes have them) */
body:not(.vs-mode) .hud-bits :is(#next-stat, #time-stat) > .label { position: static; height: auto; transform: none; flex: none; line-height: 1; }
body:not(.vs-mode) .hud-bits :is(#next-stat, #time-stat) > :is(.bit-row, .bit-sq, .value) { position: static; transform: none; flex: none; }
/* CURRENT's panel in the accent color */
.hud-bits .stat-current { border-color: var(--accent); }
/* Bots readable in every theme (audited per theme, bot and level): INSANE's red eyes go light on a
   red body (SPECTRUM's BOT is the theme's red; PAPER's GLITCH is red with a dark "light" color),
   and SPECTRUM's GLITCH, otherwise the same red as its BOT, glitches through the rainbow */
[data-theme="spectrum"] .cpu-face[data-bot="bot"][data-level="insane"] .eyes-angry { fill: var(--alarm-text); filter: drop-shadow(0 0 1px var(--alarm-text)); }
[data-theme="paper"] .cpu-face[data-level="insane"][data-bot="glitch"] .eyes-angry { fill: #ffffff; filter: none; }
[data-theme="spectrum"] .cpu-face[data-bot="glitch"] .bot-body { animation: glitch-hue 2.4s steps(6) infinite; }
@keyframes glitch-hue { from { filter: hue-rotate(0deg) drop-shadow(0 0 1px rgba(var(--bot-rgb), 0.8)); } to { filter: hue-rotate(360deg) drop-shadow(0 0 1px rgba(var(--bot-rgb), 0.8)); } }
/* (MONOCHROME's "red" is near white: INSANE's eyes are cut out of the body like the other faces;
   AMBER CRT's GRIFTER is orange: its INSANE eyes go light) */
[data-theme="monochrome"] .cpu-face[data-level="insane"] .eyes-angry { fill: var(--board-bg); filter: none; }
[data-theme="amber-crt"] .cpu-face[data-bot="grifter"][data-level="insane"] .eyes-angry { fill: var(--alarm-text); filter: drop-shadow(0 0 1px var(--alarm-text)); }
/* SWAP armed: the bits it can pick glow faintly; the one picked is outlined in the accent */
.board .cell.swap-target { cursor: pointer; box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.35); }
.board .cell.swap-pick { outline: 2px solid var(--accent); outline-offset: -2px; box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.6); }

/* PIXEL MODE (pixel.js; html.pixel-mode, the bot sandbox's switch for now): the bots on a screen
   at twice the art's resolution, everything in whole screen pixels (half an art pixel). The
   animations that squashed, stretched or turned the picture move by those pixels instead. */
svg.px-drawn > .bot-swap { visibility: hidden; } /* (its pixels redrawn in .px-body, turned) */
svg.px-pose > .px-hair { visibility: hidden; } /* (CORE DUMP's poses draw their own hair) */
html.pixel-mode .px-layer rect { shape-rendering: crispEdges; }
html.pixel-mode .cpu-face :is(.eyes) { transform-box: view-box; }
html.pixel-mode .cpu-face[data-mood="idle"] .eyes,
html.pixel-mode .cpu-face[data-variant="tapping"] .eyes { animation-name: px-blink; transform-origin: 8px 8px; }
html.pixel-mode .cpu-face[data-variant="ponder"] .eyes { animation-name: px-blink; transform-origin: 8px 8px; }
@keyframes px-blink { 0%, 92% { transform: scaleY(1); } 94% { transform: scaleY(0.25); } 97% { transform: scaleY(1); } } /* (2 pixels of eye down to half of one, from the bottom) */
html.pixel-mode .cpu-face[data-mood="love"] .eyes-heart { animation-name: px-beat; }
@keyframes px-beat { 0%, 60% { transform: translateY(0); } 61%, 100% { transform: translateY(-0.5px); } }
html.pixel-mode .cpu-face[data-mood="dizzy"] .bot { animation-name: px-sway; }
@keyframes px-sway { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-0.5px); } 50% { transform: translateX(0); } 75% { transform: translateX(0.5px); } }
html.pixel-mode :is(.walker, #cpu-face).snapping .bot { animation-name: px-lunge; }
@keyframes px-lunge { 0% { transform: translateY(-1px); } 100% { transform: translateY(0.5px); } }
html.pixel-mode .walker.skater.walking .bot,
html.pixel-mode .walker.skater.walking[data-look="left"] .bot { transform: none; } /* (its lean is redrawn, pixel.js) */

/* PUZZLES: the menu card's page, every puzzle of a set */
.panel-puzzles .pz-tiers { margin: 0 0 8px; }
.pz-count { margin: 0 0 8px; text-align: center; letter-spacing: 2px; color: var(--accent); }
.pz-pages { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; margin-bottom: 10px; }
.pz-pages button {
  padding: 4px 2px; background: none; border: 1px solid var(--grid-line); border-radius: 4px;
  color: var(--fg-dim); font-family: inherit; font-size: 11px; letter-spacing: 1px; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; line-height: 1.3;
}
.pz-pages button small { font-size: 9px; opacity: 0.8; }
.pz-pages button.active { color: var(--fg); border-color: var(--fg); background: rgba(var(--fg-rgb), 0.08); }
.pz-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.pz-tile {
  position: relative; aspect-ratio: 1; display: grid; place-items: center;
  background: var(--inset-bg, transparent); border: 1px solid var(--fg-dim); border-radius: 4px;
  color: var(--fg); font-family: inherit; font-size: 14px; cursor: pointer;
}
.pz-tile svg { width: 14px; height: 14px; }
.pz-tile i { position: absolute; top: 2px; right: 4px; font-style: normal; font-size: 9px; color: var(--accent); }
.pz-tile.done { border-color: var(--fg); background: rgba(var(--fg-rgb), 0.12); }
.pz-tile.next { border-color: var(--accent); color: var(--accent); box-shadow: 0 0 6px rgba(var(--accent-rgb), 0.45); }
.pz-tile.current { outline: 2px solid var(--accent); outline-offset: 1px; }
.pz-tile:disabled { opacity: 0.3; cursor: default; color: var(--fg-dim); border-style: dashed; }
.pz-note { margin: 10px 0 0; font-size: 13px; color: var(--fg-dim); text-align: center; }

/* KEYS: beside the level bar, in the accent color, after a key */
/* The STORE buttons' sign: the currency sign in its corner, always there. Unlit, a dark tube; while the
   DAILY DROP waits it lights up like a HOT NOW sign: the accent, a glow, a slow hum and a flicker now and then */
#home-store { position: relative; }
.store-lamp { position: absolute; top: 50%; right: 9px; translate: 0 -50%; display: flex; color: var(--fg-dim); opacity: 0.45; transition: color 0.3s, opacity 0.3s; pointer-events: none; }
.store-lamp .cur-ico { width: 13px; height: 13px; }
.has-drop .store-lamp { color: var(--accent); opacity: 1; filter: drop-shadow(0 0 3px rgba(var(--accent-rgb), 0.95)) drop-shadow(0 0 7px rgba(var(--accent-rgb), 0.6)); animation: lamp-hum 4.2s ease-in-out infinite; }
@keyframes lamp-hum {
  0%, 100% { opacity: 1; }
  40% { opacity: 0.82; }
  /* (the flicker: off, on, off, on, the way a neon sign catches) */
  76% { opacity: 1; } 77% { opacity: 0.2; } 78% { opacity: 1; } 80% { opacity: 0.35; } 81% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .has-drop .store-lamp { animation: none; } }
/* STORE: the balance, the sections, the boosters */
.panel-store .store-keys { display: flex; justify-content: space-between; align-items: baseline; margin: 0 0 10px; letter-spacing: 2px; color: var(--fg-dim); }
.panel-store .store-keys b { font-size: 21px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
.panel-store .store-sub { margin: 14px 0 4px; font-size: 15.5px; letter-spacing: 2px; color: var(--accent); }
.panel-store .store-sub-note { margin: 0 0 8px; font-size: 13px; color: var(--fg-dim); }
/* BLACK BOXES: the infections, a warning stamped under the boxes */
.panel-store .box-warn { margin: 10px 0 4px; padding: 8px 10px; border: 1px dashed var(--danger); background: rgba(var(--danger-rgb), 0.07); font-size: 13px; }
.panel-store .box-warn p { margin: 0 0 6px; }
.panel-store .box-warn-head { color: var(--danger); letter-spacing: 1px; text-shadow: 0 0 6px rgba(var(--danger-rgb), 0.5); }
.panel-store .box-warn-list { margin: 0; padding: 0; list-style: none; }
.panel-store .box-warn-list li { margin: 3px 0; padding-left: 12px; text-indent: -12px; }
.panel-store .box-warn-list li::before { content: '> '; color: var(--danger); }
.panel-store .box-warn b { color: var(--danger); font-weight: normal; }
.booster-shop { display: flex; flex-direction: column; gap: 8px; }
.booster-buy-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.booster-owned { font-size: 14.5px; letter-spacing: 1px; color: var(--accent); }
.store-buy.short { opacity: 0.45; }
/* (a starter slot's card: the theme's color, not the game over's red) */
#starter-pick { z-index: 207; } /* (over the main menu and its toasts) */
.starter-pick-box { border-color: var(--fg-dim); box-shadow: 0 0 30px rgba(var(--fg-rgb), 0.25); width: min(360px, calc(100vw - 32px)); padding: 18px 18px; }
.starter-pick-box h2 { color: var(--accent); text-shadow: 0 0 8px rgba(var(--accent-rgb), 0.5); font-size: 16px; margin: 0 0 6px; }
.starter-pick-list { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; max-height: 50vh; overflow-y: auto; }
.starter-pick-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; font-family: inherit; font-size: 12px; letter-spacing: 1px; color: var(--fg); background: transparent; border: 1px solid var(--grid-line); border-radius: 4px; cursor: pointer; text-align: left; }
.starter-pick-item .exploit-glyph { width: 1.6em; text-align: center; color: var(--accent); }
.starter-pick-item .starter-pick-name { flex: 1; }
.starter-pick-item .starter-pick-count { color: var(--fg-dim); }
.starter-pick-item.on { border-color: var(--accent); color: var(--accent); }
.starter-pick-item:disabled { opacity: 0.4; cursor: default; }
.starter-pick-empty { justify-content: center; color: var(--fg-dim); border-style: dashed; }
.starter-pick-foot { display: flex; gap: 8px; justify-content: center; }
/* GAME SETTINGS: a section each (a head, its buttons, a note), 8px apart; its can't-do line over the
   title, as VS's setup has it */
.mode-settings-box { position: relative; }
.mode-settings-box h2 { margin: 0; }
.mode-settings-box .ms-msg { position: absolute; top: 18px; left: 18px; right: 18px; height: 20px; line-height: 20px; min-height: 0; font-size: 13px; text-align: center; }
.mode-settings-box .ms-msg.show + h2 { visibility: hidden; }
.mode-settings-box .ms-sec { margin: var(--gap) 0 0; }
.mode-settings-box .ms-sec[hidden] { display: none; }
.mode-settings-box .ms-head { margin: 0 0 var(--gap); font-size: 13px; letter-spacing: 2px; color: var(--fg-dim); }
.mode-settings-box .ms-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); margin: 0; }
.mode-settings-box .ms-row.one { grid-template-columns: minmax(0, 1fr); }
.mode-settings-box .ms-row button { height: 32px; min-width: 0; padding: 0 8px; font-size: 12px; letter-spacing: 1px; display: flex; align-items: center; justify-content: center; white-space: nowrap; overflow: hidden; }
#mode-settings #difficulty-row button { height: 32px; }
.mode-settings-box .ms-note { margin: var(--gap) 0 0; font-size: 13px; line-height: 1.4; color: var(--fg-dim); }
.mode-settings-box .starter-pick-foot { margin-top: 16px; }
/* STORY's message cards (#story-msg: an unprompted message, a thread opened again) */
.story-intro-box p { margin: var(--gap) 0 0; font-size: 13px; line-height: 1.4; text-align: left; color: var(--panel-text); }
.story-intro-box .sf-caret { display: inline-block; width: 0.55em; height: 1em; margin-left: 2px; background: var(--fg); vertical-align: -0.15em; animation: sf-blink 1s steps(1) infinite; }
.low-fx .story-intro-box .sf-caret { animation: none; }
.story-intro-box .starter-pick-foot { margin-top: 16px; }
/* STORY's intro (script.js's storyTerminal): a terminal over the whole screen. The screen fades slowly
   to black, a cursor blinks top left and the message types out; ENTER, and it goes dark again. Black
   in every theme, in the theme's own color (a light theme's ink would be lost on it: a phosphor green
   there). The phone comes up over it (#story-msg raised while it's on) */
.story-term { --term-rgb: var(--fg-rgb); position: fixed; inset: 0; z-index: 9000; box-sizing: border-box; padding: calc(16px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom)); overflow-y: auto; scrollbar-width: none;
  background: #000; opacity: 0; transition: opacity 2.6s ease-in; font-family: 'Courier New', monospace; color: rgb(var(--term-rgb)); text-align: left; cursor: default; }
.story-term::-webkit-scrollbar { display: none; }
:is([data-theme="paper"], [data-theme="daylight"]) .story-term { --term-rgb: 51, 255, 153; }
.story-term.hidden { display: none; }
.story-term.on { opacity: 1; }
.story-term.lift { opacity: 0; transition: opacity 1.4s ease-out; } /* (back to the board, or the menu) */
.low-fx .story-term, .low-fx .term-out { transition: none; }
@media (prefers-reduced-motion: reduce) { .story-term, .term-out { transition: none; } }
.term-out { max-width: 64ch; font-size: 15px; line-height: 1.5; text-shadow: 0 0 6px rgba(var(--term-rgb), 0.5); transition: opacity 0.4s ease-out; }
@media (min-width: 700px) { .term-out { font-size: 18px; } }
.term-out.dark { opacity: 0; }
.term-out p { margin: 0 0 1em; white-space: pre-wrap; overflow-wrap: anywhere; }
.term-out :is(.term-head, .term-prompt) { font-size: 0.86em; letter-spacing: 0.5px; } /* (the terminal's own lines: on one line on a phone) */
.term-caret { display: inline-block; width: 0.6em; height: 1.05em; margin-left: 1px; vertical-align: -0.18em; background: rgb(var(--term-rgb)); box-shadow: 0 0 6px rgba(var(--term-rgb), 0.6); }
.term-caret.blink { animation: sf-blink 1.06s steps(1) infinite; }
/* (PRESS ENTER TO CONTINUE: the terminal's own line, plain text as a terminal prints it, the cursor
   after it; a button underneath only so a key, a tap or a screen reader can press it) */
.term-enter { display: inline; margin: 0; padding: 0; font: inherit; letter-spacing: 0.5px; color: inherit; background: none; border: 0; border-radius: 0; text-shadow: inherit; cursor: pointer; }
.term-enter[hidden] { display: none; }
.term-enter:focus { outline: none; }
body.term-on #story-msg { z-index: 9001; }
/* (the phone raised into view as a thread comes in) */
.story-msg-box.phone .phone-screen { animation: phone-rise 0.42s cubic-bezier(0.2, 0.8, 0.25, 1) both; }
@keyframes phone-rise { from { opacity: 0; transform: translateY(48px) scale(0.96); } }
.low-fx .story-msg-box.phone .phone-screen { animation: none; }
/* THE PHONE BUTTON, in a STORY game: top left across from PAUSE, its size and shape (script.js matches
   its width to PAUSE's), a little phone in the middle; it opens your messages to read again */
.phone-btn { position: absolute; top: 8px; left: 8px; height: 26px; width: 79px; padding: 0; display: none; align-items: center; justify-content: center;
  border: 1px solid var(--fg); border-radius: 4px; background: transparent; color: var(--fg); cursor: pointer; }
.phone-btn svg { width: 10px; height: 16px; display: block; }
.phone-btn::before { content: ""; position: absolute; inset: -12px -16px -14px -10px; } /* (a fingertip-sized target, as PAUSE has) */
body.in-game.can-pause .phone-btn:not([hidden]) { display: flex; }
body.panel-open .phone-btn { visibility: hidden; }
@media (hover: hover) { .phone-btn:hover { background: rgba(var(--fg-rgb), 0.12); } }
/* STORY's kit: the side slots as PATCHES and EXPLOITS, how many uses this key has left in the corner;
   used up, dimmed */
/* (STORY: the EXPLOIT button not there till an exploit's introduced, its place kept) */
.exploit-icon.story-hidden { visibility: hidden; }
.exploit-icon.side-slot.story-kit { color: var(--fg); border-color: rgba(var(--fg-rgb), 0.6); }
.exploit-icon.side-slot.story-kit .exploit-glyph { display: inline-flex; align-items: center; gap: 1px; font-size: 12px; opacity: 1; }
.exploit-icon.side-slot.story-kit .exploit-glyph svg { width: 16px; height: auto; }
.exploit-icon.side-slot.story-kit .kit-left { position: absolute; top: 1px; right: 3px; font-size: 8px; line-height: 1; color: var(--accent); }
.exploit-icon.side-slot.story-kit.spent { opacity: 0.45; }
/* (its card: owned items as the main menu's pick cards; the BLACK MARKET's offers with their price on
   one line, red where you're short) */
.story-kit-box #story-kit-title svg { width: 1.1em; height: auto; margin-right: 6px; vertical-align: -0.1em; }
.story-kit-box .starter-pick-item.off { opacity: 0.5; }
.story-kit-box .kit-cost { display: inline-flex; gap: 6px; margin-left: auto; font-size: 11px; white-space: nowrap; }
.story-kit-box .kit-cost .kc { display: inline-flex; align-items: center; gap: 2px; }
.story-kit-box .kit-cost .kc svg { width: 11px; height: 11px; }
.story-kit-box .kit-cost .kc.short { color: var(--danger, #ff5a5a); }
.story-kit-box #story-kit-market svg { width: 1em; height: 1em; margin-right: 4px; vertical-align: -0.15em; }
/* (the cracked card and the ARCHIVE: what a file revealed, in the accent color) */
/* A TRANSMISSION's lines (stories.js): an IM's messages in bubbles (below), a chat log's <handle> dim,
   a call's ring and end in the accent (the ring pulsing till ANSWER), its spoken lines bright, notes
   dim; a line not typed yet keeps its room (an IM's doesn't: it comes in at the bottom) */
:is(.story-frag, .archive-file, .story-msg-box) .tl { margin: 0 0 4px; font-size: 13px; line-height: 1.4; color: var(--panel-text); text-align: left; white-space: normal; }
:is(.story-frag, .archive-file, .story-msg-box) .tl.tl-wait { visibility: hidden; }
.tl.tl-chat .tl-who { color: var(--fg-dim); }
:is(.story-frag, .archive-file, .story-msg-box) .tl:is(.tl-ring, .tl-end, .tl-mail) { font-size: 11.5px; letter-spacing: 1px; color: var(--accent); }
.tl.tl-ring.ringing .tl-t { animation: warn-pulse 0.8s ease-in-out infinite; }
:is(.story-frag, .archive-file, .story-msg-box) .tl.tl-voice { color: var(--fg); }
:is(.story-frag, .archive-file, .story-msg-box) .tl.tl-note { font-size: 11.5px; color: var(--fg-dim); }
.tl.tl-gap { height: 6px; margin: 0; }
/* AN IM's MESSAGES: each in a bubble, its sender and time above it on its side (theirs to the left,
   yours to the right), each sender's own color (--who-rgb: MOTH the theme's color, TOLL its accent,
   yours --im-you-rgb); while they type, three dots bob in theirs */
:is(.story-frag, .archive-file, .story-msg-box) .tl:is(.tl-im, .tl-you) { display: flex; flex-direction: column; align-items: flex-start; margin: 10px 0 0; --who-rgb: var(--fg-rgb); }
:is(.story-frag, .archive-file, .story-msg-box) .tl.tl-you { align-items: flex-end; --who-rgb: var(--im-you-rgb); }
.tl[data-who="toll"] { --who-rgb: var(--accent-rgb); }
.tl:is(.tl-im, .tl-you) .tl-head { display: flex; gap: 6px; align-items: baseline; margin: 0 6px 3px; font-size: 11px; line-height: 1.2; letter-spacing: 1px; }
.tl:is(.tl-im, .tl-you) .tl-who { color: rgb(var(--who-rgb)); }
.tl:is(.tl-im, .tl-you) .tl-time { color: var(--fg-dim); letter-spacing: 0; }
.tl .tl-bubble { max-width: 84%; box-sizing: border-box; padding: 6px 10px; border: 1px solid rgba(var(--who-rgb), 0.55); border-radius: 14px 14px 14px 4px; background: rgba(var(--who-rgb), 0.14); color: var(--panel-text); overflow-wrap: anywhere; }
.tl.tl-you .tl-bubble { border-radius: 14px 14px 4px 14px; }
.tl .tl-dots { display: none; }
.tl.tl-typing .tl-t { display: none; }
.tl.tl-typing .tl-dots { display: inline-flex; align-items: center; gap: 4px; height: 1.4em; padding: 0 2px; color: rgb(var(--who-rgb)); }
.tl-dots i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: 0.35; animation: tl-dot 1.2s ease-in-out infinite; }
.tl-dots i:nth-child(2) { animation-delay: 0.15s; }
.tl-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes tl-dot { 0%, 60%, 100% { transform: translateY(0); opacity: 0.35; } 30% { transform: translateY(-3px); opacity: 1; } }
.low-fx .tl-dots i { animation: none; opacity: 0.7; }
/* (a thread live: kept to its newest at the bottom, each new one rising in) */
.sf-chat { display: flex; flex-direction: column; }
.sf-chat::before { content: ''; flex: 1 0 0; } /* (few messages: they sit at the bottom) */
:is(.story-frag, .archive-file, .story-msg-box) .sf-chat .tl.tl-wait { display: none; }
.story-msg-box .sf-chat .tl:is(.tl-im, .tl-you) { animation: tl-rise 0.24s ease-out both; }
@keyframes tl-rise { from { opacity: 0; transform: translateY(10px); } }
.low-fx .story-msg-box .sf-chat .tl { animation: none; }
/* THE PHONE (#story-msg as .phone, every IM): one size, a phone's 9:19.5, its height the screen's
   less room for OK (no taller than 640px); status bar (the clock the newest message's time, a punch-hole
   camera, signal, wifi, battery), the contact (back arrow, avatar: ? till you know them), the thread
   (it scrolls), a message field and the gesture bar */
.story-msg-box.phone { width: auto; max-height: none; padding: 0; border: 0; background: none; box-shadow: none; display: flex; flex-direction: column; align-items: center; }
.story-msg-box.phone::before, .story-msg-box.phone::after { display: none; }
.story-msg-box.phone h2 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.story-msg-box.phone #story-msg-body { margin: 0; display: flex; flex-direction: column; align-items: center; }
.story-msg-box.phone .starter-pick-foot { margin-top: 12px; }
.story-msg-box.phone .sf-reveal { align-self: stretch; text-align: center; }
.phone-screen { position: relative; display: flex; flex-direction: column; box-sizing: border-box; height: min(640px, calc(100vh - 110px)); height: min(640px, calc(100dvh - 110px)); aspect-ratio: 9 / 19.5; border: 7px solid #000; border-radius: 30px; background: var(--popup-bg); box-shadow: 0 0 0 1px rgba(var(--fg-rgb), 0.45), 0 0 22px rgba(var(--fg-rgb), 0.22); overflow: hidden; text-align: left; }
.ph-status { position: relative; display: flex; align-items: center; justify-content: space-between; flex: 0 0 auto; padding: 6px 16px 2px; font-size: 11px; letter-spacing: 1px; color: var(--panel-text); }
.ph-status::after { content: ''; position: absolute; left: 50%; top: 6px; width: 9px; height: 9px; margin-left: -4.5px; border-radius: 50%; background: #000; box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08); }
.ph-icons { display: inline-flex; align-items: center; gap: 4px; }
.ph-icons svg { height: 9px; width: auto; }
.ph-bar { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; padding: 6px 10px 8px; border-bottom: 1px solid rgba(var(--fg-rgb), 0.15); }
.ph-back { padding: 0 4px; font: inherit; font-size: 16px; line-height: 1; color: var(--panel-text); background: none; border: 0; cursor: pointer; }
.ph-avatar { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; font-size: 12px; color: var(--popup-bg); background: rgb(var(--fg-rgb)); }
.ph-avatar[data-who="toll"] { background: rgb(var(--accent-rgb)); }
.ph-name { min-width: 0; overflow: hidden; font-size: 12px; letter-spacing: 1px; white-space: nowrap; text-overflow: ellipsis; color: var(--panel-text); }
.story-msg-box .phone-screen .ph-msgs { flex: 1 1 auto; min-height: 0; margin: 0; padding: 0 10px 10px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; cursor: pointer; }
.phone-screen .ph-msgs::-webkit-scrollbar { display: none; }
.ph-input { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; margin: 0 8px; padding: 6px 0 4px; }
.ph-plus { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%; font-size: 15px; color: var(--fg-dim); border: 1px solid rgba(var(--fg-rgb), 0.3); }
.ph-field { flex: 1; padding: 6px 12px; border-radius: 16px; font-size: 11.5px; color: var(--fg-dim); background: rgba(var(--fg-rgb), 0.08); }
/* THE PHONE'S OS (stories.js): the screen (an app) between the status bar and the nav bar, which is
   always there and works (BACK, HOME, MENU: recent apps), in place of a gesture line */
.phone-screen.os .ph-app { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.ph-nav { flex: 0 0 auto; display: flex; justify-content: space-around; align-items: center; height: 40px; border-top: 1px solid rgba(var(--fg-rgb), 0.12); }
.ph-nav button { width: 56px; height: 34px; display: flex; align-items: center; justify-content: center; padding: 0; background: none; border: 0; border-radius: 17px; color: var(--panel-text); cursor: pointer; }
.ph-nav svg { width: 18px; height: 18px; }
@media (hover: hover) { .ph-nav button:hover { background: rgba(var(--fg-rgb), 0.1); } }
.ph-nav button:active { background: rgba(var(--fg-rgb), 0.18); }
/* (the home screen: its apps in a grid; GAMES a folder of four) */
.ph-home-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px 4px; padding: 18px 10px; align-content: start; overflow-y: auto; }
.ph-icon { display: flex; flex-direction: column; align-items: center; gap: 5px; min-width: 0; padding: 0; font: inherit; color: var(--panel-text); background: none; border: 0; cursor: pointer; }
.ph-glyph { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 42px; height: 42px; box-sizing: border-box; border: 1px solid rgba(var(--fg-rgb), 0.55); border-radius: 11px; color: rgb(var(--fg-rgb)); background: rgba(var(--fg-rgb), 0.08); }
.ph-glyph svg { width: 22px; height: 22px; }
.ph-label { max-width: 100%; font-size: 8.5px; letter-spacing: 0.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ph-folder { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; padding: 5px; }
.ph-folder i { display: flex; align-items: center; justify-content: center; font-style: normal; font-size: 6.5px; border: 1px solid rgba(var(--fg-rgb), 0.4); border-radius: 3px; }
.ph-tile { font-size: 12px; letter-spacing: 0.5px; }
@media (hover: hover) { .ph-icon:hover .ph-glyph { background: rgba(var(--fg-rgb), 0.16); } }
/* (an app with nothing in it yet) */
.ph-note { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 20px; text-align: center; font-size: 11.5px; color: var(--fg-dim); }
.ph-note b { font-weight: normal; font-size: 12.5px; letter-spacing: 1.5px; color: var(--panel-text); }
/* MAIL: rows of who it's from, its time, its subject and first line; an email opened */
.ph-mail-subj { font-size: 11.5px; color: var(--panel-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ph-mail { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 10px 12px; }
.ph-mail-from { margin: 0; font-size: 10.5px; letter-spacing: 0.5px; color: var(--fg-dim); overflow-wrap: anywhere; }
.ph-mail-subject { margin: 4px 0 10px; font-size: 13px; color: var(--fg); }
/* CALLS: one read again; the ARCHIVE; a game, its frame filling the screen */
.ph-call, .ph-archive { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 8px 12px 12px; scrollbar-width: none; }
.ph-archive { zoom: 0.86; }
.ph-recent .ph-glyph { width: 30px; height: 30px; border-radius: 8px; }
.ph-recent .ph-glyph svg { width: 16px; height: 16px; }
.ph-game { display: block; flex: none; border: 0; transform-origin: 0 0; background: #000; }
/* THE INBOX (the phone's back arrow, stories.js's openInbox): the conversations, the newest first, each
   its avatar, name, time and last message; moving about the phone doesn't raise it again */
.ph-bar-inbox { padding: 10px 14px; }
.ph-title { font-size: 13px; letter-spacing: 2px; color: var(--panel-text); }
.ph-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; }
.ph-list::-webkit-scrollbar { display: none; }
.ph-convo { display: flex; align-items: center; gap: 10px; width: 100%; padding: 10px 12px; font: inherit; text-align: left; color: inherit; background: none; border: 0; border-bottom: 1px solid rgba(var(--fg-rgb), 0.12); cursor: pointer; }
.ph-convo .ph-avatar { width: 34px; height: 34px; font-size: 14px; }
.ph-convo-text { display: flex; flex-direction: column; gap: 3px; flex: 1 1 auto; min-width: 0; }
.ph-convo-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.ph-convo-time { flex: none; font-size: 10.5px; color: var(--fg-dim); }
.ph-convo-last { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 11.5px; color: var(--fg-dim); }
@media (hover: hover) { .ph-convo:hover { background: rgba(var(--fg-rgb), 0.06); } }
.ph-empty { display: block; margin: 24px 14px; font-size: 12px; color: var(--fg-dim); text-align: center; }
/* (the cracked card and the ARCHIVE: a thread as an inbox shows it, its last message, OPEN THREAD) */
:is(.sf-snippet, .af-snippet) { margin: 0 0 6px; overflow: hidden; font-size: 13px; line-height: 1.4; white-space: nowrap; text-overflow: ellipsis; color: var(--panel-text); }
:is(.sf-snippet, .af-snippet) span { color: var(--fg); letter-spacing: 1px; }
.sf-open { padding: 6px 10px; font: inherit; font-size: 11.5px; letter-spacing: 1px; color: var(--fg); background: transparent; border: 1px solid var(--fg); border-radius: 3px; cursor: pointer; }
/* (yours: a third color, apart from each theme's own two) */
:root { --im-you-rgb: 108, 182, 255; }
[data-theme="cipher"] { --im-you-rgb: 255, 158, 122; }
:is([data-theme="amber-crt"], [data-theme="anaglyph"]) { --im-you-rgb: 255, 143, 200; }
[data-theme="glyph"] { --im-you-rgb: 141, 255, 158; }
[data-theme="paper"] { --im-you-rgb: 31, 111, 209; }
[data-theme="monochrome"] { --im-you-rgb: 150, 150, 150; }
[data-theme="dot-matrix"] { --im-you-rgb: 120, 160, 40; }
.sf-answer { margin-left: 8px; padding: 2px 10px; font: inherit; font-size: 11.5px; letter-spacing: 1px; color: var(--accent); background: transparent; border: 1px solid var(--accent); border-radius: 3px; cursor: pointer; }
.story-frag .sf-lines { margin: 0; }
.story-frag .sf-gift { margin-top: 2px; }
/* (the ARCHIVE's GHOSTS: whose transmissions show) */
.archive-filter { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; }
.archive-filter button { padding: 4px 8px; font: inherit; font-size: 11.5px; letter-spacing: 1px; color: var(--fg-dim); background: transparent; border: 1px solid rgba(var(--fg-rgb), 0.35); border-radius: 3px; cursor: pointer; }
.archive-filter button.on { color: var(--fg); border-color: var(--fg); }
.story-msg-box #story-msg-body { margin-top: var(--gap); }
.story-frag .sf-reveal, .story-msg-box .sf-reveal, .archive-file .af-reveal { margin: 6px 0 0; font-size: 11.5px; letter-spacing: 1px; color: var(--accent); }
.starter-pick-foot button { font-family: inherit; font-size: 11px; letter-spacing: 1px; padding: 8px 12px; color: var(--fg); background: transparent; border: 1px solid var(--fg-dim); border-radius: 4px; cursor: pointer; }
.booster-break { flex-basis: 100%; height: 0; } /* (the slots on one line, the exploits owned below) */
/* PUZZLE: HINT and UNDO under the drop buttons, and the column HINT lights */
.puzzle-tools { display: flex; justify-content: center; gap: 8px; margin-top: 6px; }
.puzzle-tools[hidden] { display: none; }
.puzzle-tools button {
  padding: 4px 12px; background: none; border: 1px solid var(--fg-dim); border-radius: 4px;
  color: var(--fg); font-family: inherit; font-size: 11px; letter-spacing: 1px; cursor: pointer;
}
.puzzle-tools button:disabled { opacity: 0.35; cursor: default; }
.column-buttons button.hinted { border-color: var(--accent); color: var(--accent); animation: amber-pulse 0.9s ease-in-out infinite; }
/* (the DAILY PUZZLE's hint, in words: a card over the board's empty top, till the next drop or a tap) */
.hint-card { position: absolute; top: 8px; left: 16px; right: 16px; z-index: 3; display: flex; flex-direction: column; gap: 4px; padding: 8px; background: rgba(2, 6, 4, 0.92); border: 1px solid var(--accent); border-radius: 6px; box-shadow: 0 0 12px rgba(var(--accent-rgb), 0.35); text-align: center; cursor: pointer; }
.hint-card[hidden] { display: none; }
.hint-card b { font-weight: normal; font-size: 11.5px; letter-spacing: 2px; color: var(--accent); }
.hint-card span { font-size: 14.5px; line-height: 1.35; color: var(--fg); text-shadow: 0 0 6px rgba(var(--fg-rgb), 0.5); }
/* (the DAILY PUZZLE's crossed-out columns: a red X on the button, a faint red over the column, till the next drop) */
.column-buttons button.crossed, .column-buttons button.crossed:disabled { opacity: 0.9; color: var(--danger); border-color: rgba(var(--danger-rgb), 0.7); text-shadow: 0 0 6px rgba(var(--danger-rgb), 0.6); }
.cell.hint-crossed:not(.disc):not(.firewall) { background-color: rgba(var(--danger-rgb), 0.07); border-color: rgba(var(--danger-rgb), 0.25); }
/* The KEYS a game earned, under its score */
.overlay-keys { margin: 4px 0 0; font-size: 15.5px; letter-spacing: 1px; color: var(--accent); }
.overlay-keys[hidden] { display: none; }
/* THE LEVEL METER after a game: this game's bits filling it; a flash at each LEVEL UP */
.overlay-xp { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 10px 0 14px; font-size: 12px; letter-spacing: 1px; color: var(--fg-dim); cursor: pointer; }
.overlay-xp[hidden] { display: none; }
.oxp-level { min-width: 52px; text-align: right; color: var(--fg); }
.oxp-bar { display: block; width: 120px; height: 6px; background: rgba(var(--fg-rgb), 0.12); border-radius: 3px; overflow: hidden; }
.oxp-bar i { display: block; height: 100%; width: 0; background: var(--fg); box-shadow: 0 0 6px rgba(var(--fg-rgb), 0.6); }
.oxp-gain { min-width: 70px; text-align: left; }
.overlay-xp.leveled .oxp-level { color: var(--accent); animation: oxp-flash 0.6s steps(2) 2; }
.overlay-xp.leveled .oxp-bar i { background: var(--accent); }
@keyframes oxp-flash { 50% { opacity: 0.3; } }
.key-ico { width: 1em; height: 1em; vertical-align: -0.15em; }
/* EXPLOITS' terminal (TERMINAL_SVG): in a heading, KEYS's size */
h2 > .term-ico, h3 > .term-ico, .opt-text .term-ico { width: 1em; height: 1em; vertical-align: -0.15em; margin-right: 0.35em; }
/* PATCHES' USB stick (USB_SVG): KEYS's height, twice its width */
.usb-ico { width: 2em; height: 1em; vertical-align: -0.15em; margin-right: 0.35em; flex: none; }
/* STORE: the ===== line between what KEYS buy and what money buys, as the other menus have them */
.store-rule { margin: 16px 0 4px; overflow: hidden; white-space: nowrap; font-size: 14.5px; line-height: 15px; letter-spacing: 2px; color: var(--accent); opacity: 0.7; } /* (as RECORDS' .rec-sep) */
body:not(.vs-mode) .hud-bits #time-stat .value { margin: 0; font-size: 14px; line-height: 1; }
/* The game's one text size (what the old TEXT SIZE setting called LARGER), written in as each
   element's own font size. Text that has no size of its own in the menu card's pages, the notes, the
   tutorial and the game over box's lines takes 1.3x what it would inherit (:where, so any element's
   own size wins) */
:root { --label-min: 9; }
:where(.settings-note, .tut-text, .tut-points, .overlay-box p, .records .menu-pane > .panel) { font-size: 1.3em; }
.cpu-desc { font-size: 13px; }
.hud .stat .label { font-size: 10.5px; }
/* The snowman's powder as it comes apart (visitors.js) */
.visitor .snow-powder { position: absolute; bottom: 0; pointer-events: none; }
/* The other viruses: ADWARE's message on its window, the LOGIC BOMB's last seconds (its fuse
   flaring, the bomb flashing), the WORM and SPYWARE glitching now and then like the BUG */
.visitor-adware .adware-text { position: absolute; left: 0; right: 0; top: 34%; text-align: center; font-size: 7px; line-height: 1; letter-spacing: 0; color: #d42a2a; font-weight: bold; white-space: nowrap; pointer-events: none; }
.visitor-logicbomb.v-fuse-hot > svg { animation: fuse-hot 0.3s steps(1) infinite; }
@keyframes fuse-hot { 50% { filter: brightness(1.8) drop-shadow(0 0 3px #ff7a1f); } }
:is(.visitor-worm, .visitor-spyware, .visitor-ransomware) > svg { animation: virus-glitch 3.2s steps(1) infinite; }
/* PUSHED BITs (visitors.js): the grid's own bit (.cell.disc), half again a bot's size, on the floor */
.visitor-bit .pushed-bit { position: absolute; left: 0; bottom: 0; width: 51px; height: 51px; font-size: 19px; box-sizing: border-box; }
.visitor-bit .pushed-bit .glyph-num { font-size: 12px; right: 4px; bottom: 2px; }

/* The RESOURCES (ECONOMY.md): the wallet lines, the game-over haul, a drop's pickups */
.wallet { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 12px; margin: 2px 0 6px; font-size: 12px; letter-spacing: 1px; color: var(--fg); }
.res-chip { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
.res-chip .key-ico { width: 13px; height: 13px; }
.res-chip .key-ico, .shop-cost .key-ico { color: var(--accent); } /* (KEYS: the theme's accent) */
.res-bugs .key-ico { color: var(--res-bugs); }
.res-cache .key-ico { color: var(--res-cache); }
.res-crypto .key-ico { color: var(--res-crypto); }
.res-rootkits .key-ico { color: var(--res-rootkits); }
.res-master .key-ico { color: var(--res-master); filter: drop-shadow(0 0 2px var(--res-master-glow)); }
.overlay-keys .haul { display: block; margin-top: 4px; }
.overlay-keys .haul .res-chip { margin: 0 4px; }
@keyframes res-pop { 0% { opacity: 0; translate: 0 8px; } 15% { opacity: 1; translate: 0 0; } 75% { opacity: 1; } 100% { opacity: 0; translate: 0 -18px; } }
@media (prefers-reduced-motion: reduce) { .res-pop, .ransom-pop { animation-name: res-pop-still; } @keyframes res-pop-still { 0%, 80% { opacity: 1; } 100% { opacity: 0; } } }

/* The STORE's exploits and boxes: the icon left of the name, the price in chips, what's short */
.starter-item h3 { display: flex; align-items: center; gap: 8px; }
.starter-item .store-name { flex: 1; }
.store-ico { display: inline-flex; align-items: center; justify-content: center; width: 24px; margin-right: 6px; height: 24px; position: relative; color: var(--accent); font-size: 23.5px; }
.store-ico svg { width: 20px; height: 20px; }
.store-cost { display: flex; flex-wrap: wrap; gap: 4px 10px; margin: 6px 0 2px; font-size: 15.5px; letter-spacing: 1px; }
.store-odds { margin: 4px 0; font-size: 14.5px; letter-spacing: 0.5px; color: var(--fg-dim); }
.store-master { margin-right: 6px; }
.store-master[hidden] { display: none; }
/* A BLACK BOX's tier, on its icon */
.box-tier { position: absolute; right: -4px; bottom: -3px; font-size: 9px; font-weight: bold; line-height: 1; color: var(--accent); text-shadow: 0 0 3px var(--bg-solid), 0 0 2px var(--bg-solid); letter-spacing: 0; }
.exploit-glyph { position: relative; }
.starter-pick-item .exploit-glyph svg { width: 18px; height: 18px; }
/* A side slot: a sealed BLACK BOX, its reel spinning, an ANTI-EXPLOIT's glitch */
.exploit-icon.side-slot.sealed { animation: amber-pulse 1.6s ease-in-out infinite; }
.exploit-icon.side-slot.rolling { color: var(--accent); border-color: var(--accent); }
.exploit-icon.side-slot.quarantined { color: var(--fg); border-color: var(--fg); --dim: 0.5; filter: grayscale(1); }
.exploit-icon.side-slot.glitched { color: var(--danger); border-color: var(--danger); animation: slot-glitch 0.12s steps(2) 5; }
@keyframes slot-glitch { 0% { transform: translate(-2px, 1px); } 50% { transform: translate(2px, -1px); } 100% { transform: none; } }
/* ADWARE's pop-up over a drop button */
.column-buttons button.adware.ad-shake { animation: ad-shake 0.3s steps(4); }
@keyframes ad-shake { 25% { transform: translateX(-2px); } 75% { transform: translateX(2px); } }
.column-buttons button.adware { color: var(--danger); border-color: var(--danger); background: repeating-linear-gradient(45deg, rgba(255, 77, 94, 0.18) 0 4px, transparent 4px 8px); opacity: 1; }

/* An exploit's icon in brackets beside its name ([!]), in the STORE and a starter slot's card */
.bracketed { width: auto !important; gap: 1px; display: inline-flex; align-items: center; }
.bracketed > svg, .bracketed > .ico { position: relative; }
.ico-br { font-weight: normal; opacity: 0.8; font-size: 0.85em; }
.store-ico.bracketed { position: relative; min-width: 44px; justify-content: flex-start; }
.store-ico.bracketed svg { width: 16px; height: 16px; }
.starter-pick-item .exploit-glyph.bracketed { min-width: 3.2em; font-size: 14px; }
.starter-pick-item .exploit-glyph.bracketed svg { width: 15px; height: 15px; }
.bracketed .box-tier { display: none; } /* (the name says I, II or III) */

/* RNG's scramble: the bits churn in place, flickering */
.cell.scrambling { color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.8); animation: scramble-flash 0.09s steps(2) infinite; }
@keyframes scramble-flash { 50% { opacity: 0.55; } }

/* THE CURRENCY SIGN (a 0 struck twice) */
.cur-ico { width: 1em; height: 1em; display: inline-block; vertical-align: -0.12em; }
/* A BLACK MARKET slot: the sign in its corner, for sale */
.slot-sale { position: absolute; top: -6px; right: -6px; width: 15px; height: 15px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--bg-solid); border: 1px solid var(--accent); color: var(--accent); box-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6); }
.slot-sale .cur-ico { width: 10px; height: 10px; }

/* THE BLACK MARKET's window: a neon sign of a border, the price in icons, BUY */
#market-shop { z-index: 207; background: rgba(0, 0, 0, 0.6); }
.shop-box { position: relative; width: min(330px, calc(100vw - 32px)); padding: 20px 18px 16px; text-align: center; border: 2px solid var(--accent); border-radius: 10px; background: linear-gradient(rgba(var(--accent-rgb), 0.06), rgba(var(--accent-rgb), 0.02)), var(--popup-bg);
  box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.7), 0 0 28px rgba(var(--accent-rgb), 0.35), inset 0 0 12px rgba(var(--accent-rgb), 0.25); animation: neon-hum 3.2s ease-in-out infinite; }
/* (scan lines over it: the data-terminal side of the shop) */
.shop-box::before { content: ''; position: absolute; inset: 0; border-radius: 8px; pointer-events: none; background: repeating-linear-gradient(0deg, rgba(var(--fg-rgb), 0.05) 0 1px, transparent 1px 3px); }
@keyframes neon-hum { 0%, 100% { box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.7), 0 0 28px rgba(var(--accent-rgb), 0.35), inset 0 0 12px rgba(var(--accent-rgb), 0.25); } 47% { box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.7), 0 0 28px rgba(var(--accent-rgb), 0.35), inset 0 0 12px rgba(var(--accent-rgb), 0.25); } 48% { box-shadow: 0 0 4px rgba(var(--accent-rgb), 0.4), 0 0 10px rgba(var(--accent-rgb), 0.15), inset 0 0 4px rgba(var(--accent-rgb), 0.1); } 50% { box-shadow: 0 0 12px rgba(var(--accent-rgb), 0.85), 0 0 34px rgba(var(--accent-rgb), 0.45), inset 0 0 14px rgba(var(--accent-rgb), 0.3); } }
.shop-box h2 { margin: 0 0 12px; font-size: 15px; letter-spacing: 3px; color: var(--accent); text-shadow: 0 0 8px rgba(var(--accent-rgb), 0.8); }
.shop-sign { position: absolute; top: -14px; right: -10px; z-index: 2; transform: rotate(14deg); display: flex; gap: 1px; padding: 3px 6px; color: var(--accent); background: var(--bg-solid); border: 1px solid var(--accent); border-radius: 4px; font-size: 18px;
  box-shadow: 0 0 8px rgba(var(--accent-rgb), 0.7); }
/* (the sign itself stays solid, so nothing shows through it: only its marks dim and flare, like a neon tube) */
.shop-sign .cur-ico { animation: sign-pulse 1.4s ease-in-out infinite; filter: drop-shadow(0 0 3px rgba(var(--accent-rgb), 0.9)); }
@keyframes sign-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } 52% { opacity: 1; } } /* (a fade, as the costs' pulse) */
.shop-item { display: flex; flex-direction: column; align-items: center; gap: 4px; margin-bottom: 12px; }
.shop-ico { display: inline-flex; align-items: center; gap: 2px; font-size: 26px; color: var(--accent); }
.shop-ico svg { width: 26px; height: 26px; }
.shop-ico .ico-br { font-size: 22px; }
.shop-ico .box-tier { display: none; }
.shop-name { font-size: 16px; letter-spacing: 2px; color: var(--fg); }
.shop-tier { font-size: 10px; letter-spacing: 1px; color: var(--fg-dim); }
.shop-costs { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 16px; margin: 6px 0 8px; padding: 10px 6px; border-top: 1px dashed rgba(var(--accent-rgb), 0.4); border-bottom: 1px dashed rgba(var(--accent-rgb), 0.4); }
.shop-cost { display: flex; flex-direction: column; align-items: center; gap: 4px; font-size: 17px; letter-spacing: 1px; color: var(--fg); min-width: 44px; }
.shop-cost .key-ico { width: 20px; height: 20px; }
.shop-cost.short span { color: var(--danger); }
.shop-note { margin: 4px 0 12px; font-size: 13.5px; letter-spacing: 1px; color: var(--fg-dim); min-height: 1em; }
.shop-foot { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.shop-buy, .shop-alt { font-family: inherit; letter-spacing: 3px; cursor: pointer; border-radius: 6px; }
.shop-buy { font-size: 15px; padding: 10px 34px; color: var(--bg-solid); background: var(--accent); border: 1px solid var(--accent); box-shadow: 0 0 12px rgba(var(--accent-rgb), 0.6); }
.shop-buy:disabled { color: var(--fg-dim); background: transparent; border-color: var(--grid-line); box-shadow: none; cursor: default; }
.shop-alt { font-size: 11px; padding: 7px 14px; color: var(--res-master); background: transparent; border: 1px solid var(--res-master); }
.shop-alt[hidden] { display: none; }
.shop-x { position: absolute; top: 6px; left: 8px; width: 28px; height: 28px; font-size: 20px; line-height: 1; color: var(--fg-dim); background: none; border: 0; cursor: pointer; }
@media (prefers-reduced-motion: reduce) { .shop-box, .shop-sign .cur-ico, .cell.scrambling, .panel-store { animation: none; } }

/* A BLACK MARKET slot before it opens (the first layer hasn't risen): its offer to look at, dimmed */
.exploit-icon.side-slot.market.locked { --dim: 0.35; }
/* (a side slot not open yet: dim, a padlock over the level it opens at) */
.exploit-icon.side-slot.locked-slot { flex-direction: column; gap: 2px; --dim: 0.5; border-style: dashed; color: var(--fg-dim); cursor: default; }
.slot-lock { width: 12px; height: 14px; }
.slot-lv { font-size: 9px; letter-spacing: 1px; line-height: 1; }
/* (the BLACK MARKET's countdown: its frame in four sides, lit, one going dark a drop till it turns over) */
/* THE COUNTDOWN: a pip under the icon for each drop till the offer turns over; on the last drop
   what's left blinks, and at the turnover the icon rolls like a reel (script.js, turnSlot) */
.exploit-icon:has(> .slot-pips) > .exploit-glyph { transform: translateY(-4px); }
.exploit-icon > .slot-pips { position: absolute; left: 0; right: 0; bottom: 4px; display: flex; justify-content: center; gap: 3px; pointer-events: none; filter: none; }
.slot-pips i { width: 5px; height: 3px; background: rgba(var(--accent-rgb), 0.2); }
.slot-pips i.on { background: var(--accent); box-shadow: 0 0 3px rgba(var(--accent-rgb), 0.8); }
.exploit-icon.side-slot.last-drop .slot-pips i.on, .exploit-icon.side-slot.last-drop:not(.turning) > .exploit-glyph { animation: last-drop 0.5s steps(1) infinite; }
@keyframes last-drop { 50% { opacity: 0.2; } }
.exploit-icon.side-slot.turning { color: var(--accent); }
:root.low-fx .exploit-icon.side-slot.last-drop :is(.slot-pips i.on, .exploit-glyph) { animation: none; }
@media (prefers-reduced-motion: reduce) { .exploit-icon.side-slot.last-drop :is(.slot-pips i.on, .exploit-glyph) { animation: none; } }
/* THE PATCH SLOTS at the row's ends: a patch for sale, as the BLACK MARKET's (applied: lit, a tick) */
.exploit-icon.patch-slot .exploit-glyph .ico { width: 22px; height: 22px; }
/* Paused: the exploits, the BLACK MARKET and the patches dim and wait, as the drop buttons do */
.exploit-row, .puzzle-tools { transition: opacity 0.15s; }
:is(.exploit-row, .puzzle-tools).paused-row { opacity: 0.25; pointer-events: none; }
:is(.exploit-row, .puzzle-tools).paused-row * { animation-play-state: paused !important; }
.exploit-icon.side-slot.market.locked .slot-sale { border-color: var(--fg-dim); color: var(--fg-dim); box-shadow: none; }

/* The description in the BLACK MARKET's window */
.shop-desc { max-width: 260px; margin-top: 4px; font-size: 11px; line-height: 1.45; color: var(--panel-text); }

/* THE STORE in the BLACK MARKET's look: a neon sign of a border in the accent, scan lines, the tilted
   sign in the corner, and the cards lit in the accent */
.panel.panel-store { position: relative; border: 2px solid var(--accent); border-radius: 10px;
  background: linear-gradient(rgba(var(--accent-rgb), 0.05), rgba(var(--accent-rgb), 0.015)), var(--panel);
  box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.55), 0 0 26px rgba(var(--accent-rgb), 0.22), inset 0 0 12px rgba(var(--accent-rgb), 0.18); animation: neon-hum 3.2s ease-in-out infinite; }
.panel.panel-store::before { content: ''; position: absolute; inset: 0; border-radius: 8px; pointer-events: none; background: repeating-linear-gradient(0deg, rgba(var(--fg-rgb), 0.045) 0 1px, transparent 1px 3px); }
.panel-store h2 { color: var(--accent); letter-spacing: 4px; text-shadow: 0 0 8px rgba(var(--accent-rgb), 0.8); }
.store-sign { top: -14px; right: -10px; } /* (where the BLACK MARKET's sits: off the corner, clear of the KEYS) */
.panel-store .store-item { border-color: rgba(var(--accent-rgb), 0.35); background: rgba(var(--accent-rgb), 0.025); }
.panel-store .store-sub { text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6); }
.panel-store .store-buy:not(:disabled):not(.short) { box-shadow: 0 0 8px rgba(var(--accent-rgb), 0.45); }
.store-desc { color: var(--panel-text); line-height: 1.45; }

/* A price's amounts: green where you have enough, red where you're short (the STORE and the BLACK MARKET's window) */
.shop-cost.afford span, .res-chip.afford { color: var(--afford); }
.shop-cost.short span, .res-chip.short { color: var(--danger); }
/* (room above the STORE's neon border, so the card's top bar, solid and pinned, doesn't cut its glow off) */
.records .menu-pane[data-pane="store"]:not([hidden]) { padding: 14px 2px 4px; }

/* The STORE's prices as the BLACK MARKET's: each resource's icon over have / cost */
.store-costs { display: flex; flex-wrap: wrap; gap: 8px 14px; padding: 6px 0 2px; }
.store-costs .shop-cost { font-size: 15.5px; min-width: 38px; }
.store-costs .shop-cost .key-ico { width: 17px; height: 17px; }
/* BUY with the currency sign */
.store-buy .cur-ico, .shop-buy .cur-ico { width: 0.95em; height: 0.95em; margin-right: 4px; vertical-align: -0.12em; }

/* A STORE item's deal: the price (have / cost under each icon) and OWNED as one tight block, BUY level with
   its middle on the right (USE A MASTER KEY over BUY when it shows) */
.store-deal { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.store-terms { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.store-terms .store-costs { padding: 2px 0 0; gap: 4px 12px; }
.store-terms .booster-owned { font-size: 13.5px; letter-spacing: 1px; line-height: 1.2; }
.store-terms .booster-owned:empty { display: none; }
.store-btns { flex: none; display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.store-btns .store-buy { align-self: auto; }
.store-btns .store-master { margin: 0; font-size: 10px; letter-spacing: 1px; padding: 5px 8px; }
/* (tight enough for a four-part price on one line beside BUY on a phone) */
.store-terms .store-costs { gap: 2px 8px; flex-wrap: nowrap; }
.store-terms .shop-cost { min-width: 0; font-size: 14.5px; letter-spacing: 0.5px; gap: 2px; }
.store-terms .shop-cost .key-ico { width: 15px; height: 15px; }
.store-btns .store-buy { padding: 6px 10px; letter-spacing: 1px; }
/* THE STORE: its top (title, KEYS, resources) stays put, its body scrolls under it inside the
   neon border. The border's glow is kept within the card's padding (the card clips what spills past it) */
.records .menu-pane > .panel.panel-store { display: flex; flex-direction: column; overflow: hidden; padding-bottom: 0;
  box-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6), 0 0 12px rgba(var(--accent-rgb), 0.25), inset 0 0 12px rgba(var(--accent-rgb), 0.18); animation: none; }
.store-top { flex: none; position: relative; z-index: 1; padding-bottom: 0; }
.store-top::after { content: "================================================================================"; display: block; margin-top: 8px; overflow: hidden; white-space: nowrap; font-size: 14.5px; line-height: 15px; letter-spacing: 2px; color: var(--accent); opacity: 0.7; } /* (as .store-rule) */
.store-top h2 { margin-top: 0; }
.store-top .wallet { margin-bottom: 0; }
/* The STORE's i (how resources are earned): a small ringed i by the title; the resources' line opens it too */
/* (a pixel i in the brackets the exploits and boosters wear, like a bit on the board) */
.store-info { all: unset; box-sizing: border-box; position: relative; display: inline-flex; vertical-align: middle; margin: 0 0 0 2px; gap: 1px; align-items: center;
  font-size: 17px; letter-spacing: 0; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6); cursor: pointer; }
.store-info .ico-br { color: var(--fg); opacity: 0.75; text-shadow: none; }
.store-info svg { width: 10px; height: 16px; filter: drop-shadow(0 0 3px rgba(var(--accent-rgb), 0.7)); }
.store-info::before { content: ""; position: absolute; inset: -9px; } /* (a bigger target for a thumb) */
.store-info:hover .ico-br, .store-info:focus-visible .ico-br { color: var(--accent); }
.store-info:focus-visible { outline: 1px solid var(--accent); outline-offset: 3px; }
.store-wallet-btn { cursor: pointer; border-radius: 6px; }
.store-wallet-btn:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
#res-info { z-index: 207; }
.res-info-box { width: min(400px, calc(100vw - 32px)); max-height: calc(100vh - 32px); max-height: calc(100dvh - 32px); overflow-y: auto; }
.res-info-list { display: flex; flex-direction: column; gap: 10px; margin: 10px 0 12px; text-align: left; }
.res-info-row { display: flex; flex-direction: column; gap: 3px; padding-bottom: 9px; border-bottom: 1px solid var(--grid-line); }
.res-info-row b { display: inline-flex; align-items: center; gap: 6px; font-weight: normal; font-size: 13px; letter-spacing: 2px; color: var(--fg); }
.res-info-row b .key-ico { width: 15px; height: 15px; }
.res-keys b .key-ico { color: var(--accent); }
.res-info-row span { font-size: 11px; line-height: 1.5; color: var(--fg-dim); }
.res-info-note { text-align: left; font-size: 11px; line-height: 1.5; }
.res-info-body { margin: 10px 0 14px; text-align: left; }
.res-info-body p { margin: 0 0 8px; font-size: 12px; line-height: 1.55; color: var(--fg-dim); }
.res-info-body p:first-child { color: var(--fg); }
.store-sub .store-info { font-size: 14px; margin-left: 4px; }
.store-sub .store-info svg { width: 8px; height: 13px; }
.store-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; padding: 0 0 14px; }
.records .menu-pane[data-pane="store"]:not([hidden]) { padding: 12px 0 4px; }

/* BUY with its KEYS cost under it (the STORE): the word over the cost, red when you're short */
.store-btns .store-buy { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 5px 10px; min-width: 64px; }
.buy-word { white-space: nowrap; }
.buy-keys { display: inline-flex; align-items: center; gap: 3px; font-size: 10.5px; letter-spacing: 0.5px; }
.buy-keys .key-ico { width: 13px; height: 13px; }
.store-buy .buy-keys.short { color: var(--danger); }
.store-buy:disabled .buy-keys:not(.short) { color: var(--fg-dim); }
/* (the price row: up to four resources at three digits each, have / cost, each reading cleanly) */
.store-terms .store-costs { gap: 2px 10px; }
.store-terms .shop-cost { min-width: 46px; }

/* WATCH AD (the app: a free RESTORE POINT for a rewarded ad), on the card's left, level with BUY on its
   right (a patch's price has no resources to show there): the pixel play arrow, what's left today */
.store-terms.with-ad { flex-direction: row; align-items: center; gap: 10px; }
.store-terms .store-ad { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 5px 10px; min-width: 64px; }
.store-ad .key-ico { width: 0.7em; height: 0.9em; vertical-align: -0.05em; }
.store-ad .ad-left { color: var(--accent); }
.store-ad:disabled .ad-left { color: var(--fg-dim); }
:is(.store-btns, .store-terms) [hidden] { display: none !important; }
/* (USE + the MASTER KEY's icon: as narrow as BUY, in the MASTER KEYS' gold) */
.store-btns .store-master { flex-direction: row; justify-content: center; gap: 5px; color: var(--res-master); border-color: var(--res-master); font-size: 11px; padding: 5px 10px; }
.store-btns .store-master .key-ico { width: 15px; height: 15px; filter: drop-shadow(0 0 2px var(--res-master-glow)); }
/* (a fourth resource at three digits wraps under the others on the narrowest phones, rather than running under BUY) */
.store-terms .store-costs { flex-wrap: wrap; }

/* What's short of a price pulses red (the STORE and the BLACK MARKET's window), in place of a NEED line;
   a BUY tapped without enough flashes it harder for a moment */
/* (a fade only, the glow held steady: a fade's drawn by the graphics chip, a glow redrawn every frame
   wasn't, and the STORE can have dozens of them going) */
.shop-cost.short, .buy-keys.short { filter: drop-shadow(0 0 3px rgba(var(--danger-rgb), 0.75)); animation: short-pulse 1.2s ease-in-out infinite; }
.shop-cost.short span, .buy-keys.short { color: var(--danger); }
@keyframes short-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
.shop-cost.short.nudge, .buy-keys.short.nudge { animation: short-nudge 0.5s steps(2) 2, short-pulse 1.2s ease-in-out 1s infinite; }
@keyframes short-nudge { 0% { transform: translateX(-2px) scale(1.12); filter: drop-shadow(0 0 6px rgba(var(--danger-rgb), 1)); } 100% { transform: translateX(2px) scale(1.12); filter: drop-shadow(0 0 6px rgba(var(--danger-rgb), 1)); } }
@media (prefers-reduced-motion: reduce) { .shop-cost.short, .buy-keys.short { animation: none; } }
.shop-note:empty { display: none; } /* (only the "opens when..." line now; nothing to say, no gap) */
/* A STORE item's name starts right after its icon in brackets (TIER stays at the right) */
.store-item h3 { align-items: center; gap: 0; }
.store-ico.bracketed { width: auto; min-width: 0; margin-right: 6px; }
.store-item h3 .store-name { flex: 1; }
/* The price row: four equal columns, so each tag sits in the same place on every item and four
   three-digit prices (999/99) fit beside BUY on a phone; BUY slimmer to give them the room */
.store-deal { gap: 8px; }
.store-terms { flex: 1 1 auto; }
.store-terms .store-costs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2px 4px; max-width: 216px; flex-wrap: nowrap; }
.store-terms .shop-cost { min-width: 0; font-size: 13.5px; letter-spacing: 0; }
.store-btns .store-buy { min-width: 0; padding: 4px 7px; font-size: 11px; letter-spacing: 0.5px; }
.store-btns .store-buy .cur-ico { margin-right: 2px; }
.store-btns .store-master { padding: 4px 7px; gap: 3px; }

/* The BOOSTERS card's ON / OFF */
.booster-pick-state { min-width: 2.6em; text-align: right; font-size: 10.5px; letter-spacing: 1px; color: var(--fg-dim); }
.starter-pick-item.on .booster-pick-state { color: var(--accent); }
#booster-pick { z-index: 207; }
.starter-pick-item .exploit-glyph.bracketed .ico { width: 15px; height: 15px; }

/* THE GAME CARD'S LANE reaches up to the grid's bottom edge (fitGameLane, script.js): the drop
   buttons, the exploit row and the message stay over it, so LIGHTS OUT, the night and the fog fill the
   lane under them and nothing in the air covers them. Its covers start at its own top now */
.exploit-row { position: relative; z-index: 2; }
.game-walkers .lights-out, .game-walkers .night-dark, .game-walkers .fog-dark { top: 0; }
.game-walkers .fog-layer { top: 0; height: calc(100% + 6px); }

/* The main menu's mode panel (// CLASSIC ...): the VS setup's look, the board's color with its
   defragmenting grid behind the options, in place of the flat green tint */
.home-panel { position: relative; isolation: isolate; overflow: hidden; background: var(--board-bg); }
.home-panel-bg { z-index: -1; }
/* LIGHTS OUT's top edge fades into the rest of the card, rather than a hard line (on the game card it starts a
   little above the lane, behind the grid's card, so the fade wraps around its sides) */
:is(.start-walkers, .game-walkers) .lights-out { -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 70px); mask-image: linear-gradient(to bottom, transparent 0, #000 70px); }
.game-walkers .lights-out { top: -36px; }

/* DAILY's setup on the menu's panel: a card for each of today's games (its name, rules and how today stands);
   the one picked lit, the ones whose official run is done ticked and dimmer */
.daily-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; width: 100%; }
.daily-cards[hidden] { display: none; }
.daily-cards button { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; min-width: 0; padding: 8px 9px; text-align: left;
  font-family: inherit; color: var(--fg); background: rgba(var(--fg-rgb), 0.04); border: 1px solid var(--grid-line); border-radius: 5px; cursor: pointer; }
.daily-cards .dc-name { font-size: 13px; letter-spacing: 2px; display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
/* (the game's own win streak, on its name's line) */
.daily-cards .dc-streak { font-size: 9.5px; letter-spacing: 0.5px; color: var(--accent); text-shadow: none; white-space: nowrap; }
.daily-cards .dc-rule { font-size: 10px; line-height: 1.35; color: var(--panel-text); letter-spacing: 0.3px; }
.daily-cards .dc-status { margin-top: auto; padding-top: 2px; font-size: 9.5px; letter-spacing: 0.5px; color: var(--accent); }
.daily-cards button.done .dc-status { color: var(--fg-dim); }
.daily-cards button.active { border-color: var(--fg); background: rgba(var(--fg-rgb), 0.14); box-shadow: 0 0 10px rgba(var(--fg-rgb), 0.3); }
.daily-cards button.active .dc-name { color: var(--fg); text-shadow: 0 0 6px rgba(var(--fg-rgb), 0.6); }
.daily-cards button.danger { border-color: var(--danger); color: var(--danger); justify-content: center; align-items: center; letter-spacing: 2px; }
/* In a game, PAUSE sits in the top-right corner (SETTINGS' spot, empty in a game); ← BACK, when there's
   nothing to pause, stays top left like the cards' BACK */
body.in-game.can-pause .records-btn { left: auto; right: 8px; }
/* (PAUSE: a fingertip-sized target round its two small bars, reaching past the button on every side;
   lit the moment it's pressed, even when it waits for a drop to finish) */
body.in-game.can-pause .records-btn::before { content: ""; position: absolute; inset: -12px -10px -14px -16px; }
body.in-game.can-pause .records-btn.pause-queued { opacity: 1; filter: drop-shadow(0 0 4px rgba(var(--fg-rgb), 0.6)); }
body.in-game.can-pause .records-btn svg { left: auto; right: 4px; } /* (hugging the right corner, as it hugged the left) */

/* THE MAIN MENU stays put. Pinned to the top. Every box a set size in every mode, font and TEXT SIZE:
   the buttons a fixed height, the mode panel the room left down to its cap (whatever the mode puts
   in it), the rows under it right after. Only the words change: TEXT SIZE scales them inside their
   boxes, and script.js's fitHome shrinks any that won't fit. In the panel the mode's description
   takes what its other parts leave */
.home { justify-content: flex-start; gap: 10px; padding-top: 30px; padding-bottom: 54px; }
.home > * { flex-shrink: 0; }
.home .home-panel { flex: 1 1 0; min-height: 0; max-height: 340px; justify-content: flex-start; gap: 8px; padding: 10px 12px; }
.home-panel > * { flex-shrink: 0; }
.home-panel .home-play { margin-top: auto; }
.home .modes button, .home-row button, .home .home-play, #difficulty-row button, .home .home-opts button {
  display: flex; align-items: center; justify-content: center; text-align: center;
  white-space: nowrap; overflow: hidden; padding-top: 0; padding-bottom: 0;
}
.home .modes button { height: 34px; }
.home-row button { height: 32px; }
.home .home-play { height: 36px; flex-shrink: 0; }
#difficulty-row button { height: 26px; }
.home-mode-name { height: 18px; white-space: nowrap; overflow: hidden; line-height: 18px; }
.home .mode-info { flex: 1 1 0; min-height: 0; overflow: hidden; width: 100%; font-size: 14.5px; }
.home-best { height: 15px; line-height: 15px; overflow: hidden; white-space: nowrap; font-size: 14.5px; }
/* DAILY's cards: set sizes, their words in em so they shrink together */
.home .daily-cards button { height: 64px; overflow: hidden; font-size: 13px; }
.home .daily-cards .dc-name { font-size: 1.3em; }
.home .daily-cards .dc-rule { font-size: 1em; }
.home .daily-cards .dc-status { font-size: 0.95em; }
.home .daily-cards .dc-streak { font-size: 0.73em; } /* (the status's size, under the name's 1.3em) */
/* (the menu's top lines too: one line each, a set height) */
.home .level-bar { height: 16px; padding-top: 0; padding-bottom: 0; max-width: 100%; white-space: nowrap; overflow: hidden; }
.home .wallet { height: 14px; overflow: hidden; }
/* Set boxes across the game, not just the main menu: TEXT SIZE and the font change words, never a
   button's size or where things sit. The cards' pages are zoomed for TEXT SIZE, but their buttons
   are zoomed back to their own size; the message line and VS's notes are one size and their words
   scale (and shrink to fit: script.js's fitText); BACK and TUTORIAL are wide enough for the widest
   font */
.message-slot .message { height: 18px; min-height: 0; line-height: 18px; white-space: nowrap; font-size: 18px; }
#vs-setup-note { overflow: hidden; font-size: 14.5px; } /* (as tall as the longest game mode's: script.js's fitVsSetup) */
#pause-note { height: 17px; line-height: 17px; overflow: hidden; white-space: nowrap; font-size: 14.5px; }
/* (BACK everywhere, the main menu's and the cards': as wide as its words, 26px tall) */
.card-back, :is(.records, .settings) .card-back { width: auto; height: 26px; padding: 0 10px; align-items: center; justify-content: center; }
#tutorial-btn { width: 100px; text-align: center; }
.panel-store .store-rule + .store-sub { margin-top: 6px; } /* (each STORE section under its ===== line, as RECORDS' sections) */
/* The DAILY DROP's LOGIN STREAK: days in a row, a pip for each day of this run of 7 */
.store-streak { margin-top: 6px !important; font-size: 13px !important; letter-spacing: 1px; color: var(--fg-dim); }
.store-streak b { color: var(--accent); }
.streak-pips { display: inline-flex; gap: 2px; vertical-align: -1px; margin: 0 4px; }
.streak-pips i { width: 7px; height: 9px; border: 1px solid rgba(var(--accent-rgb), 0.6); border-radius: 1px; }
.streak-pips i.on { background: var(--accent); box-shadow: 0 0 4px rgba(var(--accent-rgb), 0.7); }
/* PAUSE: its buttons one size, two to a row as the main menu's (one alone sits centered), QUIT
   as bright as the rest */
.vs-pause .pause-row { gap: 8px; flex-wrap: nowrap; }
.vs-pause .pause-row button, .vs-pause .pause-menu {
  width: 136px; min-width: 0; height: 32px; padding: 0 22px; display: flex; align-items: center; justify-content: center;
  white-space: nowrap; overflow: hidden; font-size: 11px; letter-spacing: 1px; flex: none;
}
.vs-pause .pause-menu { border-color: var(--fg); color: var(--fg); }
/* (the STORE's card lets its sign hang off the corner, as the BLACK MARKET's window does; its
   .store-scroll does the scrolling) */
.records .menu-pane > .panel.panel-store { overflow: visible; }
.vs-pause .pause-row button, .vs-pause .pause-menu { width: 140px; padding: 0 6px; }
/* (the STORE's sign hangs over the card's sticky BACK bar, painted above it so the bar can't clip
   it or its glow, and sits in from the card's right edge; the STORE card itself doesn't scroll, its
   .store-scroll does, so the sign never rides up over BACK) */
.store-sign { right: 1px; z-index: 6; } /* (its tilted corner 8px clear of the screen's edge, like everything) */
/* ONE GAP: the space between the main menu's RULES & RECORDS and SETTINGS, between every set of
   buttons and every set of cards across the game (the main menu, PAUSE, the STORE's and EXPLOITS'
   cards, SETTINGS' buttons) */
:root { --gap: 8px; }
.home { gap: var(--gap); }
.home .modes, .home-row { gap: var(--gap); }
.vs-setup.vs-pause, .vs-pause .pause-row { gap: var(--gap); }
.booster-shop { gap: var(--gap); }
.booster-shop > .store-item { margin-top: 0; }
.store-item { margin-top: var(--gap); }
.hack-item { margin-top: var(--gap); }
.theme-list, .settings-row { gap: var(--gap); }
.settings-panel > .toggle-btn + .toggle-btn { margin-top: var(--gap); }
/* (the STORE's card starts where EXPLOITS' does, right under the card's top bar) */
.records .menu-pane[data-pane="store"]:not([hidden]) { padding-top: 0; }
.settings-row { margin-bottom: var(--gap); }
/* (the ===== lines: the one gap above and below them, too, and the one gap from a section's note to its cards) */
.store-rule, .rec-sep { margin: var(--gap) 0; }
.panel-store .store-rule + .store-sub, .rec-sep + .rec-group { margin-top: 0; }
.store-top::after { margin-top: var(--gap); }
.store-scroll > .store-item:first-child { margin-top: var(--gap); }
.panel-store .store-sub { margin-bottom: 4px; }
.panel-store .store-sub-note { margin-bottom: var(--gap); }
body.cards-in-settings .settings footer::before { margin-bottom: var(--gap); }
/* THE MAIN MENU's panel: the mode's description only as tall as its words (shrunk to fit when the
   panel is short), its options right under it; the room left over goes above PLAY, which stays put */
.home .mode-info { flex: 0 1 auto; }
.home .home-panel { max-height: 292px; } /* (what the tallest mode, DAILY, needs) */
/* THE MAIN MENU, at the game's one text size: the title one small line at the top, 8px under the
   card's border, the level and resources right under it; the mode's panel takes the room left (to a
   cap), what the mode puts in it scrolling inside it on a short screen, PLAY always under that */
.home { padding-top: 8px; }
.home-head { display: flex; align-items: baseline; justify-content: center; gap: 10px; white-space: nowrap; }
.home-head h1 { font-size: 20px; letter-spacing: 3px; margin: 0; }
.home .home-panel { max-height: 420px; }
.home-panel-body { flex: 1 1 auto; min-height: 0; width: 100%; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; align-items: center; gap: var(--gap); }
.home-panel-body > * { flex-shrink: 0; }
.home .mode-info { flex: none; overflow: visible; max-width: none; }
.home .daily-cards button { height: auto; min-height: 64px; }
.home .home-best { height: auto; overflow: visible; }
.home-panel .home-play { margin-top: 0; }
/* (the title line in em, so the whole line shrinks together to fit the card's width) */
.home-head { width: 100%; overflow: hidden; font-size: 12px; gap: 0.8em; }
.home-head h1 { font-size: 1.6em; letter-spacing: 0.15em; }
.home .home-panel { max-height: 360px; }
/* (more below: the panel's body fades out at its foot until scrolled to the end) */
.home-panel-body.more { -webkit-mask-image: linear-gradient(#000 calc(100% - 22px), transparent); mask-image: linear-gradient(#000 calc(100% - 22px), transparent); }
.home .home-panel { max-height: none; } /* (all the room there is: the more a mode shows before scrolling, the better) */
/* (the menu's level bar and resources big enough to read) */
.home .level-bar { font-size: 12px; height: 14px; }
/* (KEYS and the resources on the one line, 8px under the level's: each line as tall as its words) */
.home .wallet { font-size: 12px; height: 14px; flex-wrap: nowrap; white-space: nowrap; margin: 0; }
/* (the STORE's resources, box tiers and sign at the game's text size; the BLACK MARKET window's
   costs and note, and the main menu's, as they were) */
.panel-store .wallet { font-size: 15.5px; }
.panel-store .box-tier { font-size: 11.5px; }
.panel-store .shop-sign { font-size: 23.5px; }
#market-shop .shop-cost { font-size: 13px; }
#market-shop .shop-note { font-size: 10.5px; }
/* (set boxes a little taller for their words) */
.message-slot .message { height: 22px; line-height: 22px; }
#pause-note { height: 20px; line-height: 20px; }
.home-best { height: 18px; line-height: 18px; }
.home-head { height: 26px; align-items: center; } /* (one height in every font) */
/* THE MAIN MENU's ← BACK in its top left corner, back to the title screen: the cards' own BACK button
   (one BACK everywhere); the title line keeps clear of it */
.home .home-back { position: absolute; top: 8px; left: 8px; z-index: 2; zoom: calc(1 / var(--home-zoom, 1)); } /* (not scaled with the menu on a big screen: the same BACK as everywhere, in the same corner) */
@media (hover: hover) { .home .home-back:hover { background: rgba(var(--fg-rgb), 0.12); } }
.home-head { padding: 0 80px; } /* (BACK's width and a gap, both sides: the title stays centered) */
.home-head h1 { letter-spacing: 0.1em; } /* (the title alone: its // DECRYPTION TERMINAL is the title card's) */
/* (the mode's card only as tall as what it holds: PLAY the one 8px gap under its last piece, the
   card's foot right under PLAY and the rows under the card right after; a mode with more than the
   screen has room for scrolls inside it) */
.home .home-panel { flex: 0 1 auto; }
.home { padding-bottom: 37px; } /* (room under the menu for the walking bots: just their height, so DAILY fits the S23 Ultra) */
/* THE WANDERERS' LANE: one fixed height, the same on the main menu and in every game, nothing else
   on the card changing it */
.game-walkers { height: 192px !important; }
/* The defrag backgrounds (the grid's card, the main menu's mode card, VS's setup) a little see-through,
   so the trees in the lane show faintly behind them */
.board-frame, .home-panel, .vs-setup:not(.vs-pause) { background: color-mix(in srgb, var(--board-bg) 92%, transparent) !important; }
/* The HAUNTED FOREST's big trees in front: their own layer over the lane (visitors.js's foreLayer),
   open below so their trunks run past the card's edge */
.lane-fore { position: absolute; z-index: 0; pointer-events: none; clip-path: inset(-400px 0 -400px 0); }
.lane-fore .visitor { position: absolute; left: 0; bottom: 0; }
.lane-fore .visitor.fog-tree { pointer-events: none; transition: opacity 3s ease-in; will-change: transform; }
/* The zombies' THRILLER (visitors.js): claws up to one side (z-c), then the other (z-d), on the beat */
.visitor.z-c :is(.f-a, .f-b, .f-d), .visitor.z-d :is(.f-a, .f-b, .f-c) { display: none; }
.visitor.z-c .f-c, .visitor.z-d .f-d { display: inline; }

/* SEASONAL (script.js's seasonTheme): the theme for the time of year */
[data-theme="season-halloween"] {
  --bg: #0a0610;
  --bg-solid: #050308;
  --bg-center: #1a0f22;
  --panel: #120a18;
  --panel-text: #f3d9b8;
  --popup-bg: #100818;
  --overlay-bg: #0c0612;
  --grid-line: #3a2346;
  --board-bg: #0e0714;
  --cell-bg: #160b1e;
  --fg: #ff8c1a;
  --fg-rgb: 255, 140, 26;
  --fg-dim: #8c4f1a;
  --accent: #b36bff;
  --accent-rgb: 179, 107, 255;
  --danger: #ff3b5c;
  --danger-rgb: 255, 59, 92;
  --layer-a: #2a1838;
  --layer-b: #1a0f24;
  --layer-border: #7d5a96;
  --layer-text: #a88cbf;
  --layer-rgb: 168, 140, 191;
  --exploit-bg: #1c0f26;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 255, 140, 26;
  --burst-hot-rgb: 255, 140, 26;
  --heat-text: #ffb36b;
  --heat-bg: #2e1405;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #5a2a08;
}
[data-theme="season-harvest"] {
  --bg: #0d0804;
  --bg-solid: #060402;
  --bg-center: #20140a;
  --panel: #160d06;
  --panel-text: #f1dcbc;
  --popup-bg: #140c05;
  --overlay-bg: #0e0905;
  --grid-line: #3c2814;
  --board-bg: #120b04;
  --cell-bg: #1a1007;
  --fg: #e8a33d;
  --fg-rgb: 232, 163, 61;
  --fg-dim: #8a5f22;
  --accent: #d0603a;
  --accent-rgb: 208, 96, 58;
  --danger: #ff3b5c;
  --danger-rgb: 255, 59, 92;
  --layer-a: #2b2016;
  --layer-b: #1c140c;
  --layer-border: #86684a;
  --layer-text: #a88a6a;
  --layer-rgb: 168, 138, 106;
  --exploit-bg: #22140b;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 232, 163, 61;
  --burst-hot-rgb: 232, 163, 61;
  --heat-text: #f0c070;
  --heat-bg: #2e1d08;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #5a3a0c;
}
[data-theme="season-winter"] {
  --bg: #050a12;
  --bg-solid: #03060b;
  --bg-center: #0f1a2a;
  --panel: #0a121e;
  --panel-text: #e6eef8;
  --popup-bg: #08101c;
  --overlay-bg: #060c16;
  --grid-line: #1f3046;
  --board-bg: #08101a;
  --cell-bg: #0c1624;
  --fg: #4fd66f;
  --fg-rgb: 79, 214, 111;
  --fg-dim: #2f7a45;
  --accent: #ff5a5a;
  --accent-rgb: 255, 90, 90;
  --danger: #ff3b5c;
  --danger-rgb: 255, 59, 92;
  --layer-a: #1e2a3a;
  --layer-b: #141e2b;
  --layer-border: #7a8ca3;
  --layer-text: #9fb0c6;
  --layer-rgb: 159, 176, 198;
  --exploit-bg: #0f1d16;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 79, 214, 111;
  --burst-hot-rgb: 79, 214, 111;
  --heat-text: #9be8ae;
  --heat-bg: #0f2a18;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #1c4a2a;
}
[data-theme="season-frost"] {
  --bg: #050a14;
  --bg-solid: #02050b;
  --bg-center: #10203a;
  --panel: #08111f;
  --panel-text: #e6f4ff;
  --popup-bg: #07101d;
  --overlay-bg: #050c18;
  --grid-line: #1e3352;
  --board-bg: #07101c;
  --cell-bg: #0b1828;
  --fg: #7fd4ff;
  --fg-rgb: 127, 212, 255;
  --fg-dim: #3a7aa8;
  --accent: #e8f6ff;
  --accent-rgb: 232, 246, 255;
  --danger: #ff5a7a;
  --danger-rgb: 255, 90, 122;
  --layer-a: #1c2a40;
  --layer-b: #131e30;
  --layer-border: #8aa4c4;
  --layer-text: #a8c0dc;
  --layer-rgb: 168, 192, 220;
  --exploit-bg: #0c1a28;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 127, 212, 255;
  --burst-hot-rgb: 127, 212, 255;
  --heat-text: #bfe8ff;
  --heat-bg: #0e2236;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #1c3e5e;
}
[data-theme="season-valentine"] {
  --bg: #12050c;
  --bg-solid: #0a0207;
  --bg-center: #2a0c1c;
  --panel: #17060f;
  --panel-text: #ffe6f0;
  --popup-bg: #14050d;
  --overlay-bg: #10040a;
  --grid-line: #4a1a30;
  --board-bg: #14060e;
  --cell-bg: #1c0914;
  --fg: #ff8ac0;
  --fg-rgb: 255, 138, 192;
  --fg-dim: #a84a78;
  --accent: #ff4f6d;
  --accent-rgb: 255, 79, 109;
  --danger: #ff2b2b;
  --danger-rgb: 255, 43, 43;
  --layer-a: #2e1220;
  --layer-b: #220c18;
  --layer-border: #c48aa4;
  --layer-text: #e0aac0;
  --layer-rgb: 224, 170, 192;
  --exploit-bg: #1e0a14;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 255, 138, 192;
  --burst-hot-rgb: 255, 138, 192;
  --heat-text: #ffc2dc;
  --heat-bg: #3a1024;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #5e1a3a;
}
[data-theme="season-spring"] {
  --bg: #06100a;
  --bg-solid: #030905;
  --bg-center: #122a18;
  --panel: #0a170e;
  --panel-text: #eefae8;
  --popup-bg: #08140c;
  --overlay-bg: #07120a;
  --grid-line: #1f3a26;
  --board-bg: #08140c;
  --cell-bg: #0d1e12;
  --fg: #8fe07a;
  --fg-rgb: 143, 224, 122;
  --fg-dim: #4a8a3e;
  --accent: #ffb3d1;
  --accent-rgb: 255, 179, 209;
  --danger: #ff4f6d;
  --danger-rgb: 255, 79, 109;
  --layer-a: #1c2e20;
  --layer-b: #142318;
  --layer-border: #8aa88e;
  --layer-text: #a8c8ac;
  --layer-rgb: 168, 200, 172;
  --exploit-bg: #0e1e12;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 143, 224, 122;
  --burst-hot-rgb: 143, 224, 122;
  --heat-text: #c6f0b8;
  --heat-bg: #14301a;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #24522c;
}
[data-theme="season-summer"] {
  --bg: #04101a;
  --bg-solid: #020a12;
  --bg-center: #0c2a40;
  --panel: #061624;
  --panel-text: #e8fbff;
  --popup-bg: #05131f;
  --overlay-bg: #04101b;
  --grid-line: #164058;
  --board-bg: #05141f;
  --cell-bg: #08202e;
  --fg: #4fe0d0;
  --fg-rgb: 79, 224, 208;
  --fg-dim: #2a8a82;
  --accent: #ffc23d;
  --accent-rgb: 255, 194, 61;
  --danger: #ff5a5a;
  --danger-rgb: 255, 90, 90;
  --layer-a: #163040;
  --layer-b: #0f2432;
  --layer-border: #7aa8b8;
  --layer-text: #9cc8d4;
  --layer-rgb: 156, 200, 212;
  --exploit-bg: #08202a;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 79, 224, 208;
  --burst-hot-rgb: 79, 224, 208;
  --heat-text: #a8f2ea;
  --heat-bg: #0c3036;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #16504e;
}
[data-theme="season-autumn"] {
  --bg: #0b0d10;
  --bg-solid: #060709;
  --bg-center: #1c2228;
  --panel: #101317;
  --panel-text: #f4f1e6;
  --popup-bg: #0e1114;
  --overlay-bg: #0b0e11;
  --grid-line: #2a3138;
  --board-bg: #0e1115;
  --cell-bg: #141a20;
  --fg: #f2c94c;
  --fg-rgb: 242, 201, 76;
  --fg-dim: #9a7f2c;
  --accent: #e8573a;
  --accent-rgb: 232, 87, 58;
  --danger: #ff3b3b;
  --danger-rgb: 255, 59, 59;
  --layer-a: #262c33;
  --layer-b: #1b2026;
  --layer-border: #9aa3ad;
  --layer-text: #b8c0c8;
  --layer-rgb: 184, 192, 200;
  --exploit-bg: #141a20;
  --alarm-text: #ffffff;
  --byte-text: #fff3e0;
  --hot-rgb: 242, 201, 76;
  --burst-hot-rgb: 242, 201, 76;
  --heat-text: #f8e2a0;
  --heat-bg: #2e2810;
  --heat-peak-border: #fff3e0;
  --heat-peak-text: #fffaf2;
  --heat-peak-bg: #54461a;
}
/* THE SEASON'S LIGHTS (the SEASONAL theme in December, October and Valentine's): strings of old filament
   bulbs in fine pixel art down the screen's left and right sides, top to bottom, a bulb at either end,
   the wire in the screen's 8px margin and every bulb turned in toward the middle, so none is cut off by
   the screen's edge; over everything, but they never take a tap (no pointer events: what's under them
   works as ever); the glows twinkling in turn (the strings themselves: lights.js); off with EFFECTS:
   REDUCED. December's are C9s of every color, October's orange, purple and green with jack o' lanterns
   and candy corn, Valentine's pinks, red and white with hearts */
.card-lights { display: none; }
:is([data-theme="season-winter"], [data-theme="season-halloween"], [data-theme="season-valentine"], [data-theme="season-frost"]) .card-lights { display: block; position: absolute; inset: 0; pointer-events: none; z-index: 300; overflow: clip; } /* (the glows clipped at the screen's edges: past its foot they made the page scroll) */
:root.low-fx .card-lights { display: none !important; }
/* (the glows reach a little past the screen's sides: the page is clipped there, so it never scrolls or zooms out for them) */
html, body { overflow-x: clip; }
.card-lights i { position: absolute; top: 0; bottom: 0; width: 40px; }
.card-lights i svg { position: absolute; left: 0; top: 0; display: block; }
.card-lights i.l { left: 0; }
.card-lights i.r { right: 0; transform: scaleX(-1); }
.card-lights i::before, .card-lights i::after { content: ""; position: absolute; top: -14px; bottom: -14px; left: -14px; right: -14px; background-repeat: no-repeat; mix-blend-mode: screen; } /* (bigger than the string: the glows fade out round) */
.card-lights i::before { background-image: var(--glow-a, none); animation: card-twinkle 2.6s ease-in-out infinite; }
.card-lights i::after { background-image: var(--glow-b, none); animation: card-twinkle 2.6s ease-in-out -1.3s infinite; }
/* (FROST's ice glints: slower, as light catching it) */
[data-theme="season-frost"] .card-lights i::before { animation-duration: 4.2s; }
[data-theme="season-frost"] .card-lights i::after { animation-duration: 4.2s; animation-delay: -2.1s; }
@keyframes card-twinkle { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .card-lights i::before, .card-lights i::after { animation: none; } }
[data-theme="season-winter"] .chain-meter i:nth-child(5n+1)::after { background: #ffd696; box-shadow: 0 0 6px #ffd696; }
[data-theme="season-winter"] .chain-meter i:nth-child(5n+2)::after { background: #ffaa46; box-shadow: 0 0 6px #ffaa46; }
[data-theme="season-winter"] .chain-meter i:nth-child(5n+3)::after { background: #ff6048; box-shadow: 0 0 6px #ff6048; }
[data-theme="season-winter"] .chain-meter i:nth-child(5n+4)::after { background: #6ee082; box-shadow: 0 0 6px #6ee082; }
[data-theme="season-winter"] .chain-meter i:nth-child(5n+5)::after { background: #80b2ff; box-shadow: 0 0 6px #80b2ff; }
[data-theme="season-halloween"] .chain-meter i:nth-child(5n+1)::after { background: #ff8a1f; box-shadow: 0 0 6px #ff8a1f; }
[data-theme="season-halloween"] .chain-meter i:nth-child(5n+2)::after { background: #b36bff; box-shadow: 0 0 6px #b36bff; }
[data-theme="season-halloween"] .chain-meter i:nth-child(5n+3)::after { background: #ff8a1f; box-shadow: 0 0 6px #ff8a1f; }
[data-theme="season-halloween"] .chain-meter i:nth-child(5n+4)::after { background: #7dff5a; box-shadow: 0 0 6px #7dff5a; }
[data-theme="season-halloween"] .chain-meter i:nth-child(5n+5)::after { background: #ffbe3c; box-shadow: 0 0 6px #ffbe3c; }
[data-theme="season-valentine"] .chain-meter i:nth-child(5n+1)::after { background: #ff8ac0; box-shadow: 0 0 6px #ff8ac0; }
[data-theme="season-valentine"] .chain-meter i:nth-child(5n+2)::after { background: #ff3b5c; box-shadow: 0 0 6px #ff3b5c; }
[data-theme="season-valentine"] .chain-meter i:nth-child(5n+3)::after { background: #ffe6f0; box-shadow: 0 0 6px #ffe6f0; }
[data-theme="season-valentine"] .chain-meter i:nth-child(5n+4)::after { background: #ff8ac0; box-shadow: 0 0 6px #ff8ac0; }
[data-theme="season-valentine"] .chain-meter i:nth-child(5n+5)::after { background: #ff3b5c; box-shadow: 0 0 6px #ff3b5c; }
/* (December's board in their warm light: a glow off the sides, the empty cells catching it) */
[data-theme="season-winter"]:not(.low-fx) .board { box-shadow: inset 14px 0 22px -12px rgba(255, 176, 90, 0.28), inset -14px 0 22px -12px rgba(255, 176, 90, 0.28), inset 0 0 30px rgba(255, 190, 120, 0.06); }
[data-theme="season-winter"]:not(.low-fx) .board .cell:empty:not(.overflow) { box-shadow: inset 0 0 5px rgba(255, 190, 110, 0.14); border-color: rgba(255, 196, 130, 0.16); }
/* OCTOBER's spooky touch: the title flickering now and then */
[data-theme="season-halloween"] :is(header h1, .home-head h1, .card-brand) { animation: spooky-flicker 9s steps(1) infinite; }
@keyframes spooky-flicker { 0%, 90% { opacity: 1; } 91% { opacity: 0.35; } 92% { opacity: 1; } 95% { opacity: 0.6; } 96%, 100% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { [data-theme="season-halloween"] :is(header h1, .home-head h1, .card-brand) { animation: none; } }
/* SEASONAL's button: the full width, under the two columns of themes */
.theme-list .theme-seasonal { grid-column: 1 / -1; }
/* THE OVERCAST (visitors.js): three cloud layers over the game card's lane, the sky dimmed under
   them; the flyers at their depths among them (v-alt-0 behind the middle layer, 1 between, 2 in
   front); lightning lighting the cloud from within (OCTOBER) */
.game-walkers .cloud-layer { position: absolute; left: 0; right: 0; top: 0; width: 100%; height: 64%; image-rendering: pixelated; pointer-events: none; transition: filter 0.06s linear; }
.game-walkers .cloud-0 { z-index: -1; }
.game-walkers .cloud-1 { z-index: 1; }
.game-walkers .cloud-2 { z-index: 3; }
.game-walkers .cloud-dark { position: absolute; left: 0; right: 0; top: 0; height: 75%; z-index: -4; pointer-events: none; opacity: 0;
  background: linear-gradient(to bottom, rgba(4, 2, 8, 0.7), rgba(4, 2, 8, 0.35) 55%, transparent); }
.game-walkers .cloud-flash { position: absolute; top: 0; width: 45%; height: 60%; z-index: -1; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse at center, rgba(225, 205, 255, 0.85), rgba(170, 130, 255, 0.25) 45%, transparent 70%); }
.game-walkers.lightning .cloud-flash { opacity: 1; }
.game-walkers.lightning .cloud-layer { filter: brightness(1.9) saturate(0.8); }
:is(.start-walkers, .game-walkers) .visitor.v-alt-0 { z-index: 0; }
:is(.start-walkers, .game-walkers) .visitor.v-alt-1 { z-index: 2; }
:is(.start-walkers, .game-walkers) .visitor.v-alt-2 { z-index: 4; }
[data-theme="paper"] .game-walkers :is(.cloud-layer, .cloud-dark, .cloud-flash) { display: none; } /* (the light theme keeps its card) */
@media (prefers-reduced-motion: reduce) { .game-walkers.lightning .cloud-layer { filter: none; } .game-walkers.lightning .cloud-flash { opacity: 0.3; } }
/* (the big trees stay inside the card: it frames the scene; cut off at its inside edges and rounded
   foot, the lane's 6px over the card's padding below it included) */
.lane-fore { clip-path: inset(-400px 0 -6px 0 round 0 0 8px 8px); }
/* The game card's sky FEATHERED into the UI above: the clouds, the overcast's and the fog's dark,
   the night and the moon's sky reach on past the lane's top edge (which stays where it is) and fade
   out there, so the scene melts into the card instead of stopping at a line */
.game-walkers { --feather: 56px; }
.game-walkers :is(.cloud-layer, .cloud-dark, .fog-dark, .night-dark, .moon-sky, .fog-layer) {
  top: calc(-1 * var(--feather));
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 var(--feather));
  mask-image: linear-gradient(to bottom, transparent, #000 var(--feather));
}
.game-walkers .cloud-layer { height: calc(64% + var(--feather)); }
.game-walkers .cloud-dark { height: calc(75% + var(--feather)); }
.game-walkers .fog-layer { height: calc(100% + 6px + var(--feather)); }
.game-walkers .moon-sky { clip-path: none; }
/* The HAUNTED FOREST's floor (visitors.js's drawGround): along the lane's foot, in front of the bots'
   feet, down to the card's edge (the big trees' layer clips it to the card) */
.lane-fore .forest-ground { position: absolute; left: 0; width: 100%; image-rendering: pixelated; pointer-events: none; opacity: 0; transition: opacity 3s ease-in; }
.lane-fore { overflow: clip; overflow-clip-margin: 6px; } /* (nothing sunk below the card counts toward the page: no scrolling) */
.lane-fore { clip-path: inset(-400px 0 calc(-1 * var(--below, 6px)) 0 round 0 0 8px 8px); overflow-clip-margin: var(--below, 6px); } /* (down to the card's inside edge, wherever the lane stops) */

/* WEATHER (weather.js): the rain, snow, hail, leaves and the rest on two canvases (behind the bots,
   in front of them), the sun's warmth, the night sky, a blizzard's whiteout and the lightning's flash */
:is(.start-walkers, .game-walkers) .wx-layer { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; image-rendering: pixelated; }
:is(.start-walkers, .game-walkers) .wx-back { z-index: 0; }
:is(.start-walkers, .game-walkers) .wx-front { z-index: 5; }
:is(.start-walkers, .game-walkers) :is(.wx-glow, .wx-night, .wx-white, .wx-flash) { position: absolute; left: 0; right: 0; top: 0; bottom: 0; pointer-events: none; opacity: 0; transition: opacity 0.8s linear; }
:is(.start-walkers, .game-walkers) .wx-glow { z-index: -3; background: radial-gradient(circle at var(--sx, 80%) 18%, rgba(255, 210, 90, 0.28), rgba(255, 170, 60, 0.08) 45%, transparent 75%); }
:is(.start-walkers, .game-walkers) .wx-night { z-index: -4; background: linear-gradient(to bottom, rgba(4, 6, 20, 0.85), rgba(4, 6, 20, 0.35) 70%, transparent); }
:is(.start-walkers, .game-walkers) .wx-white { z-index: 4; background: linear-gradient(to bottom, rgba(225, 232, 242, 0.7), rgba(225, 232, 242, 0.35)); }
:is(.start-walkers, .game-walkers) .wx-flash { z-index: 6; background: rgba(235, 240, 255, 0.35); transition: none; }
:is(.start-walkers, .game-walkers) .wx-flash.on { opacity: 1; }
.game-walkers :is(.wx-layer, .wx-glow, .wx-night, .wx-white, .wx-flash) {
  top: calc(-1 * var(--feather)); height: calc(100% + var(--feather)); bottom: auto;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 var(--feather));
  mask-image: linear-gradient(to bottom, transparent, #000 var(--feather));
}
.game-walkers .wx-flash { clip-path: inset(0 round 0 0 8px 8px); }
:is([data-theme="paper"], [data-theme="daylight"]) :is(.wx-night, .wx-glow) { display: none; }
@media (prefers-reduced-motion: reduce) { :is(.start-walkers, .game-walkers) .wx-flash { display: none; } }

/* SCENES (scenes.js): a place for a while, at three depths: the far layer behind everything, the
   ground behind the bots' feet, a few near details in front of them */
:is(.start-walkers, .game-walkers) .scene-layer { position: absolute; left: 0; bottom: 0; width: 100%; pointer-events: none; image-rendering: pixelated; opacity: 0; transition: opacity 4s ease; }
:is(.start-walkers, .game-walkers) .scene-far { z-index: -2; }
:is(.start-walkers, .game-walkers) .scene-ground { z-index: -1; } /* (behind the visitors, the leaves and the settled snow; first in the lane, so under the pushed scenery too) */
:is(.start-walkers, .game-walkers) .scene-near { z-index: 5; }
/* (the floor reaches down to the card's edge, under the lane's foot, and the card's corners clip it) */
.game-walkers { --floor-under: 6px; }
.game-walkers :is(.scene-ground, .scene-near) { clip-path: inset(0 round 0 0 8px 8px); }

/* GONE FISHING (scenes.js): the line, the bobber (tap it: the fish is gone), a splash, the catch;
   out on the water, so behind the bots (z-index 1) that walk past on the shore */
:is(.start-walkers, .game-walkers) .fish-line { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 0; }
:is(.start-walkers, .game-walkers) button.fish-bobber { all: unset; position: absolute; z-index: 0; width: 24px; height: 24px; margin: 0 0 -12px -12px; pointer-events: auto; cursor: pointer; -webkit-tap-highlight-color: transparent; }
:is(.start-walkers, .game-walkers) button.fish-bobber:focus-visible { outline: 1px dashed rgba(255, 255, 255, 0.6); }
.fish-bobber span { position: absolute; left: 50%; top: 50%; width: calc(34px / 16 * 2); height: calc(34px / 16 * 2); transform: translate(-50%, -50%); background: linear-gradient(#e0455f 50%, #f7f2e8 50%); }
.fish-bobber.under span { height: calc(34px / 16); background: #e0455f; opacity: 0.7; }
:is(.start-walkers, .game-walkers) .fish-splash { position: absolute; z-index: 0; width: 4px; height: 2px; margin-left: -2px; border: 1px solid rgba(200, 225, 240, 0.8); border-radius: 50%; pointer-events: none; animation: fish-splash 0.6s ease-out forwards; }
@keyframes fish-splash { to { width: 26px; height: 6px; margin-left: -13px; opacity: 0; } }
:is(.start-walkers, .game-walkers) .fish-catch { position: absolute; z-index: 0; pointer-events: none; }
.fish-catch svg { display: block; }
.fish-catch.wiggle svg { animation: fish-wiggle 0.25s steps(2) infinite; transform-origin: 50% 0; }
@keyframes fish-wiggle { 50% { transform: rotate(14deg); } }
.walker { transition: translate 0.35s ease-out; }
.fish-catch.fish-res { width: calc(34px / 16 * 6); height: calc(34px / 16 * 6); }
.fish-catch.fish-res svg { width: 100%; height: 100%; filter: drop-shadow(0 0 3px currentColor); animation: fish-res-glint 0.8s ease-in-out infinite alternate; }
.fish-res.res-bugs { color: var(--res-bugs); } .fish-res.res-cache { color: var(--res-cache); } .fish-res.res-crypto { color: var(--res-crypto); } .fish-res.res-rootkits { color: var(--res-rootkits); } .fish-res.res-master { color: var(--res-master); }
@keyframes fish-res-glint { to { transform: translateY(-2px); filter: drop-shadow(0 0 6px currentColor); } }
/* (the bits of life, scenes.js: behind the bots, over the scene's far layer and ground) */
:is(.start-walkers, .game-walkers) .scene-life { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; image-rendering: pixelated; }
:is(.start-walkers, .game-walkers) .scene-near-life { z-index: 4; } /* (the near critters: in front of the bots, nearer the camera) */
/* (the scene's sky, scenes.js: the time of day's, the weather's; fading up into the card) */
:is(.start-walkers, .game-walkers) .scene-sky { position: absolute; left: 0; right: 0; bottom: 0; height: 55%; z-index: -6; pointer-events: none; opacity: 0; transition: opacity 5s ease;
  -webkit-mask-image: linear-gradient(to top, #000 45%, transparent); mask-image: linear-gradient(to top, #000 45%, transparent); }
.game-walkers .scene-sky { top: calc(-1 * var(--feather)); height: auto; }

/* INFECTIONS (infections.js): each in its own little display, LED or ASCII, within the bits it takes up */
.board-wrap { position: relative; }
.inf { position: absolute; pointer-events: none; z-index: 6; }
.inf[hidden] { display: none; }
.inf canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* ADWARE: its own frame over the column, below the overflow line */
.inf-ad { border: 2px solid var(--accent); border-radius: 6px; background: #040406; box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.45), inset 0 0 8px rgba(0, 0, 0, 0.8); overflow: hidden; }
.inf-ad-tag { position: absolute; right: 3px; bottom: 3px; padding: 0 3px; font-size: 8px; line-height: 11px; letter-spacing: 0; color: #111; background: var(--accent); border-radius: 2px; font-weight: bold; }
.inf-ad-tag:has(.px-tag) { padding: 0; background: none; border-radius: 0; line-height: 0; filter: drop-shadow(0 0 3px rgba(var(--accent-rgb), 0.5)); } /* (in pixels: led-banner.js draws it) */
.column-buttons button .px-icon { width: 18px; height: 14px; fill: currentColor; display: block; margin: auto; } /* (ADWARE's megaphone on the blocked column's button) */
.inf-ad-tag .px-tag { position: static; display: block; image-rendering: pixelated; }
/* CRYPTOJACKER: its sign seen through the overflow row's own cells */
.inf-jack { z-index: 5; }
/* (the ad and the sign take taps: each tap, KEYS toward their demand) */
.inf-ad, .inf-jack { pointer-events: auto; cursor: pointer; }
.inf-due { position: absolute; z-index: 2; padding: 0 3px; font-size: 7.5px; line-height: 11px; letter-spacing: 0; white-space: nowrap; color: #fff; background: rgba(var(--danger-rgb), 0.85); border-radius: 2px; pointer-events: none; }
.inf-due[hidden], .inf-due:empty { display: none; }
.inf-ad .inf-due { top: 3px; left: 3px; right: 3px; white-space: normal; text-align: center; font-size: 7px; line-height: 9px; padding: 1px 2px; } /* (the column's narrow: PAY over the amount) */
.inf-jack .inf-due { right: 3px; top: 50%; translate: 0 -50%; }
.inf-win .inf-due { position: static; display: block; width: max-content; margin: -4px auto 8px; font-size: 9px; line-height: 13px; } /* (its sign solid in each cell: nothing under it shows through) */
/* RANSOMWARE: a locked bit's little screen, its padlock, its value and the drops left */
.cell.ransom { position: relative; overflow: hidden; color: var(--danger); border-color: var(--danger); }
/* An INFECTED BIT (script.js): its number as ever, a red frame pulsing and a virus in its corner */
.cell.infected { position: relative; border-color: var(--danger); animation: infected-pulse 0.8s ease-in-out infinite; }
.cell.infected .inf-mark { position: absolute; top: 1px; right: 1px; width: 38%; height: 38%; display: flex; color: var(--danger); filter: drop-shadow(0 0 2px var(--danger)); pointer-events: none; }
.cell.infected .inf-mark .ico { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.4; }
@keyframes infected-pulse { 0%, 100% { box-shadow: inset 0 0 0 1px var(--danger), 0 0 4px rgba(255, 59, 78, 0.4); } 50% { box-shadow: inset 0 0 0 2px var(--danger), 0 0 12px rgba(255, 59, 78, 0.8); } }
.inf-screen { position: absolute; inset: 3px; border-radius: 3px; background: #050607; overflow: hidden; box-shadow: inset 0 0 4px rgba(var(--danger-rgb), 0.5); }
.inf-face, .inf-term { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.inf-face { animation: inf-swap 3.2s ease-in-out infinite; }
.inf-term { flex-direction: column; align-items: flex-start; justify-content: center; padding: 8px 2px 7px; gap: 0; animation: inf-swap 3.2s ease-in-out -1.6s infinite; }
@keyframes inf-swap { 0%, 40% { opacity: 1; } 50%, 90% { opacity: 0; } 100% { opacity: 1; } }
.inf-led { width: 76%; height: auto; }
.inf-led .on { fill: var(--danger); filter: drop-shadow(0 0 0.4px var(--danger)); }
.inf-led .on2 { fill: var(--accent); }
.inf-led .off { fill: rgba(255, 255, 255, 0.07); }
.inf-term span { display: block; overflow: hidden; white-space: nowrap; width: 0; font-size: 6.5px; line-height: 7px; letter-spacing: 0; font-family: 'Courier New', monospace; color: #6dff9a; animation: inf-type 3.2s steps(5) infinite; }
.inf-term span:nth-child(2) { animation-delay: 0.3s; } .inf-term span:nth-child(3) { animation-delay: 0.6s; } .inf-term span:nth-child(4) { display: none; }
@keyframes inf-type { 0% { width: 0; } 40%, 100% { width: 5ch; } }
.inf-lock { position: absolute; top: 1px; right: 1px; width: 8px; height: 10px; color: var(--accent); filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.9)); z-index: 1; }
/* (the bit's value in its brackets, top left; its ransom, bottom right: the key, then the KEYS left to pay, in
   the KEYS' color. Sized by the bit itself, so a small one (a small phone, HARD's 8x8) isn't crowded) */
.cell.ransom { container-type: inline-size; }
.inf-ransom-val { position: absolute; left: 1px; top: 0; font-size: 11px; font-size: clamp(8px, 31cqw, 12px); line-height: 1.1; letter-spacing: -0.5px; color: var(--fg); text-shadow: 0 0 3px #000, 0 0 2px #000; z-index: 1; }
.inf-ransom-price { position: absolute; right: 2px; bottom: 0; display: flex; align-items: center; gap: 1px; font-size: 10.5px; font-size: clamp(7.5px, 29cqw, 11px); line-height: 1.15; color: var(--accent); text-shadow: 0 0 3px #000, 0 0 2px #000; z-index: 1; }
.inf-ransom-key { width: 0.85em; height: 0.85em; filter: drop-shadow(0 0 1.5px #000); }
/* A tap paying toward it: what it took, floating up off the bit */
.ransom-pop { position: absolute; z-index: 6; pointer-events: none; transform: translate(-50%, -50%); display: flex; align-items: center; gap: 1px; font-size: 15px; letter-spacing: 1px; color: var(--accent); text-shadow: 0 0 6px var(--bg-solid), 0 0 2px var(--bg-solid); animation: res-pop 1.6s ease-out forwards; white-space: nowrap; }
.ransom-pop .key-ico { width: 14px; height: 14px; }
/* MALWARE: the bits a jumble of flickering characters */
.cell.corrupt { color: var(--danger); border-color: rgba(var(--danger-rgb), 0.7); }
/* (MALWARE's blocks of characters, each bit a little CRT: kept inside the bit's border with a sliver of
   clearance, rounded like a screen, faint scanlines over it and its edges dimmed) */
.cell.corrupt, .cell.mosaic-empty { position: relative; overflow: hidden; }
.cell .inf-glitch:is(.mosaic, .mini) { position: absolute; inset: 2px; display: flex; align-items: center; justify-content: center; overflow: hidden; border-radius: 3px; }
.cell .inf-glitch:is(.mosaic, .mini)::after { content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.32) 0 1px, transparent 1px 3px);
  box-shadow: inset 0 0 5px 1px rgba(0, 0, 0, 0.85); }
.inf-glitch.mosaic, .inf-glitch.mini { white-space: pre; letter-spacing: 0; text-shadow: 0 0 3px rgba(var(--danger-rgb), 0.6); }
.inf-glitch.mosaic { font-size: 4.6px; line-height: 5.4px; color: #ff7080; text-shadow: 0 0 3px rgba(var(--danger-rgb), 0.9); } /* (each bit its piece of one big picture) */
.cell.mosaic-empty { display: flex; align-items: center; justify-content: center; overflow: hidden; }
.inf-glitch.mosaic.empty { color: rgba(var(--fg-rgb), 0.5); text-shadow: 0 0 3px rgba(var(--fg-rgb), 0.35); } /* (the empty spots: the grid's green, see-through, the background shows behind) */
.inf-glitch.mosaic.wall { color: #ff7080; } /* (a wall of binary in each bit) */
.inf-glitch.mosaic.rooms { color: rgba(255, 112, 128, 0.85); text-shadow: none; } /* (ROOMS: walls, doors, things lying about) */
.inf-walker { color: var(--accent); font-weight: bold; text-shadow: 0 0 3px rgba(var(--accent-rgb), 0.9); }
.inf-glitch.mini { font-size: 3.2px; line-height: 3.4px; }
.inf-mini { margin: 0; font-size: 3px; line-height: 3px; letter-spacing: 0; color: var(--danger); font-family: 'Courier New', monospace; text-shadow: 0 0 2px rgba(var(--danger-rgb), 0.7); }
.inf-glitch { font-family: 'Courier New', monospace; letter-spacing: 0; font-size: 0.8em; text-shadow: 1px 0 rgba(0, 220, 255, 0.6), -1px 0 rgba(255, 40, 80, 0.6); }
/* SPYWARE: eyes watching from the CURRENT box */
.inf-eyes { font-family: 'Courier New', monospace; font-size: 0.62em; letter-spacing: 0; color: var(--danger); white-space: nowrap; }
/* SCAREWARE: a fake system alert, over the board; its tiny X the only way out */
.inf-scare { z-index: 8; pointer-events: none; } /* (the grid's room: the pop-ups, up to 4, each somewhere in it) */
.inf-win { position: absolute; pointer-events: auto; width: 76%; max-width: 260px; background: #0b0b10; border: 2px solid var(--danger); border-radius: 4px; box-shadow: 0 0 0 1px #000, 0 6px 24px rgba(0, 0, 0, 0.8), 0 0 18px rgba(var(--danger-rgb), 0.5); font-family: 'Courier New', monospace; text-align: center; animation: inf-pop 0.18s steps(3); }
@keyframes inf-pop { from { transform: scale(0.6); opacity: 0; } }
.inf-bar { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 2px 3px 2px 6px; background: var(--danger); color: #fff; font-size: 10px; letter-spacing: 1px; text-align: left; }
.inf-x { all: unset; width: 11px; height: 11px; line-height: 10px; font-size: 10px; text-align: center; color: #fff; border: 1px solid rgba(255, 255, 255, 0.8); cursor: pointer; flex: none; }
.inf-x::before { content: ""; position: absolute; inset: -6px; } /* (a fair target, but it looks tiny) */
.inf-x { position: relative; }
.inf-skull { margin: 8px 0 2px; font-size: 9px; line-height: 10px; color: rgba(var(--danger-rgb), 0.45); }
.inf-skull.lit { color: var(--danger); text-shadow: 0 0 6px var(--danger); }
/* the binary art: shapes of flickering 0s and 1s */
.inf-bin { margin: 6px 0 0; font-size: 6px; line-height: 6px; letter-spacing: 0; color: rgba(var(--danger-rgb), 0.55); }
.inf-bin.lit { color: var(--danger); text-shadow: 0 0 4px rgba(var(--danger-rgb), 0.8); }
.inf-bin.big { font-size: 5px; line-height: 5px; } /* (the viruses: more of them) */
.inf-bin-alt { color: #ff6b7a; text-shadow: 0 0 3px rgba(var(--danger-rgb), 0.6); }
.inf-msg { margin: 4px 8px; font-size: 11px; color: #fff; letter-spacing: 1px; }
.inf-scan { margin: 2px 6px 8px; font-size: 10px; color: var(--danger); letter-spacing: 0; white-space: pre; }
.inf-ok { all: unset; display: inline-block; margin: 0 0 10px; padding: 4px 12px; font-size: 11px; letter-spacing: 1px; color: #fff; background: rgba(var(--danger-rgb), 0.3); border: 1px solid var(--danger); cursor: pointer; transition: transform 0.12s steps(2); }
@media (prefers-reduced-motion: reduce) { .inf-face, .inf-term, .inf-term span { animation: none; } .inf-term { opacity: 0; } .inf-term span { width: 5ch; } }
.inf-skull.inf-sad { font-size: 12px; line-height: 14px; color: var(--danger); text-align: center; }
.inf-skull.inf-wheel { font-size: 12px; line-height: 16px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6); }

/* INFECTION TESTER (index.html?inftest): its panel along the bottom of the screen */
.inftest { position: fixed; left: 8px; right: 8px; bottom: 8px; z-index: 400; max-width: 520px; margin: 0 auto; padding: 6px 8px 8px; background: rgba(2, 6, 4, 0.94); border: 1px solid var(--accent); border-radius: 8px; box-shadow: 0 0 14px rgba(0, 0, 0, 0.8); font-family: 'Courier New', monospace; color: var(--fg); }
.inftest-head { display: flex; align-items: center; justify-content: space-between; font-size: 10px; letter-spacing: 2px; color: var(--accent); }
.inftest-head b { font-weight: normal; }
.inftest.min .inftest-body { display: none; }
.inftest-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 6px; }
.inftest-row span { font-size: 9px; letter-spacing: 1px; color: var(--fg-dim); margin-right: 2px; }
.inftest button, .inftest a { all: unset; cursor: pointer; font-size: 9px; letter-spacing: 1px; padding: 4px 6px; border: 1px solid var(--fg-dim); border-radius: 3px; color: var(--fg); }
.inftest [data-inf] { border-color: var(--danger); color: #ff8a96; }
.inftest button.on { background: var(--fg); color: #020403; border-color: var(--fg); }
.inftest a { color: var(--fg-dim); margin-left: auto; }
.inftest-note { margin: 6px 0 0; font-size: 8.5px; line-height: 1.4; color: var(--fg-dim); }
/* SOUND TESTER (index.html?sfxtest): the same panel, the sounds named as they play: the last few,
   each sound and how often it's been heard, and a caption flashing over the top of the board */
.sfxtest-now { flex: 1; min-width: 0; margin: 0 8px; text-align: right; color: var(--fg); letter-spacing: 0.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sfxtest-log { margin-top: 6px; min-height: 52px; }
.sfxtest-log p { margin: 0; font-size: 9.5px; line-height: 13px; color: var(--fg-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sfxtest-log p:first-child { color: var(--fg); }
.sfxtest-log b { font-weight: normal; color: var(--accent); margin-right: 4px; }
.sfxtest-heard button { opacity: 0.5; }
.sfxtest-heard button.heard { opacity: 1; border-color: var(--fg); }
.sfxtest-heard i { font-style: normal; color: var(--accent); }
.sfxtest-cap { position: fixed; z-index: 401; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 5px 10px; background: rgba(2, 6, 4, 0.88); border: 1px solid var(--accent); border-radius: 6px; pointer-events: none; font-family: 'Courier New', monospace; white-space: nowrap; }
.sfxtest-cap[hidden] { display: none; }
.sfxtest-cap b { font-size: 12px; letter-spacing: 2px; color: var(--accent); text-shadow: 0 0 6px var(--accent); }
.sfxtest-cap span { font-size: 10px; color: var(--fg); }
.sfxtest-cap.on { animation: sfxtest-cap 1.1s ease-out forwards; }
@keyframes sfxtest-cap { 0% { opacity: 0; transform: translateX(-50%) scale(0.9); } 10% { opacity: 1; transform: translateX(-50%) scale(1); } 75% { opacity: 1; } 100% { opacity: 0; } }

/* CRT DISPLAY (SETTINGS): the whole screen as an old tube, laid over everything and never in the way
   of a tap. SOFT: scanlines, the glass darkening toward its rounded corners. FULL: and the phosphor's
   red / green / blue stripes, a faint flicker, a bright band rolling slowly down. */
.crt-fx { display: none; position: fixed; inset: 0; z-index: 10000; pointer-events: none; overflow: hidden; }
:root:is(.crt-soft, .crt-full) .crt-fx { display: block; }
.crt-fx::before { content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.22) 0 1px, transparent 1px 3px); }
.crt-fx::after { content: ""; position: absolute; inset: 0; border-radius: 22px / 26px;
  background: radial-gradient(ellipse 85% 80% at 50% 50%, transparent 55%, rgba(0, 0, 0, 0.42) 100%);
  box-shadow: inset 0 0 40px 8px rgba(0, 0, 0, 0.7), 0 0 0 40px #000; }
:root.crt-full .crt-fx::before {
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.3) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(to right, rgba(255, 40, 40, 0.06) 0 1px, rgba(40, 255, 80, 0.06) 1px 2px, rgba(60, 90, 255, 0.06) 2px 3px);
  animation: crt-flicker 0.12s steps(2) infinite; }
.crt-roll { display: none; position: absolute; left: 0; right: 0; height: 22%; top: -22%;
  background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0.035) 50%, transparent); }
:root.crt-full .crt-roll { display: block; animation: crt-roll 7s linear infinite; }
@keyframes crt-flicker { 50% { opacity: 0.88; } }
@keyframes crt-roll { to { transform: translateY(560%); } }
/* (a touch of glow on the tube's light) */
:root.crt-full body { text-shadow: 0 0 1px currentColor; }
:root.low-fx .crt-fx::before, :root.low-fx .crt-roll { animation: none; }
@media (prefers-reduced-motion: reduce) { .crt-fx::before, .crt-roll { animation: none !important; } }

/* EXPLOITS (RULES & RECORDS): its top (the title, the slots) stays put under a ===== line, the list
   scrolls under it, as the STORE's; the equipped ones filled in, lit against the card */
.records .menu-pane > .panel.panel-hacks { display: flex; flex-direction: column; overflow: hidden; padding-bottom: 0; }
.hacks-top { flex: none; }
.hacks-top h2 { margin-top: 0; }
.hacks-top .slot-info { margin-bottom: 0; }
/* THE LOADOUT: a box per slot in a centered row, 8px apart, each as the game's slot buttons: filled,
   lit as a ready exploit; empty, a dashed frame; not open yet, its padlock and level */
.loadout-boxes { display: flex; justify-content: center; gap: var(--gap); margin: var(--gap) 0 0; }
.loadout-boxes .loadout-box { width: 40px; height: 40px; flex: none; cursor: default; }
.loadout-boxes .loadout-box.filled { color: var(--fg); --dim: 1; border-color: var(--fg); text-shadow: 0 0 6px rgba(var(--fg-rgb), 0.6); }
.loadout-boxes .loadout-box.empty { border-style: dashed; }
.loadout-boxes.fixed .loadout-box.filled { --dim: 0.75; border-color: rgba(var(--fg-rgb), 0.6); }
.hacks-top::after { content: "================================================================================"; display: block; margin-top: 8px; overflow: hidden; white-space: nowrap; font-size: 14.5px; line-height: 15px; letter-spacing: 2px; color: var(--accent); opacity: 0.7; }
.hacks-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; padding: 10px 0 14px; }
.hacks-scroll .store-rule { margin: 12px 0 2px; }
.hack-item.equipped { background: linear-gradient(rgba(var(--fg-rgb), 0.13), rgba(var(--fg-rgb), 0.05)), var(--panel); box-shadow: inset 0 0 10px rgba(var(--fg-rgb), 0.12), 0 0 6px rgba(var(--fg-rgb), 0.25); }
.hack-item.equipped.held { box-shadow: inset 0 0 10px rgba(var(--fg-rgb), 0.12), 0 0 10px rgba(var(--accent-rgb), 0.3); }

/* EXPLOITS' tier sections: a heading and a line on what the tier's for, each under a ===== line */
.tier-head .store-rule { margin: 16px 0 4px; }
.tier-sub { margin: 4px 0 2px; font-size: 15.5px; letter-spacing: 2px; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); }
.tier-note { margin: 0 0 4px; font-size: 13px; color: var(--fg-dim); }

/* SETTINGS, as RULES & RECORDS, EXPLOITS and the STORE: the card stays put (BACK and its title), its
   options in a dashed box that scrolls inside its border */
.settings:not([hidden]) { display: flex; flex-direction: column; overflow: hidden; padding-bottom: 14px; }
.settings .card-head { flex: none; position: static; }
.settings-panel { flex: 1 1 auto; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
  font-size: inherit; line-height: inherit; color: inherit; padding: 4px 12px 14px; }

/* SETTINGS on the menus' type scale (as the STORE, EXPLOITS and RULES): section heads 15.5px, their
   sub-heads and notes 13px, buttons 12px, small tags 11.5px; and its sections parted by ===== lines,
   not dashes */
.settings .settings-title { font-size: 13px; }
.settings .settings-title.settings-section { font-size: 15.5px; }
#ad-privacy[hidden] { display: none; } /* (SETTINGS' ADS: only where the law asks for it, in the app: js/ads.js) */
#ad-test[hidden] { display: none; } /* (SETTINGS' TEST ADS: the app's test-ad builds only: js/ads.js) */
.settings .toggle-btn { font-size: 12px; }
.settings .dev-unlock-btn { font-size: 11.5px; }
.settings button .need { font-size: 10.5px; }
body.cards-in-settings .settings footer { font-size: 11.5px; }
.settings .settings-section, .settings .settings-options { border-top: 0; padding-top: 0; }
.settings .settings-section:not(.settings-first)::before, .settings .settings-options::before {
  content: "================================================================================"; display: block; margin: 4px 0 10px; overflow: hidden; white-space: nowrap;
  font-size: 14.5px; line-height: 15px; letter-spacing: 2px; color: var(--accent); opacity: 0.7; text-shadow: none; }
body.cards-in-settings .settings footer :is(p, span, a) { font-size: 11.5px; }
.settings .theme-option .lv-tag { font-size: 9px; } /* (the smallest label the game allows) */
/* PAUSE in a game: a bordered button like BACK and the rest (the bars centered in it, at full strength;
   its bigger tap area, ::before, still reaches past the border) */
/* (formatted as ← BACK: its width, height, border and lettering, the bars where BACK's arrow is) */
body.in-game.can-pause .records-btn { top: 8px; right: 8px; width: auto; height: 26px; padding: 0 10px; gap: 6px; opacity: 1; border: 1px solid var(--fg); border-radius: 4px; background: transparent; color: var(--fg); font-family: inherit; font-size: 12px; letter-spacing: 1px; }
body.in-game.can-pause .records-btn svg.rb-pause { position: static; width: 10px; height: 10px; flex: none; } /* (never squeezed: the words shrink instead) */
.records-btn .rb-pause-word { display: none; }
body.in-game.can-pause .records-btn .rb-pause-word { display: inline; }
@media (hover: hover) { body.in-game.can-pause .records-btn:hover { background: rgba(var(--fg-rgb), 0.12); filter: none; } }
body.in-game.can-pause .records-btn.pause-queued { background: rgba(var(--fg-rgb), 0.16); }
/* The BLACK MARKET's $: lit and glowing while what's in the slot is for sale (the market open), a slow
   pulse to draw the eye; dark while the market's still shut */
.exploit-icon.side-slot.market:not(.locked) > .slot-sale { filter: none; color: var(--accent); border-color: var(--accent);
  background: rgba(var(--accent-rgb), 0.18); box-shadow: 0 0 6px rgba(var(--accent-rgb), 0.9), 0 0 12px rgba(var(--accent-rgb), 0.45); animation: sale-glow 1.6s ease-in-out infinite; }
.exploit-icon.side-slot.market:not(.locked) > .slot-sale .cur-ico { filter: drop-shadow(0 0 2px rgba(var(--accent-rgb), 0.9)); }
@keyframes sale-glow { 50% { box-shadow: 0 0 3px rgba(var(--accent-rgb), 0.6), 0 0 6px rgba(var(--accent-rgb), 0.25); } }
:root.low-fx .exploit-icon.side-slot.market > .slot-sale { animation: none; }
@media (prefers-reduced-motion: reduce) { .exploit-icon.side-slot.market > .slot-sale { animation: none; } }
/* (the theme and font tiles' names: button labels, so 12px, as the scale has them) */
.settings .theme-option > span:not(.lv-tag) { font-size: 12px; }
/* (the corner buttons, PAUSE and SETTINGS, over the title: a theme that animates the title (HALLOWEEN's
   flicker) lifts it into a layer of its own, and it would take their taps) */
.crt > :is(.records-btn, .settings-btn) { z-index: 30; }

/* Every locked item's LV n at the smallest text size (11.5px), in the accent color, never dimmed with
   what it's on: the playlist's and the music player's tracks, the themes and fonts, the side slots */
.settings button .need, .mp-tracks .need, .settings .theme-option .lv-tag { font-size: 11.5px; }
.exploit-icon.side-slot.locked-slot > .slot-lv { font-size: 11.5px; letter-spacing: 0; color: var(--accent); filter: none; text-shadow: 0 0 4px rgba(var(--accent-rgb), 0.45); }

/* A theme change: the screen dips to black (over everything but the CRT glass), the theme goes in
   unseen, and it comes back */
.theme-black { position: fixed; inset: 0; z-index: 9990; background: #000; opacity: 0; pointer-events: none; transition: opacity 0.22s ease-in; }
.theme-black.on { opacity: 1; pointer-events: auto; transition-timing-function: ease-out; }
.settings .theme-option .lv-tag { padding: 1px 3px; border-radius: 2px; background: var(--panel); top: 1px; right: 2px; } /* (over the end of a long name: it reads clean) */
/* The buttons on the game card get a base in the card's own color (their tints laid over it), mostly
   solid with a hint of what's behind: OCTOBER's trees, the scenery and the bots show faintly through,
   never enough to swallow them. On the dark themes it looks the same; on PAPER it keeps them readable */
:root { --btn-base: color-mix(in srgb, var(--panel) 92%, transparent); } /* (92%: as the board) */
.column-buttons button { background: linear-gradient(rgba(var(--fg-rgb), 0.08), rgba(var(--fg-rgb), 0.08)), var(--btn-base); }
.difficulty button:not(.active) { background-color: var(--btn-base); }
@media (hover: hover) { .difficulty button:not(.active):hover { background-image: linear-gradient(rgba(var(--fg-rgb), 0.15), rgba(var(--fg-rgb), 0.15)); } }
.vs-start { background: linear-gradient(rgba(var(--fg-rgb), 0.12), rgba(var(--fg-rgb), 0.12)), var(--btn-base); }
/* With CRT DISPLAY on, the whole screen has its scanlines: the infected bits' own little CRTs drop
   theirs (two sets would beat against each other in a moire), keeping only the inset and dimmed edges */
:root:is(.crt-soft, .crt-full) .cell .inf-glitch:is(.mosaic, .mini)::after { background: none; }
/* (the infected bits' blocks of characters: back to filling the bit, clipped only by its own border;
   no inset screen or scanlines, just a soft dark fade in from the border) */
.cell .inf-glitch:is(.mosaic, .mini) { inset: 0; border-radius: inherit; }
.cell .inf-glitch:is(.mosaic, .mini)::after,
:root:is(.crt-soft, .crt-full) .cell .inf-glitch:is(.mosaic, .mini)::after { background: none; box-shadow: inset 0 0 6px 1px rgba(0, 0, 0, 0.75); }
/* (every bit with an infection playing inside it gets that same fade, its art clipped by the bit's own
   border: all of MALWARE's looks and RANSOMWARE's little screens. Not the ADWARE frame or the
   CRYPTOJACKER's sign: those run across the board, not in a bit) */
.cell:is(.corrupt, .mosaic-empty)::after, .cell.ransom .inf-screen::after { content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit; box-shadow: inset 0 0 6px 1px rgba(0, 0, 0, 0.75); }
.cell .inf-glitch:is(.mosaic, .mini)::after, :root:is(.crt-soft, .crt-full) .cell .inf-glitch:is(.mosaic, .mini)::after { content: none; } /* (the bit's own fade now) */
.cell.ransom .inf-screen { inset: 0; border-radius: inherit; box-shadow: none; }
/* (the AD tag a touch see-through: 92%, as the board and the buttons on the card) */
.inf-ad-tag { opacity: 0.92; }

/* VS's SETUP, laid out as the main menu's mode card: in the board's place and at its width, only as
   tall as what it holds (the board, its drop buttons and EXPLOIT step in on START), its words at the
   menu's sizes and its buttons at the menu's set heights, every row the one gap apart. On a short
   screen its options scroll inside it (fading at its foot while there's more), START staying under
   them (script.js's fitVsSetup sets how tall it may get) */
body.vs-setup-up .board-frame > :not(#vs-setup),
body.vs-setup-up .board-wrap > :not(.board-frame) { display: none; }
body.vs-setup-up #vs-setup { position: relative; inset: auto; }
#vs-setup { justify-content: flex-start; gap: var(--gap); padding: 10px 12px; }
#vs-setup > :not(.vs-setup-body) { flex-shrink: 0; }
.vs-setup-body { flex: 0 1 auto; min-height: 0; width: 100%; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; align-items: center; gap: var(--gap); }
.vs-setup-body > * { flex-shrink: 0; }
.vs-setup-body.more { -webkit-mask-image: linear-gradient(#000 calc(100% - 22px), transparent); mask-image: linear-gradient(#000 calc(100% - 22px), transparent); }
#vs-setup .vs-setup-title { height: 18px; line-height: 18px; font-size: 15px; white-space: nowrap; overflow: hidden; }
/* (a locked bot's or level's notice over the title, in its place, while it shows) */
#vs-setup .vs-setup-msg { position: absolute; top: 10px; left: 12px; right: 12px; height: 18px; line-height: 18px; min-height: 0; font-size: 13px; }
#vs-setup .vs-setup-msg.show + .vs-setup-title { visibility: hidden; }
#vs-setup .vs-setup-note { width: 100%; max-width: none; font-size: 14.5px; letter-spacing: 1px; line-height: 1.5; }
/* (the pickers in even columns: the game modes two by two, the bots and levels four across, the
   switches two across as the menu's rows under its card) */
#vs-setup .difficulty { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap); width: 100%; max-width: none; margin: 0; }
#vs-setup #vs-options-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
#vs-setup .difficulty.vs-one { grid-template-columns: minmax(0, 1fr); }
#vs-setup .difficulty button { display: flex; align-items: center; justify-content: center; min-width: 0; height: 26px; padding: 0 4px; font-size: 13px; letter-spacing: 1px; white-space: nowrap; overflow: hidden; }
#vs-setup #vs-options-row button { height: 32px; padding: 0 6px; font-size: 12px; }
#vs-setup .vs-one button { height: 32px; }
/* (LAYERS between a layer's [=]s, dimmed while it's OFF; EXPLOITS with their terminal) */
#vs-layers-btn .lay-ico { margin: 0 0.6em; }
#vs-layers-btn:not(.active) .lay-ico { opacity: 0.35; }
#vs-exploits-btn .term-ico { width: 1em; height: 1em; margin-right: 0.45em; flex: none; }
#vs-setup .vs-goal-row { gap: var(--gap); }
#vs-setup .vs-goal-row button { width: 32px; height: 26px; }
#vs-setup .vs-goal { font-size: 13px; }
#vs-setup .vs-start { display: flex; align-items: center; justify-content: center; height: 36px; padding: 0 34px; }
/* ONE TITLE: BYTEFALL at the main menu's size in every game (VS too) and on the PUZZLES card (the
   menu's is 1.6em of its 12px line; script.js's clearOfCorners shrinks a game's only where it would
   touch a corner button) */
header h1, .card-brand { font-size: 19.2px; letter-spacing: 0.1em; }
/* THE PUZZLES card and THE MUSIC PLAYER, as a game's top: BACK in its corner, BYTEFALL centered on it
   as on the main menu, the card's name under it as a game's mode line (// PUZZLES, // MUSIC PLAYER),
   what's under it 8px under that */
.card-brand { display: none; }
:is(.records.puzzles, .music-player, .arcade) .card-head { position: relative; flex-direction: column; justify-content: flex-start; gap: 8px; margin-bottom: 6px; }
:is(.records.puzzles, .music-player, .arcade) .card-head .card-back { position: absolute; left: 0; top: 0; }
:is(.records.puzzles, .music-player, .arcade) .card-brand { display: block; margin: var(--head-nudge, 4.9px) 0 0; line-height: 1; white-space: nowrap; } /* (where every game's sits: script.js's alignHeader) */
:is(.records.puzzles #records-title, .music-player .mp-title, .arcade .arcade-title) { font-size: 11px; line-height: 1; letter-spacing: 2px; color: var(--fg-dim); text-shadow: none; }
.music-player .card-head.mp-head { margin-bottom: -4px; } /* (with the player's 12px gap: the visualizer 8px under its name) */
.card-head .card-brand span { font-size: inherit; letter-spacing: inherit; color: var(--accent); text-shadow: 0 0 8px var(--accent); } /* (FALL as the title's, not the card's heading) */
/* DAILY's cards: one row that slides sideways under the panel's sides and loops, a card at a time in
   the middle (each snapping softly to the center), the cards beside it peeking in, softly dimmed; the
   one in the middle is in focus the moment it gets there (script.js's .focus), it's the game PLAY
   plays, and the pips under the row light it. The panel's body reaches the panel's sides (its
   words kept 12px in) so the cards slide all the way out */
.home-panel-body { width: calc(100% + 24px); margin: 0 -12px; padding: 0 12px; container-type: inline-size; }
.home .daily-cards:not([hidden]) {
  display: flex; gap: 8px; width: calc(100% + 24px); margin: -6px -12px; padding: 6px calc(14cqw + 12px);
  overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
  position: relative;
}
.home .daily-cards button { flex: 0 0 72cqw; scroll-snap-align: center; scroll-snap-stop: always; opacity: 0.6; transition: opacity 0.25s ease-out, border-color 0.25s, background-color 0.25s, box-shadow 0.25s; }
.home .daily-cards button.focus { opacity: 1; }
.home .mode-info { white-space: pre-line; } /* (DAILY's: its streak and countdown on a line of their own) */
.daily-pips[hidden] { display: none; }
.daily-pips { display: flex; justify-content: center; gap: 8px; }
.daily-pips i { width: 6px; height: 6px; border-radius: 1px; background: rgba(var(--fg-rgb), 0.25); cursor: pointer; transition: background 0.15s, box-shadow 0.15s; }
.daily-pips i.on { background: var(--fg); box-shadow: 0 0 6px rgba(var(--fg-rgb), 0.7); }
/* THE MAIN MENU's BYTEFALL exactly where every game's is: pinned 8px from the top in the same one-line
   box, nudged as the games' is (script.js's alignHeader), and not scaled up with the menu on a bigger
   screen, as its BACK isn't; the menu's rows start where they did under it */
.home .home-head { position: absolute; top: 8px; left: 0; right: 0; height: auto; display: block; text-align: center; zoom: calc(1 / var(--home-zoom, 1)); }
.home .home-head h1 { line-height: 1; margin-top: var(--head-nudge, 5.4px); }
/* THE NOTICE LINE (script.js's showToast): every notice on the line under BYTEFALL, in the ENCRYPTION
   warning's style: plain glowing words over nothing, fading in, holding, then bursting into pixels; the
   line's own words step aside while one shows. One line across the screen (a long one shrinks) */
.notice-line {
  position: absolute; left: 8px; right: 8px; top: 46px; z-index: 16; margin: 0; transform: translateY(-50%);
  text-align: center; white-space: nowrap; font-size: 13px; line-height: 1.2; letter-spacing: 1px; /* (not clipped: the glow fades out round it) */
  color: var(--alarm-text); text-shadow: 0 0 10px var(--accent), 0 0 22px rgba(var(--accent-rgb), 0.8); pointer-events: none;
}
.notice-line[hidden] { display: none; }
.notice-line.show { animation: alarm-in 0.25s ease-out; }
body.noticing :is(header .tagline, .home-tagline) { visibility: hidden !important; }
/* (the main menu's line under BYTEFALL: // MAIN MENU, where every game has its mode, the menu's rows
   starting 8px under it) */
.home-tagline { margin: 8px 0 0; font-size: 11px; line-height: 1; letter-spacing: 2px; color: var(--fg-dim); }
.home { padding-top: 59px; }
/* NOTICES (RULES & RECORDS' third tab): each notice with when it came, newest first; unread ones lit */
.panel-notices .notices-body { display: flex; flex-direction: column; gap: var(--gap); }
.notice-item { display: flex; flex-direction: column; gap: 3px; padding: 8px 10px; border: 1px solid var(--grid-line); border-radius: 4px; }
.notice-item .notice-when { font-size: 11.5px; letter-spacing: 1px; color: var(--fg-dim); }
.notice-item .notice-text { font-size: 13px; letter-spacing: 1px; line-height: 1.35; color: var(--panel-text); }
.notice-item .notice-desc { font-size: 13px; line-height: 1.35; color: var(--fg-dim); } /* (an ACHIEVEMENT's: what it was for) */
.notice-item.unread { border-color: var(--accent); }
.notice-item.unread .notice-text { color: var(--accent); }
.notices-empty { font-size: 13px; color: var(--fg-dim); }
/* (a dot on RULES & RECORDS, the pause screen's and the NOTICES tab while some are unread) */
:is(#home-records, #pause-records, .menu-tabs [data-pane="notices"]) { position: relative; }
/* THE STORIES (js/stories.js). On the cracked card: the file the key recovered, typed out, or (a
   dashed box) what the next one needs; it scrolls inside the card on a short screen */
.goal-card .story-frag { align-self: stretch; flex: 0 1 auto; min-height: 0; overflow-y: auto; text-align: left; border: 1px solid rgba(var(--fg-rgb), 0.35); background: rgba(0, 0, 0, 0.35); padding: 8px; margin: 0; cursor: pointer; }
.goal-card .story-frag[hidden] { display: none; }
.goal-card .story-frag.locked { border-style: dashed; cursor: default; }
.goal-card.tight #goal-note { display: none; }
.story-frag .sf-head { margin: 0 0 4px; font-size: 11.5px; letter-spacing: 1px; color: var(--accent); }
.story-frag.locked .sf-head { color: var(--fg-dim); }
.story-frag .sf-doc { margin: 0 0 6px; font-size: 11.5px; letter-spacing: 1px; color: var(--fg-dim); }
.story-frag .sf-body { margin: 0; font-size: 13px; line-height: 1.4; color: var(--panel-text); white-space: pre-line; }
.story-frag .sf-noise, .archive-file .af-noise { margin: 0 0 6px; font-size: 13px; letter-spacing: 1px; color: rgba(var(--fg-rgb), 0.45); white-space: nowrap; overflow: hidden; }
.story-frag .sf-caret { display: inline-block; width: 0.55em; height: 1em; margin-left: 2px; background: var(--fg); vertical-align: -0.15em; animation: sf-blink 1s steps(1) infinite; }
@keyframes sf-blink { 50% { opacity: 0; } }
.low-fx .story-frag .sf-caret { animation: none; }
/* The ARCHIVE: the stories, then a story's files by chapter (recovered, NEW till read, or encrypted) */
.panel-archive .archive-body { display: flex; flex-direction: column; gap: var(--gap); }
.panel-archive .archive-note, .panel-archive .archive-blurb { font-size: 13px; line-height: 1.4; color: var(--fg-dim); margin: 0; }
.archive-story { position: relative; display: flex; flex-direction: column; align-items: stretch; gap: 4px; width: 100%; padding: 8px 10px; text-align: left; border: 1px solid var(--grid-line); border-radius: 4px; background: transparent; color: var(--panel-text); font: inherit; cursor: pointer; }
.archive-story.on { border-color: var(--fg); box-shadow: 0 0 8px rgba(var(--fg-rgb), 0.25); }
.archive-story.locked { opacity: 0.5; }
.archive-story .as-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.archive-story .as-title { font-size: 14.5px; letter-spacing: 2px; color: var(--fg); }
.archive-story .as-blurb { font-size: 13px; line-height: 1.35; }
.archive-story .as-state { font-size: 11.5px; letter-spacing: 1px; color: var(--fg-dim); }
.archive-story .as-enc { letter-spacing: 1px; color: rgba(var(--fg-rgb), 0.45); overflow-wrap: anywhere; } /* (a season still to come: its lines noise) */
.archive-story.on .as-state { color: var(--fg); }
.archive-new, .archive-file .af-head b { font-size: 11.5px; letter-spacing: 1px; font-weight: normal; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6); }
.archive-back { align-self: flex-start; padding: 4px 10px; font: inherit; font-size: 12px; letter-spacing: 1px; color: var(--fg); background: transparent; border: 1px solid var(--fg-dim); border-radius: 3px; cursor: pointer; }
.panel-archive .archive-title { margin: 0; font-size: 15.5px; letter-spacing: 2px; color: var(--accent); }
.archive-pick { padding: 8px; font: inherit; font-size: 13px; letter-spacing: 1px; color: var(--fg); background: transparent; border: 1px solid var(--fg); border-radius: 3px; cursor: pointer; }
.archive-pick.on { background: var(--fg); color: var(--panel); font-weight: bold; cursor: default; }
.panel-archive .archive-state { margin: 0; font-size: 13px; letter-spacing: 1px; color: var(--fg); }
.panel-archive .archive-chapter { margin: 0; display: flex; justify-content: space-between; gap: 8px; font-size: 13px; letter-spacing: 1px; color: var(--accent); }
.panel-archive .archive-chapter span { color: var(--fg-dim); font-size: 11.5px; }
.archive-file { display: flex; flex-direction: column; gap: 4px; padding: 8px 10px; border: 1px solid var(--grid-line); border-radius: 4px; }
.archive-file.new { border-color: var(--accent); }
.archive-file.locked { border-style: dashed; }
.panel-archive .archive-file p { margin: 0; }
.archive-file .af-head { font-size: 11.5px; letter-spacing: 1px; color: var(--fg-dim); }
.archive-file .af-body { font-size: 13px; line-height: 1.4; color: var(--panel-text); white-space: pre-line; }
/* (the main menu's STORY button: its folder, as PATCHES' USB stick; its NEW dot in its own corner) */
#story-row button { position: relative; }
.opt-text .story-ico { width: 1em; height: 1em; vertical-align: -0.15em; margin-right: 0.35em; }
.has-unread::after { content: ""; position: absolute; top: 5px; right: 6px; width: 6px; height: 6px; border-radius: 1px; background: var(--accent); box-shadow: 0 0 6px rgba(var(--accent-rgb), 0.8); pointer-events: none; }
/* THE RESULT SCREEN's EARNED: what the game held back, under the level meter */
.overlay-earned { margin: var(--gap) 0 12px; max-height: 120px; overflow-y: auto; }
.overlay-earned[hidden] { display: none; }
.overlay-earned .oe-head { margin: 0 0 4px; font-size: 13px; letter-spacing: 2px; color: var(--fg-dim); }
.overlay-earned .oe-item { margin: 2px 0; font-size: 13px; letter-spacing: 1px; line-height: 1.3; color: var(--accent); text-shadow: 0 0 6px rgba(var(--accent-rgb), 0.5); animation: alarm-in 0.25s ease-out; }
/* THE DAILY DROP, claimed: what it gave, in its card */
.daily-got { margin: 8px 0 0; font-size: 13px; letter-spacing: 1px; line-height: 1.35; color: var(--accent); }
.daily-got[hidden] { display: none; }
.daily-got.fresh { animation: alarm-in 0.25s ease-out, warn-pulse 1s ease-in-out 0.25s 2; }
/* WHAT A DROP EARNED: in the CHAIN box (chains earn the resources), centered between the foot of its
   value's digits and its bottom edge (the value's centered: its foot --val-foot under the middle), every resource on
   one line (shrunk to fit) */
#chain-stat .res-pop {
  position: absolute; left: 2px; right: 2px; bottom: 0; height: calc(50% - var(--val-foot, 8px)); z-index: 2; display: flex; justify-content: center; align-items: center; gap: 5px;
  white-space: nowrap; font-size: 10px; line-height: 1; letter-spacing: 0.5px; color: var(--fg); pointer-events: none;
  animation: pickup 1.7s ease-out forwards;
}
#chain-stat .res-pop .res-chip { gap: 2px; }
#chain-stat .res-pop .key-ico { display: block; width: 1.15em; height: 1.15em; }
/* (its number trimmed to its capitals, so the icon and the +1 line up by their middles whatever the
   font's ascent and descent) */
#chain-stat .res-pop .rc-n { display: block; line-height: 1; text-box: trim-both cap alphabetic; }
@keyframes pickup { 0% { opacity: 0; transform: translateY(3px); } 12% { opacity: 1; transform: none; } 75% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { #chain-stat .res-pop { animation-name: res-pop-still; } }
/* (NOTICES: which end is newest, under its head) */
.notices-note { margin: -4px 0 var(--gap); font-size: 13px; letter-spacing: 1px; color: var(--fg-dim); }
/* THE MAIN MENU's BOOSTERS and STARTERS, as VS's settings: a button each saying NAME: what's on it, filled
   while something's on (as LAYERS: ON), the two starter slots two across, BOOSTERS across the card; a
   slot not open yet locked (its level dimmed behind the padlock). A long name trails off */
.home .home-opts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap); width: 100%; margin: 0; }
.home .home-opts.single { grid-template-columns: minmax(0, 1fr); }
.home .home-opts[hidden] { display: none; }
.home .home-opts button { height: 32px; min-width: 0; padding: 0 8px; font-size: 12px; letter-spacing: 1px; }
.home .home-opts .opt-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home .home-opts .ico { width: 1.15em; height: 1.15em; vertical-align: -0.22em; margin-right: 3px; }
/* A "can't do that" in a card's title (script.js's titleNotice), in its place while it shows: the main
   menu's mode card (where // CLASSIC is) and the menu cards (where // EXPLOITS is), as VS's setup */
.home-panel-msg { position: absolute; top: 10px; left: 12px; right: 12px; height: 18px; line-height: 18px; min-height: 0; font-size: 13px; text-align: center; z-index: 1; }
.home-panel-msg.show + .home-mode-name { visibility: hidden; }
.card-head .title-wrap { position: relative; flex: 1 1 auto; min-width: 0; display: flex; align-items: center; font-size: inherit; letter-spacing: inherit; color: inherit; text-shadow: none; } /* (as tall as the title in it: PUZZLES' // PUZZLES stays where a game's mode line is) */
.card-head .title-msg { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%); min-height: 0; font-size: 13px; letter-spacing: 1px; color: var(--accent); }
.title-wrap:has(.title-msg.show) #records-title { visibility: hidden; }

/* EXPLOITS TO KEEP (EXPLOITS): unlocked, not bought yet: its price in resources (have / cost, red
   where short) and a tap to buy it for good; a first tap lights it, pulsing, for the second */
.hack-item.to-buy { cursor: pointer; border-color: rgba(var(--accent-rgb), 0.55); }
.hack-item.to-buy .lock-tag { color: var(--accent); }
.hack-item.to-buy.confirm { border-style: solid; border-color: var(--accent); animation: amber-pulse 0.9s ease-in-out infinite; }
.hack-item .own-cost { padding: 4px 0 2px; gap: 4px 14px; }
.hack-item .own-cost[hidden] { display: none; }

/* RECORDS' HISTORY: the last games, newest first, each a block under a dotted line */
.hist-game { padding: 8px 0; border-bottom: 1px dashed var(--grid-line); }
.hist-top { display: flex; justify-content: space-between; gap: 8px; font-size: 14.5px; letter-spacing: 1px; }
.hist-name { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hist-result { color: var(--accent); white-space: nowrap; }
.hist-when { font-size: 11.5px; color: var(--fg-dim); letter-spacing: 1px; margin-top: 2px; }
.hist-stats { display: flex; flex-wrap: wrap; gap: 2px 14px; margin-top: 4px; font-size: 13px; color: var(--fg-dim); letter-spacing: 0.5px; }
.hist-stats em { font-style: normal; color: var(--accent); }
.hist-earned { display: flex; flex-wrap: wrap; gap: 2px 10px; margin-top: 4px; font-size: 13px; }
.hist-patched { margin-top: 4px; font-size: 11.5px; color: var(--fg-dim); letter-spacing: 1px; }

/* THE STORE's top, 8px between each: the title, YOUR RESOURCES, the resources on one line (KEYS
   first), PRICES TODAY, then the ===== line; the message line takes room only while it says something */
.store-top h2 { margin: 0; }
.panel-store .store-keys { display: block; margin: var(--gap) 0 0; font-size: 13px; text-align: center; }
.store-top .wallet { flex-wrap: nowrap; gap: 0 9px; margin: var(--gap) 0 0; font-size: 13px; letter-spacing: 0.5px; white-space: nowrap; }
.store-top .wallet .key-ico { color: var(--accent); }
.price-gauge { display: flex; flex-direction: column; align-items: center; gap: 2px; margin: var(--gap) 0 0; }
.pg-row { display: flex; align-items: center; gap: 6px; font-size: 11.5px; letter-spacing: 1px; color: var(--fg-dim); }
.pg-label { color: var(--fg); margin-right: 2px; }
.pg-bar { display: flex; gap: 2px; }
.pg-bar i { width: 14px; height: 6px; background: rgba(var(--fg-rgb), 0.15); }
.price-gauge.pos-0 .pg-bar i.on, .price-gauge.pos-1 .pg-bar i.on { background: var(--fg); box-shadow: 0 0 5px rgba(var(--fg-rgb), 0.8); }
.price-gauge.pos-2 .pg-bar i.on { background: var(--fg-dim); }
.price-gauge.pos-3 .pg-bar i.on, .price-gauge.pos-4 .pg-bar i.on { background: var(--danger); box-shadow: 0 0 5px var(--danger); }
.pg-why { font-size: 11.5px; letter-spacing: 1px; color: var(--accent); text-align: center; }
.price-gauge.pos-2 .pg-why { color: var(--fg-dim); }
.store-top .store-msg { min-height: 0; margin: var(--gap) 0 0 !important; font-size: 13px; }
.store-top .store-msg:empty { display: none; }
/* (a section's sale or markup today, by its head: green off, red up) */
/* (each STORE item's sale badge: its kind's change today, -n% in the terminal color, +n% in red) */
.store-item .sale-tag { flex: none; margin-left: 8px; padding: 0 4px; font-size: 11.5px; font-weight: normal; letter-spacing: 0; line-height: 15px; color: var(--bg-solid); background: var(--fg); border-radius: 3px; text-shadow: none; }
.store-item .sale-tag.up { background: var(--danger); }
.store-item .sale-tag[hidden] { display: none; }

/* CLASSIC's ENCRYPTION STRENGTH: a thin bar along the SCORE box's foot, filling toward this game's key
   (lit near it), and the card the game holds on once it's cracked, laid out as PAUSE's */
.goal-bar { position: absolute; left: 6px; right: 6px; bottom: 3px; height: 2px; background: rgba(var(--fg-rgb), 0.15); pointer-events: none; }
.goal-bar[hidden] { display: none; }
.goal-bar b { display: block; height: 100%; width: 0; background: var(--fg-dim); transition: width 0.3s ease-out; }
.goal-bar.near b { background: var(--accent); box-shadow: 0 0 5px rgba(var(--accent-rgb), 0.8); }
.goal-bar.enc { background: repeating-linear-gradient(90deg, rgba(var(--fg-rgb), 0.15) 0 3px, transparent 3px 6px); } /* (its key's strength ENCRYPTED: an empty, broken line) */
.goal-bar.reveal b { transition: width 1.2s ease-out; } /* (found out: it fills to where the score's got to) */
.goal-card .goal-keys { margin: 0; display: inline-flex; align-items: center; justify-content: center; gap: 6px; font-size: 17px; letter-spacing: 2px; color: var(--accent); text-shadow: 0 0 8px rgba(var(--accent-rgb), 0.6); }
.goal-card .goal-keys .key-ico { width: 17px; height: 17px; }
.goal-card #goal-out { margin-top: 0; }

/* (a card's items scrolled out of sight hold their animations still till they come back: script.js's
   offView watcher) */
.off-view, .off-view * { animation-play-state: paused !important; }

/* RULES & RECORDS: 8px between everything, as the game's other cards. The card's head, its tabs and
   the pane under them; in RULES, RECORDS and NOTICES each heading, paragraph, ===== line, group,
   row and stat line; RECORDS' own tabs (UNLOCKS, ACHIEVEMENTS, STATS, HISTORY) 8px apart, each as
   wide as its word, at the game's smallest text size */
.records .card-head { margin-bottom: var(--gap); }
.records .menu-tabs { margin-bottom: 0; }
.records .card-top { padding-bottom: var(--gap); }
.records :is(.panel-rules, .panel-records, .panel-notices, .panel-archive) h2 { margin: 0 0 var(--gap); }
.records :is(.panel-rules, .panel-records, .panel-notices, .panel-archive) p { margin: 0 0 var(--gap); }
.records .panel-rules .rules-sub { margin: 0 0 var(--gap); }
.records .records-tabs { gap: var(--gap); margin: 0; padding: 0 0 var(--gap); top: -1px; }
.records .records-tabs button { flex: 1 1 auto; padding: 5px 6px; font-size: 11.5px; }
.records .rec-level, .records .rec-summary, .records .rec-group { margin: 0 0 var(--gap); }
.records .rec-sep + .rec-group, .records .rec-group:first-child { margin-top: 0; }
.records .rec-row { padding: var(--gap) 0; }
.records .rec-row:first-child { padding-top: 0; }
.records .rec-desc { margin: var(--gap) 0 0; }
.records .rec-bar { margin-top: var(--gap); }
.records .rec-stats div { margin-bottom: var(--gap); }
.records .rec-reset { margin-top: 0; }
.records .notices-note { margin: 0 0 var(--gap); }
.records .notice-item { gap: var(--gap); }
.records .notices-body { gap: var(--gap); }
.records .hist-game { padding: var(--gap) 0; }
.records .hist-game:first-child { padding-top: 0; }
.records :is(.hist-when, .hist-stats, .hist-earned, .hist-patched) { margin-top: var(--gap); }

/* ?storytest: the review bar (js/story-test.js), over everything */
#story-test { position: fixed; left: 0; right: 0; bottom: 0; z-index: 10000; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 8px 16px calc(8px + env(safe-area-inset-bottom)); background: var(--bg, #000); border-top: 1px solid var(--accent); font-size: 12px; }
#story-test select { flex: 1 1 100%; min-width: 0; padding: 6px; font: inherit; color: var(--fg); background: var(--bg, #000); border: 1px solid var(--fg-dim); border-radius: 3px; }
#story-test button { flex: 1 1 0; padding: 8px 0; font: inherit; letter-spacing: 1px; color: var(--accent); background: transparent; border: 1px solid var(--accent); border-radius: 3px; cursor: pointer; }
body.storytest #story-msg { box-sizing: border-box; padding-bottom: 120px; }
body.storytest .phone-screen { height: min(600px, calc(100vh - 250px)); height: min(600px, calc(100dvh - 250px)); }
#story-test .st-count { flex: 1 1 100%; margin: 0; color: var(--fg-dim); letter-spacing: 1px; }
#story-test .st-write { flex: 1 1 100%; display: flex; flex-direction: column; gap: 8px; }
#story-test .st-write[hidden] { display: none; }
#story-test .st-kinds { display: flex; gap: 8px; }
#story-test .st-kinds button.on { color: var(--bg, #000); background: var(--accent); }
#story-test :is(.st-title, .st-text) { width: 100%; box-sizing: border-box; padding: 6px; font: inherit; color: var(--fg); background: var(--bg, #000); border: 1px solid var(--fg-dim); border-radius: 3px; }
#story-test .st-text { resize: vertical; max-height: 40vh; }
/* (STORY picked while it's COMING SOON, the Play release: PLAY says so, dimmed) */
#home-play.soon { color: var(--fg-dim); border-style: dashed; box-shadow: none; }
