{
  "common": {
    "loading": "Загрузка...",
    "error": "Что-то пошло не так",
    "retry": "Повторить",
    "save": "Сохранить",
    "saving": "Сохранение…",
    "cancel": "Отмена",
    "close": "Закрыть",
    "confirm": "Подтвердить",
    "delete": "Удалить",
    "edit": "Редактировать",
    "create": "Создать",
    "actionError": "Не удалось выполнить действие. Попробуйте ещё раз."
  },
  "themeSwitcher": {
    "switchToDark": "Тёмная тема",
    "switchToLight": "Светлая тема"
  },
  "languageSwitcher": {
    "ariaLabel": "Выбор языка",
    "languages": {
      "ru": "Русский",
      "en": "Английский"
    }
  },
  "auth": {
    "login": {
      "title": "Вход в admin",
      "subtitle": "Авторизуйтесь, чтобы управлять приглашениями, бронями и занятыми интервалами.",
      "fields": {
        "login": {
          "label": "Логин",
          "placeholder": "admin"
        },
        "password": {
          "label": "Пароль",
          "placeholder": "Пароль"
        }
      },
      "actions": {
        "signIn": "Войти",
        "signingIn": "Вход..."
      },
      "validation": {
        "loginRequired": "Укажите логин.",
        "passwordRequired": "Укажите пароль."
      },
      "switch": {
        "prompt": "Нужен отдельный admin-аккаунт?",
        "action": "Зарегистрироваться"
      },
      "errors": {
        "invalidCredentials": "Не удалось войти. Проверьте логин и пароль."
      }
    },
    "register": {
      "title": "Регистрация в admin",
      "subtitle": "Создайте отдельный аккаунт, чтобы работать со своими приглашениями и кредитами независимо от других пользователей.",
      "actions": {
        "create": "Создать аккаунт",
        "creating": "Создаю аккаунт..."
      },
      "validation": {
        "loginRequired": "Укажите логин.",
        "loginMinLength": "Логин должен содержать минимум 3 символа.",
        "passwordRequired": "Укажите пароль.",
        "passwordMinLength": "Пароль должен содержать минимум 8 символов."
      },
      "switch": {
        "prompt": "Уже есть аккаунт?",
        "action": "Войти"
      },
      "errors": {
        "loginTaken": "Этот логин уже занят.",
        "generic": "Не удалось создать аккаунт. Попробуйте ещё раз."
      }
    }
  },
  "adminShell": {
    "navLabel": "Навигация",
    "nav": {
      "invitations": "Приглашения",
      "users": "Пользователи",
      "invitees": "Профили",
      "calendar": "Календарь",
      "busySlots": "Занятые слоты",
      "settings": "Настройки"
    },
    "sidebar": {
      "collapse": "Свернуть меню",
      "expand": "Развернуть меню",
      "open": "Открыть меню",
      "close": "Закрыть меню"
    },
    "credits": {
      "ariaLabel": "Баланс кредитов: {{ count }}",
      "title": "Кредиты",
      "rule": "Первое опубликованное приглашение списывает 1 кредит.",
      "count": "Осталось: {{ count }}"
    },
    "logout": "Выйти",
    "impersonation": {
      "title": "Активна имперсонация",
      "description": "Сейчас вы в контексте {{ login }}. Исходная admin-сессия: {{ adminLogin }}.",
      "stop": "Вернуться в admin"
    }
  },
  "forbidden": {
    "kicker": "403",
    "title": "Доступ запрещён",
    "message": "Эта страница доступна только системному администратору.",
    "back": "К приглашениям"
  },
  "settings": {
    "kicker": "Аккаунт",
    "title": "Настройки пользователя",
    "subtitle": "Стабильный каркас для будущих персональных настроек, платёжного контекста и чувствительных действий с аккаунтом.",
    "sections": {
      "password": {
        "title": "Пароль",
        "description": "Смени пароль текущего аккаунта без обращения к системному администратору.",
        "login": "Логин: {{ login }}",
        "fields": {
          "currentPassword": {
            "label": "Текущий пароль",
            "placeholder": "Введите текущий пароль"
          },
          "newPassword": {
            "label": "Новый пароль",
            "placeholder": "Введите новый пароль",
            "hint": "Минимум 8 символов. После сохранения старая комбинация перестанет работать."
          },
          "confirmNewPassword": {
            "label": "Подтверждение нового пароля",
            "placeholder": "Повторите новый пароль"
          }
        },
        "validation": {
          "currentPasswordRequired": "Введите текущий пароль.",
          "newPasswordRequired": "Введите новый пароль.",
          "newPasswordMinLength": "Новый пароль должен содержать минимум 8 символов.",
          "confirmNewPasswordRequired": "Подтвердите новый пароль.",
          "confirmNewPasswordMismatch": "Подтверждение должно совпадать с новым паролем."
        },
        "actions": {
          "save": "Сменить пароль",
          "saving": "Сохраняем пароль…"
        },
        "notifications": {
          "saved": "Пароль обновлён. Текущая сессия сохранена, можно продолжать работу."
        },
        "errors": {
          "currentPasswordIncorrect": "Текущий пароль введён неверно.",
          "impersonationBlocked": "Во время имперсонации менять пароль нельзя.",
          "network": "Нет соединения с сервером.",
          "generic": "Не удалось обновить пароль. Попробуйте ещё раз."
        }
      },
      "profile": {
        "title": "Профиль",
        "description": "Здесь появится редактирование персональных данных: имя, логин и другие параметры аккаунта."
      },
      "plan": {
        "title": "Тариф и лимиты",
        "description": "Когда появится подписка, в этом блоке будут тариф, кредиты и ограничения текущего аккаунта."
      },
      "payments": {
        "title": "Платежи",
        "description": "Этот раздел зарезервирован под историю оплат, чеки и другие финансовые события аккаунта."
      },
      "deletion": {
        "title": "Удаление аккаунта",
        "description": "Безвозвратно удаляет твой аккаунт вместе со всеми приглашениями, бронями и слоями занятости.",
        "warning": "После удаления восстановить аккаунт, его приглашения и связанные данные будет невозможно.",
        "fields": {
          "currentPassword": {
            "label": "Текущий пароль",
            "placeholder": "Введите пароль для подтверждения"
          }
        },
        "validation": {
          "currentPasswordRequired": "Введите текущий пароль, чтобы подтвердить удаление."
        },
        "actions": {
          "delete": "Удалить аккаунт",
          "deleting": "Удаляем аккаунт…"
        },
        "confirm": {
          "title": "Удалить аккаунт?",
          "message": "Это действие необратимо. Все приглашения, брони, слоты занятости и кредитный баланс будут удалены вместе с аккаунтом.",
          "confirm": "Да, удалить",
          "errorFallback": "Не удалось удалить аккаунт."
        },
        "errors": {
          "currentPasswordIncorrect": "Текущий пароль введён неверно.",
          "impersonationBlocked": "Во время имперсонации удалять аккаунт нельзя.",
          "notFound": "Аккаунт уже удалён или больше не существует.",
          "network": "Нет соединения с сервером.",
          "generic": "Не удалось удалить аккаунт. Попробуйте ещё раз."
        }
      }
    }
  },
  "adminUsers": {
    "list": {
      "kicker": "Admin",
      "title": "Пользователи",
      "subtitle": "Список зарегистрированных аккаунтов с базовым контекстом для будущих действий и имперсонации.",
      "mobileScrollHint": "Таблица прокручивается горизонтально на узком экране.",
      "empty": {
        "title": "Пользователей пока нет",
        "message": "Когда кто-то зарегистрируется, аккаунты появятся в этом списке.",
        "ariaLabel": "Пустой список пользователей"
      },
      "table": {
        "titleLabel": "Зарегистрированные аккаунты",
        "ariaLabel": "Список пользователей",
        "identity": "Email / ID",
        "name": "Имя",
        "registeredAt": "Зарегистрирован",
        "creditBalance": "Кредиты",
        "status": "Статус",
        "actions": "Действия",
        "noName": "Не указано"
      },
      "status": {
        "admin": "Admin",
        "user": "User"
      },
      "actions": {
        "adjustBalance": "Изменить баланс",
        "adjustBalanceAria": "Изменить credit balance пользователя {{ email }}",
        "impersonate": "Имперсонироваться",
        "impersonateAria": "Имперсонироваться как пользователь {{ email }}"
      },
      "pagination": {
        "summary": "Показаны {{ from }}-{{ to }} из {{ total }}",
        "page": "Страница {{ page }} из {{ totalPages }}",
        "previous": "Назад",
        "next": "Дальше"
      }
    },
    "balanceDialog": {
      "title": "Изменить баланс кредитов",
      "description": "Новый баланс будет сохранён для аккаунта {{ email }}.",
      "current": "Сейчас",
      "result": "После сохранения",
      "fieldLabel": "Новый баланс",
      "helper": "Используй целое число 0 или больше.",
      "confirm": "Сохранить баланс",
      "errors": {
        "required": "Укажи новое значение баланса.",
        "min": "Баланс не может быть отрицательным.",
        "integer": "Баланс должен быть целым числом."
      }
    }
  },
  "invitations": {
    "status": {
      "draft": "Черновик",
      "published": "Опубликовано",
      "archived": "Архив"
    },
    "list": {
      "kicker": "Admin",
      "title": "Приглашения",
      "subtitle": "Список персональных ссылок, статусов публикации и быстрых действий.",
      "newInvitationTitle": "Новое приглашение",
      "mobileScrollHint": "Таблица прокручивается горизонтально на узком экране.",
      "actions": {
        "create": "Создать",
        "createInvitation": "Создать приглашение",
        "edit": "Редактировать",
        "delete": "Удалить"
      },
      "empty": {
        "title": "Пока нет приглашений",
        "message": "Создайте первое приглашение, затем настройте шаги и опубликуйте ссылку.",
        "ariaLabel": "Пустой список приглашений"
      },
      "table": {
        "ariaLabel": "Список приглашений",
        "title": "Название",
        "status": "Статус",
        "createdAt": "Создано",
        "actions": "Действия"
      },
      "sort": {
        "title": "Сортировать по названию",
        "status": "Сортировать по статусу",
        "createdAt": "Сортировать по дате создания"
      },
      "rowHints": {
        "draft": "Опубликуйте, чтобы открыть или скопировать ссылку.",
        "published": "Публичная ссылка доступна.",
        "archived": "Архивное приглашение недоступно по публичной ссылке."
      },
      "link": {
        "open": "Открыть приглашение",
        "copy": "Копировать ссылку",
        "copied": "Ссылка скопирована",
        "copyFailed": "Не удалось скопировать ссылку",
        "publishToOpen": "Опубликуйте приглашение, чтобы открыть его",
        "publishToCopy": "Опубликуйте приглашение, чтобы скопировать ссылку",
        "missingUuid": "Ссылка недоступна: не найден UUID приглашения",
        "pending": "Действие временно недоступно"
      },
      "aria": {
        "rowActions": "Действия для приглашения {{ title }}",
        "edit": "Редактировать приглашение {{ title }}",
        "open": "Открыть приглашение {{ title }}",
        "openDisabledDraft": "Нельзя открыть приглашение {{ title }}: оно не опубликовано",
        "openUnavailable": "Публичная ссылка приглашения {{ title }} недоступна",
        "copy": "Копировать публичную ссылку приглашения {{ title }}",
        "copyDisabledDraft": "Нельзя скопировать ссылку приглашения {{ title }}: оно не опубликовано",
        "copyUnavailable": "Публичная ссылка приглашения {{ title }} недоступна",
        "copied": "Ссылка приглашения {{ title }} скопирована",
        "copyFailed": "Не удалось скопировать публичную ссылку приглашения {{ title }}",
        "delete": "Удалить приглашение {{ title }}"
      },
      "deleteDialog": {
        "title": "Удалить приглашение?",
        "message": "Приглашение «{{ title }}» будет удалено. Это действие нельзя отменить."
      }
    },
    "editor": {
      "kicker": "Конструктор",
      "title": "Редактор приглашения",
      "actions": {
        "backToList": "Приглашения",
        "preview": "Предпросмотр",
        "open": "Открыть",
        "applyDraft": "Применить изменения",
        "discardDraft": "Отменить изменения",
        "createInvitee": "Создать профиль",
        "unlinkInvitee": "Отвязать",
        "manageInvitees": "Управлять профилями",
        "publish": "Опубликовать",
        "unpublish": "Снять с публикации",
        "archive": "В архив",
        "addStep": "Добавить шаг",
        "moveUp": "Выше",
        "moveDown": "Ниже",
        "chooseTemplate": "Шаблон",
        "deleteInvitation": "Удалить приглашение"
      },
      "draft": {
        "title": "Черновик и применение",
        "subtitle": "Изменения сохраняются как черновик и попадают в публичное приглашение только после применения.",
        "stateClean": "Черновик совпадает с опубликованным состоянием.",
        "stateQueued": "Локальные правки ждут сохранения в черновик.",
        "stateSaving": "Сохраняю черновик…",
        "stateDirty": "Есть неприменённые изменения в черновике."
      },
      "details": {
        "title": "Основные данные",
        "subtitle": "Название для admin и единый control получателя с опциональной привязкой к owner-bound профилю."
      },
      "fields": {
        "title": {
          "label": "Название",
          "placeholder": "Название приглашения"
        },
        "invitee": {
          "label": "Профиль получателя",
          "hint": "Выберите существующий профиль или создайте новый. Имя профиля сохранится в приглашении как snapshot для greeting и истории.",
          "unlinkedOption": "Без профиля",
          "linkedTitle": "Сейчас привязан профиль «{{ name }}»",
          "linkedHint": "История ниже считается по профилю, а имя уже сохранено в это приглашение как отдельный snapshot.",
          "emptyTitle": "Профиль пока не выбран",
          "emptyHint": "Можно оставить приглашение без профиля или выбрать/создать профиль позже.",
          "createLabel": "Новый профиль получателя",
          "createPlaceholder": "Например, Лена"
        },
        "palette": {
          "label": "Палитра"
        },
        "theme": {
          "label": "Тема"
        }
      },
      "appearance": {
        "title": "Вид публичного приглашения",
        "subtitle": "Палитра и тема применяются на invite-странице."
      },
      "publish": {
        "title": "Публикация",
        "subtitle": "Проверка обязательных условий до смены статуса.",
        "blockedTitle": "Нужно исправить перед публикацией",
        "readyTitle": "Можно публиковать"
      },
      "publishBlockers": {
        "noSteps": "Добавьте хотя бы один редактируемый шаг.",
        "noDatetime": "Добавьте шаг с выбором даты и времени.",
        "applyDraft": "Сначала примените черновик, затем публикуйте.",
        "ready": "Есть шаги и выбор даты/времени."
      },
      "steps": {
        "kicker": "Порядок",
        "title": "Шаги приглашения",
        "subtitle": "Подтверждение закреплено последним. Остальные шаги можно перетаскивать или перемещать кнопками.",
        "typeSelectorLabel": "Выберите тип шага",
        "dragHandle": "Перетащить шаг",
        "rowActions": "Действия с шагом",
        "empty": "Шагов пока нет. Добавьте первый редактируемый шаг, затем настройте финальное подтверждение.",
        "branchTargetPrefix": "Шаг {{ n }}: {{ summary }}",
        "confirmDivider": "Последний шаг",
        "lockedLast": "Закреплён последним"
      },
      "templates": {
        "title": "Добавление шага",
        "subtitle": "Возьми готовый шаг или собери с нуля — потом всё можно переписать.",
        "manualTitle": "С нуля",
        "manualSubtitle": "Пустой каркас без текстов — полностью ручная настройка.",
        "presetTitle": "Готовые шаги",
        "presetSubtitle": "Тексты уже написаны на языке приглашения. Вставь и поправь под себя.",
        "usePreset": "Вставить",
        "meta": {
          "options": "вариантов: {{count}}",
          "slot": "слоты по {{minutes}} мин",
          "fields": "полей: {{count}}"
        },
        "presets": {
          "questionVibe": {
            "title": "Настроение свидания",
            "description": "Вопрос-разведка: узнать, чего хочется, до брони столика."
          },
          "questionFood": {
            "title": "Что по еде",
            "description": "Выбор еды говорит о человеке больше, чем гороскоп. И сразу ясно, куда идти."
          },
          "datetimeEvening": {
            "title": "Будний вечер",
            "description": "Слоты по 90 минут — успеть всё и не опоздать на последнее метро."
          },
          "datetimeWeekend": {
            "title": "День без спешки",
            "description": "Двухчасовые слоты для выходных, когда будильник не приглашён."
          },
          "textContact": {
            "title": "Контакты",
            "description": "Имя и мессенджер, чтобы не передавать место встречи через общих знакомых."
          },
          "textDetails": {
            "title": "Важные детали",
            "description": "Аллергии и стоп-лист — лучше узнать до брони, а не в процессе."
          },
          "infoPlan": {
            "title": "Как это работает",
            "description": "Карточка, которая снимает вопрос «а что здесь происходит?»."
          },
          "infoAboutMe": {
            "title": "Пара фактов обо мне",
            "description": "Короткое интро, чтобы вопросы дальше не выглядели допросом."
          }
        }
      },
      "link": {
        "publishToOpen": "Опубликуйте приглашение, чтобы открыть его"
      },
      "aria": {
        "moveUp": "Переместить шаг выше",
        "moveDown": "Переместить шаг ниже",
        "editStep": "Редактировать шаг",
        "closeEditor": "Закрыть редактор шага",
        "deleteStep": "Удалить шаг"
      },
      "deleteStepDialog": {
        "title": "Удалить шаг?",
        "message": "Шаг исчезнет из приглашения. Это действие нельзя отменить."
      },
      "deleteInvitationDialog": {
        "title": "Удалить приглашение?",
        "message": "Приглашение «{{ title }}» будет удалено вместе со всеми шагами. Это действие нельзя отменить."
      },
      "dangerZone": {
        "title": "Удаление",
        "subtitle": "Необратимые действия. Восстановить приглашение после удаления невозможно."
      },
      "leaveDraftPrompt": "Есть локальные изменения, которые ещё не успели сохраниться в черновик. Уйти со страницы?",
      "notifications": {
        "saved": "Сохранено",
        "applied": "Изменения применены",
        "discarded": "Черновик сброшен",
        "inviteeCreated": "Профиль получателя создан и привязан"
      },
      "inviteeHistory": {
        "title": "История по получателю",
        "subtitle": "Короткий журнал прошлых приглашений и исходов по этому человеку.",
        "count": "{{ name }} · {{ count }} прошлых приглашений",
        "invitationDate": "дата приглашения",
        "meetingDate": "дата встречи",
        "bookingLabel": "Бронь:",
        "noBooking": "Брони не было",
        "unlinkedTitle": "Получатель не выбран",
        "unlinkedText": "История появится после привязки к новому или существующему получателю.",
        "emptyTitle": "Истории пока нет",
        "emptyText": "У этого получателя ещё не было прошлых приглашений."
      },
      "inviteeProfiles": {
        "kicker": "Профили",
        "title": "Профили получателей",
        "subtitle": "Owner-scoped список профилей с историей связанных приглашений. Переименование меняет будущий выбор профиля, но не переписывает старые snapshots.",
        "actions": {
          "backToList": "К списку профилей",
          "backToInvitation": "Вернуться в приглашение",
          "save": "Сохранить имя",
          "delete": "Удалить профиль",
          "createProfile": "Новый профиль"
        },
        "notifications": {
          "saved": "Имя профиля сохранено",
          "deleted": "Профиль «{{ name }}» удалён",
          "created": "Профиль «{{ name }}» создан"
        },
        "empty": {
          "title": "Профилей пока нет",
          "text": "Профили появляются после создания или привязки получателя в редакторе приглашения."
        },
        "list": {
          "title": "Все профили",
          "subtitle": "Откройте профиль, чтобы посмотреть историю и изменить имя.",
          "count": "{{ count }} профиля",
          "usageCount": "{{ count }} приглашений",
          "lastActivity": "Последняя активность: {{ date }}",
          "noActivity": "Пока без связанных приглашений"
        },
        "detail": {
          "emptyTitle": "Выберите профиль",
          "emptyText": "Список слева показывает все owner-bound профили текущего администратора.",
          "meta": "Создан {{ createdAt }}. Обновлён {{ updatedAt }}.",
          "usageCount": "{{ count }} связанных приглашений",
          "lastActivity": "Последняя активность: {{ date }}",
          "noActivity": "Пока без активности"
        },
        "form": {
          "nameLabel": "Имя профиля",
          "namePlaceholder": "Например, Лена",
          "nameHint": "Новые приглашения увидят обновлённое имя, но старые snapshots в уже созданных приглашениях сохранятся."
        },
        "dangerZone": {
          "title": "Удаление профиля",
          "subtitle": "После удаления связанные приглашения останутся, но `inviteeId` и `draftInviteeId` будут отвязаны. Snapshot имени внутри приглашений сохранится."
        },
        "deleteDialog": {
          "title": "Удалить профиль «{{ name }}»?",
          "message": "Профиль связан с {{ count }} приглашениями. После удаления эти приглашения останутся доступны, но потеряют связь с профилем и будут редактироваться как отвязанные. Сохранённые snapshot-имена в `recipientName` и `draftRecipientName` не изменятся.",
          "confirm": "Удалить профиль",
          "error": "Не удалось удалить профиль. Проверьте, что он существует и принадлежит текущему admin."
        },
        "history": {
          "title": "История профиля",
          "subtitle": "Связанные приглашения и их snapshot display-name.",
          "emptyTitle": "История ещё не накопилась",
          "emptyText": "Когда этот профиль будет связан с приглашениями, они появятся здесь.",
          "meetingDate": "Встреча: {{ date }}",
          "invitationDate": "Приглашение создано: {{ date }}",
          "snapshotName": "Snapshot имени в приглашении: {{ name }}",
          "noBooking": "Без брони",
          "openInvitation": "Открыть приглашение"
        },
        "create": {
          "title": "Создать профиль",
          "nameLabel": "Имя профиля",
          "namePlaceholder": "Например, Лена",
          "submit": "Создать",
          "cancel": "Отмена"
        }
      },
      "invitationTemplates": {
        "dialogTitle": "С чего начнём?",
        "dialogSubtitle": "Шаблон — это готовый сценарий: приветствие, шаги и финальный экран. Всё можно переписать после.",
        "skipLabel": "Начать с чистого листа",
        "selectLabel": "Взять этот",
        "replaceTitle": "Заменить содержимое?",
        "replaceMessage": "Шаблон заменит текущие шаги, приветственный и финальный экраны.",
        "replaceConfirm": "Заменить",
        "greetingLabel": "Приветствие",
        "successLabel": "Финал",
        "firstDate": {
          "title": "Первое свидание",
          "description": "Разведка настроения, удобный вечер и контакты. Ничего лишнего."
        },
        "coffee": {
          "title": "Кофе и посмотрим",
          "description": "Минимум обязательств: пара фактов о тебе, свободный вечер и способ связи."
        },
        "weekend": {
          "title": "Вылазка на выходные",
          "description": "План посерьёзнее: еда, целый день и важные детали вроде аллергий."
        },
        "partner": {
          "title": "Для тех, кто уже вместе",
          "description": "Отношения — не повод пропускать свидания. Всё по правилам: вопрос, календарь, интрига."
        }
      },
      "greetingPage": {
        "title": "Приветственный экран",
        "kicker": "Intro state",
        "subtitle": "Заголовок, текст и медиа для технического intro-state в начале invite-flow. Если ничего не настраивать, invite использует безопасные системные значения.",
        "stepLabel": "Greeting screen",
        "summaryDefault": "Только системное приветствие",
        "titleLabel": "Заголовок",
        "titlePlaceholder": "Например: Это официальное начало моего хитрого плана",
        "textLabel": "Дополнительный текст",
        "optional": "(необязательно)",
        "textPlaceholder": "Например: Я тут всё красиво подготовил, открывай дальше…",
        "mediaLabel": "Медиа",
        "mediaNone": "Без медиа",
        "mediaEmoji": "Эмодзи",
        "mediaImage": "Картинка / GIF",
        "mediaAlt": "Превью медиа приветственного экрана",
        "chooseMediaFile": "Выбрать GIF или изображение",
        "or": "или",
        "urlPlaceholder": "https://example.com/intro.gif",
        "urlAriaLabel": "URL внешнего GIF или изображения",
        "removeMediaAriaLabel": "Удалить медиа",
        "emojiPlaceholder": "Например: 💌",
        "emojiAriaLabel": "Эмодзи для приветственного экрана",
        "uploading": "Загружаю…",
        "errors": {
          "emojiRequired": "Введите эмодзи или переключите режим медиа",
          "upload": "Не удалось загрузить файл. Попробуйте ещё раз.",
          "invalidFile": "Пожалуйста, выберите файл изображения или GIF.",
          "invalidUrl": "Введите корректный URL изображения/GIF или используйте локальный `/uploads/...`"
        }
      },
      "successPage": {
        "title": "Страница успеха",
        "kicker": "Финальный экран",
        "subtitle": "Заголовок, текст и медиа на экране после подтверждения свидания. Если не заполнено — будут применены значения по умолчанию.",
        "stepLabel": "Success page",
        "summaryDefault": "Системные значения по умолчанию",
        "titleLabel": "Заголовок",
        "titlePlaceholder": "Например: Отлично, договорились!",
        "textLabel": "Текст",
        "optional": "(необязательно)",
        "textPlaceholder": "Например: Жду не дождусь нашей встречи…",
        "mediaLabel": "Медиа",
        "mediaNone": "Без медиа",
        "mediaEmoji": "Эмодзи",
        "mediaImage": "Картинка / GIF",
        "mediaAlt": "Превью медиа страницы успеха",
        "chooseMediaFile": "Выбрать GIF или изображение",
        "or": "или",
        "urlPlaceholder": "https://example.com/celebrate.gif",
        "urlAriaLabel": "URL внешнего GIF или изображения",
        "removeMediaAriaLabel": "Удалить медиа",
        "emojiPlaceholder": "Например: 🎉",
        "emojiAriaLabel": "Эмодзи для страницы успеха",
        "uploading": "Загружаю…",
        "errors": {
          "emojiRequired": "Введите эмодзи или переключите режим медиа",
          "upload": "Не удалось загрузить файл. Попробуйте ещё раз.",
          "invalidFile": "Пожалуйста, выберите файл изображения или GIF.",
          "invalidUrl": "Введите корректный URL изображения/GIF или используйте локальный `/uploads/...`"
        }
      }
    },
    "preview": {
      "description": "Проверка порядка, типов шагов и публичной ссылки перед публикацией.",
      "closeAria": "Закрыть предпросмотр",
      "empty": "Шагов пока нет. Добавьте шаги в редакторе.",
      "stepsLabel": "Шаги предпросмотра приглашения",
      "multipleChoice": "Множественный выбор",
      "slotDuration": "Слот: {{ minutes }} мин.",
      "required": "Обязательное поле",
      "photoAlt": "Фото шага",
      "publishToOpen": "Опубликуйте приглашение, чтобы открыть его",
      "openInvitation": "Открыть приглашение",
      "stepTypes": {
        "question": "Вопрос",
        "datetime": "Дата и время",
        "text": "Текст",
        "info": "Инфо",
        "confirm": "Подтверждение"
      }
    },
    "stepEditors": {
      "emojiPicker": {
        "title": "Выбор эмодзи",
        "choose": "Выбрать эмодзи",
        "replace": "Сменить эмодзи",
        "clear": "Очистить эмодзи"
      },
      "question": {
        "questionLabel": "Текст вопроса",
        "questionPlaceholder": "Например: Кого ты выбираешь?",
        "optionsLabel": "Варианты ответа",
        "optionPlaceholder": "Вариант {{ n }}",
        "mediaLabel": "Медиа",
        "mediaOptional": "(необязательно)",
        "mediaNone": "Без медиа",
        "mediaEmoji": "Эмодзи",
        "mediaImage": "Картинка / GIF",
        "branchLabel": "Переход после ответа",
        "branchOptional": "(необязательно)",
        "branchDefault": "По умолчанию: следующий шаг",
        "branchCustomStep": "Выбрать конкретный шаг",
        "branchSuccess": "Сразу к финалу приглашения",
        "branchStepPlaceholder": "Выберите шаг назначения",
        "emojiPlaceholder": "Например: 💘",
        "emojiAriaLabel": "Эмодзи для варианта {{ n }}",
        "imageUrlPlaceholder": "https://example.com/reaction.gif или /uploads/...",
        "imageUrlAriaLabel": "URL изображения или GIF",
        "uploadImage": "Выбрать GIF или изображение",
        "previewAlt": "Превью медиа для варианта {{ n }}",
        "removeMediaAriaLabel": "Удалить медиа",
        "uploading": "Загружаю изображение…",
        "impossibleHint": "Кнопка-«призрак»: убегает от курсора и тапа — нажать невозможно",
        "impossibleAriaLabel": "Сделать кнопку-призрак (убегает от курсора)",
        "removeOptionAriaLabel": "Удалить вариант",
        "addOption": "Добавить вариант",
        "minOptionsError": "Нужно минимум 2 варианта",
        "multipleLabel": "Разрешить выбор нескольких вариантов",
        "subtitleLabel": "Подзаголовок",
        "subtitleOptional": "(необязательно)",
        "subtitlePlaceholder": "Например: Только честно — мы проверим 😏",
        "errors": {
          "emojiRequired": "Введите эмодзи или отключите медиа для этого варианта",
          "imageRequired": "Добавьте изображение/GIF через загрузку или URL",
          "branchStepRequired": "Выберите шаг назначения или верните переход по умолчанию",
          "invalidFile": "Пожалуйста, выберите файл изображения или GIF.",
          "invalidUrl": "Введите корректный URL изображения или используйте локальный `/uploads/...`",
          "upload": "Не удалось загрузить изображение. Попробуйте ещё раз."
        }
      },
      "text": {
        "titleLabel": "Заголовок шага",
        "titlePlaceholder": "Например: Расскажи о себе",
        "fieldsLabel": "Поля формы",
        "fieldNameLabel": "Название поля",
        "fieldNamePlaceholder": "Например: Имя",
        "fieldNameRequired": "Название обязательно",
        "fieldKeyLabel": "Ключ",
        "fieldKeyHint": "Ключ — внутренний идентификатор поля. Под ним ответ сохраняется в базе данных, поэтому должен быть уникальным внутри шага. Заполняется автоматически из названия поля.",
        "fieldKeyRequired": "Ключ обязателен",
        "fieldKeyPattern": "Только a–z, 0–9 и «_»",
        "fieldKeyDuplicate": "Ключ уже используется",
        "removeFieldAriaLabel": "Удалить поле",
        "fieldRequiredLabel": "Обязательное поле",
        "addField": "Добавить поле"
      },
      "datetime": {
        "titleLabel": "Заголовок шага",
        "titlePlaceholder": "Например: Выбери дату свидания",
        "slotLabel": "Длительность слота (минуты)",
        "slotHint": "От 15 до 1440 минут. Используется при расчёте доступных слотов."
      },
      "info": {
        "titleLabel": "Заголовок",
        "titlePlaceholder": "Например: Немного обо мне",
        "textLabel": "Текст",
        "textPlaceholder": "Напиши что-нибудь о себе или о предстоящем свидании…",
        "mediaLabel": "Медиа",
        "mediaOptional": "(необязательно)",
        "mediaNone": "Без медиа",
        "mediaEmoji": "Эмодзи",
        "mediaImage": "Картинка / GIF",
        "mediaAlt": "Превью GIF или изображения",
        "removeMediaAriaLabel": "Удалить GIF или изображение",
        "emojiPlaceholder": "Например: 🌹",
        "emojiAriaLabel": "Эмодзи для info-шага",
        "chooseMediaFile": "Выбрать GIF или изображение",
        "or": "или",
        "urlPlaceholder": "https://example.com/hello.gif",
        "urlAriaLabel": "URL внешнего GIF или изображения",
        "insertUrl": "Вставить",
        "uploading": "Загружаю GIF или изображение…",
        "errors": {
          "emojiRequired": "Введите эмодзи или переключите media в другой режим",
          "upload": "Не удалось загрузить GIF или изображение. Попробуйте ещё раз.",
          "invalidFile": "Пожалуйста, выберите файл изображения или GIF.",
          "invalidUrl": "Введите корректный URL изображения/GIF или используйте локальный `/uploads/...`"
        }
      },
      "confirm": {
        "titleLabel": "Заголовок",
        "titlePlaceholder": "Например: Всё готово!",
        "textLabel": "Текст",
        "textOptional": "(необязательно)",
        "textPlaceholder": "Например: Я уже жду нашей встречи. Увидимся совсем скоро…",
        "mediaLabel": "Медиа",
        "mediaOptional": "(необязательно)",
        "mediaAlt": "Превью GIF или изображения",
        "chooseMediaFile": "Выбрать GIF или изображение",
        "or": "или",
        "urlPlaceholder": "https://example.com/celebrate.gif",
        "urlAriaLabel": "URL внешнего GIF или изображения",
        "removeMediaAriaLabel": "Удалить медиа",
        "uploading": "Загружаю GIF или изображение…",
        "successHint": "Этот шаг отображается на экране подтверждения перед бронированием свидания. Страница успеха настраивается отдельно в разделе «Страница успеха».",
        "errors": {
          "upload": "Не удалось загрузить GIF или изображение. Попробуйте ещё раз.",
          "invalidFile": "Пожалуйста, выберите файл изображения или GIF.",
          "invalidUrl": "Введите корректный URL изображения/GIF или используйте локальный `/uploads/...`",
          "emojiRequired": "Введите эмодзи или выберите другой тип медиа"
        },
        "mediaNone": "Без медиа",
        "mediaEmoji": "Эмодзи",
        "mediaImage": "Изображение / GIF",
        "emojiPlaceholder": "Например: 🎉",
        "emojiAriaLabel": "Эмодзи для шага подтверждения"
      }
    }
  },
  "bookings": {
    "status": {
      "pending": "Ожидает",
      "confirmed": "Подтверждено",
      "cancelled": "Отменено",
      "completed": "Завершено"
    },
    "calendar": {
      "kicker": "Брони",
      "title": "Календарь броней",
      "subtitle": "Месячный обзор, выбранный день и список заявок с быстрым редактированием.",
      "mobileScrollHint": "Календарь прокручивается горизонтально на узком экране.",
      "gridAriaLabel": "Месячный календарь броней",
      "dayAriaLabel": "{{ day }}, {{ countLabel }}",
      "tabs": {
        "ariaLabel": "Вид броней",
        "calendar": "Календарь",
        "list": "Список"
      },
      "controls": {
        "today": "Сегодня",
        "prevMonth": "Предыдущий месяц",
        "nextMonth": "Следующий месяц"
      },
      "weekdays": {
        "Пн": "Пн",
        "Вт": "Вт",
        "Ср": "Ср",
        "Чт": "Чт",
        "Пт": "Пт",
        "Сб": "Сб",
        "Вс": "Вс"
      },
      "months": {
        "january": "января",
        "february": "февраля",
        "march": "марта",
        "april": "апреля",
        "may": "мая",
        "june": "июня",
        "july": "июля",
        "august": "августа",
        "september": "сентября",
        "october": "октября",
        "november": "ноября",
        "december": "декабря"
      },
      "count": {
        "one": "{{ count }} бронь",
        "few": "{{ count }} брони",
        "many": "{{ count }} броней"
      },
      "detail": {
        "ariaLabel": "Детали выбранного дня",
        "empty": "На выбранный день броней нет.",
        "noName": "Без имени",
        "editAriaLabel": "Редактировать бронь: {{ name }}",
        "cancelAriaLabel": "Отменить встречу: {{ name }}"
      }
    },
    "list": {
      "mobileScrollHint": "Таблица прокручивается горизонтально на узком экране.",
      "empty": "Броней за выбранный период нет.",
      "noName": "Без имени",
      "noTitle": "Без названия",
      "filters": {
        "period": "Период",
        "apply": "Применить",
        "reset": "Сбросить"
      },
      "table": {
        "ariaLabel": "Список броней",
        "dateTime": "Дата и время",
        "name": "Имя",
        "invitation": "Приглашение",
        "status": "Статус",
        "actions": "Действия"
      },
      "actions": {
        "editAriaLabel": "Редактировать бронь: {{ name }}",
        "cancelAriaLabel": "Отменить встречу: {{ name }}",
        "showAnswers": "Показать ответы",
        "hideAnswers": "Скрыть ответы"
      },
      "answers": {
        "empty": "Ответов нет."
      }
    },
    "editDialog": {
      "title": "Редактирование ответов",
      "description": "Измените статус, имя и ответы брони без потери введённых данных.",
      "fields": {
        "status": "Статус",
        "name": "Имя"
      },
      "placeholders": {
        "name": "Не указано"
      },
      "errors": {
        "save": "Не удалось сохранить изменения. Попробуйте ещё раз."
      }
    },
    "statusSelector": {
      "changeAriaLabel": "Изменить статус брони. Текущий статус: {{ status }}.",
      "error": "Не удалось обновить статус. Попробуйте ещё раз."
    },
    "cancelDialog": {
      "title": "Отменить встречу{{ name }}?",
      "nameSuffix": " с {{ name }}",
      "message": "Статус брони изменится на «Отменено», а время снова станет доступным для записи.",
      "confirm": "Отменить встречу",
      "error": "Не удалось отменить встречу. Попробуйте ещё раз."
    },
    "busySlots": {
      "kicker": "Доступность",
      "title": "Занятые интервалы",
      "subtitle": "Промежутки, которые исключаются из выбора времени в приглашениях.",
      "mobileScrollHint": "Таблица прокручивается горизонтально на узком экране.",
      "form": {
        "title": "Добавить интервал",
        "titleEdit": "Редактировать интервал",
        "subtitle": "Укажите начало и конец одним непрерывным промежутком.",
        "subtitleEdit": "Измените начало, конец или причину занятого интервала.",
        "intervalLegend": "Период недоступности",
        "intervalHint": "Конец должен быть позже начала."
      },
      "fields": {
        "startsAt": "Начало",
        "endsAt": "Конец",
        "reason": "Причина",
        "reasonPlaceholder": "Например: личные дела",
        "reasonHint": "Необязательно. Видно только в admin."
      },
      "validation": {
        "required": "Обязательное поле.",
        "endBeforeStart": "Конец должен быть позже начала."
      },
      "actions": {
        "add": "Добавить интервал",
        "save": "Сохранить интервал",
        "saving": "Сохранение…",
        "cancel": "Отменить редактирование",
        "edit": "Редактировать",
        "editAriaLabel": "Редактировать занятый интервал",
        "delete": "Удалить",
        "deleteAriaLabel": "Удалить занятый интервал"
      },
      "list": {
        "title": "Существующие интервалы",
        "subtitle": "Сначала показаны ближайшие будущие и прошедшие блокировки по времени начала.",
        "count": "{{ count }} интервалов"
      },
      "empty": {
        "title": "Занятых интервалов нет",
        "message": "Добавьте интервал, если время не должно быть доступно для бронирования.",
        "ariaLabel": "Пустой список занятых интервалов"
      },
      "table": {
        "ariaLabel": "Список занятых интервалов",
        "startsAt": "Начало",
        "endsAt": "Конец",
        "reason": "Причина",
        "actions": "Действия",
        "noReason": "Не указана"
      },
      "deleteDialog": {
        "title": "Удалить занятый интервал?",
        "message": "Этот промежуток снова станет доступен для бронирования.",
        "confirm": "Удалить интервал",
        "error": "Не удалось удалить интервал. Попробуйте ещё раз."
      },
      "mergeDialog": {
        "title": "Объединить пересекающиеся интервалы?",
        "message": "Новый интервал пересекается или граничит с существующими: {{ conflicts }}. После подтверждения они будут объединены в один интервал: {{ nextInterval }}.",
        "confirm": "Объединить интервалы",
        "error": "Не удалось объединить интервалы. Попробуйте ещё раз."
      }
    }
  }
}
