/* ============================================================================
   График занятости «помещение × час» — публичный день.

   Форма взята из рабочего xlsx ЦРП: строки — пять помещений в том же порядке,
   колонки — часы 09:00–18:00 и отдельная колонка «Внеурочное время». Взгляд,
   привыкший к документу, не переучивается: те же строки, те же колонки, — и
   это главное требование к экрану (спека §4).

   Состояние слота различается формой, а цвет только подтверждает форму:
   свободно — пустая плитка, ожидает — штриховка, занято — заливка. Так
   состояние читается и без цвета, а цвет остаётся один — акцент.

   Плитка берёт заливку и тень из переменных --tile-* (tokens.css): сила
   глянца меняется одним классом на <html>, и ни одно правило здесь про
   уровень глянца не знает.
   ========================================================================= */

/* ── каркас дня ────────────────────────────────────────────────────── */

.schedule {
  /* Высота плитки одна на публичный график и админский календарь: день
     сравнивают между экранами, и разная высота строк ломает сравнение.
     66px — фактическая высота плитки макета, а не объявленный в нём
     min-height 58px: плитку распирает скрытый «+», который появляется на
     наведении, и вся сетка макета свёрстана по этой высоте. Здесь «+» нет
     (он вернётся вместе с формой заявки), но высоту задаём ту, которую в
     макете видно, — иначе сетка мельчает на восьмую часть. */
  --slot-h: 66px;
  /* Минимум под час — по плитке состояния: уже неё плитка превращается в
     цветное поле, а состояние обязано читаться и формой, и словом. */
  --slot-min: 3.5rem;
  /* Минимум колонки помещений — по самому длинному имени в одну строку.
     Замер в фирменном шрифте (15.5px/400, трекинг -.015em): «Переговорная
     № 2 (Б) верхняя» занимает 248px, плюс 28px отступов — 276px. При 15rem
     имя резалось многоточием, а режется оно на «верхняя/нижняя» — той части,
     по которой два помещения и различают. HoReCa шире системного шрифта на
     11%: прежний замер по системному шрифту больше не годится. */
  --grid-name: minmax(17.25rem, 1.7fr);
  --grid-after: minmax(6.5rem, .95fr);
  /* Шаблон колонок объявлен один раз, чтобы каждая строка сетки была той же
     самой сеткой, а не «похожей». */
  /* Дефолт — только для статичной витрины (static/demo): окно 09:00–18:00 даёт
     9 часовых колонок (последний слот 17:00–18:00). Живой экран всегда
     переопределяет --grid-cols инлайном из конфига (см. gridColsCSS). */
  --grid-cols: var(--grid-name) repeat(9, minmax(var(--slot-min), 1fr)) var(--grid-after);

  display: grid;
  gap: 22px;
  width: 100%;
}

/* ── полоса управления днём ────────────────────────────────────────── */

/* Навигация по датам слева, фильтр помещений справа. Это две независимые оси,
   и рядом они стоят, пока хватает ширины.

   Раскладка здесь на flex, хотя в остальном файле колонки собирает grid:
   нужно правило «фильтры переезжают на свою строку целиком, если не влезают
   рядом с датой», а такого grid не умеет — auto-fit переносит по одному
   элементу и не знает, что шесть чипов это одно целое. flex-wrap переносит
   их вместе, потому что min-width: max-content не даёт фильтрам сжаться
   ниже их натуральной ширины.

   Почему это не прихоть: у помещений официальные длинные имена («Переговорная
   № 2 (Б) верхняя»), шесть чипов занимают 1081px. В колонке рядом с датой им
   достаётся 615px — и они рвались на три ряда, поднимая полосу вдвое выше
   макета (195px против 94px). На своей строке все шесть встают в один ряд. */
.schedule-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  padding: 16px 18px;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md), 0 0 0 1px rgba(255, 255, 255, .8) inset;
}

/* Дата не сжимается и не растягивается: её ширина задана содержимым. */
.schedule-bar .date-nav {
  flex: none;
}

