:root {
  /* Фон: четыре ступени от самой тёмной к самой светлой. */
  --bg0: #101317;
  --bg1: #16191d;
  --bg2: #1b1f24;
  --bg3: #23272d;
  --void: #000;

  /* Линии: обычная и приподнятая (наведение, активная рамка). */
  --line: #2b3138;
  --line-hi: #3c444d;

  /* Текст: основной, приглушённый, совсем тихий. */
  --text: #c8ced5;
  --dim: #7d858e;
  --faint: #525a63;

  /* Смысловые. Акцент ровно один, --accent-hi — он же под курсором. */
  --accent: #e08c3c;
  --accent-hi: #f5b164;
  --err: #cc5c5c;
  --ok: #6f9a5f;
  --mod: #c9a45c;

  /* Подсветка GLSL. Приглушённая: код читают, а не разглядывают. */
  --syn-cmt: #5d6670;
  --syn-pre: #7c6aa8;
  --syn-num: #b58a5a;
  --syn-type: #6f9a8f;
  --syn-kw: #a9799f;
  --syn-fn: #7d92b8;

  /* Ритм. Один шаг на всё приложение: топбар, инспектор и таймлайн собраны
     по этим числам, а не каждый по своим. */
  --pad: 8px;
  --gap: 8px;
  --gap-sm: 6px;
  --ctl-h: 20px;
  --radius: 3px;

  --mono: ui-monospace, "JetBrains Mono", Consolas, "Liberation Mono", monospace;
  --ui: ui-sans-serif, "Segoe UI", system-ui, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg0);
  color: var(--text);
  font: 12px/1.4 var(--ui);
  overflow: hidden;
}

body {
  display: grid;
  grid-template-rows: 30px 1fr auto 22px;
  /* Колонка обязана быть ограничена окном. Без этого она считается по
     содержимому, а содержимое — канвас, который сам растёт под размер панели:
     получается положительная обратная связь, и вся сетка уезжает вправо. */
  grid-template-columns: minmax(0, 1fr);
}

#topbar, #statusbar {
  display: flex;
  align-items: center;
  gap: var(--gap);
  padding: 0 var(--pad);
  background: var(--bg2);
  border-bottom: 1px solid var(--line);
  user-select: none;
}

#statusbar {
  border-bottom: none;
  border-top: 1px solid var(--line);
  font-size: 11px;
}

.spacer { flex: 1; }

.brand {
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--accent);
}

.hint {
  color: var(--dim);
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Подсказка — единственное, чем можно жертвовать при нехватке ширины:
     кнопки обязаны остаться целыми, иначе до них не дотянуться. */
  flex: 1 1 0;
  min-width: 0;
}

#topbar button { flex: none; }

/* Переключатель языка: три кнопки встык, чтобы читались одной группой. */
#lang { display: inline-flex; flex: none; gap: 2px; margin-left: 6px; }
#lang button { padding: 0 7px; font-size: 10px; letter-spacing: 0.04em; }

/* Все кнопки приложения одной высоты и с одним радиусом: топбар, таймлайн и
   панели собирались порознь и разъезжались на два пикселя. */
button {
  height: var(--ctl-h);
  padding: 0 9px;
  font: 11px var(--ui);
  color: var(--text);
  background: var(--bg3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color 100ms, background-color 100ms, color 100ms;
}

button:hover:not(:disabled) { border-color: var(--line-hi); background: var(--bg2); }
/* Нажатие видно без анимации: фон уходит на ступень вниз. */
button:active:not(:disabled) { background: var(--bg0); border-color: var(--line-hi); }
button.active { color: var(--accent); border-color: var(--accent); }
button.active:hover:not(:disabled) { border-color: var(--accent-hi); color: var(--accent-hi); }
button:disabled {
  color: var(--faint);
  background: var(--bg2);
  border-color: var(--line);
  cursor: default;
}

/* Обводка только для клавиатуры: мышью её никто не просил. */
:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 1px;
}

main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 4px 420px;
  min-height: 0;
  min-width: 0;
}

#right {
  display: grid;
  grid-template-rows: 1fr auto;
  min-height: 0;
  min-width: 0;
  border-left: 1px solid var(--line);
}

#graph-pane, #preview-pane {
  position: relative;
  min-width: 0;
  overflow: hidden;
}

#preview-pane { background: var(--void); min-height: 0; }

/* Полноэкранное превью. Канвас тянется за панелью сам (общее правило
   canvas { width: 100%; height: 100% }), а размер буфера рендерер
   пересчитывает в каждом кадре — отдельного обработчика не нужно. */
#preview-pane:fullscreen {
  width: 100vw;
  height: 100vh;
  background: var(--void);
}

