/* ==========================================================================
   GRIDI — Swiss International Typographic Style.
   Flush-left, uppercase micro-labels on a wide track, heavy rules, a strict
   modular grid, and four flat colours. No gradients, no shadows, no radii.
   ========================================================================== */

:root,
.gridi-root {
  --paper: #ffffff;
  --paper-2: #f0f0f0;
  --ink: #111111;
  --ink-soft: #6b6862;
  --red: #e1251b;
  --blue: #1b3fd8;
  --yellow: #ffc500;
  --rule: #111111;
  --grid-fine: rgba(17, 17, 17, 0.13);
  --grid-beat: rgba(17, 17, 17, 0.22);
  --grid-module: rgba(17, 17, 17, 0.34);
  --canvas: #fafafa;

  --rule-w: 2px;
  --unit: 8px;
  --font: "Helvetica Neue", Helvetica, Inter, Arial, "Liberation Sans", sans-serif;
  --micro: 600 10px/1 var(--font);
  --track: 0.14em;
}

/* The third selector is for gridi's own page, where the attribute goes on
   <html> and the app is a `.gridi-root` inside it: without it the light block
   above — which the mount matches too — redefines the tokens on the app itself
   and wins over anything it would have inherited, and dark mode reaches the
   canvas and nothing around it. The rule cannot cross into an embed's shadow
   root, which is exactly right: there the mount carries its own attribute and
   the host page's theme is none of gridi's business. */
:root[data-theme="dark"],
.gridi-root[data-theme="dark"],
[data-theme="dark"] .gridi-root {
  --paper: #0f0f0f;
  --paper-2: #1a1a1a;
  --ink: #f5f5f5;
  --ink-soft: #8d8a84;
  --red: #ff3b2f;
  --blue: #5470ff;
  --yellow: #ffd02a;
  --rule: #f5f5f5;
  --grid-fine: rgba(245, 245, 245, 0.11);
  --grid-beat: rgba(245, 245, 245, 0.19);
  --grid-module: rgba(245, 245, 245, 0.3);
  --canvas: #131313;
}

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

/* Layout rules below set `display`, which would otherwise out-specify the
   hidden attribute and leave conditional inspector rows on screen. */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  overflow: hidden;
}

/* The mount as well as the page: colour and font are inherited properties, and
   inheritance crosses a shadow boundary even though nothing else does. With
   only `body` here an embedded copy took its text colour from whatever page it
   was sitting in — which is how the fields came to be set in the host's black
   on gridi's near-black, and to be legible only by luck anywhere else. */
