:root{
  --ink:#33302a;
  --sky-low:#e9e7d8;
  --cream:#f6ecd2;
  --gold:#ffbe00;
  --magenta:#f5006d;
  --ui:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box;}
html,body{height:100%;}
body{margin:0;overflow:hidden;background:#211f1b;font-family:var(--ui);}
/* fixed + centred rather than laid out in flow: the backing buffer is rounded
   up to whole pixels, and letting that overflow the document made Chrome
   sample a shifted backdrop behind the menus */
#game{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);
  display:block;touch-action:none;
  image-rendering:pixelated;image-rendering:crisp-edges;}
.overlay{position:fixed;color:var(--ink);user-select:none;-webkit-user-select:none;
  -webkit-tap-highlight-color:transparent;}

/* Run-only. It used to have no show/hide state at all, so on desktop the
   control hints sat over the title panel — which already lists the controls in
   its own .keys line — and over the results panel, where there is nothing to
   jump over. */
.hint{bottom:16px;left:50%;transform:translateX(-50%);pointer-events:none;z-index:3;
  font-weight:600;font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  opacity:0;transition:opacity .25s;white-space:nowrap;}
.hint.show{opacity:.5;}
.hint kbd{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11px;
  border:1px solid rgba(51,48,42,.45);border-radius:4px;padding:1px 5px;margin:0 2px;}

/* JS can't read env(), so it reads this element's padding instead */
#safe-probe{position:fixed;left:0;top:0;width:0;height:0;visibility:hidden;
  pointer-events:none;
  padding:env(safe-area-inset-top) env(safe-area-inset-right)
          env(safe-area-inset-bottom) env(safe-area-inset-left);}

/* ---------- now playing ticker ---------- */
.nowplaying{left:max(10px,env(safe-area-inset-left));
  bottom:max(10px,env(safe-area-inset-bottom));z-index:5;pointer-events:none;
  display:flex;align-items:center;gap:7px;
  background:rgba(51,48,42,.62);color:#fff;border-radius:999px;padding:6px 13px 6px 10px;
  font:600 10px/1 var(--ui);letter-spacing:.12em;text-transform:uppercase;
  opacity:0;transform:translateY(6px);transition:opacity .35s,transform .35s;
  backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);}
.nowplaying.show{opacity:1;transform:none;}
.nowplaying .eq{display:flex;align-items:flex-end;gap:2px;height:11px;}
.nowplaying .eq i{width:2px;background:var(--gold);animation:eq .7s ease-in-out infinite;}
.nowplaying .eq i:nth-child(1){height:5px;animation-delay:0s;}
.nowplaying .eq i:nth-child(2){height:11px;animation-delay:.18s;}
.nowplaying .eq i:nth-child(3){height:7px;animation-delay:.36s;}
@keyframes eq{0%,100%{transform:scaleY(.35);}50%{transform:scaleY(1);}}

/* ---------- mute ---------- */
.mute{top:max(10px,env(safe-area-inset-top));right:max(10px,env(safe-area-inset-right));
  z-index:5;width:30px;height:30px;border-radius:999px;cursor:pointer;
  border:1px solid rgba(51,48,42,.28);background:rgba(255,255,255,.55);
  backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  display:none;align-items:center;justify-content:center;padding:0;overflow:hidden;}
.mute.show{display:flex;}
.mute span{display:block;width:12px;height:12px;background:var(--ink);
  clip-path:polygon(0 32%,32% 32%,64% 0,64% 100%,32% 68%,0 68%);}
