/* Tibia look: textures, frames, buttons and cursors come from the client's own interface files (ui/). */
:root {
  --ui: url('ui/images');
  --text: #c0c0c0;
  --text-bright: #f4f4f4;
  --muted: #8f8f8f;
  --gold: #f0c850;
  /* The client's interface font: bold Verdana with a 1px black outline (ui/fonts/Verdana10px.fnt). */
  --font: bold 11px/1.45 Verdana, Geneva, sans-serif;
  --shadow: 1px 0 0 #000, -1px 0 0 #000, 0 1px 0 #000, 0 -1px 0 #000, 1px 1px 0 #000;
  /* Seamless stone tiles. Frames only draw their border; the inside is one of these, repeated. */
  --stone: #464646 url('ui/images/background-dark.png');
  --stone-dark: #2c2c2c url('ui/images/backdrop-dark-grey.png');
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body { height: 100%; margin: 0; }

body {
  display: flex;
  flex-direction: column;
  background: var(--stone);
  color: var(--text);
  font: var(--font);
  text-shadow: var(--shadow);
  cursor: url('ui/cursors/cursor-default.png') 0 0, default;
  -webkit-font-smoothing: none;
}

button, label { cursor: url('ui/cursors/cursor-pointinghand.png') 4 2, pointer; }

/* ── Header ─────────────────────────────────────────────────────── */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 46px;
  /* No bar of its own: the stat boxes sit straight on the page's stone background.
     Horizontal padding lines the boxes up with the windows' outer edges below. */
  padding: 6px 6px 0;
}


.stats { display: flex; gap: 8px; }
.stats-left .stat { align-items: flex-start; }
.stat {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  min-width: 92px;
  /* 2px less on top than below: the pixel font leaves empty rows under its letters (for
     descenders), so this centres the visible text in the box. */
  padding: 2px 10px 6px;
  border-style: solid;
  border-width: 3px;
  border-image: url('ui/images/3pixel-frame-borderimage.png') 3 / 3px round;
  background: var(--stone);
}
.stat-text { display: flex; flex-direction: column; align-items: inherit; }
.stat-icon, .stat-progress { display: none; } /* only some top bar looks use these */
.label { color: var(--muted); font-size: 10px; }
.value { color: var(--text-bright); font-weight: bold; font-variant-numeric: tabular-nums; }
.value.gold { color: var(--gold); }

/* ── Windows: the client's window frame, with its dark title bar ── */

main {
  /* Keep the shares equal to the fr values below; the logo's position is worked out from them. */
  --view-share: 1.1;
  --map-share: 1;
  --gap: 6px;
  position: relative;
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: var(--gap);
  padding: var(--gap);
}

/* The logo sits on the line between the two windows, half over each, reaching up into the top bar. */
.game-logo {
  position: absolute;
  z-index: 1;
  top: -44px;
  left: calc(var(--gap) * 1.5 + (100% - var(--gap) * 3) * var(--view-share) / (var(--view-share) + var(--map-share)));
  width: 180px;
  transform: translateX(-50%);
  pointer-events: none;
  filter: drop-shadow(0 3px 6px rgb(0 0 0 / 0.7));
}
main[hidden] { display: none; }

.window {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-style: solid;
  border-width: 15px 4px 4px;
  border-image: url('ui/images/skin/classic/widget-borderimage.png') 15 4 4 / 15px 4px 4px round;
  background: var(--stone);
}

.window-title {
  position: absolute;
  top: -14px;
  left: 0;
  right: 0;
  height: 12px;
  color: var(--text);
  font-size: 10px;
  font-weight: bold;
  line-height: 12px;
  text-align: center;
  white-space: nowrap;
}

.window-body { display: flex; flex-direction: column; flex: 1; min-height: 0; padding: 2px; }

.window-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 4px;
  padding: 6px; /* + the 2px border = 8px around the button on every side */
  /* A flat bar, without the bevel's light top/left edge. To bring the bevel back, replace the
     border line with: border-image: url('ui/images/2pixel-up-frame-borderimage-dark.png') 2 / 2px round; */
  border: 2px solid transparent;
  background: var(--stone-dark);
}

.hint { color: var(--text); }
/* Same space left of the help text as above and below it (the taller button sets the footer height). */
.window-footer .hint { margin-left: 6.5px; }

/* ── Game view and map: sunken into the window like the client's game screen ── */

.view-stage, .map-viewport {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: #000;
  outline: 1px solid #111;
  box-shadow: inset 1px 1px 0 #2a2a2a;
}