/* Фильтры просят столько, сколько занимают чипы в строку, но не больше
   полосы: min(max-content, 100%) — это «или во всю натуральную ширину, или
   во всю доступную». На широком экране побеждает первое (и фильтры уезжают
   на свою строку), на узком — второе, и дальше работает перенос по чипам.
   Без этого свойства flex-элемент молча сжался бы до остатка строки. */
.schedule-bar .filters {
  flex: 1 1 auto;
  min-width: min(max-content, 100%);
  justify-content: flex-end;
}

/* ── навигация по датам ────────────────────────────────────────────── */

.date-nav {
  display: grid;
  grid-template-columns: auto auto auto auto;
  align-items: center;
  gap: 10px;
}

/* Стрелка — квадрат цвета подложки с белой обводкой. Не белое на белом:
   едва серый тон и белая кромка дают объём, которого чистая заливка не даёт,
   а тень снизу доводит это до «выдавлено из фона». */
.date-step {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--color-text);
  background: var(--chip);
  border: 1px solid var(--chip-line);
  border-radius: var(--key-radius);
  text-decoration: none;
  box-shadow: 0 10px 18px -8px rgba(18, 24, 58, .34), 0 2px 3px rgba(18, 24, 58, .05);
  transition: color var(--dur-base) var(--ease), background var(--dur-base) var(--ease),
    box-shadow var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
}

.date-step:hover {
  color: var(--color-accent);
  transform: translateY(-1px);
  box-shadow: 0 8px 18px rgba(59, 91, 255, .26), 0 16px 34px rgba(18, 24, 58, .10);
}

.date-step:active {
  transform: translateY(1px);
  box-shadow: 0 2px 6px rgba(18, 24, 58, .12);
}

.date-step:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

.date-step svg {
  width: 18px;
  height: 18px;
}

/* Текущий день — единственный крупный текст в строке: он и есть заголовок. */
.date-current {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0 6px;
  min-width: 10rem;
}

/* День недели набран градиентом акцента: это подпись дня, и она единственная
   в панели носит цвет буквами, а не плашкой. */
