/* /all/timer/board-skins.css — оформление конструктора табло.
 *
 * Подключается ПОСЛЕ css.css и после owner-темы (акцент клуба приходит
 * !important-переменными --accent*). Здесь только то, что появляется у клубов,
 * которые собрали доску конструктором: пока раскладка не сохранена, ни один
 * селектор ниже не срабатывает (все они висят на html[data-tb] / .root[data-*]).
 *
 * Бюджет ТВ (см. память tv-board-render-budget): на полноэкранных слоях никаких
 * filter-анимаций, бесконечные анимации — только opacity/transform. Статический
 * blur фона допустим: он считается один раз при загрузке.
 */

/* =========================================================
   1. БАЗА: шрифт, масштабы, регистр
   ========================================================= */
/* Переменные скина объявлены на .root, поэтому и семейство назначаем ему же:
   body выше по дереву, до var(--tb-font) он не дотянется. Крупные цифры в
   css.css держат своё семейство — их перекрываем отдельно. */
html[data-tb] .root,
html[data-tb] .root .timer-value,
html[data-tb] .root .blind-value,
html[data-tb] .root .v {
    font-family: var(--tb-font, 'Saira', system-ui, sans-serif);
}

/* Размеры собираются множителями: общий (--tb-scale), отдельно подписи
   (--tb-label) и значения (--tb-value), плюс личный масштаб блока (--bs).
   ВАЖНО: весь блок висит на html[data-tb-size] — атрибут ставится, только
   когда владелец реально что-то подкрутил. Пока все множители = 1, правил
   ниже НЕТ, и размеры остаются такими, какими их считает css.css со всеми
   своими медиа-запросами (на узких экранах и низких ТВ он ужимает подписи —
   переписав размеры здесь, мы бы эту адаптацию выключили). */
html[data-tb-size] .root .k {
    font-size: calc(11px * var(--tb-scale, 1) * var(--tb-label, 1) * var(--bs, 1));
}
html[data-tb] .root .k,
html[data-tb] .root .blind-label {
    text-transform: var(--tb-caps, uppercase);
}
html[data-tb-size] .root .v {
    font-size: calc(clamp(18px, 2.1vw, 34px) * var(--tb-scale, 1) * var(--tb-value, 1) * var(--bs, 1));
}
html[data-tb-size] .root .blind-label {
    font-size: calc(12px * var(--tb-scale, 1) * var(--tb-label, 1) * var(--bs, 1)) !important;
}
/* Крупные значения не переносятся: «1 000» в две строки вылезало из карточки,
   когда владелец поднимал размер блайндов. */
html[data-tb] .root .blind-value { white-space: nowrap; }
html[data-tb] .root .v { white-space: nowrap; }
html[data-tb-size] .root .blind-value {
    font-size: calc(clamp(30px, 5.8vw, 96px) * var(--tb-scale, 1) * var(--tb-value, 1) * var(--bs, 1)) !important;
}
html[data-tb-size] .root .timer-value {
    font-size: calc(clamp(46px, calc(var(--timer-size) * 0.21), 168px) * var(--tb-scale, 1) * var(--tb-value, 1));
}
html[data-tb-size] .root .timer-level {
    font-size: calc(12px * var(--tb-scale, 1) * var(--tb-label, 1));
}
html[data-tb-size] .root .club-title {
    font-size: calc(clamp(18px, 2.6vw, 44px) * var(--tb-scale, 1));
}

/* Тон текста блока. Акцент — единственный «цветной» тон: он тянет цвет клуба. */
html[data-tb] .tb-b[data-tone="text"]   .v,
html[data-tb] .tb-b[data-tone="text"]   .blind-value { color: var(--text); }
html[data-tb] .tb-b[data-tone="muted"]  .v,
html[data-tb] .tb-b[data-tone="muted"]  .blind-value { color: var(--text-muted); }
html[data-tb] .tb-b[data-tone="accent"] .v,
html[data-tb] .tb-b[data-tone="accent"] .blind-value {
    color: rgba(var(--accent-soft-rgb, 255, 86, 102), 1);
}

/* =========================================================
   2. НОВЫЕ ЭЛЕМЕНТЫ (строка, картинка, знак, стопки)
   ========================================================= */
.tb-pic {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
}
.tb-pic img {
    max-width: 100%;
    max-height: calc(120px * var(--bs, 1));
    object-fit: contain;
    display: block;
}
.tb-pic-empty {
    font-size: 12px;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--text-muted);
    border: 1px dashed var(--border);
    border-radius: 10px;
    padding: 18px 26px;
}

/* Фон выключен тумблером — слой не участвует вовсе (иначе его затемнение
   осталось бы висеть поверх доски серой пеленой). */
.root[data-bg="0"] .tb-bg { display: none; }

/* Свой фон зала. Слой уходит ПОД содержимое (z-index:-1 рисуется поверх фона
   body, но под всеми блоками) и накрывается затемнением: без него белая
   фотография съедает цифры. */
.tb-bg {
    position: fixed;
    inset: 0;
    z-index: -1;
    background-image: var(--tb-bg-img, none);
    background-size: cover;
    background-position: center;
    filter: blur(var(--tb-bg-blur, 0px));
    transform: scale(1.06);          /* съедает размытые края, а не показывает их */
}
.tb-bg::after {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(4, 5, 12, var(--tb-bg-dim, .6));
}
html[data-theme="light"] .tb-bg::after { background: rgba(255, 255, 255, var(--tb-bg-dim, .6)); }

/* Пустой необязательный блок (двойных ре-энтри не было и т.п.) — вон с доски.
   Класс ставит js.js по данным турнира. */
.root .tb-b.tb-empty { display: none !important; }

