/* Кабинет ОптМастер — ОБОЛОЧКА: база документа, тёмная шапка, меню, подвал, кнопки.

   Второй слой каскада (порядок — `lib/layout.mjs::STYLESHEETS`): опирается на токены из
   `tokens.css` и ничего, кроме них, не предполагает.

   ⚠️ Новый файл стилей ОБЯЗАН попасть в `STYLESHEETS` — иначе он просто не подключён,
   и страница отрисуется без него. Это проверяет тест (`test/shell-ui.test.mjs`):
   любой `static/*.css` без строки в списке валит сборку.

   Мобильный первый: у Meest кабинет на телефоне разваливается в горизонтальную
   прокрутку таблиц, у нас таблиц нет вовсе. */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.5 var(--font-text);
}

/* Заголовки, подписи-надзаголовки и крупные числа — Oswald, как на сайте.
   Подгружается он оттуда же (`lib/layout.mjs`): клиент пришёл с /posylky/, файл уже
   в кеше браузера, и кабинет открывается сразу в нужной гарнитуре. */
h1, h2, h3 { font-family: var(--font-head); font-weight: 600; }

a { color: var(--brand); }

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 16px;
}

/* Ссылка для клавиатуры: видна только при фокусе. */
.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: 8px;
  top: 8px;
  z-index: 30;
  background: var(--card);
  padding: 8px 12px;
  border-radius: var(--radius);
}

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

   Тёмная, как у сайта (`--dark` в его `stenin.css`), и это не вкусовщина: клиент попадает
   сюда кнопкой со светлой /posylky/, и белая шапка кабинета под белой шапкой сайта читалась
   как «страница не догрузилась». Второй уровень (меню) — на полтона светлее, чтобы граница
   между «кто я» и «куда идти» была видна без линейки. */

.hdr {
  background: var(--surface-dark);
  color: var(--on-dark);
}
.hdr-in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
  min-height: 60px;
  padding-top: 10px;
  padding-bottom: 10px;
}
.hdr-brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-head);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  color: var(--on-dark);
  text-decoration: none;
  margin-right: auto;
}
/* Метка логотипа — единственное синее пятно на тёмной шапке. Синий здесь допустим именно
   потому, что он ничего не сообщает: это фигура, а не текст и не граница активного пункта,
   поэтому порог 3:1 к фону к ней не применяется. */
.hdr-mark {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: var(--brand);
  flex: none;
}
.hdr-money {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--on-dark-muted);
}
.hdr-money b { color: var(--on-dark); }
/* Разделитель между «Бонус» и «До сплати». #3a4756 давал 1.79 к шапке — на экране его
   не было, и два числа читались как одно. `--on-dark-dim` даёт 3.6: декор, но работающий.
   С UI-2 это токен, а не литерал: тем же тоном набраны непройденные шаги маршрута. */
.hdr-sep { color: var(--on-dark-dim); }
/* Приглашение подтвердить телефон — оранжевое, а не зелёное: `--ok` на тёмном даёт 3.26 и
   AA не проходит, а сообщение это про действие и деньги, то есть ровно роль `--accent`. */
.hdr-verify {
  font-size: 14px;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dashed currentColor;
  /* Тач-зона: без вертикального padding высота строки 21 px при минимуме 24 (WCAG 2.5.8). */
  padding: 6px 0;
}
/* Тач-зона переключателя языка: без padding кликабельны два символа — на телефоне
   в него не попасть (WCAG 2.5.8 просит минимум 24×24 CSS px). */
.hdr-lang { display: flex; gap: 2px; font-size: 14px; align-items: center; }
.hdr-lang a,
.hdr-lang .lang-on { display: inline-block; padding: 6px 8px; }
.hdr-lang a { color: var(--on-dark-muted); }
.hdr-lang .lang-on { color: var(--on-dark); }
.hdr-profile { font-size: 14px; text-decoration: none; padding: 6px 0; color: var(--on-dark-muted); }

/* Кольцо фокуса на тёмных поверхностях — своё, а не браузерное по умолчанию: Chromium
   рисует двухцветное и его видно, Firefox и Safari — однотонное, которое на #141d28
   сливается с фоном. Светлое, а не фирменное: синий к тёмной шапке даёт 2.78 при пороге
   3.0 (WCAG 1.4.11) — то самое место, где «как у полей ввода» было бы ошибкой. */