body,
.gridi-root {
  font: 400 12px/1.4 var(--font);
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, input, select, textarea { font-family: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; }
::selection { background: var(--yellow); color: #111; }

.micro {
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
}

/* --------------------------------------------------------------- shell --- */

/* The shell is whatever gridi was mounted into: its own page's #app, or a
   container in somebody's note. So the rule goes on the class the app puts on
   its mount, and the height is that container's rather than the window's — a
   note gives gridi a box, and 100vh inside a box is the wrong window. It used
   to overflow the box by three hundred pixels, with the footer somewhere below
   the border.

   `container-type` makes the same box the reference for the widths further
   down. The layout has to answer to the room the app actually has, which
   embedded is never the viewport's. */
.gridi-root {
  display: flex;
  flex-direction: column;
  height: 100%;
  container-type: inline-size;

  /* The two rails, as values, because both of them collapse and the widths
     have to be answerable from three places at once: the layout below, the
     narrow steps at the end of this file, and whichever of them is shut. */
  --rail-w: 178px;
  --pane-w: 272px;
}

.head,
.transport,
.foot { flex: 0 0 auto; }

/* Off-screen but read out: the disclosure buttons are a chevron and nothing
   else, and a chevron does not say what it opens. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------------------------------------------------------------- head --- */

.head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  border-bottom: var(--rule-w) solid var(--rule);
  background: var(--paper);
}

/* Both rows of the header, so the lockup is the height of what it introduces.
   Embedded there is no lockup and the column collapses to nothing. */
.head__mark { grid-area: 1 / 1 / 3 / 2; }

.tabs {
  grid-column: 2;
  display: flex;
  border-bottom: 1px solid var(--rule);
}

.tab {
  padding: 8px 14px 7px;
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
  border-right: 1px solid var(--rule);
  background: var(--paper);
}

.tab:hover { background: var(--paper-2); }

.tab[aria-selected="true"] {
  background: var(--ink);
  color: var(--paper);
}

.panels { grid-column: 2; }

.panel {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
}

/* Two shelves: what gridi ships with, and what this browser has been asked to
   keep. Each is a labelled band of cells, one patch to a cell. */
.shelf {
  display: flex;
  align-items: stretch;
  min-width: 0;
}

.shelf + .shelf { border-top: 1px solid var(--rule); }

.shelf__label {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  width: 84px;
  padding: 0 11px;
  border-right: 1px solid var(--rule);
  color: var(--ink-soft);
}

.shelf__row {
  display: flex;
  flex-wrap: wrap;
  flex: 1 1 auto;
  min-width: 0;
}

/* The cell is not a button, because it holds two: the patch, and the one thing
   that can be done to it without opening it. */
.library__item {
  display: flex;
  align-items: stretch;
  max-width: 236px;
  border-right: 1px solid var(--rule);
  background: var(--paper);
}

.library__open {
  flex: 1 1 auto;
  min-width: 0;
  padding: 7px 11px;
  text-align: left;
  background: var(--paper);
}

.library__open:hover { background: var(--paper-2); }

.library__open b {
  display: block;
  font: 700 12px/1.1 var(--font);
  letter-spacing: 0.01em;
}

/* Two lines of it here; the whole of it on hover. */
.library__open span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  margin-top: 3px;
  font: var(--micro);
  line-height: 1.45;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}

/* What can be done to the patch in this cell, down its right-hand edge: one
   thing for a patch that ships, two for one of yours, and the same column is
   where a question puts its answers. */
.library__acts {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  border-left: 1px solid var(--rule);
}

.library__act {
  flex: 1 1 0;
  min-height: 21px;
  padding: 0 7px;
  white-space: nowrap;
  background: var(--paper);
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
}