/* Подстрочка кратности под значением: тихая, не спорит с главной цифрой. */
.root .tb-sub {
    margin-top: 4px;
    font-size: calc(11px * var(--tb-scale, 1) * var(--tb-label, 1) * var(--bs, 1));
    font-weight: 700;
    letter-spacing: .10em;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.root .tb-sub:empty { display: none; }
.root .blind-card .tb-sub { text-align: center; }

/* QR на запись: небольшой, читается телефоном с 2-3 метров. */
.tb-qr { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.tb-qr-box {
    width: calc(120px * var(--bs, 1));
    height: calc(120px * var(--bs, 1));
    background: #fff;
    border-radius: 10px;
    padding: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* svg обязателен в списке: qrcode.js отдаёт именно <svg> с зашитыми width/height
   (124px). Пока правило ловило только img/canvas, код торчал за пределы своего
   белого квадрата — ровно то, что владелец увидел на боевой доске. */
.tb-qr-box img,
.tb-qr-box canvas,
.tb-qr-box svg { width: 100% !important; height: 100% !important; display: block; }
.tb-qr-box { overflow: hidden; }
.tb-qr .k { text-align: center; white-space: normal; }

/* =========================================================
   3. СТИЛИ КАРТОЧЕК (независимы от шаблона — можно смешивать)
   ========================================================= */

/* --- плотная плашка --- */
.root[data-cards="plate"] .card,
.root[data-cards="plate"] .blind-card {
    background: linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .02));
    border-color: rgba(255, 255, 255, .10);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06), 0 10px 26px rgba(0, 0, 0, .45);
}
html[data-theme="light"] .root[data-cards="plate"] .card,
html[data-theme="light"] .root[data-cards="plate"] .blind-card {
    background: #fff;
    border-color: rgba(11, 14, 20, .10);
    box-shadow: 0 12px 28px rgba(11, 14, 20, .10);
}

/* --- стекло --- */
.root[data-cards="glass"] .card,
.root[data-cards="glass"] .blind-card {
    position: relative;
    background: linear-gradient(180deg, rgba(255, 255, 255, .07), rgba(255, 255, 255, .015));
    border: 1px solid rgba(var(--accent-rgb, 255, 46, 59), .22);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .10), 0 14px 30px rgba(0, 0, 0, .5);
    overflow: hidden;
}
.root[data-cards="glass"] .card::after,
.root[data-cards="glass"] .blind-card::after {
    content: '';
    position: absolute;
    left: 12%;
    right: 12%;
    bottom: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb, 255, 46, 59), .85), transparent);
}

/* --- лопасти вокзального табло ---
   Шов идёт по середине ЦИФР, а не карточки: сверху стоит подпись («BIG
   BLIND»), и раздел по середине карточки резал цифры не пополам, а криво по
   нижней трети. Долю считает board-layout.js (--flap-split) по реальному
   центру значения; 50% — запасной вариант, если посчитать не вышло. */
.root[data-cards="flap"] .card,
.root[data-cards="flap"] .blind-card {
    position: relative;
    background: linear-gradient(180deg,
        #16171c 0 var(--flap-split, 50%), #101116 var(--flap-split, 50%) 100%);
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 8px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 10px 22px rgba(0, 0, 0, .55);
}
.root[data-cards="flap"] .card::before,
.root[data-cards="flap"] .blind-card::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: var(--flap-split, 50%);
    height: 1px;
    background: rgba(0, 0, 0, .75);
    box-shadow: 0 1px 0 rgba(255, 255, 255, .05);
}
.root[data-cards="flap"] .v,
.root[data-cards="flap"] .blind-value {
    font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 0 rgba(0, 0, 0, .8);
}

/* --- маркиза с лампами --- */
.root[data-cards="marquee"] .card,
.root[data-cards="marquee"] .blind-card {
    position: relative;
    background: linear-gradient(180deg, #14121a, #0c0a11);
    border: 1px solid rgba(var(--accent-rgb, 255, 46, 59), .35);
    border-radius: 16px;
    box-shadow: 0 10px 26px rgba(0, 0, 0, .55), 0 0 26px rgba(var(--accent-rgb, 255, 46, 59), .10);
}
@supports (mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0)) or
          (-webkit-mask-composite: xor) {
    .root[data-cards="marquee"] .card::before,
    .root[data-cards="marquee"] .blind-card::before {
        content: '';
        position: absolute;
        inset: 0;
        padding: 9px;
        border-radius: inherit;
        pointer-events: none;
        background:
            radial-gradient(circle at 50% 50%,
                rgba(255, 228, 190, .98) 2.1px, rgba(255, 228, 190, 0) 3.2px) 0 0 / 22px 22px;
        -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
        -webkit-mask-composite: xor;
                mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
        animation: tb-bulbs 2.6s ease-in-out infinite alternate;
    }
}
@keyframes tb-bulbs { from { opacity: .72; } to { opacity: 1; } }

/* --- без коробок: ведомость на волосяной линии --- */
.root[data-cards="bare"] .card,
.root[data-cards="bare"] .blind-card {
    background: none;
    border: 0;
    box-shadow: none;
    border-radius: 0;
    padding: 10px 2px;
}
.root[data-cards="bare"] .col-side .tb-b + .tb-b {
    border-top: 1px solid rgba(255, 255, 255, .07);
}
html[data-theme="light"] .root[data-cards="bare"] .col-side .tb-b + .tb-b {
    border-top-color: rgba(11, 14, 20, .10);
}
.root[data-cards="bare"] .blinds-row { gap: calc(var(--gap) * 2); }
.root[data-cards="bare"] .blind-card { min-height: 0; }

/* Пустой нижний ряд не должен занимать место. Шаблон «Борт» уносит блайнды в
   левую колонку, и без этого правила внизу доски оставалась полоса из зазора
   родителя — на ТВ это съедало высоту у самих цифр. Правило висит на
   html[data-tb], то есть работает только у собранных конструктором досок:
   у клуба, который ничего не трогал, нижний ряд всегда с блайндами. */
html[data-tb] .root .blinds-row:empty { display: none; }
html[data-tb] .root .bottom:has(> .blinds-row:empty) { display: none; }

/* Выделенный блок на ЛЮБОМ стиле карточек: «главный» обязан отличаться, иначе
   тумблер «выделить» ничего не делает на всём, кроме голых списков. */
