/* 35-composition.css — накладной слой КОМПОЗИЦИИ трёх самых видимых экранов.

   Чем этот файл отличается от соседних. 00–30 переводили капсулу на светлый язык
   лендинга: цвета, поверхности, кегли, тач-цели. Структура экранов при этом осталась
   прежней — карточка входа, лента с одинаковыми интервалами и список обведённых
   прямоугольников на Холсте. Этот файл не меняет ни одного цвета, ни одной заливки и
   ни одного начертания: он занимается только шириной содержимого, вертикальным ритмом,
   длиной строки и группировкой. Ни одного hex и ни одного rgba здесь нет — все
   величины берутся из шкал 00-tokens.css (--sp-*, --r-*, --milk, --paper).

   Место в цепочке: 30-components.css → ЭТОТ ФАЙЛ → 40-mobile.css → 50-a11y.css →
   70-fixes.css. То есть файл перебивает компонентный слой, но сам уступает мобильному,
   доступности и финальным заплаткам. Это осознанно: ниже 760px композицию ведёт
   40-mobile.css, и здесь нет ни одного правила для узкого экрана.

   Ни один класс и ни один идентификатор не переименован: JS ищет узлы по ним
   (568 обращений через $() и 38 через $$()). Разметка не тронута — файл накладной,
   откат это снятие одного <link>. */


/* ==========================================================================
   1. ЭКРАН ВХОДА — из карточки в спокойную страницу
   Разметка: index.html:36–90. Три формы (#login-form:38, #invite-form:59,
   #invite-member-form:76) устроены одинаково: .brand-lockup → .login-copy →
   0…3 <label> → button.primary.wide → необязательный .text-button → p.error.
   Поэтому все правила ниже написаны на .login-card и на отношения соседства,
   а не на конкретный id: они работают для всех трёх, включая #invite-member-form,
   у которой полей нет вообще.
   Базовые стили: app.css:102–144.
   ========================================================================== */

/* Оболочка. app.css:103 задаёт grid + place-items:center + overflow:hidden.
   Центрирование через место в треке ломается, когда содержимое выше экрана:
   форма обрезается сверху и доскроллить до неё нельзя. Переходим на
   центрирование автополями — они поглощают только положительное свободное
   место, а когда содержимое выше контейнера, схлопываются в 0, и форма
   начинается от верхнего края и нормально прокручивается.
   overflow-x при этом остаётся hidden из app.css:103. */
.login-shell {
  overflow-y: auto;
  padding-block: var(--sp-7);   /* 48px — воздух главы вместо 24px по кругу */
}

/* Сама «карточка» перестаёт быть карточкой.
   Обводку и бумагу ей выдал 30-components.css:501–518 (общая группа карточек),
   скругление — app.css:125. По языку лендинга вход это страница, а не объект:
   LANDING_DESIGN_GUARDRAILS.md:31–33 прямо запрещает отдельные подложки-карточки.
   Поля остаются белыми (30-components.css:393–400) и на молочном фоне оболочки
   сами образуют второй блок — именно этим текст и разводится с полями. */
.login-card {
  width: min(100%, 400px);   /* было min(100%,432px) при padding:34px, то есть
                                мера строки 364px; убрав padding, отдаём эти 36px
                                самому содержимому и получаем спокойное поле */
  margin-block: auto;        /* см. комментарий к .login-shell */
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  gap: var(--sp-4);          /* 16px — базовый шаг ленты формы (было 17px) */
}

/* Крупный знак. app.css:47–52 задаёт 42px на все места использования сразу,
   поэтому увеличение строго ограничено экраном входа. */
.login-card .brand-mark {
  width: 52px;
  height: 52px;
}

.login-card .brand-lockup {
  gap: var(--sp-4);
}

/* Блок текста. app.css:128 задавал margin:14px 0 4px поверх общего gap —
   несимметричная величина мимо любой шкалы. Ритм внутри блока: 8 / 12.
   Заголовок ограничен по кеглю, потому что при clamp(38px,7vw,58px)
   из app.css:129 слово «Присоединиться» (14 знаков) на верхней ступени
   занимает около 400px и не помещается в меру ни при старой ширине 364px,
   ни при новой 400px. 42px дают около 306px — заголовок остаётся крупным,
   но перестаёт вылезать. Верх шкалы капсулы --fs-2xl это 34px
   (00-tokens.css:141), плакатных кеглей лендинга здесь по определению нет. */
.login-card .login-copy {
  margin: var(--sp-2) 0 0;   /* знак → текст = 16 + 8 = 24px */
}

.login-card .login-copy h1 {
  margin: var(--sp-2) 0 var(--sp-3);
  font-size: clamp(32px, 6vw, 42px);
}

