/* ==========================================================================
   PlanV — слой веб-клиента поверх дизайн-системы / web client layer on top of the design system
   RU: Здесь только то, чего нет в макетах: экраны приложения, безопасные зоны айфона,
       поведение при установке на домашний экран. Токены и атомы — в planv.css.
   EN: Only what the mockups lack: app screens, iPhone safe areas, home-screen install
       behaviour. Tokens and atoms live in planv.css.
   ========================================================================== */

/* RU: 100dvh, а не 100vh: на мобильных Safari и Chrome адресная строка съезжает, и
       100vh оказывается больше видимой области — нижняя кнопка уходит за край экрана.
   EN: 100dvh rather than 100vh: on mobile Safari and Chrome the address bar retracts, making
       100vh taller than the visible area — the bottom button ends up off-screen. */
html, body { height: 100%; overscroll-behavior-y: none; }

/* RU: Высота экранной клавиатуры, вычисляется в app.js через visualViewport.
       0px по умолчанию — без него calc() ниже станет недействительным и нижние
       панели пропадут совсем.
   EN: The on-screen keyboard height, computed in app.js via visualViewport. The 0px default is
       required — without it the calc() below becomes invalid and the bottom bars vanish. */
:root { --keyboard-inset: 0px; }

.screen {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  height: 100dvh;
  background: var(--bg);
}
.screen[hidden] { display: none; }

/* RU: Отступы по безопасным зонам: на айфонах с вырезом верхняя панель иначе лезет
       под «чёлку», а нижняя — под индикатор home.
   EN: Safe-area padding: on notched iPhones the top bar otherwise slides under the notch and
       the bottom bar under the home indicator. */
.topbar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: calc(env(safe-area-inset-top) + 12px) 16px 10px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg);
}
.brand { display: flex; align-items: center; gap: 8px; color: var(--brand-600); }

.body {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 12px 14px calc(env(safe-area-inset-bottom) + 120px);
}

.tabbar {
  position: fixed;
  left: 0; right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 12px 16px calc(env(safe-area-inset-bottom) + 16px);
  bottom: var(--keyboard-inset);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--line-soft);
  z-index: 20;
}

/* RU: Квадрат «стоп» и точка «запись» рисуются, а не берутся из шрифта: эмодзи и
       символы Unicode выглядят по-разному на Android и iOS, а это главная кнопка.
   EN: The stop square and record dot are drawn rather than taken from a font: emoji and
       Unicode symbols render differently on Android and iOS, and this is the primary button. */
.rec-dot { width: 26px; height: 26px; border-radius: 50%; background: #fff; display: block; }
.rec-square { width: 24px; height: 24px; border-radius: 6px; background: #fff; display: block; }

.rec-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.rec-timer {
  font-size: 56px;
  font-weight: 300;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  margin: 18px 0 2px;
}

/* RU: Волна во время записи занимает всю ширину и строится из живого уровня.
       Высота фиксирована, чтобы столбики не «прыгали» по вертикали при перерисовке.
   EN: The recording waveform spans the full width and is built from the live level. Its height
       is fixed so bars do not jump vertically on each repaint. */
#rec-wave { width: 100%; height: 64px; justify-content: center; margin: 22px 0 6px; }
#rec-wave i { transition: height 90ms linear; animation: none; }

.memo-panel {
  width: 100%;
  text-align: left;
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--line-soft);
}

.empty { text-align: center; padding: 56px 20px; }
.empty__mark { color: var(--line); display: flex; justify-content: center; margin-bottom: 18px; }
.empty h2 { margin-bottom: 8px; }
.empty p { max-width: 34ch; margin: 0 auto; font-size: 14px; }

/* RU: Строка состояния сети и загрузки. Показывается только когда есть что сказать:
       постоянный индикатор «всё хорошо» пользователь перестаёт замечать за день.
   EN: A network and upload status line. Shown only when there is something to say: a permanent
       "all good" indicator stops being noticed within a day. */
.status-line {
  padding: 9px 12px;
  margin-bottom: 10px;
  border-radius: var(--r-sm);
  font-size: 13px;
  background: var(--surface-2);
  color: var(--text-2);
}
.status-line--error { background: color-mix(in srgb, var(--rec) 14%, transparent); color: var(--rec); }
.status-line--work { background: var(--brand-050); color: var(--brand-600); }

.card-note {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 13px 14px;
  margin-bottom: 8px;
  cursor: pointer;
  /* RU: Гасим синюю подсветку тапа в мобильных браузерах: на карточке она выглядит
         как ошибка отрисовки, а собственное :active-состояние уже есть.
     EN: Suppress the blue tap highlight in mobile browsers: on a card it looks like a
         rendering glitch, and an explicit :active state already exists. */
  -webkit-tap-highlight-color: transparent;
}
.card-note:active { transform: scale(0.995); background: var(--surface-2); }

.player-bar {
  position: fixed;
  left: 10px; right: 10px;
  bottom: calc(env(safe-area-inset-bottom) + 12px + var(--keyboard-inset));
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  z-index: 20;
}
.seek {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: 2px;
  background: var(--surface-3);
  outline: none;
}
.seek::-webkit-slider-thumb {
  -webkit-appearance: none;
  /* RU: 18 px — минимум, за который реально попасть пальцем. Стандартный ползунок
         в 8 px на телефоне промахивается чаще, чем попадает.
     EN: 18 px is the minimum a finger can actually hit. The default 8 px thumb on a phone is
         missed more often than hit. */
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--brand-600);
  border: 0;
}
.seek::-moz-range-thumb {
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--brand-600);
  border: 0;
}

