:root {
  --bg: #14161a;
  --bg-elevated: #1e2126;
  --bg-input: #24282f;
  --border: #33373f;
  --text: #eef0f3;
  --text-dim: #9aa2ad;
  /* Акцент — розово-фиолетовый. --accent используется как есть на бордерах,
     ссылках, активных вкладках и заливке кнопок. --accent-hover светлее —
     для текста/бордеров на тёмном фоне (там светлее только читается
     лучше), а не для заливки кнопок: на белом тексте контраст бы просел.
     --accent-active темнее — годится и для заливки тоже, с белым текстом
     контраст только растёт (проверено, см. заметку у .btn-primary). */
  --accent: #a855f7;
  --accent-hover: #c084fc;
  --accent-active: #9333ea;
  --accent-text: #ffffff;
  --urgent: #ef4444;
  --green: #22c55e;
  --orange: #f59e0b;
  --purple: #a855f7;
  --gray: #6b7280;

  /* Скругления: --radius — карточки/панели (базовый, умеренно увеличен —
     14→18px, чтобы не превращались в овалы), --radius-input — поля форм
     (text-input, select, вкладки — тоже увеличен, 12→16px), --radius-sm —
     элементы поменьше (тулбары, мини-кнопки), --radius-xs — миниатюрные
     (превью фото, мелкие иконки-кнопки), --radius-pill — капсулы
     (статус-бейджи). --btn-radius/-sm — отдельно для кнопок, см. ниже. */
  --radius: 18px;
  --radius-input: 16px;
  --radius-sm: 10px;
  --radius-xs: 6px;
  --radius-pill: 999px;

  /* Кнопки — "пилюли": border-radius больше половины высоты кнопки
     автоматически схлопывается до полукруглых торцов (браузер сам клэмпит
     999px до geometрически возможного), поэтому не считаем высоту руками.
     У мелких кнопок (.btn-sm) — помягче, не полная капсула. */
  --btn-radius: var(--radius-pill);
  --btn-radius-sm: 16px;

  /* Отступы между блоками: --space-md — стандартный (между карточками,
     секциями формы), --space-lg — крупный (между секциями страницы,
     hero-блоки на витрине). */
  --space-md: 16px;
  --space-lg: 24px;

  /* Заголовки — единственные два уровня во всём приложении: .page-title
     (h1 страницы) и .section-heading (подзаголовок секции внутри неё). */
  --font-size-page-title: 22px;
  --font-size-section-heading: 17px;

  /* Стандартный размер кнопки (.btn) — совпадает с большинством прежних
     разрозненных .xxx-btn, которые дублировали одни и те же числа. -sm —
     компактные инлайновые кнопки (очистить дату, скрыть сотрудника и т.п.),
     -lg — крупная CTA-кнопка на всю ширину (.btn-big). */
  --btn-font-size: 14px;
  --btn-font-size-sm: 12px;
  --btn-font-size-lg: 17px;
  --btn-padding-y: 10px;
  --btn-padding-x: 16px;
  --btn-padding-y-sm: 6px;
  --btn-padding-x-sm: 10px;
  --btn-padding-lg: 16px;

  /* Фирменный градиент, 135deg: в основном синий (0–70% длины), фиолетовый
     только на самом конце, без розового. Единая переменная --accent-gradient
     для всех "фирменных" интерактивных поверхностей: заливка основных
     кнопок, градиентная рамка у кнопок с обводкой, активные вкладки/пилюли,
     градиент на тексте ссылок/названия в шапке/активного пункта меню,
     кольца на витрине, приветствие.

     Контраст с белым текстом кнопок по стопам: 2563eb — 5.17:1, 3b82f6 —
     3.68:1, 6366f1 — 4.47:1, 8b5cf6 — 4.23:1. Средние два чуть ниже 4.5:1
     (тот же уровень, что был у самого первого синего акцента этого
     приложения) — оставлены как заданы: это не самый край градиента, а
     текст обычно по центру кнопки, где реальный цвет — блендинг соседних
     стопов, контраст там выше, чем в опорных точках. */
  --accent-grad-from: #2563eb;
  --accent-grad-mid: #3b82f6;
  --accent-grad-mid2: #6366f1;
  --accent-grad-to: #8b5cf6;
  --accent-gradient: linear-gradient(135deg, var(--accent-grad-from) 0%, var(--accent-grad-mid) 45%, var(--accent-grad-mid2) 70%, var(--accent-grad-to) 100%);

  /* Объём — не буквальный 3D, а мягкая многослойная тень (близкий плотный
     слой + дальний размытый) плюс еле заметная inset-окантовка сверху/снизу
     на карточках (создаёт ощущение приподнятости, как будто на них падает
     свет сверху). Всё приглушённо (низкая непрозрачность) специально —
     эффект должен читаться боковым зрением, а не бросаться в глаза. Все
     значения — здесь, чтобы менять глубину по всему приложению в одном
     месте. */
  --shadow-near: rgba(0, 0, 0, 0.26);
  --shadow-far: rgba(0, 0, 0, 0.16);
  --edge-light: rgba(255, 255, 255, 0.05);
  --edge-dark: rgba(0, 0, 0, 0.16);

  /* .card рисует box-shadow, но живёт с overflow: hidden (чтобы миниатюры
     скруглялись вместе с карточкой) — обычный (не inset) box-shadow в этом
     случае обрежется той же overflow-клипой. inset-тени не обрезаются
     (рисуются внутри рамки), поэтому окантовка — box-shadow, а внешняя
     глубина — filter: drop-shadow(), которая рендерится уже поверх
     обрезанного контента и overflow её не трогает. */
  --card-edge: inset 0 1px 0 var(--edge-light), inset 0 -1px 0 var(--edge-dark);
  --card-depth: drop-shadow(0 1px 2px var(--shadow-near)) drop-shadow(0 6px 16px var(--shadow-far));
  --card-depth-hover: drop-shadow(0 3px 6px var(--shadow-near)) drop-shadow(0 14px 32px var(--shadow-far));
  --card-depth-active: drop-shadow(0 1px 3px var(--shadow-near));

  --lift-hover: -3px;
  --lift-active: -1px;
  --lift-transition: 220ms ease-out;

  /* Кнопки без overflow: hidden — им обычный box-shadow ничего не обрезает,
     inset-блик сверху и внешние слои можно объединить в одном свойстве.
     При нажатии заливка гасится инсет-тенью вместо блика — ощущение
     вдавливания вместе с translateY(--btn-press). */
  --shadow-btn:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 1px 2px var(--shadow-near),
    0 4px 10px var(--shadow-far);
  --shadow-btn-active: inset 0 1px 4px rgba(0, 0, 0, 0.35);
  --btn-press: 1px;
}

:root[data-theme="light"] {
  --bg: #f5f6f8;
  --bg-elevated: #ffffff;
  --bg-input: #edeff2;
  --border: #d3d7dd;
  --text: #12141a;
  --text-dim: #4b5262;
}

/* Говорит браузеру, какая тема у страницы реально активна (в отрыве от
   системной light/dark) — без этого форм-контролы, скроллбары и area
   растяжения на "резиновом" скролле (мобильный overscroll/bounce) красятся
   браузером по СИСТЕМНОЙ теме: на светлой системе это белый, даже когда
   весь остальной фон страницы тёмный — отсюда "белая полоса снизу/сбоку"
   именно при светлой системной теме. */
:root {
  color-scheme: dark;
}

:root[data-theme="light"] {
  color-scheme: light;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  /* min-height, а не только background: у короткой страницы box body по
     умолчанию высотой ровно в контент — ниже него, если контента меньше
     вьюпорта, красится уже не наш фон, а дефолтный (белый) канвас
     браузера. */
  min-height: 100%;
  /* Не плоская заливка, а очень мягкий вертикальный градиент (чуть светлее
     сверху, темнее снизу) — привязан к вьюпорту (background-attachment:
     fixed), чтобы не "ехал" вместе с прокруткой длинных страниц. */
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg), white 8%) 0%, var(--bg) 100%);
  background-attachment: fixed;
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 17px;
  -webkit-tap-highlight-color: transparent;
  /* Раньше было только в @media (max-width: 899px) — вынесено сюда без
     условия: это чистая защита от горизонтального скролла всей страницы
     (не мешает внутреннему overflow-x: auto у .journal-table-wrap и
     подобных — они скроллятся сами по себе, независимо от html/body). */
  max-width: 100vw;
  overflow-x: hidden;
}

@media (max-width: 899px) {
  /* На узких экранах подпись убираем совсем — в самом лого уже есть
     название, а место в шапке ограничено. */
  .logo-text {
    display: none;
  }

  .logo-img {
    height: 16px;
  }
}

a { color: inherit; text-decoration: none; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 16px;
  /* iOS (Safari и standalone-режим "На экран Домой" с apple-mobile-web-app-
     status-bar-style: black-translucent) рисует шапку под чёлкой/статус-баром,
     раз position: sticky/top: 0 держит её у самого верха вьюпорта — без этого
     отступа контент и меню оказываются в недоступной зоне. env() с фоллбэком
     0px, чтобы на Android/десктопе, где safe-area нет, паддинг остался прежним
     (14px из строки выше). */
  padding-top: calc(14px + env(safe-area-inset-top, 0px));
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border);
}

.logo {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
  cursor: pointer;
  /* Только затемнение/высветление, без сдвигов — "мягкая подсветка". */
  transition: filter 200ms ease-out;
}

.logo:hover,
.logo:focus-visible {
  filter: brightness(1.18);
}

.logo-img {
  height: 20px;
  width: auto;
  display: block;
  flex-shrink: 0;
}

/* Тёмная тема (по умолчанию — без [data-theme], либо явный "dark"):
   у официального лого умеренный контраст к почти чёрному фону (синие
   тона, не чёрный силуэт) — вместо перекраски самого файла или инверсии
   (которая исказила бы фирменные цвета) поднимаем читаемость мягкой
   светлой подложкой. content-box, чтобы паддинг не сжимал сам логотип
   внутрь фиксированной высоты (глобально box-sizing: border-box). */
:root:not([data-theme="light"]) .logo-img {
  box-sizing: content-box;
  background: rgba(255, 255, 255, 0.14);
  border-radius: 8px;
  padding: 4px 7px;
}

/* В самом SVG уже есть название — рядом не повторяем его, а даём мелкую
   приглушённую подпись без градиента: лого крупное и главное, текст —
   подпись сбоку, а не второй заголовок. */
