/* Воздух: дизайн-система продукта.
 *
 * Светлый холодный фон, стеклянные оболочки поверх него, крупные скругления,
 * многослойные мягкие тени, синий акцент. Экран читается как стопка карточек
 * на светлом столе, а не как чертёж: у продукта разговорная задача, человек
 * приходит сюда с тревогой про свою будущую квартиру.
 *
 * Иерархия поверхностей ровно трёхступенчатая, и это главное правило системы.
 * Оболочка (shell) это лист, на котором живёт экран. Карточка (card) лежит на
 * оболочке. Панель (panel) это врезка внутри карточки. Четвёртой ступени нет:
 * стекло на стекле на стекле перестаёт читаться как глубина и превращается в
 * муть.
 *
 * Здесь только система: токены и компонентный слой. Специфика конкретных
 * экранов живёт в site.css, рядом. Правка, которая выглядит как «поправить
 * систему под эту страницу», делается в site.css или не делается вовсе.
 *
 * Три отклонения от исходного концепта, все вынужденные и все намеренные.
 *
 * Шрифт локальный, а не из Google Fonts. Загрузка с чужого домена означает,
 * что адрес каждого посетителя уезжает третьей стороне, а третьи стороны у нас
 * перечислены поимённо в политике обработки данных. Ради шрифта список
 * получателей персональных данных не расширяют.
 *
 * Fira Mono, которым в концепте набраны служебные метки, номера и знаки
 * состояний, отсюда следует: локально его нет, а тянуть его из сети нельзя по
 * причине выше. Техническую роль играет Fira Sans Condensed вразрядку. Жест
 * тот же (узкое, служебное, не для чтения абзацем), а лишнего домена нет.
 *
 * Насыщенности 600 у Fira Sans в наборе тоже нет, есть 400, 500 и 700. Кегль
 * заголовка держит 700, подзаголовок и название карточки 500. Объявлять 600
 * было бы самообманом: браузер всё равно возьмёт ближайшую сверху, то есть
 * 700, просто мы перестали бы понимать, где какая.
 */

/* --- шрифты ------------------------------------------------------------ */
/* Fira Sans, SIL Open Font License 1.1.
 *
 * Сабсеты собраны своим проходом (pyftsubset), а не взяты у Google: в готовых
 * нет ни рубля, ни стрелок, ни знака пустого множества, а цена и знаки
 * состояний рисовались бы системным шрифтом вперемешку с остальным текстом.
 *
 * Латинский файл грузится практически всегда: в нём живут не только латинские
 * буквы, но и кавычки-ёлочки, неразрывный пробел, цифры и рубль. Кириллический
 * прибавляется к нему на русской странице, то есть на всех наших. */

@font-face {
  font-family: 'Fira Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/fira-sans-400-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Fira Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/fira-sans-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+20BD, U+2122,
    U+2190-2193, U+2205, U+2212, U+2215, U+2219, U+221A, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fira Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/fira-sans-500-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Fira Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/fira-sans-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+20BD, U+2122,
    U+2190-2193, U+2205, U+2212, U+2215, U+2219, U+221A, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fira Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/static/fonts/fira-sans-700-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Fira Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/static/fonts/fira-sans-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+20BD, U+2122,
    U+2190-2193, U+2205, U+2212, U+2215, U+2219, U+221A, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fira Sans Condensed';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/fira-sans-condensed-400-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Fira Sans Condensed';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/fira-sans-condensed-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+20BD, U+2122,
    U+2190-2193, U+2205, U+2212, U+2219, U+221A, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fira Sans Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/fira-sans-condensed-600-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Fira Sans Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/fira-sans-condensed-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+20BD, U+2122,
    U+2190-2193, U+2205, U+2212, U+2215, U+2219, U+221A, U+FEFF, U+FFFD;
}

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