/* RU: На широком экране приложение не растягивается на всю ширину монитора: колонка
       текста шире 68 символов читается заметно хуже.
       Условие по высоте обязательно: лежащий телефон шире 720 px, но ниже 400 —
       настольная раскладка в такой полосе занимает четверть экрана и выглядит сломанной.
   EN: On a wide screen the app does not stretch across the monitor: a text column wider than
       68 characters reads noticeably worse.
       The height condition is mandatory: a phone in landscape is wider than 720 px but under
       400 tall, and the desktop layout in that strip takes a quarter of the screen and looks
       broken. */
@media (min-width: 720px) and (min-height: 600px) {
  .screen { max-width: 560px; margin: 0 auto; border-left: 1px solid var(--line); border-right: 1px solid var(--line); }
  .tabbar, .player-bar { max-width: 560px; left: 50%; transform: translateX(-50%); right: auto; width: 100%; }
  .player-bar { width: calc(100% - 20px); }
}

/* RU: Строка расшифровки. Таймкод фиксированной ширины слева, текст справа: без
       фиксированной колонки строки «пляшут» по горизонтали и читать их тяжело.
   EN: A transcript row. A fixed-width timecode on the left, text on the right: without a fixed
       column the lines jitter horizontally and become hard to read. */
.seg-row {
  display: grid;
  grid-template-columns: 46px 1fr;
  gap: 10px;
  padding: 8px 6px;
  border-radius: var(--r-sm);
  font-size: 15.5px;
  line-height: 1.6;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.seg-row .tc { padding-top: 4px; }
.seg-row:active { background: var(--surface-2); }

/* RU: Текущая реплика при воспроизведении. Полоса слева, а не заливка всей строки:
       заливка на длинной стенограмме превращает экран в мигающее полотно.
   EN: The currently playing span. A left rule rather than a full-row fill: on a long transcript a
       fill turns the screen into a flashing sheet. */
.seg-row--active {
  background: var(--brand-050);
  box-shadow: inset 3px 0 0 var(--brand-600);
}

/* RU: Подпись говорящего в реплике. Цвет и точка — те же, что в чипах над расшифровкой:
       один визуальный ключ на человека, иначе взгляду приходится сопоставлять заново
       в каждой строке.
   EN: The speaker label inside a span. Colour and dot match the chips above the transcript: one
       visual key per person, otherwise the eye has to re-match on every line. */
.seg-speaker {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12.5px;
  font-weight: 600;
  margin-right: 8px;
  vertical-align: baseline;
}

/* RU: Блок выбора числа говорящих на экране записи.
   EN: The speaker-count selector block on the recording screen. */
.speakers-hint {
  width: 100%;
  margin-top: 18px;
  text-align: center;
}

/* RU: Чип голоса — кнопка переименования. Пунктирная обводка показывает, что на него
       можно нажать: без подсказки главная механика продукта осталась бы ненайденной.
   EN: A voice chip is a rename button. The dashed outline signals it is tappable: without that hint
       the product's key mechanic would go undiscovered. */
.speaker-chip {
  border: 1px dashed var(--line);
  cursor: pointer;
}
.speaker-chip:active { background: var(--surface-3); }

/* ==========================================================================
   RU: Слои текста: переключатель, абзацы «Читаемо», блоки «Структуры».
   EN: Text layers: the switcher, "Readable" paragraphs, "Structure" blocks.
   ========================================================================== */

/* RU: Переключатель слоёв. Прижат к содержимому, а не к верху экрана: он относится к
       расшифровке, а не к заметке целиком, и уехав в шапку читался бы как навигация.
   EN: The layer switcher. Attached to the content rather than to the top of the screen: it belongs to
       the transcript, not to the note as a whole, and moved into the header it would read as
       navigation. */
.layer-tabs {
  display: flex;
  gap: 4px;
  padding: 3px;
  margin-bottom: 12px;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.layer-tab {
  flex: 1;
  padding: 7px 10px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  background: transparent;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
  /* RU: Отклик на нажатие обязан быть мгновенным на вид: слои переключаются локально,
         и любая задержка читалась бы как «не нажалось».
     EN: The tap response must look instant: layers switch locally, and any delay would read as "the
         tap did not register". */
  transition: background .12s, color .12s;
}

.layer-tab--on {
  color: var(--ink);
  background: var(--paper);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
}

/* RU: Абзац обработанного слоя. Отступ снизу больше, чем у дословных строк: там единица —
       реплика в секунду длиной, здесь — законченная мысль, и глазу нужен воздух.
   EN: A paragraph of a processed layer. More bottom spacing than verbatim rows: there the unit is a
       one-second span, here a complete thought, and the eye needs air. */
.para-row {
  padding: 10px 12px;
  margin-bottom: 8px;
  border-radius: 10px;
  cursor: pointer;
}

.para-row:hover { background: var(--paper-2); }

.para-row.seg-row--active { background: var(--brand-50, rgba(91, 75, 232, .08)); }

.para-text {
  margin: 4px 0 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink);
}

/* RU: Заголовок раздела структуры. Флажок повторяет метку пометки на экране записи —
       так видно, что заголовок пришёл от человека, а не придуман программой.
   EN: A structure section heading. The flag repeats the memo marker from the recording screen — making
       it visible that the heading came from the person rather than being invented by the program. */
.sec-title {
  margin: 18px 0 8px;
  font-size: 13px;
  font-weight: 650;
  letter-spacing: -.01em;
  color: var(--amber);
}

/* RU: Метка вида блока. Рамкой, а не заливкой: заливка спорила бы с цветами голосов,
       а они несут более важный смысл — кто говорил.
   EN: The block-kind badge. Outlined rather than filled: a fill would compete with the speaker colours,
       and those carry the more important meaning — who was speaking. */
.block-mark {
  display: inline-block;
  padding: 1px 7px;
  margin-bottom: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .01em;
  border: 1px solid;
  border-radius: 20px;
}

/* RU: Подсветка найденного. Не жёлтая заливка по умолчанию браузера: на тёплой бумаге
       она выглядит грязным пятном. Мягкий фон брендового цвета читается как «вот оно»,
       не перебивая сам текст.
   EN: Highlight for matches. Not the browser's default yellow fill: on warm paper it looks like a
       dirty smear. A soft brand-tinted background reads as "here it is" without overpowering the text
       itself. */
mark {
  padding: 0 2px;
  color: inherit;
  background: rgba(91, 75, 232, .16);
  border-radius: 3px;
}

/* RU: Кнопка голосового поиска во время слушания. Пульсация — единственный честный
       способ показать, что микрофон открыт: статичная кнопка не отличается от нажатой
       и не сработавшей.
   EN: The voice-search button while listening. A pulse is the only honest way to show the microphone
       is open: a static button is indistinguishable from one that was pressed and did nothing. */
.btn--listening {
  color: var(--rec);
  border-color: var(--rec);
  animation: listening 1.1s ease-in-out infinite;
}

@keyframes listening {
  0%, 100% { opacity: 1; }
  50%      { opacity: .45; }
}

/* RU: Уважаем системную настройку «меньше движения»: для части людей пульсация вызывает
       физический дискомфорт, а сообщение о слушании есть и в строке состояния.
   EN: Respect the system "reduce motion" setting: for some people a pulse causes physical discomfort,
       and the listening state is also stated in the status line. */
@media (prefers-reduced-motion: reduce) {
  .btn--listening { animation: none; }
}

/* RU: Карточка вопроса о неуверенном узнавании. Янтарная рамка, а не красная: это не
       ошибка и не тревога, а честное «не знаю» — красный здесь напугал бы там, где
       система просто добросовестно сомневается.
   EN: The card asking about an uncertain match. An amber border rather than a red one: this is neither
       an error nor an alarm but an honest "I don't know" — red here would frighten where the system is
       merely being conscientious about its doubt. */
.ask-card {
  padding: 12px 14px;
  margin: 16px 0;
  background: var(--paper-2);
  border: 1px solid var(--amber);
  border-radius: 12px;
}

/* RU: Метка на заметке. Рамкой цвета метки, без заливки: заливка спорила бы с цветами
       голосов, а те несут более важный смысл — кто говорил. Метка отвечает на «про что»,
       и это вопрос второго порядка.
   EN: A tag on a note. Outlined in the tag's colour, unfilled: a fill would compete with the speaker
       colours, and those carry the more important meaning — who spoke. A tag answers "what about", which
       is a second-order question. */
.tag-chip {
  padding: 3px 10px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  background: transparent;
  border: 1px solid;
  border-radius: 20px;
  cursor: pointer;
}

.tag-chip:active { opacity: .6; }

/* RU: Выпадающий список внутри формы правила. Наследует вид поля ввода намеренно: это
       часть одной формы, и разный вид её элементов читается как разные по важности поля.
   EN: The select inside the rule form. It inherits the input's look on purpose: it is part of one form,
       and differing looks across its elements read as fields of differing importance. */
select.search {
  height: 40px;
  padding: 0 10px;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}

/* RU: Метка в карточке ленты — мельче, чем в заметке. В ленте она отвечает на «про что
       это», глядя мельком; в заметке — участвует в разговоре про «почему это здесь», и
       там ей нужен полный размер.
   EN: A tag on a feed card — smaller than inside a note. In the feed it answers "what is this about" at
       a glance; inside a note it takes part in the "why is this here" conversation and needs full size
       there. */
.tag-chip--sm {
  padding: 1px 8px;
  font-size: 11.5px;
}
