/* What player.js mounts, and what the page around it is made of.
 *
 * A WORKBENCH. The page is a cutting mat; on it sit two things -- the device (a
 * block of black glass with the screen in it, and a readout under the device)
 * and whatever the page puts in `below`, which index.html makes a sheet of
 * paper. Each has the corners of what it is: paper nearly square, glass round.
 *
 * THE COLOURS ARE DEFINED HERE, ONCE, for the page as well (index.html styles
 * its own parts with these names). Light is the design and dark is the same
 * bench with the lamp off; both follow the system.
 *
 * --pixel IS NOT IN THIS LIST. It is the colour the panel is lit in, set by
 * player.js whenever that changes, and it is only ever put on black: the
 * person chooses it, and white is one of the choices.
 */
:root {
  /* Each colour is light-dark(by day, by night), and WHICH is color-scheme's
   * to say: the system's, unless the page's menu chose (data-theme, set by
   * index.html before the first paint). */
  color-scheme: light dark;
  --mat: light-dark(#e1e6e2, #121715);        /* the bench */
  --mat-line: light-dark(#d3dad5, #1a211e);   /* the mat's grid */
  --sheet: light-dark(#fbfcfb, #1a211e);      /* paper, and anything paper-coloured that sits on the mat */
  --ink: light-dark(#152019, #e6ece8);
  --ink-2: light-dark(#57645d, #93a099);      /* ink, further back */
  --rule: light-dark(#cdd5d0, #2c3531);
  --body: light-dark(#f1f3f1, #27302b);       /* the device's shell */
  --body-edge: light-dark(#c2cbc5, #3a4640);
  --glass: light-dark(#0a0c0b, #040505);      /* its screen and its buttons: black either way */
  --glass-edge: light-dark(#2a302c, #262d29);
  --readout: #9aa69f;    /* type on the glass */
  --yes: light-dark(#1b7548, #62d29b);
  --no: light-dark(#b42318, #ff8f85);
  --sans: system-ui, "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
  --mono: ui-monospace, "JetBrains Mono", "Cascadia Mono", "SF Mono", Menlo, Consolas,
          "Noto Sans Mono CJK SC", "Noto Sans Mono", monospace;
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
/* THE NAMED THEMES (the user, 2026-10-12), each in its palette's own colours
 * and nothing mixed in between them, with one exception said below: the bench
 * is the palette's darker background, paper its background, ink its foreground
 * and its dimmer one, rules and the device's shell its highlight, the verdicts
 * its green and red. Each still says which scheme it is, for the browser's
 * own parts (the menus, the sliders, the scrollbar). The glass stays black:
 * that is the device, not the page.
 *
 * Tokyo Night's four are folke/tokyonight.nvim's. */
:root[data-theme="tokyo-night"] {
  color-scheme: dark;
  --mat: #16161e; --mat-line: #1a1b26; --sheet: #1a1b26; --ink: #c0caf5; --ink-2: #a9b1d6;
  --rule: #292e42; --body: #292e42; --body-edge: #414868; --yes: #9ece6a; --no: #f7768e;
}
:root[data-theme="tokyo-storm"] {
  color-scheme: dark;
  --mat: #1f2335; --mat-line: #24283b; --sheet: #24283b; --ink: #c0caf5; --ink-2: #a9b1d6;
  --rule: #343a52; --body: #343a52; --body-edge: #414868; --yes: #9ece6a; --no: #f7768e;
}
:root[data-theme="tokyo-moon"] {
  color-scheme: dark;
  --mat: #1e2030; --mat-line: #222436; --sheet: #222436; --ink: #c8d3f5; --ink-2: #828bb8;
  --rule: #2f334d; --body: #2f334d; --body-edge: #444a73; --yes: #c3e88d; --no: #ff757f;
}
:root[data-theme="tokyo-day"] {
  color-scheme: light;
  --mat: #d0d5e3; --mat-line: #c4c8da; --sheet: #e1e2e7; --ink: #3760bf; --ink-2: #6172b0;
  --rule: #c4c8da; --body: #e9e9ec; --body-edge: #a8aecb; --yes: #587539; --no: #f52a65;
}
/* Gruvbox, the medium contrast of each (there are a hard and a soft too). */
:root[data-theme="gruvbox-dark"] {
  color-scheme: dark;
  --mat: #1d2021; --mat-line: #282828; --sheet: #282828; --ink: #ebdbb2; --ink-2: #a89984;
  --rule: #3c3836; --body: #3c3836; --body-edge: #504945; --yes: #b8bb26; --no: #fb4934;
}
:root[data-theme="gruvbox-light"] {
  color-scheme: light;
  --mat: #ebdbb2; --mat-line: #d5c4a1; --sheet: #fbf1c7; --ink: #3c3836; --ink-2: #7c6f64;
  --rule: #d5c4a1; --body: #f9f5d7; --body-edge: #bdae93; --yes: #79740e; --no: #9d0006;
}
/* Solarized: the same sixteen, turned over. */
:root[data-theme="solarized-dark"] {
  color-scheme: dark;
  --mat: #002b36; --mat-line: #073642; --sheet: #073642; --ink: #93a1a1; --ink-2: #839496;
  --rule: #586e75; --body: #073642; --body-edge: #586e75; --yes: #859900; --no: #dc322f;
}
:root[data-theme="solarized-light"] {
  color-scheme: light;
  --mat: #eee8d5; --mat-line: #fdf6e3; --sheet: #fdf6e3; --ink: #586e75; --ink-2: #657b83;
  --rule: #93a1a1; --body: #fdf6e3; --body-edge: #93a1a1; --yes: #859900; --no: #dc322f;
}
/* Nord, and the bright ambiance its own guide describes (Snow Storm for the
 * background, Polar Night for the type). */
:root[data-theme="nord"] {
  color-scheme: dark;
  --mat: #2e3440; --mat-line: #3b4252; --sheet: #3b4252; --ink: #eceff4; --ink-2: #d8dee9;
  --rule: #4c566a; --body: #434c5e; --body-edge: #4c566a; --yes: #a3be8c; --no: #bf616a;
}
:root[data-theme="nord-light"] {
  color-scheme: light;
  --mat: #d8dee9; --mat-line: #e5e9f0; --sheet: #eceff4; --ink: #2e3440; --ink-2: #4c566a;
  --rule: #d8dee9; --body: #e5e9f0; --body-edge: #4c566a; --yes: #a3be8c; --no: #bf616a;
}
/* Dracula. THE EXCEPTION: its dim colour (Comment, #6272a4) is too faint on
 * its background for the amount of small type this page sets in --ink-2, so
 * that one is its foreground let down toward its background. */
:root[data-theme="dracula"] {
  color-scheme: dark;
  --mat: #21222c; --mat-line: #282a36; --sheet: #282a36; --ink: #f8f8f2;
  --ink-2: color-mix(in srgb, #f8f8f2 65%, #282a36);
  --rule: #44475a; --body: #44475a; --body-edge: #6272a4; --yes: #50fa7b; --no: #ff5555;
}
/* Catppuccin's four flavours, lightest first as its own pages list them: the
 * bench is Mantle (Latte's is Crust, so the paper shows on it), paper Base, ink
 * Text and Subtext 0, rules and the shell the Surfaces. */
:root[data-theme="catppuccin-latte"] {
  color-scheme: light;
  --mat: #dce0e8; --mat-line: #ccd0da; --sheet: #eff1f5; --ink: #4c4f69; --ink-2: #6c6f85;
  --rule: #ccd0da; --body: #e6e9ef; --body-edge: #acb0be; --yes: #40a02b; --no: #d20f39;
}
:root[data-theme="catppuccin-frappe"] {
  color-scheme: dark;
  --mat: #292c3c; --mat-line: #303446; --sheet: #303446; --ink: #c6d0f5; --ink-2: #a5adce;
  --rule: #414559; --body: #414559; --body-edge: #51576d; --yes: #a6d189; --no: #e78284;
}
:root[data-theme="catppuccin-macchiato"] {
  color-scheme: dark;
  --mat: #1e2030; --mat-line: #24273a; --sheet: #24273a; --ink: #cad3f5; --ink-2: #a5adcb;
  --rule: #363a4f; --body: #363a4f; --body-edge: #494d64; --yes: #a6da95; --no: #ed8796;
}
:root[data-theme="catppuccin-mocha"] {
  color-scheme: dark;
  --mat: #181825; --mat-line: #1e1e2e; --sheet: #1e1e2e; --ink: #cdd6f4; --ink-2: #a6adc8;
  --rule: #313244; --body: #313244; --body-edge: #45475a; --yes: #a6e3a1; --no: #f38ba8;
}
/* Chicago (the user, 2026-10-13): Windows 98's Standard scheme, named for the
 * system's typeface and the codename of the 95 before it. Its sixteen colours
 * and nothing else: the desktop's teal for the bench (flat -- that desktop has
 * no grid), the grey of a window and its buttons for paper, black type, the
 * title bar's navy for the type further back, the bevel's shadow for rules.
 *
 * COLOURS ONLY. No bevels, no title bars, no change of typeface: this menu
 * changes what colour things are, not what shape.
 *
 * THE SECOND EXCEPTION, and a larger one: this palette cannot be said in the
 * names above alone. Its desktop is a middle tone, so nothing dark reads on it,
 * and its paper is not its lightest colour. So below, by name, are the things
 * the names cannot reach -- and a new thing that sits on the mat, or is sunk
 * into the paper, or is typed in --sheet, needs a line here too. */
:root[data-theme="chicago"] {
  color-scheme: light;
  --mat: #008080; --mat-line: #008080; --sheet: #c0c0c0; --ink: #000000; --ink-2: #000080;
  --rule: #808080; --body: #c0c0c0; --body-edge: #808080; --yes: #008000; --no: #800000;
}
/* Type on the desktop is white, as the names under its icons are. */
:root[data-theme="chicago"] :is(#notice, #notice strong, #prefs, #noask, #status, #keys) { color: #ffffff; }
/* The lamp beside the readout sits on the teal too, where the dark green is lost. */
:root[data-theme="chicago"] #status::before { background: #c0c0c0; }
:root[data-theme="chicago"] .player[data-state="running"] #status::before { background: #00ff00; }
:root[data-theme="chicago"] .player[data-state="stopped"] #status::before { background: #ff0000; }
/* What is sunk into a window is white: a text field, a button held down. */
:root[data-theme="chicago"] :is(#assist-log .asked, #assist-log code, #assist-log pre, #assist button.quiet[aria-pressed="true"]) { background: #ffffff; }
/* What was typed in paper's colour on something dark is white, and the two
 * buttons in ink are the active title bar. */
:root[data-theme="chicago"] .badge { color: #ffffff; }
:root[data-theme="chicago"] :is(#open, #assist-intro button) { color: #ffffff; background: #000080; border-color: #000080; }

/* The scrollbar's room is kept whether there is one or not. Something on the
   page folding shut -- a sheet beside the screen -- makes the page short enough
   to lose its scrollbar, and without this everything centred slides half a
   scrollbar sideways: the screen moved 7 pixels when the ROM sheet closed. */
html { height: 100%; scrollbar-gutter: stable; }
body {
  min-height: 100%; margin: 0;
  color: var(--ink);
  font: 14px/1.5 var(--sans);
  /* A cutting mat, ruled in squares. */
  background:
    linear-gradient(var(--mat-line) 1px, transparent 1px) 0 0 / 32px 32px,
    linear-gradient(90deg, var(--mat-line) 1px, transparent 1px) 0 0 / 32px 32px,
    var(--mat);
}
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ------------------------------------------------------------ the two columns
 *
 * Side by side only when the stage still has room for its three controls in
 * one row; otherwise `below` is below. */
.player {
  display: grid; gap: 28px;
  max-width: 1200px; margin: 0 auto; padding: 8px 24px 48px;
}
/* The stage is what the device asks about its room (the @container below). */
.stage { display: grid; justify-items: center; align-content: start; gap: 20px; min-width: 0; container-type: inline-size; }
#below, #before { justify-self: center; width: min(100%, 34rem); min-width: 0; }
#below:empty, #before:empty { display: none; }
@media (min-width: 1180px) {
  /* 656px: room for the device with its buttons, at any display scaling. */
  .player { grid-template-columns: minmax(656px, 1fr) minmax(24rem, 29rem); gap: 48px; align-items: start; }
  #below, #before { justify-self: stretch; width: auto; }
  /* With something in `before` and no room for a third column, it goes
   * under `below`, and the stage keeps the whole of the other column. */
  .player:has(#before:not(:empty)) .stage { grid-area: 1 / 1 / span 2 / auto; }
  .player:has(#before:not(:empty)) #below { grid-area: 1 / 2; }
  #before { grid-area: 2 / 2; }
  /* The sheet can be longer than the window; the screen stays in it. */
  .stage { position: sticky; top: 24px; }
}
/* THREE COLUMNS when there is room and the page put something in `before`:
 * it sits left of the stage as `below` sits right of it, the same width, so
 * the device is in the middle. 1600px is the two side columns at their
 * narrowest, the stage at its narrowest, the gaps and the padding. */
@media (min-width: 1600px) {
  .player:has(#before:not(:empty)) {
    max-width: 1720px; grid-template-columns: minmax(24rem, 29rem) minmax(656px, 1fr) minmax(24rem, 29rem);
  }
  .player:has(#before:not(:empty)) .stage { grid-area: 1 / 2; }
  .player:has(#before:not(:empty)) #below { grid-area: 1 / 3; }
  #before { grid-area: 1 / 1; }
}
/* DEVELOPER MODE: the sheet in `before` takes most of the page, and the right
 * column keeps the device with `below` under it -- one column, as it is when the
 * window is narrow. Whoever is talking to it needs the room; the ROM sheet does
 * not need its own column to be read.
 *
 * The screen is neither covered nor made smaller: its column is still the 656px
 * it asks for, so the sketch of the handheld stays. The page is still columns,
 * not a panel over it.
 *
 * Pressed by `<html data-dev>` (web/assistant.js). Two columns are the least this
 * needs, so it is inside the 1180px above: under that the page is one column and
 * this changes nothing.
 *
 * THE PAGE KEEPS ITS OWN WIDTH THROUGH ALL OF THIS (the user, 2026-10-13): the
 * max-width above is not touched, so both edges of the page are where they were
 * and only the line between the columns moves. Letting it out to the window was
 * the first try, and what it reads as is a different page, not the same one with
 * more room to write in. */
@media (min-width: 1180px) {
  :root[data-dev] .player:has(#before:not(:empty)) { grid-template-columns: minmax(24rem, 1fr) 656px; }
  :root[data-dev] .player:has(#before:not(:empty)) #before { grid-area: 1 / 1 / span 2 / auto; }
  /* Not held in the window here: `below` is in this column under it, and would slide up over it. */
  :root[data-dev] .player:has(#before:not(:empty)) .stage { grid-area: 1 / 2; position: static; }
  :root[data-dev] .player:has(#before:not(:empty)) #below { grid-area: 2 / 2; }
}

/* ------------------------------------------------------------------ buttons */
.stage header { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.player button {
  font: 500 13px/1 var(--sans);
  padding: 9px 14px;
  color: var(--ink); background: var(--sheet);
  border: 1px solid var(--rule); border-radius: 7px;
  cursor: pointer;
  transition: border-color .08s, translate .08s;
}
.player button:hover:not(:disabled) { border-color: var(--ink-2); }
.player button:active:not(:disabled) { translate: 0 1px; }
.player button:disabled { opacity: .45; cursor: default; }
/* The one box under the buttons: a line to itself, and quieter than a button. */
#noask {
  flex-basis: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 2px;
  color: var(--ink-2); font: 12px/1 var(--mono); cursor: pointer;
}
#noask input { margin: 0; accent-color: var(--ink); }
/* The one that starts everything is the one in ink. */
#open { color: var(--sheet); background: var(--ink); border-color: var(--ink); }

/* ------------------------------------------------------------------ the device
 *
 * Black glass in either scheme, lying on the mat. The screen is a fixed size
 * (player.js: twice the panel); this is only what is around it. */
main { display: grid; }
.glass {
  padding: 24px;
  background: var(--glass);
  border-radius: 18px;
  box-shadow: inset 0 0 0 1px var(--glass-edge),
              0 1px 2px rgb(0 0 0 / .25), 0 18px 34px -16px rgb(0 0 0 / .5);
}
.pads { display: none; }

/* WITH ROOM FOR IT, THE GLASS IS SET IN A SKETCH OF THE HANDHELD, HELD
 * SIDEWAYS: the D-pad left of the screen, four buttons in a diamond right of
 * it (A at the bottom), Select and Start under those -- where HARDWARE.md puts
 * them and no more exactly than that. WITHOUT ROOM THERE IS NO SKETCH (the
 * user, 2026-10-12), rather than one stood on end. 656px is the sketch at the
 * widest the screen gets: 125% scaling makes it 307 across, not 256.
 *
 * The two side columns are a fixed width, so nothing moves when the machine
 * has named the buttons and they appear. */
@container (min-width: 656px) {
  main {
    grid-template: 1fr auto / 134px min-content 134px;
    place-items: center;
    padding: 16px 16px 20px;
    background: var(--body);
    border-radius: 34px 34px 46px 46px;
    box-shadow: inset 0 0 0 1px var(--body-edge), inset 0 -6px 0 -1px var(--body-edge),
                0 1px 2px rgb(0 0 0 / .2), 0 18px 34px -16px rgb(0 0 0 / .45);
  }
  .glass { grid-area: 1 / 2 / 3 / 3; padding: 18px; border-radius: 12px; box-shadow: inset 0 0 0 1px var(--glass-edge); }
  .pads, .mid { display: contents; }
  .dpad { grid-area: 1 / 1; }
  .face { grid-area: 1 / 3; }
  [data-button="SELECT"] { grid-area: 2 / 1; }
  [data-button="START"] { grid-area: 2 / 3; }
}
.dpad, .face { display: grid; grid-template: repeat(3, 34px) / repeat(3, 34px); }
.dpad::before { content: ""; grid-area: 2 / 2; background: var(--glass); }
.pads button {
  padding: 0; border: 0; border-radius: 7px;
  color: var(--readout); background: var(--glass);
  font: 600 12px/1 var(--mono);
  touch-action: none; user-select: none; -webkit-user-select: none;
}
.face button { margin: 1px; border-radius: 50%; }
.mid button { margin-bottom: 14px; padding: 6px 12px; border-radius: 999px; font-size: 9px; letter-spacing: .06em; }
[data-button="UP"], [data-button="Y"] { grid-area: 1 / 2; }
[data-button="LEFT"], [data-button="X"] { grid-area: 2 / 1; }
[data-button="RIGHT"], [data-button="B"] { grid-area: 2 / 3; }
[data-button="DOWN"], [data-button="A"] { grid-area: 3 / 2; }
/* Down: lit in the colour the panel is lit in. On black, like every use of it. */
.pads button.down { color: var(--pixel, #fff); box-shadow: inset 0 0 0 2px var(--pixel, var(--readout)); }
/* Nearest-neighbour, at a whole number of DEVICE pixels per panel pixel --
   player.js picks the size; this only says how to fill it. */
canvas { display: block; image-rendering: pixelated; background: #000; }

/* The readout: what is running and how fast, or why nothing is. UNDER THE
   DEVICE, on the mat (the user, 2026-10-12) -- so it is ink and not --pixel,
   which is somebody's choice and may be white. No wider than the device, so a
   long reason wraps. */
#status {
  max-width: min(100%, 37rem);
  color: var(--ink-2);
  font: 12px/1.45 var(--mono);
  text-align: center; overflow-wrap: anywhere;
}
#status::before {
  content: ""; display: inline-block;
  width: 7px; height: 7px; margin-right: 8px; border-radius: 50%;
  background: var(--rule);
}
.player[data-state="running"] #status::before { background: var(--yes); }
.player[data-state="stopped"] #status::before { background: var(--no); }

/* ------------------------------------------------------------------- the look */
#look {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px 26px;
  padding: 9px 18px;
  color: var(--ink-2); background: var(--sheet);
  border: 1px solid var(--rule); border-radius: 12px;
  font: 12px/1 var(--mono);
}
#look label { display: inline-flex; align-items: center; gap: 10px; white-space: nowrap; }
#look input[type="range"] { width: 128px; margin: 0; accent-color: var(--ink); }
#look input:disabled { opacity: .4; }
/* As wide as "100", so the row does not shuffle as a slider moves. */
#look output { min-width: 3ch; color: var(--ink); font-variant-numeric: tabular-nums; }
#look input[type="color"] {
  appearance: none; box-sizing: border-box;
  width: 30px; height: 30px; padding: 0;
  background: none; border: 1px solid var(--rule); border-radius: 8px;
  cursor: pointer; overflow: hidden;
}
#look input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
#look input[type="color"]::-webkit-color-swatch { border: 0; }
#look input[type="color"]::-moz-color-swatch { border: 0; }

/* ------------------------------------------------------------------- the keys */
#keys {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 18px;
  color: var(--ink-2);
  font: 12px/1 var(--mono);
}
#keys span { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
#keys b { margin-left: 5px; font-weight: 400; }
kbd {
  box-sizing: border-box; min-width: 24px; padding: 5px 6px;
  color: var(--ink); background: var(--sheet);
  border: 1px solid var(--rule); border-bottom-width: 2px; border-radius: 5px;
  font: inherit; text-align: center;
}

/* --------------------------------------------------------------- the bindings */
dialog {
  box-sizing: border-box; max-width: min(100vw - 24px, 32rem); padding: 22px 24px 18px;
  color: var(--ink); background: var(--sheet);
  border: 1px solid var(--rule); border-radius: 12px;
  box-shadow: 0 24px 48px -20px rgb(0 0 0 / .5);
}
dialog::backdrop { background: rgb(0 0 0 / .45); }
dialog h2 { margin: 0 0 12px; font: 600 15px/1.3 var(--sans); }
dialog table { width: 100%; margin: 0 0 12px; border-collapse: collapse; }
dialog th, dialog td { padding: 4px 10px 4px 0; text-align: left; font-weight: 400; }
dialog thead th { color: var(--ink-2); font: 11px/1.4 var(--mono); }
dialog tbody th { font: 12px/1 var(--mono); }
dialog td:last-child { padding-right: 0; }
.bind { width: 100%; min-width: 9em; }
.bind.waiting { border-style: dashed; border-color: var(--ink); }
#padname { margin: 0; color: var(--ink-2); font-size: 12.5px; overflow-wrap: anywhere; }
dialog footer { display: flex; justify-content: space-between; gap: 8px; margin-top: 16px; }

/* A file held over the page. */
body.drop::after {
  content: ""; position: fixed; inset: 12px; pointer-events: none;
  border: 2px dashed var(--ink); border-radius: 20px;
  background: color-mix(in srgb, var(--mat) 55%, transparent);
}

@media (prefers-reduced-motion: reduce) { .player button { transition: none; } }
