/* Shared by the laser trainer (index.html) and the map explorer (explorer.html, plus explorer.css): the look of a CS
   radar overview. Slate grounds, map names in condensed callout caps, coordinates in mono, and four colors that mean
   what the trigger volumes mean in a map (T): --hurt red for lasers and damage, --teleport blue for links to other
   places, --trigger yellow for what can be pressed (and focus), --push green for new, done and copied. */
/* Barlow's subsets: vietnamese first, as Google Fonts orders them, so that latin-ext keeps the letters both have */
@font-face { font-family: 'Barlow'; font-weight: 400; font-display: swap; src: url(fonts/barlow-400-vietnamese.woff2) format('woff2');
  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: 'Barlow'; font-weight: 400; font-display: swap; src: url(fonts/barlow-400-latin.woff2) format('woff2');
  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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Barlow'; font-weight: 400; font-display: swap; src: url(fonts/barlow-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, 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: 'Barlow'; font-weight: 500; font-display: swap; src: url(fonts/barlow-500-vietnamese.woff2) format('woff2');
  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: 'Barlow'; font-weight: 500; font-display: swap; src: url(fonts/barlow-500-latin.woff2) format('woff2');
  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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Barlow'; font-weight: 500; font-display: swap; src: url(fonts/barlow-500-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, 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: 'Barlow'; font-weight: 600; font-display: swap; src: url(fonts/barlow-600-vietnamese.woff2) format('woff2');
  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: 'Barlow'; font-weight: 600; font-display: swap; src: url(fonts/barlow-600-latin.woff2) format('woff2');
  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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Barlow'; font-weight: 600; font-display: swap; src: url(fonts/barlow-600-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, 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: 'Barlow Condensed'; font-weight: 500; font-display: swap; src: url(fonts/barlow-condensed-500-vietnamese.woff2) format('woff2');
  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: 'Barlow Condensed'; font-weight: 500; font-display: swap; src: url(fonts/barlow-condensed-500-latin.woff2) format('woff2');
  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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Barlow Condensed'; font-weight: 500; font-display: swap; src: url(fonts/barlow-condensed-500-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, 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: 'Barlow Condensed'; font-weight: 600; font-display: swap; src: url(fonts/barlow-condensed-600-vietnamese.woff2) format('woff2');
  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: 'Barlow Condensed'; font-weight: 600; font-display: swap; src: url(fonts/barlow-condensed-600-latin.woff2) format('woff2');
  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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Barlow Condensed'; font-weight: 600; font-display: swap; src: url(fonts/barlow-condensed-600-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, 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: 'Barlow Condensed'; font-weight: 700; font-display: swap; src: url(fonts/barlow-condensed-700-vietnamese.woff2) format('woff2');
  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: 'Barlow Condensed'; font-weight: 700; font-display: swap; src: url(fonts/barlow-condensed-700-latin.woff2) format('woff2');
  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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Barlow Condensed'; font-weight: 700; font-display: swap; src: url(fonts/barlow-condensed-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
/* Barlow Condensed has no Cyrillic: Roboto Condensed's takes its place for those letters only, so Russian callouts stay
   condensed caps (and the words fit the touch buttons). One variable file, named once per weight: a face with a range
   of weights would be a family of its own to Chrome, and chosen over Barlow's for every letter, Latin too */
@font-face { font-family: 'Barlow Condensed'; font-weight: 500; font-display: swap; src: url(fonts/roboto-condensed-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family: 'Barlow Condensed'; font-weight: 600; font-display: swap; src: url(fonts/roboto-condensed-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family: 'Barlow Condensed'; font-weight: 700; font-display: swap; src: url(fonts/roboto-condensed-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family: 'JetBrains Mono'; font-weight: 400 500; font-display: swap; src: url(fonts/jetbrains-mono-latin.woff2) format('woff2'); }

:root {
  --ground: #19222a;
  --terrain: #202b34;
  --plate: #283540;
  --plate-hi: #304050;
  --rule: #34444f;
  --rule-soft: #26323c;
  --ink: #eef3f6;
  --ink-2: #aab9c4;
  --ink-3: #8797a4;
  --hurt: #ff5a5a;
  --teleport: #5ca3ff;
  --trigger: #ffd23f;
  --trigger-ink: #1a1300;
  --push: #44e08e;
  --panel: rgb(25 34 42 / 0.96);
  --ring: 0 0 0 3px rgb(255 210 63 / 0.2);
  --call: 'Barlow Condensed', 'Arial Narrow', sans-serif;
  --ui: 'Barlow', system-ui, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, Consolas, monospace;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  color-scheme: dark;
}
/* Barlow has no Cyrillic, Chinese or Japanese: those letters come from the system's fonts (Cyrillic callouts from the
   face above), the closest first */
html:lang(zh) { --ui: 'Barlow', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', 'Noto Sans CJK SC', system-ui, sans-serif;
  --call: 'Barlow Condensed', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', 'Noto Sans CJK SC', sans-serif; }
html:lang(ja) { --ui: 'Barlow', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Yu Gothic UI', Meiryo, 'Noto Sans JP', 'Noto Sans CJK JP', system-ui, sans-serif;
  --call: 'Barlow Condensed', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Yu Gothic UI', Meiryo, 'Noto Sans JP', 'Noto Sans CJK JP', sans-serif; }

/* the page's text waits for its translation (src/lang.js), one small request, rather than show in English first;
   should that request hang, the English shows after 3 s */
html.lang-wait [data-i18n] { visibility: hidden; animation: lang-late 0s 3s forwards; }
html.lang-wait ::placeholder { color: transparent; }
@keyframes lang-late { to { visibility: visible; } }

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--ground); color: var(--ink); font: 15px/1.45 var(--ui); }
::selection { background: rgb(255 210 63 / 0.35); color: var(--ink); }
[hidden] { display: none !important; }
a { color: inherit; }
button { font: inherit; color: inherit; cursor: pointer; }
:focus-visible { outline: 2px solid var(--trigger); outline-offset: 2px; }
#view, #view canvas { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }

/* a map name in callout caps; the "ze_" prefix small above it, the underscores dim (src/sites.js callout) */
.callout { font-family: var(--call); font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em; line-height: 1.02; overflow-wrap: break-word; }
.callout small { display: block; font-size: 12px; font-weight: 600; letter-spacing: 0.12em; line-height: 1.3; color: var(--ink-3); }
.callout i { font-style: normal; opacity: 0.4; }
.caps { font-family: var(--call); font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; }

/* the radar logomark, next to a page's title; its sweep turns slowly. The sweep is an svg of its own: turning a part of
   an svg lays out and paints it on the main thread every frame, turning a whole one is left to the compositor. */
.mark { position: relative; flex: none; display: block; width: 34px; height: 34px; }
.mark svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.mark .sweep { animation: sweep 4s linear infinite; }
@keyframes sweep { to { transform: rotate(360deg); } }

/* skeletons: what is still loading, in its place and at the size it will have (the page does not move when it comes),
   pulsing. Opacity is the compositor's, so none of this repaints; .sk holds a line of text's height with a &nbsp;. */
.sk, .ghost .thumb, .ghost .mp-thumb, .thumb.loading, .mp-thumb.loading, .primary:disabled, .scenario:disabled {
  animation: pulse 1.5s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: 0.45; } }
.sk { display: block; width: var(--w, 60%); border-radius: 3px; background: var(--plate); color: transparent; }
.ghost { pointer-events: none; }

/* the version next to a site's name; a green dot until its changelog is opened (src/changelog.js) */
.ver { display: inline-flex; align-items: center; height: 24px; padding: 0 8px; border: 1px solid var(--rule); border-radius: 4px;
  background: var(--terrain); font: 500 12px/1 var(--mono); color: var(--ink-2); white-space: nowrap; transition: border-color 0.15s, color 0.15s; }
.ver:hover { border-color: var(--trigger); color: var(--ink); }
.ver.new::before { content: ''; margin-right: 6px; width: 7px; height: 7px; border-radius: 50%; background: var(--push); box-shadow: 0 0 0 3px rgb(68 224 142 / 0.18); }

/* drawn arrows after a link's text: out to another site, on, or back */
.out::after, .on-arrow::after, .back-arrow::before { content: ''; flex: none; display: inline-block; width: 0.95em; height: 0.95em;
  vertical-align: -0.12em; background: currentColor; mask: var(--arrow) center / contain no-repeat; }
.out::after { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 17 17 7M9 7h8v8'/%3E%3C/svg%3E"); margin-left: 0.25em; }
.on-arrow::after { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E"); margin-left: 0.35em; }
.back-arrow::before { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 12H5M11 6l-6 6 6 6'/%3E%3C/svg%3E"); margin-right: 0.35em; }

/* a link to the other site or elsewhere: teleport blue */
.teleport { display: inline-flex; align-items: center; gap: 8px; height: 38px; padding: 0 14px; border-radius: 4px; text-decoration: none;
  border: 1px solid rgb(92 163 255 / 0.45); background: rgb(92 163 255 / 0.1); color: color-mix(in srgb, var(--teleport) 25%, var(--ink)); font: 600 15px/1 var(--call);
  letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap; transition: background-color 0.15s, border-color 0.15s; }
.teleport:hover { background: rgb(92 163 255 / 0.2); border-color: var(--teleport); }
.teleport::before { content: ''; width: 8px; height: 8px; border-radius: 2px; background: var(--teleport); }
.teleport.out::after { margin-left: -2px; }

/* ------------------------------------------------------------------ in a map */

#fade, #flash { position: fixed; inset: 0; pointer-events: none; opacity: 0; }
#flash { background: radial-gradient(transparent 40%, color-mix(in srgb, var(--hurt) 60%, transparent)); }
#flash.on { animation: flash 0.4s ease-out; }
@keyframes flash { from { opacity: 1; } to { opacity: 0; } }

#crosshair { position: fixed; left: 50%; top: 50%; width: 4px; height: 4px; margin: -2px 0 0 -2px; background: #7dff7d; border-radius: 50%; pointer-events: none; }

/* trainer HUD: health, speed and time bottom left in callout figures */
#hud { position: fixed; inset: 0; pointer-events: none; text-shadow: 0 1px 2px var(--ground); }
body:not(.playing) #hud, body:not(.playing) #crosshair { display: none; }
#stats { position: absolute; left: 16px; bottom: 14px; display: flex; align-items: baseline; gap: 20px; padding: 6px 14px 7px; border-radius: 4px;
  border: 1px solid var(--rule-soft); background: color-mix(in srgb, var(--ground) 70%, transparent); font: 600 14px var(--call); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2); }
#stats b { margin-right: 3px; font: 700 26px/1 var(--call); letter-spacing: 0.01em; color: var(--ink); font-variant-numeric: tabular-nums; }
#seed, #lag, #practice, #ranked { font: 500 12px var(--mono); letter-spacing: 0; text-transform: none; color: var(--ink-3); }
#lag:empty, #practice:empty, #ranked:empty { display: none; }
#practice { color: var(--ink); } /* set for this run, and it changes what the run means */
#chat { position: absolute; left: 16px; bottom: 66px; max-width: min(640px, 80vw); display: flex; flex-direction: column; gap: 2px; }
#chat div { background: color-mix(in srgb, var(--ground) 50%, transparent); padding: 2px 8px; border-radius: 4px; transition: opacity 1s; }
#chat div.old { opacity: 0; }
#center { position: absolute; top: 28%; width: 100%; text-align: center; font-size: 22px; font-weight: 700; }
#hint { position: absolute; top: 12%; width: 100%; text-align: center; font-size: 18px; }
/* playing together (src/together.js): who is in the round, top left, and the countdown to it */
#roster { position: absolute; left: 16px; top: 14px; display: grid; gap: 3px; min-width: 190px; padding: 8px 12px; border-radius: 4px;
  border: 1px solid var(--rule-soft); background: color-mix(in srgb, var(--ground) 70%, transparent); font-size: 14px; text-shadow: none; }
#roster[hidden] { display: none; }
#roster .r-row { display: grid; grid-template-columns: 10px 1fr auto auto; align-items: center; gap: 8px; }
#roster .r-row.gone { opacity: 0.55; }
#roster .r-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#roster .r-state { font: 500 12px var(--mono); color: var(--ink-2); }
#roster .r-wins { font: 700 16px/1 var(--call); color: var(--ink); }
#roster .dot, .together .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--c); box-shadow: 0 0 0 2px rgb(0 0 0 / 0.35); }
#countdown { position: absolute; top: 30%; width: 100%; text-align: center; font: 700 96px/1 var(--call); color: var(--trigger);
  text-shadow: 0 3px 18px rgb(0 0 0 / 0.6); pointer-events: none; }
#countdown[hidden] { display: none; }
#banner-ready { margin-top: 12px; }

/* the controls list, top right over a map in both games (keysCard in src/controls.js) */
#keys { position: fixed; right: 14px; top: 12px; width: 280px; padding: 10px 12px 8px; border: 1px solid var(--rule); border-radius: 6px;
  background: rgb(25 34 42 / 0.86); backdrop-filter: blur(6px); font-size: 13.5px; pointer-events: none; text-shadow: none; }
body.browsing #keys { display: none; }
#keys h2 { display: flex; justify-content: space-between; align-items: center; margin: 0 0 6px; font: 700 13px var(--call);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3); }
#keys h2 span { font: 500 12px var(--ui); letter-spacing: 0; text-transform: none; }
#keys .row { display: grid; grid-template-columns: 96px 1fr; gap: 8px; align-items: center; padding: 2px 0; }
#keys .row.active .what { color: var(--ink); }
#keys .what { color: var(--ink-2); white-space: nowrap; }
#keys kbd { margin-bottom: 2px; }
#keys .state { margin-left: 6px; padding: 1px 6px; border-radius: 3px; background: var(--plate); color: var(--ink-3);
  font: 700 11px var(--call); letter-spacing: 0.1em; text-transform: uppercase; }