.mute.off span{background:#b0392f;}
.mute.off::after{content:"";position:absolute;width:22px;height:2px;background:#b0392f;
  transform:rotate(-38deg);border-radius:2px;}

/* On a phone the top-right belongs to the score and the bottom to your thumb,
   so the chrome moves to the top-left. MUST come after the .nowplaying and
   .mute blocks above: these are same-specificity overrides, so placing them
   earlier let the base `bottom`/`right` win and the ticker stretched itself
   from top to bottom of the screen. */
@media (pointer:coarse){
  .hint{display:none;}
  /* the score lives top-right, so the speaker moves out of its way */
  .mute{left:max(10px,env(safe-area-inset-left));right:auto;}
}

/* ---------- landscape + fullscreen gate ---------- */
.gate{position:fixed;inset:0;z-index:60;display:none;
  align-items:center;justify-content:center;padding:22px;
  background:#211f1b;color:#f6ecd2;text-align:center;
  /* a phone in landscape has ~330px of usable height; the install steps are
     taller than that, so the gate scrolls rather than clipping its own buttons */
  overflow-y:auto;overscroll-behavior:contain;
  -webkit-tap-highlight-color:transparent;}
.gate.show{display:flex;}
.gate-in{max-width:340px;margin:auto;}
/* the tipping-phone animation says "rotate", which is not what the install
   prompt is asking for — and it is the easiest 48px to give back */
.gate.a2hs .gate-ico{display:none;}
.gate h2{margin:16px 0 8px;font:800 19px/1.2 var(--ui);letter-spacing:.06em;
  text-transform:uppercase;}
.gate p{margin:0 0 18px;font:600 12px/1.6 var(--ui);opacity:.62;}
.gate .btn{color:var(--ink);}
.gate .btn.ghost{color:#f6ecd2;border-color:rgba(246,236,210,.3);margin-top:8px;}
/* iPhone install steps — numbered, left-aligned so they read as instructions
   rather than as more of the headline */
.gate-steps{margin:0 0 18px;padding:0;list-style:none;counter-reset:s;
  text-align:left;display:grid;gap:9px;}
/* the `display:grid` above outranks the UA rule behind the hidden attribute, so
   without this the steps stay on screen in every other gate state */
.gate-steps[hidden]{display:none;}
.gate-steps li{counter-increment:s;display:grid;grid-template-columns:20px 1fr;
  gap:9px;align-items:baseline;font:600 12px/1.45 var(--ui);opacity:.82;}
.gate-steps li::before{content:counter(s);justify-self:center;
  font:800 9px/18px var(--ui);color:var(--ink);background:var(--gold);
  width:18px;height:18px;border-radius:50%;text-align:center;}
.gate-steps b{font-weight:800;opacity:1;}
.gate-steps .glyph{display:inline-flex;vertical-align:-2px;color:var(--gold);}

/* a phone that tips over, drawn with borders so it needs no font glyph */
.gate-ico{display:flex;justify-content:center;}
.gate-ico span{width:30px;height:48px;border:3px solid var(--gold);border-radius:6px;
  display:block;animation:tip 1.9s ease-in-out infinite;transform-origin:50% 50%;}
@keyframes tip{0%,18%{transform:rotate(0deg);}50%,82%{transform:rotate(-90deg);}
  100%{transform:rotate(0deg);}}

/* phone held sideways: every vertical gap in the gate gets tightened so the
   copy, the three steps and both buttons all land on one screen */
@media (max-height:460px){
  .gate{padding:14px 18px;}
  .gate h2{margin:10px 0 6px;font-size:15px;}
  .gate p{margin:0 0 11px;font-size:11px;line-height:1.5;}
  .gate-steps{margin:0 0 11px;gap:6px;}
  .gate-steps li{font-size:11px;line-height:1.35;}
  .gate .btn{padding:9px 12px;}
  .gate .btn.ghost{margin-top:6px;}
  .gate-ico span{width:24px;height:38px;}
}

/* ---------- full-screen UI ---------- */
/* the scrim is deliberately light: the ghost is still up there doing laps and
   should stay visible behind the panel */
.screen{position:fixed;inset:0;z-index:20;display:none;
  align-items:center;justify-content:center;padding:18px;overflow-y:auto;
  background:rgba(28,26,22,.62);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  -webkit-tap-highlight-color:transparent;}
#scr-title{background:rgba(28,26,22,.8);backdrop-filter:blur(9px);
  -webkit-backdrop-filter:blur(9px);}
.screen.show{display:flex;animation:fade .22s ease-out;}
@keyframes fade{from{opacity:0;}to{opacity:1;}}

.panel{width:100%;max-width:330px;background:var(--cream);color:var(--ink);
  border:2px solid var(--ink);border-radius:16px;padding:20px 18px 18px;
  box-shadow:0 14px 0 rgba(0,0,0,.28),0 0 0 4px rgba(255,190,0,.16);
  text-align:center;margin:auto;}
/* The results panel is height-bounded and lays itself out as a flex column, so
   the leaderboard has something definite to scroll inside. Without this the
   grid row just grew to fit 25 rows and pushed the share button off-screen. */
.panel.wide{max-width:360px;max-height:100%;display:flex;flex-direction:column;}

/* one line, pixel font, sized in JS so it lands on whole pixels */
.wordmark{display:block;margin:0 auto;max-width:100%;height:auto;
  image-rendering:pixelated;image-rendering:crisp-edges;}

/* soundtrack preload — the title screen doubles as the loader */
.loading{margin-top:13px;transition:opacity .5s;}
.loading.done{opacity:0;pointer-events:none;height:0;margin:0;overflow:hidden;}
.loading .bar{height:3px;border-radius:99px;background:rgba(51,48,42,.14);overflow:hidden;}
.loading .bar i{display:block;height:100%;width:0;border-radius:99px;
  background:var(--gold);transition:width .3s ease-out;}
.loading span{display:block;margin-top:6px;font:600 8px/1 var(--ui);
  letter-spacing:.2em;text-transform:uppercase;opacity:.45;}

.flabel{display:block;margin:20px 0 7px;font:700 9px/1 var(--ui);
  letter-spacing:.22em;text-transform:uppercase;opacity:.6;}
#uname{width:100%;padding:11px 12px;border:2px solid var(--ink);border-radius:10px;
  background:#fffaee;color:var(--ink);text-align:center;
  font:800 16px/1 ui-monospace,Menlo,Consolas,monospace;letter-spacing:.16em;
  text-transform:uppercase;outline:none;}
