* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  --ease: cubic-bezier(0.25, 0.1, 0.25, 1);
  --canvas-bg: #fff;   /* the drawing's default paper */
}

/* ---- Palette ----
   Every color in this file comes from these tokens. Soft and warm:
   parchment neutrals instead of pure white and gray, and the Tomorrow
   syntax colors, muted and warmed to match. */
:root {
  --bg: #ece6dc;
  --surface: #f6f2eb;
  --border: #dbd2c4;
  --text: #3b342b;
  --text-muted: #72695c;
  --accent: #237a69;
  --accent-dim: #8fbfb2;
  --accent-wash: rgba(35, 122, 105, 0.1);
  --selection: rgba(35, 122, 105, 0.18);
  --error: #b5443b;
  --error-bg: rgba(181, 68, 59, 0.09);
  --error-bg-hover: rgba(181, 68, 59, 0.16);
  --primary-bg: #2b7d6c;
  --primary-border: #22685a;
  --primary-fg: #fbf8f2;
  --primary-hover-bg: #22685a;
  --primary-hover-fg: #fbf8f2;
  --kbd-bg: rgba(255, 250, 240, 0.2);
  --kbd-hover-bg: rgba(255, 250, 240, 0.2);
  --kbd-secondary-bg: rgba(70, 50, 20, 0.07);
  --hover-wash: rgba(70, 50, 20, 0.05);
  --hairline: rgba(70, 50, 20, 0.07);
  --scrollbar: rgba(70, 50, 20, 0.2);
  --shadow: rgba(70, 50, 20, 0.12);
  --hint-shadow: 0 0 3px rgba(255, 255, 255, 0.9);
  --glass-bg: rgba(246, 242, 235, 0.82);
  --glass-border: rgba(70, 50, 20, 0.08);
  --overlay-bg: rgba(246, 242, 235, 0.92);
  --close-bg: rgba(70, 50, 20, 0.06);
  --close-hover-bg: rgba(70, 50, 20, 0.11);

  --editor-bg: #faf7f1;
  --editor-fg: #4a4339;
  --editor-cursor: #4a4339;
  --editor-selection: #e9dfcc;
  --editor-linenumber: #aaa193;
  /* The underline carries the cue; the tint stays light enough that syntax
     colors remain readable over it. */
  --editor-error-bg: #f5d3cb;
  --editor-error-line: var(--error);
  --syn-comment: #958c7e;
  --syn-keyword: #bb4a42;
  --syn-atom: #88609e;
  --syn-variable: #637a2e;
  --syn-variable-2: #4b6f9c;
  --syn-def: #bf6a2c;
  --syn-string: #92702a;
  --syn-turtle: #92702a;
  --syn-bracket-match: #1f1a14;
  color-scheme: light;
}

:root { --focus-ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent-dim); }

::selection { background: var(--selection); }

/* Thin, unobtrusive scrollbars that only draw attention on hover. */
* { scrollbar-width: thin; scrollbar-color: var(--scrollbar) transparent; }

body {
  font-family: 'IBM Plex Sans', sans-serif;
  background: var(--bg);
  color: var(--text);
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

#app {
  display: grid;
  grid-template-rows: auto 1fr;
  height: 100vh;
  height: 100dvh;
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px max(16px, env(safe-area-inset-right)) 8px max(16px, env(safe-area-inset-left));
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.header-brand {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-shrink: 0;
}

header h1 {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.5px;
  white-space: nowrap;
}

header h1 .logo { width: 16px; height: 16px; flex-shrink: 0; }

#header-status {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--text-muted);
  margin-right: 4px;
  transition: color 0.2s var(--ease);
}

#header-status.error { color: var(--error); }

/* A pulsing dot marks work in progress (loading, running, stopping). */
#header-status.running::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  vertical-align: 1px;
  border-radius: 50%;
  background: var(--accent);
  animation: status-pulse 1.2s var(--ease) infinite;
}

@keyframes status-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.25; }
}

.header-controls {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 0;
}

header button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 30px;
  flex-shrink: 0;
  white-space: nowrap;
}

.icon { width: 14px; height: 14px; flex-shrink: 0; }

/* Share swaps its link icon for a check while "Copied" shows. */
#btn-share .icon-done { display: none; }
#btn-share.copied .icon-idle { display: none; }
#btn-share.copied .icon-done { display: inline; }
#btn-share.copied { color: var(--accent); border-color: var(--accent-dim); }

.kbd {
  font-family: inherit;
  font-size: 10px;
  font-weight: 500;
  line-height: 1;
  padding: 3px 5px;
  margin-left: 2px;
  border-radius: 4px;
  background: var(--kbd-bg);
  opacity: 0.85;
}

.kbd:empty { display: none; }
.btn-secondary .kbd { background: var(--kbd-secondary-bg); }

button {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  font-weight: 500;
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    background-color 0.15s var(--ease),
    border-color 0.15s var(--ease),
    color 0.15s var(--ease),
    transform 0.1s var(--ease);
}

