/* ===== ТАБЛО У КАБИНЕТА · финальный макет заказчика (DESIGN §6f, docs/board/mockup-final.html) =====
   Вёрстка перенесена из макета один в один: те же классы, структура, цвета, скругления и пропорции.
   Разница одна — единицы. Макет свёрстан в px для сцены 1280×800; здесь все размеры поделены на 16
   и записаны в rem, а корневой кегль привязан к окну:
       html { font-size: min(100vw / 80, 100vh / 50) }
   На 1280×800 это ровно 16 px (1:1 с макетом), на 1280×752 — 15,04, на 1920×1080 — 21,6.
   Никаких transform-сцен и полей-леттербоксов: сетка растягивается, пропорции сохраняются.
   Портрет (800×1280) — колонки становятся рядами, блок очереди снизу (@media orientation:portrait).
   Комментарии-обоснования из макета сохранены: они объясняют решения по брендбуку и контрасту. */

/* Корневой кегль: 80 колонок по ширине и 50 по высоте — это и есть сцена макета 1280×800 в rem.
   Берётся меньшее, поэтому на любом отношении сторон сцена целиком помещается в экран,
   а в высоту всегда ровно 50rem — значит вертикальная раскладка макета не ломается никогда. */
html { font-size: min(100vw / 80, 100vh / 50); }

/* Палитра макета. Имена — как в mockup-final.html, чтобы правила читались рядом с исходником.
   Объявлены на теле страницы, а не в :root: --ok/--warn/--crit макета (статусные цвета, согласованное
   расширение палитры) не совпадают с одноимёнными токенами brand.css, и перекрывать их глобально нельзя. */
body.board-page {
  --azure: #0FC7CE;        /* лазурный — основной цвет бренда */
  --shell: #F7F8FC;        /* скорлупа — фон экрана */
  --blue-l: #DBF5FF;       /* светло-голубой — фон, стр. 53 */
  --viol-l: #E2E8FD;       /* светло-васильковый */
  --green-m: #37A3B6;      /* средне-зелёный — только элементы, текстом быть не может */
  --green-d: #1B5A61;      /* тёмно-зелёный — подписи и вторичный текст */
  --viol-d: #001045;       /* тёмно-васильковый — числа и заголовки */
  --coal: #393939;         /* уголь */
  --ok: #137A52; --warn: #8F5C00; --crit: #B02F26;   /* статусные цвета — расширение палитры */
  --grey-b: #E4E9F0;       /* нейтральный фон блока очереди и плашки номера кабинета */
  --card-w: #FFFFFF;
  --sans: var(--font);     /* Manrope уже локальный в brand.css, внешних шрифтов нет */
  font-size: 1rem;
  background: var(--shell);
  color: var(--coal);
  line-height: 1.3;
  font-family: var(--sans);
  overscroll-behavior: none;
}
body.board-page * { box-sizing: border-box; }
/* [hidden] должен побеждать классы с собственным display: .tbtns, .tmeta, .tscan и прочие объявлены
   флексами, и скрытый через hidden блок иначе остаётся в потоке со своими полями (на экране «Вы в
   очереди» пустой ряд кнопок сдвигал весь центрированный столбец на 12 px вверх). */
body.board-page [hidden] { display: none; }

/* Сцена макета = весь экран планшета. Рамка корпуса, скругление и тень из прототипа не переносятся. */
.tstage { position: relative; flex: 1; min-height: 0; overflow: hidden; background: var(--shell); }

/* ---------- экраны ---------- */
.tscr { position: absolute; inset: 0; display: none; flex-direction: column; padding: 2rem; }
.tscr.on { display: flex; }
/* Дежурный экран — исключение: он не прячется через display:none, потому что внутри живёт <video>
   сканера, а элемент вне дерева отрисовки перестаёт получать кадры (§6d, «видео НЕ прятать»).
   Он остаётся в раскладке под активным экраном, но прозрачен и не принимает касания. */
#t-queue { display: flex; opacity: 0; pointer-events: none; }
#t-queue.on { opacity: 1; pointer-events: auto; }

/* ---------- нижняя полоса: кабинет и врач ----------
   Колонки 33rem / 1fr те же, что у рабочего поля .tmain, хотя левая теперь пуста:
   белый блок кабинета остаётся ровно под блоком очереди, как и договаривались.
   Сканер уехал внутрь блока «В очереди» и в полосе больше не участвует.
   Полоса идёт последней в разметке каждого экрана, поэтому flex прижимает её к низу. */
