/* Общий блок кода для всех ста вариантов.
   DESIGN_DIRECTIONS.md §6. Компонент один, оформление — переменное:
   вариант переопределяет токены --code-*, но не трогает разметку и грамматику.

   Требования, которые здесь выполняются:
   - номера строк не захватываются при копировании (user-select: none);
   - шапка с именем метода, бейджем языка и кнопкой копирования;
   - подсветка активных строк;
   - диф-маркеры + / −;
   - горизонтальный скролл внутри блока, свой скроллбар;
   - выделение текста в цвет варианта, не системным синим;
   - две темы через --sk-light / --sk-dark от Shiki. */

.cb {
  /* ---- токены варианта: переопределять только их ---- */
  /* Чистый белый, не тёплый: токены github-light откалиброваны под #fff,
     и на #fbfbfa худший токен давал 4.47 против порога 4.5. Замерено. */
  --code-bg: #ffffff;
  --code-fg: #24292f;
  --code-border: rgb(0 0 0 / 0.10);
  --code-radius: 12px;
  --code-header-bg: rgb(0 0 0 / 0.03);
  --code-muted: rgb(0 0 0 / 0.55);
  /* Номера строк — тоже текст, и WCAG к ним применяется. 0.30 давало 2.1:1.
     Значение подобрано измерением, а не на глаз: см. чек-лист §5. */
  --code-gutter: rgb(0 0 0 / 0.58);
  --code-line-active: rgb(255 214 10 / 0.14);
  --code-add: rgb(46 160 67 / 0.15);
  --code-del: rgb(248 81 73 / 0.13);
  --code-selection: rgb(56 139 253 / 0.22);
  --code-font: "JetBrains Mono", "Geist Mono", ui-monospace, SFMono-Regular, monospace;
  --code-size: 13px;
  --code-leading: 1.55;
  --code-pad: 16px;
  /* Префикс пространства имён в UBL: cbc: / cac: гаснут относительно
     локального имени. Единственное, что делает UBL читаемым глазом. */
  --code-ns-opacity: 0.62;
  --code-ns-weight: 400;

  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;                       /* иначе flex-родитель разорвёт скролл */
  border: 1px solid var(--code-border);
  border-radius: var(--code-radius);
  background: var(--code-bg);
  color: var(--code-fg);
  overflow: hidden;
  font-feature-settings: "tnum" 1;    /* табличные цифры */
}

/* Тёмная тема варианта: класс на корне страницы. */
.dark .cb {
  --code-bg: #0d1117;
  --code-fg: #e6edf3;
  --code-border: rgb(255 255 255 / 0.12);
  --code-header-bg: rgb(255 255 255 / 0.04);
  --code-muted: rgb(255 255 255 / 0.60);
  --code-gutter: rgb(255 255 255 / 0.55);
  --code-line-active: rgb(255 214 10 / 0.10);
  --code-selection: rgb(56 139 253 / 0.35);
  --code-ns-opacity: 0.58;
}

/* ---- шапка ---- */

.cb__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px var(--code-pad);
  background: var(--code-header-bg);
  border-bottom: 1px solid var(--code-border);
  font: 500 12px/1 var(--code-font);
  color: var(--code-muted);
}

.cb__file { color: var(--code-fg); opacity: 0.8; }

/* Блок кода почти всегда лежит в колонке сетки, а автоминимум трека `1fr` —
   это min-content содержимого. Пока шапка блока не умела сжиматься, её
   min-content (строка вида «POST /v1/invoicing/validate» плюс два значка)
   распирал колонку до ~400 px и на узком экране выносил вёрстку за край
   у большинства вариантов серии. Тело и так прокручивается по горизонтали,
   поэтому достаточно разрешить сжатие шапке и снять автоминимум у фигуры. */