.hdr a:focus-visible,
.nav-in a:focus-visible {
  outline: 2px solid var(--on-dark);
  outline-offset: 2px;
  border-radius: 4px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--brand);
  color: var(--brand-ink);
  text-decoration: none;
  padding: 9px 18px;
  /* Прозрачная граница, а не её отсутствие: тихая кнопка (`.btn-quiet`) рисует ту же рамку
     цветом, и без места под неё она смещала бы соседей на два пикселя. Плюс главная причина
     писать это ЗДЕСЬ, а не у тихой: раньше границу снимал `button.btn { border: 0 }` из
     `components.css` — специфичность (0,1,1) против (0,1,0), и порядок файлов этого не
     отменяет. Все вторичные кнопки кабинета («Видалити», «Вийти», «Перевиставити») выходили
     голым словом, а `<a class="btn btn-quiet">` рядом — обведённым: одна пара классов
     рисовалась двумя разными способами в зависимости от ТЕГА (аудит UI-4). */
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-weight: 600;
  font-size: 15px;
}
/* Кружок со стрелкой в кнопке — идиома сайта (`.btn .chip`). Глиф системный СВЕДОМО, как
   и у сайта: в Oswald он уехал бы в поздний latin-сабсет и менял ширину строки при свопе. */
.btn-chip {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: rgba(0, 0, 0, .22);
  display: inline-grid;
  place-items: center;
  font-style: normal;
  font-size: 11px;
  font-family: system-ui, sans-serif;
  flex: none;
}
/* Кнопка в шапке — оранжевая с ТЁМНОЙ подписью. Так делает сайт (`.btn.orange`: фон
   бренд-#ec6118, текст `--ink`, 5.1): белая подпись на этом оранжевом даёт 3.35 и AA не
   проходит. Синей её сделать нельзя по другой причине — синяя ПОВЕРХНОСТЬ на тёмной шапке
   даёт 2.84 и не отделяется от фона. */
.hdr-cta {
  background: var(--accent);
  color: var(--ink);
}
.hdr-cta .btn-chip { background: rgba(20, 29, 40, .22); }

/* ---------------------------------------------------------------- меню

   На широком экране — вторая полоса тёмной шапки. На телефоне — нижнее фиксированное меню
   с иконками: большим пальцем достаётся низ экрана, а не верх, и шесть подписей больше не
   переносятся в две строки. Разметка при этом ОДНА (`renderNav`), различие целиком в CSS:
   второй экземпляр меню для телефона означал бы два места, где заводят новый пункт. */

.nav {
  background: var(--surface-dark-2);
  /* Полутон между #141d28 и #1b2531 даёт контраст 1.10 — «границу видно без линейки»
     комментарий обещал, а глаз её не находил. Волосок делает обещание правдой. */
  border-top: 1px solid rgba(255, 255, 255, .07);
}
.nav-in {
  display: flex;
  flex-wrap: wrap;
  gap: 0 20px;
  list-style: none;
  margin: 0;
  padding: 0 16px;
}
.nav-in a {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 0;
  color: var(--on-dark-muted);
  text-decoration: none;
  font-size: 15px;
  border-bottom: 2px solid transparent;
}
.nav-in a.on {
  color: var(--on-dark);
  font-weight: 600;
  /* Оранжевый, а не фирменный синий: на тёмной полосе синяя черта даёт 2.84 и как признак
     «вы здесь» физически не видна. На светлых экранах активный элемент по-прежнему синий. */
  border-bottom-color: var(--accent);
}
/* В режиме принудительных цветов (Windows High Contrast) и цвет подписи, и цвет черты
   перекрашиваются системой — «вы здесь» осталось бы только в `aria-current`, то есть
   исчезло бы для всех, кто видит экран глазами. Системный цвет выделения это чинит. */
@media (forced-colors: active) {
  .nav-in a.on { border-bottom-color: Highlight; }
}

/* Иконка нужна только нижнему меню на телефоне; на широком экране рядом с подписью в один
   ряд она превращает меню в панель инструментов. */
.nav-ic { display: none; }
/* Подпись, спрятанная ВИЗУАЛЬНО, но оставшаяся в дереве доступности: `display: none` убрал бы
   её и из доступного имени ссылки, а имя обязано содержать обе подписи (WCAG 2.5.3, разбор —
   в `renderNav`). На широком экране прячется короткая, на телефоне — полная. */
.nav-tx-s {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------------------------------------------------------------- контент */

main.wrap { padding-top: 24px; padding-bottom: 40px; }

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 20px;
  box-shadow: var(--shadow-card);
}
.card h1 { margin-top: 0; font-size: 22px; }