.tbar { display: grid; grid-template-columns: 33rem minmax(0, 1fr); align-items: stretch; gap: 1.5rem; flex: none;
  min-height: 7.5rem; padding-top: 1.5rem; }
/* 1,75rem и перенос на две строки: помещается «Врач функциональной диагностики» */
.tfn { font-size: 1.75rem; font-weight: 700; line-height: 1.15; letter-spacing: -.01em; color: var(--viol-d);
  margin: 0; }

/* Сканер: белый субблок в подвале блока «В очереди».
   Субблок белый, и талоны очереди белые: без отбивки нижний ряд втекал в него одним пятном,
   а сам субблок читался как продолжение карточки. Поэтому он стоит ВНУТРИ падингов карточки,
   вровень с плашками талонов: левый и правый край совпадают с краями талонов, снизу те же 1,5rem,
   что у карточки, сверху 1,5rem серого фона отделяют его от последнего ряда.
   Радиус 1rem — как у талонов: субблок читается как элемент того же ряда.
   Прижимает субблок к низу не margin-top:auto, а flex:1 у списка талонов: auto занял бы верхнее
   поле, и полосы фона над субблоком не осталось бы.
   Без сканера (?scan=0) субблока нет вовсе — display:none, а не visibility: пустая белая плашка
   обещала бы пациенту действие, которого нет. */
.tqueue { flex: 1; }
.tscan { margin: 1.5rem 0 0; display: flex; align-items: center; gap: 1.5rem;
  background: var(--card-w); border-radius: 1rem; padding: 1.25rem 1.5rem; min-width: 0;
  -webkit-user-select: none; user-select: none; }
.tscan.off { display: none; }
/* камера сведена к квадрату и стоит у левого края субблока.
   ОТСТУПЛЕНИЕ ОТ ПАЛИТРЫ, согласовано: это не элемент интерфейса, а место
   живой картинки с камеры. Любой цвет из палитры читался бы как акцент. */