#uname::placeholder{color:rgba(51,48,42,.28);}
#uname:focus{border-color:var(--magenta);box-shadow:0 0 0 3px rgba(245,0,109,.16);}

.btn{display:block;width:100%;margin-top:10px;padding:12px 14px;cursor:pointer;
  border:2px solid var(--ink);border-radius:10px;background:#fffaee;color:var(--ink);
  font:800 12px/1 var(--ui);letter-spacing:.18em;text-transform:uppercase;
  transition:transform .05s,background .12s;}
.btn:hover{background:#fff;}
.btn:active{transform:translateY(2px);}
.btn.primary{background:var(--gold);border-color:#8a6a00;box-shadow:0 4px 0 #8a6a00;}
.btn.primary:hover{background:#ffcb2e;}
.btn.primary:active{box-shadow:0 1px 0 #8a6a00;}
.btn.ghost{background:transparent;border-color:rgba(51,48,42,.3);font-size:10px;
  letter-spacing:.16em;opacity:.7;box-shadow:none;}
.btn.waiting{opacity:.6;pointer-events:none;}
.row{display:flex;gap:8px;}
.row .btn{margin-top:12px;flex:1 1 0;min-width:0;}  /* equal halves, not text-sized */

.keys{margin-top:14px;font:600 9px/1.6 var(--ui);letter-spacing:.1em;
  text-transform:uppercase;opacity:.45;}
.keys kbd{font-family:ui-monospace,Menlo,Consolas,monospace;
  border:1px solid rgba(51,48,42,.4);border-radius:3px;padding:1px 4px;}
.keys .tk{display:none;}
@media (pointer:coarse){ .keys .dk{display:none;} .keys .tk{display:inline;} }

/* ---------- leaderboard ---------- */
.lbwrap{margin-top:16px;text-align:left;}
.lbwrap h3{margin:0 0 7px;font:700 9px/1 var(--ui);letter-spacing:.24em;
  text-transform:uppercase;opacity:.55;text-align:center;}
/* shown only while the global board is unreachable, so a local-only list is
   never mistaken for everyone's scores */
.lbwrap h3 .lblocal{font-size:8px;letter-spacing:.12em;opacity:.7;}
.lbwrap h3 .lblocal::before{content:"\00b7\00a0";}
.lbrow{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;
  font:700 11px/1 ui-monospace,Menlo,Consolas,monospace;}
.lbrow:nth-of-type(even){background:rgba(51,48,42,.055);}
.lbrow.rank-1{
  font-size:12px;
  padding:7px 8px;
  background:rgba(255,190,0,.16);
  box-shadow:inset 0 0 0 1px rgba(184,134,0,.35);
}
.lbrow.rank-1 .rk{
  font-weight:900;
  color:#8a6400;
  opacity:1;
}
.lbrow.rank-1 .nm{
  font-weight:800;
  display:inline-flex;
  align-items:center;
}
.lbrow.rank-1 .sc{
  font-weight:900;
}
.lbrow.rank-2{
  font-size:11px;
  padding:5px 8px;
  background:rgba(207,216,220,.12);
  box-shadow:inset 0 0 0 1px rgba(144,164,174,.3);
}
.lbrow.rank-2 .rk{
  font-weight:800;
  color:#546e7a;
  opacity:1;
}
.lbrow.rank-2 .nm{
  font-weight:700;
  display:inline-flex;
  align-items:center;
}
.lbrow.rank-2 .sc{
  font-weight:800;
}
.lbrow.rank-3{
  font-size:11px;
  padding:5px 8px;
  background:rgba(205,127,50,.12);
  box-shadow:inset 0 0 0 1px rgba(160,82,45,.3);
}
.lbrow.rank-3 .rk{
  font-weight:800;
  color:#8d4f18;
  opacity:1;
}
.lbrow.rank-3 .nm{
  font-weight:700;
  display:inline-flex;
  align-items:center;
}
.lbrow.rank-3 .sc{
  font-weight:800;
}
.lbrow.me{background:rgba(255,190,0,.38);box-shadow:inset 0 0 0 1px rgba(138,106,0,.4);}
.lbrow.rank-1.me{background:rgba(255,190,0,.48);box-shadow:inset 0 0 0 1.5px rgba(138,106,0,.6);}
.nettipattam-badge{filter:drop-shadow(0 1px 2px rgba(0,0,0,.3));}
.lbrow .rk{width:18px;opacity:.45;flex:none;}
.lbrow .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  letter-spacing:.06em;display:inline-flex;align-items:center;}
.lbrow .tm{opacity:.45;font-size:9px;flex:none;}
.lbrow .sc{font-weight:800;flex:none;}
.lbempty{padding:8px;text-align:center;font:600 10px/1.5 var(--ui);opacity:.4;
  letter-spacing:.08em;text-transform:uppercase;}
/* An unfilled slot on the results board. Faint enough to read as absence rather
   than as a player called [EMPTY], but still holding its row so the region is
   occupied from the first run instead of being blank space to grow into. */
.lbrow.empty .rk{opacity:.22;}
.lbrow.empty .nm{opacity:.26;letter-spacing:.14em;}

/* ============================================================================
   RESULTS
   Three columns:  card + share  |  leaderboard + tape  |  actions + community.
   The card carries the score, survival and rank, so there is no separate stat
   readout to keep in sync. Each column is a flex stack with one flexible child
   (board, community) that absorbs the height, so when a conditional block is
   hidden the space closes up instead of leaving a hole.
   ========================================================================= */
.gover-row{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin-bottom:9px;flex-wrap:wrap;}
.gover{font:800 12px/1 var(--ui);letter-spacing:.22em;text-transform:uppercase;
  color:var(--magenta);text-align:left;flex:none;}
.gover-score{font:800 11px/1 ui-monospace,Menlo,Consolas,monospace;letter-spacing:.08em;
  color:var(--ink);opacity:.75;flex:none;}
.res{display:grid;gap:14px;margin-top:0;text-align:left;align-items:stretch;
  flex:1;min-height:0;}
.res section{min-width:0;min-height:0;display:flex;flex-direction:column;}

/* ---- column 1: the card ---- */
.cardwrap{display:flex;justify-content:center;align-items:flex-start;min-height:0;flex:1;}
#card{display:block;width:auto;height:auto;max-width:100%;max-height:100%;
  border-radius:9px;border:2px solid var(--ink);
  image-rendering:pixelated;image-rendering:crisp-edges;}
.col-card .btn{margin-top:10px;flex:none;}

/* ---- column 2: leaderboard (scrolls) then the tape block ---- */
.col-mid .lbwrap{flex:1;min-height:0;display:flex;flex-direction:column;margin:0;}
.lbwrap h3{margin:0 0 7px;font:700 9px/1 var(--ui);letter-spacing:.24em;
  text-transform:uppercase;opacity:.55;flex:none;}
/* no row cap any more — it scrolls instead */
.lblist{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;padding-right:2px;}
/* On the title screen the board is a sidebar, not the subject — bound it so a
   long list can't stretch the panel down the whole screen. */
#lb-title{margin-top:16px;}
#lb-title .lblist{max-height:132px;}
.lblist::-webkit-scrollbar{width:5px;}
.lblist::-webkit-scrollbar-thumb{background:rgba(51,48,42,.28);border-radius:99px;}
.tapeslot:empty{display:none;}
.tapeslot{flex:none;margin-top:12px;}

/* ---- column 3: actions then the community ---- */
.col-act > .btn{flex:none;margin-top:0;}
.col-act > .btn + .btn{margin-top:8px;}
.commslot{flex:1;min-height:0;margin-top:12px;display:flex;}
.commslot > *{flex:1;}
.commslot:empty{display:none;}

/* ---- the tape block: one clickable plate, no button inside it ---- */
.blk-tape{display:flex;flex-direction:column;justify-content:center;
  padding:13px 15px;border-radius:10px;text-align:center;
  background:linear-gradient(180deg,#2a1220,#1b0a12);
  border:2px solid var(--gold);box-shadow:0 0 0 3px rgba(255,190,0,.14);}
a.blk-tape{text-decoration:none;cursor:pointer;transition:transform .06s,box-shadow .12s;}
a.blk-tape:hover{box-shadow:0 0 0 3px rgba(255,190,0,.3);}
a.blk-tape:active{transform:translateY(2px);}
.blk-tape .tag{display:block;font:800 8px/1 var(--ui);letter-spacing:.24em;
  text-transform:uppercase;color:var(--gold);opacity:.85;margin-bottom:6px;}
.blk-tape strong{display:block;font:800 13px/1.3 var(--ui);letter-spacing:.07em;
  text-transform:uppercase;color:#fff;}
.blk-tape .go{display:block;margin-top:7px;font:800 9px/1 var(--ui);
  letter-spacing:.18em;text-transform:uppercase;color:var(--gold);}
.blk-tape .go::after{content:" \2192";}

/* ---- community ---- */
.blk-locked{display:flex;flex-direction:column;justify-content:center;
  padding:12px 13px;border-radius:10px;border:2px dashed rgba(51,48,42,.3);}
.blk-locked .lhead{display:flex;justify-content:space-between;align-items:baseline;
  gap:10px;font:700 9px/1.3 var(--ui);letter-spacing:.14em;text-transform:uppercase;
  opacity:.62;}
.blk-locked .lhead b{font-weight:800;opacity:.9;white-space:nowrap;}
.blk-locked .track{margin-top:9px;height:5px;border-radius:99px;
  background:rgba(51,48,42,.14);overflow:hidden;}
.blk-locked .track i{display:block;height:100%;border-radius:99px;
  background:var(--gold);transition:width .5s ease-out;}

.blk-unlock{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:9px;padding:12px;border-radius:10px;border:2px solid var(--ink);background:#fffaee;
  text-align:center;flex:1;}
.qrbox{flex:none;width:100%;display:flex;justify-content:center;}
/* Sized from WIDTH only, so it is always exactly square. Driving it from
   height instead let max-width clip one side and the QR came out 209x218 —
   a stretched QR is a sloppy QR. */
.qrbox canvas{width:100%;max-width:190px;height:auto;aspect-ratio:1;
  display:block;border:2px solid rgba(51,48,42,.3);border-radius:6px;background:#fff;
  image-rendering:pixelated;image-rendering:crisp-edges;}
.blk-unlock h4{margin:0;font:800 10px/1.2 var(--ui);letter-spacing:.14em;
  text-transform:uppercase;}
.blk-unlock p{margin:0;font:600 9px/1.4 var(--ui);letter-spacing:.05em;
  text-transform:uppercase;opacity:.55;}
.blk-unlock .btn{width:100%;margin:0;white-space:nowrap;flex:none;
  background:#25d366;border-color:#0f7a3a;box-shadow:0 4px 0 #0f7a3a;
  color:#06301a;text-decoration:none;}
.blk-unlock .btn:active{box-shadow:0 1px 0 #0f7a3a;}

/* ---- three across once there is room ---- */
@media (min-width:720px){
  /* board is CAPPED, not flexible: given a whole 1fr its rows stretched into a
     canyon between the name and the score. The slack goes to the QR instead. */
  /* The card is sized so card+button equals the height the QR column comes to,
     leaving no dead space beneath it. Width is taken from the board, which had
     slack to spare — its rows were stretching into a canyon anyway. */
  .res{grid-template-columns:244px minmax(196px,244px) minmax(184px,1fr);}
}
@media (min-width:720px) and (min-height:620px){
  .panel.wide{max-width:790px;}
  .res{min-height:400px;}
}
/* stacked (narrow portrait): the card would dominate, so cap it */
@media (max-width:719px){
  #card{max-height:min(40vh,300px);}
  .lblist{max-height:240px;}
  .commslot{margin-top:14px;}
  /* One column means the three sections stack, and their heights add up rather
     than sitting side by side — with a full board they exceed the window. Let
     them take their natural heights and scroll the panel instead of squeezing
     them: the card's height comes from the vh cap above, not from its box, so
     compressing .cardwrap just made the canvas overflow its own wrapper and
     land on top of the Share button and the board. */
  .panel.wide{overflow-y:auto;overscroll-behavior:contain;}
  .res{flex:0 0 auto;}
  .cardwrap{flex:none;}
}

/* ---- short landscape: a phone held sideways, ~390px of height total ---- */
@media (orientation:landscape) and (max-height:560px){
  .screen{padding:10px;}
  .panel{max-width:400px;padding:12px 14px;}
  .panel.wide{max-width:730px;}
  .flabel{margin:12px 0 6px;}
  #uname{padding:9px 12px;font-size:15px;}
  .keys{margin-top:9px;}
  .loading{margin-top:10px;}
  #lb-title{margin-top:10px;}
  #lb-title .lblist{max-height:74px;}

  .gover-row{margin-bottom:7px;}
  .gover{font-size:10px;}
  .gover-score{font-size:10px;}
  .res{margin-top:0;gap:12px;min-height:0;
    grid-template-columns:160px minmax(200px,255px) minmax(170px,1fr);}
  .col-card .btn,.col-act > .btn{padding:9px 10px;font-size:10px;letter-spacing:.1em;}
  .col-card .btn{margin-top:8px;}
  .tapeslot{margin-top:9px;}
  .blk-tape{padding:9px 11px;}
  .blk-tape strong{font-size:11px;}
  .commslot{margin-top:9px;}
  .blk-unlock{padding:9px;gap:7px;}
  .qrbox canvas{max-width:118px;}
  .blk-unlock h4{font-size:9px;}
  .blk-unlock p{display:none;}     /* the QR and the button already say it */
  .blk-unlock .btn{padding:9px 8px;font-size:9px;letter-spacing:.08em;}
  .lbrow{padding:4px 7px;font-size:10px;}
}

.toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(10px);
  z-index:40;background:var(--ink);color:#fff;border-radius:999px;padding:9px 16px;
  font:700 10px/1 var(--ui);letter-spacing:.14em;text-transform:uppercase;
  opacity:0;transition:opacity .2s,transform .2s;pointer-events:none;}
.toast.show{opacity:1;transform:translateX(-50%);}
