/* =========================================================================
   Тема Marina — themes/marina/fonts.css
   Self-hosted шрифты (spec/docs/11: внешний CDN Google Fonts раскрывает IP
   посетителя третьей стороне — запрещено по умолчанию). Файлы woff2 — копия
   из projects/unona-site/build/media/fonts/ (сборка прошлого прогона unona,
   та же дизайн-система colors_and_type.css); источник субсетов — Google
   Fonts API (cyrillic + cyrillic-ext + latin, единый файл на начертание,
   без деления на unicode-range — так же, как было собрано для build unona,
   I2: не выдумываю новое сабсетирование). Начертания по requirements
   TASK-P3-FONTS-BEHAVIORS: Cormorant Garamond 300/400/500, Manrope
   400/500/600. Файл 300italic присутствует в build unona (реально
   собранный набор), не входит в обязательный список ячейки, но подключён
   ниже как есть — используется в цитатах/акцентах темы, если понадобится.
   ========================================================================= */

@font-face {
  font-family: "Cormorant Garamond";
  src: url("./fonts/cormorant-garamond-300.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Cormorant Garamond";
  src: url("./fonts/cormorant-garamond-300italic.woff2") format("woff2");
  font-weight: 300;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "Cormorant Garamond";
  src: url("./fonts/cormorant-garamond-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Cormorant Garamond";
  src: url("./fonts/cormorant-garamond-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Manrope";
  src: url("./fonts/manrope-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Manrope";
  src: url("./fonts/manrope-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Manrope";
  src: url("./fonts/manrope-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* =========================================================================
   Тема Marina — themes/marina/tokens.css
   Слой ТЕМЫ библиотеки блоков (DEC-001 п.1, п.5): ТОЛЬКО CSS-переменные,
   без классов и без касания разметки. Значения — дизайн-система Marina
   (projects/unona-site/design/project/colors_and_type.css), перенесены
   без изменений (I2 — не выдумываю, беру из первоисточника проекта).
   Иерархия токенов global→semantic→component→instance — spec/docs/11.
   ========================================================================= */

/* --- Web fonts (self-hosted, TASK-P3-FONTS-BEHAVIORS) -------------------
   Источник: colors_and_type.css. Ранее подключались через @import с CDN
   Google Fonts — нарушение spec/docs/11 (внешний CDN раскрывает IP
   посетителя третьей стороне). Заменено на self-hosted woff2:
   themes/marina/fonts.css (@font-face) + themes/marina/fonts/*.woff2,
   копия из projects/unona-site/build/media/fonts/ (та же дизайн-система).
   fonts.css подключается сборщиком (block_assembler.py) рядом с
   tokens.css — см. themes/marina/fonts.css для деталей начертаний. */

:root {
  /* ------------------------------------------------------------ COLOR */

  /* Поверхности — тёплые, светлые, бумажные */
  --linen:        #F4EEE6;
  --paper:        #FBF8F2;
  --sand:         #E9DDCF;
  --dune:         #D8C7B5;

  /* Бренд — пыльно-розовая линейка */
  --blush-50:     #F5E5DD;
  --blush-100:    #ECD2C5;
  --blush-200:    #E2C0AE;
  --blush-300:    #D2A492;
  --blush-400:    #B98674;
  --blush-500:    #9C6957;

  /* Cocoa — глубокие тёплые нейтрали (замена чёрного) */
  --cocoa-900:    #2A1E1A;
  --cocoa-700:    #4A372F;
  --cocoa-500:    #6B5048;
  --cocoa-300:    #8B6F65;
  --cocoa-200:    #B09A91;

  /* Sage — спокойный акцент */
  --sage-100:     #DDE3D5;
  --sage-300:     #A8B59A;
  --sage-500:     #7B8A6E;

  /* Gilt — тёплое золото (только декоративно) */
  --gilt-300:     #D4B98A;
  --gilt-500:     #B8956A;

  /* Семантика состояний */
  --positive:     #7B8A6E;
  --warning:      #C99A5B;
  --critical:     #B5544A;
  --info:         #8E9AA6;

  /* Семантические токены переднего/заднего плана (semantic level, doc 11) */
  --fg-1:         var(--cocoa-900);
  --fg-2:         var(--cocoa-500);
  --fg-3:         var(--cocoa-300);
  --fg-on-dark:   var(--linen);
  --fg-brand:     var(--blush-500);

  --bg-1:         var(--linen);
  --bg-2:         var(--paper);
  --bg-3:         var(--sand);
  --bg-inverse:   var(--cocoa-900);

  --border-1:     #E5DACB;
  --border-2:     var(--dune);
  --border-strong:var(--cocoa-300);

  /* ------------------------------------------------------------ TYPE */

  --font-display: 'Cormorant Garamond', 'Times New Roman', Georgia, serif;
  --font-body:    'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono:    ui-monospace, 'SF Mono', Menlo, monospace;

  /* Шкала насыщенности начертания — иерархическая (DEC-001 п.12) */
  --w-light:      300;
  --w-regular:    400;
  --w-medium:     500;
  --w-semibold:   600;

  /* Шкала размеров типографики (rem на базе 16px) — иерархическая */
  --t-display-xl: 5.25rem;
  --t-display-l:  3.75rem;
  --t-display-m:  2.75rem;
  --t-h1:         2.25rem;
  --t-h2:         1.75rem;
  --t-h3:         1.375rem;
  --t-h4:         1.125rem;
  --t-body:       1rem;
  --t-body-s:     0.9375rem;
  --t-caption:    0.8125rem;
  --t-eyebrow:    0.75rem;

  /* Межстрочный интервал */
  --lh-tight:     1.05;
  --lh-snug:      1.2;
  --lh-normal:    1.5;
  --lh-loose:     1.7;

  /* Трекинг */
  --ls-display:   -0.015em;
  --ls-tight:     -0.01em;
  --ls-normal:    0;
  --ls-eyebrow:   0.18em;

  /* ------------------------------------------------------------ SPACE
     Шкала пространств — иерархическая по классу значений (DEC-001 п.12) */
  --s-1:  4px;
  --s-2:  8px;
  --s-3:  12px;
  --s-4:  16px;
  --s-5:  20px;
  --s-6:  24px;
  --s-8:  32px;
  --s-10: 40px;
  --s-12: 48px;
  --s-16: 64px;
  --s-20: 80px;
  --s-24: 96px;
  --s-32: 128px;

  /* ------------------------------------------------------------ RADIUS */
  --r-xs: 2px;
  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 14px;
  --r-xl: 22px;
  --r-2xl:32px;
  --r-pill: 999px;

  /* ------------------------------------------------------------ SHADOW
     Мягкие, тёплые, никогда резкие. Без чистого чёрного. */
  --shadow-1: 0 1px 2px rgba(58, 42, 36, 0.04);
  --shadow-2: 0 4px 14px rgba(58, 42, 36, 0.06);
  --shadow-3: 0 12px 32px rgba(58, 42, 36, 0.08);
  --shadow-4: 0 24px 56px rgba(58, 42, 36, 0.10);

  --ring-blush: 0 0 0 3px rgba(210, 164, 146, 0.28);

  /* ------------------------------------------------------------ MOTION
     Шкала длительности + easing — иерархическая (DEC-001 п.12) */
  --ease-out:    cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --t-fast:   140ms;
  --t-normal: 240ms;
  --t-slow:   420ms;

  /* ------------------------------------------------------------ BREAKPOINTS
     Контрактные точки переключения макета (spec/docs/11, DEC-004) */
  --bp-sm: 360px;
  --bp-md: 960px;
  --bp-lg: 1200px;
  --bp-xl: 1600px;

  /* ------------------------------------------------------------ FLUID
     Резина между брейкпоинтами (DEC-001 п.14, находка Владельца на воротах
     Фазы 2, 2026-07-06, флаг FLG-003). Регулируемые размеры типографики,
     отступов секций и сеток текут плавно между токенами-границами через
     clamp(), а не скачками на брейкпоинтах; брейкпоинты остаются только для
     смены СТРУКТУРЫ раскладки. Добавлено рядом со старыми шкалами без их
     изменения — обратная совместимость: --t-*/--s-* продолжают работать как
     были, --tf-* — новый слой поверх них для мест, где нужна плавность.

     УСТАРЕВАЕТ (TASK-ETALON-LIB-1, 2026-07-08): --tf-* перенос ручных
     clamp()-формул этой ячейкой на общую шкалу --fl-* ниже (методика Utopia,
     см. блок «UTOPIA»). Новые виджеты/стили берут --fl-*; --tf-* НЕ удаляется
     (используются существующими стилями hero/quote_block/section_header) —
     миграция на --fl-* оставшихся мест вне охвата этой ячейки (I7, узкая
     зона — верх страницы; согласовать с последующей ячейкой библиотеки). */
  --tf-display-l:  clamp(var(--t-h1),  1.1rem + 3.5vw, var(--t-display-l));
  --tf-display-m:  clamp(var(--t-h2),  1rem + 2.6vw,   var(--t-display-m));
  --tf-h2:         clamp(var(--t-h3),  0.9rem + 1.6vw, var(--t-h2));
  --tf-section-y:  clamp(var(--s-12),  2rem + 4vw,     var(--s-20));
  --tf-gap:        clamp(var(--s-6),   1rem + 2vw,     var(--s-12));

  /* ------------------------------------------------------------ UTOPIA
     Шкалы типографики/пространств методики Utopia (utopia.fyi/type,
     utopia.fyi/space): clamp(min, yIntercept + slope*vw, max), опорные точки
     ширины 360px (min) и 1240px (max) — источник формулы: design/etalon/
     eskiz-glavnaya.html (эталон Владельца, DEC-003 unona-site), перенесены
     БЕЗ пересчёта (I2). КРИТИЧНО: операторы clamp() пишутся БЕЗ пробелов
     вокруг `+`/`*` в аргументе preferred (`0.8864rem + 0.2273vw`, не
     `0.8864rem+0.2273vw` — пробелы вокруг оператора обязательны для
     валидности, а вот слитный vw-множитель типа `10.2273vw` — норма);
     задокументированный инцидент — clamp() с некорректным пробелом внутри
     токена браузер отбрасывает ЦЕЛИКОМ правило (TASK-ETALON-LIB-1, докстрока
     задания ячейки). Именование --fl-<кегль-в-px-эталона>[b] — кегль на
     минимальной опоре 360px, суффикс b/в отличает вторую шкалу того же
     кегля (--fl-20 hd__name ≠ --fl-20b pain__h — разные max). */
  --fl-15:        clamp(0.9375rem, 0.8864rem + 0.2273vw, 1.0625rem);  /* 15->17px */
  --fl-17:        clamp(1.0625rem, 0.9858rem + 0.3409vw, 1.2500rem);  /* 17->20px */
  --fl-20:        clamp(1.2500rem, 1.1222rem + 0.5682vw, 1.5625rem);  /* 20->25px */
  --fl-20b:       clamp(1.2500rem, 1.1477rem + 0.4545vw, 1.5000rem);  /* 20->24px */
  --fl-22:        clamp(1.3750rem, 1.2472rem + 0.5682vw, 1.6875rem);  /* 22->27px */
  --fl-27:        clamp(1.6875rem, 1.5085rem + 0.7955vw, 2.1250rem);  /* 27->34px */
  --fl-28:        clamp(1.7500rem, 1.5455rem + 0.9091vw, 2.2500rem);  /* 28->36px */
  --fl-mark:      clamp(6.8750rem, 4.5739rem + 10.2273vw, 12.5000rem); /* 110->200px, декоративный глиф кавычки */
  --fl-space-72:  clamp(2.5000rem, 1.6818rem + 3.6364vw, 4.5000rem);  /* 40->72px */
  --fl-space-100: clamp(4.0000rem, 3.0795rem + 4.0909vw, 6.2500rem);  /* 64->100px */
  --fl-space-104: clamp(4.1250rem, 3.1534rem + 4.3182vw, 6.5000rem);  /* 66->104px */
  --fl-space-110: clamp(4.0000rem, 2.8239rem + 5.2273vw, 6.8750rem);  /* 64->110px */

  /* Заголовок секции (section_header__title) — TASK-RHYTHM-MATCH
     (2026-07-08): перенесено буквально из design/etalon/eskiz-glavnaya.html
     .pains__title/.progs__title/.dirs__title (clamp(2rem,1rem + 2.4vw,
     3.1rem), не Utopia-калиброванный по обеим опорам, как --fl-15..28 выше
     — сам эталон формулу для заголовков секций не переносил на 360/1240,
     писал clamp() вручную; перенесено как есть, без пересчёта, I2). */
  --fl-title-a:   clamp(2rem, 1rem + 2.4vw, 3.1rem);  /* 32->~49.6px, заголовок секции (pains/progs/dirs/faq) */

  /* ------------------------------------------------------ МОСТ OPEN PROPS
     Донор шкал: vendor/open-props@1.7.23/{shadows,easings}.min.css (research/
     frameworks.md — ранжирование №1, тема-мост; DEC-003 черновик). Файлы
     подключаются сборщиком СТРОГО ДО этого блока (шкала-донор объявляет свои
     переменные первой, тема Marina переопределяет только цветовой вход и
     добавляет алиасы под наши имена — var()-мост, не копипаста чисел, I2).

     --shadow-color Open Props — нейтральный HSL (220 3% 15%). Переопределяем
     ЗДЕСЬ HSL-эквивалентом --cocoa-900 (#2A1E1A → hsl(15 24% 13%), посчитано
     программно из hex, не подобрано на глаз), поэтому многослойная
     прогрессия --shadow-2/3/4 донора (K10/K11 best-practices.md — 2-5 слоёв
     с падающей альфа/растущим blur) становится ТЁПЛОЙ автоматически, без
     переписывания самих слоёв. */
  --shadow-color: 15 24% 13%;
  --shadow-strength: 3%;

  /* Алиасы под наши имена — K10/K11 (двух-/трёхслойные тени растущей
     elevation) поверх существующей однослойной шкалы --shadow-1..4. Старые
     --shadow-1..4 НЕ трогаются (обратная совместимость, I7) — новые имена
     op-* доступны стилям, которые хотят донорскую многослойность. */
  --op-shadow-1: 0 1px 2px -1px hsl(var(--shadow-color) / var(--shadow-strength));
  --op-shadow-2: 0 3px 5px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
                 0 7px 14px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%));
  --op-shadow-3: 0 -1px 3px 0 hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
                 0 1px 2px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
                 0 2px 5px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 4%)),
                 0 4px 12px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%)),
                 0 12px 15px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 7%));
  --op-shadow-4: 0 -2px 5px 0 hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
                 0 1px 1px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
                 0 2px 2px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
                 0 5px 5px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 4%)),
                 0 9px 9px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%)),
                 0 16px 16px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 6%));

  /* Easing-донор (vendor easings.min.css) — фирменный «перелёт» для карточек
     манеры marina-layered (K16: длительность/агрессивность easing растёт с
     масштабом изменения). --ease-out-3 донора — мягкий выход без перелёта,
     --ease-elastic-out-2 — с лёгким перелётом (аналог фирменного Geist
     cubic-bezier(.175,.885,.32,1.1) из best-practices.md §7). */
  --op-ease-out: cubic-bezier(0, 0, .3, 1);
  --op-ease-elastic-out: cubic-bezier(.5, 1, .75, 1.25);
}

/* =========================================================================
   layout/base.css — сетка и контейнер общего каркаса библиотеки блоков
   Минимально достаточное для секции hero (DEC-001 п.10): ширины
   full_bleed/container секции-сборки. Регулируемые значения — только
   var() (DEC-001 п.12); брейкпоинты — контрактные точки 360/960/1200/1600
   (spec/docs/11).
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }

/* `color-scheme: light` — сайт светлый по дизайну. Без этого объявления
   браузер (или хост-страница превью) в тёмной теме красит канву тёмным, а
   секции БЕЗ собственного фона (напр. `.section--sticky-split` с FAQ)
   проваливаются на неё: тёмный текст на тёмном, нечитаемо. Найдено живым
   замером (2026-07-09, замечание Владельца «шрифты стали нечитаемые»). */
html {
  -webkit-text-size-adjust: 100%;
  color-scheme: light;
}

body {
  margin: 0;
  overflow-x: hidden; /* QA: без горизонтального скролла на 360/1200 */
  /* Явная канва страницы. Раньше фон не задавался вовсе — страница
     полагалась на белый фон браузера по умолчанию (bodyBg было
     rgba(0,0,0,0)); в тёмной теме это давало чёрную подложку под
     прозрачными секциями. */
  background: var(--paper, #FBF8F2);
  /* Найдено ячейкой TASK-P3-CANONIZE-FIX-EXEC (перенос ручной правки
     build/index.html в канон, п.6б задания): без явного font-family на
     body браузер применяет UA-стиль (обычно serif) ко всему тексту
     страницы, если ни один элемент текста не задаёт шрифт явно —
     основы block-library стилизуют конкретные классы (__title, __text
     и т.д.), но не голый текстовый узел body. */
  font-family: var(--font-body, sans-serif);
  color: var(--fg-1, #111);
}

img, svg { max-width: 100%; display: block; }

/* Секция full_bleed — во всю ширину вьюпорта, внутренний контейнер
   ограничивает содержимое (DEC-001 п.10, реестр block-library).
   Ритм вертикальных отступов между секциями — один токен на все секции
   (TASK-P3-CANONIZE-FIX-EXEC, п.1 задания): --tf-section-y с константным
   запасным значением через clamp, если тема не переопределила токен.

   ПОЧИНКА (TASK-RHYTHM-MATCH, 2026-07-08, гонка специфичности): секции,
   чья ОСНОВА уже несёт собственный вертикальный ритм (hero — первый экран
   без общего правила отступа секций, cta-block и disclaimer — узкие
   акцентные полосы с собственным padding в base.css основы, registry.yaml
   self_wrapped:true) ИСКЛЮЧЕНЫ из этого правила через :not() — не
   получают .section padding-block ВООБЩЕ, а не получают его и тут же
   обнуляются вторым конкурирующим правилом. Раньше здесь стояло два
   правила: `.section{padding-block:var(--tf-section-y,...)}` +
   `.section.hero,.section.cta-block,.section.disclaimer{padding-block:0}`
   — специфичность второго правила (0,2,0, два класса) ВСЕГДА побеждает
   специфичность собственного правила виджета (`.hero{padding-block:
   var(--fl-space-72)...}` в bases/hero/base.css, `.cta-block{padding-block:
   clamp(...)}` в bases/cta_block/base.css — оба (0,1,0), один класс)
   независимо от порядка подключения файлов. Итог — hero и cta_block
   реально рендерились БЕЗ вертикального отступа секции: замер на 1200px
   показал .hero padding-top 0px (ожидалось ~70px, --fl-space-72) и
   .cta-block padding-block 0px (ожидалось ~102px/сторону, --fl-space-104)
   — крупнейший вклад в общее расхождение с эталоном design/etalon/
   eskiz-glavnaya.html (вердикт Владельца «всё поехало»). :not() решает
   гонку структурно: правило для .hero/.cta-block/.disclaimer вообще не
   матчится, конкурировать не с чем. disclaimer в списке фактически не
   участвовал и раньше (это <aside> без класса .section, см. assemble_page)
   — оставлен для симметрии с registry.yaml (документирует все три
   self_wrapped:true записи одним местом, I7). */
.section {
  width: 100%;
}

/* :not(:is(...)) вместо трёх цепочкой :not(.hero):not(.cta-block):not(.disclaimer)
   — НЕ косметика (найдено при живом замере этой ячейки): три :not() в цепочке
   складывают специфичность (0,1,0) КАЖДЫЙ — итог (0,4,0), что ВЫШЕ специфичности
   секционных override-правил ниже (`.section:has(> .container > .progs-list)`
   даёт (0,3,0) — два класса в аргументе :has() + .section) и даже части
   `:has()`-правил на 4 класса глубиной (0,4,0) — при равенстве спас только
   порядок объявления (пронесло у pains/faq, но progs/dirs/stats ПРОИГРАЛИ
   этому правилу и остались на generic 80px вместо --fl-space-100/110, замер
   после первой попытки правки это вскрыл). :is() внутри :not() считает
   специфичность ОДНИМ разом (максимум среди аргументов, все три — один класс),
   так что весь :not(:is(...)) даёт всего (0,1,0) — override-правила ниже
   гарантированно валиднее его при ЛЮБОМ порядке файлов. */
.section:not(:is(.hero, .cta-block, .disclaimer)) {
  padding-block: var(--tf-section-y, clamp(3rem, 2rem + 4vw, 5rem));
}

/* Резина ПО ТИПУ секции (TASK-RHYTHM-MATCH, эталон design/etalon/
   eskiz-glavnaya.html): виджеты pains/progs/quote_block/dirs/faq_accordion
   — self_wrapped:false (registry.yaml), их класс-модификатор темы сидит на
   ВНУТРЕННЕМ элементе (`.pains--marina`, `.progs-list.progs--marina` и
   т.д.), НЕ на самом <section> — значит section-level ритм нельзя задать
   через `.section.<widget>` (как для self_wrapped:true), только через
   :has() на СТРУКТУРНЫЙ класс виджета (не суффикс темы --marina — общий
   для любой темы этого же виджета, DEC-001 слой темы не должен диктовать
   структурный отступ секции). Значения — буквально из эталона (I2), не
   пересчитаны: .pains/.progs/.quote_block/.faq_accordion —
   --fl-space-110, .dirs — --fl-space-100 (themes/marina/tokens.css).
   Раньше все пятеро получали только общий --tf-section-y (максимум 80px/
   сторону на 1200px) — вдвое-втрое меньше эталонных 98-108px/сторону,
   крупная доля общего расхождения (pains -110px, progs -111px, faq -119px
   из замера этой ячейки). */
.section:has(> .container > .section-sticky-split__content > .pains),
.section:has(> .container > .progs-list),
.section:has(> .container > .quote-block),
.section:has(> .container > .section-sticky-split__content > .faq-accordion) {
  padding-block: var(--fl-space-110, clamp(4rem, 2.8239rem + 5.2273vw, 6.875rem));
}

.section:has(> .container > .dirs-row) {
  padding-block: var(--fl-space-100, clamp(4rem, 3.0795rem + 4.0909vw, 6.25rem));
}

/* stats_strip--marina-dark — единственный стиль виджета stats_strip,
   несущий собственный тёмный фон И full-bleed фото — де-факто
   self_wrapped-поведение поверх self_wrapped:false записи реестра.
   Светлый стиль .stats-strip--marina (без full-bleed, без тёмного фона)
   этим исключением НЕ затронут — ему по-прежнему нужен общий ритм
   .section, поэтому исключение указывает стилевой класс, а не структурный
   .stats-strip (осознанное отступление от паттерна выше, I7: здесь именно
   стиль, а не структура, определяет self_wrapped-подобное поведение).

   ПОЧИНКА (TASK-FIGURES-UNIFY, 2026-07-08, дефект Владельца — скриншот):
   раньше тёмный фон+padding-block (--fl-space-100) сидели НА САМОМ
   `.stats-strip--marina-dark` (breakout width:100vw), а `.section-header`
   (эйброу+заголовок) — родной СОСЕД `.stats-strip` внутри одного
   `.container`, вне зоны тёмного фона (тот покрывал только `<ul>` — ряд
   цифр). Секция при этом обнулялась (`padding-block:0`) вот этим самым
   правилом — итог: заголовок прижат к верхней кромке секции на СВЕТЛОМ
   фоне, оторван от тёмной полосы цифр ниже. Эталон (design/etalon/
   eskiz-glavnaya.html, `.figures`) держит фон+padding-block НА СЕКЦИИ
   целиком — единый тёмный блок покрывает и заголовок, и ряд. Перенесено
   сюда буквально по той же схеме: `position:relative;isolation:isolate`
   делает `.section` содержащим блоком для `.stats-strip__bg`
   (`position:absolute;inset:0` в bases/stats_strip/base.css) — фото
   теперь растягивается на ВСЮ секцию (включая заголовок) без переноса
   DOM/разметки, только сменой ближайшего позиционированного предка.
   padding-block вернулся к --fl-space-100 (тот же токен, что был на
   `<ul>`) — суммарный отступ секции НЕ задвоился (I2, проверено расчётом):
   раньше 100px верх+низ сидели ВОКРУГ ряда (`<ul>`) при заголовке с 0
   сверху; теперь те же 100px сидят ВОКРУГ (заголовок+отступ+ряд) целиком
   — общая высота секции не меняется, меняется только распределение (см.
   разбор в отчёте ячейки). Палитра (background/color самой секции,
   цвет section-header внутри) — в стилевом слое
   (styles/stats_strip/marina-dark.css), не здесь (DEC-001: цвет — забота
   style, layout отвечает только за структуру/позиционирование). */
.section:has(> .container > .stats-strip--marina-dark) {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: var(--fl-space-100, clamp(4rem, 3.0795rem + 4.0909vw, 6.25rem));
}

/* Чередование фона секций без собственной обёртки (self_wrapped: false) —
   индекс считает assemble_page только СРЕДИ таких секций (п.1 задания,
   докстрока assemble_page). Токен --bg-2/paper (TASK-P3-MOOD-PASS, находка
   Владельца арт-ворот 02 п.3 «фон везде одинаковый»): paper (#FBF8F2)
   светлее linen (#F4EEE6) базового фона страницы всего на несколько
   пунктов яркости — на глаз чередование не читалось вовсе. --bg-3/sand
   (#E9DDCF) даёт ощутимую, но всё ещё в фирменной палитре разницу
   (та же тёплая бумажная линейка тонов темы, не произвольный цвет). */
.section--alt {
  background: var(--bg-3, #e9ddcf);
}

/* Reveal-появление секций при скролле (behaviors/reveal, п.7 задания).
   Активно только под .js-reveal-ready на <html> (класс ставит синхронный
   inline-скрипт в <head> ДО отрисовки — см. assemble_page, вставляется,
   если хоть одна секция несёт [data-reveal]); без класса (JS отключён,
   упал или prefers-reduced-motion) элементы с data-reveal остаются видимы
   сразу — деградация безопасна, тот же принцип no-js, что у остальных
   поведений библиотеки. Правило — уровня layout (общее для любого блока
   с data-reveal), не стиля конкретного виджета. */
.js-reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--t-slow, 420ms) var(--ease-out), transform var(--t-slow, 420ms) var(--ease-out);
}

.js-reveal-ready [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .js-reveal-ready [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* =========================================================================
   Заголовки без сирот — text-wrap: balance/pretty (TASK-ETALON-LIB-2,
   перенос из projects/unona-site/design/etalon/eskiz-glavnaya.html строки
   262-263: `.hero__title,.pains__title,.figures__title,.progs__title,
   .dirs__title,.faq__title,.book__title{text-wrap:balance;}` и
   `.progs__sub,.hero__lede,.pain__t,.prog__t,.dir__t,.book__sub{text-wrap:
   pretty;}`). Правило общего каркаса библиотеки (не точечная правка одного
   проекта, I2) — балансируется ЛЮБОЙ заголовок секции (section_header и
   голые h1-h3 внутри основ), лид/описательный абзац не оставляет короткий
   висящий хвост. Специфичность — голые селекторы элемента/класса, любой
   стиль-модификатор виджета перебивает при необходимости без !important. */
h1, h2, h3,
.section-header__title {
  text-wrap: balance;
}

p,
.section-header__lede {
  text-wrap: pretty;
}

/* Контейнер — центрированная колонка с адаптивными боковыми полями. */
.container {
  width: 100%;
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: var(--s-6);
}

@media (min-width: 960px) {
  .container { padding-inline: var(--s-10); }
}

@media (min-width: 1200px) {
  .container { padding-inline: var(--s-12); }
}

/* Отступ шкалы между заголовком секции и телом секции (TASK-GLASS-CONTENT,
   разведка корня, баг «б»): assemble_page (block_assembler.py,
   _render_heading_html + container_inner) склеивает heading_html и
   combined_body строкой без разделителя — .section-header не несёт
   собственный margin-bottom (bases/section_header/base.css — блок
   структурно нейтрален, отступы задаёт родитель по докстроке файла), и
   зазора не было вовсе, тело секции садилось вплотную к лиду заголовка.
   Правило — здесь, в layout (группировка заголовок+тело — ответственность
   сборки секции, не самой основы section_header, которая переиспользуется
   и как самостоятельный слот без гарантии, что после неё идёт тело
   секции). Токен шкалы --tf-gap — тот же резиновый зазор, что уже
   используют колонки .section--sticky-split (DEC-001 п.14). */
.section > .container > .section-header {
  margin-bottom: var(--tf-gap, clamp(var(--s-6, 1.5rem), 1rem + 2vw, var(--s-12, 3rem)));
}

/* Секция «Цифры» (stats_strip--marina-dark) — TASK-RHYTHM-MATCH
   (2026-07-08): эталон design/etalon/eskiz-glavnaya.html `.figures__head
   {margin-bottom:56px}` — фиксированное значение крупнее общего --tf-gap
   (максимум 48px на 1200px), секция была на замере короче эталона на
   ~13% высоты (за вычетом уже исправленного двойного паддинга и паддинга
   пунктов ряда). Перенесено буквально (I2), не пересчитано на резиновую
   шкалу — сам эталон здесь тоже фиксированное число, не clamp(). */
.section:has(> .container > .stats-strip--marina-dark) > .container > .section-header {
  margin-bottom: 56px;
}

/* Центрирование интро секции «Программы» (TASK-RITM-REPAIR-A, 2026-07-08,
   скан-приёмка projects/unona-site/representations/scan-01.md, пачка A):
   эталон design/etalon/eskiz-glavnaya.html строки 317-318 —
   `.progs__head{text-align:center;max-width:58ch;margin:0 auto 64px}
   .progs__head .progs__sub{max-width:44ch;margin-inline:auto}`. Сборка
   рендерила интро левым — bases/section_header/base.css не задаёт
   align-items (флекс-столбец по умолчанию тянется от начала), а
   переключателя «эта секция центрирует свой заголовок» у block_assembler
   нет (_render_heading_html резолвит стиль только по имени файла). Модификатор
   .section-header--centered в основе уже существует, но сборщик его не
   проставляет — правка структурным override по тому же паттерну, что и
   .figures выше: адресация СТРУКТУРНЫМ селектором по .progs-list
   (self_wrapped:false, DEC-001 — палитра/манера темы --marina не должна
   диктовать структурное выравнивание секции). Figures интро эталон держит
   ЛЕВЫМ (строка 294, .figures__head без text-align/margin auto) — сборка тут
   уже совпадает, НЕ трогать; pains/dirs/faq интро в эталоне тоже левые/
   сплит — этим правилом не затронуты (селектор адресует только .progs-list). */
.section:has(> .container > .progs-list) > .container > .section-header {
  align-items: center;
  text-align: center;
  max-width: 58ch;
  margin-inline: auto;
}

.section:has(> .container > .progs-list) > .container > .section-header .section-header__lede {
  max-width: 44ch;
  margin-inline: auto;
}

/* =========================================================================
   Утилита «Аврора» — вынесена из styles/hero/marina-split.css (TASK-P3-
   MOOD-PASS, находка Владельца арт-ворот 02 п.4в: аврора-подложка нужна не
   только в герое). Два псевдоэлемента-градиента с независимыми keyframes
   (14s/16s ease-in-out infinite alternate, планка прототипа design/
   reference/prototype-breakdown.md) — приём переиспользуется классом
   .aurora на корне ЛЮБОЙ секции (isolation:isolate уже обязан завести сам
   стиль-модификатор секции, аврора не создаёт stacking context повторно).
   Цвета градиентов — переменные --aurora-a/--aurora-b с запасными
   значениями исходного героя; стиль конкретного блока переопределяет их
   под свою палитру (например тёмный cta_block — приглушённые blush/sage на
   cocoa), не копирует keyframes заново (I7 — экономия дублирования).

   Подключение без нового HTML-класса (block_assembler.py ставит РОВНО один
   класс-модификатор стиля на корень, DEC-001 п.4/5 — layout не расширяет
   схему сборщика ради утилиты): селектор утилиты перечисляет явно КАЖДЫЙ
   существующий класс-модификатор стиля, который использует аврору
   (.hero--marina-split, .cta-block--marina-dark, .hero--marina-glass —
   манера «Мягкое стекло», TASK-GLASS-CONTENT: аврора-фон остаётся под
   стеклянными карточками содержания, задание ячейки явно требует «аврора
   остаётся») — та же техника, что div с одним классом стилизуется
   несколькими правилами через запятую в селекторе. Список закрытый и
   явный (I2, не угадан по маске): расширяется этой же строкой, когда
   следующий стиль подключает аврору. Сама утилита НЕ содержит специфики
   палитры конкретного блока (только структуру position/isolation/
   keyframes) — граница слоёв DEC-001 п.1 соблюдена, --aurora-a/--aurora-b
   переопределяет стиль каждого блока в своём файле. */
.hero--marina-split,
.hero--marina-glass,
.hero--marina-editorial,
.cta-block--marina-dark {
  position: relative;
  isolation: isolate;
}

.hero--marina-split::before,
.hero--marina-split::after,
.hero--marina-glass::before,
.hero--marina-glass::after,
.hero--marina-editorial::before,
.hero--marina-editorial::after,
.cta-block--marina-dark::before,
.cta-block--marina-dark::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.hero--marina-split::before,
.hero--marina-glass::before,
.hero--marina-editorial::before,
.cta-block--marina-dark::before {
  background: var(--aurora-a, radial-gradient(55% 50% at 14% 10%, rgba(210, 164, 146, 0.20), transparent 70%));
  animation: aurora-a 14s var(--ease-in-out, ease-in-out) infinite alternate;
}

.hero--marina-split::after,
.hero--marina-glass::after,
.hero--marina-editorial::after,
.cta-block--marina-dark::after {
  background: var(--aurora-b, radial-gradient(45% 42% at 90% 88%, rgba(168, 181, 154, 0.14), transparent 70%));
  animation: aurora-b 16s var(--ease-in-out, ease-in-out) infinite alternate 2s;
}

@keyframes aurora-a {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.85; }
  to   { transform: translate3d(2%, 3%, 0) scale(1.08); opacity: 1; }
}

@keyframes aurora-b {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.7; }
  to   { transform: translate3d(-3%, -2%, 0) scale(1.1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .hero--marina-split::before,
  .hero--marina-split::after,
  .hero--marina-glass::before,
  .hero--marina-glass::after,
  .hero--marina-editorial::before,
  .hero--marina-editorial::after,
  .cta-block--marina-dark::before,
  .cta-block--marina-dark::after {
    animation: none;
  }
}

/* =========================================================================
   Структурная опция «Липкая колонка» — .section--sticky-split (TASK-P3-
   MOOD-PASS, находка Владельца арт-ворот 02 п.4б «нет липких блоков при
   прокрутке»). Планка — прототип-эталон design/reference/prototype-
   breakdown.md, раздел «Витамины и добавки»: 2 колонки, слева sticky-панель
   с заголовком/текстом/CTA, справа прокручиваемый список карточек.

   Разметка ставится сборщиком (block_assembler.py, SectionSchema.sticky_split)
   двумя обёртками внутри .container: .section-sticky-split__header (несёт
   section_header) и .section-sticky-split__content (несёт карточки).
   Десктоп — CSS Grid 2 колонки, левая липнет к верху вьюпорта на время
   прокрутки правой (position: sticky по родителю .container, не по
   документу — колонка не съезжает за пределы своей секции). Мобайл —
   обычный поток одной колонкой (структурная секция ЯВНО отключает sticky
   ниже брейкпоинта md — планка прототипа предполагает 2 колонки только на
   широких экранах, doc 11 контрактная точка 960px). */
.section--sticky-split .container {
  display: block;
}

/* Стек (одна колонка, ниже 960 у faq и ниже 700 у pains): заголовок-панель
   стоит НАД контентом — нужен вертикальный зазор, иначе кнопка aside
   склеивается с первым пунктом (планшетная склейка FAQ, находка Владельца).
   Общий отступ section-header (стр. выше) сюда не достаёт — заголовок вложен
   в .section-sticky-split__header. Тот же токен-зазор. Сбрасывается в 0, как
   только колонки встают рядом (grid ниже и pains 700-959). */
.section--sticky-split .section-sticky-split__header {
  margin-bottom: var(--tf-gap, clamp(var(--s-6, 1.5rem), 1rem + 2vw, var(--s-12, 3rem)));
}

@media (min-width: 960px) {
  .section--sticky-split .container {
    display: grid;
    grid-template-columns: minmax(16rem, 22rem) 1fr;
    gap: var(--tf-gap, var(--s-12, 3rem));
    align-items: start;
  }

  .section--sticky-split .section-sticky-split__header {
    position: sticky;
    top: var(--s-10, 2.5rem);
    margin-bottom: 0;
  }
}

/* Планшет 700-959 — pains держит 2 колонки БЕЗ sticky, не схлопывается в
   одну раньше эталона (TASK-RITM-REPAIR-B2, 2026-07-08, scan-01.md пачка
   B.2, K4.2 «схлопнуто рано»). Эталон design/etalon/eskiz-glavnaya.html:
   строка 531 `.pains__grid{grid-template-columns:minmax(0,0.85fr)
   minmax(0,1.15fr)}` внутри `@media(max-width:960px)`, строка 532
   `.pains__aside{position:static}` — та же секция линеаризуется в 1 колонку
   только на строке 590 `@media(max-width:700px){.pains__grid{grid-template-
   columns:1fr}}`. Общее правило `.section--sticky-split .container` выше
   уходит в grid только от 960px — pains ниже этого порога был block/1-кол
   уже на 768, эталон там держит 2 кол. Правка АДРЕСНАЯ (структурный
   селектор по `.pains`, не общий `.section--sticky-split`) — faq тоже
   sticky-split, но эталон схлопывает faq на том же 960 (строка 560,
   `.faq__grid{grid-template-columns:1fr}`), сборка там уже совпадает,
   трогать нельзя (задание ячейки, явный запрет). Диапазон 700-959 не
   пересекается с общим правилом ≥960 (mutually exclusive media, гонки
   специфичности нет) и не пересекается с дефолтным display:block ниже 700
   (наш блок начинается от 700, значит <700 остаётся 1-колоночным потоком
   без изменений — линеаризация эталона на этом пороге не нарушена). */
@media (min-width: 700px) and (max-width: 959px) {
  .section:has(> .container > .section-sticky-split__content > .pains) > .container {
    display: grid;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: var(--tf-gap, clamp(1.5rem, 1rem + 2vw, 2.25rem));
    align-items: start;
  }

  .section:has(> .container > .section-sticky-split__content > .pains) .section-sticky-split__header {
    position: static;
    /* pains тут в 2 колонки — колонки рядом, вертикальный зазор стека не нужен */
    margin-bottom: 0;
  }
}

/* =========================================================================
   bases/mobile_nav/base.css — структурный слой основы «Мобильное меню»
   Специфичность: только базовый класс .mobile-nav (DEC-001 п.5). Раскладка
   через нативный <details>/<summary> (без JS — I7, решение зафиксировано
   в base.html и acceptance.md). Резина: паддинги/размеры — clamp() между
   var()-границами; брейкпоинт 960 — только смена структуры (эта основа
   видна НИЖЕ 960, скрыта на широких, где активен site_header__nav инлайн).

   Композиция с site_header (TASK-BURGER-INLINE, сверка сборки с эталоном
   design/etalon/eskiz-glavnaya.html): сборщик (block_assembler.py,
   _NESTED_FRAME_BLOCKS) теперь вставляет ЭТУ разметку целиком ВНУТРЬ
   <header class="site-header">, последним элементом .site-header__container
   (после .site-header__actions) — не отдельным полноширинным блоком ПОСЛЕ
   </header>, как было раньше. DOM (details/summary/panel) и behaviors/
   burger_menu/behavior.js НЕ МЕНЯЮТСЯ — меняется только позиционирование:
   - .mobile-nav / .mobile-nav__disclosure сжимаются до содержимого триггера
     (flex-item строки шапки, не блок на 100% ширины) — компактная кнопка
     ≥44px в конце строки, как .hd__burger эталона.
   - .mobile-nav__panel вырывается из потока через position:absolute,
     привязываясь к .site-header (position: sticky — устанавливает
     containing block для абсолютно позиционированных потомков даже без
     явного position:relative, спецификация CSS Position) — top:100%/left:0/
     right:0 относительно ВСЕЙ шапки даёт панели полную ширину строки .hd,
     не только ширину компактного триггера, при этом не раздвигая высоту
     строки шапки, когда открыта (эталон: .hd__menu тем же приёмом —
     оверлей поверх контента страницы, не сдвиг вниз).
   Основа остаётся собираемой САМОСТОЯТЕЛЬНО (demo/index.html,
   assemble_section) — вне site_header контейнер .mobile-nav просто не
   получает подходящий positioned-предок; в этом случае панель позиционир-
   уется относительно ближайшего positioned-предка страницы (обычно
   viewport/<html>, если такого предка нет вовсе) — визуально то же самое
   поведение (полноширинный оверлей), демо не ломается, просто без строки
   шапки над ним (I7 — зафиксировано, не скрыто).
   ========================================================================= */

.mobile-nav {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
}

.mobile-nav__disclosure {
  width: auto;
}

/* Убираем нативный маркер-треугольник summary (Chromium/Firefox), рисуем
   свою иконку через ::before на trigger-icon. */
/* K1.4/K1.5 (DEC-002): триггер — единственная мишень открытия/закрытия
   <details>, min-height 44px даёт полноценную тач-площадь на любой
   ширине (раньше зависело только от clamp-padding вокруг кегля). */
.mobile-nav__trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2, 0.5rem);
  min-width: 44px;
  min-height: 44px;
  list-style: none;
  cursor: pointer;
  padding: clamp(var(--s-2, 0.5rem), 1.5vw, var(--s-3, 0.75rem));
  user-select: none;
}

.mobile-nav__trigger::-webkit-details-marker {
  display: none;
}

.mobile-nav__trigger-icon {
  position: relative;
  width: clamp(1.25rem, 3vw, 1.5rem);
  height: 2px;
  background: currentColor;
  flex-shrink: 0;
  transition: transform var(--t-fast, 140ms) var(--ease-out, ease);
}

.mobile-nav__trigger-icon::before,
.mobile-nav__trigger-icon::after {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  background: currentColor;
  transition: transform var(--t-fast, 140ms) var(--ease-out, ease), top var(--t-fast, 140ms) var(--ease-out, ease);
}

.mobile-nav__trigger-icon::before { top: -6px; }
.mobile-nav__trigger-icon::after { top: 6px; }

/* K1.5 (DEC-002): в открытом состоянии бургер визуально складывается в
   крестик (та же мишень, теперь читается как «закрыть»), а подпись
   меняется с «Меню» на «Закрыть» — details[open] нативный без JS. */
.mobile-nav__disclosure[open] .mobile-nav__trigger-icon {
  background: transparent;
}

.mobile-nav__disclosure[open] .mobile-nav__trigger-icon::before {
  top: 0;
  transform: rotate(45deg);
}

.mobile-nav__disclosure[open] .mobile-nav__trigger-icon::after {
  top: 0;
  transform: rotate(-45deg);
}

/* Визуально скрытая подпись (TASK-BURGER-INLINE, находка сборки: видимый
   текст "Меню"/"Закрыть" рядом с иконкой не помещался в компактный слот
   строки шапки — trigger шириной ~89px переносился на отдельную строку
   flex-wrap контейнера site-header__container, воспроизводя старый дефект
   "полноширинный блок под шапкой" другим путём. Решение: подпись остаётся
   в DOM для скринридеров (visually-hidden clip-приём, НЕ display:none —
   текст не выпадает из дерева доступности), видимый аффорданс закрытия —
   анимация иконки бургер→крестик (уже реализована, K1.5) + aria-expanded
   (объявляет collapsed/expanded голосом читалки). Статичный aria-label
   "Меню" на summary (base.html) даёт название действия независимо от
   состояния — тот же приём, что и эталон design/etalon/eskiz-glavnaya.html
   .hd__burger[aria-label="Меню"], компактная квадратная кнопка ~44px без
   видимого текста. Замена смены display:none/inline между двумя подписями
   (старое K1.5-решение) — обе подписи теперь просто visually-hidden,
   swap текста больше не нужен визуально (I7 — решение по стоимости,
   зафиксировано в acceptance.md). */
.mobile-nav__trigger-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .mobile-nav__trigger-icon,
  .mobile-nav__trigger-icon::before,
  .mobile-nav__trigger-icon::after {
    transition: none;
  }
}

