Files
animexe/resources/views/frontend/layouts/app.blade.php
T

3476 lines
149 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="tr" prefix="og: https://ogp.me/ns#">
<head>
<!-- Google AdSense -->
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9174346193739022" crossorigin="anonymous"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="#06060d">
<meta name="csrf-token" content="{{ csrf_token() }}">
@php
// SEO ayarlarını cache'den yükle
$__seo = cache()->remember('seo_settings', 3600, fn() =>
\App\Models\Setting::where('key','like','seo_%')->pluck('value','key')->toArray()
);
$__seoSite = $__seo['seo_site_name'] ?? 'Animexe';
$__seoDefDesc = $__seo['seo_home_description'] ?? 'Animexe\'de binlerce anime dizisi ve filmini Türkçe altyazılı veya dublajlı, ücretsiz HD kalitede izleyin.';
$__seoDefKw = $__seo['seo_home_keywords'] ?? 'anime izle, türkçe anime, anime dizi, anime film, ücretsiz anime';
$__seoOgImg = url($__seo['seo_og_image'] ?? '/logo.jpg');
$__seoDomain = rtrim($__seo['seo_canonical_domain'] ?? config('app.url'), '/');
$__seoCanon = $__seoDomain . '/' . ltrim(request()->path(), '/');
$__seoTwitter = $__seo['seo_twitter_site'] ?? '';
$__seoGa = $__seo['seo_google_analytics'] ?? '';
$__seoGtm = $__seo['seo_gtm_id'] ?? '';
$__seoGsc = $__seo['seo_gsc_verification'] ?? '';
$__seoBing = $__seo['seo_bing_verification'] ?? '';
$__seoYandex = $__seo['seo_yandex_verification'] ?? '';
$__seoSchema = ($__seo['seo_enable_schema'] ?? '1') === '1';
// Sayfa başlığı ve diğerleri (child template section'ları okuma)
$__pageTitle = $__env->yieldContent('title', $__seoSite . ' — Türkçe Anime İzle');
$__pageDesc = $__env->yieldContent('meta_description', $__seoDefDesc);
$__pageKw = $__env->yieldContent('meta_keywords', $__seoDefKw);
$__pageRobots = $__env->yieldContent('robots', 'index, follow');
$__pageCanon = $__env->yieldContent('canonical', $__seoCanon);
$__pageOgType = $__env->yieldContent('og_type', 'website');
$__pageOgTitle = $__env->yieldContent('og_title', $__pageTitle);
$__pageOgDesc = $__env->yieldContent('og_description', $__pageDesc);
$__pageOgImg = $__env->yieldContent('og_image', $__seoOgImg);
$__pageOgImgW = $__env->yieldContent('og_image_width', '1200');
$__pageOgImgH = $__env->yieldContent('og_image_height', '630');
@endphp
{{-- LCP Preload: sayfaya özgü kritik görseller --}}
@yield('preload')
<title>{{ $__pageTitle }}</title>
{{-- Temel Meta --}}
<meta name="description" content="{{ $__pageDesc }}">
<meta name="keywords" content="{{ $__pageKw }}">
<meta name="robots" content="{{ $__pageRobots }}">
<link rel="canonical" href="{{ $__pageCanon }}">
<link rel="alternate" hreflang="tr" href="{{ $__pageCanon }}">
<link rel="alternate" hreflang="x-default" href="{{ $__pageCanon }}">
@php $__favicon = \App\Models\Setting::get('site_favicon','') @endphp
@if($__favicon)<link rel="icon" href="{{ $__favicon }}">@else<link rel="icon" href="/favicon.png">@endif
<link rel="manifest" href="/manifest.json">
<link rel="search" type="application/opensearchdescription+xml" title="Animexe Anime Ara" href="/opensearch.xml">
{{-- Preconnect: CDN ve harici kaynaklar --}}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
<link rel="dns-prefetch" href="https://www.googletagmanager.com">
<link rel="dns-prefetch" href="https://www.google-analytics.com">
{{-- Doğrulama Etiketleri --}}
@if($__seoGsc)<meta name="google-site-verification" content="{{ $__seoGsc }}">@endif
@if($__seoBing)<meta name="msvalidate.01" content="{{ $__seoBing }}">@endif
@if($__seoYandex)<meta name="yandex-verification" content="{{ $__seoYandex }}">@endif
{{-- Open Graph --}}
<meta property="og:site_name" content="{{ $__seoSite }}">
<meta property="og:locale" content="tr_TR">
<meta property="og:type" content="{{ $__pageOgType }}">
<meta property="og:title" content="{{ $__pageOgTitle }}">
<meta property="og:description" content="{{ $__pageOgDesc }}">
<meta property="og:image" content="{{ $__pageOgImg }}">
<meta property="og:image:width" content="{{ $__pageOgImgW }}">
<meta property="og:image:height" content="{{ $__pageOgImgH }}">
<meta property="og:url" content="{{ $__pageCanon }}">
@if(!empty($__seo['seo_facebook_app_id']))<meta property="fb:app_id" content="{{ $__seo['seo_facebook_app_id'] }}">@endif
{{-- Twitter Card --}}
<meta name="twitter:card" content="summary_large_image">
@if($__seoTwitter)<meta name="twitter:site" content="{{ Str::startsWith($__seoTwitter,'@') ? $__seoTwitter : '@'.$__seoTwitter }}">@endif
<meta name="twitter:title" content="{{ $__pageOgTitle }}">
<meta name="twitter:description" content="{{ $__pageOgDesc }}">
<meta name="twitter:image" content="{{ $__pageOgImg }}">
{{-- JSON-LD: WebSite Schema (sitewide) --}}
@if($__seoSchema)
<script type="application/ld+json">
{
"@@context":"https://schema.org",
"@@type":"WebSite",
"name":"{{ $__seoSite }}",
"url":"{{ $__seoDomain }}",
"description":"{{ addslashes($__seoDefDesc) }}",
"inLanguage":"tr-TR",
"potentialAction":{
"@@type":"SearchAction",
"target":{"@@type":"EntryPoint","urlTemplate":"{{ $__seoDomain }}/search?q={search_term_string}"},
"query-input":"required name=search_term_string"
}
}
</script>
@if(!empty($__seo['seo_org_logo']) || !empty($__seo['seo_org_twitter']))
<script type="application/ld+json">
{
"@@context":"https://schema.org",
"@@type":"Organization",
"name":"{{ $__seoSite }}",
"url":"{{ $__seoDomain }}",
"logo":{"@type":"ImageObject","url":"{{ url($__seo['seo_org_logo'] ?? '/logo.jpg') }}"},
"sameAs":[
@php $sameAs = array_filter([$__seo['seo_org_twitter'] ?? null, $__seo['seo_org_facebook'] ?? null, $__seo['seo_org_instagram'] ?? null]); @endphp
@foreach(array_values($sameAs) as $i => $sa)"{{ $sa }}"{{ $i < count($sameAs)-1 ? ',' : '' }}@endforeach
]
}
</script>
@endif
@endif
{{-- Sayfaya özgü JSON-LD --}}
@yield('schema')
{{-- Google Analytics 4 --}}
@if($__seoGtm)
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','{{ $__seoGtm }}');</script>
@elseif($__seoGa)
<script async src="https://www.googletagmanager.com/gtag/js?id={{ $__seoGa }}"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','{{ $__seoGa }}');</script>
@endif
{{-- Ayris VPS Panel Analytics --}}
<script defer src="https://panel.ayris.tech/api/analytics/script" data-domain="animexe.com"></script>
<style>
/* ── Initial page load splash (inline, no FOUC) ────────────────── */
#splash{
position:fixed;inset:0;z-index:99999;
background:#06060d;
display:flex;flex-direction:column;align-items:center;justify-content:center;gap:28px;
transition:opacity .35s ease, visibility .35s ease;
}
#splash.done{ opacity:0;visibility:hidden; }
.splash-logo{
font-family:'Orbitron','system-ui',sans-serif;
font-size:clamp(1.6rem,5vw,2.4rem);font-weight:900;
letter-spacing:.22em;text-transform:uppercase;
background:linear-gradient(105deg,#fff 0%,#00f5ff 40%,#ff2d7d 100%);
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
text-shadow:none;
animation:splash-pulse 1.4s ease-in-out infinite alternate;
}
@keyframes splash-pulse{
from{ filter:drop-shadow(0 0 8px rgba(0,245,255,.4)); }
to{ filter:drop-shadow(0 0 20px rgba(255,45,125,.5)); }
}
.splash-bar-wrap{
width:min(220px,55vw);height:2px;
background:rgba(255,255,255,.08);border-radius:2px;overflow:hidden;
}
.splash-bar{
height:100%;width:0%;border-radius:2px;
background:linear-gradient(90deg,#00f5ff,#ff2d7d,#b84dff);
animation:splash-fill 1.1s cubic-bezier(.4,0,.2,1) forwards;
}
@keyframes splash-fill{ to{ width:100%; } }
.splash-dots{
display:flex;gap:7px;
}
.splash-dots span{
width:6px;height:6px;border-radius:50%;
background:#00f5ff;opacity:.25;
animation:sdot 1s ease-in-out infinite;
}
.splash-dots span:nth-child(2){ animation-delay:.18s;background:#ff2d7d; }
.splash-dots span:nth-child(3){ animation-delay:.36s;background:#b84dff; }
@keyframes sdot{
0%,100%{ opacity:.25;transform:scale(1); }
50%{ opacity:1;transform:scale(1.5); }
}
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700;800;900&family=Outfit:wght@300;400;500;600;700;800&display=swap">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<style>
/* ── Neon cyber theme ─────────────────────────────────────────── */
:root{
--bg:#06060d;
--bg2:#0a0a14;
--surface:#11111f;
--surface2:#18182a;
--border:rgba(0,245,255,.14);
--border2:rgba(255,45,125,.2);
--accent:#ff2d7d;
--accent2:#00f5ff;
--accent3:#b84dff;
--glow:rgba(0,245,255,.18);
--glow-pink:rgba(255,45,125,.25);
--text:#f0f4ff;
--text2:#9ca8d4;
--text3:#5c6789;
--nav-h:64px;
--r:10px;
--r2:14px;
--font:'Outfit',system-ui,sans-serif;
--font-display:'Orbitron',sans-serif;
--shadow-neon:0 0 32px rgba(0,245,255,.12),0 0 64px rgba(255,45,125,.08);
--shadow-card:0 4px 24px rgba(0,0,0,.45);
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;overflow-x:hidden}
body{
font-family:var(--font);font-size:15px;line-height:1.6;color:var(--text);
overflow-x:hidden;min-height:100vh;width:100%;max-width:100vw;
background-color:var(--bg);
background-image:
radial-gradient(ellipse 120% 70% at 50% -25%,rgba(184,77,255,.22),transparent 55%),
radial-gradient(ellipse 80% 50% at 100% 20%,rgba(0,245,255,.08),transparent 45%),
radial-gradient(ellipse 70% 45% at 0% 90%,rgba(255,45,125,.1),transparent 50%),
linear-gradient(180deg,#06060d 0%,#08081a 50%,#06060d 100%);
}
body::before{
content:'';position:fixed;inset:0;pointer-events:none;z-index:0;
background-image:
linear-gradient(rgba(0,245,255,.035) 1px,transparent 1px),
linear-gradient(90deg,rgba(0,245,255,.035) 1px,transparent 1px);
background-size:56px 56px;
mask-image:linear-gradient(180deg,rgba(0,0,0,.9) 0%,rgba(0,0,0,.4) 70%,transparent 100%);
}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
button,input,select{font-family:inherit}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-track{background:rgba(0,0,0,.2)}
::-webkit-scrollbar-thumb{
background:linear-gradient(180deg,rgba(0,245,255,.35),rgba(255,45,125,.35));
border-radius:8px;
}
/* ── Navbar ───────────────────────────────────────────────────── */
#topnav{
position:fixed;top:0;left:0;right:0;z-index:500;
height:var(--nav-h);
display:flex;align-items:center;gap:10px;
padding:0 22px;
background:rgba(6,6,13,.82);
backdrop-filter:blur(16px) saturate(1.2);
border-bottom:1px solid var(--border);
box-shadow:0 4px 30px rgba(0,0,0,.35),0 0 40px rgba(0,245,255,.04);
}
#topnav::after{
content:'';position:absolute;bottom:0;left:0;right:0;height:1px;
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
opacity:.45;pointer-events:none;
}
.nav-logo{
font-family:var(--font-display);
font-size:1.05rem;font-weight:800;letter-spacing:.18em;
text-transform:uppercase;
color:var(--text);
text-shadow:0 0 24px rgba(0,245,255,.5),0 0 40px rgba(255,45,125,.35);
flex-shrink:0;margin-right:12px;
background:linear-gradient(105deg,#fff 0%,var(--accent2) 40%,var(--accent) 100%);
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
background-clip:text;
}
.nav-links{display:flex;gap:4px;list-style:none}
.nav-links a{
padding:8px 14px;border-radius:var(--r);font-size:.86rem;font-weight:600;
color:var(--text2);transition:all .18s;
border:1px solid transparent;
}
.nav-links a:hover{
color:var(--accent2);
background:rgba(0,245,255,.06);
border-color:rgba(0,245,255,.2);
box-shadow:0 0 20px rgba(0,245,255,.1);
}
.nav-links a.on{
color:var(--text);
background:rgba(255,45,125,.1);
border-color:rgba(255,45,125,.35);
box-shadow:0 0 24px rgba(255,45,125,.15);
}
.nav-search{margin-left:auto;display:flex;align-items:center;gap:10px}
.ns-form{position:relative;display:flex;align-items:center}
.ns-form input{
background:rgba(17,17,31,.9);border:1px solid var(--border);border-radius:999px;
padding:9px 16px 9px 38px;color:var(--text);font-size:.85rem;
width:210px;outline:none;transition:all .22s;
}
.ns-form input:focus{
width:280px;border-color:var(--accent2);
background:rgba(0,245,255,.06);
box-shadow:0 0 0 2px rgba(0,245,255,.2),0 0 28px rgba(0,245,255,.12);
}
.ns-form input::placeholder{color:var(--text3)}
.ns-form .ns-icon{position:absolute;left:13px;color:var(--accent2);font-size:.92rem;pointer-events:none;opacity:.85}
/* ── Autocomplete dropdown ────────────────────────── */
.ns-ac{
position:absolute;top:calc(100% + 6px);left:0;right:0;
background:#0d0d1c;border:1px solid rgba(0,245,255,.22);
border-radius:14px;overflow:hidden;
box-shadow:0 16px 48px rgba(0,0,0,.7),0 0 0 1px rgba(0,245,255,.06);
z-index:9999;display:none;min-width:320px;
}
.ns-ac.show{display:block;animation:acIn .16s ease}
@keyframes acIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.ns-ac-item{
display:flex;align-items:center;gap:11px;padding:9px 14px;
cursor:pointer;transition:background .12s;text-decoration:none;
}
.ns-ac-item:hover,.ns-ac-item.focused{background:rgba(0,245,255,.07)}
.ns-ac-item img,.ns-ac-item .ns-ac-ph{
width:34px;height:48px;border-radius:5px;object-fit:cover;flex-shrink:0;
}
.ns-ac-ph{background:rgba(255,255,255,.07);display:flex;align-items:center;justify-content:center}
.ns-ac-info{flex:1;min-width:0}
.ns-ac-title{color:var(--text);font-size:.83rem;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ns-ac-meta{color:var(--text3);font-size:.72rem;margin-top:2px}
.ns-ac-type{
font-size:.65rem;font-weight:800;padding:2px 7px;border-radius:4px;
background:rgba(0,245,255,.1);color:var(--accent2);border:1px solid rgba(0,245,255,.2);flex-shrink:0;
}
.ns-ac-all{
display:block;text-align:center;padding:9px;
font-size:.78rem;color:var(--accent2);font-weight:700;
border-top:1px solid rgba(255,255,255,.06);
transition:background .12s;
}
.ns-ac-all:hover{background:rgba(0,245,255,.06)}
.nav-auth{display:flex;gap:10px;align-items:center;flex-shrink:0}
.btn-ghost{
background:rgba(17,17,31,.6);border:1px solid rgba(0,245,255,.28);color:var(--text2);
padding:8px 18px;border-radius:999px;font-size:.82rem;font-weight:600;cursor:pointer;
transition:all .18s;
}
.btn-ghost:hover{
border-color:var(--accent2);color:var(--accent2);
box-shadow:0 0 20px rgba(0,245,255,.2);
}
.btn-solid{
background:linear-gradient(135deg,var(--accent) 0%,var(--accent3) 100%);
color:#fff;border:none;
padding:8px 20px;border-radius:999px;font-size:.82rem;font-weight:700;cursor:pointer;
transition:transform .16s,box-shadow .2s;
box-shadow:0 0 24px rgba(255,45,125,.35),0 4px 16px rgba(184,77,255,.2);
}
.btn-solid:hover{transform:translateY(-1px);box-shadow:0 0 32px rgba(255,45,125,.5)}
.nav-bell{position:relative;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:50%;color:var(--text2);text-decoration:none;font-size:1.1rem;transition:color .15s,background .15s}
.nav-bell:hover{color:var(--accent2);background:rgba(0,245,255,.08)}
.bell-badge{position:absolute;top:2px;right:2px;min-width:16px;height:16px;border-radius:8px;background:var(--accent);color:#fff;font-size:.6rem;font-weight:800;display:flex;align-items:center;justify-content:center;padding:0 3px;pointer-events:none}
.nav-user{position:relative;display:flex;align-items:center;gap:8px;cursor:pointer}
.nav-avatar{
width:34px;height:34px;border-radius:50%;
background:linear-gradient(135deg,var(--accent2),var(--accent));
display:flex;align-items:center;justify-content:center;
font-size:.78rem;font-weight:800;color:#06060d;flex-shrink:0;
box-shadow:0 0 16px rgba(0,245,255,.4);
}
.nav-user-name{font-size:.82rem;font-weight:600;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav-dropdown{
position:absolute;top:100%;right:0;
background:rgba(10,10,20,.96);border:1px solid var(--border);border-radius:var(--r2);
padding:20px 8px 8px;min-width:180px;display:none;z-index:200;
box-shadow:var(--shadow-neon),0 16px 48px rgba(0,0,0,.55);
margin-top:0;
}
.nav-user:hover .nav-dropdown{display:block}
.nav-dropdown a,.nav-dropdown button{
display:flex;align-items:center;gap:8px;width:100%;
padding:10px 12px;border-radius:var(--r);color:var(--text2);font-size:.85rem;font-weight:500;
background:none;border:none;cursor:pointer;transition:all .14s;text-align:left;
}
.nav-dropdown a:hover,.nav-dropdown button:hover{
background:rgba(0,245,255,.08);color:var(--accent2);
}
.nav-dropdown .sep{height:1px;background:linear-gradient(90deg,transparent,var(--border),transparent);margin:6px 0}
.nav-ham{display:none;background:none;border:none;color:var(--accent2);font-size:1.45rem;cursor:pointer;margin-left:auto;padding:6px;filter:drop-shadow(0 0 8px rgba(0,245,255,.4))}
#mob-menu{
display:none;flex-direction:column;
position:fixed;top:var(--nav-h);left:0;right:0;
background:rgba(6,6,14,.98);backdrop-filter:blur(20px) saturate(1.4);
border-bottom:1px solid var(--border);
padding:0 0 16px;z-index:499;gap:0;
box-shadow:0 20px 60px rgba(0,0,0,.6),0 0 40px rgba(0,245,255,.04);
max-height:calc(100vh - var(--nav-h));
overflow-y:auto;
}
#mob-menu::before{
content:'';display:block;height:1px;
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
opacity:.4;flex-shrink:0;
}
#mob-menu.open{display:flex}
.mob-nav-links{padding:10px 14px 6px;display:flex;flex-direction:column;gap:2px}
#mob-menu a{
padding:12px 16px;border-radius:var(--r);color:var(--text2);font-weight:600;transition:all .14s;
border:1px solid transparent;display:flex;align-items:center;gap:10px;
}
#mob-menu a:hover{background:rgba(0,245,255,.08);border-color:rgba(0,245,255,.18);color:var(--accent2)}
#mob-menu a i{font-size:1rem;opacity:.7;width:18px;text-align:center}
.mob-divider{height:1px;background:linear-gradient(90deg,transparent,var(--border),transparent);margin:8px 14px}
.mob-search{padding:0 14px 8px;position:relative}
.mob-search input{
width:100%;background:var(--surface);border:1px solid var(--border);
border-radius:var(--r);padding:12px 16px 12px 42px;color:var(--text);font-size:.9rem;outline:none;
transition:border-color .18s;
}
.mob-search input:focus{border-color:var(--accent2);box-shadow:0 0 0 2px rgba(0,245,255,.15)}
.mob-search .ns-icon{position:absolute;left:27px;top:50%;transform:translateY(-50%);color:var(--accent2);pointer-events:none}
.mob-auth{display:flex;gap:10px;padding:6px 14px;margin-top:4px}
.mob-auth a{flex:1;text-align:center;padding:13px;border-radius:var(--r);font-size:.86rem;font-weight:700;display:flex;align-items:center;justify-content:center;gap:7px}
.mob-auth .login{background:var(--surface);color:var(--text2);border:1px solid var(--border)}
.mob-auth .login:hover{border-color:var(--accent2);color:var(--accent2)}
.mob-auth .reg{background:linear-gradient(135deg,var(--accent),var(--accent3));color:#fff;box-shadow:0 0 20px rgba(255,45,125,.3)}
.mob-user-block{padding:16px 14px 10px;display:flex;align-items:center;gap:13px;border-bottom:1px solid rgba(0,245,255,.08);margin-bottom:4px}
.mob-user-ava{
width:42px;height:42px;border-radius:50%;flex-shrink:0;
background:linear-gradient(135deg,var(--accent2),var(--accent));
display:flex;align-items:center;justify-content:center;
font-size:.9rem;font-weight:800;color:#06060d;
box-shadow:0 0 18px rgba(0,245,255,.4);
}
.mob-user-info{flex:1;min-width:0}
.mob-user-name{font-size:.9rem;font-weight:700;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mob-user-tier{font-size:.72rem;color:var(--text3);margin-top:1px}
#pg{padding-top:var(--nav-h);min-height:100vh;position:relative;z-index:1;overflow-x:hidden;max-width:100%}
.section{padding:40px 28px;max-width:1680px;margin:0 auto}
.section-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:26px}
.section-title{
font-family:var(--font-display);
font-size:clamp(1.0rem,1.8vw,1.3rem);font-weight:900;letter-spacing:.07em;text-transform:uppercase;
display:flex;align-items:center;gap:13px;color:var(--text);
}
.section-title::before{
content:'';width:4px;height:26px;
background:linear-gradient(180deg,var(--accent2),var(--accent));
border-radius:3px;
box-shadow:0 0 16px rgba(0,245,255,.7),0 0 24px rgba(255,45,125,.45);
}
.section-more{
color:var(--accent2);font-size:.82rem;font-weight:700;letter-spacing:.04em;
text-transform:uppercase;
padding:7px 14px;border-radius:8px;border:1px solid rgba(0,245,255,.3);
background:rgba(0,245,255,.04);
transition:all .18s;
}
.section-more:hover{
background:rgba(0,245,255,.1);box-shadow:0 0 20px rgba(0,245,255,.2);
text-decoration:none;
}
.a-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:20px}
.a-card{
background:linear-gradient(145deg,rgba(17,17,31,.96),rgba(10,10,20,.99));
border-radius:14px;overflow:hidden;cursor:pointer;
border:1px solid rgba(255,255,255,.07);
transition:transform .22s,box-shadow .25s,border-color .22s;
box-shadow:0 6px 28px rgba(0,0,0,.5);
}
.a-card:hover{
transform:translateY(-7px) scale(1.01);
border-color:rgba(255,45,125,.48);
box-shadow:0 20px 56px rgba(0,0,0,.6),0 0 44px rgba(255,45,125,.12),0 0 64px rgba(0,245,255,.06);
}
.a-poster{position:relative;aspect-ratio:2/3;background:var(--surface2);overflow:hidden}
.a-poster::after{
content:'';position:absolute;inset:0;pointer-events:none;
box-shadow:inset 0 0 40px rgba(0,0,0,.3);
}
/* Shine sweep on hover */
.a-poster::before{
content:'';position:absolute;inset:0;z-index:3;pointer-events:none;
background:linear-gradient(115deg,transparent 35%,rgba(255,255,255,.09) 50%,transparent 65%);
transform:translateX(-100%) skewX(-15deg);
transition:transform .65s ease;
}
.a-card:hover .a-poster::before{transform:translateX(200%) skewX(-15deg)}
.a-poster img{width:100%;height:100%;object-fit:cover;transition:transform .35s}
.a-card:hover .a-poster img{transform:scale(1.08)}
.a-no-img{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text3);font-size:2.5rem}
.a-badge{
position:absolute;top:9px;left:9px;
background:linear-gradient(135deg,var(--accent),var(--accent3));
color:#fff;font-size:.6rem;font-weight:900;padding:4px 9px;border-radius:5px;
text-transform:uppercase;letter-spacing:.08em;
box-shadow:0 0 16px rgba(255,45,125,.5);
z-index:2;
}
.a-rating{
position:absolute;top:9px;right:9px;background:rgba(6,6,13,.88);
color:#ffd60a;font-size:.68rem;font-weight:800;padding:4px 8px;border-radius:6px;
display:flex;align-items:center;gap:3px;backdrop-filter:blur(8px);
border:1px solid rgba(255,214,10,.25);
z-index:2;
}
.a-hover-play{position:absolute;inset:0;background:rgba(6,6,13,.52);display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .22s;z-index:2}
.a-card:hover .a-hover-play{opacity:1}
.play-circle{
width:52px;height:52px;border-radius:50%;
background:rgba(255,255,255,.14);backdrop-filter:blur(10px);
border:2px solid rgba(255,255,255,.55);
display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.1rem;
box-shadow:0 0 28px rgba(0,0,0,.5);
}
.a-info{padding:13px 13px}
.a-title{font-size:.88rem;font-weight:700;color:var(--text);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.a-meta{font-size:.73rem;color:var(--text3);margin-top:5px}
.h-row{display:flex;gap:14px;overflow-x:auto;padding:4px 0 12px;scrollbar-width:none}
.h-row::-webkit-scrollbar{display:none}
.h-row .a-card{flex-shrink:0;width:152px}
.ep-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px}
.ep-card{
background:linear-gradient(145deg,rgba(17,17,31,.95),rgba(10,10,20,.98));
border-radius:var(--r2);overflow:hidden;cursor:pointer;border:1px solid rgba(0,245,255,.1);
transition:transform .2s,box-shadow .22s,border-color .2s;
}
.ep-card:hover{
transform:translateY(-4px);
border-color:rgba(0,245,255,.35);
box-shadow:0 12px 36px rgba(0,0,0,.5),0 0 30px rgba(0,245,255,.1);
}
.ep-thumb{position:relative;aspect-ratio:16/9;background:var(--surface2);overflow:hidden}
.ep-thumb img{width:100%;height:100%;object-fit:cover;transition:transform .28s}
.ep-card:hover .ep-thumb img{transform:scale(1.05)}
.ep-ep-badge{
position:absolute;bottom:8px;left:8px;
background:linear-gradient(135deg,var(--accent2),var(--accent));
color:#06060d;font-size:.65rem;font-weight:900;padding:3px 9px;border-radius:6px;
box-shadow:0 0 16px rgba(0,245,255,.4);
}
.ep-play{position:absolute;inset:0;background:rgba(6,6,13,.45);display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s}
.ep-card:hover .ep-play{opacity:1}
.ep-body{padding:10px 12px}
.ep-anime-name{font-size:.7rem;color:var(--accent2);font-weight:700;margin-bottom:3px}
.ep-title{font-size:.82rem;font-weight:700;color:var(--text);display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
.ep-time{font-size:.72rem;color:var(--text3);margin-top:4px}
.genre-chip{
display:inline-flex;align-items:center;gap:5px;padding:6px 14px;border-radius:999px;
background:rgba(17,17,31,.8);border:1px solid var(--border);color:var(--text2);
font-size:.78rem;font-weight:600;transition:all .16s;cursor:pointer;
}
.genre-chip:hover,.genre-chip.on{
background:rgba(255,45,125,.12);border-color:var(--accent);color:var(--accent);
box-shadow:0 0 20px rgba(255,45,125,.2);
}
.pager{display:flex;justify-content:center;gap:8px;margin-top:36px;flex-wrap:wrap}
.pager a,.pager span{
padding:8px 14px;border-radius:var(--r);font-size:.84rem;font-weight:700;
background:var(--surface);border:1px solid var(--border);color:var(--text2);transition:all .15s;
}
.pager a:hover{background:rgba(0,245,255,.08);border-color:var(--accent2);color:var(--accent2)}
.pager .on{
background:linear-gradient(135deg,var(--accent),var(--accent3));
border-color:transparent;color:#fff;
box-shadow:0 0 20px rgba(255,45,125,.35);
}
.alert{padding:12px 18px;border-radius:var(--r);font-size:.88rem;font-weight:600;margin-bottom:16px}
.alert-err{background:rgba(255,60,90,.1);border:1px solid rgba(255,60,90,.35);color:#ff8a9a;box-shadow:0 0 20px rgba(255,60,90,.08)}
.alert-ok{background:rgba(0,245,180,.08);border:1px solid rgba(0,245,180,.3);color:#6effd0}
footer{
position:relative;z-index:1;
background:linear-gradient(180deg,rgba(6,6,16,.99),#030309);
border-top:1px solid rgba(255,255,255,.05);
padding:clamp(40px,5vw,60px) clamp(16px,4vw,40px) clamp(24px,3vw,36px);
margin-top:56px;
box-shadow:0 -20px 60px rgba(0,0,0,.4);
overflow:hidden;
}
footer::before{
content:'';position:absolute;top:0;left:5%;right:5%;height:1px;
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
opacity:.55;
}
/* Footer ambient glow */
footer::after{
content:'';position:absolute;top:-40%;left:50%;transform:translateX(-50%);
width:600px;height:300px;border-radius:50%;
background:radial-gradient(ellipse,rgba(0,245,255,.03),transparent 70%);
pointer-events:none;
}
.footer-in{max-width:1200px;margin:0 auto;display:flex;gap:40px;flex-wrap:wrap;justify-content:space-between}
.footer-brand .logo{
font-family:var(--font-display);font-size:1.15rem;font-weight:800;letter-spacing:.2em;
background:linear-gradient(105deg,#fff,var(--accent2),var(--accent));
-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:10px;
}
.footer-brand p{color:var(--text3);font-size:.84rem;max-width:280px;line-height:1.65}
.footer-col h5{
font-family:var(--font-display);font-size:.68rem;text-transform:uppercase;letter-spacing:.15em;
color:var(--accent2);font-weight:700;margin-bottom:12px;opacity:.9;
}
.footer-col ul{list-style:none;display:flex;flex-direction:column;gap:9px}
.footer-col a{color:rgba(255,255,255,.35);font-size:.84rem;font-weight:500;transition:all .16s;padding:2px 0;position:relative}
.footer-col a::after{content:'';position:absolute;bottom:0;left:0;width:0;height:1px;background:var(--accent2);transition:width .2s ease}
.footer-col a:hover{color:var(--accent2);text-shadow:0 0 14px rgba(0,245,255,.4)}
.footer-col a:hover::after{width:100%}
.footer-bottom{
max-width:1200px;margin:28px auto 0;padding-top:20px;
border-top:1px solid rgba(0,245,255,.08);
display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;color:var(--text3);font-size:.78rem;
}
/* ── Responsive ───────────────────────────────────────────────── */
@media(max-width:900px){
#topnav{padding:0 16px}
.nav-links,.nav-search,.nav-auth{display:none}
.nav-ham{display:block}
.section{padding:24px 14px}
.a-grid{grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:12px}
.h-row .a-card{width:130px}
}
@media(max-width:480px){
.a-grid{grid-template-columns:repeat(3,1fr);gap:9px}
.ep-grid{grid-template-columns:repeat(2,1fr);gap:9px}
}
/* ═══════════════════════════════════════════════════════
PREMIUM GLOBAL ENHANCEMENTS v2
═══════════════════════════════════════════════════════ */
/* ── Scroll Progress Bar ────────────────────────────── */
#scroll-progress{
position:fixed;top:0;left:0;height:2px;width:0%;z-index:10000;
background:linear-gradient(90deg,var(--accent2),var(--accent),var(--accent3));
box-shadow:0 0 10px rgba(0,245,255,.9),0 0 24px rgba(255,45,125,.6);
transition:width .08s linear;pointer-events:none;
}
/* ── Scroll To Top ──────────────────────────────────── */
#scroll-top{
position:fixed;bottom:84px;right:18px;z-index:850;
width:40px;height:40px;border-radius:50%;background:rgba(6,6,13,.92);
border:1px solid rgba(0,245,255,.3);color:var(--accent2);font-size:1rem;
cursor:pointer;display:flex;align-items:center;justify-content:center;
opacity:0;visibility:hidden;transform:translateY(10px);
transition:all .26s cubic-bezier(.22,1,.36,1);
backdrop-filter:blur(14px);
box-shadow:0 4px 20px rgba(0,0,0,.45),0 0 16px rgba(0,245,255,.1);
}
#scroll-top.show{opacity:1;visibility:visible;transform:none}
#scroll-top:hover{
background:rgba(0,245,255,.15);border-color:var(--accent2);
box-shadow:0 0 26px rgba(0,245,255,.4),0 4px 20px rgba(0,0,0,.4);
transform:translateY(-3px);
}
/* ── Scroll Reveal System ───────────────────────────── */
.reveal{
opacity:0;transform:translateY(30px);
transition:opacity .65s cubic-bezier(.22,1,.36,1),transform .65s cubic-bezier(.22,1,.36,1);
}
.reveal.visible{opacity:1;transform:none}
.reveal-d1{transition-delay:.07s}
.reveal-d2{transition-delay:.14s}
.reveal-d3{transition-delay:.21s}
.reveal-d4{transition-delay:.28s}
.reveal-d5{transition-delay:.35s}
/* Card shine effects are defined per-page */
/* ── Navbar Scroll State ────────────────────────────── */
#topnav{transition:background .3s ease,box-shadow .3s ease,height .25s ease,transform .28s cubic-bezier(.22,1,.36,1)}
#topnav.scrolled{
background:rgba(3,3,9,.97)!important;
box-shadow:0 2px 48px rgba(0,0,0,.65),0 0 60px rgba(0,245,255,.02)!important;
height:56px;
}
#topnav.scrolled .nav-logo{font-size:.92rem}
/* ── Ambient Floating Orbs ──────────────────────────── */
.amb{position:fixed;border-radius:50%;pointer-events:none;z-index:0;filter:blur(90px);will-change:transform}
.amb-1{
width:clamp(220px,28vw,420px);height:clamp(220px,28vw,420px);
background:radial-gradient(circle,rgba(0,245,255,.11),transparent 70%);
top:-5%;right:0%;
animation:amb-drift-a 20s ease-in-out infinite alternate;
}
.amb-2{
width:clamp(180px,22vw,340px);height:clamp(180px,22vw,340px);
background:radial-gradient(circle,rgba(255,45,125,.09),transparent 70%);
bottom:15%;left:-5%;
animation:amb-drift-b 25s ease-in-out infinite alternate;
}
.amb-3{
width:clamp(140px,18vw,280px);height:clamp(140px,18vw,280px);
background:radial-gradient(circle,rgba(184,77,255,.08),transparent 70%);
top:45%;right:15%;
animation:amb-drift-c 18s ease-in-out infinite alternate;
}
@keyframes amb-drift-a{from{transform:translate(0,0) scale(1)}to{transform:translate(-50px,70px) scale(1.1)}}
@keyframes amb-drift-b{from{transform:translate(0,0) scale(1)}to{transform:translate(60px,-50px) scale(1.12)}}
@keyframes amb-drift-c{from{transform:translate(0,0) scale(1)}to{transform:translate(-35px,55px) scale(1.08)}}
/* ── Mobile Bottom Navigation ───────────────────────── */
#mob-bottom-nav{
display:none;
position:fixed;bottom:0;left:0;right:0;z-index:490;
transition:transform .28s cubic-bezier(.22,1,.36,1),opacity .22s;
height:60px;
background:rgba(4,4,11,.96);
backdrop-filter:blur(28px) saturate(1.8);
border-top:1px solid rgba(255,255,255,.07);
box-shadow:0 -8px 48px rgba(0,0,0,.65),0 -4px 20px rgba(0,245,255,.03);
padding-bottom:env(safe-area-inset-bottom,0px);
}
#mob-bottom-nav::before{
content:'';position:absolute;top:0;left:8%;right:8%;height:1px;
background:linear-gradient(90deg,transparent,rgba(0,245,255,.5),rgba(255,45,125,.4),transparent);
opacity:.6;
}
.mbn-list{
display:flex;
width:100%;
height:60px;
list-style:none;
align-items:stretch;
margin:0;padding:0;
}
.mbn-list li{flex:1;display:flex;min-width:0}
.mbn-a{
flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
gap:3px;padding:6px 4px;
color:rgba(255,255,255,.28);text-decoration:none;
font-size:.54rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
position:relative;transition:color .18s;
-webkit-tap-highlight-color:transparent;
user-select:none;
min-width:0;
overflow:hidden;
white-space:nowrap;
}
.mbn-a i{
font-size:1.18rem;
transition:transform .22s cubic-bezier(.34,1.56,.64,1),filter .22s,opacity .18s;
}
.mbn-a:active i{transform:scale(.82)!important}
.mbn-a.on{color:var(--accent2)}
.mbn-a.on i{
transform:scale(1.08);
filter:drop-shadow(0 0 6px rgba(0,245,255,.85));
}
.mbn-a.on::after{
content:'';position:absolute;top:0;left:18%;right:18%;height:2px;
background:linear-gradient(90deg,var(--accent2),var(--accent));
border-radius:0 0 4px 4px;
box-shadow:0 0 10px rgba(0,245,255,.7);
}
.mbn-a.mbn-ai.on{color:var(--accent3)!important}
.mbn-a.mbn-ai.on i{filter:drop-shadow(0 0 6px rgba(184,77,255,.85))!important}
.mbn-a.mbn-ai.on::after{background:linear-gradient(90deg,var(--accent3),var(--accent))!important;box-shadow:0 0 10px rgba(184,77,255,.7)!important}
@media(max-width:900px){
#mob-bottom-nav{display:flex;flex-direction:column}
#pg{padding-bottom:calc(60px + env(safe-area-inset-bottom,0px))!important}
footer{margin-bottom:0}
#ai-fab{bottom:calc(72px + env(safe-area-inset-bottom,0px))!important;right:14px!important}
#ai-panel{bottom:calc(136px + env(safe-area-inset-bottom,0px))!important;right:8px!important;left:8px!important;width:auto!important}
#scroll-top{bottom:calc(138px + env(safe-area-inset-bottom,0px));right:14px;width:36px;height:36px;font-size:.88rem}
}
@media(max-width:480px){
.mbn-a{font-size:.5rem}
.mbn-a i{font-size:1.12rem}
}
/* ── Enhanced Genre Cards ───────────────────────────── */
.gc{overflow:hidden;position:relative}
.gc::after{
content:'';position:absolute;inset:0;
background:radial-gradient(ellipse at 10% 90%,var(--gc,#00f5ff) 0%,transparent 60%);
opacity:0;transition:opacity .28s;
}
.gc:hover::after{opacity:.1}
/* ── Home Section Headers Enhanced ─────────────────── */
.hs-hdr{position:relative}
/* ── Promo Banner Glow Pulse ────────────────────────── */
@keyframes promo-pulse{
0%,100%{transform:translate(-10%,-20%) scale(1);opacity:.6}
50%{transform:translate(15%,15%) scale(1.25);opacity:.25}
}
.promo-inner{overflow:hidden}
.promo-inner::after{
content:'';position:absolute;
width:320px;height:320px;border-radius:50%;
background:radial-gradient(circle,rgba(0,245,255,.07),transparent);
top:-80px;right:8%;
animation:promo-pulse 7s ease-in-out infinite;pointer-events:none;
}
/* ── Ticker glow on hover ───────────────────────────── */
.ticker-item a{transition:color .15s,text-shadow .15s}
.ticker-item a:hover{color:var(--accent2);text-shadow:0 0 14px rgba(0,245,255,.55)}
/* ── Footer glow line ───────────────────────────────── */
footer{position:relative}
/* ── Card hover micro-interaction enhancement ───────── */
.a-card:hover,.ep-card:hover{
border-color:rgba(255,45,125,.5);
}
/* ── Splash screen improvement ──────────────────────── */
.splash-logo{animation:splash-pulse 1.2s ease-in-out infinite alternate}
/* ── Bottom nav APK banner spacing ─────────────────── */
@media(max-width:900px){
.app-download-banner{margin-bottom:8px}
}
/* ── Custom scrollbar (webkit) enhancement ─────────── */
::-webkit-scrollbar-thumb:hover{
background:linear-gradient(180deg,rgba(0,245,255,.6),rgba(255,45,125,.6));
}
/* ════════════════════════════════════════════════════
CHAT PANEL v2
════════════════════════════════════════════════════ */
#cp-backdrop{
display:none;position:fixed;inset:0;z-index:900;
background:rgba(0,0,0,.55);backdrop-filter:blur(4px);
}
#cp-backdrop.on{display:block}
#chat-panel{
position:fixed;top:0;right:0;bottom:0;z-index:901;
width:420px;max-width:100vw;
display:flex;flex-direction:column;
background:rgba(7,7,18,.98);
border-left:1px solid rgba(0,245,255,.1);
box-shadow:-20px 0 80px rgba(0,0,0,.7),-4px 0 24px rgba(0,245,255,.04);
transform:translateX(100%);
transition:transform .32s cubic-bezier(.22,1,.36,1);
overflow:hidden;
}
#chat-panel.open{transform:translateX(0)}
/* Header */
.cp-hdr{
display:flex;align-items:center;gap:8px;
padding:12px 14px;
background:rgba(5,5,14,.9);
border-bottom:1px solid rgba(255,255,255,.07);
flex-shrink:0;
}
.cp-hdr-title{font-size:.98rem;font-weight:800;color:#fff;flex:1}
.cp-hdr-close,.cp-hdr-back,.cp-hdr-call{
width:32px;height:32px;border-radius:8px;
background:rgba(255,255,255,.07);border:none;
color:rgba(255,255,255,.5);font-size:.9rem;
cursor:pointer;display:flex;align-items:center;justify-content:center;
transition:all .15s;flex-shrink:0;
}
.cp-hdr-close:hover,.cp-hdr-back:hover{background:rgba(255,255,255,.14);color:#fff}
.cp-hdr-call{color:#22c55e}
.cp-hdr-call:hover{background:rgba(34,197,94,.2);color:#22c55e}
.cp-hdr-ava{
width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0;
background:linear-gradient(135deg,var(--accent2),var(--accent));
display:flex;align-items:center;justify-content:center;
font-size:.75rem;font-weight:800;color:#fff;
}
.cp-hdr-ava img{width:100%;height:100%;object-fit:cover}
.cp-hdr-name{font-size:.88rem;font-weight:700;color:#fff;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Conversation list */
#cp-list{display:flex;flex-direction:column;flex:1;min-height:0}
#cp-convs{flex:1;overflow-y:auto;padding:8px}
#cp-convs::-webkit-scrollbar{width:3px}
#cp-convs::-webkit-scrollbar-thumb{background:rgba(255,255,255,.1);border-radius:2px}
.cp-conv-item{
display:flex;align-items:center;gap:12px;
padding:11px 12px;border-radius:12px;cursor:pointer;
transition:background .15s;position:relative;
border:1px solid transparent;
}
.cp-conv-item:hover{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.07)}
.cp-conv-item.unread{background:rgba(0,245,255,.04);border-color:rgba(0,245,255,.1)}
.cp-conv-ava{
width:44px;height:44px;border-radius:50%;overflow:hidden;flex-shrink:0;
background:linear-gradient(135deg,var(--accent2),var(--accent));
display:flex;align-items:center;justify-content:center;
font-size:1rem;font-weight:800;color:#fff;
}
.cp-conv-ava img{width:100%;height:100%;object-fit:cover}
.cp-conv-body{flex:1;min-width:0}
.cp-conv-name{font-size:.88rem;font-weight:700;color:#fff;margin-bottom:3px}
.cp-conv-preview{font-size:.76rem;color:rgba(255,255,255,.35);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cp-conv-item.unread .cp-conv-preview{color:rgba(255,255,255,.65)}
.cp-conv-meta{display:flex;flex-direction:column;align-items:flex-end;gap:5px;flex-shrink:0}
.cp-conv-time{font-size:.65rem;color:rgba(255,255,255,.2)}
.cp-unread-badge{
min-width:18px;height:18px;border-radius:9px;
background:var(--accent2);color:#05050e;
font-size:.58rem;font-weight:900;
display:flex;align-items:center;justify-content:center;
padding:0 4px;
}
.cp-new-btn{
margin:12px;padding:11px;border-radius:12px;border:1px dashed rgba(0,245,255,.2);
background:rgba(0,245,255,.04);color:var(--accent2);
font-size:.82rem;font-weight:700;cursor:pointer;text-align:center;
transition:all .15s;text-decoration:none;display:block;
}
.cp-new-btn:hover{background:rgba(0,245,255,.1);border-color:rgba(0,245,255,.4)}
.cp-empty{padding:40px 20px;text-align:center;color:rgba(255,255,255,.2);font-size:.84rem}
.cp-empty i{font-size:2rem;display:block;margin-bottom:10px;opacity:.2}
/* Thread view */
#cp-thread{display:none;flex-direction:column;flex:1;min-height:0}
#cp-thread.active{display:flex}
#cp-msgs{
flex:1;overflow-y:auto;
padding:14px 14px 8px;
display:flex;flex-direction:column;gap:4px;
-webkit-overflow-scrolling:touch;
}
#cp-msgs::-webkit-scrollbar{width:3px}
#cp-msgs::-webkit-scrollbar-thumb{background:rgba(255,255,255,.08);border-radius:2px}
.cpm{display:flex;gap:8px;max-width:86%;align-items:flex-end}
.cpm.mine{align-self:flex-end;flex-direction:row-reverse}
.cpm.theirs{align-self:flex-start}
.cpm-ava{
width:26px;height:26px;border-radius:50%;overflow:hidden;flex-shrink:0;
background:linear-gradient(135deg,var(--accent2),var(--accent));
display:flex;align-items:center;justify-content:center;
font-size:.6rem;font-weight:800;color:#fff;
}
.cpm-ava img{width:100%;height:100%;object-fit:cover}
.cpm.mine .cpm-ava{display:none}
.cpm-bubble{
padding:9px 13px;border-radius:18px;
font-size:.86rem;line-height:1.5;word-break:break-word;
}
.cpm.mine .cpm-bubble{
background:linear-gradient(135deg,var(--accent2),#00d4de);
color:#05050e;font-weight:600;
border-bottom-right-radius:4px;
}
.cpm.theirs .cpm-bubble{
background:rgba(255,255,255,.09);
border:1px solid rgba(255,255,255,.08);
color:rgba(255,255,255,.9);
border-bottom-left-radius:4px;
}
.cpm-time{font-size:.58rem;color:rgba(255,255,255,.22);align-self:flex-end;margin-bottom:2px;flex-shrink:0}
.cp-date-sep{
text-align:center;font-size:.62rem;color:rgba(255,255,255,.2);
padding:10px 0 4px;font-weight:600;letter-spacing:.06em;
}
/* Media messages */
.cpm-img{
max-width:200px;max-height:200px;border-radius:12px;
cursor:pointer;display:block;object-fit:cover;
transition:opacity .15s;
}
.cpm-img:hover{opacity:.88}
.cpm-gif{
max-width:200px;border-radius:12px;display:block;
}
/* Share card in panel */
.cp-share-card{
display:flex;gap:10px;align-items:flex-start;
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.18);
border-radius:12px;padding:9px 11px;text-decoration:none;max-width:240px;
transition:all .15s;
}
.cp-share-card:hover{background:rgba(0,245,255,.12);border-color:rgba(0,245,255,.35)}
.cp-share-img{width:50px;height:70px;border-radius:7px;overflow:hidden;flex-shrink:0;background:rgba(255,255,255,.05)}
.cp-share-img img{width:100%;height:100%;object-fit:cover;display:block}
.cp-share-title{font-size:.78rem;font-weight:800;color:#fff;line-height:1.3;margin-bottom:2px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.cp-share-ep{font-size:.68rem;color:rgba(255,255,255,.45)}
.cp-share-play{font-size:.66rem;color:var(--accent2);display:flex;align-items:center;gap:3px;margin-top:4px;font-weight:700}
/* Input area */
#cp-input-wrap{
padding:8px 10px;
background:rgba(5,5,14,.95);
border-top:1px solid rgba(255,255,255,.07);
flex-shrink:0;
padding-bottom:max(8px,env(safe-area-inset-bottom));
}
.cp-toolbar{
display:flex;align-items:center;gap:6px;
padding:6px 0 8px;
border-bottom:1px solid rgba(255,255,255,.06);
margin-bottom:6px;
}
.cp-tool-btn{
width:38px;height:38px;border-radius:10px;border:none;
background:rgba(255,255,255,.06);color:rgba(255,255,255,.4);
font-size:.88rem;cursor:pointer;
display:flex;align-items:center;justify-content:center;
transition:all .15s;flex-shrink:0;
}
.cp-tool-btn:hover{background:rgba(255,255,255,.13);color:#fff}
.cp-tool-btn.active{background:rgba(0,245,255,.12);color:var(--accent2)}
.cp-form{display:flex;align-items:flex-end;gap:8px}
#cp-textarea{
flex:1;background:rgba(255,255,255,.08);
border:1px solid rgba(255,255,255,.1);border-radius:20px;
padding:10px 14px;color:#fff;font-size:.88rem;font-family:inherit;
resize:none;max-height:100px;overflow-y:auto;min-height:40px;
line-height:1.4;outline:none;-webkit-appearance:none;
transition:border-color .15s;
}
#cp-textarea:focus{border-color:rgba(0,245,255,.35)}
#cp-textarea::placeholder{color:rgba(255,255,255,.22)}
#cp-send-btn{
width:40px;height:40px;border-radius:50%;flex-shrink:0;
background:linear-gradient(135deg,var(--accent2),#00c6d4);
border:none;color:#05050e;font-size:.95rem;cursor:pointer;
display:flex;align-items:center;justify-content:center;
transition:all .15s;
}
#cp-send-btn:hover{transform:scale(1.08);box-shadow:0 0 16px rgba(0,245,255,.5)}
#cp-send-btn:disabled{opacity:.35;transform:none;cursor:default}
/* Emoji picker */
#cp-emoji-picker{
display:none;
background:rgba(10,10,22,.98);border:1px solid rgba(255,255,255,.1);
border-radius:14px;padding:10px;
max-height:180px;overflow-y:auto;
margin-bottom:6px;
scrollbar-width:thin;
}
#cp-emoji-picker.show{display:flex;flex-wrap:wrap;gap:2px}
.cp-emoji-btn{
font-size:1.3rem;width:36px;height:36px;
display:flex;align-items:center;justify-content:center;
border:none;background:none;cursor:pointer;border-radius:8px;
transition:background .12s;
}
.cp-emoji-btn:hover{background:rgba(255,255,255,.1)}
/* GIF picker */
#cp-gif-picker{
display:none;
background:rgba(10,10,22,.98);border:1px solid rgba(255,255,255,.1);
border-radius:14px;padding:8px;
margin-bottom:6px;
}
#cp-gif-picker.show{display:block}
.cp-gif-search{
width:100%;padding:8px 12px;border-radius:10px;
background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);
color:#fff;font-size:.82rem;font-family:inherit;outline:none;
margin-bottom:8px;
}
.cp-gif-search::placeholder{color:rgba(255,255,255,.3)}
.cp-gif-grid{
display:grid;grid-template-columns:repeat(3,1fr);gap:4px;
max-height:160px;overflow-y:auto;
}
.cp-gif-item{
aspect-ratio:1;background:rgba(255,255,255,.05);border-radius:8px;
overflow:hidden;cursor:pointer;transition:opacity .15s;
}
.cp-gif-item:hover{opacity:.8}
.cp-gif-item img{width:100%;height:100%;object-fit:cover;display:block}
.cp-gif-placeholder{
padding:20px;text-align:center;color:rgba(255,255,255,.25);font-size:.78rem;
}
/* Loading skeleton */
.cp-loading{padding:20px;text-align:center;color:rgba(255,255,255,.2);font-size:.82rem}
/* Mobile nav chat button */
.mbn-a.mbn-chat.on{color:var(--accent2)}
.mbn-a.mbn-chat.on i{filter:drop-shadow(0 0 6px rgba(0,245,255,.85))}
.mbn-a.mbn-chat.on::after{background:linear-gradient(90deg,var(--accent2),var(--accent))}
.mbn-chat-badge{
position:absolute;top:4px;right:calc(50% - 14px);
min-width:14px;height:14px;border-radius:7px;
background:var(--accent);color:#fff;
font-size:.5rem;font-weight:900;
display:flex;align-items:center;justify-content:center;
padding:0 3px;
}
@media(max-width:900px){
#chat-panel{
width:100vw;border-left:none;border-top:1px solid rgba(0,245,255,.1);
top:0;
}
}
/* ════════════════════════════════════════════════════
INCOMING CALL OVERLAY
════════════════════════════════════════════════════ */
#call-overlay{
display:none;
position:fixed;inset:0;z-index:99998;
background:rgba(0,0,0,.88);backdrop-filter:blur(20px);
align-items:center;justify-content:center;flex-direction:column;
gap:24px;
}
#call-overlay.show{display:flex}
.call-ava{
width:90px;height:90px;border-radius:50%;
background:linear-gradient(135deg,var(--accent2),var(--accent));
display:flex;align-items:center;justify-content:center;
font-size:2rem;font-weight:800;color:#fff;overflow:hidden;
box-shadow:0 0 0 8px rgba(0,245,255,.15),0 0 0 16px rgba(0,245,255,.07);
animation:call-ring 1.4s ease-in-out infinite;
}
.call-ava img{width:100%;height:100%;object-fit:cover}
@keyframes call-ring{
0%,100%{box-shadow:0 0 0 8px rgba(0,245,255,.15),0 0 0 16px rgba(0,245,255,.07)}
50%{box-shadow:0 0 0 14px rgba(0,245,255,.2),0 0 0 28px rgba(0,245,255,.06)}
}
.call-name{font-size:1.4rem;font-weight:800;color:#fff;text-align:center}
.call-status{font-size:.88rem;color:rgba(255,255,255,.5);text-align:center}
.call-btns{display:flex;gap:28px;margin-top:8px}
.call-btn{
width:64px;height:64px;border-radius:50%;border:none;cursor:pointer;
display:flex;align-items:center;justify-content:center;
font-size:1.5rem;color:#fff;transition:transform .15s,box-shadow .15s;
}
.call-btn:active{transform:scale(.92)}
.call-btn-accept{
background:linear-gradient(135deg,#22c55e,#16a34a);
box-shadow:0 0 32px rgba(34,197,94,.55);
}
.call-btn-accept:hover{box-shadow:0 0 44px rgba(34,197,94,.7)}
.call-btn-decline{
background:linear-gradient(135deg,#ef4444,#dc2626);
box-shadow:0 0 32px rgba(239,68,68,.55);
}
.call-btn-decline:hover{box-shadow:0 0 44px rgba(239,68,68,.7)}
.call-btn-end{
background:linear-gradient(135deg,#ef4444,#dc2626);
box-shadow:0 0 32px rgba(239,68,68,.55);
}
/* Active call bar (small, top of screen) */
#call-bar{
display:none;
position:fixed;top:64px;left:50%;transform:translateX(-50%);z-index:99997;
background:rgba(34,197,94,.15);border:1px solid rgba(34,197,94,.4);
border-radius:999px;padding:8px 18px;
align-items:center;gap:10px;
backdrop-filter:blur(12px);
box-shadow:0 4px 20px rgba(0,0,0,.4);
}
#call-bar.show{display:flex}
.call-bar-dot{
width:8px;height:8px;border-radius:50%;background:#22c55e;
animation:call-dot-pulse 1s ease-in-out infinite;
}
@keyframes call-dot-pulse{0%,100%{opacity:1}50%{opacity:.3}}
.call-bar-name{font-size:.82rem;font-weight:700;color:#fff}
.call-bar-timer{font-size:.78rem;color:rgba(255,255,255,.6);min-width:40px}
.call-bar-end{
padding:4px 12px;border-radius:999px;border:none;cursor:pointer;
background:rgba(239,68,68,.8);color:#fff;font-size:.75rem;font-weight:700;
transition:background .15s;
}
.call-bar-end:hover{background:#ef4444}
</style>
<link rel="stylesheet" href="/css/premium-cosmetics.css">
@stack('styles')
</head>
<body @auth @if(auth()->user()->entry_effect && auth()->user()->hasPerk('entry_effect'))class="entry-{{ auth()->user()->entry_effect }}"@endif @endauth>
{{-- Ambient floating orbs (CSS animated, no perf cost) --}}
<div class="amb amb-1" aria-hidden="true"></div>
<div class="amb amb-2" aria-hidden="true"></div>
<div class="amb amb-3" aria-hidden="true"></div>
{{-- Scroll progress bar --}}
<div id="scroll-progress" aria-hidden="true"></div>
{{-- Scroll to top button --}}
<button id="scroll-top" aria-label="Başa dön" title="Başa dön">
<i class="bi bi-chevron-up"></i>
</button>
<div id="splash">
<div class="splash-logo">ANIMEXE</div>
<div class="splash-bar-wrap"><div class="splash-bar"></div></div>
<div class="splash-dots"><span></span><span></span><span></span></div>
</div>
<nav id="topnav">
<a href="{{ route('home') }}" class="nav-logo">ANIMEXE</a>
<ul class="nav-links">
<li><a href="{{ route('home') }}" class="{{ request()->routeIs('home') ? 'on' : '' }}">Ana Sayfa</a></li>
<li><a href="{{ route('search') }}?type=series" class="{{ request()->is('search') && request('type')=='series' ? 'on' : '' }}">Diziler</a></li>
<li><a href="{{ route('search') }}?type=movie" class="{{ request()->is('search') && request('type')=='movie' ? 'on' : '' }}">Filmler</a></li>
<li><a href="{{ route('blog.index') }}" class="{{ request()->routeIs('blog.*') ? 'on' : '' }}"><i class="bi bi-journal-richtext" style="margin-right:4px"></i>Blog</a></li>
<li><a href="{{ route('anime.request') }}" class="{{ request()->routeIs('anime.request*') ? 'on' : '' }}"><i class="bi bi-plus-circle" style="margin-right:4px"></i>İstek</a></li>
<li><a href="{{ route('tribunal.index') }}" class="{{ request()->routeIs('tribunal.*') ? 'on' : '' }}" style="color:#ff9f0a;border-color:rgba(255,159,10,.2)"><i class="bi bi-balance" style="margin-right:4px"></i>Mahkeme</a></li>
<li><a href="{{ route('premium.plans') }}" class="{{ request()->routeIs('premium.*') ? 'on' : '' }}" style="color:#ffd700;border-color:rgba(255,215,0,.2)"><i class="bi bi-stars" style="margin-right:4px"></i>Premium</a></li>
@php $navShowMessages = \App\Models\Setting::get('nav_show_messages', '1'); @endphp
@if($navShowMessages)
<li><a href="{{ route('messages.index') }}" class="{{ request()->routeIs('messages.*') ? 'on' : '' }}" style="color:var(--accent2);border-color:rgba(0,245,255,.2)"><i class="bi bi-chat-dots" style="margin-right:4px"></i>Mesajlar @auth @if($unreadMsgCount??0)<span style="background:var(--accent2);color:#05050e;border-radius:8px;padding:0 5px;font-size:.6rem;font-weight:800;margin-left:2px">{{ $unreadMsgCount }}</span>@endif @endauth</a></li>
@else
<li><a href="{{ route('ai.index') }}" class="{{ request()->routeIs('ai.*') ? 'on' : '' }}" style="color:var(--accent3);border-color:rgba(184,77,255,.3)"><i class="bi bi-stars" style="margin-right:4px"></i>AI @guest<i class="bi bi-lock-fill" style="font-size:.6rem;opacity:.7"></i>@endguest</a></li>
@endif
</ul>
<div class="nav-search">
<form action="{{ route('search') }}" method="GET" class="ns-form" id="ns-form">
<i class="bi bi-search ns-icon"></i>
<input type="text" name="q" id="ns-input" placeholder="Anime ara..." value="{{ request('q') }}" autocomplete="off">
<div class="ns-ac" id="ns-ac" role="listbox"></div>
</form>
</div>
<div class="nav-auth">
@auth
@php
$unreadNotifCount = \App\Models\UserNotification::where('user_id', auth()->id())->whereNull('read_at')->count();
$unreadMsgCount = 0;
try {
foreach(auth()->user()->conversations()->with('messages')->get() as $_conv) {
$unreadMsgCount += $_conv->unreadCountFor(auth()->id());
}
} catch(\Throwable $e) {}
@endphp
<button class="nav-bell" id="cp-nav-btn" onclick="chatPanelToggle()" title="Mesajlar" style="background:none;border:none;cursor:pointer;position:relative">
<i class="bi bi-chat-dots{{ $unreadMsgCount ? '-fill' : '' }}" id="cp-nav-icon"></i>
<span class="bell-badge" id="cp-nav-badge" style="{{ $unreadMsgCount ? '' : 'display:none' }}">{{ $unreadMsgCount > 9 ? '9+' : $unreadMsgCount }}</span>
</button>
<a href="{{ route('notifications') }}" class="nav-bell" title="Bildirimler">
<i class="bi bi-bell{{ $unreadNotifCount ? '-fill' : '' }}"></i>
@if($unreadNotifCount)<span class="bell-badge">{{ $unreadNotifCount > 9 ? '9+' : $unreadNotifCount }}</span>@endif
</a>
<div class="nav-user">
<div class="nav-avatar">{{ mb_substr(auth()->user()->name,0,1) }}</div>
<span class="nav-user-name d-none d-md-block">{{ auth()->user()->name }}</span>
<div class="nav-dropdown">
<a href="{{ route('profile') }}"><i class="bi bi-person"></i> Profilim</a>
<a href="{{ route('messages.index') }}"><i class="bi bi-chat-dots"></i> Mesajlar @if($unreadMsgCount)<span style="background:var(--accent2);color:#05050e;border-radius:10px;padding:1px 6px;font-size:.65rem;margin-left:4px">{{ $unreadMsgCount }}</span>@endif</a>
<a href="{{ route('notifications') }}"><i class="bi bi-bell"></i> Bildirimler @if($unreadNotifCount)<span style="background:var(--accent);color:#fff;border-radius:10px;padding:1px 6px;font-size:.65rem;margin-left:4px">{{ $unreadNotifCount }}</span>@endif</a>
<a href="{{ route('capsules.index') }}"><i class="bi bi-hourglass-split"></i> Kapsüllerim</a>
@if(auth()->user()->isPremium())
<a href="{{ route('profile.settings') }}" style="color:#ffd700"><i class="bi bi-stars"></i> Kozmetik Ayarları</a>
@else
<a href="{{ route('premium.plans') }}" style="color:#ffd700"><i class="bi bi-stars"></i> Premium'a Geç ✨</a>
@endif
@if(auth()->user()->role === 'admin')
<a href="{{ route('admin.dashboard') }}"><i class="bi bi-speedometer2"></i> Admin Panel</a>
@endif
<div class="sep"></div>
<form action="{{ route('frontend.logout') }}" method="POST" style="display:block">
@csrf
<button type="submit"><i class="bi bi-box-arrow-right"></i> Çıkış Yap</button>
</form>
</div>
</div>
@else
<a href="{{ route('frontend.login') }}" class="btn-ghost">Giriş Yap</a>
<a href="{{ route('frontend.register') }}" class="btn-solid">Üye Ol</a>
@endauth
</div>
<button class="nav-ham" id="ham-btn"><i class="bi bi-list"></i></button>
</nav>
<div id="mob-menu">
@auth
<div class="mob-user-block">
<div class="mob-user-ava">{{ mb_substr(auth()->user()->name,0,1) }}</div>
<div class="mob-user-info">
<div class="mob-user-name">{{ auth()->user()->name }}</div>
<div class="mob-user-tier">{{ auth()->user()->isPremium() ? ' Premium Üye' : 'Standart Üye' }}</div>
</div>
</div>
@endauth
<div class="mob-search">
<i class="bi bi-search ns-icon"></i>
<form action="{{ route('search') }}" method="GET">
<input type="text" name="q" placeholder="Anime ara..." value="{{ request('q') }}">
</form>
</div>
<div class="mob-nav-links">
<a href="{{ route('home') }}"><i class="bi bi-house"></i> Ana Sayfa</a>
<a href="{{ route('search') }}?type=series"><i class="bi bi-tv"></i> Anime Diziler</a>
<a href="{{ route('search') }}?type=movie"><i class="bi bi-film"></i> Anime Filmler</a>
<a href="{{ route('search') }}"><i class="bi bi-grid"></i> Tüm Animeler</a>
<a href="{{ route('blog.index') }}"><i class="bi bi-journal-richtext"></i> Blog</a>
<a href="{{ route('anime.request') }}"><i class="bi bi-plus-circle"></i> Anime İsteği</a>
<a href="{{ route('premium.plans') }}" style="color:#ffd700"><i class="bi bi-stars"></i> Premium</a>
@if($navShowMessages ?? \App\Models\Setting::getValue('nav_show_messages','1'))
<a href="{{ route('messages.index') }}" style="color:var(--accent2)"><i class="bi bi-chat-dots"></i> Mesajlar @auth @if($unreadMsgCount??0)<span style="background:var(--accent2);color:#05050e;border-radius:8px;padding:0 5px;font-size:.6rem;font-weight:800;margin-left:2px">{{ $unreadMsgCount }}</span>@endif @endauth</a>
@else
<a href="{{ route('ai.index') }}" style="color:var(--accent3)"><i class="bi bi-stars"></i> AI Asistan @guest<i class="bi bi-lock-fill" style="font-size:.65rem;opacity:.7"></i>@endguest</a>
@endif
</div>
@auth
<div class="mob-divider"></div>
<div class="mob-nav-links">
<a href="{{ route('profile') }}"><i class="bi bi-person-circle"></i> Profilim</a>
<a href="{{ route('messages.index') }}"><i class="bi bi-chat-dots"></i> Mesajlar @if($unreadMsgCount ?? 0)<span style="background:var(--accent2);color:#05050e;border-radius:10px;padding:1px 7px;font-size:.65rem;margin-left:4px">{{ $unreadMsgCount }}</span>@endif</a>
<a href="{{ route('notifications') }}"><i class="bi bi-bell"></i> Bildirimler @if($unreadNotifCount ?? 0)<span style="background:var(--accent);color:#fff;border-radius:10px;padding:1px 7px;font-size:.65rem;margin-left:4px">{{ $unreadNotifCount }}</span>@endif</a>
@if(auth()->user()->role==='admin')
<a href="{{ route('admin.dashboard') }}" style="color:var(--accent2)"><i class="bi bi-speedometer2"></i> Admin Panel</a>
@endif
<form action="{{ route('frontend.logout') }}" method="POST" style="display:block">
@csrf
<button type="submit" style="width:100%;text-align:left;padding:12px 16px;border-radius:var(--r);background:none;border:none;color:rgba(255,90,90,.85);font-weight:600;font-family:inherit;cursor:pointer;font-size:inherit;display:flex;align-items:center;gap:10px"><i class="bi bi-box-arrow-right" style="width:18px;text-align:center;opacity:.7"></i> Çıkış Yap</button>
</form>
</div>
@else
<div class="mob-auth">
<a href="{{ route('frontend.login') }}" class="login"><i class="bi bi-box-arrow-in-right"></i> Giriş Yap</a>
<a href="{{ route('frontend.register') }}" class="reg"><i class="bi bi-person-plus"></i> Üye Ol</a>
</div>
@endauth
</div>
{{-- ═══════════════════════════════════════════════════════
MOBİL ALT NAVİGASYON ÇUBUĞU (90% mobil ziyaretçi)
════════════════════════════════════════════════════════ --}}
<nav id="mob-bottom-nav" aria-label="Alt Navigasyon">
<ul class="mbn-list">
<li>
<a href="{{ route('home') }}"
class="mbn-a {{ request()->routeIs('home') ? 'on' : '' }}"
aria-label="Ana Sayfa">
<i class="bi bi-house{{ request()->routeIs('home') ? '-fill' : '' }}"></i>
<span>Anasayfa</span>
</a>
</li>
<li>
<a href="{{ route('search') }}"
class="mbn-a {{ request()->routeIs('search') && !request('type') ? 'on' : '' }}"
aria-label="Keşfet">
<i class="bi bi-compass{{ request()->routeIs('search') && !request('type') ? '-fill' : '' }}"></i>
<span>Keşfet</span>
</a>
</li>
<li>
<a href="{{ route('search') }}?type=series"
class="mbn-a {{ request()->routeIs('search') && request('type')==='series' ? 'on' : '' }}"
aria-label="Diziler">
<i class="bi bi-play-circle{{ request()->routeIs('search') && request('type')==='series' ? '-fill' : '' }}"></i>
<span>Diziler</span>
</a>
</li>
<li>
@auth
<button onclick="chatPanelToggle()"
class="mbn-a mbn-chat {{ request()->routeIs('messages.*') ? 'on' : '' }}"
aria-label="Mesajlar" style="background:none;border:none;width:100%;position:relative">
<i class="bi bi-chat-dots{{ ($unreadMsgCount??0) ? '-fill' : '' }}"></i>
@if($unreadMsgCount??0)<span class="mbn-chat-badge">{{ ($unreadMsgCount??0) > 9 ? '9+' : ($unreadMsgCount??0) }}</span>@endif
<span>Chat</span>
</button>
@else
<a href="{{ route('ai.index') }}"
class="mbn-a mbn-ai {{ request()->routeIs('ai.*') ? 'on' : '' }}"
aria-label="AI Asistan">
<i class="bi bi-stars"></i>
<span>AI</span>
</a>
@endauth
</li>
<li>
@auth
<a href="{{ route('profile') }}"
class="mbn-a {{ request()->routeIs('profile*') ? 'on' : '' }}"
aria-label="Profilim">
<i class="bi bi-person{{ request()->routeIs('profile*') ? '-fill' : '' }}"></i>
<span>Profil</span>
</a>
@else
<a href="{{ route('frontend.register') }}"
class="mbn-a {{ request()->routeIs('frontend.register') ? 'on' : '' }}"
aria-label="Üye Ol">
<i class="bi bi-person-plus{{ request()->routeIs('frontend.register') ? '-fill' : '' }}"></i>
<span>Üye Ol</span>
</a>
@endauth
</li>
</ul>
</nav>
{{-- ════════════════════════════════════════════════════
CHAT PANEL (site genelinde erişilebilir)
════════════════════════════════════════════════════ --}}
<div id="cp-backdrop" onclick="chatPanelClose()"></div>
<div id="chat-panel">
{{-- Konuşma listesi --}}
<div id="cp-list">
<div class="cp-hdr">
<span class="cp-hdr-title"><i class="bi bi-chat-dots-fill" style="color:var(--accent2);margin-right:8px"></i>Mesajlar</span>
<a href="{{ route('messages.index') }}" class="cp-hdr-close" title="Tam sayfa aç" style="text-decoration:none;font-size:.8rem">
<i class="bi bi-box-arrow-up-right"></i>
</a>
<button class="cp-hdr-close" onclick="chatPanelClose()" title="Kapat">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div id="cp-convs">
<div class="cp-loading"><i class="bi bi-hourglass" style="font-size:1.2rem;display:block;margin-bottom:6px;opacity:.3"></i>Yükleniyor…</div>
</div>
<a href="{{ route('messages.index') }}" class="cp-new-btn">
<i class="bi bi-plus-circle"></i> Tüm Mesajlar / Yeni Sohbet
</a>
</div>
{{-- Sohbet ekranı --}}
<div id="cp-thread">
<div class="cp-hdr">
<button class="cp-hdr-back" onclick="cpShowList()"><i class="bi bi-arrow-left"></i></button>
<div class="cp-hdr-ava" id="cp-t-ava"></div>
<div style="flex:1;min-width:0">
<div class="cp-hdr-name" id="cp-t-name"></div>
</div>
@auth
<button class="cp-hdr-call" id="cp-t-call-btn" onclick="cpStartCall()" title="Sesli ara">
<i class="bi bi-telephone-fill"></i>
</button>
@endauth
<a id="cp-t-fulllink" href="#" class="cp-hdr-close" style="text-decoration:none;font-size:.8rem" title="Tam sayfada aç">
<i class="bi bi-box-arrow-up-right"></i>
</a>
<button class="cp-hdr-close" onclick="chatPanelClose()"><i class="bi bi-x-lg"></i></button>
</div>
<div id="cp-msgs"></div>
<div id="cp-input-wrap">
{{-- Emoji picker (desktop only) --}}
<div id="cp-emoji-picker"></div>
{{-- GIF picker --}}
<div id="cp-gif-picker">
<input type="text" class="cp-gif-search" id="cp-gif-input" placeholder="GIF ara…">
<div class="cp-gif-grid" id="cp-gif-grid">
<div class="cp-gif-placeholder">GIF aramak için yazmaya başla</div>
</div>
</div>
{{-- Toolbar: only desktop emoji + both gif/image --}}
<div class="cp-toolbar">
<button class="cp-tool-btn" id="cp-emoji-btn" onclick="cpToggleEmoji()" title="Emoji" style="display:none">
<i class="bi bi-emoji-smile"></i>
</button>
<button class="cp-tool-btn" id="cp-gif-btn" onclick="cpToggleGif()" title="GIF">
<span style="font-size:.65rem;font-weight:800;letter-spacing:.03em">GIF</span>
</button>
<label class="cp-tool-btn" title="Resim gönder" style="cursor:pointer">
<i class="bi bi-image"></i>
<input type="file" id="cp-img-input" accept="image/*" style="display:none" onchange="cpSendImage(this)">
</label>
<div style="flex:1"></div>
</div>
<div class="cp-form">
<textarea id="cp-textarea" placeholder="Mesaj yaz…" rows="1" maxlength="2000"></textarea>
<button id="cp-send-btn" onclick="cpSend()"><i class="bi bi-send-fill"></i></button>
</div>
</div>
</div>
</div>
{{-- ═══ INCOMING CALL OVERLAY ════════════════════════════════════════════════ --}}
<div id="call-overlay">
<div class="call-ava" id="call-ava-el"></div>
<div class="call-name" id="call-name-el"></div>
<div class="call-status" id="call-status-el">Sesli arama…</div>
<div class="call-btns" id="call-btns-el">
<button class="call-btn call-btn-decline" onclick="vcDecline()" title="Reddet">
<i class="bi bi-telephone-x-fill"></i>
</button>
<button class="call-btn call-btn-accept" onclick="vcAnswer()" title="Kabul et">
<i class="bi bi-telephone-fill"></i>
</button>
</div>
</div>
{{-- Active call bar --}}
<div id="call-bar">
<div class="call-bar-dot"></div>
<span class="call-bar-name" id="call-bar-name"></span>
<span class="call-bar-timer" id="call-bar-timer">00:00</span>
<button class="call-bar-end" onclick="vcEnd()">Kapat</button>
</div>
<div id="page-content">@yield('content')</div>
<footer>
<div class="footer-in">
<div class="footer-brand">
<div class="logo">ANIMEXE</div>
<p>Türkçe altyazılı ve dublajlı anime topluluğu platformu. Tüm içerikler üçüncü taraf kaynaklara aittir.</p>
</div>
<div class="footer-col">
<h5>Keşfet</h5>
<ul>
<li><a href="{{ route('search') }}?type=series">Anime Diziler</a></li>
<li><a href="{{ route('search') }}?type=movie">Anime Filmler</a></li>
<li><a href="{{ route('search') }}?status=ongoing">Devam Edenler</a></li>
<li><a href="{{ route('search') }}?status=completed">Tamamlananlar</a></li>
<li><a href="{{ route('blog.index') }}">Anime Blog</a></li>
<li><a href="{{ route('tribunal.index') }}">Anime Mahkemesi</a></li>
</ul>
</div>
<div class="footer-col">
<h5>Hesap</h5>
<ul>
@guest
<li><a href="{{ route('frontend.login') }}">Giriş Yap</a></li>
<li><a href="{{ route('frontend.register') }}">Üye Ol</a></li>
@else
<li><a href="{{ route('profile') }}">Profilim</a></li>
@endguest
</ul>
</div>
<div class="footer-col">
<h5>Yasal</h5>
<ul>
<li><a href="{{ route('legal.terms') }}">Kullanım Koşulları</a></li>
<li><a href="{{ route('legal.privacy') }}">Gizlilik Politikası</a></li>
<li><a href="{{ route('legal.dmca') }}">Telif Hakkı & DMCA</a></li>
<li><a href="mailto:iletisim@animexe.com">İletişim</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<span>&copy; {{ date('Y') }} Animexe — Tüm hakları saklıdır. Platform yalnızca teknik aracı konumundadır; içerikler ilgili hak sahiplerine aittir. · <a href="https://ayris.tech" target="_blank" rel="noopener" style="color:inherit;opacity:.75">Created by ayris.tech</a></span>
<span style="display:flex;gap:16px;flex-wrap:wrap;justify-content:flex-end">
<a href="{{ route('legal.terms') }}" style="color:inherit;opacity:.6;font-size:.78rem">Kullanım Koşulları</a>
<a href="{{ route('legal.privacy') }}" style="color:inherit;opacity:.6;font-size:.78rem">Gizlilik</a>
<a href="{{ route('legal.dmca') }}" style="color:inherit;opacity:.6;font-size:.78rem">DMCA</a>
</span>
</div>
{{-- Partnerler — resources/data/partners.json'dan okunur. Cache anahtarı dosya
değişim zamanına bağlı: JSON güncellenip deploy edilince otomatik tazelenir. --}}
@php
$__pFile = resource_path('data/partners.json');
$__partners = \Illuminate\Support\Facades\Cache::remember(
'footer_partners_' . (is_file($__pFile) ? @filemtime($__pFile) : '0'),
86400,
function () use ($__pFile) {
if (! is_file($__pFile)) return [];
$rows = json_decode((string) @file_get_contents($__pFile), true);
if (! is_array($rows)) return [];
return array_values(array_filter($rows, fn ($r) =>
is_array($r)
&& ! empty($r['url']) && ! empty($r['anchor'])
&& filter_var($r['url'], FILTER_VALIDATE_URL)
&& preg_match('#^https?://#i', $r['url'])
));
}
);
@endphp
@if(! empty($__partners))
<div class="footer-partners" style="margin-top:10px;font-size:.72rem;line-height:2">
<span style="opacity:.6">Partnerler:</span>
@foreach($__partners as $__p)
@php
// Per-link opaklık: görünür aralıkta tutulur (0.41). Daha düşük
// değerler (gizleme amaçlı 0.1 vb.) okunabilir alt sınıra yükseltilir.
$__op = isset($__p['opacity']) && is_numeric($__p['opacity'])
? max(0.1, min(1.0, (float) $__p['opacity']))
: 0.55;
@endphp
<a href="{{ $__p['url'] }}"
@isset($__p['title']) title="{{ $__p['title'] }}" @endisset
rel="{{ $__p['rel'] ?? 'dofollow' }} noopener"
target="_blank"
style="color:inherit;text-decoration:none;margin-right:12px;opacity:{{ $__op }}">{{ $__p['anchor'] }}</a>
@endforeach
</div>
@endif
</footer>
<script>
document.getElementById('ham-btn').addEventListener('click',()=>{
document.getElementById('mob-menu').classList.toggle('open');
});
</script>
@stack('scripts')
{{-- ── Search Autocomplete ──────────────────────────────────────────────────── --}}
<script>
(function() {
const input = document.getElementById('ns-input');
const ac = document.getElementById('ns-ac');
if (!input || !ac) return;
let timer, focusIdx = -1, lastQ = '';
function typeLabel(type) {
return type === 'series' ? 'Dizi' : type === 'movie' ? 'Film' : 'OVA';
}
function render(results, q) {
if (!results.length) { ac.classList.remove('show'); return; }
const hl = (txt) => txt ? txt.replace(new RegExp('(' + q.replace(/[.*+?^${}()|[\]\\]/g,'\\$&') + ')', 'gi'), '<mark style="background:transparent;color:var(--accent2)">$1</mark>') : '';
ac.innerHTML = results.map((r, i) =>
`<a href="/anime/${r.slug}" class="ns-ac-item" data-idx="${i}" role="option">
${r.cover
? `<img src="${r.cover}" alt="${r.title}" loading="lazy">`
: `<div class="ns-ac-ph"><i class="bi bi-film" style="color:var(--text3)"></i></div>`
}
<div class="ns-ac-info">
<div class="ns-ac-title">${hl(r.title)}</div>
<div class="ns-ac-meta">${r.title_en ? hl(r.title_en) + ' · ' : ''}${r.year ?? ''}${r.episodes ? ' · ' + r.episodes + ' Bölüm' : ''}</div>
</div>
${r.type ? `<span class="ns-ac-type">${typeLabel(r.type)}</span>` : ''}
</a>`
).join('') +
`<a href="/search?q=${encodeURIComponent(q)}" class="ns-ac-all">Tüm sonuçları gör için →</a>`;
focusIdx = -1;
ac.classList.add('show');
}
function moveFocus(dir) {
const items = ac.querySelectorAll('.ns-ac-item');
if (!items.length) return;
items.forEach(el => el.classList.remove('focused'));
focusIdx = (focusIdx + dir + items.length + 1) % (items.length + 1) - 1;
if (focusIdx >= 0) items[focusIdx].classList.add('focused');
}
input.addEventListener('input', () => {
const q = input.value.trim();
if (q === lastQ) return;
lastQ = q;
clearTimeout(timer);
if (q.length < 2) { ac.classList.remove('show'); return; }
timer = setTimeout(async () => {
try {
const res = await fetch(`/search/suggest?q=${encodeURIComponent(q)}`);
const data = await res.json();
if (input.value.trim() === q) render(data.results || [], q);
} catch (_) {}
}, 220);
});
input.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') { e.preventDefault(); moveFocus(1); }
if (e.key === 'ArrowUp') { e.preventDefault(); moveFocus(-1); }
if (e.key === 'Escape') { ac.classList.remove('show'); focusIdx = -1; }
if (e.key === 'Enter' && focusIdx >= 0) {
e.preventDefault();
const item = ac.querySelectorAll('.ns-ac-item')[focusIdx];
if (item) window.location.href = item.href;
}
});
document.addEventListener('click', (e) => {
if (!(e.target instanceof Node)) return;
if (!input.contains(e.target) && !ac.contains(e.target)) ac.classList.remove('show');
});
input.addEventListener('focus', () => {
if (input.value.trim().length >= 2 && ac.children.length) ac.classList.add('show');
});
})();
</script>
@auth
{{-- ── Floating AI Chat Widget ─────────────────────────────────── --}}
<style>
#ai-fab{
position:fixed;bottom:24px;right:24px;z-index:900;
width:56px;height:56px;border-radius:50%;border:none;cursor:pointer;
background:linear-gradient(135deg,var(--accent3),var(--accent));
color:#fff;font-size:1.4rem;
display:flex;align-items:center;justify-content:center;
box-shadow:0 0 0 0 rgba(184,77,255,.5),0 4px 20px rgba(184,77,255,.4);
animation:ai-pulse 2.8s infinite;
transition:transform .18s,box-shadow .18s;
}
#ai-fab:hover{transform:scale(1.08);box-shadow:0 0 32px rgba(184,77,255,.55),0 6px 24px rgba(255,45,125,.3)}
@keyframes ai-pulse{
0%,100%{box-shadow:0 0 0 0 rgba(184,77,255,.4),0 4px 20px rgba(184,77,255,.4)}
50%{box-shadow:0 0 0 10px rgba(184,77,255,0),0 4px 20px rgba(184,77,255,.4)}
}
#ai-panel{
position:fixed;bottom:92px;right:24px;z-index:899;
width:min(400px, calc(100vw - 32px));
background:linear-gradient(160deg,rgba(10,10,22,.99),rgba(6,6,16,.99));
border:1px solid rgba(184,77,255,.35);border-radius:20px;
box-shadow:0 24px 64px rgba(0,0,0,.7),0 0 60px rgba(184,77,255,.1);
display:flex;flex-direction:column;overflow:hidden;
transform:translateY(20px) scale(.96);opacity:0;pointer-events:none;
transition:transform .22s cubic-bezier(.22,1,.36,1),opacity .22s cubic-bezier(.22,1,.36,1);
height:min(560px, calc(100dvh - 120px));
}
#ai-panel.open{transform:translateY(0) scale(1);opacity:1;pointer-events:all}
.aip-head{
padding:13px 16px;display:flex;align-items:center;gap:10px;
background:linear-gradient(135deg,rgba(184,77,255,.18),rgba(255,45,125,.1));
border-bottom:1px solid rgba(184,77,255,.2);flex-shrink:0;
}
.aip-head-icon{
width:34px;height:34px;border-radius:50%;
background:linear-gradient(135deg,var(--accent3),var(--accent));
display:flex;align-items:center;justify-content:center;font-size:.9rem;color:#fff;
box-shadow:0 0 14px rgba(184,77,255,.5);flex-shrink:0;
}
.aip-head-info{flex:1;min-width:0}
.aip-head-title{font-size:.88rem;font-weight:700;color:var(--text);letter-spacing:.03em}
.aip-head-sub{font-size:.7rem;color:var(--text3);margin-top:1px;display:flex;align-items:center;gap:5px}
.aip-online-dot{width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;box-shadow:0 0 6px #22c55e}
.aip-head-actions{display:flex;gap:4px;flex-shrink:0}
.aip-close,.aip-clear{background:none;border:none;color:var(--text3);font-size:1rem;cursor:pointer;padding:5px 6px;border-radius:7px;transition:all .14s}
.aip-close:hover,.aip-clear:hover{color:var(--text);background:rgba(255,255,255,.07)}
.aip-msgs{
flex:1;overflow-y:auto;padding:14px 12px;display:flex;flex-direction:column;gap:10px;
scrollbar-width:thin;scrollbar-color:rgba(184,77,255,.25) transparent;
min-height:0;
}
.aip-msgs::-webkit-scrollbar{width:3px}
.aip-msgs::-webkit-scrollbar-thumb{background:rgba(184,77,255,.3);border-radius:3px}
.aip-msg-wrap{display:flex;flex-direction:column;gap:6px;max-width:92%}
.aip-msg-wrap.ai{align-self:flex-start}
.aip-msg-wrap.user{align-self:flex-end;align-items:flex-end}
.aip-msg{font-size:.84rem;line-height:1.6;padding:10px 13px;border-radius:14px;word-break:break-word}
.aip-msg.ai{
background:linear-gradient(135deg,rgba(184,77,255,.14),rgba(0,245,255,.07));
border:1px solid rgba(184,77,255,.22);color:var(--text);border-bottom-left-radius:4px;
}
.aip-msg.user{
background:linear-gradient(135deg,rgba(255,45,125,.2),rgba(184,77,255,.14));
border:1px solid rgba(255,45,125,.28);color:var(--text);border-bottom-right-radius:4px;
}
/* Markdown inside ai bubble */
.aip-msg.ai b,.aip-msg.ai strong{color:#e2d3ff;font-weight:700}
.aip-msg.ai em,.aip-msg.ai i{color:var(--text2);font-style:italic}
.aip-msg.ai ul{margin:6px 0 2px 16px;padding:0;list-style:disc}
.aip-msg.ai ol{margin:6px 0 2px 20px;padding:0}
.aip-msg.ai li{margin-bottom:3px}
.aip-msg.ai p{margin:0 0 6px}
.aip-msg.ai p:last-child{margin-bottom:0}
/* Anime öneri kartları */
.aip-cards{display:grid;grid-template-columns:repeat(2,1fr);gap:7px;padding:2px 0}
.aip-card{
background:rgba(255,255,255,.04);border:1px solid rgba(184,77,255,.15);
border-radius:10px;overflow:hidden;cursor:pointer;text-decoration:none;
display:flex;flex-direction:column;transition:all .18s;
}
.aip-card:hover{border-color:rgba(255,45,125,.4);background:rgba(255,45,125,.06);transform:translateY(-2px);box-shadow:0 6px 20px rgba(0,0,0,.3)}
.aip-card-img{position:relative;aspect-ratio:2/3;background:#0d0d1a;overflow:hidden}
.aip-card-img img{width:100%;height:100%;object-fit:cover;transition:transform .25s}
.aip-card:hover .aip-card-img img{transform:scale(1.05)}
.aip-card-img-ph{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.15);font-size:1.6rem}
.aip-card-badge{position:absolute;top:4px;left:4px;background:rgba(0,0,0,.7);backdrop-filter:blur(4px);border-radius:5px;padding:2px 6px;font-size:.62rem;font-weight:700;color:rgba(255,255,255,.9)}
.aip-card-body{padding:7px 8px;flex:1}
.aip-card-title{font-size:.75rem;font-weight:700;color:var(--text);line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-bottom:4px}
.aip-card-meta{font-size:.67rem;color:var(--text3);display:flex;align-items:center;gap:4px;flex-wrap:wrap}
.aip-card-rating{color:#f59e0b;font-weight:700}
.aip-card-btns{display:flex;gap:4px;padding:0 7px 7px}
.aip-card-btn{flex:1;padding:5px 0;border-radius:7px;border:none;cursor:pointer;font-size:.7rem;font-weight:700;text-align:center;text-decoration:none;display:flex;align-items:center;justify-content:center;gap:3px;transition:all .14s}
.aip-card-btn.watch{background:linear-gradient(135deg,var(--accent3),var(--accent));color:#fff}
.aip-card-btn.detail{background:rgba(255,255,255,.07);color:var(--text2);border:1px solid rgba(255,255,255,.1)}
.aip-card-btn:hover{opacity:.85}
/* Follow-up chips */
.aip-followup{display:flex;flex-wrap:wrap;gap:5px;padding:2px 0}
.aip-fu{
padding:5px 10px;border-radius:999px;font-size:.73rem;font-weight:600;cursor:pointer;
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.2);color:var(--accent2);
transition:all .14s;white-space:nowrap;
}
.aip-fu:hover{background:rgba(0,245,255,.12);box-shadow:0 0 10px rgba(0,245,255,.15)}
/* Typing */
.aip-typing{display:flex;gap:4px;padding:10px 13px;align-self:flex-start;background:rgba(184,77,255,.08);border:1px solid rgba(184,77,255,.15);border-radius:14px;border-bottom-left-radius:4px}
.aip-dot{width:6px;height:6px;border-radius:50%;background:var(--accent3);animation:aip-b .9s ease-in-out infinite}
.aip-dot:nth-child(2){animation-delay:.18s;background:var(--accent)}
.aip-dot:nth-child(3){animation-delay:.36s;background:var(--accent2)}
@keyframes aip-b{0%,80%,100%{transform:scale(.55);opacity:.35}40%{transform:scale(1);opacity:1}}
/* Quick actions */
.aip-quick{padding:0 12px 10px;display:flex;flex-wrap:wrap;gap:5px;flex-shrink:0}
.aip-q{
padding:5px 11px;border-radius:999px;font-size:.74rem;font-weight:600;cursor:pointer;
background:rgba(184,77,255,.1);border:1px solid rgba(184,77,255,.22);color:var(--accent3);
transition:all .14s;
}
.aip-q:hover{background:rgba(184,77,255,.2);border-color:var(--accent3);box-shadow:0 0 12px rgba(184,77,255,.18)}
/* Page context badge */
.aip-ctx-badge{
margin:0 12px 6px;padding:6px 10px;border-radius:8px;font-size:.72rem;
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.18);color:var(--accent2);
display:flex;align-items:center;gap:6px;flex-shrink:0;
}
/* Footer */
.aip-foot{
padding:10px 12px;display:flex;gap:8px;align-items:flex-end;
border-top:1px solid rgba(184,77,255,.12);flex-shrink:0;
background:rgba(0,0,0,.2);
}
#ai-inp{
flex:1;background:rgba(255,255,255,.05);border:1px solid rgba(184,77,255,.22);
border-radius:10px;padding:9px 12px;color:var(--text);font-size:.84rem;
font-family:inherit;resize:none;max-height:100px;outline:none;line-height:1.45;
transition:border-color .16s;scrollbar-width:none;
}
#ai-inp:focus{border-color:var(--accent3);box-shadow:0 0 0 2px rgba(184,77,255,.13)}
#ai-inp::placeholder{color:var(--text3)}
#ai-send{
width:38px;height:38px;border-radius:10px;border:none;cursor:pointer;flex-shrink:0;
background:linear-gradient(135deg,var(--accent3),var(--accent));color:#fff;font-size:.9rem;
display:flex;align-items:center;justify-content:center;
transition:transform .14s,box-shadow .16s;box-shadow:0 0 14px rgba(184,77,255,.3);
}
#ai-send:hover{transform:scale(1.06);box-shadow:0 0 22px rgba(184,77,255,.5)}
#ai-send:disabled{opacity:.4;cursor:not-allowed;transform:none}
@media(max-width:600px){
#ai-fab{bottom:16px;right:16px;width:52px;height:52px}
#ai-panel{
bottom:80px;right:8px;left:8px;width:auto;
height:min(480px, calc(100dvh - 100px));
border-radius:16px;
}
}
</style>
<div id="ai-fab" title="AI Asistan" onclick="toggleAiPanel()">
<i class="bi bi-stars"></i>
</div>
<div id="ai-panel">
<div class="aip-head">
<div class="aip-head-icon"><i class="bi bi-cpu-fill"></i></div>
<div class="aip-head-info">
<div class="aip-head-title">Animexe AI</div>
<div class="aip-head-sub"><span class="aip-online-dot"></span> Aktif &amp; hazır</div>
</div>
<div class="aip-head-actions">
<button class="aip-clear" onclick="aiClearChat()" title="Sohbeti temizle"><i class="bi bi-arrow-counterclockwise"></i></button>
<button class="aip-close" onclick="toggleAiPanel()" title="Kapat"><i class="bi bi-x-lg"></i></button>
</div>
</div>
<div id="aip-ctx-badge" class="aip-ctx-badge" style="display:none">
<i class="bi bi-eye-fill"></i><span id="aip-ctx-text"></span>
</div>
<div class="aip-msgs" id="aip-msgs">
<div class="aip-msg-wrap ai">
<div class="aip-msg ai">Merhaba! 👋 Anime önerisi isteyebilir, site hakkında sorular sorabilir ya da izlediğin bölüm hakkında konuşabiliriz. Nasıl yardımcı olabilirim?</div>
</div>
</div>
<div class="aip-quick" id="aip-quick">
<button class="aip-q" onclick="aiQuick('Şu an ne izlesem?')">🎯 Ne izlesem?</button>
<button class="aip-q" onclick="aiQuick('Aksiyon anime öner')">⚔️ Aksiyon</button>
<button class="aip-q" onclick="aiQuick('Romantik anime film öner')">🌸 Romantik film</button>
<button class="aip-q" onclick="aiQuick('Nasıl üye olabilirim?')"> Site yardımı</button>
<button class="aip-q" onclick="aiQuick('2024\'te çıkan en iyi animeler?')"> 2024 animeleri</button>
</div>
<div class="aip-foot">
<textarea id="ai-inp" rows="1" placeholder="Mesaj yaz..." onkeydown="aiKeydown(event)" oninput="autoGrow(this)"></textarea>
<button id="ai-send" onclick="aiSend()"><i class="bi bi-send-fill"></i></button>
</div>
</div>
<script>
(function(){
const CSRF = document.querySelector('meta[name=csrf-token]').content;
let aiOpen = false, aiLoading = false;
// Mesaj geçmişi (sistem mesajları dahil)
const _ctx = window.USER_WATCH_CTX;
const aiMsgs = _ctx
? [{role:'user', content:`[SİSTEM: Kullanıcının son izledikleri: ${_ctx}. Sadece bağlam için kullan, listeyi gösterme.]`},
{role:'assistant', content:'Anlıyorum, izleme geçmişinizi bağlam olarak kaydettim.'}]
: [];
// Sayfa bağlamını belirle
function getPageContext(){
const p = location.pathname;
const animeTitle = document.querySelector('meta[name="anime-title"]')?.content;
const epNum = document.querySelector('meta[name="episode-number"]')?.content;
const seasonNum = document.querySelector('meta[name="season-number"]')?.content;
if(p.startsWith('/watch/') && animeTitle){
return `${animeTitle} adlı animeyi izliyor — S${seasonNum||1}E${epNum||1}`;
}
if(p.startsWith('/anime/') && animeTitle){
return `${animeTitle} anime sayfasında`;
}
return '';
}
// Sayfa bağlamı badge'ini göster
const pageCtx = getPageContext();
if(pageCtx){
document.getElementById('aip-ctx-badge').style.display = 'flex';
document.getElementById('aip-ctx-text').textContent = pageCtx;
}
// Basit markdown renderer
function renderMarkdown(text){
// Başında/sonunda boşlukları temizle
text = text.trim();
// Satırları işle
const lines = text.split('\n');
const out = [];
let inList = false, listTag = '';
function closeList(){
if(inList){ out.push(`</${listTag}>`); inList=false; listTag=''; }
}
for(let i=0; i<lines.length; i++){
let ln = lines[i];
// Unordered list
if(/^[\-\*] (.+)/.test(ln)){
if(!inList || listTag!=='ul'){ closeList(); out.push('<ul>'); inList=true; listTag='ul'; }
out.push('<li>'+inlineMd(ln.replace(/^[\-\*] /,''))+'</li>');
// Ordered list
} else if(/^\d+\. (.+)/.test(ln)){
if(!inList || listTag!=='ol'){ closeList(); out.push('<ol>'); inList=true; listTag='ol'; }
out.push('<li>'+inlineMd(ln.replace(/^\d+\. /,''))+'</li>');
} else {
closeList();
if(ln.trim()===''){
// blank line → paragraph break
if(out.length && !out[out.length-1].endsWith('<br>')){
out.push('<br>');
}
} else {
out.push('<p>'+inlineMd(ln)+'</p>');
}
}
}
closeList();
return out.join('');
}
function inlineMd(s){
s = s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
// Bold
s = s.replace(/\*\*(.+?)\*\*/g,'<b>$1</b>');
// Italic
s = s.replace(/\*(.+?)\*/g,'<em>$1</em>');
// Inline code
s = s.replace(/`([^`]+)`/g,'<code style="background:rgba(255,255,255,.08);padding:1px 5px;border-radius:4px;font-size:.82em">$1</code>');
return s;
}
function esc(s){ return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
function appendMsg(role, html, isHtml){
const wrap = document.createElement('div');
wrap.className = 'aip-msg-wrap '+role;
const el = document.createElement('div');
el.className = 'aip-msg '+role;
if(isHtml) el.innerHTML = html;
else el.textContent = html;
wrap.appendChild(el);
document.getElementById('aip-msgs').appendChild(wrap);
el.scrollIntoView({behavior:'smooth', block:'end'});
return wrap;
}
function appendAnimeCards(cards){
if(!cards || !cards.length) return;
const wrap = document.createElement('div');
wrap.className = 'aip-msg-wrap ai';
const grid = document.createElement('div');
grid.className = 'aip-cards';
cards.forEach(a=>{
const typeLabel = a.type==='movie' ? 'Film' : (a.type==='ova' ? 'OVA' : 'Dizi');
const ratingHtml = a.rating ? `<span class="aip-card-rating">${parseFloat(a.rating).toFixed(1)}</span>` : '';
grid.innerHTML += `
<div class="aip-card">
<div class="aip-card-img">
${a.cover
? `<img src="${esc(a.cover)}" alt="${esc(a.title)}" loading="lazy">`
: `<div class="aip-card-img-ph"><i class="bi bi-image"></i></div>`}
<div class="aip-card-badge">${esc(typeLabel)}</div>
</div>
<div class="aip-card-body">
<div class="aip-card-title">${esc(a.title)}</div>
<div class="aip-card-meta">
${ratingHtml}
${a.genres ? `<span>${esc(a.genres)}</span>` : ''}
</div>
</div>
<div class="aip-card-btns">
<a class="aip-card-btn watch" href="/watch/${esc(a.slug)}/1/1"><i class="bi bi-play-fill"></i>İzle</a>
<a class="aip-card-btn detail" href="/anime/${esc(a.slug)}"><i class="bi bi-info-circle"></i>Detay</a>
</div>
</div>`;
});
wrap.appendChild(grid);
document.getElementById('aip-msgs').appendChild(wrap);
grid.scrollIntoView({behavior:'smooth', block:'end'});
}
function appendFollowUps(chips){
if(!chips || !chips.length) return;
const wrap = document.createElement('div');
wrap.className = 'aip-msg-wrap ai';
const row = document.createElement('div');
row.className = 'aip-followup';
chips.forEach(c=>{
const btn = document.createElement('button');
btn.className = 'aip-fu';
btn.textContent = c;
btn.onclick = ()=>{ row.parentElement?.remove(); aiQuick(c); };
row.appendChild(btn);
});
wrap.appendChild(row);
document.getElementById('aip-msgs').appendChild(wrap);
}
// Follow-up chip üretici — mesaj içeriğine göre
function suggestFollowUps(reply, hasCards){
const r = reply.toLowerCase();
const chips = [];
if(hasCards){
chips.push('Daha fazla öner', 'Benzer anime var mı?');
}
if(r.includes('aksiyon') || r.includes('dövüş')){
chips.push('Fantezi anime öner', '2024 aksiyon izle');
} else if(r.includes('roman') || r.includes('sevgi') || r.includes('aşk')){
chips.push('Hüzünlü romantik öner', 'Komedi romantik göster');
} else if(r.includes('premium') || r.includes('üyelik') || r.includes('hesap')){
chips.push('Premium nasıl alınır?', 'Ücretsiz özellikler neler?');
} else if(!hasCards){
chips.push('Aksiyon öner', 'Daha fazla anlat');
}
return chips.slice(0,3);
}
function showTyping(){
const el=document.createElement('div');
el.className='aip-typing';el.id='aip-typing';
el.innerHTML='<div class="aip-dot"></div><div class="aip-dot"></div><div class="aip-dot"></div>';
document.getElementById('aip-msgs').appendChild(el);
el.scrollIntoView({behavior:'smooth',block:'end'});
}
function removeTyping(){
document.getElementById('aip-typing')?.remove();
}
window.toggleAiPanel=function(){
aiOpen=!aiOpen;
document.getElementById('ai-panel').classList.toggle('open',aiOpen);
if(aiOpen) setTimeout(()=>document.getElementById('ai-inp').focus(),220);
};
window.aiQuick=function(txt){
document.getElementById('aip-quick').style.display='none';
document.getElementById('ai-inp').value=txt;
aiSend();
};
window.autoGrow=function(el){
el.style.height='auto';
el.style.height=Math.min(el.scrollHeight,80)+'px';
};
window.aiKeydown=function(e){
if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();aiSend();}
};
window.aiClearChat=function(){
aiMsgs.length=0;
const msgs=document.getElementById('aip-msgs');
msgs.innerHTML='<div class="aip-msg-wrap ai"><div class="aip-msg ai">Sohbet temizlendi. Nasıl yardımcı olabilirim? 😊</div></div>';
document.getElementById('aip-quick').style.display='';
};
window.aiSend=async function(){
if(aiLoading) return;
const inp=document.getElementById('ai-inp');
const txt=inp.value.trim();
if(!txt) return;
inp.value=''; inp.style.height='auto';
document.getElementById('aip-quick').style.display='none';
document.getElementById('ai-send').disabled=true;
aiLoading=true;
appendMsg('user', txt, false);
aiMsgs.push({role:'user', content:txt});
showTyping();
try{
const body = {messages: aiMsgs};
if(pageCtx) body.page_context = pageCtx;
const res=await fetch('{{ route("ai.chat") }}',{
method:'POST',
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
body:JSON.stringify(body)
});
const data=await res.json();
removeTyping();
const reply = data.reply || data.error || 'Bir hata oluştu.';
appendMsg('ai', renderMarkdown(reply), true);
aiMsgs.push({role:'assistant', content:reply});
// Anime kartları
const cards = data.anime_cards || [];
appendAnimeCards(cards);
// Follow-up chips
appendFollowUps(suggestFollowUps(reply, cards.length > 0));
}catch(e){
removeTyping();
appendMsg('ai','Bağlantı hatası, lütfen tekrar dene.', false);
}
aiLoading=false;
document.getElementById('ai-send').disabled=false;
};
})();
</script>
@endauth
{{-- ── Sayfa takip sistemi ────────────────────────────────────────────────── --}}
<script>
(function(){
const CSRF = document.querySelector('meta[name="csrf-token"]')?.content || '';
function beacon(url, data) {
// sendBeacon tercih et; fallback fetch
const body = JSON.stringify(data);
if (navigator.sendBeacon) {
const blob = new Blob([body], {type:'application/json'});
// sendBeacon CSRF header gönderemez, fetch kullan
}
fetch(url, {
method:'POST',
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
keepalive:true, body
}).catch(()=>{});
}
// Sayfa türünü URL'den tespit et
function detectPageType() {
const p = location.pathname;
if (p === '/' || p === '') return 'home';
if (p.startsWith('/watch/')) return 'player';
if (p.startsWith('/anime/')) return 'anime';
if (p.startsWith('/search')) return 'search';
if (p.startsWith('/ai')) return 'ai';
if (p.startsWith('/genre/')) return 'genre';
return 'other';
}
// Anime ID'yi meta tag'den al (player/anime sayfası bunu set eder)
function getMeta(name) {
return document.querySelector(`meta[name="${name}"]`)?.content || null;
}
// Sayfa görüntüleme kaydı
window.addEventListener('load', function() {
beacon('/track/pageview', {
page_type: detectPageType(),
anime_id: getMeta('track-anime-id'),
episode_id: getMeta('track-episode-id'),
url: location.pathname + location.search,
referrer: document.referrer,
});
});
// Video izleme takibi (player sayfasında tetiklenir)
window.TrackWatch = function(animeId, episodeId, seasonNum, episodeNum) {
const vd = document.querySelector('video');
if (!vd || !animeId) return;
let lastReported = 0;
let trackTimer = null;
function sendWatch() {
const sec = Math.floor(vd.currentTime);
if (sec === lastReported || sec < 5) return;
lastReported = sec;
const total = Math.floor(vd.duration) || 0;
const pct = total > 0 ? Math.min(100, Math.round(sec / total * 100)) : 0;
beacon('/track/watch', {
anime_id: parseInt(animeId),
episode_id: episodeId ? parseInt(episodeId) : null,
season_number: parseInt(seasonNum) || 1,
episode_number: parseInt(episodeNum) || 1,
seconds: sec,
total: total,
percent: pct,
});
}
// Her 30 saniyede bir gönder
trackTimer = setInterval(sendWatch, 30000);
// Video kapanırken de gönder
vd.addEventListener('pause', sendWatch);
document.addEventListener('visibilitychange', function() {
if (document.hidden) sendWatch();
});
window.addEventListener('beforeunload', function() {
sendWatch();
clearInterval(trackTimer);
});
};
})();
</script>
{{-- ── Page Transition Loader ──────────────────────────────────────── --}}
<style>
#page-loader{
position:fixed;inset:0;z-index:9999;
pointer-events:none;
opacity:0;transition:opacity .2s ease;
}
#page-loader.show{ opacity:1;pointer-events:all; }
/* Top progress bar */
#loader-bar{
position:absolute;top:0;left:0;height:2px;width:0%;
background:linear-gradient(90deg,var(--accent2),var(--accent),var(--accent3));
box-shadow:0 0 12px var(--accent2),0 0 24px var(--accent);
transition:width .4s cubic-bezier(.4,0,.2,1);
border-radius:0 2px 2px 0;
}
#loader-bar::after{
content:'';position:absolute;right:0;top:50%;transform:translateY(-50%);
width:80px;height:100%;
background:linear-gradient(90deg,transparent,rgba(0,245,255,.7));
filter:blur(4px);
}
/* Center spinner */
#loader-center{
position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
display:flex;flex-direction:column;align-items:center;gap:16px;
opacity:0;transition:opacity .15s ease .25s;
}
#page-loader.show #loader-center{ opacity:1; }
.loader-ring{
width:44px;height:44px;
border-radius:50%;
border:2px solid rgba(0,245,255,.1);
border-top-color:var(--accent2);
border-right-color:var(--accent);
animation:loader-spin .7s linear infinite;
box-shadow:0 0 20px rgba(0,245,255,.15) inset;
}
@keyframes loader-spin{ to{ transform:rotate(360deg); } }
.loader-dots{
display:flex;gap:6px;
}
.loader-dots span{
width:5px;height:5px;border-radius:50%;
background:var(--accent2);
animation:loader-dot .9s ease-in-out infinite;
opacity:.3;
}
.loader-dots span:nth-child(2){ animation-delay:.15s;background:var(--accent); }
.loader-dots span:nth-child(3){ animation-delay:.3s;background:var(--accent3); }
@keyframes loader-dot{
0%,100%{ opacity:.3;transform:scale(1); }
50%{ opacity:1;transform:scale(1.4); }
}
/* Page content fade-out on leave */
#page-content{ transition:opacity .18s ease,transform .18s ease; }
#page-content.leaving{ opacity:0;transform:translateY(8px); }
</style>
<div id="page-loader">
<div id="loader-bar"></div>
<div id="loader-center">
<div class="loader-ring"></div>
<div class="loader-dots"><span></span><span></span><span></span></div>
</div>
</div>
<script>
(function(){
// ── Splash (ilk giriş) ──────────────────────────────────────────
const splash = document.getElementById('splash');
function hideSplash(){
if (!splash) return;
splash.classList.add('done');
setTimeout(()=>{ if(splash.parentNode) splash.parentNode.removeChild(splash); }, 400);
}
// Sayfa hazır olunca hemen kapat, en fazla 2sn bekle
const splashTimeout = setTimeout(hideSplash, 2000);
function tryHideSplash(){
clearTimeout(splashTimeout);
hideSplash();
}
if (document.readyState === 'complete') tryHideSplash();
else window.addEventListener('load', tryHideSplash);
// back-forward cache: splash DOM yoksa sorun yok (removeChild ile silindi)
window.addEventListener('pageshow', function(e){ if(e.persisted) hideSplash(); });
})();
(function(){
const loader = document.getElementById('page-loader');
const bar = document.getElementById('loader-bar');
const content = document.getElementById('page-content');
if (!loader) return;
let barTimer, hideTimer;
function showLoader(){
clearTimeout(hideTimer);
loader.classList.add('show');
bar.style.width = '0%';
// Progress bar animasyonu: hızlı başlar, 85'de yavaşlar
requestAnimationFrame(()=>{
bar.style.width = '45%';
barTimer = setTimeout(()=>{ bar.style.width = '75%'; }, 300);
setTimeout(()=>{ bar.style.width = '88%'; }, 700);
});
if (content) content.classList.add('leaving');
}
function hideLoader(){
clearTimeout(barTimer);
bar.style.transition = 'width .15s ease';
bar.style.width = '100%';
setTimeout(()=>{
loader.classList.remove('show');
bar.style.transition = 'width .4s cubic-bezier(.4,0,.2,1)';
bar.style.width = '0%';
if (content) content.classList.remove('leaving');
}, 200);
}
// Link click'te loader göster (aynı sekme, dış link değil, anchor değil)
document.addEventListener('click', function(e){
if (!(e.target instanceof Element)) return;
const a = e.target.closest('a');
if (!a) return;
const href = a.getAttribute('href');
if (!href || href.startsWith('#') || href.startsWith('javascript') || href.startsWith('mailto')) return;
if (a.target === '_blank') return;
try {
const url = new URL(href, location.href);
if (url.origin !== location.origin) return;
if (url.pathname === location.pathname && url.search === location.search) return;
} catch(err){ return; }
showLoader();
});
// Form submit'te loader göster (sadece gerçek sayfa yükleyen formlar için)
document.addEventListener('submit', function(e){
if (e.defaultPrevented) return;
const f = e.target;
if (f.method && f.method.toLowerCase() === 'get') showLoader();
});
// Sayfa yüklenince gizle
window.addEventListener('pageshow', function(e){
hideLoader();
// back-forward cache'den geliyorsa loader'ı da kapat
if (e.persisted) hideLoader();
});
window.addEventListener('load', hideLoader);
// Geri/ileri buton
window.addEventListener('popstate', showLoader);
})();
</script>
{{-- ── Global Kullanıcı Kart Popup ─────────────────────────────── --}}
<style>
#ucard-popup{
position:fixed;z-index:9990;
background:linear-gradient(160deg,rgba(10,10,22,.98),rgba(6,6,14,.99));
border:1px solid rgba(255,255,255,.12);
border-radius:16px;padding:16px;
width:230px;
box-shadow:0 20px 60px rgba(0,0,0,.7),0 0 40px rgba(0,0,0,.4);
pointer-events:auto;
opacity:0;transform:scale(.94);
transition:opacity .16s,transform .16s;
}
#ucard-popup.show{opacity:1;transform:scale(1)}
.ucard-top{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.ucard-ava{
width:44px;height:44px;border-radius:50%;overflow:hidden;flex-shrink:0;
background:linear-gradient(135deg,var(--accent2),var(--accent));
display:flex;align-items:center;justify-content:center;
font-size:.95rem;font-weight:800;color:#fff;text-decoration:none;
}
.ucard-ava img{width:100%;height:100%;object-fit:cover}
.ucard-info{flex:1;min-width:0}
.ucard-name{font-size:.88rem;font-weight:800;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ucard-user{font-size:.72rem;color:rgba(255,255,255,.35);margin-top:1px}
.ucard-stats{display:flex;gap:14px;margin-bottom:12px}
.ucard-stat{text-align:center}
.ucard-stat-n{font-size:.88rem;font-weight:800;color:#fff}
.ucard-stat-l{font-size:.62rem;color:rgba(255,255,255,.35)}
.ucard-actions{display:flex;gap:6px}
.ucard-btn{
flex:1;padding:7px 0;border-radius:9px;border:none;cursor:pointer;
font-size:.75rem;font-weight:700;font-family:inherit;
display:flex;align-items:center;justify-content:center;gap:5px;
transition:all .15s;text-decoration:none;
}
.ucard-btn-follow{background:var(--accent2);color:#05050e}
.ucard-btn-follow:hover{background:#00d4de}
.ucard-btn-follow.following{background:rgba(255,255,255,.1);color:rgba(255,255,255,.6);border:1px solid rgba(255,255,255,.15)}
.ucard-btn-follow.following:hover{background:rgba(255,80,80,.15);color:#ff6b6b;border-color:rgba(255,80,80,.3)}
.ucard-btn-msg{background:rgba(255,255,255,.08);color:rgba(255,255,255,.7);border:1px solid rgba(255,255,255,.12)}
.ucard-btn-msg:hover{background:rgba(255,255,255,.14);color:#fff}
.ucard-profile-link{display:block;text-align:center;font-size:.7rem;color:rgba(255,255,255,.3);margin-top:9px;text-decoration:none;transition:color .15s}
.ucard-profile-link:hover{color:rgba(255,255,255,.7)}
#ucard-popup .ucard-loading{text-align:center;padding:12px 0;color:rgba(255,255,255,.3);font-size:.8rem}
</style>
<div id="ucard-popup"></div>
<script>
(function(){
const popup = document.getElementById('ucard-popup');
if (!popup) return;
let hideTimer = null;
let currentUid = null;
let cache = {};
const IS_LOGGED = {{ auth()->check() ? 'true' : 'false' }};
const CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
function showPopup(uid, anchor) {
clearTimeout(hideTimer);
if (currentUid === uid && popup.classList.contains('show')) return;
currentUid = uid;
popup.classList.remove('show');
popup.innerHTML = '<div class="ucard-loading"><i class="bi bi-arrow-repeat" style="animation:spin .8s linear infinite;display:inline-block"></i> Yükleniyor…</div>';
positionPopup(anchor);
popup.classList.add('show');
if (cache[uid]) { renderCard(cache[uid]); return; }
fetch(`/u/${uid}/card`, { headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CSRF } })
.then(r => r.json())
.then(d => { cache[uid] = d; if (currentUid == uid) renderCard(d); })
.catch(() => { popup.classList.remove('show'); });
}
function positionPopup(el) {
const r = el.getBoundingClientRect();
const pw = 230, margin = 8;
let left = r.right + margin;
let top = r.top;
if (left + pw > window.innerWidth - 8) left = r.left - pw - margin;
if (left < 8) left = 8;
if (top + 220 > window.innerHeight) top = window.innerHeight - 228;
if (top < 8) top = 8;
popup.style.left = left + 'px';
popup.style.top = top + 'px';
}
function renderCard(d) {
const ava = d.avatar
? `<img src="${esc(d.avatar)}" alt="${esc(d.name)}">`
: (d.name||'?').charAt(0).toUpperCase();
const userTag = d.username ? `<div class="ucard-user">@${esc(d.username)}</div>` : '';
const followBtn = IS_LOGGED && !d.is_me && d.follow_url
? `<button class="ucard-btn ucard-btn-follow${d.is_following?' following':''}" data-follow-url="${esc(d.follow_url)}" onclick="ucardFollow(this,${d.id})">${d.is_following?'<i class="bi bi-check2"></i> Takip Ediliyor':'<i class="bi bi-person-plus"></i> Takip Et'}</button>`
: '';
const msgBtn = IS_LOGGED && !d.is_me && d.msg_url
? `<form method="POST" action="${esc(d.msg_url)}" style="flex:1"><input type="hidden" name="_token" value="${CSRF}"><button type="submit" class="ucard-btn ucard-btn-msg" style="width:100%"><i class="bi bi-chat-dots"></i> Mesaj</button></form>`
: '';
popup.innerHTML = `
<div class="ucard-top">
<a href="${esc(d.profile_url)}" class="ucard-ava">${ava}</a>
<div class="ucard-info">
<div class="ucard-name">${esc(d.name)}</div>
${userTag}
</div>
</div>
<div class="ucard-stats">
<div class="ucard-stat"><div class="ucard-stat-n">${d.followers}</div><div class="ucard-stat-l">Takipçi</div></div>
<div class="ucard-stat"><div class="ucard-stat-n">${d.following}</div><div class="ucard-stat-l">Takip</div></div>
</div>
<div class="ucard-actions">${followBtn}${msgBtn}</div>
<a href="${esc(d.profile_url)}" class="ucard-profile-link">Profilini gör <i class="bi bi-arrow-right"></i></a>
`;
}
function esc(s) {
return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
window.ucardFollow = async function(btn, uid) {
try {
const url = btn.dataset.followUrl;
const r = await fetch(url, { method:'POST', headers:{'X-CSRF-TOKEN':CSRF,'Accept':'application/json'} });
const d = await r.json();
const following = d.following;
btn.className = `ucard-btn ucard-btn-follow${following?' following':''}`;
btn.innerHTML = following ? '<i class="bi bi-check2"></i> Takip Ediliyor' : '<i class="bi bi-person-plus"></i> Takip Et';
if (cache[uid]) cache[uid].is_following = following;
} catch(e) {}
};
// Dismiss popup
popup.addEventListener('mouseenter', () => clearTimeout(hideTimer));
popup.addEventListener('mouseleave', () => { hideTimer = setTimeout(() => popup.classList.remove('show'), 300); currentUid = null; });
document.addEventListener('click', function(e) {
if (!(e.target instanceof Element)) return;
// Click on [data-uid]
const el = e.target.closest('[data-uid]');
if (el) {
// Anchor links with href should navigate normally (don't intercept)
if (el.tagName === 'A' && el.href) return;
e.preventDefault();
const uid = el.dataset.uid;
if (popup.classList.contains('show') && currentUid == uid) {
popup.classList.remove('show'); currentUid = null;
} else {
showPopup(uid, el);
}
return;
}
// Click outside popup
if (!popup.contains(e.target)) {
popup.classList.remove('show'); currentUid = null;
}
});
// Hover on [data-uid] (desktop)
document.addEventListener('mouseover', function(e) {
if (!(e.target instanceof Element)) return;
const el = e.target.closest('[data-uid]');
if (!el) return;
clearTimeout(hideTimer);
hideTimer = setTimeout(() => showPopup(el.dataset.uid, el), 350);
});
document.addEventListener('mouseout', function(e) {
if (!(e.target instanceof Element)) return;
const el = e.target.closest('[data-uid]');
if (!el) return;
clearTimeout(hideTimer);
hideTimer = setTimeout(() => {
if (!popup.matches(':hover')) { popup.classList.remove('show'); currentUid = null; }
}, 250);
});
})();
</script>
<style>
@keyframes spin{from{transform:rotate(0)}to{transform:rotate(360deg)}}
</style>
<script>
/* ══════════════════════════════════════════════════════
ANIMEXE PREMIUM GLOBAL JS
══════════════════════════════════════════════════════ */
(function() {
'use strict';
// ── Scroll Progress Bar ─────────────────────────────
const progressEl = document.getElementById('scroll-progress');
const scrollTopBtn = document.getElementById('scroll-top');
const topnav = document.getElementById('topnav');
function onScroll() {
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
if (progressEl && scrollable > 0) {
progressEl.style.width = Math.min(100, (window.scrollY / scrollable) * 100) + '%';
}
if (scrollTopBtn) scrollTopBtn.classList.toggle('show', window.scrollY > 420);
if (topnav) topnav.classList.toggle('scrolled', window.scrollY > 50);
}
window.addEventListener('scroll', onScroll, { passive: true });
// Scroll to top
if (scrollTopBtn) {
scrollTopBtn.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' }));
}
// ── Scroll Reveal System ─────────────────────────────
function initReveal() {
// Auto-add reveal class to home sections and section headers
document.querySelectorAll('.home-section').forEach((el, i) => {
if (!el.classList.contains('reveal')) el.classList.add('reveal');
});
document.querySelectorAll('.hs-hdr').forEach((el, i) => {
if (!el.classList.contains('reveal')) {
el.classList.add('reveal');
el.classList.add('reveal-d' + Math.min(i % 3 + 1, 5));
}
});
document.querySelectorAll('.promo-banner').forEach(el => {
if (!el.classList.contains('reveal')) el.classList.add('reveal');
});
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.08, rootMargin: '0px 0px -30px 0px' });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
}
// Run after DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initReveal);
} else {
initReveal();
}
// ── Card hover magnetic tilt (desktop) ─────────────
if (!('ontouchstart' in window)) {
document.addEventListener('mousemove', function(e) {
if (!(e.target instanceof Element)) return;
const card = e.target.closest('.pc, .tpc, .sl-card, .mv-card');
if (!card) return;
const rect = card.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
const dx = (e.clientX - cx) / (rect.width / 2);
const dy = (e.clientY - cy) / (rect.height / 2);
card.style.transform = `translateY(-4px) perspective(600px) rotateY(${dx * 4}deg) rotateX(${-dy * 3}deg)`;
});
document.addEventListener('mouseleave', function(e) {
if (!(e.target instanceof Element)) return;
const card = e.target.closest('.pc, .tpc, .sl-card, .mv-card');
if (card) card.style.transform = '';
}, true);
}
// ── Splash screen dismiss ───────────────────────────
const splash = document.getElementById('splash');
if (splash) {
window.addEventListener('load', () => {
setTimeout(() => splash.classList.add('done'), 300);
});
// Fallback: max 2.5s
setTimeout(() => splash && splash.classList.add('done'), 2500);
}
// ── Button ripple effect ────────────────────────────
document.addEventListener('click', function(e) {
if (!(e.target instanceof Element)) return;
const btn = e.target.closest('.h-play-btn, .btn-solid, .promo-cta, .btn-ghost');
if (!btn) return;
const rect = btn.getBoundingClientRect();
const ripple = document.createElement('span');
const size = Math.max(rect.width, rect.height) * 1.8;
ripple.style.cssText = `
position:absolute;width:${size}px;height:${size}px;border-radius:50%;
background:rgba(255,255,255,.22);pointer-events:none;
left:${e.clientX - rect.left - size/2}px;
top:${e.clientY - rect.top - size/2}px;
transform:scale(0);animation:ripple-burst .55s ease-out forwards;
`;
if (getComputedStyle(btn).position === 'static') btn.style.position = 'relative';
btn.appendChild(ripple);
ripple.addEventListener('animationend', () => ripple.remove());
});
// ── Stats counter animation ─────────────────────────
function animateCount(el) {
const target = parseFloat(el.dataset.count || el.textContent.replace(/\D/g,''));
if (!target || isNaN(target)) return;
const duration = 900;
const start = performance.now();
const isFloat = String(target).includes('.');
function step(now) {
const progress = Math.min((now - start) / duration, 1);
const eased = 1 - Math.pow(1 - progress, 3);
const val = eased * target;
el.textContent = isFloat ? val.toFixed(1) : Math.round(val).toLocaleString('tr-TR');
if (progress < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
const countObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !entry.target.dataset.counted) {
entry.target.dataset.counted = '1';
animateCount(entry.target);
}
});
}, { threshold: 0.5 });
document.querySelectorAll('[data-count]').forEach(el => countObserver.observe(el));
})();
</script>
<style>
@keyframes ripple-burst{
to{transform:scale(1);opacity:0}
}
</style>
{{-- ── Global Toast Notification System ──────────────────────── --}}
<style>
#toast-container{
position:fixed;bottom:24px;left:50%;transform:translateX(-50%);
z-index:99999;display:flex;flex-direction:column;gap:8px;
align-items:center;pointer-events:none;
}
.gtoast{
display:flex;align-items:center;gap:10px;
padding:11px 18px;border-radius:12px;
background:rgba(14,14,28,.96);
border:1px solid rgba(255,255,255,.12);
backdrop-filter:blur(16px);
box-shadow:0 8px 32px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.04);
color:var(--text);font-size:.84rem;font-weight:600;
pointer-events:auto;white-space:nowrap;max-width:min(420px,90vw);
animation:toast-in .28s cubic-bezier(.22,1,.36,1) forwards;
}
.gtoast.out{ animation:toast-out .25s ease forwards; }
.gtoast i{ font-size:1rem;flex-shrink:0; }
.gtoast.success{ border-color:rgba(0,245,255,.3); }
.gtoast.success i{ color:var(--accent2); }
.gtoast.error{ border-color:rgba(255,45,125,.3); }
.gtoast.error i{ color:var(--accent); }
.gtoast.info{ border-color:rgba(184,77,255,.3); }
.gtoast.info i{ color:var(--accent3); }
.gtoast.warning{ border-color:rgba(251,191,36,.3); }
.gtoast.warning i{ color:#fbbf24; }
@keyframes toast-in{
from{ opacity:0;transform:translateY(16px) scale(.94); }
to{ opacity:1;transform:translateY(0) scale(1); }
}
@keyframes toast-out{
from{ opacity:1;transform:scale(1); }
to{ opacity:0;transform:scale(.92); }
}
@media(max-width:500px){
#toast-container{ bottom:16px;left:12px;right:12px;transform:none;align-items:stretch; }
.gtoast{ white-space:normal; }
}
</style>
<div id="toast-container" aria-live="polite"></div>
<script>
(function(){
const ICONS = { success:'bi-check-circle-fill', error:'bi-x-circle-fill', info:'bi-info-circle-fill', warning:'bi-exclamation-triangle-fill' };
window.showToast = function(msg, type, duration) {
type = type || 'success';
duration = duration || 3200;
const c = document.getElementById('toast-container');
if (!c) return;
const t = document.createElement('div');
t.className = 'gtoast ' + type;
t.innerHTML = '<i class="bi ' + (ICONS[type]||ICONS.info) + '"></i><span>' + msg + '</span>';
c.appendChild(t);
setTimeout(() => {
t.classList.add('out');
t.addEventListener('animationend', () => t.remove(), { once: true });
}, duration);
};
})();
</script>
{{-- ═══════════════════════════════════════════════════════════════
CHAT PANEL JS v2
═══════════════════════════════════════════════════════════════ --}}
@auth
<script>
(function(){
'use strict';
const CP_CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
const CP_ME_ID = {{ auth()->id() }};
const CP_MY_NAME = {!! json_encode(auth()->user()->name) !!};
const CP_MY_AVA = {!! json_encode(auth()->user()->avatar ? \App\Support\MediaUrl::fromStoragePath(auth()->user()->avatar) : null) !!};
const CP_CONVS_URL = '{{ route("messages.conversations") }}';
const CP_UPLOAD_URL = '{{ route("messages.upload-image") }}';
const TENOR_KEY = '{{ env("TENOR_API_KEY","") }}';
const IS_MOBILE = window.matchMedia('(max-width:900px)').matches;
let cpOpen = false;
let cpConvId = null;
let cpConvUserId = null;
let cpLastMsgId = 0;
let cpPollTimer = null;
let cpEmojiOpen = false;
let cpGifOpen = false;
let cpGifTimer = null;
/* ════════════════════════════════════════════════════
PANEL OPEN / CLOSE
════════════════════════════════════════════════════ */
window.chatPanelToggle = function() {
cpOpen ? chatPanelClose() : chatPanelOpen();
};
window.chatPanelClose = function() {
document.getElementById('chat-panel').classList.remove('open');
document.getElementById('cp-backdrop').classList.remove('on');
document.body.style.overflow = '';
cpOpen = false;
cpStopPoll();
cpHideEmoji();
cpHideGif();
// Restore topnav
const topnav = document.getElementById('topnav');
if (topnav) topnav.style.transform = '';
// Restore mobile bottom nav
const nav = document.getElementById('mob-bottom-nav');
if (nav) { nav.style.transform = ''; nav.style.opacity = ''; }
// Restore Crisp support widget
if (window.$crisp) try { $crisp.push(['do','chat:show']); } catch(_) {}
};
function chatPanelOpen() {
document.getElementById('chat-panel').classList.add('open');
document.getElementById('cp-backdrop').classList.add('on');
document.body.style.overflow = 'hidden';
cpOpen = true;
// Hide topnav (site header)
const topnav = document.getElementById('topnav');
if (topnav) topnav.style.transform = 'translateY(-100%)';
// Hide mobile bottom nav
const nav = document.getElementById('mob-bottom-nav');
if (nav) { nav.style.transform = 'translateY(100%)'; nav.style.opacity = '0'; }
// Hide Crisp support widget
if (window.$crisp) try { $crisp.push(['do','chat:hide']); } catch(_) {}
cpShowList();
cpLoadConvs();
}
document.addEventListener('keydown', e => { if (e.key === 'Escape' && cpOpen) chatPanelClose(); });
/* ════════════════════════════════════════════════════
LIST / THREAD SWITCH
════════════════════════════════════════════════════ */
function cpShowList() {
const list = document.getElementById('cp-list');
const thread = document.getElementById('cp-thread');
list.style.display = 'flex';
thread.classList.remove('active');
cpStopPoll();
cpConvId = null;
cpConvUserId = null;
}
window.cpShowList = cpShowList;
function cpShowThread() {
document.getElementById('cp-list').style.display = 'none';
document.getElementById('cp-thread').classList.add('active');
}
/* ════════════════════════════════════════════════════
LOAD CONVERSATIONS
════════════════════════════════════════════════════ */
async function cpLoadConvs() {
const el = document.getElementById('cp-convs');
el.innerHTML = '<div class="cp-loading"><i class="bi bi-hourglass" style="font-size:1.2rem;display:block;margin-bottom:6px;opacity:.3"></i>Yükleniyor…</div>';
try {
const r = await fetch(CP_CONVS_URL, { headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF } });
const convs = await r.json();
if (!convs.length) {
el.innerHTML = '<div class="cp-empty"><i class="bi bi-chat-square-dots"></i>Henüz mesajın yok.</div>';
return;
}
el.innerHTML = '';
convs.forEach(c => {
const convId = c.conv_id ?? c.id;
const letter = (c.name || '?').charAt(0).toUpperCase();
const ava = c.avatar
? `<div class="cp-conv-ava"><img src="${escH(c.avatar)}" alt=""></div>`
: `<div class="cp-conv-ava">${escH(letter)}</div>`;
let preview = '';
if (!c.last_preview) {
preview = '<em style="color:rgba(255,255,255,.2)">Henüz mesaj yok</em>';
} else if (c.last_preview.startsWith('IMAGE::')) {
preview = '📷 Fotoğraf';
} else if (c.last_preview.startsWith('GIF::')) {
preview = '🎞 GIF';
} else {
preview = escH(c.last_preview);
}
const badge = c.unread > 0 ? `<span class="cp-unread-badge">${c.unread > 9 ? '9+' : c.unread}</span>` : '';
const time = c.time ? `<span class="cp-conv-time">${escH(c.time)}</span>` : '';
// data-* ile data taşı — JSON.stringify double-quote HTML attribute'u kırar
const item = document.createElement('div');
item.className = 'cp-conv-item' + (c.unread > 0 ? ' unread' : '');
item.dataset.convId = convId;
item.dataset.userId = c.id || '';
item.dataset.name = c.name || '';
item.dataset.avatar = c.avatar || '';
item.innerHTML = `${ava}
<div class="cp-conv-body">
<div class="cp-conv-name">${escH(c.name || 'Kullanıcı')}</div>
<div class="cp-conv-preview">${preview}</div>
</div>
<div class="cp-conv-meta">${time}${badge}</div>`;
item.addEventListener('click', () => {
cpOpenThread(item.dataset.userId, item.dataset.name, item.dataset.avatar || null, item.dataset.convId);
});
el.appendChild(item);
});
} catch(e) {
el.innerHTML = '<div class="cp-empty">Yüklenemedi.</div>';
const btn = document.createElement('button');
btn.textContent = 'Tekrar dene';
btn.style.cssText = 'color:var(--accent2);background:none;border:none;cursor:pointer;font-size:.84rem;display:block;margin:8px auto';
btn.onclick = cpLoadConvs;
el.appendChild(btn);
}
}
/* ════════════════════════════════════════════════════
OPEN THREAD
════════════════════════════════════════════════════ */
window.cpOpenThread = async function(userId, name, avatar, convId) {
cpConvId = convId;
cpConvUserId = userId;
cpLastMsgId = 0;
cpHideEmoji();
cpHideGif();
document.getElementById('cp-t-name').textContent = name || 'Kullanıcı';
document.getElementById('cp-t-fulllink').href = `/messages/${convId}`;
// Store userId for call button
const callBtn = document.getElementById('cp-t-call-btn');
if (callBtn) callBtn.dataset.userId = userId;
const avaEl = document.getElementById('cp-t-ava');
if (avatar) {
avaEl.innerHTML = `<img src="${escH(avatar)}" alt="">`;
} else {
avaEl.innerHTML = '';
avaEl.textContent = (name || '?').charAt(0).toUpperCase();
}
document.getElementById('cp-msgs').innerHTML = '<div class="cp-loading">Yükleniyor…</div>';
cpShowThread();
try {
const r = await fetch(`/messages/${convId}/poll?after=0`, {
headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF }
});
const d = await r.json();
const msgsEl = document.getElementById('cp-msgs');
msgsEl.innerHTML = '';
if (!d.messages || !d.messages.length) {
msgsEl.innerHTML = '<div class="cp-loading" style="padding:30px 20px;color:rgba(255,255,255,.2)">İlk mesajı sen gönder! 👋</div>';
} else {
d.messages.forEach(m => cpAppendMsg(m));
cpLastMsgId = d.messages[d.messages.length - 1].id;
}
cpScrollBottom(true);
cpUpdateBadge(0);
} catch(e) {}
cpStartPoll();
setTimeout(() => document.getElementById('cp-textarea')?.focus(), 120);
};
/* ════════════════════════════════════════════════════
APPEND MESSAGE
════════════════════════════════════════════════════ */
function cpAppendMsg(m) {
if (document.querySelector(`.cpm[data-id="${m.id}"]`)) return;
const isMine = m.user_id === CP_ME_ID;
const el = document.createElement('div');
el.className = 'cpm ' + (isMine ? 'mine' : 'theirs');
el.dataset.id = m.id;
let content = '';
const body = m.body || '';
if (body.startsWith('ANIMESHARE::')) {
try {
const sd = JSON.parse(body.slice(12));
const url = `/watch/${sd.slug}/${sd.s}/${sd.e}${sd.ts > 0 ? '?t=' + sd.ts : ''}`;
const img = sd.cover ? `<img src="${escH(sd.cover)}" loading="lazy" alt="">` : '';
content = `<a href="${escH(url)}" class="cp-share-card">
<div class="cp-share-img">${img}</div>
<div>
<div class="cp-share-title">${escH(sd.title || '')}</div>
<div class="cp-share-ep">${sd.s}. Sezon ${sd.e}. Bölüm</div>
<div class="cp-share-play"><i class="bi bi-play-circle-fill"></i> İzle</div>
</div>
</a>`;
} catch(_) { content = `<div class="cpm-bubble">${escH(body)}</div>`; }
} else if (body.startsWith('IMAGE::')) {
const url = body.slice(7);
content = `<img src="${escH(url)}" class="cpm-img" loading="lazy" alt="Resim" onclick="window.open('${escH(url)}','_blank')">`;
} else if (body.startsWith('GIF::')) {
const url = body.slice(5);
content = `<img src="${escH(url)}" class="cpm-gif" loading="lazy" alt="GIF">`;
} else {
content = `<div class="cpm-bubble">${escH(body)}</div>`;
}
const avaHtml = !isMine
? (m.avatar
? `<div class="cpm-ava"><img src="${escH(m.avatar)}" alt=""></div>`
: `<div class="cpm-ava">${escH((m.name || '?').charAt(0).toUpperCase())}</div>`)
: '';
el.innerHTML = avaHtml + `<div>${content}</div><span class="cpm-time">${escH(m.created_at || '')}</span>`;
document.getElementById('cp-msgs').appendChild(el);
}
function cpScrollBottom(force = false) {
const el = document.getElementById('cp-msgs');
if (!el) return;
const near = el.scrollHeight - el.scrollTop - el.clientHeight < 200;
if (force || near) el.scrollTop = el.scrollHeight;
}
/* ════════════════════════════════════════════════════
SEND TEXT
════════════════════════════════════════════════════ */
window.cpSend = async function() {
if (!cpConvId) return;
const ta = document.getElementById('cp-textarea');
const btn = document.getElementById('cp-send-btn');
const text = ta.value.trim();
if (!text) return;
ta.value = '';
ta.style.height = 'auto';
btn.disabled = true;
try {
const r = await fetch(`/messages/${cpConvId}/send`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
body: JSON.stringify({ body: text }),
});
const d = await r.json();
cpAppendMsg({ id: d.id, body: d.body, user_id: CP_ME_ID, created_at: d.created_at, avatar: CP_MY_AVA, name: CP_MY_NAME });
if (d.id > cpLastMsgId) cpLastMsgId = d.id;
cpScrollBottom(true);
} catch(_) { ta.value = text; }
btn.disabled = false;
};
/* ════════════════════════════════════════════════════
SEND IMAGE
════════════════════════════════════════════════════ */
window.cpSendImage = async function(input) {
const file = input.files[0];
if (!file || !cpConvId) return;
input.value = '';
try {
const fd = new FormData();
fd.append('image', file);
const r = await fetch(CP_UPLOAD_URL, {
method: 'POST',
headers: { 'X-CSRF-TOKEN': CP_CSRF, 'Accept': 'application/json' },
body: fd,
});
const d = await r.json();
if (!d.url) throw new Error('No URL');
const r2 = await fetch(`/messages/${cpConvId}/send`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
body: JSON.stringify({ body: 'IMAGE::' + d.url }),
});
const d2 = await r2.json();
cpAppendMsg({ id: d2.id, body: d2.body, user_id: CP_ME_ID, created_at: d2.created_at, avatar: CP_MY_AVA, name: CP_MY_NAME });
if (d2.id > cpLastMsgId) cpLastMsgId = d2.id;
cpScrollBottom(true);
} catch(e) {
showToast('Resim gönderilemedi.', 'error');
}
};
/* ════════════════════════════════════════════════════
SEND GIF
════════════════════════════════════════════════════ */
window.cpSendGif = async function(gifUrl) {
if (!cpConvId) return;
cpHideGif();
try {
const r = await fetch(`/messages/${cpConvId}/send`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
body: JSON.stringify({ body: 'GIF::' + gifUrl }),
});
const d = await r.json();
cpAppendMsg({ id: d.id, body: d.body, user_id: CP_ME_ID, created_at: d.created_at, avatar: CP_MY_AVA, name: CP_MY_NAME });
if (d.id > cpLastMsgId) cpLastMsgId = d.id;
cpScrollBottom(true);
} catch(_) { showToast('GIF gönderilemedi.', 'error'); }
};
/* ════════════════════════════════════════════════════
EMOJI PICKER
════════════════════════════════════════════════════ */
const EMOJIS = '😀😂😅😊😍🥰😘😎😭😤😡🥺🤔😴🤩🥳😱🙈🙄😏🤗😬😵👍👎❤️🔥💯✨🎉🎊🎮🎬🎵🍕🍜🍣🎃👻🦊🐱🐶🐼🌸🌙⭐🌈💎🚀🏆🎯🔮';
const emojiArr = [...EMOJIS];
function cpInitEmoji() {
const picker = document.getElementById('cp-emoji-picker');
if (!picker || picker.dataset.built) return;
picker.dataset.built = '1';
const frag = document.createDocumentFragment();
emojiArr.forEach(em => {
const btn = document.createElement('button');
btn.className = 'cp-emoji-btn';
btn.textContent = em;
btn.title = em;
btn.onclick = () => {
const ta = document.getElementById('cp-textarea');
const pos = ta.selectionStart;
ta.value = ta.value.slice(0, pos) + em + ta.value.slice(ta.selectionEnd);
ta.selectionStart = ta.selectionEnd = pos + em.length;
ta.dispatchEvent(new Event('input'));
ta.focus();
};
frag.appendChild(btn);
});
picker.appendChild(frag);
}
window.cpToggleEmoji = function() {
cpEmojiOpen = !cpEmojiOpen;
if (cpEmojiOpen) {
cpHideGif();
cpInitEmoji();
}
document.getElementById('cp-emoji-picker').classList.toggle('show', cpEmojiOpen);
document.getElementById('cp-emoji-btn')?.classList.toggle('active', cpEmojiOpen);
};
function cpHideEmoji() {
cpEmojiOpen = false;
document.getElementById('cp-emoji-picker')?.classList.remove('show');
document.getElementById('cp-emoji-btn')?.classList.remove('active');
}
/* Show emoji btn on desktop */
if (!IS_MOBILE) {
const eb = document.getElementById('cp-emoji-btn');
if (eb) eb.style.display = '';
}
/* ════════════════════════════════════════════════════
GIF PICKER (Tenor)
════════════════════════════════════════════════════ */
window.cpToggleGif = function() {
cpGifOpen = !cpGifOpen;
if (cpGifOpen) {
cpHideEmoji();
if (TENOR_KEY) cpSearchGifs('');
}
document.getElementById('cp-gif-picker').classList.toggle('show', cpGifOpen);
document.getElementById('cp-gif-btn')?.classList.toggle('active', cpGifOpen);
if (cpGifOpen) setTimeout(() => document.getElementById('cp-gif-input')?.focus(), 100);
};
function cpHideGif() {
cpGifOpen = false;
document.getElementById('cp-gif-picker')?.classList.remove('show');
document.getElementById('cp-gif-btn')?.classList.remove('active');
}
async function cpSearchGifs(q) {
const grid = document.getElementById('cp-gif-grid');
if (!grid) return;
if (!TENOR_KEY) {
grid.innerHTML = '<div class="cp-gif-placeholder">TENOR_API_KEY ayarlanmamış.<br>GIF özelliği devre dışı.</div>';
return;
}
grid.innerHTML = '<div class="cp-gif-placeholder">Yükleniyor…</div>';
try {
const endpoint = q
? `https://tenor.googleapis.com/v2/search?q=${encodeURIComponent(q)}&key=${TENOR_KEY}&limit=12&media_filter=gif`
: `https://tenor.googleapis.com/v2/featured?key=${TENOR_KEY}&limit=12&media_filter=gif`;
const r = await fetch(endpoint);
const d = await r.json();
const results = d.results || [];
if (!results.length) { grid.innerHTML = '<div class="cp-gif-placeholder">Sonuç bulunamadı.</div>'; return; }
grid.innerHTML = results.map(g => {
const url = g.media_formats?.tinygif?.url || g.media_formats?.gif?.url || '';
return url ? `<div class="cp-gif-item" onclick="cpSendGif('${escH(url)}')"><img src="${escH(url)}" alt="" loading="lazy"></div>` : '';
}).filter(Boolean).join('');
} catch(e) {
grid.innerHTML = '<div class="cp-gif-placeholder">Yüklenemedi.</div>';
}
}
document.getElementById('cp-gif-input')?.addEventListener('input', function() {
clearTimeout(cpGifTimer);
cpGifTimer = setTimeout(() => cpSearchGifs(this.value.trim()), 400);
});
/* ════════════════════════════════════════════════════
TEXTAREA EVENTS
════════════════════════════════════════════════════ */
document.getElementById('cp-textarea')?.addEventListener('keydown', e => {
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); cpSend(); }
});
document.getElementById('cp-textarea')?.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = Math.min(this.scrollHeight, 100) + 'px';
// hide pickers when typing
if (this.value) { cpHideEmoji(); cpHideGif(); }
});
/* ════════════════════════════════════════════════════
POLLING (messages)
════════════════════════════════════════════════════ */
function cpStartPoll() {
cpStopPoll();
cpPollTimer = setInterval(cpPoll, 3000);
}
function cpStopPoll() {
clearInterval(cpPollTimer);
cpPollTimer = null;
}
async function cpPoll() {
if (!cpConvId || !cpOpen) return;
try {
const r = await fetch(`/messages/${cpConvId}/poll?after=${cpLastMsgId}`, {
headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF }
});
const d = await r.json();
if (d.messages && d.messages.length) {
d.messages.forEach(m => {
if (m.user_id !== CP_ME_ID) {
cpAppendMsg(m);
if (m.id > cpLastMsgId) cpLastMsgId = m.id;
}
});
cpScrollBottom();
}
} catch(_) {}
}
/* ════════════════════════════════════════════════════
BADGE UPDATE
════════════════════════════════════════════════════ */
function cpUpdateBadge(count) {
const badge = document.getElementById('cp-nav-badge');
const icon = document.getElementById('cp-nav-icon');
if (badge) {
badge.style.display = count > 0 ? '' : 'none';
badge.textContent = count > 9 ? '9+' : count;
}
if (icon) icon.className = count > 0 ? 'bi bi-chat-dots-fill' : 'bi bi-chat-dots';
}
/* ════════════════════════════════════════════════════
VOICE CALLS
════════════════════════════════════════════════════ */
let vcCallId = null;
let vcAgoraClient = null;
let vcCallTimer = null;
let vcCallSecs = 0;
let vcPollTimer = null;
/* Start outgoing call */
window.cpStartCall = async function() {
const callBtn = document.getElementById('cp-t-call-btn');
const userId = cpConvUserId || (callBtn && callBtn.dataset.userId);
if (!userId) return;
try {
const r = await fetch('/calls/initiate', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
body: JSON.stringify({ callee_id: parseInt(userId) }),
});
const d = await r.json();
if (d.error) { showToast(d.error, 'error'); return; }
vcCallId = d.call_id;
vcShowOutgoing(d.callee.name, d.callee.avatar);
vcMaybeJoinAgora(d.agora_app_id, d.channel_name, d.token, CP_ME_ID);
vcStartCallPoll();
} catch(e) { showToast('Arama başlatılamadı.', 'error'); }
};
/* Answer incoming call */
window.vcAnswer = async function() {
if (!vcCallId) return;
try {
const r = await fetch(`/calls/${vcCallId}/answer`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
});
const d = await r.json();
vcShowActive(document.getElementById('call-name-el')?.textContent);
vcMaybeJoinAgora(d.agora_app_id, d.channel_name, d.token, CP_ME_ID);
} catch(e) { showToast('Arama cevaplanamadı.', 'error'); }
};
/* Decline */
window.vcDecline = async function() {
if (!vcCallId) return;
const id = vcCallId;
vcCallId = null;
vcHideOverlay();
try {
await fetch(`/calls/${id}/decline`, {
method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
});
} catch(_) {}
};
/* End call */
window.vcEnd = async function() {
const id = vcCallId;
vcCallId = null;
vcHideOverlay();
vcHideCallBar();
vcStopCallPoll();
vcLeaveAgora();
if (!id) return;
try {
await fetch(`/calls/${id}/end`, {
method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
});
} catch(_) {}
};
function vcShowIncoming(name, avatar, callId) {
vcCallId = callId;
const avaEl = document.getElementById('call-ava-el');
const nameEl = document.getElementById('call-name-el');
const statusEl = document.getElementById('call-status-el');
const btnsEl = document.getElementById('call-btns-el');
if (!avaEl) return;
if (avatar) {
avaEl.innerHTML = `<img src="${escH(avatar)}" alt="">`;
} else {
avaEl.innerHTML = '';
avaEl.textContent = (name || '?').charAt(0).toUpperCase();
}
if (nameEl) nameEl.textContent = name || 'Bilinmeyen';
if (statusEl) statusEl.textContent = 'Sesli arama geliyor…';
if (btnsEl) btnsEl.innerHTML = `
<button class="call-btn call-btn-decline" onclick="vcDecline()" title="Reddet">
<i class="bi bi-telephone-x-fill"></i>
</button>
<button class="call-btn call-btn-accept" onclick="vcAnswer()" title="Kabul et">
<i class="bi bi-telephone-fill"></i>
</button>`;
document.getElementById('call-overlay').classList.add('show');
}
function vcShowOutgoing(name, avatar) {
const avaEl = document.getElementById('call-ava-el');
const nameEl = document.getElementById('call-name-el');
const statusEl = document.getElementById('call-status-el');
const btnsEl = document.getElementById('call-btns-el');
if (!avaEl) return;
if (avatar) avaEl.innerHTML = `<img src="${escH(avatar)}" alt="">`;
else { avaEl.innerHTML = ''; avaEl.textContent = (name||'?').charAt(0).toUpperCase(); }
if (nameEl) nameEl.textContent = name || '';
if (statusEl) statusEl.textContent = 'Aranıyor…';
if (btnsEl) btnsEl.innerHTML = `
<button class="call-btn call-btn-decline" onclick="vcEnd()" title="İptal">
<i class="bi bi-telephone-x-fill"></i>
</button>`;
document.getElementById('call-overlay').classList.add('show');
}
function vcShowActive(name) {
vcHideOverlay();
const bar = document.getElementById('call-bar');
if (!bar) return;
document.getElementById('call-bar-name').textContent = name || '';
vcCallSecs = 0;
clearInterval(vcCallTimer);
vcCallTimer = setInterval(() => {
vcCallSecs++;
const m = String(Math.floor(vcCallSecs / 60)).padStart(2, '0');
const s = String(vcCallSecs % 60).padStart(2, '0');
const el = document.getElementById('call-bar-timer');
if (el) el.textContent = `${m}:${s}`;
}, 1000);
bar.classList.add('show');
}
function vcHideOverlay() {
document.getElementById('call-overlay')?.classList.remove('show');
}
function vcHideCallBar() {
clearInterval(vcCallTimer);
document.getElementById('call-bar')?.classList.remove('show');
}
/* Agora Web SDK integration */
function vcMaybeJoinAgora(appId, channel, token, uid) {
if (!appId || !window.AgoraRTC) return;
try {
vcLeaveAgora();
vcAgoraClient = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp8' });
vcAgoraClient.join(appId, channel, token || null, uid).then(() => {
return AgoraRTC.createMicrophoneAudioTrack();
}).then(track => {
vcAgoraClient.publish([track]);
}).catch(e => { console.warn('Agora join failed:', e); });
} catch(e) {}
}
async function vcLeaveAgora() {
if (!vcAgoraClient) return;
try { await vcAgoraClient.leave(); } catch(_) {}
vcAgoraClient = null;
}
/* Poll for incoming calls + call status changes */
function vcStartCallPoll() {
vcStopCallPoll();
vcPollTimer = setInterval(vcPollCalls, 4000);
}
function vcStopCallPoll() {
clearInterval(vcPollTimer);
vcPollTimer = null;
}
async function vcPollCalls() {
try {
const url = vcCallId ? `/calls/poll?call_id=${vcCallId}` : '/calls/poll';
const r = await fetch(url, { headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF } });
const d = await r.json();
if (d.type === 'incoming' && !vcCallId) {
vcShowIncoming(d.caller.name, d.caller.avatar, d.call_id);
} else if (d.type === 'status') {
if (d.status === 'active' && document.getElementById('call-overlay')?.classList.contains('show')) {
// Other side answered our outgoing — switch to active bar
const nameEl = document.getElementById('call-name-el');
vcShowActive(nameEl?.textContent);
} else if (d.status === 'ended' || d.status === 'declined') {
vcCallId = null;
vcHideOverlay();
vcHideCallBar();
vcLeaveAgora();
vcStopCallPoll();
if (d.status === 'declined') showToast('Arama reddedildi.', 'info');
else showToast('Arama sona erdi.', 'info');
}
}
} catch(_) {}
}
// Start polling for calls immediately (even without active call)
vcStartCallPoll();
/* ════════════════════════════════════════════════════
UTIL
════════════════════════════════════════════════════ */
function escH(s) {
return String(s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
})();
</script>
@endauth
{{-- Crisp Chat --}}
<script type="text/javascript">
window.$crisp=[];
window.$crisp.push(["config","position:reverse",[true]]);
window.CRISP_WEBSITE_ID="a484d897-f0e5-478c-acc5-ac9ec0814dd8";
(function(){d=document;s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();
</script>
</body>
</html>