#view {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  touch-action: none;
  cursor: url('ui/cursors/cursor-crosshair.png') 11 11, move;
}
.view.static #view { cursor: inherit; }
.view.static #recenter { display: none; }

.map-viewport {
  background: #284da6;
  touch-action: none;
  cursor: url('ui/cursors/cursor-crosshair.png') 11 11, crosshair;
}
.map-layer { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
.map-layer img { display: block; image-rendering: pixelated; user-select: none; }
.map-viewport.smooth .map-layer img { image-rendering: auto; }
.overlay { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }

.map-controls { position: absolute; top: 6px; right: 6px; display: flex; flex-direction: column; gap: 2px; }
/* The client's automap zoom buttons are 20x20 images: a 1px bevel around stone with a 15x14
   magnifier at (3, 3). Here the bevel becomes the border, the inside is stone, and the magnifier
   is cut out of the same image at its own size, with 4px of space around it. */
.map-button {
  --img: url('ui/images/automap-button-zoomin-up.png');
  display: grid;
  place-items: center;
  padding: 4px;
  border: 1px solid;
  border-image: var(--img) 1 / 1px stretch;
  background: var(--stone);
  image-rendering: pixelated;
}
.map-button::before {
  content: '';
  width: 15px;
  height: 14px;
  background: var(--img) -3px -3px no-repeat;
}
.zoom-in { --img: url('ui/images/automap-button-zoomin-up.png'); }
.zoom-in:active { --img: url('ui/images/automap-button-zoomin-down.png'); }
.zoom-out { --img: url('ui/images/automap-button-zoomout-up.png'); }
.zoom-out:active { --img: url('ui/images/automap-button-zoomout-down.png'); }
/* Floor up/down: the automap's move buttons, cut the same way (their arrows fit the same 15x14). */
.floor-up { --img: url('ui/images/automap-button-moveup-up.png'); margin-top: 6px; }
.floor-up:active { --img: url('ui/images/automap-button-moveup-down.png'); }
.floor-down { --img: url('ui/images/automap-button-movedown-up.png'); }
.floor-down:active { --img: url('ui/images/automap-button-movedown-down.png'); }
.map-button:disabled { opacity: 0.45; }
/* Surface-only games have nothing to guess about floors, so the floor controls are left out. */
.map-viewport.no-floors .floor-up, .map-viewport.no-floors .map-floor, .map-viewport.no-floors .floor-down { display: none; }
.map-floor {
  display: grid;
  place-items: center;
  box-sizing: border-box;
  height: 25px; /* as tall as the buttons are wide: a square */
  border: 1px solid #777;
  background: #141414;
  color: var(--text-bright);
}

/* ── Buttons: grey stone, green for the main action ─────────────── */

.btn {
  min-width: 92px;
  padding: 3px 13px 4px;
  color: var(--text-bright);
  font: var(--font);
  text-shadow: var(--shadow);
  background: none;
  border-style: solid;
  border-width: 3px;
  border-image: url('ui/images/skin/classic/button-9grid-idle.png') 3 fill / 3px repeat;
}
.btn:active:not(:disabled) {
  padding: 4px 12px 3px 14px;
  border-image-source: url('ui/images/skin/classic/button-9grid-pressed.png');
}
.btn.primary { border-image-source: url('ui/images/skin/classic/button-green-up.png'); }
.btn.primary:active:not(:disabled) { border-image-source: url('ui/images/skin/classic/button-green-down.png'); }
.btn:disabled { filter: grayscale(1) brightness(0.7); cursor: inherit; }

/* ── Dialogs ────────────────────────────────────────────────────── */

.dialog {
  position: fixed;
  z-index: 5; /* above the game, including its logo; below the info banner */
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 16px;
  background: rgb(0 0 0 / 0.55);
}
.dialog[hidden] { display: none; }
/* The big logo only shows on the start and game-over screens. */
/* Floats above the dialog (outside the layout), so the settings stay centred on the screen. */
.dialog-logo {
  display: none;
  position: absolute;
  left: 50%;
  /* The video is wider and taller than the logo itself (wings above, fire below and to the right),
     so it's placed to keep the finished logo where the still one was: 256px wide, above the title. */
  bottom: calc(100% + 28px);
  width: 300px;
  transform: translateX(calc(-50% + 20px));
  filter: drop-shadow(0 4px 12px rgb(0 0 0 / 0.6));
  pointer-events: none;
}
.dialog.home .dialog-logo { display: block; }
/* The start and game-over screens show a backdrop: a live scene from the game (see game.js),
   or the client's title artwork. */
.dialog.home.backdrop-artwork {
  background: linear-gradient(rgb(0 0 0 / 0.35), rgb(0 0 0 / 0.65)), url('ui/images/title.jpg') center / cover;
}
.backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  filter: brightness(0.7) saturate(0.9);
  display: none;
}
.dialog.home.backdrop-scene .backdrop { display: block; }
.dialog > :not(.backdrop) { position: relative; }
/* The way back to the site's start page with all the games (an arrow) at the top left of a game's start
   screen, and the volume at the top right: 30px square, as the volume panel (.volume-panel). Above the
   window, so the logo's video never covers them. */
