AJARA - SOURCE CODE UNTUK FINAL FIX


====================================
routes\web.php
====================================
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\CompetitionController;
use App\Http\Controllers\RegistrationController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\NotificationController;
use App\Http\Controllers\OrganizerController;
use App\Http\Controllers\AdminController;
use App\Http\Controllers\ChatController;

Route::get('/', [HomeController::class, 'index'])
    ->name('welcome');

// Alias kompatibilitas untuk tautan lama yang masih memanggil route('home').
Route::get('/home', fn () => redirect()->route('welcome'))->name('home');

Route::get('/lomba', [CompetitionController::class, 'index'])
    ->name('competitions.index');
Route::get('/lomba/{competition}', [CompetitionController::class, 'show'])
    ->name('competitions.show');

Route::middleware('guest')->group(function () {
    Route::get('/login', [AuthController::class, 'showLogin'])
        ->name('login');
    Route::get('/forgot-password', [AuthController::class, 'showForgotPassword'])
        ->name('password.request');
    Route::post('/login', [AuthController::class, 'login'])
        ->name('login.store');

    Route::get('/register', [AuthController::class, 'showRegister'])    
    ->name('register');
    Route::post('/register', [AuthController::class, 'register'])
        ->name('register.store');
    });

Route::middleware('auth')->group(function () {
    Route::post('/logout', [AuthController::class, 'logout'])
        ->name('logout');
    Route::post('/lomba/{competition}/favorit', [CompetitionController::class, 'toggleFavorite'])
        ->name('competitions.favorite');
    Route::get('/chat', [ChatController::class, 'index'])
        ->name('chat.index');
    Route::post('/chat', [ChatController::class, 'store'])
        ->name('chat.store');

    Route::middleware('role:mahasiswa')->group(function () {
        Route::get('/dashboard', [DashboardController::class, 'index'])
            ->name('dashboard');
        Route::get('/lomba/{competition}/daftar', [RegistrationController::class, 'create'])
            ->name('registrations.create');
        Route::post('/lomba/{competition}/daftar', [RegistrationController::class, 'store'])
            ->name('registrations.store');
        Route::get('/notifikasi', [NotificationController::class, 'index'])
            ->name('notifications.index');
        Route::post('/notifikasi/{notification}/read', [NotificationController::class, 'markRead'])
            ->name('notifications.read');
        Route::get('/profil', [ProfileController::class, 'show'])
            ->name('profile.show');
        Route::get('/profil/data-akun', [ProfileController::class, 'edit'])
            ->name('profile.edit');
        Route::put('/profil/data-akun', [ProfileController::class, 'update'])
            ->name('profile.update');
    });

    Route::middleware('role:penyelenggara')
        ->prefix('penyelenggara')
        ->name('organizer.')
        ->group(function () {

            Route::get('/', [OrganizerController::class, 'index'])
                ->name('dashboard');

            Route::get('/lomba/baru', [OrganizerController::class, 'create'])
                ->name('create');

            Route::post('/lomba', [OrganizerController::class, 'store'])
                ->name('store');

            Route::get('/pengajuan/{order}/edit', [OrganizerController::class, 'edit'])
                ->name('edit');

            Route::put('/pengajuan/{order}', [OrganizerController::class, 'update'])
                ->name('update');

            Route::get('/pembayaran/{order}', [OrganizerController::class, 'payment'])
                ->name('payment');

            Route::post('/pembayaran/{order}', [OrganizerController::class, 'submitPayment'])
                ->name('payment.submit');

            Route::get('/pembayaran/{order}/struk', [OrganizerController::class, 'receipt'])
                ->name('payment.receipt');

            Route::post('/pengajuan/{order}/tutup', [OrganizerController::class, 'closeCompetition'])
                ->name('close');

            // Kelola lomba yang sudah dipublikasikan
            Route::get('/lomba/{order}/kelola', [OrganizerController::class, 'manage'])
                ->name('manage');

            Route::put('/lomba/{order}/kelola', [OrganizerController::class, 'updatePublished'])
                ->name('manage.update');
        });
        
        Route::middleware('role:admin')
        ->prefix('admin')
        ->name('admin.')
        ->group(function () {

        Route::get('/', [AdminController::class, 'index'])
            ->name('dashboard');
        // Pemeriksaan informasi lomba
        Route::post('/pengajuan/{order}/review', [AdminController::class, 'reviewContent'])
            ->name('content.review');
        // Verifikasi pembayaran
        Route::post('/publikasi/{order}/review', [AdminController::class, 'review'])
            ->name('publication.review');
        Route::post('/publikasi/{order}/hapus-poster', [AdminController::class, 'removePoster'])->name('poster.remove');
        });
    });
// AJARA ADMIN COMMAND CENTER - route moderasi
Route::middleware(['auth','role:admin'])->prefix('admin')->name('admin.')->group(function () {
    Route::post('/publikasi/{order}/turunkan', [AdminController::class, 'hidePoster'])->name('poster.hide');
    Route::post('/publikasi/{order}/aktifkan-kembali', [AdminController::class, 'restorePoster'])->name('poster.restore');
    Route::post('/publikasi/{order}/aktifkan-masa-tayang', [AdminController::class, 'activatePromotion'])->name('promotion.activate');
    Route::post('/publikasi/{order}/perpanjang', [AdminController::class, 'extendPromotion'])->name('promotion.extend');
});
Route::middleware('auth')->group(function () {
    Route::get('/notifikasi', [NotificationController::class, 'index'])->name('notifications.index');
    Route::post('/notifikasi/{notification}/read', [NotificationController::class, 'markRead'])->name('notifications.read');
});
// AJARA CONNECT - NOTIFIKASI
\Illuminate\Support\Facades\Route::middleware('auth')->get('/ajara-notification/{id}', function ($id) {
    $notification = \App\Models\Notification::where('user_id', auth()->id())
        ->findOrFail($id);

    $notification->update(['read_at' => now()]);

    return redirect()->route('chat.index');
})->name('ajara.notification.open');

\Illuminate\Support\Facades\Route::middleware('auth')->get('/ajara-notification-count', function () {
    return response()->json([
        'count' => \App\Models\Notification::where('user_id', auth()->id())
            ->whereNull('read_at')->count()
    ]);
})->name('ajara.notification.count');

// AJARA CONNECT - MARK CHAT AS READ
\Illuminate\Support\Facades\Route::middleware('auth')->post(
    '/ajara-chat-mark-read',
    function () {
        $user = auth()->user();

        if ($user->role === 'admin') {
            \App\Models\ChatMessage::where('sender_role', 'user')
                ->whereNull('read_at')
                ->update(['read_at' => now()]);
        } elseif ($user->role === 'penyelenggara') {
            \App\Models\ChatMessage::where('user_id', $user->id)
                ->where('sender_role', 'admin')
                ->whereNull('read_at')
                ->update(['read_at' => now()]);
        } else {
            abort(403);
        }

        return response()->json(['success' => true]);
    }
)->name('ajara.chat.mark-read');

// AJARA NAVIGATION FIX
Route::view('/about', 'about')->name('about');



====================================
app\Http\Controllers\ProfileController.php
====================================
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class ProfileController extends Controller
{
    public function show()
    {
        return view('profile.show');
    }

    public function edit()
    {
        return view('profile.edit');
    }

    public function update(Request $request)
    {
        $user = $request->user();

        $data = $request->validate([
            'name' => ['required', 'string', 'max:120'],

            'nim' => [
                'required',
                'string',
                'max:30',
                'unique:users,nim,' . $user->id,
            ],

            'email' => [
                'required',
                'email',
                'max:150',
                'unique:users,email,' . $user->id,
            ],

            'avatar' => [
                'nullable',
                'image',
                'mimes:jpg,jpeg,png,webp',
                'max:3072',
            ],
        ], [
            'avatar.image' => 'File harus berupa gambar.',
            'avatar.mimes' => 'Foto harus berformat JPG, PNG, atau WEBP.',
            'avatar.max' => 'Ukuran foto maksimal 3 MB.',
        ]);

        unset($data['avatar']);

        $oldAvatar = $user->avatar;
        $newAvatar = null;

        if ($request->hasFile('avatar')) {
            $newAvatar = $request->file('avatar')
                ->store('avatars', 'public');
        }

        $user->fill($data);

        if ($newAvatar) {
            $user->avatar = $newAvatar;
        }

        $user->save();

        if (
            $newAvatar &&
            $oldAvatar &&
            str_starts_with($oldAvatar, 'avatars/') &&
            Storage::disk('public')->exists($oldAvatar)
        ) {
            Storage::disk('public')->delete($oldAvatar);
        }

        return redirect()
            ->route('profile.show')
            ->with('success', 'Profil mahasiswa berhasil diperbarui.');
    }
}


====================================
app\Http\Controllers\AdminController.php
====================================
<?php

namespace App\Http\Controllers;

use App\Models\Competition;
use App\Models\Notification;
use App\Models\PublicationOrder;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class AdminController extends Controller
{
    public function index()
    {
        $stats = [
            'users' => User::where('role', 'mahasiswa')->count(),
            'organizers' => User::where('role', 'penyelenggara')->count(),
            'competitions' => Competition::count(),
            'pending_content' => PublicationOrder::where('content_review_status', 'pending')->count(),
            'pending' => PublicationOrder::where('payment_status', 'pending')->count(),
            'published' => Competition::where('status', 'published')->count(),
            'revenue' => (int) PublicationOrder::where('payment_status', 'verified')->sum('amount'),
        ];

        $contentOrders = PublicationOrder::with(['user','competition'])->where('content_review_status','pending')->latest()->get();
        $orders = PublicationOrder::with(['user','competition'])->where('payment_status','pending')->latest()->get();
        $allOrders = PublicationOrder::with(['user','competition'])->latest()->get();
        $organizers = User::where('role','penyelenggara')->withCount('publicationOrders')->with(['publicationOrders.competition'])->orderBy('name')->get();
        $publishedOrders = PublicationOrder::with(['user','competition'])->where('payment_status','verified')->latest()->get();
        $audits = DB::table('publication_audits')->latest()->limit(30)->get();
        $chatUsers = User::where('role','penyelenggara')->orderBy('name')->get();

        return view('admin.dashboard', compact('stats','contentOrders','orders','allOrders','organizers','publishedOrders','audits','chatUsers'));
    }

    public function reviewContent(Request $request, PublicationOrder $order)
    {
        $data = $request->validate([
            'decision' => 'required|in:approve,revision',
            'admin_note' => 'nullable|string|max:2000',
        ]);
        abort_unless($order->content_review_status === 'pending', 422, 'Pengajuan ini sudah diperiksa.');
        $approved = $data['decision'] === 'approve';
        DB::transaction(function () use ($order,$data,$approved) {
            $order->update([
                'content_review_status' => $approved ? 'approved' : 'revision',
                'content_admin_note' => $data['admin_note'] ?? ($approved ? 'Informasi lomba telah disetujui.' : 'Mohon perbaiki informasi lomba.'),
                'content_reviewed_at' => now(),
                'content_reviewed_by' => auth()->id(),
            ]);
            $this->notifyOrganizer($order, $approved ? 'Pengajuan lomba disetujui' : 'Pengajuan lomba perlu direvisi', $approved ? 'Informasi lomba disetujui. Silakan lanjutkan pembayaran publikasi.' : 'Admin meminta revisi: '.($data['admin_note'] ?? '-'), $approved ? 'success' : 'warning');
            $this->audit('content_review', $order, $approved ? 'Pengajuan konten disetujui' : 'Pengajuan konten diminta revisi', $data['admin_note'] ?? null);
        });
        return back()->with('success', $approved ? 'Konten disetujui. Penyelenggara dapat melanjutkan pembayaran.' : 'Permintaan revisi berhasil dikirim.');
    }

    public function review(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['decision'=>'required|in:approve,reject','admin_note'=>'nullable|string|max:2000']);
        $order->load(['user','competition']);
        abort_unless(
            $order->content_review_status === 'approved',
            422,
            'Informasi lomba harus disetujui sebelum pembayaran dapat diverifikasi.'
        );
        abort_unless($order->payment_status === 'pending' && $order->review_status === 'pending', 422, 'Pembayaran ini sudah diproses.');
        abort_unless($order->proof_path && Storage::disk('public')->exists($order->proof_path), 422, 'Bukti transfer belum tersedia.');
        $approved = $data['decision'] === 'approve';
        $days = ['Basic'=>30,'Premium'=>60,'Featured'=>90][$order->package] ?? null;
        abort_if($approved && !$days, 422, 'Paket publikasi tidak valid.');

        DB::transaction(function () use ($order,$data,$approved,$days) {
            $update = [
                'payment_status' => $approved ? 'verified' : 'rejected',
                'review_status' => $approved ? 'approved' : 'rejected',
                'admin_note' => $data['admin_note'] ?? ($approved ? 'Pembayaran diverifikasi Admin AJARA.' : 'Pembayaran ditolak Admin AJARA.'),
            ];
            if ($approved) {
                $start = now();
                $update['promotion_started_at'] = $start;
                $update['promotion_ends_at'] = $start->copy()->addDays($days);
                $order->competition->update(['status'=>'published','admin_hidden_at'=>null,'admin_hidden_by'=>null,'admin_hidden_reason'=>null]);
            } else {
                $order->competition->update(['status'=>'draft']);
            }
            $order->update($update);
            $this->notifyOrganizer($order, $approved ? 'Pembayaran berhasil diverifikasi' : 'Pembayaran ditolak', $approved ? "Pembayaran disetujui. Masa tayang paket {$order->package} aktif selama {$days} hari." : 'Pembayaran belum disetujui: '.($data['admin_note'] ?? '-'), $approved ? 'success' : 'warning');
            $this->audit('payment_review', $order, $approved ? 'Pembayaran diverifikasi' : 'Pembayaran ditolak', $data['admin_note'] ?? null);
        });
        return back()->with('success', $approved ? "Pembayaran diverifikasi dan masa tayang {$days} hari diaktifkan." : 'Pembayaran ditolak.');
    }

    public function hidePoster(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['reason'=>'required|string|max:2000']);
        $order->load('competition');
        abort_unless($order->competition, 404);
        $order->competition->update(['status'=>'draft','admin_hidden_at'=>now(),'admin_hidden_by'=>auth()->id(),'admin_hidden_reason'=>$data['reason']]);
        $this->notifyOrganizer($order, 'Poster diturunkan oleh Admin AJARA', 'Poster lomba dinonaktifkan oleh Admin. Alasan: '.$data['reason'], 'warning');
        $this->audit('poster_hidden',$order,'Poster diturunkan',$data['reason']);
        return back()->with('success','Poster berhasil diturunkan. Riwayat dan tanggal promosi tetap tersimpan.');
    }

    public function restorePoster(PublicationOrder $order)
    {
        $order->load('competition');
        abort_unless($order->competition && $order->payment_status === 'verified' && $order->promotion_ends_at && now()->lt($order->promotion_ends_at), 422, 'Poster tidak dapat diaktifkan: pembayaran atau masa tayang tidak valid.');
        $order->competition->update(['status'=>'published','admin_hidden_at'=>null,'admin_hidden_by'=>null,'admin_hidden_reason'=>null]);
        $this->notifyOrganizer($order,'Poster diaktifkan kembali','Admin AJARA mengaktifkan kembali poster lomba Anda.','success');
        $this->audit('poster_restored',$order,'Poster diaktifkan kembali',null);
        return back()->with('success','Poster berhasil ditayangkan kembali.');
    }

    public function activatePromotion(PublicationOrder $order)
    {
        abort_unless($order->payment_status === 'verified' && $order->review_status === 'approved', 422, 'Pembayaran belum disetujui.');
        abort_unless(!$order->promotion_started_at || !$order->promotion_ends_at, 422, 'Masa tayang sudah pernah diaktifkan. Gunakan fitur perpanjang.');
        $days = ['Basic'=>30,'Premium'=>60,'Featured'=>90][$order->package] ?? null;
        abort_unless($days, 422, 'Paket publikasi tidak valid.');
        $start = now();
        $order->update(['promotion_started_at'=>$start,'promotion_ends_at'=>$start->copy()->addDays($days)]);
        $this->notifyOrganizer($order, 'Masa tayang diaktifkan Admin', "Admin mengaktifkan masa tayang {$order->package} selama {$days} hari.", 'success');
        $this->audit('promotion_activated',$order,'Masa tayang diaktifkan manual',"{$days} hari");
        return back()->with('success', "Masa tayang {$days} hari berhasil diaktifkan.");
    }

    public function extendPromotion(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['days'=>'required|integer|min:1|max:365']);
        abort_unless($order->payment_status === 'verified' && $order->promotion_started_at, 422, 'Masa tayang belum pernah diaktifkan.');
        $base = $order->promotion_ends_at && $order->promotion_ends_at->isFuture() ? $order->promotion_ends_at->copy() : now();
        $order->update(['promotion_ends_at'=>$base->addDays((int)$data['days'])]);
        $this->notifyOrganizer($order,'Masa tayang diperpanjang',"Admin memperpanjang masa tayang poster selama {$data['days']} hari.",'success');
        $this->audit('promotion_extended',$order,'Masa tayang diperpanjang',$data['days'].' hari');
        return back()->with('success','Masa tayang berhasil diperpanjang.');
    }

    public function removePoster(Request $request, PublicationOrder $order)
    {
        $data = $request->validate(['reason'=>'required|string|max:2000']);
        $order->load('competition');
        abort_unless($order->competition,404);
        $competition = $order->competition;
        if ($competition->banner) Storage::disk('public')->delete($competition->banner);
        $competition->update(['banner'=>null,'status'=>'draft','admin_hidden_at'=>now(),'admin_hidden_by'=>auth()->id(),'admin_hidden_reason'=>$data['reason']]);
        $this->notifyOrganizer($order,'Poster dihapus oleh Admin AJARA','File poster dihapus. Alasan: '.$data['reason'],'danger');
        $this->audit('poster_deleted',$order,'File poster dihapus',$data['reason']);
        return back()->with('success','File poster dihapus. Data lomba dan riwayat transaksi tetap dipertahankan.');
    }

    private function notifyOrganizer(PublicationOrder $order, string $title, string $message, string $type='info'): void
    {
        Notification::create(['user_id'=>$order->user_id,'title'=>$title,'message'=>$message,'type'=>$type]);
    }

    private function audit(string $action, PublicationOrder $order, string $description, ?string $detail): void
    {
        DB::table('publication_audits')->insert([
            'admin_id'=>auth()->id(),'user_id'=>$order->user_id,'publication_order_id'=>$order->id,
            'competition_id'=>$order->competition_id,'action'=>$action,'description'=>$description,
            'detail'=>$detail,'created_at'=>now(),'updated_at'=>now(),
        ]);
    }
}