.tcam { position: relative; display: block; flex: none; width: 7.5rem; aspect-ratio: 1;
  background: #D9DDE3; border-radius: 1rem; overflow: hidden; }
.tcam i { position: absolute; width: 1.5rem; height: 1.5rem; border: .25rem solid #5A6B75; z-index: 3; }  /* 4,06 на плейсхолдере */
.tcam i:nth-of-type(1) { top: .75rem; left: .75rem; border-right: 0; border-bottom: 0; border-radius: .5rem 0 0 0; }
.tcam i:nth-of-type(2) { top: .75rem; right: .75rem; border-left: 0; border-bottom: 0; border-radius: 0 .5rem 0 0; }
.tcam i:nth-of-type(3) { bottom: .75rem; left: .75rem; border-right: 0; border-top: 0; border-radius: 0 0 0 .5rem; }
.tcam i:nth-of-type(4) { bottom: .75rem; right: .75rem; border-left: 0; border-top: 0; border-radius: 0 0 .5rem 0; }
/* Живое видео заполняет квадрат целиком (object-fit: cover), уголки остаются поверх (§6f).
   Фронтальная камера — зеркально, как в зеркале; кадры для распознавания берутся из потока как есть.
   До первого кадра видео прозрачно, и сквозь него виден плейсхолдер #D9DDE3. */
.tcam .tvid { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; z-index: 1; }
.tscan.mirror .tvid { transform: scaleX(-1); }
.tscan.nocam .tvid { display: none; }
/* Бегущая линия сканирования — только при живой камере: пустой плейсхолдер её не заслуживает. */
.tscanline { position: absolute; left: 0; right: 0; top: 0; height: .25rem; z-index: 2; opacity: 0;
  background: linear-gradient(90deg, rgba(15,199,206,0), var(--azure), rgba(15,199,206,0)); }
.tscan.live .tscanline { opacity: 1; animation: tscan 2.4s ease-in-out infinite; }
@keyframes tscan { 0%, 100% { transform: translateY(.75rem); } 50% { transform: translateY(6rem); } }
/* Отклик при распознавании: квадрат вспыхивает лазурным и показывает галочку (§6c). */
.tcamhit { position: absolute; inset: 0; z-index: 4; display: flex; align-items: center; justify-content: center;
  background: var(--azure); color: var(--viol-d); opacity: 0; transition: opacity .18s; }
.tcamhit svg { width: 3.5rem; height: 3.5rem; }
.tscan.hit .tcamhit { opacity: .92; transition: none; }
@media (prefers-reduced-motion: reduce) { .tscan.live .tscanline { animation: none; } }
/* подпись рядом с камерой, а не под ней: 1,75rem тёмно-зелёным на белом — 7,83, AAA */
/* перенос задан <br>, а не шириной блока: строки делятся по смыслу —
   что сделать, и зачем. Балансировать нечего, поэтому text-wrap не нужен */
.tscap { margin: 0; font-size: 1.75rem; font-weight: 600; line-height: 1.25; color: var(--green-d); min-width: 0; }
/* Когда сканера нет, подпись длиннее призыва и в 1,75rem ломается посреди слова.
   1,5rem — нижняя граница body планшета по таблице расстояний, и она здесь оправдана:
   это сообщение читает тот, кто уже подошёл вплотную и пытался приложить талон,
   а не человек через коридор. Контраст тот же 7,83 — AAA. */
.tscan.nocam .tscap { font-size: 1.5rem; }

/* кабинет, специализация и врач — одним белым блоком по правой колонке.
   Остаётся только в нерабочих состояниях: на дежурном экране эти сведения
   переехали в шапку карточки «Идет прием».
   grid-column:2 обязателен: сканер ушёл из полосы, и без него блок встал бы
   в первую колонку — под карточки вызова вместо блока очереди */
.tdoc { grid-column: 2; background: var(--card-w); border-radius: 1.5rem; padding: 1.25rem 2rem; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: .75rem; }
.tdocmain { display: flex; align-items: baseline; gap: 1.25rem; min-width: 0; flex-wrap: wrap; }
/* разделитель между специализацией и ФИО — тот же, что между номером и специализацией */
.tdiv { font-style: normal; font-size: 1.75rem; color: var(--green-d); opacity: .5; }

/* ---------- блок кабинета: отдельная белая карточка под «Следующим» ----------
   Ширина по левой колонке, 33rem; под текст остаётся 29rem, поэтому кегли
   ниже, чем были в нижней полосе: номер 2rem вместо 2,5, специализация и ФИО
   1,5rem вместо 1,75. 1,5rem — это body планшета по таблице расстояний, то есть
   нижняя граница, а не произвольное уменьшение: сведения служебные и читаются
   с 0,5–1 м, тогда как статус и номера рассчитаны на 2,4–4,8 м.
   Текст стандартный тёмно-васильковый: на белом 18,10, AAA.
   Строка переносится на длинной специализации — высоту держит содержимое.
   Две части: текст слева, знак справа. Текст переносится внутри своего
   блока, поэтому знак остаётся у правого края при любом числе строк.
   flex-direction:row обязателен: базовое .tcard объявлено НИЖЕ в файле
   и задаёт column — без явного row знак встал бы под текстом */
.tcard.room { display: flex; flex-direction: row; align-items: stretch; gap: 1rem;
  padding: 1.25rem 1.5rem; min-width: 0; }
/* column, а не wrap: ФИО всегда на второй строке, а не «когда не поместится».
   Так блок не прыгает между одно- и двухстрочным видом при смене врача */
.roomtext { display: flex; flex-direction: column; gap: .25rem; min-width: 0; flex: 1; }
/* Разделитель после номера кабинета скрыт: специализация теперь стоит
   в той же строке, а не отделяется от ФИО, и на длинном названии точка
   повисала в конце строки. В нижней полосе нерабочих состояний он остаётся */
.roomtext .troom { flex-wrap: wrap; gap: .75rem; }
.roomtext .troom i { display: none; }
.tcard.room .troom { font-size: 1.5rem; gap: 1rem; color: var(--viol-d); }
/* Номер кабинета — в серой плашке #E4E9F0, тот же серый, что у блока очереди.
   Радиус 999px: плашка скругляется по своей высоте, как теги статуса в
   нерабочих состояниях. Кегль снижен с 2 до 1,5rem, вровень со специализацией:
   плашка выделяет номер сама, дублировать выделение размером не нужно.
   Тёмно-васильковый на #E4E9F0 даёт 14,84 — AAA. */
.tcard.room .troom b { font-size: 1.5rem; color: var(--viol-d);
  background: var(--grey-b); border-radius: 999px; padding: .25rem 1rem; }
.tcard.room .troom i { color: var(--green-d); opacity: .5; }
.tcard.room .tfn { font-size: 1.5rem; color: var(--viol-d); }
/* Знак у правого края блока: Знак МЕДСИ без текстовой части, тот же файл и тот же вид,
   что на дежурном экране киоска. Пропорция 1,75:1: при высоте 2,25rem это 3,94rem.
   Цвет лазурный #0FC7CE, фирменный. На белом он даёт 2,08, но знак — не текст
   и не орган управления, поэтому под WCAG 1.4.3 и 1.4.11 не подпадает;
   брендбук прямо разрешает лазурное лого на фоне скорлупы и зелёных оттенков
   (стр. 34), а запрещает лишь на неконтрастных и васильковых фонах (стр. 35).
   Знак вынесен из потока текста: .tcard.room — флекс из двух частей, слева
   .roomtext колонкой из двух строк, справа знак, центрированный по высоте
   блока через align-self:center (карточка при этом stretch, иначе центрировать
   было бы не по чему: высоту блока задаёт текст).
   Высоту блока знак не увеличивает: 2,25rem ниже двух строк текста (~4,1rem). */
.tcard.room .tlogo { flex: none; align-self: center; height: 2.25rem; color: var(--azure); }
.tcard.room .tlogo svg { height: 100%; width: auto; display: block; }

/* Разделителя перед ФИО в карточке кабинета нет: на длинной специализации
   строка переносится, и точка повисала бы одна в начале второй строки,
   читаясь как маркер списка. В нижней полосе нерабочих состояний разделитель
   остаётся: там строка короче и не переносится. */
/* чипы статуса второй строкой блока — только в нерабочих состояниях */
.tmeta { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.tstatus { font-size: 1.25rem; font-weight: 600; padding: .5rem 1rem; border-radius: 999px; white-space: nowrap; }
.tstatus.ok { background: #DCEEE3; color: var(--ok); }
.tstatus.warn { background: #F7ECD7; color: var(--warn); }
.tstatus.crit { background: #F7E3E0; color: var(--crit); }
/* нейтральный тег режима приёма · РАСШИРЕНИЕ: серого в палитре нет,
   основание — стр. 59. Уголь на #E4E9F0 даёт 9,47 — AAA */
.tstatus.neutral { background: var(--grey-b); color: var(--coal); }

/* ---------- рабочее поле: слева вызов и следующий, справа очередь ----------
   minmax(0,1fr) вместо 1fr и min-width:0 у колонок — против «распирания» сетки: талоны набраны
   nowrap («П-1025», «П-1032»), их min-content шире колонки, и обычный 1fr вырастал бы по содержимому,
   выталкивая блок очереди за край экрана. Здесь длинному числу вместо этого снижается кегль (board.js). */
.tmain { display: grid; grid-template-columns: 33rem minmax(0, 1fr); gap: 1.5rem; margin: 0; flex: 1; min-height: 0; }
/* три ряда: карточка вызова и блок кабинета по содержимому, «Следующий»
   забирает остаток — его число самое крупное и должно дышать */
.tcol { display: grid; grid-template-rows: auto 1fr auto; grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem; min-height: 0; min-width: 0; }
.tcol.q { grid-template-rows: 1fr; }
.tcard { background: var(--card-w); border-radius: 1.5rem; padding: 1.5rem 2rem; min-height: 0; min-width: 0;
  display: flex; flex-direction: column; justify-content: flex-start; }
/* Подписи разделов набраны строчными, не капителью.
   Основание: брендбук закрепляет верхний регистр за двумя служебными ролями —
   логотип (стр. 62, RF Dewi Expanded) и дисклеймер о противопоказаниях
   (стр. 66, Roboto Condensed Light). Для наборного Manrope капитель не задана
   нигде, а на стр. 155, в разделе недопустимых макетов, выноска к плашке,
   набранной капсом, гласит «Недопустимый кегль и регистр».
   Работу капители — отделить служебную подпись от крупного числа — взяли
   на себя вес 700, кегль 1,75rem и положение. Трекинг снят: он был нужен,
   только чтобы прописные не слипались, и съедал ширину карточки.
   Цвет подписи совпадает с цветом числа под ней: «Следующий» и «В очереди»
   тёмно-васильковые, как их талоны; «Сейчас вызван» — зелёная, потому
   что её число лежит на белой плашке и отделено ею, а не цветом. */
.tlbl { font-size: 1.75rem; font-weight: 700; letter-spacing: 0;
  color: var(--viol-d); margin: 0 0 .75rem; }           /* 18,10 на белом, 14,98 на сером блоке — AAA */
/* «Сейчас вызван» — одним цветом со статусом над ней: 4,42 на #DCEEE3, AA
   для крупного текста. 1,75rem под определение проходят (порог 24 px по
   WCAG 1.4.3); мельче этот цвет здесь применять нельзя — до 4,5 не дотягивает */
.tlbl.called { color: var(--ok); }
.tlbl.dark { color: var(--viol-d); opacity: .72; }

/* Карточка вызова. Фон — тот же #DCEEE3, что у тега статуса: идущий приём
   и есть содержание карточки, отдельный тег на нём был бы повтором.
   Статус 4,5rem даёт при 10″ 12 мм высоты прописной — читается с 2,4 м. */
.tcard.now { background: #DCEEE3; justify-content: center; }
.tstate { font-size: 4.5rem; font-weight: 700; line-height: .9; letter-spacing: -.02em; color: var(--ok);
  margin: 0 0 1rem; }                               /* 4,42 на #DCEEE3 — AA для крупного текста */
/* карточка несёт только статус и подпись под ним: кабинет уехал
   отдельной карточкой под «Следующий».
   подпись несёт номер талона: он ушёл из заголовка карточки в строку под статусом */
.tlbl.called { margin: 0; display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
/* «Кабинет свободен»: подписи под статусом нет, и нижнего поля у статуса тоже */
.tcard.now.free .tstate { margin-bottom: 0; }
/* Цвет статуса синхронизирован с RGB-подсветкой корпуса (2026-09-18, заказчик): свободно — зелёный тон
   (как в макете), идёт приём — красный тон. Цвета — те же статусные расширения макета (#F7E3E0 / --crit, как у
   чипа «Приём не ведётся»), фирменные цвета, шрифт и карточки не меняются.
   --crit #B02F26 на #F7E3E0 — 5,2:1, AA для текста любого кегля. */
.tcard.now { transition: background-color .4s ease; }
.tstate, .tlbl.called { transition: color .4s ease; }
.tcard.now.busy { background: #F7E3E0; }
.tcard.now.busy .tstate, .tcard.now.busy .tlbl.called { color: var(--crit); }
/* номер в том же кегле и начертании, что подпись: выделяет его плашка, а не размер.
   Белая плашка повторяет карточки «Следующий» и талоны очереди */
.tlbl.called b { font-size: inherit; font-weight: inherit; letter-spacing: inherit; color: var(--viol-d);
  background: var(--card-w); border-radius: 999px; padding: .25rem 1rem;
  font-variant-numeric: tabular-nums; }             /* 18,10 на белом — AAA */
/* приоритет экрана — талон, который вызовут следующим.
   white-space:nowrap — добавлено к макету: в макете талон всегда «А-302», а «П-1024»
   в узкой колонке уехал бы на вторую строку и сломал высоту ряда; вместо переноса
   кегль подгоняется по ширине карточки (fit в board.js). */
.tnext { font-size: 9rem; font-weight: 700; line-height: .86; letter-spacing: -.03em; color: var(--viol-d);
  margin: 0; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Очередь пуста: числа нет, и крупный кегль здесь не нужен — это не номер, а пояснение. */
.tnext.none { font-size: 2.5rem; font-weight: 600; line-height: 1.2; letter-spacing: 0; color: var(--green-d); }

/* Заголовок блока очереди. Счётчик «ещё N не отметились» убран по решению заказчика (2026-09-18). */
.tqhead { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex: none; }
.tqhead .tlbl { margin-bottom: .75rem; }

.tqueue { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1rem 1.5rem; align-content: start; margin-top: .25rem; }
/* Радиус 999px — скругление по высоте плашки. Основание: стр. 148 брендбука,
   «один из кругов фрейма может увеличиваться до прямоугольника со скруглёнными
   краями, который может вмещать в себя текст», и стр. 207, где теги приложения
   МЕДСИ скруглены так же. Падинги подняты с .5/1,25 до .75/2rem: при полном
   скруглении углы съедают часть внутреннего поля, и прежние 1,25rem по бокам
   ставили цифры вплотную к дуге. */
.tq { font-size: 4.5rem; font-weight: 600; color: var(--viol-d); line-height: 1.1;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  background: var(--card-w); border-radius: 999px; padding: .75rem 2rem; text-align: center; }
/* Хвост очереди, который не поместился: та же плашка, но тише и мельче —
   число, а не талон. ДОБАВЛЕНО: в макете ровно шесть плашек, в жизни сервер
   отдаёт до восьми, и на 8 талонах нижний ряд вылезал на субблок сканера. */
.tq.more { background: var(--grey-b); color: var(--green-d); font-size: 3rem; font-weight: 700; }
/* блок очереди тише белых карточек вызова: те несут приоритет */
.tcard.queue { justify-content: flex-start; background: var(--grey-b); }
/* Очередь пуста — вместо плашек одна строка на всю ширину блока (иначе она ложится
   в одну колонку сетки и переносится посередине фразы). */
.tqempty { grid-column: 1 / -1; font-size: 1.75rem; color: var(--green-d); margin: .25rem 0 0; }

/* ---------- РАСКЛАДКА Б (?layout=b): кабинет вместо «Следующего» ----------
   Карточка «Следующий» убирается, её талон уходит первым в очередь,
   а блок кабинета занимает освободившийся ряд. Колонка становится auto 1fr:
   кабинет растягивается на остаток, поэтому кегли внутри подняты на шаг —
   1,75rem вместо 1,5, номер 2,5 вместо 2. */
.tstage.layout-b #q-nextcard { display: none; }
.tstage.layout-b .tcol { grid-template-rows: auto 1fr; }
/* В раскладке Б блок занимает целый ряд колонки: текст центрируется по высоте,
   знак остаётся центрированным — stretch у карточки, justify-content:center у текста */
.tstage.layout-b .tcard.room { align-items: stretch; padding: 1.5rem 2rem; }
.tstage.layout-b .roomtext { justify-content: center; }
.tstage.layout-b .tcard.room .tlogo { align-self: center; height: 2.5rem; }
.tstage.layout-b .tcard.room .troom { font-size: 1.75rem; }
.tstage.layout-b .tcard.room .troom b { font-size: 1.75rem; padding: .375rem 1.25rem; }
.tstage.layout-b .tcard.room .tfn { font-size: 1.75rem; }
/* Выделение светло-голубым #DBF5FF из палитры, стр. 53. К белым плашкам оно
   даёт всего 1,13 — цветом одним такой талон не опознать, поэтому под номером
   стоит подпись «следующий»: цвет намекает, слово называет.
   Тёмно-васильковый на #DBF5FF — 15,96, AAA. */
.tq.next { background: var(--blue-l); position: relative; }
.tq.next i { display: block; font-size: 1.25rem; font-weight: 600; font-style: normal;
  letter-spacing: 0; color: var(--green-d); margin-top: -.25rem; }   /* 6,48 на #DBF5FF — AA */
/* кабинет и специализация — первыми в белом блоке справа */
.troom { display: flex; align-items: baseline; gap: 1.25rem;
  font-size: 1.75rem; font-weight: 600; color: var(--viol-d); min-width: 0; }
.troom b { font-size: 2.5rem; font-weight: 700; color: var(--viol-d); font-variant-numeric: tabular-nums; }
.troom i { font-style: normal; color: var(--green-d); opacity: .5; }

/* ---------- вызов ---------- */
.tscr.call { background: var(--azure); align-items: center; justify-content: center; text-align: center; padding: 3rem; }
.tbig { font-size: 15rem; font-weight: 700; line-height: .86; letter-spacing: -.04em; color: var(--viol-d);
  margin: .75rem 0 1.25rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tcallto { font-size: 2.75rem; font-weight: 600; color: var(--viol-d); margin: 0 0 2.25rem; line-height: 1.15; }
.tcallto b { font-size: 4rem; }
.tsnd { display: inline-flex; align-items: center; gap: .875rem; font-size: 1.5rem; font-weight: 600; color: var(--viol-d);
  background: rgba(255, 255, 255, .55); border-radius: 999px; padding: .875rem 1.625rem;
  border: 0; font-family: var(--sans); cursor: pointer; position: relative; }
/* В макете это подпись; здесь пилюля ещё и повторяет сигнал по нажатию (§6c), то есть орган управления.
   Вид оставлен макетным (пилюля 3,75rem высотой), а цель касания доведена до тех же 6rem, что у кнопок:
   невидимая область поверх пилюли — положение и размеры самой пилюли не меняются. */
.tsnd::after { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 6rem; transform: translateY(-50%); }
.tsnd svg { width: 2rem; height: 2rem; animation: tpulse 1.6s ease-in-out infinite; }
.tsnd.muted svg { animation: none; opacity: .5; }
@keyframes tpulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .tsnd svg { animation: none; } }

/* ---------- сообщения и нерабочие состояния ---------- */
.tscr.msg { align-items: center; justify-content: center; text-align: center; }
.tbody { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; min-height: 0; }
.tico { width: 7rem; height: 7rem; border-radius: 999px; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem; flex: none; }
.tico svg { width: 3.75rem; height: 3.75rem; }
.tico.ok { background: #DCEEE3; color: var(--ok); }
.tico.warn { background: #F7ECD7; color: var(--warn); }
.tico.crit { background: #F7E3E0; color: var(--crit); }
.tico.info { background: var(--blue-l); color: var(--green-d); }
.tmsg { font-size: 3.5rem; font-weight: 700; color: var(--viol-d); margin: 0; line-height: 1.05; letter-spacing: -.02em; }
.tbignum { font-size: 9rem; font-weight: 700; line-height: .86; letter-spacing: -.03em; color: var(--viol-d);
  margin: 1.25rem 0 0; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tsub { font-size: 1.75rem; color: var(--green-d); margin: 1.25rem 0 0; line-height: 1.3; max-width: 52ch; }
.tsub b { color: var(--viol-d); font-weight: 700; }
.tbtns { display: flex; gap: 1rem; margin-top: 2.5rem; flex: none; }
.tbtn { min-height: 6rem; border: 0; border-radius: 1.5rem; background: var(--azure); color: var(--viol-d);
  font-family: var(--sans); font-size: 1.75rem; font-weight: 600; cursor: pointer; padding: 0 2.5rem; line-height: 1.15; }
.tbtn.gh { background: transparent; border: .1875rem solid var(--green-d); color: var(--green-d); }
.tbtn:focus-visible, .tsnd:focus-visible, .tpb:focus-visible, .tkey:focus-visible { outline: .25rem solid var(--viol-d); outline-offset: .25rem; }
.tbtn[disabled] { opacity: .45; cursor: default; }
.tlast { flex: none; background: var(--card-w); border-radius: 1.5rem; padding: 1.25rem 2rem;
  display: flex; align-items: center; gap: 1.5rem; opacity: .72; }
.tlast .tlbl { margin: 0; }
.tlast b { font-size: 3.5rem; font-weight: 700; color: var(--viol-d); margin-left: auto; font-variant-numeric: tabular-nums; }

/* ---------- ручной ввод талона (служебный экран, §6f) ----------
   В макете его нет. Собран из тех же токенов: белые плашки радиусом 1,5rem,
   подпись 1,75rem, цифры 3rem, кнопки .tbtn. Две колонки: слева поле и подписи,
   справа клавиатура — иначе четыре ряда клавиш не помещаются в 50rem высоты. */
.tman { display: grid; grid-template-columns: auto auto; justify-content: center; gap: 4rem; align-items: center; text-align: left; }
.tmanside { display: flex; flex-direction: column; align-items: flex-start; min-width: 0; }
.tmanside .tsub { margin-top: .75rem; }
.tmanside .tbtns { margin-top: 2rem; }
.tfield { font-size: 4.5rem; font-weight: 700; color: var(--viol-d); background: var(--card-w);
  border-radius: 1.5rem; padding: .75rem 2rem; margin-top: 1.5rem; letter-spacing: .04em;
  font-variant-numeric: tabular-nums; min-width: 18rem; }
/* Недобранные цифры прочерками. Средне-зелёный #37A3B6 на белом даёт 2,97 — текстом он быть не может
   даже как крупный (порог 3,0), и макет это прямо запрещает. Берём тёмно-зелёный (7,83, AAA),
   а подчинённость прочерков держим начертанием: 400 против 700 у набранных цифр. */
.tfield .p { color: var(--green-d); font-weight: 400; }
.tpfx { display: flex; gap: .75rem; margin-top: 1.5rem; }
.tpb { min-width: 5rem; min-height: 4rem; border-radius: 1rem; border: .1875rem solid var(--green-d);
  background: transparent; color: var(--green-d); font-family: var(--sans); font-size: 1.75rem; font-weight: 700; cursor: pointer; }
.tpb.on { background: var(--blue-l); border-color: var(--viol-d); color: var(--viol-d); }
.tpad { display: grid; grid-template-columns: repeat(3, 7rem); gap: 1rem; flex: none; }
/* Клавиши — те же 6rem высоты, что у кнопок макета: это цель касания, а не подпись.
   На высоту экрана не влияет: левая колонка (заголовок, поле, буквы, кнопки) всё равно выше клавиатуры. */
.tkey { min-height: 6rem; border: 0; border-radius: 1rem; background: var(--card-w); font-family: var(--sans);
  font-size: 3rem; font-weight: 600; color: var(--viol-d); cursor: pointer; display: flex; align-items: center; justify-content: center; }
.tkey.empty { visibility: hidden; }
.tkey svg { width: 2.5rem; height: 2.5rem; fill: none; stroke: currentColor; }

/* ---------- выбор кабинета (страница без ?room=) ---------- */
.tpick { margin-top: 2rem; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); width: 100%; max-width: 60rem; }
a.tq { text-decoration: none; display: block; font-size: 2.5rem; }
a.tq span { display: block; font-size: 1.25rem; font-weight: 600; color: var(--green-d); white-space: normal; }

/* ---------- ПОРТРЕТ 800×1280 (§6f: колонки становятся рядами, очередь снизу) ----------
   Корневой кегль на 800×1280 — 10 px, поэтому сцена в rem выше и уже: 80 × 128rem.
   Левая колонка ложится рядом из двух карточек (вызов и «Следующий»), блок кабинета
   занимает всю ширину под ними, блок очереди забирает остаток высоты. */
@media (orientation: portrait) {
  /* Ряды примерно пополам: верхний несёт статус и «Следующего», нижний — очередь со сканером.
     Без явных долей очередь забирала всю высоту, а карточки вызова сжимались в полоску. */
  .tmain { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) minmax(0, 1.15fr); }
  .tcol { grid-template-rows: minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .tcard.room { grid-column: 1 / -1; }
  .tstage.layout-b .tcol { grid-template-rows: minmax(0, 1fr) auto; }
  .tcol.q { grid-template-rows: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr); }
  .tbar { grid-template-columns: minmax(0, 1fr); }
  .tdoc { grid-column: 1; }
  /* Полноэкранные центрированные экраны — вызов, результат скана, нерабочие состояния.
     По ширине портрет даёт те же 80rem, а по высоте 128rem вместо 50: блок, рассчитанный
     на ландшафт, теряется посреди экрана. Кегли этих экранов подняты примерно в 1,4 раза —
     ровно настолько, чтобы талон по-прежнему умещался в ширину (подгонка в board.js
     страхует длинные номера вроде «П-1024»). Нижняя полоса с кабинетом не трогается:
     это служебные сведения, их кегль задан расстоянием чтения, а не размером экрана. */
  .tbig { font-size: 21rem; }
  .tcallto { font-size: 3.75rem; }
  .tcallto b { font-size: 5.5rem; }
  .tlbl.dark { font-size: 2.5rem; }
  .tsnd { font-size: 2rem; padding: 1.25rem 2.25rem; }
  .tsnd svg { width: 2.75rem; height: 2.75rem; }
  .tico { width: 10rem; height: 10rem; margin-bottom: 2rem; }
  .tico svg { width: 5.25rem; height: 5.25rem; }
  .tmsg { font-size: 5rem; }
  .tbignum { font-size: 12.5rem; }
  .tsub { font-size: 2.5rem; }
  .tlast b { font-size: 5rem; }
  .tlast .tlbl { font-size: 2.5rem; }
  .tbtn { font-size: 2.5rem; min-height: 8rem; padding: 0 3rem; border-radius: 2rem; }
  /* Клавиатура ручного ввода: в портрете она стоит под полем, места хватает на крупные клавиши. */
  .tman { grid-template-columns: auto; gap: 2rem; justify-items: center; }
  .tmanside { align-items: center; text-align: center; }
  .tfield { font-size: 6rem; min-width: 24rem; }
  .tpb { min-width: 7rem; min-height: 5.5rem; font-size: 2.5rem; }
  .tpad { grid-template-columns: repeat(3, 10rem); }
  .tkey { min-height: 8rem; font-size: 4rem; }
  .tkey svg { width: 3.5rem; height: 3.5rem; }
}

/* Нерабочие состояния: фон всего экрана повторяет RGB-подсветку (2026-09-18, заказчик) — перерыв жёлтый тон
   (#F7ECD7, как чип «Перерыв»), закрыт — красный тон (#F7E3E0, как чип «Приём не ведётся»). Белые карточки и
   полоса кабинета остаются белыми; кружок иконки на тонированном фоне — белый, иначе он сливается с фоном.
   Контраст: заголовок --viol-d и подпись --green-d на обоих тонах ≥ 6:1. */
#t-state { transition: background-color .4s ease; }
#t-state[data-tone="warn"] { background: #F7ECD7; }
#t-state[data-tone="crit"] { background: #F7E3E0; }
#t-state[data-tone="warn"] .tico, #t-state[data-tone="crit"] .tico { background: #FFFFFF; }