/* --- инспектор --- */

#inspector {
  max-height: 46vh;
  overflow: auto;
  padding: var(--gap-sm) var(--pad) var(--pad);
  background: var(--bg2);
  border-top: 1px solid var(--line);
  user-select: none;
}

.insp-head {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 2px 2px 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 5px;
}
.insp-head b { font-size: 12px; font-weight: 600; }
.insp-head em { font-style: normal; font-size: 10px; color: var(--dim); font-family: var(--mono); }

.insp-empty { color: var(--dim); padding: 4px 2px; font-size: 11px; }

.insp-row {
  display: grid;
  grid-template-columns: 74px 1fr auto;
  align-items: center;
  gap: var(--gap-sm);
  padding: 1px 0;
}
.insp-key {
  width: var(--ctl-h);
  height: var(--ctl-h);
  padding: 0;
  line-height: 1;
  font-size: 9px;
  color: var(--dim);
  background: none;
  border: 1px solid transparent;
}
.insp-key:hover { color: var(--accent); border-color: var(--line); }

.insp-row label {
  color: var(--dim);
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.num {
  position: relative;
  height: var(--ctl-h);
  padding: 0 7px;
  background: var(--bg3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font: 11px/18px var(--mono);
  text-align: right;
  cursor: ew-resize;
  overflow: hidden;
}
.num:hover { border-color: var(--line-hi); }
.num.dragging { border-color: var(--accent); color: var(--accent); }
.num.editing { cursor: text; padding: 0; }
.num input {
  width: 100%;
  height: calc(var(--ctl-h) - 2px);
  padding: 0 6px;
  border: none;
  outline: none;
  background: var(--bg0);
  color: var(--text);
  font: 11px var(--mono);
  text-align: right;
}

.color { display: grid; grid-template-columns: 14px 1fr 1fr 1fr; gap: 4px; align-items: center; }
.color i { height: 14px; border-radius: 2px; border: 1px solid var(--line); }

#inspector select {
  height: var(--ctl-h);
  background: var(--bg3);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font: 11px var(--ui);
  outline: none;
}

/* --- палитра --- */

#palette {
  position: fixed;
  z-index: 20;
  width: 260px;
  padding: 4px;
  background: var(--bg2);
  border: 1px solid var(--line);
  border-radius: 3px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.55);
}

#palette input {
  width: 100%;
  height: 24px;
  padding: 0 7px;
  background: var(--bg0);
  border: 1px solid var(--line);
  border-radius: 2px;
  color: var(--text);
  font: 12px var(--ui);
  outline: none;
}
#palette input:focus { border-color: var(--accent); }

.pal-list { max-height: 264px; overflow: auto; margin-top: 4px; }

.pal-item {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 7px;
  border-radius: 2px;
  cursor: pointer;
}
.pal-item.active { background: var(--bg3); }
.pal-item i { width: 3px; height: 11px; border-radius: 1px; flex: none; }
.pal-item em { margin-left: auto; font-style: normal; font-size: 10px; color: var(--dim); }
.pal-empty { padding: 5px 7px; color: var(--dim); font-size: 11px; }

canvas { display: block; width: 100%; height: 100%; }
#graph-canvas { cursor: default; }

#splitter {
  background: var(--bg2);
  cursor: col-resize;
}
#splitter:hover { background: var(--accent); }

/* Три вида сообщений различаются значком, а не только цветом: цвет читается
   не всеми и не на всяком экране. */
#status {
  font-family: var(--mono);
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}
#status::before {
  content: '·';
  color: var(--faint);
  font-weight: 600;
  flex: none;
}
#status.ok { color: var(--dim); }
#status.ok::before { content: '✓'; color: var(--ok); }
#status.err { color: var(--err); }
#status.err::before { content: '✕'; color: var(--err); }
#status.clickable { cursor: pointer; text-decoration: underline dotted; }
#stats { font-family: var(--mono); color: var(--dim); }

#rawlog {
  position: fixed;
  left: 10px;
  bottom: 28px;
  max-width: 60vw;
  max-height: 40vh;
  overflow: auto;
  margin: 0;
  padding: 8px 10px;
  background: var(--bg2);
  border: 1px solid var(--line);
  border-radius: 3px;
  font: 11px/1.5 var(--mono);
  color: var(--err);
  white-space: pre-wrap;
}

#menu {
  position: fixed;
  z-index: 10;
  min-width: 168px;
  padding: 3px;
  background: var(--bg2);
  border: 1px solid var(--line);
  border-radius: 3px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
  user-select: none;
}