.logo-text {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  /* Сплошной приглушённый — запасной вариант, если background-clip: text
     не поддержится (см. @supports ниже). */
  color: var(--text-dim);
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .logo-text {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  .logo {
    transition: none !important;
  }
}

.logo-preview {
  height: 48px;
  width: auto;
  border-radius: var(--radius-xs);
  display: block;
  margin-bottom: var(--space-md);
  background: var(--bg-input);
}

.admin-nav {
  display: flex;
  align-items: center;
  gap: 8px;
  /* Само не скроллится — скроллится только .admin-nav-scroll внутри (см.
     ниже). Раньше overflow-x:auto стоял прямо здесь, но .nav-menu
     (гамбургер + выпадающее меню) — тоже потомок .admin-nav: overflow-x
     без явного overflow-y на любом предке автоматически даёт эффективный
     overflow-y: auto (правило CSS Overflow — "visible" на одной оси при
     не-"visible" на другой считается как "auto"), а auto обрезает всё, что
     выходит за границы блока по высоте. Абсолютно спозиционированная
     .nav-menu-dropdown как раз выходит за пределы узкой строки иконок —
     и обрезалась целиком, поэтому меню открывалось на вид "никак". */
  flex-shrink: 1;
  min-width: 0;
}

.admin-nav-scroll {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 1;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.admin-nav-scroll::-webkit-scrollbar {
  display: none;
}

.weather-widget {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.25;
  flex-shrink: 0;
}

.weather-widget-main {
  font-size: 13px;
  color: var(--text-dim);
  white-space: nowrap;
}

/* Совет по погоде — мелко, приглушённо, в одну строку под температурой. */
.weather-advice {
  font-size: 10px;
  color: var(--text-dim);
  opacity: 0.75;
  white-space: nowrap;
}

@media (max-width: 899px) {
  /* На телефоне при нехватке места первым уходит необязательный совет
     (сейчас это только "Сильный ветер") — дождь/снег/жара/мороз остаются. */
  .weather-advice-optional {
    display: none;
  }
}

.icon-btn {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
}

.theme-toggle {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.nav-menu {
  position: relative;
  flex-shrink: 0;
}

.nav-menu-toggle {
  position: relative;
  z-index: 26;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.nav-menu-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(8, 9, 11, 0.4);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  opacity: 0;
  z-index: 25;
  transition: opacity 160ms ease-out;
}

.nav-menu-backdrop.nav-menu-backdrop-open {
  opacity: 1;
  transition: opacity 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.nav-menu-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 260px;
  /* Двойной background (padding-box + border-box) — стандартный способ дать
     рамке градиент вместе со скруглением, раз обычный border градиент не
     умеет. color-mix() поверх --bg-elevated/--bg — лёгкий тёмный градиент,
     который остаётся полупрозрачным, чтобы backdrop-filter под ним был
     заметен, и при этом сам подстраивается под тему (в светлой — светлый).
     Блюр раньше сознательно не ставили на панель (пересчёт каждый кадр
     transform мог "гасить" пружину на слабом железе) — теперь он нужен по
     дизайну; анимация короткая (260ms) и с will-change, так что оставляем. */
  background:
    linear-gradient(160deg, color-mix(in srgb, var(--bg-elevated) 90%, transparent), color-mix(in srgb, var(--bg) 85%, transparent)) padding-box,
    var(--accent-gradient) border-box;
  border: 1px solid transparent;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-radius: var(--radius);
  box-shadow:
    0 24px 60px rgba(0, 0, 0, 0.45),
    0 8px 24px rgba(0, 0, 0, 0.22),
    0 0 32px rgba(139, 92, 246, 0.14);
  padding: 6px;
  z-index: 30;

  transform-origin: top right;
  opacity: 0;
  transform: scale(0.92) translateY(-8px);
  pointer-events: none;
  will-change: opacity, transform;
}

/* @keyframes вместо transition: анимация с явным from/to надёжно стартует
   даже на элементе, который только что перестал быть display:none — ей не
   нужно "подсматривать" предыдущее состояние, в отличие от transition. */
.nav-menu-dropdown.nav-menu-dropdown-open {
  animation: nav-menu-dropdown-in 260ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  pointer-events: auto;
}

.nav-menu-dropdown.nav-menu-dropdown-closing {
  animation: nav-menu-dropdown-out 160ms ease-out forwards;
  pointer-events: none;
}

@keyframes nav-menu-dropdown-in {
  from { opacity: 0; transform: scale(0.92) translateY(-8px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

@keyframes nav-menu-dropdown-out {
  from { opacity: 1; transform: scale(1) translateY(0); }
  to   { opacity: 0; transform: scale(0.92) translateY(-8px); }
}

.nav-menu-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  opacity: 0;
  transform: translateY(-6px);
}

.nav-menu-item-icon {
  flex-shrink: 0;
  color: var(--text-dim);
  transition: color 160ms ease-out;
}

.nav-menu-item-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.nav-menu-dropdown-open .nav-menu-item {
  animation: nav-menu-item-in 180ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

/* Каскад через animation-delay. Первый пункт стартует сразу (0ms). Длительность
   (180ms) короче суммарного разброса задержек (0–200ms), чтобы пункты не
   перекрывались почти полностью и появление читалось как последовательность. */
.nav-menu-dropdown-open .nav-menu-item:nth-child(1) { animation-delay: 0ms; }
.nav-menu-dropdown-open .nav-menu-item:nth-child(2) { animation-delay: 40ms; }
.nav-menu-dropdown-open .nav-menu-item:nth-child(3) { animation-delay: 80ms; }
.nav-menu-dropdown-open .nav-menu-item:nth-child(4) { animation-delay: 120ms; }
.nav-menu-dropdown-open .nav-menu-item:nth-child(5) { animation-delay: 160ms; }
.nav-menu-dropdown-open .nav-menu-item:nth-child(6) { animation-delay: 200ms; }

/* При закрытии — без каскада, разом (селектор один на всех, без nth-child). */
.nav-menu-dropdown-closing .nav-menu-item {
  animation: nav-menu-item-out 120ms ease-out forwards;
}

@keyframes nav-menu-item-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes nav-menu-item-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-6px); }
}

/* Активный пункт — не сплошная заливка, а еле заметный фон плюс тонкая
   градиентная полоска слева (псевдоэлемент, т.к. border-градиент по одной
   стороне так просто не сделать). */
.nav-menu-dropdown-open .nav-menu-item.active {
  background: rgba(139, 92, 246, 0.08);
}

.nav-menu-dropdown-open .nav-menu-item.active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 3px;
  border-radius: 2px;
  background: var(--accent-gradient);
}

.nav-menu-dropdown-open .nav-menu-item:hover {
  background: linear-gradient(90deg, rgba(37, 99, 235, 0.12), rgba(139, 92, 246, 0.07));
  /* animation-fill-mode: forwards держит transform с приоритетом выше обычных
     author-правил (transition > !important > animation > обычные правила) —
     без !important наведение не смогло бы перебить активную анимацию входа. */
  transform: translateX(2px) !important;
  transition: background 160ms ease-out, transform 160ms ease-out;
}

.nav-menu-dropdown-open .nav-menu-item:hover .nav-menu-item-icon,
.nav-menu-dropdown-open .nav-menu-item.active .nav-menu-item-icon {
  color: var(--text);
}

.nav-menu-item-title {
  display: block;
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
}

.nav-menu-dropdown-open .nav-menu-item.active .nav-menu-item-title {
  color: var(--accent-grad-to);
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .nav-menu-dropdown-open .nav-menu-item.active .nav-menu-item-title {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

.nav-menu-item-desc {
  display: block;
  font-size: 11px;
  color: var(--text-dim);
  opacity: 0.8;
  margin-top: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .nav-menu-dropdown,
  .nav-menu-backdrop,
  .nav-menu-item {
    transition: none !important;
    animation: none !important;
  }

  /* animation: none убирает саму анимацию входа — без этого явного конечного
     состояния меню осталось бы невидимым (opacity: 0 из базового правила). */
  .nav-menu-dropdown.nav-menu-dropdown-open {
    opacity: 1;
    transform: none;
  }

  .nav-menu-backdrop.nav-menu-backdrop-open {
    opacity: 1;
  }

  .nav-menu-dropdown-open .nav-menu-item {
    opacity: 1;
    transform: none;
  }
}

.container {
  max-width: 720px;
  margin: 0 auto;
  padding: 16px 16px 96px;
  /* vh на мобильных считается по высоте экрана БЕЗ учёта адресной строки —
     даёт просвет снизу, когда она видна. dvh учитывает её; vh идёт первым
     как фолбэк для браузеров без поддержки dvh (invalid-value просто
     игнорируется, второе объявление тогда не применяется). */
  min-height: 100vh;
  min-height: 100dvh;
}

.page-title {
  font-size: var(--font-size-page-title);
  margin: 8px 0 var(--space-md);
}

.section-heading {
  font-size: var(--font-size-section-heading);
  font-weight: 700;
  margin: var(--space-lg) 0 4px;
}

.back-link {
  display: inline-block;
  color: var(--text-dim);
  margin-bottom: 8px;
  padding: 6px 0;
}

.empty {
  color: var(--text-dim);
  text-align: center;
  margin-top: 40px;
}

.section-disabled-card {
  text-align: center;
  padding: 40px 20px;
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.section-disabled-icon { font-size: 40px; }

.section-disabled-text {
  color: var(--text-dim);
  max-width: 420px;
  margin: 0 0 6px;
}

/* Tabs */
.toolbar-row { display: none; }

.scale-toggle { display: none; }

.scale-toggle-btn {
  padding: 8px 12px;
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}

.scale-toggle-btn.active {
  background: var(--accent-gradient);
  color: var(--accent-text);
  border-color: transparent;
}

.zoom-toggle { display: none; }

.zoom-toggle-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 16px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.zoom-toggle-value {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
  min-width: 42px;
  text-align: center;
}

.tabs {
  display: flex;
  gap: 8px;
  margin-bottom: var(--space-md);
}

.journal-summary-line {
  color: var(--text-dim);
  font-size: 13px;
  margin: 0 0 var(--space-md);
}

.journal-machine-filter {
  margin-bottom: var(--space-md);
}

.journal-machine-filter select {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  padding-right: 40px;
  border: 1px solid var(--border);
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239aa2ad' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

/* Нативная стрелка select теряется/обрезается в некоторых мобильных
   WebView вместе с боковыми рамками — appearance: none выше отключает
   отрисовку системного виджета целиком, так что наши border и стрелка
   (SVG-фон) гарантированно видны на всех четырёх сторонах. Цвет стрелки
   зашит в data URI (var() внутри background-image не работает), поэтому
   под светлую тему нужен отдельный SVG. */
:root[data-theme="light"] .journal-machine-filter select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234b5262' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

/* Карточка приветствия — общая для /journal и / (landing.html). */
.card.greeting-card {
  flex-direction: column;
  gap: 16px;
  padding: 18px 20px;
  margin-bottom: var(--space-md);
  background:
    linear-gradient(135deg, rgba(37, 99, 235, 0.08), rgba(139, 92, 246, 0.08)),
    var(--bg-elevated);
}

.greeting-row {
  display: flex;
  align-items: center;
  gap: 14px;
}

.greeting-icon {
  flex-shrink: 0;
  display: block;
}

.greeting-title {
  font-size: 26px;
  font-weight: 700;
  line-height: 1.15;
  margin: 0;
  /* Запасной сплошной цвет, если background-clip: text не поддержится. */
  color: var(--text-dim);
}

.greeting-stats {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
}

.greeting-stat {
  display: flex;
  flex-direction: column;
}

.greeting-stat-value {
  font-size: 26px;
  font-weight: 800;
  line-height: 1;
  color: var(--text-dim);
}

.greeting-stat-label {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 3px;
}

/* Тот же фирменный градиент, что у названия в шапке (.logo-text) — единый
   акцент бренда на приветствии и на его цифрах. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .greeting-title,
  .greeting-stat-value {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

.card.journal-card {
  flex-direction: column;
  padding: 8px;
}

.journal-card-link {
  display: block;
}

.journal-card-top {
  color: var(--text-dim);
  font-size: 12px;
  margin-bottom: 2px;
}

.journal-card-title {
  font-weight: 700;
  font-size: 13.5px;
  margin-bottom: 2px;
}

.journal-card-meta {
  color: var(--text-dim);
  font-size: 13px;
}

.journal-card-comment {
  color: var(--text-dim);
  font-size: 12px;
  font-style: italic;
  margin-top: 2px;
}

.journal-tabs {
  position: relative;
  z-index: 1;
  margin-bottom: 12px;
  max-width: 100%;
  overflow-x: auto;
  flex-wrap: nowrap;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.journal-tabs::-webkit-scrollbar {
  display: none;
}

.journal-tabs .tab {
  flex: 0 0 auto;
  width: max-content;
  min-width: max-content;
  white-space: nowrap;
  padding: 6px 10px;
  font-size: 13px;
}

.tab {
  flex: 1;
  text-align: center;
  padding: 12px 8px;
  border-radius: var(--radius-input);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  font-weight: 600;
  color: var(--text-dim);
}

.tab.active {
  background: var(--accent-gradient);
  color: var(--accent-text);
  border-color: transparent;
}

.admin-new-count {
  margin: 0 0 16px;
  font-weight: 600;
}

.admin-new-count strong {
  color: var(--accent);
}

.status-filter-row {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 4px;
  margin-bottom: var(--space-md);
}

.status-filter-row::-webkit-scrollbar { display: none; }

.status-filter-btn {
  flex: 0 0 auto;
  white-space: nowrap;
  padding: 8px 12px;
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}

.status-filter-btn.active {
  background: var(--accent-gradient);
  color: var(--accent-text);
  border-color: transparent;
}

.search-input {
  display: block;
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: var(--radius-input);
  padding: 14px;
  font-size: 16px;
  font-family: inherit;
  margin-bottom: var(--space-md);
}

.search-input:focus { outline: 2px solid var(--accent); }

/* Cards */
.card-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

#request-list {
  padding-bottom: 70px;
}

#journal-list {
  padding-bottom: 100px;
  gap: 8px;
}

.card {
  display: flex;
  gap: 12px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  padding: 10px;
  box-shadow: var(--card-edge);
  filter: var(--card-depth);
}

/* Приподнятость при наведении — только у кликабельных карточек (<a class="card">,
   список заявок); статичные <div class="card"> подъём не получают, чтобы не
   намекать на кликабельность, которой нет. */
a.card {
  transition: filter var(--lift-transition), transform var(--lift-transition);
}

a.card:hover,
a.card:focus-visible {
  transform: translateY(var(--lift-hover));
  filter: var(--card-depth-hover);
}

a.card:active {
  transform: translateY(var(--lift-active));
  filter: var(--card-depth-active);
}

@media (prefers-reduced-motion: reduce) {
  a.card {
    transition: none !important;
  }

  a.card:hover,
  a.card:focus-visible,
  a.card:active {
    transform: none;
  }
}

/* Подсветка карточки/строки при возврате к списку (см. initScrollRestore()
   в app.js) — фон через background-image, а не background целиком: у чётных
   строк .journal-table цвет задан через background-color, background-image
   его не трогает. Тень — inset: у .card overflow: hidden, обычная внешняя
   тень обрезалась бы (см. заметку у --card-edge выше); inset ничего не
   двигает и не меняет размер карточки. */
@keyframes scroll-highlight-flash {
  0%, 100% {
    background-image: none;
    box-shadow: none;
  }
  15% {
    background-image: linear-gradient(135deg, rgba(37, 99, 235, 0.3), rgba(99, 102, 241, 0.26), rgba(139, 92, 246, 0.24));
    box-shadow: inset 0 0 0 2px rgba(99, 102, 241, 0.55), inset 0 0 26px rgba(139, 92, 246, 0.4);
  }
}

.scroll-highlight {
  animation: scroll-highlight-flash 1.5s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .scroll-highlight {
    animation: none;
    background-image: linear-gradient(135deg, rgba(37, 99, 235, 0.3), rgba(99, 102, 241, 0.26), rgba(139, 92, 246, 0.24));
    box-shadow: inset 0 0 0 2px rgba(99, 102, 241, 0.55), inset 0 0 26px rgba(139, 92, 246, 0.4);
  }
}

.card-thumb {
  width: 84px;
  height: 84px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  background: var(--bg-input);
}

.card-thumb-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  font-size: 11px;
  text-align: center;
}

.card-body {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  justify-content: center;
}

.card-badges {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.card-title {
  font-weight: 700;
  font-size: 16px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-description {
  color: var(--text-dim);
  font-size: 13px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-meta { color: var(--text-dim); font-size: 14px; }

/* Карточка заявки на /requests: сама заявка кликабельна (.request-card-link),
   а кнопка "Забрал" — соседний блок вне ссылки, чтобы не вкладывать
   интерактивный элемент в <a> (см. .admin-card/.admin-card-link — тот же приём). */
.request-card {
  flex-direction: column;
  gap: 8px;
}

.request-card-link {
  display: flex;
  gap: 12px;
}

.request-card-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

.badge-picked { background: rgba(34, 197, 94, 0.18); color: var(--green); }

.stock-take-remaining {
  color: var(--text-dim);
  opacity: 0.75;
}

.stock-take-remaining::before {
  content: " · ";
}
.card-date { color: var(--text-dim); font-size: 12px; }

.card-views,
.table-views,
.detail-views {
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--text-dim);
  font-size: 12px;
}
.detail-views { font-size: 13px; }
.view-eye { opacity: 0.85; }
.buyer-seen-mark {
  margin-left: 2px;
  color: var(--text-dim);
  font-weight: 700;
  cursor: default;
}

/* Badges */
.badge {
  display: inline-block;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.badge-workshop { background: var(--bg-input); color: var(--text-dim); }
.badge-author { background: var(--bg-input); color: var(--text-dim); }
.badge-urgent {
  background: var(--urgent);
  color: #fff;
  animation: urgent-pulse 2s ease-in-out infinite;
}

/* Свечение вокруг плашки "СРОЧНО" через box-shadow (не transform/размер —
   геометрия плашки не меняется), плавно разгорается и гаснет по синусоиде
   ease-in-out. Приглушённое (transparent 45% в пике) — заметно боковым
   зрением, не мельтешит. */
@keyframes urgent-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--urgent), transparent 100%); }
  50% { box-shadow: 0 0 7px 3px color-mix(in srgb, var(--urgent), transparent 45%); }
}

@media (prefers-reduced-motion: reduce) {
  .badge-urgent { animation: none; }
}

.badge-status.status-new { background: var(--gray); color: #fff; }
.badge-status.status-ordered { background: var(--orange); color: #1a1400; }
.badge-status.status-shipping { background: var(--purple); color: #fff; }
.badge-status.status-received { background: var(--green); color: #05230f; }

/* FAB */
.fab {
  position: fixed;
  left: 16px;
  right: 16px;
  /* Такой же приём, что и в .topbar/.app-toast — иначе кнопка проваливается
     под системную полоску снизу (home indicator) на iPhone/в standalone. */
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  max-width: 688px;
  margin: 0 auto;
  background: var(--accent-gradient);
  background-size: 145% 145%;
  background-position: 0% 0%;
  color: var(--accent-text);
  text-align: center;
  padding: 16px;
  border-radius: var(--btn-radius);
  font-weight: 700;
  font-size: 17px;
  box-shadow: var(--shadow-btn), 0 8px 24px rgba(0, 0, 0, 0.4);
  z-index: 20;
  transition: background-position 220ms ease-out, filter 120ms ease-out, transform 120ms ease-out;
}

.fab:hover,
.fab:focus-visible {
  background-position: 100% 100%;
  filter: brightness(1.08);
}

.fab:active {
  filter: brightness(0.88);
  transform: translateY(var(--btn-press));
}

@media (prefers-reduced-motion: reduce) {
  .fab {
    transition: none !important;
  }
}

/* На широких экранах FAB не растягивается на всю ширину контейнера —
   компактная кнопка в правом нижнем углу, не перекрывающая карточки. */
@media (min-width: 900px) {
  .fab {
    left: auto;
    right: 24px;
    bottom: calc(24px + env(safe-area-inset-bottom, 0px));
    max-width: none;
    width: auto;
    margin: 0;
    padding: 14px 22px;
  }
}

.footer-links {
  text-align: center;
  margin-top: 32px;
  padding-bottom: 80px;
}

.admin-link {
  color: var(--text-dim);
  font-size: 12px;
  opacity: 0.5;
  padding: 8px;
}

/* Forms */
.form {
  display: flex;
  flex-direction: column;
}

.field-label {
  font-size: 14px;
  color: var(--text-dim);
  margin: 16px 0 6px;
  font-weight: 600;
}

.text-input {
  background: var(--bg-input);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: var(--radius-input);
  padding: 14px;
  font-size: 16px;
  width: 100%;
  font-family: inherit;
}

.text-input:focus { outline: 2px solid var(--accent); }

/* Клик открывает системный календарь через showPicker() (см. initDatePickerFields
   в app.js) — курсор-указатель сигнализирует, что поле нажимается целиком,
   а не только его правая часть с иконкой. */
input[type="date"].text-input { cursor: pointer; }

#unit_other {
  width: 100%;
  box-sizing: border-box;
  margin-top: 8px;
}

.pin-input {
  text-align: center;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: 10px;
}

.form-checkbox-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 10px 0;
  font-size: 14px;
  cursor: pointer;
}

.qty-stepper {
  display: flex;
  align-items: center;
  gap: 10px;
}

.qty-stepper-btn {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  border-radius: var(--radius-input);
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text);
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}

.qty-stepper-btn:active {
  filter: brightness(0.88);
}

.qty-stepper-input {
  flex: 1;
  text-align: center;
}

.choice-group {
  display: flex;
  gap: 10px;
}

.choice {
  flex: 1;
  text-align: center;
  padding: 16px 8px;
  border-radius: var(--radius-input);
  background: var(--bg-input);
  border: 2px solid var(--border);
  font-weight: 700;
  cursor: pointer;
  position: relative;
}

.choice input {
  position: absolute;
  opacity: 0;
  inset: 0;
  cursor: pointer;
}

.choice:has(input:checked) {
  border-color: var(--accent);
  background: rgba(59,130,246,0.15);
  color: var(--accent);
}

.choice-urgent:has(input:checked) {
  border-color: var(--urgent);
  background: rgba(239,68,68,0.15);
  color: var(--urgent);
}

.file-input {
  background: var(--bg-input);
  border: 1px dashed var(--border);
  border-radius: var(--radius-input);
  padding: 14px;
  color: var(--text-dim);
  width: 100%;
}

.visually-hidden {
  display: none;
}

.photo-buttons {
  display: flex;
  gap: 10px;
}

.photo-btn {
  flex: 1;
  padding: 16px 8px;
  font-size: 14px;
  line-height: 1.3;
}

.photo-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 10px;
}

.photo-preview-item {
  position: relative;
  width: 90px;
  height: 90px;
}

.photo-preview-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  display: block;
}

.photo-preview-file,
.photo-preview-loading {
  width: 100%;
  height: 100%;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 4px;
  text-align: center;
  overflow: hidden;
}

.photo-preview-file-icon {
  font-size: 22px;
  line-height: 1;
}

.photo-preview-file-name,
.photo-preview-loading-text {
  font-size: 10px;
  line-height: 1.2;
  color: var(--text-dim);
  word-break: break-all;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.photo-preview-loading-spinner {
  width: 20px;
  height: 20px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: photo-preview-spin 0.8s linear infinite;
}

@keyframes photo-preview-spin {
  to { transform: rotate(360deg); }
}

.photo-preview-remove {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid var(--bg);
  background: var(--urgent);
  color: #fff;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.photo-edit-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-top: 8px;
}

.photo-edit-item {
  position: relative;
}

.photo-edit-item img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}

.photo-delete-x {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--urgent);
  color: #fff;
  border: 2px solid var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.btn[hidden] {
  display: none;
}

.btn {
  display: inline-block;
  text-align: center;
  border: none;
  border-radius: var(--btn-radius);
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
  /* Стандартный размер по умолчанию — раньше его не было вовсе, и почти
     каждое место использования (.export-btn, .archive-btn и т.д.) заново
     объявляло свои padding/font-size, которые почти совпадали, но не
     точь-в-точь. Теперь совпадают, потому что берутся из одних переменных;
     модификаторы ниже переопределяют размер только там, где он
     действительно другой (.btn-big, .btn-sm). */
  padding: var(--btn-padding-y) var(--btn-padding-x);
  font-size: var(--btn-font-size);
  /* Лёгкий блик сверху (inset) + внешняя глубина — общие для всех кнопок;
     нет overflow: hidden на .btn, так что обычный box-shadow тут не
     обрезается (в отличие от .card, см. --card-depth). */
  box-shadow: var(--shadow-btn);
  transition: transform 120ms ease-out, box-shadow 120ms ease-out, filter 120ms ease-out;
}

.btn:active {
  transform: translateY(var(--btn-press));
  box-shadow: var(--shadow-btn-active);
}

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none !important;
  }

  .btn:active {
    transform: none;
  }
}

