* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #000000;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

#gameCanvas {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
}

#ui-overlay {
  position: fixed;
  top: 20px;
  left: 0;
  width: 100%;
  display: flex;
  justify-content: space-between;
  padding: 0 24px;
  pointer-events: none;
  font-family: 'Courier New', monospace;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.45);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  z-index: 10;
}

#right-col {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}

#top-buttons-row {
  display: flex;
  gap: 8px;
}

/* Hidden until a game is actually in progress (see updateWaveDisplay) —
   togglePause() is a deliberate no-op on the title screen, and a visible
   button that does nothing on tap reads as broken rather than absent.
   #help-button is deliberately not part of that display:none rule below —
   it's meaningful on the title screen too, so it's always visible. */
#pause-button, #hint-button, #help-button {
  pointer-events: auto;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.7);
  font-family: 'Courier New', monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
  line-height: 1;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}
#pause-button, #hint-button {
  display: none;
}
#pause-button.visible, #hint-button.visible {
  display: block;
}
#pause-button, #help-button {
  border-radius: 50%;
  width: 30px;
  height: 30px;
}
/* HINT reads as a label, not a glyph, so it needs a pill wide enough for
   the word -- the shared circular sizing above was built for a single
   character (the old "?") and clipped "HINT" badly. */
#hint-button {
  border-radius: 15px;
  padding: 0 12px;
  height: 30px;
  font-weight: 700;
}
#pause-button:hover, #pause-button:active,
#hint-button:hover, #hint-button:active,
#help-button:hover, #help-button:active {
  background: rgba(255, 255, 255, 0.18);
  color: rgba(255, 255, 255, 0.95);
}

/* Live points for the line currently being drawn — counts up in real time
   while dragging, then clears the instant the connection lands (its value
   has folded into #score-display by then). Brighter/warmer than the
   settled score so it reads as "still earning this". */
#draw-score-display {
  font-size: 13px;
  color: rgba(255, 214, 120, 0.95);
  text-shadow: 0 0 10px rgba(255, 190, 80, 0.6);
  min-height: 16px;
  margin-bottom: 2px;
}

/* Pause menu — a simple centered modal. Freezes/mutes the game underneath
   (see pauseGame/resumeGame in game.js) while open. */
#pause-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.72);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  z-index: 30;
}
#pause-overlay.visible {
  opacity: 1;
  pointer-events: auto;
}

#pause-panel {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  width: min(86vw, 360px);
  padding: 28px 24px;
  background: rgba(12, 12, 18, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  box-shadow: 0 0 60px rgba(0, 0, 0, 0.6);
}

#pause-title {
  font-family: 'Courier New', monospace;
  font-size: 22px;
  font-weight: 300;
  letter-spacing: 0.3em;
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
  margin-bottom: 8px;
}

.pause-menu-item {
  font-family: 'Courier New', monospace;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 8px;
  padding: 12px 14px;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.pause-menu-item:hover, .pause-menu-item:active {
  background: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.3);
}
#pause-resume {
  background: rgba(120, 200, 255, 0.15);
  border-color: rgba(120, 200, 255, 0.4);
}

/* The rotating fact/tip — fades in and out on its own timer (see
   startPauseFactRotation), never touching the menu buttons above it. */
#pause-fact {
  margin-top: 14px;
  min-height: 4.5em;
  font-family: Georgia, 'Palatino Linotype', 'Times New Roman', serif;
  font-style: italic;
  font-size: 13.5px;
  line-height: 1.55;
  text-align: center;
  color: rgba(255, 255, 255, 0.6);
  opacity: 0;
  transition: opacity 1.2s ease;
}
#pause-fact.visible {
  opacity: 1;
}

#pause-save-toast {
  text-align: center;
  font-family: 'Courier New', monospace;
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(140, 255, 180, 0.85);
  min-height: 1.2em;
  opacity: 0;
  transition: opacity 0.3s ease;
}
#pause-save-toast.visible {
  opacity: 1;
}

/* How-to-play reference — reachable from the title screen (a curious new
   player) and mid-game alike (see #help-button not being in the
   TITLE-only display:none rule above). A plain informational overlay, not
   a second pause mechanism: its own opaque backdrop already blocks every
   pointer event from reaching the board underneath while it's open. */
#help-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.72);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  z-index: 30;
}
#help-overlay.visible {
  opacity: 1;
  pointer-events: auto;
}

#help-panel {
  position: relative;
  width: min(86vw, 420px);
  max-height: 80vh;
  overflow-y: auto;
  padding: 32px 26px 24px;
  background: rgba(12, 12, 18, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  box-shadow: 0 0 60px rgba(0, 0, 0, 0.6);
}