====================================
app\Http\Controllers\OrganizerController.php
====================================
<?php

namespace App\Http\Controllers;

use App\Models\Competition;
use App\Models\PublicationOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class OrganizerController extends Controller
{
    private const PACKAGES = [
        'Basic' => 49000,
        'Premium' => 99000,
        'Featured' => 199000,
    ];
    public function index()
    {
        $orders = auth()->user()
            ->publicationOrders()
            ->with('competition')
            ->latest()
            ->get();

        return view('organizer.dashboard', compact('orders'));
    }

    public function create()
    {
        return view('organizer.create', [
            'packages' => self::PACKAGES
        ]);
    }

    public function store(Request $r)
    {
        $d = $r->validate([
            'title' => 'required|string|max:180',
            'organizer' => 'required|string|max:180',
            'competition_category' => 'required|string|max:100',
            'competition_level' => 'required|string|max:50',
            'delivery_mode' => 'required|in:Online,Offline,Hybrid',
            'location' => 'nullable|string|max:180',
            'description' => 'required|string|max:10000',
            'requirements' => 'required|string|max:10000',
            'benefits' => 'nullable|string|max:5000',
            'registration_start' => 'required|date',
            'registration_end' => 'required|date|after_or_equal:registration_start',
            'event_start' => 'nullable|date',
            'event_end' => 'nullable|date|after_or_equal:event_start',
            'contact' => 'required|string|max:180',
            'banner' => 'required|image|mimes:jpg,jpeg,png,webp|max:5120',
            'package' => 'required|in:Basic,Premium,Featured',
        ]);

        $mode = $d['delivery_mode'];

        $banner = $r->file('banner')
            ->store('competition-posters', 'public');

        $competition = Competition::create([
            'title' => $d['title'],
            'organizer' => $d['organizer'],
            'category' => $d['competition_level'] === 'Internasional'
                ? 'Internasional'
                : ($d['competition_level'] === 'Nasional'
                    ? 'Nasional' : 'Kampus'),
            'competition_category' => $d['competition_category'],
            'competition_level' => $d['competition_level'],
            'mode' => $mode === 'Offline' ? 'Offline' : 'Online',
            'delivery_mode' => $mode,
            'location' => $d['location'] ?? ($mode === 'Online' ? 'Online' : null),
            'description' => $d['description'],
            'requirements' => $d['requirements'],
            'benefits' => $d['benefits'] ?? null,
            'registration_start' => $d['registration_start'],
            'registration_end' => $d['registration_end'],
            'event_start' => $d['event_start'] ?? null,
            'event_end' => $d['event_end'] ?? null,
            'contact' => $d['contact'],
            'banner' => $banner,
            'status' => 'draft',
        ]);

        PublicationOrder::create([
            'user_id' => auth()->id(),
            'competition_id' => $competition->id,
            'package' => $d['package'],
            'amount' => self::PACKAGES[$d['package']],

            // Pemeriksaan informasi lomba
            'content_review_status' => 'pending',
            'content_admin_note' => null,
            'content_reviewed_at' => null,
            'content_reviewed_by' => null,

            // Pembayaran
            'payment_status' => 'unpaid',
            'review_status' => 'pending',
        ]);
        return redirect()
            ->route('organizer.dashboard')
            ->with(
                'success', 
                'Pengajuan berhasil dikirim. Silakan tunggu pemeriksaan Admin AJARA sebelum melakukan pembayaran.');
    }

    public function edit(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'revision',
        403,
        'Pengajuan ini tidak sedang menunggu revisi.'
    );

    $order->load('competition');
    $competition = $order->competition;

    return view('organizer.edit', compact('order', 'competition'));
}

public function update(Request $r, PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'revision',
        403,
        'Pengajuan ini tidak sedang menunggu revisi.'
    );

    $d = $r->validate([
        'title' => 'required|string|max:180',
        'organizer' => 'required|string|max:180',
        'competition_category' => 'required|string|max:100',
        'competition_level' => 'required|string|max:50',
        'delivery_mode' => 'required|in:Online,Offline,Hybrid',
        'location' => 'nullable|string|max:180',
        'description' => 'required|string|max:10000',
        'requirements' => 'required|string|max:10000',
        'benefits' => 'nullable|string|max:5000',
        'registration_start' => 'required|date',
        'registration_end' => 'required|date|after_or_equal:registration_start',
        'event_start' => 'nullable|date',
        'event_end' => 'nullable|date|after_or_equal:event_start',
        'contact' => 'required|string|max:180',
        'banner' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:5120',
    ]);

    $competition = $order->competition;
    $oldBanner = $competition->banner;

    // Jika poster baru diunggah, simpan poster baru.
    // Jika tidak, gunakan poster lama.
    $banner = $oldBanner;

    if ($r->hasFile('banner')) {
        $banner = $r->file('banner')
            ->store('competition-posters', 'public');
    }

    $mode = $d['delivery_mode'];

    $competition->update([
        'title' => $d['title'],
        'organizer' => $d['organizer'],
        'category' => $d['competition_level'] === 'Internasional'
            ? 'Internasional'
            : ($d['competition_level'] === 'Nasional'
                ? 'Nasional' : 'Kampus'),
        'competition_category' => $d['competition_category'],
        'competition_level' => $d['competition_level'],
        'mode' => $mode === 'Offline' ? 'Offline' : 'Online',
        'delivery_mode' => $mode,
        'location' => $d['location'] ?? ($mode === 'Online' ? 'Online' : null),
        'description' => $d['description'],
        'requirements' => $d['requirements'],
        'benefits' => $d['benefits'] ?? null,
        'registration_start' => $d['registration_start'],
        'registration_end' => $d['registration_end'],
        'event_start' => $d['event_start'] ?? null,
        'event_end' => $d['event_end'] ?? null,
        'contact' => $d['contact'],
        'banner' => $banner,
        'status' => 'draft',
    ]);

    // Kirim kembali ke antrean pemeriksaan Admin.
    $order->update([
        'content_review_status' => 'pending',
        'content_admin_note' => null,
        'content_reviewed_at' => null,
        'content_reviewed_by' => null,
    ]);

    // Hapus poster lama hanya jika poster baru berhasil diunggah.
    if ($r->hasFile('banner') && $oldBanner) {
        Storage::disk('public')->delete($oldBanner);
    }

    return redirect()
        ->route('organizer.dashboard')
        ->with('success', 'Perbaikan berhasil dikirim. Pengajuan menunggu pemeriksaan ulang Admin AJARA.');
}

public function payment(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'approved',
        403,
        'Pengajuan lomba belum disetujui Admin AJARA.'
    );

    abort_if(
        $order->payment_status === 'verified',
        403,
        'Pembayaran sudah diverifikasi.'
    );

    return view('organizer.payment', compact('order'));
}
    public function receipt(PublicationOrder $order)
    {
        abort_unless($order->user_id === auth()->id(), 403);

        $order->load(['user', 'competition']);

        return view('organizer.receipt', compact('order'));
    }

public function submitPayment(Request $r, PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    abort_unless(
        $order->content_review_status === 'approved',
        403,
        'Pengajuan lomba belum disetujui Admin AJARA.'
    );

    abort_if(
        $order->payment_status === 'verified',
        403,
        'Pembayaran sudah diverifikasi dan tidak dapat diubah.'
    );

    $d = $r->validate([
        'proof' => 'required|image|mimes:jpg,jpeg,png,webp|max:5120',
    ]);

    $oldPath = $order->proof_path;

    $path = $r->file('proof')
        ->store('payment-proofs', 'public');

    $order->update([
        'proof_path' => $path,
        'payment_status' => 'pending',
        'review_status' => 'pending',
        'paid_at' => now(),
        'admin_note' => null,
    ]);

    if ($oldPath && $oldPath !== $path) {
        Storage::disk('public')->delete($oldPath);
    }

    return redirect()
        ->route('organizer.dashboard')
        ->with(
            'success',
            'Bukti pembayaran berhasil dikirim. Tunggu verifikasi Admin AJARA.'
        );
}

public function closeCompetition(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    $order->load('competition');
    $competition = $order->competition;

    abort_unless(
        $order->content_review_status === 'approved'
        && $order->payment_status === 'verified'
        && $order->review_status === 'approved'
        && $competition
        && $competition->status === 'published',
        403,
        'Lomba hanya dapat ditutup setelah publikasi aktif dan pembayaran terverifikasi.'
    );

    $competition->update([
        'status' => 'closed',
        'closure_type' => 'manual',
        'closed_at' => now(),
        'closed_by' => auth()->id(),
    ]);

    return redirect()->route('organizer.dashboard')
        ->with('success', 'Lomba berhasil ditutup. Lomba tetap dapat dilihat mahasiswa, tetapi pendaftaran tidak tersedia.');
}

public function manage(PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    $order->load('competition');
    $competition = $order->competition;
    abort_unless(
        $order->promotion_started_at
        && $order->promotion_ends_at
        && now()->lt($order->promotion_ends_at),
        403,
        'Masa promosi lomba telah berakhir atau belum aktif.'
    );

    abort_unless(
        $order->content_review_status === 'approved'
        && $order->payment_status === 'verified'
        && $order->review_status === 'approved'
        && $competition
        && $competition->status === 'published',
        403,
        'Lomba ini belum dapat dikelola.'
    );

    return view('organizer.manage', compact('order', 'competition'));
}

public function updatePublished(Request $r, PublicationOrder $order)
{
    abort_unless($order->user_id === auth()->id(), 403);

    $order->load('competition');
    $competition = $order->competition;
    // Pastikan masa promosi masih aktif.
    abort_unless(
        $order->promotion_started_at
        && $order->promotion_ends_at
        && now()->lt($order->promotion_ends_at),
        403,
        'Masa promosi lomba telah berakhir atau belum aktif.'
    );

    abort_unless(
        $order->content_review_status === 'approved'
        && $order->payment_status === 'verified'
        && $order->review_status === 'approved'
        && $competition
        && $competition->status === 'published',
        403,
        'Lomba ini tidak dapat diperbarui.'
    );

    $d = $r->validate([
        'title' => 'required|string|max:180',
        'organizer' => 'required|string|max:180',
        'competition_category' => 'required|string|max:100',
        'competition_level' => 'required|string|max:50',
        'delivery_mode' => 'required|in:Online,Offline,Hybrid',
        'location' => 'nullable|string|max:180',
        'description' => 'required|string|max:10000',
        'requirements' => 'required|string|max:10000',
        'benefits' => 'nullable|string|max:5000',
        'registration_start' => 'required|date',
        'registration_end' => 'required|date|after_or_equal:registration_start',
        'event_start' => 'nullable|date',
        'event_end' => 'nullable|date|after_or_equal:event_start',
        'contact' => 'required|string|max:180',
        'banner' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:5120',
    ]);

    $oldBanner = $competition->banner;
    $banner = $oldBanner;

    if ($r->hasFile('banner')) {
        $banner = $r->file('banner')->store('competition-posters', 'public');
    }

    $mode = $d['delivery_mode'];

    $competition->update([
        'title' => $d['title'],
        'organizer' => $d['organizer'],
        'category' => $d['competition_level'] === 'Internasional'
            ? 'Internasional'
            : ($d['competition_level'] === 'Nasional' ? 'Nasional' : 'Kampus'),
        'competition_category' => $d['competition_category'],
        'competition_level' => $d['competition_level'],
        'mode' => $mode === 'Offline' ? 'Offline' : 'Online',
        'delivery_mode' => $mode,
        'location' => $d['location'] ?? ($mode === 'Online' ? 'Online' : null),
        'description' => $d['description'],
        'requirements' => $d['requirements'],
        'benefits' => $d['benefits'] ?? null,
        'registration_start' => $d['registration_start'],
        'registration_end' => $d['registration_end'],
        'event_start' => $d['event_start'] ?? null,
        'event_end' => $d['event_end'] ?? null,
        'contact' => $d['contact'],
        'banner' => $banner,
    ]);

    if ($r->hasFile('banner') && $oldBanner) {
        Storage::disk('public')->delete($oldBanner);
    }

    return redirect()
        ->route('organizer.dashboard')
        ->with('success', 'Informasi lomba berhasil diperbarui.');
}

}


====================================
app\Http\Controllers\ChatController.php
====================================
<?php

namespace App\Http\Controllers;

use App\Models\ChatMessage;
use App\Models\Notification;
use App\Models\User;
use Illuminate\Http\Request;

class ChatController extends Controller
{
    public function index(Request $request)
    {
        $current = $request->user();

        $isAdmin = $current->role === 'admin';

        abort_unless(
            $isAdmin ||
            in_array($current->role, ['mahasiswa', 'penyelenggara'], true),
            403
        );

        if ($isAdmin) {

            // ADMIN DAPAT MELIHAT MAHASISWA DAN PENYELENGGARA
            $users = User::whereIn('role', [
                'mahasiswa',
                'penyelenggara'
            ])
                ->withCount('chatMessages')
                ->orderBy('name')
                ->get();

            $target = $request->filled('user')
                ? $users->firstWhere('id', $request->integer('user'))
                : $users->first();

        } else {

            // MAHASISWA DAN PENYELENGGARA HANYA MEMBUKA CHAT SENDIRI
            $users = collect();
            $target = $current;
        }

        $messages = $target
            ? $target->chatMessages()
                ->latest()
                ->take(200)
                ->get()
                ->sortBy('created_at')
                ->values()
            : collect();

        // STATUS PESAN DIBACA
        if ($isAdmin && $target) {

            $target->chatMessages()
                ->where('sender_role', 'user')
                ->whereNull('read_at')
                ->update(['read_at' => now()]);

        } elseif (!$isAdmin) {

            $current->chatMessages()
                ->where('sender_role', 'admin')
                ->whereNull('read_at')
                ->update(['read_at' => now()]);
        
            // AJARA_SYNC_CHAT_NOTIFICATION_FINAL
            // Tandai notifikasi pesan Admin sebagai sudah dibaca
            Notification::where('user_id', $current->id)
                ->where('title', 'Pesan baru dari Admin AJARA')
                ->whereNull('read_at')
                ->update(['read_at' => now()]);
}

        return view('chat.index', compact(
            'messages',
            'users',
            'target',
            'isAdmin'
        ))->with('selectedUser', $target);
    }

    public function store(Request $request)
    {
        $current = $request->user();

        $isAdmin = $current->role === 'admin';

        abort_unless(
            $isAdmin ||
            in_array($current->role, ['mahasiswa', 'penyelenggara'], true),
            403
        );

        $data = $request->validate([
            'message' => 'nullable|string|max:3000|required_without:attachment',
            'user_id' => 'nullable|integer|exists:users,id',
            'attachment' => 'nullable|file|max:20480|mimes:jpg,jpeg,png,webp,mp4,mov,avi,pdf,doc,docx,zip',
        ]);

        if ($isAdmin) {

            $target = User::whereIn('role', [
                'mahasiswa',
                'penyelenggara'
            ])->findOrFail($data['user_id'] ?? 0);

        } else {

            $target = $current;
        }

        $filePath = null;
        $fileType = null;
        $fileName = null;

        if ($request->hasFile('attachment')) {

            $file = $request->file('attachment');

            $extension = strtolower(
                $file->getClientOriginalExtension()
            );

            $fileName = basename(
                $file->getClientOriginalName()
            );

            $safeName = preg_replace(
                '/[^A-Za-z0-9._-]/',
                '_',
                $fileName
            );

            $storedName = time() . '_' .
                bin2hex(random_bytes(5)) . '_' . $safeName;

            $fileType = in_array(
                $extension,
                ['jpg', 'jpeg', 'png', 'webp'],
                true
            ) ? 'image' : (
                in_array($extension, ['mp4', 'mov', 'avi'], true)
                    ? 'video'
                    : 'document'
            );

            $filePath = $file->storeAs(
                'chat-uploads',
                $storedName,
                'public'
            );

            if (!$filePath) {
                throw new \RuntimeException(
                    'Gagal menyimpan lampiran.'
                );
            }
        }

        // KOLOM MESSAGE PADA MIGRATION LAMA BERSIFAT NOT NULL.
        // KARENA ITU PESAN LAMPIRAN SAJA DISIMPAN SEBAGAI STRING KOSONG.
        ChatMessage::create([
            'user_id' => $target->id,
            'sender_role' => $isAdmin ? 'admin' : 'user',
            'message' => trim($data['message'] ?? ''),
            'file_path' => $filePath,
            'file_type' => $fileType,
            'file_name' => $fileName,
        ]);

        // NOTIFIKASI PENERIMA
        if ($isAdmin) {

            Notification::create([
                'user_id' => $target->id,
                'title' => 'Pesan baru dari Admin AJARA',
                'message' => 'Admin mengirim pesan baru kepada Anda.',
                'type' => 'info',
            ]);

        } else {

            User::where('role', 'admin')
                ->pluck('id')
                ->each(function ($adminId) use ($current) {

                    Notification::create([
                        'user_id' => $adminId,
                        'title' => 'Pesan baru dari ' . $current->name,
                        'message' => 'Ada pesan baru di Pusat Bantuan AJARA.',
                        'type' => 'info',
                    ]);
                });
        }

        return redirect()
            ->route('chat.index', $isAdmin ? [
                'user' => $target->id
            ] : [])
            ->with('success', 'Pesan berhasil dikirim.');
    }
}


====================================
app\Models\User.php
====================================
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Relations\HasMany;
use App\Models\PublicationOrder;