button:hover { border-color: var(--accent-dim); color: var(--accent); }
button:active { transform: scale(0.97); }
button:focus { outline: none; }
button:focus-visible { box-shadow: var(--focus-ring); }

button:disabled,
button:disabled:hover {
  border-color: var(--border);
  color: var(--text-muted);
  opacity: 0.45;
  cursor: default;
  transform: none;
}

button.active { border-color: var(--accent-dim); color: var(--accent); }

button.primary {
  background: var(--primary-bg);
  border-color: var(--primary-border);
  color: var(--primary-fg);
}

button.primary:hover { background: var(--primary-hover-bg); color: var(--primary-hover-fg); }
button.primary:hover .kbd { background: var(--kbd-hover-bg); }

/* --split-x / --split-y are set by splitter.js; unset means an even split. */
#main {
  display: grid;
  grid-template-columns: minmax(0, var(--split-x, 1fr)) 6px minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  overflow: hidden;
}

#editor-panel {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 100px;
}

#splitter {
  background: var(--border);
  cursor: col-resize;
  position: relative;
  z-index: 10;
  touch-action: none;
  transition: background 0.15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Widen the grab area beyond the 6px bar without changing its look. */
#splitter::before { content: ''; position: absolute; inset: 0 -5px; }

#splitter:focus { outline: none; }
#splitter:hover, #splitter.dragging, #splitter:focus-visible { background: var(--accent-dim); }

#splitter-grip {
  display: flex;
  flex-direction: column;
  gap: 3px;
  opacity: 0.4;
  transition: opacity 0.15s ease;
}

#splitter:hover #splitter-grip,
#splitter.dragging #splitter-grip,
#splitter:focus-visible #splitter-grip { opacity: 1; }

#splitter-grip span {
  display: block;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--text-muted);
  transition: background-color 0.15s var(--ease);
}

#splitter:hover #splitter-grip span,
#splitter.dragging #splitter-grip span,
#splitter:focus-visible #splitter-grip span { background: var(--accent); }

.CodeMirror {
  flex: 1;
  font-family: 'IBM Plex Mono', monospace !important;
  font-size: 14px;
  line-height: 1.6;
  height: auto !important;
}

.CodeMirror-lines { padding: 8px 0; }
.CodeMirror-linenumber { opacity: 0.7; }

/* Editor theme ("turtle"), driven entirely by the palette tokens. */
.cm-s-turtle.CodeMirror { background: var(--editor-bg); color: var(--editor-fg); }
.cm-s-turtle .CodeMirror-gutters { background: var(--editor-bg); border-right: 1px solid var(--hairline); }
.cm-s-turtle .CodeMirror-linenumber { color: var(--editor-linenumber); }
.cm-s-turtle .CodeMirror-cursor { border-left: 1px solid var(--editor-cursor); }

/* While the command reference has focus, keep the editor's caret visible and
   blinking so the learner can see where a paste will land. CodeMirror hides
   blurred cursors (sometimes via an inline style), hence !important; the
   blink matches CodeMirror's own 530ms rate. */
.CodeMirror.cm-ghost-cursor:not(.CodeMirror-focused) div.CodeMirror-cursors { visibility: visible !important; }
.CodeMirror.cm-ghost-cursor:not(.CodeMirror-focused) .CodeMirror-cursor { animation: cursor-blink 1.06s steps(1) infinite; }

@keyframes cursor-blink {
  50% { visibility: hidden; }
}
.cm-s-turtle div.CodeMirror-selected,
.cm-s-turtle.CodeMirror-focused div.CodeMirror-selected { background: var(--editor-selection); }
.cm-s-turtle .CodeMirror-line::selection,
.cm-s-turtle .CodeMirror-line > span::selection,
.cm-s-turtle .CodeMirror-line > span > span::selection { background: var(--editor-selection); }
.cm-s-turtle span.cm-comment { color: var(--syn-comment); }
.cm-s-turtle span.cm-keyword,
.cm-s-turtle span.cm-tag { color: var(--syn-keyword); }
.cm-s-turtle span.cm-atom,
.cm-s-turtle span.cm-number,
.cm-s-turtle span.cm-link { color: var(--syn-atom); }
.cm-s-turtle span.cm-variable,
.cm-s-turtle span.cm-property,
.cm-s-turtle span.cm-attribute { color: var(--syn-variable); }
.cm-s-turtle span.cm-variable-2 { color: var(--syn-variable-2); }
.cm-s-turtle span.cm-def { color: var(--syn-def); }
.cm-s-turtle span.cm-string { color: var(--syn-string); }
.cm-s-turtle span.cm-bracket { color: var(--editor-fg); }
.cm-s-turtle span.cm-error { background: var(--syn-keyword); color: var(--editor-bg); }
.cm-s-turtle .CodeMirror-matchingbracket { text-decoration: underline; color: var(--syn-bracket-match) !important; }
.cm-s-turtle .cm-turtle-cmd { color: var(--syn-turtle); }

