/* TETROS98 - madzcor (layout + game styles, layered on 98.css) */

/* ===== base ===== */
:root {
  /* brightness theme: the settings slider writes --brightness; every surface
     derives from it in OKLab (oklch + color-mix), and text auto-picks black
     or white via color-contrast() so legibility survives any brightness.
     The L values are COMPUTED IN JS (applyBrightness clamps them) - Chrome
     ignores clamp() inside substituted var() chains, so the clamping has to
     happen where it provably works. These are the brightness-1 defaults. */
  --brightness: 1; /* 0.4 dark .. 1.6 bright, slider in Settings */
  --face-l: 0.78;
  --face-lite-l: 0.82;
  --face-lite: oklch(var(--face-lite-l) 0 0);
  --navy-a-l: 0.35;
  --navy-b-l: 0.52;
  --board-well-l: 0.78; /* the well frame: #b7b7b7 at normal, darkens at dark -
                           JS keeps it a step above the playfield canvas */
  --well-l: 0.686;
  --well-active-l: 0.655;
  --face: oklch(var(--face-l) 0 0);
  --well-bg: oklch(var(--well-l) 0 0);
  --well-active-bg: oklch(var(--well-active-l) 0 0);
  --canvas-filter: brightness(1);
  /* the grid/frame themes now (dark at dark) - the canvas stays darker
     inside it, so the screen still reads; the bright grid was the last
     glaring box at full dark */
  --board-bg: oklch(var(--board-well-l) 0 0);
  --field-l: 0.97;
  --field: oklch(var(--field-l) 0 0);
  --titlebar-gradient: linear-gradient(90deg, var(--navy-a), var(--navy-b));
  --bevel-edge: #0a0a0a;  /* the 98 pixel bevels - ONE source of truth   */
  --bevel-hi: #ffffff;   /* raised: buttons/window/knob/thumb/radio ring     */
  --bevel-lo: #808080;   /* recessed: inputs/checkbox/select wells           */
  --bevel-face: #dfdfdf;
  --raised-bevel: inset -1px -1px var(--bevel-edge), inset 1px 1px var(--bevel-hi),
                  inset -2px -2px var(--bevel-lo), inset 2px 2px var(--bevel-face);
  --recessed-bevel: inset -1px -1px var(--bevel-hi), inset 1px 1px var(--bevel-lo),
                    inset -2px -2px var(--bevel-face), inset 2px 2px var(--bevel-edge);

  /* IMPORTANT: rules must reference these BARE (var(--x)) - Chrome resolves
     var() inside function notation (oklch(var(--face-l) ...) in a rule) at
     PARSE time with the then-current value and never re-resolves it. Custom
     property definitions stay token streams, so bare references track. */
  /* bevels stay CONSTANT - the white/grey/black pixel bevels ARE the 98
     charm; only the big faces + titlebar theme with brightness */
  --face-hi: #ffffff;
  --face-lo: #808080;
  --edge: #0a0a0a;
  --text: #000;        /* JS picks black or white per brightness - color- */
  --text-dim: #404040; /* contrast() is not implemented in browsers yet    */
  --navy-a: oklch(var(--navy-a-l) 0.188 -95.9); /* true #000080 hue/chroma - */
  --navy-b: oklch(var(--navy-b-l) 0.148 -114.2); /* the old 290/240 was purple */
  --accent: var(--navy-b);
  --bg: var(--face);
}

/* 98.css now carries the theme itself (silver -> var(--face), navy gradient
   -> var(--navy-*)) - its bevels stay constant, which is the charm. The only
   JS-drawn surface left is the playfield: the filter does its share, but a
   GENTLER curve so pieces stay visible when the chrome goes dark (the value
   is computed + clamped in JS - see applyBrightness). */
#canvas-board, .mini-canvas { filter: var(--canvas-filter); }

/* ===== base ===== */
html, body {
  height: 100%;
  height: 100dvh; /* track the visible viewport under browser chrome */
  margin: 0; /* kill default 8px body margin - it showed grey around the window */
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-tap-highlight-color: transparent;
  background: var(--bg);
  color: var(--text);
  -webkit-user-select: none;
  user-select: none;
}

#desktop {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--bg);
}

/* 98.css provides all the theming - no custom re-skin needed. */

/* window chrome: title bar flush to the top, body flexes, status bar pinned */
.window {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  padding: 0; /* no top inset - the title bar carries the safe-area padding so its gradient paints into the status bar */
}
.title-bar { flex-shrink: 0; padding: calc(env(safe-area-inset-top, 0px) + 3px) 2px 3px 3px; }
.version-badge {
  /* mirror of the title text: same white tone + the title's 24px margin,
     on the OTHER side of the bar (controls sit between the two gaps) */
  font-size: 10px;
  font-weight: normal;
  color: #ffffff;
  opacity: 0.9;
  margin-right: 9px; /* sits near the right edge like the title sits near
                         the left - close, not identical */
  align-self: center;
}
.window-body {
  margin: 0;
  padding: 8px;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  position: relative; /* overlays anchor here: inset 0 = full body, no gap */
  flex-direction: column;
}
.status-bar {
  flex-shrink: 0;
  position: relative;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px;
  /* the bar's face spans the FULL bottom edge (the phone's corners are the
     window's business) - only the divisions inside tuck in laterally */
  background: var(--face);
  border-top: 2px solid var(--bevel-lo);
  box-shadow: inset 0 1px 0 var(--bevel-hi);
}
/* the fields keep their natural width (no flex-grow) so the centered pill
   box gets the free space; tight screens clip with an ellipsis */
.status-bar-field {
  flex: 0 1 auto;
}
/* status fields must degrade gracefully when tight: clip with an ellipsis
   instead of wrapping or vanishing (the old mobile rule hid the third
   field entirely - it carried keyboard hints, now it carries speeds) */