class User extends Authenticatable
{
    use HasFactory, Notifiable;
    protected $fillable = ['name', 'nim', 'email', 'password', 'role', 'avatar'];
    protected $hidden = ['password', 'remember_token'];
    protected $casts = ['email_verified_at' => 'datetime', 'password' => 'hashed'];

    public function registrations(): HasMany { return $this->hasMany(Registration::class); }
    public function notifications(): HasMany { return $this->hasMany(\App\Models\Notification::class); }
    public function publicationOrders(): HasMany { return $this->hasMany(PublicationOrder::class); }
    public function chatMessages(): HasMany { return $this->hasMany(ChatMessage::class); }
    public function reviewedContentOrders(): HasMany
{
    return $this->hasMany(
        PublicationOrder::class,
        'content_reviewed_by'
    );
}
}



====================================
resources\views\layouts\app.blade.php
====================================
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title', 'AJARA - Ajang Jejaring Prestasi Mahasiswa')</title>
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
@vite(['resources/css/app.css', 'resources/js/app.js'])
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style>
html{scroll-behavior:smooth}body{font-family:'Plus Jakarta Sans',sans-serif;background:#0A192F}[x-cloak]{display:none!important}
.ajara-container{width:min(100% - 2rem,80rem);margin-inline:auto}.ajara-link:hover{color:#5EEAD4}
.cursor-ring,.cursor-dot{position:fixed;left:-100px;top:-100px;z-index:10000;pointer-events:none;transform:translate(-50%,-50%);border-radius:50%}
@media(pointer:fine) and (min-width:1024px){body,a,button{cursor:none}}@media(pointer:coarse){.cursor-ring,.cursor-dot{display:none}}
</style>
@stack('head')
    <link rel="stylesheet" href="{{ asset('css/ajara-visual.css') }}">
    <link rel="stylesheet" href="{{ asset('css/ajara-final-theme.css') }}">
<link rel="stylesheet" href="{{ asset('css/ajara-premium-hero.css') }}">
    <link rel="stylesheet" href="{{ asset('css/ajara-unified-gaming.css') }}">

<!-- AJARA-HEADER-FINAL-CLEANUP-START -->
<style>
/* ===========================
   AJARA FINAL HEADER CLEANUP
=========================== */

/* KURSOR PANAH ELEGAN - TANPA BULAT / HALO */
body{
    cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='%23FDE68A' stroke='%230A192F' stroke-width='1.5'%3E%3Cpolygon points='5.5 3 19 12 12 14 16.5 21 14.5 22 10 15 5.5 19.5 5.5 3'/%3E%3C/svg%3E"), auto !important;
}
a, button, input, select, textarea, [role="button"], label{
    cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='%23FFFFFF' stroke='%230A192F' stroke-width='1.5'%3E%3Cpolygon points='5.5 3 19 12 12 14 16.5 21 14.5 22 10 15 5.5 19.5 5.5 3'/%3E%3C/svg%3E"), pointer !important;
}

/* HAPUS TOTAL CURSOR BULAT / HALO LAMA */
#cursorOuter, #cursorInner, #cursorDot, #cursorRing,
.custom-cursor, .cursor-dot, .cursor-ring, .cursor-outer, .cursor-inner,
.ajara-cursor, .cursor-glow, .cursor-halo, .cursor-follower,
[data-cursor], [x-ref="cursor"], [x-ref="cursorDot"], [x-ref="cursorRing"]{
    display:none !important;
    opacity:0 !important;
    visibility:hidden !important;
    pointer-events:none !important;
}

/* LOGO AJARA TANPA BACKGROUND PUTIH WRAPPER */
.ajara-final-brand-link{
    display:flex !important;
    align-items:center !important;
    gap:12px !important;
    background:transparent !important;
    border:none !important;
    box-shadow:none !important;
    padding:0 !important;
}
.ajara-final-brand-link:hover{
    transform:translateY(-1px);
}
.ajara-final-brand-link,
.ajara-final-brand-link *{
    text-decoration:none !important;
}

/* FOTO LOGO - USAHAKAN PUTIH HILANG */
.ajara-final-logo-img{
    height:64px !important;
    width:auto !important;
    display:block !important;
    background:transparent !important;
    border:none !important;
    box-shadow:none !important;
    padding:0 !important;
    object-fit:contain !important;
    filter:contrast(1.06) saturate(1.04) !important;
    mix-blend-mode:multiply !important;
}

/* TEKS BRAND DI HEADER BIAR LEBIH BAGUS */
.ajara-final-brand-copy{
    display:flex !important;
    flex-direction:column !important;
    line-height:1.02 !important;
    gap:2px !important;
}
.ajara-final-brand-title{
    font-size:1.95rem !important;
    font-weight:900 !important;
    letter-spacing:.035em !important;
    color:#F8FAFC !important;
    text-transform:uppercase !important;
    text-shadow:0 0 14px rgba(245,158,11,.10) !important;
}
.ajara-final-brand-subtitle{
    font-size:.78rem !important;
    font-weight:800 !important;
    letter-spacing:.16em !important;
    color:#FDE68A !important;
    text-transform:uppercase !important;
    opacity:.96 !important;
}

/* HEADER ELEGAN + SEMANGAT */
header, nav, .navbar, .site-header{
    background:linear-gradient(90deg,#07152A 0%, #08203F 48%, #07152A 100%) !important;
}
header nav, .navbar, .site-header{
    min-height:96px !important;
    border-bottom:1px solid rgba(245,158,11,.24) !important;
    box-shadow:
        0 16px 40px rgba(2, 6, 23, .22),
        inset 0 -1px 0 rgba(250,204,21,.12) !important;
}
header nav .container,
header nav .container-page,
.navbar .container,
.site-header .container{
    min-height:96px !important;
    display:flex !important;
    align-items:center !important;
}

/* LINK NAVBAR */
.ajara-final-nav-link{
    display:inline-flex !important;
    align-items:center !important;
    justify-content:center !important;
    min-height:48px !important;
    padding:0 16px !important;
    border-radius:999px !important;
    color:#F8FAFC !important;
    font-size:1.08rem !important;
    font-weight:800 !important;
    transition:all .25s ease !important;
    text-decoration:none !important;
}
.ajara-final-nav-link:hover{
    color:#FDE68A !important;
    background:linear-gradient(180deg, rgba(245,158,11,.08), rgba(13,148,136,.10)) !important;
}
.ajara-final-btn-login{
    display:inline-flex !important;
    align-items:center !important;
    justify-content:center !important;
    min-height:48px !important;
    padding:0 28px !important;
    border-radius:999px !important;
    border:1.5px solid rgba(245,158,11,.72) !important;
    background:transparent !important;
    color:#FDE68A !important;
    font-size:1.06rem !important;
    font-weight:800 !important;
    text-decoration:none !important;
}
.ajara-final-btn-register{
    display:inline-flex !important;
    align-items:center !important;
    justify-content:center !important;
    min-height:50px !important;
    padding:0 30px !important;
    border-radius:999px !important;
    background:linear-gradient(135deg,#F59E0B 0%, #D97706 100%) !important;
    color:#081526 !important;
    font-size:1.08rem !important;
    font-weight:900 !important;
    border:1px solid rgba(251,191,36,.55) !important;
    text-decoration:none !important;
    box-shadow:0 14px 28px rgba(245,158,11,.20) !important;
}

/* SEMBUNYIKAN PANEL MOBILE YANG MUNCUL TIBA-TIBA DI DESKTOP */
@media (min-width: 768px){
    #mobileNav,
    .mobile-nav,
    .mobile-nav-panel,
    .mobile-menu,
    [data-mobile-nav]{
        display:none !important;
        visibility:hidden !important;
        opacity:0 !important;
        max-height:0 !important;
        overflow:hidden !important;
    }
}

/* DI MOBILE: HANYA TAMPIL SAAT BENAR-BENAR TIDAK ADA class hidden */
@media (max-width: 767px){
    #mobileNav.hidden{
        display:none !important;
    }
    #mobileNav:not(.hidden){
        display:block !important;
    }
}

/* KALAU ADA BLOK DUPLIKAT NAV BESAR DI BAWAH HEADER */
.ajara-duplicate-nav-fix{
    display:none !important;
}

/* RESPONSIVE */
@media (max-width:1024px){
    .ajara-final-logo-img{height:56px !important;}
    .ajara-final-brand-title{font-size:1.55rem !important;}
    .ajara-final-brand-subtitle{font-size:.70rem !important;}
}
@media (max-width:768px){
    .ajara-final-logo-img{height:48px !important;}
    .ajara-final-brand-title{font-size:1.22rem !important;}
    .ajara-final-brand-subtitle{display:none !important;}
}
</style>
<!-- AJARA-HEADER-FINAL-CLEANUP-END -->
<!-- AJARA-PREMIUM-FOOTER-START -->
<style>

/* ==========================================
   AJARA PREMIUM CTA & FOOTER
========================================== */

:root {
    --ajara-navy: #08182d;
    --ajara-teal: #0d9488;
    --ajara-mint: #5eead4;
    --ajara-gold: #fbbf24;
    --ajara-cream: #fef3c7;
    --ajara-rose: #e11d48;
}

/* ========== CTA SECTION ========== */

main section:has(a[href*="register"]) {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    background:
        radial-gradient(
            ellipse at 5% 50%,
            rgba(13,148,136,.35),
            transparent 45%
        ),
        radial-gradient(
            ellipse at 95% 20%,
            rgba(245,158,11,.16),
            transparent 38%
        ),
        linear-gradient(
            115deg,
            #064e49 0%,
            #103b43 45%,
            #101d35 100%
        ) !important;
    border: none !important;
    padding-top: 76px !important;
    padding-bottom: 76px !important;
}

main section:has(a[href*="register"])::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    opacity: .15;
    background-image:
        radial-gradient(#ffffff 1px, transparent 1px);
    background-size: 25px 25px;
    pointer-events: none;
}

main section:has(a[href*="register"]) h2 {
    color: #ffffff !important;
    font-size: clamp(2rem, 3.2vw, 3.1rem) !important;
    line-height: 1.2 !important;
    font-weight: 900 !important;
    letter-spacing: -.035em !important;
    max-width: 1000px;
}

main section:has(a[href*="register"]) p {
    color: #d5e7e8 !important;
    font-size: 1.08rem !important;
    line-height: 1.9 !important;
}

main section:has(a[href*="register"]) a[href*="register"] {
    background: linear-gradient(
        135deg,
        #fbbf24,
        #d97706
    ) !important;
    color: #101827 !important;
    border: 1px solid rgba(255,255,255,.25) !important;
    border-radius: 999px !important;
    padding: 19px 38px !important;
    font-size: 1.08rem !important;
    font-weight: 900 !important;
    box-shadow: 0 12px 35px rgba(245,158,11,.25) !important;
    transition: all .3s ease !important;
    white-space: nowrap;
}

main section:has(a[href*="register"]) a[href*="register"]:hover {
    transform: translateY(-4px) scale(1.035);
    box-shadow: 0 18px 45px rgba(245,158,11,.4) !important;
}

/* ========== FOOTER UTAMA ========== */

footer {
    position: relative;
    overflow: hidden;
    background:
        radial-gradient(
            ellipse at 0% 0%,
            rgba(13,148,136,.19),
            transparent 42%
        ),
        radial-gradient(
            ellipse at 100% 100%,
            rgba(245,158,11,.08),
            transparent 38%
        ),
        linear-gradient(
            180deg,
            #062828 0%,
            #031b20 55%,
            #03151a 100%
        ) !important;
    border-top: 1px solid rgba(45,212,191,.25) !important;
}

/* Garis emas dekoratif */
footer::before {
    content: "";
    position: absolute;
    top: 0;
    left: 7%;
    width: 86%;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent,
        rgba(251,191,36,.8),
        rgba(45,212,191,.7),
        transparent
    );
}

/* Container footer */
footer > div {
    position: relative;
    z-index: 1;
}

/* Judul brand */
footer h2,
footer h3,
footer h4 {
    color: #ffffff !important;
    font-weight: 900 !important;
    letter-spacing: -.015em;
}

/* Judul kolom */
footer h3,
footer h4 {
    font-size: 1.03rem !important;
    margin-bottom: 24px !important;
    position: relative;
}

footer h3::after,
footer h4::after {
    content: "";
    display: block;
    width: 38px;
    height: 3px;
    border-radius: 10px;
    margin-top: 12px;
    background: linear-gradient(
        90deg,
        #fbbf24,
        #0d9488
    );
}

/* Deskripsi */
footer p {
    color: #cbd5e1 !important;
    line-height: 1.95 !important;
    font-size: .96rem !important;
}

/* Link footer */
footer a {
    color: #cbd5e1 !important;
    text-decoration: none !important;
    transition: all .25s ease !important;
}

footer a:hover {
    color: #fbbf24 !important;
    transform: translateX(4px);
}

/* Link navigasi */
footer a:not([href*="instagram"]):not([href*="tiktok"]) {
    font-weight: 600;
}

/* Ikon */
footer svg {
    color: #2dd4bf;
    transition: all .25s ease;
}

footer a:hover svg {
    color: #fbbf24;
    transform: scale(1.12);
}

/* Brand AJARA */
footer .footer-brand,
footer .brand-footer {
    color: #ffffff !important;
    font-size: 1.8rem !important;
    font-weight: 900 !important;
    letter-spacing: .06em;
}

/* Jarak kolom */
footer .grid {
    column-gap: 55px !important;
    row-gap: 42px !important;
}

/* Jarak antar-link */
footer .flex-col {
    gap: 15px;
}

/* Bagian copyright */
footer .border-t {
    border-color: rgba(148,163,184,.17) !important;
}

footer small,
footer .text-xs {
    color: #94a3b8 !important;
}

/* Badge aksen emas */
footer strong {
    color: #fcd34d;
}

/* Responsif */
@media(max-width: 768px) {
    main section:has(a[href*="register"]) {
        padding: 55px 22px !important;
        text-align: center;
    }

    main section:has(a[href*="register"]) a[href*="register"] {
        width: 100%;
        justify-content: center;
    }

    footer {
        text-align: left;
    }

    footer .grid {
        grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
        gap: 35px !important;
    }
}

/* Animasi lembut */
@media(prefers-reduced-motion: no-preference) {
    footer a,
    main section:has(a[href*="register"]) a {
        transition-duration: .3s;
    }
}

</style>
<!-- AJARA-PREMIUM-FOOTER-END -->
<!-- AJARA-FOOTER-TYPO-START -->
<style>

/* =====================================
   AJARA PREMIUM FOOTER TYPOGRAPHY
===================================== */

footer {
    font-family: 'Plus Jakarta Sans', sans-serif !important;
    -webkit-font-smoothing: antialiased;
}

/* BRAND AJARA */
footer .footer-brand,
footer .brand-footer,
footer h2 {
    font-size: 30px !important;
    font-weight: 900 !important;
    letter-spacing: 0.025em !important;
    line-height: 1.3 !important;
    color: #fcd98b !important;
}

/* JUDUL KOLOM */
footer h3,
footer h4 {
    font-size: 19px !important;
    font-weight: 800 !important;
    line-height: 1.5 !important;
    letter-spacing: 0.015em !important;
    color: #ffffff !important;
    margin-bottom: 25px !important;
}

/* DESKRIPSI BRAND */
footer p {
    font-size: 17px !important;
    font-weight: 450 !important;
    line-height: 2.05 !important;
    letter-spacing: 0.005em !important;
    color: #d5e2e7 !important;
    max-width: 390px;
}

/* LINK NAVIGASI */
footer a {
    font-family: 'Plus Jakarta Sans', sans-serif !important;
    font-size: 16px !important;
    font-weight: 600 !important;
    line-height: 1.8 !important;
    letter-spacing: 0.005em !important;
    transition: color .25s ease, transform .25s ease !important;
}

/* NAVIGASI UTAMA */
footer a[href]:hover {
    color: #fbbf24 !important;
}

/* LINK NAVIGASI YANG MENONJOL */
footer a[href*="welcome"],
footer a[href*="lomba"],
footer a[href*="about"] {
    font-size: 19px !important;
    font-weight: 750 !important;
    color: #f1f5f9 !important;
}

/* KATEGORI POPULER */
footer a[href*="kategori"],
footer a[href*="category"] {
    font-size: 16px !important;
    font-weight: 550 !important;
    color: #cbd5e1 !important;
}

/* KONTAK DAN SOSIAL MEDIA */
footer a[href^="mailto:"],
footer a[href*="instagram"],
footer a[href*="tiktok"] {
    font-size: 16px !important;
    font-weight: 550 !important;
    color: #dbe5e9 !important;
}

/* IKON KONTAK */
footer svg {
    width: 19px;
    height: 19px;
    flex-shrink: 0;
}

/* JARAK ANTAR LINK */
footer .flex-col {
    gap: 16px !important;
}

/* COPYRIGHT */
footer small,
footer .text-xs {
    font-size: 13px !important;
    line-height: 1.8 !important;
    letter-spacing: .015em;
    color: #94a3b8 !important;
}

/* GARIS DEKORATIF JUDUL */
footer h3::after,
footer h4::after {
    width: 48px !important;
    height: 3px !important;
    margin-top: 14px !important;
    border-radius: 10px;
    background: linear-gradient(
        90deg,
        #fbbf24,
        #0d9488
    ) !important;
}

/* RESPONSIVE TABLET */
@media (max-width: 1024px) {
    footer h3,
    footer h4 {
        font-size: 18px !important;
    }

    footer p {
        font-size: 16px !important;
    }
}

/* RESPONSIVE MOBILE */
@media (max-width: 640px) {
    footer .footer-brand,
    footer .brand-footer,
    footer h2 {
        font-size: 26px !important;
    }

    footer h3,
    footer h4 {
        font-size: 18px !important;
        margin-bottom: 18px !important;
    }

    footer p {
        font-size: 15px !important;
        line-height: 1.9 !important;
    }

    footer a {
        font-size: 15px !important;
    }

    footer a[href*="welcome"],
    footer a[href*="lomba"],
    footer a[href*="about"] {
        font-size: 17px !important;
    }
}

</style>
<!-- AJARA-FOOTER-TYPO-END -->
<!-- AJARA-FOOTER-COMPACT-START -->
<style>

/* =====================================
   AJARA ELEGANT COMPACT FOOTER
===================================== */

footer {
    font-family: 'Plus Jakarta Sans', sans-serif !important;
}

/* BRAND AJARA */
footer h2,
footer .footer-brand,
footer .brand-footer {
    font-size: 23px !important;
    line-height: 1.4 !important;
    font-weight: 800 !important;
    letter-spacing: .025em !important;
    color: #f8d58b !important;
}

/* SEMUA JUDUL KOLOM */
footer h1,
footer h3,
footer h4 {
    font-size: 16px !important;
    line-height: 1.5 !important;
    font-weight: 750 !important;
    letter-spacing: .015em !important;
    color: #f8fafc !important;
    margin-bottom: 18px !important;
}

/* DESKRIPSI */
footer p {
    font-size: 14px !important;
    line-height: 1.9 !important;
    font-weight: 400 !important;
    color: #cbd5e1 !important;
    letter-spacing: 0 !important;
    max-width: 330px;
}

/* SEMUA LINK */
footer a {
    font-size: 14px !important;
    line-height: 1.7 !important;
    font-weight: 500 !important;
    color: #cbd5e1 !important;
    letter-spacing: 0 !important;
    transition: color .25s ease, transform .25s ease !important;
}

/* LINK NAVIGASI */
footer a:hover {
    color: #fbbf24 !important;
}

/* NAVIGASI CEPAT */
footer a[href*="welcome"],
footer a[href*="lomba"],
footer a[href*="about"] {
    font-size: 15px !important;
    font-weight: 650 !important;
}

/* KATEGORI */
footer a[href*="kategori"],
footer a[href*="category"] {
    font-size: 14px !important;
    font-weight: 500 !important;
}

/* KONTAK */
footer a[href^="mailto:"],
footer a[href*="instagram"],
footer a[href*="tiktok"] {
    font-size: 14px !important;
    font-weight: 500 !important;
}

/* IKON KONTAK */
footer svg {
    width: 17px !important;
    height: 17px !important;
}

/* JARAK ANTAR LINK */
footer .flex-col {
    gap: 11px !important;
}

/* GARIS JUDUL */
footer h3::after,
footer h4::after {
    width: 34px !important;
    height: 2px !important;
    margin-top: 9px !important;
    border-radius: 10px;
    background: linear-gradient(
        90deg,
        #fbbf24,
        #0d9488
    ) !important;
}

/* COPYRIGHT */
footer small,
footer .text-xs {
    font-size: 12px !important;
    line-height: 1.7 !important;
    color: #94a3b8 !important;
}

/* FOOTER RESPONSIVE */
@media(max-width: 768px) {
    footer h1,
    footer h3,
    footer h4 {
        font-size: 15px !important;
    }

    footer p,
    footer a {
        font-size: 14px !important;
    }

    footer h2,
    footer .footer-brand,
    footer .brand-footer {
        font-size: 21px !important;
    }
}

</style>
<!-- AJARA-FOOTER-COMPACT-END -->
<!-- AJARA-FOOTER-MICRO-START -->
<style>

/* AJARA FOOTER - REFINED TYPOGRAPHY */

footer {
    font-family: 'Plus Jakarta Sans', sans-serif !important;
}

/* BRAND */
footer h2,
footer h2[class],
footer .footer-brand,
footer .brand-footer {
    font-size: 19px !important;
    line-height: 1.4 !important;
    font-weight: 800 !important;
    letter-spacing: .02em !important;
    color: #f8d58b !important;
}

/* JUDUL KOLOM */
footer h1,
footer h1[class],
footer h3,
footer h3[class],
footer h4,
footer h4[class] {
    font-size: 14px !important;
    line-height: 1.5 !important;
    font-weight: 750 !important;
    letter-spacing: .01em !important;
    color: #f8fafc !important;
    margin-bottom: 15px !important;
}

/* DESKRIPSI */
footer p,
footer p[class] {
    font-size: 13px !important;
    line-height: 1.85 !important;
    font-weight: 400 !important;
    letter-spacing: 0 !important;
    color: #bdcbd4 !important;
}

/* SEMUA LINK */
footer a,
footer a[class] {
    font-size: 13px !important;
    line-height: 1.65 !important;
    font-weight: 500 !important;
    letter-spacing: 0 !important;
    color: #cbd5e1 !important;
}

/* NAVIGASI */
footer a[href*="welcome"],
footer a[href*="lomba"],
footer a[href*="about"] {
    font-size: 14px !important;
    font-weight: 650 !important;
}

/* KATEGORI */
footer li,
footer li a,
footer li a[class] {
    font-size: 13px !important;
    font-weight: 450 !important;
}

/* KONTAK */
footer a[href^="mailto:"],
footer a[href*="instagram"],
footer a[href*="tiktok"] {
    font-size: 13px !important;
    font-weight: 450 !important;
}

/* SPASI ANTAR LINK */
footer .flex-col {
    gap: 9px !important;
}

/* IKON */
footer svg {
    width: 15px !important;
    height: 15px !important;
}

/* GARIS JUDUL */
footer h3::after,
footer h4::after {
    width: 28px !important;
    height: 2px !important;
    margin-top: 7px !important;
}

/* COPYRIGHT */
footer small,
footer .text-xs,
footer small[class] {
    font-size: 11px !important;
    line-height: 1.6 !important;
    color: #94a3b8 !important;
}

/* RESPONSIVE */
@media(max-width: 768px) {
    footer h3,
    footer h4 {
        font-size: 14px !important;
    }

    footer p,
    footer a {
        font-size: 13px !important;
    }
}

</style>
<!-- AJARA-FOOTER-MICRO-END -->

<!-- AJARA MASTER LAYOUT REPAIR -->
<style id="ajara-master-layout-repair">

:root {
    --ajara-navy: #0A192F;
    --ajara-slate: #172B45;
    --ajara-teal: #119B8D;
    --ajara-border: #30445C;
}

/* GLOBAL */
html, body {
    width: 100%;
    max-width: 100%;
    min-height: 100%;
    margin: 0;
    overflow-x: clip;
}

body {
    font-size: 16px;
    line-height: 1.65;
    background: var(--ajara-navy);
}

/* MAIN NAVBAR */
body > header,
body > nav,
body header,
body .navbar,
body #navbar {
    box-sizing: border-box;
}