/* Code on the line the last error points at (not the whole editor row);
   cleared on the next edit or run. The underline is an inset shadow so it
   never changes the line's height. */
.cm-error-code {
  background: var(--editor-error-bg);
  box-shadow: inset 0 -2px 0 var(--editor-error-line);
}

/* A turtle command under the pointer while Cmd/Ctrl is held: click it for
   its examples (command-lookup.js). */
.cm-command-link {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  cursor: pointer;
}

/* Example calls of a turtle command, under a line whose call to it was
   rejected or a Cmd/Ctrl+clicked command name (usage-popup.js). CodeMirror positions it; this only sizes and paints it.
   The error-colored left edge ties it to the highlighted code. */
.usage-popup {
  z-index: 5;
  min-width: 180px;
  max-width: min(420px, calc(100% - 16px));
  margin-top: 4px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--editor-error-line);
  border-radius: 6px;
  background: var(--surface);
  box-shadow: 0 4px 14px var(--shadow);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  line-height: 1.5;
  cursor: default;
}

.usage-popup-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 4px 2px 10px;
}

.usage-popup-title {
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-muted);
}

.usage-popup-controls {
  display: flex;
  align-items: center;
  gap: 6px;
}

.usage-popup-hint {
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
}

.usage-popup-hint .kbd {
  margin: 0 3px 0 0;
  background: var(--kbd-secondary-bg);
  opacity: 1;
}

.usage-popup-close {
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.usage-popup-close:hover { background: var(--close-hover-bg); color: var(--text); }
.usage-popup-close:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.usage-popup-examples {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 2px 10px 8px;
}

.usage-popup-example {
  margin: 0;
  padding: 3px 8px;
  border-radius: 4px;
  background: var(--editor-bg);
  color: var(--editor-fg);
  font: inherit;
  white-space: pre;
  overflow-x: auto;
}

/* A panel docked to the bottom of a column (dock.js): the command reference
   under the editor, the terminal under the canvas. Collapsed, only the
   header shows; the header is the handle that resizes it. */
.dock {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  background: var(--surface);
  border-top: 1px solid var(--border);
}

.dock.collapsed > :not(.dock-header) { display: none; }

.dock-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  cursor: row-resize;
  user-select: none;
  min-height: 26px;
  position: relative;
  z-index: 10;
  font-family: 'IBM Plex Mono', monospace;
}

.dock.collapsed .dock-header { cursor: default; border-bottom: none; }

.dock-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-left: 2px;
  font-size: 11px;
  font-weight: 400;
  line-height: 1.3;
  color: var(--text-muted);
  white-space: nowrap;
}

/* Shortcuts named in a panel's header, and a switch beside them. The keys
   show at any width a keyboard is likely, since the header has room; a
   touch screen has no keys to press. */
/* Sized to fit the header's 17px of content height, like the clear button,
   so the header keeps the height dock.js collapses the panel to. */
.dock-header .kbd {
  margin: 0;
  padding: 2px 4px;
  background: var(--kbd-secondary-bg);
  color: var(--text);
  opacity: 1;
}

@media (max-width: 960px) and (hover: hover) {
  .dock-header .kbd:not(:empty) { display: inline-block; }
}

.dock-hint {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-right: 4px;
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
}

@media (hover: none) {
  .dock-hint { display: none; }
}

/* A dot says whether it's on: hollow off, filled on. */
.dock-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  height: 17px;
  padding: 0 1px 0 6px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: none;
  color: var(--text-muted);
  font-family: inherit;
  font-size: 11px;
  font-weight: 400;
  line-height: 1;
  white-space: nowrap;
}

.dock-toggle::before {
  content: '';
  width: 6px;
  height: 6px;
  border: 1px solid currentColor;
  border-radius: 50%;
}

.dock-toggle:hover { border-color: var(--text-muted); color: var(--text); }
.dock-toggle:active { transform: none; }

.dock-toggle[aria-pressed="true"],
.dock-toggle[aria-pressed="true"]:hover {
  border-color: var(--accent-dim);
  background: var(--accent-wash);
  color: var(--accent);
}

.dock-toggle[aria-pressed="true"]::before { background: currentColor; }

/* No key to press on a touch screen; the padding balances the dot. */
@media (hover: none) {
  .dock-toggle { padding-right: 6px; }
}

/* What a panel shows under its header. A class, not an id rule, so that the
   collapsed rule above outranks it. */
.dock-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

#terminal-panel {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
}

[data-tooltip] { position: relative; }

[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  white-space: nowrap;
  padding: 3px 7px;
  border-radius: 5px;
  box-shadow: 0 4px 12px var(--shadow);
  pointer-events: none;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 0.12s var(--ease), transform 0.12s var(--ease);
  z-index: 100;
}

[data-tooltip]:hover::after {
  opacity: 1;
  transform: none;
  transition-delay: 0.4s;
}
.dock-caret[data-tooltip]::after { left: 0; }
#terminal-clear[data-tooltip]::after { right: 0; }

