OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / examples / hiveworm-app / style.css

651 lines · css ref:
/*
 * HiveWorm — goofy + nostalgic + slick.
 *
 * Reference points: Worms 2 (Team17), Pokémon Gold/Silver route maps, Katamari
 * Damacy, Bubble Bobble, Sayonara Wild Hearts, Earthbound. We want chunky,
 * saturated, characterful — Saturday-morning cartoon meets late-arcade —
 * but rendered with grown-up motion design. Goofy is the personality, slick
 * is the quality.
 *
 * Palette
 *   sky-top       #7ec8e3   warm sky-blue
 *   sky-mid       #a8e6cf   horizon mint
 *   grass         #7cba5f   rich saturated grass
 *   grass-deep    #4a8a3c   tuft / shadow grass
 *   dirt          #8b5a2b   warm brown
 *   sun           #ffd54f
 *   flower-red    #e74c3c
 *   flower-yel    #f1c40f
 *
 * UI palette (chunky arcade)
 *   ink           #1f1d2b   near-black with violet tilt — used for outlines
 *   bone          #fff8e7   off-white for text fills
 *   accent-pink   #ff5e9c   bubblegum
 *   accent-cyan   #4fc3f7
 *   accent-yel    #ffd54f
 *   accent-purp   #b266ff
 *
 * Type
 *   "Press Start 2P" — chunky pixel display for headings / score / KO
 *   "VT323"          — terminal pixel for body / hints / status
 */

@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&display=swap');

:root {
  --sky-top:    #7ec8e3;
  --sky-mid:    #a8e6cf;
  --grass:      #7cba5f;
  --grass-deep: #4a8a3c;
  --dirt:       #8b5a2b;
  --sun:        #ffd54f;

  --ink:         #1f1d2b;
  --bone:        #fff8e7;
  --bone-soft:   #ffe8a8;
  --paper:       #fff5d4;
  --shadow:      rgba(31, 29, 43, 0.28);

  --pink:   #ff5e9c;
  --lime:   #aedb45;
  --cyan:   #4fc3f7;
  --yel:    #ffd54f;
  --tomato: #ff5e3a;
  --purp:   #b266ff;

  --font-display: "Press Start 2P", "Pixelify Sans", ui-monospace, monospace;
  --font-body:    "VT323", "Press Start 2P", ui-monospace, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  width: 100%; height: 100%;
  overflow: hidden;
  background: #6dbbe0;            /* fallback before canvas paints */
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 18px;
  font-weight: 400;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: none;
  text-rendering: optimizeLegibility;
  image-rendering: -webkit-optimize-contrast;
}

#world {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  display: block;
  background: linear-gradient(to bottom, var(--sky-top) 0%, var(--sky-mid) 55%, var(--grass) 100%);
  cursor: crosshair;
}

.hidden { display: none !important; }

/* Chunky arcade text — used everywhere a label needs presence */
.chunk {
  font-family: var(--font-display);
  color: var(--bone);
  text-shadow:
    2px 0 0 var(--ink),
    -2px 0 0 var(--ink),
    0 2px 0 var(--ink),
    0 -2px 0 var(--ink),
    2px 2px 0 var(--ink),
    -2px -2px 0 var(--ink),
    2px -2px 0 var(--ink),
    -2px 2px 0 var(--ink),
    3px 3px 0 var(--shadow);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ─── Boot splash ────────────────────────────────────────── */

#splash {
  position: fixed; inset: 0;
  background: linear-gradient(to bottom, var(--sky-top) 0%, var(--sky-mid) 50%, var(--grass) 100%);
  display: flex; align-items: center; justify-content: center;
  z-index: 100;
  transition: opacity 0.6s ease;
  overflow: hidden;
}
#splash.hidden { opacity: 0; pointer-events: none; display: flex !important; }

/* a couple of slow clouds + a sun */
.splash-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.splash-card {
  text-align: center;
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.splash-art {
  width: 220px;
  height: 220px;
  filter: drop-shadow(6px 6px 0 var(--shadow));
  image-rendering: pixelated;
}

.splash-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 40px;
  letter-spacing: 0.06em;
  color: var(--bone);
  -webkit-text-stroke: 0;
  text-shadow:
    3px 0 0 var(--ink),
    -3px 0 0 var(--ink),
    0 3px 0 var(--ink),
    0 -3px 0 var(--ink),
    3px 3px 0 var(--ink),
    -3px -3px 0 var(--ink),
    3px -3px 0 var(--ink),
    -3px 3px 0 var(--ink),
    6px 6px 0 var(--shadow);
}