.root .tb-b.is-hero .k,
.root .tb-b.is-hero .blind-label { color: rgba(var(--accent-soft-rgb, 255, 86, 102), .92); }
.root[data-cards="outline"] .tb-b.is-hero,
.root[data-cards="plate"] .tb-b.is-hero,
.root[data-cards="glass"] .tb-b.is-hero,
.root[data-cards="flap"] .tb-b.is-hero,
.root[data-cards="marquee"] .tb-b.is-hero {
    border-color: rgba(var(--accent-rgb, 255, 46, 59), .45);
    box-shadow: 0 16px 34px rgba(0, 0, 0, .5);
}

/* Выделенный блок без коробок держится цветом и планкой, а не рамкой:
   обводка вокруг числа — ровно тот дешёвый приём, от которого уходим. */
.root[data-cards="bare"] .blind-card.is-hero { position: relative; }
.root[data-cards="bare"] .blind-card.is-hero::after {
    content: '';
    position: absolute;
    left: 22%;
    right: 22%;
    bottom: 0;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg,
        transparent,
        rgba(var(--accent-rgb, 255, 46, 59), .9),
        transparent);
}

/* =========================================================
   4. ЦЕНТР ТАБЛО
   Кольцо — прежнее (живёт в css.css). Ниже три остальных вида; все они
   работают вокруг тех же узлов, которые пишет js.js: #timer-ring, .ring-fg,
   #timer-value. Ни один селектор не подменяет разметку — только оправу.
   ========================================================= */

/* --- только цифры: время во весь экран, никакой оправы --- */
.root[data-ring="bare"] #timer-ring,
.root[data-ring="bare"] .ring-glow { display: none; }
.root[data-ring="bare"] .timer-wrap {
    width: auto;
    height: auto;
    min-width: var(--timer-size);
    padding: 1.4vmin 0;
}
.root[data-ring="bare"] .timer-label { position: static; inset: auto; padding: 0; gap: 1.1vmin; }

/* --- циферблат: гравированная шкала, металлический обод, стрелки-засечки ---
   Стрелки поворачивает рендерер атрибутом transform (setHand): CSS-трансформ
   на узлах SVG на части ТВ-браузеров считается мимо начала координат.
   Длинных стрелок нет намеренно — они резали бы цифры времени пополам. */
