/* ==========================================================================
   APS Design System — компоненты (v1.0.0)
   Требует aps-tokens.css. Имена классов = имена компонентов в задачах для ИИ.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--aps-font);
  font-size: var(--aps-fs-body);
  line-height: var(--aps-lh-body);
  color: var(--aps-text);
  background: var(--aps-bg);
  -webkit-font-smoothing: antialiased;
}

/* Двухслойное кольцо: внутреннее контрастирует с тёмным фоном и с красной
   заливкой, внешнее — со светлым. Хотя бы один слой всегда даёт >= 3:1.
   outline виден в режиме высокой контрастности Windows и наследует
   собственный border-radius элемента. */
:focus-visible {
  outline: 2px solid var(--aps-focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--aps-focus-inner);
}

/* --- Раскладка ---------------------------------------------------------- */
.aps-container { width: 100%; max-width: var(--aps-container); margin-inline: auto; padding-inline: var(--aps-gutter); }
.aps-container--narrow { max-width: var(--aps-container-narrow); }

.aps-section { padding-block: var(--aps-section-py); background: var(--aps-bg); }
.aps-section--alt { background: var(--aps-bg-alt); }
.aps-section--inverse { background: var(--aps-bg-inverse); color: var(--aps-text-inverse); }

.aps-grid { display: grid; gap: var(--aps-space-5); }
.aps-grid--2 { grid-template-columns: repeat(2, 1fr); }
.aps-grid--3 { grid-template-columns: repeat(3, 1fr); }
.aps-grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1024px) { .aps-grid--3, .aps-grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 767px)  { .aps-grid--2, .aps-grid--3, .aps-grid--4 { grid-template-columns: 1fr; } }

/* --- Типографика --------------------------------------------------------
   Теги h1–h4 оформляются наравне с классами: заголовок без класса больше
   не выпадает в браузерный дефолт. Класс .aps-hN нужен, когда визуальный
   уровень не совпадает с уровнем тега. */
h1, .aps-h1, h2, .aps-h2, h3, .aps-h3, h4, .aps-h4 { font-family: var(--aps-font); color: var(--aps-text); }
.aps-display { font-size: var(--aps-fs-display); line-height: var(--aps-lh-display); font-weight: 800; letter-spacing: var(--aps-tracking-tight); margin: 0 0 var(--aps-space-4); }
h1, .aps-h1 { font-size: var(--aps-fs-h1); line-height: var(--aps-lh-h1); font-weight: 800; letter-spacing: var(--aps-tracking-tight); margin: 0 0 var(--aps-space-4); }
h2, .aps-h2 { font-size: var(--aps-fs-h2); line-height: var(--aps-lh-h2); font-weight: 700; letter-spacing: -0.01em; margin: 0 0 var(--aps-space-3); }
h3, .aps-h3 { font-size: var(--aps-fs-h3); line-height: var(--aps-lh-h3); font-weight: 700; letter-spacing: -0.01em; margin: 0 0 var(--aps-space-2); }
h4, .aps-h4 { font-size: var(--aps-fs-h4); line-height: var(--aps-lh-h4); font-weight: 600; margin: 0 0 var(--aps-space-2); }
.aps-lead { font-size: var(--aps-fs-lead); line-height: var(--aps-lh-lead); color: var(--aps-text-muted); margin: 0 0 var(--aps-space-5); max-width: 68ch; }
.aps-body { font-size: var(--aps-fs-body); line-height: var(--aps-lh-body); margin: 0 0 var(--aps-space-4); }
.aps-small { font-size: var(--aps-fs-small); line-height: var(--aps-lh-small); color: var(--aps-text-muted); }
.aps-mono { font-family: var(--aps-font-mono); font-variant-numeric: tabular-nums; }

/* Надзаголовок с красной чертой — прямая цитата из логотипа */
.aps-eyebrow {
  display: inline-flex; align-items: center; gap: var(--aps-space-2);
  font-size: var(--aps-fs-eyebrow); line-height: var(--aps-lh-eyebrow);
  font-weight: 700; text-transform: uppercase;
  letter-spacing: var(--aps-tracking-wide); color: var(--aps-accent-text);
  margin: 0 0 var(--aps-space-3);
}
.aps-eyebrow::before { content: ""; width: 24px; height: var(--aps-bar); background: var(--aps-accent); border-radius: var(--aps-radius-bar); }
.aps-section--inverse .aps-eyebrow,
.aps-hero .aps-eyebrow,
.aps-footer .aps-eyebrow { color: var(--aps-accent-on-dark); }
.aps-section--inverse .aps-eyebrow::before,
.aps-hero .aps-eyebrow::before,
.aps-footer .aps-eyebrow::before { background: var(--aps-red-500); }
.aps-hero .aps-accent-word, .aps-cta .aps-accent-word { color: var(--aps-accent-on-dark); }

/* Красное выделение ключевого слова (мотив «ASIA PREMIUM SERVICE») */
.aps-accent-word { color: var(--aps-accent-text); }
.aps-section--inverse .aps-accent-word { color: var(--aps-accent-on-dark); }

.aps-section-head { max-width: 720px; margin-bottom: var(--aps-space-7); }
.aps-section-head--center { margin-inline: auto; text-align: center; }
.aps-section-head--center .aps-eyebrow { justify-content: center; }
.aps-section--inverse .aps-lead,
.aps-section--inverse .aps-small { color: var(--aps-navy-200); }