/* ------------------------------------------------------- узкий десктоп и планшет

   Между 721 и 900 px шапка разъезжалась на две строки: точку перелома выбирали по МЕНЮ
   (шесть подписей), а шапка теряет строку раньше — с UI-1 в ней прибавились метка логотипа
   и чип кнопки. Здесь она просто ужимается, оставаясь одной строкой; нижнее меню включается
   отдельно, ниже. */
@media (max-width: 900px) {
  .hdr-in { gap: 10px; }
  .hdr-brand { font-size: 13px; }
  .hdr-money { font-size: 13px; }
  .hdr-profile { font-size: 13px; }
  .hdr-cta { padding: 8px 14px; font-size: 14px; }
  /* Чип-стрелка — украшение, и первой уступает место: замер на 800 px давал 816 px
     содержимого при 768 доступных, то есть «Профіль» уезжал вниз из-за полусотни пикселей. */
  .hdr-cta .btn-chip { display: none; }
}

/* Ниже 780 px даже ужатая шапка не держит пять элементов в строку, и перенос выходил
   случайным: вниз уезжал то «Профіль», то язык. Деньги уходят своей строкой — ровно так же,
   как на телефоне, где это уже сделано. Одинаковое поведение вместо двух разных. */
@media (max-width: 780px) {
  .hdr-money {
    flex-basis: 100%;
    order: 3;
  }
}

/* ---------------------------------------------------------------- телефон

   720px — не «типичный телефон», а точка, где шесть пунктов меню перестают помещаться
   в одну строку вместе с шапкой. */