.date-day {
  font-family: var(--font-head);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  background: var(--color-accent-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.date-full {
  font-family: var(--font-head);
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}

/* «Сегодня» — шайба: тёмный диск слева от подписи. Диск не украшение, а тот же
   орган управления, что и стрелки, только ведущий не на шаг, а к известной
   дате; поэтому он и выглядит предметом, а не текстом. */
.date-today {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 4px 16px 4px 4px;
  font-size: 16px;
  color: var(--color-text-soft);
  text-decoration: none;
  border-radius: 999px;
  transition: color var(--dur-base) var(--ease);
}

.date-today:hover {
  color: var(--color-text);
}

.date-today:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

/* Шайба: плоский матовый диск с подсвеченной кромкой. Слоёв два:
     1) сама шайба — ровное лицо плюс тёмная полоса по нижней кромке: она и
        читается как бок цилиндра, то есть как толщина;
     2) кольцо вокруг — тёплое слева, холодное справа, белая искра сверху.
   Кольцо сделано маской: радиальный градиент оставляет видимой только внешнюю
   полоску, поэтому под ним видно фон, а не заливку.
   Лицо залито по диагонали (152deg), а не сверху вниз: у вертикали ось
   совпадает с осью шара, и любой её перепад читается как объём шара, а не
   диска. Свет слева согласован с кольцом — там тоже тёплое слева. */
.today-orb {
  /* Свечения разведены по сторонам: холодное — вниз-вправо, тёплое —
     вверх-влево. Сдвиг по X и есть «сторона»: тень с нулевым сдвигом светит
     во все стороны кругом и читается нимбом, а не подсветкой кромки. */
  --orb-glow:
    3px 8px 18px -6px rgba(59, 91, 255, .7),
    0 0 16px -3px rgba(59, 91, 255, .35),
    -3px -6px 16px -8px rgba(242, 168, 60, .95),
    0 12px 20px -10px rgba(12, 16, 36, .6);
  position: relative;
  width: 54px;
  height: 54px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background:
    linear-gradient(180deg,
      rgba(6, 9, 22, 0) 70%, rgba(6, 9, 22, .45) 80%, rgba(3, 5, 12, 1) 100%),
    linear-gradient(152deg,
      #2E3866 0%, #262F58 32%, #1E2749 62%, #1A2244 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .14),
    inset 0 1px 0 rgba(255, 255, 255, .17),
    inset 0 -1px 0 rgba(255, 255, 255, .13),
    var(--orb-glow);
  transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
}

/* У конического градиента ноль — 12 часов, дальше по часовой: 90deg — справа,
   270deg — слева. Отсюда и стороны: янтарь слева, синева справа, искра сверху. */
.today-orb::before {
  content: '';
  position: absolute;
  inset: -3.5px;
  border-radius: 999px;
  background: conic-gradient(from 0deg,
    #FFFFFF 0deg,
    #B9CBFF 42deg, #7E9BFF 78deg, #3B5BFF 112deg,
    #2A3FD0 170deg,
    rgba(242, 168, 60, .8) 220deg, #FFCF7A 262deg, #F2A83C 302deg,
    #FFE9B8 334deg, #FFFFFF 360deg);
  -webkit-mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 3.5px), #000 calc(100% - 3px));
  mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 3.5px), #000 calc(100% - 3px));
  pointer-events: none;
}

.date-today:hover .today-orb {
  transform: translateY(-1px);
  --orb-glow:
    0 0 26px -2px rgba(59, 91, 255, .9),
    0 9px 20px -6px rgba(59, 91, 255, .7),
    0 -7px 20px -8px rgba(242, 168, 60, 1),
    0 14px 22px -10px rgba(12, 16, 36, .6);
}

.date-today:active .today-orb {
  transform: translateY(1px);
}

/* ── полоса недели ─────────────────────────────────────────────────── */

/* Семь дней подряд вместо одних стрелок: видно, что было и что будет, и не
   приходится щёлкать вслепую. Плитки гаснут у нерабочих дней — это ответ,
   который иначе пришлось бы добывать переходом. */
.week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 10px;
}

.week-day {
  display: grid;
  justify-items: center;
  gap: 2px;
  padding: 11px 6px 12px;
  color: inherit;
  text-decoration: none;
  background: var(--color-surface);
  border-radius: var(--radius-md);
  box-shadow: 0 3px 8px rgba(18, 24, 58, .06), 0 10px 22px rgba(18, 24, 58, .05);
  transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease),
    background var(--dur-base) var(--ease);
}

.week-day:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-sm);
}

.week-day:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