#help-title {
  font-family: 'Courier New', monospace;
  font-size: 20px;
  font-weight: 300;
  letter-spacing: 0.25em;
  text-align: center;
  color: rgba(255, 255, 255, 0.85);
  margin-bottom: 18px;
}

#help-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
  font-size: 14px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.75);
}
#help-list li {
  padding-left: 16px;
  position: relative;
}
#help-list li::before {
  content: '•';
  position: absolute;
  left: 0;
  color: rgba(140, 200, 255, 0.7);
}

#help-close {
  position: absolute;
  top: 12px;
  right: 14px;
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.6);
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
}
#help-close:hover, #help-close:active {
  color: rgba(255, 255, 255, 0.95);
}

#message-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  pointer-events: none;
  z-index: 20;
  opacity: 1;
  transition: opacity 0.8s ease;
}

#message-title {
  font-family: 'Courier New', monospace;
  font-size: 42px;
  font-weight: 300;
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.9);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-shadow: 0 0 30px rgba(255, 255, 255, 0.5);
  max-width: 90%;
  text-align: center;
}

/* This line is always a call to action ("tap to begin" / "tap to
   continue"), not decorative flavor text — testers reported missing it
   entirely at the old 14px/40%-opacity styling. Bumped up and given a slow
   pulse so it visibly reads as something to act on, not part of the
   background. The flex `gap` on #message-overlay (not margin-top here)
   keeps this clear of the title even when both wrap to multiple lines on
   narrow screens. */
#message-subtitle {
  font-family: 'Courier New', monospace;
  font-size: 18px;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.85);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-shadow: 0 0 16px rgba(255, 255, 255, 0.4);
  animation: subtitle-pulse 1.8s ease-in-out infinite;
  max-width: 85%;
  text-align: center;
}

@keyframes subtitle-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}

/* Only shown on the title screen (see showMessage's isTitleScreen option) —
   a lot of first-time players don't realize this is a music game and start
   with the device muted. Kept quiet/secondary so it never competes with
   the subtitle for attention. */
#sound-hint {
  display: none;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 0.1em;
  text-align: center;
  max-width: 85%;
}
#sound-hint.visible {
  display: block;
}

/* Title-screen-only difficulty picker (see showMessage's isTitleScreen
   option and setupDifficultySelectorListeners). Sits below the sound
   hint, quiet until interacted with — the active choice gets a soft
   highlight so it reads as a persistent setting, not a one-off prompt. */
#difficulty-selector {
  display: none;
  gap: 10px;
  margin-top: 8px;
  pointer-events: auto;
}
#difficulty-selector.visible {
  display: flex;
}
.difficulty-btn {
  font-family: 'Courier New', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 20px;
  padding: 7px 14px;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
.difficulty-btn:hover {
  background: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.8);
}
.difficulty-btn.active {
  background: rgba(120, 200, 255, 0.18);
  border-color: rgba(120, 200, 255, 0.55);
  color: rgba(255, 255, 255, 0.95);
}

/* Title-screen-only load row (see showMessage's isTitleScreen option and
   setupTitleLoadListeners). "Load Game" only appears once there's
   actually a save to load (see refreshTitleLoadRow) -- a visible button
   that does nothing on tap reads as broken rather than absent. */
#title-load-row {
  display: none;
  align-items: center;
  gap: 14px;
  margin-top: 4px;
  pointer-events: auto;
}
#title-load-row.visible {
  display: flex;
}
#title-load-button {
  display: none;
  font-family: 'Courier New', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 20px;
  padding: 7px 14px;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
#title-load-button.visible {
  display: block;
}
#title-load-button:hover {
  background: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.8);
}
#autoload-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: 'Courier New', monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  cursor: pointer;
}
#autoload-label input[type="checkbox"] {
  width: 14px;
  height: 14px;
  cursor: pointer;
  accent-color: rgba(120, 200, 255, 0.85);
}

#version-display {
  position: fixed;
  bottom: 10px;
  left: 14px;
  font-family: 'Courier New', monospace;
  font-size: 20px;
  color: #ffffff;
  letter-spacing: 0.1em;
  pointer-events: none;
  z-index: 10;
}

/* Tutorial hint — a quiet line of text centered on screen for the first
   five waves only. Fades in on wave start, stays put until the player
   does what it describes, then fades out for good. Kept pointer-events:none
   so it never blocks a drag; game.js reflows its line breaks at render
   time (see layoutTutorialHint) so its box never sits on top of a dot. */
#tutorial-hint {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 82%;
  max-width: 640px;
  text-align: center;
  font-family: Georgia, 'Palatino Linotype', 'Times New Roman', serif;
  font-style: italic;
  font-weight: 400;
  font-size: 30px;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.7);
  letter-spacing: 0.02em;
  text-shadow: 0 0 24px rgba(255, 255, 255, 0.25);
  opacity: 0;
  transition: opacity 1.4s ease;
  pointer-events: none;
  z-index: 10;
}