.root[data-ring="dial"] .timer-wrap::before {
    content: '';
    position: absolute;
    inset: -2.5%;
    border-radius: 50%;
    background:
        conic-gradient(from 210deg,
            rgba(255, 255, 255, .10) 0deg,
            rgba(255, 255, 255, .02) 60deg,
            rgba(255, 255, 255, .12) 140deg,
            rgba(255, 255, 255, .015) 220deg,
            rgba(255, 255, 255, .09) 300deg,
            rgba(255, 255, 255, .10) 360deg),
        radial-gradient(circle at 50% 50%, #0e1015 62%, #171a21 78%, #0b0d12 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06), 0 26px 60px rgba(0, 0, 0, .55);
    z-index: 1;
}
.root[data-ring="dial"] .ring-bg { stroke-width: 1.6; stroke: rgba(255, 255, 255, .09); }
.root[data-ring="dial"] .ring-fg { stroke-width: 2.6; }
/* Ореол вокруг кольца спорит с металлом обода — приглушаем. */
.root[data-ring="dial"] .ring-glow { opacity: .32; }
/* Шкалу несёт дуга, вторая полоса под цифрами — лишний элемент. */
.root[data-ring="dial"] .level-progress { display: none; }
.root[data-ring="dial"] .ring-head { display: none; }
.root[data-ring="dial"] .tb-tick {
    stroke: rgba(255, 255, 255, .24);
    stroke-width: .8;
    stroke-linecap: round;
}
.root[data-ring="dial"] .tb-tick.is-big { stroke: rgba(255, 255, 255, .58); stroke-width: 1.8; }
.root[data-ring="dial"] .tb-hand {
    stroke: rgba(255, 255, 255, .92);
    stroke-width: 2.6;
    stroke-linecap: round;
    /* Ход раз в секунду; транзишен превращает его в движение, а не в прыжок.
       Только transform — композитор, без перерисовки слоя (бюджет ТВ). */
    transition: transform .42s cubic-bezier(.22, .9, .3, 1);
}
.root[data-ring="dial"] .tb-hand-s {
    stroke: rgba(255, 255, 255, .5);
    stroke-width: 1.6;
}
.root[data-ring="dial"] .timer-value { font-size: calc(var(--timer-size) * .175); }
html[data-theme="light"] .root[data-ring="dial"] .timer-wrap::before {
    background: radial-gradient(circle at 50% 50%, #fff 62%, #f1f2f6 78%, #e7e9ef 100%);
    box-shadow: 0 26px 60px rgba(11, 14, 20, .14);
}
html[data-theme="light"] .root[data-ring="dial"] .tb-tick { stroke: rgba(11, 14, 20, .26); }
html[data-theme="light"] .root[data-ring="dial"] .tb-tick.is-big { stroke: rgba(11, 14, 20, .55); }
html[data-theme="light"] .root[data-ring="dial"] .tb-hand { stroke: rgba(11, 14, 20, .85); }

/* --- карточка «Текущие блайнды»: одно значение, а не три ---
   Значения приезжают копиями (data-tb-mirror), разметка общая для колонки и
   нижнего ряда. Дробь красная — единственный акцент внутри карточки. */
html[data-tb] .root .tb-blinds .tb-blinds-v {
    white-space: nowrap;                        /* «30 000 / 60 000» одной строкой */
    letter-spacing: .01em;
}
html[data-tb] .root .tb-blinds .tb-blinds-v i {
    font-style: normal;
    color: var(--accent, #E11D2E);
    margin: 0 .22em;
}
html[data-tb] .root .tb-blinds .tb-blinds-ante {
    margin-top: .35em;
    padding-top: .35em;
    border-top: 1px solid rgba(255, 255, 255, .08);
    white-space: nowrap;
    font-size: calc(11px * var(--tb-scale, 1) * var(--tb-label, 1) * var(--bs, 1));
    font-weight: 700;
    letter-spacing: .12em;
}
html[data-tb] .root .tb-blinds .tb-blinds-ante-k { color: rgba(255, 255, 255, .58); margin-right: .7em; }
html[data-tb] .root .tb-blinds .tb-blinds-ante-v { color: var(--accent, #E11D2E); }
html[data-theme="light"] .root .tb-blinds .tb-blinds-ante { border-top-color: rgba(11, 14, 20, .12); }
html[data-theme="light"] .root .tb-blinds .tb-blinds-ante-k { color: rgba(11, 14, 20, .58); }

/* =========================================================
   ЦЕНТР «core»: тонкий прибор, внутри время + блайнды
   =========================================================
   По второму образцу владельца (21.08.2026). Отличие от «dial» намеренное:
   там металлический обод и стрелки, здесь — минимализм. Ни конического
   градиента, ни ореола: чёрный круг, волосяная окружность, частая насечка.
   Стрелок нет — под временем стоят блайнды, стрелка лезла бы на них.

   Бюджет ТВ: ни одной анимации и ни одного filter. Насечка — 120 <line> в том
   же SVG, что и кольцо, строится один раз при сборке доски. */
/* Круг здесь — главный элемент экрана, а не один из блоков: на образце он
   занимает почти всю высоту. Поднимаем диаметр, оставаясь в тех же ограничителях
   (vmin/vh), чтобы на низком ТВ он не вылез за экран. */
.root[data-ring="core"] { --timer-size: min(74vmin, 66vh, 720px); }

.root[data-ring="core"] .timer-wrap::before {
    content: '';
    position: absolute;
    inset: -2.5%;
    border-radius: 50%;
    background: #05070A;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .10);
    z-index: 1;
}
/* Дуга уровня остаётся, но волосяная: она здесь мера времени, а не украшение. */
.root[data-ring="core"] .ring-bg { stroke-width: 1; stroke: rgba(255, 255, 255, .07); }
.root[data-ring="core"] .ring-fg { stroke-width: 1.8; }
.root[data-ring="core"] .ring-glow { opacity: 0; }
.root[data-ring="core"] .ring-head { display: none; }
/* Полосы прогресса под цифрами нет: её роль играет красная черта .tb-core-rule. */
.root[data-ring="core"] .level-progress { display: none; }

.root[data-ring="core"] .tb-tick {
    stroke: rgba(255, 255, 255, .30);
    stroke-width: .55;
    stroke-linecap: butt;   /* округлые концы на 120 штрихах смазываются в кашу */
}
.root[data-ring="core"] .tb-tick.is-big { stroke: rgba(255, 255, 255, .62); stroke-width: .9; }
/* Четверти — цветом клуба: единственный акцент на самом круге. */
.root[data-ring="core"] .tb-tick.is-key {
    stroke: var(--accent, #E11D2E);
    stroke-width: 1.15;
}

/* Время крупнее, чем на «dial»: под ним ещё две строки, и мелкое время
   потерялось бы между насечкой и блайндами. */
.root[data-ring="core"] .timer-value { font-size: calc(var(--timer-size) * .21); }
.root[data-ring="core"] .timer-level { letter-spacing: .18em; opacity: .82; }

/* --- блайнды и анте внутри круга --- */
/* Ширину держим долей КРУГА, а не экрана: «30 000 / 60 000» обязано вставать в
   одну строку, а край текста — не наезжать на насечку. */
.root[data-ring="core"] .tb-core {
    width: min(74%, calc(var(--timer-size) * .74));
    margin: calc(var(--timer-size) * .022) auto 0;
    text-align: center;
}
.root[data-ring="core"] .tb-core-rule {
    width: 100%;
    height: 1px;
    background: linear-gradient(90deg,
        rgba(255, 255, 255, 0),
        var(--accent, #E11D2E) 22%,
        var(--accent, #E11D2E) 78%,
        rgba(255, 255, 255, 0));
    position: relative;
}
/* Точка на черте — единственная деталь, взятая с образца буквально: она ловит
   центр и не даёт линии выглядеть обрезанной. */
.root[data-ring="core"] .tb-core-rule::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: 5px;
    height: 5px;
    margin: -2.5px 0 0 -2.5px;
    border-radius: 50%;
    background: var(--accent, #E11D2E);
}
.root[data-ring="core"] .tb-core-blinds {
    margin-top: calc(var(--timer-size) * .026);
    font-weight: 800;
    line-height: 1.06;
    white-space: nowrap;                       /* «30 000 / 60 000» не переносим */
    color: #FFFFFF;
    font-size: calc(var(--timer-size) * .072);
    letter-spacing: .01em;
}
.root[data-ring="core"] .tb-core-blinds i {
    font-style: normal;
    color: var(--accent, #E11D2E);
    margin: 0 .28em;
}
.root[data-ring="core"] .tb-core-ante {
    margin-top: calc(var(--timer-size) * .012);
    white-space: nowrap;
    font-size: calc(var(--timer-size) * .038);
    font-weight: 700;
    letter-spacing: .12em;
}
.root[data-ring="core"] .tb-core-ante-k { color: rgba(255, 255, 255, .62); margin-right: .6em; }
.root[data-ring="core"] .tb-core-ante-v { color: var(--accent, #E11D2E); }

/* Множители из «Оформления» должны доставать и до цифр внутри круга — иначе
   ползунок «значения» двигает всё, кроме них (владелец правит размеры прямо
   в настройках клуба). Блок висит на html[data-tb-size] по той же причине,
   что и остальные: пока владелец ничего не крутил, размеры считает css.css. */
html[data-tb-size] .root[data-ring="core"] .tb-core-blinds {
    font-size: calc(var(--timer-size) * .072 * var(--tb-scale, 1) * var(--tb-value, 1));
}
html[data-tb-size] .root[data-ring="core"] .tb-core-ante {
    font-size: calc(var(--timer-size) * .038 * var(--tb-scale, 1) * var(--tb-label, 1));
}

html[data-theme="light"] .root[data-ring="core"] .timer-wrap::before {
    background: #FFFFFF;
    box-shadow: inset 0 0 0 1px rgba(11, 14, 20, .12);
}
html[data-theme="light"] .root[data-ring="core"] .tb-tick { stroke: rgba(11, 14, 20, .30); }
html[data-theme="light"] .root[data-ring="core"] .tb-tick.is-big { stroke: rgba(11, 14, 20, .60); }
html[data-theme="light"] .root[data-ring="core"] .tb-core-blinds { color: #0B0E14; }
html[data-theme="light"] .root[data-ring="core"] .tb-core-ante-k { color: rgba(11, 14, 20, .60); }

/* --- ячейки: цифры перекатываются, как на механическом табло ---
   #timer-value остаётся в DOM (в него пишет js.js) и просто уводится с глаз:
   display:none лишил бы нас размера, по которому считается кегль ячеек. */
.root[data-ring="flip"] #timer-ring,
.root[data-ring="flip"] .ring-glow { display: none; }
.root[data-ring="flip"] .timer-wrap {
    width: auto;
    height: auto;
    min-width: var(--timer-size);
    padding: 1.6vmin 0;
}
.root[data-ring="flip"] #timer-value {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
}
.root[data-ring="flip"] .timer-label { position: static; inset: auto; padding: 0; gap: 1.4vmin; }
.root[data-ring="flip"] .level-progress { width: 64%; }

.tb-digits {
    display: flex;
    align-items: stretch;
    justify-content: center;
    gap: .09em;
    /* Второй предел — по высоте экрана: на низком ТВ (1280×720) кегль,
       посчитанный только от диаметра, выдавливал блайнды за нижний край. */
    /* Три предела: диаметр, высота экрана и ЕГО ШИРИНА — на планшете в портрете
       четыре ячейки вылезали за правый край. */
    font-size: min(clamp(40px, calc(var(--timer-size) * .40), 260px), 30vh, 19vw);
    max-width: 100%;
    line-height: 1;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
/* Минуты от секунд разводит зазор: двоеточие в ячейке ломало ритм ряда. */
.tb-dg:nth-child(2) { margin-right: .34em; }
.tb-dg {
    position: relative;
    overflow: hidden;
    min-width: .78em;
    padding: .16em .1em;
    border-radius: .1em;
    background: linear-gradient(180deg, #1b1d24 0 50%, #12141a 50% 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 18px 34px rgba(0, 0, 0, .5);
}
/* Риска посередине — линия разрыва лопасти. */
.tb-dg::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 1px;
    background: rgba(0, 0, 0, .8);
    box-shadow: 0 1px 0 rgba(255, 255, 255, .045);
    z-index: 3;
}
.tb-dg > i { display: block; font-style: normal; text-align: center; }
.tb-dg > .nxt {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: translateY(102%);
}
html[data-theme="light"] .tb-dg {
    background: linear-gradient(180deg, #fff 0 50%, #f3f4f8 50% 100%);
    box-shadow: 0 18px 34px rgba(11, 14, 20, .12);
    color: #10131a;
}
html[data-theme="light"] .tb-dg::before { background: rgba(11, 14, 20, .14); box-shadow: none; }

/* =========================================================
   5. КОМПОНОВКА: где стоят метрики
   Зоны те же (левая/правая/нижний ряд) — меняется только их место, иначе
   перетаскивание в редакторе и сохранённые раскладки пришлось бы переучивать.
   ========================================================= */
.tb-rowzones {
    display: flex;
    width: 100%;
    min-width: 0;
    gap: var(--gap);
}
.tb-rowzones .col-side {
    /* Доля группы = число её блоков (--tbn ставит board-layout.js и редактор):
       ячейки одной ширины по всей ленте, сколько бы блоков ни было слева и справа. */
    flex: var(--tbn, 1) 1 0;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 0;
    width: auto;
    justify-self: auto;
}
.tb-rowzones .col-side .tb-b { flex: 1 1 0; min-width: 0; }
/* QR в тонкой ленте: код и подпись СТРОКОЙ, а не столбиком — иначе блок торчит
   из ленты, подпись обрезается, а соседние значения («средний стек») ужимаются
   в многоточие, потому что квадрат отъедает их долю ширины. */
.tb-rowzones .tb-qr {
    /* Ячейка берёт ровно свою ширину и не отъедает долю у значений. */
    flex: 0 0 auto;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
.tb-rowzones .tb-qr-box {
    flex: 0 0 auto;
    /* Нижний предел обязателен: на короткой ленте (широкий экран, низкий
       вьюпорт) код скатывался до 47px и переставал читаться камерой. */
    width: calc(clamp(64px, 8.4vh, 96px) * var(--bs, 1));
    height: calc(clamp(64px, 8.4vh, 96px) * var(--bs, 1));
    padding: 4px;
}
.tb-rowzones .tb-qr .k {
    text-align: center;
    white-space: nowrap;
    max-width: none;
    line-height: 1.2;
    font-size: calc(clamp(9px, .72vw, 15px) * var(--tb-scale, 1) * var(--tb-label, 1));
}
.tb-rowzones .card-bzone[hidden] { display: none; }

.root[data-layout="over"],
.root[data-layout="under"] { --timer-size: min(70vmin, 54vh, 660px); }
.root[data-layout="over"] .main.is-rows,
.root[data-layout="under"] .main.is-rows {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: var(--gap);
    height: 100%;
}
/* Лента метрик прижата к шапке, таймер занимает весь остаток и стоит по центру:
   иначе строка висела над цифрами посреди пустого экрана. */
.root[data-layout="over"] .main.is-rows .col-center,
.root[data-layout="under"] .main.is-rows .col-center {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.root[data-layout="over"] .main.is-rows .col-center,
.root[data-layout="under"] .main.is-rows .col-center { width: 100%; }
.tb-rowzones--under { margin-top: 4px; margin-bottom: 8px; }
/* Лента под шапкой: свой воздух, иначе подписи липнут к названию клуба. */
.tb-rowzones--over { margin-top: 1.2vmin; }

/* «Блайнды над таймером» (layout=top): .bottom стоит в DOM перед .main, поэтому
   строки сетки — шапка, блайнды, ОСНОВНОЕ (1fr), бегущая строка, дисклеймер.
   Без этого 1fr достался бы ряду блайндов, и кольцо уехало бы вниз. */
.root[data-layout="top"] { grid-template-rows: auto auto 1fr auto auto; }
.root[data-layout="top"] .bottom { margin-top: .6vmin; }

/* Ячейка метрики в строке: подпись над значением, разделение — волоском,
   который гаснет к краям. Рамок и заливок здесь нет намеренно. */
.tb-rowzones .col-side .tb-b {
    position: relative;
    padding: .5vmin 1.6vw;
    text-align: left;
}
/* Волосок одинаковой длины и на одной высоте у ВСЕХ ячеек. На процентах от
   высоты ячейки линии разъезжались: у «повторных входов» есть подстрочка,
   у QR — свой квадрат, у рекламы — карточка. Отсчёт от ВЕРХА: все ячейки
   ленты начинаются на одной линии. */
.tb-rowzones .col-side .tb-b + .tb-b::after,
.tb-rowzones .col-right > .tb-b:first-child::after {
    content: '';
    position: absolute;
    left: 0;
    top: 14px;
    bottom: auto;
    height: min(52px, 4.4vw);
    width: 1px;
    background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .16), transparent);
}
.tb-rowzones .col-right::after { content: none; }
.tb-rowzones .col-right { position: relative; }
html[data-theme="light"] .tb-rowzones .col-side .tb-b + .tb-b::after,
html[data-theme="light"] .tb-rowzones .col-right > .tb-b:first-child::after {
    background: linear-gradient(180deg, transparent, rgba(11, 14, 20, .18), transparent);
}
.tb-rowzones .k {
    font-size: calc(clamp(11px, .78vw, 19px) * var(--tb-scale, 1) * var(--tb-label, 1));
    /* Разрядка в ленте меньше, чем в колонках, и подпись имеет право уйти на
       вторую строку: на широком шрифте (Unbounded) «ПОВТОРНЫХ ВХОДОВ» в одну
       строку не помещается ни при каком кегле и обрезалась на полуслове. */
    letter-spacing: .14em;
    white-space: normal;
    overflow: visible;
    line-height: 1.15;
    color: var(--text-muted);
}
.tb-rowzones .v {
    font-size: calc(clamp(18px, 1.6vw, 38px) * var(--tb-scale, 1) * var(--tb-value, 1) * var(--bs, 1));
    letter-spacing: -.02em;
    /* Ужимает кегль сама доска (fitBlocks); отсечка нужна как страховка на
       случай широкого шрифта — иначе значение переливается на соседнюю ячейку.
       Многоточия нет: обрезанная цифра хуже мелкой. */
    overflow: hidden;
    text-overflow: clip;
}

/* Подпись уровня — набор, а не капсула: пилюля с подложкой на доске читается
   как стоковый бейдж из дашборда. */
html[data-tb] .root .level-progress { border: 0 !important; }
html[data-tb] .root .timer-level {
    background: none !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
}

/* Рекламная карточка внутри строки метрик: своей ширины у неё нет, и на
   планшете она выталкивала строку за правый край. Ограничиваем и её, и QR. */
.tb-rowzones .card-bzone{ flex:0 0 auto; max-width:min(26%, 240px); min-width:0; }
.tb-rowzones .card-bzone .bzone-qr{ max-width:min(100%, 11vh); }

/* Узкая полоса (1024-1400px): шесть ячеек в ряд — поля съедают место под
   значение, и «1 080 000» обрезалось. */
@media (max-width: 1400px) {
    .tb-rowzones .col-side .tb-b { padding: .5vmin .9vw; }
}
/* До 1200px шесть ячеек и рекламная карточка в один ряд уже не помещаются —
   переносим группы одна под другую (на 1024×768 строка уезжала за экран). */
@media (max-width: 1200px) {
    .tb-rowzones { flex-wrap: wrap; }
    .tb-rowzones .col-side { flex: 1 1 100%; }
}

/* Планшет в портрете и телефон: строка разворачивается в столбик — иначе
   шесть блоков и реклама не помещаются по ширине и доска уезжает вбок. */
@media (max-width: 900px) {
    .tb-rowzones { flex-direction: column; }
    .tb-rowzones .col-side { flex: 0 0 auto; flex-direction: column; flex-wrap: nowrap; }
    .tb-rowzones .card-bzone { max-width: 100%; }
    /* Вертикальные волоски-разделители в столбике не нужны — там делит отступ. */
    .tb-rowzones .col-side .tb-b + .tb-b::after,
    .tb-rowzones .col-right::after { display: none; }
    .root[data-layout="over"] .main.is-rows,
    .root[data-layout="under"] .main.is-rows { height: auto; }
}

/* =========================================================
   6. ТРИ ДОСКИ
   ========================================================= */

/* ---------- ЗАЛ: трансляционная ведомость ----------
   Ни одной коробки: пространство делят волоски и воздух, слева по всей высоте
   идёт акцентная планка — она же держит фирменный цвет клуба. */
.root[data-tpl="hall"] .card,
.root[data-tpl="hall"] .blind-card {
    background: none !important;
    border: 0 !important;
    box-shadow: none !important;
    border-radius: 0 !important;
}
.root[data-tpl="hall"]::before {
    content: '';
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: 5px;
    z-index: 2;
    pointer-events: none;
    background: linear-gradient(180deg,
        transparent 0%,
        rgba(var(--accent-rgb, 255, 46, 59), .95) 18%,
        rgba(var(--accent-rgb, 255, 46, 59), .35) 72%,
        transparent 100%);
}
.root[data-tpl="hall"] .timer-level {
    letter-spacing: .42em;
    font-size: calc(clamp(12px, .9vw, 22px) * var(--tb-scale, 1) * var(--tb-label, 1));
    color: var(--text-muted);
}
.root[data-tpl="hall"] .timer-value {
    font-size: min(clamp(110px, 20.5vw, 440px), 40vh);
    font-weight: 800;
    letter-spacing: -.028em;
    text-shadow: none;
}
/* Линия уровня — единственная «шкала» этой доски, поэтому она во всю ширину
   центра и заметно толще стандартной. */
.root[data-tpl="hall"] .level-progress {
    width: min(52vw, 900px);
    height: 5px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .07);
}
.root[data-tpl="hall"] .blinds-row { gap: 0; }
.root[data-tpl="hall"] .blind-card {
    position: relative;
    padding: 1.2vmin 2vw 0;
    gap: .4vmin;
}
.root[data-tpl="hall"] .blind-card + .blind-card::before {
    content: '';
    position: absolute;
    left: 0;
    top: 18%;
    bottom: 18%;
    width: 1px;
    background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .16), transparent);
}
.root[data-tpl="hall"] .blind-label {
    letter-spacing: .34em;
    font-size: calc(clamp(11px, .8vw, 19px) * var(--tb-scale, 1) * var(--tb-label, 1)) !important;
    color: var(--text-muted);
}
.root[data-tpl="hall"] .blind-value {
    font-size: calc(clamp(38px, 4.6vw, 104px) * var(--tb-scale, 1) * var(--tb-value, 1) * var(--bs, 1)) !important;
    font-weight: 800;
    letter-spacing: -.02em;
    /* Цветом отмечен только большой блайнд — три красных числа в ряд
       превращают акцент в фон. */
    color: var(--text);
}
.root[data-tpl="hall"] .blind-card-main .blind-value {
    color: rgba(var(--accent-soft-rgb, 255, 86, 102), 1);
    font-size: calc(clamp(46px, 5.8vw, 132px) * var(--tb-scale, 1) * var(--tb-value, 1) * var(--bs, 1)) !important;
}
.root[data-tpl="hall"] .blind-card-main .blind-label { color: rgba(var(--accent-soft-rgb, 255, 86, 102), .85); }
.root[data-tpl="hall"] .legal-note { background: none; border: 0; box-shadow: none; }

/* ---------- ХРОНОМЕТР: прибор ----------
   Бланки без рамок: мягкий градиент + волосок сверху; у главного блока —
   акцентная планка у левого края во всю высоту. */
.root[data-tpl="chrono"] .card,
.root[data-tpl="chrono"] .blind-card {
    position: relative;
    background: linear-gradient(180deg, rgba(255, 255, 255, .055), rgba(255, 255, 255, .012)) !important;
    border: 0 !important;
    box-shadow: 0 18px 40px rgba(0, 0, 0, .38) !important;
    border-radius: 14px !important;
    overflow: hidden;
}
.root[data-tpl="chrono"] .card::after,
.root[data-tpl="chrono"] .blind-card::after {
    content: '';
    position: absolute;
    left: 8%;
    right: 8%;
    top: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .22), transparent);
}
.root[data-tpl="chrono"] .tb-b.is-hero::before {
    content: '';
    position: absolute;
    left: 0;
    top: 12%;
    bottom: 12%;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: linear-gradient(180deg,
        rgba(var(--accent-rgb, 255, 46, 59), .25),
        rgba(var(--accent-rgb, 255, 46, 59), .95),
        rgba(var(--accent-rgb, 255, 46, 59), .25));
}
.root[data-tpl="chrono"] .k,
.root[data-tpl="chrono"] .blind-label {
    letter-spacing: .3em;
    color: rgba(199, 206, 218, .62);
    font-size: calc(clamp(11px, .78vw, 19px) * var(--tb-scale, 1) * var(--tb-label, 1)) !important;
}
.root[data-tpl="chrono"] .v {
    font-size: calc(clamp(22px, 1.9vw, 40px) * var(--tb-scale, 1) * var(--tb-value, 1) * var(--bs, 1));
}
.root[data-tpl="chrono"] .blind-value {
    font-size: calc(clamp(34px, 4.2vw, 96px) * var(--tb-scale, 1) * var(--tb-value, 1) * var(--bs, 1)) !important;
    letter-spacing: -.01em;
    color: var(--text);
}
.root[data-tpl="chrono"] .blind-card-main .blind-value { color: rgba(var(--accent-soft-rgb, 255, 86, 102), 1); }
.root[data-tpl="chrono"] .timer-level { letter-spacing: .34em; }

/* ---------- ВОКЗАЛ: механическое табло ----------
   Ячейки с риской, узкий шрифт, метрики внизу — расписанием. */
.root[data-tpl="depot"] .card,
.root[data-tpl="depot"] .blind-card {
    position: relative;
    background: linear-gradient(180deg, #16181e 0 50%, #101218 50% 100%) !important;
    border: 0 !important;
    border-radius: 8px !important;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .045), 0 14px 28px rgba(0, 0, 0, .5) !important;
    overflow: hidden;
}
.root[data-tpl="depot"] .card::before,
.root[data-tpl="depot"] .blind-card::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 1px;
    background: rgba(0, 0, 0, .78);
    box-shadow: 0 1px 0 rgba(255, 255, 255, .04);
}
.root[data-tpl="depot"] .k,
.root[data-tpl="depot"] .blind-label {
    letter-spacing: .38em;
    color: rgba(198, 214, 232, .62);
}
.root[data-tpl="depot"] .v,
.root[data-tpl="depot"] .blind-value {
    color: #eef3fa;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 0 rgba(0, 0, 0, .75);
}
.root[data-tpl="depot"] .blind-card-main .blind-value { color: rgba(var(--accent-soft-rgb, 255, 86, 102), 1); }
.root[data-tpl="depot"] .timer-level {
    letter-spacing: .46em;
    font-size: calc(clamp(12px, .92vw, 22px) * var(--tb-scale, 1) * var(--tb-label, 1));
}
/* Нижнее расписание: ячейки одной высоты, значения в ряд, разделение волоском. */
.root[data-tpl="depot"] .tb-rowzones--under .tb-b {
    background: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    padding: .4vmin 1.4vw;
}
.root[data-tpl="depot"] .tb-rowzones--under .tb-b::before { display: none; }   /* риска лопасти в строке лишняя */
.root[data-tpl="depot"] .tb-rowzones--under .v { font-size: calc(clamp(18px, 1.5vw, 32px) * var(--tb-scale, 1) * var(--tb-value, 1)); }

/* =========================================================
   7. ДВИЖЕНИЕ
   Секундный цикл не должен дёргать крупные элементы: на телевизоре подпрыгивающие
   цифры и «дышащий» круг читаются как дешёвый эффект. Поэтому на досках
   конструктора прежние ccTick / ccHeartbeat / ccShock выключены, а движение
   собрано заново: вход по очереди, перекат цифр, смена уровня и последняя минута.
   Всё держится на transform/opacity — фильтров и полноэкранных перерисовок нет
   (бюджет ТВ, см. память tv-board-render-budget).
   ========================================================= */
html[data-tb] .root .timer-value.tick { animation: none !important; }
html[data-tb] body.t-critical .timer-wrap { animation: none !important; }
html[data-tb] .root .timer-wrap.level-burst::before,
html[data-tb] .root .timer-wrap.level-burst::after { animation: none !important; }

/* --- вход: доска собирается по очереди, сверху вниз --- */
@keyframes tbIn {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
}
@keyframes tbInCenter {
    from { opacity: 0; transform: translateY(20px) scale(.985); }
    to   { opacity: 1; transform: none; }
}
html[data-tb] .root .top-bar { animation: tbIn .5s cubic-bezier(.2, .8, .2, 1) both; }
html[data-tb] .root .tb-rowzones .tb-b { animation: tbIn .5s cubic-bezier(.2, .8, .2, 1) both; }
html[data-tb] .root .tb-rowzones .tb-b:nth-child(1) { animation-delay: .06s; }
html[data-tb] .root .tb-rowzones .tb-b:nth-child(2) { animation-delay: .12s; }
html[data-tb] .root .tb-rowzones .tb-b:nth-child(3) { animation-delay: .18s; }
html[data-tb] .root .col-center .timer-wrap { animation: tbInCenter .62s cubic-bezier(.2, .8, .2, 1) both; animation-delay: .1s; }
html[data-tb] .root .blinds-row .blind-card { animation: tbIn .55s cubic-bezier(.2, .8, .2, 1) both; }
html[data-tb] .root .blinds-row .blind-card:nth-child(1) { animation-delay: .24s; }
html[data-tb] .root .blinds-row .blind-card:nth-child(2) { animation-delay: .3s; }
html[data-tb] .root .blinds-row .blind-card:nth-child(3) { animation-delay: .36s; }

/* --- перекат цифр в ячейках --- */
@keyframes tbRollOutA { to { transform: translateY(-102%); opacity: .1; } }
@keyframes tbRollInA  { from { transform: translateY(102%); opacity: .1; } to { transform: translateY(0); opacity: 1; } }
@keyframes tbRollOutB { to { transform: translateY(-102%); opacity: .1; } }
@keyframes tbRollInB  { from { transform: translateY(102%); opacity: .1; } to { transform: translateY(0); opacity: 1; } }
.tb-dg.is-roll-a > .cur { animation: tbRollOutA .34s cubic-bezier(.3, .8, .25, 1) both; }
.tb-dg.is-roll-a > .nxt { animation: tbRollInA  .34s cubic-bezier(.3, .8, .25, 1) both; }
.tb-dg.is-roll-b > .cur { animation: tbRollOutB .34s cubic-bezier(.3, .8, .25, 1) both; }
.tb-dg.is-roll-b > .nxt { animation: tbRollInB  .34s cubic-bezier(.3, .8, .25, 1) both; }

/* --- смена уровня: один заметный жест вместо трёх ---
   блайнды коротко переставляются, по акцентной планке «Зала» проходит свет. */
@keyframes tbSwap {
    0%   { transform: translateY(0); opacity: 1; }
    38%  { transform: translateY(-26%); opacity: 0; }
    62%  { transform: translateY(22%); opacity: 0; }
    100% { transform: translateY(0); opacity: 1; }
}
html[data-tb] .root .blind-card.flash .blind-value { animation: tbSwap .62s cubic-bezier(.3, .8, .25, 1); }
@keyframes tbPlank {
    0%   { opacity: .55; transform: translateY(-30%); }
    45%  { opacity: 1; }
    100% { opacity: .55; transform: translateY(30%); }
}
html[data-tb] body.level-flash .root[data-tpl="hall"]::before,
html[data-tb] body.level-flash .root[data-tpl="chrono"] .tb-b.is-hero::before { animation: tbPlank .9s cubic-bezier(.2, .8, .2, 1); }

/* --- последняя минута: доска не прыгает, а «наливается» ---
   цвет уходит в акцент, шкала уровня медленно дышит (только opacity). --- */
@keyframes tbBreath { 0%, 100% { opacity: 1; } 50% { opacity: .62; } }
html[data-tb] body.t-critical .root .timer-value,
html[data-tb] body.t-critical .root .tb-dg > i { color: rgba(var(--accent-soft-rgb, 255, 86, 102), 1); }
html[data-tb] body.t-critical .root .level-progress > span,
html[data-tb] body.t-critical .root .ring-fg { animation: tbBreath 1.8s ease-in-out infinite; }
html[data-tb] body.t-critical .root[data-ring="dial"] .tb-hand-s { animation: tbBreath 1.8s ease-in-out infinite; }

/* =========================================================
   8. ДОСТУПНОСТЬ ДВИЖЕНИЯ
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
    html[data-tb] .root .top-bar,
    html[data-tb] .root .tb-rowzones .tb-b,
    html[data-tb] .root .col-center .timer-wrap,
    html[data-tb] .root .blinds-row .blind-card,
    html[data-tb] .root .blind-card.flash .blind-value,
    html[data-tb] body.t-critical .root .level-progress > span,
    html[data-tb] body.t-critical .root .ring-fg,
    .tb-dg.is-roll-a > .cur, .tb-dg.is-roll-a > .nxt,
    .tb-dg.is-roll-b > .cur, .tb-dg.is-roll-b > .nxt { animation: none !important; }
    .root[data-ring="dial"] .tb-hand { transition: none !important; }
}