.splash-msg {
  margin: 0;
  font-family: var(--font-display);
  font-size: 11px;
  color: var(--bone);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-shadow: 2px 2px 0 var(--ink);
}
.splash-msg::after {
  content: '_';
  display: inline-block;
  margin-left: 4px;
  animation: caret-blink 0.9s steps(2, end) infinite;
}

@keyframes caret-blink {
  0%, 50%   { opacity: 1; }
  51%, 100% { opacity: 0; }
}

@keyframes wave-bob {
  0%, 100% { transform: translateY(0) rotate(-1deg); }
  50%      { transform: translateY(-6px) rotate(2deg); }
}

.splash-art {
  animation: wave-bob 1.6s ease-in-out infinite;
}

/* ─── HUD scaffolding ────────────────────────────────────── */

#hud {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 10;
  font-family: var(--font-body);
}
#hud > * { pointer-events: auto; }

.hud-corner {
  position: absolute;
  padding: 14px;
}
.hud-tl { top: 0; left: 0; }
.hud-tr { top: 0; right: 0; }
.hud-bl { bottom: 0; left: 0; }
.hud-br { bottom: 0; right: 0; }

.hud-bottom {
  position: absolute;
  left: 50%;
  bottom: 26px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/* Generic chunky panel: thick black outline, paper fill, hard offset shadow */
.panel {
  background: var(--paper);
  color: var(--ink);
  border: 3px solid var(--ink);
  border-radius: 8px;
  box-shadow: 4px 4px 0 var(--ink), 4px 4px 0 4px var(--shadow);
  padding: 8px 12px;
  position: relative;
}

/* ─── Score card ─────────────────────────────────────────── */

.score-card {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 14px 10px 14px;
}
.score-label {
  font-family: var(--font-display);
  font-size: 9px;
  letter-spacing: 0.18em;
  color: var(--ink);
  text-transform: uppercase;
  opacity: 0.75;
}
.score-num {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 400;
  line-height: 1;
  color: var(--bone);
  text-shadow:
    2px 0 0 var(--ink), -2px 0 0 var(--ink),
    0 2px 0 var(--ink), 0 -2px 0 var(--ink),
    2px 2px 0 var(--ink), -2px -2px 0 var(--ink),
    2px -2px 0 var(--ink), -2px 2px 0 var(--ink),
    3px 4px 0 var(--shadow);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  transition: transform 0.18s cubic-bezier(.32,1.7,.6,.95);
  display: inline-block;
}
.score-num.bump {
  transform: scale(1.18);
}

/* ─── Mini-map ───────────────────────────────────────────── */

.mini-card {
  padding: 8px 8px 6px 8px;
}
#mini-map {
  display: block;
  background: var(--grass);
  border: 2px solid var(--ink);
  border-radius: 4px;
  image-rendering: pixelated;
}
.mini-stats {
  font-family: var(--font-display);
  font-size: 8px;
  letter-spacing: 0.15em;
  text-align: center;
  margin-top: 6px;
  color: var(--ink);
  text-transform: uppercase;
}
.mini-stats #worm-count {
  color: var(--ink);
  background: var(--yel);
  border: 2px solid var(--ink);
  padding: 1px 5px;
  border-radius: 4px;
  margin-right: 2px;
}

/* ─── Identity / status panel ────────────────────────────── */

