/* Smart Beauty — design system for the warehouse terminal & orders board.
   Self-contained, no external fonts/icons/build step — matches the rest
   of frontend/dist. */

/* Палитра: холодные тонированные нейтралы (zinc) как основа + фиолетовый
   как единственный акцент для действий и фирменного знака. Чистый серый
   #808080 выглядит устаревшим — все нейтралы здесь с лёгким холодным
   подтоном, поэтому интерфейс читается как продуктовый, а не как форма. */
:root{
  /* Фирменные цвета компании, с smartbeauty.pro: тёмный сливовый и его
     светлый оттенок. Раньше здесь был просто «модный фиолетовый». */
  --sb-purple:#7f64a9;
  --sb-purple-dark:#522d6a;
  --sb-purple-light:#f3effa;

  /* zinc-шкала */
  --sb-bg:#fafafa;
  --sb-surface:#ffffff;
  --sb-surface-2:#f7f7f8;
  --sb-border:#e6e6e9;
  --sb-border-strong:#d6d6db;
  --sb-text:#18181b;
  --sb-text-muted:#71717a;
  --sb-grey:#a1a1aa;
  --sb-grey-bg:#f4f4f5;

  /* статусы — приглушённые, не «светофорные» */
  --sb-success:#15803d;
  --sb-success-bg:#f0fdf4;
  --sb-warn:#b45309;
  --sb-warn-bg:#fffbeb;
  --sb-error:#b91c1c;
  --sb-error-bg:#fef2f2;
  /* «В пути» — состояние, а не тревога: отдельный синий, чтобы не занимать
     ни успех, ни предупреждение. */
  --sb-info:#1668c4;
  --sb-info-bg:#e4f1ff;

  --sb-radius:14px;
  --sb-radius-sm:10px;
  /* Тени мягче и «дороже»: два слоя, почти нейтральные по цвету. */
  --sb-shadow:0 1px 2px rgba(24,24,27,.04),0 1px 3px rgba(24,24,27,.06);
  --sb-shadow-md:0 2px 4px rgba(24,24,27,.04),0 4px 12px rgba(24,24,27,.06);
  --sb-shadow-lg:0 4px 8px rgba(24,24,27,.04),0 12px 28px rgba(24,24,27,.10);
  --sb-ring:0 0 0 3px rgba(127,100,169,.22);
}

/* Тёмная тема. Не инверсия светлой: фон уходит в холодный графит, а не в
   чёрный, поверхности светлее фона (в темноте «выше» значит светлее),
   акцент чуть светлее — фирменный сливовый на тёмном читается тускло.
   Статусные подложки — полупрозрачные, чтобы не давать грязных плашек. */
:root[data-theme="dark"]{
  /* На тёмном фоне фирменный сливовый читается тускло — берём его же,
     осветлённый, чтобы цвет остался узнаваемым. */
  --sb-purple:#b49ad6;
  --sb-purple-dark:#7f64a9;
  --sb-purple-light:#2a2237;

  --sb-bg:#0e0e11;
  --sb-surface:#18181b;
  --sb-surface-2:#1f1f23;
  --sb-border:#2a2a30;
  --sb-border-strong:#3a3a42;
  --sb-text:#f4f4f5;
  --sb-text-muted:#a1a1aa;
  --sb-grey:#71717a;
  --sb-grey-bg:#232327;

  --sb-success:#4ade80;
  --sb-success-bg:rgba(74,222,128,.12);
  --sb-warn:#fbbf24;
  --sb-warn-bg:rgba(251,191,36,.12);
  --sb-error:#f87171;
  --sb-error-bg:rgba(248,113,113,.12);
  --sb-info:#60a5fa;
  --sb-info-bg:rgba(96,165,250,.14);

  /* В темноте тень почти не видна — глубину задаёт граница поверхности,
     поэтому тени слабее, а не сильнее. */
  --sb-shadow:0 1px 2px rgba(0,0,0,.4);
  --sb-shadow-md:0 2px 8px rgba(0,0,0,.45);
  --sb-shadow-lg:0 8px 28px rgba(0,0,0,.55);
  --sb-ring:0 0 0 3px rgba(139,124,240,.3);
}

/* Системная тема — только если пользователь не выбрал светлую сам. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --sb-purple:#b49ad6;
    --sb-purple-dark:#7f64a9;
    --sb-purple-light:#2a2237;

    --sb-bg:#0e0e11;
    --sb-surface:#18181b;
    --sb-surface-2:#1f1f23;
    --sb-border:#2a2a30;
    --sb-border-strong:#3a3a42;
    --sb-text:#f4f4f5;
    --sb-text-muted:#a1a1aa;
    --sb-grey:#71717a;
    --sb-grey-bg:#232327;

    --sb-success:#4ade80;
    --sb-success-bg:rgba(74,222,128,.12);
    --sb-warn:#fbbf24;
    --sb-warn-bg:rgba(251,191,36,.12);
    --sb-error:#f87171;
    --sb-error-bg:rgba(248,113,113,.12);
    --sb-info:#60a5fa;
    --sb-info-bg:rgba(96,165,250,.14);

    --sb-shadow:0 1px 2px rgba(0,0,0,.4);
    --sb-shadow-md:0 2px 8px rgba(0,0,0,.45);
    --sb-shadow-lg:0 8px 28px rgba(0,0,0,.55);
    --sb-ring:0 0 0 3px rgba(139,124,240,.3);
  }
}

*{box-sizing:border-box}
.sb-body{
  margin:0;
  min-height:100vh;
  background:var(--sb-bg);
  color:var(--sb-text);
  font-family:"Segoe UI",system-ui,-apple-system,sans-serif;
  overflow-x:hidden;
}
.sb-app{min-height:100vh;display:flex;flex-direction:column}

/* ---------- topbar ---------- */
.sb-topbar{
  display:flex;align-items:center;gap:clamp(10px,1.6vw,24px);
  padding:clamp(10px,1.6vw,14px) clamp(14px,2.4vw,28px);background:var(--sb-surface);
  border-bottom:1px solid var(--sb-border);flex-wrap:wrap;
}
.sb-brand{display:flex;align-items:center;gap:12px}
.sb-brand-mark{
  width:40px;height:40px;border-radius:12px;
  background:linear-gradient(135deg,var(--sb-purple),var(--sb-purple-dark));
  color:#fff;display:flex;align-items:center;justify-content:center;
  font-weight:700;font-size:15px;letter-spacing:.5px;
  box-shadow:var(--sb-shadow);
}
.sb-theme-toggle{
  width:36px;height:36px;flex-shrink:0;border-radius:10px;cursor:pointer;
  border:1px solid var(--sb-border);background:var(--sb-surface);
  color:var(--sb-text-muted);font-size:15px;line-height:1;
  display:inline-flex;align-items:center;justify-content:center;
  transition:border-color .12s ease,color .12s ease,transform .12s ease;
}
.sb-theme-toggle:hover{border-color:var(--sb-border-strong);color:var(--sb-text)}
.sb-theme-toggle:active{transform:translateY(1px)}
.sb-theme-toggle:focus-visible{outline:none;box-shadow:var(--sb-ring)}

.sb-brand-name{font-size:15px;font-weight:800;letter-spacing:1.2px}
.sb-brand-sub{font-size:12px;color:var(--sb-text-muted);margin-top:1px}

.sb-order-badge{
  display:flex;align-items:baseline;gap:8px;
  background:var(--sb-purple-light);color:var(--sb-purple-dark);
  padding:8px 18px;border-radius:999px;font-weight:700;
}
.sb-order-badge-label{font-size:12px;font-weight:600;opacity:.8}
.sb-order-badge-num{font-size:17px;letter-spacing:.3px}

.sb-indicators{display:flex;gap:14px;margin-left:auto;flex-wrap:wrap}
.sb-indicator{
  display:flex;align-items:center;gap:6px;font-size:12px;color:var(--sb-text-muted);
  font-weight:600;
}
.sb-dot{width:8px;height:8px;border-radius:50%;background:var(--sb-grey);flex-shrink:0}
.sb-indicator-ok .sb-dot{background:var(--sb-success);box-shadow:0 0 0 3px var(--sb-success-bg)}
.sb-indicator-warn .sb-dot,.sb-indicator-deferred .sb-dot{background:var(--sb-warn);box-shadow:0 0 0 3px var(--sb-warn-bg)}
.sb-indicator-error .sb-dot{background:var(--sb-error);box-shadow:0 0 0 3px var(--sb-error-bg)}
.sb-indicator-unknown .sb-dot{background:var(--sb-grey);box-shadow:0 0 0 3px var(--sb-grey-bg)}