/* --- Кнопки ------------------------------------------------------------- */
.aps-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--aps-space-2);
  font-family: inherit; font-size: 16px; font-weight: 600; line-height: 1;
  padding: 14px 28px; min-height: 44px; border-radius: var(--aps-radius-sm);
  border: 1.5px solid transparent; cursor: pointer; text-decoration: none;
  transition: background var(--aps-t-base), color var(--aps-t-base), border-color var(--aps-t-base);
}
.aps-btn--primary { background: var(--aps-accent); color: #fff; }
.aps-btn--primary:hover { background: var(--aps-accent-hover); }
.aps-btn--primary:active { background: var(--aps-accent-active); }

.aps-btn--secondary { background: transparent; color: var(--aps-text); border-color: var(--aps-text); }
.aps-btn--secondary:hover { background: var(--aps-text); color: var(--aps-bg); }

.aps-btn--ghost { background: transparent; color: var(--aps-text); border-color: transparent; padding-inline: var(--aps-space-3); }
.aps-btn--ghost:hover { color: var(--aps-accent-text); }

.aps-section--inverse .aps-btn--secondary,
.aps-hero .aps-btn--secondary,
.aps-cta .aps-btn--secondary,
.aps-footer .aps-btn--secondary { color: #fff; border-color: rgba(255,255,255,0.55); }
.aps-section--inverse .aps-btn--secondary:hover,
.aps-hero .aps-btn--secondary:hover,
.aps-cta .aps-btn--secondary:hover,
.aps-footer .aps-btn--secondary:hover { background: #fff; color: var(--aps-navy-900); }
.aps-section--inverse .aps-btn--ghost,
.aps-hero .aps-btn--ghost,
.aps-cta .aps-btn--ghost { color: #fff; }
.aps-hero .aps-btn--ghost:hover,
.aps-cta .aps-btn--ghost:hover { color: var(--aps-accent-on-dark); }

.aps-btn--sm { font-size: 14px; padding: 10px 18px; }
.aps-btn--lg { font-size: 17px; padding: 17px 34px; }
.aps-btn--block { width: 100%; }
.aps-btn[disabled], .aps-btn--disabled { opacity: 0.45; pointer-events: none; }
@media (max-width: 767px) { .aps-btn { width: 100%; } .aps-btn--auto { width: auto; } }

.aps-btn-row { display: flex; flex-wrap: wrap; gap: var(--aps-space-3); align-items: center; }

/* --- Карточки ----------------------------------------------------------- */
.aps-card {
  background: var(--aps-surface); border: 1px solid var(--aps-border);
  border-radius: var(--aps-radius-md); padding: var(--aps-space-5);
  transition: border-color var(--aps-t-base), box-shadow var(--aps-t-base), transform var(--aps-t-base);
}
.aps-card:hover { border-color: var(--aps-border-strong); box-shadow: var(--aps-shadow-md); }
.aps-section--inverse .aps-card { background: rgba(255,255,255,0.04); border-color: var(--aps-border-inverse); }
.aps-section--inverse .aps-card:hover { border-color: var(--aps-border-strong); box-shadow: none; }

/* Размер вывода 32, а не 48: контур нарисован на сетке 24 с обводкой 2, и при
   выводе в 48 реальный штрих становится 4 px — ровно толщина акцентной полосы
   --aps-bar, из-за чего иконка начинает спорить с мотивом щита. Правило штриха:
   stroke-width = 2 x 24 / размер вывода, чтобы видимая обводка всегда была 2 px. */
.aps-card__icon { width: 32px; height: 32px; stroke-width: 1.5; color: var(--aps-accent); margin-bottom: var(--aps-space-4); display: block; }
.aps-card__text { color: var(--aps-text-muted); margin: 0; }
.aps-section--inverse .aps-card__text { color: var(--aps-navy-200); }

/* Icon-box: модификатора достаточно, дочерний класс остаётся поддержанным */
.aps-card--icon { display: flex; flex-direction: column; }
.aps-card--icon > svg:first-child,
.aps-card--icon > img:first-child,
.aps-card--icon .aps-card__icon {
  width: 32px; height: 32px; stroke-width: 1.5; color: var(--aps-accent);
  margin-bottom: var(--aps-space-4); display: block;
}

/* Карточка платформы: сверху изображение, снизу вторичная кнопка */
.aps-card--platform { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.aps-card--platform img { width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block; }
.aps-card--platform .aps-card__body { padding: var(--aps-space-5); display: flex; flex-direction: column; gap: var(--aps-space-3); flex: 1; }
.aps-card--platform .aps-btn { margin-top: auto; }

/* Карточка-кейс с красной полосой сверху */
.aps-card--case { border-top: var(--aps-bar) solid var(--aps-accent); }

/* --- Числа/метрики ------------------------------------------------------ */
.aps-stat { display: grid; gap: var(--aps-space-2); }
.aps-stat .aps-stat__label { margin-top: 0; }
.aps-stat__value { font-size: var(--aps-fs-stat); font-weight: 800; letter-spacing: var(--aps-tracking-tight); line-height: 1; color: var(--aps-text); }
.aps-stat__value .aps-accent-word { color: var(--aps-accent-text); }
.aps-stat__label { font-size: var(--aps-fs-small); color: var(--aps-text-muted); margin-top: var(--aps-space-2); }
/* Источник или оговорка под цифрой. Размер 13 — не новое значение шкалы,
   а та же нижняя ступень, что у eyebrow. Цвет text-muted (5.47), не
   text-subtle: 3.83 не проходит для обычного текста. */
.aps-stat__note { font-size: var(--aps-fs-eyebrow); line-height: 1.4; color: var(--aps-text-muted); margin-top: var(--aps-space-1); }
.aps-section--inverse .aps-stat__note { color: var(--aps-navy-200); }
.aps-section--inverse .aps-stat__value { color: #fff; }
.aps-section--inverse .aps-stat__label { color: var(--aps-navy-200); }

/* --- Списки ------------------------------------------------------------- */
.aps-list { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--aps-space-3); }
.aps-list li { position: relative; padding-left: 30px; }
.aps-list li::before {
  content: ""; position: absolute; left: 0; top: 0.45em; width: 12px; height: 14px;
  background: var(--aps-accent);
  /* силуэт щита из логотипа */
  clip-path: polygon(0 0, 100% 0, 100% 55%, 50% 100%, 0 55%);
}

/* --- Шаги процесса ------------------------------------------------------ */
.aps-steps { counter-reset: step; display: grid; gap: var(--aps-space-5); }
.aps-step { position: relative; padding-left: 60px; }
.aps-step::before {
  counter-increment: step; content: counter(step,decimal-leading-zero);
  position: absolute; left: 0; top: -2px;
  font-size: 20px; font-weight: 800; color: var(--aps-accent-text);
  letter-spacing: var(--aps-tracking-tight);
}
.aps-step::after { content: ""; position: absolute; left: 44px; top: 4px; width: 1px; height: calc(100% + var(--aps-space-5)); background: var(--aps-border); }
.aps-step:last-child::after { display: none; }

/* --- Логотипы клиентов --------------------------------------------------- */
.aps-logo-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--aps-space-7); }
.aps-logo-row img { height: 44px; width: auto; }
/* Приглушение — приём для ДЛИННОГО ряда, где важен ритм, а не отдельный знак.
   На коротком ряду (<= 6 логотипов) оно превращает доказательство в декорацию,
   поэтому по умолчанию логотипы в полном цвете, а grayscale включается явно. */
.aps-logo-row--muted img { filter: grayscale(1); opacity: 0.65; transition: filter var(--aps-t-base), opacity var(--aps-t-base); }
.aps-logo-row--muted img:hover { filter: none; opacity: 1; }
@media (hover: none) { .aps-logo-row--muted img { filter: none; opacity: 1; } }

/* --- Отзыв -------------------------------------------------------------- */
.aps-quote { border-left: var(--aps-bar) solid var(--aps-accent); padding-left: var(--aps-space-5); }
.aps-quote__text { font-size: var(--aps-fs-lead); line-height: var(--aps-lh-lead); margin: 0 0 var(--aps-space-4); }
.aps-quote__author { font-weight: 600; }
.aps-quote__role { font-size: var(--aps-fs-small); color: var(--aps-text-muted); }

/* --- CTA-полоса --------------------------------------------------------- */
.aps-cta { background: var(--aps-bg-inverse); color: var(--aps-text-inverse); border-radius: var(--aps-radius-lg); padding: var(--aps-space-8) var(--aps-space-6); text-align: center; }
.aps-cta .aps-h2 { color: var(--aps-text-inverse); }
.aps-cta p { color: var(--aps-text-inverse-muted); max-width: 620px; margin-inline: auto; }
.aps-cta--accent { background: var(--aps-accent); }
.aps-cta--accent p { color: rgba(255,255,255,0.9); }
/* На красной заливке полупрозрачная рамка даёт 2.21 при требуемых 3.0
   (WCAG 2.1 SC 1.4.11). Рамка становится сплошной белой — 4.59. */
.aps-cta--accent .aps-btn--secondary { border-color: var(--aps-white); }

/* --- Формы -------------------------------------------------------------- */
.aps-field { display: grid; gap: var(--aps-space-2); margin-bottom: var(--aps-space-4); }
.aps-label { font-size: var(--aps-fs-small); font-weight: 600; }
.aps-label__req { color: var(--aps-accent-text); }
.aps-input, .aps-select, .aps-textarea {
  font-family: inherit; font-size: 16px; color: var(--aps-text);
  background: var(--aps-white); border: 1.5px solid var(--aps-border-ui);
  border-radius: var(--aps-radius-sm); padding: 12px 14px; width: 100%;
  box-shadow: var(--aps-shadow-sm);
  transition: border-color var(--aps-t-base), box-shadow var(--aps-t-base);
}
.aps-input::placeholder, .aps-textarea::placeholder { color: var(--aps-text-muted); }
.aps-input:focus, .aps-select:focus, .aps-textarea:focus { border-color: var(--aps-focus); }
.aps-textarea { min-height: var(--aps-space-10); resize: vertical; }
.aps-field--error .aps-input, .aps-field--error .aps-textarea { border-color: var(--aps-danger); }
.aps-field__error { font-size: var(--aps-fs-small); color: var(--aps-danger); }
.aps-field__help { font-size: var(--aps-fs-small); color: var(--aps-text-muted); }
.aps-checkbox { display: flex; gap: var(--aps-space-3); align-items: flex-start; min-height: 44px; padding-block: var(--aps-space-2);
  font-size: var(--aps-fs-small); color: var(--aps-text-muted); cursor: pointer; }
.aps-checkbox input { width: 24px; height: 24px; accent-color: var(--aps-accent); margin-top: 0; flex: none; }

/* --- Таблица ------------------------------------------------------------ */
.aps-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.aps-table-wrap .aps-table { min-width: 560px; }
.aps-table { width: 100%; border-collapse: collapse; font-size: var(--aps-fs-body); }
.aps-table th, .aps-table td { text-align: left; padding: var(--aps-space-3) var(--aps-space-4); border-bottom: 1px solid var(--aps-border); }
.aps-table thead th { background: var(--aps-bg-alt); font-size: var(--aps-fs-small); text-transform: uppercase; letter-spacing: 0.06em; color: var(--aps-text-muted); border-bottom: 1.5px solid var(--aps-border-strong); }
.aps-table tbody tr:hover { background: var(--aps-surface-alt); }

/* --- Бейджи и теги ------------------------------------------------------ */
.aps-badge { display: inline-flex; align-items: center; gap: 6px; font-size: var(--aps-fs-eyebrow); font-weight: 600; padding: 4px 10px; border-radius: var(--aps-radius-pill); background: var(--aps-accent-soft); color: var(--aps-accent-active); }
.aps-badge--neutral { background: var(--aps-gray-100); color: var(--aps-text-muted); }
.aps-badge--success { background: var(--aps-success-bg); color: var(--aps-success-text); }
.aps-badge--warning { background: var(--aps-warning-bg); color: var(--aps-warning-text); }
.aps-badge--info { background: var(--aps-info-bg); color: var(--aps-navy-700); }
/* Подтверждённый статус: не заливка-статус, а штамп. Собственного цвета
   не заводит — белая поверхность, граница контрола и галочка цветом accent. */
.aps-badge--verified { background: var(--aps-surface); color: var(--aps-text); border: 1.5px solid var(--aps-border-ui); padding: 6px 12px; }
.aps-badge--verified svg { width: 14px; height: 14px; stroke-width: 3.4; color: var(--aps-accent); flex: none; }
.aps-section--inverse .aps-badge--verified svg,
.aps-cta .aps-badge--verified svg,
.aps-hero .aps-badge--verified svg { color: var(--aps-accent-on-dark); }

/* --- Уведомление -------------------------------------------------------- */
.aps-note { border-left: var(--aps-bar) solid var(--aps-accent); background: var(--aps-accent-soft); padding: var(--aps-space-4) var(--aps-space-5); border-radius: 0 var(--aps-radius-sm) var(--aps-radius-sm) 0; }
.aps-note--info { border-color: var(--aps-info); background: var(--aps-info-bg); }
.aps-note--success { border-color: var(--aps-success); background: var(--aps-success-bg); }
.aps-note--warning { border-color: var(--aps-warning); background: var(--aps-warning-bg); }

/* --- Аккордеон (FAQ) ---------------------------------------------------- */
.aps-accordion { border-top: 1px solid var(--aps-border); }
.aps-accordion__item { border-bottom: 1px solid var(--aps-border); }
.aps-accordion__head { display: flex; justify-content: space-between; align-items: center; gap: var(--aps-space-4); width: 100%; background: none; border: 0; padding: var(--aps-space-4) 0; font: inherit; font-weight: 600; color: var(--aps-text); text-align: left; cursor: pointer; }
.aps-accordion__head::after { content: "+"; color: var(--aps-accent-text); font-size: 22px; font-weight: 700; line-height: 1; }
.aps-accordion__item[open] .aps-accordion__head::after { content: "–"; }
.aps-accordion__body { padding-bottom: var(--aps-space-4); color: var(--aps-text-muted); }

/* --- Хедер / футер ------------------------------------------------------ */
.aps-header { display: flex; align-items: center; justify-content: space-between; gap: var(--aps-space-5); padding-block: var(--aps-space-4); border-bottom: 1px solid var(--aps-border); }
.aps-header__logo img, .aps-header__logo svg { height: 36px; width: auto; display: block; }
.aps-nav { display: flex; gap: var(--aps-space-5); align-items: center; }
.aps-nav a { display: inline-flex; align-items: center; min-height: 44px; color: var(--aps-text); text-decoration: none; font-weight: 500; font-size: 16px; padding-block: var(--aps-space-1); border-bottom: 2px solid transparent; }
.aps-nav a:hover, .aps-nav a[aria-current="page"] { color: var(--aps-accent-text); border-bottom-color: var(--aps-accent); }

.aps-footer { background: var(--aps-bg-inverse); color: var(--aps-text-inverse); padding-block: var(--aps-space-8) var(--aps-space-5); }
.aps-footer a { color: var(--aps-text-inverse-muted); text-decoration: none; }
.aps-footer a:hover { color: var(--aps-text-inverse); }
.aps-footer__bottom { margin-top: var(--aps-space-6); padding-top: var(--aps-space-4); border-top: 1px solid var(--aps-border-inverse); font-size: var(--aps-fs-small); color: var(--aps-navy-300); }

/* --- Hero --------------------------------------------------------------- */
.aps-hero { padding-block: var(--aps-space-9); background: var(--aps-bg-inverse); color: var(--aps-text-inverse); }
.aps-hero__grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--aps-space-7); align-items: center; }
@media (max-width: 1024px) { .aps-hero__grid { grid-template-columns: 1fr; } }
.aps-hero .aps-h1 { color: #fff; }
.aps-hero p { color: var(--aps-navy-200); }
.aps-hero__media img { width: 100%; border-radius: var(--aps-radius-lg); display: block; box-shadow: var(--aps-shadow-lg); }


/* --- Скриншоты платформ и карты ------------------------------------------
   Главное изображение продукта. Голый кадр: рамок и «шапок браузера» нет.
   Аннотации — только красный контур участка и подпись ВНЕ кадра.
   object-position: left top — кадр интерфейса читается от левого верхнего
   угла (панель объектов, меню), и обрезка съедает пустую часть карты,
   а не то, ради чего скриншот сделан. */
.aps-shot { position: relative; margin: 0; }
.aps-shot img {
  display: block; width: 100%; aspect-ratio: 16/9;
  object-fit: cover; object-position: left top;
  border-radius: var(--aps-radius-lg); border: 0;
}
.aps-shot--tall img { aspect-ratio: 4/3; }
/* Вертикальный кадр кабинета или приложения. Рамка устройства не рисуется:
   пропорция сама говорит, что это экран телефона. */
.aps-shot--portrait { max-width: 360px; }
.aps-shot--portrait img { aspect-ratio: 3/4; }
.aps-section--inverse .aps-shot img,
.aps-hero .aps-shot img { box-shadow: var(--aps-shadow-lg); }
/* На мобильном 16:9 даёт кадр высотой ~220 px — интерфейс нечитаем.
   Кадр переключается на 4:3 и показывает фрагмент, а не весь экран. */
@media (max-width: 767px) {
  .aps-shot img { aspect-ratio: 4/3; }
  .aps-shot--portrait img { aspect-ratio: 3/4; }
}
/* Подсветка участка и плашка обезличивания лежат поверх ЧУЖОГО интерфейса,
   яркость которого системе неизвестна: карта бывает и светлой, и тёмной.
   Поэтому обе получают белое отделяющее кольцо 1 px — та же двухслойная
   логика, что у кольца фокуса: хотя бы один слой всегда даёт >= 3:1.
   Замер: красный контур на тёмной карте #2E406B — 2.22 (мало), белое кольцо
   там же — 10.19; на светлой карте наоборот. Плашка navy на тёмном — 1.59,
   на светлом — 16.20. */
.aps-shot__mark {
  position: absolute; border: 2px solid var(--aps-accent);
  border-radius: var(--aps-radius-xs); pointer-events: none;
  box-shadow: 0 0 0 1px var(--aps-white);
}
/* Обезличивание: сплошная плашка поверх персональных данных.
   Размытие запрещено — оно обратимо и читается как брак печати. */
.aps-shot__redact {
  position: absolute; background: var(--aps-navy-900);
  border-radius: var(--aps-radius-xs); pointer-events: none;
  box-shadow: 0 0 0 1px var(--aps-white);
}
.aps-shot__caption {
  display: block; margin-top: var(--aps-space-3);
  font-size: var(--aps-fs-small); line-height: var(--aps-lh-small);
  color: var(--aps-text-muted);
}
.aps-section--inverse .aps-shot__caption { color: var(--aps-text-muted); }

/* --- Вход по ролям -------------------------------------------------------- */
.aps-role-grid { display: grid; gap: var(--aps-space-5); grid-template-columns: repeat(2, 1fr); }
@media (max-width: 767px) { .aps-role-grid { grid-template-columns: 1fr; } }
.aps-role-card { display: flex; flex-direction: column; gap: var(--aps-space-3); }
.aps-role-card__icon { width: 32px; height: 32px; stroke-width: 1.5; color: var(--aps-accent); display: block; }
.aps-role-card .aps-btn { margin-top: auto; align-self: flex-start; }

/* --- Мобильное меню ------------------------------------------------------- */
.aps-nav-toggle {
  display: none; width: 44px; height: 44px; padding: 0; flex: none;
  align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer; color: var(--aps-text);
  border-radius: var(--aps-radius-sm);
}
.aps-nav-toggle span { position: relative; display: block; width: 22px; height: 2px; background: currentColor; }
.aps-nav-toggle span::before,
.aps-nav-toggle span::after { content: ""; position: absolute; left: 0; width: 22px; height: 2px; background: currentColor; }
.aps-nav-toggle span::before { top: -7px; }
.aps-nav-toggle span::after  { top: 7px; }
.aps-nav-toggle[aria-expanded="true"] span { background: transparent; }
.aps-nav-toggle[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.aps-nav-toggle[aria-expanded="true"] span::after  { top: 0; transform: rotate(-45deg); }

@media (max-width: 1024px) {
  .aps-nav-toggle { display: inline-flex; }
  .aps-header { position: relative; flex-wrap: wrap; }
  .aps-nav {
    display: none; order: 3; flex-basis: 100%; flex-direction: column;
    align-items: stretch; gap: 0; padding-block: var(--aps-space-2);
    border-top: 1px solid var(--aps-border);
  }
  .aps-nav[data-open="true"] { display: flex; }
  .aps-nav a { border-bottom: 0; border-left: 2px solid transparent; padding-inline: var(--aps-space-4); }
  .aps-nav a:hover, .aps-nav a[aria-current="page"] { border-bottom-color: transparent; border-left-color: var(--aps-accent); }
}

/* --- Вход по ролям в шапке (шорткод [aps_login_buttons]) ------------------
   Состав кнопок задаёт роль пользователя, оформление — одно на все роли.
   В шапке видно не больше двух кнопок; остальное уходит в aps-login__more. */
.aps-login { display: flex; align-items: center; gap: var(--aps-space-3); }
.aps-login .aps-btn { width: auto; }

.aps-login__more { position: relative; }
.aps-login__more > summary {
  display: inline-flex; align-items: center; gap: var(--aps-space-2);
  min-height: 44px; padding: 14px var(--aps-space-3);
  font-size: 16px; font-weight: 600; line-height: 1;
  color: var(--aps-text); cursor: pointer; list-style: none;
  border-radius: var(--aps-radius-sm);
  transition: color var(--aps-t-fast);
}
.aps-login__more > summary::-webkit-details-marker { display: none; }
.aps-login__more > summary::after {
  content: ""; width: 7px; height: 7px; margin-top: -3px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform var(--aps-t-fast);
}
.aps-login__more[open] > summary::after { transform: rotate(225deg); margin-top: 2px; }
.aps-login__more > summary:hover { color: var(--aps-accent-text); }

.aps-login__panel {
  position: absolute; right: 0; top: calc(100% + var(--aps-space-2));
  z-index: 30; min-width: 232px; display: grid; gap: var(--aps-space-1);
  padding: var(--aps-space-2);
  background: var(--aps-surface); color: var(--aps-text);
  border: 1px solid var(--aps-border); border-radius: var(--aps-radius-md);
  box-shadow: var(--aps-shadow-md);
  animation: aps-panel-in var(--aps-t-base) var(--aps-ease-enter) both;
}
.aps-login__panel a {
  display: flex; align-items: center; min-height: 44px;
  padding: 0 var(--aps-space-3); border-radius: var(--aps-radius-sm);
  font-size: 16px; font-weight: 500; color: var(--aps-text); text-decoration: none;
  transition: background var(--aps-t-fast), color var(--aps-t-fast);
}
.aps-login__panel a:hover { background: var(--aps-bg-alt); color: var(--aps-accent-text); }
/* Служебная ссылка администратора — заметно тише рабочих кнопок, но
   цель касания та же 44 px: правило 44 пикселей не знает исключений
   для «неважных» ссылок. Тише её делает кегль и цвет, а не размер цели. */
.aps-login__admin {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: var(--aps-fs-small); color: var(--aps-text-muted);
}

/* На тёмной шапке панель остаётся светлой: это меню, а не часть полотна */
.aps-section--inverse .aps-login__panel,
.aps-header.aps-inverse .aps-login__panel {
  background: var(--aps-white); color: var(--aps-navy-900);
  border-color: var(--aps-border-strong);
}

/* Мобильный: вход не прячется в бургер — он переезжает отдельной строкой
   под шапкой и остаётся виден при закрытом меню. */
@media (max-width: 1024px) {
  .aps-login {
    order: 4; flex-basis: 100%; flex-wrap: wrap;
    padding-top: var(--aps-space-3);
    border-top: 1px solid var(--aps-border);
  }
  .aps-login .aps-btn { flex: 1 1 160px; width: auto; }
  .aps-login__more { flex: 1 1 100%; }
  .aps-login__more > summary { justify-content: center; width: 100%; }
  /* Служебная ссылка занимает свою строку: рядом с кнопкой она зажимается
     к краю и перестаёт быть целью касания. */
  .aps-login__admin {
    flex: 1 1 100%; display: flex; align-items: center; justify-content: center;
    min-height: 44px;
  }
  .aps-login__panel { position: static; min-width: 0; box-shadow: none; margin-top: var(--aps-space-2); }
}

/* --- Ссылка в тексте ------------------------------------------------------
   Браузерный синий — третий цвет в системе, где третьего цвета нет. */
a.aps-link,
.aps-body a, .aps-lead a, .aps-card__text a, .aps-list a, .aps-quote__text a, .aps-note a {
  color: var(--aps-text); text-decoration: none;
  border-bottom: 1px solid var(--aps-border-ui);
  transition: color var(--aps-t-fast), border-color var(--aps-t-fast);
}
a.aps-link:hover,
.aps-body a:hover, .aps-lead a:hover, .aps-card__text a:hover,
.aps-list a:hover, .aps-quote__text a:hover, .aps-note a:hover {
  color: var(--aps-accent-text); border-bottom-color: var(--aps-accent);
}


/* --- Split-hero: композиция знака ----------------------------------------
   Щит разрезан по вертикали: слева красное, справа тёмное. Приём объявлен
   в Overview с первого дня — здесь он наконец становится компонентом. */
.aps-hero--split { position: relative; overflow: hidden; padding-block: var(--aps-space-10) var(--aps-space-9); }
.aps-hero--split .aps-container { position: relative; }
.aps-hero__edge {
  position: absolute; inset-block: 0; left: 0; width: var(--aps-bar);
  background: var(--aps-accent); transform-origin: top;
}
.aps-hero--split .aps-hero__grid { grid-template-columns: 1.15fr 1fr; gap: var(--aps-space-8); }
@media (max-width: 1024px) { .aps-hero--split .aps-hero__grid { grid-template-columns: 1fr; } }
/* Display берётся на полную: первый экран — единственное место, где он живёт */
.aps-hero--split .aps-display { color: var(--aps-text-inverse); max-width: 15ch; margin-bottom: var(--aps-space-5); }
.aps-hero--split .aps-lead { color: var(--aps-text-inverse-muted); max-width: 46ch; }

/* Фокальный момент: кромка прочерчивается сверху вниз — знак собирается.
   Один раз, при загрузке, только на первом экране. */
@keyframes aps-edge-draw { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.aps-hero--split .aps-hero__edge {
  animation: aps-edge-draw var(--aps-t-focal) both;
}

/* --- Служебное движение ---------------------------------------------------- */
/* Карточка: подъём на 2 px делает объявленный transform живым, а не мёртвым */
.aps-card:hover { transform: translateY(-2px); }
.aps-section--inverse .aps-card:hover { transform: none; }

/* Бургер: состояние объясняется переходом, а не мгновенной подменой */
.aps-nav-toggle span,
.aps-nav-toggle span::before,
.aps-nav-toggle span::after { transition: transform var(--aps-t-fast), background var(--aps-t-fast), top var(--aps-t-fast); }

/* Панель меню приезжает сверху — оттуда, откуда её открыли */
@keyframes aps-panel-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@media (max-width: 1024px) {
  .aps-nav[data-open="true"] { animation: aps-panel-in var(--aps-t-base) var(--aps-ease-enter) both; }
}

/* Ответ аккордеона проявляется, а не возникает */
@keyframes aps-answer-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.aps-accordion__item[open] .aps-accordion__body { animation: aps-answer-in var(--aps-t-base) var(--aps-ease-enter) both; }

/* --- Разделитель -------------------------------------------------------- */
.aps-divider { height: 1px; background: var(--aps-border); border: 0; margin-block: var(--aps-space-7); }
.aps-divider--accent { height: var(--aps-bar); width: 56px; background: var(--aps-accent); border-radius: var(--aps-radius-bar); }

/* --- Hero: три паттерна ----------------------------------------------------
   Паттерн выбирает не вкус, а пропорция главного кадра (правило выбора hero):
     --split  вертикальный или портретный кадр (кабинет, приложение) — текст
              слева, медиа справа;
     --stack  горизонтальный кадр (карта, список объектов) — текст узкой
              колонкой по центру, кадр во всю ширину контейнера;
     --plain  страница без скриншота (Оборудование, Цены) — медиа нет вовсе.
   Причина у --stack арифметическая: в --split правая колонка при контейнере
   1160 даёт кадру около 490 px. Скриншот Wialon шириной 490 px нечитаем —
   панель объектов сливается с картой. Тот же кадр на 1112 px читается. Это
   тот же довод, которым система уже обосновала переключение на 4:3 на мобильном.
   Авторский момент (прочерчивание кромки) остаётся один: hero на странице один. */
.aps-hero--stack { position: relative; overflow: hidden; padding-block: var(--aps-space-10) var(--aps-space-9); }
.aps-hero--stack .aps-container { position: relative; }
.aps-hero__lede { max-width: var(--aps-container-narrow); }
.aps-hero--stack .aps-hero__lede { margin-inline: auto; text-align: center; }
.aps-hero--stack .aps-display { color: var(--aps-text-inverse); max-width: 20ch; margin-inline: auto; margin-bottom: var(--aps-space-5); }
.aps-hero--stack .aps-lead { color: var(--aps-text-inverse-muted); max-width: 56ch; margin-inline: auto; }
.aps-hero--stack .aps-btn-row { justify-content: center; }
.aps-hero--stack .aps-eyebrow { justify-content: center; }
.aps-hero--stack .aps-hero__media { margin-top: var(--aps-space-8); }
.aps-hero--stack .aps-hero__edge { animation: aps-edge-draw var(--aps-t-focal) both; }

/* Страница без кадра открывается H1, а не Display: Display берётся на полную
   там, где рядом стоит главное изображение продукта. Один заголовок, держащий
   пустой экран размером 64 px, читается как объявление, а не как первый экран. */
.aps-hero--plain { padding-block: var(--aps-space-9); }
.aps-hero--plain .aps-hero__lede { max-width: var(--aps-container-narrow); }

/* Строка уточнений под кнопками: короткие проверяемые факты через разделитель.
   Не лозунг — условия сделки, которые снимают вопрос до звонка. */
.aps-hero__note { display: flex; flex-wrap: wrap; gap: var(--aps-space-2) var(--aps-space-4); margin-top: var(--aps-space-5); font-size: var(--aps-fs-small); color: var(--aps-text-inverse-muted); }
.aps-hero--stack .aps-hero__note { justify-content: center; }

/* --- Широкий кадр продукта -------------------------------------------------
   Пропорция для горизонтального интерфейса во всю ширину контейнера.
   До 767 px переключается на 4:3 по общему правилу кадра: 21:9 при ширине
   экрана 390 px даёт полосу высотой 167 px, на которой не видно ничего. */
.aps-shot--wide img { aspect-ratio: 21/9; }
@media (max-width: 767px) { .aps-shot--wide img { aspect-ratio: 4/3; } }

/* --- Доказательство одной секцией ------------------------------------------
   У APS четыре подтверждённых числа, один опубликованный отзыв и четыре
   логотипа. Разложенные по трём секциям страницы, они читаются как «больше
   нечем»; собранные в один блок — как ответ на вопрос «почему вам». Компонент
   ничего не рисует сам: он расставляет aps-stat, aps-logo-row и aps-quote. */
.aps-proof { display: grid; gap: var(--aps-space-8); }
.aps-proof__stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--aps-space-5); }
@media (max-width: 1024px) { .aps-proof__stats { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 767px)  { .aps-proof__stats { grid-template-columns: 1fr; } }
.aps-proof__divider { height: 1px; background: var(--aps-border); border: 0; margin: 0; }
/* Ряд логотипов — только на светлом: все четыре подтверждённых файла несут
   собственную светлую подложку и на тёмном без grayscale читаются как белые
   прямоугольники. В инверсной секции aps-proof идёт БЕЗ aps-logo-row. */
.aps-section--inverse .aps-proof .aps-logo-row { display: none; }
.aps-proof__foot { display: grid; grid-template-columns: 1fr 1fr; gap: var(--aps-space-7); align-items: start; }
@media (max-width: 1024px) { .aps-proof__foot { grid-template-columns: 1fr; } }

/* --- Карточка-ссылка -------------------------------------------------------
   Вся карточка — цель нажатия. В плитке отраслей и витрине оборудования
   заставлять целиться в слово «Подробнее» — потеря: цель 44 px существует,
   но занимает одну строку из шести. Состояния наследуются от .aps-card. */
a.aps-card--link { text-decoration: none; color: inherit; display: flex; flex-direction: column; }
a.aps-card--link .aps-card__more { margin-top: auto; padding-top: var(--aps-space-3); font-size: var(--aps-fs-small); font-weight: 600; color: var(--aps-accent-text); }
a.aps-card--link:hover .aps-card__more { color: var(--aps-accent-active); }
.aps-section--inverse a.aps-card--link .aps-card__more { color: var(--aps-accent-on-dark); }

/* --- Схемы и диаграммы -----------------------------------------------------
   То, что мы рисуем сами, а не снимаем с экрана: график «до и после настройки»,
   цепочка этапов, условная карта. Главный риск здесь не чужие персональные
   данные, как у скриншота, а то, что схему примут за показания прибора, —
   отсюда обязательная подпись и запрет числовой шкалы на оси.
   Значимого текста внутри SVG не бывает: он не переводится в казахскую версию
   и не читается скринридером. Сам SVG — aria-hidden, смысл несёт HTML рядом. */
.aps-scheme {
  background: var(--aps-surface-alt); border: 1px solid var(--aps-border);
  border-radius: var(--aps-radius-lg); padding: var(--aps-space-5);
}
.aps-scheme > svg { display: block; width: 100%; height: auto; }
.aps-inverse .aps-scheme,
.aps-section--inverse .aps-scheme,
.aps-hero .aps-scheme {
  background: linear-gradient(rgba(255,255,255,.04), rgba(255,255,255,.04)), var(--aps-bg-inverse);
  border-color: var(--aps-border-inverse);
}

/* Легенда — в HTML, не внутри вектора. Обязательна, когда линий две. */
.aps-scheme__legend { display: flex; flex-wrap: wrap; gap: var(--aps-space-2) var(--aps-space-5); margin-top: var(--aps-space-4); }
.aps-scheme__key { display: inline-flex; align-items: center; gap: var(--aps-space-2); font-size: var(--aps-fs-small); color: var(--aps-text-muted); }
.aps-scheme__key::before { content: ""; width: 16px; height: 3px; border-radius: 2px; background: currentColor; flex: 0 0 auto; }
.aps-scheme__key--event { color: var(--aps-accent-text); }
/* Ключ интервала: образец — заливка, а не отрезок. Найдено рендером: линейный
   образец у ключа, который описывает подсветку, читается как третья линия
   и нарушает собственное правило схемы «не больше двух линий». */
.aps-scheme__key--band::before { width: 16px; height: 12px; border-radius: 3px; background: var(--aps-accent); opacity: .16; }
.aps-section--inverse .aps-scheme__key { color: var(--aps-text-inverse-muted); }
.aps-section--inverse .aps-scheme__key--event { color: var(--aps-accent-on-dark); }

/* Роли линий, а не цвета. Красный на странице означает исключение, требующее
   внимания; схема не имеет права учить читателя другому значению цвета,
   поэтому «сырые данные» нейтральны, а «результат настройки» акцентен. */
.aps-scheme-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.aps-scheme-line--raw   { stroke: var(--aps-text-muted); }
.aps-scheme-line--event { stroke: var(--aps-accent); }
.aps-section--inverse .aps-scheme-line--raw   { stroke: var(--aps-text-inverse-muted); }
.aps-section--inverse .aps-scheme-line--event { stroke: var(--aps-accent-on-dark); }
.aps-scheme-axis { fill: none; stroke: var(--aps-border-strong); stroke-width: 1; }
.aps-section--inverse .aps-scheme-axis { stroke: var(--aps-border-inverse); }
.aps-scheme-band { fill: var(--aps-accent); opacity: .16; }

/* --- Живой первый экран ----------------------------------------------------
   aps-hero--live. Четвёртый паттерн, введён 16.09.2026 вместе со сменой
   эталона на waliot. Отличается от трёх остальных не композицией, а природой
   медиа: у --split, --stack и --plain медиа это кадр, здесь — фон плюс живая
   колонка показателей. Правило выбора hero поэтому дополнено четвёртой строкой:
   кадра нет, но есть работающая система, которую надо показать в работе.

   Цена приёма: ни одного сетевого запроса. Карта — инлайновый SVG, движение —
   stroke-dashoffset и offset-distance, счётчики — @property. У waliot на этом
   месте шесть видео; вёрстка даёт тот же смысл за ноль килобайт. */
.aps-hero--live { position: relative; overflow: hidden; padding-block: var(--aps-space-10) var(--aps-space-9); }
.aps-hero--live .aps-container { position: relative; z-index: 1; }
.aps-hero--live .aps-hero__grid { grid-template-columns: 1.05fr 0.95fr; gap: var(--aps-space-8); align-items: center; }
@media (max-width: 1024px) { .aps-hero--live .aps-hero__grid { grid-template-columns: 1fr; } }
.aps-hero--live .aps-display { color: var(--aps-text-inverse); max-width: 17ch; margin-bottom: var(--aps-space-5); }
.aps-hero--live .aps-lead { color: var(--aps-text-inverse-muted); max-width: 48ch; }
.aps-hero--live .aps-hero__edge { animation: aps-edge-draw var(--aps-t-focal) both; }

/* Карта — фон, а не иллюстрация: она уходит под текст и гаснет к левому краю,
   чтобы заголовок читался по белому на navy, а не по линиям. */
.aps-hero__map { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.aps-hero__map svg { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Маска отрезает карту от текстовой колонки. Не вкус: линия, проходящая через
   заголовок, снижает его читаемость, а заголовок — LCP-элемент экрана. Карта
   живёт справа, под показателями, и мягко растворяется к середине. */
.aps-hero__map {
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 36%, #000 66%, #000 100%);
          mask-image: linear-gradient(90deg, transparent 0%, transparent 36%, #000 66%, #000 100%);
}
@media (max-width: 1024px) {
  .aps-hero__map { -webkit-mask-image: linear-gradient(180deg, transparent 0%, transparent 34%, #000 70%, #000 100%);
                           mask-image: linear-gradient(180deg, transparent 0%, transparent 34%, #000 70%, #000 100%); }
}
.aps-hero__map .aps-map-grid  { stroke: var(--aps-text-inverse-muted); stroke-width: 1; opacity: .10; fill: none; }
.aps-hero__map .aps-map-route { stroke: var(--aps-accent-on-dark); stroke-width: 1.5; opacity: .7; fill: none; stroke-linecap: round;
  stroke-dasharray: var(--len, 1200); stroke-dashoffset: var(--len, 1200);
  animation: aps-route-draw var(--aps-t-loop) var(--aps-ease-enter) infinite; }
.aps-hero__map .aps-map-route--b { --len: 1400; stroke: var(--aps-text-inverse-muted); opacity: .38;
  animation-duration: var(--aps-t-loop-slow); }
.aps-hero__map .aps-map-route--c { --len: 900; stroke: var(--aps-text-inverse-muted); opacity: .28;
  animation-duration: var(--aps-t-loop-fast); }
.aps-hero__map .aps-map-unit { fill: var(--aps-accent-on-dark); offset-rotate: 0deg;
  animation: aps-route-move var(--aps-t-loop) linear infinite; }
.aps-hero__map .aps-map-unit--b { fill: var(--aps-text-inverse-muted); opacity: .6; animation-duration: var(--aps-t-loop-slow); }

@keyframes aps-route-draw {
  0%   { stroke-dashoffset: var(--len, 1200); }
  55%  { stroke-dashoffset: 0; }
  85%  { stroke-dashoffset: 0; opacity: inherit; }
  100% { stroke-dashoffset: calc(var(--len, 1200) * -1); }
}
@keyframes aps-route-move { from { offset-distance: 0%; } to { offset-distance: 100%; } }

/* Колонка показателей. Поверхность — rgba(255,255,255,.04) поверх navy, то есть
   #20293E: не новый цвет, а тот же композит, что у карточки в инверсной секции.
   Замерено: белый 14.50, text-inverse-muted 9.58, accent-on-dark 5.38.
   Брендовый #E3271F на этой поверхности даёт 3.16 — заливка и полоса законны,
   текстом нельзя, правило двух красных действует и здесь. */
.aps-hero__widgets { display: grid; gap: var(--aps-space-3); }
/* Поверхность непрозрачная намеренно. При полупрозрачной заливке линии карты
   просвечивали сквозь виджет и шли поперёк строк ленты событий — найдено
   рендером. Слой rgba поверх непрозрачного navy даёт ровно тот же #20293E,
   на котором считался контраст, но перекрывает фон. Нового цвета не заведено. */
.aps-widget {
  background: linear-gradient(rgba(255,255,255,.04), rgba(255,255,255,.04)), var(--aps-bg-inverse);
  border: 1px solid var(--aps-border-inverse);
  border-radius: var(--aps-radius-md); padding: var(--aps-space-4) var(--aps-space-5);
}
.aps-widget__label { font-size: var(--aps-fs-small); color: var(--aps-text-inverse-muted); margin: 0 0 var(--aps-space-2); }
/* Специфичность: .aps-hero p (0,1,1) перебивает .aps-widget__value (0,1,0),
   и цифра приходила приглушённой. Селектор поднят намеренно, а не !important. */
.aps-hero .aps-widget__value,
.aps-widget__value { font-size: var(--aps-fs-stat); font-weight: 800; line-height: 1; letter-spacing: -.02em; color: #fff; margin: 0; }
.aps-widget__unit  { font-size: var(--aps-fs-h4); font-weight: 600; color: var(--aps-text-inverse-muted); margin-left: var(--aps-space-2); }
.aps-widget__note  { font-size: var(--aps-fs-small); color: var(--aps-text-inverse-muted); margin: var(--aps-space-2) 0 0; }
.aps-widget__accent { color: var(--aps-accent-on-dark); }

/* Лента событий: четыре строки, верхняя уезжает раз в 4 с. Демонстрационные
   данные — подпись обязательна, как у схемы. Номерных знаков в строках нет
   и быть не может. */
.aps-widget__feed { list-style: none; margin: var(--aps-space-2) 0 0; padding: 0; display: grid; gap: var(--aps-space-2);
  max-height: 132px; overflow: hidden; }
.aps-widget__feed li { display: flex; gap: var(--aps-space-3); font-size: var(--aps-fs-small); color: var(--aps-text-inverse-muted);
  animation: aps-feed-in var(--aps-t-base) var(--aps-ease-enter) both; }
.aps-widget__feed time { color: #fff; font-variant-numeric: tabular-nums; flex: 0 0 auto; }
@keyframes aps-feed-in { from { opacity: 0; transform: translateY(var(--aps-reveal-shift)); } to { opacity: 1; transform: none; } }

/* Спарклайн: линия одного показателя, без осей и без цифр внутри картинки.
   Значимый текст живёт в HTML — требование локализации, а не вкус. */
.aps-widget__spark { display: block; width: 100%; height: 48px; margin-top: var(--aps-space-3); }
.aps-widget__spark path { fill: none; stroke: var(--aps-accent-on-dark); stroke-width: 2; stroke-linecap: round; }
.aps-widget__spark .aps-spark-band { fill: var(--aps-accent); opacity: .16; }

/* Счётчик: набегает один раз при входе в вид. @property делает переменную
   анимируемой, поэтому набор цифры не стоит ни строки JS. */
@property --aps-count { syntax: '<integer>'; initial-value: 0; inherits: false; }
.aps-count { counter-reset: aps-n var(--aps-count); }
.aps-count::after { content: counter(aps-n); }
@supports (animation-timeline: view()) {
  .aps-count { animation: aps-count-up 1200ms var(--aps-ease-enter) both; animation-timeline: view(); animation-range: entry 0% cover 20%; }
}
@keyframes aps-count-up { to { --aps-count: var(--to, 0); } }

/* --- Появление при прокрутке -----------------------------------------------
   Запрет, действовавший до 16.09.2026, выводился из замера navixy, у которого
   reveal-механики нет. Эталон сменился на waliot, и правило пересмотрено.
   Конструкция намеренно такая: конечное состояние — состояние по умолчанию,
   анимация добавляется только там, где браузер её поддерживает. Поэтому без
   поддержки, без JS и при reduce страница выглядит так, будто всё уже
   проявилось, — и ни один текст никогда не остаётся невидимым. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .aps-reveal { animation: aps-reveal both; animation-timeline: view(); animation-range: var(--aps-reveal-range); }
    .aps-reveal-stagger > * { animation: aps-reveal both; animation-timeline: view(); animation-range: var(--aps-reveal-range); }
  }
}
@keyframes aps-reveal { from { opacity: 0; transform: translateY(var(--aps-reveal-shift)); } to { opacity: 1; transform: none; } }

/* --- Живой экран при приглушённом движении ---------------------------------
   Выключается движение, но не содержание: маршруты показаны прочерченными,
   маркеры стоят на местах, счётчики сразу в конечном значении. */
@media (prefers-reduced-motion: reduce) {
  .aps-hero__map .aps-map-route { stroke-dashoffset: 0; animation: none; }
  .aps-hero__map .aps-map-unit { animation: none; offset-distance: 62%; }
  .aps-hero--live .aps-hero__edge { animation: none; transform: none; }
  .aps-widget__feed li { animation: none; }
  .aps-count { animation: none; counter-reset: aps-n var(--to, 0); }
  .aps-reveal, .aps-reveal-stagger > * { animation: none; opacity: 1; transform: none; }
}

/* --- Приглушённое движение: компонентные исключения ------------------------
   Блок стоит последним намеренно: правила ниже должны переиграть анимации,
   объявленные выше, при равной специфичности. */
@media (prefers-reduced-motion: reduce) {
  .aps-card:hover { transform: none; }
  .aps-hero--split .aps-hero__edge,
  .aps-hero--stack .aps-hero__edge { animation: none; transform: none; }
  .aps-accordion__item[open] .aps-accordion__body,
  .aps-nav[data-open="true"],
  .aps-login__panel { animation: none; }
}