.dock-caret {
  background: none;
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-muted);
  font-size: 9px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
  min-width: unset;
  font-family: inherit;
  flex-shrink: 0;
}

.dock-caret:hover { border-color: var(--text-muted); color: var(--text); }

.dock-caret-icon {
  display: inline-block;
  transition: transform 0.2s var(--ease);
}

.dock.collapsed .dock-caret-icon { transform: rotate(-90deg); }

/* Output arrived while the terminal was collapsed. */
#terminal-panel.has-unread #terminal-title::after {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 7px;
  vertical-align: 1px;
  border-radius: 50%;
  background: var(--accent);
}

#terminal-clear {
  background: none;
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-muted);
  font-size: 11px;
  cursor: pointer;
  padding: 2px 6px;
  line-height: 1;
  min-width: unset;
  font-family: inherit;
}

#terminal-clear:hover { border-color: var(--text-muted); color: var(--text); }
#terminal-panel.collapsed #terminal-clear { display: none; }

#terminal-content {
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  padding: 4px 8px;
  line-height: 1.6;
}

.terminal-line { white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text); }
.terminal-line.error { color: var(--error); }
.terminal-line.info { color: var(--text-muted); font-style: italic; }

/* "Line N" prefix on errors; jumps the editor to that line. */
.terminal-link {
  font: inherit;
  font-weight: 600;
  line-height: inherit;
  padding: 0 5px;
  border: none;
  border-radius: 4px;
  background: var(--error-bg);
  color: var(--error);
}

.terminal-link:hover { background: var(--error-bg-hover); color: var(--error); }

/* The canvas above the terminal. */
#stage {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 100px;
}

#canvas-panel {
  position: relative;
  flex: 1;
  min-height: 0;
  background: var(--canvas-bg);
  overflow: hidden;
}

/* Toolbar plus the gesture hint beneath it; they fade in and out together. */
#canvas-controls {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  opacity: 0.6;
  transition: opacity 0.25s var(--ease);
}

#canvas-toolbar {
  display: flex;
  gap: 4px;
  align-items: center;
  padding: 3px;
  border: 1px solid var(--glass-border);
  border-radius: 9px;
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
  box-shadow: 0 6px 20px var(--shadow);
}

/* Legible at rest, solid when used. */
#canvas-controls:hover,
#canvas-controls:focus-within { opacity: 1; }

/* No hover on touch screens, so the controls must always be visible. */
@media (hover: none) {
  #canvas-controls { opacity: 1; }
}

/* Never intercepts the pointer, so drags that start on it still pan the canvas. */
#canvas-hint {
  padding-right: 4px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  line-height: 1.4;
  color: var(--text-muted);
  text-align: right;
  text-shadow: var(--hint-shadow);
  pointer-events: none;
  user-select: none;
}

#canvas-hint .hint-touch { display: none; }

@media (hover: none) {
  #canvas-hint .hint-pointer { display: none; }
  #canvas-hint .hint-touch   { display: inline; }
}

#canvas-toolbar button {
  padding: 4px 8px;
  font-size: 11px;
  background: transparent;
  border-color: transparent;
  min-width: 28px;
}

#canvas-toolbar button:hover {
  background: var(--hover-wash);
  border-color: transparent;
}

#btn-grid.active { background: var(--accent-wash); color: var(--accent); }

#zoom-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  color: var(--text-muted);
  padding: 4px 6px;
  line-height: 1.6;
  min-width: 5ch;
  text-align: center;
  font-variant-numeric: tabular-nums;
  user-select: none;
}

#turtle-canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
  touch-action: none;
}

#turtle-canvas.panning { cursor: grabbing; }

/* Key hints add ~70px to the header, so they go before the status line does. */
@media (max-width: 960px), (hover: none) {
  .kbd { display: none; }
}

@media (max-width: 768px) {
  #main {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, var(--split-y, 1fr)) 6px minmax(0, 1fr);
  }
  #splitter { cursor: row-resize; }
  #splitter::before { inset: -8px 0; }
  #splitter-grip { flex-direction: row; }
  #editor-panel { border-bottom: none; min-width: unset; min-height: 80px; }
  #stage { min-width: unset; min-height: 80px; }
  .CodeMirror { font-size: 13px; }
}

/* Breakpoints below follow the header's width budget: full labels need ~720px,
   and the status line needs ~160px on top of that to say anything useful.
   Without it, errors still surface via the terminal and the highlighted line. */
@media (max-width: 880px) {
  #header-status { display: none; }
}

/* Narrow screens: secondary actions collapse to icons. */
@media (max-width: 760px) {
  header { gap: 12px; padding-left: max(12px, env(safe-area-inset-left)); padding-right: max(12px, env(safe-area-inset-right)); }
  .header-controls { gap: 6px; }
  header button { height: 34px; }
  header .btn-secondary { width: 34px; padding: 0; }
  header .btn-secondary .btn-label { display: none; }
}