/* Achievement toast — a solid white card that drops down from off-screen
   above the center-top, sits there for game.js's ACHIEVEMENT_VISIBLE_MS,
   then retracts back up. It's meant to read as a physical object laying
   on top of the game UI, not a blend-in HUD element, so it no longer
   dodges dots the way the (translucent, glow-text) toast used to — it's
   opaque and always dead-center now. The base rule's transition (used
   when .visible is removed, i.e. retracting) is deliberately a snappier
   ease-in than .visible's own transition (used when dropping in), so the
   two motions don't feel identical played in reverse.  */
#achievement-toast {
  position: fixed;
  top: 18px;
  left: 50%;
  transform: translate(-50%, -220%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 22px 30px 20px;
  max-width: min(78vw, 300px);
  background: linear-gradient(165deg, #ffffff 0%, #f1f1f5 100%);
  border-radius: 20px;
  border: 1px solid rgba(0, 0, 0, 0.05);
  box-shadow:
    0 22px 40px -8px rgba(0, 0, 0, 0.5),
    0 2px 0 rgba(255, 255, 255, 0.9) inset,
    0 -3px 8px rgba(0, 0, 0, 0.06) inset;
  transition: transform 0.4s cubic-bezier(0.55, 0, 0.85, 0.35);
  pointer-events: none;
  z-index: 15;
}

#achievement-toast.visible {
  transform: translate(-50%, 0);
  transition: transform 0.65s cubic-bezier(0.34, 1.56, 0.64, 1);
}

#achievement-badge {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  box-shadow:
    0 10px 16px -4px rgba(0, 0, 0, 0.4),
    0 0 26px 3px var(--badge-glow, rgba(255, 215, 0, 0.55)),
    inset 0 0 12px rgba(255, 255, 255, 0.45);
  background: var(--badge-bg, radial-gradient(circle at 35% 30%, #ffe9a8, #d4a017));
  animation: achievement-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

#achievement-label {
  font-family: Georgia, 'Palatino Linotype', 'Times New Roman', serif;
  font-weight: 700;
  font-style: italic;
  font-size: 19px;
  text-align: center;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #2c2c34;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7), 0 -1px 0 rgba(0, 0, 0, 0.1);
}

@keyframes achievement-pop {
  0%   { transform: scale(0.4); opacity: 0; }
  60%  { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* Connection praise: a small "crowd reaction" popup anchored to a dot's
   world position (see updateConnectionPraise in game.js, which repositions
   left/top every frame via worldToScreen so it tracks pan/zoom) but with a
   fixed font-size here -- it must read the same size at any zoom level,
   never scaled with the camera. The reveal is a clip-path sweep rather
   than an actual position change or scale transform, so it reads as the
   box "unfurling" in place -- like a flag unrolling -- without ever
   distorting the text; closing plays the same transition in reverse by
   simply removing the class that opened it. */
#connection-praise-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 16;
}
.connection-praise {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(255, 255, 255, 0.97);
  color: #16161f;
  padding: 8px 14px;
  border-radius: 10px;
  font-family: Georgia, 'Palatino Linotype', 'Times New Roman', serif;
  font-weight: 700;
  font-size: 15px;
  white-space: nowrap;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
  clip-path: inset(0 100% 0 0); /* fully hidden, revealing left-to-right when opened */
  transition: clip-path 260ms ease-out;
}
.connection-praise.praise-flip {
  clip-path: inset(0 0 0 100%); /* mirrored: fully hidden, reveals right-to-left */
}
.connection-praise.open {
  clip-path: inset(0 0 0 0); /* fully revealed -- removing .open plays this transition backward */
}
.connection-praise-emoji {
  font-size: 1.15em;
  line-height: 1;
}
/* Tier 0 (the common case, unstyled beyond the base above) is deliberately
   the plainest -- tiers 1 and 2 escalate size and add a colored glow, the
   same "crowd gets more excited" progression the achievement/riff side
   also follows (see CONNECTION_PRAISE_CONFIG in game.js). */
.connection-praise.praise-tier-1 {
  font-size: 17px;
  border: 2px solid #ffd700;
  box-shadow: 0 4px 20px rgba(255, 215, 0, 0.5), 0 4px 18px rgba(0, 0, 0, 0.35);
}
.connection-praise.praise-tier-2 {
  font-size: 20px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  border: 2px solid #ff5e57;
  box-shadow: 0 4px 26px rgba(255, 94, 87, 0.6), 0 4px 18px rgba(0, 0, 0, 0.4);
}