:root {
  /* Фон холодный и с лёгким уклоном: ровная заливка под полупрозрачным
     стеклом даёт плоское пятно, а градиент проявляет саму прозрачность. */
  --color-bg: #eef0f4;
  --gradient-bg: linear-gradient(160deg, #eef0f4 0%, #e7ebf2 45%, #eceef2 100%);

  /* Чернила тремя ступенями, и ровно тремя.
   *
   * Четвёртая была и умерла: #68727f и #6b7480 отличались на единицы по
   * каналам, то есть на глаз не отличались вовсе. Ступень, которую никто не
   * видит, это не ступень, а разрешение поставить в шаблон любое из двух
   * значений наугад. Ниже muted не спускаемся: следующий тон уже не даёт
   * 4.5:1 на стекле, а «серее» перестаёт означать «менее важно» и начинает
   * означать «не прочитано».
   *
   * Ограничение muted: он рассчитан на стеклянную поверхность. На голом
   * градиенте фона он даёт 4.08:1, поэтому текст, лежащий прямо на фоне
   * (подвал, подписи под секциями), берёт ступень soft. */
  --color-ink: #1a212b;
  --color-ink-soft: #3d4654;
  --color-ink-muted: #68727f;

  /* Акцент двумя значениями. Заливка яркая, текст тёмный: #3b6ef0 на белом
     даёт 3.9:1, и для строки в 13 пикселей этого не хватает, а для полосы
     прогресса и точки состояния хватает с запасом. */
  --color-accent: #3b6ef0;
  --color-accent-strong: #2451c4;
  --color-accent-text: #2451c4;
  --color-accent-wash: rgba(59, 110, 240, 0.06);
  --color-accent-line: rgba(59, 110, 240, 0.14);

  /* Состояния. Цвет здесь всегда идёт вторым голосом, первым идёт знак: цвет
     один не читается ни на монохромном экране, ни человеком, который его не
     различает. Знаки приходят из разметки и из скриптов. */
  --color-calm: #256b3d;
  --color-calm-wash: rgba(46, 125, 72, 0.09);
  --color-calm-line: rgba(46, 125, 72, 0.16);
  --color-doubt: #8f6210;
  --color-doubt-wash: rgba(178, 124, 24, 0.1);
  --color-doubt-line: rgba(178, 124, 24, 0.18);
  --color-alarm: #b0432f;
  --color-alarm-wash: rgba(190, 70, 45, 0.06);
  --color-alarm-line: rgba(190, 70, 45, 0.14);

  /* Три ступени поверхностей, четвёртой нет намеренно. */
  --surface-shell: rgba(255, 255, 255, 0.55);
  --surface-shell-line: rgba(255, 255, 255, 0.7);
  --surface-card: rgba(255, 255, 255, 0.8);
  --surface-card-line: rgba(255, 255, 255, 0.95);
  --surface-panel: rgba(255, 255, 255, 0.75);
  --surface-panel-line: rgba(255, 255, 255, 0.9);
  --surface-quiet: rgba(23, 32, 50, 0.035);
  --surface-quiet-line: rgba(23, 32, 50, 0.12);
  --divider: rgba(23, 32, 50, 0.06);

  --blur-shell: 24px;

  /* Скругления убывают вместе с поверхностью: оболочка мягче карточки,
     карточка мягче панели, панель мягче кнопки. Радиус это тоже иерархия. */
  --radius-shell: 32px;
  --radius-card: 22px;
  --radius-panel: 18px;
  --radius-control: 14px;
  --radius-pill: 999px;

  /* Ширина колонки со знаком в списке шагов. Токеном, потому что от неё
     зависит отступ подписи на узком экране, и это правило живёт в другом
     файле: связанные голым совпадением числа разъезжаются молча. */
  --steps-mark-width: 18px;

  /* Тени многослойные: один слой даёт либо жёсткий край, либо грязное пятно.
     Ближний слой рисует край, средний отрывает от фона, дальний даёт вес. */
  --shadow-shell: 0 1px 2px rgba(23, 32, 50, 0.04), 0 8px 24px rgba(23, 32, 50, 0.06),
    0 24px 64px rgba(23, 32, 50, 0.08);
  --shadow-card: 0 1px 2px rgba(23, 32, 50, 0.03), 0 6px 20px rgba(23, 32, 50, 0.06);
  --shadow-soft: 0 2px 8px rgba(23, 32, 50, 0.06), 0 4px 14px rgba(23, 32, 50, 0.07);
  /* Тень основной кнопки цветная, под её же заливку: серая тень под тёмным
     объектом читается как грязь, а не как высота. */
  --shadow-ink: 0 2px 6px rgba(26, 33, 43, 0.18), 0 8px 20px rgba(26, 33, 43, 0.25);

  --font-body: 'Fira Sans', system-ui, sans-serif;
  --font-heading: 'Fira Sans', system-ui, sans-serif;
  /* Служебная роль: метки разделов, номера, единицы. Не для чтения абзацем. */
  --font-meta: 'Fira Sans Condensed', system-ui, sans-serif;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 22px;
  --space-6: 28px;
  --space-8: 36px;
  --space-12: 52px;
  --space-16: 72px;
}

/* --- основа ------------------------------------------------------------ */

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

/* Атрибут hidden обязан скрывать, чем бы элемент ни был.
 *
 * Браузер задаёт его правилом display:none с обычным весом, и любой класс
 * системы с собственным display (кнопка это inline-flex, ряд действий это
 * flex) молча его перебивает. Скрипт ставит hidden и уверен, что элемент
 * пропал, а на экране остаётся вторая кнопка рядом с первой. Ошибка тихая:
 * серверный прогон её не видит, а глазами она заметна только там, где оба
 * состояния сходятся на одном экране.
 */
[hidden] { display: none !important; }

/* Текст только для экранного читателя.
 *
 * Нужен там, где смысл несёт знак: «√», «∅», «×» это формы, а не слова, и
 * синтез речи читает их именами символов («квадратный корень»), либо молчит
 * вовсе. Знак остаётся глазу, слово достаётся уху, и ни один из двух способов
 * читать экран не оказывается второсортным.
 *
 * clip-path, а не display:none и не visibility:hidden: последние убирают
 * элемент и из дерева доступности тоже, то есть ровно того читателя, ради
 * которого текст и написан. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--color-bg);
  background-image: var(--gradient-bg);
  background-attachment: fixed;
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0;
}

h1 { font-size: 40px; }
h2 { font-size: 28px; }
h3 { font-size: 22px; }
h4 { font-size: 18px; }
h5 { font-size: 16px; }

h6 {
  font-family: var(--font-meta);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-ink-muted);
}

p { margin: 0 0 var(--space-4); }

a {
  color: var(--color-accent-text);
  text-decoration: none;
  text-underline-offset: 2px;
}

a:hover { text-decoration: underline; }

strong { font-weight: 500; }

/* Курсива в наборе нет ни одного начертания, и браузер нарисовал бы его
   наклоном прямого, то есть подделкой. Документы правит юрист в markdown, где
   звёздочки вокруг слова ставятся не задумываясь, поэтому выделение делается
   весом. */
em { font-style: normal; font-weight: 500; }

/* --- служебная метка --------------------------------------------------- */
/* Роль, которую в концепте играл Fira Mono: имя раздела, номер заказа,
   единица измерения. Узкое, вразрядку, никогда не абзацем. */

.meta {
  font-family: var(--font-meta);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.mono {
  font-family: var(--font-meta);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.muted { color: var(--color-ink-muted); }

/* --- поверхности ------------------------------------------------------- */

/* Лист, на котором живёт экран. Стекло здесь настоящее, с размытием фона. */
.shell {
  position: relative;
  background: var(--surface-shell);
  backdrop-filter: blur(var(--blur-shell));
  -webkit-backdrop-filter: blur(var(--blur-shell));
  border: 1px solid var(--surface-shell-line);
  border-radius: var(--radius-shell);
  box-shadow: var(--shadow-shell);
}

/* Карточка на оболочке. Размытия у неё нет намеренно: под ней уже стекло, и
   второй слой blur стоит кадров, не давая ничего глазу. */
.card {
  background: var(--surface-card);
  border: 1px solid var(--surface-card-line);
  border-radius: var(--radius-card);
  padding: var(--space-5);
  box-shadow: var(--shadow-card);
}

/* Врезка внутри карточки: пояснение, состояние, служебный блок. Тени нет,
   отделяет заливка. */
.panel {
  background: var(--surface-panel);
  border: 1px solid var(--surface-panel-line);
  border-radius: var(--radius-panel);
  padding: var(--space-4);
}

.panel-accent {
  background: var(--color-accent-wash);
  border-color: var(--color-accent-line);
}

.panel-calm {
  background: var(--color-calm-wash);
  border-color: var(--color-calm-line);
}

.panel-doubt {
  background: var(--color-doubt-wash);
  border-color: var(--color-doubt-line);
}

.panel-alarm {
  background: var(--color-alarm-wash);
  border-color: var(--color-alarm-line);
}

/* Пустое место, о котором сказано прямо. Пунктир, а не заливка: это единственный
   блок в системе, который сообщает об отсутствии данных, и выглядеть он обязан
   иначе, чем блок с данными. */
.panel-empty {
  background: var(--surface-quiet);
  border: 1px dashed var(--surface-quiet-line);
  color: var(--color-ink-muted);
}

.card > :last-child,
.panel > :last-child { margin-bottom: 0; }

/* --- кнопки ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px;
  line-height: 1.2;
  padding: var(--space-3) var(--space-5);
  /* Палец промахивается там, где мышь попадает. 44 пикселя это не запас на
     вырост, а нижняя граница, при которой нажатие большим пальцем на ходу
     перестаёт быть лотереей. Своей высоты кнопке не хватало двух пикселей. */
  min-height: 44px;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--color-ink);
  cursor: pointer;
  text-decoration: none;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
}

.btn:hover { text-decoration: none; }

/* Единственный плотный объект на экране. Тёмный, а не синий: синий на этом
   фоне уже занят ссылками и прогрессом, и кнопка того же цвета перестала бы
   быть точкой, к которой ведут остальные. */
.btn-primary {
  background: var(--color-ink);
  color: #fff;
  box-shadow: var(--shadow-ink);
}

.btn-primary:hover { background: #232c38; }
.btn-primary:active { transform: translateY(1px); box-shadow: var(--shadow-soft); }

.btn-secondary {
  background: var(--surface-panel);
  border-color: var(--surface-panel-line);
  box-shadow: var(--shadow-soft);
}

.btn-secondary:hover { background: rgba(255, 255, 255, 0.92); }
.btn-secondary:active { transform: translateY(1px); box-shadow: none; }

.btn-quiet {
  color: var(--color-accent-text);
  padding: var(--space-2) var(--space-3);
}

.btn-quiet:hover { background: var(--color-accent-wash); }

.btn-block { display: flex; width: 100%; }

.btn:disabled,
.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

/* --- чипы состояния ---------------------------------------------------- */
/* Вердикт по дому и району. Знак внутри текста, а не отдельным элементом:
   чип переносится целиком и не разваливается на узком экране. */

.chip {
  display: inline-block;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.3;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--surface-quiet);
  color: var(--color-ink-muted);
}

.chip-calm { background: var(--color-calm-wash); color: var(--color-calm); }
.chip-doubt { background: var(--color-doubt-wash); color: var(--color-doubt); }
.chip-alarm { background: var(--color-alarm-wash); color: var(--color-alarm); }

/* --- врезки ------------------------------------------------------------ */

.callout {
  font-size: 14px;
  line-height: 1.55;
  color: var(--color-ink-soft);
  background: var(--color-accent-wash);
  border: 1px solid var(--color-accent-line);
  border-radius: var(--radius-panel);
  padding: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4);
}

