/* The site's own fonts (tools/subset_fonts.py; SIL Open Font License, fonts/OFL-*.txt), split by
   script: a browser downloads only the pieces a page's text needs. */
/* fonts: begin (written by tools/subset_fonts.py) */
@font-face{font-family:"Inter";src:url(../fonts/inter-latin.woff2) format("woff2");font-weight:400 800;font-display:swap;unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+2605, U+2713, U+FEFF, U+FFFD}
@font-face{font-family:"Inter";src:url(../fonts/inter-latin-ext.woff2) format("woff2");font-weight:400 800;font-display:swap;unicode-range:U+0100-024F, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Inter";src:url(../fonts/inter-vietnamese.woff2) format("woff2");font-weight:400 800;font-display:swap;unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"Inter";src:url(../fonts/inter-cyrillic.woff2) format("woff2");font-weight:400 800;font-display:swap;unicode-range:U+0400-052F, U+1C80-1C8A, U+20B4, U+2116, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F}
@font-face{font-family:"Inter";src:url(../fonts/inter-greek.woff2) format("woff2");font-weight:400 800;font-display:swap;unicode-range:U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF, U+1F00-1FFF}
@font-face{font-family:"JetBrains Mono";src:url(../fonts/jetbrains-mono-latin.woff2) format("woff2");font-weight:500 700;font-display:swap;unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+2605, U+2713, U+FEFF, U+FFFD}
@font-face{font-family:"JetBrains Mono";src:url(../fonts/jetbrains-mono-latin-ext.woff2) format("woff2");font-weight:500 700;font-display:swap;unicode-range:U+0100-024F, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"JetBrains Mono";src:url(../fonts/jetbrains-mono-vietnamese.woff2) format("woff2");font-weight:500 700;font-display:swap;unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"JetBrains Mono";src:url(../fonts/jetbrains-mono-cyrillic.woff2) format("woff2");font-weight:500 700;font-display:swap;unicode-range:U+0400-052F, U+1C80-1C8A, U+20B4, U+2116, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F}
@font-face{font-family:"JetBrains Mono";src:url(../fonts/jetbrains-mono-greek.woff2) format("woff2");font-weight:500 700;font-display:swap;unicode-range:U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF, U+1F00-1FFF}
@font-face{font-family:"Lilita One";src:url(../fonts/lilita-one-latin.woff2) format("woff2");font-weight:400;font-display:swap;unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+2605, U+2713, U+FEFF, U+FFFD}
@font-face{font-family:"Lilita One";src:url(../fonts/lilita-one-latin-ext.woff2) format("woff2");font-weight:400;font-display:swap;unicode-range:U+0100-024F, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
/* fonts: end */
:root{
  --bg:#0f0a26; --bg2:#160f36; --panel:#1d1446; --panel2:#251a58; --line:#3a2b80;
  --text:#f1ecff; --muted:#a99fd6; --faint:#9186c4;
  --violet:#7b4dff; --violet2:#9a74ff; --lav:#e7defe;
  --gold:#ffb627; --orange:#ff7a2f; --red:#ff4d6d; --green:#46d37e; --teal:#3cc7c0;
  --radius:14px; --shadow:0 10px 30px rgba(0,0,0,.35);
  --edge:#7563c4;  /* borders that mark a control: 3.5:1 on the panels (WCAG non-text contrast) */
  color-scheme:dark;
}
*{box-sizing:border-box}
html,body{margin:0}
body{background:radial-gradient(1200px 600px at 50% -200px,#2a1a6e 0%,transparent 70%),var(--bg);color:var(--text);
  font:15px/1.5 Inter,system-ui,sans-serif;min-height:100vh;overflow-x:hidden}
a{color:inherit;text-decoration:none}
a.link{color:var(--violet2);text-decoration:underline;text-underline-offset:2px}
button{font:inherit;color:inherit;cursor:pointer}
.wrap{max-width:1180px;margin:0 auto;padding:0 20px}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip{position:absolute;left:12px;top:-80px;z-index:100;background:var(--gold);color:#2a1700;font-weight:800;padding:8px 14px;border-radius:10px}
.skip:focus{top:12px}
main:focus{outline:none}
/* nav */
.banner{background:repeating-linear-gradient(45deg,#2b1d70,#2b1d70 10px,#24185f 10px,#24185f 20px);color:var(--lav);text-align:center;font-size:12.5px;padding:6px 10px}
.nav{position:sticky;top:0;z-index:10;background:rgba(15,10,38,.86);backdrop-filter:blur(10px);border-bottom:1px solid #2a1f63}
.nav .wrap{display:flex;align-items:center;gap:18px;height:64px}
/* The brand: the logo's "P" as an icon and the name in the site's heading font, legible at the bar's
   size, where the whole logo, two lines and its floating blocks, was too small to read. Below 1041px
   the name gives the links its room (it stays for screen readers: it names the link). */
.nav .brand{position:relative;flex:none}
.nav .brand .mark{display:flex;align-items:center;gap:10px}
.nav .brand img{display:block}
.nav .brand .mark img{width:36px;height:36px}
.nav .brand .name{font:400 22px/1 "Lilita One",sans-serif;letter-spacing:.4px;white-space:nowrap;text-shadow:0 2px 0 var(--line)}
.nav .brand .name span{color:var(--gold)}
.nav .brand .badge{display:none}
@media (max-width:1040px){.nav .brand .name{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}}
/* the focus ring round what shows: the link's own box is the icon and name, transparent while the logo hangs */
.nav .brand:focus-visible{outline:none}
.nav .brand:focus-visible .mark,.nav .brand:focus-visible .badge{outline:2px solid var(--violet2);outline-offset:2px;border-radius:8px}
/* Where the name shows, the top of a page (not home's) has the whole logo hanging from the bar instead:
   over the first 64px of scrolling (all of it, on a page that scrolls less) it tucks away by 5/8 of the
   way and the icon and name come in over the second half (barely overlapping, where the two would show
   through each other). One range for both: a page that stops being scrollable (a search with no results)
   leaves Chrome keeping or dropping the two together, never the logo gone and the name not in. Only where
   the browser drives animations by scrolling, ranges and all (without them the swap would spread over the
   whole page): elsewhere the icon and name stay. The logo is the starting point, so a page too short to
   scroll from the start (whose timeline never starts) keeps it. */
@media (min-width:1041px){@supports (animation-timeline:scroll()) and (animation-range:0 min(64px,100%)){
  .nav .brand .badge{display:block;position:absolute;left:0;top:-8px;transform-origin:0 0;
    animation:pgg-tuck linear both;animation-timeline:scroll(root);animation-range:0 min(64px,100%)}
  .nav .brand:has(.badge) .mark{opacity:0;animation:pgg-show linear both;animation-timeline:scroll(root);animation-range:0 min(64px,100%)}
}}
@media (min-width:1041px) and (prefers-reduced-motion:no-preference){.nav .brand .badge{animation-name:pgg-tuck-up}}
@keyframes pgg-tuck{62.5%,to{opacity:0;visibility:hidden}}  /* (hidden: it no longer takes clicks over the page) */
@keyframes pgg-tuck-up{62.5%,to{opacity:0;visibility:hidden;translate:0 -8px;scale:.85}}
@keyframes pgg-show{0%,50%{opacity:0}to{opacity:1}}
/* Scrolls sideways rather than cutting a link off, should the links ever not fit (#35). */
.nav nav{display:flex;gap:4px;margin:-4px 0 -4px 4px;padding:4px;min-width:0;overflow-x:auto;scrollbar-width:none}
/* (the padding is room for focus rings, which the scrolling box would otherwise cut off) */
.nav nav::-webkit-scrollbar{display:none}
.nav nav .short{display:none}
.nav nav a{padding:8px 12px;border-radius:10px;color:var(--muted);font-weight:600;white-space:nowrap}
.nav nav a.on,.nav nav a:hover{color:var(--text);background:var(--panel)}
.nav .spacer{flex:1}
.hero-ip code{font-family:"JetBrains Mono",monospace;font-weight:700;color:var(--gold)}
.ip{display:flex;align-items:center;gap:8px;background:var(--panel);border:1px solid var(--line);border-radius:999px;padding:6px 6px 6px 14px;font-weight:600;white-space:nowrap}
[hidden]{display:none!important}  /* .btn's display would otherwise beat the browser's [hidden] */
/* Copy buttons and the difficulty toggles only work with JavaScript, which marks the page (html.js):
   without it they are invisible (not removed, so nothing moves when they appear). */
html:not(.js) [data-copy],html:not(.js) .filters .diffs,html:not(.js) #random,html:not(.js) #isme,html:not(.js) #pbsort{visibility:hidden}
.btn{border:0;border-radius:999px;padding:7px 14px;background:var(--violet);font-weight:700;box-shadow:0 3px 0 #4b2bb3;display:inline-block;color:#fff}
.btn:hover{background:#6a3df0}  /* darker, not lighter: white text stays above 4.5:1 */
.btn.gold{background:var(--gold);color:#2a1700;box-shadow:0 3px 0 #b97700}
.btn.ghost{background:transparent;border:1px solid var(--line);box-shadow:none;color:var(--text)}
/* hero: room above the logo for the runner's highest jumps, hat and all (static/js/logo.js, TOP) */
.hero{text-align:center;padding:66px 0 18px}
.hero .stage{position:relative;width:min(620px,92%);margin:0 auto}
.hero .logo{display:block;position:relative;filter:drop-shadow(0 18px 40px rgba(123,77,255,.35))}
.hero .logo img{display:block;width:100%;height:auto}
/* the logo's runner and blocks, over it; the runner stands above its top edge on the high blocks */
.hero .run{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
/* The run (static/js/logo.js) goes on, so a button stops it (WCAG 2.2.2), in the logo's empty bottom
   right corner: stopped, the logo is as it's drawn. Without JavaScript or with reduced motion there's
   no button: the run doesn't play there. */
.hero .still{display:none;position:absolute;right:0;bottom:4%;width:32px;height:32px;padding:8px;border:1px solid var(--line);border-radius:50%;background:rgba(15,10,38,.6);color:var(--lav);cursor:pointer}
.hero .still svg{display:block;width:100%;height:100%;fill:currentColor}
.hero .still:hover{color:#fff;border-color:var(--violet2)}
.hero .still .i-go,.hero .still.stopped .i-stop{display:none}
.hero .still.stopped .i-go{display:inline}
@media (prefers-reduced-motion:no-preference){.js .hero .still{display:block}}
.hero p{color:var(--muted);font-size:18px;margin:6px auto 22px;max-width:620px}
.hero p code{white-space:nowrap} /* (/fp start whole, #413) */
.hero .cta{display:flex;flex-direction:column;align-items:center;gap:16px}
.hero .hero-ip{font-size:20px;padding:8px 8px 8px 22px;gap:14px;max-width:100%}
.hero .hero-ip code{font-size:20px;min-width:0;overflow:hidden;text-overflow:ellipsis}  /* (a long address at 320 px) */
.hero .hero-ip .btn{padding:10px 22px;font-size:17px}
/* the next steps, as links under the address: each a finger's height (WCAG 2.5.8) */
.hero .next{display:flex;flex-wrap:wrap;justify-content:center;gap:2px 22px}
.hero .next a{color:var(--violet2);font-weight:600;padding:6px 2px}
.hero .next a:hover{color:var(--lav);text-decoration:underline;text-underline-offset:3px}
.hero .next a::after{content:" →";content:" →"/""}  /* (the first for browsers without alt text) */
.hero .next a[target]::after{content:" ↗";content:" ↗"/""}
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:34px 0 8px}
.stat{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;min-width:0}
.stat b{display:block;font-family:"Lilita One",sans-serif;font-weight:400;font-size:30px;letter-spacing:.5px}
.stat span{color:var(--muted);font-size:13px}
/* (#433) The band of phantoms, right above the Map of the Day: the loop over the open space and the line,
   its edges faded into the page (wider than the page's column, up to 1600 px, so it has no sides), a little
   darker at its foot, where the line sits. A grid, so the loop's box is that of its rows (an absolutely
   placed child of a grid sits in its grid area), reaching 24 px past them above and below, faded out there.
   The poster shows until the video plays, which then fades in over it (static/js/phantoms.js). */
.phantoms{position:relative;isolation:isolate;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:clamp(170px,24vw,280px) auto;margin:34px 0 24px}  /* (24 below: the loop's faded foot clears whatever follows) */
/* (100vw counts a classic scrollbar too, so the loop can pass the window's edge by its width: the body's
   overflow-x:hidden clips it, faded out there anyway) */
.phantoms .reel{position:absolute;grid-row:1/3;grid-column:1/2;top:-24px;bottom:-24px;left:50%;width:min(100vw,1600px);transform:translateX(-50%);z-index:-1;overflow:hidden;pointer-events:none;
  --fade-x:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent);--fade-y:linear-gradient(180deg,transparent,#000 22%,#000 70%,transparent);
  -webkit-mask-image:var(--fade-x),var(--fade-y);
  -webkit-mask-composite:source-in;
  mask-image:var(--fade-x),var(--fade-y);
  mask-composite:intersect}
.phantoms .reel img,.phantoms .reel video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.phantoms .reel video{opacity:0;transition:opacity .8s}
.phantoms .pane.playing .reel video{opacity:1}
/* (the footage tinted towards the page's violet, and darker at its foot: an overlay rather than a filter
   on the video) */
.phantoms .reel::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(42,26,110,.42),rgba(30,18,84,.34) 55%,rgba(15,10,38,.8))}
/* (the line on a dark pill of its own: over the brightest frame its text keeps 4.5:1) */
.phantoms .onmap{grid-row:2;grid-column:1;align-self:end;justify-self:start;max-width:calc(100% - 44px);margin:0 0 8px;padding:2px 10px;border-radius:999px;background:rgba(15,10,38,.78);font-size:13px;color:var(--lav);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.phantoms .onmap a{color:#fff;font-weight:600}
.phantoms .onmap a:focus-visible{outline-offset:-2px}  /* (inside the pill, which clips what passes its edge) */
/* (hidden, not taken out: its row keeps its height whether it shows or not, so nothing moves) */
.phantoms .reel-stop{visibility:hidden;grid-row:2;grid-column:1;justify-self:end;align-self:end;margin-bottom:6px;width:32px;height:32px;padding:8px;border:1px solid var(--edge);border-radius:50%;background:rgba(15,10,38,.6);color:var(--lav);cursor:pointer}
.phantoms .reel-stop svg{display:block;width:100%;height:100%;fill:currentColor}
.phantoms .reel-stop:hover{color:#fff;border-color:var(--violet2)}
.phantoms .reel-stop .i-go,.phantoms.stopped .reel-stop .i-stop{display:none}
.phantoms.stopped .reel-stop .i-go{display:inline}
@media (prefers-reduced-motion:no-preference){.js .phantoms .reel-stop{visibility:visible}}
.phantoms.broken .reel-stop{visibility:hidden}
/* (#462) Its loops, up to three (templates/home.html): each a pane, whose loop and line are the band's grid's
   (display: contents), a column each, 8 px apart, the button in the last. The band stays as wide as one
   loop's: the first pane's loop reaches out to the band's left edge and the last's to its right, each faded
   there as one loop is (by 14% of the band: min(14vw,224px)), and the ones between only at their top and
   foot. (An absolutely placed child of a grid sits in its grid area, both its lines given: a missing end
   line is the grid's own edge, not the next line. From the first column's left, the band's left edge is
   (min(100vw,1600px) - the band's column)/2 away, the column being n areas of 100% and n-1 gaps.)
   Fewer on a narrower screen: the third from 861 px (where the Map of the Day under it takes its two
   columns), the second from 561 px (above the phones' layout); a pane not shown is display: none, the
   script plays only the panes shown (static/js/phantoms.js), and home.html's <source> keeps their posters
   from downloading below these same widths (not all and (min-width: ...)). Each width by min-width alone,
   so every width is on one side or the other: a viewport can be a fraction of a pixel wide (860.8 px at
   125% scaling), which max-width:860px and min-width:861px would both miss. Three panes are each a little
   wider than tall, about square at 861 px: the middle of each 16:9 loop shows (object-fit: cover). */
.phantoms .pane{display:contents}
.phantoms .pane+.pane{display:none}
@media (min-width:561px){
  .phantoms .pane:nth-child(2){display:contents}
  .phantoms.n2,.phantoms.n3{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:8px}
  .phantoms.n2 .pane:nth-child(2)>*,.phantoms.n3 .pane:nth-child(2)>*{grid-column:2/3}
  .phantoms.n2 .reel-stop,.phantoms.n3 .reel-stop{grid-column:-2}
  .phantoms.n2 .reel,.phantoms.n3 .reel{left:0;right:0;width:auto;transform:none;--fade-x:linear-gradient(#000,#000)}
  .phantoms.n2 .pane:first-child .reel,.phantoms.n3 .pane:first-child .reel{left:calc(100% + 4px - min(50vw,800px));--fade-x:linear-gradient(90deg,transparent,#000 min(14vw,224px))}
  .phantoms.n2 .pane:nth-child(2) .reel,.phantoms.n3 .pane:nth-child(2) .reel{right:calc(100% + 4px - min(50vw,800px));--fade-x:linear-gradient(270deg,transparent,#000 min(14vw,224px))}
  /* (only the last pane's line keeps clear of the button) */
  .phantoms.n2 .onmap,.phantoms.n3 .onmap{max-width:100%}
  .phantoms.n2 .pane:nth-child(2) .onmap,.phantoms.n3 .pane:nth-child(2) .onmap{max-width:calc(100% - 44px)}
}
@media (min-width:861px){
  .phantoms .pane:nth-child(3){display:contents}
  .phantoms.n3{grid-template-columns:repeat(3,minmax(0,1fr))}
  .phantoms.n3 .pane:first-child .reel{left:calc(150% + 8px - min(50vw,800px))}
  .phantoms.n3 .pane:nth-child(2) .reel{right:0;--fade-x:linear-gradient(#000,#000)}
  .phantoms.n3 .pane:nth-child(2) .onmap{max-width:100%}
  .phantoms.n3 .pane:nth-child(3)>*{grid-column:3/4}
  .phantoms.n3 .pane:nth-child(3) .reel{right:calc(150% + 8px - min(50vw,800px));--fade-x:linear-gradient(270deg,transparent,#000 min(14vw,224px))}
  .phantoms.n3 .pane:nth-child(3) .onmap{max-width:calc(100% - 44px)}
}
h1,h2,h3{overflow-wrap:anywhere}
h2,h1.page{font-family:"Lilita One",sans-serif;font-weight:400;font-size:28px;letter-spacing:.4px;margin:42px 0 14px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
h1.page{font-size:32px;margin-top:30px}
h2 small,h1.page small{font:500 13px Inter,sans-serif;color:var(--faint)}
.hero h1{margin:0;font-size:inherit}
.prestige{font-weight:800}
h2 .more{margin-left:auto;font:600 14px Inter,sans-serif;color:var(--violet2)}
.sechead{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 12px;margin:42px 0 14px}
.sechead h2{margin:0}
.sechead p{margin:0;font:500 13px Inter,sans-serif;color:var(--faint)}
.sechead .more{margin-left:auto;font:600 14px Inter,sans-serif;color:var(--violet2)}
/* Trending, top rated, newest and most played (templates/home.html): the names in a row over one list
   at a time, where the browser has :has(); elsewhere every list under its own heading. */
.listpick{display:none}
@supports selector(:has(*)){
  .listpick{display:flex;flex-wrap:wrap;gap:4px 26px;margin:42px 0 0;padding:2px 2px 0}
  .listpick label{font:400 28px/1.3 "Lilita One",sans-serif;letter-spacing:.4px;color:var(--faint);cursor:pointer;white-space:nowrap;
    padding-bottom:6px;border-bottom:3px solid transparent}
  .listpick label:hover{color:var(--lav)}
  .listpick input:checked+label{color:var(--text);border-bottom-color:var(--gold)}
  .listpick input:focus-visible+label{outline:2px solid var(--violet2);outline-offset:2px;border-radius:4px}
  .lists .list{display:none}
  .lists .list .sechead{margin-top:10px}
  .lists .list .sechead h2{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .lists:has(#ml-trending:checked) #list-trending,.lists:has(#ml-top:checked) #list-top,
  .lists:has(#ml-newest:checked) #list-newest,.lists:has(#ml-played:checked) #list-played{display:block}
}
h3.sub{font-family:"Lilita One",sans-serif;font-weight:400;font-size:20px;margin:22px 0 12px}
.h1note{font-size:.72em;color:var(--lav)}
/* map of the day */
.motd{display:grid;grid-template-columns:1.1fr 1fr;background:linear-gradient(135deg,#2a1b6b,#1b1248);border:1px solid #4a36a8;border-radius:20px;overflow:hidden;box-shadow:var(--shadow)}
.motd>*{min-width:0}
.motd .art{position:relative;min-height:300px;background:radial-gradient(circle at 50% 60%,#3b28a0,#140d38);display:grid;place-items:center}
.motd .art svg{width:190px;height:190px}
.ribbon{position:absolute;top:16px;left:16px;background:var(--gold);color:#2a1700;font:800 12px Inter,sans-serif;letter-spacing:1px;padding:6px 10px;border-radius:8px;text-transform:uppercase}
.motd .body{padding:26px 28px}
.motd h3{font-family:"Lilita One",sans-serif;font-weight:400;font-size:34px;margin:0 0 4px;line-height:1.1}
.by{color:var(--muted)} .by b{color:var(--lav)} .by a:hover b{text-decoration:underline}
.meta{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0}
.chip{display:inline-flex;align-items:center;gap:6px;background:var(--panel2);border:1px solid var(--line);border-radius:999px;padding:4px 10px;font-size:13px;color:var(--lav);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
a.chip:hover{border-color:var(--violet)}
.diff{font-weight:700;border:0}
/* players' vote, not the builder's pick (or shown harder by its finish rate): the same chip, "voted" (or
   "by finish rate") said more quietly */
.diff{display:inline-block}  /* (one run of text: no flex gap before "voted") */
.diff small{font-size:inherit;font-weight:500}  /* (by weight, not opacity: the chip's colours hold 4.5:1, #269) */
.d-BEGINNER{background:#0f4458;color:#7fdcf8}
.d-EASY{background:#174a2c;color:#86f0b0}
.d-NORMAL{background:#4d3a0b;color:#f2cf73}
.d-HARD{background:#5a1b19;color:#ff9a95}
.d-HARDCORE{background:#3a2366;color:#c7a8ff}
.rating{display:inline-flex;align-items:center;gap:6px;font-weight:700}
.rating .bar{width:70px;height:8px;border-radius:9px;background:#2d2366;overflow:hidden}
.rating .bar i{display:block;height:100%;background:linear-gradient(90deg,var(--orange),var(--gold))}
.card .rating .bar{width:52px}
.rating small{color:var(--faint);font-weight:500}
.rating.none{color:var(--faint);font-weight:500}
.cmd{display:flex;align-items:center;gap:8px;background:#120c2f;border:1px dashed #4a36a8;border-radius:12px;padding:8px 8px 8px 12px;margin-top:14px;min-width:0}
.cmd code{flex:1;min-width:0;font-family:"JetBrains Mono",monospace;font-size:13px;color:var(--gold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.podium{margin-top:16px;display:grid;gap:6px}
.podium div{display:flex;align-items:center;gap:10px;font-size:14px;min-width:0}
.podium .who{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.medal{width:24px;height:24px;border-radius:50%;display:inline-grid;place-items:center;font:800 12px Inter,sans-serif;color:#1b1030;flex:none}
.m1{background:linear-gradient(#ffe08a,#ffb627)}.m2{background:linear-gradient(#f2f2ff,#b9b6d6)}.m3{background:linear-gradient(#f3b98d,#c9773e)}.mx{background:#2d2366;color:var(--muted)}
.medal.wide{width:auto;min-width:24px;padding:0 7px;border-radius:12px}
.time{font-family:"JetBrains Mono",monospace;font-weight:700;margin-left:auto;white-space:nowrap}
/* cards */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:16px}
.card{position:relative;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;transition:transform .28s cubic-bezier(.34,1.7,.6,1),border-color .12s;display:flex;flex-direction:column;min-width:0}
.card:hover,.card:focus-within{transform:translateY(-3px);border-color:var(--violet)}
/* The map's name is the card's link and covers the card; the builder's name is a link above it. */
.card .name::after{content:"";position:absolute;inset:0;z-index:1}
.card .name:focus-visible{outline:none}
.card:has(.name:focus-visible){outline:2px solid var(--violet2);outline-offset:2px}
.card .by a{position:relative;z-index:2}
/* The difficulty chip is a link of its own to the difficulty's page (#260), above the card's link as the
   builder's name is; a voted one's explanation, or a finish rate's, shows on hover. */
.card .thumb .d a{position:relative;z-index:2}
.card .thumb .d .voted,.card .thumb .d .rate{cursor:help}
.more-built{margin-top:12px}
.more-built summary{list-style:none;cursor:pointer;margin:0 auto 12px;display:table}
.more-built summary::-webkit-details-marker{display:none}
.more-built[open] summary{display:none}
/* Featured maps (its builder paid for it, or staff featured it): listed first and coloured, as in the game. */
.card.featured{border-color:var(--gold)}
.ft{display:inline-flex;align-items:center;background:var(--gold);color:#2a1700;font:800 12px Inter,sans-serif;padding:4px 9px;border-radius:999px;white-space:nowrap}
.card .thumb .ft{position:absolute;left:10px;bottom:8px;padding:3px 8px;font-size:11px}
.grid.stale{opacity:.45;transition:opacity .2s}  /* cards that don't match the filter yet (#37) */
.card .thumb{height:120px;display:grid;place-items:center;position:relative;background:radial-gradient(circle at 50% 70%,#33248a,#1a1245)}
.card .thumb .d{position:absolute;top:10px;left:10px}
.card .thumb img.pic{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;padding:6px 8px}
/* (scale-down: at most the size its srcset's `sizes` says, 480 px wide on a wide screen: the picture's
   own pixels, not a 1x screen fetching the 960 to show it at 512; parkourgg/pieces.py SLOT_SIZES, #267) */
.viewer img.pic{width:100%;height:100%;object-fit:scale-down;padding:28px 20px 70px;position:absolute;inset:0}
.motd .art img.pic{width:100%;height:100%;object-fit:scale-down;padding:44px 20px 20px;position:absolute;inset:0}
.mini img.pic{width:64px;height:40px;object-fit:contain;flex:none}
.viewer iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.viewer .view3d{position:absolute;left:50%;bottom:44px;transform:translateX(-50%);font-size:16px;padding:10px 20px;white-space:nowrap}
.viewer .view3d small{font-weight:500;margin-left:6px}  /* (no opacity: white on violet is 4.8:1, #269) */
/* (#469) A map's short clip (templates/_macros.html clip_video): over its picture in the map page's top box, the
   Map of the Day's and a card's thumb, filling it (the middle of its 16:9 frames shows), faded in once it
   plays (static/js/reel.js), the picture showing until then. Under the box's own chips, ribbon and buttons
   (after the picture in the page, before them; the ribbon raised). In the top box, a little darker at its
   foot while it plays, where "View in 3D" and the hint sit. Its button, as the band's (hidden, not taken out:
   nothing moves as it comes or goes), in the box's top right corner: the Map of the Day's over its picture's
   (an absolutely placed child of a grid sits in its grid area, both its lines given: the picture's, 1/1/2/2;
   a missing end line would be the grid's own edge). */
.clip{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.clip video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .8s}
.clip.playing video{opacity:1}
/* (a card's only while pointed at or focused, clip-on, static/js/clips.js: paused once left, it fades back to the
   picture rather than staying a frozen frame) */
.card .clip.playing video{opacity:0}
.card.clip-on .clip.playing video{opacity:1}
.viewer .clip::after{content:"";position:absolute;left:0;right:0;bottom:0;height:110px;background:linear-gradient(180deg,transparent,rgba(15,10,38,.75));opacity:0;transition:opacity .8s}
.viewer .clip.playing::after{opacity:1}
/* (the "3D view" chip goes while the clip shows, static/js/clips.js: it isn't the 3D view) */
.viewer .tag{transition:opacity .8s}
.viewer.clip-shown .tag{opacity:0}
/* (The whole clip shows in the top box, at every width: letterboxed in the middle over a dark band, the picture
   dimmed behind it, where the box isn't 16:9. A phone's box (560 px and under) is as tall as the 3D view needs;
   a wide screen's (861 px and up) 418 px tall and 480 to 670 px wide, so filled, its clip would lose a third of
   its width at 861 px (a runner at its edge out of sight), a tenth at its widest. From 561 to 860 px wide the
   box is 300 px tall (below), as much as 820 px wide: there a box with a clip (has-clip, from the page itself,
   so nothing moves as it plays) takes the clip's 16:9 instead, which the clip fills, "View in 3D" over its
   foot. Its min-height goes: kept, the browser would carry it over to a width through the ratio (300 px tall,
   533 px wide), past the column's edge at 561 px; and so not below 561 px, where the box's min-height (the 3D
   view's, up to 440 px) would make it 782 px wide. The hint under the clip: its sentence (.said) gets a dark
   backing of its own while the clip shows (over its brightest frames, the muted text alone is under 4.5:1), and
   "This is the map's icon." (.icon, a line of its own) goes. The geometry stays as it was drawn: the backing's
   padding is there from the start, and the line goes as invisible, so nothing moves as the clip starts.) */
@media (min-width:561px) and (max-width:860px){.viewer.has-clip{aspect-ratio:16/9;min-height:0}}
.viewer .clip{transition:background .8s}
.viewer .clip video{object-fit:contain}
.viewer .clip.playing{background:rgba(10,7,28,.82)}
.viewer .hint .said{padding:2px 8px;border-radius:8px;-webkit-box-decoration-break:clone;box-decoration-break:clone;transition:background .8s}
.viewer .hint .icon{display:block}
.viewer.clip-shown .hint .said{background:rgba(15,10,38,.85)}
.viewer.clip-shown .hint .icon{visibility:hidden}
.motd .ribbon{z-index:1}
.motd{position:relative}
.motd>.clip-stop{grid-area:1/1/2/2}
.clip-stop{visibility:hidden;position:absolute;top:12px;right:12px;z-index:2;width:32px;height:32px;padding:8px;border:1px solid var(--edge);border-radius:50%;background:rgba(15,10,38,.6);color:var(--lav);cursor:pointer}
.clip-stop svg{display:block;width:100%;height:100%;fill:currentColor}
.clip-stop:hover{color:#fff;border-color:var(--violet2)}
.clip-stop .i-go,.stopped>.clip-stop .i-stop{display:none}
.stopped>.clip-stop .i-go{display:inline}
/* (shown once static/js/clips.js has set its clip going, clip-ready: before, or if it never loads, it does nothing) */
@media (prefers-reduced-motion:no-preference){.clip-ready>.clip-stop{visibility:visible}}
.broken>.clip-stop{visibility:hidden}
/* (#471, #472) A clip in a frame of its own (templates/_macros.html clip_frame): 16:9, its poster until it plays,
   the clip over it (.clip, above) and its button in the corner. A minigame's in its panel, and the duel's in How
   to play's Duels section (.side-clip): beside the words on a wide screen, floated right of them in the room
   their 820 px leave (the panel holds it: flow-root), the steps after it a plain block that flows round it (as a
   grid it would keep clear of it all the way down), and under the heading up to 899 px, where beside the words
   it would be narrower than about 340 px (a little less with a scrollbar that takes room; 400 px from about
   1,030 px). The duel's on the duels board, a figure of its own above the latest duels; its caption names the
   map. */
.clip-frame{position:relative;aspect-ratio:16/9;border-radius:14px;overflow:hidden;border:1px solid #4a36a8;background:radial-gradient(circle at 50% 65%,#3a2a9a,#120c32)}
.clip-frame>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.duel-clip{margin:24px 0 0;max-width:560px}
.duel-clip figcaption{margin-top:6px;font-size:14px;color:var(--muted)}
.guide{display:flow-root}
.side-clip{float:right;width:min(400px,42%);margin:2px 0 12px 20px}
.side-clip~.steps{display:block}
.side-clip~.steps li+li{margin-top:8px}  /* (the grid's gap) */
@media (max-width:899px){.side-clip{float:none;width:auto;max-width:560px;margin:0 0 12px}}
/* A video (#263, templates/_video.html): 16:9 before and after the press, the poster filling it */
.video{margin:0;max-width:880px}
.video .frame{position:relative;aspect-ratio:16/9;border-radius:18px;overflow:hidden;border:1px solid #4a36a8;background:radial-gradient(circle at 50% 65%,#3a2a9a,#120c32)}
.video .poster{position:absolute;inset:0;display:grid;place-items:center}
.video .poster img,.video video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.video iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.video .play{position:relative;width:68px;height:48px;filter:drop-shadow(0 2px 6px rgba(0,0,0,.5))}
.video .play svg{width:100%;height:100%;display:block;fill:#e6223a}
.video .play .tri{fill:#fff}
/* (each on its own: a browser without :focus-visible, Safari before 15.4, drops a list it's in, :hover too) */
.video .poster:hover .play svg{fill:#ff3550}
.video .poster:focus-visible .play svg{fill:#ff3550}
.video .poster:focus-visible{outline:3px solid var(--violet2);outline-offset:-3px;border-radius:18px}
.video figcaption{margin-top:10px;font-size:14px;color:var(--muted)}
.video figcaption b{color:var(--text);margin-right:4px}
.video-sec .sechead{max-width:880px}  /* (#473: the link to its watch page over the box's right edge) */
/* (#473) A watch page: the player first, as the page's main content; a Short (9:16) beside its text on wide
   screens, as tall as the window lets it be, and centred above it on narrow ones */
.watch .video{max-width:960px}
.watch h1.page{margin:18px 0 0;overflow-wrap:anywhere}
.video.tall .frame{aspect-ratio:9/16}
.video.tall .poster img{object-fit:contain}  /* (a wide poster whole, not its middle third; a 9:16 one fills it all the same) */
.video.tall{width:min(380px,calc((100vh - 120px) * 9 / 16))}
.watch.tall{display:grid;grid-template-columns:auto minmax(0,1fr);gap:28px;align-items:start;margin-top:12px}
.watch.tall h1.page{margin-top:0}
@media (max-width:760px){.watch.tall{display:block}.video.tall{width:min(100%,calc((100vh - 140px) * 9 / 16));margin:0 auto}.watch.tall h1.page{margin-top:18px}}
.vmeta{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;color:var(--muted);font-size:14px;margin:10px 0 16px}
ul.named{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:10px 22px}
/* (#473) /videos/: a card per video, its picture 16:9 (a Short's whole, in the middle), the whole card its link */
.vkinds{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 18px}
.vgrid{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:16px}
.vcard{position:relative;display:flex;flex-direction:column;min-width:0;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
.vcard:hover,.vcard:focus-within{border-color:var(--violet)}
.vcard:has(.vname:focus-visible){outline:2px solid var(--violet2);outline-offset:2px}
.vthumb{position:relative;aspect-ratio:16/9;display:grid;place-items:center;background:radial-gradient(circle at 50% 65%,#3a2a9a,#120c32)}
.vthumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.vthumb.tall img{object-fit:contain}
.vthumb .play{position:relative;width:48px;height:34px;fill:#e6223a;filter:drop-shadow(0 2px 6px rgba(0,0,0,.5))}
.vthumb .play .tri{fill:#fff}
.vcard:hover .vthumb .play{fill:#ff3550}
.vthumb .len{position:absolute;right:8px;bottom:8px;background:rgba(8,5,22,.85);color:#fff;font-size:12px;font-weight:700;border-radius:6px;padding:1px 6px}
.vinfo{padding:12px 14px 14px;display:flex;flex-direction:column;gap:8px;flex:1;min-width:0}
.vname{font-weight:700;line-height:1.25;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow-wrap:anywhere}
.vname::after{content:"";position:absolute;inset:0;z-index:1}
.vname:focus-visible{outline:none}
.vrow{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;color:var(--muted);font-size:13px;margin-top:auto}

/* (#474) /updates/: a day's lines in a panel, one under the other; a line's tags before its text (a category in the
   feed's own hue, light enough to read on the panel), its screenshot under it. A long word breaks rather than
   pushing the page sideways on a phone. */
.upday{max-width:880px}  /* (a line of text no longer than reads well) */
.upday .sechead{margin:30px 0 10px}
.panel.uplist{list-style:none;margin:0;padding:4px 18px}
.uplist li{padding:11px 0;border-top:1px solid var(--line);overflow-wrap:anywhere}
.uplist li:first-child{border-top:0}
.utags{display:inline-flex;flex-wrap:wrap;gap:4px 6px;vertical-align:1px;margin-right:2px}
.utag{display:inline-block;border:1px solid var(--line);border-radius:999px;padding:0 8px;font-size:12px;font-weight:700;
  line-height:18px;color:var(--lav);background:var(--panel2);white-space:nowrap}
.utag[style]{color:hsl(var(--h) 90% 80%);border-color:hsl(var(--h) 60% 55% / .55);background:hsl(var(--h) 60% 45% / .16)}
.utag.sys{color:var(--muted);background:none}
.ushot{display:block;max-width:min(100%,560px);height:auto;margin-top:10px;border-radius:10px;border:1px solid var(--line)}
@media (max-width:450px){.panel.uplist{padding:2px 12px}}

.card .info{padding:12px 14px 14px;display:flex;flex-direction:column;gap:6px;flex:1;min-width:0}
.card .name{font-weight:700;line-height:1.25;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow-wrap:anywhere}
.card .by{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card .row{display:flex;justify-content:space-between;align-items:center;gap:8px;color:var(--muted);font-size:13px;margin-top:auto}
.card .row{flex-wrap:wrap;row-gap:2px}  /* a narrow card puts the count under the rating */
.card .row>span:last-child{white-space:nowrap}
.strip{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}
/* (#410) a main page's picks (a kind's, a difficulty's, browse's): 4 in a row, 2 when narrower, and 2 of each on a phone, so its list isn't pushed far down */
.picks .strip{grid-template-columns:repeat(2,minmax(0,1fr))}
@media (min-width:1000px){.picks .strip{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media (max-width:600px){.picks .strip{grid-template-columns:minmax(0,1fr)}.picks .strip .mini:nth-child(n+3){display:none}}
.mini{display:flex;align-items:center;gap:12px;background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:10px 12px;min-width:0}
.mini:hover{border-color:var(--violet)}
.mini .t{min-width:0}
.mini .t b{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mini .t span{color:var(--faint);font-size:12.5px}
/* map page */
.crumbs{color:var(--faint);margin:26px 0 8px;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crumbs a{color:var(--violet2)}
.maphead h1{font-family:"Lilita One",sans-serif;font-weight:400;font-size:44px;line-height:1.05;margin:0}
.desc{color:var(--lav);margin:0 0 4px;max-width:760px;overflow-wrap:anywhere}
.mapgrid{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);gap:20px;margin-top:20px}.mapgrid>*{min-width:0}
.side{display:grid;gap:16px;align-content:start}
.viewer{position:relative;border-radius:18px;overflow:hidden;border:1px solid #4a36a8;background:radial-gradient(circle at 50% 65%,#3a2a9a,#120c32);min-height:420px;display:grid;place-items:center}
.viewer>svg{width:220px;height:220px}  /* (the map's icon: not the clip button's, #469) */
.viewer .tag{position:absolute;left:14px;top:14px;display:flex;gap:8px;z-index:1}
.viewer .hint{position:absolute;bottom:12px;left:12px;right:12px;text-align:center;color:var(--muted);font-size:13px}
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:18px;min-width:0}
.panel h2{margin:0 0 10px;font-family:"Lilita One",sans-serif;font-weight:400;font-size:22px;display:block;letter-spacing:0}
.kv{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.kv div{background:var(--panel2);border-radius:10px;padding:10px 12px;min-width:0}
.kv b{display:block;font-size:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kv span{color:var(--muted);font-size:12px}
.facts{display:grid;gap:8px;margin:0;font-size:14px}
.facts>div{display:flex;justify-content:space-between;gap:12px;border-bottom:1px solid #2a2064;padding-bottom:8px}
.facts>div:last-child{border:0;padding:0}
.facts>div.stack{display:block}
.facts dt{color:var(--muted)} .facts dd{margin:0;text-align:right;min-width:0;overflow-wrap:anywhere}
.facts dd .pl{justify-content:flex-end}.facts .when{display:block;color:var(--faint);font-size:13px}
.votes{display:grid;gap:6px;margin-top:4px}
.votes>div{display:grid;grid-template-columns:84px 1fr 44px;align-items:center;gap:8px;font-size:13px;background:none}
.facts dd .votes{margin-top:8px}
.votes .bar{height:8px;border-radius:9px;background:#2d2366;overflow:hidden}
.votes .bar i{display:block;height:100%;background:currentColor}
.votes span:last-child{text-align:right;color:var(--muted)}
/* tables */
table{width:100%;border-collapse:collapse;table-layout:auto}
td,th{padding:9px 10px;text-align:left;border-bottom:1px solid #2a2064;font-size:14px}
th{color:var(--faint);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.6px;white-space:nowrap}
td.num,th.num{text-align:right;white-space:nowrap}
th abbr{text-decoration:none}
tr:hover td{background:#211858}
td.who{max-width:0;width:100%}
.pl{display:flex;align-items:center;gap:8px;min-width:0}
.pl span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.pl svg{flex:none}
a.pl:hover span{text-decoration:underline}
.head{width:24px;height:24px;border-radius:5px;flex:none;image-rendering:pixelated;background:#2d2366;display:inline-grid;place-items:center;font:800 12px Inter,sans-serif;color:var(--muted);overflow:hidden}
.head.big{width:72px;height:72px;border-radius:12px;font-size:30px}
.tablewrap{overflow-x:auto}
/* browse */
.filters{display:flex;flex-wrap:wrap;gap:10px;align-items:center;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:12px;margin-bottom:16px}
.filters input,.filters select,.search input{background:#120c2f;border:1px solid var(--edge);border-radius:10px;padding:9px 12px;color:var(--text);font:inherit;min-width:0}
.filters input{flex:1 1 220px}
.filters .diffs{display:flex;flex-wrap:wrap;gap:6px}
.filters .glabel{align-self:center;font-size:13px;color:var(--muted);margin-right:2px}
/* what a group's label means, in words beside its toggles (#368: a title would reach only a mouse) */
.filters .gnote{align-self:center;font-size:13px;color:var(--muted)}
.tog small{font-size:11.5px;opacity:.8;margin-left:2px}
.tog{border:1px solid var(--edge);background:transparent;border-radius:999px;padding:6px 12px;font-size:13px;color:var(--muted)}
.tog.on,a.tog.on{background:var(--violet);border-color:var(--violet);color:#fff}
a.tog{display:inline-block}
.tabs{display:flex;gap:6px;margin-bottom:14px;flex-wrap:wrap}
.count{color:var(--faint);font-size:13px;margin:-6px 0 12px}
/* (#410) under picks over the list: clear of their last cards, which the pull-up would put it under */
.picks ~ .count{margin-top:12px}
.more-wrap{text-align:center;margin:22px 0 0}
/* the map leaderboard's All time / This month / This week / Today (#196) */
.lbtabs{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 12px}
#lbperiod .note:empty{display:none}
.note{color:var(--faint);font-size:13px;margin-top:10px}
.search{display:flex;gap:8px;margin:0 0 16px;max-width:460px}
.search input{flex:1}
.pager{display:flex;flex-wrap:wrap;justify-content:center;gap:6px;margin:24px 0 0}
.pager a,.pager span{min-width:38px;padding:7px 11px;border-radius:10px;border:1px solid var(--edge);text-align:center;font-weight:600;color:var(--lav)}
.pager a:hover{border-color:var(--violet2);background:var(--panel)}
.pager .on{background:var(--violet);border-color:var(--violet);color:#fff}
.pager .gap{border-color:transparent;color:var(--faint);min-width:0;padding:7px 2px}
/* join (#194) */
.lead{color:var(--lav);max-width:760px;margin:0 0 20px}
.join{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px}
.join .for{color:var(--faint);font-size:13px;margin:-6px 0 4px}
.cmd .lbl{flex:none;min-width:62px;color:var(--muted);font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}
.join .cmd+.cmd{margin-top:8px}
.join .cmd code{white-space:normal;overflow-wrap:anywhere}  /* the whole address, even at 320px */
.steps{margin:16px 0 0;padding-left:22px;display:grid;gap:8px}
.steps li::marker{color:var(--gold);font-weight:700}
.steps code,.guide code{font-family:"JetBrains Mono",monospace;font-size:13px;color:var(--gold)}
.join-next{margin-top:20px}.join-next .steps{margin-top:0}
.faq h3{font-size:15px;margin:14px 0 2px}.faq h3:first-of-type{margin-top:0}.faq p{margin:0;color:var(--lav)}
/* The kinds of map people search for by name (#223): links to their pages, and a kind's own page */
.types{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 16px}
.types .chip small{color:var(--faint);font-size:12px}
.topic .lead{margin-bottom:12px}
.play-these .btn{margin-left:4px;vertical-align:middle}
.topic-records,.topic-faq,.more-types{margin-top:24px}
.more-types h2{margin:0 0 12px}
.topic-records td.mapc{max-width:0;width:55%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.topic-records td.who{width:45%}
.toc{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 20px}
.toc a{border:1px solid var(--edge);border-radius:999px;padding:6px 12px;font-size:13px;color:var(--lav)}
.toc a:hover{border-color:var(--violet2);background:var(--panel)}
/* a jump link's heading clears the sticky nav */
.guide{margin-top:20px}.guide>h2{scroll-margin-top:100px}.guide p{margin:0 0 10px;max-width:820px}.guide p:last-child{margin-bottom:0}
.guide .steps{margin:0 0 10px}.guide .steps:last-child{margin-bottom:0}
/* (#470) A jump's clip (templates/jumps.html), at the top of "How to do it": the browser's own player, as wide as the
   panel up to a page video's width (#263), 16:9 before and after it plays (its poster, then its frames), so
   nothing moves */
.jump-clip{margin:0 0 14px;max-width:880px}.jump-clip:last-child{margin-bottom:0}
.jump-clip video{display:block;width:100%;height:auto;aspect-ratio:16/9;border-radius:14px;border:1px solid #4a36a8;background:#120c32}
.jump-clip figcaption{margin-top:8px;font-size:14px;color:var(--muted)}
/* the server's artwork beside a page's heading (#217), and the minigames (#215) */
.intro{display:flex;align-items:flex-end;justify-content:space-between;gap:20px}
.intro .lead{margin-bottom:12px}
.art-pic{display:block;flex:none;width:auto;height:180px}
.intro .art-pic{margin:20px 0 4px}
.game-head{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 10px}
.game-head h2{margin:0;scroll-margin-top:100px}
.game-head .chip{white-space:normal}  /* (a long one wraps at 320px rather than being cut off) */
.chip.soon{background:none;border-color:var(--gold);color:var(--gold);font-weight:600}
.game .cmd{max-width:520px}
.game .cmd code{white-space:normal;overflow-wrap:anywhere}  /* the whole command, even at 320px */
.with-art{display:flex;align-items:flex-end;justify-content:space-between;gap:20px}
.with-art .art-pic{height:150px}
.play-together{display:flex;align-items:center;gap:20px;margin-top:20px}
.play-together .art-pic{height:132px;margin:-8px 0 -18px}
.play-together h2{margin:0 0 6px}
.play-together p{margin:0 0 12px;color:var(--lav)}
.play-together .meta{display:flex;flex-wrap:wrap;gap:6px}
.play-together .chip:hover{border-color:var(--violet2);color:var(--text)}
/* The server, live (#288): the players online (home, /join/ and /bedrock/ only), and the day's Elimination events */
.online{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;color:var(--muted);font-size:15px;margin:0 0 14px}
.online b{color:var(--text)}
.online .dot{flex:none;width:9px;height:9px;border-radius:50%;background:#3ddc84;box-shadow:0 0 0 3px rgba(61,220,132,.2)}
.hero p.online{justify-content:center;font-size:15px;margin:16px auto 0}
.events b{color:var(--text)}
.play-together p.events{color:var(--muted)}
/* Sharing (#274) and the one-tap Bedrock link (#287) */
.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.add-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.by .share-own{margin-left:10px;padding:3px 12px;font-size:13px;vertical-align:middle}
td.time button.share-race{display:block;margin:2px 0 0 auto;padding:0;border:0;background:none;cursor:pointer;font:600 12px Inter,system-ui,sans-serif;color:var(--violet2);text-decoration:underline;text-underline-offset:2px}
td.time button.share-race:hover{color:var(--lav)}
#lb tr.raced td{background:rgba(123,77,255,.14)}
.view3d.raced{outline:2px solid var(--gold);outline-offset:2px}
@media (max-width:620px){
  .intro .art-pic,.with-art .art-pic{display:none}
  .play-together .art-pic{height:96px;margin:0}
}
@media (max-width:420px){.play-together .art-pic{display:none}}
/* "What you can do" (#290): six tiles, each picture in a box of fixed height, so nothing moves as they load */
.tiles{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:12px}  /* 6, 3 + 3 or 2 x 3: never 4 + 2 */
.tile{display:flex;flex-direction:column;gap:4px;height:100%;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:12px 14px 14px}
.tile:hover{border-color:var(--violet2)}
.tile:focus-visible{border-color:var(--violet2)}
.tile .pic{display:flex;align-items:flex-end;justify-content:center;height:96px;margin-bottom:6px;overflow:hidden}
.tile .pic img{height:96px;width:auto;max-width:100%;object-fit:contain}
.tile .pic svg{height:56px;width:auto;max-width:100%;margin-bottom:12px}
.tile b{font:400 21px "Lilita One",sans-serif;letter-spacing:.3px;color:var(--text)}
.tile .line{color:var(--lav);font-size:14px}
@media (max-width:1060px){.tiles{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (max-width:560px){.tiles{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:420px){.tiles{gap:8px}.tile{padding:10px}.tile .pic,.tile .pic img{height:72px}.tile .pic svg{height:44px;margin-bottom:8px}}
/* The cosmetics page (#290): a name, what it is and how to get it, by an icon of its kind */
.cosm-grid{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:8px}
.cosm{display:flex;gap:10px;align-items:flex-start;background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:10px 12px;min-width:0}
.cosm>div{display:flex;flex-direction:column;min-width:0}
.cosm b{color:var(--text);overflow-wrap:anywhere}
.cosm .desc{color:var(--lav);font-size:13px;overflow-wrap:anywhere}
.cosm .how{color:var(--muted);font-size:13px;font-weight:600}
.cosm .how.sold{color:var(--gold)}
.cicon{flex:none;width:28px;height:28px;margin-top:2px;fill:currentColor}
/* its picture (or, without one, its icon) on a lit backdrop, so dark cosmetics show on the dark card */
.cosm .pic{flex:none;display:grid;place-items:center;width:96px;height:96px;border-radius:10px;background:radial-gradient(circle at 50% 42%,#4b3c9e 0,#2c2068 62%,var(--panel2) 100%)}
.cosm .pic img{display:block;width:96px;height:96px}
.cosm .pic .cicon{width:40px;height:40px;margin:0}
.cicon.hat{color:#c9b8ff}.cicon.plushie{color:#ffb08a}.cicon.backpack{color:#6fd6a0}.cicon.balloon{color:#ff8fa8}
.abilities{list-style:none;margin:0 0 10px;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:6px 18px}
.abilities b{color:var(--gold)}
.ranks{list-style:none;display:flex;flex-wrap:wrap;gap:6px;margin:4px 0 14px;padding:0}
.ranks li{background:var(--panel2);border-radius:999px;padding:4px 11px;font-size:13px;font-weight:600}
/* player */
.phead{display:flex;align-items:center;gap:18px;margin:30px 0 6px;flex-wrap:wrap}
.phead h1{font-family:"Lilita One",sans-serif;font-weight:400;font-size:40px;margin:0;line-height:1.1;overflow-wrap:anywhere}
.phead .tags{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}
.pstats{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:20px 0 4px}
.choose{display:grid;gap:8px;max-width:460px}
/* The browser-drawn player page fills in after two downloads: its space is kept from the start, so
   the footer never jumps (#32: a 0.73 layout shift on phones). */
#player.drawn{min-height:100vh}
.empty{color:var(--muted);padding:30px 0}
footer.wrap{margin:60px auto 30px;color:var(--faint);font-size:13px;text-align:center}
/* the config's community links (#195): a row that wraps on phones, each link about 24px tall (WCAG
   2.5.8's minimum target size) */
footer .community{display:flex;flex-wrap:wrap;justify-content:center;gap:0 14px;margin-bottom:8px}
footer .community a{color:var(--muted);font-weight:600;padding:4px 2px;text-decoration:underline;text-underline-offset:2px}
footer .community a:hover{color:var(--text)}
footer a.link{display:inline-block;padding:4px 2px;margin-top:2px}  /* (a finger's height too) */
/* the privacy page (#193): text at a reading width; a long address wraps rather than scroll sideways */
.prose{max-width:760px;overflow-wrap:anywhere}
.prose h2{font-size:22px;margin:30px 0 8px}
.prose p,.prose li{color:var(--muted)}
.prose ul{padding-left:22px;margin:8px 0}
.prose li{margin:5px 0}
.toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(80px);background:var(--gold);color:#2a1700;font-weight:800;padding:10px 16px;border-radius:12px;transition:transform .32s cubic-bezier(.34,1.56,.64,1),opacity .2s,visibility .2s;z-index:50;max-width:calc(100% - 32px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:0;visibility:hidden}
.toast.on{transform:translateX(-50%) translateY(0);opacity:1;visibility:visible}
.toast.long{white-space:normal;overflow-wrap:anywhere}  /* a message to act on wraps rather than cut off (#143) */
/* the four list names in one row down to the phone sizes below (#218) */
@media (max-width:620px){.listpick{gap:4px 18px}.listpick label{font-size:22px}}
/* Six links with Games (#215): below 961px the icon alone is the home link, and on phones Games goes
   too (the home page's Play together panel and every footer link it), so Players, which becomes a
   visitor's own "You" (common.js, #144), stays. */
@media (max-width:960px){.nav nav a[href="/"]{display:none}}
@media (max-width:420px){.nav nav a[href="/games/"]{display:none}}
@media (max-width:860px){
  .motd,.mapgrid,.join{grid-template-columns:minmax(0,1fr)}
  .stats,.pstats{grid-template-columns:repeat(2,1fr)}
  .nav .ip{display:none}
  .nav nav a{padding:8px 10px}  /* five links fit from 561px up (#35) */
  .maphead h1{font-size:34px}
  .viewer{min-height:300px}
}
/* a phone: a taller 3D view, so its chips, splits and buttons leave the map room (#232); never under
   the 300px above, and only where there is a model to view */
@media (max-width:560px){.viewer[data-src]{min-height:clamp(300px,64vh,440px)}}
td.place .of{color:var(--faint)}
@media (max-width:560px){
  td.lvl{white-space:normal;font-size:13px;min-width:4.5em}
  td.place .of{display:block;font-size:12px}
  .wrap{padding:0 16px}
  .nav .wrap{gap:10px}
  .nav nav{margin-left:-4px;gap:0}
  .nav nav a{padding:6px 7px;font-size:14px}
  .nav .brand .mark img{width:32px;height:32px}
  .stat{padding:12px 14px}.stat b{font-size:24px}
  .motd .body{padding:18px}
  .motd .art{min-height:220px}.motd .art svg{width:150px;height:150px}
  .grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px}
  .card .thumb{height:96px}.card .thumb svg{width:60px;height:60px}
  .card .info{padding:10px 10px 12px}
  .card .row{flex-direction:column;align-items:flex-start;gap:2px}
  .rating .bar{width:44px}
  h2{font-size:24px;margin-top:32px}
  .listpick{margin-top:32px;gap:2px 14px}.listpick label{font-size:17px;padding-bottom:4px}
  .hero .hero-ip,.hero .hero-ip code{font-size:17px}.hero .hero-ip .btn{padding:8px 18px;font-size:16px}
  .sechead{margin-top:32px}
  td,th{padding:8px 5px}
  .phead h1{font-size:30px}
}
/* Phones (#35, #36): "Home" gives its room to the other links up to 960px (#215), since the icon is the way home
   and from 451px the links are wider again (#194; with Games, 441-445px was too narrow for
   "Leaderboards", #215); "Leaderboards" says "Boards" (its full name stays
   for screen readers); names in tables keep to one line, cut with an ellipsis (the full name is the
   title), and give up their head picture and some padding for room. */
@media (max-width:450px){
  .nav nav .long{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .nav nav .short{display:inline}
  .panel{padding:12px}
  td .pl .head{display:none}
  td.who .pl{gap:0}
  th{font-size:10.5px;letter-spacing:.2px}
  td,th{padding:8px 4px}
}
@media (max-width:380px){.nav nav a{padding:6px 5px;font-size:13px}}
/* a personal best whose run can be raced against the record in the 3D view (#71) */
td.time a.race{display:block;margin-top:2px;font:600 12px Inter,system-ui,sans-serif;color:var(--violet2);text-decoration:underline;text-underline-offset:2px}
td.time a.race:hover{color:var(--lav)}
/* Reduced motion (#153, as the 3D view does, #64): cards don't lift, the toast doesn't slide. */
@media (prefers-reduced-motion:reduce){.card,.toast,.grid.stale{transition:none}.card:hover,.card:focus-within{transform:none}}
/* A personal best's gap to the record (#147), and a leaderboard's own rows (#144, #146) */
td.time .gap{display:block;font:600 12px Inter,system-ui,sans-serif;color:var(--faint)}
td.time .gap.rec{color:var(--gold)}
/* ... and every map leaderboard row's gap to its board's first (#339): under the time, so the names keep their
   room; after it only from 701 to 860 px, where the board has the page's whole width (in the side column, from
   861 px, an inline gap cut the widest names even at the column's widest, 1201 px and up: #372). Under the
   time it may reach into the cell's left padding: a gap has no more digits than its time and is set smaller,
   but should one still be the wider (in another font), it never widens the column (#372) */
.lbrows td.time .gap{margin-left:-10px}
@media (min-width:701px) and (max-width:860px){.lbrows td.time .gap{display:inline;margin-left:8px}}
@media (max-width:560px){.lbrows td.time .gap{margin-left:-5px}}
@media (max-width:450px){.lbrows td.time .gap{margin-left:-4px}}
/* (on the visitor's own row and the row raced in 3D, whose tint takes --faint under 4.5:1: #361 review) */
.lbrows tr.me td.time .gap,#lb tr.raced td.time .gap{color:var(--muted)}
/* A player's share of the maps and their 2nd and 3rd places (#338), on a line of their own in the stat (the
   share's words short enough for one line in a 320 px phone's stat: player.js counts()) */
.stat .sub{display:block;font-size:inherit}
/* ... and their maps finished per difficulty (#338): "of N" and the bars come with data/versions.json
   (player.js), in the room kept for them; without scripts, no bars that would say none */
.bydiff .hardest{margin:0 0 12px;display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px}
.bydiff .votes>div{grid-template-columns:84px minmax(0,1fr) 9.5em}
.bydiff .votes span:last-child{white-space:nowrap}
.bydiff .votes a{text-decoration:underline;text-underline-offset:2px}
/* (the bars only once player.js has the counts, "counted": until then, without scripts, or when data/versions.json
   doesn't come, an empty or full bar would say none or every one) */
.bydiff .bar{visibility:hidden}
.bydiff .bar i{width:0}
.bydiff.counted .bar{visibility:visible}
tr.me td{background:rgba(123,77,255,.16)}
.note.mybest b{color:var(--gold)}
.pbsort{margin-left:auto;background:#120c2f;border:1px solid var(--edge);border-radius:10px;padding:6px 10px;color:var(--text);font:inherit;font-size:13px}
/* A player's places on the boards (#145), and "This is me" (#144) */
/* One chip tall at any width, so the room the page keeps for it is the room it takes (#270): the row
   scrolls sideways where the chips don't fit (a phone), its end faded. (The padding is room for focus
   rings, which the scrolling box would otherwise cut off.) */
.places{display:flex;flex-wrap:nowrap;gap:8px;margin:8px -4px 0;padding:4px;overflow-x:auto;scrollbar-width:none;overscroll-behavior-x:contain}
.places::-webkit-scrollbar{display:none}
.places .chip{flex:none;max-width:none}
.places .held{visibility:hidden}
/* its end faded at every width (#305 review: from 561 to about 1030 px five chips don't fit either); the
   padding keeps a row that fits clear of the fade, and the last chip once scrolled to */
.places{padding-right:28px;scroll-padding-inline-end:28px;-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent);mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent)}
/* With a mouse, a thin scrollbar to drag (shift+wheel, trackpads and Tab turn it too), its room always
   kept so the row is the same height whether its chips fit or not (the room the page keeps, #270): 6 px,
   a violet thumb only when there is something to scroll. Chromium and Safari draw it from the
   ::-webkit-scrollbar rules, which Chromium ignores once scrollbar-width or -color is set (other than
   auto: the base's none is undone here); Firefox, without them, takes its thin one. Touch screens
   swipe the row. */
@media (hover:hover) and (pointer:fine){
  .places{overflow-x:scroll;scrollbar-width:auto}
  .places::-webkit-scrollbar{display:block;height:6px}
  .places::-webkit-scrollbar-track,.places::-webkit-scrollbar-corner{background:transparent}
  .places::-webkit-scrollbar-button{display:none}
  .places::-webkit-scrollbar-thumb{background:var(--violet);border-radius:3px}
  @supports not selector(::-webkit-scrollbar){.places{scrollbar-width:thin;scrollbar-color:var(--violet) transparent}}
}
.places .chip b{color:var(--gold)}
.places .chip small{color:var(--faint);font-size:12px}
/* A player's tier on the skill ladder and what the next one needs (#337); the ladder page's tiers */
.ladder{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;margin:14px 0 0;padding:12px 16px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);font-size:13px;color:var(--muted)}
.ladder .rung,.rungs .rung,td .chip.rung{font-weight:700}
.ladder .next b{font-weight:700}
.ladder .gates{display:flex;flex-wrap:wrap;gap:4px 14px;margin:0;padding:0;list-style:none;color:var(--text)}
.ladder .gates li::before{content:"•";margin-right:6px;color:var(--gold)}
.ladder .gates li.ok{color:var(--muted)}
.ladder .gates li.ok::before{content:"✓";color:var(--green)}
/* ... and on narrow screens they keep to the panel (#364 review): the board's cells in short forms (.rs for .rl:
   its skill without the difficulty's name, its place without "top"; the headings say what they are) and smaller
   tier chips up to 700px, its tier under the name (its own column and the maps, which the tier says enough of,
   gone) up to 560px; the tiers table's cells in short forms ("Hard+") and its tiers without the chip up to 450px */
.ladderboard .lsub,.ladderboard .rs,.rungs .rs{display:none}
.rungs td,.rungs th{white-space:normal}  /* (its headings and "20 at Hardcore" wrap where the panel is narrow) */
@media (max-width:700px){
  .ladderboard .chip.rung,.rungs .chip.rung{font-size:11px;padding:1px 7px}
  .ladderboard .rl{display:none}
  .ladderboard .rs{display:inline}  /* (the skill's difficulty, then, for screen readers only) */
}
@media (max-width:560px){
  .ladderboard .lrank,.ladderboard .lmaps{display:none}
  .ladderboard .lsub{display:inline-flex;margin-top:3px}
}
@media (max-width:450px){
  .rungs .rl{display:none}
  .rungs .rs{display:inline}
  .rungs td{font-size:13px}.rungs th{letter-spacing:0}.rungs td,.rungs th{padding:8px 2px}
  .rungs .chip.rung{background:none;border:0;padding:0}  /* (its name in its colour) */
}
.phead .isme{margin-left:auto;min-width:7em}  /* "Not me" as wide as "This is me" (104 px), which the page draws first (#270) */
.card .thumb .done{position:absolute;right:8px;bottom:8px;background:var(--green);color:#06210f;font-weight:800;border-radius:999px;padding:1px 8px;font-size:12px}
.you-strip{margin:18px 0 0}
/* a new record: who and the time (the time goes under a long name, never cut off; a name too long for
   the card ends in an ellipsis, whole in its title), then by how much it beat the one before and when,
   wrapping rather than cut off on a narrow card */
.records .t>span{display:block}
.records .t .who{display:flex;flex-wrap:wrap;white-space:nowrap}
.records .who .nm{display:flex;min-width:0;margin-right:4px}  /* (the dot stays with the name) */
.records .who bdi{min-width:0;overflow:hidden;text-overflow:ellipsis;margin-right:4px}
.records .who .ms{flex:none}
.records time{white-space:nowrap}
.records .t .gain{display:inline-block;white-space:nowrap;margin-right:4px;padding:0 7px;border-radius:999px;background:rgba(70,211,126,.14);
  color:var(--green);font:700 11.5px/1.6 "JetBrains Mono",monospace}
#random{white-space:nowrap}
/* Name suggestions in a player search (#149) */
.suggest{position:absolute;left:0;right:0;top:100%;z-index:20;margin:4px 0 0;padding:4px;list-style:none;background:var(--panel2);border:1px solid var(--edge);border-radius:10px;box-shadow:var(--shadow);max-width:460px}
.suggest li a{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:8px}
.suggest li[aria-selected="true"] a,.suggest li a:hover{background:var(--violet)}
.suggest .head{width:24px;height:24px;font-size:12px}
/* Motion (#185): parkour moves, small, and played once, but for the logo's run, which goes on with two
   ghosts and a button to stop it (above; static/js/logo.js). The logo lands and its runner runs over
   its blocks, the 404 page's runner misses a jump (tools/make_course.py, below), cards and lists land as they scroll in,
   and a map's picture hops on its card. Only without reduced motion, and the scroll-in only where the
   browser drives animations by scrolling (elsewhere they simply show). Only transforms and opacity
   move, so nothing shifts the layout (#32). */
.fall{display:block;width:min(480px,100%);height:auto;margin:28px 0 0}
@media (prefers-reduced-motion:no-preference){
  .hero .logo{animation:pgg-land .7s cubic-bezier(.3,.7,.4,1) both;transform-origin:50% 100%}
  .card:hover .thumb .pic,.card:hover .thumb>svg,.mini:hover .pic,.mini:hover>svg,.nav .brand:hover .mark img{animation:pgg-hop .45s cubic-bezier(.3,.7,.4,1);transform-origin:50% 100%}
  @supports (animation-timeline:view()) and (animation-range:entry 0% entry 70%){  /* (without ranges a card would slide in all the way across the screen) */
    /* not .panel or .motd: a leaderboard's, or the Map of the Day on a landscape phone, is taller
       than the screen and would stay half slid in */
    .grid .card,.strip .mini,.stat{animation:pgg-in linear;animation-timeline:view();animation-range:entry 0% entry 70%}
  }
}
@keyframes pgg-land{0%{translate:0 -22px;scale:.98 1.03}45%{translate:0 0;scale:1.03 .95}70%{scale:.99 1.01}100%{translate:0 0;scale:1 1}}
@keyframes pgg-hop{0%{translate:0 0}40%{translate:0 -8px;scale:.96 1.05}70%{translate:0 0;scale:1.05 .94}100%{translate:0 0;scale:1 1}}
/* (moves only, no fade: a card halfway in would show its text below 4.5:1, #269) */
@keyframes pgg-in{0%{translate:0 28px;scale:.97}100%{translate:0 0;scale:1}}
/* course: begin (written by tools/make_course.py) */
@media (prefers-reduced-motion:no-preference){
@keyframes pgg-f-x{0%{transform:translate(164px,0);opacity:1}20%{transform:translate(164px,0);opacity:1}64%{transform:translate(464px,0);opacity:1;animation-timing-function:step-end}64.4%{transform:translate(164px,0);opacity:0}84%{transform:translate(164px,0);opacity:0;animation-timing-function:ease-out}100%{transform:translate(164px,0);opacity:1}}@keyframes pgg-f-y{0%{transform:translate(0,181px)}20%{transform:translate(0,181px);animation-timing-function:cubic-bezier(.33,.66,.66,1)}34%{transform:translate(0,131px);animation-timing-function:cubic-bezier(.33,0,.66,.33)}64%{transform:translate(0,430px);animation-timing-function:step-end}64.4%{transform:translate(0,181px)}100%{transform:translate(0,181px)}}@keyframes pgg-f-s{0%{transform:none}15.2%{transform:none;animation-timing-function:ease-out}20%{transform:scale(1.14,0.84);animation-timing-function:ease-out}24%{transform:scale(0.9,1.12);animation-timing-function:ease-out}32%{transform:none}100%{transform:none}}.fall .f-x{animation:pgg-f-x 2.5s linear both}.fall .f-y{animation:pgg-f-y 2.5s both}.fall .f-s{animation:pgg-f-s 2.5s both}
}
/* course: end */
/* the admin pages (#211, templates/admin.html, static/js/admin.js) */
.admin .tabs{margin-top:-4px}
.admin-msg{color:var(--muted)}
.admin-tiles{grid-template-columns:repeat(auto-fill,minmax(210px,1fr));margin:18px 0}
.admin-tiles .stat b{font-size:22px;line-height:1.25;margin:4px 0 2px;overflow-wrap:anywhere}
.admin-tiles .stat .lbl{display:block;color:var(--faint);font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.6px}
.admin-tiles code,.admin dd code{font:500 12px "JetBrains Mono",monospace;color:var(--lav);overflow-wrap:anywhere}
.admin .panel{margin:0 0 16px}
.admin .panel h3{margin:16px 0 6px;font-size:13px;color:var(--faint);font-weight:600;text-transform:uppercase;letter-spacing:.6px}
.admin-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr));gap:16px;align-items:start}
.admin-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,480px),1fr));gap:16px;align-items:start}
.admin-stack{display:grid;gap:16px}
.admin-stack .panel{margin:0}
.state{display:inline-flex;align-items:center;gap:2px;font-weight:700;font-size:12.5px;padding:1px 8px;border-radius:999px;border:1px solid currentColor;white-space:nowrap}
.state.ok{color:var(--green)}.state.warn{color:var(--gold)}.state.bad{color:var(--red)}.state.none{color:var(--faint)}
.kv{display:grid;grid-template-columns:fit-content(45%) minmax(0,1fr);gap:6px 14px;margin:0;font-size:14px}
.kv dt{color:var(--muted);overflow-wrap:anywhere}
.kv .state{white-space:normal}.kv dd{margin:0;min-width:0;overflow-wrap:anywhere}
.admin .note{color:var(--lav);font-size:13px;overflow-wrap:anywhere}
.admin .faint{color:var(--faint)}
.log{margin:0;max-height:260px;overflow:auto;background:var(--bg2);border:1px solid var(--line);border-radius:10px;padding:10px;
  font:500 12px/1.5 "JetBrains Mono",monospace;color:var(--lav);white-space:pre-wrap;overflow-wrap:anywhere}
.admin-foot{color:var(--faint);font-size:13px;margin:6px 0 30px}
.admin-sub{margin:28px 0 0;font-size:18px}
.admin-count{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin:10px 0 14px;font-size:14px;color:var(--muted)}
.admin-warn{margin:16px 0 0;display:grid;gap:6px}
.admin-warn p{margin:0}
.admin .tablewrap:focus-visible{outline:2px solid var(--violet2);outline-offset:2px}
.admin table.top td.lbl{min-width:14em;width:100%}
.admin table.top td.states{min-width:16em;font-size:13px;color:var(--muted)}
.admin table.top td.lbl>span:first-child{display:block;overflow-wrap:anywhere}
.admin table.top small{display:block;margin-top:2px;color:var(--faint);font-size:12px}
.admin table.top code{font:500 12.5px "JetBrains Mono",monospace}
.hbar{display:block;height:6px;margin-top:5px;background:transparent}
.hbar i{display:block;height:100%;min-width:2px;background:#9a74ff;border-radius:0 4px 4px 0}
.chart .legend{display:flex;gap:16px;font-size:13px;color:var(--muted);margin:0 0 6px}
.chart .legend .key{display:inline-block;width:14px;height:2px;border-radius:1px;vertical-align:middle;margin-right:6px}
.chart .plot{position:relative;outline:none;border-radius:8px;touch-action:pan-y}
.chart .plot:focus-visible{box-shadow:0 0 0 2px var(--violet2)}
.chart svg{display:block;max-width:100%;height:auto}
.chart .grid{stroke:#2a2064;stroke-width:1}
.chart .axis{fill:var(--faint);font:500 11px Inter,system-ui,sans-serif}
.chart .cross{stroke:var(--muted);stroke-width:1}
.chart .dot{stroke:var(--panel);stroke-width:2}
.chart .tip{position:absolute;top:8px;min-width:130px;background:var(--panel2);border:1px solid var(--edge);border-radius:10px;padding:8px 10px;
  font-size:13px;color:var(--muted);pointer-events:none;box-shadow:var(--shadow)}
.chart .tip .when{color:var(--text);font-weight:600;margin-bottom:2px}
.chart .tip b{color:var(--text);margin-left:6px}
.chart .tip .line{display:inline-block;width:12px;height:2px;vertical-align:middle}
.chart details.daily{margin-top:10px;font-size:14px}
.chart details.daily summary{cursor:pointer;color:var(--violet2)}
/* the game's own data (#291, #292): a map's falls, a playlist's maps in order, challenges, videos */
ol.falls{margin:4px 0 0;padding-left:20px}
ol.falls li{margin:2px 0}
ol.grid.playlist{list-style:none;padding:0;margin:0}
.challenges{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px}
.challenges h3{margin:0 0 6px}
.challenges h3 small{color:var(--faint);font-weight:400;font-size:13px}
.start-here{margin-top:24px}
.start-here .strip{margin-top:12px}
ul.featured-in{padding-left:20px}
ul.featured-in li{margin:4px 0}
.chip.tier{font-size:11px;padding:1px 7px;vertical-align:1px}
.feed td.who{width:30%}
.feed td.m{max-width:0;width:30%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:560px){.feed .when{display:none}.feed td,.feed th{padding:9px 5px}}
/* the record and hardest-maps lists (#412): the long header wraps; below 761 px the difficulty, the all-time count
   and the record beaten give way, so the map's name keeps its room; on phones its builder too */
.feed td.m .by{color:var(--muted)}
.feed th.fb{white-space:normal}
@media (max-width:760px){.feed .d,.feed .fb,.feed .beat{display:none}}
@media (max-width:560px){.feed td.m .by{display:none}}
/* the longest-standing records: on phones the place gives way to the day, which is the point of the list */
@media (max-width:560px){.longest-list .rk{display:none}}
@media (max-width:450px){.chip.tier{display:none}}
/* "About this map" (#262) */
.about{margin-top:24px}
.about h2{margin-top:0}
.about p{max-width:72ch}
.about .facts{margin-top:12px}