.status-bar-field {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* touch surfaces: themed here in the BASE section - Chrome bakes var()
   substitution in parsed media-query rules at load, so declarations inside
   the mobile block would never track the brightness slider. Layout stays
   in the media block; colors live here. */
.touch-controls .face-btn { background: var(--face); }
.stick-well { background: var(--well-bg); }
.pad.pad-active .stick-well { background: var(--well-active-bg); }
.stick-knob { background: var(--face); }
.stick-clip-inner { background: var(--well-bg); }
.pad.pad-active .stick-clip-inner { background: var(--well-active-bg); }

[data-theme="dark"] input[type="range"]::-webkit-slider-thumb {
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0v16h2v2h2v2h1v-1H3v-2H1V1h9V0Z' fill='%23a0a0a0'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 1v15h1v1h1v1h1v1h2v-1h1v-1h1v-1h1V1Z' fill='%23808080'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1h1v15H8v2H6v2H5v-1h2v-2h2Z' fill='%23606060'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0h1v16H9v2H7v2H5v1h1v-2h2v-2h2Z' fill='%23000'/%3E%3C/svg%3E");
}
[data-theme="dark"] input[type="range"]::-moz-range-thumb {
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0v16h2v2h2v2h1v-1H3v-2H1V1h9V0Z' fill='%23a0a0a0'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 1v15h1v1h1v1h1v1h2v-1h1v-1h1v-1h1V1Z' fill='%23808080'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1h1v15H8v2H6v2H5v-1h2v-2h2Z' fill='%23606060'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0h1v16H9v2H7v2H5v1h1v-2h2v-2h2Z' fill='%23000'/%3E%3C/svg%3E");
}
/* theme changes glide instead of snapping: a short transition on the
   themed surfaces (colors only - never layout/transform). The SVG tier
   swaps can't transition, so JS delays them to land after the glide. */
.window, .title-bar, button, input[type="reset"], input[type="submit"],
.stat-value, .t98-select, fieldset, .sunken-panel, .status-bar-field,
input[type="text"], input[type="number"], input[type="password"],
input[type="search"], input[type="tel"], input[type="url"], select, textarea,
.stick-knob, .stick-well, .stick-clip-inner, .touch-controls .face-btn,
.menu-btn, .start-title, .start-sub, .slider-val, .cfg-row-name, legend {
  transition: background-color 0.18s ease, box-shadow 0.18s ease,
              color 0.18s ease, border-color 0.18s ease, border-image 0.18s ease,
              filter 0.18s ease;
}
@media (prefers-reduced-motion: reduce) {
  .window, .title-bar, button, .stat-value, .t98-select, fieldset,
  .sunken-panel, .status-bar-field, input, select, textarea, .stick-knob,
  .stick-well, .touch-controls .face-btn, .menu-btn, .start-title, .start-sub {
    transition: none;
  }
}

.stat-row, .stat-label, .stat-value, .start-title, .start-sub, .settings-hint,
.slider-row, .slider-val, .version-badge, .last-clear, .status-msg, .cfg-row,
.controls-label, .key-chip, .key-restore, .menu-btn, .dialog-title,
.progress-indicator, .cfg-row-name, legend {
  -webkit-font-smoothing: none;
  font-smooth: never;
}

/* ===== screens ===== */
.screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  position: relative;
  /* fill the window body so the board can actually use desktop space -
     without this the board size loop converges on content size, not window */
  flex: 1 1 auto;
  min-height: 0;
}