@media (max-width: 720px) {
  /* Логотип, язык и вход обязаны уместиться в ОДНУ строку: перенос «Увійти» на вторую
     делает шапку вдвое выше ещё до того, как в неё придут деньги вошедшего клиента.
     На 360 px это 164 + 60 + 45 px при 32 px внутренних отступов. */
  /* ⚠️ `flex-wrap: nowrap` здесь стоял ровно один заход и был снят живым проходом: у ГОСТЯ
     шапка от него собиралась в строку, а у вошедшего клиента — ломалась. Деньги рассчитаны
     на перенос (`flex-basis: 100%` ниже), и запрет переноса втиснул их в первую строку,
     схлопнув бренд до «ОПТМА…». В CSS это не видно: дефект появляется только при том
     наборе элементов, которого нет на странице входа. */
  .hdr-brand {
    /* 12px, а не 13: замер на живой странице (360 px, вошедший клиент, Oswald с прода) дал
       бренд 188 + язык 65 + профиль 57 при 328 px доступных — «Профіль» уезжал третьей
       строкой из-за двух пикселей. На 12 px бренд занимает ~174, и запас становится 16 px.
       Многоточие ниже остаётся страховкой на случай более длинной локали. */
    font-size: 12px;
    gap: 7px;
    /* `flex: 1 1 0` — не про растяжение, а про ПЕРЕНОС: при `flex-wrap` браузер решает,
       что перенести, по базовым размерам, и бренд с базой 175 px выталкивал «Профіль» на
       третью строку при 320 px. С нулевой базой он места в этом решении не занимает,
       забирает остаток строки и при нехватке усекается многоточием — язык и вход остаются
       наверху всегда, на любой ширине и в любой локали. */
    flex: 1 1 0;
    min-width: 0;
  }
  /* ⚠️ Многоточие рисует ВНУТРЕННИЙ span, а не сам `.hdr-brand`: тот — `inline-flex`, а
     `text-overflow` работает только в блочном контейнере. Первая редакция ставила правило
     прямо на бренд, комментарий рядом обещал «усечётся многоточием» — и это было обещание,
     которого код не выполнял: на 320 px бренд резался по букве («ОПТМАСТЕР · ПОСИЛ»). */
  .hdr-brand-tx {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  /* Служебная шапка набрана из ДРУГИХ элементов (имя сотрудника, тег роли, кнопка выхода),
     и они не сжимаются — весь дефицит уходил в бренд с нулевой базой, оставляя «СЛУЖ».
     Ей перенос по-прежнему дешевле усечения: строк в служебной шапке не жалко. */
  .hdr-adm .hdr-brand {
    flex: 0 1 auto;
  }
  .hdr-mark { width: 18px; height: 18px; border-radius: 5px; }
  .hdr-profile { font-size: 13px; }
  .hdr-lang { font-size: 13px; }
  .hdr-lang a,
  .hdr-lang .lang-on { padding: 6px; }
  .hdr-in { min-height: 52px; gap: 8px; }
  /* Главное действие с шапки уходит: на телефоне оно вторым пунктом нижнего меню («Викуп»),
     и две кнопки «Замовити викуп» на одном экране — это вопрос «а они разные?». */
  .hdr-cta { display: none; }
  /* Деньги — своей строкой под брендом: `flex-basis: 100%` переносит их целиком, а не
     отжимает бренд. `order: 3` ставит их после языка и профиля, то есть внизу шапки. */
  .hdr-money {
    font-size: 13px;
    flex-basis: 100%;
    order: 3;
    /* Каждая половина — цельной строкой: «До сплати:» и сумма, разорванные переносом,
       читаются как два разных числа. */
    flex-wrap: wrap;
    gap: 4px 8px;
  }
  .hdr-bonus,
  .hdr-due { white-space: nowrap; }
  /* Приглашение подтвердить телефон занимает в шапке ТОТ ЖЕ слот, что и деньги, и такое же
     длинное («Підтвердіть телефон — отримайте 100 ₴», ~240 px). Без своей строки оно
     схлопнуло бы бренд ровно так же — дефект латентный: блок не рендерится, пока
     `CABINET_SMS_DRIVER=off`, и проснётся в день, когда приедет ключ SMS. */
  .hdr-verify {
    font-size: 13px;
    flex-basis: 100%;
    order: 3;
  }

  .nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    background: var(--card);
    border-top: 1px solid var(--line);
    box-shadow: var(--shadow-bar);
    /* Полоса жестов iPhone: без этого нижний ряд подписей оказывается под ней. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .nav-in {
    display: grid;
    /* Число колонок НЕ задано числом: у админки пунктов три, а не шесть, и `repeat(6, 1fr)`
       оставил бы её меню в трети экрана. */
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    flex-wrap: nowrap;
    gap: 0;
    padding: 6px 2px 8px;
  }
  .nav-in a {
    /* ⚠️ P0 аудита: цвет ОБЯЗАН переопределяться вместе с фоном. Полоса меню здесь
       переворачивается в белую (`.nav` выше), а `--on-dark-muted` посчитан под тёмную
       поверхность: на белом он даёт 2.10 при кегле 10 px, то есть пять подписей и пять
       значков из шести физически не читались. Токен «для тёмного», доехавший до светлой
       поверхности, — это отдельный класс дефекта, и он не виден ни в одном правиле по
       отдельности: обе строки верны, неверна их пара. */
    color: var(--muted);
    display: grid;
    justify-items: center;
    align-content: center;
    gap: 4px;
    padding: 4px 2px;
    font-size: 10px;
    line-height: 1.2;
    text-align: center;
    border-bottom: 0;
    /* Тач-зона по WCAG 2.5.8: 44 px высоты у пункта, в который целятся пальцем на ходу. */
    min-height: 44px;
    /* `grid-auto-columns: 1fr` не мешает колонке вырасти под содержимое: у грид-элемента
       `min-width: auto`. При увеличении текста до 200% (WCAG 1.4.4) подписи распирали
       полосу до 510 px на вьюпорте 485 — и последний пункт уезжал ЗА экран без прокрутки,
       потому что полоса фиксированная. С нулевым минимумом лишнее уходит в многоточие. */
    min-width: 0;
  }
  .nav-in a > span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .nav-in a.on {
    color: var(--brand);
    font-weight: 600;
  }
  /* Полоса здесь белая — светлое кольцо на ней исчезло бы. */
  .nav-in a:focus-visible { outline-color: var(--brand); }
  .nav-ic {
    display: block;
    width: 22px;
    height: 22px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  /* Подписи меняются местами: короткая видна, полная остаётся в доступном имени. */
  .nav-tx-s {
    position: static;
    width: auto;
    height: auto;
    overflow: hidden;
    clip-path: none;
  }
  .nav-has-short .nav-tx {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  /* Место под фиксированное меню отдаёт `body`, а не `main`: подвал стоит ПОСЛЕ main и
     при отступе на нём уезжал бы под меню — а это единственное место, где написано, чей
     это кабинет. */
  body { padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px)); }
}

.err { text-align: center; }
.err-code {
  font-family: var(--font-head);
  font-size: 40px;
  font-weight: 700;
  color: var(--line);
  margin: 0;
}

.ftr {
  border-top: 1px solid var(--line);
  padding: 16px 0;
  color: var(--muted);
  font-size: 14px;
}