.library__act + .library__act { border-top: 1px solid var(--rule); }
.library__act:hover { background: var(--ink); color: var(--paper); }
.library__act--off:hover { background: var(--red); color: #fff; }

/* Mid-question: the cell holds the question, or the field, and its answers. */
.library__item--asking { align-items: stretch; }

.library__ask {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  padding: 0 11px;
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
}

.library__name {
  flex: 1 1 auto;
  min-width: 0;
  align-self: center;
  margin: 0 8px;
}

.library__note {
  padding: 8px 12px;
  font: var(--micro);
  line-height: 1.5;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}

.head__mark {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 10px 16px 8px;
  border-right: var(--rule-w) solid var(--rule);
  background: var(--red);
  color: #fff;
  min-width: 140px;
}

.head__mark b {
  font: 700 26px/0.86 var(--font);
  letter-spacing: -0.035em;
}

.head__mark span {
  font: var(--micro);
  letter-spacing: var(--track);
  color: rgba(255, 255, 255, 0.85);
  margin-top: 5px;
}

.mod {
  display: flex;
  flex-direction: column;
  gap: 5px;
  justify-content: center;
  padding: 8px 11px;
  border-right: 1px solid var(--rule);
}

.mod:last-child { border-right: 0; }
.mod--grow { flex: 1; }
.mod--right { margin-left: auto; }
.mod:last-child { border-right: 0; }
.mod__row { display: flex; align-items: center; gap: 6px; }

/* Transport ---------------------------------------------------------------- */

/* The strip between the settings and the grid: what is running, on the left,
   and what it is running, on the right. A rule with controls on it rather than
   a panel — 24px is the height of a button, and the rest is the canvas's. */
.transport {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  min-height: 30px;
  border-bottom: var(--rule-w) solid var(--rule);
  background: var(--paper);
}

/* On the line, not stacked under a label: the strip is one control tall. */
.transport .mod {
  flex-direction: row;
  align-items: baseline;
  gap: 7px;
  padding: 0 12px;
}

.transport .readout { font: 700 17px/1 var(--font); }

/* The library's tab is the patch's: what this one is called and what can be
   done to it, over the shelf of the ones that ship. */
.panel--library { flex-direction: column; }

.patch {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 11px;
  border-bottom: 1px solid var(--rule);
}

.patch__name { width: 148px; }

.patch__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.btn-play {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  font: 700 12px/1 var(--font);
  letter-spacing: 0.08em;
  background: var(--ink);
  color: var(--paper);
  min-width: 92px;
}

.btn-play::before {
  content: "";
  width: 0;
  height: 0;
  border-left: 10px solid currentColor;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
}

.btn-play[aria-pressed="true"] { background: var(--red); color: #fff; }
.btn-play[aria-pressed="true"]::before {
  border: 0;
  width: 9px;
  height: 10px;
  background: currentColor;
}

/* Big readouts ------------------------------------------------------------- */

.readout {
  font: 700 30px/0.82 var(--font);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  gap: 4px;
}

.readout small {
  font: 600 11px/1 var(--font);
  letter-spacing: var(--track);
  color: var(--ink-soft);
}

.bpm-input {
  font: 700 30px/0.82 var(--font);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  width: 4ch;
  background: none;
  border: 0;
  border-bottom: var(--rule-w) solid var(--rule);
  padding: 0 0 2px;
  color: var(--ink);
}

.bpm-input:focus { outline: 0; background: var(--yellow); color: #111; }

/* Controls ----------------------------------------------------------------- */

.field {
  display: flex;
  align-items: center;
  height: 24px;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper);
}

select.field,
input.field {
  padding: 0 6px;
  font: 600 11px/1 var(--font);
  letter-spacing: 0.04em;
  background: var(--paper);
  border-radius: 0;
  appearance: none;
  min-width: 0;
}

select.field {
  padding-right: 18px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 11px) 10px, calc(100% - 6px) 10px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

input.field[type="text"],
input.field[type="number"] { text-transform: none; }
.field:focus { outline: 0; background: var(--yellow); color: #111; }

.btn {
  height: 24px;
  padding: 0 10px;
  border: var(--rule-w) solid var(--rule);
  font: 600 10px/1 var(--font);
  letter-spacing: var(--track);
  background: var(--paper);
  color: var(--ink);
}

.btn { white-space: nowrap; }
.btn:hover { background: var(--ink); color: var(--paper); }
.btn[aria-pressed="true"] { background: var(--blue); border-color: var(--blue); color: #fff; }
.btn--red:hover { background: var(--red); border-color: var(--red); color: #fff; }
.btn--ghost { border-color: var(--ink-soft); }

.seg { display: flex; }
.seg > button {
  height: 24px;
  padding: 0 8px;
  white-space: nowrap;
  border: var(--rule-w) solid var(--rule);
  border-left-width: 0;
  font: 600 10px/1 var(--font);
  letter-spacing: 0.08em;
  background: var(--paper);
}
.seg > button:first-child { border-left-width: var(--rule-w); }
.seg > button[aria-pressed="true"] { background: var(--ink); color: var(--paper); }
.seg > button:hover:not([aria-pressed="true"]) { background: var(--paper-2); }

/* Inside an inspector row the control column is fixed, so segments share it out
   between them. A four-way choice then fits as readily as a two-way one. */
.row__control .seg { flex: 1; min-width: 0; }
.row__control .seg > button { flex: 1; min-width: 0; padding: 0 4px; }

#slot-picker > button { padding: 0 7px; }

/* A slot button shows at a glance whether a device sits behind it. */
.seg > button.slot--bound { border-bottom-width: 4px; }
.seg > button[aria-pressed="true"].slot--bound { border-bottom-color: var(--blue); }
.btn[disabled] { opacity: 0.4; cursor: default; }
.btn[disabled]:hover { background: var(--paper); color: var(--ink); }

/* Range: a bar graph, not a slider ---------------------------------------- */

input[type="range"] {
  appearance: none;
  width: 100%;
  height: 16px;
  background: none;
  cursor: ew-resize;
}

input[type="range"]::-webkit-slider-runnable-track {
  height: 14px;
  background: var(--paper-2);
  border: var(--rule-w) solid var(--rule);
}

input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  width: 8px;
  height: 14px;
  margin-top: -2px;
  background: var(--ink);
  border: 0;
}

input[type="range"]::-moz-range-track {
  height: 14px;
  background: var(--paper-2);
  border: var(--rule-w) solid var(--rule);
}

input[type="range"]::-moz-range-thumb {
  width: 8px;
  height: 14px;
  border: 0;
  border-radius: 0;
  background: var(--ink);
}

input[type="checkbox"] {
  appearance: none;
  width: 18px;
  height: 18px;
  border: var(--rule-w) solid var(--rule);
  background: var(--paper);
  display: grid;
  place-items: center;
  cursor: pointer;
}

input[type="checkbox"]:checked { background: var(--ink); }
input[type="checkbox"]:checked::after {
  content: "";
  width: 8px;
  height: 8px;
  background: var(--yellow);
}

/* --------------------------------------------------------------- body ---- */

.body {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr) var(--pane-w);
  /* An implicit row is sized by its content, which for a rail of twelve chips
     is taller than the shell has to give: the row has to be told to take the
     height it is in and let its items scroll inside it. */
  grid-template-rows: minmax(0, 1fr);
  min-height: 0;
}

/* Palette rail ------------------------------------------------------------- */

.rail {
  border-right: var(--rule-w) solid var(--rule);
  overflow-y: auto;
  background: var(--paper);
}

.rail__head,
.pane__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 7px;
  border-bottom: var(--rule-w) solid var(--rule);
  font: var(--micro);
  letter-spacing: var(--track);
}

/* Whatever is selected sits at the far end of the inspector's own head. */
.pane__head #sel-kind { margin-left: auto; }

/* A chevron in a box: the one control that opens a rail and shuts it again.
   Down is open and right is shut, the way a disclosure triangle has always
   read; the inspector's points at the edge it folds against instead. */
.disclose {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
}

.disclose:hover { background: var(--paper-2); }

.chev {
  width: 6px;
  height: 6px;
  margin: -2px 0 0 -2px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
}

.disclose[aria-expanded="true"] .chev {
  margin: -2px 0 0 0;
  transform: rotate(45deg);
}

.disclose--pane[aria-expanded="true"] .chev {
  margin: -2px 0 0 -2px;
  transform: rotate(-45deg);
}

.disclose--pane[aria-expanded="false"] .chev {
  margin: -2px 0 0 2px;
  transform: rotate(135deg);
}

.rail__head b, .pane__head b { font-weight: 700; color: var(--ink); }

.chip {
  display: grid;
  grid-template-columns: 26px 1fr;
  align-items: stretch;
  width: 100%;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  background: var(--paper);
}

.chip:hover { background: var(--paper-2); }
.chip[aria-pressed="true"] { background: var(--ink); }
.chip[aria-pressed="true"] .chip__name { color: var(--paper); }
.chip[aria-pressed="true"] .chip__role { color: var(--paper); opacity: 0.7; }

.chip__swatch {
  border-right: 1px solid var(--rule);
  display: grid;
  place-items: center;
}

.chip__body { padding: 7px 10px 8px; }

.chip__name {
  display: block;
  font: 700 12px/1.1 var(--font);
  letter-spacing: 0.01em;
}

.chip__role {
  display: block;
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
  margin-top: 3px;
}

.rail__note {
  padding: 10px 12px;
  font: var(--micro);
  line-height: 1.5;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}

/* Stage -------------------------------------------------------------------- */

.stage { position: relative; min-width: 0; background: var(--canvas); }
#canvas { display: block; width: 100%; height: 100%; touch-action: none; }

/* The grid takes focus on a click, which is how an embedded copy is handed the
   keyboard. Say so to whoever tabbed here, and to nobody who clicked: the
   click marks the canvas on its way in. */
#canvas:focus { outline: none; }
#canvas:focus-visible:not([data-pointer]) {
  outline: var(--rule-w) solid var(--blue);
  outline-offset: -2px;
}

.stage__hint {
  position: absolute;
  left: 14px;
  bottom: 12px;
  display: flex;
  gap: 14px;
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
  pointer-events: none;
}

.stage__hint b { color: var(--ink); font-weight: 700; }

.stage__placing {
  position: absolute;
  left: 14px;
  top: 12px;
  padding: 6px 10px;
  background: var(--blue);
  color: #fff;
  font: var(--micro);
  letter-spacing: var(--track);
  pointer-events: none;
}

.stage__placing[hidden] { display: none; }

/*
 * The drop target. A dragged patch covers the whole stage rather than aiming
 * at a spot, because opening one replaces what is there -- there is no
 * position to get right, so the target should not pretend otherwise.
 */
.stage__drop {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  padding-left: 48px;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  box-shadow: inset 0 0 0 4px var(--red);
  pointer-events: none;
}

.stage__drop b {
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.stage__drop span {
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
}

.stage__drop[hidden] { display: none; }

/* The library. A short list, so it is a panel in the corner of the stage
   rather than anything that takes the screen over. */
.sheet {
  position: absolute;
  left: 14px;
  top: 12px;
  z-index: 4;
  width: min(360px, calc(100% - 28px));
  background: var(--paper);
  border: var(--rule-w) solid var(--rule);
}

.sheet__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 9px 12px;
  border-bottom: var(--rule-w) solid var(--rule);
  font: var(--micro);
  letter-spacing: var(--track);
}

.sheet__close {
  border: 0;
  background: none;
  padding: 0 2px;
  font-size: 17px;
  line-height: 1;
  color: var(--ink);
  cursor: pointer;
}

.sheet__body { max-height: 320px; overflow-y: auto; }

.sheet__note { padding: 10px 12px; font: var(--micro); letter-spacing: var(--track); color: var(--ink-soft); }

.sheet__row {
  display: grid;
  grid-template-columns: 62px 1fr;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--grid-module);
}