/* Тот же объект голосом громче: отказ, сбой, черновик договора. */
.callout-strong {
  color: var(--color-ink);
  background: var(--color-alarm-wash);
  border-color: var(--color-alarm-line);
}

/* --- поля -------------------------------------------------------------- */

.field {
  display: block;
  margin-bottom: var(--space-4);
}

.field-label {
  display: block;
  font-size: 14px;
  font-weight: 500;
  margin-bottom: var(--space-2);
}

.input {
  display: block;
  width: 100%;
  font-family: inherit;
  font-size: 15px;
  line-height: 1.5;
  color: var(--color-ink);
  background: rgba(255, 255, 255, 0.85);
  /* Граница поля это граница элемента управления, а не украшение: по ней
     человек понимает, куда можно писать. Прежние 10% чернил давали 1.2:1 к
     заливке поля, то есть на светлом стекле поле было почти неотличимо от
     фона до касания. Норма для управляющих элементов 3:1, и она достигается
     только заметно более плотной линией. */
  border: 1px solid rgba(23, 32, 50, 0.45);
  border-radius: var(--radius-control);
  padding: var(--space-3) var(--space-4);
  caret-color: var(--color-accent);
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.input::placeholder { color: var(--color-ink-muted); }

.input:focus {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px rgba(59, 110, 240, 0.12);
}

textarea.input {
  min-height: 120px;
  resize: vertical;
}

.field-hint {
  display: block;
  margin-top: var(--space-2);
  font-size: 13px;
  line-height: 1.45;
  color: var(--color-ink-muted);
}

/* --- список шагов ------------------------------------------------------ */
/* Ход сборки отчёта. Состояние несут знак (из скрипта) и вес, цвет идёт
   третьим: строка обязана читаться и без него. */

/* Список отделён сверху от того, что стоит перед ним. Без этого первая строка
   прилипала к панели прогресса и читалась как её продолжение, хотя панель это
   сводка, а список это раскрытие. Снизу отступа нет: его задаёт следующий
   блок, и два отступа подряд дали бы дыру. */
.steps {
  list-style: none;
  padding: 0;
  margin: var(--space-4) 0 0;
}

.steps li {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-1);
  border-top: 1px solid var(--divider);
}