.week-dow {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.week-num {
  font-family: var(--font-head);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

/* Сегодня — обводка, выбранный — заливка. Два разных вопроса: «где мы» и
   «что открыто», и отвечать на них одним признаком нельзя. */
.week-day.is-today {
  box-shadow: 0 0 0 2px var(--color-accent), 0 8px 18px rgba(59, 91, 255, .18);
}

.week-tag {
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .02em;
  color: var(--color-accent);
}

.week-day.is-active {
  background: var(--color-accent-grad);
  box-shadow: 0 12px 26px var(--glow), 0 1px 0 rgba(255, 255, 255, .35) inset;
}

.week-day.is-active .week-dow,
.week-day.is-active .week-num,
.week-day.is-active .week-tag {
  color: #fff;
}

.week-day.is-weekend .week-dow {
  color: var(--color-accent-2);
}

/* Выходной приёма не ведёт — плитка гаснет, но остаётся ссылкой: в такие дни
   всё равно заходят посмотреть, что было. Число берёт --color-quiet, а не
   --color-muted: оно не читается, а узнаётся по форме плитки, и ему нужна
   бледность — у --color-muted теперь порог AA, а порог к погасшему не относится. */
.week-day.is-off {
  background: rgba(255, 255, 255, .5);
  box-shadow: none;
  opacity: .6;
}

.week-day.is-off .week-num {
  color: var(--color-quiet);
}

/* ── легенда ───────────────────────────────────────────────────────── */

/* Легенда переехала в app.css: те же четыре состояния расшифровываются и в
   панели, на мини-табло загрузки, а schedule.css грузится только публичной
   страницей. Два экземпляра одной легенды разошлись бы молча — метка должна
   учить тому же языку, что и сетка, на обоих экранах. */

/* ── сетка ─────────────────────────────────────────────────────────── */

.grid-wrap {
  width: 100%;
  overflow-x: auto;
  padding: 18px;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md), 0 0 0 1px rgba(255, 255, 255, .8) inset, var(--sh-halo);
  /* Горизонтальная прокрутка — единственная деградация на узком экране: день
     остаётся днём. Список карточек на телефоне читался бы легче, но сверить
     его с документом ЦРП уже нельзя, а сверка — смысл экрана. */
  overscroll-behavior-x: contain;
}

/* Сетка столбцов, а не строк: ряд — своя сетка с тем же шаблоном колонок,
   поэтому колонки выравниваются между строками, а роли row/cell остаются
   в дереве доступности (display: contents их оттуда выносит). */
.grid {
  display: grid;
  gap: 10px;
  min-width: 64rem;
}

.grid-row {
  display: grid;
  grid-template-columns: var(--grid-cols);
  gap: 10px;
}

/* Шапка сетки — не часы, а подписи часов: у неё нет ни плитки, ни состояния.
   Заголовок колонки помещений залипает вместе с нею самой: строки имён
   остаются на месте при горизонтальной прокрутке, и без этого шапка уезжала
   бы из-под них — колонка без названия. */
.grid-corner {
  position: sticky;
  left: 0;
  z-index: var(--z-sticky);
  display: grid;
  place-items: center start;
  padding: 2px 4px 8px 14px;
  background: var(--color-surface);
  font-family: var(--font-head);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* Цифры часов крупнее подписи под ними и набраны фирменным шрифтом: это
   единственные цифры, которые читают построчно, сверяя строку помещения со
   столбцом времени. 18px, а не 20px макета: при 20px «09:00» занимает 72px и
   не влезает в часовую колонку полной ширины (74px минус отступы). */
.grid-hour {
  display: grid;
  place-items: center;
  padding: 2px 4px 8px;
  font-family: var(--font-head);
  font-size: 18px;
  font-weight: 700;
  color: var(--color-text-soft);
  font-variant-numeric: tabular-nums;
}

/* Подпись внеурочной колонки мельче часовых: это не час, а раздел, и в две
   строки она переносится намеренно — «Внеурочное / время» читается, а
   «Внеурочн…» нет. */
.grid-hour-after {
  font-size: 12.5px;
  line-height: 1.2;
  text-align: center;
}

/* Колонка помещений залипает при горизонтальной прокрутке: на телефоне часы
   уезжают, а имя строки остаётся — иначе непонятно, чей это час. */
.grid-room {
  position: sticky;
  left: 0;
  z-index: var(--z-sticky);
  display: grid;
  align-content: center;
  gap: 3px;
  padding: 10px 14px;
  background: var(--color-surface);
}

/* Вес ровно 400, а не 600–700: у семейства есть только 400/700/800, и любой
   промежуточный вес браузер сводит к ближайшему файлу. Жирное имя при 276px
   доступной ширины обрезалось бы многоточием. */
.grid-room-name {
  font-family: var(--font-head);
  font-size: 15.5px;
  font-weight: 400;
  letter-spacing: -.015em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.grid-room-note {
  font-size: 12.5px;
  color: var(--color-muted);
}

/* ── знак помещения ────────────────────────────────────────────────── */

/* Знак заменяет имя строки на узком экране — там, где колонка имён шириной в
   256px забирала две трети экрана. На широком он скрыт: имя видно целиком, и
   второй способ назвать то же самое только спорил бы с первым. Показывает его
   медиазапрос ниже. */
.room-badge {
  display: none;
  place-items: center;
  position: relative;
  width: 40px;
  height: 40px;
  padding: 0;
  color: var(--color-text);
  background: var(--chip);
  border: 1px solid var(--chip-line);
  border-radius: 12px;
  cursor: pointer;
  transition: background var(--dur-base) var(--ease);
}

.room-badge:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

.room-mark {
  width: 22px;
  height: 22px;
}

/* Бабл — расшифровка знака: полное имя помещения по тапу. Справа от кнопки, а
   не над ней, потому что сетка прокручивается по горизонтали (.grid-wrap), и
   край обрезал бы всё, что вышло за её пределы; по горизонтали места хватает —
   сетка шире экрана ровно настолько, насколько нужно баблу. */
.room-bubble {
  position: absolute;
  left: calc(100% + 8px);
  top: 50%;
  transform: translateY(-50%);
  z-index: var(--z-sticky);
  display: none;
  padding: 7px 11px;
  white-space: nowrap;
  color: var(--color-text);
  background: var(--color-surface);
  border-radius: 10px;
  box-shadow: var(--shadow-md), 0 0 0 1px var(--chip-line);
  font-size: 13.5px;
}

.room-badge.is-open .room-bubble {
  display: block;
}

.grid-cell {
  display: grid;
  min-width: 0;
}

/* Внеурочное время — не час, а договорённость: в документе ЦРП это отдельная
   колонка. Плитка у неё та же, а содержимое — фраза («до 19:30»): время у
   вечерней брони не круглое, и «свободно/занято» по часу его не опишет. */
.grid-after {
  display: grid;
  place-items: center;
  min-height: var(--slot-h);
  padding: 0 8px;
  font-size: 12.5px;
  color: var(--color-muted);
  text-align: center;
  background: var(--tile-free-bg);
  border-radius: 15px;
  box-shadow: var(--tile-free-shadow);
}

.grid-after-busy {
  color: #fff;
  background: var(--tile-busy-bg);
  box-shadow: var(--tile-busy-shadow);
}

/* ── плитка слота ──────────────────────────────────────────────────── */

/* Слот — плитка, потому что его выбирают в следующем этапе; здесь он только
   читается, поэтому и разметка не обещает действия. Размеры, радиус и тени
   общие с легендой и внеурочной колонкой: это один предмет в трёх местах. */
.slot {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  min-height: var(--slot-h);
  padding: 0 4px;
  font-size: 12px;
  line-height: 1.2;
  color: var(--color-text-soft);
  background: var(--tile-free-bg);
  border: 1px solid transparent;
  border-radius: 15px;
  box-shadow: var(--tile-free-shadow);
  transition: background var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease);
}

/* Блик по диагонали: узкая светлая полоса сверху слева. Именно она делает
   из цветного прямоугольника клавишу. */
.slot::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--tile-sheen);
  pointer-events: none;
}