.ident-card {
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 1;
  min-width: 220px;
  padding: 8px 12px 10px 12px;
}
.ident-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 0;
  font-variant-numeric: tabular-nums;
}
.ident-label {
  font-family: var(--font-display);
  font-size: 8px;
  letter-spacing: 0.16em;
  color: var(--ink);
  opacity: 0.7;
  text-transform: uppercase;
}
.ident-pubkey {
  font-family: var(--font-body);
  font-size: 18px;
  color: var(--ink);
  background: var(--bone-soft);
  border: 2px solid var(--ink);
  padding: 0 6px;
  border-radius: 4px;
}
.ident-status[data-kind="ok"]    { color: #2c7d2c; }
.ident-status[data-kind="warn"]  { color: #b97000; }
.ident-status[data-kind="error"] { color: #c0392b; }

#cooldown {
  font-family: var(--font-display);
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--ink);
  background: var(--bone-soft);
  border: 2px solid var(--ink);
  padding: 2px 5px;
  border-radius: 4px;
}
.buttons-row { gap: 6px; margin-top: 6px; }

.mini-btn {
  font: inherit;
  font-family: var(--font-display);
  font-size: 8px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: var(--cyan);
  color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 4px;
  padding: 5px 9px;
  cursor: pointer;
  box-shadow: 2px 2px 0 var(--ink);
  transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.12s ease;
}
.mini-btn:hover {
  background: var(--lime);
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 var(--ink);
}
.mini-btn:active {
  transform: translate(2px, 2px);
  box-shadow: 0 0 0 var(--ink);
}

/* ─── Mute / audio button ────────────────────────────────── */

.mute-btn {
  font: inherit;
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  background: var(--purp);
  color: var(--bone);
  border: 3px solid var(--ink);
  border-radius: 8px;
  padding: 9px 14px;
  cursor: pointer;
  box-shadow: 3px 3px 0 var(--ink), 3px 3px 0 3px var(--shadow);
  transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.12s ease;
  text-shadow: 2px 2px 0 var(--ink);
}
.mute-btn:hover {
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 var(--ink), 4px 4px 0 3px var(--shadow);
}
.mute-btn:active {
  transform: translate(2px, 2px);
  box-shadow: 0 0 0 var(--ink), 0 0 0 0 var(--shadow);
}
.mute-btn[data-muted="1"] {
  background: #777;
  color: var(--bone);
}

/* ─── Big bottom button (SPAWN / RESPAWN) ────────────────── */

.big-btn {
  font: inherit;
  font-family: var(--font-display);
  font-size: 18px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  background: var(--lime);
  color: var(--bone);
  border: 4px solid var(--ink);
  border-radius: 14px;
  padding: 16px 36px;
  cursor: pointer;
  position: relative;
  box-shadow: 5px 5px 0 var(--ink), 5px 5px 0 5px var(--shadow);
  text-shadow:
    2px 0 0 var(--ink), -2px 0 0 var(--ink),
    0 2px 0 var(--ink), 0 -2px 0 var(--ink),
    2px 2px 0 var(--ink), -2px -2px 0 var(--ink),
    2px -2px 0 var(--ink), -2px 2px 0 var(--ink),
    3px 4px 0 rgba(0,0,0,0.25);
  transition: transform 0.1s cubic-bezier(.32,1.6,.6,.95), box-shadow 0.1s ease, background 0.15s ease;
}
.big-btn:hover {
  transform: translate(-2px, -2px) rotate(-1deg);
  box-shadow: 7px 7px 0 var(--ink), 7px 7px 0 5px var(--shadow);
  background: var(--yel);
}
.big-btn:active {
  transform: translate(3px, 3px) rotate(0);
  box-shadow: 1px 1px 0 var(--ink), 1px 1px 0 5px var(--shadow);
}

#respawn-btn {
  background: var(--pink);
}
#respawn-btn:hover {
  background: var(--tomato);
}

.bounce-in {
  animation: chunky-bounce-in 0.55s cubic-bezier(.32,1.7,.6,.95);
}
@keyframes chunky-bounce-in {
  0%   { opacity: 0; transform: translateY(28px) scale(0.7) rotate(-6deg); }
  60%  { opacity: 1; transform: translateY(-6px) scale(1.08) rotate(2deg); }
  80%  { transform: translateY(2px) scale(0.97) rotate(-1deg); }
  100% { transform: translateY(0) scale(1) rotate(0); }
}

.move-hint {
  font-family: var(--font-body);
  font-size: 18px;
  color: var(--ink);
  background: var(--paper);
  border: 3px solid var(--ink);
  border-radius: 10px;
  padding: 6px 14px;
  letter-spacing: 0.04em;
  text-transform: lowercase;
  box-shadow: 3px 3px 0 var(--ink);
}

/* ─── Tooltips / toasts ──────────────────────────────────── */

#first-tooltip {
  position: absolute;
  left: 50%;
  bottom: 130px;
  transform: translateX(-50%);
  background: var(--bone);
  color: var(--ink);
  padding: 8px 18px;
  font-family: var(--font-body);
  font-size: 18px;
  border: 3px solid var(--ink);
  border-radius: 10px;
  box-shadow: 4px 4px 0 var(--ink);
  animation: nudge 1.6s ease-in-out infinite;
}
.tooltip-arrow {
  position: absolute;
  bottom: -10px;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  width: 14px; height: 14px;
  background: var(--bone);
  border-right: 3px solid var(--ink);
  border-bottom: 3px solid var(--ink);
}
@keyframes nudge {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(-4px); }
}