.btn-primary {
  background: var(--accent-gradient);
  /* Больше самого блока — чтобы на hover сдвинуть background-position и
     получить видимое "перетекание", а не просто смену двух статичных
     состояний. */
  background-size: 145% 145%;
  background-position: 0% 0%;
  color: var(--accent-text);
  transition: background-position 220ms ease-out, filter 120ms ease-out, transform 120ms ease-out, box-shadow 120ms ease-out;
}

.btn-primary:hover,
.btn-primary:focus-visible {
  background-position: 100% 100%;
  filter: brightness(1.08);
}

.btn-primary:active {
  filter: brightness(0.88);
}

/* Кнопка с обводкой: обычный border градиентом не красится, а border-image
   плохо дружит со скруглением в разных браузерах — вместо этого двойной
   background (тот же приём, что у .nav-menu-dropdown): внутренний слой
   прозрачный и обрезан по padding-box (сквозь него видно то, что за
   кнопкой — карточка или страница, не подбираем цвет вручную), внешний —
   градиент, обрезанный по border-box, поэтому виден только в кольце рамки. */
.btn-secondary {
  border: 2px solid transparent;
  background:
    transparent padding-box,
    var(--accent-gradient) border-box;
  color: var(--accent-grad-to);
  transition: filter 160ms ease-out, transform 120ms ease-out, box-shadow 120ms ease-out;
}

.btn-secondary:hover,
.btn-secondary:focus-visible {
  filter: brightness(1.15);
}

.btn-secondary:active {
  filter: brightness(0.85);
}

.btn-big {
  padding: var(--btn-padding-lg);
  font-size: var(--btn-font-size-lg);
  margin-top: var(--space-lg);
  width: 100%;
}

/* Компактная кнопка — инлайновые действия (тулбары экспорта, строки карточек
   и т.п.). Раньше на это место претендовало полдюжины .xxx-btn с почти, но
   не совсем одинаковыми числами — см. .archive-btn/.status-save-btn/
   .employee-btn/.landing-install-btn ниже, которые теперь
   комбинируются с этим классом вместо своих padding/font-size. */
.btn-sm {
  padding: var(--btn-padding-y-sm) var(--btn-padding-x-sm);
  font-size: var(--btn-font-size-sm);
  border-radius: var(--btn-radius-sm);
}

.export-btn {
  display: inline-block;
  margin-bottom: var(--space-md);
}

.form-error {
  background: rgba(239,68,68,0.15);
  color: var(--urgent);
  border: 1px solid var(--urgent);
  padding: 12px;
  border-radius: var(--radius-sm);
}

.form-success {
  background: rgba(34,197,94,0.15);
  color: var(--green);
  border: 1px solid var(--green);
  padding: 12px;
  border-radius: var(--radius-sm);
}

.settings-hint {
  color: var(--text-dim);
  font-size: 14px;
  margin: 0 0 12px;
}

.sections-manage-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: var(--space-lg);
}

.section-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.section-row-check {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  font-weight: 600;
}

.section-row-check input {
  accent-color: var(--accent);
  width: 18px;
  height: 18px;
}

.section-row-controls {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.section-move-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.section-move-btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.error-box {
  text-align: center;
  margin-top: 40px;
  padding: 24px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.error-code {
  font-size: 15px;
  font-weight: 700;
  color: var(--urgent);
  margin-bottom: 10px;
}

.error-message {
  color: var(--text);
  margin-bottom: 8px;
}

/* Detail page */
.detail-badges {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
}

.detail-meta {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  font-size: 15px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.detail-meta b { color: var(--text-dim); font-weight: 600; }
.detail-description { margin-top: 6px; white-space: pre-wrap; }

.updated-note {
  font-size: 13px;
  color: var(--text-dim);
  font-style: italic;
}

.expected-date {
  font-size: 13px;
  color: var(--text-dim);
}

.expected-date-overdue {
  color: var(--urgent);
  font-weight: 600;
}

.sheet-sync-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--urgent);
  background: rgba(239, 68, 68, 0.1);
  border-radius: var(--radius-xs);
  padding: 6px 10px;
  margin-bottom: 8px;
}

.sheet-sync-badge .btn-link {
  background: none;
  border: none;
  padding: 0;
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
}

/* Текстовое поле даты (не type="date" — см. initCustomDateFields в app.js:
   нужно принимать ручной ввод в двух форматах и подсвечивать поле при
   ошибке, а нативный date-инпут для этого не годится, у него свой
   сегментный ввод) + кнопка-календарь + кнопка очистки в один ряд.
   align-items не задаём — по умолчанию stretch, поэтому кнопки сами
   растягиваются на высоту инпута, без числа в пикселях. */
.date-field {
  display: flex;
  gap: 8px;
}

.date-field-input {
  flex: 1;
  min-width: 0;
  width: auto;
}

.date-field-input.date-field-invalid {
  border-color: var(--urgent);
  background: rgba(239, 68, 68, 0.08);
}

.date-field-btn {
  flex-shrink: 0;
  width: 48px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  background: var(--bg-input);
  color: var(--text);
  font-size: 18px;
  font-family: inherit;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.date-field-btn:focus-visible {
  outline: 2px solid var(--accent);
}

.date-field-clear {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-dim);
}

.date-field-clear:hover {
  color: var(--urgent);
}

/* Сам пикер невидим (открывается только через showPicker() из JS по клику
   на .date-field-pick) — но не display:none и не visibility:hidden: оба
   исключают элемент из рендера, а showPicker() требует, чтобы элемент
   именно рендерился, иначе бросает InvalidStateError. */
.date-field-native {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
  border: none;
  padding: 0;
  margin: 0;
}

/* На случай, если сам факт непустого элемента где-то всё же даёт
   браузеру нарисовать иконку календаря внутри этой 1px-области — второй
   календарь рядом с нашей кнопкой не нужен ни при каких условиях. */
.date-field-native::-webkit-calendar-picker-indicator {
  display: none;
}

.status-comment {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-bottom: 12px;
  font-size: 14px;
  color: var(--text);
}

.status-form-field {
  margin-bottom: 10px;
  grid-column: 1 / -1;
}

.status-save-btn {
  grid-column: 1 / -1;
  margin-bottom: 10px;
}

.supplier-info {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-left: 3px solid var(--orange);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-bottom: var(--space-md);
  font-size: 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.supplier-info b { color: var(--text-dim); font-weight: 600; }
.supplier-info .field-label { margin: 0 0 4px; }

.archive-supplier {
  color: var(--orange);
  font-size: 13px;
  margin-top: 2px;
}

.photo-gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: 14px;
}

.photo-thumb-btn {
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  cursor: pointer;
  aspect-ratio: 1;
  overflow: hidden;
}

.photo-thumb-btn img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.btn-danger {
  background: transparent;
  color: var(--urgent);
  border: 2px solid var(--urgent);
  margin-top: 12px;
}

/* Полноэкранный просмотр фото */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(6, 7, 9, 0.96);
  display: none;
  align-items: center;
  justify-content: center;
}