/* Разведение текста и полей — главный смысловой шов экрана.
   Два селектора вместо одного, потому что у #invite-member-form (index.html:76–89)
   полей нет и после текста сразу идёт кнопка. */
.login-card > .login-copy + label,
.login-card > .login-copy + .primary {
  margin-top: var(--sp-4);   /* 16 + 16 = 32px */
}

/* Поля между собой держатся плотнее шва: 16px против 32px.
   Отдельного правила не требуется — это базовый gap. Пара «подпись + поле»
   внутри label остаётся плотнее обоих (7px, app.css:131), так что группировка
   читается однозначно. */

/* Одна кнопка. app.css:144 разгоняет ярлык и стрелку по краям через
   space-between; на кнопке шириной 400px это выглядит как растянутая полоса,
   а не как действие. Собираем ярлык и стрелку в центр. */
/* ИСПРАВЛЕНО ПОСЛЕ РЕВЬЮ: селектор .login-card > .primary.wide (0,3,0) стоял
   ниже и перебивал шов «текст → кнопка» (0,3,0 выше по файлу) у формы
   #invite-member-form, где полей нет вообще: задуманные 32px превращались в 24px.
   Отступ теперь задаётся только для случая, когда перед кнопкой реально стоит
   поле; форма без полей сохраняет свой шов. */
.login-card > label + .primary {
  margin-top: var(--sp-2);   /* поля → кнопка = 16 + 8 = 24px */
}

.login-card > .primary.wide {
  justify-content: center;
  gap: var(--sp-2);
}

/* Вторичное действие подчиняется кнопке, а не спорит с ней:
   ближе по вертикали и по той же оси. app.css:405 ставит его влево. */
.login-card > .primary + .text-button {
  justify-self: center;
  margin-top: calc(-1 * var(--sp-2));   /* 16 - 8 = 8px */
}


/* ==========================================================================
   2. ПРИВЕТСТВИЕ И ЛЕНТА
   #welcome — index.html:226–231 (.eyebrow, h1, p, .starter-prompts).
   Сообщение собирается в app.js:321–358: article.message + role, внутри
   .bubble, внутри .message-body. Роли ровно две — 'user' и 'assistant'
   (app.js:1483, 5725, 6557, 6559, 6941, 6947). Служебные варианты это тот же
   .message.assistant с добавленным классом: .action-receipt (app.js:1484),
   .memory-update-receipt (app.js:5727) и .micro-status (app.js:6560).
   Других классов на сообщение не вешается — поэтому здесь нет ни одного
   селектора, придуманного «на всякий случай».
   Базовые стили: app.css:504–543.
   ========================================================================== */

/* Приветствие уже сделано главой без коробки (70-fixes.css:183–189).
   Добавляем ему воздух сверху: глава должна начинаться не сразу под шапкой.
   Пишем именно margin-top, чтобы не сбить margin-inline:auto из app.css:509. */
.welcome-card {
  margin-top: clamp(var(--sp-6), 10vh, 88px);
}

/* Мера чтения.
   app.css:523 задаёт колонку 720px. За вычетом padding пузыря (18px по бокам,
   30-components.css:745) это около 684px, то есть примерно 82 знака при кегле
   16px (app.css:530) — заметно выше комфортного потолка. Колонка 620px даёт
   584px текста, ровно те же 66 знаков, что и правило ниже; два числа
   намеренно согласованы, а не независимы. */
.messages > .message {
  width: min(100%, 620px);
}

/* Собственно потолок строки. Единица ch взята не случайно: .message-body
   наследует кегль от .bubble (16px), поэтому 66ch здесь это действительно
   66 знаков текущего шрифта, а не пересчёт через пиксели.
   Блоки кода не страдают: у .bubble pre уже стоит overflow:auto (app.css:575),
   он прокручивается внутри меры. */
.message.assistant .message-body {
  max-width: 66ch;
}

/* РИТМ ЛЕНТЫ.
   В app.css:523 и 526 расстояние между всеми сообщениями одинаковое — 26px,
   и лента читается как список одинаковых объектов без границ ходов.
   Переводим весь ритм на верхний отступ следующего сообщения и обнуляем
   нижний: тогда каждое расстояние задаётся ровно одним правилом, а не суммой
   двух, и приведённые ниже величины и есть то, что видно на экране.
   Смысл шкалы: ответ агента принадлежит реплике человека (12px), а новая
   реплика человека открывает следующий ход (48px). */
.messages > .message {
  margin-bottom: 0;
}

.messages > .message + .message {
  margin-top: var(--sp-5);   /* 24px — соседи внутри одного потока */
}