/* Кольцо показываем только при навигации с клавиатуры: по клику мыши оно
   мигает у всех подряд и мешает смотреть на сетку. */
.slot:focus {
  outline: none;
}

.slot:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  z-index: 2;
}

/* Свободно — единственное состояние, которое откликается на наведение:
   приглашение к действию должно быть слышно, а занятое — молчать. */
.slot-free {
  cursor: pointer;
}

.slot-free:hover {
  transform: translateY(-2px);
  background: var(--tile-free-hover);
  box-shadow: var(--tile-free-hover-shadow);
}

/* Ожидает подтверждения — штриховка: чужая несогласованная заявка видна, но
   не спорит с подтверждённой бронью и не запирает слот (спека §3). Слово на
   плите остаётся: штриховку заявитель может не знать, а состояние обязано
   читаться словом, а не узором. */
.slot-pending {
  color: var(--color-accent-dark);
  font-weight: 500;
  background: var(--tile-pend-bg);
  box-shadow: var(--tile-pend-shadow);
}

/* Занято — заливка: самый сильный знак в сетке достаётся самому твёрдому
   состоянию, всё остальное его не перебивает. */
.slot-busy {
  display: grid;
  grid-template-rows: auto auto;
  place-content: center;
  justify-items: center;
  gap: 6px;
  color: #fff;
  font-weight: 600;
  background: var(--tile-busy-bg);
  box-shadow: var(--tile-busy-shadow);
}

