/* ---------- Retro pixel-art theme ---------- */
:root {
  --bg:        #1a1030;
  --bg2:       #2a1a4a;
  --ink:       #fff4d6;
  --shadow:    #0d0820;
  --masa:      #f2c14e;   /* tortilla yellow */
  --masa-dk:   #c98f2b;
  --salsa:     #e63946;   /* red */
  --lime:      #7bd651;   /* green */
  --lime-dk:   #4a9e2f;
  --sky:       #4cc9f0;
  --purple:    #b15cff;
  --panel:     #241640;
  --border:    #0d0820;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  /* 100vh, not 100%: a percentage resolves against html's auto height, so on a short page
     the body gradient stopped at the content and the base colour showed through below it —
     very visible on a challenge, where the two gradients differ. */
  min-height: 100vh;
  background:
    repeating-linear-gradient(0deg, transparent 0 3px, rgba(0,0,0,.05) 3px 4px),
    linear-gradient(160deg, var(--bg), var(--bg2));
  color: var(--ink);
  font-family: 'VT323', monospace;
  font-size: 20px;
  letter-spacing: .5px;
  image-rendering: pixelated;
  transition: background .6s;
}

/* Challenge background — warm fiery gradient that slowly pans through its tones so the sky
   feels alive behind the flying tacos. The gradient is drawn 280% tall and its position drifts
   top↔bottom; the scanline layer (first in the list) stays put at 0 0. */