.sb-print-mode{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.sb-print-mode-btn{
  padding:8px 14px;border-radius:20px;border:1px solid var(--sb-border);
  background:var(--sb-surface);font-size:12px;font-weight:700;cursor:pointer;
  color:var(--sb-purple-dark);white-space:nowrap;
}
.sb-print-mode-btn:hover{border-color:var(--sb-purple)}
/* Выключенная настройка приглушена, но остаётся читаемой: это не
   ошибка и не запрет, а выбор человека за столом. */
.sb-print-mode-btn.off{opacity:.6}
/* COM-сканер в боковой панели: подключён — значок и подпись зелёные. */
.sb-side-serial.is-on{color:var(--sb-green,#0E9F6E)}
.sb-side-serial.is-on .sb-side-icon{color:var(--sb-green,#0E9F6E)}
/* COM-сканер подключён — кнопка светится зелёным, как индикатор связи. */
.sb-print-mode-btn.is-on{
  border-color:var(--sb-green,#0E9F6E);
  color:var(--sb-green,#0E9F6E);
  background:color-mix(in srgb,var(--sb-green,#0E9F6E) 10%,var(--sb-surface));
}
/* Панель настройки COM-сканера — всплывает у кнопки. */
.sb-serial-panel{
  position:absolute;z-index:1000;width:260px;
  background:var(--sb-surface);border:1px solid var(--sb-border);
  border-radius:12px;padding:14px;
  box-shadow:0 10px 34px rgba(16,26,45,.18);
  font-size:13px;color:var(--sb-text,#152238);
}
.sb-serial-panel .ssp-row{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.sb-serial-panel .ssp-dot{width:9px;height:9px;border-radius:50%;
  background:var(--sb-border);flex:none}
.sb-serial-panel .ssp-dot.on{background:var(--sb-green,#0E9F6E)}
.sb-serial-panel .ssp-lab{display:flex;flex-direction:column;gap:5px;
  font-size:11.5px;color:var(--sb-text-muted,#7C8CA6);font-weight:600;margin-bottom:8px}
.sb-serial-panel .ssp-baud{padding:8px 10px;border-radius:8px;
  border:1px solid var(--sb-border);background:var(--sb-surface);
  font-size:13px;color:inherit;font-family:inherit}
.sb-serial-panel .ssp-hint{font-size:11.5px;color:var(--sb-text-muted,#7C8CA6);
  line-height:1.5;margin-bottom:12px}
.sb-serial-panel .ssp-actions{display:flex;gap:8px}
.sb-serial-panel .ssp-btn{flex:1;padding:9px 10px;border-radius:9px;
  border:1px solid var(--sb-border);background:var(--sb-surface);
  font-size:12.5px;font-weight:700;cursor:pointer;color:inherit;font-family:inherit}
.sb-serial-panel .ssp-on{background:var(--sb-green,#0E9F6E);color:#fff;border-color:transparent}
.sb-serial-panel .ssp-off{background:var(--sb-red,#E23D57);color:#fff;border-color:transparent}
.sb-serial-panel .ssp-btn:hover{filter:brightness(1.05)}
.sb-serial-panel .ssp-err{margin-top:10px;font-size:12px;color:var(--sb-red,#E23D57)}

/* Меню одинаково на всех экранах и собирается из nav.js: раньше каждая
   страница держала свой список, и было непонятно, куда нажимать. Текущий
   раздел подсвечен — видно, где находишься. */
.sb-nav{display:flex;gap:4px;margin-left:8px;align-items:center;flex-wrap:wrap}
.sb-nav a{
  color:var(--sb-text-muted);text-decoration:none;font-size:13px;font-weight:600;
  padding:7px 12px;border-radius:9px;white-space:nowrap;
}
.sb-nav a:hover{color:var(--sb-text);background:var(--sb-surface-2)}
.sb-nav a.active{background:var(--sb-purple-light);color:var(--sb-purple-dark)}

.sb-nav-more{position:relative}
.sb-nav-more-btn{
  border:none;background:transparent;cursor:pointer;
  color:var(--sb-text-muted);font-size:13px;font-weight:600;
  padding:7px 12px;border-radius:9px;white-space:nowrap;font-family:inherit;
}
.sb-nav-more-btn:hover{color:var(--sb-text);background:var(--sb-surface-2)}
.sb-nav-more-btn.active{background:var(--sb-purple-light);color:var(--sb-purple-dark)}
.sb-nav-menu{
  position:absolute;top:calc(100% + 6px);right:0;z-index:40;min-width:250px;
  background:var(--sb-surface);border:1px solid var(--sb-border);
  border-radius:14px;box-shadow:var(--sb-shadow-lg);padding:6px;
}
/* В выпадающем списке у каждого пункта подпись: названия разделов сами по
   себе не всегда объясняют, что внутри. */
.sb-nav-menu a{display:block;padding:10px 12px;border-radius:10px}
.sb-nav-menu-label{display:block;font-size:13.5px;color:var(--sb-text);font-weight:600}
.sb-nav-menu a.active .sb-nav-menu-label{color:var(--sb-purple-dark)}
.sb-nav-menu-hint{display:block;font-size:11.5px;color:var(--sb-text-muted);margin-top:2px;font-weight:500}

.sb-nav-links{display:flex;gap:4px;align-items:center}
/* Кнопка меню — только на узком экране, где ряд разделов не помещается. */
.sb-nav-burger{
  display:none;width:40px;height:40px;border-radius:11px;cursor:pointer;
  border:1px solid var(--sb-border);background:var(--sb-surface);
  color:var(--sb-text);font-size:18px;line-height:1;font-family:inherit;
}
.sb-nav-burger:active{transform:translateY(1px)}

/* Выдвижная панель: весь список сразу, без горизонтальной прокрутки. */
.sb-drawer{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.45)}
.sb-drawer[hidden]{display:none}
.sb-drawer-panel{
  position:absolute;left:0;top:0;bottom:0;width:min(84vw,320px);
  background:var(--sb-surface);border-right:1px solid var(--sb-border);
  box-shadow:var(--sb-shadow-lg);padding:12px;overflow-y:auto;
  display:flex;flex-direction:column;gap:2px;
}
.sb-drawer-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:6px 8px 12px;
}
.sb-drawer-title{
  font-size:11.5px;font-weight:800;letter-spacing:.6px;text-transform:uppercase;
  color:var(--sb-text-muted);
}
.sb-drawer-close{
  width:34px;height:34px;border-radius:10px;border:1px solid var(--sb-border);
  background:var(--sb-surface);color:var(--sb-text-muted);cursor:pointer;
  font-size:14px;line-height:1;font-family:inherit;
}
.sb-drawer-panel a{
  display:block;padding:13px 14px;border-radius:12px;text-decoration:none;
}
.sb-drawer-panel a:active{background:var(--sb-surface-2)}
.sb-drawer-panel a.active{background:var(--sb-purple-light)}
.sb-drawer-label{display:block;font-size:15px;font-weight:600;color:var(--sb-text)}
.sb-drawer-panel a.active .sb-drawer-label{color:var(--sb-purple-dark)}
.sb-drawer-hint{display:block;font-size:12px;color:var(--sb-text-muted);margin-top:2px}
body.sb-drawer-open{overflow:hidden}

@media (max-width:900px){
  .sb-nav{gap:2px}
  .sb-nav a,.sb-nav-more-btn{padding:6px 9px;font-size:12.5px}
}
@media (max-width:760px){
  /* Горизонтальный ряд прячем целиком вместе с выпадающим «Ещё»: части
     разделов всё равно не видно, а прокручивать шапку неудобно. Остаётся
     одна кнопка, открывающая панель со всем списком. */
  .sb-nav-links,.sb-nav-more{display:none !important}
  .sb-nav-burger{display:inline-flex;align-items:center;justify-content:center}
  .sb-nav{margin-left:auto;flex-wrap:nowrap}
  .sb-topbar{gap:12px;padding:12px 14px;flex-wrap:nowrap}
  .sb-brand-sub{display:none}
}

/* ---------- stepper ----------
   Размеры текучие (clamp): красиво и на большом мониторе, и на маленьком
   сенсорном POS, без отдельных ломающихся брейкпоинтов. */
.sb-stepper{
  display:flex;align-items:flex-start;justify-content:center;gap:0;
  padding:clamp(10px,2.2vw,22px) clamp(10px,3vw,28px) clamp(8px,1.8vw,18px);
  max-width:900px;margin:0 auto;width:100%;
}
.sb-step{display:flex;flex-direction:column;align-items:center;gap:clamp(4px,1vw,8px);
  width:clamp(64px,16vw,150px)}
.sb-step-dot{
  width:clamp(28px,6vw,36px);height:clamp(28px,6vw,36px);border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-weight:700;font-size:clamp(12px,2.4vw,14px);background:var(--sb-grey-bg);color:var(--sb-grey);
  border:2px solid transparent;transition:all .2s ease;flex:none;
}
.sb-step-label{font-size:clamp(9.5px,1.8vw,11.5px);font-weight:700;letter-spacing:.3px;
  color:var(--sb-grey);text-align:center;line-height:1.2}
.sb-step-connector{flex:1;height:2px;background:var(--sb-grey-bg);
  margin-top:clamp(13px,3vw,17px);min-width:10px}

.sb-step-done .sb-step-dot{background:var(--sb-success);color:#fff}
.sb-step-done .sb-step-label{color:var(--sb-success)}
.sb-step-current .sb-step-dot{background:var(--sb-purple);color:#fff;box-shadow:0 0 0 5px var(--sb-purple-light)}
.sb-step-current .sb-step-label{color:var(--sb-purple-dark)}
.sb-step-skipped .sb-step-dot{background:var(--sb-grey-bg);color:var(--sb-grey);opacity:.5}
.sb-step-skipped .sb-step-label{color:var(--sb-grey);opacity:.5;text-decoration:line-through}

/* ---------- main / stage ---------- */
.sb-main{flex:1;display:flex;justify-content:center;padding:clamp(6px,1.5vw,8px) clamp(12px,3vw,28px) clamp(16px,3vw,32px)}
.sb-stage-col{width:100%;max-width:680px;display:flex;flex-direction:column;gap:clamp(10px,2vw,18px);align-items:stretch}

.sb-card{
  background:var(--sb-surface);border-radius:var(--sb-radius);
  box-shadow:var(--sb-shadow);border:1px solid var(--sb-border);
}

.sb-stage{padding:clamp(18px,4vw,44px) clamp(14px,3vw,32px);text-align:center;display:flex;flex-direction:column;align-items:center;gap:6px}
.sb-stage-icon{
  width:clamp(56px,13vw,96px);height:clamp(56px,13vw,96px);border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--sb-purple-light);color:var(--sb-purple);margin-bottom:clamp(4px,1.5vw,8px);flex:none;
}
.sb-stage-icon svg{width:50%;height:50%}
.sb-stage-icon.icon-success{background:var(--sb-success-bg);color:var(--sb-success)}
.sb-stage-icon.icon-error{background:var(--sb-error-bg);color:var(--sb-error)}
.sb-stage-icon.icon-warn{background:var(--sb-warn-bg);color:var(--sb-warn)}
.sb-stage-icon.icon-spin svg{animation:sb-spin 1s linear infinite}
@keyframes sb-spin{to{transform:rotate(360deg)}}

.sb-stage-title{font-size:clamp(21px,4.2vw,30px);font-weight:800;margin:0;letter-spacing:.2px;text-wrap:balance}
.sb-stage.state-error .sb-stage-title{color:var(--sb-error)}
.sb-stage.state-success .sb-stage-title{color:var(--sb-success)}
.sb-stage-sub{font-size:clamp(13px,2.6vw,15px);color:var(--sb-text-muted);margin:0;white-space:pre-line;max-width:440px}
.sb-stage-extra:empty{display:none}

/* Ввод срока годности — единственное место в терминале, где печатают
   руками, поэтому поле крупное и попадает под палец без прицеливания. */
.term-expiry{display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:20px}
.term-expiry-input{
  font-size:32px;font-weight:700;padding:16px 24px;text-align:center;
  border:2px solid var(--sb-border-strong);border-radius:14px;
  background:var(--sb-surface);color:var(--sb-text);min-width:280px;
  font-variant-numeric:tabular-nums;
}
.term-expiry-input:focus{outline:none;border-color:var(--sb-purple);box-shadow:var(--sb-ring)}
.term-expiry-hint{font-size:13px;color:var(--sb-text-muted)}
/* Подсказка, ставшая требованием. Тот же текст на том же месте, но
   цветом ошибки: человек уже нажал кнопку и ждёт объяснения там, куда
   смотрит, — а смотрит он на поле, а не на кнопку. */
.term-expiry-hint.term-expiry-need{color:var(--sb-error);font-weight:700}

/* Тач-выбор месяца и года — для маленьких сенсорных POS без клавиатуры.
   Клавиатурный ввод выше остаётся; это второй путь, не замена. */
.term-pick-lbl{font-size:11px;font-weight:800;letter-spacing:.5px;
  text-transform:uppercase;color:var(--sb-text-muted);margin-top:6px;align-self:center}
.term-pick{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;max-width:520px}
.term-pick-mon{max-width:360px}
.term-pick-b{
  border:1.5px solid var(--sb-border);background:var(--sb-surface);color:var(--sb-text);
  border-radius:12px;padding:12px 16px;font-size:17px;font-weight:700;cursor:pointer;
  font-family:inherit;min-width:64px;min-height:52px;
}
.term-pick-mon .term-pick-b{min-width:74px}
.term-pick-b:hover{border-color:var(--sb-purple)}
.term-pick-b:active{transform:translateY(1px)}
.term-pick-b.on{
  background:var(--sb-purple);border-color:var(--sb-purple);color:#fff;
  box-shadow:0 4px 14px rgba(0,0,0,.18);
}

.sb-stage.state-success{background:linear-gradient(180deg,var(--sb-success-bg),var(--sb-surface))}
.sb-stage.state-error{background:linear-gradient(180deg,var(--sb-error-bg),var(--sb-surface))}

.sb-candidate-list{display:flex;flex-direction:column;gap:10px;width:100%;margin-top:12px}
.sb-candidate{
  display:flex;justify-content:space-between;align-items:center;
  background:var(--sb-purple-light);border-radius:var(--sb-radius-sm);padding:14px 18px;text-align:left;
}
.sb-candidate b{color:var(--sb-purple-dark);font-size:20px;margin-right:12px}
.sb-candidate span{font-size:14px;color:var(--sb-text-muted)}

/* ---------- item card ---------- */
.sb-item-card{display:flex;gap:24px;padding:24px}
.sb-item-photo-wrap{
  position:relative;flex-shrink:0;width:200px;height:200px;border-radius:var(--sb-radius-sm);
  background:var(--sb-grey-bg);display:flex;align-items:center;justify-content:center;overflow:hidden;
}
.sb-item-photo{width:100%;height:100%;object-fit:contain;display:none}
.sb-item-photo[src]:not([src=""]){display:block}
.sb-item-photo-placeholder{color:var(--sb-grey)}
.sb-item-photo[src]:not([src=""]) + .sb-item-photo-placeholder{display:none}

.sb-item-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px}
.sb-item-badges{display:flex;gap:8px;margin-bottom:2px}
.sb-chip{
  display:inline-flex;align-items:center;padding:4px 12px;border-radius:999px;
  font-size:11.5px;font-weight:700;letter-spacing:.3px;background:var(--sb-grey-bg);color:var(--sb-text-muted);
}
.sb-chip.chip-marking{background:var(--sb-purple-light);color:var(--sb-purple-dark)}
.sb-chip.chip-no-marking{background:var(--sb-grey-bg);color:var(--sb-text-muted)}
.sb-chip.chip-task{background:var(--sb-surface);color:var(--sb-text-muted);border:1px solid var(--sb-border)}
/* Сколько ещё таких же заданий в очереди — подсказка «бери сразу пачку». */
.sb-chip.chip-queue{background:var(--sb-info-bg);color:var(--sb-info)}
/* Срок показывается, только когда поджимает, поэтому цвет тревожный. */
.sb-chip.chip-deadline{background:var(--sb-warn-bg);color:var(--sb-warn)}
.sb-chip.chip-deadline.overdue{background:var(--sb-error);color:#fff}
.sb-item-badges{flex-wrap:wrap}

.sb-item-title{font-size:20px;font-weight:700;line-height:1.3}
.sb-item-brand{font-size:14px;color:var(--sb-purple-dark);font-weight:600}
.sb-item-meta{display:grid;grid-template-columns:1fr 1fr;gap:8px 20px;margin-top:8px}
.sb-item-meta div{display:flex;flex-direction:column;gap:1px}
.sb-item-meta dt{font-size:11px;color:var(--sb-text-muted);text-transform:uppercase;letter-spacing:.3px}
.sb-item-meta dd{margin:0;font-size:14.5px;font-weight:600}

/* ---------- checklist ---------- */
.sb-checklist{display:flex;flex-direction:column;gap:10px;padding:20px 24px}
.sb-check-item{display:flex;align-items:center;gap:12px;font-size:15px;font-weight:600;color:var(--sb-grey)}
.sb-check-item .sb-check-dot{
  width:24px;height:24px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;
  background:var(--sb-grey-bg);color:var(--sb-grey);font-size:13px;
}
.sb-check-item.done{color:var(--sb-text)}
.sb-check-item.done .sb-check-dot{background:var(--sb-success);color:#fff}
.sb-check-item.pending .sb-check-dot{background:var(--sb-purple-light);color:var(--sb-purple)}
.sb-check-item.fail{color:var(--sb-error)}
.sb-check-item.fail .sb-check-dot{background:var(--sb-error);color:#fff}

/* ---------- buttons ----------
   Главная кнопка: плотный градиент, тонкая внутренняя подсветка сверху
   (даёт объём без «пластика»), тень как у поднятой поверхности. При
   нажатии опускается на 1px и теряет тень — как физическая клавиша. */
.sb-btn-primary{
  padding:clamp(14px,3vw,20px) clamp(18px,3vw,24px);font-size:clamp(16px,3vw,19px);
  font-weight:700;letter-spacing:.2px;min-height:52px;
  background:linear-gradient(180deg,var(--sb-purple),var(--sb-purple-dark));color:#fff;
  border:none;border-radius:12px;cursor:pointer;
  box-shadow:var(--sb-shadow-md),inset 0 1px 0 rgba(255,255,255,.18);
  transition:transform .12s cubic-bezier(.4,0,.2,1),box-shadow .12s ease,filter .12s ease;
}
.sb-btn-primary:hover{filter:brightness(1.05)}
.sb-btn-primary:active{transform:translateY(1px);box-shadow:var(--sb-shadow)}
.sb-btn-primary:focus-visible{outline:none;box-shadow:var(--sb-shadow-md),var(--sb-ring)}
.sb-btn-primary.secondary{
  background:var(--sb-surface);color:var(--sb-text);box-shadow:var(--sb-shadow);
  border:1px solid var(--sb-border);font-size:14px;padding:13px 18px;font-weight:600;
}
.sb-btn-primary.secondary:hover{border-color:var(--sb-border-strong);filter:none;background:var(--sb-surface-2)}
.sb-secondary-actions{display:flex;flex-direction:column;gap:10px}

.sb-hint{text-align:center;color:var(--sb-text-muted);font-size:13.5px;margin:0}
.sb-key{
  display:inline-block;background:var(--sb-grey-bg);border-radius:5px;padding:1px 7px;
  font-size:11px;font-weight:700;margin-left:6px;
}

.sb-btn-cancel{
  position:fixed;top:80px;right:28px;
  background:var(--sb-surface);color:var(--sb-error);border:1px solid var(--sb-border);
  border-radius:999px;padding:10px 18px;font-size:13px;font-weight:700;cursor:pointer;
  box-shadow:var(--sb-shadow);display:flex;align-items:center;gap:6px;
}
.sb-btn-cancel:hover{background:var(--sb-error-bg)}

/* ---------- shift panel ---------- */
.sb-shift-panel{
  position:fixed;left:20px;bottom:20px;background:var(--sb-surface);
  border:1px solid var(--sb-border);border-radius:var(--sb-radius-sm);
  padding:14px 18px;box-shadow:var(--sb-shadow);min-width:190px;
}
.sb-shift-title{font-size:10.5px;font-weight:800;letter-spacing:.6px;color:var(--sb-text-muted);margin-bottom:8px;text-transform:uppercase}
.sb-shift-stats{display:grid;grid-template-columns:1fr 1fr;gap:8px 16px}
.sb-shift-stat-num{font-size:19px;font-weight:800;line-height:1.1}
.sb-shift-stat-lbl{font-size:10.5px;color:var(--sb-text-muted);margin-top:1px}
.sb-shift-stat-num.warn{color:var(--sb-warn)}

.sb-ws-badge{
  position:fixed;right:20px;bottom:20px;font-size:11px;color:var(--sb-text-muted);
  background:var(--sb-surface);border:1px solid var(--sb-border);border-radius:999px;padding:6px 14px;
}

.sb-scan-input{
  position:fixed;bottom:0;left:0;width:100%;padding:10px;font-size:13px;
  border:none;outline:none;background:var(--sb-purple-dark);color:#fff;text-align:center;opacity:.55;
}
.sb-scan-input:focus{opacity:1}

@media (max-width:900px){
  .sb-indicators{display:none}
  .sb-shift-panel{position:static;margin:16px auto 0}
  .sb-item-card{flex-direction:column}
  .sb-item-photo-wrap{width:100%;height:220px}
}

/* Нестандартный экран рабочего места: монитор в портрете или низкий.
 * Тогда фиксированные панели в углах (смена, рабочее место) налезают на
 * центральную карточку и закрывают собой цель сканера и кнопки. На таких
 * экранах ставим их в поток — под содержимым, а не поверх него, — и даём
 * запас снизу, чтобы полоса ввода сканера ничего не перекрывала.
 * 17.08: на повёрнутом мониторе склада панель смены закрывала кнопку. */
@media (orientation:portrait), (max-height:760px){
  .sb-shift-panel{position:static;margin:16px auto 0;width:max-content;max-width:100%}
  .sb-ws-badge{position:static;display:block;margin:10px auto 0;width:max-content}
  .sb-main{padding-bottom:64px}
}
/* Панели-подсказки в углах не должны перехватывать нажатия по содержимому
 * даже там, где визуально не мешают: клик всегда достаётся тому, на что
 * человек целится, а не панели под курсором. */
.sb-shift-panel, .sb-ws-badge{z-index:1}
.sb-scanbtn{position:relative;z-index:2}

/* Низкий экран рабочего места (маленький сенсорный POS): ужимаем по
 * вертикали, чтобы весь шаг влезал без прокрутки — иконка, заголовок и
 * кнопка на одном экране. Ширину не трогаем, только высоту. */
@media (max-height:680px){
  .sb-stepper{padding:6px 12px 4px}
  .sb-stage{padding:clamp(12px,2.5vh,20px) 16px}
  .sb-stage-icon{width:clamp(44px,9vh,64px);height:clamp(44px,9vh,64px);margin-bottom:2px}
  .sb-stage-title{font-size:clamp(19px,3.5vh,24px)}
  .sb-stage-sub{font-size:13px}
  .sb-main{padding-top:2px}
  .sb-stage-col{gap:10px}
}

/* ---------- компактная шапка на телефоне ----------
   На узком экране бренд в две строки и горизонтальное меню не помещались:
   навигация уезжала за правый край. Логотип ужимаем в одну строку, меню
   переносим отдельной строкой во всю ширину. */
@media (max-width:760px){
  .sb-topbar{
    flex-wrap:wrap;gap:10px 14px;padding:10px 14px;
    position:sticky;top:0;z-index:20;
  }
  .sb-brand{gap:9px}
  .sb-brand-mark{width:32px;height:32px;border-radius:9px;font-size:12px}
  .sb-brand-name{font-size:12.5px;letter-spacing:.8px}
  .sb-brand-sub{display:none}
  .sb-order-badge{padding:5px 12px;order:2}
  .sb-order-badge-label{display:none}
  .sb-order-badge-num{font-size:14px}
  .sb-print-mode{order:3;margin-left:auto}
  .sb-print-mode-btn{padding:6px 11px;font-size:11px}

  .sb-nav{
    order:5;width:100%;margin-left:0;gap:0;
    display:flex;overflow-x:auto;scrollbar-width:none;
    border-top:1px solid var(--sb-border);padding-top:8px;margin-top:2px;
  }
  .sb-nav::-webkit-scrollbar{display:none}
  .sb-nav a{
    flex:1 0 auto;text-align:center;padding:8px 14px;font-size:13px;
    white-space:nowrap;
  }
}

/* Инструкция «что делать» на экранах ошибок терминала. Без неё оператор
   знает, что что-то не так, но не знает, как выйти из положения. */
.term-howto{
  margin-top:18px;text-align:left;max-width:460px;
  background:var(--sb-surface-2);border:1px solid var(--sb-border);
  border-radius:14px;padding:16px 18px;
}
.term-howto-title{
  font-size:11.5px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;
  color:var(--sb-text-muted);margin-bottom:10px;
}
.term-howto-steps{margin:0;padding-left:20px;font-size:15px;line-height:1.55}
.term-howto-steps li{margin-bottom:6px}
.term-howto-note{
  font-size:13px;color:var(--sb-text-muted);margin-top:10px;line-height:1.5;
  padding-top:10px;border-top:1px solid var(--sb-border);
}

/* ---------- выбор текущей партии ---------- */
.sb-supply-pick{position:relative;display:flex;align-items:center}
.sb-supply-btn{
  padding:8px 14px;border-radius:20px;border:1px solid var(--sb-border);
  background:var(--sb-surface);font-size:12px;font-weight:700;cursor:pointer;
  color:var(--sb-text-muted);white-space:nowrap;max-width:280px;
  overflow:hidden;text-overflow:ellipsis;
}
.sb-supply-btn:hover{border-color:var(--sb-border-strong);color:var(--sb-text)}
/* Выбранная партия подсвечена: сборщик должен видеть, что пикинг ограничен,
   иначе «товар не найден» будет выглядеть загадкой. */
.sb-supply-btn.active{
  background:var(--sb-purple-light);color:var(--sb-purple-dark);
  border-color:transparent;
}
.sb-supply-menu{
  position:absolute;top:calc(100% + 8px);left:0;z-index:30;min-width:320px;
  background:var(--sb-surface);border:1px solid var(--sb-border);
  border-radius:14px;box-shadow:var(--sb-shadow-lg);padding:6px;
}
.sb-supply-item{
  display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  width:100%;padding:11px 14px;border:none;background:transparent;cursor:pointer;
  border-radius:10px;text-align:left;font-size:13.5px;color:var(--sb-text);
}
.sb-supply-item:hover{background:var(--sb-surface-2)}
.sb-supply-item.active{background:var(--sb-purple-light);color:var(--sb-purple-dark)}
.sb-supply-item-name{font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sb-supply-item-num{font-size:12px;color:var(--sb-text-muted);white-space:nowrap;font-variant-numeric:tabular-nums}
.sb-supply-item.active .sb-supply-item-num{color:var(--sb-purple-dark)}
.sb-supply-empty{padding:14px;font-size:13px;color:var(--sb-text-muted);text-align:center}

/* Логотип кликабелен и ведёт на сводку — привычное «домой». */
.sb-brand-link{cursor:pointer;border-radius:12px;transition:opacity .12s ease}
.sb-brand-link:hover{opacity:.82}
.sb-brand-link:focus-visible{outline:none;box-shadow:var(--sb-ring)}

/* ---------- выбор партии на главном экране терминала ----------
   Сборщик смотрит в центр экрана, а не в шапку. Поэтому вопрос «какую
   партию собираем» задаётся здесь крупно, а не прячется в кнопке вверху. */
.term-supply-pick{margin-top:22px;width:100%;max-width:520px}
.term-supply-ask{
  font-size:13px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;
  color:var(--sb-text-muted);margin-bottom:12px;
}
.term-supply-list{display:flex;flex-direction:column;gap:10px}
.term-supply-choice{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  width:100%;padding:18px 22px;border-radius:14px;cursor:pointer;
  border:2px solid var(--sb-border);background:var(--sb-surface);
  font-family:inherit;text-align:left;
  transition:border-color .12s ease,transform .12s ease;
}
.term-supply-choice:hover{border-color:var(--sb-purple)}
.term-supply-choice:active{transform:translateY(1px)}
.term-supply-choice-name{font-size:17px;font-weight:700;color:var(--sb-text)}
.term-supply-choice-num{
  font-size:14px;font-weight:700;color:var(--sb-purple-dark);white-space:nowrap;
  background:var(--sb-purple-light);padding:6px 14px;border-radius:20px;
}
.term-supply-choice.all .term-supply-choice-num{
  background:var(--sb-grey-bg);color:var(--sb-text-muted);font-weight:600;
}

/* Выбранная партия: видно название и сколько осталось — это и есть тот
   счётчик, ради которого партию выбирают. */
.term-supply-now{
  margin-top:20px;width:100%;max-width:520px;
  background:var(--sb-surface-2);border:1px solid var(--sb-border);
  border-radius:14px;padding:16px 20px;
}
.term-supply-now-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
.term-supply-now-label{
  font-size:11.5px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;
  color:var(--sb-text-muted);
}
.term-supply-change{
  border:none;background:transparent;cursor:pointer;font-family:inherit;
  font-size:12.5px;font-weight:700;color:var(--sb-purple-dark);
  padding:4px 8px;border-radius:8px;
}
.term-supply-change:hover{background:var(--sb-purple-light)}
.term-supply-now-name{font-size:19px;font-weight:700;margin-top:6px}
.term-supply-track{height:8px;border-radius:6px;background:var(--sb-grey-bg);margin:12px 0 8px;overflow:hidden}
.term-supply-fill{height:100%;border-radius:6px;background:var(--sb-purple);transition:width .3s ease}
.term-supply-now-num{font-size:14px;color:var(--sb-text-muted)}
.term-supply-now-num b{color:var(--sb-text);font-weight:800}
/* «Показать оставшиеся» — список несобранных прямо на экране. */
.term-supply-show{
  margin-top:12px;border:1px solid var(--sb-border);background:var(--sb-surface);
  cursor:pointer;font-family:inherit;font-size:13px;font-weight:700;
  color:var(--sb-purple-dark);padding:9px 14px;border-radius:10px;width:100%;
}
.term-supply-show:hover{border-color:var(--sb-purple);background:var(--sb-purple-light)}
.term-supply-left{margin-top:12px;display:flex;flex-direction:column;gap:8px;
  max-height:46vh;overflow-y:auto;text-align:left}
.term-left-load{font-size:13px;color:var(--sb-text-muted);padding:8px 2px}
.term-left-item{
  background:var(--sb-surface);border:1px solid var(--sb-border);
  border-radius:10px;padding:10px 12px;
}
.term-left-main{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.term-left-title{font-weight:700;font-size:14px;color:var(--sb-text)}
.term-left-x{font-weight:800;font-size:13px;color:var(--sb-purple-dark);
  background:var(--sb-purple-light);border-radius:6px;padding:1px 7px}
.term-left-busy{font-size:11px;font-weight:700;color:var(--sb-text-muted);
  background:var(--sb-grey-bg);border-radius:6px;padding:2px 7px}
.term-left-sub{font-size:12px;color:var(--sb-text-muted);margin-top:3px}

/* Кнопка партии в шапке: пока не выбрана — зовёт нажать, а не молчит. */
.sb-supply-btn.empty{
  border-color:var(--sb-purple);color:var(--sb-purple-dark);font-weight:800;
  background:var(--sb-purple-light);
}
.sb-caret{opacity:.6;font-size:10px;margin-left:2px}

/* Выход — в конце меню на каждом экране. Раньше он был только на паре
   старых страниц, и выйти из системы было неоткуда. */
.sb-nav-logout{
  border:1px solid var(--sb-border);background:var(--sb-surface);cursor:pointer;
  color:var(--sb-text-muted);font-size:12.5px;font-weight:600;font-family:inherit;
  padding:7px 13px;border-radius:9px;white-space:nowrap;margin-left:6px;
}
.sb-nav-logout:hover{border-color:var(--sb-error);color:var(--sb-error)}
.sb-drawer-logout{
  margin-top:10px;padding:13px 14px;border-radius:12px;cursor:pointer;
  border:1px solid var(--sb-border);background:var(--sb-surface);
  color:var(--sb-error);font-size:15px;font-weight:600;font-family:inherit;
  width:100%;text-align:left;
}
@media (max-width:760px){
  /* В шапке остаётся только кнопка меню — выход живёт в самой панели. */
  .sb-nav-logout{display:none}
}

/* Логотип компании в шапке. Высота привязана к строке подписи, чтобы шапка
   не «прыгала» между экранами. */
.sb-logo { height: 34px; width: auto; display: block; flex: none; }
.sb-brand-link .sb-logo { cursor: pointer; }
@media (max-width: 720px) { .sb-logo { height: 28px; } }

/* ---------- верхнее меню: размер и вес по важности ---------- */
/* Ряд стал мельче и тише: это навигация, а не содержимое экрана.
   Правила идут после базовых, поэтому переопределяют их без !important. */
.sb-nav-links { gap: 2px; }
.sb-nav-links > a {
  font-size: 13px;
  font-weight: 500;
  padding: 7px 10px;
  border-radius: 8px;
  color: var(--sb-text-muted);
  background: none;
  position: relative;
}
.sb-nav-links > a:hover { color: var(--sb-text); background: var(--sb-surface-2); }

/* Активный раздел — цветом и тонкой линией снизу, без плашки:
   плашка спорила по весу с кнопкой терминала. */
.sb-nav-links > a.active {
  color: var(--sb-purple-dark);
  background: none;
  font-weight: 650;
}
.sb-nav-links > a.active::after {
  content: ""; position: absolute; left: 10px; right: 10px; bottom: 2px;
  height: 2px; border-radius: 2px; background: var(--sb-purple);
}

/* Терминал — единственная выделенная кнопка в ряду. */
.sb-nav-links > a.primary {
  color: #fff;
  font-weight: 650;
  background: linear-gradient(180deg, var(--sb-purple), var(--sb-purple-dark));
  box-shadow: var(--sb-shadow), inset 0 1px 0 rgba(255,255,255,.16);
  margin-right: 8px;
}
.sb-nav-links > a.primary:hover { color: #fff; filter: brightness(1.06); background: linear-gradient(180deg, var(--sb-purple), var(--sb-purple-dark)); }
.sb-nav-links > a.primary.active::after { display: none; }

.sb-nav-more-btn { font-size: 13px; font-weight: 500; padding: 7px 10px; color: var(--sb-text-muted); }
.sb-nav-more-btn:hover { color: var(--sb-text); }
.sb-nav-logout { font-size: 13px; font-weight: 500; padding: 7px 12px; }

/* Шапка ниже: 34-пиксельный логотип и мелкие ссылки не требуют прежней высоты. */
.sb-topbar { padding-top: 10px; padding-bottom: 10px; }

/* Выбор рабочего места на первом экране терминала. Кнопки крупные:
   их жмут пальцем, стоя у стола, а не мышью сидя. */
.term-ws-list { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-top: 20px; }
.term-ws-choice {
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
  padding: 16px 22px; min-width: 200px; cursor: pointer; text-align: left;
  border-radius: 14px; border: 1px solid var(--sb-border); background: var(--sb-surface);
  box-shadow: var(--sb-shadow);
}
.term-ws-choice:hover { border-color: var(--sb-purple); box-shadow: var(--sb-shadow-md); }
.term-ws-name { font-size: 17px; font-weight: 650; color: var(--sb-text); }
.term-ws-code { font-size: 13px; color: var(--sb-text-muted); }
.term-ws-empty { margin-top: 18px; font-size: 15px; color: var(--sb-text-muted); }

/* Партия собрана: не поздравление, а указание следующего шага. */
.term-supply-done {
  margin-top: 18px; padding: 20px 24px; border-radius: 16px;
  background: var(--sb-success-bg); border: 1px solid var(--sb-border);
  display: flex; flex-direction: column; gap: 6px; align-items: center; text-align: center;
}
.term-done-title { font-size: 20px; font-weight: 700; color: var(--sb-success); }
.term-done-sub { font-size: 15px; color: var(--sb-text); }
.term-done-next { font-size: 14px; color: var(--sb-text-muted); margin-top: 2px; }
.term-done-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 14px; }
.term-done-btn {
  padding: 12px 22px; border-radius: 12px; font-size: 15px; font-weight: 600;
  border: 1px solid var(--sb-border); background: var(--sb-surface); color: var(--sb-text);
  cursor: pointer; text-decoration: none; display: inline-flex; align-items: center;
}
.term-done-btn.primary {
  background: linear-gradient(180deg, var(--sb-purple), var(--sb-purple-dark));
  color: #fff; border-color: transparent;
}
.term-done-btn:hover { border-color: var(--sb-border-strong); }
.term-done-btn.primary:hover { filter: brightness(1.06); border-color: transparent; }

/* Ожидание печати: объяснение и выход, а не бесконечный крутящийся значок. */
.term-print-wait { margin-top: 16px; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.term-print-wait-note { font-size: 14px; color: var(--sb-text-muted); text-align: center; max-width: 46ch; }

/* Предупреждение о недоступной печати — над рабочей областью терминала. */
.term-print-warn {
  display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 20px; background: var(--sb-warn-bg); color: var(--sb-text);
  border-bottom: 1px solid var(--sb-border); font-size: 15px;
}
.term-print-warn button {
  padding: 8px 18px; border-radius: 10px; border: 0; cursor: pointer;
  background: linear-gradient(180deg, var(--sb-purple), var(--sb-purple-dark));
  color: #fff; font-size: 14px; font-weight: 600; font-family: inherit;
}
.term-print-warn button:hover { filter: brightness(1.06); }

/* Код не в обороте. Красный, а не жёлтый: печать можно доделать потом,
   а отгруженный чужой код обратно не вернёшь. Сборку при этом не
   останавливаем — решает человек. */
.term-cis-warn {
  display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 20px; background: var(--sb-error-bg); color: var(--sb-text);
  border-bottom: 1px solid var(--sb-border); font-size: 15px;
}
.term-cis-warn b { font-weight: 700 }
.term-cis-warn code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
}
.term-cis-warn button {
  padding: 8px 18px; border-radius: 10px; border: 1px solid var(--sb-border);
  cursor: pointer; background: var(--sb-surface); color: var(--sb-text);
  font-size: 14px; font-weight: 600; font-family: inherit;
}

/* ==========================================================================
   Боковая панель разделов.

   Строится скриптом и живёт поверх любой вёрстки: position fixed плюс
   отступ у body работают одинаково и на страницах с .sb-app, и на тех,
   где main лежит прямо в body. Переделывать тринадцать страниц ради меню
   не пришлось.
   ========================================================================== */
:root{ --sb-side-w: 216px; --sb-side-w-min: 64px; }

body.sb-has-side{ padding-left: var(--sb-side-w); transition: padding-left .16s }
body.sb-side-collapsed{ padding-left: var(--sb-side-w-min) }

.sb-side{
  position:fixed; top:0; left:0; bottom:0; width:var(--sb-side-w); z-index:80;
  display:flex; flex-direction:column;
  background:var(--sb-surface); border-right:1px solid var(--sb-border);
  transition:width .16s;
}
.sb-side.collapsed{ width:var(--sb-side-w-min) }

.sb-side-brand{
  display:flex; align-items:center; gap:10px; padding:16px 14px;
  border-bottom:1px solid var(--sb-border); text-decoration:none; color:inherit;
  min-height:76px; justify-content:flex-start;
}
/* Логотип — настоящих пропорций: знак широкий (203x60), и квадрат его
   расплющивал. Высота задана, ширина считается сама. */
.sb-side-brand img{ height:34px; width:auto; max-width:100%; flex:0 0 auto }
.sb-side.collapsed .sb-side-brand img{ height:22px }
.sb-side-brand-text{ font-size:12.5px; font-weight:800; letter-spacing:.6px; white-space:nowrap }

/* Список разделов прокручивается сам: на низком экране он длиннее окна,
   а выход и кнопка сворачивания должны оставаться на виду. */
.sb-side-links{ flex:1; min-height:0; overflow-y:auto; padding:8px 8px 12px }
.sb-side-links a{
  display:flex; align-items:center; gap:11px;
  padding:9px 11px; margin-bottom:2px; border-radius:10px;
  color:var(--sb-text-muted); text-decoration:none;
  font-size:13.5px; font-weight:600; white-space:nowrap;
}
.sb-side-links a:hover{ background:var(--sb-surface-2); color:var(--sb-text) }
.sb-side-links a.active{ background:var(--sb-purple-light); color:var(--sb-purple-dark) }
/* Раздел-витрина: тусклее рабочих, но не серый — туда можно зайти
   и посмотреть. Точка справа отличает его от обычного пункта. */
.sb-side-links a.preview{ opacity:.72 }
.sb-side-links a.preview::after{
  content:''; margin-left:auto; width:5px; height:5px; border-radius:50%;
  background:var(--sb-purple); flex:0 0 auto;
}
.sb-side.collapsed .sb-side-links a.preview::after{ display:none }
.sb-side-links a.active .sb-side-icon{ color:var(--sb-purple-dark) }
/* Черта отделяет ежедневное от настроек: глазу не нужно перечитывать
   весь список, чтобы понять, где кончается работа и начинается наладка. */
.sb-side-links a.group-start{ margin-top:10px; padding-top:15px; border-top:1px solid var(--sb-border) }
.sb-side-icon{ width:19px; height:19px; flex:0 0 auto }

.sb-side-foot{ border-top:1px solid var(--sb-border); padding:8px; display:flex; gap:6px; flex-wrap:wrap }
/* Звук — своей строкой над выходом. Рядом с «Выйти» он бы жался, а
   промахнуться мимо выхода и вылететь из системы вместо выключения
   звука — обидно вдвойне. */
.sb-side-sound{
  flex:0 0 100%; display:flex; align-items:center; gap:11px;
  padding:9px 11px; border:0; border-radius:10px; cursor:pointer;
  background:none; color:var(--sb-text-muted);
  font-size:13.5px; font-weight:600; font-family:inherit; white-space:nowrap;
}
.sb-side-sound:hover{ background:var(--sb-surface-2); color:var(--sb-text) }
/* Значок один, состояний два: волны или крестик — но не оба сразу. */
.sb-side-sound .sb-sound-off{ display:none }
.sb-side-sound.muted .sb-sound-on{ display:none }
.sb-side-sound.muted .sb-sound-off{ display:inline }
.sb-side.collapsed .sb-side-sound{ justify-content:center; padding-left:0; padding-right:0 }
.sb-side-logout{
  flex:1; display:flex; align-items:center; gap:11px;
  padding:9px 11px; border:0; border-radius:10px; cursor:pointer;
  background:none; color:var(--sb-text-muted);
  font-size:13.5px; font-weight:600; font-family:inherit; white-space:nowrap;
}
.sb-side-logout:hover{ background:var(--sb-surface-2); color:var(--sb-error) }
/* Сворачивание — редкое действие, но попадать в него надо с первого
   раза: у кнопки своя строка и подпись, а не значок в углу. */
.sb-side-toggle{
  flex:0 0 auto; width:42px; height:40px; border:0; border-radius:10px; cursor:pointer;
  background:var(--sb-surface-2); color:var(--sb-text-muted);
  display:flex; align-items:center; justify-content:center;
}
.sb-side-toggle:hover{ background:var(--sb-surface-2); color:var(--sb-text) }
.sb-side-toggle svg{ width:20px; height:20px; transition:transform .16s }
.sb-side.collapsed .sb-side-toggle svg{ transform:rotate(180deg) }

/* Свёрнутая панель: только значки. Подписи убраны из потока, а не
   спрятаны прозрачностью — иначе они продолжали бы держать ширину. */
.sb-side.collapsed .sb-side-label,
.sb-side.collapsed .sb-side-brand-text{ display:none }
.sb-side.collapsed .sb-side-links a,
.sb-side.collapsed .sb-side-logout{ justify-content:center; padding-left:0; padding-right:0 }
.sb-side.collapsed .sb-side-brand{ justify-content:center; padding-left:0; padding-right:0 }
.sb-side.collapsed .sb-side-foot{ flex-direction:column }
.sb-side.collapsed .sb-side-toggle{ width:100%; height:32px }

/* Кнопка открытия — только на узком экране. */
/* Накладка: панель всегда за краем и выезжает по кнопке, независимо
   от ширины экрана. Так показ и витрина остаются во весь экран, а
   меню из них всё равно доступно. */
.sb-side.sb-side-overlay{ transform:translateX(-100%); transition:transform .18s; width:var(--sb-side-w) }
.sb-side.sb-side-overlay.open{ transform:none; box-shadow:0 0 0 100vmax rgba(0,0,0,.45) }
.sb-side.sb-side-overlay .sb-side-label,
.sb-side.sb-side-overlay .sb-side-brand-text{ display:inline }
/* В накладке эта кнопка закрывает меню, поэтому видна и повёрнута
   в другую сторону: стрелка указывает наружу, куда панель и уедет. */
.sb-side.sb-side-overlay .sb-side-toggle svg{ transform:rotate(0) }
body.sb-overlay-mode .sb-side-open,
body:has(.sb-side-overlay) .sb-side-open{
  display:flex; position:fixed; left:14px; bottom:14px; z-index:90;
}

/* Пока панель открыта, кнопка вызова не нужна: она перекрывала собой
   «Выйти» в самом низу списка. Закрыть панель можно касанием мимо неё
   или клавишей Esc. */
body.sb-side-shown .sb-side-open{ display:none !important }

.sb-side-open{ display:none }

@media (max-width: 900px){
  body.sb-has-side, body.sb-side-collapsed{ padding-left:0 }
  .sb-side{ transform:translateX(-100%); transition:transform .18s; box-shadow:none }
  .sb-side.open{ transform:none; box-shadow:0 0 0 100vmax rgba(0,0,0,.45) }
  /* В выехавшей панели подписи нужны всегда: пальцем по значкам не
     угадаешь, а места на телефоне достаточно. */
  .sb-side.collapsed{ width:var(--sb-side-w) }
  .sb-side.collapsed .sb-side-label,
  .sb-side.collapsed .sb-side-brand-text{ display:inline }
  .sb-side.collapsed .sb-side-links a,
  .sb-side.collapsed .sb-side-logout,
  .sb-side.collapsed .sb-side-brand{ justify-content:flex-start; padding-left:11px }
  .sb-side.collapsed .sb-side-foot{ flex-direction:row }

  /* Кнопку жмут на ходу, часто мокрой или в перчатке рукой: 62 пикселя
     против рекомендованных сорока восьми, контрастная заливка и подпись —
     чтобы не искать её глазами и не промахиваться. */
  .sb-side-open{
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:1px; position:fixed; left:14px; bottom:14px; z-index:90;
    width:62px; height:62px; border-radius:18px; cursor:pointer;
    background:linear-gradient(180deg,var(--sb-purple),var(--sb-purple-dark));
    color:#fff; border:0; font-size:22px; line-height:1; font-family:inherit;
    box-shadow:0 8px 24px rgba(0,0,0,.32), 0 0 0 4px var(--sb-purple-light);
  }
  .sb-side-open:active{ transform:translateY(2px) }
  .sb-side-open span{ font-size:9.5px; font-weight:700; letter-spacing:.4px }
}

/* Терминал: вместо разделов две простые ссылки в шапке. */
.sb-nav-plain{
  padding:8px 14px; border-radius:10px; border:1px solid var(--sb-border);
  background:var(--sb-surface); color:var(--sb-text-muted);
  font-size:13px; font-weight:600; font-family:inherit; cursor:pointer;
  text-decoration:none; margin-left:8px;
}
.sb-nav-plain:hover{ color:var(--sb-text); border-color:var(--sb-border-strong) }

/* При боковой панели логотип в шапке лишний — он уже слева. Шапка
   становится строкой названия текущего экрана, и подпись раздела в ней
   вырастает из мелкой сноски в заголовок. */
body.sb-has-side .sb-topbar .sb-logo,
body.sb-has-side .sb-topbar .sb-brand-mark,
body.sb-has-side .sb-topbar .sb-brand-name{ display:none }
body.sb-has-side .sb-topbar .sb-brand-sub{
  font-size:16px; font-weight:700; color:var(--sb-text); margin-top:0;
}
body.sb-has-side .sb-topbar{ padding-left:22px }

/* ==========================================================================
   Шапка: фирменный градиент вместо белой полосы.

   Цвета — сливовые, с smartbeauty.pro. Движение медленное и слабое: это
   рабочий экран, за которым проводят смену, и мигающая шапка через час
   начинает раздражать. Заметно ровно настолько, чтобы верх не читался
   как пустое место.
   ========================================================================== */
.sb-topbar{
  position:relative;
  /* Сливовый по всей ширине, а не только по краям: прошлый вариант был
     настолько деликатным, что верх по-прежнему читался белым. */
  background:
    linear-gradient(115deg,
      var(--sb-purple-light) 0%,
      #ece4f8 22%,
      var(--sb-surface) 46%,
      #f1eafb 70%,
      var(--sb-purple-light) 100%);
  background-size:260% 100%;
  animation: sb-topbar-flow 18s ease-in-out infinite;
  /* Границу рисует бегущая полоса ниже — вторая линия была бы лишней. */
  border-bottom-color:transparent;
}
/* Полоса под шапкой — фирменная, с бегущим бликом. Она же отделяет
   шапку от содержимого: раньше это делала серая граница. */
.sb-topbar::after{
  content:""; position:absolute; left:0; right:0; bottom:-1px; height:3px;
  background:linear-gradient(90deg,
    var(--sb-purple-dark), var(--sb-purple), #f0e4b8, var(--sb-purple), var(--sb-purple-dark));
  background-size:200% 100%;
  animation: sb-topbar-line 8s linear infinite;
}
@keyframes sb-topbar-flow{
  0%,100%{ background-position:0% 50% }
  50%{ background-position:100% 50% }
}
@keyframes sb-topbar-line{
  from{ background-position:0% 0 }
  to{ background-position:200% 0 }
}
/* Кому движение мешает — тому его нет. Градиент остаётся, он статичный. */
@media (prefers-reduced-motion: reduce){
  .sb-topbar, .sb-topbar::after{ animation:none }
}

/* На узком экране боковая панель уехала за край, и шапка оставалась
   пустой белой полосой. Возвращаем в неё знак — верх без логотипа
   выглядит недогруженной страницей. */
@media (max-width: 900px){
  body.sb-has-side .sb-topbar .sb-logo{ display:block; height:30px; width:auto }
  body.sb-has-side .sb-topbar .sb-brand-sub{ font-size:13px; color:var(--sb-text-muted) }
  body.sb-has-side .sb-topbar{ padding-left:16px; gap:12px }
}

/* На телефоне боковой панели не видно, и название текущего экрана —
   единственный способ понять, где находишься. Общее правило прячет его
   на узких экранах ради компактности; здесь возвращаем. */
@media (max-width: 760px){
  body.sb-has-side .sb-topbar .sb-brand-sub{
    display:block; font-size:12.5px; font-weight:700; color:var(--sb-text);
  }
  body.sb-has-side .sb-topbar{ padding:12px 14px; min-height:58px }
}

/* Экран терминала для тех, кто не собирает: вместо поля сканера —
   объяснение. Не отказ в доступе, а «здесь работают, посмотреть можно
   в других разделах». */
.sb-guest-terminal{
  max-width:520px; margin:60px auto; padding:34px 32px; text-align:center;
  background:var(--sb-surface); border:1px solid var(--sb-border);
  border-radius:var(--sb-radius); box-shadow:var(--sb-shadow-md);
}
.sb-guest-terminal h1{ font-size:21px; margin:0 0 10px }
.sb-guest-terminal p{ font-size:14px; color:var(--sb-text-muted); line-height:1.6; margin:0 0 20px }
.sb-guest-terminal .sb-guest-actions{ display:flex; gap:10px; justify-content:center; flex-wrap:wrap }
.sb-guest-terminal a{
  padding:11px 20px; border-radius:11px; text-decoration:none;
  font-size:13.5px; font-weight:600;
  background:var(--sb-purple); color:#fff;
}
.sb-guest-terminal a.ghost{
  background:var(--sb-surface-2); color:var(--sb-text); border:1px solid var(--sb-border);
}
.sb-guest-icon{ font-size:38px; line-height:1; margin-bottom:12px }

/* ==========================================================================
   Единый шрифт и единая главная кнопка.
   ========================================================================== */

/* Шрифт объявлялся один раз, на body, — но кнопки, поля и списки его не
   наследуют: браузер ставит им свой системный. Отсюда и разнобой, который
   заметен именно на формах. Наследование включаем принудительно. */
:root{ --sb-font: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif; }
html, body{ font-family: var(--sb-font) }
button, input, select, textarea, optgroup{ font-family: inherit; font-size: inherit }

/* Главная кнопка — одна на всю систему.
 *
 * Золотая кнопка на сводке была единственной такой во всём интерфейсе и
 * читалась как чужая. Либо золото везде, либо нигде; выбираем фирменный
 * сливовый — он и в логотипе, и в подсветке текущего раздела.
 *
 * Объём даётся тремя слоями: светлая линия по верхней кромке (блик),
 * градиент сверху вниз (форма) и цветная тень под кнопкой (отрыв от
 * поверхности). При нажатии кнопка проседает — палец получает ответ. */
.hm-cta,
.an-btn.us-btn-wide,
.sb-btn-primary,
.sp-btn-primary,
.cz-btn-primary,
.tour-exit,
.us-btn-primary{
  background: linear-gradient(180deg, #9a80c4 0%, var(--sb-purple) 42%, var(--sb-purple-dark) 100%);
  color: #fff;
  border: 0;
  border-radius: 13px;
  font-family: var(--sb-font);
  font-weight: 700;
  letter-spacing: .2px;
  text-decoration: none;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.38),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 6px 16px rgba(82,45,106,.34),
    0 2px 4px rgba(24,24,27,.14);
  transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
}
.hm-cta:hover,
.an-btn.us-btn-wide:hover,
.sb-btn-primary:hover,
.sp-btn-primary:hover,
.cz-btn-primary:hover,
.tour-exit:hover,
.us-btn-primary:hover{
  filter: brightness(1.07);
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -2px 0 rgba(0,0,0,.16),
    0 10px 22px rgba(82,45,106,.4),
    0 3px 6px rgba(24,24,27,.16);
}
.hm-cta:active,
.an-btn.us-btn-wide:active,
.sb-btn-primary:active,
.sp-btn-primary:active,
.cz-btn-primary:active,
.tour-exit:active,
.us-btn-primary:active{
  transform: translateY(1px);
  box-shadow:
    inset 0 2px 5px rgba(0,0,0,.24),
    0 2px 6px rgba(82,45,106,.28);
}

/* Второстепенная кнопка рядом с главной: та же форма и высота, но без
   заливки — иначе две одинаково яркие кнопки спорят, какую нажать. */
.hm-cta.ghost{
  background: var(--sb-surface);
  color: var(--sb-text);
  border: 1px solid var(--sb-border-strong);
  box-shadow: 0 2px 6px rgba(24,24,27,.06);
}
.hm-cta.ghost:hover{
  border-color: var(--sb-purple);
  color: var(--sb-purple-dark);
  filter: none;
  box-shadow: 0 6px 14px rgba(24,24,27,.10);
}

/* Логотип крупнее: знак — единственное фирменное пятно на экране, и в
   34 пикселя он терялся рядом с заголовком раздела. */
.sb-side-brand img{ height:42px }
.sb-side{ --sb-side-w: 216px }
.sb-side-brand{ min-height:84px }
@media (max-width: 900px){
  body.sb-has-side .sb-topbar .sb-logo{ height:36px }
}

/* Днём анимации шапки почти не видно: сливовый оттенок в светлой теме
   бледный по замыслу — он служит подложкой для выделенных пунктов меню.
   Для самой шапки берём заметно более насыщенный, иначе движение есть,
   а глазу его не поймать. */
.sb-topbar{
  background:
    linear-gradient(115deg,
      #ded1f2 0%,
      #efe8fa 20%,
      var(--sb-surface) 44%,
      #f0e6d2 68%,
      #e3d5f5 100%);
  background-size:260% 100%;
}
:root[data-theme="dark"] .sb-topbar,
:root:not([data-theme="light"]) .sb-topbar{
  background:
    linear-gradient(115deg,
      #2f2542 0%,
      #241d33 22%,
      var(--sb-surface) 46%,
      #2b2438 70%,
      #332a4a 100%);
  background-size:260% 100%;
}

/* ==========================================================================
   Общий приём для крупных чисел и кнопок.

   Цифра и кнопка — два главных пятна на экране, и делать их по-разному
   значит собирать интерфейс из кусков. Один градиент, одна тень, одна
   светлая грань сверху: разное назначение, одна рука.
   ========================================================================== */
.sb-num-3d{
  font-weight:800; letter-spacing:-.03em;
  background:linear-gradient(180deg, var(--sb-text), color-mix(in srgb, var(--sb-text) 55%, var(--sb-purple)));
  -webkit-background-clip:text; background-clip:text; color:transparent;
  filter: drop-shadow(0 1px 0 rgba(255,255,255,.9)) drop-shadow(0 3px 5px rgba(24,24,27,.18));
}
:root[data-theme="dark"] .sb-num-3d,
:root:not([data-theme="light"]) .sb-num-3d{
  filter: drop-shadow(0 3px 8px rgba(180,154,214,.35));
}

/* Кнопки второго ряда: не заливка, а объёмная плашка. Раньше они были
   плоскими прямоугольниками рядом с объёмной главной кнопкой — на одном
   экране это читалось как две разные системы. */
.hm-cta.ghost,
.an-btn:not(.us-btn-wide),
.sp-btn:not(.sp-btn-primary),
.cz-btn:not(.cz-btn-primary),
.us-mini{
  background:linear-gradient(180deg, var(--sb-surface) 0%, var(--sb-surface-2) 100%);
  border:1px solid var(--sb-border-strong);
  border-radius:12px;
  font-weight:700;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.75),
    0 2px 4px rgba(24,24,27,.07),
    0 6px 14px rgba(24,24,27,.06);
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.hm-cta.ghost:hover,
.an-btn:not(.us-btn-wide):hover,
.sp-btn:not(.sp-btn-primary):hover,
.cz-btn:not(.cz-btn-primary):hover,
.us-mini:hover{
  transform: translateY(-2px);
  border-color: var(--sb-purple);
  color: var(--sb-purple-dark);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.85),
    0 4px 8px rgba(24,24,27,.08),
    0 12px 22px rgba(82,45,106,.14);
}
.hm-cta.ghost:active,
.an-btn:not(.us-btn-wide):active,
.sp-btn:not(.sp-btn-primary):active,
.cz-btn:not(.cz-btn-primary):active,
.us-mini:active{
  transform: translateY(1px);
  box-shadow: inset 0 2px 5px rgba(24,24,27,.14);
}
:root[data-theme="dark"] .hm-cta.ghost,
:root:not([data-theme="light"]) .hm-cta.ghost,
:root[data-theme="dark"] .an-btn:not(.us-btn-wide),
:root:not([data-theme="light"]) .an-btn:not(.us-btn-wide),
:root[data-theme="dark"] .sp-btn:not(.sp-btn-primary),
:root:not([data-theme="light"]) .sp-btn:not(.sp-btn-primary),
:root[data-theme="dark"] .cz-btn:not(.cz-btn-primary),
:root:not([data-theme="light"]) .cz-btn:not(.cz-btn-primary){
  box-shadow: 0 2px 6px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.06);
}

/* Кнопка меню: текст крупнее — её читают на ходу и издалека. */
.sb-side-open span{ font-size:11px; letter-spacing:.5px }

/* ==========================================================================
   Кнопка. Одна на всю систему.

   Заливкой мы выделяли «главное действие» — но на экране, где действий
   три, выделять одно значит спорить с человеком: он всё равно нажмёт то,
   зачем пришёл. Поэтому кнопки равны, а объём даётся не цветом, а
   формой: прозрачное тело, фирменная окантовка и жёсткая тень под ней —
   как у клавиши, которую можно нажать.

   Нажатие проваливает кнопку в свою тень: палец получает ответ раньше,
   чем экран успеет перерисоваться.
   ========================================================================== */
.hm-cta,
.hm-cta.ghost,
.an-btn,
.an-btn.us-btn-wide,
.sb-btn-primary,
.sp-btn,
.sp-btn-primary,
.cz-btn,
.cz-btn-primary,
.us-mini,
.us-btn-primary,
.tour-exit{
  background: transparent;
  color: var(--sb-purple-dark);
  border: 1.5px solid var(--sb-purple);
  border-radius: 12px;
  font-family: var(--sb-font);
  font-weight: 700;
  text-decoration: none;
  box-shadow:
    0 3px 0 0 var(--sb-purple-dark),
    0 5px 12px rgba(82,45,106,.22);
  transition: transform .1s ease, box-shadow .1s ease, background .14s ease;
}
.hm-cta:hover,
.hm-cta.ghost:hover,
.an-btn:hover,
.sb-btn-primary:hover,
.sp-btn:hover,
.cz-btn:hover,
.us-mini:hover,
.tour-exit:hover{
  background: var(--sb-purple-light);
  filter: none;
  transform: translateY(-1px);
  box-shadow:
    0 4px 0 0 var(--sb-purple-dark),
    0 8px 18px rgba(82,45,106,.28);
}
.hm-cta:active,
.hm-cta.ghost:active,
.an-btn:active,
.sb-btn-primary:active,
.sp-btn:active,
.cz-btn:active,
.us-mini:active,
.tour-exit:active{
  transform: translateY(3px);
  box-shadow:
    0 0 0 0 var(--sb-purple-dark),
    0 1px 3px rgba(82,45,106,.25);
}
.an-btn:disabled,
.sp-btn:disabled,
.cz-btn:disabled,
.us-mini:disabled{
  opacity: .45;
  box-shadow: 0 2px 0 0 var(--sb-border-strong);
  border-color: var(--sb-border-strong);
  color: var(--sb-text-muted);
  transform: none;
}
/* Опасное действие сохраняет свой цвет: одинаковыми должны быть кнопки,
   а не последствия. */
.sp-btn-danger{
  color: var(--sb-error);
  border-color: var(--sb-error);
  box-shadow: 0 3px 0 0 var(--sb-error), 0 5px 12px rgba(185,28,28,.2);
}
.sp-btn-danger:hover{
  background: var(--sb-error-bg);
  box-shadow: 0 4px 0 0 var(--sb-error), 0 8px 18px rgba(185,28,28,.26);
}
:root[data-theme="dark"] .hm-cta,
:root:not([data-theme="light"]) .hm-cta,
:root[data-theme="dark"] .an-btn,
:root:not([data-theme="light"]) .an-btn,
:root[data-theme="dark"] .sp-btn,
:root:not([data-theme="light"]) .sp-btn,
:root[data-theme="dark"] .cz-btn,
:root:not([data-theme="light"]) .cz-btn,
:root[data-theme="dark"] .tour-exit,
:root:not([data-theme="light"]) .tour-exit{
  color: var(--sb-purple);
  box-shadow: 0 3px 0 0 var(--sb-purple-dark), 0 5px 14px rgba(0,0,0,.4);
}

/* Кнопка показа у гостя — та же форма, только крупнее: это главное, что
   он должен нажать, и размер говорит об этом честнее цвета. */
.hm-cta-demo{ border-width:2px }
.hm-cta-demo .hm-play{
  background: var(--sb-purple-light);
  box-shadow: inset 0 0 0 1px var(--sb-purple);
}
.hm-cta-demo .hm-play::after{ border-left-color: var(--sb-purple-dark) }

/* ==========================================================================
   Шапка: выше, и надпись в ней плавает.
   ========================================================================== */
.sb-topbar{
  min-height: 76px;
  padding-top: 16px;
  padding-bottom: 16px;
  background-size: 300% 100%;
  animation: sb-topbar-flow 22s ease-in-out infinite;
}
/* Название раздела покачивается — шапка перестаёт быть неподвижной
   полосой, но движение медленное: за экраном сидят весь день. */
body.sb-has-side .sb-topbar .sb-brand-sub{
  font-size: 18px;
  animation: sb-title-float 7s ease-in-out infinite;
}
@keyframes sb-title-float{
  0%,100%{ transform: translateY(0) }
  50%{ transform: translateY(-3px) }
}
.sb-side-brand img{ height: 52px }
.sb-side-brand{ min-height: 96px }
@media (max-width: 900px){
  body.sb-has-side .sb-topbar .sb-logo{ height: 42px }
  body.sb-has-side .sb-topbar .sb-brand-sub{ font-size: 14px }
  .sb-topbar{ min-height: 64px }
}
@media (prefers-reduced-motion: reduce){
  body.sb-has-side .sb-topbar .sb-brand-sub{ animation: none }
}

/* ==========================================================================
   Выделение главного действия — только на большом экране.

   На телефоне кнопки идут в столбик во всю ширину: порядок сам по себе
   говорит, что первое, и подкрашивать его незачем. На компьютере они
   стоят в ряд, глазу нужно за что-то зацепиться — там главная заливается.

   Форма при этом одна и та же: заливка добавляется поверх общей кнопки,
   а не заменяет её. Поэтому нажатие и провал в тень везде одинаковы.
   ========================================================================== */
/* Выделяем главное действие только там, где есть курсор: на телефоне
   кнопки идут в столбик во всю ширину, порядок сам говорит, что первое,
   а заливка делает экран пёстрым. Проверяем именно наличие мыши, а не
   ширину: планшет бывает широким и без курсора. */
@media (min-width: 901px) and (hover: hover) and (pointer: fine){
  .hm-cta:not(.ghost),
  .hm-cta-demo,
  .an-btn.us-btn-wide,
  .sb-btn-primary,
  .sp-btn-primary,
  .cz-btn-primary,
  .us-btn-primary,
  .tour-exit{
    background: linear-gradient(180deg, #9a80c4 0%, var(--sb-purple) 45%, var(--sb-purple-dark) 100%);
    color: #fff;
    border-color: var(--sb-purple-dark);
  }
  .hm-cta:not(.ghost):hover,
  .hm-cta-demo:hover,
  .an-btn.us-btn-wide:hover,
  .sb-btn-primary:hover,
  .sp-btn-primary:hover,
  .cz-btn-primary:hover,
  .tour-exit:hover{
    background: linear-gradient(180deg, #a68ecf 0%, var(--sb-purple) 45%, var(--sb-purple-dark) 100%);
    color: #fff;
  }
  /* Треугольник «плей» на залитой кнопке — светлый, иначе тонет. */
  .hm-cta-demo .hm-play{
    background: rgba(255,255,255,.22);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.45);
  }
  .hm-cta-demo .hm-play::after{ border-left-color: #fff }
}

/* Кнопка меню: не мешать читающему.
 *
 * Она висит поверх содержимого и закрывает последние строки, а нужна раз
 * в несколько минут. Поэтому: прячется при прокрутке вниз, возвращается
 * при прокрутке вверх и в покое, в состоянии покоя полупрозрачна, и под
 * ней резервируется место — чтобы конец страницы не оказывался под ней
 * навсегда. */
.sb-side-open{
  opacity:.88;
  transition: transform .22s cubic-bezier(.3,.8,.3,1), opacity .22s ease;
}
.sb-side-open:hover,
.sb-side-open:active{ opacity:1 }
.sb-side-open.away{
  transform: translateY(96px) scale(.85);
  opacity:0;
  pointer-events:none;
}
@media (max-width: 900px){
  /* Место под кнопкой: последняя строка страницы не должна навсегда
     оставаться под ней. */
  body.sb-has-side, body.sb-overlay-mode{ padding-bottom:86px }
  .tour-foot{ padding-bottom:96px }
  .show-page .tour-stage{ padding-bottom:96px }
}
@media (prefers-reduced-motion: reduce){
  .sb-side-open{ transition:none }
}

/* ==========================================================================
   Переходы между страницами.

   Обычный переход по ссылке — это белая вспышка и сборка страницы заново.
   View Transitions даёт браузеру снять кадр до и после и связать их: шапка
   и логотип не мигают, а перетекают, содержимое проявляется.

   Пять строк вместо одностраничного приложения. Браузер без поддержки
   просто переходит как раньше — ничего не ломается и не требует запасного
   пути.
   ========================================================================== */
@view-transition{ navigation: auto }

/* Шапка и панель остаются на месте при переходе: они одни и те же на всех
   экранах, и перерисовывать их — значит показывать мигание там, где ничего
   не изменилось. */
.sb-topbar{ view-transition-name: sb-topbar }
.sb-side{ view-transition-name: sb-side }
.sb-side-open{ view-transition-name: sb-menu }

::view-transition-old(root){ animation: sb-vt-out .18s ease both }
::view-transition-new(root){ animation: sb-vt-in .26s cubic-bezier(.2,.9,.3,1) both }
@keyframes sb-vt-out{ to{ opacity:0; transform:translateY(-6px) } }
@keyframes sb-vt-in{ from{ opacity:0; transform:translateY(10px) } }

/* Закреплённые части не анимируем вовсе — иначе они дрожат на каждом
   переходе. */
::view-transition-group(sb-topbar),
::view-transition-group(sb-side),
::view-transition-group(sb-menu){ animation:none }

@media (prefers-reduced-motion: reduce){
  ::view-transition-old(root), ::view-transition-new(root){ animation:none }
}

/* ==========================================================================
   Отклик на нажатие — везде и одинаковый.

   Палец не видит курсора и не получает подсветки при наведении: на
   сенсорном экране единственный ответ, который человек может получить, —
   это реакция на само касание. Без неё он жмёт второй раз, и заказ
   упаковывается дважды.

   Приём один на всю систему: волна от точки касания и лёгкая просадка
   элемента. Работает и для кнопок, и для строк списков, и для плиток.
   ========================================================================== */
/* Волне нужно, чтобы её обрезали по краям кнопки и чтобы кнопка была
   точкой отсчёта. Обрезку задаём здесь, а точку отсчёта — из скрипта и
   только тем, у кого её нет.
   Здесь нельзя писать position:relative: у плавающей кнопки меню
   position:fixed, и это правило сбивало её на место в конце страницы —
   палец касался кнопки, кнопка мгновенно уезжала вниз, и нажатие уходило
   в пустоту под ней. Меню не открывалось, а кнопка «пропадала». */
.sb-ripple{ overflow:hidden }
.sb-ripple-wave{
  position:absolute; border-radius:50%; pointer-events:none;
  background:currentColor; opacity:.22; transform:scale(0);
  animation: sb-ripple .5s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes sb-ripple{
  to{ transform:scale(2.4); opacity:0 }
}

/* Просадка при нажатии — для всего, что нажимается. Кнопки уже проседают
   своим правилом; здесь то же для строк, плиток и карточек. */
.hm-tile:active,
.ob-row[data-print]:active,
.sp-item:active,
.rg-row:active,
.us-row:active{
  transform: scale(.985);
  transition: transform .08s ease;
}

@media (prefers-reduced-motion: reduce){
  .sb-ripple-wave{ display:none }
  .hm-tile:active, .ob-row[data-print]:active, .sp-item:active{ transform:none }
}

/* Раздел-витрина в панели: заметно приглушён, а не чуть-чуть. Прежние
   72% прозрачности глаз не различал, и пункт выглядел обычным. */
.sb-side-links a.preview{ opacity:.5; filter:grayscale(.7) }
.sb-side-links a.preview:hover{ opacity:.85; filter:grayscale(0) }

/* Залипшее наведение на сенсорном экране.
 *
 * После касания браузер оставляет состояние :hover на кнопке до
 * следующего касания в другом месте. На заливке это выглядит как
 * «кнопка застряла нажатой», а там, где наведение меняет фон под текстом
 * того же цвета, надпись просто пропадает.
 *
 * Там, где мыши нет, наведения быть не должно вовсе. */
@media (hover: none){
  .hm-cta:hover,
  .hm-cta.ghost:hover,
  .an-btn:hover,
  .sb-btn-primary:hover,
  .sp-btn:hover,
  .cz-btn:hover,
  .us-mini:hover,
  .hm-tile:hover,
  .hm-period:hover,
  .cz-tab:hover{
    background: inherit;
    color: inherit;
    transform: none;
    filter: none;
  }
  /* Кнопки со своей заливкой сохраняют её: inherit взял бы фон родителя. */
  .hm-cta:not(.ghost):hover,
  .hm-cta-demo:hover{ background: transparent }
}

/* ==========================================================================
   Золотой знак в тёмной теме.

   Логотип — картинка, и перекрасить текст внутри неё стилями нельзя. Зато
   можно взять её форму как трафарет: маска вырезает силуэт, а под ним
   лежит золотой градиент с бегущим бликом.

   Приём даёт ровно то, что нужно, и не требует ни второго файла, ни
   правки самого знака. В светлой теме ничего не меняется: там фирменный
   сливовый на белом читается лучше золота.
   ========================================================================== */
:root[data-theme="dark"] .sb-side-brand,
:root:not([data-theme="light"]) .sb-side-brand{ position:relative }

/* Перелив по надписи — в обеих темах, но своим цветом.
 *
 * Картинка логотипа служит трафаретом: её собственные пиксели не видны,
 * видно то, что просвечивает сквозь её форму. Поэтому перекрасить надпись
 * можно, не трогая сам файл, — и цвет свободно меняется по теме.
 *
 * Днём — фиолетовая волна фирменного цвета: золото на белом читается
 * тускло, ему нужен тёмный фон, чтобы блик выглядел бликом. Ночью —
 * золото. */
.sb-side-brand img,
.tour-logo,
.sb-topbar .sb-logo{
  background:
    linear-gradient(100deg,
      var(--sb-purple-dark) 0%, #7f64a9 18%, #c8b2e4 34%, #a98fd0 44%,
      #7f64a9 60%, var(--sb-purple-dark) 78%, #7f64a9 100%);
  background-size: 260% 100%;
  -webkit-mask-image: url("/logo.svg");
  mask-image: url("/logo.svg");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-position: center;
  mask-position: center;
  animation: sb-gold 6s ease-in-out infinite;
  filter: drop-shadow(0 2px 8px rgba(82,45,106,.28));
}
:root[data-theme="dark"] .sb-side-brand img,
:root:not([data-theme="light"]) .sb-side-brand img,
:root[data-theme="dark"] .tour-logo,
:root:not([data-theme="light"]) .tour-logo,
:root[data-theme="dark"] .sb-topbar .sb-logo,
:root:not([data-theme="light"]) .sb-topbar .sb-logo{
  background:
    linear-gradient(100deg,
      #8a6a2a 0%, #d9ad4e 18%, #ffeec0 34%, #f5dc9a 44%,
      #d9ad4e 60%, #8a6a2a 78%, #d9ad4e 100%);
  background-size: 260% 100%;
  filter: drop-shadow(0 2px 8px rgba(217,173,78,.35));
}
@keyframes sb-gold{
  0%, 100%{ background-position: 0% 50% }
  50%{ background-position: 100% 50% }
}
@media (prefers-reduced-motion: reduce){
  .sb-side-brand img,
  .tour-logo,
  .sb-topbar .sb-logo{ animation:none }
}

/* ==========================================================================
   Кнопки сводки: окончательно одинаковые.

   Правил накопилось четыре слоя, и они спорили: главная получала
   окантовку, второстепенные — нет. Этот блок последний в файле и
   перекрывает предыдущие целиком.

   На сенсорном экране все три кнопки выглядят одинаково: там нет
   курсора, подсказать порядок нечем, кроме самого порядка — а он и так
   сверху вниз. Выделение возвращается только там, где есть мышь.
   ========================================================================== */
.hm-hero-actions .hm-cta,
.hm-hero-actions .hm-cta.ghost{
  background: transparent;
  color: var(--sb-purple-dark);
  border: 1.5px solid var(--sb-purple);
  border-radius: 12px;
  box-shadow: 0 3px 0 0 var(--sb-purple-dark), 0 5px 12px rgba(82,45,106,.22);
}
:root[data-theme="dark"] .hm-hero-actions .hm-cta,
:root[data-theme="dark"] .hm-hero-actions .hm-cta.ghost,
:root:not([data-theme="light"]) .hm-hero-actions .hm-cta,
:root:not([data-theme="light"]) .hm-hero-actions .hm-cta.ghost{
  color: var(--sb-purple);
  border-color: var(--sb-purple);
  box-shadow: 0 3px 0 0 var(--sb-purple-dark), 0 5px 14px rgba(0,0,0,.4);
}
.hm-hero-actions .hm-cta:active,
.hm-hero-actions .hm-cta.ghost:active{
  transform: translateY(3px);
  box-shadow: 0 0 0 0 var(--sb-purple-dark), 0 1px 3px rgba(82,45,106,.25);
}

/* Мышь есть — главную заливаем: в ряду из трёх кнопок глазу нужна точка
   входа, и на большом экране её нечем задать, кроме цвета. */
@media (min-width: 901px) and (hover: hover) and (pointer: fine){
  .hm-hero-actions .hm-cta:not(.ghost){
    background: linear-gradient(180deg, #9a80c4 0%, var(--sb-purple) 45%, var(--sb-purple-dark) 100%);
    color: #fff;
    border-color: var(--sb-purple-dark);
  }
  .hm-hero-actions .hm-cta:not(.ghost) .hm-play{
    background: rgba(255,255,255,.22);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.45);
  }
  .hm-hero-actions .hm-cta:not(.ghost) .hm-play::after{ border-left-color:#fff }
}

/* Тёмная тема: заливка главной кнопки была слишком светлой — в серединке
   градиента стояла светлая сирень (--sb-purple = #b49ad6), и белый текст по
   ней не читался (контраст ~2:1). Делаем весь градиент насыщённо-фиолетовым:
   белый текст теперь контрастный по всей высоте (≥4.9:1). Светлую тему и
   сенсорный (контурный) вид не трогаем — там читаемость и так в норме. */
@media (min-width: 901px) and (hover: hover) and (pointer: fine){
  :root[data-theme="dark"] .hm-cta:not(.ghost),
  :root:not([data-theme="light"]) .hm-cta:not(.ghost),
  :root[data-theme="dark"] .hm-hero-actions .hm-cta:not(.ghost),
  :root:not([data-theme="light"]) .hm-hero-actions .hm-cta:not(.ghost){
    background: linear-gradient(180deg, var(--sb-purple-dark) 0%, #4f386f 100%);
    color: #fff;
    border-color: #43305e;
  }
}

/* Номера заказа и наклейки на шаге упаковки.
 *
 * Крупно и рядом: с закрытой коробки читается только пара чисел с
 * наклейки, а зовётся заказ номером задания. Пока обе стороны на одном
 * экране, потерянную коробку находят за секунду; порознь — не находят
 * вовсе. */
.term-numbers{
  display:flex; gap:10px; flex-wrap:wrap; margin-top:16px;
}
.term-number{
  flex:1 1 200px; padding:12px 16px; border-radius:12px;
  background:var(--sb-surface-2); border:1px solid var(--sb-border);
}
.term-number i{
  display:block; font-style:normal; font-size:11px; font-weight:700;
  letter-spacing:.06em; text-transform:uppercase; color:var(--sb-text-muted);
}
.term-number b{
  display:block; margin-top:2px; font-size:24px; font-weight:800;
  font-variant-numeric:tabular-nums; letter-spacing:-.01em;
}
.term-number-wait b{ font-size:16px; color:var(--sb-text-muted); font-weight:600 }

/* Цифры с наклейки WB в карточке заказа.
 *
 * Единственное, что читается с закрытой коробки: номера заказа на
 * наклейке нет. Поэтому крупно и всегда на виду, а не мелкой строкой
 * среди артикулов — по ним ищут потерянную коробку. */
.sb-sticker-nums{
  margin-top:12px; padding:10px 14px; border-radius:10px;
  background:var(--sb-purple-bg,var(--sb-surface-2));
  border:1px solid var(--sb-border);
}
.sb-sticker-nums i{
  display:block; font-style:normal; font-size:10.5px; font-weight:700;
  letter-spacing:.06em; text-transform:uppercase; color:var(--sb-text-muted);
}
.sb-sticker-nums b{
  display:block; margin-top:1px; font-size:22px; font-weight:800;
  font-variant-numeric:tabular-nums; letter-spacing:.01em;
}

/* Выбор голоса — лист поверх терминала.
 *
 * Открывается редко и не мешает работе: голос настраивают один раз за
 * смену, а то и за всё время. Поэтому длинное нажатие на кнопку голоса,
 * а не отдельная кнопка в шапке — место там дорогое. */
.term-sheet-back{
  position:fixed; inset:0; z-index:80; padding:16px;
  background:rgba(0,0,0,.55); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center;
}
.term-sheet{
  width:100%; max-width:520px; max-height:88vh; overflow-y:auto;
  padding:22px; border-radius:16px;
  background:var(--sb-bg); border:1px solid var(--sb-border);
}
.term-sheet-head{
  display:flex; align-items:flex-start; justify-content:space-between; gap:14px;
}
.term-sheet-name{font-size:19px; font-weight:800; letter-spacing:-.02em}
.term-sheet-sub{margin-top:4px; font-size:13px; color:var(--sb-text-muted); max-width:44ch}
.term-sheet-x{
  flex:none; width:36px; height:36px; border-radius:50%; cursor:pointer;
  background:var(--sb-surface-2); border:1px solid var(--sb-border);
  color:var(--sb-text); font-size:20px; line-height:1;
}
.term-sheet-note{
  margin:16px 0 0; font-size:12.5px; line-height:1.55; color:var(--sb-text-muted);
}
.term-sheet-note b{color:var(--sb-text)}

.term-voices{display:flex; flex-direction:column; gap:8px; margin-top:18px}
.term-voice{
  display:flex; flex-direction:column; gap:2px; text-align:left; cursor:pointer;
  padding:13px 16px; border-radius:12px; font:inherit; color:var(--sb-text);
  background:var(--sb-surface); border:1px solid var(--sb-border);
}
.term-voice:hover{border-color:var(--sb-purple)}
.term-voice.active{
  background:var(--sb-purple); border-color:var(--sb-purple); color:#fff;
}
.term-voice b{font-size:16px; font-weight:700}
.term-voice i{font-style:normal; font-size:12px; opacity:.75}

/* Визуальный «пик» подтверждения скана в терминале: на успешный шаг сцена
   пускает зелёную волну, а иконка успеха подскакивает. Чистый CSS поверх
   уже существующего класса .state-success — логику скана не трогает. */
@keyframes sb-scanpop{
  0%{box-shadow:0 0 0 0 rgba(31,157,107,.45)}
  60%{box-shadow:0 0 0 20px rgba(31,157,107,0)}
  100%{box-shadow:0 0 0 0 rgba(31,157,107,0)}
}
@keyframes sb-iconpop{
  0%{transform:scale(.55);opacity:.35}
  60%{transform:scale(1.14)}
  100%{transform:scale(1)}
}
.sb-stage.state-success{animation:sb-scanpop .7s ease-out}
.sb-stage.state-success .sb-stage-icon{animation:sb-iconpop .5s cubic-bezier(.34,1.56,.64,1)}
@media (prefers-reduced-motion:reduce){
  .sb-stage.state-success,.sb-stage.state-success .sb-stage-icon{animation:none}
}

/* Всплывающее уведомление терминала (смена срока и пр.). */
.term-toast{
  position:fixed;left:50%;bottom:32px;transform:translateX(-50%) translateY(20px);
  background:#111827;color:#fff;padding:14px 22px;border-radius:12px;
  font-size:16px;font-weight:600;box-shadow:0 12px 32px rgba(0,0,0,.35);
  opacity:0;pointer-events:none;transition:opacity .25s ease, transform .25s ease;
  z-index:9999;max-width:90vw;text-align:center;line-height:1.35;
}
.term-toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
@media (prefers-reduced-motion:reduce){
  .term-toast{transition:opacity .25s ease}
}

/* Кликабельная плитка «Ошибок» на карточке смены терминала. */
.sb-shift-errtile{cursor:pointer;border-radius:12px;transition:background .15s ease, transform .1s ease;}
.sb-shift-errtile:hover{background:rgba(0,0,0,.04)}
.sb-shift-errtile:active{transform:scale(.97)}
.sb-shift-errtile:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(124,92,246,.35)}

/* Модалка списка ошибок смены. */
#shift-err-modal .se-back{
  position:fixed;inset:0;z-index:10000;display:flex;align-items:center;justify-content:center;
  background:rgba(15,18,30,.55);backdrop-filter:blur(3px);padding:20px;
}
#shift-err-modal .se-modal{
  width:min(560px,96vw);max-height:82vh;display:flex;flex-direction:column;
  background:var(--sb-surface,#fff);color:var(--sb-text,#1a1a2e);
  border-radius:18px;box-shadow:0 24px 70px rgba(0,0,0,.4);overflow:hidden;
}
#shift-err-modal .se-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:18px 22px;border-bottom:1px solid var(--sb-border,#eee);
}
#shift-err-modal .se-title{font-size:19px;font-weight:700}
#shift-err-modal .se-x{
  border:none;background:transparent;font-size:26px;line-height:1;cursor:pointer;
  color:var(--sb-text-muted,#888);width:38px;height:38px;border-radius:10px;
}
#shift-err-modal .se-x:hover{background:rgba(0,0,0,.06)}
#shift-err-modal .se-body{padding:10px 14px;overflow-y:auto}
#shift-err-modal .se-empty{padding:32px;text-align:center;color:var(--sb-text-muted,#888);font-size:16px}
#shift-err-modal .se-row{
  display:flex;align-items:flex-start;gap:12px;padding:13px 12px;
  border-bottom:1px solid var(--sb-border,#f0f0f0);border-left:4px solid transparent;border-radius:8px;
}
#shift-err-modal .se-row.se-cancel{border-left-color:#ef8a4b}
#shift-err-modal .se-row.se-print{border-left-color:#e0504f}
#shift-err-modal .se-row-main{flex:1;min-width:0}
#shift-err-modal .se-row-title{font-size:15px;font-weight:600;margin-bottom:3px}
#shift-err-modal .se-row-detail{font-size:13px;color:var(--sb-text-muted,#777);word-break:break-word}
#shift-err-modal .se-row-time{font-size:13px;color:var(--sb-text-muted,#999);font-variant-numeric:tabular-nums;white-space:nowrap}

/* «Пик» на каждый успешный скан — зелёная волна по экрану + подскок иконки. */
@keyframes sb-pulse-ring{
  0%{box-shadow:0 0 0 0 rgba(34,197,94,.5)}
  70%{box-shadow:0 0 0 26px rgba(34,197,94,0)}
  100%{box-shadow:0 0 0 0 rgba(34,197,94,0)}
}
@keyframes sb-pulse-pop{0%{transform:scale(1)}35%{transform:scale(1.035)}100%{transform:scale(1)}}
.sb-stage.sb-pulse{animation:sb-pulse-ring .6s ease-out, sb-pulse-pop .42s ease}
.sb-stage.sb-pulse .sb-stage-icon{animation:sb-iconpop .5s cubic-bezier(.34,1.56,.64,1)}

/* Ожидание скана — иконка мягко «дышит», подсказывая «наведи сюда». */
@keyframes sb-breathe{
  0%,100%{transform:scale(1);opacity:.9}
  50%{transform:scale(1.06);opacity:1}
}
.sb-stage.waiting .sb-stage-icon{animation:sb-breathe 1.8s ease-in-out infinite}

@media (prefers-reduced-motion: reduce){
  .sb-stage.sb-pulse,.sb-stage.sb-pulse .sb-stage-icon,.sb-stage.waiting .sb-stage-icon{animation:none}
}

/* Полноэкранная вспышка по краям на скан: видно с любого угла склада и не
   зависит от того, перерисовалась ли сцена (кольцо на .sb-stage обрезалось
   родителем). Только свечение по периметру — контент не перекрывает, кликам
   не мешает. Зелёная = принято, красная = ошибка. Логику скана не трогает. */
#sb-flash{position:fixed;inset:0;z-index:9998;pointer-events:none;opacity:0}
#sb-flash.ok{box-shadow:inset 0 0 150px 30px rgba(34,197,94,.60);animation:sb-flash-fade .5s ease-out}
#sb-flash.err{box-shadow:inset 0 0 170px 38px rgba(239,68,68,.66);animation:sb-flash-fade .6s ease-out}
@keyframes sb-flash-fade{0%{opacity:0}16%{opacity:1}100%{opacity:0}}
@media (prefers-reduced-motion: reduce){#sb-flash{display:none}}

/* Видео-фон Алтая для страниц (база). Главная тонко переопределяет в home.css. */
.sb-hero-bg{position:fixed;inset:0;z-index:-1;overflow:hidden;pointer-events:none;
  height:100lvh;min-height:100svh;background:#1b2a2b}
.sb-hero-bg video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(1.26) contrast(1.05)}
.sb-hero-veil{position:absolute;inset:0;
  background:color-mix(in srgb, var(--sb-bg) 55%, transparent)}
@media (max-width:720px){
  .sb-hero-veil{ background:color-mix(in srgb, var(--sb-bg) 48%, transparent) }
}
@media (prefers-reduced-motion: reduce){ .sb-hero-bg video{ display:none } }