.lightbox.open { display: flex; }

.lightbox-viewport {
  display: flex;
  width: 100%;
  height: 100%;
  touch-action: none;
}

.lightbox-img {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  object-fit: contain;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.lightbox-close {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 1001;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
}

.lightbox-counter {
  position: absolute;
  top: 22px;
  left: 16px;
  z-index: 1001;
  color: #fff;
  font-size: 14px;
  opacity: 0.8;
}

.lightbox-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 1001;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
}

.lightbox-prev { left: 8px; }
.lightbox-next { right: 8px; }

/* Admin */
.admin-card {
  flex-direction: column;
  gap: 10px;
}

.admin-card-link {
  display: flex;
  gap: 12px;
}

.archive-form { margin-top: 8px; }

.archive-btn {
  width: 100%;
}

.archive-card-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* До 4 кнопок в ряд (К заявке/Остаток/Изменить/Удалить на /admin/stock-takes) —
   на узкой карточке все разом не помещаются, перенос на вторую строку и
   уменьшенный .btn-sm (не трогаем сам .btn-sm — он общий) не дают "Удалить"
   уехать за край карточки, как раньше при overflow: hidden у .card. */
.stock-take-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
  max-width: 100%;
}

.stock-take-card-actions .btn {
  padding: 5px 8px;
  font-size: 11px;
  flex: 0 0 auto;
}

.stock-take-card-actions form {
  margin: 0;
  flex: 0 0 auto;
}


/* Карточки "Итоги по месяцам" переиспользуют .landing-summary-card
   (сводка на главной) — тот же вид, но со словом-месяцем вместо
   числа: крупному .landing-summary-value тут нужен размер поменьше,
   иначе "Сентябрь 2026" не влезает в узкую карточку 2-в-ряд. */
.stock-takes-monthly-month {
  font-size: 16px;
  font-weight: 700;
}

.stock-takes-filter-actions {
  display: flex;
  gap: 10px;
  margin-top: 16px;
}
.stock-takes-filter-actions .btn { flex: 1; }

.status-form {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}

.status-btn {
  padding: 12px 6px;
  border-radius: var(--radius-sm);
  border: 2px solid var(--border);
  background: var(--bg-input);
  color: var(--text-dim);
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  font-family: inherit;
}

.status-btn-active.status-btn-new { border-color: var(--gray); background: rgba(107,114,128,0.2); color: #fff; }
.status-btn-active.status-btn-ordered { border-color: var(--orange); background: rgba(245,158,11,0.2); color: var(--orange); }
.status-btn-active.status-btn-shipping { border-color: var(--purple); background: rgba(168,85,247,0.2); color: var(--purple); }
.status-btn-active.status-btn-received { border-color: var(--green); background: rgba(34,197,94,0.2); color: var(--green); }

@media (min-width: 480px) {
  .status-form { grid-template-columns: repeat(4, 1fr); }
}

.admin-table-wrap {
  max-width: 100%;
  overflow-x: auto;
  border-radius: var(--radius);
  border: 1px solid var(--border);
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--bg-elevated);
  font-size: 14px;
  white-space: nowrap;
}

.admin-table th,
.admin-table td {
  padding: 10px 12px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.admin-table th {
  color: var(--text-dim);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--bg-input);
}

.admin-table tbody tr:last-child td { border-bottom: none; }
.admin-table tbody tr:hover { background: var(--bg-input); }

.push-log-row-warn td:first-child {
  box-shadow: inset 3px 0 0 var(--urgent);
}

.table-thumb {
  width: 40px;
  height: 40px;
  object-fit: cover;
  border-radius: var(--radius-xs);
  display: block;
  background: var(--bg-input);
}

.table-thumb-empty { border: 1px dashed var(--border); }