@media (max-width: 440px) {
  .brand-text { display: none; }
  .header-brand { gap: 10px; }
}

/* The reference fills its panel under the editor: a fixed header (search
   bar and keyboard hint) above the body, a scrolling list of signatures
   beside the selected command's detail pane, so the search bar and the
   detail stay in reach however far down the list the learner has scrolled.
   A narrow panel stacks the detail pane under the list (see the container
   queries below). Its size comes from the panel, never from its content,
   so it can be a size container. */
#api-overlay {
  container: api-overlay / size;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 16px;
  background: var(--surface);
}

#api-overlay:focus { outline: none; }

@keyframes overlay-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

#api-header {
  flex: none;
  padding: 16px 24px 12px;
  border-bottom: 1px solid var(--hairline);
}

#api-searchbar {
  display: flex;
  align-items: center;
  gap: 10px;
}

#api-search-field {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text-muted);
  cursor: text;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

#api-search-field:focus-within { border-color: var(--accent-dim); box-shadow: var(--focus-ring); }

#api-search {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: none;
  background: none;
  outline: none;
  color: var(--text);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  -webkit-appearance: none;
  appearance: none;
}

#api-search::placeholder { color: var(--text-muted); opacity: 1; }
#api-search::-webkit-search-cancel-button,
#api-search::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }

/* iOS Safari zooms the page into any focused input under 16px. */
@media (hover: none) {
  #api-search { font-size: 16px; }
}

#api-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: fit-content(50%) minmax(0, 1fr);
}

/* A gap rather than heading margins, so the first visible section sits flush
   at the top whichever sections the search has hidden. */
#api-list {
  min-height: 0;
  min-width: 200px;
  overflow-y: auto;
  padding: 16px 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

#api-scroll-hint {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}

#api-scroll-hint .kbd { background: var(--kbd-secondary-bg); margin: 0; }

/* No arrow keys to press on a touch screen. */
@media (hover: none) {
  #api-scroll-hint { display: none; }
}

.api-section[hidden],
.api-rows li[hidden],
#api-empty[hidden] { display: none; }

.api-section h2 {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  margin: 0 0 8px 0;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

/* Rows show only the signature; the description is data for the search and
   the detail pane. */
.api-rows { list-style: none; }

.api-rows li {
  position: relative;
  display: flex;
  align-items: center;
  padding: 5px 0;
  border-bottom: 1px solid var(--hairline);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  line-height: 1.5;
  color: var(--accent);
  white-space: nowrap;
  cursor: pointer;
}

.api-rows code { font: inherit; }
.api-about { display: none; }

/* The last visible row, not the last row: search may hide the rows below it. */
.api-rows li:not(:has(~ li:not([hidden]))) { border-bottom: none; }

/* Hovered and selected rows. The side shadows extend the wash 8px past the text on
   each end (into #api-list's padding) so the text isn't flush. The scroll
   margin keeps the tooltip above the row in view when the selection
   scrolls the list. */
.api-rows li:hover {
  background: var(--hover-wash);
  box-shadow: -8px 0 0 var(--hover-wash), 8px 0 0 var(--hover-wash);
}

.api-rows li.selected {
  scroll-margin-top: 32px;
  background: var(--accent-wash);
  box-shadow: -8px 0 0 var(--accent-wash), 8px 0 0 var(--accent-wash);
}

/* Icon buttons: copy (beside each signature, and on the demo) and insert
   (on the demo). After acting, the icon turns to a checkmark for a moment. */
.api-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex: none;
  padding: 0;
  vertical-align: middle;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--text-muted);
  transition: opacity 0.15s var(--ease), background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.api-action .icon { width: 13px; height: 13px; }
.api-action:hover { background: var(--hover-wash); color: var(--accent); }
.api-action.done { color: var(--accent); }

.api-action .icon-done { display: none; }
.api-action.done .icon-idle { display: none; }
.api-action.done .icon-done { display: inline; }

/* An insert-and-copy pair. Tooltips name what each unlabeled icon does, so
   they show at once, centered over their buttons. */
.api-actions { display: flex; gap: 2px; }

.api-actions [data-tooltip]::after {
  left: 50%;
  transform: translate(-50%, 2px);
  transition-duration: 0.06s;
}
.api-actions [data-tooltip]:hover::after { transform: translateX(-50%); transition-delay: 0s; }

/* A row's pair sits at its right edge, out of the signature's way. It shows
   only on the row the learner picked (clicked or arrowed to): hidden, not
   transparent, so it can't be clicked or tabbed to before then. Its space
   is always reserved, so rows never shift, and the negative vertical margins
   keep it from making the row taller. */
.api-rows .api-actions { margin: -3px 0 -3px auto; padding-left: 16px; visibility: hidden; }
.api-rows li.picked .api-actions { visibility: visible; }

/* Tooltip above the selected row, so it covers the row above rather than the
   row itself. Left-aligned with the signature: centered on the copy button it
   would overhang #api-list's left edge on short signatures. */