.hint {
  position: absolute;
  top: 18px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--paper);
  color: var(--ink);
  border: 3px solid var(--ink);
  padding: 8px 18px;
  font-family: var(--font-body);
  font-size: 18px;
  letter-spacing: 0.02em;
  max-width: 80%;
  text-align: center;
  z-index: 30;
  border-radius: 10px;
  box-shadow: 4px 4px 0 var(--ink);
}

.reason-toast {
  position: absolute;
  bottom: 130px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--tomato);
  color: var(--bone);
  border: 3px solid var(--ink);
  padding: 6px 16px;
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-shadow: 2px 2px 0 var(--ink);
  border-radius: 10px;
  box-shadow: 4px 4px 0 var(--ink);
  z-index: 25;
  animation: shimmy 0.4s cubic-bezier(.32,1.7,.6,.95);
}
@keyframes shimmy {
  0%   { transform: translateX(-50%) translateY(8px) rotate(-2deg); opacity: 0; }
  60%  { transform: translateX(-50%) translateY(-2px) rotate(1.5deg); opacity: 1; }
  100% { transform: translateX(-50%) translateY(0) rotate(0); opacity: 1; }
}

/* ─── KO / death banner ──────────────────────────────────── */

#ko-banner {
  position: fixed;
  left: 50%;
  top: 38%;
  transform: translate(-50%, -50%);
  font-family: var(--font-display);
  font-size: 96px;
  color: var(--bone);
  text-shadow:
    5px 0 0 var(--ink), -5px 0 0 var(--ink),
    0 5px 0 var(--ink), 0 -5px 0 var(--ink),
    5px 5px 0 var(--ink), -5px -5px 0 var(--ink),
    5px -5px 0 var(--ink), -5px 5px 0 var(--ink),
    8px 10px 0 rgba(0,0,0,0.35);
  pointer-events: none;
  z-index: 40;
  letter-spacing: 0.08em;
  transform-origin: 50% 50%;
}
#ko-banner.show {
  animation: ko-impact 1.6s cubic-bezier(.18,1.9,.4,1.05) forwards;
}
@keyframes ko-impact {
  0%   { transform: translate(-50%,-50%) scale(0.2) rotate(-12deg); opacity: 0; }
  20%  { transform: translate(-50%,-50%) scale(1.4) rotate(6deg); opacity: 1; }
  35%  { transform: translate(-50%,-50%) scale(0.95) rotate(-3deg); }
  50%  { transform: translate(-50%,-50%) scale(1.05) rotate(1deg); }
  65%  { transform: translate(-50%,-50%) scale(1) rotate(0); }
  100% { transform: translate(-50%,-50%) scale(1) rotate(0); opacity: 1; }
}

/* ─── Touch directional pad ──────────────────────────────── */

#touch-pad-host {
  position: absolute;
  bottom: 110px;
  right: 18px;
  pointer-events: auto;
}
.touch-pad {
  position: relative;
  width: 156px;
  height: 156px;
}
.touch-btn {
  position: absolute;
  width: 52px;
  height: 52px;
  background: var(--paper);
  color: var(--ink);
  border: 3px solid var(--ink);
  border-radius: 8px;
  font-size: 22px;
  cursor: pointer;
  box-shadow: 3px 3px 0 var(--ink);
}
.touch-btn:active {
  background: var(--yel);
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 var(--ink);
}
.touch-up    { top: 0;    left: 52px; }
.touch-down  { bottom: 0; left: 52px; transform: rotate(180deg); }
.touch-left  { top: 52px; left: 0;    transform: rotate(-90deg); }
.touch-right { top: 52px; right: 0;   transform: rotate(90deg); }

/* ─── Death white-flash overlay ──────────────────────────── */

.flash::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 50;
  background: rgba(255, 255, 255, 0.85);
  animation: flash-fade 0.22s ease-out forwards;
}
@keyframes flash-fade {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}

/* ─── Mobile adjustments ─────────────────────────────────── */

@media (max-width: 720px) {
  .score-num { font-size: 24px; }
  .ident-card { font-size: 15px; min-width: 170px; }
  .big-btn { font-size: 14px; padding: 13px 26px; letter-spacing: 0.12em; border-width: 3px; }
  .hud-bottom { bottom: 18px; }
  .hud-corner { padding: 8px; }
  #mini-map { width: 96px; height: 96px; }
  .splash-title { font-size: 28px; }
  .splash-art { width: 160px; height: 160px; }
  #ko-banner { font-size: 64px; }
}

/* ─── Reduced motion ─────────────────────────────────────── */

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