.dialog > .hub-link { display: none; position: absolute; z-index: 1; top: 12px; left: 12px; width: 30px; height: 30px; margin: 0; }
.dialog.home > .hub-link { display: grid; }
.hub-link::before { content: ''; width: 6px; height: 9px; background: url('ui/images/icon-arrow.png') no-repeat; image-rendering: pixelated; }
.dialog > .home-sound { position: absolute; z-index: 1; top: 12px; right: 12px; width: 30px; height: 30px; margin: 0; }
/* On the start screen the main button (Start, Play daily challenge) is the only one: the window's full width. */
.dialog.home .dialog-actions #dialog-button { flex: 1; }

.dialog-card {
  width: min(360px, 100%);
  /* The client's dialog frame with a 6px taller title bar (tools/make-dialog-frame.ts). */
  border-width: 23px 4px 4px;
  border-image: url('data/dialog-frame-tall.png') 23 4 4 / 23px 4px 4px round;
}
.dialog-card .window-title { top: -21px; height: 19px; line-height: 19px; }
.dialog-card .window-body { padding: 10px 12px 8px; }
.dialog-card p { margin: 0 0 10px; white-space: pre-line; }
/* The GeoGuesser's start screen tutorial loop (game.js): a 7x3-tile scene, sunk into the window like the game
   screen, at the window's width. By id, as the other games style their own .tutorial. */
#how-to-play {
  position: relative;
  margin: 0 0 10px;
  aspect-ratio: 7 / 3;
  background: #000;
  outline: 1px solid #111;
  box-shadow: inset 1px 1px 0 #2a2a2a;
}
#how-to-play[hidden] { display: none; }
#how-to-play canvas { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; }
.dialog-actions {
  display: flex;
  justify-content: flex-end;
  padding-top: 8px;
  border-top: 5px solid;
  border-image: url('ui/images/divider-horizontal.png') 5 0 0 / 5px 0 0 stretch;
}

/* Setting choices as the client's default stone buttons (see .btn): unchosen ones raised with grey
   text, the chosen one in the client's own pressed state with white text. The radio inputs stay
   for keyboard and screen readers, but aren't drawn. */
.modes { display: grid; gap: 4px; margin: 0 0 10px; padding: 0; border: 0; }
.modes legend { margin-bottom: 4px; }
.choice {
  position: relative;
  border-style: solid;
  border-width: 3px;
  border-image: url('ui/images/skin/classic/button-9grid-idle.png') 3 fill / 3px repeat;
  color: var(--text);
}
.choice:has(input:checked) {
  border-image-source: url('ui/images/skin/classic/button-9grid-pressed.png');
  color: var(--text-bright);
}
.choice:has(input:focus-visible) { outline: 1px solid var(--text); }
.choice input { position: absolute; opacity: 0; pointer-events: none; }

/* Game mode: the figures from Tibia's chase-mode buttons, "follow" (running, green when on) for
   Explore and "stand" (standing still, red when on) for No moving, cut out of the button's stone
   (tools/export-mode-icons.ts). */
.choice.with-icon { display: flex; align-items: center; justify-content: center; gap: 6px; }
.choice .icon { width: 18px; height: 18px; zoom: 1.25; background: no-repeat; image-rendering: pixelated; }
.icon.follow { background-image: url('data/mode-follow-up.png'); }
.icon.stand { background-image: url('data/mode-stand-up.png'); }
.choice:has(input:checked) .icon.follow { background-image: url('data/mode-follow-down.png'); }
.choice:has(input:checked) .icon.stand { background-image: url('data/mode-stand-down.png'); }
/* The pressed figures sit 1px lower and to the right (the client's pressed button); put them back,
   so they don't jump when chosen. */
.choice:has(input:checked) .icon { background-position: -1px -1px; }
/* The running figure leaves room on its right, so Explore looks off-centre: nudge it 2px left. */
.choice.with-icon:has(.icon.follow) { padding-right: 10px; }

/* Dropdown settings side by side: Region and Where, then spots and time. */
.settings-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
/* The High Scores' choices, unlabelled (their options say what they are): sharing the row, full width when alone. */
#score-filters { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 1fr; }
/* Read out, not shown. */
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.dropdown-list { max-height: 260px; overflow-y: auto; }