.messages > .message.user + .message.assistant {
  margin-top: var(--sp-3);   /* 12px — ответ прижат к вопросу */
}

.messages > .message.assistant + .message.user {
  margin-top: var(--sp-7);   /* 48px — начался новый ход */
}

/* Квитанции и микростатус — не самостоятельные реплики, а приписка к
   предыдущему сообщению, и должны стоять к нему ближе всего.
   ИСПРАВЛЕНО ПОСЛЕ РЕВЬЮ: прежняя запись в четыре класса (0,4,0) проигрывала
   правилу «человек → агент» в пять классов (0,5,0) выше, и поскольку служебные
   сообщения создаются в app.js:6557 сразу после реплики человека, правило
   не срабатывало ни разу. Добавляем .assistant — служебное сообщение это
   всегда ассистент — и получаем (0,5,0) при более позднем положении в файле. */
.messages > .message + .message.assistant.action-receipt,
.messages > .message + .message.assistant.micro-status,
.messages > .message + .message.action-receipt,
.messages > .message + .message.micro-status {
  margin-top: var(--sp-2);   /* 8px */
}

/* РАЗЛИЧИЕ ПУЗЫРЕЙ БЕЗ ОБВОДОК.
   Заливки уже разведены в 30-components.css:744–756 (агент — бумага,
   человек — мята) и здесь намеренно не трогаются: цвет это чужая зона.
   Композиционный вклад этого файла другой — форма и положение.
   Реплика человека приходит справа и узкой (app.css:526, 533), ответ агента
   стоит слева во всю меру чтения. Скругление закрепляет это направление:
   у каждого пузыря угол со стороны собеседника притуплен до 4px.
   Приём структурный, а не декоративный: ни рамки, ни тени, ни стекла. */
.message.user .bubble {
  border-radius: var(--r-md) var(--r-md) var(--sp-1) var(--r-md);
}

.message.assistant:not(.micro-status):not(.action-receipt):not(.memory-update-receipt) .bubble {
  border-radius: var(--sp-1) var(--r-md) var(--r-md) var(--r-md);
}


/* ==========================================================================
   3. ХОЛСТ — группировка подложкой и отступом вместо обводок
   Разметка собирается в app.js:2016–2100 (.space-item), 2112–2135
   (.space-surface-summary и .space-surface-group). Внутри .space-item-header
   лежат: <div> с <strong> и необязательным <p> (app.js:2021–2029),
   необязательный .space-item-meta (2031–2036) и необязательный
   .space-winner-badge (2037–2043).
   Базовые стили: app.css:1218–1253. Контейнер прокрутки — .work-view
   (app.css:1194, padding 20px 22px 32px).

   СЕТКА НЕ ТРОГАЕТСЯ. Ширину панели считает JS: work-surface.js:3–16 задаёт
   границы (min 360, max min(760, ширина окна - 600)), defaultWorkSurfaceWidth
   их применяет, а app.js:590 пишет результат в --work-surface-width на
   #workbench; читает его app.css:649. Поэтому ниже нет ни одного объявления
   width, min-width и max-width, и .work-surface как узел не тронут вовсе.
   Всё, что здесь есть, — внутренние отступы и подложки, они переживают любую
   ширину панели от 360px и выше.
   ========================================================================== */

/* Расстояние между главами Холста. .work-canvas (app.css:1218) — прямой
   родитель именно тех узлов, ритм которых задан в задании, поэтому его gap
   и есть та величина, которой главы отделяются друг от друга. */
.work-canvas {
  gap: var(--sp-6);   /* 32px между сводкой и группами и между группами */
}

/* Сводка — заголовок главы, а не карточка. Отступ 2px 2px 4px из app.css:1220
   ни с чем не выравнивал: убираем его, и заголовок встаёт по краю содержимого
   панели, а карточки уходят внутрь на собственный padding. Это и создаёт
   иерархию «глава снаружи — материал внутри». */
.space-surface-summary {
  gap: var(--sp-1);   /* 4px: заголовок и его пояснение — одна пара */
  padding: 0;
}

/* Группа: подпись плотно ведёт свой список, элементы внутри держатся вместе. */
.space-surface-group {
  gap: var(--sp-2);   /* 8px — элементы одной группы читаются как один блок */
}

.space-surface-group > h4 {
  margin: 0 0 var(--sp-1);   /* подпись → первый элемент = 8 + 4 = 12px */
}