.cb { min-width: 0; }
.cb__head { min-width: 0; }
.cb__file { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb__lang, .cb__copy { flex: none; }

/* Кегль и коробка — как у соседней кнопки «Copy», чтобы они стояли парой
   по одной высоте и базовой линии. Было 10 px: мелко для капслока и заметно
   ниже кнопки рядом. Начертание оставлено легче кнопочного, чтобы плашка
   не выглядела нажимаемой. */
.cb__lang {
  margin-left: auto;
  min-height: 24px;
  display: inline-flex;
  align-items: center;
  padding: 4px 9px;
  border: 1px solid var(--code-border);
  border-radius: 6px;
  font-size: inherit;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.cb__copy {
  /* WCAG 2.5.8: цель указателя не меньше 24x24 CSS px.
     Было 22px по высоте — не хватало двух пикселей на всех ста вариантах. */
  min-width: 24px;
  min-height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 9px;
  border: 1px solid var(--code-border);
  border-radius: 6px;
  background: transparent;
  color: var(--code-muted);
  font: inherit;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s;
}
.cb__copy:hover { color: var(--code-fg); border-color: var(--code-fg); }
.cb__copy[data-copied="true"] { color: #2ea043; border-color: #2ea043; }

/* ---- тело ---- */

/* overflow-y: auto, а не hidden. Прежде вариант ограничивал высоту у <pre>,
   у которого своего переполнения нет, и остаток срезал предок через
   .cb{overflow:hidden}: сорок шесть строк из семидесяти двух были не просто
   не видны, а недостижимы. Ограничивать высоту надо здесь — у элемента,
   который умеет прокручиваться. */
.cb__body { overflow-x: auto; overflow-y: auto; }
/* Прокручиваемая область обязана быть достижима с клавиатуры (WCAG 2.1.1):
   без tabindex до правого края длинной строки не добраться вовсе. */
.cb__body:focus-visible { outline: 2px solid var(--code-fg); outline-offset: -2px; }

.cb pre {
  margin: 0;
  padding: var(--code-pad) var(--code-pad) var(--code-pad) 0;
  background: transparent !important;   /* фон даёт .cb, не тема Shiki */
  color: var(--code-fg);
  font: var(--code-size) / var(--code-leading) var(--code-font);
  tab-size: 2;
}

/* Раздача цветов темы. ОБЯЗАТЕЛЬНО: build-code.mjs собирает с
   defaultColor: false, то есть Shiki кладёт только переменные
   --sk-light / --sk-dark и сам ничего не красит. Без этих двух правил
   подсветки нет вообще — проверено измерением, все токены выходили
   одного цвета с контрастом 14:1. */
.cb .shiki span { color: var(--sk-light); }
.dark .cb .shiki span { color: var(--sk-dark); }

/* line-height: 0 на code и восстановление на .line — обязательно.
   Shiki оставляет между строчными спанами текстовые узлы "\n"; при
   display:block на .line они создают собственные строковые боксы и
   межстрочный удваивается. Замерено: шаг 40.28 px при line-height 20.15. */
.cb code {
  display: block;
  width: max-content;
  min-width: 100%;
  counter-reset: ln;
  line-height: 0;
}

/* Номера строк. user-select: none — копирование забирает код без них. */
.cb .line {
  display: block;
  position: relative;                 /* якорь для диф-маркеров ::after */
  line-height: var(--code-leading);
  padding-right: var(--code-pad);
}
.cb .line::before {
  counter-increment: ln;
  content: counter(ln);
  display: inline-block;
  width: 3.2em;
  margin-right: 1.1em;
  text-align: right;
  color: var(--code-gutter);
  user-select: none;
  -webkit-user-select: none;
}

/* Блок без номеров — для команд оболочки, где номер строки бессмыслен. */
.cb--bare .line::before { content: none; margin: 0; width: 0; }
.cb--bare pre { padding-left: var(--code-pad); }

/* Подсветка строк и диф. Классы ставит вариант на .line по индексу. */
.cb .line.is-active { background: var(--code-line-active); }
.cb .line.is-add    { background: var(--code-add); }
.cb .line.is-del    { background: var(--code-del); }
.cb .line.is-add::after,
.cb .line.is-del::after {
  position: absolute;
  left: calc(var(--code-pad) + 3.2em + 0.2em);
  color: var(--code-muted);
}
.cb .line.is-add::after { content: "+"; }
.cb .line.is-del::after { content: "−"; }

/* Префиксы пространств имён UBL. Вставляет build-code.mjs. */
.cb .ns { opacity: var(--code-ns-opacity); font-weight: var(--code-ns-weight); }

/* Выделение — токеном варианта, не системным синим. */
.cb ::selection { background: var(--code-selection); }

/* Свой скроллбар. */
.cb__body::-webkit-scrollbar { height: 9px; }
.cb__body::-webkit-scrollbar-track { background: transparent; }
.cb__body::-webkit-scrollbar-thumb {
  background: var(--code-gutter);
  border-radius: 99px;
  border: 3px solid transparent;
  background-clip: content-box;
}
.cb__body { scrollbar-width: thin; scrollbar-color: var(--code-gutter) transparent; }

@media (max-width: 640px) {
  .cb { --code-size: 12px; --code-pad: 12px; }
  .cb .line::before { width: 2.2em; margin-right: 0.7em; }
}

/* На узком экране адрес важнее ярлыка языка. Замерено на 320: строке нужно
   264 px, ей давали 122 — от «POST api.apiriver.dev/invoicing/generate»
   оставалось «POST api.apiriver…», при том что ярлык и кнопка занимали
   190 px из 264. Единственное, что разработчик обязан прочитать, вытеснялось
   двумя значками. Ярлык уходит первым: язык виден по самому коду. */
@media (max-width: 560px) {
  .cb__lang { display: none; }
  /* Адрес переносится, а не режется многоточием. На 320 строке нужно 264 px,
     а после снятия ярлыка остаётся 182 — «POST api.apiriver.dev/invo…».
     Это единственное, что разработчик обязан прочитать целиком, поэтому
     шапке разрешено стать в две строки. */
  .cb__head { flex-wrap: wrap; row-gap: 4px; }
  .cb__file { white-space: normal; overflow: visible; text-overflow: clip;
              overflow-wrap: anywhere; flex: 1 1 100%; }
  .cb__copy { margin-left: auto; }
}
/* ПОРЯДОК: этот блок обязан стоять последним в файле. Стоял выше — и правило
   .cb__lang{display:inline-flex} ниже по файлу его убивало при равной
   весомости. Тот же капкан, что был с отступами полосы цифр. */