#keys .state.on { background: var(--trigger); color: var(--trigger-ink); }
/* while the triggers show: what their colors mean */
#keys .legend-rows { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--rule-soft); display: grid; grid-template-columns: 1fr 1fr; gap: 3px 10px; }
#keys .legend-rows span { display: flex; align-items: center; gap: 7px; color: var(--ink-2); font-size: 12.5px; }
#keys .legend-rows i { width: 10px; height: 10px; border-radius: 2px; background: var(--c); }
@media (max-width: 720px), (max-height: 420px) { #keys { display: none; } }

#banner { position: fixed; left: 50%; top: 40%; transform: translate(-50%, -50%); text-align: center; padding: 18px 32px 16px;
  border: 1px solid var(--rule); border-radius: 6px; background: var(--panel); pointer-events: none; }
#banner h2 { margin: 0 0 6px; font: 700 40px/1 var(--call); letter-spacing: 0.04em; text-transform: uppercase; }
#banner.dead h2 { color: var(--hurt); }
#banner.won h2 { color: var(--push); }
#banner p { margin: 0; color: var(--ink-2); }
/* how the server's check of a ranked run went (src/ranked.js) */
#banner #banner-ranked { margin-top: 8px; font-size: 14px; }
#banner .ranked-good { color: var(--push); }
#banner .ranked-bad { color: var(--hurt); }

/* what is loading, under the menu that is already up; alone (an error) it takes the middle of the page */
#status { position: fixed; z-index: 4; left: 50%; bottom: 16px; transform: translateX(-50%); padding: 12px 18px; max-width: calc(100vw - 32px);
  border: 1px solid var(--rule); border-radius: 6px; background: var(--panel); font: 500 13px var(--mono); color: var(--ink-2); }