.game-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 6px 0 2px;
}
.start-title { font-size: clamp(20px, 4vw, 52px); font-weight: bold; letter-spacing: 5px; color: var(--logo, #000080); text-shadow: 1px 1px 0 var(--logo-shadow, #ffffff); text-wrap: balance; }
.start-sub { font-size: clamp(9px, 1.2vw, 16px); color: #808080; letter-spacing: 2px; text-wrap: balance; }


.menu { display: flex; flex-direction: column; gap: 8px; width: 190px; }
.menu-btn { width: 100%; min-height: 28px; font-size: clamp(10px, 1vw, 14px); }
.menu-btn:focus {
  outline: 1px dotted #000;
}

/* ===== game: single-window groupbox layout ===== */
.game-grid {
  display: flex;
  gap: 12px;
  justify-content: center;
  align-items: stretch; /* stack + well share the grid height - the stack boxes
                           match the board exactly, equal gaps, no ragged edges */
  flex-wrap: nowrap;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%; /* fill the window width - without this the grid was
                  content-width (stack+board) and the board was width-starved */
}

.side-stack {
  display: flex;
  flex-direction: column;
  gap: 12px; /* equal to the grid gap - boxes and board breathe together */
  width: 200px;
  flex-shrink: 0;
  min-height: 0; /* allow shrinking on short screens instead of overflowing */
}

/* groupbox titles (legends): no bg tab - just the text on the groove line,
   themed with everything else (the 98.css face tab read as a little box) */
fieldset legend {
  background: transparent;
  color: var(--text);
  padding: 0 2px;
}
fieldset.stats-groupbox, fieldset.mini-groupbox {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
fieldset.stats-groupbox { flex: 1 1 0; min-width: 0; min-height: 0; }
fieldset.mini-groupbox {
  flex: 1 1 0; /* definite equal share - the box height is NOT content-driven,
                  so the well's height:100% resolves cleanly (no circulars) */
  min-height: 0;
  width: 100%; /* match the stack width - wells used to overhang 8px */
  box-sizing: border-box;
}
legend { font-size: 11px; padding: 0 4px; }

/* stats window - rows spread to fill the box so it matches its siblings */
.stats-body { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; justify-content: space-evenly; overflow: hidden; }
.stat-row {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: clamp(9px, 0.9vw, 14px);
}
.stat-label {
  color: var(--text-dim);
  letter-spacing: 1px;
  width: 52px; /* fixed so every value box lines up in one column */
  flex-shrink: 0;
  text-align: left;
}
.stat-value {
  font-size: 14px; /* right-aligned bold scores sit flush - that's the look */
  font-weight: bold;
  color: var(--text);
  background: transparent; /* no chip - the field box was too bright for the
                              white text at dark; text sits on the window face */
  padding: 2px 8px;
  flex: 1 1 auto;
  min-width: 0;
  text-align: right;
  line-height: 1.1; /* keep the number vertically centered in the white box */
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  font-variant-numeric: tabular-nums; /* digits line up - no jitter as scores grow */
  box-shadow:
    inset 1px 1px var(--edge), inset -1px -1px var(--face-hi),
    inset 2px 2px var(--edge), inset -2px -2px var(--face);
}
/* 8+ digits (high scores): shrink the number so it stays inside the box
   instead of painting over the bevel */
.stat-value.stat-long { font-size: 11px; padding: 2px 6px; }

/* gray veil over the board while waiting to start */
.board-overlay {
  position: absolute;
  inset: 0;
  background: rgba(128, 128, 128, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 5;
}
.board-overlay[hidden] { display: none; }
/* pause + game over are FULL-WINDOW modals like settings/controls/help:
   dim everything, compact centered dialog. (They used to be board-scoped -
   the grey board veil stays for the start screen only.) */
#overlay-pause, #overlay-gameover {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}
.board-dialog {
  min-width: 0;
  max-width: 90%;
  max-height: 90%;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.board-dialog .menu { gap: 6px; }
.board-dialog .dialog-title { text-align: center; }
.start-btn { width: 50%; max-width: 160px; min-height: 32px; font-size: 13px; font-weight: bold; }
.mini-well {
  background: var(--canvas-bg, #b7b7b7); /* matches the board + the canvases -
                                             hold/next are board-colored, not field */
  padding: 4px;
  display: flex;
  justify-content: center;
  width: 100%;
  height: 100%; /* fill the box - the canvas then fits the well instead of
                   the well wrapping the canvas (that loop shrank canvases
                   down to slivers on every refit) */
  box-sizing: border-box;
  overflow: hidden; /* the fit math can land 1px over - never show scrollbars */
}

/* board well: the sunken screen, recessed into the window face */
.board-well {
  position: relative; /* the veil/modal overlays anchor to it */
  background: var(--board-bg);
  padding: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 1 auto; /* wrap the canvas - no stretching, border hugs the grid */
  height: 100%; /* match the side stack exactly - both share the grid height */
  overflow: hidden; /* sunken-panel default is auto - never scrollbars */
  min-width: 0;
  min-height: 0;
  align-self: flex-start; /* top edge aligns with the stats box top */
  margin-top: 0;
  box-shadow:
    inset 1px 1px var(--edge), inset -1px -1px var(--face-hi),
    inset 2px 2px var(--edge), inset -2px -2px var(--face);
}

#canvas-board {
  background: var(--canvas-bg, #b7b7b7); /* themed by JS - a clear/resize never
                                            flashes the old bright fallback */
  display: block;
}

canvas { image-rendering: pixelated; display: block; }
.mini-canvas {
  background: var(--canvas-bg, #b7b7b7); /* the board color - matches the well */
  display: block;
}

/* overlays / dialogs */
.overlay {
  position: absolute;
  inset: 0; /* dim edge to edge - no gap around the modal */
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}
/* overlay opens get a 120ms fade; engines without @starting-style just snap */
.overlay, .board-overlay {
  transition: opacity 120ms ease-out, display 120ms allow-discrete;
}
.overlay[hidden], .board-overlay[hidden] { display: none; opacity: 0; }
@starting-style {
  .overlay[hidden], .board-overlay[hidden] { opacity: 0; }
}

.dialog {
  background: var(--face);
  box-shadow:
    inset -1px -1px var(--edge), inset 1px 1px var(--face-hi),
    inset -2px -2px var(--face-lo), inset 2px 2px var(--face);
  min-width: 240px;
  max-width: 92%;
  max-height: 92%;
  overflow: hidden; /* content scrolls inside .dialog-body, frame never scrolls */
  padding: 3px;
  display: flex;
  flex-direction: column;
}
/* content scrolls INSIDE the body panel so the bottom buttons stay visible;
   scrollbars hidden on every scroll container (WebView overlay mode shows
   a thin modern bar otherwise) */
.dialog, .dialog-body, .settings-page { scrollbar-width: none; -ms-overflow-style: none; }
.dialog::-webkit-scrollbar, .dialog-body::-webkit-scrollbar, .settings-page::-webkit-scrollbar { display: none; width: 0; height: 0; }
.dialog.wide {
  width: min(460px, calc(100vw - 32px)); /* never wider than the screen */
}
.dialog-title {
  background: linear-gradient(90deg, var(--navy-a), var(--navy-b));
  color: #fff;
  font-weight: bold;
  font-size: 12px;
  padding: 4px 8px;
}
.dialog-body {
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 12px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto; /* the inset scroll area - buttons below stay visible */
}
.dialog-buttons { display: flex; justify-content: flex-end; gap: 6px; padding: 8px 10px; flex-shrink: 0; }

.field-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.field-row input[type="range"] { min-width: 80px; height: 21px; margin: 0; }
/* the range slider is styled by 98.css itself - authentic pixel track + a
   beveled thumb that THEMES with the slider (98.css's thumb is a hardcoded
   light SVG - it stayed white at dark). The wrapper flexes + paints the
   tick: a 1px notch at the 50 = normal position. */
.t98-range-wrap {
  position: relative;
  flex: 1;
  min-width: 80px;
  height: 21px;
}
.t98-range-wrap input[type="range"] { width: 100%; display: block; margin-top: 9px; position: relative; z-index: 1; }
.t98-range-wrap::after {
  /* a real 98 pixel notch (same pixel language as the 98.css thumb SVGs):
     3x6 black with a white 1px right edge - sits below the track. The
     dark tier swaps in a dark-notch SVG so it never glares. */
  content: "";
  position: absolute;
  left: 50%;
  top: 15px;
  width: 3px;
  height: 6px;
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='3' height='6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h3v6H0V0Z' fill='%230a0a0a'/%3E%3Cpath d='M2 0h1v6h-1V0Z' fill='%23ffffff'/%3E%3C/svg%3E") no-repeat;
  transform: translateX(-50%);
  pointer-events: none;
}
[data-theme="dark"] .t98-range-wrap::after {
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='3' height='6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h3v6H0V0Z' fill='%23606060'/%3E%3Cpath d='M2 0h1v6h-1V0Z' fill='%23a0a0a0'/%3E%3C/svg%3E") no-repeat;
}
.field-row select, .field-row input[type="number"] { width: 120px; }
/* custom dropdowns keep a CONSTANT width - wide enough for the longest
   option ("Guideline (modern)") so the field never resizes when the
   selected value changes */
.field-row .t98-select-wrap { width: 170px; max-width: 100%; }
.settings-hint { font-size: clamp(10px, 0.9vw, 13px); color: var(--text-dim); margin: 2px 0 4px; line-height: 1.45; max-width: 52ch; }
.radio-row { display: flex; flex-wrap: wrap; gap: 4px 14px; }
.radio-row label { margin-left: 2px; }
.check-row { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.check-row label { margin-left: 2px; }
/* sub-options that hang off a parent checkbox (kick tables under wall kicks) */
.radio-row.sub-group { padding-left: 26px; }
.slider-row { display: flex; align-items: center; gap: 8px; min-height: 24px; }
.slider-row label { width: 120px; flex-shrink: 0; }
.slider-row input[type="range"] { flex: 1; min-width: 80px; height: 21px; margin: 0; }
.slider-val { width: 44px; text-align: right; font-size: 11px; flex-shrink: 0; }

/* settings page: single scrollable list, Tuning is a collapsible section */
.settings-page {
  border: 1px solid;
  border-color: var(--edge) var(--face-hi) var(--face-hi) var(--edge);
  background: var(--face);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* the beveled frame is the element's own border, so it STAYS while the
     content scrolls inside it - no more bevel scrolling away */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
/* two-column group grid for the small toggles; collapses on narrow screens */
.settings-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  align-items: start;
}
/* group boxes inside settings: even padding, column stack, breathing room */
.settings-page fieldset {
  margin: 0;
  padding: 6px 9px 9px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.settings-page fieldset legend { margin-bottom: 3px; }
/* settings scrolls inside its own inset frame, not the dialog body */
#overlay-settings .dialog-body { overflow: visible; }
.tuning-toggle {
  width: 100%;
  text-align: left;
  font-size: 11px;
  font-weight: bold;
  padding: 4px 8px;
}

/* row-clear feedback: soft flash + tiny scoreboard note */
.page-buttons {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 4px;
}
.page-buttons .menu-btn { width: 100%; min-height: 24px; font-size: 11px; }

.last-clear {
  text-align: center;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--text-dim);
  min-height: 12px;
  opacity: 0;
}
.last-clear.show { animation: last-fade 1.4s ease-out forwards; }
@keyframes last-fade {
  0% { opacity: 1; }
  70% { opacity: 1; }
  100% { opacity: 0; }
}

.level-progress { height: 12px; margin-top: 2px; }

.cfg-tool {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border-top: 1px solid var(--face-hi);
  padding-top: 8px;
  margin-top: 4px;
}
.cfg-tool .field-row { justify-content: flex-start; }
.cfg-tool #cfg-name { flex: 1; min-width: 0; }
/* saved setups: one row per profile - name + Load + Delete, no dropdown */
.cfg-row { display: flex; align-items: center; gap: 6px; padding: 2px 0; }
.cfg-row-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cfg-row .cfg-row-btn { min-width: 68px; font-size: 11px; }

/* ===== 98-style custom dropdowns (no native picker) ===== */
.t98-select-wrap { position: relative; display: inline-block; }
.t98-select-wrap select {
  /* real select kept in the DOM for value/options/JS, but invisible so the
     Android WebView never pops its OS picker dialog */
  position: absolute; opacity: 0; pointer-events: none;
  width: 0; height: 0; border: 0; margin: 0; padding: 0; inset: 0;
}
.t98-select {
  display: flex; align-items: center; justify-content: space-between;
  background: var(--field); color: var(--text); text-shadow: none;
  box-shadow: inset -1px -1px #fff, inset 1px 1px grey,
              inset -2px -2px #dfdfdf, inset 2px 2px #0a0a0a;
  box-sizing: border-box; min-height: 21px; min-width: 100px;
  padding: 2px 3px; text-align: left; width: 100%;
}
/* the dark tier darkens the bevel pixels themselves - the same two
   recipes, just with dark values, so no control keeps a light ring */
[data-theme="dark"] {
  --bevel-edge: #000000;
  --bevel-hi: #a0a0a0;
  --bevel-lo: #606060;
  --bevel-face: #808080;
}
[data-theme="dark"] button, [data-theme="dark"] input[type="reset"], [data-theme="dark"] input[type="submit"] {
  box-shadow: var(--raised-bevel);
}
[data-theme="dark"] .window {
  box-shadow: var(--raised-bevel);
}
[data-theme="dark"] .title-bar-controls button {
  box-shadow: var(--raised-bevel);
}
[data-theme="dark"] .status-bar-field {
  box-shadow: inset -1px -1px var(--bevel-face), inset 1px 1px var(--bevel-lo);
}
[data-theme="dark"] input[type="checkbox"] + label::before {
  box-shadow: var(--recessed-bevel);
}
[data-theme="dark"] input[type="text"], [data-theme="dark"] input[type="number"],
[data-theme="dark"] input[type="password"], [data-theme="dark"] input[type="search"],
[data-theme="dark"] input[type="tel"], [data-theme="dark"] input[type="url"],
[data-theme="dark"] select, [data-theme="dark"] textarea {
  background: var(--field); /* the field darkens with the theme, not just its bevel */
  box-shadow: var(--recessed-bevel);
}
/* the groove border-images are pixel SVGs - dark variants swap in */
[data-theme="dark"] fieldset {
  border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='5' height='5' fill='gray' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0h5v5H0V2h2v1h1V2H0' fill='%23a0a0a0'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0h4v4H0V1h1v2h2V1H0' fill='%230a0a0a'/%3E%3C/svg%3E") 2;
}
[data-theme="dark"] .sunken-panel {
  border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='5' height='5' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23606060' d='M0 0h4v1H0z'/%3E%3Cpath fill='%23606060' d='M0 0h1v4H0z'/%3E%3Cpath fill='%23000' d='M1 1h2v1H1z'/%3E%3Cpath fill='%23000' d='M1 1h1v2H1z'/%3E%3Cpath fill='%23a0a0a0' d='M0 4h5v1H0z'/%3E%3Cpath fill='%23a0a0a0' d='M4 0h1v5H4z'/%3E%3Cpath fill='%23808080' d='M3 1h1v3H3z'/%3E%3Cpath fill='%23808080' d='M1 3h3v1H1z'/%3E%3C/svg%3E") 2;
}

/* dark theme: the field bevel goes dark too - no light ring around the well */
[data-theme="dark"] .t98-select {
  box-shadow: inset -1px -1px #808080, inset 1px 1px #000000,
              inset -2px -2px #a0a0a0, inset 2px 2px #000000;
}
.t98-select:active { padding: 2px 3px; }
.t98-select .t98-value {
  flex: 1; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; padding: 0 2px;
}
.t98-select .t98-arrow {
  flex: none; width: 16px; height: 15px; margin-left: 6px;
  background: var(--face); /* themed - was hardcoded silver, glared at dark */
  position: relative;
  box-shadow: inset -1px -1px #0a0a0a, inset 1px 1px #fff,
              inset -2px -2px grey, inset 2px 2px #dfdfdf;
}
.t98-select .t98-arrow::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -60%);
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid #000;
}
.t98-select-list {
  position: absolute; top: calc(100% + 2px); left: 0; z-index: 40;
  background: var(--field); color: var(--text); list-style: none; margin: 0; padding: 2px;
  min-width: 100%; max-height: 200px; overflow-y: auto;
  box-shadow: inset -1px -1px #0a0a0a, inset 1px 1px #dfdfdf,
              inset -2px -2px grey, inset 2px 2px #fff;
}
.t98-select-list[hidden] { display: none; }
.t98-select-list li { padding: 3px 8px; white-space: nowrap; }
.t98-select-list li:hover, .t98-select-list li.selected {
  background: var(--navy-a); color: #fff;
}

/* radios + checkboxes theme with the slider: the well (::before) follows
   --field (darkens/brightens over the range), the checked mark follows
   --text, and the bevels stay the constant 98 pixels. */
input[type="radio"] + label::before,
input[type="checkbox"] + label::before {
  background: var(--field);
}
input[type="radio"] + label::before {
  /* the authentic 8-bit radio ring - three SVG variants (dark/normal/bright
     body) switched by the theme tier, so it never reads as a fixed grey */
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4v1H2v1H1v2H0v4h1v2h1V8H1V4h1V2h2V1h4v1h2V1H8V0Z' fill='gray'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4v1H2v2H1v4h1v1h1V8H2V4h1V3h1V2h4v1h2V2H8V1Z' fill='%23000'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3h1v1H9V3Zm1 5V4h1v4h-1Zm-2 2V9h1V8h1v2H8Zm-4 0v1h4v-1H4Zm0 0V9H2v1h2Z' fill='%23DFDFDF'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2h-1v2h1v4h-1v2H8v1H4v-1H2v1h2v1h4v-1h2v-1h1V8h1V4h-1V2Z' fill='%23ffffff'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2h4v1h1v1h1v4H9v1H8v1H4V9H3V8H2V4h1V3h1V2Z' fill='%23ffffff'/%3E%3C/svg%3E") no-repeat center / 12px 12px;
  border-radius: 0;
  box-shadow: none;
}
[data-theme="dark"] input[type="radio"] + label::before {
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4v1H2v1H1v2H0v4h1v2h1V8H1V4h1V2h2V1h4v1h2V1H8V0Z' fill='%23606060'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4v1H2v2H1v4h1v1h1V8H2V4h1V3h1V2h4v1h2V2H8V1Z' fill='%23000'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3h1v1H9V3Zm1 5V4h1v4h-1Zm-2 2V9h1V8h1v2H8Zm-4 0v1h4v-1H4Zm0 0V9H2v1h2Z' fill='%23a0a0a0'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2h-1v2h1v4h-1v2H8v1H4v-1H2v1h2v1h4v-1h2v-1h1V8h1V4h-1V2Z' fill='%23808080'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2h4v1h1v1h1v4H9v1H8v1H4V9H3V8H2V4h1V3h1V2Z' fill='%23808080'/%3E%3C/svg%3E") no-repeat center / 12px 12px;
}
[data-theme="dark"] input[type="checkbox"] + label::before {
  box-shadow: inset -1px -1px #808080, inset 1px 1px #000000,
              inset -2px -2px #a0a0a0, inset 2px 2px #000000;
}
input[type="radio"]:checked + label::after {
  background: var(--text);
  border-radius: 50%;
}
input[type="checkbox"]:checked + label::after {
  background:
    linear-gradient(45deg, transparent 42%, var(--text) 42% 58%, transparent 58%),
    linear-gradient(-45deg, transparent 42%, var(--text) 42% 58%, transparent 58%);
}

#gameover-info { font-size: 13px; }

/* controls list */
.controls-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 3px 0;
  min-width: 0; /* let the row shrink inside the dialog - no clipping */
}
.controls-label {
  flex: 0 0 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* multi-key editor: chips + add button + conflict warning */
.keys-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  justify-content: flex-end;
  max-width: 240px;
  flex: 0 1 auto;
  min-width: 0;
}
.key-chip {
  background: var(--field); /* themed - was hardcoded white, lagged the theme */
  color: var(--text);
  border: 1px solid var(--edge);
  padding: 2px 8px;
  font-size: 11px;
  min-width: 28px;
  text-align: center;
  box-shadow: inset 1px 1px var(--face-hi), inset -1px -1px var(--face-lo);
}
.key-chip:hover { background: var(--navy-a); color: #fff; }
.key-restore {
  margin-top: 8px;
  font-size: 11px;
}
.key-add {
  background: var(--face);
  box-shadow: inset -1px -1px var(--edge), inset 1px 1px var(--face-hi),
    inset -2px -2px var(--face-lo), inset 2px 2px var(--face);
  padding: 2px 10px;
  font-size: 11px;
  min-width: 28px;
}
.key-add.listening { background: var(--navy-a); color: #fff; text-shadow: none; }
.conflict-flash {
  color: #c00;
  font-weight: bold;
  transition: color 0.2s;
}

/* touch button rebinding rows (Controls dialog) */
.touch-bind-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 3px 0;
}
.touch-btn-name { font-weight: bold; width: 24px; flex-shrink: 0; }
.touch-bind-wrap { width: 170px; max-width: 100%; }

[hidden] { display: none !important; }

/* ===== touch controls (mobile) ===== */
.touch-controls { display: none; }

@media (max-width: 768px), (pointer: coarse) {
  html, body { touch-action: manipulation; }
  * { -webkit-tap-highlight-color: transparent; }
  #desktop { padding: 0; }

  .window {
    width: 100%;
    box-shadow: none;
  }
  .window-body {
    margin: 0;
    padding: 4px;
    min-height: 0;
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    position: relative; /* keep overlays anchored full-bleed on mobile too */
  }

  #screen-game {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: 100%;
    align-items: stretch;
  }

  .game-grid {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: row;
    gap: 6px;
    overflow: hidden;
    width: 100%;
    align-items: stretch; /* keep the tuned mobile layout as-is */
    justify-content: space-evenly; /* edge margins match the stack/board
                                      gap at any width - no lopsided gaps */
  }

  /* side column: stats + hold + next stacked vertically beside the board */
  .side-stack {
    width: 116px;
    flex: 0 0 116px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    overflow-y: auto;
    justify-content: flex-start;
  }
  fieldset.stats-groupbox { flex: 0 0 auto; }
  fieldset.stats-groupbox, fieldset.mini-groupbox { padding: 5px 4px 4px; gap: 3px; }
  legend { font-size: 9px; }
  .stats-body {
    display: flex;
    flex-direction: column;
    gap: 3px;
  }
  .stat-row { font-size: 10px; }
  .stat-label {
    width: 38px; /* narrow on phones so the value box keeps room for big scores */
  }
  .stat-value {
    font-size: 12px;
    padding: 1px 5px;
    min-width: 0;
  }
  .stat-value.stat-long { font-size: 10px; padding: 1px 3px; }
  .level-progress { height: 8px; margin-top: 1px; }

  .mini-well { padding: 2px; }
  .mini-canvas { width: 36px; height: 36px; }

  .last-clear { display: none; }

  /* board fills the remaining width beside the side column */
  .board-well {
    flex: 0 1 auto; /* NO grow: the frame hugs the canvas horizontally -
                       flex-grow:1 stretched it to the grid width and the
                       silver showed inside the frame on both sides */
    min-height: 0;
    min-width: 0;
    align-self: flex-start;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3px;
  }
  #canvas-board {
    height: 100%;
    width: auto;
    aspect-ratio: 1 / 2;
    max-height: 100%;
    max-width: 100%;
    touch-action: none;
  }

  .start-title { font-size: 24px; letter-spacing: 3px; margin-top: 12px; }
  .start-sub { margin-bottom: 14px; }
  .menu { width: 180px; }


  .dialog.wide { width: 100%; }
  /* settings options: the flex-wrap run-on becomes a tidy 2-column grid.
     The inputs are position:fixed (98.css), so only the labels flow -
     each option lands in its own cell, aligned like a real form */
  .radio-row, .check-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px 8px;
  }
  .status-bar { padding: 2px 4px; padding-bottom: max(2px, env(safe-area-inset-bottom)); flex-wrap: nowrap; }


  /* pause on touch: a NORMAL full-screen modal - dims the whole game
     (touch controls included) instead of a little board-scoped box */
  #overlay-pause {
    position: fixed;
    inset: 0;
    z-index: 50;
  }
  #overlay-pause .board-dialog { width: min(260px, 80vw); }
  #overlay-pause .menu { width: 100%; }
  #overlay-pause .menu-btn { min-height: 42px; font-size: 13px; }

  /* game over gets the same full-screen treatment on touch */
  #overlay-gameover {
    position: fixed;
    inset: 0;
    z-index: 50;
  }
  #overlay-gameover .board-dialog { width: min(280px, 80vw); }
  #overlay-gameover .menu { width: 100%; }
  #overlay-gameover .menu-btn { min-height: 42px; font-size: 13px; }
  #overlay-gameover #gameover-info { text-align: center; font-size: 14px; }

  /* the window min/max/close buttons are useless chrome on touch - drop
     them (the title text stays) */
  .title-bar-controls { display: none; }

  /* more slider room on phones - narrower labels */
  .slider-row label { width: 100px; font-size: 11px; }

  /* settings groups stack instead of grid on small screens */
  .settings-grid { grid-template-columns: 1fr; }

  /* compact header while waiting to start */
  .game-header { padding: 2px 0 0; gap: 0; }
  .start-title { font-size: 20px; letter-spacing: 3px; }
  .start-sub { font-size: 9px; }
  .page-buttons { gap: 3px; margin-top: 2px; }
  .page-buttons .menu-btn { min-height: 22px; font-size: 10px; }

  /* narrow phones: stack label above its keys so nothing clips */
  .controls-row {
    flex-wrap: wrap;
    gap: 2px 8px;
  }
  .controls-label {
    width: 100%; /* label on its own line */
    flex-basis: 100%;
  }
  .keys-wrap {
    max-width: 100%;
    justify-content: flex-start;
  }

  .touch-controls {
    /* spread to the screen edges: stick under the left thumb, face
       diamond under the right thumb - not clustered mid-screen */
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    margin-top: 2px;
    flex-wrap: nowrap;
    padding: 8px 24px 6px;
    box-sizing: border-box;
    /* Win98 sunken divider above the controls - separates the game window
       from the touch row like a status-bar groove */
    border-top: 2px solid #808080;
    box-shadow: inset 0 1px 0 #dfdfdf;
  }
  .touch-controls button {
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
    font-family: inherit;
    cursor: pointer;
  }
  /* ===== Win98 button recipe (exact 98.css) =====
     background: silver; border: none; border-radius: 0;
     box-shadow: inset -1px -1px #0a0a0a, inset 1px 1px #fff,
                 inset -2px -2px grey, inset 2px 2px #dfdfdf;
     active: flip to sunken. Applied to every touch control. */
  .touch-controls .face-btn {
    border: none;
    border-radius: 0;
    box-shadow: inset -1px -1px var(--bevel-edge), inset 1px 1px var(--bevel-hi),
                inset -2px -2px var(--bevel-lo), inset 2px 2px var(--bevel-face),
                /* ONE global light (top-left, like the stick): the raised
                   button casts a tight 1px shadow bottom-right */
                1px 1px 0 rgba(0, 0, 0, 0.15);
    color: #000;
    box-sizing: border-box;
    /* reset 98.css's global button min sizes + padding - they force every
       touch button to 75px wide, overflowing its grid cell and clipping
       the pad arms / diamond buttons */
    min-width: 0;
    min-height: 0;
    padding: 0;
  }
  .touch-controls .face-btn.touch-pressed {
    /* oldschool press: the key drops STRAIGHT DOWN (no diagonal slide),
       darkens, and KEEPS its cast shadow so the silhouette never
       shrinks - the pressed button reads the same size as raised */
    transform: translate(0, 2px);
    box-shadow: inset -1px -1px var(--bevel-hi), inset 1px 1px var(--bevel-edge),
                inset -2px -2px var(--bevel-face), inset 2px 2px var(--bevel-lo),
                1px 1px 0 rgba(0, 0, 0, 0.15);
    background: var(--face-lite);
  }
  .touch-controls .face-btn.touch-kathunk {
    /* kathunk: the return is a SLIDESHOW - the press drops instantly, the
       release rolls back through stepped frames (bevel, motion, and a
       THEMED grey face roll - the bevel vars, never hardcoded light greys
       that flashed white on the dark theme). */
    animation: face-kathunk-move 0.14s steps(3, end),
               face-kathunk-face 0.14s steps(3, end);
  }
  @keyframes face-kathunk-move {
    0%   { transform: translate(0, 2px); }
    100% { transform: translate(0, 0); }
  }
  @keyframes face-kathunk-face {
    0%   { background: var(--face-lite); }
    55%  { background: var(--face); }
    100% { background: var(--face); }
  }
  .touch-controls .face-btn.touch-kathunk::before {
    /* the colored chip does its own stepped slideshow - a subtle
       brightness climb (1 -> 1.15 -> 1) in 5 slides, same 0.14s */
    animation: face-kathunk-chip 0.14s;
  }
  @keyframes face-kathunk-chip {
    0%   { filter: brightness(1); animation-timing-function: steps(1, end); }
    25%  { filter: brightness(1.12); animation-timing-function: steps(1, end); }
    50%  { filter: brightness(1.2); animation-timing-function: steps(1, end); }
    75%  { filter: brightness(1.12); animation-timing-function: steps(1, end); }
    100% { filter: brightness(1); }
  }
  /* the letter stays solid black + engraved shadow - grey color steps
     on the colored chip read as a flash, so it sits out of the
     slideshow entirely */
  .touch-controls .face-btn:not(.touch-pressed) {
    /* ASYMMETRIC: the press is instant (no transition while pressed -
       a quick tap always reads as a full depression). The return motion
       and bevel belong to the kathunk animation (stepped), so the only
       thing transitioning here is the background fallback. */
    transition: background 0.09s ease-out;
  }
  /* 98.css's :hover/:active paint the pressed bevel and mobile browsers
     stick :hover on the last-tapped element -> looked latched after lift.
     Neutralize both, but NEVER while .touch-pressed is active: mobile sets
     :active for the whole touch, and that rule (same specificity, later
     in source) used to override the pressed bevel - buttons looked raised
     while pressed. The :not() keeps .touch-pressed authoritative. */
  .touch-controls .face-btn:not(.touch-pressed):hover,
  .touch-controls .face-btn:not(.touch-pressed):active {
    box-shadow: inset -1px -1px #0a0a0a, inset 1px 1px #fff,
                inset -2px -2px #808080, inset 2px 2px #dfdfdf;
  }
  /* Analog stick: circular recessed well + knob. The pad is the touch
     surface; the knob follows the thumb, clamps at the well rim, and
     springs back to center on release (Win98 bevels). */
  .pad {
    position: relative;
    /* 160px touch area: big enough that the knob (64px) + 4px shadow at
       full 40px travel (edge at 72+4=76px) never clips the hit surface */
    width: 160px;
    height: 160px;
    flex: 0 0 auto;
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
  }
  .stick-well {
    /* 3DS-style socket: a visible recessed square the pad sits in. Pad is
       64px, well 100px - an ~18px rim shows around the pad at rest so it
       reads as a stick base, and at full push (40px travel) the pad leans
       clearly out of it. */
    position: absolute;
    left: 50%;
    top: 50%;
    width: 100px;
    height: 100px;
    margin-left: -50px;
    margin-top: -50px;
    /* authentic 98.css recessed bevel, right on the well: 1px #808080 +
       1px #0a0a0a top/left, 1px #fff + 1px #dfdfdf bottom/right. The
       ring-clipped shadows paint OVER it (real socket: the far wall is
       in shadow); the floor shadow never reaches it (interior clip). */
    box-shadow: inset -1px -1px #fff, inset 1px 1px #808080,
                inset -2px -2px #dfdfdf, inset 2px 2px #0a0a0a;
    /* clips the in-well shadows to the socket */
    overflow: hidden;
    transition: background 0.2s ease, box-shadow 0.2s ease;
    z-index: 1; /* above the surface shadow, whose in-well part this opaque face hides */
  }
  .pad.pad-active .stick-well {
    /* pushed: the stick sinks into its base - barely darker, bevel
       deepens (top/left darkens, light edges dim). Subtle enough to
       feel, not announce. */
    box-shadow: inset -1px -1px #e8e8e8, inset 1px 1px #777777,
                inset -2px -2px #d0d0d0, inset 2px 2px #0a0a0a;
  }
  .stick-knob {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 64px;
    height: 64px;
    margin-left: -32px;
    margin-top: -32px;
    box-shadow: inset -1px -1px #0a0a0a, inset 1px 1px #fff,
                inset -2px -2px #808080, inset 2px 2px #dfdfdf;
    /* NO drop shadow here: the surface shadow is a separate element UNDER
       the well so it never paints over the socket (see .stick-shadow-outer) */
    transition: box-shadow 0.15s ease;
    will-change: transform;
    /* pad rides ABOVE the socket so it overhangs it at rest */
    z-index: 2;
    /* press color eases in with the socket - no jump */
    transition: background 0.2s ease, box-shadow 0.2s ease;
  }
  .stick-clip-bevel, .stick-clip-inner {
    /* static clip zones inside the socket, sized to it: the bevel zone is
       the full well (the rim band), the inner zone is inset 3px (the
       floor). The moving shadows inside get masked by these. */
    position: absolute;
    inset: 0;
    pointer-events: none;
  }
  .stick-clip-bevel {
    /* the bevel zone: clipped to the full well (overflow), the interior
       part is COVERED by the inner wrapper's opaque background, so the
       +3 bevel shadow only ever shows in the 3px rim band */
    z-index: 0;
  }
  .stick-clip-inner {
    /* static clip zone for the socket floor: inset 3px + an OPAQUE face
       (same color as the socket) - it masks the bevel shadow out of the
       interior without needing an SVG mask (WebView-safe), and the
       floor shadow paints on top of it */
    z-index: 1;
    clip-path: inset(3px);
  }
  .stick-shadow {
    /* parallel-light model: every shadow is exactly the cap size (64px);
       depth = offset only. The floor is deepest, so its shadow shifts
       furthest (+10,+8) and the visible crescent reads as a deep hole. */
    position: absolute;
    left: 50%;
    top: 50%;
    width: 64px;
    height: 64px;
    margin-left: -32px;
    margin-top: -32px;
    background: rgba(0, 0, 0, 0.30);
    will-change: transform;
  }
  .stick-shadow-mid {
    /* rim: mid depth, mid offset (+6,+4) */
    position: absolute;
    left: 50%;
    top: 50%;
    width: 64px;
    height: 64px;
    margin-left: -32px;
    margin-top: -32px;
    background: rgba(0, 0, 0, 0.30);
    will-change: transform;
  }
  .stick-shadow-outer {
    /* outer surface: closest to the light, tightest offset (+3,+2) and a
       lighter shade (0.22) so it reads as a different surface. Lives
       UNDER the well - the socket's opaque face hides the in-well part,
       so it only shows outside the rim. */
    position: absolute;
    left: 50%;
    top: 50%;
    width: 64px;
    height: 64px;
    margin-left: -32px;
    margin-top: -32px;
    background: rgba(0, 0, 0, 0.22);
    pointer-events: none;
    will-change: transform;
    z-index: 0;
  }
  .stick-shadow-mid2 {
    /* the bevel's SECOND layer: its own crescent in the band, offset a
       beat shallower (+5,+3) and lighter (0.20) than the mid - the two
       band crescents stagger, reading the double bevel as two layers.
       Clipped to the band by the same clip zone - nothing escapes. */
    position: absolute;
    left: 50%;
    top: 50%;
    width: 64px;
    height: 64px;
    margin-left: -32px;
    margin-top: -32px;
    background: rgba(0, 0, 0, 0.20);
    will-change: transform;
  }
  .pad.pad-active .stick-knob {
    /* pressed = a real analog stick, not a keyboard key: no dark grey.
       The fill LIGHTENS a touch and the bevel ring tightens (top/left
       light edges shrink) - reads as finger pressure, stays silver.
       Depth comes from the two shadow layers, not the knob. */
    background: var(--face-lite);
    box-shadow: inset -1px -1px #0a0a0a, inset 1px 1px #fff,
                inset -1px -1px #808080, inset 1px 1px #dfdfdf;
  }

  /* SNES face-button diamond: X top, Y left, A right, B bottom.
     Square Win98 buttons in the SNES arrangement - colored chips via
     small color swatch INSIDE the silver button, not the whole button. */
  .face-diamond {
    /* scaled up to match the big square stick (well 118px) - the cluster
       should read as one unit, not a giant stick next to tiny buttons */
    display: grid;
    grid-template-columns: repeat(3, 46px);
    grid-template-rows: repeat(3, 46px);
    gap: 3px;
    flex: 0 0 auto;
  }
  .face-x { grid-area: 1 / 2; }
  .face-y { grid-area: 2 / 1; }
  .face-a { grid-area: 2 / 3; }
  .face-b { grid-area: 3 / 2; }
  .face-btn {
    position: relative;
    font-size: 15px;
    font-weight: bold;
    color: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
  }
  .face-btn::before {
    content: '';
    position: absolute;
    top: 4px; left: 4px; right: 4px; bottom: 4px;
    /* SNES color chip SET INTO the silver button - sunken 1px bevel,
       kept faint so the chip blends rather than stickers out */
    box-shadow: inset 1px 1px rgba(255, 255, 255, 0.22),
                inset -1px -1px rgba(0, 0, 0, 0.15);
  }
  .face-x::before { background: #2f43c8; }
  .face-y::before { background: #2f9830; }
  .face-a::before { background: #c02f2f; }
  .face-b::before { background: #c8a800; }
  .face-btn span {
    position: relative;
    z-index: 1;
    text-shadow: 1px 1px 0 rgba(255,255,255,0.6);
  }
  /* compact phones (< 380px): shrink pad + diamond so nothing overflows */
  @media (max-width: 379px) {
    .pad { width: 150px; height: 150px; }
    .stick-well { width: 88px; height: 88px; margin-left: -44px; margin-top: -44px; }
    .stick-knob { width: 56px; height: 56px; margin-left: -28px; margin-top: -28px; }
    .stick-shadow { width: 56px; height: 56px; margin-left: -28px; margin-top: -28px; }
    .stick-shadow-mid { width: 56px; height: 56px; margin-left: -28px; margin-top: -28px; }
    .stick-shadow-outer { width: 56px; height: 56px; margin-left: -28px; margin-top: -28px; }
    .face-diamond { grid-template-columns: repeat(3, 42px); grid-template-rows: repeat(3, 42px); }
    .face-btn { font-size: 13px; }
  }
}

/* ===== short screens (MUST come after the base rules - equal specificity
   means the last rule wins; sitting earlier they silently lost) ===== */
@media (max-height: 700px) {
  .start-title { margin-top: 20px; font-size: 34px; }
  .start-sub { margin-bottom: 14px; }

  .menu { gap: 6px; }
  /* tighten the stack so stats/hold/next never overlap their neighbours */
  .side-stack { gap: 8px; }
  .stats-body { gap: 2px; justify-content: flex-start; }
  .stats-groupbox .stat-row { font-size: 9px; }
  .page-buttons { gap: 2px; margin-top: 2px; }
  .page-buttons .menu-btn { min-height: 20px; }
}

/* nav-bar integration: a themed host for the Android gesture pill (or a
   full-width face tint for the 3-button bar). Sized by native insets. */
#nav-integration {
  /* the pill's slot: a REAL blank box in the bar flow (like the other
     fields, but empty) - the Android gesture pill lands inside it. Auto
     margins dead-center it between the left info fields and the hint, so
     nothing overlaps and the bar reads READY / Guideline | pill | hints.
     The bevel themes itself (dark override below) in both themes. */
  position: static;
  flex: 0 0 auto;
  margin: 0 auto;
  align-self: center;
  height: 20px;
  width: 60px; /* JS overrides from the inset */
  border-radius: 2px;
  box-shadow: inset -1px -1px #dfdfdf, inset 1px 1px grey;
  transition: width 0.15s ease, opacity 0.2s ease;
  pointer-events: none;
}
[data-theme="dark"] #nav-integration {
  box-shadow: inset -1px -1px var(--bevel-face), inset 1px 1px var(--bevel-lo);
}
#nav-integration.buttons {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  border-radius: 0;
  background: #161616;
  opacity: 0.55;
}

/* the titlebar's right side: version badge + window controls in one group
   (badge mirrors the title's 24px margin, controls at the far edge) */
.title-bar-right { display: flex; align-items: center; }