.menu-item {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 7px;
  border-radius: 2px;
  cursor: pointer;
  white-space: nowrap;
}

.menu-item:hover { background: var(--bg3); }
.menu-item.disabled { color: var(--dim); cursor: default; }
.menu-item.disabled:hover { background: none; }

.menu-item i {
  width: 3px;
  height: 11px;
  border-radius: 1px;
}

.menu-item em {
  margin-left: auto;
  font-style: normal;
  font-size: 10px;
  color: var(--dim);
}

#breadcrumbs {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: 4px;
  font-size: 11px;
}

.crumb {
  background: none;
  border: 1px solid transparent;
  border-radius: 3px;
  padding: 2px 7px;
  color: var(--dim);
  font: inherit;
  cursor: pointer;
}

.crumb:hover { color: var(--text); border-color: var(--line-hi); }

.crumb.current {
  color: var(--accent);
  border-color: var(--line-hi);
  background: var(--bg3);
  cursor: default;
}

.crumb-sep { color: var(--faint); }

#gallery {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 14, 0.62);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 40;
}

/* display у #gallery перебивает [hidden], иначе закрытая галерея остаётся
   прозрачным полотном на весь экран: сцена притемнена, мышь до холста
   не доходит. Правило нужно всем оверлеям, у которых display задан по id. */
#gallery[hidden],
#palette[hidden],
#menu[hidden],
#rawlog[hidden] {
  display: none;
}

.gallery-panel {
  width: min(880px, calc(100vw - 32px));
  max-height: min(78vh, 720px);
  display: flex;
  flex-direction: column;
  background: var(--bg2);
  border: 1px solid var(--line-hi);
  border-radius: 6px;
  padding: 14px;
}

.gallery-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
  flex: none;
}
.gallery-head b {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}
.gallery-head span { font-size: 11px; color: var(--dim); }

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  /* Высота строки — по содержимому карточки. Без этого grid растягивает
     карточки по строке, а подпись уезжает под overflow: hidden. */
  grid-auto-rows: max-content;
  align-items: start;
  gap: 10px;
  overflow: auto;
  padding-right: 4px;
  min-height: 0;
}

/* Карточка — тоже button, но не контрол панели: высоту ей задаёт содержимое,
   иначе общая высота кнопок раздавила бы превью в полоску. */
.gallery-card {
  display: block;
  height: auto;
  padding: 0;
  background: var(--bg1);
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
  font: inherit;
  text-align: left;
}
.gallery-card:hover { border-color: var(--accent); }
.gallery-card.failed { border-color: var(--err); }

/* height здесь обязателен: общее правило canvas { height: 100% } тянет высоту
   от родителя, и карточка схлопывается вместе с подписью. */
.gallery-card canvas {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  background: var(--bg0);
}

.gallery-caption { padding: 7px 9px 9px; }
.gallery-caption b {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--text);
  margin-bottom: 2px;
}
.gallery-caption span {
  display: block;
  font-size: 10px;
  color: var(--dim);
  line-height: 1.35;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* --- таймлайн --- */

#timeline {
  grid-column: 1 / -1;
  min-width: 0;
  background: var(--bg2);
  border-top: 1px solid var(--line);
  user-select: none;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.tl-bar {
  display: flex;
  align-items: center;
  gap: var(--gap);
  padding: var(--gap-sm) var(--pad);
  flex: none;
}

.tl-bar button { min-width: 26px; }

.tl-readout {
  font: 11px var(--mono);
  color: var(--dim);
  min-width: 96px;
}

.tl-field {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--dim);
}
.tl-field input {
  width: 52px;
  height: var(--ctl-h);
  padding: 0 4px;
  background: var(--bg3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--text);
  font: 11px var(--mono);
  outline: none;
}

.tl-spacer { flex: 1; }
.tl-progress { font: 11px var(--mono); color: var(--accent); }

.timeline.collapsed .tl-body { display: none; }

.tl-body {
  position: relative;
  padding: 0 var(--pad) var(--pad);
  overflow: auto;
  min-height: 0;
}

.tl-ruler {
  position: relative;
  height: 16px;
  /* Линейка обязана совпадать по геометрии с дорожкой: 140px подпись + 8px
     зазор слева, 18px кнопка + 8px зазор справа. */
  margin: 0 26px 0 148px;
  border-bottom: 1px solid var(--line);
  cursor: ew-resize;
}

.tl-tick {
  position: absolute;
  top: 2px;
  font: 9px var(--mono);
  color: var(--faint);
  transform: translateX(-50%);
}

.tl-rows { margin-top: 3px; }

.tl-row {
  display: grid;
  grid-template-columns: 140px 1fr 18px;
  gap: 8px;
  align-items: center;
  height: 20px;
}