/* Плавное раскрытие (TASK-ETALON-LIB-1, перенос эскиза design/etalon/
   eskiz-glavnaya.html .hd__menu/.hd__menu--open, коммит unona-site 5ac52b0/
   a11f0b0) — max-height/opacity/translate 420ms поверх native <details>.
   Приём: UA-стилевое правило `details:not([open]) > *:not(summary){display:
   none}` — это ОБЫЧНОЕ правило браузерного стиля, author CSS правомочен его
   перебить (не хардкод движка) — `display:block` ниже делает панель ВСЕГДА
   присутствующей в потоке, видимость управляется max-height/opacity, не
   display. Деградация без JS сохранена: [open] без inline-переопределения
   даёт max-height:none (контент открывается мгновенно, без анимации — но
   ОТКРЫВАЕТСЯ, что и требует I11/DEC-001 «недостижимого контента без
   взаимодействия» доктрина дока 31). С JS (behaviors/burger_menu/behavior.js)
   — inline style.maxHeight = scrollHeight + 'px' (тот же приём, что
   behaviors/accordion/behavior.js) даёт настоящую анимацию по реальной
   высоте; opacity задержана на 80ms (var(--t-delay-menu)) — эталон
   .hd__menu--open transition. */
.mobile-nav__panel {
  /* position:absolute (TASK-BURGER-INLINE) — панель вырывается из потока
     компактного триггера-flex-item и растягивается на полную ширину
     ближайшего positioned-предка (.site-header, position: sticky, см.
     докстрока файла) — не сдвигает высоту строки шапки при открытии,
     полная ширина независимо от узкой ширины самого триггера. */
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  display: block;
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transform: translateY(-8px);
  padding: clamp(var(--s-3, 0.75rem), 2vw, var(--s-5, 1.25rem));
  padding-top: 0;
  transition: max-height var(--t-slow, 420ms) var(--ease-out, ease),
              opacity var(--t-normal, 240ms) var(--ease-out, ease),
              transform var(--t-slow, 420ms) var(--ease-out, ease);
}

.mobile-nav__disclosure[open] .mobile-nav__panel {
  /* NO-JS фолбэк: показывает контент целиком без анимации (JS переопределяет
     max-height инлайном на реальный scrollHeight — выше по специфичности). */
  max-height: none;
  opacity: 1;
  transform: translateY(0);
  transition: max-height var(--t-slow, 420ms) var(--ease-out, ease),
              opacity var(--t-normal, 240ms) var(--ease-out, ease) var(--t-delay-menu, 80ms),
              transform var(--t-slow, 420ms) var(--ease-out, ease);
}

@media (prefers-reduced-motion: reduce) {
  .mobile-nav__panel,
  .mobile-nav__disclosure[open] .mobile-nav__panel {
    transition: none;
    transform: none;
  }
}

.mobile-nav__nav-list {
  display: flex;
  flex-direction: column;
  gap: clamp(var(--s-2, 0.5rem), 2vw, var(--s-4, 1rem));
  list-style: none;
  margin: 0;
  padding: 0;
}

/* K1.4 (DEC-002): пункт навигации — кликабельная площадь ≥44px, не голая
   строка текста. padding-block --s-3 (12px) сверху/снизу вокруг типового
   кегля 15-16px даёт итог ≥44px; display:flex+align-items вместо block,
   чтобы вся площадь строки (не только текст) была кликабельна. */
.mobile-nav__nav-link {
  display: flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
  color: inherit;
  padding-block: var(--s-3, 0.75rem);
}