@media (max-width: 760px) {
  main { grid-template-columns: 1fr; grid-template-rows: minmax(260px, 1fr) minmax(300px, 1fr); }
  .stat { min-width: 0; }
  .game-logo { left: 50%; width: 140px; top: -36px; }
}

/* Text drawn in Tibia's pixel font (see pixelfont.js): one game pixel per CSS pixel, never smoothed. */
.pixel-text { display: inline-block; vertical-align: top; image-rendering: pixelated; }
/* setPixelText's text in the browser's Verdana (useBrowserFont in pixelfont.js), as the GeoGuesser shows all its text. */
.plain-text { display: inline-block; font: var(--font); line-height: 1.45; white-space: nowrap; }
.plain-text.wrap { white-space: normal; }
/* The Server Log's lines wrap (setWrappedPixelText) rather than scroll sideways. */
.server-log { overflow-x: hidden; }
.window-title .pixel-text { margin-top: -1px; }

.choices { display: flex; gap: 4px; }
.choice { flex: 1; padding: 4px 6px; text-align: center; }
.value.warning { color: #ff4040; }

/* Bigger pixel text for buttons and the footer hints. Kept slightly above 1x; the font stays sharp
   (pixelated scaling), though at non-whole sizes a few pixel columns come out one device pixel wider. */
.btn .pixel-text { zoom: 1.25; }
.window-footer .hint .pixel-text { zoom: 1.25; }
.stat .pixel-text { zoom: 1.25; }

/* The distance between your guess and the answer, in the middle of the line (positioned in drawOverlay). */
.distance-label {
  position: absolute;
  left: 0;
  top: 0;
  color: var(--text-bright);
  pointer-events: none;
}
.distance-label[hidden] { display: none; }
.distance-label .pixel-text { zoom: 1.5; animation: points-appear 0.3s ease-out; }
@keyframes points-appear {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* The menu button (menu.js) and the speaker beside it: the same stone button as the others (see .btn),
   square, with its icon at 1.5x. The menu's icon is three bars in the client's text grey, outlined in
   black like its pixel font. */
.settings-button {
  display: grid;
  place-items: center;
  align-self: center;
  width: 49px;
  height: 49px;
  padding: 0;
  border-style: solid;
  border-width: 3px;
  border-image: url('ui/images/skin/classic/button-9grid-idle.png') 3 fill / 3px repeat;
  background: none;
}
.settings-button::before {
  content: '';
  zoom: 1.5;
  image-rendering: pixelated;
}
.settings-button:not(.sound-button)::before {
  width: 12px;
  height: 10px;
  background: linear-gradient(#c0c0c0 0 2px, transparent 2px 4px, #c0c0c0 4px 6px, transparent 6px 8px, #c0c0c0 8px 10px);
  filter: drop-shadow(1px 0 0 #000) drop-shadow(-1px 0 0 #000) drop-shadow(0 1px 0 #000) drop-shadow(0 -1px 0 #000);
}
.settings-button:active {
  border-image-source: url('ui/images/skin/classic/button-9grid-pressed.png');
  padding: 1px 0 0 1px; /* the bars sink in, like the other buttons' labels */
}
/* Daily challenge: the name field (dark, like the dropdowns) and today's high scores. */
.name-entry { display: grid; gap: 4px; margin: 4px 0 8px; }
.name-entry input {
  height: 24px;
  padding: 0 6px;
  border: 1px solid #777;
  background: var(--stone-dark);
  color: var(--text-bright);
  font: var(--font);
}
.name-entry input:focus { outline: 1px solid var(--text); }
/* No space of its own above: the filter (or text) over it keeps 10px to it, the same as the tabs above that. */
.leaderboard {
  margin: 0 0 8px;
  padding: 4px 0;
  list-style: none;
  max-height: 340px;
  overflow-y: auto;
  border: 1px solid #777;
  background: var(--stone-dark);
}
.leaderboard li { display: grid; grid-template-columns: 32px 1fr auto; align-items: center; min-height: 30px; padding: 6px 8px; color: var(--text); }
.leaderboard .goblet { display: block; width: 32px; height: 32px; margin: -7px 0 -5px -6px; image-rendering: pixelated; }
.leaderboard .name { display: grid; }
.leaderboard .detail { color: var(--muted); font-size: 10px; text-shadow: none; }
.leaderboard li.mine { color: var(--gold); } /* your entry: gold text, no background of its own */
.leaderboard li.empty { display: block; color: var(--muted); }
.leaderboard li.open .goblet { opacity: 0.35; filter: grayscale(0.6); } /* a place nobody has taken yet */
.leaderboard .points { text-align: right; }
.leaderboard .pixel-text { zoom: 1.25; }
/* Your own score, under the five places and set apart from them: your flag (the minimap's) in a dark
   box, as the SD Trainer's portrait, then "You". */
.leaderboard li.yours { margin-top: 6px; border-top: 1px solid #5a5a5a; padding-top: 8px; }
.leaderboard .flag-box {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1px solid #111;
  box-shadow: 1px 1px 0 #555;
  background: #1a1a1a;
}
.leaderboard .flag { width: 11px; height: 11px; zoom: 1.5; background: url('ui/images/minimap/markers.png') 0 0 no-repeat; image-rendering: pixelated; }

/* The start screen's sound button: square, with the same icons. */
.btn.icon-button { display: grid; place-items: center; box-sizing: border-box; min-width: 0; width: 30px; padding: 0; margin-right: auto; }
.btn.icon-button:active:not(:disabled) { padding: 1px 0 0 1px; } /* the icon sinks in, like the menu button's bars; the button keeps its size */
.sound-toggle::before { content: ''; width: 13px; height: 13px; background: url('ui/images/icon-sound.png') no-repeat; image-rendering: pixelated; }
.sound-toggle.muted::before { background-image: url('ui/images/icon-mute-pressed.png'); }
/* Sound on/off: the same button with the client's speaker icons (13x13). */
.sound-button::before { width: 13px; height: 13px; background: url('ui/images/icon-sound.png') no-repeat; }
.sound-button.muted::before { background-image: url('ui/images/icon-mute-pressed.png'); }
.dialog-actions { gap: 6px; }

/* The time bar: like the client's health bar, a black-edged trough with a shaded fill (the client's
   1px-wide progress bar strips, repeated across) and white pixel text in the middle. */
.time-bar {
  position: relative;
  height: 20px;
  margin: 0 6px 6px;
  border: 1px solid #000;
  background: #101010;
  box-shadow: 0 0 0 1px #3a3a3a;
}
.time-bar[hidden], main[hidden] + .time-bar { display: none; }
.time-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  background: url('ui/images/progressbar-green-large.png') repeat-x 0 0 / auto 100%;
  image-rendering: pixelated;
}
.time-bar-fill.yellow { background-image: url('ui/images/progressbar-yellow-large.png'); }
.time-bar-fill.orange { background-image: url('ui/images/progressbar-orange-large.png'); }
.time-bar-fill.red { background-image: url('ui/images/progressbar-red-large.png'); }
.time-bar-text {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  color: #fff;
}
.time-bar-text .pixel-text { zoom: 1.25; }

/* Tibia's info banner, built from the client's pieces (ui/images/tutorial/*infobanner*): the parchment
   (289x88: a title band on top, a subtitle band below that leaves room for the icon at bottom left),
   the ornament lines framing the title, and the 8-frame roll that unrolls it. Shown at 1.5x, centred
   on the screen. */
.info-banner {
  position: fixed;
  z-index: 10;
  top: 50%;
  left: 50%;
  width: 289px;
  height: 88px;
  zoom: 1.5;
  transform: translate(-50%, -50%);
  pointer-events: none;
  image-rendering: pixelated;
}
.info-banner[hidden] { display: none; }
.info-banner img { position: absolute; image-rendering: pixelated; }
.ib-scroll { position: absolute; inset: 0; }
.ib-parchment { left: 0; top: 0; }
.ib-ornaments { left: 117px; top: 3px; }
.ib-title, .ib-subtitle { position: absolute; text-align: center; }
/* Optically centred: the emblem covers the left end of both bands, so the title, its ornament
   lines and the subtitle are centred on the parchment that stays visible right of the emblem
   (about x 83 to 280), not on the whole image. */
.ib-title { left: 77px; right: 4px; top: 15px; color: #fff2b0; }
/* Set slightly above the lower band's middle: its darker bottom edge makes true centre look low. */
.ib-subtitle { left: 81px; right: 4px; top: 47px; color: #f2f2f2; }
.ib-roll { position: absolute; top: -8px; width: 21px; height: 105px; }
/* Level with the title and overlapping the parchment's left end, as in the client. */
.ib-icon { left: 11px; top: -17px; } /* the banner is shown at 1.5x, so 1px here = 1.5px on screen */

/* A touch larger: the dialog's title and its section headings (Game mode, Time limit, …). */
.dialog-card .window-title .pixel-text, .modes legend .pixel-text { zoom: 1.25; }
.dialog-card .window-title { display: flex; justify-content: center; align-items: center; }
/* Optically centred: a little below the middle, as the bar's light top edge makes it look higher. */
.dialog-card .window-title .pixel-text { margin-top: 0; }

/* Tibia-style dropdowns (see dropdown.js), after the client's own (e.g. Bounty Tasks' difficulty):
   a dark field with a light 1px edge, the value centred and the client's arrow button, and a list in
   the window's stone with the same edge and a lighter band on the hovered option. The radio groups
   they're built from stay in the page, hidden. */
.dropdown-source { display: none; }
.dropdown { position: relative; }
.dropdown-field {
  display: flex;
  align-items: center;
  width: 100%;
  height: 24px;
  padding: 0 0 0 4px;
  /* The client's grey stone, like its buttons (the dark field: border 1px #777, background --stone-dark). */
  border-style: solid;
  border-width: 3px 1px 3px 3px;
  border-image: url('ui/images/skin/classic/button-9grid-idle.png') 3 1 3 3 fill / 3px 1px 3px 3px repeat;
  background: none;
  color: var(--text-bright);
}
.dropdown-value { flex: 1; text-align: center; }
.dropdown-value .pixel-text, .dropdown-list .pixel-text { zoom: 1.25; }
.dropdown-arrow {
  flex: none;
  width: 20px;
  height: 20px;
  margin: -1px 0;
  background: url('ui/images/skin/classic/button-dropdown-20x20-idle.png');
  image-rendering: pixelated;
}
.dropdown.open .dropdown-arrow,
.dropdown-field:active .dropdown-arrow { background-image: url('ui/images/skin/classic/button-dropdown-20x20-pressed.png'); }
.dropdown-field:focus-visible { outline: 1px solid var(--text); }
.dropdown-list {
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  top: 100%;
  margin: 1px 0 0;
  padding: 1px 0;
  list-style: none;
  border: 1px solid #777;
  background: var(--stone);
  box-shadow: 0 4px 10px rgb(0 0 0 / 0.4);
}
.dropdown-list[hidden] { display: none; }
.dropdown-list li { padding: 3px 8px; color: var(--text); }
.dropdown-list li.active { background: rgb(255 255 255 / 0.1); color: var(--text-bright); }
.dropdown-list li[aria-selected="true"] { color: var(--text-bright); }
 /* on its own at the left, apart from Start */

/* Anything hidden stays hidden, whatever display its class gives it. */
[hidden] { display: none !important; }

/* Toggles (Play / Daily challenge, Game mode): two equal halves in a sunken dark track. A raised
   stone button (the thumb) slides under the chosen half, whose text turns white; the other half's
   text is grey. The chosen half's index is set as data-on by setupToggles() in game.js. */
.toggle {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  padding: 2px;
  border: 1px solid #4a4a4a; /* a soft edge: lighter than the track, darker than the dropdowns' */
  background: var(--stone-dark);
}
.toggle::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 2px;
  width: calc(50% - 2px);
  border-style: solid;
  border-width: 3px;
  border-image: url('ui/images/skin/classic/button-9grid-idle.png') 3 fill / 3px repeat;
  box-sizing: border-box;
  transition: transform 0.22s ease-in-out;
}
.toggle[data-on="1"]::before { transform: translateX(100%); }
.toggle .choice {
  position: relative; /* above the thumb */
  border-color: transparent;
  border-image: none;
  background: none;
  color: var(--muted);
  transition: color 0.22s;
}
.toggle .choice:has(input:checked) { border-image: none; color: var(--text-bright); }
.toggle .choice:hover:not(:has(input:checked)) { color: var(--text); }
.home-tabs { margin-bottom: 10px; }
.home-tabs .choice { display: grid; place-items: center; height: 28px; padding: 0 4px; }
/* On the start screen the window keeps its top edge in place (below the logo), so switching tabs,
   which changes its height, doesn't move the tabs. */
.dialog.home { justify-content: flex-start; padding-top: max(150px, calc(50vh - 200px)); background: #000; } /* black between cities */

/* The in-game menu (menu.js): the paused game under a darker veil, its buttons stacked at the window's width,
   with the way to all games below a divider. Above the info banner, below the volume panel. */
.dialog.game-menu { z-index: 20; background: rgb(0 0 0 / 0.7); }
.game-menu .dialog-card { width: min(260px, 100%); }
body.paused > main { filter: blur(8px); }
.game-menu .window-title { display: flex; justify-content: center; align-items: center; }
.menu-note { margin: 0 0 10px; color: var(--gold); white-space: normal; }
.menu-note[hidden] { display: none; }
.menu-buttons { display: grid; gap: 6px; }
.menu-buttons .btn[hidden] { display: none; }
.game-menu .menu-footer { margin-top: 10px; }
.menu-hub { flex: 1; display: grid; place-items: center; text-decoration: none; }

/* ── The results screen (results.js) ── */
.results {
  position: fixed;
  z-index: 6; /* above the dialogs, below the info banner */
  inset: 0;
  display: grid;
  place-items: center;
  padding: 16px;
  overflow-y: auto;
  background: rgb(0 0 0 / 0.82);
}
/* The fankit's dragon panel, rebuilt by tools/make-results-panel.ts so the drake is 1.5x while the
   gold curls, the plate and the frame keep their own size: the header (drake and plate, 440x125)
   on top of the dark box, a 9-slice with a 13px frame that grows to fit the content. */
.results-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 440px;
  max-width: 100%;
  margin-top: 125px; /* room for the header above the box */
  border-style: solid;
  border-width: 0 13px 13px;
  border-image: url('data/results-box.png') 0 13 13 fill / 0 13px 13px stretch;
  image-rendering: pixelated;
  padding: 6px 10px 2px;
}
.results-header {
  position: absolute;
  width: 440px;
  height: 125px;
  margin: -125px -23px 0; /* over the box's top, from its outer left edge (13px frame + 10px padding) */
  background: url('data/results-header.png');
  image-rendering: pixelated;
  pointer-events: none;
}
/* On the plate: its middle is at y 106 in the header; the text sits 2px above that, which looks centred. */
.results-plate {
  position: absolute;
  left: 0;
  right: 0;
  top: 86px;
  height: 37px;
  display: grid;
  place-items: center;
  color: var(--gold);
  white-space: nowrap;
}
.results-plate .pixel-text { zoom: 1.5; }
.results-total { display: grid; place-items: center; color: var(--text-bright); }
.results-total .pixel-text { zoom: 2; }
.results-fireworks { position: fixed; inset: 0; pointer-events: none; }
.results-firework { position: absolute; width: 128px; height: 128px; transform: translate(-50%, -50%); image-rendering: pixelated; }
.results-rounds {
  margin: 4px 0 0;
  padding: 2px 0;
  list-style: none;
  max-height: 46vh;
  overflow-y: auto;
  border-top: 1px solid #3a4246;
  border-bottom: 1px solid #3a4246;
}
.results-rounds li { display: grid; grid-template-columns: 18px 1fr auto 18px; align-items: center; gap: 10px; padding: 6px 4px; }
.results-rounds li + li { border-top: 1px solid rgb(255 255 255 / 0.05); }
.results-rounds .pixel-text { zoom: 1.25; }
.results-badge { width: 18px; height: 16px; background: url('ui/images/tiers-strip-big.png') no-repeat; image-rendering: pixelated; }
.results-badge.plain { display: grid; place-items: center; background: none; }
.results-place { display: grid; gap: 3px; min-width: 0; }
.results-points { text-align: right; }
.results-star { width: 18px; height: 20px; image-rendering: pixelated; }
.results-actions { display: flex; justify-content: flex-end; gap: 6px; padding: 4px 0 6px; }
#results-home { margin-right: auto; }

/* ── Top bar looks (chosen on the admin page; data-style on #bar) ──
   classic: the framed boxes with a label and value.
   icons: the same boxes, each with an item from the client as its icon and a bigger value.
   statusbar: one continuous dark bar like the client's status bar: icons and values only, split by
     thin lines, with the round as a green progress bar.
   slots: no boxes; each icon sits in an inventory slot, with its label and value beside it. */
.stat-icon { flex: none; width: 32px; height: 32px; background: center no-repeat; image-rendering: pixelated; }
.stat[data-stat="time"] .stat-icon { background-image: url('data/hud-watch.png'); }
.stat[data-stat="score"] .stat-icon { background-image: url('data/hud-coins.png'); }
.stat[data-stat="round"] .stat-icon { background-image: url('data/hud-map.png'); }
.stat[data-stat="mode"] .stat-icon { background-image: url('data/mode-follow-down.png'); background-size: 27px; }
.stat[data-stat="mode"][data-mode="static"] .stat-icon { background-image: url('data/mode-stand-down.png'); }
.stat[data-stat="mode"][data-mode="daily"] .stat-icon { background-image: url('data/hud-compass.png'); background-size: auto; }
.stat-progress { position: relative; height: 6px; margin-top: 3px; border: 1px solid #000; background: #101010; }
#round-fill { position: absolute; inset: 0 auto 0 0; width: 0; background: url('ui/images/progressbar-green-small.png') repeat-x center / auto 100%; transition: width 0.4s; }

/* icons */
.bar[data-style="icons"] .stat { flex-direction: row; align-items: center; gap: 6px; padding: 2px 10px 2px 4px; }
.bar[data-style="icons"] .stat-icon { display: block; }
.bar[data-style="icons"] .stat-text { align-items: flex-start; }
.bar[data-style="icons"] .value .pixel-text { zoom: 1.5; }

/* statusbar */
.bar[data-style="statusbar"] { padding: 0; min-height: 46px; gap: 0; border-bottom: 1px solid #000; background: var(--stone-dark); box-shadow: inset 0 -1px 0 #3a3a3a; }
.bar[data-style="statusbar"] .stats { gap: 0; align-items: stretch; height: 46px; }
.bar[data-style="statusbar"] .settings-button { align-self: center; margin: 0 4px; }
.bar[data-style="statusbar"] .stat {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding: 0 14px 0 8px;
  border: none;
  border-image: none;
  border-left: 1px solid #000;
  box-shadow: inset 1px 0 0 #3a3a3a;
  background: none;
}
.bar[data-style="statusbar"] .stat-icon { display: block; }
.bar[data-style="statusbar"] .label { display: none; }
.bar[data-style="statusbar"] .stat-text { align-items: flex-start; }
.bar[data-style="statusbar"] .value .pixel-text { zoom: 1.5; }
.bar[data-style="statusbar"] .stat[data-stat="round"] .stat-text { min-width: 64px; }
.bar[data-style="statusbar"] .stat-progress { display: block; align-self: stretch; }

/* slots */
.bar[data-style="slots"] .stat { flex-direction: row; align-items: center; gap: 8px; min-width: 0; padding: 0 8px 0 0; border: none; border-image: none; background: none; }
.bar[data-style="slots"] .stat-icon {
  display: block;
  width: 34px;
  height: 34px;
  background-color: #1c1c1c;
  border: 1px solid;
  border-color: #111 #4a4a4a #4a4a4a #111; /* sunken, like an inventory slot */
  box-sizing: border-box;
}
.bar[data-style="slots"] .stat-text { align-items: flex-start; }
.bar[data-style="slots"] .value .pixel-text { zoom: 1.5; }

/* The volume panel (volume.js): opens beside a speaker button, in the stat boxes' frame, with the
   client's slider: 12x12 arrow buttons either side of the stone track (slider-texture), and the
   scrollbar's handle drawn 14px wide (its 3px ends kept, the middle stretched). */
.volume-panel {
  position: fixed;
  z-index: 30; /* above the dialogs, the results and the info banner */
  display: grid;
  grid-template-columns: auto auto 40px;
  align-items: center;
  gap: 8px;
  box-sizing: border-box;
  height: 30px; /* as the start screen's sound button */
  padding: 0 8px;
  border-style: solid;
  border-width: 3px;
  border-image: url('ui/images/3pixel-frame-borderimage.png') 3 / 3px round;
  background: var(--stone);
  box-shadow: 0 4px 10px rgb(0 0 0 / 0.5);
  line-height: 0;
}
.volume-panel .pixel-text { zoom: 1.25; }
.volume-slider { display: flex; align-items: center; outline: none; }
.volume-slider:focus-visible { outline: 1px solid var(--text); outline-offset: 2px; }
.volume-arrow { width: 12px; height: 12px; padding: 0; border: 0; background: url('ui/images/skin/classic/slider-buttonleft-up.png'); image-rendering: pixelated; }
.volume-arrow:active { background-image: url('ui/images/skin/classic/slider-buttonleft-down.png'); }
.volume-arrow.right { background-image: url('ui/images/skin/classic/slider-buttonright-up.png'); }
.volume-arrow.right:active { background-image: url('ui/images/skin/classic/slider-buttonright-down.png'); }
.volume-track {
  position: relative;
  width: 96px;
  height: 12px;
  background: url('ui/images/skin/classic/slider-texture.png');
  image-rendering: pixelated;
  touch-action: none;
  cursor: url('ui/cursors/cursor-pointinghand.png') 4 2, pointer;
}
.volume-handle {
  position: absolute;
  top: 0;
  width: 14px;
  height: 12px;
  box-sizing: border-box;
  border-style: solid;
  border-width: 0 3px;
  border-image: url('ui/images/skin/classic/scrollbar-handle-horizontal.png') 0 3 fill / 0 3px stretch;
  image-rendering: pixelated;
  pointer-events: none;
}
.volume-value { text-align: right; }