/* Счётчик занимает правый верхний угол, а содержимое занятой плитки — две
   строки по центру: вместе им шестидесяти шести пикселей не хватает, и цифра
   ложится на слово. Свободной плите счётчик не мешает — там одна короткая
   строка, — поэтому запас сверху берём только у занятой. */
.slot-busy:has(.slot-count) {
  padding-top: 22px;
}

/* Волна — знак «внутри идёт встреча»: состояние, переданное формой, а не
   цветом. Придумана взамен полупрозрачной каймы вокруг плитки: кайма выходила
   за сетку и на соседних занятых часах сливалась в пятно. */
.slot-wave {
  display: grid;
  place-items: center;
  color: #fff;
  opacity: .5;
  pointer-events: none;
}

.slot-wave svg {
  width: 40px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* На плоском глянце плитка теряет блик, и волне нужен вес побольше. */
html.gloss-flat .slot-wave {
  opacity: .66;
}

/* Счётчик заявок — углом плитки: две заявки и больше читаются числом, одна
   читается штриховкой, и цифра «1» на каждой ячейке была бы шумом. */
.slot-count {
  position: absolute;
  top: 6px;
  right: 7px;
  min-width: 20px;
  padding: 2px 6px;
  font-family: var(--font-head);
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1.4;
  text-align: center;
  color: #fff;
  background: var(--color-accent-grad);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 3px 8px var(--glow);
}

/* Значок «ваша» — углом плитки, напротив счётчика заявок. Словом, а не цветом:
   цвет на плите уже занят состоянием часа, и второй смысл в том же канале читался
   бы как ошибка состояния. Углом, а не строкой, — плитка шестьдесят шесть
   пикселей высотой, и третья строка выдавила бы надпись состояния наружу.
   У своей заявки места хватает обеим отметкам: счётчик справа, «ваша» слева. */
.slot-own {
  position: absolute;
  top: 6px;
  left: 7px;
  padding: 2px 7px;
  font-family: var(--font-head);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--color-accent);
  background: var(--color-surface);
  border-radius: 999px;
  box-shadow: 0 3px 8px var(--glow);
}

/* Прошедшее время — состояние дня, а не слота: оно гаснет, но не исчезает,
   день читается как хроника, а не как список доступного. Правило стоит последним
   в разделе: у него та же сила, что у состояний выше, и решает порядок.
   Цвет — --color-quiet: погасшее, а не приглушённое. Плитка прошедшего часа не
   нажимается и не читается по буквам, её узнают по фону подложки; дай ей порог
   AA — и день перестанет быть хроникой, а станет списком доступного. */
.slot-past {
  color: var(--color-quiet);
  background: var(--color-surface-alt);
  box-shadow: none;
  cursor: default;
}

.slot-past::before {
  background: none;
}

/* Прошедшая бронь остаётся различимой: по дню видно, что было занято. */
.slot-past.slot-busy {
  color: var(--color-accent-dark);
  background: var(--color-accent-soft);
}

.slot-past.slot-pending {
  background: repeating-linear-gradient(135deg, rgba(140, 150, 180, .3) 0 1.5px, transparent 1.5px 6px), var(--color-surface-alt);
}

.slot:disabled,
.slot[aria-disabled="true"] {
  cursor: default;
}

/* Режим без подачи: гость, заявитель без договора, отменённая подача. Слот не
   притворяется кнопкой — иначе наведение обещает то, чего система не сделает. */
.grid-readonly .slot-free {
  cursor: default;
}