.api-copy-hint {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  box-shadow: 0 2px 6px var(--shadow);
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1.4;
  white-space: nowrap;
  pointer-events: none;
}

.api-copy-hint .kbd { margin: 0; background: var(--kbd-secondary-bg); color: var(--text); }

/* Its shortcuts need a keyboard, and .kbd hides them on touch screens. */
@media (max-width: 960px), (hover: none) {
  .api-copy-hint { display: none; }
}

/* ---- Detail pane: the selected command, its demo, and the demo running ---- */

#api-detail {
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 24px 20px;
  border-left: 1px solid var(--hairline);
  overflow-y: auto;   /* a short canvas panel: the canvas stops shrinking at its minimum */
}

/* No match: the pane keeps its space, so the list doesn't reflow. */
#api-detail.empty > * { visibility: hidden; }

/* Demos off: the description alone, and a note on how to turn them on. Off
   in the narrow layout, the strip is only as tall as its text. */
#api-detail.demos-off #api-detail-demo,
#api-detail.demos-off #api-preview,
#api-detail.demos-off #api-preview-output { display: none; }
#api-detail.demos-off { height: auto; }
#api-detail:not(.demos-off) #api-demo-off { display: none; }

#api-demo-off {
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}

#api-demo-off b { font-weight: 500; color: var(--text); }

#api-detail-call {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--accent);
  overflow-wrap: anywhere;
}

#api-detail-about {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}

#api-detail-code,
#api-preview-output {
  flex: none;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  line-height: 1.6;
  tab-size: 4;
  white-space: pre;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
}

/* The demo's buttons sit in the code's top-right corner, always shown; the
   code keeps clear of them with its right padding. */
#api-detail-demo {
  position: relative;
  flex: none;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

#api-detail-code {
  min-height: 0;
  padding: 8px 58px 8px 12px;
  background: var(--editor-bg);
  color: var(--editor-fg);
}

/* Opaque, since the code runs under them; the hover wash is layered on. */
.api-demo-actions {
  position: absolute;
  top: 6px;
  right: 6px;
}

.api-demo-actions .api-action { background: var(--editor-bg); }
.api-demo-actions .api-action:hover { background: linear-gradient(var(--hover-wash), var(--hover-wash)), var(--editor-bg); }

#api-detail-demo[hidden],
#api-preview-output[hidden] { display: none; }

/* The canvas takes whatever height is left. Absolutely positioned, so the
   box's size never depends on the canvas the renderer sizes from it. */
#api-preview {
  position: relative;
  flex: 1;
  min-height: 120px;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--canvas-bg);
}

#api-preview-canvas {
  position: absolute;
  inset: 0;
  display: block;
}

/* Printed lines are laid out from the start and revealed as the demo
   reaches them, so the canvas above keeps its size. */
#api-preview-output {
  margin-top: -4px;
  padding: 6px 12px;
  background: var(--surface);
  color: var(--text);
}

.preview-line { min-height: 1.6em; }
.preview-line.pending { visibility: hidden; }
.preview-line.error { color: var(--error); white-space: pre-wrap; }

/* Too narrow for two columns: the list above, the detail pane below it as a
   strip, with the demo's code on the left and the canvas on the right. */
@container api-overlay (max-width: 560px) {
  #api-header { padding: 12px 16px 10px; }
  #api-body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
  }
  #api-list { min-width: 0; padding: 12px 16px 16px; }
  #api-detail {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 45%);
    grid-template-rows: auto auto minmax(0, 1fr) auto;
    gap: 6px 12px;
    height: 200px;
    padding: 12px 16px 14px;
    border-left: none;
    border-top: 1px solid var(--hairline);
    overflow: hidden;
  }
  #api-detail > * { grid-column: 1; }
  #api-detail-about { font-size: 12px; }
  #api-detail-demo { align-self: start; max-height: 100%; }
  #api-detail-code { flex: 0 1 auto; overflow: auto; }
  #api-preview { grid-column: 2; grid-row: 1 / -1; min-height: 0; }
  #api-preview-output { margin-top: 0; }
}

/* Short: tighter padding, and no keyboard hint.
   Narrow and short, the detail strip gives the list half the height. */
@container api-overlay (max-height: 420px) {
  #api-header { padding: 10px 16px 8px; }
  #api-scroll-hint { display: none; }
  #api-list { padding: 10px 16px 14px; gap: 14px; }
  #api-detail { padding: 10px 16px 14px; }
}

@container api-overlay (max-width: 560px) and (max-height: 420px) {
  #api-detail { height: min(200px, 50cqh); }
}

#api-empty {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--text-muted);
  text-align: center;
  padding: 24px 0;
  overflow-wrap: anywhere;
}

#api-empty q { color: var(--text); }

/* Small round buttons in the controller menu's and mapping view's headers. */
.icon-button {
  flex: none;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--close-bg);
  border: none;
  border-radius: 50%;
  color: var(--text-muted);
  font-size: 16px;
  cursor: pointer;
  padding: 0;
  line-height: 1;
}