body:has(#menu[hidden]) #status { bottom: auto; top: 50%; transform: translate(-50%, -50%); }
#status:empty { display: none; }

/* ------------------------------------------------------------------ the menus over a map */

#menu { position: fixed; inset: 0; display: grid; place-items: center; background: rgb(8 12 15 / 0.5); padding: 16px; }
#menu { transition: background-color 0.15s; }
/* UI text never selects (the user, 2026-11-05): a click, double click or drag on the menus, lists, drawers and HUD only
   acts; what is typed into a field and the contact address still select */
body:not(.admin) { user-select: none; -webkit-user-select: none; }
body:not(.admin) :is(input:not([type=checkbox], [type=radio], [type=range], [role=switch]), textarea, [contenteditable], .contact) { user-select: text; -webkit-user-select: text; }
.panel, .panel > *, .settings > *, .set-groups > *, #pane-settings > * { transition: opacity 0.15s, background-color 0.15s, border-color 0.15s, box-shadow 0.15s; }
/* moving a FOV slider fades everything but that slider, so the view behind shows the result */
body.fov-preview #menu, body.fov-preview .panel { background: transparent; }
body.fov-preview .panel { border-color: transparent; box-shadow: none; }
body.fov-preview .panel:not(.tabbed) > :not(.settings), body.fov-preview .settings > :not(.previewing),
body.fov-preview .panel.tabbed > :not(.panes), body.fov-preview #pane-settings > :not(.set-groups),
body.fov-preview .set-groups > :not(:has(.previewing)) { opacity: 0; pointer-events: none; }
body.fov-preview .settings > .previewing { background: var(--panel); box-shadow: 0 0 0 8px var(--panel); border-radius: 2px; }
body.fov-preview #crosshair { display: block; }
.panel { width: min(600px, 100%); max-height: 100%; overflow: auto; padding: 20px 24px 18px; border: 1px solid var(--rule); border-radius: 8px;
  background: var(--panel); box-shadow: 0 30px 70px -30px rgb(0 0 0 / 0.95); scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
.panel-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.panel h1 { display: flex; align-items: center; gap: 12px; margin: 0; font: 700 28px/1 var(--call); letter-spacing: 0.04em; text-transform: uppercase; overflow-wrap: anywhere; }
.panel-head .teleport { margin-left: auto; height: 32px; padding: 0 11px; font-size: 14px; }
.mappick { display: flex; align-items: center; gap: 12px; margin: 0 0 14px; }
.mappick > span { font: 700 13px/1 var(--call); letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3); }

/* map dropdown (src/mappicker.js) */
.mp { position: relative; flex: 1; min-width: 0; }
.mp-button { display: flex; align-items: center; gap: 10px; width: 100%; padding: 6px 12px 6px 6px; text-align: left;
  border: 1px solid var(--rule); border-radius: 6px; background: var(--terrain);
  transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s; }
.mp-button:hover { border-color: var(--plate-hi); background: var(--plate); }
.mp-button[aria-expanded=true] { border-color: var(--trigger); background: var(--plate); }
.mp-button:focus-visible { outline: none; border-color: var(--trigger); box-shadow: var(--ring); }
.mp-list:focus-visible { outline: 2px solid var(--trigger); outline-offset: 2px; }
.mp-thumb { flex: none; width: 72px; aspect-ratio: 16 / 9; border-radius: 3px; background: var(--plate) var(--img, none) center / cover no-repeat; }
.mp-button.ghost { pointer-events: none; }
.mp-name.sk { --w: 55%; margin-bottom: 2px; }
.mp-sub.sk { --w: 75%; }
.mp-thumb.none { display: grid; place-items: center; color: var(--ink-3); font: 500 9px var(--mono); }
.mp-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.mp-name { color: var(--ink); font: 700 18px/1.1 var(--call); letter-spacing: 0.03em; text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-sub { color: var(--ink-3); font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-chevron { flex: none; width: 8px; height: 8px; margin: 0 4px 4px; border: solid var(--ink-3); border-width: 0 2px 2px 0; transform: rotate(45deg); transition: transform 0.25s var(--ease); }
.mp-button[aria-expanded=true] .mp-chevron { transform: translateY(4px) rotate(-135deg); }
.mp-list { position: absolute; z-index: 1; left: 0; right: 0; top: calc(100% + 6px); max-height: min(340px, 60vh); overflow: auto;
  margin: 0; padding: 5px; list-style: none; border: 1px solid var(--rule); border-radius: 6px; background: var(--terrain);
  box-shadow: 0 18px 40px -12px rgb(0 0 0 / 0.9); scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
.mp-option { display: flex; align-items: center; gap: 10px; padding: 5px 6px; border-radius: 4px; cursor: pointer; }
.mp-option.active { background: var(--plate); }
.mp-option[aria-selected=true] .mp-name { color: var(--trigger); }

/* a map whose lasers are not fully tested (scenario file "beta"): the strongest neutral, a filled chip in the lightest
   ink, as none of the four inks means that */
.beta { display: inline-block; flex: none; margin-left: 8px; padding: 4px 7px 3px; border-radius: 4px; background: var(--ink); color: var(--ground); font: 700 14px/1 var(--call); letter-spacing: 0.1em; text-transform: uppercase; text-shadow: none; vertical-align: middle; }
/* who made a map's lasers or a run for the trainer (scenario lasersBy): the changelog's thanks colours (li.thanks) */
.mp-by { color: var(--trigger); font-size: 12.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lasers-by { margin: 0 0 8px; padding: 10px 14px; border: 1px solid var(--trigger); border-radius: 6px; background: rgb(255 210 63 / 0.12); color: var(--ink); font-size: 14px; font-weight: 600; }
.lasers-by .thanked, .scenario .run-by .thanked { color: var(--trigger); font-weight: 800; }
.scenario span.run-by { margin-top: 3px; color: var(--ink); font-size: 12.5px; font-weight: 600; }
.beta-note { margin: 0 0 8px; padding: 10px 14px; border: 1px solid var(--ink-2); border-radius: 6px; background: var(--plate); color: var(--ink); font-size: 14px; }
.empty { margin: 0 0 8px; padding: 12px 14px; border: 1px dashed var(--rule); border-radius: 6px; color: var(--ink-2); }
.empty a { color: var(--teleport); }
.empty button.link, #status button.link { padding: 0; border: 0; background: none; color: var(--teleport); text-decoration: underline; text-underline-offset: 3px; }
/* the one button that starts or resumes: trigger yellow */
.primary { display: block; width: 100%; margin-bottom: 10px; padding: 11px 14px 10px; border: 0; border-radius: 4px; background: var(--trigger); color: var(--trigger-ink);
  font: 700 18px/1 var(--call); letter-spacing: 0.1em; text-transform: uppercase; transition: background-color 0.15s; }
.primary:hover { background: #ffe066; }
.primary:disabled { background: var(--plate-hi); color: var(--ink-2); cursor: progress; }
/* a button beside or under the primary one */
.plain { padding: 9px 14px 8px; border: 1px solid var(--rule); border-radius: 4px; background: none; font: 600 15px/1 var(--call); letter-spacing: 0.1em; text-transform: uppercase; white-space: nowrap; }
.plain:hover { border-color: var(--trigger); }
.resume-row { display: flex; gap: 8px; }
.resume-row .primary { flex: 1; min-width: 0; }
.resume-row .plain { margin-bottom: 10px; }
.resume-row #restart-run { color: var(--ink); }
/* a laser scenario: a short red beam before its name, like the ones it makes you dodge */
.scenario { display: block; width: 100%; margin-bottom: 8px; padding: 10px 14px; text-align: left; border: 1px solid var(--rule-soft); border-radius: 6px;
  background: var(--terrain); transition: border-color 0.15s, background-color 0.15s; }
.scenario strong { display: flex; align-items: center; gap: 10px; font: 700 19px/1.1 var(--call); letter-spacing: 0.03em; text-transform: uppercase; }
.scenario strong::before { content: ''; flex: none; width: 16px; height: 2px; background: var(--hurt); }
.scenario span { display: block; padding-left: 26px; }
.scenario span { color: var(--ink-2); font-size: 13.5px; }
.scenario:hover { border-color: var(--trigger); background: var(--plate); }
.scenario:disabled { border-color: var(--rule-soft); background: var(--terrain); cursor: progress; }
.scenario.ghost strong { --w: 55%; }
.scenario.ghost strong::before { display: none; }
.scenario.ghost span { --w: 80%; height: 16px; margin-top: 3.6px; padding: 0; }
.primary:focus-visible, .scenario:focus-visible, .secondary:focus-visible { outline: 2px solid var(--trigger); outline-offset: 2px; }
.settings { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 18px; margin: 16px 0 14px; padding-top: 14px; border-top: 1px solid var(--rule-soft); }
.settings label { display: flex; flex-direction: column; gap: 5px; color: var(--ink-2); font-size: 14px; }
.settings label.check { flex-direction: row; align-items: center; gap: 10px; color: var(--ink); cursor: pointer; }
.settings .field { width: 100%; }
.settings output { position: absolute; right: 0; top: 0; color: var(--ink); font: 500 13px var(--mono); }

/* the number field and the dropdown before src/controls.js takes them over: the same box, so nothing moves */
.settings > label > select:not(.dd-native), .settings > label > input[type=number] { appearance: none; width: 100%; height: 38px; padding: 0;
  border: 1px solid var(--rule); border-radius: 4px; background: var(--terrain); color: transparent; animation: pulse 1.5s ease-in-out infinite; }

/* sliders: a slim track filled up to the thumb; --fill (0..1) comes from main.js, Firefox fills it natively */
.settings input[type=range] { --thumb: 16px; --track: 4px; -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px; margin: 0; background: transparent; cursor: pointer; }
.settings input[type=range]:focus-visible { outline: none; }
.settings input[type=range]::-webkit-slider-runnable-track { height: var(--track); border-radius: var(--track);
  background: linear-gradient(to right, var(--trigger) calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--fill, 0)), var(--plate-hi) 0); }
.settings input[type=range]::-moz-range-track { height: var(--track); border-radius: var(--track); background: var(--plate-hi); }
.settings input[type=range]::-moz-range-progress { height: var(--track); border-radius: var(--track); background: var(--trigger); }
.settings input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none;
  width: var(--thumb); height: var(--thumb); margin-top: calc((var(--track) - var(--thumb)) / 2); border: 3px solid var(--ground); border-radius: 50%;
  background: var(--ink); transition: box-shadow 0.15s, transform 0.15s; }
.settings input[type=range]::-moz-range-thumb { width: var(--thumb); height: var(--thumb); border: 3px solid var(--ground); border-radius: 50%;
  background: var(--ink); transition: box-shadow 0.15s, transform 0.15s; }
.settings input[type=range]:hover::-webkit-slider-thumb { box-shadow: 0 0 0 5px rgb(255 210 63 / 0.22); }
.settings input[type=range]:hover::-moz-range-thumb { box-shadow: 0 0 0 5px rgb(255 210 63 / 0.22); }
.settings input[type=range]:active::-webkit-slider-thumb { box-shadow: 0 0 0 7px rgb(255 210 63 / 0.3); transform: scale(1.12); }
.settings input[type=range]:active::-moz-range-thumb { box-shadow: 0 0 0 7px rgb(255 210 63 / 0.3); transform: scale(1.12); }
.settings input[type=range]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--ground), 0 0 0 4px var(--trigger); }
.settings input[type=range]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 2px var(--ground), 0 0 0 4px var(--trigger); }
.settings label:has(output) { position: relative; }
/* a volume: its name and what it covers, the exact value to type at the right, the slider below */
.settings label.vol { position: relative; }
.settings label.vol small { margin-left: 4px; font-size: 12.5px; color: var(--ink-3); }
.settings .vol-num { position: absolute; right: -6px; top: -4px; width: 52px; height: 24px; padding: 0 6px; text-align: right;
  font: 500 13px var(--mono); color: var(--ink); background: none; border: 1px solid transparent; border-radius: 4px; caret-color: var(--trigger); }
.settings .vol-num:hover { border-color: var(--rule); }
.settings .vol-num:focus-visible { outline: none; border-color: var(--trigger); box-shadow: var(--ring); }
/* the seed: typed in, or taken from the last run with the link above it */
.settings label:has(.seed) { position: relative; }
.settings input.seed { width: 100%; padding: 0 12px; font: 500 14px var(--mono); caret-color: var(--trigger); }
.settings input.seed::placeholder { color: var(--ink-3); font-family: inherit; }
.seed-last { position: absolute; right: 0; top: 0; padding: 0; border: 0; background: none; color: var(--ink-2);
  font: 500 13px var(--mono); cursor: pointer; text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
.seed-last:hover { color: var(--trigger); text-decoration-color: currentColor; }
.secondary { align-self: center; justify-self: start; border: 1px solid var(--rule); background: var(--plate); border-radius: 4px; padding: 6px 14px; }
.secondary:hover { border-color: var(--plate-hi); background: var(--plate-hi); }

/* the controls line: key caps */
.keys { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 4px 0 10px; font-size: 13.5px; color: var(--ink-2); }
.keys span { white-space: nowrap; }
kbd { display: inline-block; min-width: 20px; margin-right: 3px; padding: 0 5px; border: 1px solid var(--rule); border-bottom-width: 2px; border-radius: 3px;
  background: var(--terrain); color: var(--ink); text-align: center; font: 500 11px/1.6 var(--mono); }
/* the menus' help: short points behind "How it works" */
.help { margin: 2px 0 0; }
.help summary { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; list-style: none;
  font: 700 13px/1 var(--call); letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-2); }
