/* One palette, written once. `light-dark()` under `color-scheme` gives both
   themes from a single declaration, and choosing a theme is narrowing the
   scheme on the root element (see theme.js) — there is no second sheet to keep
   in step. */
:root {
  color-scheme: light dark;
  --mono: ui-monospace, "Cascadia Code", "SF Mono", Consolas, monospace;
  --line: color-mix(in srgb, currentColor 22%, transparent);
  --field: color-mix(in srgb, currentColor 5%, transparent);
  --panel: light-dark(#ffffff, #191919);
  --page: light-dark(#fbfbfb, #111111);
  --answer: light-dark(#0b5f2a, #7ee2a8);
  --error: light-dark(#a01b1b, #ff9a9a);
  --muted: color-mix(in srgb, currentColor 55%, transparent);
  --caret: light-dark(#111, #eee);
  --accent: light-dark(#1e5fbf, #7fb2ff);
}

body {
  font: 15px/1.5 system-ui, sans-serif;
  margin: 0 auto;
  max-width: 82rem;
  padding: 1.5rem 1rem 2.5rem;
  background: var(--page);
}

/* --- header ------------------------------------------------------------- */

header {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 1.1rem;
}
.title { flex: 1; min-width: 0; }
h1 { font-size: 1.3rem; margin: 0; letter-spacing: -.01em; }
.sub { margin: .15rem 0 0; color: var(--muted); font-size: .9rem; }

.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  flex: none;
  border-radius: .5rem;
  color: var(--muted);
}
.icon-button:hover { color: inherit; }

/* --- panes -------------------------------------------------------------- */

/* The two panes are the same height, top and bottom. They do not hold the same
   furniture — the program side carries a workspace bar and a file list — so
   equal height means the TRANSCRIPT takes up the slack, which is where extra
   room is worth having. */
/* The source side is a little wider: it now carries a line-number gutter, and
   code is the thing that suffers first from a narrow column. The middle column
   is the draggable seam (layout.js): --split is the source side's share, and
   its default keeps the old 1.15fr/1fr proportion. */
.panes {
  display: grid;
  grid-template-columns: minmax(16rem, var(--split, 53.5%)) .9rem minmax(16rem, 1fr);
  align-items: stretch;
}
@media (max-width: 62rem) {
  .panes { grid-template-columns: 1fr; gap: 1.25rem; }
  /* The stacked layout has no seams to drag: panes flow, docks size to content. */
  .splitter-v, .dock-resize { display: none !important; }
}

/* --- the resizable seams (layout.js) ------------------------------------- */

.splitter-v { cursor: col-resize; position: relative; touch-action: none; }
.splitter-v::before {
  content: '';
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: 1px;
  background: var(--line);
}
.splitter-v:hover::before, .splitter-v:active::before {
  width: 3px; margin-left: -1px;
  background: var(--accent);
}

/* A dock's top edge. It IS the dock's separator line — the border the dock
   used to draw — grown into a grab strip. */
.dock-resize {
  flex: none;
  height: .55rem;
  cursor: row-resize;
  position: relative;
  touch-action: none;
  margin-bottom: .15rem;
}
.dock-resize::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 1px;
  background: var(--line);
}
.dock-resize:hover::before, .dock-resize:active::before {
  height: 3px; margin-top: -1px;
  background: var(--accent);
}

.pane {
  min-width: 0;
  min-height: 0;          /* so a child may be smaller than its content */
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: .6rem;
  padding: .85rem .9rem 1rem;
}

h2 {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); margin: 0 0 .5rem; font-weight: 600;
}

/* An action that belongs to a pane rather than to the query line — putting it
   down there would take room from the thing being typed. */
.heading-action {
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0 .2rem;
  margin-left: .5rem;
  cursor: pointer;
  text-decoration: underline;
}
.heading-action:hover { color: inherit; opacity: .75; }

/* --- fields ------------------------------------------------------------- */

pre#out, input, select {
  font: 13px/1.5 var(--mono);
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-radius: .4rem;
  background: var(--field);
  color: inherit;
  padding: .4rem .6rem;
}
pre#out { padding: .6rem .75rem; }
:is(input, select, pre#out, .editor, button):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* --- the editor ---
   One element, holding the coloured text it edits. Nothing to keep aligned. */
.editor {
  font: 13px/1.5 var(--mono);
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-radius: .4rem;
  background: var(--field);
  color: inherit;
  padding: .6rem .75rem;
  /* Fixed rather than growing: the editor is the reference the answers pane is
     matched against, so it must not chase it back. */
  height: 24rem;
  flex: none;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  tab-size: 4;
  caret-color: var(--caret);
}
.editor.has-error { border-color: var(--error); }
.editor:empty::before {
  content: attr(data-placeholder);
  color: var(--muted);
  white-space: pre-wrap;
}

/* Token colours. Deliberately few: structure first, then what a reader scans
   for — a variable, a quoted string, a comment to skip. */
.tok-comment  { color: var(--muted); font-style: italic; }
.tok-variable { color: light-dark(#7a3ea3, #d8a7ff); }
.tok-operator { color: light-dark(#0b5f8a, #7fd1ff); }
.tok-number   { color: light-dark(#0b5f2a, #7ee2a8); }
.tok-quoted   { color: light-dark(#9a5b00, #ffc879); }
.tok-error    { text-decoration: underline wavy var(--error); }

.completions {
  font: 12px var(--mono);
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: .35rem;
  padding: .35rem .5rem;
  margin-top: .35rem;
  max-height: 6rem;
  overflow: auto;
}

.hint { font-size: .78rem; color: var(--muted); margin-left: auto; }

/* --- workspace bar and files -------------------------------------------- */

.bar { display: flex; gap: .35rem; align-items: center; margin-bottom: .5rem; }
.bar select { flex: 1; min-width: 0; }

/* The dropdown is drawn by the platform using the ELEMENT's background, and
   --field is nearly transparent (it is meant to sit on a panel). That left the
   popup on the system's own white with our light-theme-on-dark text. Both the
   control and its options get an opaque colour of their own. */
select { background: var(--panel); }
select option { background: var(--panel); color: light-dark(#111, #eee); }
.bar button { font-size: .82rem; padding: .3rem .6rem; }

/* The file list is ONE row however many files there are: a wrapping list of
   forty chips pushes the editor off the screen, and the thing you came for is
   the editor. The strip scrolls instead, with its scrollbar hidden so the row
   keeps a fixed height — the arrows are the visible affordance. */
.files { display: flex; align-items: center; gap: .3rem; margin-bottom: .45rem; min-height: 1.6rem; }
.files-strip {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  gap: .3rem;
  overflow-x: auto;
  scroll-behavior: smooth;
  scrollbar-width: none;
}
.files-strip::-webkit-scrollbar { display: none; }
.files-nav {
  flex: none;
  font: 14px/1 system-ui, sans-serif;
  padding: .1rem .35rem;
  border-radius: .3rem;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.files-nav:hover:not(:disabled) { color: inherit; }
.files-nav:disabled { opacity: .35; cursor: default; }
.file {
  flex: none;
  white-space: nowrap;
  font: 12px var(--mono);
  padding: .15rem .5rem;
  border-radius: .3rem;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.file:hover { color: inherit; }
.file.current {
  color: inherit;
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

.row { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin-top: .5rem; }
.row.end { justify-content: flex-end; }

/* --- the transcript ----------------------------------------------------- */

pre#out {
  /* `flex: 1 1 0` with a min-height SMALLER than the pane's natural height is
     what makes this a window rather than a growing page: a flex item is sized
     from its content unless its basis is zero, so transcript text pushed the
     pane taller and taller instead of scrolling inside it. The height now comes
     from the pane — which the editor opposite sets — and the floor only matters
     if that side ever gets short. */
  flex: 1 1 0;
  min-height: 12rem;
  overflow: auto;
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
}
pre#out .query  { color: var(--muted); }
pre#out .answer { color: var(--answer); }
pre#out .error  { color: var(--error); }
pre#out .note   { color: var(--muted); font-style: italic; }

.status {
  font: 12px var(--mono);
  color: var(--muted);
  margin: .35rem 0 0;
  min-height: 1.2em;
}
/* The prompt marks that the engine is holding a solution back. */
body.pending .prompt { color: var(--answer); font-weight: 700; }

#query-form { display: flex; gap: .4rem; align-items: center; margin-top: .35rem; }
.prompt { font: 13px var(--mono); color: var(--muted); }
#query { flex: 1; }

/* --- buttons ------------------------------------------------------------ */

button {
  font: inherit;
  padding: .35rem .85rem;
  border-radius: .35rem;
  border: 1px solid var(--line);
  background: color-mix(in srgb, currentColor 8%, transparent);
  color: inherit;
  cursor: pointer;
}
button:hover { background: color-mix(in srgb, currentColor 16%, transparent); }
button:active { transform: translateY(1px); }

/* One primary action per pane, so the eye knows where to go first. */
button.primary {
  border-color: transparent;
  background: var(--accent);
  color: light-dark(#fff, #10203a);
  font-weight: 600;
}
button.primary:hover { background: color-mix(in srgb, var(--accent) 85%, currentColor); }

/* --- dialogs ------------------------------------------------------------ */

dialog {
  /* Without this, `width` is the CONTENT box: a dialog asking for 94vw ends up
     94vw PLUS its padding and border, and the page grows a horizontal
     scrollbar it can never justify. */
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-radius: .6rem;
  background: var(--panel);
  color: inherit;
  padding: 1rem 1.1rem;
  max-width: 26rem;
  width: calc(100% - 2rem);
}
dialog::backdrop { background: rgb(0 0 0 / .45); }
dialog h3 { margin: 0 0 .4rem; font-size: 1rem; }
dialog p { margin: 0; color: var(--muted); font-size: .9rem; }
dialog input { margin-top: .6rem; }

.tools { display: flex; gap: .3rem; flex: none; }

/* A dialog that holds a document rather than a question: as wide as the app
   itself, and deliberately NOT as tall as the window — a panel that reaches
   both edges reads as a page that replaced the app rather than something
   sitting on top of it. */
dialog.wide {
  max-width: none;
  width: min(96vw, 78rem);
  padding: 1.2rem 1.6rem;
}
dialog.wide .row { align-items: center; margin: 0 0 .7rem; }
dialog.wide .row h3 { flex: 1; margin: 0; font-size: 1.05rem; }
dialog.wide .row input { flex: 1; max-width: 20rem; }

.doc {
  max-height: min(58vh, 32rem);
  overflow-y: auto;
  padding-right: .5rem;
}
/* The reference's rows have a fixed first column, so a narrow window has to be
   able to scroll them sideways. Prose never does. */
.doc:not(.prose) {
  overflow-x: auto;
  /* A FIXED height, not a maximum: filtering must not resize the dialog under
     the search box you are typing in. */
  height: min(58vh, 32rem);
}
.prose { overflow-x: hidden; }

/* The predicate reference: one line per predicate, so a filtered list reads as
   a list and not as a wall. */
.doc h4 {
  position: sticky;          /* the category stays visible while its entries scroll */
  top: 0;
  background: var(--panel);
  margin: 1.3rem 0 .4rem;
  padding: .3rem 0;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
}
.doc h4:first-child { margin-top: 0; }

/* Room to breathe: a reference is read by scanning down one column and across
   to the other, which a tight list defeats. */
.doc-entry {
  display: flex;
  gap: 1.2rem;
  padding: .35rem .4rem;
  align-items: baseline;
  border-radius: .25rem;
}
.doc-entry:hover { background: var(--field); }
.doc-entry code {
  font: 12.5px/1.5 var(--mono);
  color: inherit;
  flex: none;
  min-width: 21rem;
}
.doc-entry span { color: var(--muted); font-size: .9rem; }
/* A library whose last compile had something to say. Marked in the list
   because that is where someone goes looking for a library to use. One that
   will not compile is not usable at all, so it carries the stronger mark. */
.doc-entry span.library-note { color: inherit; font-style: italic; }
.doc-entry span.library-broken { color: var(--error); }
@media (max-width: 52rem) {
  .doc-entry { display: block; padding-bottom: .5rem; }
  .doc-entry code { min-width: 0; }
}
.doc-empty { color: var(--muted); font-style: italic; padding: .6rem 0; }

.hint-block { color: var(--muted); font-size: .86rem; margin: 0 0 .6rem; }
.hint-block code { font: 12px var(--mono); }

/* A labelled field in a dialog: the label above what it names. */
.field { display: block; margin-top: .7rem; font-size: .86rem; color: var(--muted); }
.field input, .field select { margin-top: .2rem; }

/* A file open from a library rather than from the workspace. */
.file.lib { border-style: dashed; }

/* The guide reads as prose. It keeps a measure — a line the full width of a
   wide panel is one the eye loses its place on — but a generous one, so the
   panel is not mostly empty around it. */
.prose { max-width: 68rem; margin-inline: auto; }
.prose p { color: inherit; margin: .55rem 0; line-height: 1.6; }
.prose h4 {
  position: static;
  background: none;
  border: 0;
  margin: 1.4rem 0 .2rem;
  font-size: .78rem;
  color: var(--accent);
}
.prose h4:first-child { margin-top: 0; }
.prose h5 {
  margin: 1rem 0 .1rem;
  font-size: .82rem;
  font-weight: 600;
  color: inherit;
}
.prose ul { margin: .35rem 0 .55rem; padding-left: 1.3rem; }
.prose li { margin: .2rem 0; line-height: 1.55; }
/* The keyboard-shortcut list reads as rows, not bullets. */
.prose ul.keys { list-style: none; padding-left: 0; }
.prose ul.keys li { margin: .3rem 0; }
.prose code { font: 12px var(--mono); }
.prose pre {
  font: 12px/1.5 var(--mono);
  background: var(--field);
  border: 1px solid var(--line);
  border-radius: .4rem;
  padding: .6rem .75rem;
  /* Wraps rather than scrolls: a sample you have to drag sideways to finish
     reading is a sample nobody finishes reading. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-width: 100%;
}
.prose kbd {
  font: 11px var(--mono);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: .25rem;
  padding: 0 .3rem;
}
.prose a { color: var(--accent); }
.fineprint { font-size: .82rem; color: var(--muted); margin-top: 1.2rem; }

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

/* Something is being worked on. The page is not frozen — the search runs on
   another thread — so the only thing missing is saying so. */
body.busy .status { color: var(--accent); }
body.busy #consult, body.busy #libraries { opacity: .6; pointer-events: none; }

/* --- debug mode ---
   One body class is the whole switch. Normal mode shows NONE of this: the
   gutter, the toolbar and the pane all hang off .debug-mode, and the shell
   around the editor is an unstyled wrapper without it. */

.debug-mode #debug-toggle { color: var(--accent); border-color: var(--accent); }

.editor-shell { position: relative; }

/* The line-number column — always there, in both modes. Debug mode adds the
   breakpoint dots and the position markers on top of it. */
#gutter {
  position: absolute;
  /* Inside the editor's own border, over its widened left padding. */
  left: 1px; top: 1px; bottom: 1px;
  width: 2.4rem;
  overflow: hidden;
  border-radius: .4rem 0 0 .4rem;
  background: color-mix(in srgb, currentColor 4%, transparent);
  border-right: 1px solid var(--line);
  z-index: 1;
}
.debug-mode #gutter { cursor: pointer; }
.editor { padding-left: 2.9rem; }

#gutter-lines { position: relative; will-change: transform; }
.gutter-row {
  position: absolute; left: 0; width: 100%;
  box-sizing: border-box;
  display: flex; align-items: center; justify-content: flex-end;
  padding-right: .45rem;
  font: 10.5px var(--mono);
  color: color-mix(in srgb, currentColor 38%, transparent);
  user-select: none;
}
.gutter-row::before {
  content: '';
  position: absolute;
  left: .3rem; top: 50%;
  width: .6rem; height: .6rem;
  /* transform, not a fractional negative margin: margins round to layout
     pixels and the dot landed one lower than the hover preview; border-box
     keeps the hollow variants the same size as the solid dot. */
  transform: translateY(-50%);
  box-sizing: border-box;
  border-radius: 50%;
}
/* Only where there is NO dot yet: the preview outranked the real dot by
   specificity, so a just-set breakpoint looked washed out under the mouse. */
.debug-mode .gutter-row:hover:not(.bp)::before { background: color-mix(in srgb, var(--error) 40%, transparent); }
.gutter-row.bp::before { background: var(--error); }
/* Placed but not attached to any compiled code (not consulted yet, or a line
   with nothing on it): shown hollow, the pending-breakpoint convention. */
.gutter-row.bp.unbound::before { background: none; border: 2px solid var(--error); }
/* The stop's line and the SELECTED frame's line: the arrow replaces the
   number (both would not fit), solid accent for where the machine IS,
   hollow green for the frame being looked at — the VS convention. */
.gutter-row.current, .gutter-row.frame { color: transparent; }
.gutter-row.current::after, .gutter-row.frame::after {
  position: absolute;
  right: .3rem; top: 50%;
  transform: translateY(-50%);
  font-size: .6rem;
}
.gutter-row.current::after { content: '▶'; color: var(--accent); }
.gutter-row.frame::after { content: '▷'; color: var(--answer); }

#debug-toolbar { display: none; }
.debug-mode #debug-toolbar {
  display: flex;
  gap: .4rem;
  align-items: center;
  margin-bottom: .5rem;
}
#debug-toolbar button { font-size: .82rem; padding: .3rem .6rem; }
#debug-toolbar button:disabled { opacity: .45; }

/* The bottom half of the answers pane while debugging: one tab at a time —
   the stack, the locals, the watches — so the page never needs to scroll to
   see them. */
.debug-tabs { display: none; }
/* A dock with no views collapses even in debug mode: the editor (left) or
   the transcript (right) takes the space back. */
/* The 40% is only the DEFAULT share: dragging the .dock-resize strip sets an
   inline flex-basis over it (layout.js), which is also what a reload restores. */
.debug-mode .debug-tabs:not(.empty) {
  display: flex;
  flex-direction: column;
  flex: 0 0 40%;
  min-height: 8rem;
  margin-top: .3rem;
}
.tab-bar { display: flex; gap: .3rem; flex: none; margin-bottom: .4rem; align-items: center; }
.tab-strip { display: flex; gap: .3rem; flex: 1 1 auto; min-width: 0; }
.tab-bar button { font-size: .78rem; padding: .22rem .7rem; color: var(--muted); }
.tab-bar button.active { color: var(--accent); border-color: var(--accent); }
.tab-bar .tab-move { flex: none; padding: .22rem .45rem; }
.tab-panel { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
.tab-panel[hidden] { display: none; }

.debug-list {
  font: 12px/1.6 var(--mono);
  border: 1px solid var(--line);
  border-radius: .4rem;
  background: var(--field);
  flex: 1 1 0;
  min-height: 5rem;
  overflow: auto;
  padding: .3rem 0;
}
.debug-row { padding: 0 .6rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.debug-row.selected { background: color-mix(in srgb, var(--accent) 18%, transparent); }
#debug-stack .debug-row { cursor: pointer; }
#debug-stack .debug-row:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.debug-row.residual { color: var(--accent); }
.debug-row.muted { color: var(--muted); }
/* The query moved on: the last stop's stack stays readable but visibly past. */
.debug-tabs.stale .debug-list { opacity: .55; }

/* Breakpoint variants. A condition marks the dot with a hole ring tint; a
   logpoint is a different thing (it never stops) so it changes colour. */
.gutter-row.bp.conditional::before {
  background: var(--error);
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--error) 35%, white);
}
.gutter-row.bp.log::before { background: var(--accent); }
.gutter-row.bp.log.unbound::before { background: none; border-color: var(--accent); }

#watch-form { display: flex; gap: .35rem; margin-top: .4rem; }
#watch-form input { flex: 1; min-width: 0; font: 12px var(--mono); }
#watch-form button { font-size: .82rem; padding: .3rem .6rem; }
.watch-goal { color: inherit; }
.watch-result { color: var(--muted); }
.watch-row { display: flex; gap: .4rem; align-items: baseline; }
.watch-row .watch-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.watch-remove {
  border: 0; background: none; color: var(--muted);
  cursor: pointer; font-size: .8rem; padding: 0 .15rem;
}
.watch-remove:hover { color: var(--error); }

/* --- the app fills the viewport (wide screens) ---
   Everything visible at once, no page scroll: the transcript, the editor and
   the debug tabs scroll INSIDE their boxes. Narrow screens keep the normal
   flowing page — a stacked layout inside a fixed viewport would leave every
   pane a sliver. */
@media (min-width: 62.01rem) {
  html, body { height: 100%; }
  body {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: .9rem 1rem 1rem;
  }
  header { flex: none; margin-bottom: .8rem; }
  .panes { flex: 1 1 0; min-height: 0; }
  .pane { overflow: hidden; }
  /* The editor takes the slack on its side, as the transcript does on its
     own — the fixed height only exists for the flowing (narrow) layout. */
  .editor-shell {
    flex: 1 1 0;
    min-height: 8rem;
    display: flex;
    flex-direction: column;
  }
  .editor { flex: 1 1 0; height: auto; min-height: 0; }
}

/* The Immediate tab: the conversation with the suspended query. */
pre#immediate-log { margin: 0; white-space: pre-wrap; word-break: break-word; }
#immediate-log .query { color: var(--muted); }
#immediate-log .answer { color: var(--answer); }
#immediate-log .error { color: var(--error); }
#immediate-form { display: flex; gap: .35rem; margin-top: .4rem; }
#immediate-form input { flex: 1; min-width: 0; font: 12px var(--mono); }
#immediate-form button { font-size: .82rem; padding: .3rem .6rem; }

/* Stack rows: the goal on the left, where-it-is pinned to the right — the
   alignment a stack is read by. */
.stack-row { display: flex; gap: .8rem; align-items: baseline; }
.stack-goal { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.stack-where { flex: none; color: var(--muted); font-size: 11px; }

/* DISABLED breakpoint: kept but not armed — hollow grey, after the hollow-red
   unbound rule so it wins when both would apply. */
.gutter-row.bp.disabled::before {
  background: none;
  border: 2px solid var(--muted);
}

/* The gutter's right-click menu. */
.gutter-menu {
  position: fixed;
  z-index: 50;
  min-width: 13rem;
  padding: .25rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: .45rem;
  box-shadow: 0 6px 22px color-mix(in srgb, currentColor 18%, transparent);
  display: flex;
  flex-direction: column;
}
.gutter-menu button {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  justify-content: space-between;
  border: 0;
  background: none;
  text-align: left;
  font-size: .85rem;
  padding: .35rem .6rem;
  border-radius: .3rem;
}
.gutter-menu button:hover:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.gutter-menu button:disabled { color: var(--muted); }
.gutter-menu kbd {
  font: 10.5px var(--mono);
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: .25rem;
  padding: 0 .3rem;
}