body.challenge-bg {
  background:
    repeating-linear-gradient(0deg, transparent 0 3px, rgba(0,0,0,.06) 3px 4px),
    linear-gradient(160deg, #1a0808, #3d1510, #4a1a0a, #2a0a20, #1a0818, #1a0808) !important;
  background-size: auto, 100% 280% !important;
  animation: sky-drift 48s ease-in-out infinite;
}
@keyframes sky-drift {
  0%, 100% { background-position: 0 0, 50% 0%; }
  50%      { background-position: 0 0, 50% 100%; }
}
@media (prefers-reduced-motion: reduce) { body.challenge-bg { animation: none; } }

/* ---------- Cosmos: parallax star + confetti field behind the challenge tacos ----------
   Injected as the sprite field's first child (see sprites.js spawnCosmos), so it paints behind
   the flying tacos and the #app panels. Three tiled dot layers drifting at different speeds give
   depth; the two star layers twinkle, the confetti layer slowly falls. */
.ch-cosmos { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.cos { position: absolute; inset: -12%; background-repeat: repeat; }

/* Far stars — faint, small, slowest drift. */
.cos-far {
  opacity: .5;
  background-image:
    radial-gradient(1px 1px at 30px 40px,   rgba(255,244,214,.7), transparent),
    radial-gradient(1px 1px at 120px 90px,  rgba(255,244,214,.6), transparent),
    radial-gradient(1.5px 1.5px at 180px 30px, rgba(255,244,214,.7), transparent),
    radial-gradient(1px 1px at 70px 160px,  rgba(255,244,214,.5), transparent),
    radial-gradient(1px 1px at 205px 190px, rgba(255,244,214,.6), transparent);
  background-size: 220px 220px;
  animation: cos-far 120s linear infinite, cos-twinkle-far 7s ease-in-out infinite;
}
/* Mid stars — brighter, larger, quicker drift (nearer = faster parallax). */
.cos-mid {
  opacity: .7;
  background-image:
    radial-gradient(2px 2px at 40px 30px,    #fff, transparent),
    radial-gradient(1.5px 1.5px at 110px 120px, rgba(255,255,255,.85), transparent),
    radial-gradient(2px 2px at 140px 60px,   #fff, transparent),
    radial-gradient(1.5px 1.5px at 20px 130px,  rgba(255,255,255,.8), transparent);
  background-size: 160px 160px;
  animation: cos-mid 70s linear infinite, cos-twinkle-mid 4.5s ease-in-out infinite;
}
/* Confetti — the fiesta palette, sifting gently downward past the stars. */
.cos-confetti {
  opacity: .7;
  background-image:
    radial-gradient(3px 3px at 50px 20px,    var(--masa), transparent),
    radial-gradient(2.5px 2.5px at 150px 80px, var(--lime), transparent),
    radial-gradient(3px 3px at 90px 140px,   var(--salsa), transparent),
    radial-gradient(2.5px 2.5px at 20px 100px, var(--sky), transparent),
    radial-gradient(2.5px 2.5px at 170px 165px, var(--purple), transparent);
  background-size: 190px 190px;
  animation: cos-confetti 45s linear infinite;
}
@keyframes cos-far      { from { background-position: 0 0; }      to { background-position: 220px -220px; } }
@keyframes cos-mid      { from { background-position: 0 0; }      to { background-position: -160px 160px; } }
@keyframes cos-confetti { from { background-position: 0 -190px; } to { background-position: 0 190px; } }
@keyframes cos-twinkle-far { 0%, 100% { opacity: .5; } 50% { opacity: .25; } }
@keyframes cos-twinkle-mid { 0%, 100% { opacity: .7; } 50% { opacity: .4; } }
@media (prefers-reduced-motion: reduce) {
  .cos-far, .cos-mid, .cos-confetti { animation: none; }
}

h1, h2, h3, .pixel { font-family: 'Press Start 2P', monospace; letter-spacing: 0; line-height: 1.5; }
h1 { font-size: 20px; }
h2 { font-size: 15px; }
h3 { font-size: 11px; }

button, input, textarea, select {
  font-family: 'VT323', monospace;
  font-size: 20px;
}

a { color: var(--sky); }

/* ---------- Sprite field (background taco parade) ---------- */
#sprite-field {
  position: fixed; inset: 0;
  overflow: hidden; pointer-events: none;
  z-index: 0;
}
.sprite {
  position: absolute;
  width: 44px; height: 44px;
  image-rendering: pixelated;
  will-change: transform;
  opacity: .9;
}

/* The truck: parked bottom-right on every page except a challenge, engine idling.
   Off to the side rather than centred — the content panels are centred, and a truck behind
   them is a truck you can't see. Faint enough to read past; it's scenery, not a component. */
.truck {
  position: absolute;
  right: 2vw;
  bottom: 2vh;
  width: 210px;                 /* JS overrides this to min(34vw,220px) so queue geometry lines up */
  height: auto;
  image-rendering: pixelated;
  opacity: .62;
  animation: idle 1.7s steps(2, end) infinite;
}

/* The customers milling about the truck. Positioned bottom-anchored by the sprite field;
   a touch more present than the truck so the movement reads, but still scenery. */
.actor {
  position: absolute; top: 0; left: 0;
  image-rendering: pixelated;
  opacity: .5;
  will-change: transform;
}

/* Papel picado banner across the top of the truck scene, swaying in the breeze. */
.papel {
  position: absolute; top: 0; left: 0; width: 100%; height: 44px;
  image-rendering: pixelated; opacity: .6;
  transform-origin: top center;
  animation: sway 5s ease-in-out infinite;
}
@keyframes sway {
  0%, 100% { transform: translateY(0) rotate(-0.4deg); }
  50%      { transform: translateY(3px) rotate(0.4deg); }
}
@media (prefers-reduced-motion: reduce) { .papel { animation: none; } }
/* steps(), not a smooth ease — sub-pixel drift would blur the pixel art and undo the whole
   look. The truck judders on whole pixels, like the sprite it is. */
@keyframes idle {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
  .truck { animation: none; }
}
/* Warm headlight / window glow, placed by JS over the truck at night. */
.truck-glow {
  position: absolute; border-radius: 50%; pointer-events: none;
  transform: translate(-50%, -50%); mix-blend-mode: screen;
  background: radial-gradient(circle, rgba(255,226,150,.85), rgba(255,200,120,.3) 45%, transparent 70%);
  animation: headlight 3.5s ease-in-out infinite;
}
@keyframes headlight { 0%, 100% { opacity: .7; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .truck-glow { animation: none; } }

/* ---------- Beach scene (live Mexico-City time of day, behind the truck) ----------
   Colours, the sun/moon disc and its position, star opacity and the sea veil are all driven by
   CSS custom properties that sprites.js sets from the current hour. Waves roll toward the viewer.
   The whole layer is half-opacity over the dark page so it reads as atmosphere and never fights
   the text in the gaps between panels. Bands are placed by % so it stays responsive. */
.beach-layer { position: absolute; inset: 0; overflow: hidden; opacity: .5; }

/* sky graded from its zenith colour down to the horizon colour */
.beach-sky {
  position: absolute; left: 0; right: 0; top: 0; height: 56%;
  background: linear-gradient(180deg, var(--sky-top, #14143a), var(--sky-hor, #5a3a6a) 92%);
}
/* stars, faded in by --star-a at night */
.stars {
  position: absolute; left: 0; right: 0; top: 0; height: 44%;
  background-repeat: repeat; opacity: var(--star-a, 0);
}
/* the soft halo around the sun/moon, and the crisp disc itself, placed at --orb-x / --orb-y */
.beach-sun {
  position: absolute; width: 58vw; height: 42vh;
  left: var(--orb-x, 50%); top: var(--orb-y, 30%); transform: translate(-50%, -50%);
  background: radial-gradient(ellipse at center, var(--glow, #ff8c5a), transparent 66%);
  opacity: var(--glow-a, .5);
}
.beach-orb {
  position: absolute; width: 34px; height: 34px; border-radius: 50%;
  left: var(--orb-x, 50%); top: var(--orb-y, 30%); transform: translate(-50%, -50%);
  background: var(--orb, #ffcaa0); box-shadow: 0 0 16px 5px var(--glow, #ff8c5a);
}
/* the sun/moon reflection shimmering straight down the water beneath the orb */
.beach-glitter {
  position: absolute; width: 52px; height: 22%;
  left: var(--orb-x, 50%); top: 37%; transform: translateX(-50%);
  filter: blur(1px); mix-blend-mode: screen;
  background: linear-gradient(180deg, var(--glow, #ffd696), transparent);
  opacity: var(--glow-a, .5); animation: glint 4s ease-in-out infinite;
}
@keyframes glint { 0%, 100% { filter: blur(1px) brightness(.8); } 50% { filter: blur(1px) brightness(1.15); } }
/* the sea, a tall band on the horizon, plus a time-of-day veil to key the water colour */
.beach-sea {
  position: absolute; left: 0; right: 0; top: 36%; height: 20%;
  background: linear-gradient(180deg, var(--sea-top, #123049), var(--sea-bot, #1d4a63));
}
.beach-veil {
  position: absolute; left: 0; right: 0; top: 36%; height: 22%;
  background: var(--veil, #141640); opacity: var(--veil-a, 0);
}
/* waves ROLL TOWARD the viewer: each band rises at the horizon, advances down the beach growing
   taller, then dissolves into the surf. Four bands staggered in phase read as continuous rollers.
   Tile images are pixel wave crests generated in sprites.js and set inline. */
.beach-wave {
  position: absolute; left: 0; right: 0; top: 37%; height: 26px;
  background-repeat: repeat-x; transform-origin: center top; will-change: transform, opacity;
  animation: rollIn var(--dur, 8s) linear infinite;
}
@keyframes rollIn {
  0%   { transform: translateY(0)    scaleY(.55); opacity: 0; }
  18%  { opacity: .85; }
  82%  { opacity: .8; }
  100% { transform: translateY(19vh) scaleY(1.3); opacity: 0; }
}
.wave-1 { --dur: 6.5s; animation-delay: 0s;    background-size: 96px 22px; }
.wave-2 { --dur: 7.6s; animation-delay: -1.9s; background-size: 116px 24px; }
.wave-3 { --dur: 8.7s; animation-delay: -3.8s; background-size: 138px 26px; }
.wave-4 { --dur: 9.8s; animation-delay: -5.7s; background-size: 160px 28px; }
/* surf line where the sea washes up the sand, swelling in and out */
.beach-foam {
  position: absolute; left: 0; right: 0; top: 55%; height: 3%;
  background: linear-gradient(180deg, rgba(255,255,255,.6), transparent);
  animation: surf 5s ease-in-out infinite;
}
@keyframes surf {
  0%, 100% { transform: translateY(0);   opacity: .55; }
  50%      { transform: translateY(7px); opacity: .9; }
}
/* dry sand the truck and its diners sit on, with a darker moist strip nearest the water */
.beach-sand {
  position: absolute; left: 0; right: 0; top: 56%; bottom: 0;
  background: linear-gradient(180deg, #c79a5e, #a9793f 45%, #8a5f30);
}
.beach-wetsand {
  position: absolute; left: 0; right: 0; top: 56%; height: 5%;
  background: linear-gradient(180deg, #6f4f2c, #9a7038); opacity: .85;
}
/* sailboats out on the water, drifting shore-parallel with a faint bob */
.ship { position: absolute; left: 0; image-rendering: pixelated; opacity: .5; animation: sail linear infinite; }
.ship-1 { top: 39%;   width: 52px; animation-duration: 95s; }
.ship-2 { top: 41.5%; width: 38px; opacity: .4; animation-duration: 135s; animation-delay: -45s; }
@keyframes sail {
  0%   { transform: translate(-8vw, 0); }
  25%  { transform: translate(22vw, -2px); }
  50%  { transform: translate(52vw, 0); }
  75%  { transform: translate(82vw, -2px); }
  100% { transform: translate(114vw, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .beach-wave, .beach-foam, .beach-glitter, .ship { animation: none; }
}

/* seagulls drifting across the sky, and static beach props (towels, umbrella, ball) on the sand */
.bird { position: absolute; top: 0; left: 0; image-rendering: pixelated; opacity: .55; }
.prop { position: absolute; top: 0; left: 0; image-rendering: pixelated; opacity: .62; }

/* On a phone the truck would sit under the form. Tuck it into the corner instead. */
@media (max-width: 640px) {
  .ship { display: none; }
  .truck { right: 1vw; bottom: 1vh; opacity: .5; }
}

/* ---------- Layout ---------- */
#app { position: relative; z-index: 1; max-width: 860px; margin: 0 auto; padding: 16px 16px 80px; }

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 18px; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 12px; cursor: pointer; }
.brand h1 { margin: 0; color: var(--masa); text-shadow: 3px 3px 0 var(--salsa), 6px 6px 0 var(--shadow); }
.brand .logo { width: 40px; height: 40px; }

.nav { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }

/* ---------- Avatar ---------- */
.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  border: 2px solid var(--border); box-shadow: 2px 2px 0 var(--shadow);
  font-family: 'Press Start 2P', monospace; color: #10240a;
  flex-shrink: 0;
}
.profile-link {
  gap: 6px; padding: 4px 8px;
}
.profile-name {
  font-family: 'VT323', monospace; font-size: 16px;
  max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- Color picker ---------- */
.color-picker { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.swatch {
  width: 36px; height: 36px; border: 3px solid var(--border); cursor: pointer;
  box-shadow: 2px 2px 0 var(--shadow); transition: transform .05s;
}
.swatch:hover { transform: translate(-1px,-1px); }
.swatch.active { border-color: var(--ink); box-shadow: 0 0 0 2px var(--ink), 3px 3px 0 var(--shadow); }

/* ---------- Pixel panels & buttons ---------- */
.panel {
  background: var(--panel);
  border: 4px solid var(--border);
  box-shadow: 6px 6px 0 var(--shadow);
  padding: 16px;
  margin-bottom: 16px;
}
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--lime); color: #10240a;
  border: 3px solid var(--border);
  box-shadow: 4px 4px 0 var(--shadow);
  padding: 8px 14px; cursor: pointer;
  font-family: 'Press Start 2P', monospace; font-size: 10px;
  text-transform: uppercase; text-decoration: none;
  transition: transform .05s, box-shadow .05s;
}
.btn:hover { transform: translate(-1px,-1px); box-shadow: 5px 5px 0 var(--shadow); }
.btn:active { transform: translate(2px,2px); box-shadow: 1px 1px 0 var(--shadow); }
.btn.alt   { background: var(--sky); }
.btn.warn  { background: var(--salsa); color: var(--ink); }
.btn.ghost { background: transparent; color: var(--ink); box-shadow: none; }
.btn.small { font-size: 8px; padding: 6px 10px; }
.btn:disabled { filter: grayscale(.6) brightness(.7); cursor: not-allowed; }

label { display: block; margin: 12px 0 4px; color: var(--masa); font-size: 18px; }
input, textarea, select {
  width: 100%; background: #14092c; color: var(--ink);
  border: 3px solid var(--border); padding: 8px 10px; outline: none;
}
input:focus, textarea:focus, select:focus { border-color: var(--masa); }
textarea { resize: vertical; min-height: 64px; }
input.picked { border-color: var(--lime); }

/* place typeahead */
/* Honeypot. Off-screen rather than display:none — the naive form-filling bots this is
   meant to catch skip hidden fields, but happily fill one they can "see". */
.hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  opacity: 0; pointer-events: none;
}

.hits:empty { display: none; }
.hits {
  max-height: 220px; overflow-y: auto;
  border: 3px solid var(--border); border-top: none; background: #14092c;
}
.hit { padding: 8px 10px; cursor: pointer; border-bottom: 2px solid var(--bg2); }
.hit:last-child { border-bottom: none; }
.hit:hover { background: var(--bg2); }
.hit-name { color: var(--ink); font-size: 18px; }
.hit-addr { color: #9d8fc0; font-size: 15px; }

.row { display: flex; gap: 12px; flex-wrap: wrap; }
.row > * { flex: 1; min-width: 120px; }
.muted { opacity: .7; }
.center { text-align: center; }
.pill {
  display: inline-block; background: var(--purple); color: #fff;
  border: 2px solid var(--border); padding: 2px 8px; font-size: 16px;
}

/* ---------- Grids ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px,1fr)); gap: 16px; }

.card {
  background: var(--panel); border: 4px solid var(--border);
  box-shadow: 5px 5px 0 var(--shadow); cursor: pointer;
  transition: transform .05s;
}
.card:hover { transform: translate(-2px,-2px); }
.card .thumb {
  height: 130px; background: #10061f center/contain no-repeat;
  border-bottom: 4px solid var(--border);
  display: flex; align-items: center; justify-content: center;
}
.card .thumb .noimg { font-size: 46px; }
.card .body { padding: 10px 12px; }
.card .body .title { font-family: 'Press Start 2P', monospace; font-size: 10px; color: var(--masa); }

.badge { font-size: 15px; color: var(--lime); }

/* photo strip */
.photos { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.photos img { width: 84px; height: 84px; object-fit: cover; border: 3px solid var(--border); }

/* photo upload */
.photo-upload-area { margin-top: 4px; }
.photo-btn { margin-bottom: 8px; }
#photo-preview, #ch-photo-preview { margin-top: 0; }
#photo-preview img, #ch-photo-preview img { width: 60px; height: 60px; }

.taco-row {
  border: 3px solid var(--border); background: #1c1038;
  padding: 10px 12px; margin-bottom: 10px;
}
.taco-row .head { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }

/* link preview */
.preview {
  display: flex; gap: 12px; align-items: center;
  border: 3px dashed var(--masa-dk); padding: 8px; margin-top: 10px; background:#180d33;
  text-decoration: none;
}
.preview img { width: 64px; height: 64px; object-fit: cover; border: 2px solid var(--border); }
.preview-rich { flex-direction: column; align-items: flex-start; }
.preview-rich img { width: 100%; max-width: 280px; height: auto; max-height: 200px; }

/* ---------- Challenge progress ---------- */
.progress-wrap { margin: 8px 0; }
.progress {
  height: 26px; background: #10061f; border: 3px solid var(--border); position: relative; overflow: hidden;
}
.progress .fill {
  height: 100%; background: repeating-linear-gradient(45deg, var(--masa) 0 10px, var(--masa-dk) 10px 20px);
  transition: width .4s steps(12);
}
.progress .label {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: 'Press Start 2P', monospace; font-size: 9px; color: #10240a; text-shadow: 1px 1px 0 #fff8;
}
.leader { display: flex; align-items: center; gap: 10px; margin: 6px 0; }
.leader .rank { width: 22px; font-family:'Press Start 2P'; font-size: 10px; color: var(--masa); }

/* challenge hero */
.challenge-hero {
  border: 4px solid var(--border); box-shadow: 6px 6px 0 var(--shadow);
  background: linear-gradient(180deg, #3a1510, #1a0808);
  padding: 18px; margin-bottom: 16px; position: relative; overflow: hidden;
}
.challenge-totals {
  display: flex; justify-content: center; gap: 30px; margin: 12px 0;
}

/* ---------- Hero progress: one big taco, eaten toward the goal ---------- */
.eaten-meter { text-align: center; padding: 4px 0 2px; }
.big-taco {
  width: 168px; height: 168px; max-width: 62vw;
  image-rendering: pixelated;
  filter: drop-shadow(4px 4px 0 var(--shadow));
}
.eaten-label {
  font-family: 'Press Start 2P', monospace; font-size: 11px; color: var(--masa);
  text-shadow: 2px 2px 0 var(--shadow); margin-top: 2px;
}

/* Slim per-row progress, for cards and the leaderboard (was a row of taco sprites). */
.mini-bar {
  height: 10px; margin-top: 6px; background: #10061f;
  border: 2px solid var(--border); overflow: hidden;
}
.mini-fill {
  height: 100%; width: 0;
  background: repeating-linear-gradient(45deg, var(--masa) 0 6px, var(--masa-dk) 6px 12px);
  transition: width .4s steps(10);
}

/* invite link box */
.invite-link-box {
  display: flex; align-items: center; gap: 8px;
  background: #14092c; border: 2px solid var(--border); padding: 6px 10px;
  margin: 4px 0; cursor: pointer; overflow: hidden;
}
.invite-link-box:hover { border-color: var(--masa); }
.invite-url {
  flex: 1; font-size: 14px; color: var(--sky);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* city filter tabs */
.city-tabs {
  display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px;
}

/* ---- failed: a challenge (or a racer) that can't get there any more ---- */
.pill-failed { background: var(--salsa); color: #fff4d6; }
.card.failed, .challenge-hero.failed { border-color: var(--salsa); }
/* Drained of colour, but still legible — a failed run is history, not a mistake. */
.card.failed .body, .leader.failed { opacity: .6; filter: grayscale(.6); }
.leader.failed .taco-meter { filter: grayscale(1); }

/* ---- map pins, tiered by how many tacos you've eaten at a spot ---- */
.taco-pin, .taco-cluster {
  display: flex; align-items: center; justify-content: center; position: relative;
}
.taco-pin img, .taco-cluster img {
  width: 100%; height: 100%; image-rendering: pixelated;
}
/* challenge map: a small corner dot in the first-arriver's colour, instead of a disc */
.taco-pin .pin-owner {
  position: absolute; right: 0; bottom: 1px; width: 10px; height: 10px;
  border-radius: 50%; border: 2px solid #1a1030; box-sizing: border-box;
}
/* the top two tiers earn a glow, so a shrine is findable at a glance */
.taco-pin.tier-4 { filter: drop-shadow(0 0 4px #fff6e5); }
.taco-pin.tier-5 { filter: drop-shadow(0 0 6px #ffd700); }

/* cluster badge: the merged tacos' tier, with a count of the spots inside */
.taco-cluster { position: relative; width: 46px; height: 46px; }
.taco-cluster img { width: 46px; height: 46px; }
.taco-cluster b {
  position: absolute; right: -2px; bottom: -2px;
  min-width: 20px; padding: 1px 3px;
  font-family: 'Press Start 2P'; font-size: 9px; line-height: 1.3; text-align: center;
  color: #10240a; background: var(--masa);
  border: 2px solid var(--shadow); border-radius: 2px;
}
.taco-cluster.tier-5 b { background: #ffd700; }

/* tier name, in popups */
.tier-label {
  font-family: 'Press Start 2P'; font-size: 8px;
  padding: 2px 4px; border-radius: 2px; color: #10240a; background: var(--masa);
}
.tier-label.tier-4 { background: #fff6e5; }
.tier-label.tier-5 { background: #ffd700; }

/* tier key under the map */
.tier-key { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.tier-key-item {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 8px; min-width: 74px;
  border: 2px solid var(--border); background: rgba(0,0,0,.25);
  opacity: .45; filter: grayscale(1);
}
.tier-key-item.earned { opacity: 1; filter: none; }
.tier-key-item img { width: 34px; height: 34px; image-rendering: pixelated; }
.tier-key-item b { font-size: 14px; color: var(--masa); }
.tier-key-item span { font-size: 12px; }

/* share section */
.share-section {
  margin-top: 12px; padding-top: 12px;
  border-top: 2px dashed rgba(255,255,255,.15);
}
.share-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.link-mode-select {
  width: auto; background: #14092c; font-size: 16px;
  padding: 4px 8px; border: 2px solid var(--border);
}

/* ---------- Modal ---------- */
#modal-overlay {
  position: fixed; inset: 0; z-index: 40;
  background: #0a0518cc;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.modal-content {
  max-width: 460px; width: 100%; max-height: 90vh; overflow: auto;
}

/* ---------- Toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(80px);
  background: var(--lime); color: #10240a; border: 3px solid var(--border);
  box-shadow: 4px 4px 0 var(--shadow); padding: 10px 16px; z-index: 50;
  font-family: 'Press Start 2P', monospace; font-size: 10px;
  transition: transform .25s; max-width: 90vw;
  line-height: 1.6;                       /* error copy runs to two or three lines */
}
.toast.error { background: var(--salsa); color: #fff; }
.toast.show { transform: translateX(-50%) translateY(0); }

/* ---------- Auth screen ---------- */
.auth { max-width: 380px; margin: 8vh auto 0; }
.tabs { display: flex; gap: 8px; margin-bottom: 12px; }
.tabs .btn { flex: 1; justify-content: center; }

.stat-num { font-family: 'Press Start 2P', monospace; font-size: 22px; color: var(--masa); }

.empty { text-align: center; padding: 30px 10px; }
.empty .big { font-size: 60px; }

/* ---------- Profile hero ---------- */
.profile-hero {
  display: flex; align-items: center; gap: 16px;
  background: linear-gradient(180deg, #33205c, #1d1138);
  border: 4px solid var(--border); box-shadow: 6px 6px 0 var(--shadow);
  padding: 18px; margin-bottom: 16px;
}
.profile-hero-text { min-width: 0; }
.profile-hero h2 { margin: 0 0 6px; color: var(--masa); word-break: break-word; }
.hero-title {
  font-family: 'Press Start 2P', monospace; font-size: 10px;
  color: var(--lime); margin-bottom: 6px;
}
.hero-title .muted { font-family: 'VT323', monospace; font-size: 16px; color: var(--ink); }

/* title shown under a name on challenge leaderboards */
.member-title { font-size: 15px; color: var(--masa); opacity: .85; }

/* ---------- Achievements ---------- */
.ach-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px,1fr)); gap: 12px; }
.ach {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--panel); border: 4px solid var(--border);
  box-shadow: 5px 5px 0 var(--shadow); padding: 12px;
}
.ach.locked { filter: grayscale(.7); opacity: .6; }
.ach.earned.tier-bronze { border-color: var(--masa-dk); }
.ach.earned.tier-silver { border-color: #c9d1d9; }
.ach.earned.tier-gold   { border-color: var(--masa); }
.ach.earned.tier-legend { border-color: var(--purple); box-shadow: 5px 5px 0 var(--shadow), 0 0 12px #b15cff88; }
.ach-emoji { font-size: 32px; line-height: 1; flex-shrink: 0; }
.ach-body { flex: 1; min-width: 0; }
.ach-name { font-family: 'Press Start 2P', monospace; font-size: 10px; color: var(--masa); margin-bottom: 5px; }
.ach-desc { font-size: 16px; line-height: 1.3; }
.ach-title-line { font-size: 15px; color: var(--lime); margin-top: 5px; }
.ach-earned { font-size: 14px; color: var(--sky); margin-top: 5px; }
.ach-progress { height: 18px; margin-top: 6px; }
.ach-progress .label { font-size: 8px; }

/* ---------- Achievement unlock celebration ---------- */
.unlock-banner {
  font-family: 'Press Start 2P', monospace; font-size: 11px; color: var(--masa);
  text-shadow: 2px 2px 0 var(--salsa); margin-bottom: 14px; line-height: 1.6;
}
.unlock-card {
  border: 4px solid var(--masa); background: #1c1038;
  box-shadow: 4px 4px 0 var(--shadow);
  padding: 14px; margin-bottom: 10px;
}
.unlock-card.tier-legend { border-color: var(--purple); box-shadow: 4px 4px 0 var(--shadow), 0 0 16px #b15cff88; }
.unlock-emoji { font-size: 44px; line-height: 1.2; }
.unlock-name { font-family: 'Press Start 2P', monospace; font-size: 12px; color: var(--masa); margin: 6px 0; }
.unlock-title { font-family: 'Press Start 2P', monospace; font-size: 9px; color: var(--lime); margin-top: 10px; line-height: 1.6; }

/* ---------- Leaflet map overrides ---------- */
#map-container { background: #10061f; }
#map-container .leaflet-popup-content-wrapper {
  background: var(--panel); color: var(--ink); border: 3px solid var(--border);
  box-shadow: 4px 4px 0 var(--shadow); border-radius: 0;
  font-family: 'VT323', monospace; font-size: 18px;
}
#map-container .leaflet-popup-tip { background: var(--panel); }

/* ---------- Live update flash ---------- */
@keyframes flash-update {
  0% { background: var(--lime); } 100% { background: transparent; }
}
.leader.updated { animation: flash-update .8s ease-out; }

/* ---------- Mobile responsive ---------- */
@media (max-width: 560px) {
  body { font-size: 18px; }
  h1 { font-size: 14px; }
  h2 { font-size: 12px; }
  h3 { font-size: 10px; }

  #app { padding: 10px 10px 60px; }

  .topbar { gap: 8px; margin-bottom: 12px; }
  .brand h1 { font-size: 12px; text-shadow: 2px 2px 0 var(--salsa), 4px 4px 0 var(--shadow); }
  .brand .logo { width: 30px; height: 30px; }

  .nav { gap: 4px; }
  .btn { font-size: 9px; padding: 6px 10px; }
  .btn.small { font-size: 7px; padding: 5px 8px; }
  .profile-name { display: none; } /* hide username on mobile, show avatar only */

  .panel { padding: 12px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(160px,1fr)); gap: 10px; }
  .card .thumb { height: 100px; }
  .card .body .title { font-size: 8px; }

  .stat-num { font-size: 16px; }
  .stats-row { gap: 8px; }

  .modal-content { max-height: 95vh; }
  #modal-overlay { padding: 8px; align-items: flex-start; padding-top: 5vh; }

  label { font-size: 16px; margin: 8px 0 3px; }
  input, textarea, select { font-size: 18px; padding: 8px; }

  .photos img { width: 64px; height: 64px; }
  #photo-preview img { width: 50px; height: 50px; }

  .preview { flex-direction: column; align-items: flex-start; gap: 8px; }

  .progress .label { font-size: 7px; }
  .leader { gap: 6px; }
  .leader .rank { font-size: 9px; }

  .challenge-hero { padding: 14px; }
  .challenge-totals { gap: 16px; }

  .share-row { gap: 6px; }
  .toast { font-size: 8px; padding: 8px 12px; bottom: 12px; }

  .taco-meter.large .taco-slot { width: 22px; height: 22px; }
  .taco-meter.small .taco-slot { width: 12px; height: 12px; }
  .taco-meter { gap: 2px; }

  .invite-link-box { padding: 4px 8px; }
  .invite-url { font-size: 12px; }
  .city-tabs { gap: 4px; }

  .profile-hero { padding: 14px; gap: 12px; }
  .hero-title { font-size: 8px; }
  .ach-grid { grid-template-columns: 1fr; gap: 10px; }
  .ach { padding: 10px; gap: 10px; }
  .ach-emoji { font-size: 26px; }
  .ach-name { font-size: 9px; }
  .unlock-banner { font-size: 9px; }
  .unlock-name { font-size: 10px; }
  .unlock-title { font-size: 8px; }
}

/* Extra small screens */
@media (max-width: 380px) {
  .brand h1 { font-size: 10px; }
  .grid { grid-template-columns: 1fr; }
  .row > * { min-width: 100px; }
}