.table-title-link {
  font-weight: 600;
  color: var(--text);
  white-space: normal;
}
.table-title-link:hover { color: var(--accent-grad-to); }

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .table-title-link:hover {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

.table-description {
  font-size: 12px;
  color: var(--text-dim);
  white-space: normal;
  margin-top: 2px;
}

.table-actions {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.table-status-form {
  display: flex;
  gap: 4px;
}

.table-archive-btn {
  border-color: var(--orange);
}

.table-archive-btn .table-status-label {
  color: var(--orange);
}

.table-status-btn {
  padding: 4px 5px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-input);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  line-height: 1;
}

.table-status-icon { font-size: 13px; }

.table-status-label {
  font-size: 8px;
  font-weight: 600;
  color: var(--text-dim);
  white-space: nowrap;
}

.table-status-btn-active {
  border-color: transparent;
  /* Раньше здесь был захардкожен rgba синего акцента (rgba(59,130,246,...)),
     не завязанный на переменную — при смене --accent на розово-фиолетовый
     тон стал бы просто не тем цветом. */
  background: linear-gradient(135deg, rgba(37, 99, 235, 0.18), rgba(139, 92, 246, 0.18));
}

.table-status-btn-active .table-status-label {
  color: var(--accent-grad-to);
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .table-status-btn-active .table-status-label {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

/* Переключение карточки/таблица в админке: правило размещено в самом конце файла
   и селекторы составные (.card-list.admin-cards-mobile), чтобы гарантированно
   выигрывать и по порядку каскада, и по специфичности у .card-list{display:flex}. */
.journal-table-wrap {
  position: relative;
  z-index: 0;
  max-width: 100%;
  overflow-x: auto;
  border-radius: var(--radius);
  border: 1px solid var(--border);
}

.journal-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}

.journal-table tbody tr:nth-child(even) { background: var(--bg-input); }

/* Фиксированная высота строки: и обычная ячейка, и её editing-состояние
   (текстовый инпут/селект внутри) занимают ровно эту высоту, так что вход
   в редактирование не "толкает" соседние строки. */
.journal-table th,
.journal-table td {
  height: 44px;
}

/* border-collapse у .admin-table позволяет соседней колонке просвечивать
   через шов sticky-колонки на скролле (известная связка багов sticky +
   collapsed borders) — у этой таблицы швы рисуем раздельно. */
.journal-table {
  border-collapse: separate;
  border-spacing: 0;
}

.journal-table th[data-col-key="date"],
.journal-table td[data-field="created_at"] {
  min-width: 140px;
}

.journal-table th[data-col-key="line_no"],
.journal-table td[data-field="line_no"] {
  min-width: 68px;
}

/* Значение центрируется всегда (текст и в обычном режиме, и в select при
   редактировании — text-align наследуется в .cell-input). Горизонтальный
   padding задаём только для неактивного состояния: у editing уже есть
   свой (тот же 6px/28px) через .cell-input, а .editing{padding:0} должен
   остаться в силе, иначе паддинг задвоится и цифра сместится при клике. */
.journal-table td[data-field="line_no"] {
  text-align: center;
}

.journal-table td[data-field="line_no"]:not(.editing) {
  padding-left: 6px;
  padding-right: 28px;
}

/* «Ответственный» тоже стал select при редактировании — ширина колонки под
   самую длинную фамилию из справочника ("Никогосян") плюс место под
   стрелку, тот же гутер 28px справа зарезервирован и в обычном режиме,
   чтобы текст не сдвигался при входе в редактирование. */
.journal-table th[data-col-key="author"],
.journal-table td[data-field="author"] {
  min-width: 130px;
}

.journal-table td[data-field="author"]:not(.editing) {
  padding-right: 28px;
}

/* «Время остановки»/«Время запуска»: короткий формат "11.08 14:20" в
   обычном режиме, но нативный <input type="datetime-local"> в редакторе
   всегда рисует свой полный локализованный текст с годом ("11.08.2026,
   14:20") — браузер это не даёт сократить никаким CSS/HTML, независимо
   от ширины поля. Поэтому вместо сжатия контрола или его выхода поверх
   соседней колонки (то и другое пробовали — обрезает либо перекрывает)
   колонка сразу шире, с запасом под полный формат + место под иконку
   пикера. Контрол остаётся в потоке, width: 100% (общее правило
   .cell-input), сосед никогда не перекрывается. white-space: normal
   вместо общего .resizable-table nowrap+ellipsis — если значение всё же
   не влезло, оно переносится, а не обрезается "…". */
.journal-table th[data-col-key="stopped_at"],
.journal-table td[data-field="stopped_at"],
.journal-table th[data-col-key="started_at"],
.journal-table td[data-field="started_at"] {
  min-width: 220px;
  white-space: normal;
  overflow: visible;
}

/* Изменяемая ширина колонок: table-layout переключается на fixed только после того,
   как JS проставит явные ширины <col> (замер натуральных + сохранённые из localStorage),
   поэтому вид таблицы не "прыгает" в момент инициализации. */
.resizable-table {
  table-layout: fixed;
}

.resizable-table th,
.resizable-table td {
  overflow: hidden;
  text-overflow: ellipsis;
}

.col-resize-handle {
  position: absolute;
  top: 0;
  right: -4px;
  bottom: 0;
  width: 8px;
  cursor: col-resize;
  z-index: 5;
  touch-action: none;
}

.col-resize-handle:hover {
  background: rgba(59, 130, 246, 0.35);
}

body.col-resizing {
  cursor: col-resize;
  user-select: none;
}

body.col-resizing .col-resize-handle {
  background: rgba(59, 130, 246, 0.35);
}

.journal-table-work {
  white-space: normal;
  min-width: 220px;
}

.journal-table-comment {
  white-space: normal;
  min-width: 140px;
}

.journal-row-link-cell {
  width: 56px;
  white-space: nowrap;
  text-align: center;
}

.journal-row-link {
  color: var(--accent-grad-to);
  font-weight: 700;
  font-size: 16px;
  text-decoration: none;
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .journal-row-link {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

.journal-row-delete-btn {
  background: transparent;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 13px;
  padding: 2px 4px;
  border-radius: var(--radius-xs);
  line-height: 1;
  margin-left: 6px;
}

.journal-row-delete-btn:hover {
  color: var(--urgent);
  background: rgba(239, 68, 68, 0.12);
}

.journal-row-delete-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.journal-row-link:hover { text-decoration: underline; }

.journal-sheet-retry-btn {
  background: rgba(239, 68, 68, 0.12);
  border: none;
  color: var(--urgent);
  cursor: pointer;
  font-size: 11px;
  padding: 3px 6px;
  border-radius: var(--radius-xs);
  line-height: 1.3;
  margin-right: 6px;
  white-space: normal;
}

.journal-sheet-retry-btn:disabled {
  opacity: 0.6;
  cursor: default;
}

.journal-cell-editable {
  cursor: text;
  position: relative;
}

.journal-cell-editable:hover {
  background: rgba(59, 130, 246, 0.08);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* Рамка выделения рисуется один раз — на самой ячейке (её реальные
   границы), а не на контроле внутри. padding: 0, чтобы весь бюджет
   фиксированной высоты строки доставался input/select без второго слоя
   отступов поверх высоты строки. */
.journal-cell-editable.editing {
  padding: 0;
  cursor: default;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.journal-cell-editable .cell-input {
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  height: 100%;
  background: transparent;
  border: none;
  box-shadow: none;
  color: var(--text);
  border-radius: 0;
  padding: 0 28px 0 6px;
  font-size: 13px;
  font-family: inherit;
  box-sizing: border-box;
}

.journal-cell-editable .cell-input:focus { outline: none; }

/* Нативная стрелка <select> на некоторых мобильных WebView рисуется без
   учёта нашего padding-right и/или как собственный "чип" с паддингами —
   appearance: none отключает системный виджет целиком, дальше стрелку
   рисуем сами тем же приёмом, что и у .journal-machine-filter select.
   Цвет зашит в data URI (var() внутри background-image не работает),
   поэтому под светлую тему — отдельный SVG. */
.journal-cell-editable select.cell-input {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 12px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239aa2ad' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

:root[data-theme="light"] .journal-cell-editable select.cell-input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234b5262' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

.journal-cell-editable.cell-pending {
  background: rgba(59, 130, 246, 0.18);
}

.journal-cell-editable.cell-flash-success {
  background: rgba(34, 197, 94, 0.35);
  transition: background 0.6s ease;
}

.journal-cell-editable.cell-flash-error {
  background: rgba(239, 68, 68, 0.35);
  transition: background 0.6s ease;
}

/* График смен */
.shifts-today-card {
  flex-direction: column;
  gap: 8px;
  padding: 12px 14px;
  margin-bottom: var(--space-md);
}

.shifts-today-title {
  font-weight: 700;
  font-size: 15px;
}

.shifts-today-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.shifts-today-col { flex: 1; min-width: 140px; }

.shifts-today-label {
  font-weight: 600;
  font-size: 13px;
  color: var(--text-dim);
  margin-bottom: 4px;
}

.shifts-today-person { font-size: 14px; }

.shifts-today-empty {
  font-size: 13px;
  color: var(--text-dim);
}

.shifts-month-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-bottom: var(--space-md);
}

.shifts-month-arrow {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 700;
}

.shifts-month-label {
  font-weight: 700;
  font-size: 16px;
  min-width: 160px;
  text-align: center;
}

.shifts-table { font-size: 13px; }

.shifts-employee-cell {
  min-width: 160px;
  white-space: normal;
}

.shifts-employee-position {
  font-size: 11px;
  color: var(--text-dim);
}

.shifts-table th.shifts-day-head {
  min-width: 34px;
  padding: 6px 1px;
  text-align: center;
}

.shifts-weekday {
  display: block;
  font-size: 9px;
  font-weight: 400;
  text-transform: none;
  color: var(--text-dim);
}

/* tbody tr фиксированной высоты: одинаковая для всех строк, чтобы редактирование
   одной ячейки (см. .shifts-cell-editor ниже, он вынесен из потока через
   position: absolute) не "распирало" именно эту строку и не сдвигало остальные. */
.shifts-table tbody tr {
  height: 34px;
}

.shifts-table td.shifts-day-cell {
  text-align: center;
  white-space: nowrap;
  min-width: 34px;
  padding: 3px 1px;
  font-size: 11px;
  font-weight: 600;
}

.shifts-table td.shifts-day-cell.editing {
  padding: 3px 1px;
  overflow: visible;
}

/* box-shadow, а не background — чтобы не спорить за фон с заливкой типа смены ниже */
.shifts-today-mark { box-shadow: inset 0 0 0 2px var(--accent); }

/* День — тёплый (жёлто-оранжевый), ночь — холодный (сине-фиолетовый), оба приглушённые:
   полупрозрачная заливка поверх фона темы сама даёт нужный муted-тон в любой теме. */
.shifts-table td.shifts-day-cell[data-type="day"] {
  background: rgba(245, 158, 11, 0.2);
}

.shifts-table td.shifts-day-cell[data-type="night"] {
  background: rgba(99, 102, 241, 0.2);
}

/* Выходной — заметно, но не как рабочая смена: буква приглушённо-красная
   (не яркий --urgent, чтобы не резало глаза на тёмном фоне), заливка
   тоже слабее, чем у дня/ночи. Светлая тема — тот же красный, но темнее:
   светло-розовый на белом фоне почти нечитаем. */
.shifts-table td.shifts-day-cell[data-type="day_off"] {
  background: rgba(239, 68, 68, 0.12);
  color: #e29999;
}

:root[data-theme="light"] .shifts-table td.shifts-day-cell[data-type="day_off"] {
  color: #b3261e;
}

.shifts-total-col,
.shifts-total-cell {
  text-align: center;
  font-weight: 700;
  min-width: 70px;
}

/* Тип смены и часы — в одну строку (не друг под другом), а сам редактор
   вынесен из потока (position: absolute) поверх узкой колонки, чтобы не
   растягивать высоту строки и при необходимости перекрывать соседнюю ячейку. */
.shifts-cell-editor {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 2px;
  position: absolute;
  top: 0;
  left: 0;
  min-width: 78px;
  padding: 2px;
  background: var(--bg-elevated);
  border: 1px solid var(--accent);
  border-radius: var(--radius-xs);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  z-index: 3;
}

.shifts-cell-editor select,
.shifts-cell-editor input {
  flex: 1 1 0;
  min-width: 0;
  width: auto;
  background: var(--bg);
  border: 1px solid var(--accent);
  color: var(--text);
  border-radius: var(--radius-xs);
  padding: 2px 3px;
  font-size: 11px;
  font-family: inherit;
  box-sizing: border-box;
}

.shifts-cell-editor select:focus,
.shifts-cell-editor input:focus { outline: none; }

.shifts-cell-clear-btn {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--urgent);
  color: #fff;
  border: 2px solid var(--bg-elevated);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  z-index: 4;
}

.shifts-cell-clear-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.employee-list { gap: 8px; }

.card.employee-card {
  padding: 8px 10px;
}

/* Форма редактирования и форма скрытия — два разных <form>, но display:contents
   убирает их из потока разметки, так что их поля/кнопки становятся прямыми
   элементами грида карточки: ряд 1 — ФИО + Должность, ряд 2 — Сохранить + Скрыть. */
.card.employee-card-active {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 8px;
}

.employee-card-active .employee-edit-form,
.employee-card-active .employee-hide-form {
  display: contents;
}

.employee-input {
  padding: 6px 8px;
  font-size: 13px;
  min-width: 0;
}

.employee-btn {
  white-space: nowrap;
}

.card.employee-card-hidden {
  align-items: center;
  opacity: 0.75;
}

.employee-hidden-info {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

.employee-hidden-name {
  font-weight: 600;
  font-size: 14px;
}

.employee-hidden-position {
  font-size: 12px;
  color: var(--text-dim);
}

/* Справочники журнала (/journal/settings) */
.settings-section {
  margin-bottom: var(--space-lg);
}

.settings-list {
  list-style: none;
  margin: 0 0 10px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.settings-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}

.settings-item-name {
  font-size: 14px;
}

.settings-item-remove {
  background: transparent;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 14px;
  padding: 2px 6px;
  border-radius: var(--radius-xs);
  line-height: 1;
  flex-shrink: 0;
}

.settings-item-remove:hover {
  color: var(--urgent);
  background: rgba(239, 68, 68, 0.12);
}

.settings-item-remove:disabled {
  opacity: 0.5;
  cursor: default;
}

.settings-add-form {
  display: flex;
  gap: 8px;
}

.settings-add-form .text-input {
  flex: 1;
  padding: 10px 12px;
}

.settings-add-btn {
  width: 44px;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  border: none;
  background: var(--accent-gradient);
  color: var(--accent-text);
  font-size: 18px;
  font-weight: 700;
  cursor: pointer;
}

.settings-add-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

#units-machine-select {
  margin-bottom: 10px;
}

.admin-table-wrap.admin-table-desktop { display: none; }

@media (min-width: 600px) and (max-width: 899px) {
  .container {
    max-width: 900px;
    padding-left: 20px;
    padding-right: 20px;
  }

  .card-list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    align-items: stretch;
  }
}

@media (min-width: 900px) {
  .container {
    max-width: 1100px;
    padding-left: 24px;
    padding-right: 24px;
  }

  .container.scale-compact,
  .container.admin-wide.scale-compact {
    max-width: 900px;
  }

  .container.scale-wide,
  .container.admin-wide.scale-wide {
    max-width: 100%;
  }

  .container.scale-list,
  .container.admin-wide.scale-list {
    max-width: 100%;
  }

  .container.scale-list .card-list {
    grid-template-columns: 1fr;
  }

  .container.scale-list .card-thumb {
    width: 120px;
    height: 120px;
    object-fit: cover;
  }

  /* Режим "Список" на /admin: карточки вместо таблицы, как на телефоне */
  .container.scale-list .admin-table-wrap.admin-table-desktop {
    display: none;
  }

  .container.scale-list .card-list.admin-cards-mobile {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
  }

  /* "Список" — таблица скрыта (показаны карточки), но правило для 2-й колонки
     сохранено на случай, если разметка когда-то снова покажет таблицу в этом режиме. */
  .container.scale-list .admin-table-desktop table th:nth-child(2),
  .container.scale-list .admin-table-desktop table td:nth-child(2) {
    width: auto;
  }

  /* "Широкий": жёсткие пиксельные ширины колонок (table-layout: fixed), рассчитанные
     под контейнер 1100px, при max-width: 100% не совпадали с шириной экрана и вместе
     с нерастяжимой группой кнопок статуса раздували таблицу за пределы обёртки.
     Переходим на table-layout: auto — браузер сам распределяет свободное место
     (забирает его "Название"), а min-width держит остальные колонки не уже нужного.
     Компакт/Обычный/Список не трогаем — там всё уже работает. */
  .container.scale-wide .admin-table-desktop table {
    table-layout: auto;
  }

  .container.scale-wide .admin-table {
    font-size: 14px;
  }

  .container.scale-wide .table-thumb {
    width: 56px;
    height: 56px;
    object-fit: cover;
  }

  .container.scale-wide .admin-table-desktop table th:nth-child(1),
  .container.scale-wide .admin-table-desktop table td:nth-child(1) { width: auto; min-width: 80px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(2),
  .container.scale-wide .admin-table-desktop table td:nth-child(2) { width: auto; min-width: 200px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(3),
  .container.scale-wide .admin-table-desktop table td:nth-child(3) { width: auto; min-width: 60px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(4),
  .container.scale-wide .admin-table-desktop table td:nth-child(4) { width: auto; min-width: 70px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(5),
  .container.scale-wide .admin-table-desktop table td:nth-child(5) { width: auto; min-width: 90px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(6),
  .container.scale-wide .admin-table-desktop table td:nth-child(6) { width: auto; min-width: 110px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(7),
  .container.scale-wide .admin-table-desktop table td:nth-child(7) { width: auto; min-width: 90px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(8),
  .container.scale-wide .admin-table-desktop table td:nth-child(8) { width: auto; min-width: 90px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(9),
  .container.scale-wide .admin-table-desktop table td:nth-child(9) { width: auto; min-width: 120px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(10),
  .container.scale-wide .admin-table-desktop table td:nth-child(10) { width: auto; min-width: 80px; }
  .container.scale-wide .admin-table-desktop table th:nth-child(11),
  .container.scale-wide .admin-table-desktop table td:nth-child(11) { width: auto; min-width: 280px; }

  .container.scale-wide .table-actions {
    white-space: nowrap;
  }

  .toolbar-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
    margin-bottom: var(--space-md);
  }

  .scale-toggle {
    display: flex;
    gap: 8px;
  }

  .zoom-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .card-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 12px;
    align-items: stretch;
  }

  .form {
    max-width: 600px;
  }

  .admin-table-desktop table {
    table-layout: fixed;
  }

  .admin-table-desktop table th:nth-child(1),
  .admin-table-desktop table td:nth-child(1) { width: 50px; }   /* Фото */
  .admin-table-desktop table th:nth-child(2),
  .admin-table-desktop table td:nth-child(2) { width: auto; }   /* Название — забирает свободное место */
  .admin-table-desktop table th:nth-child(3),
  .admin-table-desktop table td:nth-child(3) { width: 56px; }   /* Кол-во */
  .admin-table-desktop table th:nth-child(4),
  .admin-table-desktop table td:nth-child(4) { width: 68px; }   /* Цех */
  .admin-table-desktop table th:nth-child(5),
  .admin-table-desktop table td:nth-child(5) { width: 84px; }   /* Срочность */
  .admin-table-desktop table th:nth-child(6),
  .admin-table-desktop table td:nth-child(6) { width: 100px; }  /* Автор */
  .admin-table-desktop table th:nth-child(7),
  .admin-table-desktop table td:nth-child(7) { width: 84px; }   /* Дата */
  .admin-table-desktop table th:nth-child(8),
  .admin-table-desktop table td:nth-child(8) { width: 84px; }   /* Статус */
  .admin-table-desktop table th:nth-child(9),
  .admin-table-desktop table td:nth-child(9) { width: 110px; }  /* Поставщик */
  .admin-table-desktop table th:nth-child(10),
  .admin-table-desktop table td:nth-child(10) { width: 76px; }  /* Ожид. дата */
  .admin-table-desktop table th:nth-child(11),
  .admin-table-desktop table td:nth-child(11) { width: 250px; } /* Действия — по контенту, не растягивается */
}

@media (min-width: 1000px) {
  .container.admin-wide {
    max-width: 1200px;
  }

  .card-list.admin-cards-mobile { display: none; }

  .admin-table-wrap.admin-table-desktop { display: block; }
}

/* Chat */
.chat-history {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: var(--space-md);
}

.chat-msg {
  max-width: 85%;
  padding: 12px 14px;
  border-radius: var(--radius);
  font-size: 15px;
  line-height: 1.4;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.chat-msg-user {
  align-self: flex-end;
  background: var(--accent);
  color: var(--accent-text);
  border-bottom-right-radius: 4px;
}

.chat-msg-assistant {
  align-self: flex-start;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-bottom-left-radius: 4px;
}

.chat-msg-error {
  align-self: flex-start;
  background: rgba(239,68,68,0.15);
  color: var(--urgent);
  border: 1px solid var(--urgent);
}

.chat-msg-pending { color: var(--text-dim); }

.chat-form {
  position: sticky;
  bottom: 12px;
  display: flex;
  gap: 8px;
  background: var(--bg);
  padding-top: 8px;
}

.chat-form .text-input {
  flex: 1;
}

.chat-form .btn {
  flex-shrink: 0;
  padding: 0 20px;
}

/* Chat widget */
.chat-widget-btn {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--accent-gradient);
  color: var(--accent-text);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0,0,0,0.3);
  z-index: 1000;
  padding: 0;
}

.chat-widget-bubble {
  display: none;
  position: fixed;
  bottom: 86px;
  right: 20px;
  max-width: 220px;
  background: var(--bg-elevated);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 12px 14px;
  border-radius: var(--radius);
  border-bottom-right-radius: 4px;
  font-size: 14px;
  line-height: 1.4;
  box-shadow: 0 4px 16px rgba(0,0,0,0.25);
  cursor: pointer;
  z-index: 999;
}

.chat-widget-bubble.visible { display: block; }

.chat-widget-panel {
  position: fixed;
  bottom: 86px;
  right: 20px;
  width: 340px;
  height: 460px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 8px 32px rgba(0,0,0,0.35);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.chat-widget-panel[hidden] { display: none; }

.chat-widget-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  font-weight: 700;
  flex-shrink: 0;
}

.chat-widget-close {
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
}

.chat-widget-panel .chat-history {
  flex: 1;
  overflow-y: auto;
  margin-bottom: 0;
  padding: 12px 14px;
}

.chat-widget-panel .chat-form {
  position: static;
  flex-shrink: 0;
  margin: 0;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
  background: transparent;
}

@media (max-width: 500px) {
  .chat-widget-panel {
    left: 10px;
    right: 10px;
    bottom: 10px;
    top: 10px;
    width: auto;
    height: auto;
  }
}

/* Витрина / */
.landing-greeting-card {
  margin-bottom: var(--space-lg);
}

.landing-tiles {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  margin-bottom: var(--space-lg);
}

.landing-tile {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  transition: transform 200ms ease-out, box-shadow 200ms ease-out, border-color 200ms ease-out;
  /* Свой стиль нажатия на тач-устройствах (.landing-tile:active ниже)
     вместо стандартной синей вспышки браузера. */
  -webkit-tap-highlight-color: transparent;
}

/* Подсказка про жест встряски — абсолютным позиционированием внутри
   нижнего padding плитки (16px), а не в потоке: высота карточки не растёт
   (см. запрос "не увеличивать высоту"). left повторяет отступ тела плитки
   (padding-left + ширина кольца 68px + gap 16px) — держать в синхроне с
   .landing-tile/.landing-tile-ring, если те изменятся. */
.landing-tile-shake-hint {
  position: absolute;
  left: 102px;
  right: 40px;
  bottom: 3px;
  display: block;
  font-size: 12px;
  line-height: 1.3;
  color: var(--text-dim);
  cursor: pointer;
}

.landing-tile-shake-hint[hidden] {
  display: none;
}

.landing-tile-shake-hint-icon {
  display: inline-block;
  font-size: 14px;
  line-height: 1;
  vertical-align: middle;
  margin-right: 6px;
}

@media (min-width: 900px) {
  .landing-tile-shake-hint {
    left: 106px;
    bottom: 5px;
  }
}

.landing-tile:hover,
.landing-tile:focus-visible {
  transform: translateY(-6px);
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.22);
  border-color: var(--accent);
}

.landing-tile:active {
  background: var(--bg-input);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
}

.landing-tile-ring-wrap {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.landing-tile-ring {
  position: relative;
  width: 68px;
  height: 68px;
}

/* Подпись под кольцом — опциональная (макрос tile()'s ring_caption):
   поясняет, что именно измеряет процент, если это не очевидно из
   заголовка плитки (как у "Журнал обслуживания" — заголовок не говорит,
   что кольцо теперь про охват оборудования, а не про сами записи). */
.landing-tile-ring-caption {
  font-size: 10px;
  line-height: 1.2;
  color: var(--text-dim);
  text-align: center;
  max-width: 68px;
}

.landing-tile-icon {
  flex-shrink: 0;
  width: 68px;
  height: 68px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent-gradient);
}

.landing-tile-body {
  flex: 1;
  min-width: 0;
}

.landing-tile-title {
  font-size: 17px;
  font-weight: 700;
}

.landing-tile-desc {
  font-size: 13px;
  color: var(--text-dim);
  margin-top: 2px;
}

.landing-tile-count {
  margin-top: 8px;
  font-size: 13px;
  color: var(--text-dim);
}

.landing-tile-count-num {
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  margin-right: 4px;
}

.landing-tile-arrow {
  flex-shrink: 0;
  font-size: 20px;
  font-weight: 700;
  color: var(--text-dim);
  transition: transform 200ms ease-out, color 200ms ease-out;
}

.landing-tile:hover .landing-tile-arrow,
.landing-tile:focus-visible .landing-tile-arrow {
  color: var(--accent);
  transform: translateX(4px);
}

.landing-summary {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: var(--space-lg);
}

@media (max-width: 899px) {
  .landing-summary {
    grid-template-columns: repeat(2, 1fr);
  }
}

.landing-summary-card {
  position: relative;
  flex-direction: column;
  gap: 0;
  padding: 14px 14px 14px 18px;
}

/* Тонкая фирменная полоска слева — overflow: hidden у .card (базовый
   класс) сам обрежет её по скруглению карточки. */
.landing-summary-card-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--accent-gradient);
}

.landing-summary-card-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.landing-summary-value {
  font-size: 24px;
  font-weight: 800;
  line-height: 1;
  color: var(--text);
}

.landing-summary-label {
  margin-top: 4px;
  font-size: 11px;
  color: var(--text-dim);
}

.landing-summary-progress {
  margin-top: 10px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--bg-input);
  overflow: hidden;
}

.landing-summary-progress-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--accent-gradient);
  width: 0%;
  animation: landing-progress-fill 1s ease-out forwards;
}

@keyframes landing-progress-fill {
  from { width: 0%; }
  to { width: var(--progress-target); }
}

@media (prefers-reduced-motion: reduce) {
  .landing-summary-progress-fill {
    animation: none !important;
    width: var(--progress-target) !important;
  }
}

@media (min-width: 900px) {
  .landing-tiles {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }

  .landing-tile {
    padding: 20px 22px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .landing-tile,
  .landing-tile-arrow {
    transition: none !important;
  }

  .landing-tile:hover,
  .landing-tile:focus-visible,
  .landing-tile:active {
    transform: none;
  }

  .landing-tile:hover .landing-tile-arrow,
  .landing-tile:focus-visible .landing-tile-arrow {
    transform: none;
  }
}

/* Кольцевые диаграммы внутри плиток витрины — чистый CSS (conic-gradient
   + mask-вырезка кольца), без SVG-градиента: заполненность фирменным
   градиентом (--accent-grad-from → -mid2 → -to — в основном синий, как и
   везде), незакрашенная часть — еле заметная тёмная дуга. Промежуточный
   стоп стоит на 70% заполненной дуги (calc(--ring-fill * 0.7)), а не всего
   круга, чтобы пропорция синий/фиолетовый сохранялась именно внутри
   закрашенной части, а не размывалась по всему кольцу.
   --ring-target проставляется инлайн-стилем в landing.html (см. tile()),
   --ring-fill — тот же процент, но анимируется от 0% при загрузке страницы. */
@property --ring-fill {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

.landing-tile-ring-fill {
  --ring-fill: 0%;
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    var(--accent-grad-from) 0%,
    var(--accent-grad-mid2) calc(var(--ring-fill) * 0.7),
    var(--accent-grad-to) var(--ring-fill),
    rgba(0, 0, 0, 0.35) var(--ring-fill) 100%
  );
  -webkit-mask: radial-gradient(circle farthest-side, transparent calc(100% - 7px), #000 calc(100% - 7px));
  mask: radial-gradient(circle farthest-side, transparent calc(100% - 7px), #000 calc(100% - 7px));
  animation: ring-sweep 1.1s ease-out forwards;
}

@keyframes ring-sweep {
  from { --ring-fill: 0%; }
  to { --ring-fill: var(--ring-target); }
}

.landing-tile-ring-percent {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}

@media (prefers-reduced-motion: reduce) {
  .landing-tile-ring-fill {
    animation: none !important;
    --ring-fill: var(--ring-target) !important;
  }
}

/* Блок "Установить приложение": контейнер #landing-install и все три
   .landing-install-item скрыты по умолчанию (hidden в разметке) — JS
   (initInstallPrompt в app.js) открывает ровно один вариант под платформу,
   либо не показывает блок вовсе (уже установлено / браузер не поддерживает). */
.landing-install-item {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  margin-bottom: var(--space-lg);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* [hidden] у UA-стилей той же специфичности (0,1,0), что и класс выше, а
   правило автора всегда выигрывает у правила браузера при равном весе —
   поэтому display:flex "побеждал" hidden и все три блока были видны разом.
   Атрибутный селектор добавляет вес и гарантированно перебивает display:flex. */
.landing-install-item[hidden] {
  display: none;
}

.landing-install-icon {
  flex-shrink: 0;
  color: var(--accent);
}

.landing-install-body {
  flex: 1;
  min-width: 0;
}

.landing-install-title {
  font-size: 15px;
  font-weight: 700;
}

.landing-install-text {
  font-size: 13px;
  color: var(--text-dim);
  margin-top: 2px;
}

.landing-install-btn {
  flex-shrink: 0;
  white-space: nowrap;
}

.push-enable-card {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: var(--space-lg);
}

.push-enable-card[hidden] {
  display: none;
}

.push-enable-body {
  flex: 1;
  min-width: 0;
}

.push-enable-title {
  font-size: 15px;
  font-weight: 700;
}

.push-hint {
  font-size: 13px;
  color: var(--text-dim);
  margin: 2px 0 0;
}

[data-push-enable-btn] {
  flex-shrink: 0;
  white-space: nowrap;
}

.app-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 10px 16px;
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border);
}

.app-banner[hidden] {
  display: none;
}

.app-banner-text {
  flex: 1;
  min-width: 180px;
  font-size: 14px;
}

.app-banner-close {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  font-size: 14px;
}

.app-toast {
  position: fixed;
  left: 50%;
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  max-width: min(90vw, 360px);
  padding: 12px 18px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  font-size: 14px;
  text-align: center;
  z-index: 2100;
}

.app-toast[hidden] {
  display: none;
}

.push-settings-state {
  color: var(--text-dim);
  font-size: 14px;
  margin: 0 0 12px;
}

.push-settings-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 14px 0;
}

.push-settings-form[hidden] {
  display: none;
}

.push-settings-check {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  cursor: pointer;
}

.push-settings-check input {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

#push-settings-disable-btn {
  margin-top: 4px;
}

/* Подвал витрины: только на / (см. {% block footer %} в base.html,
   переопределён исключительно в landing.html) — приглушённый, по центру,
   тонкая линия с затуханием к краям вместо сплошной границы. */
.landing-footer {
  margin-top: 40px;
  padding: 0 16px 36px;
  text-align: center;
}

.landing-footer-line {
  height: 1px;
  max-width: 480px;
  margin: 0 auto 24px;
  background: linear-gradient(to right, transparent, var(--border), transparent);
}

.landing-footer-logo {
  height: 22px;
  width: auto;
  /* Не так приглушённо, как раньше: лого теперь цветное (синие тона), а не
     нейтральная картинка — на почти чёрном фоне при сильном затемнении
     контраст и так на грани, дальше уводить в прозрачность не стоит. */
  opacity: 0.8;
  margin-bottom: 10px;
}

.landing-footer-copyright {
  font-size: 13px;
  color: var(--text-dim);
}

.landing-footer-meta {
  margin-top: 4px;
  font-size: 11px;
  color: var(--text-dim);
  opacity: 0.7;
}

/* Объявления — виджет на / и полная страница /news. */
.news-widget {
  flex-direction: column;
  gap: 10px;
  margin-bottom: var(--space-lg);
}

.news-widget-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.news-widget-heading {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.news-widget-icon {
  flex-shrink: 0;
  display: block;
}

.news-widget-title {
  font-size: 20px;
  font-weight: 800;
  margin: 0;
  /* Сплошной приглушённый — запасной вариант, если background-clip: text
     не поддержится (см. @supports ниже). */
  color: var(--text-dim);
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .news-widget-title {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

/* Точка "новое" — еле заметная пульсация, не мигание. */
.news-widget-new-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent-grad-mid2, var(--accent-grad-to));
  animation: news-dot-pulse 1.8s ease-in-out infinite;
}

@keyframes news-dot-pulse {
  0%, 100% { opacity: 0.35; transform: scale(0.85); }
  50% { opacity: 1; transform: scale(1.15); }
}

@media (prefers-reduced-motion: reduce) {
  .news-widget-new-dot {
    animation: none;
    opacity: 0.9;
  }
}

.news-widget-count {
  flex-shrink: 0;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--bg-input);
  border: 1px solid var(--border);
  color: var(--text-dim);
}

.news-widget-all {
  flex-shrink: 0;
  font-size: 13px;
  color: var(--text-dim);
}

/* Тонкая линия под заголовком, затухающая вправо. */
.news-widget-title-line {
  height: 2px;
  margin-top: 2px;
  background: linear-gradient(90deg, var(--accent-grad-from), var(--accent-grad-to), transparent);
}

.news-write-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
}

/* .form{display:flex} и встроенное правило [hidden]{display:none} — обе
   специфичности (0,1,0), а правило автора побеждает над UA-правилом даже
   при равном весе, поэтому обычный [hidden] на .form сам по себе не
   срабатывает (тот же баг, что был у .nav-menu-item/.landing-install-item). */
.news-write-form[hidden] {
  display: none;
}

.news-widget-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.news-widget-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px 12px;
  background: var(--bg-input);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
}

/* Важное — тёплый янтарный, не красный: красный на тёмном фоне читается
   как ошибка, а это не ошибка, а приоритет. */
.news-widget-item-important {
  border-color: var(--orange);
  background: rgba(245, 158, 11, 0.1);
}

.news-widget-item-body {
  min-width: 0;
}

.news-important-icon {
  flex-shrink: 0;
  color: var(--orange);
  margin-top: 1px;
}

.news-important-check {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
}

.news-important-check input {
  accent-color: var(--orange);
}

.news-widget-text {
  font-size: 15px;
  color: var(--text);
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* Приглушённый синий — тот же оттенок, что у фирменного градиента, но
   смешанный с приглушённым серым текста, а не сам акцент "в лоб". */
.news-first-line {
  font-weight: 700;
}

.news-widget-meta {
  margin-top: 4px;
  font-size: 11px;
  color: color-mix(in srgb, var(--accent-grad-from), var(--text-dim) 50%);
}

.news-widget-empty {
  margin: 0;
  font-size: 13px;
}

.news-card {
  flex-direction: column;
  gap: 4px;
}

.news-card-important {
  border-color: var(--orange);
  background: rgba(245, 158, 11, 0.06);
}

.news-card-header {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.news-text {
  font-size: 17px;
  color: var(--text);
  white-space: pre-wrap;
  word-wrap: break-word;
}

.news-meta {
  display: flex;
  gap: 8px;
  font-size: 12px;
  color: color-mix(in srgb, var(--accent-grad-from), var(--text-dim) 50%);
}

.news-delete-form {
  margin-top: 4px;
}

/* Свёрнутый блок "Завершённые" под основным списком объявлений — плашка без
   фона/рамки (тот же приём, что у .poll-summary-toggle), список раскрывается
   тапом по всей строке. */
.announcements-completed {
  margin-top: 12px;
}

.announcements-completed-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  min-height: 32px;
  padding: 6px 0;
  border: none;
  background: none;
  color: color-mix(in srgb, var(--accent-grad-from), var(--text-dim) 50%);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.announcements-completed-count {
  color: var(--text-dim);
  font-weight: 400;
}


.announcements-completed-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 8px;
}

.announcements-completed-list[hidden] {
  display: none;
}

/* Слегка приглушаем завершённые карточки — читаются как архив, а не как
   актуальная лента. */
.announcements-completed-item {
  opacity: 0.8;
}

.announcements-delete-all-form {
  align-self: flex-start;
}

/* Корзина у завершённого объявления — иконка справа, не текстовая кнопка с
   рамкой (та у активных объявлений остаётся как есть, не трогали). */
.announcements-completed-item .news-delete-form {
  align-self: flex-end;
  margin-top: 0;
}

.news-delete-icon-btn {
  background: none;
  border: none;
  padding: 4px;
  font-size: 16px;
  line-height: 1;
  color: var(--text-dim);
  cursor: pointer;
}

.news-delete-icon-btn:hover {
  color: var(--urgent);
}

/* Калькулятор зарплаты (/payroll) */
.payroll-form {
  margin-bottom: var(--space-lg);
}

.payroll-field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.payroll-result {
  flex-direction: column;
  gap: 14px;
  padding: 16px 18px;
  margin-bottom: var(--space-lg);
}

.payroll-result-main {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.payroll-result-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.payroll-result-value {
  font-size: 20px;
  font-weight: 800;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.payroll-result-label {
  font-size: 12px;
  color: var(--text-dim);
}

.payroll-result-breakdown {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  color: var(--text-dim);
}

.payroll-result-breakdown strong {
  color: var(--text);
  font-weight: 700;
}

.payroll-privacy-note {
  margin: 0 0 var(--space-lg);
  font-size: 12px;
  color: var(--text-dim);
  opacity: 0.7;
  text-align: center;
}

@media (max-width: 500px) {
  .payroll-field-row {
    grid-template-columns: 1fr;
  }

  .payroll-result-main {
    grid-template-columns: 1fr;
  }
}

/* Инструменты (/tools) */
.tools-search {
  margin-bottom: var(--space-md);
}

/* .tab обычно ссылка, здесь ещё и кнопка (переключение вкладок без
   перезагрузки) — сбрасываем шрифт и курсор, background/border у .tab уже
   переопределены явно и перекрывают дефолтные стили кнопки. */
.tab {
  font: inherit;
  cursor: pointer;
}

.tools-employee-card {
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px;
}

.tools-employee-header {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}

.tools-employee-name {
  font-weight: 700;
  font-size: 15px;
}

.tools-employee-position {
  font-size: 12px;
  color: var(--text-dim);
}

.tools-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.tool-item {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-input);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
}

.tool-item-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1;
}

.tool-item-name {
  font-weight: 600;
  font-size: 14px;
  overflow-wrap: break-word;
}

.tool-item-note {
  font-size: 12px;
  color: var(--text-dim);
  overflow-wrap: break-word;
}

.tool-item-delete {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.tool-item-delete:hover,
.tool-item-delete:focus-visible {
  background: color-mix(in srgb, var(--urgent), transparent 88%);
  color: var(--urgent);
}

.tools-add-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.tools-add-name {
  flex: 1 1 120px;
}

.tools-add-note {
  flex: 2 1 160px;
}

.tools-add-save {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: var(--accent-gradient);
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
}

.tools-all-item {
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.tools-all-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.tools-all-owner {
  flex-shrink: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
}

/* Голосования и опросы в объявлениях */
.poll-type-group {
  margin: 4px 0;
}

.choice-sm {
  padding: 8px 6px;
  font-size: 12px;
  font-weight: 600;
}

.poll-options-fields {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 8px;
}

.poll {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.poll-buttons {
  display: flex;
  gap: 8px;
}

.poll-btn {
  flex: 1;
  padding: 8px 10px;
  border-radius: var(--radius-input);
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
}

.poll-btn-for.poll-btn-active {
  border-color: var(--green);
  background: color-mix(in srgb, var(--green), transparent 85%);
  color: var(--green);
}

.poll-btn-against.poll-btn-active {
  border-color: var(--text-dim);
  background: color-mix(in srgb, var(--text-dim), transparent 85%);
  color: var(--text);
}

.poll-hint {
  margin: 0;
  font-size: 12px;
  color: var(--text-dim);
}

.poll-result {
  display: flex;
  align-items: center;
  gap: 8px;
}

.poll-count {
  flex-shrink: 0;
  min-width: 18px;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}

.poll-bar {
  flex: 1;
  height: 4px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--text-dim), transparent 60%);
  overflow: hidden;
}

.poll-bar-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--green);
  transition: width 300ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .poll-bar-fill {
    transition: none;
  }
}

.poll-closed-label {
  margin: 0;
  font-size: 12px;
  color: var(--text-dim);
  font-style: italic;
}

.poll-close-btn {
  align-self: flex-start;
}

/* Внутри .poll-bars (только там, где голосующий видит варианты раскрытыми)
   кнопка — не ещё один вариант, а отдельное действие автора/админа, поэтому
   визуально отбита сверху тонкой границей. */
.poll-bars .poll-close-btn {
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

/* Варианты опроса — список горизонтальных строк (не вертикальные столбики):
   подпись слева, тонкая полоса заливки посередине, процент+число голосов
   справа. Строки просто идут одна под другой, поэтому при любом числе
   вариантов блок не "разъезжается" вбок — растёт только по высоте. */
.poll-bars {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
}

.poll-bar-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 22px;
  padding: 0;
  border: none;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
}

button.poll-bar-row {
  cursor: pointer;
}

button.poll-bar-row:disabled {
  cursor: default;
  opacity: 0.85;
}

.poll-bar-name-wrap {
  display: flex;
  align-items: center;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 42%;
  overflow: hidden;
}

/* Отметка варианта, за который проголосовал текущий пользователь — раньше
   была фиолетовая рамка вокруг всего столбика; в строчном виде рамка вокруг
   узкой строки смотрелась бы странно, поэтому смысл ("это ваш голос")
   перенесён на галочку перед подписью + сама подпись ярче. */
.poll-bar-check {
  display: none;
  flex-shrink: 0;
  margin-right: 3px;
  color: var(--accent);
  font-size: 12px;
}

.poll-bar-mine .poll-bar-check {
  display: inline;
}

.poll-bar-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  line-height: 1.2;
  color: var(--text-dim);
}

.poll-bar-mine .poll-bar-name {
  color: var(--text);
  font-weight: 700;
}

.poll-bar-track {
  position: relative;
  display: block;
  flex: 1;
  min-width: 0;
  height: 4px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--text-dim), transparent 75%);
  overflow: hidden;
}

