/* Кит серии: base.css — только сантехника. Ни одной композиции, ни одного размера, ни одного цвета.
   Здесь живёт то, что одинаково у любого сайта и чего не видно на кадре: сброс, фокус, цифры антиквы,
   поведение шапки, меню, нижней панели, форм, раскрытий, карты по клику и слой движения.
   Геометрию (ширину, сетки, шкалу кеглей, отбивки) и палитру задаёт css/site.css сборщика — см. README «Обязательные токены».
   Разметку сборщик компонует сам из blocks/. В проекте этот файл не правится.
   «ловушка:» у правила = запись из references/traps.md, которую это правило закрывает.
   Точки перелома ПОВЕДЕНИЯ: 1100 (меню уезжает в кнопку), 760 (нижняя панель). Композиция — на любых ширинах в site.css. */

/* ======================= ОБЯЗАТЕЛЬНЫЕ ТОКЕНЫ =======================
   Значения ниже намеренно сломаны. Кит не решает, как сайт выглядит: пока сборщик не задал свои
   в css/site.css, страница выглядит бракованной — и это видно в первом же кадре и в tools/sameness.js.
   Полный список с пояснениями — README, раздел «Обязательные токены». */
:root {
  --base: #ff00e4; --tint: #ff62f0; --card: #ffd9fb;            /* фоны */
  --ink: #2b002a; --muted: #7a0074; --line: rgba(43, 0, 42, .45);
  --brand: #00c2ff; --brand-ink: #000;                           /* акцент и текст на нём */
  --dark: #4b0047; --on-dark: #fff; --on-dark-muted: rgba(255, 255, 255, .7);
  --serif: serif; --sans: sans-serif;
  --wrap: 520px;                /* ширина колонки: у наших ручных сайтов от «без колонки» до 1560 */
  --pad: 6px; --sec: 8px; --gap: 4px;   /* поля, вертикаль секции, зазор групп */
  --top: 44px;                  /* высота шапки: от неё scroll-padding, якоря, панель меню */
  --r: 0; --btn-pad: 2px 6px;   /* радиус и поля кнопки */
  --h1: 21px; --h2: 19px; --h3: 17px; --lead: 15px;   /* шкала: у наших сайтов h1 от 48 до 140 px */
}
/* не сломаны: цвет ошибки — доступность, и высота панели, которой на широком экране нет */
:root { --bad: #a3372b; --dock: 0px; }

/* ======================= сброс и мелочь ======================= */
*, *::before, *::after { box-sizing: border-box; }
/* ловушка: фиксированная шапка прячет цель якоря, нижняя панель — поле формы */
html { -webkit-text-size-adjust: 100%; background: var(--base); scroll-padding-top: calc(var(--top) + 12px); scroll-padding-bottom: calc(var(--dock) + 12px); }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
body { margin: 0; background: var(--base); color: var(--ink); font: 400 17px/1.55 var(--sans); font-variant-numeric: lining-nums; }
[hidden] { display: none !important; }   /* ловушка: display:flex у компонента перебивает атрибут hidden */
img, svg, video, iframe { display: block; max-width: 100%; }
img { height: auto; }
h1, h2, h3, p, ul, ol, dl, dd, figure, blockquote, table { margin: 0; }
ul, ol { padding: 0; list-style: none; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--brand); text-decoration-thickness: 1px; text-underline-offset: .18em; }
a[href^="tel:"] { white-space: nowrap; }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
/* ловушка: антиква рисует старостильные цифры, «10» читается как «I O» */
h1, h2, h3 { font-family: var(--serif); font-weight: 300; line-height: 1.08; font-variant-numeric: lining-nums; font-feature-settings: "lnum" 1; text-wrap: balance; overflow-wrap: break-word; }
h1 { font-size: var(--h1); }
h2 { font-size: var(--h2); }
h3 { font-size: var(--h3); }
.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding-inline: var(--pad); }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: 12px; top: -80px; z-index: 110; padding: 10px 14px; background: var(--card); color: var(--ink); }
.skip:focus { top: 12px; }
/* ловушка: скрытый спрайт через display:none — часть движков не рисует его градиенты; а без position он занимает строку */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.nw { white-space: nowrap; }
.warn { color: var(--muted); }   /* «Имеются противопоказания…»: кегль и место — в site.css */
.foot .warn, .sec--dark .warn { color: var(--on-dark-muted); }