.mobile-nav__actions {
  display: flex;
  flex-direction: column;
  gap: clamp(var(--s-2, 0.5rem), 2vw, var(--s-3, 0.75rem));
  margin-top: clamp(var(--s-3, 0.75rem), 2vw, var(--s-5, 1.25rem));
  padding-top: clamp(var(--s-3, 0.75rem), 2vw, var(--s-5, 1.25rem));
  border-top: 1px solid var(--border-1, #e5dacb);
}

.mobile-nav__phone,
.mobile-nav__cta {
  text-decoration: none;
}

.mobile-nav__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: clamp(var(--s-2, 0.5rem), 1.5vw, var(--s-3, 0.75rem)) clamp(var(--s-4, 1rem), 3vw, var(--s-5, 1.25rem));
  border-radius: var(--r-pill, 999px);
  background: var(--fg-brand, #9C6957);
  color: var(--fg-on-dark, #fff);
}

/* Структура: эта основа видна ниже контрактной точки 960 (spec/docs/11) —
   выше неё main_nav инлайн site_header берёт на себя навигацию. Смена
   структуры, не размеров (Владелец, дополнение к заданию ячейки). */
@media (min-width: 960px) {
  .mobile-nav {
    display: none;
  }
}

/* =========================================================================
   styles/mobile_nav/marina-glass.css — манера «Мягкое стекло»
   Один класс-модификатор .mobile-nav--marina-glass (DEC-001 п.4/5), одна
   ступень специфичности поверх .mobile-nav, без !important.

   Панель раскрывается под sticky-шапкой (details/summary, base.html) —
   стекло здесь визуально примыкает к .site-header--marina-glass, поэтому
   параметры blur/фон совпадают с шапкой (единая "стеклянная плита").
   Источники: K17 (blur, кромка, fallback), K16 (переход панели — на
   ступени "попап", не мелкого элемента — 240мс, а не 140мс шапки),
   research/best-practices.md.
   ========================================================================= */

.mobile-nav--marina-glass .mobile-nav__trigger {
  color: var(--fg-1);
}

.mobile-nav--marina-glass .mobile-nav__panel {
  background: var(--bg-2);
  border-top: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .mobile-nav--marina-glass .mobile-nav__panel {
    background: rgba(251, 248, 242, 0.72);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

.mobile-nav--marina-glass .mobile-nav__panel {
  transition: background-color var(--t-normal, 240ms) var(--ease-out);
}

.mobile-nav--marina-glass .mobile-nav__nav-link {
  font-family: var(--font-body);
  font-size: clamp(var(--t-body-s, 0.9375rem), 1vw + 0.5rem, var(--t-body, 1rem));
  color: var(--fg-1);
  transition: color var(--t-fast, 140ms) var(--ease-out);
}

.mobile-nav--marina-glass .mobile-nav__nav-link--active {
  color: var(--fg-brand);
}

.mobile-nav--marina-glass .mobile-nav__phone {
  font-family: var(--font-body);
  font-size: var(--t-body-s);
  color: var(--fg-1);
}

.mobile-nav--marina-glass .mobile-nav__cta {
  font-family: var(--font-body);
  font-weight: var(--w-medium);
  font-size: var(--t-body-s);
  border: none;
  background: rgba(255, 255, 255, 0.35);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
  color: var(--fg-1);
  transition: transform var(--t-normal, 240ms) var(--ease-out),
              background-color var(--t-normal, 240ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .mobile-nav--marina-glass .mobile-nav__cta {
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }
}

.mobile-nav--marina-glass .mobile-nav__cta:hover {
  transform: translateY(-1px);
  background: var(--fg-brand);
  color: var(--fg-on-dark);
}

.mobile-nav--marina-glass .mobile-nav__cta:focus-visible,
.mobile-nav--marina-glass .mobile-nav__trigger:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 4px var(--fg-brand);
}

@media (prefers-reduced-motion: reduce) {
  .mobile-nav--marina-glass .mobile-nav__panel,
  .mobile-nav--marina-glass .mobile-nav__nav-link,
  .mobile-nav--marina-glass .mobile-nav__cta {
    transition: none;
    transform: none;
  }
}

/* =========================================================================
   bases/site_header/base.css — структурный слой основы «Шапка сайта»
   Специфичность: только базовый класс .site-header (DEC-001 п.5). Sticky —
   структурное поведение CSS position:sticky (не зависит от JS манифеста
   sticky_header — манифест декоративен и не несёт кода позиционирования,
   doc 31: "не требуется" ARIA, "не перехватывает клавиши").
   Всё регулируемое — через var() (DEC-001 п.12).
   ========================================================================= */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header, 40);
  width: 100%;
  background: var(--bg-1, #fff);
  border-bottom: 1px solid var(--border-1, transparent);
}

.site-header__container {
  display: flex;
  align-items: center;
  /* nowrap (было wrap): на узких мобилках (≤360px) бренд+actions+бургер
     переносились на 2-3 строки (найдено на 280px — высота 106px вместо
     одной строки ~60px, Владелец: «шапка рассыпалась в столбец»). Бренд
     уже min-width:0 + ellipsis (.site-header__brand-group/.site-header__
     brand ниже) — при нехватке ширины усечётся текстом, а не перенесёт
     блок. Эталон design/etalon/eskiz-glavnaya.html .hd__in{display:flex}
     тоже без wrap — одна строка на любой ширине. */
  flex-wrap: nowrap;
  gap: clamp(var(--s-3, 0.75rem), 2vw, var(--s-6, 1.5rem));
  min-height: var(--header-height, clamp(3.5rem, 5vw + 2rem, 4.5rem));
  padding-block: clamp(var(--s-2, 0.5rem), 1vw, var(--s-3, 0.75rem));
}

.site-header__brand-group {
  display: flex;
  align-items: center;
  gap: var(--s-3, 0.75rem);
  margin-right: auto;
  text-decoration: none;
  min-width: 0;
}

.site-header__emblem {
  width: clamp(var(--s-8, 2rem), 4vw, var(--s-10, 2.5rem));
  height: clamp(var(--s-8, 2rem), 4vw, var(--s-10, 2.5rem));
  border-radius: var(--r-pill, 999px);
  object-fit: cover;
  flex-shrink: 0;
}

.site-header__brand {
  margin: 0;
  font-weight: var(--w-medium, 500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.site-header__nav {
  display: none;
}

.site-header__nav-list {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(var(--s-4, 1rem), 2.5vw, var(--s-6, 1.5rem));
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-header__nav-link {
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
}

.site-header__actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(var(--s-3, 0.75rem), 2vw, var(--s-4, 1rem));
}

.site-header__phone {
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
}

.site-header__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: clamp(var(--s-2, 0.5rem), 1.2vw, var(--s-2, 0.5rem)) clamp(var(--s-4, 1rem), 3vw, var(--s-5, 1.25rem));
  border-radius: var(--r-pill, 999px);
  background: var(--fg-brand, #9C6957);
  color: var(--fg-on-dark, #fff);
  text-decoration: none;
  white-space: nowrap;
}

/* Раскладка (структура) переключается на контрактной точке 960
   (spec/docs/11): ниже неё main_nav инлайн скрыт (мобильная навигация —
   отдельная основа mobile_nav, монтируется каркасом рядом, DEC-001 п.10).
   Это смена СТРУКТУРЫ (список ссылок ↔ бургер), не смена размеров —
   размеры внутри каждой структуры уже резиновые через clamp() выше. */
@media (min-width: 960px) {
  .site-header__nav {
    display: block;
  }
}

/* .site-header__actions (телефон + CTA «Записаться») скрывается ниже 960 —
   та же структурная точка, на которой появляется .mobile-nav (бургер,
   bases/mobile_nav/base.css @media(min-width:960px){display:none}, т.е.
   виден <960). Ниже 960 строка шапки несёт только бренд + бургер (находка
   Владельца на 280/320/360: actions+бургер вместе не помещались в одну
   строку без переноса). CTA не теряется — дублируется в панели бургера
   (.mobile-nav__actions, bases/mobile_nav/base.html/base.css, TASK-
   BURGER-INLINE) и в нижнем баре bottom_action_bar (карта секций
   unona-site). Телефон в actions скрыт отдельно ещё раньше, на 700
   (правило .site-header__phone ниже) — это правило избыточно с 700 до
   959 для phone, но необходимо для cta. */
@media (max-width: 959px) {
  .site-header__actions {
    display: none;
  }
}

/* Телефон в шапке скрывается ниже 700 (TASK-ETALON-LIB-1, эталон design/
   etalon/eskiz-glavnaya.html .hd__phone{display:none} на @media(max-width:
   700px)) — на узких экранах связь несёт CTA-кнопка + выдвижное меню
   (mobile_nav), телефонная строка перестаёт помещаться рядом с брендом без
   переноса. Структурная точка 700 — та же, что у остальных виджетов этой
   ячейки (bases/hero/base.css, докстрока), не 960: CTA/бренд продолжают
   умещаться с телефоном до 700 (резина container уже сжимает отступы). */
@media (max-width: 699px) {
  .site-header__phone {
    display: none;
  }
}

/* =========================================================================
   styles/site_header/marina-glass.css — манера «Мягкое стекло»
   Один класс-модификатор .site-header--marina-glass (DEC-001 п.4/5), одна
   ступень специфичности поверх .site-header, без !important.

   Раскатка манеры с эталона styles/service_card/marina-glass.css на
   каркас (TASK-GLASS-FRAME). Шапка — родная стихия приёма K17: sticky-
   подложка с blur ощущается «правильно» именно здесь (в отличие от
   marina.css, где blur включён безусловно, здесь кромка K17 добавлена
   явным приёмом «тень-как-граница», K12 — box-shadow вместо border-bottom).

   Источники приёмов: K17 (blur 12–20px, фон ≥50% непрозрачности, тонкая
   светлая кромка, обязательный fallback), K12 (тень-как-граница вместо
   border), K16 (иерархия длительностей — шапка меняется быстро, hover
   ссылок/CTA на нижней ступени ~150-240мс, не на «тяжёлой» ступени
   стекла) — research/best-practices.md.
   ========================================================================= */

.site-header--marina-glass {
  /* Fallback ПЕРВЫМ — непрозрачный bg-2, читаемый без backdrop-filter. */
  background: var(--bg-2);
  border-bottom: none;
  /* K12: тень-как-граница вместо border-bottom, чтобы кромка не участвовала
     в box-model и не спорила с фоном стекла ниже. */
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.15), var(--shadow-1);
  transition: box-shadow var(--t-slow, 420ms) var(--ease-out),
              background-color var(--t-slow, 420ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .site-header--marina-glass {
    background: rgba(251, 248, 242, 0.62);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

/* Кромка при прокрутке — CSS-only приём: якорь :target/sticky не различает
   "проскроллено" без JS (doc 31 — sticky_header не даёт JS-детекции
   скролла), поэтому кромка стекла активна постоянно, как и в marina.css,
   а не переключается по порогу. Состояние подано визуально через плотность
   тени/кромки, а не через появление/исчезание. */
.site-header--marina-glass .site-header__brand {
  font-family: var(--font-display);
  font-size: clamp(var(--t-body, 1rem), 1.6vw + 0.5rem, var(--t-h3, 1.375rem));
  color: var(--fg-1);
}

.site-header--marina-glass .site-header__nav-link {
  font-family: var(--font-body);
  font-size: clamp(var(--t-caption, 0.8125rem), 0.9vw + 0.4rem, var(--t-body-s, 0.9375rem));
  color: var(--fg-2);
  transition: color var(--t-fast, 140ms) var(--ease-out);
}

.site-header--marina-glass .site-header__nav-link:hover,
.site-header--marina-glass .site-header__nav-link--active {
  color: var(--fg-brand);
}

.site-header--marina-glass .site-header__phone {
  font-family: var(--font-body);
  font-size: clamp(var(--t-caption, 0.8125rem), 0.9vw + 0.4rem, var(--t-body-s, 0.9375rem));
  color: var(--fg-1);
}

.site-header--marina-glass .site-header__cta {
  font-family: var(--font-body);
  font-weight: var(--w-medium);
  font-size: clamp(var(--t-caption, 0.8125rem), 0.9vw + 0.4rem, var(--t-body-s, 0.9375rem));
  border: none;
  /* K17: сама CTA-кнопка тоже несёт лёгкое стекло (кромка+подложка), а не
     сплошную заливку — продолжает манеру внутрь интерактивного элемента. */
  background: rgba(255, 255, 255, 0.35);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
  color: var(--fg-1);
  transition: transform var(--t-normal, 240ms) var(--ease-out),
              box-shadow var(--t-normal, 240ms) var(--ease-out),
              background-color var(--t-normal, 240ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .site-header--marina-glass .site-header__cta {
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }
}

.site-header--marina-glass .site-header__cta:hover {
  transform: translateY(-1px);
  background: var(--fg-brand);
  color: var(--fg-on-dark);
  box-shadow: var(--shadow-2);
}

/* K13: двойное фокус-кольцо — тот же инвариант доступности, что у прочих
   манер, стекло не освобождает от требования. */
.site-header--marina-glass .site-header__cta:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 4px var(--fg-brand);
}

@media (prefers-reduced-motion: reduce) {
  .site-header--marina-glass,
  .site-header--marina-glass .site-header__nav-link,
  .site-header--marina-glass .site-header__cta {
    transition: none;
    transform: none;
  }
}

/* =========================================================================
   bases/hero/base.css — структурный слой основы «Герой»
   Специфичность: только базовый класс .hero (DEC-001 п.5). Раскладка split
   по умолчанию (две колонки на широких экранах, одна колонка на узких).
   Всё регулируемое — через var() (DEC-001 п.12); значения без темы падают
   на нейтральный fallback, чтобы основа была демонстрируема без темы.
   Адаптив на контрактных точках 360/960/1200 (spec/docs/11).
   ========================================================================= */

.hero {
  padding-block: var(--hero-section-padding-y, var(--s-16, 4rem));
  background: var(--bg-1, #fff);
  color: var(--fg-1, #111);
  overflow: hidden;
}

.hero__container {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--hero-gap, var(--s-10, 2.5rem));
  align-items: center;
}

.hero__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-4, 1rem);
}

.hero__eyebrow-row {
  display: flex;
  align-items: center;
  gap: var(--s-4, 1rem);
}

.hero__eyebrow {
  margin: 0;
}

.hero__title {
  margin: 0;
}

.hero__lede {
  margin: 0;
  max-width: 56ch;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3, 0.75rem);
  margin-top: var(--s-2, 0.5rem);
}

.hero__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: var(--s-3, 0.75rem) var(--s-6, 1.5rem);
  border-radius: var(--r-pill, 999px);
  font-weight: var(--w-medium, 500);
  text-decoration: none;
  transition: transform var(--t-fast, 140ms) var(--ease-out, ease),
              box-shadow var(--t-fast, 140ms) var(--ease-out, ease);
}

.hero__cta-label {
  position: relative;
  z-index: 1;
}

.hero__cta--primary {
  background: var(--fg-brand, #9C6957);
  color: var(--fg-on-dark, #fff);
  border: 1px solid transparent;
}

.hero__cta--secondary {
  background: transparent;
  color: var(--fg-1, #111);
  border: 1px solid var(--border-strong, currentColor);
}

.hero__cta:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-2, 0 4px 14px rgba(0, 0, 0, 0.08));
}

.hero__facts {
  list-style: none;
  margin: var(--s-4, 1rem) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
}

.hero__fact {
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
}

.hero__fact::before {
  content: "— ";
  color: var(--fg-brand, currentColor);
}

/* Метрики — планка прототипа (design/reference/prototype-breakdown.md,
   раздел «Карта секций»): строка «значение крупно + подпись», до 4 шт.
   Структура нейтральна — типографику даёт слой style. */
.hero__metrics {
  list-style: none;
  margin: var(--s-6, 1.5rem) 0 0;
  padding-top: var(--s-4, 1rem);
  border-top: 1px solid var(--border-1, #e5dacb);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-6, 1.5rem);
}

.hero__metric {
  display: flex;
  flex-direction: column;
  gap: var(--s-1, 0.25rem);
}

.hero__metric-value {
  font-family: var(--font-display, serif);
  /* Резина DEC-001 п.14, FLG-003: --tf-h2 (themes/marina/tokens.css) —
     clamp() поверх --t-h3/--t-h2; fallback-clamp сохранён для сборки без
     темы, где --tf-h2 не объявлен. */
  font-size: var(--tf-h2, clamp(var(--t-h3, 1.375rem), 0.9rem + 1.6vw, var(--t-h2, 1.75rem)));
  line-height: var(--lh-tight, 1.05);
  color: var(--fg-1, #111);
}

.hero__metric-label {
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-2, #555);
}

/* variant "course" (эталон hero__price--course): значение — слово, не число
   («курсом»), типографику (курсив/цвет) задаёт слой style; структурно
   нейтрально, чтобы основа не диктовала декоративный вид варианта. */
.hero__metric--course {
  min-width: 0;
}

/* Медиа-композиция: контейнер-обёртка держит главное фото + опциональную
   малую деталь, перекрывающую угол (планка прототипа). detail позиционируется
   относительно media, поэтому hero__media — positioning context. */
.hero__media {
  width: 100%;
  position: relative;
  /* Починка бага «низ героя обрезан» (TASK-GLASS-CONTENT, разведка корня):
     .hero несёт overflow:hidden (ради авроры .hero--marina-split::before/
     ::after, layout/base.css, isolation:isolate из того же файла) — тот же
     контекст обрезки задевал .hero__media-detail, которая выступает за
     .hero__media на bottom:-8% (правило .hero__media-detail ниже).
     Нижний паддинг резервирует под секцией место ровно на выступ детали —
     деталь дорисовывается целиком, аврора остаётся обрезанной по секции
     как и было (паддинг — не заплатка стиля, причина структурная,
     чинится в структурном слое, DEC-001 п.1). */
  padding-bottom: var(--hero-detail-overhang, var(--s-8, 2rem));
}

/* hero__photo-wrap (TASK-ETALON-LIB-1, перенос починки эскиза — коммит
   unona-site 95583dc «фото-композиция героя»): единственный positioning
   context для badge/detail/cameo — эти три элемента сидят НА ФОТО, не в
   произвольном месте медиа-колонки (hero__media может однажды нести что-то
   ещё, кроме фото). Фото само получает управляемый aspect-ratio и потолок
   высоты (max-height) через переменные — реальное фото на узких/средних
   экранах не растягивается «во весь экран» (требование Владельца, DEC-001
   block-library п.14). */
.hero__photo-wrap {
  position: relative;
  width: 100%;
}

.hero__media-main {
  aspect-ratio: var(--hero-photo-ratio, 4 / 3.4);
  max-height: var(--hero-photo-max-h, none);
}

.hero__media-main .hero__image,
.hero__media-main .hero__placeholder {
  height: 100%;
  aspect-ratio: auto;
}

/* Камея-эмблема студии, плавает поверх фото (эталон hero__cameo) — тот же
   приём позиционирования, что и малая деталь, зеркальный угол (низ-лево). */
.hero__media-cameo {
  position: absolute;
  width: var(--hero-cameo-size, 4.625rem);
  height: var(--hero-cameo-size, 4.625rem);
  left: var(--s-4, 1rem);
  bottom: var(--s-4, 1rem);
  border-radius: var(--r-pill, 999px);
  overflow: hidden;
  z-index: 2;
}

.hero__media-cameo .hero__image,
.hero__media-cameo .hero__placeholder {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  border-radius: var(--r-pill, 999px);
}

/* Узкие экраны (одна колонка): медиа не полотно во всю ширину, а компактная
   композиция ограниченного размера по центру (находка Владельца, FLG-003).
   Порог сдвинут с 959 на 699 (TASK-ETALON-LIB-1) — см. докстрока у
   .hero__container/@media ниже: структурная точка переключения колонок
   героя перенесена на 700 по эталону, эта точка следует за ней. */
@media (max-width: 699px) {
  .hero__media {
    max-width: min(420px, 82%);
    margin-inline: auto;
  }
}

.hero__media-main {
  position: relative;
  width: 100%;
  border-radius: var(--hero-media-radius, var(--r-xl, 1.375rem));
}

.hero__image {
  width: 100%;
  height: auto;
  border-radius: var(--hero-media-radius, var(--r-xl, 1.375rem));
  object-fit: cover;
  display: block;
}

.hero__placeholder {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: var(--hero-media-radius, var(--r-xl, 1.375rem));
  background: linear-gradient(135deg, var(--blush-200, #ddd), var(--blush-400, #999));
}

.hero__placeholder--sage {
  background: linear-gradient(135deg, var(--sage-100, #ddd), var(--sage-500, #7B8A6E));
}

.hero__placeholder--gilt {
  background: linear-gradient(135deg, var(--gilt-300, #ddd), var(--gilt-500, #B8956A));
}

/* Grain-оверлей главного фото — SVG-шум инлайном (data-URI), без внешних
   файлов (задание ячейки: без внешних зависимостей). Нейтральная основа —
   слабая, ровная зернистость; интенсивность/blend-mode регулирует стиль. */
.hero__media-grain {
  position: absolute;
  inset: 0;
  border-radius: var(--hero-media-radius, var(--r-xl, 1.375rem));
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  opacity: var(--hero-grain-opacity, 0.05);
  mix-blend-mode: var(--hero-grain-blend, overlay);
}

/* Малое фото-деталь, перекрывающее угол главного (планка прототипа:
   ~200×240 против ~620×620 главного — пропорция задана шириной 34%). */
.hero__media-detail {
  position: absolute;
  width: 34%;
  aspect-ratio: 5 / 6;
  right: var(--s-neg-detail, -5%);
  bottom: var(--s-neg-detail, -8%);
  border-radius: var(--hero-media-detail-radius, var(--r-lg, 0.875rem));
  overflow: hidden;
}

.hero__media-detail .hero__image,
.hero__media-detail .hero__placeholder {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  border-radius: var(--hero-media-detail-radius, var(--r-lg, 0.875rem));
}

/* Тег-бейдж поверх медиа-композиции (обоснование позиционирования). */
.hero__badge {
  position: absolute;
  top: var(--s-4, 1rem);
  left: var(--s-4, 1rem);
  display: inline-flex;
  align-items: center;
  padding: var(--s-2, 0.5rem) var(--s-4, 1rem);
  border-radius: var(--r-pill, 999px);
  font-size: var(--t-eyebrow, 0.75rem);
  letter-spacing: var(--ls-eyebrow, 0.18em);
  text-transform: uppercase;
}

@media (max-width: 480px) {
  .hero__media-detail {
    width: 40%;
    right: var(--s-2, 0.5rem);
    bottom: var(--s-neg-detail-mobile, -6%);
  }
}

/* Раскладка split: две колонки от точки 700, не 960 (TASK-ETALON-LIB-1,
   перенос структурного брейкпоинта эскиза design/etalon/eskiz-glavnaya.html,
   докстрока раздела «ПЛАНШЕТНЫЙ ДИАПАЗОН 700–960» — вердикт Владельца: на
   планшете-портрете герой держит 2 колонки, схлопывается в столбец только
   ниже 700, где фото рядом с текстом уже нечитаемо. Точка 960 остаётся
   контрактной (spec/docs/11) для ПРОЧИХ виджетов страницы (container,
   site-header nav); герой — осознанное исключение по эталону, см. также
   .hero__media/@media(max-width:699px) выше и стиль marina-editorial,
   который донастраивает пропорцию колонок в диапазоне 700–960). */
@media (min-width: 700px) {
  .hero__container {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  }
}

@media (min-width: 1200px) {
  .hero__container {
    gap: var(--hero-gap, var(--s-12, 3rem));
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero__cta {
    transition: none;
  }
}

/* =========================================================================
   styles/hero/marina-editorial.css — стиль «Герой editorial» темы Marina
   Ровно один класс-модификатор .hero--marina-editorial (DEC-001 п.4/5): путь
   файла механически совпадает с суффиксом класса. Специфичность: одна
   ступень поверх .hero (плюс потомки — не эскалирует специфичность класса
   корня). Без !important.

   ИСТОЧНИК КОДА — эталон design/etalon/eskiz-glavnaya.html (арт-ворота
   Владельца, DEC-003 unona-site, «эскиз — ИСТОЧНИК КОДА: приёмы/значения
   переносить точно, не пересочинять», TASK-ETALON-LIB-1). Приёмы,
   отсутствовавшие у marina-split/marina-glass: строка eyebrow с линией-
   разделителем, вынос ключевого слова заголовка курсивом (em) и полужирным
   (b), ценовая строка-метрики с курсивным «курсом» (variant "course" в
   hero__metrics основы), камея-эмблема студии поверх фото, резиновая шкала
   Utopia (--fl-*, themes/marina/tokens.css) вместо clamp-формул на месте.
   ========================================================================= */

.hero--marina-editorial {
  padding-block: var(--hero-section-padding-y, var(--fl-space-72, clamp(2.5rem, 1.68rem + 3.64vw, 4.5rem))) 0;
  background: var(--bg-1);
}

.hero--marina-editorial .hero__container {
  gap: var(--hero-gap, 3.5rem);
}

.hero--marina-editorial .hero__body {
  gap: var(--s-6, 1.5rem);
  padding-bottom: var(--s-16, 4rem);
}

/* --- Eyebrow-строка с линией (эталон .hero__eyebrow-row::after) --- */

.hero--marina-editorial .hero__eyebrow-row::after {
  content: "";
  height: 1px;
  flex: 1;
  background: var(--border-2);
}

.hero--marina-editorial .hero__eyebrow {
  font-family: var(--font-body);
  font-size: var(--t-eyebrow);
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--fg-brand);
}

/* --- Заголовок: вынос ключевого слова курсивом/полужирным (эталон
   .hero__title em/b) --- */

.hero--marina-editorial .hero__title {
  font-family: var(--font-display);
  font-weight: var(--w-light);
  font-size: clamp(2.6rem, 1.1rem + 3.9vw, 4.6rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
  color: var(--fg-1);
}

.hero--marina-editorial .hero__title em {
  font-style: italic;
  color: var(--fg-brand);
  font-weight: var(--w-regular);
}

.hero--marina-editorial .hero__title b {
  font-weight: var(--w-medium);
}

.hero--marina-editorial .hero__lede {
  font-family: var(--font-body);
  font-size: var(--t-body, 1rem);
  line-height: var(--lh-loose);
  color: var(--fg-2);
  max-width: 46ch;
}

.hero--marina-editorial .hero__cta {
  font-family: var(--font-body);
}

.hero--marina-editorial .hero__cta--primary {
  background: var(--fg-brand);
  box-shadow: var(--shadow-2);
}

.hero--marina-editorial .hero__cta--primary::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.35) 50%, transparent 70%);
  transform: translateX(-120%);
  transition: transform var(--t-cta-sheen, 720ms) var(--ease-out);
}

.hero--marina-editorial .hero__cta--primary:hover {
  box-shadow: var(--shadow-3);
  transform: translateY(-2px);
}

.hero--marina-editorial .hero__cta--primary:hover::before {
  transform: translateX(120%);
}

.hero--marina-editorial .hero__cta--secondary:hover {
  border-color: var(--fg-brand);
  color: var(--fg-brand);
}

/* --- Ценовая строка-метрики (эталон .hero__priceline/.hero__price) —
   значение крупным дисплейным шрифтом, надстрочная единица, variant
   "course" курсивом без числа. --- */

.hero--marina-editorial .hero__metrics {
  flex-wrap: nowrap;
  gap: var(--s-8, 2rem);
  margin-top: var(--s-1, 0.25rem);
  padding-top: var(--s-8, 2rem);
  border-top: 1px solid var(--border-2);
  align-items: flex-end;
}

.hero--marina-editorial .hero__metric {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: none;
  max-width: none;
  padding-inline: 0;
}

.hero--marina-editorial .hero__metric-value {
  font-family: var(--font-display);
  font-size: clamp(2rem, 1rem + 2.4vw, 3rem);
  font-weight: var(--w-medium);
  line-height: 0.95;
  color: var(--fg-1);
  letter-spacing: -0.02em;
}

/* Надстрочная единица «₽» (Пачка C, п.1) — перенос буквальный, эталон
   design/etalon/eskiz-glavnaya.html .hero__price-v span{font-size:.5em;
   color:var(--fg-brand)} (I2). */
.hero--marina-editorial .hero__metric-unit {
  font-size: 0.5em;
  color: var(--fg-brand);
}

.hero--marina-editorial .hero__metric-label {
  font-family: var(--font-body);
  font-size: 12.5px;
  color: var(--fg-2);
  line-height: 1.35;
  max-width: 20ch;
}

.hero--marina-editorial .hero__metric--course .hero__metric-value {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--w-regular);
  color: var(--fg-brand);
  font-size: clamp(1.5rem, 1rem + 1.4vw, 2rem);
}

/* --- Медиа: photo-wrap, тень-композиция, grain, badge, деталь, камея --- */

.hero--marina-editorial .hero__media {
  align-self: stretch;
  display: flex;
  align-items: center;
}

.hero--marina-editorial .hero__media-main {
  border-radius: var(--r-2xl, 26px);
  box-shadow: var(--shadow-4);
}

.hero--marina-editorial .hero__media-grain {
  opacity: 0.06;
}

.hero--marina-editorial .hero__media-detail {
  border: 5px solid var(--bg-1);
  box-shadow: var(--shadow-3);
}

.hero--marina-editorial .hero__badge {
  background: var(--bg-1);
  color: var(--fg-brand);
  font-family: var(--font-body);
  font-weight: var(--w-semibold);
  letter-spacing: 0.14em;
  box-shadow: var(--shadow-3);
}

.hero--marina-editorial .hero__badge::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--sage-500);
  margin-inline-end: 4px;
}

.hero--marina-editorial .hero__media-cameo {
  box-shadow: var(--shadow-3), 0 0 0 4px rgba(244, 238, 230, 0.85);
}

/* =========================================================================
   ПЛАНШЕТНЫЙ ДИАПАЗОН 700–960 (эталон, докстрока base.css/@media 700–960):
   2 колонки сохраняются (структурная точка — base.css), но пропорция
   смещается в пользу текста, фото ограничено по высоте. */
@media (min-width: 700px) and (max-width: 960px) {
  .hero--marina-editorial .hero__container {
    grid-template-columns: 1fr 0.82fr;
    gap: var(--s-8, 2rem);
  }
  .hero--marina-editorial .hero__body {
    padding-bottom: var(--s-8, 2rem);
    gap: var(--s-5, 1.25rem);
  }
  .hero--marina-editorial .hero__title {
    font-size: clamp(2rem, 1.1rem + 2.6vw, 2.8rem);
  }
  .hero--marina-editorial .hero__media-main {
    --hero-photo-ratio: 3 / 4;
    --hero-photo-max-h: 52vh;
  }
  .hero--marina-editorial .hero__media-detail {
    width: 34%;
    right: -10px;
    bottom: -20px;
  }
  .hero--marina-editorial .hero__media-cameo {
    --hero-cameo-size: 3.5rem;
  }
  .hero--marina-editorial .hero__metrics {
    flex-wrap: wrap;
    gap: var(--s-5, 1.25rem);
    padding-top: var(--s-6, 1.5rem);
  }
  .hero--marina-editorial .hero__metric-value {
    font-size: clamp(1.6rem, 1rem + 1.6vw, 2.2rem);
  }
}

/* =========================================================================
   МОБИЛЬНАЯ ЛИНЕАРИЗАЦИЯ — ниже 700 (структурная точка base.css) фото идёт
   ПЕРВЫМ (эталон: .hero__media{order:1}), текст вторым, оба ограничены по
   высоте/ширине (не «весь экран»). */
@media (max-width: 699px) {
  /* .hero__container{gap:var(--hero-gap,3.5rem)=56px} (правило вне media,
     строка 24) задумано как ГОРИЗОНТАЛЬНЫЙ зазор между колонками текст/фото
     на десктопе (>=700, 2 колонки, base.css). На мобиле (1 колонка) grid-gap
     работает как ВЕРТИКАЛЬНЫЙ row-gap между .hero__body и .hero__media —
     складывается с margin-bottom:32px у .hero__media (ниже) в 56+32=88px
     зазора фото→eyebrow (замер Владельца на 280/320/360). Эталон design/
     etalon/eskiz-glavnaya.html .hero__grid на max-width:700 задаёт
     gap:12px (не 56) — margin-bottom самой медиа-колонки (36px) несёт
     зазор. Обнуляем grid-gap на мобиле, margin-bottom .hero__media —
     единственный источник зазора. */
  .hero--marina-editorial .hero__container {
    gap: 0;
  }
  .hero--marina-editorial .hero__body {
    order: 2;
    padding-bottom: var(--s-10, 2.5rem);
    gap: var(--s-6, 1.5rem);
  }
  /* align-self:stretch + display:flex/align-items:center (правило вне
     media-запроса выше, строки 162-166) рассчитаны на ДЕСКТОП 2-колоночную
     сетку (.hero__container grid, base.css) — там медиа-колонка растягива-
     ется на высоту текстовой и фото центрируется внутри. На мобиле (1
     колонка, каждый элемент — своя grid-строка) stretch/центрирование не
     нужны и раздували контейнер выше фото (Владелец: «огромное пространство
     под фото» — измерено 88px зазора фото→eyebrow на 280/320 вместо
     эталонных ~32-36px, design/etalon/eskiz-glavnaya.html .hero__media
     margin-bottom:36px БЕЗ display:flex/align-items). align-self:auto +
     display:block снимают лишнюю высоту; margin-bottom остаётся —
     единственный зазор фото→текст на мобиле, как в эталоне. */
  .hero--marina-editorial .hero__media {
    order: 1;
    align-self: auto;
    display: block;
    margin-bottom: var(--s-8, 2rem);
  }
  .hero--marina-editorial .hero__media-main {
    --hero-photo-ratio: 4 / 3.4;
    --hero-photo-max-h: 40vh;
  }
  .hero--marina-editorial .hero__media-detail {
    width: 36%;
    right: -8px;
    bottom: -24px;
  }
  .hero--marina-editorial .hero__badge {
    top: var(--s-3, 0.75rem);
    left: var(--s-3, 0.75rem);
  }
  .hero--marina-editorial .hero__media-cameo {
    --hero-cameo-size: 3.75rem;
  }
  .hero--marina-editorial .hero__metrics {
    flex-wrap: wrap;
    gap: var(--s-5, 1.25rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero--marina-editorial .hero__cta--primary::before {
    transition: none;
    transform: translateX(-120%);
  }
  .hero--marina-editorial .hero__cta--primary:hover::before {
    transform: translateX(-120%);
  }
  .hero--marina-editorial .hero__cta--primary,
  .hero--marina-editorial .hero__cta--primary:hover {
    box-shadow: var(--shadow-2);
  }
}

/* =========================================================================
   bases/pains/base.css — структурный слой основы «Боли и сегменты»
   Специфичность: только базовый класс .pains (DEC-001 п.5). Раскладка пункта
   — CSS Grid «номер | тело», resina через var()/clamp (DEC-001 п.12). Блок
   не несёт .section/.container сам (self_wrapped: false, registry.yaml) —
   отступы даёт родитель (assemble_page/layout/base.css).
   ========================================================================= */

.pains__list {
  display: flex;
  flex-direction: column;
}

.pains__item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-6, 1.5rem);
  align-items: baseline;
  padding-block: var(--s-8, 2rem);
  border-top: 1px solid var(--border-1, #e5dacb);
}

.pains__list .pains__item:last-child {
  border-bottom: 1px solid var(--border-1, #e5dacb);
}

.pains__number {
  font-family: var(--font-display, serif);
  font-size: var(--fl-27, clamp(1.6875rem, 1.5085rem + 0.7955vw, 2.125rem));
  line-height: 1;
  color: var(--fg-3, #8b6f65);
}

.pains__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
}

.pains__title {
  margin: 0;
  font-size: var(--fl-20b, clamp(1.25rem, 1.1477rem + 0.4545vw, 1.5rem));
  color: var(--fg-1, #111);
}

.pains__text {
  margin: 0;
  max-width: 52ch;
  color: var(--fg-2, #555);
}

.pains__link {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2, 0.5rem);
  margin-top: var(--s-2, 0.5rem);
  font-weight: var(--w-semibold, 600);
  color: var(--fg-brand, #9c6957);
  text-decoration: none;
}

/* Ниже 700 (та же структурная точка, что и герой этой ячейки — эталон
   design/etalon/eskiz-glavnaya.html, .pain{grid-template-columns:auto 1fr}
   сохраняется на мобиле, только зазор и паддинг уже) пункт остаётся той же
   двухколоночной сеткой (номер+тело) — линеаризации в один столбец эталон
   для .pain НЕ делает (проверено: секция .pains в @media(max-width:700px)
   меняет только grid-template-columns РОДИТЕЛЯ .pains__grid на 1fr, сама
   .pain остаётся auto 1fr). */
@media (max-width: 699px) {
  .pains__item {
    gap: var(--s-4, 1rem);
    padding-block: var(--s-6, 1.5rem);
  }
}

/* =========================================================================
   styles/pains/marina.css — стиль «Marina» ленты «Боли и сегменты»
   Ровно один класс-модификатор .pains--marina (DEC-001 п.4/5). Специфичность:
   одна ступень поверх .pains. Без !important.

   Источник кода — design/etalon/eskiz-glavnaya.html (.pain__n курсив
   дисплейным шрифтом цвета blush-300, .pain__h дисплейный regular, .pain__t
   body, .pain__arrow — цвет бренда с зазором, растущим на hover).
   ========================================================================= */

.pains--marina .pains__number {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--w-light);
  color: var(--blush-300);
}

.pains--marina .pains__title {
  font-family: var(--font-display);
  font-weight: var(--w-regular);
  color: var(--fg-1);
}

.pains--marina .pains__text {
  font-family: var(--font-body);
  line-height: var(--lh-loose);
  color: var(--fg-2);
}

.pains--marina .pains__link {
  font-family: var(--font-body);
  font-size: var(--t-caption, 0.8125rem);
  letter-spacing: var(--ls-tight);
  transition: gap var(--t-fast) var(--ease-out);
}

.pains--marina .pains__link:hover {
  gap: var(--s-3, 0.75rem);
}

@media (prefers-reduced-motion: reduce) {
  .pains--marina .pains__link {
    transition: none;
  }
}

/* Контраст hairline-разделителей на фоне section--alt (TASK-RITM-REPAIR-B1,
   2026-07-08, scan-01.md пачка B.1 «разделителей нет»). Проверено: линии в
   DOM есть (bases/pains/base.css border-top/last-child border-bottom, тот
   же --border-1 #E5DACB, что и эталон design/etalon/eskiz-glavnaya.html
   строки 268-271) — но pains в текущей альтернации фонов секций (layout/
   base.css .section--alt) рендерится на --bg-3/sand #E9DDCF, который
   отличается от --border-1 #E5DACB буквально на несколько пунктов RGB —
   контраст практически 1:1, линия визуально пропадает. Эталон держит
   .pains на фиксированном --bg-2/paper #FBF8F2 независимо от альтернации,
   там контраст border-1 достаточен; трогать саму альтернацию фона вне
   рамок этой ячейки (структурная правка чужой зоны). Решение — точечно
   поднять контраст самого разделителя ТОЛЬКО когда pains сидит на
   section--alt: --border-2/dune (#D8C7B5) — тот же токен уже используется
   как видимый hairline-разделитель в styles/hero/marina-editorial.css:122
   (border-top:1px solid var(--border-2)), переиспользован приём, не
   изобретён новый цвет (I2). Специфичность (0,3,0) выше базового
   (0,1,0) — переопределяет без !important независимо от порядка файлов. */
.section--alt .pains--marina .pains__item {
  border-top-color: var(--border-2, #d8c7b5);
}

.section--alt .pains--marina .pains__list .pains__item:last-child {
  border-bottom-color: var(--border-2, #d8c7b5);
}

/* =========================================================================
   bases/section_header/base.css — структурный слой основы «Заголовок секции»
   Специфичность: только базовый класс .section-header (DEC-001 п.5).
   Регулируемое — через var() (DEC-001 п.12); значения падают на нейтральный
   fallback, основа демонстрируема без темы. Блок не несёт .section/.container
   сам — это слот внутри секции-сборки, отступы задаёт родитель.
   ========================================================================= */

.section-header {
  display: flex;
  flex-direction: column;
  gap: var(--s-3, 0.75rem);
  max-width: var(--section-header-max-width, 62ch);
}

.section-header__eyebrow {
  margin: 0;
}

.section-header__title {
  margin: 0;
}

.section-header__lede {
  margin: 0;
  max-width: var(--section-header-lede-max-width, 56ch);
  color: var(--fg-2, #555);
}

/* CTA под лидом (TASK-ETALON-LIB-1) — структурно нейтральная кнопка-пилюля,
   палитру/типографику даёт слой style (styles/section_header/<theme>.css). */
.section-header__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: var(--s-3, 0.75rem);
  padding: var(--s-3, 0.75rem) var(--s-6, 1.5rem);
  border-radius: var(--r-pill, 999px);
  text-decoration: none;
  align-self: flex-start;
}

.section-header--centered .section-header__cta {
  align-self: center;
}

/* Модификатор центрирования — доступен без отдельного стиля, т.к. это
   структурное, а не оформительское решение (выравнивание секции целиком,
   не палитра/типографика). Используется пресетами hero_centered и
   подобными сборками секции. */
.section-header--centered {
  align-items: center;
  text-align: center;
  max-width: var(--section-header-max-width-centered, 44rem);
  margin-inline: auto;
}

/* =========================================================================
   styles/section_header/marina.css — стиль «Marina» заголовка секции
   Ровно один класс-модификатор .section-header--marina (DEC-001 п.4/5):
   путь styles/section_header/marina.css механически совпадает с суффиксом
   класса. Специфичность: одна ступень поверх .section-header. Без !important.

   Перенос ручной правки эталона (FLG-034, TASK-P3-INTEGRATION-FIX) в
   канонический слой библиотеки (TASK-P3-CANONIZE-FIX-EXEC, починка 2):
   типографика — тот же язык, что cta-block__title/faq-accordion__heading
   (шрифт display для заголовка, body для eyebrow/lede), эйброу капсом с
   трекингом — тот же приём, что hero__eyebrow/service-card__category.
   До этой ячейки папка styles/section_header/ была пустой на диске —
   обёртка секции применяла style_class="section-header--marina" (см.
   block_assembler.py _render_heading_html), но CSS-файл для него не
   существовал (I2 — не изобретаю несуществующий файл, завожу его явно).

   Правка размера заголовка (TASK-P3-ART-FIX, арт-ворота №2, находка 1 —
   регресс правки 2а первого суда): __title сидел на токене --tf-h2
   (потолок 1.75rem = 28px) — та же высота, что карточные h3, иерархия
   h1(60)->h2(28)->h3(22) читалась плоской, и на странице получались ДВА
   разных размера h2 (28px секции против 40.4px у cta-block__title,
   который уже стоял на дисплейной ступени). Перевод на --tf-display-m
   (потолок 2.75rem = 44px, themes/marina/tokens.css) — та же ступень, что
   у cta-block__title (styles/cta_block/marina.css) — снимает и разнобой
   размеров, и слабый контраст h1->h2.

   ПОВТОРНАЯ ПРАВКА (TASK-RHYTHM-MATCH, 2026-07-08): --tf-display-m
   (28->44px) всё ещё МЕЛЬЧЕ эталона design/etalon/eskiz-glavnaya.html —
   .pains__title/.progs__title/.dirs__title там сидят на
   clamp(2rem,1rem + 2.4vw,3.1rem) (32->49.6px), .faq__title на почти той
   же ступени (32->48px, разница ~1.6px на максимуме — в пределах общего
   допуска). section_header — один переиспользуемый компонент на 4 секции
   (pains/programs/directions/faq) плюс общий заголовок stats, у эталона же
   эти секции используют близкие, но не идентичные клампы (figures__title
   отдельно 1.9->2.8rem/30.4->44.8px, книга — отдельный крупный клампу
   cta-block__title). Беру числа БОЛЬШИНСТВА секций эталона (I2, буквально,
   не выдумано) — расхождение с faq/figures на максимуме кегля <2px,
   заведомо ниже 10%-порога приёмки (задание ячейки, п.2). */

.section-header--marina .section-header__eyebrow {
  font-family: var(--font-body);
  font-size: var(--t-eyebrow);
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--fg-brand);
}

.section-header--marina .section-header__title {
  font-family: var(--font-display);
  font-weight: var(--w-medium);
  font-size: var(--fl-title-a, clamp(2rem, 1rem + 2.4vw, 3.1rem));
  color: var(--fg-1);
}

.section-header--marina .section-header__lede {
  font-family: var(--font-body);
  line-height: var(--lh-loose);
}

/* CTA (TASK-ETALON-LIB-1) — тот же язык primary-кнопки, что hero__cta--primary. */
.section-header--marina .section-header__cta {
  font-family: var(--font-body);
  font-weight: var(--w-medium);
  background: var(--fg-brand);
  color: var(--fg-on-dark);
  box-shadow: var(--shadow-2);
  transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}

.section-header--marina .section-header__cta:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-3);
}

@media (prefers-reduced-motion: reduce) {
  .section-header--marina .section-header__cta {
    transition: none;
  }
}

/* =========================================================================
   bases/stats_strip/base.css — структурный слой основы «Статистика и цифры»
   Специфичность: только базовый класс .stats-strip (DEC-001 п.5). Паттерн
   «ряд с разделителями» перенесён из hero__metrics (правка Владельца,
   registry.yaml hero 0.2.2) — реализован здесь как разделитель-граница
   между соседними пунктами (border-inline-start у всех кроме первого),
   не через ::after с абсолютным позиционированием — переносится корректно
   при переносе строк на узких экранах (flex-wrap, без брейкпоинтов:
   резина, дополнение Владельца TASK-P3-CONTENT-1).
   ========================================================================= */

/* К5.2/К4.2 (DEC-002)/находка audit-01 пачка H: вертикальный
   border-inline-start ломался при переносе в столбик на 360-600 —
   становился левой границей-отступом каждого пункта (лесенка) и на
   480/600 давал висячую линию у одинокого последнего элемента неполного
   ряда. Замена без брейкпоинтов и без JS-подсчёта переносов: разделитель
   — justify-content:center (неполный ряд центрируется, K4.3) плюс
   разделительная ГРАНИЦА СНИЗУ у каждого пункта КРОМЕ последнего в
   потоке через :not(:last-child), нарисованная так, что при переносе
   она читается как завершение строки, а не как рваный левый край —
   ряд выровнен по одному левому краю всегда (padding-inline-start
   убран целиком, разделитель больше не создаёт отступа). */
/* FLG (prodazha, 2026-07-09): flex-wrap кидал 4-й стат неполного ряда в
   новую строку одиноко по центру — «сирота снизу». Замена на сетку, где
   сироты нет ни при 3, ни при 4 статах:
   — узкий: 1 столбец (столбик N×1, сирота невозможна);
   — средний: 2 столбца ТОЛЬКО для чётного числа статов (4→2×2 без сироты);
     нечётное (3) держим в 1 столбец — 2 столбца дали бы ряд 2+1 сироту;
   — широкий: ровно N столбцов по числу статов — один ряд N×1, сироты нет
     при любом количестве. N берётся из --stats-strip-count (основа ставит
     из длины items), чётность — из класса-модификатора stats-strip--even. */
.stats-strip {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--stats-strip-gap, var(--s-6, 1.5rem));
}

/* Чётное число статов (4) — 2 столбца от среднего и на широком: 2×2,
   просторно, без сироты. Дальше не разворачиваем — 4×1 на широком зажимал
   крупное значение и число переносилось (560–/680). */
@media (min-width: 560px) {
  .stats-strip--even { grid-template-columns: repeat(2, 1fr); }
}

/* Нечётное (3) — до широкого столбик (2 столбца дали бы 2+1 сироту), на
   широком ровно N столбцов одним рядом (3×1). N из --stats-strip-count. */
@media (min-width: 960px) {
  .stats-strip--odd {
    grid-template-columns: repeat(var(--stats-strip-count, 3), minmax(0, 1fr));
  }
}

/* Фон-фото full-bleed (TASK-ETALON-LIB-1, опциональный props.background) —
   decorative <li aria-hidden>, position:absolute выводит его из потока
   flex-строки (соседние .stats-strip__item не смещаются). Full-bleed —
   отрицательный margin приёмом «breakout», т.к. блок остаётся self_wrapped:
   false и физически сидит внутри .container родителя (registry.yaml). */
.stats-strip__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  width: 100vw;
  left: 50%;
  transform: translateX(-50%);
}

.stats-strip__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.stats-strip__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--s-1, 0.25rem);
  padding-inline: var(--stats-strip-gap, var(--s-6, 1.5rem));
}

/* Вертикальные разделители по раскладке — без «лесенки»:
   — чётное 2×2 (≥560): граница на правом столбце (nth-child(even)) —
     одна вертикаль между колонками, у левого столбца границы нет;
   — нечётное N×1 (≥960): граница между всеми, кроме первого;
   в столбик (узкий) границ нет. */
@media (min-width: 560px) {
  .stats-strip--even .stats-strip__item:nth-child(even) {
    border-inline-start: 1px solid var(--stats-strip-divider-color, var(--border-1, #e5dacb));
  }
}
@media (min-width: 960px) {
  .stats-strip--odd .stats-strip__item {
    border-inline-start: 1px solid var(--stats-strip-divider-color, var(--border-1, #e5dacb));
  }
  .stats-strip--odd .stats-strip__item:first-child {
    border-inline-start: none;
  }
}

.stats-strip__value {
  font-family: var(--font-display, serif);
  /* Резиновый калибр значения — clamp() между t-h2 и t-display-m, растёт
     плавно с шириной, без фиксированного скачка на брейкпоинте
     (дополнение Владельца, TASK-P3-CONTENT-1). */
  font-size: var(--stats-strip-value-size, clamp(var(--t-h2, 1.75rem), 2vw + 1rem, var(--t-display-m, 2.75rem)));
  line-height: var(--lh-tight, 1.05);
  color: var(--fg-1, #111);
}

/* Надстрочная единица (TASK-ETALON-LIB-1, эталон .fig__v span) — мельче,
   выше базовой линии значения, не отдельный элемент типографической
   ступени (структурно нейтрально, палитру задаёт style).
   FLG (prodazha, 2026-07-09): многобуквенная единица («тыс ₽», «ч/день»)
   без nowrap ужималась в ширину колонки и буквы налезали друг на друга.
   Правки: inline-block + nowrap (единица не переносится и не сжимается),
   калибр чуть крупнее для читаемости слов, сдвиг вверх через нижний
   margin вместо vertical-align:super (super задирал многобуквенную
   единицу за верх крупного значения). Короткий значок «₽» (главная)
   рендерится так же аккуратно. */
.stats-strip__unit {
  display: inline-block;
  font-size: 0.36em;
  white-space: nowrap;
  margin-inline-start: 0.25em;
  margin-block-end: 0.9em;
  vertical-align: baseline;
}

.stats-strip__label {
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-2, #555);
  max-width: var(--stats-strip-label-max-width, 22ch);
}

/* Когда ряд переносится на узком экране (flex-wrap), разделитель первого
   пункта новой визуальной строки визуально «висит» слева без соседа сверху
   — это ожидаемо для CSS-only разделителя без JS-подсчёта переносов;
   отступ читается как начало нового пункта, не как ошибка (I7, явный
   компромисс механизма без брейкпоинтов). */

/* =========================================================================
   styles/stats_strip/marina-dark.css — «Статистика и цифры» тёмной полосой
   Ровно один класс-модификатор .stats-strip--marina-dark (DEC-001 п.4/5).
   Специфичность: одна ступень поверх .stats-strip. Без !important.

   ИСТОЧНИК КОДА — design/etalon/eskiz-glavnaya.html, секция «3. ФОТО-ПОЛОСА
   С ЦИФРАМИ» (DEC-003 unona-site, TASK-ETALON-LIB-1): тёмная полоса cocoa
   во всю ширину, фон-фото приглушённый (opacity+градиент-затемнение),
   гигантские цифры с надстрочной единицей (stats-strip__unit основы) и
   курсивным словом-вариантом (variant "word"). Перенесена свежая правка
   Владельца (2026-07-07, коммит unona-site ec143fb) — поджатый ряд из трёх
   с разделителями на планшете/мобиле, НЕ гигантский столбик.

   Full-bleed фон — приём базового слоя (stats-strip__bg, base.css);
   градиент-затемнение и оттенок фото — здесь (палитра — забота style).
   Ограничение (I7): разделители-границы построчной раскладки (base.css,
   :first-child) корректны для ОДНОЙ строки из 3 пунктов (фактический
   состав секции «Цифры» эталона) — многострочный ряд > 3 пунктов не
   тестировался этим стилем. */

/* ПОЧИНКА (TASK-FIGURES-UNIFY, 2026-07-08): раньше `.stats-strip--marina-
   dark` сам нёс тёмный фон + full-bleed breakout (width:100vw) + свой
   padding-block — де-факто отдельный тёмный остров ВНУТРИ секции, соседний
   с `.section-header`, а не под ним. Фон/позиционирование/отступ секции
   целиком перенесены на уровень `.section` (layout/base.css) — эта
   обёртка больше не пробивает свой контейнер сама (нет смысла: `.section`
   и так full-width, `.container` внутри держит горизонтальные поля). Ряду
   остаётся только внутренняя раскладка (центрирование, без зазора между
   пунктами — зазор даёт padding-inline пункта).

   `position: static` (селектор `.stats-strip.stats-strip--marina-dark` —
   ОБЕ ступени специфичности намеренно, не одна): базовый слой
   (bases/stats_strip/base.css) держит `.stats-strip{position:relative}`
   БЕЗУСЛОВНО для любой темы — иначе `.stats-strip__bg`
   (`position:absolute;inset:0`) анкорится к самому `<ul>` и фон-фото не
   дотянется до `.section-header` выше. Компаунд-селектор даёт
   специфичность (0,2,0) — гарантированно перебивает базовое
   `.stats-strip{position:relative}` (0,1,0) НЕЗАВИСИМО от порядка
   подключения файлов (в отличие от одноклассового `.stats-strip--marina-
   dark{position:static}`, которое дало бы тот же (0,1,0) — ничья,
   решаемая только порядком, хрупко). `.stats-strip__bg` при этом
   анкорится к БЛИЖАЙШЕМУ позиционированному предку выше по дереву —
   теперь это `.section` (position:relative, layout/base.css), поэтому
   фон-фото растягивается на всю секцию (эйброу+заголовок+ряд), не только
   на ряд. Другие (не full-bleed) стили `.stats-strip` этот override не
   затрагивает — `position:relative` базового слоя остаётся для них как
   было. */
.stats-strip.stats-strip--marina-dark {
  position: static;
  justify-content: center;
  gap: 0;
}

/* Находка живым замером этой же ячейки (I7, не в исходном дефекте
   Владельца): `<ul>` несёт `data-reveal` (layout/base.css) — при появлении
   секции в вьюпорте общее правило `.js-reveal-ready [data-reveal]` играет
   `transform:translateY(16px)->none`. Пока transform на `<ul>` НЕ `none`
   (во время самого перехода, ~420мс), CSS делает `<ul>` содержащим блоком
   для СВОИХ position:absolute потомков — `.stats-strip__bg` на этот
   короткий промежуток анкорится обратно к `<ul>` (к ряду), а не к
   `.section` — фон-фото визуально «прыгает»/меняет размер в момент
   завершения перехода. Отключаем именно transform-часть перехода ДЛЯ
   ЭТОГО элемента (opacity-часть остаётся — плавное появление сохранено),
   специфичность `.js-reveal-ready .stats-strip.stats-strip--marina-dark`
   (0,3,0) перебивает базовое `.js-reveal-ready [data-reveal]` (0,2,0) без
   `!important`. */
.js-reveal-ready .stats-strip.stats-strip--marina-dark {
  transform: none;
}

/* Палитра секции-обёртки (фон+цвет текста по умолчанию) и section-header
   внутри неё (эйброу/заголовок/em-акцент) — эталон design/etalon/
   eskiz-glavnaya.html: `.figures{background:cocoa-900;color:linen}`,
   `.figures__head .eyebrow{color:blush-300}`, `.figures__title{color:
   linen}`, `.figures__title em{color:blush-300}`. Структура/позиция уже
   перенесены на `.section` в layout/base.css — здесь только цвет
   (DEC-001: палитра — забота style, не layout). Специфичность
   селектора `.section:has(> .container > .stats-strip--marina-dark)
   .section-header__*` — (0,4,0)/(0,5,0), перебивает
   `.section-header--marina .section-header__*` (0,2,0) при любом порядке
   подключения файлов, без !important. */
.section:has(> .container > .stats-strip--marina-dark) {
  background: var(--cocoa-900);
  color: var(--linen);
}

.section:has(> .container > .stats-strip--marina-dark) .section-header__eyebrow {
  color: var(--blush-300);
}

.section:has(> .container > .stats-strip--marina-dark) .section-header__title {
  color: var(--linen);
}

.section:has(> .container > .stats-strip--marina-dark) .section-header__title em {
  color: var(--blush-300);
}

.stats-strip--marina-dark .stats-strip__bg img {
  opacity: 0.22;
  filter: grayscale(0.2) saturate(1.1);
}

.stats-strip--marina-dark .stats-strip__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(42, 30, 26, 0.72), rgba(42, 30, 26, 0.86)),
    radial-gradient(60% 60% at 80% 20%, rgba(210, 164, 146, 0.18), transparent 70%);
}

.stats-strip--marina-dark .stats-strip__item {
  /* padding-block 8px — TASK-RHYTHM-MATCH (2026-07-08): эталон
     design/etalon/eskiz-glavnaya.html `.fig{padding:8px 40px}` — было
     только padding-inline, ряд цифр был на 16px ниже эталона (доля общего
     дефицита секции «Цифры», -81px из общего замера). Перенесено буквально
     (I2). */
  padding-block: 0.5rem;
  padding-inline: var(--s-10, 2.5rem);
  border-inline-start-color: rgba(244, 238, 230, 0.16);
  align-items: flex-start;
  text-align: left;
}

.stats-strip--marina-dark .stats-strip__value {
  font-family: var(--font-display);
  font-weight: var(--w-light);
  line-height: 0.8;
  font-size: clamp(4rem, 1.5rem + 8.5vw, 9rem);
  letter-spacing: -0.04em;
  color: var(--linen);
}

.stats-strip--marina-dark .stats-strip__unit {
  color: var(--blush-300);
  font-weight: var(--w-regular);
}

.stats-strip--marina-dark .stats-strip__item--word .stats-strip__value {
  font-style: italic;
  font-size: clamp(2.8rem, 1.5rem + 4.6vw, 5.6rem);
  color: var(--blush-300);
  line-height: 0.94;
}

.stats-strip--marina-dark .stats-strip__label {
  font-family: var(--font-body);
  margin-top: var(--s-4, 1rem);
  font-size: 14.5px;
  color: rgba(244, 238, 230, 0.75);
  max-width: 26ch;
}

/* padding-inline у самого `.stats-strip--marina-dark` на 960/1200 —
   УБРАНО (TASK-FIGURES-UNIFY): раньше дублировало шкалу `.container`
   (layout/base.css), компенсируя чужой full-bleed breakout. Ряд теперь
   обычный ребёнок `.container` — горизонтальные поля даёт сам контейнер,
   повторять их здесь означало бы задваивать отступ. */

/* --- Правка Владельца (ec143fb): поджатый ряд из трёх с разделителями на
   планшете/мобиле, не гигантский столбик. --- */

@media (max-width: 960px) {
  .stats-strip--marina-dark {
    gap: var(--s-4, 1rem);
  }
  .stats-strip--marina-dark .stats-strip__item {
    padding-inline: var(--s-5, 1.25rem);
  }
  .stats-strip--marina-dark .stats-strip__value {
    font-size: clamp(2.2rem, 0.8rem + 3.4vw, 3.4rem);
  }
  .stats-strip--marina-dark .stats-strip__item--word .stats-strip__value {
    font-size: clamp(1.8rem, 0.7rem + 2.8vw, 2.8rem);
  }
  .stats-strip--marina-dark .stats-strip__label {
    font-size: 13px;
    margin-top: var(--s-3, 0.75rem);
  }
}

@media (max-width: 699px) {
  .stats-strip--marina-dark {
    flex-wrap: nowrap;
    gap: var(--s-3, 0.75rem);
  }
  .stats-strip--marina-dark .stats-strip__item {
    flex: 1 1 0;
    min-width: 0;
    padding-inline: var(--s-3, 0.75rem);
    align-items: flex-start;
    text-align: left;
  }
  .stats-strip--marina-dark .stats-strip__item:first-child {
    padding-inline-start: 0;
  }
  .stats-strip--marina-dark .stats-strip__value {
    font-size: clamp(1.5rem, 6vw, 2.2rem);
  }
  .stats-strip--marina-dark .stats-strip__unit {
    margin-inline-start: 0.15em;
  }
  .stats-strip--marina-dark .stats-strip__item--word .stats-strip__value {
    font-size: clamp(1.3rem, 5vw, 1.9rem);
  }
  .stats-strip--marina-dark .stats-strip__label {
    font-size: 12px;
    margin-top: var(--s-2, 0.5rem);
    max-width: none;
  }
}

/* =========================================================================
   bases/progs/base.css — структурный слой основы «Программы»
   Специфичность: только базовый класс .progs-list (DEC-001 п.5).

   Резина (FLG-003, DEC-001 п.14): все регулируемые размеры — clamp()/var(),
   структурные брейкпоинты — только контрактные точки доки 11 (960/700),
   перенесены из эталона (media max-width:960px/700px) один в один. Проверка
   на промежуточных ширинах (540/768/1024) — обязательный пункт acceptance.md.

   ВНИМАНИЕ (задокументированный инцидент): clamp() пишется С ПРОБЕЛАМИ
   вокруг +/- операторов — без пробелов браузер отбрасывает всё правило.
   ========================================================================= */

.progs-list {
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 1rem + 2vw, 2.125rem);
}

.prog {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  overflow: hidden;
  border-radius: var(--progs-radius, 26px);
}

.prog__media {
  position: relative;
  min-height: var(--progs-media-min-h, 300px);
  overflow: hidden;
}

.prog__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  position: absolute;
  inset: 0;
  transition: transform 600ms var(--ease-out, ease);
}

.prog:hover .prog__img {
  transform: scale(1.04);
}

.prog__cat {
  position: absolute;
  top: clamp(0.875rem, 0.75rem + 0.4vw, 1.25rem);
  left: clamp(0.875rem, 0.75rem + 0.4vw, 1.25rem);
  padding: 7px 15px;
  border-radius: var(--r-pill, 999px);
  font-size: 11px;
  font-weight: var(--w-semibold, 600);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.prog__body {
  padding: clamp(1.75rem, 1.4rem + 1.6vw, 2.875rem) clamp(1.5rem, 1.2rem + 1.4vw, 3rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(0.875rem, 0.7rem + 0.6vw, 1rem);
}

.prog__h {
  margin: 0;
  font-family: var(--font-display, serif);
  font-size: clamp(1.7rem, 1rem + 1.6vw, 2.4rem);
  line-height: 1.08;
}

.prog__t {
  margin: 0;
  font-size: clamp(0.9375rem, 0.9rem + 0.2vw, 0.96875rem);
  line-height: 1.65;
  max-width: 46ch;
}

.prog__foot {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 1rem + 1vw, 1.625rem);
  margin-top: 10px;
  padding-top: clamp(1.125rem, 1rem + 0.6vw, 1.375rem);
  border-top: 1px solid var(--progs-price-border, var(--border-1, #e5dacb));
}

.prog__price {
  font-family: var(--font-display, serif);
  font-size: clamp(1.75rem, 1rem + 0.9vw, 2.25rem);
  font-weight: var(--w-medium, 500);
  line-height: 1;
  letter-spacing: -0.02em;
}

.prog__price span {
  font-size: 0.42em;
  display: block;
  margin-top: 5px;
  font-family: var(--font-body, sans-serif);
  font-weight: var(--w-regular, 400);
  letter-spacing: 0;
}

.prog__link {
  margin-left: auto;
  font-size: 14px;
  font-weight: var(--w-semibold, 600);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  transition: gap var(--t-fast, 140ms) var(--ease-out, ease);
}

.prog__link:hover {
  gap: 13px;
}

/* Зигзаг: чётные карточки — фото справа (перенос эталона, строки 349-351).
   Разметка НЕ меняет порядок узлов (media всегда первый в DOM — доступность
   с клавиатуры/скринридером читает медиа перед текстом одинаково для всех
   карточек), только визуальный CSS order переставляет фото и тело местами. */
.prog:nth-child(even) .prog__media {
  order: 2;
}

.prog:nth-child(even) .prog__body {
  order: 1;
}

/* ======================================================================
   ПЛАНШЕТНЫЙ ДИАПАЗОН 700-960 — перенос эталона (строки 542-549): фото
   получает потолок высоты (не пол-экрана впустую), пропорция уже,
   структура разворота (фото+текст) сохраняется — сетка не разваливается
   в столбец раньше времени (контрактная точка doc 11, урок пилота unona:
   "плашки огромные, фото разворачивается на весь экран").
   ====================================================================== */
@media (max-width: 960px) {
  .prog {
    grid-template-columns: 0.9fr 1.1fr;
  }

  .prog__media {
    min-height: 0;
    max-height: 340px;
  }

  .prog__body {
    padding: clamp(1.5rem, 1.2rem + 1vw, 2.125rem) clamp(1.25rem, 1rem + 1vw, 1.875rem);
  }
}

/* ======================================================================
   МОБИЛЬНАЯ ЛИНЕАРИЗАЦИЯ 700 и ниже — перенос эталона (строки 604-611):
   честный столбец, фото сверху (order 1 принудительно для ОБЕИХ чётности —
   зигзаг имеет смысл только в две колонки), текст снизу, цена/ссылка
   переносятся по ширине без горизонтального скролла.
   ====================================================================== */
@media (max-width: 700px) {
  .progs-list {
    gap: clamp(1.25rem, 1rem + 1vw, 1.5rem);
  }

  .prog,
  .prog:nth-child(even) {
    grid-template-columns: 1fr;
  }

  .prog__media {
    min-height: 220px;
    max-height: none;
    order: 1 !important;
  }

  .prog__body {
    order: 2 !important;
    padding: clamp(1.5rem, 1.3rem + 0.8vw, 1.875rem) clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  }

  .prog__foot {
    flex-wrap: wrap;
    gap: 1rem;
  }

  .prog__link {
    margin-left: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .prog,
  .prog__img {
    transition: none;
  }
}

/* =========================================================================
   styles/progs/marina.css — стиль «Программы» темы Marina
   Ровно один класс-модификатор .progs--marina (DEC-001 п.4/5).
   Специфичность: одна ступень поверх .progs-list. Без !important.

   Перенос секции .progs эталона (eskiz-glavnaya.html строки 316-351) —
   карточка на var(--bg-2), тень поднимается на hover, бейдж категории —
   полупрозрачная плашка linen с backdrop-filter (fallback непрозрачный).
   ========================================================================= */

.progs--marina .prog {
  background: var(--bg-2, #fbf8f2);
  box-shadow: var(--shadow-2);
  transition: transform var(--t-normal, 240ms) var(--ease-out, ease),
              box-shadow var(--t-normal, 240ms) var(--ease-out, ease);
}

.progs--marina .prog:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-4);
}

.progs--marina .prog__cat {
  background: color-mix(in srgb, var(--linen, #f4eee6) 88%, transparent);
  color: var(--fg-brand, #9c6957);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .progs--marina .prog__cat {
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
}

.progs--marina .prog__h {
  color: var(--fg-1, #111);
  font-weight: var(--w-regular, 400);
}

.progs--marina .prog__t {
  color: var(--fg-2, #555);
}

.progs--marina .prog__foot {
  border-top-color: var(--border-1, #e5dacb);
}

.progs--marina .prog__price {
  color: var(--fg-1, #111);
}

.progs--marina .prog__price span {
  color: var(--fg-brand, #9c6957);
}

.progs--marina .prog__link {
  color: var(--fg-brand, #9c6957);
}

@media (prefers-reduced-motion: reduce) {
  .progs--marina .prog {
    transition: none;
  }
}

/* =========================================================================
   bases/quote_block/base.css — структурный слой основы «Цитата»
   Специфичность: только базовый класс .quote-block (DEC-001 п.5). Регулируемое
   — через var() (DEC-001 п.12). Знак кавычки — крупный дисплейный элемент:
   размер задан clamp() между границами-токенами, плавно с шириной вьюпорта,
   без скачка на брейкпоинте (дополнение Владельца по резине — герой,
   TASK-P3-CONTENT-1). Брейкпоинтов в этой основе нет — раскладка не меняет
   структуру (одна колонка при любой ширине), только внутренние размеры.
   ========================================================================= */

.quote-block {
  position: relative;
  margin: 0;
  max-width: var(--quote-block-max-width, 60ch);
}

.quote-block__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-4, 1rem);
  padding-inline-start: var(--s-2, 0.5rem);
}

/* Раскладка с media (TASK-ETALON-LIB-1, эталон design/etalon/
   eskiz-glavnaya.html «5. О СТУДИИ / ЦИТАТА») — две колонки от 700
   (та же структурная точка, что герой этой ячейки, см. bases/hero/base.css
   докстрока), одна колонка ниже (фото уже не помещается рядом с текстом
   читаемо). Модификатор — присутствие props.media (base.html), не класс
   стиля: композиция text+media структурна, палитру/тени даёт слой style. */
.quote-block--has-media {
  max-width: none;
}

@media (min-width: 700px) {
  .quote-block--has-media {
    display: grid;
    grid-template-columns: 1.3fr 0.7fr;
    gap: var(--s-12, 3rem);
    align-items: center;
  }
  .quote-block--has-media .quote-block__body {
    max-width: var(--quote-block-max-width, 60ch);
  }
}

.quote-block__media {
  position: relative;
}

.quote-block__photo-image {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  display: block;
  border-radius: var(--quote-block-media-radius, var(--r-xl, 1.375rem));
  overflow: hidden;
}

.quote-block__placeholder {
  background: linear-gradient(135deg, var(--blush-200, #ddd), var(--blush-400, #999));
}

.quote-block__placeholder--sage {
  background: linear-gradient(135deg, var(--sage-100, #ddd), var(--sage-500, #7B8A6E));
}

.quote-block__placeholder--gilt {
  background: linear-gradient(135deg, var(--gilt-300, #ddd), var(--gilt-500, #B8956A));
}

@media (max-width: 699px) {
  .quote-block--has-media .quote-block__media {
    order: -1;
    max-width: min(320px, 80%);
    margin-inline: auto;
  }
}

.quote-block__mark {
  display: block;
  line-height: 1;
  font-family: var(--font-display, serif);
  /* Резиновый калибр знака: от t-h1 до t-display-l, без фиксированного
     скачка — растёт вместе с шириной контейнера, не вьюпорта, чтобы
     компоновка внутри узкой карточки не переполнялась (dec-001 п.12,
     токены как границы clamp). */
  font-size: var(--quote-block-mark-size, clamp(var(--t-h1, 2.25rem), 6vw + 1rem, var(--t-display-l, 3.75rem)));
  color: var(--fg-brand, #9C6957);
  opacity: var(--quote-block-mark-opacity, 0.6);
}

.quote-block__text {
  margin: 0;
  padding: 0;
  border: none;
}

.quote-block__text p {
  margin: 0;
  font-size: var(--t-body, 1rem);
  line-height: var(--lh-normal, 1.5);
  color: var(--fg-1, #111);
}

.quote-block__author {
  display: flex;
  align-items: center;
  gap: var(--s-3, 0.75rem);
}

.quote-block__avatar {
  flex: none;
  width: var(--quote-block-avatar-size, 2.75rem);
  height: var(--quote-block-avatar-size, 2.75rem);
  border-radius: var(--r-pill, 999px);
  overflow: hidden;
}

.quote-block__avatar-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.quote-block__avatar-placeholder {
  display: block;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, var(--blush-200, #ddd), var(--blush-400, #999));
}

.quote-block__author-text {
  display: flex;
  flex-direction: column;
}

.quote-block__author-name {
  font-weight: var(--w-medium, 500);
  color: var(--fg-1, #111);
}

.quote-block__author-role {
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-2, #555);
}

/* =========================================================================
   styles/quote_block/marina-editorial.css — стиль «Цитата» по эскизу
   Ровно один класс-модификатор .quote-block--marina-editorial (DEC-001
   п.4/5). Специфичность: одна ступень поверх .quote-block. Без !important.

   ИСТОЧНИК КОДА — design/etalon/eskiz-glavnaya.html, секция «5. О СТУДИИ /
   ЦИТАТА» (DEC-003 unona-site, TASK-ETALON-LIB-1): крупная кавычка-глиф с
   отступом (перекрывает текст сверху-слева, --fl-mark), арочное фото справа
   (border-radius сверху большой, снизу обычный), подпись с камеей (уже
   quote-block__avatar основы — здесь только типографика).
   ========================================================================= */

.quote-block--marina-editorial {
  max-width: none;
}

.quote-block--marina-editorial .quote-block__body {
  position: relative;
  padding-top: var(--s-12, 3rem);
  padding-inline-start: 0;
  max-width: 60ch;
}

.quote-block--marina-editorial .quote-block__mark {
  position: absolute;
  top: calc(-1 * var(--s-10, 2.5rem));
  left: calc(-1 * var(--s-3, 0.75rem));
  z-index: 0;
  font-family: var(--font-display);
  font-size: var(--fl-mark, clamp(6.875rem, 4.5739rem + 10.2273vw, 12.5rem));
  line-height: 0.7;
  color: var(--blush-200);
  opacity: 1;
}

.quote-block--marina-editorial .quote-block__text {
  position: relative;
  z-index: 1;
}

.quote-block--marina-editorial .quote-block__text p {
  font-family: var(--font-display);
  font-weight: var(--w-light);
  font-size: clamp(1.7rem, 1rem + 1.9vw, 2.6rem);
  line-height: 1.32;
  color: var(--cocoa-700);
  letter-spacing: -0.01em;
}

.quote-block--marina-editorial .quote-block__text p em {
  font-style: italic;
  color: var(--fg-brand);
}

.quote-block--marina-editorial .quote-block__author {
  position: relative;
  z-index: 1;
  margin-top: var(--s-8, 2rem);
}

.quote-block--marina-editorial .quote-block__avatar {
  width: 3.5rem;
  height: 3.5rem;
  box-shadow: 0 0 0 1px var(--border-2);
}

.quote-block--marina-editorial .quote-block__author-name {
  font-family: var(--font-display);
  font-size: var(--fl-17, clamp(1.0625rem, 0.9858rem + 0.3409vw, 1.25rem));
  color: var(--fg-1);
}

.quote-block--marina-editorial .quote-block__author-role {
  font-family: var(--font-body);
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-2);
}

/* --- Медиа: арочное фото (border-radius большой сверху, обычный снизу) --- */

.quote-block--marina-editorial .quote-block__photo-image {
  border-radius: 200px 200px var(--r-lg, 22px) var(--r-lg, 22px);
  box-shadow: var(--shadow-3);
}

@media (max-width: 699px) {
  .quote-block--marina-editorial .quote-block__mark {
    font-size: 130px;
    top: calc(-1 * var(--s-8, 2rem));
  }
}

/* =========================================================================
   bases/dirs/base.css — структурный слой основы «Направления»
   Специфичность: только базовый класс .dirs-row (DEC-001 п.5).

   Резина (DEC-001 п.14): clamp()/var(), брейкпоинты — только контрактные
   точки doc 11 (960/700), перенесены из эталона (строки 556-558/618-620)
   один в один, включая паттерн сироты: на планшете 2 колонки, последняя
   плитка (нечётный остаток из 3) растягивается на всю строку — не остаётся
   одинокой узкой колонкой у левого края.

   ВНИМАНИЕ (задокументированный инцидент): clamp() — с пробелами вокруг
   +/- операторов, иначе браузер отбрасывает правило целиком.
   ========================================================================= */

.dirs-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.125rem, 0.9rem + 1vw, 1.625rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

.dir-item {
  display: contents;
}

.dir {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  border-radius: var(--dirs-radius, 22px);
  overflow: hidden;
  min-height: var(--dirs-min-h, 420px);
  text-decoration: none;
  color: inherit;
  transition: transform var(--t-normal, 240ms) var(--ease-out, ease),
              box-shadow var(--t-normal, 240ms) var(--ease-out, ease);
}

.dir__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.dir__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 600ms var(--ease-out, ease);
}

.dir:hover .dir__bg img {
  transform: scale(1.05);
}

/* Градиентная подложка для читаемости текста поверх фото (перенос эталона
   строка 398-399) — цвет градиента var()-переменная, тон задаёт стиль. */
.dir::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--dirs-scrim, linear-gradient(180deg, transparent 30%, rgba(42, 30, 26, 0.28) 55%, rgba(42, 30, 26, 0.82)));
}

.dir__body {
  position: relative;
  z-index: 2;
  padding: clamp(1.5rem, 1.25rem + 1vw, 2.125rem) clamp(1.25rem, 1.1rem + 0.6vw, 1.875rem);
}

.dir__n {
  font-family: var(--font-display, serif);
  font-style: italic;
  font-size: 18px;
  margin-bottom: 8px;
}

.dir__h {
  margin: 0 0 10px;
  font-family: var(--font-display, serif);
  font-size: clamp(1.3rem, 1rem + 0.9vw, 1.6875rem);
  line-height: 1.1;
}

.dir__t {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.55;
}

.dir__link {
  font-size: 13px;
  font-weight: var(--w-semibold, 600);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  letter-spacing: 0.03em;
  border-bottom: 1px solid var(--dirs-link-border, rgba(244, 238, 230, 0.4));
  padding-bottom: 3px;
  transition: gap var(--t-fast, 140ms) var(--ease-out, ease),
              border-color var(--t-fast, 140ms) var(--ease-out, ease);
}

.dir:hover .dir__link {
  gap: 13px;
}

/* ======================================================================
   ПЛАНШЕТ 700-960 — перенос эталона (строки 556-558): 2 колонки, сетка
   не разваливается в столбец раньше времени; ТРЕТЬЯ плитка (сирота при
   нечётном остатке из 3 карточек) растягивается на всю строку, не остаётся
   узкой колонкой у левого края — паттерн сирот (задание ячейки п.2 dirs).
   ====================================================================== */
@media (max-width: 960px) {
  .dirs-row {
    grid-template-columns: 1fr 1fr;
  }

  /* .dir-item — display:contents (не создаёт своего бокса), фактический
     grid-item — вложенный .dir; grid-column ставится на НЕГО, не на
     .dir-item (правило на контейнере без бокса не применилось бы). */
  .dir-item:last-child .dir {
    min-height: 300px;
    grid-column: 1 / -1;
  }
}

/* ======================================================================
   МОБИЛЬНАЯ ЛИНЕАРИЗАЦИЯ 700 и ниже — перенос эталона (строки 618-620):
   честный столбец, сирота больше не растягивается (весь ряд уже 1 колонка).
   ====================================================================== */
@media (max-width: 700px) {
  .dirs-row {
    grid-template-columns: 1fr;
    gap: clamp(1rem, 0.85rem + 0.6vw, 1.125rem);
  }

  .dir-item:last-child .dir {
    grid-column: auto;
    min-height: 340px;
  }

  .dir {
    min-height: 340px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .dir,
  .dir__bg img,
  .dir__link {
    transition: none;
  }
}

/* =========================================================================
   styles/dirs/marina.css — стиль «Направления» темы Marina
   Ровно один класс-модификатор .dirs--marina (DEC-001 п.4/5).
   Специфичность: одна ступень поверх .dirs-row. Без !important.

   Перенос секции .dirs эталона (eskiz-glavnaya.html строки 385-410) —
   текст поверх фото на linen (светлый, читается на тёмном градиенте-скриме
   base.css), номер и подчёркивание — акцент blush.
   ========================================================================= */

/* Тёплый италик-акцент ключевого слова заголовка секции (Пачка C, п.2;
   эталон design/etalon/eskiz-glavnaya.html .dirs__title em{font-style:
   italic;color:var(--blush-500)}, строка 389). Заголовок рендерится общим
   слотом section_header (bases/section_header/base.html, класс
   .section-header__title) внутри того же <section>, что и .dirs--marina —
   селектор скопирован буквально с прецедента styles/stats_strip/
   marina-dark.css (.section:has(> .container > .stats-strip--marina-dark)
   .section-header__title em), там же паттерн для figures. content.yaml уже
   несёт `<em>дальше</em>` (строка 227) — правки данных не требуется. */
.section:has(> .container > .dirs--marina) .section-header__title em {
  font-style: italic;
  color: var(--blush-500);
}

.dirs--marina .dir {
  box-shadow: var(--shadow-2);
}

.dirs--marina .dir:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-4);
}

.dirs--marina .dir__body {
  color: var(--linen, #f4eee6);
}

.dirs--marina .dir__n {
  color: var(--blush-200, #e8c9bd);
}

.dirs--marina .dir__h {
  color: var(--linen, #f4eee6);
}

.dirs--marina .dir__t {
  color: rgba(244, 238, 230, 0.82);
}

.dirs--marina .dir__link {
  color: var(--linen, #f4eee6);
}

.dirs--marina .dir:hover .dir__link {
  border-color: var(--blush-200, #e8c9bd);
}

@media (prefers-reduced-motion: reduce) {
  .dirs--marina .dir {
    transition: none;
  }
}

/* =========================================================================
   bases/faq_accordion/base.css — структурный слой основы «FAQ-аккордеон»
   Специфичность: только базовый класс .faq-accordion (DEC-001 п.5).
   Раскрытие по высоте — планка прототипа design/reference/prototype-
   breakdown.md, раздел 1: transition: max-height 420ms var(--ease-out),
   opacity 240ms var(--ease-out). Высоту в px выставляет behavior.js
   (panel.scrollHeight) — CSS только анимирует переход между значениями.
   ========================================================================= */

.faq-accordion__heading {
  margin: 0 0 var(--s-6, 1.5rem);
  font-size: var(--t-h2, 1.75rem);
  color: var(--fg-1, #111);
}

/* Композиция «липкий аside + аккордеон» (TASK-ETALON-LIB-2, перенос
   .faq__grid эталона eskiz-glavnaya.html строки 915-940) СОБИРАЕТСЯ НЕ
   ВНУТРИ этой основы, а на уровне страницы — тем же приёмом, что и «pains»
   (TASK-ETALON-LIB-1, sibling-ячейка): SectionSchema.sticky_split:true +
   heading{eyebrow,title,lede,cta} → section_header (props.cta уже несёт
   кнопку «Задать вопрос в WhatsApp», bases/section_header/base.html) в
   .section-sticky-split__header, эта основа (self_wrapped:false, только
   список) — в .section-sticky-split__content (layout/base.css). Дублировать
   eyebrow/note/cta ВНУТРИ faq_accordion было бы повтором уже построенного
   sibling-ячейкой механизма (I7 — экономия, не два конкурирующих способа
   получить одно и то же); композиция — demo/index.html этой основы,
   зеркалит bases/pains/demo/index.html буквально.

   Разделители аккордеона (перенос .qa эталона, строки 424-440): рамка
   ПЕРЕД первым пунктом переносится на список целиком (border-top на
   .faq-accordion__list) — граница КАЖДОГО пункта (border-bottom, ниже)
   создаёт линию перед первым и после последнего без двойной линии между
   соседними пунктами. */
.faq-accordion__list {
  border-top: 1px solid var(--faq-accordion-border, var(--border-1, #e5dacb));
  display: flex;
  flex-direction: column;
  gap: var(--faq-accordion-item-gap, var(--s-3, 0.75rem));
}

.faq-accordion__item {
  border-bottom: 1px solid var(--faq-accordion-border, var(--border-1, #e5dacb));
}

.faq-accordion__item-heading {
  margin: 0;
}

.faq-accordion__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4, 1rem);
  /* TASK-RHYTHM-MATCH (2026-07-08): было var(--s-4,1rem)=16px (32px
     суммарно) — эталон design/etalon/eskiz-glavnaya.html .qa__q
     padding:28px 4px (56px суммарно по блоку). При 3 вопросах секции —
     основной вклад в дефицит высоты faq (-63px из -119px до починки
     раздела padding-block секции, замер этой ячейки). Перенесено буквально
     (I2). */
  padding-block: var(--faq-accordion-trigger-padding-y, 1.75rem);
  background: none;
  border: none;
  text-align: left;
  font: inherit;
  color: var(--fg-1, #111);
  cursor: pointer;
}

/* Видимый индикатор фокуса — НЕ подавлен (doc 31: обязателен). */
.faq-accordion__trigger:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 2px;
}

.faq-accordion__question {
  font-size: var(--t-h4, 1.125rem);
  font-weight: var(--w-medium, 500);
}

/* K1.5 (DEC-002)/находка audit-01 пачка E: визуальный глиф ~18-20px без
   видимой мишени — клик по всей строке спасал функционально, но иконка
   сама читалась как голый глиф без кликаемой площади. ::before расширяет
   видимую/кликаемую площадь до 44×44 (прозрачный hit-area), сам глиф
   (--faq-accordion-toggle-size) остаётся прежнего визуального размера
   внутри, центрированный. */
.faq-accordion__toggle {
  position: relative;
  flex: 0 0 auto;
  width: var(--faq-accordion-toggle-size, 1.25rem);
  height: var(--faq-accordion-toggle-size, 1.25rem);
}

.faq-accordion__toggle::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 44px;
  height: 44px;
  border-radius: var(--r-pill, 999px);
}

.faq-accordion__toggle-icon {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity var(--t-fast, 140ms) var(--ease-out, ease),
              transform var(--t-fast, 140ms) var(--ease-out, ease);
}

/* ± меняется состоянием: closed показывает plus, opened — minus. Оба
   слоя всегда в DOM (decorative), CSS переключает видимость по классу
   is-opened на .accordion__item — расхождение класса и визуала
   исключено структурно (не JS-подмена innerHTML). */
.faq-accordion__toggle-icon--plus::before,
.faq-accordion__toggle-icon--minus::before {
  content: "";
  position: absolute;
  background: currentColor;
  border-radius: 1px;
}

.faq-accordion__toggle-icon--plus::before {
  /* горизонтальная черта */
  width: 100%;
  height: 2px;
  top: 50%;
  transform: translateY(-50%);
}

.faq-accordion__toggle-icon--plus::after {
  content: "";
  position: absolute;
  width: 2px;
  height: 100%;
  left: 50%;
  transform: translateX(-50%);
  background: currentColor;
  border-radius: 1px;
}

.faq-accordion__toggle-icon--minus::before {
  width: 100%;
  height: 2px;
  top: 50%;
  transform: translateY(-50%);
}

.faq-accordion__toggle-icon--minus {
  opacity: 0;
  transform: scale(0.6);
}

.is-opened .faq-accordion__toggle-icon--plus {
  opacity: 0;
  transform: scale(0.6);
}

.is-opened .faq-accordion__toggle-icon--minus {
  opacity: 1;
  transform: scale(1);
}

.faq-accordion__panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height var(--t-slow, 420ms) var(--ease-out, cubic-bezier(0.22, 1, 0.36, 1)),
              opacity var(--t-normal, 240ms) var(--ease-out, cubic-bezier(0.22, 1, 0.36, 1));
  opacity: 0;
}

.is-opened .faq-accordion__panel {
  opacity: 1;
}

.faq-accordion__answer {
  margin: 0 0 var(--s-4, 1rem);
  color: var(--fg-2, #555);
  max-width: 65ch;
}

/* Деградация без JS — честный зафиксированный компромисс (I7, детали и
   альтернативы см. acceptance.md, раздел "Деградация без JS"). <noscript>
   не может скрыть родного соседа средствами чистого CSS без :has(), поэтому
   при выключенном JS видны ОБА списка: основной (кнопки неактивны, панели
   статично закрыты) и <details>/<summary> fallback (реально раскрывается
   браузером). Дублирование вопросов без JS — принятая цена простоты,
   не молчаливый дефект. */
.faq-accordion__list--fallback {
  margin-top: var(--s-4, 1rem);
}

.faq-accordion__details {
  border-bottom: 1px solid var(--faq-accordion-border, var(--border-1, #e5dacb));
  padding-block: var(--s-2, 0.5rem);
}

.faq-accordion__summary {
  cursor: pointer;
  font-weight: var(--w-medium, 500);
  padding-block: var(--s-2, 0.5rem);
}

@media (prefers-reduced-motion: reduce) {
  .faq-accordion__panel,
  .faq-accordion__toggle-icon {
    transition: none;
  }
}

/* =========================================================================
   styles/faq_accordion/marina-dark.css — стиль «Частые вопросы на тёмном»
   темы Marina. Ровно один класс-модификатор .faq-accordion--marina-dark
   (DEC-001 п.4/5). Специфичность: одна ступень поверх .faq-accordion,
   без !important.

   Решение Владельца (2026-07-09): в хвосте страниц три тёмных блока подряд
   (CTA + юр-плашка + подвал ≈ 970px одного цвета) сливались в одну массу.
   Тон перераспределён: ЧаВо забирает тёмную палитру (бывшую у CTA), секция
   записи становится светлой (cta_block--marina-light), подвал остаётся
   тёмным. Ритм страницы: … тёмное ЧаВо → светлая запись → тёмный хвост.

   Приём покраски — как у stats_strip/marina-dark.css: сам виджет НЕ
   self_wrapped, фон и палитру несёт секция-обёртка через `:has()`. Цвета
   вопросов/ответов/границ/иконки НЕ переопределяются селекторами поштучно:
   основа (bases/faq_accordion/base.css) читает токены --fg-1/--fg-2/
   --faq-accordion-border, а иконка ± рисуется currentColor — достаточно
   переопределить токены на корне виджета, и вся начинка перекрашивается
   согласованно (DEC-001 п.12: регулируемое — только var()).
   ========================================================================= */

/* Палитра секции-обёртки (фон + цвет по умолчанию). Селектор `.section:has()`
   — тот же приём, что stats_strip/marina-dark.css; FAQ живёт в секции
   sticky-split (шапка слева, список справа), поэтому потомок не прямой. */
.section:has(.faq-accordion--marina-dark) {
  background: var(--bg-inverse, var(--cocoa-900, #2A1E1A));
  color: var(--fg-on-dark, #F4EEE6);
}

.section:has(.faq-accordion--marina-dark) .section-header__eyebrow {
  color: var(--blush-300);
}

.section:has(.faq-accordion--marina-dark) .section-header__title {
  color: var(--fg-on-dark, #F4EEE6);
}

/* Тёплый италик-акцент ключевого слова — светлее оттенок читается на
   cocoa-900 (тот же выбор blush-300, что у stats_strip/cta_block на тёмном). */
.section:has(.faq-accordion--marina-dark) .section-header__title em {
  color: var(--blush-300);
}

.section:has(.faq-accordion--marina-dark) .section-header__lede {
  color: var(--cocoa-200, #B09A91);
}

/* Начинка аккордеона — через токены основы, не поштучными селекторами. */
.faq-accordion--marina-dark {
  --fg-1: var(--fg-on-dark, #F4EEE6);            /* вопрос, иконка ± (currentColor) */
  --fg-2: var(--cocoa-200, #B09A91);             /* текст ответа */
  --fg-brand: var(--blush-300);                  /* открытый вопрос */
  --faq-accordion-border: rgba(244, 238, 230, 0.16);
}

.faq-accordion--marina-dark .faq-accordion__heading {
  font-family: var(--font-display);
  font-weight: var(--w-medium);
}

.faq-accordion--marina-dark .faq-accordion__question {
  font-family: var(--font-body);
}

/* Открытый вопрос — бренд-акцент, как в светлом стиле (там --fg-brand
   насыщенный, здесь переопределён на blush-300: на cocoa-900 читается). */
.faq-accordion--marina-dark .is-opened .faq-accordion__question {
  color: var(--fg-brand);
}

/* Кнопка «задать вопрос» в шапке секции остаётся фирменной (blush на
   тёмном читается), только подсветка фокуса приводится к светлому кольцу. */
.faq-accordion--marina-dark .faq-accordion__trigger:focus-visible {
  outline-color: var(--blush-300);
}

/* =========================================================================
   bases/booking_form/base.css — структурный слой основы «Форма записи».
   Специфичность: только базовый класс .booking-form (DEC-001 п.5).

   Резина (CLAUDE.md, обязательное требование): типографика/отступы —
   clamp() между токенами, поля ввода — width:100% контейнера. Одна колонка
   на ВСЕХ ширинах (решение ячейки, I7 — см. докстрока base.html): лид-форма
   не заводит структурный брейкпоинт ради второй колонки, задание этого не
   требовало. Ширина всей формы ограничена --booking-form-max-width для
   читаемости на широких экранах (форма не растягивается на всю .container).
   ========================================================================= */

.booking-form__inner {
  display: flex;
  flex-direction: column;
  gap: var(--booking-form-gap, clamp(1.25rem, 1rem + 1vw, 2rem));
  max-width: var(--booking-form-max-width, 30rem);
  margin-inline: auto;
  text-align: center;
}

/* --- Заголовок --- */

.booking-form__eyebrow {
  margin: 0 0 var(--s-2, 0.5rem);
  font-size: var(--t-eyebrow, 0.75rem);
  font-weight: var(--w-semibold, 600);
  letter-spacing: var(--ls-eyebrow, 0.18em);
  text-transform: uppercase;
  color: var(--fg-brand, #9C6957);
}

.booking-form__title {
  margin: 0 0 var(--s-2, 0.5rem);
  font-family: var(--font-display, serif);
  font-size: var(--fl-title-a, clamp(1.5rem, 1rem + 2vw, 2.25rem));
  color: var(--fg-1, #111);
}

.booking-form__lede {
  margin: 0;
  max-width: 55ch;
  margin-inline: auto;
  color: var(--fg-2, #555);
}

/* --- Форма: одна колонка, поля на всю ширину. --- */

.booking-form__form {
  display: flex;
  flex-direction: column;
  gap: var(--booking-form-field-gap, clamp(1rem, 0.85rem + 0.75vw, 1.5rem));
  text-align: left;
}

.booking-form__field {
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
  min-width: 0;
}

.booking-form__label {
  font-size: var(--t-body-s, 0.9375rem);
  font-weight: var(--w-medium, 500);
  color: var(--fg-1, #111);
}

.booking-form__input {
  width: 100%;
  box-sizing: border-box;
  padding: var(--s-3, 0.75rem) var(--s-4, 1rem);
  font: inherit;
  color: var(--fg-1, #111);
  background: var(--bg-2, #FBF8F2);
  border: 1px solid var(--border-1, #E5DACB);
  border-radius: var(--r-md, 8px);
}

.booking-form__input::placeholder {
  color: var(--fg-3, #8B6F65);
  opacity: 0.7;
}

.booking-form__input:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 2px;
}

/* Ошибка поля — видима словом (не только цветом рамки, доступность/
   дальтоники). Рамка меняет цвет ТОЛЬКО когда есть текст ошибки (aria-invalid
   проставляет behavior.js вместе с показом/скрытием параграфа). */
.booking-form__input[aria-invalid="true"] {
  border-color: var(--critical, #B5544A);
}

.booking-form__error {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--critical, #B5544A);
}

.booking-form__error[hidden] {
  display: none;
}

/* --- Согласие (чекбокс + ссылка на политику). --- */

.booking-form__field--consent {
  gap: var(--s-2, 0.5rem);
}

.booking-form__consent-label {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2, 0.5rem);
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-1, #111);
  cursor: pointer;
  text-align: left;
}

.booking-form__checkbox {
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  margin-top: 0.15rem;
  accent-color: var(--fg-brand, #9C6957);
  cursor: pointer;
}

.booking-form__checkbox:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 2px;
}

.booking-form__link {
  color: var(--fg-brand, #9C6957);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

.booking-form__link:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 2px;
}

/* --- Кнопка отправки. --- */

.booking-form__submit {
  width: 100%;
  padding: var(--s-3, 0.75rem) var(--s-6, 1.5rem);
  font: inherit;
  font-weight: var(--w-semibold, 600);
  color: var(--fg-on-dark, #FBF8F2);
  background: var(--fg-brand, #9C6957);
  border: none;
  border-radius: var(--booking-form-radius, var(--r-md, 8px));
  cursor: pointer;
  transition: transform var(--t-fast, 140ms) var(--ease-out, ease),
              opacity var(--t-fast, 140ms) var(--ease-out, ease);
}

.booking-form__submit:hover {
  transform: translateY(-1px);
}

.booking-form__submit:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 3px;
}

.booking-form__submit:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
}

/* --- Статус отправки (aria-live="polite" — успех/отправка/ошибка). --- */

.booking-form__status {
  margin: 0;
  min-height: 1.2em; /* резервирует строку — текст не "прыгает" макет при появлении */
  font-size: var(--t-body-s, 0.9375rem);
  font-weight: var(--w-medium, 500);
  color: var(--fg-2, #555);
  text-align: center;
}

.booking-form__status:empty {
  min-height: 0;
}

.booking-form__status[data-state="error"] {
  color: var(--critical, #B5544A);
}

.booking-form__status[data-state="success"] {
  color: var(--positive, #7B8A6E);
}

/* --- Фолбэк-кнопка WhatsApp (появляется только при ошибке отправки). --- */

.booking-form__wa-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: var(--s-2, 0.5rem) var(--s-4, 1rem);
  font: inherit;
  font-weight: var(--w-medium, 500);
  color: var(--fg-brand, #9C6957);
  background: transparent;
  border: 1px solid var(--border-2, #D8C7B5);
  border-radius: var(--r-md, 8px);
  text-decoration: none;
}

.booking-form__wa-fallback[hidden] {
  display: none;
}

.booking-form__wa-fallback:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 2px;
}

.booking-form__noscript-note {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
}

/* --- Оговорка под формой (юр-рамка). --- */

.booking-form__legal-note {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
  max-width: 60ch;
  margin-inline: auto;
}

@media (prefers-reduced-motion: reduce) {
  .booking-form__submit {
    transition: none;
  }
}

/* =========================================================================
   styles/booking_form/marina-glass.css — «Форма записи» манеры «Мягкое
   стекло» (DEC-001 п.4/5: ровно один класс-модификатор
   .booking-form--marina-glass, тот же приём, что income_calculator/
   comparison_table/price_table/steps_timeline/filter_grid).

   Специфичность: одна ступень поверх .booking-form (базовый класс
   присутствует на корне <section> ОДНОВРЕМЕННО с модификатором —
   self_wrapped:true, см. base.html). Без !important.

   Стекло — на самой форме целиком (единственная содержательная панель
   виджета, аналог income_calculator__result), не на отдельных полях
   ввода (K18: стекло на каждом мелком элементе формы шумит и мешает
   читать ввод). Fallback непрозрачный ПЕРВЫМ (K17).
   ========================================================================= */

.booking-form--marina-glass .booking-form__eyebrow {
  color: var(--fg-brand, #9C6957);
}

.booking-form--marina-glass .booking-form__title {
  font-family: var(--font-display, serif);
}

.booking-form--marina-glass .booking-form__form {
  padding: clamp(1.25rem, 1rem + 1.2vw, 2rem);
  border-radius: var(--r-xl, 22px);
  /* Fallback ПЕРВЫМ (K17). */
  background: var(--bg-2, #FBF8F2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18),
              var(--op-shadow-2, var(--shadow-2));
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .booking-form--marina-glass .booking-form__form {
    background: rgba(251, 248, 242, 0.62);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

.booking-form--marina-glass .booking-form__input {
  background: rgba(255, 255, 255, 0.55);
  border-color: rgba(255, 255, 255, 0.4);
}

.booking-form--marina-glass .booking-form__submit {
  box-shadow: var(--op-shadow-1, var(--shadow-1));
}

/* =========================================================================
   bases/cta_block/base.css — структурный слой основы «CTA-блок»
   Специфичность: только базовый класс .cta-block (DEC-001 п.5).

   СОГЛАСОВАННОЕ ВЫРАВНИВАНИЕ (урок арт-ворот пилота unona — смещение
   CTA-текста от кнопок было дефектом): заголовок, подзаголовок и ряд
   действий лежат в ОДНОМ .cta-block__inner и наследуют ОДНО значение
   --cta-block-align через text-align + align-items — рассинхрон между
   текстом и кнопками структурно невозможен, потому что оба используют
   один и тот же токен выравнивания, не два независимых свойства.

   Резина (FLG-003): отступы и ширина — clamp()/var(), без брейкпоинтов.
   ========================================================================= */

.cta-block {
  padding-block: var(--cta-block-section-padding-y, clamp(var(--s-12, 3rem), 2rem + 3vw, var(--s-20, 5rem)));
  text-align: var(--cta-block-align, center);
}

/* K1.2/S1 (DEC-002)/находка audit-01 пачка B: стопка двух кнопок на 360
   давала РАЗНУЮ ширину (primary ≈full, secondary — узкая пилюля) — тот же
   корень FLG-011, что service_card. Тот же приём S1 (донор service_card):
   container-type:inline-size на .cta-block__inner, @container ниже
   порога переключает .cta-block__actions на column и обе кнопки на
   width:100% — единообразно, не авто-шириной. */
.cta-block__inner {
  display: flex;
  flex-direction: column;
  align-items: var(--cta-block-align, center);
  gap: var(--s-4, 1rem);
  max-width: var(--cta-block-max-width, 40rem);
  margin-inline: auto;
  container-type: inline-size;
  container-name: cta-block-inner;
}

/* Камея (TASK-ETALON-LIB-2, перенос .book__cameo эталона строки 455-457) —
   decorative circle above the title, structural sizing here, color/ring
   shadow is style-layer. */
.cta-block__cameo {
  width: var(--cta-block-cameo-size, 4.875rem);
  height: var(--cta-block-cameo-size, 4.875rem);
  border-radius: 50%;
  overflow: hidden;
}

.cta-block__cameo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cta-block__eyebrow {
  margin: 0;
}

.cta-block__title {
  margin: 0;
  font-family: var(--font-display, serif);
  /* TASK-RHYTHM-MATCH (2026-07-08): было clamp(1.75rem,...,2.75rem)
     (28->44px) — эталон design/etalon/eskiz-glavnaya.html .book__title
     заметно крупнее (clamp(2.2rem,1rem + 3vw,3.6rem), 35.2->57.6px) —
     секция «Запись» финальный конверсионный аккорд, самый насыщенный
     заголовок страницы (докстрока эталона, раздел «8. ЗАПИСЬ»). Перенесено
     буквально (I2), не Utopia-калиброванный по 360/1240 в эталоне самом —
     клампу оставлен как есть, без пересчёта на общую шкалу. */
  font-size: clamp(2.2rem, 1rem + 3vw, 3.6rem);
  color: var(--fg-1, #111);
}

.cta-block__subtitle {
  margin: 0;
  color: var(--fg-2, #555);
  max-width: 36rem;
}

.cta-block__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: var(--cta-block-align, center);
  gap: var(--s-4, 1rem);
  margin-block-start: var(--s-2, 0.5rem);
  /* Hover-резерв (TASK-GLASS-CONTENT, разведка корня, баг «в»): кнопки
     .cta-block__action поднимаются на hover (translateY) и/или растят
     box-shadow (стили marina/marina-dark/marina-glass) — без запаса ряд
     действий стоит вплотную к нижнему краю .cta-block__inner, который
     совпадает с padding-block секции (.cta-block, self_wrapped:true —
     единственный отступ от края секции, layout/base.css обнуляет верхний
     .section.padding-block для self_wrapped-блоков). Подъём/тень крайней
     по вертикали кнопки визуально резался границей секции. Паддинг-запас
     снизу — тем же приёмом, что hover-резерв карточек библиотеки. */
  padding-bottom: var(--s-2, 0.5rem);
}

.cta-block__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-4, 1rem) var(--s-8, 2rem);
  border-radius: var(--r-pill, 999px);
  font-weight: var(--w-medium, 500);
  text-decoration: none;
  white-space: nowrap;
}

.cta-block__action--primary {
  background: var(--fg-brand, #9C6957);
  color: var(--fg-on-dark, #fff);
}

.cta-block__action--secondary {
  background: transparent;
  color: var(--fg-1, #111);
  border: 1px solid var(--border-strong, #8B6F65);
}

/* K1.2 (DEC-002): ниже порога — обе кнопки в столбик, КАЖДАЯ на 100%
   ширины родителя (не авто-шириной ступенчатыми обрубками). Порог
   320px — тот же, что service_card (карточка уже сжата настолько, что
   двум кнопкам auto-шириной в ряд тесно). */
@container cta-block-inner (max-width: 320px) {
  .cta-block__actions {
    flex-direction: column;
    align-items: stretch;
  }

  .cta-block__action {
    width: 100%;
  }
}

/* =========================================================================
   styles/cta_block/marina-light.css — стиль «Запись на светлом фоне» темы
   Marina. Ровно один класс-модификатор .cta-block--marina-light (DEC-001
   п.4/5). Специфичность: одна ступень поверх .cta-block, без !important.

   Решение Владельца (2026-07-09): тёмный хвост страниц (CTA + юр-плашка +
   подвал ≈ 970px одного cocoa-900) сливался в одну массу. Тон
   перераспределён: секция записи становится СВЕТЛОЙ, тёмную палитру
   забирает ЧаВо (faq_accordion--marina-dark), подвал остаётся тёмным.

   Отличие от `cta_block/marina.css` (тонкий типографский слой без фона):
   здесь секция несёт СВОЙ светлый фон (linen) — иначе запись сливалась бы с
   кремовой канвой body и переставала читаться как отдельный блок между
   тёмным ЧаВо сверху и тёмным хвостом снизу. Аврора-градиенты — зеркало
   тёмного варианта, но приглушённые: на светлом те же плотности дают грязь.
   ========================================================================= */

.cta-block--marina-light {
  background: var(--linen, #F4EEE6);
  --aurora-a: radial-gradient(50% 60% at 20% 15%, rgba(210, 164, 146, 0.16), transparent 68%);
  --aurora-b: radial-gradient(46% 50% at 85% 85%, rgba(168, 181, 154, 0.12), transparent 70%);
}

/* Кольцо камеи — тёмное на светлом (зеркало rgba(244,238,230,.12) тёмного). */
.cta-block--marina-light .cta-block__cameo {
  box-shadow: 0 0 0 4px rgba(42, 30, 26, 0.08);
}

.cta-block--marina-light .cta-block__title {
  font-family: var(--font-display);
  font-weight: var(--w-medium);
  color: var(--fg-1, #2A1E1A);
}

/* Италик-акцент ключевого слова: на светлом фоне читается насыщенный
   бренд-тон (blush-300 тёмного варианта здесь был бы блёклым). */
.cta-block--marina-light .cta-block__title em {
  font-style: italic;
  color: var(--fg-brand, #9C6957);
}

.cta-block--marina-light .cta-block__subtitle {
  font-family: var(--font-body);
  color: var(--fg-2, #555);
}

.cta-block--marina-light .cta-block__action {
  font-family: var(--font-body);
}

.cta-block--marina-light .cta-block__action--primary {
  background: var(--fg-brand, #9C6957);
  color: var(--fg-on-dark, #F4EEE6);
}

.cta-block--marina-light .cta-block__action--secondary {
  color: var(--fg-1, #2A1E1A);
  border-color: var(--border-2, #D8C7B5);
}

/* =========================================================================
   bases/disclaimer/base.css — структурный слой основы «Дисклеймер»
   Специфичность: только базовый класс .disclaimer (DEC-001 п.5).

   Сдержанный: мелкий кегль (t-caption), приглушённый цвет, компактные
   отступы — блок не конкурирует вниманием с контентом страницы.
   ========================================================================= */

.disclaimer {
  /* Разрыв ритма (арт-ворота 02, п.2 «секция записи склеилась со
     следующей»): предыдущая секция (cta_block, self_wrapped, свой
     padding-block снизу) не оставляла собственного видимого воздуха ПЕРЕД
     disclaimer — единственной границей была тонкая линия border-block-start
     без запаса пространства над ней, читалось как продолжение той же
     полосы. padding-block-start отдельно увеличен (не общий --s-6 на обе
     стороны) — низ остаётся компактным (дисклеймер не должен тянуть
     страницу), верх получает явный вдох перед линией-разделителем. */
  padding-block-start: var(--disclaimer-padding-top, var(--s-10, 2.5rem));
  padding-block-end: var(--s-6, 1.5rem);
  background: var(--disclaimer-bg, var(--bg-2, #FBF8F2));
  border-block-start: 1px solid var(--border-1, #E5DACB);
}

/* K7.3 (DEC-002)/находка audit-01 пачка O: на 1600 строка тянулась почти
   во всю ширину контейнера (~110 символов в одну линию) — max-width
   ограничивает читаемую меру. K8.4: выравнивание единообразно для ЛЮБОЙ
   полосы дисклеймера (нет отдельного правила текста по полосам — если
   сборщик центрирует один экземпляр и оставляет другой flush-left, это
   делается через .container/utility снаружи основы, не здесь; основа
   сама не создаёт разнобоя). */
.disclaimer__text {
  margin: 0;
  max-width: 66ch;
  font-size: var(--disclaimer-font-size, var(--t-caption, 0.8125rem));
  line-height: var(--lh-normal, 1.5);
  color: var(--disclaimer-fg, var(--fg-3, #8B6F65));
}

.disclaimer__line {
  display: inline;
}

/* =========================================================================
   styles/disclaimer/marina-dark.css — «Дисклеймер» тёмная юр.плашка темы
   Marina. Ровно один класс-модификатор .disclaimer--marina-dark (DEC-001
   п.4/5). Специфичность: одна ступень поверх .disclaimer. Без !important.

   Перенос секции .legal эталона projects/unona-site/design/etalon/
   eskiz-glavnaya.html (строки 483-488): узкая тёмная полоса cocoa-900 ПОД
   подвалом (не тот же тон, что сам подвал cocoa-700 — разведены по
   яркости, эталон намеренно контрастирует их), строки-предостережения в
   ряд с точкой-разделителем перед каждой (кроме первой), мелкий кегль.
   Базовый .disclaimer__line (base.css) — inline-текст с пробелом между
   строками; здесь переключаем контейнер на flex-строку с явным gap и
   декоративным разделителем — без изменения base.html/base.css (стиль не
   трогает разметку, DEC-001 п.1).
   ========================================================================= */

.disclaimer--marina-dark {
  background: var(--cocoa-900, #2a1e1a);
}

.disclaimer--marina-dark .disclaimer__text {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  max-width: none;
  font-family: var(--font-body);
  /* Контраст (Пачка C, п.3, scan-01.md): эталон .legal__in несёт БУКВАЛЬНО
     тот же rgba(244,238,230,.5) (design/etalon/eskiz-glavnaya.html строка
     484) — расчётный контраст текста поверх cocoa-900 ≈4.53:1, формально
     проходит WCAG AA (4.5:1) для мелкого текста, но впритык, без запаса
     (арбитр: «нижняя граница читаемости» для юр. строки). Отступление от
     буквы эталона (I7): заменено на непрозрачный токен var(--cocoa-200)
     (#B09A91) — уже используется как приглушённый-но-читаемый текст на
     cocoa-900 в этой же теме (styles/cta_block/marina-dark.css
     .cta-block__subtitle), расчётный контраст ≈6.07:1, уверенный запас
     над порогом AA. Токен, не хардкод (правило 1 брифа). */
  color: var(--cocoa-200, #B09A91);
}

.disclaimer--marina-dark .disclaimer__line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.disclaimer--marina-dark .disclaimer__line:not(:first-child)::before {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--blush-400, #b98674);
  flex-shrink: 0;
}

/* =========================================================================
   bases/site_footer/base.css — структурный слой основы «Подвал»
   Специфичность: только базовый класс .site-footer (DEC-001 п.5). Резина:
   колонки через auto-fit/minmax (не фиксированные брейкпоинт-ступени),
   паддинги/gap — clamp() между var()-границами. Брейкпоинты структуры не
   нужны — grid auto-fit сам сжимается по ширине контейнера.
   ========================================================================= */

.site-footer {
  /* TASK-RHYTHM-MATCH (2026-07-08): было clamp(2.5rem,6vw,5rem) — на 1200px
     даёт симметричные 72px/72px (144px суммарно), заметно больше эталона
     design/etalon/eskiz-glavnaya.html `.ft{padding-block:64px 30px}`
     (94px суммарно, АСИММЕТРИЧНО — верх 64, низ 30). Эталон сам не даёт
     это резиновым (буквально фиксированные px), но проектное правило
     «резина всегда» (CLAUDE.md) обязывает регулируемый размер держать на
     clamp() — вместо копирования фиксированных чисел посчитаны две
     резиновые границы Utopia-формулой (360->1240) так, чтобы значение НА
     1200PX было близко к эталонным 64/30 (I2, число эталона — цель
     расчёта, не выдумано с нуля): верх 48->64px, низ 24->30px. */
  padding-block-start: clamp(3rem, 2.5909rem + 1.8182vw, 4rem);
  padding-block-end: clamp(1.5rem, 1.3466rem + 0.6818vw, 1.875rem);
  background: var(--bg-2, #fbf8f2);
  color: var(--fg-2, #555);
}

.site-footer__container {
  display: flex;
  flex-direction: column;
  gap: clamp(var(--s-6, 1.5rem), 4vw, var(--s-8, 2rem));
}

/* Группа верха (TASK-ETALON-LIB-2, перенос .ft__grid эталона строки
   469-470): бренд шире колонок ссылок, граница снизу отделяет от нижней
   строки копирайт+контакты — перенос эталона буквально (auto-fit вместо
   фиксированных 4 колонок, чтобы бренд-колонка не схлопывалась раньше
   времени на промежуточных ширинах — резина, DEC-001 п.14). */
.site-footer__top {
  display: grid;
  /* Два трека: бренд + обёртка колонок — сама .site-footer__columns несёт
     ВНУТРЕННИЙ auto-fit на 3 подколонки (см. ниже), поэтому визуально
     получается одна строка из 4 колонок (brand+3), как в эталоне, без
     необходимости выносить каждую .site-footer__column прямым потомком
     .site-footer__top (разметка колонок остаётся вложенной, DEC-001 —
     стиль/структура не завязаны на плоский список прямых детей грида). */
  grid-template-columns: minmax(14rem, 1.4fr) minmax(0, 3fr);
  gap: clamp(var(--s-8, 2rem), 5vw, var(--s-12, 3rem));
  padding-bottom: clamp(var(--s-8, 2rem), 4vw, var(--s-10, 2.5rem));
  border-bottom: 1px solid var(--site-footer-divider, var(--border-1, #e5dacb));
}

@media (max-width: 700px) {
  .site-footer__top {
    grid-template-columns: 1fr;
  }
}

.site-footer__brand-block {
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
}

.site-footer__brand-row {
  display: flex;
  align-items: center;
  gap: var(--s-3, 0.75rem);
}

.site-footer__tag {
  margin: 0;
  max-width: 34ch;
  line-height: 1.7;
  font-size: clamp(var(--t-body-s, 0.9375rem), 0.4vw + 0.85rem, var(--t-body, 1rem));
}

/* Эмблема подвала (FLG-034 починка 4) — тот же актив, что и в шапке;
   decorative (бренд уже подписан текстом рядом), aria-hidden в base.html. */
.site-footer__emblem {
  width: var(--s-8, 2rem);
  height: var(--s-8, 2rem);
  border-radius: var(--r-pill, 999px);
  object-fit: cover;
  align-self: center;
}

.site-footer__brand {
  margin: 0;
  font-weight: var(--w-medium, 500);
}

.site-footer__city {
  margin: 0;
}

/* Колонки — auto-fit/minmax: сжимаются плавно по доступной ширине, без
   фиксированных ступеней брейкпоинтов (дополнение Владельца к заданию). */
.site-footer__columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: clamp(var(--s-6, 1.5rem), 4vw, var(--s-10, 2.5rem));
}

.site-footer__column-title {
  margin: 0 0 var(--s-3, 0.75rem);
  font-weight: var(--w-medium, 500);
}

.site-footer__column-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
}

.site-footer__column-link {
  text-decoration: none;
  color: inherit;
}

/* Строка низа (TASK-ETALON-LIB-2, перенос .ft__bottom эталона строки
   481-482): копирайт слева, контакты справа, перенос по ширине на узких
   экранах — не отдельная секция с рамкой сверху/снизу, компактная строка. */
.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(var(--s-3, 0.75rem), 2vw, var(--s-6, 1.5rem));
  font-size: var(--t-caption, 0.8125rem);
}

/* Контакты — инлайн-ряд рядом с копирайтом (перенос силуэта эталона).
   Роль остаётся ВИДИМОЙ (урок пилота unona — не sr-only), но компактно
   ИНЛАЙН перед значением через ::after-разделитель, не отдельной строкой
   над значением — так строка не растягивается по высоте лишний раз. */
.site-footer__contacts {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(var(--s-3, 0.75rem), 2vw, var(--s-6, 1.5rem));
}

.site-footer__contact {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-2, 0.5rem);
  text-decoration: none;
  color: inherit;
}

.site-footer__contact-role {
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8b6f65);
}

.site-footer__contact-role::after {
  content: ":";
}

.site-footer__contact-value {
  font-size: var(--t-caption, 0.8125rem);
}

.site-footer__copyright {
  margin: 0;
}

/* =========================================================================
   styles/site_footer/marina.css — стиль «Подвал» темы Marina
   Ровно один класс-модификатор .site-footer--marina (DEC-001 п.4/5).
   Без !important.
   ========================================================================= */

.site-footer--marina {
  background: var(--bg-inverse, #2a1e1a);
  color: var(--fg-on-dark, #f4eee6);
}

.site-footer--marina .site-footer__brand {
  font-family: var(--font-display);
  font-size: clamp(var(--t-h4, 1.125rem), 1.4vw + 0.6rem, var(--t-h3, 1.375rem));
  color: var(--fg-on-dark, #f4eee6);
}

.site-footer--marina .site-footer__city,
.site-footer--marina .site-footer__tag {
  font-family: var(--font-body);
  color: var(--cocoa-200, #b09a91);
}

.site-footer--marina .site-footer__column-title {
  font-family: var(--font-body);
  font-size: var(--t-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--cocoa-200, #b09a91);
}

.site-footer--marina .site-footer__column-link,
.site-footer--marina .site-footer__contact-value,
.site-footer--marina .site-footer__copyright {
  font-family: var(--font-body);
}

.site-footer--marina .site-footer__column-link {
  color: var(--fg-on-dark, #f4eee6);
  opacity: 0.85;
  transition: opacity var(--t-fast) var(--ease-out);
}

.site-footer--marina .site-footer__column-link:hover {
  opacity: 1;
  color: var(--gilt-300, #d4b98a);
}

.site-footer--marina .site-footer__top {
  border-color: rgba(244, 238, 230, 0.14);
}

.site-footer--marina .site-footer__contact-role {
  font-family: var(--font-body);
  color: var(--gilt-300, #d4b98a);
}

.site-footer--marina .site-footer__contact-value {
  color: var(--fg-on-dark, #f4eee6);
}

.site-footer--marina .site-footer__copyright {
  color: var(--cocoa-200, #b09a91);
}

@media (prefers-reduced-motion: reduce) {
  .site-footer--marina .site-footer__column-link {
    transition: none;
  }
}

/* =========================================================================
   bases/floating_button/base.css — структурный слой основы «Плавающая
   кнопка». Специфичность: только базовый класс .floating-button
   (DEC-001 п.5). scope: global — position: fixed относительно вьюпорта.

   Видна ВСЕГДА по умолчанию (без JS — доступность действия важнее
   декоративного появления, doc 10). behaviors/floating_cta/behavior.js
   добавляет класс .is-visible/.floating-cta--animated и переключает
   видимость по порогу прокрутки — CSS ниже уважает эти классы, когда
   они есть, и остаётся видимым, когда их нет.
   ========================================================================= */

.floating-button {
  position: fixed;
  right: var(--floating-button-offset-x, var(--s-6, 1.5rem));
  bottom: var(--floating-button-offset-y, var(--s-6, 1.5rem));
  z-index: var(--z-floating, 40);
  display: inline-flex;
  align-items: center;
  gap: var(--s-2, 0.5rem);
  padding: var(--s-3, 0.75rem) var(--s-5, 1.25rem);
  border-radius: var(--r-pill, 999px);
  background: var(--fg-brand, #9C6957);
  color: var(--fg-on-dark, #fff);
  text-decoration: none;
  font-weight: var(--w-medium, 500);
  box-shadow: var(--shadow-3, 0 12px 32px rgba(0, 0, 0, 0.12));
}

.floating-button:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-1, #111);
  outline-offset: 3px;
}

.floating-button__icon {
  display: block;
  width: var(--floating-button-icon-size, 1.25rem);
  height: var(--floating-button-icon-size, 1.25rem);
}

/* Появление по прокрутке — только когда JS реально навесил класс
   .floating-cta--animated (prefers-reduced-motion уважается: behavior.js
   не добавляет этот класс, если reduce активен — тогда переключение
   .is-visible происходит без transition, мгновенно). */
.floating-button.floating-cta--animated {
  transition: opacity var(--t-normal, 240ms) var(--ease-out, ease),
              transform var(--t-normal, 240ms) var(--ease-out, ease);
}

/* Состояния visible/hidden ставит behavior.js по порогу прокрутки (doc 31
   именует их так для семейства «показ по условию» — переиспользовано по
   аналогии, см. behaviors/floating_cta/README.md). Без JS ни один из
   классов не появляется — кнопка остаётся в состоянии по умолчанию
   (видима), что и требуется для деградации. */
.floating-button[aria-hidden="true"] {
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
}

.floating-button.is-visible,
.floating-button:not([aria-hidden]) {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* Ниже 600 плавающую пилюлю несёт нижняя панель связи (bottom_action_bar,
   display:block только ≤600, тот же канал WhatsApp) — плавающая кнопка тут
   избыточна и накладывалась на бар после порога прокрутки (task_7725acf5).
   Скрываем на узких: связь на мобиле держит нижний бар (телефон+WhatsApp),
   плавающая пилюля остаётся для десктопа, где бара нет. Смена СТРУКТУРЫ
   мобильной страховки связи, не подмена размеров. */
@media (max-width: 600px) {
  .floating-button {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .floating-button {
    transition: none;
  }
}

/* =========================================================================
   styles/floating_button/marina.css — стиль «Marina» плавающей кнопки
   Ровно один класс-модификатор .floating-button--marina (DEC-001 п.4/5).
   Специфичность: одна ступень поверх .floating-button. Без !important.

   Заведён ячейкой TASK-P3-FIRST-PAGE (главная unona, каркас floating_button)
   — ранее у блока не было ни одного стиля на диске (base.css уже задаёт
   цвет/форму кнопки токенами темы структурно). marina добавляет только
   шрифт лейбла — единственное, что ещё не покрыто base.css.
   ========================================================================= */

.floating-button--marina .floating-button__label {
  font-family: var(--font-body);
  font-weight: var(--w-medium);
}

/* =========================================================================
   bases/bottom_action_bar/base.css — структурный слой «Нижняя панель действий»
   Специфичность: только базовый класс .bottom-action-bar (DEC-001 п.5).
   Sticky снизу — чистый CSS position:fixed (не sticky: панель должна
   оставаться в viewport независимо от высоты страницы, а не только внутри
   родителя). Видна только ≤600px (структурная граница мобильной панели —
   задание ячейки), размеры внутри — clamp().
   ========================================================================= */

.bottom-action-bar {
  display: none;
}

@media (max-width: 600px) {
  .bottom-action-bar {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-header, 40);
    padding: clamp(var(--s-2, 0.5rem), 2vw, var(--s-3, 0.75rem));
    padding-bottom: max(clamp(var(--s-2, 0.5rem), 2vw, var(--s-3, 0.75rem)), env(safe-area-inset-bottom, 0px));
    background: var(--bg-1, #fff);
    border-top: 1px solid var(--border-1, #e5dacb);
  }
}

.bottom-action-bar__row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: clamp(var(--s-2, 0.5rem), 2vw, var(--s-3, 0.75rem));
}

.bottom-action-bar__action {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2, 0.5rem);
  padding-block: clamp(var(--s-2, 0.5rem), 2vw, var(--s-3, 0.75rem));
  border-radius: var(--r-pill, 999px);
  text-decoration: none;
  white-space: nowrap;
}

.bottom-action-bar__icon {
  width: 1.1rem;
  height: 1.1rem;
  flex-shrink: 0;
  border-radius: var(--r-pill, 999px);
  background: currentColor;
  opacity: 0.85;
}

.bottom-action-bar__label {
  font-size: clamp(var(--t-caption, 0.8125rem), 1vw + 0.4rem, var(--t-body-s, 0.9375rem));
}

/* Состояния visible/hidden манифеста sticky_action_bar (spec/docs/31) —
   behaviors/sticky_action_bar/behavior.js переключает aria-hidden/
   .is-visible по порогу прокрутки (data-visible-after-px, база 600 —
   bases/bottom_action_bar/base.html). ГЛАВНЫЙ фикс Пачки C п.4
   (scan-01.md): без порога панель нависала НАД первым экраном (замер
   qa/scan/narrow-mobile-fix/w280-header-hero.png — накрывала
   hero__cta--secondary на 320/360) — с порогом 600 панель скрыта, пока
   виден hero, как и эталонная плавающая пилюля (design/etalon/
   eskiz-glavnaya.html, floating_button.visible_after_px той же страницы).
   Приём — тот же, что bases/floating_button/base.css (.floating-button[
   aria-hidden="true"]/.is-visible). Деградация без JS: без aria-hidden в
   разметке (base.html не проставляет статически) — правило
   :not([aria-hidden]) ниже держит панель видимой, доступность действия
   важнее декоративного порога (doc 10), тот же принцип, что floating_button. */
@media (max-width: 600px) {
  .bottom-action-bar[aria-hidden="true"] {
    opacity: 0;
    transform: translateY(12px);
    pointer-events: none;
  }

  .bottom-action-bar.is-visible,
  .bottom-action-bar:not([aria-hidden]) {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  .bottom-action-bar.sticky-action-bar--animated {
    transition: opacity var(--t-normal, 240ms) var(--ease-out, ease),
                transform var(--t-normal, 240ms) var(--ease-out, ease);
  }
}

@media (prefers-reduced-motion: reduce) {
  .bottom-action-bar {
    transition: none;
  }
}

/* Держит место в САМОМ НИЗУ ДОКУМЕНТА, чтобы панель (видимая после порога
   прокрутки — правило выше) не перекрывала ПОСЛЕДНИЙ контент страницы
   (дисклеймер/футер), когда пользователь долистывает до конца — другой
   сценарий, чем перекрытие hero на первом экране (тот закрывает порог
   прокрутки выше, этот — про «хвост» страницы). acceptance.md фиксировал
   это отложенным пунктом («резервирование места — ответственность каркаса
   страницы, не этой основы») — каркас так и не получил правило, закрываю
   здесь (I7, не оставляю дыру молча). Формула ИЗМЕРЕНА, не угадана (I2,
   Playwright getBoundingClientRect на standalone-сборке 360px, scratchpad
   ячейки): ДВА слоя padding-block делят одну и ту же clamp-формулу — сам
   бар (padding строка 22-23 выше) И .bottom-action-bar__action
   (padding-block строка 41) — измеренный barBox.height=53px на 360
   раскладывается как 4×8px (оба слоя padding по 8px на этой ширине) +
   ~20px высоты строки действия (max иконки 17.6px/подписи) + 1px
   border-top. Формула ниже считает 4×clamp + 1.5rem контента (запас над
   измеренными ~20px) + 2px буфер на округление + safe-area — на 360 даёт
   58px резерва при 53px фактических. body:has() — тот же приём, что
   styles/stats_strip/marina-dark.css .section:has(...) (тот же браузерный
   порог поддержки, уже принят в проекте). */
@media (max-width: 600px) {
  body:has(.bottom-action-bar) {
    padding-bottom: calc(
      4 * clamp(var(--s-2, 0.5rem), 2vw, var(--s-3, 0.75rem)) +
      1.5rem + 2px +
      env(safe-area-inset-bottom, 0px)
    );
  }
}

/* =========================================================================
   styles/bottom_action_bar/marina.css — стиль темы Marina
   Ровно один класс-модификатор .bottom-action-bar--marina (DEC-001 п.4/5).
   Без !important.
   ========================================================================= */

.bottom-action-bar--marina {
  background: color-mix(in srgb, var(--bg-1) 96%, transparent);
  backdrop-filter: blur(var(--header-blur, 10px));
  -webkit-backdrop-filter: blur(var(--header-blur, 10px));
  box-shadow: var(--shadow-3);
}

.bottom-action-bar--marina .bottom-action-bar__action {
  font-family: var(--font-body);
  font-weight: var(--w-medium);
}

.bottom-action-bar--marina .bottom-action-bar__action--phone {
  background: transparent;
  color: var(--fg-1);
  border: 1px solid var(--border-strong, var(--cocoa-300));
}

.bottom-action-bar--marina .bottom-action-bar__action--whatsapp {
  background: var(--fg-brand);
  color: var(--fg-on-dark);
}

/* =========================================================================
   bases/comparison_table/base.css — структурный слой основы «Таблица
   сравнения». Специфичность: базовые классы .comparison-table и
   .comparison-cards (DEC-001 п.5) — два корня разметки, одна раскладка
   активна на любой ширине через media (см. ниже), другая display:none.

   Брейкпоинт --bp-md (960px) переключает СТРУКТУРУ (table ↔ карточки) —
   допустимо по FLG-003 («брейкпоинты только для структуры»). Внутри
   каждого режима — резина через clamp()/var(), без промежуточных
   брейкпоинтов.

   Требование ячейки: на узких — карточки, НЕ горизонтальный скролл
   таблицы (урок арт-ворот пилота unona о нечитаемых узких таблицах).
   ========================================================================= */

.comparison-table-section {
  padding-block: var(--s-12, 3rem);
}

/* --- Таблица (широкие экраны, ≥960px) ---------------------------------- */

/* K5.2 (DEC-002)/находка топ-4 audit-01: правило .comparison-cards{display:
   flex} ниже по каскаду (порядок в файле, та же специфичность 0,1,0)
   побеждало @media-версию display:none — обе раскладки рендерились
   одновременно на ≥960 (карточка «Наша методика» наезжала на таблицу).
   Фикс: базовое видимое состояние карточек живёт ЗДЕСЬ, до определения
   .comparison-cards{display:flex} ниже, и переключатель — единственный
   источник display для обоих корней (без дыры/пересечения диапазонов). */
.comparison-table-wrap {
  display: none;
}

@media (min-width: 960px) {
  .comparison-table-wrap { display: block; }
}

.comparison-table {
  width: 100%;
  border-collapse: collapse;
  /* table-layout:fixed (правка scan-prodazha-03): при 3 колонках значений
     авто-раскладка давала min-content шире вьюпорта — горизонтальный скролл
     на 960–1046 (нарушение резины). Фиксированная раскладка делит 100%
     ширины между колонками поровну, длинный текст переносится — таблица не
     вылезает за контейнер при любом числе колонок. */
  table-layout: fixed;
}

.comparison-table__caption {
  text-align: left;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
  margin-block-end: var(--s-3, 0.75rem);
}

.comparison-table th,
.comparison-table td {
  padding: var(--comparison-table-cell-padding, var(--s-4, 1rem));
  border-bottom: 1px solid var(--comparison-table-border-color, var(--border-1, #E5DACB));
  text-align: left;
  vertical-align: top;
}

.comparison-table__criterion-head,
.comparison-table__criterion {
  color: var(--fg-2, #555);
  font-weight: var(--w-medium, 500);
  /* nowrap снят вместе с table-layout:fixed — при фиксированной раскладке
     длинные критерии («Окно решения», «Состав пакета») переносятся, а не
     распирают колонку; иначе fixed отдал бы им лишнюю ширину. */
}

.comparison-table__col-head {
  color: var(--fg-1, #111);
  font-weight: var(--w-semibold, 600);
}

.comparison-table__col-head--highlighted,
.comparison-table__value--highlighted {
  background: var(--comparison-table-highlight-bg, var(--bg-2, #FBF8F2));
}

.comparison-table__col-head--highlighted {
  border-radius: var(--r-md, 8px) var(--r-md, 8px) 0 0;
}

/* --- Карточки (узкие экраны, <960px) ------------------------------------ */

.comparison-cards {
  display: flex;
  flex-direction: column;
  gap: var(--s-6, 1.5rem);
}

.comparison-cards__card {
  border: 1px solid var(--comparison-table-border-color, var(--border-1, #E5DACB));
  border-radius: var(--r-lg, 14px);
  padding: var(--comparison-table-cell-padding, var(--s-5, 1.25rem));
}

.comparison-cards__card--highlighted {
  background: var(--comparison-table-highlight-bg, var(--bg-2, #FBF8F2));
  border-color: var(--fg-brand, #9C6957);
}

.comparison-cards__title {
  margin: 0 0 var(--s-4, 1rem);
  font-size: var(--t-h4, 1.125rem);
  color: var(--fg-1, #111);
}

.comparison-cards__list {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-3, 0.75rem);
}

.comparison-cards__criterion {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
}

.comparison-cards__value {
  margin: 0 0 var(--s-2, 0.5rem);
  color: var(--fg-2, #555);
}

/* Переключатель карточек размещён ПОСЛЕ базового .comparison-cards{display:
   flex} (см. правку выше по этой же находке) — гарантирует, что на ≥960
   именно display:none выигрывает каскад при равной специфичности 0,1,0;
   границы диапазонов стык-в-стык с .comparison-table-wrap (тот же 960px),
   без дыры и без пересечения. */
@media (min-width: 960px) {
  .comparison-cards { display: none; }
}

/* =========================================================================
   styles/comparison_table/marina-glass.css — «Таблица сравнения» манеры
   «Мягкое стекло» (TASK-GLASS-CONTENT). Ровно один класс-модификатор
   .comparison-table--marina-glass (DEC-001 п.4/5).

   НАХОДКА (I7, фиксирую явно, вне зоны правки этой ячейки): сборщик
   (site-factory/src/sitefactory/block_assembler.py, _kebab + style_class)
   ставит на корневой <section> класс "comparison-table-section" (базовый,
   из bases/comparison_table/base.html) ПЛЮС
   "{_kebab('comparison_table')}--{style}" = "comparison-table--{style}" —
   ДВА разных класса на одном элементе, не один составной
   "comparison-table-section--{style}". Тот же класс расхождения найден
   этой ячейкой у styles/steps_timeline/marina-dark.css (см. находку там) —
   системный паттерн у виджетов, чей базовый класс секции длиннее
   kebab(block_id) (steps_timeline/comparison_table против hero/cta_block,
   где базовый класс секции совпадает с kebab(id)). Первый стиль этого
   виджета — registry.yaml нёс styles: [] (ещё не заводился ни один стиль),
   поэтому здесь нет предыдущего сломанного файла для сверки — строю сразу
   на РЕАЛЬНОМ классе, который сборщик генерирует.

   Специфичность: одна ступень поверх .comparison-table-section (базовый
   класс присутствует на элементе одновременно с модификатором). Без
   !important.

   Стекло здесь — акцент, не общая манера ВСЕЙ таблицы (сплошная строчная
   таблица со стеклом на каждой ячейке визуально шумит и не читается,
   K18 — стекло не должно мешать восприятию данных): колонка/карточка
   --highlighted (наша методика, приоритетный вариант сравнения) получает
   стеклянную плиту, остальные строки/карточки остаются на нейтральном
   base.css. Fallback непрозрачный ПЕРВЫМ (K17).
   ========================================================================= */

.comparison-table-section.comparison-table--marina-glass {
  background: var(--bg-1);
}

.comparison-table--marina-glass .comparison-table__caption {
  font-family: var(--font-body);
}

.comparison-table--marina-glass .comparison-table__criterion-head,
.comparison-table--marina-glass .comparison-table__criterion {
  font-family: var(--font-body);
}

.comparison-table--marina-glass .comparison-table__col-head {
  font-family: var(--font-display);
  font-weight: var(--w-medium);
}

/* --- Таблица (широкие экраны): колонка-приоритет — стеклянная плита. --- */

.comparison-table--marina-glass .comparison-table__col-head--highlighted,
.comparison-table--marina-glass .comparison-table__value--highlighted {
  border: none;
  /* Fallback ПЕРВЫМ (K17). */
  background: var(--bg-2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .comparison-table--marina-glass .comparison-table__col-head--highlighted,
  .comparison-table--marina-glass .comparison-table__value--highlighted {
    background: rgba(251, 248, 242, 0.62);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
  }
}

.comparison-table--marina-glass .comparison-table__col-head--highlighted {
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}

/* --- Карточки (узкие экраны): карточка-приоритет — стеклянная плита,
   остальные карточки — нейтральный border base.css. --- */

.comparison-table--marina-glass .comparison-cards__title {
  font-family: var(--font-display);
}

.comparison-table--marina-glass .comparison-cards__card {
  transition: box-shadow var(--t-slow, 420ms) var(--ease-out),
              background-color var(--t-slow, 420ms) var(--ease-out);
}

.comparison-table--marina-glass .comparison-cards__card--highlighted {
  border: none;
  border-radius: var(--r-2xl);
  /* Fallback ПЕРВЫМ (K17). */
  background: var(--bg-2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18),
              var(--op-shadow-2, var(--shadow-2));
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .comparison-table--marina-glass .comparison-cards__card--highlighted {
    background: rgba(251, 248, 242, 0.62);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .comparison-table--marina-glass .comparison-cards__card {
    transition: none;
  }
}

/* =========================================================================
   bases/price_table/base.css — структурный слой основы «Прайс-таблица»
   Специфичность: только базовый класс .price-table (DEC-001 п.5).

   СТРУКТУРНЫЙ ПЕРЕТОК (задание ячейки: «на узких экранах таблица
   превращается в карточки-строки — структурный приём, не горизонтальный
   скролл»): .price-table__row — CSS Grid с явными колонками
   (услуга/длительность/цена) на широких экранах; на узких (< --bp-md,
   960px, spec/docs/11) колонки схлопываются в одну через grid-template-
   columns: 1fr и каждая ячейка становится строкой с видимой подписью
   (.price-table__cell-label, скрытой на широких через clip-path — не
   display:none, чтобы не ломать порядок чтения скринридером). Единая
   разметка для обоих состояний (см. base.html) — переключение только
   раскладкой, без дублирования DOM.

   РЕЗИНА (FLG-003): межстрочный зазор и типографика группы — clamp()/
   var()-границы; единственный брейкпоинт --bp-md меняет СТРУКТУРУ
   (колонки → строки), что разрешено правилом FLG-003 явно («брейкпоинты
   только для смены структуры раскладки»).
   ========================================================================= */

.price-table {
  display: flex;
  flex-direction: column;
  gap: var(--price-table-group-gap, clamp(var(--s-8, 2rem), 1.5rem + 2vw, var(--s-16, 4rem)));
}

.price-table__group-title {
  margin: 0 0 var(--s-4, 1rem);
  font-size: clamp(var(--t-h4, 1.125rem), 0.4vw + 1rem, var(--t-h3, 1.375rem));
  color: var(--fg-1, #111);
}

.price-table__table {
  display: block;
}

.price-table__row-group {
  display: flex;
  flex-direction: column;
  gap: var(--price-table-row-gap, var(--s-2, 0.5rem));
}

/* Широкие экраны: строка — сетка из трёх колонок с фиксированной шириной
   длительности/цены и гибкой шириной названия. */
.price-table__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-1, 0.25rem) var(--s-4, 1rem);
  padding: var(--s-3, 0.75rem) var(--s-4, 1rem);
  border-radius: var(--r-md, 8px);
  background: var(--bg-2, #fff);
}

.price-table__cell {
  display: flex;
  /* Починка (TASK-GLASS-CONTENT, находка QA-приёмки манеры стекла —
     горизонтальное переполнение на 360px, .price-table__row не влезал
     в вьюпорт): на узких экранах метка ("Услуга") и значение стояли В
     РЯД (align-items:baseline, метка фиксированной шириной 6.5rem) —
     длинное название услуги ("Аппаратная RF/TECAR-процедура для лица")
     получало слишком узкий остаток ширины и либо распирало строку, либо
     (первая попытка починки, min-width:0 без смены direction) ломало
     текст ПО БУКВЕ в колонку в 1 символ — хуже исходного бага, найдено
     живым скриншотом на 360px этой же ячейкой ПЕРЕД тем, как записать
     финальную версию (I2 — правка проверена, не оставлена на глаз).
     Верное решение: на узких экранах метка и значение идут СТОЛБИКОМ
     (подпись мелким кеглем сверху, значение под ней — та же карточка-
     строка, что уже описана докстрокой файла), в ряд — только на широких
     (≥960px, где метка визуально скрыта clip-path и колонки заданы
     grid-template-columns на .price-table__row, ширина там не проблема).
     Баг структурный (основы, не манеры стекла), найден и чинится здесь —
     вне списка багов а–г задания, но в зоне той же основы, что и
     стекло приёмки (I7). */
  flex-direction: column;
  gap: var(--s-1, 0.25rem);
  min-width: 0;
}

/* Подпись видима на узких экранах (карточка-строка), скрыта визуально
   на широких (таблица) — clip-path вместо display:none, чтобы не рвать
   порядок чтения ARIA-таблицы row/cell. */
.price-table__cell-label {
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #777);
}

/* Значение ячейки (название услуги/длительность/цена) — второй ребёнок
   .price-table__cell без собственного класса в разметке (текстовый
   <span>). Переносится по словам на узкой колонке-столбике вместо
   распирания строки за пределы вьюпорта (та же находка, что комментарий
   выше на .price-table__cell). */
.price-table__cell > span:not(.price-table__cell-label) {
  min-width: 0;
  overflow-wrap: break-word;
}

.price-table__price {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-1, 0.25rem);
  font-family: var(--font-display, serif);
  color: var(--fg-1, #111);
}

.price-table__price--pending {
  font-family: var(--font-body, sans-serif);
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
  font-style: italic;
}

.price-table__price-unit {
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
}

.price-table__group-footnote {
  margin: var(--s-3, 0.75rem) 0 0;
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
}

/* --- Структурная смена на широких экранах: таблица (doc 11, --bp-md) --- */
@media (min-width: 960px) {
  .price-table__row {
    grid-template-columns: minmax(0, 2.2fr) minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: var(--s-4, 1rem);
  }

  .price-table__cell--duration,
  .price-table__cell--price {
    justify-content: flex-end;
    text-align: right;
  }

  .price-table__cell--price {
    justify-self: end;
  }

  /* Подпись остаётся в DOM (ARIA), визуально скрыта на широких экранах. */
  .price-table__cell-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .price-table__cell {
    position: relative;
  }
}

/* =========================================================================
   styles/price_table/marina-glass.css — «Прайс-таблица» манеры
   «Мягкое стекло» (TASK-GLASS-CONTENT). Ровно один класс-модификатор
   .price-table--marina-glass (DEC-001 п.4/5). Специфичность: одна ступень
   поверх .price-table. Без !important.

   Каждая строка услуги (.price-table__row) — стеклянная плита вместо
   border+hover-тень marina.css (K17). На узких экранах строка становится
   карточкой (структурный переток base.css, brейкпоинт --bp-md) — стекло
   работает одинаково в обоих представлениях, т.к. .price-table__row один
   и тот же узел на любой ширине (переключается только grid-template-
   columns, не разметка). Fallback непрозрачный ПЕРВЫМ.
   ========================================================================= */

.price-table--marina-glass .price-table__group-title {
  font-family: var(--font-display);
  font-weight: var(--w-medium);
}

.price-table--marina-glass .price-table__row {
  border: none;
  /* Fallback ПЕРВЫМ (K17). */
  background: var(--bg-2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
  transition: box-shadow var(--t-slow, 420ms) var(--ease-out),
              background-color var(--t-slow, 420ms) var(--ease-out),
              transform var(--t-slow, 420ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .price-table--marina-glass .price-table__row {
    background: rgba(251, 248, 242, 0.6);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
  }
}

.price-table--marina-glass .price-table__row:hover {
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.24),
              var(--op-shadow-1, var(--shadow-1));
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .price-table--marina-glass .price-table__row:hover {
    background: rgba(251, 248, 242, 0.72);
  }
}

.price-table--marina-glass .price-table__cell--name {
  font-family: var(--font-body);
  color: var(--fg-1);
}

.price-table--marina-glass .price-table__price {
  font-family: var(--font-display, serif);
  color: var(--fg-brand);
}

.price-table--marina-glass .price-table__group-footnote {
  font-family: var(--font-body);
  font-style: italic;
}

@media (prefers-reduced-motion: reduce) {
  .price-table--marina-glass .price-table__row {
    transition: none;
  }
  .price-table--marina-glass .price-table__row:hover {
    transform: none;
  }
}

/* =========================================================================
   bases/service_card/base.css — структурный слой основы «Карточка услуги»
   Специфичность: базовый класс .service-card плюс обёртка сетки
   .service-card-grid (DEC-001 п.5) — обёртка сетки не самостоятельный
   виджет реестра, а разметочный контейнер, который использует секция/
   сборщик страницы при повторении карточек (тот же уровень специфичности,
   часть основы, не отдельный блок).

   МЕХАНИЗМ СИРОТ — перенос решения benefits_grid (bases/benefits_grid/
   base.css) без изменений: flexbox с flex-wrap + justify-content: center
   центрирует КАЖДУЮ визуальную строку независимо, включая неполный
   последний ряд, без JS и без подсчёта карточек на стороне рендера. Grid
   отклонён по той же причине (центрирует набор треков колонок целиком,
   не отдельные строки — см. acceptance.md benefits_grid, отрицательный
   результат зафиксирован там же, не повторяю проверку здесь).

   РЕЗИНА (FLG-003): flex-basis между --service-card-min/-max, gap и
   типографика — clamp() с var()-границами; медиа queries не используются
   вовсе, переход 3→2→1 колонки идёт по ширине контейнера как у
   benefits_grid.

   КРАФТ-РЕМОНТ (DEC-002, TASK-P3-REPAIR-CARDS, горизонтали S1/S2/S5):
   - K3.1: `.service-card-grid` — `align-items: stretch`, чтобы карточки
     одного ряда тянулись до высоты самой высокой (по умолчанию у flex-строки
     stretch и так работает, свойство прописано явно — I7, не полагаемся на
     умолчание молча).
   - K1.2/S1: `.service-card` — `container-type: inline-size` (контекст
     контейнер-запроса для `.service-card__actions`); ниже порога кнопки
     переходят в столбик на 100% ширины — было flex-wrap без запроса,
     обрубки авто-шириной (ядро FLG-011).
   - K2.2/K3.2/S2: `.service-card__actions` — `margin-top: auto` (приём-донор
     testimonials), действия садятся на низ тела карточки.
   - K2.3/K7.4: заголовок line-clamp 2 строки, короткое описание — 3.
   ========================================================================= */

.service-card-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  justify-content: center;
  gap: var(--service-card-gap, var(--s-8, 2rem));
}

.service-card {
  display: flex;
  flex-direction: column;
  flex: 1 1 var(--service-card-min, 17rem);
  max-width: var(--service-card-max, 22rem);
  border-radius: var(--service-card-radius, var(--r-lg, 14px));
  overflow: hidden;
  background: var(--bg-2, #fff);
  box-shadow: var(--shadow-1, 0 1px 2px rgba(0, 0, 0, 0.04));
  /* K1.2/S1: контекст контейнер-запроса для группы действий тела карточки. */
  container-type: inline-size;
  container-name: service-card;
}

.service-card__media {
  width: 100%;
  aspect-ratio: var(--service-card-photo-ratio, 4 / 3);
  overflow: hidden;
}

.service-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.service-card__placeholder {
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, var(--blush-200, #ddd), var(--blush-400, #999));
}

.service-card__placeholder--sage {
  background: linear-gradient(135deg, var(--sage-100, #ddd), var(--sage-500, #7B8A6E));
}

.service-card__placeholder--gilt {
  background: linear-gradient(135deg, var(--gilt-300, #ddd), var(--gilt-500, #B8956A));
}

/* TASK-USLUGI-CATALOG: код-графика мотива (photo.motif) вместо src — та же
   зона медиа, что фото/плейсхолдер, тот же aspect-ratio родителя. SVG сам
   несёт свой фон (rect), поэтому контейнер не нуждается в собственном. */
.service-card__motif {
  width: 100%;
  height: 100%;
  display: flex;
}

.service-card__motif svg {
  width: 100%;
  height: 100%;
  display: block;
}

.service-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
  padding: var(--s-5, 1.25rem);
  flex: 1 1 auto;
}

.service-card__category {
  margin: 0;
}

.service-card__title {
  margin: 0;
  /* Резиновая типографика — clamp() между h4 и h3, без брейкпоинта. */
  font-size: clamp(var(--t-h4, 1.125rem), 0.5vw + 1rem, var(--t-h3, 1.375rem));
  color: var(--fg-1, #111);
  /* K2.3/K7.4: заголовок непредсказуемой длины не расталкивает карточку
     выше соседей в ряду — максимум 2 строки, третья обрезается. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.service-card__short {
  margin: 0;
  color: var(--fg-2, #555);
  /* K2.3/K7.4: описание — максимум 3 строки, та же причина. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.service-card__meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2, 0.5rem) var(--s-4, 1rem);
  /* K3.2: карточки без меты (напр. price_needs_owner без duration/course)
     не должны поднимать цену выше, чем у карточек с метой — резервируем
     высоту одной строки меты даже когда список пуст, чтобы цена/действия
     всех карточек ряда легли на одну горизонталь (донор testimonials —
     здесь используем min-height вместо margin-top:auto, т.к. зона не
     последняя в теле). */
  min-height: calc(var(--t-caption, 0.8125rem) * var(--lh-normal, 1.5));
}

.service-card__meta-item {
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #777);
}

.service-card__meta-item::before {
  content: "— ";
  color: var(--fg-brand, currentColor);
}

.service-card__price {
  margin-top: var(--s-2, 0.5rem);
  display: flex;
  align-items: baseline;
  gap: var(--s-1, 0.25rem);
}

.service-card__price-value {
  font-family: var(--font-display, serif);
  font-size: clamp(var(--t-h4, 1.125rem), 0.6vw + 1rem, var(--t-h3, 1.375rem));
  color: var(--fg-1, #111);
}

.service-card__price-value--pending {
  font-family: var(--font-body, sans-serif);
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
  font-style: italic;
}

.service-card__price-unit {
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
}

.service-card__actions {
  /* K2.2/K3.2/S2: действия прижаты к низу тела карточки (донор testimonials) —
     margin-top:auto вместо фиксированного отступа, чтобы в ряду карточек с
     разным объёмом текста над ценой кнопки садились на одну горизонталь. */
  margin-top: auto;
  padding-top: var(--s-3, 0.75rem);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3, 0.75rem);
}

/* TASK-USLUGI-CATALOG: cta_details опционален (props.schema.json) — карточка
   без "Подробнее" несёт единственную кнопку "Записаться"; без этого правила
   она остаётся авто-шириной слева, обрубком на фоне соседних двухкнопочных
   карточек ряда. */
.service-card__actions > .service-card__cta:only-child {
  width: 100%;
}

/* K1.2/S1: ниже порога контейнера группа действий переходит в столбик,
   каждая кнопка — 100% ширины родителя (запрет ступенчатых обрубков
   авто-шириной, ядро претензии FLG-011). Порог 320px контейнера —
   карточка уже сжата настолько, что двум кнопкам auto-шириной в ряд
   тесно (граничный случай найден на 360-ширине вьюпорта, K1.4). */
@container service-card (max-width: 320px) {
  .service-card__actions {
    flex-direction: column;
    align-items: stretch;
  }
}

.service-card__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* K1.4: минимальная тач-мишень ≥44px — вертикальный padding поднят с
     --s-2 (8px) до --s-3 (12px), плюс min-height как страховка на низком
     кегле (было --s-2, ступенчатая мишень не всегда добирала 44px). */
  min-height: 44px;
  padding: var(--s-3, 0.75rem) var(--s-5, 1.25rem);
  border-radius: var(--r-pill, 999px);
  font-weight: var(--w-medium, 500);
  text-decoration: none;
  border: none;
  cursor: pointer;
  font: inherit;
  transition: transform var(--t-fast, 140ms) var(--ease-out, ease),
              box-shadow var(--t-fast, 140ms) var(--ease-out, ease);
}

/* K1.2: кнопки в столбике — каждая 100% ширины родителя, не авто-ширина. */
@container service-card (max-width: 320px) {
  .service-card__cta {
    width: 100%;
  }
}

.service-card__cta--details {
  background: transparent;
  color: var(--fg-1, #111);
  border: 1px solid var(--border-strong, currentColor);
}

.service-card__cta--book {
  background: var(--fg-brand, #9C6957);
  color: var(--fg-on-dark, #fff);
}

.service-card__cta:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-2, 0 4px 14px rgba(0, 0, 0, 0.08));
}

@media (prefers-reduced-motion: reduce) {
  .service-card__cta {
    transition: none;
  }
}

/* =========================================================================
   styles/service_card/marina-glass.css — манера «Мягкое стекло»
   Один класс-модификатор .service-card--marina-glass (DEC-001 п.4/5),
   одна ступень специфичности поверх .service-card, без !important.

   Кандидат на манеру по умолчанию из трёх (DEC-003 черновик) — Владелец
   выбирает глазами на демо qa/style-vote/index.html.

   Источник приёмов: K17 (стеклянная подложка — backdrop-filter blur
   12–20px, полупрозрачный фон ≥50% непрозрачности базового цвета, тонкая
   светлая кромка rgba(255,255,255,.1–.15), обязательный fallback без
   backdrop-filter), K14 (крупные вложенные радиусы — карточка --r-2xl,
   внутренние элементы на ступень меньше --r-xl), K16 (медленные длинные
   переходы — верх иерархии длительностей, 300мс+, т.к. стекло физически
   «тяжелее» ощущается медленным откликом). Значения диапазона blur и
   правило фолбэка — best-practices.md §6/K17, не подобраны на глаз.

   Демонстрационная поверхность манеры ожидает визуально сложный фон
   позади карточки (best-practices.md §6 — «на сплошном плоском цвете
   backdrop-filter визуально не работает»); демо qa/style-vote/index.html
   кладёт карточки на градиентный фон именно по этой причине, не
   произвольно.
   ========================================================================= */

.service-card--marina-glass {
  /* Fallback ПЕРВЫМ — браузеры без backdrop-filter получают непрозрачный
     bg-2 (K17 обязательный fallback, иначе текст на голом фоне за
     карточкой нечитаем). @supports ниже переопределяет только для
     поддерживающих браузеров. */
  background: var(--bg-2);
  border: none;
  border-radius: var(--r-2xl);
  /* K17: тонкая светлая кромка вместо обычного border — часть иллюзии
     физической толщины стекла. */
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15),
              var(--shadow-3, 0 12px 32px rgba(58, 42, 36, 0.08));
  transition: box-shadow var(--t-slow, 420ms) var(--ease-out),
              transform var(--t-slow, 420ms) var(--ease-out),
              background-color var(--t-slow, 420ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .service-card--marina-glass {
    /* K17: фон ≥50% непрозрачности базового цвета (не ниже — иначе
       контраст текста ломается), blur в рабочем диапазоне 12–20px. */
    background: rgba(251, 248, 242, 0.62); /* --paper с alpha, ≥50% как требует K17 */
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

.service-card--marina-glass:hover {
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2),
              var(--shadow-4, 0 24px 56px rgba(58, 42, 36, 0.10));
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .service-card--marina-glass:hover {
    background: rgba(251, 248, 242, 0.72);
  }
}

.service-card--marina-glass .service-card__media {
  border-radius: var(--r-xl) var(--r-xl) 0 0;
}

.service-card--marina-glass .service-card__category {
  font-family: var(--font-body);
  font-size: var(--t-eyebrow);
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--fg-brand);
}

.service-card--marina-glass .service-card__title {
  font-family: var(--font-display);
  font-weight: var(--w-light);
}

.service-card--marina-glass .service-card__short {
  font-family: var(--font-body);
  line-height: var(--lh-loose);
}

.service-card--marina-glass .service-card__price-value {
  font-family: var(--font-display);
  color: var(--fg-brand);
}

.service-card--marina-glass .service-card__cta {
  border-radius: var(--r-pill);
  transition: box-shadow var(--t-normal, 240ms) var(--ease-out),
              background-color var(--t-normal, 240ms) var(--ease-out),
              transform var(--t-normal, 240ms) var(--ease-out);
}

.service-card--marina-glass .service-card__cta--details {
  background: rgba(255, 255, 255, 0.35);
  color: var(--fg-1);
  border: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .service-card--marina-glass .service-card__cta--details {
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }
}

.service-card--marina-glass .service-card__cta--details:hover {
  background: rgba(255, 255, 255, 0.55);
  color: var(--fg-brand);
  transform: translateY(-1px);
}

.service-card--marina-glass .service-card__cta--book {
  background: var(--fg-brand);
  color: var(--fg-on-dark);
}

.service-card--marina-glass .service-card__cta--book:hover {
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}

/* K13: двойное фокус-кольцо — тот же инвариант доступности, что и у
   остальных двух манер, стекло не освобождает от требования. */
.service-card--marina-glass .service-card__cta:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 4px var(--fg-brand);
}

@media (prefers-reduced-motion: reduce) {
  .service-card--marina-glass,
  .service-card--marina-glass:hover,
  .service-card--marina-glass .service-card__cta {
    transition: none;
    transform: none;
  }
}

/* =========================================================================
   bases/filter_grid/base.css — структурный слой основы «Сетка с фильтрами»
   Специфичность: только базовый класс .filter-grid (DEC-001 п.5).

   TASK-USLUGI-CATALOG (2026-07-08), пересмотр .filter-grid__items —
   flex-wrap-сироты (как у benefits_grid) ЗАМЕНЕНЫ на CSS Grid (I7,
   отклонение от прежнего решения, зафиксировано явно):
   - Сетка — часть слоя ОСНОВЫ, не стиля (DEC-001 положение 3: "слой основы
     несёт base (структура) И layout (сетка, контейнеры, адаптив)"); механизм
     раскладки живёт здесь, а не в styles/filter_grid/marina-glass.css.
   - grid, не flex, — потому что фильтруемый каталог с переменным числом
     видимых карточек (клик по пилюле прячет часть элементов через [hidden])
     не обязан центрировать неполный ряд, как это нужно benefits_grid/
     service_card-grid (статичная лента преимуществ/список услуг без
     скрытия элементов) — там сохранение центрирования сирот было явным
     требованием (см. acceptance.md обоих блоков). Каталогу естественнее
     поведение "лишние карточки просто уходят", без прыжка в центр строки
     при каждом переключении фильтра — auto-fill (не auto-fit) держит число
     треков по ширине контейнера независимо от текущего количества видимых
     карточек, так узкий отфильтрованный список не растягивается на всю
     строку гигантскими карточками.
   - `minmax(min(100%, var(...)), 1fr)` — стандартный приём против
     переполнения на очень узких экранах (без min(100%, …) карточка шире
     доступной ширины уводит контейнер в горизontal-scroll; правило 10
     CLAUDE.md требует ноль горизонтального скролла на всех ширинах).
   ========================================================================= */

.filter-grid__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--filter-grid-pill-gap, var(--s-2, 0.5rem));
  margin-bottom: var(--s-6, 1.5rem);
}

.filter-grid__pill {
  border: 1px solid var(--border-2, #d8c7b5);
  background: var(--bg-2, #fff);
  color: var(--fg-2, #555);
  border-radius: var(--r-pill, 999px);
  padding: var(--s-2, 0.5rem) var(--s-5, 1.25rem);
  font-size: var(--t-body-s, 0.9375rem);
  cursor: pointer;
  transition: background var(--t-fast, 140ms) var(--ease-out), color var(--t-fast, 140ms) var(--ease-out), border-color var(--t-fast, 140ms) var(--ease-out);
}
.filter-grid__pill:focus-visible { outline: 2px solid var(--fg-brand); outline-offset: 2px; }
.filter-grid__pill.is-active {
  background: var(--fg-brand, #9c6957);
  border-color: var(--fg-brand, #9c6957);
  color: var(--fg-on-dark, #fff);
}

.filter-grid__items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--filter-grid-card-min, var(--service-card-min, 17rem))), 1fr));
  align-items: stretch;
  gap: var(--filter-grid-gap, var(--s-6, 1.5rem));
}

/* justify-items оставлен на дефолте stretch (не переопределён): карточка
   заполняет свой трек по ширине и лишь СВЕРХУ ограничена собственным
   max-width (service_card: --service-card-max) — на обычных треках (уже
   max-width) это заполнение без зазоров; на редком сверхширoком треке
   (мало видимых карточек на очень широком экране) карточка просто
   останавливается на max-width и прижимается к левому краю трека —
   известный, не устраняемый без правки общего service_card CSS компромисс
   (I7), не влияет на функциональность и не создаёт горизонтальный скролл. */

.filter-grid__items > [hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .filter-grid__pill { transition: none; }
}

/* =========================================================================
   styles/filter_grid/marina-glass.css — «Сетка с фильтрами» манеры
   «Мягкое стекло» (TASK-USLUGI-CATALOG). Ровно один класс-модификатор
   .filter-grid--marina-glass (DEC-001 п.4/5), одна ступень специфичности
   поверх .filter-grid, без !important.

   Стиль красит только пилюли-фильтры (визуальное оформление — слой style
   по DEC-001 п.3); сетка карточек (layout) — уже CSS Grid в base.css этой
   основы, стиль её не трогает. Карточки внутри несут СВОЙ стиль
   .service-card--marina-glass (styles/service_card/marina-glass.css) —
   эта манера не переопределяет их.

   Источник приёмов — тот же словарь, что styles/service_card/marina-glass.css
   (эталон исполнения приёма K17): blur 12px (пилюля меньше карточки — блюр
   мельче, K17 не требует единого числа для всех форм-факторов), фон ≥50%
   непрозрачности, обязательный непрозрачный fallback ПЕРВЫМ. K13 — двойное
   фокус-кольцо. K16 — активная пилюля не несёт стекла (сплошной fg-brand,
   переход самой смены состояния — обычная скорость t-normal, не t-slow —
   пилюля лёгкий UI-элемент, не «тяжёлая» стеклянная поверхность карточки).
   ========================================================================= */

.filter-grid--marina-glass .filter-grid__pill {
  /* Fallback ПЕРВЫМ — непрозрачный bg-2 (K17). */
  background: var(--bg-2);
  border: none;
  color: var(--fg-2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
  transition: box-shadow var(--t-normal, 240ms) var(--ease-out),
              background-color var(--t-normal, 240ms) var(--ease-out),
              color var(--t-normal, 240ms) var(--ease-out),
              transform var(--t-fast, 140ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .filter-grid--marina-glass .filter-grid__pill {
    background: rgba(251, 248, 242, 0.55);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }
}

.filter-grid--marina-glass .filter-grid__pill:hover {
  color: var(--fg-brand);
  transform: translateY(-1px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .filter-grid--marina-glass .filter-grid__pill:hover {
    background: rgba(251, 248, 242, 0.7);
  }
}

/* Активная пилюля — сплошной фирменный цвет, НЕ стекло (K17 фон ≥50% всё
   равно не даёт достаточный контраст для белого текста поверх; активное
   состояние явно ярче нейтральных стеклянных). backdrop-filter снят явно —
   сплошной непрозрачный фон делает блюр позади бесполезным (GPU-нагрузка
   без видимого эффекта). */
.filter-grid--marina-glass .filter-grid__pill.is-active {
  background: var(--fg-brand);
  color: var(--fg-on-dark);
  box-shadow: var(--shadow-2);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.filter-grid--marina-glass .filter-grid__pill.is-active:hover {
  color: var(--fg-on-dark);
  transform: none;
}

/* K13: двойное фокус-кольцо — тот же инвариант доступности, что у прочих
   манер стекла (service_card, benefits_grid). */
.filter-grid--marina-glass .filter-grid__pill:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 4px var(--fg-brand);
}

@media (prefers-reduced-motion: reduce) {
  .filter-grid--marina-glass .filter-grid__pill,
  .filter-grid--marina-glass .filter-grid__pill:hover {
    transition: none;
    transform: none;
  }
}

/* =========================================================================
   bases/steps_timeline/base.css — структурный слой основы «Шаги и таймлайн»
   Специфичность: только базовый класс .steps-timeline (DEC-001 п.5).

   РЕЗИНА (FLG-003): типографика и отступы — clamp() с var()-границами, без
   промежуточных брейкпоинтов. РАСКЛАДКА: горизонталь на широких экранах,
   вертикаль на узких — это смена СТРУКТУРЫ, а не размера, поэтому
   единственный допустимый брейкпоинт (--bp-md, 960px, FLG-003 явно
   разрешает брейкпоинты «только для структуры») переключает flex-direction
   row → column. Между брейкпоинтом ничего не скачет: gap и калибр номера —
   clamp().
   ========================================================================= */

.steps-timeline-section {
  padding-block: var(--steps-timeline-section-padding-y, clamp(var(--s-12, 3rem), 2rem + 3vw, var(--s-20, 5rem)));
}

.steps-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--steps-timeline-gap, var(--s-10, 2.5rem));
}

/* Структурная смена раскладки — единственный брейкпоинт основы (FLG-003:
   брейкпоинты допустимы там, где меняется структура). */
@media (min-width: 960px) {
  .steps-timeline {
    flex-direction: row;
    /* stretch (не flex-start): карточки шагов в ряду равной высоты, нижние
       кромки не рваные (крафт-стандарт DEC-002 «ряд равной высоты»). */
    align-items: stretch;
    /* Резиновый gap в ряду (правка scan-prodazha-03): фиксированный s-10
       (2.5rem) ×(N−1) съедал ширину — при 5 шагах на 1024 крайний вылезал
       за вьюпорт. clamp сжимает промежуток на узком краю диапазона, на
       широком возвращает 2.5rem. */
    gap: clamp(var(--s-4, 1rem), 0.4rem + 1.6vw, var(--steps-timeline-gap, var(--s-10, 2.5rem)));
  }
}

.steps-timeline__step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-3, 0.75rem);
  flex: 1 1 0;
  /* min-width:0 (правка scan-prodazha-03) — иначе flex-basis:0 не даёт шагу
     сжаться ниже min-content (длинное слово заголовка), и ряд из 5 шагов
     распирал контейнер. С min-width:0 текст переносится, ряд всегда влезает. */
  min-width: 0;
  padding-inline-start: var(--s-6, 1.5rem);
  border-inline-start: 1px solid var(--steps-timeline-line-color, var(--border-2, #D8C7B5));
}

@media (min-width: 960px) {
  .steps-timeline__step {
    padding-inline-start: 0;
    padding-block-start: var(--s-6, 1.5rem);
    border-inline-start: none;
    border-block-start: 1px solid var(--steps-timeline-line-color, var(--border-2, #D8C7B5));
  }
}

.steps-timeline__number {
  font-family: var(--font-display, serif);
  font-size: var(--steps-timeline-number-size, clamp(var(--t-h2, 1.75rem), 1.2vw + 1.4rem, var(--t-display-m, 2.75rem)));
  font-weight: var(--w-light, 300);
  color: var(--fg-brand, #9C6957);
  line-height: 1;
}

.steps-timeline__title {
  margin: 0;
  font-size: var(--t-h4, 1.125rem);
  color: var(--fg-1, #111);
}

.steps-timeline__body {
  margin: 0;
  color: var(--fg-2, #555);
}

/* =========================================================================
   styles/steps_timeline/marina-glass.css — «Шаги и таймлайн» манеры
   «Мягкое стекло» (TASK-GLASS-CONTENT). Ровно один класс-модификатор
   .steps-timeline--marina-glass (DEC-001 п.4/5).

   НАХОДКА (I7, фиксирую явно, вне зоны правки этой ячейки): сборщик
   (site-factory/src/sitefactory/block_assembler.py, _kebab + style_class =
   f"{_kebab(block_id)}--{style}") ставит на корневой <section> класс
   "steps-timeline-section" (базовый, из bases/steps_timeline/base.html)
   ПЛЮС "{_kebab('steps_timeline')}--{style}" = "steps-timeline--{style}" —
   ДВА разных класса на одном элементе, не один составной
   "steps-timeline-section--{style}". Существующий соседний файл
   styles/steps_timeline/marina-dark.css целится в
   ".steps-timeline-section--marina-dark", которого сборщик никогда не
   генерирует — селектор там не совпадает ни с одним реальным элементом
   (проверено вычислением _kebab программно этой ячейкой). Это существующий
   баг библиотеки ВНЕ зоны данной задачи (правка чужого файла стиля другой
   манеры не входит в задание TASK-GLASS-CONTENT) — не чиню marina-dark.css
   молча, фиксирую находку в acceptance.md виджета и в докладе ячейки,
   решение о починке — за оркестратором/Владельцем. Свой НОВЫЙ файл строю
   на РЕАЛЬНОМ классе, который сборщик генерирует, — иначе манера не
   применится ни на одной странице, введённая специально для показа.

   Специфичность: одна ступень поверх .steps-timeline-section (базовый
   класс секции, присутствует на элементе одновременно с модификатором).
   Без !important.

   В отличие от marina-dark (тёмный фон cocoa-900, линия-разделитель между
   шагами) — эта манера светлая: каждый шаг становится собственной
   стеклянной плитой (K17), граница-разделитель base.css (border-inline-
   start/border-block-start) снимается, т.к. стекло само несёт кромку.
   Fallback непрозрачный ПЕРВЫМ.
   ========================================================================= */

.steps-timeline-section.steps-timeline--marina-glass {
  background: var(--bg-1);
}

.steps-timeline--marina-glass .steps-timeline__step {
  border-inline-start: none;
  border-block-start: none;
  padding: var(--s-6, 1.5rem);
  border-radius: var(--r-xl);
  /* Fallback ПЕРВЫМ (K17). */
  background: var(--bg-2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15),
              var(--op-shadow-1, var(--shadow-1));
  transition: box-shadow var(--t-slow, 420ms) var(--ease-out),
              transform var(--t-slow, 420ms) var(--ease-out),
              background-color var(--t-slow, 420ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .steps-timeline--marina-glass .steps-timeline__step {
    background: rgba(251, 248, 242, 0.62);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

.steps-timeline--marina-glass .steps-timeline__step:hover {
  transform: translateY(-3px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22),
              var(--op-shadow-2, var(--shadow-2));
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .steps-timeline--marina-glass .steps-timeline__step:hover {
    background: rgba(251, 248, 242, 0.74);
  }
}

.steps-timeline--marina-glass .steps-timeline__number {
  font-family: var(--font-display, serif);
  font-weight: var(--w-light, 300);
  color: var(--fg-brand, #9C6957);
}

.steps-timeline--marina-glass .steps-timeline__title {
  font-family: var(--font-display);
  color: var(--fg-1, #111);
}

.steps-timeline--marina-glass .steps-timeline__body {
  font-family: var(--font-body);
  color: var(--fg-2, #555);
}

@media (prefers-reduced-motion: reduce) {
  .steps-timeline--marina-glass .steps-timeline__step {
    transition: none;
  }
  .steps-timeline--marina-glass .steps-timeline__step:hover {
    transform: none;
  }
}

/* =========================================================================
   bases/benefits_grid/base.css — структурный слой основы «Сетка преимуществ»
   Специфичность: только базовый класс .benefits-grid (DEC-001 п.5).

   МЕХАНИЗМ СИРОТ (решено на уровне основы раз и навсегда — задание ячейки
   TASK-P3-CONTENT-1, двойной возврат ворот пилота unona был об этом же).

   ПЕРВАЯ ПОПЫТКА (отклонена после проверки браузером — фиксирую как
   отрицательный результат, I7, не молчу о неверном ходе): CSS Grid
   (repeat(auto-fit, minmax(...)) + justify-content: center) центрирует
   НАБОР ТРЕКОВ КОЛОНОК сетки целиком — один раз для всей сетки, а не
   отдельно для каждой визуальной строки. При 4 карточках в 3-колоннике
   неполный второй ряд (1 карточка) вставал в ПЕРВУЮ колонку сетки, не
   по центру — потому что Grid Layout не видит «неполные строки» как
   самостоятельную единицу для justify-content. Проверено инспектом в
   браузере на 1200px (карточка-сирота x=134, совпадает с первой
   колонкой обычного ряда, а не с центром своей строки) — не то, что
   требовалось.

   ПРИНЯТОЕ РЕШЕНИЕ: flexbox вместо grid. flex-wrap переносит карточки по
   строкам, а justify-content: center на контейнере центрирует КАЖДУЮ
   визуальную строку независимо (родное поведение flexbox, в отличие от
   grid) — включая неполный последний ряд, без JS и без подсчёта числа
   карточек на стороне рендера. Резина без брейкпоинтов сохранена: каждая
   карточка растёт/сжимается между --benefits-grid-card-min (15rem) и
   --benefits-grid-card-max (20rem) через flex-basis + max-width, перенос
   3→2→1 колонки происходит сам по ширине контейнера (дополнение
   Владельца — брейкпоинты только там, где меняется структура).

   Проверено в демо на 4 карточках в 3-колоннике (см. acceptance.md) —
   последняя карточка (4-я) стоит по центру во второй строке, не прижата
   к левому краю.
   ========================================================================= */

.benefits-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  /* CSS Grid, не flexbox (правка по арт-скану scan-prodazha-02): flexbox с
     flex-grow растягивал карточки НЕПОЛНОГО последнего ряда (напр. 4+3 или
     4+1) до max-width — карты между рядами получались разной ширины/высоты
     (сирота-карта шире соседних). Grid с auto-fill даёт РАВНЫЕ колонки во
     всех рядах; неполный ряд выравнивается по колонкам без растяжения.
     Ширина колонки — та же пара min/max (15–20rem), что была во flexbox. */
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--benefits-grid-card-min, 15rem), 100%), 1fr));
  align-items: stretch;
  gap: var(--benefits-grid-gap, var(--s-8, 2rem));
}

.benefits-grid__card {
  display: flex;
  flex-direction: column;
  gap: var(--s-3, 0.75rem);
  text-align: var(--benefits-grid-card-align, left);
}

.benefits-grid__icon {
  display: block;
  width: var(--benefits-grid-icon-size, 2.5rem);
  height: var(--benefits-grid-icon-size, 2.5rem);
  border-radius: var(--r-md, 8px);
  /* K9.2 (крафт-ремонт DEC-002): плоская заливка --bg-3 без иконки читалась
     как пустой/битый слот вне фирменной палитры (аудит, состояние «иконки
     вместо номеров»). Реального SVG-набора icons/ в репозитории нет — не
     выдумываю иконки без первоисточника (I2, честно зафиксировано в
     acceptance.md как отдельный вход). Минимально честный фикс здесь —
     фирменный градиент вместо плоского --bg-3, тот же приём тона, что и
     фото-плейсхолдеры карточек (service_card/team_grid), не пустая дыра. */
  background: linear-gradient(135deg, var(--blush-200, #ddd), var(--blush-400, #999));
}

.benefits-grid__number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--benefits-grid-icon-size, 2.5rem);
  height: var(--benefits-grid-icon-size, 2.5rem);
  border-radius: var(--r-pill, 999px);
  font-family: var(--font-display, serif);
  /* Резиновый калибр номера — clamp() между границами-токенами, без
     фиксированного скачка (дополнение Владельца, TASK-P3-CONTENT-1). */
  font-size: var(--benefits-grid-number-size, clamp(var(--t-body, 1rem), 1.2vw + 0.6rem, var(--t-h3, 1.375rem)));
  color: var(--fg-on-dark, #fff);
  background: var(--fg-brand, #9C6957);
}

.benefits-grid__title {
  margin: 0;
  font-size: var(--t-h4, 1.125rem);
  color: var(--fg-1, #111);
  /* K2.3/K7.4: заголовок непредсказуемой длины не расталкивает карточку
     выше соседей ряда — максимум 2 строки. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.benefits-grid__text {
  margin: 0;
  color: var(--fg-2, #555);
  /* Кламп описания снят (был 3 строки): на детальном контенте (оффер продажи
     студии) он резал текст «…». Равную высоту карточек в ряду держит
     align-items:stretch сетки — жёсткий клип для этого не нужен; короткие
     описания (напр. принципы косметики) визуально не меняются. */
}

/* =========================================================================
   styles/benefits_grid/marina-glass.css — «Сетка преимуществ» манеры
   «Мягкое стекло» (TASK-GLASS-CONTENT). Ровно один класс-модификатор
   .benefits-grid--marina-glass (DEC-001 п.4/5). Специфичность: одна ступень
   поверх .benefits-grid. Без !important.

   Эталон исполнения — styles/service_card/marina-glass.css (K17: blur
   12–20px, фон ≥50% непрозрачности, тонкая светлая кромка, обязательный
   непрозрачный fallback ПЕРВЫМ). Секция benefits_grid стоит на фоне
   .section--alt (sand, --bg-3) через чередование layout/base.css — именно
   там backdrop-filter визуально работает (research/best-practices.md §6:
   «на сплошном плоском цвете… визуально не работает» — sand достаточно
   отличается от прозрачного paper-стекла карточки, эффект виден).
   ========================================================================= */

.benefits-grid--marina-glass .benefits-grid__title {
  font-family: var(--font-display);
  font-weight: var(--w-medium);
}

.benefits-grid--marina-glass .benefits-grid__text {
  font-family: var(--font-body);
  line-height: var(--lh-normal);
}

.benefits-grid--marina-glass .benefits-grid__number {
  font-family: var(--font-display);
}

.benefits-grid--marina-glass .benefits-grid__card {
  /* Fallback ПЕРВЫМ (K17 обязательный fallback) — непрозрачный bg-2. */
  background: var(--bg-2);
  border: none;
  padding: var(--s-6, 1.5rem);
  border-radius: var(--r-2xl);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15),
              var(--op-shadow-2, var(--shadow-2));
  transition: box-shadow var(--t-slow, 420ms) var(--ease-out),
              transform var(--t-slow, 420ms) var(--ease-out),
              background-color var(--t-slow, 420ms) var(--ease-out);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .benefits-grid--marina-glass .benefits-grid__card {
    background: rgba(251, 248, 242, 0.62);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

.benefits-grid--marina-glass .benefits-grid__card:hover {
  transform: translateY(-3px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22),
              var(--op-shadow-3, var(--shadow-3));
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .benefits-grid--marina-glass .benefits-grid__card:hover {
    background: rgba(251, 248, 242, 0.74);
  }
}

/* K14: вложенный радиус ступенью меньше карточки (--r-2xl) — иконка/номер
   на --r-md/--r-pill, оба уже так заданы структурным base.css, стиль не
   переопределяет форму, только палитру/типографику (граница слоёв). */

/* K13: двойное фокус-кольцо на карточке, если она когда-либо становится
   фокусируемой (ссылка-обёртка вокруг карточки не входит в текущий
   контракт base.html — правило заготовлено на случай интерактивной
   карточки, безвредно при её отсутствии). */
.benefits-grid--marina-glass .benefits-grid__card:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg-3), 0 0 0 4px var(--fg-brand);
}

@media (prefers-reduced-motion: reduce) {
  .benefits-grid--marina-glass .benefits-grid__card {
    transition: none;
  }
  .benefits-grid--marina-glass .benefits-grid__card:hover {
    transform: none;
  }
}

/* =========================================================================
   bases/income_calculator/base.css — структурный слой основы «Калькулятор
   дохода» (TASK-INCOME-CALC-WIDGET). Специфичность: только базовый класс
   .income-calculator (DEC-001 п.5).

   Резина (CLAUDE.md, обязательное требование): типографика/отступы/крупная
   цифра результата — clamp() между токенами темы, ползунки — width:100%
   контейнера. Брейкпоинт --bp-md (960px, см. themes/marina/tokens.css)
   меняет ТОЛЬКО структуру (поля+результат: один столбец → два), не
   размеры — var() внутри @media-условия не поддерживается спецификацией
   CSS, поэтому значение хардкодится числом с комментарием (тот же приём,
   что bases/comparison_table/base.css).

   Цветовые зоны ползунка — decorative градиент на подложке под нативным
   треком (подложка непрозрачна и НЕ зависит от текущего значения —
   границы зон статичны, задаются один раз при рендере через
   --zone-green-end/--zone-yellow-end инлайн-стилем в base.html). Нативный
   track/thumb сброшены в transparent, чтобы подложка просвечивала —
   сам ползунок остаётся полностью функциональным (не decorative-имитация).
   ========================================================================= */

.income-calculator {
  display: flex;
  flex-direction: column;
  gap: var(--income-calculator-gap, clamp(1.25rem, 1rem + 1vw, 2rem));
}

/* --- Заголовок (props.heading — эта основа несёт свой, см. base.html) --- */

.income-calculator__eyebrow {
  margin: 0 0 var(--s-2, 0.5rem);
  font-size: var(--t-eyebrow, 0.75rem);
  font-weight: var(--w-semibold, 600);
  letter-spacing: var(--ls-eyebrow, 0.18em);
  text-transform: uppercase;
  color: var(--fg-brand, #9C6957);
}

.income-calculator__title {
  margin: 0 0 var(--s-2, 0.5rem);
  font-family: var(--font-display, serif);
  font-size: var(--fl-title-a, clamp(1.5rem, 1rem + 2vw, 2.25rem));
  color: var(--fg-1, #111);
}

.income-calculator__lede {
  margin: 0;
  max-width: 65ch;
  color: var(--fg-2, #555);
}

/* --- Раскладка: поля + результат. Один столбец мобильно, два столбца от
   структурного брейкпоинта 960px (--bp-md) — смена СТРУКТУРЫ, не размеров. */

.income-calculator__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--income-calculator-field-gap, clamp(1.5rem, 1rem + 2vw, 2.5rem));
  align-items: start;
}

@media (min-width: 960px) { /* --bp-md, themes/marina/tokens.css */
  .income-calculator__body {
    grid-template-columns: minmax(0, 1.3fr) minmax(280px, 360px);
  }
}

.income-calculator__fields {
  display: flex;
  flex-direction: column;
  gap: var(--s-8, 2rem);
  min-width: 0;
}

.income-calculator__field {
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
  min-width: 0;
}

.income-calculator__label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3, 0.75rem);
  font-size: var(--t-body-s, 0.9375rem);
  font-weight: var(--w-medium, 500);
  color: var(--fg-1, #111);
}

.income-calculator__echo {
  font-variant-numeric: tabular-nums;
  font-weight: var(--w-semibold, 600);
  color: var(--fg-brand, #9C6957);
  white-space: nowrap;
}

.income-calculator__hint {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
}

/* --- Цена сделки (radio-группа, ДОБАВЛЕНИЕ окупаемости, 2026-07-09). ---
   <fieldset> несёт UA-дефолты (border/padding/margin, min-width:
   min-content) — сбрасываются явно: min-width:0 обязателен, иначе
   fieldset отказывается сжиматься уже в grid/flex-контейнере на узких
   экранах (известный баг браузеров, ломает резину без этого сброса). */
.income-calculator__price-group {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.income-calculator__legend {
  padding: 0;
  width: 100%;
}

.income-calculator__price-option {
  display: flex;
  align-items: center;
  gap: var(--s-2, 0.5rem);
  padding-block: var(--s-1, 0.25rem);
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-1, #111);
  cursor: pointer;
}

.income-calculator__price-radio {
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  accent-color: var(--fg-brand, #9C6957);
  cursor: pointer;
}

.income-calculator__price-radio:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 2px;
}

/* --- Ползунки: на всю ширину контейнера (требование ячейки). --- */

.income-calculator__range-wrap {
  position: relative;
  display: flex;
  align-items: center;
  height: var(--income-calculator-thumb-size, 22px);
}

.income-calculator__range-wrap--zoned::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: var(--income-calculator-track-height, 6px);
  border-radius: var(--r-pill, 999px);
  pointer-events: none;
  /* Три статичные зоны (границы — из props.inputs.*.zones, посчитаны в
     base.html при рендере). Цвета — существующие семантические токены
     состояния (tokens.css), не изобретённые новые. */
  background: linear-gradient(
    to right,
    var(--positive, #7B8A6E) 0%,
    var(--positive, #7B8A6E) var(--zone-green-end, 40%),
    var(--warning, #C99A5B) var(--zone-green-end, 40%),
    var(--warning, #C99A5B) var(--zone-yellow-end, 70%),
    var(--critical, #B5544A) var(--zone-yellow-end, 70%),
    var(--critical, #B5544A) 100%
  );
  opacity: 0.85;
}

.income-calculator__range {
  width: 100%;
  margin: 0;
  position: relative;
  z-index: 1;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  cursor: pointer;
}

/* Трек нейтрального ползунка (без зон, напр. avg_check) — сплошной, на
   базовом токене границы. Зонированный трек прозрачен — просвечивает
   градиент подложки (::before выше). */
.income-calculator__range::-webkit-slider-runnable-track {
  height: var(--income-calculator-track-height, 6px);
  border-radius: var(--r-pill, 999px);
  background: var(--border-2, #D8C7B5);
}
.income-calculator__range-wrap--zoned .income-calculator__range::-webkit-slider-runnable-track {
  background: transparent;
}
.income-calculator__range::-moz-range-track {
  height: var(--income-calculator-track-height, 6px);
  border-radius: var(--r-pill, 999px);
  background: var(--border-2, #D8C7B5);
}
.income-calculator__range-wrap--zoned .income-calculator__range::-moz-range-track {
  background: transparent;
}

.income-calculator__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: var(--income-calculator-thumb-size, 22px);
  height: var(--income-calculator-thumb-size, 22px);
  margin-top: calc((var(--income-calculator-track-height, 6px) - var(--income-calculator-thumb-size, 22px)) / 2);
  border-radius: var(--r-pill, 999px);
  background: var(--fg-brand, #9C6957);
  border: 2px solid var(--paper, #FBF8F2);
  box-shadow: var(--shadow-2, 0 4px 14px rgba(58, 42, 36, 0.06));
}
.income-calculator__range::-moz-range-thumb {
  width: var(--income-calculator-thumb-size, 22px);
  height: var(--income-calculator-thumb-size, 22px);
  border-radius: var(--r-pill, 999px);
  background: var(--fg-brand, #9C6957);
  border: 2px solid var(--paper, #FBF8F2);
  box-shadow: var(--shadow-2, 0 4px 14px rgba(58, 42, 36, 0.06));
}

/* Видимый индикатор фокуса — НЕ подавлен (обязателен доступности). */
.income-calculator__range:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 4px;
}

/* --- Числовые поля (косметика, расходы). --- */

.income-calculator__number {
  width: 100%;
  box-sizing: border-box;
  padding: var(--s-3, 0.75rem) var(--s-4, 1rem);
  font: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--fg-1, #111);
  background: var(--bg-2, #FBF8F2);
  border: 1px solid var(--border-1, #E5DACB);
  border-radius: var(--r-md, 8px);
}

.income-calculator__number:focus-visible {
  outline: var(--focus-ring-width, 2px) solid var(--fg-brand, #9C6957);
  outline-offset: 2px;
}

/* --- Результат (панель с крупной цифрой + вердикт + оговорка). --- */

.income-calculator__result {
  display: flex;
  flex-direction: column;
  gap: var(--s-3, 0.75rem);
  padding: clamp(1.25rem, 1rem + 1.2vw, 2rem);
  border-radius: var(--income-calculator-result-radius, var(--r-lg, 14px));
  background: var(--bg-2, #FBF8F2);
  border: 1px solid var(--border-1, #E5DACB);
}

.income-calculator__net-label {
  margin: 0;
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
}

.income-calculator__net-value {
  margin: 0;
  /* Крупная цифра результата — резиновая, между границами-токенами, не
     разрывает вёрстку на узком (требование ячейки). */
  font-size: var(--income-calculator-net-size, clamp(1.75rem, 1.4rem + 1.8vw, 2.75rem));
  font-weight: var(--w-semibold, 600);
  font-variant-numeric: tabular-nums;
  color: var(--fg-1, #111);
  line-height: var(--lh-tight, 1.05);
  overflow-wrap: anywhere;
}

/* --- Окупаемость (ДОБАВЛЕНИЕ, 2026-07-09) — отдельная строка рядом с
   «Чистыми в месяц», не про усилие/нагрузку, поэтому НЕ несёт цветовую
   зону (нейтральный цвет текста результата). --- */

.income-calculator__payback {
  margin: 0;
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-1, #111);
  font-variant-numeric: tabular-nums;
}

.income-calculator__payback [data-role="payback-value"] {
  font-weight: var(--w-semibold, 600);
}

.income-calculator__payback-note {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
  /* Пусто, когда окупаемость посчиталась (net > 0) — пустой <p> без
     min-height не занимает видимого места, не оставляет "дыры" в макете. */
}

.income-calculator__verdict {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--s-2, 0.5rem);
  font-weight: var(--w-medium, 500);
  transition: color var(--t-fast, 140ms) var(--ease-out, ease);
}

.income-calculator__verdict-icon {
  font-size: var(--t-h4, 1.125rem);
  line-height: 1;
}

/* Цвет вердикта — тот же семантический токен, что и зоны ползунка (не
   изобретаю новую палитру). Слово в тексте остаётся источником смысла —
   цвет только усиливает, не единственный носитель (доступность/дальтоники). */
.income-calculator__verdict[data-zone="green"]  { color: var(--positive, #7B8A6E); }
.income-calculator__verdict[data-zone="yellow"] { color: var(--warning, #C99A5B); }
.income-calculator__verdict[data-zone="red"]    { color: var(--critical, #B5544A); }

.income-calculator__breakdown {
  margin: 0;
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
  font-variant-numeric: tabular-nums;
}

/* Короткая юр-оговорка ВНУТРИ панели результата (рядом с крупной цифрой и
   окупаемостью) — на десктопе (две колонки) полный дисклеймер под виджетом
   визуально далеко от числа; эта строка держит «не гарантия» у самой цифры
   (юр-ворота калькулятора, риск №4). */
.income-calculator__result-note {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
}

/* Предупреждения (лимит самозанятости, косметика-только-ИП) — заметны, но не
   кричат. Скрываются атрибутом hidden при неактуальности (сервер-рендер) /
   свойством hidden из behavior.js (живой пересчёт). */
.income-calculator__warning {
  margin: var(--s-2, 0.5rem) 0 0;
  padding: var(--s-2, 0.5rem) var(--s-3, 0.75rem);
  border-radius: var(--r-sm, 8px);
  background: var(--warning-soft, #F5EAD6);
  font-size: var(--t-caption, 0.8125rem);
  color: var(--warning-fg, #8A6320);
}
.income-calculator__warning[hidden] { display: none; }

/* Своя сумма косметики — отступ от радио-группы, disabled приглушён. */
.income-calculator__cosmetics-custom {
  margin-top: var(--s-2, 0.5rem);
}
.income-calculator__cosmetics-custom:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.income-calculator__noscript-note {
  margin: 0;
  font-size: var(--t-caption, 0.8125rem);
  color: var(--fg-3, #8B6F65);
}

/* --- График точки безубыточности (ДОБАВЛЕНИЕ, 2026-07-09). ---
   SVG через viewBox + width:100% + aspect-ratio, соответствующий viewBox
   (320/200 = 1.6) — резина без media-запросов: контейнер сжимается, SVG
   масштабируется целиком, включая текст внутри (координаты viewBox
   намеренно взяты БЛИЗКИМИ к минимальной поддерживаемой ширине 320px —
   подписи не становятся нечитаемо мелкими на узком экране; на широком
   экране те же подписи пропорционально крупнее — безопасный компромисс,
   см. docstring base.html). */

.income-calculator__chart-wrap {
  display: flex;
  flex-direction: column;
  gap: var(--s-3, 0.75rem);
}

.income-calculator__chart-title {
  margin: 0;
  font-family: var(--font-display, serif);
  font-size: var(--t-h4, 1.125rem);
  color: var(--fg-1, #111);
}

.income-calculator__chart {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 320 / 200;
}

.income-calculator__chart-axis {
  stroke: var(--border-2, #D8C7B5);
  stroke-width: 1;
}

.income-calculator__chart-tick {
  font-size: 11px;
  fill: var(--fg-3, #8B6F65);
}

.income-calculator__chart-income-line {
  fill: none;
  stroke: var(--fg-brand, #9C6957);
  stroke-width: 2.5;
  stroke-linecap: round;
  transition: none; /* координаты меняются мгновенно с пересчётом, без анимации рассинхрона с числами */
}

.income-calculator__chart-price-line {
  stroke: var(--fg-3, #8B6F65);
  stroke-width: 1.5;
  stroke-dasharray: 4 3;
}

.income-calculator__chart-price-label {
  font-size: 12px;
  font-weight: var(--w-medium, 500);
  fill: var(--fg-2, #555);
}

.income-calculator__chart-marker {
  fill: var(--fg-brand, #9C6957);
  stroke: var(--paper, #FBF8F2);
  stroke-width: 1.5;
}

.income-calculator__chart-marker-label {
  font-size: 12px;
  font-weight: var(--w-semibold, 600);
  fill: var(--fg-1, #111);
  text-anchor: middle;
}

/* Скрытие маркера, когда окупаемость вне видимого окна графика или
   чистыми ≤ 0 (base.html/behavior.js переключают этот класс) — display:none
   убирает узел из DOM-рендера полностью (не просто прозрачность), честно
   не рисуем маркер там, где линии не пересекаются в кадре. */
.income-calculator__chart-marker.is-hidden,
.income-calculator__chart-marker-label.is-hidden {
  display: none;
}

.income-calculator__chart-summary {
  margin: 0;
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
}

/* --- Юридическая оговорка (ФЗ-38) — обязана быть видна ВСЕГДА, спокойно,
   не мелким шрифтом-невидимкой и не кричаще (требование ячейки). --- */

.income-calculator__disclaimer {
  margin: 0;
  padding-top: var(--s-4, 1rem);
  border-top: 1px solid var(--border-1, #E5DACB);
  font-size: var(--t-body-s, 0.9375rem);
  color: var(--fg-2, #555);
  max-width: 70ch;
}

@media (prefers-reduced-motion: reduce) {
  .income-calculator__verdict {
    transition: none;
  }
}

/* =========================================================================
   styles/income_calculator/marina-glass.css — «Калькулятор дохода» манеры
   «Мягкое стекло» (TASK-INCOME-CALC-WIDGET, тот же приём, что уже несут
   comparison_table/price_table/steps_timeline/filter_grid — DEC-001 п.4/5:
   ровно один класс-модификатор .income-calculator--marina-glass).

   Специфичность: одна ступень поверх .income-calculator (базовый класс
   присутствует на корне ОДНОВРЕМЕННО с модификатором — контракт
   self_wrapped:false этой основы, см. base.html). Без !important.

   Стекло — на панели результата (визуальный якорь виджета: крупная цифра
   + вердикт), не на самих полях ввода (K18: стекло на каждом мелком
   элементе формы шумит и мешает читать значения при вводе). Fallback
   непрозрачный ПЕРВЫМ (K17).
   ========================================================================= */

.income-calculator--marina-glass .income-calculator__eyebrow {
  color: var(--fg-brand, #9C6957);
}

.income-calculator--marina-glass .income-calculator__title {
  font-family: var(--font-display, serif);
}

.income-calculator--marina-glass .income-calculator__result {
  border: none;
  border-radius: var(--r-xl, 22px);
  /* Fallback ПЕРВЫМ (K17). */
  background: var(--bg-2, #FBF8F2);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18),
              var(--op-shadow-2, var(--shadow-2));
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .income-calculator--marina-glass .income-calculator__result {
    background: rgba(251, 248, 242, 0.62);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}

/* Ползунки манеры «стекло» — тонкая стеклянная плита ПОД зонированной
   дорожкой (не поверх — зоны остаются читаемыми, см. K18 в docstring
   выше), только у зонированных полей (procedures/workdays). */
.income-calculator--marina-glass .income-calculator__range-wrap--zoned {
  border-radius: var(--r-pill, 999px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}

/* =========================================================================
   bases/text_block/base.css — структурный слой основы «Текстовый блок»
   Специфичность: только базовый класс .text-block (DEC-001 п.5). Регулируемое
   — через var() (DEC-001 п.12); значения падают на нейтральный fallback.
   ========================================================================= */

.text-block {
  display: flex;
  flex-direction: column;
  gap: var(--s-4, 1rem);
  max-width: var(--text-block-max-width, 72ch);
  color: var(--fg-2, #555);
  line-height: var(--lh-normal, 1.5);
}

.text-block__heading {
  margin: var(--s-2, 0.5rem) 0 0;
  color: var(--fg-1, #111);
}

.text-block__paragraph {
  margin: 0;
}

.text-block__list {
  margin: 0;
  padding-inline-start: var(--s-6, 1.5rem);
  display: flex;
  flex-direction: column;
  gap: var(--s-2, 0.5rem);
}

.text-block__list-item {
  margin: 0;
}

/* =========================================================================
   styles/text_block/marina.css — стиль «Marina» текстового блока (служебные
   юр-документы: политика ПДн и т.п.). Ровно один класс-модификатор
   .text-block--marina (DEC-001 п.4/5). Специфичность: одна ступень поверх
   .text-block. Без !important.

   Задача — читаемость длинного юридического текста: ограниченная ширина
   строки (мера), спокойный ритм абзацев, различимые подзаголовки и списки в
   палитре темы marina. Резина: всё регулируемое — через var()/clamp
   (DEC-001 п.12).
   ========================================================================= */

.text-block--marina {
  max-width: var(--measure-prose, 68ch);
  color: var(--fg-2, #555);
  font-family: var(--font-body);
  line-height: var(--lh-loose, 1.7);
}

.text-block--marina .text-block__heading {
  font-family: var(--font-display);
  font-weight: var(--w-medium, 500);
  font-size: var(--fl-20b, clamp(1.15rem, 1.05rem + 0.5vw, 1.4rem));
  color: var(--fg-1, #111);
  margin-block: clamp(var(--s-6, 1.5rem), 1rem + 1.5vw, var(--s-8, 2rem)) var(--s-2, 0.5rem);
}

.text-block--marina .text-block__heading:first-child {
  margin-block-start: 0;
}

.text-block--marina .text-block__paragraph {
  margin-block: 0 var(--s-4, 1rem);
}

.text-block--marina .text-block__list {
  margin-block: 0 var(--s-4, 1rem);
  padding-inline-start: var(--s-6, 1.5rem);
}

.text-block--marina .text-block__list li {
  margin-block: var(--s-1, 0.25rem);
}

.text-block--marina .text-block__paragraph:last-child,
.text-block--marina .text-block__list:last-child {
  margin-block-end: 0;
}
