

/* --------------------------------------------------------------- Шрифты -- */

@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url("../fonts/roboto-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url("../fonts/roboto-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


@font-face {
  font-family: "eob-icons";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/eob-icons.woff2") format("woff2"),
       url("../fonts/eob-icons.ttf") format("truetype");
}

/* ---------------------------------------------------------------- Сброс -- */

*,
*::before,
*::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
}

/* Размер шрифта по умолчанию — через те же две переменные, что и остальной
   текст, чтобы масштаб не разъехался там, где кегль явно не задан */
html { font-size: calc(16 * var(--dpx) * var(--tz)); }

/* Мгновенное применение, без переходов. Нужно всюду, где js меняет --dpx или
   --tz: пересчёт масштаба не должен превращаться в анимацию подсказки поля.
   Класс висит один кадр, см. main.js */
.is-instant *,
.is-instant *::before,
.is-instant *::after { transition: none !important; }

/* Эталон для замера текстового масштаба («Только текст» в Firefox и аналоги).
   Кегль задан литералом, без --dpx и без --tz: замер должен видеть только
   множитель браузера и ничего больше, иначе он зациклится сам на себя. */
.tz-probe {
  position: fixed;
  left: -9999px;
  top: 0;
  display: inline-block;
  font-size: 100px;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
}