/* кнопка: хит-таргет и механика. Цвет, кегль, форма — site.css через токены */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 48px; padding: var(--btn-pad);
  border: 1px solid var(--brand); border-radius: var(--r); background: var(--brand); color: var(--brand-ink);
  font: inherit; text-align: center; text-decoration: none; cursor: pointer;
  transition: background-color .35s var(--motion-ease), border-color .35s var(--motion-ease), color .35s var(--motion-ease), box-shadow .35s var(--motion-ease), translate .35s var(--motion-ease); }
.btn--wide { width: 100%; }

/* ======================= шапка: только поведение ======================= */
/* Облик (сетка, кегли, знак, порядок) — blocks/header-*.css. Высота обязана прийти в --top: от неё зависят якоря и панель меню. */
.top { position: sticky; top: 0; z-index: 40; transition: box-shadow .5s var(--motion-ease), background-color .5s var(--motion-ease); }
.nav__btn, .nav__close { display: none; }
@media (max-width: 1100px) {
  .nav__btn { order: 3; display: grid; place-items: center; flex: none; width: 44px; height: 44px; }
  .nav__btn i, .nav__btn i::before, .nav__btn i::after { content: ""; position: relative; display: block; width: 22px; height: 1.5px; background: currentColor; transition: transform .35s var(--motion-ease), background-color .35s; }
  .nav__btn i::before { position: absolute; top: -7px; }
  .nav__btn i::after { position: absolute; top: 7px; }
  .is-menu .nav__btn i { background: transparent; }
  .is-menu .nav__btn i::before { transform: translateY(7px) rotate(45deg); }
  .is-menu .nav__btn i::after { transform: translateY(-7px) rotate(-45deg); }
  /* ловушка: меню на <details> пропадало на широком экране — без JS :target, с JS класс is-menu */
  .nav { position: absolute; inset: var(--top) 0 auto; display: none; flex-direction: column; align-items: stretch; gap: 0; max-height: calc(100svh - var(--top)); margin: 0;
    padding: 8px var(--pad) 20px; overflow: auto; background: inherit; }
  .nav:target, .is-menu .nav { display: flex; }
  .nav__close { display: block; }
  .is-js .nav__close { display: none; }
}

/* ======================= нижняя панель (телефон) ======================= */
.dock { display: none; }
@media (max-width: 760px) {
  /* ловушка: панель мигала, пока скрипт её прятал — по умолчанию скрыта сдвигом и visibility (не display: forms.js меряет рамку),
     показывает is-dock из app.js: в окне нет целой кнопки записи первого экрана, формы и подвала; пока фокус в форме — скрыта */
  .is-js .dock { position: fixed; inset: auto 0 0; z-index: 45; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px;
    height: calc(var(--dock) + env(safe-area-inset-bottom)); padding: 8px 10px calc(8px + env(safe-area-inset-bottom)); background: var(--dark);
    transform: translateY(100%); visibility: hidden; transition: transform .45s var(--motion-ease), visibility 0s linear .45s; }
  .is-dock .dock { transform: none; visibility: visible; transition: transform .45s var(--motion-ease), visibility 0s; }
  .is-dock:has(form:focus-within) .dock { transform: translateY(100%); visibility: hidden; transition: transform .45s var(--motion-ease), visibility 0s linear .45s; }
  .dock a { display: flex; align-items: center; justify-content: center; border: 1px solid rgba(255, 255, 255, .28); border-radius: var(--r); color: var(--on-dark); text-decoration: none; }
}