button.poll-bar-row:hover:not(:disabled) .poll-bar-track {
  background: color-mix(in srgb, var(--text-dim), transparent 60%);
}

.poll-bar-row-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 0%;
  border-radius: var(--radius-pill);
  background: var(--accent-gradient);
  transition: width 300ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .poll-bar-row-fill {
    transition: none;
  }
}

.poll-bar-percent {
  flex: 0 0 auto;
  min-width: 46px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text-dim);
  text-align: right;
  white-space: nowrap;
}

.poll-bar-mine .poll-bar-percent {
  color: var(--text);
}

/* До голосования — только кликабельные подписи, ни полосы, ни процента
   (visibility, не display: место остаётся зарезервировано, и заливка
   после голоса анимируется от реального 0%, а не "выезжает" вместе с
   появлением строки). */
.poll-bars:not(.poll-bars-revealed) .poll-bar-track,
.poll-bars:not(.poll-bars-revealed) .poll-bar-percent {
  visibility: hidden;
}

/* [hidden] — стандартный атрибут с display: none в UA-стилях, но он в самом
   низу приоритета каскада: любое авторское правило с display (а у .poll-bars
   он есть — display: flex) молча его перебивает, и блок остаётся видимым.
   Форсируем display: none явно для всего, что скрывается/раскрывается по
   тапу на плашку опроса — и обнуляем margin/padding/height на всякий
   случай, чтобы даже при каком-то ещё не найденном переопределении display
   свёрнутое состояние не могло удержать за собой высоту. */