.help summary::-webkit-details-marker { display: none; }
.help summary::before { content: ''; width: 6px; height: 6px; border: solid currentColor; border-width: 0 2px 2px 0; transform: rotate(-45deg); transition: transform 0.2s var(--ease); }
.help[open] summary::before { transform: rotate(45deg); }
.help summary:hover { color: var(--ink); }
.note { display: grid; gap: 6px; max-width: 68ch; margin: 10px 0 0; padding: 0 0 0 16px; color: var(--ink-2); font-size: 13px; line-height: 1.5; }
.note li::marker { color: var(--ink-3); }

/* bug reports and ideas (src/contact.js, src/feedback.js), plus the version and friends; selectable, unlike the rest of the menu */
.contact { margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--rule-soft); color: var(--ink-2); font-size: 13.5px; }
.contact a { color: var(--teleport); text-underline-offset: 3px; }
.contact a:hover { color: #8fc0ff; }
.contact button { padding: 0 6px; border: 1px solid var(--rule); border-radius: 4px; background: var(--terrain); color: var(--ink); }
.contact button:hover { border-color: var(--trigger); }
.contact button.copied { border-color: var(--push); color: var(--push); }
.contact-do { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.contact .contact-do button { padding: 5px 11px 4px; font: 600 14px/1.2 var(--call); letter-spacing: 0.08em; text-transform: uppercase; }
/* while a language translated by machine is on (src/lang.js) */
.mt-note { margin: 10px 0 0; color: var(--ink-3); font-size: 12.5px; }
.foot .mt-note { margin-top: 6px; }
.dd-note { display: block; margin-top: 1px; color: var(--ink-3); font-size: 11.5px; font-weight: 400; }
.menu-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 10px 0 0; font-size: 13px; color: var(--ink-3); }
.menu-foot a { color: var(--teleport); text-underline-offset: 3px; }
.menu-foot button.link { padding: 0; border: 0; background: none; color: var(--teleport); text-decoration: underline; text-underline-offset: 3px; }

/* ------------------------------------------------------------------ the trainer's menu in tabs (index.html, src/main.js pickTab)
   The head and the account stay put; under them one part at a time, scrolling on its own, and the Resume row at the
   foot. The panel keeps one height, so picking a tab never makes it jump. The explorer's panel is the plain one. */
#menu .panel.tabbed { position: relative; display: flex; flex-direction: column; width: min(760px, 100%); height: min(100%, 780px); overflow: hidden; padding-bottom: 0; }
.panel.tabbed > * { flex: none; }
.panel.tabbed > .account { margin-bottom: 2px; padding-bottom: 12px; border-bottom: 0; }
.tabs { display: flex; gap: 2px; margin: 0 -24px; padding: 0 14px; border-bottom: 1px solid var(--rule); overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tab { position: relative; flex: none; padding: 12px 10px 11px; border: 0; background: none; color: var(--ink-3);
  font: 700 16px/1 var(--call); letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap; transition: color 0.15s; }
.tab::after { content: ''; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 2px; border-radius: 2px 2px 0 0; background: transparent; transition: background-color 0.15s; }
.tab:hover { color: var(--ink-2); }
.tab[aria-selected=true] { color: var(--ink); }
.tab[aria-selected=true]::after { background: var(--trigger); }
.tab:focus-visible { outline: 2px solid var(--trigger); outline-offset: -5px; border-radius: 6px; }
.tab[hidden], .pane[hidden] { display: none; }
.panel.tabbed > .panes { flex: 1; min-height: 0; overflow: auto; margin: 0 -24px; padding: 18px 24px 20px; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
.panel.tabbed > .resume-row { margin: 0 -24px; padding: 12px 24px 14px; border-top: 1px solid var(--rule); }
.panel.tabbed > .resume-row:not(:has(> :not([hidden]))) { display: none; }
.panel.tabbed > .resume-row > * { margin-bottom: 0; }
/* a phone, or a window too low for the head to stay: the whole panel scrolls, the tabs and the Resume row stay in reach */
@media (max-width: 560px), (max-height: 560px) {
  #menu .panel.tabbed { display: block; overflow: auto; padding-top: 0; } /* the head has it: nothing shows above the stuck tabs */
  .panel.tabbed > .panel-head { padding-top: 20px; }
  body.touch .panel.tabbed > .panel-head { padding-top: 8px; }
  .panel.tabbed > .tabs { position: sticky; top: 0; z-index: 2; background: var(--ground); }
  /* four tabs across a phone in any language (Mehrspieler, Nhiều người chơi): tighter, and shared out if room is left */
  .tabs { gap: 0; }
  .tab, body.touch .tab { flex: 1 0 auto; padding-inline: 6px; font-size: 15px; letter-spacing: 0.05em; }
  .tab::after { left: 6px; right: 6px; }
  .panel.tabbed > .panes { overflow: visible; }
  .panel.tabbed > .resume-row { position: sticky; bottom: 0; z-index: 2; background: var(--ground); }
}
@media (max-width: 380px) { /* a narrow phone (360 px) */
  .tab, body.touch .tab { padding-inline: 4px; font-size: 14px; letter-spacing: 0.02em; }
  .tab::after { left: 4px; right: 4px; }
}
/* Play: the section, the map, ranked mode, the scenarios side by side */
/* the sections (src/sections.js): three links in a row, the page's own shown as a chosen graphics level is. Neutral: none
   of the four inks means a section, but lasers keep their red beam dash */
.sections { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; margin: 0 0 16px; }
.section { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; min-height: 40px; padding: 11px 12px 9px;
  border: 1px solid var(--rule-soft); border-radius: 4px; color: var(--ink-2); text-decoration: none; -webkit-tap-highlight-color: transparent;
  transition: background-color 0.15s, border-color 0.15s, color 0.15s; }
.section-name { display: flex; align-items: center; gap: 5px 9px; min-width: 0; font: 700 17px/1 var(--call); letter-spacing: 0.1em; text-transform: uppercase; }
.section-count { color: var(--ink-3); font: 500 12px/1 var(--mono); white-space: nowrap; }
.section-lasers .section-name::before { content: ''; flex: none; width: 14px; height: 2px; background: var(--hurt); }
.section .beta { margin-left: 0; } /* the name's gap spaces it */
.section-name:has(.beta) { flex-wrap: wrap; } /* only the chip goes under the name where a cell is narrow */
.section[href]:hover { background: var(--plate); color: var(--ink); }
.section[aria-current] { border-color: var(--plate-hi); background: var(--plate); color: var(--ink); }
.section:focus-visible { outline: 2px solid var(--trigger); outline-offset: 2px; }
.section[aria-disabled] { opacity: 0.45; }
.section.ghost { align-items: center; }
.section.ghost .section-name { --w: 50%; height: 15px; }
.section.ghost .section-name::before { display: none; }
.section.ghost .section-count { --w: 22%; height: 12px; }
body.touch .section { min-height: 44px; }
@media (max-width: 440px) { .section { flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; }
  .section-name { gap: 5px 7px; font-size: 15px; letter-spacing: 0.06em; }
  .section-lasers .section-name::before { width: 10px; }
  .section .beta { padding: 3px 5px 2px; font-size: 12px; } } /* a phone's narrow cells: it wraps under the name if need be */
/* a course's row (bhop, surf): a neutral dash where a laser scenario has its red beam */
.scenario.course strong::before { background: var(--ink-3); }
#pane-play .mappick { margin-bottom: 14px; }
#ranked-mode { margin: 0 0 16px; padding: 10px 12px; border: 1px solid var(--rule-soft); border-radius: 6px; }
#ranked-mode:empty { display: none; }
#pane-play #scenarios { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(310px, 100%), 1fr)); gap: 8px; }
#pane-play #scenarios > p { grid-column: 1 / -1; margin: 0; }
#pane-play #scenarios > .scenario-group { grid-column: 1 / -1; margin: 10px 0 0; color: var(--ink-3); font: 700 13px/1 var(--call); letter-spacing: 0.14em; text-transform: uppercase; }
#pane-play .scenario { display: flex; flex-direction: column; gap: 4px; margin: 0; }
/* Together: the room has the pane to itself */
#pane-together .together { margin: 0; padding: 0; border: 0; }
#pane-together .together .tg-lines { max-height: 240px; }
/* Settings: four groups in two columns (how you play and see; the practice tools and sound), the graphics across */
.set-lock { margin: 0 0 18px; padding: 10px 14px; border: 1px solid var(--rule); border-radius: 6px; background: var(--plate); color: var(--ink-2); font-size: 13.5px; }
.set-lock[hidden] { display: none; }
.set-groups { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 36px; align-items: start;
  grid-template-areas: "controls practice" "view practice" "sound bosses" ". bosses" "graphics graphics"; }
.panel.tabbed .set-group { grid-template-columns: minmax(0, 1fr); gap: 12px; margin: 0; padding: 0; border: 0; }
.set-controls { grid-area: controls; }
.set-view { grid-area: view; }
.set-practice { grid-area: practice; }
.set-sound { grid-area: sound; }
.set-bosses { grid-area: bosses; }
.settings label.check small { display: block; margin-top: 2px; font-size: 12.5px; color: var(--ink-3); }
.panel.tabbed .set-wide { grid-area: graphics; padding-top: 20px; border-top: 1px solid var(--rule-soft); }
.set-wide .levels { margin-top: 0; }
.set-head { margin: 0 0 2px; color: var(--ink-3); font: 700 13px/1 var(--call); letter-spacing: 0.14em; text-transform: uppercase; }
@media (max-width: 700px) {
  .set-groups { grid-template-columns: minmax(0, 1fr); grid-template-areas: none; gap: 22px; }
  .set-groups > .set-group, .panel.tabbed .set-wide { grid-area: auto; }
}
/* Help: the keys, how it works, the ways to write */
#pane-help .keys { margin-top: 0; }
#pane-help .help summary { margin-bottom: 2px; }

/* ------------------------------------------------------------------ the changelog (src/changelog.js) and the forms (src/feedback.js) */

.log-scrim, .fb-scrim { position: fixed; inset: 0; z-index: 30; background: rgb(6 10 13 / 0.6); opacity: 0; pointer-events: none; transition: opacity 0.25s; }
.log, .fb { position: fixed; z-index: 31; top: 0; right: 0; bottom: 0; width: min(500px, 100vw); display: flex; flex-direction: column;
  background: var(--terrain); border-left: 1px solid var(--rule); transform: translateX(100%); visibility: hidden;
  transition: transform 0.35s var(--ease), visibility 0s 0.35s; }
body.log-open .log-scrim, body.fb-open .fb-scrim { opacity: 1; pointer-events: auto; }
body.log-open .log, body.fb-open .fb { transform: none; visibility: visible; transition: transform 0.35s var(--ease); }
.log header, .fb header { display: flex; align-items: center; justify-content: space-between; padding: 18px 22px 0; }
.log h2, .fb h2 { margin: 0; font: 700 28px/1 var(--call); letter-spacing: 0.06em; text-transform: uppercase; }
.log .x, .fb .x { display: grid; place-items: center; width: 34px; height: 34px; padding: 0; border: 1px solid var(--rule); border-radius: 4px; background: none; color: var(--ink-2); }
.log .x svg, .fb .x svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; }
.log .x:hover, .fb .x:hover { border-color: var(--trigger); color: var(--ink); }
.log-intro { margin: 8px 22px 0; color: var(--ink-3); font-size: 13.5px; }
/* every version on one line, newest lit; the line scrolls once they do not fit, what leaves it fading at the ends */
.log-strip { flex: none; display: flex; min-height: 48px; margin: 12px 0 4px; padding: 4px 16px; overflow: auto hidden; overscroll-behavior: contain; scrollbar-width: none;
  mask-image: linear-gradient(to right, transparent, #000 16px, #000 calc(100% - 16px), transparent); }
.log-strip::-webkit-scrollbar { display: none; }
.log-strip button { position: relative; flex: 1 0 44px; display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 0; border: 0; background: none; font: 500 11px/1 var(--mono); color: var(--ink-3); }
.log-strip button::before { content: ''; position: relative; z-index: 1; width: 9px; height: 9px; margin-top: 9px; border-radius: 50%; background: var(--terrain); border: 2px solid var(--ink-3); }
/* each version draws its piece of the line, which runs from the first dot to the last */
.log-strip button::after { content: ''; position: absolute; left: 0; right: 0; top: 13px; height: 1px; background: var(--rule); }
.log-strip button:first-child::after { left: 50%; }
.log-strip button:last-child::after { right: 50%; }
.log-strip button.now { color: var(--push); }
.log-strip button.now::before { background: var(--push); border-color: var(--push); box-shadow: 0 0 0 4px rgb(68 224 142 / 0.2); }
.log-strip button:hover { color: var(--ink); }
.log-list { flex: 1; overflow: auto; padding: 4px 22px 30px; scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
.release { padding: 20px 0 18px; }
/* an update and the fixes that follow it, the fixes above it: smaller, and on a line that leads down to it */
.series, .release.ghost { border-bottom: 1px solid var(--rule-soft); }
.series:last-child { border-bottom: 0; }
.release.fix { margin-left: 3px; padding: 14px 0 6px 14px; border-left: 1px solid var(--rule); }
.series > .release.fix:first-child { margin-top: 16px; }
.release.fix .v { font-size: 22px; }
.release.fix .top + ul { margin-top: 8px; }
/* the forms; what they send along shows in a dashed box, the map list reuses the rows of the trainer's map dropdown */
.fb-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.fb-form { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 14px; padding: 8px 22px 22px; overflow: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
.fb-intro { margin: 0; color: var(--ink-3); font-size: 13.5px; }
.fb-field { display: block; }
.fb-field > span { display: block; margin-bottom: 6px; font: 700 13px/1.2 var(--call); letter-spacing: 0.14em; text-transform: uppercase; }
.fb-field small { margin-left: 4px; font: 400 12.5px var(--ui); letter-spacing: 0; text-transform: none; color: var(--ink-3); }
.fb textarea, .fb input:not([role=switch]) { display: block; width: 100%; padding: 9px 12px; border: 1px solid var(--rule); border-radius: 4px; background: var(--ground); color: var(--ink); font: 15px/1.45 var(--ui);
  caret-color: var(--trigger); user-select: text; -webkit-user-select: text; transition: border-color 0.15s, box-shadow 0.15s; }
.fb input:not([role=switch]) { flex: none; }
.fb textarea { min-height: 112px; resize: vertical; }
.fb textarea:focus, .fb input:not([role=switch]):focus { outline: none; border-color: var(--trigger); box-shadow: var(--ring); }
.fb ::placeholder { color: var(--ink-3); opacity: 1; }
.fb-sent { padding: 10px 12px; border: 1px dashed var(--rule); border-radius: 6px; color: var(--ink-3); font-size: 13px; }
.fb-sent h3 { margin: 0 0 6px; font: 700 13px/1.2 var(--call); letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-2); }
.fb-sent p { margin: 0; }
.fb-sent .fb-place { margin-bottom: 4px; font: 500 12px/1.5 var(--mono); color: var(--ink-2); overflow-wrap: anywhere; }
.fb-switch { display: flex; align-items: flex-start; gap: 10px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--rule-soft); cursor: pointer; }
.fb-switch b { display: block; font-weight: 600; color: var(--ink-2); }
.fb-switch small { display: block; font-size: 13px; color: var(--ink-3); }
.fb-status { margin: 0; color: var(--hurt); font-size: 13.5px; }
.fb-status:empty { display: none; }
.fb-form .primary { flex: none; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-maps { flex: 1 1 200px; min-height: 180px; margin: 0; padding: 5px; list-style: none; overflow: auto; overscroll-behavior: contain; border: 1px solid var(--rule); border-radius: 6px;
  background: var(--ground); scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
.fb-maps .mp-option:hover { background: var(--plate); }
.fb-maps .mp-option[aria-selected=true] { background: var(--plate-hi); }
.fb-none { padding: 12px; color: var(--ink-3); font-size: 13.5px; }
.fb-done { padding: 14px 22px 22px; }
.fb-done p { margin: 0 0 14px; color: var(--push); font-size: 15px; overflow-wrap: anywhere; }
.fb-done .primary { margin-bottom: 8px; }
.fb-done .plain { display: block; width: 100%; }
/* the note to first-time visitors (src/welcome.js) and the one on a new update (src/changelog.js), with the
   headline and the buttons of the menus */
.welcome { width: min(440px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); margin: auto; padding: 0; overflow: auto; overscroll-behavior: contain;
  border: 1px solid var(--rule); border-radius: 6px; background: var(--terrain); color: var(--ink); }
.welcome::backdrop { background: rgb(6 10 13 / 0.6); }
.welcome-in { padding: 22px; }
.welcome h2 { margin: 0 0 14px; font: 700 28px/1 var(--call); letter-spacing: 0.06em; text-transform: uppercase; }
.welcome p { margin: 0 0 12px; color: var(--ink-2); }
.welcome-do { display: flex; gap: 8px; margin-top: 20px; }
.welcome-do > * { flex: 1; min-width: 0; }
.welcome .primary { margin: 0; }

/* the account row under the menu's head (src/account.js): who is signed in, or the Steam button, then their keys and the board */
.account { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; margin: 0 0 14px; padding-bottom: 14px; border-bottom: 1px solid var(--rule-soft); }
.account[hidden] { display: none; }
.account .who { display: inline-flex; align-items: center; gap: 8px; min-width: 0; margin-right: auto; font-weight: 600; }
.account .who b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ava { flex: none; width: 26px; height: 26px; border-radius: 3px; object-fit: cover; background: var(--plate); }
.account .steam-in { margin-right: auto; }
.steam-in { display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 12px; border: 1px solid var(--rule); border-radius: 4px;
  background: var(--ground); color: var(--ink); font: 600 14px var(--ui); text-decoration: none; white-space: nowrap; }
.steam-in:hover { border-color: var(--teleport); }
.steam-in svg { flex: none; width: 18px; height: 18px; fill: currentColor; }
.steam-in.big { justify-content: center; height: auto; padding: 10px 14px; }
.plain.small { padding: 7px 11px 6px; font-size: 13px; }
.account button.link { padding: 0; border: 0; background: none; color: var(--ink-3); font: 13px var(--ui); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.account button.link:hover { color: var(--ink); }
.account-note { flex-basis: 100%; color: var(--ink-2); font-size: 13px; }
/* playing together in the menu (src/together.js): the way in, or the room with its link, players and Ready */
.together { display: grid; gap: 10px; margin: 0 0 14px; padding-bottom: 14px; border-bottom: 1px solid var(--rule-soft); }
.together[hidden] { display: none; }
.together .tg-area { display: grid; gap: 10px; }
.together .tg-area:empty { display: none; }
.together .tg-area > button.plain { justify-self: start; }
.together .tg-what { color: var(--ink-2); font-size: 13px; }
.together .tg-area > .tg-what { margin-top: -4px; }
.together .tg-note { margin: 0; color: var(--ink-2); font-size: 14px; }
.together .tg-note.bad { color: var(--hurt); }
.together .tg-head { display: flex; align-items: baseline; gap: 10px; }
.together .tg-head b { font: 700 18px/1.1 var(--call); text-transform: uppercase; letter-spacing: 0.02em; }
.together .tg-count { color: var(--ink-3); font-size: 13px; margin-right: auto; }
.together button.link, .together-dialog button.link { padding: 0; border: 0; background: none; color: var(--ink-3); font: 13px var(--ui);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.together .tg-link { display: flex; align-items: center; gap: 8px; }
.together .tg-link .field { flex: 1; min-width: 0; font: 13px var(--mono); }
/* a room's code: big enough to read out to a friend */
.together .tg-code-label { color: var(--ink-3); font-size: 13px; }
.together .tg-link .tg-code { flex: 0 1 9ch; font: 700 22px/1 var(--mono); letter-spacing: 0.18em; text-align: center; }
.together .tg-join { display: flex; gap: 8px; }
.together .tg-join .tg-code-in { flex: 0 1 12ch; min-width: 0; font: 700 16px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; }
.together .tg-join .tg-code-in::placeholder { font: 400 14px var(--ui); letter-spacing: 0; text-transform: none; }
.together .tg-players { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; }
.together .tg-players li { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto auto auto; align-items: center; gap: 8px; }
.together .tg-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.together .tg-state { color: var(--ink-3); font-size: 13px; }
.together .tg-state.on { color: var(--push); }
.together .tg-host { padding: 1px 6px; border-radius: 3px; background: var(--plate); color: var(--ink-2); font-size: 12px; }
.together .tg-wins { font: 700 18px/1 var(--call); min-width: 1ch; text-align: right; }
.together .tg-pick { display: grid; grid-template-columns: auto 1fr; gap: 8px; }
.together .tg-pick .tg-which { grid-column: 1 / -1; }
.together .tg-rotate { grid-column: 1 / -1; display: flex; align-items: center; gap: 10px; color: var(--ink-2); font-size: 14px; cursor: pointer; }
.together .tg-do { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.together .tg-chat { display: grid; gap: 6px; }
.together .tg-chat[hidden] { display: none; }
.together .tg-lines { display: grid; gap: 2px; max-height: 150px; overflow: auto; margin: 0; padding: 6px 8px; list-style: none;
  border: 1px solid var(--rule-soft); border-radius: 4px; background: var(--ground); font-size: 14px; overflow-wrap: anywhere; }
.together .tg-lines:empty { display: none; }
.together .tg-sys, #chat .tg-sys { color: var(--ink-3); font-style: italic; }
.together .tg-say { display: flex; gap: 8px; }
.together .tg-say .field { flex: 1; min-width: 0; }
/* a chat line typed in the game (src/together.js openChat), above the lines */
#saybox { position: absolute; left: 16px; bottom: 66px; width: min(480px, 70vw); pointer-events: auto; }
#saybox[hidden] { display: none; }
body:has(#saybox:not([hidden])) #chat { bottom: 112px; }
.together-dialog .tg-modes { display: grid; gap: 8px; margin: 0 0 12px; }
.together-dialog .tg-mode { display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: start; padding: 10px 12px;
  border: 1px solid var(--rule); border-radius: 6px; cursor: pointer; }
.together-dialog .tg-mode:has(input:checked) { border-color: var(--trigger); background: rgb(255 210 63 / 0.06); }
.together-dialog .tg-mode input { margin-top: 3px; accent-color: var(--trigger); }
.together-dialog .tg-mode b { display: block; font: 700 17px/1.2 var(--call); text-transform: uppercase; }
.together-dialog .tg-mode span span { color: var(--ink-2); font-size: 14px; }
.together-dialog .tg-scenario { display: grid; gap: 5px; margin: 0 0 8px; color: var(--ink-2); font-size: 14px; }
/* ranked mode (src/account.js): a line of its own under the name, the switch and what it means */
.ranked-mode { flex-basis: 100%; display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 2px 10px; cursor: pointer; }
.ranked-mode b { font-size: 14px; }
.ranked-what { grid-column: 2; color: var(--ink-2); font-size: 13px; line-height: 1.4; }
/* what ranked mode keeps as the game is: shown, but not to be changed (src/main.js applyRankedMode) */
.settings label.locked { opacity: 0.45; cursor: not-allowed; }
.settings label.locked .field:disabled { animation: none; opacity: 1; }
.settings label.locked input, .settings label.locked select, .settings label.locked button { pointer-events: none; }

/* the key editor and the time board, in the dialog of the notes */
.keys-dialog { width: min(520px, calc(100vw - 32px)); }
.keys-table { display: grid; gap: 4px; }
.keys-row { display: grid; grid-template-columns: 1fr 124px 124px; align-items: center; gap: 8px; }
.keys-what { color: var(--ink-2); font-size: 14.5px; }
.keys-slot { display: flex; align-items: center; gap: 4px; min-width: 0; }
.keycap { flex: 1; min-width: 0; height: 30px; padding: 0 8px; border: 1px solid var(--rule); border-radius: 4px; background: var(--ground);
  color: var(--ink); font: 500 13px var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.keycap:hover:not(:disabled) { border-color: var(--trigger); }
.keycap:focus-visible { outline: none; border-color: var(--trigger); box-shadow: var(--ring); }
.keycap:disabled { cursor: default; color: var(--ink-2); }
.keycap.waiting { border-color: var(--trigger); color: var(--trigger); font-family: var(--ui); }
.keys-clear { flex: none; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 3px; background: none; color: var(--ink-3); cursor: pointer; }
.keys-clear:hover { color: var(--hurt); background: var(--plate); }
.welcome .keys-warn { margin: 12px 0 0; color: var(--hurt); font-size: 13.5px; }
.keys-warn:empty { display: none; }
/* one set of columns down the whole list (subgrid): the versions, ranks and times line up whatever their width */
.board { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: 30px minmax(0, 1fr) auto auto; gap: 2px 10px;
  max-height: 50vh; overflow: auto; }
.board li { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; border-radius: 3px; }
.board-row { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: center; width: 100%; padding: 5px 6px; border: 0;
  border-radius: 3px; background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.board-row:hover { background: var(--plate); }
.board-row:focus-visible { outline: none; box-shadow: var(--ring); }
.board-pick-row { margin: 0 0 12px; }
.board-pick-row[hidden] { display: none; }
.board-pick-row .field { width: 100%; }
.board-race { margin-left: 6px; padding: 0; border: 0; background: none; color: var(--teleport); font: 13px var(--ui); cursor: pointer; }
/* an endless board's best run one may race, over the list; one's own profile's switch for being raced */
.board-race-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; margin: 0 0 12px; }
.board-race-row[hidden] { display: none; }
.board-race-what { color: var(--ink-3); font-size: 13px; }
.board-race-name { text-transform: none; letter-spacing: 0.02em; }
.welcome .race-allow { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--rule-soft); }
.welcome .board-back { margin: 0 0 12px; padding: 0; border: 0; background: none; color: var(--teleport); font: 14px var(--ui); cursor: pointer; }
.profile-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 10px; font-weight: 600; }
.profile-head .who { display: inline-flex; align-items: center; gap: 8px; }
.profile-head .time, .profile .time { font: 500 13px var(--mono); color: var(--ink-2); white-space: nowrap; }
.profile { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; gap: 4px 10px; }
.profile li { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: center; padding: 4px 6px; }
/* the release an entry was played in, and Beta when its map was in beta then (src/account.js played) */
.board-ver { display: inline-flex; align-items: center; gap: 6px; font: 500 11px var(--mono); color: var(--ink-3); white-space: nowrap; }
.board .time, .profile .time, .profile .rank { text-align: right; }
.board-ver .beta { margin: 0; padding: 2px 4px 1px; font-size: 10px; letter-spacing: 0.06em; background: var(--ink-3); }
.profile .rank { font: 500 12px var(--mono); color: var(--ink-3); }
.profile .board-wait, .board .board-wait { grid-column: 1 / -1; }
.profile .board-wait { display: block; color: var(--ink-3); }
.board li.me { background: rgb(255 210 63 / 0.1); }
.board .rank { font: 500 13px var(--mono); color: var(--ink-3); text-align: right; }
.board .who { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.board .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board .time { font: 500 13px var(--mono); color: var(--ink-2); white-space: nowrap; }
.board .board-wait { display: block; color: var(--ink-3); }
.welcome .board-note { font-size: 13.5px; }
@media (max-width: 520px) { .keys-row { grid-template-columns: 1fr 96px 96px; } }
.news .news-kicker { margin: 0 0 8px; font: 700 13px/1.2 var(--call); letter-spacing: 0.14em; text-transform: uppercase; color: var(--push); }
.news-lines, .news-more { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.news-lines li { display: grid; grid-template-columns: 62px 1fr; gap: 10px; font-size: 14.5px; color: var(--ink-2); }
.news-there { display: inline-block; margin-top: 12px; color: var(--teleport); font-size: 14px; text-underline-offset: 3px; }
.news .news-also { margin: 20px 0 8px; padding-top: 14px; border-top: 1px solid var(--rule-soft);
  font: 700 13px/1.2 var(--call); letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3); }
.news-more { gap: 2px; }
.news-more button { display: flex; align-items: baseline; gap: 10px; width: 100%; padding: 4px 0; border: 0; background: none; color: var(--ink-2); font: 14.5px var(--ui); text-align: left; }
.news-more button .v { flex: none; min-width: 44px; font: 500 12px var(--mono); color: var(--ink-3); }
.news-more button:hover { color: var(--ink); }
.news-rest { padding: 4px 0 0 54px; color: var(--ink-3); font-size: 13.5px; }

.release .top { display: flex; align-items: baseline; gap: 12px; }
.release .v { font: 700 36px/1 var(--call); letter-spacing: 0.02em; }
.release.now .v { color: var(--push); }
.release time { font: 500 12px var(--mono); color: var(--ink-3); }
.release h3 { margin: 6px 0 10px; font: 600 16px var(--ui); }
.release ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.release.ghost .sk { margin-bottom: 9px; }
.release.ghost .v { --w: 90px; font-size: 30px; line-height: 1; }
.release.ghost .title { --w: 45%; font-size: 16px; }
.release.ghost .line { --w: 90%; font-size: 14px; }
.release.ghost .short { --w: 60%; }
.release li { display: grid; grid-template-columns: 62px 1fr; gap: 10px; font-size: 14.5px; color: var(--ink-2); }
.site-tag { align-self: start; padding: 2px 0; border: 1px solid var(--rule); border-radius: 3px; text-align: center; font: 600 11px/1.3 var(--call);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); }
/* a thank-you line of the changelog: framed in the trigger colour, its words brighter */
li.thanks { padding: 10px 12px; border: 1px solid var(--trigger); border-radius: 6px; background: rgb(255 210 63 / 0.12);
  box-shadow: 0 0 0 3px rgb(255 210 63 / 0.08); }
li.thanks > span:last-child { color: var(--ink); font-size: 1.08em; font-weight: 600; line-height: 1.45; }
li.thanks .thanked { color: var(--trigger); font-weight: 800; }
.site-tag.heart { border-color: var(--trigger); background: var(--trigger); color: var(--trigger-ink); font-size: 13px; }
.site-tag.lasers { border-color: rgb(255 90 90 / 0.5); color: color-mix(in srgb, var(--hurt) 45%, var(--ink)); }

/* ------------------------------------------------------------------ the pages' own controls (src/controls.js) */

/* one look for fields and the buttons that open something: dropdowns, number fields, the explorer's search */
.field { height: 38px; font: inherit; color: var(--ink); border: 1px solid var(--rule); border-radius: 4px;
  background-color: var(--terrain); transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s; }
.field:hover { border-color: var(--plate-hi); }
button.field:hover { background-color: var(--plate); }
.field[aria-expanded=true] { border-color: var(--trigger); background-color: var(--plate); }
.field:focus-visible, .stepper:focus-within { outline: none; border-color: var(--trigger); box-shadow: var(--ring); }
.field:disabled { opacity: 0.5; cursor: default; animation: pulse 1.5s ease-in-out infinite; }
/* the language picker (src/lang.js): a globe and the language's code, in a box that is there before the script builds it;
   its list names each language in its own words */
#lang:not(.dd-native), #map-lang:not(.dd-native) { appearance: none; flex: none; width: 74px; height: 32px; border: 1px solid var(--rule);
  border-radius: 4px; background: var(--terrain); color: transparent; }
#lang + .dd-button, #map-lang + .dd-button { flex: none; height: 32px; padding: 0 9px; gap: 6px;
  font: 500 12px/1 var(--mono); letter-spacing: 0.06em; color: var(--ink-2); }
#lang + .dd-button:hover, #map-lang + .dd-button:hover { color: var(--ink); }
.panel-head #lang + .dd-button, .panel-head #lang:not(.dd-native) { margin-left: auto; }
/* beside the trainer's name only the globe: the name stays on one line (the list names the languages) */
.panel-head #lang + .dd-button { width: 32px; padding: 0; justify-content: center; }
.panel-head #lang + .dd-button :is(.dd-value, .dd-chevron) { display: none; }
.panel-head #lang:not(.dd-native) { width: 32px; }
.panel-head #lang ~ .teleport { margin-left: 0; }
#map-lang + .dd-button, #map-lang:not(.dd-native) { margin-left: auto; }
.dd-button { display: inline-flex; align-items: center; gap: 8px; padding: 0 12px; text-align: left; white-space: nowrap; cursor: pointer; font-weight: 500; }
.dd-button svg, .dd-list svg, .step svg { flex: none; width: 16px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.dd-icon, .dd-chevron { color: var(--ink-3); }
.dd-chevron { margin-left: auto; transition: transform 0.25s var(--ease); }
[aria-expanded=true] > .dd-chevron { transform: rotate(180deg); }
.dd-value { overflow: hidden; text-overflow: ellipsis; }
.dd-native { display: none !important; }

/* the dropdown's list, hung from <body> */
.dd-list { position: fixed; inset: auto; z-index: 20; margin: 0; padding: 5px; list-style: none; overflow: auto; overscroll-behavior: contain;
  color: var(--ink); font-size: 14px; border: 1px solid var(--rule); border-radius: 6px; background: var(--terrain);
  box-shadow: 0 18px 40px -12px rgb(0 0 0 / 0.9); scrollbar-width: thin; scrollbar-color: var(--rule) transparent;
  user-select: none; transition: opacity 0.15s var(--ease), translate 0.2s var(--ease); }
@starting-style { .dd-list { opacity: 0; translate: 0 -4px; } .dd-list.up { translate: 0 4px; } }
.dd-list:focus { outline: none; }
.dd-option { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 8px 10px;
  border-radius: 4px; white-space: nowrap; cursor: pointer; }
.dd-option.active { background: var(--plate); }
.dd-option[aria-selected=true] { color: var(--trigger); font-weight: 600; }
.dd-check { visibility: hidden; }
.dd-option[aria-selected=true] .dd-check { visibility: visible; }

/* - and + around a number field */
.stepper { display: flex; align-items: stretch; overflow: hidden; }
.stepper input { flex: 1; min-width: 0; width: 100%; margin: 0; padding: 0; border: 0; border-radius: 0; background: transparent;
  color: var(--ink); font: 500 14px var(--mono); text-align: center; outline: none;
  appearance: textfield; -moz-appearance: textfield; caret-color: var(--trigger); }
.stepper input::-webkit-inner-spin-button, .stepper input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.step { flex: none; display: grid; place-items: center; width: 38px; padding: 0; border: 0; background: transparent; color: var(--ink-3);
  transition: background-color 0.15s, color 0.15s; }
.step:hover { background: var(--plate); color: var(--ink); }
.step:active { background: var(--plate-hi); }

/* checkboxes as switches */
input[role=switch] { appearance: none; position: relative; flex: none; width: 34px; height: 20px; margin: 0;
  border: 1px solid var(--rule); border-radius: 999px; background: var(--plate); cursor: pointer;
  transition: background-color 0.2s var(--ease), border-color 0.2s; }
input[role=switch]::before { content: ''; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px;
  border-radius: 50%; background: var(--ink-3); transition: transform 0.3s var(--ease), background-color 0.2s; }
label:hover > input[role=switch] { border-color: var(--plate-hi); }
input[role=switch]:checked { border-color: var(--trigger); background: var(--trigger); }
input[role=switch]:checked::before { transform: translateX(14px); background: var(--trigger-ink); }
input[role=switch]:focus-visible { outline: 2px solid var(--trigger); outline-offset: 2px; }
/* the baked lighting switch under the graphics levels: it only counts at Medium and High (src/graphics.js) */
.lighting-check { grid-column: 1 / -1; }
.lighting-check:has(input:disabled) { opacity: 0.5; cursor: default; }

/* the graphics levels: a table you pick a row of (src/graphics.js) */
.settings .levels, .settings .levels-note { grid-column: 1 / -1; }
.settings .levels { margin-top: 6px; }
.settings .levels-note { margin-top: -4px; }
.levels { --columns: minmax(80px, 1.2fr) repeat(3, minmax(0, 1fr)); display: grid; gap: 2px; }
.level-head, .levels .level { display: grid; grid-template-columns: var(--columns); column-gap: 8px; align-items: center; padding-inline: 10px; }
.level-head { padding-bottom: 3px; color: var(--ink-3); font-size: 12.5px; }
.level-head b { color: var(--ink-2); font-size: 14px; font-weight: 400; }
.levels .level { min-height: 34px; border: 1px solid transparent; border-radius: 4px; color: var(--ink-2); font-size: 13.5px; cursor: pointer;
  -webkit-tap-highlight-color: transparent; transition: background-color 0.15s, border-color 0.15s, color 0.15s; }
.levels .level:hover { background: var(--plate); }
.levels .level:has(:checked) { border-color: var(--plate-hi); background: var(--plate); color: var(--ink); }
.levels .level:has(:focus-visible) { outline: 2px solid var(--trigger); outline-offset: 2px; }
.level-name { display: flex; align-items: center; gap: 9px; color: var(--ink); font: 700 15px/1 var(--call); letter-spacing: 0.06em; text-transform: uppercase; }
.level-size { font: 500 12px var(--mono); white-space: nowrap; }
.level-name input { appearance: none; flex: none; width: 16px; height: 16px; margin: 0; border: 1px solid var(--ink-3); border-radius: 50%; background: var(--terrain);
  cursor: pointer; outline: none; transition: background-color 0.2s var(--ease), border-color 0.2s; }
.level:hover .level-name input { border-color: var(--ink); }
.level-name input:checked, .level:hover .level-name input:checked { border-color: var(--trigger); background: radial-gradient(circle, var(--trigger-ink) 0 3px, var(--trigger) 3.5px); }
.levels-note { margin: 0; padding-inline: 10px; color: var(--ink-3); font-size: 12.5px; line-height: 1.45; }
body.touch .levels .level { min-height: 44px; }

@media (max-width: 520px) { .settings { grid-template-columns: 1fr; } .panel-head { flex-wrap: wrap; } }

/* ------------------------------------------------------------------ on a touch screen */

/* over the map on a touch screen (src/touch.js): what the thumbs reach sits low, what is rarely used up top. No blur
   behind any of it: a phone needs its graphics power for the map. */
#touch { position: fixed; inset: 0; z-index: 3; pointer-events: none; --glass: rgb(25 34 42 / 0.86); --edge: max(10px, env(safe-area-inset-left)); --edge-r: max(10px, env(safe-area-inset-right)); }
.t-top { position: absolute; left: var(--edge); right: var(--edge-r); top: max(10px, env(safe-area-inset-top)); display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px; }
.t-tools { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; margin-left: auto; }
.t-btn { height: 44px; padding: 0 11px; border: 1px solid var(--rule); border-radius: 4px; background: var(--glass); color: var(--ink); pointer-events: auto; touch-action: none;
  font: 600 14px/1 var(--call); letter-spacing: 0.08em; text-transform: uppercase; transition: background-color 0.1s, border-color 0.1s, color 0.1s; }
.t-btn:active, .t-btn[aria-pressed=true] { border-color: var(--trigger); background: var(--trigger); color: var(--trigger-ink); }
.t-act { position: absolute; right: max(18px, calc(env(safe-area-inset-right) + 6px)); bottom: max(22px, calc(env(safe-area-inset-bottom) + 6px)); display: grid; grid-template-columns: repeat(2, 68px); grid-auto-rows: 68px; gap: 8px; }
.t-act .t-btn { height: auto; padding: 0; border-color: var(--ink-3); border-radius: 6px; font: 700 16px/1 var(--call); }
.t-act .t-btn:nth-child(1) { grid-area: 1 / 2; }
.t-act .t-btn:nth-child(2) { grid-area: 2 / 2; }
.t-act .t-btn:nth-child(3) { grid-area: 2 / 1; }
/* the stick rests low on the left and comes to where the thumb lands; away from the very edge, which is the system's back gesture */
#stick { position: absolute; left: max(26px, calc(env(safe-area-inset-left) + 6px)); bottom: max(26px, calc(env(safe-area-inset-bottom) + 6px)); width: 132px; height: 132px; opacity: 0.72;
  transition: opacity 0.2s, translate 0.25s var(--ease); }
#stick svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
#sweep { opacity: 0; transition: opacity 0.15s; }
#knob { position: absolute; left: 50%; top: 50%; width: 46px; height: 46px; margin: -23px; border: 2px solid var(--ground); border-radius: 50%; background: var(--ink); transition: translate 0.25s var(--ease), background-color 0.1s; }
#stick.on { opacity: 1; transition: opacity 0.1s; }
#stick.on #knob { background: var(--trigger); transition: background-color 0.1s; }
#stick.moving #sweep { opacity: 1; }
body.touch #status { left: max(10px, env(safe-area-inset-left)); right: max(10px, env(safe-area-inset-right)); bottom: max(10px, env(safe-area-inset-bottom)); max-width: none; padding: 9px 12px; transform: none; text-align: center; line-height: 1.4; }
/* what the map view asks of a phone: no browser gestures, selection or callouts over the map; the menu and its lists still scroll */
body.touch:not(.browsing) { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }
body.touch:not(.browsing), body.touch #view canvas { touch-action: none; }
body.touch .panel, body.touch .dd-list, body.touch .log-list, body.touch .fb-form, body.touch .fb-maps, body.touch .welcome { touch-action: pan-y; overscroll-behavior: contain; }
body.touch #menu { padding: max(10px, env(safe-area-inset-top)) max(10px, env(safe-area-inset-right)) max(10px, env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-left)); }
body.touch .panel { padding: 8px 16px 14px; }
body.touch .primary { padding: 15px 14px 14px; }
body.touch .settings .field { height: 44px; }
body.touch .settings { margin: 12px 0; padding-top: 12px; }
/* under 16 px iOS zooms the page when a field gets the focus */
body.touch .stepper input { font-size: 16px; }
body.touch .step { width: 48px; }
body.touch .dd-option { padding: 12px 10px; }
body.touch .help summary { padding: 8px 0; }
body.touch #menu .panel.tabbed { padding-bottom: 0; }
body.touch .tabs { margin: 0 -16px; padding: 0 6px; }
body.touch .tab { padding: 15px 10px 14px; }
body.touch .panel.tabbed > .panes { margin: 0 -16px; padding: 14px 16px 18px; }
body.touch .panel.tabbed > .resume-row { margin: 0 -16px; padding: 10px 16px 12px; }
body:not(.touch) .touch-only, body.touch .mouse-only { display: none; }
.t-act .t-btn:nth-child(4) { grid-area: 1 / 1; }
/* with the knife off in the menu, nothing is left for its buttons to do */
body:has(#knife:not(:checked)) .t-knife { display: none; }
/* the small phones: tighter, so that the top row keeps to its rows */
@media (max-width: 389px), (orientation: landscape) and (max-width: 700px) {
  .t-tools { gap: 4px; }
  .t-btn { padding: 0 7px; font-size: 13px; letter-spacing: 0.04em; }
}
/* the trainer's HUD around the thumbs: the stats in the top row (src/touch.js), where the stick does not cover them, and
   what the map says in what is left between the top row and the stick */
body.touch #stats { position: static; height: 44px; align-items: center; gap: 10px; padding: 0 9px; border-color: var(--rule); background: var(--glass);
  font-size: 12px; letter-spacing: 0.06em; white-space: nowrap; }
body.touch #stats b { font-size: 20px; }
body.touch #seed, body.touch #practice { display: none; } /* the practice tools' own buttons show them */
/* the narrow phones: the ping chip would push the tools down a row, and the player set it themselves */
@media (max-width: 389px) {
  body.touch #lag { display: none; }
}
body.touch #chat { left: max(10px, env(safe-area-inset-left)); bottom: calc(max(26px, calc(env(safe-area-inset-bottom) + 6px)) + 142px); font-size: 13px; }
body.touch #center, body.touch #hint { padding-inline: max(12px, env(safe-area-inset-left), env(safe-area-inset-right)); }
body.touch #hint { top: calc(max(10px, env(safe-area-inset-top)) + 104px); }
body.touch #banner { width: max-content; max-width: calc(100vw - 32px); padding: 14px 20px; }
#banner .primary { margin: 12px 0 0; pointer-events: auto; }
@media (orientation: landscape) {
  body.touch #hint { top: calc(max(10px, env(safe-area-inset-top)) + 52px); }
}
/* the sliders of the menu, for a thumb */
body.touch .settings input[type=range] { --thumb: 24px; --track: 6px; height: 36px; }
@media (prefers-reduced-motion: reduce) {
  .mark .sweep, .field:disabled, .sk, .ghost .thumb, .ghost .mp-thumb, .thumb.loading, .mp-thumb.loading, .primary:disabled, .scenario:disabled,
  .settings > label > select, .settings > label > input[type=number] { animation: none; }
  .dd-list, .dd-chevron, .mp-chevron, input[role=switch], input[role=switch]::before, .log, .log-scrim, .fb, .fb-scrim { transition: none; }
  #stick, #knob, #sweep, .t-btn { transition: none; }
}
/* watching a ranked run (src/watch.js): the bar along the bottom, the HUD above it, no controls list of one's own */
body.watching #hud { bottom: 92px; }
body.watching #keys, body.watching:not(.watch-eyes) #crosshair { display: none; }
.watch-bar { position: fixed; z-index: 5; left: 0; right: 0; bottom: 0; padding: 8px max(14px, env(safe-area-inset-right)) max(10px, env(safe-area-inset-bottom)) max(14px, env(safe-area-inset-left));
  border-top: 1px solid var(--rule); background: var(--panel); font: 14px var(--ui); color: var(--ink-2); }
.wb-top { display: flex; align-items: baseline; gap: 6px 16px; flex-wrap: wrap; margin-bottom: 6px; }
.wb-title { flex: 1 1 auto; min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-2); }
.wb-badge { margin-right: 8px; padding: 2px 6px 1px; border-radius: 3px; background: var(--hurt); color: var(--ground); font: 700 12px var(--call); letter-spacing: 0.1em; text-transform: uppercase; }
.wb-name { color: var(--ink); font-weight: 600; }
.wb-hint { margin: 0; font-size: 12.5px; color: var(--ink-3); white-space: nowrap; }
.wb-note { margin: 0 0 6px; font-size: 12.5px; color: var(--trigger); }
.wb-note[hidden] { display: none; }
.wb-row { display: flex; align-items: center; gap: 8px; }
.wb-btn { min-width: 34px; height: 32px; padding: 0 10px; border: 1px solid var(--rule); border-radius: 4px; background: var(--plate); color: var(--ink);
  font: 600 14px/1 var(--call); letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; cursor: pointer; }
.wb-btn:hover { border-color: var(--trigger); }
.wb-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.wb-play { width: 44px; font-size: 15px; }
.wb-cams { display: flex; gap: 2px; }
.wb-cam[aria-pressed=true] { background: var(--trigger); border-color: var(--trigger); color: var(--trigger-ink); }
.wb-time, .wb-speed { font: 500 13px var(--mono); color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.wb-speed { min-width: 44px; text-align: center; }
.wb-scrub { --thumb: 16px; --track: 4px; flex: 1 1 200px; min-width: 80px; height: 26px; margin: 0; -webkit-appearance: none; appearance: none; background: transparent; cursor: pointer; }
.wb-scrub:focus-visible { outline: none; }
.wb-scrub::-webkit-slider-runnable-track { height: var(--track); border-radius: var(--track);
  background: linear-gradient(to right, var(--hurt) calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--fill, 0)), var(--plate-hi) 0); }
.wb-scrub::-moz-range-track { height: var(--track); border-radius: var(--track); background: var(--plate-hi); }
.wb-scrub::-moz-range-progress { height: var(--track); border-radius: var(--track); background: var(--hurt); }
.wb-scrub::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: var(--thumb); height: var(--thumb); margin-top: calc((var(--track) - var(--thumb)) / 2);
  border: 3px solid var(--ground); border-radius: 50%; background: var(--ink); }
.wb-scrub::-moz-range-thumb { width: var(--thumb); height: var(--thumb); border: 3px solid var(--ground); border-radius: 50%; background: var(--ink); }
.wb-scrub:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--ground), 0 0 0 4px var(--trigger); }
.watch-bar.seeking .wb-scrub { opacity: 0.6; }
/* a phone: two rows, the slider over the whole width */
@media (max-width: 720px) {
  .wb-row { flex-wrap: wrap; }
  .wb-scrub { order: -1; flex-basis: 100%; }
  .wb-hint { display: none; }
  body.watching #hud { bottom: 128px; }
}
body.touch .wb-hint { display: none; } /* keys, which a touch screen has none of */
/* on a board and a profile: watch that run (src/account.js) */
.board.watchable { grid-template-columns: 30px minmax(0, 1fr) auto auto auto; }
.board.watchable .board-row { grid-column: 1 / -2; }
.board-watch { align-self: center; padding: 0 4px; color: var(--teleport); font: 13px var(--ui); text-decoration: none; white-space: nowrap; }
.board-watch:hover, .board-race:hover { text-decoration: underline; }