.sheet__row:last-child { border-bottom: 0; }
.sheet__row > span { font: var(--micro); letter-spacing: var(--track); color: var(--ink-soft); }
.sheet__row select { width: 100%; }

.sheet__note a { color: var(--ink); }

.sheet__link {
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  text-decoration: underline;
  cursor: pointer;
}

.sheet[hidden] { display: none; }

/* Inspector ---------------------------------------------------------------- */

.pane {
  border-left: var(--rule-w) solid var(--rule);
  overflow-y: auto;
  background: var(--paper);
  display: flex;
  flex-direction: column;
}

.pane__body { flex: 1; }

.pane__title {
  padding: 12px 12px 11px;
  border-bottom: var(--rule-w) solid var(--rule);
}

.pane__title h2 {
  font: 700 19px/1 var(--font);
  letter-spacing: -0.02em;
}

.pane__title p {
  margin-top: 6px;
  font: var(--micro);
  line-height: 1.5;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}

.pane__empty { padding: 16px 12px; }

.group {
  padding: 7px 12px 6px;
  border-bottom: 1px solid var(--rule);
  font: var(--micro);
  letter-spacing: var(--track);
  background: var(--paper-2);
}

.row {
  display: grid;
  grid-template-columns: 74px 1fr;
  gap: 8px;
  align-items: center;
  padding: 7px 12px;
  border-bottom: 1px solid var(--grid-module);
}