body > header,
body > nav,
body header:has(> nav),
body .navbar {
    width: 100% !important;
    max-width: none !important;
    background: var(--ajara-navy) !important;
    color: #fff !important;
}

body header > nav,
body .navbar {
    min-height: 76px !important;
    width: 100% !important;
    padding: 12px clamp(20px, 5vw, 76px) !important;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    border-bottom: 1px solid var(--ajara-border);
}

body header > nav a,
body .navbar a {
    font-size: 15px;
    font-weight: 600;
}

body header > nav img,
body .navbar img {
    max-height: 48px;
    width: auto;
}

/* HERO */
body main > section:has(h1),
body main > div:has(> h1) {
    width: 100%;
    max-width: none;
}

body h1 {
    font-size: clamp(32px, 3.5vw, 46px);
    line-height: 1.2;
    font-weight: 800;
}

/* SEARCH */
form:has(input[name="search"]) {
    width: min(100%, 680px);
    min-height: 58px;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px;
    border-radius: 16px;
}

form:has(input[name="search"]) input {
    flex: 1;
    min-width: 0;
    min-height: 46px;
    padding: 10px 14px;
    font-size: 16px;
}

form:has(input[name="search"]) button {
    min-height: 46px;
    padding: 10px 24px;
    border-radius: 12px;
    font-size: 15px;
    font-weight: 700;
}

/* MAIN CONTENT: FILTER + GRID */
main .max-w-7xl:has(aside) {
    max-width: 1440px !important;
    width: 100%;
    margin-left: auto;
    margin-right: auto;
}

main .grid:has(> aside) {
    display: grid !important;
    grid-template-columns: minmax(320px, 360px) minmax(0, 1fr) !important;
    gap: 30px !important;
    align-items: start;
}

main aside,
main .filter-sidebar,
main .filter-card {
    width: 100% !important;
    min-width: 0;
    padding: 28px !important;
    border-radius: 22px !important;
    background: var(--ajara-slate) !important;
    border: 1px solid var(--ajara-border) !important;
    color: #f8fafc;
    box-sizing: border-box;
}

main aside h3 {
    font-size: 21px !important;
    font-weight: 800 !important;
    margin-bottom: 22px;
}

main aside label {
    font-size: 15px !important;
    line-height: 1.7;
}

main aside select {
    width: 100% !important;
    min-height: 48px !important;
    padding: 10px 14px !important;
    font-size: 15px !important;
    border-radius: 12px !important;
    background-color: var(--ajara-navy);
    color: white;
    border: 1px solid var(--ajara-border);
}

main aside input[type="radio"],
main aside input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: var(--ajara-teal);
}

main aside button {
    min-height: 48px;
    width: 100%;
    border-radius: 12px;
    font-size: 15px;
    font-weight: 800;
}

/* GRID KARTU */
main .grid:has(> aside) > div:last-child {
    min-width: 0;
}

main .grid:has(> aside) > div:last-child .grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 22px;
}

/* FOOTER */
body footer {
    display: block;
    width: 100%;
    max-width: none;
    background: var(--ajara-navy);
    color: #e2e8f0;
    border-top: 1px solid var(--ajara-border);
    padding: 48px clamp(20px, 5vw, 76px) 28px;
    margin-top: 0px;
}

body footer .grid {
    display: grid !important;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 32px;
    max-width: 1440px;
    margin: auto;
}

body footer h3,
body footer h4 {
    color: white;
    font-size: 17px;
    font-weight: 800;
    margin-bottom: 14px;
}

body footer a {
    color: #cbd5e1;
    transition: color .2s ease;
}

body footer a:hover {
    color: #2dd4bf;
}