.steps li:first-child { border-top: none; }

.steps .mark {
  flex: 0 0 var(--steps-mark-width);
  font-family: var(--font-meta);
  font-size: 15px;
  color: var(--color-ink-muted);
}

.steps .title {
  flex: 1;
  font-size: 15px;
}

.steps .step-note {
  font-size: 13px;
  color: var(--color-ink-muted);
}

.steps .done .mark { color: var(--color-calm); }
.steps .running .mark,
.steps .running .step-note { color: var(--color-accent-text); }
.steps .running .title { font-weight: 500; }
.steps .pending .title { color: var(--color-ink-muted); }
.steps .failed .mark,
.steps .failed .step-note { color: var(--color-alarm); }

/* --- полоса прогресса -------------------------------------------------- */

/* Трек не обрезает содержимое. Заливка внутри скруглена сама, а overflow тут
   отрезал бы ей цветную тень целиком: эффект был объявлен и не появлялся ни
   разу, что дороже отсутствия эффекта, потому что чинить будут не то. */
.bar {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--color-accent-line);
}

.bar > span {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  box-shadow: 0 1px 4px rgba(59, 110, 240, 0.4);
  transition: width 0.4s ease;
}

/* --- встроенные состояния ---------------------------------------------- */
/* Не переопределять на страницах: одинаковый фокус и одинаковое выделение по
   всему сайту это часть системы, а не украшение отдельного экрана. */

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

::selection { background: rgba(59, 110, 240, 0.22); }

:disabled { opacity: 0.45; }

/* --- сетка ------------------------------------------------------------- */

.grid {
  display: grid;
  gap: var(--space-4);
}

.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }

@media (max-width: 900px) {
  .grid-2,
  .grid-3 { grid-template-columns: 1fr; }

  h1 { font-size: 30px; }
  h2 { font-size: 24px; }
  h3 { font-size: 20px; }
}

/* Прозрачность и размытие это украшение, и человеку, который просил их
   выключить, они выключаются целиком. Стекло становится плотным листом:
   иерархия поверхностей держится тенью и рамкой, а не только прозрачностью,
   поэтому экран остаётся тем же экраном. */
@media (prefers-reduced-transparency: reduce) {
  .shell {
    background: rgba(255, 255, 255, 0.96);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .card { background: #fff; }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