.grid-readonly .slot-free:hover {
  transform: none;
  background: var(--tile-free-bg);
  box-shadow: var(--tile-free-shadow);
}

/* Свободный час со ссылкой — единственное действие сетки: ссылка обёрнута вокруг
   той же плитки, и правила «режима без подачи» гасят её заодно. Гашение
   снимается точечно здесь, а не отменой общего правила: там оно верное — гостю
   и вошедшему без договора плитка так и остаётся плиткой. */
.slot-link {
  position: relative;
  text-decoration: none;
  border-radius: 15px;
}

.grid-readonly .slot-link .slot-free {
  cursor: pointer;
}

.grid-readonly .slot-link .slot-free:hover {
  transform: translateY(-2px);
  background: var(--tile-free-hover);
  box-shadow: var(--tile-free-hover-shadow);
}

/* Кольцо рисуется на ссылке, а не на плите: фокус приходит к ссылке, и правило
   .slot:focus-visible до неё не достаёт. Показывается только при навигации с
   клавиатуры — как и в остальной сетке. */
.slot-link:focus {
  outline: none;
}

.slot-link:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  z-index: 2;
}

/* ── плашка-предупреждение ─────────────────────────────────────────── */

/* Белая лента с цветным свечением снизу: янтарным у предупреждения, синим у
   пояснения. Цвет у ленты не в заливке, а в подсветке кромки — так текст
   остаётся чёрным на белом, а состояние всё равно видно издалека. */
.notice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 18px;
  padding: 18px;
  font-size: 14px;
  background: var(--color-surface);
  border: 1px solid var(--chip-line);
  border-radius: var(--radius-lg);
  box-shadow:
    0 14px 30px -24px rgba(18, 24, 58, .6),
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 2px 4px rgba(18, 24, 58, .04);
}

.notice-warn {
  box-shadow:
    0 18px 30px -16px rgba(242, 168, 60, .95),
    0 34px 62px -34px rgba(242, 168, 60, .8),
    0 14px 30px -24px rgba(18, 24, 58, .6),
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 2px 4px rgba(18, 24, 58, .04);
}

.notice-info {
  box-shadow:
    0 18px 30px -16px rgba(59, 91, 255, .8),
    0 34px 62px -34px rgba(59, 91, 255, .6),
    0 14px 30px -24px rgba(18, 24, 58, .6),
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 2px 4px rgba(18, 24, 58, .04);
}

/* Знак — по высоте ленты: он должен читаться издалека, а не точкой у текста. */
.notice-mark {
  flex: none;
  width: 38px;
  height: 34px;
}

.notice-warn .notice-mark {
  filter: drop-shadow(0 8px 14px rgba(242, 168, 60, .8));
}

.notice-info .notice-mark {
  width: 30px;
  height: 30px;
  color: var(--color-accent);
  filter: drop-shadow(0 8px 14px rgba(59, 91, 255, .5));
}

.notice-body {
  display: grid;
  gap: 3px;
}

.notice-title {
  margin: 0;
  font-family: var(--font-head);
  font-size: 16.5px;
  font-weight: 700;
  letter-spacing: -.012em;
}

.notice-text {
  margin: 0;
  color: var(--color-text-soft);
}

/* ── форма заявки ──────────────────────────────────────────────────── */

/* Заявка — короткая анкета: две колонки на широком экране, одна на узком.
   Тянуть шесть полей в один столбец на 1080px значит заставлять глаз бегать. */
.form-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

.form-wide {
  grid-column: 1 / -1;
}

/* Длительность — выбор из четырёх, а не число: так заявитель не вводит
   полтора часа текстом, а правила помещения (мин/макс) видно сразу.

   Чипы переносятся на вторую строку, а не уезжают за край колонки: она уже,
   чем четыре подписи, и горизонтальная прокрутка прятала бы часть выбора —
   человек видел бы два варианта из четырёх и не знал об остальных. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.chip {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-soft);
  white-space: nowrap;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease);
}

.chip:hover {
  color: var(--color-text);
}

.chip:has(input:checked) {
  font-weight: 500;
  color: var(--color-accent-dark);
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
}

.chip:has(input:focus-visible) {
  box-shadow: var(--ring);
}

/* ── свотч категории (админский календарь) ─────────────────────────── */