.tl-label {
  font-size: 11px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tl-lane {
  position: relative;
  height: 14px;
  background: var(--bg0);
  border: 1px solid var(--line);
  border-radius: 2px;
  cursor: ew-resize;
}

.tl-key {
  position: absolute;
  top: 50%;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  background: var(--accent);
  transform: rotate(45deg);
  cursor: pointer;
}
.tl-key.ease { border-radius: 4px; transform: none; margin-top: -4px; }
.tl-key:hover { background: var(--accent-hi); }

.tl-drop {
  width: 18px;
  height: 18px;
  padding: 0;
  line-height: 1;
  background: none;
  border: 1px solid transparent;
  color: var(--dim);
}
.tl-drop:hover { color: var(--err); border-color: var(--line); }

.tl-empty {
  font-size: 11px;
  color: var(--dim);
  padding: 6px 0 2px 148px;
}

.tl-playhead {
  position: absolute;
  top: 0;
  bottom: 8px;
  left: 0;
  width: 1px;
  background: var(--accent);
  pointer-events: none;
}

/* --- сравнение версий --- */

#compare-pick {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 14, 0.62);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 45;
}
#compare-pick[hidden] { display: none; }

.cmp-panel {
  width: min(520px, calc(100vw - 32px));
  background: var(--bg2);
  border: 1px solid var(--line-hi);
  border-radius: 6px;
  padding: 14px;
}

#compare {
  position: fixed;
  right: var(--pad);
  bottom: 42px;
  width: 330px;
  max-height: 52vh;
  display: flex;
  flex-direction: column;
  background: var(--bg2);
  border: 1px solid var(--line-hi);
  border-radius: 5px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.55);
  z-index: 30;
  padding: 10px;
}
#compare[hidden] { display: none; }

.cmp-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 8px;
}
.cmp-head b {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}
.cmp-sides {
  font-size: 10px;
  color: var(--dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cmp-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
  font-size: 11px;
  color: var(--dim);
}
.cmp-row select {
  flex: 1;
  min-width: 0;
  height: 20px;
  background: var(--bg3);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 2px;
  font: 11px var(--ui);
}
.cmp-split { font: 11px var(--mono); color: var(--text); margin-left: auto; }

.cmp-list {
  overflow: auto;
  min-height: 0;
  border-top: 1px solid var(--line);
  padding-top: 6px;
}

.cmp-item {
  font: 10px/1.5 var(--mono);
  padding: 1px 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cmp-item.add { color: var(--ok); }
.cmp-item.del { color: var(--err); }
.cmp-item.mod { color: var(--mod); }
.cmp-item.same { color: var(--dim); }

/* --- просмотр GLSL -------------------------------------------------------- */

#code {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 14, 0.62);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 40;
}
#code[hidden] { display: none; }

.cv-panel {
  width: min(900px, calc(100vw - 32px));
  max-height: min(82vh, 760px);
  display: flex;
  flex-direction: column;
  background: var(--bg2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 14px;
}

.cv-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
  flex: none;
}
.cv-head b {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}
.cv-stats { font-size: 11px; color: var(--dim); }
.cv-spacer { flex: 1; }

.cv-body {
  overflow: auto;
  min-height: 0;
  background: var(--bg0);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 8px 0;
  font: 12px/1.55 var(--mono);
}

.cv-empty {
  padding: 24px 14px;
  color: var(--dim);
  font: 12px var(--ui);
  text-align: center;
}

.cv-line {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 0 10px;
  white-space: pre;
}

.cv-num {
  flex: none;
  width: 30px;
  text-align: right;
  color: var(--faint);
  user-select: none;
}

.cv-line code {
  flex: 1;
  min-width: 0;
  font: inherit;
  color: var(--text);
}

/* Строка, за которой стоит нода, кликабельна — это и есть source map наружу. */
.cv-hot { cursor: pointer; }
.cv-hot:hover { background: var(--bg2); }
.cv-hot:hover .cv-tag { color: var(--accent); }

.cv-tag {
  flex: none;
  color: var(--faint);
  font-size: 11px;
  user-select: none;
}

.cv-cmt     { color: var(--syn-cmt); font-style: normal; }
.cv-pre     { color: var(--syn-pre); font-style: normal; }
.cv-num-lit { color: var(--syn-num); font-style: normal; }
.cv-type    { color: var(--syn-type); font-style: normal; }
.cv-kw      { color: var(--syn-kw); font-style: normal; }
.cv-fn      { color: var(--syn-fn); font-style: normal; }
.cv-uni     { color: var(--accent); font-style: normal; }