.row__label {
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
}

.row__control { display: flex; align-items: center; gap: 6px; min-width: 0; }
.row__control > select,
.row__control > input[type="text"] { flex: 1; }
.row__control > input[type="range"] { flex: 1; }

.row__value {
  font: 600 11px/1 var(--font);
  font-variant-numeric: tabular-nums;
  min-width: 42px;
  text-align: right;
}

.row__hint {
  grid-column: 2;
  font: var(--micro);
  line-height: 1.45;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  padding-top: 2px;
}

.row--readout .row__value {
  text-align: left;
  font: 700 13px/1 var(--font);
  color: var(--red);
  letter-spacing: 0.02em;
}

.stepper { display: flex; align-items: center; }
.stepper button {
  width: 22px;
  height: 24px;
  border: var(--rule-w) solid var(--rule);
  font: 700 13px/1 var(--font);
}
.stepper button:hover { background: var(--ink); color: var(--paper); }
.stepper input {
  width: 46px;
  height: 24px;
  text-align: center;
  border: var(--rule-w) solid var(--rule);
  border-left: 0;
  border-right: 0;
  background: var(--paper);
  font: 600 12px/1 var(--font);
  font-variant-numeric: tabular-nums;
}
.stepper input:focus { outline: 0; background: var(--yellow); color: #111; }

/* Channel editor ----------------------------------------------------------- */

.chan-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
  padding: 8px 12px 10px;
  border-bottom: 1px solid var(--grid-module);
}