/* Свотч — единственное место, где цвет что-то значит сам по себе, и потому он
   приглушён: рабочий цвет в интерфейсе занят состоянием. Различает категории
   текстовый код рядом, а свотч лишь помогает найти строку глазами. */
.cat-swatch {
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
  background: var(--cat-tint, var(--tint-quiet));
  border: 1px solid color-mix(in srgb, var(--color-text) 18%, transparent);
  border-radius: 3px;
}

.swatch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-2) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.swatch-item {
  display: flex; /* одномерная строка: свотч, код, расшифровка */
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-text-soft);
}

.swatch-item code {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text);
}

.tint-1 { --cat-tint: var(--tint-1); }
.tint-2 { --cat-tint: var(--tint-2); }
.tint-3 { --cat-tint: var(--tint-3); }
.tint-4 { --cat-tint: var(--tint-4); }

/* Погашенная категория: в справочнике она остаётся (на неё ссылаются
   подтверждённые брони), но в выборе больше не мешает. */
.swatch-off {
  opacity: 0.45;
}

/* ── узкий экран ───────────────────────────────────────────────────── */

@media (max-width: 900px) {
  /* Фильтры уже переехали на свою строку — здесь они ещё и перестают
     прижиматься вправо: на узком экране правый край не читается как ось, и
     рваный левый край выглядит случайным. */
  .schedule-bar .filters {
    justify-content: flex-start;
  }

  /* На узком четвёртая колонка (‹ дата › плюс «Сегодня») не влезала и вылезала
     за экран. Разносим: стрелки и дата — строка, «Сегодня» — под ними. */
  .date-nav {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  .date-today {
    grid-column: 1 / -1;
    justify-self: start;
  }

  /* Неделя в четыре колонки: семь плиток по 20px цифрой в строку не встают,
     а половинки дней читались бы хуже, чем два ряда. */
  .week {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  /* Имя строки на телефоне не помещается: 224px самого длинного имени — это
     больше половины экрана, и колонка имён, залипая при прокрутке, оставляла
     часам один столбец. Здесь имя уходит в бабл, а строку называет знак —
     сорок пикселей вместо двухсот пятидесяти шести.

     Различать строки это не мешает: знаки разные (см. roommarks.go), а полное
     имя приходит по тапу того же знака. */
  .schedule {
    --grid-name: 3.75rem;
  }

  .grid-room-name {
    display: none;
  }

  .room-badge {
    display: grid;
  }

  /* Отступы строки — под знак: имя ушло, и прежние 14px слева оставляли бы
     колонку с пустой полосой. */
  .grid-room {
    padding: 10px 8px;
  }

  /* Слово «Помещение» в сжатой колонке не влезает. Прячется глазами, но не из
     разметки: колонка обязана остаться названной для читалки с экрана. */
  .grid-corner {
    place-items: center;
    padding: 2px 4px 8px;
  }

  .grid-corner-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  /* Дата мельче и без запаса по ширине: вчетвером — шаг назад, шаг вперёд,
     дата и «Сегодня» — строка навигации иначе не влезает и обрезает кнопку. */
  .date-current {
    min-width: 0;
  }

  .date-full {
    font-size: 20px;
  }
}

/* Настройка «меньше движения». Длительности уже обнулены токенами
   (tokens.css) — здесь снимается то, что от них не зависит: плавная прокрутка
   сетки и любые появления, которые компонент мог бы завести себе сам. */
@media (prefers-reduced-motion: reduce) {
  .grid-wrap {
    scroll-behavior: auto;
  }

  .slot,
  .date-step,
  .week-day,
  .chip {
    transition: none;
    animation: none;
  }
}