/* Карточка результата.
   Обводку ей вернул 30-components.css:501–506 (общая группа карточек): на
   бумажной панели (10-surfaces.css:277) бумажная карточка без рамки была бы
   не видна. Меняем приём целиком: карточка становится молочной, то есть на
   ступень ниже бумаги, и группируется подложкой, а не линией. Разделители в
   новом языке не нужны — LANDING_DESIGN_GUARDRAILS.md:35–36 запрещает
   разделительные полосы и швы.
   Гасим border-color, а не border: ширина рамки остаётся 1px, геометрия
   карточки не меняется ни на пиксель, и ничего не переезжает. */
.space-item {
  gap: var(--sp-2);                    /* 8px между строками карточки */
  padding: var(--sp-3) var(--sp-4);    /* 12px / 16px вместо 13px / 14px */
  border-color: transparent;
  background: var(--milk);
}

/* Режим полного холста: там сама панель уже молочная
   (10-surfaces.css:279), и молочная карточка на ней исчезла бы.
   Лестница переворачивается — карточка становится бумагой. */
.workbench.canvas-full .space-item {
  background: var(--paper);
}

/* ВНУТРЕННИЙ РИТМ КАРТОЧКИ: заголовок → текст → мета.
   В разметке мета лежит в шапке справа от текста (app.js:2030–2036), и на
   узкой панели — а она по work-surface.js:4 сжимается до 360px — короткая
   колонка меты отбирает ширину у заголовка. Переносим мету на собственную
   строку под текстом: получается ровно та последовательность, которая нужна,
   и заголовку возвращается вся мера. Порядок в DOM не меняется, JS ничего не
   замечает. */
.space-item-header {
  flex-wrap: wrap;
  align-items: baseline;      /* мета и бейдж садятся на базовую линию строки,
                                 а не на её верхний край */
  justify-content: flex-start;
  row-gap: var(--sp-2);
}

.space-item-header > div {
  flex: 1 1 100%;             /* заголовок с текстом занимают первую строку */
  gap: var(--sp-1);           /* 4px: пояснение принадлежит заголовку */
}

/* Действия отделены от содержимого заметнее, чем строки содержимого
   между собой: 8 + 4 = 12px. */
.space-item-actions {
  margin-top: var(--sp-1);
}


/* ==========================================================================
   ЧТО СОЗНАТЕЛЬНО НЕ ТРОНУТО

   1. Ширины и сетка Холста. Ни одного width / min-width / max-width в разделе 3
      и ни одного правила на сам .work-surface. Ширину панели считает
      work-surface.js:3–16 и записывает app.js:590 в --work-surface-width;
      любое объявление ширины здесь стало бы вторым источником правды и
      разошлось бы с JS при перетаскивании разделителя.

   2. Цвета, заливки пузырей, начертания и кегли — кроме одного случая.
      Заливки .message.user и .message.assistant оставлены как их развёл
      30-components.css:744–756, хотя задание разрешало трогать различие
      пузырей: цвет это зона соседнего файла, а различить их можно формой и
      положением, что и сделано. Единственное вмешательство в кегль —
      .login-copy h1: это не вкус, а невлезающая в меру строка, арифметика
      приведена на месте.

   3. Мобильные ширины ниже 760px. В файле нет ни одного @media. Ритм входа
      ниже 760px ведёт 40-mobile.css:555–560, радиусы — 00-tokens.css:202–209.
      Правила выше написаны на относительных мерах (min(100%,…), ch, clamp),
      поэтому мобильный слой их дожимает, а не воюет с ними.

   4. p.error в формах входа (app.css:46, index.html:57, 74, 88). Напрашивалось
      схлопнуть пустой параграф и убрать 36px под кнопкой, но у него
      role="alert": элемент, скрытый через display:none, выпадает из дерева
      доступности, и объявление ошибки становится ненадёжным. Тихий отступ
      под кнопкой дешевле сломанного оповещения. Зона доступности — 50-a11y.css.

   5. Служебные сообщения ленты как объекты: .action-receipt,
      .memory-update-receipt и .micro-status получили только новое расстояние
      сверху (иначе отрицательный отступ app.css:544 наложил бы их на
      предыдущее сообщение). Их собственные размеры, заливки и кегли —
      app.css:544–552 и 30-components.css:810 — не тронуты.

   6. .login-orbit, .boot-cosmos, .ambient-grid и прочие декоративные слои
      тёмной темы. Они уже погашены в 10-surfaces.css:131 и 70-fixes.css:117;
      композиции они больше не касаются.

   7. Мера текста приветствия. app.css:511 держит .welcome-card > p
      в min(470px,100%), то есть около 56 знаков при кегле 16px — потолок в
      66 знаков уже соблюдён, и трогать величину было незачем.

   8. Разметка, имена классов и идентификаторов, порядок узлов в DOM.
      Мета на Холсте переставлена визуально через flex-wrap, а не изменением
      порядка элементов. */