.icon-button:hover { background: var(--close-hover-bg); color: var(--text); }

/* ---- Controller ----
   The menu of commands worked with a game controller (gamepad-menu.js), the
   button that opens it, and the view that shows and changes what each
   button does (gamepad-mapping.js). All three sit in the canvas panel. */

.icon-button.quiet:not(:hover) { background: none; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* A controller button's label, wherever one is named. */
.pad-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--surface);
  color: var(--text);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  font-style: normal;
  line-height: 1;
  vertical-align: middle;
}

.pad-glyph:empty { display: none; }

#gamepad-chip[hidden],
#gamepad-menu[hidden],
#gamepad-menu-back[hidden],
#gamepad-menu-rows[hidden],
#gamepad-menu-form[hidden],
#gamepad-menu-empty[hidden],
#gamepad-mapping[hidden] { display: none; }

/* The menu opens from the corner its button sits in. The button is covered
   by the reference when that is over the canvas; the menu, being worked
   without the pointer, stays above it. */
#gamepad-chip,
#gamepad-menu {
  position: absolute;
  left: 8px;
  bottom: 8px;
}

#gamepad-chip {
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 8px 0 10px;
  border-color: var(--glass-border);
  border-radius: 9px;
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
  box-shadow: 0 6px 20px var(--shadow);
  font-size: 11px;
}

/* A fixed height, so the header and hints stay put from page to page. */
#gamepad-menu {
  z-index: 25;
  display: flex;
  flex-direction: column;
  width: 280px;
  max-width: calc(100% - 16px);
  height: 380px;
  max-height: calc(100% - 16px);
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--overlay-bg);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  backdrop-filter: blur(20px) saturate(1.2);
  box-shadow: 0 12px 36px var(--shadow), 0 2px 8px var(--shadow);
  font-family: 'IBM Plex Sans', sans-serif;
  animation: overlay-in 0.2s var(--ease);
}

#gamepad-menu-header {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 8px 8px 12px;
  border-bottom: 1px solid var(--hairline);
}

#gamepad-menu-back { margin-left: -6px; }

#gamepad-menu-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
  line-height: 26px;
  color: var(--text);
}

#gamepad-menu-rows {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px;
  list-style: none;
}

/* The selected row is the controller's place in the list; a hovered row is
   only the pointer's. */
.pad-row {
  display: flex;
  align-items: center;
  border-radius: 6px;
  scroll-margin: 4px;
}

.pad-row:hover { background: var(--hover-wash); }
.pad-row.selected { background: var(--accent-wash); }

.pad-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 30px;
  padding: 0 8px;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  text-align: left;
}

.pad-row-main:hover { color: var(--text); }

.pad-row-main:active,
.pad-row-alt:active,
.pad-map-row:active,
.pad-option:active { transform: none; }

.pad-row-label,
.pad-map-function,
.pad-option-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pad-row-command .pad-row-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--accent);
}

.pad-row-danger .pad-row-label { color: var(--error); }

.pad-row-detail {
  flex: none;
  font-size: 11px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.pad-row-group .pad-row-main::after {
  content: '›';
  font-size: 15px;
  line-height: 1;
  color: var(--text-muted);
}

/* A row's second action: hidden, not transparent, until the row is selected
   or hovered, so it can't be clicked or tabbed to before then. A saved
   command keeps its star showing, filled in. */
.pad-row-alt {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin-right: 3px;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--text-muted);
  visibility: hidden;
}

.pad-row-alt .icon { width: 13px; height: 13px; }
.pad-row-alt:hover { background: var(--hover-wash); color: var(--accent); }

.pad-row:hover .pad-row-alt,
.pad-row.selected .pad-row-alt,
.pad-row.saved .pad-row-alt { visibility: visible; }

.pad-row.saved .pad-row-alt { color: var(--accent); }
.pad-row.saved .pad-row-alt path { fill: currentColor; }

#gamepad-menu-form {
  flex: none;
  padding: 10px 12px 0;
}

#gamepad-menu-input {
  width: 100%;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  outline: none;
  background: var(--surface);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

#gamepad-menu-input:focus { border-color: var(--accent-dim); box-shadow: var(--focus-ring); }

/* iOS Safari zooms the page into any focused input under 16px. */
@media (hover: none) {
  #gamepad-menu-input { font-size: 16px; }
}

#gamepad-menu-empty {
  flex: 1;
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}

/* Which button does what to the selected row. */
#gamepad-menu-hints {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  padding: 6px 12px;
  border-top: 1px solid var(--hairline);
  font-size: 11px;
  color: var(--text-muted);
}

#gamepad-menu-hints:empty { display: none; }

.pad-hint {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
}

/* The mapping view covers the canvas, as the reference does there: the
   controller and its legend beside the list of functions. Its size comes
   from the canvas panel, so it can be a size container; narrow, the list
   goes under the controller. */