body {
  background: var(--c-page, #f8f6f1);
  font-family: "Roboto", "Helvetica Neue", Arial, sans-serif;
  overflow: hidden;

  /* Ширины глифов берём геометрические, без подгонки под пиксельную сетку.
     Иначе браузер округляет их по-своему на каждом масштабе, и текст на пару
     десятых пикселя «ходит» — заметнее всего на подсказке в поле. Наследуется,
     поэтому хватает одного объявления на body. */
  text-rendering: geometricPrecision;

  transition: background-color .2s linear;
}

img { display: block; border: 0; }

button {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-appearance: none;
          appearance: none;
}

input {
  margin: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  -webkit-appearance: none;
          appearance: none;
}

/* ------------------------------------------------- Темы по дням недели --
   Семь вариантов из макета «Слоны высота поля 60рх изм.2», по фрейму на
   день. Какой показать — решает js по текущему дню, см. js/main.js. */

/* Понедельник — фрейм 25555672 */
[data-theme="mon"] {
  --c-page:         #f8f6f1;
  --c-lead:         #76d1ff;
  --c-title:        #1db3fd;
  --c-border:       173, 205, 221;
  --c-value:        #1db3fd;
  --c-placeholder:  #b9b9b9;
  --c-label:        #b9b9b9;
  --c-btn-on:       #ffa8bc;
  --c-btn-on-text:  #ffffff;
  --c-btn-off:      #f8d0d9;
  --c-btn-off-text: #5b5b5b;
  --c-dot-off:      #f8d0d9;
  --c-dot-on:       #ffa8bc;
}

/* Вторник — фрейм 25555673 */
[data-theme="tue"] {
  --c-page:         #fefefe;
  --c-lead:         #ffbf8d;
  --c-title:        #ffa660;
  --c-border:       252, 218, 191;
  --c-value:        #ff7100;
  --c-placeholder:  #b3b3b3;
  --c-label:        #827f7b;
  --c-btn-on:       #ffaf6f;
  --c-btn-on-text:  #ffffff;
  --c-btn-off:      #fcdabf;
  --c-btn-off-text: #7d7673;
  --c-dot-off:      #fcdabf;
  --c-dot-on:       #ffaf6f;
}

/* Среда — фрейм 25555723 */
[data-theme="wed"] {
  --c-page:         #f8f6f1;
  --c-lead:         #ffa5b9;
  --c-title:        #fb7997;
  --c-border:       248, 208, 217;
  --c-value:        #fb7997;
  --c-placeholder:  #adadad;
  --c-label:        #b9b9b9;
  --c-btn-on:       #0ba2b6;
  --c-btn-on-text:  #ffffff;
  --c-btn-off:      #bae0e5;
  --c-btn-off-text: #787878;
  --c-dot-off:      #bae0e5;
  --c-dot-on:       #0ba2b6;
}

/* Четверг — фрейм 25555674 */
[data-theme="thu"] {
  --c-page:         #fefcf8;
  --c-lead:         #e2d1a2;
  --c-title:        #f1bd36;
  --c-border:       248, 208, 217;
  --c-value:        #f1bd36;
  --c-placeholder:  #adadad;
  --c-label:        #b9b9b9;
  --c-btn-on:       #f1bd36;
  --c-btn-on-text:  #ffffff;
  --c-btn-off:      #f3dfa9;
  --c-btn-off-text: #6e6e6e;
  --c-dot-off:      #f3dfa9;
  --c-dot-on:       #f1bd36;
}

/* Пятница — фрейм 25555777 */
[data-theme="fri"] {
  --c-page:         #fcf7f7;
  --c-lead:         #ffa5b9;
  --c-title:        #fb7997;
  --c-border:       248, 208, 217;
  --c-value:        #fb7997;
  --c-placeholder:  #adadad;
  --c-label:        #b9b9b9;
  --c-btn-on:       #0ba2b6;
  --c-btn-on-text:  #ffffff;
  --c-btn-off:      #bae0e5;
  --c-btn-off-text: #787878;
  --c-dot-off:      #bae0e5;
  --c-dot-on:       #0ba2b6;
}

/* Суббота — фрейм 25555782 */
[data-theme="sat"] {
  --c-page:         #fdfeff;
  --c-lead:         #e17ee4;
  --c-title:        #bf61c1;
  --c-border:       225, 126, 228;
  --c-value:        #bf61c1;
  --c-placeholder:  #adadad;
  --c-label:        #b9b9b9;
  --c-btn-on:       #4a78cd;
  --c-btn-on-text:  #ffffff;
  --c-btn-off:      #cad6ec;
  --c-btn-off-text: #4c525c;
  --c-dot-off:      #cad6ec;
  --c-dot-on:       #4a78cd;
}

/* Воскресенье — фрейм 25555675 */
[data-theme="sun"] {
  --c-page:         #f0faff;
  --c-lead:         #f985a5;
  --c-title:        #ff0048;
  --c-border:       248, 208, 217;
  --c-value:        #ff0048;
  --c-placeholder:  #adadad;
  --c-label:        #b9b9b9;
  --c-btn-on:       #ff0048;
  --c-btn-on-text:  #ffffff;
  --c-btn-off:      #ffd7e2;
  --c-btn-off-text: #6e6e6e;
  --c-dot-off:      #ffd7e2;
  --c-dot-on:       #ff0048;
}

/* Общие для всех тем */
:root {
  --c-accent:   0, 135, 252;  /* #0087fc — наведение и фокус поля, ТЗ п.3 */
  --c-error:    #ff0303;
  --c-error-value: #827f7b;
  --c-dot-idle: #d9d9d9;

  --card-top:      calc(184 * var(--dpx));
  --card-right:    calc(415 * var(--dpx));
  --btn-text-top:  calc(13 * var(--dpx));


  --hairline: .245;

  /* ------------------------------------------------------------------------
     Один макетный пиксель, выраженный в css-пикселях. Пересчитывается из js.

     Через эту переменную идут ВСЕ длины в файле — размеры, отступы, координаты,
     скругления, кегли. Это и есть весь механизм масштабирования: холст не
     растягивается через transform, а сразу верстается в конечных размерах.

     Почему именно так, а не transform. При transform браузер считает раскладку
     в макетных пикселях, прижимает края блоков к целым пикселям в этой системе
     координат, и только потом всё масштабирует — на экране края оказываются в
     дробных позициях и сглаживаются, причём по-разному на разных ступенях
     масштаба. Отсюда и брались «дрожание» и мыло. При расчёте через --dpx
     раскладка идёт сразу в конечных координатах, и прижатие к пиксельной сетке
     попадает в настоящие экранные пиксели.

     Единица здесь — запасное значение на случай, если js не отработал.
     --------------------------------------------------------------------- */
  --dpx: 1px;

  /* Толщина окантовки, уже в css-пикселях (не в макетных): js подбирает её так,
     чтобы на экране линия занимала ровно один пиксель и не размазывалась по
     двум. При масштабе 1:1 это те же 1px, что и в макете.

     Рисуется окантовка через box-shadow, а не border, и это принципиально:
     border-width браузер округляет до целого экранного пикселя, из-за чего на
     мелком масштабе страницы рамка получалась в разы толще. box-shadow этому
     округлению не подвержен и принимает дробную ширину. */
  --hairline-w: 1px;

  /* Компенсация текстового масштаба. 1 — обычный режим; в режиме «Только текст»
     js ставит сюда 1/z, и браузер, домножив обратно на z, рисует ровно то, что
     в макете.

     Через эту переменную обязаны идти ВСЕ font-size и ВСЕ line-height, заданные
     длиной: Firefox в этом режиме масштабирует и то, и другое (line-height в px
     — тоже, это не очевидно и стоило одного круга правок). Прочие длины —
     отступы, высоты, окантовки — он не трогает, их компенсировать не нужно.
     line-height числом (как у .tz-probe) компенсировать нельзя: он и так
     считается от уже отмасштабированного кегля.

     Если появятся letter-spacing, word-spacing или размеры в em/rem — их тоже
     надо проверить и, если браузер их масштабирует, провести через --tz. */
  --tz: 1;
}

/* --------------------------------------------------------------- Холст -- */

.stage {
  position: absolute;
  /* Позиция — через переменные, а не прямые стили: их выставляют и загрузочный
     скрипт в <head> (до первого кадра, чтобы не мигало), и fitStage из main.js */
  top: var(--stage-top, 0);
  left: var(--stage-left, 0);
  width: calc(1920 * var(--dpx));
  height: calc(800 * var(--dpx));
  overflow: hidden;
  display: flex;
  align-items: flex-start;
  background: var(--c-page);
  transition: background-color .2s linear;

  /* Отдельного слоя у холста намеренно нет. Пробовали — тексту не помогло:
     слой группирует отрисовку, но не замораживает её, и базовая линия внутри
     слоя всё равно прижимается к пиксельной сетке заново на каждой ступени
     масштаба. Зато слой на холсте отнимал свой слой у иллюстрации, и та снова
     начинала разъезжаться. Слой нужен именно иллюстрации, см. .illu. */
}


/* -------------------------------------------------------- Иллюстрации --
   Каждая иллюстрация — векторные части от дизайнера, разложенные рядами:
   у понедельника и среды сетка 2x2, у остальных 3x3. Части заходят друг на
   друга отрицательными полями — так на стыках не появляется светлых полосок.

   Все части собраны в один обёрточный <svg> (.illu__all): позиции плиток — это
   координаты x/y во viewBox, макетные пиксели. Раньше плитки были отдельными
   svg-элементами, каждый со своей css-коробкой, и Firefox прижимал каждую к
   своей ближайшей пиксельной линии — на смене масштаба часть плиток
   перескакивала через границу пикселя, часть нет, и рисунок дрожал. Координата
   во viewBox — чистая геометрия, прижатию не подвергается; это тот же приём,
   которым вылечена подводка (.card__lead). Пункт 9 ТЗ соблюдён: иллюстрация в
   разметке по-прежнему собрана из исходных частей.

   Координаты left/top самих иллюстраций округлены до целых макетных пикселей
   (сдвиг от макета не больше 0,53px). В режиме 1:1 целое число ложится ровно
   на пиксельную сетку, и слою нечего прижимать: иллюстрации с дробной
   координатой прыгали в Firefox, с целой — стояли. */

.illus {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.illu {
  position: absolute;
  font-size: 0;
  line-height: 0;

  /* Иллюстрация вынесена в отдельный слой, и это проверено на практике: без него
     браузер рисует каждую плитку сама по себе и каждую прижимает к своей
     ближайшей пиксельной линии. Дробные части координат у плиток разные, поэтому
     на смене масштаба часть перескакивает через границу пикселя, а часть нет —
     рисунок разъезжается на стыках. В своём слое плитки растеризуются вместе, в
     общей системе координат, и прижимается один раз вся картинка целиком.

     Слой должен быть именно здесь. Если поднять его на весь холст (.stage),
     иллюстрация перестаёт быть отдельным слоем и дрожание возвращается. */
  will-change: transform;
}

.illu[hidden] { display: none; }

/* Обёртка всех частей одной иллюстрации. Части заходят за нулевую точку
   отрицательными полями нахлёста, поэтому viewBox обёртки расширен до полного
   охвата (начинается с --ovm), а сама обёртка сдвинута на то же поле влево и
   вверх — итоговое положение рисунка не меняется. Так обёртке не нужен
   overflow: visible, который в Chromium отключает обрезку вложенных svg по их
   вьюпортам: у части рисунка контент — это весь холст целиком, где viewBox
   лишь окно-вырезка, и без обрезки такая часть расползается на всю сцену. */
.illu__all {
  display: block;
  width: calc(var(--ovw) * var(--dpx));
  margin: calc(var(--ovm) * var(--dpx)) 0 0 calc(var(--ovm) * var(--dpx));
}

.illu--mon {
  left: calc(336 * var(--dpx));
  top: calc(6 * var(--dpx));
  width: calc(721.14 * var(--dpx));
  --ovm: -15.7494;
  --ovw: 750.9978;
}

.illu--tue {
  left: calc(296 * var(--dpx));
  top: calc(2 * var(--dpx));
  width: calc(719.98 * var(--dpx));
  --ovm: -9.8637;
  --ovw: 738.1455;
}

.illu--wed {
  left: calc(294 * var(--dpx));
  top: calc(-40 * var(--dpx));
  width: calc(752.56 * var(--dpx));
  --ovm: -16.545;
  --ovw: 783.9318;
}

.illu--thu {
  left: calc(325 * var(--dpx));
  top: calc(-11 * var(--dpx));
  width: calc(722.96 * var(--dpx));
  --ovm: -10.3164;
  --ovw: 742.0128;
}

.illu--fri {
  left: calc(298 * var(--dpx));
  top: calc(14 * var(--dpx));
  width: calc(780.65 * var(--dpx));
  --ovm: -6.0594;
  --ovw: 791.8653;
  transform: scaleX(-1);
}

.illu--sat {
  left: calc(356 * var(--dpx));
  top: calc(16 * var(--dpx));
  width: calc(692.46 * var(--dpx));
  --ovm: -5.4642;
  --ovw: 702.5457;
}

.illu--sun {
  left: calc(174 * var(--dpx));
  top: calc(8 * var(--dpx));
  width: calc(867.77 * var(--dpx));
  --ovm: -5.7897;
  --ovw: 878.4729;
}

.card {
  position: relative;
  z-index: 1;
  width: calc(423 * var(--dpx));
  margin: var(--card-top) var(--card-right) 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Подводка — SVG-текст, а не html (см. разметку): html-текст Firefox прижимает
   базовой линией к целому экранному пикселю, и на границе округления строки
   прыгали на пиксель при смене масштаба. В SVG базовая линия задана координатой
   (y=23 и y=53 — замер с прежней html-вёрстки) и прижатию не подвергается —
   текст стоит как иллюстрации. Приём с эталонного сайта заказчика: свои
   заголовки он тоже рисует SVG-текстом, html-ом их не выводит.

   Внутренние размеры — в единицах viewBox, это макетные пиксели; масштаб даёт
   сама коробка svg через --dpx. Компенсации --tz нет намеренно: режим «Только
   текст» SVG-текст не масштабирует, дизайн в нём не меняется — ровно то, что
   требует ТЗ. Если в каком-то браузере текстовый зум всё же тронет SVG-текст,
   кегль ниже меняется на calc(24px * var(--tz)). */
.card__lead {
  display: block;
  width: calc(423 * var(--dpx));
  height: calc(60 * var(--dpx));
  fill: var(--c-lead);
  transition: fill .2s linear;
}

.card__lead text {
  font-weight: 300;
  font-size: 24px;      /* единицы viewBox, не экранные */
  text-anchor: middle;
}

.card__title {
  margin: calc(8 * var(--dpx)) 0 0;
  width: 100%;
  font-size: calc(40 * var(--dpx) * var(--tz));
  font-weight: 500;
  line-height: calc(47 * var(--dpx) * var(--tz));
  text-align: center;
  color: var(--c-title);
  transition: color .2s linear;
}

.card__body {
  /* Не центрируем, а отбиваем ровно на 47px: ширина карточки 423, а полей 328,
     и на центрирование остаётся 47,5 — поля вставали на полпикселя правее
     макета. С жёстким отступом поля и кнопка попадают на 1129, а ряд кружочков
     внутри тела (328 против 326) — на 1130, как в макете. */
  align-self: flex-start;
  margin-left: calc(47 * var(--dpx));
  margin-top: calc(15 * var(--dpx));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(18 * var(--dpx));
  width: calc(328 * var(--dpx));
}

/* -------------------------------------------------------------- Поля -- */

.field {
  position: relative;
  width: calc(328 * var(--dpx));
  height: calc(60 * var(--dpx));
  background: #ffffff;
  border-radius: calc(2 * var(--dpx));

  --fb-rgb: var(--c-border);
  --fb-alpha: var(--hairline);
}

/* Окантовка отдельным слоем: смена толщины 0,3px -> 1px не двигает текст */
.field::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: calc(2 * var(--dpx));
  box-shadow: inset 0 0 0 var(--hairline-w) rgba(var(--fb-rgb), var(--fb-alpha));
  pointer-events: none;
  transition: box-shadow .12s linear;
}

/* 0,3px #0087FC — наведение мышкой */
.field:hover { --fb-rgb: var(--c-accent); --fb-alpha: var(--hairline); }

/* Красная окантовка ошибки — уступает наведению и фокусу */
.field.is-error:not(:hover):not(:focus-within) { --fb-rgb: 255, 3, 3; --fb-alpha: 1; }

/* 1,0px #0087FC — поле в фокусе */
.field:focus-within { --fb-rgb: var(--c-accent); --fb-alpha: 1; }

.field__input {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  padding: calc(13 * var(--dpx)) calc(14 * var(--dpx))
           calc(19 * var(--dpx)) calc(18 * var(--dpx));
  font-size: calc(24 * var(--dpx) * var(--tz));
  font-weight: 300;
  line-height: calc(28 * var(--dpx) * var(--tz));
  color: var(--c-value);
  border-radius: calc(2 * var(--dpx));
  outline: none;
}

.field.is-error .field__input { color: var(--c-error-value); }

.field__input::-ms-reveal,
.field__input::-ms-clear { display: none; }


.field__label {
  position: absolute;
  left: calc(14 * var(--dpx));
  top: calc(13 * var(--dpx));
  font-size: calc(27 * var(--dpx) * var(--tz));
  font-weight: 300;
  line-height: calc(32 * var(--dpx) * var(--tz));
  white-space: nowrap;
  color: var(--c-placeholder);
  background: #ffffff;

  z-index: 1;
  pointer-events: none;
  transition: top .15s ease, font-size .15s ease, line-height .15s ease,
              color .12s linear, padding .15s ease;
}


.field.is-float .field__label {
  top: calc(-14 * var(--dpx));
  padding: calc(2 * var(--dpx)) calc(6 * var(--dpx)) 0;
  font-size: calc(18 * var(--dpx) * var(--tz));
  line-height: calc(21 * var(--dpx) * var(--tz));
  color: var(--c-label);
}

.field.is-float.is-error .field__label { color: var(--c-error); }



.error {
  display: none;
  align-items: center;
  align-self: flex-start;
  margin: calc(-11 * var(--dpx)) 0 calc(-1 * var(--dpx));
  padding-left: calc(20 * var(--dpx));
  height: calc(20 * var(--dpx));
}

.error.is-visible { display: flex; }

.error__icon {
  position: relative;
  flex: 0 0 auto;
  width: calc(20 * var(--dpx));
  height: calc(20 * var(--dpx));
  margin-right: calc(9 * var(--dpx));
}

.error__ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 var(--hairline-w) var(--c-error);
}

.error__bar {
  position: absolute;
  left: calc(9 * var(--dpx));
  top: calc(4.56 * var(--dpx));
  width: calc(2 * var(--dpx));
  height: calc(5.56 * var(--dpx));
  background: var(--c-error);
}

.error__dot {
  position: absolute;
  left: calc(8.5 * var(--dpx));
  top: calc(12.93 * var(--dpx));
  width: calc(3 * var(--dpx));
  height: calc(3 * var(--dpx));
  border-radius: 50%;
  background: var(--c-error);
}

.error__text {
  font-size: calc(18 * var(--dpx) * var(--tz));
  font-weight: 300;
  line-height: calc(20 * var(--dpx) * var(--tz));
  color: var(--c-error);
  white-space: nowrap;
}

/* ------------------------------------------------------------ Кнопка -- */

.submit {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  width: calc(328 * var(--dpx));
  height: calc(60 * var(--dpx));
  padding-top: var(--btn-text-top);
  border-radius: calc(2 * var(--dpx));
  background: var(--c-btn-off);
  color: var(--c-btn-off-text);
  font-size: calc(27 * var(--dpx) * var(--tz));
  font-weight: 300;
  line-height: calc(32 * var(--dpx) * var(--tz));
  text-align: center;
  cursor: default;
  transition: background-color .2s linear, color .2s linear;
}

.submit.is-active {
  background: var(--c-btn-on);
  color: var(--c-btn-on-text);
  font-weight: 400;
  cursor: pointer;
}

/* ---------------------------------------------- Кружочки смены стиля -- */

/* Кружочки стоят не потоком с gap, а каждый на своей координате из макета.
   В потоке ширина и промежуток округляются по разу каждый, но ошибки
   складываются от кружочка к кружочку, и последний уезжал заметнее всех.
   Считая координату сразу от макетной (48 = 38 ширины + 10 промежутка),
   округляем ровно один раз, и накопления не остаётся. */
.dots {
  position: relative;
  width: calc(326 * var(--dpx));
  height: calc(38 * var(--dpx));
}

.dots__item:nth-child(1) { left: 0; }
.dots__item:nth-child(2) { left: calc(48 * var(--dpx)); }
.dots__item:nth-child(3) { left: calc(96 * var(--dpx)); }
.dots__item:nth-child(4) { left: calc(144 * var(--dpx)); }
.dots__item:nth-child(5) { left: calc(192 * var(--dpx)); }
.dots__item:nth-child(6) { left: calc(240 * var(--dpx)); }
.dots__item:nth-child(7) { left: calc(288 * var(--dpx)); }

.dots__item {
  position: absolute;
  top: 0;
  width: calc(38 * var(--dpx));
  height: calc(38 * var(--dpx));
  font-family: "eob-icons";
  font-size: calc(38 * var(--dpx) * var(--tz));
  line-height: calc(38 * var(--dpx) * var(--tz));
  color: var(--c-dot-idle);
  cursor: pointer;
  transition: color .2s linear;
}

.dots__item::before {
  content: "\e900";
  display: block;
  speak: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Текущий стиль: бледный кружок, пока форма не заполнена, и яркий — когда заполнена */
.dots__item.is-current { color: var(--c-dot-off); }
.stage.is-ready .dots__item.is-current { color: var(--c-dot-on); }

.dots__item:focus-visible {
  outline: 1px solid rgb(var(--c-accent));
  outline-offset: 2px;
  border-radius: 50%;
}

.dots__item:disabled { cursor: default; }