/* ======================= формы: поведение и доступность ======================= */
/* Облик коробки, сетка полей, кегль заголовка — blocks/form-*.css */
.form { display: grid; }
.field { display: grid; align-content: start; gap: 6px; }   /* в ряду поле без строки ошибки не растягивается */
.field input, .field select, .field textarea { width: 100%; min-height: 48px; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--ink) 28%, transparent);
  border-radius: var(--r); background-color: #fff; }
.field textarea { min-height: 110px; resize: vertical; }
/* ловушка: шорткат background сбрасывает repeat и position — у select только background-color и отдельные свойства */
.field select { appearance: none; padding-right: 40px; background-image: linear-gradient(45deg, transparent 50%, var(--brand) 50%), linear-gradient(135deg, var(--brand) 50%, transparent 50%);
  background-position: calc(100% - 20px) 55%, calc(100% - 14px) 55%; background-size: 6px 6px; background-repeat: no-repeat; }
.field :is(input, select, textarea):focus { border-color: var(--brand); outline: 2px solid color-mix(in srgb, var(--brand) 30%, transparent); outline-offset: 0; }
.field [aria-invalid="true"], .check:has([aria-invalid="true"]) input { border-color: var(--bad); outline-color: var(--bad); }
/* ловушка: строка ошибки исчезала и уводила чекбокс из-под пальца — высота строки зарезервирована, текст гасит app.js на input */
.err { display: block; min-height: 20px; color: var(--bad); font: 400 14px/20px var(--sans); }
/* чекбокс согласия 24 px, подпись нажимается целиком, хит-таргет ≥ 44 px; согласие не отмечено заранее */
.check { display: flex; align-items: flex-start; gap: 12px; min-height: 44px; padding-top: 8px; cursor: pointer; }
.check input { flex: none; width: 24px; height: 24px; margin: 0; accent-color: var(--brand); }
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
/* панель успеха — СНАРУЖИ скрываемой формы: без JS её открывает :target после 303 на #ok-<имя>, с JS — .is-sent */
.ok { display: none; }
.ok:target, .is-sent + .ok { display: block; }
.fbox:has(.ok:target) .form, .form.is-sent { display: none; }

/* ======================= раскрытия ======================= */
/* details — механика «видно немного, остальное на месте». Кегли, линии и отбивки — в CSS блока. */
details > summary { list-style: none; cursor: pointer; }
details > summary::-webkit-details-marker { display: none; }
/* ловушка: под .is-motion .more становится flex-колонкой, и закрытая кнопка растягивалась во всю ширину */
.more > summary { display: inline-flex; align-self: flex-start; align-items: center; min-height: 48px; cursor: pointer;
  transition: background-color .35s var(--motion-ease), color .35s var(--motion-ease), box-shadow .35s var(--motion-ease), translate .35s var(--motion-ease); }
.more[open] { display: flex; flex-direction: column; }
.more[open] > summary { order: 2; }
.more__open, .more[open] .more__closed { display: none; }
.more[open] .more__open { display: inline; }
.price > summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 56px; }
.price td { overflow-wrap: anywhere; }
.price td:last-child { text-align: right; white-space: nowrap; font-variant-numeric: lining-nums tabular-nums; }

/* ======================= карта и видео за клик ======================= */
/* до клика ни одного внешнего запроса; соотношение рамки — --embed-ratio в site.css */
.embed { position: relative; aspect-ratio: var(--embed-ratio, 16 / 10); background: var(--tint); }
.embed__btn { position: absolute; inset: 0; display: grid; place-content: center; justify-items: center; gap: 8px; width: 100%; border: 0; background: transparent; color: var(--brand); font: inherit; cursor: pointer; }
.embed__link { position: absolute; right: 12px; bottom: 12px; }
.embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ловушка: длинное слово распирает страницу — любая колонка сетки объявляется minmax(0, 1fr), в том числе в site.css */
.card, .quote, .fbox { min-width: 0; }

/* ======================= слой движения =======================
   Пара — app.js §6. Набор выбирает сборщик: <html data-motion-set="rise|mask|fade-scale|stagger-grid">.
   Без набора --motion-ease не определён: transition с ним недействителен, наведения стоят, появлений нет,
   motion-check краснеет. Это и есть требование выбрать набор, а не получить его молча.
   Прячет только html.is-motion (ставит app.js): без JS и при reduced-motion всё видно сразу. */
