diff --git a/public/core/auth-security-v1774.js b/public/core/auth-security-v1774.js
new file mode 100644
index 0000000..96c4fd8
--- /dev/null
+++ b/public/core/auth-security-v1774.js
@@ -0,0 +1,192 @@
+(()=>{
+ 'use strict';
+
+ const VERSION='17.7.3-auth-security-v1';
+ const PENDING_REGISTRATION_KEY='sunPendingRegistrationV23';
+ let busy=false;
+
+ const $=id=>document.getElementById(id);
+ const cloud=()=>window.SunCloudV2||null;
+ const client=()=>cloud()?.getClient?.()||null;
+ const esc=value=>window.SunSafe?.escapeHTML?window.SunSafe.escapeHTML(String(value??'')):String(value??'');
+
+ function redirectUrl(){
+ try{
+ const u=new URL(location.href);
+ u.hash='';
+ return u.toString();
+ }catch(_){return location.href.split('#')[0];}
+ }
+
+ function savePendingRegistration(email,companyName){
+ try{
+ localStorage.setItem(PENDING_REGISTRATION_KEY,JSON.stringify({
+ email:String(email||'').trim().toLowerCase(),
+ companyName:String(companyName||'').trim()||'Новая компания',
+ createdAt:new Date().toISOString()
+ }));
+ }catch(_){}
+ }
+
+ function clearPendingRegistration(){
+ try{localStorage.removeItem(PENDING_REGISTRATION_KEY)}catch(_){}
+ }
+
+ function setError(root,message){
+ const node=root?.querySelector?.('#sunGateErrorV3');
+ if(node)node.textContent=String(message||'');
+ }
+
+ function friendlySignupError(error){
+ const message=String(error?.message||error||'Не удалось создать аккаунт.');
+ if(/email address not authorized/i.test(message)){
+ return 'Не удалось отправить письмо подтверждения. Обратитесь к администратору Caterium.';
+ }
+ if(/rate limit|rate_limit|too many/i.test(message)){
+ return 'Слишком много попыток регистрации. Попробуйте немного позже.';
+ }
+ return message;
+ }
+
+ async function signOutUnsafeSession(c){
+ try{await c?.auth?.signOut?.()}catch(_){}
+ }
+
+ function showPublicConfirmation(gate,email){
+ if(!gate)return;
+ gate.innerHTML=`

Подтвердите email
Безопасная регистрация Caterium
Мы отправили письмо на ${esc(email)}. Откройте письмо и нажмите ссылку подтверждения. После подтверждения Caterium откроется автоматически.
`;
+ gate.querySelector('#sunAuthGoLoginV1774')?.addEventListener('click',()=>{gate.remove();document.body.classList.remove('sun-cloud-auth-required');setTimeout(()=>window.SunEnterprise?.ensureAuthGate?.(),30);location.reload();},{once:true});
+ }
+
+ function showInviteConfirmation(gate,email){
+ if(!gate)return;
+ gate.innerHTML=`
Подтвердите email
Приглашение сохранено
Письмо подтверждения отправлено на ${esc(email)}. Подтвердите адрес по ссылке в письме. После возврата в Caterium приглашение останется доступно.
`;
+ gate.querySelector('#sunInviteReloadV1774')?.addEventListener('click',()=>location.reload(),{once:true});
+ }
+
+ async function publicSignup(gate){
+ if(busy)return;
+ const c=client();
+ if(!c){setError(gate,'Облачный сервис не подключён.');return;}
+ const email=String($('sunGateEmailV3')?.value||'').trim().toLowerCase();
+ const password=String($('sunGatePasswordV3')?.value||'');
+ const password2=String($('sunGatePassword2V27')?.value||'');
+ const companyName=String($('sunGateCompanyV3')?.value||'').trim();
+ if(!companyName){setError(gate,'Введите название компании.');return;}
+ if(!email||password.length<6){setError(gate,'Введите email и пароль минимум из 6 символов.');return;}
+ if(password!==password2){setError(gate,'Пароли не совпадают.');return;}
+
+ busy=true;
+ const button=$('sunGateSubmitV3');if(button)button.disabled=true;
+ setError(gate,'Создаю безопасный аккаунт…');
+ savePendingRegistration(email,companyName);
+ try{
+ const existing=await c.auth.signInWithPassword({email,password});
+ if(!existing.error&&existing.data?.session){
+ location.reload();
+ return;
+ }
+ const result=await c.auth.signUp({
+ email,
+ password,
+ options:{
+ emailRedirectTo:redirectUrl(),
+ data:{company_name:companyName}
+ }
+ });
+ if(result.error)throw result.error;
+ if(result.data?.session){
+ await signOutUnsafeSession(c);
+ throw new Error('Защита email ещё не активирована на сервере. Регистрация остановлена, чтобы не создавать неподтверждённый аккаунт.');
+ }
+ showPublicConfirmation(gate,email);
+ }catch(error){
+ clearPendingRegistration();
+ setError(gate,friendlySignupError(error));
+ if(button)button.disabled=false;
+ }finally{busy=false;}
+ }
+
+ async function acceptInviteAfterLogin(token,gate){
+ const api=cloud();
+ const ws=await api?.acceptInvite?.(token);
+ if(!ws)throw new Error('Не удалось присоединиться к компании.');
+ try{const u=new URL(location.href);u.searchParams.delete('invite');history.replaceState(null,'',u.toString())}catch(_){}
+ location.reload();
+ }
+
+ async function inviteSignup(gate){
+ if(busy)return;
+ const c=client();
+ if(!c){setError(gate,'Облачный сервис не подключён.');return;}
+ const email=String($('sunInviteEmailV27')?.value||'').trim().toLowerCase();
+ const name=String($('sunInviteNameV27')?.value||'').trim();
+ const password=String($('sunInvitePasswordV27')?.value||'');
+ const password2=String($('sunInvitePassword2V27')?.value||'');
+ let token='';try{token=String(new URL(location.href).searchParams.get('invite')||'').trim()}catch(_){}
+ if(!token){setError(gate,'Ссылка приглашения повреждена.');return;}
+ if(!email||password.length<6){setError(gate,'Пароль должен содержать минимум 6 символов.');return;}
+ if(password!==password2){setError(gate,'Пароли не совпадают.');return;}
+
+ busy=true;
+ const button=$('sunInviteJoinV27');if(button)button.disabled=true;
+ setError(gate,'Проверяю аккаунт…');
+ try{
+ const existing=await c.auth.signInWithPassword({email,password});
+ if(!existing.error&&existing.data?.session){
+ await acceptInviteAfterLogin(token,gate);
+ return;
+ }
+ const result=await c.auth.signUp({
+ email,
+ password,
+ options:{
+ emailRedirectTo:redirectUrl(),
+ data:{name}
+ }
+ });
+ if(result.error)throw result.error;
+ if(result.data?.session){
+ await signOutUnsafeSession(c);
+ throw new Error('Защита email ещё не активирована на сервере. Приглашение остановлено, чтобы не создавать неподтверждённый аккаунт.');
+ }
+ showInviteConfirmation(gate,email);
+ }catch(error){
+ setError(gate,friendlySignupError(error));
+ if(button)button.disabled=false;
+ }finally{busy=false;}
+ }
+
+ function publicRegistrationMode(){
+ const fields=$('sunGateRegisterFieldsV27');
+ return Boolean(fields&&!fields.hidden);
+ }
+
+ document.addEventListener('click',event=>{
+ const target=event.target instanceof Element?event.target:null;
+ if(!target)return;
+ if(target.closest('#sunGateSubmitV3')&&publicRegistrationMode()){
+ event.preventDefault();event.stopImmediatePropagation();
+ publicSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));
+ return;
+ }
+ if(target.closest('#sunInviteJoinV27')){
+ event.preventDefault();event.stopImmediatePropagation();
+ inviteSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));
+ }
+ },true);
+
+ document.addEventListener('keydown',event=>{
+ if(event.key!=='Enter')return;
+ const target=event.target instanceof Element?event.target:null;
+ if(target?.id==='sunGatePassword2V27'&&publicRegistrationMode()){
+ event.preventDefault();event.stopImmediatePropagation();
+ publicSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));
+ }else if(target?.id==='sunInvitePassword2V27'){
+ event.preventDefault();event.stopImmediatePropagation();
+ inviteSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));
+ }
+ },true);
+
+ window.CateriumAuthSecurityV1774=Object.freeze({VERSION,redirectUrl});
+})();
\ No newline at end of file