.chan-grid button {
  height: 22px;
  border: 1px solid var(--rule);
  font: 600 10px/1 var(--font);
  font-variant-numeric: tabular-nums;
  background: var(--paper);
}

.chan-grid button[aria-pressed="true"] { background: var(--blue); border-color: var(--blue); color: #fff; }

.chan-list { padding: 0 12px 8px; }

.chan-item {
  display: grid;
  grid-template-columns: 34px 24px 1fr 1fr;
  gap: 6px;
  align-items: end;
  padding: 6px 0;
  border-bottom: 1px solid var(--grid-module);
}

.chan-item label {
  display: grid;
  gap: 3px;
  min-width: 0;
}

.chan-item b {
  font: 700 11px/1 var(--font);
  background: var(--blue);
  color: #fff;
  padding: 6px 0;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.chan-item select {
  height: 22px;
  min-width: 0;
  padding: 0 2px;
  border: 1px solid var(--rule);
  background: var(--paper);
  font: 700 10px/1 var(--font);
  appearance: none;
  text-align: center;
}

.chan-item select:focus { outline: 0; background: var(--yellow); color: #111; }

.chan-item input {
  width: 100%;
  min-width: 0;
  height: 22px;
  border: 1px solid var(--rule);
  background: var(--paper);
  padding: 0 4px;
  font: 600 10px/1 var(--font);
  font-variant-numeric: tabular-nums;
}

.chan-item input:focus { outline: 0; background: var(--yellow); color: #111; }

.chan-item span {
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
}

.pane__actions {
  display: flex;
  gap: 6px;
  padding: 10px 12px;
  border-top: var(--rule-w) solid var(--rule);
}

/* -------------------------------------------------------------- guard ---- */

.guard {
  display: flex;
  align-items: stretch;
  border-bottom: var(--rule-w) solid var(--rule);
  background: var(--yellow);
  color: #111;
}

.guard__mark {
  display: flex;
  align-items: center;
  padding: 0 14px;
  background: #111;
  color: var(--yellow);
  font: 700 11px/1 var(--font);
  letter-spacing: var(--track);
}

.guard__body { flex: 1; padding: 9px 14px 10px; min-width: 0; }

.guard__body b {
  display: block;
  font: 700 13px/1.2 var(--font);
  letter-spacing: 0.01em;
}

.guard__body p {
  margin-top: 4px;
  font-size: 11.5px;
  line-height: 1.45;
  max-width: 96ch;
}

.guard__scope { font-weight: 700; }

.guard__close {
  width: 40px;
  border-left: 1px solid rgba(17, 17, 17, 0.25);
  font: 400 20px/1 var(--font);
  color: #111;
}

.guard__close:hover { background: #111; color: var(--yellow); }

/* --------------------------------------------------------------- foot ---- */

.foot {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 14px;
  height: 30px;
  border-top: var(--rule-w) solid var(--rule);
  background: var(--paper);
  font: var(--micro);
  letter-spacing: var(--track);
  color: var(--ink-soft);
  overflow: hidden;
  white-space: nowrap;
}

.foot b { color: var(--ink); font-weight: 700; }
.foot__sep { width: 1px; height: 16px; background: var(--rule); opacity: 0.4; }
.foot__log { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.foot__dot { width: 8px; height: 8px; background: var(--ink-soft); }

.foot__level {
  display: flex;
  align-items: center;
  gap: 7px;
  flex: none;
}

.foot__level input[type="range"] { width: 84px; height: 14px; }
.foot__level input[type="range"]::-webkit-slider-runnable-track { height: 12px; }
.foot__level input[type="range"]::-webkit-slider-thumb { height: 12px; margin-top: -2px; }
.foot__level input[type="range"]::-moz-range-track { height: 12px; }
.foot__level input[type="range"]::-moz-range-thumb { height: 12px; }
.foot__dot[data-on="true"] { background: var(--red); }

/* Which way round the app is: an app-wide switch, on the app-wide strip, with
   the level and the count of what is on the grid. Sized for the 30px it sits
   in rather than for a panel. */
.foot__theme {
  height: 20px;
  padding: 0 8px;
  border-width: 1px;
}

/* --------------------------------------------------------------- misc ---- */

.warn {
  padding: 8px 12px;
  background: var(--yellow);
  color: #111;
  font: var(--micro);
  line-height: 1.5;
  letter-spacing: 0.06em;
  border-bottom: var(--rule-w) solid var(--rule);
}

.warn[hidden] { display: none; }

/* ------------------------------------------------------- shut and open --- */

/* The palette, down to its colours.
   A node type is a colour and a glyph before it is a word — the glyph is what
   is drawn on the node itself — so the rail can say all of it in 44px and hand
   the rest to the canvas. The names come back with the chevron, and which way
   it was left is remembered. */

.gridi-root[data-rail="icons"] { --rail-w: 44px; }

.gridi-root[data-rail="icons"] .rail__label,
.gridi-root[data-rail="icons"] .rail__note,
.gridi-root[data-rail="icons"] .chip__body { display: none; }

.gridi-root[data-rail="icons"] .rail__head {
  justify-content: center;
  padding: 6px 0;
}

.gridi-root[data-rail="icons"] .chip {
  grid-template-columns: 1fr;
  height: 36px;
}

.gridi-root[data-rail="icons"] .chip__swatch { border-right: 0; }

/* The inspector, folded against the right edge.
   Its head turns on its side and stays: something has to be left to click, and
   a strip of type down the edge says what will come back. */

.gridi-root[data-pane="min"] { --pane-w: 30px; }

.gridi-root[data-pane="min"] .pane__body,
.gridi-root[data-pane="min"] .pane__actions,
.gridi-root[data-pane="min"] .pane__head #sel-kind { display: none; }

.gridi-root[data-pane="min"] .pane__head {
  flex-direction: column;
  gap: 10px;
  padding: 6px 3px;
  border-bottom: 0;
}

.gridi-root[data-pane="min"] .pane__label { writing-mode: vertical-rl; }

/* Narrower, in three steps, and the stage is what each of them protects: the
   canvas is the app, and every pixel the chrome gives back goes to it. */

@container (max-width: 1080px) {
  .gridi-root { --rail-w: 132px; --pane-w: 236px; }
}

/* Two rails and a canvas do not fit across a tablet, let alone a phone: at
   860px the three columns leave the stage narrower than a single node. The
   inspector is the one that can go under the stage and still be looking at
   the thing it inspects, so it goes there. */
@container (max-width: 860px) {
  .body {
    grid-template-columns: var(--rail-w) minmax(0, 1fr);
    /* What the inspector asks for, up to two fifths of the body: a row of its
       own would stand half empty on a bare selection and swallow the stage on
       a voice. `fit-content` is the one that does both. */
    grid-template-rows: minmax(0, 1fr) fit-content(40%);
  }

  .pane {
    grid-column: 1 / -1;
    border-left: 0;
    border-top: var(--rule-w) solid var(--rule);
  }

  /* Folded, the inspector is a bar along the bottom rather than a strip down
     the side, so its head stays the way round it started. */
  .gridi-root[data-pane="min"] .pane__head {
    flex-direction: row;
    padding: 6px 10px 6px 7px;
  }

  .gridi-root[data-pane="min"] .pane__label { writing-mode: horizontal-tb; }
  .gridi-root[data-pane="min"] .pane__head #sel-kind { display: block; }

  /* Folded downwards, so it reads like the rail's: down is open, right is
     shut, rather than pointing at an edge it is no longer against. */
  .disclose--pane[aria-expanded="true"] .chev {
    margin: -2px 0 0 0;
    transform: rotate(45deg);
  }

  .disclose--pane[aria-expanded="false"] .chev {
    margin: -2px 0 0 -2px;
    transform: rotate(-45deg);
  }
}

/* A phone. The palette keeps its colours and its names and loses its roles;
   the header wraps rather than running off the side; the pointer hints along
   the bottom of the stage are describing a mouse that is not there. */
@container (max-width: 560px) {
  .gridi-root { --rail-w: 104px; }

  /* Label beside control rather than above it. Stacked, the header took two
     thirds of a phone-sized embed and left the canvas a letterbox. */
  .mod {
    flex-direction: row;
    align-items: center;
    gap: 7px;
    padding: 6px 9px;
  }

  .mod__row { flex-wrap: wrap; }
  .readout { font-size: 17px; }
  .btn-play { min-width: 80px; padding: 0 11px; }
  .chip { grid-template-columns: 20px 1fr; }
  .chip__body { padding: 6px 7px; }
  .chip__role { display: none; }
  .stage__hint { display: none; }

  /* The MIDI row is six controls wide; given the whole line it wraps into two
     tidy rows instead of a column of one button each. */
  .mod--grow { flex-basis: 100%; }

  /* The patch's controls wrap as one run rather than as a name and a block of
     buttons: `display: contents` hands the buttons to the same flex box as the
     name, so they fill each line instead of taking one of their own. */
  .patch {
    flex-wrap: wrap;
    gap: 5px;
    padding: 5px 9px;
  }

  .patch__buttons { display: contents; }
  .patch__name { flex: 1 1 118px; width: auto; }

  /* The footer clips what it cannot fit, and what it cannot fit on a phone is
     most of it. The status earns its place by truncating rather than pushing;
     the log and the node count are already on the canvas, and the two controls
     are not readable anywhere else. */
  .foot { gap: 10px; padding: 0 8px; }
  .foot__log, #counts, .foot__sep { display: none; }

  #status {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .foot__theme { margin-left: auto; }

  /* Five patches across a phone is five rows of blurb. The names fit on two
     lines between them, and the blurbs are a tap-and-hold away. */
  .library__open { padding: 6px 9px; }
  .library__open span { display: none; }
  .shelf__label { width: 62px; padding: 0 8px; }

  /* A phone gets a list rather than a wall: one patch to a line, and the shelf
     scrolls inside its own band so a long one cannot push the grid off the
     bottom of the note. */
  .library__item { max-width: none; width: 100%; }
  .shelf__row { max-height: 68px; overflow-y: auto; }
}
