  :root {
    --bg: #f2f2f7; --card: #ffffff; --text: #0d0d14;
    --muted: #737380; --brand: #595ced; --error: #ff6961; --ok: #21a651;
    --border: #d9d9e0;
    /* Шеврон селектора рисуем САМИ (см. `header select`): системная стрелка
       у каждой платформы своей ширины, и место под неё приходилось угадывать.
       ⚠️ Файлом, а НЕ data-URI: на бою стоит `img-src 'self'`, и картинка,
       вшитая в стиль, просто не загружается - шеврон пропал у владельца на
       живой странице 31.08.2026, а локально, где CSP нет, проба этого не
       показала. Ослаблять заголовок ради стрелки незачем.
       Файла два, по одному на тему: у внешней картинки нет доступа к
       currentColor. */
    --chevron: url("/chevron.svg");
    /* Высота органов управления шапки - одна на всех: селектор и кнопка
       входа стоят рядом, и разница даже в два пикселя читается как
       небрежность (замечание владельца 31.08.2026). */
    --control-h: 36px;
    /* Место под свой шеврон. Читается и из JS, который меряет ширину
       селектора: константа обязана быть ОДНА, иначе вёрстка и замер
       разъедутся молча. */
    --select-arrow: 30px;
    /* Код всегда на тёмном фоне — как в приложениях (codeBackground). */
    --code-bg: #171a24; --code-text: #f2f2f7;
    --tk-kw: #c791f5; --tk-str: #99db8c; --tk-com: #808799;
    --tk-num: #f2b866; --tk-def: #73bfff; --tk-blt: #66d9d9;
  }
  @media (prefers-color-scheme: dark) {
    :root {
      --bg: #121217; --card: #212129; --text: #f2f2f7;
      --muted: #9999a6; --brand: #787aff; --error: #ff6961; --ok: #4cc770;
      --border: #3a3a45;
      --chevron: url("/chevron-dark.svg");
    }
  }
  * { box-sizing: border-box; }
  body {
    margin: 0; min-height: 100vh; background: var(--bg); color: var(--text);
    font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
    padding: 16px;
  }
  .wrap { max-width: 860px; margin: 0 auto; }
  /* Шапка держится в ОДНУ строку на любой ширине (правило владельца
     2026-08-21). Порядок уступок при нехватке места такой:
       1) селектор языка сужается до выбранного названия (это делает play.js);
       2) шрифты плавно уменьшаются clamp'ом, без скачков на границе;
       3) на самых узких экранах пропадает слово «Песочница».
     Кнопка и селектор не сжимаются вовсе: это органы управления, и палец
     промахивается по ним раньше, чем глаз замечает выигранные пиксели. */
  header {
    display: flex; align-items: center; gap: 10px; margin: 4px 0 16px;
    flex-wrap: nowrap;
  }
  header .name {
    display: flex; align-items: center; gap: 8px;
    font-size: clamp(15px, 4.4vw, 18px); font-weight: 700;
    white-space: nowrap;
    /* Название НЕ сжимается: обрезанный бренд («Byte…») выглядит поломкой
       страницы, а не экономией места. Уступает место почта вошедшего - она
       единственное в шапке, что бывает какой угодно длины и что не жалко
       сократить многоточием. Поймано замером на 430px у вошедшего. */
    flex: 0 0 auto;
  }
  header .badge { color: var(--muted); font-weight: 400; }
  /* ⚠️ Системную стрелку убираем нарочно (`appearance: none`). До 31.08.2026
     её рисовала операционная система, ширины у неё в CSS нет, и JS резервировал
     под неё 22px НАУГАД - «запас, при котором текст не подлезает ни в одном из
     проверенных браузеров». На macOS запас не сошёлся, и «JavaScript» в шапке
     стоял обрезанным как «JavaScrip». Своя стрелка - своя известная ширина,
     одна на все платформы, и угадывать больше нечего.
     Шрифт и высота - как у кнопки входа: они стоят рядом. */
  header select {
    height: var(--control-h);
    padding: 0 var(--select-arrow) 0 12px; color: var(--text);
    font-size: clamp(13px, 3.4vw, 14px); line-height: 1;
    appearance: none; -webkit-appearance: none;
    background-color: var(--card);
    background-image: var(--chevron);
    background-repeat: no-repeat;
    background-position: right 11px center;
    border: 1px solid var(--border);
    border-radius: 10px; outline: none; flex: 0 0 auto;
  }
  header select:focus-visible { border-color: var(--brand); }
  /* Отжимает вправо ТОЛЬКО первый селектор, а не каждый: с `margin-left:auto`
     на всех подряд у SQL, где рядом появляется второй список (набор данных),
     свободное место делилось между ними и посреди шапки зияла дыра в полтораста
     пикселей. Правый край - это один блок: язык, набор, кнопка. */
  header #langSelect { margin-left: auto; }
  /* Аккаунт и форма входа (21.4). Кнопка мельче кнопок действия: вход —
     служебный шаг, а не то, ради чего пришли на страницу. */
  .account { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
  /* Почта вошедшего - единственное в шапке, что бывает какой угодно длины.
     Ограничение долей экрана, а не только знаками: на телефоне 22ch съели бы
     половину строки и вытолкнули кнопку. */
  .account button { height: var(--control-h); }
  .account button, .login button {
    padding: 0 clamp(10px, 3vw, 14px); font-size: clamp(13px, 3.4vw, 14px);
    line-height: var(--control-h);
    font-weight: 600; border-radius: 10px;
    cursor: pointer; border: 0; color: #fff; background: var(--brand);
  }
  .account button.secondary, .login button.secondary {
    color: var(--text); background: var(--card); border: 1px solid var(--border);
  }
  /* display у .login перебивает `hidden`, поэтому прячем явно: иначе
     форма входа встречает на пороге всех, включая тех, кому она не нужна. */
  .login[hidden] { display: none; }
  .login {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    margin: 0 0 14px; padding: 12px; border-radius: 12px;
    background: var(--card); border: 1px solid var(--border);
  }
  .login input {
    flex: 1 1 180px; padding: 9px 11px; font-size: 15px; color: var(--text);
    background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
    outline: none;
  }
  .login .note { flex-basis: 100%; margin: 0; color: var(--muted); font-size: 13px; }
  .login .err { flex-basis: 100%; margin: 0; color: var(--error); font-size: 13px; }
  .editor { position: relative; border-radius: 12px; background: var(--code-bg);
            overflow: hidden; }
  .codefont {
    font: 14px/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas,
          "Liberation Mono", monospace;
    tab-size: 4; white-space: pre; overflow-wrap: normal;
  }
  .editor pre, .editor textarea {
    margin: 0; padding: 14px 16px; border: 0; width: 100%;
    height: min(46vh, 480px); min-height: 260px; overflow: auto;
  }
  .editor pre { color: var(--code-text); }
  .editor textarea {
    position: absolute; inset: 0; resize: none; outline: none;
    background: transparent; color: transparent; caret-color: var(--code-text);
  }
  .editor textarea::selection { background: rgb(89 92 237 / 40%); }
  .tk-kw { color: var(--tk-kw); } .tk-str { color: var(--tk-str); }
  .tk-com { color: var(--tk-com); } .tk-num { color: var(--tk-num); }
  .tk-def { color: var(--tk-def); } .tk-blt { color: var(--tk-blt); }
  .hint { color: var(--muted); font-size: 13px; margin: 8px 2px 0; min-height: 1.2em; }
  .actions { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
  .actions button {
    padding: 11px 22px; font-size: 15px; font-weight: 600; border-radius: 10px;
    cursor: pointer; border: 0; color: #fff; background: var(--brand);
  }
  .actions button.secondary {
    color: var(--text); background: var(--card); border: 1px solid var(--border);
  }
  .actions button:disabled { opacity: 0.55; cursor: default; }
  .toast { color: var(--ok); font-size: 14px; opacity: 0; transition: opacity 0.3s; }
  .toast.show { opacity: 1; }
  .output { margin-top: 16px; display: none; }
  .output pre {
    margin: 0 0 8px; padding: 12px 16px; border-radius: 12px;
    background: var(--code-bg); color: var(--code-text);
    overflow-x: auto; max-height: 40vh;
  }
  .output pre.err { color: var(--error); }
  .output .none { color: var(--muted); font-style: italic; }

  /* Результат SQL. Прокрутка живёт на обёртке каждого шага: у country
     15 колонок, и на телефоне таблица обязана ездить вбок сама, не унося
     вбок всю страницу. */
  .step { margin-top: 12px; }
  .step .scroll { overflow-x: auto; border: 1px solid var(--border); border-radius: 8px; }
  .step table { border-collapse: collapse; width: max-content; min-width: 100%; }
  .step th, .step td {
    padding: 6px 10px; text-align: left; white-space: pre;
    border-bottom: 1px solid var(--border); font-size: 13px;
  }
  .step th {
    position: sticky; top: 0; background: var(--card);
    font-weight: 600; z-index: 1;
  }
  .step th .type { display: block; font-weight: 400; font-size: 11px; color: var(--muted); }
  .step td.null { color: var(--muted); font-style: italic; }
  .step .note { color: var(--muted); font-size: 12px; margin: 6px 2px 0; }
  .step .fail { color: var(--error); font-size: 13px; margin: 6px 2px 0; }
  .credit { color: var(--muted); font-size: 12px; margin: 14px 2px 0; }

  /* Приглашение в проект: тот же приглушённый тон, что у сноски с данными.
     Подчёркивание только у ссылки и только по наведению - строка обязана
     читаться как подпись, а не как баннер. */
  .promo { color: var(--muted); font-size: 13px; margin: 18px 2px 0; }
  .promo a { color: var(--brand); text-decoration: none; }
  .promo a:hover, .promo a:focus-visible { text-decoration: underline; }
  /* Ссылка на сайт - знак и слово «Bytelore». Подчёркивается при наведении
     САМО СЛОВО, а не «Playground» рядом: раньше подчёркивалось именно оно, и
     подсказка указывала на часть, которая никуда не ведёт. */
  .brand {
    display: inline-flex; align-items: center; gap: 8px;
    color: inherit; text-decoration: none;
  }
  .brand:hover .wordmark, .brand:focus-visible .wordmark {
    text-decoration: underline;
  }
  .status { color: var(--muted); font-size: 14px; margin: 10px 2px; min-height: 1.2em; }
  @media (max-width: 520px) {
    body { padding: 10px; }
    .actions button { flex: 1; padding: 12px 0; }
  }
  /* Последняя уступка на узком экране: «Песочница» уходит ПОД «Bytelore»,
     а не пропадает (решение владельца 2026-08-21). Слово остаётся частью
     знака, просто знак становится в две строки - так делают почти все
     двусоставные логотипы, когда места по горизонтали нет.
     Порог взят замером: при 430px имя целиком, селектор с самым длинным
     названием («Objective-C») и кнопка перестают складываться в строку. */
  /* Самый тесный случай во всей шапке - SQL: рядом с языком появляется
     второй список (набор учебных данных), и на 320px строка вылезала за край
     на десяток пикселей. Забираем их у зазоров и полей, а не у шрифта:
     мельче текст в органах управления делать некуда. */
  @media (max-width: 380px) {
    header { gap: 6px; }
    /* Слева ужимаем, справа НЕТ: там стоит шеврон, и отнятые пиксели
       вернули бы ту самую обрезку названия, ради которой всё и делалось. */
    header select { padding-left: 8px; }
  }
  @media (max-width: 430px) {
    header .name {
      flex-direction: column; align-items: flex-start; gap: 0;
      /* Плотный интерлиньяж: две строки должны читаться как один знак, а не
         как две случайно оказавшиеся рядом надписи. */
      line-height: 1.05;
    }
    header .badge {
      /* Мельче основного слова - иначе блок выглядит перевёрнутым: у
         двухэтажных знаков нижняя строка всегда легче верхней. */
      font-size: 0.72em; letter-spacing: 0.01em;
      /* Отступ ровно на знак с зазором (22 + 8): вторая строка обязана
         начинаться под СЛОВОМ, а не под значком, иначе двухэтажный знак
         рассыпается на картинку и подпись рядом. */
      padding-left: 30px;
    }
  }