#gamepad-mapping {
  container: gamepad-mapping / size;
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: 26;
  display: flex;
  flex-direction: column;
  background: var(--overlay-bg);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  backdrop-filter: blur(20px) saturate(1.2);
  font-family: 'IBM Plex Sans', sans-serif;
  animation: overlay-in 0.2s var(--ease);
}

#gamepad-mapping-header {
  flex: none;
  padding: 16px 24px 12px;
  border-bottom: 1px solid var(--hairline);
}

#gamepad-mapping-titlebar {
  display: flex;
  align-items: center;
  gap: 10px;
}

#gamepad-mapping-titlebar h2 {
  flex: 1;
  min-width: 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

#gamepad-mapping-reset { padding: 4px 10px; font-size: 11px; }

#gamepad-mapping-help {
  margin-top: 10px;
  font-size: 12px;
  line-height: 2;
  color: var(--text-muted);
}

#gamepad-mapping-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(200px, 38%);
}

#gamepad-mapping-controller {
  min-height: 0;
  overflow-y: auto;
  padding: 16px 24px 20px;
}

#gamepad-mapping-diagram {
  max-width: 400px;
  margin: 0 auto 16px;
}

#gamepad-mapping-diagram svg {
  display: block;
  width: 100%;
  height: auto;
}

.pad-body { fill: var(--bg); stroke: var(--text-muted); stroke-width: 1.2; }
.pad-detail { fill: none; stroke: var(--border); stroke-width: 1; }

.pad-button { cursor: pointer; }

.pad-shape {
  fill: var(--surface);
  stroke: var(--text-muted);
  stroke-width: 1;
  transition: fill 0.12s var(--ease), stroke 0.12s var(--ease);
}

.pad-button text {
  fill: var(--text);
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 600;
  text-anchor: middle;
  dominant-baseline: central;
  pointer-events: none;
  user-select: none;
}

/* A button that does nothing is an outline; the one being changed is ringed;
   one held down on the controller fills in. */
.pad-button.unmapped .pad-shape { fill: var(--bg); stroke-dasharray: 2 2; }
.pad-button.unmapped text { fill: var(--text-muted); }
.pad-button:hover .pad-shape,
.pad-button.selected .pad-shape { stroke: var(--accent); }
.pad-button.selected .pad-shape { stroke-width: 2; stroke-dasharray: none; }
.pad-button.pressed .pad-shape { fill: var(--accent-dim); }

/* Two columns read downward, the order the controller steps through them. */
#gamepad-mapping-legend {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: repeat(8, auto);
  gap: 2px 16px;
  max-width: 480px;
  margin: 0 auto;
  list-style: none;
}

.pad-map-row,
.pad-option {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 28px;
  padding: 0 8px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  text-align: left;
  scroll-margin: 4px;
}

.pad-map-row:hover,
.pad-option:hover { background: var(--hover-wash); color: var(--text); }

.pad-map-row.selected { background: var(--accent-wash); }

/* As wide as the widest label, so the functions line up. */
.pad-map-row .pad-glyph { min-width: 42px; }

.pad-map-row.unmapped .pad-map-function { color: var(--text-muted); font-style: italic; }

.pad-map-function.code,
.pad-option.code {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--accent);
}

#gamepad-mapping-picker {
  min-height: 0;
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--hairline);
}

#gamepad-mapping-button {
  flex: none;
  padding: 16px 24px 8px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--text);
}

#gamepad-mapping-options {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0 16px 20px;
  list-style: none;
}

.pad-option-group {
  margin: 14px 8px 4px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

/* What the button does now is checked; the row the controller is on, while
   it is in this list, is washed and ringed. */
.pad-option.current { font-weight: 500; }
.pad-option.current::after { content: '✓'; flex: none; color: var(--accent); }
.pad-option.selected { background: var(--accent-wash); box-shadow: inset 0 0 0 1px var(--accent-dim); }

@container gamepad-mapping (max-width: 560px) {
  #gamepad-mapping-header { padding: 12px 16px 10px; }
  #gamepad-mapping-body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
  }
  #gamepad-mapping-controller { padding: 12px 16px 16px; }
  #gamepad-mapping-picker { border-left: none; border-top: 1px solid var(--hairline); }
  #gamepad-mapping-button { padding: 12px 16px 6px; }
  #gamepad-mapping-options { padding: 0 8px 16px; }
}

@container gamepad-mapping (max-height: 420px) {
  #gamepad-mapping-header { padding: 10px 16px 8px; }
  #gamepad-mapping-help { display: none; }
}

/* SharedArrayBuffer not available warning */
#sab-warning[hidden] { display: none; }

#sab-warning {
  position: fixed;
  top: 0; left: 0; right: 0;
  background: #7a2020;
  color: #ffd;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  padding: 8px 16px;
  text-align: center;
  z-index: 999;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
  button:active { transform: none; }
  #header-status.running::before { animation: none; }
  .CodeMirror.cm-ghost-cursor .CodeMirror-cursor { animation: none; }
}