.poll-bars[hidden],
.poll-close-link[hidden] {
  display: none;
  margin: 0;
  padding: 0;
  height: 0;
  overflow: hidden;
}

@media (max-width: 500px) {
  .poll-bar-row {
    gap: 6px;
  }

  .poll-bar-percent {
    min-width: 40px;
    font-size: 10px;
  }
}

/* Плашка опроса — просто строка текста (без фона/рамки), как подпись
   автора/даты в .news-meta: сама .poll-summary-line — только flex-обвязка,
   раскрывающая кнопка и ссылка "Завершить опрос" держат общую высоту в
   одну строку и делят её между собой. */
.poll-summary-line {
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}

.poll-summary-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
  /* Вся строка кликабельна (кнопка растянута на всю ширину через flex: 1
     выше), но раньше высота была только line-height без запаса — палец
     промахивался мимо текста и попадал только по стрелке. Вертикальный
     padding даёт честные ~32px тап-таргета, не сдвигая текст влево. */
  padding: 6px 0;
  border: none;
  border-radius: var(--radius-xs);
  background: none;
  color: color-mix(in srgb, var(--accent-grad-from), var(--text-dim) 50%);
  font: inherit;
  font-size: 12px;
  line-height: 20px;
  text-align: left;
  cursor: pointer;
  transition: background 120ms ease-out;
}

.poll-summary-toggle:active {
  background: color-mix(in srgb, var(--text-dim), transparent 85%);
}

.poll-summary-label {
  flex-shrink: 0;
  font-weight: 600;
}

.poll-summary-winner {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
}

.poll-summary-muted {
  font-weight: 400;
  font-style: italic;
}

/* Chevron сворачиваемых строк (плашка опроса, "Завершённые") — круглая
   подложка на самой ссылке (кнопке), поворот — на SVG внутри неё. Это два
   разных элемента специально: :active даёт подложке transform: scale(...),
   а открытое/закрытое состояние — rotate(...) на иконке; если бы оба
   transform жили на одном элементе, они бы не складывались (transform —
   не аддитивное свойство), и нажатие "сбрасывало" бы поворот.
   background — полупрозрачный белый, а не токен темы: подложка должна
   читаться одинаково на любом фоне карточки, а не подстраивать оттенок. */
.chevron-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-left: auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: var(--accent);
  transition: transform 120ms ease-out;
}

.chevron-badge:active {
  transform: scale(0.92);
}

.chevron-icon {
  display: block;
  transition: transform 200ms ease;
}

.poll-summary-open .chevron-icon,
.announcements-completed-open .chevron-icon {
  transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .chevron-badge,
  .chevron-icon {
    transition: none;
  }
}

/* Ссылка "Завершить опрос" — только автору/админу, только когда опрос
   раскрыт (та же [data-poll-toggle-target], что и .poll-bars), в одну
   строку с плашкой, а не отдельным блоком с рамкой. */
.poll-close-link {
  flex-shrink: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-dim);
  font: inherit;
  font-size: 11px;
  line-height: 20px;
  text-decoration: underline;
  cursor: pointer;
}

.poll-close-link:hover {
  color: var(--text);
}

/* Кружки-сторис на главной: последние заявки с фото. */
.stories-strip {
  display: block;
  padding: 14px 10px 8px;
  margin-bottom: var(--space-md);
  background: linear-gradient(
    160deg,
    color-mix(in srgb, var(--accent-grad-mid2) 18%, var(--bg-elevated)),
    color-mix(in srgb, var(--accent-grad-to) 8%, var(--bg-elevated))
  );
  box-shadow:
    var(--card-edge),
    0 0 0 1px color-mix(in srgb, var(--accent-grad-mid2) 38%, transparent),
    0 0 34px -4px color-mix(in srgb, var(--accent-grad-to) 65%, transparent);
}

.stories-row {
  display: flex;
  gap: 14px;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 4px 4px 10px;
  margin: 0;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
}
.stories-row::-webkit-scrollbar {
  display: none;
}

.story-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  width: 64px;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  color: var(--text);
  font: inherit;
}

.story-ring {
  position: relative;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  padding: 2.5px;
  background: var(--accent-gradient);
}