html[data-motion-set="rise"]         { --motion-dur: .8s;  --motion-ease: cubic-bezier(.2, .7, .2, 1);  --motion-shift: 26px; --motion-stagger: 80ms; }
html[data-motion-set="mask"]         { --motion-dur: .95s; --motion-ease: cubic-bezier(.33, 1, .68, 1); --motion-shift: 0px;  --motion-stagger: 0ms; }
html[data-motion-set="fade-scale"]   { --motion-dur: 1s;   --motion-ease: cubic-bezier(.16, 1, .3, 1);  --motion-shift: 0px;  --motion-stagger: 60ms; }
html[data-motion-set="stagger-grid"] { --motion-dur: .7s;  --motion-ease: cubic-bezier(.5, 0, .1, 1);   --motion-shift: 18px; --motion-stagger: 110ms; }
@media (max-width: 760px) { :root { --motion-shift: 14px; } }

.is-motion [data-m]:not(.is-in) { opacity: 0; }
/* ловушка: первый экран, спрятанный до JS или до заставки, — белый экран на медленной сети и битый LCP.
   Помеченные узлы героя стоят на месте; их вход начинает app.js §6б от старта ухода заставки, анимацией с fill: backwards */
.is-motion [data-hero] [data-m]:not(.is-in) { opacity: 1; }
.mw { display: inline-block; }   /* слово заголовка при входе по строкам */
/* фирменная деталь: контур знака. draw — дорисовывается, trace — по контуру бежит штрих, fill — знак наливается снизу */
[data-m="draw"] [pathLength] { stroke-dasharray: 1; }
[data-m="trace"] [pathLength] { stroke-dasharray: .14 .86; }
:is([data-m="draw"], [data-m="trace"], [data-m="fill"]) * { transform-box: fill-box; transform-origin: 50% 50%; }

a { transition: color .3s var(--motion-ease), text-decoration-color .3s var(--motion-ease), text-underline-offset .3s var(--motion-ease), opacity .3s var(--motion-ease); }
:focus-visible { transition: outline-offset .2s var(--motion-ease); }
@media (hover: hover) {
  .btn:hover, .more > summary:hover { translate: 0 -2px; box-shadow: 0 12px 24px -14px color-mix(in srgb, var(--dark) 70%, transparent); }
  .embed__btn { transition: background-color .35s var(--motion-ease); }
  .embed__btn:hover { background-color: color-mix(in srgb, var(--brand) 6%, transparent); }
}
.btn:active, .more > summary:active { translate: none; transition-duration: .1s; }
@media (max-width: 1100px) {
  .is-motion .nav { opacity: 0; translate: 0 -10px; transition: opacity .4s var(--motion-ease), translate .4s var(--motion-ease), display .4s allow-discrete; }
  .is-motion.is-menu .nav { opacity: 1; translate: none; }
  @starting-style { .is-motion.is-menu .nav { opacity: 0; translate: 0 -10px; } }
}
/* <details>: строка сетки ::details-content 0fr → 1fr, не height (ловушка: layout-transition); содержимое — один узел */
@supports selector(::details-content) {
  .is-motion details::details-content { display: grid; grid-template-rows: minmax(0, 0fr); overflow: clip; overflow-clip-margin: 6px;
    transition: grid-template-rows .45s var(--motion-ease), content-visibility .45s allow-discrete; }
  .is-motion details[open]::details-content { grid-template-rows: minmax(0, 1fr); }
  .is-motion .more { display: flex; flex-direction: column; }   /* «Свернуть» едет вместе со сворачиванием, а не прыгает */
}
.is-motion .is-sent + .ok { animation: m-up var(--motion-dur) var(--motion-ease) both; }   /* панель успеха поднимается на место формы */
@keyframes m-up { from { opacity: 0; translate: 0 var(--motion-shift); } }

/* ловушка: .01ms под reduced-motion давали переход на каждом узле — none */
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }
