/* TapTap's menus (menu.js). Ported from mockups/taptap-menus.html and scoped under #ui, so the setup
   panel and the in-game HUD keep their own look. Fonts: LINE Seed JP for the UI, Outfit for grade
   letters, Comfortaa for the pause / fail header (all OFL, in fonts/menu). */
@import url("fonts/menu/fonts.css");
  #ui{
    --bg:#0b0d11; --panel:#12151c; --panel-2:#0d1016; --raise:#171c27; --line:#242a38; --line-2:#323a4d;
    --text:#e8ebf1; --muted:#a3abbd; --soft:#8c95a8;
    --lane-a:#ffb04d; --lane-a-ink:#1a1205; --lane-b:#3fd0c9;
    --gold:#ffd24d; --ok:#7ee787; --miss:#ff6b6b; --blue:#6bb6ff; --violet:#c9a0ff;
    --g-SS:#ffd24d; --g-S:#3fd0c9; --g-A:#7ee787; --g-B:#6bb6ff; --g-C:#c9a0ff; --g-D:#ff6b6b;
    /* LINE Seed JP: the user's pick from round 2. One family draws Latin and Japanese, so song titles in
       either script match the rest of the UI. */
    --ui:"LINE Seed JP",system-ui,-apple-system,"Segoe UI",sans-serif;
    /* Grade letters are stamps, not text: a heavy geometric face sets them apart from the UI text.
       Outfit is the pick, Lexend the runner-up; the mockup bar switches between the candidates. */
    --grade:"Outfit",var(--ui); --grade-style:normal; --grade-weight:800;
    --tb:52px;
    --r-s:6px; --r-m:10px; --r-l:14px;
    color-scheme:dark;
  }
  #ui *{box-sizing:border-box}
  /* Panels set their own display; this keeps the hidden attribute winning when the page is opened directly. */
  #ui [hidden]{display:none!important}
  #ui{height:100%}
  #ui{background:var(--bg);color:var(--text);font-family:var(--ui);overflow:hidden}
  #ui button,#ui input,#ui select{font:inherit;color:inherit}
  #ui :focus-visible{outline:2px solid var(--lane-b);outline-offset:2px}
  #ui .num{font-variant-numeric:tabular-nums}
  #ui .sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  #ui .muted{color:var(--muted)}
  #ui .small{font-size:13px;line-height:1.5}
  #ui #stage{position:relative;flex:1;overflow:hidden;background:radial-gradient(120% 90% at 50% 0%,#141a28 0%,var(--bg) 60%)}
  /* ---------- toolbar: home and settings on the left, the overlays and your profile on the right ---------- */
  #ui .toolbar{position:absolute;left:0;right:0;top:0;height:var(--tb);z-index:20;display:flex;align-items:center;gap:4px;
    padding:0 max(10px,env(safe-area-inset-right,0px)) 0 max(10px,env(safe-area-inset-left,0px));background:rgba(8,9,12,.94);border-bottom:1px solid var(--line)}
  #ui .toolbar .grow{flex:1}
  #ui .tb{display:inline-flex;align-items:center;gap:7px;height:40px;padding:0 10px;border:0;border-radius:var(--r-m);background:transparent;color:var(--muted);font-weight:800;font-size:14px;cursor:pointer}
  #ui .tb svg{width:20px;height:20px;fill:currentColor;flex:none}
  #ui .tb:hover{color:var(--text);background:var(--raise)}
  #ui .tb[aria-pressed="true"]{color:var(--text);background:#10232a;box-shadow:inset 0 -2px 0 var(--lane-b)}
  #ui .tb .av{width:28px;height:28px;font-size:14px;border-radius:7px}
  #ui .screen{position:absolute;inset:var(--tb) 0 0 0;overflow:auto;
    padding-left:max(16px,env(safe-area-inset-left,0px));padding-right:max(16px,env(safe-area-inset-right,0px))}
  /* Screen changes slide in from the direction of travel, so forward and back read differently. */
  #ui .screen.enter-fwd{animation:in-fwd .22s ease-out}
  #ui .screen.enter-back{animation:in-back .22s ease-out}
  @keyframes in-fwd{from{opacity:0;transform:translateX(18px)}to{opacity:1;transform:none}}
  @keyframes in-back{from{opacity:0;transform:translateX(-18px)}to{opacity:1;transform:none}}
  @keyframes fade{from{opacity:0}}
  @keyframes row-in{from{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:none}}

  /* ---------- shared controls ---------- */
  #ui .bar{display:flex;align-items:center;gap:10px 12px;flex-wrap:wrap;padding-block:14px 12px}
  #ui .bar h2{margin:0 auto 0 0;font-size:22px;font-weight:900}
  #ui .btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:38px;padding:7px 14px;border-radius:var(--r-m);border:1px solid var(--line-2);
    background:var(--raise);font-weight:800;cursor:pointer}
  #ui .btn:hover{border-color:var(--lane-b)}
  #ui .btn.primary{background:var(--lane-a);color:var(--lane-a-ink);border-color:transparent}
  #ui .btn.primary:hover{filter:brightness(1.08)}
  #ui .btn[aria-pressed="true"]{background:#10232a;border-color:var(--lane-b)}
  #ui .btn:disabled{cursor:not-allowed;opacity:.55}
  #ui .seg{display:inline-flex;border:1px solid var(--line-2);border-radius:var(--r-m);overflow:hidden}
  #ui .seg button{border:0;background:transparent;padding:6px 12px;min-height:34px;font-weight:700;font-size:14px;color:var(--muted);cursor:pointer}
  #ui .seg button + button{border-left:1px solid var(--line-2)}
  #ui .seg button[aria-selected="true"]{background:#10232a;color:var(--text);box-shadow:inset 0 -2px 0 var(--lane-b)}
  #ui .search{background:var(--panel-2);border:1px solid var(--line-2);border-radius:var(--r-m);padding:7px 10px;min-height:38px;font-size:14px;width:min(240px,100%)}
  #ui .pick{display:inline-flex;align-items:center;border:1px solid var(--line-2);border-radius:var(--r-m);overflow:hidden;background:var(--panel-2)}
  #ui .pick span{padding:0 10px;font-size:13px;font-weight:800;color:var(--muted);border-right:1px solid var(--line-2);align-self:stretch;display:flex;align-items:center}
  #ui .pick select{border:0;background:transparent;padding:7px 8px;min-height:36px;font-size:14px;font-weight:700;cursor:pointer}
  #ui .pick select option{background:var(--panel);color:var(--text)}
  #ui .tag{display:inline-block;font-size:12px;font-weight:800;border-radius:var(--r-s);padding:2px 7px;white-space:nowrap}
  #ui .tag.built{background:#232a39;color:var(--muted)}
  #ui .tag.example{background:#232a39;color:var(--soft)}
  #ui .tag.ranked{background:rgba(126,231,135,.14);color:var(--ok)}
  #ui .tag.pending{background:rgba(255,210,77,.14);color:var(--gold)}
  #ui .tag.fail{background:rgba(255,107,107,.14);color:var(--miss)}
  #ui .tag.pass{background:rgba(126,231,135,.12);color:var(--ok)}
  #ui .unr{display:inline-block;font-size:12px;font-weight:900;letter-spacing:.04em;color:var(--gold);background:rgba(255,210,77,.12);border-radius:var(--r-s);padding:2px 7px}
  #ui .state{padding:18px 14px;border:1px dashed var(--line-2);border-radius:var(--r-m);color:var(--muted);font-size:14px;line-height:1.5;display:flex;gap:10px;align-items:center;flex-wrap:wrap}
  #ui .state.err{border-color:rgba(255,107,107,.45);color:var(--text)}
  #ui .spinner{width:16px;height:16px;border-radius:50%;border:2px solid var(--line-2);border-top-color:var(--lane-b);animation:spin .8s linear infinite}
  @keyframes spin{to{transform:rotate(360deg)}}
  #ui .gl,#ui .sv-letter,#ui .sv-flash,#ui .lz-grade,#ui .gpill,#ui .rk-g{font-family:var(--grade);font-style:var(--grade-style);font-weight:var(--grade-weight)}
  #ui .gl.g-SS{color:var(--g-SS)} #ui .gl.g-S{color:var(--g-S)} #ui .gl.g-A{color:var(--g-A)} #ui .gl.g-B{color:var(--g-B)} #ui .gl.g-C{color:var(--g-C)} #ui .gl.g-D{color:var(--g-D)}

  /* initial-based avatar placeholders (no account pictures exist yet) */
  #ui .av{display:inline-grid;place-items:center;flex:none;width:40px;height:40px;border-radius:9px;font-weight:900;font-size:18px;color:#fff;
    background:hsl(var(--h) 38% 32%)}
  #ui .av.lg{width:64px;height:64px;border-radius:14px;font-size:28px}

  /* mod icons: one square slot per icon, skin art fitted inside it, so any skin's shapes line up */
  #ui .mslot{display:inline-grid;place-items:center;width:var(--s);height:var(--s);flex:none;vertical-align:middle}
  #ui .mslot img{display:block;max-width:100%;max-height:100%;object-fit:contain}
  #ui .mslot svg{display:block;width:88%;height:88%}
  /* lazer's ModIcon adjustment marker: a cog at the icon's top right when the mod's settings were changed */
  #ui .mslot.tweaked{position:relative}
  #ui .mcog{position:absolute;left:80%;top:17.5%;width:max(9px,30%);aspect-ratio:1;translate:-50% -50%;pointer-events:none}
  #ui .mcog svg{display:block;width:100%;height:100%}
  #ui .modset{display:inline-flex;align-items:center;gap:3px;flex-wrap:wrap}
  #ui .modset .rate{font-size:12px;font-weight:800;color:var(--muted);margin-right:3px}
  /* ---------- title ---------- */
  #ui #title{display:flex;align-items:center;justify-content:center;padding-block:24px 48px}
  #ui #titleCanvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
  #ui .np{position:absolute;top:14px;right:max(16px,env(safe-area-inset-right,0px));display:flex;align-items:center;gap:10px;font-size:14px;color:var(--muted);z-index:2}
  #ui .np b{color:var(--text)}
  #ui .np button{width:36px;height:36px;border-radius:50%;border:1px solid var(--line-2);background:var(--panel);cursor:pointer;display:grid;place-items:center}
  #ui .np svg{width:14px;height:14px;fill:var(--text)}
  #ui .bars{display:flex;gap:2px;align-items:flex-end;height:14px}
  #ui .bars i{width:3px;height:5px;background:var(--lane-b);border-radius:1px}
  #ui .bars i:nth-child(2){background:var(--lane-a)}
  #ui #title.playing .bars i,#ui .np.on .bars i{animation:eq var(--beat) ease-in-out infinite}
  #ui .np.on .bars i:nth-child(2){animation-delay:calc(var(--beat) / -3)}
  #ui .np.on .bars i:nth-child(3){animation-delay:calc(var(--beat) / -1.5)}
  #ui .np.inbar{position:static;min-width:0}
  #ui .np.inbar .label{max-width:30ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  #ui #title.playing .bars i:nth-child(2){animation-delay:calc(var(--beat) / -3)}
  #ui #title.playing .bars i:nth-child(3){animation-delay:calc(var(--beat) / -1.5)}
  @keyframes eq{0%,100%{height:4px}50%{height:14px}}
  #ui .title-wrap{position:relative;z-index:1;display:flex;align-items:center;gap:28px;transition:transform .45s cubic-bezier(.2,.8,.2,1)}
  #ui #title:not(.open) .title-wrap{transform:translateX(calc(var(--menu-w,0px) / 2))}
  #ui .logo{position:relative;width:min(280px,58vw);aspect-ratio:1;border-radius:50%;border:0;cursor:pointer;padding:0;
    background:radial-gradient(circle at 50% 30%,#1d2335,#0e1119 72%);box-shadow:0 0 0 6px var(--text),0 18px 60px rgba(0,0,0,.55),0 0 70px rgba(63,208,201,.18);overflow:hidden}
  /* The logo beats on the menu music's tempo; it stops when the music is paused. */
  #ui #title.playing .logo{animation:beat var(--beat) ease-out infinite}
  @keyframes beat{0%{transform:scale(1.035)}30%{transform:scale(1)}}
  #ui .logo .lanes{position:absolute;inset:14% 31% 26%;display:grid;grid-template-columns:1fr 1fr;gap:8%}
  #ui .logo .lanes i{position:relative;border-radius:8px;background:linear-gradient(180deg,rgba(255,255,255,0),rgba(255,255,255,.05))}
  #ui .logo .lanes i::after{content:"";position:absolute;left:6%;right:6%;height:15%;border-radius:5px}
  #ui .logo .lanes i:first-child::after{top:58%;background:linear-gradient(180deg,#ffe2b3,var(--lane-a) 45%,#cf7c16)}
  #ui .logo .lanes i:last-child::after{top:22%;background:linear-gradient(180deg,#bdf7f3,var(--lane-b) 45%,#18958f)}
  #ui .logo .line{position:absolute;left:22%;right:22%;bottom:30%;height:3px;background:#fff;border-radius:2px}
  #ui .logo .word{position:absolute;bottom:12%;left:0;right:0;text-align:center;font-weight:900;font-size:clamp(28px,7vw,42px)}
  #ui .menu{display:flex;flex-direction:column;gap:10px;opacity:0;visibility:hidden;transform:translateX(-20px);transition:opacity .25s,transform .35s,visibility 0s .35s}
  #ui #title.open .menu{opacity:1;visibility:visible;transform:none;transition:opacity .25s,transform .35s}
  /* One label per button (osu!'s main menu has no subtitles), centred both ways. */
  #ui .menu button{display:grid;place-items:center;width:min(250px,70vw);min-height:54px;padding:9px 16px;border-radius:var(--r-m);
    border:1px solid var(--line-2);background:var(--raise);font-size:19px;font-weight:800;line-height:1.2;cursor:pointer;text-align:center}
  #ui .menu button.primary{background:var(--lane-a);color:var(--lane-a-ink);border-color:transparent}
  #ui .menu button:hover:not(:disabled){border-color:var(--lane-b)}
  #ui .menu button:disabled{cursor:not-allowed;opacity:.6}
  @media (max-width:700px){
    #ui .title-wrap{flex-direction:column;gap:20px}
    #ui #title:not(.open) .title-wrap{transform:translateY(calc(var(--menu-h,0px) / 2))}
    #ui .menu{transform:translateY(-12px)}
    #ui .np .label{display:none}
  }
  /* ---------- song select ---------- */
  #ui #select{display:flex;flex-direction:column}
  #ui .ss{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:16px;align-items:start}
  #ui .col{display:flex;flex-direction:column;gap:12px;min-width:0}
  #ui .meta{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-l);padding:14px 16px}
  #ui .meta h3{margin:0;font-size:24px;font-weight:900;text-wrap:balance}
  #ui .meta .by{color:var(--muted);font-size:15px;margin:2px 0 12px}
  #ui .stats{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:8px}
  #ui .stat{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-s);padding:6px 9px}
  #ui .stat span{display:block;font-size:12px;color:var(--muted)}
  #ui .stat b{font-size:17px;font-variant-numeric:tabular-nums}
  #ui .pv-row{display:flex;align-items:center;gap:10px;margin-top:12px}
  #ui .pv-label{font-size:12px;font-weight:700;color:var(--muted)}
  #ui .pvtrack{flex:1;height:4px;border-radius:2px;background:var(--line);overflow:hidden}
  #ui .pvtrack i{display:block;height:100%;width:0;background:var(--lane-b)}
  #ui .stat.adj{border-color:rgba(255,176,77,.55)}
  #ui .stat.adj b{color:var(--lane-a)}

  #ui .board{container-type:inline-size}
  #ui .board-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}
  #ui .board-head h4{margin:0 auto 0 0;font-size:16px;font-weight:900}
  /* Leaderboard rows lean: each row is a parallelogram, and the list steps left as it goes down. */
  #ui .lz{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
  #ui .lz li{margin-left:calc(var(--step) * 9px)}
  #ui .lz li.in{animation:row-in .3s ease-out both}
  #ui .lz-row{display:flex;align-items:center;gap:10px;width:100%;padding:0;border:0;background:transparent;cursor:pointer;text-align:left}
  #ui .lz-rank{width:2.6em;flex:none;text-align:right;font-weight:900;font-size:16px;color:var(--muted);font-variant-numeric:tabular-nums}
  #ui .lz-card{position:relative;flex:1;min-width:0;display:flex;align-items:center;gap:12px;height:58px;padding:0 58px 0 22px;
    background:var(--raise);clip-path:polygon(14px 0,100% 0,calc(100% - 14px) 100%,0 100%);transition:background .15s}
  #ui .lz-row:hover .lz-card{background:#1d2331}
  #ui .lz-row:focus-visible{outline:none}
  #ui .lz-row:focus-visible .lz-card{background:#10232a}
  #ui .lz li.me .lz-card{background:#2a1f10}
  #ui .lz li.me .lz-rank{color:var(--lane-a)}
  #ui .lz-id{min-width:0;flex:1}
  #ui .lz-id small{display:block;font-size:12px;color:var(--muted)}
  #ui .lz-id b{display:block;font-size:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #ui .lz-stat{flex:none;width:78px}
  #ui .lz-stat small{display:block;font-size:11px;color:var(--muted);font-weight:700}
  #ui .lz-stat b{font-size:15px;font-variant-numeric:tabular-nums}
  #ui .lz-stat b.fc{color:var(--ok)}
  #ui .lz-score{flex:none;text-align:right;display:flex;flex-direction:column;align-items:flex-end;gap:2px}
  #ui .lz-score b{font-size:20px;font-weight:800;font-variant-numeric:tabular-nums;line-height:1}
  #ui .lz-grade{position:absolute;right:0;top:0;bottom:0;width:52px;display:grid;place-items:center;padding-left:6px;font-size:21px;color:var(--bg);
    clip-path:polygon(14px 0,100% 0,calc(100% - 14px) 100%,0 100%)}
  #ui .lz-grade.g-SS{background:var(--g-SS)} #ui .lz-grade.g-S{background:var(--g-S)} #ui .lz-grade.g-A{background:var(--g-A)}
  #ui .lz-grade.g-B{background:var(--g-B)} #ui .lz-grade.g-C{background:var(--g-C)} #ui .lz-grade.g-D{background:var(--g-D)}
  @container (max-width:560px){
    #ui .lz li{margin-left:0}
    #ui .lz-stat{display:none}
    #ui .lz-card{height:56px;gap:10px;padding:0 54px 0 18px}
    #ui .lz-rank{width:2.2em;font-size:14px}
    #ui .lz-score b{font-size:17px}
  }
  #ui .board-foot{margin:10px 2px 0}

  #ui .list{display:flex;flex-direction:column;gap:8px;min-width:0}
  #ui .listbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
  #ui .group-h{margin:8px 2px 0;font-size:14px;font-weight:900;color:var(--lane-b)}
  #ui .song{border:1px solid var(--line);border-radius:var(--r-l);background:var(--panel);overflow:hidden;transition:border-color .15s}
  #ui .song.sel{border-color:var(--lane-a)}
  #ui .song.new{animation:song-new 1.2s ease-out}
  @keyframes song-new{0%{opacity:0;transform:translateY(-8px);border-color:var(--lane-b)}25%{opacity:1;transform:none}100%{border-color:var(--line)}}
  #ui .song-head{display:flex;gap:12px;align-items:center;width:100%;padding:11px 14px;border:0;background:transparent;cursor:pointer;text-align:left}
  #ui .song-head .grow{flex:1;min-width:0}
  #ui .song-head .t{display:block;font-weight:800;font-size:17px}
  #ui .song-head .a{display:block;color:var(--muted);font-size:14px}
  #ui .dots{display:flex;gap:4px;align-items:center;flex:none}
  #ui .dots i{width:10px;height:10px;border-radius:50%;background:var(--sc)}
  #ui .diffs{display:grid;grid-template-rows:0fr;transition:grid-template-rows .22s ease-out}
  #ui .song.sel .diffs{grid-template-rows:1fr}
  #ui .diffs > div{overflow:hidden;display:flex;flex-direction:column;gap:5px;padding:0 10px}
  #ui .song.sel .diffs > div{padding-bottom:10px}
  #ui .diff{display:flex;align-items:center;gap:10px;min-height:40px;padding:6px 12px;border-radius:var(--r-m);cursor:pointer;background:var(--panel-2);border:1px solid var(--line);text-align:left}
  #ui .diff[aria-selected="true"]{border-color:var(--lane-b);background:#0f2027}
  #ui .diff .n{font-weight:700;flex:1}
  #ui .stars{font-weight:800;font-size:14px;font-variant-numeric:tabular-nums}
  #ui .drop-hint{border:1.5px dashed var(--line-2);border-radius:var(--r-l);padding:14px;display:flex;gap:10px 14px;align-items:center;flex-wrap:wrap;color:var(--muted);font-size:14px}
  #ui .drop-hint label{cursor:pointer}

  /* Sticky, so it stays at the bottom however long the song list gets; the negative margins let it run
     edge to edge past the screen's side gutter. */
  #ui .bottom{position:sticky;bottom:0;margin-top:auto;z-index:5;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
    margin-left:calc(-1 * max(16px,env(safe-area-inset-left,0px)));margin-right:calc(-1 * max(16px,env(safe-area-inset-right,0px)));
    padding:10px max(16px,env(safe-area-inset-right,0px)) calc(10px + env(safe-area-inset-bottom,0px)) max(16px,env(safe-area-inset-left,0px));
    background:rgba(9,11,15,.94);border-top:1px solid var(--line)}
  #ui .bottom .grow{flex:1}
  #ui .mods-btn .mult{color:var(--lane-a);font-variant-numeric:tabular-nums}
  #ui .unr-note{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--gold);font-weight:700}
  #ui .bottom .play{padding-inline:28px;font-size:17px}
  @media (max-width:980px){#ui .ss{grid-template-columns:1fr}#ui .ss .list{order:-1}}
  #ui .ss{margin-bottom:16px}
  @media (max-width:600px){#ui .bottom .grow{display:none}#ui .bottom .play{flex:1}}

  /* ---------- score viewer ---------- */
  #ui .sv{display:flex;flex-direction:column;align-items:center;width:min(440px,100%);margin-inline:auto}
  /* The avatar straddles the card's top edge (half out, half in) and the name sits inside the card under
     it, so the two read as one header instead of the picture above the card and the name below its edge. */
  #ui .sv-av{margin-bottom:-32px;position:relative;z-index:1;border-radius:16px;box-shadow:0 0 0 4px var(--bg)}
  #ui .sv-name{border:0;background:transparent;padding:2px 8px;border-radius:var(--r-s);font-size:16px;font-weight:800;cursor:pointer;margin-top:-2px}
  #ui .sv-name:hover{color:var(--lane-b)}
  #ui .sv-card{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:22px;padding:40px 18px 16px;display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center}
  #ui .sv-song b{display:block;font-size:20px;font-weight:900;text-wrap:balance}
  #ui .sv-song span{color:var(--muted);font-size:14px}
  /* The results ring follows osu!'s AccuracyCircle: the ring pops in, the grade bands draw, the accuracy
     arc fills (OutPow10, 3 s), badges light up as the arc passes them, and the letter lands at 1.5 s. */
  #ui .sv-ring{position:relative;width:min(300px,78vw);aspect-ratio:1}
  #ui .sv-ring svg{position:absolute;inset:0;width:100%;height:100%}
  #ui .sv-letter,#ui .sv-failed,#ui .sv-flash{position:absolute;inset:0;display:grid;place-items:center;font-size:clamp(56px,17vw,92px);line-height:1;letter-spacing:-.02em;opacity:0;pointer-events:none}
  /* osu!'s RankText: the letter is white, and only a tight glow (a 3 px blur in osu) carries the grade's
     colour. The flash is a heavily blurred copy of the letter at 1.8x that fades out, added on top like
     light; SS also gets a soft white burst behind it. */
  #ui .sv-letter{color:#fff;text-shadow:0 0 2px var(--gc),0 0 7px var(--gc)}
  #ui .sv-letter.g-SS{--gc:var(--g-SS)} #ui .sv-letter.g-S{--gc:var(--g-S)} #ui .sv-letter.g-A{--gc:var(--g-A)}
  #ui .sv-letter.g-B{--gc:var(--g-B)} #ui .sv-letter.g-C{--gc:var(--g-C)} #ui .sv-letter.g-D{--gc:var(--g-D)}
  #ui .sv-failed{color:var(--g-SS);text-shadow:0 0 2px currentColor,0 0 7px currentColor}
  #ui .sv-flash{inset:25%;color:var(--fc);scale:1.8;filter:blur(30px);mix-blend-mode:screen;mix-blend-mode:plus-lighter}
  #ui .sv-flash.super{inset:auto;left:50%;top:50%;width:62%;height:62%;translate:-50% -50%;scale:1;background:#fff;filter:blur(60px)}
  #ui .sv-badge .ov{opacity:0}
  #ui .ring-ctl{display:flex;gap:6px;flex-wrap:wrap;justify-content:center;align-items:center;margin-top:10px}
  #ui .ring-ctl .chip{min-height:30px;padding:3px 10px;border-radius:999px;border:1px solid var(--line-2);background:var(--panel-2);font-size:13px;font-weight:700;cursor:pointer}
  #ui .ring-ctl .chip[aria-pressed="true"]{border-color:var(--lane-b);background:#10232a}
  #ui .sv-score{font-size:clamp(36px,9vw,50px);font-weight:400;font-variant-numeric:tabular-nums;letter-spacing:.01em;line-height:1}
  #ui .sv-tags{display:flex;align-items:center;gap:6px;flex-wrap:wrap;justify-content:center}
  #ui .sv-star{font-size:13px;font-weight:900;border-radius:999px;padding:3px 10px;color:var(--bg)}
  #ui .sv-diff b{display:block;font-size:16px}
  #ui .sv-diff small{color:var(--muted);font-size:13px}
  #ui .sv-grid{width:100%;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;margin-top:4px}
  #ui .sv-grid.six{grid-template-columns:repeat(6,minmax(0,1fr))}
  #ui .sv-cell span{display:block;font-size:12px;font-weight:800;background:var(--panel-2);border-radius:999px;padding:2px 4px}
  #ui .sv-cell b{display:block;font-size:18px;font-variant-numeric:tabular-nums;margin-top:3px}
  #ui .sv-cell b small{font-size:12px;color:var(--muted);font-weight:700}
  #ui .sv-date{font-size:12px;color:var(--muted);margin-top:4px}
  @media (max-width:520px){#ui .sv-grid.six{grid-template-columns:repeat(3,minmax(0,1fr))}}

  /* ---------- results ---------- */
  #ui #results{padding-bottom:28px}
  #ui .res{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.9fr);gap:20px;align-items:start}
  #ui .place{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-l);padding:16px;display:flex;flex-direction:column;gap:12px}
  #ui .place .big{font-size:20px;font-weight:900;text-wrap:balance}
  /* ---------- statistics: osu!'s results statistics for mania (timing distribution, hit error, unstable
     rate, performance breakdown), plus a per-key split because TapTap has exactly two keys ---------- */
  #ui .rstats{display:flex;flex-direction:column;gap:14px;text-align:left}
  #ui .st-item h4{display:flex;align-items:center;gap:8px;margin:0 0 8px;font-size:14px;font-weight:800}
  #ui .st-item h4::before{content:"";width:16px;height:4px;border-radius:2px;background:var(--lane-b)}
  #ui .st-head{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}
  #ui .st-head h4{margin:0}
  #ui .st-legend{display:flex;gap:4px 12px;flex-wrap:wrap;font-size:12px;font-weight:700;color:var(--muted);margin:6px 0}
  #ui .st-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:5px;vertical-align:-1px}
  #ui .st-hist{position:relative;border-radius:var(--r-s)}
  #ui .st-hist svg{display:block;width:100%;height:auto}
  #ui .st-hist:focus-visible{outline:2px solid var(--lane-b);outline-offset:4px}
  #ui .st-axis{position:relative;height:18px;font-size:12px;font-weight:700;font-variant-numeric:tabular-nums}
  #ui .st-axis span{position:absolute;top:3px;translate:-50% 0}
  #ui .st-rows{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 12px;font-size:14px;margin-top:8px}
  #ui .st-rows span{color:var(--muted)}
  #ui .st-rows b{font-variant-numeric:tabular-nums;text-align:right}
  #ui .st-pp{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:6px 10px;align-items:center;font-size:14px}
  #ui .st-pp .bar{height:5px;border-radius:3px;background:rgba(255,255,255,.18);overflow:hidden}
  #ui .st-pp .bar i{display:block;height:100%;background:var(--lane-b);border-radius:3px}
  #ui .st-pp b{font-variant-numeric:tabular-nums}
  #ui .st-tot{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 12px;font-size:14px;margin-top:8px;font-variant-numeric:tabular-nums}
  #ui .st-tot .ach{color:var(--lane-b);font-weight:800}
  #ui .st-tot .max{color:var(--muted)}
  #ui .rstats table{width:100%;border-collapse:collapse;font-size:13px;margin-top:8px}
  #ui .rstats th,#ui .rstats td{text-align:right;padding:4px 6px;border-bottom:1px solid var(--line);font-variant-numeric:tabular-nums}
  #ui .rstats th:first-child,#ui .rstats td:first-child{text-align:left}
  #ui .rstats th{color:var(--muted);font-weight:700}
  #ui .st-cal{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:14px}
  #ui #viewerStats{padding:4px 2px}
  #ui .w-group{border-radius:var(--r-m);background:rgba(18,21,28,.35);transition:background-color .2s cubic-bezier(.22,1,.36,1)}
  #ui .w-group:hover,#ui .w-group:focus-within{background:rgba(18,21,28,.96)}
  #ui .w-ph{display:flex;align-items:center;justify-content:space-between;gap:8px;height:34px;padding:0 6px 0 12px}
  #ui .w-ph b{font-size:14px;transition:color .2s}
  #ui .w-group.folded .w-ph b{color:var(--muted)}
  #ui .w-fold{width:28px;height:28px;border:0;border-radius:50%;background:transparent;display:grid;place-items:center;cursor:pointer;opacity:.4;transition:opacity .2s}
  #ui .w-group:hover .w-fold,#ui .w-fold:focus-visible{opacity:1}
  #ui .w-fold svg{width:14px;height:14px;fill:currentColor;transition:rotate .25s cubic-bezier(.22,1,.36,1)}
  #ui .w-group.folded .w-fold svg{rotate:-90deg}
  #ui .w-gbody{display:grid;grid-template-rows:1fr;transition:grid-template-rows .25s cubic-bezier(.22,1,.36,1)}
  #ui .w-group.folded .w-gbody{grid-template-rows:0fr}
  #ui .w-gbody > div{overflow:hidden;min-height:0}
  #ui .w-gin{display:flex;flex-direction:column;gap:10px;padding:2px 12px 12px}
  /* ---------- map start: osu!'s PlayerLoader. The map's background (blurred and dimmed by the settings on
     the right), the map's details in the middle, disclaimers on the left and the player settings on the
     right. The metadata scales in from 0.7x (650 ms OutQuint) and fades in after 500 ms; the side
     columns slide in from their edges (500 ms OutQuint). Gameplay starts 1.8 s in, plus 0.5 s per
     disclaimer, but waits while the pointer is on a side column (after 0.5 s the cover reads "Loading
     paused…"). On the way out the middle shrinks back to 0.7x and the columns slide away. ---------- */
  #ui #stage.immersive .toolbar{display:none}
  #ui #loader{inset:0;padding:0;overflow:hidden}
  #ui .ld-scroll{position:absolute;inset:0}
  #ui .ld-bg{position:absolute;inset:-40px;background:radial-gradient(70% 60% at 30% 30%,hsl(var(--h) 45% 32%),transparent 70%),radial-gradient(60% 70% at 75% 70%,hsl(calc(var(--h) + 40) 40% 26%),transparent 70%),linear-gradient(160deg,hsl(var(--h) 30% 16%),#07080b);
    filter:blur(var(--blur,15px));transition:filter .2s}
  #ui .ld-dim{position:absolute;inset:0;background:#000;opacity:var(--dim,.6);transition:opacity .2s}
  #ui #loader.quick .ld-meta,#ui #loader.quick .ld-side,#ui #loader.quick .ld-disc,#ui #loader.quick .ld-hold{visibility:hidden}
  #ui #loader.quick::after{content:"";position:absolute;inset:0;background:#000;animation:ld-black .5s cubic-bezier(.22,1,.36,1) forwards}
  @keyframes ld-black{to{opacity:0}}
  #ui .ld-meta{position:absolute;left:50%;top:50%;translate:-50% -50%;display:flex;flex-direction:column;align-items:center;text-align:center;width:min(440px,calc(100% - 32px));opacity:0}
  #ui .ld-logo{width:64px;height:64px;border-radius:50%;background:radial-gradient(circle at 50% 35%,#2a3346,#11151e);box-shadow:0 0 0 3px rgba(255,255,255,.12);position:relative}
  #ui .ld-logo i{position:absolute;top:20%;bottom:24%;width:16%;border-radius:4px;background:rgba(255,255,255,.06)}
  #ui .ld-logo i:first-child{left:31%} #ui .ld-logo i:last-child{right:31%}
  #ui .ld-logo i::after{content:"";position:absolute;left:0;right:0;height:22%;border-radius:3px}
  #ui .ld-logo i:first-child::after{top:58%;background:var(--lane-a)} #ui .ld-logo i:last-child::after{top:20%;background:var(--lane-b)}
  #ui .ld-title{margin:15px 0 0;font-size:clamp(24px,6vw,34px);font-weight:800;line-height:1.3;text-wrap:balance}
  #ui .ld-artist{font-size:clamp(17px,4.5vw,22px);color:var(--text);opacity:.9;line-height:1.45}
  #ui .ld-cover{position:relative;width:min(300px,100%);height:60px;margin:10px;border-radius:10px;overflow:hidden;background:linear-gradient(120deg,hsl(var(--h) 45% 36%),hsl(calc(var(--h) + 40) 40% 22%))}
  #ui .ld-load{position:absolute;inset:0;display:grid;place-items:center;background:rgba(0,0,0,.45);transition:opacity .3s}
  #ui .ld-load.done{opacity:0}
  #ui .ld-spin{width:24px;height:24px;border-radius:50%;border:3px solid rgba(255,255,255,.25);border-top-color:#fff;animation:spin .8s linear infinite}
  @keyframes spin{to{rotate:360deg}}
  #ui .ld-paused{position:absolute;inset:0;display:grid;place-items:center;background:rgba(160,40,100,.5);font-weight:800;font-size:16px;opacity:0;pointer-events:none}
  #ui .ld-paused.on{animation:ld-pause 1.3s ease-in .5s infinite alternate both}
  @keyframes ld-pause{0%{opacity:0}23%{opacity:1}100%{opacity:.6}}
  #ui .ld-diff{font-size:clamp(17px,4.5vw,22px);font-weight:700;line-height:1.45}
  #ui .ld-star{display:inline-block;margin-top:5px;font-size:13px;font-weight:900;border-radius:999px;padding:3px 10px;color:var(--bg);opacity:0;transition:opacity .3s cubic-bezier(.64,0,.78,0)}
  #ui .ld-star.on{opacity:1}
  #ui .ld-lines{display:grid;grid-template-columns:auto auto;gap:2px 6px;margin-top:40px;font-size:14px;line-height:1.45}
  #ui .ld-lines span{text-align:right;color:var(--muted)} #ui .ld-lines b{text-align:left;font-weight:700}
  #ui .ld-mods{display:flex;gap:6px;justify-content:center;flex-wrap:wrap;margin-top:20px;min-height:30px}
  #ui .ld-disc{position:absolute;left:0;top:0;width:min(320px,100%);padding:25px;display:flex;flex-direction:column;gap:20px}
  #ui .ld-dc{display:flex;gap:12px;padding:10px;border-radius:5px;background:rgba(18,21,28,.25);transition:background-color .5s cubic-bezier(.22,1,.36,1)}
  #ui .ld-dc:hover{background:rgba(18,21,28,.95)}
  #ui .ld-dc i{flex:none;width:7px;margin-top:2px;border-radius:4px;background:var(--lane-a)}
  #ui .ld-dc b{display:block;font-size:15px;line-height:1.4}
  #ui .ld-dc p{margin:2px 0 0;font-size:14px;line-height:1.45;color:var(--muted)}
  #ui .ld-side{position:absolute;right:0;top:0;bottom:0;width:min(320px,100%);padding:25px;display:flex;flex-direction:column;gap:20px;overflow:auto}
  #ui .ld-side .w-group{background:rgba(18,21,28,.35)}
  #ui .ld-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 8px;font-size:13px;font-weight:700}
  #ui .ld-row output{font-variant-numeric:tabular-nums}
  #ui .ld-row input[type=range]{grid-column:1/-1;width:100%;accent-color:var(--lane-b)}
  #ui .ld-cal{font-size:12px;color:var(--muted);line-height:1.5}
  #ui .ld-cal button{margin-top:6px}
  #ui .ld-hold{position:absolute;right:25px;bottom:25px;display:flex;align-items:center;gap:10px;border:0;background:transparent;color:var(--muted);font-size:13px;font-weight:700;cursor:pointer;padding:6px}
  #ui .ld-hold span{opacity:0;transition:opacity .2s}
  #ui .ld-hold:hover span,#ui .ld-hold:focus-visible span,#ui .ld-hold.down span{opacity:1}
  #ui .ld-hold svg{width:30px;height:30px;rotate:-90deg}
  #ui .ld-hold .bgc{fill:none;stroke:rgba(255,255,255,.18);stroke-width:3}
  #ui .ld-hold .fgc{fill:none;stroke:#fff;stroke-width:3;stroke-dasharray:0 100}
  @media (max-width:860px){
    /* No room for three columns: the details sit at the top, settings and disclaimers stack below. */
    #ui .ld-scroll{overflow:hidden auto}
    #ui .ld-meta{position:relative;left:auto;top:auto;translate:none;margin:28px auto 8px}
    #ui .ld-disc,#ui .ld-side{position:relative;width:auto;bottom:auto;padding:12px 16px;overflow:visible}
    #ui .ld-hold{position:relative;right:auto;bottom:auto;margin:0 auto 20px}
  }

  /* osu!'s SkipOverlay: during a long intro a wide SKIP button sits 70% down the screen with a thin bar
     that runs out as the skippable time does. Hovering spreads the chevrons; pressing squashes it. */
  #ui .w-skip{position:absolute;left:0;right:0;top:70%;height:100px;translate:0 -50%;display:grid;place-items:center;opacity:0;visibility:hidden;transition:opacity .3s,visibility 0s .3s;z-index:2}
  #ui .w-skip.on{opacity:1;visibility:visible;transition:opacity .3s,visibility 0s}
  #ui .w-skip::before{content:"";position:absolute;inset:0;background:rgba(0,0,0,.2)}
  #ui .w-skip button{position:relative;height:60%;aspect-ratio:3.2;border:0;border-radius:15px;cursor:pointer;font-weight:900;font-size:17px;letter-spacing:.06em;
    background:linear-gradient(180deg,#ffbf6b,var(--lane-a));color:var(--lane-a-ink);display:grid;place-items:center;transition:scale 1s cubic-bezier(.34,1.56,.64,1),filter .5s}
  #ui .w-skip button:hover{filter:brightness(1.1)}
  #ui .w-skip button:active{scale:.85;transition:scale 2s cubic-bezier(.22,1,.36,1)}
  #ui .w-skip .chev{display:flex;gap:0;transition:gap .5s cubic-bezier(.22,1,.36,1)}
  #ui .w-skip button:hover .chev{gap:5px}
  #ui .w-skip .chev svg{width:15px;height:15px;fill:currentColor}
  #ui .w-skip .left{position:absolute;left:50%;bottom:0;translate:-50% 0;height:5px;border-radius:3px;background:#d9822b;width:var(--left,100%)}
  #ui .ld-hold.w-holdm{position:absolute;right:16px;bottom:70px;margin:0;z-index:2}
  /* ---------- pause and fail menus: osu!'s GameplayMenuOverlay. Black at 75% over the frozen field, the
     header in big lowercase, full-width slanted buttons that widen and glow when hovered or picked with
     the arrow keys, then the retry count, song progress and accuracy. A fail first plays osu!'s fail
     animation: the song winds down, the field tilts a degree and greys out under a fading red flash. With
     OT!skin the menu uses the skin's own art (pause-overlay and its button sprites), as the game does;
     its fail menu swaps the overlay art for a dark red wash. Continue counts 3-2-1 back in (osu!mania's
     DelayedResumeOverlay, 2 s). ---------- */
  #ui .w-red{position:absolute;inset:0;background:#f00;opacity:0;pointer-events:none}
  #ui .w-field.failing #watchCanvas{transform:rotate(1deg);filter:grayscale(1) brightness(.6);transition:transform 2.5s cubic-bezier(.165,.84,.44,1),filter 2.5s}
  #ui .gm{position:absolute;inset:0;z-index:4;display:grid;grid-template-rows:minmax(0,1fr) auto;background:rgba(0,0,0,.75);animation:gm-in .2s ease-in}
  @keyframes gm-in{from{opacity:0}}
  #ui .gm-in{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:26px;padding:24px 0;overflow:auto}
  /* The menu header has its own font: Comfortaa, the user's pick (osu! sets "paused" / "failed" in Torus
     Alternate, a commercial font). The mockup bar still switches it for comparison. */
  #ui .gm-h{margin:0;font-family:var(--gm-font,"Comfortaa",var(--ui));font-style:var(--gm-style,normal);font-weight:var(--gm-weight,700);font-size:clamp(38px,8vw,54px);letter-spacing:.12em;color:var(--gold);line-height:1.1}
  #ui .gm-btns{width:min(560px,100%);display:flex;flex-direction:column;gap:8px;padding:0 24px}
  #ui .gm-b{position:relative;display:grid;place-items:center;width:80%;margin:0 auto;height:62px;border:0;background:transparent;cursor:pointer;
    color:#fff;font-weight:800;font-size:19px;letter-spacing:.02em;transition:width .4s cubic-bezier(.22,1,.36,1),letter-spacing .4s cubic-bezier(.22,1,.36,1)}
  #ui .gm-b::before{content:"";position:absolute;inset:0;transform:skewX(-12deg);border-radius:6px;background:var(--bc);transition:box-shadow .4s cubic-bezier(.22,1,.36,1),filter .2s}
  #ui .gm-b span{position:relative}
  #ui .gm-b:hover,#ui .gm-b.sel{width:90%;letter-spacing:.08em}
  #ui .gm-b:hover::before,#ui .gm-b.sel::before{box-shadow:0 0 30px color-mix(in srgb,var(--bc) 65%,transparent)}
  #ui .gm-b:active::before{filter:brightness(1.15)}
  #ui .gm-b:focus-visible{outline:none}
  #ui .gm-b:focus-visible::before{outline:2px solid #fff;outline-offset:3px}
  #ui .gm-info{margin:0;text-align:center;font-size:15px;line-height:1.7}
  #ui .gm-foot{display:flex;justify-content:center;align-items:center;gap:14px;flex-wrap:wrap;padding:10px 16px;background:#1d2028;font-size:14px}
  #ui .gm.skin{background:#07060a var(--gm-art,none) center/cover no-repeat}
  #ui .gm.skin.fail{background:radial-gradient(ellipse at 50% 40%,rgba(58,10,16,.72),rgba(7,6,10,.94) 70%)}
  #ui .gm.skin:not(.fail) .gm-h,#ui .gm.skin .gm-info{display:none}
  #ui .gm.skin .gm-btns{gap:14px}
  #ui .gm.skin .gm-b{width:auto;height:auto}
  #ui .gm.skin .gm-b::before{display:none}
  #ui .gm.skin .gm-b img{display:block;height:clamp(64px,12vh,112px);width:auto;transition:filter .2s,scale .4s cubic-bezier(.22,1,.36,1)}
  #ui .gm.skin .gm-b:hover img,#ui .gm.skin .gm-b.sel img{filter:brightness(1.15);scale:1.05}
  #ui .gm.skin .gm-b:focus-visible img{outline:2px solid #fff;outline-offset:4px;border-radius:12px}
  #ui .gm.skin .gm-b span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  #ui .gm-cd{position:absolute;left:50%;top:45%;translate:-50% -50%;width:min(200px,50vw);aspect-ratio:1;z-index:4;display:grid;place-items:center}
  #ui .gm-cd svg{position:absolute;inset:0;width:100%;height:100%}
  #ui .gm-cd .o{fill:rgba(0,0,0,.45)}
  #ui .gm-cd .i{fill:rgba(18,21,28,.92)}
  #ui .gm-cd .p{fill:none;stroke:#fff;stroke-width:7;stroke-dasharray:0 100;transform:rotate(-90deg);transform-origin:100px 100px}
  #ui .gm-cd b{position:relative;font-size:clamp(44px,12vw,70px);font-weight:400;font-variant-numeric:tabular-nums}
  @media (prefers-reduced-motion:reduce){#ui .gm{animation:none}#ui .gm-b,#ui .gm-b::before,#ui .w-field.failing #watchCanvas{transition:none}}
  #ui .actions{display:flex;gap:8px;flex-wrap:wrap}
  @media (max-width:880px){#ui .res{grid-template-columns:1fr}}
  /* ---------- beatmap listing ---------- */
  #ui #listing{padding-bottom:28px}
  #ui .filters{display:flex;gap:10px 14px;flex-wrap:wrap;align-items:center;margin-bottom:14px}
  #ui .maps{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,340px),1fr));gap:12px}
  #ui .map{position:relative;display:flex;background:var(--panel);border:1px solid var(--line);border-radius:var(--r-l);min-width:0}
  #ui .map:hover,#ui .map:focus-within{z-index:3}
  #ui .pv{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:42px;height:42px;border-radius:50%;border:0;background:rgba(8,9,12,.75);
    display:grid;place-items:center;cursor:pointer;color:var(--text);opacity:0;transition:opacity .15s}
  #ui .map:hover .pv,#ui .pv:focus-visible,#ui .pv[aria-pressed="true"]{opacity:1}
  @media (hover:none){#ui .pv{opacity:1}}
  #ui .pv svg{width:14px;height:14px;fill:currentColor;display:block}
  #ui .pvbar{position:absolute;left:0;bottom:0;height:3px;width:0;background:var(--lane-b)}
  #ui .diffpop{position:relative;display:inline-flex}
  #ui .dots-btn{border:0;background:transparent;padding:6px 4px;cursor:pointer;border-radius:var(--r-s)}
  #ui .pop{display:none;position:absolute;left:-6px;top:calc(100% + 6px);z-index:10;width:max-content;min-width:200px;max-width:min(280px,calc(100vw - 48px));
    flex-direction:column;gap:2px;background:var(--panel-2);border:1px solid var(--line-2);border-radius:var(--r-m);padding:8px;box-shadow:0 14px 40px rgba(0,0,0,.55);animation:fade .12s ease-out}
  #ui .pop > b{font-size:12px;color:var(--muted);padding:0 4px 4px}
  #ui .diffpop:hover .pop,#ui .diffpop:focus-within .pop,#ui .diffpop.open .pop{display:flex}
  #ui .pd{display:flex;align-items:center;gap:8px;padding:3px 4px;font-size:14px;font-weight:700}
  #ui .pd .pill{font-size:12px;font-weight:900;border-radius:999px;padding:2px 8px;color:var(--bg);min-width:58px;text-align:center;font-variant-numeric:tabular-nums}
  #ui .map.in{animation:fade .3s ease-out both}
  #ui .cover{position:relative;width:104px;flex:none;overflow:hidden;border-radius:var(--r-l) 0 0 var(--r-l);background:linear-gradient(160deg,hsl(var(--h) 38% 26%),hsl(var(--h) 30% 12%))}
  #ui .cover i{position:absolute;top:0;bottom:0;width:22%;background:rgba(255,255,255,.06)}
  #ui .cover i:first-child{left:26%}#ui .cover i:nth-child(2){left:52%}
  #ui .cover b{position:absolute;left:0;right:0;bottom:22%;height:3px;background:rgba(255,255,255,.55)}
  #ui .map-body{flex:1;min-width:0;padding:10px 12px;display:flex;flex-direction:column;gap:4px}
  #ui .map-body .t{font-weight:800;font-size:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #ui .map-body .a{font-size:13px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #ui .map-foot{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:auto}
  #ui .dl{margin-left:auto;min-height:34px;padding:5px 12px;font-size:13px}
  #ui .prog{height:4px;border-radius:2px;background:var(--line);overflow:hidden;margin-top:6px}
  #ui .prog i{display:block;height:100%;background:var(--lane-b);width:0;transition:width .12s linear}
  /* ---------- replays ---------- */
  #ui #replays{padding-bottom:28px}
  #ui .reps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
  #ui .rep{display:grid;grid-template-columns:minmax(0,1.5fr) 2.4em minmax(0,1.2fr) auto;gap:12px;align-items:center;padding:10px 12px;border:1px solid var(--line);border-radius:var(--r-l);background:var(--panel)}
  #ui .rep.in{animation:row-in .28s ease-out both}
  #ui .rep .t{font-weight:800}
  #ui .rep .s{font-size:13px;color:var(--muted)}
  #ui .rep .nums{font-size:14px;color:var(--muted);display:flex;gap:6px 10px;flex-wrap:wrap;align-items:center}
  #ui .rep .nums b{color:var(--text);font-variant-numeric:tabular-nums}
  #ui .rep .gr{font-size:24px;text-align:center}
  #ui .acts{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
  #ui .acts button{min-height:34px;padding:5px 10px;border-radius:var(--r-s);border:1px solid var(--line-2);background:var(--raise);font-size:13px;font-weight:700;cursor:pointer}
  #ui .acts button:disabled{cursor:not-allowed;opacity:.5}
  #ui .acts .danger{color:var(--miss)}
  #ui .missing-note{color:var(--miss)}
  @media (max-width:760px){#ui .rep{grid-template-columns:2.2em minmax(0,1fr)}#ui .rep .gr{grid-row:1 / span 2;grid-column:1}#ui .rep .acts{grid-column:1 / -1;justify-content:flex-start}}

  /* ---------- tools ---------- */
  #ui #tools{padding-bottom:28px}
  #ui .tools{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr));gap:10px}
  #ui .tools li{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-m);padding:12px 14px}
  #ui .tools b{display:block;font-size:16px;margin-bottom:2px}
  #ui .tools p{margin:0;font-size:14px;color:var(--muted);line-height:1.5}

  /* ---------- overlays ---------- */
  #ui .scrim{position:absolute;inset:0;z-index:30;background:rgba(5,6,9,.66)}
  #ui .sheet{position:absolute;z-index:31;background:var(--panel);border:1px solid var(--line-2);overflow:auto}
  #ui #modSelect{left:50%;top:50%;transform:translate(-50%,-50%);width:min(1000px,calc(100% - 24px));max-height:calc(100% - 24px);border-radius:var(--r-l);padding:18px;box-shadow:0 30px 80px rgba(0,0,0,.6)}
  #ui #modSelect:not([hidden]),#ui #viewer:not([hidden]){animation:sheet-in .2s ease-out}
  @keyframes sheet-in{from{opacity:0;transform:translate(-50%,-48%)}to{opacity:1;transform:translate(-50%,-50%)}}
  #ui #viewer{left:50%;top:50%;transform:translate(-50%,-50%);width:min(520px,calc(100% - 24px));max-height:calc(100% - 24px);border-radius:var(--r-l);padding:16px;background:var(--bg)}
  #ui .viewer-actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin-top:12px}
  #ui .mods-head{display:flex;align-items:flex-end;gap:10px 18px;flex-wrap:wrap;margin-bottom:14px}
  #ui .mods-head h3{margin:0 auto 0 0;font-size:24px;font-weight:900}
  #ui .mult-big{font-size:30px;font-weight:900;color:var(--lane-a);font-variant-numeric:tabular-nums;line-height:1}
  #ui .mods-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,230px),1fr));gap:12px}
  #ui .group{display:flex;flex-direction:column;gap:8px;min-width:0}
  #ui .group h4{margin:0;font-size:14px;font-weight:800;display:flex;align-items:center;gap:8px}
  #ui .group h4 i{width:10px;height:10px;border-radius:3px}
  /* A mod tile changes state in place (rebuilding the grid recreated every icon, which blinked): the
     colours ease over, the icon dips while pressed and bounces when the mod turns on, and the options
     unfold under it. */
  #ui .tile{border:1px solid var(--line);border-radius:var(--r-m);background:var(--panel-2);transition:border-color .2s,background-color .2s}
  #ui .tile > button .mslot{transition:scale .15s cubic-bezier(.22,1,.36,1)}
  #ui .tile > button:active .mslot{scale:.86}
  #ui .tile .mx{transition:color .2s}
  #ui .tile > button{display:flex;align-items:center;gap:10px;width:100%;min-height:56px;padding:8px 10px;border:0;background:transparent;cursor:pointer;text-align:left}
  #ui .tile .nm{display:block;font-weight:800;font-size:15px}
  #ui .tile .ds{display:block;font-size:13px;color:var(--muted)}
  #ui .tile .mx{margin-left:auto;font-size:13px;font-weight:800;color:var(--muted);font-variant-numeric:tabular-nums}
  #ui .tile.on{border-color:var(--lane-a);background:#1b1710}
  #ui .tile.on .mx{color:var(--lane-a)}
  #ui .opts-w{display:grid;grid-template-rows:0fr;transition:grid-template-rows .25s cubic-bezier(.22,1,.36,1)}
  #ui .tile.on .opts-w{grid-template-rows:1fr}
  #ui .opts-w > div{min-height:0;overflow:hidden}
  #ui .opts{display:flex;flex-direction:column;gap:8px;padding:2px 12px 12px;opacity:0;transition:opacity .2s}
  #ui .tile.on .opts{opacity:1}
  #ui #modsOn .mo{display:inline-flex;align-items:center;gap:3px}
  @media (prefers-reduced-motion:reduce){#ui .tile,#ui .tile .mx,#ui .opts,#ui .opts-w,#ui .tile > button .mslot{transition:none}}
  #ui .slider{display:grid;grid-template-columns:4.5em 1fr 3.4em;gap:8px;align-items:center;font-size:13px;color:var(--muted)}
  #ui .slider input{width:100%;accent-color:var(--lane-a);min-height:28px}
  #ui .slider output{font-weight:800;color:var(--text);text-align:right;font-variant-numeric:tabular-nums}
  #ui .check{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--muted);min-height:28px}
  #ui .check input{accent-color:var(--lane-a);width:16px;height:16px}
  #ui .status{margin-top:14px;padding:10px 12px;border-radius:var(--r-m);border:1px solid var(--line);background:var(--panel-2);display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap}
  #ui .status p{margin:0;font-size:14px;line-height:1.5;color:var(--muted);flex:1;min-width:220px}
  #ui .status p b{color:var(--text)}
  #ui .ranked-chip{display:inline-block;font-size:12px;font-weight:900;letter-spacing:.04em;color:var(--ok);background:rgba(126,231,135,.12);border-radius:var(--r-s);padding:2px 7px}
  #ui .sheet-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:12px;flex-wrap:wrap}

  #ui #settings{left:0;top:0;bottom:0;width:min(440px,100%);border-radius:0 var(--r-l) var(--r-l) 0;padding:16px 18px calc(16px + env(safe-area-inset-bottom,0px)) max(18px,env(safe-area-inset-left,0px))}
  #ui #settings:not([hidden]){animation:side-in .22s ease-out}
  @keyframes side-in{from{transform:translateX(-24px);opacity:0}to{transform:none;opacity:1}}
  #ui #settings h3{margin:0;font-size:24px;font-weight:900}
  #ui .sec{border-top:1px solid var(--line);padding:12px 0;display:flex;flex-direction:column;gap:6px}
  #ui .sec h4{margin:0 0 2px;font-size:15px;font-weight:900;color:var(--lane-b)}
  #ui .row{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:15px;min-height:40px}
  #ui .row label,#ui .row > span:first-child{flex:1}
  #ui .row select{background:var(--panel-2);border:1px solid var(--line-2);border-radius:var(--r-s);padding:5px 8px;min-height:34px;font-size:14px;max-width:58%}
  #ui .row input[type=range]{width:42%;accent-color:var(--lane-a)}
  #ui .sec .note{margin:-2px 0 4px;font-size:12.5px;line-height:1.4;color:var(--muted)}
  #ui .row output{min-width:3.6em;text-align:right;font-weight:800;font-variant-numeric:tabular-nums}
  #ui .switch{appearance:none;width:42px;height:24px;border-radius:999px;background:#2b3242;position:relative;cursor:pointer;flex:none;transition:background .15s}
  #ui .switch::after{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--text);transition:transform .15s}
  #ui .switch:checked{background:var(--lane-b)}
  #ui .switch:checked::after{transform:translateX(18px)}
  #ui .keycap{min-width:48px;min-height:36px;text-align:center;font-weight:900;border:1px solid var(--line-2);border-bottom-width:3px;border-radius:var(--r-s);padding:4px 10px;background:var(--raise);cursor:pointer}
  #ui .keycap.wait{border-color:var(--lane-a);color:var(--lane-a)}
  /* ---------- rankings and friends panels ---------- */
  #ui .panel-lg{left:50%;top:50%;transform:translate(-50%,-50%);width:min(1100px,calc(100% - 24px));height:calc(100% - 24px);border-radius:var(--r-l);
    padding:16px 18px;display:flex;flex-direction:column;gap:12px;box-shadow:0 30px 80px rgba(0,0,0,.6)}
  #ui #rankings:not([hidden]),#ui #friends:not([hidden]){animation:sheet-in .2s ease-out}
  #ui .panel-head{display:flex;align-items:center;gap:10px 14px;flex-wrap:wrap}
  #ui .adm-tools{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:12px 0 6px}
  #ui .adm-row{display:flex;align-items:center;gap:8px 14px;padding:10px 2px;border-top:1px solid var(--line)}
  #ui .adm-row .info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
  #ui .adm-row .info b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  #ui .adm-row .info small{font-size:13px;color:var(--muted);line-height:1.5}
  @media (max-width:600px){#ui .adm-row{flex-wrap:wrap}#ui .adm-row .acts{width:100%;justify-content:flex-start}}
  #ui .adm-h{margin:18px 0 4px;font-size:16px;font-weight:900}
  #ui .adm-invite label{display:flex;align-items:center;gap:6px}
  #ui .adm-invite label .search{width:90px}
  #ui .adm-invite #invNote{width:min(260px,60vw)}
  #ui .acct-hint{margin:-2px 0 0;line-height:1.5}
  #ui .adm-set .acts{display:flex;gap:8px;align-items:center}
  #ui .adm-set .search{width:min(220px,40vw)}
  #ui .maps-foot{text-align:center;margin:18px 0 6px;line-height:1.6}
  #ui .maps-foot a{color:inherit}
  #ui .acct-note{margin:12px 0 0;padding:10px 12px;border-radius:var(--r-m);background:#2a1414;font-size:14px;line-height:1.5}
  #ui .panel-head h3{margin:0 auto 0 0;font-size:24px;font-weight:900}
  #ui .rk{container-type:inline-size;overflow-y:auto;overflow-x:hidden;flex:1;min-height:0}
  #ui .rk-row{display:grid;grid-template-columns:3.2em minmax(0,1fr) 5.4em 6em 7.4em 3.4em 3.4em 3.4em;gap:10px;align-items:center;padding:9px 12px;border-radius:var(--r-m);
    background:var(--raise);margin-bottom:6px;font-variant-numeric:tabular-nums;font-size:14px}
  #ui .rk-row.head{background:transparent;color:var(--muted);font-size:13px;font-weight:800;padding-block:2px;margin-bottom:2px}
  #ui .rk-row.me{background:#2a1f10}
  #ui .rk-row.in{animation:row-in .28s ease-out both}
  #ui .rk-row .r{text-align:right}
  #ui .rk-row .pos{font-weight:900;color:var(--muted)}
  #ui .rk-row.me .pos{color:var(--lane-a)}
  #ui .rk-row .who{display:flex;align-items:center;gap:10px;min-width:0}
  #ui .rk-row .who .av{width:32px;height:32px;font-size:15px;border-radius:8px}
  #ui .rk-row .who b{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #ui .rk-row .key{font-weight:900}
  #ui .rk-row.head .key{color:var(--text)}
  #ui .rk-g{font-size:15px}
  @container (max-width:720px){#ui .rk-row{grid-template-columns:2.8em minmax(0,1fr) 5em 6.8em}#ui .rk-row .wide{display:none}}
  #ui button.rk-row{border:0;width:100%;text-align:left;color:inherit;cursor:pointer}
  #ui button.rk-row:hover{background:#1d2331}
  #ui button.rk-row.me:hover{background:#33260f}

  /* ---------- profile ---------- */
  #ui #profile{padding:0;display:block;overflow:hidden}
  #ui #profile:not([hidden]){animation:sheet-in .2s ease-out}
  #ui #pfBody,#ui .pf{height:100%}
  #ui .pf{overflow-y:auto}
  #ui .pf-cover{height:120px;background:linear-gradient(120deg,hsl(var(--h) 40% 24%),hsl(calc(var(--h) + 50) 35% 13%))}
  #ui .pf-head{display:flex;align-items:flex-end;gap:14px 16px;flex-wrap:wrap;padding:0 20px;margin-top:-44px}
  #ui .pf-head .av{width:96px;height:96px;font-size:42px;border-radius:20px;box-shadow:0 0 0 5px var(--panel)}
  #ui .pf-id{flex:1;min-width:180px;padding-bottom:4px}
  #ui .pf-id h3{margin:0;font-size:26px;font-weight:900}
  #ui .pf-acts{display:flex;gap:8px;padding-bottom:4px;flex-wrap:wrap}
  #ui .pf-acts [aria-pressed="true"]{border-color:var(--lane-b)}
  #ui .pf-body{padding:16px 20px 22px;display:flex;flex-direction:column;gap:18px}
  #ui .pf-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px}
  #ui .pf-tile{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-m);padding:10px 12px}
  #ui .pf-tile span{display:block;font-size:12px;color:var(--muted);font-weight:700}
  #ui .pf-tile b{font-size:18px;font-variant-numeric:tabular-nums}
  #ui .pf-tile.big b{font-size:28px}
  #ui .pf-grades{display:flex;gap:18px;flex-wrap:wrap}
  #ui .pf-grades div{display:flex;align-items:baseline;gap:8px;font-size:16px}
  #ui .pf-grades .gl{font-size:24px}
  #ui .pf-sec h4{margin:0;font-size:16px;font-weight:900}
  #ui .pf-sec-h{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px;flex-wrap:wrap}
  #ui .chart{position:relative;border-radius:var(--r-s)}
  #ui .chart svg{display:block;width:100%;height:auto}
  #ui .chart:focus-visible{outline:2px solid var(--lane-b);outline-offset:4px}
  #ui .tip{position:absolute;pointer-events:none;transform:translate(-50%,calc(-100% - 10px));background:var(--panel-2);border:1px solid var(--line-2);
    border-radius:var(--r-s);padding:4px 8px;font-size:13px;font-weight:800;white-space:nowrap;font-variant-numeric:tabular-nums}
  #ui .pf table{width:100%;border-collapse:collapse;font-size:14px}
  #ui .pf th,#ui .pf td{text-align:left;padding:5px 8px;border-bottom:1px solid var(--line);font-variant-numeric:tabular-nums}
  #ui .pf th{color:var(--muted);font-size:13px}
  #ui .pf-plays{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}
  #ui .pf-play{display:grid;grid-template-columns:2.2em minmax(0,1fr) auto 4.8em 6em;gap:10px;align-items:center;width:100%;padding:8px 12px;
    border:1px solid var(--line);border-radius:var(--r-m);background:var(--raise);cursor:pointer;text-align:left}
  #ui .pf-play:hover{border-color:var(--lane-b)}
  #ui .pf-play .gl{font-size:20px;text-align:center}
  #ui .pf-play .t{display:block;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #ui .pf-play small{display:block;color:var(--muted);font-size:12px}
  #ui .pf-play .r{text-align:right;font-variant-numeric:tabular-nums}
  #ui .pf-play .pp b{display:block;font-size:16px}
  @media (max-width:640px){#ui .pf-play{grid-template-columns:2em minmax(0,1fr) 5.4em}#ui .pf-play .acc,#ui .pf-play .modset{display:none}#ui .pf-head{margin-top:-40px}}
  #ui .dropzone{position:absolute;inset:10px;z-index:40;border:2px dashed var(--lane-b);border-radius:var(--r-l);background:rgba(8,20,24,.86);
    display:grid;place-items:center;text-align:center;font-size:20px;font-weight:900;pointer-events:none;animation:fade .15s ease-out}
  #ui .dropzone small{display:block;font-size:14px;font-weight:600;color:var(--muted);margin-top:4px}
  #ui .toast{position:absolute;left:50%;top:12px;transform:translateX(-50%);z-index:60;background:var(--panel);border:1px solid var(--line-2);
    border-radius:var(--r-m);padding:9px 14px;font-size:14px;font-weight:700;max-width:calc(100% - 32px);animation:fade .15s ease-out}

  @media (pointer:coarse){#ui .btn,#ui .seg button,#ui .search,#ui .acts button,#ui .diff,#ui .keycap,#ui .pick select{min-height:44px}}
  @media (prefers-reduced-motion:reduce){#ui *,#ui *::before,#ui *::after{animation:none!important;transition:none!important}}

/* ---------- the game around the menus ---------- */
#ui{position:fixed;inset:0;z-index:50;display:flex;flex-direction:column;-webkit-user-select:none;user-select:none}
#ui input[type=search],#ui input[type=text]{-webkit-user-select:text;user-select:text}
/* The setup panel's element styles must not reach the menus. */
#ui select{width:auto}
#ui output{min-width:0;font-size:inherit;color:inherit}
#ui input[type=range]{flex:none}
#ui #stage{flex:1}
/* In play the menus step aside: only the pause / fail menus, the countdown and the skip button take input. */
#ui.ingame{background:transparent;pointer-events:none}
#ui.ingame #stage{display:none}
#ui .playlayer{position:absolute;inset:0;pointer-events:none}
#ui .playlayer .gm,#ui .playlayer .w-skip.on button{pointer-events:auto}
#ui .ld-quickflash{position:absolute;inset:0;z-index:6;background:#000;pointer-events:none}
#ui.legacy{display:none}
/* The selected map's background behind song select, and its real picture on the map start screen. */
#ui .sel-bg{position:absolute;inset:0;background:center/cover no-repeat;opacity:0;transition:opacity .4s;pointer-events:none}
#ui .sel-bg.on{opacity:.22}
#ui #select > :not(.sel-bg){position:relative}
/* ...except the Play bar, which stays on screen while the song select scrolls (a phone, a short window). */
#ui #select > .bottom{position:sticky}
#ui .ld-bg.img{background:#07080b center/cover no-repeat}
#ui .ld-cover.img{background:#07080b center/cover no-repeat}
/* A player name inside a list row opens their profile. */
#ui .linkish{border:0;background:none;padding:0;font:inherit;color:var(--text);font-weight:700;cursor:pointer}
#ui .linkish:hover{color:var(--lane-b);text-decoration:underline}
/* The account sheet (online server only). */
#ui #account{left:50%;top:50%;transform:translate(-50%,-50%);width:min(400px,calc(100% - 24px));max-height:calc(100% - 24px);border-radius:var(--r-l);padding:18px;box-shadow:0 30px 80px rgba(0,0,0,.6)}
#ui #account:not([hidden]){animation:sheet-in .2s ease-out}
#ui .acct-form{display:flex;flex-direction:column;gap:12px;margin-top:16px}
#ui .acct-form label{display:flex;flex-direction:column;gap:5px;font-size:13px;font-weight:700;color:var(--muted)}
#ui .acct-form .search{width:100%;color:var(--text)}
#ui .acct-form .sheet-actions{margin-top:0}
#ui .acct-err{min-height:1.5em;margin:0;font-size:13px;color:var(--miss)}
#ui .acct-me{display:flex;align-items:center;gap:14px}
#ui .acct-name{font-size:20px;font-weight:800}
#ui .tb .tb-label{font-size:14px}
/* The setup panel, opened from Tools, gets a way back. */
.ui-back{position:fixed;left:16px;top:16px;z-index:45}