/* Ореол — отдельный круглый слой позади кружка (не box-shadow: тот вместе
   с анимируемым filter на прямоугольном боксе давал квадратный отблеск по
   углам вместо круглого свечения). */
.story-item:not(.story-item-viewed) .story-ring {
  animation: story-ring-shine 3.5s ease-in-out infinite;
}

.story-item:not(.story-item-viewed) .story-ring::after {
  content: "";
  position: absolute;
  inset: -14px;
  border-radius: 50%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    circle,
    color-mix(in srgb, var(--accent-grad-to) 95%, transparent) 0%,
    color-mix(in srgb, var(--accent-grad-to) 40%, transparent) 45%,
    transparent 72%
  );
  opacity: 0;
  animation: story-ring-halo 3.5s ease-in-out infinite;
}

@keyframes story-ring-shine {
  0%, 100% {
    filter: brightness(1) saturate(1);
  }
  50% {
    filter: brightness(1.6) saturate(1.55);
  }
}

@keyframes story-ring-halo {
  0%, 100% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .story-item:not(.story-item-viewed) .story-ring,
  .story-item:not(.story-item-viewed) .story-ring::after {
    animation: none;
  }
  .story-item:not(.story-item-viewed) .story-ring::after {
    opacity: 0;
  }
}

.story-item-viewed .story-ring {
  background: var(--border);
}

.story-avatar {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  display: block;
  border: 2px solid var(--bg);
  background: var(--bg-input);
}

.story-name {
  max-width: 64px;
  font-size: 11px;
  line-height: 1.25;
  color: var(--text-dim);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Полноэкранный просмотр сторис. */
.story-viewer {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: #000;
  display: flex;
  flex-direction: column;
  touch-action: none;
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 280ms cubic-bezier(0.16, 1, 0.3, 1), transform 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.story-viewer[hidden] {
  display: none;
}

.story-viewer-visible {
  opacity: 1;
  transform: scale(1);
}

.story-viewer-closing {
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 180ms ease-in, transform 180ms ease-in;
}

@media (prefers-reduced-motion: reduce) {
  .story-viewer,
  .story-viewer-visible,
  .story-viewer-closing {
    transition: none;
  }
}

.story-viewer-progress {
  display: flex;
  gap: 4px;
  padding: 10px 10px 0;
  flex-shrink: 0;
}

.story-viewer-progress-seg {
  flex: 1 1 0;
  height: 2.5px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.3);
  overflow: hidden;
}

.story-viewer-progress-seg-fill {
  height: 100%;
  width: 0%;
  background: #fff;
}

.story-viewer-close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 5;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  font-size: 16px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.story-viewer-header {
  position: absolute;
  top: 24px;
  left: 14px;
  right: 56px;
  z-index: 5;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

.story-viewer-title {
  font-size: 15px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.story-viewer-author {
  font-size: 12px;
  opacity: 0.85;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.story-viewer-img-wrap {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  min-height: 0;
}

.story-viewer-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}

.story-viewer-nav {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50%;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  z-index: 3;
}

.story-viewer-prev {
  left: 0;
}

.story-viewer-next {
  right: 0;
}

.story-viewer-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-shrink: 0;
  padding: 14px 16px calc(16px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.55), transparent);
  position: relative;
  z-index: 4;
}

.story-viewer-status {
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

.admin-badge {
  flex-shrink: 0;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-text);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}

.admin-unlock-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.55);
}

.admin-unlock-overlay[hidden] {
  display: none;
}

.admin-unlock-modal {
  width: 100%;
  max-width: 320px;
  padding: 20px;
  border-radius: var(--radius-md, 14px);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  box-shadow: 0 10px 30px var(--shadow-near);
}

.admin-unlock-title {
  font-size: 15px;
  font-weight: 600;
  margin-bottom: 12px;
}

.admin-unlock-error {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--urgent);
}

.admin-unlock-error[hidden] {
  display: none;
}

.admin-unlock-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 14px;
}

/* Панель "Забрал" на /requests — выезжает снизу, не по центру (в отличие
   от .admin-unlock-overlay/.admin-unlock-modal, того же по механике оверлея). */
.pickup-sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
}

.pickup-sheet-overlay[hidden] {
  display: none;
}

.pickup-sheet {
  width: 100%;
  max-width: 520px;
  max-height: 88vh;
  overflow-y: auto;
  padding: 20px;
  padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  border-radius: var(--radius-md, 14px) var(--radius-md, 14px) 0 0;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-bottom: none;
  box-shadow: 0 -10px 30px var(--shadow-near);
  animation: pickup-sheet-in 200ms ease-out;
}

@keyframes pickup-sheet-in {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .pickup-sheet {
    animation: none;
  }
}

.pickup-sheet-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}

.pickup-sheet-title {
  font-size: 16px;
  font-weight: 700;
}

.pickup-sheet-subtitle {
  color: var(--text-dim);
  font-size: 13px;
  margin-top: 2px;
}

.pickup-sheet-close {
  background: none;
  border: none;
  font-size: 22px;
  line-height: 1;
  color: var(--text-dim);
  cursor: pointer;
  padding: 4px;
  flex-shrink: 0;
}

.pickup-sheet-error {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--urgent);
}

.pickup-sheet-error[hidden] {
  display: none;
}

.measure-unsupported-text {
  color: var(--text-dim);
  font-size: 15px;
  margin: 0;
}

/* .card задаёт display:flex безусловно — атрибут [hidden] (UA-стиль, низкий
   приоритет) без этого переопределения будет молча проигрывать каскад, и
   элемент останется видимым несмотря на hidden. См. такие же переопределения
   у .btn, .push-enable-card, .announcements-completed-list и т.д. */
#measure-unsupported[hidden] {
  display: none;
}

.measure-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-top: var(--space-md);
}

.measure-grid[hidden] {
  display: none;
}

.measure-tool-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 22px 10px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  box-shadow: var(--card-edge);
  filter: var(--card-depth);
}

.measure-tool-card:active {
  filter: var(--card-depth-active);
  transform: scale(0.98);
}

.measure-tool-card-icon {
  color: var(--accent);
}

.measure-tool-card-title {
  font-size: 15px;
  font-weight: 600;
}

/* Полноэкранная панель инструмента — открывается тапом по карточке из
   .measure-grid, поверх всего (в том числе шапки/меню). display:flex тоже
   безусловный, поэтому та же оговорка про [hidden], что и выше. */
.measure-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  background: var(--bg);
}

.measure-fullscreen[hidden] {
  display: none;
}

.measure-fullscreen-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px calc(14px + env(safe-area-inset-top, 0px));
  padding-top: max(14px, env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.measure-fullscreen-title {
  font-size: 17px;
  font-weight: 700;
}

.measure-fullscreen-close {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text);
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.measure-fullscreen-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 24px 20px calc(24px + env(safe-area-inset-bottom, 0px));
  text-align: center;
}

.measure-orientation-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-width: 320px;
}

.measure-orientation-gate[hidden] {
  display: none;
}

.measure-level {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.measure-level-target {
  position: relative;
  width: 168px;
  height: 168px;
  border-radius: 50%;
  background: var(--bg-input);
  border: 1px solid var(--border);
}

.measure-level-crosshair {
  position: absolute;
  inset: 20px;
  border-radius: 50%;
  border: 1px dashed var(--border);
}

.measure-level-crosshair::before,
.measure-level-crosshair::after {
  content: "";
  position: absolute;
  background: var(--border);
}

.measure-level-crosshair::before {
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  transform: translateX(-50%);
}

.measure-level-crosshair::after {
  top: 50%;
  left: 0;
  right: 0;
  height: 1px;
  transform: translateY(-50%);
}

.measure-level-bubble {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  transition: background-color 150ms ease;
}

.measure-level-bubble.measure-good {
  background: var(--green);
}

.measure-level-values {
  display: flex;
  gap: 20px;
  font-size: 26px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.measure-angle-value {
  font-size: 52px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.measure-plumb {
  position: relative;
  width: 100%;
  max-width: 220px;
  height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.measure-plumb-vertical {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: var(--border);
  transform: translateX(-50%);
}

.measure-plumb-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 4px;
  margin-left: -2px;
  border-radius: 2px;
  background: var(--accent);
  transform-origin: top center;
  transition: background-color 150ms ease;
}

.measure-plumb-line.measure-good {
  background: var(--green);
}

.measure-plumb-value {
  font-size: 40px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.measure-plumb-value.measure-good {
  color: var(--green);
}

.measure-plumb-line.measure-bad {
  background: var(--urgent);
}

.measure-plumb-value.measure-bad {
  color: var(--urgent);
}

.measure-plumb-mm {
  font-size: 18px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.measure-plumb-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 280px;
}

/* Экран не гаснет (Wake Lock — общий, см. measureAcquireWakeLock), а
   touch-action/overscroll блокируют скролл и pull-to-refresh, пока грань
   телефона прижата к стойке. */
.measure-plumb-fullscreen {
  touch-action: none;
  overscroll-behavior: none;
}

.measure-slope-body {
  overflow-y: auto;
  gap: 14px;
}

.measure-slope-settings {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 280px;
}

.measure-slope-settings-label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--text-dim);
  text-align: left;
}

.measure-slope-value {
  font-size: 40px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.measure-slope-mm {
  font-size: 18px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.measure-slope-actions {
  display: flex;
  gap: 10px;
}

.measure-slope-points {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  max-width: 320px;
  max-height: 22vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}

.measure-slope-chart {
  width: 100%;
  max-width: 320px;
  height: 120px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.measure-slope-save {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 280px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.measure-slope-save-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--text-dim);
  text-align: left;
}

.measure-slope-save-status {
  margin: 0;
  font-size: 13px;
  color: var(--text-dim);
  min-height: 1.2em;
}

.measure-slope-history {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--text-dim);
  text-align: left;
}

/* Линейка — единственная панель без .measure-fullscreen-header/-body: шкала
   должна доходить до самого верхнего угла экрана (ноль без отступа) и до
   левого края (метки вплотную к грани телефона), поэтому свой, а не общий
   каркас. touch-action/overscroll — чтобы прикладывание детали к экрану не
   листало страницу и не будило pull-to-refresh. */
.measure-ruler-fullscreen {
  touch-action: none;
  overscroll-behavior: none;
  overflow: hidden;
}

.measure-ruler-calibrate {
  position: relative;
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 24px 20px;
  text-align: center;
}

.measure-ruler-calibrate[hidden],
.measure-ruler-view[hidden] {
  display: none;
}

.measure-ruler-calibrate-close {
  position: absolute;
  top: calc(10px + env(safe-area-inset-top, 0px));
  right: 10px;
}

.measure-ruler-calibrate-hint {
  max-width: 320px;
}

.measure-ruler-calibrate-bar-wrap {
  width: 100%;
  padding: 20px 0;
  display: flex;
  justify-content: center;
  overflow-x: auto;
}

.measure-ruler-calibrate-bar {
  height: 54px;
  background: var(--accent);
  border-radius: 4px;
  flex-shrink: 0;
}

.measure-ruler-calibrate-slider {
  width: 100%;
  max-width: 320px;
}

/* Шкала идёт по всей высоте экрана (длинная сторона телефона в портретной
   ориентации) — ноль в самом верхнем углу, без safe-area отступа, потому что
   тут отступ буквально означает "врёт на N мм". */
.measure-ruler-view {
  position: relative;
  flex: 1;
  min-height: 0;
  width: 100%;
}

.measure-ruler-scale {
  position: absolute;
  inset: 0;
}

.measure-ruler-scale[hidden] {
  display: none;
}

.measure-ruler-tick-v {
  position: absolute;
  height: 1px;
  width: 14px;
  background: var(--text-dim);
}

.measure-ruler-tick-v.measure-ruler-tick-left {
  left: 0;
}

.measure-ruler-tick-v.measure-ruler-tick-right {
  right: 0;
}

.measure-ruler-tick-v.measure-ruler-tick-mid {
  width: 26px;
  background: var(--text);
}

.measure-ruler-tick-v.measure-ruler-tick-cm {
  width: 46px;
  height: 1.5px;
  background: var(--accent);
}

/* Цифры повёрнуты на 90° — читаются, когда телефон повёрнут и лежит вдоль
   измеряемой детали, а не когда смотришь на экран как обычно. */
.measure-ruler-tick-label-v {
  position: absolute;
  font-size: 13px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transform: rotate(90deg);
}

.measure-ruler-tick-label-v.measure-ruler-tick-label-left {
  left: 52px;
  transform-origin: left center;
}

.measure-ruler-tick-label-v.measure-ruler-tick-label-right {
  right: 52px;
  transform-origin: right center;
}

/* Кнопки — в дальнем от шкалы (левого края) и от нуля (верха) углу, то есть
   внизу справа, чтобы не мешать прикладывать деталь. */
.measure-ruler-controls {
  position: absolute;
  right: 10px;
  bottom: calc(10px + env(safe-area-inset-bottom, 0px));
  display: flex;
  align-items: center;
  gap: 10px;
  z-index: 1;
}

.measure-ruler-mini-btn {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  color: var(--text);
  font-size: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.85;
}

.measure-ruler-inch-toggle {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--text-dim);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 8px 12px;
}

.measure-ruler-inch-toggle input {
  width: 14px;
  height: 14px;
}

.measure-stopwatch-time {
  font-size: 56px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.measure-stopwatch-controls {
  display: flex;
  gap: 10px;
}

.measure-stopwatch-laps {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  max-width: 260px;
  max-height: 30vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}

.measure-flashlight-body {
  gap: 24px;
}

.measure-flashlight-btn {
  min-width: 220px;
  padding: 18px 24px;
  font-size: 17px;
}

.measure-flashlight-btn.measure-flashlight-on {
  background: var(--green);
  border-color: var(--green);
}