/* TABLET */
@media(max-width: 1023px) {
    main .grid:has(> aside) {
        grid-template-columns: minmax(280px, 320px) minmax(0, 1fr) !important;
        gap: 20px !important;
    }

    body footer .grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* MOBILE */
@media(max-width: 767px) {
    body header > nav,
    body .navbar {
        min-height: 64px !important;
        padding: 10px 16px !important;
        flex-wrap: wrap;
    }

    main .grid:has(> aside) {
        grid-template-columns: minmax(0, 1fr) !important;
        gap: 22px !important;
    }

    main aside {
        width: 100% !important;
        padding: 22px !important;
    }

    main .grid:has(> aside) > div:last-child .grid {
        grid-template-columns: minmax(0, 1fr);
    }

    form:has(input[name="search"]) {
        width: 100%;
    }

    body footer .grid {
        grid-template-columns: minmax(0, 1fr);
        gap: 24px;
    }
}

</style>
<!-- END AJARA MASTER LAYOUT REPAIR -->

<link id="ajara-responsive-global" rel="stylesheet" href="{{ asset('/css/ajara-responsive-global.css') }}?v=1">
</head>
<body class="min-h-screen bg-[#0A192F] text-slate-100 antialiased" x-data="{open:false,x:-100,y:-100,active:false}" @mousemove.window="x=$event.clientX;y=$event.clientY" @mouseover.window="active=!!$event.target.closest('a,button,input,textarea,select')">
<div class="cursor-ring hidden lg:block" :style="`left:${x}px;top:${y}px;width:${active?54:34}px;height:${active?54:34}px;border:1px solid ${active?'#2DD4BF':'#64748B'};box-shadow:${active?'0 0 22px #0D9488':'none'};transition:all .18s`"></div>
<div class="cursor-dot hidden lg:block" :style="`left:${x}px;top:${y}px;width:5px;height:5px;background:#FB7185`"></div>
<header class="sticky top-0 z-50 border-b border-white/10 bg-[#071629]/95 backdrop-blur-xl">
<nav class="ajara-container flex min-h-[76px] items-center justify-between gap-5">
<a href="{{ url('/') }}" class="flex items-center gap-3"><span class="grid h-10 w-10 place-items-center rounded-xl bg-teal-600 text-xl font-extrabold">A</span><span class="text-xl font-extrabold tracking-[.12em]">AJARA</span></a>
<button class="rounded-lg border border-slate-700 px-3 py-2 md:hidden" @click="open=!open" aria-label="Menu"><i class="bi bi-list"></i></button>
<div class="hidden items-center gap-8 md:flex"><a class="ajara-link text-sm font-semibold text-slate-300" href="{{ url('/') }}">Beranda</a><a class="ajara-link text-sm font-semibold text-slate-300" href="{{ Route::has('competitions.index') ? route('competitions.index') : url('/lomba') }}">Cari Lomba</a><a class="ajara-link text-sm font-semibold text-slate-300" href="{{ url('/about') }}">Tentang AJARA</a></div>
<div class="hidden items-center gap-3 md:flex">
@auth
<a href="{{ route('chat.index') }}" aria-label="Buka chat" title="Chat AJARA" class="relative grid h-10 w-10 place-items-center rounded-full border border-slate-700 text-slate-200 hover:border-teal-400 hover:text-teal-300"><i class="bi bi-chat-dots text-lg"></i></a>
<a href="{{ route('notifications.index') }}" aria-label="Notifikasi" title="Notifikasi" class="relative grid h-10 w-10 place-items-center rounded-full border border-slate-700 text-slate-200 hover:border-teal-400 hover:text-teal-300"><i class="bi bi-bell text-lg"></i><span id="ajara-notification-badge" class="absolute -right-1 -top-1 hidden min-w-4 rounded-full bg-rose-600 px-1 text-center text-[10px] font-extrabold leading-4 text-white"></span></a>
<a class="rounded-full border border-slate-600 px-4 py-2 text-sm font-bold" href="{{ auth()->user()->role==='admin'?(Route::has('admin.dashboard')?route('admin.dashboard'):url('/admin')):(auth()->user()->role==='penyelenggara'?(Route::has('organizer.dashboard')?route('organizer.dashboard'):url('/penyelenggara')):url('/dashboard')) }}"><i class="bi bi-person-circle mr-1"></i>{{ \Illuminate\Support\Str::limit(auth()->user()->name,18) }}</a>
<form method="POST" action="{{ route('logout') }}">@csrf<button class="rounded-full bg-rose-600 px-5 py-2.5 text-sm font-bold hover:bg-rose-500">Keluar</button></form>
@else<a href="{{ route('login') }}" class="rounded-full border border-slate-500 px-5 py-2.5 text-sm font-bold">Masuk</a><a href="{{ route('register') }}" class="rounded-full bg-teal-600 px-5 py-2.5 text-sm font-bold hover:bg-teal-500">Daftar</a>@endauth
</div></nav>
<div x-cloak x-show="open" class="border-t border-white/10 bg-[#071629] p-5 md:hidden"><div class="ajara-container flex flex-col gap-4"><a href="{{ url('/') }}">Beranda</a><a href="{{ Route::has('competitions.index')?route('competitions.index'):url('/lomba') }}">Cari Lomba</a><a href="{{ url('/about') }}">Tentang AJARA</a>@auth<a href="{{ route('chat.index') }}">Chat AJARA</a><a href="{{ route('notifications.index') }}">Notifikasi</a>@endauth @guest<a href="{{ route('login') }}">Masuk</a><a href="{{ route('register') }}">Daftar</a>@endguest</div></div>
</header>
<main>@yield('content')</main>
<footer class="border-t border-teal-900/60 bg-gradient-to-b from-[#062828] to-[#03151A]"><div class="ajara-container grid gap-10 py-14 sm:grid-cols-2 lg:grid-cols-4">
<div><a href="{{ url('/') }}" class="text-xl font-extrabold tracking-widest">AJARA</a><p class="mt-5 max-w-xs text-sm leading-7 text-slate-300">Ajang Jejaring Prestasi Mahasiswa. Ruang untuk menemukan peluang, mengembangkan potensi, dan mewujudkan prestasi.</p></div>
<div><h2 class="text-sm font-extrabold uppercase tracking-wider">Navigasi Cepat</h2><ul class="mt-5 space-y-3 text-sm text-slate-300"><li><a class="ajara-link" href="{{ url('/') }}">Beranda</a></li><li><a class="ajara-link" href="{{ Route::has('competitions.index')?route('competitions.index'):url('/lomba') }}">Cari Lomba</a></li><li><a class="ajara-link" href="{{ url('/about') }}">Tentang AJARA</a></li><li><a class="ajara-link" href="{{ route('register') }}">Daftar Akun</a></li></ul></div>
<div><h2 class="text-sm font-extrabold uppercase tracking-wider">Kategori Populer</h2><ul class="mt-5 space-y-3 text-sm text-slate-300">@foreach(['Essay','Karya Tulis Ilmiah','Desain Poster','Business Plan'] as $c)<li><a class="ajara-link" href="{{ (Route::has('competitions.index')?route('competitions.index'):url('/lomba')).'?q='.urlencode($c) }}">{{ $c }}</a></li>@endforeach</ul></div>
<div><h2 class="text-sm font-extrabold uppercase tracking-wider">Kontak & Sosial Media</h2><ul class="mt-5 space-y-3 text-sm text-slate-300"><li><i class="bi bi-envelope mr-2 text-teal-400"></i><a href="mailto:ajangjejaringlomba@gmail.com">ajangjejaringlomba@gmail.com</a></li><li><i class="bi bi-instagram mr-2 text-teal-400"></i><a href="https://www.instagram.com/ajara_id/" target="_blank" rel="noopener">Instagram AJARA</a></li><li><i class="bi bi-tiktok mr-2 text-teal-400"></i><a href="https://www.tiktok.com/" target="_blank" rel="noopener">TikTok AJARA</a></li></ul></div>
</div><div class="border-t border-white/10"><div class="ajara-container flex flex-col justify-between gap-3 py-5 text-xs text-slate-400 sm:flex-row"><p>&copy; {{ date('Y') }} AJARA. Seluruh hak cipta dilindungi.</p><p>Ajang Jejaring Prestasi Mahasiswa</p></div></div></footer>
@stack('scripts')
    <script src="{{ asset('js/ajara-visual.js') }}" defer></script>
    <script src="{{ asset('js/ajara-final-theme.js') }}" defer></script>
<script src="{{ asset('js/ajara-header-cursor-final.js') }}" defer></script>

<!-- AJARA-HEADER-FINAL-CLEANUP-JS-START -->
<script>
document.addEventListener('DOMContentLoaded', function () {
    const header = document.querySelector('header') || document.querySelector('nav') || document.body;
    const nav = header.querySelector('nav') || document.querySelector('nav');
    const desktopWidth = window.innerWidth >= 768;

    // ===============================
    // 1) PERBAIKI LOGO HEADER
    // ===============================
    let logoImg = null;

    if (header) {
        const images = header.querySelectorAll('img');
        if (images.length) {
            logoImg = images[0];
        }
    }

    if (logoImg) {
        logoImg.classList.add('ajara-final-logo-img');

        const brandLink = logoImg.closest('a') || logoImg.parentElement;
        if (brandLink) {
            brandLink.classList.add('ajara-final-brand-link');
            brandLink.style.background = 'transparent';
            brandLink.style.boxShadow = 'none';
            brandLink.style.border = 'none';
            brandLink.style.padding = '0';

            // kalau belum ada text brand, tambahkan
            let copy = brandLink.querySelector('.ajara-final-brand-copy');
            if (!copy) {
                copy = document.createElement('div');
                copy.className = 'ajara-final-brand-copy';
                copy.innerHTML =
                    '<span class="ajara-final-brand-title">AJARA</span>' +
                    '<span class="ajara-final-brand-subtitle">Ajang Jejaring Prestasi</span>';
                brandLink.appendChild(copy);
            }
        }
    }

    // ===============================
    // 2) STYLING LINK NAVBAR
    // ===============================
    const links = Array.from(document.querySelectorAll('a'));
    links.forEach(function(link){
        const txt = (link.textContent || '').trim().toLowerCase();

        if (!txt) return;

        if (
            txt === 'beranda' ||
            txt === 'cari lomba' ||
            txt === 'tentang ajara' ||
            txt === 'tentang'
        ) {
            link.classList.add('ajara-final-nav-link');
        }

        if (txt === 'masuk') {
            link.classList.add('ajara-final-btn-login');
        }

        if (txt === 'daftar' || txt === 'daftar sekarang') {
            link.classList.add('ajara-final-btn-register');
        }
    });

    // ===============================
    // 3) HAPUS PANEL / BLOK DUPLIKAT DI DESKTOP
    // ===============================
    const mobileNav = document.getElementById('mobileNav');
    if (mobileNav && desktopWidth) {
        mobileNav.classList.add('ajara-duplicate-nav-fix', 'hidden');
        mobileNav.style.display = 'none';
        mobileNav.style.visibility = 'hidden';
        mobileNav.style.opacity = '0';
        mobileNav.style.maxHeight = '0';
        mobileNav.style.overflow = 'hidden';
    }

    // sembunyikan panel besar yang isinya copy menu yang sama
    const candidates = Array.from(document.querySelectorAll('div, section'));
    candidates.forEach(function(el){
        const text = (el.innerText || '').trim();
        const hasMenu =
            text.includes('Beranda') &&
            text.includes('Cari Lomba') &&
            text.includes('Tentang AJARA') &&
            text.includes('Masuk') &&
            text.includes('Daftar');

        const insideHeader = !!el.closest('header');
        const isMobileNav = el.id === 'mobileNav';

        if (hasMenu && !insideHeader && !isMobileNav && desktopWidth) {
            // blok aneh yang nutup konten
            el.classList.add('ajara-duplicate-nav-fix');
            el.style.display = 'none';
        }
    });

    // ===============================
    // 4) PAKSA WRAPPER LOGO TRANSPARAN
    // ===============================
    if (logoImg) {
        let parent = logoImg.parentElement;
        let depth = 0;
        while (parent && depth < 4) {
            parent.style.background = 'transparent';
            parent.style.boxShadow = 'none';
            parent.style.borderColor = 'transparent';
            depth++;
            parent = parent.parentElement;
        }
    }
});
</script>
<!-- AJARA-HEADER-FINAL-CLEANUP-JS-END -->
<script>
document.addEventListener('DOMContentLoaded', () => {
    const badge = document.getElementById('ajara-notification-badge');
    if (!badge) return;
    const refreshAjaraNotifications = async () => {
        try {
            const response = await fetch(@json(route('ajara.notification.count')), {headers:{'Accept':'application/json'}, credentials:'same-origin'});
            if (!response.ok) return;
            const data = await response.json();
            const count = Number(data.count || 0);
            badge.textContent = count > 99 ? '99+' : String(count);
            badge.classList.toggle('hidden', count < 1);
        } catch (_) { /* badge tetap tersembunyi jika jaringan sedang offline */ }
    };
    refreshAjaraNotifications();
    window.setInterval(refreshAjaraNotifications, 20000);
});
</script>
</body></html>




====================================
resources\views\admin\dashboard.blade.php
====================================
@extends('layouts.app')

@section('title', 'Dashboard Admin AJARA')

@section('content')
@php
    $pendingContent = collect($contentOrders ?? []);
    $pendingPayments = collect($orders ?? []);
    $allRows = isset($allOrders)
        ? collect($allOrders)
        : $pendingPayments->concat($pendingContent)->unique('id')->values();

    $organizerDirectory = $allRows->filter(function ($item) {
        return $item && $item->user;
    })->groupBy('user_id');

    $auditRows = collect($audits ?? []);
    $unreadChat = (int)($unreadChatCount ?? 0);
@endphp

<style>
    :root{
        --ajara-dark:#072f5f;
        --ajara-blue:#0b5ed7;
        --ajara-teal:#00796b;
        --ajara-cyan:#00a6a6;
        --ajara-gold:#f4b400;
        --ajara-orange:#ff7a00;
        --ajara-red:#d62828;
        --ajara-bg:#eef5ff;
        --ajara-card:#ffffff;
        --ajara-line:#d6e4ff;
        --ajara-text:#0f172a;
        --ajara-sub:#475569;
        --ajara-soft:#f8fbff;
    }

    body{
        background:
            radial-gradient(circle at top left, #fff0c9 0%, #fff0c9 14%, transparent 15%),
            linear-gradient(135deg,#eaf4ff 0%,#f2fff6 48%,#fff8ea 100%);
        color:var(--ajara-text);
    }

    header{
        background:#ffffff !important;
        border-bottom:1px solid #dce7f7 !important;
        box-shadow:0 8px 24px rgba(7,47,95,.06);
    }

    main{
        padding-top:18px;
        padding-bottom:40px;
    }

    .aj-wrap{
        max-width:1280px;
        margin:0 auto;
        padding:0 18px;
    }

    .aj-alert{
        background:#f0fff4;
        color:#065f46;
        border:2px solid #34d399;
        border-radius:14px;
        padding:12px 16px;
        font-weight:700;
        margin-bottom:18px;
    }

    .aj-hero{
        background:linear-gradient(135deg,#073b8a 0%, #006d77 52%, #ff7a00 100%);
        color:#fff;
        border-radius:28px;
        padding:34px;
        box-shadow:0 22px 50px rgba(7,47,95,.22);
        position:relative;
        overflow:hidden;
    }

    .aj-hero:before{
        content:'';
        position:absolute;
        width:320px;
        height:320px;
        right:-60px;
        top:-80px;
        background:#ffffff;
        opacity:.08;
        border-radius:50%;
    }

    .aj-hero small{
        display:inline-block;
        letter-spacing:.18em;
        font-weight:800;
        color:#ffe29a;
        margin-bottom:12px;
    }

    .aj-hero h1{
        font-size:44px;
        line-height:1.06;
        margin:0 0 8px 0;
        font-weight:900;
    }

    .aj-hero p{
        font-size:16px;
        line-height:1.7;
        max-width:760px;
        color:#eef7ff;
        margin:0;
    }

    .aj-hero-top{
        display:flex;
        gap:18px;
        align-items:flex-start;
        justify-content:space-between;
        flex-wrap:wrap;
    }

    .aj-hero-actions{
        display:flex;
        flex-wrap:wrap;
        gap:12px;
        align-items:center;
    }

    .aj-btn{
        display:inline-flex;
        align-items:center;
        justify-content:center;
        gap:10px;
        text-decoration:none;
        border:none;
        cursor:pointer;
        font-weight:800;
        border-radius:14px;
        padding:12px 18px;
        transition:.2s ease;
        font-size:14px;
    }

    .aj-btn:hover{ transform:translateY(-1px); }

    .aj-btn-light{
        background:#ffffff;
        color:#073b8a;
        box-shadow:0 8px 20px rgba(0,0,0,.10);
    }

    .aj-btn-dark{
        background:#0f172a;
        color:#ffffff;
    }

    .aj-badge-count{
        min-width:24px;
        height:24px;
        border-radius:999px;
        background:#ff3b30;
        color:#fff;
        font-size:12px;
        display:inline-flex;
        align-items:center;
        justify-content:center;
        font-weight:900;
    }

    .aj-stats{
        display:grid;
        grid-template-columns:repeat(5,minmax(0,1fr));
        gap:16px;
        margin-top:22px;
    }

    .aj-stat{
        background:#fff;
        border-radius:20px;
        padding:18px;
        border:2px solid #d9e7ff;
        box-shadow:0 10px 24px rgba(7,47,95,.07);
    }

    .aj-stat span{
        color:#64748b;
        font-size:14px;
        font-weight:700;
        display:block;
        margin-bottom:8px;
    }

    .aj-stat strong{
        font-size:36px;
        font-weight:900;
        color:#0f172a;
    }

    .aj-summary{
        margin-top:22px;
        display:grid;
        grid-template-columns:repeat(3,minmax(0,1fr));
        gap:16px;
    }

    .aj-summary-card{
        background:#fff;
        border:2px solid #d9e7ff;
        border-radius:22px;
        padding:22px 24px;
        box-shadow:0 10px 24px rgba(7,47,95,.06);
    }

    .aj-summary-card .k{
        color:#64748b;
        font-size:15px;
        margin-bottom:10px;
        font-weight:700;
    }

    .aj-summary-card .v{
        font-size:24px;
        font-weight:900;
        color:#0f172a;
    }

    .aj-tabs{
        display:flex;
        gap:10px;
        flex-wrap:wrap;
        margin:22px 0;
    }

    .aj-tab{
        background:#ffffff;
        border:2px solid #d7e4ff;
        color:#1e293b;
        padding:10px 18px;
        border-radius:999px;
        font-weight:800;
        text-decoration:none;
    }

    .aj-grid-2{
        display:grid;
        grid-template-columns:1.15fr .95fr;
        gap:18px;
        margin-top:8px;
    }

    .aj-card{
        background:#fff;
        border:2px solid #dbe7ff;
        border-radius:24px;
        box-shadow:0 12px 26px rgba(7,47,95,.06);
        overflow:hidden;
    }

    .aj-card-head{
        padding:24px 24px 18px 24px;
        border-bottom:1px solid #e5eefc;
    }

    .aj-card-head h2{
        margin:0;
        font-size:20px;
        font-weight:900;
        color:#0f172a;
    }

    .aj-card-head p{
        margin:6px 0 0;
        color:#64748b;
        line-height:1.6;
    }

    .aj-count-pill{
        margin-left:auto;
        background:#ecfdf5;
        color:#065f46;
        border-radius:999px;
        padding:6px 12px;
        font-size:12px;
        font-weight:800;
        white-space:nowrap;
    }

    .aj-head-inline{
        display:flex;
        justify-content:space-between;
        align-items:flex-start;
        gap:12px;
    }

    .aj-card-body{
        padding:22px;
    }

    .aj-empty{
        border:2px dashed #c9daf7;
        background:#f8fbff;
        border-radius:18px;
        padding:26px;
        text-align:center;
        color:#64748b;
        font-weight:700;
    }

    .aj-list{
        display:grid;
        gap:16px;
    }

    .aj-item{
        background:#f9fbff;
        border:2px solid #d9e5fb;
        border-radius:20px;
        padding:18px;
    }

    .aj-item h3{
        margin:0 0 6px;
        font-size:20px;
        font-weight:900;
    }

    .aj-meta{
        display:flex;
        flex-wrap:wrap;
        gap:10px 16px;
        color:#475569;
        font-size:14px;
        margin-bottom:14px;
    }

    .aj-status{
        display:inline-flex;
        padding:6px 12px;
        border-radius:999px;
        font-size:12px;
        font-weight:900;
    }

    .s-amber{ background:#fff4cc; color:#9a6700; }
    .s-blue{ background:#dbeafe; color:#1d4ed8; }
    .s-green{ background:#dcfce7; color:#166534; }
    .s-red{ background:#fee2e2; color:#b91c1c; }

    .aj-note{
        border-radius:14px;
        padding:12px 14px;
        font-size:14px;
        font-weight:700;
        margin-top:10px;
    }

    .aj-note-amber{ background:#fff7dd; color:#9a6700; border:1px solid #f3d27a; }
    .aj-note-red{ background:#fff1f2; color:#be123c; border:1px solid #fecdd3; }
    .aj-note-green{ background:#ecfdf5; color:#166534; border:1px solid #a7f3d0; }

    .aj-form{
        display:grid;
        gap:10px;
        margin-top:14px;
    }

    .aj-input, .aj-select, .aj-textarea{
        width:100%;
        border:2px solid #cfe0ff;
        border-radius:14px;
        padding:12px 14px;
        background:#fff;
        color:#0f172a;
        outline:none;
        font-size:14px;
    }

    .aj-input:focus, .aj-select:focus, .aj-textarea:focus{
        border-color:#0b5ed7;
        box-shadow:0 0 0 3px rgba(11,94,215,.12);
    }

    .aj-actions{
        display:flex;
        flex-wrap:wrap;
        gap:10px;
        margin-top:10px;
    }

    .btn-primary{ background:#0b5ed7; color:#fff; }
    .btn-success{ background:#00796b; color:#fff; }
    .btn-warning{ background:#ffb703; color:#111827; }
    .btn-danger{ background:#d62828; color:#fff; }
    .btn-dark{ background:#111827; color:#fff; }
    .btn-outline{ background:#fff; color:#0b5ed7; border:2px solid #0b5ed7; }

    .aj-organizer-table{
        width:100%;
        border-collapse:collapse;
    }

    .aj-organizer-table th,
    .aj-organizer-table td{
        padding:16px 14px;
        border-bottom:1px solid #e8eef9;
        text-align:left;
    }

    .aj-organizer-table th{
        font-size:12px;
        letter-spacing:.06em;
        color:#64748b;
        text-transform:uppercase;
        font-weight:900;
        background:#f8fbff;
    }

    .aj-organizer-table td{
        font-size:15px;
        color:#0f172a;
        vertical-align:top;
    }

    .aj-poster-list{
        display:grid;
        gap:16px;
    }

    .aj-poster-item{
        display:grid;
        grid-template-columns:170px 1fr 320px;
        gap:18px;
        align-items:flex-start;
        background:#f9fbff;
        border:2px solid #d7e3fb;
        border-radius:22px;
        padding:18px;
    }

    .aj-poster-thumb{
        width:100%;
        height:220px;
        border-radius:18px;
        overflow:hidden;
        border:2px solid #d4e4ff;
        background:linear-gradient(135deg,#dfefff 0%,#fff5df 100%);
        display:flex;
        align-items:center;
        justify-content:center;
        color:#475569;
        font-weight:800;
        text-align:center;
    }

    .aj-poster-thumb img{
        width:100%;
        height:100%;
        object-fit:cover;
        display:block;
    }

    .aj-mini-grid{
        display:grid;
        grid-template-columns:repeat(3,minmax(0,1fr));
        gap:10px;
        margin-top:12px;
    }

    .aj-mini{
        background:#fff;
        border:1px solid #dbe7ff;
        border-radius:14px;
        padding:12px;
    }

    .aj-mini span{
        display:block;
        font-size:11px;
        font-weight:900;
        color:#64748b;
        text-transform:uppercase;
        margin-bottom:6px;
    }

    .aj-mini strong{
        font-size:14px;
        color:#0f172a;
    }

    .aj-side-actions{
        display:grid;
        gap:10px;
    }

    .aj-table{
        width:100%;
        border-collapse:collapse;
    }

    .aj-table th, .aj-table td{
        padding:16px 14px;
        border-bottom:1px solid #e8eef9;
        text-align:left;
    }

    .aj-table th{
        font-size:12px;
        text-transform:uppercase;
        color:#64748b;
        font-weight:900;
        background:#f8fbff;
    }

    .aj-table td{
        color:#0f172a;
        vertical-align:top;
    }

    .aj-audit-item{
        display:flex;
        justify-content:space-between;
        gap:14px;
        padding:16px 0;
        border-bottom:1px solid #e7effb;
    }

    .aj-audit-item:last-child{ border-bottom:none; }

    .aj-audit-item h4{
        margin:0 0 4px;
        font-size:18px;
        font-weight:900;
    }

    .aj-audit-item p{
        margin:0;
        color:#64748b;
        line-height:1.6;
    }

    .aj-footer-contact{
        margin-top:20px;
        background:#ffffff;
        border:2px solid #dce7fb;
        border-radius:24px;
        padding:20px;
        box-shadow:0 10px 24px rgba(7,47,95,.05);
    }

    .aj-footer-contact h3{
        margin:0 0 14px;
        font-size:20px;
        font-weight:900;
    }

    .aj-contact-grid{
        display:grid;
        grid-template-columns:repeat(3,minmax(0,1fr));
        gap:14px;
    }

    .aj-contact-box{
        border:2px solid #dfe8fb;
        background:#f8fbff;
        border-radius:18px;
        padding:16px;
    }

    .aj-contact-box span{
        display:block;
        font-size:12px;
        letter-spacing:.06em;
        text-transform:uppercase;
        color:#64748b;
        font-weight:900;
        margin-bottom:6px;
    }

    .aj-contact-box a{
        font-weight:800;
        color:#0b5ed7;
        text-decoration:none;
        word-break:break-word;
    }

    @media (max-width:1100px){
        .aj-stats{ grid-template-columns:repeat(2,minmax(0,1fr)); }
        .aj-summary{ grid-template-columns:1fr; }
        .aj-grid-2{ grid-template-columns:1fr; }
        .aj-poster-item{ grid-template-columns:1fr; }
        .aj-contact-grid{ grid-template-columns:1fr; }
    }

    @media (max-width:720px){
        .aj-hero{ padding:24px; }
        .aj-hero h1{ font-size:32px; }
        .aj-stats{ grid-template-columns:1fr; }
        .aj-mini-grid{ grid-template-columns:1fr; }
    }
</style>

<main>
    <div class="aj-wrap">
        @if(session('success'))
            <div class="aj-alert">{{ session('success') }}</div>
        @endif

        @if($errors->any())
            <div class="aj-note aj-note-red" style="margin-bottom:18px;">
                @foreach($errors->all() as $error)
                    <div>{{ $error }}</div>
                @endforeach
            </div>
        @endif

        <section class="aj-hero">
            <div class="aj-hero-top">
                <div>
                    <small>AJARA COMMAND CENTER</small>
                    <h1>Dashboard Admin AJARA</h1>
                    <p>
                        Kelola review lomba, verifikasi pembayaran, monitoring masa tayang, poster,
                        transaksi, audit admin, dan komunikasi dengan penyelenggara dalam satu halaman.
                    </p>
                </div>

                <div class="aj-hero-actions">
                    <a href="{{ route('chat.index') }}" class="relative z-20 inline-flex cursor-pointer items-center justify-center rounded-xl bg-white px-5 py-3 font-bold text-[#0B2239] shadow-lg hover:bg-slate-100" style="pointer-events:auto">Chat Room</a>
                </div>
            </div>

            <div class="aj-stats">
                <div class="aj-stat">
                    <span>Mahasiswa</span>
                    <strong>{{ $stats['users'] ?? 0 }}</strong>
                </div>
                <div class="aj-stat">
                    <span>Penyelenggara</span>
                    <strong>{{ $stats['organizers'] ?? 0 }}</strong>
                </div>
                <div class="aj-stat">
                    <span>Total lomba</span>
                    <strong>{{ $stats['competitions'] ?? 0 }}</strong>
                </div>
                <div class="aj-stat">
                    <span>Menunggu review konten</span>
                    <strong>{{ $stats['pending_content'] ?? 0 }}</strong>
                </div>
                <div class="aj-stat">
                    <span>Menunggu verifikasi bayar</span>
                    <strong>{{ $stats['pending'] ?? 0 }}</strong>
                </div>
            </div>
        </section>

        <div class="aj-summary">
            <div class="aj-summary-card">
                <div class="k">Total transaksi publikasi</div>
                <div class="v">{{ $allRows->count() }}</div>
            </div>
            <div class="aj-summary-card">
                <div class="k">Pembayaran terverifikasi</div>
                <div class="v">Rp{{ number_format($allRows->where('payment_status','verified')->sum('amount'),0,',','.') }}</div>
            </div>
            <div class="aj-summary-card">
                <div class="k">Poster sedang tayang</div>
                <div class="v">{{ $allRows->filter(fn($o) => optional($o)->review_status === 'approved')->count() }}</div>
            </div>
        </div>

        <div class="aj-tabs">
            <a href="#review-konten" class="aj-tab">Review konten</a>
            <a href="#verifikasi-bayar" class="aj-tab">Verifikasi bayar</a>
            <a href="#monitoring-poster" class="aj-tab">Monitoring poster</a>
            <a href="#direktori-penyelenggara" class="aj-tab">Penyelenggara</a>
            <a href="#riwayat-transaksi" class="aj-tab">Transaksi</a>
            <a href="#audit-admin" class="aj-tab">Audit</a>
        </div>

        <div class="aj-grid-2">
            <section id="review-konten" class="aj-card">
                <div class="aj-card-head">
                    <div class="aj-head-inline">
                        <div>
                            <h2>Review Pengajuan Lomba</h2>
                            <p>Setujui atau minta revisi data lomba dari penyelenggara.</p>
                        </div>
                        <div class="aj-count-pill">{{ $pendingContent->count() }} menunggu</div>
                    </div>
                </div>
                <div class="aj-card-body">
                    @if($pendingContent->isEmpty())
                        <div class="aj-empty">Tidak ada pengajuan konten yang menunggu review.</div>
                    @else
                        <div class="aj-list">
                            @foreach($pendingContent as $o)
                                <div class="aj-item">
                                    <h3>{{ optional($o->competition)->title ?? 'Judul lomba belum tersedia' }}</h3>
                                    <div class="aj-meta">
                                        <span>Penyelenggara: <strong>{{ optional($o->user)->name ?? '-' }}</strong></span>
                                        <span>Paket: <strong>{{ $o->package }}</strong></span>
                                        <span>Nominal: <strong>Rp{{ number_format($o->amount,0,',','.') }}</strong></span>
                                    </div>
                                    <span class="aj-status s-amber">Menunggu review konten</span>

                                    <form method="POST" action="{{ route('admin.content.review', $o) }}" class="aj-form">
                                        @csrf
                                        <textarea name="admin_note" class="aj-textarea" rows="3" placeholder="Catatan admin (isi jika revisi)"></textarea>
                                        <div class="aj-actions">
                                            <button type="submit" name="decision" value="approve" class="aj-btn btn-success">Setujui konten</button>
                                            <button type="submit" name="decision" value="revision" class="aj-btn btn-warning">Minta revisi</button>
                                        </div>
                                    </form>
                                </div>
                            @endforeach
                        </div>
                    @endif
                </div>
            </section>

            <section id="verifikasi-bayar" class="aj-card">
                <div class="aj-card-head">
                    <div class="aj-head-inline">
                        <div>
                            <h2>Verifikasi Pembayaran</h2>
                            <p>Periksa bukti transfer, nominal, lalu aktifkan tayang paket.</p>
                        </div>
                        <div class="aj-count-pill">{{ $pendingPayments->count() }} menunggu</div>
                    </div>
                </div>
                <div class="aj-card-body">
                    @if($pendingPayments->isEmpty())
                        <div class="aj-empty">Tidak ada pembayaran yang sedang menunggu verifikasi.</div>
                    @else
                        <div class="aj-list">
                            @foreach($pendingPayments as $o)
                                <div class="aj-item">
                                    <h3>{{ optional($o->competition)->title ?? 'Judul lomba belum tersedia' }}</h3>
                                    <div class="aj-meta">
                                        <span>Penyelenggara: <strong>{{ optional($o->user)->name ?? '-' }}</strong></span>
                                        <span>Paket: <strong>{{ $o->package }}</strong></span>
                                        <span>Nominal: <strong>Rp{{ number_format($o->amount,0,',','.') }}</strong></span>
                                    </div>

                                    <span class="aj-status s-blue">Menunggu verifikasi pembayaran</span>

                                    <div style="margin-top:12px;">
                                        @if($o->proof_path)
                                            <a href="{{ asset('storage/'.$o->proof_path) }}" target="_blank" class="aj-btn btn-outline">Buka bukti pembayaran</a>
                                        @else
                                            <div class="aj-note aj-note-red">Bukti pembayaran belum tersedia.</div>
                                        @endif
                                    </div>

                                    <form method="POST" action="{{ route('admin.publication.review', $o) }}" class="aj-form">
                                        @csrf
                                        <textarea name="admin_note" class="aj-textarea" rows="3" placeholder="Catatan admin (opsional)"></textarea>
                                        <div class="aj-actions">
                                            <button type="submit" name="decision" value="approve" class="aj-btn btn-success">Verifikasi pembayaran</button>
                                            <button type="submit" name="decision" value="reject" class="aj-btn btn-danger">Tolak pembayaran</button>
                                        </div>
                                    </form>
                                </div>
                            @endforeach
                        </div>
                    @endif
                </div>
            </section>
        </div>

        <section id="direktori-penyelenggara" class="aj-card" style="margin-top:18px;">
            <div class="aj-card-head">
                <div class="aj-head-inline">
                    <div>
                        <h2>Direktori Penyelenggara</h2>
                        <p>Lihat siapa saja penyelenggara yang aktif di AJARA.</p>
                    </div>
                    <div class="aj-count-pill">{{ $organizerDirectory->count() }} akun</div>
                </div>
            </div>
            <div class="aj-card-body" style="padding:0;">
                @if($organizerDirectory->isEmpty())
                    <div class="aj-card-body">
                        <div class="aj-empty">Belum ada data penyelenggara yang tampil.</div>
                    </div>
                @else
                    <table class="aj-organizer-table">
                        <thead>
                            <tr>
                                <th>Penyelenggara</th>
                                <th>Email</th>
                                <th>Total pengajuan</th>
                                <th>Aksi</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach($organizerDirectory as $userId => $rows)
                                @php $user = optional($rows->first())->user; @endphp
                                <tr>
                                    <td><strong>{{ optional($user)->name ?? 'Akun tidak ditemukan' }}</strong></td>
                                    <td>{{ optional($user)->email ?? '-' }}</td>
                                    <td>{{ $rows->count() }}</td>
                                    <td>
                                        <a href="{{ route('chat.index') }}" class="aj-btn btn-primary" style="padding:10px 16px;">Chat</a>
                                    </td>
                                </tr>
                            @endforeach
                        </tbody>
                    </table>
                @endif
            </div>
        </section>

        <section id="monitoring-poster" class="aj-card" style="margin-top:18px;">
            <div class="aj-card-head">
                <div class="aj-head-inline">
                    <div>
                        <h2>Monitoring & Moderasi Poster</h2>
                        <p>Kelola poster, masa tayang, perpanjangan, penurunan tayang, dan penghapusan file.</p>
                    </div>
                    <div class="aj-count-pill">{{ $allRows->count() }} poster</div>
                </div>
            </div>
            <div class="aj-card-body">
                @if($allRows->isEmpty())
                    <div class="aj-empty">Belum ada data poster untuk dimonitor.</div>
                @else
                    <div class="aj-poster-list">
                        @foreach($allRows as $o)
                            <div class="aj-poster-item">
                                <div class="aj-poster-thumb">
                                    @if(optional($o->competition)->banner)
                                        <a href="{{ asset('storage/'.optional($o->competition)->banner) }}" target="_blank" style="display:block;width:100%;height:100%;">
                                            <img src="{{ asset('storage/'.optional($o->competition)->banner) }}" alt="Poster lomba">
                                        </a>
                                    @else
                                        <span>Poster tidak tersedia</span>
                                    @endif
                                </div>

                                <div>
                                    <h3 style="margin:0 0 6px;">{{ optional($o->competition)->title ?? '-' }}</h3>
                                    <div class="aj-meta" style="margin-bottom:8px;">
                                        <span>Penyelenggara: <strong>{{ optional($o->user)->name ?? '-' }}</strong></span>
                                        <span>Paket: <strong>{{ $o->package }}</strong></span>
                                        <span>Status: <strong>{{ optional($o->competition)->status ?? $o->review_status }}</strong></span>
                                    </div>

                                    @if(optional($o->competition)->admin_hidden_at)
                                        <div class="aj-note aj-note-red">
                                            Poster sedang diturunkan. Alasan:
                                            {{ optional($o->competition)->admin_hidden_reason ?? 'Tidak ada alasan.' }}
                                        </div>
                                    @elseif($o->payment_status === 'verified')
                                        <div class="aj-note aj-note-green">
                                            Poster aktif atau siap aktif sesuai status tayang.
                                        </div>
                                    @endif

                                    <div class="aj-mini-grid">
                                        <div class="aj-mini">
                                            <span>Mulai tayang</span>
                                            <strong>{{ $o->promotion_started_at ? \Illuminate\Support\Carbon::parse($o->promotion_started_at)->format('d M Y') : 'Belum aktif' }}</strong>
                                        </div>
                                        <div class="aj-mini">
                                            <span>Akhir tayang</span>
                                            <strong>{{ $o->promotion_ends_at ? \Illuminate\Support\Carbon::parse($o->promotion_ends_at)->format('d M Y') : 'Belum aktif' }}</strong>
                                        </div>
                                        <div class="aj-mini">
                                            <span>Sisa masa tayang</span>
                                            <strong>
                                                @if($o->promotion_ends_at)
                                                    {{ max(0, now()->diffInDays(\Illuminate\Support\Carbon::parse($o->promotion_ends_at), false)) }} hari
                                                @else
                                                    Belum aktif
                                                @endif
                                            </strong>
                                        </div>
                                    </div>
                                </div>

                                <div class="aj-side-actions">
                                    @if(optional($o->competition)->admin_hidden_at)
                                        <form method="POST" action="{{ route('admin.poster.restore', $o) }}">
                                            @csrf
                                            <button class="aj-btn btn-success" style="width:100%;">Aktifkan kembali</button>
                                        </form>
                                    @else
                                        <form method="POST" action="{{ route('admin.poster.hide', $o) }}">
                                            @csrf
                                            <input type="text" name="reason" class="aj-input" placeholder="Alasan menurunkan poster" required>
                                            <button class="aj-btn btn-warning" style="width:100%;margin-top:10px;">Turunkan poster</button>
                                        </form>
                                    @endif

                                    @if(!$o->promotion_started_at)
                                        <form method="POST" action="{{ route('admin.promotion.activate', $o) }}">
                                            @csrf
                                            <button class="aj-btn btn-primary" style="width:100%;">Aktifkan masa tayang paket</button>
                                        </form>
                                    @endif

                                    <form method="POST" action="{{ route('admin.promotion.extend', $o) }}">
                                        @csrf
                                        <div style="display:flex;gap:8px;">
                                            <input type="number" name="days" min="1" class="aj-input" placeholder="Hari" required>
                                            <button class="aj-btn btn-dark" type="submit">Perpanjang</button>
                                        </div>
                                    </form>

                                    <form method="POST" action="{{ route('admin.poster.remove', $o) }}">
                                        @csrf
                                        <input type="text" name="reason" class="aj-input" placeholder="Alasan hapus file poster" required>
                                        <button class="aj-btn btn-danger" style="width:100%;margin-top:10px;">Hapus file poster</button>
                                    </form>
                                </div>
                            </div>
                        @endforeach
                    </div>
                @endif
            </div>
        </section>

        <section id="riwayat-transaksi" class="aj-card" style="margin-top:18px;">
            <div class="aj-card-head">
                <div class="aj-head-inline">
                    <div>
                        <h2>Riwayat Transaksi Publikasi</h2>
                        <p>Seluruh order, status pembayaran, paket, dan nominal.</p>
                    </div>
                    <div class="aj-count-pill">{{ $allRows->count() }} transaksi</div>
                </div>
            </div>
            <div class="aj-card-body" style="padding:0;">
                @if($allRows->isEmpty())
                    <div class="aj-card-body">
                        <div class="aj-empty">Belum ada riwayat transaksi.</div>
                    </div>
                @else
                    <table class="aj-table">
                        <thead>
                            <tr>
                                <th>Tanggal</th>
                                <th>Penyelenggara</th>
                                <th>Lomba</th>
                                <th>Paket</th>
                                <th>Nominal</th>
                                <th>Pembayaran</th>
                                <th>Bukti</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach($allRows->sortByDesc('created_at') as $o)
                                <tr>
                                    <td>{{ optional($o->created_at)->format('d/m/Y') }}</td>
                                    <td>{{ optional($o->user)->name ?? '-' }}</td>
                                    <td>{{ optional($o->competition)->title ?? '-' }}</td>
                                    <td>{{ $o->package }}</td>
                                    <td>Rp{{ number_format($o->amount,0,',','.') }}</td>
                                    <td>
                                        @if($o->payment_status === 'verified')
                                            <span class="aj-status s-green">VERIFIED</span>
                                        @elseif($o->payment_status === 'pending')
                                            <span class="aj-status s-amber">PENDING</span>
                                        @elseif($o->payment_status === 'rejected')
                                            <span class="aj-status s-red">REJECTED</span>
                                        @else
                                            <span class="aj-status s-blue">UNPAID</span>
                                        @endif
                                    </td>
                                    <td>
                                        @if($o->proof_path)
                                            <a href="{{ asset('storage/'.$o->proof_path) }}" target="_blank" class="aj-btn btn-outline" style="padding:8px 12px;">Lihat</a>
                                        @else
                                            -
                                        @endif
                                    </td>
                                </tr>
                            @endforeach
                        </tbody>
                    </table>
                @endif
            </div>
        </section>

        <section id="audit-admin" class="aj-card" style="margin-top:18px;">
            <div class="aj-card-head">
                <div class="aj-head-inline">
                    <div>
                        <h2>Jejak Aktivitas Admin</h2>
                        <p>Riwayat keputusan review, moderasi, dan perubahan masa tayang.</p>
                    </div>
                    <div class="aj-count-pill">{{ $auditRows->count() }} log</div>
                </div>
            </div>
            <div class="aj-card-body">
                @if($auditRows->isEmpty())
                    <div class="aj-empty">Belum ada data audit admin.</div>
                @else
                    @foreach($auditRows->take(12) as $a)
                        <div class="aj-audit-item">
                            <div>
                                <h4>{{ $a->title ?? ($a->action ?? 'Aktivitas admin') }}</h4>
                                <p>{{ $a->description ?? ($a->detail ?? 'Tidak ada deskripsi.') }}</p>
                            </div>
                            <div style="color:#64748b;font-weight:700;white-space:nowrap;">
                                {{ optional($a->created_at)->format('d M Y H:i') }}
                            </div>
                        </div>
                    @endforeach
                @endif
            </div>
        </section>

        <section class="aj-footer-contact">
            <h3>Kontak Resmi AJARA</h3>
            <div class="aj-contact-grid">
                <div class="aj-contact-box">
                    <span>Email</span>
                    <a href="mailto:ajangjejaringlomba@gmail.com">ajangjejaringlomba@gmail.com</a>
                </div>
                <div class="aj-contact-box">
                    <span>Instagram</span>
                    <a href="https://www.instagram.com/ajara_id?srtk=MXJsazFyNTV3b3I0Yg==" target="_blank">@ajara_id</a>
                </div>
                <div class="aj-contact-box">
                    <span>TikTok</span>
                    <a href="https://www.tiktok.com/@http.seruni?_r=1&_t=ZS-9BOSJP3BZno" target="_blank">@http.seruni</a>
                </div>
            </div>
        </section>
    </div>
</main>
@endsection


====================================
resources\views\organizer\dashboard.blade.php
====================================
@extends('layouts.app')

@section('title', 'Dashboard Penyelenggara')

@section('content')
@php
    $rows = collect($orders ?? []);
@endphp

<style>
    :root{
        --org-dark:#082f49;
        --org-blue:#1d4ed8;
        --org-teal:#0f766e;
        --org-orange:#f97316;
        --org-gold:#f59e0b;
        --org-red:#dc2626;
        --org-bg:#eef6ff;
        --org-card:#ffffff;
        --org-line:#d9e7fb;
        --org-text:#0f172a;
        --org-sub:#475569;
    }

    body{
        background:
            radial-gradient(circle at top right, #ffe1b5 0%, #ffe1b5 12%, transparent 13%),
            linear-gradient(135deg,#eef6ff 0%,#f7fffb 45%,#fff6ea 100%);
        color:var(--org-text);
    }

    header{
        background:#fff !important;
        border-bottom:1px solid #dce7f7 !important;
        box-shadow:0 8px 24px rgba(8,47,73,.06);
    }

    .org-wrap{
        max-width:1240px;
        margin:0 auto;
        padding:22px 18px 42px;
    }

    .org-alert{
        background:#f0fff4;
        color:#065f46;
        border:2px solid #34d399;
        border-radius:14px;
        padding:12px 16px;
        font-weight:700;
        margin-bottom:18px;
    }

    .org-danger{
        background:#fff1f2;
        color:#b91c1c;
        border:2px solid #fecdd3;
        border-radius:14px;
        padding:12px 16px;
        font-weight:700;
        margin-bottom:18px;
    }

    .org-hero{
        background:linear-gradient(135deg,#ff7a00 0%, #f4b400 35%, #00796b 100%);
        color:#fff;
        border-radius:28px;
        padding:30px 30px 26px;
        box-shadow:0 22px 48px rgba(8,47,73,.18);
        position:relative;
        overflow:hidden;
    }

    .org-hero:after{
        content:'';
        position:absolute;
        right:-50px;
        top:-60px;
        width:220px;
        height:220px;
        background:#fff;
        opacity:.10;
        border-radius:50%;
    }

    .org-hero-top{
        display:flex;
        justify-content:space-between;
        gap:16px;
        flex-wrap:wrap;
        align-items:flex-start;
    }

    .org-hero small{
        display:inline-block;
        color:#fff4c7;
        font-weight:900;
        letter-spacing:.14em;
        margin-bottom:8px;
    }

    .org-hero h1{
        margin:0;
        font-size:42px;
        line-height:1.06;
        font-weight:900;
    }

    .org-hero p{
        margin:8px 0 0;
        max-width:720px;
        line-height:1.7;
        color:#f3fbff;
        font-size:15px;
    }

    .org-hero-actions{
        display:flex;
        gap:12px;
        flex-wrap:wrap;
    }

    .org-btn{
        display:inline-flex;
        align-items:center;
        justify-content:center;
        gap:8px;
        text-decoration:none;
        border:none;
        cursor:pointer;
        border-radius:14px;
        padding:12px 18px;
        font-size:14px;
        font-weight:800;
        transition:.2s ease;
    }

    .org-btn:hover{ transform:translateY(-1px); }

    .org-btn-light{
        background:#fff;
        color:#0b5ed7;
    }

    .org-btn-dark{
        background:#082f49;
        color:#fff;
    }

    .org-btn-outline{
        background:transparent;
        color:#fff;
        border:2px solid #fff;
    }

    .org-stats{
        margin-top:20px;
        display:grid;
        grid-template-columns:repeat(4,minmax(0,1fr));
        gap:16px;
    }

    .org-stat{
        background:#fff;
        border-radius:20px;
        border:2px solid #dce7fb;
        padding:18px;
        color:#0f172a;
        box-shadow:0 10px 24px rgba(8,47,73,.06);
    }

    .org-stat span{
        display:block;
        color:#64748b;
        font-size:14px;
        font-weight:700;
        margin-bottom:8px;
    }

    .org-stat strong{
        font-size:36px;
        font-weight:900;
    }

    .org-card{
        margin-top:18px;
        background:#fff;
        border:2px solid #dce7fb;
        border-radius:26px;
        box-shadow:0 12px 28px rgba(8,47,73,.06);
        overflow:hidden;
    }

    .org-card-head{
        padding:22px 22px 16px;
        border-bottom:1px solid #e8eef9;
        display:flex;
        justify-content:space-between;
        gap:12px;
        flex-wrap:wrap;
        align-items:flex-start;
    }

    .org-card-head h2{
        margin:0;
        font-size:20px;
        font-weight:900;
        color:#0f172a;
    }

    .org-card-head p{
        margin:6px 0 0;
        color:#64748b;
        line-height:1.6;
    }

    .org-card-body{
        padding:18px;
    }

    .org-empty{
        border:2px dashed #cbdcf8;
        background:#f8fbff;
        border-radius:18px;
        padding:26px;
        text-align:center;
        color:#64748b;
        font-weight:700;
    }

    .org-list{
        display:grid;
        gap:18px;
    }

    .org-item{
        border:2px solid #dce7fb;
        background:#fbfdff;
        border-radius:22px;
        padding:18px;
    }

    .org-top{
        display:flex;
        align-items:flex-start;
        justify-content:space-between;
        gap:16px;
        flex-wrap:wrap;
    }

    .org-top h3{
        margin:0;
        font-size:24px;
        font-weight:900;
        line-height:1.25;
    }

    .org-sub{
        color:#475569;
        margin-top:6px;
        font-size:15px;
    }

    .org-pill{
        display:inline-flex;
        align-items:center;
        padding:7px 12px;
        border-radius:999px;
        font-size:12px;
        font-weight:900;
        white-space:nowrap;
    }

    .pill-green{ background:#dcfce7; color:#166534; }
    .pill-blue{ background:#dbeafe; color:#1d4ed8; }
    .pill-amber{ background:#fff4cc; color:#9a6700; }
    .pill-red{ background:#fee2e2; color:#b91c1c; }
    .pill-dark{ background:#e2e8f0; color:#0f172a; }

    .org-content{
        display:grid;
        grid-template-columns:1.25fr .95fr;
        gap:18px;
        margin-top:16px;
    }

    .org-info{
        display:grid;
        gap:12px;
    }

    .org-info-grid{
        display:grid;
        grid-template-columns:repeat(3,minmax(0,1fr));
        gap:10px;
    }

    .org-box{
        background:#fff;
        border:1px solid #dfe8fb;
        border-radius:16px;
        padding:14px;
    }

    .org-box span{
        display:block;
        font-size:11px;
        text-transform:uppercase;
        color:#64748b;
        font-weight:900;
        margin-bottom:5px;
    }

    .org-box strong{
        color:#0f172a;
        font-size:14px;
        line-height:1.5;
    }

    .org-note{
        border-radius:14px;
        padding:12px 14px;
        font-size:14px;
        font-weight:700;
    }

    .org-note-amber{ background:#fff8df; color:#9a6700; border:1px solid #f6db91; }
    .org-note-red{ background:#fff1f2; color:#be123c; border:1px solid #fecdd3; }

    .org-promo{
        background:linear-gradient(180deg,#f4fffb 0%, #ffffff 100%);
        border:2px solid #c7f0df;
        border-radius:20px;
        padding:18px;
        height:100%;
    }

    .org-promo h4{
        margin:0 0 12px;
        font-size:16px;
        font-weight:900;
        letter-spacing:.05em;
        text-transform:uppercase;
        color:#0f766e;
    }

    .org-promo-main{
        display:grid;
        gap:12px;
    }

    .org-promo-stat{
        background:#fff;
        border:1px solid #dcecf1;
        border-radius:16px;
        padding:14px;
    }

    .org-promo-stat span{
        display:block;
        font-size:11px;
        color:#64748b;
        text-transform:uppercase;
        font-weight:900;
        margin-bottom:6px;
    }

    .org-promo-stat strong{
        font-size:18px;
        color:#0f172a;
    }

    .org-actions{
        margin-top:16px;
        display:grid;
        grid-template-columns:repeat(3,minmax(0,1fr));
        gap:12px;
    }

    .org-actions .org-btn{
        width:100%;
        padding:13px 14px;
    }

    .org-btn-primary{ background:#0b5ed7; color:#fff; }
    .org-btn-success{ background:#00796b; color:#fff; }
    .org-btn-chat{ background:#ffffff; color:#0f766e; border:2px solid #0f766e; }
    .org-btn-danger{ background:#ffffff; color:#dc2626; border:2px solid #fecaca; }

    .org-footer-contact{
        margin-top:20px;
        background:#fff;
        border:2px solid #dce7fb;
        border-radius:24px;
        padding:20px;
        box-shadow:0 10px 24px rgba(8,47,73,.05);
    }

    .org-footer-contact h3{
        margin:0 0 14px;
        font-size:20px;
        font-weight:900;
    }

    .org-contact-grid{
        display:grid;
        grid-template-columns:repeat(3,minmax(0,1fr));
        gap:14px;
    }

    .org-contact-box{
        border:2px solid #dfe8fb;
        background:#f8fbff;
        border-radius:18px;
        padding:16px;
    }

    .org-contact-box span{
        display:block;
        font-size:12px;
        letter-spacing:.06em;
        text-transform:uppercase;
        color:#64748b;
        font-weight:900;
        margin-bottom:6px;
    }

    .org-contact-box a{
        font-weight:800;
        color:#0b5ed7;
        text-decoration:none;
        word-break:break-word;
    }

    @media (max-width:1050px){
        .org-stats{ grid-template-columns:repeat(2,minmax(0,1fr)); }
        .org-content{ grid-template-columns:1fr; }
        .org-actions{ grid-template-columns:1fr; }
        .org-contact-grid{ grid-template-columns:1fr; }
    }

    @media (max-width:760px){
        .org-hero h1{ font-size:32px; }
        .org-stats{ grid-template-columns:1fr; }
        .org-info-grid{ grid-template-columns:1fr; }
    }
</style>

<main>
    <div class="org-wrap">
        @if(session('success'))
            <div class="org-alert">{{ session('success') }}</div>
        @endif

        @if($errors->any())
            <div class="org-danger">
                @foreach($errors->all() as $error)
                    <div>{{ $error }}</div>
                @endforeach
            </div>
        @endif

        <section class="org-hero">
            <div class="org-hero-top">
                <div>
                    <small>RUANG PENYELENGGARA AJARA</small>
                    <h1>Dashboard Publikasi Lomba</h1>
                    <p>
                        Kelola pengajuan lomba, verifikasi pembayaran, masa promosi, komunikasi dengan admin,
                        dan pantau seluruh riwayat publikasi dalam tampilan yang lebih rapi dan profesional.
                    </p>
                </div>

                <div class="org-hero-actions">
                    <a href="{{ route('organizer.create') }}" class="org-btn org-btn-light">+ Ajukan Lomba</a>
                    <a href="{{ url('/chat') }}" class="org-btn org-btn-outline" style="position:relative;z-index:9999;pointer-events:auto;cursor:pointer;" onclick="window.location.href='/chat';return false;">Room Chat</a>
                </div>
            </div>

            <div class="org-stats">
                <div class="org-stat">
                    <span>Total Pengajuan</span>
                    <strong>{{ $rows->count() }}</strong>
                </div>
                <div class="org-stat">
                    <span>Belum Bayar</span>
                    <strong>{{ $rows->where('payment_status','unpaid')->count() }}</strong>
                </div>
                <div class="org-stat">
                    <span>Menunggu Verifikasi</span>
                    <strong>{{ $rows->where('payment_status','pending')->count() }}</strong>
                </div>
                <div class="org-stat">
                    <span>Terverifikasi</span>
                    <strong>{{ $rows->where('payment_status','verified')->count() }}</strong>
                </div>
            </div>
        </section>

        <section class="org-card">
            <div class="org-card-head">
                <div>
                    <h2>Riwayat Pengajuan Publikasi</h2>
                    <p>Pantau seluruh status pengajuan, pembayaran, publikasi, dan masa promosi internal.</p>
                </div>
                <a href="{{ route('organizer.create') }}" class="org-btn org-btn-primary">+ Ajukan Lomba Baru</a>
            </div>

            <div class="org-card-body">
                @if($rows->isEmpty())
                    <div class="org-empty">Belum ada pengajuan lomba. Silakan buat pengajuan baru.</div>
                @else
                    <div class="org-list">
                        @foreach($rows as $o)
                            <article class="org-item">
                                <div class="org-top">
                                    <div>
                                        <h3>{{ optional($o->competition)->title ?? '-' }}</h3>
                                        <div class="org-sub">
                                            Paket {{ $o->package }} · Rp{{ number_format($o->amount,0,',','.') }}
                                        </div>
                                    </div>

                                    <div>
                                        @if($o->competition && $o->competition->status === 'closed')
                                            <span class="org-pill pill-red">Lomba ditutup</span>
                                        @elseif($o->payment_status === 'verified')
                                            <span class="org-pill pill-green">Publikasi aktif</span>
                                        @elseif($o->payment_status === 'pending')
                                            <span class="org-pill pill-amber">Menunggu verifikasi</span>
                                        @elseif($o->content_review_status === 'pending')
                                            <span class="org-pill pill-blue">Menunggu review konten</span>
                                        @else
                                            <span class="org-pill pill-dark">{{ ucfirst($o->review_status) }}</span>
                                        @endif
                                    </div>
                                </div>

                                <div class="org-content">
                                    <div class="org-info">
                                        <div class="org-info-grid">
                                            <div class="org-box">
                                                <span>Status review konten</span>
                                                <strong>
                                                    @if($o->content_review_status === 'approved')
                                                        Disetujui Admin
                                                    @elseif($o->content_review_status === 'revision')
                                                        Perlu revisi
                                                    @else
                                                        Menunggu pemeriksaan
                                                    @endif
                                                </strong>
                                            </div>

                                            <div class="org-box">
                                                <span>Status pembayaran</span>
                                                <strong>
                                                    @if($o->payment_status === 'verified')
                                                        Terverifikasi
                                                    @elseif($o->payment_status === 'pending')
                                                        Menunggu Admin
                                                    @elseif($o->payment_status === 'rejected')
                                                        Ditolak
                                                    @else
                                                        Belum dibayar
                                                    @endif
                                                </strong>
                                            </div>

                                            <div class="org-box">
                                                <span>Status publikasi</span>
                                                <strong>{{ ucfirst($o->review_status) }}</strong>
                                            </div>
                                        </div>

                                        @if($o->content_admin_note)
                                            <div class="org-note org-note-amber">
                                                Catatan pemeriksaan admin: {{ $o->content_admin_note }}
                                            </div>
                                        @endif

                                        @if($o->admin_note)
                                            <div class="org-note org-note-red">
                                                Catatan admin: {{ $o->admin_note }}
                                            </div>
                                        @endif
                                    </div>

                                    <div class="org-promo">
                                        <h4>Masa Promosi {{ $o->package }}</h4>
                                        <div class="org-promo-main">
                                            <div class="org-promo-stat">
                                                <span>Mulai tayang</span>
                                                <strong>{{ $o->promotion_started_at ? \Illuminate\Support\Carbon::parse($o->promotion_started_at)->format('d M Y') : 'Belum diaktifkan' }}</strong>
                                            </div>
                                            <div class="org-promo-stat">
                                                <span>Berakhir pada</span>
                                                <strong>{{ $o->promotion_ends_at ? \Illuminate\Support\Carbon::parse($o->promotion_ends_at)->format('d M Y') : 'Belum diaktifkan' }}</strong>
                                            </div>
                                            <div class="org-promo-stat">
                                                <span>Sisa masa promosi</span>
                                                <strong>
                                                    @if($o->promotion_ends_at)
                                                        {{ max(0, now()->diffInDays(\Illuminate\Support\Carbon::parse($o->promotion_ends_at), false)) }} hari
                                                    @else
                                                        Belum diaktifkan
                                                    @endif
                                                </strong>
                                            </div>
                                        </div>
                                    </div>
                                </div>

                                <div class="org-actions">
                                    <a href="{{ route('organizer.payment.receipt', $o) }}" class="org-btn org-btn-primary">Lihat Struk</a>

                                    @if($o->review_status === 'approved' && $o->competition && $o->competition->status === 'published')
                                        <a href="{{ route('organizer.manage', $o) }}" class="org-btn org-btn-success">Kelola Lomba</a>
                                    @elseif($o->content_review_status === 'revision')
                                        <a href="{{ route('organizer.edit', $o) }}" class="org-btn org-btn-success">Perbaiki Pengajuan</a>
                                    @elseif($o->content_review_status === 'approved' && in_array($o->payment_status, ['unpaid','rejected']))
                                        <a href="{{ route('organizer.payment', $o) }}" class="org-btn org-btn-success">Bayar Sekarang</a>
                                    @else
                                        <button type="button" class="org-btn org-btn-success" disabled>Kelola Lomba</button>
                                    @endif

                                    <a href="{{ url('/chat') }}" class="org-btn org-btn-chat" style="position:relative;z-index:9999;pointer-events:auto;cursor:pointer;" onclick="window.location.href='/chat';return false;">Room Chat</a>
                                </div>

                                @if($o->review_status === 'approved' && $o->competition && $o->competition->status === 'published')
                                    <div class="org-actions" style="margin-top:10px;grid-template-columns:1fr;">
                                        <form method="POST"
                                              action="{{ route('organizer.close', $o) }}"
                                              onsubmit="return confirm('Yakin ingin menutup lomba ini? Mahasiswa tidak dapat mendaftar lagi setelah lomba ditutup.');">
                                            @csrf
                                            <button type="submit" class="org-btn org-btn-danger" style="width:100%;">Tutup Lomba</button>
                                        </form>
                                    </div>
                                @endif
                            </article>
                        @endforeach
                    </div>
                @endif
            </div>
        </section>

        <section class="org-footer-contact">
            <h3>Kontak Resmi AJARA</h3>
            <div class="org-contact-grid">
                <div class="org-contact-box">
                    <span>Email</span>
                    <a href="mailto:ajangjejaringlomba@gmail.com">ajangjejaringlomba@gmail.com</a>
                </div>
                <div class="org-contact-box">
                    <span>Instagram</span>
                    <a href="https://www.instagram.com/ajara_id?srtk=MXJsazFyNTV3b3I0Yg==" target="_blank">@ajara_id</a>
                </div>
                <div class="org-contact-box">
                    <span>TikTok</span>
                    <a href="https://www.tiktok.com/@http.seruni?_r=1&_t=ZS-9BOSJP3BZno" target="_blank">@http.seruni</a>
                </div>
            </div>
        </section>
    </div>
</main>
@endsection


====================================
resources\views\profile\show.blade.php
====================================
@extends('layouts.app')

@section('title', 'Profil Mahasiswa')

@section('content')

<style>
.aj-profile {
    --navy: #0b1c30;
    --card: #142b43;
    --border: rgba(148,180,205,.19);
    --teal: #35d9c5;
    --gold: #f8c75e;
    color: #f1f6fc;
    max-width: 1100px;
    width: 100%;
    margin: auto;
    padding: 38px 24px 120px;
}

.aj-profile * { box-sizing: border-box; }

.aj-profile-header {
    margin-bottom: 28px;
}

.aj-profile-header h1 {
    font-size: clamp(27px,3vw,36px);
    font-weight: 900;
    letter-spacing: -.8px;
    margin: 0;
    color: #fff;
}

.aj-profile-header p {
    color: #aebfd2;
    font-size: 15px;
    margin-top: 8px;
}

.aj-profile-hero {
    display: flex;
    align-items: center;
    gap: 27px;
    padding: 32px;
    border: 1px solid var(--border);
    border-radius: 24px;
    background: linear-gradient(120deg,#17364e,#10253d 65%,#123b40);
    box-shadow: 0 15px 40px rgba(0,0,0,.16);
    position: relative;
    overflow: hidden;
}

.aj-profile-photo {
    width: 112px;
    height: 112px;
    min-width: 112px;
    border-radius: 50%;
    object-fit: cover;
    border: 4px solid var(--teal);
    background: #203c54;
    box-shadow: 0 0 0 7px rgba(53,217,197,.10);
}

.aj-profile-initial {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 42px;
    font-weight: 900;
    color: var(--teal);
}

.aj-profile-info {
    flex: 1;
    min-width: 0;
}

.aj-profile-info h2 {
    font-size: 27px;
    font-weight: 900;
    margin: 0 0 8px;
    color: white;
    overflow-wrap: anywhere;
}

.aj-profile-info p {
    font-size: 15px;
    color: #c1d1df;
    margin: 5px 0;
}

.aj-profile-role {
    display: inline-block;
    padding: 6px 13px;
    margin-top: 8px;
    border-radius: 30px;
    background: rgba(53,217,197,.13);
    color: var(--teal);
    font-size: 12px;
    font-weight: 800;
}

.aj-profile-edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    min-height: 48px;
    padding: 0 20px;
    border-radius: 13px;
    background: var(--gold);
    color: #172638;
    font-weight: 800;
    font-size: 14px;
    text-decoration: none;
    white-space: nowrap;
}

.aj-profile-section {
    margin-top: 32px;
}

.aj-profile-section h3 {
    font-size: 19px;
    font-weight: 900;
    margin-bottom: 15px;
    color: #fff;
}

.aj-profile-menu {
    display: grid;
    grid-template-columns: repeat(2,minmax(0,1fr));
    gap: 14px;
}

.aj-profile-menu a {
    min-height: 88px;
    display: flex;
    align-items: center;
    gap: 17px;
    padding: 17px 20px;
    border: 1px solid var(--border);
    border-radius: 17px;
    background: var(--card);
    color: #fff;
    text-decoration: none;
    transition: .2s ease;
}

.aj-profile-menu a:hover {
    border-color: var(--teal);
    transform: translateY(-2px);
    background: #19364e;
}

.aj-profile-menu .aj-menu-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 49px;
    height: 49px;
    min-width: 49px;
    border-radius: 14px;
    background: rgba(53,217,197,.12);
    color: var(--teal);
    font-size: 23px;
}

.aj-profile-menu strong {
    display: block;
    font-size: 15px;
    font-weight: 800;
}

.aj-profile-menu small {
    display: block;
    margin-top: 5px;
    color: #a9bfd2;
    font-size: 12px;
}

.aj-profile-menu .aj-menu-arrow {
    margin-left: auto;
    font-size: 17px;
    color: #8fa8bd;
}

.aj-profile-logout {
    margin-top: 30px;
    text-align: center;
}

.aj-profile-logout button {
    min-height: 50px;
    padding: 0 25px;
    border-radius: 13px;
    border: 1px solid rgba(255,90,110,.3);
    background: rgba(255,70,95,.10);
    color: #ff8999;
    font-size: 15px;
    font-weight: 800;
    cursor: pointer;
}

.aj-profile-logout button:hover {
    background: #e73555;
    color: white;
}

.aj-profile-alert {
    padding: 14px 18px;
    margin-bottom: 20px;
    border-radius: 12px;
    background: rgba(53,217,197,.12);
    color: #6ce7d7;
    font-size: 14px;
}

@media(max-width:700px) {
    .aj-profile {
        padding: 25px 16px 115px;
    }

    .aj-profile-hero {
        padding: 22px 18px;
        gap: 16px;
        flex-wrap: wrap;
    }

    .aj-profile-photo {
        width: 86px;
        height: 86px;
        min-width: 86px;
    }

    .aj-profile-initial {
        font-size: 32px;
    }

    .aj-profile-info h2 {
        font-size: 21px;
    }

    .aj-profile-info p {
        font-size: 14px;
    }

    .aj-profile-edit {
        width: 100%;
        margin-top: 8px;
    }

    .aj-profile-menu {
        grid-template-columns: 1fr;
        gap: 11px;
    }

    .aj-profile-menu a {
        min-height: 78px;
        padding: 14px;
    }

    .aj-profile-menu .aj-menu-icon {
        width: 48px;
        height: 48px;
        min-width: 48px;
        font-size: 22px;
    }
}

@media(prefers-reduced-motion:reduce) {
    .aj-profile-menu a { transition:none; }
}
</style>

<div class="aj-profile">

    <div class="aj-profile-header">
        <h1>Profil Mahasiswa</h1>
        <p>Kelola informasi akun dan aktivitas prestasimu di AJARA.</p>
    </div>

    @if(session('success'))
        <div class="aj-profile-alert">
            <i class="bi bi-check-circle-fill"></i>
            {{ session('success') }}
        </div>
    @endif

    @php
        $user = auth()->user();
    @endphp

    <section class="aj-profile-hero">

        @if($user->avatar)
            <img
                class="aj-profile-photo"
                src="{{ asset('storage/'.$user->avatar) }}"
                alt="Foto profil {{ $user->name }}"
            >
        @else
            <div class="aj-profile-photo aj-profile-initial">
                {{ strtoupper(substr($user->name,0,1)) }}
            </div>
        @endif

        <div class="aj-profile-info">
            <h2>{{ $user->name }}</h2>

            <p>
                <i class="bi bi-mortarboard"></i>
                Mahasiswa AJARA
            </p>

            <p>
                <i class="bi bi-person-badge"></i>
                NIM: {{ $user->nim ?: 'Belum diisi' }}
            </p>

            <span class="aj-profile-role">
                <i class="bi bi-patch-check-fill"></i>
                AKUN MAHASISWA
            </span>
        </div>

        <a href="{{ route('profile.edit') }}" class="aj-profile-edit">
            <i class="bi bi-pencil-square"></i>
            Edit Profil
        </a>

    </section>

    <section class="aj-profile-section">

        <h3>Pengaturan Akun</h3>

        <div class="aj-profile-menu">

            <a href="{{ route('profile.edit') }}">
                <span class="aj-menu-icon">
                    <i class="bi bi-person-vcard"></i>
                </span>
                <span>
                    <strong>Data Akun</strong>
                    <small>Nama, NIM, email dan foto profil</small>
                </span>
                <i class="bi bi-chevron-right aj-menu-arrow"></i>
            </a>

            <a href="{{ route('chat.index') }}">
                <span class="aj-menu-icon">
                    <i class="bi bi-headset"></i>
                </span>
                <span>
                    <strong>Pusat Bantuan AJARA</strong>
                    <small>Hubungi admin melalui layanan chat</small>
                </span>
                <i class="bi bi-chevron-right aj-menu-arrow"></i>
            </a>

            <a href="{{ route('notifications.index') }}">
                <span class="aj-menu-icon">
                    <i class="bi bi-bell"></i>
                </span>
                <span>
                    <strong>Notifikasi</strong>
                    <small>Informasi dan pesan terbaru</small>
                </span>
                <i class="bi bi-chevron-right aj-menu-arrow"></i>
            </a>

            <a href="{{ route('dashboard') }}">
                <span class="aj-menu-icon">
                    <i class="bi bi-house-door"></i>
                </span>
                <span>
                    <strong>Dashboard</strong>
                    <small>Kembali ke halaman utama mahasiswa</small>
                </span>
                <i class="bi bi-chevron-right aj-menu-arrow"></i>
            </a>

        </div>
    </section>

    <div class="aj-profile-logout">
        <form method="POST" action="{{ route('logout') }}">
            @csrf
            <button type="submit">
                <i class="bi bi-box-arrow-right"></i>
                Keluar dari Akun
            </button>
        </form>
    </div>

</div>

@include('partials.bottom-nav')

@endsection


====================================
resources\views\profile\edit.blade.php
====================================
@extends('layouts.app')

@section('title','Edit Profil Mahasiswa')

@section('content')

<style>
.aj-edit {
    max-width: 760px;
    margin: auto;
    padding: 35px 22px 120px;
    color: #f2f7fc;
}

.aj-edit h1 {
    font-size: 30px;
    font-weight: 900;
    color: white;
}

.aj-edit-subtitle {
    color: #b0c2d5;
    font-size: 14px;
    margin-top: 7px;
}

.aj-edit-card {
    margin-top: 25px;
    padding: 28px;
    border-radius: 22px;
    border: 1px solid rgba(148,180,205,.2);
    background: #142b43;
    box-shadow: 0 15px 40px rgba(0,0,0,.15);
}

.aj-edit-back {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: #55dece;
    font-size: 14px;
    font-weight: 700;
    text-decoration: none;
    margin-bottom: 20px;
}

.aj-edit-photo-wrap {
    display: flex;
    align-items: center;
    gap: 23px;
    padding-bottom: 25px;
    margin-bottom: 25px;
    border-bottom: 1px solid rgba(148,180,205,.17);
}

.aj-edit-photo {
    width: 110px;
    height: 110px;
    min-width: 110px;
    border-radius: 50%;
    object-fit: cover;
    border: 4px solid #35d9c5;
    background: #203b53;
}

.aj-edit-photo-info strong {
    font-size: 16px;
    display: block;
    margin-bottom: 7px;
}

.aj-edit-photo-info p {
    color: #adc0d2;
    font-size: 13px;
    margin-bottom: 12px;
}

.aj-edit-upload {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 16px;
    border-radius: 11px;
    background: rgba(53,217,197,.13);
    color: #5de5d4;
    font-size: 13px;
    font-weight: 800;
    cursor: pointer;
}

.aj-edit-upload input {
    display: none;
}

.aj-edit-field {
    display: block;
    margin-bottom: 20px;
}

.aj-edit-field label {
    display: block;
    margin-bottom: 9px;
    font-size: 14px;
    font-weight: 800;
    color: #f2f7fc;
}

.aj-edit-field input {
    display: block;
    width: 100%;
    min-height: 51px;
    padding: 12px 15px;
    border-radius: 12px;
    border: 1px solid rgba(148,180,205,.28);
    background: #0d2035;
    color: white;
    font-size: 15px;
    outline: none;
}

.aj-edit-field input:focus {
    border-color: #35d9c5;
    box-shadow: 0 0 0 3px rgba(53,217,197,.10);
}

.aj-edit-error {
    color: #ff8b9b;
    display: block;
    margin-top: 7px;
    font-size: 13px;
}

.aj-edit-save {
    width: 100%;
    min-height: 53px;
    margin-top: 8px;
    border: 0;
    border-radius: 13px;
    background: linear-gradient(110deg,#35d9c5,#12aaa7);
    color: #092333;
    font-size: 15px;
    font-weight: 900;
    cursor: pointer;
}

.aj-edit-save:hover {
    filter: brightness(1.08);
}

@media(max-width:600px) {
    .aj-edit {
        padding: 25px 16px 115px;
    }

    .aj-edit-card {
        padding: 20px 16px;
    }

    .aj-edit-photo-wrap {
        align-items: flex-start;
        gap: 15px;
    }

    .aj-edit-photo {
        width: 85px;
        height: 85px;
        min-width: 85px;
    }

    .aj-edit-photo-info strong {
        font-size: 14px;
    }

    .aj-edit-field input {
        font-size: 16px;
    }
}
</style>

<div class="aj-edit">

    <a href="{{ route('profile.show') }}" class="aj-edit-back">
        <i class="bi bi-arrow-left"></i>
        Kembali ke Profil
    </a>

    <h1>Data Akun</h1>

    <p class="aj-edit-subtitle">
        Perbarui identitas dan foto profil mahasiswa AJARA.
    </p>

    <div class="aj-edit-card">

        <form
            method="POST"
            action="{{ route('profile.update') }}"
            enctype="multipart/form-data"
        >
            @csrf
            @method('PUT')

            <div class="aj-edit-photo-wrap">

                <img
                    id="ajAvatarPreview"
                    class="aj-edit-photo"
                    src="{{ auth()->user()->avatar
                        ? asset('storage/'.auth()->user()->avatar)
                        : asset('images/ajara-logo.jpeg') }}"
                    alt="Preview foto profil"
                >

                <div class="aj-edit-photo-info">

                    <strong>Foto Profil</strong>

                    <p>
                        JPG, JPEG, PNG atau WEBP.
                        Maksimal 3 MB.
                    </p>

                    <label class="aj-edit-upload">
                        <i class="bi bi-camera-fill"></i>
                        Pilih Foto

                        <input
                            type="file"
                            name="avatar"
                            id="ajAvatarInput"
                            accept="image/jpeg,image/png,image/webp"
                        >
                    </label>

                    @error('avatar')
                        <span class="aj-edit-error">{{ $message }}</span>
                    @enderror

                </div>
            </div>

            <div class="aj-edit-field">
                <label for="name">Nama Lengkap</label>

                <input
                    type="text"
                    id="name"
                    name="name"
                    value="{{ old('name',auth()->user()->name) }}"
                    maxlength="120"
                    required
                >

                @error('name')
                    <span class="aj-edit-error">{{ $message }}</span>
                @enderror
            </div>

            <div class="aj-edit-field">
                <label for="nim">Nomor Induk Mahasiswa (NIM)</label>

                <input
                    type="text"
                    id="nim"
                    name="nim"
                    value="{{ old('nim',auth()->user()->nim) }}"
                    maxlength="30"
                    required
                >

                @error('nim')
                    <span class="aj-edit-error">{{ $message }}</span>
                @enderror
            </div>

            <div class="aj-edit-field">
                <label for="email">Alamat Email</label>

                <input
                    type="email"
                    id="email"
                    name="email"
                    value="{{ old('email',auth()->user()->email) }}"
                    maxlength="150"
                    required
                >

                @error('email')
                    <span class="aj-edit-error">{{ $message }}</span>
                @enderror
            </div>

            <button type="submit" class="aj-edit-save">
                <i class="bi bi-check-circle-fill"></i>
                Simpan Perubahan Profil
            </button>

        </form>
    </div>

</div>

@include('partials.bottom-nav')

<script>
document.addEventListener('DOMContentLoaded', function () {
    const input = document.getElementById('ajAvatarInput');
    const preview = document.getElementById('ajAvatarPreview');

    if (!input || !preview) return;

    input.addEventListener('change', function () {
        const file = this.files && this.files[0];

        if (!file) return;

        const allowed = [
            'image/jpeg',
            'image/png',
            'image/webp'
        ];

        if (!allowed.includes(file.type)) {
            alert('Format foto harus JPG, PNG, atau WEBP.');
            this.value = '';
            return;
        }

        if (file.size > 3 * 1024 * 1024) {
            alert('Ukuran foto maksimal 3 MB.');
            this.value = '';
            return;
        }

        const reader = new FileReader();

        reader.onload = function (event) {
            preview.src = event.target.result;
        };

        reader.readAsDataURL(file);
    });
});
</script>

@endsection


====================================
resources\views\partials\bottom-nav.blade.php
====================================
<nav class="fixed bottom-0 left-0 right-0 z-40 border-t border-slate-200 bg-white/95 backdrop-blur">
  <div class="mx-auto grid max-w-3xl grid-cols-4 px-3 pb-[env(safe-area-inset-bottom)] pt-2">
    @php($items = [['dashboard','house-door','Beranda'],['competitions.index','trophy','Lomba'],['notifications.index','bell','Notifikasi'],['profile.show','person','Profil']])
    @foreach($items as [$route,$icon,$label])
      <a href="{{ route($route) }}" class="flex flex-col items-center gap-1 py-1 text-xs {{ request()->routeIs($route) ? 'font-semibold text-ajara-700' : 'text-slate-400' }}">
        <i class="bi bi-{{ $icon }} text-xl"></i><span>{{ $label }}</span>
      </a>
    @endforeach
  </div>
</nav>

