droplyvictor89 commited on
Commit
1b1667b
·
verified ·
1 Parent(s): 0561fee

Upload 6 files

Browse files
Files changed (3) hide show
  1. app.js +60 -55
  2. index.html +112 -130
  3. style.css +362 -369
app.js CHANGED
@@ -40,14 +40,20 @@ window.addEventListener('firebase-ready',()=>{
40
  window.addEventListener('DOMContentLoaded',()=>{
41
  loadLocal();
42
  seedAdmin();
43
- // If no firebase yet, check local login
44
- setTimeout(()=>{
45
- if(!FIREBASE_OK){
46
- const uid=localStorage.getItem('loom_uid');
47
- if(uid && S.users[uid]){S.uid=uid;S.user=S.users[uid];showApp();}
48
- else showAuth();
49
- }
50
- },1500);
 
 
 
 
 
 
51
  });
52
 
53
  // ── LOCAL STORAGE ──
@@ -63,7 +69,7 @@ function loadLocal(){
63
  }
64
  function seedAdmin(){
65
  if(!S.users[ADMIN_UID]){
66
- S.users[ADMIN_UID]={id:ADMIN_UID,username:ADMIN_UID,name:'S',displayName:'S',email:ADMIN_EMAIL,password:ADMIN_PASS,bio:'Creator of Loom ✦',avatar:null,color:'#111',verified:true,isCreator:true,followers:[],following:[],followersCount:23834,followingCount:0,isPrivate:false,ts:Date.now()-86400000*300};
67
  S.posts.unshift({id:'sp1',uid:ADMIN_UID,text:'Welcome to Loom. A new era of communication. ✦',image:null,likes:[],comments:[],ts:Date.now()-3600000*5});
68
  S.posts.unshift({id:'sp2',uid:ADMIN_UID,text:'Minimalism is not a style. It\'s an attitude. 🖤',image:null,likes:[],comments:[],ts:Date.now()-3600000*2});
69
  saveLocal();
@@ -92,7 +98,7 @@ function setBtnLoading(id,on){
92
  async function handleLogin(){
93
  const val=document.getElementById('li-user').value.trim();
94
  const pass=document.getElementById('li-pass').value;
95
- if(!val||!pass){authErr('Fill all fields');return;}
96
  setBtnLoading('li',true);
97
 
98
  // Check local first (handles admin vicros89/122012 and offline users)
@@ -108,13 +114,13 @@ async function handleLogin(){
108
  let email=val;
109
  if(!val.includes('@')){
110
  const fu=Object.values(S.users).find(u=>u.username===val);
111
- if(fu) email=fu.email; else {authErr('User not found');setBtnLoading('li',false);return;}
112
  }
113
  await FB.signInWithEmailAndPassword(AUTH,email,pass);
114
  // onAuthStateChanged will handle rest
115
- }catch(e){authErr('Wrong email or password');setBtnLoading('li',false);}
116
  } else {
117
- authErr('User not found');setBtnLoading('li',false);
118
  }
119
  }
120
 
@@ -123,10 +129,10 @@ async function handleRegister(){
123
  const username=document.getElementById('re-user').value.trim().toLowerCase().replace(/\s/g,'');
124
  const email=document.getElementById('re-email').value.trim().toLowerCase();
125
  const pass=document.getElementById('re-pass').value;
126
- if(!name||!username||!email||!pass){authErr('Fill all fields');return;}
127
- if(username.length<3){authErr('Username min 3 chars');return;}
128
- if(pass.length<6){authErr('Password min 6 chars');return;}
129
- if(Object.values(S.users).find(u=>u.username===username)){authErr('Username taken');return;}
130
  setBtnLoading('re',true);
131
  const profile={id:username,username,name,displayName:name,email,password:pass,bio:'',avatar:null,color:pickColor(username),verified:false,isCreator:false,followers:[ADMIN_UID],following:[ADMIN_UID],followersCount:0,followingCount:1,isPrivate:false,ts:Date.now()};
132
  if(FIREBASE_OK){
@@ -252,7 +258,7 @@ function renderFeedContent(){
252
  if(!fc) return;
253
 
254
  if(!posts.length){
255
- fc.innerHTML=`<div class="empty-state-center"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2"><rect x="3" y="3" width="18" height="18" rx="4"/><path d="M3 9h18M9 21V9"/></svg><p>No posts yetbe the first!</p></div>`;
256
  return;
257
  }
258
 
@@ -353,7 +359,7 @@ function postCtx(e,pid){
353
  const post=S.posts.find(p=>p.id===pid); if(!post) return;
354
  const isOwn=(post.uid||post.userId)===S.uid;
355
  const m=mkCtx(e.clientX,e.clientY);
356
- m.innerHTML=`<div class="ctx-item" onclick="openComments('${pid}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Comments</div>${post.image?`<div class="ctx-item" onclick="dlImg('${post.image}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/></svg>Download</div>`:''}${isOwn?`<div class="ctx-item danger" onclick="delPost('${pid}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>Delete</div>`:`<div class="ctx-item" onclick="toast('Reported ✓');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>Report</div>`}`;
357
  document.body.appendChild(m);
358
  }
359
  function likePost(pid){
@@ -361,14 +367,14 @@ function likePost(pid){
361
  if(!post.likes) post.likes=[];
362
  const i=post.likes.indexOf(S.uid);
363
  if(i>-1) post.likes.splice(i,1);
364
- else{post.likes.push(S.uid); if((post.uid||post.userId)!==S.uid) addNotif(post.uid||post.userId,'like',dname(S.user)+' liked your post.');}
365
  if(FIREBASE_OK) FB.updateDoc(FB.doc(DB,'posts',pid),{likes:post.likes}).catch(()=>{});
366
  saveLocal(); renderFeedContent();
367
  }
368
  function delPost(pid){
369
  S.posts=S.posts.filter(p=>p.id!==pid);
370
  if(FIREBASE_OK) FB.deleteDoc(FB.doc(DB,'posts',pid)).catch(()=>{});
371
- saveLocal(); renderFeedContent(); toast('Deleted');
372
  }
373
  function fullImg(src){
374
  const o=document.createElement('div');
@@ -404,13 +410,13 @@ async function submitPost(){
404
  const text=document.getElementById('post-text-input').value.trim();
405
  const img=document.getElementById('post-img-preview').querySelector('img');
406
  const image=img?img.src:null;
407
- if(!text&&!image){toast('Add text or photo');return;}
408
  const post={id:'p'+Date.now(),uid:S.uid,userId:S.uid,text,image,likes:[],comments:[],ts:Date.now()};
409
  if(FIREBASE_OK){
410
  try{const ref=await FB.addDoc(FB.collection(DB,'posts'),post);post.id=ref.id;}catch(e){}
411
  }
412
  S.posts.unshift(post); saveLocal();
413
- closeModal('new-post-modal'); renderFeed(); toast('Posted ✦');
414
  }
415
 
416
  // ── STORIES ──
@@ -426,7 +432,7 @@ function previewStory(){
426
  }
427
  async function submitStory(){
428
  const img=document.getElementById('story-preview-img');
429
- if(!img.src||img.src===location.href){toast('Select image');return;}
430
  const text=document.getElementById('story-text-input').value.trim();
431
  S.stories=S.stories.filter(s=>s.uid!==S.uid);
432
  const story={id:'st'+Date.now(),uid:S.uid,userId:S.uid,image:img.src,text,viewers:[],ts:Date.now()};
@@ -434,7 +440,7 @@ async function submitStory(){
434
  try{const ref=await FB.addDoc(FB.collection(DB,'stories'),story);story.id=ref.id;}catch(e){}
435
  }
436
  S.stories.push(story); saveLocal();
437
- closeModal('add-story-modal'); renderStories(); toast('Story shared!');
438
  }
439
  function viewStory(uid){
440
  const list=S.stories.filter(s=>s.uid===uid||s.userId===uid);
@@ -495,7 +501,7 @@ function followUser(targetId,btn){
495
  u.following.push(targetId); u.followingCount=(u.followingCount||0)+1;
496
  t.followersCount=(t.followersCount||0)+1;
497
  if(btn){btn.textContent='Following';btn.classList.add('following');}
498
- addNotif(targetId,'follow',dname(u)+' started following you.');
499
  }
500
  if(FIREBASE_OK) FB.updateDoc(FB.doc(DB,'users',S.uid),{following:u.following,followingCount:u.followingCount}).catch(()=>{});
501
  saveLocal();
@@ -531,7 +537,7 @@ function renderConvList(){
531
  <div class="conv-name">${esc(dname(other))}${other.verified?badge():''}</div>
532
  <div class="conv-time">${last?ago(last.ts):''}</div>
533
  </div>
534
- <div class="conv-preview">${last?(last.type==='voice'?'🎤 Voice':last.type==='image'?'📷 Photo':esc((last.text||'').slice(0,42))):'Start chatting...'}</div>
535
  </div>
536
  <div class="conv-right">
537
  ${(chat.streak||0)>0?`<span class="conv-streak">🔥${chat.streak}</span>`:''}
@@ -612,7 +618,7 @@ function submitPin(){
612
  const chatId=S.pendingPin;
613
  const chat=S.chats[chatId]; if(!chat) return;
614
  if(pin===chat.pin){S.activeChat=chatId;closeModal('pin-modal');document.getElementById('pin-input').value='';renderChatWindow(chatId);renderConvList();}
615
- else toast('Wrong PIN');
616
  }
617
 
618
  function goBackToList(){
@@ -664,7 +670,7 @@ function renderChatWindow(chatId){
664
  <div class="input-action" onclick="toggleEmoji(event)" title="Emoji">
665
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>
666
  </div>
667
- <textarea id="chat-ta" class="chat-textarea" placeholder="Message..." rows="1"
668
  onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();sendMsg();}"
669
  oninput="this.style.height='auto';this.style.height=Math.min(this.scrollHeight,80)+'px'"></textarea>
670
  <label class="input-action" title="Image">
@@ -745,9 +751,6 @@ function renderMessages(chatId){
745
  if(msg.type==='image'&&msg.image){
746
  const img=document.createElement('img');img.src=msg.image;img.onclick=()=>fullImg(msg.image);bub.appendChild(img);
747
  if(msg.text){const p=document.createElement('p');p.style.marginTop='5px';p.textContent=msg.text;bub.appendChild(p);}
748
- } else if(msg.type==='voice'){
749
- const bars=Array.from({length:20},()=>`<div class="wv" style="height:${3+Math.random()*16}px"></div>`).join('');
750
- bub.innerHTML+=`<div class="voice-bubble"><div class="voice-play" onclick="toast('Playing...')"><svg viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg></div><div class="voice-waveform">${bars}</div><span class="voice-dur">${msg.duration||'0:03'}</span></div>`;
751
  } else if(msg.type==='gif'){
752
  const p=document.createElement('p');p.style.fontSize='24px';p.textContent=msg.text;bub.appendChild(p);
753
  } else {
@@ -793,7 +796,7 @@ function sendMsg(){
793
  if(FIREBASE_OK){
794
  const otherId=chatId.split('_').find(x=>x!==S.uid);
795
  FB.addDoc(FB.collection(DB,'chats',chatId,'messages'),msg).catch(()=>{});
796
- addNotif(otherId,'message',dname(S.user)+' sent you a message.');
797
  }
798
  }
799
 
@@ -814,7 +817,7 @@ function sendGif(){
814
  if(!chat.messages) chat.messages=[];
815
  chat.messages.push(msg); updateStreak(chatId); saveLocal(); renderMessages(chatId); renderConvList();
816
  }
817
- function startVoice(){S.voiceSecs=0;S.voiceTimer=setInterval(()=>S.voiceSecs++,1000);toast('🎤 Recording...');}
818
  function stopVoice(){
819
  clearInterval(S.voiceTimer); if(S.voiceSecs<1) return;
820
  const chatId=S.activeChat; const chat=S.chats[chatId]; if(!chat) return;
@@ -847,24 +850,24 @@ function bubCtx(e,msgId,chatId){
847
  ['❤️','😂','😮','👍','🔥','💯'].forEach(em=>{const b=document.createElement('div');b.className='emoji-opt';b.textContent=em;b.onclick=()=>{addReact(msgId,chatId,em);closeCtx();};er.appendChild(b);});
848
  m.appendChild(er);
849
  const sep=document.createElement('div');sep.style.cssText='border-top:1px solid rgba(255,255,255,.08);margin:3px 0';m.appendChild(sep);
850
- m.innerHTML+=`<div class="ctx-item" onclick="replyToMsg('${msgId}','${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>Reply</div>${isOwn?`<div class="ctx-item" onclick="editMsg('${msgId}','${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>Edit</div><div class="ctx-item danger" onclick="delMsg('${msgId}','${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>Delete</div>`:''}`;
851
  document.body.appendChild(m);
852
  }
853
  function addReact(msgId,chatId,emoji){const chat=S.chats[chatId];const msg=(chat.messages||[]).find(m=>m.id===msgId);if(!msg)return;if(!msg.reactions)msg.reactions=[];msg.reactions.push(emoji);saveLocal();renderMessages(chatId);}
854
- function replyToMsg(msgId,chatId){const chat=S.chats[chatId];const msg=(chat.messages||[]).find(m=>m.id===msgId);if(!msg)return;S.replyTo=msgId;const rb=document.getElementById('reply-bar');const rt=document.getElementById('reply-text');if(rb&&rt){rt.textContent='↩ '+(msg.text||'📷 Photo').slice(0,50);rb.classList.remove('hidden');}document.getElementById('chat-ta')?.focus();}
855
  function cancelReply(){S.replyTo=null;document.getElementById('reply-bar')?.classList.add('hidden');}
856
- function editMsg(msgId,chatId){const chat=S.chats[chatId];const msg=(chat.messages||[]).find(m=>m.id===msgId);if(!msg||msg.type!=='text')return;const nt=prompt('Edit message:',msg.text);if(nt===null)return;msg.text=nt.trim();msg.edited=true;saveLocal();renderMessages(chatId);}
857
  function delMsg(msgId,chatId){const chat=S.chats[chatId];if(!chat)return;chat.messages=(chat.messages||[]).filter(m=>m.id!==msgId);saveLocal();renderMessages(chatId);}
858
  function chatCtx(e,chatId){
859
  e.stopPropagation(); closeCtx();
860
  const chat=S.chats[chatId];
861
  const m=mkCtx(e.clientX,e.clientY);
862
- m.innerHTML=`<div class="ctx-item" onclick="toggleHide('${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><line x1="1" y1="1" x2="23" y2="23"/></svg>${chat.isHidden?'Unhide chat':'Hide chat'}</div><div class="ctx-item" onclick="setPin('${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Set PIN</div><div class="ctx-item danger" onclick="delChat('${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>Delete chat</div>`;
863
  document.body.appendChild(m);
864
  }
865
- function toggleHide(chatId){const c=S.chats[chatId];if(!c)return;c.isHidden=!c.isHidden;if(!c.isHidden)c.pin=null;saveLocal();renderConvList();toast(c.isHidden?'Chat hidden':'Chat visible');}
866
- function setPin(chatId){const pin=prompt('Set PIN (numbers):');if(!pin||!/^\d+$/.test(pin)){toast('Invalid PIN');return;}S.chats[chatId].pin=pin;S.chats[chatId].isHidden=true;saveLocal();renderConvList();toast('Chat protected 🔒');}
867
- function delChat(chatId){if(!confirm('Delete this conversation?'))return;delete S.chats[chatId];S.activeChat=null;goBackToList();saveLocal();renderConvList();}
868
  function updateStreak(chatId){
869
  const c=S.chats[chatId]; if(!c) return;
870
  if(!c.lastActive) c.lastActive={};
@@ -874,7 +877,7 @@ function updateStreak(chatId){
874
  const yest=new Date(Date.now()-86400000).toDateString();
875
  c.streak=(last===yest||!last)?(c.streak||0)+1:1;
876
  c.lastActive[S.uid]=Date.now();
877
- if(STREAK_MS.includes(c.streak)) setTimeout(()=>{document.getElementById('streak-title').textContent='🔥 '+c.streak+' Day Streak!';document.getElementById('streak-desc').textContent=`${c.streak} consecutive days chatting!`;document.getElementById('streak-modal').classList.remove('hidden');},300);
878
  }
879
  function closeStreakModal(){document.getElementById('streak-modal').classList.add('hidden');}
880
 
@@ -897,7 +900,7 @@ function renderNotifList(){
897
  const list=document.getElementById('notif-list'); if(!list) return;
898
  const mine=S.notifs.filter(n=>n.toUid===S.uid);
899
  list.innerHTML='';
900
- if(!mine.length){list.innerHTML=`<div class="empty-state-center"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/></svg><p>No notifications yet</p></div>`;return;}
901
  const ico={like:'❤️',comment:'💬',follow:'👤',message:'✉️'};
902
  mine.forEach(n=>{
903
  n.read=true;
@@ -934,7 +937,7 @@ function buildUserRow(u){
934
  const el=document.createElement('div');el.className='explore-user-item';
935
  el.onclick=()=>viewProfile(u.id);
936
  const id='exav_'+u.id.replace(/[^a-z0-9]/gi,'_');
937
- el.innerHTML=`<div class="avatar sm" id="${id}"></div><div class="exu-info"><div class="exu-name">${esc(dname(u))}${u.verified?badge():''}</div><div class="exu-handle">@${esc(u.username)}</div><div class="exu-count">${u.isCreator?'23,834':(u.followersCount||0).toLocaleString()} followers</div></div><button class="follow-btn${iF?' following':''}" onclick="event.stopPropagation();followUser('${u.id}',this)">${iF?'Following':'Follow'}</button>`;
938
  setTimeout(()=>{const av=document.getElementById(id);if(av)setAv(av,u);},10);
939
  return el;
940
  }
@@ -951,14 +954,16 @@ function renderProfile(uid){
951
  const fc=u.isCreator?'23,834':(u.followersCount||0).toLocaleString();
952
  const userPosts=S.posts.filter(p=>(p.uid||p.userId)===uid).sort((a,b)=>b.ts-a.ts);
953
  let actions='';
 
 
 
954
  if(isMe){
955
- actions=`<button class="check-profile-btn" onclick="openVerifyModal()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>Verify</button>
956
- <button class="check-profile-btn" onclick="openSettings()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>Settings</button>`;
957
  } else {
958
  actions=`<button class="prof-follow-btn${iF?' following':''}" onclick="followFromProfile('${uid}',this)">${iF?'Following':'Follow'}</button><button class="prof-msg-btn" onclick="startChatFromProfile('${uid}')">Message</button>`;
959
  }
960
  const backBar=!isMe?`<div style="padding:12px 18px 0;display:flex;align-items:center;gap:8px;"><button onclick="navigateTo('feed')" style="width:30px;height:30px;border-radius:50%;background:var(--surface2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text3);flex-shrink:0"><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.2' width='14' height='14'><polyline points='15 18 9 12 15 6'/></svg></button><span style="font-size:13px;font-weight:600;color:var(--text3)">@${esc(u.username)}</span></div>`:'';
961
- c.innerHTML=backBar+`<div class="profile-header"><div class="profile-top"><div class="avatar-wrap${S.stories.some(s=>s.uid===uid)?' has-story':''}"><div class="avatar xl" id="prof-av"${isMe?' style="cursor:pointer" onclick="document.getElementById(\'avatar-upload\').click()"':''}></div></div><div class="profile-info"><div class="profile-name">${esc(dname(u))}${u.verified?badge():''}</div><div class="profile-handle">@${esc(u.username)}</div>${u.bio?`<p class="profile-bio">${esc(u.bio)}</p>`:''}<div class="profile-stats"><div class="pstat"><div class="pstat-num">${userPosts.length}</div><div class="pstat-label">Posts</div></div><div class="pstat"><div class="pstat-num">${fc}</div><div class="pstat-label">Followers</div></div><div class="pstat"><div class="pstat-num">${(u.followingCount||u.following?.length||0).toLocaleString()}</div><div class="pstat-label">Following</div></div></div></div></div><div class="profile-actions">${actions}</div></div>${canSee?`<div class="posts-grid">${userPosts.map(p=>`<div class="grid-post" onclick="openComments('${p.id}')">${p.image?`<img src="${p.image}">`:`<div class="grid-post-text">${esc(p.text.slice(0,70))}</div>`}</div>`).join('')||`<p style="padding:30px;color:var(--text3);grid-column:1/-1;text-align:center;font-size:12px">No posts yet</p>`}</div>`:`<div class="private-notice"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg><p>This account is private</p></div>`}`;
962
  requestAnimationFrame(()=>{const av=document.getElementById('prof-av');if(av)setAv(av,u);});
963
  }
964
  function followFromProfile(uid,btn){followUser(uid,btn);renderProfile(uid);}
@@ -974,20 +979,20 @@ function openSettings(){
974
  }
975
  function saveSettings(){
976
  const name=document.getElementById('settings-name').value.trim();
977
- if(!name){toast('Name cannot be empty');return;}
978
  const u=S.user;
979
  u.name=name; u.displayName=name; u.bio=document.getElementById('settings-bio').value.trim();
980
  u.isPrivate=document.getElementById('private-toggle').classList.contains('on');
981
  if(FIREBASE_OK) FB.updateDoc(FB.doc(DB,'users',S.uid),{name:u.name,bio:u.bio,isPrivate:u.isPrivate}).catch(()=>{});
982
  saveLocal(); closeModal('settings-modal'); renderSidebar();
983
- if(S.page==='profile') renderMyProfile(); toast('Saved! ✓');
984
  }
985
  function changeAvatar(){
986
  const f=document.getElementById('avatar-upload').files[0]; if(!f) return;
987
  const r=new FileReader(); r.onload=e=>{
988
  const u=S.user; u.avatar=e.target.result; saveLocal();
989
  const av=document.getElementById('settings-avatar');if(av)setAv(av,u);
990
- renderSidebar(); if(S.page==='profile') renderMyProfile(); toast('Photo updated!');
991
  }; r.readAsDataURL(f);
992
  }
993
 
@@ -998,10 +1003,10 @@ function openVerifyModal(){
998
  document.getElementById('verify-step-2').classList.toggle('hidden',!u.verified);
999
  openModal('verify-modal');
1000
  }
1001
- function submitVerifyRequest(){const e=document.getElementById('verify-email').value.trim();const p=document.getElementById('verify-phone').value.trim();const n=document.getElementById('verify-realname').value.trim();if(!e||!p||!n){toast('Fill all fields');return;}document.getElementById('verify-step-1').classList.add('hidden');document.getElementById('verify-step-2').classList.remove('hidden');toast('Request sent! ✉️');}
1002
  function codeNext(el,idx){if(el.value.length===1&&idx<5)document.querySelectorAll('.code-box')[idx+1]?.focus();}
1003
  function codeBack(e,el,idx){if(e.key==='Backspace'&&!el.value&&idx>0)document.querySelectorAll('.code-box')[idx-1]?.focus();}
1004
- function submitVerifyCode(){const code=Array.from(document.querySelectorAll('.code-box')).map(i=>i.value).join('');if(code.length!==6){toast('Enter all 6 digits');return;}S.user.verified=true;saveLocal();closeModal('verify-modal');toast('Verified! ✓');renderMyProfile();}
1005
 
1006
  // ── COMMENTS ──
1007
  function openComments(pid){
@@ -1012,12 +1017,12 @@ function openComments(pid){
1012
  function renderComments(pid){
1013
  const post=S.posts.find(p=>p.id===pid);
1014
  const list=document.getElementById('comments-list'); list.innerHTML='';
1015
- if(!post||(post.comments||[]).length===0){list.innerHTML='<p style="padding:24px;text-align:center;color:var(--w30);font-size:12px">No comments yet be first!</p>';return;}
1016
  (post.comments||[]).forEach(c=>{
1017
  const cu=S.users[c.uid||c.userId]; if(!cu) return;
1018
  const el=document.createElement('div');el.className='comment-item';
1019
  const id='cmav_'+c.id;
1020
- el.innerHTML=`<div class="avatar xs" id="${id}"></div><div class="comment-body"><span class="comment-uname">${esc(dname(cu))}</span><span class="comment-txt">${esc(c.text)}</span><div class="comment-actions"><span class="comment-time">${ago(c.ts||c.createdAt)}</span><div class="comment-like-btn" onclick="likeComment('${pid}','${c.id}')"><svg viewBox="0 0 24 24" fill="${(c.likes||[]).includes(S.uid)?'currentColor':'none'}" stroke="currentColor" stroke-width="2"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg><span>${(c.likes||[]).length}</span></div><div class="comment-reply-btn" onclick="replyComment('${esc(dname(cu))}')">Reply</div></div></div>`;
1021
  setTimeout(()=>{const av=document.getElementById(id);if(av)setAv(av,cu);},10);
1022
  list.appendChild(el);
1023
  });
@@ -1052,7 +1057,7 @@ function toast(msg){const t=document.getElementById('toast-el');t.textContent=ms
1052
  function dname(u){if(!u)return'?';return u.isCreator?'S':(u.displayName||u.name||u.username||'?');}
1053
  function esc(s){if(!s)return'';return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}
1054
  function ago(ts){if(!ts)return'now';const d=(Date.now()-ts)/1000;if(d<60)return'now';if(d<3600)return Math.floor(d/60)+'m';if(d<86400)return Math.floor(d/3600)+'h';if(d<604800)return Math.floor(d/86400)+'d';return Math.floor(d/604800)+'w';}
1055
- function fmtDate(ts){const d=new Date(ts),t=new Date();if(d.toDateString()===t.toDateString())return'Today';if(d.toDateString()===new Date(Date.now()-86400000).toDateString())return'Yesterday';return d.toLocaleDateString('en-US',{month:'long',day:'numeric'});}
1056
  function initials(n){if(!n)return'?';return n.split(' ').map(w=>w[0]).join('').toUpperCase().slice(0,2);}
1057
  function pickColor(s){const c=['#111','#131313','#0f0f0f','#151515','#181818'];let h=0;for(let i=0;i<s.length;i++)h=s.charCodeAt(i)+((h<<5)-h);return c[Math.abs(h)%c.length];}
1058
  function badge(){return`<svg class="v-badge" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>`;}
 
40
  window.addEventListener('DOMContentLoaded',()=>{
41
  loadLocal();
42
  seedAdmin();
43
+ // Try auto-login from localStorage immediately
44
+ const savedUid=localStorage.getItem('loom_uid');
45
+ if(savedUid && S.users[savedUid]){
46
+ S.uid=savedUid;
47
+ S.user=S.users[savedUid];
48
+ showApp();
49
+ } else {
50
+ // If no firebase yet after 1.5s, show auth
51
+ setTimeout(()=>{
52
+ if(!FIREBASE_OK && !S.uid){
53
+ showAuth();
54
+ }
55
+ },1500);
56
+ }
57
  });
58
 
59
  // ── LOCAL STORAGE ──
 
69
  }
70
  function seedAdmin(){
71
  if(!S.users[ADMIN_UID]){
72
+ S.users[ADMIN_UID]={id:ADMIN_UID,username:ADMIN_UID,name:'Victor',displayName:'Victor',email:ADMIN_EMAIL,password:ADMIN_PASS,bio:'Creator of Loom ✦',avatar:null,color:'#111',verified:true,isCreator:true,followers:[],following:[],followersCount:23834,followingCount:0,isPrivate:false,ts:Date.now()-86400000*300};
73
  S.posts.unshift({id:'sp1',uid:ADMIN_UID,text:'Welcome to Loom. A new era of communication. ✦',image:null,likes:[],comments:[],ts:Date.now()-3600000*5});
74
  S.posts.unshift({id:'sp2',uid:ADMIN_UID,text:'Minimalism is not a style. It\'s an attitude. 🖤',image:null,likes:[],comments:[],ts:Date.now()-3600000*2});
75
  saveLocal();
 
98
  async function handleLogin(){
99
  const val=document.getElementById('li-user').value.trim();
100
  const pass=document.getElementById('li-pass').value;
101
+ if(!val||!pass){authErr('Completează toate câmpurile');return;}
102
  setBtnLoading('li',true);
103
 
104
  // Check local first (handles admin vicros89/122012 and offline users)
 
114
  let email=val;
115
  if(!val.includes('@')){
116
  const fu=Object.values(S.users).find(u=>u.username===val);
117
+ if(fu) email=fu.email; else {authErr('Utilizatorul nu a fost găsit');setBtnLoading('li',false);return;}
118
  }
119
  await FB.signInWithEmailAndPassword(AUTH,email,pass);
120
  // onAuthStateChanged will handle rest
121
+ }catch(e){authErr('Email sau parolă incorectă');setBtnLoading('li',false);}
122
  } else {
123
+ authErr('Utilizatorul nu a fost găsit');setBtnLoading('li',false);
124
  }
125
  }
126
 
 
129
  const username=document.getElementById('re-user').value.trim().toLowerCase().replace(/\s/g,'');
130
  const email=document.getElementById('re-email').value.trim().toLowerCase();
131
  const pass=document.getElementById('re-pass').value;
132
+ if(!name||!username||!email||!pass){authErr('Completează toate câmpurile');return;}
133
+ if(username.length<3){authErr('Utilizatorul trebuie să aibă minim 3 caractere');return;}
134
+ if(pass.length<6){authErr('Parola trebuie să aibă minim 6 caractere');return;}
135
+ if(Object.values(S.users).find(u=>u.username===username)){authErr('Utilizatorul este deja folosit');return;}
136
  setBtnLoading('re',true);
137
  const profile={id:username,username,name,displayName:name,email,password:pass,bio:'',avatar:null,color:pickColor(username),verified:false,isCreator:false,followers:[ADMIN_UID],following:[ADMIN_UID],followersCount:0,followingCount:1,isPrivate:false,ts:Date.now()};
138
  if(FIREBASE_OK){
 
258
  if(!fc) return;
259
 
260
  if(!posts.length){
261
+ fc.innerHTML=`<div class="empty-state-center"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2"><rect x="3" y="3" width="18" height="18" rx="4"/><path d="M3 9h18M9 21V9"/></svg><p>Niciun post încăfii primul!</p></div>`;
262
  return;
263
  }
264
 
 
359
  const post=S.posts.find(p=>p.id===pid); if(!post) return;
360
  const isOwn=(post.uid||post.userId)===S.uid;
361
  const m=mkCtx(e.clientX,e.clientY);
362
+ m.innerHTML=`<div class="ctx-item" onclick="openComments('${pid}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Comentarii</div>${post.image?`<div class="ctx-item" onclick="dlImg('${post.image}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/></svg>Descarcă</div>`:''}${isOwn?`<div class="ctx-item danger" onclick="delPost('${pid}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>Șterge</div>`:`<div class="ctx-item" onclick="toast('Raportat ✓');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>Raportează</div>`}`;
363
  document.body.appendChild(m);
364
  }
365
  function likePost(pid){
 
367
  if(!post.likes) post.likes=[];
368
  const i=post.likes.indexOf(S.uid);
369
  if(i>-1) post.likes.splice(i,1);
370
+ else{post.likes.push(S.uid); if((post.uid||post.userId)!==S.uid) addNotif(post.uid||post.userId,'like',dname(S.user)+' a apreciat postarea ta.');}
371
  if(FIREBASE_OK) FB.updateDoc(FB.doc(DB,'posts',pid),{likes:post.likes}).catch(()=>{});
372
  saveLocal(); renderFeedContent();
373
  }
374
  function delPost(pid){
375
  S.posts=S.posts.filter(p=>p.id!==pid);
376
  if(FIREBASE_OK) FB.deleteDoc(FB.doc(DB,'posts',pid)).catch(()=>{});
377
+ saveLocal(); renderFeedContent(); toast('Șters');
378
  }
379
  function fullImg(src){
380
  const o=document.createElement('div');
 
410
  const text=document.getElementById('post-text-input').value.trim();
411
  const img=document.getElementById('post-img-preview').querySelector('img');
412
  const image=img?img.src:null;
413
+ if(!text&&!image){toast('Adaugă text sau poză');return;}
414
  const post={id:'p'+Date.now(),uid:S.uid,userId:S.uid,text,image,likes:[],comments:[],ts:Date.now()};
415
  if(FIREBASE_OK){
416
  try{const ref=await FB.addDoc(FB.collection(DB,'posts'),post);post.id=ref.id;}catch(e){}
417
  }
418
  S.posts.unshift(post); saveLocal();
419
+ closeModal('new-post-modal'); renderFeed(); toast('Publicat ✦');
420
  }
421
 
422
  // ── STORIES ──
 
432
  }
433
  async function submitStory(){
434
  const img=document.getElementById('story-preview-img');
435
+ if(!img.src||img.src===location.href){toast('Selectează o imagine');return;}
436
  const text=document.getElementById('story-text-input').value.trim();
437
  S.stories=S.stories.filter(s=>s.uid!==S.uid);
438
  const story={id:'st'+Date.now(),uid:S.uid,userId:S.uid,image:img.src,text,viewers:[],ts:Date.now()};
 
440
  try{const ref=await FB.addDoc(FB.collection(DB,'stories'),story);story.id=ref.id;}catch(e){}
441
  }
442
  S.stories.push(story); saveLocal();
443
+ closeModal('add-story-modal'); renderStories(); toast('Story distribuit!');
444
  }
445
  function viewStory(uid){
446
  const list=S.stories.filter(s=>s.uid===uid||s.userId===uid);
 
501
  u.following.push(targetId); u.followingCount=(u.followingCount||0)+1;
502
  t.followersCount=(t.followersCount||0)+1;
503
  if(btn){btn.textContent='Following';btn.classList.add('following');}
504
+ addNotif(targetId,'follow',dname(u)+' a început să te urmărească.');
505
  }
506
  if(FIREBASE_OK) FB.updateDoc(FB.doc(DB,'users',S.uid),{following:u.following,followingCount:u.followingCount}).catch(()=>{});
507
  saveLocal();
 
537
  <div class="conv-name">${esc(dname(other))}${other.verified?badge():''}</div>
538
  <div class="conv-time">${last?ago(last.ts):''}</div>
539
  </div>
540
+ <div class="conv-preview">${last?(last.type==='voice'?'🎤 Voice':last.type==='image'?'📷 Foto':esc((last.text||'').slice(0,42))):'Începe conversația...'}</div>
541
  </div>
542
  <div class="conv-right">
543
  ${(chat.streak||0)>0?`<span class="conv-streak">🔥${chat.streak}</span>`:''}
 
618
  const chatId=S.pendingPin;
619
  const chat=S.chats[chatId]; if(!chat) return;
620
  if(pin===chat.pin){S.activeChat=chatId;closeModal('pin-modal');document.getElementById('pin-input').value='';renderChatWindow(chatId);renderConvList();}
621
+ else toast('PIN greșit');
622
  }
623
 
624
  function goBackToList(){
 
670
  <div class="input-action" onclick="toggleEmoji(event)" title="Emoji">
671
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>
672
  </div>
673
+ <textarea id="chat-ta" class="chat-textarea" placeholder="Mesaj..." rows="1"
674
  onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();sendMsg();}"
675
  oninput="this.style.height='auto';this.style.height=Math.min(this.scrollHeight,80)+'px'"></textarea>
676
  <label class="input-action" title="Image">
 
751
  if(msg.type==='image'&&msg.image){
752
  const img=document.createElement('img');img.src=msg.image;img.onclick=()=>fullImg(msg.image);bub.appendChild(img);
753
  if(msg.text){const p=document.createElement('p');p.style.marginTop='5px';p.textContent=msg.text;bub.appendChild(p);}
 
 
 
754
  } else if(msg.type==='gif'){
755
  const p=document.createElement('p');p.style.fontSize='24px';p.textContent=msg.text;bub.appendChild(p);
756
  } else {
 
796
  if(FIREBASE_OK){
797
  const otherId=chatId.split('_').find(x=>x!==S.uid);
798
  FB.addDoc(FB.collection(DB,'chats',chatId,'messages'),msg).catch(()=>{});
799
+ addNotif(otherId,'message',dname(S.user)+' ți-a trimis un mesaj.');
800
  }
801
  }
802
 
 
817
  if(!chat.messages) chat.messages=[];
818
  chat.messages.push(msg); updateStreak(chatId); saveLocal(); renderMessages(chatId); renderConvList();
819
  }
820
+ function startVoice(){S.voiceSecs=0;S.voiceTimer=setInterval(()=>S.voiceSecs++,1000);toast('🎤 Se înregistrează...');}
821
  function stopVoice(){
822
  clearInterval(S.voiceTimer); if(S.voiceSecs<1) return;
823
  const chatId=S.activeChat; const chat=S.chats[chatId]; if(!chat) return;
 
850
  ['❤️','😂','😮','👍','🔥','💯'].forEach(em=>{const b=document.createElement('div');b.className='emoji-opt';b.textContent=em;b.onclick=()=>{addReact(msgId,chatId,em);closeCtx();};er.appendChild(b);});
851
  m.appendChild(er);
852
  const sep=document.createElement('div');sep.style.cssText='border-top:1px solid rgba(255,255,255,.08);margin:3px 0';m.appendChild(sep);
853
+ m.innerHTML+=`<div class="ctx-item" onclick="replyToMsg('${msgId}','${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>Răspunde</div>${isOwn?`<div class="ctx-item" onclick="editMsg('${msgId}','${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>Editează</div><div class="ctx-item danger" onclick="delMsg('${msgId}','${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>Șterge</div>`:''}`;
854
  document.body.appendChild(m);
855
  }
856
  function addReact(msgId,chatId,emoji){const chat=S.chats[chatId];const msg=(chat.messages||[]).find(m=>m.id===msgId);if(!msg)return;if(!msg.reactions)msg.reactions=[];msg.reactions.push(emoji);saveLocal();renderMessages(chatId);}
857
+ function replyToMsg(msgId,chatId){const chat=S.chats[chatId];const msg=(chat.messages||[]).find(m=>m.id===msgId);if(!msg)return;S.replyTo=msgId;const rb=document.getElementById('reply-bar');const rt=document.getElementById('reply-text');if(rb&&rt){rt.textContent='↩ '+(msg.text||'📷 Foto').slice(0,50);rb.classList.remove('hidden');}document.getElementById('chat-ta')?.focus();}
858
  function cancelReply(){S.replyTo=null;document.getElementById('reply-bar')?.classList.add('hidden');}
859
+ function editMsg(msgId,chatId){const chat=S.chats[chatId];const msg=(chat.messages||[]).find(m=>m.id===msgId);if(!msg||msg.type!=='text')return;const nt=prompt('Editează mesajul:',msg.text);if(nt===null)return;msg.text=nt.trim();msg.edited=true;saveLocal();renderMessages(chatId);}
860
  function delMsg(msgId,chatId){const chat=S.chats[chatId];if(!chat)return;chat.messages=(chat.messages||[]).filter(m=>m.id!==msgId);saveLocal();renderMessages(chatId);}
861
  function chatCtx(e,chatId){
862
  e.stopPropagation(); closeCtx();
863
  const chat=S.chats[chatId];
864
  const m=mkCtx(e.clientX,e.clientY);
865
+ m.innerHTML=`<div class="ctx-item" onclick="toggleHide('${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><line x1="1" y1="1" x2="23" y2="23"/></svg>${chat.isHidden?'Arată chat':'Ascunde chat'}</div><div class="ctx-item" onclick="setPin('${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Setează PIN</div><div class="ctx-item danger" onclick="delChat('${chatId}');closeCtx()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg>Șterge chat</div>`;
866
  document.body.appendChild(m);
867
  }
868
+ function toggleHide(chatId){const c=S.chats[chatId];if(!c)return;c.isHidden=!c.isHidden;if(!c.isHidden)c.pin=null;saveLocal();renderConvList();toast(c.isHidden?'Chat ascuns':'Chat vizibil');}
869
+ function setPin(chatId){const pin=prompt('Set PIN (numbers):');if(!pin||!/^\d+$/.test(pin)){toast('PIN invalid');return;}S.chats[chatId].pin=pin;S.chats[chatId].isHidden=true;saveLocal();renderConvList();toast('Chat protejat 🔒');}
870
+ function delChat(chatId){if(!confirm('Ștergi această conversație?'))return;delete S.chats[chatId];S.activeChat=null;goBackToList();saveLocal();renderConvList();}
871
  function updateStreak(chatId){
872
  const c=S.chats[chatId]; if(!c) return;
873
  if(!c.lastActive) c.lastActive={};
 
877
  const yest=new Date(Date.now()-86400000).toDateString();
878
  c.streak=(last===yest||!last)?(c.streak||0)+1:1;
879
  c.lastActive[S.uid]=Date.now();
880
+ if(STREAK_MS.includes(c.streak)) setTimeout(()=>{document.getElementById('streak-title').textContent='🔥 '+c.streak+' Zile Consecutive!';document.getElementById('streak-desc').textContent=`${c.streak} zile consecutive de chat!`;document.getElementById('streak-modal').classList.remove('hidden');},300);
881
  }
882
  function closeStreakModal(){document.getElementById('streak-modal').classList.add('hidden');}
883
 
 
900
  const list=document.getElementById('notif-list'); if(!list) return;
901
  const mine=S.notifs.filter(n=>n.toUid===S.uid);
902
  list.innerHTML='';
903
+ if(!mine.length){list.innerHTML=`<div class="empty-state-center"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/></svg><p>Nicio notificare încă</p></div>`;return;}
904
  const ico={like:'❤️',comment:'💬',follow:'👤',message:'✉️'};
905
  mine.forEach(n=>{
906
  n.read=true;
 
937
  const el=document.createElement('div');el.className='explore-user-item';
938
  el.onclick=()=>viewProfile(u.id);
939
  const id='exav_'+u.id.replace(/[^a-z0-9]/gi,'_');
940
+ el.innerHTML=`<div class="avatar sm" id="${id}"></div><div class="exu-info"><div class="exu-name">${esc(dname(u))}${u.verified?badge():''}</div><div class="exu-handle">@${esc(u.username)}</div><div class="exu-count">${u.isCreator?'23,834':(u.followersCount||0).toLocaleString()} urmăritori</div></div><button class="follow-btn${iF?' following':''}" onclick="event.stopPropagation();followUser('${u.id}',this)">${iF?'Following':'Follow'}</button>`;
941
  setTimeout(()=>{const av=document.getElementById(id);if(av)setAv(av,u);},10);
942
  return el;
943
  }
 
954
  const fc=u.isCreator?'23,834':(u.followersCount||0).toLocaleString();
955
  const userPosts=S.posts.filter(p=>(p.uid||p.userId)===uid).sort((a,b)=>b.ts-a.ts);
956
  let actions='';
957
+ const settingsBtn=`<button class="check-profile-btn" onclick="openSettings()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>Setări</button>`;
958
+ // Admin (vicros89) and already-verified users: no Verify button
959
+ const verifyBtn=(isMe&&!u.verified&&uid!==ADMIN_UID)?`<button class="check-profile-btn" onclick="openVerifyModal()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>Verifică</button>`:'';
960
  if(isMe){
961
+ actions=verifyBtn+settingsBtn;
 
962
  } else {
963
  actions=`<button class="prof-follow-btn${iF?' following':''}" onclick="followFromProfile('${uid}',this)">${iF?'Following':'Follow'}</button><button class="prof-msg-btn" onclick="startChatFromProfile('${uid}')">Message</button>`;
964
  }
965
  const backBar=!isMe?`<div style="padding:12px 18px 0;display:flex;align-items:center;gap:8px;"><button onclick="navigateTo('feed')" style="width:30px;height:30px;border-radius:50%;background:var(--surface2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text3);flex-shrink:0"><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.2' width='14' height='14'><polyline points='15 18 9 12 15 6'/></svg></button><span style="font-size:13px;font-weight:600;color:var(--text3)">@${esc(u.username)}</span></div>`:'';
966
+ c.innerHTML=backBar+`<div class="profile-header"><div class="profile-top"><div class="avatar-wrap${S.stories.some(s=>s.uid===uid)?' has-story':''}"><div class="avatar xl" id="prof-av"${isMe?' style="cursor:pointer" onclick="document.getElementById(\'avatar-upload\').click()"':''}></div></div><div class="profile-info"><div class="profile-name">${esc(dname(u))}${u.verified?badge():''}</div><div class="profile-handle">@${esc(u.username)}</div>${u.bio?`<p class="profile-bio">${esc(u.bio)}</p>`:''}<div class="profile-stats"><div class="pstat"><div class="pstat-num">${userPosts.length}</div><div class="pstat-label">Postări</div></div><div class="pstat"><div class="pstat-num">${fc}</div><div class="pstat-label">Urmăritori</div></div><div class="pstat"><div class="pstat-num">${(u.followingCount||u.following?.length||0).toLocaleString()}</div><div class="pstat-label">Urmărești</div></div></div></div></div><div class="profile-actions">${actions}</div></div>${canSee?`<div class="posts-grid">${userPosts.map(p=>`<div class="grid-post" onclick="openComments('${p.id}')">${p.image?`<img src="${p.image}">`:`<div class="grid-post-text">${esc(p.text.slice(0,70))}</div>`}</div>`).join('')||`<p style="padding:30px;color:var(--text3);grid-column:1/-1;text-align:center;font-size:12px">Niciun post încă</p>`}</div>`:`<div class="private-notice"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg><p>Acest cont este privat</p></div>`}`;
967
  requestAnimationFrame(()=>{const av=document.getElementById('prof-av');if(av)setAv(av,u);});
968
  }
969
  function followFromProfile(uid,btn){followUser(uid,btn);renderProfile(uid);}
 
979
  }
980
  function saveSettings(){
981
  const name=document.getElementById('settings-name').value.trim();
982
+ if(!name){toast('Numele nu poate fi gol');return;}
983
  const u=S.user;
984
  u.name=name; u.displayName=name; u.bio=document.getElementById('settings-bio').value.trim();
985
  u.isPrivate=document.getElementById('private-toggle').classList.contains('on');
986
  if(FIREBASE_OK) FB.updateDoc(FB.doc(DB,'users',S.uid),{name:u.name,bio:u.bio,isPrivate:u.isPrivate}).catch(()=>{});
987
  saveLocal(); closeModal('settings-modal'); renderSidebar();
988
+ if(S.page==='profile') renderMyProfile(); toast('Salvat! ✓');
989
  }
990
  function changeAvatar(){
991
  const f=document.getElementById('avatar-upload').files[0]; if(!f) return;
992
  const r=new FileReader(); r.onload=e=>{
993
  const u=S.user; u.avatar=e.target.result; saveLocal();
994
  const av=document.getElementById('settings-avatar');if(av)setAv(av,u);
995
+ renderSidebar(); if(S.page==='profile') renderMyProfile(); toast('Poză actualizată!');
996
  }; r.readAsDataURL(f);
997
  }
998
 
 
1003
  document.getElementById('verify-step-2').classList.toggle('hidden',!u.verified);
1004
  openModal('verify-modal');
1005
  }
1006
+ function submitVerifyRequest(){const e=document.getElementById('verify-email').value.trim();const p=document.getElementById('verify-phone').value.trim();const n=document.getElementById('verify-realname').value.trim();if(!e||!p||!n){toast('Completează toate câmpurile');return;}document.getElementById('verify-step-1').classList.add('hidden');document.getElementById('verify-step-2').classList.remove('hidden');toast('Cerere trimisă! ✉️');}
1007
  function codeNext(el,idx){if(el.value.length===1&&idx<5)document.querySelectorAll('.code-box')[idx+1]?.focus();}
1008
  function codeBack(e,el,idx){if(e.key==='Backspace'&&!el.value&&idx>0)document.querySelectorAll('.code-box')[idx-1]?.focus();}
1009
+ function submitVerifyCode(){const code=Array.from(document.querySelectorAll('.code-box')).map(i=>i.value).join('');if(code.length!==6){toast('Introdu toate cele 6 cifre');return;}S.user.verified=true;saveLocal();closeModal('verify-modal');toast('Verificat! ✓');renderMyProfile();}
1010
 
1011
  // ── COMMENTS ──
1012
  function openComments(pid){
 
1017
  function renderComments(pid){
1018
  const post=S.posts.find(p=>p.id===pid);
1019
  const list=document.getElementById('comments-list'); list.innerHTML='';
1020
+ if(!post||(post.comments||[]).length===0){list.innerHTML='<p style="padding:24px;text-align:center;color:var(--w30);font-size:12px">Niciun comentariufii primul!</p>';return;}
1021
  (post.comments||[]).forEach(c=>{
1022
  const cu=S.users[c.uid||c.userId]; if(!cu) return;
1023
  const el=document.createElement('div');el.className='comment-item';
1024
  const id='cmav_'+c.id;
1025
+ el.innerHTML=`<div class="avatar xs" id="${id}"></div><div class="comment-body"><span class="comment-uname">${esc(dname(cu))}</span><span class="comment-txt">${esc(c.text)}</span><div class="comment-actions"><span class="comment-time">${ago(c.ts||c.createdAt)}</span><div class="comment-like-btn" onclick="likeComment('${pid}','${c.id}')"><svg viewBox="0 0 24 24" fill="${(c.likes||[]).includes(S.uid)?'currentColor':'none'}" stroke="currentColor" stroke-width="2"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg><span>${(c.likes||[]).length}</span></div><div class="comment-reply-btn" onclick="replyComment('${esc(dname(cu))}')">Răspunde</div></div></div>`;
1026
  setTimeout(()=>{const av=document.getElementById(id);if(av)setAv(av,cu);},10);
1027
  list.appendChild(el);
1028
  });
 
1057
  function dname(u){if(!u)return'?';return u.isCreator?'S':(u.displayName||u.name||u.username||'?');}
1058
  function esc(s){if(!s)return'';return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}
1059
  function ago(ts){if(!ts)return'now';const d=(Date.now()-ts)/1000;if(d<60)return'now';if(d<3600)return Math.floor(d/60)+'m';if(d<86400)return Math.floor(d/3600)+'h';if(d<604800)return Math.floor(d/86400)+'d';return Math.floor(d/604800)+'w';}
1060
+ function fmtDate(ts){const d=new Date(ts),t=new Date();if(d.toDateString()===t.toDateString())return'Azi';if(d.toDateString()===new Date(Date.now()-86400000).toDateString())return'Ieri';return d.toLocaleDateString('ro-RO',{month:'long',day:'numeric'});}
1061
  function initials(n){if(!n)return'?';return n.split(' ').map(w=>w[0]).join('').toUpperCase().slice(0,2);}
1062
  function pickColor(s){const c=['#111','#131313','#0f0f0f','#151515','#181818'];let h=0;for(let i=0;i<s.length;i++)h=s.charCodeAt(i)+((h<<5)-h);return c[Math.abs(h)%c.length];}
1063
  function badge(){return`<svg class="v-badge" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>`;}
index.html CHANGED
@@ -8,7 +8,7 @@
8
  <title>Loom</title>
9
  <link rel="icon" type="image/svg+xml" href="logo.svg">
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
11
- <link href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,600;1,400&display=swap" rel="stylesheet">
12
  <script type="module">
13
  import{initializeApp}from'https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js';
14
  import{getAuth,createUserWithEmailAndPassword,signInWithEmailAndPassword,onAuthStateChanged,signOut,updateProfile}from'https://www.gstatic.com/firebasejs/10.12.0/firebase-auth.js';
@@ -32,55 +32,49 @@
32
  <div class="auth-card">
33
  <div class="auth-logo">
34
  <img src="logo.svg" class="auth-logo-img" alt="">
35
- <span class="logo-text">Loom</span>
36
  </div>
37
- <p class="auth-tagline">Communicate. Share. Connect.</p>
38
-
39
  <div class="auth-tabs">
40
- <button class="auth-tab active" onclick="switchAuthTab('login')">Sign In</button>
41
- <button class="auth-tab" onclick="switchAuthTab('register')">Create Account</button>
42
  </div>
43
-
44
- <!-- LOGIN -->
45
  <div id="login-form" class="auth-form">
46
  <div class="input-group">
47
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
48
- <input type="text" id="li-user" placeholder="Username or Email" autocomplete="off" autocapitalize="off" onkeydown="if(event.key==='Enter')handleLogin()">
49
  </div>
50
  <div class="input-group">
51
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
52
- <input type="password" id="li-pass" placeholder="Password" onkeydown="if(event.key==='Enter')handleLogin()">
53
  </div>
54
  <button class="btn-primary" onclick="handleLogin()">
55
- <span id="li-text">Sign In</span>
56
- <div class="btn-spinner hidden" id="li-spin"></div>
57
  </button>
58
  </div>
59
-
60
- <!-- REGISTER -->
61
  <div id="register-form" class="auth-form hidden">
62
  <div class="input-group">
63
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
64
- <input type="text" id="re-name" placeholder="Full Name" autocapitalize="words">
65
  </div>
66
  <div class="input-group">
67
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="10"/><path d="M8.56 2.75c4.37 6.03 6.02 9.42 8.03 17.72m2.54-15.38c-3.72 4.35-8.94 5.66-16.88 5.85m19.5 1.9c-3.5-.93-6.63-.82-8.94 0-2.58.92-5.01 2.86-7.44 6.32"/></svg>
68
- <input type="text" id="re-user" placeholder="Username" autocapitalize="off" autocomplete="off">
69
  </div>
70
  <div class="input-group">
71
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
72
  <input type="email" id="re-email" placeholder="Email">
73
  </div>
74
  <div class="input-group">
75
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
76
- <input type="password" id="re-pass" placeholder="Password (min 6)" onkeydown="if(event.key==='Enter')handleRegister()">
77
  </div>
78
  <button class="btn-primary" onclick="handleRegister()">
79
- <span id="re-text">Create Account</span>
80
- <div class="btn-spinner hidden" id="re-spin"></div>
81
  </button>
82
  </div>
83
-
84
  <p class="auth-error hidden" id="auth-error"></p>
85
  </div>
86
  </div>
@@ -88,41 +82,15 @@
88
  <!-- ═══ APP ═══ -->
89
  <div id="app" class="hidden">
90
 
91
- <!-- BOTTOM NAVBAR -->
92
- <aside class="sidebar">
93
- <nav class="sidebar-nav">
94
- <div class="nav-item active" data-page="feed" onclick="navigateTo('feed')" title="Feed">
95
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
96
- </div>
97
- <div class="nav-item" data-page="chat" onclick="navigateTo('chat')" title="Messages">
98
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
99
- <span class="nav-badge hidden" id="msg-badge">0</span>
100
- </div>
101
- <div class="nav-item" data-page="notifications" onclick="navigateTo('notifications')" title="Notifications">
102
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
103
- <span class="nav-badge hidden" id="notif-badge">0</span>
104
- </div>
105
- <div class="nav-item" data-page="explore" onclick="navigateTo('explore')" title="Explore">
106
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
107
- </div>
108
- <div class="nav-item" data-page="profile" onclick="navigateTo('profile')" title="Profile">
109
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
110
- </div>
111
- <div class="nav-item" onclick="openSettings()" title="Settings">
112
- <div class="avatar xs" id="sb-avatar"></div>
113
- </div>
114
- </nav>
115
- </aside>
116
-
117
- <!-- MAIN -->
118
  <main class="main-content">
119
 
120
  <!-- FEED -->
121
  <div id="pg-feed" class="page active">
122
- <div class="page-header glass-header">
123
  <h1 class="page-title font-serif">Feed</h1>
124
  <div class="header-actions">
125
- <button class="icon-btn" onclick="openNewPost()">
126
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
127
  </button>
128
  </div>
@@ -136,7 +104,7 @@
136
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
137
  </div>
138
  </div>
139
- <span class="story-label">Your Story</span>
140
  </div>
141
  </div>
142
  </div>
@@ -149,10 +117,9 @@
149
  <!-- CHAT -->
150
  <div id="pg-chat" class="page">
151
  <div class="chat-layout" id="chat-layout">
152
- <!-- List -->
153
  <div class="chat-sidebar">
154
  <div class="chat-sidebar-header">
155
- <h2 class="font-serif">Messages</h2>
156
  <button class="icon-btn" onclick="openNewChat()">
157
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
158
  </button>
@@ -160,127 +127,142 @@
160
  <div class="chat-search-area">
161
  <div class="search-bar">
162
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
163
- <input type="text" id="chat-search-input" placeholder="Search..." oninput="filterChats()">
164
  </div>
165
  </div>
166
  <div class="chat-tabs-row">
167
- <button class="chat-tab active" onclick="switchChatTab('all',this)">All</button>
168
  <button class="chat-tab" onclick="switchChatTab('secret',this)">Secret</button>
169
- <button class="chat-tab" onclick="switchChatTab('hidden',this)">Hidden</button>
170
  </div>
171
  <div class="chat-list-scroll" id="chat-list"></div>
172
  </div>
173
- <!-- Window -->
174
  <div class="chat-main" id="chat-main">
175
  <div class="chat-empty-state">
176
  <div class="chat-empty-icon">
177
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
178
  </div>
179
- <p>Select a conversation</p>
180
- <span>or start a new one →</span>
181
  </div>
182
  </div>
183
  </div>
184
  </div>
185
 
186
- <!-- NOTIFICATIONS -->
187
  <div id="pg-notifications" class="page">
188
- <div class="page-header glass-header">
189
- <h1 class="page-title font-serif">Notifications</h1>
190
- <button class="icon-btn" onclick="clearAllNotifications()" title="Clear all">
191
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
192
  </button>
193
  </div>
194
  <div class="notif-list" id="notif-list"></div>
195
  </div>
196
 
197
- <!-- EXPLORE -->
198
  <div id="pg-explore" class="page">
199
- <div class="page-header glass-header">
200
- <h1 class="page-title font-serif">Explore</h1>
201
  </div>
202
  <div class="explore-search-wrap">
203
  <div class="search-bar large">
204
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
205
- <input type="text" id="explore-input" placeholder="Search users..." oninput="searchUsers()">
206
  </div>
207
  </div>
208
  <div id="explore-results"></div>
209
  <div class="explore-section">
210
- <p class="section-label">All Users</p>
211
  <div id="explore-suggested"></div>
212
  </div>
213
  </div>
214
 
215
- <!-- PROFILE -->
216
  <div id="pg-profile" class="page">
217
  <div id="profile-content"></div>
218
  </div>
219
 
220
  </main>
221
 
222
- <!-- RIGHT PANEL -->
223
- <aside class="right-panel">
224
- <div>
225
- <p class="section-label">Suggested</p>
226
- <div id="right-suggested"></div>
 
 
 
 
 
227
  </div>
228
- <div>
229
- <p class="section-label">Trending</p>
230
- <div id="trending-tags"></div>
 
 
 
 
 
 
 
 
 
 
 
231
  </div>
232
- </aside>
233
 
234
  </div><!-- /app -->
235
 
236
  <!-- ═══ MODALS ═══ -->
237
 
238
- <!-- NEW POST -->
239
  <div class="modal-overlay hidden" id="new-post-modal" onclick="if(event.target===this)closeModal('new-post-modal')">
240
- <div class="modal glass-modal">
241
  <div class="modal-header">
242
- <h2 class="font-serif">New Post</h2>
243
  <button class="modal-close" onclick="closeModal('new-post-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
244
  </div>
245
  <div class="modal-body">
246
  <div class="composer-row">
247
  <div class="avatar sm" id="composer-av"></div>
248
- <textarea id="post-text-input" class="post-textarea" placeholder="What's on your mind?" rows="3"></textarea>
249
  </div>
250
  <div id="post-img-preview" class="hidden"></div>
251
  <div class="composer-toolbar">
252
  <label class="toolbar-btn">
253
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
254
- Photo
255
  <input type="file" accept="image/*" id="post-img-input" onchange="previewPostImg()" hidden>
256
  </label>
257
  </div>
258
- <button class="btn-primary" onclick="submitPost()">Post ✦</button>
259
  </div>
260
  </div>
261
  </div>
262
 
263
- <!-- ADD STORY -->
264
  <div class="modal-overlay hidden" id="add-story-modal" onclick="if(event.target===this)closeModal('add-story-modal')">
265
- <div class="modal glass-modal">
266
  <div class="modal-header">
267
- <h2 class="font-serif">Add Story</h2>
268
  <button class="modal-close" onclick="closeModal('add-story-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
269
  </div>
270
  <div class="modal-body">
271
  <label class="upload-area" id="story-upload-label">
272
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
273
- <span>Tap to select photo</span>
274
  <input type="file" accept="image/*" id="story-img-input" onchange="previewStory()" hidden>
275
  </label>
276
  <div id="story-preview" class="hidden story-preview-wrap"><img id="story-preview-img" alt=""></div>
277
- <input type="text" id="story-text-input" class="auth-input" placeholder="Add text (optional)">
278
- <button class="btn-primary" onclick="submitStory()">Share Story</button>
279
  </div>
280
  </div>
281
  </div>
282
 
283
- <!-- STORY VIEWER -->
284
  <div class="story-viewer hidden" id="story-viewer">
285
  <div class="story-bg" id="sv-bg"></div>
286
  <div class="story-progress-bar"><div class="story-progress" id="sv-prog"></div></div>
@@ -296,32 +278,32 @@
296
  <div class="story-nav-l" onclick="prevStory()"></div>
297
  <div class="story-nav-r" onclick="nextStory()"></div>
298
  <div class="story-viewers hidden" id="sv-viewers">
299
- <p class="sv-viewers-label">Viewers</p>
300
  <div id="sv-viewers-list"></div>
301
  </div>
302
  </div>
303
 
304
- <!-- COMMENTS -->
305
  <div class="modal-overlay hidden" id="comments-modal" onclick="if(event.target===this)closeModal('comments-modal')">
306
- <div class="modal glass-modal tall-modal">
307
  <div class="modal-header">
308
- <h2 class="font-serif">Comments</h2>
309
  <button class="modal-close" onclick="closeModal('comments-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
310
  </div>
311
  <div class="comments-list" id="comments-list"></div>
312
  <div class="comment-compose">
313
  <div class="avatar xs" id="comment-avatar"></div>
314
- <input type="text" id="comment-input" class="comment-field" placeholder="Add a comment..." onkeydown="if(event.key==='Enter')submitComment()">
315
  <button class="send-icon-btn" onclick="submitComment()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg></button>
316
  </div>
317
  </div>
318
  </div>
319
 
320
- <!-- SETTINGS -->
321
  <div class="modal-overlay hidden" id="settings-modal" onclick="if(event.target===this)closeModal('settings-modal')">
322
- <div class="modal glass-modal">
323
  <div class="modal-header">
324
- <h2 class="font-serif">Settings</h2>
325
  <button class="modal-close" onclick="closeModal('settings-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
326
  </div>
327
  <div class="modal-body">
@@ -331,55 +313,55 @@
331
  <div class="change-avatar-overlay"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg></div>
332
  <input type="file" accept="image/*" id="avatar-upload" onchange="changeAvatar()" hidden>
333
  </label>
334
- <p class="settings-avatar-hint">Tap to change photo</p>
335
  </div>
336
- <input type="text" id="settings-name" class="auth-input" placeholder="Full Name">
337
- <input type="text" id="settings-bio" class="auth-input" placeholder="Bio (optional)">
338
  <div class="toggle-row">
339
- <div><p class="toggle-label">Private Account</p><p class="toggle-sub">Only approved followers see your posts</p></div>
340
  <div class="toggle" id="private-toggle" onclick="this.classList.toggle('on')"><div class="toggle-knob"></div></div>
341
  </div>
342
- <button class="btn-primary" onclick="saveSettings()">Save Changes</button>
343
- <button class="btn-ghost" onclick="handleLogout()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>Sign Out</button>
344
  </div>
345
  </div>
346
  </div>
347
 
348
- <!-- NEW CHAT -->
349
  <div class="modal-overlay hidden" id="new-chat-modal" onclick="if(event.target===this)closeModal('new-chat-modal')">
350
- <div class="modal glass-modal">
351
  <div class="modal-header">
352
- <h2 class="font-serif">New Message</h2>
353
  <button class="modal-close" onclick="closeModal('new-chat-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
354
  </div>
355
  <div class="modal-body">
356
- <div class="search-bar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg><input type="text" id="new-chat-search" placeholder="Search users..." oninput="searchNewChat()"></div>
357
  <div id="new-chat-results"></div>
358
  <div class="toggle-row">
359
- <div><p class="toggle-label">Secret Chat</p><p class="toggle-sub">Encrypted appearance, hidden from list</p></div>
360
  <div class="toggle" id="secret-toggle" onclick="this.classList.toggle('on')"><div class="toggle-knob"></div></div>
361
  </div>
362
  </div>
363
  </div>
364
  </div>
365
 
366
- <!-- VERIFY -->
367
  <div class="modal-overlay hidden" id="verify-modal" onclick="if(event.target===this)closeModal('verify-modal')">
368
- <div class="modal glass-modal">
369
  <div class="modal-header">
370
- <h2 class="font-serif">Verify Account</h2>
371
  <button class="modal-close" onclick="closeModal('verify-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
372
  </div>
373
  <div class="modal-body">
374
  <div id="verify-step-1">
375
- <p class="modal-desc">Submit your details to request verification from the creator.</p>
376
- <input type="email" id="verify-email" class="auth-input" placeholder="Email address">
377
- <input type="tel" id="verify-phone" class="auth-input" placeholder="Phone number">
378
- <input type="text" id="verify-realname" class="auth-input" placeholder="Real name">
379
- <button class="btn-primary" onclick="submitVerifyRequest()">Request Verification</button>
380
  </div>
381
  <div id="verify-step-2" class="hidden">
382
- <p class="modal-desc">Enter the 6-digit code sent by the creator.</p>
383
  <div class="code-grid">
384
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,0)" onkeydown="codeBack(event,this,0)">
385
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,1)" onkeydown="codeBack(event,this,1)">
@@ -388,7 +370,7 @@
388
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,4)" onkeydown="codeBack(event,this,4)">
389
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,5)" onkeydown="codeBack(event,this,5)">
390
  </div>
391
- <button class="btn-primary" onclick="submitVerifyCode()">Confirm Code</button>
392
  </div>
393
  </div>
394
  </div>
@@ -396,15 +378,15 @@
396
 
397
  <!-- PIN -->
398
  <div class="modal-overlay hidden" id="pin-modal" onclick="if(event.target===this)closeModal('pin-modal')">
399
- <div class="modal glass-modal small-modal">
400
  <div class="modal-header">
401
- <h2 class="font-serif">Protected 🔒</h2>
402
  <button class="modal-close" onclick="closeModal('pin-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
403
  </div>
404
  <div class="modal-body">
405
- <p class="modal-desc">Enter PIN to unlock this chat</p>
406
  <input type="password" id="pin-input" class="auth-input" placeholder="PIN" maxlength="6" onkeydown="if(event.key==='Enter')submitPin()">
407
- <button class="btn-primary" onclick="submitPin()">Unlock</button>
408
  </div>
409
  </div>
410
  </div>
@@ -415,7 +397,7 @@
415
  <div class="streak-emoji">🔥</div>
416
  <h2 class="streak-title font-serif" id="streak-title"></h2>
417
  <p class="streak-desc" id="streak-desc"></p>
418
- <button class="btn-primary" onclick="closeStreakModal()">Awesome! 🎉</button>
419
  </div>
420
  </div>
421
 
 
8
  <title>Loom</title>
9
  <link rel="icon" type="image/svg+xml" href="logo.svg">
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,600;1,400&display=swap" rel="stylesheet">
12
  <script type="module">
13
  import{initializeApp}from'https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js';
14
  import{getAuth,createUserWithEmailAndPassword,signInWithEmailAndPassword,onAuthStateChanged,signOut,updateProfile}from'https://www.gstatic.com/firebasejs/10.12.0/firebase-auth.js';
 
32
  <div class="auth-card">
33
  <div class="auth-logo">
34
  <img src="logo.svg" class="auth-logo-img" alt="">
35
+ <span class="logo-text font-serif">Loom</span>
36
  </div>
37
+ <p class="auth-tagline">Conectează-te cu lumea ta</p>
 
38
  <div class="auth-tabs">
39
+ <button class="auth-tab active" onclick="switchAuthTab('login')">Autentificare</button>
40
+ <button class="auth-tab" onclick="switchAuthTab('register')">Înregistrare</button>
41
  </div>
 
 
42
  <div id="login-form" class="auth-form">
43
  <div class="input-group">
44
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
45
+ <input type="text" id="li-user" placeholder="Utilizator sau email" autocomplete="username">
46
  </div>
47
  <div class="input-group">
48
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
49
+ <input type="password" id="li-pass" placeholder="Parolă" autocomplete="current-password" onkeydown="if(event.key==='Enter')handleLogin()">
50
  </div>
51
  <button class="btn-primary" onclick="handleLogin()">
52
+ <span id="li-text">Autentificare</span>
53
+ <span id="li-spin" class="btn-spinner hidden"></span>
54
  </button>
55
  </div>
 
 
56
  <div id="register-form" class="auth-form hidden">
57
  <div class="input-group">
58
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
59
+ <input type="text" id="re-name" placeholder="Nume complet">
60
  </div>
61
  <div class="input-group">
62
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
63
+ <input type="text" id="re-user" placeholder="Nume de utilizator">
64
  </div>
65
  <div class="input-group">
66
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
67
  <input type="email" id="re-email" placeholder="Email">
68
  </div>
69
  <div class="input-group">
70
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
71
+ <input type="password" id="re-pass" placeholder="Parolă (min. 6 caractere)" onkeydown="if(event.key==='Enter')handleRegister()">
72
  </div>
73
  <button class="btn-primary" onclick="handleRegister()">
74
+ <span id="re-text">Creează cont</span>
75
+ <span id="re-spin" class="btn-spinner hidden"></span>
76
  </button>
77
  </div>
 
78
  <p class="auth-error hidden" id="auth-error"></p>
79
  </div>
80
  </div>
 
82
  <!-- ═══ APP ═══ -->
83
  <div id="app" class="hidden">
84
 
85
+ <!-- MAIN CONTENT -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  <main class="main-content">
87
 
88
  <!-- FEED -->
89
  <div id="pg-feed" class="page active">
90
+ <div class="page-header">
91
  <h1 class="page-title font-serif">Feed</h1>
92
  <div class="header-actions">
93
+ <button class="icon-btn" onclick="openNewPost()" title="Post nou">
94
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
95
  </button>
96
  </div>
 
104
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
105
  </div>
106
  </div>
107
+ <span class="story-label">Story tău</span>
108
  </div>
109
  </div>
110
  </div>
 
117
  <!-- CHAT -->
118
  <div id="pg-chat" class="page">
119
  <div class="chat-layout" id="chat-layout">
 
120
  <div class="chat-sidebar">
121
  <div class="chat-sidebar-header">
122
+ <h2 class="font-serif">Mesaje</h2>
123
  <button class="icon-btn" onclick="openNewChat()">
124
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
125
  </button>
 
127
  <div class="chat-search-area">
128
  <div class="search-bar">
129
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
130
+ <input type="text" id="chat-search-input" placeholder="Caută..." oninput="filterChats()">
131
  </div>
132
  </div>
133
  <div class="chat-tabs-row">
134
+ <button class="chat-tab active" onclick="switchChatTab('all',this)">Toate</button>
135
  <button class="chat-tab" onclick="switchChatTab('secret',this)">Secret</button>
136
+ <button class="chat-tab" onclick="switchChatTab('hidden',this)">Ascuns</button>
137
  </div>
138
  <div class="chat-list-scroll" id="chat-list"></div>
139
  </div>
 
140
  <div class="chat-main" id="chat-main">
141
  <div class="chat-empty-state">
142
  <div class="chat-empty-icon">
143
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
144
  </div>
145
+ <p>Selectează o conversație</p>
146
+ <span>sau începe una nouă →</span>
147
  </div>
148
  </div>
149
  </div>
150
  </div>
151
 
152
+ <!-- NOTIFICĂRI -->
153
  <div id="pg-notifications" class="page">
154
+ <div class="page-header">
155
+ <h1 class="page-title font-serif">Notificări</h1>
156
+ <button class="icon-btn" onclick="clearAllNotifications()" title="Șterge tot">
157
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
158
  </button>
159
  </div>
160
  <div class="notif-list" id="notif-list"></div>
161
  </div>
162
 
163
+ <!-- EXPLORARE -->
164
  <div id="pg-explore" class="page">
165
+ <div class="page-header">
166
+ <h1 class="page-title font-serif">Explorare</h1>
167
  </div>
168
  <div class="explore-search-wrap">
169
  <div class="search-bar large">
170
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
171
+ <input type="text" id="explore-input" placeholder="Caută utilizatori..." oninput="searchUsers()">
172
  </div>
173
  </div>
174
  <div id="explore-results"></div>
175
  <div class="explore-section">
176
+ <p class="section-label">Toți utilizatorii</p>
177
  <div id="explore-suggested"></div>
178
  </div>
179
  </div>
180
 
181
+ <!-- PROFIL -->
182
  <div id="pg-profile" class="page">
183
  <div id="profile-content"></div>
184
  </div>
185
 
186
  </main>
187
 
188
+ <!-- NAVBAR JOS -->
189
+ <nav class="bottom-nav">
190
+ <div class="nav-item active" data-page="feed" onclick="navigateTo('feed')">
191
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
192
+ <span>Feed</span>
193
+ </div>
194
+ <div class="nav-item" data-page="chat" onclick="navigateTo('chat')">
195
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
196
+ <span>Mesaje</span>
197
+ <div class="nav-badge hidden" id="msg-badge">0</div>
198
  </div>
199
+ <div class="nav-item" data-page="notifications" onclick="navigateTo('notifications')">
200
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
201
+ <span>Notificări</span>
202
+ <div class="nav-badge hidden" id="notif-badge">0</div>
203
+ </div>
204
+ <div class="nav-item" data-page="explore" onclick="navigateTo('explore')">
205
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
206
+ <span>Explorare</span>
207
+ </div>
208
+ <div class="nav-item" data-page="profile" onclick="navigateTo('profile')">
209
+ <div class="nav-av-wrap">
210
+ <div class="avatar xs" id="sb-avatar"></div>
211
+ </div>
212
+ <span>Profil</span>
213
  </div>
214
+ </nav>
215
 
216
  </div><!-- /app -->
217
 
218
  <!-- ═══ MODALS ═══ -->
219
 
220
+ <!-- POST NOU -->
221
  <div class="modal-overlay hidden" id="new-post-modal" onclick="if(event.target===this)closeModal('new-post-modal')">
222
+ <div class="modal">
223
  <div class="modal-header">
224
+ <h2 class="font-serif">Post Nou</h2>
225
  <button class="modal-close" onclick="closeModal('new-post-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
226
  </div>
227
  <div class="modal-body">
228
  <div class="composer-row">
229
  <div class="avatar sm" id="composer-av"></div>
230
+ <textarea id="post-text-input" class="post-textarea" placeholder="Ce gândești?" rows="3"></textarea>
231
  </div>
232
  <div id="post-img-preview" class="hidden"></div>
233
  <div class="composer-toolbar">
234
  <label class="toolbar-btn">
235
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
236
+ Foto
237
  <input type="file" accept="image/*" id="post-img-input" onchange="previewPostImg()" hidden>
238
  </label>
239
  </div>
240
+ <button class="btn-primary" onclick="submitPost()">Publică ✦</button>
241
  </div>
242
  </div>
243
  </div>
244
 
245
+ <!-- ADAUGĂ STORY -->
246
  <div class="modal-overlay hidden" id="add-story-modal" onclick="if(event.target===this)closeModal('add-story-modal')">
247
+ <div class="modal">
248
  <div class="modal-header">
249
+ <h2 class="font-serif">Adaugă Story</h2>
250
  <button class="modal-close" onclick="closeModal('add-story-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
251
  </div>
252
  <div class="modal-body">
253
  <label class="upload-area" id="story-upload-label">
254
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
255
+ <span>Apasă pentru a selecta o poză</span>
256
  <input type="file" accept="image/*" id="story-img-input" onchange="previewStory()" hidden>
257
  </label>
258
  <div id="story-preview" class="hidden story-preview-wrap"><img id="story-preview-img" alt=""></div>
259
+ <input type="text" id="story-text-input" class="auth-input" placeholder="Adaugă text (opțional)">
260
+ <button class="btn-primary" onclick="submitStory()">Distribuie Story</button>
261
  </div>
262
  </div>
263
  </div>
264
 
265
+ <!-- VIZUALIZATOR STORY -->
266
  <div class="story-viewer hidden" id="story-viewer">
267
  <div class="story-bg" id="sv-bg"></div>
268
  <div class="story-progress-bar"><div class="story-progress" id="sv-prog"></div></div>
 
278
  <div class="story-nav-l" onclick="prevStory()"></div>
279
  <div class="story-nav-r" onclick="nextStory()"></div>
280
  <div class="story-viewers hidden" id="sv-viewers">
281
+ <p class="sv-viewers-label">Vizualizatori</p>
282
  <div id="sv-viewers-list"></div>
283
  </div>
284
  </div>
285
 
286
+ <!-- COMENTARII -->
287
  <div class="modal-overlay hidden" id="comments-modal" onclick="if(event.target===this)closeModal('comments-modal')">
288
+ <div class="modal tall-modal">
289
  <div class="modal-header">
290
+ <h2 class="font-serif">Comentarii</h2>
291
  <button class="modal-close" onclick="closeModal('comments-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
292
  </div>
293
  <div class="comments-list" id="comments-list"></div>
294
  <div class="comment-compose">
295
  <div class="avatar xs" id="comment-avatar"></div>
296
+ <input type="text" id="comment-input" class="comment-field" placeholder="Adaugă un comentariu..." onkeydown="if(event.key==='Enter')submitComment()">
297
  <button class="send-icon-btn" onclick="submitComment()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg></button>
298
  </div>
299
  </div>
300
  </div>
301
 
302
+ <!-- SETĂRI -->
303
  <div class="modal-overlay hidden" id="settings-modal" onclick="if(event.target===this)closeModal('settings-modal')">
304
+ <div class="modal">
305
  <div class="modal-header">
306
+ <h2 class="font-serif">Setări</h2>
307
  <button class="modal-close" onclick="closeModal('settings-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
308
  </div>
309
  <div class="modal-body">
 
313
  <div class="change-avatar-overlay"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg></div>
314
  <input type="file" accept="image/*" id="avatar-upload" onchange="changeAvatar()" hidden>
315
  </label>
316
+ <p class="settings-avatar-hint">Apasă pentru a schimba poza</p>
317
  </div>
318
+ <input type="text" id="settings-name" class="auth-input" placeholder="Nume complet">
319
+ <input type="text" id="settings-bio" class="auth-input" placeholder="Bio (opțional)">
320
  <div class="toggle-row">
321
+ <div><p class="toggle-label">Cont privat</p><p class="toggle-sub">Doar urmăritorii aprobați îți văd postările</p></div>
322
  <div class="toggle" id="private-toggle" onclick="this.classList.toggle('on')"><div class="toggle-knob"></div></div>
323
  </div>
324
+ <button class="btn-primary" onclick="saveSettings()">Salvează</button>
325
+ <button class="btn-ghost" onclick="handleLogout()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>Deconectare</button>
326
  </div>
327
  </div>
328
  </div>
329
 
330
+ <!-- CHAT NOU -->
331
  <div class="modal-overlay hidden" id="new-chat-modal" onclick="if(event.target===this)closeModal('new-chat-modal')">
332
+ <div class="modal">
333
  <div class="modal-header">
334
+ <h2 class="font-serif">Mesaj Nou</h2>
335
  <button class="modal-close" onclick="closeModal('new-chat-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
336
  </div>
337
  <div class="modal-body">
338
+ <div class="search-bar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg><input type="text" id="new-chat-search" placeholder="Caută utilizatori..." oninput="searchNewChat()"></div>
339
  <div id="new-chat-results"></div>
340
  <div class="toggle-row">
341
+ <div><p class="toggle-label">Chat Secret</p><p class="toggle-sub">Apare criptat, ascuns din listă</p></div>
342
  <div class="toggle" id="secret-toggle" onclick="this.classList.toggle('on')"><div class="toggle-knob"></div></div>
343
  </div>
344
  </div>
345
  </div>
346
  </div>
347
 
348
+ <!-- VERIFICARE -->
349
  <div class="modal-overlay hidden" id="verify-modal" onclick="if(event.target===this)closeModal('verify-modal')">
350
+ <div class="modal">
351
  <div class="modal-header">
352
+ <h2 class="font-serif">Verifică Contul</h2>
353
  <button class="modal-close" onclick="closeModal('verify-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
354
  </div>
355
  <div class="modal-body">
356
  <div id="verify-step-1">
357
+ <p class="modal-desc">Trimite detaliile tale pentru a solicita verificarea de la creator.</p>
358
+ <input type="email" id="verify-email" class="auth-input" placeholder="Adresă de email">
359
+ <input type="tel" id="verify-phone" class="auth-input" placeholder="Număr de telefon">
360
+ <input type="text" id="verify-realname" class="auth-input" placeholder="Nume real">
361
+ <button class="btn-primary" onclick="submitVerifyRequest()">Solicită Verificarea</button>
362
  </div>
363
  <div id="verify-step-2" class="hidden">
364
+ <p class="modal-desc">Introdu codul de 6 cifre trimis de creator.</p>
365
  <div class="code-grid">
366
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,0)" onkeydown="codeBack(event,this,0)">
367
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,1)" onkeydown="codeBack(event,this,1)">
 
370
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,4)" onkeydown="codeBack(event,this,4)">
371
  <input type="text" maxlength="1" class="code-box" oninput="codeNext(this,5)" onkeydown="codeBack(event,this,5)">
372
  </div>
373
+ <button class="btn-primary" onclick="submitVerifyCode()">Confirmă Codul</button>
374
  </div>
375
  </div>
376
  </div>
 
378
 
379
  <!-- PIN -->
380
  <div class="modal-overlay hidden" id="pin-modal" onclick="if(event.target===this)closeModal('pin-modal')">
381
+ <div class="modal small-modal">
382
  <div class="modal-header">
383
+ <h2 class="font-serif">Protejat 🔒</h2>
384
  <button class="modal-close" onclick="closeModal('pin-modal')"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
385
  </div>
386
  <div class="modal-body">
387
+ <p class="modal-desc">Introdu PIN-ul pentru a debloca acest chat</p>
388
  <input type="password" id="pin-input" class="auth-input" placeholder="PIN" maxlength="6" onkeydown="if(event.key==='Enter')submitPin()">
389
+ <button class="btn-primary" onclick="submitPin()">Deblochează</button>
390
  </div>
391
  </div>
392
  </div>
 
397
  <div class="streak-emoji">🔥</div>
398
  <h2 class="streak-title font-serif" id="streak-title"></h2>
399
  <p class="streak-desc" id="streak-desc"></p>
400
+ <button class="btn-primary" onclick="closeStreakModal()">Super! 🎉</button>
401
  </div>
402
  </div>
403
 
style.css CHANGED
@@ -1,509 +1,502 @@
1
- @import url('https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,600;1,400&display=swap');
2
 
3
  *,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
4
 
5
  :root{
6
- /* Dark theme: black bg, white UI */
7
- --black:#000;
8
- --white:#fff;
9
  --bg:#0a0a0a;
10
- --surface:#111;
11
- --surface2:#1a1a1a;
12
- --surface3:#222;
13
- --border:rgba(255,255,255,.08);
14
- --border2:rgba(255,255,255,.14);
15
- --text:#fff;
16
- --text2:rgba(255,255,255,.85);
17
- --text3:rgba(255,255,255,.45);
18
- --text4:rgba(255,255,255,.25);
19
- --r:14px;--r-sm:10px;--r-xs:7px;
20
- --shadow:0 2px 14px rgba(0,0,0,.5);
21
- --shadow-md:0 4px 28px rgba(0,0,0,.7);
22
- --ease:cubic-bezier(.4,0,.2,1);--t:.2s var(--ease);
23
- --font:'Geist',system-ui,sans-serif;
 
 
 
24
  --serif:'Playfair Display',Georgia,serif;
25
- --nb:58px; /* navbar height */
26
  }
27
 
28
- html,body{height:100%;overflow:hidden;background:var(--bg);color:var(--text);font-family:var(--font);font-size:13px;-webkit-font-smoothing:antialiased;}
29
  .font-serif{font-family:var(--serif);}
30
  .hidden{display:none!important;}
31
- ::-webkit-scrollbar{width:3px;height:3px;}
32
- ::-webkit-scrollbar-thumb{background:var(--surface3);border-radius:3px;}
33
- ::-webkit-scrollbar-track{background:transparent;}
34
 
35
  /* ── AUTH ── */
36
- #auth-screen{position:fixed;inset:0;z-index:999;display:flex;align-items:center;justify-content:center;background:var(--bg);padding:20px;animation:fadeIn .3s;}
 
 
 
 
 
37
  .auth-card{width:100%;max-width:360px;display:flex;flex-direction:column;animation:slideUp .4s var(--ease);}
38
- .auth-logo{display:flex;align-items:center;gap:10px;margin-bottom:6px;}
39
- .auth-logo-img{width:28px;height:28px;color:var(--white);}
40
- .logo-text{font-family:var(--serif);font-size:26px;letter-spacing:-.5px;color:var(--white);}
41
- .auth-tagline{font-size:12px;color:var(--text3);margin-bottom:28px;}
42
- .auth-tabs{display:flex;background:var(--surface2);border-radius:var(--r-sm);padding:3px;margin-bottom:20px;}
43
- .auth-tab{flex:1;padding:8px;border-radius:8px;cursor:pointer;font-size:12px;font-weight:500;color:var(--text3);border:none;background:none;font-family:var(--font);transition:var(--t);}
44
- .auth-tab.active{background:var(--surface3);color:var(--white);}
45
  .auth-form{display:flex;flex-direction:column;gap:10px;}
46
- .input-group{display:flex;align-items:center;gap:10px;background:var(--surface2);border:1.5px solid transparent;border-radius:var(--r-sm);padding:11px 14px;transition:var(--t);}
47
- .input-group:focus-within{border-color:var(--white);background:var(--surface3);}
48
- .input-group svg{width:15px;height:15px;color:var(--text3);flex-shrink:0;}
49
- .input-group input{flex:1;background:none;border:none;outline:none;color:var(--white);font-family:var(--font);font-size:13px;}
50
- .input-group input::placeholder{color:var(--text4);}
51
- input.auth-input{background:var(--surface2);border:1.5px solid transparent;border-radius:var(--r-sm);padding:11px 14px;font-family:var(--font);font-size:13px;color:var(--white);outline:none;width:100%;display:block;transition:var(--t);}
52
- input.auth-input:focus{border-color:var(--white);background:var(--surface3);}
53
- input.auth-input::placeholder{color:var(--text4);}
54
- .btn-primary{background:var(--white);color:var(--black);border:none;border-radius:var(--r-sm);padding:13px;font-family:var(--font);font-size:13px;font-weight:600;cursor:pointer;transition:var(--t);width:100%;display:flex;align-items:center;justify-content:center;gap:6px;margin-top:4px;}
55
- .btn-primary:hover{opacity:.86;transform:translateY(-1px);}
56
  .btn-primary:active{transform:translateY(0);}
57
- .btn-ghost{background:transparent;color:var(--text3);border:1.5px solid var(--border2);border-radius:var(--r-sm);padding:11px;font-family:var(--font);font-size:12px;font-weight:500;cursor:pointer;transition:var(--t);width:100%;display:flex;align-items:center;justify-content:center;gap:6px;}
58
- .btn-ghost:hover{color:var(--white);border-color:var(--white);}
59
  .btn-ghost svg{width:13px;height:13px;}
60
- .btn-spinner{width:13px;height:13px;border:2px solid rgba(0,0,0,.25);border-top-color:var(--black);border-radius:50%;animation:spin .7s linear infinite;}
61
- .auth-error{color:#ff6b6b;font-size:11px;text-align:center;margin-top:4px;}
62
-
63
- /* ── APP SHELL — bottom navbar layout ── */
64
- #app{height:100vh;display:flex;flex-direction:column;overflow:hidden;background:var(--bg);animation:fadeIn .25s;}
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  /* ── BOTTOM NAVBAR ── */
67
- .sidebar{
68
- height:var(--nb);min-height:var(--nb);
69
- width:100%;flex-shrink:0;
70
  background:rgba(10,10,10,.97);
71
- border-top:1px solid var(--border);
72
- display:flex;flex-direction:row;align-items:center;
73
- justify-content:space-around;
74
- padding:0 8px;
75
- order:2; /* Push to bottom */
76
- backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
77
- position:relative;z-index:50;
78
- }
79
- /* Hide old sidebar-specific elements */
80
- .sidebar-logo{display:none!important;}
81
- .sidebar-logo-img{display:none!important;}
82
- .sidebar-bottom{display:none!important;}
83
- .sidebar-nav{
84
- display:flex;flex-direction:row;align-items:center;
85
- justify-content:space-around;flex:1;padding:0;gap:0;
86
  }
87
  .nav-item{
88
- display:flex;flex-direction:column;align-items:center;justify-content:center;
89
- padding:8px 16px;cursor:pointer;border-radius:12px;
90
- color:var(--text3);transition:var(--t);position:relative;user-select:none;
91
- flex:1;gap:3px;min-width:0;
 
 
 
 
 
 
 
 
 
92
  }
93
- .nav-item svg{width:22px;height:22px;stroke-width:1.8;}
94
- .nav-item:hover{color:var(--text2);}
95
- .nav-item.active{color:var(--white);}
 
96
  .nav-item.active svg{stroke-width:2.2;}
97
  .nav-badge{
98
- position:absolute;top:4px;right:calc(50% - 22px);
99
- background:var(--white);color:var(--black);
100
  font-size:9px;font-weight:700;border-radius:20px;
101
- padding:1px 5px;min-width:15px;text-align:center;line-height:1.4;
102
- }
103
- /* Profile button in bottom nav */
104
- .sidebar-user{
105
- display:flex;flex-direction:column;align-items:center;justify-content:center;
106
- padding:8px 16px;cursor:pointer;border-radius:12px;
107
- transition:var(--t);flex:1;gap:3px;color:var(--text3);
108
- }
109
- .sidebar-user:hover{color:var(--text2);}
110
-
111
- /* ── AVATAR ── */
112
- .avatar{
113
- border-radius:50%;background:var(--surface2);
114
- display:flex;align-items:center;justify-content:center;
115
- font-weight:600;overflow:hidden;flex-shrink:0;
116
- color:rgba(255,255,255,.6);
117
- border:1.5px solid var(--border2);
118
- background-size:cover;background-position:center;
119
  }
120
- .avatar.xs{width:26px;height:26px;font-size:9px;}
121
- .avatar.sm{width:34px;height:34px;font-size:12px;}
122
- .avatar.md{width:40px;height:40px;font-size:14px;}
123
- .avatar.lg{width:66px;height:66px;font-size:22px;}
124
- .avatar.xl{width:84px;height:84px;font-size:28px;}
125
- .avatar-wrap{position:relative;flex-shrink:0;}
126
- .avatar-wrap.has-story::before{content:'';position:absolute;inset:-2px;border-radius:50%;border:2px solid var(--white);pointer-events:none;}
127
 
128
- /* ── MAIN CONTENT AREA (above bottom nav) ── */
129
- .main-content{
130
- flex:1;display:flex;flex-direction:column;
131
- overflow:hidden;min-width:0;
132
- order:1; /* Main area on top */
133
- }
134
- .page{display:none;flex:1;flex-direction:column;overflow-y:auto;overflow-x:hidden;}
135
  .page.active{display:flex;animation:pageFadeIn .2s var(--ease);}
136
 
137
  /* PAGE HEADER */
138
  .page-header{
139
- padding:14px 18px 12px;border-bottom:1px solid var(--border);
 
140
  display:flex;align-items:center;justify-content:space-between;
141
  flex-shrink:0;position:sticky;top:0;z-index:20;
142
- background:rgba(10,10,10,.94);backdrop-filter:blur(12px);
 
143
  }
144
- .page-title{font-size:19px;letter-spacing:-.4px;font-weight:700;color:var(--white);}
145
  .header-actions{display:flex;gap:6px;}
146
  .icon-btn{
147
- width:32px;height:32px;border-radius:50%;
148
- background:var(--surface2);border:1px solid var(--border);
149
  display:flex;align-items:center;justify-content:center;
150
- cursor:pointer;transition:var(--t);color:var(--text3);
151
  }
152
- .icon-btn:hover{border-color:var(--white);color:var(--white);}
153
  .icon-btn svg{width:14px;height:14px;}
154
 
155
- /* RIGHT PANEL hidden on small, shown on wide */
156
- .right-panel{display:none;}
157
- @media(min-width:1100px){
158
- #app{flex-direction:row;}
159
- .sidebar{
160
- height:100%;width:64px;min-height:unset;
161
- flex-direction:column;justify-content:flex-start;
162
- border-top:none;border-right:1px solid var(--border);
163
- padding:0;order:0;
164
- }
165
- .sidebar-nav{flex-direction:column;justify-content:flex-start;padding:8px 6px;flex:1;gap:2px;}
166
- .nav-item{flex-direction:row;padding:12px 0;justify-content:center;flex:none;width:100%;}
167
- .sidebar-bottom{display:flex!important;padding:6px 6px 14px;border-top:1px solid var(--border);}
168
- .sidebar-user{flex-direction:row;justify-content:center;padding:8px 0;flex:none;width:100%;}
169
- .main-content{order:1;}
170
- .right-panel{display:flex;width:220px;min-width:220px;border-left:1px solid var(--border);padding:16px 14px;overflow-y:auto;flex-direction:column;gap:20px;flex-shrink:0;background:var(--surface);}
171
  }
172
-
173
- .section-label{font-size:10px;color:var(--text3);font-weight:700;letter-spacing:.9px;text-transform:uppercase;margin-bottom:12px;}
174
- .sug-item{display:flex;align-items:center;gap:9px;margin-bottom:12px;}
175
- .sug-info{flex:1;min-width:0;}
176
- .sug-name{font-size:12px;font-weight:600;display:flex;align-items:center;gap:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
177
- .sug-handle{font-size:11px;color:var(--text3);}
178
- .follow-btn{font-size:11px;font-weight:600;background:var(--white);color:var(--black);border:none;border-radius:20px;padding:5px 12px;cursor:pointer;font-family:var(--font);transition:var(--t);white-space:nowrap;}
179
- .follow-btn.following{background:var(--surface3);color:var(--text2);border:1px solid var(--border2);}
180
- .trending-item{display:flex;justify-content:space-between;padding:8px 10px;border-radius:var(--r-xs);background:var(--surface2);margin-bottom:5px;cursor:pointer;transition:var(--t);}
181
- .trending-item:hover{background:var(--surface3);}
182
- .trending-name{font-size:12px;font-weight:500;}
183
- .trending-count{font-size:11px;color:var(--text3);}
184
 
185
  /* ── STORIES ── */
186
- .stories-section{border-bottom:1px solid var(--border);padding:12px 0;flex-shrink:0;}
187
- .stories-scroll{display:flex;gap:12px;padding:0 18px;overflow-x:auto;}
188
  .stories-scroll::-webkit-scrollbar{display:none;}
189
  .story-item{display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;flex-shrink:0;transition:transform .15s;}
190
  .story-item:hover{transform:translateY(-2px);}
191
- .story-ring{width:54px;height:54px;border-radius:50%;border:2px solid var(--white);padding:2px;background:var(--bg);position:relative;}
192
  .story-ring .avatar{width:100%;height:100%;border:none;}
193
- .add-ring{border-color:var(--border2);border-style:dashed;}
194
- .add-story-icon{position:absolute;bottom:-1px;right:-1px;width:17px;height:17px;background:var(--white);border-radius:50%;display:flex;align-items:center;justify-content:center;border:2px solid var(--bg);}
195
- .add-story-icon svg{width:8px;height:8px;color:var(--black);}
196
- .story-label{font-size:10px;color:var(--text3);white-space:nowrap;max-width:56px;overflow:hidden;text-overflow:ellipsis;text-align:center;}
197
 
198
  /* ── POSTS ── */
199
- .skeleton-post{height:96px;margin:12px 18px;background:linear-gradient(90deg,var(--surface) 25%,var(--surface2) 50%,var(--surface) 75%);background-size:200% 100%;border-radius:var(--r);animation:shimmer 1.5s infinite;}
200
- .post{border-bottom:1px solid var(--border);padding:14px 18px;transition:background .12s;}
201
  .post.new-post{animation:postFadeIn .22s var(--ease);}
202
- .post:hover{background:rgba(255,255,255,.02);}
203
- .post-header{display:flex;align-items:center;gap:10px;margin-bottom:10px;}
204
  .post-user{flex:1;cursor:pointer;}
205
- .post-name{font-size:13px;font-weight:600;display:inline-flex;align-items:center;gap:4px;}
206
- .post-time{font-size:11px;color:var(--text3);margin-top:2px;}
207
- .post-menu-btn{color:var(--text3);cursor:pointer;padding:5px;border-radius:50%;transition:var(--t);}
208
- .post-menu-btn:hover{color:var(--white);background:var(--surface2);}
209
  .post-menu-btn svg{width:14px;height:14px;display:block;}
210
- .post-text{font-size:13px;line-height:1.6;color:var(--text2);margin-bottom:10px;}
211
- .post-img{width:100%;border-radius:var(--r);overflow:hidden;margin-bottom:10px;border:1px solid var(--border);}
212
  .post-img img{width:100%;display:block;max-height:360px;object-fit:cover;cursor:zoom-in;}
213
- .post-actions{display:flex;gap:18px;padding-top:3px;}
214
- .post-action{display:flex;align-items:center;gap:5px;color:var(--text3);cursor:pointer;font-size:12px;transition:var(--t);user-select:none;}
215
- .post-action:hover{color:var(--white);}
216
- .post-action.liked{color:var(--white);}
217
  .post-action svg{width:15px;height:15px;}
218
- .v-badge{width:13px;height:13px;flex-shrink:0;color:var(--white);}
219
- .empty-state-center{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:60px 20px;color:var(--text4);}
220
- .empty-state-center svg{width:40px;height:40px;}
221
- .empty-state-center p{font-size:13px;color:var(--text3);}
222
 
223
- /* ── CHAT ── */
224
  .chat-layout{display:flex;flex:1;overflow:hidden;position:relative;background:var(--bg);}
225
- .chat-sidebar{width:100%;min-width:unset;flex-shrink:0;border-right:none;display:flex;flex-direction:column;overflow:hidden;background:var(--bg);transition:transform .28s var(--ease);position:absolute;inset:0;z-index:5;}
226
- .chat-main{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;background:var(--bg);transition:transform .28s var(--ease);position:absolute;inset:0;transform:translateX(110%);}
 
 
 
 
 
 
 
 
227
  .chat-layout.chat-open .chat-sidebar{transform:translateX(-110%);}
228
  .chat-layout.chat-open .chat-main{transform:translateX(0);}
229
- .chat-back{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;background:var(--surface2);border:1px solid var(--border);cursor:pointer;color:var(--text3);flex-shrink:0;}
230
- .chat-back svg{width:14px;height:14px;}
231
- @media(min-width:700px){
232
- .chat-sidebar{position:relative;width:280px;min-width:280px;border-right:1px solid var(--border);z-index:auto;transform:none!important;}
233
  .chat-main{position:relative;transform:none!important;}
234
- .chat-back{display:none;}
235
  .chat-layout.chat-open .chat-sidebar{transform:none!important;}
236
  }
237
-
238
- .chat-sidebar-header{padding:14px 14px 10px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;}
239
- .chat-sidebar-header h2{font-family:var(--serif);font-size:18px;letter-spacing:-.3px;color:var(--white);}
240
- .chat-search-area{padding:8px 12px;border-bottom:1px solid var(--border);}
241
- .search-bar{background:var(--surface2);border:1px solid transparent;border-radius:20px;padding:8px 12px;display:flex;align-items:center;gap:7px;transition:var(--t);}
242
- .search-bar:focus-within{border-color:var(--border2);background:var(--surface3);}
243
- .search-bar.large{border-radius:var(--r);padding:11px 15px;}
244
- .search-bar svg{width:13px;height:13px;color:var(--text3);flex-shrink:0;}
245
- .search-bar input{background:none;border:none;outline:none;color:var(--white);font-family:var(--font);font-size:12px;flex:1;min-width:0;}
246
- .search-bar input::placeholder{color:var(--text4);}
247
- .chat-tabs-row{display:flex;padding:6px 12px 0;border-bottom:1px solid var(--border);}
248
- .chat-tab{flex:1;padding:8px 4px;text-align:center;cursor:pointer;font-size:11px;font-weight:500;color:var(--text3);border:none;background:none;font-family:var(--font);border-bottom:2px solid transparent;margin-bottom:-1px;transition:var(--t);}
249
- .chat-tab.active{color:var(--white);border-bottom-color:var(--white);}
 
250
  .chat-list-scroll{flex:1;overflow-y:auto;}
251
 
252
- /* Conv rows */
253
- .conv-item{display:flex;align-items:center;gap:10px;padding:12px 14px;cursor:pointer;transition:background .12s;border-bottom:1px solid var(--border);}
254
  .conv-item:hover{background:rgba(255,255,255,.03);}
255
- .conv-item.active{background:rgba(255,255,255,.06);}
256
  .conv-item-body{flex:1;min-width:0;}
257
  .conv-top{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:3px;}
258
- .conv-name{font-size:13px;font-weight:600;display:flex;align-items:center;gap:3px;}
259
- .conv-time{font-size:10px;color:var(--text3);}
260
- .conv-preview{font-size:12px;color:var(--text3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
261
- .conv-right{display:flex;flex-direction:column;align-items:flex-end;gap:3px;}
262
- .conv-unread-dot{width:9px;height:9px;background:var(--white);border-radius:50%;}
263
  .conv-streak{font-size:10px;}
264
 
265
- /* Chat window */
266
- .chat-empty-state{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;color:var(--text3);}
267
- .chat-empty-state p{font-size:13px;}
268
- .chat-empty-state span{font-size:11px;color:var(--text4);}
269
- .chat-empty-icon svg{width:44px;height:44px;color:var(--text4);}
270
  .chat-window{flex:1;display:flex;flex-direction:column;overflow:hidden;}
271
- .chat-win-header{display:flex;align-items:center;gap:10px;padding:12px 16px;border-bottom:1px solid var(--border);flex-shrink:0;background:rgba(10,10,10,.95);backdrop-filter:blur(10px);}
272
- .chat-win-user{flex:1;min-width:0;}
273
- .chat-win-name{font-size:14px;font-weight:600;display:flex;align-items:center;gap:5px;}
274
- .chat-win-sub{font-size:11px;color:var(--text3);margin-top:2px;}
275
  .chat-win-actions{display:flex;gap:5px;}
276
 
277
- /* Messages area */
278
- .messages-area{flex:1;overflow-y:auto;padding:16px 14px 8px;display:flex;flex-direction:column;gap:0;scroll-behavior:smooth;background:var(--bg);}
279
- .date-sep{text-align:center;font-size:10px;color:var(--text3);margin:12px 0 8px;letter-spacing:.5px;}
 
 
 
 
 
 
280
 
281
- /* iMessage bubbles */
282
- .msg-group{display:flex;flex-direction:column;margin-bottom:10px;}
283
  .msg-group.own{align-items:flex-end;}
284
- .msg-group.other{align-items:flex-start;padding-left:40px;} /* Space for avatar */
285
- .msg-row{display:flex;align-items:flex-end;gap:6px;}
286
  .msg-row.own{flex-direction:row-reverse;}
287
- .msg-row.other{position:relative;}
288
- /* Avatar shown only on first message of group */
289
- .msg-group.other .msg-row:last-child .msg-avatar{display:flex;}
290
- .msg-avatar{position:absolute;left:-38px;bottom:0;display:none;}
291
 
292
- .bubble{max-width:75%;padding:10px 14px;font-size:13px;line-height:1.52;word-break:break-word;animation:bubblePop .18s var(--ease);}
293
- .bubble.own{background:var(--white);color:var(--black);border-radius:20px 20px 4px 20px;}
294
- .bubble.other{background:var(--surface2);color:var(--white);border-radius:20px 20px 20px 4px;}
295
  .bubble p{margin:0;white-space:pre-wrap;word-break:break-word;}
296
  .bubble img{max-width:200px;border-radius:12px;display:block;cursor:zoom-in;}
297
- .bubble-reply{background:rgba(255,255,255,.07);border-left:2.5px solid rgba(255,255,255,.25);border-radius:4px;padding:4px 8px;margin-bottom:6px;font-size:11px;opacity:.7;cursor:pointer;}
298
- .bubble.own .bubble-reply{background:rgba(0,0,0,.08);border-left-color:rgba(0,0,0,.2);}
299
- .voice-bubble{display:flex;align-items:center;gap:8px;min-width:140px;}
300
- .voice-play{width:28px;height:28px;border-radius:50%;flex-shrink:0;cursor:pointer;background:rgba(255,255,255,.1);display:flex;align-items:center;justify-content:center;}
301
- .bubble.own .voice-play{background:rgba(0,0,0,.1);}
302
- .voice-play svg{width:10px;height:10px;}
303
- .voice-waveform{flex:1;display:flex;align-items:center;gap:2px;height:22px;}
304
- .wv{width:2px;border-radius:2px;background:currentColor;opacity:.35;}
305
- .voice-dur{font-size:10px;opacity:.6;white-space:nowrap;}
306
- .reactions-row{display:flex;gap:3px;flex-wrap:wrap;margin-top:4px;}
307
- .reaction-pill{background:var(--surface2);border:1.5px solid var(--border2);border-radius:12px;padding:3px 8px;font-size:11px;cursor:pointer;transition:var(--t);}
308
- .reaction-pill:hover{border-color:var(--white);}
309
  .msg-group.own .reactions-row{justify-content:flex-end;}
310
- .msg-meta{font-size:9px;color:var(--text4);margin-top:3px;padding:0 4px;}
311
  .msg-group.own .msg-meta{text-align:right;}
312
 
313
- /* INPUT ZONE */
314
- .chat-input-zone{padding:10px 14px 14px;border-top:1px solid var(--border);flex-shrink:0;background:rgba(10,10,10,.97);backdrop-filter:blur(10px);}
315
- .reply-bar{display:flex;align-items:center;gap:7px;padding:6px 10px;margin-bottom:8px;background:var(--surface2);border-radius:var(--r-xs);border-left:2.5px solid var(--white);}
316
- .reply-bar-text{flex:1;font-size:11px;color:var(--text3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
317
- .reply-cancel{cursor:pointer;color:var(--text3);}
318
  .reply-cancel svg{width:11px;height:11px;display:block;}
319
- .input-row{display:flex;align-items:flex-end;gap:8px;}
320
- .input-wrap{flex:1;display:flex;align-items:flex-end;gap:6px;background:var(--surface2);border:1.5px solid transparent;border-radius:24px;padding:9px 14px;transition:var(--t);min-width:0;}
321
- .input-wrap:focus-within{border-color:rgba(255,255,255,.3);background:var(--surface3);}
322
- .chat-textarea{flex:1;background:none;border:none;outline:none;color:var(--white);font-family:var(--font);font-size:13px;resize:none;max-height:80px;line-height:1.45;min-width:0;}
323
- .chat-textarea::placeholder{color:var(--text4);}
324
- .input-action{color:var(--text3);cursor:pointer;transition:var(--t);display:flex;align-items:center;flex-shrink:0;padding:2px;}
325
- .input-action:hover{color:var(--white);}
326
  .input-action svg{width:17px;height:17px;}
327
- .gif-label{font-size:10px;font-weight:800;letter-spacing:.3px;}
328
- .send-btn{width:40px;height:40px;border-radius:50%;flex-shrink:0;background:var(--white);display:flex;align-items:center;justify-content:center;cursor:pointer;border:none;transition:var(--t);}
329
  .send-btn:hover{opacity:.82;transform:scale(1.05);}
330
- .send-btn:active{transform:scale(.95);}
331
- .send-btn svg{width:15px;height:15px;color:var(--black);margin-left:2px;}
332
- .emoji-picker{position:fixed;z-index:9000;background:var(--surface);border:1.5px solid var(--border2);border-radius:var(--r);padding:10px;display:flex;flex-wrap:wrap;gap:3px;max-width:260px;box-shadow:var(--shadow-md);animation:fadeInUp .15s;}
333
- .emoji-opt{font-size:21px;cursor:pointer;padding:4px;border-radius:5px;transition:transform .1s;}
334
  .emoji-opt:hover{transform:scale(1.35);}
335
 
336
- /* NOTIFS */
337
  .notif-list{flex:1;overflow-y:auto;}
338
- .notif-item{display:flex;align-items:center;gap:11px;padding:12px 18px;border-bottom:1px solid var(--border);cursor:pointer;transition:var(--t);}
339
  .notif-item:hover{background:rgba(255,255,255,.02);}
340
- .notif-icon{width:32px;height:32px;border-radius:50%;background:var(--surface2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:14px;}
341
- .notif-text{flex:1;font-size:12px;line-height:1.5;}
342
- .notif-time{font-size:10px;color:var(--text3);flex-shrink:0;}
343
 
344
- /* EXPLORE */
345
- .explore-search-wrap{padding:12px 18px;border-bottom:1px solid var(--border);}
346
  .explore-section{padding:16px 18px;}
347
- .explore-user-item{display:flex;align-items:center;gap:11px;padding:10px 18px;border-bottom:1px solid var(--border);cursor:pointer;transition:var(--t);}
348
  .explore-user-item:hover{background:rgba(255,255,255,.02);}
349
  .exu-info{flex:1;min-width:0;}
350
- .exu-name{font-size:12px;font-weight:600;display:flex;align-items:center;gap:3px;}
351
- .exu-handle{font-size:11px;color:var(--text3);}
352
- .exu-count{font-size:10px;color:var(--text4);}
353
-
354
- /* PROFILE */
355
- .profile-header{padding:22px 18px 16px;border-bottom:1px solid var(--border);}
 
 
 
 
 
356
  .profile-top{display:flex;gap:18px;align-items:flex-start;}
357
  .profile-info{flex:1;min-width:0;}
358
- .profile-name{font-family:var(--serif);font-size:21px;letter-spacing:-.3px;display:flex;align-items:center;gap:6px;color:var(--white);}
359
- .profile-handle{font-size:12px;color:var(--text3);margin:3px 0 8px;}
360
- .profile-bio{font-size:12px;line-height:1.6;color:var(--text2);margin-bottom:13px;}
361
- .profile-stats{display:flex;gap:22px;}
362
  .pstat{text-align:center;cursor:pointer;}
363
- .pstat-num{font-size:16px;font-weight:700;letter-spacing:-.2px;}
364
- .pstat-label{font-size:10px;color:var(--text3);}
365
- .profile-actions{display:flex;gap:8px;margin-top:14px;flex-wrap:wrap;}
366
- .prof-follow-btn{flex:1;min-width:80px;padding:10px;border-radius:var(--r-sm);background:var(--white);color:var(--black);border:none;font-family:var(--font);font-size:12px;font-weight:600;cursor:pointer;transition:var(--t);}
367
- .prof-follow-btn.following{background:transparent;color:var(--white);border:1.5px solid var(--border2);}
368
- .prof-msg-btn{padding:10px 14px;border-radius:var(--r-sm);background:var(--surface2);border:1.5px solid var(--border2);color:var(--white);font-family:var(--font);font-size:12px;cursor:pointer;transition:var(--t);}
369
- .prof-msg-btn:hover{border-color:var(--white);}
370
- .check-profile-btn{padding:10px 13px;border-radius:var(--r-sm);background:var(--surface2);border:1.5px solid var(--border);color:var(--text3);cursor:pointer;font-family:var(--font);font-size:12px;transition:var(--t);display:flex;align-items:center;gap:5px;}
371
- .check-profile-btn:hover{border-color:var(--white);color:var(--white);}
 
372
  .check-profile-btn svg{width:12px;height:12px;}
373
  .posts-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;}
374
- .grid-post{aspect-ratio:1;background:var(--surface2);overflow:hidden;cursor:pointer;position:relative;}
375
- .grid-post:hover::after{content:'';position:absolute;inset:0;background:rgba(0,0,0,.3);}
 
376
  .grid-post img{width:100%;height:100%;object-fit:cover;}
377
- .grid-post-text{display:flex;align-items:center;justify-content:center;padding:8px;font-size:11px;color:var(--text3);text-align:center;}
378
- .private-notice{display:flex;flex-direction:column;align-items:center;gap:12px;padding:40px 20px;color:var(--text3);text-align:center;}
379
- .private-notice svg{width:32px;height:32px;}
 
 
 
 
 
 
 
 
 
 
380
 
381
- /* MODALS */
382
  .modal-overlay{position:fixed;inset:0;z-index:500;background:rgba(0,0,0,.82);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;padding:16px;animation:fadeIn .16s;}
383
- .modal{width:100%;max-width:420px;border-radius:20px;box-shadow:var(--shadow-md);max-height:88vh;overflow-y:auto;animation:slideUp .22s var(--ease);background:var(--surface);border:1px solid var(--border2);}
384
  .modal::-webkit-scrollbar{display:none;}
385
- .glass-modal{background:var(--surface);}
386
- .tall-modal{max-height:74vh;display:flex;flex-direction:column;}
387
  .small-modal{max-width:320px;}
388
- .modal-header{padding:16px 20px 13px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;background:var(--surface);z-index:5;}
389
- .modal-header h2{font-family:var(--serif);font-size:17px;letter-spacing:-.2px;color:var(--white);}
390
- .modal-close{width:28px;height:28px;border-radius:50%;background:var(--surface2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--t);color:var(--text3);}
391
- .modal-close:hover{border-color:var(--white);color:var(--white);}
392
  .modal-close svg{width:12px;height:12px;}
393
- .modal-body{padding:16px 20px;display:flex;flex-direction:column;gap:10px;}
394
- .modal-desc{font-size:12px;color:var(--text3);line-height:1.6;}
395
- .composer-row{display:flex;gap:10px;align-items:flex-start;}
396
- .post-textarea{flex:1;background:none;border:none;outline:none;color:var(--white);font-family:var(--font);font-size:13px;resize:none;line-height:1.58;min-height:56px;}
397
- .post-textarea::placeholder{color:var(--text4);}
398
- .composer-toolbar{display:flex;gap:6px;}
399
- .toolbar-btn{display:flex;align-items:center;gap:5px;color:var(--text3);font-size:12px;cursor:pointer;padding:7px 11px;border-radius:var(--r-xs);background:var(--surface2);border:1px solid var(--border);transition:var(--t);}
400
- .toolbar-btn:hover{color:var(--white);border-color:var(--border2);}
401
  .toolbar-btn svg{width:12px;height:12px;}
402
- .upload-area{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:30px 16px;border:1.5px dashed var(--border2);border-radius:var(--r);cursor:pointer;transition:var(--t);color:var(--text3);}
403
- .upload-area:hover{border-color:var(--white);background:rgba(255,255,255,.03);}
404
- .upload-area svg{width:30px;height:30px;}
405
- .story-preview-wrap img{width:100%;max-height:160px;object-fit:cover;border-radius:var(--r-sm);}
406
  .code-grid{display:flex;gap:7px;justify-content:center;}
407
- .code-box{width:42px;height:50px;text-align:center;background:var(--surface2);border:1.5px solid var(--border);border-radius:var(--r-sm);color:var(--white);font-size:20px;font-weight:700;font-family:var(--font);outline:none;transition:var(--t);}
408
- .code-box:focus{border-color:var(--white);}
409
- .settings-avatar-wrap{display:flex;flex-direction:column;align-items:center;gap:8px;padding-bottom:14px;border-bottom:1px solid var(--border);}
410
  .change-avatar-overlay{position:absolute;inset:0;border-radius:50%;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;opacity:0;transition:var(--t);}
411
  label:hover .change-avatar-overlay{opacity:1;}
412
- .change-avatar-overlay svg{width:16px;height:16px;color:var(--white);}
413
- .settings-avatar-hint{font-size:11px;color:var(--text3);}
414
- .toggle-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 0;}
415
- .toggle-label{font-size:13px;font-weight:500;}
416
- .toggle-sub{font-size:11px;color:var(--text3);margin-top:1px;}
417
- .toggle{width:40px;height:23px;border-radius:12px;background:var(--surface3);border:1.5px solid var(--border2);cursor:pointer;position:relative;transition:var(--t);flex-shrink:0;}
418
- .toggle.on{background:var(--white);border-color:var(--white);}
419
- .toggle-knob{width:16px;height:16px;border-radius:50%;background:var(--text3);position:absolute;top:2px;left:2px;transition:var(--t);}
420
- .toggle.on .toggle-knob{background:var(--black);left:19px;}
421
  #new-chat-results{max-height:220px;overflow-y:auto;}
422
- .ncu-item{display:flex;align-items:center;gap:10px;padding:8px;border-radius:var(--r-xs);cursor:pointer;transition:var(--t);}
423
  .ncu-item:hover{background:rgba(255,255,255,.04);}
424
- .ncu-name{font-size:12px;font-weight:600;display:flex;align-items:center;gap:3px;}
425
- .ncu-handle{font-size:11px;color:var(--text3);}
426
  .post-img-preview-item{position:relative;display:inline-block;}
427
- .post-img-preview-item img{max-height:96px;border-radius:var(--r-xs);display:block;}
428
- .remove-img{position:absolute;top:-4px;right:-4px;width:18px;height:18px;background:var(--white);border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;border:2px solid var(--surface);}
429
- .remove-img svg{width:8px;height:8px;color:var(--black);}
430
 
431
- /* STORY VIEWER */
432
  .story-viewer{position:fixed;inset:0;z-index:900;background:#000;display:flex;flex-direction:column;animation:fadeIn .18s;}
433
  .story-bg{position:absolute;inset:0;background-size:cover;background-position:center;filter:blur(30px) brightness(.2);}
434
- .story-progress-bar{position:absolute;top:0;left:0;right:0;height:2px;background:rgba(255,255,255,.2);z-index:10;}
435
- .story-progress{height:100%;background:var(--white);transition:width .1s linear;}
436
- .story-top-bar{position:absolute;top:12px;left:14px;right:14px;display:flex;align-items:center;justify-content:space-between;z-index:10;}
437
  .story-user-info{display:flex;align-items:center;gap:9px;}
438
- .sv-name{font-size:13px;font-weight:600;color:var(--white);text-shadow:0 1px 8px rgba(0,0,0,.9);}
439
  .sv-time{font-size:10px;color:rgba(255,255,255,.5);}
440
- .sv-close{background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.15);color:var(--white);border-radius:50%;width:30px;height:30px;display:flex;align-items:center;justify-content:center;cursor:pointer;}
441
  .sv-close svg{width:12px;height:12px;}
442
  .story-img{width:100%;height:100%;object-fit:contain;position:absolute;inset:0;z-index:5;}
443
- /* Story caption: raised higher */
444
- .story-caption{position:absolute;bottom:100px;left:0;right:0;text-align:center;font-size:15px;font-weight:500;text-shadow:0 2px 12px rgba(0,0,0,.9);z-index:10;padding:0 20px;color:var(--white);}
445
  .story-nav-l,.story-nav-r{position:absolute;top:0;bottom:0;width:35%;z-index:8;cursor:pointer;}
446
  .story-nav-l{left:0;}.story-nav-r{right:0;}
447
- .story-viewers{position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,.86);padding:14px 16px;z-index:10;border-top:1px solid rgba(255,255,255,.08);border-radius:18px 18px 0 0;}
448
  .sv-viewers-label{font-size:10px;color:rgba(255,255,255,.35);margin-bottom:8px;}
449
 
450
- /* COMMENTS */
451
  .comments-list{flex:1;overflow-y:auto;padding:4px 0;min-height:0;}
452
- .comment-item{display:flex;gap:9px;padding:9px 18px;}
453
  .comment-body{flex:1;min-width:0;}
454
- .comment-uname{font-size:12px;font-weight:600;}
455
- .comment-txt{font-size:12px;display:inline;margin-left:5px;line-height:1.52;}
456
- .comment-actions{display:flex;gap:10px;margin-top:4px;align-items:center;}
457
- .comment-time{font-size:10px;color:var(--text3);}
458
- .comment-like-btn{display:flex;align-items:center;gap:3px;color:var(--text3);cursor:pointer;font-size:10px;transition:var(--t);}
459
- .comment-like-btn:hover{color:var(--white);}
460
  .comment-like-btn svg{width:10px;height:10px;}
461
- .comment-reply-btn{font-size:10px;color:var(--text3);cursor:pointer;transition:var(--t);}
462
- .comment-reply-btn:hover{color:var(--white);}
463
- .comment-compose{display:flex;align-items:center;gap:9px;padding:10px 16px;border-top:1px solid var(--border);flex-shrink:0;}
464
- .comment-field{flex:1;background:var(--surface2);border:1.5px solid transparent;border-radius:20px;padding:9px 14px;color:var(--white);font-family:var(--font);font-size:12px;outline:none;transition:var(--t);}
465
- .comment-field:focus{border-color:rgba(255,255,255,.3);background:var(--surface3);}
466
- .comment-field::placeholder{color:var(--text4);}
467
- .send-icon-btn{width:32px;height:32px;border-radius:50%;background:var(--white);display:flex;align-items:center;justify-content:center;cursor:pointer;border:none;transition:var(--t);flex-shrink:0;}
468
  .send-icon-btn:hover{opacity:.84;}
469
- .send-icon-btn svg{width:12px;height:12px;color:var(--black);margin-left:1px;}
470
-
471
- /* STREAK */
472
- .streak-overlay{position:fixed;inset:0;z-index:600;background:rgba(0,0,0,.85);backdrop-filter:blur(20px);display:flex;align-items:center;justify-content:center;animation:fadeIn .18s;}
473
- .streak-card{text-align:center;display:flex;flex-direction:column;align-items:center;gap:14px;animation:slideUp .3s var(--ease);background:var(--surface);border:1px solid var(--border2);border-radius:24px;padding:36px 32px;max-width:280px;width:100%;box-shadow:var(--shadow-md);}
474
- .streak-emoji{font-size:60px;animation:pulse 1s infinite;}
475
- .streak-title{font-size:26px;letter-spacing:-.5px;font-family:var(--serif);}
476
- .streak-desc{font-size:12px;color:var(--text3);max-width:200px;line-height:1.6;}
477
  .streak-card .btn-primary{max-width:165px;}
478
 
479
- /* CTX MENU */
480
- .ctx-menu{position:fixed;z-index:9999;background:var(--surface);border:1px solid var(--border2);border-radius:var(--r-sm);padding:5px;box-shadow:var(--shadow-md);animation:fadeInUp .12s;min-width:165px;}
481
- .ctx-item{padding:9px 12px;border-radius:var(--r-xs);cursor:pointer;font-size:12px;color:var(--text2);transition:var(--t);display:flex;align-items:center;gap:9px;}
482
- .ctx-item:hover{background:rgba(255,255,255,.06);color:var(--white);}
483
  .ctx-item.danger{color:#ff6b6b;}
484
  .ctx-item.danger:hover{background:rgba(255,80,80,.08);}
485
  .ctx-item svg{width:13px;height:13px;}
486
  .ctx-emoji-row{display:flex;gap:3px;padding:6px 8px;flex-wrap:wrap;}
487
 
488
- /* TOAST */
489
- .toast{position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:var(--white);color:var(--black);padding:9px 22px;border-radius:40px;font-size:12px;font-weight:600;z-index:9999;box-shadow:var(--shadow-md);animation:toastIn .2s var(--ease);white-space:nowrap;}
490
 
491
- /* ANIMATIONS */
492
  @keyframes fadeIn{from{opacity:0}to{opacity:1}}
493
  @keyframes fadeInUp{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
494
- @keyframes slideUp{from{opacity:0;transform:translateY(18px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}
495
- @keyframes pageFadeIn{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}}
496
- @keyframes postFadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
497
  @keyframes bubblePop{from{opacity:0;transform:scale(.92) translateY(5px)}to{opacity:1;transform:scale(1) translateY(0)}}
498
  @keyframes spin{to{transform:rotate(360deg)}}
499
  @keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
500
  @keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(.93)}}
501
  @keyframes toastIn{from{opacity:0;transform:translateX(-50%) translateY(8px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}
502
 
503
- /* EXTRA FIXES */
504
- .prof-back-btn{width:30px;height:30px;border-radius:50%;background:var(--surface2);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text3);flex-shrink:0;}
505
- .prof-back-btn svg{width:14px;height:14px;}
506
- /* Fix msg group other avatar spacing */
507
- .msg-group.other{padding-left:38px;position:relative;}
508
- .msg-group.other .msg-row{position:relative;}
509
- .msg-group.other .msg-row .avatar.xs{position:absolute;left:-38px;bottom:0;}
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,600;1,400&display=swap');
2
 
3
  *,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
4
 
5
  :root{
 
 
 
6
  --bg:#0a0a0a;
7
+ --s1:#111111;
8
+ --s2:#1a1a1a;
9
+ --s3:#242424;
10
+ --s4:#2e2e2e;
11
+ --b1:rgba(255,255,255,.07);
12
+ --b2:rgba(255,255,255,.13);
13
+ --b3:rgba(255,255,255,.22);
14
+ --t1:#ffffff;
15
+ --t2:rgba(255,255,255,.80);
16
+ --t3:rgba(255,255,255,.45);
17
+ --t4:rgba(255,255,255,.22);
18
+ --r:14px;--rsm:10px;--rxs:7px;
19
+ --sh:0 2px 16px rgba(0,0,0,.6);
20
+ --shmd:0 6px 32px rgba(0,0,0,.75);
21
+ --ease:cubic-bezier(.4,0,.2,1);
22
+ --t:.18s var(--ease);
23
+ --font:'Inter',system-ui,sans-serif;
24
  --serif:'Playfair Display',Georgia,serif;
25
+ --nb:62px;
26
  }
27
 
28
+ html,body{height:100%;overflow:hidden;background:var(--bg);color:var(--t1);font-family:var(--font);font-size:13px;-webkit-font-smoothing:antialiased;}
29
  .font-serif{font-family:var(--serif);}
30
  .hidden{display:none!important;}
31
+ ::-webkit-scrollbar{width:3px;}::-webkit-scrollbar-thumb{background:var(--s3);}::-webkit-scrollbar-track{background:transparent;}
 
 
32
 
33
  /* ── AUTH ── */
34
+ #auth-screen{
35
+ position:fixed;inset:0;z-index:999;
36
+ display:flex;align-items:center;justify-content:center;
37
+ background:var(--bg);padding:24px;
38
+ animation:fadeIn .3s;
39
+ }
40
  .auth-card{width:100%;max-width:360px;display:flex;flex-direction:column;animation:slideUp .4s var(--ease);}
41
+ .auth-logo{display:flex;align-items:center;gap:10px;margin-bottom:5px;}
42
+ .auth-logo-img{width:26px;height:26px;}
43
+ .logo-text{font-size:26px;letter-spacing:-.5px;color:var(--t1);}
44
+ .auth-tagline{font-size:12px;color:var(--t3);margin-bottom:24px;}
45
+ .auth-tabs{display:flex;background:var(--s2);border-radius:var(--rsm);padding:3px;margin-bottom:18px;border:1px solid var(--b1);}
46
+ .auth-tab{flex:1;padding:9px;border-radius:8px;cursor:pointer;font-size:12px;font-weight:500;color:var(--t3);border:none;background:none;font-family:var(--font);transition:var(--t);}
47
+ .auth-tab.active{background:var(--s3);color:var(--t1);}
48
  .auth-form{display:flex;flex-direction:column;gap:10px;}
49
+ .input-group{display:flex;align-items:center;gap:10px;background:var(--s2);border:1.5px solid transparent;border-radius:var(--rsm);padding:12px 14px;transition:var(--t);}
50
+ .input-group:focus-within{border-color:var(--b3);background:var(--s3);}
51
+ .input-group svg{width:15px;height:15px;color:var(--t3);flex-shrink:0;}
52
+ .input-group input{flex:1;background:none;border:none;outline:none;color:var(--t1);font-family:var(--font);font-size:13px;}
53
+ .input-group input::placeholder{color:var(--t4);}
54
+ input.auth-input{background:var(--s2);border:1.5px solid transparent;border-radius:var(--rsm);padding:12px 14px;font-family:var(--font);font-size:13px;color:var(--t1);outline:none;width:100%;display:block;transition:var(--t);}
55
+ input.auth-input:focus{border-color:var(--b3);background:var(--s3);}
56
+ input.auth-input::placeholder{color:var(--t4);}
57
+ .btn-primary{background:var(--t1);color:#000;border:none;border-radius:var(--rsm);padding:13px;font-family:var(--font);font-size:13px;font-weight:600;cursor:pointer;transition:var(--t);width:100%;display:flex;align-items:center;justify-content:center;gap:7px;}
58
+ .btn-primary:hover{opacity:.88;transform:translateY(-1px);}
59
  .btn-primary:active{transform:translateY(0);}
60
+ .btn-ghost{background:transparent;color:var(--t3);border:1.5px solid var(--b2);border-radius:var(--rsm);padding:11px;font-family:var(--font);font-size:12px;font-weight:500;cursor:pointer;transition:var(--t);width:100%;display:flex;align-items:center;justify-content:center;gap:7px;}
61
+ .btn-ghost:hover{color:var(--t1);border-color:var(--b3);}
62
  .btn-ghost svg{width:13px;height:13px;}
63
+ .btn-spinner{width:13px;height:13px;border:2px solid rgba(0,0,0,.25);border-top-color:#000;border-radius:50%;animation:spin .7s linear infinite;}
64
+ .auth-error{color:#ff6b6b;font-size:11px;text-align:center;margin-top:6px;}
65
+
66
+ /* ── APP SHELL ── */
67
+ #app{
68
+ height:100dvh;
69
+ display:flex;
70
+ flex-direction:column;
71
+ overflow:hidden;
72
+ background:var(--bg);
73
+ }
74
+ .main-content{
75
+ flex:1;
76
+ display:flex;
77
+ flex-direction:column;
78
+ overflow:hidden;
79
+ min-height:0;
80
+ }
81
 
82
  /* ── BOTTOM NAVBAR ── */
83
+ .bottom-nav{
84
+ height:var(--nb);
85
+ flex-shrink:0;
86
  background:rgba(10,10,10,.97);
87
+ border-top:1px solid var(--b1);
88
+ display:flex;
89
+ align-items:stretch;
90
+ position:relative;
91
+ z-index:100;
92
+ backdrop-filter:blur(20px);
93
+ -webkit-backdrop-filter:blur(20px);
 
 
 
 
 
 
 
 
94
  }
95
  .nav-item{
96
+ flex:1;
97
+ display:flex;
98
+ flex-direction:column;
99
+ align-items:center;
100
+ justify-content:center;
101
+ gap:3px;
102
+ cursor:pointer;
103
+ color:var(--t3);
104
+ transition:var(--t);
105
+ position:relative;
106
+ user-select:none;
107
+ padding:6px 4px;
108
+ -webkit-tap-highlight-color:transparent;
109
  }
110
+ .nav-item svg{width:22px;height:22px;stroke-width:1.8;transition:var(--t);}
111
+ .nav-item span{font-size:10px;font-weight:500;letter-spacing:.1px;}
112
+ .nav-item:hover{color:rgba(255,255,255,.6);}
113
+ .nav-item.active{color:var(--t1);}
114
  .nav-item.active svg{stroke-width:2.2;}
115
  .nav-badge{
116
+ position:absolute;top:5px;right:calc(50% - 22px);
117
+ background:var(--t1);color:#000;
118
  font-size:9px;font-weight:700;border-radius:20px;
119
+ padding:1px 5px;min-width:16px;text-align:center;line-height:1.5;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  }
121
+ .nav-av-wrap{display:flex;align-items:center;justify-content:center;}
122
+ .nav-av-wrap .avatar{border:2px solid var(--b2);}
123
+ .nav-item.active .nav-av-wrap .avatar{border-color:var(--t1);}
 
 
 
 
124
 
125
+ /* ── PAGES ── */
126
+ .page{display:none;flex:1;flex-direction:column;overflow-y:auto;overflow-x:hidden;min-height:0;}
 
 
 
 
 
127
  .page.active{display:flex;animation:pageFadeIn .2s var(--ease);}
128
 
129
  /* PAGE HEADER */
130
  .page-header{
131
+ padding:16px 18px 14px;
132
+ border-bottom:1px solid var(--b1);
133
  display:flex;align-items:center;justify-content:space-between;
134
  flex-shrink:0;position:sticky;top:0;z-index:20;
135
+ background:rgba(10,10,10,.94);
136
+ backdrop-filter:blur(12px);
137
  }
138
+ .page-title{font-size:20px;letter-spacing:-.4px;font-weight:700;color:var(--t1);}
139
  .header-actions{display:flex;gap:6px;}
140
  .icon-btn{
141
+ width:33px;height:33px;border-radius:50%;
142
+ background:var(--s2);border:1px solid var(--b1);
143
  display:flex;align-items:center;justify-content:center;
144
+ cursor:pointer;transition:var(--t);color:var(--t3);
145
  }
146
+ .icon-btn:hover{border-color:var(--b2);color:var(--t1);}
147
  .icon-btn svg{width:14px;height:14px;}
148
 
149
+ /* ── AVATAR ── */
150
+ .avatar{
151
+ border-radius:50%;background:var(--s2);
152
+ display:flex;align-items:center;justify-content:center;
153
+ font-weight:600;overflow:hidden;flex-shrink:0;
154
+ color:rgba(255,255,255,.55);
155
+ border:1.5px solid var(--b1);
156
+ background-size:cover;background-position:center;
 
 
 
 
 
 
 
 
157
  }
158
+ .avatar.xs{width:26px;height:26px;font-size:9px;}
159
+ .avatar.sm{width:34px;height:34px;font-size:12px;}
160
+ .avatar.md{width:42px;height:42px;font-size:14px;}
161
+ .avatar.lg{width:68px;height:68px;font-size:22px;}
162
+ .avatar.xl{width:86px;height:86px;font-size:28px;}
163
+ .avatar-wrap{position:relative;flex-shrink:0;}
164
+ .avatar-wrap.has-story::before{content:'';position:absolute;inset:-2px;border-radius:50%;border:2px solid var(--t1);pointer-events:none;}
 
 
 
 
 
165
 
166
  /* ── STORIES ── */
167
+ .stories-section{border-bottom:1px solid var(--b1);padding:14px 0;flex-shrink:0;}
168
+ .stories-scroll{display:flex;gap:14px;padding:0 18px;overflow-x:auto;}
169
  .stories-scroll::-webkit-scrollbar{display:none;}
170
  .story-item{display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;flex-shrink:0;transition:transform .15s;}
171
  .story-item:hover{transform:translateY(-2px);}
172
+ .story-ring{width:56px;height:56px;border-radius:50%;border:2px solid var(--t1);padding:2px;background:var(--bg);position:relative;}
173
  .story-ring .avatar{width:100%;height:100%;border:none;}
174
+ .add-ring{border-color:var(--b2);border-style:dashed;}
175
+ .add-story-icon{position:absolute;bottom:-1px;right:-1px;width:18px;height:18px;background:var(--t1);border-radius:50%;display:flex;align-items:center;justify-content:center;border:2px solid var(--bg);}
176
+ .add-story-icon svg{width:8px;height:8px;color:#000;}
177
+ .story-label{font-size:10px;color:var(--t3);white-space:nowrap;max-width:60px;overflow:hidden;text-overflow:ellipsis;text-align:center;}
178
 
179
  /* ── POSTS ── */
180
+ .skeleton-post{height:100px;margin:14px 18px;background:linear-gradient(90deg,var(--s1) 25%,var(--s2) 50%,var(--s1) 75%);background-size:200% 100%;border-radius:var(--r);animation:shimmer 1.5s infinite;}
181
+ .post{border-bottom:1px solid var(--b1);padding:16px 18px;transition:background .12s;}
182
  .post.new-post{animation:postFadeIn .22s var(--ease);}
183
+ .post:hover{background:rgba(255,255,255,.015);}
184
+ .post-header{display:flex;align-items:center;gap:10px;margin-bottom:11px;}
185
  .post-user{flex:1;cursor:pointer;}
186
+ .post-name{font-size:13px;font-weight:600;display:inline-flex;align-items:center;gap:4px;color:var(--t1);}
187
+ .post-time{font-size:11px;color:var(--t3);margin-top:2px;}
188
+ .post-menu-btn{color:var(--t3);cursor:pointer;padding:5px;border-radius:50%;transition:var(--t);}
189
+ .post-menu-btn:hover{color:var(--t1);background:var(--s2);}
190
  .post-menu-btn svg{width:14px;height:14px;display:block;}
191
+ .post-text{font-size:13px;line-height:1.65;color:var(--t2);margin-bottom:11px;}
192
+ .post-img{width:100%;border-radius:var(--r);overflow:hidden;margin-bottom:11px;border:1px solid var(--b1);}
193
  .post-img img{width:100%;display:block;max-height:360px;object-fit:cover;cursor:zoom-in;}
194
+ .post-actions{display:flex;gap:20px;padding-top:2px;}
195
+ .post-action{display:flex;align-items:center;gap:5px;color:var(--t3);cursor:pointer;font-size:12px;transition:var(--t);user-select:none;}
196
+ .post-action:hover{color:var(--t1);}
197
+ .post-action.liked{color:var(--t1);}
198
  .post-action svg{width:15px;height:15px;}
199
+ .v-badge{width:13px;height:13px;flex-shrink:0;}
200
+ .empty-state-center{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:60px 20px;color:var(--t4);}
201
+ .empty-state-center svg{width:42px;height:42px;}
202
+ .empty-state-center p{font-size:13px;color:var(--t3);}
203
 
204
+ /* ── CHAT LAYOUT ── */
205
  .chat-layout{display:flex;flex:1;overflow:hidden;position:relative;background:var(--bg);}
206
+ .chat-sidebar{
207
+ width:100%;flex-shrink:0;display:flex;flex-direction:column;overflow:hidden;
208
+ background:var(--bg);transition:transform .28s var(--ease);
209
+ position:absolute;inset:0;z-index:5;
210
+ }
211
+ .chat-main{
212
+ flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;
213
+ background:var(--bg);transition:transform .28s var(--ease);
214
+ position:absolute;inset:0;transform:translateX(110%);
215
+ }
216
  .chat-layout.chat-open .chat-sidebar{transform:translateX(-110%);}
217
  .chat-layout.chat-open .chat-main{transform:translateX(0);}
218
+ @media(min-width:680px){
219
+ .chat-sidebar{position:relative;width:280px;min-width:280px;border-right:1px solid var(--b1);z-index:auto;transform:none!important;}
 
 
220
  .chat-main{position:relative;transform:none!important;}
221
+ .chat-back{display:none!important;}
222
  .chat-layout.chat-open .chat-sidebar{transform:none!important;}
223
  }
224
+ .chat-back{display:flex;align-items:center;justify-content:center;width:31px;height:31px;border-radius:50%;background:var(--s2);border:1px solid var(--b1);cursor:pointer;color:var(--t3);flex-shrink:0;}
225
+ .chat-back svg{width:14px;height:14px;}
226
+ .chat-sidebar-header{padding:16px 14px 12px;border-bottom:1px solid var(--b1);display:flex;align-items:center;justify-content:space-between;}
227
+ .chat-sidebar-header h2{font-size:19px;letter-spacing:-.3px;color:var(--t1);}
228
+ .chat-search-area{padding:9px 13px;border-bottom:1px solid var(--b1);}
229
+ .search-bar{background:var(--s2);border:1px solid transparent;border-radius:22px;padding:9px 13px;display:flex;align-items:center;gap:8px;transition:var(--t);}
230
+ .search-bar:focus-within{border-color:var(--b2);background:var(--s3);}
231
+ .search-bar.large{border-radius:var(--r);padding:12px 16px;}
232
+ .search-bar svg{width:13px;height:13px;color:var(--t3);flex-shrink:0;}
233
+ .search-bar input{background:none;border:none;outline:none;color:var(--t1);font-family:var(--font);font-size:12px;flex:1;min-width:0;}
234
+ .search-bar input::placeholder{color:var(--t4);}
235
+ .chat-tabs-row{display:flex;padding:6px 13px 0;border-bottom:1px solid var(--b1);}
236
+ .chat-tab{flex:1;padding:9px 4px;text-align:center;cursor:pointer;font-size:11px;font-weight:500;color:var(--t3);border:none;background:none;font-family:var(--font);border-bottom:2px solid transparent;margin-bottom:-1px;transition:var(--t);}
237
+ .chat-tab.active{color:var(--t1);border-bottom-color:var(--t1);}
238
  .chat-list-scroll{flex:1;overflow-y:auto;}
239
 
240
+ /* Conversații */
241
+ .conv-item{display:flex;align-items:center;gap:11px;padding:13px 14px;cursor:pointer;transition:background .12s;border-bottom:1px solid var(--b1);}
242
  .conv-item:hover{background:rgba(255,255,255,.03);}
243
+ .conv-item.active{background:rgba(255,255,255,.05);}
244
  .conv-item-body{flex:1;min-width:0;}
245
  .conv-top{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:3px;}
246
+ .conv-name{font-size:13px;font-weight:600;color:var(--t1);display:flex;align-items:center;gap:3px;}
247
+ .conv-time{font-size:10px;color:var(--t3);}
248
+ .conv-preview{font-size:12px;color:var(--t3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
249
+ .conv-right{display:flex;flex-direction:column;align-items:flex-end;gap:4px;}
250
+ .conv-unread-dot{width:9px;height:9px;background:var(--t1);border-radius:50%;}
251
  .conv-streak{font-size:10px;}
252
 
253
+ /* Fereastra chat */
254
+ .chat-empty-state{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:13px;color:var(--t3);}
255
+ .chat-empty-state p{font-size:13px;color:var(--t2);}
256
+ .chat-empty-state span{font-size:11px;color:var(--t4);}
257
+ .chat-empty-icon svg{width:46px;height:46px;color:var(--t4);}
258
  .chat-window{flex:1;display:flex;flex-direction:column;overflow:hidden;}
259
+ .chat-win-header{display:flex;align-items:center;gap:11px;padding:13px 16px;border-bottom:1px solid var(--b1);flex-shrink:0;background:rgba(10,10,10,.95);backdrop-filter:blur(10px);}
260
+ .chat-win-user{flex:1;min-width:0;cursor:pointer;}
261
+ .chat-win-name{font-size:14px;font-weight:600;display:flex;align-items:center;gap:5px;color:var(--t1);}
262
+ .chat-win-sub{font-size:11px;color:var(--t3);margin-top:2px;}
263
  .chat-win-actions{display:flex;gap:5px;}
264
 
265
+ /* Zona mesaje */
266
+ .messages-area{
267
+ flex:1;overflow-y:auto;
268
+ padding:16px 14px 10px;
269
+ display:flex;flex-direction:column;
270
+ gap:0;scroll-behavior:smooth;
271
+ background:var(--bg);
272
+ }
273
+ .date-sep{text-align:center;font-size:10px;color:var(--t3);margin:14px 0 8px;letter-spacing:.5px;}
274
 
275
+ /* Bule iMessage */
276
+ .msg-group{display:flex;flex-direction:column;margin-bottom:12px;}
277
  .msg-group.own{align-items:flex-end;}
278
+ .msg-group.other{align-items:flex-start;padding-left:38px;position:relative;}
279
+ .msg-row{display:flex;align-items:flex-end;gap:6px;position:relative;}
280
  .msg-row.own{flex-direction:row-reverse;}
281
+ .msg-av-abs{position:absolute;left:-38px;bottom:0;}
 
 
 
282
 
283
+ .bubble{max-width:78%;padding:10px 14px;font-size:13px;line-height:1.55;word-break:break-word;animation:bubblePop .18s var(--ease);}
284
+ .bubble.own{background:var(--t1);color:#000;border-radius:20px 20px 4px 20px;}
285
+ .bubble.other{background:var(--s2);color:var(--t1);border-radius:20px 20px 20px 4px;}
286
  .bubble p{margin:0;white-space:pre-wrap;word-break:break-word;}
287
  .bubble img{max-width:200px;border-radius:12px;display:block;cursor:zoom-in;}
288
+ .bubble-reply{background:rgba(255,255,255,.07);border-left:2.5px solid rgba(255,255,255,.25);border-radius:5px;padding:5px 9px;margin-bottom:7px;font-size:11px;opacity:.7;cursor:pointer;}
289
+ .bubble.own .bubble-reply{background:rgba(0,0,0,.1);border-left-color:rgba(0,0,0,.2);}
290
+ .reactions-row{display:flex;gap:3px;flex-wrap:wrap;margin-top:5px;}
291
+ .reaction-pill{background:var(--s2);border:1.5px solid var(--b2);border-radius:13px;padding:3px 8px;font-size:11px;cursor:pointer;transition:var(--t);}
292
+ .reaction-pill:hover{border-color:var(--t1);}
 
 
 
 
 
 
 
293
  .msg-group.own .reactions-row{justify-content:flex-end;}
294
+ .msg-meta{font-size:9px;color:var(--t4);margin-top:4px;padding:0 5px;}
295
  .msg-group.own .msg-meta{text-align:right;}
296
 
297
+ /* Input mesaj */
298
+ .chat-input-zone{padding:10px 14px 14px;border-top:1px solid var(--b1);flex-shrink:0;background:rgba(10,10,10,.97);backdrop-filter:blur(10px);}
299
+ .reply-bar{display:flex;align-items:center;gap:8px;padding:7px 11px;margin-bottom:9px;background:var(--s2);border-radius:var(--rxs);border-left:2.5px solid var(--t1);}
300
+ .reply-bar-text{flex:1;font-size:11px;color:var(--t3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
301
+ .reply-cancel{cursor:pointer;color:var(--t3);}
302
  .reply-cancel svg{width:11px;height:11px;display:block;}
303
+ .input-row{display:flex;align-items:flex-end;gap:9px;}
304
+ .input-wrap{flex:1;display:flex;align-items:flex-end;gap:7px;background:var(--s2);border:1.5px solid transparent;border-radius:24px;padding:10px 14px;transition:var(--t);min-width:0;}
305
+ .input-wrap:focus-within{border-color:var(--b3);background:var(--s3);}
306
+ .chat-textarea{flex:1;background:none;border:none;outline:none;color:var(--t1);font-family:var(--font);font-size:13px;resize:none;max-height:80px;line-height:1.45;min-width:0;}
307
+ .chat-textarea::placeholder{color:var(--t4);}
308
+ .input-action{color:var(--t3);cursor:pointer;transition:var(--t);display:flex;align-items:center;flex-shrink:0;padding:2px;}
309
+ .input-action:hover{color:var(--t1);}
310
  .input-action svg{width:17px;height:17px;}
311
+ .send-btn{width:42px;height:42px;border-radius:50%;flex-shrink:0;background:var(--t1);display:flex;align-items:center;justify-content:center;cursor:pointer;border:none;transition:var(--t);}
 
312
  .send-btn:hover{opacity:.82;transform:scale(1.05);}
313
+ .send-btn:active{transform:scale(.96);}
314
+ .send-btn svg{width:15px;height:15px;color:#000;margin-left:2px;}
315
+ .emoji-picker{position:fixed;z-index:9000;background:var(--s1);border:1.5px solid var(--b2);border-radius:var(--r);padding:10px;display:flex;flex-wrap:wrap;gap:3px;max-width:260px;box-shadow:var(--shmd);animation:fadeInUp .15s;}
316
+ .emoji-opt{font-size:22px;cursor:pointer;padding:4px;border-radius:6px;transition:transform .1s;}
317
  .emoji-opt:hover{transform:scale(1.35);}
318
 
319
+ /* ── NOTIFICĂRI ── */
320
  .notif-list{flex:1;overflow-y:auto;}
321
+ .notif-item{display:flex;align-items:center;gap:12px;padding:13px 18px;border-bottom:1px solid var(--b1);cursor:pointer;transition:var(--t);}
322
  .notif-item:hover{background:rgba(255,255,255,.02);}
323
+ .notif-icon{width:33px;height:33px;border-radius:50%;background:var(--s2);border:1px solid var(--b1);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:14px;}
324
+ .notif-text{flex:1;font-size:12px;line-height:1.55;}
325
+ .notif-time{font-size:10px;color:var(--t3);flex-shrink:0;}
326
 
327
+ /* ── EXPLORARE ── */
328
+ .explore-search-wrap{padding:13px 18px;border-bottom:1px solid var(--b1);}
329
  .explore-section{padding:16px 18px;}
330
+ .explore-user-item{display:flex;align-items:center;gap:12px;padding:11px 18px;border-bottom:1px solid var(--b1);cursor:pointer;transition:var(--t);}
331
  .explore-user-item:hover{background:rgba(255,255,255,.02);}
332
  .exu-info{flex:1;min-width:0;}
333
+ .exu-name{font-size:13px;font-weight:600;display:flex;align-items:center;gap:3px;color:var(--t1);}
334
+ .exu-handle{font-size:11px;color:var(--t3);}
335
+ .exu-count{font-size:10px;color:var(--t4);margin-top:1px;}
336
+
337
+ /* ── PROFIL ── */
338
+ .profile-back-bar{padding:13px 18px 0;display:flex;align-items:center;gap:9px;flex-shrink:0;}
339
+ .profile-back-btn{width:32px;height:32px;border-radius:50%;background:var(--s2);border:1px solid var(--b1);display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--t3);flex-shrink:0;transition:var(--t);}
340
+ .profile-back-btn:hover{color:var(--t1);border-color:var(--b2);}
341
+ .profile-back-btn svg{width:14px;height:14px;}
342
+ .profile-back-name{font-size:13px;font-weight:600;color:var(--t3);}
343
+ .profile-header{padding:22px 18px 18px;border-bottom:1px solid var(--b1);flex-shrink:0;}
344
  .profile-top{display:flex;gap:18px;align-items:flex-start;}
345
  .profile-info{flex:1;min-width:0;}
346
+ .profile-name{font-size:21px;letter-spacing:-.3px;display:flex;align-items:center;gap:6px;color:var(--t1);}
347
+ .profile-handle{font-size:12px;color:var(--t3);margin:3px 0 9px;}
348
+ .profile-bio{font-size:12px;line-height:1.65;color:var(--t2);margin-bottom:14px;}
349
+ .profile-stats{display:flex;gap:24px;}
350
  .pstat{text-align:center;cursor:pointer;}
351
+ .pstat-num{font-size:16px;font-weight:700;letter-spacing:-.2px;color:var(--t1);}
352
+ .pstat-label{font-size:10px;color:var(--t3);margin-top:2px;}
353
+ .profile-actions{display:flex;gap:8px;margin-top:15px;flex-wrap:wrap;}
354
+ .prof-follow-btn{flex:1;min-width:80px;padding:10px;border-radius:var(--rsm);background:var(--t1);color:#000;border:none;font-family:var(--font);font-size:12px;font-weight:600;cursor:pointer;transition:var(--t);}
355
+ .prof-follow-btn:hover{opacity:.86;}
356
+ .prof-follow-btn.following{background:transparent;color:var(--t1);border:1.5px solid var(--b2);}
357
+ .prof-msg-btn{padding:10px 14px;border-radius:var(--rsm);background:var(--s2);border:1.5px solid var(--b1);color:var(--t1);font-family:var(--font);font-size:12px;cursor:pointer;transition:var(--t);}
358
+ .prof-msg-btn:hover{border-color:var(--b2);}
359
+ .check-profile-btn{padding:9px 13px;border-radius:var(--rsm);background:var(--s2);border:1.5px solid var(--b1);color:var(--t3);cursor:pointer;font-family:var(--font);font-size:12px;transition:var(--t);display:flex;align-items:center;gap:5px;}
360
+ .check-profile-btn:hover{border-color:var(--b2);color:var(--t1);}
361
  .check-profile-btn svg{width:12px;height:12px;}
362
  .posts-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;}
363
+ .grid-post{aspect-ratio:1;background:var(--s2);overflow:hidden;cursor:pointer;position:relative;}
364
+ .grid-post::after{content:'';position:absolute;inset:0;opacity:0;transition:var(--t);background:rgba(0,0,0,.3);}
365
+ .grid-post:hover::after{opacity:1;}
366
  .grid-post img{width:100%;height:100%;object-fit:cover;}
367
+ .grid-post-text{display:flex;align-items:center;justify-content:center;padding:8px;font-size:11px;color:var(--t3);text-align:center;height:100%;}
368
+ .private-notice{display:flex;flex-direction:column;align-items:center;gap:13px;padding:50px 20px;color:var(--t3);text-align:center;}
369
+ .private-notice svg{width:34px;height:34px;}
370
+ .private-notice p{font-size:13px;}
371
+
372
+ /* ── SUGESTII (panou dreapta) ── */
373
+ .section-label{font-size:10px;color:var(--t3);font-weight:700;letter-spacing:.9px;text-transform:uppercase;margin-bottom:12px;}
374
+ .sug-item{display:flex;align-items:center;gap:10px;margin-bottom:12px;}
375
+ .sug-info{flex:1;min-width:0;}
376
+ .sug-name{font-size:12px;font-weight:600;display:flex;align-items:center;gap:3px;color:var(--t1);}
377
+ .sug-handle{font-size:11px;color:var(--t3);}
378
+ .follow-btn{font-size:11px;font-weight:600;background:var(--t1);color:#000;border:none;border-radius:20px;padding:5px 12px;cursor:pointer;font-family:var(--font);transition:var(--t);white-space:nowrap;}
379
+ .follow-btn.following{background:var(--s3);color:var(--t2);border:1px solid var(--b2);}
380
 
381
+ /* ── MODALS ── */
382
  .modal-overlay{position:fixed;inset:0;z-index:500;background:rgba(0,0,0,.82);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;padding:16px;animation:fadeIn .16s;}
383
+ .modal{width:100%;max-width:420px;border-radius:20px;box-shadow:var(--shmd);max-height:88vh;overflow-y:auto;animation:slideUp .22s var(--ease);background:var(--s1);border:1px solid var(--b2);}
384
  .modal::-webkit-scrollbar{display:none;}
385
+ .tall-modal{max-height:75vh;display:flex;flex-direction:column;}
 
386
  .small-modal{max-width:320px;}
387
+ .modal-header{padding:16px 20px 14px;border-bottom:1px solid var(--b1);display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;background:var(--s1);z-index:5;}
388
+ .modal-header h2{font-size:18px;letter-spacing:-.2px;color:var(--t1);}
389
+ .modal-close{width:29px;height:29px;border-radius:50%;background:var(--s2);border:1px solid var(--b1);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--t);color:var(--t3);}
390
+ .modal-close:hover{border-color:var(--b2);color:var(--t1);}
391
  .modal-close svg{width:12px;height:12px;}
392
+ .modal-body{padding:16px 20px;display:flex;flex-direction:column;gap:11px;}
393
+ .modal-desc{font-size:12px;color:var(--t3);line-height:1.65;}
394
+ .composer-row{display:flex;gap:11px;align-items:flex-start;}
395
+ .post-textarea{flex:1;background:none;border:none;outline:none;color:var(--t1);font-family:var(--font);font-size:13px;resize:none;line-height:1.6;min-height:60px;}
396
+ .post-textarea::placeholder{color:var(--t4);}
397
+ .composer-toolbar{display:flex;gap:7px;}
398
+ .toolbar-btn{display:flex;align-items:center;gap:5px;color:var(--t3);font-size:12px;cursor:pointer;padding:7px 12px;border-radius:var(--rxs);background:var(--s2);border:1px solid var(--b1);transition:var(--t);font-family:var(--font);}
399
+ .toolbar-btn:hover{color:var(--t1);border-color:var(--b2);}
400
  .toolbar-btn svg{width:12px;height:12px;}
401
+ .upload-area{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:11px;padding:32px 16px;border:1.5px dashed var(--b2);border-radius:var(--r);cursor:pointer;transition:var(--t);color:var(--t3);}
402
+ .upload-area:hover{border-color:var(--t1);background:rgba(255,255,255,.03);}
403
+ .upload-area svg{width:32px;height:32px;}
404
+ .story-preview-wrap img{width:100%;max-height:160px;object-fit:cover;border-radius:var(--rsm);}
405
  .code-grid{display:flex;gap:7px;justify-content:center;}
406
+ .code-box{width:43px;height:52px;text-align:center;background:var(--s2);border:1.5px solid var(--b1);border-radius:var(--rsm);color:var(--t1);font-size:20px;font-weight:700;font-family:var(--font);outline:none;transition:var(--t);}
407
+ .code-box:focus{border-color:var(--t1);}
408
+ .settings-avatar-wrap{display:flex;flex-direction:column;align-items:center;gap:9px;padding-bottom:14px;border-bottom:1px solid var(--b1);}
409
  .change-avatar-overlay{position:absolute;inset:0;border-radius:50%;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;opacity:0;transition:var(--t);}
410
  label:hover .change-avatar-overlay{opacity:1;}
411
+ .change-avatar-overlay svg{width:16px;height:16px;color:var(--t1);}
412
+ .settings-avatar-hint{font-size:11px;color:var(--t3);}
413
+ .toggle-row{display:flex;align-items:center;justify-content:space-between;gap:11px;padding:9px 0;}
414
+ .toggle-label{font-size:13px;font-weight:500;color:var(--t1);}
415
+ .toggle-sub{font-size:11px;color:var(--t3);margin-top:2px;}
416
+ .toggle{width:40px;height:23px;border-radius:12px;background:var(--s3);border:1.5px solid var(--b2);cursor:pointer;position:relative;transition:var(--t);flex-shrink:0;}
417
+ .toggle.on{background:var(--t1);border-color:var(--t1);}
418
+ .toggle-knob{width:16px;height:16px;border-radius:50%;background:var(--t3);position:absolute;top:2px;left:2px;transition:var(--t);}
419
+ .toggle.on .toggle-knob{background:#000;left:19px;}
420
  #new-chat-results{max-height:220px;overflow-y:auto;}
421
+ .ncu-item{display:flex;align-items:center;gap:10px;padding:9px;border-radius:var(--rxs);cursor:pointer;transition:var(--t);}
422
  .ncu-item:hover{background:rgba(255,255,255,.04);}
423
+ .ncu-name{font-size:12px;font-weight:600;display:flex;align-items:center;gap:3px;color:var(--t1);}
424
+ .ncu-handle{font-size:11px;color:var(--t3);}
425
  .post-img-preview-item{position:relative;display:inline-block;}
426
+ .post-img-preview-item img{max-height:98px;border-radius:var(--rxs);display:block;}
427
+ .remove-img{position:absolute;top:-4px;right:-4px;width:18px;height:18px;background:var(--t1);border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;border:2px solid var(--s1);}
428
+ .remove-img svg{width:8px;height:8px;color:#000;}
429
 
430
+ /* ── STORY VIEWER ── */
431
  .story-viewer{position:fixed;inset:0;z-index:900;background:#000;display:flex;flex-direction:column;animation:fadeIn .18s;}
432
  .story-bg{position:absolute;inset:0;background-size:cover;background-position:center;filter:blur(30px) brightness(.2);}
433
+ .story-progress-bar{position:absolute;top:0;left:0;right:0;height:2.5px;background:rgba(255,255,255,.2);z-index:10;}
434
+ .story-progress{height:100%;background:var(--t1);transition:width .1s linear;}
435
+ .story-top-bar{position:absolute;top:14px;left:14px;right:14px;display:flex;align-items:center;justify-content:space-between;z-index:10;}
436
  .story-user-info{display:flex;align-items:center;gap:9px;}
437
+ .sv-name{font-size:13px;font-weight:600;color:var(--t1);text-shadow:0 1px 8px rgba(0,0,0,.9);}
438
  .sv-time{font-size:10px;color:rgba(255,255,255,.5);}
439
+ .sv-close{background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.15);color:var(--t1);border-radius:50%;width:30px;height:30px;display:flex;align-items:center;justify-content:center;cursor:pointer;}
440
  .sv-close svg{width:12px;height:12px;}
441
  .story-img{width:100%;height:100%;object-fit:contain;position:absolute;inset:0;z-index:5;}
442
+ .story-caption{position:absolute;bottom:110px;left:0;right:0;text-align:center;font-size:16px;font-weight:500;text-shadow:0 2px 12px rgba(0,0,0,.9);z-index:10;padding:0 24px;color:var(--t1);}
 
443
  .story-nav-l,.story-nav-r{position:absolute;top:0;bottom:0;width:35%;z-index:8;cursor:pointer;}
444
  .story-nav-l{left:0;}.story-nav-r{right:0;}
445
+ .story-viewers{position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,.88);padding:14px 16px;z-index:10;border-top:1px solid rgba(255,255,255,.08);border-radius:18px 18px 0 0;}
446
  .sv-viewers-label{font-size:10px;color:rgba(255,255,255,.35);margin-bottom:8px;}
447
 
448
+ /* ── COMENTARII ── */
449
  .comments-list{flex:1;overflow-y:auto;padding:4px 0;min-height:0;}
450
+ .comment-item{display:flex;gap:10px;padding:10px 18px;}
451
  .comment-body{flex:1;min-width:0;}
452
+ .comment-uname{font-size:12px;font-weight:600;color:var(--t1);}
453
+ .comment-txt{font-size:12px;display:inline;margin-left:5px;line-height:1.55;color:var(--t2);}
454
+ .comment-actions{display:flex;gap:10px;margin-top:5px;align-items:center;}
455
+ .comment-time{font-size:10px;color:var(--t3);}
456
+ .comment-like-btn{display:flex;align-items:center;gap:3px;color:var(--t3);cursor:pointer;font-size:10px;transition:var(--t);}
457
+ .comment-like-btn:hover{color:var(--t1);}
458
  .comment-like-btn svg{width:10px;height:10px;}
459
+ .comment-reply-btn{font-size:10px;color:var(--t3);cursor:pointer;transition:var(--t);}
460
+ .comment-reply-btn:hover{color:var(--t1);}
461
+ .comment-compose{display:flex;align-items:center;gap:9px;padding:11px 16px;border-top:1px solid var(--b1);flex-shrink:0;}
462
+ .comment-field{flex:1;background:var(--s2);border:1.5px solid transparent;border-radius:22px;padding:9px 14px;color:var(--t1);font-family:var(--font);font-size:12px;outline:none;transition:var(--t);}
463
+ .comment-field:focus{border-color:var(--b3);background:var(--s3);}
464
+ .comment-field::placeholder{color:var(--t4);}
465
+ .send-icon-btn{width:33px;height:33px;border-radius:50%;background:var(--t1);display:flex;align-items:center;justify-content:center;cursor:pointer;border:none;transition:var(--t);flex-shrink:0;}
466
  .send-icon-btn:hover{opacity:.84;}
467
+ .send-icon-btn svg{width:12px;height:12px;color:#000;margin-left:1px;}
468
+
469
+ /* ── STREAK ── */
470
+ .streak-overlay{position:fixed;inset:0;z-index:600;background:rgba(0,0,0,.88);backdrop-filter:blur(20px);display:flex;align-items:center;justify-content:center;animation:fadeIn .18s;}
471
+ .streak-card{text-align:center;display:flex;flex-direction:column;align-items:center;gap:14px;animation:slideUp .3s var(--ease);background:var(--s1);border:1px solid var(--b2);border-radius:24px;padding:40px 32px;max-width:280px;width:100%;box-shadow:var(--shmd);}
472
+ .streak-emoji{font-size:62px;animation:pulse 1s infinite;}
473
+ .streak-title{font-size:26px;letter-spacing:-.5px;}
474
+ .streak-desc{font-size:12px;color:var(--t3);max-width:200px;line-height:1.65;}
475
  .streak-card .btn-primary{max-width:165px;}
476
 
477
+ /* ── CTX MENU ── */
478
+ .ctx-menu{position:fixed;z-index:9999;background:var(--s1);border:1px solid var(--b2);border-radius:var(--rsm);padding:5px;box-shadow:var(--shmd);animation:fadeInUp .12s;min-width:165px;}
479
+ .ctx-item{padding:9px 13px;border-radius:var(--rxs);cursor:pointer;font-size:12px;color:var(--t2);transition:var(--t);display:flex;align-items:center;gap:9px;}
480
+ .ctx-item:hover{background:rgba(255,255,255,.06);color:var(--t1);}
481
  .ctx-item.danger{color:#ff6b6b;}
482
  .ctx-item.danger:hover{background:rgba(255,80,80,.08);}
483
  .ctx-item svg{width:13px;height:13px;}
484
  .ctx-emoji-row{display:flex;gap:3px;padding:6px 8px;flex-wrap:wrap;}
485
 
486
+ /* ── TOAST ── */
487
+ .toast{position:fixed;bottom:74px;left:50%;transform:translateX(-50%);background:var(--t1);color:#000;padding:9px 22px;border-radius:40px;font-size:12px;font-weight:600;z-index:9999;box-shadow:var(--shmd);animation:toastIn .2s var(--ease);white-space:nowrap;}
488
 
489
+ /* ── ANIMAȚII ── */
490
  @keyframes fadeIn{from{opacity:0}to{opacity:1}}
491
  @keyframes fadeInUp{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
492
+ @keyframes slideUp{from{opacity:0;transform:translateY(20px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}
493
+ @keyframes pageFadeIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
494
+ @keyframes postFadeIn{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:translateY(0)}}
495
  @keyframes bubblePop{from{opacity:0;transform:scale(.92) translateY(5px)}to{opacity:1;transform:scale(1) translateY(0)}}
496
  @keyframes spin{to{transform:rotate(360deg)}}
497
  @keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
498
  @keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(.93)}}
499
  @keyframes toastIn{from{opacity:0;transform:translateX(-50%) translateY(8px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}
500
 
501
+ /* Badge verificat */
502
+ .v-badge{width:13px;height:13px;color:var(--t1);}